Skip to content

Commit

Permalink
Add adjust losses to batt stateful, clean up cmod batt to fix seh exc…
Browse files Browse the repository at this point in the history
…eption (still doesn't relay losses properly
  • Loading branch information
brtietz committed Nov 7, 2024
1 parent 638998f commit 7bb945e
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 263 deletions.
6 changes: 3 additions & 3 deletions shared/lib_battery_powerflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ BatteryPower::BatteryPower(double dtHour) :
voltageSystem(0),
acLossWiring(0.0),
acLossSystemAvailability(0.0),
adjustLosses(0.0),
acXfmrLoadLoss(0.0),
acXfmrNoLoadLoss(0.0),
acXfmrRating(0.0),
Expand Down Expand Up @@ -151,6 +152,7 @@ BatteryPower::BatteryPower(const BatteryPower& orig) {
voltageSystem = orig.voltageSystem;
acLossWiring = orig.acLossWiring;
acLossSystemAvailability = orig.acLossSystemAvailability;
adjustLosses = orig.adjustLosses;
acXfmrLoadLoss = orig.acXfmrLoadLoss;
acXfmrNoLoadLoss = orig.acXfmrNoLoadLoss;
acXfmrRating = orig.acXfmrRating;
Expand Down Expand Up @@ -218,6 +220,7 @@ void BatteryPower::reset()
voltageSystem = 0;
acLossWiring = 0.0;
acLossSystemAvailability = 0.0;
adjustLosses = 0.0;
acXfmrLoadLoss = 0.0;
acXfmrNoLoadLoss = 0.0;
isOutageStep = false;
Expand Down Expand Up @@ -332,7 +335,6 @@ void BatteryPowerFlow::calculateACConnected()
double P_load_ac = m_BatteryPower->powerLoad;
double P_crit_load_ac = m_BatteryPower->powerCritLoad;
double P_system_loss_ac = m_BatteryPower->powerSystemLoss;
double system_availability_loss = m_BatteryPower->acLossSystemAvailability; // Losses due to system availability. Inverter losses are accounted for in the PV numbers already
double P_pv_to_batt_ac, P_grid_to_batt_ac, P_fuelcell_to_batt_ac,
P_batt_to_load_ac, P_grid_to_load_ac, P_pv_to_load_ac, P_fuelcell_to_load_ac, P_available_pv,
P_pv_to_grid_ac, P_batt_to_grid_ac, P_fuelcell_to_grid_ac, P_gen_ac, P_grid_ac,
Expand Down Expand Up @@ -365,8 +367,6 @@ void BatteryPowerFlow::calculateACConnected()
// Code simplification to remove redundancy for code that should use either critical load or actual load
double calc_load_ac = (m_BatteryPower->isOutageStep ? P_crit_load_ac : P_load_ac);

P_pv_ac *= (1 - system_availability_loss);

// charging and idle
if (P_battery_ac <= 0)
{
Expand Down
2 changes: 1 addition & 1 deletion ssc/cmod_battery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1175,7 +1175,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c
}

// TODO: fix this!
std::vector<double> adj_losses;
std::vector<double> adj_losses(8760, 0.0);
if (batt_vars->batt_loss_choice == losses_params::MONTHLY) {
if (*std::min_element(batt_vars->batt_losses_charging.begin(), batt_vars->batt_losses_charging.end()) < 0
|| *std::min_element(batt_vars->batt_losses_discharging.begin(), batt_vars->batt_losses_discharging.end()) < 0
Expand Down
10 changes: 10 additions & 0 deletions ssc/cmod_battery_stateful.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ var_info vtab_battery_stateful_inputs[] = {
{ SSC_INPUT, SSC_ARRAY, "monthly_discharge_loss", "Battery system losses when discharging", "[kW]", "", "ParamsPack", "?=0", "", "" },
{ SSC_INPUT, SSC_ARRAY, "monthly_idle_loss", "Battery system losses when idle", "[kW]", "", "ParamsPack", "?=0", "", "" },
{ SSC_INPUT, SSC_ARRAY, "schedule_loss", "Battery system losses at each timestep", "[kW]", "", "ParamsPack", "?=0", "", "" },
{ SSC_INPUT, SSC_ARRAY, "availabilty_loss", "Battery availability losses at each timestep", "[%]", "", "ParamsPack", "?=0", "", "" },


// replacement inputs
{ SSC_INPUT, SSC_NUMBER, "replacement_option", "Replacements: none (0), by capacity (1), or schedule (2)", "0=none,1=capacity limit,2=yearly schedule", "", "ParamsPack", "?=0", "INTEGER,MIN=0,MAX=2", "" },
Expand Down Expand Up @@ -128,6 +130,8 @@ var_info vtab_battery_state[] = {
{ SSC_INOUT, SSC_NUMBER, "charge_mode", "Charge (0), Idle (1), Discharge (2)", "0/1/2", "", "StateCell", "", "", "" },
{ SSC_INOUT, SSC_NUMBER, "SOC_prev", "State of Charge of last time step", "%", "", "StateCell", "", "", "" },
{ SSC_INOUT, SSC_NUMBER, "prev_charge", "Charge mode of last time step", "0/1/2", "", "StateCell", "", "", "" },
{ SSC_INOUT, SSC_NUMBER, "percent_unavailable", "Percent of system that is down", "%", "", "StateCell", "", "", "" },
{ SSC_INOUT, SSC_NUMBER, "percent_unavailable_prev", "Percent of system that was down last step", "%", "", "StateCell", "", "", "" },
{ SSC_INOUT, SSC_NUMBER, "chargeChange", "Whether Charge mode changed since last step", "0/1", "", "StateCell", "", "", "" },
{ SSC_INOUT, SSC_NUMBER, "q1_0", "Lead acid - Cell charge available", "Ah", "", "StateCell", "", "", "" },
{ SSC_INOUT, SSC_NUMBER, "q2_0", "Lead acid - Cell charge bound", "Ah", "", "StateCell", "", "", "" },
Expand Down Expand Up @@ -216,6 +220,8 @@ void write_battery_state(const battery_state& state, var_table* vt) {
vt->assign_match_case("charge_mode", cap->charge_mode);
vt->assign_match_case("prev_charge", cap->prev_charge);
vt->assign_match_case("chargeChange", cap->chargeChange);
vt->assign_match_case("percent_unavailable", cap->percent_unavailable);
vt->assign_match_case("percent_unavailable_prev", cap->percent_unavailable_prev);

int choice;
vt_get_int(vt, "chem", &choice);
Expand Down Expand Up @@ -325,6 +331,8 @@ void read_battery_state(battery_state& state, var_table* vt) {
vt_get_int(vt, "charge_mode", &cap->charge_mode);
vt_get_int(vt, "prev_charge", &cap->prev_charge);
vt_get_bool(vt, "chargeChange", &cap->chargeChange);
vt_get_number(vt, "percent_unavailable", &cap->percent_unavailable);
vt_get_number(vt, "percent_unavailable_prev", &cap->percent_unavailable_prev);

int choice;
vt_get_int(vt, "chem", &choice);
Expand Down Expand Up @@ -539,6 +547,8 @@ std::shared_ptr<battery_params> create_battery_params(var_table* vt, double dt_h
vt_get_array_vec(vt, "schedule_loss", losses->schedule_loss);
}

vt_get_array_vec(vt, "availabilty_loss", losses->adjust_loss);

// replacements
auto replacements = params->replacement;
vt_get_int(vt, "replacement_option", &choice);
Expand Down
73 changes: 45 additions & 28 deletions ssc/cmod_pvsamv1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3055,16 +3055,27 @@ void cm_pvsamv1::exec()

if (en_batt && batt_topology == ChargeController::AC_CONNECTED)
{
double delivered_percent = adj_factor; // Delivered percent is effectively 1 before this line, so just set it to adj_factor
//apply lifetime daily AC losses only if they are enabled
if (system_use_lifetime_output && PVSystem->enableACLifetimeLosses)
{
//current index of the lifetime daily AC losses is the number of years that have passed (iyear, because it is 0-indexed) * days in a year + the number of complete days that have passed
int ac_loss_index = (int)iyear * 365 + (int)floor(hour_of_year / 24); //in units of days
delivered_percent *= (1 - PVSystem->acLifetimeLosses[ac_loss_index] / 100); // loss in kWac
ssc_number_t ac_lifetime_loss = PVSystem->p_systemACPower[idx] * (PVSystem->acLifetimeLosses[ac_loss_index] / 100); // loss in kWac
if (iyear == 0 || save_full_lifetime_variables == 1) {
PVSystem->p_acLifetimeLoss[idx] = ac_lifetime_loss;
}
if (iyear == 0) annual_ac_lifetime_loss += ac_lifetime_loss * ts_hour; // convert to kWh for yr 1 annual sum
PVSystem->p_systemACPower[idx] *= (100 - PVSystem->acLifetimeLosses[ac_loss_index]) / 100;
}


if (iyear == 0 || save_full_lifetime_variables == 1) {
PVSystem->p_acPerfAdjLoss[idx] = PVSystem->p_systemACPower[idx] * (1 - adj_factor);
}
//apply availability
PVSystem->p_systemACPower[idx] *= adj_factor;

double ac_loss_post_inverter = 0; // Already accounted for in pv AC power (including transformer losses)
double ac_pv_availability_loss_for_batt = 1 - delivered_percent;
double ac_pv_availability_loss_for_batt = 0; // Already accounted for as well

// calculate timestep in hour for battery models
// jj represents which timestep within the hour you're on, 0-indexed
Expand All @@ -3082,6 +3093,10 @@ void cm_pvsamv1::exec()
batt->advance(m_vartab, PVSystem->p_systemACPower[idx], 0, p_load_full[idx], p_crit_load_full[idx], ac_loss_post_inverter, ac_pv_availability_loss_for_batt);
batt->outGenWithoutBattery[idx] = PVSystem->p_systemACPower[idx];
PVSystem->p_systemACPower[idx] = batt->outGenPower[idx];
// accumulate system generation availability loss
if (iyear == 0) {
annual_ac_pre_avail += (PVSystem->p_systemACPower[idx] + PVSystem->p_acPerfAdjLoss[idx]) * ts_hour;
}

bool offline = false;
if (batt->is_outage_step(idx % 8760)) {
Expand All @@ -3099,37 +3114,39 @@ void cm_pvsamv1::exec()
PVSystem->p_transmissionLoss[idx] = 0.0;
}
}
else {

//apply lifetime daily AC losses only if they are enabled
if (system_use_lifetime_output && PVSystem->enableACLifetimeLosses)
{
//current index of the lifetime daily AC losses is the number of years that have passed (iyear, because it is 0-indexed) * days in a year + the number of complete days that have passed
int ac_loss_index = (int)iyear * 365 + (int)floor(hour_of_year / 24); //in units of days
ssc_number_t ac_lifetime_loss = PVSystem->p_systemACPower[idx] * (PVSystem->acLifetimeLosses[ac_loss_index] / 100); // loss in kWac
if (iyear == 0 || save_full_lifetime_variables == 1) {
PVSystem->p_acLifetimeLoss[idx] = ac_lifetime_loss;
}
if (iyear == 0) annual_ac_lifetime_loss += ac_lifetime_loss * ts_hour; // convert to kWh for yr 1 annual sum
PVSystem->p_systemACPower[idx] *= (100 - PVSystem->acLifetimeLosses[ac_loss_index]) / 100;
if (en_batt) {
batt->outGenWithoutBattery[idx] *= (100 - PVSystem->acLifetimeLosses[ac_loss_index]) / 100;
}
}

// accumulate system generation before curtailment and availability
if (iyear == 0) {
annual_ac_pre_avail += PVSystem->p_systemACPower[idx] * ts_hour;
}

//apply lifetime daily AC losses only if they are enabled
if (system_use_lifetime_output && PVSystem->enableACLifetimeLosses)
{
//current index of the lifetime daily AC losses is the number of years that have passed (iyear, because it is 0-indexed) * days in a year + the number of complete days that have passed
int ac_loss_index = (int)iyear * 365 + (int)floor(hour_of_year / 24); //in units of days
ssc_number_t ac_lifetime_loss = PVSystem->p_systemACPower[idx] * (PVSystem->acLifetimeLosses[ac_loss_index] / 100); // loss in kWac
if (iyear == 0 || save_full_lifetime_variables == 1) {
PVSystem->p_acLifetimeLoss[idx] = ac_lifetime_loss;
PVSystem->p_acPerfAdjLoss[idx] = PVSystem->p_systemACPower[idx] * (1 - adj_factor);
}
if (iyear == 0) annual_ac_lifetime_loss += ac_lifetime_loss * ts_hour; // convert to kWh for yr 1 annual sum
PVSystem->p_systemACPower[idx] *= (100 - PVSystem->acLifetimeLosses[ac_loss_index]) / 100;
//apply availability
PVSystem->p_systemACPower[idx] *= adj_factor;
if (en_batt) {
batt->outGenWithoutBattery[idx] *= (100 - PVSystem->acLifetimeLosses[ac_loss_index]) / 100;
batt->outGenWithoutBattery[idx] *= adj_factor;
}
}

// accumulate system generation before curtailment and availability
if (iyear == 0) {
annual_ac_pre_avail += PVSystem->p_systemACPower[idx] * ts_hour;
}

if (iyear == 0 || save_full_lifetime_variables == 1) {
PVSystem->p_acPerfAdjLoss[idx] = PVSystem->p_systemACPower[idx] * (1 - adj_factor);
}
//apply availability
PVSystem->p_systemACPower[idx] *= adj_factor;
if (en_batt) {
batt->outGenWithoutBattery[idx] *= adj_factor;
}

// Update battery with final gen to compute grid power
// TODO: use this block to apply adjustment losses to PV and battery seperately
if (en_batt) {
Expand Down
4 changes: 2 additions & 2 deletions ssc/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -567,8 +567,8 @@ var_info vtab_batt_adjustment_factors[] = {
{ SSC_INPUT,SSC_NUMBER , "batt_adjust_constant" , "DC Constant loss adjustment", "%", "", "Adjustment Factors", "?=0" , "MAX=100" , ""},
{ SSC_INPUT, SSC_NUMBER, "batt_adjust_en_timeindex" , "Enable lifetime adjustment factors", "0/1", "", "Adjustment Factors", "?=0", "BOOLEAN", "" },
{ SSC_INPUT, SSC_NUMBER, "batt_adjust_en_periods" , "Enable period-based adjustment factors", "0/1", "", "Adjustment Factors", "?=0", "BOOLEAN", "" },
{ SSC_INPUT,SSC_ARRAY , "batt_adjust_timeindex" , "DC Lifetime Adjustment Factors" , "%" , "" , "Adjustment Factors" , "dc_adjust_en_timeindex=1" , "" , ""},
{ SSC_INPUT,SSC_MATRIX , "batt_adjust_periods" , "DC Period-based Adjustment Factors" , "%" , "n x 3 matrix [ start, end, loss ]" , "Adjustment Factors" , "dc_adjust_en_periods=1" , "COLS=3" , ""},
{ SSC_INPUT,SSC_ARRAY , "batt_adjust_timeindex" , "DC Lifetime Adjustment Factors" , "%" , "" , "Adjustment Factors" , "batt_adjust_en_timeindex=1" , "" , ""},
{ SSC_INPUT,SSC_MATRIX , "batt_adjust_periods" , "DC Period-based Adjustment Factors" , "%" , "n x 3 matrix [ start, end, loss ]" , "Adjustment Factors" , "batt_adjust_en_periods=1" , "COLS=3" , ""},
var_info_invalid };

var_info vtab_financial_capacity_payments[] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,7 @@ TEST_F(AutoBTMTest_lib_battery_dispatch, DispatchAutoBTMGridOutageWithAvailabili
if (h < 6) {
batteryPower->isOutageStep = true;
batteryPower->powerCritLoad = 50;
batteryPower->acLossSystemAvailability = 1;
batteryPower->acLossSystemAvailability = 1; // TODO: redo this! This number only applies to PV now
}
else {
batteryPower->acLossSystemAvailability = 0;
Expand Down
Loading

0 comments on commit 7bb945e

Please sign in to comment.