From 9ed783b2926133a397d32c337a65683714863e00 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Thu, 15 May 2025 12:17:05 -0700 Subject: [PATCH 1/4] WIP stash - copy-paste exploration of https://github.com/aljubrmj/FGEM/commit/a67a15ef122efe329f933cd7547f680cb48b6676 --- setup.py | 1 + src/fgem/__init__.py | 0 .../HighEnthalpyCLGWGPowerPlant.pkl | Bin 0 -> 1219 bytes .../powerplants/NRELORCPowerPlant_30ckm.csv | 25 + .../powerplants/NRELORCPowerPlant_30ckm.pkl | Bin 0 -> 1112 bytes .../powerplants/NRELORCPowerPlant_60ckm.csv | 25 + .../powerplants/NRELORCPowerPlant_60ckm.pkl | Bin 0 -> 1112 bytes .../NRELORCPowerPlant_normalized.csv | 49 + .../NRELORCPowerPlant_normalized.pkl | Bin 0 -> 1112 bytes src/fgem/data/powerplants/ORCPowerPlant.pkl | Bin 0 -> 427125 bytes src/fgem/powerplant.py | 619 +++++ src/fgem/utils/__init__.py | 3 + src/fgem/utils/config.py | 17 + src/fgem/utils/constants.py | 198 ++ src/fgem/utils/geocluster_utils.py | 2451 +++++++++++++++++ src/fgem/utils/utils.py | 920 +++++++ tests/fgem_tests/__init__.py | 0 tests/fgem_tests/test_fgem.py | 17 + 18 files changed, 4325 insertions(+) create mode 100644 src/fgem/__init__.py create mode 100755 src/fgem/data/powerplants/HighEnthalpyCLGWGPowerPlant.pkl create mode 100755 src/fgem/data/powerplants/NRELORCPowerPlant_30ckm.csv create mode 100755 src/fgem/data/powerplants/NRELORCPowerPlant_30ckm.pkl create mode 100755 src/fgem/data/powerplants/NRELORCPowerPlant_60ckm.csv create mode 100755 src/fgem/data/powerplants/NRELORCPowerPlant_60ckm.pkl create mode 100755 src/fgem/data/powerplants/NRELORCPowerPlant_normalized.csv create mode 100755 src/fgem/data/powerplants/NRELORCPowerPlant_normalized.pkl create mode 100755 src/fgem/data/powerplants/ORCPowerPlant.pkl create mode 100644 src/fgem/powerplant.py create mode 100755 src/fgem/utils/__init__.py create mode 100755 src/fgem/utils/config.py create mode 100755 src/fgem/utils/constants.py create mode 100755 src/fgem/utils/geocluster_utils.py create mode 100755 src/fgem/utils/utils.py create mode 100644 tests/fgem_tests/__init__.py create mode 100644 tests/fgem_tests/test_fgem.py diff --git a/setup.py b/setup.py index e6989a316..12b79a10d 100755 --- a/setup.py +++ b/setup.py @@ -87,6 +87,7 @@ def read(*names, **kwargs): 'pylocker', 'nrel-pysam', 'tabulate', + 'tqdm', ], extras_require={ # eg: diff --git a/src/fgem/__init__.py b/src/fgem/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/fgem/data/powerplants/HighEnthalpyCLGWGPowerPlant.pkl b/src/fgem/data/powerplants/HighEnthalpyCLGWGPowerPlant.pkl new file mode 100755 index 0000000000000000000000000000000000000000..7fea133f5f7b6361d944584b72f00316d8576fba GIT binary patch literal 1219 zcmaJ=Z)jUp6mOQMYtu}!&@ECGt&^@=8Gf*@7{x~wBbRuQ9({nhOZyZQri*MPlMU@bsH5{+VnSky_qvPuw! zB9S!}XsVKBIqH#BQ8AMUBxGo?Y3kB&5@ALi5k_xQK{XK|tH7pc1{uDqQr6ivJXo`x z)W?ZUqMPIvl0{p%TlpNMOhvJ6FIX)Lj3aFDbQpC716u=In3_IVT?8zNI~UBFiw{h6&0vS^wGQ=2W8T9}=SJfcc6z#&PtL(@)S+e3X!=iPES;UcG zN7w-Ch&rNcqAgQQ+DctXlGTw7T9ewza?_Q2Cw1&%u~@9{AHK@JXdPjR>D^&RMX>+) zPkc0am%b8zFK?U@tQy}SIW1lsT z39kgs9qnJgN7%jh%R}a=QNefl%y6$Wp5MOz(&r=39umfj>u>zBZ^fD)c=UbG&~KrQ z1^KP(!&j_#|MIy?X=k3ik;u0Di`FAObCXwFZdkjvykI`q{IRt(-Z}t}6hrrtxuKVf z=dI(Xcl@6I@TL{tH21xGzz=a zw`6YXzZrVXGt$1W^P-g*yXWw^?xuWaUE>A)#8;s^?w+wqs1RaYN!pY&p#nys4ww{_ zw%hHIx@*nhMkp8YzTH+5^Bdr#k2-n(yF z1u{dxEndvX&WHw4`NI%!i9`is;H}DpEG9;D(P%<2Og{XY#s(yc0dKptc>lOL=bqm= z_x#TJ4c3f3TH`4n8nT~Nv0&*jQ!%ls=on~lUBw)QB`?7iXrY`4Fj)B=hoH322Sr z5QA;nG;D<^1FS(>X9>DwXvii4!H|&~8BGr>aO zLfiM^CXL_v(I@A#TrvLf-Zf#*ef#+y-)eHl&TA9F`@8F-O@loDP4tx$(b_^$k_Inq z*yFy{vF-4e-*Sl+BVBv1?VfUXE!cPJz*Iv*IkVW_Cme8poSjUz3`PnoU%mWK@u@NQ zh`(m`Nb{mZU-IDopPoL!?;82x)A5bbLh{d^bB#|P_30&(E|Vg literal 0 HcmV?d00001 diff --git a/src/fgem/data/powerplants/NRELORCPowerPlant_60ckm.csv b/src/fgem/data/powerplants/NRELORCPowerPlant_60ckm.csv new file mode 100755 index 000000000..c07aa9b8b --- /dev/null +++ b/src/fgem/data/powerplants/NRELORCPowerPlant_60ckm.csv @@ -0,0 +1,25 @@ +T_amb [deg C],T [deg C],m_turbine [kg/s],Net Output [MWh],T_inj [deg C],power_output [MWh/kg] +15,210,80,8.6,60,2.98611E-05 +10,210,80,8.8,59.954,3.05556E-05 +5,210,80,8.9,58.242,3.09028E-05 +20,210,80,8.1,64.186,0.000028125 +25,210,80,7.5,67.919,2.60417E-05 +30,210,80,7.1,70.003,2.46528E-05 +15,220,80,9.3,66.737,3.22917E-05 +15,230,80,10,70.524,3.47222E-05 +15,240,80,10.6,77.805,3.68056E-05 +15,250,80,11.1,85.385,3.85417E-05 +15,260,80,11.6,93.226,4.02778E-05 +15,270,80,12.1,101.31,4.20139E-05 +15,280,80,12.6,109.66,0.00004375 +15,200,80,7.9,56.87,2.74306E-05 +15,190,80,7.1,53.809,2.46528E-05 +15,180,80,6.2,51.276,2.15278E-05 +15,210,90,9.4,70.479,2.90123E-05 +15,210,100,10,81.915,2.77778E-05 +15,210,110,10.4,91.677,2.62626E-05 +15,210,120,10.8,100.07,0.000025 +15,210,70,7.6,51.267,3.01587E-05 +15,210,60,6.5,40.629,3.00926E-05 +15,210,50,5.2,35.239,2.88889E-05 +15,210,40,3.9,42.934,2.70833E-05 diff --git a/src/fgem/data/powerplants/NRELORCPowerPlant_60ckm.pkl b/src/fgem/data/powerplants/NRELORCPowerPlant_60ckm.pkl new file mode 100755 index 0000000000000000000000000000000000000000..dea73d665eccf17312b815d52296e29bb6c5b198 GIT binary patch literal 1112 zcmYjPU2GIp6y9xjwpF&WtraM=NWsJsWdw_rAhTP$NvkZ~)cT+XaGagJ+nIEBX1sH! zb{k10R=Sl-FzHzX2x0NTHUyP4@F22XjI@bXk`{k}2cxNd&>*H(v?B56?zX#lA8yXM z=R4<~@0{;7SF+XR$Q|mnIyEF=oi|kzX{wHZmbT^1L0G>R_COuwEP_l6b~CfI091+= zq6)VgXoYELaovcik`_f0u`#lM))tCmWMV@`mZj<)ym$x8659%i&H2Q_zwQX?zz9LG zn0i&6AS}s5HFVL?wKxn=kE+X>9YJDPl`Ke5&cG3bfjR>~@6pA4BciH{*%C{{7_;&v z9a&%MF8IZ?f)%!jX_Gsd5Ugad+`AaHH7)CV#YI|T7s3{62Pn6Rf0W+{c6c91)Ez@H z1IHmmOBf(*SO^A`RZ4X>N;#}XI@pj`e*g)Nup|O^L zx+I$zY}2M;sYLB!4N?!5^oS7?Eg}&FA!Qk3%E<6i8PjDYydwrtQzq4HL-j=#4 z9G!_ioBTGAIeuwR_Xo}yq4%5eif23zWN7QXpYE8ykaoPX|IJC)3jaFyb7QyHO$y}L zrLE;Jmir@o@~e|`r-iRSzPRT5p^A)Pp1bnW{wbmN+(>e2qer>-6t6CP_@-qp0MA@ly{ zm(`Z!Y#RTz)O9QMr2k>hA1@ETZKsF-e)_Xi{U@V4*HmBbJ%31eqV|Qu_0pfdS5NJz zswwIbdVBiTPA;Dqy?(y+r<$`V;m7!)n{e>=QDBo~tI3H&Wa_xPARrNxdZi(|DrHMy oQOs!^2zbww)o$%uGV5zI4%e)2uWHOz$;%ljt3%5Di|Xe81A-UP$^ZZW literal 0 HcmV?d00001 diff --git a/src/fgem/data/powerplants/NRELORCPowerPlant_normalized.csv b/src/fgem/data/powerplants/NRELORCPowerPlant_normalized.csv new file mode 100755 index 000000000..e653992da --- /dev/null +++ b/src/fgem/data/powerplants/NRELORCPowerPlant_normalized.csv @@ -0,0 +1,49 @@ +,T_amb [deg C],T [deg C],m_turbine [kg/s],Net Output [MWh],T_inj [deg C],power_output [MWh/kg] +0,0,125,80,1.0666666666666667,60.0,3.7037022222222225e-06 +1,5,125,80,1.0577777777777777,60.0,3.67284e-06 +2,5,210,80,1.0348837209302326,58.242,3.5933488372093023e-06 +3,10,125,80,1.04,60.0,3.6111111111111106e-06 +4,10,210,80,1.0232558139534884,59.954,3.552976744186047e-06 +5,15,125,80,1.0,60.0,3.4722222222222224e-06 +6,15,220,80,1.0813953488372094,66.737,3.7548488372093027e-06 +7,15,230,80,1.1627906976744187,70.524,4.037465116279069e-06 +8,15,240,80,1.2325581395348837,77.805,4.279720930232558e-06 +9,15,250,80,1.2906976744186047,85.385,4.4815930232558135e-06 +10,15,260,80,1.3488372093023255,93.226,4.6834651162790705e-06 +11,15,270,80,1.4069767441860466,101.31,4.885337209302326e-06 +12,15,280,80,1.4651162790697674,109.66,5.087209302325582e-06 +13,15,190,80,0.8255813953488372,53.809,2.8666046511627907e-06 +14,15,180,80,0.7209302325581396,51.276,2.503232558139535e-06 +15,15,210,90,1.0930232558139537,70.479,3.3735232558139535e-06 +16,15,210,100,1.1627906976744187,81.915,3.229976744186047e-06 +17,15,210,110,1.2093023255813955,91.677,3.053790697674419e-06 +18,15,210,120,1.2558139534883723,100.07,2.9069767441860468e-06 +19,15,210,70,0.8837209302325582,51.267,3.506825581395349e-06 +20,15,210,60,0.7558139534883721,40.629,3.499139534883721e-06 +21,15,200,80,0.9186046511627908,56.87,3.189604651162791e-06 +22,15,210,80,1.0,60.0,3.4722209302325583e-06 +23,15,125,40,0.56,35.186,3.888888888888889e-06 +24,15,125,50,0.7022222222222223,42.461,3.901235555555556e-06 +25,15,130,80,1.097777777777778,60.0,3.811728888888889e-06 +26,15,135,80,1.1777777777777778,61.28,4.089506666666667e-06 +27,15,140,80,1.248888888888889,62.288,4.336417777777778e-06 +28,15,145,80,1.3155555555555556,63.224,4.567911111111111e-06 +29,15,120,80,0.8888888888888888,59.64,3.086417777777778e-06 +30,15,115,80,0.7866666666666666,59.354,2.73148e-06 +31,15,110,80,0.6844444444444444,59.166,2.376542222222222e-06 +32,15,210,50,0.6046511627906977,35.239,3.359174418604651e-06 +33,15,100,80,0.47111111111111115,56.704,1.6358044444444444e-06 +34,15,105,80,0.5822222222222222,58.981,2.0216044444444444e-06 +35,15,125,100,1.1377777777777778,67.754,3.1604933333333336e-06 +36,15,125,110,1.1777777777777778,71.361,2.9741866666666666e-06 +37,15,125,120,1.2177777777777778,74.997,2.818928888888889e-06 +38,15,125,70,0.9066666666666667,55.19,3.5978844444444443e-06 +39,15,125,60,0.8088888888888889,49.334,3.744857777777778e-06 +40,15,125,90,1.0755555555555556,64.087,3.319617777777778e-06 +41,15,210,40,0.4534883720930233,42.934,3.149220930232558e-06 +42,20,210,80,0.9418604651162791,64.186,3.2703488372093026e-06 +43,20,125,80,0.8933333333333332,61.937,3.1018533333333332e-06 +44,25,210,80,0.872093023255814,67.919,3.0281046511627907e-06 +45,25,125,80,0.7822222222222223,64.648,2.716048888888889e-06 +46,30,210,80,0.8255813953488372,70.003,2.8666046511627907e-06 +47,30,125,80,0.6755555555555556,66.366,2.34568e-06 diff --git a/src/fgem/data/powerplants/NRELORCPowerPlant_normalized.pkl b/src/fgem/data/powerplants/NRELORCPowerPlant_normalized.pkl new file mode 100755 index 0000000000000000000000000000000000000000..030a20e83125b182cbc441f3aa1b24a360703b34 GIT binary patch literal 1112 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%0AKy{OK2ZBWN%&2>9Y@Z;a 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 literal 0 HcmV?d00001 diff --git a/src/fgem/powerplant.py b/src/fgem/powerplant.py new file mode 100644 index 000000000..e236af494 --- /dev/null +++ b/src/fgem/powerplant.py @@ -0,0 +1,619 @@ +import math +import os +import pickle +from datetime import timedelta +from pathlib import Path + +import numpy as np +from scipy.spatial import cKDTree + +from .utils.utils import * + +parent_path = Path(__file__).parent + + +class CustomUnpickler(pickle.Unpickler): + + def find_class(self, module, name): + try: + return super().find_class(__name__, name) + except AttributeError: + return super().find_class(module, name) + + +class BasePowerPlant: + """Base class for defining a power plant.""" + + def __init__(self, ppc, Tres, cf, timestep=timedelta(hours=1)): + """Define attributes for the BasePowerPlant class. + + Args: + ppc (float): power plant nameplate capacity in MW. + Tres (float): reservoir temperature in deg C. + cf (float): capacity factor. + timestep (datetime, optional): simulation timestep size. Defaults to timedelta(hours=1). + """ + self.powerplant_capacity = ppc + self.cf = cf + + # default starting point + self.power_output_MWh_kg = 1e-5 + self.power_output_MWe = ppc + self.power_generation_MWh = ppc * 1 + self.T_mix = Tres + self.T_inj = Tres / 2 + self.timestep = timestep + + def compute_geofluid_consumption(self, T, T_amb, m_turbine): + """Compute geofluid consumption. + + Args: + T (float): power plant inlet temperature in deg C. + T_amb (float): ambient temperautre in deg C. + + Raises: + NotImplementedError: you must implemented this. + """ + raise NotImplementedError + + def compute_injection_temp(self, T, T_amb, m_turbine): + """Compute injection temperature. + + Args: + T (float): power plant inlet temperature in deg C. + T_amb (float): ambient temperautre in deg C. + + Raises: + NotImplementedError: you must implement this. + """ + raise NotImplementedError + + def compute_cplant(self, MaxProducedTemperature, min_cost=0): + """Compute power plant capex. + + Args: + MaxProducedTemperature (float): maximum produced geofluid temperature in deg C. + + Raises: + NotImplementedError: you must implement this. + """ + raise NotImplementedError + + def compute_thermalexergy(self, T, T_amb): + """Compute power plant thermal exergy for an inflowing geofluid at a given ambient temperature. + + Args: + T (float): power plant inlet temperature in deg C. + T_amb (float): ambient temperature in deg C. + + Returns: + float: thermal exergy in MJ/kg. + """ + + A = 4.041650 + B = -1.204e-2 + C = 1.60500e-5 + T_amb_k = T_amb + 273.15 # deg K + T_k = T + 273.15 # deg K + thermal_exergy = ( + ( + (A - B * T_amb_k) * (T_k - T_amb_k) + + (B - C * T_amb_k) / 2.0 * (T_k**2 - T_amb_k**2) + + C / 3.0 * (T_k**3 - T_amb_k**3) + - A * T_amb_k * np.log(T_k / T_amb_k) + ) + * 2.2046 + / 947.83 + ) # MJ/kg + + return thermal_exergy + + def compute_power_output(self, m_turbine): + return self.cf * min(self.powerplant_capacity, self.power_output_MWh_kg * (m_turbine * 3600)) + + def step( + self, + m_turbine, + T_prd_wh, + T_amb, + m_tes_out=0, + T_tes_out=100, + ): + """Step and update power plant. + + Args: + m_turbine (float): total mass flowing into the turbine in kg/s (including flow from both producers and thermal energy storage tank). + T_prd_wh (float): producer wellheat temperature in deg C. + T_amb (float): ambient temperature in deg C. + m_tes_out (float, optional): mass flow rate from the thermal energy storage tank in kg/s. Defaults to 0. + T_tes_out (float, optional): temperature of water of the thermal energy storage tank. Defaults to 100. + + """ + + # If we are using all geofluid to charge the tank, then there is no output + if m_turbine == 0: + self.power_output_MWe = 0 + self.power_generation_MWh = 0 + self.T_inj = self.compute_injection_temp(self.T_mix, T_amb, m_turbine) + return 0.0, 0.0, 0.0, 0.0, self.T_inj + else: + if m_tes_out > 0: + m_wh_to_turbine = m_turbine - m_tes_out + self.T_mix = ( + m_wh_to_turbine * heatcapacitywater(T_prd_wh) * T_prd_wh + + m_tes_out * heatcapacitywater(T_tes_out) * T_tes_out + ) / (m_wh_to_turbine * heatcapacitywater(T_prd_wh) + m_tes_out * heatcapacitywater(T_tes_out) + 1e-3) + else: + self.T_mix = T_prd_wh + + self.power_output_MWh_kg = self.compute_geofluid_consumption(self.T_mix, T_amb, m_turbine) + self.power_output_MWe = self.compute_power_output(m_turbine) + self.power_generation_MWh = self.power_output_MWe * (self.timestep.total_seconds() / 3600) + self.T_inj = self.compute_injection_temp(self.T_mix, T_amb, m_turbine) + + +class GEOPHIRESORCPowerPlant(BasePowerPlant): + """ORC Binary power plant based on GEOPHIRES.""" + + def __init__(self, ppc, Tres, cf=1.0): + """Define attributes for the BasePowerPlant class. + + Args: + ppc (float): power plant nameplate capacity in MW. + Tres (float): reservoir temperature in deg C. + cf (float): capacity factor. Defualts to 1. + """ + super(GEOPHIRESORCPowerPlant, self).__init__(ppc, Tres, cf) + + def compute_cplant(self, MaxProducedTemperature, min_cost=0): + """Compute power plant capex. + + Args: + MaxProducedTemperature (float): maximum produced geofluid temperature in deg C. + + Returns: + float: cost of power plant in USD/kW + """ + if MaxProducedTemperature < 150.0: + C3 = -1.458333e-3 + C2 = 7.6875e-1 + C1 = -1.347917e2 + C0 = 1.0075e4 + CCAPP1 = C3 * MaxProducedTemperature**3 + C2 * MaxProducedTemperature**2 + C1 * MaxProducedTemperature + C0 + else: + CCAPP1 = 2231 - 2 * (MaxProducedTemperature - 150.0) + + Cplantcorrelation = ( + max(min_cost, CCAPP1 * math.pow(self.powerplant_capacity / 15.0, -0.06)) + * 1e-6 + * self.powerplant_capacity + * 1e3 + ) # $MM + return Cplantcorrelation + + def compute_geofluid_consumption(self, T, T_amb, m_turbine): + """Compute geofluid consumption. + + Args: + T (float): power plant inlet temperature in deg C. + T_amb (float): ambient temperautre in deg C. + + Returns: + float: power plant output in MWh/kg. + """ + + self.thermal_exergy = self.compute_thermalexergy(T, T_amb) + if T_amb < 15.0: + C1 = 2.746e-3 + C0 = -8.3806e-2 + D1 = 2.713e-3 + D0 = -9.1841e-2 + Tfraction = (T_amb - 5.0) / 10.0 + else: + C1 = 2.713e-3 + C0 = -9.1841e-2 + D1 = 2.676e-3 + D0 = -1.012e-1 + Tfraction = (T_amb - 15.0) / 10.0 + etaull = C1 * T + C0 + etauul = D1 * T + D0 + self.etau = (1 - Tfraction) * etaull + Tfraction * etauul + + power_output_MWh_kg = max(self.thermal_exergy * self.etau / 3600, 0.0) # MWh/kg + + return power_output_MWh_kg # MWh/kg + + def compute_injection_temp(self, T, T_amb, m_turbine): + """Compute injection temperature. + + Args: + T (float): power plant inlet temperature in deg C. + T_amb (float): ambient temperautre in deg C. + + Returns: + float: power plant condenser outlet temperature in deg C. + """ + + """Compute the exiting (reinjection) water temperature of an ORC binary power plant.""" + + if T_amb < 15.0: + C1 = 0.0894 + C0 = 55.6 + D1 = 0.0894 + D0 = 62.6 + Tfraction = (T_amb - 5.0) / 10.0 + else: + C1 = 0.0894 + C0 = 62.6 + D1 = 0.0894 + D0 = 69.6 + Tfraction = (T_amb - 15.0) / 10.0 + reinjtll = C1 * T + C0 + reinjtul = D1 * T + D0 + Tinj = max((1.0 - Tfraction) * reinjtll + Tfraction * reinjtul, 0.0) # deg C + + return Tinj # deg C + + +class GEOPHIRESFlashPowerPlant(BasePowerPlant): + """Single Flash Binary power plant.""" + + def __init__(self, ppc, Tres, cf=1.0): + """Define attributes for the BasePowerPlant class. + + Args: + ppc (float): power plant nameplate capacity in MW. + Tres (float): reservoir temperature in deg C. + cf (float): capacity factor. Defualts to 1. + """ + + super(GEOPHIRESFlashPowerPlant, self).__init__(ppc, Tres, cf) + + def compute_cplant(self, MaxProducedTemperature, min_cost=0): + """Compute power plant capex. + + Args: + MaxProducedTemperature (float): maximum produced geofluid temperature in deg C. + + Returns: + float: cost of power plant in USD/kW + """ + + if self.powerplant_capacity < 10: + C2 = 4.8472e-2 + C1 = -35.2186 + C0 = 8.4474e3 + D2 = 4.0604e-2 + D1 = -29.3817 + D0 = 6.9911e3 + PLL = 5.0 + PRL = 10.0 + elif self.powerplant_capacity < 25: + C2 = 4.0604e-2 + C1 = -29.3817 + C0 = 6.9911e3 + D2 = 3.2773e-2 + D1 = -23.5519 + D0 = 5.5263e3 + PLL = 10.0 + PRL = 25.0 + elif self.powerplant_capacity < 50: + C2 = 3.2773e-2 + C1 = -23.5519 + C0 = 5.5263e3 + D2 = 3.4716e-2 + D1 = -23.8139 + D0 = 5.1787e3 + PLL = 25.0 + PRL = 50.0 + elif self.powerplant_capacity < 75: + C2 = 3.4716e-2 + C1 = -23.8139 + C0 = 5.1787e3 + D2 = 3.5271e-2 + D1 = -24.3962 + D0 = 5.1972e3 + PLL = 50.0 + PRL = 75.0 + else: + C2 = 3.5271e-2 + C1 = -24.3962 + C0 = 5.1972e3 + D2 = 3.3908e-2 + D1 = -23.4890 + D0 = 5.0238e3 + PLL = 75.0 + PRL = 100.0 + CCAPPLL = C2 * MaxProducedTemperature**2 + C1 * MaxProducedTemperature + C0 + CCAPPRL = D2 * MaxProducedTemperature**2 + D1 * MaxProducedTemperature + D0 + b = math.log(CCAPPRL / CCAPPLL) / math.log(PRL / PLL) + a = CCAPPRL / PRL**b + Cplantcorrelation = ( + max(min_cost, 0.8 * a * math.pow(self.powerplant_capacity, b)) * self.powerplant_capacity * 1000.0 / 1e6 + ) # factor 0.75 to make double flash 25% more expansive than single flash + + return Cplantcorrelation + + def compute_geofluid_consumption(self, T, T_amb, m_turbine): + """Compute geofluid consumption. + + Args: + T (float): power plant inlet temperature in deg C. + T_amb (float): ambient temperautre in deg C. + + Returns: + float: power plant output in MWh/kg. + """ + + self.thermal_exergy = self.compute_thermalexergy(T, T_amb) + if T_amb < 15.0: + C2 = -4.27318e-7 + C1 = 8.65629e-4 + C0 = 1.78931e-1 + D2 = -5.85412e-7 + D1 = 9.68352e-4 + D0 = 1.58056e-1 + Tfraction = (T_amb - 5.0) / 10.0 + else: + C2 = -5.85412e-7 + C1 = 9.68352e-4 + C0 = 1.58056e-1 + D2 = -7.78996e-7 + D1 = 1.09230e-3 + D0 = 1.33708e-1 + Tfraction = (T_amb - 15.0) / 10.0 + etaull = C2 * T**2 + C1 * T + C0 + etauul = D2 * T**2 + D1 * T + D0 + self.etau = (1.0 - Tfraction) * etaull + Tfraction * etauul + + power_output_MWh_kg = max(self.thermal_exergy * self.etau / 3600, 0.0) # MWh/kg + + return power_output_MWh_kg # MWh/kg + + def compute_injection_temp(self, T, T_amb, m_turbine): + """Compute injection temperature. + + Args: + T (float): power plant inlet temperature in deg C. + T_amb (float): ambient temperautre in deg C. + + Returns: + float: power plant condenser outlet temperature in deg C. + """ + + """Compute the exiting (reinjection) water temperature of an ORC binary power plant.""" + + if T_amb < 15.0: + C2 = -1.11519e-3 + C1 = 7.79126e-1 + C0 = -10.2242 + D2 = -1.10232e-3 + D1 = 7.83893e-1 + D0 = -5.17039 + Tfraction = (T_amb - 5.0) / 10.0 + else: + C2 = -1.10232e-3 + C1 = 7.83893e-1 + C0 = -5.17039 + D2 = -1.08914e-3 + D1 = 7.88562e-1 + D0 = -1.89707e-1 + Tfraction = (T_amb - 15.0) / 10.0 + reinjtll = C2 * T**2 + C1 * T + C0 + reinjtul = D2 * T**2 + D1 * T + D0 + Tinj = max((1.0 - Tfraction) * reinjtll + Tfraction * reinjtul, 0.0) + + return Tinj # deg C + + +class HighEnthalpyCLGWGPowerPlant(BasePowerPlant): + """On/Off-Design Air-cooled ORC Binary power plant developed in Python by Aljubran et al. (2024).""" + + def __init__(self, Tres, Tamb, m_prd, num_prd, cf=1.0, high_resolution=False, k=2): + """Define attributes for the BasePowerPlant class. + + Args: + ppc (float): power plant nameplate capacity in MW. + Tres (float): reservoir temperature in deg C. + m_prd (float): mass flow rate of a single producer in the project in kg/s. + cf (float): capacity factor. Defualts to 1. + high_resolution (bool): if True, a higher resolution power plant model is loaded, but it is slower + """ + self.Tres_design = Tres + self.Tamb_design = Tamb + self.m_prd_design = m_prd + self.num_prd = num_prd + self.k = k + self.model = CustomUnpickler( + open(os.path.join(parent_path, 'data/powerplants', 'HighEnthalpyCLGWGPowerPlant.pkl'), 'rb') + ).load() + + model_input = np.array([[self.Tamb_design, self.Tres_design, self.m_prd_design]]) + model_output = self.model.predict(model_input)[0] + + ppc = model_output[0] * num_prd # MWe power plant capacity for all wells + super(HighEnthalpyCLGWGPowerPlant, self).__init__(ppc, Tres, cf) + + self.power_output_MWh_kg = model_output[0] / self.m_prd_design / 3600 # MWh/kg + self.T_inj = model_output[1] # deg C + + def compute_cplant(self, MaxProducedTemperature, min_cost=0): + """Compute power plant capex. + + Args: + MaxProducedTemperature (float): maximum produced geofluid temperature in deg C. + + Returns: + float: cost of power plant in USD/kW + """ + if MaxProducedTemperature < 150.0: + C3 = -1.458333e-3 + C2 = 7.6875e-1 + C1 = -1.347917e2 + C0 = 1.0075e4 + CCAPP1 = C3 * MaxProducedTemperature**3 + C2 * MaxProducedTemperature**2 + C1 * MaxProducedTemperature + C0 + else: + CCAPP1 = 2231 - 2 * (MaxProducedTemperature - 150.0) + Cplantcorrelation = ( + max(min_cost, CCAPP1 * math.pow(self.powerplant_capacity / 15.0, -0.06)) + * 1e-6 + * self.powerplant_capacity + * 1e3 + ) # $MM + return Cplantcorrelation + + def compute_geofluid_consumption(self, T, T_amb, m_turbine): + """Compute geofluid consumption. + + Args: + T (float): power plant inlet temperature in deg C. + T_amb (float): ambient temperautre in deg C. + + Returns: + float: power plant output in MWh/kg. + """ + + m_prd = m_turbine / self.num_prd # single well flow rate + + model_input = np.array([[T_amb, T, m_prd]]) + model_output = self.model.predict(model_input)[0] + + self.power_output_MWh_kg = max(model_output[0] / m_prd / 3600, 0) # MWh/kg + if self.power_output_MWh_kg == 0: + self.T_inj = T + else: + self.T_inj = model_output[1] # deg C + + return self.power_output_MWh_kg # MWh/kg + + def compute_injection_temp(self, T, T_amb, m_turbine): + """Compute injection temperature. + + Args: + T (float): power plant inlet temperature in deg C. + T_amb (float): ambient temperautre in deg C. + + Returns: + float: power plant condenser outlet temperature in deg C. + """ + + """Compute the exiting (reinjection) water temperature of an ORC binary power plant.""" + + return self.T_inj # deg C + + +class ORCPowerPlant(BasePowerPlant): + """On/Off-Design Air-cooled ORC Binary power plant developed in Python by Aljubran et al. (2024).""" + + def __init__(self, Tres, Tamb, m_prd, num_prd=None, ppc=None, cf=1.0, k=2): + """Define attributes for the BasePowerPlant class. + + Args: + Tres (float): reservoir temperature in deg C. + Tamb (float): ambient temperature in deg C. + m_prd (float): mass flow rate of a single producer in the project in kg/s. + num_prd (int): number of producers (Note: only used if power plant capacity 'ppc' is not provided) + ppc (float): power plant nameplate capacity in MW. + cf (float): capacity factor. Defualts to 1. + """ + + self.Tres_design = Tres + self.Tamb_design = Tamb + self.m_prd_design = m_prd + self.num_prd = num_prd + self.k = k + self.model = CustomUnpickler( + open(os.path.join(parent_path, 'data/powerplants', 'ORCPowerPlant.pkl'), 'rb') + ).load() + + self.keys = np.array(list(self.model.keys())) + tree = cKDTree(self.keys) + distances, indices = tree.query(np.array([[self.Tamb_design, self.Tres_design, self.m_prd_design]]), k=self.k) + self.distances, self.indices = distances[0], indices[0] + if isinstance(self.distances, float): + self.distances, self.indices = np.array([self.distances]), np.array([self.indices]) + self.inv_distances = ( + 1 / (self.distances + 1e-3) ** 2 + ) # important choice on how much to interpolate ... more impactful when simualted data is sparse ... + self.inv_distances = self.inv_distances / self.inv_distances.sum() + self.inv_distances = self.inv_distances[:, None] + self.model_list = [self.model[tuple(self.keys[self.indices][i])] for i in range(self.k)] + + model_input = np.array([[self.Tamb_design, self.Tres_design, self.m_prd_design]]) + preds = np.vstack([m.predict(model_input) for m in self.model_list]) + model_output = (preds * self.inv_distances).sum(axis=0) + + if ppc is None: + ppc = max(model_output[0] * num_prd, 1) # MWe power plant capacity for all wells + super(ORCPowerPlant, self).__init__(ppc, Tres, cf) + + self.power_output_MWh_kg = np.clip( + model_output[0] / self.m_prd_design / 3600, a_min=0.0, a_max=2.5e-4 + ) # MWh/kg + self.T_inj = np.clip(model_output[1], a_min=self.Tamb_design, a_max=self.Tres_design) # deg C + + if self.num_prd is None: + m_g = ppc / nonzero(self.power_output_MWh_kg) / 3600 # kg/s + self.num_prd = np.ceil(m_g / m_prd).astype(int) + + def compute_cplant(self, MaxProducedTemperature, min_cost=0): + """Compute power plant capex. + + Args: + MaxProducedTemperature (float): maximum produced geofluid temperature in deg C. + + Returns: + float: cost of power plant in USD/kW + """ + + if MaxProducedTemperature < 150.0: + C3 = -1.458333e-3 + C2 = 7.6875e-1 + C1 = -1.347917e2 + C0 = 1.0075e4 + CCAPP1 = C3 * MaxProducedTemperature**3 + C2 * MaxProducedTemperature**2 + C1 * MaxProducedTemperature + C0 + else: + CCAPP1 = 2231 - 2 * (MaxProducedTemperature - 150.0) + Cplantcorrelation = ( + max(min_cost, CCAPP1 * math.pow(self.powerplant_capacity / 15.0, -0.06)) + * 1e-6 + * self.powerplant_capacity + * 1e3 + ) # $MM + return Cplantcorrelation + + def compute_geofluid_consumption(self, T, T_amb, m_turbine): + """Compute geofluid consumption. + + Args: + T (float): power plant inlet temperature in deg C. + T_amb (float): ambient temperautre in deg C. + + Returns: + float: power plant output in MWh/kg. + """ + + m_prd = m_turbine / self.num_prd # single well flow rate + model_input = np.array([[T_amb, T, m_prd]]) + + preds = np.vstack([m.predict(model_input) for m in self.model_list]) + model_output = (preds * self.inv_distances).sum(axis=0) + self.power_output_MWh_kg = np.clip(model_output[0] / m_prd / 3600, a_min=0.0, a_max=2.5e-4) # MWh/kg + self.T_inj = np.clip(model_output[1], a_min=T_amb, a_max=T) # deg C + + return self.power_output_MWh_kg # MWh/kg + + def compute_injection_temp(self, T, T_amb, m_turbine): + """Compute injection temperature. + + Args: + T (float): power plant inlet temperature in deg C. + T_amb (float): ambient temperautre in deg C. + + Returns: + float: power plant condenser outlet temperature in deg C. + """ + + """Compute the exiting (reinjection) water temperature of an ORC binary power plant.""" + + return self.T_inj # deg C diff --git a/src/fgem/utils/__init__.py b/src/fgem/utils/__init__.py new file mode 100755 index 000000000..2900eda72 --- /dev/null +++ b/src/fgem/utils/__init__.py @@ -0,0 +1,3 @@ +from .config import * +from .constants import * +from .utils import * diff --git a/src/fgem/utils/config.py b/src/fgem/utils/config.py new file mode 100755 index 000000000..69659f3c8 --- /dev/null +++ b/src/fgem/utils/config.py @@ -0,0 +1,17 @@ +import json + + +def get_config_from_json(json_file): + """Parse the configurations from the config json file provided. + + Args: + json_file (str): file path to configuration json file + + Returns: + dict: configuration in json format + """ + + with open(json_file) as config_file: + config_dict = json.load(config_file) + + return config_dict diff --git a/src/fgem/utils/constants.py b/src/fgem/utils/constants.py new file mode 100755 index 000000000..c95c3c4c8 --- /dev/null +++ b/src/fgem/utils/constants.py @@ -0,0 +1,198 @@ +us_state_to_abbrev = { + 'Alabama': 'AL', + 'Alaska': 'AK', + 'Arizona': 'AZ', + 'Arkansas': 'AR', + 'California': 'CA', + 'Colorado': 'CO', + 'Connecticut': 'CT', + 'Delaware': 'DE', + 'Florida': 'FL', + 'Georgia': 'GA', + 'Hawaii': 'HI', + 'Idaho': 'ID', + 'Illinois': 'IL', + 'Indiana': 'IN', + 'Iowa': 'IA', + 'Kansas': 'KS', + 'Kentucky': 'KY', + 'Louisiana': 'LA', + 'Maine': 'ME', + 'Maryland': 'MD', + 'Massachusetts': 'MA', + 'Michigan': 'MI', + 'Minnesota': 'MN', + 'Mississippi': 'MS', + 'Missouri': 'MO', + 'Montana': 'MT', + 'Nebraska': 'NE', + 'Nevada': 'NV', + 'New Hampshire': 'NH', + 'New Jersey': 'NJ', + 'New Mexico': 'NM', + 'New York': 'NY', + 'North Carolina': 'NC', + 'North Dakota': 'ND', + 'Ohio': 'OH', + 'Oklahoma': 'OK', + 'Oregon': 'OR', + 'Pennsylvania': 'PA', + 'Rhode Island': 'RI', + 'South Carolina': 'SC', + 'South Dakota': 'SD', + 'Tennessee': 'TN', + 'Texas': 'TX', + 'Utah': 'UT', + 'Vermont': 'VT', + 'Virginia': 'VA', + 'Washington': 'WA', + 'West Virginia': 'WV', + 'Wisconsin': 'WI', + 'Wyoming': 'WY', + 'District of Columbia': 'DC', + 'American Samoa': 'AS', + 'Guam': 'GU', + 'Northern Mariana Islands': 'MP', + 'Puerto Rico': 'PR', + 'United States Minor Outlying Islands': 'UM', + 'U.S. Virgin Islands': 'VI', +} + +WESTERN_STATE_NAMES = [ + 'Arizona', + 'California', + 'Colorado', + 'Idaho', + 'Montana', + 'Nevada', + 'New Mexico', + 'Oregon', + 'Utah', + 'Washington', + 'Wyoming', +] + +regions_to_states = { + 'Southeast': [ + 'West Virginia', + 'District of Columbia', + 'Maryland', + 'Virginia', + 'Kentucky', + 'Tennessee', + 'North Carolina', + 'Mississippi', + 'Arkansas', + 'Louisiana', + 'Alabama', + 'Georgia', + 'South Carolina', + 'Florida', + 'Delaware', + ], + 'Southwest': ['Arizona', 'New Mexico', 'Oklahoma', 'Texas'], + 'West': [ + 'Washington', + 'Oregon', + 'California', + 'Nevada', + 'Idaho', + 'Montana', + 'Wyoming', + 'Utah', + 'Colorado', + 'Alaska', + 'Hawaii', + ], + 'Midwest': [ + 'North Dakota', + 'South Dakota', + 'Nebraska', + 'Kansas', + 'Minnesota', + 'Iowa', + 'Missouri', + 'Wisconsin', + 'Illinois', + 'Michigan', + 'Indiana', + 'Ohio', + ], + 'Northeast': [ + 'Maine', + 'Vermont', + 'New York', + 'New Hampshire', + 'Massachusetts', + 'Rhode Island', + 'Connecticut', + 'New Jersey', + 'Pennsylvania', + ], +} + +states_to_regions = { + 'Washington': 'West', + 'Oregon': 'West', + 'California': 'West', + 'Nevada': 'West', + 'Idaho': 'West', + 'Montana': 'West', + 'Wyoming': 'West', + 'Utah': 'West', + 'Colorado': 'West', + 'Alaska': 'West', + 'Hawaii': 'West', + 'Maine': 'Northeast', + 'Vermont': 'Northeast', + 'New York': 'Northeast', + 'New Hampshire': 'Northeast', + 'Massachusetts': 'Northeast', + 'Rhode Island': 'Northeast', + 'Connecticut': 'Northeast', + 'New Jersey': 'Northeast', + 'Pennsylvania': 'Northeast', + 'North Dakota': 'Midwest', + 'South Dakota': 'Midwest', + 'Nebraska': 'Midwest', + 'Kansas': 'Midwest', + 'Minnesota': 'Midwest', + 'Iowa': 'Midwest', + 'Missouri': 'Midwest', + 'Wisconsin': 'Midwest', + 'Illinois': 'Midwest', + 'Michigan': 'Midwest', + 'Indiana': 'Midwest', + 'Ohio': 'Midwest', + 'West Virginia': 'Southeast', + 'District of Columbia': 'Southeast', + 'Maryland': 'Southeast', + 'Virginia': 'Southeast', + 'Kentucky': 'Southeast', + 'Tennessee': 'Southeast', + 'North Carolina': 'Southeast', + 'Mississippi': 'Southeast', + 'Arkansas': 'Southeast', + 'Louisiana': 'Southeast', + 'Alabama': 'Southeast', + 'Georgia': 'Southeast', + 'South Carolina': 'Southeast', + 'Florida': 'Southeast', + 'Delaware': 'Southeast', + 'Arizona': 'Southwest', + 'New Mexico': 'Southwest', + 'Oklahoma': 'Southwest', + 'Texas': 'Southwest', +} + +UNIFIED_CRS = 'EPSG:3857' +LATLON_CRS = 'EPSG:4326' + +US_LATMIN, US_LATMAX = 24.521208, 49.382808 +US_LONMIN, US_LONMAX = -124.736342, -66.945392 + +SMALL_NUM = 1e-3 +SMALLER_NUM = 1e-6 + +# invert the dictionary +abbrev_to_us_state = dict(map(reversed, us_state_to_abbrev.items())) diff --git a/src/fgem/utils/geocluster_utils.py b/src/fgem/utils/geocluster_utils.py new file mode 100755 index 000000000..ea5a445fe --- /dev/null +++ b/src/fgem/utils/geocluster_utils.py @@ -0,0 +1,2451 @@ +import itertools as iter +import sys + +import h5py +import numpy as np +import scipy.io +from matplotlib import cm +from matplotlib import pyplot as plt +from scipy.interpolate import interpn + + +class data: + def __init__(self, fname, case, fluid): + + self.fluid = fluid + self.case = case + + with h5py.File(fname, 'r') as file: + fixed_loc = '/' + case + '/fixed_params/' + input_loc = '/' + case + '/' + fluid + '/input/' + output_loc = '/' + case + '/' + fluid + '/output/' + + # independent vars + self.mdot = file[input_loc + 'mdot'][:] # i0 + self.L2 = file[input_loc + 'L2'][:] # i1 + self.L1 = file[input_loc + 'L1'][:] # i2 + self.grad = file[input_loc + 'grad'][:] # i3 + self.D = file[input_loc + 'D'][:] # i4 + self.Tinj = file[input_loc + 'T_i'][:] # i5 + self.k = file[input_loc + 'k_rock'][:] # i6 + self.time = file[input_loc + 'time'][:] # i7 + self.ivars = (self.mdot, self.L2, self.L1, self.grad, self.D, self.Tinj, self.k, self.time) + + # fixed vars + self.Pinj = file[fixed_loc + 'Pinj'][()] + self.Tamb = file[fixed_loc + 'Tamb'][()] + + # dim = Mdot x L2 x L1 x grad x D x Tinj x k + self.Wt = file[output_loc + 'Wt'][:] # int mdot * dh dt + self.We = file[output_loc + 'We'][:] # int mdot * (dh - Too * ds) dt + + self.GWhr = 1e6 * 3600000.0 + + self.kWe_avg = self.We * self.GWhr / (1000.0 * self.time[-1] * 86400.0 * 365.0) + self.kWt_avg = self.Wt * self.GWhr / (1000.0 * self.time[-1] * 86400.0 * 365.0) + + # dim = Mdot x L2 x L1 x grad x D x Tinj x k x time + self.shape = ( + len(self.mdot), + len(self.L2), + len(self.L1), + len(self.grad), + len(self.D), + len(self.Tinj), + len(self.k), + len(self.time), + ) + self.Tout = self.__uncompress(file, output_loc, 'Tout') + self.Pout = self.__uncompress(file, output_loc, 'Pout') + + self.CP_fluid = 'CO2' + if fluid == 'H2O': + self.CP_fluid = 'H2O' + + def __uncompress(self, file, output_loc, state): + U = file[output_loc + state + '/' + 'U'][:] + sigma = file[output_loc + state + '/' + 'sigma'][:] + Vt = file[output_loc + state + '/' + 'Vt'][:] + M_k = np.dot(U, np.dot(np.diag(sigma), Vt)) + + shape = self.shape + valid_runs = np.argwhere(np.isfinite(self.We.flatten()))[:, 0] + M_k_full = np.full((shape[-1], np.prod(shape[:-1])), np.nan) + M_k_full[:, valid_runs] = M_k + return np.reshape(M_k_full.T, shape) + + def interp_outlet_states(self, point): + + points = list( + iter.product( + (point[0],), (point[1],), (point[2],), (point[3],), (point[4],), (point[5],), (point[6],), self.time + ) + ) + Tout = interpn(self.ivars, self.Tout, points) + Pout = interpn(self.ivars, self.Pout, points) + + return Tout, Pout + + def interp_kWe_avg(self, point): + ivars = self.ivars[:-1] + return self.GWhr * interpn(ivars, self.We, point) / (1000.0 * self.time[-1] * 86400.0 * 365.0) + + def interp_kWt_avg(self, point): + ivars = self.ivars[:-1] + return self.GWhr * interpn(ivars, self.Wt, point) / (1000.0 * self.time[-1] * 86400.0 * 365.0) + + +class TEA: + def __init__( + self, + Fluid, + End_use, + Configuration, + Flow_user, + Hor_length_user, + Depth_user, + Gradient_user, + Diameter_user, + Tin_user, + krock_user, + Drilling_cost_per_m, + O_and_M_cost_plant, + Discount_rate, + Pump_efficiency, + Lifetime, + Direct_use_heat_cost_per_kWth, + Electricity_rate, + Power_plant_cost_per_kWe, + T0, + P0, + Turbine_isentropic_efficiency, + Generator_efficiency, + Compressor_isentropic_efficiency, + Pre_Cooling_Delta_T, + Turbine_outlet_pressure, + ): + self.Fluid = Fluid + self.End_use = End_use + self.Configuration = Configuration + self.Flow_user = Flow_user + self.Hor_length_user = Hor_length_user + self.Depth_user = Depth_user + self.Gradient_user = Gradient_user + self.Diameter_user = Diameter_user + self.Tin_user = Tin_user + self.krock_user = krock_user + self.Drilling_cost_per_m = Drilling_cost_per_m + self.O_and_M_cost_plant = O_and_M_cost_plant + self.Discount_rate = Discount_rate + self.Pump_efficiency = Pump_efficiency + self.Lifetime = Lifetime + self.Direct_use_heat_cost_per_kWth = Direct_use_heat_cost_per_kWth + self.Electricity_rate = Electricity_rate + self.Power_plant_cost_per_kWe = Power_plant_cost_per_kWe + self.T0 = T0 + self.P0 = P0 + self.Turbine_isentropic_efficiency = Turbine_isentropic_efficiency + self.Generator_efficiency = Generator_efficiency + self.Compressor_isentropic_efficiency = Compressor_isentropic_efficiency + self.Pre_Cooling_Delta_T = Pre_Cooling_Delta_T + self.Turbine_outlet_pressure = Turbine_outlet_pressure + + # self.filename = 'clgs_results.h5' #Filename of h5 database with simulation results [-] + self.filename = 'clgs_results_final.h5' # Filename of h5 database with simulation results [-] + self.Number_of_points_per_year = 4 # Number of time steps per year in database [-] (must be 4) + + self.point = (Flow_user, Hor_length_user, Depth_user, Gradient_user, Diameter_user, Tin_user, krock_user) + + self.P_in = 2e7 # Constant Injection pressure [Pa] + self.T_in = Tin_user - 273.15 # Injection temperature [deg.C] + + def verify(self): # Verify inputs are within allowable bounds + self.error = 0 + if self.Fluid != 1 and self.Fluid != 2: + print('Error: Fluid must be 1 (H2O) or 2 (CO2). Simulation terminated.') + self.error = 1 + if self.End_use != 1 and self.End_use != 2: + print('Error: End_use must be 1 (Direct-Use) or 2 (Electricity). Simulation terminated.') + self.error = 1 + if self.Flow_user < 5 or self.Flow_user > 100: + print('Error: Flow rate must be between 5 and 100 kg/s. Simulation terminated.') + self.error = 1 + if self.Hor_length_user < 1000 or self.Hor_length_user > 20000: + print('Error: Horizontal length must be between 1,000 and 20,000 m. Simulation terminated.') + self.error = 1 + if self.Depth_user < 1000 or self.Depth_user > 5000: + print('Error: Vertical depth must be between 1,000 and 5,000 m. Simulation terminated.') + self.error = 1 + if self.Gradient_user < 0.03 or self.Gradient_user > 0.07: + print('Error: Geothermal gradient must be between 0.03 and 0.07 degrees C per m. Simulation terminated.') + self.error = 1 + if self.Diameter_user < 0.2159 or self.Diameter_user > 0.4445: + print('Error: Wellbore diameter must be between 0.2159 and 0.4445 m. Simulation terminated.') + self.error = 1 + if self.Tin_user < 303.15 or self.Tin_user > 333.15: + print('Error: Injection temperature must be between 303.15 and 333.15 K. Simulation terminated.') + self.error = 1 + if self.krock_user < 1.5 or self.krock_user > 4.5: + print('Error: Rock thermal conductivity must be between 1.5 and 4.5 W/m/K. Simulation terminated.') + self.error = 1 + if self.Drilling_cost_per_m < 0 or self.Drilling_cost_per_m > 10000: + print( + 'Error: Drilling costs per m of measured depth must be between 0 and 10,000 $/m. Simulation terminated.' + ) + self.error = 1 + if self.O_and_M_cost_plant < 0 or self.O_and_M_cost_plant > 0.2: + print( + 'Error: Operation & maintance cost of surface plant (expressed as fraction of total surface plant capital cost) must be between 0 and 0.2. Simulation terminated.' + ) + self.error = 1 + if self.Discount_rate < 0 or self.Discount_rate > 0.2: + print('Error: Discount rate must be between 0 and 0.2. Simulation terminated.') + self.error = 1 + if self.Pump_efficiency < 0.5 or self.Pump_efficiency > 1: + print('Error: Pump efficiency must be between 0.5 and 1. Simulation terminated.') + self.error = 1 + if self.Lifetime < 5 or self.Lifetime > 40: + print('Error: System lifetime must be between 5 and 40 years. Simulation terminated.') + self.error = 1 + if isinstance(self.Lifetime, int) == False: + print('Error: System lifetime must be integer. Simulation terminated.') + self.error = 1 + if self.End_use == 1: + if self.Direct_use_heat_cost_per_kWth < 0 or self.Direct_use_heat_cost_per_kWth > 10000: + print( + 'Error: Capital cost for direct-use surface plant must be between 0 and 10,000 $/kWth. Simulation terminated.' + ) + self.error = 1 + if self.Electricity_rate < 0 or self.Electricity_rate > 0.5: + print( + 'Error: Electricity rate in direct-use for pumping power must be between 0 and 0.5 $/kWh. Simulation terminated.' + ) + self.error = 1 + if self.End_use == 2: + if self.Power_plant_cost_per_kWe < 0 or self.Power_plant_cost_per_kWe > 10000: + print('Error: Power plant capital cost must be between 0 and 10,000 $/kWe. Simulation terminated.') + self.error = 1 + if self.T0 < 278.15 or self.T0 > 303.15: + print('Error: Dead-state temperature must be between 278.15 and 303.15 K. Simulation terminated.') + self.error = 1 + if self.P0 < 0.8e5 or self.P0 > 1.1e5: + print('Error: Dead state pressure must be between 0.8e5 and 1.1e5 Pa. Simulation terminated.') + self.error = 1 + if self.Fluid == 2 and self.End_use == 2: + if self.Turbine_isentropic_efficiency < 0.8 or self.Turbine_isentropic_efficiency > 1: + print('Error: Turbine isentropic efficiency must be between 0.8 and 1. Simulation terminated.') + self.error = 1 + if self.Generator_efficiency < 0.8 or self.Generator_efficiency > 1: + print('Error: Generator efficiency must be between 0.8 and 1. Simulation terminated.') + self.error = 1 + if self.Compressor_isentropic_efficiency < 0.8 or self.Compressor_isentropic_efficiency > 1: + print('Error: Compressor isentropic efficiency must be between 0.8 and 1. Simulation terminated.') + self.error = 1 + if self.Pre_Cooling_Delta_T < 0 or self.Pre_Cooling_Delta_T > 15: + print( + 'Error: CO2 temperature decline after turbine and before compressor must be between 0 and 15 degrees C. Simulation terminated.' + ) + self.error = 1 + if self.Turbine_outlet_pressure < 75 or self.Turbine_outlet_pressure > 200: + print('Error: CO2 turbine outlet pressure must be between 75 and 200 bar. Simulation terminated.') + self.error = 1 + return self.error + + def initialize(self): + + if self.Fluid == 1: + if self.Configuration == 1: + self.u_H2O = data(self.filename, 'utube', 'H2O') + elif self.Configuration == 2: + self.u_H2O = data(self.filename, 'coaxial', 'H2O') + self.timearray = self.u_H2O.time + self.FlowRateVector = self.u_H2O.mdot # length of 26 + self.HorizontalLengthVector = self.u_H2O.L2 # length of 20 + self.DepthVector = self.u_H2O.L1 # length of 9 + self.GradientVector = self.u_H2O.grad # length of 5 + self.DiameterVector = self.u_H2O.D # length of 3 + self.TinVector = self.u_H2O.Tinj # length of 3 + self.KrockVector = self.u_H2O.k # length of 3 + self.Fluid_name = 'Water' + elif self.Fluid == 2: + if self.Configuration == 1: + self.u_sCO2 = data(self.filename, 'utube', 'sCO2') + elif self.Configuration == 2: + self.u_sCO2 = data(self.filename, 'coaxial', 'sCO2') + self.timearray = self.u_sCO2.time + self.FlowRateVector = self.u_sCO2.mdot # length of 26 + self.HorizontalLengthVector = self.u_sCO2.L2 # length of 20 + self.DepthVector = self.u_sCO2.L1 # length of 9 + self.GradientVector = self.u_sCO2.grad # length of 5 + self.DiameterVector = self.u_sCO2.D # length of 3 + self.TinVector = self.u_sCO2.Tinj # length of 3 + self.KrockVector = self.u_sCO2.k # length of 3 + self.Fluid_name = 'CarbonDioxide' + + self.numberofcases = ( + len(self.FlowRateVector) + * len(self.HorizontalLengthVector) + * len(self.DepthVector) + * len(self.GradientVector) + * len(self.DiameterVector) + * len(self.TinVector) + * len(self.KrockVector) + ) + + self.Time_array = np.linspace( + 0, self.Lifetime * 365 * 24 * 3600, 1 + self.Lifetime * self.Number_of_points_per_year + ) # [s] + self.Linear_time_distribution = self.Time_array / 365 / 24 / 3600 + self.TNOP = self.Lifetime * self.Number_of_points_per_year + 1 # Total number of points for selected lifetime + # Find closests lifetime + closestlifetime = self.timearray.flat[np.abs(self.timearray - self.Lifetime).argmin()] + self.indexclosestlifetime = np.where(self.timearray == closestlifetime)[0][0] + + # load property data + if self.Fluid == 1: + mat = scipy.io.loadmat('properties_H2O.mat') + else: + mat = scipy.io.loadmat('properties_CO2v2.mat') + additional_mat = scipy.io.loadmat('additional_properties_CO2v2.mat') + self.Pvector = mat['Pvector'][0] + self.Tvector = mat['Tvector'][0] + self.density = mat['density'] + self.enthalpy = mat['enthalpy'] + self.entropy = mat['entropy'] + if self.Fluid == 2: + self.Pvector_ap = additional_mat['Pvector_ap'][0] + self.hvector_ap = additional_mat['hvector_ap'][0] + self.svector_ap = additional_mat['svector_ap'][0] + self.TPh = additional_mat['TPh'] + self.hPs = additional_mat['hPs'] + + # Define ORC power plant conversion efficiencies + self.Utilization_efficiency_correlation_temperatures = np.array( + [100, 200, 385] + ) # Linear correlation assumed here based on GEOPHIRES ORC correlation between 100 and 200 deg C [deg.C] plus plateaued above 200 deg. C + self.Utilization_efficiency_correlation_conversion = np.array( + [0.2, 0.45, 0.45] + ) # Efficiency of ORC conversion from production exergy to electricity based on GEOPHIRES correlation [-] + self.Heat_to_power_efficiency_correlation_temperatures = np.array( + [100, 200, 385] + ) # Linear correlation based on Chad Augustine's thesis [deg.C] plus plateaued above 200 deg. C + self.Heat_to_power_efficiency_correlation_conversion = np.array( + [0.05, 0.14, 0.14] + ) # Conversion from enthalpy to electricity [-] + + # Calculate dead-state enthalpy and entropy in case of electricity production + if self.End_use == 2: + self.h_0 = interpn((self.Pvector, self.Tvector), self.enthalpy, np.array([self.P0, self.T0]))[ + 0 + ] # dead-state enthalpy [J/kg] + self.s_0 = interpn((self.Pvector, self.Tvector), self.entropy, np.array([self.P0, self.T0]))[ + 0 + ] # dead-state entropy [J/kg/K] + + # Pre-populate specific heat capacity of air in case of electricity production + if self.End_use == 2: + self.Tair_for_cp_array = np.linspace(0, 100, num=10) + # self.cp_air_array = CP.PropsSI('C','P',self.P0,'T',self.Tair_for_cp_array+273.15,'air') + self.cp_air_array = np.array( + [ + 1005.65818063, + 1005.87727966, + 1006.19281999, + 1006.60616167, + 1007.11890862, + 1007.73265999, + 1008.44882744, + 1009.26850304, + 1010.19236691, + 1011.2206266, + ] + ) + + # Initialize heat/electricity arrays + self.Instantaneous_production_enthalpy = np.zeros(len(self.Time_array)) + self.Instantaneous_temperature_after_isenthalpic_throttling = np.zeros(len(self.Time_array)) + self.Instantaneous_heat_production = np.zeros(len(self.Time_array)) + self.Annual_heat_production = np.zeros(self.Lifetime) + self.Annual_pumping_power = np.zeros(self.Lifetime) + self.Average_fluid_density = np.zeros(len(self.Time_array)) + if self.End_use == 2: # electricity generation + self.Instantaneous_exergy_production = np.zeros( + len(self.Time_array) + ) # Produced exergy only (independent from injection conditions) + self.Instantaneous_exergy_extraction = np.zeros( + len(self.Time_array) + ) # Difference between produced exergy and injected exergy + self.Instantaneous_electricity_production_method_1 = np.zeros( + len(self.Time_array) + ) # based on exergy produced (only for water) + self.Instantaneous_electricity_production_method_2 = np.zeros( + len(self.Time_array) + ) # based on exergy extracted + self.Instantaneous_electricity_production_method_3 = np.zeros( + len(self.Time_array) + ) # based on thermal efficiency + self.Instantaneous_electricity_production_method_4 = np.zeros( + len(self.Time_array) + ) # based on direct turbine expansion (for CO2) + self.Instantaneous_utilization_efficiency_method_1 = np.zeros( + len(self.Time_array) + ) # conversion from produced exergy to electricity + self.Instantaneous_utilization_efficiency_method_2 = np.zeros( + len(self.Time_array) + ) # conversion from extracted exergy to electricity + self.Instantaneous_themal_efficiency = np.zeros( + len(self.Time_array) + ) # conversion from enthalpy to electricity + self.Annual_electricity_production = np.zeros(self.Lifetime) + if self.Fluid == 2: + self.Instantaneous_turbine_power = np.zeros( + len(self.Time_array) + ) # Direct turbine expansion considered for systems using sCO2 + + # Initialize error code + self.error_codes = np.zeros(0) # if error occurs, code will be assigned to this tag + + def getTandP(self): + + if self.Fluid == 1: + self.Tout, self.Pout = self.u_H2O.interp_outlet_states(self.point) + elif self.Fluid == 2: + self.Tout, self.Pout = self.u_sCO2.interp_outlet_states(self.point) + + # Initial time correction (Correct production temperature and pressure at time 0 (the value at time 0 [=initial condition] is not a good representation for the first few months) + self.Tout[0] = self.Tout[1] + self.Pout[0] = self.Pout[1] + + # Extract Tout and Pout over lifetime + self.InterpolatedTemperatureArray = self.Tout[0 : self.indexclosestlifetime + 1] - 273.15 + self.InterpolatedPressureArray = self.Pout[0 : self.indexclosestlifetime + 1] + + def calculateLC(self): + self.Linear_production_temperature = self.InterpolatedTemperatureArray + self.Linear_production_pressure = self.InterpolatedPressureArray + self.AveProductionTemperature = np.average(self.Linear_production_temperature) + self.AveProductionPressure = np.average(self.Linear_production_pressure) / 1e5 # [bar] + self.Flow_rate = self.Flow_user # Total flow rate [kg/s] + self.calculatedrillinglength() + # print(self.Linear_production_temperature) + if min(self.Linear_production_temperature) > self.T_in: + self.calculateheatproduction() + if self.End_use == 2: + self.calculateelectricityproduction() + self.calculatecapex() + self.calculatopex() + + Discount_vector = 1.0 / np.power(1 + self.Discount_rate, np.linspace(0, self.Lifetime - 1, self.Lifetime)) + # if self.End_use == 1: #direct-use heating + self.LCOH = ( + (self.TotalCAPEX + np.sum(self.OPEX_Plant * Discount_vector)) + * 1e6 + / np.sum(self.Annual_heat_production / 1e3 * Discount_vector) + ) # $/MWh + self.LCOH100 = ( + (self.TotalCAPEX100 + np.sum(self.OPEX_Plant * Discount_vector)) + * 1e6 + / np.sum(self.Annual_heat_production / 1e3 * Discount_vector) + ) # $/MWh + self.LCOH500 = ( + (self.TotalCAPEX500 + np.sum(self.OPEX_Plant * Discount_vector)) + * 1e6 + / np.sum(self.Annual_heat_production / 1e3 * Discount_vector) + ) # $/MWh + self.LCOH1500 = ( + (self.TotalCAPEX1500 + np.sum(self.OPEX_Plant * Discount_vector)) + * 1e6 + / np.sum(self.Annual_heat_production / 1e3 * Discount_vector) + ) # $/MWh + if self.LCOH < 0: + self.LCOH = 9999 + self.error_codes = np.append(self.error_codes, 5000) + # elif self.End_use == 2: #electricity production + if self.Average_electricity_production == 0: + self.LCOE = 9999 + self.LCOE100 = float('nan') + self.LCOE500 = float('nan') + self.LCOE1500 = float('nan') + self.error_codes = np.append(self.error_codes, 6000) + else: + self.LCOE = ( + (self.TotalCAPEX + np.sum(self.OPEX_Plant * Discount_vector)) + * 1e6 + / np.sum((self.Annual_electricity_production - self.Annual_pumping_power) / 1e3 * Discount_vector) + ) # $/MWh + self.LCOE100 = ( + (self.TotalCAPEX100 + np.sum(self.OPEX_Plant * Discount_vector)) + * 1e6 + / np.sum((self.Annual_electricity_production - self.Annual_pumping_power) / 1e3 * Discount_vector) + ) # $/MWh + self.LCOE500 = ( + (self.TotalCAPEX500 + np.sum(self.OPEX_Plant * Discount_vector)) + * 1e6 + / np.sum((self.Annual_electricity_production - self.Annual_pumping_power) / 1e3 * Discount_vector) + ) # $/MWh + self.LCOE1500 = ( + (self.TotalCAPEX1500 + np.sum(self.OPEX_Plant * Discount_vector)) + * 1e6 + / np.sum((self.Annual_electricity_production - self.Annual_pumping_power) / 1e3 * Discount_vector) + ) # $/MWh + if self.LCOE < 0: + self.LCOE = 9999 + self.LCOE100 = float('nan') + self.LCOE500 = float('nan') + self.LCOE1500 = float('nan') + self.error_codes = np.append(self.error_codes, 7000) + + else: # Production temperature went below injection temperature + self.LCOE = 9999 + self.LCOH = 9999 + self.error_codes = np.append(self.error_codes, 1000) + + def calculatedrillinglength(self): + if self.Configuration == 1: + self.Drilling_length = ( + self.Hor_length_user + 2 * self.Depth_user + ) # Total drilling depth of both wells and lateral in U-loop [m] + elif self.Configuration == 2: + self.Drilling_length = ( + self.Hor_length_user + self.Depth_user + ) # Total drilling depth of well and lateral in co-axial case [m] + + def calculateheatproduction(self): + # Calculate instantaneous heat production + self.Average_fluid_density = interpn( + (self.Pvector, self.Tvector), + self.density, + np.dstack( + ( + 0.5 * self.P_in + 0.5 * self.Linear_production_pressure, + 0.5 * self.T_in + 0.5 * self.Linear_production_temperature + 273.15, + ) + )[0], + ) + self.hprod = interpn( + (self.Pvector, self.Tvector), + self.enthalpy, + np.dstack((self.Linear_production_pressure, self.Linear_production_temperature + 273.15))[0], + ) + self.hinj = interpn((self.Pvector, self.Tvector), self.enthalpy, np.array([self.P_in, self.T_in + 273.15])) + self.Instantaneous_heat_production = ( + self.Flow_rate * (self.hprod - self.hinj) / 1000 + ) # Heat production based on produced minus injected enthalpy [kW] + + # Calculate annual heat production (kWh) + self.Annual_heat_production = ( + 8760 + / 5 + * ( + self.Instantaneous_heat_production[0::4][0:-1] + + self.Instantaneous_heat_production[1::4] + + self.Instantaneous_heat_production[2::4] + + self.Instantaneous_heat_production[3::4] + + self.Instantaneous_heat_production[4::4] + ) + ) + + # Calculate average heat production + self.AveAnnualHeatProduction = np.average(self.Annual_heat_production) # kWh + self.AveInstHeatProduction = np.average(self.Instantaneous_heat_production) # kWth + + # Calculate average heat production and first year heat production + self.Average_heat_production = np.average(self.Instantaneous_heat_production) # [kW] + # Average_production_temperature = np.average(Linear_production_temperature) #[deg.C] + self.FirstYearHeatProduction = self.Annual_heat_production[0] # kWh + + self.calculatepumpingpower() + + def calculateelectricityproduction(self): + + # Calculate instantaneous exergy production, exergy extraction, and electricity generation (MW) and annual electricity generation [kWh] + self.h_prod = self.hprod # produced enthalpy [J/kg] + self.h_inj = self.hinj # injected enthalpy [J/kg] + self.s_prod = interpn( + (self.Pvector, self.Tvector), + self.entropy, + np.dstack((self.Linear_production_pressure, self.Linear_production_temperature + 273.15))[0], + ) # produced entropy [J/kg/K] + self.s_inj = interpn( + (self.Pvector, self.Tvector), self.entropy, np.array([self.P_in, self.T_in + 273.15]) + ) # injected entropy [J/kg/K] + + self.Instantaneous_exergy_production = ( + self.Flow_rate * (self.h_prod - self.h_0 - self.T0 * (self.s_prod - self.s_0)) + ) / 1000 # [kW] + self.Instantaneous_exergy_extraction = ( + self.Flow_rate * (self.h_prod - self.h_inj - self.T0 * (self.s_prod - self.s_inj)) + ) / 1000 # [kW] + + self.AverageInstNetExergyProduction = np.average(self.Instantaneous_exergy_production) # [kW] + self.AverageInstNetExergyExtraction = np.average(self.Instantaneous_exergy_extraction) # [kW] + + if self.Fluid == 1: + + if ( + self.T_in >= 50 + and min(self.Linear_production_temperature) >= 100 + and max(self.Linear_production_temperature) <= 385 + ): + self.Instantaneous_utilization_efficiency_method_1 = np.interp( + self.Linear_production_temperature, + self.Utilization_efficiency_correlation_temperatures, + self.Utilization_efficiency_correlation_conversion, + left=0, + ) # Utilization efficiency based on conversion of produced exergy to electricity + self.Instantaneous_electricity_production_method_1 = ( + self.Instantaneous_exergy_production * self.Instantaneous_utilization_efficiency_method_1 + ) # [kW] + self.Instantaneous_themal_efficiency = np.interp( + self.Linear_production_temperature, + self.Heat_to_power_efficiency_correlation_temperatures, + self.Heat_to_power_efficiency_correlation_conversion, + left=0, + ) # Utilization efficiency based on conversion of produced exergy to electricity + self.Instantaneous_electricity_production_method_3 = ( + self.Instantaneous_heat_production * self.Instantaneous_themal_efficiency + ) # [kW] + + else: # Water injection temperature and/or production tempeature fall outside the range used in the correlations + self.error_codes = np.append(self.error_codes, 2000) + self.Instantaneous_utilization_efficiency_method_1 = np.zeros(len(self.Time_array)) + self.Instantaneous_electricity_production_method_1 = np.zeros(len(self.Time_array)) + self.Instantaneous_themal_efficiency = np.zeros(len(self.Time_array)) + self.Instantaneous_electricity_production_method_3 = np.zeros(len(self.Time_array)) + + # based on method 1 for now (could be 50-50) + self.Annual_electricity_production = ( + 8760 + / 5 + * ( + self.Instantaneous_electricity_production_method_1[0::4][0:-1] + + self.Instantaneous_electricity_production_method_1[1::4] + + self.Instantaneous_electricity_production_method_1[2::4] + + self.Instantaneous_electricity_production_method_1[3::4] + + self.Instantaneous_electricity_production_method_1[4::4] + ) + ) + self.Inst_electricity_production = self.Instantaneous_electricity_production_method_1 # [kW] + self.AveInstElectricityProduction = np.average(self.Instantaneous_electricity_production_method_1) # [kW] + + elif self.Fluid == 2: + T_prod = self.Linear_production_temperature # Production temperature [deg.C] + P_prod = self.Linear_production_pressure # Production pressure [Pa] + + h_turbine_out_ideal = interpn( + (self.Pvector_ap, self.svector_ap), + self.hPs, + np.dstack((np.ones(self.TNOP) * self.Turbine_outlet_pressure * 1e5, self.s_prod))[0], + ) + self.Instantaneous_turbine_power = ( + self.Flow_rate * (self.h_prod - h_turbine_out_ideal) * self.Turbine_isentropic_efficiency / 1000 + ) # Turbine output [kW] + h_turbine_out_actual = ( + self.h_prod - self.Instantaneous_turbine_power / self.Flow_rate * 1000 + ) # Actual fluid enthalpy at turbine outlet [J/kg] + self.T_turbine_out_actual = ( + interpn( + (self.Pvector_ap, self.hvector_ap), + self.TPh, + np.dstack((np.ones(self.TNOP) * self.Turbine_outlet_pressure * 1e5, h_turbine_out_actual))[0], + ) + - 273.15 + ) + + if min(self.T_turbine_out_actual) > 37 and self.T_in > 32: + + self.Pre_cooling_temperature = min(self.T_turbine_out_actual) - self.Pre_Cooling_Delta_T + Post_cooling = 2000 + valuefound = 0 + lastrun = 0 + # print('y') + while valuefound == 0: + # print('b') + Pre_compressor_h = interpn( + (self.Pvector, self.Tvector), + self.enthalpy, + np.array([self.Turbine_outlet_pressure * 1e5, self.Pre_cooling_temperature + 273.15]), + ) + + Pre_cooling = ( + self.Flow_rate * (h_turbine_out_actual - Pre_compressor_h) / 1e3 + ) # Pre-compressor cooling [kWth] + Pre_compressor_s = interpn( + (self.Pvector, self.Tvector), + self.entropy, + np.array([self.Turbine_outlet_pressure * 1e5, self.Pre_cooling_temperature + 273.15]), + ) + + Post_compressor_h_ideal = interpn( + (self.Pvector_ap, self.svector_ap), self.hPs, np.array([self.P_in, Pre_compressor_s[0]]) + ) + Post_compressor_h_actual = ( + Pre_compressor_h + + (Post_compressor_h_ideal - Pre_compressor_h) / self.Compressor_isentropic_efficiency + ) # Actual fluid enthalpy at compressor outlet [J/kg] + self.Post_compressor_T_actual = ( + interpn( + (self.Pvector_ap, self.hvector_ap), + self.TPh, + np.array([self.P_in, Post_compressor_h_actual[0]]), + ) + - 273.15 + ) + Compressor_Work = self.Flow_rate * (Post_compressor_h_actual - Pre_compressor_h) / 1e3 # [kWe] + Post_cooling = ( + self.Flow_rate * (Post_compressor_h_actual - self.h_inj) / 1e3 + ) # Fluid cooling after compression [kWth] + # print(str(Post_cooling)) + # print(str(self.Pre_cooling_temperature)) + + if lastrun == 0: + if self.Pre_cooling_temperature < 32: + lastrun = 1 + self.Pre_cooling_temperature = self.Pre_cooling_temperature + 0.5 + elif Post_cooling < 0: + self.Pre_cooling_temperature = self.Pre_cooling_temperature + 0.5 + lastrun = 1 + elif Post_cooling > 0: + self.Pre_cooling_temperature = self.Pre_cooling_temperature - 0.5 + + elif lastrun == 1: + valuefound = 1 + print(self.Pre_cooling_temperature - min(self.T_turbine_out_actual)) + + # print(min(self.T_turbine_out_actual)) + # print(self.Pre_cooling_temperature) + + if Post_cooling < 0: + ResistiveHeating = -Post_cooling + Post_cooling = 0 + else: + ResistiveHeating = 0 + + Total_cooling = Pre_cooling + Post_cooling # Total CO2 cooling requirements [kWth] + + T_air_in_pre_cooler = self.T0 - 273.15 + T_air_out_pre_cooler = ( + self.T_turbine_out_actual + self.Pre_cooling_temperature + ) / 2 # Air outlet temperature in pre-cooler [deg.C] + cp_air = np.interp( + 0.5 * T_air_in_pre_cooler + 0.5 * T_air_out_pre_cooler, self.Tair_for_cp_array, self.cp_air_array + ) # Air specific heat capacity in pre-cooler [J/kg/K] + m_air_pre_cooler = ( + Pre_cooling * 1000 / (cp_air * (T_air_out_pre_cooler - T_air_in_pre_cooler)) + ) # Air flow rate in pre-cooler [kg/s] + + T_air_in_post_cooler = self.T0 - 273.15 + T_air_out_post_cooler = ( + self.Post_compressor_T_actual + self.T_in + ) / 2 # Air outlet temperature in post-cooler [deg.C] + cp_air = np.interp( + 0.5 * T_air_in_post_cooler + 0.5 * T_air_out_post_cooler, self.Tair_for_cp_array, self.cp_air_array + ) # Air specific heat capacity in post-cooler [J/kg/K] + + m_air_post_cooler = ( + Post_cooling * 1000 / (cp_air * (T_air_out_post_cooler - T_air_in_post_cooler)) + ) # Air flow rate in post-cooler [kg/s] + + Air_cooling_power = ( + m_air_pre_cooler + m_air_post_cooler + ) * 0.25 # Electricity for air-cooling, assuming 0.25 kWe per kg/s [kWe] + # print(self.Instantaneous_turbine_power) + # print(Compressor_Work) + self.Instantaneous_electricity_production_method_4 = ( + self.Instantaneous_turbine_power * self.Generator_efficiency + - Compressor_Work + - Air_cooling_power + - ResistiveHeating + ) # Net electricity using CO2 direct turbine expansion cycle [kWe] + self.Inst_electricity_production = self.Instantaneous_electricity_production_method_4 # [kW] + self.Annual_electricity_production = ( + 8760 + / 5 + * ( + self.Instantaneous_electricity_production_method_4[0::4][0:-1] + + self.Instantaneous_electricity_production_method_4[1::4] + + self.Instantaneous_electricity_production_method_4[2::4] + + self.Instantaneous_electricity_production_method_4[3::4] + + self.Instantaneous_electricity_production_method_4[4::4] + ) + ) + self.AveInstElectricityProduction = np.average( + self.Instantaneous_electricity_production_method_4 + ) # [kW] + # check if negative + if min(self.Instantaneous_electricity_production_method_4) < 0: + self.error_codes = np.append( + self.error_codes, 5500 + ) # Calculated electricity generation is negative + + self.Annual_electricity_production = np.zeros(self.Lifetime) + self.Inst_electricity_production = np.zeros(self.TNOP) + self.AveInstElectricityProduction = 0 + else: # turbine outlet or reinjection temperature too low + if self.T_in <= 32: + self.error_codes = np.append(self.error_codes, 3000) + + if min(self.T_turbine_out_actual) <= 37: + self.error_codes = np.append(self.error_codes, 4000) + + self.Annual_electricity_production = np.zeros(self.Lifetime) + self.Inst_electricity_production = np.zeros(self.TNOP) + self.AveInstElectricityProduction = 0 + + self.calculatepumpingpower() + + self.Average_electricity_production = np.average(self.Annual_electricity_production) / 8760 # [kW] + self.AveAnnualElectricityProduction = np.average(self.Annual_electricity_production) # [kWh] + self.AveInstNetElectricityProduction = self.AveInstElectricityProduction - np.average(self.PumpingPower) # [kW] + self.AveAnnualNetElectricityProduction = self.AveAnnualElectricityProduction - np.average( + self.Annual_pumping_power + ) # kWh + self.FirstYearElectricityProduction = self.Annual_electricity_production[0] # kWh + self.Inst_Net_Electricity_production = self.Inst_electricity_production - self.PumpingPower # [kW] + + if self.AveInstNetElectricityProduction < 0: + self.AveInstNetElectricityProduction = 0 + + def calculatepumpingpower(self): + # Calculate pumping power + self.PumpingPower = ( + (self.P_in - self.Linear_production_pressure) + * self.Flow_rate + / self.Average_fluid_density + / self.Pump_efficiency + / 1e3 + ) # Pumping power [kW] + self.PumpingPower[self.PumpingPower < 0] = ( + 0 # Set negative values to zero (if the production pressure is above the injection pressure, we throttle the fluid) + ) + self.Annual_pumping_power = ( + 8760 + / 5 + * ( + self.PumpingPower[0::4][0:-1] + + self.PumpingPower[1::4] + + self.PumpingPower[2::4] + + self.PumpingPower[3::4] + + self.PumpingPower[4::4] + ) + ) # kWh + + def calculatecapex(self): + self.CAPEX_Drilling = self.Drilling_length * self.Drilling_cost_per_m / 1e6 # Drilling capital cost [M$] + if self.End_use == 1: # direct-use heating + self.CAPEX_Surface_Plant = ( + np.max(self.Instantaneous_heat_production) * self.Direct_use_heat_cost_per_kWth / 1e6 + ) # [M$] + elif self.End_use == 2: # electricity production + if self.Fluid == 1: + self.CAPEX_Surface_Plant = ( + np.max(self.Instantaneous_electricity_production_method_1) * self.Power_plant_cost_per_kWe / 1e6 + ) # [M$] + elif self.Fluid == 2: + self.CAPEX_Surface_Plant = ( + np.max(self.Instantaneous_electricity_production_method_4) * self.Power_plant_cost_per_kWe / 1e6 + ) # [M$] + + self.TotalCAPEX = ( + self.CAPEX_Drilling + self.CAPEX_Surface_Plant + ) # Total system capital cost (only includes drilling and surface plant cost) [M$] + self.TotalCAPEX100 = ( + self.Drilling_length * 100 / 1e6 + self.CAPEX_Surface_Plant + ) # Total system capital cost (only includes drilling and surface plant cost) [M$] + self.TotalCAPEX500 = ( + self.Drilling_length * 500 / 1e6 + self.CAPEX_Surface_Plant + ) # Total system capital cost (only includes drilling and surface plant cost) [M$] + self.TotalCAPEX1500 = ( + self.Drilling_length * 1500 / 1e6 + self.CAPEX_Surface_Plant + ) # Total system capital cost (only includes drilling and surface plant cost) [M$] + + def calculatopex(self): + # Calculate OPEX + if self.End_use == 1: # direct-use heating + self.OPEX_Plant = ( + self.O_and_M_cost_plant * self.CAPEX_Surface_Plant + + self.Annual_pumping_power * self.Electricity_rate / 1e6 + ) # Annual plant O&M cost [M$/year] + elif self.End_use == 2: # electricity production + self.OPEX_Plant = self.O_and_M_cost_plant * self.CAPEX_Surface_Plant # Annual plant O&M cost [M$/year] + self.AverageOPEX_Plant = np.average(self.OPEX_Plant) + + def printresults(self): + ### Print results to screen + print('##################') + print('Simulation Results') + print('##################') + print('Number of cases in database = ' + str(self.numberofcases)) + print(' ') + print('### Configuration ###') + if self.End_use == 1: + print('End-Use = Direct-Use') + elif self.End_use == 2: + print('End-Use = Electricity') + if self.Fluid == 1: + print('Fluid = water') + elif self.Fluid == 2: + print('Fluid = sCO2') + if self.Configuration == 1: + print('Design = U-loop') + elif self.Configuration == 2: + print('Design = Co-axial') + + # Print conditions + print('Flow rate = ' + f'{self.Flow_user:.1f}' + ' kg/s') + print('Lateral Length = ' + str(round(self.Hor_length_user)) + ' m') + print('Vertical Depth = ' + str(round(self.Depth_user)) + ' m') + print('Geothermal Gradient = ' + f'{self.Gradient_user*1000:.1f}' + ' deg.C/km') + print('Wellbore Diameter = ' + f'{self.Diameter_user:.4f}' + ' m') + print('Injection Temperature = ' + f'{self.Tin_user-273.15:.1f}' + ' deg.C') + print('Thermal Conductivity = ' + f'{self.krock_user:.2f}' + ' W/m/K') + + # check if error occured + if len(self.error_codes) > 0: + print(' ') + if np.in1d(1000, self.error_codes): # plot the temperature and pressure for these + print('Error: production temperature drops below injection temperature. Simulation terminated.\n') + + if np.in1d(2000, self.error_codes): # plot the temperature and pressure for these + print( + 'Error: Water injection temperature and/or production tempeature fall outside the range of the ORC correlations. These correlations require injection temperature larger than 50 deg.C and production temperature in the range of 100 to 385 deg.C. Electricity production set to 0. \n' + ) + + if np.in1d( + 3000, self.error_codes + ): # CO2 injection temperature cannot be below 32 degrees C (CO2 must be supercritical) + print('Error: Too low CO2 reinjection temperature. CO2 must remain supercritical.\n') + + if np.in1d(4000, self.error_codes): # Turbine outlet CO2 temperature dropped below 37 degrees C + print( + 'Error: Too low CO2 turbine outlet temperature. Turbine outlet temperature must be above 37 degrees C.\n' + ) + + if np.in1d(5000, self.error_codes): # Calculated LCOH was negative, set to $9999/MWh + print('Error: Calculated LCOH was negative and has been reset to $9,999/MWh.\n') + + if np.in1d(5500, self.error_codes): # Negative electricity calculated with CO2 cycle + print('Error: Calculated net electricity generation is negative and reset to 0.\n') + + if np.in1d(6000, self.error_codes): # Zero electricity production. LCOE set to $9999/MWh + print('Error: Calculated net electricity production was 0. LCOE reset to $9,999/MWh.\n') + + if np.in1d(7000, self.error_codes): # Calculated LCOE was negative, set to $9999/MWh + print('Error: Calculated LCOE was negative and has been reset to $9,999/MWh.\n') + + # Print results for heating + if self.End_use == 1: + print(' ') + print('### Reservoir Simulation Results ###') + print('Average Production Temperature = ' + f'{self.AveProductionTemperature:.1f}' + ' deg.C') + print('Average Production Pressure = ' + f'{self.AveProductionPressure:.1f}' + ' bar') + if np.in1d(1000, self.error_codes) == False: + print('Average Heat Production = ' + f'{self.AveInstHeatProduction:.1f}' + ' kWth') + print('First Year Heat Production = ' + f'{self.FirstYearHeatProduction/1e3:.1f}' + ' MWh') + print(' ') + print('### Cost Results ###') + print('Total CAPEX = ' + f'{self.TotalCAPEX:.1f}' + ' M$') + print('Drilling Cost = ' + f'{self.CAPEX_Drilling:.1f}' + ' M$') + print('Surface Plant Cost = ' + f'{self.CAPEX_Surface_Plant:.1f}' + ' M$') + print('OPEX = ' + f'{self.AverageOPEX_Plant*1000:.1f}' + ' k$/year') + print('LCOH = ' + f'{self.LCOH:.1f}' + ' $/MWh') + + if self.End_use == 2: + print(' ') + print('### Reservoir Simulation Results ###') + print('Average Production Temperature = ' + f'{self.AveProductionTemperature:.1f}' + ' deg.C') + print('Average Production Pressure = ' + f'{self.AveProductionPressure:.1f}' + ' bar') + if np.in1d(1000, self.error_codes) == False: + print('Average Heat Production = ' + f'{self.AveInstHeatProduction:.1f}' + ' kWth') + print('Average Net Electricity Production = ' + f'{self.AveInstNetElectricityProduction:.1f}' + ' kWe') + print('First Year Heat Production = ' + f'{self.FirstYearHeatProduction/1e3:.1f}' + ' MWh') + print( + 'First Year Electricity Production = ' + f'{self.FirstYearElectricityProduction/1e3:.1f}' + ' MWh' + ) + print(' ') + print('### Cost Results ###') + print('Total CAPEX = ' + f'{self.TotalCAPEX:.1f}' + ' M$') + print('Drilling Cost = ' + f'{self.CAPEX_Drilling:.1f}' + ' M$') + print('Surface Plant Cost = ' + f'{self.CAPEX_Surface_Plant:.1f}' + ' M$') + print('OPEX = ' + f'{self.AverageOPEX_Plant*1000:.1f}' + ' k$/year') + print('LCOE = ' + f'{self.LCOE:.1f}' + ' $/MWh') + + def plotresults(self): + # Plot injection and production temperature + plt.figure() + plt.title('Injection and Production Temperature') + plt.xlabel('Time [year]') + plt.ylabel(r'Temperature [$^\circ$C]') + plt.plot([0, self.Lifetime], [self.T_in, self.T_in], 'b-') + plt.plot(self.Linear_time_distribution, self.Linear_production_temperature, 'r-') + plt.legend(['Injection Temperature', 'Production Temperature']) + plt.axis([0, self.Lifetime, self.T_in - 10, max(self.Linear_production_temperature) + 10]) + plt.xticks(np.arange(0, self.Lifetime + 1, 2), np.arange(0, self.Lifetime + 1, 2)) + plt.show() + + # Plot injection and production pressure + plt.figure() + plt.title('Injection and Production Pressure') + plt.xlabel('Time [year]') + plt.ylabel('Pressure [bar]') + plt.plot([0, self.Lifetime], [self.P_in / 1e5, self.P_in / 1e5], 'b-') + plt.plot(self.Linear_time_distribution, self.Linear_production_pressure / 1e5, 'r-') + plt.legend(['Injection Pressure', 'Production Pressure']) + maxpressure = np.max([self.P_in / 1e5, np.max(self.Linear_production_pressure) / 1e5]) + minpressure = np.min([self.P_in / 1e5, np.min(self.Linear_production_pressure) / 1e5]) + plt.axis([0, self.Lifetime, minpressure - 10, maxpressure + 10]) + plt.xticks(np.arange(0, self.Lifetime + 1, 2), np.arange(0, self.Lifetime + 1, 2)) + plt.show() + + # Plot heat production + plt.figure() + plt.title('Heat Production') + plt.xlabel('Time [year]') + params = {'mathtext.default': 'regular'} + plt.rcParams.update(params) + plt.ylabel('Heat [$MW_{t}$]') + plt.plot(self.Linear_time_distribution, self.Instantaneous_heat_production / 1e3, 'r-') + plt.axis([0, self.Lifetime, 0, max(self.Instantaneous_heat_production / 1e3) + 1]) + plt.xticks(np.arange(0, self.Lifetime + 1, 2), np.arange(0, self.Lifetime + 1, 2)) + plt.show() + + plt.figure() + plt.bar(np.arange(1, self.Lifetime + 1), self.Annual_heat_production / 1e6) + plt.xlabel('Time [year]') + plt.ylabel('Heat Production [GWh]') + plt.title('Annual Heat Production') + plt.xticks(np.arange(0, self.Lifetime + 1, 2), np.arange(0, self.Lifetime + 1, 2)) + plt.show() + + # plot electricity over time if end-use is 2 + if self.End_use == 2: + plt.figure() + plt.title('Electricity Production') + plt.xlabel('Time [year]') + params = {'mathtext.default': 'regular'} + plt.rcParams.update(params) + plt.ylabel('Electricity [$MW_{e}$]') + plt.plot(self.Linear_time_distribution, self.Inst_Net_Electricity_production / 1e3, 'r-') + plt.axis([0, self.Lifetime, 0, max(self.Inst_Net_Electricity_production / 1e3) + 1]) + plt.xticks(np.arange(0, self.Lifetime + 1, 2), np.arange(0, self.Lifetime + 1, 2)) + plt.show() + + plt.figure() + plt.bar(np.arange(1, self.Lifetime + 1), self.Annual_electricity_production / 1e6) + plt.xlabel('Time [year]') + plt.ylabel('Electricity Production [GWh]') + plt.title('Annual Electricity Production') + plt.xticks(np.arange(0, self.Lifetime + 1, 2), np.arange(0, self.Lifetime + 1, 2)) + plt.show() + + # create Ts-diagram in case of CO2 power production + if ( + self.Fluid == 2 + and np.in1d(3000, self.error_codes) == False + and np.in1d(4000, self.error_codes) == False + ): + # CO2 isobaric lines for Ts diagram (do not change data below) + pvectorforTS = np.array([40, 50, 60, 70, 80, 90, 100, 120, 150, 190, 240, 300]) # bar + svectorforTS = np.arange(1000, 2000, 20) # J/kg/K + tmatrix = np.array( + [ + [ + 273.58779987, + 275.73964358, + 277.82952322, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 278.44972407, + 279.16739097, + 281.98680218, + 285.11251959, + 288.53183612, + 292.23286854, + 296.20421415, + 300.43497368, + 304.91492276, + 309.63463723, + ], + [ + 274.42077418, + 276.63242586, + 278.79031756, + 280.88470759, + 282.90420093, + 284.8353605, + 286.66228321, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.43392381, + 287.96651004, + 290.06555059, + 292.48128297, + 295.20562474, + 298.23009373, + 301.54561859, + 305.14278777, + 309.01219991, + 313.14471796, + 317.53155667, + 322.16425682, + 327.03466505, + ], + [ + 275.23288781, + 277.50029097, + 279.72101728, + 281.88672793, + 283.98779516, + 286.01303489, + 287.94946975, + 289.78218424, + 291.4942541, + 293.06653014, + 294.47679734, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.12790099, + 295.9354915, + 297.35537749, + 299.07212335, + 301.08795261, + 303.40261519, + 306.01350043, + 308.91613741, + 312.10478208, + 315.57290651, + 319.31351482, + 323.31931035, + 327.58280441, + 332.09645076, + 336.85281943, + 341.84475813, + ], + [ + 276.02607997, + 278.34583338, + 280.62513674, + 282.85677401, + 285.03249573, + 287.14282112, + 289.17689654, + 291.12248905, + 292.96614008, + 294.69336153, + 296.28858454, + 297.73458483, + 299.011625, + 300.09758466, + 300.97073532, + 301.61423442, + 301.8325153, + 301.8325153, + 301.8325153, + 301.8325153, + 301.8325153, + 301.8325153, + 301.8325153, + 301.8325153, + 301.8325153, + 301.8325153, + 301.8325153, + 301.8325153, + 301.8325153, + 301.8325153, + 302.09542982, + 302.58879462, + 303.2793647, + 304.18893716, + 305.33653776, + 306.73773627, + 308.40431208, + 310.34433077, + 312.56253551, + 315.06089701, + 317.83917492, + 320.89539075, + 324.2261797, + 327.82705562, + 331.69265609, + 335.81701249, + 340.19383373, + 344.81675258, + 349.67949196, + 354.77594888, + ], + [ + 276.80189842, + 279.17107055, + 281.50533372, + 283.79838944, + 286.04309117, + 288.23128859, + 290.3537384, + 292.40016137, + 294.35947993, + 296.22015087, + 297.97036237, + 299.59784329, + 301.08934154, + 302.43049789, + 303.60731254, + 304.60958484, + 305.43472959, + 306.09016372, + 306.59420747, + 306.97336927, + 307.25532028, + 307.47069845, + 307.65403034, + 307.82936031, + 308.0076719, + 308.20853737, + 308.45497452, + 308.76827506, + 309.16916382, + 309.67981016, + 310.32386748, + 311.12522831, + 312.10669659, + 313.28900162, + 314.69018476, + 316.32529927, + 318.20635339, + 320.34242373, + 322.73986477, + 325.4025539, + 328.33214361, + 331.52832983, + 334.98916153, + 338.71139868, + 342.69088804, + 346.92290167, + 351.40239399, + 356.12416833, + 361.08297566, + 366.27357671, + ], + [ + 277.56162433, + 279.97764204, + 282.36372714, + 284.71434274, + 287.02324203, + 289.28333988, + 291.48665471, + 293.6243954, + 295.68722534, + 297.66562966, + 299.55018853, + 301.33153232, + 302.9999648, + 304.54520748, + 305.95710135, + 307.22771897, + 308.35404538, + 309.33970039, + 310.19516516, + 310.935894, + 311.57873857, + 312.143772, + 312.65796099, + 313.14933519, + 313.64039782, + 314.1467086, + 314.6901326, + 315.29582886, + 315.98700684, + 316.78469962, + 317.70901078, + 318.78001191, + 320.01762104, + 321.44086311, + 323.06709059, + 324.91143497, + 326.98650416, + 329.30226115, + 331.86603447, + 334.68264398, + 337.75463976, + 341.08263885, + 344.66571751, + 348.50179783, + 352.58797567, + 356.92076582, + 361.49627286, + 366.31031192, + 371.3585025, + 376.63634824, + ], + [ + 278.30634695, + 280.76692289, + 283.20206879, + 285.60688807, + 287.97587967, + 290.30282905, + 292.58077049, + 294.80208911, + 296.95878792, + 299.04284976, + 301.04652031, + 302.96231809, + 304.78273895, + 306.49997116, + 308.10624416, + 309.59524733, + 310.96417741, + 312.21517992, + 313.35532245, + 314.39511557, + 315.34669749, + 316.22485477, + 317.04972335, + 317.84500607, + 318.63352456, + 319.43547086, + 320.26866588, + 321.15491544, + 322.11728356, + 323.17735523, + 324.3552376, + 325.67016149, + 327.14083776, + 328.78527246, + 330.6202218, + 332.6605961, + 334.91901704, + 337.40559839, + 340.12794395, + 343.09132309, + 346.29896643, + 349.7524136, + 353.45185087, + 357.39639806, + 361.58433378, + 366.01326948, + 370.68028972, + 375.58207254, + 380.71499591, + 386.07523169, + ], + [ + 279.75444778, + 282.29817944, + 284.82433455, + 287.32902789, + 289.80791774, + 292.25612472, + 294.66822243, + 297.0383542, + 299.36048536, + 301.62872141, + 303.83755132, + 305.98187696, + 308.05680937, + 310.05743003, + 311.97889683, + 313.81720263, + 315.57044276, + 317.23986013, + 318.82984388, + 320.3468679, + 321.79853724, + 323.19410279, + 324.5458906, + 325.8693588, + 327.18153051, + 328.49985457, + 329.84235722, + 331.22807789, + 332.67693979, + 334.20933551, + 335.84483513, + 337.60187632, + 339.49779226, + 341.54879485, + 343.76981952, + 346.17429027, + 348.77391483, + 351.57858366, + 354.59638447, + 357.83370121, + 361.29535632, + 364.98476646, + 368.9040978, + 373.05441794, + 377.43584441, + 382.04768885, + 386.88859397, + 391.9566601, + 397.24955922, + 402.76463545, + ], + [ + 281.83443065, + 284.49054627, + 287.13869075, + 289.77604486, + 292.3994679, + 295.00544884, + 297.59012963, + 300.14943366, + 302.67928723, + 305.17586241, + 307.63573556, + 310.05588235, + 312.43352359, + 314.76595749, + 317.05058504, + 319.28527574, + 321.46901173, + 323.60249084, + 325.68827882, + 327.73038804, + 329.73373947, + 331.70423537, + 333.64955593, + 335.5798509, + 337.50755558, + 339.44657727, + 341.4116138, + 343.41789639, + 345.48108684, + 347.61704308, + 349.84146682, + 352.169554, + 354.61583061, + 357.19410582, + 359.91740391, + 362.79786554, + 365.84662864, + 369.07371357, + 372.48793503, + 376.09685442, + 379.90677609, + 383.92278397, + 388.14881086, + 392.58773063, + 397.24146404, + 402.11109043, + 407.19695909, + 412.49879649, + 418.01580673, + 423.74676402, + ], + [ + 284.46010614, + 287.24808249, + 290.03809343, + 292.82824725, + 295.61643858, + 298.40033711, + 301.17744368, + 303.94522119, + 306.70126758, + 309.44346417, + 312.1700312, + 314.87946451, + 317.57039544, + 320.24147407, + 322.89138567, + 325.51905575, + 328.12400395, + 330.70672155, + 333.2689251, + 335.81360214, + 338.34489257, + 340.86796442, + 343.38903245, + 345.91549948, + 348.45602389, + 351.02034174, + 353.61888872, + 356.26243929, + 358.96193526, + 361.72849507, + 364.5734711, + 367.50843626, + 370.54506747, + 373.69496089, + 376.9694292, + 380.37931828, + 383.93485464, + 387.64552617, + 391.51999386, + 395.56603159, + 399.79049255, + 404.19930077, + 408.79746559, + 413.58911618, + 418.57755178, + 423.76530373, + 429.15420499, + 434.74546357, + 440.53973699, + 446.53720545, + ], + [ + 287.54370173, + 290.47477034, + 293.41743992, + 296.37055692, + 299.33284669, + 302.30293816, + 305.27943869, + 308.26104366, + 311.24664098, + 314.23536353, + 317.22656351, + 320.21972203, + 323.21434555, + 326.20991425, + 329.20592964, + 332.20206785, + 335.19840422, + 338.19565227, + 341.19536186, + 344.20003798, + 347.21316276, + 350.23912622, + 353.28309478, + 356.35086517, + 359.44874828, + 362.58349711, + 365.76225958, + 368.99253217, + 372.28211442, + 375.63908334, + 379.07179464, + 382.58888913, + 386.19926861, + 389.9120183, + 393.7362794, + 397.68109447, + 401.75525243, + 405.96715298, + 410.32469917, + 414.8352191, + 419.50541343, + 424.34132465, + 429.34832416, + 434.5311145, + 439.89374434, + 445.43963403, + 451.17161001, + 457.09194579, + 463.2024078, + 469.50430417, + ], + [ + 291.00408259, + 294.08333456, + 297.18293362, + 300.3023086, + 303.44085231, + 306.59796523, + 309.77312115, + 312.96593133, + 316.17617866, + 319.40380478, + 322.64885629, + 325.91141812, + 329.19156995, + 332.48939224, + 335.80502725, + 339.13878159, + 342.4912472, + 345.86342063, + 349.25680717, + 352.67350208, + 356.11624126, + 359.58841294, + 363.09402366, + 366.63762115, + 370.22418891, + 373.85903781, + 377.54771937, + 381.29597333, + 385.10970762, + 388.99499966, + 392.95810832, + 397.00548825, + 401.14379812, + 405.37989264, + 409.72078858, + 414.17360117, + 418.74545536, + 423.4433829, + 428.2742184, + 433.24450557, + 438.36042029, + 443.62771334, + 449.05167197, + 454.63709839, + 460.38830223, + 466.30910437, + 472.40284992, + 478.67242829, + 485.12029884, + 491.74852062, + ], + ] + ) + + # dome data for Ts diagram + sdome = np.array( + [ + 1001.37898699, + 1046.06882698, + 1088.21416035, + 1128.86481841, + 1169.09596369, + 1210.24526707, + 1254.66210399, + 1309.32653659, + 1323.58218729, + 1340.74189756, + 1364.61655928, + 1400.86587985, + 1468.75018408, + 1516.27446567, + 1546.66849166, + 1567.63482054, + 1584.41961907, + 1643.56442582, + 1686.22125974, + 1722.06785103, + 1754.37017763, + 1784.81415615, + 1814.51645442, + 1844.39848637, + ] + ) + Tdome = np.array( + [ + 273.31081538, + 278.44972407, + 283.13044128, + 287.43392381, + 291.41872472, + 295.12790099, + 298.59249754, + 301.8325153, + 302.45422394, + 303.06687319, + 303.6699029, + 304.08533585, + 304.08533585, + 303.6699029, + 303.06687319, + 302.45422394, + 301.8325153, + 298.59249754, + 295.12790099, + 291.41872472, + 287.43392381, + 283.13044128, + 278.44972407, + 273.31081538, + ] + ) + + # Ts at turbine inlet + turbinletT = self.Linear_production_temperature[-1] + turbinletS = self.s_prod[-1] + + # Ts at turbine outlet + turbineoutletT = self.T_turbine_out_actual[-1] + turbineoutletS = interpn( + (self.Pvector, self.Tvector), + self.entropy, + np.array([self.Turbine_outlet_pressure * 1e5, turbineoutletT + 273.15]), + )[0] + + # Ts at compressor inlet + compressorinletT = self.Pre_cooling_temperature + compressorinletS = interpn( + (self.Pvector, self.Tvector), + self.entropy, + np.array([self.Turbine_outlet_pressure * 1e5, compressorinletT + 273.15]), + )[0] + + # Ts at compressor outlet + compressoroutletT = self.Post_compressor_T_actual[0] + compressoroutletS = interpn( + (self.Pvector, self.Tvector), self.entropy, np.array([self.P_in, compressoroutletT + 273.15]) + )[0] + + # Ts at re-injection + reinjectionT = self.T_in + reinjectionS = interpn( + (self.Pvector, self.Tvector), self.entropy, np.array([self.P_in, reinjectionT + 273.15]) + )[0] + + cycleTarray = np.array( + [turbinletT, turbineoutletT, compressorinletT, compressoroutletT, reinjectionT, turbinletT] + ) + cycleSarray = np.array( + [turbinletS, turbineoutletS, compressorinletS, compressoroutletS, reinjectionS, turbinletS] + ) + + # + plt.figure() + plt.title('CO2 TS-diagram') + plt.xlabel('Entropy [J/kg/K]') + plt.ylabel('Temperature [K]') + for i in range(len(pvectorforTS)): + plt.plot(svectorforTS, tmatrix[i, :], 'b-') + plt.plot(sdome, Tdome, 'r-') + plt.plot(cycleSarray, cycleTarray + 273.15, 'k-+') + # plt.axis([0, 200,0,50]) + plt.show() + + def lineplot(self, parameterrange, parameterindex): + print(' ') + print('### Line Plot Calculation ###') + + # create arrays to store result + lcoerange = np.zeros(len(parameterrange)) + avekwthrange = np.zeros(len(parameterrange)) + avekwerange = np.zeros(len(parameterrange)) + + # 0 = Flow rate; 1 = Horizontal length; 2 = Depth; 3 = Gradient; 4 = Diameter; 5 = Injection temperature; 6 = Rock thermal conductivity + # store originals + flow_original = self.Flow_user + hor_length_original = self.Hor_length_user + depth_original = self.Depth_user + gradient_original = self.Gradient_user + diameter_original = self.Diameter_user + Tin_original = self.Tin_user + krock_original = self.krock_user + + # verify input + if parameterindex == 0: + if min(parameterrange) < 5 or max(parameterrange) > 100: + print('Error: Flow rate outise allowable range [5 to 100 kg/s]') + sys.exit() + elif parameterindex == 1: + if min(parameterrange) < 1000 or max(parameterrange) > 20000: + print('Error: Horizontal length outise allowable range [1,000 to 20,000 m]') + sys.exit() + elif parameterindex == 2: + if min(parameterrange) < 1000 or max(parameterrange) > 5000: + print('Error: Depth outise allowable range [1,000 to 5,000 m]') + sys.exit() + elif parameterindex == 3: + if min(parameterrange) < 0.03 or max(parameterrange) > 0.07: + print('Error: Gradient outside allowable range [0.03 to 0.07 deg.C/m]') + sys.exit() + elif parameterindex == 4: + if min(parameterrange) < 0.2159 or max(parameterrange) > 0.4445: + print('Error: Diameter outise allowable range [0.2159 to 0.4445 m]') + sys.exit() + elif parameterindex == 5: + if min(parameterrange) < 303.15 or max(parameterrange) > 333.15: + print('Error: Injection temperature outside allowable range [303.15 to 333.15 K]') + sys.exit() + elif parameterindex == 6: + if min(parameterrange) < 1.5 or max(parameterrange) > 4.5: + print('Error: Rock thermal conductivity outise allowable range [1.5 to 4.5 W/m-K]') + sys.exit() + + # cycle through array to update object and recalculated TEA results, then store them in arrays + for i in range(len(parameterrange)): + print('Line plot calculation: ' + str(i + 1) + '/' + str(len(parameterrange))) + if parameterindex == 0: + self.Flow_user = parameterrange[i] + xlabel = 'Flow rate [kg/s]' + elif parameterindex == 1: + self.Hor_length_user = parameterrange[i] + xlabel = 'Horizontal length [m]' + elif parameterindex == 2: + self.Depth_user = parameterrange[i] + xlabel = 'Depth [m]' + elif parameterindex == 3: + self.Gradient_user = parameterrange[i] + xlabel = 'Geothermal gradient [deg.C/m]' + elif parameterindex == 4: + self.Diameter_user = parameterrange[i] + xlabel = 'Diameter [m]' + elif parameterindex == 5: + self.Tin_user = parameterrange[i] + self.T_in = self.Tin_user - 273.15 # Injection temperature [deg.C] + xlabel = 'Injection temperature [deg.C]' + elif parameterindex == 6: + self.krock_user = parameterrange[i] + xlabel = 'Rock thermal conductivity [W/m-K]' + + # update self.point + self.point = ( + self.Flow_user, + self.Hor_length_user, + self.Depth_user, + self.Gradient_user, + self.Diameter_user, + self.Tin_user, + self.krock_user, + ) + + self.getTandP() + self.calculateLC() + if np.in1d(1000, self.error_codes) == False: + avekwthrange[i] = self.AveInstHeatProduction + if self.End_use == 1: + lcoerange[i] = self.LCOH + else: + lcoerange[i] = self.LCOE + avekwerange[i] = self.AveInstNetElectricityProduction + else: + lcoerange[i] = 9999 + + # restore object to its original condition + self.Flow_user = flow_original + self.Hor_length_user = hor_length_original + self.Depth_user = depth_original + self.Gradient_user = gradient_original + self.Diameter_user = diameter_original + self.Tin_user = Tin_original + self.T_in = self.Tin_user - 273.15 + self.krock_user = krock_original + self.point = ( + self.Flow_user, + self.Hor_length_user, + self.Depth_user, + self.Gradient_user, + self.Diameter_user, + self.Tin_user, + self.krock_user, + ) + + # create 1D line plots + plt.figure() + plt.plot(parameterrange, lcoerange, color='blue', linestyle='-', linewidth='2') + plt.grid() + plt.xlim([parameterrange[0], parameterrange[-1]]) + plt.ylim([0, 1.05 * np.max(lcoerange)]) + plt.xlabel(xlabel) + if self.End_use == 1: + plt.ylabel('Levelized cost of heat [$/MWh]') + else: + plt.ylabel('Levelized cost of electricity [$/MWh]') + plt.show() + + plt.figure() + plt.plot(parameterrange, avekwthrange / 1000, color='blue', linestyle='-', linewidth='2') + plt.grid() + plt.xlim([parameterrange[0], parameterrange[-1]]) + plt.ylim([0, 1.05 * np.max(avekwthrange / 1000)]) + plt.xlabel(xlabel) + plt.ylabel('Average heat production [$MW_{t}$]') + plt.show() + + if self.End_use == 2: + plt.figure() + plt.plot(parameterrange, avekwerange, color='blue', linestyle='-', linewidth='2') + plt.grid() + plt.xlim([parameterrange[0], parameterrange[-1]]) + plt.ylim([0, 1.05 * np.max(avekwerange)]) + plt.xlabel(xlabel) + plt.ylabel('Average electricity production [$kW_{e}$]') + plt.show() + + def contourplot(self, parameter1range, parameter1index, parameter2range, parameter2index, newtitle): + print(' ') + print('### Contour Plot Calculation ###') + + # create arrays to store result + lcoerange = np.zeros((len(parameter1range), len(parameter2range))) + lcoerange100 = np.zeros((len(parameter1range), len(parameter2range))) + lcoerange500 = np.zeros((len(parameter1range), len(parameter2range))) + lcoerange1500 = np.zeros((len(parameter1range), len(parameter2range))) + avekwthrange = np.zeros((len(parameter1range), len(parameter2range))) + avekwerange = np.zeros((len(parameter1range), len(parameter2range))) + + # 0 = Flow rate; 1 = Horizontal length; 2 = Depth; 3 = Gradient; 4 = Diameter; 5 = Injection temperature; 6 = Rock thermal conductivity + # store originals + flow_original = self.Flow_user + hor_length_original = self.Hor_length_user + depth_original = self.Depth_user + gradient_original = self.Gradient_user + diameter_original = self.Diameter_user + Tin_original = self.Tin_user + krock_original = self.krock_user + + # verify input + if parameter1index == 0: + if min(parameter1range) < 5 or max(parameter1range) > 100: + print('Error: Flow rate outise allowable range [5 to 100 kg/s]') + sys.exit() + elif parameter1index == 1: + if min(parameter1range) < 1000 or max(parameter1range) > 20000: + print('Error: Horizontal length outise allowable range [1,000 to 20,000 m]') + sys.exit() + elif parameter1index == 2: + if min(parameter1range) < 1000 or max(parameter1range) > 5000: + print('Error: Depth outise allowable range [1,000 to 5,000 m]') + sys.exit() + elif parameter1index == 3: + if min(parameter1range) < 0.03 or max(parameter1range) > 0.07: + print('Error: Gradient outside allowable range [0.03 to 0.07 deg.C/m]') + sys.exit() + elif parameter1index == 4: + if min(parameter1range) < 0.2159 or max(parameter1range) > 0.4445: + print('Error: Diameter outise allowable range [0.2159 to 0.4445 m]') + sys.exit() + elif parameter1index == 5: + if min(parameter1range) < 303.15 or max(parameter1range) > 333.15: + print('Error: Injection temperature outside allowable range [303.15 to 333.15 K]') + sys.exit() + elif parameter1index == 6: + if min(parameter1range) < 1.5 or max(parameter1range) > 4.5: + print('Error: Rock thermal conductivity outise allowable range [1.5 to 4.5 W/m-K]') + sys.exit() + if parameter2index == 0: + if min(parameter2range) < 5 or max(parameter2range) > 100: + print('Error: Flow rate outise allowable range [5 to 100 kg/s]') + sys.exit() + elif parameter2index == 1: + if min(parameter2range) < 1000 or max(parameter2range) > 20000: + print('Error: Horizontal length outise allowable range [1,000 to 20,000 m]') + sys.exit() + elif parameter2index == 2: + if min(parameter2range) < 1000 or max(parameter2range) > 5000: + print('Error: Depth outise allowable range [1,000 to 5,000 m]') + sys.exit() + elif parameter2index == 3: + if min(parameter2range) < 0.03 or max(parameter2range) > 0.07: + print('Error: Gradient outside allowable range [0.03 to 0.07 deg.C/m]') + sys.exit() + elif parameter2index == 4: + if min(parameter2range) < 0.2159 or max(parameter2range) > 0.4445: + print('Error: Diameter outise allowable range [0.2159 to 0.4445 m]') + sys.exit() + elif parameter2index == 5: + if min(parameter2range) < 303.15 or max(parameter2range) > 333.15: + print('Error: Injection temperature outside allowable range [303.15 to 333.15 K]') + sys.exit() + elif parameter2index == 6: + if min(parameter2range) < 1.5 or max(parameter2range) > 4.5: + print('Error: Rock thermal conductivity outise allowable range [1.5 to 4.5 W/m-K]') + sys.exit() + + # cycle through double array to update object and recalculated TEA results, then store them in arrays + for i in range(len(parameter1range)): + if parameter1index == 0: + self.Flow_user = parameter1range[i] + xlabel = 'Flow rate [kg/s]' + elif parameter1index == 1: + self.Hor_length_user = parameter1range[i] + xlabel = 'Horizontal length [m]' + elif parameter1index == 2: + self.Depth_user = parameter1range[i] + xlabel = 'Depth [m]' + elif parameter1index == 3: + self.Gradient_user = parameter1range[i] + xlabel = 'Geothermal gradient [deg.C/m]' + elif parameter1index == 4: + self.Diameter_user = parameter1range[i] + xlabel = 'Diameter [m]' + elif parameter1index == 5: + self.Tin_user = parameter1range[i] + self.T_in = self.Tin_user - 273.15 # Injection temperature [deg.C] + xlabel = 'Injection temperature [deg.C]' + elif parameter1index == 6: + self.krock_user = parameter1range[i] + + for j in range(len(parameter2range)): + print( + 'Contour plot calculation: ' + + str(j + 1 + i * len(parameter2range)) + + '/' + + str(len(parameter1range) * len(parameter2range)) + ) + if parameter2index == 0: + self.Flow_user = parameter2range[j] + ylabel = 'Flow rate [kg/s]' + elif parameter2index == 1: + self.Hor_length_user = parameter2range[j] + ylabel = 'Horizontal length [m]' + elif parameter2index == 2: + self.Depth_user = parameter2range[j] + ylabel = 'Depth [m]' + elif parameter2index == 3: + self.Gradient_user = parameter2range[j] + ylabel = 'Geothermal gradient [deg.C/m]' + elif parameter2index == 4: + self.Diameter_user = parameter2range[j] + ylabel = 'Diameter [m]' + elif parameter2index == 5: + self.Tin_user = parameter2range[j] + self.T_in = self.Tin_user - 273.15 # Injection temperature [deg.C] + ylabel = 'Injection temperature [deg.C]' + elif parameter2index == 6: + self.krock_user = parameter2range[j] + + # update self.point + self.point = ( + self.Flow_user, + self.Hor_length_user, + self.Depth_user, + self.Gradient_user, + self.Diameter_user, + self.Tin_user, + self.krock_user, + ) + self.error_codes = np.zeros(0) + self.getTandP() + self.calculateLC() + if np.in1d(1000, self.error_codes) == False: + avekwthrange[(i, j)] = self.AveInstHeatProduction + + if self.End_use == 1: + lcoerange[(i, j)] = self.LCOH + lcoerange100[(i, j)] = self.LCOH100 + lcoerange500[(i, j)] = self.LCOH500 + lcoerange1500[(i, j)] = self.LCOH1500 + else: + lcoerange[(i, j)] = self.LCOE + lcoerange100[(i, j)] = self.LCOE100 + lcoerange500[(i, j)] = self.LCOE500 + lcoerange1500[(i, j)] = self.LCOE1500 + avekwerange[(i, j)] = self.AveInstNetElectricityProduction + else: + lcoerange[(i, j)] = float('nan') + lcoerange100[(i, j)] = float('nan') + lcoerange500[(i, j)] = float('nan') + lcoerange1500[(i, j)] = float('nan') + + lcoerange100[lcoerange100 > 1000] = float('nan') + lcoerange500[lcoerange500 > 2000] = float('nan') + lcoerange1500[lcoerange1500 > 5000] = float('nan') + + self.avekwthrange = avekwthrange + self.lcoerange = lcoerange + self.lcoerange100 = lcoerange100 + self.lcoerange500 = lcoerange500 + self.lcoerange1500 = lcoerange1500 + + # restore object to its original condition + self.Flow_user = flow_original + self.Hor_length_user = hor_length_original + self.Depth_user = depth_original + self.Gradient_user = gradient_original + self.Diameter_user = diameter_original + self.Tin_user = Tin_original + self.T_in = self.Tin_user - 273.15 + self.krock_user = krock_original + self.point = ( + self.Flow_user, + self.Hor_length_user, + self.Depth_user, + self.Gradient_user, + self.Diameter_user, + self.Tin_user, + self.krock_user, + ) + + # make plots + X, Y = np.meshgrid(parameter1range, parameter2range) + fig, ax = plt.subplots() + contour = plt.contourf(X, Y, np.transpose(avekwthrange), levels=32, cmap=cm.coolwarm) + ax.set(xlim=(X.min(), X.max()), ylim=(Y.min(), Y.max())) + ax.set_xlabel(xlabel) + ax.set_ylabel(ylabel) + plt.title('Average Heat Production') + cbar = plt.colorbar(contour) + cbar.set_label('Average Heat Production [kWth]') + plt.show() + + newtitle100 = newtitle + str(100) + '/m' + newtitle500 = newtitle + str(500) + '/m' + newtitle1500 = newtitle + str(1500) + '/m' + + # fig, ax = plt.subplots() + # contour = plt.contourf(X,Y, np.transpose(lcoerange), levels = 32, cmap=cm.coolwarm) + # ax.set(xlim=(X.min(), X.max()),ylim=(Y.min(), Y.max())) + # ax.set_xlabel(xlabel) + # ax.set_ylabel(ylabel) + # plt.title(newtitle) + # cbar = plt.colorbar(contour) + # if self.End_use == 1: + # cbar.set_label('LCOH [$/MWh]') + # elif self.End_use == 2: + # cbar.set_label('LCOE [$/MWh]') + # plt.show() + + fig, ax = plt.subplots() + contour = plt.contourf(X, Y, np.transpose(lcoerange100), levels=32, cmap=cm.coolwarm) + ax.set(xlim=(X.min(), X.max()), ylim=(Y.min(), Y.max())) + ax.set_xlabel(xlabel) + ax.set_ylabel(ylabel) + # if self.End_use == 1: + # newtile = 'U-loop | water | $'+str(self.Drilling_cost_per_m)+'/m' + # plt.title(newtile) + # elif self.End_use == 2: + plt.title(newtitle100) + cbar = plt.colorbar(contour) + if self.End_use == 1: + cbar.set_label('LCOH [$/MWh]') + elif self.End_use == 2: + cbar.set_label('LCOE [$/MWh]') + plt.show() + + fig, ax = plt.subplots() + contour = plt.contourf(X, Y, np.transpose(lcoerange500), levels=32, cmap=cm.coolwarm) + ax.set(xlim=(X.min(), X.max()), ylim=(Y.min(), Y.max())) + ax.set_xlabel(xlabel) + ax.set_ylabel(ylabel) + # if self.End_use == 1: + # newtile = 'U-loop | water | $'+str(self.Drilling_cost_per_m)+'/m' + # plt.title(newtile) + # elif self.End_use == 2: + plt.title(newtitle500) + cbar = plt.colorbar(contour) + if self.End_use == 1: + cbar.set_label('LCOH [$/MWh]') + elif self.End_use == 2: + cbar.set_label('LCOE [$/MWh]') + plt.show() + + fig, ax = plt.subplots() + contour = plt.contourf(X, Y, np.transpose(lcoerange1500), levels=32, cmap=cm.coolwarm) + ax.set(xlim=(X.min(), X.max()), ylim=(Y.min(), Y.max())) + ax.set_xlabel(xlabel) + ax.set_ylabel(ylabel) + # if self.End_use == 1: + # newtile = 'U-loop | water | $'+str(self.Drilling_cost_per_m)+'/m' + # plt.title(newtile) + # elif self.End_use == 2: + + plt.title(newtitle1500) + cbar = plt.colorbar(contour) + if self.End_use == 1: + cbar.set_label('LCOH [$/MWh]') + elif self.End_use == 2: + cbar.set_label('LCOE [$/MWh]') + plt.show() + + if self.End_use == 2: + fig, ax = plt.subplots() + contour = plt.contourf(X, Y, np.transpose(avekwerange), levels=32, cmap=cm.coolwarm) + ax.set(xlim=(X.min(), X.max()), ylim=(Y.min(), Y.max())) + ax.set_xlabel(xlabel) + ax.set_ylabel(ylabel) + plt.title('Average Electricity Production') + cbar = plt.colorbar(contour) + cbar.set_label('Average Electricity Production [kWe]') + plt.show() + + def optimalLCOH(self): + # parameters to vary: FlowRateVector,HorizontalLengthVector,DepthVector, , TinVector, KrockVector + + # store originals + flow_original = self.Flow_user + hor_length_original = self.Hor_length_user + depth_original = self.Depth_user + gradient_original = self.Gradient_user + diameter_original = self.Diameter_user + Tin_original = self.Tin_user + krock_original = self.krock_user + + # create optimum vectors + flowratevectorforoptimum = self.FlowRateVector + horizontallengthvectorforoptimum = self.HorizontalLengthVector + depthvectorforoptimum = self.DepthVector + tinvectorforoptimum = self.TinVector + + # create zero vectors to store results + avekwthrange = np.zeros( + [ + len(flowratevectorforoptimum), + len(horizontallengthvectorforoptimum), + len(depthvectorforoptimum), + len(tinvectorforoptimum), + ] + ) + lcoerange = np.zeros( + [ + len(flowratevectorforoptimum), + len(horizontallengthvectorforoptimum), + len(depthvectorforoptimum), + len(tinvectorforoptimum), + ] + ) + avekwerange = np.zeros( + [ + len(flowratevectorforoptimum), + len(horizontallengthvectorforoptimum), + len(depthvectorforoptimum), + len(tinvectorforoptimum), + ] + ) + + # cycle through array to update object and recalculated TEA results, then store them in arrays + for i in range(len(flowratevectorforoptimum)): + print('Optimum calculation: ' + str(i + 1) + '/' + str(len(flowratevectorforoptimum))) + self.Flow_user = flowratevectorforoptimum[i] + + for j in range(len(horizontallengthvectorforoptimum)): + self.Hor_length_user = horizontallengthvectorforoptimum[j] + + for k in range(len(depthvectorforoptimum)): + self.Depth_user = depthvectorforoptimum[k] + + for l in range(len(tinvectorforoptimum)): + self.Tin_user = tinvectorforoptimum[l] + self.T_in = self.Tin_user - 273.15 + + # elif parameterindex == 2: + # self.Depth_user = parameterrange[i] + # xlabel = 'Depth [m]' + # elif parameterindex == 3: + # self.Gradient_user = parameterrange[i] + # xlabel = 'Geothermal gradient [deg.C/m]' + # elif parameterindex == 4: + # self.Diameter_user = parameterrange[i] + # xlabel = 'Diameter [m]' + # elif parameterindex == 5: + # self.Tin_user = parameterrange[i] + # self.T_in = self.Tin_user-273.15 #Injection temperature [deg.C] + # xlabel = 'Injection temperature [deg.C]' + # elif parameterindex == 6: + # self.krock_user = parameterrange[i] + # xlabel = 'Rock thermal conductivity [W/m-K]' + + # update self.point + self.point = ( + self.Flow_user, + self.Hor_length_user, + self.Depth_user, + self.Gradient_user, + self.Diameter_user, + self.Tin_user, + self.krock_user, + ) + + self.getTandP() + self.calculateLC() + + if np.in1d(1000, self.error_codes) == False: + avekwthrange[i, j, k, l] = self.AveInstHeatProduction + if self.End_use == 1: + lcoerange[i, j, k, l] = self.LCOH + else: + lcoerange[i, j, k, l] = self.LCOE + avekwerange[i, j, k, l] = self.AveInstNetElectricityProduction + else: + lcoerange[i, j, k, l] = 9999 + + # store results + self.avekwthrange = avekwthrange + self.lcoerange = lcoerange + self.avekwerange = avekwerange + + # restore object to its original condition + self.Flow_user = flow_original + self.Hor_length_user = hor_length_original + self.Depth_user = depth_original + self.Gradient_user = gradient_original + self.Diameter_user = diameter_original + self.Tin_user = Tin_original + self.T_in = self.Tin_user - 273.15 + self.krock_user = krock_original + self.point = ( + self.Flow_user, + self.Hor_length_user, + self.Depth_user, + self.Gradient_user, + self.Diameter_user, + self.Tin_user, + self.krock_user, + ) + + def optimalLCOH2(self): + # parameters to vary: FlowRateVector,HorizontalLengthVector,DepthVector, , TinVector, KrockVector + + # store originals + flow_original = self.Flow_user + hor_length_original = self.Hor_length_user + depth_original = self.Depth_user + gradient_original = self.Gradient_user + diameter_original = self.Diameter_user + Tin_original = self.Tin_user + krock_original = self.krock_user + + # create optimum vectors + flowratevectorforoptimum = self.FlowRateVector + horizontallengthvectorforoptimum = self.HorizontalLengthVector + tinvectorforoptimum = self.TinVector + + # create zero vectors to store results + avekwthrange = np.zeros( + [len(flowratevectorforoptimum), len(horizontallengthvectorforoptimum), len(tinvectorforoptimum)] + ) + lcoerange = np.zeros( + [len(flowratevectorforoptimum), len(horizontallengthvectorforoptimum), len(tinvectorforoptimum)] + ) + avekwerange = np.zeros( + [len(flowratevectorforoptimum), len(horizontallengthvectorforoptimum), len(tinvectorforoptimum)] + ) + + # cycle through array to update object and recalculated TEA results, then store them in arrays + for i in range(len(flowratevectorforoptimum)): + print('Optimum calculation: ' + str(i + 1) + '/' + str(len(flowratevectorforoptimum))) + self.Flow_user = flowratevectorforoptimum[i] + + for j in range(len(horizontallengthvectorforoptimum)): + self.Hor_length_user = horizontallengthvectorforoptimum[j] + + for l in range(len(tinvectorforoptimum)): + self.Tin_user = tinvectorforoptimum[l] + self.T_in = self.Tin_user - 273.15 + + # elif parameterindex == 2: + # self.Depth_user = parameterrange[i] + # xlabel = 'Depth [m]' + # elif parameterindex == 3: + # self.Gradient_user = parameterrange[i] + # xlabel = 'Geothermal gradient [deg.C/m]' + # elif parameterindex == 4: + # self.Diameter_user = parameterrange[i] + # xlabel = 'Diameter [m]' + # elif parameterindex == 5: + # self.Tin_user = parameterrange[i] + # self.T_in = self.Tin_user-273.15 #Injection temperature [deg.C] + # xlabel = 'Injection temperature [deg.C]' + # elif parameterindex == 6: + # self.krock_user = parameterrange[i] + # xlabel = 'Rock thermal conductivity [W/m-K]' + + # update self.point + self.point = ( + self.Flow_user, + self.Hor_length_user, + self.Depth_user, + self.Gradient_user, + self.Diameter_user, + self.Tin_user, + self.krock_user, + ) + + self.getTandP() + self.calculateLC() + + if np.in1d(1000, self.error_codes) == False: + avekwthrange[i, j, l] = self.AveInstHeatProduction + if self.End_use == 1: + lcoerange[i, j, l] = self.LCOH + else: + lcoerange[i, j, l] = self.LCOE + avekwerange[i, j, l] = self.AveInstNetElectricityProduction + else: + lcoerange[i, j, l] = 9999 + + # store results + self.avekwthrange = avekwthrange + self.lcoerange = lcoerange + self.avekwerange = avekwerange + + # restore object to its original condition + self.Flow_user = flow_original + self.Hor_length_user = hor_length_original + self.Depth_user = depth_original + self.Gradient_user = gradient_original + self.Diameter_user = diameter_original + self.Tin_user = Tin_original + self.T_in = self.Tin_user - 273.15 + self.krock_user = krock_original + self.point = ( + self.Flow_user, + self.Hor_length_user, + self.Depth_user, + self.Gradient_user, + self.Diameter_user, + self.Tin_user, + self.krock_user, + ) diff --git a/src/fgem/utils/utils.py b/src/fgem/utils/utils.py new file mode 100755 index 000000000..6ed9ff189 --- /dev/null +++ b/src/fgem/utils/utils.py @@ -0,0 +1,920 @@ +import os +from datetime import datetime +from datetime import timedelta + +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import seaborn as sns +from meteostat import Hourly +from meteostat import Stations +from pyXSteam.XSteam import XSteam +from scipy.optimize import curve_fit +from shapely.geometry import Polygon +from shapely.geometry.polygon import orient +from shapely.prepared import prep +from timezonefinder import TimezoneFinder + +steamTable = XSteam(XSteam.UNIT_SYSTEM_MKS) # m/kg/sec/°C/bar/W + +colors = 24 * sns.color_palette() + +linestyles = {0: 'solid', 1: 'dashed', 2: 'dashdot', 3: 'dotted'} + + +class FastXsteam: + """Faster corrleations for Steam Tables.""" + + def __init__(self, T_max=300, steps=30000): + """Initiate class for fast Xsteam tables. + + Args: + T_max (int, optional): maximum temperature. Defaults to 300. + steps (int, optional): number of steps. Defaults to 30000. + """ + + self.xdata = np.linspace(1, T_max, steps) + self.tc = 647.096 # K + + ydata = [steamTable.hL_t(x) for x in self.xdata] + self.popt_hl, pcov = curve_fit(self.func_hl, self.xdata, ydata) + ydata = [steamTable.hV_t(x) for x in self.xdata] + self.popt_hv, pcov = curve_fit(self.func_hv, self.xdata, ydata) + ydata = [steamTable.vL_t(x) for x in self.xdata] + self.popt_vl, pcov = curve_fit(self.func_vl, self.xdata, ydata) + ydata = [steamTable.vV_t(x) for x in self.xdata] + self.popt_vv, pcov = curve_fit(self.func_vv, self.xdata, ydata) + + def func_hl(self, t, a, b, c, d, e): + """Liquid enthalpy correlation. + + Args: + t (float): temperature in C + a (float): correlation coefficient. + b (float): correlation coefficient. + c (float): correlation coefficient. + d (float): correlation coefficient. + e (float): correlation coefficient. + + Returns: + float: liquid enthalpy in kJ/kg at the given temperature + """ + tr = (t + 273.15) / self.tc + return a + b * np.log(1 / tr) ** 0.35 + c / tr**2 + d / tr**3 + e / tr**4 + + def func_hv(self, t, a, b, c, d, e): + """Vapor enthalpy correlation. + + Args: + t (float): temperature in C + a (float): correlation coefficient. + b (float): correlation coefficient. + c (float): correlation coefficient. + d (float): correlation coefficient. + e (float): correlation coefficient. + + Returns: + float: vapor enthalpy in kJ/kg at the given temperature + """ + + tr = (t + 273.15) / self.tc + return (a + b * np.log(1 / tr) ** 0.35 + c / tr**2 + d / tr**3 + e / tr**4) ** (1 / 2) + + def func_vl(self, t, a, b, c, d, e): + """Liquid specific volume correlation. + + Args: + t (float): temperature in C + a (float): correlation coefficient. + b (float): correlation coefficient. + c (float): correlation coefficient. + d (float): correlation coefficient. + e (float): correlation coefficient. + + Returns: + float: liquid specific volume in m3/kg at the given temperature + """ + + tr = (t + 273.15) / self.tc + return a + b * np.log(1 / tr) ** 0.35 + c / tr**2 + d / tr**3 + e / tr**4 + + def func_vv(self, t, a, b, c, d, e): + """Vapor specific volume correlation. + + Args: + t (float): temperature in C + a (float): correlation coefficient. + b (float): correlation coefficient. + c (float): correlation coefficient. + d (float): correlation coefficient. + e (float): correlation coefficient. + + Returns: + float: vapor specific volume in m3/kg at the given temperature + """ + + tr = (t + 273.15) / self.tc + return np.exp(a + b * np.log(1 / tr) ** 0.35 + c / tr**2 + d / tr**3 + e / tr**4) + + def hL_t(self, t): + """Liquid enthalpy correlation. + + Args: + t (float): temperature in C + + Returns: + float: liquid enthalpy in kJ/kg at the given temperature + """ + t = t[0] if isinstance(t, np.ndarray) else t + return self.func_hl(t, *self.popt_hl) + + def hV_t(self, t): + """Vapor enthalpy correlation. + + Args: + t (float): temperature in C + + Returns: + float: vapor enthalpy in kJ/kg at the given temperature + """ + + t = t[0] if isinstance(t, np.ndarray) else t + return self.func_hv(t, *self.popt_hv) + + def vL_t(self, t): + """Liquid specific volume correlation. + + Args: + t (float): temperature in C + + Returns: + float: liquid specific volume in m3/kg at the given temperature + """ + + t = t[0] if isinstance(t, np.ndarray) else t + return self.func_vl(t, *self.popt_vl) + + def vV_t(self, t): + """Vapor specific volume correlation. + + Args: + t (float): temperature in C + + Returns: + float: vapor specific volume in m3/kg at the given temperature + """ + + t = t[0] if isinstance(t, np.ndarray) else t + return self.func_vv(t, *self.popt_vv) + + +def plot_ex(worlds, figsize=(10, 10), dpi=150, colors=colors, fontsize=10): + """Visualize expenditure of multiple projects. + + Args: + worlds (dict): projects or worlds to visualize + figsize (tuple, optional): figure size. Defaults to (10,10). + dpi (int, optional): figure dpi resolution. Defaults to 150. + colors (list, optional): list of colors to be used. Defaults to seaborn.color_palette(). + fontsize (int, optional): font size. Defaults to 10. + + Returns: + matplotlib.figure.Figure: figure object + """ + + fig, axes = plt.subplots(1, len(worlds), figsize=figsize, dpi=dpi) + axes = [axes] if len(worlds) == 1 else axes + + def func(pct, allvals): + absolute = int(np.round(pct / 100.0 * np.sum(allvals))) + # return "{:.0f}%\n({:d} $MM)".format(pct, absolute) + return f'{pct:.0f}%' + + for i, (title, present_per_unit) in enumerate(worlds.items()): + ex = [v for _, v in present_per_unit.items() if v > 0] + labels = [k for k, v in present_per_unit.items() if v > 0] + wedges, _, _ = axes[i].pie( + x=ex, + pctdistance=0.8, + labels=labels, + colors=colors, + autopct=lambda pct: func(pct, ex), + textprops=dict(color='w', weight='bold', fontsize=fontsize), + ) + + axes[i].legend(wedges, labels, title=title, loc='center left', bbox_to_anchor=(0.3, 0.6, 0.0, 1)) + + return fig + + +def plot_cols( + dfs, + span, + quantities, + figsize=(10, 10), + xlabel='World Time', + ylabels=None, + ylogscale=False, + use_title=True, + legend_loc='lower right', + manual_legends=None, + color_per_col=True, + use_linestyles=True, + blackout_first=False, + formattime=False, + dpi=100, +): + """Visualize columns of a dataframe. + + Args: + dfs (dict): dictionary of dataframes to plot with key as names. + span (Union[range, list]): range of indices to plot. + quantities (list): dataframe columns to plot. + figsize (tuple, optional): figure size. Defaults to (10,10). + xlabel (str, optional): label of the x axis. Defaults to "World Time". + ylabels (list, optional): labels of the y axes. Defaults to None. + ylogscale (bool, optional): whether or not to use log-scale on the y axis. Defaults to False. + use_title (bool, optional): whether or not to use a figure title. Defaults to True. + legend_loc (str, optional): legend location. Defaults to "lower right". + manual_legends (list, optional): list to override default legends. Defaults to None. + color_per_col (bool, optional): whether or not to assign one color to each column. Defaults to True. + use_linestyles (bool, optional): whether or not to use linestyles. If False, all quantities are plotted with solid linestyle. Defaults to True. + blackout_first (bool, optional): whether or not to plot the very first quantity in black color. Defaults to False. + formattime (bool, optional): whether or not to apply time formatting. Defaults to False. + dpi (int, optional): figure dpi resolution. Defaults to 100. + + Returns: + matplotlib.figure.Figure: figure object + + """ + + fig, axes = plt.subplots(len(quantities), 1, figsize=figsize, sharex=True, dpi=dpi) + + df_plots = [df.iloc[span].copy() for df in dfs.values()] + counter = 0 + + for k, df_plot in enumerate(df_plots): + for i, q in enumerate(quantities): + q = q if isinstance(q, list) else [q] + for col in q: + if all([qi in df_plot.columns for qi in q]): + # axes[i].plot(df_plot.index, df_plot[col].rolling(10).mean(), color=colors[counter], linestyle=linestyles[k if use_linestyles else 0]) + axes[i].plot( + df_plot.index, + df_plot[col], + color=colors[counter], + linestyle=linestyles[k if use_linestyles else 0], + ) + if color_per_col: + counter += 1 + if legend_loc: + axes[i].legend(q, loc=legend_loc) + if not color_per_col: + counter += 1 + else: + counter = 0 + + if use_title: + if len(dfs.keys()) > 1: + axes[0].set_title('\n'.join([f'{k}: {linestyles[i]}' for i, k in enumerate(dfs.keys())])) + else: + axes[0].set_title(list(dfs.keys())[0]) + + axes[i].set_xlabel(xlabel) + if formattime: + if 'time' in xlabel.lower() or 'date' in xlabel.lower(): + plt.gcf().autofmt_xdate() + + if ylabels: + for i, ylabel in enumerate(ylabels): + axes[i].set_ylabel(ylabel) + if ylogscale: + for i, log in enumerate(ylogscale): + if log: + axes[i].set_yscale('log') + if manual_legends: + axes[0].legend(list(dfs.keys()), loc='upper right', fontsize=10) + if blackout_first: + axes[0].plot(df_plot.index, df_plot[quantities[0]], color='black') + + plt.show() + + return fig + + +def viz_wholesale(filepath, span=range(2025, 2056, 2)): + """Visualize wholesale market data. + + Args: + filepath (str): file path to csv file. + span (range, optional): range or list of years to visualize. Defaults to range(2025,2056,2). + """ + + if isinstance(filepath, str): + df = pd.read_csv(filepath) + df.Date = pd.to_datetime(df.Date, format='%m/%d/%y %H:%M') + else: + df = filepath.copy() + + df['Year'], df['Hour'] = df.Date.dt.year, df.Date.dt.hour + df = pd.pivot_table(df, values='price', index=['Hour'], columns=['Year'], aggfunc=np.mean) + mappaple = df.groupby('Hour').mean().plot(y=span, cmap='jet') + plt.legend(ncol=4, loc='upper right') + plt.xlabel('Hour of Day') + plt.ylabel('Price [Nominal $/MWh]') + plt.show() + + +def preprocess_cambium_capacity( + scenario, + state, + infl, + base_year=2023, + span=range(2024, 2061), + plot=False, + dst_dir='.', + save=None, + adjustment=0, + states_with_no_capacity_market=['TX'], +): + """Preprocess and plot Cambium capacity market data for a chosen state and forecast scenario""" + + filepath = f'../../Cambium_2022/{scenario}/Cambium22_{scenario}_annual_state.csv' + df = pd.read_csv(filepath, header=5) + df = df.loc[df.state == state, ['t', 'capacity_cost_enduse']] + df = df.rename(columns={'t': 'Year', 'capacity_cost_enduse': 'capacity cost'}) + df['capacity cost'] *= 8760 / 1e3 # to convert $/MWh to $/kW-yr + + if state in states_with_no_capacity_market: + df['capacity cost'] = 0.0 + + df_full = pd.merge(pd.DataFrame({'Year': span}), df, how='outer', on='Year').interpolate(method='linear', order=1) + + if adjustment > 0: + df_full[ + 'capacity cost' + ] += adjustment # based on Fig 3-C of https://eta-publications.lbl.gov/sites/default/files/berkeley_lab_2021.11-_integrating_cambium_prices_into_electric-sector_decisions.pdf + + df_full['capacity cost'] = df_full['capacity cost'] * (1 + infl) ** (df_full.Year - base_year) + if plot: + # plt.scatter(df["Year"], df["capacity cost"], color="black") + plt.plot(df_full['Year'], df_full['capacity cost']) + plt.xlabel('Year') + plt.ylabel('Capacity Value [Nominal $/kW-yr]') + plt.show() + + if save: + df_full.to_csv(os.path.join(dst_dir, 'Capacity.csv'), index=False) + + return df_full + + +def preprocess_cambium_wholesale( + scenario, + state, + infl, + daily_fat_factor=1.0, + seasonal_fat_factor=1.0, + base_year=2022, + span=range(2024, 2061), + plot=False, + dst_dir='.', + save=False, +): + """Preprocess and plot Cambium wholesale market data for a chosen state and forecast scenario.""" + + base_dir = os.path.join('../../Cambium_2022/', scenario) + data_dir = os.path.join(base_dir, 'hourly_state') + filepaths = [os.path.join(data_dir, filename) for filename in os.listdir(data_dir) if f'_{state}_' in filename] + avail_years = np.sort([int(f.split('.csv')[0].split('_')[-1]) for f in filepaths]) + + df_recs = pd.read_csv(os.path.join(base_dir, 'RECs.csv')) + df_recs['Date'] = pd.to_datetime(df_recs['Date'], format='%m/%d/%y %H:%M') + df_recs = df_recs.loc[df_recs.Date.dt.year >= 2024] + + df = [] + for i, year in enumerate(avail_years): + filepath = os.path.join(data_dir, f'Cambium22_{scenario}_hourly_{state}_{year}.csv') + df_temp = pd.read_csv(filepath, header=5) + + if i == 0: + df_temp['Date'] = pd.to_datetime(df_temp['timestamp_local']) + df_temp['Month'] = df_temp.Date.dt.month + df_temp['Day'] = df_temp.Date.dt.day + df_temp['Hour'] = df_temp.Date.dt.hour + df_temp['DayofYear'] = df_temp.Date.dt.dayofyear + df_temp['HourofYear'] = np.arange(1, len(df_temp) + 1) + df_temp[year] = df_temp['energy_cost_enduse'].values + df = df_temp[['Month', 'Day', 'Hour', 'DayofYear', 'HourofYear', year]].copy() + else: + df[year] = df_temp['energy_cost_enduse'].values + + for i, year in enumerate(span): + + if year in avail_years: + continue + + if any(year < avail_years): + upper_years = avail_years[avail_years > year] + lower_years = avail_years[avail_years < year] + upper_year = upper_years[np.argmin(np.abs(year - upper_years))] + lower_year = lower_years[np.argmin(np.abs(lower_years - year))] + assert (year < upper_year) and (year > lower_year), 'Issue with lower/upper year allocation ...' + + dpdy = (df[upper_year] - df[lower_year]) / (upper_year - lower_year) + + df[year] = df[lower_year] + dpdy * (year - lower_year) + + for i, year in enumerate(span): + df[year] = df[year] * (1 + infl) ** (year - base_year) + + daily_price_means = np.zeros(len(df)) + for i in range(int(len(daily_price_means) / 24)): + daily_price_means[24 * i : 24 * i + 24] = df[year][24 * i : 24 * i + 24].mean() + + seasonal_price_means = np.zeros(len(df)) + for i in range(int(len(seasonal_price_means) / 8760)): + seasonal_price_means[8760 * i : 8760 * i + 8760] = df[year][8760 * i : 8760 * i + 8760].mean() + + df[year] += daily_fat_factor * (df[year] - daily_price_means) + seasonal_fat_factor * ( + df[year] - seasonal_price_means + ) + + df_melt = pd.melt(df, id_vars=['Hour', 'Day', 'Month'], value_vars=span, var_name='Year', value_name='price') + df_melt['Date'] = pd.to_datetime(df_melt[['Year', 'Month', 'Day', 'Hour']]) + df_final = pd.merge(df_melt, df_recs, how='inner', on='Date')[['Date', 'Hour', 'price', 'recs_price']] + + baseload_score = df_final.price.mean() # $/MWh + arbitrage_score = ( + df_final.groupby('Hour').mean(numeric_only=True)['price'].max() + - df_final.groupby('Hour').mean(numeric_only=True)['price'].min() + ) # $/MWh + scores = {'baseload': round(baseload_score, 2), 'arbitrage': round(arbitrage_score, 2)} + if plot: + viz_wholesale(df_final, span=span[::2]) + + df_final['Date'] = df_final.Date.dt.strftime('%m/%d/%y %H:%M') + if save: + df_final.to_csv(os.path.join(dst_dir, 'DA.csv'), index=False) + + return df_final, df, scores + + +def preprocess_cambium_elcc( + scenario, state, span=range(2024, 2061), plot=False, dst_dir='../../Data/dummy', save=False +): + """Preprocess and plot Cambium ELCC data for a chosen state and forecast scenario.""" + + filepath = f'../../Cambium_2022/{scenario}/Cambium22_{scenario}_annual_state.csv' + df = pd.read_csv(filepath, header=5) + df = df.loc[df.state == state, ['t', 'battery_MW']] + df = df.rename(columns={'t': 'Year', 'battery_MW': 'battery_GW'}) + df['battery_GW'] = df['battery_GW'] / 1e3 + df_full = pd.merge(pd.DataFrame({'Year': span}), df, how='outer', on='Year').interpolate(method='linear', order=1) + + # based on Figure 20 in https://www.ethree.com/wp-content/uploads/2019/06/E3_Long_Run_Resource_Adequacy_CA_Deep-Decarbonization_Final.pdf + d = {0: 1, 5: 0.80, 10: 0.60, 15: 0.40, 20: 0.35, 25: 0.30, 30: 0.20, 40: 0.11, 45: 0.10, 55: 0.06, 75: 0.05} + df_elcc = pd.DataFrame([d.keys(), d.values()]).T.rename(columns={0: 'battery_GW', 1: 'elcc'}) + df_elcc = pd.merge(pd.DataFrame({'battery_GW': range(101)}), df_elcc, on='battery_GW', how='outer').interpolate( + method='linear' + ) + + df_full['elcc'] = df_full['battery_GW'].apply( + lambda x: df_elcc.loc[df_elcc['battery_GW'] == int(x), 'elcc'].iloc[0] + ) + + bat_filepath = os.path.join(dst_dir, 'battery_costs.csv') + df_bat = pd.read_csv(bat_filepath) + df_bat.drop(columns='elcc', inplace=True) + df_bat = pd.merge(df_full, df_bat, on='Year', how='left') + df_bat.drop(columns=[i for i in df_bat.columns if 'battery_GW' in i], inplace=True) + + if save: + df_bat.to_csv(bat_filepath, index=False) + + if plot: + df_bat.plot(x='Year', y='elcc', legend=False) + plt.ylabel('ELCC [fraction]') + + return df_bat + + +def viz_trial_logs(trial_dir, quantities, span=2000, figsize=(10, 10)): + """Visualize logs produced from an Rllib training session.""" + + df = pd.read_json(os.path.join(trial_dir, 'result.json'), lines=True)[:span] + fig, ax = plt.subplots(len(quantities), 1, figsize=figsize, sharex=True) + + for i, (q, label) in enumerate(quantities.items()): + data = df['custom_metrics'].apply(lambda x: dict(x).get(q + '_mean')).values + ax[i].plot(range(len(df)), data, label=label, color=colors[i]) + ax[i].legend([q], loc='upper right') + if q in ['NPV', 'ROI']: + ax[i].set_ylim([0, None]) + plt.show() + + +def compute_f(Rewaterprod, well_diam): + """Compute Darcy friction coefficient. + + Args: + Rewaterprod (Union[ndarray, float]): Reynold's number + well_diam (Union[ndarray, float]): well diameter + + Returns: + Union[ndarray, float]: Darcy friction factor + """ + + relroughness = 1e-4 / well_diam + f = 1.0 / np.power(-2 * np.log10(relroughness / 3.7 + 5.74 / np.power(Rewaterprod, 0.9)), 2.0) + f = 1.0 / np.power((-2 * np.log10(relroughness / 3.7 + 2.51 / Rewaterprod / np.sqrt(f))), 2.0) + f = 1.0 / np.power((-2 * np.log10(relroughness / 3.7 + 2.51 / Rewaterprod / np.sqrt(f))), 2.0) + f = 1.0 / np.power((-2 * np.log10(relroughness / 3.7 + 2.51 / Rewaterprod / np.sqrt(f))), 2.0) + f = 1.0 / np.power((-2 * np.log10(relroughness / 3.7 + 2.51 / Rewaterprod / np.sqrt(f))), 2.0) + f = 1.0 / np.power( + (-2 * np.log10(relroughness / 3.7 + 2.51 / Rewaterprod / np.sqrt(f))), 2.0 + ) # 6 iterations to converge + + # if laminar + f = np.where(Rewaterprod < 2300.0, 64.0 / nonzero(Rewaterprod), f) + + return f + + +def densitywater(Twater): + """Computationally efficient correlation for water density based on GEOPHIRES. + + Args: + Twater (Union[ndarray, float]): water temperature in deg C + + Returns: + Union[ndarray, float]: water density in kg/m3 + """ + + T = Twater + 273.15 + rhowater = ( + 0.7983223 + (1.50896e-3 - 2.9104e-6 * T) * T + ) * 1e3 # water density correlation as used in Geophires v1.2 [kg/m3] + return rhowater + + +def viscositywater(Twater): + """Computationally efficient correlation for water viscosity based on the GEOPHIRES. + + Args: + Twater (Union[ndarray, float]): water temperature in deg C + + Returns: + Union[ndarray, float]: water viscosity in m2/s + """ + + muwater = 2.414e-5 * np.power( + 10, 247.8 / (Twater + 273.15 - 140) + ) # accurate to within 2.5% from 0 to 370 degrees C [Ns/m2] + return muwater + + +def heatcapacitywater(Twater): + """Computationally efficient correlation for water specific heat capacity based on the GEOPHIRES. + + Args: + Twater (Union[ndarray, float]): water temperature in deg C + + Returns: + Union[ndarray, float]: water specific heat capacity in J/kg-K + """ + + # Based on GEOPHIRES correlations (more stable XSTEAM) + Twater = (Twater + 273.15) / 1000 + A = -203.6060 + B = 1523.290 + C = -3196.413 + D = 2474.455 + E = 3.855326 + cpwater = (A + B * Twater + C * Twater**2 + D * Twater**3 + E / (Twater**2)) / 18.02 * 1000 + return cpwater + + +def vaporpressurewater(Twater): + """Computationally efficient correlation for vapor pressure based on the GEOPHIRES. + + Args: + Twater (Union[ndarray, float]): water temperature in deg C + + Returns: + Union[ndarray, float]: vapor pressure in kPa + """ + + return np.where( + Twater < 100, + 133.322 * (10 ** (8.07131 - 1730.63 / (233.426 + Twater))) / 1000, + 133.322 * (10 ** (8.14019 - 1810.94 / (244.485 + Twater))) / 1000, + ) + + +def compute_drilling_cost( + well_tvd, well_diam, lateral_length=0, numberoflaterals=1, total_drilling_length=None, drilling_cost=None +): + """Correlations for computing drilling costs.""" + well_md = well_tvd + lateral_length * numberoflaterals + + if total_drilling_length: + if not drilling_cost: + raise ValueError('You must specify drilling drilling_cost for the provided system design.') + else: + return total_drilling_length * drilling_cost / 1e6 + + if drilling_cost: + return well_md * drilling_cost / 1e6 + # Divide by 1.15 to remove the 15% contiengency already included by SNL (ref: GETEM page 85) + if well_diam > 0.3: # units in meters + if lateral_length > 0: + return (0.2553 * well_md**2 + 1716.7157 * well_md + 500867.0) * 1e-6 / 1.15 + else: + return (0.2818 * well_tvd**2 + 1275.5213 * well_tvd + 632315.0) * 1e-6 / 1.15 + else: + if lateral_length > 0: + return (0.2898 * well_md**2 + 822.1507 * well_md + 680563.0) * 1e-6 / 1.15 + else: + return (0.3021 * well_tvd**2 + 584.9112 * well_tvd + 751368.0) * 1e-6 / 1.15 + + +def compute_latlon_distance(lat1, lon1, lat2, lon2): + """Compute Euclidean distance in kilometers based on latlon cooredinates of two locations.""" + + return ( + np.arccos(np.sin(lat1) * np.sin(lat2) + np.cos(lat1) * np.cos(lat2) * np.cos(lon2 - lon1)) * 6371 + ) # kilometers + + +def egs_mw_from_temp(T): + """Find GETEM default for power plant size in MW given resource temperature.""" + + if T < 140: + return 10 + elif T < 175: + return 15 + elif T < 250: + return 25 + else: + return 30 + + +def gpd_geographic_area(geodf): + """Compute the geographic area of latlon polygons in a geopandas df.""" + + if not geodf.crs and geodf.crs.is_geographic: + raise TypeError('geodataframe should have geographic coordinate system') + + geod = geodf.crs.get_geod() + + def area_calc(geom): + if geom.geom_type not in ['MultiPolygon', 'Polygon']: + return np.nan + + # For MultiPolygon do each separately + if geom.geom_type == 'MultiPolygon': + return np.sum([area_calc(p) for p in geom.geoms]) + + # orient to ensure a counter-clockwise traversal. + # See https://pyproj4.github.io/pyproj/stable/api/geod.html + # geometry_area_perimeter returns (area, perimeter) + return geod.geometry_area_perimeter(orient(geom, 1))[0] # m2 + + return geodf.geometry.apply(area_calc) + + +def latlon_tres_to_depth( + df_maps, query_northing, query_easting, tres, MJth_per_km3=5.1e9, thickness=500, eta=0.1, L=25 +): + """Get depth required to reach a target temperature at a latlon location.""" + + all_depths = np.array(list(df_maps.keys())) + depths = all_depths + temps = [] + for depth in all_depths: + df_temp = df_maps[depth] + row = df_temp.iloc[ + [ + ( + np.sqrt((query_northing - df_temp['Northing']) ** 2 + (query_easting - df_temp['Easting']) ** 2) + ).argmin() + ] + ] + temp = row['T'].values[0] + temps.append(temp) + if temp >= tres: + depths = all_depths[: len(temps)] + break + + temps = np.array(sorted(temps)) + surface_temp = temps[0] + geothermal_gradient = np.mean(np.clip(np.diff(temps[[0, -1]]) / (np.diff(depths[[0, -1]]) / 1000), 0.0, np.inf)) + if geothermal_gradient <= 0.0: + print(temps, depths, tres, temp) + print('Non-Positive Geothermal Gradient ... !!!') + + if tres > max(temps): + z = np.polyfit(temps, depths, 1) + p = np.poly1d(z) + well_depth = p(tres) + else: + well_depth = np.interp(tres, temps, depths) + + A_r = gpd_geographic_area(row).values[0] / 1e6 # km2 + V_r = A_r * thickness / 1000 # km3 + electric_energy_MJe = MJth_per_km3 * V_r * eta + electric_power_MWe = electric_energy_MJe / (L * 365 * 24 * 3600) + + return well_depth, surface_temp, geothermal_gradient, electric_power_MWe, A_r, V_r + + +def latlon_depth_to_tres( + df_maps, query_northing, query_easting, well_depth, MJth_per_km3=5.1e9, thickness=1000, eta=0.1, L=25 +): + """Get depth required to reach a target temperature at a latlon location.""" + + all_depths = np.sort(list(df_maps.keys())) + ref_depth = all_depths[np.argmin(np.abs(np.array(list(df_maps.keys())) - well_depth))] + df_temp = df_maps[ref_depth] + ref_row = df_temp.iloc[ + [(np.sqrt((query_northing - df_temp['Northing']).abs() + (query_easting - df_temp['Easting']).abs())).argmin()] + ] + + depths = all_depths[all_depths <= well_depth] + temps = [] + for depth in depths: + df_temp = df_maps[depth] + row = df_temp.iloc[ + [ + ( + np.sqrt((query_northing - df_temp['Northing']).abs() + (query_easting - df_temp['Easting']).abs()) + ).argmin() + ] + ] + temp = row['T'].values[0] + temps.append(temp) + + temps = np.array(sorted(temps)) + surface_temp = temps[0] + geothermal_gradient = np.mean(np.clip(np.diff(temps[[0, -1]]) / (np.diff(depths[[0, -1]]) / 1000), 0.0, np.inf)) + if geothermal_gradient <= 0.0: + print(temps, depths, tres, temp) + print('Non-Positive Geothermal Gradient ... !!!') + + z = np.polyfit(depths[-2:], temps[-2:], 1) + p = np.poly1d(z) + tres = p(well_depth) + + A_r = gpd_geographic_area(ref_row).values[0] / 1e6 # km2 + V_r = A_r * thickness / 1000 # km3 + electric_energy_MJe = MJth_per_km3 * V_r * eta + electric_power_MWe = electric_energy_MJe / (L * 365 * 24 * 3600) + + return tres, surface_temp, geothermal_gradient, electric_power_MWe, A_r, V_r + + +def augustine_MWeperkm3(tres): + """Based on page22 of Augustine (2011): https://www.nrel.gov/docs/fy12osti/47459.pdf""" + if tres <= 200: + return 0.59 + elif tres <= 250: + return 0.76 + elif tres <= 300: + return 0.86 + elif tres <= 350: + return 0.97 + else: + return 1.19 + + +def augustine_eff(tres): + """Based on page22 of Augustine (2011): https://www.nrel.gov/docs/fy12osti/47459.pdf""" + if tres <= 200: + return 0.11 + elif tres <= 250: + return 0.14 + elif tres <= 300: + return 0.16 + elif tres <= 350: + return 0.18 + else: + return 0.22 + + +def nonzero(x, thresh=1e-6): + """Ensure input is nonzero + + Args: + x (ndarray): input numbers + thresh (float, optional): threshold below which numbers are set to zero. Defaults to 1E-6. + + Returns: + ndarray: nonzero version of input array + """ + return np.maximum(thresh, x) + + +def grid_bounds(geom, delta): + """Create a grid/mesh based on geometry.""" + minx, miny, maxx, maxy = geom.bounds + nx = int((maxx - minx) / delta) + ny = int((maxy - miny) / delta) + gx, gy = np.linspace(minx, maxx, nx), np.linspace(miny, maxy, ny) + grid = [] + for i in range(len(gx) - 1): + for j in range(len(gy) - 1): + poly_ij = Polygon([[gx[i], gy[j]], [gx[i], gy[j + 1]], [gx[i + 1], gy[j + 1]], [gx[i + 1], gy[j]]]) + grid.append(poly_ij) + return grid + + +def partition(geom, delta): + """Partition a geometry based on delta value.""" + prepared_geom = prep(geom) + grid = list(filter(prepared_geom.intersects, grid_bounds(geom, delta))) + return grid + + +def harrison(z): + """Harrison temperature correction. + + Args: + z (ndarray): true vertical depth in meters + + Returns: + ndarray: harrison correction in deg C + """ + return -2.3449e-6 * z**2 + 0.018268 * z - 16.512 + + +def forster(z): + """Forster temperature correction. + + Args: + z (ndarray): true vertical depth in meters + + Returns: + ndarray: forster correction in deg C + """ + return 0.017 * z - 6.58 + + +def retrieve_weather(lat, lon, year, station_idx_limit=10): + """Retrieve weather.""" + + # Set time period + findtz = TimezoneFinder() + findstations = Stations() + start = datetime(year, 1, 1) + end = datetime(year, 12, 31, 23, 59) + + data = [] + station_idx = 0 + stations = findstations.nearby(lat, lon).fetch(station_idx_limit + 1) + + while len(data) != 8760: + station = stations.iloc[[station_idx]] + data = Hourly( + station, start - timedelta(days=2), end + timedelta(days=2) + ) # get more days to account for timezone shifting + data = data.fetch() + data = data.bfill().ffill() + data.reset_index(inplace=True) + tz = findtz.timezone_at(lng=lon, lat=lat) + if len(data): + data['time'] = data.time.dt.tz_localize('utc').dt.tz_convert(tz).dt.tz_localize(None) + year_col = data.time.dt.year + data = data[year_col == year].reset_index(drop=True) + + if station_idx >= station_idx_limit: + print(state, f'##### {len(data)} #####') + break + station_idx += 1 + + return data + + +class FaissKNeighbors: + def __init__(self, k=5): + self.index = None + self.y = None + self.k = k + + def fit(self, X, y): + self.index = faiss.IndexFlatL2(X.shape[1]) + self.index.add(X.astype(np.float32)) + self.y = y + + def predict(self, X): + + distances, indices = self.index.search(X.astype(np.float32), k=self.k) + inv_distances = 1 / (distances + 1e-3) ** 4 + inv_distances = inv_distances / inv_distances.sum(axis=1, keepdims=True) + predictions = (inv_distances[:, :, None] * self.y[indices]).sum(axis=1) + + return predictions + + +if __name__ == '__main__': + pass diff --git a/tests/fgem_tests/__init__.py b/tests/fgem_tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/fgem_tests/test_fgem.py b/tests/fgem_tests/test_fgem.py new file mode 100644 index 000000000..ab7380650 --- /dev/null +++ b/tests/fgem_tests/test_fgem.py @@ -0,0 +1,17 @@ +from __future__ import annotations + + +from base_test_case import BaseTestCase + +# ruff: noqa: I001 # Successful module initialization is dependent on this specific import order. + +# noinspection PyProtectedMember + +# noinspection PyProtectedMember + + +# noinspection SpellCheckingInspection +class FgemTestCase(BaseTestCase): + + def test_fgem(self): + pass From f4c3e0dadf77e7759d37a2cbbb19f4429b79d393 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Fri, 16 May 2025 10:33:58 -0700 Subject: [PATCH 2/4] Move relevant utils methods to powerplant.py --- src/fgem/powerplant.py | 50 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/src/fgem/powerplant.py b/src/fgem/powerplant.py index e236af494..1ba9b50c5 100644 --- a/src/fgem/powerplant.py +++ b/src/fgem/powerplant.py @@ -7,11 +7,45 @@ import numpy as np from scipy.spatial import cKDTree -from .utils.utils import * - parent_path = Path(__file__).parent +class _Utils: + @staticmethod + def heatcapacitywater(Twater): + """Computationally efficient correlation for water specific heat capacity based on the GEOPHIRES. + + Args: + Twater (Union[ndarray, float]): water temperature in deg C + + Returns: + Union[ndarray, float]: water specific heat capacity in J/kg-K + """ + + # Based on GEOPHIRES correlations (more stable XSTEAM) + Twater = (Twater + 273.15) / 1000 + A = -203.6060 + B = 1523.290 + C = -3196.413 + D = 2474.455 + E = 3.855326 + cpwater = (A + B * Twater + C * Twater**2 + D * Twater**3 + E / (Twater**2)) / 18.02 * 1000 + return cpwater + + @staticmethod + def nonzero(x, thresh=1e-6): + """Ensure input is nonzero + + Args: + x (ndarray): input numbers + thresh (float, optional): threshold below which numbers are set to zero. Defaults to 1E-6. + + Returns: + ndarray: nonzero version of input array + """ + return np.maximum(thresh, x) + + class CustomUnpickler(pickle.Unpickler): def find_class(self, module, name): @@ -140,9 +174,13 @@ def step( if m_tes_out > 0: m_wh_to_turbine = m_turbine - m_tes_out self.T_mix = ( - m_wh_to_turbine * heatcapacitywater(T_prd_wh) * T_prd_wh - + m_tes_out * heatcapacitywater(T_tes_out) * T_tes_out - ) / (m_wh_to_turbine * heatcapacitywater(T_prd_wh) + m_tes_out * heatcapacitywater(T_tes_out) + 1e-3) + m_wh_to_turbine * _Utils.heatcapacitywater(T_prd_wh) * T_prd_wh + + m_tes_out * _Utils.heatcapacitywater(T_tes_out) * T_tes_out + ) / ( + m_wh_to_turbine * _Utils.heatcapacitywater(T_prd_wh) + + m_tes_out * _Utils.heatcapacitywater(T_tes_out) + + 1e-3 + ) else: self.T_mix = T_prd_wh @@ -553,7 +591,7 @@ def __init__(self, Tres, Tamb, m_prd, num_prd=None, ppc=None, cf=1.0, k=2): self.T_inj = np.clip(model_output[1], a_min=self.Tamb_design, a_max=self.Tres_design) # deg C if self.num_prd is None: - m_g = ppc / nonzero(self.power_output_MWh_kg) / 3600 # kg/s + m_g = ppc / _Utils.nonzero(self.power_output_MWh_kg) / 3600 # kg/s self.num_prd = np.ceil(m_g / m_prd).astype(int) def compute_cplant(self, MaxProducedTemperature, min_cost=0): From 77e3fded43746e916fe79f6a69f54f35e0ecacc2 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Fri, 16 May 2025 11:25:09 -0700 Subject: [PATCH 3/4] WIP - SurfacePlantFgemORC.py --- setup.py | 2 + src/fgem/powerplant.py | 4 +- src/geophires_x/Model.py | 5 + src/geophires_x/OptionList.py | 1 + src/geophires_x/SurfacePlant.py | 2 +- src/geophires_x/SurfacePlantFgemORC.py | 180 +++++++++++++++++++++++++ tests/fgem_tests/test_fgem.py | 20 ++- 7 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 src/geophires_x/SurfacePlantFgemORC.py diff --git a/setup.py b/setup.py index 12b79a10d..b7a75997d 100755 --- a/setup.py +++ b/setup.py @@ -88,6 +88,8 @@ def read(*names, **kwargs): 'nrel-pysam', 'tabulate', 'tqdm', + #'sklearn', + 'scikit-learn', ], extras_require={ # eg: diff --git a/src/fgem/powerplant.py b/src/fgem/powerplant.py index 1ba9b50c5..166981e9c 100644 --- a/src/fgem/powerplant.py +++ b/src/fgem/powerplant.py @@ -543,7 +543,7 @@ def compute_injection_temp(self, T, T_amb, m_turbine): class ORCPowerPlant(BasePowerPlant): """On/Off-Design Air-cooled ORC Binary power plant developed in Python by Aljubran et al. (2024).""" - def __init__(self, Tres, Tamb, m_prd, num_prd=None, ppc=None, cf=1.0, k=2): + def __init__(self, Tres, Tamb, m_prd, num_prd=None, ppc=None, cf=1.0, k=2, timestep=timedelta(hours=1)): """Define attributes for the BasePowerPlant class. Args: @@ -583,7 +583,7 @@ def __init__(self, Tres, Tamb, m_prd, num_prd=None, ppc=None, cf=1.0, k=2): if ppc is None: ppc = max(model_output[0] * num_prd, 1) # MWe power plant capacity for all wells - super(ORCPowerPlant, self).__init__(ppc, Tres, cf) + super(ORCPowerPlant, self).__init__(ppc, Tres, cf, timestep=timestep) self.power_output_MWh_kg = np.clip( model_output[0] / self.m_prd_design / 3600, a_min=0.0, a_max=2.5e-4 diff --git a/src/geophires_x/Model.py b/src/geophires_x/Model.py index 211c26a78..72d492b95 100644 --- a/src/geophires_x/Model.py +++ b/src/geophires_x/Model.py @@ -8,6 +8,7 @@ from geophires_x.GeoPHIRESUtils import read_input_file from geophires_x.OutputsAddOns import OutputsAddOns from geophires_x.OutputsS_DAC_GT import OutputsS_DAC_GT +from geophires_x.SurfacePlantFgemORC import SurfacePlantFgemOrc from geophires_x.TDPReservoir import TDPReservoir from geophires_x.WellBores import WellBores from geophires_x.SurfacePlant import SurfacePlant @@ -176,6 +177,8 @@ def __init__(self, enable_geophires_logging_config=True, input_file=None): self.surfaceplant = SurfacePlantSUTRA(self) elif self.InputParameters['Power Plant Type'].sValue in ['9', 'Industrial']: self.surfaceplant = SurfacePlantIndustrialHeat(self) + elif self.InputParameters['Power Plant Type'].sValue in ['10', 'FGEM ORC']: + self.surfaceplant = SurfacePlantFgemOrc(self) # if we find out we have an add-ons, we need to instantiate it, then read for the parameters if 'AddOn Nickname 1' in self.InputParameters: @@ -237,6 +240,8 @@ def read_parameters(self, default_output_path: Path = None) -> None: self.surfaceplant = SurfacePlantSupercriticalOrc(self) elif self.surfaceplant.plant_type.value == PlantType.SINGLE_FLASH: self.surfaceplant = SurfacePlantSingleFlash(self) + elif self.surfaceplant.plant_type.value == PlantType.FGEM_ORC: + self.surfaceplant = SurfacePlantFgemOrc(self) else: # default is double flash self.surfaceplant = SurfacePlantDoubleFlash(self) diff --git a/src/geophires_x/OptionList.py b/src/geophires_x/OptionList.py index 6d0dfc6ce..e1e845f71 100644 --- a/src/geophires_x/OptionList.py +++ b/src/geophires_x/OptionList.py @@ -86,6 +86,7 @@ class PlantType(GeophiresInputEnum): DISTRICT_HEATING = 7, "District Heating" RTES = 8, "Reservoir Thermal Energy Storage" INDUSTRIAL = 9, "Industrial" + FGEM_ORC = 10, "FGEM ORC" @staticmethod def from_input_string(input_string: str): diff --git a/src/geophires_x/SurfacePlant.py b/src/geophires_x/SurfacePlant.py index ccf2ac9a6..add973a44 100644 --- a/src/geophires_x/SurfacePlant.py +++ b/src/geophires_x/SurfacePlant.py @@ -279,7 +279,7 @@ def __init__(self, model: Model): self.plant_type = self.ParameterDict[self.plant_type.Name] = intParameter( "Power Plant Type", DefaultValue=PlantType.SUB_CRITICAL_ORC.int_value, - AllowableRange=[1, 2, 3, 4, 5, 6, 7, 8, 9], + AllowableRange=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ValuesEnum=PlantType, UnitType=Units.NONE, ErrMessage="assume default power plant type (1: subcritical ORC)", diff --git a/src/geophires_x/SurfacePlantFgemORC.py b/src/geophires_x/SurfacePlantFgemORC.py new file mode 100644 index 000000000..83746fd0b --- /dev/null +++ b/src/geophires_x/SurfacePlantFgemORC.py @@ -0,0 +1,180 @@ +from datetime import timedelta +from pathlib import Path + +import numpy as np + +from fgem.powerplant import GEOPHIRESORCPowerPlant, ORCPowerPlant +from geophires_x.Parameter import HasQuantity +from geophires_x.SurfacePlant import SurfacePlant +import geophires_x.Model as Model + + +class SurfacePlantFgemOrc(SurfacePlant): + def __init__(self, model: Model): + """ + The __init__ function is called automatically when a class is instantiated. + It initializes the attributes of an object, and sets default values for certain arguments that can be overridden + by user input. + The __init__ function is used to set up all the parameters in the Surfaceplant. + :param model: The container class of the application, giving access to everything else, including the logger + :type model: :class:`~geophires_x.Model.Model` + :return: None + """ + + model.logger.info("Init " + self.__class__.__name__ + ": " + __name__) + super().__init__(model) # Initialize all the parameters in the superclass + + # Set up all the Parameters that will be predefined by this class using the different types of parameter classes. + # Setting up includes giving it a name, a default value, The Unit Type (length, volume, temperature, etc.) and + # Unit Name of that value, sets it as required (or not), sets allowable range, the error message if that range + # is exceeded, the ToolTip Text, and the name of teh class that created it. + # This includes setting up temporary variables that will be available to all the class but noy read in by user, + # or used for Output + # This also includes all Parameters that are calculated and then published using the Printouts function. + + # These dictionaries contain a list of all the parameters set in this object, stored as "Parameter" and + # "OutputParameter" Objects. This will allow us later to access them in a user interface and get that list, + # along with unit type, preferred units, etc. + + # local variable initialization + sclass = self.__class__.__name__ + self.MyClass = sclass + self.MyPath = Path(__file__).resolve() + + model.logger.info("Complete " + self.__class__.__name__ + ": " + __name__) + + def __str__(self): + return "SurfacePlantFgemORC" + + def read_parameters(self, model: Model) -> None: + """ + The read_parameters function reads in the parameters from a dictionary and stores them in the parameters. + It also handles special cases that need to be handled after a value has been read in and checked. + If you choose to subclass this master class, you can also choose to override this method (or not), and if you do + :param model: The container class of the application, giving access to everything else, including the logger + :return: None + """ + model.logger.info("Init " + self.__class__.__name__ + ": " + __name__) + super().read_parameters(model) # Initialize all the parameters in the superclass + model.logger.info("complete " + self.__class__.__name__ + ": " + __name__) + + def Calculate(self, model: Model) -> None: + """ + :param model: The container class of the application + :type model: :class:`~geophires_x.Model.Model` + """ + + model.logger.info("Init " + self.__class__.__name__ + ": " + __name__) + + def degC(p: HasQuantity) -> float: + return p.quantity().to('degC').magnitude + + # fgem_TenteringPP = np.zeros(len(model.reserv.timevector.value)) + + # calculate power plant entering temperature + self.TenteringPP.value = SurfacePlant.power_plant_entering_temperature(self, self.enduse_option.value, + model.reserv.timevector.value, + self.T_chp_bottom.value, + model.wellbores.ProducedTemperature.value) + + + + # Availability water + self.Availability.value = SurfacePlant.availability_water(self, self.ambient_temperature.value, + self.TenteringPP.value, + self.ambient_temperature.value) + + # Subcritical ORC-specific values. + if self.ambient_temperature.value < 15.: + C21 = 0.0 + C11 = 2.746E-3 + C01 = -8.3806E-2 + D21 = 0.0 + D11 = 2.713E-3 + D01 = -9.1841E-2 + C22 = 0.0 + C12 = 0.0894 + C02 = 55.6 + D22 = 0.0 + D12 = 0.0894 + D02 = 62.6 + else: + C21 = 0.0 + C11 = 2.713E-3 + C01 = -9.1841E-2 + D21 = 0.0 + D11 = 2.676E-3 + D01 = -1.012E-1 + C22 = 0.0 + C12 = 0.0894 + C02 = 62.6 + D22 = 0.0 + D12 = 0.0894 + D02 = 69.6 + + model.wellbores.Tinj.value, ReinjTemp, etau = SurfacePlant.reinjection_temperature(self, model, + self.ambient_temperature.value, self.TenteringPP.value, model.wellbores.Tinj.value, + C01, C11, C21, D01, D11, D21, C02, C12, C22, D02, D12, D22) + + # calculate electricity & heat production + self.ElectricityProduced.value, self.HeatExtracted.value, self.HeatProduced.value, HeatExtractedTowardsElectricity = \ + SurfacePlant.electricity_heat_production(self, self.enduse_option.value, self.Availability.value, etau, + model.wellbores.nprod.value, + model.wellbores.prodwellflowrate.value, + model.reserv.cpwater.value, + model.wellbores.ProducedTemperature.value, + model.wellbores.Tinj.value, ReinjTemp, self.T_chp_bottom.value, + self.enduse_efficiency_factor.value, self.chp_fraction.value) + + # subtract pumping power for net electricity and calculate first law efficiency + self.NetElectricityProduced.value = self.ElectricityProduced.value - model.wellbores.PumpingPower.value + self.FirstLawEfficiency.value = self.NetElectricityProduced.value / HeatExtractedTowardsElectricity + + # Calculate annual electricity, pum;ping, and heat production + self.HeatkWhExtracted.value, self.PumpingkWh.value, self.TotalkWhProduced.value, self.NetkWhProduced.value, self.HeatkWhProduced.value = \ + SurfacePlant.annual_electricity_pumping_power(self, self.plant_lifetime.value, self.enduse_option.value, + self.HeatExtracted.value, + model.economics.timestepsperyear.value, + self.utilization_factor.value, + model.wellbores.PumpingPower.value, + self.ElectricityProduced.value, + self.NetElectricityProduced.value, self.HeatProduced.value) + + # calculate reservoir heat content + self.RemainingReservoirHeatContent.value = SurfacePlant.remaining_reservoir_heat_content( + self, model.reserv.InitialReservoirHeatContent.value, self.HeatkWhExtracted.value) + + + nameplate_capacity_MW = 10 # FIXME WIP + # self._fgem_geophires_orc_power_plant: GEOPHIRESORCPowerPlant = GEOPHIRESORCPowerPlant( + # nameplate_capacity_MW, + # model.reserv.Tresoutput.value + # ) # FIXME TEMP WIP + + fgem_orc_power_plant = ORCPowerPlant( + #degC(model.reserv.Tresoutput)[0], + degC(model.wellbores.ProducedTemperature)[0], + degC(self.ambient_temperature), + model.wellbores.prodwellflowrate.value, + num_prd=model.wellbores.nprod.value, + # TODO capacity factor + cf =self.utilization_factor.value, + + timestep=timedelta(days=365*(1 / model.economics.timestepsperyear.value)) + ) + + + fgem_Tinj = np.zeros(len(model.reserv.timevector.value)) + fgem_ElectricityProduced = np.zeros(len(model.reserv.timevector.value)) + for t in range(len(model.reserv.timevector.value)): + m_turbine = model.wellbores.prodwellflowrate.value * model.wellbores.nprod.value + fgem_orc_power_plant.step( + m_turbine, # total mass flowing into turbine + model.wellbores.ProducedTemperature.value[t], # T_prd_wh = producer wellhead temperature degC + self.ambient_temperature.value + ) + fgem_Tinj[t] = fgem_orc_power_plant.T_inj + fgem_ElectricityProduced[t] = fgem_orc_power_plant.power_output_MWe + + self._calculate_derived_outputs(model) + model.logger.info(f"complete {self.__class__.__name__}: {__name__}") diff --git a/tests/fgem_tests/test_fgem.py b/tests/fgem_tests/test_fgem.py index ab7380650..48ee1460c 100644 --- a/tests/fgem_tests/test_fgem.py +++ b/tests/fgem_tests/test_fgem.py @@ -2,6 +2,8 @@ from base_test_case import BaseTestCase +from geophires_x_client import GeophiresXResult, GeophiresXClient, GeophiresInputParameters + # ruff: noqa: I001 # Successful module initialization is dependent on this specific import order. @@ -14,4 +16,20 @@ class FgemTestCase(BaseTestCase): def test_fgem(self): - pass + r = self._get_result({}) + self.assertIsNotNone(r) + + def _egs_test_file_path(self) -> str: + # return self._get_test_file_path('generic-egs-case-2_sam-single-owner-ppa.txt') + return self._get_test_file_path('../examples/example4.txt') + + def _get_result(self, _params, file_path=None) -> GeophiresXResult: + if file_path is None: + file_path = self._egs_test_file_path() + + return GeophiresXClient().get_geophires_result( + GeophiresInputParameters( + from_file_path=file_path, + params={'Power Plant Type': 10, **_params}, + ) + ) From 940299bf96148db3ed018ad12ca20ecc9f130cb1 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Fri, 16 May 2025 12:00:07 -0700 Subject: [PATCH 4/4] separate calculate_fgem function --- src/geophires_x/SurfacePlantFgemORC.py | 31 ++++++++++++++++---------- tests/fgem_tests/test_fgem.py | 2 +- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/geophires_x/SurfacePlantFgemORC.py b/src/geophires_x/SurfacePlantFgemORC.py index 83746fd0b..e40fd5964 100644 --- a/src/geophires_x/SurfacePlantFgemORC.py +++ b/src/geophires_x/SurfacePlantFgemORC.py @@ -66,11 +66,6 @@ def Calculate(self, model: Model) -> None: model.logger.info("Init " + self.__class__.__name__ + ": " + __name__) - def degC(p: HasQuantity) -> float: - return p.quantity().to('degC').magnitude - - # fgem_TenteringPP = np.zeros(len(model.reserv.timevector.value)) - # calculate power plant entering temperature self.TenteringPP.value = SurfacePlant.power_plant_entering_temperature(self, self.enduse_option.value, model.reserv.timevector.value, @@ -144,26 +139,36 @@ def degC(p: HasQuantity) -> float: self.RemainingReservoirHeatContent.value = SurfacePlant.remaining_reservoir_heat_content( self, model.reserv.InitialReservoirHeatContent.value, self.HeatkWhExtracted.value) + self._calculate_fgem(model) + self._calculate_derived_outputs(model) + model.logger.info(f"complete {self.__class__.__name__}: {__name__}") + + def _calculate_fgem(self, model: Model): - nameplate_capacity_MW = 10 # FIXME WIP + def degC(p: HasQuantity) -> float: + return p.quantity().to('degC').magnitude + + # fgem_TenteringPP = np.zeros(len(model.reserv.timevector.value)) + + # nameplate_capacity_MW = 10 # FIXME WIP # self._fgem_geophires_orc_power_plant: GEOPHIRESORCPowerPlant = GEOPHIRESORCPowerPlant( # nameplate_capacity_MW, # model.reserv.Tresoutput.value # ) # FIXME TEMP WIP + fgem_timestep = timedelta(days=365 * (1 / model.economics.timestepsperyear.value)) fgem_orc_power_plant = ORCPowerPlant( - #degC(model.reserv.Tresoutput)[0], + # degC(model.reserv.Tresoutput)[0], degC(model.wellbores.ProducedTemperature)[0], degC(self.ambient_temperature), model.wellbores.prodwellflowrate.value, num_prd=model.wellbores.nprod.value, # TODO capacity factor - cf =self.utilization_factor.value, + cf=self.utilization_factor.value, - timestep=timedelta(days=365*(1 / model.economics.timestepsperyear.value)) + timestep=fgem_timestep ) - fgem_Tinj = np.zeros(len(model.reserv.timevector.value)) fgem_ElectricityProduced = np.zeros(len(model.reserv.timevector.value)) for t in range(len(model.reserv.timevector.value)): @@ -176,5 +181,7 @@ def degC(p: HasQuantity) -> float: fgem_Tinj[t] = fgem_orc_power_plant.T_inj fgem_ElectricityProduced[t] = fgem_orc_power_plant.power_output_MWe - self._calculate_derived_outputs(model) - model.logger.info(f"complete {self.__class__.__name__}: {__name__}") + + fgem_calculated = True + + diff --git a/tests/fgem_tests/test_fgem.py b/tests/fgem_tests/test_fgem.py index 48ee1460c..527c9b35c 100644 --- a/tests/fgem_tests/test_fgem.py +++ b/tests/fgem_tests/test_fgem.py @@ -30,6 +30,6 @@ def _get_result(self, _params, file_path=None) -> GeophiresXResult: return GeophiresXClient().get_geophires_result( GeophiresInputParameters( from_file_path=file_path, - params={'Power Plant Type': 10, **_params}, + params={'Power Plant Type': 10, 'Time steps per year': 12, **_params}, ) )