@@ -2769,94 +2769,7 @@ def Calculate(self, model: Model) -> None:
27692769 if self .DoSDACGTCalculations .value :
27702770 model .sdacgteconomics .Calculate (model )
27712771
2772- # Calculate cashflow and cumulative cash flow
2773- total_duration = model .surfaceplant .plant_lifetime .value + model .surfaceplant .construction_years .value
2774- self .ElecRevenue .value = [0.0 ] * total_duration
2775- self .ElecCummRevenue .value = [0.0 ] * total_duration
2776- self .HeatRevenue .value = [0.0 ] * total_duration
2777- self .HeatCummRevenue .value = [0.0 ] * total_duration
2778- self .CoolingRevenue .value = [0.0 ] * total_duration
2779- self .CoolingCummRevenue .value = [0.0 ] * total_duration
2780- self .CarbonRevenue .value = [0.0 ] * total_duration
2781- self .CarbonCummCashFlow .value = [0.0 ] * total_duration
2782- self .TotalRevenue .value = [0.0 ] * total_duration
2783- self .TotalCummRevenue .value = [0.0 ] * total_duration
2784- self .CarbonThatWouldHaveBeenProducedTotal .value = 0.0
2785-
2786- # Based on the style of the project, calculate the revenue & cumulative revenue
2787- if model .surfaceplant .enduse_option .value == EndUseOptions .ELECTRICITY :
2788- self .ElecRevenue .value , self .ElecCummRevenue .value = CalculateRevenue (
2789- model .surfaceplant .plant_lifetime .value , model .surfaceplant .construction_years .value ,
2790- model .surfaceplant .NetkWhProduced .value , self .ElecPrice .value )
2791- self .TotalRevenue .value = self .ElecRevenue .value .copy ()
2792- #self.TotalCummRevenue.value = self.ElecCummRevenue.value
2793- elif model .surfaceplant .enduse_option .value == EndUseOptions .HEAT and model .surfaceplant .plant_type .value not in [PlantType .ABSORPTION_CHILLER ]:
2794- self .HeatRevenue .value , self .HeatCummRevenue .value = CalculateRevenue (
2795- model .surfaceplant .plant_lifetime .value , model .surfaceplant .construction_years .value ,
2796- model .surfaceplant .HeatkWhProduced .value , self .HeatPrice .value )
2797- self .TotalRevenue .value = self .HeatRevenue .value .copy ()
2798- #self.TotalCummRevenue.value = self.HeatCummRevenue.value
2799- elif model .surfaceplant .enduse_option .value == EndUseOptions .HEAT and model .surfaceplant .plant_type .value in [PlantType .ABSORPTION_CHILLER ]:
2800- self .CoolingRevenue .value , self .CoolingCummRevenue .value = CalculateRevenue (
2801- model .surfaceplant .plant_lifetime .value , model .surfaceplant .construction_years .value ,
2802- model .surfaceplant .cooling_kWh_Produced .value , self .CoolingPrice .value )
2803- self .TotalRevenue .value = self .CoolingRevenue .value .copy ()
2804- #self.TotalCummRevenue.value = self.CoolingCummRevenue.value
2805- elif model .surfaceplant .enduse_option .value in [EndUseOptions .COGENERATION_TOPPING_EXTRA_HEAT ,
2806- EndUseOptions .COGENERATION_TOPPING_EXTRA_ELECTRICITY ,
2807- EndUseOptions .COGENERATION_BOTTOMING_EXTRA_ELECTRICITY ,
2808- EndUseOptions .COGENERATION_BOTTOMING_EXTRA_HEAT ,
2809- EndUseOptions .COGENERATION_PARALLEL_EXTRA_HEAT ,
2810- EndUseOptions .COGENERATION_PARALLEL_EXTRA_ELECTRICITY ]: # co-gen
2811- # else:
2812- self .ElecRevenue .value , self .ElecCummRevenue .value = CalculateRevenue (
2813- model .surfaceplant .plant_lifetime .value , model .surfaceplant .construction_years .value ,
2814- model .surfaceplant .NetkWhProduced .value , self .ElecPrice .value )
2815- self .HeatRevenue .value , self .HeatCummRevenue .value = CalculateRevenue (
2816- model .surfaceplant .plant_lifetime .value , model .surfaceplant .construction_years .value ,
2817- model .surfaceplant .HeatkWhProduced .value , self .HeatPrice .value )
2818-
2819- for i in range (0 , model .surfaceplant .plant_lifetime .value + model .surfaceplant .construction_years .value , 1 ):
2820- self .TotalRevenue .value [i ] = self .ElecRevenue .value [i ] + self .HeatRevenue .value [i ]
2821- #if i > 0:
2822- # self.TotalCummRevenue.value[i] = self.TotalCummRevenue.value[i - 1] + self.TotalRevenue.value[i]
2823-
2824- if self .DoCarbonCalculations .value :
2825- self .CarbonRevenue .value , self .CarbonCummCashFlow .value , self .CarbonThatWouldHaveBeenProducedAnnually .value , \
2826- self .CarbonThatWouldHaveBeenProducedTotal .value = CalculateCarbonRevenue (model ,
2827- model .surfaceplant .plant_lifetime .value , model .surfaceplant .construction_years .value ,
2828- self .CarbonPrice .value , self .GridCO2Intensity .value , self .NaturalGasCO2Intensity .value ,
2829- model .surfaceplant .NetkWhProduced .value , model .surfaceplant .HeatkWhProduced .value )
2830- for i in range (model .surfaceplant .construction_years .value , model .surfaceplant .plant_lifetime .value + model .surfaceplant .construction_years .value , 1 ):
2831- self .TotalRevenue .value [i ] = self .TotalRevenue .value [i ] + self .CarbonRevenue .value [i ]
2832- #self.TotalCummRevenue.value[i] = self.TotalCummRevenue.value[i] + self.CarbonCummCashFlow.value[i]
2833-
2834- # for the sake of display, insert zeros at the beginning of the pricing arrays
2835- for i in range (0 , model .surfaceplant .construction_years .value , 1 ):
2836- self .ElecPrice .value .insert (0 , 0.0 )
2837- self .HeatPrice .value .insert (0 , 0.0 )
2838- self .CoolingPrice .value .insert (0 , 0.0 )
2839- self .CarbonPrice .value .insert (0 , 0.0 )
2840-
2841- # Insert the cost of construction into the front of the array that will be used to calculate NPV
2842- # the convention is that the upfront CAPEX is negative
2843- # This is the same for all projects
2844- ProjectCAPEXPerConstructionYear = self .CCap .value / model .surfaceplant .construction_years .value
2845- for i in range (0 , model .surfaceplant .construction_years .value , 1 ):
2846- self .TotalRevenue .value [i ] = - 1.0 * ProjectCAPEXPerConstructionYear
2847- self .TotalCummRevenue .value [i ] = - 1.0 * ProjectCAPEXPerConstructionYear
2848- # self.TotalRevenue.value, self.TotalCummRevenue.value = CalculateTotalRevenue(
2849- # model.surfaceplant.plant_lifetime.value, model.surfaceplant.construction_years.value, self.CCap.value,
2850- # self.Coam.value, self.TotalRevenue.value, self.TotalCummRevenue.value)
2851-
2852- # Do a one-time calculation that accounts for OPEX - no OPEX in the first year.
2853- for i in range (model .surfaceplant .construction_years .value ,
2854- model .surfaceplant .plant_lifetime .value + model .surfaceplant .construction_years .value , 1 ):
2855- self .TotalRevenue .value [i ] = self .TotalRevenue .value [i ] - self .Coam .value
2856-
2857- # Now do a one-time calculation that calculates the cumulative cash flow after everything else has been accounted for
2858- for i in range (1 , model .surfaceplant .plant_lifetime .value + model .surfaceplant .construction_years .value , 1 ):
2859- self .TotalCummRevenue .value [i ] = self .TotalCummRevenue .value [i - 1 ] + self .TotalRevenue .value [i ]
2772+ self .calculate_cashflow (model )
28602773
28612774 # Calculate more financial values using numpy financials
28622775 self .ProjectNPV .value , self .ProjectIRR .value , self .ProjectVIR .value , self .ProjectMOIC .value = \
@@ -2899,6 +2812,99 @@ def Calculate(self, model: Model) -> None:
28992812 self ._calculate_derived_outputs (model )
29002813 model .logger .info (f'complete { __class__ !s} : { sys ._getframe ().f_code .co_name } ' )
29012814
2815+
2816+ def calculate_cashflow (self , model : Model ) -> None :
2817+ """
2818+ Calculate cashflow and cumulative cash flow
2819+ """
2820+ total_duration = model .surfaceplant .plant_lifetime .value + model .surfaceplant .construction_years .value
2821+ self .ElecRevenue .value = [0.0 ] * total_duration
2822+ self .ElecCummRevenue .value = [0.0 ] * total_duration
2823+ self .HeatRevenue .value = [0.0 ] * total_duration
2824+ self .HeatCummRevenue .value = [0.0 ] * total_duration
2825+ self .CoolingRevenue .value = [0.0 ] * total_duration
2826+ self .CoolingCummRevenue .value = [0.0 ] * total_duration
2827+ self .CarbonRevenue .value = [0.0 ] * total_duration
2828+ self .CarbonCummCashFlow .value = [0.0 ] * total_duration
2829+ self .TotalRevenue .value = [0.0 ] * total_duration
2830+ self .TotalCummRevenue .value = [0.0 ] * total_duration
2831+ self .CarbonThatWouldHaveBeenProducedTotal .value = 0.0
2832+
2833+ # Based on the style of the project, calculate the revenue & cumulative revenue
2834+ if model .surfaceplant .enduse_option .value == EndUseOptions .ELECTRICITY :
2835+ self .ElecRevenue .value , self .ElecCummRevenue .value = CalculateRevenue (
2836+ model .surfaceplant .plant_lifetime .value , model .surfaceplant .construction_years .value ,
2837+ model .surfaceplant .NetkWhProduced .value , self .ElecPrice .value )
2838+ self .TotalRevenue .value = self .ElecRevenue .value .copy ()
2839+ #self.TotalCummRevenue.value = self.ElecCummRevenue.value
2840+ elif model .surfaceplant .enduse_option .value == EndUseOptions .HEAT and model .surfaceplant .plant_type .value not in [PlantType .ABSORPTION_CHILLER ]:
2841+ self .HeatRevenue .value , self .HeatCummRevenue .value = CalculateRevenue (
2842+ model .surfaceplant .plant_lifetime .value , model .surfaceplant .construction_years .value ,
2843+ model .surfaceplant .HeatkWhProduced .value , self .HeatPrice .value )
2844+ self .TotalRevenue .value = self .HeatRevenue .value .copy ()
2845+ #self.TotalCummRevenue.value = self.HeatCummRevenue.value
2846+ elif model .surfaceplant .enduse_option .value == EndUseOptions .HEAT and model .surfaceplant .plant_type .value in [PlantType .ABSORPTION_CHILLER ]:
2847+ self .CoolingRevenue .value , self .CoolingCummRevenue .value = CalculateRevenue (
2848+ model .surfaceplant .plant_lifetime .value , model .surfaceplant .construction_years .value ,
2849+ model .surfaceplant .cooling_kWh_Produced .value , self .CoolingPrice .value )
2850+ self .TotalRevenue .value = self .CoolingRevenue .value .copy ()
2851+ #self.TotalCummRevenue.value = self.CoolingCummRevenue.value
2852+ elif model .surfaceplant .enduse_option .value in [EndUseOptions .COGENERATION_TOPPING_EXTRA_HEAT ,
2853+ EndUseOptions .COGENERATION_TOPPING_EXTRA_ELECTRICITY ,
2854+ EndUseOptions .COGENERATION_BOTTOMING_EXTRA_ELECTRICITY ,
2855+ EndUseOptions .COGENERATION_BOTTOMING_EXTRA_HEAT ,
2856+ EndUseOptions .COGENERATION_PARALLEL_EXTRA_HEAT ,
2857+ EndUseOptions .COGENERATION_PARALLEL_EXTRA_ELECTRICITY ]: # co-gen
2858+ # else:
2859+ self .ElecRevenue .value , self .ElecCummRevenue .value = CalculateRevenue (
2860+ model .surfaceplant .plant_lifetime .value , model .surfaceplant .construction_years .value ,
2861+ model .surfaceplant .NetkWhProduced .value , self .ElecPrice .value )
2862+ self .HeatRevenue .value , self .HeatCummRevenue .value = CalculateRevenue (
2863+ model .surfaceplant .plant_lifetime .value , model .surfaceplant .construction_years .value ,
2864+ model .surfaceplant .HeatkWhProduced .value , self .HeatPrice .value )
2865+
2866+ for i in range (0 , model .surfaceplant .plant_lifetime .value + model .surfaceplant .construction_years .value , 1 ):
2867+ self .TotalRevenue .value [i ] = self .ElecRevenue .value [i ] + self .HeatRevenue .value [i ]
2868+ #if i > 0:
2869+ # self.TotalCummRevenue.value[i] = self.TotalCummRevenue.value[i - 1] + self.TotalRevenue.value[i]
2870+
2871+ if self .DoCarbonCalculations .value :
2872+ self .CarbonRevenue .value , self .CarbonCummCashFlow .value , self .CarbonThatWouldHaveBeenProducedAnnually .value , \
2873+ self .CarbonThatWouldHaveBeenProducedTotal .value = CalculateCarbonRevenue (model ,
2874+ model .surfaceplant .plant_lifetime .value , model .surfaceplant .construction_years .value ,
2875+ self .CarbonPrice .value , self .GridCO2Intensity .value , self .NaturalGasCO2Intensity .value ,
2876+ model .surfaceplant .NetkWhProduced .value , model .surfaceplant .HeatkWhProduced .value )
2877+ for i in range (model .surfaceplant .construction_years .value , model .surfaceplant .plant_lifetime .value + model .surfaceplant .construction_years .value , 1 ):
2878+ self .TotalRevenue .value [i ] = self .TotalRevenue .value [i ] + self .CarbonRevenue .value [i ]
2879+ #self.TotalCummRevenue.value[i] = self.TotalCummRevenue.value[i] + self.CarbonCummCashFlow.value[i]
2880+
2881+ # for the sake of display, insert zeros at the beginning of the pricing arrays
2882+ for i in range (0 , model .surfaceplant .construction_years .value , 1 ):
2883+ self .ElecPrice .value .insert (0 , 0.0 )
2884+ self .HeatPrice .value .insert (0 , 0.0 )
2885+ self .CoolingPrice .value .insert (0 , 0.0 )
2886+ self .CarbonPrice .value .insert (0 , 0.0 )
2887+
2888+ # Insert the cost of construction into the front of the array that will be used to calculate NPV
2889+ # the convention is that the upfront CAPEX is negative
2890+ # This is the same for all projects
2891+ ProjectCAPEXPerConstructionYear = self .CCap .value / model .surfaceplant .construction_years .value
2892+ for i in range (0 , model .surfaceplant .construction_years .value , 1 ):
2893+ self .TotalRevenue .value [i ] = - 1.0 * ProjectCAPEXPerConstructionYear
2894+ self .TotalCummRevenue .value [i ] = - 1.0 * ProjectCAPEXPerConstructionYear
2895+ # self.TotalRevenue.value, self.TotalCummRevenue.value = CalculateTotalRevenue(
2896+ # model.surfaceplant.plant_lifetime.value, model.surfaceplant.construction_years.value, self.CCap.value,
2897+ # self.Coam.value, self.TotalRevenue.value, self.TotalCummRevenue.value)
2898+
2899+ # Do a one-time calculation that accounts for OPEX - no OPEX in the first year.
2900+ for i in range (model .surfaceplant .construction_years .value ,
2901+ model .surfaceplant .plant_lifetime .value + model .surfaceplant .construction_years .value , 1 ):
2902+ self .TotalRevenue .value [i ] = self .TotalRevenue .value [i ] - self .Coam .value
2903+
2904+ # Now do a one-time calculation that calculates the cumulative cash flow after everything else has been accounted for
2905+ for i in range (1 , model .surfaceplant .plant_lifetime .value + model .surfaceplant .construction_years .value , 1 ):
2906+ self .TotalCummRevenue .value [i ] = self .TotalCummRevenue .value [i - 1 ] + self .TotalRevenue .value [i ]
2907+
29022908 def _calculate_derived_outputs (self , model : Model ) -> None :
29032909 """
29042910 Subclasses should call _calculate_derived_outputs at the end of their Calculate methods to populate output
0 commit comments