CYCLUS
Loading...
Searching...
No Matches
facility_cost.cycpp.h
Go to the documentation of this file.
1/// This includes the required header to add facility costs to archetypes.
2/// One should only need to:
3/// - '#include "toolkit/facility_cost.cycpp.h"' in the header of the
4/// archetype class (as private)
5/// - Add `InitEconParameters()` to `EnterNotify()` in the cc file of the
6/// archetype class.
7
8/// How to add parameters to this file:
9/// 1. Add the pragma. A default value MUST be added to ensure backwards
10/// compatibility.
11/// 2. Edit the unordered_map called "econ_params"
12/// i. add the desired parameter to the array {"name", value}
13/// ii. the value of the pair should be the variable name exactly
14/// 3. Add "std::vector<int> cycpp_shape_<param_name> = {0};" to the end of the
15/// file with the other ones, reaplcing <param_name> with the name you put
16/// in the econ_params array (again, must match exactly).
17
18// clang-format off
19#pragma cyclus var {"default" : 0.0, \
20 "uilabel" : "Capital cost required to build facility", \
21 "doc" : "Capital cost required to build facility", \
22 "units" : "Unit of Currency" }
24
25#pragma cyclus var { \
26 "default": 0.0, \
27 "uilabel": "Property Tax Rate as decimal", \
28 "range": [0.0, 1.0], \
29 "doc": "Property tax rate for this facility as decimal (1% --> 0.01)" \
30 }
32
33#pragma cyclus var { \
34 "default" : 0.0, "uilabel" : "Annual Operations and Maintenance Cost", \
35 "doc" : "Annual Operations and Maintenance Cost required to run facility", \
36 "units" : "Unit of Currency" }
38
39#pragma cyclus var { \
40 "default": 1.0, \
41 "uilabel": "Estimated Useful lifetime of facility for economic purposes in years", \
42 "doc": "Estimate on how long the facility will be active for economic purposes", \
43 "units": "years" \
44 }
46
47#pragma cyclus var { \
48 "default": 1.0, \
49 "uilabel": "Taxable lifetime of facility for economic purposes in years", \
50 "doc": "How long the facility will be depreciating their initial investment", \
51 "units": "years" \
52 }
54
55// We maybe want this to be more like a line-item not per unit?
56#pragma cyclus var { \
57 "default": 0.0, \
58 "uilabel": "Annual cost of labor", \
59 "doc": "Annual cost of labor", \
60 "units": "Unit of Currency" \
61 }
63
64#pragma cyclus var { \
65 "default": -1.0, \
66 "uilabel": "Cost in dollars of one unit of production", \
67 "doc": "(optional) Hook to bypass LCP calculation and provide a cost in dollars", \
68 "units": "Dimensionless" \
69 }
71
72#pragma cyclus var { \
73 "default": 0.0, \
74 "uilabel": "Property Insurance Rate as decimal", \
75 "range": [0.0, 1.0], \
76 "doc": "Property insurance rate for this facility as decimal (1% --> 0.01)" \
77 }
79// clang-format on
80
81// Must be done in a function so that we can access the user-defined values
82std::unordered_map<std::string, double> GenerateParamList() const override {
83 std::unordered_map<std::string, double> econ_params{
84 {"capital_cost", capital_cost},
85 {"property_tax_rate", property_tax_rate},
86 {"annual_operations_and_maintenance", annual_operations_and_maintenance},
87 {"facility_operational_lifetime", facility_operational_lifetime},
88 {"facility_depreciation_lifetime", facility_depreciation_lifetime},
89 {"annual_labor_cost", annual_labor_cost},
90 {"property_insurance_rate", property_insurance_rate}};
91
92 return econ_params;
93}
94
95/// @brief Calculates the levelized unit cost of production, accounting for
96/// capital depreciation, O&M, labor, property taxes, and input costs.
97///
98/// unit_cost = cost_override if cost_override > 0, otherwise unit_cost = production_cost + material_cost
99///
100/// Where:
101/// - production_cost = levelized_fixed_costs/units_produced_annually + levelized_variable_costs + (initial_investment/units_produced_annually) * [property_tax_insurance_rate + (1/(1-income_tax_rate)) * PMT(facility_lifetime, tax_modified_rate_of_return, 1, 0) - (1/facility_lifetime) * (income_tax_rate/(1-income_tax_rate))]
102/// - material_cost = Unit Cost of Material (weighted average of input material unit values)
103/// - units_produced_annually = production_capacity * timesteps_per_year
104/// - levelized_fixed_costs = annual_operations_and_maintenance
105/// - levelized_variable_costs = annual_labor_cost
106/// - initial_investment = capital_cost
107/// - property_and_insurance_rate = property_tax_rate + property_insurance_rate
108/// - tax_modified_rate_of_return = (1-income_tax_rate)*bond_rate*bond_fraction + shareholder_rate*shareholder_fraction
109/// - income_tax_rate = Income Tax Rate
110/// - facility_lifetime = facility_depreciation_lifetime
111///
112/// The model assumes straight-line depreciation over the facility lifetime.
113///
114/// @param production_capacity Maximum throughput per timestep
115/// @param units_to_produce Number of units produced in the batch
116/// @param input_cost (Optional) Total cost of input materials used in the batch
117/// @return Estimated levelized cost to produce one unit
118double CalculateUnitCost(double production_capacity, double units_to_produce,
119 double input_cost_per_unit = 0.0) const {
120 // Check if there's a cost override, and if so, use that
121 if (cost_override > 0) {
122 return cost_override + input_cost_per_unit;
123 }
124
125 // Economic Parameters (required for the try catch block)
126 double initial_investment;
127 double facility_lifetime;
128 double levelized_fixed_costs;
129 double levelized_variable_costs;
130 double property_and_insurance_rate;
131 double tax_modified_rate_of_return;
132 double income_tax_rate;
133 double bond_rate;
134 double bond_fraction;
135 double shareholder_rate;
136 double shareholder_fraction;
138
139 // Get facility-level parameters
140 try {
141 initial_investment = GetEconParameter("capital_cost");
142 facility_lifetime = GetEconParameter("facility_depreciation_lifetime");
143 property_insurance_rate = GetEconParameter("property_insurance_rate");
144
145 // Note: Since our fixed and variable costs are the same every timestep, we
146 // call them levelized here. If that changes in the future, we need to
147 // change this to reflect actual levelization. Additionally, if more
148 // fixed and variable costs are added in the future, we need to change this
149 // to reflect that as well.
150 levelized_fixed_costs = GetEconParameter("annual_operations_and_maintenance");
151 levelized_variable_costs = GetEconParameter("annual_labor_cost");
152
153 } catch (const std::exception& e) {
154 LOG(cyclus::LEV_INFO1, "CalculateUnitCost")
155 << prototype() << "failed to get facility financial_data_: " << e.what();
156 return kDefaultUnitCost;
157 }
158
159 // Get institution-level parameters
160 try {
161 income_tax_rate = parent()->GetEconParameter("corporate_income_tax_rate");
162 bond_rate = parent()->GetEconParameter("bond_holders_rate_of_return");
163 bond_fraction = parent()->GetEconParameter("fraction_bond_financing");
164 shareholder_rate = parent()->GetEconParameter("share_holders_rate_of_return");
165 shareholder_fraction = parent()->GetEconParameter("fraction_private_capital");
166 } catch (const std::exception& e) {
167 LOG(cyclus::LEV_INFO1, "CalculateUnitCost")
168 << prototype()
169 << "failed to get institution financial_data_: " << e.what();
170 return kDefaultUnitCost;
171 }
172
173 // Get region-level parameters
174 try {
175 double property_tax_rate = parent()->parent()->GetEconParameter("property_tax_rate");
176 property_and_insurance_rate = property_tax_rate + property_insurance_rate;
177 } catch (const std::exception& e) {
178 LOG(cyclus::LEV_INFO1, "CalculateUnitCost")
179 << prototype() << "failed to get region financial_data_: " << e.what();
180 return kDefaultUnitCost;
181 }
182
183 // U = throughput * timesteps_per_year
184 double timesteps_per_year = cyclusYear / context()->dt();
185 double units_produced_annually = production_capacity * timesteps_per_year;
186
187 // x = (1-τ)*r_b*f_b + r_s*f_s
188 tax_modified_rate_of_return = (1 - income_tax_rate) * bond_rate * bond_fraction + shareholder_rate * shareholder_fraction;
189
190 // c_j = F_bar/U + V_bar + (I_0/U) * [p + (1/(1-τ)) * PMT(N,x,1,0) - (1/N) * (τ/(1-τ))]
191 double fixed_cost_per_unit = levelized_fixed_costs / units_produced_annually;
192 double capital_investment_per_unit = initial_investment / units_produced_annually;
193
194 double depreciation_tax_shield = income_tax_rate / (1.0 - income_tax_rate) / facility_lifetime;
195 double capital_recovery_factor = PMT(facility_lifetime, tax_modified_rate_of_return, 1.0, 0.0) / (1.0 - income_tax_rate);
196 double capital_cost_per_unit = capital_investment_per_unit * (property_and_insurance_rate + capital_recovery_factor - depreciation_tax_shield);
197 double production_cost = fixed_cost_per_unit + levelized_variable_costs + capital_cost_per_unit;
198
199 // c_u = c_j + c_M = production_cost + input_cost_per_unit
200 double unit_cost = production_cost + input_cost_per_unit;
201
202 // Protects against divide by zero in pref = 1/unit_cost
203 return unit_cost != 0 ? unit_cost : kDefaultUnitCost;
204}
205
206double CalculateUnitPrice(double production_capacity, double units_to_produce,
207 double input_cost_per_unit = 0.0) const {
208 // Default implementation
209 return CalculateUnitCost(production_capacity, units_to_produce, input_cost_per_unit);
210}
211
212// Required for compilation but not added by the cycpp preprocessor. Do not
213// remove. Must be one for each variable.
214std::vector<int> cycpp_shape_capital_cost = {0};
215std::vector<int> cycpp_shape_property_tax_rate = {0};
219std::vector<int> cycpp_shape_annual_labor_cost = {0};
220std::vector<int> cycpp_shape_cost_override = {0};
const uint64_t cyclusYear
Definition context.h:25
double annual_labor_cost
double facility_depreciation_lifetime
double property_tax_rate
double cost_override
std::vector< int > cycpp_shape_capital_cost
std::vector< int > cycpp_shape_property_insurance_rate
std::vector< int > cycpp_shape_facility_depreciation_lifetime
std::vector< int > cycpp_shape_property_tax_rate
double facility_operational_lifetime
double CalculateUnitPrice(double production_capacity, double units_to_produce, double input_cost_per_unit=0.0) const
double property_insurance_rate
std::unordered_map< std::string, double > GenerateParamList() const override
std::vector< int > cycpp_shape_annual_labor_cost
double annual_operations_and_maintenance
std::vector< int > cycpp_shape_facility_operational_lifetime
std::vector< int > cycpp_shape_cost_override
std::vector< int > cycpp_shape_annual_operations_and_maintenance
double CalculateUnitCost(double production_capacity, double units_to_produce, double input_cost_per_unit=0.0) const
Calculates the levelized unit cost of production, accounting for capital depreciation,...
double capital_cost
This includes the required header to add facility costs to archetypes.
#define LOG(level, prefix)
allows easy logging via the streaming operator similar to std::cout; this is the primary way to use t...
Definition logger.h:34
@ LEV_INFO1
Information helpful for simulation users and developers alike.
Definition logger.h:60