diff --git a/shared/lib_battery_dispatch_manual.cpp b/shared/lib_battery_dispatch_manual.cpp index 8c7cbc817..5dd718129 100644 --- a/shared/lib_battery_dispatch_manual.cpp +++ b/shared/lib_battery_dispatch_manual.cpp @@ -45,11 +45,13 @@ dispatch_manual_t::dispatch_manual_t(battery_t * Battery, double dt, double SOC_ util::matrix_t dm_dynamic_sched, util::matrix_t dm_dynamic_sched_weekend, std::vector dm_charge, std::vector dm_discharge, std::vector dm_gridcharge, std::vector dm_fuelcellcharge, std::vector dm_btm_to_grid, std::map dm_percent_discharge, std::map dm_percent_gridcharge, bool can_clip_charge, bool can_curtail_charge, double interconnection_limit, + size_t start_day_of_year, bool chargeOnlySystemExceedLoad, bool dischargeOnlyLoadExceedSystem, double SOC_min_outage, bool priorityChargeBattery) : dispatch_t(Battery, dt, SOC_min, SOC_max, current_choice, Ic_max, Id_max, Pc_max_kwdc, Pd_max_kwdc, Pc_max_kwac, Pd_max_kwac, t_min, mode, battMeterPosition, interconnection_limit, chargeOnlySystemExceedLoad, dischargeOnlyLoadExceedSystem, SOC_min_outage) { - init_with_vects(dm_dynamic_sched, dm_dynamic_sched_weekend, dm_charge, dm_discharge, dm_gridcharge, dm_fuelcellcharge, dm_btm_to_grid, dm_percent_discharge, dm_percent_gridcharge, can_clip_charge, can_curtail_charge, priorityChargeBattery); + init_with_vects(dm_dynamic_sched, dm_dynamic_sched_weekend, dm_charge, dm_discharge, dm_gridcharge, dm_fuelcellcharge, dm_btm_to_grid, dm_percent_discharge, dm_percent_gridcharge, + can_clip_charge, can_curtail_charge, priorityChargeBattery, start_day_of_year); } void dispatch_manual_t::init_with_vects( @@ -64,7 +66,8 @@ void dispatch_manual_t::init_with_vects( std::map dm_percent_gridcharge, bool can_clip_charge, bool can_curtail_charge, - bool priorityChargeBattery) + bool priorityChargeBattery, + size_t start_day_of_year) { _sched = dm_dynamic_sched; _sched_weekend = dm_dynamic_sched_weekend; @@ -79,6 +82,7 @@ void dispatch_manual_t::init_with_vects( _can_curtail_charge = can_curtail_charge; _priority_charge_battery = priorityChargeBattery; _iprofile = 0; + _start_day_of_year = start_day_of_year; } // deep copy from dispatch to this @@ -88,7 +92,7 @@ dispatch_t(dispatch) const dispatch_manual_t * tmp = dynamic_cast(&dispatch); init_with_vects(tmp->_sched, tmp->_sched_weekend, tmp->_charge_array, tmp->_discharge_array, tmp->_gridcharge_array, tmp->_fuelcellcharge_array, tmp->_discharge_grid_array, - tmp->_percent_discharge_array, tmp->_percent_charge_array, tmp->_can_clip_charge, tmp->_can_curtail_charge, tmp->_priority_charge_battery); + tmp->_percent_discharge_array, tmp->_percent_charge_array, tmp->_can_clip_charge, tmp->_can_curtail_charge, tmp->_priority_charge_battery, tmp->_start_day_of_year); } // shallow copy from dispatch to this @@ -98,7 +102,7 @@ void dispatch_manual_t::copy(const dispatch_t * dispatch) const dispatch_manual_t * tmp = dynamic_cast(dispatch); init_with_vects(tmp->_sched, tmp->_sched_weekend, tmp->_charge_array, tmp->_discharge_array, tmp->_gridcharge_array, tmp->_fuelcellcharge_array, tmp->_discharge_grid_array, - tmp->_percent_discharge_array, tmp->_percent_charge_array, tmp->_can_clip_charge, tmp->_can_curtail_charge, tmp->_priority_charge_battery); + tmp->_percent_discharge_array, tmp->_percent_charge_array, tmp->_can_clip_charge, tmp->_can_curtail_charge, tmp->_priority_charge_battery, tmp->_start_day_of_year); } void dispatch_manual_t::prepareDispatch(size_t hour_of_year, size_t ) @@ -108,7 +112,7 @@ void dispatch_manual_t::prepareDispatch(size_t hour_of_year, size_t ) size_t column = h - 1; _iprofile = 0; - bool is_weekday = util::weekday(hour_of_year); + bool is_weekday = util::weekday(hour_of_year, _start_day_of_year); if (!is_weekday && _mode == MANUAL) _iprofile = _sched_weekend(m - 1, column); else diff --git a/shared/lib_battery_dispatch_manual.h b/shared/lib_battery_dispatch_manual.h index bf9456efe..6813da0d2 100644 --- a/shared/lib_battery_dispatch_manual.h +++ b/shared/lib_battery_dispatch_manual.h @@ -67,6 +67,7 @@ class dispatch_manual_t : public dispatch_t bool can_clip_charge, bool can_curtail_charge, double interconnection_limit, + size_t start_day_of_year, bool chargeOnlySystemExceedLoad = true, bool dischargeOnlyLoadExceedSystem = true, double SOC_min_outage = 0.0, @@ -104,7 +105,8 @@ class dispatch_manual_t : public dispatch_t std::map dm_percent_gridcharge, bool can_clip_charge, bool can_curtail_charge, - bool priorityChargeBattery); + bool priorityChargeBattery, + size_t start_day_of_year); void SOC_controller() override; bool check_constraints(double &I, size_t count) override; @@ -129,6 +131,8 @@ class dispatch_manual_t : public dispatch_t std::map _percent_discharge_array; std::map _percent_charge_array; + size_t _start_day_of_year; + }; #endif // __LIB_BATTERY_DISPATCH_MANUAL_H__ diff --git a/shared/lib_fuel_cell_dispatch.cpp b/shared/lib_fuel_cell_dispatch.cpp index 04c0b88e7..e43bf2a0b 100644 --- a/shared/lib_fuel_cell_dispatch.cpp +++ b/shared/lib_fuel_cell_dispatch.cpp @@ -39,13 +39,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lib_power_electronics.h" -FuelCellDispatch::FuelCellDispatch(FuelCell * fuelCell, size_t numberOfUnits, int dispatchOption, int shutdownOption, double dt_hour, double fixed_percent, +FuelCellDispatch::FuelCellDispatch(FuelCell * fuelCell, size_t numberOfUnits, int dispatchOption, int shutdownOption, double dt_hour, double fixed_percent, size_t start_day_of_year, std::vector dispatchInput_kW, std::vector canCharge, std::vector canDischarge, std::map discharge_percent, std::map discharge_units, util::matrix_t scheduleWeekday, util::matrix_t scheduleWeekend) : m_powerTotal_kW(0), m_numberOfUnits(numberOfUnits), m_dispatchOption(dispatchOption), m_shutdownOption(shutdownOption), dt_hour(dt_hour), m_fixed_percent(fixed_percent * 0.01), m_dispatchInput_kW(dispatchInput_kW), m_canCharge(canCharge), m_canDischarge(canDischarge), m_discharge_percent(discharge_percent), m_discharge_units(discharge_units), - m_scheduleWeekday(scheduleWeekday), m_scheduleWeekend(scheduleWeekend) + m_scheduleWeekday(scheduleWeekday), m_scheduleWeekend(scheduleWeekend), + m_start_day_of_year(start_day_of_year) { // Convert percentages to fractions for (auto percent = m_discharge_percent.begin(); percent != m_discharge_percent.end(); percent++) { @@ -75,7 +76,7 @@ FuelCellDispatch::FuelCellDispatch(FuelCell * fuelCell, size_t numberOfUnits, in else if (m_dispatchOption == FuelCellDispatch::FC_DISPATCH_OPTION::MANUAL) { size_t period = m_scheduleWeekday(0, 0); - if (!util::weekday(0)) { + if (!util::weekday(0, m_start_day_of_year)) { period = m_scheduleWeekend(0, 0); } double discharge_percent_init = 0; @@ -163,7 +164,7 @@ void FuelCellDispatch::runSingleTimeStep(size_t hour_of_year, size_t year_idx, d util::month_hour(hour_of_year, month, hour); size_t period = m_scheduleWeekday(month - 1, hour - 1); - if (!util::weekday(hour_of_year)) { + if (!util::weekday(hour_of_year, m_start_day_of_year)) { period = m_scheduleWeekend(month - 1, hour - 1); } diff --git a/shared/lib_fuel_cell_dispatch.h b/shared/lib_fuel_cell_dispatch.h index a74a67cd2..628227242 100644 --- a/shared/lib_fuel_cell_dispatch.h +++ b/shared/lib_fuel_cell_dispatch.h @@ -48,6 +48,7 @@ class FuelCellDispatch /// Construct with arguments FuelCellDispatch(FuelCell * fuelCell, size_t numberOfUnits, int dispatchOption, int shutdownOption, double dt_hour, double fixed_percent, + size_t start_day_of_year, std::vector dispatchInput_kW, std::vector canCharge, std::vector canDischarge, @@ -115,6 +116,7 @@ class FuelCellDispatch int m_shutdownOption; double dt_hour; double m_fixed_percent; + size_t m_start_day_of_year; std::vector m_dispatchInput_kW; std::vector< FuelCell *> m_fuelCellVector; diff --git a/shared/lib_time.cpp b/shared/lib_time.cpp index c11d4a0ed..d0d27b35d 100644 --- a/shared/lib_time.cpp +++ b/shared/lib_time.cpp @@ -152,7 +152,7 @@ template void single_year_to_lifetime_interpolated(bool, size_t, size_t, * \param[out] flat_vector - The 8760*steps per hour values at each hour */ template -std::vector flatten_diurnal(util::matrix_t weekday_schedule, util::matrix_t weekend_schedule, size_t steps_per_hour, std::vector period_values, T multiplier) +std::vector flatten_diurnal(util::matrix_t weekday_schedule, util::matrix_t weekend_schedule, size_t steps_per_hour, std::vector period_values, size_t start_day_of_year, T multiplier) { std::vector flat_vector; flat_vector.reserve(8760 * steps_per_hour); @@ -162,7 +162,7 @@ std::vector flatten_diurnal(util::matrix_t weekday_schedule, util::ma for (size_t hour_of_year = 0; hour_of_year != 8760; hour_of_year++) { util::month_hour(hour_of_year % 8760, month, hour); - if (util::weekday(hour_of_year)) + if (util::weekday(hour_of_year, start_day_of_year)) iprofile = weekday_schedule(month - 1, hour - 1); else iprofile = weekend_schedule(month - 1, hour - 1); @@ -175,7 +175,7 @@ std::vector flatten_diurnal(util::matrix_t weekday_schedule, util::ma return flat_vector; } -template std::vector flatten_diurnal(util::matrix_t weekday_schedule, util::matrix_t weekend_schedule, size_t steps_per_hour, std::vector period_values, double multiplier); +template std::vector flatten_diurnal(util::matrix_t weekday_schedule, util::matrix_t weekend_schedule, size_t steps_per_hour, std::vector period_values, size_t start_day_of_year, double multiplier); /** diff --git a/shared/lib_time.h b/shared/lib_time.h index f6fd7719a..127b05c4c 100644 --- a/shared/lib_time.h +++ b/shared/lib_time.h @@ -61,7 +61,7 @@ Function takes in a weekday and weekend schedule, plus the period values and an a vector */ template -std::vector flatten_diurnal(util::matrix_t weekday_schedule, util::matrix_t weekend_schedule, size_t steps_per_hour, std::vector period_values, T multiplier = 1.0); +std::vector flatten_diurnal(util::matrix_t weekday_schedule, util::matrix_t weekend_schedule, size_t steps_per_hour, std::vector period_values, size_t start_day_of_year, T multiplier = 1.0); /** Function takes input values, desired steps per hour, and an optional multiplier and returns diff --git a/shared/lib_util.cpp b/shared/lib_util.cpp index fa1c03bf3..6d6df08d0 100644 --- a/shared/lib_util.cpp +++ b/shared/lib_util.cpp @@ -949,10 +949,10 @@ size_t util::hour_of_year(size_t month, size_t day, size_t hour) return h; } -bool util::weekday(size_t hour_of_year) +bool util::weekday(size_t hour_of_year, size_t start_day_of_year) { int day_of_year = (int)(floor((float)(hour_of_year) / 24)); - int day_of_week = day_of_year; + int day_of_week = day_of_year + start_day_of_year; if (day_of_week > 6) day_of_week = day_of_year % 7; @@ -1033,7 +1033,7 @@ std::string util::schedule_int_to_month( int m ) return ret; } -bool util::translate_schedule( int tod[8760], const char *wkday, const char *wkend, int min_val, int max_val) +bool util::translate_schedule( int tod[8760], const char *wkday, const char *wkend, int min_val, int max_val, int start_day) { size_t i=0; if (!wkday || !wkend || strlen(wkday) != 288 || strlen(wkend) != 288) @@ -1042,7 +1042,7 @@ bool util::translate_schedule( int tod[8760], const char *wkday, const char *wke return false; } - int wday = 5; + int wday = 5 - start_day; // start_day: 0 == Monday, 6 == Sunday for (size_t m=0;m<12;m++) { for (size_t d=0;d &wkday, const matrix_t &wkend, int min_val, int max_val) +bool util::translate_schedule(int tod[8760], const matrix_t &wkday, const matrix_t &wkend, int min_val, int max_val, int start_day) { size_t i = 0; if ((wkday.nrows() != 12) || (wkend.nrows() != 12) || (wkday.ncols() != 24) || (wkend.ncols() != 24) ) @@ -1075,7 +1075,7 @@ bool util::translate_schedule(int tod[8760], const matrix_t &wkday, cons return false; } - int wday = 5; // start on Monday + int wday = 5 - start_day; // start_day: 0 == Monday, 6 == Sunday bool is_weekday = true; for (size_t m = 0; m<12; m++) { diff --git a/shared/lib_util.h b/shared/lib_util.h index 070775f3a..ed700faab 100644 --- a/shared/lib_util.h +++ b/shared/lib_util.h @@ -140,14 +140,14 @@ namespace util int day_of_month(int month, double time); /* month: 1-12 time: hours, starting 0=jan 1st 12am, returns 1-nday*/ int days_in_month(int month); /*month: 0-11, return 0-30, depending on the month*/ void month_hour(size_t hour_of_year, size_t & out_month, size_t & out_hour); /*given the hour of year, return the month, and hour of day*/ - bool weekday(size_t hour_of_year); /* return true if is a weekday, assuming first hour of year is Monday at 12 am*/ + bool weekday(size_t hour_of_year, size_t start_day_of_year); /* return true if is a weekday, start day of year = 0 is Monday at 12 am*/ size_t lifetimeIndex(size_t year, size_t hour_of_year, size_t step_of_hour, size_t steps_per_hour); size_t yearOneIndex(double dtHour, size_t lifetimeIndex); size_t yearIndex(size_t year, size_t month, size_t day, size_t hour, double minute, size_t step_per_hour); int schedule_char_to_int( char c ); std::string schedule_int_to_month( int m ); - bool translate_schedule(int tod[8760], const char *wkday, const char *wkend, int min_val, int max_val); + bool translate_schedule(int tod[8760], const char *wkday, const char *wkend, int min_val, int max_val, int start_day); bool file_exists( const char *file ); bool dir_exists( const char *path ); @@ -860,7 +860,7 @@ namespace util double linterp_col( const matrix_t &mat, size_t ixcol, double xval, size_t iycol ); size_t nearest_col_index(const matrix_t& mat, size_t col, double val); size_t nearest_col_index(const std::vector>& mat, size_t col, double val); - bool translate_schedule(int tod[8760], const matrix_t &wkday, const matrix_t &wkend, int min_val, int max_val); + bool translate_schedule(int tod[8760], const matrix_t &wkday, const matrix_t &wkend, int min_val, int max_val, int start_day); std::vector frequency_table(double* values, size_t n_vals, double bin_width); }; diff --git a/shared/lib_utility_rate.cpp b/shared/lib_utility_rate.cpp index 0092bb058..13cfb19b5 100644 --- a/shared/lib_utility_rate.cpp +++ b/shared/lib_utility_rate.cpp @@ -39,12 +39,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. UtilityRate::UtilityRate( bool useRealTimePrices, + size_t start_day_of_year, util::matrix_t ecWeekday, util::matrix_t ecWeekend, util::matrix_t ecRatesMatrix, std::vector ecRealTimeBuy) { - m_useRealTimePrices = useRealTimePrices, + m_useRealTimePrices = useRealTimePrices; + m_start_day_of_year = start_day_of_year; m_ecWeekday = ecWeekday; m_ecWeekend = ecWeekend; m_ecRatesMatrix = ecRatesMatrix; @@ -53,6 +55,7 @@ UtilityRate::UtilityRate( UtilityRate::UtilityRate(const UtilityRate& tmp){ m_useRealTimePrices = tmp.m_useRealTimePrices; + m_start_day_of_year = tmp.m_start_day_of_year; m_ecWeekday = tmp.m_ecWeekday; m_ecWeekend = tmp.m_ecWeekend; m_ecRatesMatrix = tmp.m_ecRatesMatrix; @@ -144,7 +147,7 @@ size_t UtilityRateCalculator::getEnergyPeriod(size_t hourOfYear) size_t period, month, hour; util::month_hour(hourOfYear, month, hour); - if (util::weekday(hourOfYear)) { + if (util::weekday(hourOfYear, m_start_day_of_year)) { if (m_ecWeekday.nrows() == 1 && m_ecWeekday.ncols() == 1) { period = m_ecWeekday.at(0, 0); } diff --git a/shared/lib_utility_rate.h b/shared/lib_utility_rate.h index 4822fb4e6..088801aa7 100644 --- a/shared/lib_utility_rate.h +++ b/shared/lib_utility_rate.h @@ -50,6 +50,7 @@ class UtilityRate UtilityRate(){}; UtilityRate(bool useRealTimePrices, + size_t start_day_of_year, util::matrix_t ecWeekday, util::matrix_t ecWeekend, util::matrix_t ecRatesMatrix, @@ -77,6 +78,11 @@ class UtilityRate /// Use real time prices or not bool m_useRealTimePrices; + + /// + /// Monday = 0, Sunday = 6 + /// + size_t m_start_day_of_year; }; class UtilityRateCalculator : protected UtilityRate diff --git a/shared/lib_utility_rate_equations.cpp b/shared/lib_utility_rate_equations.cpp index 42c15c0e1..981348807 100644 --- a/shared/lib_utility_rate_equations.cpp +++ b/shared/lib_utility_rate_equations.cpp @@ -502,7 +502,7 @@ void rate_data::setup_time_series(size_t cnt, ssc_number_t* ts_sr, ssc_number_t* } void rate_data::setup_energy_rates(ssc_number_t* ec_weekday, ssc_number_t* ec_weekend, - size_t ec_tou_rows, ssc_number_t* ec_tou_in, bool sell_eq_buy) + size_t ec_tou_rows, ssc_number_t* ec_tou_in, bool sell_eq_buy, size_t start_day_of_year) { size_t nrows, ncols, r, c, m, i, j; int period, tier; @@ -527,7 +527,7 @@ void rate_data::setup_energy_rates(ssc_number_t* ec_weekday, ssc_number_t* ec_we size_t max_tou_periods = 36; - if (!util::translate_schedule(ec_tod, ec_schedwkday, ec_schedwkend, 1, max_tou_periods)) + if (!util::translate_schedule(ec_tod, ec_schedwkday, ec_schedwkend, 1, max_tou_periods, start_day_of_year)) throw general_error("Could not translate weekday and weekend schedules for energy rates."); for (i = 0; i < 8760; i++) { @@ -711,7 +711,7 @@ void rate_data::setup_energy_rates(ssc_number_t* ec_weekday, ssc_number_t* ec_we } void rate_data::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) { + size_t dc_tou_rows, ssc_number_t* dc_tou_in, size_t dc_flat_rows, ssc_number_t* dc_flat_in, size_t start_day_of_year) { size_t nrows, ncols, r, c, m, i, j, idx; int period, tier, month; @@ -734,7 +734,7 @@ void rate_data::setup_demand_charges(ssc_number_t* dc_weekday, ssc_number_t* dc_ size_t max_tou_periods = 36; - if (!util::translate_schedule(dc_tod, dc_schedwkday, dc_schedwkend, 1, max_tou_periods)) + if (!util::translate_schedule(dc_tod, dc_schedwkday, dc_schedwkend, 1, max_tou_periods, start_day_of_year)) throw general_error("Could not translate weekday and weekend schedules for demand charges"); idx = 0; diff --git a/shared/lib_utility_rate_equations.h b/shared/lib_utility_rate_equations.h index 14a7a8e88..c9eb4454e 100644 --- a/shared/lib_utility_rate_equations.h +++ b/shared/lib_utility_rate_equations.h @@ -155,9 +155,9 @@ class rate_data { /* Optional function if time series buy or sell rates are being used */ void setup_time_series(size_t cnt, ssc_number_t* ts_sr, ssc_number_t* ts_br); /* Required function for setting up energy rate data */ - void setup_energy_rates(ssc_number_t* ec_weekday, ssc_number_t* ec_weekend, size_t ec_tou_rows, ssc_number_t* ec_tou_in, bool sell_eq_buy); + void setup_energy_rates(ssc_number_t* ec_weekday, ssc_number_t* ec_weekend, size_t ec_tou_rows, ssc_number_t* ec_tou_in, bool sell_eq_buy, size_t start_day_of_year); /* 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); + 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, size_t start_day_of_year); /* Optional function if energy charges use a ratchet for the billing demand - returns error code based on data validitiy (at least one active period) */ bool setup_ratcheting_demand(ssc_number_t* ratchet_percent_matrix, ssc_number_t* bd_tou_period_matrix); diff --git a/ssc/cmod_battery.cpp b/ssc/cmod_battery.cpp index 650faf1d6..d807ac20c 100644 --- a/ssc/cmod_battery.cpp +++ b/ssc/cmod_battery.cpp @@ -215,6 +215,8 @@ var_info vtab_battery_inputs[] = { // Powerflow calculation inputs { SSC_INPUT, SSC_ARRAY, "fuelcell_power", "Electricity from fuel cell AC", "kW", "", "FuelCell", "", "", "" }, + // Start day of week for manual dispatch arrays + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "BatteryDispatch", "?=0", "", "" }, var_info_invalid }; @@ -751,6 +753,8 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c } } + batt_vars->start_day_of_year = vt.as_number("start_day_of_year"); + // Common to automated methods batt_vars->batt_dispatch_auto_can_charge = true; batt_vars->batt_dispatch_auto_can_clipcharge = false; @@ -1295,6 +1299,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c batt_vars->batt_discharge_schedule_weekday, batt_vars->batt_discharge_schedule_weekend, batt_vars->batt_can_charge, batt_vars->batt_can_discharge, batt_vars->batt_can_gridcharge, batt_vars->batt_can_fuelcellcharge, batt_vars->batt_btm_can_discharge_to_grid, dm_percent_discharge, dm_percent_gridcharge, batt_vars->batt_dispatch_auto_can_clipcharge, batt_vars->batt_dispatch_auto_can_curtailcharge, batt_vars->grid_interconnection_limit_kW, + batt_vars->start_day_of_year, batt_vars->batt_dispatch_charge_only_system_exceeds_load, batt_vars->batt_dispatch_discharge_only_load_exceeds_system, batt_vars->batt_minimum_outage_SOC, @@ -1315,7 +1320,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c // Create UtilityRate object only if utility rate is defined if (batt_vars->ec_rate_defined) { - utilityRate = new UtilityRate(batt_vars->ec_use_realtime, batt_vars->ec_weekday_schedule, batt_vars->ec_weekend_schedule, batt_vars->ec_tou_matrix, batt_vars->ec_realtime_buy); + utilityRate = new UtilityRate(batt_vars->ec_use_realtime, batt_vars->start_day_of_year, batt_vars->ec_weekday_schedule, batt_vars->ec_weekend_schedule, batt_vars->ec_tou_matrix, batt_vars->ec_realtime_buy); } // PV Smoothing dispatch model diff --git a/ssc/cmod_battery.h b/ssc/cmod_battery.h index e0e17fbe0..159e9432b 100644 --- a/ssc/cmod_battery.h +++ b/ssc/cmod_battery.h @@ -231,6 +231,7 @@ struct batt_variables util::matrix_t ec_weekend_schedule; util::matrix_t ec_tou_matrix; std::vector ec_realtime_buy; + size_t start_day_of_year; /* Battery replacement options */ int batt_replacement_option; diff --git a/ssc/cmod_battwatts.cpp b/ssc/cmod_battwatts.cpp index 8ce5bf6e8..cc6d1db9f 100644 --- a/ssc/cmod_battwatts.cpp +++ b/ssc/cmod_battwatts.cpp @@ -258,6 +258,8 @@ battwatts_create(size_t n_recs, size_t n_years, int chem, int meter_pos, double batt_vars->batt_dispatch_charge_only_system_exceeds_load = false; batt_vars->batt_dispatch_discharge_only_load_exceeds_system = false; + batt_vars->start_day_of_year = 0; // None of the inputs for this cmod use a weekday/weekend schedule, so hardcode this + // Battery bank replacement batt_vars->batt_replacement_capacity = 0.; diff --git a/ssc/cmod_belpe.cpp b/ssc/cmod_belpe.cpp index 137450ad9..f544683db 100644 --- a/ssc/cmod_belpe.cpp +++ b/ssc/cmod_belpe.cpp @@ -83,6 +83,10 @@ static var_info _cm_vtab_belpe[] = { SSC_INPUT, SSC_ARRAY, "Monthly_util", "Monthly consumption from utility bill", "kWh", "", "Load Profile Estimator", "en_belpe=1", "LENGTH=12", "" }, + // Day of week for weekday/weekend schedules + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "Load Profile Estimator", "?=0", "", "" }, + + //OUTPUTS // { SSC_OUTPUT, SSC_ARRAY, "HVAC_load", "Electric Load due to HVAC", "Wh", "", "Load Profile Estimator", "en_belpe=1", "LENGTH=8760", "" }, @@ -347,6 +351,8 @@ class cm_belpe : public compute_module ssc_number_t en_dry = as_number("en_dry"); // boolean, so will be 0 or 1 ssc_number_t en_mels = as_number("en_mels"); // boolean, so will be 0 or 1 + ssc_number_t start_day_of_year = as_number("start_day_of_year"); // 0 = Monday, 6 = Sunday + //Possible other input options include color, construction, WWR, bldg L&W, wall //height per floor @@ -703,8 +709,8 @@ class cm_belpe : public compute_module SEER = 10; //END COOLING SEER - //day of the week: Days 1-7. - int D = 1; //somehow I am one day off BEOPT so compensating here(this is days of the week) + //day of the week: Days 0-6. + int D = start_day_of_year - 1; // First day will get incremented below immediately, compensate here // TMY DEFAULT IS MONDAY!!!!!!! //Sol - Air -- This part is ALL SI -- get effective envelope temperatures for the heat transfer. std::vector Vacay(8760), Hset(8760), Cset(8760); @@ -762,8 +768,8 @@ class cm_belpe : public compute_module if (Hr == 0) //first hour of a new day { D = D + 1; //increment the day of the week - if (D > 7) - D = 1; + if (D > 6) + D = 0; } int Mon = month[i]; int Dy = day[i]; @@ -861,7 +867,7 @@ class cm_belpe : public compute_module EquipRadHrLoad[inext] = SensibleEquipRadorConvVacay[NextHr]; EquipConvHrLoad[inext] = SensibleEquipRadorConvVacay[NextHr]; } - else if ((D == 2 && Hr < 23) || (D == 7 && Hr == 23) || D == 1) // weekend!(hour inext) + else if (D == 5 || D == 6) // weekend!(hour inext) { EquipElecHrLoad[inext] = TotalPlugHourlyWkend[NextHr]; EquipRadHrLoad[inext] = SensibleEquipRadorConvWkend[NextHr]; //These are just 50 / 50 rad and conv, but the multipliers are BLDG AM sensible load fractions diff --git a/ssc/cmod_biomass.cpp b/ssc/cmod_biomass.cpp index b3ff86429..57ee7760f 100644 --- a/ssc/cmod_biomass.cpp +++ b/ssc/cmod_biomass.cpp @@ -152,6 +152,9 @@ static var_info _cm_vtab_biomass[] = { { SSC_INPUT, SSC_STRING, "biopwr.plant.tou_grid", "", "", "", "biopower", "*", "", "" }, { SSC_INPUT, SSC_NUMBER, "biopwr.plant.boiler.steam_pressure", "", "", "", "biopower", "*", "", "" }, + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "biopower", "?=0", "", "" }, + + /* { SSC_INPUT, SSC_NUMBER, "biopwr.feedstockcost.biomass_fuel_used", "Annual biomass used", "dry tons/year", "", "biopower", "*", "", "" }, { SSC_INPUT, SSC_NUMBER, "biopwr.feedstockcost.biomass_fuel_cost", "Annual biomass fuel cost", "$", "", "biopower", "*", "", "" }, @@ -402,7 +405,8 @@ class cm_biomass : public compute_module } char *sched = (char*)as_string("biopwr.plant.tou_grid"); - if (!util::translate_schedule(tou, sched, sched, 0, 8)) + size_t start_day = as_number("start_day_of_year"); + if (!util::translate_schedule(tou, sched, sched, 0, 8, start_day)) throw exec_error("biopower", "could not translate schedule for time-of-use rate"); } diff --git a/ssc/cmod_etes_electric_resistance.cpp b/ssc/cmod_etes_electric_resistance.cpp index cb4e77418..204aec055 100644 --- a/ssc/cmod_etes_electric_resistance.cpp +++ b/ssc/cmod_etes_electric_resistance.cpp @@ -152,6 +152,9 @@ static var_info _cm_vtab_etes_electric_resistance[] = { { SSC_INPUT, SSC_ARRAY, "dispatch_tod_factors", "TOD factors for periods 1 through 9", "", "We added this array input after SAM 2022.12.21 to replace the functionality of former single value inputs dispatch_factor1 through dispatch_factor9", "Time of Delivery Factors", "ppa_multiplier_model=0&csp_financial_model<5&is_dispatch=1&sim_type=1", "", "SIMULATION_PARAMETER" }, + // Day of week for weekday/weekend schedules + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "Time of Delivery Factors", "?=0", "", "" }, + { SSC_INPUT, SSC_ARRAY, "ppa_price_input", "PPA prices - yearly", "$/kWh", "", "Revenue", "ppa_multiplier_model=0&etes_financial_model<5&is_dispatch=1&sim_type=1", "", "SIMULATION_PARAMETER"}, { SSC_INPUT, SSC_MATRIX, "mp_energy_market_revenue", "Energy market revenue input", "", "Lifetime x 2[Cleared Capacity(MW),Price($/MWh)]", "Revenue", "etes_financial_model=6&is_dispatch=1&sim_type=1", "", "SIMULATION_PARAMETER"}, @@ -683,7 +686,7 @@ class cm_etes_electric_resistance : public compute_module if (is_one_assigned || is_dispatch) { elec_pricing_schedule = C_timeseries_schedule_inputs(as_matrix("dispatch_sched_weekday"), as_matrix("dispatch_sched_weekend"), - as_vector_double("dispatch_tod_factors"), ppa_price_year1); + as_vector_double("dispatch_tod_factors"), ppa_price_year1, as_number("start_day_of_year")); } else { // If electricity pricing data is not available, then dispatch to a uniform schedule diff --git a/ssc/cmod_etes_ptes.cpp b/ssc/cmod_etes_ptes.cpp index 9040d9152..e6e65bc68 100644 --- a/ssc/cmod_etes_ptes.cpp +++ b/ssc/cmod_etes_ptes.cpp @@ -148,6 +148,8 @@ static var_info _cm_vtab_etes_ptes[] = { { SSC_INPUT, SSC_ARRAY, "ppa_price_input", "PPA prices - yearly", "$/kWh", "", "Revenue", "ppa_multiplier_model=0&etes_financial_model<5&is_dispatch=1&sim_type=1", "", "SIMULATION_PARAMETER"}, + // Day of week for weekday/weekend schedules + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "Time of Delivery Factors", "?=0", "", "" }, // System performance { SSC_INPUT, SSC_NUMBER, "pb_fixed_par", "Fixed parasitic load that don't generate heat - runs at all times","MWe/MWcap", "", "System Control", "*", "", ""}, @@ -783,7 +785,7 @@ class cm_etes_ptes : public compute_module if (is_one_assigned || is_dispatch) { elec_pricing_schedule = C_timeseries_schedule_inputs(as_matrix("dispatch_sched_weekday"), as_matrix("dispatch_sched_weekend"), - as_vector_double("dispatch_tod_factors"), ppa_price_year1); + as_vector_double("dispatch_tod_factors"), ppa_price_year1, as_number("start_day_of_year")); } else { // If electricity pricing data is not available, then dispatch to a uniform schedule diff --git a/ssc/cmod_fresnel_physical.cpp b/ssc/cmod_fresnel_physical.cpp index ef2493146..c9a482cfd 100644 --- a/ssc/cmod_fresnel_physical.cpp +++ b/ssc/cmod_fresnel_physical.cpp @@ -255,6 +255,9 @@ static var_info _cm_vtab_fresnel_physical[] = { "We added this array input after SAM 2022.12.21 to replace the functionality of former single value inputs dispatch_factor1 through dispatch_factor9", "Time of Delivery Factors","ppa_multiplier_model=0&csp_financial_model<5&is_dispatch=1&sim_type=1","", "SIMULATION_PARAMETER" }, + // Day of week for weekday/weekend schedules + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "Time of Delivery Factors", "?=0", "", "" }, + { SSC_INPUT, SSC_NUMBER, "ppa_soln_mode", "PPA solution mode (0=Specify IRR target, 1=Specify PPA price)", "", "", "Financial Solution Mode", "ppa_multiplier_model=0&csp_financial_model<5&is_dispatch=1&sim_type=1", "", "SIMULATION_PARAMETER" }, { SSC_INPUT, SSC_ARRAY, "ppa_price_input", "PPA solution mode (0=Specify IRR target, 1=Specify PPA price)", "", "", "Financial Solution Mode", "ppa_multiplier_model=0&csp_financial_model<5&is_dispatch=1&sim_type=1", "", "SIMULATION_PARAMETER" }, @@ -1046,7 +1049,7 @@ class cm_fresnel_physical : public compute_module } else { // Block schedules C_timeseries_schedule_inputs offtaker_block = C_timeseries_schedule_inputs(as_matrix("weekday_schedule"), - as_matrix("weekend_schedule"), as_vector_double("f_turb_tou_periods"), std::numeric_limits::quiet_NaN()); + as_matrix("weekend_schedule"), as_vector_double("f_turb_tou_periods"), std::numeric_limits::quiet_NaN(), as_number("start_day_of_year")); offtaker_schedule = offtaker_block; } @@ -1113,7 +1116,7 @@ class cm_fresnel_physical : public compute_module if (is_one_assigned || is_dispatch) { elec_pricing_schedule = C_timeseries_schedule_inputs(as_matrix("dispatch_sched_weekday"), as_matrix("dispatch_sched_weekend"), - as_vector_double("dispatch_tod_factors"), ppa_price_year1); + as_vector_double("dispatch_tod_factors"), ppa_price_year1, as_number("start_day_of_year")); } else { // If electricity pricing data is not available, then dispatch to a uniform schedule diff --git a/ssc/cmod_fresnel_physical_iph.cpp b/ssc/cmod_fresnel_physical_iph.cpp index 2bda1e298..26dcb053a 100644 --- a/ssc/cmod_fresnel_physical_iph.cpp +++ b/ssc/cmod_fresnel_physical_iph.cpp @@ -236,6 +236,9 @@ static var_info _cm_vtab_fresnel_physical_iph[] = { { SSC_INPUT, SSC_ARRAY, "dispatch_tod_factors", "TOD factors for periods 1 through 9", "", "", "Time of Delivery Factors", "ppa_multiplier_model=0&csp_financial_model<5&is_dispatch=1", "", "" }, { SSC_INPUT, SSC_ARRAY, "ppa_price_input_heat_btu", "PPA prices - yearly", "$/MMBtu", "", "Revenue", "ppa_multiplier_model=0&csp_financial_model<5&is_dispatch=1", "", "" }, + // Day of week for weekday/weekend schedules + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "Time of Delivery Factors", "?=0", "", "" }, + // Capital Costs // Direct Capital Costs { SSC_INPUT, SSC_NUMBER, "site_improvements_spec_cost", "Site Improvement Cost per m2", "$/m2", "", "Capital_Costs", "?=0", "", "" }, @@ -889,7 +892,7 @@ class cm_fresnel_physical_iph : public compute_module // Block schedules if (is_timestep_load_fractions == 0) { C_timeseries_schedule_inputs offtaker_block = C_timeseries_schedule_inputs(as_matrix("weekday_schedule"), - as_matrix("weekend_schedule"), as_vector_double("f_turb_tou_periods"), std::numeric_limits::quiet_NaN()); + as_matrix("weekend_schedule"), as_vector_double("f_turb_tou_periods"), std::numeric_limits::quiet_NaN(), as_number("start_day_of_year")); offtaker_schedule = offtaker_block; } else if (is_timestep_load_fractions == 1) { @@ -1072,7 +1075,7 @@ class cm_fresnel_physical_iph : public compute_module if (is_one_assigned || is_dispatch) { elec_pricing_schedule = C_timeseries_schedule_inputs(as_matrix("dispatch_sched_weekday"), - as_matrix("dispatch_sched_weekend"), as_vector_double("dispatch_tod_factors"), ppa_price_year1); + as_matrix("dispatch_sched_weekend"), as_vector_double("dispatch_tod_factors"), ppa_price_year1, as_number("start_day_of_year")); } else { // If electricity pricing data is not available, then dispatch to a uniform schedule diff --git a/ssc/cmod_fuelcell.cpp b/ssc/cmod_fuelcell.cpp index 38cf2396e..69591821a 100644 --- a/ssc/cmod_fuelcell.cpp +++ b/ssc/cmod_fuelcell.cpp @@ -87,6 +87,9 @@ var_info vtab_fuelcell_input[] = { { SSC_INPUT, SSC_MATRIX, "dispatch_manual_fuelcell_sched", "Dispatch schedule for weekday", "", "", "Fuel Cell", "", "", "" }, { SSC_INPUT, SSC_MATRIX, "dispatch_manual_fuelcell_sched_weekend", "Dispatch schedule for weekend", "", "", "Fuel Cell", "", "", "" }, + // Start day of week for manual dispatch arrays + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "Fuel Cell", "?=0", "", "" }, + { SSC_INOUT, SSC_NUMBER, "capacity_factor", "Capacity factor", "%", "", "", "?=0", "", "" }, { SSC_INOUT, SSC_NUMBER, "annual_energy", "Annual AC energy in Year 1", "kWh", "", "", "?=0", "", "" }, @@ -141,7 +144,7 @@ void cm_fuelcell::construct() fuelCell = std::move(tmp2); std::unique_ptr tmp3(new FuelCellDispatch(fuelCell.get(), fcVars->numberOfUnits, - fcVars->dispatchOption, fcVars->shutdownOption, fcVars->dt_hour, fcVars->fixed_percent, fcVars->dispatch_kW, + fcVars->dispatchOption, fcVars->shutdownOption, fcVars->dt_hour, fcVars->fixed_percent, fcVars->startDayOfYear, fcVars->dispatch_kW, fcVars->canCharge, fcVars->canDischarge, fcVars->discharge_percentByPeriod, fcVars->discharge_unitsByPeriod, fcVars->scheduleWeekday,fcVars->scheduleWeekend)); fuelCellDispatch = std::move(tmp3); diff --git a/ssc/cmod_fuelcell.h b/ssc/cmod_fuelcell.h index 2c4f91d8e..990d8c033 100644 --- a/ssc/cmod_fuelcell.h +++ b/ssc/cmod_fuelcell.h @@ -76,7 +76,8 @@ struct fuelCellVariables discharge_percent(cm.as_vector_double("dispatch_manual_percent_fc_discharge")), discharge_units(cm.as_vector_unsigned_long("dispatch_manual_units_fc_discharge")), scheduleWeekday(cm.as_matrix_unsigned_long("dispatch_manual_fuelcell_sched")), - scheduleWeekend(cm.as_matrix_unsigned_long("dispatch_manual_fuelcell_sched_weekend")) + scheduleWeekend(cm.as_matrix_unsigned_long("dispatch_manual_fuelcell_sched_weekend")), + startDayOfYear(cm.as_number("start_day_of_year")) { numberOfYears = 1; if (systemUseLifetimeOutput) { @@ -157,6 +158,7 @@ struct fuelCellVariables size_t numberOfRecordsPerYear; size_t numberOfLifetimeRecords; size_t stepsPerHour; + size_t startDayOfYear; // generation input std::vector systemGeneration_kW; diff --git a/ssc/cmod_geothermal.cpp b/ssc/cmod_geothermal.cpp index cdfadebfb..18bad9aad 100644 --- a/ssc/cmod_geothermal.cpp +++ b/ssc/cmod_geothermal.cpp @@ -162,6 +162,9 @@ static var_info _cm_vtab_geothermal[] = { { SSC_INPUT, SSC_NUMBER, "allow_reservoir_replacements", "Allow reservoir replacements", "", "", "GeoHourly", "?=0", "", "" }, + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "GeoHourly", "?=0", "", "" }, + + // OUTPUTS // VARTYPE DATATYPE NAME LABEL UNITS META GROUP REQUIRED_IF CONSTRAINTS UI_HINTS @@ -456,7 +459,8 @@ class cm_geothermal : public compute_module // hybrid dispatch schedule, which will set the value for pbInputs.TOU const char *sched = as_string("hybrid_dispatch_schedule"); int tou[8760]; - if (!util::translate_schedule(tou, sched, sched, 0, 8)) + int start_day = as_number("start_day_of_year"); + if (!util::translate_schedule(tou, sched, sched, 0, 8, start_day)) throw general_error("could not translate schedule for time-of-use rate"); // weather file and time-of-use data diff --git a/ssc/cmod_mspt_iph.cpp b/ssc/cmod_mspt_iph.cpp index cc0e2e831..343b8ebfb 100644 --- a/ssc/cmod_mspt_iph.cpp +++ b/ssc/cmod_mspt_iph.cpp @@ -289,6 +289,8 @@ static var_info _cm_vtab_mspt_iph[] = { { SSC_INPUT, SSC_ARRAY, "dispatch_tod_factors", "TOD factors for periods 1 through 9", "", "", "Time of Delivery Factors", "ppa_multiplier_model=0&csp_financial_model<5&is_dispatch=1&sim_type=1", "", "SIMULATION_PARAMETER" }, { SSC_INPUT, SSC_ARRAY, "ppa_price_input_heat_btu", "PPA prices - yearly", "$/MMBtu", "", "Revenue", "ppa_multiplier_model=0&csp_financial_model<5&is_dispatch=1", "", "" }, +// Day of week for weekday/weekend schedules +{ SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "Time of Delivery Factors", "?=0", "", "" }, // Costs { SSC_INPUT, SSC_NUMBER, "tower_fixed_cost", "Tower fixed cost", "$", "", "System Costs", "*", "", "" }, @@ -1686,7 +1688,7 @@ class cm_mspt_iph : public compute_module } else { // Block schedules C_timeseries_schedule_inputs offtaker_block = C_timeseries_schedule_inputs(as_matrix("weekday_schedule"), - as_matrix("weekend_schedule"), as_vector_double("f_turb_tou_periods"), std::numeric_limits::quiet_NaN()); + as_matrix("weekend_schedule"), as_vector_double("f_turb_tou_periods"), std::numeric_limits::quiet_NaN(), as_number("start_day_of_year")); offtaker_schedule = offtaker_block; } @@ -1753,7 +1755,7 @@ class cm_mspt_iph : public compute_module if (is_one_assigned || is_dispatch) { elec_pricing_schedule = C_timeseries_schedule_inputs(as_matrix("dispatch_sched_weekday"), - as_matrix("dispatch_sched_weekend"), as_vector_double("dispatch_tod_factors"), ppa_price_year1); + as_matrix("dispatch_sched_weekend"), as_vector_double("dispatch_tod_factors"), ppa_price_year1, as_number("start_day_of_year")); } else { // If electricity pricing data is not available, then dispatch to a uniform schedule diff --git a/ssc/cmod_tcsmolten_salt.cpp b/ssc/cmod_tcsmolten_salt.cpp index 5a6938466..18858c6c5 100644 --- a/ssc/cmod_tcsmolten_salt.cpp +++ b/ssc/cmod_tcsmolten_salt.cpp @@ -356,6 +356,9 @@ static var_info _cm_vtab_tcsmolten_salt[] = { { SSC_INPUT, SSC_ARRAY, "dispatch_tod_factors", "TOD factors for periods 1 through 9", "", "We added this array input after SAM 2022.12.21 to replace the functionality of former single value inputs dispatch_factor1 through dispatch_factor9", "Time of Delivery Factors", "ppa_multiplier_model=0&csp_financial_model<5&is_dispatch=1&sim_type=1", "", "SIMULATION_PARAMETER" }, + // Day of week for weekday/weekend schedules + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "Time of Delivery Factors", "?=0", "", "" }, + { SSC_INPUT, SSC_ARRAY, "ppa_price_input", "PPA prices - yearly", "$/kWh", "", "Revenue", "ppa_multiplier_model=0&csp_financial_model<5&is_dispatch=1&sim_type=1", "", "SIMULATION_PARAMETER"}, { SSC_INPUT, SSC_MATRIX, "mp_energy_market_revenue", "Energy market revenue input", "", "Lifetime x 2[Cleared Capacity(MW),Price($/MWh)]", "Revenue", "csp_financial_model=6&is_dispatch=1&sim_type=1", "", "SIMULATION_PARAMETER"}, @@ -2050,7 +2053,7 @@ class cm_tcsmolten_salt : public compute_module } else { // Block schedules C_timeseries_schedule_inputs offtaker_block = C_timeseries_schedule_inputs(as_matrix("weekday_schedule"), as_matrix("weekend_schedule"), - as_vector_double("f_turb_tou_periods"), std::numeric_limits::quiet_NaN()); + as_vector_double("f_turb_tou_periods"), std::numeric_limits::quiet_NaN(), as_number("start_day_of_year")); offtaker_schedule = offtaker_block; } @@ -2115,7 +2118,7 @@ class cm_tcsmolten_salt : public compute_module if (is_one_assigned || is_dispatch) { elec_pricing_schedule = C_timeseries_schedule_inputs(as_matrix("dispatch_sched_weekday"), as_matrix("dispatch_sched_weekend"), - as_vector_double("dispatch_tod_factors"), ppa_price_year1); + as_vector_double("dispatch_tod_factors"), ppa_price_year1, as_number("start_day_of_year")); } else { // If electricity pricing data is not available, then dispatch to a uniform schedule diff --git a/ssc/cmod_trough_physical.cpp b/ssc/cmod_trough_physical.cpp index 8cbe688b5..bd6a2f85f 100644 --- a/ssc/cmod_trough_physical.cpp +++ b/ssc/cmod_trough_physical.cpp @@ -309,6 +309,9 @@ static var_info _cm_vtab_trough_physical[] = { { SSC_INPUT, SSC_ARRAY, "dispatch_tod_factors", "TOD factors for periods 1 through 9", "", "We added this array input after SAM 2022.12.21 to replace the functionality of former single value inputs dispatch_factor1 through dispatch_factor9", "Time of Delivery Factors","sim_type=1&ppa_multiplier_model=0&csp_financial_model<5&is_dispatch=1","", "SIMULATION_PARAMETER" }, + // Day of week for weekday/weekend schedules + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "Time of Delivery Factors", "?=0", "", "" }, + { SSC_INPUT, SSC_NUMBER, "is_timestep_load_fractions","Use turbine load fraction for each timestep instead of block dispatch?", "", "", "tou", "?=0", "", "SIMULATION_PARAMETER" }, { SSC_INPUT, SSC_ARRAY, "timestep_load_fractions", "Turbine load fraction for each timestep, alternative to block dispatch", "", "", "tou", "?", "", "SIMULATION_PARAMETER" }, { SSC_INPUT, SSC_ARRAY, "ppa_price_input", "PPA prices - yearly", "$/kWh", "", "Revenue", "sim_type=1&ppa_multiplier_model=0&csp_financial_model<5&is_dispatch=1","", "SIMULATION_PARAMETER" }, @@ -1668,7 +1671,7 @@ class cm_trough_physical : public compute_module } else { // Block schedules C_timeseries_schedule_inputs offtaker_block = C_timeseries_schedule_inputs(as_matrix("weekday_schedule"), - as_matrix("weekend_schedule"), as_vector_double("f_turb_tou_periods"), std::numeric_limits::quiet_NaN()); + as_matrix("weekend_schedule"), as_vector_double("f_turb_tou_periods"), std::numeric_limits::quiet_NaN(), as_number("start_day_of_year")); offtaker_schedule = offtaker_block; } @@ -1733,7 +1736,7 @@ class cm_trough_physical : public compute_module if (is_one_assigned || is_dispatch) { elec_pricing_schedule = C_timeseries_schedule_inputs(as_matrix("dispatch_sched_weekday"), as_matrix("dispatch_sched_weekend"), - as_vector_double("dispatch_tod_factors"), ppa_price_year1); + as_vector_double("dispatch_tod_factors"), ppa_price_year1, as_number("start_day_of_year")); } else { // If electricity pricing data is not available, then dispatch to a uniform schedule diff --git a/ssc/cmod_trough_physical_iph.cpp b/ssc/cmod_trough_physical_iph.cpp index e1fdcc95f..d0525f874 100644 --- a/ssc/cmod_trough_physical_iph.cpp +++ b/ssc/cmod_trough_physical_iph.cpp @@ -265,7 +265,10 @@ static var_info _cm_vtab_trough_physical_iph[] = { "We added this array input after SAM 2022.12.21 to replace the functionality of former single value inputs dispatch_factor1 through dispatch_factor9", "Time of Delivery Factors","ppa_multiplier_model=0&csp_financial_model<5&is_dispatch=1","", "" }, // *Electricity* hourly price multipliers from time series input { SSC_INPUT, SSC_ARRAY, "dispatch_factors_ts", "Time series electricity price multipliers", "", "", "tou", "ppa_multiplier_model=1&csp_financial_model<5&is_dispatch=1","", "" }, - + + // Day of week for weekday/weekend schedules + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "Time of Delivery Factors", "?=0", "", "" }, + // Control for *heat* output { SSC_INPUT, SSC_NUMBER, "is_timestep_load_fractions","0: block dispatch, 1: hourly load fraction, 2: absolute load", "", "", "tou", "?=0", "", "" }, { SSC_INPUT, SSC_ARRAY, "timestep_load_fractions", "Heat sink load fraction for each timestep, alternative to block dispatch", "", "", "tou", "is_timestep_load_fractions=1", "", "" }, @@ -1501,7 +1504,7 @@ class cm_trough_physical_iph : public compute_module // Block schedules if(is_timestep_load_fractions == 0) { // Block schedules C_timeseries_schedule_inputs offtaker_block = C_timeseries_schedule_inputs(as_matrix("weekday_schedule"), - as_matrix("weekend_schedule"), as_vector_double("f_turb_tou_periods"), std::numeric_limits::quiet_NaN()); + as_matrix("weekend_schedule"), as_vector_double("f_turb_tou_periods"), std::numeric_limits::quiet_NaN(), as_number("start_day_of_year")); offtaker_schedule = offtaker_block; } // Hourly load fractions @@ -1691,7 +1694,7 @@ class cm_trough_physical_iph : public compute_module if (is_one_assigned || is_dispatch) { elec_pricing_schedule = C_timeseries_schedule_inputs(as_matrix("dispatch_sched_weekday"), - as_matrix("dispatch_sched_weekend"), as_vector_double("dispatch_tod_factors"), ppa_price_year1); + as_matrix("dispatch_sched_weekend"), as_vector_double("dispatch_tod_factors"), ppa_price_year1, as_number("start_day_of_year")); } else { // If electricity pricing data is not available, then dispatch to a uniform schedule diff --git a/ssc/cmod_utilityrate5.cpp b/ssc/cmod_utilityrate5.cpp index 02d102428..5d44e3a2f 100644 --- a/ssc/cmod_utilityrate5.cpp +++ b/ssc/cmod_utilityrate5.cpp @@ -280,6 +280,8 @@ void rate_setup::setup(var_table* vt, int num_recs_yearly, size_t nyears, rate_d ssc_number_t* parr = 0; ssc_number_t* ts_sr = NULL; ssc_number_t* ts_br = NULL; + size_t start_day_of_year = vt->as_number("start_day_of_year"); + rate.init(num_recs_yearly); double inflation_rate = vt->as_double("inflation_rate") * 0.01; @@ -363,7 +365,7 @@ void rate_setup::setup(var_table* vt, int num_recs_yearly, size_t nyears, rate_d bool sell_eq_buy = vt->as_boolean("ur_sell_eq_buy"); - rate.setup_energy_rates(ec_weekday, ec_weekend, tou_rows, ec_tou_in, sell_eq_buy); + rate.setup_energy_rates(ec_weekday, ec_weekend, tou_rows, ec_tou_in, sell_eq_buy, start_day_of_year); ssc_number_t* dc_weekday = NULL; ssc_number_t* dc_weekend = NULL; ssc_number_t* dc_tou_in = NULL; ssc_number_t* dc_flat_in = NULL; size_t dc_tier_rows = 0; size_t dc_flat_rows = 0; @@ -403,7 +405,7 @@ void rate_setup::setup(var_table* vt, int num_recs_yearly, size_t nyears, rate_d throw exec_error(cm_name, ss.str()); } dc_flat_rows = nrows; - rate.setup_demand_charges(dc_weekday, dc_weekend, dc_tier_rows, dc_tou_in, dc_flat_rows, dc_flat_in); + rate.setup_demand_charges(dc_weekday, dc_weekend, dc_tier_rows, dc_tou_in, dc_flat_rows, dc_flat_in, start_day_of_year); } int metering_option = vt->as_integer("ur_metering_option"); diff --git a/ssc/common.cpp b/ssc/common.cpp index 1d9deeea3..62d939df4 100644 --- a/ssc/common.cpp +++ b/ssc/common.cpp @@ -1246,7 +1246,9 @@ bool forecast_price_signal::setup(size_t step_per_hour) vartab->as_matrix_unsigned_long("dispatch_sched_weekday"), vartab->as_matrix_unsigned_long("dispatch_sched_weekend"), step_per_hour, - vartab->as_vector_double("dispatch_tod_factors"), ppa); + vartab->as_vector_double("dispatch_tod_factors"), + vartab->as_number("start_day_of_year"), + ppa); } else { // assumption on size - check that is requested size. @@ -1404,6 +1406,8 @@ var_info vtab_utility_rate_common[] = { { SSC_INPUT, SSC_MATRIX, "ur_dc_billing_demand_periods", "Billing demand applicability to a given demand charge time of use period", "", "", "Electricity Rates", "ur_enable_billing_demand=1", "", "SIMULATION_PARAMETER" }, { SSC_INPUT, SSC_ARRAY, "ur_yearzero_usage_peaks", "Peak usage by month for year zero", "kW", "12", "Electricity Rates", "ur_enable_billing_demand=1", "", "SIMULATION_PARAMETER" }, + // Day of week for weekday/weekend schedules + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "Electricity Rates", "?=0", "", "" }, var_info_invalid }; diff --git a/ssc/common_financial.cpp b/ssc/common_financial.cpp index 814fb1a27..19e0f9a6e 100644 --- a/ssc/common_financial.cpp +++ b/ssc/common_financial.cpp @@ -1197,8 +1197,8 @@ bool dispatch_calculations::setup() schedwkend.assign(disp_weekend, nrows, ncols); int tod[8760]; - - if (!util::translate_schedule(tod, schedwkday, schedwkend, 1, 9)) + int start_day = m_cm->as_number("start_day_of_year"); + if (!util::translate_schedule(tod, schedwkday, schedwkend, 1, 9, start_day)) { m_error = "could not translate weekday and weekend schedules for dispatch values"; throw general_error(m_error); @@ -3315,6 +3315,7 @@ var_info vtab_tod_dispatch_periods[] = { { SSC_INPUT, SSC_ARRAY, "dispatch_tod_factors", "TOD factors for periods 1 through 9", "", "", "Revenue", "ppa_multiplier_model=0", "", "" }, { SSC_INPUT, SSC_MATRIX, "dispatch_sched_weekday", "Diurnal weekday TOD periods", "1..9", "12 x 24 matrix", "Revenue", "ppa_multiplier_model=0", "", "" }, { SSC_INPUT, SSC_MATRIX, "dispatch_sched_weekend", "Diurnal weekend TOD periods", "1..9", "12 x 24 matrix", "Revenue", "ppa_multiplier_model=0", "", "" }, + { SSC_INPUT, SSC_NUMBER, "start_day_of_year", "Start day of year for TOD periods", "0..6", "0=Monday, 6=Sunday", "Revenue", "?=0", "", "" }, var_info_invalid }; var_info vtab_update_tech_outputs[] = { diff --git a/tcs/csp_solver_core.h b/tcs/csp_solver_core.h index 30a915581..e52dee598 100644 --- a/tcs/csp_solver_core.h +++ b/tcs/csp_solver_core.h @@ -257,7 +257,7 @@ class C_timeseries_schedule_inputs std::vector mv_timeseries_schedule_data; C_timeseries_schedule_inputs(const util::matrix_t& weekdays, const util::matrix_t& weekends, - std::vector tod_factors, double base_value /*dimensional*/); + std::vector tod_factors, double base_value /*dimensional*/, size_t start_day_of_year /*0 = Mon, 6 = Sun*/); C_timeseries_schedule_inputs(std::vector& timeseries_values_in, double base_value /*dimensional*/); diff --git a/tcs/csp_solver_tou_block_schedules.cpp b/tcs/csp_solver_tou_block_schedules.cpp index 4d250543c..f0b6a1c36 100644 --- a/tcs/csp_solver_tou_block_schedules.cpp +++ b/tcs/csp_solver_tou_block_schedules.cpp @@ -37,7 +37,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "lib_util.h" C_timeseries_schedule_inputs::C_timeseries_schedule_inputs(const util::matrix_t& weekdays, const util::matrix_t& weekends, - std::vector tod_factors, double base_value /*dimensional*/) + std::vector tod_factors, double base_value /*dimensional*/, size_t start_day_of_year /*0 = Mon, 6 = Sun*/) { input_type = BLOCK; @@ -45,8 +45,7 @@ C_timeseries_schedule_inputs::C_timeseries_schedule_inputs(const util::matrix_t< // and does not report an error or message if this happens int tod[8760]; - - if (!util::translate_schedule(tod, weekdays, weekends, 1, 9)) { + if (!util::translate_schedule(tod, weekdays, weekends, 1, 9, start_day_of_year)) { std::string m_error_msg = "TOU schedules must have 12 rows and 24 columns"; throw C_csp_exception( m_error_msg, "TOU block schedule init" ); } diff --git a/test/input_cases/shared_rate_data.cpp b/test/input_cases/shared_rate_data.cpp index e87042214..017538757 100644 --- a/test/input_cases/shared_rate_data.cpp +++ b/test/input_cases/shared_rate_data.cpp @@ -68,11 +68,12 @@ void set_up_default_commercial_rate_data(rate_data& data) 10, 1, 9.9999999999999998e+37, 0, 11, 1, 9.9999999999999998e+37, 0 }; size_t dc_flat_rows = 12; + size_t start_day_of_year = 0; data.rate_scale = { 1, 1.025 }; data.init(8760); - data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0]); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0], start_day_of_year); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.init_energy_rates_all_months(false); // enable_nm and nm_credits_w_rollover default to false, meaning this is a net billing rate @@ -92,11 +93,12 @@ void set_up_pge_residential_rate_data(rate_data& data) size_t dc_tou_rows = 1; bool sell_eq_buy = false; size_t dc_flat_rows = 12; + size_t start_day_of_year = 0; data.rate_scale = { 1, 1.025 }; data.init(8760); //data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0]); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], ec_tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], ec_tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.init_energy_rates_all_months(false); data.enable_nm = true; data.nm_credits_w_rollover = true; @@ -115,10 +117,11 @@ void set_up_residential_1_4_peak(rate_data& data, size_t steps_per_hour) size_t dc_tou_rows = 1; bool sell_eq_buy = false; size_t dc_flat_rows = 12; + size_t start_day_of_year = 0; data.rate_scale = { 1, 1.025 }; data.init(8760 * steps_per_hour); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], ec_tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], ec_tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.init_energy_rates_all_months(false); data.enable_nm = true; data.nm_credits_w_rollover = true; @@ -137,6 +140,7 @@ void set_up_time_series(rate_data& data) size_t dc_tou_rows = 1; bool sell_eq_buy = false; size_t dc_flat_rows = 12; + size_t start_day_of_year = 0; ssc_number_t ur_ts_sell_rate[8760]; ssc_number_t ur_ts_buy_rate[8760]; @@ -154,7 +158,7 @@ void set_up_time_series(rate_data& data) data.en_ts_sell_rate = true; data.setup_time_series(8760, ur_ts_sell_rate, ur_ts_buy_rate); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], ec_tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], ec_tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.init_energy_rates_all_months(false); data.enable_nm = false; // Can't have time series rates with nm data.nm_credits_w_rollover = false; @@ -199,11 +203,12 @@ void set_up_simple_demand_charge(rate_data& data) 10, 1, 9.9999999999999998e+37, 1, 11, 1, 9.9999999999999998e+37, 1 }; size_t dc_flat_rows = 12; + size_t start_day_of_year = 0; data.rate_scale = { 1, 1.025 }; data.init(8760); - data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0]); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0], start_day_of_year); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.uses_billing_demand = true; data.en_billing_demand_lookback = false; data.init_energy_rates_all_months(false); @@ -250,11 +255,12 @@ void set_up_tou_demand_charge(rate_data& data) 10, 1, 9.9999999999999998e+37, 1, 11, 1, 9.9999999999999998e+37, 1 }; size_t dc_flat_rows = 12; + size_t start_day_of_year = 0; data.rate_scale = { 1, 1.025 }; data.init(8760); - data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0]); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0], start_day_of_year); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.uses_billing_demand = true; data.en_billing_demand_lookback = false; data.init_energy_rates_all_months(false); diff --git a/test/shared_test/lib_battery_dispatch_manual_test.cpp b/test/shared_test/lib_battery_dispatch_manual_test.cpp index fe05cb95c..8638e36e5 100644 --- a/test/shared_test/lib_battery_dispatch_manual_test.cpp +++ b/test/shared_test/lib_battery_dispatch_manual_test.cpp @@ -43,7 +43,7 @@ TEST_F(ManualTest_lib_battery_dispatch, PowerLimitsDispatchManualAC) { powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; @@ -74,7 +74,7 @@ TEST_F(ManualTest_lib_battery_dispatch, PowerLimitsDispatchManualDC) { powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::DC_CONNECTED; @@ -103,7 +103,7 @@ TEST_F(ManualTest_lib_battery_dispatch, CurrentLimitsDispatchManualAC) { powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; @@ -133,7 +133,7 @@ TEST_F(ManualTest_lib_battery_dispatch, CurrentLimitsDispatchManualDC) { powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::DC_CONNECTED; @@ -166,7 +166,7 @@ TEST_F(ManualTest_lib_battery_dispatch, BothLimitsDispatchManualAC) { testDischargeMaxPower, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; @@ -217,7 +217,7 @@ TEST_F(ManualTest_lib_battery_dispatch, BothLimitsDispatchManualDC) { powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::DC_CONNECTED; @@ -267,7 +267,7 @@ TEST_F(ManualTest_lib_battery_dispatch, DispatchChangeFrequency) { powerDischargeMax, testMinTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; @@ -314,7 +314,7 @@ TEST_F(ManualTest_lib_battery_dispatch, SOCLimitsOnDispatch) { powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; @@ -373,7 +373,7 @@ TEST_F(ManualTest_lib_battery_dispatch, ManualGridChargingOffTest) powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::DC_CONNECTED; @@ -399,7 +399,7 @@ TEST_F(ManualTest_lib_battery_dispatch, ManualGridChargingOnTest) powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, testCanGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - testPercentGridCharge, canClipCharge, canCurtailCharge, interconnection_limit); + testPercentGridCharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; @@ -425,7 +425,7 @@ TEST_F(ManualTest_lib_battery_dispatch, ManualGridChargingOnDCConnectedTest) powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, testCanGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - testPercentGridCharge, canClipCharge, canCurtailCharge, interconnection_limit); + testPercentGridCharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::DC_CONNECTED; @@ -452,7 +452,7 @@ TEST_F(ManualTest_lib_battery_dispatch, NoGridChargingWhilePVIsOnTest) powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, testCanGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - testPercentGridCharge, canClipCharge, canCurtailCharge, interconnection_limit); + testPercentGridCharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; @@ -471,7 +471,7 @@ TEST_F(ManualTest_lib_battery_dispatch, EfficiencyLimitsDispatchManualDC) powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::DC_CONNECTED; @@ -502,7 +502,7 @@ TEST_F(ManualTest_lib_battery_dispatch, InverterEfficiencyCutoffDC) currentDischargeMax, powerChargeMax, powerDischargeMax, powerChargeMax, powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, - canDischarge, testCanGridcharge, canDischargeToGrid, canGridcharge, testPercentGridCharge, testPercentGridCharge, canClipCharge, canCurtailCharge, interconnection_limit); + canDischarge, testCanGridcharge, canDischargeToGrid, canGridcharge, testPercentGridCharge, testPercentGridCharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::DC_CONNECTED; @@ -545,7 +545,7 @@ TEST_F(ManualTest_lib_battery_dispatch_losses, TestLossesWithDispatch) powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::DC_CONNECTED; @@ -570,7 +570,7 @@ TEST_F(ManualTest_lib_battery_dispatch_availability_losses, TestAvailabilityLoss powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::DC_CONNECTED; @@ -599,7 +599,7 @@ TEST_F(ManualTest_lib_battery_dispatch, TestDischargeToGrid) powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canGridcharge, testCanDischargeToGrid, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; @@ -625,7 +625,7 @@ TEST_F(ManualTest_lib_battery_dispatch, TestClipCharging) powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, testDoNothingExceptClipCharge, testDoNothingExceptClipCharge, testDoNothingExceptClipCharge, testDoNothingExceptClipCharge, testDoNothingExceptClipCharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::DC_CONNECTED; @@ -647,7 +647,7 @@ TEST_F(ManualTest_lib_battery_dispatch, OutageWithManualDispatch) { powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canGridcharge, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; @@ -720,7 +720,7 @@ TEST_F(ManualTest_lib_battery_dispatch, PVPriorityLoadFirst) powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year, chargeOnlySystemExceedLoad, dischargeOnlyLoadExceedSystem, SOC_min_outage, priorityChargeBattery); batteryPower = dispatchManual->getBatteryPower(); @@ -747,7 +747,7 @@ TEST_F(ManualTest_lib_battery_dispatch, PVPriorityBatteryFirst) powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year, chargeOnlySystemExceedLoad, dischargeOnlyLoadExceedSystem, SOC_min_outage, priorityChargeBattery); batteryPower = dispatchManual->getBatteryPower(); @@ -773,7 +773,7 @@ TEST_F(ManualTest_lib_battery_dispatch, ManualInterconnectionLimitTest) powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canDischargeToGrid, canGridcharge, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::DC_CONNECTED; @@ -798,7 +798,7 @@ TEST_F(ManualTest_lib_battery_dispatch, TestDischargeToGridInterconnectionLimit) powerDischargeMax, minimumModeTime, dispatchChoice, meterPosition, scheduleWeekday, scheduleWeekend, canCharge, canDischarge, canGridcharge, canGridcharge, testCanDischargeToGrid, percentDischarge, - percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit); + percentGridcharge, canClipCharge, canCurtailCharge, interconnection_limit, start_hour_of_year); batteryPower = dispatchManual->getBatteryPower(); batteryPower->connectionMode = ChargeController::AC_CONNECTED; diff --git a/test/shared_test/lib_battery_dispatch_manual_test.h b/test/shared_test/lib_battery_dispatch_manual_test.h index da2065c8f..2a6c449a3 100644 --- a/test/shared_test/lib_battery_dispatch_manual_test.h +++ b/test/shared_test/lib_battery_dispatch_manual_test.h @@ -77,6 +77,8 @@ class ManualTest_lib_battery_dispatch : public BatteryProperties, public Dispatc double interconnection_limit = 1e+38; + size_t start_hour_of_year = 0; + public: void SetUp() diff --git a/test/shared_test/lib_fuel_cell_test.h b/test/shared_test/lib_fuel_cell_test.h index 502185a9a..2f4354cc5 100644 --- a/test/shared_test/lib_fuel_cell_test.h +++ b/test/shared_test/lib_fuel_cell_test.h @@ -67,6 +67,7 @@ class FuelCellProperties : public ::testing::Test int dispatchOption; double dt_hour; double fixed_percent; + size_t start_day_of_year; std::vector dispatchInput_kW; std::vector canCharge; @@ -100,6 +101,7 @@ class FuelCellProperties : public ::testing::Test dispatchOption = FuelCellDispatch::FC_DISPATCH_OPTION::FIXED; dt_hour = 1.0; fixed_percent = 40; + start_day_of_year = 0; const double tmpValues[33] = { 0,0,50,16,21,50,25,25,50,34,32,50,44,37,50,53,42,50,62,47,49,72,50,48,82,52,47,90,52,46,100,51,45 }; efficiencyTable.assign(tmpValues, 11, 3); @@ -172,14 +174,14 @@ class FuelCellTest : public FuelCellProperties /* fuelCellDispatchStarted = new FuelCellDispatch(fuelCellStarted, numberOfUnits, dispatchOption, shutdownOption, dt_hour, fixed_percent, dispatchInput_kW, canCharge, canDischarge, discharge_percent, discharge_units, scheduleWeekday, scheduleWeekend); */ - fuelCellDispatch = new FuelCellDispatch(fuelCell, numberOfUnits, dispatchOption, shutdownOption, dt_hour, fixed_percent, + fuelCellDispatch = new FuelCellDispatch(fuelCell, numberOfUnits, dispatchOption, shutdownOption, dt_hour, fixed_percent, start_day_of_year, dispatchInput_kW, canCharge, canDischarge, discharge_percent, discharge_units, scheduleWeekday, scheduleWeekend); - fuelCellDispatchSubhourly = new FuelCellDispatch(fuelCellSubHourly, numberOfUnits, dispatchOption, shutdownOption, dt_subHourly, fixed_percent, + fuelCellDispatchSubhourly = new FuelCellDispatch(fuelCellSubHourly, numberOfUnits, dispatchOption, shutdownOption, dt_subHourly, fixed_percent, start_day_of_year, dispatchInput_kW, canCharge, canDischarge, discharge_percent, discharge_units, scheduleWeekday, scheduleWeekend); discharge_units[0] = n_multipleFuelCells; - fuelCellDispatchMultiple = new FuelCellDispatch(fuelCell, n_multipleFuelCells, dispatchOption, shutdownOption, dt_hour, fixed_percent, + fuelCellDispatchMultiple = new FuelCellDispatch(fuelCell, n_multipleFuelCells, dispatchOption, shutdownOption, dt_hour, fixed_percent, start_day_of_year, dispatchInput_kW, canCharge, canDischarge, discharge_percent, discharge_units, scheduleWeekday, scheduleWeekend); /* fuelCellDispatchMultipleStarted = new FuelCellDispatch(fuelCellStarted, n_multipleFuelCells, dispatchOption, shutdownOption, dt_hour, fixed_percent, diff --git a/test/shared_test/lib_time_test.cpp b/test/shared_test/lib_time_test.cpp index 6abaecad5..4d795c4ea 100644 --- a/test/shared_test/lib_time_test.cpp +++ b/test/shared_test/lib_time_test.cpp @@ -247,8 +247,8 @@ TEST_F(libTimeTest_lib_time, single_year_to_lifetime_interpolated_DownsampleSing // Test diurnal to flat TEST_F(libTimeTest_lib_time, flatten_diurnal_Schedule) { - std::vector flat = flatten_diurnal(schedule, schedule, 1, sched_values, multiplier); - std::vector flat30min = flatten_diurnal(schedule, schedule, 2, sched_values, multiplier); + std::vector flat = flatten_diurnal(schedule, schedule, 1, sched_values, start_day_of_year, multiplier); + std::vector flat30min = flatten_diurnal(schedule, schedule, 2, sched_values, start_day_of_year, multiplier); EXPECT_EQ(flat.size(), util::hours_per_year); EXPECT_EQ(flat30min.size(), util::hours_per_year * 2); @@ -277,7 +277,7 @@ TEST_F(libTimeTest_lib_time, flatten_diurnal_Schedule) // Test diurnal to flat TEST_F(libTimeTest_lib_time, flatten_diurnal_ScheduleTOD) { - std::vector flat = flatten_diurnal(schedule, schedule, 1, sched_values, multiplier); + std::vector flat = flatten_diurnal(schedule, schedule, 1, sched_values, start_day_of_year, multiplier); EXPECT_EQ(flat.size(), util::hours_per_year); for (size_t h = 0; h < flat.size(); h++) { @@ -298,7 +298,7 @@ TEST_F(libTimeTest_lib_time, TestDiurnalToFlat) util::matrix_t weekend(12, 24, &we); std::vector sched_values = { 2.2304, 0.8067, 0.9569, 1.1982, 0.7741, 0.9399, 1.1941, 0.6585, 0.9299}; - std::vector flat = flatten_diurnal(weekday, weekend, 1, sched_values, 1.0); + std::vector flat = flatten_diurnal(weekday, weekend, 1, sched_values, start_day_of_year, 1.0); EXPECT_EQ(flat.size(), util::hours_per_year); diff --git a/test/shared_test/lib_time_test.h b/test/shared_test/lib_time_test.h index 1afa91450..19b2f0ecc 100644 --- a/test/shared_test/lib_time_test.h +++ b/test/shared_test/lib_time_test.h @@ -59,6 +59,7 @@ class libTimeTest_lib_time : public ::testing::Test double multiplier = 2.0; double interpolation_factor = 1.0; + size_t start_day_of_year = 0; void SetUp() { diff --git a/test/shared_test/lib_util_test.cpp b/test/shared_test/lib_util_test.cpp index b99c381e6..2b5ec492d 100644 --- a/test/shared_test/lib_util_test.cpp +++ b/test/shared_test/lib_util_test.cpp @@ -63,6 +63,68 @@ TEST(libUtilTests, testNearestColValue) { ASSERT_EQ(8, util::nearest_col_index(cycles_vs_DOD, 0, 100)); } +TEST(libUtilTests, testCharScheduleStartonMonday) { + char* wkday = "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"; + char* wknd = "222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222"; + + int tod[8760]; + int start_day = 0; // Monday + bool result = util::translate_schedule(tod, wkday, wknd, 0, 8, start_day); + ASSERT_TRUE(result); + + ASSERT_EQ(0, tod[0]); + ASSERT_EQ(0, tod[24]); + ASSERT_EQ(1, tod[24 * 6]); +} + +TEST(libUtilTests, testMatrixScheduleStartonMonday) { + ssc_number_t p_ur_ec_sched_weekday[288] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + ssc_number_t p_ur_ec_sched_weekend[288] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; + + util::matrix_t wkdy(12, 24, p_ur_ec_sched_weekday[0]); + util::matrix_t wknd(12, 24, p_ur_ec_sched_weekend[0]); + + int tod[8760]; + int start_day = 0; // Monday + bool result = util::translate_schedule(tod, wkdy, wknd, 0, 8, start_day); + ASSERT_TRUE(result); + + ASSERT_EQ(1, tod[0]); + ASSERT_EQ(1, tod[24]); + ASSERT_EQ(2, tod[24 * 6]); +} + +TEST(libUtilTests, testCharScheduleStartonFriday) { + char* wkday = "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"; + char* wknd = "222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222"; + + int tod[8760]; + int start_day = 4; // Friday + bool result = util::translate_schedule(tod, wkday, wknd, 0, 8, start_day); + ASSERT_TRUE(result); + + ASSERT_EQ(0, tod[0]); + ASSERT_EQ(1, tod[24]); + ASSERT_EQ(0, tod[24 * 6]); +} + +TEST(libUtilTests, testMatrixScheduleStartonFriday) { + ssc_number_t p_ur_ec_sched_weekday[288] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + ssc_number_t p_ur_ec_sched_weekend[288] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; + + util::matrix_t wkdy(12, 24, p_ur_ec_sched_weekday[0]); + util::matrix_t wknd(12, 24, p_ur_ec_sched_weekend[0]); + + int tod[8760]; + int start_day = 4; // Friday + bool result = util::translate_schedule(tod, wkdy, wknd, 0, 8, start_day); + ASSERT_TRUE(result); + + ASSERT_EQ(1, tod[0]); + ASSERT_EQ(2, tod[24]); + ASSERT_EQ(1, tod[24 * 6]); +} + TEST(sscapiTest, SSC_DATARR_test) { // create data entries diff --git a/test/shared_test/lib_utility_rate_equations_test.cpp b/test/shared_test/lib_utility_rate_equations_test.cpp index 3eada36e2..1c5af7aee 100644 --- a/test/shared_test/lib_utility_rate_equations_test.cpp +++ b/test/shared_test/lib_utility_rate_equations_test.cpp @@ -44,10 +44,11 @@ TEST(lib_utility_rate_equations_test, test_copy) 4, 1, 9.9999999999999998e+37, 0, 0.25, 0 }; size_t tou_rows = 4; bool sell_eq_buy = false; + size_t start_day_of_year = 0; rate_data data; data.init(8760); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); rate_data data2(data); @@ -90,13 +91,14 @@ TEST(lib_utility_rate_equations_test, test_demand_charges) 10, 1, 9.9999999999999998e+37, 0, 11, 1, 9.9999999999999998e+37, 0 }; size_t dc_flat_rows = 12; + size_t start_day_of_year = 0; rate_data data; data.m_num_rec_yearly = 8760; data.rate_scale = { 1 }; data.init(8760); - data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0]); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0], start_day_of_year); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.init_energy_rates_all_months(false); data.init_dc_peak_vectors(0); @@ -154,13 +156,14 @@ TEST(lib_utility_rate_equations_test, test_seasonal_demand_charges) ssc_number_t prev_monthly_peaks[12] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; + size_t start_day_of_year = 0; rate_data data; data.m_num_rec_yearly = 8760; data.rate_scale = { 1 }; data.init(8760); - data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0]); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0], start_day_of_year); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.init_energy_rates_all_months(false); data.uses_billing_demand = true; data.en_billing_demand_lookback = false; @@ -260,6 +263,7 @@ TEST(lib_utility_rate_equations_test, test_block_step_tiers) 11, 1, 9.9999999999999998e+37, 0 }; size_t dc_flat_rows = 12; + size_t start_day_of_year = 0; ssc_number_t prev_monthly_peaks[12] = { 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500 }; @@ -269,8 +273,8 @@ TEST(lib_utility_rate_equations_test, test_block_step_tiers) data.m_num_rec_yearly = 8760; data.rate_scale = { 1 }; data.init(8760); - data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0]); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0], start_day_of_year); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.init_energy_rates_all_months(false); // This gets called once to set up all the vectors data.init_dc_peak_vectors(0); data.uses_billing_demand = true; @@ -389,12 +393,14 @@ TEST(lib_utility_rate_equations_test, test_kwh_per_kw_only) ssc_number_t prev_monthly_peaks[12] = { -500, -500, -500, -500, -500, -500, -500, -500, -500, -500, -500, -500 }; + size_t start_day_of_year = 0; + rate_data data; data.m_num_rec_yearly = 8760; data.rate_scale = { 1 }; data.init(8760); - data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0]); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0], start_day_of_year); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.init_energy_rates_all_months(false); // This gets called once to set up all the vectors data.init_dc_peak_vectors(0); data.uses_billing_demand = true; @@ -499,13 +505,14 @@ TEST(lib_utility_rate_equations_test, test_billing_demand_calcs) 11, 1, 9.9999999999999998e+37, 0 }; size_t dc_flat_rows = 12; + size_t start_day_of_year = 0; rate_data data; data.m_num_rec_yearly = 8760; data.rate_scale = { 1 }; data.init(8760); - data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0]); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0], start_day_of_year); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.init_energy_rates_all_months(false); // This gets called once to set up all the vectors for (size_t i = 0; i < 12; i++) { data.init_dc_peak_vectors(i); @@ -631,13 +638,14 @@ TEST(lib_utility_rate_equations_test, test_billing_demand_calcs_w_tou) size_t dc_flat_rows = 12; + size_t start_day_of_year = 0; rate_data data; data.m_num_rec_yearly = 8760; data.rate_scale = { 1 }; data.init(8760); - data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0]); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0], start_day_of_year); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.init_energy_rates_all_months(false); // This gets called once to set up all the vectors for (size_t i = 0; i < 12; i++) { data.init_dc_peak_vectors(i); @@ -755,13 +763,14 @@ TEST(lib_utility_rate_equations_test, test_demand_hourly_tou_charges) 11, 1, 9.9999999999999998e+37, 0 }; */ size_t dc_flat_rows = 2; + size_t start_day_of_year = 0; rate_data data; data.m_num_rec_yearly = 8760; data.rate_scale = { 1 }; data.init(8760); - data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0]); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0], start_day_of_year); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.init_energy_rates_all_months(false); data.init_dc_peak_vectors(2); @@ -824,14 +833,15 @@ TEST(lib_utility_rate_equations_test, test_demand_subhourly_tou_charges) 11, 1, 9.9999999999999998e+37, 0 }; */ size_t dc_flat_rows = 2; + size_t start_day_of_year = 0; rate_data data; data.m_num_rec_yearly = 8760*4; data.rate_scale = { 1 }; data.init(8760*4); - data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0]); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); - data.init_energy_rates_all_months(false); + data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], dc_tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0], start_day_of_year); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); + data.init_energy_rates_all_months(false); // This gets called once to set up all the vectors data.init_dc_peak_vectors(2); // Peak period 1: 5 kW, peak period 2: 10 kW diff --git a/test/shared_test/lib_utility_rate_test.cpp b/test/shared_test/lib_utility_rate_test.cpp index 2c44bec7f..0f6e64424 100644 --- a/test/shared_test/lib_utility_rate_test.cpp +++ b/test/shared_test/lib_utility_rate_test.cpp @@ -48,10 +48,11 @@ TEST(lib_utility_rate_test, test_copy) 4, 1, 9.9999999999999998e+37, 0, 0.050000000000000003, 0 }; size_t tou_rows = 4; bool sell_eq_buy = false; + size_t start_day_of_year = 0; rate_data data; data.init(8760); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.rate_scale.push_back(1.0); int steps_per_hour = 1; @@ -96,10 +97,11 @@ TEST(lib_utility_rate_test, test_tiered_tou_cost_estimates) 3, 5, 9.9999999999999998e+37, 0, 0.5611, 0, }; size_t tou_rows = 15; bool sell_eq_buy = false; + size_t start_day_of_year = 0; rate_data data; data.init(8760); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.rate_scale.push_back(1.0); int steps_per_hour = 1; @@ -143,10 +145,11 @@ TEST(lib_utility_rate_test, test_tiered_sell_rates) 2, 3, 9.9999999999999998e+37, 0, 0.3733, 0.01 }; size_t tou_rows = 6; bool sell_eq_buy = false; + size_t start_day_of_year = 0; rate_data data; data.init(8760); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.rate_scale.push_back(1.0); data.nm_credits_w_rollover = true; @@ -342,11 +345,12 @@ TEST(lib_utility_rate_test, test_sell_rates) 10, 1, 9.9999999999999998e+37, 0, 11, 1, 9.9999999999999998e+37, 0 }; size_t dc_flat_rows = 12; + size_t start_day_of_year = 0; data.rate_scale = { 1, 1.025 }; data.init(8760); - data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0]); - data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy); + data.setup_demand_charges(&p_ur_dc_sched_weekday[0], &p_ur_dc_sched_weekend[0], tou_rows, &p_ur_dc_tou_mat[0], dc_flat_rows, &p_ur_dc_flat_mat[0], start_day_of_year); + data.setup_energy_rates(&p_ur_ec_sched_weekday[0], &p_ur_ec_sched_weekend[0], tou_rows, &p_ur_ec_tou_mat[0], sell_eq_buy, start_day_of_year); data.init_energy_rates_all_months(false); data.nm_credits_w_rollover = true;