From 7270e02da158978ec6e924ed228d23cdac9e62a3 Mon Sep 17 00:00:00 2001 From: Dean Krueger Date: Tue, 9 Dec 2025 19:10:33 -0600 Subject: [PATCH 01/28] first pass on reworking facility_cost.cycpp.h, still needs work. --- src/toolkit/facility_cost.cycpp.h | 318 +++++++++++++++++++++--------- 1 file changed, 230 insertions(+), 88 deletions(-) diff --git a/src/toolkit/facility_cost.cycpp.h b/src/toolkit/facility_cost.cycpp.h index bd99a6a87e..f0cd715237 100644 --- a/src/toolkit/facility_cost.cycpp.h +++ b/src/toolkit/facility_cost.cycpp.h @@ -31,10 +31,10 @@ double capital_cost; double property_tax_rate; #pragma cyclus var { \ - "default" : 0.0, "uilabel" : "Annual Operations and Maintenance Cost", \ - "doc" : "Annual Operations and Maintenance Cost required to run facility", \ - "units" : "Unit of Currency" } -double annual_operations_and_maintenance; + "default" : 0.0, "uilabel" : "Annual Fixed Costs", \ + "doc" : "Annual fixed costs (operations, maintenance, etc.) required to run facility", \ + "units" : "Unit of Currency/year" } +double annual_fixed_costs; #pragma cyclus var { \ "default": 1.0, \ @@ -52,14 +52,13 @@ double facility_operational_lifetime; } double facility_depreciation_lifetime; -// We maybe want this to be more like a line-item not per unit? #pragma cyclus var { \ "default": 0.0, \ - "uilabel": "Annual cost of labor", \ - "doc": "Annual cost of labor", \ - "units": "Unit of Currency" \ + "uilabel": "Annual Variable Costs", \ + "doc": "Annual variable costs (labor, materials, etc.) that vary with production", \ + "units": "Unit of Currency/Unit of Production/year" \ } -double annual_labor_cost; +double annual_variable_costs; #pragma cyclus var { \ "default": -1.0, \ @@ -83,17 +82,200 @@ std::unordered_map GenerateParamList() const override { std::unordered_map econ_params{ {"capital_cost", capital_cost}, {"property_tax_rate", property_tax_rate}, - {"annual_operations_and_maintenance", annual_operations_and_maintenance}, + {"annual_fixed_costs", annual_fixed_costs}, {"facility_operational_lifetime", facility_operational_lifetime}, {"facility_depreciation_lifetime", facility_depreciation_lifetime}, - {"annual_labor_cost", annual_labor_cost}, + {"annual_variable_costs", annual_variable_costs}, {"property_insurance_rate", property_insurance_rate}}; return econ_params; } +// ============================================================================= +// Economic Parameter Retrieval Functions +// ============================================================================= + +/// @brief Retrieves facility-level economic parameters +/// @param initial_investment Output parameter for capital cost +/// @param facility_lifetime Output parameter for depreciation lifetime +/// @param property_insurance_rate Output parameter for property insurance rate +/// @param levelized_fixed_costs Output parameter for annual fixed costs +/// @param levelized_variable_costs Output parameter for annual variable costs +/// @return true if successful, false otherwise +bool GetFacilityEconParameters(double& initial_investment, + double& facility_lifetime, + double& property_insurance_rate, + double& levelized_fixed_costs, + double& levelized_variable_costs) const { + try { + initial_investment = GetEconParameter("capital_cost"); + facility_lifetime = GetEconParameter("facility_depreciation_lifetime"); + property_insurance_rate = GetEconParameter("property_insurance_rate"); + + // Note: Since our fixed and variable costs are the same every timestep, we + // call them levelized here. If that changes in the future, we need to + // change this to reflect actual levelization. Additionally, if more + // fixed and variable costs are added in the future, we need to change this + // to reflect that as well. + levelized_fixed_costs = + GetEconParameter("annual_fixed_costs"); + levelized_variable_costs = GetEconParameter("annual_variable_costs"); + return true; + } catch (const std::exception& e) { + LOG(cyclus::LEV_INFO1, "GetFacilityEconParameters") + << prototype() + << "failed to get facility financial_data_: " << e.what(); + return false; + } +} + +/// @brief Retrieves institution-level economic parameters +/// @param income_tax_rate Output parameter for corporate income tax rate +/// @param bond_rate Output parameter for bond holders rate of return +/// @param bond_fraction Output parameter for fraction bond financing +/// @param shareholder_rate Output parameter for share holders rate of return +/// @param shareholder_fraction Output parameter for fraction private capital +/// @return true if successful, false otherwise +bool GetInstitutionEconParameters(double& income_tax_rate, + double& bond_rate, + double& bond_fraction, + double& shareholder_rate, + double& shareholder_fraction) const { + try { + income_tax_rate = parent()->GetEconParameter("corporate_income_tax_rate"); + bond_rate = parent()->GetEconParameter("bond_holders_rate_of_return"); + bond_fraction = parent()->GetEconParameter("fraction_bond_financing"); + shareholder_rate = + parent()->GetEconParameter("share_holders_rate_of_return"); + shareholder_fraction = + parent()->GetEconParameter("fraction_private_capital"); + return true; + } catch (const std::exception& e) { + LOG(cyclus::LEV_INFO1, "GetInstitutionEconParameters") + << prototype() + << "failed to get institution financial_data_: " << e.what(); + return false; + } +} + +/// @brief Retrieves region-level economic parameters +/// @param property_and_insurance_rate Output parameter for combined property +/// tax and insurance rate +/// @param property_insurance_rate Input parameter for property insurance rate +/// @return true if successful, false otherwise +bool GetRegionEconParameters(double& property_and_insurance_rate, + double property_insurance_rate) const { + try { + double property_tax_rate = + parent()->parent()->GetEconParameter("property_tax_rate"); + property_and_insurance_rate = property_tax_rate + property_insurance_rate; + return true; + } catch (const std::exception& e) { + LOG(cyclus::LEV_INFO1, "GetRegionEconParameters") + << prototype() << "failed to get region financial_data_: " << e.what(); + return false; + } +} + +// ============================================================================= +// Cost Calculation Functions +// ============================================================================= + +/// @brief Calculates the number of units produced annually +/// @param production_capacity Maximum throughput per timestep +/// @return Units produced annually +double CalcUnitsProducedAnnually(double production_capacity) const { + double timesteps_per_year = cyclusYear / context()->dt(); + return production_capacity * timesteps_per_year; +} + +/// @brief Calculates the tax-modified rate of return +/// Formula: (1-τ)*r_b*f_b + r_s*f_s +/// @param income_tax_rate Corporate income tax rate +/// @param bond_rate Bond holders rate of return +/// @param bond_fraction Fraction of bond financing +/// @param shareholder_rate Share holders rate of return +/// @param shareholder_fraction Fraction of private capital +/// @return Tax-modified rate of return +double CalcTaxModifiedRateOfReturn(double income_tax_rate, + double bond_rate, + double bond_fraction, + double shareholder_rate, + double shareholder_fraction) const { + return (1 - income_tax_rate) * bond_rate * bond_fraction + + shareholder_rate * shareholder_fraction; +} + +/// @brief Calculates fixed cost per unit +/// @param levelized_fixed_costs Annual fixed costs +/// @param units_produced_annually Number of units produced per year +/// @return Fixed cost per unit +double CalcFixedCostPerUnit(double levelized_fixed_costs, + double units_produced_annually) const { + if (units_produced_annually == 0) { + return 0.0; + } + return levelized_fixed_costs / units_produced_annually; +} + +/// @brief Calculates capital cost per unit +/// Formula: (I_0/U) * [p + (1/(1-τ)) * PMT(N,x,1,0) - (1/N) * (τ/(1-τ))] +/// where: +/// - I_0 = initial investment +/// - U = units produced annually +/// - p = property and insurance rate +/// - τ = income tax rate +/// - N = facility lifetime +/// - x = tax-modified rate of return +/// @param initial_investment Capital cost +/// @param units_produced_annually Number of units produced per year +/// @param facility_lifetime Facility depreciation lifetime in years +/// @param income_tax_rate Corporate income tax rate +/// @param tax_modified_rate_of_return Tax-modified rate of return +/// @param property_and_insurance_rate Combined property tax and insurance rate +/// @return Capital cost per unit +double CalcCapitalCostPerUnit(double initial_investment, + double units_produced_annually, + double facility_lifetime, + double income_tax_rate, + double tax_modified_rate_of_return, + double property_and_insurance_rate) const { + if (units_produced_annually == 0) { + return 0.0; + } + + double capital_investment_per_unit = + initial_investment / units_produced_annually; + + double depreciation_tax_shield = + income_tax_rate / (1.0 - income_tax_rate) / facility_lifetime; + double capital_recovery_factor = + PMT(facility_lifetime, tax_modified_rate_of_return, 1.0, 0.0) / + (1.0 - income_tax_rate); + + return capital_investment_per_unit * + (property_and_insurance_rate + capital_recovery_factor - + depreciation_tax_shield); +} + +/// @brief Calculates marginal cost per unit (variable + material, excluding +/// fixed and capital costs) +/// Marginal cost represents the cost of producing one additional unit, +/// excluding fixed and capital costs which are sunk. +/// @param variable_cost_per_unit Variable cost per unit +/// @param material_cost_per_unit Material cost per unit +/// @return Marginal cost per unit +double CalcMarginalCost(double variable_cost_per_unit, + double material_cost_per_unit) const { + return variable_cost_per_unit + material_cost_per_unit; +} + +// ============================================================================= +// Main Cost Calculation Function +// ============================================================================= + /// @brief Calculates the levelized unit cost of production, accounting for -/// capital depreciation, O&M, labor, property taxes, and input costs. +/// capital depreciation, fixed costs, variable costs, property taxes, and input costs. /// /// unit_cost = cost_override if cost_override > 0, otherwise unit_cost = /// production_cost + material_cost @@ -107,8 +289,8 @@ std::unordered_map GenerateParamList() const override { /// - material_cost = Unit Cost of Material (weighted average of input material /// unit values) /// - units_produced_annually = production_capacity * timesteps_per_year -/// - levelized_fixed_costs = annual_operations_and_maintenance -/// - levelized_variable_costs = annual_labor_cost +/// - levelized_fixed_costs = annual_fixed_costs +/// - levelized_variable_costs = annual_variable_costs /// - initial_investment = capital_cost /// - property_and_insurance_rate = property_tax_rate + property_insurance_rate /// - tax_modified_rate_of_return = (1-income_tax_rate)*bond_rate*bond_fraction @@ -122,6 +304,7 @@ std::unordered_map GenerateParamList() const override { /// @param units_to_produce Number of units produced in the batch /// @param input_cost (Optional) Total cost of input materials used in the batch /// @return Estimated levelized cost to produce one unit + double CalculateUnitCost(double production_capacity, double units_to_produce, double input_cost_per_unit = 0.0) const { // Check if there's a cost override, and if so, use that @@ -129,97 +312,56 @@ double CalculateUnitCost(double production_capacity, double units_to_produce, return cost_override + input_cost_per_unit; } - // Economic Parameters (required for the try catch block) + // Get facility-level parameters double initial_investment; double facility_lifetime; + double property_insurance_rate; double levelized_fixed_costs; double levelized_variable_costs; - double property_and_insurance_rate; - double tax_modified_rate_of_return; + if (!GetFacilityEconParameters(initial_investment, facility_lifetime, + property_insurance_rate, + levelized_fixed_costs, + levelized_variable_costs)) { + return kDefaultUnitCost; + } + + // Get institution-level parameters double income_tax_rate; double bond_rate; double bond_fraction; double shareholder_rate; double shareholder_fraction; - double property_insurance_rate; - - // Get facility-level parameters - try { - initial_investment = GetEconParameter("capital_cost"); - facility_lifetime = GetEconParameter("facility_depreciation_lifetime"); - property_insurance_rate = GetEconParameter("property_insurance_rate"); - - // Note: Since our fixed and variable costs are the same every timestep, we - // call them levelized here. If that changes in the future, we need to - // change this to reflect actual levelization. Additionally, if more - // fixed and variable costs are added in the future, we need to change this - // to reflect that as well. - levelized_fixed_costs = - GetEconParameter("annual_operations_and_maintenance"); - levelized_variable_costs = GetEconParameter("annual_labor_cost"); - - } catch (const std::exception& e) { - LOG(cyclus::LEV_INFO1, "CalculateUnitCost") - << prototype() - << "failed to get facility financial_data_: " << e.what(); - return kDefaultUnitCost; - } - - // Get institution-level parameters - try { - income_tax_rate = parent()->GetEconParameter("corporate_income_tax_rate"); - bond_rate = parent()->GetEconParameter("bond_holders_rate_of_return"); - bond_fraction = parent()->GetEconParameter("fraction_bond_financing"); - shareholder_rate = - parent()->GetEconParameter("share_holders_rate_of_return"); - shareholder_fraction = - parent()->GetEconParameter("fraction_private_capital"); - } catch (const std::exception& e) { - LOG(cyclus::LEV_INFO1, "CalculateUnitCost") - << prototype() - << "failed to get institution financial_data_: " << e.what(); + if (!GetInstitutionEconParameters(income_tax_rate, bond_rate, bond_fraction, + shareholder_rate, shareholder_fraction)) { return kDefaultUnitCost; } // Get region-level parameters - try { - double property_tax_rate = - parent()->parent()->GetEconParameter("property_tax_rate"); - property_and_insurance_rate = property_tax_rate + property_insurance_rate; - } catch (const std::exception& e) { - LOG(cyclus::LEV_INFO1, "CalculateUnitCost") - << prototype() << "failed to get region financial_data_: " << e.what(); + double property_and_insurance_rate; + if (!GetRegionEconParameters(property_and_insurance_rate, + property_insurance_rate)) { return kDefaultUnitCost; } - // U = throughput * timesteps_per_year - double timesteps_per_year = cyclusYear / context()->dt(); - double units_produced_annually = production_capacity * timesteps_per_year; + // Calculate intermediate values + double units_produced_annually = + CalcUnitsProducedAnnually(production_capacity); + double tax_modified_rate_of_return = CalcTaxModifiedRateOfReturn( + income_tax_rate, bond_rate, bond_fraction, shareholder_rate, + shareholder_fraction); - // x = (1-τ)*r_b*f_b + r_s*f_s - tax_modified_rate_of_return = - (1 - income_tax_rate) * bond_rate * bond_fraction + - shareholder_rate * shareholder_fraction; + // Calculate cost components + double fixed_cost_per_unit = + CalcFixedCostPerUnit(levelized_fixed_costs, units_produced_annually); + double capital_cost_per_unit = CalcCapitalCostPerUnit( + initial_investment, units_produced_annually, facility_lifetime, + income_tax_rate, tax_modified_rate_of_return, + property_and_insurance_rate); - // c_j = F_bar/U + V_bar + (I_0/U) * [p + (1/(1-τ)) * PMT(N,x,1,0) - (1/N) * - // (τ/(1-τ))] - double fixed_cost_per_unit = levelized_fixed_costs / units_produced_annually; - double capital_investment_per_unit = - initial_investment / units_produced_annually; - double depreciation_tax_shield = - income_tax_rate / (1.0 - income_tax_rate) / facility_lifetime; - double capital_recovery_factor = - PMT(facility_lifetime, tax_modified_rate_of_return, 1.0, 0.0) / - (1.0 - income_tax_rate); - double capital_cost_per_unit = - capital_investment_per_unit * - (property_and_insurance_rate + capital_recovery_factor - - depreciation_tax_shield); - double production_cost = - fixed_cost_per_unit + levelized_variable_costs + capital_cost_per_unit; - - // c_u = c_j + c_M = production_cost + input_cost_per_unit + // Assemble total unit cost + double production_cost = fixed_cost_per_unit + levelized_variable_costs + + capital_cost_per_unit; double unit_cost = production_cost + input_cost_per_unit; // Protects against divide by zero in pref = 1/unit_cost @@ -237,9 +379,9 @@ double CalculateUnitPrice(double production_capacity, double units_to_produce, // remove. Must be one for each variable. std::vector cycpp_shape_capital_cost = {0}; std::vector cycpp_shape_property_tax_rate = {0}; -std::vector cycpp_shape_annual_operations_and_maintenance = {0}; +std::vector cycpp_shape_annual_fixed_costs = {0}; std::vector cycpp_shape_facility_operational_lifetime = {0}; std::vector cycpp_shape_facility_depreciation_lifetime = {0}; -std::vector cycpp_shape_annual_labor_cost = {0}; +std::vector cycpp_shape_annual_variable_costs = {0}; std::vector cycpp_shape_cost_override = {0}; std::vector cycpp_shape_property_insurance_rate = {0}; \ No newline at end of file From 1286a462ff8bc40e62a5b35d98ff56b34273a2de Mon Sep 17 00:00:00 2001 From: Dean Krueger Date: Wed, 10 Dec 2025 16:51:20 -0600 Subject: [PATCH 02/28] second pass at reformatting this for MC, fixed a few errors with where certain values came from. --- src/toolkit/facility_cost.cycpp.h | 124 ++++++++++++++------------- src/toolkit/institution_cost.cycpp.h | 14 ++- src/toolkit/region_cost.cycpp.h | 11 +-- 3 files changed, 82 insertions(+), 67 deletions(-) diff --git a/src/toolkit/facility_cost.cycpp.h b/src/toolkit/facility_cost.cycpp.h index f0cd715237..03d43e3dea 100644 --- a/src/toolkit/facility_cost.cycpp.h +++ b/src/toolkit/facility_cost.cycpp.h @@ -18,21 +18,13 @@ // clang-format off #pragma cyclus var {"default" : 0.0, \ "uilabel" : "Capital cost required to build facility", \ - "doc" : "Capital cost required to build facility", \ + "doc" : "Total overnight capital cost required to build facility", \ "units" : "Unit of Currency" } double capital_cost; -#pragma cyclus var { \ - "default": 0.0, \ - "uilabel": "Property Tax Rate as decimal", \ - "range": [0.0, 1.0], \ - "doc": "Property tax rate for this facility as decimal (1% --> 0.01)" \ - } -double property_tax_rate; - #pragma cyclus var { \ "default" : 0.0, "uilabel" : "Annual Fixed Costs", \ - "doc" : "Annual fixed costs (operations, maintenance, etc.) required to run facility", \ + "doc" : "Annual fixed costs (operations, maintenance, etc., excluding property tax and insurance) required to run facility", \ "units" : "Unit of Currency/year" } double annual_fixed_costs; @@ -54,17 +46,17 @@ double facility_depreciation_lifetime; #pragma cyclus var { \ "default": 0.0, \ - "uilabel": "Annual Variable Costs", \ - "doc": "Annual variable costs (labor, materials, etc.) that vary with production", \ - "units": "Unit of Currency/Unit of Production/year" \ + "uilabel": "Variable Cost Per Unit", \ + "doc": "Variable cost per unit of production (labor, materials, etc. that vary with production)", \ + "units": "Unit of Currency/Unit of Production" \ } -double annual_variable_costs; +double variable_cost_per_unit; #pragma cyclus var { \ "default": -1.0, \ - "uilabel": "Cost in dollars of one unit of production", \ - "doc": "(optional) Hook to bypass LCP calculation and provide a cost in dollars", \ - "units": "Dimensionless" \ + "uilabel": "Non-material cost override in dollars of one unit of production", \ + "doc": "(optional) Hook to bypass LCP calculation and provide a cost in dollars. Should NOT include material costs, which are added later", \ + "units": "unit of currency/unit of production (eg. $/kg)" \ } double cost_override; @@ -81,11 +73,10 @@ double property_insurance_rate; std::unordered_map GenerateParamList() const override { std::unordered_map econ_params{ {"capital_cost", capital_cost}, - {"property_tax_rate", property_tax_rate}, {"annual_fixed_costs", annual_fixed_costs}, {"facility_operational_lifetime", facility_operational_lifetime}, {"facility_depreciation_lifetime", facility_depreciation_lifetime}, - {"annual_variable_costs", annual_variable_costs}, + {"variable_cost_per_unit", variable_cost_per_unit}, {"property_insurance_rate", property_insurance_rate}}; return econ_params; @@ -100,26 +91,25 @@ std::unordered_map GenerateParamList() const override { /// @param facility_lifetime Output parameter for depreciation lifetime /// @param property_insurance_rate Output parameter for property insurance rate /// @param levelized_fixed_costs Output parameter for annual fixed costs -/// @param levelized_variable_costs Output parameter for annual variable costs +/// @param variable_cost_per_unit Output parameter for variable cost per unit /// @return true if successful, false otherwise bool GetFacilityEconParameters(double& initial_investment, double& facility_lifetime, double& property_insurance_rate, double& levelized_fixed_costs, - double& levelized_variable_costs) const { + double& variable_cost_per_unit) const { try { initial_investment = GetEconParameter("capital_cost"); facility_lifetime = GetEconParameter("facility_depreciation_lifetime"); property_insurance_rate = GetEconParameter("property_insurance_rate"); - // Note: Since our fixed and variable costs are the same every timestep, we + // Note: Since our fixed costs are the same every timestep, we // call them levelized here. If that changes in the future, we need to - // change this to reflect actual levelization. Additionally, if more - // fixed and variable costs are added in the future, we need to change this - // to reflect that as well. + // change this to reflect actual levelization. Variable costs are provided + // directly as per-unit costs. levelized_fixed_costs = GetEconParameter("annual_fixed_costs"); - levelized_variable_costs = GetEconParameter("annual_variable_costs"); + variable_cost_per_unit = GetEconParameter("variable_cost_per_unit"); return true; } catch (const std::exception& e) { LOG(cyclus::LEV_INFO1, "GetFacilityEconParameters") @@ -135,12 +125,14 @@ bool GetFacilityEconParameters(double& initial_investment, /// @param bond_fraction Output parameter for fraction bond financing /// @param shareholder_rate Output parameter for share holders rate of return /// @param shareholder_fraction Output parameter for fraction private capital +/// @param discount_rate_override Output parameter for discount rate override /// @return true if successful, false otherwise bool GetInstitutionEconParameters(double& income_tax_rate, double& bond_rate, double& bond_fraction, double& shareholder_rate, - double& shareholder_fraction) const { + double& shareholder_fraction, + double& discount_rate_override) const { try { income_tax_rate = parent()->GetEconParameter("corporate_income_tax_rate"); bond_rate = parent()->GetEconParameter("bond_holders_rate_of_return"); @@ -149,6 +141,8 @@ bool GetInstitutionEconParameters(double& income_tax_rate, parent()->GetEconParameter("share_holders_rate_of_return"); shareholder_fraction = parent()->GetEconParameter("fraction_private_capital"); + discount_rate_override = + parent()->GetEconParameter("discount_rate_override"); return true; } catch (const std::exception& e) { LOG(cyclus::LEV_INFO1, "GetInstitutionEconParameters") @@ -159,16 +153,12 @@ bool GetInstitutionEconParameters(double& income_tax_rate, } /// @brief Retrieves region-level economic parameters -/// @param property_and_insurance_rate Output parameter for combined property -/// tax and insurance rate -/// @param property_insurance_rate Input parameter for property insurance rate +/// @param property_tax_rate Output parameter for property tax rate from region /// @return true if successful, false otherwise -bool GetRegionEconParameters(double& property_and_insurance_rate, - double property_insurance_rate) const { +bool GetRegionEconParameters(double& property_tax_rate) const { try { - double property_tax_rate = + property_tax_rate = parent()->parent()->GetEconParameter("property_tax_rate"); - property_and_insurance_rate = property_tax_rate + property_insurance_rate; return true; } catch (const std::exception& e) { LOG(cyclus::LEV_INFO1, "GetRegionEconParameters") @@ -189,14 +179,17 @@ double CalcUnitsProducedAnnually(double production_capacity) const { return production_capacity * timesteps_per_year; } -/// @brief Calculates the tax-modified rate of return +/// @brief Calculates the post tax weighted average cost of capital (WACC), also known as +/// tax-modified rate of return /// Formula: (1-τ)*r_b*f_b + r_s*f_s +/// This is the discount rate used in capital cost calculations. Can be overridden +/// by setting discount_rate_override > 0 at the institution level. /// @param income_tax_rate Corporate income tax rate /// @param bond_rate Bond holders rate of return /// @param bond_fraction Fraction of bond financing /// @param shareholder_rate Share holders rate of return /// @param shareholder_fraction Fraction of private capital -/// @return Tax-modified rate of return +/// @return Tax-modified rate of return (WACC) double CalcTaxModifiedRateOfReturn(double income_tax_rate, double bond_rate, double bond_fraction, @@ -249,6 +242,7 @@ double CalcCapitalCostPerUnit(double initial_investment, double depreciation_tax_shield = income_tax_rate / (1.0 - income_tax_rate) / facility_lifetime; + double capital_recovery_factor = PMT(facility_lifetime, tax_modified_rate_of_return, 1.0, 0.0) / (1.0 - income_tax_rate); @@ -277,12 +271,12 @@ double CalcMarginalCost(double variable_cost_per_unit, /// @brief Calculates the levelized unit cost of production, accounting for /// capital depreciation, fixed costs, variable costs, property taxes, and input costs. /// -/// unit_cost = cost_override if cost_override > 0, otherwise unit_cost = +/// unit_cost = cost_override + material_cost if cost_override > 0, otherwise unit_cost = /// production_cost + material_cost /// /// Where: /// - production_cost = levelized_fixed_costs/units_produced_annually + -/// levelized_variable_costs + (initial_investment/units_produced_annually) * +/// variable_cost_per_unit + (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))] @@ -290,22 +284,23 @@ double CalcMarginalCost(double variable_cost_per_unit, /// unit values) /// - units_produced_annually = production_capacity * timesteps_per_year /// - levelized_fixed_costs = annual_fixed_costs -/// - levelized_variable_costs = annual_variable_costs +/// - variable_cost_per_unit = variable_cost_per_unit (provided directly by user) /// - initial_investment = capital_cost /// - property_and_insurance_rate = property_tax_rate + property_insurance_rate -/// - tax_modified_rate_of_return = (1-income_tax_rate)*bond_rate*bond_fraction -/// + shareholder_rate*shareholder_fraction -/// - income_tax_rate = Income Tax Rate +/// - tax_modified_rate_of_return = WACC (weighted average cost of capital). +/// If discount_rate_override > 0 at institution level, uses that value. +/// Otherwise calculated as: (1-income_tax_rate)*bond_rate*bond_fraction + +/// shareholder_rate*shareholder_fraction +/// - income_tax_rate = Income Tax Rate (from institution) /// - facility_lifetime = facility_depreciation_lifetime /// /// The model assumes straight-line depreciation over the facility lifetime. /// /// @param production_capacity Maximum throughput per timestep -/// @param units_to_produce Number of units produced in the batch -/// @param input_cost (Optional) Total cost of input materials used in the batch +/// @param input_cost_per_unit (Optional) per-unit cost of input materials used in the batch /// @return Estimated levelized cost to produce one unit -double CalculateUnitCost(double production_capacity, double units_to_produce, +double CalculateUnitCost(double production_capacity, double input_cost_per_unit = 0.0) const { // Check if there's a cost override, and if so, use that if (cost_override > 0) { @@ -317,11 +312,11 @@ double CalculateUnitCost(double production_capacity, double units_to_produce, double facility_lifetime; double property_insurance_rate; double levelized_fixed_costs; - double levelized_variable_costs; + double variable_cost_per_unit; if (!GetFacilityEconParameters(initial_investment, facility_lifetime, property_insurance_rate, levelized_fixed_costs, - levelized_variable_costs)) { + variable_cost_per_unit)) { return kDefaultUnitCost; } @@ -331,24 +326,35 @@ double CalculateUnitCost(double production_capacity, double units_to_produce, double bond_fraction; double shareholder_rate; double shareholder_fraction; + double discount_rate_override; if (!GetInstitutionEconParameters(income_tax_rate, bond_rate, bond_fraction, - shareholder_rate, shareholder_fraction)) { + shareholder_rate, shareholder_fraction, + discount_rate_override)) { return kDefaultUnitCost; } // Get region-level parameters - double property_and_insurance_rate; - if (!GetRegionEconParameters(property_and_insurance_rate, - property_insurance_rate)) { + double property_tax_rate; + if (!GetRegionEconParameters(property_tax_rate)) { return kDefaultUnitCost; } + // Combine property tax (from region) and property insurance (from facility) + double property_and_insurance_rate = property_tax_rate + property_insurance_rate; + // Calculate intermediate values double units_produced_annually = CalcUnitsProducedAnnually(production_capacity); - double tax_modified_rate_of_return = CalcTaxModifiedRateOfReturn( - income_tax_rate, bond_rate, bond_fraction, shareholder_rate, - shareholder_fraction); + + // Use discount_rate_override if provided, otherwise calculate manually + double tax_modified_rate_of_return; + if (discount_rate_override > 0) { + tax_modified_rate_of_return = discount_rate_override; + } else { + tax_modified_rate_of_return = CalcTaxModifiedRateOfReturn( + income_tax_rate, bond_rate, bond_fraction, shareholder_rate, + shareholder_fraction); + } // Calculate cost components double fixed_cost_per_unit = @@ -360,7 +366,7 @@ double CalculateUnitCost(double production_capacity, double units_to_produce, // Assemble total unit cost - double production_cost = fixed_cost_per_unit + levelized_variable_costs + double production_cost = fixed_cost_per_unit + variable_cost_per_unit + capital_cost_per_unit; double unit_cost = production_cost + input_cost_per_unit; @@ -368,20 +374,18 @@ double CalculateUnitCost(double production_capacity, double units_to_produce, return unit_cost != 0 ? unit_cost : kDefaultUnitCost; } -double CalculateUnitPrice(double production_capacity, double units_to_produce, +double CalculateUnitPrice(double production_capacity, double input_cost_per_unit = 0.0) const { // Default implementation - return CalculateUnitCost(production_capacity, units_to_produce, - input_cost_per_unit); + return CalculateUnitCost(production_capacity, input_cost_per_unit); } // Required for compilation but not added by the cycpp preprocessor. Do not // remove. Must be one for each variable. std::vector cycpp_shape_capital_cost = {0}; -std::vector cycpp_shape_property_tax_rate = {0}; std::vector cycpp_shape_annual_fixed_costs = {0}; std::vector cycpp_shape_facility_operational_lifetime = {0}; std::vector cycpp_shape_facility_depreciation_lifetime = {0}; -std::vector cycpp_shape_annual_variable_costs = {0}; +std::vector cycpp_shape_variable_cost_per_unit = {0}; std::vector cycpp_shape_cost_override = {0}; std::vector cycpp_shape_property_insurance_rate = {0}; \ No newline at end of file diff --git a/src/toolkit/institution_cost.cycpp.h b/src/toolkit/institution_cost.cycpp.h index e908ac9a8c..a698ea8c17 100644 --- a/src/toolkit/institution_cost.cycpp.h +++ b/src/toolkit/institution_cost.cycpp.h @@ -69,6 +69,14 @@ double share_holders_rate_of_return; "units": "Dimensionless" \ } double fraction_private_capital; + +#pragma cyclus var { \ + "default": -1.0, \ + "uilabel": "Discount Rate Override", \ + "doc": "Optional discount rate (post-tax WACC) override. If > 0, this value overrides the calculated tax_modified_rate_of_return based on bond and shareholder rates of return. If 0, WACC is calculated from financing parameters. As decimal (1% --> 0.01)", \ + "units": "Dimensionless" \ + } +double discount_rate_override; // clang-format on // Must be done in a function so that we can access the user-defined values @@ -79,7 +87,8 @@ std::unordered_map GenerateParamList() const { {"bond_holders_rate_of_return", bond_holders_rate_of_return}, {"fraction_bond_financing", fraction_bond_financing}, {"share_holders_rate_of_return", share_holders_rate_of_return}, - {"fraction_private_capital", fraction_private_capital} + {"fraction_private_capital", fraction_private_capital}, + {"discount_rate_override", discount_rate_override} }; return econ_params; @@ -93,4 +102,5 @@ std::vector cycpp_shape_corporate_income_tax_rate = {0}; std::vector cycpp_shape_bond_holders_rate_of_return = {0}; std::vector cycpp_shape_fraction_bond_financing = {0}; std::vector cycpp_shape_share_holders_rate_of_return = {0}; -std::vector cycpp_shape_fraction_private_capital = {0}; \ No newline at end of file +std::vector cycpp_shape_fraction_private_capital = {0}; +std::vector cycpp_shape_discount_rate_override = {0}; \ No newline at end of file diff --git a/src/toolkit/region_cost.cycpp.h b/src/toolkit/region_cost.cycpp.h index 151548fdd6..c4a44dd48d 100644 --- a/src/toolkit/region_cost.cycpp.h +++ b/src/toolkit/region_cost.cycpp.h @@ -15,25 +15,26 @@ /// file with the other ones, reaplcing with the name you put /// in the econ_params array (again, must match exactly). + // clang-format off #pragma cyclus var { \ "default": 0.0, \ - "uilabel": "Corporate Income Tax Rate as decimal", \ + "uilabel": "Property Tax Rate as decimal", \ "range": [0.0, 1.0], \ - "doc": "Income Tax Rate for all facilities belonging to this region as decimal (1% --> 0.01)", \ + "doc": "Property tax rate for all facilities in this region as decimal (1% --> 0.01)", \ "units": "Dimensionless" \ } -double corporate_income_tax_rate; +double property_tax_rate; // clang-format on // Must be done in a function so that we can access the user-defined values std::unordered_map GenerateParamList() const { std::unordered_map econ_params{ - {"corporate_income_tax_rate", corporate_income_tax_rate}}; + {"property_tax_rate", property_tax_rate}}; return econ_params; } // Required for compilation but not added by the cycpp preprocessor. Do not // remove. Must be one for each variable. -std::vector cycpp_shape_corporate_income_tax_rate = {0}; \ No newline at end of file +std::vector cycpp_shape_property_tax_rate = {0}; \ No newline at end of file From a53b30a5e922766d3623b4307b106f6204737e8a Mon Sep 17 00:00:00 2001 From: Dean Krueger Date: Mon, 15 Dec 2025 14:14:44 -0600 Subject: [PATCH 03/28] reorganized and refined after a review. Made MC caclulation more central, changed how the validation of econ parameters worked, removed the idea of price since ultimately what we want is cost --- src/toolkit/facility_cost.cycpp.h | 231 ++++++++++++--------------- src/toolkit/institution_cost.cycpp.h | 11 -- 2 files changed, 103 insertions(+), 139 deletions(-) diff --git a/src/toolkit/facility_cost.cycpp.h b/src/toolkit/facility_cost.cycpp.h index 03d43e3dea..6b1c0c1aeb 100644 --- a/src/toolkit/facility_cost.cycpp.h +++ b/src/toolkit/facility_cost.cycpp.h @@ -29,12 +29,12 @@ double capital_cost; double annual_fixed_costs; #pragma cyclus var { \ - "default": 1.0, \ - "uilabel": "Estimated Useful lifetime of facility for economic purposes in years", \ - "doc": "Estimate on how long the facility will be active for economic purposes", \ - "units": "years" \ - } -double facility_operational_lifetime; + "default": 0.0, \ + "uilabel": "Variable Cost Per Unit", \ + "doc": "Variable cost per unit of production (labor, materials, etc. that vary with production)", \ + "units": "Unit of Currency/Unit of Production" \ + } +double variable_cost_per_unit; #pragma cyclus var { \ "default": 1.0, \ @@ -45,12 +45,12 @@ double facility_operational_lifetime; double facility_depreciation_lifetime; #pragma cyclus var { \ - "default": 0.0, \ - "uilabel": "Variable Cost Per Unit", \ - "doc": "Variable cost per unit of production (labor, materials, etc. that vary with production)", \ - "units": "Unit of Currency/Unit of Production" \ - } -double variable_cost_per_unit; + "default": 0.0, \ + "uilabel": "Property Insurance Rate as decimal", \ + "range": [0.0, 1.0], \ + "doc": "Property insurance rate for this facility as decimal (1% --> 0.01)" \ + } +double property_insurance_rate; #pragma cyclus var { \ "default": -1.0, \ @@ -59,14 +59,6 @@ double variable_cost_per_unit; "units": "unit of currency/unit of production (eg. $/kg)" \ } double cost_override; - -#pragma cyclus var { \ - "default": 0.0, \ - "uilabel": "Property Insurance Rate as decimal", \ - "range": [0.0, 1.0], \ - "doc": "Property insurance rate for this facility as decimal (1% --> 0.01)" \ - } -double property_insurance_rate; // clang-format on // Must be done in a function so that we can access the user-defined values @@ -74,101 +66,108 @@ std::unordered_map GenerateParamList() const override { std::unordered_map econ_params{ {"capital_cost", capital_cost}, {"annual_fixed_costs", annual_fixed_costs}, - {"facility_operational_lifetime", facility_operational_lifetime}, - {"facility_depreciation_lifetime", facility_depreciation_lifetime}, {"variable_cost_per_unit", variable_cost_per_unit}, - {"property_insurance_rate", property_insurance_rate}}; + {"facility_depreciation_lifetime", facility_depreciation_lifetime}, + {"property_insurance_rate", property_insurance_rate}, + {"cost_override", cost_override}}; return econ_params; } // ============================================================================= -// Economic Parameter Retrieval Functions +// Public API: Marginal Cost Calculation +// ============================================================================= + +/// @brief Calculates marginal cost per unit (variable + material, excluding +/// fixed and capital costs) +/// +/// Marginal cost represents the cost of producing one additional unit, +/// excluding fixed and capital costs which are sunk. This is the primary +/// function for facilities to use when submitting bids to the DRE for +/// surplus maximization. +/// +/// If cost_override > 0, returns cost_override + material_cost_per_unit. +/// Otherwise, returns variable_cost_per_unit + material_cost_per_unit. +/// +/// Example usage: +/// double MC = this->CalcMarginalCost(material_cost_per_unit); +/// // Use MC in bid to DRE +/// +/// @param material_cost_per_unit Per-unit cost of input materials +/// @return Marginal cost per unit, or material_cost_per_unit if facility parameters unavailable +double CalcMarginalCost(double material_cost_per_unit) const { + // Validate facility parameters are available + if (!ValidateFacilityEconParameters()) { + return material_cost_per_unit; + } + + // Get the values we need + double cost_override_val = GetEconParameter("cost_override"); + if (cost_override_val > 0) { + return cost_override_val + material_cost_per_unit; + } + + double variable_cost_per_unit = GetEconParameter("variable_cost_per_unit"); + return variable_cost_per_unit + material_cost_per_unit; +} + +// ============================================================================= +// Economic Parameter Validation Functions // ============================================================================= -/// @brief Retrieves facility-level economic parameters -/// @param initial_investment Output parameter for capital cost -/// @param facility_lifetime Output parameter for depreciation lifetime -/// @param property_insurance_rate Output parameter for property insurance rate -/// @param levelized_fixed_costs Output parameter for annual fixed costs -/// @param variable_cost_per_unit Output parameter for variable cost per unit -/// @return true if successful, false otherwise -bool GetFacilityEconParameters(double& initial_investment, - double& facility_lifetime, - double& property_insurance_rate, - double& levelized_fixed_costs, - double& variable_cost_per_unit) const { +/// @brief Validates that all required facility-level economic parameters exist +/// @return true if all parameters are available, false otherwise +bool ValidateFacilityEconParameters() const { try { - initial_investment = GetEconParameter("capital_cost"); - facility_lifetime = GetEconParameter("facility_depreciation_lifetime"); - property_insurance_rate = GetEconParameter("property_insurance_rate"); - - // Note: Since our fixed costs are the same every timestep, we - // call them levelized here. If that changes in the future, we need to - // change this to reflect actual levelization. Variable costs are provided - // directly as per-unit costs. - levelized_fixed_costs = - GetEconParameter("annual_fixed_costs"); - variable_cost_per_unit = GetEconParameter("variable_cost_per_unit"); + GetEconParameter("capital_cost"); + GetEconParameter("facility_depreciation_lifetime"); + GetEconParameter("property_insurance_rate"); + GetEconParameter("annual_fixed_costs"); + GetEconParameter("variable_cost_per_unit"); + GetEconParameter("cost_override"); return true; } catch (const std::exception& e) { - LOG(cyclus::LEV_INFO1, "GetFacilityEconParameters") + LOG(cyclus::LEV_INFO1, "ValidateFacilityEconParameters") << prototype() - << "failed to get facility financial_data_: " << e.what(); + << "failed to validate facility financial_data_: " << e.what(); return false; } } -/// @brief Retrieves institution-level economic parameters -/// @param income_tax_rate Output parameter for corporate income tax rate -/// @param bond_rate Output parameter for bond holders rate of return -/// @param bond_fraction Output parameter for fraction bond financing -/// @param shareholder_rate Output parameter for share holders rate of return -/// @param shareholder_fraction Output parameter for fraction private capital -/// @param discount_rate_override Output parameter for discount rate override -/// @return true if successful, false otherwise -bool GetInstitutionEconParameters(double& income_tax_rate, - double& bond_rate, - double& bond_fraction, - double& shareholder_rate, - double& shareholder_fraction, - double& discount_rate_override) const { +/// @brief Validates that all required institution-level economic parameters exist +/// @return true if all parameters are available, false otherwise +bool ValidateInstitutionEconParameters() const { try { - income_tax_rate = parent()->GetEconParameter("corporate_income_tax_rate"); - bond_rate = parent()->GetEconParameter("bond_holders_rate_of_return"); - bond_fraction = parent()->GetEconParameter("fraction_bond_financing"); - shareholder_rate = - parent()->GetEconParameter("share_holders_rate_of_return"); - shareholder_fraction = - parent()->GetEconParameter("fraction_private_capital"); - discount_rate_override = - parent()->GetEconParameter("discount_rate_override"); + parent()->GetEconParameter("corporate_income_tax_rate"); + parent()->GetEconParameter("bond_holders_rate_of_return"); + parent()->GetEconParameter("fraction_bond_financing"); + parent()->GetEconParameter("share_holders_rate_of_return"); + parent()->GetEconParameter("fraction_private_capital"); + parent()->GetEconParameter("discount_rate_override"); return true; } catch (const std::exception& e) { - LOG(cyclus::LEV_INFO1, "GetInstitutionEconParameters") + LOG(cyclus::LEV_INFO1, "ValidateInstitutionEconParameters") << prototype() - << "failed to get institution financial_data_: " << e.what(); + << "failed to validate institution financial_data_: " << e.what(); return false; } } -/// @brief Retrieves region-level economic parameters -/// @param property_tax_rate Output parameter for property tax rate from region -/// @return true if successful, false otherwise -bool GetRegionEconParameters(double& property_tax_rate) const { +/// @brief Validates that all required region-level economic parameters exist +/// @return true if all parameters are available, false otherwise +bool ValidateRegionEconParameters() const { try { - property_tax_rate = - parent()->parent()->GetEconParameter("property_tax_rate"); + parent()->parent()->GetEconParameter("property_tax_rate"); return true; } catch (const std::exception& e) { - LOG(cyclus::LEV_INFO1, "GetRegionEconParameters") - << prototype() << "failed to get region financial_data_: " << e.what(); + LOG(cyclus::LEV_INFO1, "ValidateRegionEconParameters") + << prototype() << "failed to validate region financial_data_: " << e.what(); return false; } } // ============================================================================= -// Cost Calculation Functions +// Internal Helper Functions (for CalculateUnitCost implementation) // ============================================================================= /// @brief Calculates the number of units produced annually @@ -252,20 +251,8 @@ double CalcCapitalCostPerUnit(double initial_investment, depreciation_tax_shield); } -/// @brief Calculates marginal cost per unit (variable + material, excluding -/// fixed and capital costs) -/// Marginal cost represents the cost of producing one additional unit, -/// excluding fixed and capital costs which are sunk. -/// @param variable_cost_per_unit Variable cost per unit -/// @param material_cost_per_unit Material cost per unit -/// @return Marginal cost per unit -double CalcMarginalCost(double variable_cost_per_unit, - double material_cost_per_unit) const { - return variable_cost_per_unit + material_cost_per_unit; -} - // ============================================================================= -// Main Cost Calculation Function +// Full Unit Cost Calculation Function // ============================================================================= /// @brief Calculates the levelized unit cost of production, accounting for @@ -307,37 +294,32 @@ double CalculateUnitCost(double production_capacity, return cost_override + input_cost_per_unit; } - // Get facility-level parameters - double initial_investment; - double facility_lifetime; - double property_insurance_rate; - double levelized_fixed_costs; - double variable_cost_per_unit; - if (!GetFacilityEconParameters(initial_investment, facility_lifetime, - property_insurance_rate, - levelized_fixed_costs, - variable_cost_per_unit)) { + // Validate and get facility-level parameters + if (!ValidateFacilityEconParameters()) { return kDefaultUnitCost; } - - // Get institution-level parameters - double income_tax_rate; - double bond_rate; - double bond_fraction; - double shareholder_rate; - double shareholder_fraction; - double discount_rate_override; - if (!GetInstitutionEconParameters(income_tax_rate, bond_rate, bond_fraction, - shareholder_rate, shareholder_fraction, - discount_rate_override)) { + double initial_investment = GetEconParameter("capital_cost"); + double facility_lifetime = GetEconParameter("facility_depreciation_lifetime"); + double property_insurance_rate = GetEconParameter("property_insurance_rate"); + double levelized_fixed_costs = GetEconParameter("annual_fixed_costs"); + double variable_cost_per_unit = GetEconParameter("variable_cost_per_unit"); + + // Validate and get institution-level parameters + if (!ValidateInstitutionEconParameters()) { return kDefaultUnitCost; } - - // Get region-level parameters - double property_tax_rate; - if (!GetRegionEconParameters(property_tax_rate)) { + double income_tax_rate = parent()->GetEconParameter("corporate_income_tax_rate"); + double bond_rate = parent()->GetEconParameter("bond_holders_rate_of_return"); + double bond_fraction = parent()->GetEconParameter("fraction_bond_financing"); + double shareholder_rate = parent()->GetEconParameter("share_holders_rate_of_return"); + double shareholder_fraction = parent()->GetEconParameter("fraction_private_capital"); + double discount_rate_override = parent()->GetEconParameter("discount_rate_override"); + + // Validate and get region-level parameters + if (!ValidateRegionEconParameters()) { return kDefaultUnitCost; } + double property_tax_rate = parent()->parent()->GetEconParameter("property_tax_rate"); // Combine property tax (from region) and property insurance (from facility) double property_and_insurance_rate = property_tax_rate + property_insurance_rate; @@ -374,17 +356,10 @@ double CalculateUnitCost(double production_capacity, return unit_cost != 0 ? unit_cost : kDefaultUnitCost; } -double CalculateUnitPrice(double production_capacity, - double input_cost_per_unit = 0.0) const { - // Default implementation - return CalculateUnitCost(production_capacity, input_cost_per_unit); -} - // Required for compilation but not added by the cycpp preprocessor. Do not // remove. Must be one for each variable. std::vector cycpp_shape_capital_cost = {0}; std::vector cycpp_shape_annual_fixed_costs = {0}; -std::vector cycpp_shape_facility_operational_lifetime = {0}; std::vector cycpp_shape_facility_depreciation_lifetime = {0}; std::vector cycpp_shape_variable_cost_per_unit = {0}; std::vector cycpp_shape_cost_override = {0}; diff --git a/src/toolkit/institution_cost.cycpp.h b/src/toolkit/institution_cost.cycpp.h index a698ea8c17..d6e6e76cd4 100644 --- a/src/toolkit/institution_cost.cycpp.h +++ b/src/toolkit/institution_cost.cycpp.h @@ -16,15 +16,6 @@ /// in the econ_params array (again, must match exactly). // clang-format off -#pragma cyclus var { \ - "default": 0.0, \ - "uilabel": "Minimum acceptable rate of return", \ - "range": [0.0, 1.0], \ - "doc": "Minimum acceptable rate of return for the institution", \ - "units": "Dimensionless" \ - } -double minimum_acceptable_return_rate; - #pragma cyclus var { \ "default": 0.0, \ "uilabel": "Corporate Income Tax Rate", \ @@ -82,7 +73,6 @@ double discount_rate_override; // Must be done in a function so that we can access the user-defined values std::unordered_map GenerateParamList() const { std::unordered_map econ_params { - {"minimum_acceptable_return_rate", minimum_acceptable_return_rate}, {"corporate_income_tax_rate", corporate_income_tax_rate}, {"bond_holders_rate_of_return", bond_holders_rate_of_return}, {"fraction_bond_financing", fraction_bond_financing}, @@ -97,7 +87,6 @@ std::unordered_map GenerateParamList() const { // Required for compilation but not added by the cycpp preprocessor. Do not // remove. Must be one for each variable. -std::vector cycpp_shape_minimum_acceptable_return_rate = {0}; std::vector cycpp_shape_corporate_income_tax_rate = {0}; std::vector cycpp_shape_bond_holders_rate_of_return = {0}; std::vector cycpp_shape_fraction_bond_financing = {0}; From 8c0aae722716c681605ef2bce9543a23ad2dbeaa Mon Sep 17 00:00:00 2001 From: Dean Krueger Date: Wed, 17 Dec 2025 11:41:49 -0600 Subject: [PATCH 04/28] moved a few of the one-liner functions to just variables in the single place they get used, deleted a few comments that didn't make sense, did another read through and checked for weird things --- src/toolkit/facility_cost.cycpp.h | 104 +++++++++++------------------- 1 file changed, 39 insertions(+), 65 deletions(-) diff --git a/src/toolkit/facility_cost.cycpp.h b/src/toolkit/facility_cost.cycpp.h index 6b1c0c1aeb..b20a89d801 100644 --- a/src/toolkit/facility_cost.cycpp.h +++ b/src/toolkit/facility_cost.cycpp.h @@ -55,7 +55,7 @@ double property_insurance_rate; #pragma cyclus var { \ "default": -1.0, \ "uilabel": "Non-material cost override in dollars of one unit of production", \ - "doc": "(optional) Hook to bypass LCP calculation and provide a cost in dollars. Should NOT include material costs, which are added later", \ + "doc": "(optional) Hook to bypass MC calculation and provide a direct cost. Should NOT include material costs, which are added later", \ "units": "unit of currency/unit of production (eg. $/kg)" \ } double cost_override; @@ -74,10 +74,6 @@ std::unordered_map GenerateParamList() const override { return econ_params; } -// ============================================================================= -// Public API: Marginal Cost Calculation -// ============================================================================= - /// @brief Calculates marginal cost per unit (variable + material, excluding /// fixed and capital costs) /// @@ -89,32 +85,24 @@ std::unordered_map GenerateParamList() const override { /// If cost_override > 0, returns cost_override + material_cost_per_unit. /// Otherwise, returns variable_cost_per_unit + material_cost_per_unit. /// -/// Example usage: -/// double MC = this->CalcMarginalCost(material_cost_per_unit); -/// // Use MC in bid to DRE -/// /// @param material_cost_per_unit Per-unit cost of input materials /// @return Marginal cost per unit, or material_cost_per_unit if facility parameters unavailable double CalcMarginalCost(double material_cost_per_unit) const { // Validate facility parameters are available if (!ValidateFacilityEconParameters()) { - return material_cost_per_unit; + return kDefaultUnitCost; } // Get the values we need - double cost_override_val = GetEconParameter("cost_override"); - if (cost_override_val > 0) { - return cost_override_val + material_cost_per_unit; + double cost_override = GetEconParameter("cost_override"); + if (cost_override > 0) { + return cost_override + material_cost_per_unit; } double variable_cost_per_unit = GetEconParameter("variable_cost_per_unit"); return variable_cost_per_unit + material_cost_per_unit; } -// ============================================================================= -// Economic Parameter Validation Functions -// ============================================================================= - /// @brief Validates that all required facility-level economic parameters exist /// @return true if all parameters are available, false otherwise bool ValidateFacilityEconParameters() const { @@ -166,23 +154,21 @@ bool ValidateRegionEconParameters() const { } } -// ============================================================================= -// Internal Helper Functions (for CalculateUnitCost implementation) -// ============================================================================= - -/// @brief Calculates the number of units produced annually -/// @param production_capacity Maximum throughput per timestep -/// @return Units produced annually -double CalcUnitsProducedAnnually(double production_capacity) const { - double timesteps_per_year = cyclusYear / context()->dt(); - return production_capacity * timesteps_per_year; -} - -/// @brief Calculates the post tax weighted average cost of capital (WACC), also known as +/// @brief Calculates the weighted average cost of capital (WACC), also known as /// tax-modified rate of return +/// +/// WACC represents the average rate a company is expected to pay to finance its +/// assets, accounting for the tax benefits of debt financing. This is the discount +/// rate used in capital cost calculations. +/// /// Formula: (1-τ)*r_b*f_b + r_s*f_s -/// This is the discount rate used in capital cost calculations. Can be overridden -/// by setting discount_rate_override > 0 at the institution level. +/// where: +/// - τ = income_tax_rate (corporate income tax rate) +/// - r_b = bond_rate (bond holders rate of return) +/// - f_b = bond_fraction (fraction of bond financing) +/// - r_s = shareholder_rate (share holders rate of return) +/// - f_s = shareholder_fraction (fraction of private capital) +/// /// @param income_tax_rate Corporate income tax rate /// @param bond_rate Bond holders rate of return /// @param bond_fraction Fraction of bond financing @@ -198,18 +184,6 @@ double CalcTaxModifiedRateOfReturn(double income_tax_rate, shareholder_rate * shareholder_fraction; } -/// @brief Calculates fixed cost per unit -/// @param levelized_fixed_costs Annual fixed costs -/// @param units_produced_annually Number of units produced per year -/// @return Fixed cost per unit -double CalcFixedCostPerUnit(double levelized_fixed_costs, - double units_produced_annually) const { - if (units_produced_annually == 0) { - return 0.0; - } - return levelized_fixed_costs / units_produced_annually; -} - /// @brief Calculates capital cost per unit /// Formula: (I_0/U) * [p + (1/(1-τ)) * PMT(N,x,1,0) - (1/N) * (τ/(1-τ))] /// where: @@ -232,13 +206,6 @@ double CalcCapitalCostPerUnit(double initial_investment, double income_tax_rate, double tax_modified_rate_of_return, double property_and_insurance_rate) const { - if (units_produced_annually == 0) { - return 0.0; - } - - double capital_investment_per_unit = - initial_investment / units_produced_annually; - double depreciation_tax_shield = income_tax_rate / (1.0 - income_tax_rate) / facility_lifetime; @@ -246,9 +213,19 @@ double CalcCapitalCostPerUnit(double initial_investment, PMT(facility_lifetime, tax_modified_rate_of_return, 1.0, 0.0) / (1.0 - income_tax_rate); - return capital_investment_per_unit * - (property_and_insurance_rate + capital_recovery_factor - - depreciation_tax_shield); + double annual_capital_cost_factor = + property_and_insurance_rate + capital_recovery_factor - + depreciation_tax_shield; + + // If no units produced, capital costs can't be amortized - use annual cost as limit + if (units_produced_annually == 0) { + return initial_investment * annual_capital_cost_factor; + } + + double capital_investment_per_unit = + initial_investment / units_produced_annually; + + return capital_investment_per_unit * annual_capital_cost_factor; } // ============================================================================= @@ -286,9 +263,8 @@ double CalcCapitalCostPerUnit(double initial_investment, /// @param production_capacity Maximum throughput per timestep /// @param input_cost_per_unit (Optional) per-unit cost of input materials used in the batch /// @return Estimated levelized cost to produce one unit - -double CalculateUnitCost(double production_capacity, - double input_cost_per_unit = 0.0) const { +double CalcUnitCost(double production_capacity, + double input_cost_per_unit = 0.0) const { // Check if there's a cost override, and if so, use that if (cost_override > 0) { return cost_override + input_cost_per_unit; @@ -325,10 +301,9 @@ double CalculateUnitCost(double production_capacity, double property_and_insurance_rate = property_tax_rate + property_insurance_rate; // Calculate intermediate values - double units_produced_annually = - CalcUnitsProducedAnnually(production_capacity); + double units_produced_annually = production_capacity * (cyclusYear / context()->dt()); - // Use discount_rate_override if provided, otherwise calculate manually + // Use discount_rate_override if provided, otherwise calculate WACC double tax_modified_rate_of_return; if (discount_rate_override > 0) { tax_modified_rate_of_return = discount_rate_override; @@ -339,21 +314,20 @@ double CalculateUnitCost(double production_capacity, } // Calculate cost components - double fixed_cost_per_unit = - CalcFixedCostPerUnit(levelized_fixed_costs, units_produced_annually); + // If no units produced, fixed costs can't be amortized - use total as limit + double fixed_cost_per_unit = (units_produced_annually == 0) ? levelized_fixed_costs : + levelized_fixed_costs / units_produced_annually; double capital_cost_per_unit = CalcCapitalCostPerUnit( initial_investment, units_produced_annually, facility_lifetime, income_tax_rate, tax_modified_rate_of_return, property_and_insurance_rate); - // Assemble total unit cost double production_cost = fixed_cost_per_unit + variable_cost_per_unit + capital_cost_per_unit; double unit_cost = production_cost + input_cost_per_unit; - // Protects against divide by zero in pref = 1/unit_cost - return unit_cost != 0 ? unit_cost : kDefaultUnitCost; + return unit_cost; } // Required for compilation but not added by the cycpp preprocessor. Do not From c4efc5f131720624aa16b0bb6dca7d9226cd1a15 Mon Sep 17 00:00:00 2001 From: Dean Krueger Date: Wed, 17 Dec 2025 12:00:55 -0600 Subject: [PATCH 05/28] changelog --- CHANGELOG.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c39efff0a9..75440c14e6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -34,7 +34,9 @@ Since last release * Allow multiple archetype blocks to facilitate includes (#1874) **Changed:** + * Made the Unit Tests far less verbose by suppressing log output during RunSim (#1927) +* Reworked the facility/instituion/region_cost.cycpp.h files to work with MC (#1931) * Changed Dockerfile to use boost and boost-cpp instead of libboost-devel (#1906) * Changed TradeExecutor to use adjusted preferences from ExchangeContext (#1897) * Ran clang-format on src directory (#1881, #1893) From e44e5fcc134210d068fd94592e967a54e3714539 Mon Sep 17 00:00:00 2001 From: Dean Krueger Date: Sun, 4 Jan 2026 10:20:20 -0600 Subject: [PATCH 06/28] removed extra code for calculating the fixed and capital costs of production, etc. Redid the MC function to have a few catches in it and otherwise return some values that will make it play nicely --- src/toolkit/facility_cost.cycpp.h | 307 ++---------------------------- 1 file changed, 18 insertions(+), 289 deletions(-) diff --git a/src/toolkit/facility_cost.cycpp.h b/src/toolkit/facility_cost.cycpp.h index b20a89d801..cf3e962528 100644 --- a/src/toolkit/facility_cost.cycpp.h +++ b/src/toolkit/facility_cost.cycpp.h @@ -16,325 +16,54 @@ /// in the econ_params array (again, must match exactly). // clang-format off -#pragma cyclus var {"default" : 0.0, \ - "uilabel" : "Capital cost required to build facility", \ - "doc" : "Total overnight capital cost required to build facility", \ - "units" : "Unit of Currency" } -double capital_cost; - -#pragma cyclus var { \ - "default" : 0.0, "uilabel" : "Annual Fixed Costs", \ - "doc" : "Annual fixed costs (operations, maintenance, etc., excluding property tax and insurance) required to run facility", \ - "units" : "Unit of Currency/year" } -double annual_fixed_costs; - #pragma cyclus var { \ "default": 0.0, \ "uilabel": "Variable Cost Per Unit", \ - "doc": "Variable cost per unit of production (labor, materials, etc. that vary with production)", \ + "doc": "Variable cost per unit of production (labor, materials, etc.). " \ + "The data from the Cost Basis Report represents a variable cost per " \ + "unit and can be used here.", \ "units": "Unit of Currency/Unit of Production" \ } double variable_cost_per_unit; - -#pragma cyclus var { \ - "default": 1.0, \ - "uilabel": "Taxable lifetime of facility for economic purposes in years", \ - "doc": "How long the facility will be depreciating their initial investment", \ - "units": "years" \ - } -double facility_depreciation_lifetime; - -#pragma cyclus var { \ - "default": 0.0, \ - "uilabel": "Property Insurance Rate as decimal", \ - "range": [0.0, 1.0], \ - "doc": "Property insurance rate for this facility as decimal (1% --> 0.01)" \ - } -double property_insurance_rate; - -#pragma cyclus var { \ - "default": -1.0, \ - "uilabel": "Non-material cost override in dollars of one unit of production", \ - "doc": "(optional) Hook to bypass MC calculation and provide a direct cost. Should NOT include material costs, which are added later", \ - "units": "unit of currency/unit of production (eg. $/kg)" \ - } -double cost_override; // clang-format on // Must be done in a function so that we can access the user-defined values std::unordered_map GenerateParamList() const override { std::unordered_map econ_params{ - {"capital_cost", capital_cost}, - {"annual_fixed_costs", annual_fixed_costs}, - {"variable_cost_per_unit", variable_cost_per_unit}, - {"facility_depreciation_lifetime", facility_depreciation_lifetime}, - {"property_insurance_rate", property_insurance_rate}, - {"cost_override", cost_override}}; + {"variable_cost_per_unit", variable_cost_per_unit}}; return econ_params; } -/// @brief Calculates marginal cost per unit (variable + material, excluding -/// fixed and capital costs) -/// -/// Marginal cost represents the cost of producing one additional unit, -/// excluding fixed and capital costs which are sunk. This is the primary -/// function for facilities to use when submitting bids to the DRE for -/// surplus maximization. -/// -/// If cost_override > 0, returns cost_override + material_cost_per_unit. -/// Otherwise, returns variable_cost_per_unit + material_cost_per_unit. +/// @brief Returns the sum of the variable cost per unit and the material cost +/// per unit if available, and the default unit cost of kDefaultUnitCost if not. /// /// @param material_cost_per_unit Per-unit cost of input materials -/// @return Marginal cost per unit, or material_cost_per_unit if facility parameters unavailable +/// @return Sum of variable cost per unit and material cost per unit, or +/// kDefaultUnitCost if not available double CalcMarginalCost(double material_cost_per_unit) const { - // Validate facility parameters are available - if (!ValidateFacilityEconParameters()) { - return kDefaultUnitCost; - } - - // Get the values we need - double cost_override = GetEconParameter("cost_override"); - if (cost_override > 0) { - return cost_override + material_cost_per_unit; - } + double variable_cost_per_unit; - double variable_cost_per_unit = GetEconParameter("variable_cost_per_unit"); - return variable_cost_per_unit + material_cost_per_unit; -} - -/// @brief Validates that all required facility-level economic parameters exist -/// @return true if all parameters are available, false otherwise -bool ValidateFacilityEconParameters() const { try { - GetEconParameter("capital_cost"); - GetEconParameter("facility_depreciation_lifetime"); - GetEconParameter("property_insurance_rate"); - GetEconParameter("annual_fixed_costs"); - GetEconParameter("variable_cost_per_unit"); - GetEconParameter("cost_override"); - return true; + variable_cost_per_unit = GetEconParameter("variable_cost_per_unit"); } catch (const std::exception& e) { LOG(cyclus::LEV_INFO1, "ValidateFacilityEconParameters") << prototype() - << "failed to validate facility financial_data_: " << e.what(); - return false; - } -} - -/// @brief Validates that all required institution-level economic parameters exist -/// @return true if all parameters are available, false otherwise -bool ValidateInstitutionEconParameters() const { - try { - parent()->GetEconParameter("corporate_income_tax_rate"); - parent()->GetEconParameter("bond_holders_rate_of_return"); - parent()->GetEconParameter("fraction_bond_financing"); - parent()->GetEconParameter("share_holders_rate_of_return"); - parent()->GetEconParameter("fraction_private_capital"); - parent()->GetEconParameter("discount_rate_override"); - return true; - } catch (const std::exception& e) { - LOG(cyclus::LEV_INFO1, "ValidateInstitutionEconParameters") - << prototype() - << "failed to validate institution financial_data_: " << e.what(); - return false; - } -} - -/// @brief Validates that all required region-level economic parameters exist -/// @return true if all parameters are available, false otherwise -bool ValidateRegionEconParameters() const { - try { - parent()->parent()->GetEconParameter("property_tax_rate"); - return true; - } catch (const std::exception& e) { - LOG(cyclus::LEV_INFO1, "ValidateRegionEconParameters") - << prototype() << "failed to validate region financial_data_: " << e.what(); - return false; - } -} - -/// @brief Calculates the weighted average cost of capital (WACC), also known as -/// tax-modified rate of return -/// -/// WACC represents the average rate a company is expected to pay to finance its -/// assets, accounting for the tax benefits of debt financing. This is the discount -/// rate used in capital cost calculations. -/// -/// Formula: (1-τ)*r_b*f_b + r_s*f_s -/// where: -/// - τ = income_tax_rate (corporate income tax rate) -/// - r_b = bond_rate (bond holders rate of return) -/// - f_b = bond_fraction (fraction of bond financing) -/// - r_s = shareholder_rate (share holders rate of return) -/// - f_s = shareholder_fraction (fraction of private capital) -/// -/// @param income_tax_rate Corporate income tax rate -/// @param bond_rate Bond holders rate of return -/// @param bond_fraction Fraction of bond financing -/// @param shareholder_rate Share holders rate of return -/// @param shareholder_fraction Fraction of private capital -/// @return Tax-modified rate of return (WACC) -double CalcTaxModifiedRateOfReturn(double income_tax_rate, - double bond_rate, - double bond_fraction, - double shareholder_rate, - double shareholder_fraction) const { - return (1 - income_tax_rate) * bond_rate * bond_fraction + - shareholder_rate * shareholder_fraction; -} - -/// @brief Calculates capital cost per unit -/// Formula: (I_0/U) * [p + (1/(1-τ)) * PMT(N,x,1,0) - (1/N) * (τ/(1-τ))] -/// where: -/// - I_0 = initial investment -/// - U = units produced annually -/// - p = property and insurance rate -/// - τ = income tax rate -/// - N = facility lifetime -/// - x = tax-modified rate of return -/// @param initial_investment Capital cost -/// @param units_produced_annually Number of units produced per year -/// @param facility_lifetime Facility depreciation lifetime in years -/// @param income_tax_rate Corporate income tax rate -/// @param tax_modified_rate_of_return Tax-modified rate of return -/// @param property_and_insurance_rate Combined property tax and insurance rate -/// @return Capital cost per unit -double CalcCapitalCostPerUnit(double initial_investment, - double units_produced_annually, - double facility_lifetime, - double income_tax_rate, - double tax_modified_rate_of_return, - double property_and_insurance_rate) const { - double depreciation_tax_shield = - income_tax_rate / (1.0 - income_tax_rate) / facility_lifetime; - - double capital_recovery_factor = - PMT(facility_lifetime, tax_modified_rate_of_return, 1.0, 0.0) / - (1.0 - income_tax_rate); - - double annual_capital_cost_factor = - property_and_insurance_rate + capital_recovery_factor - - depreciation_tax_shield; - - // If no units produced, capital costs can't be amortized - use annual cost as limit - if (units_produced_annually == 0) { - return initial_investment * annual_capital_cost_factor; - } - - double capital_investment_per_unit = - initial_investment / units_produced_annually; - - return capital_investment_per_unit * annual_capital_cost_factor; -} - -// ============================================================================= -// Full Unit Cost Calculation Function -// ============================================================================= - -/// @brief Calculates the levelized unit cost of production, accounting for -/// capital depreciation, fixed costs, variable costs, property taxes, and input costs. -/// -/// unit_cost = cost_override + material_cost if cost_override > 0, otherwise unit_cost = -/// production_cost + material_cost -/// -/// Where: -/// - production_cost = levelized_fixed_costs/units_produced_annually + -/// variable_cost_per_unit + (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))] -/// - material_cost = Unit Cost of Material (weighted average of input material -/// unit values) -/// - units_produced_annually = production_capacity * timesteps_per_year -/// - levelized_fixed_costs = annual_fixed_costs -/// - variable_cost_per_unit = variable_cost_per_unit (provided directly by user) -/// - initial_investment = capital_cost -/// - property_and_insurance_rate = property_tax_rate + property_insurance_rate -/// - tax_modified_rate_of_return = WACC (weighted average cost of capital). -/// If discount_rate_override > 0 at institution level, uses that value. -/// Otherwise calculated as: (1-income_tax_rate)*bond_rate*bond_fraction + -/// shareholder_rate*shareholder_fraction -/// - income_tax_rate = Income Tax Rate (from institution) -/// - facility_lifetime = facility_depreciation_lifetime -/// -/// The model assumes straight-line depreciation over the facility lifetime. -/// -/// @param production_capacity Maximum throughput per timestep -/// @param input_cost_per_unit (Optional) per-unit cost of input materials used in the batch -/// @return Estimated levelized cost to produce one unit -double CalcUnitCost(double production_capacity, - double input_cost_per_unit = 0.0) const { - // Check if there's a cost override, and if so, use that - if (cost_override > 0) { - return cost_override + input_cost_per_unit; - } - - // Validate and get facility-level parameters - if (!ValidateFacilityEconParameters()) { - return kDefaultUnitCost; - } - double initial_investment = GetEconParameter("capital_cost"); - double facility_lifetime = GetEconParameter("facility_depreciation_lifetime"); - double property_insurance_rate = GetEconParameter("property_insurance_rate"); - double levelized_fixed_costs = GetEconParameter("annual_fixed_costs"); - double variable_cost_per_unit = GetEconParameter("variable_cost_per_unit"); - - // Validate and get institution-level parameters - if (!ValidateInstitutionEconParameters()) { + << "failed to get variable cost per unit: " << e.what(); return kDefaultUnitCost; } - double income_tax_rate = parent()->GetEconParameter("corporate_income_tax_rate"); - double bond_rate = parent()->GetEconParameter("bond_holders_rate_of_return"); - double bond_fraction = parent()->GetEconParameter("fraction_bond_financing"); - double shareholder_rate = parent()->GetEconParameter("share_holders_rate_of_return"); - double shareholder_fraction = parent()->GetEconParameter("fraction_private_capital"); - double discount_rate_override = parent()->GetEconParameter("discount_rate_override"); - // Validate and get region-level parameters - if (!ValidateRegionEconParameters()) { - return kDefaultUnitCost; - } - double property_tax_rate = parent()->parent()->GetEconParameter("property_tax_rate"); - - // Combine property tax (from region) and property insurance (from facility) - double property_and_insurance_rate = property_tax_rate + property_insurance_rate; - - // Calculate intermediate values - double units_produced_annually = production_capacity * (cyclusYear / context()->dt()); - - // Use discount_rate_override if provided, otherwise calculate WACC - double tax_modified_rate_of_return; - if (discount_rate_override > 0) { - tax_modified_rate_of_return = discount_rate_override; - } else { - tax_modified_rate_of_return = CalcTaxModifiedRateOfReturn( - income_tax_rate, bond_rate, bond_fraction, shareholder_rate, - shareholder_fraction); + if (variable_cost_per_unit <= cyclus::eps()) { + LOG(cyclus::LEV_WARN, "CalcMarginalCost") + << prototype() + << "has a very low (" << variable_cost_per_unit << ") variable cost per unit!"; } - // Calculate cost components - // If no units produced, fixed costs can't be amortized - use total as limit - double fixed_cost_per_unit = (units_produced_annually == 0) ? levelized_fixed_costs : - levelized_fixed_costs / units_produced_annually; - double capital_cost_per_unit = CalcCapitalCostPerUnit( - initial_investment, units_produced_annually, facility_lifetime, - income_tax_rate, tax_modified_rate_of_return, - property_and_insurance_rate); + return variable_cost_per_unit + material_cost_per_unit; +} - // Assemble total unit cost - double production_cost = fixed_cost_per_unit + variable_cost_per_unit - + capital_cost_per_unit; - double unit_cost = production_cost + input_cost_per_unit; - return unit_cost; -} // Required for compilation but not added by the cycpp preprocessor. Do not // remove. Must be one for each variable. -std::vector cycpp_shape_capital_cost = {0}; -std::vector cycpp_shape_annual_fixed_costs = {0}; -std::vector cycpp_shape_facility_depreciation_lifetime = {0}; -std::vector cycpp_shape_variable_cost_per_unit = {0}; -std::vector cycpp_shape_cost_override = {0}; -std::vector cycpp_shape_property_insurance_rate = {0}; \ No newline at end of file +std::vector cycpp_shape_variable_cost_per_unit = {0}; \ No newline at end of file From 0b2fee3a693b35a0fdb243287c4e93a8adb46b53 Mon Sep 17 00:00:00 2001 From: Dean Krueger Date: Sun, 4 Jan 2026 10:21:04 -0600 Subject: [PATCH 07/28] renamed facility_cost to marginal_cost, since that's more the direction we're going with this now. --- src/toolkit/{facility_cost.cycpp.h => marginal_cost.cycpp.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/toolkit/{facility_cost.cycpp.h => marginal_cost.cycpp.h} (100%) diff --git a/src/toolkit/facility_cost.cycpp.h b/src/toolkit/marginal_cost.cycpp.h similarity index 100% rename from src/toolkit/facility_cost.cycpp.h rename to src/toolkit/marginal_cost.cycpp.h From f0793a295ca347dca7b578b5944736247bd75bd9 Mon Sep 17 00:00:00 2001 From: Dean Krueger Date: Sun, 4 Jan 2026 10:22:41 -0600 Subject: [PATCH 08/28] removed institution and region cost files since they no longer do anything. --- src/toolkit/institution_cost.cycpp.h | 95 ---------------------------- src/toolkit/region_cost.cycpp.h | 40 ------------ 2 files changed, 135 deletions(-) delete mode 100644 src/toolkit/institution_cost.cycpp.h delete mode 100644 src/toolkit/region_cost.cycpp.h diff --git a/src/toolkit/institution_cost.cycpp.h b/src/toolkit/institution_cost.cycpp.h deleted file mode 100644 index d6e6e76cd4..0000000000 --- a/src/toolkit/institution_cost.cycpp.h +++ /dev/null @@ -1,95 +0,0 @@ -/// This includes the required header to add institution costs to archetypes. -/// One should only need to: -/// - '#include "toolkit/institution_cost.cycpp.h"' in the header of the -/// archetype class (as private) -/// - Add `InitEconParameters()` to `EnterNotify()` in the cc file of the -/// archetype class. - -/// How to add parameters to this file: -/// 1. Add the pragma. A default value MUST be added to ensure backwards -/// compatibility. -/// 2. Edit the unordered_map called "econ_params" -/// i. add the desired parameter to the array {"name", value} -/// ii. the value of the pair should be the variable name exactly -/// 3. Add "std::vector cycpp_shape_ = {0};" to the end of the -/// file with the other ones, reaplcing with the name you put -/// in the econ_params array (again, must match exactly). - -// clang-format off -#pragma cyclus var { \ - "default": 0.0, \ - "uilabel": "Corporate Income Tax Rate", \ - "range": [0.0, 1.0], \ - "doc": "Corporate income tax rate as decimal (1% --> 0.01)", \ - "units": "Dimensionless" \ - } -double corporate_income_tax_rate; - -#pragma cyclus var { \ - "default": 0.0, \ - "uilabel": "Bond-holder's Expected Rate of Return", \ - "range": [0.0, 1.0], \ - "doc": "Expected rate of return for bond holders as decimal (1% --> 0.01)", \ - "units": "Dimensionless" \ - } -double bond_holders_rate_of_return; - -#pragma cyclus var { \ - "default": 0.0, \ - "uilabel": "Fraction of Initial Investment from Bonds", \ - "range": [0.0, 1.0], \ - "doc": "Fraction of initial investment financed through bonds as decimal (1% --> 0.01)", \ - "units": "Dimensionless" \ - } -double fraction_bond_financing; - -#pragma cyclus var { \ - "default": 0.0, \ - "uilabel": "Share-holder's Expected Rate of Return", \ - "range": [0.0, 1.0], \ - "doc": "Expected rate of return for share holders as decimal (1% --> 0.01)", \ - "units": "Dimensionless" \ - } -double share_holders_rate_of_return; - -#pragma cyclus var { \ - "default": 0.0, \ - "uilabel": "Fraction of Initial Investment from Private Capital", \ - "range": [0.0, 1.0], \ - "doc": "Fraction of initial investment financed through private capital as decimal (1% --> 0.01)", \ - "units": "Dimensionless" \ - } -double fraction_private_capital; - -#pragma cyclus var { \ - "default": -1.0, \ - "uilabel": "Discount Rate Override", \ - "doc": "Optional discount rate (post-tax WACC) override. If > 0, this value overrides the calculated tax_modified_rate_of_return based on bond and shareholder rates of return. If 0, WACC is calculated from financing parameters. As decimal (1% --> 0.01)", \ - "units": "Dimensionless" \ - } -double discount_rate_override; -// clang-format on - -// Must be done in a function so that we can access the user-defined values -std::unordered_map GenerateParamList() const { - std::unordered_map econ_params { - {"corporate_income_tax_rate", corporate_income_tax_rate}, - {"bond_holders_rate_of_return", bond_holders_rate_of_return}, - {"fraction_bond_financing", fraction_bond_financing}, - {"share_holders_rate_of_return", share_holders_rate_of_return}, - {"fraction_private_capital", fraction_private_capital}, - {"discount_rate_override", discount_rate_override} - }; - - return econ_params; -} - - -// Required for compilation but not added by the cycpp preprocessor. Do not -// remove. Must be one for each variable. -std::vector cycpp_shape_corporate_income_tax_rate = {0}; -std::vector cycpp_shape_bond_holders_rate_of_return = {0}; -std::vector cycpp_shape_fraction_bond_financing = {0}; -std::vector cycpp_shape_share_holders_rate_of_return = {0}; -std::vector cycpp_shape_fraction_private_capital = {0}; -std::vector cycpp_shape_discount_rate_override = {0}; \ No newline at end of file diff --git a/src/toolkit/region_cost.cycpp.h b/src/toolkit/region_cost.cycpp.h deleted file mode 100644 index c4a44dd48d..0000000000 --- a/src/toolkit/region_cost.cycpp.h +++ /dev/null @@ -1,40 +0,0 @@ -/// This includes the required header to add regional costs to archetypes. -/// One should only need to: -/// - '#include "toolkit/region_cost.cycpp.h"' in the header of the -/// archetype class (as private) -/// - Add `InitEconParameters()` to `EnterNotify()` in the cc file of the -/// archetype class. - -/// How to add parameters to this file: -/// 1. Add the pragma. A default value MUST be added to ensure backwards -/// compatibility. -/// 2. Edit the unordered_map called "econ_params" -/// i. add the desired parameter to the array {"name", value} -/// ii. the value of the pair should be the variable name exactly -/// 3. Add "std::vector cycpp_shape_ = {0};" to the end of the -/// file with the other ones, reaplcing with the name you put -/// in the econ_params array (again, must match exactly). - - -// clang-format off -#pragma cyclus var { \ - "default": 0.0, \ - "uilabel": "Property Tax Rate as decimal", \ - "range": [0.0, 1.0], \ - "doc": "Property tax rate for all facilities in this region as decimal (1% --> 0.01)", \ - "units": "Dimensionless" \ - } -double property_tax_rate; -// clang-format on - -// Must be done in a function so that we can access the user-defined values -std::unordered_map GenerateParamList() const { - std::unordered_map econ_params{ - {"property_tax_rate", property_tax_rate}}; - - return econ_params; -} - -// Required for compilation but not added by the cycpp preprocessor. Do not -// remove. Must be one for each variable. -std::vector cycpp_shape_property_tax_rate = {0}; \ No newline at end of file From 32dbe028cf8c50aa199ad7841cc1e5034d83452f Mon Sep 17 00:00:00 2001 From: Dean Krueger Date: Sun, 4 Jan 2026 11:47:53 -0600 Subject: [PATCH 09/28] removed region_cost.cycpp.h call from null_region, fixed an inconsistency in the comment at the top of the marginal_cost.cycpp.h header file --- agents/null_region.cc | 4 +--- agents/null_region.h | 3 --- src/toolkit/marginal_cost.cycpp.h | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/agents/null_region.cc b/agents/null_region.cc index 055f90aefd..da1f5762c4 100644 --- a/agents/null_region.cc +++ b/agents/null_region.cc @@ -6,9 +6,7 @@ NullRegion::NullRegion(cyclus::Context* ctx) : cyclus::Region(ctx) {} NullRegion::~NullRegion() {} -void NullRegion::EnterNotify() { - InitEconParameters(); -} +void NullRegion::EnterNotify() {} extern "C" cyclus::Agent* ConstructNullRegion(cyclus::Context* ctx) { return new NullRegion(ctx); diff --git a/agents/null_region.h b/agents/null_region.h index eec1efb479..49964ef5b2 100644 --- a/agents/null_region.h +++ b/agents/null_region.h @@ -22,9 +22,6 @@ class NullRegion : public cyclus::Region { "institutions but exhibits null behavior. " \ "No parameters are given when using the " \ "null region."} - - private: - #include "toolkit/region_cost.cycpp.h" }; } // namespace cyclus diff --git a/src/toolkit/marginal_cost.cycpp.h b/src/toolkit/marginal_cost.cycpp.h index cf3e962528..2e76a5c100 100644 --- a/src/toolkit/marginal_cost.cycpp.h +++ b/src/toolkit/marginal_cost.cycpp.h @@ -1,6 +1,6 @@ /// This includes the required header to add facility costs to archetypes. /// One should only need to: -/// - '#include "toolkit/facility_cost.cycpp.h"' in the header of the +/// - '#include "toolkit/marginal_cost.cycpp.h"' in the header of the /// archetype class (as private) /// - Add `InitEconParameters()` to `EnterNotify()` in the cc file of the /// archetype class. From 1b2a1e3b6512072539e9bb34aaf0ea26705ee097 Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Mon, 16 Feb 2026 10:32:08 -0800 Subject: [PATCH 10/28] changes to allow discrete event timing based on dynamic timeline updates --- src/context.h | 13 ++++++++++++- src/resource_exchange.h | 23 +++++++++++++++++++---- src/timer.cc | 39 ++++++++++++++++++++++++++++++++------- src/timer.h | 8 +++++++- src/trader.h | 2 ++ 5 files changed, 72 insertions(+), 13 deletions(-) diff --git a/src/context.h b/src/context.h index 0e5b925de4..ee93bc1dd4 100644 --- a/src/context.h +++ b/src/context.h @@ -19,6 +19,7 @@ #include "pyhooks.h" #include "recorder.h" #include "package.h" +//#include "timer.h" MEG // Defined as 4 seconds longer than a Gaussian year (to make division by 12 // a round number) @@ -183,6 +184,16 @@ class Context { /// @return the current set of traders registered for resource exchange. inline const std::set& traders() const { return traders_; } + inline void RegisterRequesters(std::pair e) {request_queue_[e.first].insert(e.second); } + + inline const std::map>& EventRequesters() const { return request_queue_; } + + inline void Populate(int next_event) {request_queue_[next_event] = traders(); } + + int time_; + inline void GetTime(int t) {time_ = t;} + + //inline const std::set& GetRequesterEvent() {return request_queue_[ti_->time()]; } /// Create a new agent by cloning the named prototype. The returned agent is /// not initialized as a simulation participant. /// @@ -364,13 +375,13 @@ class Context { /// contains archetype specs of all agents for which version have already /// been recorded in the db std::set rec_ver_; - std::map protos_; std::map recipes_; std::map packages_; std::map transport_units_; std::set agent_list_; std::set traders_; + std::map> request_queue_; std::map n_prototypes_; std::map n_specs_; diff --git a/src/resource_exchange.h b/src/resource_exchange.h index 2b73e0675f..8f8febe706 100644 --- a/src/resource_exchange.h +++ b/src/resource_exchange.h @@ -68,9 +68,11 @@ template class ResourceExchange { /// @brief queries traders and collects all requests for bids void AddAllRequests() { - InitTraders(); - std::for_each(traders_.begin(), - traders_.end(), + std::cout << sim_ctx_ ->time_ << "\n"; + + InitRequesters(); + std::for_each(requesters_.begin(), + requesters_.end(), std::bind(&cyclus::ResourceExchange::AddRequests_, this, std::placeholders::_1)); @@ -111,6 +113,19 @@ template class ResourceExchange { } } } +// MEG HAVE TO FIX THIS LINe SO THAT WE GET THE CORRECT ELEMMENT IN The MAP + void InitRequesters() { + //std::set orig = sim_ctx_->EventRequesters()[sim_ctx_->time_]; + if (requesters_.size() == 0) { + auto map = sim_ctx_->EventRequesters(); + std::set orig = map[sim_ctx_->time_]; + std::set::iterator it; + for (it = orig.begin(); it != orig.end(); ++it) { + requesters_.insert(*it); + } + } + //requesters_.insert(req_vec.begin(),req_vec.end()); + } /// @brief queries a given facility agent for void AddRequests_(Trader* t) { @@ -160,7 +175,7 @@ template class ResourceExchange { // determinism of Cyclus overall. This allows all traders' resource // exchange functions are called in a much closer to deterministic order. std::set traders_; - + std::set requesters_; Context* sim_ctx_; ExchangeContext ex_ctx_; }; diff --git a/src/timer.cc b/src/timer.cc index 86ae859de5..377bdcfa99 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -29,9 +29,8 @@ void Timer::RunSim() { ExchangeManager matl_manager(ctx_); ExchangeManager genrsrc_manager(ctx_); - while (time_ < si_.duration) { + while ( (time_ < si_.duration) && (prev_time_ != time_)) { CLOG(LEV_INFO1) << "Current time: " << time_; - if (want_snapshot_) { want_snapshot_ = false; SimInit::Snapshot(ctx_); @@ -48,13 +47,15 @@ void Timer::RunSim() { CLOG(LEV_INFO2) << "Beginning Decision for time: " << time_; DoDecision(); DoDecom(); + DoLookAhead(); #ifdef CYCLUS_WITH_PYTHON EventLoop(); #endif - - time_++; - + prev_time_ = time_; + time_ = NextEvent(); + ctx_->GetTime(time_); + if (want_kill_) { break; } @@ -113,6 +114,7 @@ void Timer::DoTock() { } #pragma omp parallel for +// change this so that it is just for (size_t i = 0; i < cpp_tickers_.size(); ++i) { cpp_tickers_[i]->Tock(); } @@ -198,7 +200,7 @@ void Timer::DoDecom() { m->Decommission(); } } - +// I want this to go every time event void Timer::RegisterTimeListener(TimeListener* agent) { tickers_[agent->id()] = agent; if (agent->IsShim()) { @@ -220,6 +222,26 @@ void Timer::UnregisterTimeListener(TimeListener* tl) { } } +void Timer::DoLookAhead() { + std::set all_traders = ctx_->traders(); + for(Trader* m : all_traders){ + m->EventRequest(); + }; + auto reg_traders = ctx_->EventRequesters(); + if(reg_traders.count(time_+1) == 0){ + ctx_->Populate(NextEvent()); + }; +} + +int Timer::NextEvent(){ + auto reg_traders = ctx_->EventRequesters(); + int t_p = time_ + 1; // time plus +1 + std::vector event_lists = {build_queue_.upper_bound(t_p)->first, + decom_queue_.upper_bound(t_p)->first, + reg_traders.upper_bound(t_p)->first}; + return *std::min_element(event_lists.begin(), event_lists.end()); +} + void Timer::SchedBuild(Agent* parent, std::string proto_name, int t) { if (t <= time_) { throw ValueError("Cannot schedule build for t < [current-time]"); @@ -276,12 +298,15 @@ void Timer::Initialize(Context* ctx, SimInfo si) { if (si.m0 < 1 || si.m0 > 12) { throw ValueError("Invalid month0; must be between 1 and 12 (inclusive)."); } - + prev_time_ = -1; want_kill_ = false; ctx_ = ctx; time_ = 0; si_ = si; + + //ctx_->Populate(0); + //std::cout << (ctx_->EventRequesters())[0].size(); if (si.branch_time > -1) { time_ = si.branch_time; } diff --git a/src/timer.h b/src/timer.h index 43eadd323b..9834e9dc90 100644 --- a/src/timer.h +++ b/src/timer.h @@ -50,6 +50,10 @@ class Timer { /// Agents should unregister from their Decommission method. void UnregisterTimeListener(TimeListener* tl); + void DoLookAhead(); + + int NextEvent(); + /// Schedules the named prototype to be built for the specified parent at /// timestep t. void SchedBuild(Agent* parent, std::string proto_name, int t); @@ -106,7 +110,7 @@ class Timer { /// The current time, measured in months from when the simulation /// started. int time_; - + int prev_time_; SimInfo si_; bool want_snapshot_; @@ -122,6 +126,8 @@ class Timer { // std::map > > std::map>> build_queue_; + std::map> request_queue_; + // std::map > std::map> decom_queue_; diff --git a/src/trader.h b/src/trader.h index ce999ac949..7cbcca1d3d 100644 --- a/src/trader.h +++ b/src/trader.h @@ -78,6 +78,8 @@ class Trader { virtual void AcceptProductTrades( const std::vector, Product::Ptr>>& responses) {} + virtual void EventRequest() {} + protected: Agent* manager_; From 1c23f3b2e11e2b6749629fbeb272a19a4a184a30 Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Tue, 17 Feb 2026 15:54:11 -0800 Subject: [PATCH 11/28] deleted print statements --- src/resource_exchange.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/resource_exchange.h b/src/resource_exchange.h index 8f8febe706..65a9eb7691 100644 --- a/src/resource_exchange.h +++ b/src/resource_exchange.h @@ -68,8 +68,6 @@ template class ResourceExchange { /// @brief queries traders and collects all requests for bids void AddAllRequests() { - std::cout << sim_ctx_ ->time_ << "\n"; - InitRequesters(); std::for_each(requesters_.begin(), requesters_.end(), From a0391f7163c73d781ee1ded506473398d32a2208 Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Tue, 17 Feb 2026 15:54:27 -0800 Subject: [PATCH 12/28] deleted print statements --- src/timer.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/timer.cc b/src/timer.cc index 377bdcfa99..b3273bd624 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -77,6 +77,7 @@ void Timer::RunSim() { void Timer::DoBuild() { // build queued agents std::vector> build_list = build_queue_[time_]; + std::cout<CreateAgent(build_list[i].first); Agent* parent = build_list[i].second; @@ -88,6 +89,8 @@ void Timer::DoBuild() { } else { CLOG(LEV_DEBUG1) << "Hey! Listen! Built an Agent without a Parent."; } + std::cout<<"HERE"; + std::cout<Populate(0); - //std::cout << (ctx_->EventRequesters())[0].size(); + ctx_->Populate(0); if (si.branch_time > -1) { time_ = si.branch_time; } From 06ed96355f5e7b3ef55c0f2e6fba85d01024c07a Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Wed, 18 Feb 2026 13:10:41 -0800 Subject: [PATCH 13/28] fixing a seg fault bug --- src/context.h | 3 ++- src/resource_exchange.h | 2 -- src/timer.cc | 13 +++++++------ src/timer.h | 2 -- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/context.h b/src/context.h index ee93bc1dd4..f560103d4d 100644 --- a/src/context.h +++ b/src/context.h @@ -186,6 +186,8 @@ class Context { inline void RegisterRequesters(std::pair e) {request_queue_[e.first].insert(e.second); } + inline void EventComplete(int t) {request_queue_.erase(t);} + inline const std::map>& EventRequesters() const { return request_queue_; } inline void Populate(int next_event) {request_queue_[next_event] = traders(); } @@ -193,7 +195,6 @@ class Context { int time_; inline void GetTime(int t) {time_ = t;} - //inline const std::set& GetRequesterEvent() {return request_queue_[ti_->time()]; } /// Create a new agent by cloning the named prototype. The returned agent is /// not initialized as a simulation participant. /// diff --git a/src/resource_exchange.h b/src/resource_exchange.h index 65a9eb7691..63fedee081 100644 --- a/src/resource_exchange.h +++ b/src/resource_exchange.h @@ -113,7 +113,6 @@ template class ResourceExchange { } // MEG HAVE TO FIX THIS LINe SO THAT WE GET THE CORRECT ELEMMENT IN The MAP void InitRequesters() { - //std::set orig = sim_ctx_->EventRequesters()[sim_ctx_->time_]; if (requesters_.size() == 0) { auto map = sim_ctx_->EventRequesters(); std::set orig = map[sim_ctx_->time_]; @@ -122,7 +121,6 @@ template class ResourceExchange { requesters_.insert(*it); } } - //requesters_.insert(req_vec.begin(),req_vec.end()); } /// @brief queries a given facility agent for diff --git a/src/timer.cc b/src/timer.cc index b3273bd624..d1dd3636bf 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -29,13 +29,18 @@ void Timer::RunSim() { ExchangeManager matl_manager(ctx_); ExchangeManager genrsrc_manager(ctx_); + + ctx_->Populate(0); //find better home for this line + ctx_->GetTime(0); + while ( (time_ < si_.duration) && (prev_time_ != time_)) { + + //std::cout<<(ctx_->EventRequesters()).at(time_).size(); CLOG(LEV_INFO1) << "Current time: " << time_; if (want_snapshot_) { want_snapshot_ = false; SimInit::Snapshot(ctx_); } - // run through phases DoBuild(); CLOG(LEV_INFO2) << "Beginning Tick for time: " << time_; @@ -53,6 +58,7 @@ void Timer::RunSim() { EventLoop(); #endif prev_time_ = time_; + ctx_->EventComplete(time_); time_ = NextEvent(); ctx_->GetTime(time_); @@ -77,7 +83,6 @@ void Timer::RunSim() { void Timer::DoBuild() { // build queued agents std::vector> build_list = build_queue_[time_]; - std::cout<CreateAgent(build_list[i].first); Agent* parent = build_list[i].second; @@ -89,8 +94,6 @@ void Timer::DoBuild() { } else { CLOG(LEV_DEBUG1) << "Hey! Listen! Built an Agent without a Parent."; } - std::cout<<"HERE"; - std::cout<Populate(0); if (si.branch_time > -1) { time_ = si.branch_time; } diff --git a/src/timer.h b/src/timer.h index 9834e9dc90..6ef3478f24 100644 --- a/src/timer.h +++ b/src/timer.h @@ -126,8 +126,6 @@ class Timer { // std::map > > std::map>> build_queue_; - std::map> request_queue_; - // std::map > std::map> decom_queue_; From 4a421b38e4c9dd92197d2d57dcadfb7f8944569f Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Mon, 23 Feb 2026 13:26:56 -0800 Subject: [PATCH 14/28] personal feature testings --- src/context.h | 7 ++++--- src/facility.cc | 1 + src/resource_exchange.h | 40 +++++++++++++++++++++++++++++----------- src/timer.cc | 26 ++++++++++++++++++-------- src/trader.h | 2 +- 5 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/context.h b/src/context.h index f560103d4d..f4b11e1cdb 100644 --- a/src/context.h +++ b/src/context.h @@ -184,7 +184,7 @@ class Context { /// @return the current set of traders registered for resource exchange. inline const std::set& traders() const { return traders_; } - inline void RegisterRequesters(std::pair e) {request_queue_[e.first].insert(e.second); } + inline void RegisterRequesters(int time, Trader* e) {request_queue_[time].insert(e); } inline void EventComplete(int t) {request_queue_.erase(t);} @@ -192,8 +192,9 @@ class Context { inline void Populate(int next_event) {request_queue_[next_event] = traders(); } - int time_; - inline void GetTime(int t) {time_ = t;} + // int time_; + // inline void GetTime(int t) {time_ = t;} + //inline int GetTime(){return ti_->time();} /// Create a new agent by cloning the named prototype. The returned agent is /// not initialized as a simulation participant. diff --git a/src/facility.cc b/src/facility.cc index bfcad159d8..074030872f 100644 --- a/src/facility.cc +++ b/src/facility.cc @@ -46,6 +46,7 @@ void Facility::Decommission() { } context()->UnregisterTrader(dynamic_cast(this)); + //unregister requester context()->UnregisterTimeListener(this); Agent::Decommission(); } diff --git a/src/resource_exchange.h b/src/resource_exchange.h index 63fedee081..edc24e2ac9 100644 --- a/src/resource_exchange.h +++ b/src/resource_exchange.h @@ -68,9 +68,9 @@ template class ResourceExchange { /// @brief queries traders and collects all requests for bids void AddAllRequests() { - InitRequesters(); - std::for_each(requesters_.begin(), - requesters_.end(), + InitTraders(); //InitRequesters // + std::for_each(traders_.begin(), //requesters_ + traders_.end(), //requesters _ std::bind(&cyclus::ResourceExchange::AddRequests_, this, std::placeholders::_1)); @@ -112,16 +112,34 @@ template class ResourceExchange { } } // MEG HAVE TO FIX THIS LINe SO THAT WE GET THE CORRECT ELEMMENT IN The MAP + // void InitRequesters() { + // auto map = sim_ctx_->EventRequesters(); + // if(map.count(sim_ctx_->time())!=0){ + // std::set orig = map.at(sim_ctx_->time()); + // std::set::iterator it; + // for (it = orig.begin(); it != orig.end(); ++it) { + // requesters_.insert(*it); + // } ;} + // else { + // return; + // } + // } + // if (requesters_.size() == 0) { + // auto map = sim_ctx_->EventRequesters(); + // std::set orig = map.at(sim_ctx_->time()); + // std::set::iterator it; + // for (it = orig.begin(); it != orig.end(); ++it) { + // requesters_.insert(*it); + // } + // } void InitRequesters() { - if (requesters_.size() == 0) { - auto map = sim_ctx_->EventRequesters(); - std::set orig = map[sim_ctx_->time_]; - std::set::iterator it; - for (it = orig.begin(); it != orig.end(); ++it) { - requesters_.insert(*it); - } + auto map = sim_ctx_->EventRequesters(); + std::set orig = map.at(sim_ctx_->time()); + std::set::iterator it; + for (it = orig.begin(); it != orig.end(); ++it) { + requesters_.insert(*it); + } } - } /// @brief queries a given facility agent for void AddRequests_(Trader* t) { diff --git a/src/timer.cc b/src/timer.cc index d1dd3636bf..2c3a6c77b6 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -30,9 +30,11 @@ void Timer::RunSim() { ExchangeManager matl_manager(ctx_); ExchangeManager genrsrc_manager(ctx_); + //ctx_->GetTime(0); ctx_->Populate(0); //find better home for this line - ctx_->GetTime(0); + build_queue_[dur()]; // find a better home + decom_queue_[dur()]; // find a better home while ( (time_ < si_.duration) && (prev_time_ != time_)) { //std::cout<<(ctx_->EventRequesters()).at(time_).size(); @@ -52,15 +54,15 @@ void Timer::RunSim() { CLOG(LEV_INFO2) << "Beginning Decision for time: " << time_; DoDecision(); DoDecom(); - DoLookAhead(); + //DoLookAhead(); #ifdef CYCLUS_WITH_PYTHON EventLoop(); #endif prev_time_ = time_; - ctx_->EventComplete(time_); + //ctx_->EventComplete(time_); time_ = NextEvent(); - ctx_->GetTime(time_); + //ctx_->GetTime(time_); if (want_kill_) { break; @@ -110,8 +112,13 @@ void Timer::DoTick() { void Timer::DoResEx(ExchangeManager* matmgr, ExchangeManager* genmgr) { + // auto reg_traders = ctx_->EventRequesters(); // MEG + // if(reg_traders.count(time_)==0){ + // return; + // } else { matmgr->Execute(); genmgr->Execute(); + //} } void Timer::DoTock() { @@ -198,7 +205,9 @@ void Timer::RecordInventory(Agent* a, std::string name, Material::Ptr m) { void Timer::DoDecom() { // decommission queued agents std::vector decom_list = decom_queue_[time_]; + std::cout <<"DECOM KEY check 2 "<< decom_queue_.count(time_)<< "\n"; for (int i = 0; i < decom_list.size(); ++i) { + std::cout<<"we are decomissioning at" << time_; Agent* m = decom_list[i]; if (m->parent() != NULL) { m->parent()->DecomNotify(m); @@ -241,10 +250,11 @@ void Timer::DoLookAhead() { int Timer::NextEvent(){ auto reg_traders = ctx_->EventRequesters(); - int t_p = time_ + 1; // time plus +1 - std::vector event_lists = {build_queue_.upper_bound(t_p)->first, - decom_queue_.upper_bound(t_p)->first, - reg_traders.upper_bound(t_p)->first}; + int t_p = time_; // time plus +1 + std::vector event_lists = {decom_queue_.upper_bound(t_p)->first,build_queue_.upper_bound(t_p)->first}; + //reg_traders.upper_bound(t_p)->first}; + std::cout<< "NExt Decom EVENT" << decom_queue_.upper_bound(t_p)->first << "\n"; + std::cout << "NEXT EVENT"<< *std::min_element(event_lists.begin(), event_lists.end()) << "\n"; return *std::min_element(event_lists.begin(), event_lists.end()); } diff --git a/src/trader.h b/src/trader.h index 7cbcca1d3d..4abd3e8fee 100644 --- a/src/trader.h +++ b/src/trader.h @@ -78,7 +78,7 @@ class Trader { virtual void AcceptProductTrades( const std::vector, Product::Ptr>>& responses) {} - virtual void EventRequest() {} + virtual void EventRequest() {manager()->context()->RegisterRequesters(manager()->context()->time(),this);} // MEG protected: Agent* manager_; From ae2dcc763dcc3ac5643418f0834801886403a98f Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Tue, 24 Feb 2026 21:59:30 -0800 Subject: [PATCH 15/28] moving decom from inst tock --- src/facility.cc | 9 +++++---- src/resource_exchange.h | 6 +++--- src/timer.cc | 30 ++++++++++++++---------------- src/trader.h | 2 +- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/facility.cc b/src/facility.cc index 074030872f..a6ded0213c 100644 --- a/src/facility.cc +++ b/src/facility.cc @@ -41,7 +41,7 @@ std::string Facility::str() { } void Facility::Decommission() { - if (!CheckDecommissionCondition()) { + if (!CheckDecommissionCondition()) { //MEG should be able to keep this throw Error("Cannot decommission " + prototype()); } @@ -51,9 +51,10 @@ void Facility::Decommission() { Agent::Decommission(); } -bool Facility::CheckDecommissionCondition() { - return true; -} +//MEG +// bool Facility::CheckDecommissionCondition() { +// return true; +// } Region* Facility::GetParentRegion(int layer) { return dynamic_cast(GetAncestorOfKind("Region", layer)); diff --git a/src/resource_exchange.h b/src/resource_exchange.h index edc24e2ac9..be9c659eac 100644 --- a/src/resource_exchange.h +++ b/src/resource_exchange.h @@ -68,9 +68,9 @@ template class ResourceExchange { /// @brief queries traders and collects all requests for bids void AddAllRequests() { - InitTraders(); //InitRequesters // - std::for_each(traders_.begin(), //requesters_ - traders_.end(), //requesters _ + InitRequesters(); + std::for_each(requesters_.begin(), //requesters_ + requesters_.end(), //requesters _ std::bind(&cyclus::ResourceExchange::AddRequests_, this, std::placeholders::_1)); diff --git a/src/timer.cc b/src/timer.cc index 2c3a6c77b6..78d09c74b3 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -32,12 +32,11 @@ void Timer::RunSim() { //ctx_->GetTime(0); ctx_->Populate(0); //find better home for this line - + ctx_->Populate(dur()); build_queue_[dur()]; // find a better home decom_queue_[dur()]; // find a better home - while ( (time_ < si_.duration) && (prev_time_ != time_)) { + while ( (time_ < si_.duration)) { - //std::cout<<(ctx_->EventRequesters()).at(time_).size(); CLOG(LEV_INFO1) << "Current time: " << time_; if (want_snapshot_) { want_snapshot_ = false; @@ -54,14 +53,15 @@ void Timer::RunSim() { CLOG(LEV_INFO2) << "Beginning Decision for time: " << time_; DoDecision(); DoDecom(); - //DoLookAhead(); + DoLookAhead(); #ifdef CYCLUS_WITH_PYTHON EventLoop(); #endif prev_time_ = time_; - //ctx_->EventComplete(time_); + ctx_->EventComplete(time_); time_ = NextEvent(); + std::cout<GetTime(time_); if (want_kill_) { @@ -112,13 +112,15 @@ void Timer::DoTick() { void Timer::DoResEx(ExchangeManager* matmgr, ExchangeManager* genmgr) { - // auto reg_traders = ctx_->EventRequesters(); // MEG - // if(reg_traders.count(time_)==0){ - // return; - // } else { + auto reg_traders = ctx_->EventRequesters(); // MEG + if(reg_traders.count(time_)==0){ + return; + } else { + std::cout<<"evenrequster "<<(ctx_->EventRequesters()).at(time_).size()<<"\n"; + std::cout<<"trading "<<(ctx_->traders()).size()<<"\n"; matmgr->Execute(); genmgr->Execute(); - //} + } } void Timer::DoTock() { @@ -205,9 +207,7 @@ void Timer::RecordInventory(Agent* a, std::string name, Material::Ptr m) { void Timer::DoDecom() { // decommission queued agents std::vector decom_list = decom_queue_[time_]; - std::cout <<"DECOM KEY check 2 "<< decom_queue_.count(time_)<< "\n"; for (int i = 0; i < decom_list.size(); ++i) { - std::cout<<"we are decomissioning at" << time_; Agent* m = decom_list[i]; if (m->parent() != NULL) { m->parent()->DecomNotify(m); @@ -251,10 +251,8 @@ void Timer::DoLookAhead() { int Timer::NextEvent(){ auto reg_traders = ctx_->EventRequesters(); int t_p = time_; // time plus +1 - std::vector event_lists = {decom_queue_.upper_bound(t_p)->first,build_queue_.upper_bound(t_p)->first}; - //reg_traders.upper_bound(t_p)->first}; - std::cout<< "NExt Decom EVENT" << decom_queue_.upper_bound(t_p)->first << "\n"; - std::cout << "NEXT EVENT"<< *std::min_element(event_lists.begin(), event_lists.end()) << "\n"; + std::vector event_lists = {decom_queue_.upper_bound(t_p)->first,build_queue_.upper_bound(t_p)->first, + reg_traders.upper_bound(t_p)->first}; return *std::min_element(event_lists.begin(), event_lists.end()); } diff --git a/src/trader.h b/src/trader.h index 4abd3e8fee..6b29e060f7 100644 --- a/src/trader.h +++ b/src/trader.h @@ -78,7 +78,7 @@ class Trader { virtual void AcceptProductTrades( const std::vector, Product::Ptr>>& responses) {} - virtual void EventRequest() {manager()->context()->RegisterRequesters(manager()->context()->time(),this);} // MEG + virtual void EventRequest() {manager()->context()->RegisterRequesters(manager()->context()->time(),this);} // MEG can be overridden protected: Agent* manager_; From 6263f3f09a551b4beaf24ed13b6dd0132d216acb Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Tue, 24 Feb 2026 22:07:43 -0800 Subject: [PATCH 16/28] adding decom condition to agent --- src/agent.cc | 9 +++++++++ src/agent.h | 1 + src/facility.h | 2 +- src/institution.cc | 24 ++++++++++++------------ 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/agent.cc b/src/agent.cc index fea56549b2..3e33b65f63 100644 --- a/src/agent.cc +++ b/src/agent.cc @@ -153,8 +153,17 @@ void Agent::Build(Agent* parent) { enter_time_ = ctx_->time(); EnterNotify(); this->AddToTable(); + // this is redacted from Institution::Tock() and merely checks if DecomStatus variable exists (if it does) it will not schedule a decom event during the build event + if (lifetime() >= 0 || !CheckDecommissionCondition()) { + context()->SchedDecom(this, exit_time()); + } } +//MEG +// bool Agent::CheckDecommissionCondition() { +// return true; +// } + void Agent::EnterNotify() { ctx_->RegisterAgent(this); } diff --git a/src/agent.h b/src/agent.h index ad80f2246c..39027a4ea7 100644 --- a/src/agent.h +++ b/src/agent.h @@ -390,6 +390,7 @@ class Agent : public StateWrangler, virtual public Ider, public EconomicEntity { /// Returns the number of time steps this agent operates between building and /// decommissioning (-1 if the agent has an infinite lifetime). inline const int lifetime() const { return lifetime_; } + inline bool CheckDecommissionCondition() const {return true;}; // MEG /// Returns the default time step at which this agent will exit the /// simulation (-1 if the agent has an infinite lifetime). diff --git a/src/facility.h b/src/facility.h index 2b12657c63..0cb4fd7a59 100644 --- a/src/facility.h +++ b/src/facility.h @@ -100,7 +100,7 @@ class Facility : public TimeListener, public Agent, public Trader { /// facilities over write this method if a condition must be met /// before their destructors can be called - virtual bool CheckDecommissionCondition(); + //virtual bool CheckDecommissionCondition(); MEG /// every agent should be able to print a verbose description virtual std::string str(); diff --git a/src/institution.cc b/src/institution.cc index d8b03aae78..b7aed12d7c 100644 --- a/src/institution.cc +++ b/src/institution.cc @@ -45,18 +45,18 @@ void Institution::Decommission() { } void Institution::Tock() { - std::set::iterator it; - for (it = children().begin(); it != children().end(); ++it) { - Agent* a = *it; - if (a->lifetime() != -1 && context()->time() >= a->exit_time()) { - Facility* fac = dynamic_cast(a); - if (fac == NULL || fac->CheckDecommissionCondition()) { - CLOG(LEV_INFO3) << a->prototype() - << " has reached the end of its lifetime"; - context()->SchedDecom(a); - } - } - } + // std::set::iterator it; MEG COMMENTED + // for (it = children().begin(); it != children().end(); ++it) { + // Agent* a = *it; + // if (a->lifetime() != -1 && context()->time() >= a->exit_time()) { + // Facility* fac = dynamic_cast(a); + // if (fac == NULL || fac->CheckDecommissionCondition()) { + // CLOG(LEV_INFO3) << a->prototype() + // << " has reached the end of its lifetime"; + // context()->SchedDecom(a); + // } + // } + // } } Region* Institution::GetParentRegion(int layer) { From 463297ea1db3a83c636b9852bbbfe0512a0a8daa Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Mon, 2 Mar 2026 16:47:18 -0800 Subject: [PATCH 17/28] changing default behavior --- src/context.h | 4 ---- src/timer.cc | 32 ++++++++++++++++++-------------- src/trader.h | 4 ++-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/context.h b/src/context.h index f4b11e1cdb..5704ab00ee 100644 --- a/src/context.h +++ b/src/context.h @@ -192,10 +192,6 @@ class Context { inline void Populate(int next_event) {request_queue_[next_event] = traders(); } - // int time_; - // inline void GetTime(int t) {time_ = t;} - //inline int GetTime(){return ti_->time();} - /// Create a new agent by cloning the named prototype. The returned agent is /// not initialized as a simulation participant. /// diff --git a/src/timer.cc b/src/timer.cc index 78d09c74b3..1118c796b1 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -17,6 +17,7 @@ namespace cyclus { void Timer::RunSim() { + auto start = std::chrono::high_resolution_clock::now(); LogLevel saved_level = Logger::ReportLevel(); if (quiet_) { // Set log level below LEV_ERROR (lowest level) to suppress all CLOG output @@ -32,11 +33,11 @@ void Timer::RunSim() { //ctx_->GetTime(0); ctx_->Populate(0); //find better home for this line - ctx_->Populate(dur()); - build_queue_[dur()]; // find a better home - decom_queue_[dur()]; // find a better home - while ( (time_ < si_.duration)) { - + ctx_->Populate(dur()+1); + build_queue_[dur()+1]; // find a better home + decom_queue_[dur()+1]; // find a better home + while (time_ < si_.duration) { + std::cout<EventComplete(time_); time_ = NextEvent(); - std::cout<GetTime(time_); if (want_kill_) { break; @@ -80,6 +79,11 @@ void Timer::RunSim() { if (quiet_) { Logger::SetReportLevel(saved_level); } + auto stop = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(stop - start); + + std::cout << "Time taken by function: " + << duration.count() << " microseconds" << std::endl; } void Timer::DoBuild() { @@ -242,17 +246,17 @@ void Timer::DoLookAhead() { for(Trader* m : all_traders){ m->EventRequest(); }; - auto reg_traders = ctx_->EventRequesters(); - if(reg_traders.count(time_+1) == 0){ - ctx_->Populate(NextEvent()); - }; + // auto reg_traders = ctx_->EventRequesters(); + // if(reg_traders.count(time_+1) == 0){ + // ctx_->Populate(NextEvent()); + // }; } int Timer::NextEvent(){ auto reg_traders = ctx_->EventRequesters(); - int t_p = time_; // time plus +1 - std::vector event_lists = {decom_queue_.upper_bound(t_p)->first,build_queue_.upper_bound(t_p)->first, - reg_traders.upper_bound(t_p)->first}; + int t_p = time_ +1; // time plus +1 + std::vector event_lists = {decom_queue_.lower_bound(t_p)->first,build_queue_.lower_bound(t_p)->first, + reg_traders.lower_bound(t_p)->first}; return *std::min_element(event_lists.begin(), event_lists.end()); } diff --git a/src/trader.h b/src/trader.h index 6b29e060f7..e76279488d 100644 --- a/src/trader.h +++ b/src/trader.h @@ -78,8 +78,8 @@ class Trader { virtual void AcceptProductTrades( const std::vector, Product::Ptr>>& responses) {} - virtual void EventRequest() {manager()->context()->RegisterRequesters(manager()->context()->time(),this);} // MEG can be overridden - + virtual void EventRequest(){} // MEG can be overridden + protected: Agent* manager_; From c23ca084e5cc4555271dc8fc5c2b0a3a2727d26f Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Thu, 5 Mar 2026 17:50:41 -0800 Subject: [PATCH 18/28] default behav --- src/timer.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/timer.cc b/src/timer.cc index 1118c796b1..ecbf7e6856 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -246,10 +246,10 @@ void Timer::DoLookAhead() { for(Trader* m : all_traders){ m->EventRequest(); }; - // auto reg_traders = ctx_->EventRequesters(); - // if(reg_traders.count(time_+1) == 0){ - // ctx_->Populate(NextEvent()); - // }; + auto reg_traders = ctx_->EventRequesters(); + if(reg_traders.count(time_+1) == 0){ + ctx_->Populate(NextEvent()); + }; } int Timer::NextEvent(){ From d08509ac8db98bbe7c1a15625c8a074bc512fe35 Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Tue, 17 Mar 2026 11:49:21 -0700 Subject: [PATCH 19/28] changing event end --- src/context.h | 6 ++++-- src/timer.cc | 22 ++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/context.h b/src/context.h index 5704ab00ee..4a5c0ab874 100644 --- a/src/context.h +++ b/src/context.h @@ -190,7 +190,9 @@ class Context { inline const std::map>& EventRequesters() const { return request_queue_; } - inline void Populate(int next_event) {request_queue_[next_event] = traders(); } + inline void Populate(int t) {if (pop_sched_.count(t)>0){request_queue_.at(t) = traders();};} // if there is someone already there then i wouldve unionized the sets any way, is ithe same thing as just resetting the vals + + inline void SchedPopulate(int next_event) {pop_sched_.insert(next_event); request_queue_[next_event];} /// Create a new agent by cloning the named prototype. The returned agent is /// not initialized as a simulation participant. @@ -382,7 +384,7 @@ class Context { std::map> request_queue_; std::map n_prototypes_; std::map n_specs_; - + std::set pop_sched_; SimInfo si_; Timer* ti_; ExchangeSolver* solver_; diff --git a/src/timer.cc b/src/timer.cc index ecbf7e6856..a3f3c651a0 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -31,9 +31,9 @@ void Timer::RunSim() { ExchangeManager matl_manager(ctx_); ExchangeManager genrsrc_manager(ctx_); - //ctx_->GetTime(0); + ctx_->SchedPopulate(0); ctx_->Populate(0); //find better home for this line - ctx_->Populate(dur()+1); + ctx_->SchedPopulate(dur()+1); build_queue_[dur()+1]; // find a better home decom_queue_[dur()+1]; // find a better home while (time_ < si_.duration) { @@ -60,7 +60,6 @@ void Timer::RunSim() { EventLoop(); #endif prev_time_ = time_; - ctx_->EventComplete(time_); time_ = NextEvent(); if (want_kill_) { @@ -117,14 +116,12 @@ void Timer::DoTick() { void Timer::DoResEx(ExchangeManager* matmgr, ExchangeManager* genmgr) { auto reg_traders = ctx_->EventRequesters(); // MEG - if(reg_traders.count(time_)==0){ - return; - } else { - std::cout<<"evenrequster "<<(ctx_->EventRequesters()).at(time_).size()<<"\n"; - std::cout<<"trading "<<(ctx_->traders()).size()<<"\n"; - matmgr->Execute(); - genmgr->Execute(); - } + ctx_->Populate(time_); + if(reg_traders.at(time_).size()>0){ + std::cout<<"registered to trade " << reg_traders.at(time_).size() << "\n"; + matmgr->Execute(); + genmgr->Execute(); + } } void Timer::DoTock() { @@ -242,13 +239,14 @@ void Timer::UnregisterTimeListener(TimeListener* tl) { } void Timer::DoLookAhead() { + ctx_->EventComplete(time_); std::set all_traders = ctx_->traders(); for(Trader* m : all_traders){ m->EventRequest(); }; auto reg_traders = ctx_->EventRequesters(); if(reg_traders.count(time_+1) == 0){ - ctx_->Populate(NextEvent()); + ctx_->SchedPopulate(NextEvent()); }; } From d2cff0f247398a84a3dc77d7ec4d349c746a3fe5 Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Tue, 5 May 2026 17:30:20 -0700 Subject: [PATCH 20/28] second discrete event implementation (cyclus 1.6v default) --- src/agent.cc | 9 --------- src/agent.h | 1 - src/context.h | 10 ++++++---- src/facility.cc | 22 ++++++++++++++++------ src/facility.h | 8 +++++++- src/institution.cc | 26 +++++++++++++------------- src/resource_exchange.h | 28 ++++------------------------ src/timer.cc | 31 +++++++++---------------------- src/trader.h | 7 ++++++- src/trader_management.h | 2 ++ 10 files changed, 63 insertions(+), 81 deletions(-) diff --git a/src/agent.cc b/src/agent.cc index 3e33b65f63..fea56549b2 100644 --- a/src/agent.cc +++ b/src/agent.cc @@ -153,17 +153,8 @@ void Agent::Build(Agent* parent) { enter_time_ = ctx_->time(); EnterNotify(); this->AddToTable(); - // this is redacted from Institution::Tock() and merely checks if DecomStatus variable exists (if it does) it will not schedule a decom event during the build event - if (lifetime() >= 0 || !CheckDecommissionCondition()) { - context()->SchedDecom(this, exit_time()); - } } -//MEG -// bool Agent::CheckDecommissionCondition() { -// return true; -// } - void Agent::EnterNotify() { ctx_->RegisterAgent(this); } diff --git a/src/agent.h b/src/agent.h index 39027a4ea7..ad80f2246c 100644 --- a/src/agent.h +++ b/src/agent.h @@ -390,7 +390,6 @@ class Agent : public StateWrangler, virtual public Ider, public EconomicEntity { /// Returns the number of time steps this agent operates between building and /// decommissioning (-1 if the agent has an infinite lifetime). inline const int lifetime() const { return lifetime_; } - inline bool CheckDecommissionCondition() const {return true;}; // MEG /// Returns the default time step at which this agent will exit the /// simulation (-1 if the agent has an infinite lifetime). diff --git a/src/context.h b/src/context.h index 4a5c0ab874..2458b5b7b6 100644 --- a/src/context.h +++ b/src/context.h @@ -184,15 +184,17 @@ class Context { /// @return the current set of traders registered for resource exchange. inline const std::set& traders() const { return traders_; } - inline void RegisterRequesters(int time, Trader* e) {request_queue_[time].insert(e); } + inline void RegisterRequesters(int time, Trader* e) {request_queue_[time].insert(e); } //conditions to register an event is up to archetype dev - inline void EventComplete(int t) {request_queue_.erase(t);} + inline void EventComplete(int t) {request_queue_.erase(t);} // fit this so it purges any 0 entries as well as the most current completed event ! inline const std::map>& EventRequesters() const { return request_queue_; } - inline void Populate(int t) {if (pop_sched_.count(t)>0){request_queue_.at(t) = traders();};} // if there is someone already there then i wouldve unionized the sets any way, is ithe same thing as just resetting the vals + inline void Populate(int t) {if (pop_sched_.count(t)>0){request_queue_.at(t) = traders();};} //there are more use cases for this - inline void SchedPopulate(int next_event) {pop_sched_.insert(next_event); request_queue_[next_event];} + inline void SchedPopulate(int next_event) {pop_sched_.insert(next_event); request_queue_[next_event];} // there are more use cases for this + + inline void DeregisterRequesters(int time, Trader* e) {request_queue_[time].erase(e);} //conditions to deregister an event is up to archetype dev /// Create a new agent by cloning the named prototype. The returned agent is /// not initialized as a simulation participant. diff --git a/src/facility.cc b/src/facility.cc index a6ded0213c..750b057428 100644 --- a/src/facility.cc +++ b/src/facility.cc @@ -25,12 +25,16 @@ void Facility::InitFrom(Facility* m) { void Facility::Build(Agent* parent) { Agent::Build(parent); + if (lifetime() >= 0 && CheckDecommissionCondition() == NULL) { + context()->SchedDecom(this, exit_time()); + } } void Facility::EnterNotify() { Agent::EnterNotify(); context()->RegisterTrader(dynamic_cast(this)); context()->RegisterTimeListener(this); + // maybe have a context()->RegisterCommodityConsumer(this); } std::string Facility::str() { @@ -41,20 +45,26 @@ std::string Facility::str() { } void Facility::Decommission() { - if (!CheckDecommissionCondition()) { //MEG should be able to keep this + if (!CheckDecommissionCondition()) { //check what happens w NULL throw Error("Cannot decommission " + prototype()); } context()->UnregisterTrader(dynamic_cast(this)); - //unregister requester context()->UnregisterTimeListener(this); Agent::Decommission(); } -//MEG -// bool Facility::CheckDecommissionCondition() { -// return true; -// } +bool Facility::CheckDecommissionCondition() { + return NULL; +} + +void Facility::Tock(){ + EventRequest(); +} + +void Facility::Tick(){ + SetTraded(false); +} Region* Facility::GetParentRegion(int layer) { return dynamic_cast(GetAncestorOfKind("Region", layer)); diff --git a/src/facility.h b/src/facility.h index 0cb4fd7a59..9b92c9edc1 100644 --- a/src/facility.h +++ b/src/facility.h @@ -100,7 +100,7 @@ class Facility : public TimeListener, public Agent, public Trader { /// facilities over write this method if a condition must be met /// before their destructors can be called - //virtual bool CheckDecommissionCondition(); MEG + virtual bool CheckDecommissionCondition(); /// every agent should be able to print a verbose description virtual std::string str(); @@ -127,6 +127,12 @@ class Facility : public TimeListener, public Agent, public Trader { return std::set::Ptr>(); } + virtual void EventRequest(){context()->RegisterRequesters(context()->time() + 1, this);} + + virtual void Tock(); + + virtual void Tick(); + /// default implementation for material preferences. virtual void AdjustMatlPrefs(PrefMap::type& prefs) {} diff --git a/src/institution.cc b/src/institution.cc index b7aed12d7c..566062abf6 100644 --- a/src/institution.cc +++ b/src/institution.cc @@ -44,19 +44,19 @@ void Institution::Decommission() { Agent::Decommission(); } -void Institution::Tock() { - // std::set::iterator it; MEG COMMENTED - // for (it = children().begin(); it != children().end(); ++it) { - // Agent* a = *it; - // if (a->lifetime() != -1 && context()->time() >= a->exit_time()) { - // Facility* fac = dynamic_cast(a); - // if (fac == NULL || fac->CheckDecommissionCondition()) { - // CLOG(LEV_INFO3) << a->prototype() - // << " has reached the end of its lifetime"; - // context()->SchedDecom(a); - // } - // } - // } +void Institution::Tock() { + std::set::iterator it; + for (it = children().begin(); it != children().end(); ++it) { + Agent* a = *it; + if (a->lifetime() != -1 && context()->time() >= a->exit_time()) { + Facility* fac = dynamic_cast(a); + if (fac == NULL || fac->CheckDecommissionCondition()) { // any faciilty without overwritten checkdecomcondition expects a NULL, only true will pass || + CLOG(LEV_INFO3) << a->prototype() + << " has reached the end of its lifetime"; + context()->SchedDecom(a); + } + } + } } Region* Institution::GetParentRegion(int layer) { diff --git a/src/resource_exchange.h b/src/resource_exchange.h index be9c659eac..290a3553be 100644 --- a/src/resource_exchange.h +++ b/src/resource_exchange.h @@ -67,10 +67,10 @@ template class ResourceExchange { inline ExchangeContext& ex_ctx() { return ex_ctx_; } /// @brief queries traders and collects all requests for bids - void AddAllRequests() { + void AddAllRequests() { //MEG I think we should add the collect other commodity consumers of type a into the mix with this as well. Have some function below within init requesters InitRequesters(); - std::for_each(requesters_.begin(), //requesters_ - requesters_.end(), //requesters _ + std::for_each(requesters_.begin(), + requesters_.end(), std::bind(&cyclus::ResourceExchange::AddRequests_, this, std::placeholders::_1)); @@ -111,27 +111,7 @@ template class ResourceExchange { } } } -// MEG HAVE TO FIX THIS LINe SO THAT WE GET THE CORRECT ELEMMENT IN The MAP - // void InitRequesters() { - // auto map = sim_ctx_->EventRequesters(); - // if(map.count(sim_ctx_->time())!=0){ - // std::set orig = map.at(sim_ctx_->time()); - // std::set::iterator it; - // for (it = orig.begin(); it != orig.end(); ++it) { - // requesters_.insert(*it); - // } ;} - // else { - // return; - // } - // } - // if (requesters_.size() == 0) { - // auto map = sim_ctx_->EventRequesters(); - // std::set orig = map.at(sim_ctx_->time()); - // std::set::iterator it; - // for (it = orig.begin(); it != orig.end(); ++it) { - // requesters_.insert(*it); - // } - // } + void InitRequesters() { auto map = sim_ctx_->EventRequesters(); std::set orig = map.at(sim_ctx_->time()); diff --git a/src/timer.cc b/src/timer.cc index a3f3c651a0..38e7c18e34 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -17,7 +17,6 @@ namespace cyclus { void Timer::RunSim() { - auto start = std::chrono::high_resolution_clock::now(); LogLevel saved_level = Logger::ReportLevel(); if (quiet_) { // Set log level below LEV_ERROR (lowest level) to suppress all CLOG output @@ -36,8 +35,8 @@ void Timer::RunSim() { ctx_->SchedPopulate(dur()+1); build_queue_[dur()+1]; // find a better home decom_queue_[dur()+1]; // find a better home + while (time_ < si_.duration) { - std::cout<(stop - start); - - std::cout << "Time taken by function: " - << duration.count() << " microseconds" << std::endl; } void Timer::DoBuild() { @@ -116,9 +109,7 @@ void Timer::DoTick() { void Timer::DoResEx(ExchangeManager* matmgr, ExchangeManager* genmgr) { auto reg_traders = ctx_->EventRequesters(); // MEG - ctx_->Populate(time_); if(reg_traders.at(time_).size()>0){ - std::cout<<"registered to trade " << reg_traders.at(time_).size() << "\n"; matmgr->Execute(); genmgr->Execute(); } @@ -146,6 +137,14 @@ void Timer::DoTock() { } } } + auto reg_traders = ctx_->EventRequesters(); + if(reg_traders.at(time_).size()>0){ + ctx_->EventComplete(time_); + + if(reg_traders.count(reg_traders.lower_bound(time_ +1)->first) == 0){ // + ctx_->EventComplete(reg_traders.lower_bound(time_ + 1)->first); + } + } } void Timer::DoDecision() { @@ -238,18 +237,6 @@ void Timer::UnregisterTimeListener(TimeListener* tl) { } } -void Timer::DoLookAhead() { - ctx_->EventComplete(time_); - std::set all_traders = ctx_->traders(); - for(Trader* m : all_traders){ - m->EventRequest(); - }; - auto reg_traders = ctx_->EventRequesters(); - if(reg_traders.count(time_+1) == 0){ - ctx_->SchedPopulate(NextEvent()); - }; -} - int Timer::NextEvent(){ auto reg_traders = ctx_->EventRequesters(); int t_p = time_ +1; // time plus +1 diff --git a/src/trader.h b/src/trader.h index e76279488d..edddf02da7 100644 --- a/src/trader.h +++ b/src/trader.h @@ -80,9 +80,14 @@ class Trader { virtual void EventRequest(){} // MEG can be overridden + bool Traded; + + void SetTraded(bool status){Traded = status;} + + bool ReturnTraded(){return Traded;} + protected: Agent* manager_; - private: /// @warning this function is hidden to prevent an invalid signature that can /// raise difficult to find bugs diff --git a/src/trader_management.h b/src/trader_management.h index 97fb22eaab..0288a13800 100644 --- a/src/trader_management.h +++ b/src/trader_management.h @@ -84,6 +84,7 @@ inline void AcceptTrades( Trader* trader, const std::vector, Material::Ptr>>& responses) { dynamic_cast(trader)->AcceptMatlTrades(responses); + trader->SetTraded(true); } template <> @@ -91,6 +92,7 @@ inline void AcceptTrades( Trader* trader, const std::vector, Product::Ptr>>& responses) { trader->AcceptProductTrades(responses); + trader->SetTraded(true); } } // namespace cyclus From 4728bfece2d7fdff4155c6c91faa189a7ef77379 Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Tue, 5 May 2026 17:56:42 -0700 Subject: [PATCH 21/28] tweaking explanatory comments --- .gitignore | 12 ++++++++++++ src/context.h | 1 - src/institution.cc | 6 +++--- src/resource_exchange.h | 2 +- src/timer.cc | 5 ++--- src/timer.h | 2 -- 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 0f0dc8e700..15b9ea78f6 100644 --- a/.gitignore +++ b/.gitignore @@ -86,3 +86,15 @@ cyclus/cycpp.py # Rever rever/ .vscode +# pixi environments +.pixi/* +!.pixi/config.toml +pixi.lock +pixi.toml + +#MEG build +lib/* +include/* +bin/* +share/cyclus/* +.gitattributes \ No newline at end of file diff --git a/src/context.h b/src/context.h index 2458b5b7b6..adbd2a32dc 100644 --- a/src/context.h +++ b/src/context.h @@ -19,7 +19,6 @@ #include "pyhooks.h" #include "recorder.h" #include "package.h" -//#include "timer.h" MEG // Defined as 4 seconds longer than a Gaussian year (to make division by 12 // a round number) diff --git a/src/institution.cc b/src/institution.cc index 566062abf6..9b9f0fd2c1 100644 --- a/src/institution.cc +++ b/src/institution.cc @@ -44,13 +44,13 @@ void Institution::Decommission() { Agent::Decommission(); } -void Institution::Tock() { - std::set::iterator it; +void Institution::Tock() { + std::set::iterator it; for (it = children().begin(); it != children().end(); ++it) { Agent* a = *it; if (a->lifetime() != -1 && context()->time() >= a->exit_time()) { Facility* fac = dynamic_cast(a); - if (fac == NULL || fac->CheckDecommissionCondition()) { // any faciilty without overwritten checkdecomcondition expects a NULL, only true will pass || + if (fac == NULL || fac->CheckDecommissionCondition()) { // any facility without overwritten checkdecomcondition expects a NULL, only true will pass || CLOG(LEV_INFO3) << a->prototype() << " has reached the end of its lifetime"; context()->SchedDecom(a); diff --git a/src/resource_exchange.h b/src/resource_exchange.h index 290a3553be..986c79b64b 100644 --- a/src/resource_exchange.h +++ b/src/resource_exchange.h @@ -67,7 +67,7 @@ template class ResourceExchange { inline ExchangeContext& ex_ctx() { return ex_ctx_; } /// @brief queries traders and collects all requests for bids - void AddAllRequests() { //MEG I think we should add the collect other commodity consumers of type a into the mix with this as well. Have some function below within init requesters + void AddAllRequests() { // I think we should add other commodity consumers of type a into the mix within InitRequesters() as well. InitRequesters(); std::for_each(requesters_.begin(), requesters_.end(), diff --git a/src/timer.cc b/src/timer.cc index 38e7c18e34..1e34a76531 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -108,7 +108,7 @@ void Timer::DoTick() { void Timer::DoResEx(ExchangeManager* matmgr, ExchangeManager* genmgr) { - auto reg_traders = ctx_->EventRequesters(); // MEG + auto reg_traders = ctx_->EventRequesters(); if(reg_traders.at(time_).size()>0){ matmgr->Execute(); genmgr->Execute(); @@ -121,7 +121,6 @@ void Timer::DoTock() { } #pragma omp parallel for -// change this so that it is just for (size_t i = 0; i < cpp_tickers_.size(); ++i) { cpp_tickers_[i]->Tock(); } @@ -215,7 +214,7 @@ void Timer::DoDecom() { m->Decommission(); } } -// I want this to go every time event + void Timer::RegisterTimeListener(TimeListener* agent) { tickers_[agent->id()] = agent; if (agent->IsShim()) { diff --git a/src/timer.h b/src/timer.h index 6ef3478f24..93a0e80cb6 100644 --- a/src/timer.h +++ b/src/timer.h @@ -50,8 +50,6 @@ class Timer { /// Agents should unregister from their Decommission method. void UnregisterTimeListener(TimeListener* tl); - void DoLookAhead(); - int NextEvent(); /// Schedules the named prototype to be built for the specified parent at From aa1458a6a0795ce2ed17ca349676c3249ab6e4ee Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Tue, 5 May 2026 18:15:26 -0700 Subject: [PATCH 22/28] adding functions to headers --- src/facility.cc | 9 ++++++--- src/facility.h | 3 ++- src/timer.cc | 4 +++- src/trader.h | 8 ++++---- src/trader_management.h | 4 ++-- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/facility.cc b/src/facility.cc index 750b057428..399c4b71ee 100644 --- a/src/facility.cc +++ b/src/facility.cc @@ -24,10 +24,13 @@ void Facility::InitFrom(Facility* m) { } void Facility::Build(Agent* parent) { - Agent::Build(parent); + Agent::Build(parent); + //for agents WITHOUT the need for a checkdecom function, they can easily schedule decom at build (only reactor/separations use this right now) if (lifetime() >= 0 && CheckDecommissionCondition() == NULL) { context()->SchedDecom(this, exit_time()); } + //all agents who have been build should want to immediately trade + EventRequest(); } void Facility::EnterNotify() { @@ -58,12 +61,12 @@ bool Facility::CheckDecommissionCondition() { return NULL; } -void Facility::Tock(){ +void Facility::Tock(){ // archetype developers need to invoke this method in tock EventRequest(); } void Facility::Tick(){ - SetTraded(false); + SetTraded(false); //archetype developers need to invoke this method in tick } Region* Facility::GetParentRegion(int layer) { diff --git a/src/facility.h b/src/facility.h index 9b92c9edc1..eb33df4929 100644 --- a/src/facility.h +++ b/src/facility.h @@ -127,7 +127,8 @@ class Facility : public TimeListener, public Agent, public Trader { return std::set::Ptr>(); } - virtual void EventRequest(){context()->RegisterRequesters(context()->time() + 1, this);} + // this is intended to be a default behavior should an archetype developer not invoke their own "EventRequest " + virtual void EventRequest(){context()->RegisterRequesters(context()->time() + 1, this);} virtual void Tock(); diff --git a/src/timer.cc b/src/timer.cc index 1e34a76531..404b6ec9f9 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -30,8 +30,10 @@ void Timer::RunSim() { ExchangeManager matl_manager(ctx_); ExchangeManager genrsrc_manager(ctx_); + // following two lines are for primary initialization of "requesters" map in context ctx_->SchedPopulate(0); ctx_->Populate(0); //find better home for this line + //the following 3 lines are to add an upper limit to the 3 event maps ctx_->SchedPopulate(dur()+1); build_queue_[dur()+1]; // find a better home decom_queue_[dur()+1]; // find a better home @@ -238,7 +240,7 @@ void Timer::UnregisterTimeListener(TimeListener* tl) { int Timer::NextEvent(){ auto reg_traders = ctx_->EventRequesters(); - int t_p = time_ +1; // time plus +1 + int t_p = time_ +1; std::vector event_lists = {decom_queue_.lower_bound(t_p)->first,build_queue_.lower_bound(t_p)->first, reg_traders.lower_bound(t_p)->first}; return *std::min_element(event_lists.begin(), event_lists.end()); diff --git a/src/trader.h b/src/trader.h index edddf02da7..9d11ce69a4 100644 --- a/src/trader.h +++ b/src/trader.h @@ -78,13 +78,13 @@ class Trader { virtual void AcceptProductTrades( const std::vector, Product::Ptr>>& responses) {} - virtual void EventRequest(){} // MEG can be overridden + virtual void EventRequest(){} // can be overridden ? - bool Traded; + bool Traded; //follows DRE to assess whether trader completed trades - void SetTraded(bool status){Traded = status;} + void SetTraded(bool status){Traded = status;} //setter for Traded - bool ReturnTraded(){return Traded;} + bool ReturnTraded(){return Traded;} //getter for Traded protected: Agent* manager_; diff --git a/src/trader_management.h b/src/trader_management.h index 0288a13800..69a227ad57 100644 --- a/src/trader_management.h +++ b/src/trader_management.h @@ -84,7 +84,7 @@ inline void AcceptTrades( Trader* trader, const std::vector, Material::Ptr>>& responses) { dynamic_cast(trader)->AcceptMatlTrades(responses); - trader->SetTraded(true); + trader->SetTraded(true); //successful trade means Traded status changes } template <> @@ -92,7 +92,7 @@ inline void AcceptTrades( Trader* trader, const std::vector, Product::Ptr>>& responses) { trader->AcceptProductTrades(responses); - trader->SetTraded(true); + trader->SetTraded(true); //successful trade means Traded status changes } } // namespace cyclus From b6cbaa7441821e3c675eaebcd80d10e1630159d7 Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Tue, 5 May 2026 18:24:23 -0700 Subject: [PATCH 23/28] stop trackingin gitignore --- .gitignore | 100 ----------------------------------------------------- 1 file changed, 100 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 15b9ea78f6..0000000000 --- a/.gitignore +++ /dev/null @@ -1,100 +0,0 @@ -*.sw* -*.orig -build -.DS_Store -debug -core -packages.xml -doxygen.conf -platform.h -*.pdf -*.pyc -*.dvi -*.toc -*.aux -*.out -*.log -*.bbl -*.blg -*.log -*.spl -*~ -*# -#* -*.zip -*.tex -*.s -src/Core/Utility/Env.cpp -src/cyclus_nuc_data.h5 -stubs/stub_version.h -src/cyc_limits.h -src/env.cc -src/version.cc -src/version.h -share/cyclus_nuc_data.h5 -src/pyne_decay.h -src/pyne_decay.cc -src/hdf5_back.cc -src/hdf5_back.h -src/*.tar.gz -src/cram.c -src/cram.h -src/decay.cpp -src/decay.h -share/dbtypes.json -tests/db.h5 -cyclus/cpp_typesystem.pxd -cyclus/typesystem.pxd -cyclus/typesystem.pyx -cyclus/system.py -tests/libcyclus-orig.h5 -tests/libcyclus-orig.sqlite -tests/libcyclus-test.h5 -tests/libcyclus-test.sqlite -tests/dummy.json -tests/dummy.h5 -tests/default-toaster.json -tests/default-toaster.h5 -tests/attr-toaster-comapny.h5 -tests/attr-toaster-comapny.json -tests/attr-toaster-region.h5 -tests/attr-toaster-region.json -rs.cred - -# Docker stuff -build-local/ -Debug/ - -# generated cython ignores -*.cc.gen -*.cc.h -*.cc_api.h -*.h.gen -src/eventhooks.cc -src/eventhooks.h -src/eventhooks_api.h -src/pyinfile.cc -src/pyinfile.h -src/pyinfile_api.h -src/pymodule.cc -src/pymodule.h -src/pymodule_api.h - -# this is copied over by the installer -cyclus/cycpp.py - -# Rever -rever/ -.vscode -# pixi environments -.pixi/* -!.pixi/config.toml -pixi.lock -pixi.toml - -#MEG build -lib/* -include/* -bin/* -share/cyclus/* -.gitattributes \ No newline at end of file From 2f39d6fcb6c01abea26e6963bd7ec4ca3088a73a Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Tue, 5 May 2026 18:33:37 -0700 Subject: [PATCH 24/28] restoring .gitignore --- .gitignore | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..9843daf52c --- /dev/null +++ b/.gitignore @@ -0,0 +1,88 @@ +*.sw* +*.orig +build +.DS_Store +debug +core +packages.xml +doxygen.conf +platform.h +*.pdf +*.pyc +*.dvi +*.toc +*.aux +*.out +*.log +*.bbl +*.blg +*.log +*.spl +*~ +*# +#* +*.zip +*.tex +*.s +src/Core/Utility/Env.cpp +src/cyclus_nuc_data.h5 +stubs/stub_version.h +src/cyc_limits.h +src/env.cc +src/version.cc +src/version.h +share/cyclus_nuc_data.h5 +src/pyne_decay.h +src/pyne_decay.cc +src/hdf5_back.cc +src/hdf5_back.h +src/*.tar.gz +src/cram.c +src/cram.h +src/decay.cpp +src/decay.h +share/dbtypes.json +tests/db.h5 +cyclus/cpp_typesystem.pxd +cyclus/typesystem.pxd +cyclus/typesystem.pyx +cyclus/system.py +tests/libcyclus-orig.h5 +tests/libcyclus-orig.sqlite +tests/libcyclus-test.h5 +tests/libcyclus-test.sqlite +tests/dummy.json +tests/dummy.h5 +tests/default-toaster.json +tests/default-toaster.h5 +tests/attr-toaster-comapny.h5 +tests/attr-toaster-comapny.json +tests/attr-toaster-region.h5 +tests/attr-toaster-region.json +rs.cred + +# Docker stuff +build-local/ +Debug/ + +# generated cython ignores +*.cc.gen +*.cc.h +*.cc_api.h +*.h.gen +src/eventhooks.cc +src/eventhooks.h +src/eventhooks_api.h +src/pyinfile.cc +src/pyinfile.h +src/pyinfile_api.h +src/pymodule.cc +src/pymodule.h +src/pymodule_api.h + +# this is copied over by the installer +cyclus/cycpp.py + +# Rever +rever/ +.vscode \ No newline at end of file From fc5b723f9dc3f29d0e70dd48ad7c4f179369027a Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Tue, 5 May 2026 23:02:34 -0700 Subject: [PATCH 25/28] added in annotations/explanations --- src/timer.cc | 19 +++++++++++-------- src/timer.h | 1 - 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/timer.cc b/src/timer.cc index 404b6ec9f9..cfbc09ee18 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -30,10 +30,7 @@ void Timer::RunSim() { ExchangeManager matl_manager(ctx_); ExchangeManager genrsrc_manager(ctx_); - // following two lines are for primary initialization of "requesters" map in context - ctx_->SchedPopulate(0); - ctx_->Populate(0); //find better home for this line - //the following 3 lines are to add an upper limit to the 3 event maps + //the following 3 lines are to add an upper limit to the 3 event maps so that the there is always a final event in "queue" ctx_->SchedPopulate(dur()+1); build_queue_[dur()+1]; // find a better home decom_queue_[dur()+1]; // find a better home @@ -59,7 +56,6 @@ void Timer::RunSim() { #ifdef CYCLUS_WITH_PYTHON EventLoop(); #endif - prev_time_ = time_; time_ = NextEvent(); if (want_kill_) { @@ -83,6 +79,7 @@ void Timer::RunSim() { void Timer::DoBuild() { // build queued agents std::vector> build_list = build_queue_[time_]; + //if build_list is empty at time, already no one builds i.e. "skips" event for (int i = 0; i < build_list.size(); ++i) { Agent* m = ctx_->CreateAgent(build_list[i].first); Agent* parent = build_list[i].second; @@ -103,6 +100,7 @@ void Timer::DoTick() { } #pragma omp parallel for + //everyone ticks for all events (Cyclus 04/21 notes) for (size_t i = 0; i < cpp_tickers_.size(); ++i) { cpp_tickers_[i]->Tick(); } @@ -111,6 +109,7 @@ void Timer::DoTick() { void Timer::DoResEx(ExchangeManager* matmgr, ExchangeManager* genmgr) { auto reg_traders = ctx_->EventRequesters(); + //still unclear: do decom events require secondary registration for trades? if(reg_traders.at(time_).size()>0){ matmgr->Execute(); genmgr->Execute(); @@ -118,6 +117,7 @@ void Timer::DoResEx(ExchangeManager* matmgr, } void Timer::DoTock() { + //everyone tocks for all events (Cyclus 04/21 notes) for (TimeListener* agent : py_tickers_) { agent->Tock(); } @@ -140,9 +140,12 @@ void Timer::DoTock() { } auto reg_traders = ctx_->EventRequesters(); if(reg_traders.at(time_).size()>0){ - ctx_->EventComplete(time_); + ctx_->EventComplete(time_); //to dereference some pointers, maybe applied to build/decom maps too - if(reg_traders.count(reg_traders.lower_bound(time_ +1)->first) == 0){ // + if(reg_traders.count(reg_traders.lower_bound(time_ +1)->first) == 0){ + //if archetype developer has some ctx_->DeregisterRequester behavior + //this looks for instances that previously registered -upcoming- events + //have been emptied of requesters ctx_->EventComplete(reg_traders.lower_bound(time_ + 1)->first); } } @@ -208,6 +211,7 @@ void Timer::RecordInventory(Agent* a, std::string name, Material::Ptr m) { void Timer::DoDecom() { // decommission queued agents std::vector decom_list = decom_queue_[time_]; + //if decom_list is empty at time, already no one decommissions i.e. "skips" event for (int i = 0; i < decom_list.size(); ++i) { Agent* m = decom_list[i]; if (m->parent() != NULL) { @@ -302,7 +306,6 @@ void Timer::Initialize(Context* ctx, SimInfo si) { if (si.m0 < 1 || si.m0 > 12) { throw ValueError("Invalid month0; must be between 1 and 12 (inclusive)."); } - prev_time_ = -1; want_kill_ = false; ctx_ = ctx; time_ = 0; diff --git a/src/timer.h b/src/timer.h index 93a0e80cb6..cd300fa805 100644 --- a/src/timer.h +++ b/src/timer.h @@ -108,7 +108,6 @@ class Timer { /// The current time, measured in months from when the simulation /// started. int time_; - int prev_time_; SimInfo si_; bool want_snapshot_; From 7d72b8769cc38bfc01db6032c05219e8064fbb38 Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Thu, 14 May 2026 12:21:49 -0700 Subject: [PATCH 26/28] adding sched to toolkit, adjusting maps --- src/cyclus.h | 1 + src/facility.cc | 27 ++++++++++++++++++- src/facility.h | 25 ++++++++++++++++-- src/timer.cc | 4 +-- src/toolkit/scheduling_function.cc | 38 +++++++++++++++++++++++++++ src/toolkit/scheduling_function.h | 42 ++++++++++++++++++++++++++++++ src/trader.h | 3 ++- 7 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 src/toolkit/scheduling_function.cc create mode 100644 src/toolkit/scheduling_function.h diff --git a/src/cyclus.h b/src/cyclus.h index dfa37ec0fa..ff6aa58daa 100644 --- a/src/cyclus.h +++ b/src/cyclus.h @@ -79,6 +79,7 @@ extern "C" { #include "toolkit/symbolic_function_factories.h" #include "toolkit/symbolic_functions.h" #include "toolkit/timeseries.h" +#include "toolkit/scheduling_function.h" // Undefines isnan from pyne #ifdef isnan diff --git a/src/facility.cc b/src/facility.cc index 399c4b71ee..6ca07b41d2 100644 --- a/src/facility.cc +++ b/src/facility.cc @@ -10,6 +10,7 @@ #include "institution.h" #include "logger.h" #include "timer.h" +#include "toolkit/scheduling_function.h" namespace cyclus { @@ -30,7 +31,7 @@ void Facility::Build(Agent* parent) { context()->SchedDecom(this, exit_time()); } //all agents who have been build should want to immediately trade - EventRequest(); + InitialTrade(); } void Facility::EnterNotify() { @@ -69,6 +70,30 @@ void Facility::Tick(){ SetTraded(false); //archetype developers need to invoke this method in tick } +std::set Facility::GetSchedulingTime(){ + cyclus::toolkit::SchedulingFunctions sc(this); //not ideal.... this class instance will be made every tock... + sc.FixIncSchedule(); //FixIncSchedule schedules like cyclus 1.6v + std::set EventTime = sc.EventTime(); + sc.clear(); + return EventTime; +} + +void Facility::EventRequest(){ + for(int i: GetSchedulingTime()){ + context()->RegisterRequesters(i, this); + selftimes_.insert(i); + } +} + +void Facility::InitialTrade(){ + if(context()->time() ==0){ + context()->RegisterRequesters(1,this); //if sim_tims (t=0) register for time =1 + } + else if (context()->time()>0){ //if during sim_time >0 register for sim_time + context()->RegisterRequesters(context()->time(),this); + } +} + Region* Facility::GetParentRegion(int layer) { return dynamic_cast(GetAncestorOfKind("Region", layer)); } diff --git a/src/facility.h b/src/facility.h index eb33df4929..997a8d1861 100644 --- a/src/facility.h +++ b/src/facility.h @@ -127,13 +127,30 @@ class Facility : public TimeListener, public Agent, public Trader { return std::set::Ptr>(); } - // this is intended to be a default behavior should an archetype developer not invoke their own "EventRequest " - virtual void EventRequest(){context()->RegisterRequesters(context()->time() + 1, this);} + virtual void EventRequest(); //maybe an archetype dev will want to replace this + + // this is intended to be a default behavior should an archetype developer not invoke their own "Scheduling Function " + virtual std::set GetSchedulingTime(); + //within cycamore + // std::set GetSchedulingTime(){ + // cyclus::toolkit::SchedulingFuncs sc(this); + // std::set scheduletime = sc.();}; + // sc.clear() //(for next schedule time) + // return scheduletime; + //} + + void InitialTrade(); virtual void Tock(); virtual void Tick(); + //return all future events scheduled for some facility (this function is useful for deregistration context()->DeregisterRequesters(--) + // purposes and for archetype developer scheduled facility behavior) + const std::set& GetFutureEvents() const { + return selftimes_; + } + /// default implementation for material preferences. virtual void AdjustMatlPrefs(PrefMap::type& prefs) {} @@ -200,6 +217,10 @@ class Facility : public TimeListener, public Agent, public Trader { /// @brief Returns all parent facilities by traversing up the hierarchy /// @return Vector of all parent facilities, ordered from closest to farthest std::vector GetAllParentFacilities(); + + + private: + std::set selftimes_; }; } // namespace cyclus diff --git a/src/timer.cc b/src/timer.cc index cfbc09ee18..95bafc5d35 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -110,7 +110,7 @@ void Timer::DoResEx(ExchangeManager* matmgr, ExchangeManager* genmgr) { auto reg_traders = ctx_->EventRequesters(); //still unclear: do decom events require secondary registration for trades? - if(reg_traders.at(time_).size()>0){ + if(reg_traders[time_].size()>0){ matmgr->Execute(); genmgr->Execute(); } @@ -139,7 +139,7 @@ void Timer::DoTock() { } } auto reg_traders = ctx_->EventRequesters(); - if(reg_traders.at(time_).size()>0){ + if(reg_traders[time_].size()>0){ ctx_->EventComplete(time_); //to dereference some pointers, maybe applied to build/decom maps too if(reg_traders.count(reg_traders.lower_bound(time_ +1)->first) == 0){ diff --git a/src/toolkit/scheduling_function.cc b/src/toolkit/scheduling_function.cc new file mode 100644 index 0000000000..4d434ef935 --- /dev/null +++ b/src/toolkit/scheduling_function.cc @@ -0,0 +1,38 @@ +#include "scheduling_function.h" +#include "cyc_limits.h" + +namespace cyclus { +namespace toolkit { + +SchedulingFunctions::SchedulingFunctions(Facility* fac): //does this even need to be facility? + f(fac) {} + +void SchedulingFunctions::FixIncSchedule(){ + t_.insert(f->context()->time() + 1); //all these can be converted to context()->time() instead? //can be initialized only in enter notify +} + +void SchedulingFunctions::ConstantRequest(int cycle_length){ + t_.insert(f->context()->time() + cycle_length); +} + +void SchedulingFunctions::DemandDrivenRequests(ResBuf res){ + if (res.space() > eps_rsrc()) { + t_.insert(f->context()->time()+1); + } + else { + return; + } +} + +void SchedulingFunctions::PredefinedSchedule(std::set sched){ + //in order to use this function the entire schedule of a facilities requests should be mapped. + //do not invoke parent tock in facilities that use this. Add additional EventSchedule() to EnterNotify() instead. + t_ = sched; +} + +void SchedulingFunctions::clear(){ + t_.clear(); +} + +} // namespace toolkit +} // namespace cyclus \ No newline at end of file diff --git a/src/toolkit/scheduling_function.h b/src/toolkit/scheduling_function.h new file mode 100644 index 0000000000..49616fd94b --- /dev/null +++ b/src/toolkit/scheduling_function.h @@ -0,0 +1,42 @@ +#ifndef CYCLUS_SRC_TOOLKIT_SCHEDULING_FUNCTION_H_ +#define CYCLUS_SRC_TOOLKIT_SCHEDULING_FUNCTION_H_ + +#include "context.h" +#include "symbolic_functions.h" //I may add a symbolic functions later... +#include "facility.h" +#include "res_buf.h" +#include + +namespace cyclus { +namespace toolkit { +//these are a kit of functions to help the archetype developer start their own DRE event scheduling. + +class SchedulingFunctions { + +public: + SchedulingFunctions(Facility* fac); + +// deconstructor .. + +void DemandDrivenRequests(ResBuf res); + +void ConstantRequest(int cycle_length); + +void FixIncSchedule(); + +void clear(); + +void PredefinedSchedule(std::set sched); + +const std::set& EventTime() const {//schedule + return t_; + } + +private: + Facility* f; + std::set t_; //this may be sketchy with clear(), should i not have a variable and just have sched. func return event times? +}; + +} // namespace toolkit +} // namespace cyclus +#endif \ No newline at end of file diff --git a/src/trader.h b/src/trader.h index 9d11ce69a4..79cf8942e7 100644 --- a/src/trader.h +++ b/src/trader.h @@ -80,7 +80,8 @@ class Trader { virtual void EventRequest(){} // can be overridden ? - bool Traded; //follows DRE to assess whether trader completed trades + bool Traded; //follows DRE to assess whether trader completed trades; + // archetype devs may want to use this to assess event scheduling void SetTraded(bool status){Traded = status;} //setter for Traded From 086899c92b70b1285802a969a195989d5119ada9 Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Fri, 22 May 2026 13:15:04 -0700 Subject: [PATCH 27/28] print testing phase --- src/context.cc | 15 ++++++- src/context.h | 65 +++++++++++++++++++++++++++-- src/facility.cc | 65 ++++++++++++++++------------- src/facility.h | 21 +++++----- src/resource_exchange.h | 15 +++++-- src/timer.cc | 16 +++++--- src/toolkit/scheduling_function.cc | 66 ++++++++++++++++++++---------- src/toolkit/scheduling_function.h | 24 ++++++++--- src/trader.h | 8 +++- src/xml_file_loader.cc | 2 + 10 files changed, 216 insertions(+), 81 deletions(-) diff --git a/src/context.cc b/src/context.cc index 616e5a5af8..0f00149479 100644 --- a/src/context.cc +++ b/src/context.cc @@ -82,7 +82,7 @@ SimInfo::SimInfo(int dur, boost::uuids::uuid parent_sim, int branch_time, stride(kDefaultStride) {} Context::Context(Timer* ti, Recorder* rec) - : ti_(ti), rec_(rec), solver_(NULL), trans_id_(0), si_(0) { + : ti_(ti), rec_(rec), solver_(NULL), trans_id_(0), si_(0), testing({}) { rng_ = new RandomNumberGenerator(); } @@ -348,6 +348,19 @@ void Context::UnregisterTimeListener(TimeListener* tl) { ti_->UnregisterTimeListener(tl); } +void Context::UnregisterCommodityConsumer(std::set in_commods, Trader* e){ + return; + for (std::string commod : in_commods){ + commodity_consumers_.at(commod).erase(e); + } + } + +void Context::RegisterCommoditiesTraded(int t, std::set trade_commods){ + std::cout<NewDatum(title); } diff --git a/src/context.h b/src/context.h index adbd2a32dc..a96fc0234b 100644 --- a/src/context.h +++ b/src/context.h @@ -183,17 +183,68 @@ class Context { /// @return the current set of traders registered for resource exchange. inline const std::set& traders() const { return traders_; } - inline void RegisterRequesters(int time, Trader* e) {request_queue_[time].insert(e); } //conditions to register an event is up to archetype dev + ////////////////////////////////////////////////////////// discrete cyclus functions /////////////////// + + inline void RegisterCommodityConsumer(std::string in_commod, Trader* e){commodity_consumers_[in_commod].insert(e);} + + void UnregisterCommodityConsumer(std::set in_commods, Trader* e); + + inline const std::map>& consumers() const {return commodity_consumers_;} + + + void RegisterCommoditiesTraded(int t, std::set trade_commods); + + std::set& CommoditiesTraded(int t) {std::cout << "CTX REGISTER: " << this << "\n"; return commodities_traded_.at(t);} + +void test(int commod) +{ + testing.insert(std::move(commod)); +} + +inline const std::set& GetTest() const +{ + return testing; +} + +// void test(int commod) +// { +// testing = commod; +// } + +// inline int& GetTest() +// { +// return testing; +// } + +void stringtest(const std::string& commod) +{ + stringtesting = commod; +} + +inline const std::string& GetStringTest() const +{ + return stringtesting; +} + + inline void RegisterRequesters(int time, Trader* e) { + std::cout<<"iam requesting \n" ; request_queue_[time].insert(e); + } //conditions to register an event is up to archetype dev inline void EventComplete(int t) {request_queue_.erase(t);} // fit this so it purges any 0 entries as well as the most current completed event ! - inline const std::map>& EventRequesters() const { return request_queue_; } + inline const std::set& EventRequesters(int t) const {std::cout << "CTX REGISTER: " << this << "\n"; return request_queue_.at(t); } + + inline const std::map>& EventTimeline() const { return request_queue_; } + + //// currently unused inline void Populate(int t) {if (pop_sched_.count(t)>0){request_queue_.at(t) = traders();};} //there are more use cases for this inline void SchedPopulate(int next_event) {pop_sched_.insert(next_event); request_queue_[next_event];} // there are more use cases for this - inline void DeregisterRequesters(int time, Trader* e) {request_queue_[time].erase(e);} //conditions to deregister an event is up to archetype dev + inline void DeregisterRequesters(int time, Trader* e) {request_queue_.at(time).erase(e);} //conditions to deregister an event is up to archetype dev + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Create a new agent by cloning the named prototype. The returned agent is /// not initialized as a simulation participant. @@ -382,10 +433,16 @@ class Context { std::map transport_units_; std::set agent_list_; std::set traders_; + std::map> request_queue_; + std::map> commodity_consumers_; + std::map> commodities_traded_; + std::set pop_sched_; + std::set testing; + std::string stringtesting; + std::map n_prototypes_; std::map n_specs_; - std::set pop_sched_; SimInfo si_; Timer* ti_; ExchangeSolver* solver_; diff --git a/src/facility.cc b/src/facility.cc index 6ca07b41d2..6ee067cdce 100644 --- a/src/facility.cc +++ b/src/facility.cc @@ -10,11 +10,12 @@ #include "institution.h" #include "logger.h" #include "timer.h" -#include "toolkit/scheduling_function.h" +#include +#include namespace cyclus { -Facility::Facility(Context* ctx) : Trader(this), Agent(ctx) { +Facility::Facility(Context* ctx) : Trader(this), Agent(ctx), schedule_helper_(this) { kind_ = std::string("Facility"); } @@ -26,19 +27,37 @@ void Facility::InitFrom(Facility* m) { void Facility::Build(Agent* parent) { Agent::Build(parent); - //for agents WITHOUT the need for a checkdecom function, they can easily schedule decom at build (only reactor/separations use this right now) - if (lifetime() >= 0 && CheckDecommissionCondition() == NULL) { - context()->SchedDecom(this, exit_time()); + //for agents WITHOUT the need for a checkdecom status, they can easily schedule decom at build (only reactor/separations use this right now) + // if (lifetime() >= 0 && CheckDecommissionCondition() == NULL) { + // context()->SchedDecom(this, exit_time()); + // } + for (auto& requests: GetMatlRequests()) { + if(requests){ + for(auto& request : requests->requests()) { + // //hopefully this is a dry run with no impact on DRE (ie adding porfolios) + std::string commodity = request->commodity(); + context()->RegisterCommodityConsumer(commodity,this); + FillInCommods(1); //("commodity"); //any repeats should be + std::cout<test(17); + context()->stringtest("velma"); + } + } } - //all agents who have been build should want to immediately trade - InitialTrade(); + std::cout<< GetInCommods().size()<<"in fac the incommods in trader is \n\n\n"; + std::cout<GetStringTest()<<"getting string test in build \n\n\n"; + context()->RegisterCommoditiesTraded(context()->time(), {"spent_uox"});//GetInCommods()); + std::cout<<(context()->CommoditiesTraded(0)).size()<<"commodities traded in f\n"; + std::cout<RegisterTrader(dynamic_cast(this)); context()->RegisterTimeListener(this); - // maybe have a context()->RegisterCommodityConsumer(this); + schedule_helper_.InitialTrade(); + //all agents who have been build should want to immediately trade } std::string Facility::str() { @@ -55,6 +74,8 @@ void Facility::Decommission() { context()->UnregisterTrader(dynamic_cast(this)); context()->UnregisterTimeListener(this); + //context()->UnregisterCommodityConsumer(in_commods_,this); + Agent::Decommission(); } @@ -67,31 +88,17 @@ void Facility::Tock(){ // archetype developers need to invoke this method in toc } void Facility::Tick(){ + //std::cout<<(context()->GetTest()).size()<<"\n\n"; + std::cout<GetStringTest()<<"getting string test \n\n\n"; + std::cout<< GetInCommods().size()<<"in fac tick the incommods in trader is \n\n\n"; SetTraded(false); //archetype developers need to invoke this method in tick } -std::set Facility::GetSchedulingTime(){ - cyclus::toolkit::SchedulingFunctions sc(this); //not ideal.... this class instance will be made every tock... - sc.FixIncSchedule(); //FixIncSchedule schedules like cyclus 1.6v - std::set EventTime = sc.EventTime(); - sc.clear(); - return EventTime; -} - void Facility::EventRequest(){ - for(int i: GetSchedulingTime()){ - context()->RegisterRequesters(i, this); - selftimes_.insert(i); - } -} - -void Facility::InitialTrade(){ - if(context()->time() ==0){ - context()->RegisterRequesters(1,this); //if sim_tims (t=0) register for time =1 - } - else if (context()->time()>0){ //if during sim_time >0 register for sim_time - context()->RegisterRequesters(context()->time(),this); - } + // schedule_helper_.FixIncSchedule(); //FixIncSchedule schedules like cyclus 1.6v + // for(int i: schedule_helper_.EventTime()){ //probably needed in future... + // selftimes_.insert(i); + // } } Region* Facility::GetParentRegion(int layer) { diff --git a/src/facility.h b/src/facility.h index 997a8d1861..4a8f46301e 100644 --- a/src/facility.h +++ b/src/facility.h @@ -8,6 +8,7 @@ #include "agent.h" #include "time_listener.h" #include "trader.h" +#include "toolkit/scheduling_function.h" namespace cyclus { @@ -128,29 +129,25 @@ class Facility : public TimeListener, public Agent, public Trader { } virtual void EventRequest(); //maybe an archetype dev will want to replace this - // this is intended to be a default behavior should an archetype developer not invoke their own "Scheduling Function " - virtual std::set GetSchedulingTime(); //within cycamore - // std::set GetSchedulingTime(){ - // cyclus::toolkit::SchedulingFuncs sc(this); - // std::set scheduletime = sc.();}; - // sc.clear() //(for next schedule time) - // return scheduletime; + // void EventRequest(){ + //schedule_helper_.(args);; + // or more directly schedule_helper.schedule(time,commods) //} - void InitialTrade(); - virtual void Tock(); virtual void Tick(); + // inline const std::set& GetInCommods() const {return in_commods_;} + //return all future events scheduled for some facility (this function is useful for deregistration context()->DeregisterRequesters(--) // purposes and for archetype developer scheduled facility behavior) - const std::set& GetFutureEvents() const { + inline const std::set& GetFutureEvents() const { return selftimes_; } - + /// default implementation for material preferences. virtual void AdjustMatlPrefs(PrefMap::type& prefs) {} @@ -221,6 +218,8 @@ class Facility : public TimeListener, public Agent, public Trader { private: std::set selftimes_; + // std::set in_commods_; + toolkit::SchedulingFunctions schedule_helper_; }; } // namespace cyclus diff --git a/src/resource_exchange.h b/src/resource_exchange.h index 986c79b64b..073f146a31 100644 --- a/src/resource_exchange.h +++ b/src/resource_exchange.h @@ -113,13 +113,22 @@ template class ResourceExchange { } void InitRequesters() { - auto map = sim_ctx_->EventRequesters(); - std::set orig = map.at(sim_ctx_->time()); + auto orig = InitRequestersAdjacent(); //we do not need the whole ass map tbh. std::set::iterator it; for (it = orig.begin(); it != orig.end(); ++it) { requesters_.insert(*it); } - } + } + + std::set InitRequestersAdjacent() { + std::set traders; + // auto commod_map = sim_ctx_->consumers(); + // auto map2 = sim_ctx_->CommoditiesTraded(sim_ctx_->time()); + // for (std::string commods : map2){ + // traders.merge(commod_map[commods]); + // } + return traders; + } /// @brief queries a given facility agent for void AddRequests_(Trader* t) { diff --git a/src/timer.cc b/src/timer.cc index 95bafc5d35..c8bf35b74a 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -89,7 +89,6 @@ void Timer::DoBuild() { if (parent != NULL) { parent->BuildNotify(m); } else { - CLOG(LEV_DEBUG1) << "Hey! Listen! Built an Agent without a Parent."; } } } @@ -108,9 +107,16 @@ void Timer::DoTick() { void Timer::DoResEx(ExchangeManager* matmgr, ExchangeManager* genmgr) { - auto reg_traders = ctx_->EventRequesters(); + auto reg_traders = ctx_->EventRequesters(time_); + std::cout <<"TESTING:"<< (ctx_->GetTest()).size()<<"\n\n\n\n"; + std::cout <<"TESTING string:"<< (ctx_->GetStringTest())<<"\n\n\n\n"; + for (auto& trader : reg_traders){ + std::cout<< (trader->GetInCommods()).size()<<"\n\n\n"; + } + std::cout<CommoditiesTraded(0)).size()<<"\n\n\n\n"; //still unclear: do decom events require secondary registration for trades? - if(reg_traders[time_].size()>0){ + if(reg_traders.size()>0){ matmgr->Execute(); genmgr->Execute(); } @@ -138,7 +144,7 @@ void Timer::DoTock() { } } } - auto reg_traders = ctx_->EventRequesters(); + auto reg_traders = ctx_->EventTimeline(); if(reg_traders[time_].size()>0){ ctx_->EventComplete(time_); //to dereference some pointers, maybe applied to build/decom maps too @@ -243,7 +249,7 @@ void Timer::UnregisterTimeListener(TimeListener* tl) { } int Timer::NextEvent(){ - auto reg_traders = ctx_->EventRequesters(); + auto reg_traders = ctx_->EventTimeline(); int t_p = time_ +1; std::vector event_lists = {decom_queue_.lower_bound(t_p)->first,build_queue_.lower_bound(t_p)->first, reg_traders.lower_bound(t_p)->first}; diff --git a/src/toolkit/scheduling_function.cc b/src/toolkit/scheduling_function.cc index 4d434ef935..3f99cd4390 100644 --- a/src/toolkit/scheduling_function.cc +++ b/src/toolkit/scheduling_function.cc @@ -1,38 +1,62 @@ #include "scheduling_function.h" #include "cyc_limits.h" +#include "facility.h" namespace cyclus { namespace toolkit { -SchedulingFunctions::SchedulingFunctions(Facility* fac): //does this even need to be facility? - f(fac) {} -void SchedulingFunctions::FixIncSchedule(){ - t_.insert(f->context()->time() + 1); //all these can be converted to context()->time() instead? //can be initialized only in enter notify -} +SchedulingFunctions::SchedulingFunctions(Facility* fac): + f_(fac) {} -void SchedulingFunctions::ConstantRequest(int cycle_length){ - t_.insert(f->context()->time() + cycle_length); -} +void SchedulingFunctions::Scheduler(int t, std::set in_commods){ + f_-> context()-> RegisterRequesters(t, f_); + f_-> context()-> RegisterCommoditiesTraded(t, in_commods); + t_.insert(t); +} //archetype developers can also call this method to schedule some time directly with context +// from their own scheduling function/parameters -void SchedulingFunctions::DemandDrivenRequests(ResBuf res){ - if (res.space() > eps_rsrc()) { - t_.insert(f->context()->time()+1); - } - else { - return; - } -} +// void SchedulingFunctions::FixIncSchedule(){ +// Scheduler(FacilityTime()+ 1, f_->GetInCommods()); +// } -void SchedulingFunctions::PredefinedSchedule(std::set sched){ - //in order to use this function the entire schedule of a facilities requests should be mapped. - //do not invoke parent tock in facilities that use this. Add additional EventSchedule() to EnterNotify() instead. - t_ = sched; -} +// void SchedulingFunctions::ConstantRequest(int cycle_length, std::set commods){ +// Scheduler(FacilityTime() + cycle_length, commods); +// } + +// void SchedulingFunctions::DemandDrivenRequests(ResBuf res,std::set commods){ +// if (res.space() > eps_rsrc()) { +// Scheduler(FacilityTime()+1, commods); +// } +// else { +// return; +// } +// } + +// void SchedulingFunctions::PredefinedSchedule(std::set sched){ +// //in order to use this function the entire schedule of a facilities requests should be mapped. +// //do not invoke parent tock in facilities that use this. Add additional EventSchedule() to EnterNotify() instead. +// t_ = sched; +// } void SchedulingFunctions::clear(){ t_.clear(); } +void SchedulingFunctions::InitialTrade(){ + f_-> context()-> RegisterRequesters(FacilityTime(), f_); + //i changed this from the original +// if(FacilityTime() == 0){ +// Scheduler(1, f_->GetInCommods()); +// } +// else if (FacilityTime() > 0){ //if during sim_time >0 register for sim_time +// Scheduler(FacilityTime(),f_->GetInCommods()); +// } +} + +int SchedulingFunctions::FacilityTime(){ + return f_->context()->time(); +} + } // namespace toolkit } // namespace cyclus \ No newline at end of file diff --git a/src/toolkit/scheduling_function.h b/src/toolkit/scheduling_function.h index 49616fd94b..ca13f6b431 100644 --- a/src/toolkit/scheduling_function.h +++ b/src/toolkit/scheduling_function.h @@ -3,13 +3,18 @@ #include "context.h" #include "symbolic_functions.h" //I may add a symbolic functions later... -#include "facility.h" #include "res_buf.h" #include namespace cyclus { + +class Facility; + namespace toolkit { //these are a kit of functions to help the archetype developer start their own DRE event scheduling. +//the dev can use as many functions as they want in the GetSchedulingTime() override ... +// because of that fact there is an time_stamp set with an associated commodity pair (which times they want to trade what) getter function +// class SchedulingFunctions { @@ -18,23 +23,30 @@ class SchedulingFunctions { // deconstructor .. -void DemandDrivenRequests(ResBuf res); +// void DemandDrivenRequests(ResBuf res,std::set commods); -void ConstantRequest(int cycle_length); +// void ConstantRequest(int cycle_length, std::set commods); void FixIncSchedule(); void clear(); -void PredefinedSchedule(std::set sched); +void InitialTrade(); + +int FacilityTime(); + +void Scheduler(int t, std::set in_commods); + +//void PredefinedSchedule(std::set sched); const std::set& EventTime() const {//schedule return t_; - } +} private: - Facility* f; + Facility* f_; std::set t_; //this may be sketchy with clear(), should i not have a variable and just have sched. func return event times? + std::set in_commods_; }; } // namespace toolkit diff --git a/src/trader.h b/src/trader.h index 79cf8942e7..064aa455f3 100644 --- a/src/trader.h +++ b/src/trader.h @@ -87,8 +87,14 @@ class Trader { bool ReturnTraded(){return Traded;} //getter for Traded - protected: + void FillInCommods(int commod){std::cout<< "here in trader FillCommods:"; in_commods_.insert(commod);} + + std::set GetInCommods() {return in_commods_;} + std::set in_commods_; + + protected: Agent* manager_; + private: /// @warning this function is hidden to prevent an invalid signature that can /// raise difficult to find bugs diff --git a/src/xml_file_loader.cc b/src/xml_file_loader.cc index 78fefe6e98..bd24f25203 100644 --- a/src/xml_file_loader.cc +++ b/src/xml_file_loader.cc @@ -465,7 +465,9 @@ void XMLFileLoader::LoadInitialAgents() { Agent* XMLFileLoader::BuildAgent(std::string proto, Agent* parent) { Agent* m = ctx_->CreateAgent(proto); + std::cout<<"\033[92m PEEPEE\n"; m->Build(parent); + std::cout<<"POOPOO\033[0m\n"; if (parent != NULL) { parent->BuildNotify(m); } From 7c802fecab0180df7417c021873d8d0ea2da2506 Mon Sep 17 00:00:00 2001 From: meg-krieg Date: Fri, 29 May 2026 11:03:11 -0700 Subject: [PATCH 28/28] deleting some debugging comments --- src/context.cc | 6 ++-- src/context.h | 41 +++----------------------- src/facility.cc | 34 +++++++++------------- src/facility.h | 4 --- src/resource_exchange.h | 10 +++---- src/timer.cc | 9 ++---- src/toolkit/scheduling_function.cc | 46 +++++++++++++++--------------- src/toolkit/scheduling_function.h | 7 ++--- src/trader.h | 7 +++-- src/xml_file_loader.cc | 2 -- 10 files changed, 56 insertions(+), 110 deletions(-) diff --git a/src/context.cc b/src/context.cc index 0f00149479..51324d8158 100644 --- a/src/context.cc +++ b/src/context.cc @@ -82,7 +82,7 @@ SimInfo::SimInfo(int dur, boost::uuids::uuid parent_sim, int branch_time, stride(kDefaultStride) {} Context::Context(Timer* ti, Recorder* rec) - : ti_(ti), rec_(rec), solver_(NULL), trans_id_(0), si_(0), testing({}) { + : ti_(ti), rec_(rec), solver_(NULL), trans_id_(0), si_(0) { rng_ = new RandomNumberGenerator(); } @@ -356,9 +356,7 @@ void Context::UnregisterCommodityConsumer(std::set in_commods, Trad } void Context::RegisterCommoditiesTraded(int t, std::set trade_commods){ - std::cout< trade_commods); - std::set& CommoditiesTraded(int t) {std::cout << "CTX REGISTER: " << this << "\n"; return commodities_traded_.at(t);} - -void test(int commod) -{ - testing.insert(std::move(commod)); -} - -inline const std::set& GetTest() const -{ - return testing; -} - -// void test(int commod) -// { -// testing = commod; -// } - -// inline int& GetTest() -// { -// return testing; -// } - -void stringtest(const std::string& commod) -{ - stringtesting = commod; -} - -inline const std::string& GetStringTest() const -{ - return stringtesting; -} - - inline void RegisterRequesters(int time, Trader* e) { - std::cout<<"iam requesting \n" ; request_queue_[time].insert(e); + inline std::set& CommoditiesTraded(int t) {return commodities_traded_.at(t);} + + inline void RegisterRequesters(int time, Trader* e) {request_queue_[time].insert(e); } //conditions to register an event is up to archetype dev inline void EventComplete(int t) {request_queue_.erase(t);} // fit this so it purges any 0 entries as well as the most current completed event ! - inline const std::set& EventRequesters(int t) const {std::cout << "CTX REGISTER: " << this << "\n"; return request_queue_.at(t); } + inline const std::set& EventRequesters(int t) const {return request_queue_.at(t); } inline const std::map>& EventTimeline() const { return request_queue_; } @@ -438,8 +407,6 @@ inline const std::string& GetStringTest() const std::map> commodity_consumers_; std::map> commodities_traded_; std::set pop_sched_; - std::set testing; - std::string stringtesting; std::map n_prototypes_; std::map n_specs_; diff --git a/src/facility.cc b/src/facility.cc index 6ee067cdce..beb04fbb37 100644 --- a/src/facility.cc +++ b/src/facility.cc @@ -28,32 +28,27 @@ void Facility::InitFrom(Facility* m) { void Facility::Build(Agent* parent) { Agent::Build(parent); //for agents WITHOUT the need for a checkdecom status, they can easily schedule decom at build (only reactor/separations use this right now) - // if (lifetime() >= 0 && CheckDecommissionCondition() == NULL) { - // context()->SchedDecom(this, exit_time()); - // } + if (lifetime() >= 0 && CheckDecommissionCondition() == NULL) { + context()->SchedDecom(this, exit_time()); + } for (auto& requests: GetMatlRequests()) { if(requests){ for(auto& request : requests->requests()) { // //hopefully this is a dry run with no impact on DRE (ie adding porfolios) std::string commodity = request->commodity(); context()->RegisterCommodityConsumer(commodity,this); - FillInCommods(1); //("commodity"); //any repeats should be - std::cout<test(17); - context()->stringtest("velma"); + FillInCommods(commodity); //any repeats should be } } } - std::cout<< GetInCommods().size()<<"in fac the incommods in trader is \n\n\n"; - std::cout<GetStringTest()<<"getting string test in build \n\n\n"; - context()->RegisterCommoditiesTraded(context()->time(), {"spent_uox"});//GetInCommods()); - std::cout<<(context()->CommoditiesTraded(0)).size()<<"commodities traded in f\n"; - std::cout< RegisterCommoditiesTraded(context()->time(), GetInCommods()); + std::cout <<"Context commodity map size called in Facility::Build is "<< (context()->CommoditiesTraded(context()->time())).size()<<" (not empty) \n\n\n\n"; } void Facility::EnterNotify() { Agent::EnterNotify(); - std::cout<RegisterTrader(dynamic_cast(this)); context()->RegisterTimeListener(this); schedule_helper_.InitialTrade(); @@ -74,7 +69,7 @@ void Facility::Decommission() { context()->UnregisterTrader(dynamic_cast(this)); context()->UnregisterTimeListener(this); - //context()->UnregisterCommodityConsumer(in_commods_,this); + context()->UnregisterCommodityConsumer(GetInCommods(),this); Agent::Decommission(); } @@ -88,17 +83,14 @@ void Facility::Tock(){ // archetype developers need to invoke this method in toc } void Facility::Tick(){ - //std::cout<<(context()->GetTest()).size()<<"\n\n"; - std::cout<GetStringTest()<<"getting string test \n\n\n"; - std::cout<< GetInCommods().size()<<"in fac tick the incommods in trader is \n\n\n"; SetTraded(false); //archetype developers need to invoke this method in tick } void Facility::EventRequest(){ - // schedule_helper_.FixIncSchedule(); //FixIncSchedule schedules like cyclus 1.6v - // for(int i: schedule_helper_.EventTime()){ //probably needed in future... - // selftimes_.insert(i); - // } + schedule_helper_.FixIncSchedule(); //FixIncSchedule schedules like cyclus 1.6v + for(int i: schedule_helper_.EventTime()){ //probably needed in future... + selftimes_.insert(i); + } } Region* Facility::GetParentRegion(int layer) { diff --git a/src/facility.h b/src/facility.h index 4a8f46301e..8a108e2d06 100644 --- a/src/facility.h +++ b/src/facility.h @@ -140,8 +140,6 @@ class Facility : public TimeListener, public Agent, public Trader { virtual void Tick(); - // inline const std::set& GetInCommods() const {return in_commods_;} - //return all future events scheduled for some facility (this function is useful for deregistration context()->DeregisterRequesters(--) // purposes and for archetype developer scheduled facility behavior) inline const std::set& GetFutureEvents() const { @@ -160,7 +158,6 @@ class Facility : public TimeListener, public Agent, public Trader { virtual void GetMatlTrades( const std::vector>& trades, std::vector, Material::Ptr>>& responses) { - std::cout << "in material facility getmatltrades\n"; } /// @brief default implementation for responding to product trades @@ -218,7 +215,6 @@ class Facility : public TimeListener, public Agent, public Trader { private: std::set selftimes_; - // std::set in_commods_; toolkit::SchedulingFunctions schedule_helper_; }; diff --git a/src/resource_exchange.h b/src/resource_exchange.h index 073f146a31..41da99d987 100644 --- a/src/resource_exchange.h +++ b/src/resource_exchange.h @@ -122,11 +122,11 @@ template class ResourceExchange { std::set InitRequestersAdjacent() { std::set traders; - // auto commod_map = sim_ctx_->consumers(); - // auto map2 = sim_ctx_->CommoditiesTraded(sim_ctx_->time()); - // for (std::string commods : map2){ - // traders.merge(commod_map[commods]); - // } + auto commod_map = sim_ctx_->consumers(); + auto map2 = sim_ctx_->CommoditiesTraded(sim_ctx_->time()); + for (std::string commods : map2){ + traders.merge(commod_map[commods]); + } return traders; } diff --git a/src/timer.cc b/src/timer.cc index c8bf35b74a..542dc366c0 100644 --- a/src/timer.cc +++ b/src/timer.cc @@ -108,13 +108,8 @@ void Timer::DoTick() { void Timer::DoResEx(ExchangeManager* matmgr, ExchangeManager* genmgr) { auto reg_traders = ctx_->EventRequesters(time_); - std::cout <<"TESTING:"<< (ctx_->GetTest()).size()<<"\n\n\n\n"; - std::cout <<"TESTING string:"<< (ctx_->GetStringTest())<<"\n\n\n\n"; - for (auto& trader : reg_traders){ - std::cout<< (trader->GetInCommods()).size()<<"\n\n\n"; - } - std::cout<CommoditiesTraded(0)).size()<<"\n\n\n\n"; + std::cout <<"Context commodity map size called in Timer is"<< (ctx_->CommoditiesTraded(time_)).size()<<" (empty) \n\n\n\n"; + std::cout<<"Context discrete-registered traders map size is "<0){ matmgr->Execute(); diff --git a/src/toolkit/scheduling_function.cc b/src/toolkit/scheduling_function.cc index 3f99cd4390..ee72ad97e2 100644 --- a/src/toolkit/scheduling_function.cc +++ b/src/toolkit/scheduling_function.cc @@ -16,35 +16,35 @@ void SchedulingFunctions::Scheduler(int t, std::set in_commods){ } //archetype developers can also call this method to schedule some time directly with context // from their own scheduling function/parameters -// void SchedulingFunctions::FixIncSchedule(){ -// Scheduler(FacilityTime()+ 1, f_->GetInCommods()); -// } - -// void SchedulingFunctions::ConstantRequest(int cycle_length, std::set commods){ -// Scheduler(FacilityTime() + cycle_length, commods); -// } - -// void SchedulingFunctions::DemandDrivenRequests(ResBuf res,std::set commods){ -// if (res.space() > eps_rsrc()) { -// Scheduler(FacilityTime()+1, commods); -// } -// else { -// return; -// } -// } - -// void SchedulingFunctions::PredefinedSchedule(std::set sched){ -// //in order to use this function the entire schedule of a facilities requests should be mapped. -// //do not invoke parent tock in facilities that use this. Add additional EventSchedule() to EnterNotify() instead. -// t_ = sched; -// } +void SchedulingFunctions::FixIncSchedule(){ + Scheduler(FacilityTime()+ 1, f_->GetInCommods()); +} + +void SchedulingFunctions::ConstantRequest(int cycle_length, std::set commods){ + Scheduler(FacilityTime() + cycle_length, commods); +} + +void SchedulingFunctions::DemandDrivenRequests(ResBuf res,std::set commods){ + if (res.space() > eps_rsrc()) { + Scheduler(FacilityTime()+1, commods); + } + else { + return; + } +} + +void SchedulingFunctions::PredefinedSchedule(std::set sched){ + //in order to use this function the entire schedule of a facilities requests should be mapped. + //do not invoke parent tock in facilities that use this. Add additional EventSchedule() to EnterNotify() instead. + t_ = sched; +} void SchedulingFunctions::clear(){ t_.clear(); } void SchedulingFunctions::InitialTrade(){ - f_-> context()-> RegisterRequesters(FacilityTime(), f_); + Scheduler(FacilityTime(),f_->GetInCommods()); //i changed this from the original // if(FacilityTime() == 0){ // Scheduler(1, f_->GetInCommods()); diff --git a/src/toolkit/scheduling_function.h b/src/toolkit/scheduling_function.h index ca13f6b431..9b1d31e408 100644 --- a/src/toolkit/scheduling_function.h +++ b/src/toolkit/scheduling_function.h @@ -23,9 +23,9 @@ class SchedulingFunctions { // deconstructor .. -// void DemandDrivenRequests(ResBuf res,std::set commods); +void DemandDrivenRequests(ResBuf res,std::set commods); -// void ConstantRequest(int cycle_length, std::set commods); +void ConstantRequest(int cycle_length, std::set commods); void FixIncSchedule(); @@ -37,7 +37,7 @@ int FacilityTime(); void Scheduler(int t, std::set in_commods); -//void PredefinedSchedule(std::set sched); +void PredefinedSchedule(std::set sched); const std::set& EventTime() const {//schedule return t_; @@ -46,7 +46,6 @@ const std::set& EventTime() const {//schedule private: Facility* f_; std::set t_; //this may be sketchy with clear(), should i not have a variable and just have sched. func return event times? - std::set in_commods_; }; } // namespace toolkit diff --git a/src/trader.h b/src/trader.h index 064aa455f3..557cd1b0e9 100644 --- a/src/trader.h +++ b/src/trader.h @@ -87,10 +87,9 @@ class Trader { bool ReturnTraded(){return Traded;} //getter for Traded - void FillInCommods(int commod){std::cout<< "here in trader FillCommods:"; in_commods_.insert(commod);} + void FillInCommods(std::string commod){in_commods_.insert(commod);} - std::set GetInCommods() {return in_commods_;} - std::set in_commods_; + std::set GetInCommods() {return in_commods_;} protected: Agent* manager_; @@ -98,6 +97,8 @@ class Trader { private: /// @warning this function is hidden to prevent an invalid signature that can /// raise difficult to find bugs + std::set in_commods_; + virtual std::set::Ptr> GetMatlBids( const CommodMap::type& commod_requests) { return std::set::Ptr>(); diff --git a/src/xml_file_loader.cc b/src/xml_file_loader.cc index bd24f25203..78fefe6e98 100644 --- a/src/xml_file_loader.cc +++ b/src/xml_file_loader.cc @@ -465,9 +465,7 @@ void XMLFileLoader::LoadInitialAgents() { Agent* XMLFileLoader::BuildAgent(std::string proto, Agent* parent) { Agent* m = ctx_->CreateAgent(proto); - std::cout<<"\033[92m PEEPEE\n"; m->Build(parent); - std::cout<<"POOPOO\033[0m\n"; if (parent != NULL) { parent->BuildNotify(m); }