11import sys
2+
3+ from mpmath import mp , exp , invertlaplace , sqrt , tanh , workdps
24import numpy as np
3- from mpmath import *
5+
46import geophires_x .Model as Model
7+ from .Parameter import intParameter
58from .Reservoir import Reservoir
9+ from .Units import Units
610
711
812class MPFReservoir (Reservoir ):
@@ -12,6 +16,7 @@ class MPFReservoir(Reservoir):
1216 It also has its own methods and attributes that are unique to this class.
1317 """
1418
19+ # noinspection PyUnresolvedReferences,PyProtectedMember
1520 def __init__ (self , model : Model ):
1621 """
1722 The __init__ function is called automatically when a class is instantiated.
@@ -31,15 +36,33 @@ def __init__(self, model: Model):
3136 :type model: :class:`~geophires_x.Model.Model`
3237 :return: None
3338 """
34- model .logger .info ("Init " + str (__class__ ) + ": " + sys ._getframe ().f_code .co_name )
39+ model .logger .info (f'Init { str (__class__ )} : { sys ._getframe ().f_code .co_name } ' )
40+
3541 super ().__init__ (model ) # initialize the parent parameters and variables
3642 sclass = str (__class__ ).replace ("<class \' " , "" )
3743 self .MyClass = sclass .replace ("\' >" , "" )
38- model .logger .info ("Complete " + str (__class__ ) + ": " + sys ._getframe ().f_code .co_name )
44+
45+ max_allowed_precision = 15
46+ self .gringarten_stehfest_precision = self .ParameterDict [self .gringarten_stehfest_precision .Name ] = intParameter (
47+ 'Gringarten-Stehfest Precision' ,
48+ DefaultValue = 15 ,
49+ AllowableRange = list (range (8 , max_allowed_precision + 1 )),
50+ UnitType = Units .NONE ,
51+ Required = False ,
52+ ToolTipText = 'Sets the numerical precision (decimal places) for the inverse Laplace transform '
53+ '(Stehfest algorithm) used in the Gringarten calculation for the Multiple Parallel Fractures '
54+ 'Reservoir Model. '
55+ 'The default value provides maximum result stability; '
56+ 'lower values calculate faster but may reduce consistency.'
57+ )
58+
59+
60+ model .logger .info (f'Complete { str (__class__ )} : { sys ._getframe ().f_code .co_name } ' )
3961
4062 def __str__ (self ):
4163 return "MPFReservoir"
4264
65+ # noinspection PyUnresolvedReferences,PyProtectedMember
4366 def read_parameters (self , model : Model ) -> None :
4467 """
4568 The read_parameters function reads in the parameters from a dictionary created by reading the user-provided file
@@ -51,15 +74,16 @@ def read_parameters(self, model: Model) -> None:
5174 :type model: :class:`~geophires_x.Model.Model`
5275 :return: None
5376 """
54- model .logger .info (" Init " + str (__class__ ) + ": " + sys ._getframe ().f_code .co_name )
77+ model .logger .info (f' Init { str (__class__ )} : { sys ._getframe ().f_code .co_name } ' )
5578 # if we call super, we don't need to deal with setting the parameters here,
5679 # just deal with the special cases for the variables in this class
5780 # because the call to the super.readparameters will set all the variables,
5881 # including the ones that are specific to this class
5982 super ().read_parameters (model ) # read the parameters for the parent.
6083
61- model .logger .info (" Complete " + str (__class__ ) + ": " + sys ._getframe ().f_code .co_name )
84+ model .logger .info (f' Complete { str (__class__ )} : { sys ._getframe ().f_code .co_name } ' )
6285
86+ # noinspection SpellCheckingInspection,PyUnresolvedReferences,PyProtectedMember
6387 def Calculate (self , model : Model ):
6488 """
6589 The Calculate function calculates the values of all the parameters that are calculated by this object.
@@ -87,13 +111,31 @@ def Calculate(self, model: Model):
87111 # calculate non-dimensional temperature array
88112 Twnd = []
89113 try :
90- for t in range (1 , len (model .reserv .timevector .value )):
91- Twnd = Twnd + [float (invertlaplace (fp , td [t ], method = 'stehfest' ))]
92- except :
93- msg = ('Error: GEOPHIRES could not execute numerical inverse laplace calculation for reservoir model 1. '
94- 'Simulation will abort.' )
114+ # Determine the required precision for this calculation.
115+ precision = (
116+ self .gringarten_stehfest_precision .value
117+ if self .gringarten_stehfest_precision .Provided
118+ else mp .dps
119+ )
120+
121+ # Use the workdps context manager for a robust, thread-safe solution.
122+ # It temporarily sets mp.dps for this block and restores it automatically.
123+ with workdps (precision ):
124+ twnd_list = [
125+ float (invertlaplace (fp , td [t ], method = 'stehfest' ))
126+ for t in range (1 , len (model .reserv .timevector .value ))
127+ ]
128+
129+ Twnd = np .asarray (twnd_list )
130+
131+ except Exception as e_ :
132+ msg = (
133+ f'Error: GEOPHIRES could not execute numerical inverse laplace calculation for reservoir model 1 '
134+ f'({ self .gringarten_stehfest_precision .Name } = { precision } ). '
135+ 'Simulation will abort.'
136+ )
95137 print (msg )
96- raise RuntimeError (msg )
138+ raise RuntimeError (msg ) from e_
97139
98140 Twnd = np .asarray (Twnd )
99141
@@ -102,3 +144,4 @@ def Calculate(self, model: Model):
102144 model .reserv .Tresoutput .value = np .append ([model .reserv .Trock .value ], model .reserv .Tresoutput .value )
103145
104146 model .logger .info (f'Complete { str (__class__ )} : { sys ._getframe ().f_code .co_name } ' )
147+
0 commit comments