Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revenue & Cashflow Profile #16

Merged
merged 32 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
71b45f2
Fixed typo in Economics.py for Parallel CHP production LCOH calculation.
malcolm-dsider Feb 14, 2024
7897f47
Update HIP-RA-X functions to include pressure in all calculations.
malcolm-dsider Feb 20, 2024
2ed5773
Update HIP-RA-X functions to include pressure in all calculations.
malcolm-dsider Feb 20, 2024
cb1adf8
Update HIP-RA-X functions to include pressure in all calculations. Up…
malcolm-dsider Feb 21, 2024
49ff3a1
WIP 2024-03-01
malcolm-dsider Mar 1, 2024
7882e59
Updates all example outputs to contain new output, like cashflow tabl…
malcolm-dsider Mar 3, 2024
c7e8994
Updates to allow testing framework to work. Also contains Rich libray…
malcolm-dsider Mar 3, 2024
e91a3c0
updated test for higher temperature limit for UtilEff. Was 373.xxx, n…
malcolm-dsider Mar 3, 2024
c0c98ee
updates that allow testing famework to work with sys.argv containing …
malcolm-dsider Mar 3, 2024
af3a6f8
fixed python 3.8 syntax error
malcolm-dsider Mar 3, 2024
468998f
Update example11_AC IRR output format
softwareengineerprogrammer Mar 4, 2024
fc03c4d
Undo backwards-incompatible '(LCOE)' suffix to 'Electricity breakeven…
softwareengineerprogrammer Mar 4, 2024
c2d00ce
Remove obsolete FIXME in MC
softwareengineerprogrammer Mar 4, 2024
ec6edb1
Revert erroneous rollback of output file arg centralization
softwareengineerprogrammer Mar 4, 2024
57ace7d
WIP - extract revenue & cashflow profile
softwareengineerprogrammer Mar 4, 2024
f771923
FIXME re: transforming CCUS profile from revenue & cashflow
softwareengineerprogrammer Mar 4, 2024
e5d4bd7
REVENUE & CASHFLOW PROFILE extraction/integration
softwareengineerprogrammer Mar 4, 2024
11c70a7
Update examples with revenue & cashflow profiles
softwareengineerprogrammer Mar 4, 2024
43110be
Revert probably-unnecessary addition of blank lines to MC output file…
softwareengineerprogrammer Mar 4, 2024
5e37490
Move Border_EGS_150C_Electricity_Input.txt to Examples
softwareengineerprogrammer Mar 4, 2024
8a95526
Correct utils static pressure methoddoc
softwareengineerprogrammer Mar 4, 2024
17d3b08
Economics - remove redundant value declarations on new fields
softwareengineerprogrammer Mar 4, 2024
a142470
Delete stray HIP.html
softwareengineerprogrammer Mar 4, 2024
3073642
Tweak utils docs
softwareengineerprogrammer Mar 4, 2024
2d5af8f
Document commented WIP implementation for https://github.com/NREL/GEO…
softwareengineerprogrammer Mar 4, 2024
8a9a89c
Align LCOE output spaces
softwareengineerprogrammer Mar 4, 2024
4d98df7
Account for LCOH-suffixed direct-use heat property name change
softwareengineerprogrammer Mar 4, 2024
490d3fe
Re-add erroneously removed type in method doc
softwareengineerprogrammer Mar 4, 2024
469b298
Render projects with no payback period as N/A instead of 0.00 yr
softwareengineerprogrammer Mar 4, 2024
2d635a6
Add payback period & chp cost allocation fields to client result
softwareengineerprogrammer Mar 4, 2024
3acd94b
Update schema-generated geophires-request.json
softwareengineerprogrammer Mar 4, 2024
09390a8
Mark backwards-compatible CCUS profile transform as FIXME TODO instea…
softwareengineerprogrammer Mar 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/geophires_monte_carlo/MC_GeoPHIRES3.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ def work_package(pass_list: list):
HipRaInputParameters(from_file_path=Path(tmp_input_file))
)
shutil.copyfile(result.output_file_path, tmp_output_file)
elif args.Code_File.endswith('HIP_RA_x.py'):
hip_ra_x_client: HipRaXClient = HipRaXClient()
result: HipRaResult = hip_ra_x_client.get_hip_ra_result(
HipRaInputParameters(from_file_path=Path(tmp_input_file))
)
shutil.copyfile(result.output_file_path, tmp_output_file)
else:
log.warning(
f'Code file from args ({args.Code_File}) is not a known program, '
Expand Down Expand Up @@ -311,7 +317,7 @@ def main(command_line_args=None):

args = []
for _ in range(iterations):
args.append(pass_list) # we need to make Iterations number of copies of this list fr the map
args.append(pass_list) # we need to make Iterations number of copies of this list for the map
args = tuple(args) # convert to a tuple

# Now run the executor with the map - that will run it Iterations number of times
Expand All @@ -335,6 +341,7 @@ def main(command_line_args=None):
if len(line) > 3:
# FIXME TODO doesn't work for HIP RA results
line, sep, tail = line.partition(', (') # strip off the Input Variable Values
line = line.replace('(', '').replace(')', '') # strip off the ()
results.append([float(y) for y in line.split(',')])
else:
logger.warning(f'-9999.0 or space found in line {result_count!s}')
Expand Down
2 changes: 1 addition & 1 deletion src/geophires_x/AGSWellBores.py
Original file line number Diff line number Diff line change
Expand Up @@ -1054,7 +1054,7 @@ def Calculate(self, model: Model) -> None:
DowngoingPumpingPower, ppp2, dppw, ppwh = ProdPressureDropAndPumpingPowerUsingIndexes(
model, self.productionwellpumping.value,
self.usebuiltinppwellheadcorrelation,
model.reserv.Trock.value, model.reserv.depth.value,
model.reserv.Trock.value, model.reserv.InputDepth.value,
self.ppwellhead.value, self.PI.value,
self.prodwellflowrate.value, f3, vprod,
self.injwelldiam.value, self.nprod.value, model.surfaceplant.pump_efficiency.value,
Expand Down
6 changes: 3 additions & 3 deletions src/geophires_x/CylindricalReservoir.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import numpy as np
from pint.facets.plain import PlainQuantity

from geophires_x.GeoPHIRESUtils import density_water_kg_per_m3, lithostatic_pressure_MPa, quantity
from geophires_x.GeoPHIRESUtils import density_water_kg_per_m3, static_pressure_MPa, quantity

from geophires_x.GeoPHIRESUtils import heat_capacity_water_J_per_kg_per_K
import geophires_x.Model as Model
Expand Down Expand Up @@ -266,5 +266,5 @@ def lithostatic_pressure(self) -> PlainQuantity:

Standard reservoir implementation uses depth but CylindricalReservoir sets depth to total drilled length
"""
return quantity(lithostatic_pressure_MPa(self.rhorock.quantity().to('kg/m**3').magnitude,
self.InputDepth.quantity().to('m').magnitude), 'MPa')
return quantity(static_pressure_MPa(self.rhorock.quantity().to('kg/m**3').magnitude,
self.InputDepth.quantity().to('m').magnitude), 'MPa')
593 changes: 436 additions & 157 deletions src/geophires_x/Economics.py

Large diffs are not rendered by default.

15 changes: 2 additions & 13 deletions src/geophires_x/EconomicsAddOns.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,6 @@ def __init__(self, model: Model):
PreferredUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR,
CurrentUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR
)
self.ProjectPaybackPeriod = self.OutputParameterDict[self.ProjectPaybackPeriod.Name] = OutputParameter(
"Project Payback Period",
UnitType=Units.TIME,
PreferredUnits=TimeUnit.YEAR,
CurrentUnits=TimeUnit.YEAR
)
self.AddOnPaybackPeriod = self.OutputParameterDict[self.AddOnPaybackPeriod.Name] = OutputParameter(
"AddOn Payback Period",
UnitType=Units.TIME,
Expand Down Expand Up @@ -348,19 +342,14 @@ def Calculate(self, model: Model) -> None:
self.ProjectIRR.value = 0.0
self.ProjectVIR.value = 1.0 + (self.ProjectNPV.value / self.AdjustedProjectCAPEX.value)

# calculate Cummcashflows and paybacks
# calculate Cummcashflows and payback period
self.ProjectCummCashFlow.value = [0.0] * len(self.ProjectCashFlow.value)
i = 0
for val in self.ProjectCashFlow.value:
if i == 0:
self.ProjectCummCashFlow.value[i] = val
else:
self.ProjectCummCashFlow.value[i] = self.ProjectCummCashFlow.value[i - 1] + val
if self.ProjectCummCashFlow.value[i] > 0 >= self.ProjectCummCashFlow.value[
i - 1]: # we just crossed the threshold into positive project cummcashflow, so we can calculate payback period
dFullDiff = self.ProjectCummCashFlow.value[i] + math.fabs(self.ProjectCummCashFlow.value[(i - 1)])
dPerc = math.fabs(self.ProjectCummCashFlow.value[(i - 1)]) / dFullDiff
self.ProjectPaybackPeriod.value = i + dPerc
i = i + 1
i = 0
self.AddOnCummCashFlow.value = [0.0] * len(self.AddOnCashFlow.value)
Expand All @@ -382,7 +371,7 @@ def Calculate(self, model: Model) -> None:
self.AdjustedProjectOPEX.value * model.surfaceplant.plant_lifetime.value))

# recalculate LCOE/LCOH
self.LCOE.value, self.LCOH.value, LCOC = Economics.CalculateLCOELCOH(self, model)
self.LCOE.value, self.LCOH.value, LCOC = Economics.CalculateLCOELCOHLCOC(self, model)

model.logger.info(f'complete {str(__class__)}: {sys._getframe().f_code.co_name}')

Expand Down
11 changes: 0 additions & 11 deletions src/geophires_x/EconomicsCCUS.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,6 @@ def __init__(self, model):
PreferredUnits=PercentUnit.TENTH,
CurrentUnits=PercentUnit.TENTH
)
self.ProjectPaybackPeriod = self.OutputParameterDict[self.ProjectPaybackPeriod.Name] = OutputParameter(
"Project Payback Period",
UnitType=Units.TIME,
PreferredUnits=TimeUnit.YEAR,
CurrentUnits=TimeUnit.YEAR
)
self.ProjectMOIC = self.OutputParameterDict[self.ProjectMOIC.Name] = OutputParameter(
"Project Multiple of Invested Capital",
UnitType=Units.PERCENT,
Expand Down Expand Up @@ -429,11 +423,6 @@ def Calculate(self, model) -> None:
self.ProjectCummCashFlow.value[0] = val
else:
self.ProjectCummCashFlow.value[i] = self.ProjectCummCashFlow.value[i - 1] + val
if self.ProjectCummCashFlow.value[i] > 0 >= self.ProjectCummCashFlow.value[
i - 1]: # we just crossed the threshold into positive project cummcashflow, so we can calculate payback period
dFullDiff = self.ProjectCummCashFlow.value[i] + math.fabs(self.ProjectCummCashFlow.value[(i - 1)])
dPerc = math.fabs(self.ProjectCummCashFlow.value[(i - 1)]) / dFullDiff
self.ProjectPaybackPeriod.value = i + dPerc
i = i + 1

# Calculate more financial values using numpy financials
Expand Down
38 changes: 26 additions & 12 deletions src/geophires_x/EconomicsS_DAC_GT.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ def __init__(self, model: Model):
"""
model.logger.info("Init " + str(__class__) + ": " + sys._getframe().f_code.co_name)

# These disctionaries contains a list of all the parameters set in this object, stored as "Parameter" and
# OutputParameter Objects. This will alow us later to access them in a user interface and get that list,
# These dictionaries contains a list of all the parameters set in this object, stored as "Parameter" and
# OutputParameter Objects. This will allow us later to access them in a user interface and get that list,
# along with unit type, preferred units, etc.
self.ParameterDict = {}
self.OutputParameterDict = {}
Expand Down Expand Up @@ -593,15 +593,18 @@ def Calculate(self, model: Model) -> None:
print(err_message + " Exiting....")
sys.exit()

self.CRF = self.calculate_CRF(self.wacc.value,
model.surfaceplant.plant_lifetime.value) # Calculate initial CRF value based on default inputs
CAPEX = self.CAPEX.value * self.CRF # don't change a parameters value directly - it throw off the rehydration
# Calculate initial CRF value based on default inputs
self.CRF = self.calculate_CRF(self.wacc.value, model.surfaceplant.plant_lifetime.value)

# don't change a parameters value directly - it throw off the rehydration
CAPEX = self.CAPEX.value * self.CRF
CAPEX = CAPEX * self.CAPEX_mult.value
self.OPEX.value = self.OPEX.value * self.OPEX_mult.value
self.therm.value = self.therm.value * self.therm_index.value
power_totalcost = self.elec.value * model.surfaceplant.electricity_cost_to_buy.value
elec_heat_totalcost = self.therm.value * model.surfaceplant.electricity_cost_to_buy.value
# Convert from $/McF to $/kWh_th, but don't change a parameters value directly - it will throw off the rehydration

# Convert from $/McF to $/kWh_th, but don't change any parameters value directly - it will throw off the rehydration
NG_price = self.NG_price.value / self.NG_EnergyDensity.value
NG_totalcost = self.therm.value * NG_price
self.LCOH.value, self.kWh_e_per_kWh_th.value = self.geo_therm_cost(model.surfaceplant.electricity_cost_to_buy.value,
Expand Down Expand Up @@ -659,7 +662,8 @@ def Calculate(self, model: Model) -> None:
# some (all) of it to do the capture, so when they get used in the final economic calculation (below),
# the new values reflect the impact of S-DAC-GT
for i in range(0, model.surfaceplant.plant_lifetime.value):
if model.surfaceplant.enduse_option.value != EndUseOptions.HEAT: # all these end-use options have an electricity generation component
if model.surfaceplant.enduse_option.value != EndUseOptions.HEAT:
# all these end-use options have an electricity generation component
model.surfaceplant.TotalkWhProduced.value[i] = model.surfaceplant.TotalkWhProduced.value[i] - (
self.CarbonExtractedAnnually.value[i] * self.elec.value)
model.surfaceplant.NetkWhProduced.value[i] = model.surfaceplant.NetkWhProduced.value[i] - (
Expand All @@ -668,8 +672,18 @@ def Calculate(self, model: Model) -> None:
model.surfaceplant.HeatkWhProduced.value[i] = model.surfaceplant.HeatkWhProduced.value[i] - (
self.CarbonExtractedAnnually.value[i] * self.therm.value)
else:
model.surfaceplant.HeatkWhProduced.value[i] = model.surfaceplant.HeatkWhProduced.value[i] - (
self.CarbonExtractedAnnually.value[
i] * self.therm.value) # all the end-use option of direct-use only component

model.logger.info("complete " + str(__class__) + ": " + sys._getframe().f_code.co_name)
# all the end-use option of direct-use only component
model.surfaceplant.HeatkWhProduced.value[i] = (model.surfaceplant.HeatkWhProduced.value[i] -
(self.CarbonExtractedAnnually.value[i] * self.therm.value))

# Build a revenue generation model for the carbon capture, assuming the capture is being sequestered and that
# there is some sort of credit involved for doing that sequestering
# note that there may already be values in the CarbonRevenue array, so we need to
# add to them, not just set them. If there isn't values, there, the array will be filed with zeros, so adding won't be a problem
#total_duration = model.surfaceplant.plant_lifetime.value
#for i in range(0, total_duration, 1):
# model.sdacgteconomics.CarbonRevenue.value[i] = (model.sdacgteconomics.CarbonRevenue.value[i] +
# (self.CarbonExtractedAnnually.value[i] * model.economics.CarbonPrice.value[i]))
# if i > 0:
# model.economics.CarbonCummCashFlow.value[i] = model.economics.CarbonCummCashFlow.value[i - 1] + model.economics.CarbonRevenue.value[i]
model.logger.info("Complete " + str(__class__) + ": " + sys._getframe().f_code.co_name)
67 changes: 67 additions & 0 deletions src/geophires_x/Examples/Border_EGS_150C_Electricity_Input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
Reservoir Model,1, ---Multiple, Fractures, reservoir, model
Reservoir Depth,3.7, ---[km]
Number of Segments,3, ---[-]
Gradient 1,42.69972, ---[deg.C/km]
Gradient 2,51.66667, ---[deg.C/km]
Thickness 1,0.793, ---[km]
Gradient 3,46.9697, ---[deg.C/km]
Thickness 2,1.646, ---[km]
Maximum Temperature,400, ---[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, ---
Production Wellbore Temperature Drop,.5, ---[deg.C]
Injection Wellbore Temperature Gain,0, ---[deg.C]
Production Flow Rate per Well,90, ---[kg/s]
Fracture Shape,3, ---[-]
Fracture Height,900, ---[m]
Reservoir Volume Option,3, ---[-]
Reservoir Volume,1000000000000, ---[m^3]
Number of Fractures,20, ---[-]
Water Loss Fraction,.02, ---[-]
Productivity Index,5, ---[kg/s/bar]
Injectivity Index,5, ---[kg/s/bar]
Injection Temperature,40, ---[deg.C]
Maximum Drawdown,0.3, ---[-] no redrilling considered
Reservoir Heat Capacity,975, ---[J/kg/K]
Reservoir Density,2600, ---[kg/m^3]
Reservoir Thermal Conductivity,3, ---[W/m/K]

***SURFACE TECHNICAL PARAMETERS***
**********************************
End-Use Option,1, ---[-] Electricity
Economic Model,1, ---[-] Fixed Charge Rate Model
Power Plant Type,2, ---[-] Supercritcal 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]

***FINANCIAL PARAMETERS***
**************************
Plant Lifetime,30, ---[years]
Fixed Charge Rate,.05, ---[-] between 0 and 1

Inflation Rate During Construction,0, ---[-]

Starting Electricity Sale Price, 0.10

Ending Electricity Sale Price, 0.15

Electricity Escalation Start Year, 5

Electricity Escalation Rate Per Year, 0.01

***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]

***Output unit conversions you wish to make***
***************************
Units:Bottom-hole temperature, degF, ---[This is what I want the units to be for this output parameter
Units:Exploration cost,MEUR, ---[This is what I want the units to be for this output parameter
Units:O&M Make-up Water costs, MEUR/yr
4 changes: 0 additions & 4 deletions src/geophires_x/GEOPHIRESv3.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ def main(enable_geophires_logging_config=True):
json_addons = jsons.dumps(model.addeconomics.OutputParameterDict, indent=4, sort_keys=True,
supress_warnings=True)
json_merged = {**json_merged, **json.loads(json_addons)}
if model.economics.DoCCUSCalculations.value:
json_ccus = jsons.dumps(model.ccuseconomics.OutputParameterDict, indent=4, sort_keys=True,
supress_warnings=True)
json_merged = {**json_merged, **json.loads(json_ccus)}
if model.economics.DoSDACGTCalculations.value:
json_sdacgt = jsons.dumps(model.sdacgteconomics.OutputParameterDict, indent=4, sort_keys=True,
supress_warnings=True)
Expand Down
Loading
Loading