diff --git a/src/geophires_monte_carlo/Examples/MC_HIP_Settings_file.txt b/src/geophires_monte_carlo/Examples/MC_HIP_Settings_file.txt index 3a6baae6..d26816ea 100644 --- a/src/geophires_monte_carlo/Examples/MC_HIP_Settings_file.txt +++ b/src/geophires_monte_carlo/Examples/MC_HIP_Settings_file.txt @@ -3,10 +3,11 @@ INPUT, Reservoir Area, uniform, 50.0, 120.0 INPUT, Reservoir Thickness, uniform, 0.122, 0.299 INPUT, Reservoir Temperature, uniform, 130, 170 INPUT, Rejection Temperature, uniform, 20, 33 -OUTPUT, Available Heat (fluid) -OUTPUT, Producible Heat (fluid) -OUTPUT, Producible Heat/Unit Area (fluid) -OUTPUT, Producible Electricity (fluid) -OUTPUT, Producible Electricity/Unit Area (fluid) -ITERATIONS, 250 +OUTPUT, Producible Heat (reservoir) +OUTPUT, Producible Heat/Unit Area (reservoir) +OUTPUT, Producible Heat/Unit Volume (reservoir) +OUTPUT, Producible Electricity (reservoir) +OUTPUT, Producible Electricity/Unit Area (reservoir) +OUTPUT, Producible Electricity/Unit Volume (reservoir) +ITERATIONS, 25 MC_OUTPUT_FILE, MC_HIP_Result.txt diff --git a/src/geophires_monte_carlo/MC_GeoPHIRES3.py b/src/geophires_monte_carlo/MC_GeoPHIRES3.py index 07a57e80..87bdaf06 100755 --- a/src/geophires_monte_carlo/MC_GeoPHIRES3.py +++ b/src/geophires_monte_carlo/MC_GeoPHIRES3.py @@ -26,7 +26,8 @@ from rich.table import Table from geophires_monte_carlo.common import _get_logger -from geophires_x.Parameter import Parameter +from geophires_x.GeoPHIRESUtils import InsertImagesIntoHTML +from geophires_x.GeoPHIRESUtils import render_default from geophires_x_client import GeophiresInputParameters from geophires_x_client import GeophiresXClient from geophires_x_client import GeophiresXResult @@ -125,95 +126,7 @@ def Write_HTML_Output( console.print(statistics_table) console.save_html(html_path) - # Write a reference to the image(s) into the HTML file by inserting before the "" tag - # build the string to be inserted first - insert_string = '' - for _ in range(len(full_names)): - name_to_use = short_names.pop() - insert_string = insert_string + f'{name_to_use}\n' - - match_string = '' - with open(html_path, 'r+', encoding='UTF-8') as html_file: - contents = html_file.readlines() - if match_string in contents[-1]: # Handle last line to prevent IndexError - pass - else: - for index, line in enumerate(contents): - if match_string in line and insert_string not in contents[index + 1]: - contents.insert(index, insert_string) - break - html_file.seek(0) - html_file.writelines(contents) - - -def UpgradeSymbologyOfUnits(unit: str) -> str: - """ - UpgradeSymbologyOfUnits is a function that takes a string that represents a unit and replaces the **2 and **3 - with the appropriate unicode characters for superscript 2 and 3, and replaces "deg" with the unicode character - for degrees. - :param unit: a string that represents a unit - :return: a string that represents a unit with the appropriate unicode characters for superscript 2 and 3, and - replaces "deg" with the unicode character for degrees. - """ - return unit.replace('**2', '\u00b2').replace('**3', '\u00b3').replace('deg', '\u00b0') - - -def render_default(p: float, unit: str = '') -> str: - """ - RenderDefault - render a float as a string with 2 decimal places, or in scientific notation if it is greater than - 10,000 with the unit appended to it if it is not an empty string (the default) - :param p: the float to render - :type p: float - :param unit: the unit to append to the string - :type unit: str - :return: the string representation of the float - :rtype: str - """ - unit = UpgradeSymbologyOfUnits(unit) - # if the number is greater than 10,000, render it in scientific notation - if p > 10_000: - return f'{p:10.2e} {unit}'.strip() - # otherwise, render it with 2 decimal places - else: - return f'{p:10.2f} {unit}'.strip() - - -def render_scientific(p: float, unit: str = '') -> str: - """ - RenderScientific - render a float as a string in scientific notation with 2 decimal places - and the unit appended to it if it is not an empty string (the default) - :param p: the float to render - :type p: float - :param unit: the unit to append to the string - :type unit: str - :return: the string representation of the float - :rtype: str - """ - unit = UpgradeSymbologyOfUnits(unit) - return f'{p:10.2e} {unit}'.strip() - - -def render_Parameter_default(p: Parameter) -> str: - """ - RenderDefault - render a float as a string with 2 decimal places, or in scientific notation if it is greater than - 10,000 with the unit appended to it if it is not an empty string (the default) by calling the render_default base - function - :param p: the parameter to render - :type p: float - :return: the string representation of the float - """ - return render_default(p.value, p.CurrentUnits.value) - - -def render_parameter_scientific(p: Parameter) -> str: - """ - RenderScientific - render a float as a string in scientific notation with 2 decimal places - and the unit appended to it if it is not an empty string (the default) by calling the render_scientific base function - :param p: the parameter to render - :type p: float - :return: the string representation of the float - """ - return render_scientific(p.value, p.CurrentUnits.value) + InsertImagesIntoHTML(html_path, full_names, short_names) def check_and_replace_mean(input_value, args) -> list: diff --git a/src/geophires_x/.gitignore b/src/geophires_x/.gitignore index 701adf2a..dee1bab6 100644 --- a/src/geophires_x/.gitignore +++ b/src/geophires_x/.gitignore @@ -133,3 +133,4 @@ Examples\Test2.json /References/Muffler and Cataldi Methods for regional assessment of geothermal resources.pdf /Preliminary_Corpus Christi GRA_093019.xlsx /temperature.txt +all_messages_conf.log diff --git a/src/geophires_x/Economics.py b/src/geophires_x/Economics.py index 6904c66c..fe6a9cf5 100644 --- a/src/geophires_x/Economics.py +++ b/src/geophires_x/Economics.py @@ -9,38 +9,65 @@ from geophires_x.Units import * -def BuildPricingModel(plantlifetime: int, StartYear: int, StartPrice: float, EndPrice: float, - EscalationStart: int, EscalationRate: float): +def BuildPTCModel(plantlifetime: int, duration: int, ptc_price: float, + ptc_inflation_adjusted: bool, inflation_rate: float) -> list: + """ + BuildPricingModel builds the price model array for the project lifetime. It is used to calculate the revenue + stream for the project. + :param plantlifetime: The lifetime of the project in years + :type plantlifetime: int + :param duration: The duration of the PTC in years + :type duration: int + :param ptc_price: The PTC in $/kWh + :type ptc_price: float + :param ptc_inflation_adjusted: Is the PTC is inflation? + :type ptc_inflation_adjusted: bool + :param inflation_rate: The inflation rate in % + :type inflation_rate: float + :return: Price: The price model array for the PTC in $/kWh + :rtype: list + """ + # Build the PTC price model by setting the price to the PTCPrice for the duration of the PTC + Price = [0.0] * plantlifetime + for year in range(0, duration, 1): + Price[year] = ptc_price + if ptc_inflation_adjusted and year > 0: + Price[year] = Price[year-1] * (1 + inflation_rate) + return Price + + +def BuildPricingModel(plantlifetime: int, StartPrice: float, EndPrice: float, + EscalationStartYear: int, EscalationRate: float, PTCAddition: list) -> list: """ BuildPricingModel builds the price model array for the project lifetime. It is used to calculate the revenue stream for the project. :param plantlifetime: The lifetime of the project in years :type plantlifetime: int - :param StartYear: The year the project starts in years (not including construction years) - :type StartYear: int :param StartPrice: The price in the first year of the project in $/kWh :type StartPrice: float :param EndPrice: The price in the last year of the project in $/kWh :type EndPrice: float - :param EscalationStart: The year the price escalation starts in years (not including construction years) in years - :type EscalationStart: int + :param EscalationStartYear: The year the price escalation starts in years (not including construction years) in years + :type EscalationStartYear: int :param EscalationRate: The rate of price escalation in $/kWh/year :type EscalationRate: float + :param PTCAddition: The PTC addition array for the project in $/kWh + :type PTCAddition: list :return: Price: The price model array for the project in $/kWh :rtype: list """ - Price = [StartPrice] * plantlifetime - if StartPrice == EndPrice: - return Price - for i in range(StartYear, plantlifetime, 1): - if i >= EscalationStart: - Price[i] = Price[i] + ((i - EscalationStart) * EscalationRate) + Price = [0.0] * plantlifetime + for i in range(0, plantlifetime, 1): + Price[i] = StartPrice + if i >= EscalationStartYear: + Price[i] = Price[i] + ((i - EscalationStartYear) * EscalationRate) if Price[i] > EndPrice: Price[i] = EndPrice + Price[i] = Price[i] + PTCAddition[i] return Price -def CalculateTotalRevenue(plantlifetime: int, ConstructionYears: int, CAPEX: float, OPEX: float, AnnualRev, CummRev): +def CalculateTotalRevenue(plantlifetime: int, ConstructionYears: int, CAPEX: float, OPEX: float, AnnualRev): """ CalculateRevenue calculates the revenue stream for the project. It is used to calculate the revenue stream for the project. @@ -52,10 +79,8 @@ def CalculateTotalRevenue(plantlifetime: int, ConstructionYears: int, CAPEX: flo :type CAPEX: float :param OPEX: The total annual operating cost of the project in MUSD :type OPEX: float - :param Energy: The energy production array for the project in kWh - :type Energy: list - :param Price: The price model array for the project in $/kWh - :type Price: list + :param AnnualRev: The annual revenue array for the project in MUSD + :type AnnualRev: list :return: CashFlow: The annual cash flow for the project in MUSD and CummCashFlow: The cumulative cash flow for the project in MUSD :rtype: list @@ -307,6 +332,7 @@ def CalculateLCOELCOHLCOC(self, model: Model) -> tuple: NPVfc = np.sum((1 + self.inflrateconstruction.value) * self.CCap.value * self.PTR.value * inflationvector * discountvector) NPVit = np.sum(self.CTR.value / (1 - self.CTR.value) * ((1 + self.inflrateconstruction.value) * self.CCap.value * CRF - self.CCap.value / model.surfaceplant.plant_lifetime.value) * discountvector) NPVitc = (1 + self.inflrateconstruction.value) * self.CCap.value * self.RITC.value / (1 - self.CTR.value) + if model.surfaceplant.enduse_option.value == EndUseOptions.ELECTRICITY: NPVoandm = np.sum(self.Coam.value * inflationvector * discountvector) NPVgrt = self.GTR.value / (1 - self.GTR.value) * (NPVcap + NPVoandm + NPVfc + NPVit - NPVitc) @@ -1223,6 +1249,57 @@ def __init__(self, model: Model): ErrMessage="assume calculation for CHP Electrical Plant Cost Allocation Ratio (cost electrical plant/total CAPEX)", ToolTipText="CHP Electrical Plant Cost Allocation Ratio (cost electrical plant/total CAPEX)" ) + self.PTCElec = self.ParameterDict[self.PTCElec.Name] = floatParameter( + "Production Tax Credit Electricity", + DefaultValue=0.04, + Min=0.0, + Max=10.0, + UnitType=Units.ENERGYCOST, + PreferredUnits=EnergyCostUnit.DOLLARSPERKWH, + CurrentUnits=EnergyCostUnit.DOLLARSPERKWH, + ErrMessage="assume default for Production Tax Credit Electricity ($0.04/kWh)", + ToolTipText="Production tax credit for electricity in $/kWh" + ) + self.PTCHeat = self.ParameterDict[self.PTCHeat.Name] = floatParameter( + "Production Tax Credit Heat", + DefaultValue=0.0, + Min=0.0, + Max=100.0, + UnitType=Units.ENERGYCOST, + PreferredUnits=EnergyCostUnit.DOLLARSPERMMBTU, + CurrentUnits=EnergyCostUnit.DOLLARSPERMMBTU, + ErrMessage="assume default for Production Tax Credit Heat ($0.0/MMBTU)", + ToolTipText="Production tax credit for heat in $/MMBTU" + ) + self.PTCCooling = self.ParameterDict[self.PTCCooling.Name] = floatParameter( + "Production Tax Credit Cooling", + DefaultValue=0.0, + Min=0.0, + Max=100.0, + UnitType=Units.ENERGYCOST, + PreferredUnits=EnergyCostUnit.DOLLARSPERMMBTU, + CurrentUnits=EnergyCostUnit.DOLLARSPERMMBTU, + ErrMessage="assume default for Production Tax Credit Cooling ($0.0/MMBTU)", + ToolTipText="Production tax credit for cooling in $/MMBTU" + ) + self.PTCDuration = self.ParameterDict[self.PTCDuration.Name] = intParameter( + "Production Tax Credit Duration", + DefaultValue=10, + AllowableRange=list(range(0, 100, 1)), + UnitType=Units.TIME, + PreferredUnits=TimeUnit.YEAR, + CurrentUnits=TimeUnit.YEAR, + ErrMessage="assume default for Production Tax Credit Duration (10 years)", + ToolTipText="Production tax credit for duration in years" + ) + self.PTCInflationAdjusted = self.ParameterDict[self.PTCInflationAdjusted.Name] = boolParameter( + "Production Tax Credit Inflation Adjusted", + DefaultValue=False, + UnitType=Units.NONE, + Required=False, + ErrMessage="assume default for Production Tax Credit Inflation Adjusted (False)", + ToolTipText="Production tax credit inflation adjusted" + ) # local variable initialization self.CAPEX_cost_electricity_plant = 0.0 @@ -1512,6 +1589,12 @@ def __init__(self, model: Model): PreferredUnits=TimeUnit.YEAR, CurrentUnits=TimeUnit.YEAR ) + self.RITCValue = self.OutputParameterDict[self.RITCValue.Name] = OutputParameter( + Name="Investment Tax Credit Value", + UnitType=Units.CURRENCY, + PreferredUnits=CurrencyUnit.MDOLLARS, + CurrentUnits=CurrencyUnit.MDOLLARS + ) model.logger.info(f'Complete {__class__!s}: {sys._getframe().f_code.co_name}') @@ -2301,6 +2384,11 @@ def Calculate(self, model: Model) -> None: else: self.CCap.value = self.totalcapcost.value + # update the capitol costs, assuming the entire ITC is used to reduce the capitol costs + if self.RITC.Provided: + self.RITCValue.value = self.RITC.value * self.CCap.value + self.CCap.value = self.CCap.value - self.RITCValue.value + # Add in the FlatLicenseEtc, OtherIncentives, & TotalGrant self.CCap.value = self.CCap.value + self.FlatLicenseEtc.value - self.OtherIncentives.value - self.TotalGrant.value @@ -2410,19 +2498,41 @@ def Calculate(self, model: Model) -> None: model.reserv.depth.value = model.reserv.depth.value / 1000.0 model.reserv.depth.CurrentUnits = LengthUnit.KILOMETERS + # build the PTC price models + self.PTCElecPrice = [0.0] * model.surfaceplant.plant_lifetime.value + self.PTCHeatPrice = [0.0] * model.surfaceplant.plant_lifetime.value + self.PTCCoolingPrice = [0.0] * model.surfaceplant.plant_lifetime.value + self.PTCCarbonPrice = [0.0] * model.surfaceplant.plant_lifetime.value + if self.PTCElec.Provided: + self.PTCElecPrice = BuildPTCModel(model.surfaceplant.plant_lifetime.value, + self.PTCDuration.value, self.PTCElec.value, self.PTCInflationAdjusted.value, + self.RINFL.value) + if self.PTCHeat.Provided: + self.PTCHeatPrice = BuildPTCModel(model.surfaceplant.plant_lifetime.value, + self.PTCDuration.value, self.PTCHeat.value, self.PTCInflationAdjusted.value, + self.RINFL.value) + if self.PTCCooling.Provided: + self.PTCCoolingPrice = BuildPTCModel(model.surfaceplant.plant_lifetime.value, + self.PTCDuration.value,self.PTCCooling.value, self.PTCInflationAdjusted.value, + self.RINFL.value) + # build the price models - self.ElecPrice.value = BuildPricingModel(model.surfaceplant.plant_lifetime.value, 0, + self.ElecPrice.value = BuildPricingModel(model.surfaceplant.plant_lifetime.value, self.ElecStartPrice.value, self.ElecEndPrice.value, - self.ElecEscalationStart.value, self.ElecEscalationRate.value) - self.HeatPrice.value = BuildPricingModel(model.surfaceplant.plant_lifetime.value, 0, + self.ElecEscalationStart.value, self.ElecEscalationRate.value, + self.PTCElecPrice) + self.HeatPrice.value = BuildPricingModel(model.surfaceplant.plant_lifetime.value, self.HeatStartPrice.value, self.HeatEndPrice.value, - self.HeatEscalationStart.value, self.HeatEscalationRate.value) - self.CoolingPrice.value = BuildPricingModel(model.surfaceplant.plant_lifetime.value, 0, + self.HeatEscalationStart.value, self.HeatEscalationRate.value, + self.PTCHeatPrice) + self.CoolingPrice.value = BuildPricingModel(model.surfaceplant.plant_lifetime.value, self.CoolingStartPrice.value, self.CoolingEndPrice.value, - self.CoolingEscalationStart.value, self.CoolingEscalationRate.value) - self.CarbonPrice.value = BuildPricingModel(model.surfaceplant.plant_lifetime.value, self.CarbonEscalationStart.value, + self.CoolingEscalationStart.value, self.CoolingEscalationRate.value, + self.PTCCoolingPrice) + self.CarbonPrice.value = BuildPricingModel(model.surfaceplant.plant_lifetime.value, self.CarbonStartPrice.value, self.CarbonEndPrice.value, - self.CarbonEscalationStart.value, self.CarbonEscalationRate.value) + self.CarbonEscalationStart.value, self.CarbonEscalationRate.value, + self.PTCCarbonPrice) # do the additional economic calculations first, if needed, so the summaries below work. if self.DoAddOnCalculations.value: @@ -2492,6 +2602,13 @@ def Calculate(self, model: Model) -> None: self.TotalRevenue.value[i] = self.TotalRevenue.value[i] + self.CarbonRevenue.value[i] #self.TotalCummRevenue.value[i] = self.TotalCummRevenue.value[i] + self.CarbonCummCashFlow.value[i] + # for the sake of display, insert zeros at the beginning of the pricing arrays + for i in range(0, model.surfaceplant.construction_years.value, 1): + self.ElecPrice.value.insert(0, 0.0) + self.HeatPrice.value.insert(0, 0.0) + self.CoolingPrice.value.insert(0, 0.0) + self.CarbonPrice.value.insert(0, 0.0) + # Insert the cost of construction into the front of the array that will be used to calculate NPV # the convention is that the upfront CAPEX is negative # This is the same for all projects diff --git a/src/geophires_x/GEOPHIRESv3.py b/src/geophires_x/GEOPHIRESv3.py index 9662d307..3523dcf8 100644 --- a/src/geophires_x/GEOPHIRESv3.py +++ b/src/geophires_x/GEOPHIRESv3.py @@ -41,6 +41,7 @@ def main(enable_geophires_logging_config=True): # write the outputs as JSON import jsons, json + jsons.suppress_warnings(True) json_resrv = jsons.dumps(model.reserv.OutputParameterDict, indent=4, sort_keys=True, supress_warnings=True) json_wells = jsons.dumps(model.wellbores.OutputParameterDict, indent=4, sort_keys=True, supress_warnings=True) @@ -80,10 +81,6 @@ def main(enable_geophires_logging_config=True): for line in content: sys.stdout.write(line) - # make district heating plot - if model.surfaceplant.plant_type.value == OptionList.PlantType.DISTRICT_HEATING: - model.outputs.MakeDistrictHeatingPlot(model) - logger.info(f'Complete {str(__name__)}: {sys._getframe().f_code.co_name}') diff --git a/src/geophires_x/GeoPHIRESUtils.py b/src/geophires_x/GeoPHIRESUtils.py index bbb599d4..885aebee 100644 --- a/src/geophires_x/GeoPHIRESUtils.py +++ b/src/geophires_x/GeoPHIRESUtils.py @@ -17,7 +17,7 @@ import CoolProp.CoolProp as CP -from geophires_x.Parameter import ParameterEntry +from geophires_x.Parameter import ParameterEntry, Parameter from geophires_x.Units import get_unit_registry _logger = logging.getLogger('root') # TODO use __name__ instead of root @@ -94,6 +94,131 @@ _ureg = get_unit_registry() +def InsertImagesIntoHTML(html_path: str, short_names: set, full_names: set) -> None: + + # Write a reference to the image(s) into the HTML file by inserting before the "" tag + # build the string to be inserted first + insert_string = '' + for _ in range(len(full_names)): + name_to_use = short_names.pop() + insert_string = insert_string + f'{name_to_use}\n
' + + match_string = '' + with open(html_path, 'r+', encoding='UTF-8') as html_file: + contents = html_file.readlines() + if match_string in contents[-1]: # Handle last line to prevent IndexError + pass + else: + for index, line in enumerate(contents): + if match_string in line and insert_string not in contents[index + 1]: + contents.insert(index, insert_string) + break + html_file.seek(0) + html_file.writelines(contents) + + +def UpgradeSymbologyOfUnits(unit: str) -> str: + """ + UpgradeSymbologyOfUnits is a function that takes a string that represents a unit and replaces the **2 and **3 + with the appropriate unicode characters for superscript 2 and 3, and replaces "deg" with the unicode character + for degrees. + :param unit: a string that represents a unit + :return: a string that represents a unit with the appropriate unicode characters for superscript 2 and 3, and + replaces "deg" with the unicode character for degrees. + """ + + return unit.replace('**2', '\u00b2').replace('**3', '\u00b3').replace('deg', '\u00b0') + + +def render_default(p: float, unit: str = '', fmt: str = '') -> str: + """ + RenderDefault - render a float as a string with 2 decimal place by default, or whatever format the user specifies, + or in scientific notation if it is greater than 10,000 + with the unit appended to it if it is not an empty string (the default) + :param p: the float to render + :type p: float + :param unit: the unit to append to the string + :type unit: str + :param fmt: the format to use for the string representation of the float + :type fmt: str + :return: the string representation of the float + """ + if not np.can_cast(p, float): + raise ValueError(f'Parameter ({p}) must be a float or convertible to float.') + + unit = UpgradeSymbologyOfUnits(unit) + # if the number is greater than 10,000, render it in scientific notation + if p > 10_000: + return render_scientific(p, unit) + # otherwise, render it with 2 decimal places + else: + if not fmt: + return f'{p:10.2f} {unit}'.strip() + else: + if ':' in fmt: + fmt = fmt.split(':')[1] + fmt = '{0:' + fmt + '}{1:s}' + return fmt.format(p, unit.strip()) + + +def render_scientific(p: float, unit: str = '', fmt: str = '') -> str: + """ + RenderScientific - render a float as a string in scientific notation with 2 decimal places by default, or whatever + format the user specifies, and the unit appended to it if it is not an empty string (the default) + :param p: the float to render + :type p: float + :param unit: the unit to append to the string + :type unit: str + :param fmt: the format to use for the string representation of the float + :type fmt: str + :return: the string representation of the float + :rtype: str + """ + + if not np.can_cast(p, float): + raise ValueError(f'Parameter ({p}) must be a float or convertible to float.') + + unit = UpgradeSymbologyOfUnits(unit) + if not fmt: + return f'{p:10.2e} {unit}'.strip() + else: + pass + + +def render_Parameter_default(p: Parameter, fmt: str = '') -> str: + """ + RenderDefault - render a float parameter in scientific notation as a string with 2 decimal places, + or whatever format the user specifies with the unit appended to it if it is not an empty string (the default) + function + :param p: the parameter to render + :type p: Parameter + :param fmt: the format to use for the string representation of the float + :type fmt: str + :return: the string representation of the float + """ + if not np.can_cast(p.value, float): + raise ValueError(f'Parameter ({p.value}) must be a float or convertible to float.') + + return render_default(p.value, p.CurrentUnits.value) + + +def render_parameter_scientific(p: Parameter, fmt: str = '') -> str: + """ + RenderScientific - render a float as a string in scientific notation with 2 decimal places + and the unit appended to it if it is not an empty string (the default) by calling the render_scientific base function + :param p: the parameter to render + :type p: float + :param fmt: the format to use for the string representation of the float + :type fmt: str + :return: the string representation of the float + """ + + if not np.can_cast(p.value, float): + raise ValueError(f'Parameter ({p.value}) must be a float or convertible to float.') + + return render_scientific(p.value, p.CurrentUnits.value) + + def quantity(value: float, unit: str) -> PlainQuantity: """ :rtype: pint.registry.Quantity - note type annotation uses PlainQuantity due to issues with python 3.8 failing diff --git a/src/geophires_x/Outputs.py b/src/geophires_x/Outputs.py index ca9a0509..f580112d 100644 --- a/src/geophires_x/Outputs.py +++ b/src/geophires_x/Outputs.py @@ -1,16 +1,618 @@ import datetime import time import sys -import geophires_x +import string +import unicodedata +import dataclasses +from pathlib import Path + +import rich + import numpy as np +import pandas as pd from matplotlib import pyplot as plt +from rich.console import Console +from rich.table import Table + +import geophires_x import geophires_x.Model as Model from geophires_x.Economics import Economics -from geophires_x.Parameter import ConvertUnitsBack, ConvertOutputUnits, LookupUnits, OutputParameter +from geophires_x.Parameter import ConvertUnitsBack, ConvertOutputUnits, LookupUnits, strParameter, boolParameter, \ + OutputParameter, ReadParameter, intParameter from geophires_x.OptionList import EndUseOptions, EconomicModel, ReservoirModel, FractureShape, ReservoirVolume, \ PlantType +from geophires_x.GeoPHIRESUtils import UpgradeSymbologyOfUnits, render_default, InsertImagesIntoHTML + +NL = '\n' +validFilenameChars = "-_.() %s%s" % (string.ascii_letters, string.digits) + + +@dataclasses.dataclass +class OutputTableItem: + parameter: str = '' + value: str = '' + units: str = '' + + def __init__(self, parameter: str, value: str = '', units: str = ''): + self.parameter = parameter + self.value = value + self.units = units + if self.units: + self.units = UpgradeSymbologyOfUnits(self.units) + + +def removeDisallowedFilenameChars(filename): + """ + This function removes disallowed filename characters + :param filename: the filename + :type filename: str + :return: the cleaned filename + :rtype: str + """ + cleanedFilename = unicodedata.normalize('NFKD', filename).encode('ASCII', 'ignore') + return ''.join(chr(c) for c in cleanedFilename if chr(c) in validFilenameChars) + + +def ShortenArrayToAnnual(array_to_shorten: pd.array, new_length:int, time_steps_per_year: int) -> pd.array: + """ + This function shortens the array to the number of years in the model + :param array_to_shorten: the array to shorten + :type array_to_shorten: pd.array + :param new_length: the new length + :type new_length: int + :param time_steps_per_year: the number of time steps per year + :type time_steps_per_year: int + :return: the new array + :rtype: pd.array + """ + if len(array_to_shorten) == new_length: + return array_to_shorten + + new_array = np.zeros(new_length) + + j = 0 + for i in range(0, len(array_to_shorten), time_steps_per_year): + new_array[j] = array_to_shorten[i] + j = j + 1 + + return new_array + +def Write_Simple_Text_Table(title: str, items: list, f) -> None: + """ + This function writes out the simple tables as text + :param title: the title of the table + :type title: str + :param items: the list of items to be written out + :type items: list + :param f: the file object + :type f: file + """ + f.write(f'{NL}') + f.write(f' ***{title}***{NL}') + f.write(f'{NL}') + for item in items: + f.write(f' {item.parameter:<45}: {item.value:^10} {item.units}{NL}') + + +def Write_Complex_Text_table(title: str, df_table: pd.DataFrame, time_steps_per_year: int, f) -> None: + """ + This function writes out the complex tables as text + :param title: the title of the table + :type title: str + :param df_table: the dataframe to be written out + :type df_table: pd.DataFrame + :param time_steps_per_year: the number of time steps per year + :type time_steps_per_year: int + :param f: the file object + :type f: file + """ + f.write(f'{NL}') + f.write(f' ***************************************************************{NL}') + f.write(f' *{title:^58}*{NL}') + f.write(f' ***************************************************************{NL}') + column_fmt = [] + for col in df_table.columns: + if col != 'index': + pair = col.split('|') + column_name = pair[0] + column_fmt.append(pair[1]) + f.write(f' {UpgradeSymbologyOfUnits(column_name):^29} ') + + f.write(f'{NL}') + for index, row in df_table.iterrows(): + # only print the number of rows implied by time_steps_per_year + if int(index) % time_steps_per_year == 0: + for i in range(1, len(row)): + f.write(f'{render_default((df_table.at[index, row.index[i]]) / time_steps_per_year, "", column_fmt[i - 1]):^33} ') + f.write(f'{NL}') + + +def Write_Text_Output(output_path: str, simulation_metadata: list, summary: list, economic_parameters: list, + engineering_parameters: list, resource_characteristics: list, reservoir_parameters: list, + reservoir_stimulation_results: list, CAPEX: list, OPEX: list, surface_equipment_results: list, + sdac_results: list, addon_results: list, hce: pd.DataFrame, ahce: pd.DataFrame, + cashflow: pd.DataFrame, sdac_df: pd.DataFrame, addon_df: pd.DataFrame) -> None: + """ + This function writes out the text output + :param output_path: the path to the output file + :type output_path: str + :param simulation_metadata: the simulation metadata + :type simulation_metadata: list + :param summary: the summary of results + :type summary: list + :param economic_parameters: the economic parameters + :type economic_parameters: list + :param engineering_parameters: the engineering parameters + :type engineering_parameters: list + :param resource_characteristics: the resource characteristics + :type resource_characteristics: list + :param reservoir_parameters: the reservoir parameters + :type reservoir_parameters: list + :param reservoir_stimulation_results: the reservoir stimulation results + :type reservoir_stimulation_results: list + :param CAPEX: the capital costs + :type CAPEX: list + :param OPEX: the operating and maintenance costs + :type OPEX: list + :param surface_equipment_results: the surface equipment simulation results + :type surface_equipment_results: list + :param sdac_results: the sdac results + :type sdac_results: list + :param hce: the heating, cooling and/or electricity production profile + :type hce: pd.DataFrame + :param cashflow: the revenue & cashflow profile + :type cashflow: pd.DataFrame + :param sdac_df: the sdac dataframe + :type sdac_df: pd.DataFrame + :return: None + """ + with open(output_path, 'w', encoding='UTF-8') as f: + f.write(f' *****************{NL}') + f.write(f' ***CASE REPORT***{NL}') + f.write(f' *****************{NL}') + f.write(f'{NL}') + + # write out the simulation metadata + f.write(f'Simulation Metadata{NL}') + f.write(f'----------------------{NL}') + for item in simulation_metadata: + f.write(f'{item.parameter}: {item.value} {item.units}{NL}') + + # write the simple text tables + Write_Simple_Text_Table('SUMMARY OF RESULTS', summary, f) + Write_Simple_Text_Table('ECONOMIC PARAMETERS', economic_parameters, f) + Write_Simple_Text_Table('ENGINEERING PARAMETERS', engineering_parameters, f) + Write_Simple_Text_Table('RESOURCE CHARACTERISTICS', resource_characteristics, f) + Write_Simple_Text_Table('RESERVOIR PARAMETERS', reservoir_parameters, f) + Write_Simple_Text_Table('RESERVOIR STIMULATION RESULTS', reservoir_stimulation_results, f) + Write_Simple_Text_Table('CAPITAL COSTS', CAPEX, f) + Write_Simple_Text_Table('OPERATING AND MAINTENANCE COSTS', OPEX, f) + Write_Simple_Text_Table('SURFACE EQUIPMENT SIMULATION RESULTS', surface_equipment_results, f) + if len(addon_results) > 0: + Write_Simple_Text_Table('ADD-ON ECONOMICS', addon_results, f) + if len(sdac_results) > 0: + Write_Simple_Text_Table('S_DAC_GT ECONOMICS', sdac_results, f) + + # write the complex text tables + Write_Complex_Text_table('HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE', hce, 1, f) + Write_Complex_Text_table('ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE', ahce, 1, f) + Write_Complex_Text_table('REVENUE & CASHFLOW PROFILE', cashflow, 1, f) + if len(addon_df) > 0: + Write_Complex_Text_table('ADD-ON PROFILE', addon_df, 1, f) + if len(sdac_df) > 0: + Write_Complex_Text_table('S_DAC_GT PROFILE', sdac_df, 1, f) + + +def Write_Simple_HTML_Table(title: str, items: list, console: rich.console) -> None: + """ + This function writes out the simple tables as HTML. The console object is used to write out the HTML. + :param title: the title of the table + :type title: str + :param items: the list of items to be written out + :type items: list + :param console: the console object + :type console: rich.Console + """ + table = Table(title=title) + table.add_column('Parameter', style='bold', no_wrap=True, justify='center') + table.add_column('Value', style='bold', no_wrap=True, justify='center') + table.add_column('Units', style='bold', no_wrap=True, justify='center') + for item in items: + table.add_row(str(item.parameter), str(item.value), str(item.units)) + console.print(table) + + +def Write_Complex_HTML_Table(title: str, df_table: pd.DataFrame, time_steps_per_year: int, console: rich.console)-> None: + """ + This function writes out the complex tables + :param title: the title of the table + :type title: str + :param df_table: the dataframe to be written out + :type df_table: pd.DataFrame + :param time_steps_per_year: the number of time steps per year + :type time_steps_per_year: int + :param console: the console object + :type console: rich.Console + """ + table = Table(title=title) + column_fmt = [] + for col in df_table.columns: + if col != 'index': + pair = col.split('|') + column_name=pair[0] + column_fmt.append(pair[1]) + table.add_column(UpgradeSymbologyOfUnits(column_name), style='bold', no_wrap=True, justify='center') + for index, row in df_table.iterrows(): + # only print the number of rows implied by time_steps_per_year + if time_steps_per_year == 0 or int(index) % time_steps_per_year == 0: + table.add_row(*[render_default((df_table.at[index, row.index[i]]) / time_steps_per_year, '', column_fmt[i - 1]) for i in range(1, len(row))]) + console.print(table) + + +def Write_HTML_Output(html_path: str, simulation_metadata: list, summary: list, economic_parameters: list, + engineering_parameters: list, resource_characteristics: list, reservoir_parameters: list, + reservoir_stimulation_results: list, CAPEX: list, OPEX: list, surface_equipment_results: list, + sdac_results: list, addon_results: list, hce: pd.DataFrame, ahce: pd.DataFrame, + cashflow: pd.DataFrame, sdac_df: pd.DataFrame, addon_df: pd.DataFrame) -> None: + """ + This function writes out the HTML output + :param html_path: the path to the HTML output file + :type html_path: str + :param simulation_metadata: the simulation metadata + :type simulation_metadata: list + :param summary: the summary of results + :type summary: list + :param economic_parameters: the economic parameters + :type economic_parameters: list + :param engineering_parameters: the engineering parameters + :type engineering_parameters: list + :param resource_characteristics: the resource characteristics + :type resource_characteristics: list + :param reservoir_parameters: the reservoir parameters + :type reservoir_parameters: list + :param reservoir_stimulation_results: the reservoir stimulation results + :type reservoir_stimulation_results: list + :param CAPEX: the capital costs + :type CAPEX: list + :param OPEX: the operating and maintenance costs + :type OPEX: list + :param surface_equipment_results: the surface equipment simulation results + :type surface_equipment_results: list + :param sdac_results: the sdac results + :type sdac_results: list + :param addon_results: the addon results + :type addon_results: list + :param hce: the heating, cooling and/or electricity production profile + :type hce: pd.DataFrame + :param ahce: the annual heating, cooling and/or electricity production profile + :type ahce: pd.DataFrame + :param cashflow: the revenue & cashflow profile + :type cashflow: pd.DataFrame + :param sdac_df: the sdac dataframe + :type sdac_df: pd.DataFrame + :param addon_df: the addon dataframe + + """ + + console = Console(style='bold black on white', force_terminal=True, record=True, width=500) + + # write out the simulation metadata + console.print('*****************') + console.print('***CASE REPORT***') + console.print('*****************') + console.print('Simulation Metadata') + console.print('----------------------') + + for item in simulation_metadata: + console.print(f'{str(item.parameter)}: {str(item.value)} {str(item.units)}') + + # write out the simple tables + Write_Simple_HTML_Table('SUMMARY OF RESULTS', summary, console) + Write_Simple_HTML_Table('ECONOMIC PARAMETERS', economic_parameters, console) + Write_Simple_HTML_Table('ENGINEERING PARAMETERS', engineering_parameters, console) + Write_Simple_HTML_Table('RESOURCE CHARACTERISTICS', resource_characteristics, console) + Write_Simple_HTML_Table('RESERVOIR PARAMETERS', reservoir_parameters, console) + Write_Simple_HTML_Table('RESERVOIR STIMULATION RESULTS', reservoir_stimulation_results, console) + Write_Simple_HTML_Table('CAPITAL COSTS', CAPEX, console) + Write_Simple_HTML_Table('OPERATING AND MAINTENANCE COSTS', OPEX, console) + Write_Simple_HTML_Table('SURFACE EQUIPMENT SIMULATION RESULTS', surface_equipment_results, console) + if len(addon_results) > 0: + Write_Simple_HTML_Table('ADD-ON ECONOMICS', addon_results, console) + if len(sdac_results) > 0: + Write_Simple_HTML_Table('S_DAC_GT ECONOMICS', sdac_results, console) + + # write out the complex tables + Write_Complex_HTML_Table('HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE', hce, 1, console) + Write_Complex_HTML_Table('ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE', ahce, 1, console) + Write_Complex_HTML_Table('REVENUE & CASHFLOW PROFILE', cashflow, 1, console) + if len(addon_df) > 0: + Write_Complex_HTML_Table('ADD-ON PROFILE', addon_df, 1, console) + if len(sdac_df) > 0: + Write_Complex_HTML_Table('S_DAC_GT PROFILE', sdac_df, 1, console) + + # Save it all as HTML. + console.save_html(html_path) + + +def Plot_Twin_Graph(title: str, html_path: str, x: pd.array, y1: pd.array, y2: pd.array, + x_label: str, y1_label: str, y2_label:str) -> None: + """ + This function plots the twin graph + :param title: the title of the graph + :type title: str + :param html_path: the path to the HTML output file + :type html_path: str + :param x: the x values + :type x: pd.array + :param y1: the y1 values + :type y1: pd.array + :param y2: the y2 values + :type y2: pd.array + :param x_label: the x label + :type x_label: str + :param y1_label: the y1 label + :type y1_label: str + :param y2_label: the y2 label + :type y2_label: str + """ + COLOR_TEMPERATURE = "#69b3a2" + COLOR_PRICE = "#3399e6" -NL="\n" + fig, ax1 = plt.subplots(figsize=(40, 4)) + + ax1.plot(x, y1, label=UpgradeSymbologyOfUnits(y1_label), color=COLOR_PRICE, lw=3) + ax1.set_xlabel(UpgradeSymbologyOfUnits(x_label), color = COLOR_PRICE, fontsize=14) + ax1.set_ylabel(UpgradeSymbologyOfUnits(y1_label), color=COLOR_PRICE, fontsize=14) + ax1.tick_params(axis="y", labelcolor=COLOR_PRICE) + ax1.set_xlim(x.min(), x.max()) + ax1.legend(loc='lower left') + + ax2 = ax1.twinx() + ax2.plot(x, y2, label=UpgradeSymbologyOfUnits(y2_label), color=COLOR_TEMPERATURE, lw=4) + ax2.set_ylabel(UpgradeSymbologyOfUnits(y2_label), color=COLOR_TEMPERATURE, fontsize=14) + ax2.tick_params(axis="y", labelcolor=COLOR_TEMPERATURE) + ax2.legend(loc='best') + + fig.suptitle(title, fontsize=20) + + full_names: set = set() + short_names: set = set() + title = removeDisallowedFilenameChars(title.replace(' ', '_')) + save_path = Path(Path(html_path).parent, f'{title}.png') + plt.savefig(save_path) + short_names.add(title) + full_names.add(save_path) + + InsertImagesIntoHTML(html_path, short_names, full_names) + + +def Plot_Single_Graph(title: str, html_path: str, x: pd.array, y: pd.array, x_label: str, y_label: str) -> None: + """ + This function plots the single graph + :param title: the title of the graph + :type title: str + :param html_path: the path to the HTML output file + :type html_path: str + :param x: the x values + :type x: pd.array + :param y: the y values + :type y: pd.array + :param x_label: the x label + :type x_label: str + :param y_label: the y label + :type y_label: str + """ + COLOR_PRICE = "#3399e6" + +# plt.plot(x, y, color=COLOR_PRICE) + fig, ax = plt.subplots(figsize=(40, 4)) + ax.plot(x, y, label=UpgradeSymbologyOfUnits(y_label), color=COLOR_PRICE) + ax.set_xlabel(UpgradeSymbologyOfUnits(x_label), color = COLOR_PRICE, fontsize=14) + ax.set_ylabel(UpgradeSymbologyOfUnits(y_label), color=COLOR_PRICE, fontsize=14) + ax.tick_params(axis="y", labelcolor=COLOR_PRICE) + ax.set_xlim(x.min(), x.max()) + ax.legend(loc='best') + #plt.ylim(y.min(), y.max()) + #plt.gca().legend((UpgradeSymbologyOfUnits(x_label), UpgradeSymbologyOfUnits(y_label)), loc='best') + fig.suptitle(title, fontsize=20) + + full_names: set = set() + short_names: set = set() + title = removeDisallowedFilenameChars(title.replace(' ', '_')) + save_path = Path(Path(html_path).parent, f'{title}.png') + plt.savefig(save_path) + short_names.add(title) + full_names.add(save_path) + + InsertImagesIntoHTML(html_path, short_names, full_names) + + +def Plot_Tables_Into_HTML(enduse_option: intParameter, plant_type: intParameter, html_path: str, + hce: pd.DataFrame, ahce: pd.DataFrame, cashflow: pd.DataFrame, sdac_df: pd.DataFrame, + addon_df: pd.DataFrame) -> None: + """ + This function plots the tables into the HTML + :param enduse_option: the end use option + :type enduse_option: intParameter + :param html_path: the path to the HTML output file + :type html_path: str + :param plant_type: the plant type + :type plant_type: intParameter + :param hce: the heating, cooling and/or electricity production profile + :type hce: pd.DataFrame + :param ahce: the annual heating, cooling and/or electricity production profile + :type ahce: pd.DataFrame + :param cashflow: the revenue & cashflow profile + :type cashflow: pd.DataFrame + :param sdac_df: the sdac dataframe + :type sdac_df: pd.DataFrame + :param addon_df: the addon dataframe + :type addon_df: pd.DataFrame + """ + + # HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILES + # Plot the three that appear for all end uses + Plot_Single_Graph('HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILES: Thermal Drawdown', + html_path, hce.values[0:, 1], hce.values[0:, 2], hce.columns[1].split('|')[0], hce.columns[2].split('|')[0]) + Plot_Single_Graph('HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILES: Geofluid Temperature', + html_path, hce.values[0:, 1], hce.values[0:, 3], hce.columns[1].split('|')[0], hce.columns[3].split('|')[0]) + Plot_Single_Graph('HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILES: Pump Power', + html_path, hce.values[0:, 1], hce.values[0:, 4], hce.columns[1].split('|')[0], hce.columns[4].split('|')[0]) + if enduse_option.value == EndUseOptions.ELECTRICITY: + # only electricity + Plot_Single_Graph('HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILES: First Law Efficiency', + html_path, hce.values[0:, 1], hce.values[0:, 6], hce.columns[1].split('|')[0], hce.columns[6].split('|')[0]) + Plot_Single_Graph('HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILES: Net Power', + html_path, hce.values[0:, 1], hce.values[0:, 5], hce.columns[1].split('|')[0], hce.columns[5].split('|')[0]) + elif enduse_option.value == EndUseOptions.HEAT and plant_type.value not in [PlantType.HEAT_PUMP, PlantType.DISTRICT_HEATING, PlantType.ABSORPTION_CHILLER]: + # only direct-use + Plot_Single_Graph('HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILES: Net Heat', + html_path, hce.values[0:, 1], hce.values[0:, 5], hce.columns[1].split('|')[0], hce.columns[5].split('|')[0]) + elif enduse_option.value == EndUseOptions.HEAT and plant_type.value == PlantType.HEAT_PUMP: + # heat pump + Plot_Twin_Graph('HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILES: Net Heat & Heat Pump Electricity Use', + html_path, hce.values[0:, 1], hce.values[0:, 5], hce.values[0:, 6], + hce.columns[1].split('|')[0], hce.columns[5].split('|')[0], hce.columns[6].split('|')[0]) + elif enduse_option.value == EndUseOptions.HEAT and plant_type.value == PlantType.DISTRICT_HEATING: + # district heating + Plot_Single_Graph('HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILES: Geothermal Heat Output', + html_path, hce.values[0:, 1], hce.values[0:, 5], hce.columns[1].split('|')[0], hce.columns[5].split('|')[0]) + elif enduse_option.value == EndUseOptions.HEAT and plant_type.value == PlantType.ABSORPTION_CHILLER: + # absorption chiller + Plot_Twin_Graph('HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILES: Net Heat & Net Cooling', + html_path, hce.values[0:, 1], hce.values[0:, 5], hce.values[0:, 6], + hce.columns[1].split('|')[0], hce.columns[5].split('|')[0], hce.columns[6].split('|')[0]) + elif enduse_option.value in [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]: + # co-gen + Plot_Twin_Graph('HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILES: Net Power & Net Heat', + html_path, hce.values[0:, 1], hce.values[0:, 5], hce.values[0:, 6], + hce.columns[1].split('|')[0], hce.columns[5].split('|')[0], hce.columns[6].split('|')[0]) + Plot_Single_Graph('HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILES: First Law Efficiency', + html_path, hce.values[0:, 1], hce.values[0:, 7], hce.columns[1].split('|')[0], hce.columns[7].split('|')[0]) + + # ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE + # plot the common graphs + Plot_Twin_Graph('ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE: Heat Extracted & Reservoir Heat Content', + html_path, ahce.values[0:, 1], ahce.values[0:, 3], ahce.values[0:, 4], + ahce.columns[1].split('|')[0], ahce.columns[3].split('|')[0], ahce.columns[4].split('|')[0]) + if plant_type.value in [PlantType.DISTRICT_HEATING]: + # columns are in a different place for district heating + Plot_Single_Graph('ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE: Percentage of Total Heat Mined', + html_path, ahce.values[0:, 1], ahce.values[0:, 6], ahce.columns[1].split('|')[0], ahce.columns[6].split('|')[0]) + else: + Plot_Single_Graph('ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE: Percentage of Total Heat Mined', + html_path, ahce.values[0:, 1], ahce.values[0:, 5], ahce.columns[1].split('|')[0], ahce.columns[5].split('|')[0]) + + if enduse_option.value == EndUseOptions.ELECTRICITY: + # only electricity + Plot_Single_Graph('ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE: Electricity Provided', + html_path, ahce.values[0:, 1], ahce.values[0:, 2], ahce.columns[1].split('|')[0], ahce.columns[2].split('|')[0]) + elif plant_type.value == PlantType.ABSORPTION_CHILLER: + # absorption chiller + Plot_Single_Graph('ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE: Cooling Provided', + html_path, ahce.values[0:, 1], ahce.values[0:, 2], ahce.columns[1].split('|')[0], ahce.columns[2].split('|')[0]) + elif plant_type.value in [PlantType.DISTRICT_HEATING]: + # district-heating + Plot_Twin_Graph('ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE: Geothermal Heating Provided & Peaking Boiler Heating Provided', + html_path, ahce.values[0:, 1], ahce.values[0:, 2], ahce.values[0:, 3], + ahce.columns[1].split('|')[0], ahce.columns[2].split('|')[0], ahce.columns[3].split('|')[0]) + elif plant_type.value == PlantType.HEAT_PUMP: + # heat pump + Plot_Single_Graph('ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE: Heating Provided', + html_path, ahce.values[0:, 1], ahce.values[0:, 2], ahce.columns[1].split('|')[0], ahce.columns[2].split('|')[0]) + Plot_Single_Graph('ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE: Heat Pump Electricity Use', + html_path, ahce.values[0:, 1], ahce.values[0:, 4], ahce.columns[1].split('|')[0], ahce.columns[4].split('|')[0]) + elif enduse_option.value in [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]: + # co-gen + Plot_Twin_Graph('ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE: Heat Provided & Electricity Provided', + html_path, ahce.values[0:, 1], ahce.values[0:, 2], ahce.values[0:, 3], + ahce.columns[1].split('|')[0], ahce.columns[2].split('|')[0], ahce.columns[3].split('|')[0]) + elif enduse_option.value == EndUseOptions.HEAT: + # only direct-use + Plot_Single_Graph('ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE: Heat Provided', + html_path, ahce.values[0:, 1], ahce.values[0:, 2], ahce.columns[1].split('|')[0], ahce.columns[2].split('|')[0]) + + # Cashflow Graphs + Plot_Twin_Graph('REVENUE & CASHFLOW PROFILE: Electricity: Price & Cumulative Revenue', + html_path, cashflow.values[0:, 1], cashflow.values[0:, 2], cashflow.values[0:, 4], + cashflow.columns[1].split('|')[0], cashflow.columns[2].split('|')[0], cashflow.columns[4].split('|')[0]) + Plot_Twin_Graph('REVENUE & CASHFLOW PROFILE: Heat: Price & Cumulative Revenue', + html_path, cashflow.values[0:, 1], cashflow.values[0:, 5], cashflow.values[0:, 7], + cashflow.columns[1].split('|')[0], cashflow.columns[5].split('|')[0], cashflow.columns[7].split('|')[0]) + Plot_Twin_Graph('REVENUE & CASHFLOW PROFILE: Cooling: Price & Cumulative Revenue', + html_path, cashflow.values[0:, 1], cashflow.values[0:, 8], cashflow.values[0:, 10], + cashflow.columns[1].split('|')[0], cashflow.columns[8].split('|')[0], cashflow.columns[10].split('|')[0]) + Plot_Twin_Graph('REVENUE & CASHFLOW PROFILE: Carbon: Price & Cumulative Revenue', + html_path, cashflow.values[0:, 1], cashflow.values[0:, 11], cashflow.values[0:, 13], + cashflow.columns[1].split('|')[0], cashflow.columns[11].split('|')[0], cashflow.columns[13].split('|')[0]) + Plot_Twin_Graph('REVENUE & CASHFLOW PROFILE: Project: Net Revenue and cashflow', + html_path, cashflow.values[0:, 1], cashflow.values[0:, 15], cashflow.values[0:, 16], + cashflow.columns[1].split('|')[0], cashflow.columns[15].split('|')[0], cashflow.columns[16].split('|')[0]) + + if len (addon_df) > 0: + Plot_Twin_Graph('ADD-ON PROFILE: Electricity Annual Price vs. Revenue', + html_path, addon_df.values[0:, 1], addon_df.values[0:, 2], addon_df.values[0:, 3], + addon_df.columns[1].split('|')[0], addon_df.columns[2].split('|')[0], addon_df.columns[3].split('|')[0]) + Plot_Twin_Graph('ADD-ON PROFILE: Heat Annual Price vs. Revenue', + html_path, addon_df.values[0:, 1], addon_df.values[0:, 4], addon_df.values[0:, 5], + addon_df.columns[1].split('|')[0], addon_df.columns[4].split('|')[0], addon_df.columns[5].split('|')[0]) + Plot_Twin_Graph('ADD-ON PROFILE: Add-On Net Revenue & Annual Cashflow', + html_path, addon_df.values[0:, 1], addon_df.values[0:, 6], addon_df.values[0:, 7], + addon_df.columns[1].split('|')[0], addon_df.columns[6].split('|')[0], addon_df.columns[7].split('|')[0]) + Plot_Single_Graph('ADD-ON PROFILE: Add-On Cumulative Cashflow', + html_path, addon_df.values[0:, 1], addon_df.values[0:, 8], addon_df.columns[1].split('|')[0], + addon_df.columns[8].split('|')[0]) + Plot_Twin_Graph('ADD-ON PROFILE: Project Cashflow vs. Cumulative Cashflow', + html_path, addon_df.values[0:, 1], addon_df.values[0:, 9], addon_df.values[0:, 10], + addon_df.columns[1].split('|')[0], addon_df.columns[9].split('|')[0], addon_df.columns[10].split('|')[0]) + if len(sdac_df) > 0: + Plot_Twin_Graph('S_DAC_GT PROFILE: Annual vs Cumulative Carbon Captured', + html_path, sdac_df.values[0:, 1], sdac_df.values[0:, 2], sdac_df.values[0:, 3], + sdac_df.columns[1].split('|')[0], sdac_df.columns[2].split('|')[0], sdac_df.columns[3].split('|')[0]) + Plot_Twin_Graph('S_DAC_GT PROFILE: Annual Cost vs Cumulative Cost', + html_path, sdac_df.values[0:, 1], sdac_df.values[0:, 4], sdac_df.values[0:, 5], + sdac_df.columns[1].split('|')[0], sdac_df.columns[4].split('|')[0], sdac_df.columns[5].split('|')[0]) + Plot_Single_Graph('S_DAC_GT PROFILE: Cumulative Capture Cost per Tonne', + html_path, sdac_df.values[0:, 1], sdac_df.values[0:, 6], sdac_df.columns[1].split('|')[0], + sdac_df.columns[6].split('|')[0]) + + +def MakeDistrictHeatingPlot(html_path: str, dh_geothermal_heating: pd.array, daily_heating_demand: pd.array) -> None: + """" + Make a plot of the district heating system + :param html_path: the path to the HTML output file + :type html_path: str + :param dh_geothermal_heating: the geothermal heating + :type dh_geothermal_heating: pd.array + :param daily_heating_demand: the daily heating demand + :type daily_heating_demand: pd.array + """ + plt.close('all') + year_day = np.arange(1, 366, 1) # make an array of days for plot x-axis + plt.plot(year_day, daily_heating_demand, label='District Heating Demand') + plt.fill_between(year_day, 0, dh_geothermal_heating[0:365] * 24, color='g', alpha=0.5, + label='Geothermal Heat Supply') + plt.fill_between(year_day, dh_geothermal_heating[0:365] * 24, + daily_heating_demand, color='r', alpha=0.5, + label='Natural Gas Heat Supply') + plt.xlabel('Ordinal Day') + plt.ylabel('Heating Demand/Supply [MWh/day]') + plt.ylim([0, max(daily_heating_demand) * 1.05]) + plt.legend() + plt.title('Geothermal district heating system with peaking boilers') + full_names: set = set() + short_names: set = set() + title = removeDisallowedFilenameChars('Geothermal district heating system with peaking boilers'.replace(' ', '_')) + save_path = Path(Path(html_path).parent, f'{title}.png') + plt.savefig(save_path) + short_names.add(title) + full_names.add(save_path) + + InsertImagesIntoHTML(html_path, short_names, full_names) class Outputs: @@ -18,18 +620,46 @@ class Outputs: This class handles all the outputs for the GEOPHIRESv3 model. """ def __init__(self, model:Model, output_file:str ='HDR.out'): - model.logger.info(f'Init {__class__!s}: {sys._getframe().f_code.co_name}') + model.logger.info(f'Init {__class__!s}: {__name__}') + self.ParameterDict = {} + self.OutputParameterDict = {} + + self.text_output_file = self.ParameterDict[self.text_output_file.Name] = strParameter( + 'Improved Text Output File', + DefaultValue='GEOPHIRES_Text.html', + Required=False, + Provided=False, + ErrMessage='assume no improved text output', + ToolTipText='Provide a improved text output name if you want to have improved text output (no output if not provided)', + ) + + self.html_output_file = self.ParameterDict[self.html_output_file.Name] = strParameter( + 'HTML Output File', + DefaultValue='GEOPHIRES.html', + Required=False, + Provided=False, + ErrMessage='assume no HTML output', + ToolTipText='Provide a HTML output name if you want to have HTML output (no output if not provided)', + ) + + self.printoutput = self.ParameterDict[self.printoutput.Name] = boolParameter( + 'Print Output to Console', + DefaultValue=True, + Required=False, + Provided=False, + ErrMessage='assume no output to console', + ToolTipText='Provide a 0 if you do not want to print output to the console', + ) # Dictionary to hold the Units definitions that the user wants for outputs created by GEOPHIRES. # It is empty by default initially - this will expand as the user desires are read from the input file - self.ParameterDict = {} self.printoutput = True self.output_file = output_file - model.logger.info(f'Complete {__class__!s}: {sys._getframe().f_code.co_name}') + model.logger.info(f'Complete {__class__!s}: {__name__}') def __str__(self): - return "Outputs" + return 'Outputs' def read_parameters(self, model:Model) -> None: """ @@ -48,26 +678,39 @@ def read_parameters(self, model:Model) -> None: :type model: :class:`~geophires_x.Model.Model` :return: None """ - model.logger.info(f'Init {__class__!s}: {sys._getframe().f_code.co_name}') - + model.logger.info(f'Init {__class__!s}: {__name__}') + if len(model.InputParameters) > 0: + # loop through all the parameters that the user wishes to set, looking for parameters that match this object + for item in self.ParameterDict.items(): + ParameterToModify = item[1] + key = ParameterToModify.Name.strip() + if key in model.InputParameters: + ParameterReadIn = model.InputParameters[key] + # Before we change the parameter, let's assume that the unit preferences will match + # - if they don't, the later code will fix this. + ParameterToModify.CurrentUnits = ParameterToModify.PreferredUnits + # this should handle all the non-special cases + ReadParameter(ParameterReadIn, ParameterToModify, model) + + # handle the special cases if len(model.InputParameters) > 0: # if the user wants it, we need to know if the user wants to copy the contents of the # output file to the screen - this serves as the screen report - if "Print Output to Console" in model.InputParameters: - ParameterReadIn = model.InputParameters["Print Output to Console"] - if ParameterReadIn.sValue == "0": + if 'Print Output to Console' in model.InputParameters: + ParameterReadIn = model.InputParameters['Print Output to Console'] + if ParameterReadIn.sValue == '0': self.printoutput = False # loop through all the parameters that the user wishes to set, looking for parameters that contain the # prefix "Units:" - that means we want to set a special case for converting this # output parameter to new units for key in model.InputParameters.keys(): - if key.startswith("Units:"): - self.ParameterDict[key.replace("Units:", "")] = LookupUnits(model.InputParameters[key].sValue)[0] + if key.startswith('Units:'): + self.ParameterDict[key.replace('Units:', '')] = LookupUnits(model.InputParameters[key].sValue)[0] # handle special cases - model.logger.info(f'Complete {__class__!s}: {sys._getframe().f_code.co_name}') + model.logger.info(f'Complete {__class__!s}: {__name__}') def PrintOutputs(self, model: Model): """ @@ -98,94 +741,843 @@ def PrintOutputs(self, model: Model): for key in obj.OutputParameterDict: output_param:OutputParameter = obj.OutputParameterDict[key] if key in self.ParameterDict: - if self.ParameterDict[key].PreferredUnits != output_param.CurrentUnits: - ConvertOutputUnits(output_param, self.ParameterDict[key].PreferredUnits, model) + if self.ParameterDict[key] != output_param.CurrentUnits: + ConvertOutputUnits(output_param, self.ParameterDict[key], model) elif not output_param.UnitsMatch: obj.OutputParameterDict[key] = output_param.with_preferred_units() + #data structures and assignments for HTML and Improved Text Output formats + simulation_metadata = [] + summary = [] + economic_parameters = [] + engineering_parameters = [] + resource_characteristics = [] + reservoir_parameters = [] + reservoir_stimulation_results = [] + CAPEX = [] + OPEX = [] + surface_equipment_results = [] + addon_results = [] + sdac_resa_results = [] + + simulation_metadata.append(OutputTableItem('GEOPHIRES Version', geophires_x.__version__)) + simulation_metadata.append(OutputTableItem('GEOPHIRES Build Date', '2024-03-05')) + simulation_metadata.append(OutputTableItem('Simulation Date', datetime.datetime.now().strftime('%Y-%m-%d'))) + simulation_metadata.append(OutputTableItem('Simulation Time', datetime.datetime.now().strftime('%H:%M'))) + simulation_metadata.append(OutputTableItem('Calculation Time', '{0:10.3f}'.format((time.time() - model.tic)) + ' sec')) + + summary.append(OutputTableItem('End-Use Option', str(model.surfaceplant.enduse_option.value.value))) + + 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 + summary.append(OutputTableItem('Average Net Electricity Production', '{0:10.2f}'.format( + np.average(model.surfaceplant.NetElectricityProduced.value)), + model.surfaceplant.NetElectricityProduced.CurrentUnits.value)) + if model.surfaceplant.enduse_option.value != EndUseOptions.ELECTRICITY: # there is a direct-use component + summary.append(OutputTableItem('Average Direct-Use Heat Production', + '{0:10.2f}'.format(np.average(model.surfaceplant.HeatProduced.value)), + model.surfaceplant.HeatProduced.CurrentUnits.value)) + if model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING: + summary.append(OutputTableItem('Annual District Heating Demand', '{0:10.2f}'.format( + np.average(model.surfaceplant.annual_heating_demand.value)), + model.surfaceplant.annual_heating_demand.CurrentUnits.value)) + summary.append(OutputTableItem('Average Annual Geothermal Heat Production', '{0:10.2f}'.format( + sum(model.surfaceplant.dh_geothermal_heating.value * 24) / model.surfaceplant.plant_lifetime.value / 1e3), + model.surfaceplant.annual_heating_demand.CurrentUnits.value)) + summary.append(OutputTableItem('Average Annual Peaking Fuel Heat Production', '{0:10.2f}'.format( + sum(model.surfaceplant.dh_natural_gas_heating.value * 24) / model.surfaceplant.plant_lifetime.value / 1e3), + model.surfaceplant.annual_heating_demand.CurrentUnits.value)) + if model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: + summary.append(OutputTableItem('Average Cooling Production', + '{0:10.2f}'.format(np.average(model.surfaceplant.cooling_produced.value)), + model.surfaceplant.cooling_produced.CurrentUnits.value)) + + if model.surfaceplant.enduse_option.value in [EndUseOptions.ELECTRICITY]: + summary.append( + OutputTableItem('Electricity breakeven price', '{0:10.2f}'.format(model.economics.LCOE.value), + model.economics.LCOE.CurrentUnits.value)) + elif model.surfaceplant.enduse_option.value in [EndUseOptions.HEAT] and model.surfaceplant.plant_type.value not in [PlantType.ABSORPTION_CHILLER]: + summary.append(OutputTableItem('Direct-Use heat breakeven price (LCOH)', + '{0:10.2f}'.format(model.economics.LCOH.value), + model.economics.LCOH.CurrentUnits.value)) + elif (model.surfaceplant.enduse_option.value in [EndUseOptions.HEAT] and + model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER): + summary.append(OutputTableItem('Direct-Use Cooling Breakeven Price (LCOC)', + '{0:10.2f}'.format(model.economics.LCOC.value), + model.economics.LCOC.CurrentUnits.value)) + elif model.surfaceplant.enduse_option.value in [EndUseOptions.COGENERATION_TOPPING_EXTRA_HEAT, + EndUseOptions.COGENERATION_BOTTOMING_EXTRA_HEAT, + EndUseOptions.COGENERATION_PARALLEL_EXTRA_HEAT, + EndUseOptions.COGENERATION_TOPPING_EXTRA_ELECTRICITY, + EndUseOptions.COGENERATION_BOTTOMING_EXTRA_ELECTRICITY, + EndUseOptions.COGENERATION_PARALLEL_EXTRA_ELECTRICITY]: + summary.append(OutputTableItem('Electricity breakeven price', '{0:10.2f}'.format(model.economics.LCOE.value), + model.economics.LCOE.CurrentUnits.value)) + summary.append(OutputTableItem('Direct-Use heat breakeven price (LCOH)', + '{0:10.2f}'.format(model.economics.LCOH.value), + model.economics.LCOH.CurrentUnits.value)) + + summary.append(OutputTableItem('Number of production wells', '{0:10.0f}'.format(model.wellbores.nprod.value))) + summary.append(OutputTableItem('Number of injection wells', '{0:10.0f}'.format(model.wellbores.ninj.value))) + summary.append(OutputTableItem('Flowrate per production well', '{0:10.1f}'.format(model.wellbores.prodwellflowrate.value), + model.wellbores.prodwellflowrate.CurrentUnits.value)) + summary.append(OutputTableItem('Well depth (or total length, if not vertical)', + '{0:10.1f}'.format(model.reserv.depth.value), + model.reserv.depth.CurrentUnits.value)) + + if model.reserv.numseg.value == 1: + summary.append(OutputTableItem('Geothermal gradient', '{0:10.4f}'.format(model.reserv.gradient.value[0]), + model.reserv.gradient.CurrentUnits.value)) + else: + for i in range(1, model.reserv.numseg.value): + summary.append(OutputTableItem(f'Segment {str(i)} Geothermal gradient', + '{0:10.4f}'.format(model.reserv.gradient.value[i - 1]), + model.reserv.gradient.CurrentUnits.value)) + summary.append(OutputTableItem(f'Segment {str(i)} Thickness', + '{0:10.0f}'.format(model.reserv.layerthickness.value[i - 1]), + model.reserv.layerthickness.CurrentUnits.value)) + summary.append(OutputTableItem(f'Segment {str(i + 1)} Geothermal gradient', + '{0:10.4f}'.format(model.reserv.gradient.value[i]), + model.reserv.gradient.CurrentUnits.value)) + if model.economics.DoCarbonCalculations.value: + summary.append(OutputTableItem('Total Avoided Carbon Emissions', '{0:10.2f}'.format( + model.economics.CarbonThatWouldHaveBeenProducedTotal.value * 0.000453592), 'metric tonnes')) + + if model.economics.econmodel.value == EconomicModel.FCR: + economic_parameters.append(OutputTableItem('Economic Model', model.economics.econmodel.value.value)) + economic_parameters.append(OutputTableItem('Fixed Charge Rate (FCR)', '{0:10.2f}'.format(model.economics.FCR.value * 100.0), + model.economics.FCR.CurrentUnits.value)) + elif model.economics.econmodel.value == EconomicModel.STANDARDIZED_LEVELIZED_COST: + economic_parameters.append(OutputTableItem('Economic Model', model.economics.econmodel.value.value)) + economic_parameters.append(OutputTableItem('Interest Rate', '{0:10.2f}'.format(model.economics.discountrate.value * 100.0), + model.economics.discountrate.CurrentUnits.value)) + elif model.economics.econmodel.value == EconomicModel.BICYCLE: + economic_parameters.append(OutputTableItem('Economic Model', model.economics.econmodel.value.value)) + economic_parameters.append(OutputTableItem('Accrued financing during construction', + '{0:10.2f}'.format(model.economics.inflrateconstruction.value * 100), + model.economics.inflrateconstruction.CurrentUnits.value)) + economic_parameters.append(OutputTableItem('Project lifetime', '{0:10.0f}'.format(model.surfaceplant.plant_lifetime.value), + model.surfaceplant.plant_lifetime.CurrentUnits.value)) + economic_parameters.append(OutputTableItem('Capacity factor', '{0:10.1f}'.format(model.surfaceplant.utilization_factor.value * 100), + '%')) + economic_parameters.append(OutputTableItem('Project NPV', '{0:10.2f}'.format(model.economics.ProjectNPV.value), + model.economics.ProjectNPV.PreferredUnits.value)) + economic_parameters.append(OutputTableItem('Project IRR', '{0:10.2f}'.format(model.economics.ProjectIRR.value), + model.economics.ProjectIRR.PreferredUnits.value)) + economic_parameters.append(OutputTableItem('Project VIR=PI=PIR', '{0:10.2f}'.format(model.economics.ProjectVIR.value))) + economic_parameters.append(OutputTableItem('Project MOIC', '{0:10.2f}'.format(model.economics.ProjectMOIC.value))) + + payback_period_val = model.economics.ProjectPaybackPeriod.value + project_payback_period_display = f'{payback_period_val:10.2f} {model.economics.ProjectPaybackPeriod.PreferredUnits.value}' \ + if payback_period_val > 0.0 else 'N/A' + economic_parameters.append(OutputTableItem('Project Payback Period', project_payback_period_display)) + + if model.surfaceplant.enduse_option.value in [EndUseOptions.COGENERATION_TOPPING_EXTRA_HEAT, + EndUseOptions.COGENERATION_BOTTOMING_EXTRA_HEAT, + EndUseOptions.COGENERATION_PARALLEL_EXTRA_HEAT, + EndUseOptions.COGENERATION_TOPPING_EXTRA_ELECTRICITY, + EndUseOptions.COGENERATION_BOTTOMING_EXTRA_ELECTRICITY, + EndUseOptions.COGENERATION_PARALLEL_EXTRA_ELECTRICITY]: + economic_parameters.append(OutputTableItem('CHP: Percent cost allocation for electrical plant', + '{0:10.2f}'.format( + model.economics.CAPEX_heat_electricity_plant_ratio.value * 100.0), + '%')) + + engineering_parameters.append(OutputTableItem('Number of Production Wells', '{0:10.0f}'.format(model.wellbores.nprod.value))) + engineering_parameters.append(OutputTableItem('Number of Injection Wells', '{0:10.0f}'.format(model.wellbores.ninj.value))) + engineering_parameters.append(OutputTableItem('Well depth (or total length, if not vertical)', + '{0:10.1f}'.format(model.reserv.depth.value), + model.reserv.depth.CurrentUnits.value)) + engineering_parameters.append(OutputTableItem('Water loss rate', '{0:10.1f}'.format(model.reserv.waterloss.value * 100), + model.reserv.waterloss.CurrentUnits.value)) + engineering_parameters.append(OutputTableItem('Pump efficiency', '{0:10.1f}'.format(model.surfaceplant.pump_efficiency.value * 100), + model.surfaceplant.pump_efficiency.CurrentUnits.value)) + engineering_parameters.append(OutputTableItem('Injection temperature', '{0:10.1f}'.format(model.wellbores.Tinj.value), + model.wellbores.Tinj.CurrentUnits.value)) + if model.wellbores.rameyoptionprod.value: + engineering_parameters.append(OutputTableItem('Production Wellbore heat transmission calculated with Rameys model')) + engineering_parameters.append(OutputTableItem('Average production well temperature drop', + '{0:10.1f}'.format( + np.average(model.wellbores.ProdTempDrop.value)), + model.wellbores.ProdTempDrop.PreferredUnits.value)) + else: + engineering_parameters.append(OutputTableItem('User-provided production well temperature drop')) + engineering_parameters.append(OutputTableItem('Constant production well temperature drop', + '{0:10.1f}'.format(model.wellbores.tempdropprod.value), + model.wellbores.tempdropprod.PreferredUnits.value)) + engineering_parameters.append(OutputTableItem('Flowrate per production well', '{0:10.1f}'.format(model.wellbores.prodwellflowrate.value), + model.wellbores.prodwellflowrate.CurrentUnits.value)) + engineering_parameters.append(OutputTableItem('Injection well casing ID', '{0:10.3f}'.format(model.wellbores.injwelldiam.value), + model.wellbores.injwelldiam.CurrentUnits.value)) + engineering_parameters.append(OutputTableItem('Production well casing ID', '{0:10.3f}'.format(model.wellbores.prodwelldiam.value), + model.wellbores.prodwelldiam.CurrentUnits.value)) + engineering_parameters.append(OutputTableItem('Number of times redrilling', '{0:10.0f}'.format(model.wellbores.redrill.value))) + 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]: + engineering_parameters.append(OutputTableItem('Power plant type', model.surfaceplant.plant_type.value.value)) + + resource_characteristics.append(OutputTableItem('Maximum reservoir temperature', '{0:10.1f}'.format(model.reserv.Tmax.value), + model.reserv.Tmax.CurrentUnits.value)) + resource_characteristics.append(OutputTableItem('Number of segments', '{0:10.0f}'.format(model.reserv.numseg.value))) + if model.reserv.numseg.value == 1: + resource_characteristics.append(OutputTableItem('Geothermal gradient', '{0:10.4f}'.format(model.reserv.gradient.value[0]), + model.reserv.gradient.CurrentUnits.value)) + else: + for i in range(1, model.reserv.numseg.value): + resource_characteristics.append(OutputTableItem(f'Segment {str(i)} Geothermal gradient', + '{0:10.4f}'.format( + model.reserv.gradient.value[i - 1]), + model.reserv.gradient.CurrentUnits.value)) + resource_characteristics.append(OutputTableItem(f'Segment {str(i)} Thickness', '{0:10.0f}'.format( + model.reserv.layerthickness.value[i - 1]), model.reserv.layerthickness.CurrentUnits.value)) + resource_characteristics.append(OutputTableItem(f'Segment {str(i + 1)} Geothermal gradient', + '{0:10.4f}'.format(model.reserv.gradient.value[i]), + model.reserv.gradient.CurrentUnits.value)) + if model.wellbores.IsAGS.value: + reservoir_parameters.append(OutputTableItem('The AGS models contain an intrinsic reservoir model that doesn\'t expose values that can be used in extensive reporting.')) + else: + reservoir_parameters.append(OutputTableItem('Reservoir Model', str(model.reserv.resoption.value.value) + ' Model')) + if model.reserv.resoption.value == ReservoirModel.SINGLE_FRACTURE: + reservoir_parameters.append(OutputTableItem('m/A Drawdown Parameter', '{0:.5f}'.format(model.reserv.drawdp.value), + model.reserv.drawdp.CurrentUnits.value)) + elif model.reserv.resoption.value == ReservoirModel.ANNUAL_PERCENTAGE: + reservoir_parameters.append(OutputTableItem('Annual Thermal Drawdown', '{0:.3f}'.format(model.reserv.drawdp.value * 100), + model.reserv.drawdp.CurrentUnits.value)) + reservoir_parameters.append(OutputTableItem('Bottom-hole temperature', '{0:10.2f}'.format(model.reserv.Trock.value), + model.reserv.Trock.CurrentUnits.value)) + if model.reserv.resoption.value in [ReservoirModel.ANNUAL_PERCENTAGE, ReservoirModel.USER_PROVIDED_PROFILE, + ReservoirModel.TOUGH2_SIMULATOR]: + reservoir_parameters.append(OutputTableItem('Warning: the reservoir dimensions and thermo-physical properties')) + reservoir_parameters.append(OutputTableItem('listed below are default values if not provided by the user.')) + reservoir_parameters.append(OutputTableItem('They are only used for calculating remaining heat content.')) + + if model.reserv.resoption.value in [ReservoirModel.MULTIPLE_PARALLEL_FRACTURES, + ReservoirModel.LINEAR_HEAT_SWEEP]: + reservoir_parameters.append(OutputTableItem('Fracture model', model.reserv.fracshape.value.value)) + if model.reserv.fracshape.value == FractureShape.CIRCULAR_AREA: + reservoir_parameters.append(OutputTableItem('Well separation: fracture diameter', + '{0:10.2f}'.format(model.reserv.fracheightcalc.value), + model.reserv.fracheight.CurrentUnits.value)) + elif model.reserv.fracshape.value == FractureShape.CIRCULAR_DIAMETER: + reservoir_parameters.append(OutputTableItem('Well separation: fracture diameter', + '{0:10.2f}'.format(model.reserv.fracheightcalc.value), + model.reserv.fracheight.CurrentUnits.value)) + elif model.reserv.fracshape.value == FractureShape.SQUARE: + reservoir_parameters.append(OutputTableItem('Well separation: fracture height', + '{0:10.2f}'.format(model.reserv.fracheightcalc.value), + model.reserv.fracheight.CurrentUnits.value)) + elif model.reserv.fracshape.value == FractureShape.RECTANGULAR: + reservoir_parameters.append(OutputTableItem('Well separation: fracture height', + '{0:10.2f}'.format(model.reserv.fracheightcalc.value), + model.reserv.fracheight.CurrentUnits.value)) + reservoir_parameters.append( + OutputTableItem('Fracture width', '{0:10.2f}'.format(model.reserv.fracwidthcalc.value), + model.reserv.fracwidth.CurrentUnits.value)) + reservoir_parameters.append( + OutputTableItem('Fracture area', '{0:10.2f}'.format(model.reserv.fracareacalc.value), + model.reserv.fracarea.CurrentUnits.value)) + if model.reserv.resvoloption.value == ReservoirVolume.FRAC_NUM_SEP: + reservoir_parameters.append(OutputTableItem('Reservoir volume calculated with fracture separation and number of fractures as input')) + elif model.reserv.resvoloption.value == ReservoirVolume.RES_VOL_FRAC_SEP: + reservoir_parameters.append(OutputTableItem('Number of fractures calculated with reservoir volume and fracture separation as input')) + elif model.reserv.resvoloption.value == ReservoirVolume.FRAC_NUM_SEP: + reservoir_parameters.append(OutputTableItem('Fracture separation calculated with reservoir volume and number of fractures as input')) + elif model.reserv.resvoloption.value == ReservoirVolume.RES_VOL_ONLY: + reservoir_parameters.append(OutputTableItem('Reservoir volume provided as input')) + if model.reserv.resvoloption.value in [ReservoirVolume.FRAC_NUM_SEP, ReservoirVolume.RES_VOL_FRAC_SEP, + ReservoirVolume.FRAC_NUM_SEP]: + reservoir_parameters.append(OutputTableItem('Number of fractures', '{0:10.2f}'.format(model.reserv.fracnumbcalc.value))) + reservoir_parameters.append(OutputTableItem('Fracture separation', '{0:10.2f}'.format(model.reserv.fracsepcalc.value), + model.reserv.fracsep.CurrentUnits.value)) + reservoir_parameters.append(OutputTableItem('Reservoir volume', '{0:10.0f}'.format(model.reserv.resvolcalc.value), + model.reserv.resvol.CurrentUnits.value)) + if model.wellbores.impedancemodelused.value: + reservoir_parameters.append(OutputTableItem('Reservoir impedance', '{0:10.2f}'.format(model.wellbores.impedance.value / 1000), + model.wellbores.impedance.CurrentUnits.value)) + else: + reservoir_parameters.append(OutputTableItem('Reservoir hydrostatic pressure', + '{0:10.2f}'.format(model.wellbores.Phydrostaticcalc.value), + model.wellbores.Phydrostaticcalc.CurrentUnits.value)) + reservoir_parameters.append(OutputTableItem('Plant outlet pressure', '{0:10.2f}'.format( + model.surfaceplant.plant_outlet_pressure.value), + model.surfaceplant.plant_outlet_pressure.CurrentUnits.value)) + if model.wellbores.productionwellpumping.value: + reservoir_parameters.append(OutputTableItem('Production wellhead pressure', + '{0:10.2f}'.format(model.wellbores.Pprodwellhead.value), + model.wellbores.Pprodwellhead.CurrentUnits.value)) + reservoir_parameters.append(OutputTableItem('Productivity Index', '{0:10.2f}'.format(model.wellbores.PI.value), + model.wellbores.PI.CurrentUnits.value)) + reservoir_parameters.append(OutputTableItem('Injectivity Index', '{0:10.2f}'.format(model.wellbores.II.value), + model.wellbores.II.CurrentUnits.value)) + reservoir_parameters.append(OutputTableItem('Reservoir density', '{0:10.2f}'.format(model.reserv.rhorock.value), + model.reserv.rhorock.CurrentUnits.value)) + if model.wellbores.rameyoptionprod.value or model.reserv.resoption.value in [ + ReservoirModel.MULTIPLE_PARALLEL_FRACTURES, ReservoirModel.LINEAR_HEAT_SWEEP, + ReservoirModel.SINGLE_FRACTURE, ReservoirModel.TOUGH2_SIMULATOR]: + reservoir_parameters.append(OutputTableItem('Reservoir thermal conductivity', '{0:10.2f}'.format(model.reserv.krock.value), + model.reserv.krock.CurrentUnits.value)) + reservoir_parameters.append(OutputTableItem('Reservoir heat capacity', '{0:10.2f}'.format(model.reserv.cprock.value), + model.reserv.cprock.CurrentUnits.value)) + if model.reserv.resoption.value == ReservoirModel.LINEAR_HEAT_SWEEP or ( + model.reserv.resoption.value == ReservoirModel.TOUGH2_SIMULATOR and model.reserv.usebuiltintough2model): + reservoir_parameters.append(OutputTableItem('Reservoir porosity', '{0:10.2f}'.format(model.reserv.porrock.value * 100), + model.reserv.porrock.CurrentUnits.value)) + if model.reserv.resoption.value == ReservoirModel.TOUGH2_SIMULATOR and model.reserv.usebuiltintough2model: + reservoir_parameters.append(OutputTableItem('Reservoir permeability', '{0:10.2E}'.format(model.reserv.permrock.value), + model.reserv.permrock.CurrentUnits.value)) + reservoir_parameters.append(OutputTableItem('Reservoir thickness', '{0:10.2f}'.format(model.reserv.resthickness.value), + model.reserv.resthickness.CurrentUnits.value)) + reservoir_parameters.append(OutputTableItem('Reservoir width', '{0:10.2f}'.format(model.reserv.reswidth.value), + model.reserv.reswidth.CurrentUnits.value)) + reservoir_parameters.append(OutputTableItem('Well separation', '{0:10.2f}'.format(model.wellbores.wellsep.value), + model.wellbores.wellsep.CurrentUnits.value)) + + reservoir_stimulation_results.append(OutputTableItem('Maximum Production Temperature', '{0:10.1f}'.format( + np.max(model.wellbores.ProducedTemperature.value)), model.wellbores.ProducedTemperature.PreferredUnits.value)) + reservoir_stimulation_results.append(OutputTableItem('Average Production Temperature', '{0:10.1f}'.format( + np.average(model.wellbores.ProducedTemperature.value)), model.wellbores.ProducedTemperature.PreferredUnits.value)) + reservoir_stimulation_results.append(OutputTableItem('Minimum Production Temperature', '{0:10.1f}'.format( + np.min(model.wellbores.ProducedTemperature.value)), model.wellbores.ProducedTemperature.PreferredUnits.value)) + reservoir_stimulation_results.append(OutputTableItem('Initial Production Temperature', '{0:10.1f}'.format( + model.wellbores.ProducedTemperature.value[0]), model.wellbores.ProducedTemperature.PreferredUnits.value)) + if model.wellbores.IsAGS.value: + reservoir_stimulation_results.append(OutputTableItem('The AGS models contain an intrinsic reservoir model that doesn\'t expose values that can be used in extensive reporting.')) + else: + reservoir_stimulation_results.append(OutputTableItem('Average Reservoir Heat Extraction', + '{0:10.2f}'.format(np.average( + model.surfaceplant.HeatExtracted.value)), + model.surfaceplant.HeatExtracted.PreferredUnits.value)) + if model.wellbores.rameyoptionprod.value: + reservoir_stimulation_results.append(OutputTableItem('Production Wellbore Heat Transmission Model', 'Ramey Model')) + reservoir_stimulation_results.append(OutputTableItem('Average Production Well Temperature Drop', + '{0:10.1f}'.format(np.average( + model.wellbores.ProdTempDrop.value)), + model.wellbores.ProdTempDrop.PreferredUnits.value)) + else: + reservoir_stimulation_results.append(OutputTableItem('Wellbore Heat Transmission Model = Constant Temperature Drop', + '{0:10.1f}'.format(model.wellbores.tempdropprod.value), + model.wellbores.tempdropprod.PreferredUnits.value)) + if model.wellbores.impedancemodelused.value: + reservoir_stimulation_results.append(OutputTableItem('Total Average Pressure Drop', '{0:10.1f}'.format( + np.average(model.wellbores.DPOverall.value)), model.wellbores.DPOverall.PreferredUnits.value)) + reservoir_stimulation_results.append(OutputTableItem('Average Injection Well Pressure Drop', + '{0:10.1f}'.format( + np.average(model.wellbores.DPInjWell.value)), + model.wellbores.DPInjWell.PreferredUnits.value)) + reservoir_stimulation_results.append(OutputTableItem('Average Reservoir Pressure Drop', + '{0:10.1f}'.format( + np.average(model.wellbores.DPReserv.value)), + model.wellbores.DPReserv.PreferredUnits.value)) + reservoir_stimulation_results.append(OutputTableItem('Average Production Well Pressure Drop', + '{0:10.1f}'.format( + np.average(model.wellbores.DPProdWell.value)), + model.wellbores.DPProdWell.PreferredUnits.value)) + reservoir_stimulation_results.append(OutputTableItem('Average Buoyancy Pressure Drop', + '{0:10.1f}'.format( + np.average(model.wellbores.DPBouyancy.value)), + model.wellbores.DPBouyancy.PreferredUnits.value)) + else: + reservoir_stimulation_results.append(OutputTableItem('Average Injection Well Pump Pressure Drop', + '{0:10.1f}'.format( + np.average(model.wellbores.DPInjWell.value)), + model.wellbores.DPInjWell.PreferredUnits.value)) + if model.wellbores.productionwellpumping.value: + reservoir_stimulation_results.append(OutputTableItem('Average Production Well Pump Pressure Drop', + '{0:10.1f}'.format(np.average( + model.wellbores.DPProdWell.value)), + model.wellbores.DPProdWell.PreferredUnits.value)) + if not model.economics.totalcapcost.Valid: + CAPEX.append(OutputTableItem('Drilling and completion costs', '{0:10.2f}'.format(model.economics.Cwell.value), + model.economics.Cwell.CurrentUnits.value)) + CAPEX.append(OutputTableItem('Drilling and completion costs per well', '{0:10.2f}'.format( + model.economics.Cwell.value / (model.wellbores.nprod.value + model.wellbores.ninj.value)), + model.economics.Cwell.CurrentUnits.value)) + CAPEX.append(OutputTableItem('Stimulation costs', '{0:10.2f}'.format(model.economics.Cstim.value), + model.economics.Cstim.CurrentUnits.value)) + CAPEX.append(OutputTableItem('Surface power plant costs', '{0:10.2f}'.format(model.economics.Cplant.value), + model.economics.Cplant.CurrentUnits.value)) + if model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: + CAPEX.append(OutputTableItem('Absorption Chiller Cost', '{0:10.2f}'.format(model.economics.chillercapex.value), + model.economics.Cplant.CurrentUnits.value)) + if model.surfaceplant.plant_type.value == PlantType.HEAT_PUMP: + CAPEX.append(OutputTableItem('Heat Pump Cost', '{0:10.2f}'.format(model.economics.heatpumpcapex.value), + model.economics.Cplant.CurrentUnits.value)) + if model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING: + CAPEX.append(OutputTableItem('Peaking Boiler Cost', '{0:10.2f}'.format(model.economics.peakingboilercost.value), + model.economics.peakingboilercost.CurrentUnits.value)) + CAPEX.append(OutputTableItem('Field gathering system costs', '{0:10.2f}'.format(model.economics.Cgath.value), + model.economics.Cgath.CurrentUnits.value)) + if model.surfaceplant.piping_length.value > 0: + CAPEX.append(OutputTableItem('Transmission pipeline cost', '{0:10.2f}'.format(model.economics.Cpiping.value), + model.economics.Cpiping.CurrentUnits.value)) + if model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING: + CAPEX.append(OutputTableItem('District Heating System Cost', + '{0:10.2f}'.format(model.economics.dhdistrictcost.value), + model.economics.dhdistrictcost.CurrentUnits.value)) + CAPEX.append(OutputTableItem('Total surface equipment costs', + '{0:10.2f}'.format(model.economics.Cplant.value + model.economics.Cgath.value), + model.economics.Cplant.CurrentUnits.value)) + CAPEX.append(OutputTableItem('Exploration costs', '{0:10.2f}'.format(model.economics.Cexpl.value), + model.economics.Cexpl.CurrentUnits.value)) + if model.economics.totalcapcost.Valid and model.wellbores.redrill.value > 0: + CAPEX.append(OutputTableItem('Drilling and completion costs (for redrilling)', + '{0:10.2f}'.format(model.economics.Cwell.value), + model.economics.Cwell.CurrentUnits.value)) + CAPEX.append(OutputTableItem('Drilling and completion costs per redrilled well', '{0:10.2f}'.format( + model.economics.Cwell.value / (model.wellbores.nprod.value + model.wellbores.ninj.value)), + model.economics.Cwell.CurrentUnits.value)) + CAPEX.append( + OutputTableItem('Stimulation costs (for redrilling)', '{0:10.2f}'.format(model.economics.Cstim.value), + model.economics.Cstim.CurrentUnits.value)) + if model.economics.RITC.Provided: + CAPEX.append(OutputTableItem('Investment tax Credit', '{0:10.2f}'.format(-1*model.economics.RITCValue.value), + model.economics.RITCValue.CurrentUnits.value)) + CAPEX.append(OutputTableItem('Total capital costs', '{0:10.2f}'.format(model.economics.CCap.value), + model.economics.CCap.CurrentUnits.value)) + if model.economics.econmodel.value == EconomicModel.FCR: + CAPEX.append(OutputTableItem('Annualized capital costs', '{0:10.2f}'.format(model.economics.CCap.value * ( + 1 + model.economics.inflrateconstruction.value) * model.economics.FCR.value), + model.economics.CCap.CurrentUnits.value)) + + if not model.economics.oamtotalfixed.Valid: + OPEX.append(OutputTableItem('Wellfield maintenance costs', '{0:10.2f}'.format(model.economics.Coamwell.value), + model.economics.Coamwell.CurrentUnits.value)) + OPEX.append(OutputTableItem('Power plant maintenance costs', '{0:10.2f}'.format(model.economics.Coamplant.value), + model.economics.Coamplant.CurrentUnits.value)) + OPEX.append(OutputTableItem('Water costs', '{0:10.2f}'.format(model.economics.Coamwater.value), + model.economics.Coamwater.CurrentUnits.value)) + if model.surfaceplant.plant_type.value in [PlantType.INDUSTRIAL, PlantType.ABSORPTION_CHILLER, + PlantType.HEAT_PUMP, PlantType.DISTRICT_HEATING]: + OPEX.append(OutputTableItem('Average Reservoir Pumping Cost', + '{0:10.2f}'.format(model.economics.averageannualpumpingcosts.value), + model.economics.averageannualpumpingcosts.CurrentUnits.value)) + if model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: + OPEX.append(OutputTableItem('Absorption Chiller O&M Cost', + '{0:10.2f}'.format(model.economics.chilleropex.value), + model.economics.chilleropex.CurrentUnits.value)) + if model.surfaceplant.plant_type.value == PlantType.HEAT_PUMP: + OPEX.append(OutputTableItem('Average Heat Pump Electricity Cost', '{0:10.2f}'.format( + model.economics.averageannualheatpumpelectricitycost.value), + model.economics.averageannualheatpumpelectricitycost.CurrentUnits.value)) + if model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING: + OPEX.append(OutputTableItem('Annual District Heating O&M Cost', + '{0:10.2f}'.format(model.economics.dhdistrictoandmcost.value), + model.economics.dhdistrictoandmcost.CurrentUnits.value)) + OPEX.append(OutputTableItem('Average Annual Peaking Fuel Cost', + '{0:10.2f}'.format(model.economics.averageannualngcost.value), + model.economics.averageannualngcost.CurrentUnits.value)) + OPEX.append(OutputTableItem('Total operating and maintenance costs', '{0:10.2f}'.format( + model.economics.Coam.value + model.economics.averageannualpumpingcosts.value + model.economics.averageannualheatpumpelectricitycost.value), + model.economics.Coam.CurrentUnits.value)) + else: + OPEX.append(OutputTableItem('Total operating and maintenance costs', '{0:10.2f}'.format(model.economics.Coam.value), + model.economics.Coam.CurrentUnits.value)) + + 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 componenent: + surface_equipment_results.append(OutputTableItem('Initial geofluid availability', '{0:10.2f}'.format( + model.surfaceplant.Availability.value[0]), model.surfaceplant.Availability.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Maximum Total Electricity Generation', '{0:10.2f}'.format( + np.max(model.surfaceplant.ElectricityProduced.value)), model.surfaceplant.ElectricityProduced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Average Total Electricity Generation', '{0:10.2f}'.format( + np.average(model.surfaceplant.ElectricityProduced.value)), model.surfaceplant.ElectricityProduced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Minimum Total Electricity Generation', '{0:10.2f}'.format( + np.min(model.surfaceplant.ElectricityProduced.value)), model.surfaceplant.ElectricityProduced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Initial Total Electricity Generation', '{0:10.2f}'.format( + model.surfaceplant.ElectricityProduced.value[0]), model.surfaceplant.ElectricityProduced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Maximum Net Electricity Generation', '{0:10.2f}'.format( + np.max(model.surfaceplant.NetElectricityProduced.value)), model.surfaceplant.NetElectricityProduced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Average Net Electricity Generation', '{0:10.2f}'.format( + np.average(model.surfaceplant.NetElectricityProduced.value)), model.surfaceplant.NetElectricityProduced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Minimum Net Electricity Generation', '{0:10.2f}'.format( + np.min(model.surfaceplant.NetElectricityProduced.value)), model.surfaceplant.NetElectricityProduced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Initial Net Electricity Generation', '{0:10.2f}'.format( + model.surfaceplant.NetElectricityProduced.value[0]), model.surfaceplant.NetElectricityProduced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Average Annual Total Electricity Generation', + f'{0:10.2f}'.format(np.average(model.surfaceplant.TotalkWhProduced.value / 1E6)), + f'GWh')) + surface_equipment_results.append(OutputTableItem('Average Annual Net Electricity Generation', + f'{0:10.2f}'.format(np.average(model.surfaceplant.NetkWhProduced.value / 1E6)), + f'GWh')) + + if model.wellbores.PumpingPower.value[0] > 0.0: + ipp_nip = model.wellbores.PumpingPower.value[0] / model.surfaceplant.NetElectricityProduced.value[0] + surface_equipment_results.append(OutputTableItem('Initial pumping power/net installed power', '{0:10.2f}'.format(ipp_nip * 100), + '%')) + + if model.surfaceplant.enduse_option.value in [EndUseOptions.HEAT, PlantType.ABSORPTION_CHILLER, + PlantType.HEAT_PUMP, + 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]: # geothermal heating component: + surface_equipment_results.append(OutputTableItem('Maximum Net Heat Production', '{0:10.2f}'.format( + np.max(model.surfaceplant.HeatProduced.value)), model.surfaceplant.HeatProduced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Average Net Heat Production', '{0:10.2f}'.format( + np.average(model.surfaceplant.HeatProduced.value)), model.surfaceplant.HeatProduced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Minimum Net Heat Production', '{0:10.2f}'.format( + np.min(model.surfaceplant.HeatProduced.value)), model.surfaceplant.HeatProduced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Initial Net Heat Production', '{0:10.2f}'.format( + model.surfaceplant.HeatProduced.value[0]), model.surfaceplant.HeatProduced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Average Annual Heat Production', '{0:10.2f}'.format( + np.average(model.surfaceplant.HeatkWhProduced.value / 1E6), 'GWh'))) + + if model.surfaceplant.plant_type.value == PlantType.HEAT_PUMP: + surface_equipment_results.append(OutputTableItem('Average Annual Heat Pump Electricity Use', + '{0:10.2f}'.format(np.average(model.surfaceplant.heat_pump_electricity_kwh_used.value / 1E6), + 'GWh/year'))) + if model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: + surface_equipment_results.append(OutputTableItem('Maximum Cooling Production', '{0:10.2f}'.format( + np.max(model.surfaceplant.cooling_produced.value)), model.surfaceplant.cooling_produced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Average Cooling Production', '{0:10.2f}'.format( + np.average(model.surfaceplant.cooling_produced.value)), + model.surfaceplant.cooling_produced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Minimum Cooling Production', '{0:10.2f}'.format( + np.min(model.surfaceplant.cooling_produced.value)), + model.surfaceplant.cooling_produced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Initial Cooling Production', '{0:10.2f}'.format( + model.surfaceplant.cooling_produced.value[0]), + model.surfaceplant.cooling_produced.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Average Annual Cooling Production', '{0:10.2f}'.format( + np.average(model.surfaceplant.cooling_kWh_Produced.value / 1E6), 'GWh/year'))) + + if model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING: + surface_equipment_results.append(OutputTableItem('Annual District Heating Demand', '{0:10.2f}'.format( + model.surfaceplant.annual_heating_demand.value), model.surfaceplant.annual_heating_demand.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Maximum Daily District Heating Demand', + '{0:10.2f}'.format(np.max(model.surfaceplant.daily_heating_demand.value)), + model.surfaceplant.daily_heating_demand.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Average Daily District Heating Demand', + '{0:10.2f}'.format(np.average(model.surfaceplant.daily_heating_demand.value)), + model.surfaceplant.daily_heating_demand.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Minimum Daily District Heating Demand', + '{0:10.2f}'.format(np.min(model.surfaceplant.daily_heating_demand.value)), + model.surfaceplant.daily_heating_demand.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Maximum Geothermal Heating Production', + '{0:10.2f}'.format(np.max(model.surfaceplant.dh_geothermal_heating.value)), + model.surfaceplant.dh_geothermal_heating.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Average Geothermal Heating Production', + '{0:10.2f}'.format(np.average(model.surfaceplant.dh_geothermal_heating.value)), + model.surfaceplant.dh_geothermal_heating.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Minimum Geothermal Heating Production', + '{0:10.2f}'.format(np.min(model.surfaceplant.dh_geothermal_heating.value)), + model.surfaceplant.dh_geothermal_heating.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Maximum Peaking Boiler Heat Production', + '{0:10.2f}'.format(np.max(model.surfaceplant.dh_natural_gas_heating.value)), + model.surfaceplant.dh_natural_gas_heating.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Average Peaking Boiler Heat Production', + '{0:10.2f}'.format(np.average(model.surfaceplant.dh_natural_gas_heating.value)), + model.surfaceplant.dh_natural_gas_heating.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Minimum Peaking Boiler Heat Production', + '{0:10.2f}'.format(np.min(model.surfaceplant.dh_natural_gas_heating.value)), + model.surfaceplant.dh_natural_gas_heating.PreferredUnits.value)) + surface_equipment_results.append(OutputTableItem('Average Pumping Power', '{0:10.2f}'.format(np.average(model.wellbores.PumpingPower.value)), + model.wellbores.PumpingPower.CurrentUnits.value)) + + # Build the data frame to hold the heating, cooling, and/or electricity production profile + hce: pd.DataFrame = pd.DataFrame() + + # add the columns as needed based on the output. + # Note that the correct format for that column is stashed in the title of that column + # so that it can be used in the write statement. + hce[f'Year|:2.0f'] = [i for i in range(1, (model.surfaceplant.plant_lifetime.value + 1))] + short_pt = ShortenArrayToAnnual(model.wellbores.ProducedTemperature.value, + model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) + hce[f'Thermal Drawdown (%)|:8.4f'] = short_pt / short_pt[0] + + hce[ + f'Geofluid Temperature ({model.wellbores.ProducedTemperature.CurrentUnits.value})|:8.2f'] = ShortenArrayToAnnual( + model.wellbores.ProducedTemperature.value, + model.surfaceplant.plant_lifetime.value, model.economics.timestepsperyear.value) + hce[f'Pump Power ({model.wellbores.PumpingPower.CurrentUnits.value})|:8.4f'] = ShortenArrayToAnnual( + model.wellbores.PumpingPower.value, + model.surfaceplant.plant_lifetime.value, model.economics.timestepsperyear.value) + + # only electricity + if model.surfaceplant.enduse_option.value == EndUseOptions.ELECTRICITY: + hce[ + f'Net Power ({model.surfaceplant.NetElectricityProduced.CurrentUnits.value})|:8.4f'] = ShortenArrayToAnnual( + model.surfaceplant.NetElectricityProduced.value, + model.surfaceplant.plant_lifetime.value, model.economics.timestepsperyear.value) + hce[f'First Law Efficiency (%)|:8.4f'] = ShortenArrayToAnnual( + model.surfaceplant.FirstLawEfficiency.value * 100, + model.surfaceplant.plant_lifetime.value, model.economics.timestepsperyear.value) + + # only direct-use + elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and \ + model.surfaceplant.plant_type.value not in \ + [PlantType.HEAT_PUMP, PlantType.DISTRICT_HEATING, PlantType.ABSORPTION_CHILLER]: + hce[f'Net Heat ({model.surfaceplant.HeatProduced.CurrentUnits.value})|:8.4f'] = \ + ShortenArrayToAnnual(model.surfaceplant.HeatProduced.value, + model.surfaceplant.plant_lifetime.value, model.economics.timestepsperyear.value) + + # heat pump + elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and \ + model.surfaceplant.plant_type.value in [PlantType.HEAT_PUMP]: + hce[f'Net Heat ({model.surfaceplant.HeatProduced.CurrentUnits.value})|:8.4f'] = \ + ShortenArrayToAnnual(model.surfaceplant.HeatProduced.value, + model.surfaceplant.plant_lifetime.value, model.economics.timestepsperyear.value) + hce[ + f'Heat Pump Electricity Used ({model.surfaceplant.heat_pump_electricity_used.CurrentUnits.value}|:8.4f'] = \ + ShortenArrayToAnnual(model.surfaceplant.heat_pump_electricity_used.value, + model.surfaceplant.plant_lifetime.value, model.economics.timestepsperyear.value) + + # district heating + elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT \ + and model.surfaceplant.plant_type.value in [PlantType.DISTRICT_HEATING]: + hce[f'Geothermal Heat Output ({model.surfaceplant.HeatProduced.CurrentUnits.value})|:8.4f'] = \ + ShortenArrayToAnnual(model.surfaceplant.HeatProduced.value, + model.surfaceplant.plant_lifetime.value, model.economics.timestepsperyear.value) + + # absorption chiller + elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and \ + model.surfaceplant.plant_type.value in [PlantType.ABSORPTION_CHILLER]: + hce[f'Net Heat ({model.surfaceplant.HeatProduced.CurrentUnits.value})|:8.4f'] = \ + ShortenArrayToAnnual(model.surfaceplant.HeatProduced.value, + model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) + hce[f'Net Cooling ({model.surfaceplant.HeatProduced.CurrentUnits.value})|:8.4f'] = \ + ShortenArrayToAnnual(model.surfaceplant.cooling_produced.value, + model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) + + # co-generation + elif model.surfaceplant.enduse_option.value in [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]: + hce[f'Net Power ({model.surfaceplant.NetElectricityProduced.CurrentUnits.value})|:8.4f'] = \ + ShortenArrayToAnnual(model.surfaceplant.NetElectricityProduced.value, + model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) + hce[f'Net Heat ({model.surfaceplant.HeatProduced.CurrentUnits.value})|:8.4f'] = \ + ShortenArrayToAnnual(model.surfaceplant.HeatProduced.value, model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) + hce[f'First Law Efficiency (%)|:8.4f'] = ShortenArrayToAnnual(model.surfaceplant.FirstLawEfficiency.value, + model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) * 100 + hce = hce.reset_index() + + # Build the data frame to hold the annual heating, cooling, and/or electricity production profile + ahce: pd.DataFrame = pd.DataFrame() + + # add the columns as needed based on the output. + # Note that the correct format for that column is stashed in the title of that column + # so that it can be used in the write statement. + ahce[f'Year|:2.0f'] = [i for i in range(1, (model.surfaceplant.plant_lifetime.value + 1))] + + # only electricity + if model.surfaceplant.enduse_option.value == EndUseOptions.ELECTRICITY: + ahce[f'Electricity Provided ({model.surfaceplant.NetkWhProduced.CurrentUnits.value})|:8.1f'] = \ + model.surfaceplant.NetkWhProduced.value / 1E6 + + # absorption chiller + elif model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: + ahce[f'Cooling Provided ({model.surfaceplant.cooling_kWh_Produced.CurrentUnits.value})|:8.1f'] = \ + ShortenArrayToAnnual(model.surfaceplant.cooling_kWh_Produced.value, + model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) / 1E6 + + # heat pump + elif model.surfaceplant.plant_type.value == PlantType.HEAT_PUMP: + ahce[f'Heating Provided ({model.surfaceplant.HeatkWhProduced.CurrentUnits.value})|:8.1f'] = \ + ShortenArrayToAnnual(model.surfaceplant.HeatkWhProduced.value, model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) / 1E6 + ahce[f'Reservoir Heat Extracted ({model.surfaceplant.HeatkWhExtracted.CurrentUnits.value})|:8.1f'] = \ + ShortenArrayToAnnual(model.surfaceplant.HeatkWhExtracted.value, model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) / 1E6 + ahce[ + f'Heat Pump Electricity Used ({model.surfaceplant.heat_pump_electricity_kwh_used.CurrentUnits.value})|:8.1f'] = \ + ShortenArrayToAnnual(model.surfaceplant.heat_pump_electricity_kwh_used.value, + model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) / 1E6 + + # co-generation + elif model.surfaceplant.enduse_option.value in [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]: + ahce[f'Heating Provided ({model.surfaceplant.HeatkWhProduced.CurrentUnits.value})|:8.1f'] = \ + ShortenArrayToAnnual(model.surfaceplant.HeatkWhProduced.value, + model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) / 1E6 + ahce[f'Electricity Provided ({model.surfaceplant.NetkWhProduced.CurrentUnits.value})|:8.1f'] = \ + ShortenArrayToAnnual(model.surfaceplant.NetkWhProduced.value, + model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) / 1E6 + + # district-heating + elif model.surfaceplant.plant_type.value in [PlantType.DISTRICT_HEATING]: + ahce[f'Electricity Provided ({model.surfaceplant.HeatkWhProduced.CurrentUnits.value})|:8.1f'] = \ + ShortenArrayToAnnual(model.surfaceplant.HeatkWhProduced.value, + model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) / 1E6 + ahce[f'Peaking Boiler Heat Provided ({model.surfaceplant.annual_ng_demand.CurrentUnits.value})|:8.1f'] = \ + ShortenArrayToAnnual(model.surfaceplant.annual_ng_demand.value, + model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) / 1E3 + + elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT: # only direct-use + ahce[f'Heating Provided ({model.surfaceplant.HeatkWhProduced.CurrentUnits.value})|:8.1f'] = \ + ShortenArrayToAnnual(model.surfaceplant.HeatkWhProduced.value, model.surfaceplant.plant_lifetime.value, + model.economics.timestepsperyear.value) / 1E6 + + # three columns always at the end of each style of table + ahce[f'Heat Extracted({model.surfaceplant.HeatkWhExtracted.CurrentUnits.value})|:8.2f'] = \ + model.surfaceplant.HeatkWhExtracted.value / 1E6 + ahce[f'Reservoir Heat Content ({model.surfaceplant.RemainingReservoirHeatContent.CurrentUnits.value})|:8.2f'] = \ + model.surfaceplant.RemainingReservoirHeatContent.value + ahce[f'Percentage of Total Heat Mined (%)|:8.2f'] = \ + ( + model.reserv.InitialReservoirHeatContent.value - model.surfaceplant.RemainingReservoirHeatContent.value) * 100. \ + / model.reserv.InitialReservoirHeatContent.value + ahce = ahce.reset_index() + + # Build the data frame to hold the revenue and cashflow profile + econ: Economics = model.economics + # create a Coam array and zero out the OPEX during construction years + construction_years_zeros = np.zeros(model.surfaceplant.construction_years.value) + Coam = np.zeros(model.surfaceplant.construction_years.value + model.surfaceplant.plant_lifetime.value) + for ii in range(model.surfaceplant.construction_years.value, model.surfaceplant.plant_lifetime.value + 1): + Coam[ii] = econ.Coam.value + + cashflow: pd.DataFrame = pd.DataFrame() + + # add the columns as needed based on the output. + # Note that the correct format for that column is stashed in the title of that column + # so that it can be used in the write statement. + # note that the price arrays need to be extended by the number of construction years. with price = 0 + cashflow[f'Year|:3.0f'] = [i for i in range(1, + model.surfaceplant.plant_lifetime.value + model.surfaceplant.construction_years.value + 1)] + cashflow[f'Electricity:Price ({econ.ElecPrice.CurrentUnits.value})|:7.4f'] = econ.ElecPrice.value + cashflow[f'Electricity:Ann. Rev. ({econ.ElecRevenue.CurrentUnits.value})|:5.2f'] = econ.ElecRevenue.value + cashflow[ + f'Electricity:Cumm. Rev. ({econ.ElecCummRevenue.CurrentUnits.value})|:5.2f'] = econ.ElecCummRevenue.value + cashflow[f'Heat:Price ({econ.HeatPrice.CurrentUnits.value})|:7.4f'] = econ.HeatPrice.value + cashflow[f'Heat:Ann. Rev. ({econ.HeatRevenue.CurrentUnits.value})|:5.2f'] = econ.HeatRevenue.value + cashflow[f'Heat:Cumm. Rev. ({econ.HeatCummRevenue.CurrentUnits.value})|:5.2f'] = econ.HeatCummRevenue.value + cashflow[f'Cooling:Price ({econ.CoolingPrice.CurrentUnits.value})|:7.4f'] = econ.CoolingPrice.value + cashflow[f'Cooling:Ann. Rev. ({econ.CoolingRevenue.CurrentUnits.value})|:5.2f'] = econ.CoolingRevenue.value + cashflow[ + f'Cooling:Cumm. Rev. ({econ.CoolingCummRevenue.CurrentUnits.value})|:5.2f'] = econ.CoolingCummRevenue.value + cashflow[f'Carbon:Price ({econ.CarbonPrice.CurrentUnits.value})|:7.4f'] = econ.CarbonPrice.value + cashflow[f'Carbon:Ann. Rev. ({econ.CarbonRevenue.CurrentUnits.value})|:5.2f'] = econ.CarbonRevenue.value + cashflow[ + f'Carbon:Cumm. Rev. ({econ.CarbonCummCashFlow.CurrentUnits.value})|:5.2f'] = econ.CarbonCummCashFlow.value + cashflow[f'Project:OPEX ({econ.Coam.CurrentUnits.value})|:5.2f'] = Coam + cashflow[f'Project:Net Rev. ({econ.TotalRevenue.CurrentUnits.value})|:5.2f'] = econ.TotalRevenue.value + cashflow[ + f'Project:Net Cashflow ({econ.TotalCummRevenue.CurrentUnits.value})|:5.2f'] = econ.TotalCummRevenue.value + cashflow = cashflow.reset_index() + + addon_df = pd.DataFrame() + sdac_df = pd.DataFrame() + addon_results: list[OutputTableItem] = [] + sdac_results: list[OutputTableItem] = [] # write results to output file and screen - try: with open(self.output_file, 'w', encoding='UTF-8') as f: f.write(' *****************\n') f.write(' ***CASE REPORT***\n') f.write(' *****************\n') f.write(NL) - f.write("Simulation Metadata\n") - f.write("----------------------\n") + f.write('Simulation Metadata\n') + f.write('----------------------\n') f.write(f' GEOPHIRES Version: {geophires_x.__version__}\n') - f.write(" GEOPHIRES Build Date: 2024-03-05\n") # FIXME TODO https://github.com/NREL/GEOPHIRES-X/issues/139 - f.write(" Simulation Date: "+ datetime.datetime.now().strftime("%Y-%m-%d\n")) - f.write(" Simulation Time: "+ datetime.datetime.now().strftime("%H:%M\n")) - f.write(" Calculation Time: "+"{0:10.3f}".format((time.time()-model.tic)) + " sec\n") + f.write(' GEOPHIRES Build Date: 2024-03-05\n') # FIXME TODO https://github.com/NREL/GEOPHIRES-X/issues/139 + f.write(' Simulation Date: '+ datetime.datetime.now().strftime('%Y-%m-%d\n')) + f.write(' Simulation Time: '+ datetime.datetime.now().strftime('%H:%M\n')) + f.write(' Calculation Time: '+'{0:10.3f}'.format((time.time()-model.tic)) + ' sec\n') 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(' End-Use Option: ' + str(model.surfaceplant.enduse_option.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 - f.write(f" Average Net Electricity Production: {np.average(model.surfaceplant.NetElectricityProduced.value):10.2f} " + model.surfaceplant.NetElectricityProduced.CurrentUnits.value + NL) + f.write(f' Average Net Electricity Production: {np.average(model.surfaceplant.NetElectricityProduced.value):10.2f} ' + model.surfaceplant.NetElectricityProduced.CurrentUnits.value + NL) if model.surfaceplant.enduse_option.value != EndUseOptions.ELECTRICITY: # there is a direct-use component - f.write(f" Average Direct-Use Heat Production: {np.average(model.surfaceplant.HeatProduced.value):10.2f} "+ model.surfaceplant.HeatProduced.CurrentUnits.value + NL) + f.write(f' Average Direct-Use Heat Production: {np.average(model.surfaceplant.HeatProduced.value):10.2f} '+ model.surfaceplant.HeatProduced.CurrentUnits.value + NL) if model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING: - f.write(f" Annual District Heating Demand: {np.average(model.surfaceplant.annual_heating_demand.value):10.2f} " + model.surfaceplant.annual_heating_demand.CurrentUnits.value + NL) - f.write(f" Average Annual Geothermal Heat Production: {sum(model.surfaceplant.dh_geothermal_heating.value * 24) / model.surfaceplant.plant_lifetime.value / 1e3:10.2f} " + model.surfaceplant.annual_heating_demand.CurrentUnits.value + NL) - f.write(f" Average Annual Peaking Fuel Heat Production: {sum(model.surfaceplant.dh_natural_gas_heating.value * 24) / model.surfaceplant.plant_lifetime.value / 1e3:10.2f} " + model.surfaceplant.annual_heating_demand.CurrentUnits.value + NL) + f.write(f' Annual District Heating Demand: {np.average(model.surfaceplant.annual_heating_demand.value):10.2f} ' + model.surfaceplant.annual_heating_demand.CurrentUnits.value + NL) + f.write(f' Average Annual Geothermal Heat Production: {sum(model.surfaceplant.dh_geothermal_heating.value * 24) / model.surfaceplant.plant_lifetime.value / 1e3:10.2f} ' + model.surfaceplant.annual_heating_demand.CurrentUnits.value + NL) + f.write(f' Average Annual Peaking Fuel Heat Production: {sum(model.surfaceplant.dh_natural_gas_heating.value * 24) / model.surfaceplant.plant_lifetime.value / 1e3:10.2f} ' + model.surfaceplant.annual_heating_demand.CurrentUnits.value + NL) if model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: - f.write(f" Average Cooling Production: {np.average(model.surfaceplant.cooling_produced.value):10.2f} " + model.surfaceplant.cooling_produced.CurrentUnits.value + NL) + f.write(f' Average Cooling Production: {np.average(model.surfaceplant.cooling_produced.value):10.2f} ' + model.surfaceplant.cooling_produced.CurrentUnits.value + NL) if model.surfaceplant.enduse_option.value in [EndUseOptions.ELECTRICITY]: - f.write(f" Electricity breakeven price: {model.economics.LCOE.value:10.2f} " + model.economics.LCOE.CurrentUnits.value + NL) + f.write(f' Electricity breakeven price: {model.economics.LCOE.value:10.2f} ' + model.economics.LCOE.CurrentUnits.value + NL) elif model.surfaceplant.enduse_option.value in [EndUseOptions.HEAT] and \ model.surfaceplant.plant_type.value not in [PlantType.ABSORPTION_CHILLER]: - f.write(f" Direct-Use heat breakeven price (LCOH): {model.economics.LCOH.value:10.2f} " + model.economics.LCOH.CurrentUnits.value + NL) + f.write(f' Direct-Use heat breakeven price (LCOH): {model.economics.LCOH.value:10.2f} ' + model.economics.LCOH.CurrentUnits.value + NL) elif model.surfaceplant.enduse_option.value in [EndUseOptions.HEAT] and model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: - f.write(f" Direct-Use Cooling Breakeven Price (LCOC): {model.economics.LCOC.value:10.2f} " + model.economics.LCOC.CurrentUnits.value + NL) + f.write(f' Direct-Use Cooling Breakeven Price (LCOC): {model.economics.LCOC.value:10.2f} ' + model.economics.LCOC.CurrentUnits.value + NL) elif model.surfaceplant.enduse_option.value in [EndUseOptions.COGENERATION_TOPPING_EXTRA_HEAT, EndUseOptions.COGENERATION_BOTTOMING_EXTRA_HEAT, EndUseOptions.COGENERATION_PARALLEL_EXTRA_HEAT, EndUseOptions.COGENERATION_TOPPING_EXTRA_ELECTRICITY, EndUseOptions.COGENERATION_BOTTOMING_EXTRA_ELECTRICITY, EndUseOptions.COGENERATION_PARALLEL_EXTRA_ELECTRICITY]: - f.write(f" Electricity breakeven price: {model.economics.LCOE.value:10.2f} " + model.economics.LCOE.CurrentUnits.value + NL) - f.write(f" Direct-Use heat breakeven price (LCOH): {model.economics.LCOH.value:10.2f} " + model.economics.LCOH.CurrentUnits.value + NL) + f.write(f' Electricity breakeven price: {model.economics.LCOE.value:10.2f} ' + model.economics.LCOE.CurrentUnits.value + NL) + f.write(f' Direct-Use heat breakeven price (LCOH): {model.economics.LCOH.value:10.2f} ' + model.economics.LCOH.CurrentUnits.value + NL) - f.write(f" Number of production wells: {model.wellbores.nprod.value:10.0f}"+NL) - f.write(f" Number of injection wells: {model.wellbores.ninj.value:10.0f}"+NL) - f.write(f" Flowrate per production well: {model.wellbores.prodwellflowrate.value:10.1f} " + model.wellbores.prodwellflowrate.CurrentUnits.value + NL) - f.write(f" Well depth (or total length, if not vertical): {model.reserv.depth.value:10.1f} " +model.reserv.depth.CurrentUnits.value + NL) + f.write(f' Number of production wells: {model.wellbores.nprod.value:10.0f}'+NL) + f.write(f' Number of injection wells: {model.wellbores.ninj.value:10.0f}'+NL) + f.write(f' Flowrate per production well: {model.wellbores.prodwellflowrate.value:10.1f} ' + model.wellbores.prodwellflowrate.CurrentUnits.value + NL) + f.write(f' Well depth (or total length, if not vertical): {model.reserv.depth.value:10.1f} ' +model.reserv.depth.CurrentUnits.value + NL) if model.reserv.numseg.value == 1: - f.write(f" Geothermal gradient: {model.reserv.gradient.value[0]:10.4f} " + model.reserv.gradient.CurrentUnits.value + NL) + f.write(f' Geothermal gradient: {model.reserv.gradient.value[0]:10.4f} ' + model.reserv.gradient.CurrentUnits.value + NL) else: for i in range(1, model.reserv.numseg.value): - f.write(f" Segment {str(i):s} Geothermal gradient: {model.reserv.gradient.value[i-1]:10.4f} " + model.reserv.gradient.CurrentUnits.value +NL) - f.write(f" Segment {str(i):s} Thickness: {model.reserv.layerthickness.value[i-1]:10.0f} " + model.reserv.layerthickness.CurrentUnits.value + NL) - f.write(f" Segment {str(i+1):s} Geothermal gradient: {model.reserv.gradient.value[i]:10.4f} " + model.reserv.gradient.CurrentUnits.value + NL) + f.write(f' Segment {str(i):s} Geothermal gradient: {model.reserv.gradient.value[i-1]:10.4f} ' + model.reserv.gradient.CurrentUnits.value +NL) + f.write(f' Segment {str(i):s} Thickness: {model.reserv.layerthickness.value[i-1]:10.0f} ' + model.reserv.layerthickness.CurrentUnits.value + NL) + f.write(f' Segment {str(i+1):s} Geothermal gradient: {model.reserv.gradient.value[i]:10.4f} ' + model.reserv.gradient.CurrentUnits.value + NL) if model.economics.DoCarbonCalculations.value: - f.write(f" Total Avoided Carbon Emissions: {model.economics.CarbonThatWouldHaveBeenProducedTotal.value*0.000453592:10.2f} metric tonnes" + NL) + f.write(f' Total Avoided Carbon Emissions: {model.economics.CarbonThatWouldHaveBeenProducedTotal.value*0.000453592:10.2f} metric tonnes' + NL) f.write(NL) f.write(NL) f.write(' ***ECONOMIC PARAMETERS***\n') f.write(NL) if model.economics.econmodel.value == EconomicModel.FCR: - f.write(" Economic Model = " + model.economics.econmodel.value.value + NL) - f.write(f" Fixed Charge Rate (FCR): {model.economics.FCR.value*100.0:10.2f} " + model.economics.FCR.CurrentUnits.value + NL) + f.write(' Economic Model = ' + model.economics.econmodel.value.value + NL) + f.write(f' Fixed Charge Rate (FCR): {model.economics.FCR.value*100.0:10.2f} ' + model.economics.FCR.CurrentUnits.value + NL) elif model.economics.econmodel.value == EconomicModel.STANDARDIZED_LEVELIZED_COST: - f.write(" Economic Model = " + model.economics.econmodel.value.value + NL) - f.write(f" Interest Rate: {model.economics.discountrate.value*100.0:10.2f} " + model.economics.discountrate.CurrentUnits.value + NL) + f.write(' Economic Model = ' + model.economics.econmodel.value.value + NL) + f.write(f' Interest Rate: {model.economics.discountrate.value*100.0:10.2f} ' + model.economics.discountrate.CurrentUnits.value + NL) elif model.economics.econmodel.value == EconomicModel.BICYCLE: - f.write(" Economic Model = " + model.economics.econmodel.value.value + NL) - f.write(f" Accrued financing during construction: {model.economics.inflrateconstruction.value*100:10.2f} " + model.economics.inflrateconstruction.CurrentUnits.value + NL) - f.write(f" Project lifetime: {model.surfaceplant.plant_lifetime.value:10.0f} " + model.surfaceplant.plant_lifetime.CurrentUnits.value + NL) - f.write(f" Capacity factor: {model.surfaceplant.utilization_factor.value * 100:10.1f} %" + NL) - f.write(f" Project NPV: {model.economics.ProjectNPV.value:10.2f} " + model.economics.ProjectNPV.PreferredUnits.value + NL) - f.write(f" Project IRR: {model.economics.ProjectIRR.value:10.2f} " + model.economics.ProjectIRR.PreferredUnits.value + NL) - f.write(f" Project VIR=PI=PIR: {model.economics.ProjectVIR.value:10.2f}" + NL) - f.write(f" Project MOIC: {model.economics.ProjectMOIC.value:10.2f}" + NL) + f.write(' Economic Model = ' + model.economics.econmodel.value.value + NL) + f.write(f' Accrued financing during construction: {model.economics.inflrateconstruction.value*100:10.2f} ' + model.economics.inflrateconstruction.CurrentUnits.value + NL) + f.write(f' Project lifetime: {model.surfaceplant.plant_lifetime.value:10.0f} ' + model.surfaceplant.plant_lifetime.CurrentUnits.value + NL) + f.write(f' Capacity factor: {model.surfaceplant.utilization_factor.value * 100:10.1f} %' + NL) + f.write(f' Project NPV: {model.economics.ProjectNPV.value:10.2f} ' + model.economics.ProjectNPV.PreferredUnits.value + NL) + f.write(f' Project IRR: {model.economics.ProjectIRR.value:10.2f} ' + model.economics.ProjectIRR.PreferredUnits.value + NL) + f.write(f' Project VIR=PI=PIR: {model.economics.ProjectVIR.value:10.2f}' + NL) + f.write(f' Project MOIC: {model.economics.ProjectMOIC.value:10.2f}' + NL) payback_period_val = model.economics.ProjectPaybackPeriod.value project_payback_period_display = f'{payback_period_val:10.2f} {model.economics.ProjectPaybackPeriod.PreferredUnits.value}' \ @@ -198,76 +1590,73 @@ def PrintOutputs(self, model: Model): EndUseOptions.COGENERATION_TOPPING_EXTRA_ELECTRICITY, EndUseOptions.COGENERATION_BOTTOMING_EXTRA_ELECTRICITY, EndUseOptions.COGENERATION_PARALLEL_EXTRA_ELECTRICITY]: - f.write(f" CHP: Percent cost allocation for electrical plant: {model.economics.CAPEX_heat_electricity_plant_ratio.value*100.0:10.2f}%" + NL) + f.write(f' CHP: Percent cost allocation for electrical plant: {model.economics.CAPEX_heat_electricity_plant_ratio.value*100.0:10.2f}%' + NL) f.write(NL) f.write(' ***ENGINEERING PARAMETERS***\n') f.write(NL) - f.write(f" Number of Production Wells: {model.wellbores.nprod.value:10.0f}" + NL) - f.write(f" Number of Injection Wells: {model.wellbores.ninj.value:10.0f}" + NL) - f.write(f" Well depth (or total length, if not vertical): {model.reserv.depth.value:10.1f} " + model.reserv.depth.CurrentUnits.value + NL) - f.write(f" Water loss rate: {model.reserv.waterloss.value*100:10.1f} " + model.reserv.waterloss.CurrentUnits.value + NL) - f.write(f" Pump efficiency: {model.surfaceplant.pump_efficiency.value * 100:10.1f} " + model.surfaceplant.pump_efficiency.CurrentUnits.value + NL) - f.write(f" Injection temperature: {model.wellbores.Tinj.value:10.1f} " + model.wellbores.Tinj.CurrentUnits.value + NL) + f.write(f' Number of Production Wells: {model.wellbores.nprod.value:10.0f}' + NL) + f.write(f' Number of Injection Wells: {model.wellbores.ninj.value:10.0f}' + NL) + f.write(f' Well depth (or total length, if not vertical): {model.reserv.depth.value:10.1f} ' + model.reserv.depth.CurrentUnits.value + NL) + f.write(f' Water loss rate: {model.reserv.waterloss.value*100:10.1f} ' + model.reserv.waterloss.CurrentUnits.value + NL) + f.write(f' Pump efficiency: {model.surfaceplant.pump_efficiency.value * 100:10.1f} ' + model.surfaceplant.pump_efficiency.CurrentUnits.value + NL) + f.write(f' Injection temperature: {model.wellbores.Tinj.value:10.1f} ' + model.wellbores.Tinj.CurrentUnits.value + NL) if model.wellbores.rameyoptionprod.value: - f.write(" Production Wellbore heat transmission calculated with Ramey's model\n") - f.write(f" Average production well temperature drop: {np.average(model.wellbores.ProdTempDrop.value):10.1f} " + model.wellbores.ProdTempDrop.PreferredUnits.value + NL) + f.write(' Production Wellbore heat transmission calculated with Ramey\'s model\n') + f.write(f' Average production well temperature drop: {np.average(model.wellbores.ProdTempDrop.value):10.1f} ' + model.wellbores.ProdTempDrop.PreferredUnits.value + NL) else: - f.write(" User-provided production well temperature drop\n") - f.write(f" Constant production well temperature drop: {model.wellbores.tempdropprod.value:10.1f} " + model.wellbores.tempdropprod.PreferredUnits.value + NL) - f.write(f" Flowrate per production well: {model.wellbores.prodwellflowrate.value:10.1f} " + model.wellbores.prodwellflowrate.CurrentUnits.value + NL) - f.write(f" Injection well casing ID: {model.wellbores.injwelldiam.value:10.3f} " + model.wellbores.injwelldiam.CurrentUnits.value + NL) - f.write(f" Production well casing ID: {model.wellbores.prodwelldiam.value:10.3f} " + model.wellbores.prodwelldiam.CurrentUnits.value + NL) - f.write(f" Number of times redrilling: {model.wellbores.redrill.value:10.0f}"+NL) + f.write(' User-provided production well temperature drop\n') + f.write(f' Constant production well temperature drop: {model.wellbores.tempdropprod.value:10.1f} ' + model.wellbores.tempdropprod.PreferredUnits.value + NL) + f.write(f' Flowrate per production well: {model.wellbores.prodwellflowrate.value:10.1f} ' + model.wellbores.prodwellflowrate.CurrentUnits.value + NL) + f.write(f' Injection well casing ID: {model.wellbores.injwelldiam.value:10.3f} ' + model.wellbores.injwelldiam.CurrentUnits.value + NL) + f.write(f' Production well casing ID: {model.wellbores.prodwelldiam.value:10.3f} ' + model.wellbores.prodwelldiam.CurrentUnits.value + NL) + f.write(f' Number of times redrilling: {model.wellbores.redrill.value:10.0f}'+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]: - f.write(" Power plant type: " + str(model.surfaceplant.plant_type.value.value) + NL) + f.write(' Power plant type: ' + str(model.surfaceplant.plant_type.value.value) + NL) f.write(NL) f.write(NL) f.write(' ***RESOURCE CHARACTERISTICS***\n') f.write(NL) - f.write(f" Maximum reservoir temperature: {model.reserv.Tmax.value:10.1f} " + model.reserv.Tmax.CurrentUnits.value + NL) - f.write(f" Number of segments: {model.reserv.numseg.value:10.0f} " + NL) + f.write(f' Maximum reservoir temperature: {model.reserv.Tmax.value:10.1f} ' + model.reserv.Tmax.CurrentUnits.value + NL) + f.write(f' Number of segments: {model.reserv.numseg.value:10.0f} ' + NL) if model.reserv.numseg.value == 1: - f.write(f" Geothermal gradient: {model.reserv.gradient.value[0]:10.4f} " + model.reserv.gradient.CurrentUnits.value + NL) + f.write(f' Geothermal gradient: {model.reserv.gradient.value[0]:10.4f} ' + model.reserv.gradient.CurrentUnits.value + NL) else: for i in range(1, model.reserv.numseg.value): - f.write(f" Segment {str(i):s} Geothermal gradient: {model.reserv.gradient.value[i-1]:10.4f} " + model.reserv.gradient.CurrentUnits.value +NL) - f.write(f" Segment {str(i):s} Thickness: {model.reserv.layerthickness.value[i-1]:10.0f} " + model.reserv.layerthickness.CurrentUnits.value + NL) - f.write(f" Segment {str(i+1):s} Geothermal gradient: {model.reserv.gradient.value[i]:10.4f} " + model.reserv.gradient.CurrentUnits.value + NL) - - + f.write(f' Segment {str(i):s} Geothermal gradient: {model.reserv.gradient.value[i-1]:10.4f} ' + model.reserv.gradient.CurrentUnits.value +NL) + f.write(f' Segment {str(i):s} Thickness: {model.reserv.layerthickness.value[i-1]:10.0f} ' + model.reserv.layerthickness.CurrentUnits.value + NL) + f.write(f' Segment {str(i+1):s} Geothermal gradient: {model.reserv.gradient.value[i]:10.4f} ' + model.reserv.gradient.CurrentUnits.value + NL) f.write(NL) f.write(NL) f.write(' ***RESERVOIR PARAMETERS***\n') f.write(NL) if model.wellbores.IsAGS.value: - f.write("The AGS models contain an intrinsic reservoir model that doesn't expose values that can be used in extensive reporting." + NL) + f.write('The AGS models contain an intrinsic reservoir model that doesn\'t expose values that can be used in extensive reporting.' + NL) else: - f.write(" Reservoir Model = " + str(model.reserv.resoption.value.value) + " Model\n") + f.write(' Reservoir Model = ' + str(model.reserv.resoption.value.value) + ' Model\n') if model.reserv.resoption.value == ReservoirModel.SINGLE_FRACTURE: - f.write(f" m/A Drawdown Parameter: {model.reserv.drawdp.value:.5f} " + model.reserv.drawdp.CurrentUnits.value + NL) + f.write(f' m/A Drawdown Parameter: {model.reserv.drawdp.value:.5f} ' + model.reserv.drawdp.CurrentUnits.value + NL) elif model.reserv.resoption.value == ReservoirModel.ANNUAL_PERCENTAGE: - f.write(f" Annual Thermal Drawdown: {model.reserv.drawdp.value*100:.3f} " + model.reserv.drawdp.CurrentUnits.value + NL) - - f.write(f" Bottom-hole temperature: {model.reserv.Trock.value:10.2f} " + model.reserv.Trock.CurrentUnits.value + NL) + f.write(f' Annual Thermal Drawdown: {model.reserv.drawdp.value*100:.3f} ' + model.reserv.drawdp.CurrentUnits.value + NL) + f.write(f' Bottom-hole temperature: {model.reserv.Trock.value:10.2f} ' + model.reserv.Trock.CurrentUnits.value + NL) if model.reserv.resoption.value in [ReservoirModel.ANNUAL_PERCENTAGE, ReservoirModel.USER_PROVIDED_PROFILE, ReservoirModel.TOUGH2_SIMULATOR]: f.write(' Warning: the reservoir dimensions and thermo-physical properties \n') f.write(' listed below are default values if not provided by the user. \n') f.write(' They are only used for calculating remaining heat content. \n') if model.reserv.resoption.value in [ReservoirModel.MULTIPLE_PARALLEL_FRACTURES, ReservoirModel.LINEAR_HEAT_SWEEP]: - f.write(" Fracture model = " + model.reserv.fracshape.value.value + NL) + f.write(' Fracture model = ' + model.reserv.fracshape.value.value + NL) if model.reserv.fracshape.value == FractureShape.CIRCULAR_AREA: - f.write(f" Well seperation: fracture diameter: {model.reserv.fracheightcalc.value:10.2f} " + model.reserv.fracheight.CurrentUnits.value + NL) + f.write(f' Well separation: fracture diameter: {model.reserv.fracheightcalc.value:10.2f} ' + model.reserv.fracheight.CurrentUnits.value + NL) elif model.reserv.fracshape.value == FractureShape.CIRCULAR_DIAMETER: - f.write(f" Well seperation: fracture diameter: {model.reserv.fracheightcalc.value:10.2f} " + model.reserv.fracheight.CurrentUnits.value + NL) + f.write(f' Well separation: fracture diameter: {model.reserv.fracheightcalc.value:10.2f} ' + model.reserv.fracheight.CurrentUnits.value + NL) elif model.reserv.fracshape.value == FractureShape.SQUARE: - f.write(f" Well seperation: fracture height: {model.reserv.fracheightcalc.value:10.2f} " + model.reserv.fracheight.CurrentUnits.value + NL) + f.write(f' Well separation: fracture height: {model.reserv.fracheightcalc.value:10.2f} ' + model.reserv.fracheight.CurrentUnits.value + NL) elif model.reserv.fracshape.value == FractureShape.RECTANGULAR: - f.write(f" Well seperation: fracture height: {model.reserv.fracheightcalc.value:10.2f} " + model.reserv.fracheight.CurrentUnits.value + NL) - f.write(f" Fracture width: {model.reserv.fracwidthcalc.value:10.2f} " + model.reserv.fracwidth.CurrentUnits.value + NL) - f.write(f" Fracture area: {model.reserv.fracareacalc.value:10.2f} " + model.reserv.fracarea.CurrentUnits.value + NL) + f.write(f' Well separation: fracture height: {model.reserv.fracheightcalc.value:10.2f} ' + model.reserv.fracheight.CurrentUnits.value + NL) + f.write(f' Fracture width: {model.reserv.fracwidthcalc.value:10.2f} ' + model.reserv.fracwidth.CurrentUnits.value + NL) + f.write(f' Fracture area: {model.reserv.fracareacalc.value:10.2f} ' + model.reserv.fracarea.CurrentUnits.value + NL) if model.reserv.resvoloption.value == ReservoirVolume.FRAC_NUM_SEP: f.write(' Reservoir volume calculated with fracture separation and number of fractures as input\n') elif model.reserv.resvoloption.value == ReservoirVolume.RES_VOL_FRAC_SEP: @@ -277,161 +1666,163 @@ def PrintOutputs(self, model: Model): elif model.reserv.resvoloption.value == ReservoirVolume.RES_VOL_ONLY: f.write(' Reservoir volume provided as input\n') if model.reserv.resvoloption.value in [ReservoirVolume.FRAC_NUM_SEP, ReservoirVolume.RES_VOL_FRAC_SEP,ReservoirVolume.FRAC_NUM_SEP]: - f.write(f" Number of fractures: {model.reserv.fracnumbcalc.value:10.2f}" + NL) - f.write(f" Fracture separation: {model.reserv.fracsepcalc.value:10.2f} " + model.reserv.fracsep.CurrentUnits.value + NL) - f.write(f" Reservoir volume: {model.reserv.resvolcalc.value:10.0f} " + model.reserv.resvol.CurrentUnits.value + NL) + f.write(f' Number of fractures: {model.reserv.fracnumbcalc.value:10.2f}' + NL) + f.write(f' Fracture separation: {model.reserv.fracsepcalc.value:10.2f} ' + model.reserv.fracsep.CurrentUnits.value + NL) + f.write(f' Reservoir volume: {model.reserv.resvolcalc.value:10.0f} ' + model.reserv.resvol.CurrentUnits.value + NL) if model.wellbores.impedancemodelused.value: - f.write(f" Reservoir impedance: {model.wellbores.impedance.value/1000:10.2f} " + model.wellbores.impedance.CurrentUnits.value + NL) + f.write(f' Reservoir impedance: {model.wellbores.impedance.value/1000:10.2f} ' + model.wellbores.impedance.CurrentUnits.value + NL) else: - f.write(f" Reservoir hydrostatic pressure: {model.wellbores.Phydrostaticcalc.value:10.2f} " + model.wellbores.Phydrostaticcalc.CurrentUnits.value + NL) - f.write(f" Plant outlet pressure: {model.surfaceplant.plant_outlet_pressure.value:10.2f} " + model.surfaceplant.plant_outlet_pressure.CurrentUnits.value + NL) + f.write(f' Reservoir hydrostatic pressure: {model.wellbores.Phydrostaticcalc.value:10.2f} ' + model.wellbores.Phydrostaticcalc.CurrentUnits.value + NL) + f.write(f' Plant outlet pressure: {model.surfaceplant.plant_outlet_pressure.value:10.2f} ' + model.surfaceplant.plant_outlet_pressure.CurrentUnits.value + NL) if model.wellbores.productionwellpumping.value: - f.write(f" Production wellhead pressure: {model.wellbores.Pprodwellhead.value:10.2f} " + model.wellbores.Pprodwellhead.CurrentUnits.value + NL) - f.write(f" Productivity Index: {model.wellbores.PI.value:10.2f} " + model.wellbores.PI.CurrentUnits.value + NL) - f.write(f" Injectivity Index: {model.wellbores.II.value:10.2f} " + model.wellbores.II.CurrentUnits.value + NL) + f.write(f' Production wellhead pressure: {model.wellbores.Pprodwellhead.value:10.2f} ' + model.wellbores.Pprodwellhead.CurrentUnits.value + NL) + f.write(f' Productivity Index: {model.wellbores.PI.value:10.2f} ' + model.wellbores.PI.CurrentUnits.value + NL) + f.write(f' Injectivity Index: {model.wellbores.II.value:10.2f} ' + model.wellbores.II.CurrentUnits.value + NL) - f.write(f" Reservoir density: {model.reserv.rhorock.value:10.2f} " + model.reserv.rhorock.CurrentUnits.value + NL) + f.write(f' Reservoir density: {model.reserv.rhorock.value:10.2f} ' + model.reserv.rhorock.CurrentUnits.value + NL) if model.wellbores.rameyoptionprod.value or model.reserv.resoption.value in [ReservoirModel.MULTIPLE_PARALLEL_FRACTURES, ReservoirModel.LINEAR_HEAT_SWEEP, ReservoirModel.SINGLE_FRACTURE, ReservoirModel.TOUGH2_SIMULATOR]: - f.write(f" Reservoir thermal conductivity: {model.reserv.krock.value:10.2f} {model.reserv.krock.CurrentUnits.value}{NL}") - f.write(f" Reservoir heat capacity: {model.reserv.cprock.value:10.2f} " + model.reserv.cprock.CurrentUnits.value + NL) + f.write(f' Reservoir thermal conductivity: {model.reserv.krock.value:10.2f} {model.reserv.krock.CurrentUnits.value}{NL}') + f.write(f' Reservoir heat capacity: {model.reserv.cprock.value:10.2f} ' + model.reserv.cprock.CurrentUnits.value + NL) if model.reserv.resoption.value == ReservoirModel.LINEAR_HEAT_SWEEP or (model.reserv.resoption.value == ReservoirModel.TOUGH2_SIMULATOR and model.reserv.usebuiltintough2model): - f.write(f" Reservoir porosity: {model.reserv.porrock.value*100:10.2f} " + model.reserv.porrock.CurrentUnits.value + NL) + f.write(f' Reservoir porosity: {model.reserv.porrock.value*100:10.2f} ' + model.reserv.porrock.CurrentUnits.value + NL) if model.reserv.resoption.value == ReservoirModel.TOUGH2_SIMULATOR and model.reserv.usebuiltintough2model: - f.write(f" Reservoir permeability: {model.reserv.permrock.value:10.2E} " + model.reserv.permrock.CurrentUnits.value + NL) - f.write(f" Reservoir thickness: {model.reserv.resthickness.value:10.2f} " + model.reserv.resthickness.CurrentUnits.value + NL) - f.write(f" Reservoir width: {model.reserv.reswidth.value:10.2f} " + model.reserv.reswidth.CurrentUnits.value + NL) - f.write(f" Well separation: {model.wellbores.wellsep.value:10.2f} " + model.wellbores.wellsep.CurrentUnits.value + NL) + f.write(f' Reservoir permeability: {model.reserv.permrock.value:10.2E} ' + model.reserv.permrock.CurrentUnits.value + NL) + f.write(f' Reservoir thickness: {model.reserv.resthickness.value:10.2f} ' + model.reserv.resthickness.CurrentUnits.value + NL) + f.write(f' Reservoir width: {model.reserv.reswidth.value:10.2f} ' + model.reserv.reswidth.CurrentUnits.value + NL) + f.write(f' Well separation: {model.wellbores.wellsep.value:10.2f} ' + model.wellbores.wellsep.CurrentUnits.value + NL) f.write(NL) f.write(NL) - f.write(" ***RESERVOIR SIMULATION RESULTS***" + NL) + f.write(' ***RESERVOIR SIMULATION RESULTS***' + NL) f.write(NL) - f.write(f" Maximum Production Temperature: {np.max(model.wellbores.ProducedTemperature.value):10.1f} " + model.wellbores.ProducedTemperature.PreferredUnits.value + NL) - f.write(f" Average Production Temperature: {np.average(model.wellbores.ProducedTemperature.value):10.1f} " + model.wellbores.ProducedTemperature.PreferredUnits.value + NL) - f.write(f" Minimum Production Temperature: {np.min(model.wellbores.ProducedTemperature.value):10.1f} " + model.wellbores.ProducedTemperature.PreferredUnits.value + NL) - f.write(f" Initial Production Temperature: {model.wellbores.ProducedTemperature.value[0]:10.1f} " + model.wellbores.ProducedTemperature.PreferredUnits.value + NL) + f.write(f' Maximum Production Temperature: {np.max(model.wellbores.ProducedTemperature.value):10.1f} ' + model.wellbores.ProducedTemperature.PreferredUnits.value + NL) + f.write(f' Average Production Temperature: {np.average(model.wellbores.ProducedTemperature.value):10.1f} ' + model.wellbores.ProducedTemperature.PreferredUnits.value + NL) + f.write(f' Minimum Production Temperature: {np.min(model.wellbores.ProducedTemperature.value):10.1f} ' + model.wellbores.ProducedTemperature.PreferredUnits.value + NL) + f.write(f' Initial Production Temperature: {model.wellbores.ProducedTemperature.value[0]:10.1f} ' + model.wellbores.ProducedTemperature.PreferredUnits.value + NL) if model.wellbores.IsAGS.value: - f.write("The AGS models contain an intrinsic reservoir model that doesn't expose values that can be used in extensive reporting." + NL) + f.write('The AGS models contain an intrinsic reservoir model that doesn\'t expose values that can be used in extensive reporting.' + NL) else: - f.write(f" Average Reservoir Heat Extraction: {np.average(model.surfaceplant.HeatExtracted.value):10.2f} " + model.surfaceplant.HeatExtracted.PreferredUnits.value + NL) + f.write(f' Average Reservoir Heat Extraction: {np.average(model.surfaceplant.HeatExtracted.value):10.2f} ' + model.surfaceplant.HeatExtracted.PreferredUnits.value + NL) if model.wellbores.rameyoptionprod.value: - f.write(" Production Wellbore Heat Transmission Model = Ramey Model" + NL) - f.write(f" Average Production Well Temperature Drop: {np.average(model.wellbores.ProdTempDrop.value):10.1f} " + model.wellbores.ProdTempDrop.PreferredUnits.value + NL) + f.write(' Production Wellbore Heat Transmission Model = Ramey Model' + NL) + f.write(f' Average Production Well Temperature Drop: {np.average(model.wellbores.ProdTempDrop.value):10.1f} ' + model.wellbores.ProdTempDrop.PreferredUnits.value + NL) else: - f.write(f" Wellbore Heat Transmission Model = Constant Temperature Drop:{model.wellbores.tempdropprod.value:10.1f} " + model.wellbores.tempdropprod.PreferredUnits.value + NL) + f.write(f' Wellbore Heat Transmission Model = Constant Temperature Drop:{model.wellbores.tempdropprod.value:10.1f} ' + model.wellbores.tempdropprod.PreferredUnits.value + NL) if model.wellbores.impedancemodelused.value: - f.write(f" Total Average Pressure Drop: {np.average(model.wellbores.DPOverall.value):10.1f} " + model.wellbores.DPOverall.PreferredUnits.value + NL) - f.write(f" Average Injection Well Pressure Drop: {np.average(model.wellbores.DPInjWell.value):10.1f} " + model.wellbores.DPInjWell.PreferredUnits.value + NL) - f.write(f" Average Reservoir Pressure Drop: {np.average(model.wellbores.DPReserv.value):10.1f} " + model.wellbores.DPReserv.PreferredUnits.value + NL) - f.write(f" Average Production Well Pressure Drop: {np.average(model.wellbores.DPProdWell.value):10.1f} " + model.wellbores.DPProdWell.PreferredUnits.value + NL) - f.write(f" Average Buoyancy Pressure Drop: {np.average(model.wellbores.DPBouyancy.value):10.1f} " + model.wellbores.DPBouyancy.PreferredUnits.value + NL) + f.write(f' Total Average Pressure Drop: {np.average(model.wellbores.DPOverall.value):10.1f} ' + model.wellbores.DPOverall.PreferredUnits.value + NL) + f.write(f' Average Injection Well Pressure Drop: {np.average(model.wellbores.DPInjWell.value):10.1f} ' + model.wellbores.DPInjWell.PreferredUnits.value + NL) + f.write(f' Average Reservoir Pressure Drop: {np.average(model.wellbores.DPReserv.value):10.1f} ' + model.wellbores.DPReserv.PreferredUnits.value + NL) + f.write(f' Average Production Well Pressure Drop: {np.average(model.wellbores.DPProdWell.value):10.1f} ' + model.wellbores.DPProdWell.PreferredUnits.value + NL) + f.write(f' Average Buoyancy Pressure Drop: {np.average(model.wellbores.DPBouyancy.value):10.1f} ' + model.wellbores.DPBouyancy.PreferredUnits.value + NL) else: - f.write(f" Average Injection Well Pump Pressure Drop: {np.average(model.wellbores.DPInjWell.value):10.1f} " + model.wellbores.DPInjWell.PreferredUnits.value + NL) + f.write(f' Average Injection Well Pump Pressure Drop: {np.average(model.wellbores.DPInjWell.value):10.1f} ' + model.wellbores.DPInjWell.PreferredUnits.value + NL) if model.wellbores.productionwellpumping.value: - f.write(f" Average Production Well Pump Pressure Drop: {np.average(model.wellbores.DPProdWell.value):10.1f} " + model.wellbores.DPProdWell.PreferredUnits.value + NL) + f.write(f' Average Production Well Pump Pressure Drop: {np.average(model.wellbores.DPProdWell.value):10.1f} ' + model.wellbores.DPProdWell.PreferredUnits.value + NL) f.write(NL) f.write(NL) f.write(' ***CAPITAL COSTS (M$)***\n') f.write(NL) if not model.economics.totalcapcost.Valid: - f.write(f" Drilling and completion costs: {model.economics.Cwell.value:10.2f} " + model.economics.Cwell.CurrentUnits.value + NL) - f.write(f" Drilling and completion costs per well: {model.economics.Cwell.value/(model.wellbores.nprod.value+model.wellbores.ninj.value):10.2f} " + model.economics.Cwell.CurrentUnits.value + NL) - f.write(f" Stimulation costs: {model.economics.Cstim.value:10.2f} " + model.economics.Cstim.CurrentUnits.value + NL) - f.write(f" Surface power plant costs: {model.economics.Cplant.value:10.2f} " + model.economics.Cplant.CurrentUnits.value + NL) + f.write(f' Drilling and completion costs: {model.economics.Cwell.value:10.2f} ' + model.economics.Cwell.CurrentUnits.value + NL) + f.write(f' Drilling and completion costs per well: {model.economics.Cwell.value/(model.wellbores.nprod.value+model.wellbores.ninj.value):10.2f} ' + model.economics.Cwell.CurrentUnits.value + NL) + f.write(f' Stimulation costs: {model.economics.Cstim.value:10.2f} ' + model.economics.Cstim.CurrentUnits.value + NL) + f.write(f' Surface power plant costs: {model.economics.Cplant.value:10.2f} ' + model.economics.Cplant.CurrentUnits.value + NL) 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) + 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: - f.write(f" of which Heat Pump Cost: {model.economics.heatpumpcapex.value:10.2f} " + model.economics.Cplant.CurrentUnits.value + NL) + f.write(f' of which Heat Pump Cost: {model.economics.heatpumpcapex.value:10.2f} ' + model.economics.Cplant.CurrentUnits.value + NL) if model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING: - f.write(f" of which Peaking Boiler Cost: {model.economics.peakingboilercost.value:10.2f} " + model.economics.peakingboilercost.CurrentUnits.value + NL) - f.write(f" Field gathering system costs: {model.economics.Cgath.value:10.2f} " + model.economics.Cgath.CurrentUnits.value + NL) - if model.surfaceplant.piping_length.value > 0: f.write(f" Transmission pipeline cost {model.economics.Cpiping.value:10.2f} " + model.economics.Cpiping.CurrentUnits.value + NL) + f.write(f' of which Peaking Boiler Cost: {model.economics.peakingboilercost.value:10.2f} ' + model.economics.peakingboilercost.CurrentUnits.value + NL) + f.write(f' Field gathering system costs: {model.economics.Cgath.value:10.2f} ' + model.economics.Cgath.CurrentUnits.value + NL) + if model.surfaceplant.piping_length.value > 0: + f.write(f' Transmission pipeline cost {model.economics.Cpiping.value:10.2f} ' + model.economics.Cpiping.CurrentUnits.value + NL) if model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING: - f.write(f" District Heating System Cost: {model.economics.dhdistrictcost.value:10.2f} " + model.economics.dhdistrictcost.CurrentUnits.value + NL) - f.write(f" Total surface equipment costs: {(model.economics.Cplant.value+model.economics.Cgath.value):10.2f} " + model.economics.Cplant.CurrentUnits.value + NL) - f.write(f" Exploration costs: {model.economics.Cexpl.value:10.2f} " + model.economics.Cexpl.CurrentUnits.value + NL) + f.write(f' District Heating System Cost: {model.economics.dhdistrictcost.value:10.2f} ' + model.economics.dhdistrictcost.CurrentUnits.value + NL) + f.write(f' Total surface equipment costs: {(model.economics.Cplant.value+model.economics.Cgath.value):10.2f} ' + model.economics.Cplant.CurrentUnits.value + NL) + f.write(f' Exploration costs: {model.economics.Cexpl.value:10.2f} ' + model.economics.Cexpl.CurrentUnits.value + NL) if model.economics.totalcapcost.Valid and model.wellbores.redrill.value > 0: - f.write(f" Drilling and completion costs (for redrilling):{model.economics.Cwell.value:10.2f} " + model.economics.Cwell.CurrentUnits.value + NL) - f.write(f" Drilling and completion costs per redrilled well: {(model.economics.Cwell.value/(model.wellbores.nprod.value+model.wellbores.ninj.value)):10.2f} " + model.economics.Cwell.CurrentUnits.value + NL) - f.write(f" Stimulation costs (for redrilling): {model.economics.Cstim.value:10.2f} " + model.economics.Cstim.CurrentUnits.value + NL) - f.write(f" Total capital costs: {model.economics.CCap.value:10.2f} " + model.economics.CCap.CurrentUnits.value + NL) + f.write(f' Drilling and completion costs (for redrilling):{model.economics.Cwell.value:10.2f} ' + model.economics.Cwell.CurrentUnits.value + NL) + f.write(f' Drilling and completion costs per redrilled well: {(model.economics.Cwell.value/(model.wellbores.nprod.value+model.wellbores.ninj.value)):10.2f} ' + model.economics.Cwell.CurrentUnits.value + NL) + f.write(f' Stimulation costs (for redrilling): {model.economics.Cstim.value:10.2f} ' + model.economics.Cstim.CurrentUnits.value + NL) + if model.economics.RITCValue.value: + f.write(f' Investment Tax Credit: {-1*model.economics.RITCValue.value:10.2f} ' + model.economics.RITCValue.CurrentUnits.value + NL) + f.write(f' Total capital costs: {model.economics.CCap.value:10.2f} ' + model.economics.CCap.CurrentUnits.value + NL) if model.economics.econmodel.value == EconomicModel.FCR: - f.write(f" Annualized capital costs: {(model.economics.CCap.value*(1+model.economics.inflrateconstruction.value)*model.economics.FCR.value):10.2f} " + model.economics.CCap.CurrentUnits.value + NL) + f.write(f' Annualized capital costs: {(model.economics.CCap.value*(1+model.economics.inflrateconstruction.value)*model.economics.FCR.value):10.2f} ' + model.economics.CCap.CurrentUnits.value + NL) f.write(NL) f.write(NL) f.write(' ***OPERATING AND MAINTENANCE COSTS (M$/yr)***\n') f.write(NL) if not model.economics.oamtotalfixed.Valid: - f.write(f" Wellfield maintenance costs: {model.economics.Coamwell.value:10.2f} " + model.economics.Coamwell.CurrentUnits.value + NL) - f.write(f" Power plant maintenance costs: {model.economics.Coamplant.value:10.2f} " + model.economics.Coamplant.CurrentUnits.value + NL) - f.write(f" Water costs: {model.economics.Coamwater.value:10.2f} " + model.economics.Coamwater.CurrentUnits.value + NL) + f.write(f' Wellfield maintenance costs: {model.economics.Coamwell.value:10.2f} ' + model.economics.Coamwell.CurrentUnits.value + NL) + f.write(f' Power plant maintenance costs: {model.economics.Coamplant.value:10.2f} ' + model.economics.Coamplant.CurrentUnits.value + NL) + f.write(f' Water costs: {model.economics.Coamwater.value:10.2f} ' + model.economics.Coamwater.CurrentUnits.value + NL) if model.surfaceplant.plant_type.value in [PlantType.INDUSTRIAL, PlantType.ABSORPTION_CHILLER, PlantType.HEAT_PUMP, PlantType.DISTRICT_HEATING]: - f.write(f" Average Reservoir Pumping Cost: {model.economics.averageannualpumpingcosts.value:10.2f} " + model.economics.averageannualpumpingcosts.CurrentUnits.value + NL) + f.write(f' Average Reservoir Pumping Cost: {model.economics.averageannualpumpingcosts.value:10.2f} ' + model.economics.averageannualpumpingcosts.CurrentUnits.value + NL) if model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: - f.write(f" Absorption Chiller O&M Cost: {model.economics.chilleropex.value:10.2f} " + model.economics.chilleropex.CurrentUnits.value + NL) + f.write(f' Absorption Chiller O&M Cost: {model.economics.chilleropex.value:10.2f} ' + model.economics.chilleropex.CurrentUnits.value + NL) if model.surfaceplant.plant_type.value == PlantType.HEAT_PUMP: - f.write(f" Average Heat Pump Electricity Cost: {model.economics.averageannualheatpumpelectricitycost.value:10.2f} " + model.economics.averageannualheatpumpelectricitycost.CurrentUnits.value + NL) + f.write(f' Average Heat Pump Electricity Cost: {model.economics.averageannualheatpumpelectricitycost.value:10.2f} ' + model.economics.averageannualheatpumpelectricitycost.CurrentUnits.value + NL) if model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING: - f.write(f" Annual District Heating O&M Cost: {model.economics.dhdistrictoandmcost.value:10.2f} " + model.economics.dhdistrictoandmcost.CurrentUnits.value + NL) - f.write(f" Average Annual Peaking Fuel Cost: {model.economics.averageannualngcost.value:10.2f} " + model.economics.averageannualngcost.CurrentUnits.value + NL) + f.write(f' Annual District Heating O&M Cost: {model.economics.dhdistrictoandmcost.value:10.2f} ' + model.economics.dhdistrictoandmcost.CurrentUnits.value + NL) + f.write(f' Average Annual Peaking Fuel Cost: {model.economics.averageannualngcost.value:10.2f} ' + model.economics.averageannualngcost.CurrentUnits.value + NL) - f.write(f" Total operating and maintenance costs: {(model.economics.Coam.value + model.economics.averageannualpumpingcosts.value+model.economics.averageannualheatpumpelectricitycost.value):10.2f} " + model.economics.Coam.CurrentUnits.value + NL) + f.write(f' Total operating and maintenance costs: {(model.economics.Coam.value + model.economics.averageannualpumpingcosts.value+model.economics.averageannualheatpumpelectricitycost.value):10.2f} ' + model.economics.Coam.CurrentUnits.value + NL) else: - f.write(f" Total operating and maintenance costs: {model.economics.Coam.value:10.2f} " + model.economics.Coam.CurrentUnits.value + NL) + f.write(f' Total operating and maintenance costs: {model.economics.Coam.value:10.2f} ' + model.economics.Coam.CurrentUnits.value + NL) f.write(NL) f.write(NL) f.write(' ***SURFACE EQUIPMENT SIMULATION RESULTS***\n') f.write(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 componenent: - f.write(f" Initial geofluid availability: {model.surfaceplant.Availability.value[0]:10.2f} " + model.surfaceplant.Availability.PreferredUnits.value + NL) - f.write(f" Maximum Total Electricity Generation: {np.max(model.surfaceplant.ElectricityProduced.value):10.2f} " + model.surfaceplant.ElectricityProduced.PreferredUnits.value + NL) - f.write(f" Average Total Electricity Generation: {np.average(model.surfaceplant.ElectricityProduced.value):10.2f} " + model.surfaceplant.ElectricityProduced.PreferredUnits.value + NL) - f.write(f" Minimum Total Electricity Generation: {np.min(model.surfaceplant.ElectricityProduced.value):10.2f} " + model.surfaceplant.ElectricityProduced.PreferredUnits.value + NL) - f.write(f" Initial Total Electricity Generation: {model.surfaceplant.ElectricityProduced.value[0]:10.2f} " + model.surfaceplant.ElectricityProduced.PreferredUnits.value + NL) - f.write(f" Maximum Net Electricity Generation: {np.max(model.surfaceplant.NetElectricityProduced.value):10.2f} " + model.surfaceplant.NetElectricityProduced.PreferredUnits.value + NL) - f.write(f" Average Net Electricity Generation: {np.average(model.surfaceplant.NetElectricityProduced.value):10.2f} " + model.surfaceplant.NetElectricityProduced.PreferredUnits.value + NL) - f.write(f" Minimum Net Electricity Generation: {np.min(model.surfaceplant.NetElectricityProduced.value):10.2f} " + model.surfaceplant.NetElectricityProduced.PreferredUnits.value + NL) - f.write(f" Initial Net Electricity Generation: {model.surfaceplant.NetElectricityProduced.value[0]:10.2f} " + model.surfaceplant.NetElectricityProduced.PreferredUnits.value + NL) - f.write(f" Average Annual Total Electricity Generation: {np.average(model.surfaceplant.TotalkWhProduced.value/1E6):10.2f} GWh" + NL) - f.write(f" Average Annual Net Electricity Generation: {np.average(model.surfaceplant.NetkWhProduced.value/1E6):10.2f} GWh" + NL) + f.write(f' Initial geofluid availability: {model.surfaceplant.Availability.value[0]:10.2f} ' + model.surfaceplant.Availability.PreferredUnits.value + NL) + f.write(f' Maximum Total Electricity Generation: {np.max(model.surfaceplant.ElectricityProduced.value):10.2f} ' + model.surfaceplant.ElectricityProduced.PreferredUnits.value + NL) + f.write(f' Average Total Electricity Generation: {np.average(model.surfaceplant.ElectricityProduced.value):10.2f} ' + model.surfaceplant.ElectricityProduced.PreferredUnits.value + NL) + f.write(f' Minimum Total Electricity Generation: {np.min(model.surfaceplant.ElectricityProduced.value):10.2f} ' + model.surfaceplant.ElectricityProduced.PreferredUnits.value + NL) + f.write(f' Initial Total Electricity Generation: {model.surfaceplant.ElectricityProduced.value[0]:10.2f} ' + model.surfaceplant.ElectricityProduced.PreferredUnits.value + NL) + f.write(f' Maximum Net Electricity Generation: {np.max(model.surfaceplant.NetElectricityProduced.value):10.2f} ' + model.surfaceplant.NetElectricityProduced.PreferredUnits.value + NL) + f.write(f' Average Net Electricity Generation: {np.average(model.surfaceplant.NetElectricityProduced.value):10.2f} ' + model.surfaceplant.NetElectricityProduced.PreferredUnits.value + NL) + f.write(f' Minimum Net Electricity Generation: {np.min(model.surfaceplant.NetElectricityProduced.value):10.2f} ' + model.surfaceplant.NetElectricityProduced.PreferredUnits.value + NL) + f.write(f' Initial Net Electricity Generation: {model.surfaceplant.NetElectricityProduced.value[0]:10.2f} ' + model.surfaceplant.NetElectricityProduced.PreferredUnits.value + NL) + f.write(f' Average Annual Total Electricity Generation: {np.average(model.surfaceplant.TotalkWhProduced.value/1E6):10.2f} GWh' + NL) + f.write(f' Average Annual Net Electricity Generation: {np.average(model.surfaceplant.NetkWhProduced.value/1E6):10.2f} GWh' + NL) if model.wellbores.PumpingPower.value[0] > 0.0: ipp_nip = model.wellbores.PumpingPower.value[0] / model.surfaceplant.NetElectricityProduced.value[0] f.write(f' Initial pumping power/net installed power: {(ipp_nip*100):10.2f} %\n') if model.surfaceplant.enduse_option.value in [EndUseOptions.HEAT, PlantType.ABSORPTION_CHILLER, PlantType.HEAT_PUMP, 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]: # geothermal heating component: - f.write(f" Maximum Net Heat Production: {np.max(model.surfaceplant.HeatProduced.value):10.2f} " + model.surfaceplant.HeatProduced.PreferredUnits.value + NL) - f.write(f" Average Net Heat Production: {np.average(model.surfaceplant.HeatProduced.value):10.2f} " + model.surfaceplant.HeatProduced.PreferredUnits.value + NL) - f.write(f" Minimum Net Heat Production: {np.min(model.surfaceplant.HeatProduced.value):10.2f} " + model.surfaceplant.HeatProduced.PreferredUnits.value + NL) - f.write(f" Initial Net Heat Production: {model.surfaceplant.HeatProduced.value[0]:10.2f} " + model.surfaceplant.HeatProduced.PreferredUnits.value + NL) - f.write(f" Average Annual Heat Production: {np.average(model.surfaceplant.HeatkWhProduced.value/1E6):10.2f} GWh" + NL) + f.write(f' Maximum Net Heat Production: {np.max(model.surfaceplant.HeatProduced.value):10.2f} ' + model.surfaceplant.HeatProduced.PreferredUnits.value + NL) + f.write(f' Average Net Heat Production: {np.average(model.surfaceplant.HeatProduced.value):10.2f} ' + model.surfaceplant.HeatProduced.PreferredUnits.value + NL) + f.write(f' Minimum Net Heat Production: {np.min(model.surfaceplant.HeatProduced.value):10.2f} ' + model.surfaceplant.HeatProduced.PreferredUnits.value + NL) + f.write(f' Initial Net Heat Production: {model.surfaceplant.HeatProduced.value[0]:10.2f} ' + model.surfaceplant.HeatProduced.PreferredUnits.value + NL) + f.write(f' Average Annual Heat Production: {np.average(model.surfaceplant.HeatkWhProduced.value/1E6):10.2f} GWh' + NL) if model.surfaceplant.plant_type.value == PlantType.HEAT_PUMP: - f.write(f" Average Annual Heat Pump Electricity Use: {np.average(model.surfaceplant.heat_pump_electricity_kwh_used.value / 1E6):10.2f} " + "GWh/year" + NL) + f.write(f' Average Annual Heat Pump Electricity Use: {np.average(model.surfaceplant.heat_pump_electricity_kwh_used.value / 1E6):10.2f} ' + 'GWh/year' + NL) if model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: - f.write(f" Maximum Cooling Production: {np.max(model.surfaceplant.cooling_produced.value):10.2f} " + model.surfaceplant.cooling_produced.PreferredUnits.value + NL) - f.write(f" Average Cooling Production: {np.average(model.surfaceplant.cooling_produced.value):10.2f} " + model.surfaceplant.cooling_produced.PreferredUnits.value + NL) - f.write(f" Minimum Cooling Production: {np.min(model.surfaceplant.cooling_produced.value):10.2f} " + model.surfaceplant.cooling_produced.PreferredUnits.value + NL) - f.write(f" Initial Cooling Production: {model.surfaceplant.cooling_produced.value[0]:10.2f} " + model.surfaceplant.cooling_produced.PreferredUnits.value + NL) - f.write(f" Average Annual Cooling Production: {np.average(model.surfaceplant.cooling_kWh_Produced.value / 1E6):10.2f} " + "GWh/year" + NL) + f.write(f' Maximum Cooling Production: {np.max(model.surfaceplant.cooling_produced.value):10.2f} ' + model.surfaceplant.cooling_produced.PreferredUnits.value + NL) + f.write(f' Average Cooling Production: {np.average(model.surfaceplant.cooling_produced.value):10.2f} ' + model.surfaceplant.cooling_produced.PreferredUnits.value + NL) + f.write(f' Minimum Cooling Production: {np.min(model.surfaceplant.cooling_produced.value):10.2f} ' + model.surfaceplant.cooling_produced.PreferredUnits.value + NL) + f.write(f' Initial Cooling Production: {model.surfaceplant.cooling_produced.value[0]:10.2f} ' + model.surfaceplant.cooling_produced.PreferredUnits.value + NL) + f.write(f' Average Annual Cooling Production: {np.average(model.surfaceplant.cooling_kWh_Produced.value / 1E6):10.2f} ' + 'GWh/year' + NL) if model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING: - f.write(f" Annual District Heating Demand: {model.surfaceplant.annual_heating_demand.value:10.2f} " + model.surfaceplant.annual_heating_demand.PreferredUnits.value + NL) - f.write(f" Maximum Daily District Heating Demand: {np.max(model.surfaceplant.daily_heating_demand.value):10.2f} " + model.surfaceplant.daily_heating_demand.PreferredUnits.value + NL) - f.write(f" Average Daily District Heating Demand: {np.average(model.surfaceplant.daily_heating_demand.value):10.2f} " + model.surfaceplant.daily_heating_demand.PreferredUnits.value + NL) - f.write(f" Minimum Daily District Heating Demand: {np.min(model.surfaceplant.daily_heating_demand.value):10.2f} " + model.surfaceplant.daily_heating_demand.PreferredUnits.value + NL) - f.write(f" Maximum Geothermal Heating Production: {np.max(model.surfaceplant.dh_geothermal_heating.value):10.2f} " + model.surfaceplant.dh_geothermal_heating.PreferredUnits.value + NL) - f.write(f" Average Geothermal Heating Production: {np.average(model.surfaceplant.dh_geothermal_heating.value):10.2f} " + model.surfaceplant.dh_geothermal_heating.PreferredUnits.value + NL) - f.write(f" Minimum Geothermal Heating Production: {np.min(model.surfaceplant.dh_geothermal_heating.value):10.2f} " + model.surfaceplant.dh_geothermal_heating.PreferredUnits.value + NL) - f.write(f" Maximum Peaking Boiler Heat Production: {np.max(model.surfaceplant.dh_natural_gas_heating.value):10.2f} " + model.surfaceplant.dh_natural_gas_heating.PreferredUnits.value + NL) - f.write(f" Average Peaking Boiler Heat Production: {np.average(model.surfaceplant.dh_natural_gas_heating.value):10.2f} " + model.surfaceplant.dh_natural_gas_heating.PreferredUnits.value + NL) - f.write(f" Minimum Peaking Boiler Heat Production: {np.min(model.surfaceplant.dh_natural_gas_heating.value):10.2f} " + model.surfaceplant.dh_natural_gas_heating.PreferredUnits.value + NL) - - f.write(f" Average Pumping Power: {np.average(model.wellbores.PumpingPower.value):10.2f} {model.wellbores.PumpingPower.CurrentUnits.value}{NL}") - + f.write(f' Annual District Heating Demand: {model.surfaceplant.annual_heating_demand.value:10.2f} ' + model.surfaceplant.annual_heating_demand.PreferredUnits.value + NL) + f.write(f' Maximum Daily District Heating Demand: {np.max(model.surfaceplant.daily_heating_demand.value):10.2f} ' + model.surfaceplant.daily_heating_demand.PreferredUnits.value + NL) + f.write(f' Average Daily District Heating Demand: {np.average(model.surfaceplant.daily_heating_demand.value):10.2f} ' + model.surfaceplant.daily_heating_demand.PreferredUnits.value + NL) + f.write(f' Minimum Daily District Heating Demand: {np.min(model.surfaceplant.daily_heating_demand.value):10.2f} ' + model.surfaceplant.daily_heating_demand.PreferredUnits.value + NL) + f.write(f' Maximum Geothermal Heating Production: {np.max(model.surfaceplant.dh_geothermal_heating.value):10.2f} ' + model.surfaceplant.dh_geothermal_heating.PreferredUnits.value + NL) + f.write(f' Average Geothermal Heating Production: {np.average(model.surfaceplant.dh_geothermal_heating.value):10.2f} ' + model.surfaceplant.dh_geothermal_heating.PreferredUnits.value + NL) + f.write(f' Minimum Geothermal Heating Production: {np.min(model.surfaceplant.dh_geothermal_heating.value):10.2f} ' + model.surfaceplant.dh_geothermal_heating.PreferredUnits.value + NL) + f.write(f' Maximum Peaking Boiler Heat Production: {np.max(model.surfaceplant.dh_natural_gas_heating.value):10.2f} ' + model.surfaceplant.dh_natural_gas_heating.PreferredUnits.value + NL) + f.write(f' Average Peaking Boiler Heat Production: {np.average(model.surfaceplant.dh_natural_gas_heating.value):10.2f} ' + model.surfaceplant.dh_natural_gas_heating.PreferredUnits.value + NL) + f.write(f' Minimum Peaking Boiler Heat Production: {np.min(model.surfaceplant.dh_natural_gas_heating.value):10.2f} ' + model.surfaceplant.dh_natural_gas_heating.PreferredUnits.value + NL) + + f.write(f' Average Pumping Power: {np.average(model.wellbores.PumpingPower.value):10.2f} {model.wellbores.PumpingPower.CurrentUnits.value}{NL}') f.write(NL) f.write(' ************************************************************\n') @@ -440,7 +1831,7 @@ def PrintOutputs(self, model: Model): if model.surfaceplant.enduse_option.value == EndUseOptions.ELECTRICITY: # only electricity f.write(' YEAR THERMAL GEOFLUID PUMP NET FIRST LAW\n') f.write(' DRAWDOWN TEMPERATURE POWER POWER EFFICIENCY\n') - f.write(" (" + model.wellbores.ProducedTemperature.CurrentUnits.value+") (" + model.wellbores.PumpingPower.CurrentUnits.value + ") (" + model.surfaceplant.NetElectricityProduced.CurrentUnits.value + ") (%)\n") + f.write(' (' + model.wellbores.ProducedTemperature.CurrentUnits.value+') (' + model.wellbores.PumpingPower.CurrentUnits.value + ') (' + model.surfaceplant.NetElectricityProduced.CurrentUnits.value + ') (%)\n') for i in range(0, model.surfaceplant.plant_lifetime.value): f.write(' {0:2.0f} {1:8.4f} {2:8.2f} {3:8.4f} {4:8.4f} {5:8.4f}'.format(i+1, model.wellbores.ProducedTemperature.value[i*model.economics.timestepsperyear.value]/model.wellbores.ProducedTemperature.value[0], @@ -459,7 +1850,6 @@ def PrintOutputs(self, model: Model): model.wellbores.PumpingPower.value[i*model.economics.timestepsperyear.value], model.surfaceplant.HeatProduced.value[i*model.economics.timestepsperyear.value])+NL) - elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value in [PlantType.HEAT_PUMP]: # heat pump f.write(' YEAR THERMAL GEOFLUID PUMP NET HEAT PUMP\n') f.write(' DRAWDOWN TEMPERATURE POWER HEAT ELECTRICITY USE\n') @@ -482,7 +1872,6 @@ def PrintOutputs(self, model: Model): model.wellbores.PumpingPower.value[i*model.economics.timestepsperyear.value], model.surfaceplant.HeatProduced.value[i*model.economics.timestepsperyear.value])+NL) - elif model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value in [PlantType.ABSORPTION_CHILLER]: # absorption chiller f.write(' YEAR THERMAL GEOFLUID PUMP NET NET\n') f.write(' DRAWDOWN TEMPERATURE POWER HEAT COOLING\n') @@ -494,7 +1883,6 @@ def PrintOutputs(self, model: Model): model.wellbores.PumpingPower.value[i*model.economics.timestepsperyear.value], model.surfaceplant.HeatProduced.value[i*model.economics.timestepsperyear.value], model.surfaceplant.cooling_produced.value[i * model.economics.timestepsperyear.value], ) + NL) - elif model.surfaceplant.enduse_option.value in [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]: # co-gen f.write(' YEAR THERMAL GEOFLUID PUMP NET NET FIRST LAW\n') f.write(' DRAWDOWN TEMPERATURE POWER POWER HEAT EFFICIENCY\n') @@ -508,8 +1896,8 @@ def PrintOutputs(self, model: Model): model.surfaceplant.HeatProduced.value[i*model.economics.timestepsperyear.value], model.surfaceplant.FirstLawEfficiency.value[i*model.economics.timestepsperyear.value]*100)+NL) f.write(NL) - f.write(NL) + f.write(' *******************************************************************\n') f.write(' * ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE *\n') f.write(' *******************************************************************\n') @@ -534,7 +1922,6 @@ def PrintOutputs(self, model: Model): model.surfaceplant.RemainingReservoirHeatContent.value[i], (model.reserv.InitialReservoirHeatContent.value-model.surfaceplant.RemainingReservoirHeatContent.value[i]) * 100 / model.reserv.InitialReservoirHeatContent.value)+NL) - elif model.surfaceplant.plant_type.value == PlantType.HEAT_PUMP: # heat pump f.write(' YEAR HEATING RESERVOIR HEAT HEAT PUMP RESERVOIR PERCENTAGE OF\n') f.write(' PROVIDED EXTRACTED ELECTRICITY USE HEAT CONTENT TOTAL HEAT MINED\n') @@ -579,53 +1966,16 @@ def PrintOutputs(self, model: Model): model.surfaceplant.HeatkWhExtracted.value[i]/1E6, model.surfaceplant.RemainingReservoirHeatContent.value[i], (model.reserv.InitialReservoirHeatContent.value-model.surfaceplant.RemainingReservoirHeatContent.value[i])*100/model.reserv.InitialReservoirHeatContent.value)+NL) - # https://github.com/NREL/GEOPHIRES-X/issues/135?title=Colorized/enhanced+case+report -# import rich -# from rich.console import Console -# from rich.table import Table -# from rich import print as rprint - -# ytable = Table() -# ytable.add_column('Year Since') -# etable = Table() -# etable.add_column('Price, $/kWh', width=10, justify="center") -# etable.add_column('Annual Revenue, MUSD', width=15, justify="center") -# etable.add_column('Cumulative Revenue, MUSD', width=15, justify="center") -# htable = Table() -# htable.add_column('Price, $/kWh', width=10, justify="center") -# htable.add_column('Annual Revenue, MUSD', width=15, justify="center") -# htable.add_column('Cumulative Revenue, MUSD', width=15, justify="center") -# ctable = Table() -# ctable.add_column('Price, 4$/kWh', width=10, justify="center") -# ctable.add_column('Annual Revenue, MUSD', width=15, justify="center") -# ctable.add_column('Cumulative Revenue, MUSD', width=15, justify="center") -# econ = model.economics -# for ii in range(0, (model.surfaceplant.construction_years.value + model.surfaceplant.plant_lifetime.value - 1), 1): -# ytable.add_row(str(ii)) -# etable.add_row(str(econ.ElecPrice.value[ii]), str(econ.ElecRevenue.value[ii]), str(econ.ElecCummRevenue.value[ii])) -# htable.add_row(str(econ.HeatPrice.value[ii]), str(econ.HeatRevenue.value[ii]), str(econ.HeatCummRevenue.value[ii])) -# ctable.add_row(str(econ.CoolingPrice.value[ii]), str(econ.CoolingRevenue.value[ii]), str(econ.CoolingCummRevenue.value[ii])) -# -# #with open("d:\\temp\\test_table.html", "wt") as f: -# ttable = Table(title="REVENUE & CASHFLOW PROFILE", width=350) -# ttable.add_column('', width=10, justify="center") -# ttable.add_column('Electricity', width=35, justify="center") -# ttable.add_column('Heat', width=35, justify="center") -# ttable.add_column('Cooling', width=35, justify="center") -# ttable.add_row(ytable, etable, htable, ctable) -# console = Console(file=f, style="bold white on blue", force_terminal=True, record=True) -# console.print(ttable) - - #if model.surfaceplant.enduse_option.value == EndUseOptions.HEAT and model.surfaceplant.plant_type.value == PlantType.ABSORPTION_CHILLER: + f.write(NL) f.write(NL) f.write(' ********************************\n') f.write(' * REVENUE & CASHFLOW PROFILE *\n') f.write(' ********************************\n') f.write( - "Year Electricity | Heat | Cooling | Carbon | Project" + NL) + 'Year Electricity | Heat | Cooling | Carbon | Project' + NL) f.write( - "Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow" + NL) + 'Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow' + NL) econ:Economics = model.economics def o(output_param: OutputParameter): @@ -635,65 +1985,78 @@ def o(output_param: OutputParameter): else: return o - f.write("Start (" + f.write('Start (' + o(econ.ElecPrice).CurrentUnits.value + - ")(" + o(econ.ElecRevenue).CurrentUnits.value + - ") (" + o(econ.ElecCummRevenue).CurrentUnits.value + - ") |(" + o(econ.HeatPrice).CurrentUnits.value + - ") (" + o(econ.HeatRevenue).CurrentUnits.value + - ") (" + o(econ.HeatCummRevenue).CurrentUnits.value + - ") |(" + o(econ.CoolingPrice).CurrentUnits.value + - ") (" + o(econ.CoolingRevenue).CurrentUnits.value + - ") (" + o(econ.CoolingCummRevenue).CurrentUnits.value + - ") |(" + o(econ.CarbonPrice).CurrentUnits.value + - ") (" + o(econ.CarbonRevenue).CurrentUnits.value + - ") (" + o(econ.CarbonCummCashFlow).CurrentUnits.value + - ") |(" + o(econ.Coam).CurrentUnits.value + - ") (" + o(econ.TotalRevenue).CurrentUnits.value + - ") (" + o(econ.TotalCummRevenue).CurrentUnits.value + ")\n") + ')(' + o(econ.ElecRevenue).CurrentUnits.value + + ') (' + o(econ.ElecCummRevenue).CurrentUnits.value + + ') |(' + o(econ.HeatPrice).CurrentUnits.value + + ') (' + o(econ.HeatRevenue).CurrentUnits.value + + ') (' + o(econ.HeatCummRevenue).CurrentUnits.value + + ') |(' + o(econ.CoolingPrice).CurrentUnits.value + + ') (' + o(econ.CoolingRevenue).CurrentUnits.value + + ') (' + o(econ.CoolingCummRevenue).CurrentUnits.value + + ') |(' + o(econ.CarbonPrice).CurrentUnits.value + + ') (' + o(econ.CarbonRevenue).CurrentUnits.value + + ') (' + o(econ.CarbonCummCashFlow).CurrentUnits.value + + ') |(' + o(econ.Coam).CurrentUnits.value + + ') (' + o(econ.TotalRevenue).CurrentUnits.value + + ') (' + o(econ.TotalCummRevenue).CurrentUnits.value + ')\n') f.write( - "________________________________________________________________________________________________________________________________________________________________________________________" + NL) + '________________________________________________________________________________________________________________________________________________________________________________________' + NL) # running years... for ii in range(0, ( model.surfaceplant.construction_years.value + model.surfaceplant.plant_lifetime.value - 1), 1): - if ii < model.surfaceplant.construction_years.value: - OPEX = 0.0 # zero out the OPEX during construction years + opex = 0.0 # zero out the OPEX during construction years else: - OPEX = o(econ.Coam).value + opex = o(econ.Coam).value f.write( - f"{ii + 1:3.0f} {o(econ.ElecPrice).value[ii]:5.2f} {o(econ.ElecRevenue).value[ii]:5.2f} {o(econ.ElecCummRevenue).value[ii]:5.2f} | {o(econ.HeatPrice).value[ii]:5.2f} {o(econ.HeatRevenue).value[ii]:5.2f} {o(econ.HeatCummRevenue).value[ii]:5.2f} | {o(econ.CoolingPrice).value[ii]:5.2f} {o(econ.CoolingRevenue).value[ii]:5.2f} {o(econ.CoolingCummRevenue).value[ii]:5.2f} | {o(econ.CarbonPrice).value[ii]:5.2f} {o(econ.CarbonRevenue).value[ii]:5.2f} {o(econ.CarbonCummCashFlow).value[ii]:5.2f} | {OPEX:5.2f} {o(econ.TotalRevenue).value[ii]:5.2f} {o(econ.TotalCummRevenue).value[ii]:5.2f}\n") + f'{ii + 1:3.0f} {o(econ.ElecPrice).value[ii]:5.2f} {o(econ.ElecRevenue).value[ii]:5.2f} {o(econ.ElecCummRevenue).value[ii]:5.2f} | {o(econ.HeatPrice).value[ii]:5.2f} {o(econ.HeatRevenue).value[ii]:5.2f} {o(econ.HeatCummRevenue).value[ii]:5.2f} | {o(econ.CoolingPrice).value[ii]:5.2f} {o(econ.CoolingRevenue).value[ii]:5.2f} {o(econ.CoolingCummRevenue).value[ii]:5.2f} | {o(econ.CarbonPrice).value[ii]:5.2f} {o(econ.CarbonRevenue).value[ii]:5.2f} {o(econ.CarbonCummCashFlow).value[ii]:5.2f} | {opex:5.2f} {o(econ.TotalRevenue).value[ii]:5.2f} {o(econ.TotalCummRevenue).value[ii]:5.2f}\n') f.write(NL) - if model.economics.DoAddOnCalculations.value: model.addoutputs.PrintOutputs(model) - if model.economics.DoSDACGTCalculations.value: model.sdacgtoutputs.PrintOutputs(model) + if model.economics.DoAddOnCalculations.value: + addon_df, addon_results = model.addoutputs.PrintOutputs(model) + if model.economics.DoSDACGTCalculations.value: + sdac_df, sdac_results = model.sdacgtoutputs.PrintOutputs(model) except BaseException as ex: tb = sys.exc_info()[2] - msg = "Error: GEOPHIRES Failed to write the output file. Exiting....Line %i" % tb.tb_lineno + msg = 'Error: GEOPHIRES Failed to write the output file. Exiting....Line %i' % tb.tb_lineno print(str(ex)) print(msg) model.logger.critical(str(ex)) model.logger.critical(msg) raise RuntimeError(msg) from ex - model.logger.info(f'Complete {__class__!s}: {sys._getframe().f_code.co_name}') + if self.text_output_file.Provided: + Write_Text_Output(self.output_file, simulation_metadata, summary, economic_parameters,engineering_parameters, + resource_characteristics, reservoir_parameters, reservoir_stimulation_results, CAPEX, OPEX, + surface_equipment_results, sdac_results, addon_results, hce, ahce, cashflow, sdac_df, addon_df) + + # Get rid of any trailing spaces in that output file - they are confusing the testing code + with open(self.output_file, 'r+') as fp: + lines = fp.readlines() + fp.seek(0) + fp.truncate() + for line in lines: + line = line.rstrip() + '\n' + fp.write(line) + +# uncomment these to allow for testing of the HTML output +# self.html_output_file.value = 'd:\\temp\\test_table_geophires.html' +# self.html_output_file.Provided = True + if self.html_output_file.Provided: + Write_HTML_Output(self.html_output_file.value, simulation_metadata, summary, economic_parameters, + engineering_parameters, resource_characteristics, reservoir_parameters, + reservoir_stimulation_results, CAPEX, OPEX, surface_equipment_results, sdac_results, + addon_results, hce, ahce, cashflow, sdac_df, addon_df) + + Plot_Tables_Into_HTML(model.surfaceplant.enduse_option, model.surfaceplant.plant_type, + self.html_output_file.value, hce, ahce, cashflow, sdac_df, addon_df) + # make district heating plot + if model.surfaceplant.plant_type.value == PlantType.DISTRICT_HEATING: + MakeDistrictHeatingPlot(self.html_output_file.value, model.surfaceplant.dh_geothermal_heating.value, + model.surfaceplant.daily_heating_demand.value) - def MakeDistrictHeatingPlot(self, model: Model): - """ - Make a plot of the district heating system - :param model: GEOPHIRES model - :type model: :class:`~geophires_x.Model.Model` - :return: None - """ - plt.close('all') - year_day = np.arange(1, 366, 1) # make an array of days for plot x-axis - plt.plot(year_day, model.surfaceplant.daily_heating_demand.value, label='District Heating Demand') - plt.fill_between(year_day, 0, model.surfaceplant.dh_geothermal_heating.value[0:365] * 24, color="g", alpha=0.5, label='Geothermal Heat Supply') - plt.fill_between(year_day, model.surfaceplant.dh_geothermal_heating.value[0:365] * 24, model.surfaceplant.daily_heating_demand.value, color="r", alpha=0.5, label='Natural Gas Heat Supply') - plt.xlabel('Ordinal Day') - plt.ylabel('Heating Demand/Supply [MWh/day]') - plt.ylim([0, max(model.surfaceplant.daily_heating_demand.value) * 1.05]) - plt.legend() - plt.title('Geothermal district heating system with peaking boilers') - plt.show(block=False) + + model.logger.info(f'Complete {__class__!s}: {sys._getframe().f_code.co_name}') diff --git a/src/geophires_x/OutputsAddOns.py b/src/geophires_x/OutputsAddOns.py index d00df6e7..e9364bac 100644 --- a/src/geophires_x/OutputsAddOns.py +++ b/src/geophires_x/OutputsAddOns.py @@ -1,5 +1,7 @@ import sys -from geophires_x.Outputs import Outputs +import pandas as pd +from geophires_x.Outputs import Outputs, OutputTableItem + NL = "\n" @@ -8,8 +10,7 @@ class OutputsAddOns(Outputs): """ Class to handle output of the AddOns values """ - - def PrintOutputs(self, model): + def PrintOutputs(self, model) -> tuple: """ The PrintOutputs function prints the results of the AddOns to a text file and to the screen. @@ -17,47 +18,67 @@ def PrintOutputs(self, model): :type model: :class:`~geophires_x.Model.Model` :return: None """ - model.logger.info(f'Init {str(__class__)}: {sys._getframe().f_code.co_name}') + model.logger.info(f'Init {str(__class__)}: {__name__}') # now do AddOn output, which will append to the original output # write results to output file and screen try: with open(self.output_file, 'a', encoding='UTF-8') as f: + addon_results: list[OutputTableItem] = [] f.write(NL) f.write(NL) f.write(" ***EXTENDED ECONOMICS***\n") f.write(NL) if model.economics.LCOE.value > -999.0: - f.write( - f" Adjusted Project LCOE (after incentives, grants, AddOns,etc): {model.economics.LCOE.value:10.2f} " + model.economics.LCOE.PreferredUnits.value + NL) + f.write(f" Adjusted Project LCOE (after incentives, grants, AddOns,etc): {model.economics.LCOE.value:10.2f} " + model.economics.LCOE.PreferredUnits.value + NL) + addon_results.append(OutputTableItem('Adjusted Project LCOE (after incentives, grants, AddOns,etc)', '{0:10.2f}'.format(model.economics.LCOE.value), model.economics.LCOE.PreferredUnits.value)) if model.economics.LCOH.value > -999.0: - f.write( - f" Adjusted Project LCOH (after incentives, grants, AddOns,etc): {model.economics.LCOH.value:10.2f} " + model.economics.LCOH.PreferredUnits.value + NL) - f.write( - f" Adjusted Project CAPEX (after incentives, grants, AddOns, etc): {model.addeconomics.AdjustedProjectCAPEX.value:10.2f} " + model.addeconomics.AdjustedProjectCAPEX.PreferredUnits.value + NL) - f.write( - f" Adjusted Project OPEX (after incentives, grants, AddOns, etc): {model.addeconomics.AdjustedProjectOPEX.value:10.2f} " + model.addeconomics.AdjustedProjectOPEX.PreferredUnits.value + NL) - f.write( - f" Project NPV (including AddOns): {model.addeconomics.ProjectNPV.value:10.2f} " + model.addeconomics.ProjectNPV.PreferredUnits.value + NL) - f.write( - f" Project IRR (including AddOns): {model.addeconomics.ProjectIRR.value:10.2f} " + model.addeconomics.ProjectIRR.PreferredUnits.value + NL) - f.write( - f" Project VIR=PI=PIR (including AddOns): {model.addeconomics.ProjectVIR.value:10.2f}" + NL) - f.write( - f" Project MOIC (including AddOns): {model.addeconomics.ProjectMOIC.value:10.2f}" + NL) + f.write(f" Adjusted Project LCOH (after incentives, grants, AddOns,etc): {model.economics.LCOH.value:10.2f} " + model.economics.LCOH.PreferredUnits.value + NL) + addon_results.append(OutputTableItem('Adjusted Project LCOH (after incentives, grants, AddOns,etc)', '{0:10.2f}'.format(model.economics.LCOH.value), model.economics.LCOH.PreferredUnits.value)) + f.write(f" Adjusted Project CAPEX (after incentives, grants, AddOns, etc): {model.addeconomics.AdjustedProjectCAPEX.value:10.2f} " + model.addeconomics.AdjustedProjectCAPEX.PreferredUnits.value + NL) + addon_results.append(OutputTableItem('Adjusted Project CAPEX (after incentives, grants, AddOns, etc)', '{0:10.2f}'.format(model.addeconomics.AdjustedProjectCAPEX.value), model.addeconomics.AdjustedProjectCAPEX.PreferredUnits.value)) + f.write(f" Adjusted Project OPEX (after incentives, grants, AddOns, etc): {model.addeconomics.AdjustedProjectOPEX.value:10.2f} " + model.addeconomics.AdjustedProjectOPEX.PreferredUnits.value + NL) + addon_results.append(OutputTableItem('Adjusted Project OPEX (after incentives, grants, AddOns, etc)', '{0:10.2f}'.format(model.addeconomics.AdjustedProjectOPEX.value), model.addeconomics.AdjustedProjectOPEX.PreferredUnits.value)) + f.write(f" Project NPV (including AddOns): {model.addeconomics.ProjectNPV.value:10.2f} " + model.addeconomics.ProjectNPV.PreferredUnits.value + NL) + addon_results.append(OutputTableItem('Project NPV (including AddOns)', '{0:10.2f}'.format(model.addeconomics.ProjectNPV.value), model.addeconomics.ProjectNPV.PreferredUnits.value)) + f.write(f" Project IRR (including AddOns): {model.addeconomics.ProjectIRR.value:10.2f} " + model.addeconomics.ProjectIRR.PreferredUnits.value + NL) + addon_results.append(OutputTableItem('Project IRR (including AddOns)', '{0:10.2f}'.format(model.addeconomics.ProjectIRR.value), model.addeconomics.ProjectIRR.PreferredUnits.value)) + f.write(f" Project VIR=PI=PIR (including AddOns): {model.addeconomics.ProjectVIR.value:10.2f}" + NL) + addon_results.append(OutputTableItem('Project VIR=PI=PIR (including AddOns)', '{0:10.2f}'.format(model.addeconomics.ProjectVIR.value), '')) + f.write(f" Project MOIC (including AddOns): {model.addeconomics.ProjectMOIC.value:10.2f}" + NL) + addon_results.append(OutputTableItem('Project MOIC (including AddOns)', '{0:10.2f}'.format(model.addeconomics.ProjectMOIC.value), '')) if model.addeconomics.AddOnCAPEXTotal.value + model.addeconomics.AddOnOPEXTotalPerYear.value != 0: - f.write( - f" Total Add-on CAPEX: {model.addeconomics.AddOnCAPEXTotal.value:10.2f} " + model.addeconomics.AddOnCAPEXTotal.PreferredUnits.value + NL) - f.write( - f" Total Add-on OPEX: {model.addeconomics.AddOnOPEXTotalPerYear.value:10.2f} " + model.addeconomics.AddOnOPEXTotalPerYear.PreferredUnits.value + NL) - f.write( - f" Total Add-on Net Elec: {model.addeconomics.AddOnElecGainedTotalPerYear.value:10.2f} " + model.addeconomics.AddOnElecGainedTotalPerYear.PreferredUnits.value + NL) - f.write( - f" Total Add-on Net Heat: {model.addeconomics.AddOnHeatGainedTotalPerYear.value:10.2f} " + model.addeconomics.AddOnHeatGainedTotalPerYear.PreferredUnits.value + NL) - f.write( - f" Total Add-on Profit: {model.addeconomics.AddOnProfitGainedTotalPerYear.value:10.2f} " + model.addeconomics.AddOnProfitGainedTotalPerYear.PreferredUnits.value + NL) - f.write( - f" AddOns Payback Period: {model.addeconomics.AddOnPaybackPeriod.value:10.2f} " + model.addeconomics.AddOnPaybackPeriod.PreferredUnits.value + NL) + f.write(f" Total Add-on CAPEX: {model.addeconomics.AddOnCAPEXTotal.value:10.2f} " + model.addeconomics.AddOnCAPEXTotal.PreferredUnits.value + NL) + addon_results.append(OutputTableItem('Total Add-on CAPEX', '{0:10.2f}'.format(model.addeconomics.AddOnCAPEXTotal.value), model.addeconomics.AddOnCAPEXTotal.PreferredUnits.value)) + f.write(f" Total Add-on OPEX: {model.addeconomics.AddOnOPEXTotalPerYear.value:10.2f} " + model.addeconomics.AddOnOPEXTotalPerYear.PreferredUnits.value + NL) + addon_results.append(OutputTableItem('Total Add-on OPEX', '{0:10.2f}'.format(model.addeconomics.AddOnOPEXTotalPerYear.value), model.addeconomics.AddOnOPEXTotalPerYear.PreferredUnits.value)) + f.write(f" Total Add-on Net Elec: {model.addeconomics.AddOnElecGainedTotalPerYear.value:10.2f} " + model.addeconomics.AddOnElecGainedTotalPerYear.PreferredUnits.value + NL) + addon_results.append(OutputTableItem('Total Add-on Net Elec', '{0:10.2f}'.format(model.addeconomics.AddOnElecGainedTotalPerYear.value), model.addeconomics.AddOnElecGainedTotalPerYear.PreferredUnits.value)) + f.write(f" Total Add-on Net Heat: {model.addeconomics.AddOnHeatGainedTotalPerYear.value:10.2f} " + model.addeconomics.AddOnHeatGainedTotalPerYear.PreferredUnits.value + NL) + addon_results.append(OutputTableItem('Total Add-on Net Heat', '{0:10.2f}'.format(model.addeconomics.AddOnHeatGainedTotalPerYear.value), model.addeconomics.AddOnHeatGainedTotalPerYear.PreferredUnits.value)) + f.write(f" Total Add-on Profit: {model.addeconomics.AddOnProfitGainedTotalPerYear.value:10.2f} " + model.addeconomics.AddOnProfitGainedTotalPerYear.PreferredUnits.value + NL) + addon_results.append(OutputTableItem('Total Add-on Profit', '{0:10.2f}'.format(model.addeconomics.AddOnProfitGainedTotalPerYear.value), model.addeconomics.AddOnProfitGainedTotalPerYear.PreferredUnits.value)) + f.write(f" AddOns Payback Period: {model.addeconomics.AddOnPaybackPeriod.value:10.2f} " + model.addeconomics.AddOnPaybackPeriod.PreferredUnits.value + NL) + addon_results.append(OutputTableItem('AddOns Payback Period', '{0:10.2f}'.format(model.addeconomics.AddOnPaybackPeriod.value), model.addeconomics.AddOnPaybackPeriod.PreferredUnits.value)) + + ae = model.addeconomics + + # Build the data frame to hold the SDAC result profile + addon_df = pd.DataFrame() + # add the columns as needed based on the output. + # Note that the correct format for that column is stashed in the title of that column + # so that it can be used in the write statement. + addon_df[f'Year|:2.0f'] = [i for i in range(1, (model.surfaceplant.plant_lifetime.value + 1))] + addon_df[f'Electricity:Price ({ae.ElecPrice.PreferredUnits.value})|:10.2f'] = ae.ElecPrice.value + addon_df[f'Electricity:Revenue ({ae.AddOnElecRevenue.PreferredUnits.value})|:10.2f'] = ae.AddOnElecRevenue.value + addon_df[f'Heat:Price ({ae.HeatPrice.PreferredUnits.value})|:10.2f'] = ae.HeatPrice.value + addon_df[f'Heat:Revenue ({ae.AddOnHeatRevenue.PreferredUnits.value})|:10.2f'] = ae.AddOnHeatRevenue.value + addon_df[f'Add-on:Revenue ({ae.AddOnRevenue.PreferredUnits.value})|:10.2f'] = ae.AddOnRevenue.value + addon_df[f'Add-on:Cash Flow ({ae.AddOnCashFlow.PreferredUnits.value})|:10.2f'] = ae.AddOnCashFlow.value[0:len(ae.AddOnCashFlow.value) - 1] + addon_df[f'Add-on:Cumulative Cash Flow ({ae.AddOnCummCashFlow.PreferredUnits.value})|:10.2f'] = ae.AddOnCummCashFlow.value[0:len(ae.AddOnCummCashFlow.value) - 1] + addon_df[f'Project:Cash Flow ({ae.ProjectCashFlow.PreferredUnits.value})|:10.2f'] = ae.ProjectCashFlow.value[0:len(ae.ProjectCashFlow.value) - 1] + addon_df[f'Project:Cumulative Cash Flow ({ae.ProjectCummCashFlow.PreferredUnits.value})|:10.2f'] = ae.ProjectCummCashFlow.value[0:len(ae.ProjectCummCashFlow.value) - 1] + f.write(NL) f.write(NL) f.write(" *******************************" + NL) @@ -68,7 +89,6 @@ def PrintOutputs(self, model): f.write( "Since Price Revenue Price Revenue Revenue Cash Flow Cash Flow Cash Flow Cash Flow" + NL) - ae = model.addeconomics f.write("Start (" + ae.ElecPrice.PreferredUnits.value + ")(" + ae.AddOnElecRevenue.PreferredUnits.value + @@ -94,4 +114,7 @@ def PrintOutputs(self, model): model.logger.critical(err_msg) sys.exit() - model.logger.info(f'Complete {str(__class__)}: {sys._getframe().f_code.co_name}') + model.logger.info(f'Complete {str(__class__)}: {__name__}') + + addon_df = addon_df.reset_index() + return addon_df, addon_results diff --git a/src/geophires_x/OutputsS_DAC_GT.py b/src/geophires_x/OutputsS_DAC_GT.py index a619770e..f9b20b31 100644 --- a/src/geophires_x/OutputsS_DAC_GT.py +++ b/src/geophires_x/OutputsS_DAC_GT.py @@ -1,5 +1,6 @@ import sys -from geophires_x.Outputs import Outputs +import pandas as pd +from geophires_x.Outputs import Outputs, OutputTableItem NL = "\n" @@ -8,38 +9,70 @@ class OutputsS_DAC_GT(Outputs): """ Class to handles output of the SDAC_GT values """ - def PrintOutputs(self, model): + def PrintOutputs(self, model) -> tuple: """ The PrintOutputs function prints the results of the SDAC_GT to a text file and to the screen. :param model: Model: The container class of the application, giving access to everything else, including the logger :type model: :class:`~geophires_x.Model.Model` :return: Nothing """ - model.logger.info("Init " + str(__class__) + ": " + sys._getframe().f_code.co_name) + model.logger.info(f'Init {str(__class__)}: {__name__}') # now do S_DAC_GT output, which will append to the original output # write results to output file and screen try: with open(self.output_file, 'a', encoding='UTF-8') as f: + sdac_results: list[OutputTableItem] = [] f.write(NL) f.write(NL) f.write(" ***S_DAC_GT ECONOMICS***" + NL) f.write(NL) f.write(NL) f.write(f" S-DAC-GT Report: Levelized Cost of Direct Air Capture (LCOD)" + NL) + sdac_results.append(OutputTableItem('S-DAC-GT Report: Levelized Cost of Direct Air Capture (LCOD)')) f.write(f" Using grid-based electricity only: {model.sdacgteconomics.LCOD_elec.value:10.2f} " + model.sdacgteconomics.LCOD_elec.PreferredUnits.value + NL) + sdac_results.append(OutputTableItem('Using grid-based electricity only', '{0:10.2f}'.format(model.sdacgteconomics.LCOD_elec.value), model.sdacgteconomics.LCOD_elec.PreferredUnits.value)) f.write(f" Using natural gas only: {model.sdacgteconomics.LCOD_ng.value:10.2f} " + model.sdacgteconomics.LCOD_ng.PreferredUnits.value + NL) + sdac_results.append(OutputTableItem('Using natural gas only', '{0:10.2f}'.format(model.sdacgteconomics.LCOD_ng.value), model.sdacgteconomics.LCOD_ng.PreferredUnits.value)) f.write(f" Using geothermal energy only: {model.sdacgteconomics.LCOD_geo.value:10.2f} " + model.sdacgteconomics.LCOD_geo.PreferredUnits.value + NL + NL) + sdac_results.append(OutputTableItem('Using geothermal energy only', '{0:10.2f}'.format(model.sdacgteconomics.LCOD_geo.value), model.sdacgteconomics.LCOD_geo.PreferredUnits.value)) f.write(f" S-DAC-GT Report: CO2 Intensity of process (percent of CO2 mitigated that is emitted by S-DAC process)" + NL) + sdac_results.append(OutputTableItem('S-DAC-GT Report: CO2 Intensity of process (percent of CO2 mitigated that is emitted by S-DAC process)')) f.write(f" Using grid-based electricity only: {model.sdacgteconomics.CO2total_elec.value*100.0:10.2f}%" + NL) + sdac_results.append(OutputTableItem('Using grid-based electricity only', '{0:10.2f}'.format(model.sdacgteconomics.CO2total_elec.value*100.0), '%')) f.write(f" Using natural gas only: {model.sdacgteconomics.CO2total_ng.value*100:10.2f}%" + NL) + sdac_results.append(OutputTableItem('Using natural gas only', '{0:10.2f}'.format(model.sdacgteconomics.CO2total_ng.value*100.0), '%')) f.write(f" Using geothermal energy only: {model.sdacgteconomics.CO2total_geo.value*100:10.2f}%" + NL + NL) + sdac_results.append(OutputTableItem('Using geothermal energy only', '{0:10.2f}'.format(model.sdacgteconomics.CO2total_geo.value*100.0), '%')) f.write(f" Geothermal LCOH: {model.sdacgteconomics.LCOH.value:10.4f} " + model.sdacgteconomics.LCOH.PreferredUnits.value + NL) + sdac_results.append(OutputTableItem('Geothermal LCOH', '{0:10.4f}'.format(model.sdacgteconomics.LCOH.value), model.sdacgteconomics.LCOH.PreferredUnits.value)) f.write(f" Geothermal Ratio (electricity vs heat):{model.sdacgteconomics.percent_thermal_energy_going_to_heat.value*100:10.4f}%" + NL) + sdac_results.append(OutputTableItem('Geothermal Ratio (electricity vs heat)', '{0:10.4f}'.format(model.sdacgteconomics.percent_thermal_energy_going_to_heat.value*100.0), '%')) f.write(f" Percent Energy Devoted To Process: {model.sdacgteconomics.EnergySplit.value*100:10.4f}%" + NL + NL) + sdac_results.append(OutputTableItem('Percent Energy Devoted To Process', '{0:10.4f}'.format(model.sdacgteconomics.EnergySplit.value*100.0), '%')) f.write(f" Total Tonnes of CO2 Captured: {model.sdacgteconomics.CarbonExtractedTotal.value:,.2f} " + model.sdacgteconomics.CarbonExtractedTotal.PreferredUnits.value + NL) + sdac_results.append(OutputTableItem('Total Tonnes of CO2 Captured', '{0:,.2f}'.format(model.sdacgteconomics.CarbonExtractedTotal.value), model.sdacgteconomics.CarbonExtractedTotal.PreferredUnits.value)) f.write(f" Total Cost of Capture: {model.sdacgteconomics.S_DAC_GTCummCashFlow.value[len(model.sdacgteconomics.S_DAC_GTCummCashFlow.value)-1]:,.2f} " + model.sdacgteconomics.S_DAC_GTCummCashFlow.PreferredUnits.value + NL) + sdac_results.append(OutputTableItem('Total Cost of Capture', '{0:,.2f}'.format(model.sdacgteconomics.S_DAC_GTCummCashFlow.value[len(model.sdacgteconomics.S_DAC_GTCummCashFlow.value)-1]), model.sdacgteconomics.S_DAC_GTCummCashFlow.PreferredUnits.value)) f.write(NL) + + # Build the data frame to hold the SDAC result profile + sdac_df = pd.DataFrame() + # add the columns as needed based on the output. + # Note that the correct format for that column is stashed in the title of that column + # so that it can be used in the write statement. + sdac_df[f'Year|:3.0f'] = [i for i in range(1, (model.surfaceplant.plant_lifetime.value + 1))] + sdac_df[f'Carbon Captured ({model.sdacgteconomics.CarbonExtractedAnnually.PreferredUnits.value})|:,.2f'] = \ + model.sdacgteconomics.CarbonExtractedAnnually.value + sdac_df[f'Cum. Carbon Captured ({model.sdacgteconomics.S_DAC_GTCummCarbonExtracted.PreferredUnits.value})|:,.2f'] = \ + model.sdacgteconomics.S_DAC_GTCummCarbonExtracted.value + sdac_df[f'S_DAC_GT Annual Cost ({model.sdacgteconomics.S_DAC_GTAnnualCost.PreferredUnits.value})|:,.2f'] = \ + model.sdacgteconomics.S_DAC_GTAnnualCost.value + sdac_df[f'S_DAC_GT Cumulative Cash Flow ({model.sdacgteconomics.S_DAC_GTCummCashFlow.PreferredUnits.value})|:,.2f'] = \ + model.sdacgteconomics.S_DAC_GTCummCashFlow.value + sdac_df[f'Cum. Cost Per Tonne ({model.sdacgteconomics.CummCostPerTonne.PreferredUnits.value})|:,.2f'] = \ + model.sdacgteconomics.CummCostPerTonne.value + f.write(NL) f.write(" **********************" + NL) f.write(" * S_DAC_GT PROFILE *" + NL) @@ -64,4 +97,7 @@ def PrintOutputs(self, model): model.logger.critical("Error: GEOPHIRES failed to Failed to write the output file. Exiting....Line %i" % tb.tb_lineno) sys.exit() - model.logger.info("Complete " + str(__class__) + ": " + sys._getframe().f_code.co_name) + model.logger.info(f'Complete {str(__class__)}: {__name__}') + + sdac_df = sdac_df.reset_index() + return sdac_df, sdac_results diff --git a/src/geophires_x_client/geophires_x_result.py b/src/geophires_x_client/geophires_x_result.py index 3b99beee..315808a4 100644 --- a/src/geophires_x_client/geophires_x_result.py +++ b/src/geophires_x_client/geophires_x_result.py @@ -140,7 +140,7 @@ class GeophiresXResult: # TODO moved to power generation profile, parse from there # 'Annual Thermal Drawdown (%/year)', 'Bottom-hole temperature', - 'Well seperation: fracture height', # TODO correct typo upstream + 'Well separation: fracture height', 'Fracture area', 'Fracture width', 'Reservoir volume', diff --git a/tests/example1_addons.csv b/tests/example1_addons.csv index 0c8847e6..3f00b47f 100644 --- a/tests/example1_addons.csv +++ b/tests/example1_addons.csv @@ -50,7 +50,7 @@ RESOURCE CHARACTERISTICS,Geothermal gradient,,0.05,degC/m RESERVOIR PARAMETERS,Reservoir Model,,Multiple Parallel Fractures Model, RESERVOIR PARAMETERS,Fracture model,,Square, RESERVOIR PARAMETERS,Bottom-hole temperature,,170.0,degC -RESERVOIR PARAMETERS,Well seperation: fracture height,,900.0,meter +RESERVOIR PARAMETERS,Well separation: fracture height,,900.0,meter RESERVOIR PARAMETERS,Fracture area,,810000.0,m**2 RESERVOIR PARAMETERS,Reservoir volume,,1000000000,m**3 RESERVOIR PARAMETERS,Reservoir hydrostatic pressure,,29430.21,kPa @@ -366,17 +366,17 @@ HEAT AND/OR ELECTRICITY EXTRACTION AND GENERATION PROFILE,PERCENTAGE OF TOTAL HE HEAT AND/OR ELECTRICITY EXTRACTION AND GENERATION PROFILE,PERCENTAGE OF TOTAL HEAT MINED,28,12.85,% HEAT AND/OR ELECTRICITY EXTRACTION AND GENERATION PROFILE,PERCENTAGE OF TOTAL HEAT MINED,29,13.31,% HEAT AND/OR ELECTRICITY EXTRACTION AND GENERATION PROFILE,PERCENTAGE OF TOTAL HEAT MINED,30,13.69,% -EXTENDED ECONOMIC PROFILE,Electricity Price,1,0.09,cents/kWh +EXTENDED ECONOMIC PROFILE,Electricity Price,1,0.0,cents/kWh EXTENDED ECONOMIC PROFILE,Electricity Price,2,0.09,cents/kWh EXTENDED ECONOMIC PROFILE,Electricity Price,3,0.09,cents/kWh EXTENDED ECONOMIC PROFILE,Electricity Price,4,0.09,cents/kWh EXTENDED ECONOMIC PROFILE,Electricity Price,5,0.09,cents/kWh EXTENDED ECONOMIC PROFILE,Electricity Price,6,0.09,cents/kWh -EXTENDED ECONOMIC PROFILE,Electricity Price,7,0.102,cents/kWh -EXTENDED ECONOMIC PROFILE,Electricity Price,8,0.114,cents/kWh -EXTENDED ECONOMIC PROFILE,Electricity Price,9,0.126,cents/kWh -EXTENDED ECONOMIC PROFILE,Electricity Price,10,0.138,cents/kWh -EXTENDED ECONOMIC PROFILE,Electricity Price,11,0.15,cents/kWh +EXTENDED ECONOMIC PROFILE,Electricity Price,7,0.09,cents/kWh +EXTENDED ECONOMIC PROFILE,Electricity Price,8,0.102,cents/kWh +EXTENDED ECONOMIC PROFILE,Electricity Price,9,0.114,cents/kWh +EXTENDED ECONOMIC PROFILE,Electricity Price,10,0.126,cents/kWh +EXTENDED ECONOMIC PROFILE,Electricity Price,11,0.138,cents/kWh EXTENDED ECONOMIC PROFILE,Electricity Price,12,0.15,cents/kWh EXTENDED ECONOMIC PROFILE,Electricity Price,13,0.15,cents/kWh EXTENDED ECONOMIC PROFILE,Electricity Price,14,0.15,cents/kWh @@ -426,7 +426,7 @@ EXTENDED ECONOMIC PROFILE,Electricity Revenue,27,0.0039,MUSD/yr EXTENDED ECONOMIC PROFILE,Electricity Revenue,28,0.0039,MUSD/yr EXTENDED ECONOMIC PROFILE,Electricity Revenue,29,0.0039,MUSD/yr EXTENDED ECONOMIC PROFILE,Electricity Revenue,30,0.0039,MUSD/yr -EXTENDED ECONOMIC PROFILE,Heat Price,1,0.012,cents/kWh +EXTENDED ECONOMIC PROFILE,Heat Price,1,0.0,cents/kWh EXTENDED ECONOMIC PROFILE,Heat Price,2,0.012,cents/kWh EXTENDED ECONOMIC PROFILE,Heat Price,3,0.012,cents/kWh EXTENDED ECONOMIC PROFILE,Heat Price,4,0.012,cents/kWh @@ -434,9 +434,9 @@ EXTENDED ECONOMIC PROFILE,Heat Price,5,0.012,cents/kWh EXTENDED ECONOMIC PROFILE,Heat Price,6,0.012,cents/kWh EXTENDED ECONOMIC PROFILE,Heat Price,7,0.012,cents/kWh EXTENDED ECONOMIC PROFILE,Heat Price,8,0.012,cents/kWh -EXTENDED ECONOMIC PROFILE,Heat Price,9,0.022,cents/kWh -EXTENDED ECONOMIC PROFILE,Heat Price,10,0.032,cents/kWh -EXTENDED ECONOMIC PROFILE,Heat Price,11,0.036,cents/kWh +EXTENDED ECONOMIC PROFILE,Heat Price,9,0.012,cents/kWh +EXTENDED ECONOMIC PROFILE,Heat Price,10,0.022,cents/kWh +EXTENDED ECONOMIC PROFILE,Heat Price,11,0.032,cents/kWh EXTENDED ECONOMIC PROFILE,Heat Price,12,0.036,cents/kWh EXTENDED ECONOMIC PROFILE,Heat Price,13,0.036,cents/kWh EXTENDED ECONOMIC PROFILE,Heat Price,14,0.036,cents/kWh @@ -636,17 +636,17 @@ EXTENDED ECONOMIC PROFILE,Cumm. Project Cash Flow,27,94.75,MUSD EXTENDED ECONOMIC PROFILE,Cumm. Project Cash Flow,28,103.09,MUSD EXTENDED ECONOMIC PROFILE,Cumm. Project Cash Flow,29,111.43,MUSD EXTENDED ECONOMIC PROFILE,Cumm. Project Cash Flow,30,119.77,MUSD -REVENUE & CASHFLOW PROFILE,Electricity Price,1,9.0,cents/kWh +REVENUE & CASHFLOW PROFILE,Electricity Price,1,0.0,cents/kWh REVENUE & CASHFLOW PROFILE,Electricity Price,2,9.0,cents/kWh REVENUE & CASHFLOW PROFILE,Electricity Price,3,9.0,cents/kWh REVENUE & CASHFLOW PROFILE,Electricity Price,4,9.0,cents/kWh REVENUE & CASHFLOW PROFILE,Electricity Price,5,9.0,cents/kWh REVENUE & CASHFLOW PROFILE,Electricity Price,6,9.0,cents/kWh -REVENUE & CASHFLOW PROFILE,Electricity Price,7,10.2,cents/kWh -REVENUE & CASHFLOW PROFILE,Electricity Price,8,11.4,cents/kWh -REVENUE & CASHFLOW PROFILE,Electricity Price,9,12.6,cents/kWh -REVENUE & CASHFLOW PROFILE,Electricity Price,10,13.8,cents/kWh -REVENUE & CASHFLOW PROFILE,Electricity Price,11,15.0,cents/kWh +REVENUE & CASHFLOW PROFILE,Electricity Price,7,9.0,cents/kWh +REVENUE & CASHFLOW PROFILE,Electricity Price,8,10.2,cents/kWh +REVENUE & CASHFLOW PROFILE,Electricity Price,9,11.4,cents/kWh +REVENUE & CASHFLOW PROFILE,Electricity Price,10,12.6,cents/kWh +REVENUE & CASHFLOW PROFILE,Electricity Price,11,13.8,cents/kWh REVENUE & CASHFLOW PROFILE,Electricity Price,12,15.0,cents/kWh REVENUE & CASHFLOW PROFILE,Electricity Price,13,15.0,cents/kWh REVENUE & CASHFLOW PROFILE,Electricity Price,14,15.0,cents/kWh @@ -726,7 +726,7 @@ REVENUE & CASHFLOW PROFILE,Electricity Cumm. Rev.,27,144.94,MUSD REVENUE & CASHFLOW PROFILE,Electricity Cumm. Rev.,28,151.33,MUSD REVENUE & CASHFLOW PROFILE,Electricity Cumm. Rev.,29,157.71,MUSD REVENUE & CASHFLOW PROFILE,Electricity Cumm. Rev.,30,164.1,MUSD -REVENUE & CASHFLOW PROFILE,Heat Price,1,2.5,cents/kWh +REVENUE & CASHFLOW PROFILE,Heat Price,1,0.0,cents/kWh REVENUE & CASHFLOW PROFILE,Heat Price,2,2.5,cents/kWh REVENUE & CASHFLOW PROFILE,Heat Price,3,2.5,cents/kWh REVENUE & CASHFLOW PROFILE,Heat Price,4,2.5,cents/kWh @@ -816,7 +816,7 @@ REVENUE & CASHFLOW PROFILE,Heat Cumm. Rev.,27,0.0,MUSD REVENUE & CASHFLOW PROFILE,Heat Cumm. Rev.,28,0.0,MUSD REVENUE & CASHFLOW PROFILE,Heat Cumm. Rev.,29,0.0,MUSD REVENUE & CASHFLOW PROFILE,Heat Cumm. Rev.,30,0.0,MUSD -REVENUE & CASHFLOW PROFILE,Cooling Price,1,2.5,cents/kWh +REVENUE & CASHFLOW PROFILE,Cooling Price,1,0.0,cents/kWh REVENUE & CASHFLOW PROFILE,Cooling Price,2,2.5,cents/kWh REVENUE & CASHFLOW PROFILE,Cooling Price,3,2.5,cents/kWh REVENUE & CASHFLOW PROFILE,Cooling Price,4,2.5,cents/kWh @@ -906,20 +906,20 @@ REVENUE & CASHFLOW PROFILE,Cooling Cumm. Rev.,27,0.0,MUSD REVENUE & CASHFLOW PROFILE,Cooling Cumm. Rev.,28,0.0,MUSD REVENUE & CASHFLOW PROFILE,Cooling Cumm. Rev.,29,0.0,MUSD REVENUE & CASHFLOW PROFILE,Cooling Cumm. Rev.,30,0.0,MUSD -REVENUE & CASHFLOW PROFILE,Carbon Price,1,0.01,USD/tonne +REVENUE & CASHFLOW PROFILE,Carbon Price,1,0.0,USD/tonne REVENUE & CASHFLOW PROFILE,Carbon Price,2,0.01,USD/tonne REVENUE & CASHFLOW PROFILE,Carbon Price,3,0.01,USD/tonne REVENUE & CASHFLOW PROFILE,Carbon Price,4,0.01,USD/tonne REVENUE & CASHFLOW PROFILE,Carbon Price,5,0.01,USD/tonne REVENUE & CASHFLOW PROFILE,Carbon Price,6,0.01,USD/tonne -REVENUE & CASHFLOW PROFILE,Carbon Price,7,0.03,USD/tonne -REVENUE & CASHFLOW PROFILE,Carbon Price,8,0.04,USD/tonne +REVENUE & CASHFLOW PROFILE,Carbon Price,7,0.01,USD/tonne +REVENUE & CASHFLOW PROFILE,Carbon Price,8,0.03,USD/tonne REVENUE & CASHFLOW PROFILE,Carbon Price,9,0.04,USD/tonne -REVENUE & CASHFLOW PROFILE,Carbon Price,10,0.06,USD/tonne -REVENUE & CASHFLOW PROFILE,Carbon Price,11,0.07,USD/tonne +REVENUE & CASHFLOW PROFILE,Carbon Price,10,0.04,USD/tonne +REVENUE & CASHFLOW PROFILE,Carbon Price,11,0.06,USD/tonne REVENUE & CASHFLOW PROFILE,Carbon Price,12,0.07,USD/tonne -REVENUE & CASHFLOW PROFILE,Carbon Price,13,0.09,USD/tonne -REVENUE & CASHFLOW PROFILE,Carbon Price,14,0.1,USD/tonne +REVENUE & CASHFLOW PROFILE,Carbon Price,13,0.07,USD/tonne +REVENUE & CASHFLOW PROFILE,Carbon Price,14,0.09,USD/tonne REVENUE & CASHFLOW PROFILE,Carbon Price,15,0.1,USD/tonne REVENUE & CASHFLOW PROFILE,Carbon Price,16,0.1,USD/tonne REVENUE & CASHFLOW PROFILE,Carbon Price,17,0.1,USD/tonne diff --git a/tests/examples/S-DAC-GT.out b/tests/examples/S-DAC-GT.out index 34ad4696..4798eff2 100644 --- a/tests/examples/S-DAC-GT.out +++ b/tests/examples/S-DAC-GT.out @@ -4,242 +4,227 @@ Simulation Metadata ---------------------- - GEOPHIRES Version: 3.4.4 - GEOPHIRES Build Date: 2022-06-30 - Simulation Date: 2024-03-02 - Simulation Time: 14:17 - Calculation Time: 0.409 sec +GEOPHIRES Version: 3.4.22 +GEOPHIRES Build Date: 2024-03-05 +Simulation Date: 2024-03-20 +Simulation Time: 17:51 +Calculation Time: 0.433 sec ***SUMMARY OF RESULTS*** - End-Use Option: Cogeneration Topping Cycle, Heat sales considered as extra income - Average Net Electricity Production: 19.75 MW - Average Direct-Use Heat Production: 12.94 MW - Electricity breakeven price: 6.38 cents/kWh - Direct-Use heat breakeven price (LCOH): 2.34 USD/MMBTU - Number of production wells: 3 - Number of injection wells: 3 - Flowrate per production well: 70.0 kg/sec - Well depth (or total length, if not vertical): 3.1 kilometer - Geothermal gradient: 0.0700 degC/m - + End-Use Option : Cogeneration Topping Cycle, Heat sales considered as extra income + Average Net Electricity Production : 19.75 MW + Average Direct-Use Heat Production : 12.94 MW + Electricity breakeven price : 6.38 cents/kWh + Direct-Use heat breakeven price (LCOH) : 2.34 USD/MMBTU + Number of production wells : 3 + Number of injection wells : 3 + Flowrate per production well : 70.0 kg/sec + Well depth (or total length, if not vertical): 3.1 kilometer + Geothermal gradient : 0.0700 °C/m ***ECONOMIC PARAMETERS*** - Economic Model = BICYCLE - Accrued financing during construction: 0.00 - Project lifetime: 30 yr - Capacity factor: 90.0 % - Project NPV: -3.25 MUSD - Project IRR: 0.06 % - Project VIR=PI=PIR: 0.97 - Project MOIC: 0.58 - Project Payback Period: 14.27 yr - CHP: Percent cost allocation for electrical plant: 92.43% - - ***ENGINEERING PARAMETERS*** - - Number of Production Wells: 3 - Number of Injection Wells: 3 - Well depth (or total length, if not vertical): 3.1 kilometer - Water loss rate: 2.0 - Pump efficiency: 80.0 - Injection temperature: 70.0 degC - User-provided production well temperature drop - Constant production well temperature drop: 5.0 degC - Flowrate per production well: 70.0 kg/sec - Injection well casing ID: 8.500 in - Production well casing ID: 8.500 in - Number of times redrilling: 0 - Power plant type: Double-Flash - - - ***RESOURCE CHARACTERISTICS*** - - Maximum reservoir temperature: 400.0 degC - Number of segments: 1 - Geothermal gradient: 0.0700 degC/m - + Economic Model : BICYCLE + Accrued financing during construction : 0.00 + Project lifetime : 30 yr + Capacity factor : 90.0 % + Project NPV : -3.25 MUSD + Project IRR : 5.96 % + Project VIR=PI=PIR : 0.97 + Project MOIC : 0.58 + Project Payback Period : 14.27 yr + CHP: Percent cost allocation for electrical plant: 92.43 % + + ***ENGINEERING PARAMETERS*** + + Number of Production Wells : 3 + Number of Injection Wells : 3 + Well depth (or total length, if not vertical): 3.1 kilometer + Water loss rate : 2.0 + Pump efficiency : 80.0 + Injection temperature : 70.0 °C + User-provided production well temperature drop: + Constant production well temperature drop : 5.0 °C + Flowrate per production well : 70.0 kg/sec + Injection well casing ID : 8.500 in + Production well casing ID : 8.500 in + Number of times redrilling : 0 + Power plant type : Double-Flash + + ***RESOURCE CHARACTERISTICS*** + + Maximum reservoir temperature : 400.0 °C + Number of segments : 1 + Geothermal gradient : 0.0700 °C/m ***RESERVOIR PARAMETERS*** - Reservoir Model = Single Fracture m/A Thermal Drawdown Model - 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 - Fracture separation: 80.00 meter - Reservoir volume: 176000000 m**3 - Reservoir hydrostatic pressure: 29639.68 kPa - Plant outlet pressure: 100.00 kPa - Injectivity Index: 5.00 kg/sec/bar - Reservoir density: 2700.00 kg/m**3 - Reservoir thermal conductivity: 3.00 W/m/K - Reservoir heat capacity: 1000.00 J/kg/K - - - ***RESERVOIR SIMULATION RESULTS*** - - Maximum Production Temperature: 227.0 degC - Average Production Temperature: 221.2 degC - Minimum Production Temperature: 209.1 degC - Initial Production Temperature: 227.0 degC - Average Reservoir Heat Extraction: 130.23 MW - Wellbore Heat Transmission Model = Constant Temperature Drop: 5.0 degC - Average Injection Well Pump Pressure Drop: 685.6 kPa - - - ***CAPITAL COSTS (M$)*** - - Drilling and completion costs: 34.45 MUSD - Drilling and completion costs per well: 5.74 MUSD - Stimulation costs: 4.53 MUSD - Surface power plant costs: 64.77 MUSD - Field gathering system costs: 3.16 MUSD - Total surface equipment costs: 67.93 MUSD - Exploration costs: 5.51 MUSD - Total capital costs: 112.42 MUSD - - - ***OPERATING AND MAINTENANCE COSTS (M$/yr)*** - - Wellfield maintenance costs: 0.83 MUSD/yr - Power plant maintenance costs: 2.32 MUSD/yr - Water costs: 0.11 MUSD/yr - Total operating and maintenance costs: 3.26 MUSD/yr - + Reservoir Model : Single Fracture m/A Thermal Drawdown Model + m/A Drawdown Parameter : 0.00002 1/year + Bottom-hole temperature : 232.00 °C + Reservoir volume calculated with fracture separation and number of fractures as input: + Number of fractures : 12.00 + Fracture separation : 80.00 meter + Reservoir volume : 176000000 m³ + Reservoir hydrostatic pressure : 29639.68 kPa + Plant outlet pressure : 100.00 kPa + Injectivity Index : 5.00 kg/sec/bar + Reservoir density : 2700.00 kg/m³ + Reservoir thermal conductivity : 3.00 W/m/K + Reservoir heat capacity : 1000.00 J/kg/K + + ***RESERVOIR STIMULATION RESULTS*** + + Maximum Production Temperature : 227.0 °C + Average Production Temperature : 221.2 °C + Minimum Production Temperature : 209.1 °C + Initial Production Temperature : 227.0 °C + Average Reservoir Heat Extraction : 130.23 MW + Wellbore Heat Transmission Model = Constant Temperature Drop: 5.0 °C + Average Injection Well Pump Pressure Drop : 685.6 kPa + + ***CAPITAL COSTS*** + + Drilling and completion costs : 34.45 MUSD + Drilling and completion costs per well : 5.74 MUSD + Stimulation costs : 4.53 MUSD + Surface power plant costs : 64.77 MUSD + Field gathering system costs : 3.16 MUSD + Total surface equipment costs : 67.93 MUSD + Exploration costs : 5.51 MUSD + Total capital costs : 112.42 MUSD + + ***OPERATING AND MAINTENANCE COSTS*** + + Wellfield maintenance costs : 0.83 MUSD/yr + Power plant maintenance costs : 2.32 MUSD/yr + Water costs : 0.11 MUSD/yr + Total operating and maintenance costs : 3.26 MUSD/yr ***SURFACE EQUIPMENT SIMULATION RESULTS*** - Initial geofluid availability: 0.23 MW/(kg/s) - Maximum Total Electricity Generation: 21.16 MW - Average Total Electricity Generation: 19.94 MW - Minimum Total Electricity Generation: 17.44 MW - Initial Total Electricity Generation: 21.16 MW - Maximum Net Electricity Generation: 20.98 MW - Average Net Electricity Generation: 19.75 MW - Minimum Net Electricity Generation: 17.26 MW - Initial Net Electricity Generation: 20.98 MW - Average Annual Total Electricity Generation: 156.66 GWh - Average Annual Net Electricity Generation: 155.23 GWh - Initial pumping power/net installed power: 0.87 % - Maximum Net Heat Production: 13.70 MW - Average Net Heat Production: 12.94 MW - Minimum Net Heat Production: 11.28 MW - Initial Net Heat Production: 13.70 MW - Average Annual Heat Production: 101.69 GWh - Average Pumping Power: 0.18 MW - - ************************************************************ + Initial geofluid availability : 0.23 MW/(kg/s) + Maximum Total Electricity Generation : 21.16 MW + Average Total Electricity Generation : 19.94 MW + Minimum Total Electricity Generation : 17.44 MW + Initial Total Electricity Generation : 21.16 MW + Maximum Net Electricity Generation : 20.98 MW + Average Net Electricity Generation : 19.75 MW + Minimum Net Electricity Generation : 17.26 MW + Initial Net Electricity Generation : 20.98 MW + Average Annual Total Electricity Generation : 0.00 GWh + Average Annual Net Electricity Generation : 0.00 GWh + Initial pumping power/net installed power : 0.87 % + Maximum Net Heat Production : 13.70 MW + Average Net Heat Production : 12.94 MW + Minimum Net Heat Production : 11.28 MW + Initial Net Heat Production : 13.70 MW + Average Annual Heat Production : 101.69 + Average Pumping Power : 0.18 MW + + *************************************************************** * HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE * - ************************************************************ - YEAR THERMAL GEOFLUID PUMP NET NET FIRST LAW - DRAWDOWN TEMPERATURE POWER POWER HEAT EFFICIENCY - (deg C) (MW) (MW) (MW) (%) - 0 1.0000 227.00 0.1816 20.9791 13.6976 17.4835 - 1 1.0000 227.00 0.1816 20.9791 13.6976 17.4835 - 2 1.0000 227.00 0.1816 20.9791 13.6976 17.4835 - 3 1.0000 227.00 0.1816 20.9791 13.6976 17.4834 - 4 1.0000 227.00 0.1816 20.9787 13.6973 17.4833 - 5 0.9999 226.98 0.1816 20.9757 13.6957 17.4823 - 6 0.9997 226.94 0.1816 20.9660 13.6902 17.4788 - 7 0.9993 226.84 0.1816 20.9444 13.6780 17.4712 - 8 0.9985 226.67 0.1816 20.9067 13.6565 17.4578 - 9 0.9974 226.41 0.1816 20.8500 13.6243 17.4378 - 10 0.9959 226.06 0.1816 20.7734 13.5804 17.4106 - 11 0.9939 225.62 0.1816 20.6771 13.5250 17.3764 - 12 0.9916 225.09 0.1816 20.5623 13.4584 17.3354 - 13 0.9889 224.48 0.1816 20.4308 13.3814 17.2883 - 14 0.9859 223.80 0.1816 20.2846 13.2950 17.2358 - 15 0.9827 223.06 0.1816 20.1258 13.2000 17.1784 - 16 0.9792 222.27 0.1816 19.9563 13.0975 17.1169 - 17 0.9755 221.43 0.1816 19.7782 12.9884 17.0519 - 18 0.9716 220.56 0.1816 19.5931 12.8736 16.9840 - 19 0.9676 219.65 0.1816 19.4026 12.7538 16.9138 - 20 0.9635 218.72 0.1816 19.2081 12.6297 16.8416 - 21 0.9594 217.77 0.1816 19.0109 12.5020 16.7680 - 22 0.9551 216.81 0.1816 18.8118 12.3713 16.6932 - 23 0.9508 215.84 0.1816 18.6119 12.2382 16.6176 - 24 0.9465 214.86 0.1816 18.4119 12.1029 16.5415 - 25 0.9422 213.87 0.1816 18.2124 11.9661 16.4651 - 26 0.9378 212.89 0.1816 18.0140 11.8279 16.3886 - 27 0.9335 211.91 0.1816 17.8171 11.6888 16.3121 - 28 0.9292 210.93 0.1816 17.6221 11.5490 16.2360 - 29 0.9249 209.95 0.1816 17.4293 11.4088 16.1601 - - - ******************************************************************* - * ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE * - ******************************************************************* - YEAR HEAT ELECTRICITY HEAT RESERVOIR PERCENTAGE OF - PROVIDED PROVIDED EXTRACTED HEAT CONTENT TOTAL HEAT MINED - (GWh/year) (GWh/year) (GWh/year) (10^15 J) (%) - 1 108.0 165.4 1066.02 73.14 4.99 - 2 108.0 165.4 1066.02 69.31 9.97 - 3 108.0 165.4 1066.02 65.47 14.96 - 4 108.0 165.4 1066.02 61.63 19.94 - 5 108.0 165.4 1065.98 57.79 24.93 - 6 108.0 165.3 1065.79 53.96 29.91 - 7 107.9 165.2 1065.32 50.12 34.89 - 8 107.8 165.0 1064.41 46.29 39.87 - 9 107.5 164.6 1062.95 42.46 44.84 - 10 107.2 164.1 1060.88 38.64 49.80 - 11 106.9 163.4 1058.19 34.83 54.75 - 12 106.4 162.6 1054.89 31.04 59.68 - 13 105.8 161.6 1051.03 27.25 64.60 - 14 105.2 160.5 1046.66 23.49 69.49 - 15 104.4 159.3 1041.85 19.73 74.36 - 16 103.7 158.0 1036.64 16.00 79.21 - 17 102.8 156.6 1031.09 12.29 84.03 - 18 102.0 155.2 1025.27 8.60 88.83 - 19 101.0 153.7 1019.22 4.93 93.59 - 20 100.1 152.2 1012.99 1.28 98.33 - 21 99.1 150.7 1006.61 -2.34 103.04 - 22 98.1 149.1 1000.11 -5.94 107.72 - 23 97.0 147.5 993.53 -9.52 112.36 - 24 96.0 145.9 986.90 -13.07 116.98 - 25 94.9 144.4 980.23 -16.60 121.56 - 26 93.8 142.8 973.55 -20.10 126.11 - 27 92.7 141.2 966.87 -23.58 130.64 - 28 91.6 139.7 960.20 -27.04 135.13 - 29 90.5 138.2 953.56 -30.47 139.58 - 30 80.5 123.1 852.56 -33.54 143.57 - - - ******************************* - * REVENUE & CASHFLOW PROFILE * - ******************************* -Year Electricity | Heat | Cooling | Carbon | Project -Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow -Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) -________________________________________________________________________________________________________________________________________________________________________________________ - 1 0.06 0.00 0.00 | 0.03 0.00 0.00 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -112.42 -112.42 - 2 0.06 9.10 9.10 | 0.03 2.70 2.70 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.54 -103.88 - 3 0.06 9.10 18.19 | 0.03 2.70 5.40 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.54 -95.34 - 4 0.06 9.10 27.29 | 0.03 2.70 8.10 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.54 -86.81 - 5 0.06 9.10 36.39 | 0.03 2.70 10.80 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.54 -78.27 - 6 0.06 9.10 45.48 | 0.03 2.70 13.50 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.54 -69.73 - 7 0.06 9.09 54.58 | 0.03 2.70 16.20 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.53 -61.20 - 8 0.06 9.09 63.66 | 0.03 2.70 18.90 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.52 -52.68 - 9 0.06 9.07 72.74 | 0.03 2.69 21.59 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.51 -44.17 - 10 0.06 9.05 81.79 | 0.03 2.69 24.28 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.48 -35.69 - 11 0.06 9.03 90.82 | 0.03 2.68 26.96 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.45 -27.24 - 12 0.06 8.99 99.81 | 0.03 2.67 29.63 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.40 -18.84 - 13 0.06 8.94 108.75 | 0.03 2.66 32.29 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.34 -10.50 - 14 0.06 8.89 117.64 | 0.03 2.65 34.93 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.27 -2.23 - 15 0.06 8.83 126.46 | 0.03 2.63 37.56 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.20 5.97 - 16 0.06 8.76 135.23 | 0.03 2.61 40.18 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.11 14.08 - 17 0.06 8.69 143.92 | 0.03 2.59 42.77 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 8.02 22.11 - 18 0.06 8.62 152.53 | 0.03 2.57 45.34 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 7.93 30.03 - 19 0.06 8.54 161.07 | 0.03 2.55 47.89 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 7.83 37.86 - 20 0.06 8.45 169.52 | 0.03 2.53 50.41 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 7.72 45.58 - 21 0.06 8.37 177.89 | 0.03 2.50 52.91 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 7.61 53.19 - 22 0.06 8.29 186.18 | 0.03 2.48 55.39 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 7.50 60.70 - 23 0.06 8.20 194.38 | 0.03 2.45 57.84 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 7.39 68.09 - 24 0.06 8.11 202.49 | 0.03 2.43 60.27 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 7.28 75.37 - 25 0.06 8.03 210.52 | 0.03 2.40 62.67 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 7.17 82.53 - 26 0.06 7.94 218.46 | 0.03 2.37 65.04 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 7.05 89.58 - 27 0.06 7.85 226.32 | 0.03 2.34 67.38 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 6.94 96.52 - 28 0.06 7.77 234.08 | 0.03 2.32 69.70 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 6.83 103.35 - 29 0.06 7.68 241.77 | 0.03 2.29 71.99 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 6.71 110.06 - 30 0.06 7.60 249.37 | 0.03 2.26 74.25 | 0.03 0.00 0.00 | 0.00 0.00 0.00 | 3.26 6.60 116.67 + *************************************************************** + Year Thermal Drawdown (%) Geofluid Temperature (°C) Pump Power (MW) Net Power (MW) Net Heat (MW) First Law Efficiency (%) + 1 1.0000 227.00 0.1816 20.9791 13.6976 17.4835 + 2 1.0000 227.00 0.1816 20.9791 13.6976 17.4835 + 3 1.0000 227.00 0.1816 20.9791 13.6976 17.4835 + 4 1.0000 227.00 0.1816 20.9791 13.6976 17.4834 + 5 1.0000 227.00 0.1816 20.9787 13.6973 17.4833 + 6 0.9999 226.98 0.1816 20.9757 13.6957 17.4823 + 7 0.9997 226.94 0.1816 20.9660 13.6902 17.4788 + 8 0.9993 226.84 0.1816 20.9444 13.6780 17.4712 + 9 0.9985 226.67 0.1816 20.9067 13.6565 17.4578 + 10 0.9974 226.41 0.1816 20.8500 13.6243 17.4378 + 11 0.9959 226.06 0.1816 20.7734 13.5804 17.4106 + 12 0.9939 225.62 0.1816 20.6771 13.5250 17.3764 + 13 0.9916 225.09 0.1816 20.5623 13.4584 17.3354 + 14 0.9889 224.48 0.1816 20.4308 13.3814 17.2883 + 15 0.9859 223.80 0.1816 20.2846 13.2950 17.2358 + 16 0.9827 223.06 0.1816 20.1258 13.2000 17.1784 + 17 0.9792 222.27 0.1816 19.9563 13.0975 17.1169 + 18 0.9755 221.43 0.1816 19.7782 12.9884 17.0519 + 19 0.9716 220.56 0.1816 19.5931 12.8736 16.9840 + 20 0.9676 219.65 0.1816 19.4026 12.7538 16.9138 + 21 0.9635 218.72 0.1816 19.2081 12.6297 16.8416 + 22 0.9594 217.77 0.1816 19.0109 12.5020 16.7680 + 23 0.9551 216.81 0.1816 18.8118 12.3713 16.6932 + 24 0.9508 215.84 0.1816 18.6119 12.2382 16.6176 + 25 0.9465 214.86 0.1816 18.4119 12.1029 16.5415 + 26 0.9422 213.87 0.1816 18.2124 11.9661 16.4651 + 27 0.9378 212.89 0.1816 18.0140 11.8279 16.3886 + 28 0.9335 211.91 0.1816 17.8171 11.6888 16.3121 + 29 0.9292 210.93 0.1816 17.6221 11.5490 16.2360 + 30 0.9249 209.95 0.1816 17.4293 11.4088 16.1601 + + *************************************************************** + *ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE* + *************************************************************** + Year Heating Provided (kW) Electricity Provided (kWh) Heat Extracted(GW/yr) Reservoir Heat Content (MW) Percentage of Total Heat Mined (%) + 1 108.0 165.4 1066.02 73.14 4.99 + 2 108.0 165.4 1066.02 69.31 9.97 + 3 108.0 165.4 1066.02 65.47 14.96 + 4 108.0 165.4 1066.02 61.63 19.94 + 5 108.0 165.4 1065.98 57.79 24.93 + 6 108.0 165.3 1065.79 53.96 29.91 + 7 107.9 165.2 1065.32 50.12 34.89 + 8 107.8 165.0 1064.41 46.29 39.87 + 9 107.5 164.6 1062.95 42.46 44.84 + 10 107.2 164.1 1060.88 38.64 49.80 + 11 106.9 163.4 1058.19 34.83 54.75 + 12 106.4 162.6 1054.89 31.04 59.68 + 13 105.8 161.6 1051.03 27.25 64.60 + 14 105.2 160.5 1046.66 23.49 69.49 + 15 104.4 159.3 1041.85 19.73 74.36 + 16 103.7 158.0 1036.64 16.00 79.21 + 17 102.8 156.6 1031.09 12.29 84.03 + 18 102.0 155.2 1025.27 8.60 88.83 + 19 101.0 153.7 1019.22 4.93 93.59 + 20 100.1 152.2 1012.99 1.28 98.33 + 21 99.1 150.7 1006.61 -2.34 103.04 + 22 98.1 149.1 1000.11 -5.94 107.72 + 23 97.0 147.5 993.53 -9.52 112.36 + 24 96.0 145.9 986.90 -13.07 116.98 + 25 94.9 144.4 980.23 -16.60 121.56 + 26 93.8 142.8 973.55 -20.10 126.11 + 27 92.7 141.2 966.87 -23.58 130.64 + 28 91.6 139.7 960.20 -27.04 135.13 + 29 90.5 138.2 953.56 -30.47 139.58 + 30 80.5 123.1 852.56 -33.54 143.57 + + *************************************************************** + * REVENUE & CASHFLOW PROFILE * + *************************************************************** + Year Electricity:Price (USD/kWh) Electricity:Ann. Rev. (MUSD/yr) Electricity:Cumm. Rev. (MUSD) Heat:Price (USD/kWh) Heat:Ann. Rev. (MUSD/yr) Heat:Cumm. Rev. (MUSD) Cooling:Price (USD/kWh) Cooling:Ann. Rev. (MUSD/yr) Cooling:Cumm. Rev. (MUSD) Carbon:Price (USD/tonne) Carbon:Ann. Rev. (MUSD/yr) Carbon:Cumm. Rev. (MUSD) Project:OPEX (MUSD/yr) Project:Net Rev. (MUSD/yr) Project:Net Cashflow (MUSD) + 1 0.0000 0.00 0.00 0.0000 0.00 0.00 0.0000 0.00 0.00 0.0000 0.00 0.00 0.00 -112.42 -112.42 + 2 0.0550 9.10 9.10 0.0250 2.70 2.70 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.54 -103.88 + 3 0.0550 9.10 18.19 0.0250 2.70 5.40 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.54 -95.34 + 4 0.0550 9.10 27.29 0.0250 2.70 8.10 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.54 -86.81 + 5 0.0550 9.10 36.39 0.0250 2.70 10.80 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.54 -78.27 + 6 0.0550 9.10 45.48 0.0250 2.70 13.50 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.54 -69.73 + 7 0.0550 9.09 54.58 0.0250 2.70 16.20 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.53 -61.20 + 8 0.0550 9.09 63.66 0.0250 2.70 18.90 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.52 -52.68 + 9 0.0550 9.07 72.74 0.0250 2.69 21.59 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.51 -44.17 + 10 0.0550 9.05 81.79 0.0250 2.69 24.28 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.48 -35.69 + 11 0.0550 9.03 90.82 0.0250 2.68 26.96 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.45 -27.24 + 12 0.0550 8.99 99.81 0.0250 2.67 29.63 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.40 -18.84 + 13 0.0550 8.94 108.75 0.0250 2.66 32.29 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.34 -10.50 + 14 0.0550 8.89 117.64 0.0250 2.65 34.93 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.27 -2.23 + 15 0.0550 8.83 126.46 0.0250 2.63 37.56 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.20 5.97 + 16 0.0550 8.76 135.23 0.0250 2.61 40.18 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.11 14.08 + 17 0.0550 8.69 143.92 0.0250 2.59 42.77 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 8.02 22.11 + 18 0.0550 8.62 152.53 0.0250 2.57 45.34 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 7.93 30.03 + 19 0.0550 8.54 161.07 0.0250 2.55 47.89 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 7.83 37.86 + 20 0.0550 8.45 169.52 0.0250 2.53 50.41 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 7.72 45.58 + 21 0.0550 8.37 177.89 0.0250 2.50 52.91 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 7.61 53.19 + 22 0.0550 8.29 186.18 0.0250 2.48 55.39 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 7.50 60.70 + 23 0.0550 8.20 194.38 0.0250 2.45 57.84 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 7.39 68.09 + 24 0.0550 8.11 202.49 0.0250 2.43 60.27 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 7.28 75.37 + 25 0.0550 8.03 210.52 0.0250 2.40 62.67 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 7.17 82.53 + 26 0.0550 7.94 218.46 0.0250 2.37 65.04 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 7.05 89.58 + 27 0.0550 7.85 226.32 0.0250 2.34 67.38 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 6.94 96.52 + 28 0.0550 7.77 234.08 0.0250 2.32 69.70 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 6.83 103.35 + 29 0.0550 7.68 241.77 0.0250 2.29 71.99 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 6.71 110.06 + 30 0.0550 7.60 249.37 0.0250 2.26 74.25 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 6.60 116.67 + 31 0.0550 6.77 256.14 0.0250 2.01 76.27 0.0250 0.00 0.00 0.0000 0.00 0.00 3.26 5.52 122.19 diff --git a/tests/examples/S-DAC-GT.txt b/tests/examples/S-DAC-GT.txt index b41e9345..b86772f2 100644 --- a/tests/examples/S-DAC-GT.txt +++ b/tests/examples/S-DAC-GT.txt @@ -5,7 +5,9 @@ Based on Example 3 description: This example problem considers an EGS reservoir The heat is used in a combined heat and power topping cycle model with double flash as topping cycle and electricity considered as the main product. -But only lists those patameters that are different than their default values +But only lists those parameters that are different than their default values + +Do S-DAC-GT Calculations, True ***Subsurface technical parameters*** ************************************* diff --git a/tests/examples/Wanju_Yuan_Closed-Loop_Geothermal_Energy_Recovery.out b/tests/examples/Wanju_Yuan_Closed-Loop_Geothermal_Energy_Recovery.out index 2014c835..7079b5ea 100644 --- a/tests/examples/Wanju_Yuan_Closed-Loop_Geothermal_Energy_Recovery.out +++ b/tests/examples/Wanju_Yuan_Closed-Loop_Geothermal_Energy_Recovery.out @@ -211,7 +211,7 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 5.50 -126.72 0.00 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -126.72 -126.72 + 1 0.00 -126.72 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -126.72 -126.72 2 5.50 -0.38 0.66 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.38 -127.10 3 5.50 -0.52 1.19 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.52 -127.62 4 5.50 -0.50 1.73 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.05 -0.50 -128.13 diff --git a/tests/examples/example1.out b/tests/examples/example1.out index 826c49d7..3bc186eb 100644 --- a/tests/examples/example1.out +++ b/tests/examples/example1.out @@ -64,7 +64,7 @@ Simulation Metadata Reservoir Model = Multiple Parallel Fractures Model Bottom-hole temperature: 170.00 degC Fracture model = Square - Well seperation: fracture height: 900.00 meter + Well separation: fracture height: 900.00 meter Fracture area: 810000.00 m**2 Reservoir volume: 1000000000 m**3 Reservoir hydrostatic pressure: 29430.21 kPa @@ -210,7 +210,7 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 5.50 -53.39 0.00 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -53.39 -53.39 + 1 0.00 -53.39 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -53.39 -53.39 2 5.50 0.88 2.28 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.40 0.88 -52.50 3 5.50 0.91 4.58 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.40 0.91 -51.60 4 5.50 0.92 6.89 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.40 0.92 -50.68 diff --git a/tests/examples/example10_HP.out b/tests/examples/example10_HP.out index 38c4d596..afdaa9db 100644 --- a/tests/examples/example10_HP.out +++ b/tests/examples/example10_HP.out @@ -205,7 +205,7 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 5.50 0.00 0.00 | 2.50 -31.03 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -31.03 -31.03 + 1 0.00 0.00 0.00 | 0.00 -31.03 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -31.03 -31.03 2 5.50 0.00 0.00 | 2.50 2.78 3.40 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.61 2.78 -28.24 3 5.50 0.00 0.00 | 2.50 2.78 6.80 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.61 2.78 -25.46 4 5.50 0.00 0.00 | 2.50 2.78 10.19 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.61 2.78 -22.67 diff --git a/tests/examples/example11_AC.out b/tests/examples/example11_AC.out index caeb23c1..d167f2a7 100644 --- a/tests/examples/example11_AC.out +++ b/tests/examples/example11_AC.out @@ -210,7 +210,7 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 5.50 0.00 0.00 | 6.55 0.00 0.00 | 6.55 -29.68 0.00 | 0.00 0.00 0.00 | 0.00 -29.68 -29.68 + 1 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -29.68 0.00 | 0.00 0.00 0.00 | 0.00 -29.68 -29.68 2 5.50 0.00 0.00 | 6.55 0.00 0.00 | 6.55 2.36 2.94 | 0.00 0.00 0.00 | 0.58 2.36 -27.32 3 5.50 0.00 0.00 | 6.55 0.00 0.00 | 6.55 2.36 5.89 | 0.00 0.00 0.00 | 0.58 2.36 -24.96 4 5.50 0.00 0.00 | 6.55 0.00 0.00 | 6.55 2.36 8.83 | 0.00 0.00 0.00 | 0.58 2.36 -22.60 diff --git a/tests/examples/example12_DH.out b/tests/examples/example12_DH.out index d2bf5861..2e0b9a1f 100644 --- a/tests/examples/example12_DH.out +++ b/tests/examples/example12_DH.out @@ -219,7 +219,7 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 5.50 0.00 0.00 | 2.50 -45.63 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -45.63 -45.63 + 1 0.00 0.00 0.00 | 0.00 -45.63 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -45.63 -45.63 2 5.50 0.00 0.00 | 2.50 2.17 3.73 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.56 2.17 -43.46 3 5.50 0.00 0.00 | 2.50 2.17 7.46 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.56 2.17 -41.29 4 5.50 0.00 0.00 | 2.50 2.16 11.18 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.56 2.16 -39.13 diff --git a/tests/examples/example13.out b/tests/examples/example13.out index b4bab32a..efe02129 100644 --- a/tests/examples/example13.out +++ b/tests/examples/example13.out @@ -217,7 +217,7 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 5.50 0.00 0.00 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -56.29 -56.29 + 1 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -56.29 -56.29 2 5.50 1.22 1.22 | 2.50 3.30 3.30 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.11 1.40 -54.89 3 5.50 1.22 2.44 | 2.50 3.21 6.50 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.11 1.31 -53.58 4 5.50 1.22 3.65 | 2.50 3.11 9.62 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.11 1.21 -52.36 diff --git a/tests/examples/example1_addons.out b/tests/examples/example1_addons.out index 04cdb8ae..fb91888d 100644 --- a/tests/examples/example1_addons.out +++ b/tests/examples/example1_addons.out @@ -4,11 +4,11 @@ Simulation Metadata ---------------------- - GEOPHIRES Version: 3.4.21 + GEOPHIRES Version: 3.4.22 GEOPHIRES Build Date: 2024-03-05 - Simulation Date: 2024-03-12 - Simulation Time: 07:19 - Calculation Time: 0.616 sec + Simulation Date: 2024-04-11 + Simulation Time: 14:48 + Calculation Time: 1.448 sec ***SUMMARY OF RESULTS*** @@ -65,7 +65,7 @@ Simulation Metadata Reservoir Model = Multiple Parallel Fractures Model Bottom-hole temperature: 170.00 degC Fracture model = Square - Well seperation: fracture height: 900.00 meter + Well separation: fracture height: 900.00 meter Fracture area: 810000.00 m**2 Reservoir volume: 1000000000 m**3 Reservoir hydrostatic pressure: 29430.21 kPa @@ -211,20 +211,20 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 9.00 -31.06 0.00 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.01 0.00 0.00 | 0.00 -31.06 -31.06 + 1 0.00 -31.06 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -31.06 -31.06 2 9.00 5.05 3.73 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.01 0.51 0.51 | -0.82 5.05 -26.01 3 9.00 5.10 7.50 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.01 0.52 1.02 | -0.82 5.10 -20.91 4 9.00 5.12 11.28 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.01 0.52 1.54 | -0.82 5.12 -15.79 5 9.00 5.13 15.07 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.01 0.52 2.06 | -0.82 5.13 -10.66 6 9.00 5.13 18.87 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.01 0.52 2.58 | -0.82 5.13 -5.53 - 7 10.20 5.14 22.67 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.03 0.52 3.10 | -0.82 5.14 -0.39 - 8 11.40 6.00 26.98 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.04 0.87 3.96 | -0.82 6.00 5.60 - 9 12.60 6.85 31.81 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.04 1.21 5.18 | -0.82 6.85 12.46 - 10 13.80 7.71 37.14 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.06 1.56 6.74 | -0.82 7.71 20.17 - 11 15.00 8.57 42.99 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.07 1.91 8.65 | -0.82 8.57 28.75 + 7 9.00 5.14 22.67 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.01 0.52 3.10 | -0.82 5.14 -0.39 + 8 10.20 6.00 26.98 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.03 0.87 3.96 | -0.82 6.00 5.60 + 9 11.40 6.85 31.81 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.04 1.21 5.18 | -0.82 6.85 12.46 + 10 12.60 7.71 37.14 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.04 1.56 6.74 | -0.82 7.71 20.17 + 11 13.80 8.57 42.99 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.06 1.91 8.65 | -0.82 8.57 28.75 12 15.00 9.43 49.34 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.07 2.26 10.91 | -0.82 9.43 38.18 - 13 15.00 9.78 55.70 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.09 2.61 13.52 | -0.82 9.78 47.96 - 14 15.00 10.14 62.06 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.10 2.96 16.47 | -0.82 10.14 58.10 + 13 15.00 9.78 55.70 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.07 2.61 13.52 | -0.82 9.78 47.96 + 14 15.00 10.14 62.06 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.09 2.96 16.47 | -0.82 10.14 58.10 15 15.00 10.49 68.43 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.10 3.31 19.78 | -0.82 10.49 68.59 16 15.00 10.66 74.80 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.10 3.48 23.26 | -0.82 10.66 79.25 17 15.00 10.67 81.17 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.10 3.48 26.74 | -0.82 10.67 89.92 @@ -268,17 +268,17 @@ ________________________________________________________________________________ Year Electricity Heat Add-on Annual AddOn Cumm. AddOn Annual Project Cumm. Project Since Price Revenue Price Revenue Revenue Cash Flow Cash Flow Cash Flow Cash Flow Start (cents/kWh)(MUSD/yr) (cents/kWh)(MUSD/yr) (MUSD/yr) (MUSD/yr) (MUSD) (MUSD/yr) (MUSD) - 1 0.090 0.0023 0.012 0.0000 1.14 -70.00 -70.00 -101.06 -101.06 + 1 0.000 0.0023 0.000 0.0000 1.14 -70.00 -70.00 -101.06 -101.06 2 0.090 0.0023 0.012 0.0000 1.14 1.14 -68.86 5.68 -95.38 3 0.090 0.0023 0.012 0.0000 1.14 1.14 -67.72 5.72 -89.65 4 0.090 0.0023 0.012 0.0000 1.14 1.14 -66.59 5.74 -83.91 5 0.090 0.0023 0.012 0.0000 1.14 1.14 -65.45 5.75 -78.17 6 0.090 0.0023 0.012 0.0000 1.14 1.14 -64.31 5.75 -72.42 - 7 0.102 0.0026 0.012 0.0000 1.14 1.14 -63.17 5.76 -66.66 - 8 0.114 0.0030 0.012 0.0000 1.14 1.14 -62.03 6.27 -60.39 - 9 0.126 0.0033 0.022 0.0000 1.14 1.14 -60.89 6.78 -53.61 - 10 0.138 0.0036 0.032 0.0000 1.14 1.14 -59.75 7.29 -46.32 - 11 0.150 0.0039 0.036 0.0000 1.14 1.14 -58.61 7.80 -38.52 + 7 0.090 0.0026 0.012 0.0000 1.14 1.14 -63.17 5.76 -66.66 + 8 0.102 0.0030 0.012 0.0000 1.14 1.14 -62.03 6.27 -60.39 + 9 0.114 0.0033 0.012 0.0000 1.14 1.14 -60.89 6.78 -53.61 + 10 0.126 0.0036 0.022 0.0000 1.14 1.14 -59.75 7.29 -46.32 + 11 0.138 0.0039 0.032 0.0000 1.14 1.14 -58.61 7.80 -38.52 12 0.150 0.0039 0.036 0.0000 1.14 1.14 -57.47 8.31 -30.21 13 0.150 0.0039 0.036 0.0000 1.14 1.14 -56.33 8.32 -21.89 14 0.150 0.0039 0.036 0.0000 1.14 1.14 -55.19 8.32 -13.57 diff --git a/tests/examples/example2.out b/tests/examples/example2.out index 8e54f4e7..c87d6f3d 100644 --- a/tests/examples/example2.out +++ b/tests/examples/example2.out @@ -195,7 +195,7 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 5.50 0.00 0.00 | 2.50 -40.91 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -40.91 -40.91 + 1 0.00 0.00 0.00 | 0.00 -40.91 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -40.91 -40.91 2 5.50 0.00 0.00 | 2.50 3.26 4.34 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.08 3.26 -37.65 3 5.50 0.00 0.00 | 2.50 3.31 8.72 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.08 3.31 -34.34 4 5.50 0.00 0.00 | 2.50 3.33 13.13 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.08 3.33 -31.01 diff --git a/tests/examples/example3.out b/tests/examples/example3.out index 61ec4cbc..6b762615 100644 --- a/tests/examples/example3.out +++ b/tests/examples/example3.out @@ -223,7 +223,7 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 5.50 0.00 0.00 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -111.58 -111.58 + 1 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -111.58 -111.58 2 5.50 9.09 9.09 | 2.50 2.23 2.23 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.23 8.09 -103.49 3 5.50 9.09 18.18 | 2.50 2.23 4.47 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.23 8.09 -95.40 4 5.50 9.09 27.27 | 2.50 2.23 6.70 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.23 8.09 -87.31 diff --git a/tests/examples/example4.out b/tests/examples/example4.out index ad0212ae..5a851487 100644 --- a/tests/examples/example4.out +++ b/tests/examples/example4.out @@ -208,7 +208,7 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 5.50 -55.40 0.00 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -55.40 -55.40 + 1 0.00 -55.40 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -55.40 -55.40 2 5.50 1.73 3.53 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.80 1.73 -53.66 3 5.50 1.70 7.03 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.80 1.70 -51.96 4 5.50 1.66 10.48 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.80 1.66 -50.30 diff --git a/tests/examples/example5.out b/tests/examples/example5.out index 75c777d2..9a61725e 100644 --- a/tests/examples/example5.out +++ b/tests/examples/example5.out @@ -201,7 +201,7 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 5.50 0.00 0.00 | 2.50 -41.38 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -41.38 -41.38 + 1 0.00 0.00 0.00 | 0.00 -41.38 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -41.38 -41.38 2 5.50 0.00 0.00 | 2.50 3.53 4.71 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.18 3.53 -37.86 3 5.50 0.00 0.00 | 2.50 3.57 9.46 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.18 3.57 -34.28 4 5.50 0.00 0.00 | 2.50 3.58 14.22 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.18 3.58 -30.70 diff --git a/tests/examples/example8.out b/tests/examples/example8.out index 4825a559..9d940954 100644 --- a/tests/examples/example8.out +++ b/tests/examples/example8.out @@ -63,7 +63,7 @@ Simulation Metadata Reservoir Model = Multiple Parallel Fractures Model Bottom-hole temperature: 98.40 degC Fracture model = Square - Well seperation: fracture height: 700.00 meter + Well separation: fracture height: 700.00 meter Fracture area: 490000.00 m**2 Reservoir volume calculated with fracture separation and number of fractures as input Number of fractures: 5.00 @@ -205,7 +205,7 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 5.50 0.00 0.00 | 2.50 -21.06 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -21.06 -21.06 + 1 0.00 0.00 0.00 | 0.00 -21.06 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -21.06 -21.06 2 5.50 0.00 0.00 | 2.50 0.82 1.25 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.44 0.82 -20.24 3 5.50 0.00 0.00 | 2.50 0.82 2.51 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.44 0.82 -19.42 4 5.50 0.00 0.00 | 2.50 0.83 3.78 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.44 0.83 -18.59 diff --git a/tests/examples/example9.out b/tests/examples/example9.out index a4bef5fd..85074888 100644 --- a/tests/examples/example9.out +++ b/tests/examples/example9.out @@ -64,7 +64,7 @@ Simulation Metadata Reservoir Model = Multiple Parallel Fractures Model Bottom-hole temperature: 126.40 degC Fracture model = Square - Well seperation: fracture height: 700.00 meter + Well separation: fracture height: 700.00 meter Fracture area: 490000.00 m**2 Reservoir volume calculated with fracture separation and number of fractures as input Number of fractures: 5.00 @@ -212,7 +212,7 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 5.50 -27.42 0.00 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -27.42 -27.42 + 1 0.00 -27.42 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -27.42 -27.42 2 5.50 -0.28 0.20 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.48 -0.28 -27.70 3 5.50 -0.27 0.41 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.48 -0.27 -27.97 4 5.50 -0.27 0.63 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.48 -0.27 -28.24 diff --git a/tests/examples/example_ITC.out b/tests/examples/example_ITC.out new file mode 100644 index 00000000..42f514c9 --- /dev/null +++ b/tests/examples/example_ITC.out @@ -0,0 +1,241 @@ + ***************** + ***CASE REPORT*** + ***************** + +Simulation Metadata +---------------------- + GEOPHIRES Version: 3.4.22 + GEOPHIRES Build Date: 2024-03-05 + Simulation Date: 2024-04-12 + Simulation Time: 05:01 + Calculation Time: 0.622 sec + + ***SUMMARY OF RESULTS*** + + End-Use Option: Electricity + Average Net Electricity Production: 18.57 MW + Electricity breakeven price: 3.46 cents/kWh + Number of production wells: 2 + Number of injection wells: 2 + Flowrate per production well: 55.0 kg/sec + Well depth (or total length, if not vertical): 5.0 kilometer + Geothermal gradient: 0.0550 degC/m + + + ***ECONOMIC PARAMETERS*** + + Economic Model = BICYCLE + Accrued financing during construction: 0.00 + Project lifetime: 30 yr + Capacity factor: 90.0 % + Project NPV: 6.91 MUSD + Project IRR: 7.32 % + Project VIR=PI=PIR: 1.12 + Project MOIC: 0.59 + Project Payback Period: 13.01 yr + + ***ENGINEERING PARAMETERS*** + + Number of Production Wells: 2 + Number of Injection Wells: 2 + Well depth (or total length, if not vertical): 5.0 kilometer + Water loss rate: 2.0 + Pump efficiency: 80.0 + Injection temperature: 50.0 degC + Production Wellbore heat transmission calculated with Ramey's model + Average production well temperature drop: 9.3 degC + Flowrate per production well: 55.0 kg/sec + Injection well casing ID: 7.000 in + Production well casing ID: 7.000 in + Number of times redrilling: 0 + Power plant type: Supercritical ORC + + + ***RESOURCE CHARACTERISTICS*** + + Maximum reservoir temperature: 500.0 degC + Number of segments: 1 + Geothermal gradient: 0.0550 degC/m + + + ***RESERVOIR PARAMETERS*** + + Reservoir Model = Multiple Parallel Fractures Model + Bottom-hole temperature: 295.00 degC + Fracture model = Square + Well separation: fracture height: 900.00 meter + Fracture area: 810000.00 m**2 + Reservoir volume: 1000000000 m**3 + Reservoir hydrostatic pressure: 47300.51 kPa + Plant outlet pressure: 8274.86 kPa + Production wellhead pressure: 8343.81 kPa + Productivity Index: 5.00 kg/sec/bar + Injectivity Index: 5.00 kg/sec/bar + Reservoir density: 2700.00 kg/m**3 + Reservoir thermal conductivity: 2.70 W/m/K + Reservoir heat capacity: 1000.00 J/kg/K + + + ***RESERVOIR SIMULATION RESULTS*** + + Maximum Production Temperature: 286.6 degC + Average Production Temperature: 285.7 degC + Minimum Production Temperature: 280.6 degC + Initial Production Temperature: 280.6 degC + Average Reservoir Heat Extraction: 104.70 MW + Production Wellbore Heat Transmission Model = Ramey Model + Average Production Well Temperature Drop: 9.3 degC + Average Injection Well Pump Pressure Drop: -9569.9 kPa + Average Production Well Pump Pressure Drop: 5417.0 kPa + + + ***CAPITAL COSTS (M$)*** + + Drilling and completion costs: 47.16 MUSD + Drilling and completion costs per well: 11.79 MUSD + Stimulation costs: 0.00 MUSD + Surface power plant costs: 59.81 MUSD + Field gathering system costs: 2.64 MUSD + Total surface equipment costs: 62.45 MUSD + Exploration costs: 9.97 MUSD + Investment Tax Credit: -59.79 MUSD + Total capital costs: 59.79 MUSD + + + ***OPERATING AND MAINTENANCE COSTS (M$/yr)*** + + Wellfield maintenance costs: 0.90 MUSD/yr + Power plant maintenance costs: 2.09 MUSD/yr + Water costs: 0.06 MUSD/yr + Total operating and maintenance costs: 3.04 MUSD/yr + + + ***SURFACE EQUIPMENT SIMULATION RESULTS*** + + Initial geofluid availability: 0.34 MW/(kg/s) + Maximum Total Electricity Generation: 19.52 MW + Average Total Electricity Generation: 19.44 MW + Minimum Total Electricity Generation: 18.94 MW + Initial Total Electricity Generation: 18.94 MW + Maximum Net Electricity Generation: 18.65 MW + Average Net Electricity Generation: 18.57 MW + Minimum Net Electricity Generation: 18.05 MW + Initial Net Electricity Generation: 18.05 MW + Average Annual Total Electricity Generation: 152.46 GWh + Average Annual Net Electricity Generation: 145.62 GWh + Initial pumping power/net installed power: 4.88 % + Average Pumping Power: 0.87 MW + + ************************************************************ + * HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE * + ************************************************************ + YEAR THERMAL GEOFLUID PUMP NET FIRST LAW + DRAWDOWN TEMPERATURE POWER POWER EFFICIENCY + (degC) (MW) (MW) (%) + 1 1.0000 280.56 0.8811 18.0542 17.6327 + 2 1.0102 283.41 0.8763 18.3435 17.6961 + 3 1.0131 284.23 0.8750 18.4252 17.7125 + 4 1.0146 284.66 0.8742 18.4675 17.7206 + 5 1.0157 284.95 0.8738 18.4954 17.7259 + 6 1.0164 285.16 0.8734 18.5159 17.7298 + 7 1.0170 285.32 0.8731 18.5321 17.7327 + 8 1.0175 285.46 0.8729 18.5453 17.7351 + 9 1.0179 285.57 0.8727 18.5564 17.7372 + 10 1.0182 285.67 0.8726 18.5659 17.7389 + 11 1.0185 285.76 0.8724 18.5743 17.7404 + 12 1.0188 285.83 0.8723 18.5818 17.7417 + 13 1.0191 285.90 0.8722 18.5885 17.7429 + 14 1.0193 285.97 0.8721 18.5945 17.7440 + 15 1.0195 286.02 0.8720 18.6000 17.7449 + 16 1.0197 286.08 0.8719 18.6051 17.7458 + 17 1.0198 286.12 0.8718 18.6098 17.7466 + 18 1.0200 286.17 0.8717 18.6142 17.7474 + 19 1.0202 286.21 0.8717 18.6182 17.7481 + 20 1.0203 286.25 0.8716 18.6220 17.7488 + 21 1.0204 286.29 0.8715 18.6256 17.7494 + 22 1.0206 286.32 0.8715 18.6290 17.7500 + 23 1.0207 286.36 0.8714 18.6322 17.7505 + 24 1.0208 286.39 0.8714 18.6352 17.7510 + 25 1.0209 286.42 0.8713 18.6381 17.7515 + 26 1.0210 286.45 0.8713 18.6408 17.7520 + 27 1.0211 286.47 0.8712 18.6434 17.7524 + 28 1.0212 286.50 0.8712 18.6459 17.7529 + 29 1.0213 286.52 0.8711 18.6483 17.7533 + 30 1.0214 286.55 0.8711 18.6505 17.7537 + + + ******************************************************************* + * ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE * + ******************************************************************* + YEAR ELECTRICITY HEAT RESERVOIR PERCENTAGE OF + PROVIDED EXTRACTED HEAT CONTENT TOTAL HEAT MINED + (GWh/year) (GWh/year) (10^15 J) (%) + 1 143.6 812.8 658.57 0.44 + 2 145.0 818.9 655.63 0.89 + 3 145.4 820.9 652.67 1.33 + 4 145.7 822.2 649.71 1.78 + 5 145.9 823.0 646.75 2.23 + 6 146.0 823.7 643.78 2.68 + 7 146.2 824.2 640.82 3.13 + 8 146.3 824.6 637.85 3.58 + 9 146.3 825.0 634.88 4.02 + 10 146.4 825.3 631.91 4.47 + 11 146.5 825.6 628.93 4.92 + 12 146.5 825.9 625.96 5.37 + 13 146.6 826.1 622.99 5.82 + 14 146.6 826.3 620.01 6.27 + 15 146.7 826.5 617.04 6.72 + 16 146.7 826.7 614.06 7.17 + 17 146.7 826.8 611.08 7.62 + 18 146.8 827.0 608.11 8.07 + 19 146.8 827.1 605.13 8.52 + 20 146.8 827.3 602.15 8.97 + 21 146.9 827.4 599.17 9.42 + 22 146.9 827.5 596.19 9.87 + 23 146.9 827.6 593.21 10.32 + 24 146.9 827.7 590.23 10.77 + 25 147.0 827.8 587.25 11.22 + 26 147.0 827.9 584.27 11.67 + 27 147.0 828.0 581.29 12.12 + 28 147.0 828.1 578.31 12.58 + 29 147.0 828.2 575.33 13.03 + 30 122.5 690.2 572.85 13.40 + + + ******************************** + * REVENUE & CASHFLOW PROFILE * + ******************************** +Year Electricity | Heat | Cooling | Carbon | Project +Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow +Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) +________________________________________________________________________________________________________________________________________________________________________________________ + 1 0.00 -59.79 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -59.79 -59.79 + 2 5.50 4.85 7.90 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 4.85 -54.93 + 3 5.50 4.93 15.87 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 4.93 -50.00 + 4 5.50 4.96 23.87 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 4.96 -45.05 + 5 5.50 4.97 31.89 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 4.97 -40.08 + 6 5.50 4.98 39.91 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 4.98 -35.09 + 7 5.50 4.99 47.94 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 4.99 -30.11 + 8 5.50 5.00 55.98 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.00 -25.11 + 9 5.50 5.00 64.03 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.00 -20.11 + 10 5.50 5.00 72.08 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.00 -15.11 + 11 5.50 5.01 80.13 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.01 -10.10 + 12 5.50 5.01 88.18 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.01 -5.09 + 13 5.50 5.02 96.24 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.02 -0.07 + 14 5.50 5.02 104.30 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.02 4.95 + 15 5.50 5.02 112.37 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.02 9.97 + 16 5.50 5.02 120.43 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.02 14.99 + 17 5.50 5.02 128.50 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.02 20.02 + 18 5.50 5.03 136.57 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.03 25.04 + 19 5.50 5.03 144.65 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.03 30.07 + 20 5.50 5.03 152.72 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.03 35.10 + 21 5.50 5.03 160.80 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.03 40.13 + 22 5.50 5.03 168.87 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.03 45.17 + 23 5.50 5.03 176.95 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.03 50.20 + 24 5.50 5.04 185.03 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 55.24 + 25 5.50 5.04 193.11 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 60.27 + 26 5.50 5.04 201.20 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 65.31 + 27 5.50 5.04 209.28 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 70.35 + 28 5.50 5.04 217.36 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 75.39 + 29 5.50 5.04 225.45 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 80.44 + 30 5.50 5.04 233.54 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 85.48 diff --git a/tests/examples/example_ITC.txt b/tests/examples/example_ITC.txt new file mode 100644 index 00000000..c807539c --- /dev/null +++ b/tests/examples/example_ITC.txt @@ -0,0 +1,84 @@ +--- GEOPHIRES v3 Input File +--- Created on 2024-04-12 +--- Investment Tax Credit (ITC) Example + +***Subsurface technical parameters*** +************************************* +Reservoir Model,1, ---Multiple Fractures reservoir model +Reservoir Depth,5, ---[km] +Number of Segments,1, ---[-] +Gradient 1,55, ---[deg.C/km] +Maximum Temperature,500, ---[deg.C] +Number of Production Wells,2, ---[-] +Number of Injection Wells,2, ---[-] +Production Well Diameter,7, ---[inch] +Injection Well Diameter,7, ---[inch] +Ramey Production Wellbore Model,1, ---0 if disabled 1 if enabled +Production Wellbore Temperature Drop,.5, ---[deg.C] +Injection Wellbore Temperature Gain,0, ---[deg.C] +Production Flow Rate per Well,55, ---[kg/s] +Fracture Shape,3, ---[-] Should be 1 2 3 or 4. See manual for details +Fracture Height,900, ---[m] +Reservoir Volume Option,3, ---[-] Should be 1 2 3 or 4. See manual for details +Number of Fractures,20, ---[-] +Reservoir Volume,1000000000, ---[m^3] +Water Loss Fraction,.02, ---[-] +Productivity Index,5, ---[kg/s/bar] +Injectivity Index,5, ---[kg/s/bar] +Injection Temperature,50, ---[deg.C] +Maximum Drawdown,1, ---[-] no redrilling considered +Reservoir Heat Capacity,1000, ---[J/kg/K] +Reservoir Density,2700, ---[kg/m^3] +Reservoir Thermal Conductivity,2.7, ---[W/m/K] + +***SURFACE TECHNICAL PARAMETERS*** +********************************** +End-Use Option,1, ---[-] Electricity +Power Plant Type,2, ---[-] Supercritical ORC +Circulation Pump Efficiency,.8, ---[-] between .1 and 1 +Utilization Factor,.9, ---[-] between .1 and 1 +Surface Temperature,20, ---[deg.C] +Ambient Temperature,20, ---[deg.C] + +***CAPITAL AND O&M COST PARAMETERS*** +************************************* +Well Drilling and Completion Capital Cost Adjustment Factor,1, ---[-] Use built-in correlations +Well Drilling Cost Correlation,1, ---[-] Use built-in correlations +Reservoir Stimulation Capital Cost Adjustment Factor,1, ---[-] Use built-in correlations +Surface Plant Capital Cost Adjustment Factor,1, ---[-] Use built-in correlations +Field Gathering System Capital Cost Adjustment Factor,1, ---[-] Use built-in correlations +Exploration Capital Cost Adjustment Factor,1, ---[-] Use built-in correlations +Wellfield O&M Cost Adjustment Factor,1, ---[-] Use built-in correlations +Surface Plant O&M Cost Adjustment Factor,1, ---[-] Use built-in correlations +Water Cost Adjustment Factor,1, ---[-] Use built-in correlations + + +*** Economic/Financial Parameters *** +************************************* +Plant Lifetime,30, --- [years] +Economic Model,3, --- Should be 1 (FCR model) 2 (Standard LCOE/LCOH model) or 3 (Bicycle model). +Fraction of Investment in Bonds,0.65, --- [-] Required if Bicycle model is selected. See manual for details. +Inflated Bond Interest Rate,0.07, --- [-] Required if Bicycle model is selected. See manual for details. +Inflated Equity Interest Rate,0.12, --- [-] Required if Bicycle model is selected. See manual for details. +Inflation Rate,0.025, --- [-] Required if Bicycle model is selected. See manual for details. +Combined Income Tax Rate,0.392, --- [-] Required if Bicycle model is selected. See manual for details. +Gross Revenue Tax Rate,0, --- [-] Required if Bicycle model is selected. See manual for details. +Investment Tax Credit Rate,0, --- [-] Required if Bicycle model is selected. See manual for details. +Property Tax Rate,0, --- [-] Required if Bicycle model is selected. See manual for details. +Inflation Rate During Construction,0, --- [-] +Well Drilling and Completion Capital Cost Adjustment Factor,1, --- [-] Use built-in well cost correlation as is +Well Drilling Cost Correlation,1, --- [-] Use built-in well drilling cost correlation #1 +Reservoir Stimulation Capital Cost,0, --- [M$/injection well] Reservoir stimulation capital cost per injection well +Surface Plant Capital Cost Adjustment Factor,1, --- [-] Use built-in surface plant cost correlation as is +Field Gathering System Capital Cost Adjustment Factor,1, --- [-] Use built-in pipeline distribution cost correlation as is +Exploration Capital Cost Adjustment Factor,1, --- [-] Use built-in exploration cost correlation as is +Wellfield O&M Cost Adjustment Factor,1, --- [-] Use built-in wellfield O&M cost correlation as is +Water Cost Adjustment Factor,1, --- [-] Use built-in water cost correlation as is +Surface Plant O&M Cost Adjustment Factor,1, --- [-] Use built-in surface plant O&M cost correlation as is +Investment Tax Credit Rate,0.5, --- [-] Investment tax credit rate + +***Simulation Parameters*** +*************************** + +Print Output to Console,1, ---[-] Should be 0 (don't print results) or 1 (print results) +Time steps per year,6, ---[1/year] diff --git a/tests/examples/example_PTC.out b/tests/examples/example_PTC.out new file mode 100644 index 00000000..89d1770f --- /dev/null +++ b/tests/examples/example_PTC.out @@ -0,0 +1,240 @@ + ***************** + ***CASE REPORT*** + ***************** + +Simulation Metadata +---------------------- + GEOPHIRES Version: 3.4.22 + GEOPHIRES Build Date: 2024-03-05 + Simulation Date: 2024-04-12 + Simulation Time: 05:07 + Calculation Time: 0.635 sec + + ***SUMMARY OF RESULTS*** + + End-Use Option: Electricity + Average Net Electricity Production: 18.57 MW + Electricity breakeven price: 8.91 cents/kWh + Number of production wells: 2 + Number of injection wells: 2 + Flowrate per production well: 55.0 kg/sec + Well depth (or total length, if not vertical): 5.0 kilometer + Geothermal gradient: 0.0550 degC/m + + + ***ECONOMIC PARAMETERS*** + + Economic Model = BICYCLE + Accrued financing during construction: 0.00 + Project lifetime: 30 yr + Capacity factor: 90.0 % + Project NPV: 5.73 MUSD + Project IRR: 6.85 % + Project VIR=PI=PIR: 1.05 + Project MOIC: 0.53 + Project Payback Period: 10.17 yr + + ***ENGINEERING PARAMETERS*** + + Number of Production Wells: 2 + Number of Injection Wells: 2 + Well depth (or total length, if not vertical): 5.0 kilometer + Water loss rate: 2.0 + Pump efficiency: 80.0 + Injection temperature: 50.0 degC + Production Wellbore heat transmission calculated with Ramey's model + Average production well temperature drop: 9.3 degC + Flowrate per production well: 55.0 kg/sec + Injection well casing ID: 7.000 in + Production well casing ID: 7.000 in + Number of times redrilling: 0 + Power plant type: Supercritical ORC + + + ***RESOURCE CHARACTERISTICS*** + + Maximum reservoir temperature: 500.0 degC + Number of segments: 1 + Geothermal gradient: 0.0550 degC/m + + + ***RESERVOIR PARAMETERS*** + + Reservoir Model = Multiple Parallel Fractures Model + Bottom-hole temperature: 295.00 degC + Fracture model = Square + Well separation: fracture height: 900.00 meter + Fracture area: 810000.00 m**2 + Reservoir volume: 1000000000 m**3 + Reservoir hydrostatic pressure: 47300.51 kPa + Plant outlet pressure: 8274.86 kPa + Production wellhead pressure: 8343.81 kPa + Productivity Index: 5.00 kg/sec/bar + Injectivity Index: 5.00 kg/sec/bar + Reservoir density: 2700.00 kg/m**3 + Reservoir thermal conductivity: 2.70 W/m/K + Reservoir heat capacity: 1000.00 J/kg/K + + + ***RESERVOIR SIMULATION RESULTS*** + + Maximum Production Temperature: 286.6 degC + Average Production Temperature: 285.7 degC + Minimum Production Temperature: 280.6 degC + Initial Production Temperature: 280.6 degC + Average Reservoir Heat Extraction: 104.70 MW + Production Wellbore Heat Transmission Model = Ramey Model + Average Production Well Temperature Drop: 9.3 degC + Average Injection Well Pump Pressure Drop: -9569.9 kPa + Average Production Well Pump Pressure Drop: 5417.0 kPa + + + ***CAPITAL COSTS (M$)*** + + Drilling and completion costs: 47.16 MUSD + Drilling and completion costs per well: 11.79 MUSD + Stimulation costs: 0.00 MUSD + Surface power plant costs: 59.81 MUSD + Field gathering system costs: 2.64 MUSD + Total surface equipment costs: 62.45 MUSD + Exploration costs: 9.97 MUSD + Total capital costs: 119.57 MUSD + + + ***OPERATING AND MAINTENANCE COSTS (M$/yr)*** + + Wellfield maintenance costs: 0.90 MUSD/yr + Power plant maintenance costs: 2.09 MUSD/yr + Water costs: 0.06 MUSD/yr + Total operating and maintenance costs: 3.04 MUSD/yr + + + ***SURFACE EQUIPMENT SIMULATION RESULTS*** + + Initial geofluid availability: 0.34 MW/(kg/s) + Maximum Total Electricity Generation: 19.52 MW + Average Total Electricity Generation: 19.44 MW + Minimum Total Electricity Generation: 18.94 MW + Initial Total Electricity Generation: 18.94 MW + Maximum Net Electricity Generation: 18.65 MW + Average Net Electricity Generation: 18.57 MW + Minimum Net Electricity Generation: 18.05 MW + Initial Net Electricity Generation: 18.05 MW + Average Annual Total Electricity Generation: 152.46 GWh + Average Annual Net Electricity Generation: 145.62 GWh + Initial pumping power/net installed power: 4.88 % + Average Pumping Power: 0.87 MW + + ************************************************************ + * HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE * + ************************************************************ + YEAR THERMAL GEOFLUID PUMP NET FIRST LAW + DRAWDOWN TEMPERATURE POWER POWER EFFICIENCY + (degC) (MW) (MW) (%) + 1 1.0000 280.56 0.8811 18.0542 17.6327 + 2 1.0102 283.41 0.8763 18.3435 17.6961 + 3 1.0131 284.23 0.8750 18.4252 17.7125 + 4 1.0146 284.66 0.8742 18.4675 17.7206 + 5 1.0157 284.95 0.8738 18.4954 17.7259 + 6 1.0164 285.16 0.8734 18.5159 17.7298 + 7 1.0170 285.32 0.8731 18.5321 17.7327 + 8 1.0175 285.46 0.8729 18.5453 17.7351 + 9 1.0179 285.57 0.8727 18.5564 17.7372 + 10 1.0182 285.67 0.8726 18.5659 17.7389 + 11 1.0185 285.76 0.8724 18.5743 17.7404 + 12 1.0188 285.83 0.8723 18.5818 17.7417 + 13 1.0191 285.90 0.8722 18.5885 17.7429 + 14 1.0193 285.97 0.8721 18.5945 17.7440 + 15 1.0195 286.02 0.8720 18.6000 17.7449 + 16 1.0197 286.08 0.8719 18.6051 17.7458 + 17 1.0198 286.12 0.8718 18.6098 17.7466 + 18 1.0200 286.17 0.8717 18.6142 17.7474 + 19 1.0202 286.21 0.8717 18.6182 17.7481 + 20 1.0203 286.25 0.8716 18.6220 17.7488 + 21 1.0204 286.29 0.8715 18.6256 17.7494 + 22 1.0206 286.32 0.8715 18.6290 17.7500 + 23 1.0207 286.36 0.8714 18.6322 17.7505 + 24 1.0208 286.39 0.8714 18.6352 17.7510 + 25 1.0209 286.42 0.8713 18.6381 17.7515 + 26 1.0210 286.45 0.8713 18.6408 17.7520 + 27 1.0211 286.47 0.8712 18.6434 17.7524 + 28 1.0212 286.50 0.8712 18.6459 17.7529 + 29 1.0213 286.52 0.8711 18.6483 17.7533 + 30 1.0214 286.55 0.8711 18.6505 17.7537 + + + ******************************************************************* + * ANNUAL HEATING, COOLING AND/OR ELECTRICITY PRODUCTION PROFILE * + ******************************************************************* + YEAR ELECTRICITY HEAT RESERVOIR PERCENTAGE OF + PROVIDED EXTRACTED HEAT CONTENT TOTAL HEAT MINED + (GWh/year) (GWh/year) (10^15 J) (%) + 1 143.6 812.8 658.57 0.44 + 2 145.0 818.9 655.63 0.89 + 3 145.4 820.9 652.67 1.33 + 4 145.7 822.2 649.71 1.78 + 5 145.9 823.0 646.75 2.23 + 6 146.0 823.7 643.78 2.68 + 7 146.2 824.2 640.82 3.13 + 8 146.3 824.6 637.85 3.58 + 9 146.3 825.0 634.88 4.02 + 10 146.4 825.3 631.91 4.47 + 11 146.5 825.6 628.93 4.92 + 12 146.5 825.9 625.96 5.37 + 13 146.6 826.1 622.99 5.82 + 14 146.6 826.3 620.01 6.27 + 15 146.7 826.5 617.04 6.72 + 16 146.7 826.7 614.06 7.17 + 17 146.7 826.8 611.08 7.62 + 18 146.8 827.0 608.11 8.07 + 19 146.8 827.1 605.13 8.52 + 20 146.8 827.3 602.15 8.97 + 21 146.9 827.4 599.17 9.42 + 22 146.9 827.5 596.19 9.87 + 23 146.9 827.6 593.21 10.32 + 24 146.9 827.7 590.23 10.77 + 25 147.0 827.8 587.25 11.22 + 26 147.0 827.9 584.27 11.67 + 27 147.0 828.0 581.29 12.12 + 28 147.0 828.1 578.31 12.58 + 29 147.0 828.2 575.33 13.03 + 30 122.5 690.2 572.85 13.40 + + + ******************************** + * REVENUE & CASHFLOW PROFILE * + ******************************** +Year Electricity | Heat | Cooling | Carbon | Project +Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow +Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) +________________________________________________________________________________________________________________________________________________________________________________________ + 1 0.00 -119.57 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -119.57 -119.57 + 2 10.50 12.04 15.08 | 7.50 0.00 0.00 | 7.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 12.04 -107.54 + 3 10.62 12.36 30.48 | 7.62 0.00 0.00 | 7.62 0.00 0.00 | 0.00 0.00 0.00 | 3.04 12.36 -95.18 + 4 10.75 12.60 46.12 | 7.75 0.00 0.00 | 7.75 0.00 0.00 | 0.00 0.00 0.00 | 3.04 12.60 -82.58 + 5 10.88 12.82 61.98 | 7.88 0.00 0.00 | 7.88 0.00 0.00 | 0.00 0.00 0.00 | 3.04 12.82 -69.77 + 6 11.02 13.03 78.06 | 8.02 0.00 0.00 | 8.02 0.00 0.00 | 0.00 0.00 0.00 | 3.04 13.03 -56.73 + 7 11.16 13.25 94.36 | 8.16 0.00 0.00 | 8.16 0.00 0.00 | 0.00 0.00 0.00 | 3.04 13.25 -43.48 + 8 11.30 13.47 110.87 | 8.30 0.00 0.00 | 8.30 0.00 0.00 | 0.00 0.00 0.00 | 3.04 13.47 -30.01 + 9 11.44 13.69 127.61 | 8.44 0.00 0.00 | 8.44 0.00 0.00 | 0.00 0.00 0.00 | 3.04 13.69 -16.32 + 10 11.59 13.92 144.57 | 8.59 0.00 0.00 | 8.59 0.00 0.00 | 0.00 0.00 0.00 | 3.04 13.92 -2.40 + 11 11.74 14.15 161.76 | 8.74 0.00 0.00 | 8.74 0.00 0.00 | 0.00 0.00 0.00 | 3.04 14.15 11.75 + 12 5.50 5.01 169.82 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.01 16.76 + 13 5.50 5.02 177.88 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.02 21.78 + 14 5.50 5.02 185.94 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.02 26.80 + 15 5.50 5.02 194.00 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.02 31.82 + 16 5.50 5.02 202.07 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.02 36.84 + 17 5.50 5.02 210.14 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.02 41.86 + 18 5.50 5.03 218.21 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.03 46.89 + 19 5.50 5.03 226.28 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.03 51.92 + 20 5.50 5.03 234.36 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.03 56.95 + 21 5.50 5.03 242.43 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.03 61.98 + 22 5.50 5.03 250.51 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.03 67.02 + 23 5.50 5.03 258.59 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.03 72.05 + 24 5.50 5.04 266.67 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 77.09 + 25 5.50 5.04 274.75 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 82.12 + 26 5.50 5.04 282.83 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 87.16 + 27 5.50 5.04 290.92 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 92.20 + 28 5.50 5.04 299.00 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 97.24 + 29 5.50 5.04 307.09 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 102.29 + 30 5.50 5.04 315.17 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 3.04 5.04 107.33 diff --git a/tests/examples/example_PTC.txt b/tests/examples/example_PTC.txt new file mode 100644 index 00000000..3e7a3b2c --- /dev/null +++ b/tests/examples/example_PTC.txt @@ -0,0 +1,88 @@ +--- GEOPHIRES v3 Input File +--- Created on 2024-04-12 +--- Production Tax Credit (PTC) Example + +***Subsurface technical parameters*** +************************************* +Reservoir Model,1, ---Multiple Fractures reservoir model +Reservoir Depth,5, ---[km] +Number of Segments,1, ---[-] +Gradient 1,55, ---[deg.C/km] +Maximum Temperature,500, ---[deg.C] +Number of Production Wells,2, ---[-] +Number of Injection Wells,2, ---[-] +Production Well Diameter,7, ---[inch] +Injection Well Diameter,7, ---[inch] +Ramey Production Wellbore Model,1, ---0 if disabled 1 if enabled +Production Wellbore Temperature Drop,.5, ---[deg.C] +Injection Wellbore Temperature Gain,0, ---[deg.C] +Production Flow Rate per Well,55, ---[kg/s] +Fracture Shape,3, ---[-] Should be 1 2 3 or 4. See manual for details +Fracture Height,900, ---[m] +Reservoir Volume Option,3, ---[-] Should be 1 2 3 or 4. See manual for details +Number of Fractures,20, ---[-] +Reservoir Volume,1000000000, ---[m^3] +Water Loss Fraction,.02, ---[-] +Productivity Index,5, ---[kg/s/bar] +Injectivity Index,5, ---[kg/s/bar] +Injection Temperature,50, ---[deg.C] +Maximum Drawdown,1, ---[-] no redrilling considered +Reservoir Heat Capacity,1000, ---[J/kg/K] +Reservoir Density,2700, ---[kg/m^3] +Reservoir Thermal Conductivity,2.7, ---[W/m/K] + +***SURFACE TECHNICAL PARAMETERS*** +********************************** +End-Use Option,1, ---[-] Electricity +Power Plant Type,2, ---[-] Supercritical ORC +Circulation Pump Efficiency,.8, ---[-] between .1 and 1 +Utilization Factor,.9, ---[-] between .1 and 1 +Surface Temperature,20, ---[deg.C] +Ambient Temperature,20, ---[deg.C] + +***CAPITAL AND O&M COST PARAMETERS*** +************************************* +Well Drilling and Completion Capital Cost Adjustment Factor,1, ---[-] Use built-in correlations +Well Drilling Cost Correlation,1, ---[-] Use built-in correlations +Reservoir Stimulation Capital Cost Adjustment Factor,1, ---[-] Use built-in correlations +Surface Plant Capital Cost Adjustment Factor,1, ---[-] Use built-in correlations +Field Gathering System Capital Cost Adjustment Factor,1, ---[-] Use built-in correlations +Exploration Capital Cost Adjustment Factor,1, ---[-] Use built-in correlations +Wellfield O&M Cost Adjustment Factor,1, ---[-] Use built-in correlations +Surface Plant O&M Cost Adjustment Factor,1, ---[-] Use built-in correlations +Water Cost Adjustment Factor,1, ---[-] Use built-in correlations + + +*** Economic/Financial Parameters *** +************************************* +Plant Lifetime,30, --- [years] +Economic Model,3, --- Should be 1 (FCR model) 2 (Standard LCOE/LCOH model) or 3 (Bicycle model). +Fraction of Investment in Bonds,0.65, --- [-] Required if Bicycle model is selected. See manual for details. +Inflated Bond Interest Rate,0.07, --- [-] Required if Bicycle model is selected. See manual for details. +Inflated Equity Interest Rate,0.12, --- [-] Required if Bicycle model is selected. See manual for details. +Inflation Rate,0.025, --- [-] Required if Bicycle model is selected. See manual for details. +Combined Income Tax Rate,0.392, --- [-] Required if Bicycle model is selected. See manual for details. +Gross Revenue Tax Rate,0, --- [-] Required if Bicycle model is selected. See manual for details. +Investment Tax Credit Rate,0, --- [-] Required if Bicycle model is selected. See manual for details. +Property Tax Rate,0, --- [-] Required if Bicycle model is selected. See manual for details. +Inflation Rate During Construction,0, --- [-] +Well Drilling and Completion Capital Cost Adjustment Factor,1, --- [-] Use built-in well cost correlation as is +Well Drilling Cost Correlation,1, --- [-] Use built-in well drilling cost correlation #1 +Reservoir Stimulation Capital Cost,0, --- [M$/injection well] Reservoir stimulation capital cost per injection well +Surface Plant Capital Cost Adjustment Factor,1, --- [-] Use built-in surface plant cost correlation as is +Field Gathering System Capital Cost Adjustment Factor,1, --- [-] Use built-in pipeline distribution cost correlation as is +Exploration Capital Cost Adjustment Factor,1, --- [-] Use built-in exploration cost correlation as is +Wellfield O&M Cost Adjustment Factor,1, --- [-] Use built-in wellfield O&M cost correlation as is +Water Cost Adjustment Factor,1, --- [-] Use built-in water cost correlation as is +Surface Plant O&M Cost Adjustment Factor,1, --- [-] Use built-in surface plant O&M cost correlation as is +Production Tax Credit Electricity, 0.05, --- [-] Production tax credit for electricity in $/kWh +Production Tax Credit Heat, 0.05, --- [-] Production tax credit for electricity in $/kWh +Production Tax Credit Cooling, 0.05, --- [-] Production tax credit for electricity in $/kWh +Production Tax Credit Duration, 10, --- [-] Production tax credit for duration in years +Production Tax Credit Inflation Adjusted, True, --- [-] Is the Production tax credit inflation adjusted (T/F) + +***Simulation Parameters*** +*************************** + +Print Output to Console,1, ---[-] Should be 0 (don't print results) or 1 (print results) +Time steps per year,6, ---[1/year] diff --git a/tests/examples/example_SHR-1.out b/tests/examples/example_SHR-1.out index 12d6e4a2..6218480d 100644 --- a/tests/examples/example_SHR-1.out +++ b/tests/examples/example_SHR-1.out @@ -4,11 +4,11 @@ Simulation Metadata ---------------------- - GEOPHIRES Version: 3.4.15 + GEOPHIRES Version: 3.4.22 GEOPHIRES Build Date: 2024-03-05 - Simulation Date: 2024-03-05 - Simulation Time: 10:32 - Calculation Time: 0.614 sec + Simulation Date: 2024-04-10 + Simulation Time: 14:58 + Calculation Time: 1.538 sec ***SUMMARY OF RESULTS*** @@ -64,7 +64,7 @@ Simulation Metadata Reservoir Model = Multiple Parallel Fractures Model Bottom-hole temperature: 395.00 degC Fracture model = Square - Well seperation: fracture height: 900.00 meter + Well separation: fracture height: 900.00 meter Fracture area: 810000.00 m**2 Reservoir volume: 1000000000 m**3 Reservoir hydrostatic pressure: 68311.02 kPa @@ -206,12 +206,12 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 6.00 -241.92 0.00 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -241.92 -241.92 + 1 0.00 -241.92 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -241.92 -241.92 2 6.00 11.70 13.73 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 2.03 11.70 -230.22 - 3 7.20 12.05 27.80 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 2.03 12.05 -218.17 - 4 8.40 15.01 44.84 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 2.03 15.01 -203.16 - 5 9.60 17.95 64.82 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 2.03 17.95 -185.21 - 6 10.00 20.89 87.73 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 2.03 20.89 -164.32 + 3 6.00 12.05 27.80 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 2.03 12.05 -218.17 + 4 7.20 15.01 44.84 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 2.03 15.01 -203.16 + 5 8.40 17.95 64.82 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 2.03 17.95 -185.21 + 6 9.60 20.89 87.73 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 2.03 20.89 -164.32 7 10.00 21.91 111.66 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 2.03 21.91 -142.42 8 10.00 21.96 135.64 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 2.03 21.96 -120.46 9 10.00 22.00 159.67 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 2.03 22.00 -98.46 diff --git a/tests/examples/example_SHR-2.out b/tests/examples/example_SHR-2.out index febc420d..244de670 100644 --- a/tests/examples/example_SHR-2.out +++ b/tests/examples/example_SHR-2.out @@ -4,11 +4,11 @@ Simulation Metadata ---------------------- - GEOPHIRES Version: 3.4.16 + GEOPHIRES Version: 3.4.22 GEOPHIRES Build Date: 2024-03-05 - Simulation Date: 2024-03-06 - Simulation Time: 11:00 - Calculation Time: 0.620 sec + Simulation Date: 2024-04-10 + Simulation Time: 14:59 + Calculation Time: 1.435 sec ***SUMMARY OF RESULTS*** @@ -64,7 +64,7 @@ Simulation Metadata Reservoir Model = Multiple Parallel Fractures Model Bottom-hole temperature: 395.00 degC Fracture model = Square - Well seperation: fracture height: 900.00 meter + Well separation: fracture height: 900.00 meter Fracture area: 810000.00 m**2 Reservoir volume: 1000000000 m**3 Reservoir hydrostatic pressure: 68311.02 kPa @@ -206,12 +206,12 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 6.00 -161.06 0.00 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -161.06 -161.06 + 1 0.00 -161.06 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -161.06 -161.06 2 6.00 12.37 13.73 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.36 12.37 -148.69 - 3 7.20 12.72 27.80 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.36 12.72 -135.97 - 4 8.40 15.68 44.84 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.36 15.68 -120.29 - 5 9.60 18.62 64.82 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.36 18.62 -101.67 - 6 10.00 21.56 87.73 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.36 21.56 -80.11 + 3 6.00 12.72 27.80 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.36 12.72 -135.97 + 4 7.20 15.68 44.84 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.36 15.68 -120.29 + 5 8.40 18.62 64.82 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.36 18.62 -101.67 + 6 9.60 21.56 87.73 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.36 21.56 -80.11 7 10.00 22.58 111.66 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.36 22.58 -57.54 8 10.00 22.63 135.64 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.36 22.63 -34.91 9 10.00 22.67 159.67 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.36 22.67 -12.24 diff --git a/tests/examples/example_multiple_gradients.out b/tests/examples/example_multiple_gradients.out index 7c1060da..0b8ac67c 100644 --- a/tests/examples/example_multiple_gradients.out +++ b/tests/examples/example_multiple_gradients.out @@ -76,7 +76,7 @@ Simulation Metadata Reservoir Model = Multiple Parallel Fractures Model Bottom-hole temperature: 190.00 degC Fracture model = Square - Well seperation: fracture height: 600.00 meter + Well separation: fracture height: 600.00 meter Fracture area: 360000.00 m**2 Reservoir volume: 1000000000 m**3 Reservoir hydrostatic pressure: 39398.56 kPa @@ -221,7 +221,7 @@ Year Electricity | Heat | Since Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | Price Ann. Rev. Cumm. Rev. | OPEX Net Rev. Net Cashflow Start (cents/kWh)(MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(cents/kWh) (MUSD/yr) (MUSD) |(USD/tonne) (MUSD/yr) (MUSD) |(MUSD/yr) (MUSD/yr) (MUSD) ________________________________________________________________________________________________________________________________________________________________________________________ - 1 5.50 -76.26 0.00 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -76.26 -76.26 + 1 0.00 -76.26 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 0.00 0.00 | 0.00 -76.26 -76.26 2 5.50 1.68 3.61 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.93 1.68 -74.58 3 5.50 1.68 7.22 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.93 1.68 -72.90 4 5.50 1.68 10.83 | 2.50 0.00 0.00 | 2.50 0.00 0.00 | 0.00 0.00 0.00 | 1.93 1.68 -71.21 diff --git a/tests/test_geophires_x_client.py b/tests/test_geophires_x_client.py index df891192..c77e5a4f 100644 --- a/tests/test_geophires_x_client.py +++ b/tests/test_geophires_x_client.py @@ -221,17 +221,17 @@ def test_extended_economic_profile(self): 'Annual Project Cash Flow (MUSD/yr)', 'Cumm. Project Cash Flow (MUSD)', ], - [1, 0.09, 0.0023, 0.012, 0.0, 1.14, -70.0, -70.0, -101.06, -101.06], + [1, 0.0, 0.0023, 0.0, 0.0, 1.14, -70.0, -70.0, -101.06, -101.06], [2, 0.09, 0.0023, 0.012, 0.0, 1.14, 1.14, -68.86, 5.68, -95.38], [3, 0.09, 0.0023, 0.012, 0.0, 1.14, 1.14, -67.72, 5.72, -89.65], [4, 0.09, 0.0023, 0.012, 0.0, 1.14, 1.14, -66.59, 5.74, -83.91], [5, 0.09, 0.0023, 0.012, 0.0, 1.14, 1.14, -65.45, 5.75, -78.17], [6, 0.09, 0.0023, 0.012, 0.0, 1.14, 1.14, -64.31, 5.75, -72.42], - [7, 0.102, 0.0026, 0.012, 0.0, 1.14, 1.14, -63.17, 5.76, -66.66], - [8, 0.114, 0.003, 0.012, 0.0, 1.14, 1.14, -62.03, 6.27, -60.39], - [9, 0.126, 0.0033, 0.022, 0.0, 1.14, 1.14, -60.89, 6.78, -53.61], - [10, 0.138, 0.0036, 0.032, 0.0, 1.14, 1.14, -59.75, 7.29, -46.32], - [11, 0.15, 0.0039, 0.036, 0.0, 1.14, 1.14, -58.61, 7.8, -38.52], + [7, 0.09, 0.0026, 0.012, 0.0, 1.14, 1.14, -63.17, 5.76, -66.66], + [8, 0.102, 0.003, 0.012, 0.0, 1.14, 1.14, -62.03, 6.27, -60.39], + [9, 0.114, 0.0033, 0.012, 0.0, 1.14, 1.14, -60.89, 6.78, -53.61], + [10, 0.126, 0.0036, 0.022, 0.0, 1.14, 1.14, -59.75, 7.29, -46.32], + [11, 0.138, 0.0039, 0.032, 0.0, 1.14, 1.14, -58.61, 7.8, -38.52], [12, 0.15, 0.0039, 0.036, 0.0, 1.14, 1.14, -57.47, 8.31, -30.21], [13, 0.15, 0.0039, 0.036, 0.0, 1.14, 1.14, -56.33, 8.32, -21.89], [14, 0.15, 0.0039, 0.036, 0.0, 1.14, 1.14, -55.19, 8.32, -13.57],