diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 79cd1b05..bc590b30 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 3.4.25 +current_version = 3.4.26 commit = True tag = True diff --git a/.cookiecutterrc b/.cookiecutterrc index e5226635..59f948d5 100644 --- a/.cookiecutterrc +++ b/.cookiecutterrc @@ -54,7 +54,7 @@ default_context: sphinx_doctest: "no" sphinx_theme: "sphinx-py3doc-enhanced-theme" test_matrix_separate_coverage: "no" - version: 3.4.25 + version: 3.4.26 version_manager: "bump2version" website: "https://github.com/NREL" year_from: "2023" diff --git a/README.rst b/README.rst index 6774938f..d634f5ab 100644 --- a/README.rst +++ b/README.rst @@ -47,9 +47,9 @@ Free software: `MIT license `__ :alt: Supported implementations :target: https://pypi.org/project/geophires-x -.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.4.25.svg +.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.4.26.svg :alt: Commits since latest release - :target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.4.25...main + :target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.4.26...main .. |docs| image:: https://readthedocs.org/projects/GEOPHIRES-X/badge/?style=flat :target: https://nrel.github.io/GEOPHIRES-X diff --git a/docs/conf.py b/docs/conf.py index df3aab7e..16a4589d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -18,7 +18,7 @@ year = '2023' author = 'NREL' copyright = f'{year}, {author}' -version = release = '3.4.25' +version = release = '3.4.26' pygments_style = 'trac' templates_path = ['./templates'] diff --git a/setup.py b/setup.py index f11d5196..e11ee213 100755 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ def read(*names, **kwargs): setup( name='geophires-x', - version='3.4.25', + version='3.4.26', license='MIT', description='GEOPHIRES is a free and open-source geothermal techno-economic simulator.', long_description='{}\n{}'.format( diff --git a/src/geophires_monte_carlo/MC_GeoPHIRES3.py b/src/geophires_monte_carlo/MC_GeoPHIRES3.py index 87bdaf06..9a094247 100755 --- a/src/geophires_monte_carlo/MC_GeoPHIRES3.py +++ b/src/geophires_monte_carlo/MC_GeoPHIRES3.py @@ -358,6 +358,7 @@ def main(command_line_args=None): if 'MC_OUTPUT_FILE' in args and args.MC_OUTPUT_FILE is not None else str(Path(Path(args.Input_file).parent, 'MC_Result.txt').absolute()) ) + code_file_name = Path(args.Code_File).name python_path = 'python' html_path = '' @@ -450,6 +451,14 @@ def main(command_line_args=None): results_pd = pd.read_csv(output_file) df = pd.DataFrame(results_pd) + if len(results) < 1: + # TODO surface actual exceptions instead of giving this generic message + raise RuntimeError( + 'No MC results generated, ' + f'this is likely caused by {code_file_name} throwing an exception ' + f'when run with your input file.' + ) + # Compute the stats along the specified axes. mins = np.nanmin(results, 0) maxs = np.nanmax(results, 0) diff --git a/src/geophires_x/AGSWellBores.py b/src/geophires_x/AGSWellBores.py index e91edf77..e4375938 100644 --- a/src/geophires_x/AGSWellBores.py +++ b/src/geophires_x/AGSWellBores.py @@ -871,12 +871,12 @@ def CalculateNonverticalPressureDrop(self, model:Model, time_operation: float, t # nonvertical wellbore fluid conditions based on current temperature rhowater = density_water_kg_per_m3( self.NonverticalProducedTemperature.value[year], - pressure=model.reserv.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.InputDepth.quantity().to('m').magnitude) + pressure=model.reserv.lithostatic_pressure() ) muwater = viscosity_water_Pa_sec( self.NonverticalProducedTemperature.value[year], - pressure=model.reserv.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.InputDepth.quantity().to('m').magnitude) + pressure=model.reserv.lithostatic_pressure() ) vhoriz = self.q_circulation / rhowater / (math.pi / 4. * self.nonverticalwellborediameter.value ** 2) @@ -957,15 +957,15 @@ def Calculate(self, model: Model) -> None: # MIR figure out how to calculate year and extract Tini from reserv Tresoutput array year = math.trunc(self.time_operation.value / self.al) self.NonverticalProducedTemperature.value[year] = inverselaplace( - self, 16, 0, model.reserv.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.InputDepth.quantity().to('m').magnitude)) + self, 16, 0, model.reserv.lithostatic_pressure()) # update alpha_fluid value based on next temperature of reservoir self.alpha_fluid = self.WaterThermalConductivity.value / density_water_kg_per_m3( self.NonverticalProducedTemperature.value[year], - pressure=model.reserv.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.InputDepth.quantity().to('m').magnitude) + pressure=model.reserv.lithostatic_pressure() ) / heat_capacity_water_J_per_kg_per_K( self.NonverticalProducedTemperature.value[year], - pressure=model.reserv.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.InputDepth.quantity().to('m').magnitude) + pressure=model.reserv.lithostatic_pressure() ) * 24.0 * 3600.0 self.time_operation.value += self.al @@ -979,7 +979,7 @@ def Calculate(self, model: Model) -> None: self.ProdTempDrop.value = self.tempdropprod.value model.reserv.cpwater.value = heat_capacity_water_J_per_kg_per_K( self.NonverticalProducedTemperature.value[0], - pressure=model.reserv.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.InputDepth.quantity().to('m').magnitude) + pressure=model.reserv.lithostatic_pressure() ) if self.rameyoptionprod.value: self.ProdTempDrop.value = RameyCalc(model.reserv.krock.value, @@ -1002,13 +1002,13 @@ def Calculate(self, model: Model) -> None: if self.productionwellpumping.value: self.rhowaterinj = density_water_kg_per_m3( model.reserv.Tsurf.value, - pressure=model.reserv.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.InputDepth.quantity().to('m').magnitude) + pressure=model.reserv.lithostatic_pressure() ) * np.linspace(1, 1, len(self.ProducedTemperature.value)) self.rhowaterprod = density_water_kg_per_m3( model.reserv.Trock.value, - pressure=model.reserv.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.InputDepth.quantity().to('m').magnitude) + pressure=model.reserv.lithostatic_pressure() ) * np.linspace(1, 1, len(self.ProducedTemperature.value)) self.DPProdWell.value, f3, vprod, self.rhowaterprod = WellPressureDrop(model, @@ -1113,13 +1113,13 @@ def Calculate(self, model: Model) -> None: rho_water = density_water_kg_per_m3( self.Tout[0], - pressure = model.reserv.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.InputDepth.quantity().to('m').magnitude), + pressure = model.reserv.lithostatic_pressure(), ) model.reserv.cpwater.value = heat_capacity_water_J_per_kg_per_K( self.Tout[0], - pressure=model.reserv.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.InputDepth.quantity().to('m').magnitude), + pressure=model.reserv.lithostatic_pressure(), ) # Need this for surface plant output calculation # set pumping power to zero for all times, assuming that the thermosphere wil always diff --git a/src/geophires_x/CylindricalReservoir.py b/src/geophires_x/CylindricalReservoir.py index 12114301..925896be 100644 --- a/src/geophires_x/CylindricalReservoir.py +++ b/src/geophires_x/CylindricalReservoir.py @@ -98,7 +98,7 @@ def __init__(self, model: Model): UnitType=Units.PERCENT, PreferredUnits=PercentUnit.TENTH, CurrentUnits=PercentUnit.TENTH, - ErrMessage="assume default cyclindrical reservoir radius of effect reduction factor (0.1)", + ErrMessage="assume default cylindrical reservoir radius of effect reduction factor (0.1)", ToolTipText="The radius of effect reduction factor - to account for the fact that we cannot extract 100%" + " of the heat in the cylinder.", ) @@ -244,20 +244,17 @@ def Calculate(self, model: Model) -> None: ) / 1e15 # 10^15 J self.cpwater.value = heat_capacity_water_J_per_kg_per_K( model.wellbores.Tinj.value * 0.5 + (self.Trock.value * 0.9 + model.wellbores.Tinj.value * 0.1) * 0.5, - pressure=self.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.depth.quantity().to('m').magnitude) + pressure=self.lithostatic_pressure() ) self.rhowater.value = density_water_kg_per_m3( model.wellbores.Tinj.value * 0.5 + (self.Trock.value * 0.9 + model.wellbores.Tinj.value * 0.1) * 0.5, - pressure=self.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.depth.quantity().to('m').magnitude) + pressure=self.lithostatic_pressure() ) model.logger.info(f'complete {str(__class__)}: {sys._getframe().f_code.co_name}') - #def lithostatic_pressure(self) -> PlainQuantity: - """ - @override + def lithostatic_pressure(self) -> PlainQuantity: + """@override""" - Standard reservoir implementation uses depth but CylindricalReservoir sets depth to total drilled length - """ - def lithostatic_pressure(self, rho_rock_kg_per_m3: float, depth_m: float) -> PlainQuantity: - return quantity(static_pressure_MPa(rho_rock_kg_per_m3, depth_m), 'MPa') + return quantity(static_pressure_MPa(self.rhorock.quantity().to('kg/m**3').magnitude, + self.InputDepth.quantity().to('m').magnitude), 'MPa') diff --git a/src/geophires_x/Reservoir.py b/src/geophires_x/Reservoir.py index 5fc5d118..049c15ac 100644 --- a/src/geophires_x/Reservoir.py +++ b/src/geophires_x/Reservoir.py @@ -749,14 +749,12 @@ def Calculate(self, model: Model) -> None: # calculate reservoir water properties self.cpwater.value = heat_capacity_water_J_per_kg_per_K( model.wellbores.Tinj.value * 0.5 + (self.Trock.value * 0.9 + model.wellbores.Tinj.value * 0.1) * 0.5, - pressure=self.lithostatic_pressure(self.rhorock.quantity().to('kg/m**3').magnitude, - self.depth.quantity().to('m').magnitude) + pressure=self.lithostatic_pressure() ) self.rhowater.value = density_water_kg_per_m3( model.wellbores.Tinj.value * 0.5 + (self.Trock.value * 0.9 + model.wellbores.Tinj.value * 0.1) * 0.5, - pressure=self.lithostatic_pressure(self.rhorock.quantity().to('kg/m**3').magnitude, - self.depth.quantity().to('m').magnitude) + pressure=self.lithostatic_pressure() ) # temperature gain in injection wells @@ -768,7 +766,8 @@ def Calculate(self, model: Model) -> None: model.logger.info(f'complete {str(__class__)}: {sys._getframe().f_code.co_name}') - def lithostatic_pressure(self, rho_rock_kg_per_m3: float, depth_m: float) -> PlainQuantity: - return quantity(static_pressure_MPa(rho_rock_kg_per_m3, depth_m), 'MPa') + def lithostatic_pressure(self) -> PlainQuantity: + return quantity(static_pressure_MPa(self.rhorock.quantity().to('kg/m**3').magnitude, + self.depth.quantity().to('m').magnitude), 'MPa') diff --git a/src/geophires_x/WellBores.py b/src/geophires_x/WellBores.py index 347477e4..d226813e 100644 --- a/src/geophires_x/WellBores.py +++ b/src/geophires_x/WellBores.py @@ -164,7 +164,7 @@ def WellPressureDrop(model: Model, Taverage: float, wellflowrate: float, welldia rhowater = np.array([ density_water_kg_per_m3( t, - pressure=model.reserv.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.depth.quantity().to('m').magnitude), + pressure=model.reserv.lithostatic_pressure(), ) for t in Taverage ]) # replace with correlation based on Tprodaverage @@ -172,7 +172,7 @@ def WellPressureDrop(model: Model, Taverage: float, wellflowrate: float, welldia muwater = np.array([ viscosity_water_Pa_sec( t, - pressure=model.reserv.lithostatic_pressure(model.reserv.rhorock.value, model.reserv.depth.quantity().to('m').magnitude), + pressure=model.reserv.lithostatic_pressure(), ) for t in Taverage ]) # replace with correlation based on Tprodaverage @@ -228,13 +228,11 @@ def InjectionWellPressureDrop(model: Model, Taverage: float, wellflowrate: float """ # start by calculating wellbore fluid conditions [kPa], noting that most temperature drop happens in # upper section (because surrounding rock temperature is lowest in upper section) - rhowater = (density_water_kg_per_m3(Taverage, pressure=model.reserv.lithostatic_pressure(model.reserv.rhorock.value, - model.reserv.depth.quantity().to('m').magnitude)) + rhowater = (density_water_kg_per_m3(Taverage, pressure=model.reserv.lithostatic_pressure()) * np.linspace(1, 1, len(model.wellbores.ProducedTemperature.value))) # replace with correlation based on Tinjaverage - muwater = viscosity_water_Pa_sec(Taverage, pressure=model.reserv.lithostatic_pressure(model.reserv.rhorock.value, - model.reserv.depth.quantity().to('m').magnitude)) * np.linspace(1, 1, len(model.wellbores.ProducedTemperature.value)) + muwater = viscosity_water_Pa_sec(Taverage, pressure=model.reserv.lithostatic_pressure()) * np.linspace(1, 1, len(model.wellbores.ProducedTemperature.value)) v = nprod / ninj * wellflowrate * (1.0 + waterloss) / rhowater / (math.pi / 4. * welldiam ** 2) Rewater = 4. * nprod / ninj * wellflowrate * (1.0 + waterloss) / ( muwater * math.pi * welldiam) # laminar or turbulent flow? @@ -1087,8 +1085,7 @@ def Calculate(self, model: Model) -> None: self.production_reservoir_pressure.value = get_hydrostatic_pressure_kPa(model.reserv.Trock.value, model.reserv.Tsurf.value, model.reserv.depth.quantity().to('m').magnitude, model.reserv.averagegradient.value, - model.reserv.lithostatic_pressure(model.reserv.rhorock.value, - model.reserv.depth.quantity().to('m').magnitude)) if self.usebuiltinhydrostaticpressurecorrelation else self.Phydrostatic.quantity().to( + model.reserv.lithostatic_pressure()) if self.usebuiltinhydrostaticpressurecorrelation else self.Phydrostatic.quantity().to( self.production_reservoir_pressure.CurrentUnits).magnitude self.production_reservoir_pressure.value = ReservoirPressurePredictor(model.surfaceplant.plant_lifetime.value, @@ -1114,19 +1111,20 @@ def Calculate(self, model: Model) -> None: if not self.injection_reservoir_temperature.Provided: self.injection_reservoir_temperature.value = (model.reserv.averagegradient.value * self.injection_reservoir_depth.value) + model.reserv.Tsurf.value + injection_reservoir_static_pressure = quantity(static_pressure_MPa( + model.reserv.rhorock.value, self.injection_reservoir_depth.quantity().to('m').magnitude), 'MPa') + if self.injection_reservoir_pressure.value < 0: # they didn't provide a pressure so assume hydrostatic. self.injection_reservoir_pressure.value = get_hydrostatic_pressure_kPa(self.injection_reservoir_temperature.value, model.reserv.Tsurf.value, self.injection_reservoir_depth.value, model.reserv.averagegradient.value * 1000.0, - model.reserv.lithostatic_pressure(model.reserv.rhorock.value, - self.injection_reservoir_depth.quantity().to('m').magnitude)) + injection_reservoir_static_pressure) self.injection_reservoir_initial_pressure.value = self.injection_reservoir_pressure.value = get_hydrostatic_pressure_kPa(self.injection_reservoir_temperature.value, model.reserv.Tsurf.value, self.injection_reservoir_depth.value, model.reserv.averagegradient.value, - model.reserv.lithostatic_pressure(model.reserv.rhorock.value, - self.injection_reservoir_depth.quantity().to('m').magnitude)) + injection_reservoir_static_pressure) # if not self.injection_reservoir_initial_pressure.Provided: self.injection_reservoir_pressure.value = InjectionReservoirPressurePredictor(model.surfaceplant.plant_lifetime.value, diff --git a/src/geophires_x/__init__.py b/src/geophires_x/__init__.py index 24551c72..2ff709b9 100644 --- a/src/geophires_x/__init__.py +++ b/src/geophires_x/__init__.py @@ -1 +1 @@ -__version__ = '3.4.25' +__version__ = '3.4.26' diff --git a/tests/examples/Wanju_Yuan_Closed-Loop_Geothermal_Energy_Recovery.out b/tests/examples/Wanju_Yuan_Closed-Loop_Geothermal_Energy_Recovery.out index 451d2870..bb977ba1 100644 --- a/tests/examples/Wanju_Yuan_Closed-Loop_Geothermal_Energy_Recovery.out +++ b/tests/examples/Wanju_Yuan_Closed-Loop_Geothermal_Energy_Recovery.out @@ -6,15 +6,15 @@ Simulation Metadata ---------------------- GEOPHIRES Version: 3.4.25 GEOPHIRES Build Date: 2024-03-05 - Simulation Date: 2024-04-23 - Simulation Time: 11:13 - Calculation Time: 2.927 sec + Simulation Date: 2024-04-30 + Simulation Time: 08:43 + Calculation Time: 1.706 sec ***SUMMARY OF RESULTS*** End-Use Option: Electricity - Average Net Electricity Production: 1.11 MW - Electricity breakeven price: 119.74 cents/kWh + Average Net Electricity Production: 1.10 MW + Electricity breakeven price: 120.05 cents/kWh Number of production wells: 1 Number of injection wells: 0 Flowrate per production well: 110.0 kg/sec @@ -28,7 +28,7 @@ Simulation Metadata Accrued financing during construction: 0.00 Project lifetime: 40 yr Capacity factor: 90.0 % - Project NPV: -134.71 MUSD + Project NPV: -134.74 MUSD Project IRR: 0.00 % Project VIR=PI=PIR: -0.06 Project MOIC: -0.89 @@ -78,10 +78,10 @@ The AGS models contain an intrinsic reservoir model that doesn't expose values t Drilling and completion costs per well: 68.08 MUSD Stimulation costs: 0.00 MUSD Surface power plant costs: 6.74 MUSD - Field gathering system costs: 0.49 MUSD - Total surface equipment costs: 7.23 MUSD + Field gathering system costs: 0.51 MUSD + Total surface equipment costs: 7.24 MUSD Exploration costs: 51.40 MUSD - Total capital costs: 126.70 MUSD + Total capital costs: 126.72 MUSD ***OPERATING AND MAINTENANCE COSTS (M$/yr)*** @@ -99,13 +99,13 @@ The AGS models contain an intrinsic reservoir model that doesn't expose values t Average Total Electricity Generation: 1.11 MW Minimum Total Electricity Generation: 0.94 MW Initial Total Electricity Generation: 1.66 MW - Maximum Net Electricity Generation: 1.67 MW - Average Net Electricity Generation: 1.11 MW + Maximum Net Electricity Generation: 1.66 MW + Average Net Electricity Generation: 1.10 MW Minimum Net Electricity Generation: 0.94 MW Initial Net Electricity Generation: 1.66 MW Average Annual Total Electricity Generation: 8.64 GWh - Average Annual Net Electricity Generation: 8.64 GWh - Initial pumping power/net installed power: 0.04 % + Average Annual Net Electricity Generation: 8.62 GWh + Initial pumping power/net installed power: 0.21 % Average Pumping Power: 0.00 MW ************************************************************ @@ -114,46 +114,46 @@ The AGS models contain an intrinsic reservoir model that doesn't expose values t YEAR THERMAL GEOFLUID PUMP NET FIRST LAW DRAWDOWN TEMPERATURE POWER POWER EFFICIENCY (degC) (MW) (MW) (%) - 1 1.0000 120.00 0.0007 1.6639 6.2352 - 2 0.9302 111.62 0.0007 1.2924 5.6297 - 3 0.9187 110.24 0.0007 1.2369 5.5357 - 4 0.9121 109.45 0.0007 1.2056 5.4824 - 5 0.9074 108.89 0.0007 1.1840 5.4453 - 6 0.9039 108.46 0.0007 1.1676 5.4171 - 7 0.9010 108.12 0.0007 1.1544 5.3943 - 8 0.8985 107.83 0.0007 1.1434 5.3753 - 9 0.8965 107.58 0.0007 1.1339 5.3590 - 10 0.8946 107.36 0.0007 1.1257 5.3448 - 11 0.8930 107.16 0.0007 1.1184 5.3321 - 12 0.8915 106.98 0.0007 1.1119 5.3208 - 13 0.8902 106.82 0.0007 1.1059 5.3105 - 14 0.8890 106.68 0.0007 1.1005 5.3011 - 15 0.8879 106.54 0.0007 1.0955 5.2925 - 16 0.8868 106.42 0.0007 1.0909 5.2844 - 17 0.8858 106.30 0.0007 1.0867 5.2770 - 18 0.8849 106.19 0.0007 1.0827 5.2700 - 19 0.8841 106.09 0.0007 1.0789 5.2635 - 20 0.8833 105.99 0.0007 1.0754 5.2573 - 21 0.8825 105.90 0.0007 1.0721 5.2515 - 22 0.8818 105.81 0.0007 1.0689 5.2460 - 23 0.8811 105.73 0.0007 1.0659 5.2408 - 24 0.8804 105.65 0.0007 1.0631 5.2358 - 25 0.8798 105.58 0.0007 1.0603 5.2310 - 26 0.8792 105.50 0.0007 1.0577 5.2265 - 27 0.8786 105.43 0.0007 1.0552 5.2221 - 28 0.8781 105.37 0.0007 1.0529 5.2180 - 29 0.8775 105.30 0.0007 1.0506 5.2140 - 30 0.8770 105.24 0.0007 1.0484 5.2101 - 31 0.8765 105.18 0.0007 1.0462 5.2064 - 32 0.8761 105.13 0.0007 1.0442 5.2028 - 33 0.8756 105.07 0.0007 1.0422 5.1993 - 34 0.8751 105.02 0.0007 1.0403 5.1960 - 35 0.8747 104.97 0.0007 1.0385 5.1928 - 36 0.8743 104.91 0.0007 1.0367 5.1896 - 37 0.8739 104.87 0.0007 1.0349 5.1866 - 38 0.8735 104.82 0.0007 1.0333 5.1836 - 39 0.8731 104.77 0.0007 1.0316 5.1808 - 40 0.8727 104.73 0.0007 1.0300 5.1780 + 1 1.0000 120.00 0.0034 1.6611 6.2250 + 2 0.9302 111.62 0.0035 1.2897 5.6178 + 3 0.9187 110.24 0.0035 1.2342 5.5235 + 4 0.9121 109.45 0.0035 1.2029 5.4699 + 5 0.9074 108.89 0.0035 1.1813 5.4328 + 6 0.9039 108.46 0.0035 1.1649 5.4044 + 7 0.9010 108.12 0.0035 1.1516 5.3816 + 8 0.8985 107.83 0.0035 1.1406 5.3625 + 9 0.8965 107.58 0.0035 1.1312 5.3461 + 10 0.8946 107.36 0.0035 1.1230 5.3318 + 11 0.8930 107.16 0.0035 1.1157 5.3191 + 12 0.8915 106.98 0.0035 1.1091 5.3077 + 13 0.8902 106.82 0.0035 1.1032 5.2974 + 14 0.8890 106.68 0.0035 1.0978 5.2879 + 15 0.8879 106.54 0.0035 1.0928 5.2793 + 16 0.8868 106.42 0.0035 1.0882 5.2712 + 17 0.8858 106.30 0.0035 1.0839 5.2637 + 18 0.8849 106.19 0.0035 1.0799 5.2567 + 19 0.8841 106.09 0.0035 1.0762 5.2502 + 20 0.8833 105.99 0.0035 1.0727 5.2440 + 21 0.8825 105.90 0.0035 1.0693 5.2381 + 22 0.8818 105.81 0.0035 1.0662 5.2326 + 23 0.8811 105.73 0.0035 1.0632 5.2273 + 24 0.8804 105.65 0.0035 1.0603 5.2223 + 25 0.8798 105.58 0.0035 1.0576 5.2176 + 26 0.8792 105.50 0.0035 1.0550 5.2130 + 27 0.8786 105.43 0.0035 1.0525 5.2086 + 28 0.8781 105.37 0.0035 1.0501 5.2044 + 29 0.8775 105.30 0.0035 1.0478 5.2004 + 30 0.8770 105.24 0.0035 1.0456 5.1965 + 31 0.8765 105.18 0.0035 1.0435 5.1928 + 32 0.8761 105.13 0.0035 1.0415 5.1892 + 33 0.8756 105.07 0.0035 1.0395 5.1857 + 34 0.8751 105.02 0.0035 1.0376 5.1823 + 35 0.8747 104.97 0.0035 1.0357 5.1791 + 36 0.8743 104.91 0.0035 1.0339 5.1759 + 37 0.8739 104.87 0.0035 1.0322 5.1729 + 38 0.8735 104.82 0.0035 1.0305 5.1699 + 39 0.8731 104.77 0.0035 1.0289 5.1670 + 40 0.8727 104.73 0.0035 1.0273 5.1642 ******************************************************************* @@ -164,30 +164,30 @@ The AGS models contain an intrinsic reservoir model that doesn't expose values t (GWh/year) (GWh/year) (10^15 J) (%) 1 12.1 200.5 32.78 2.15 2 9.5 173.8 32.16 4.02 - 3 9.9 177.5 31.52 5.93 + 3 9.8 177.5 31.52 5.93 4 9.2 170.3 30.91 7.76 5 9.4 172.2 30.29 9.61 6 9.0 168.1 29.68 11.42 7 9.1 169.2 29.07 13.23 8 8.9 166.4 28.47 15.02 - 9 9.0 167.2 27.87 16.82 + 9 8.9 167.2 27.87 16.82 10 8.8 165.1 27.28 18.59 11 8.8 165.6 26.68 20.37 12 8.7 164.0 26.09 22.13 13 8.7 164.3 25.50 23.90 14 8.6 163.1 24.91 25.65 15 8.6 163.2 24.32 27.40 - 16 8.6 162.3 23.74 29.15 - 17 8.6 162.3 23.16 30.89 + 16 8.5 162.3 23.74 29.15 + 17 8.5 162.3 23.16 30.89 18 8.5 161.7 22.57 32.63 19 8.5 161.5 21.99 34.36 - 20 8.5 161.1 21.41 36.10 + 20 8.4 161.1 21.41 36.10 21 8.4 160.8 20.83 37.82 22 8.4 160.6 20.26 39.55 23 8.4 160.1 19.68 41.27 24 8.4 160.1 19.10 42.99 25 8.3 159.4 18.53 44.70 - 26 8.4 159.7 17.95 46.42 + 26 8.3 159.7 17.95 46.42 27 8.3 158.8 17.38 48.12 28 8.3 159.4 16.81 49.84 29 8.2 158.3 16.24 51.54 @@ -201,7 +201,7 @@ The AGS models contain an intrinsic reservoir model that doesn't expose values t 37 8.0 155.0 11.70 65.10 38 8.4 160.3 11.12 66.82 39 7.7 151.2 10.57 68.44 - 40 7.6 134.4 10.09 69.89 + 40 7.5 134.4 10.09 69.89 ******************************** @@ -211,43 +211,43 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 0.00 -126.70 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -126.70 -126.70 - 2 5.50 -0.38 0.67 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.38 -127.08 - 3 5.50 -0.52 1.19 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.52 -127.61 - 4 5.50 -0.50 1.73 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.50 -128.11 - 5 5.50 -0.54 2.24 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.54 -128.65 - 6 5.50 -0.53 2.76 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.53 -129.18 - 7 5.50 -0.55 3.26 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.55 -129.72 - 8 5.50 -0.54 3.76 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.54 -130.27 - 9 5.50 -0.56 4.25 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.56 -130.82 - 10 5.50 -0.55 4.74 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.55 -131.38 - 11 5.50 -0.56 5.23 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.56 -131.94 - 12 5.50 -0.56 5.71 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.56 -132.50 - 13 5.50 -0.57 6.19 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.57 -133.07 - 14 5.50 -0.57 6.67 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.57 -133.63 - 15 5.50 -0.57 7.15 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.57 -134.21 - 16 5.50 -0.57 7.62 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.57 -134.78 - 17 5.50 -0.58 8.09 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -135.35 - 18 5.50 -0.58 8.56 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -135.93 - 19 5.50 -0.58 9.03 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -136.51 - 20 5.50 -0.58 9.50 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -137.09 - 21 5.50 -0.58 9.96 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -137.67 - 22 5.50 -0.58 10.43 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -138.25 - 23 5.50 -0.58 10.89 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -138.83 - 24 5.50 -0.59 11.35 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -139.42 - 25 5.50 -0.59 11.81 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -140.00 - 26 5.50 -0.59 12.27 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -140.59 - 27 5.50 -0.59 12.73 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -141.18 - 28 5.50 -0.59 13.19 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -141.77 - 29 5.50 -0.59 13.64 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -142.36 - 30 5.50 -0.59 14.10 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -142.95 - 31 5.50 -0.59 14.55 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -143.54 - 32 5.50 -0.60 15.00 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.60 -144.14 - 33 5.50 -0.59 15.46 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -144.73 - 34 5.50 -0.60 15.91 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.60 -145.33 - 35 5.50 -0.59 16.36 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -145.92 - 36 5.50 -0.60 16.81 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.60 -146.52 - 37 5.50 -0.59 17.26 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -147.11 - 38 5.50 -0.61 17.70 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.61 -147.72 - 39 5.50 -0.58 18.17 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -148.30 - 40 5.50 -0.62 18.59 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.62 -148.92 + 1 0.00 -126.72 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -126.72 -126.72 + 2 5.50 -0.38 0.66 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.38 -127.10 + 3 5.50 -0.52 1.19 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.52 -127.62 + 4 5.50 -0.50 1.73 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.50 -128.13 + 5 5.50 -0.54 2.24 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.54 -128.67 + 6 5.50 -0.53 2.75 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.53 -129.20 + 7 5.50 -0.55 3.25 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.55 -129.75 + 8 5.50 -0.54 3.75 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.54 -130.29 + 9 5.50 -0.56 4.24 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.56 -130.85 + 10 5.50 -0.55 4.73 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.55 -131.41 + 11 5.50 -0.56 5.21 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.56 -131.97 + 12 5.50 -0.56 5.70 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.56 -132.53 + 13 5.50 -0.57 6.18 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.57 -133.10 + 14 5.50 -0.57 6.66 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.57 -133.67 + 15 5.50 -0.57 7.13 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.57 -134.24 + 16 5.50 -0.57 7.60 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.57 -134.81 + 17 5.50 -0.58 8.07 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -135.39 + 18 5.50 -0.58 8.54 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -135.97 + 19 5.50 -0.58 9.01 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -136.55 + 20 5.50 -0.58 9.48 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -137.13 + 21 5.50 -0.58 9.94 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -137.71 + 22 5.50 -0.58 10.40 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -138.29 + 23 5.50 -0.58 10.87 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.58 -138.88 + 24 5.50 -0.59 11.33 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -139.46 + 25 5.50 -0.59 11.79 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -140.05 + 26 5.50 -0.59 12.24 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -140.64 + 27 5.50 -0.59 12.70 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -141.23 + 28 5.50 -0.59 13.16 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -141.82 + 29 5.50 -0.59 13.61 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -142.41 + 30 5.50 -0.59 14.06 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -143.00 + 31 5.50 -0.59 14.52 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -143.60 + 32 5.50 -0.60 14.97 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.60 -144.19 + 33 5.50 -0.59 15.42 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -144.78 + 34 5.50 -0.60 15.87 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.60 -145.38 + 35 5.50 -0.59 16.32 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -145.98 + 36 5.50 -0.60 16.77 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.60 -146.58 + 37 5.50 -0.59 17.22 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -147.17 + 38 5.50 -0.61 17.66 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.61 -147.78 + 39 5.50 -0.59 18.12 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.59 -148.37 + 40 5.50 -0.63 18.54 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.63 -148.99 diff --git a/tests/geophires_monte_carlo_tests/MC_GEOPHIRES_Settings_file-3.txt b/tests/geophires_monte_carlo_tests/MC_GEOPHIRES_Settings_file-3.txt new file mode 100644 index 00000000..e4ce8300 --- /dev/null +++ b/tests/geophires_monte_carlo_tests/MC_GEOPHIRES_Settings_file-3.txt @@ -0,0 +1,4 @@ +INPUT, Gradient 1, triangular, 36, 41, 44 +OUTPUT, Average Net Electricity Production +OUTPUT, Electricity breakeven price +ITERATIONS, 3 diff --git a/tests/geophires_monte_carlo_tests/test_geophires_monte_carlo.py b/tests/geophires_monte_carlo_tests/test_geophires_monte_carlo.py index f7a2fefd..c7332e86 100644 --- a/tests/geophires_monte_carlo_tests/test_geophires_monte_carlo.py +++ b/tests/geophires_monte_carlo_tests/test_geophires_monte_carlo.py @@ -1,5 +1,6 @@ import json import os +import re import unittest from pathlib import Path @@ -107,6 +108,33 @@ def test_monte_carlo_result_ordering(self): self.assertDictEqual(result_json_obj, result.result['output']) + @unittest.skip('FIXME TODO https://github.com/NREL/GEOPHIRES-X/issues/192') + def test_geophires_monte_carlo_single_input(self): + client = GeophiresMonteCarloClient() + num_iterations = 3 + + input_file_path: Path = self._get_arg_file_path('GEOPHIRES-example1.txt') + mc_settings_file_path: Path = self._get_arg_file_path('MC_GEOPHIRES_Settings_file-3.txt') + result: MonteCarloResult = client.get_monte_carlo_result( + MonteCarloRequest( + SimulationProgram.GEOPHIRES, + input_file_path, + mc_settings_file_path, + ) + ) + self.assertIsNotNone(result) + self.assertIsNotNone(result.output_file_path) + + with open(result.output_file_path) as f: + result_content = f.read() + self.assertIn( + 'Average Net Electricity Production, Electricity breakeven price, Gradient 1', + result_content, + ) + gradient_inputs = re.compile(r'\(Gradient\s1\:[3-4][0-9]\.[0-9]+').findall(result_content) + self.assertEqual(num_iterations, len(gradient_inputs)) + self.assertEqual(num_iterations, len(set(gradient_inputs))) # verify unique values were generated + def test_hip_ra_monte_carlo(self): client = GeophiresMonteCarloClient() diff --git a/tests/geophires_x_tests/test_cylindrical_reservoir.py b/tests/geophires_x_tests/test_cylindrical_reservoir.py index 99bd8aca..eb12b334 100644 --- a/tests/geophires_x_tests/test_cylindrical_reservoir.py +++ b/tests/geophires_x_tests/test_cylindrical_reservoir.py @@ -9,7 +9,7 @@ from geophires_x.Model import Model from geophires_x.Parameter import ParameterEntry -from geophires_x.GeoPHIRESUtils import density_water_kg_per_m3 +from geophires_x.GeoPHIRESUtils import density_water_kg_per_m3, static_pressure_MPa from geophires_x.GeoPHIRESUtils import heat_capacity_water_J_per_kg_per_K as heatcapacitywater @@ -119,9 +119,7 @@ def test_calculate_heat_capacity_water(self): reservoir.Calculate(model) expected_heat_capacity = heatcapacitywater( model.wellbores.Tinj.value * 0.5 + (reservoir.Trock.value * 0.9 + model.wellbores.Tinj.value * 0.1) * 0.5, - pressure=model.reserv.lithostatic_pressure( - reservoir.rhorock.value, reservoir.depth.quantity().to('m').magnitude - ), + pressure=model.reserv.lithostatic_pressure(), ) assert reservoir.cpwater.value == expected_heat_capacity @@ -132,9 +130,7 @@ def test_calculate_density_water(self): reservoir.Calculate(model) expected_density = density_water_kg_per_m3( model.wellbores.Tinj.value * 0.5 + (reservoir.Trock.value * 0.9 + model.wellbores.Tinj.value * 0.1) * 0.5, - pressure=reservoir.lithostatic_pressure( - reservoir.rhorock.value, reservoir.depth.quantity().to('m').magnitude - ), + pressure=reservoir.lithostatic_pressure(), ) assert expected_density == reservoir.rhowater.value @@ -166,3 +162,11 @@ def test_calculate_initial_heat_content_max_values(self): reservoir = model.reserv reservoir.RadiusOfEffectFactor.value = 10.0 reservoir.resvolcalc.value = 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + + def test_lithostatic_pressure_calculated_from_input_depth(self): + model = self._new_model_with_cylindrical_reservoir() + reservoir = model.reserv + reservoir.InputDepth.value = 4.20 + assert reservoir.lithostatic_pressure().magnitude == static_pressure_MPa( + reservoir.rhorock.value, reservoir.InputDepth.quantity().to('m').magnitude + ) diff --git a/tests/geophires_x_tests/test_reservoir.py b/tests/geophires_x_tests/test_reservoir.py index 42db0aa8..5a50543f 100644 --- a/tests/geophires_x_tests/test_reservoir.py +++ b/tests/geophires_x_tests/test_reservoir.py @@ -17,9 +17,13 @@ def test_lithostatic_pressure(self): def test_reservoir_lithostatic_pressure(self): reservoir = Reservoir(self._new_model()) - p: PlainQuantity = reservoir.lithostatic_pressure(2700, 3000) # Assumes Reservoir default values of rho=2700, depth=3km + assert reservoir.rhorock.quantity() == PlainQuantity(2700.0, 'kilogram / meter ** 3') + assert reservoir.depth.quantity() == PlainQuantity(3000, 'm') + + p: PlainQuantity = reservoir.lithostatic_pressure() + self.assertAlmostEqual(79.433865, p.magnitude, places=3) self.assertEqual('megapascal', p.units)