diff --git a/CHANGELOG.md b/CHANGELOG.md index 592d95c5f1..1340ab1cba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Fixed +- Add check when capital recovery period is zero and investment costs are + non-zero in multi-stage GenX (#666) - Fix write_status with UCommit = WriteShadowPrices = 1 (#645) ## [0.3.7] - 2024-04-02 diff --git a/src/multi_stage/configure_multi_stage_inputs.jl b/src/multi_stage/configure_multi_stage_inputs.jl index cb09042f03..5bdc025e89 100644 --- a/src/multi_stage/configure_multi_stage_inputs.jl +++ b/src/multi_stage/configure_multi_stage_inputs.jl @@ -21,26 +21,39 @@ NOTE: The inv\_costs\_yr and crp arrays must be the same length; values with the returns: array object containing overnight capital costs, the discounted sum of annual investment costs incured within the model horizon. """ -function compute_overnight_capital_cost(settings_d::Dict,inv_costs_yr::Array,crp::Array, tech_wacc::Array) +function compute_overnight_capital_cost(settings_d::Dict, + inv_costs_yr::Array, + crp::Array, + tech_wacc::Array) + + # Check for resources with non-zero investment costs and a Capital_Recovery_Period value of 0 years + if any((crp .== 0) .& (inv_costs_yr .> 0)) + msg = "You have some resources with non-zero investment costs and a Capital_Recovery_Period value of 0 years.\n" * + "These resources will have a calculated overnight capital cost of \$0. Correct your inputs if this is a mistake.\n" + error(msg) + end - cur_stage = settings_d["CurStage"] # Current model - num_stages = settings_d["NumStages"] # Total number of model stages - stage_lens = settings_d["StageLengths"] + cur_stage = settings_d["CurStage"] # Current model + num_stages = settings_d["NumStages"] # Total number of model stages + stage_lens = settings_d["StageLengths"] - # 1) For each resource, find the minimum of the capital recovery period and the end of the model horizon - # Total time between the end of the final model stage and the start of the current stage - model_yrs_remaining = sum(stage_lens[cur_stage:end]) + # 1) For each resource, find the minimum of the capital recovery period and the end of the model horizon + # Total time between the end of the final model stage and the start of the current stage + model_yrs_remaining = sum(stage_lens[cur_stage:end]; init = 0) # We will sum annualized costs through the full capital recovery period or the end of planning horizon, whichever comes first payment_yrs_remaining = min.(crp, model_yrs_remaining) - # KEY ASSUMPTION: Investment costs after the planning horizon are fully recoverable, so we don't need to include these costs - # 2) Compute the present value of investment associated with capital recovery period within the model horizon - discounting to year 1 and not year 0 - # (Factor to adjust discounting to year 0 for capital cost is included in the discounting coefficient applied to all terms in the objective function value.) - occ = zeros(length(inv_costs_yr)) - for i in 1:length(occ) - occ[i] = sum(inv_costs_yr[i]/(1+tech_wacc[i]) .^ (p) for p=1:payment_yrs_remaining[i]) - end + # KEY ASSUMPTION: Investment costs after the planning horizon are fully recoverable, so we don't need to include these costs + # 2) Compute the present value of investment associated with capital recovery period within the model horizon - discounting to year 1 and not year 0 + # (Factor to adjust discounting to year 0 for capital cost is included in the discounting coefficient applied to all terms in the objective function value.) + occ = zeros(length(inv_costs_yr)) + for i in 1:length(occ) + occ[i] = sum( + inv_costs_yr[i] / (1 + tech_wacc[i]) .^ (p) + for p in 1:payment_yrs_remaining[i]; + init = 0) + end # 3) Return the overnight capital cost (discounted sum of annual investment costs incured within the model horizon) return occ