diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index d7ad098e..b89cb1fa 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import math import sys +# noinspection PyPackageRequirements import numpy as np import numpy_financial as npf from pint.facets.plain import PlainQuantity @@ -349,7 +352,7 @@ def CalculateFinancialPerformance(plantlifetime: int, return NPV, IRR, VIR, MOIC -def CalculateLCOELCOHLCOC(econ, model: Model) -> tuple: +def CalculateLCOELCOHLCOC(econ, model: Model) -> tuple[float, float, float]: """ CalculateLCOELCOH calculates the levelized cost of electricity and heat for the project. :param econ: Economics object @@ -357,21 +360,45 @@ def CalculateLCOELCOHLCOC(econ, model: Model) -> tuple: :param model: The model object :type model: :class:`~geophires_x.Model.Model` :return: LCOE: The levelized cost of electricity and LCOH: The levelized cost of heat and LCOC: The levelized cost of cooling - :rtype: tuple + :rtype: tuple[float, float, float] """ LCOE = LCOH = LCOC = 0.0 CCap_elec = (econ.CCap.value * econ.CAPEX_heat_electricity_plant_ratio.value) Coam_elec = (econ.Coam.value * econ.CAPEX_heat_electricity_plant_ratio.value) CCap_heat = (econ.CCap.value * (1.0 - econ.CAPEX_heat_electricity_plant_ratio.value)) Coam_heat = (econ.Coam.value * (1.0 - econ.CAPEX_heat_electricity_plant_ratio.value)) + + def _capex_total_plus_construction_inflation() -> float: + # TODO should be return value instead of mutating econ + econ.inflation_cost_during_construction.value = quantity( + econ.CCap.value * econ.inflrateconstruction.value, + econ.CCap.CurrentUnits + ).to(econ.inflation_cost_during_construction.CurrentUnits).magnitude + + return econ.CCap.value + econ.inflation_cost_during_construction.value + + def _construction_inflation_cost_elec_heat() -> tuple[float, float]: + construction_inflation_cost_elec = CCap_elec * econ.inflrateconstruction.value + construction_inflation_cost_heat = CCap_heat * econ.inflrateconstruction.value + + # TODO should be return value instead of mutating econ + econ.inflation_cost_during_construction.value = quantity( + construction_inflation_cost_elec+ construction_inflation_cost_heat, + econ.CCap.CurrentUnits + ).to(econ.inflation_cost_during_construction.CurrentUnits).magnitude + + return CCap_elec + construction_inflation_cost_elec, CCap_heat + construction_inflation_cost_heat + # Calculate LCOE/LCOH/LCOC if econ.econmodel.value == EconomicModel.FCR: + capex_total_plus_infl = _capex_total_plus_construction_inflation() + if model.surfaceplant.enduse_option.value == EndUseOptions.ELECTRICITY: - LCOE = (econ.FCR.value * (1 + econ.inflrateconstruction.value) * econ.CCap.value + econ.Coam.value) / \ + LCOE = (econ.FCR.value * capex_total_plus_infl + econ.Coam.value) / \ np.average(model.surfaceplant.NetkWhProduced.value) * 1E8 # cents/kWh elif (model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value not in [PlantType.ABSORPTION_CHILLER, PlantType.HEAT_PUMP, PlantType.DISTRICT_HEATING]): - LCOH = (econ.FCR.value * (1 + econ.inflrateconstruction.value) * econ.CCap.value + econ.Coam.value + + LCOH = (econ.FCR.value * capex_total_plus_infl + econ.Coam.value + econ.averageannualpumpingcosts.value) / np.average( model.surfaceplant.HeatkWhProduced.value) * 1E8 # cents/kWh LCOH = LCOH * 2.931 # $/Million Btu @@ -382,38 +409,40 @@ def CalculateLCOELCOHLCOC(econ, model: Model) -> tuple: EndUseOptions.COGENERATION_BOTTOMING_EXTRA_HEAT, EndUseOptions.COGENERATION_PARALLEL_EXTRA_HEAT, EndUseOptions.COGENERATION_PARALLEL_EXTRA_ELECTRICITY]: - LCOE = (econ.FCR.value * (1 + econ.inflrateconstruction.value) * CCap_elec + Coam_elec) / np.average(model.surfaceplant.NetkWhProduced.value) * 1E8 # cents/kWh - LCOH = (econ.FCR.value * (1 + econ.inflrateconstruction.value) * CCap_heat + Coam_heat + econ.averageannualpumpingcosts.value) / np.average(model.surfaceplant.HeatkWhProduced.value) * 1E8 # cents/kWh + capex_elec_plus_infl, capex_heat_plus_infl = _construction_inflation_cost_elec_heat() + LCOE = (econ.FCR.value * capex_elec_plus_infl + Coam_elec) / np.average(model.surfaceplant.NetkWhProduced.value) * 1E8 # cents/kWh + LCOH = (econ.FCR.value * capex_heat_plus_infl + Coam_heat + econ.averageannualpumpingcosts.value) / np.average(model.surfaceplant.HeatkWhProduced.value) * 1E8 # cents/kWh LCOH = LCOH * 2.931 # $/Million Btu elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: - LCOC = (econ.FCR.value * ( - 1 + econ.inflrateconstruction.value) * econ.CCap.value + econ.Coam.value + econ.averageannualpumpingcosts.value) / np.average( + LCOC = (econ.FCR.value * capex_total_plus_infl + econ.Coam.value + econ.averageannualpumpingcosts.value) / np.average( model.surfaceplant.cooling_kWh_Produced.value) * 1E8 # cents/kWh LCOC = LCOC * 2.931 # $/Million Btu elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value == PlantType.HEAT_PUMP: - LCOH = (econ.FCR.value * ( - 1 + econ.inflrateconstruction.value) * econ.CCap.value + econ.Coam.value + econ.averageannualpumpingcosts.value + econ.averageannualheatpumpelectricitycost.value) / np.average( + LCOH = (econ.FCR.value * capex_total_plus_infl + + econ.Coam.value + econ.averageannualpumpingcosts.value + econ.averageannualheatpumpelectricitycost.value) / np.average( model.surfaceplant.HeatkWhProduced.value) * 1E8 # cents/kWh LCOH = LCOH * 2.931 # $/Million Btu elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING: - LCOH = (econ.FCR.value * ( - 1 + econ.inflrateconstruction.value) * econ.CCap.value + econ.Coam.value + econ.averageannualpumpingcosts.value + econ.averageannualngcost.value) / model.surfaceplant.annual_heating_demand.value * 1E2 # cents/kWh + LCOH = (econ.FCR.value * capex_total_plus_infl + + econ.Coam.value + econ.averageannualpumpingcosts.value + econ.averageannualngcost.value) / model.surfaceplant.annual_heating_demand.value * 1E2 # cents/kWh LCOH = LCOH * 2.931 # $/Million Btu elif econ.econmodel.value == EconomicModel.STANDARDIZED_LEVELIZED_COST: discount_vector = 1. / np.power(1 + econ.discountrate.value, np.linspace(0, model.surfaceplant.plant_lifetime.value - 1, model.surfaceplant.plant_lifetime.value)) + capex_total_plus_infl = _capex_total_plus_construction_inflation() + if model.surfaceplant.enduse_option.value == EndUseOptions.ELECTRICITY: - LCOE = ((1 + econ.inflrateconstruction.value) * econ.CCap.value + np.sum( + LCOE = (capex_total_plus_infl + np.sum( econ.Coam.value * discount_vector)) / np.sum( model.surfaceplant.NetkWhProduced.value * discount_vector) * 1E8 # cents/kWh elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and \ model.surfaceplant.plant_type.value not in [PlantType.ABSORPTION_CHILLER, PlantType.HEAT_PUMP, PlantType.DISTRICT_HEATING]: econ.averageannualpumpingcosts.value = np.average( model.surfaceplant.PumpingkWh.value) * model.surfaceplant.electricity_cost_to_buy.value / 1E6 # M$/year - LCOH = ((1 + econ.inflrateconstruction.value) * econ.CCap.value + np.sum(( - econ.Coam.value + model.surfaceplant.PumpingkWh.value * model.surfaceplant.electricity_cost_to_buy.value / 1E6) * discount_vector)) / np.sum( + LCOH = (capex_total_plus_infl + np.sum(( + econ.Coam.value + model.surfaceplant.PumpingkWh.value * model.surfaceplant.electricity_cost_to_buy.value / 1E6) * discount_vector)) / np.sum( model.surfaceplant.HeatkWhProduced.value * discount_vector) * 1E8 # cents/kWh LCOH = LCOH * 2.931 # $/MMBTU @@ -424,24 +453,30 @@ def CalculateLCOELCOHLCOC(econ, model: Model) -> tuple: EndUseOptions.COGENERATION_BOTTOMING_EXTRA_HEAT, EndUseOptions.COGENERATION_PARALLEL_EXTRA_HEAT, EndUseOptions.COGENERATION_PARALLEL_EXTRA_ELECTRICITY]: - LCOE = ((1 + econ.inflrateconstruction.value) * CCap_elec + np.sum(Coam_elec * discount_vector)) / np.sum(model.surfaceplant.NetkWhProduced.value * discount_vector) * 1E8 # cents/kWh - LCOH = ((1 + econ.inflrateconstruction.value) * CCap_heat + + capex_elec_plus_infl, capex_heat_plus_infl = _construction_inflation_cost_elec_heat() + + LCOE = (capex_elec_plus_infl + np.sum(Coam_elec * discount_vector)) / np.sum(model.surfaceplant.NetkWhProduced.value * discount_vector) * 1E8 # cents/kWh + LCOH = (capex_heat_plus_infl + np.sum((Coam_heat + model.surfaceplant.PumpingkWh.value * model.surfaceplant.electricity_cost_to_buy.value / 1E6) * discount_vector)) / np.sum(model.surfaceplant.HeatkWhProduced.value * discount_vector) * 1E8 # cents/kWh LCOH = LCOH * 2.931 # $/MMBTU elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: - LCOC = ((1 + econ.inflrateconstruction.value) * econ.CCap.value + np.sum(( - econ.Coam.value + model.surfaceplant.PumpingkWh.value * model.surfaceplant.electricity_cost_to_buy.value / 1E6) * discount_vector)) / np.sum( + capex_total_plus_infl = _capex_total_plus_construction_inflation() + + LCOC = (capex_total_plus_infl + np.sum(( + econ.Coam.value + model.surfaceplant.PumpingkWh.value * model.surfaceplant.electricity_cost_to_buy.value / 1E6) * discount_vector)) / np.sum( model.surfaceplant.cooling_kWh_Produced.value * discount_vector) * 1E8 # cents/kWh LCOC = LCOC * 2.931 # $/Million Btu elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value == PlantType.HEAT_PUMP: - LCOH = ((1 + econ.inflrateconstruction.value) * econ.CCap.value + np.sum( + capex_total_plus_infl = _capex_total_plus_construction_inflation() + LCOH = (capex_total_plus_infl + np.sum( (econ.Coam.value + model.surfaceplant.PumpingkWh.value * model.surfaceplant.electricity_cost_to_buy.value / 1E6 + model.surfaceplant.heat_pump_electricity_kwh_used.value * model.surfaceplant.electricity_cost_to_buy.value / 1E6) * discount_vector)) / np.sum( model.surfaceplant.HeatkWhProduced.value * discount_vector) * 1E8 # cents/kWh LCOH = LCOH * 2.931 # $/Million Btu elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING: - LCOH = ((1 + econ.inflrateconstruction.value) * econ.CCap.value + np.sum( + capex_total_plus_infl = _capex_total_plus_construction_inflation() + LCOH = (capex_total_plus_infl + np.sum( (econ.Coam.value + model.surfaceplant.PumpingkWh.value * model.surfaceplant.electricity_cost_to_buy.value / 1E6 + econ.annualngcost.value) * discount_vector)) / np.sum( model.surfaceplant.annual_heating_demand.value * discount_vector) * 1E2 # cents/kWh @@ -457,10 +492,12 @@ def CalculateLCOELCOHLCOC(econ, model: Model) -> tuple: CRF = i_ave / (1 - np.power(1 + i_ave, -model.surfaceplant.plant_lifetime.value)) inflation_vector = np.power(1 + econ.RINFL.value, np.linspace(1, model.surfaceplant.plant_lifetime.value, model.surfaceplant.plant_lifetime.value)) discount_vector = 1. / np.power(1 + i_ave, np.linspace(1, model.surfaceplant.plant_lifetime.value, model.surfaceplant.plant_lifetime.value)) - NPV_cap = np.sum((1 + econ.inflrateconstruction.value) * econ.CCap.value * CRF * discount_vector) - NPV_fc = np.sum((1 + econ.inflrateconstruction.value) * econ.CCap.value * econ.PTR.value * inflation_vector * discount_vector) - NPV_it = np.sum(econ.CTR.value / (1 - econ.CTR.value) * ((1 + econ.inflrateconstruction.value) * econ.CCap.value * CRF - econ.CCap.value / model.surfaceplant.plant_lifetime.value) * discount_vector) - NPV_itc = (1 + econ.inflrateconstruction.value) * econ.CCap.value * econ.RITC.value / (1 - econ.CTR.value) + capex_total_plus_infl = _capex_total_plus_construction_inflation() + + NPV_cap = np.sum(capex_total_plus_infl * CRF * discount_vector) + NPV_fc = np.sum(capex_total_plus_infl * econ.PTR.value * inflation_vector * discount_vector) + NPV_it = np.sum(econ.CTR.value / (1 - econ.CTR.value) * (capex_total_plus_infl * CRF - econ.CCap.value / model.surfaceplant.plant_lifetime.value) * discount_vector) + NPV_itc = capex_total_plus_infl * econ.RITC.value / (1 - econ.CTR.value) if model.surfaceplant.enduse_option.value == EndUseOptions.ELECTRICITY: NPV_oandm = np.sum(econ.Coam.value * inflation_vector * discount_vector) @@ -479,21 +516,22 @@ def CalculateLCOELCOHLCOC(econ, model: Model) -> tuple: EndUseOptions.COGENERATION_BOTTOMING_EXTRA_HEAT, EndUseOptions.COGENERATION_PARALLEL_EXTRA_HEAT, EndUseOptions.COGENERATION_PARALLEL_EXTRA_ELECTRICITY]: + capex_elec_plus_infl, capex_heat_plus_infl = _construction_inflation_cost_elec_heat() - NPVcap_elec = np.sum((1 + econ.inflrateconstruction.value) * CCap_elec * CRF * discount_vector) - NPVfc_elec = np.sum((1 + econ.inflrateconstruction.value) * CCap_elec * econ.PTR.value * inflation_vector * discount_vector) - NPVit_elec = np.sum(econ.CTR.value / (1 - econ.CTR.value) * ((1 + econ.inflrateconstruction.value) * CCap_elec * CRF - CCap_elec / model.surfaceplant.plant_lifetime.value) * discount_vector) - NPVitc_elec = (1 + econ.inflrateconstruction.value) * CCap_elec * econ.RITC.value / (1 - econ.CTR.value) + NPVcap_elec = np.sum(capex_elec_plus_infl * CRF * discount_vector) + NPVfc_elec = np.sum(capex_elec_plus_infl * econ.PTR.value * inflation_vector * discount_vector) + NPVit_elec = np.sum(econ.CTR.value / (1 - econ.CTR.value) * (capex_elec_plus_infl * CRF - CCap_elec / model.surfaceplant.plant_lifetime.value) * discount_vector) + NPVitc_elec = capex_elec_plus_infl * econ.RITC.value / (1 - econ.CTR.value) NPVoandm_elec = np.sum(Coam_elec * inflation_vector * discount_vector) NPVgrt_elec = econ.GTR.value / (1 - econ.GTR.value) * (NPVcap_elec + NPVoandm_elec + NPVfc_elec + NPVit_elec - NPVitc_elec) LCOE = ((NPVcap_elec + NPVoandm_elec + NPVfc_elec + NPVit_elec + NPVgrt_elec - NPVitc_elec) / np.sum(model.surfaceplant.NetkWhProduced.value * inflation_vector * discount_vector) * 1E8) - NPV_cap_heat = np.sum((1 + econ.inflrateconstruction.value) * CCap_heat * CRF * discount_vector) + NPV_cap_heat = np.sum(capex_heat_plus_infl * CRF * discount_vector) NPV_fc_heat = np.sum((1 + econ.inflrateconstruction.value) * (econ.CCap.value * (1.0 - econ.CAPEX_heat_electricity_plant_ratio.value)) * econ.PTR.value * inflation_vector * discount_vector) - NPV_it_heat = np.sum(econ.CTR.value / (1 - econ.CTR.value) * ((1 + econ.inflrateconstruction.value) * CCap_heat * CRF - CCap_heat / model.surfaceplant.plant_lifetime.value) * discount_vector) - NPV_itc_heat = (1 + econ.inflrateconstruction.value) * CCap_heat * econ.RITC.value / (1 - econ.CTR.value) + NPV_it_heat = np.sum(econ.CTR.value / (1 - econ.CTR.value) * (capex_heat_plus_infl * CRF - CCap_heat / model.surfaceplant.plant_lifetime.value) * discount_vector) + NPV_itc_heat = capex_heat_plus_infl * econ.RITC.value / (1 - econ.CTR.value) NPV_oandm_heat = np.sum((econ.Coam.value * (1.0 - econ.CAPEX_heat_electricity_plant_ratio.value)) * inflation_vector * discount_vector) NPV_grt_heat = econ.GTR.value / (1 - econ.GTR.value) * (NPV_cap_heat + NPV_oandm_heat + NPV_fc_heat + NPV_it_heat - NPV_itc_heat) diff --git a/src/geophires_x/EconomicsUtils.py b/src/geophires_x/EconomicsUtils.py index 71dd8c62..1f586a14 100644 --- a/src/geophires_x/EconomicsUtils.py +++ b/src/geophires_x/EconomicsUtils.py @@ -139,8 +139,8 @@ def total_capex_parameter_output_parameter() -> OutputParameter: UnitType=Units.CURRENCY, CurrentUnits=CurrencyUnit.MDOLLARS, PreferredUnits=CurrencyUnit.MDOLLARS, - ToolTipText="The total capital expenditure (CAPEX) required to construct the plant. " - "This value includes all direct and indirect costs, contingency, and any cost escalation from " - "inflation during construction. It is used as the total installed cost input for " - "SAM Economic Models." + ToolTipText='The total capital expenditure (CAPEX) required to construct the plant. ' + 'This value includes all direct and indirect costs, and contingency. ' + 'For SAM Economic models, it also includes any cost escalation from inflation during construction. ' + 'It is used as the total installed cost input for SAM Economic Models.' ) diff --git a/src/geophires_x/Outputs.py b/src/geophires_x/Outputs.py index dd0b6857..26c082fa 100644 --- a/src/geophires_x/Outputs.py +++ b/src/geophires_x/Outputs.py @@ -274,6 +274,20 @@ def PrintOutputs(self, model: Model): acf_label = Outputs._field_label(acf.display_name, 49) f.write(f' {acf_label}{acf.value:10.2f} {acf.CurrentUnits.value}\n') + display_inflation_costs_in_economic_parameters: bool = ( + econ.econmodel.value in [EconomicModel.BICYCLE, + EconomicModel.FCR, + EconomicModel.STANDARDIZED_LEVELIZED_COST] + and + econ.inflation_cost_during_construction.value != 0. + ) + if display_inflation_costs_in_economic_parameters: + # Inflation cost is displayed here for economic models that don't treat inflation cost as a + # capital cost + icc: OutputParameter = econ.inflation_cost_during_construction + icc_label = Outputs._field_label(icc.display_name, 49) + f.write(f' {icc_label}{icc.value:10.2f} {icc.CurrentUnits.value}\n') + f.write(f' Project lifetime: {model.surfaceplant.plant_lifetime.value:10.0f} {model.surfaceplant.plant_lifetime.CurrentUnits.value}\n') f.write(f' Capacity factor: {model.surfaceplant.utilization_factor.value * 100:10.1f} %\n') @@ -497,8 +511,8 @@ def PrintOutputs(self, model: Model): # expenditure. pass - if is_sam_econ_model: - # TODO calculate & display for other economic models + display_inflation_during_construction_in_capital_costs = is_sam_econ_model + if display_inflation_during_construction_in_capital_costs: icc_label = Outputs._field_label(econ.inflation_cost_during_construction.display_name, 47) f.write(f' {icc_label}{econ.inflation_cost_during_construction.value:10.2f} {econ.inflation_cost_during_construction.CurrentUnits.value}\n') diff --git a/src/geophires_x_client/geophires_x_result.py b/src/geophires_x_client/geophires_x_result.py index c44e3b2f..e2ad9029 100644 --- a/src/geophires_x_client/geophires_x_result.py +++ b/src/geophires_x_client/geophires_x_result.py @@ -79,6 +79,8 @@ class GeophiresXResult: 'Nominal Discount Rate', 'WACC', 'Accrued financing during construction', + # Displayed for economic models that don't treat inflation costs as capital costs (non-SAM-EM) + 'Inflation costs during construction', 'Project lifetime', 'Capacity factor', 'Project NPV', @@ -261,6 +263,7 @@ class GeophiresXResult: 'Total surface equipment costs', 'Exploration costs', 'Investment Tax Credit', + # Displayed for economic models that treat inflation costs as capital costs (SAM-EM) 'Inflation costs during construction', 'Total Add-on CAPEX', 'Total capital costs', diff --git a/src/geophires_x_schema_generator/geophires-result.json b/src/geophires_x_schema_generator/geophires-result.json index 00cab4c7..fa345748 100644 --- a/src/geophires_x_schema_generator/geophires-result.json +++ b/src/geophires_x_schema_generator/geophires-result.json @@ -20,7 +20,7 @@ }, "Total CAPEX": { "type": "number", - "description": "The total capital expenditure (CAPEX) required to construct the plant. This value includes all direct and indirect costs, contingency, and any cost escalation from inflation during construction. It is used as the total installed cost input for SAM Economic Models.", + "description": "The total capital expenditure (CAPEX) required to construct the plant. This value includes all direct and indirect costs, and contingency. For SAM Economic models, it also includes any cost escalation from inflation during construction. It is used as the total installed cost input for SAM Economic Models.", "units": "MUSD" }, "Average Direct-Use Heat Production": {}, @@ -100,6 +100,11 @@ "description": "The accrued inflation on total capital costs over the construction period, as defined by Inflation Rate During Construction. For SAM Economic Models, this is calculated automatically by compounding Inflation Rate over Construction Years if Inflation Rate During Construction is not provided.", "units": "%" }, + "Inflation costs during construction": { + "type": "number", + "description": "The calculated amount of cost escalation due to inflation over the construction period.", + "units": "MUSD" + }, "Project lifetime": {}, "Capacity factor": {}, "Project NPV": { @@ -432,7 +437,7 @@ "Annualized capital costs": {}, "Total CAPEX": { "type": "number", - "description": "The total capital expenditure (CAPEX) required to construct the plant. This value includes all direct and indirect costs, contingency, and any cost escalation from inflation during construction. It is used as the total installed cost input for SAM Economic Models.", + "description": "The total capital expenditure (CAPEX) required to construct the plant. This value includes all direct and indirect costs, and contingency. For SAM Economic models, it also includes any cost escalation from inflation during construction. It is used as the total installed cost input for SAM Economic Models.", "units": "MUSD" }, "Drilling Cost": {}, diff --git a/tests/examples/Fervo_Norbeck_Latimer_2023.out b/tests/examples/Fervo_Norbeck_Latimer_2023.out index f133e97a..f8d443af 100644 --- a/tests/examples/Fervo_Norbeck_Latimer_2023.out +++ b/tests/examples/Fervo_Norbeck_Latimer_2023.out @@ -4,10 +4,10 @@ Simulation Metadata ---------------------- - GEOPHIRES Version: 3.9.28 - Simulation Date: 2025-07-02 - Simulation Time: 12:19 - Calculation Time: 0.481 sec + GEOPHIRES Version: 3.9.47 + Simulation Date: 2025-07-31 + Simulation Time: 08:57 + Calculation Time: 0.475 sec ***SUMMARY OF RESULTS*** @@ -24,7 +24,8 @@ Simulation Metadata ***ECONOMIC PARAMETERS*** Economic Model = BICYCLE - Accrued financing during construction: 5.00 % + Accrued financing during construction: 5.00 % + Inflation costs during construction: 1.41 MUSD Project lifetime: 10 yr Capacity factor: 90.0 % Project NPV: -13.03 MUSD diff --git a/tests/examples/Fervo_Project_Cape-2.out b/tests/examples/Fervo_Project_Cape-2.out index f4debd0d..b58acb30 100644 --- a/tests/examples/Fervo_Project_Cape-2.out +++ b/tests/examples/Fervo_Project_Cape-2.out @@ -4,10 +4,10 @@ Simulation Metadata ---------------------- - GEOPHIRES Version: 3.9.28 - Simulation Date: 2025-07-02 - Simulation Time: 12:19 - Calculation Time: 0.722 sec + GEOPHIRES Version: 3.9.47 + Simulation Date: 2025-07-31 + Simulation Time: 08:57 + Calculation Time: 0.709 sec ***SUMMARY OF RESULTS*** @@ -24,7 +24,8 @@ Simulation Metadata ***ECONOMIC PARAMETERS*** Economic Model = BICYCLE - Accrued financing during construction: 5.00 % + Accrued financing during construction: 5.00 % + Inflation costs during construction: 2.54 MUSD Project lifetime: 15 yr Capacity factor: 90.0 % Project NPV: 42.34 MUSD diff --git a/tests/examples/Fervo_Project_Cape-3.out b/tests/examples/Fervo_Project_Cape-3.out index 93f1c996..1d91ce0e 100644 --- a/tests/examples/Fervo_Project_Cape-3.out +++ b/tests/examples/Fervo_Project_Cape-3.out @@ -4,10 +4,10 @@ Simulation Metadata ---------------------- - GEOPHIRES Version: 3.9.28 - Simulation Date: 2025-07-02 - Simulation Time: 12:19 - Calculation Time: 0.956 sec + GEOPHIRES Version: 3.9.47 + Simulation Date: 2025-07-31 + Simulation Time: 08:57 + Calculation Time: 0.951 sec ***SUMMARY OF RESULTS*** @@ -24,7 +24,8 @@ Simulation Metadata ***ECONOMIC PARAMETERS*** Economic Model = BICYCLE - Accrued financing during construction: 5.00 % + Accrued financing during construction: 5.00 % + Inflation costs during construction: 53.65 MUSD Project lifetime: 20 yr Capacity factor: 90.0 % Project NPV: 4580.36 MUSD diff --git a/tests/examples/Fervo_Project_Cape.out b/tests/examples/Fervo_Project_Cape.out index af4fa2e9..ec3f23f1 100644 --- a/tests/examples/Fervo_Project_Cape.out +++ b/tests/examples/Fervo_Project_Cape.out @@ -4,10 +4,10 @@ Simulation Metadata ---------------------- - GEOPHIRES Version: 3.9.28 - Simulation Date: 2025-07-02 - Simulation Time: 12:19 - Calculation Time: 0.720 sec + GEOPHIRES Version: 3.9.47 + Simulation Date: 2025-07-31 + Simulation Time: 08:57 + Calculation Time: 0.712 sec ***SUMMARY OF RESULTS*** @@ -24,7 +24,8 @@ Simulation Metadata ***ECONOMIC PARAMETERS*** Economic Model = BICYCLE - Accrued financing during construction: 5.00 % + Accrued financing during construction: 5.00 % + Inflation costs during construction: 24.14 MUSD Project lifetime: 15 yr Capacity factor: 90.0 % Project NPV: 520.01 MUSD diff --git a/tests/examples/example10_HP.out b/tests/examples/example10_HP.out index 51991cce..95394cca 100644 --- a/tests/examples/example10_HP.out +++ b/tests/examples/example10_HP.out @@ -4,10 +4,10 @@ Simulation Metadata ---------------------- - GEOPHIRES Version: 3.9.7 - Simulation Date: 2025-05-15 - Simulation Time: 10:13 - Calculation Time: 0.096 sec + GEOPHIRES Version: 3.9.47 + Simulation Date: 2025-07-31 + Simulation Time: 08:57 + Calculation Time: 0.105 sec ***SUMMARY OF RESULTS*** @@ -26,7 +26,8 @@ Simulation Metadata Economic Model = Standard Levelized Cost Interest Rate: 5.00 % - Accrued financing during construction: 5.00 % + Accrued financing during construction: 5.00 % + Inflation costs during construction: 1.39 MUSD Project lifetime: 30 yr Capacity factor: 90.0 % Project NPV: 15.18 MUSD @@ -64,7 +65,7 @@ Simulation Metadata m/A Drawdown Parameter: 0.00002 1/year Bottom-hole temperature: 109.50 degC Reservoir volume calculated with fracture separation and number of fractures as input - Number of fractures: 12.00 + Number of fractures: 12 Fracture separation: 80.00 meter Reservoir volume: 176000000 m**3 Reservoir hydrostatic pressure: 20488.96 kPa diff --git a/tests/examples/example11_AC.out b/tests/examples/example11_AC.out index 5cff8880..cb655659 100644 --- a/tests/examples/example11_AC.out +++ b/tests/examples/example11_AC.out @@ -4,10 +4,10 @@ Simulation Metadata ---------------------- - GEOPHIRES Version: 3.9.7 - Simulation Date: 2025-05-15 - Simulation Time: 10:13 - Calculation Time: 0.096 sec + GEOPHIRES Version: 3.9.47 + Simulation Date: 2025-07-31 + Simulation Time: 08:57 + Calculation Time: 0.107 sec ***SUMMARY OF RESULTS*** @@ -27,7 +27,8 @@ Simulation Metadata Economic Model = Standard Levelized Cost Interest Rate: 5.00 % - Accrued financing during construction: 5.00 % + Accrued financing during construction: 5.00 % + Inflation costs during construction: 1.32 MUSD Project lifetime: 30 yr Capacity factor: 90.0 % Project NPV: 10.11 MUSD @@ -65,7 +66,7 @@ Simulation Metadata m/A Drawdown Parameter: 0.00002 1/year Bottom-hole temperature: 109.50 degC Reservoir volume calculated with fracture separation and number of fractures as input - Number of fractures: 12.00 + Number of fractures: 12 Fracture separation: 80.00 meter Reservoir volume: 176000000 m**3 Reservoir hydrostatic pressure: 20488.96 kPa diff --git a/tests/examples/example13.out b/tests/examples/example13.out index 006909f4..7b881308 100644 --- a/tests/examples/example13.out +++ b/tests/examples/example13.out @@ -4,10 +4,10 @@ Simulation Metadata ---------------------- - GEOPHIRES Version: 3.9.36 - Simulation Date: 2025-07-25 - Simulation Time: 11:30 - Calculation Time: 0.037 sec + GEOPHIRES Version: 3.9.47 + Simulation Date: 2025-07-31 + Simulation Time: 08:44 + Calculation Time: 0.036 sec ***SUMMARY OF RESULTS*** @@ -27,7 +27,7 @@ Simulation Metadata Economic Model = Standard Levelized Cost Interest Rate: 5.00 % - Accrued financing during construction: 0.00 % + Accrued financing during construction: 0.00 % Project lifetime: 30 yr Capacity factor: 80.0 % Project NPV: -31.42 MUSD diff --git a/tests/examples/example3.out b/tests/examples/example3.out index 01516178..9d4c402a 100644 --- a/tests/examples/example3.out +++ b/tests/examples/example3.out @@ -4,10 +4,10 @@ Simulation Metadata ---------------------- - GEOPHIRES Version: 3.9.7 - Simulation Date: 2025-05-15 - Simulation Time: 10:12 - Calculation Time: 0.113 sec + GEOPHIRES Version: 3.9.47 + Simulation Date: 2025-07-31 + Simulation Time: 08:57 + Calculation Time: 0.124 sec ***SUMMARY OF RESULTS*** @@ -26,7 +26,8 @@ Simulation Metadata ***ECONOMIC PARAMETERS*** Economic Model = BICYCLE - Accrued financing during construction: 5.00 % + Accrued financing during construction: 5.00 % + Inflation costs during construction: 5.18 MUSD Project lifetime: 35 yr Capacity factor: 90.0 % Project NPV: -2.38 MUSD @@ -66,7 +67,7 @@ Simulation Metadata m/A Drawdown Parameter: 0.00002 1/year Bottom-hole temperature: 232.00 degC Reservoir volume calculated with fracture separation and number of fractures as input - Number of fractures: 12.00 + Number of fractures: 12 Fracture separation: 80.00 meter Reservoir volume: 176000000 m**3 Reservoir hydrostatic pressure: 29019.48 kPa diff --git a/tests/test_geophires_x.py b/tests/test_geophires_x.py index 1e2c5607..0ac9abf1 100644 --- a/tests/test_geophires_x.py +++ b/tests/test_geophires_x.py @@ -1,10 +1,11 @@ +from __future__ import annotations + import math import os import tempfile import uuid from pathlib import Path from typing import Any -from typing import Optional from geophires_x.OptionList import PlantType from geophires_x.OptionList import WellDrillingCostCorrelation @@ -270,7 +271,7 @@ def _sanitize_nan(self, r: GeophiresXResult) -> None: except TypeError: pass - def _get_unequal_dicts_approximate_percent_difference(self, d1: dict, d2: dict) -> Optional[float]: + def _get_unequal_dicts_approximate_percent_difference(self, d1: dict, d2: dict) -> float | None: for i in range(99): try: self.assertDictAlmostEqual(d1, d2, percent=i) @@ -967,9 +968,9 @@ def test_sbt_coaxial_raises_error(self): def test_production_well_stimulation_cost(self): def _get_result( - prod_well_stim_MUSD: Optional[int] = None, - inj_well_stim_MUSD: Optional[int] = None, - additional_params: Optional[dict[str, Any]] = None, + prod_well_stim_MUSD: int | None = None, + inj_well_stim_MUSD: int | None = None, + additional_params: dict[str, Any] | None = None, ) -> GeophiresXResult: if additional_params is None: additional_params = {} @@ -1030,9 +1031,9 @@ def _get_result( def test_indirect_costs(self): def _get_result( - indirect_cost_percent: Optional[int] = None, - stimulation_indirect_cost_percent: Optional[int] = None, - wellfield_indirect_cost_percent: Optional[int] = None, + indirect_cost_percent: int | None = None, + stimulation_indirect_cost_percent: int | None = None, + wellfield_indirect_cost_percent: int | None = None, input_file_path: str = 'geophires_x_tests/generic-egs-case.txt', ) -> float: p = {} @@ -1130,7 +1131,7 @@ def wellfield_cost(result_cap_costs): def test_contingency(self): def _get_result( - contingency_percentage: Optional[int] = None, + contingency_percentage: int | None = None, input_file_path: str = 'geophires_x_tests/generic-egs-case.txt', ) -> float: p = {}