Skip to content

Commit

Permalink
Allow for zero time series buy and sell rates (#1264)
Browse files Browse the repository at this point in the history
* 2024.12.12.ssc.297 release candidate - no expiration

* Switch from tier charge == 0 to explicit booleans for handling time series rate length errors

---------

Co-authored-by: Steven Janzou <steven@janzouconsulting.com>
  • Loading branch information
brtietz and sjanzou authored Dec 11, 2024
1 parent 2daaee8 commit 7e7c049
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 3 deletions.
8 changes: 6 additions & 2 deletions ssc/cmod_utilityrate5.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2377,17 +2377,19 @@ class cm_utilityrate5 : public compute_module

ssc_number_t tier_credit = 0.0, sr = 0.0, tier_energy = 0.0;
// time step sell rates
bool use_ec_table_sell_rates = true;
if (as_boolean("ur_en_ts_sell_rate")) {
if (c < rate.m_ec_ts_sell_rate.size()) {
tier_energy = energy_surplus;
sr = rate.m_ec_ts_sell_rate[c];
tier_credit = tier_energy * sr * rate_esc;
curr_month.ec_energy_surplus.at(row, surplus_tier) += (ssc_number_t)tier_energy;
use_ec_table_sell_rates = false;
}
}

// Fall back to TOU rates if m_ec_ts_sell_rate.size() is too small
if (tier_credit == 0) { // So AFAICT this is to make sure we don't compute both time step and TOU. Maybe better as an else?
if (use_ec_table_sell_rates) { // So AFAICT this is to make sure we don't compute both time step and TOU. Maybe better as an else?
if (cumulative_energy <= e_upper) { // If we are within the max usage for the tier, then it's a simple multiply
tier_energy = energy_surplus; // of our usage with that rate and the escalator
sr = curr_month.ec_tou_sr.at(row, surplus_tier);
Expand Down Expand Up @@ -2468,6 +2470,7 @@ class cm_utilityrate5 : public compute_module
cumulative_deficit = daily_deficit_energy;

ssc_number_t tier_charge = 0.0, br = 0.0, tier_energy = 0.0;
bool use_ec_table_buy_rates = true;
// time step sell rates
if (as_boolean("ur_en_ts_buy_rate")) {
if (c < rate.m_ec_ts_buy_rate.size()) {
Expand All @@ -2477,11 +2480,12 @@ class cm_utilityrate5 : public compute_module
charge_amt = tier_energy * br * rate_esc;
curr_month.ec_energy_use.at(row, deficit_tier) += (ssc_number_t)tier_energy;
curr_month.ec_charge.at(row, deficit_tier) += (ssc_number_t)charge_amt;
use_ec_table_buy_rates = false;
}
}

// Fall back to TOU rates if m_ec_ts_buy_rate.size() is too small
if (tier_charge == 0) {
if (use_ec_table_buy_rates) {
if (cumulative_deficit <= e_upper) {
tier_energy = energy_deficit;
br = curr_month.ec_tou_br.at(row, deficit_tier);
Expand Down
2 changes: 1 addition & 1 deletion ssc/sscapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

SSCEXPORT int ssc_version()
{
return 296;
return 297;
}

SSCEXPORT const char *ssc_build_info()
Expand Down
58 changes: 58 additions & 0 deletions test/ssc_test/cmod_utilityrate5_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2273,3 +2273,61 @@ TEST(cmod_utilityrate5_eqns, Test_Commercial_Demand_Charges_exception) {
int status = run_module(data, "utilityrate5");
EXPECT_TRUE(status);
}

TEST(cmod_utilityrate5_eqns, Test_Residential_TOU_Rates_buyall_sellall_ts_buy_rate) {
ssc_data_t data = new var_table;

setup_residential_rates(data);
ssc_data_set_number(data, "ur_metering_option", 4);
// Need to specify sell rates for this configuration. These are higher than real life
ssc_number_t p_ur_ec_tou_mat[24] = { 1, 1, 9.9999999999999998e+37, 0, 0.10000000000000001, 0.10000000000000001,
2, 1, 9.9999999999999998e+37, 0, 0.050000000000000003, 0.050000000000000003,
3, 1, 9.9999999999999998e+37, 0, 0.20000000000000001, 0.20000000000000001,
4, 1, 9.9999999999999998e+37, 0, 0.25, 0.25 };
ssc_data_set_matrix(data, "ur_ec_tou_mat", p_ur_ec_tou_mat, 4, 6);

ssc_data_set_number(data, "ur_en_ts_buy_rate", 1);
ssc_number_t p_ur_ts_buy_rate[8760];
for (size_t i = 0; i < 8760; i++) {
p_ur_ts_buy_rate[i] = 0.0;
}
ssc_data_set_array(data, "ur_ts_buy_rate", p_ur_ts_buy_rate, 8760);

ssc_data_set_number(data, "ur_en_ts_sell_rate", 1);
ssc_number_t p_ur_ts_sell_rate[8760];
for (size_t i = 0; i < 8760; i++) {
p_ur_ts_sell_rate[i] = 0.0;
}
ssc_data_set_array(data, "ur_ts_sell_rate", p_ur_ts_sell_rate, 8760);

int analysis_period = 1;
ssc_data_set_number(data, "system_use_lifetime_output", 1);
ssc_data_set_number(data, "analysis_period", analysis_period);
set_array(data, "load", load_profile_path, 8760);
set_array(data, "gen", gen_path, 8760); // 15 min data

int status = run_module(data, "utilityrate5");
EXPECT_FALSE(status);

ensure_outputs_line_up(data);

ssc_number_t cost_without_system;
ssc_data_get_number(data, "elec_cost_without_system_year1", &cost_without_system);
EXPECT_NEAR(0.0, cost_without_system, 0.01);

ssc_number_t cost_with_system;
ssc_data_get_number(data, "elec_cost_with_system_year1", &cost_with_system);
EXPECT_NEAR(0.0, cost_with_system, 0.0);

int nrows;
int ncols;
ssc_number_t* net_billing_credits = ssc_data_get_matrix(data, "two_meter_sales_ym", &nrows, &ncols);
util::matrix_t<double> credits_matrix(nrows, ncols);
credits_matrix.assign(net_billing_credits, nrows, ncols);

double dec_year_1_credits = credits_matrix.at((size_t)1, (size_t)11);
EXPECT_NEAR(0.0, dec_year_1_credits, 0.1);

ssc_data_free(data);

}

0 comments on commit 7e7c049

Please sign in to comment.