From 8d57ffd930d35da39cb79f6f110759acfe21de27 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Sat, 4 Oct 2025 14:08:18 -0700 Subject: [PATCH 01/21] Update field gathering cost tooltip text from theoretical basis (https://github.com/NREL/GEOPHIRES-X/issues/427) --- src/geophires_x/Economics.py | 13 ++++++++++++- .../geophires-result.json | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index 5624f166..46da1a63 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -1897,12 +1897,23 @@ def __init__(self, model: Model): PreferredUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR, CurrentUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR ) + # noinspection SpellCheckingInspection self.Cgath = self.OutputParameterDict[self.Cgath.Name] = OutputParameter( Name="Field gathering system cost", display_name='Field gathering system costs', UnitType=Units.CURRENCY, PreferredUnits=CurrencyUnit.MDOLLARS, - CurrentUnits=CurrencyUnit.MDOLLARS + CurrentUnits=CurrencyUnit.MDOLLARS, + # TODO interpolate constant values in tooltip text instead of hardcoding + ToolTipText='The built-in cost correlation for estimating the field gathering system cost follows includes ' + 'the cost for surface piping from each well to the plant and pumps for production and ' + 'injection wells. The length of the surface piping is assumed 750 m per well at a cost of ' + '$500 per meter. The pumping cost for each pump in the production wells (line-shaft pumps) ' + 'and a single pump for the injection wells is calculated with the same correlation as GETEM. ' + 'An additional 15% is added for contingency and 12% for indirect costs. ' + 'The built-in cost correlation does not include the cost of pipelines to an off-site heat ' + 'user or a district-heating system. These costs are estimated at $750 per meter pipeline ' + 'length and can be manually added by the user to the pipeline distribution costs.' ) self.Cpiping = self.OutputParameterDict[self.Cpiping.Name] = OutputParameter( Name="Transmission pipeline costs", diff --git a/src/geophires_x_schema_generator/geophires-result.json b/src/geophires_x_schema_generator/geophires-result.json index a4fa2c10..4d3d36c8 100644 --- a/src/geophires_x_schema_generator/geophires-result.json +++ b/src/geophires_x_schema_generator/geophires-result.json @@ -420,7 +420,7 @@ }, "Field gathering system costs": { "type": "number", - "description": "Field gathering system cost", + "description": "Field gathering system cost. The built-in cost correlation for estimating the field gathering system cost follows includes the cost for surface piping from each well to the plant and pumps for production and injection wells. The length of the surface piping is assumed 750 m per well at a cost of $500 per meter. The pumping cost for each pump in the production wells (line-shaft pumps) and a single pump for the injection wells is calculated with the same correlation as GETEM. An additional 15% is added for contingency and 12% for indirect costs. The built-in cost correlation does not include the cost of pipelines to an off-site heat user or a district-heating system. These costs are estimated at $750 per meter pipeline length and can be manually added by the user to the pipeline distribution costs.", "units": "MUSD" }, "Total surface equipment costs": {}, From b1a104d2b32c52d50c0e597c03ce37c3cc40da72 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Sat, 4 Oct 2025 14:20:11 -0700 Subject: [PATCH 02/21] update stimulation cost output tooltip text with instruction to set cost to $0 for traditional hydrothermal systems per theoretical basis --- src/geophires_x/Economics.py | 3 ++- src/geophires_x_schema_generator/geophires-result.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index 46da1a63..89459d30 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -1824,7 +1824,8 @@ def __init__(self, model: Model): f'costs per well. ' f'Provide {self.ccstimadjfactor.Name} to multiply the correlation-calculated cost. ' f'Provide {self.ccstimfixed.Name} to override the correlation and set your own ' - f'total stimulation cost.' + f'total stimulation cost. ' + f'For traditional hydrothermal reservoirs, {self.ccstimfixed.Name} should be set to $0.' ) contingency_and_indirect_costs_tooltip = ( diff --git a/src/geophires_x_schema_generator/geophires-result.json b/src/geophires_x_schema_generator/geophires-result.json index 4d3d36c8..cb8b0eb5 100644 --- a/src/geophires_x_schema_generator/geophires-result.json +++ b/src/geophires_x_schema_generator/geophires-result.json @@ -400,7 +400,7 @@ "Drilling and completion costs per redrilled well": {}, "Stimulation costs": { "type": "number", - "description": "Default correlation: $1.25M per injection well plus 15% contingency plus 5% indirect costs. Provide Reservoir Stimulation Capital Cost per Injection Well and Reservoir Stimulation Capital Cost per Production Well to set the correlation costs per well. Provide Reservoir Stimulation Capital Cost Adjustment Factor to multiply the correlation-calculated cost. Provide Reservoir Stimulation Capital Cost to override the correlation and set your own total stimulation cost.", + "description": "Default correlation: $1.25M per injection well plus 15% contingency plus 5% indirect costs. Provide Reservoir Stimulation Capital Cost per Injection Well and Reservoir Stimulation Capital Cost per Production Well to set the correlation costs per well. Provide Reservoir Stimulation Capital Cost Adjustment Factor to multiply the correlation-calculated cost. Provide Reservoir Stimulation Capital Cost to override the correlation and set your own total stimulation cost. For traditional hydrothermal reservoirs, Reservoir Stimulation Capital Cost should be set to $0.", "units": "MUSD" }, "Stimulation costs (for redrilling)": {}, From cd645ea069bcfd11a8a674867ef6c1b76a98aef7 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Sat, 4 Oct 2025 14:30:18 -0700 Subject: [PATCH 03/21] Parameterize contingency and indirect costs in field gathering cost tooltip text --- src/geophires_x/Economics.py | 8 ++++++-- src/geophires_x_schema_generator/geophires-result.json | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index 89459d30..a6af2679 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -1909,9 +1909,13 @@ def __init__(self, model: Model): ToolTipText='The built-in cost correlation for estimating the field gathering system cost follows includes ' 'the cost for surface piping from each well to the plant and pumps for production and ' 'injection wells. The length of the surface piping is assumed 750 m per well at a cost of ' - '$500 per meter. The pumping cost for each pump in the production wells (line-shaft pumps) ' + '$500 per meter. The pumping cost for each pump in the production wells (line-shaft pumps) ' 'and a single pump for the injection wells is calculated with the same correlation as GETEM. ' - 'An additional 15% is added for contingency and 12% for indirect costs. ' + f'Contingency (default: ' + f'{self.contingency_percentage.quantity().to(convertible_unit("%")).magnitude:g}%). ' + f'and indirect costs (default: ' + f'{self.indirect_capital_cost_percentage.quantity().to(convertible_unit("%")).magnitude}%) ' + f'are added. ' 'The built-in cost correlation does not include the cost of pipelines to an off-site heat ' 'user or a district-heating system. These costs are estimated at $750 per meter pipeline ' 'length and can be manually added by the user to the pipeline distribution costs.' diff --git a/src/geophires_x_schema_generator/geophires-result.json b/src/geophires_x_schema_generator/geophires-result.json index cb8b0eb5..7b38c418 100644 --- a/src/geophires_x_schema_generator/geophires-result.json +++ b/src/geophires_x_schema_generator/geophires-result.json @@ -420,7 +420,7 @@ }, "Field gathering system costs": { "type": "number", - "description": "Field gathering system cost. The built-in cost correlation for estimating the field gathering system cost follows includes the cost for surface piping from each well to the plant and pumps for production and injection wells. The length of the surface piping is assumed 750 m per well at a cost of $500 per meter. The pumping cost for each pump in the production wells (line-shaft pumps) and a single pump for the injection wells is calculated with the same correlation as GETEM. An additional 15% is added for contingency and 12% for indirect costs. The built-in cost correlation does not include the cost of pipelines to an off-site heat user or a district-heating system. These costs are estimated at $750 per meter pipeline length and can be manually added by the user to the pipeline distribution costs.", + "description": "Field gathering system cost. The built-in cost correlation for estimating the field gathering system cost follows includes the cost for surface piping from each well to the plant and pumps for production and injection wells. The length of the surface piping is assumed 750 m per well at a cost of $500 per meter. The pumping cost for each pump in the production wells (line-shaft pumps) and a single pump for the injection wells is calculated with the same correlation as GETEM. Contingency (default: 15%). and indirect costs (default: 12%) are added. The built-in cost correlation does not include the cost of pipelines to an off-site heat user or a district-heating system. These costs are estimated at $750 per meter pipeline length and can be manually added by the user to the pipeline distribution costs.", "units": "MUSD" }, "Total surface equipment costs": {}, From 2d22b4b811becddc93bc769aea1bea5e60025cd9 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Sat, 4 Oct 2025 14:34:19 -0700 Subject: [PATCH 04/21] add note to Reservoir Stimulation Capital Cost to set to $0 for traditional hydrothermal systems --- src/geophires_x/Economics.py | 3 ++- src/geophires_x_schema_generator/geophires-request.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index a6af2679..e24a71ab 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -625,7 +625,8 @@ def __init__(self, model: Model): CurrentUnits=CurrencyUnit.MDOLLARS, Provided=False, Valid=False, - ToolTipText="Total reservoir stimulation capital cost, including indirect costs and contingency." + ToolTipText='Total reservoir stimulation capital cost, including indirect costs and contingency. ' + f'For traditional hydrothermal reservoirs, this parameter should be set to $0.' ) max_stimulation_cost_per_well_MUSD = 100 diff --git a/src/geophires_x_schema_generator/geophires-request.json b/src/geophires_x_schema_generator/geophires-request.json index 7c9ff113..c37759c0 100644 --- a/src/geophires_x_schema_generator/geophires-request.json +++ b/src/geophires_x_schema_generator/geophires-request.json @@ -1396,7 +1396,7 @@ ] }, "Reservoir Stimulation Capital Cost": { - "description": "Total reservoir stimulation capital cost, including indirect costs and contingency.", + "description": "Total reservoir stimulation capital cost, including indirect costs and contingency. For traditional hydrothermal reservoirs, this parameter should be set to $0.", "type": "number", "units": "MUSD", "category": "Economics", From daee411886a2786db67b8be9fc1d284d56819260 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Sun, 5 Oct 2025 10:50:21 -0700 Subject: [PATCH 05/21] define separate end-use option output parameter in preparation to add theoretical basis tooltip text (WIP) --- src/geophires_x/OptionList.py | 30 ++++++++++++++++++++---------- src/geophires_x/Outputs.py | 3 ++- src/geophires_x/SUTRAOutputs.py | 3 ++- src/geophires_x/SurfacePlant.py | 9 +++++++++ 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/geophires_x/OptionList.py b/src/geophires_x/OptionList.py index c3c5ddd7..77d84f52 100644 --- a/src/geophires_x/OptionList.py +++ b/src/geophires_x/OptionList.py @@ -25,18 +25,22 @@ def __ne__(self, other): return str(self) != str(other) +_EXTRA_HEAT_SNIPPET = 'Heat sales considered as extra income' +_EXTRA_ELECTRICITY_SNIPPET = 'Electricity sales considered as extra income' + + class EndUseOptions(GeophiresInputEnum): - ELECTRICITY = 1, "Electricity" - HEAT = 2, "Direct-Use Heat" - COGENERATION_TOPPING_EXTRA_HEAT = 31, "Cogeneration Topping Cycle, Heat sales considered as extra income" - COGENERATION_TOPPING_EXTRA_ELECTRICITY = 32, "Cogeneration Topping Cycle, Electricity sales considered as extra income" - COGENERATION_BOTTOMING_EXTRA_HEAT = 41, "Cogeneration Bottoming Cycle, Heat sales considered as extra income" - COGENERATION_BOTTOMING_EXTRA_ELECTRICITY = 42, "Cogeneration Bottoming Cycle, Electricity sales considered as extra income" - COGENERATION_PARALLEL_EXTRA_HEAT = 51, "Cogeneration Parallel Cycle, Heat sales considered as extra income" - COGENERATION_PARALLEL_EXTRA_ELECTRICITY = 52, "Cogeneration Parallel Cycle, Electricity sales considered as extra income" + ELECTRICITY = 1, 'Electricity' + HEAT = 2, 'Direct-Use Heat' + COGENERATION_TOPPING_EXTRA_HEAT = 31, f'Cogeneration Topping Cycle, {_EXTRA_HEAT_SNIPPET}' + COGENERATION_TOPPING_EXTRA_ELECTRICITY = 32, f'Cogeneration Topping Cycle, {_EXTRA_ELECTRICITY_SNIPPET}' + COGENERATION_BOTTOMING_EXTRA_HEAT = 41, f'Cogeneration Bottoming Cycle, {_EXTRA_HEAT_SNIPPET}' + COGENERATION_BOTTOMING_EXTRA_ELECTRICITY = 42, f'Cogeneration Bottoming Cycle, {_EXTRA_ELECTRICITY_SNIPPET}' + COGENERATION_PARALLEL_EXTRA_HEAT = 51, f'Cogeneration Parallel Cycle, {_EXTRA_HEAT_SNIPPET}' + COGENERATION_PARALLEL_EXTRA_ELECTRICITY = 52, f'Cogeneration Parallel Cycle, {_EXTRA_ELECTRICITY_SNIPPET}' @staticmethod - def from_input_string(input_string: str): + def from_input_string(input_string: str) -> 'EndUseOptions': """ :rtype: EndUseOptions """ @@ -48,11 +52,17 @@ def from_input_string(input_string: str): raise ValueError(f'Unknown End-Use Option input value: {input_string}') @staticmethod - def from_int(int_val): + def from_int(int_val: int) -> 'EndUseOptions': + """ + :rtype: EndUseOptions + """ + for member in __class__: if member.int_value == int_val: return member + raise ValueError(f'Unknown End-Use Option integer input value: {int_val}') + class PlantType(GeophiresInputEnum): SUB_CRITICAL_ORC = 1, "Subcritical ORC" diff --git a/src/geophires_x/Outputs.py b/src/geophires_x/Outputs.py index 6f8546cd..208b3c65 100644 --- a/src/geophires_x/Outputs.py +++ b/src/geophires_x/Outputs.py @@ -195,7 +195,8 @@ def PrintOutputs(self, model: Model): f.write(NL) f.write(' ***SUMMARY OF RESULTS***\n') f.write(NL) - f.write(f' End-Use Option: {str(model.surfaceplant.enduse_option.value.value)}\n') + f.write(f' {model.surfaceplant.enduse_option_output.display_name}: ' + f'{model.surfaceplant.enduse_option_output.value}\n') if model.surfaceplant.plant_type.value in [PlantType.ABSORPTION_CHILLER, PlantType.HEAT_PUMP, PlantType.DISTRICT_HEATING]: f.write(' Surface Application: ' + str(model.surfaceplant.plant_type.value.value) + NL) if model.surfaceplant.enduse_option.value in [EndUseOptions.ELECTRICITY, EndUseOptions.COGENERATION_TOPPING_EXTRA_HEAT, EndUseOptions.COGENERATION_TOPPING_EXTRA_ELECTRICITY, EndUseOptions.COGENERATION_BOTTOMING_EXTRA_ELECTRICITY, EndUseOptions.COGENERATION_BOTTOMING_EXTRA_HEAT, EndUseOptions.COGENERATION_PARALLEL_EXTRA_HEAT, EndUseOptions.COGENERATION_PARALLEL_EXTRA_ELECTRICITY]: # there is an electricity component diff --git a/src/geophires_x/SUTRAOutputs.py b/src/geophires_x/SUTRAOutputs.py index 813188cf..93172b3a 100644 --- a/src/geophires_x/SUTRAOutputs.py +++ b/src/geophires_x/SUTRAOutputs.py @@ -67,7 +67,8 @@ def PrintOutputs(self, model: Model): f.write(NL) f.write(' ***SUMMARY OF RESULTS***\n') f.write(NL) - f.write(" End-Use Option: " + str(model.surfaceplant.enduse_option.value.value) + NL) + f.write(f' {model.surfaceplant.enduse_option_output.display_name}: ' + f'{model.surfaceplant.enduse_option_output.value}\n') f.write(" Reservoir Model = " + str(model.reserv.resoption.value.value) + " Model\n") f.write(f" Direct-Use heat breakeven price: {model.economics.LCOH.value:10.2f} " + model.economics.LCOH.CurrentUnits.value + NL) diff --git a/src/geophires_x/SurfacePlant.py b/src/geophires_x/SurfacePlant.py index 2fb9f9e0..a7ec5d13 100644 --- a/src/geophires_x/SurfacePlant.py +++ b/src/geophires_x/SurfacePlant.py @@ -471,6 +471,13 @@ def __init__(self, model: Model): self.MyPath = os.path.abspath(__file__) # Results - used by other objects or printed in output downstream + self.enduse_option_output = self.OutputParameterDict[self.enduse_option_output.Name] = OutputParameter( + Name=self.enduse_option.Name, + UnitType=Units.NONE, + # FIXME WIP + # ToolTipText="Select the end-use application of the geofluid heat: " + + # '; '.join([f'{it.int_value}: {it.value}' for it in EndUseOptions]) + ) self.usebuiltinoutletplantcorrelation = self.OutputParameterDict[self.usebuiltinoutletplantcorrelation.Name] = OutputParameter( Name="usebuiltinoutletplantcorrelation", UnitType=Units.NONE @@ -697,3 +704,5 @@ def _calculate_derived_outputs(self, model: Model) -> None: convertible_unit(self.heat_to_power_conversion_efficiency.CurrentUnits)).magnitude if avg_efficiency > 0: # 0 is presumed to mean N/A self.heat_to_power_conversion_efficiency.value = avg_efficiency + + self.enduse_option_output.value = self.enduse_option.value.value From 40626ff80bcbf97708ecb0504997b8e54a177047 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Sun, 5 Oct 2025 11:14:11 -0700 Subject: [PATCH 06/21] Port End-Use Option output parameter tooltip text from theoretical basis --- src/geophires_x/SurfacePlant.py | 35 +++++++++++++++++-- .../geophires-result.json | 6 +++- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/geophires_x/SurfacePlant.py b/src/geophires_x/SurfacePlant.py index a7ec5d13..9ac33f6d 100644 --- a/src/geophires_x/SurfacePlant.py +++ b/src/geophires_x/SurfacePlant.py @@ -471,12 +471,41 @@ def __init__(self, model: Model): self.MyPath = os.path.abspath(__file__) # Results - used by other objects or printed in output downstream + self.enduse_option_output = self.OutputParameterDict[self.enduse_option_output.Name] = OutputParameter( Name=self.enduse_option.Name, UnitType=Units.NONE, - # FIXME WIP - # ToolTipText="Select the end-use application of the geofluid heat: " + - # '; '.join([f'{it.int_value}: {it.value}' for it in EndUseOptions]) + ToolTipText='Five different end-use options are available in GEOPHIRES: ' + '1: Electricity: All produced geothermal fluid is used to generate electricity with either an ' + 'ORC or flash power plant; ' + '2: Direct-use heat: All produced geothermal fluid is used to provide heating for a given ' + 'application, e.g., a district-heating system or industrial process; ' + '3: Cogeneration or combined heat and power (CHP): Both heat and electricity are produced. ' + 'Three different cogeneration configurations are available: ' + '(1): Cogeneration topping cycle: A power plant is followed by a direct-use heat application ' + 'in series. Heat at high temperatures from the geothermal fluid is first converted into ' + 'electricity. Any remaining heat in the geothermal fluid after leaving the power plant is ' + 'supplied to a low-temperature direct-use heat application; ' + '(2): Cogeneration bottoming cycle: A direct-use heat application is followed by a power plant ' + 'in series. In this less common configuration, the geothermal fluid first serves a ' + 'high-temperature direct-use heat application. Any remaining heat in the geothermal fluid ' + 'after leaving the direct-use heat process (at a user-specified temperature) is used to ' + 'generate electricity. The heat-to-power conversion typically occurs with an ORC plant ' + 'operating at low conversion efficiencies; ' + '(3): Cogeneration parallel cycle: A power plant operates in parallel with a direct-use heat ' + 'application. The produced geothermal fluid is split into two streams, providing heat at the ' + 'same temperature to a power plant and direct-use heat application. The user specifies the ' + 'fluid flow fraction going to each process.', + # TODO this tooltip text (ported from the theoretical basis) is probably better suited to being semantically + # associated with the End-Use Option input parameter rather than the corresponding OutputParameter here. + # However, the input parameter tooltip text is generated from an enumeration of EndUseOptions enum values + # which doesn't cleanly map to the information contained here because each of the CHP configurations has + # two EndUseOptions for whether heat or electricity sales are considered as extra income. This mapping + # incongruency could possibly eventually be addressed by an additional layer of metadata/indirection for + # adding pointers from input parameters to more complete documentation entries/sections. In the meantime, + # this output parameter tooltip is a logical-enough place to store the information, where it is reasonably + # user-accessible in the UI and parameters reference. + json_parameter_type='string' ) self.usebuiltinoutletplantcorrelation = self.OutputParameterDict[self.usebuiltinoutletplantcorrelation.Name] = OutputParameter( Name="usebuiltinoutletplantcorrelation", diff --git a/src/geophires_x_schema_generator/geophires-result.json b/src/geophires_x_schema_generator/geophires-result.json index 7b38c418..ddffd808 100644 --- a/src/geophires_x_schema_generator/geophires-result.json +++ b/src/geophires_x_schema_generator/geophires-result.json @@ -8,7 +8,11 @@ "SUMMARY OF RESULTS": { "type": "object", "properties": { - "End-Use Option": {}, + "End-Use Option": { + "type": "string", + "description": "Five different end-use options are available in GEOPHIRES: 1: Electricity: All produced geothermal fluid is used to generate electricity with either an ORC or flash power plant; 2: Direct-use heat: All produced geothermal fluid is used to provide heating for a given application, e.g., a district-heating system or industrial process; 3: Cogeneration or combined heat and power (CHP): Both heat and electricity are produced. Three different cogeneration configurations are available: (1): Cogeneration topping cycle: A power plant is followed by a direct-use heat application in series. Heat at high temperatures from the geothermal fluid is first converted into electricity. Any remaining heat in the geothermal fluid after leaving the power plant is supplied to a low-temperature direct-use heat application; (2): Cogeneration bottoming cycle: A direct-use heat application is followed by a power plant in series. In this less common configuration, the geothermal fluid first serves a high-temperature direct-use heat application. Any remaining heat in the geothermal fluid after leaving the direct-use heat process (at a user-specified temperature) is used to generate electricity. The heat-to-power conversion typically occurs with an ORC plant operating at low conversion efficiencies; (3): Cogeneration parallel cycle: A power plant operates in parallel with a direct-use heat application. The produced geothermal fluid is split into two streams, providing heat at the same temperature to a power plant and direct-use heat application. The user specifies the fluid flow fraction going to each process.", + "units": null + }, "End-Use": {}, "Surface Application": {}, "Reservoir Model": {}, From c19a581eeb0a9d82085c00ca8e6e2e6b051edb32 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Sun, 5 Oct 2025 11:21:48 -0700 Subject: [PATCH 07/21] incorporate theoretical basis time steps per year into tooltip text --- src/geophires_x/Economics.py | 13 ++++++++++++- .../geophires-request.json | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index e24a71ab..80ee2853 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -939,7 +939,18 @@ def __init__(self, model: Model): UnitType=Units.NONE, Required=True, ErrMessage="assume default number of time steps per year (4)", - ToolTipText="Number of internal simulation time steps per year" + ToolTipText='Number of internal simulation time steps per year. GEOPHIRES assumes linear time ' + 'discretization with a user-provided number of time steps per year over the lifetime of the ' + 'plant. The default is four time steps per year, meaning a time step of 3 months. ' + 'At every time step, GEOPHIRES calculates the reservoir output temperature, production ' + 'wellhead temperature, direct-use heat and/or electricity power output (in MW), pressure ' + 'drops and pumping power. On an annual basis, GEOPHIRES calculates the O&M costs and ' + 'direct-use heat and/or electricity production. To investigate seasonal effects, e.g., to ' + 'assess the impact of more geothermal heat demand for district heating in winter than in ' + 'summer, the user can select a smaller time step, e.g., a month (or 12 time steps per year). ' + 'For even shorter timescale effects, e.g., to account for an hourly varying ambient ' + 'temperature or investigate the response in plant operation to a fluctuating revenue rate), ' + 'the user can select an even smaller time step, e.g., 1 h (or 8760 time steps per year).' ) self.FCR = self.ParameterDict[self.FCR.Name] = floatParameter( "Fixed Charge Rate", diff --git a/src/geophires_x_schema_generator/geophires-request.json b/src/geophires_x_schema_generator/geophires-request.json index c37759c0..0788b878 100644 --- a/src/geophires_x_schema_generator/geophires-request.json +++ b/src/geophires_x_schema_generator/geophires-request.json @@ -1612,7 +1612,7 @@ "maximum": 100 }, "Time steps per year": { - "description": "Number of internal simulation time steps per year", + "description": "Number of internal simulation time steps per year. GEOPHIRES assumes linear time discretization with a user-provided number of time steps per year over the lifetime of the plant. The default is four time steps per year, meaning a time step of 3 months. At every time step, GEOPHIRES calculates the reservoir output temperature, production wellhead temperature, direct-use heat and/or electricity power output (in MW), pressure drops and pumping power. On an annual basis, GEOPHIRES calculates the O&M costs and direct-use heat and/or electricity production. To investigate seasonal effects, e.g., to assess the impact of more geothermal heat demand for district heating in winter than in summer, the user can select a smaller time step, e.g., a month (or 12 time steps per year). For even shorter timescale effects, e.g., to account for an hourly varying ambient temperature or investigate the response in plant operation to a fluctuating revenue rate), the user can select an even smaller time step, e.g., 1 h (or 8760 time steps per year).", "type": "integer", "units": null, "category": "Economics", From d7470e0a77016cc4918a0c3e1b5a0078f506c083 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Sun, 5 Oct 2025 11:26:52 -0700 Subject: [PATCH 08/21] update exploration costs tooltip from theoretical basis (previous version was missing M for geophysical aand field work) --- src/geophires_x/Economics.py | 3 ++- src/geophires_x_schema_generator/geophires-result.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index 80ee2853..9c7c204b 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -1852,7 +1852,8 @@ def __init__(self, model: Model): UnitType=Units.CURRENCY, PreferredUnits=CurrencyUnit.MDOLLARS, CurrentUnits=CurrencyUnit.MDOLLARS, - ToolTipText=f'Default correlation: 60% of the cost of one production well ' + ToolTipText=f'The built-in exploration cost correlation considers drilling of a slim-hole well at 60% of ' + f'the cost of a regular well, $1M for geophysical and field work, ' f'{contingency_and_indirect_costs_tooltip}. ' f'Provide {self.ccexpladjfactor.Name} to multiply the default correlation. ' f'Provide {self.ccexplfixed.Name} to override the default correlation and set your own cost.' diff --git a/src/geophires_x_schema_generator/geophires-result.json b/src/geophires_x_schema_generator/geophires-result.json index ddffd808..9762ca0c 100644 --- a/src/geophires_x_schema_generator/geophires-result.json +++ b/src/geophires_x_schema_generator/geophires-result.json @@ -430,7 +430,7 @@ "Total surface equipment costs": {}, "Exploration costs": { "type": "number", - "description": "Exploration cost. Default correlation: 60% of the cost of one production well plus 15% contingency plus 12% indirect costs. Provide Exploration Capital Cost Adjustment Factor to multiply the default correlation. Provide Exploration Capital Cost to override the default correlation and set your own cost.", + "description": "Exploration cost. The built-in exploration cost correlation considers drilling of a slim-hole well at 60% of the cost of a regular well, $1M for geophysical and field work, plus 15% contingency plus 12% indirect costs. Provide Exploration Capital Cost Adjustment Factor to multiply the default correlation. Provide Exploration Capital Cost to override the default correlation and set your own cost.", "units": "MUSD" }, "Investment Tax Credit": { From 8271d91140806ac7596cfb855e790d5f797205aa Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Sun, 5 Oct 2025 11:33:39 -0700 Subject: [PATCH 09/21] add reference to Water Cost Adjustment factor in water costs output paramter --- src/geophires_x/Economics.py | 4 +++- src/geophires_x_schema_generator/geophires-result.json | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index 9c7c204b..7f1b0074 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -1946,7 +1946,9 @@ def __init__(self, model: Model): UnitType=Units.CURRENCYFREQUENCY, PreferredUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR, CurrentUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR, - ToolTipText='Assumes $3.5/1,000 gallons of water' # TODO parameterize + ToolTipText=f'Default correlation: Assumes $3.50/1,000 gallons of water. ' + f'Provide {self.oamwateradjfactor.Name} to multiply the default correlation.' + # Note: $3.50 could possibly be parameterized, but adjustment factor param serves the same purpose for now. ) self.CCap = self.OutputParameterDict[self.CCap.Name] = OutputParameter( Name="Total Capital Cost", diff --git a/src/geophires_x_schema_generator/geophires-result.json b/src/geophires_x_schema_generator/geophires-result.json index 9762ca0c..1e5d126b 100644 --- a/src/geophires_x_schema_generator/geophires-result.json +++ b/src/geophires_x_schema_generator/geophires-result.json @@ -482,7 +482,7 @@ }, "Water costs": { "type": "number", - "description": "O&M Make-up Water costs. Assumes $3.5/1,000 gallons of water", + "description": "O&M Make-up Water costs. Default correlation: Assumes $3.50/1,000 gallons of water. Provide Water Cost Adjustment Factor to multiply the default correlation.", "units": "MUSD/yr" }, "Average Reservoir Pumping Cost": {}, From a1d67003bd8bf5d5bd652738c3a4556a0cb897f6 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Sun, 5 Oct 2025 11:42:48 -0700 Subject: [PATCH 10/21] Port wellfield & surface plant O&M cost tooltips from theoretical basis --- src/geophires_x/Economics.py | 23 ++++++++++++++++--- .../geophires-result.json | 4 ++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index 7f1b0074..4e510f2b 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -1879,14 +1879,21 @@ def __init__(self, model: Model): ToolTipText='Drilling and completion cost per well, including indirect costs ' f'(default: {self.wellfield_indirect_capital_cost_percentage.DefaultValue}%).' ) + + # noinspection SpellCheckingInspection self.Coamwell = self.OutputParameterDict[self.Coamwell.Name] = OutputParameter( Name="O&M Wellfield cost", display_name='Wellfield maintenance costs', UnitType=Units.CURRENCYFREQUENCY, PreferredUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR, - CurrentUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR - # TODO TooltipText to document how this is calculated + CurrentUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR, + ToolTipText='The built-in correlation for the wellfield O&M costs is similar as the surface plant O&M ' + 'costs: it assumes that it consists of 1% of the total wellfield plus field gathering system ' + 'costs (for annual non-labor costs) and 25% of the labor costs (the other 75% of the labor ' + 'costs are assigned to the surface plant O&M costs).' + # TODO parameterize relevant constants ) + self.redrilling_annual_cost = self.OutputParameterDict[self.redrilling_annual_cost.Name] = OutputParameter( Name="Redrilling costs", UnitType=Units.CURRENCYFREQUENCY, @@ -1909,7 +1916,17 @@ def __init__(self, model: Model): display_name='Power plant maintenance costs', UnitType=Units.CURRENCYFREQUENCY, PreferredUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR, - CurrentUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR + CurrentUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR, + # TODO parameterize relevant constants + # TODO update index year and/or make indexing parameterizable + ToolTipText='GEOPHIRES estimates the annual surface plant O&M costs as the sum of 1.5% of the total plant ' + 'capital cost (for annual non-labor costs), and 75% of the annual labor costs. The other 25% ' + 'of the labor costs are assigned to the wellfield O&M cost. The labor costs are calculated ' + 'internally in GEOPHIRES using the 2014 labor costs provided by Beckers (2016), indexed to ' + '2017 using the Bureau of Labor Statistics (BLS) Employment Cost Index for utilities (2018). ' + 'The original 2014 labor cost correlation expresses the labor costs as a function of the plant ' + 'size (MW) using an approximate logarithmic curve fit to the built-in labor cost data in ' + 'GETEM.' ) # noinspection SpellCheckingInspection self.Cgath = self.OutputParameterDict[self.Cgath.Name] = OutputParameter( diff --git a/src/geophires_x_schema_generator/geophires-result.json b/src/geophires_x_schema_generator/geophires-result.json index 1e5d126b..a3fbec26 100644 --- a/src/geophires_x_schema_generator/geophires-result.json +++ b/src/geophires_x_schema_generator/geophires-result.json @@ -472,12 +472,12 @@ "properties": { "Wellfield maintenance costs": { "type": "number", - "description": "O&M Wellfield cost", + "description": "O&M Wellfield cost. The built-in correlation for the wellfield O&M costs is similar as the surface plant O&M costs: it assumes that it consists of 1% of the total wellfield plus field gathering system costs (for annual non-labor costs) and 25% of the labor costs (the other 75% of the labor costs are assigned to the surface plant O&M costs).", "units": "MUSD/yr" }, "Power plant maintenance costs": { "type": "number", - "description": "O&M Surface Plant costs", + "description": "O&M Surface Plant costs. GEOPHIRES estimates the annual surface plant O&M costs as the sum of 1.5% of the total plant capital cost (for annual non-labor costs), and 75% of the annual labor costs. The other 25% of the labor costs are assigned to the wellfield O&M cost. The labor costs are calculated internally in GEOPHIRES using the 2014 labor costs provided by Beckers (2016), indexed to 2017 using the Bureau of Labor Statistics (BLS) Employment Cost Index for utilities (2018). The original 2014 labor cost correlation expresses the labor costs as a function of the plant size (MW) using an approximate logarithmic curve fit to the built-in labor cost data in GETEM.", "units": "MUSD/yr" }, "Water costs": { From e0d63ca603c1eeb1af459213d05ce051b7a44064 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:00:47 -0700 Subject: [PATCH 11/21] port tooltip text for surface plant costs from theoretical basis --- src/geophires_x/Economics.py | 36 ++++++++++++++++++- src/geophires_x/Outputs.py | 2 +- .../geophires-result.json | 6 +++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index 4e510f2b..302f58ba 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -1840,6 +1840,7 @@ def __init__(self, model: Model): f'For traditional hydrothermal reservoirs, {self.ccstimfixed.Name} should be set to $0.' ) + # TODO switch order to align with theoretical basis, which lists indirect costs first contingency_and_indirect_costs_tooltip = ( f'plus {self.contingency_percentage.quantity().to(convertible_unit("%")).magnitude:g}% contingency ' f'plus {self.indirect_capital_cost_percentage.quantity().to(convertible_unit("%")).magnitude}% ' @@ -1907,9 +1908,42 @@ def __init__(self, model: Model): ) self.Cplant = self.OutputParameterDict[self.Cplant.Name] = OutputParameter( Name="Surface Plant cost", + display_name='Surface power plant costs', UnitType=Units.CURRENCY, PreferredUnits=CurrencyUnit.MDOLLARS, - CurrentUnits=CurrencyUnit.MDOLLARS + CurrentUnits=CurrencyUnit.MDOLLARS, + ToolTipText='The built-in power plant cost correlations are based on the original correlations developed ' + 'by Beckers (2016), indexed to 2017 using the IHS Markit North American Power Capital Costs ' + 'Index (NAPCCI) excluding nuclear plants (IHS 2018). The ORC power plant cost data have been ' + 'updated with data from the 2016 GETEM tool (DOE 2016) and the geothermal binary power plants ' + # 'study by Verkís (2014). ' + 'study by Verkis (2014). ' # unicode accented i may cause unexpected problems in consumers... + # TODO incorporate reference to figure (commented out for now) + # 'Figure 4 shows the power plant capital cost expressed in $ kWe−1 as a function of plant + # size and initial production temperature for subcritical ORC and double-flash power plants. ' + # TODO use tooltip var + 'The correlations in GEOPHIRES include 12% for indirect costs and 15% contingency. ' + 'For the same plant size and production temperature, double-flash power plants are considered ' + 'about 25% more expensive than single-flash power plants (Zeyghami 2010), and supercritical ' + 'ORC plants are roughly 10% more than subcritical ORC plants (Astolfi et al. 2014). A wide ' + 'range in power plant specific cost values is reported in academic and popular literature. ' + 'The GEOPHIRES built-in surface plant cost correlations represent typical values. However, ' + 'the user is recommended to provide their own power plant cost data if available for their ' + 'case study. The ORC plant specific cost decreases only moderately at higher temperatures. ' + 'The reasons are that when increasing the temperature, the ORC plant design also changes: ' + '(1) a different organic fluid is selected, (2) piping, pump, heat exchangers, and other ' + 'equipment are designed to handle the higher temperature (and potentially also pressure), ' + 'requiring thicker walls, potentially different materials, etc., and (3) additional components ' + 'may be implemented, such as a heat recuperator, making the design and operation more complex. ' + 'Unlike flash power plants, ORC plants are a small, niche market, typically case specific, ' + 'and rely on relatively young technology, which has not been subject yet to decades of ' + 'technological advancement. The cost for direct-use heat applications is highly dependent ' + 'on the type of application. A generic cost of $250 kWth−1 is assumed ' + f'{contingency_and_indirect_costs_tooltip}. ' + 'However, users are encouraged to provide their own cost figures for ' + 'their specific application. Beckers and Young (2017) collected several cost figures to ' + 'estimate the surface equipment cost for geothermal district-heating systems.' + # TODO incorporate direct references to relevant parameters for adjusting correlation ) self.Coamplant = self.OutputParameterDict[self.Coamplant.Name] = OutputParameter( Name="O&M Surface Plant costs", diff --git a/src/geophires_x/Outputs.py b/src/geophires_x/Outputs.py index 208b3c65..6dbd57c6 100644 --- a/src/geophires_x/Outputs.py +++ b/src/geophires_x/Outputs.py @@ -482,7 +482,7 @@ def PrintOutputs(self, model: Model): cpw_label = Outputs._field_label(econ.drilling_and_completion_costs_per_well.display_name, 47) f.write(f' {cpw_label}{econ.drilling_and_completion_costs_per_well.value:10.2f} {econ.Cwell.CurrentUnits.value}\n') f.write(f' {econ.Cstim.display_name}: {econ.Cstim.value:10.2f} {econ.Cstim.CurrentUnits.value}\n') - f.write(f' Surface power plant costs: {model.economics.Cplant.value:10.2f} ' + model.economics.Cplant.CurrentUnits.value + NL) + f.write(f' {econ.Cplant.display_name}: {econ.Cplant.value:10.2f} {econ.Cplant.CurrentUnits.value}\n') if model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: f.write(f' of which Absorption Chiller Cost: {model.economics.chillercapex.value:10.2f} ' + model.economics.Cplant.CurrentUnits.value + NL) if model.surfaceplant.plant_type.value == PlantType.HEAT_PUMP: diff --git a/src/geophires_x_schema_generator/geophires-result.json b/src/geophires_x_schema_generator/geophires-result.json index a3fbec26..d21f0b63 100644 --- a/src/geophires_x_schema_generator/geophires-result.json +++ b/src/geophires_x_schema_generator/geophires-result.json @@ -408,7 +408,11 @@ "units": "MUSD" }, "Stimulation costs (for redrilling)": {}, - "Surface power plant costs": {}, + "Surface power plant costs": { + "type": "number", + "description": "Surface Plant cost. The built-in power plant cost correlations are based on the original correlations developed by Beckers (2016), indexed to 2017 using the IHS Markit North American Power Capital Costs Index (NAPCCI) excluding nuclear plants (IHS 2018). The ORC power plant cost data have been updated with data from the 2016 GETEM tool (DOE 2016) and the geothermal binary power plants study by Verkis (2014). The correlations in GEOPHIRES include 12% for indirect costs and 15% contingency. For the same plant size and production temperature, double-flash power plants are considered about 25% more expensive than single-flash power plants (Zeyghami 2010), and supercritical ORC plants are roughly 10% more than subcritical ORC plants (Astolfi et al. 2014). A wide range in power plant specific cost values is reported in academic and popular literature. The GEOPHIRES built-in surface plant cost correlations represent typical values. However, the user is recommended to provide their own power plant cost data if available for their case study. The ORC plant specific cost decreases only moderately at higher temperatures. The reasons are that when increasing the temperature, the ORC plant design also changes: (1) a different organic fluid is selected, (2) piping, pump, heat exchangers, and other equipment are designed to handle the higher temperature (and potentially also pressure), requiring thicker walls, potentially different materials, etc., and (3) additional components may be implemented, such as a heat recuperator, making the design and operation more complex. Unlike flash power plants, ORC plants are a small, niche market, typically case specific, and rely on relatively young technology, which has not been subject yet to decades of technological advancement. The cost for direct-use heat applications is highly dependent on the type of application. A generic cost of $250 kWth\u22121 is assumed plus 15% contingency plus 12% indirect costs. However, users are encouraged to provide their own cost figures for their specific application. Beckers and Young (2017) collected several cost figures to estimate the surface equipment cost for geothermal district-heating systems.", + "units": "MUSD" + }, "of which Absorption Chiller Cost": {}, "of which Heat Pump Cost": {}, "of which Peaking Boiler Cost": {}, From 83aaa81a1a5710afcfc3df23aeb52f2754279d8d Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:08:34 -0700 Subject: [PATCH 12/21] fix port-related typo in field gathering costs tooltip --- src/geophires_x/Economics.py | 2 +- src/geophires_x_schema_generator/geophires-result.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index 302f58ba..a7d47d90 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -1970,7 +1970,7 @@ def __init__(self, model: Model): PreferredUnits=CurrencyUnit.MDOLLARS, CurrentUnits=CurrencyUnit.MDOLLARS, # TODO interpolate constant values in tooltip text instead of hardcoding - ToolTipText='The built-in cost correlation for estimating the field gathering system cost follows includes ' + ToolTipText='The built-in cost correlation for estimating the field gathering system cost includes ' 'the cost for surface piping from each well to the plant and pumps for production and ' 'injection wells. The length of the surface piping is assumed 750 m per well at a cost of ' '$500 per meter. The pumping cost for each pump in the production wells (line-shaft pumps) ' diff --git a/src/geophires_x_schema_generator/geophires-result.json b/src/geophires_x_schema_generator/geophires-result.json index d21f0b63..1e334ed1 100644 --- a/src/geophires_x_schema_generator/geophires-result.json +++ b/src/geophires_x_schema_generator/geophires-result.json @@ -428,7 +428,7 @@ }, "Field gathering system costs": { "type": "number", - "description": "Field gathering system cost. The built-in cost correlation for estimating the field gathering system cost follows includes the cost for surface piping from each well to the plant and pumps for production and injection wells. The length of the surface piping is assumed 750 m per well at a cost of $500 per meter. The pumping cost for each pump in the production wells (line-shaft pumps) and a single pump for the injection wells is calculated with the same correlation as GETEM. Contingency (default: 15%). and indirect costs (default: 12%) are added. The built-in cost correlation does not include the cost of pipelines to an off-site heat user or a district-heating system. These costs are estimated at $750 per meter pipeline length and can be manually added by the user to the pipeline distribution costs.", + "description": "Field gathering system cost. The built-in cost correlation for estimating the field gathering system cost includes the cost for surface piping from each well to the plant and pumps for production and injection wells. The length of the surface piping is assumed 750 m per well at a cost of $500 per meter. The pumping cost for each pump in the production wells (line-shaft pumps) and a single pump for the injection wells is calculated with the same correlation as GETEM. Contingency (default: 15%). and indirect costs (default: 12%) are added. The built-in cost correlation does not include the cost of pipelines to an off-site heat user or a district-heating system. These costs are estimated at $750 per meter pipeline length and can be manually added by the user to the pipeline distribution costs.", "units": "MUSD" }, "Total surface equipment costs": {}, From 04347d5abc2d2fe676bd35ec56209bae6ca7d31f Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:12:28 -0700 Subject: [PATCH 13/21] copy edit: remove extraneous comma in theoretical basis summary --- docs/Theoretical-Basis-for-GEOPHIRES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Theoretical-Basis-for-GEOPHIRES.md b/docs/Theoretical-Basis-for-GEOPHIRES.md index 33e742f8..4027cff8 100644 --- a/docs/Theoretical-Basis-for-GEOPHIRES.md +++ b/docs/Theoretical-Basis-for-GEOPHIRES.md @@ -1,6 +1,6 @@ # Theoretical Basis for GEOPHIRES -This document describes the foundational theoretical basis for GEOPHIRES, adapted from the 2019 paper, "[GEOPHIRES v2.0: updated geothermal techno-economic simulation tool](https://doi.org/10.1186/s40517-019-0119-6)" by Koenraad F. Beckers & Kevin McCabe. The core theories described here remain valid and relevant to the current software. +This document describes the foundational theoretical basis for GEOPHIRES, adapted from the 2019 paper "[GEOPHIRES v2.0: updated geothermal techno-economic simulation tool](https://doi.org/10.1186/s40517-019-0119-6)" by Koenraad F. Beckers & Kevin McCabe. The core theories described here remain valid and relevant to the current software. However, the text has not been comprehensively updated to include the theory for features added in GEOPHIRES v3 (GEOPHIRES-X) and later. While pointers to the documentation for newer models have been added, the detailed technical descriptions herein still pertain to v2.0. From c7f8fb4918b694a5dfcaf0d3d11c70b6e7321139 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Wed, 8 Oct 2025 08:19:57 -0700 Subject: [PATCH 14/21] Surface power plant costs figure reference, tooltip var interpolation; various minor TODO cleanup --- src/geophires_x/Economics.py | 28 +++++++++++-------- .../geophires-result.json | 2 +- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index a7d47d90..47cb1500 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -1841,11 +1841,14 @@ def __init__(self, model: Model): ) # TODO switch order to align with theoretical basis, which lists indirect costs first - contingency_and_indirect_costs_tooltip = ( - f'plus {self.contingency_percentage.quantity().to(convertible_unit("%")).magnitude:g}% contingency ' + contingency_and_indirect_costs_tooltip_stem = ( + f'{self.contingency_percentage.quantity().to(convertible_unit("%")).magnitude:g}% contingency ' f'plus {self.indirect_capital_cost_percentage.quantity().to(convertible_unit("%")).magnitude}% ' f'indirect costs' ) + contingency_and_indirect_costs_tooltip = ( + f'plus {contingency_and_indirect_costs_tooltip_stem}' + ) self.Cexpl = self.OutputParameterDict[self.Cexpl.Name] = OutputParameter( Name="Exploration cost", @@ -1888,11 +1891,11 @@ def __init__(self, model: Model): UnitType=Units.CURRENCYFREQUENCY, PreferredUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR, CurrentUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR, + # TODO parameterize relevant constants in tooltip text ToolTipText='The built-in correlation for the wellfield O&M costs is similar as the surface plant O&M ' 'costs: it assumes that it consists of 1% of the total wellfield plus field gathering system ' 'costs (for annual non-labor costs) and 25% of the labor costs (the other 75% of the labor ' 'costs are assigned to the surface plant O&M costs).' - # TODO parameterize relevant constants ) self.redrilling_annual_cost = self.OutputParameterDict[self.redrilling_annual_cost.Name] = OutputParameter( @@ -1906,23 +1909,25 @@ def __init__(self, model: Model): f'The total is then divided over {model.surfaceplant.plant_lifetime.Name} years to calculate ' f'Redrilling costs per year.' ) + # noinspection SpellCheckingInspection self.Cplant = self.OutputParameterDict[self.Cplant.Name] = OutputParameter( Name="Surface Plant cost", display_name='Surface power plant costs', UnitType=Units.CURRENCY, PreferredUnits=CurrencyUnit.MDOLLARS, CurrentUnits=CurrencyUnit.MDOLLARS, + # TODO incorporate direct references to relevant parameters for adjusting correlation in tooltip text + # TODO interpolate relevant constants (that are currently hardcoded) in tooltip text ToolTipText='The built-in power plant cost correlations are based on the original correlations developed ' 'by Beckers (2016), indexed to 2017 using the IHS Markit North American Power Capital Costs ' 'Index (NAPCCI) excluding nuclear plants (IHS 2018). The ORC power plant cost data have been ' 'updated with data from the 2016 GETEM tool (DOE 2016) and the geothermal binary power plants ' # 'study by Verkís (2014). ' 'study by Verkis (2014). ' # unicode accented i may cause unexpected problems in consumers... - # TODO incorporate reference to figure (commented out for now) - # 'Figure 4 shows the power plant capital cost expressed in $ kWe−1 as a function of plant - # size and initial production temperature for subcritical ORC and double-flash power plants. ' - # TODO use tooltip var - 'The correlations in GEOPHIRES include 12% for indirect costs and 15% contingency. ' + 'Figure 4 in the Theoretical Basis shows the power plant capital cost expressed in $ kWe−1 ' + 'as a function of plant size and initial production temperature for subcritical ORC and ' + 'double-flash power plants. ' + f'The default correlations in GEOPHIRES include {contingency_and_indirect_costs_tooltip_stem}. ' 'For the same plant size and production temperature, double-flash power plants are considered ' 'about 25% more expensive than single-flash power plants (Zeyghami 2010), and supercritical ' 'ORC plants are roughly 10% more than subcritical ORC plants (Astolfi et al. 2014). A wide ' @@ -1943,7 +1948,6 @@ def __init__(self, model: Model): 'However, users are encouraged to provide their own cost figures for ' 'their specific application. Beckers and Young (2017) collected several cost figures to ' 'estimate the surface equipment cost for geothermal district-heating systems.' - # TODO incorporate direct references to relevant parameters for adjusting correlation ) self.Coamplant = self.OutputParameterDict[self.Coamplant.Name] = OutputParameter( Name="O&M Surface Plant costs", @@ -1951,8 +1955,8 @@ def __init__(self, model: Model): UnitType=Units.CURRENCYFREQUENCY, PreferredUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR, CurrentUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR, - # TODO parameterize relevant constants - # TODO update index year and/or make indexing parameterizable + # TODO parameterize relevant constants in tooltip text + # TODO update index year and/or make indexing parameterizable in tooltip text ToolTipText='GEOPHIRES estimates the annual surface plant O&M costs as the sum of 1.5% of the total plant ' 'capital cost (for annual non-labor costs), and 75% of the annual labor costs. The other 25% ' 'of the labor costs are assigned to the wellfield O&M cost. The labor costs are calculated ' @@ -1969,7 +1973,7 @@ def __init__(self, model: Model): UnitType=Units.CURRENCY, PreferredUnits=CurrencyUnit.MDOLLARS, CurrentUnits=CurrencyUnit.MDOLLARS, - # TODO interpolate constant values in tooltip text instead of hardcoding + # TODO interpolate constant values in tooltip text instead of hardcoding in tooltip text ToolTipText='The built-in cost correlation for estimating the field gathering system cost includes ' 'the cost for surface piping from each well to the plant and pumps for production and ' 'injection wells. The length of the surface piping is assumed 750 m per well at a cost of ' diff --git a/src/geophires_x_schema_generator/geophires-result.json b/src/geophires_x_schema_generator/geophires-result.json index 1e334ed1..0ce0ced4 100644 --- a/src/geophires_x_schema_generator/geophires-result.json +++ b/src/geophires_x_schema_generator/geophires-result.json @@ -410,7 +410,7 @@ "Stimulation costs (for redrilling)": {}, "Surface power plant costs": { "type": "number", - "description": "Surface Plant cost. The built-in power plant cost correlations are based on the original correlations developed by Beckers (2016), indexed to 2017 using the IHS Markit North American Power Capital Costs Index (NAPCCI) excluding nuclear plants (IHS 2018). The ORC power plant cost data have been updated with data from the 2016 GETEM tool (DOE 2016) and the geothermal binary power plants study by Verkis (2014). The correlations in GEOPHIRES include 12% for indirect costs and 15% contingency. For the same plant size and production temperature, double-flash power plants are considered about 25% more expensive than single-flash power plants (Zeyghami 2010), and supercritical ORC plants are roughly 10% more than subcritical ORC plants (Astolfi et al. 2014). A wide range in power plant specific cost values is reported in academic and popular literature. The GEOPHIRES built-in surface plant cost correlations represent typical values. However, the user is recommended to provide their own power plant cost data if available for their case study. The ORC plant specific cost decreases only moderately at higher temperatures. The reasons are that when increasing the temperature, the ORC plant design also changes: (1) a different organic fluid is selected, (2) piping, pump, heat exchangers, and other equipment are designed to handle the higher temperature (and potentially also pressure), requiring thicker walls, potentially different materials, etc., and (3) additional components may be implemented, such as a heat recuperator, making the design and operation more complex. Unlike flash power plants, ORC plants are a small, niche market, typically case specific, and rely on relatively young technology, which has not been subject yet to decades of technological advancement. The cost for direct-use heat applications is highly dependent on the type of application. A generic cost of $250 kWth\u22121 is assumed plus 15% contingency plus 12% indirect costs. However, users are encouraged to provide their own cost figures for their specific application. Beckers and Young (2017) collected several cost figures to estimate the surface equipment cost for geothermal district-heating systems.", + "description": "Surface Plant cost. The built-in power plant cost correlations are based on the original correlations developed by Beckers (2016), indexed to 2017 using the IHS Markit North American Power Capital Costs Index (NAPCCI) excluding nuclear plants (IHS 2018). The ORC power plant cost data have been updated with data from the 2016 GETEM tool (DOE 2016) and the geothermal binary power plants study by Verkis (2014). Figure 4 in the Theoretical Basis shows the power plant capital cost expressed in $ kWe\u22121 as a function of plant size and initial production temperature for subcritical ORC and double-flash power plants. The default correlations in GEOPHIRES include 15% contingency plus 12% indirect costs. For the same plant size and production temperature, double-flash power plants are considered about 25% more expensive than single-flash power plants (Zeyghami 2010), and supercritical ORC plants are roughly 10% more than subcritical ORC plants (Astolfi et al. 2014). A wide range in power plant specific cost values is reported in academic and popular literature. The GEOPHIRES built-in surface plant cost correlations represent typical values. However, the user is recommended to provide their own power plant cost data if available for their case study. The ORC plant specific cost decreases only moderately at higher temperatures. The reasons are that when increasing the temperature, the ORC plant design also changes: (1) a different organic fluid is selected, (2) piping, pump, heat exchangers, and other equipment are designed to handle the higher temperature (and potentially also pressure), requiring thicker walls, potentially different materials, etc., and (3) additional components may be implemented, such as a heat recuperator, making the design and operation more complex. Unlike flash power plants, ORC plants are a small, niche market, typically case specific, and rely on relatively young technology, which has not been subject yet to decades of technological advancement. The cost for direct-use heat applications is highly dependent on the type of application. A generic cost of $250 kWth\u22121 is assumed plus 15% contingency plus 12% indirect costs. However, users are encouraged to provide their own cost figures for their specific application. Beckers and Young (2017) collected several cost figures to estimate the surface equipment cost for geothermal district-heating systems.", "units": "MUSD" }, "of which Absorption Chiller Cost": {}, From c207c1819b1db8b8a0b3285c926d92a449b878ab Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Wed, 8 Oct 2025 08:27:22 -0700 Subject: [PATCH 15/21] Set Total O&M Cost (Coam) tooltip text from theoretical basis --- src/geophires_x/Economics.py | 4 +++- src/geophires_x_schema_generator/geophires-result.json | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index 47cb1500..63421c4d 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -2020,7 +2020,9 @@ def __init__(self, model: Model): display_name='Total operating and maintenance costs', UnitType=Units.CURRENCYFREQUENCY, PreferredUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR, - CurrentUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR + CurrentUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR, + ToolTipText=f'GEOPHIRES estimates the annual O&M costs as the sum of the annual surface plant, wellfield, ' + f'make-up water, and pumping O&M costs.' ) self.averageannualpumpingcosts = OutputParameter( Name="Average Annual Pumping Costs", diff --git a/src/geophires_x_schema_generator/geophires-result.json b/src/geophires_x_schema_generator/geophires-result.json index 0ce0ced4..5e0710fa 100644 --- a/src/geophires_x_schema_generator/geophires-result.json +++ b/src/geophires_x_schema_generator/geophires-result.json @@ -523,7 +523,7 @@ "Total average annual O&M costs": {}, "Total operating and maintenance costs": { "type": "number", - "description": "Total O&M Cost", + "description": "Total O&M Cost. GEOPHIRES estimates the annual O&M costs as the sum of the annual surface plant, wellfield, make-up water, and pumping O&M costs.", "units": "MUSD/yr" }, "OPEX": {} From 66317b48647395ecb6147edae1eb16bba87192c3 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Wed, 8 Oct 2025 08:41:37 -0700 Subject: [PATCH 16/21] =?UTF-8?q?Bump=20version:=203.9.62=20=E2=86=92=203.?= =?UTF-8?q?9.63?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- .cookiecutterrc | 2 +- README.rst | 4 ++-- docs/conf.py | 2 +- setup.py | 2 +- src/geophires_x/__init__.py | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index a2b1fef8..d4dc5695 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 3.9.62 +current_version = 3.9.63 commit = True tag = True diff --git a/.cookiecutterrc b/.cookiecutterrc index c5496a36..36c834e9 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.9.62 + version: 3.9.63 version_manager: "bump2version" website: "https://github.com/NREL" year_from: "2023" diff --git a/README.rst b/README.rst index 0048e314..7c8d1d25 100644 --- a/README.rst +++ b/README.rst @@ -58,9 +58,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.9.62.svg +.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.9.63.svg :alt: Commits since latest release - :target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.9.62...main + :target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.9.63...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 97ecace7..ea5b803f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -18,7 +18,7 @@ year = '2025' author = 'NREL' copyright = f'{year}, {author}' -version = release = '3.9.62' +version = release = '3.9.63' pygments_style = 'trac' templates_path = ['./templates'] diff --git a/setup.py b/setup.py index 83bc6cdd..061eafb4 100755 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ def read(*names, **kwargs): setup( name='geophires-x', - version='3.9.62', + version='3.9.63', license='MIT', description='GEOPHIRES is a free and open-source geothermal techno-economic simulator.', long_description='{}\n{}'.format( diff --git a/src/geophires_x/__init__.py b/src/geophires_x/__init__.py index 9524b5d4..bc2f5df5 100644 --- a/src/geophires_x/__init__.py +++ b/src/geophires_x/__init__.py @@ -1 +1 @@ -__version__ = '3.9.62' +__version__ = '3.9.63' From 40f11484b45a1fe8f9b0c6b5e90d447cc60f02e2 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Wed, 8 Oct 2025 08:50:35 -0700 Subject: [PATCH 17/21] Fix non-standard unicode minus sign (causes apparent issues in windows such as in https://github.com/softwareengineerprogrammer/GEOPHIRES/actions/runs/18349590806/job/52265586432) --- src/geophires_x/Economics.py | 9 +++++---- src/geophires_x_schema_generator/geophires-result.json | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index 63421c4d..8a2cd185 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -1922,9 +1922,10 @@ def __init__(self, model: Model): 'by Beckers (2016), indexed to 2017 using the IHS Markit North American Power Capital Costs ' 'Index (NAPCCI) excluding nuclear plants (IHS 2018). The ORC power plant cost data have been ' 'updated with data from the 2016 GETEM tool (DOE 2016) and the geothermal binary power plants ' - # 'study by Verkís (2014). ' - 'study by Verkis (2014). ' # unicode accented i may cause unexpected problems in consumers... - 'Figure 4 in the Theoretical Basis shows the power plant capital cost expressed in $ kWe−1 ' + 'study by Verkis (2014). ' + # Note: actual author name above is "Verkís" but the unicode accented i may cause unexpected + # problems in consumers. + 'Figure 4 in the Theoretical Basis shows the power plant capital cost expressed in $ kWe-1 ' 'as a function of plant size and initial production temperature for subcritical ORC and ' 'double-flash power plants. ' f'The default correlations in GEOPHIRES include {contingency_and_indirect_costs_tooltip_stem}. ' @@ -1943,7 +1944,7 @@ def __init__(self, model: Model): 'Unlike flash power plants, ORC plants are a small, niche market, typically case specific, ' 'and rely on relatively young technology, which has not been subject yet to decades of ' 'technological advancement. The cost for direct-use heat applications is highly dependent ' - 'on the type of application. A generic cost of $250 kWth−1 is assumed ' + 'on the type of application. A generic cost of $250 kWth-1 is assumed ' f'{contingency_and_indirect_costs_tooltip}. ' 'However, users are encouraged to provide their own cost figures for ' 'their specific application. Beckers and Young (2017) collected several cost figures to ' diff --git a/src/geophires_x_schema_generator/geophires-result.json b/src/geophires_x_schema_generator/geophires-result.json index 5e0710fa..d14644b6 100644 --- a/src/geophires_x_schema_generator/geophires-result.json +++ b/src/geophires_x_schema_generator/geophires-result.json @@ -410,7 +410,7 @@ "Stimulation costs (for redrilling)": {}, "Surface power plant costs": { "type": "number", - "description": "Surface Plant cost. The built-in power plant cost correlations are based on the original correlations developed by Beckers (2016), indexed to 2017 using the IHS Markit North American Power Capital Costs Index (NAPCCI) excluding nuclear plants (IHS 2018). The ORC power plant cost data have been updated with data from the 2016 GETEM tool (DOE 2016) and the geothermal binary power plants study by Verkis (2014). Figure 4 in the Theoretical Basis shows the power plant capital cost expressed in $ kWe\u22121 as a function of plant size and initial production temperature for subcritical ORC and double-flash power plants. The default correlations in GEOPHIRES include 15% contingency plus 12% indirect costs. For the same plant size and production temperature, double-flash power plants are considered about 25% more expensive than single-flash power plants (Zeyghami 2010), and supercritical ORC plants are roughly 10% more than subcritical ORC plants (Astolfi et al. 2014). A wide range in power plant specific cost values is reported in academic and popular literature. The GEOPHIRES built-in surface plant cost correlations represent typical values. However, the user is recommended to provide their own power plant cost data if available for their case study. The ORC plant specific cost decreases only moderately at higher temperatures. The reasons are that when increasing the temperature, the ORC plant design also changes: (1) a different organic fluid is selected, (2) piping, pump, heat exchangers, and other equipment are designed to handle the higher temperature (and potentially also pressure), requiring thicker walls, potentially different materials, etc., and (3) additional components may be implemented, such as a heat recuperator, making the design and operation more complex. Unlike flash power plants, ORC plants are a small, niche market, typically case specific, and rely on relatively young technology, which has not been subject yet to decades of technological advancement. The cost for direct-use heat applications is highly dependent on the type of application. A generic cost of $250 kWth\u22121 is assumed plus 15% contingency plus 12% indirect costs. However, users are encouraged to provide their own cost figures for their specific application. Beckers and Young (2017) collected several cost figures to estimate the surface equipment cost for geothermal district-heating systems.", + "description": "Surface Plant cost. The built-in power plant cost correlations are based on the original correlations developed by Beckers (2016), indexed to 2017 using the IHS Markit North American Power Capital Costs Index (NAPCCI) excluding nuclear plants (IHS 2018). The ORC power plant cost data have been updated with data from the 2016 GETEM tool (DOE 2016) and the geothermal binary power plants study by Verkis (2014). Figure 4 in the Theoretical Basis shows the power plant capital cost expressed in $ kWe-1 as a function of plant size and initial production temperature for subcritical ORC and double-flash power plants. The default correlations in GEOPHIRES include 15% contingency plus 12% indirect costs. For the same plant size and production temperature, double-flash power plants are considered about 25% more expensive than single-flash power plants (Zeyghami 2010), and supercritical ORC plants are roughly 10% more than subcritical ORC plants (Astolfi et al. 2014). A wide range in power plant specific cost values is reported in academic and popular literature. The GEOPHIRES built-in surface plant cost correlations represent typical values. However, the user is recommended to provide their own power plant cost data if available for their case study. The ORC plant specific cost decreases only moderately at higher temperatures. The reasons are that when increasing the temperature, the ORC plant design also changes: (1) a different organic fluid is selected, (2) piping, pump, heat exchangers, and other equipment are designed to handle the higher temperature (and potentially also pressure), requiring thicker walls, potentially different materials, etc., and (3) additional components may be implemented, such as a heat recuperator, making the design and operation more complex. Unlike flash power plants, ORC plants are a small, niche market, typically case specific, and rely on relatively young technology, which has not been subject yet to decades of technological advancement. The cost for direct-use heat applications is highly dependent on the type of application. A generic cost of $250 kWth-1 is assumed plus 15% contingency plus 12% indirect costs. However, users are encouraged to provide their own cost figures for their specific application. Beckers and Young (2017) collected several cost figures to estimate the surface equipment cost for geothermal district-heating systems.", "units": "MUSD" }, "of which Absorption Chiller Cost": {}, From e17084ed18e7a8947b5ef7c21591ccf5d04ba188 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Wed, 8 Oct 2025 08:57:57 -0700 Subject: [PATCH 18/21] use print([...], file=f) in schema generator to avoid need for precommit end of file fix on regeneration --- src/geophires_x_schema_generator/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/geophires_x_schema_generator/main.py b/src/geophires_x_schema_generator/main.py index 7eacc944..e7e813dc 100644 --- a/src/geophires_x_schema_generator/main.py +++ b/src/geophires_x_schema_generator/main.py @@ -23,13 +23,13 @@ def build(json_file_name_prefix: str, generator: GeophiresXSchemaGenerator, rst_ request_build_path = Path(build_dir, f'{json_file_name_prefix}request.json') with open(request_build_path, 'w') as f: - f.write(json.dumps(request_schema_json, indent=2)) + print(json.dumps(request_schema_json, indent=2), file=f) print(f'Wrote request JSON schema file to {request_build_path}.') if result_schema_json is not None: result_build_path = Path(build_dir, f'{json_file_name_prefix}result.json') with open(result_build_path, 'w') as f: - f.write(json.dumps(result_schema_json, indent=2)) + print(json.dumps(result_schema_json, indent=2), file=f) print(f'Wrote result JSON schema file to {result_build_path}.') rst = generator.generate_parameters_reference_rst() From 7f7830c4c51c99ab36552763c765aa03b2fc5629 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:00:37 -0700 Subject: [PATCH 19/21] specify utf-8 encoding in schema generator --- src/geophires_x_schema_generator/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/geophires_x_schema_generator/main.py b/src/geophires_x_schema_generator/main.py index e7e813dc..52f18446 100644 --- a/src/geophires_x_schema_generator/main.py +++ b/src/geophires_x_schema_generator/main.py @@ -22,13 +22,13 @@ def build(json_file_name_prefix: str, generator: GeophiresXSchemaGenerator, rst_ request_schema_json, result_schema_json = generator.generate_json_schema() request_build_path = Path(build_dir, f'{json_file_name_prefix}request.json') - with open(request_build_path, 'w') as f: + with open(request_build_path, 'w', encoding='utf-8') as f: print(json.dumps(request_schema_json, indent=2), file=f) print(f'Wrote request JSON schema file to {request_build_path}.') if result_schema_json is not None: result_build_path = Path(build_dir, f'{json_file_name_prefix}result.json') - with open(result_build_path, 'w') as f: + with open(result_build_path, 'w', encoding='utf-8') as f: print(json.dumps(result_schema_json, indent=2), file=f) print(f'Wrote result JSON schema file to {result_build_path}.') From 0b738d37a5342f657c709eac50140f6597b91480 Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:02:37 -0700 Subject: [PATCH 20/21] document use of print instead of f.write in schema generator comment --- src/geophires_x_schema_generator/main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/geophires_x_schema_generator/main.py b/src/geophires_x_schema_generator/main.py index 52f18446..fe7b1fee 100644 --- a/src/geophires_x_schema_generator/main.py +++ b/src/geophires_x_schema_generator/main.py @@ -23,7 +23,10 @@ def build(json_file_name_prefix: str, generator: GeophiresXSchemaGenerator, rst_ request_build_path = Path(build_dir, f'{json_file_name_prefix}request.json') with open(request_build_path, 'w', encoding='utf-8') as f: + print(json.dumps(request_schema_json, indent=2), file=f) + # using print([...], file=f) instead of f.write avoids need for pre-commit end of file fix + print(f'Wrote request JSON schema file to {request_build_path}.') if result_schema_json is not None: From 2b51fa05f0a39dd0f4072d9071ead8a67b2c74ae Mon Sep 17 00:00:00 2001 From: softwareengineerprogrammer <4056124+softwareengineerprogrammer@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:09:28 -0700 Subject: [PATCH 21/21] =?UTF-8?q?Bump=20version:=203.9.63=20=E2=86=92=203.?= =?UTF-8?q?9.64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- .cookiecutterrc | 2 +- README.rst | 4 ++-- docs/conf.py | 2 +- setup.py | 2 +- src/geophires_x/__init__.py | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index d4dc5695..f72d3bd0 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 3.9.63 +current_version = 3.9.64 commit = True tag = True diff --git a/.cookiecutterrc b/.cookiecutterrc index 36c834e9..d73e0063 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.9.63 + version: 3.9.64 version_manager: "bump2version" website: "https://github.com/NREL" year_from: "2023" diff --git a/README.rst b/README.rst index 7c8d1d25..a198f768 100644 --- a/README.rst +++ b/README.rst @@ -58,9 +58,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.9.63.svg +.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.9.64.svg :alt: Commits since latest release - :target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.9.63...main + :target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.9.64...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 ea5b803f..5d0927f8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -18,7 +18,7 @@ year = '2025' author = 'NREL' copyright = f'{year}, {author}' -version = release = '3.9.63' +version = release = '3.9.64' pygments_style = 'trac' templates_path = ['./templates'] diff --git a/setup.py b/setup.py index 061eafb4..a141852c 100755 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ def read(*names, **kwargs): setup( name='geophires-x', - version='3.9.63', + version='3.9.64', license='MIT', description='GEOPHIRES is a free and open-source geothermal techno-economic simulator.', long_description='{}\n{}'.format( diff --git a/src/geophires_x/__init__.py b/src/geophires_x/__init__.py index bc2f5df5..0d1d652b 100644 --- a/src/geophires_x/__init__.py +++ b/src/geophires_x/__init__.py @@ -1 +1 @@ -__version__ = '3.9.63' +__version__ = '3.9.64'