@@ -219,6 +219,19 @@ def __init__(self, model: Model):
219219 ErrMessage = "assume default Percent Energy Devoted To Process (50%)" ,
220220 ToolTipText = "Percent Energy Devoted To Process (%)"
221221 )
222+ self .carbon_credit_price = floatParameter (
223+ "S-DAC-GT Carbon Credit Price" ,
224+ value = 180.0 ,
225+ DefaultValue = 180.0 ,
226+ Min = 0.0 ,
227+ Max = 1000.0 ,
228+ UnitType = Units .COSTPERMASS ,
229+ PreferredUnits = CostPerMassUnit .DOLLARSPERTONNE ,
230+ CurrentUnits = CostPerMassUnit .DOLLARSPERTONNE ,
231+ ErrMessage = "assume default Carbon Credit Price (180 USD per tonne CO2)" ,
232+ ToolTipText = "Carbon Credit or Market Price (USD per tonne CO2)"
233+ )
234+ self .ParameterDict [self .carbon_credit_price .Name ] = self .carbon_credit_price
222235
223236 # local variable initiation
224237 # Capital Recovery Rate or Fixed Charge Factor - set initially for definitions
@@ -335,6 +348,21 @@ def __init__(self, model: Model):
335348 PreferredUnits = CostPerMassUnit .DOLLARSPERTONNE ,
336349 CurrentUnits = CostPerMassUnit .DOLLARSPERTONNE
337350 )
351+ self .CarbonRevenue = OutputParameter (
352+ Name = "Annual Carbon Revenue" ,
353+ UnitType = Units .CURRENCYFREQUENCY ,
354+ PreferredUnits = CurrencyFrequencyUnit .DOLLARSPERYEAR ,
355+ CurrentUnits = CurrencyFrequencyUnit .DOLLARSPERYEAR
356+ )
357+ self .OutputParameterDict [self .CarbonRevenue .Name ] = self .CarbonRevenue
358+
359+ self .CarbonCummCashFlow = OutputParameter (
360+ Name = "Cumulative Carbon Revenue" ,
361+ UnitType = Units .CURRENCY ,
362+ PreferredUnits = CurrencyUnit .DOLLARS ,
363+ CurrentUnits = CurrencyUnit .DOLLARS
364+ )
365+ self .OutputParameterDict [self .CarbonCummCashFlow .Name ] = self .CarbonCummCashFlow
338366
339367 model .logger .info (f"Complete { str (__class__ )} : { sys ._getframe ().f_code .co_name } " )
340368
@@ -599,12 +627,13 @@ def Calculate(self, model: Model) -> None:
599627 # Convert from $/McF to $/kWh_th, but don't change any parameters value directly - it will throw off the rehydration
600628 NG_price = self .NG_price .value / self .NG_EnergyDensity .value
601629 NG_totalcost = self .therm .value * NG_price
602- self .LCOH .value , self .kWh_e_per_kWh_th .value = self .geo_therm_cost (model .surfaceplant .electricity_cost_to_buy .value ,
603- self .CAPEX_mult .value , self .OPEX_mult .value ,
604- model .reserv .depth .value * 3280.84 ,
605- np .average (model .wellbores .ProducedTemperature .value ),
606- model .wellbores .Tinj .value ,
607- model .wellbores .nprod .value * model .wellbores .prodwellflowrate .value )
630+ self .LCOH .value , self .kWh_e_per_kWh_th .value = self .geo_therm_cost (
631+ model .surfaceplant .electricity_cost_to_buy .value ,
632+ self .CAPEX_mult .value , self .OPEX_mult .value ,
633+ model .reserv .depth .value * 3280.84 ,
634+ np .average (model .wellbores .ProducedTemperature .value ),
635+ model .wellbores .Tinj .value ,
636+ model .wellbores .nprod .value * model .wellbores .prodwellflowrate .value )
608637 geothermal_totalcost = self .LCOH .value * self .therm .value
609638 co2_power = self .elec .value / 1000 * self .power_co2intensity .value
610639 co2_elec_heat = self .therm .value / 1000 * self .power_co2intensity .value
@@ -621,7 +650,8 @@ def Calculate(self, model: Model) -> None:
621650
622651 # calculate the net impact of S-DAC-GT on the annual production of the model
623652 avg_first_law_eff = np .average (model .surfaceplant .FirstLawEfficiency .value )
624- self .tot_heat_energy_consumed_per_tonne .value = (self .elec .value / avg_first_law_eff ) + self .therm .value # kWh_th/tonne
653+ self .tot_heat_energy_consumed_per_tonne .value = (
654+ self .elec .value / avg_first_law_eff ) + self .therm .value # kWh_th/tonne
625655 self .tot_cost_per_tonne .value = CAPEX + self .OPEX .value + self .storage .value + self .transport .value # USD/tonne
626656 self .percent_thermal_energy_going_to_heat .value = self .therm .value / self .tot_heat_energy_consumed_per_tonne .value
627657
@@ -637,18 +667,22 @@ def Calculate(self, model: Model) -> None:
637667 # That then gives us the revenue, since we have a carbon price model
638668 # We can also get annual cash flow from it.
639669 for i in range (0 , model .surfaceplant .plant_lifetime .value , 1 ):
640- self .CarbonExtractedAnnually .value [i ] = (self .EnergySplit .value * model .surfaceplant .HeatkWhExtracted .value [i ]) / self .tot_heat_energy_consumed_per_tonne .value
670+ self .CarbonExtractedAnnually .value [i ] = (self .EnergySplit .value * model .surfaceplant .HeatkWhExtracted .value [
671+ i ]) / self .tot_heat_energy_consumed_per_tonne .value
641672 if i == 0 :
642673 self .S_DAC_GTCummCarbonExtracted .value [i ] = self .CarbonExtractedAnnually .value [i ]
643674 else :
644- self .S_DAC_GTCummCarbonExtracted .value [i ] = self .S_DAC_GTCummCarbonExtracted .value [i - 1 ] + self .CarbonExtractedAnnually .value [i ]
675+ self .S_DAC_GTCummCarbonExtracted .value [i ] = self .S_DAC_GTCummCarbonExtracted .value [i - 1 ] + \
676+ self .CarbonExtractedAnnually .value [i ]
645677 self .CarbonExtractedTotal .value = self .CarbonExtractedTotal .value + self .CarbonExtractedAnnually .value [i ]
646678 self .S_DAC_GTAnnualCost .value [i ] = self .CarbonExtractedAnnually .value [i ] * self .tot_cost_per_tonne .value
647679 if i == 0 :
648680 self .S_DAC_GTCummCashFlow .value [i ] = self .S_DAC_GTAnnualCost .value [i ]
649681 else :
650- self .S_DAC_GTCummCashFlow .value [i ] = self .S_DAC_GTCummCashFlow .value [i - 1 ] + self .S_DAC_GTAnnualCost .value [i ]
651- self .CummCostPerTonne .value [i ] = self .S_DAC_GTCummCashFlow .value [i ] / self .S_DAC_GTCummCarbonExtracted .value [i ]
682+ self .S_DAC_GTCummCashFlow .value [i ] = self .S_DAC_GTCummCashFlow .value [i - 1 ] + \
683+ self .S_DAC_GTAnnualCost .value [i ]
684+ self .CummCostPerTonne .value [i ] = self .S_DAC_GTCummCashFlow .value [i ] / \
685+ self .S_DAC_GTCummCarbonExtracted .value [i ]
652686
653687 # We need to update the heat and electricity generated because we have consumed
654688 # some (all) of it to do the capture, so when they get used in the final economic calculation (below),
@@ -657,28 +691,28 @@ def Calculate(self, model: Model) -> None:
657691 if model .surfaceplant .enduse_option .value is not EndUseOptions .HEAT :
658692 # all these end-use options have an electricity generation component
659693 model .surfaceplant .TotalkWhProduced .value [i ] = model .surfaceplant .TotalkWhProduced .value [i ] - (
660- self .CarbonExtractedAnnually .value [i ] * self .elec .value )
694+ self .CarbonExtractedAnnually .value [i ] * self .elec .value )
661695 model .surfaceplant .NetkWhProduced .value [i ] = model .surfaceplant .NetkWhProduced .value [i ] - (
662- self .CarbonExtractedAnnually .value [i ] * self .elec .value )
696+ self .CarbonExtractedAnnually .value [i ] * self .elec .value )
663697 if model .surfaceplant .enduse_option .value is not EndUseOptions .ELECTRICITY :
664698 model .surfaceplant .HeatkWhProduced .value [i ] = model .surfaceplant .HeatkWhProduced .value [i ] - (
665- self .CarbonExtractedAnnually .value [i ] * self .therm .value )
699+ self .CarbonExtractedAnnually .value [i ] * self .therm .value )
666700 else :
667701 # all the end-use option of direct-use only component
668702 model .surfaceplant .HeatkWhProduced .value [i ] = (model .surfaceplant .HeatkWhProduced .value [i ] -
669- (self .CarbonExtractedAnnually .value [i ] * self . therm . value ))
670-
671- # FIXME TODO https://github.com/NREL/GEOPHIRES-X/issues/341?title=S-DAC+does+not+calculate+carbon+revenue
672- # Build a revenue generation model for the carbon capture, assuming the capture is being sequestered and that
673- # there is some sort of credit involved for doing that sequestering
674- # note that there may already be values in the CarbonRevenue array, so we need to
675- # 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
676- #total_duration = model.surfaceplant.plant_lifetime.value
677- #for i in range(0, total_duration, 1):
678- # model.sdacgteconomics.CarbonRevenue.value[i] = (model.sdacgteconomics.CarbonRevenue.value[i] +
679- # ( self.CarbonExtractedAnnually .value[i] * model.economics.CarbonPrice. value[i]))
680- # if i > 0 :
681- # model.economics. CarbonCummCashFlow.value[i] = model.economics. CarbonCummCashFlow.value[i - 1] + model.economics .CarbonRevenue.value[i]
703+ (self .CarbonExtractedAnnually .value [
704+ i ] * self . therm . value ))
705+
706+ # Calculate Carbon Revenue based on S-DAC-GT specific credit price
707+ self . CarbonRevenue . value = [ 0.0 ] * model . surfaceplant . plant_lifetime . value
708+ self . CarbonCummCashFlow . value = [ 0.0 ] * model . surfaceplant . plant_lifetime . value
709+
710+ for i in range ( 0 , model .surfaceplant .plant_lifetime .value , 1 ):
711+ self . CarbonRevenue . value [ i ] = self . CarbonExtractedAnnually . value [ i ] * self . carbon_credit_price . value
712+ if i == 0 :
713+ self .CarbonCummCashFlow .value [i ] = self . CarbonRevenue . value [i ]
714+ else :
715+ self . CarbonCummCashFlow .value [i ] = self . CarbonCummCashFlow .value [i - 1 ] + self .CarbonRevenue .value [i ]
682716
683717 self ._calculate_derived_outputs (model )
684- model .logger .info (f'Complete { str (__class__ )} : { sys ._getframe ().f_code .co_name } ' )
718+ model .logger .info (f'Complete { str (__class__ )} : { sys ._getframe ().f_code .co_name } ' )
0 commit comments