Skip to content

Commit 6197f2d

Browse files
Merge pull request #16 from softwareengineerprogrammer/econo_cash_flow-4
Revenue & Cashflow Profile
2 parents d1921a9 + 09390a8 commit 6197f2d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+3136
-1048
lines changed

src/geophires_monte_carlo/MC_GeoPHIRES3.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,12 @@ def work_package(pass_list: list):
130130
HipRaInputParameters(from_file_path=Path(tmp_input_file))
131131
)
132132
shutil.copyfile(result.output_file_path, tmp_output_file)
133+
elif args.Code_File.endswith('HIP_RA_x.py'):
134+
hip_ra_x_client: HipRaXClient = HipRaXClient()
135+
result: HipRaResult = hip_ra_x_client.get_hip_ra_result(
136+
HipRaInputParameters(from_file_path=Path(tmp_input_file))
137+
)
138+
shutil.copyfile(result.output_file_path, tmp_output_file)
133139
else:
134140
log.warning(
135141
f'Code file from args ({args.Code_File}) is not a known program, '
@@ -311,7 +317,7 @@ def main(command_line_args=None):
311317

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

317323
# Now run the executor with the map - that will run it Iterations number of times
@@ -335,6 +341,7 @@ def main(command_line_args=None):
335341
if len(line) > 3:
336342
# FIXME TODO doesn't work for HIP RA results
337343
line, sep, tail = line.partition(', (') # strip off the Input Variable Values
344+
line = line.replace('(', '').replace(')', '') # strip off the ()
338345
results.append([float(y) for y in line.split(',')])
339346
else:
340347
logger.warning(f'-9999.0 or space found in line {result_count!s}')

src/geophires_x/AGSWellBores.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1054,7 +1054,7 @@ def Calculate(self, model: Model) -> None:
10541054
DowngoingPumpingPower, ppp2, dppw, ppwh = ProdPressureDropAndPumpingPowerUsingIndexes(
10551055
model, self.productionwellpumping.value,
10561056
self.usebuiltinppwellheadcorrelation,
1057-
model.reserv.Trock.value, model.reserv.depth.value,
1057+
model.reserv.Trock.value, model.reserv.InputDepth.value,
10581058
self.ppwellhead.value, self.PI.value,
10591059
self.prodwellflowrate.value, f3, vprod,
10601060
self.injwelldiam.value, self.nprod.value, model.surfaceplant.pump_efficiency.value,

src/geophires_x/CylindricalReservoir.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import numpy as np
77
from pint.facets.plain import PlainQuantity
88

9-
from geophires_x.GeoPHIRESUtils import density_water_kg_per_m3, lithostatic_pressure_MPa, quantity
9+
from geophires_x.GeoPHIRESUtils import density_water_kg_per_m3, static_pressure_MPa, quantity
1010

1111
from geophires_x.GeoPHIRESUtils import heat_capacity_water_J_per_kg_per_K
1212
import geophires_x.Model as Model
@@ -266,5 +266,5 @@ def lithostatic_pressure(self) -> PlainQuantity:
266266
267267
Standard reservoir implementation uses depth but CylindricalReservoir sets depth to total drilled length
268268
"""
269-
return quantity(lithostatic_pressure_MPa(self.rhorock.quantity().to('kg/m**3').magnitude,
270-
self.InputDepth.quantity().to('m').magnitude), 'MPa')
269+
return quantity(static_pressure_MPa(self.rhorock.quantity().to('kg/m**3').magnitude,
270+
self.InputDepth.quantity().to('m').magnitude), 'MPa')

src/geophires_x/Economics.py

Lines changed: 436 additions & 157 deletions
Large diffs are not rendered by default.

src/geophires_x/EconomicsAddOns.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,6 @@ def __init__(self, model: Model):
128128
PreferredUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR,
129129
CurrentUnits=CurrencyFrequencyUnit.MDOLLARSPERYEAR
130130
)
131-
self.ProjectPaybackPeriod = self.OutputParameterDict[self.ProjectPaybackPeriod.Name] = OutputParameter(
132-
"Project Payback Period",
133-
UnitType=Units.TIME,
134-
PreferredUnits=TimeUnit.YEAR,
135-
CurrentUnits=TimeUnit.YEAR
136-
)
137131
self.AddOnPaybackPeriod = self.OutputParameterDict[self.AddOnPaybackPeriod.Name] = OutputParameter(
138132
"AddOn Payback Period",
139133
UnitType=Units.TIME,
@@ -348,19 +342,14 @@ def Calculate(self, model: Model) -> None:
348342
self.ProjectIRR.value = 0.0
349343
self.ProjectVIR.value = 1.0 + (self.ProjectNPV.value / self.AdjustedProjectCAPEX.value)
350344

351-
# calculate Cummcashflows and paybacks
345+
# calculate Cummcashflows and payback period
352346
self.ProjectCummCashFlow.value = [0.0] * len(self.ProjectCashFlow.value)
353347
i = 0
354348
for val in self.ProjectCashFlow.value:
355349
if i == 0:
356350
self.ProjectCummCashFlow.value[i] = val
357351
else:
358352
self.ProjectCummCashFlow.value[i] = self.ProjectCummCashFlow.value[i - 1] + val
359-
if self.ProjectCummCashFlow.value[i] > 0 >= self.ProjectCummCashFlow.value[
360-
i - 1]: # we just crossed the threshold into positive project cummcashflow, so we can calculate payback period
361-
dFullDiff = self.ProjectCummCashFlow.value[i] + math.fabs(self.ProjectCummCashFlow.value[(i - 1)])
362-
dPerc = math.fabs(self.ProjectCummCashFlow.value[(i - 1)]) / dFullDiff
363-
self.ProjectPaybackPeriod.value = i + dPerc
364353
i = i + 1
365354
i = 0
366355
self.AddOnCummCashFlow.value = [0.0] * len(self.AddOnCashFlow.value)
@@ -382,7 +371,7 @@ def Calculate(self, model: Model) -> None:
382371
self.AdjustedProjectOPEX.value * model.surfaceplant.plant_lifetime.value))
383372

384373
# recalculate LCOE/LCOH
385-
self.LCOE.value, self.LCOH.value, LCOC = Economics.CalculateLCOELCOH(self, model)
374+
self.LCOE.value, self.LCOH.value, LCOC = Economics.CalculateLCOELCOHLCOC(self, model)
386375

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

src/geophires_x/EconomicsCCUS.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -226,12 +226,6 @@ def __init__(self, model):
226226
PreferredUnits=PercentUnit.TENTH,
227227
CurrentUnits=PercentUnit.TENTH
228228
)
229-
self.ProjectPaybackPeriod = self.OutputParameterDict[self.ProjectPaybackPeriod.Name] = OutputParameter(
230-
"Project Payback Period",
231-
UnitType=Units.TIME,
232-
PreferredUnits=TimeUnit.YEAR,
233-
CurrentUnits=TimeUnit.YEAR
234-
)
235229
self.ProjectMOIC = self.OutputParameterDict[self.ProjectMOIC.Name] = OutputParameter(
236230
"Project Multiple of Invested Capital",
237231
UnitType=Units.PERCENT,
@@ -429,11 +423,6 @@ def Calculate(self, model) -> None:
429423
self.ProjectCummCashFlow.value[0] = val
430424
else:
431425
self.ProjectCummCashFlow.value[i] = self.ProjectCummCashFlow.value[i - 1] + val
432-
if self.ProjectCummCashFlow.value[i] > 0 >= self.ProjectCummCashFlow.value[
433-
i - 1]: # we just crossed the threshold into positive project cummcashflow, so we can calculate payback period
434-
dFullDiff = self.ProjectCummCashFlow.value[i] + math.fabs(self.ProjectCummCashFlow.value[(i - 1)])
435-
dPerc = math.fabs(self.ProjectCummCashFlow.value[(i - 1)]) / dFullDiff
436-
self.ProjectPaybackPeriod.value = i + dPerc
437426
i = i + 1
438427

439428
# Calculate more financial values using numpy financials

src/geophires_x/EconomicsS_DAC_GT.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ def __init__(self, model: Model):
4343
"""
4444
model.logger.info("Init " + str(__class__) + ": " + sys._getframe().f_code.co_name)
4545

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

596-
self.CRF = self.calculate_CRF(self.wacc.value,
597-
model.surfaceplant.plant_lifetime.value) # Calculate initial CRF value based on default inputs
598-
CAPEX = self.CAPEX.value * self.CRF # don't change a parameters value directly - it throw off the rehydration
596+
# Calculate initial CRF value based on default inputs
597+
self.CRF = self.calculate_CRF(self.wacc.value, model.surfaceplant.plant_lifetime.value)
598+
599+
# don't change a parameters value directly - it throw off the rehydration
600+
CAPEX = self.CAPEX.value * self.CRF
599601
CAPEX = CAPEX * self.CAPEX_mult.value
600602
self.OPEX.value = self.OPEX.value * self.OPEX_mult.value
601603
self.therm.value = self.therm.value * self.therm_index.value
602604
power_totalcost = self.elec.value * model.surfaceplant.electricity_cost_to_buy.value
603605
elec_heat_totalcost = self.therm.value * model.surfaceplant.electricity_cost_to_buy.value
604-
# Convert from $/McF to $/kWh_th, but don't change a parameters value directly - it will throw off the rehydration
606+
607+
# Convert from $/McF to $/kWh_th, but don't change any parameters value directly - it will throw off the rehydration
605608
NG_price = self.NG_price.value / self.NG_EnergyDensity.value
606609
NG_totalcost = self.therm.value * NG_price
607610
self.LCOH.value, self.kWh_e_per_kWh_th.value = self.geo_therm_cost(model.surfaceplant.electricity_cost_to_buy.value,
@@ -659,7 +662,8 @@ def Calculate(self, model: Model) -> None:
659662
# some (all) of it to do the capture, so when they get used in the final economic calculation (below),
660663
# the new values reflect the impact of S-DAC-GT
661664
for i in range(0, model.surfaceplant.plant_lifetime.value):
662-
if model.surfaceplant.enduse_option.value != EndUseOptions.HEAT: # all these end-use options have an electricity generation component
665+
if model.surfaceplant.enduse_option.value != EndUseOptions.HEAT:
666+
# all these end-use options have an electricity generation component
663667
model.surfaceplant.TotalkWhProduced.value[i] = model.surfaceplant.TotalkWhProduced.value[i] - (
664668
self.CarbonExtractedAnnually.value[i] * self.elec.value)
665669
model.surfaceplant.NetkWhProduced.value[i] = model.surfaceplant.NetkWhProduced.value[i] - (
@@ -668,8 +672,18 @@ def Calculate(self, model: Model) -> None:
668672
model.surfaceplant.HeatkWhProduced.value[i] = model.surfaceplant.HeatkWhProduced.value[i] - (
669673
self.CarbonExtractedAnnually.value[i] * self.therm.value)
670674
else:
671-
model.surfaceplant.HeatkWhProduced.value[i] = model.surfaceplant.HeatkWhProduced.value[i] - (
672-
self.CarbonExtractedAnnually.value[
673-
i] * self.therm.value) # all the end-use option of direct-use only component
674-
675-
model.logger.info("complete " + str(__class__) + ": " + sys._getframe().f_code.co_name)
675+
# all the end-use option of direct-use only component
676+
model.surfaceplant.HeatkWhProduced.value[i] = (model.surfaceplant.HeatkWhProduced.value[i] -
677+
(self.CarbonExtractedAnnually.value[i] * self.therm.value))
678+
679+
# Build a revenue generation model for the carbon capture, assuming the capture is being sequestered and that
680+
# there is some sort of credit involved for doing that sequestering
681+
# note that there may already be values in the CarbonRevenue array, so we need to
682+
# 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
683+
#total_duration = model.surfaceplant.plant_lifetime.value
684+
#for i in range(0, total_duration, 1):
685+
# model.sdacgteconomics.CarbonRevenue.value[i] = (model.sdacgteconomics.CarbonRevenue.value[i] +
686+
# (self.CarbonExtractedAnnually.value[i] * model.economics.CarbonPrice.value[i]))
687+
# if i > 0:
688+
# model.economics.CarbonCummCashFlow.value[i] = model.economics.CarbonCummCashFlow.value[i - 1] + model.economics.CarbonRevenue.value[i]
689+
model.logger.info("Complete " + str(__class__) + ": " + sys._getframe().f_code.co_name)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
Reservoir Model,1, ---Multiple, Fractures, reservoir, model
2+
Reservoir Depth,3.7, ---[km]
3+
Number of Segments,3, ---[-]
4+
Gradient 1,42.69972, ---[deg.C/km]
5+
Gradient 2,51.66667, ---[deg.C/km]
6+
Thickness 1,0.793, ---[km]
7+
Gradient 3,46.9697, ---[deg.C/km]
8+
Thickness 2,1.646, ---[km]
9+
Maximum Temperature,400, ---[deg.C]
10+
Number of Production Wells,2, ---[-]
11+
Number of Injection Wells,2, ---[-]
12+
Production Well Diameter,7, ---[inch]
13+
Injection Well Diameter,7, ---[inch]
14+
Ramey Production Wellbore Model,1, ---
15+
Production Wellbore Temperature Drop,.5, ---[deg.C]
16+
Injection Wellbore Temperature Gain,0, ---[deg.C]
17+
Production Flow Rate per Well,90, ---[kg/s]
18+
Fracture Shape,3, ---[-]
19+
Fracture Height,900, ---[m]
20+
Reservoir Volume Option,3, ---[-]
21+
Reservoir Volume,1000000000000, ---[m^3]
22+
Number of Fractures,20, ---[-]
23+
Water Loss Fraction,.02, ---[-]
24+
Productivity Index,5, ---[kg/s/bar]
25+
Injectivity Index,5, ---[kg/s/bar]
26+
Injection Temperature,40, ---[deg.C]
27+
Maximum Drawdown,0.3, ---[-] no redrilling considered
28+
Reservoir Heat Capacity,975, ---[J/kg/K]
29+
Reservoir Density,2600, ---[kg/m^3]
30+
Reservoir Thermal Conductivity,3, ---[W/m/K]
31+
32+
***SURFACE TECHNICAL PARAMETERS***
33+
**********************************
34+
End-Use Option,1, ---[-] Electricity
35+
Economic Model,1, ---[-] Fixed Charge Rate Model
36+
Power Plant Type,2, ---[-] Supercritcal ORC
37+
Circulation Pump Efficiency,.8, ---[-] between .1 and 1
38+
Utilization Factor,.9, ---[-] between .1 and 1
39+
Surface Temperature,20, ---[deg.C]
40+
Ambient Temperature,20, ---[deg.C]
41+
42+
***FINANCIAL PARAMETERS***
43+
**************************
44+
Plant Lifetime,30, ---[years]
45+
Fixed Charge Rate,.05, ---[-] between 0 and 1
46+
47+
Inflation Rate During Construction,0, ---[-]
48+
49+
Starting Electricity Sale Price, 0.10
50+
51+
Ending Electricity Sale Price, 0.15
52+
53+
Electricity Escalation Start Year, 5
54+
55+
Electricity Escalation Rate Per Year, 0.01
56+
57+
***Simulation Parameters***
58+
***************************
59+
60+
Print Output to Console,1, ---[-] Should be 0 (don't print results) or 1 (print results)
61+
Time steps per year,6, ---[1/year]
62+
63+
***Output unit conversions you wish to make***
64+
***************************
65+
Units:Bottom-hole temperature, degF, ---[This is what I want the units to be for this output parameter
66+
Units:Exploration cost,MEUR, ---[This is what I want the units to be for this output parameter
67+
Units:O&M Make-up Water costs, MEUR/yr

src/geophires_x/GEOPHIRESv3.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@ def main(enable_geophires_logging_config=True):
5353
json_addons = jsons.dumps(model.addeconomics.OutputParameterDict, indent=4, sort_keys=True,
5454
supress_warnings=True)
5555
json_merged = {**json_merged, **json.loads(json_addons)}
56-
if model.economics.DoCCUSCalculations.value:
57-
json_ccus = jsons.dumps(model.ccuseconomics.OutputParameterDict, indent=4, sort_keys=True,
58-
supress_warnings=True)
59-
json_merged = {**json_merged, **json.loads(json_ccus)}
6056
if model.economics.DoSDACGTCalculations.value:
6157
json_sdacgt = jsons.dumps(model.sdacgteconomics.OutputParameterDict, indent=4, sort_keys=True,
6258
supress_warnings=True)

0 commit comments

Comments
 (0)