Skip to content

Commit

Permalink
Merge branch 'apply_ratchets_to_per_kw_charges' of https://github.com…
Browse files Browse the repository at this point in the history
…/NREL/ssc into develop
  • Loading branch information
brtietz committed Nov 9, 2021
2 parents 7e84b8d + c4243bf commit 8e9dcb0
Show file tree
Hide file tree
Showing 8 changed files with 453 additions and 180 deletions.
2 changes: 2 additions & 0 deletions shared/lib_utility_rate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ double UtilityRateForecast::forecastCost(std::vector<double>& predicted_loads, s
}

// Get previous peak cost - may need to run two months
rate->set_billing_demands();
double previousDemandCharge = rate->get_demand_charge(month, year);
double previousEnergyCharge = 0;
if (rate->enable_nm)
Expand Down Expand Up @@ -268,6 +269,7 @@ double UtilityRateForecast::forecastCost(std::vector<double>& predicted_loads, s
}

// Compute new peak cost - may need to run two months
rate->set_billing_demands();
double newDemandCharge = rate->get_demand_charge(month, year);
// If forecast length is 1, restartMonth won't be triggered on the next forecast. Trigger it now
if (crossing_month && n == 1)
Expand Down
104 changes: 72 additions & 32 deletions shared/lib_utility_rate_equations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,13 @@ rate_data::rate_data() :
dc_hourly_peak(),
monthly_dc_fixed(12),
monthly_dc_tou(12),
en_ec_billing_demand(false),
uses_billing_demand(false),
en_billing_demand_lookback(false),
prev_peak_demand(12),
ec_bd_lookback_percents(12),
ec_bd_minimum(0.0),
ec_bd_lookback_months(1),
bd_lookback_percents(12),
bd_minimum(0.0),
bd_lookback_months(1),
bd_tou_periods(),
billing_demand(12),
tou_demand_single_peak(false),
enable_nm(false),
Expand All @@ -160,11 +162,13 @@ rate_data::rate_data(const rate_data& tmp) :
dc_hourly_peak(tmp.dc_hourly_peak),
monthly_dc_fixed(tmp.monthly_dc_fixed),
monthly_dc_tou(tmp.monthly_dc_tou),
en_ec_billing_demand(tmp.en_ec_billing_demand),
uses_billing_demand(tmp.uses_billing_demand),
en_billing_demand_lookback(tmp.en_billing_demand_lookback),
prev_peak_demand(tmp.prev_peak_demand),
ec_bd_lookback_percents(tmp.ec_bd_lookback_percents),
ec_bd_minimum(tmp.ec_bd_minimum),
ec_bd_lookback_months(tmp.ec_bd_lookback_months),
bd_lookback_percents(tmp.bd_lookback_percents),
bd_minimum(tmp.bd_minimum),
bd_lookback_months(tmp.bd_lookback_months),
bd_tou_periods(tmp.bd_tou_periods),
billing_demand(tmp.billing_demand),
tou_demand_single_peak(tmp.tou_demand_single_peak),
enable_nm(tmp.enable_nm),
Expand Down Expand Up @@ -215,37 +219,64 @@ bool rate_data::check_for_kwh_per_kw_rate(int units) {

double rate_data::get_billing_demand(int month) {
int m = 0;
double billing_demand = ec_bd_minimum;
int prev_yr_lookback = 11 - (ec_bd_lookback_months - month); // What month do we stop looking back in the prev yr?
double billing_demand = bd_minimum;
int prev_yr_lookback = 11 - (bd_lookback_months - month); // What month do we stop looking back in the prev yr?

for (m = 11; m >= prev_yr_lookback && m >= 0; m--) {
double ratchet_percent = ec_bd_lookback_percents[m] * 0.01;
double ratchet_percent = bd_lookback_percents[m] * 0.01;
double months_demand = prev_peak_demand[m] * ratchet_percent;
if (months_demand > billing_demand) {
billing_demand = months_demand;
}
}

int start_month = 0;
if (month >= ec_bd_lookback_months) {
start_month = month - ec_bd_lookback_months;
if (month >= bd_lookback_months) {
start_month = month - bd_lookback_months;
}

int idx = 0;
for (m = start_month; m <= month; m++) {
double ratchet_percent = ec_bd_lookback_percents[m] * 0.01;
double months_demand = m_month[m].dc_flat_peak * ratchet_percent;
if (months_demand > billing_demand) {
billing_demand = months_demand;
idx = 0;
for (int p : m_month[m].dc_periods) {
if (bd_tou_periods.at(p)) {
double ratchet_percent = bd_lookback_percents[m] * 0.01;
double months_demand = m_month[m].dc_tou_peak[idx] * ratchet_percent;
if (months_demand > billing_demand) {
billing_demand = months_demand;
}
}
idx++;
}
}

if (m_month[month].dc_flat_peak > billing_demand && m_month[month].use_current_month_ratchet) {
billing_demand = m_month[month].dc_flat_peak;
if (m_month[month].use_current_month_ratchet) {
idx = 0;
for (int p : m_month[month].dc_periods) {
if (bd_tou_periods.at(p)) {
double months_demand = m_month[month].dc_tou_peak[idx];
if (months_demand > billing_demand) {
billing_demand = months_demand;
}
}
idx++;
}
}

return billing_demand;
}

void rate_data::set_billing_demands() {
for (int m = 0; m < (int) m_month.size(); m++) {
double flat_peak = m_month[m].dc_flat_peak;
if (en_billing_demand_lookback) {
// If ratchets are present the peak used here might be the actual peak, or something based on a previous month.
flat_peak = get_billing_demand(m);
}
billing_demand[m] = flat_peak;
}
}

void rate_data::setup_prev_demand(ssc_number_t* prev_demand) {
for (size_t i = 0; i < prev_peak_demand.size(); i++) {
prev_peak_demand[i] = prev_demand[i];
Expand Down Expand Up @@ -277,13 +308,8 @@ void rate_data::init_energy_rates(bool gen_only) {
std::vector<size_t> tier_numbers;
std::vector<double> tier_kwh;

// track monthly peak to determine which kWh/kW tier
double flat_peak = m_month[m].dc_flat_peak;
if (en_ec_billing_demand) {
// If ratchets are present the peak used here might be the actual peak, or something based on a previous month.
flat_peak = get_billing_demand(m);
}
billing_demand[m] = flat_peak;
// Monthly billing demand is computed prior to this loop
double flat_peak = billing_demand[m];

// get kWh/kW break points based on actual demand
for (size_t i_tier = 0; i_tier < m_month[m].ec_tou_units.ncols(); i_tier++)
Expand Down Expand Up @@ -805,7 +831,7 @@ void rate_data::setup_demand_charges(ssc_number_t* dc_weekday, ssc_number_t* dc_
}
}

void rate_data::setup_ratcheting_demand(ssc_number_t* ratchet_percent_matrix)
void rate_data::setup_ratcheting_demand(ssc_number_t* ratchet_percent_matrix, ssc_number_t* bd_tou_period_matrix)
{
// Error checked in SSC variables
size_t nrows = 12;
Expand All @@ -814,10 +840,16 @@ void rate_data::setup_ratcheting_demand(ssc_number_t* ratchet_percent_matrix)
ratchet_matrix.assign(ratchet_percent_matrix, nrows, ncols);

for (int i = 0; i < nrows; i++) {
ec_bd_lookback_percents[i] = ratchet_matrix.at(i, 0);
bd_lookback_percents[i] = ratchet_matrix.at(i, 0);
m_month[i].use_current_month_ratchet = ratchet_matrix.at(i, 1) == 1;
}

nrows = m_dc_tou_periods.size();
util::matrix_t<double> tou_matrix(nrows, ncols);
tou_matrix.assign(bd_tou_period_matrix, nrows, ncols);
for (int i = 0; i < nrows; i++) {
bd_tou_periods.emplace((int) tou_matrix.at(i, 0), tou_matrix.at(i, 1) == 1.0);
}
}

void rate_data::sort_energy_to_periods(int month, double energy, size_t step) {
Expand Down Expand Up @@ -881,7 +913,7 @@ ssc_number_t rate_data::get_demand_charge(int month, size_t year)
ssc_number_t charge = 0;
ssc_number_t d_lower = 0;
ssc_number_t total_charge = 0;
ssc_number_t demand = curr_month.dc_flat_peak;
ssc_number_t demand = billing_demand[month];
bool found = false;
for (tier = 0; tier < (int)curr_month.dc_flat_ub.size() && !found; tier++)
{
Expand Down Expand Up @@ -915,11 +947,19 @@ ssc_number_t rate_data::get_demand_charge(int month, size_t year)
d_lower = 0;
if (tou_demand_single_peak)
{
demand = curr_month.dc_flat_peak;
// If billing demand lookback is not enabled, this will be the flat peak
demand = billing_demand[month];
if (curr_month.dc_flat_peak_hour != curr_month.dc_tou_peak_hour[period]) continue; // only one peak per month.
}
else if (period < curr_month.dc_periods.size())
demand = curr_month.dc_tou_peak[period];
else if (period < curr_month.dc_periods.size()) {
int period_num = curr_month.dc_periods[period];
if (en_billing_demand_lookback && bd_tou_periods.at(period_num)) {
demand = billing_demand[month];
}
else {
demand = curr_month.dc_tou_peak[period];
}
}
// find tier corresponding to peak demand
found = false;
for (tier = 0; tier < (int)curr_month.dc_tou_ub.ncols() && !found; tier++)
Expand Down
14 changes: 9 additions & 5 deletions shared/lib_utility_rate_equations.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef _LIB_UTILITY_RATE_EQUATIONS_H_
#define _LIB_UTILITY_RATE_EQUATIONS_H_

#include <map>
#include <vector>

#include "../ssc/core.h"
Expand Down Expand Up @@ -113,11 +114,13 @@ class rate_data {
std::vector<ssc_number_t> monthly_dc_fixed;
std::vector<ssc_number_t> monthly_dc_tou;

bool en_ec_billing_demand; // Enable billing demand lookback percentages for kWh/kW energy charges
bool uses_billing_demand; // Has a energy rate with kWh/kw AND/OR has a demand charge. If false, en_billing_demand_lookback must be false
bool en_billing_demand_lookback; // Enable billing demand lookback percentages
std::vector<ssc_number_t> prev_peak_demand; // Set before calling init_energy_rates
std::vector<ssc_number_t> ec_bd_lookback_percents;
double ec_bd_minimum;
int ec_bd_lookback_months;
std::vector<ssc_number_t> bd_lookback_percents;
double bd_minimum;
int bd_lookback_months;
std::unordered_map<int, bool> bd_tou_periods;
std::vector<ssc_number_t> billing_demand; // Store locally for ssc outputs

bool tou_demand_single_peak;
Expand All @@ -142,11 +145,12 @@ class rate_data {
/* Optional function if demand charges are present */
void setup_demand_charges(ssc_number_t* dc_weekday, ssc_number_t* dc_weekend, size_t dc_tou_rows, ssc_number_t* dc_tou_in, size_t dc_flat_rows, ssc_number_t* dc_flat_in);
/* Optional function if energy charges use a ratchet for the billing demand */
void setup_ratcheting_demand(ssc_number_t* ratchet_percent_matrix);
void setup_ratcheting_demand(ssc_number_t* ratchet_percent_matrix, ssc_number_t* bd_tou_period_matrix);

void setup_prev_demand(ssc_number_t* prev_demand);
/* call ur_month.update_net_and_peak before this, otherwise you'll get low values back */
double get_billing_demand(int month);
void set_billing_demands(); // Runs get_billing_demand and updates the billing_demand structure

/* Populate ur_month objects from those filled out in setup_energy_rates. Called annually in cmod_utility_rate5, other classes may reset ur_month directly
Can be called right away to create the vectors, but for kWh/kW rates needs to be called once after ur_month.update_net_and_peak to be accurate */
Expand Down
Loading

0 comments on commit 8e9dcb0

Please sign in to comment.