diff --git a/shared/lib_battery_powerflow.cpp b/shared/lib_battery_powerflow.cpp index 595c5136c..58f682949 100644 --- a/shared/lib_battery_powerflow.cpp +++ b/shared/lib_battery_powerflow.cpp @@ -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), @@ -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; @@ -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; @@ -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, @@ -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) { diff --git a/ssc/cmod_battery.cpp b/ssc/cmod_battery.cpp index d6578bb51..59bdcd7a7 100644 --- a/ssc/cmod_battery.cpp +++ b/ssc/cmod_battery.cpp @@ -1175,7 +1175,7 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c } // TODO: fix this! - std::vector adj_losses; + std::vector 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 diff --git a/ssc/cmod_battery_stateful.cpp b/ssc/cmod_battery_stateful.cpp index 917d3f1c6..83e23debd 100644 --- a/ssc/cmod_battery_stateful.cpp +++ b/ssc/cmod_battery_stateful.cpp @@ -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", "" }, @@ -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", "", "", "" }, @@ -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); @@ -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); @@ -539,6 +547,8 @@ std::shared_ptr 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); diff --git a/ssc/cmod_pvsamv1.cpp b/ssc/cmod_pvsamv1.cpp index 9c4b18936..aa289c26b 100644 --- a/ssc/cmod_pvsamv1.cpp +++ b/ssc/cmod_pvsamv1.cpp @@ -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 @@ -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)) { @@ -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) { diff --git a/ssc/common.cpp b/ssc/common.cpp index bc1df631c..f956419c3 100644 --- a/ssc/common.cpp +++ b/ssc/common.cpp @@ -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[] = { diff --git a/test/shared_test/lib_battery_dispatch_automatic_btm_test.cpp b/test/shared_test/lib_battery_dispatch_automatic_btm_test.cpp index f27f81dc8..c96aa9d0f 100644 --- a/test/shared_test/lib_battery_dispatch_automatic_btm_test.cpp +++ b/test/shared_test/lib_battery_dispatch_automatic_btm_test.cpp @@ -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; diff --git a/test/shared_test/lib_battery_powerflow_test.cpp b/test/shared_test/lib_battery_powerflow_test.cpp index dfa31a533..e3f23de60 100644 --- a/test/shared_test/lib_battery_powerflow_test.cpp +++ b/test/shared_test/lib_battery_powerflow_test.cpp @@ -2871,233 +2871,6 @@ TEST_F(BatteryPowerFlowTest_lib_battery_powerflow, DC_PVCharging_ExcessLoad_Flex check_net_flows(std::string()); } -TEST_F(BatteryPowerFlowTest_lib_battery_powerflow, AC_system_w_ac_losses) { - m_batteryPower->connectionMode = ChargeController::AC_CONNECTED; - - m_batteryPower->canSystemCharge = true; - m_batteryPower->canDischarge = true; - m_batteryPower->canGridCharge = false; - m_batteryPower->powerSystem = 100; - m_batteryPower->powerLoad = 50; - - // Try to charge - but 100% system loss - m_batteryPower->acLossSystemAvailability = 1; - m_batteryPower->powerBatteryDC = -50 * m_batteryPower->singlePointEfficiencyACToDC; - m_batteryPowerFlow->calculate(); - - EXPECT_NEAR(m_batteryPower->powerBatteryAC, -50, error); // Dispatch would be responsible for reducing this to zero in the full code - EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToBattery, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToLoad, 50, error); - EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerConversionLoss, 2, error); - EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); - - double gen = m_batteryPower->powerSystem + m_batteryPower->powerBatteryAC; - EXPECT_NEAR(m_batteryPower->powerGeneratedBySystem, gen, error); - EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); - - // Try to charge when inverter loss is 100%, disallowed - m_batteryPower->powerSystem = 0; - m_batteryPower->powerLoad = 50; - m_batteryPower->acLossSystemAvailability = 0; - m_batteryPower->acLossWiring = 1; - - // Try to charge - 100% inverter loss means no available power - m_batteryPower->powerBatteryDC = -50 * m_batteryPower->singlePointEfficiencyACToDC; - m_batteryPowerFlow->calculate(); - - EXPECT_NEAR(m_batteryPower->powerBatteryAC, 0, error); // Grid charge error handling reduces this to zero - EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToBattery, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToLoad, 50, error); - EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerConversionLoss, 0, error); - - gen = m_batteryPower->powerSystem + m_batteryPower->powerBatteryAC; - EXPECT_NEAR(m_batteryPower->powerGeneratedBySystem, gen, error); - EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); - EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); - - // Allow grid charging - m_batteryPower->powerSystem = 0; - m_batteryPower->powerLoad = 50; - m_batteryPower->acLossSystemAvailability = 0; - m_batteryPower->acLossWiring = 1; - m_batteryPower->canGridCharge = true; - - // Try to charge - grid charging provides power even with inverter off - m_batteryPower->powerBatteryDC = -50 * m_batteryPower->singlePointEfficiencyACToDC; - m_batteryPowerFlow->calculate(); - - EXPECT_NEAR(m_batteryPower->powerBatteryAC, -50, error); - EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToBattery, 50, error); - EXPECT_NEAR(m_batteryPower->powerGridToLoad, 50, error); - EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerConversionLoss, 2.0, error); - - gen = m_batteryPower->powerSystem + m_batteryPower->powerBatteryAC; - EXPECT_NEAR(m_batteryPower->powerGeneratedBySystem, gen, error); - EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); - EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); - - // Cannot grid charge with post batt loss - m_batteryPower->powerSystem = 0; - m_batteryPower->powerLoad = 50; - m_batteryPower->acLossSystemAvailability = 1; - m_batteryPower->acLossWiring = 0; - m_batteryPower->canGridCharge = true; - - // Try to charge - but 100% system loss - m_batteryPower->powerBatteryDC = -50 * m_batteryPower->singlePointEfficiencyACToDC; - m_batteryPowerFlow->calculate(); - - EXPECT_NEAR(m_batteryPower->powerBatteryAC, -50, error); - EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToBattery, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToLoad, 50, error); - EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerConversionLoss, 2.0, error); - - gen = m_batteryPower->powerSystem + m_batteryPower->powerBatteryAC; - EXPECT_NEAR(m_batteryPower->powerGeneratedBySystem, gen, error); - EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); - EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); - - // Try to discharge to load w/ inverter loss - m_batteryPower->acLossSystemAvailability = 0; - m_batteryPower->acLossWiring = 1; - m_batteryPower->powerBatteryDC = 50; - m_batteryPowerFlow->calculate(); - - EXPECT_NEAR(m_batteryPower->powerBatteryAC, 48, error); - EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToBattery, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToLoad, 2, error); - EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 48, error); - EXPECT_NEAR(m_batteryPower->powerConversionLoss, 2.0, error); - EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); - - gen = m_batteryPower->powerSystem + m_batteryPower->powerBatteryAC; - EXPECT_NEAR(m_batteryPower->powerGeneratedBySystem, gen, error); - EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); - - // Cannot discharge to load w/ post batt loss - m_batteryPower->acLossSystemAvailability = 1; - m_batteryPower->acLossWiring = 0; - m_batteryPower->powerBatteryDC = 50; - m_batteryPowerFlow->calculate(); - - EXPECT_NEAR(m_batteryPower->powerBatteryAC, 48, error); - EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToBattery, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToLoad, 50, error); - EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerConversionLoss, 2, error); - EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); - - gen = m_batteryPower->powerSystem + m_batteryPower->powerBatteryAC; - EXPECT_NEAR(m_batteryPower->powerGeneratedBySystem, gen, error); - EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); - - // Try to discharge to grid w/ inverter loss - m_batteryPower->acLossSystemAvailability = 0; - m_batteryPower->acLossWiring = 1; - m_batteryPower->powerLoad = 0; - m_batteryPower->powerBatteryDC = 50; - m_batteryPowerFlow->calculate(); - - EXPECT_NEAR(m_batteryPower->powerBatteryAC, 48, error); - EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToBattery, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToGrid, 48, error); - EXPECT_NEAR(m_batteryPower->powerConversionLoss, 2.0, error); - EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); - - gen = m_batteryPower->powerSystem + m_batteryPower->powerBatteryAC; - EXPECT_NEAR(m_batteryPower->powerGeneratedBySystem, gen, error); - EXPECT_NEAR(m_batteryPower->powerLoad, 0, error); - - // Cannot discharge w/ post batt loss - m_batteryPower->acLossSystemAvailability = 1; - m_batteryPower->acLossWiring = 0; - m_batteryPower->powerBatteryDC = 50; - m_batteryPowerFlow->calculate(); - - EXPECT_NEAR(m_batteryPower->powerBatteryAC, 48, error); - EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToBattery, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerConversionLoss, 2, error); - EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); - - gen = m_batteryPower->powerSystem + m_batteryPower->powerBatteryAC; - EXPECT_NEAR(m_batteryPower->powerGeneratedBySystem, gen, error); - EXPECT_NEAR(m_batteryPower->powerLoad, 0, error); - - // Post batt loss affects meeting critical load - m_batteryPower->acLossSystemAvailability = 0.05; - m_batteryPower->acLossWiring = 0; - m_batteryPower->powerBatteryDC = 50; - m_batteryPower->isOutageStep = true; - m_batteryPower->powerCritLoad = 50; - m_batteryPower->powerLoad = 50; - m_batteryPowerFlow->calculate(); - - EXPECT_NEAR(m_batteryPower->powerBatteryAC, 48, error); - EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToBattery, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 45.6, error); - EXPECT_NEAR(m_batteryPower->powerCritLoadUnmet, 4.4, error); - EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerConversionLoss, 2, error); - EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); - EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); - - // Increasing batt power allows meeting critical load - m_batteryPower->acLossSystemAvailability = 0.05; - m_batteryPower->acLossWiring = 0; - m_batteryPower->powerBatteryDC = 60; - m_batteryPower->isOutageStep = true; - m_batteryPower->powerLoad = 50; - m_batteryPower->powerCritLoad = 50; - m_batteryPowerFlow->calculate(); - - EXPECT_NEAR(m_batteryPower->powerBatteryAC, 55.4, error); - EXPECT_NEAR(m_batteryPower->powerBatteryDC, 57.7, error); - EXPECT_NEAR(m_batteryPower->powerSystemToLoad, 0, error); - EXPECT_NEAR(m_batteryPower->powerSystemToBatteryAC, 0, error); - EXPECT_NEAR(m_batteryPower->powerGridToBattery, 0, error); - EXPECT_NEAR(m_batteryPower->powerBatteryToLoad, 50.0, error); - EXPECT_NEAR(m_batteryPower->powerCritLoadUnmet, 0.0, error); - EXPECT_NEAR(m_batteryPower->powerSystemToGrid, 0, error); - EXPECT_NEAR(m_batteryPower->powerConversionLoss, 2.308, error); - EXPECT_NEAR(m_batteryPower->powerSystemLoss, 0.0, error); - EXPECT_NEAR(m_batteryPower->powerLoad, 50, error); -} - TEST_F(BatteryPowerFlowTest_lib_battery_powerflow, DC_system_w_ac_losses) { m_batteryPower->connectionMode = ChargeController::DC_CONNECTED; diff --git a/test/ssc_test/cmod_battery_stateful_test.cpp b/test/ssc_test/cmod_battery_stateful_test.cpp index 9048a44cb..161eea11b 100644 --- a/test/ssc_test/cmod_battery_stateful_test.cpp +++ b/test/ssc_test/cmod_battery_stateful_test.cpp @@ -325,7 +325,7 @@ TEST_F(CMBatteryStatefulIntegration_cmod_battery_stateful, AdaptiveTimestep) { } TEST_F(CMBatteryStatefulIntegration_cmod_battery_stateful, TestCycleCount) { - std::string js = "{\"control_mode\": 0.0, \"dt_hr\": 0.002777777777777778, \"input_current\": 0.0, \"C_rate\": 0.2, \"Qexp\": 60.75, \"Qfull\": 75.56, \"Qnom\": 73.58, \"Vcut\": 3.0, \"Vexp\": 3.529, \"Vfull\": 4.2, \"Vnom\": 3.35, \"Vnom_default\": 3.6, \"chem\": 1.0, \"initial_SOC\": 66.0, \"life_model\": 1.0, \"maximum_SOC\": 100.0, \"minimum_SOC\": 0.0, \"resistance\": 0.001155, \"voltage_choice\": 0.0, \"Cp\": 980.0, \"T_room_init\": 29.69998526573181, \"h\": 8.066, \"loss_choice\": 0.0, \"mass\": 1.55417, \"monthly_charge_loss\": [0.0], \"monthly_discharge_loss\": [0.0], \"monthly_idle_loss\": [0.0], \"nominal_energy\": 0.272, \"nominal_voltage\": 3.6, \"replacement_option\": 0.0, \"schedule_loss\": [0.0], \"surface_area\": 0.1548, \"I\": 0.0, \"I_chargeable\": -8045.99999999998, \"I_dischargeable\": 643.841000000002, \"P\": 0.0, \"P_chargeable\": -108.70616176055955, \"P_dischargeable\": 1.9341550347606316, \"Q\": 53.21000000000006, \"Q_max\": 75.56, \"SOC\": 70.42085759661204, \"T_batt\": 30.07627155118435, \"T_room\": 29.69998526573181, \"V\": 3.7667917861703755, \"heat_dissipated\": 0.0004698373776256373, \"indices_replaced\": [0.0], \"last_idx\": 8639.0, \"loss_kw\": 0.0, \"n_replacements\": 0.0, \"DOD_max\": 1.0, \"DOD_min\": 0.0, \"I_loss\": 0.0, \"SOC_prev\": 70.42085759661204, \"T_batt_prev\": 30.0747312729467, \"average_range\": 33.594321796748574, \"b1_dt\": 0.008196217640552396, \"b2_dt\": 1.1539245050321905e-05, \"b3_dt\": 0.0421665242517969, \"c0_dt\": 76.8158487840016, \"c2_dt\": 3.772090139902601e-05, \"cell_current\": 0.0, \"cell_voltage\": 3.7667917861703755, \"chargeChange\": 0.0, \"charge_mode\": 1.0, \"cum_dt\": 0.9998842592591438, \"temp_dt\": 291.947118, \"cycle_DOD\": 100.0, \"cycle_DOD_max\": [0.0, 100.0, 100.0, 100.0], \"cycle_counts\": [[0.0, 1], [0.16094315625949207, 1], [100.0, 1], [0.6220222339862289, 1]], \"cycle_range\": 0.6220222339862289, \"day_age_of_battery\": 0.9998842592591438, \"dq_relative_li1\": 0.0, \"dq_relative_li2\": 0.0, \"dq_relative_li3\": 0.0, \"dq_relative_neg\": 0.0, \"n_cycles\": 3.0, \"prev_charge\": 2.0, \"q0\": 53.21000000000006, \"q_relative\": 100.0, \"q_relative_cycle\": 0.0, \"q_relative_li\": 100.0, \"q_relative_neg\": 100.0, \"q_relative_thermal\": 100.0, \"qmax_lifetime\": 75.56, \"qmax_thermal\": 75.56, \"rainflow_Xlt\": 0.6220222339862431, \"rainflow_Ylt\": 20.103229221810423, \"rainflow_jlt\": 4.0, \"rainflow_peaks\": [100.0, 0.0, 20.103229221810423, 19.48120698782418]}"; + std::string js = "{\"control_mode\": 0.0, \"dt_hr\": 0.002777777777777778, \"input_current\": 0.0, \"C_rate\": 0.2, \"Qexp\": 60.75, \"Qfull\": 75.56, \"Qnom\": 73.58, \"Vcut\": 3.0, \"Vexp\": 3.529, \"Vfull\": 4.2, \"Vnom\": 3.35, \"Vnom_default\": 3.6, \"chem\": 1.0, \"initial_SOC\": 66.0, \"life_model\": 1.0, \"maximum_SOC\": 100.0, \"minimum_SOC\": 0.0, \"resistance\": 0.001155, \"voltage_choice\": 0.0, \"Cp\": 980.0, \"T_room_init\": 29.69998526573181, \"h\": 8.066, \"loss_choice\": 0.0, \"mass\": 1.55417, \"monthly_charge_loss\": [0.0], \"monthly_discharge_loss\": [0.0], \"monthly_idle_loss\": [0.0], \"nominal_energy\": 0.272, \"nominal_voltage\": 3.6, \"replacement_option\": 0.0, \"schedule_loss\": [0.0], \"surface_area\": 0.1548, \"I\": 0.0, \"I_chargeable\": -8045.99999999998, \"I_dischargeable\": 643.841000000002, \"P\": 0.0, \"P_chargeable\": -108.70616176055955, \"P_dischargeable\": 1.9341550347606316, \"Q\": 53.21000000000006, \"Q_max\": 75.56, \"SOC\": 70.42085759661204, \"T_batt\": 30.07627155118435, \"T_room\": 29.69998526573181, \"V\": 3.7667917861703755, \"heat_dissipated\": 0.0004698373776256373, \"indices_replaced\": [0.0], \"last_idx\": 8639.0, \"loss_kw\": 0.0, \"n_replacements\": 0.0, \"DOD_max\": 1.0, \"DOD_min\": 0.0, \"I_loss\": 0.0, \"SOC_prev\": 70.42085759661204, \"T_batt_prev\": 30.0747312729467, \"average_range\": 33.594321796748574, \"b1_dt\": 0.008196217640552396, \"b2_dt\": 1.1539245050321905e-05, \"b3_dt\": 0.0421665242517969, \"c0_dt\": 76.8158487840016, \"c2_dt\": 3.772090139902601e-05, \"cell_current\": 0.0, \"cell_voltage\": 3.7667917861703755, \"chargeChange\": 0.0, \"charge_mode\": 1.0, \"cum_dt\": 0.9998842592591438, \"temp_dt\": 291.947118, \"cycle_DOD\": 100.0, \"cycle_DOD_max\": [0.0, 100.0, 100.0, 100.0], \"cycle_counts\": [[0.0, 1], [0.16094315625949207, 1], [100.0, 1], [0.6220222339862289, 1]], \"cycle_range\": 0.6220222339862289, \"day_age_of_battery\": 0.9998842592591438, \"dq_relative_li1\": 0.0, \"dq_relative_li2\": 0.0, \"dq_relative_li3\": 0.0, \"dq_relative_neg\": 0.0, \"n_cycles\": 3.0, \"prev_charge\": 2.0, \"q0\": 53.21000000000006, \"q_relative\": 100.0, \"q_relative_cycle\": 0.0, \"q_relative_li\": 100.0, \"q_relative_neg\": 100.0, \"q_relative_thermal\": 100.0, \"qmax_lifetime\": 75.56, \"qmax_thermal\": 75.56, \"rainflow_Xlt\": 0.6220222339862431, \"rainflow_Ylt\": 20.103229221810423, \"rainflow_jlt\": 4.0, \"rainflow_peaks\": [100.0, 0.0, 20.103229221810423, 19.48120698782418], \"percent_unavailable\": 0.0, \"percent_unavailable_prev\": 0.0}"; data = json_to_ssc_data(js.c_str()); mod = ssc_module_create("battery_stateful");