11
11
import os
12
12
import math
13
13
import numpy as np
14
+ from pint .facets .plain import PlainQuantity
15
+
14
16
import geophires_x .Model as Model
15
17
from .Parameter import floatParameter , intParameter , boolParameter , OutputParameter
16
- from .Reservoir import densitywater , heatcapacitywater
18
+ from geophires_x .GeoPHIRESUtils import density_water_kg_per_m3
19
+ from geophires_x .GeoPHIRESUtils import heat_capacity_water_J_per_kg_per_K
17
20
from .Units import *
18
21
from .OptionList import WorkingFluid , Configuration
19
22
26
29
from .WellBores import WellBores , RameyCalc , ProdPressureDropAndPumpingPowerUsingIndexes , WellPressureDrop , \
27
30
ProdPressureDropsAndPumpingPowerUsingImpedenceModel
28
31
29
- from geophires_x .GeoPHIRESUtils import ViscosityWater as viscositywater
32
+ from geophires_x .GeoPHIRESUtils import viscosity_water_Pa_sec
30
33
31
34
esp2 = 10.0e-10
32
35
@@ -162,7 +165,6 @@ def interp_kWt_avg(self, point):
162
165
return self .GWhr * interpn (ivars , self .Wt , point ) / (1000. * self .time [- 1 ] * 86400. * 365. )
163
166
164
167
165
- # #############################point source/sink solution functions################################
166
168
167
169
def pointsource (self , yy , zz , yt , zt , ye , ze , alpha , sp , t ):
168
170
"""
@@ -200,7 +202,6 @@ def pointsource(self, yy, zz, yt, zt, ye, ze, alpha, sp, t):
200
202
return z
201
203
202
204
203
- # #####Chebyshev approximation for numerical Laplace transformation integration from 1e-8 to 1e30###################
204
205
205
206
def chebeve_pointsource (self , yy , zz , yt , zt , ye , ze , alpha , sp ) -> float :
206
207
"""
@@ -237,29 +238,29 @@ def chebeve_pointsource(self, yy, zz, yt, zt, ye, ze, alpha, sp) -> float:
237
238
return temp + (1 / sp * (math .exp (- sp * 1.0e5 ) - math .exp (- sp * 1.0e30 ))) / (ye * ze ) / self .rhorock / self .cprock
238
239
239
240
240
- # ############################Duhamerl convolution method for closed-loop system######################################
241
- def laplace_solution (self , sp ) -> float :
241
+
242
+ def laplace_solution (cls : WellBores , sp , pressure : PlainQuantity ) -> float :
242
243
"""
243
244
Duhamel convolution method for closed-loop system
244
245
:param sp: Laplace variable (1/s)
245
246
:type sp: float
246
247
:return: Toutletl
247
248
:rtype: float
249
+ :param pressure: Lithostatic pressure, per https://github.com/NREL/GEOPHIRES-X/issues/113#issuecomment-1941951134
248
250
"""
249
251
250
252
Toutletl = 0.0
251
- ss = 1.0 / sp / chebeve_pointsource (self , self .y_well , self .z_well , self .y_well , self .z_well - 0.078 ,
252
- self .y_boundary , self .z_boundary , self .alpha_rock , sp )
253
+ ss = 1.0 / sp / chebeve_pointsource (cls , cls .y_well , cls .z_well , cls .y_well , cls .z_well - 0.078 ,
254
+ cls .y_boundary , cls .z_boundary , cls .alpha_rock , sp )
253
255
254
- Toutletl = (self .Tini - self .Tinj .value ) / sp * np .exp (
255
- - sp * ss / self .q_circulation / 24.0 / densitywater (
256
- self .Tini ) / heatcapacitywater (
257
- self .Tini ) * self .Nonvertical_length .value - sp / self .velocity * self .Nonvertical_length .value )
256
+ Toutletl = (cls .Tini - cls .Tinj .value ) / sp * np .exp (
257
+ - sp * ss / cls .q_circulation / 24.0 / density_water_kg_per_m3 (
258
+ cls .Tini , pressure = pressure ) / heat_capacity_water_J_per_kg_per_K (
259
+ cls .Tini , pressure = pressure ) * cls .Nonvertical_length .value - sp / cls .velocity * cls .Nonvertical_length .value )
258
260
return Toutletl
259
261
260
262
261
- # ###############################Numerical Laplace transformation algorithm#########################
262
- def inverselaplace (self , NL , MM ):
263
+ def inverselaplace (cls :WellBores , NL , MM , pressure :PlainQuantity ):
263
264
"""
264
265
Numerical Laplace transformation algorithm
265
266
:param NL: NL
@@ -303,13 +304,13 @@ def inverselaplace(self, NL, MM):
303
304
MM = NL
304
305
305
306
FI = 0.0
306
- Az = DLN2 / self .time_operation .value
307
+ Az = DLN2 / cls .time_operation .value
307
308
Toutlet = 0.0
308
309
for k in range (1 , NL + 1 ):
309
310
Z = Az * k
310
- Toutletl = laplace_solution (self , Z )
311
+ Toutletl = laplace_solution (cls , Z , pressure )
311
312
Toutlet += Toutletl * V [k ]
312
- Toutlet = self .Tini - Az * Toutlet
313
+ Toutlet = cls .Tini - Az * Toutlet
313
314
return Toutlet
314
315
315
316
@@ -449,7 +450,7 @@ def __init__(self, model: Model):
449
450
:type model: :class:`~geophires_x.Model.Model`
450
451
:return: Nothing, and is used to initialize the class
451
452
"""
452
- model .logger .info (" Init " + str ( __class__ ) + ": " + sys ._getframe ().f_code .co_name )
453
+ model .logger .info (f' Init { __class__ !s } : { sys ._getframe ().f_code .co_name } ' )
453
454
454
455
# Initialize the superclass first to gain access to those variables
455
456
super ().__init__ (model )
@@ -856,7 +857,7 @@ def on_invalid_parameter_value(err_msg):
856
857
857
858
# Multilateral code
858
859
859
- def CalculateNonverticalPressureDrop (self , model , time_operation : float , time_max : float , al : float ):
860
+ def CalculateNonverticalPressureDrop (self , model : Model , time_operation : float , time_max : float , al : float ):
860
861
"""
861
862
Calculate nonvertical pressure drops - it will vary as the temperature varies
862
863
:param model: The container class of the application, giving access to everything else, including the logger
@@ -876,8 +877,15 @@ def CalculateNonverticalPressureDrop(self, model, time_operation: float, time_ma
876
877
year = math .trunc (time_operation / al )
877
878
878
879
# nonvertical wellbore fluid conditions based on current temperature
879
- rhowater = densitywater (self .NonverticalProducedTemperature .value [year ])
880
- muwater = viscositywater (self .NonverticalProducedTemperature .value [year ])
880
+ rhowater = density_water_kg_per_m3 (
881
+ self .NonverticalProducedTemperature .value [year ],
882
+ pressure = model .reserv .lithostatic_pressure ()
883
+ )
884
+
885
+ muwater = viscosity_water_Pa_sec (
886
+ self .NonverticalProducedTemperature .value [year ],
887
+ pressure = model .reserv .lithostatic_pressure ()
888
+ )
881
889
vhoriz = self .q_circulation / rhowater / (math .pi / 4. * self .nonverticalwellborediameter .value ** 2 )
882
890
883
891
# assume turbulent flow.
@@ -955,13 +963,19 @@ def Calculate(self, model: Model) -> None:
955
963
956
964
t = self .time_operation .value
957
965
while self .time_operation .value <= self .time_max :
958
- # MIR figure out how to calculate year ands extract Tini from reserv Tresoutput array
966
+ # MIR figure out how to calculate year and extract Tini from reserv Tresoutput array
959
967
year = math .trunc (self .time_operation .value / self .al )
960
- self .NonverticalProducedTemperature .value [year ] = inverselaplace (self , 16 , 0 )
968
+ self .NonverticalProducedTemperature .value [year ] = inverselaplace (
969
+ self , 16 , 0 , model .reserv .lithostatic_pressure ())
961
970
# update alpha_fluid value based on next temperature of reservoir
962
- self .alpha_fluid = self .WaterThermalConductivity .value / densitywater (
963
- self .NonverticalProducedTemperature .value [year ]) / heatcapacitywater (
964
- self .NonverticalProducedTemperature .value [year ]) * 24.0 * 3600.0
971
+
972
+ self .alpha_fluid = self .WaterThermalConductivity .value / density_water_kg_per_m3 (
973
+ self .NonverticalProducedTemperature .value [year ],
974
+ pressure = model .reserv .lithostatic_pressure ()
975
+ ) / heat_capacity_water_J_per_kg_per_K (
976
+ self .NonverticalProducedTemperature .value [year ],
977
+ pressure = model .reserv .lithostatic_pressure ()
978
+ ) * 24.0 * 3600.0
965
979
self .time_operation .value += self .al
966
980
967
981
self .time_operation .value = t # set it back for use in later loop
@@ -972,7 +986,10 @@ def Calculate(self, model: Model) -> None:
972
986
# Calculate the temperature drop as the fluid makes it way to the surface (or use a constant value)
973
987
# if not Ramey, hard code a user-supplied temperature drop.
974
988
self .ProdTempDrop .value = self .tempdropprod .value
975
- model .reserv .cpwater .value = heatcapacitywater (self .NonverticalProducedTemperature .value [0 ])
989
+ model .reserv .cpwater .value = heat_capacity_water_J_per_kg_per_K (
990
+ self .NonverticalProducedTemperature .value [0 ],
991
+ pressure = model .reserv .lithostatic_pressure ()
992
+ )
976
993
if self .rameyoptionprod .value :
977
994
self .ProdTempDrop .value = RameyCalc (model .reserv .krock .value ,
978
995
model .reserv .rhorock .value ,
@@ -992,10 +1009,17 @@ def Calculate(self, model: Model) -> None:
992
1009
# Now use the parent's calculation to calculate the upgoing and downgoing pressure drops and pumping power
993
1010
self .PumpingPower .value = [0.0 ] * len (self .ProducedTemperature .value ) # initialize the array
994
1011
if self .productionwellpumping .value :
995
- self .rhowaterinj = densitywater (model .reserv .Tsurf .value ) * np .linspace (1 , 1 ,
996
- len (self .ProducedTemperature .value ))
997
- self .rhowaterprod = densitywater (model .reserv .Trock .value ) * np .linspace (1 , 1 ,
998
- len (self .ProducedTemperature .value ))
1012
+ self .rhowaterinj = density_water_kg_per_m3 (
1013
+ model .reserv .Tsurf .value ,
1014
+ pressure = model .reserv .lithostatic_pressure ()
1015
+ ) * np .linspace (1 , 1 ,
1016
+ len (self .ProducedTemperature .value ))
1017
+
1018
+ self .rhowaterprod = density_water_kg_per_m3 (
1019
+ model .reserv .Trock .value ,
1020
+ pressure = model .reserv .lithostatic_pressure ()
1021
+ ) * np .linspace (1 , 1 , len (self .ProducedTemperature .value ))
1022
+
999
1023
self .DPProdWell .value , f3 , vprod , self .rhowaterprod = WellPressureDrop (model ,
1000
1024
model .reserv .Tresoutput .value - self .ProdTempDrop .value / 4.0 ,
1001
1025
self .prodwellflowrate .value ,
@@ -1020,19 +1044,19 @@ def Calculate(self, model: Model) -> None:
1020
1044
else : # PI is used for both the verticals
1021
1045
UpgoingPumpingPower , self .PumpingPowerProd .value , self .DPProdWell .value , self .Pprodwellhead .value = \
1022
1046
ProdPressureDropAndPumpingPowerUsingIndexes (
1023
- model , self .usebuiltinhydrostaticpressurecorrelation , self . productionwellpumping .value ,
1047
+ model , self .productionwellpumping .value ,
1024
1048
self .usebuiltinppwellheadcorrelation ,
1025
- model .reserv .Trock .value , model .reserv .Tsurf . value , model . reserv . depth .value ,
1026
- model . reserv . averagegradient . value , self .ppwellhead .value , self .PI .value ,
1049
+ model .reserv .Trock .value , model .reserv .depth .value ,
1050
+ self .ppwellhead .value , self .PI .value ,
1027
1051
self .prodwellflowrate .value , f3 , vprod ,
1028
1052
self .prodwelldiam .value , self .nprod .value , model .surfaceplant .pump_efficiency .value ,
1029
1053
self .rhowaterprod )
1030
1054
1031
1055
DowngoingPumpingPower , ppp2 , dppw , ppwh = ProdPressureDropAndPumpingPowerUsingIndexes (
1032
- model , self .usebuiltinhydrostaticpressurecorrelation , self . productionwellpumping .value ,
1056
+ model , self .productionwellpumping .value ,
1033
1057
self .usebuiltinppwellheadcorrelation ,
1034
- model .reserv .Trock .value , model .reserv .Tsurf . value , model . reserv . depth .value ,
1035
- model . reserv . averagegradient . value , self .ppwellhead .value , self .PI .value ,
1058
+ model .reserv .Trock .value , model .reserv .depth .value ,
1059
+ self .ppwellhead .value , self .PI .value ,
1036
1060
self .prodwellflowrate .value , f3 , vprod ,
1037
1061
self .injwelldiam .value , self .nprod .value , model .surfaceplant .pump_efficiency .value ,
1038
1062
self .rhowaterinj )
@@ -1078,7 +1102,10 @@ def Calculate(self, model: Model) -> None:
1078
1102
self .ProducedTemperature .value = self .InterpolatedTemperatureArray .copy ()
1079
1103
1080
1104
tot_length , vert_length , horizontal_lengths = self .calculatedrillinglengths (model )
1081
- model .reserv .depth .value = model .reserv .InputDepth .value * 1000.0 # in this case, reserv.depth is just the vertical drill depth
1105
+
1106
+ # in this case, reserv.depth is just the vertical drill depth
1107
+ # FIXME earlier calculations use depth before this value is set, meaning they're using the wrong value
1108
+ model .reserv .depth .value = model .reserv .InputDepth .quantity ().to (model .reserv .depth .CurrentUnits ).magnitude
1082
1109
1083
1110
# getTandP results must be rejiggered to match wellbores expected output. Once done,
1084
1111
# the surfaceplant and economics models should just work
@@ -1089,12 +1116,16 @@ def Calculate(self, model: Model) -> None:
1089
1116
1090
1117
# calculate water values based on initial temperature
1091
1118
1092
- # FIXME TODO - get rid of fallback calculations https://github.com/NREL/GEOPHIRES-X/issues/110
1093
- rho_water = densitywater (self .Tout [0 ], enable_fallback_calculation = True )
1119
+ rho_water = density_water_kg_per_m3 (
1120
+ self .Tout [0 ],
1121
+ pressure = model .reserv .lithostatic_pressure (),
1122
+ )
1123
+
1094
1124
1095
- # FIXME TODO - get rid of fallback calculations https://github.com/NREL/GEOPHIRES-X/issues/110
1096
- model .reserv .cpwater .value = heatcapacitywater (
1097
- self .Tout [0 ], enable_fallback_calculation = True ) # Need this for surface plant output calculation
1125
+ model .reserv .cpwater .value = heat_capacity_water_J_per_kg_per_K (
1126
+ self .Tout [0 ],
1127
+ pressure = model .reserv .lithostatic_pressure (),
1128
+ ) # Need this for surface plant output calculation
1098
1129
1099
1130
# set pumping power to zero for all times, assuming that the thermosphere wil always
1100
1131
# make pumping of working fluid unnecessary
0 commit comments