Skip to content

Commit

Permalink
fixing merge conflicts in particle system cmod
Browse files Browse the repository at this point in the history
  • Loading branch information
jannamartinek committed Dec 13, 2023
2 parents 0f07d89 + 4e7d5ab commit 947e4df
Show file tree
Hide file tree
Showing 62 changed files with 15,461 additions and 2,867 deletions.
8 changes: 6 additions & 2 deletions shared/lib_battery_dispatch_automatic_fom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,12 @@ void dispatch_automatic_front_of_meter_t::setup_cost_forecast_vector()

ppa_prices.reserve(_forecast_hours * _steps_per_hour);
if (discharge_hours >= _forecast_hours * _steps_per_hour) {
// -1 for 0 indexed arrays, additional -1 to ensure there is always a charging price lower than the discharing price if the forecast hours is = to battery capacity in hourrs
discharge_hours = _forecast_hours * _steps_per_hour - 2;
// -1 for 0 indexed arrays, additional -1 to ensure there is always a charging price lower than the discharing price if the forecast hours is = to battery capacity in hours
// exception caused if look_ahead_hours <= 1 and _steps_per_hour =1 ). specifically, size_t extremely large if set to negative integer - see SAM issue 1547
if ((int)_forecast_hours * (int)_steps_per_hour - 2 < 0) // handles 1 hour look ahead but 0 hour look ahead still fails (should not be allowed)
discharge_hours = 0;
else
discharge_hours = _forecast_hours * _steps_per_hour - 2;
}
}

Expand Down
6 changes: 3 additions & 3 deletions shared/lib_geothermal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1348,7 +1348,7 @@ double CGeothermalAnalyzer::GetPressureChangeAcrossReservoir()
{ // Only used in GetCalculatedPumpDepthInFeet

// [7B.Reservoir Hydraulics].G70
if (mo_geo_in.me_pc == ENTER_PC) return mo_geo_in.md_ReservoirDeltaPressure * flowRatePerWell() / 1000.0;
if (mo_geo_in.me_pc == ENTER_PC) return flowRatePerWell() / mo_geo_in.md_ReservoirDeltaPressure;
double md_PressureChangeAcrossReservoir = 0.0;


Expand Down Expand Up @@ -1538,10 +1538,10 @@ double CGeothermalAnalyzer::GetNumberOfWells(void)
if (mo_geo_in.me_ct == FLASH && FlashCount() == 1) pressure_well_head = mp_geo_out->md_PressureHPFlashPSI;
else if (mo_geo_in.me_ct == FLASH && FlashCount() == 2) pressure_well_head = mp_geo_out->md_PressureLPFlashPSI;
else pressure_well_head = pressureWellHeadPSI() - mo_geo_in.md_PressureChangeAcrossSurfaceEquipmentPSI;
double prod_failed_inj_rate = (mo_geo_in.md_FailedProdFlowRatio * 1000 / mo_geo_in.md_ReservoirDeltaPressure) *
double prod_failed_inj_rate = (mo_geo_in.md_FailedProdFlowRatio * mo_geo_in.md_ReservoirDeltaPressure) *
(mo_geo_in.md_InjWellPressurePSI + geothermal::MetersToFeet(GetResourceDepthM()) * InjectionDensity() / 144.0 + (pressure_well_head) -
mo_geo_in.md_ProdWellFriction * pow(mo_geo_in.md_FailedProdFlowRatio, 2) - pressureHydrostaticPSI());
double inj_failed_inj_rate = (mo_geo_in.md_FailedProdFlowRatio * 1000 / mo_geo_in.md_ReservoirDeltaPressure) *
double inj_failed_inj_rate = (mo_geo_in.md_FailedProdFlowRatio * mo_geo_in.md_ReservoirDeltaPressure) *
(mo_geo_in.md_InjWellPressurePSI + geothermal::MetersToFeet(GetResourceDepthM()) * InjectionDensity() / 144.0 + (pressure_well_head) -
mo_geo_in.md_InjWellFriction * pow(mo_geo_in.md_FailedProdFlowRatio, 2) - pressureHydrostaticPSI());
double inj_rate_failed_prod_wells = MIN(prod_failed_inj_rate, flowRatePerWell()); //Injectivity of failed production well?
Expand Down
21 changes: 18 additions & 3 deletions shared/lib_irradproc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2293,9 +2293,24 @@ int irrad::calc() {
directNormal, diffuseHorizontal, globalHorizontal, planeOfArrayIrradianceFront,
diffuseIrradianceFront);
if (enableSubhourlyClipping) {
int errorcode_cs = poaDecomp(weatherFilePOA, surfaceAnglesRadians, sunAnglesRadians, albedo, poaAll,
clearskyIrradiance[1], clearskyIrradiance[2], clearskyIrradiance[0], planeOfArrayIrradianceFrontCS,
diffuseIrradianceFrontCS);
double hextra = sunAnglesRadians[8];
switch (skyModel) {
case 0:
isotropic(hextra, clearskyIrradiance[1], clearskyIrradiance[2], albedo,
surfaceAnglesRadians[0], surfaceAnglesRadians[1], sunAnglesRadians[1],
planeOfArrayIrradianceFrontCS, diffuseIrradianceFrontCS);
break;
case 1:
hdkr(hextra, clearskyIrradiance[1], clearskyIrradiance[2], albedo, surfaceAnglesRadians[0],
surfaceAnglesRadians[1], sunAnglesRadians[1], planeOfArrayIrradianceFrontCS,
diffuseIrradianceFrontCS);
break;
default:
perez(hextra, clearskyIrradiance[1], clearskyIrradiance[2], albedo, surfaceAnglesRadians[0],
surfaceAnglesRadians[1], sunAnglesRadians[1], planeOfArrayIrradianceFrontCS,
diffuseIrradianceFrontCS);
break;
}
}
calculatedDirectNormal = directNormal;
calculatedDiffuseHorizontal = diffuseHorizontal;
Expand Down
1 change: 1 addition & 0 deletions ssc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ set(SSC_SRC
cmod_timeseq.cpp
cmod_trough_physical.cpp
cmod_trough_physical_iph.cpp
cmod_trough_physical_iph_old.cpp
cmod_ui_tes_calcs.cpp
cmod_ui_udpc_checks.cpp
cmod_user_htf_comparison.cpp
Expand Down
7 changes: 5 additions & 2 deletions ssc/cmod_battery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ var_info vtab_battery_inputs[] = {
{ SSC_INPUT, SSC_NUMBER, "batt_dispatch_auto_btm_can_discharge_to_grid", "Behind the meter battery can discharge to grid?", "0/1", "", "BatteryDispatch", "", "", "" },
{ SSC_INPUT, SSC_NUMBER, "batt_dispatch_charge_only_system_exceeds_load", "Battery can charge from system only when system output exceeds load", "0/1", "", "BatteryDispatch", "en_batt=1&en_standalone_batt=0&batt_meter_position=0", "", "" },
{ SSC_INPUT, SSC_NUMBER, "batt_dispatch_discharge_only_load_exceeds_system","Battery can discharge battery only when load exceeds system output", "0/1", "", "BatteryDispatch", "en_batt=1&en_standalone_batt=0&batt_meter_position=0", "", "" },
{ SSC_INPUT, SSC_NUMBER, "batt_look_ahead_hours", "Hours to look ahead in automated dispatch", "hours", "", "BatteryDispatch", "", "", "" },
{ SSC_INPUT, SSC_NUMBER, "batt_look_ahead_hours", "Hours to look ahead in automated dispatch", "hours", "", "BatteryDispatch", "", "MIN=1", "" },
{ SSC_INPUT, SSC_NUMBER, "batt_dispatch_update_frequency_hours", "Frequency to update the look-ahead dispatch", "hours", "", "BatteryDispatch", "", "", "" },

// PV smoothing specific inputs
Expand Down Expand Up @@ -1335,7 +1335,10 @@ battstor::battstor(var_table& vt, bool setup_model, size_t nrec, double dt_hr, c
if (batt_vars->ec_rate_defined) {
util_rate_data = new rate_data();
rate_setup::setup(&vt, (int)step_per_year, batt_vars->analysis_period, *util_rate_data, "cmod_battery");
}
}
else if (batt_vars->batt_dispatch == dispatch_t::RETAIL_RATE) {
throw exec_error("Battery", "Cannot select retail rate dispatch without providing utility rate data.");
}
dispatch_model = new dispatch_automatic_behind_the_meter_t(battery_model, dt_hr, batt_vars->batt_minimum_SOC, batt_vars->batt_maximum_SOC,
batt_vars->batt_current_choice, batt_vars->batt_current_charge_max, batt_vars->batt_current_discharge_max,
batt_vars->batt_power_charge_max_kwdc, batt_vars->batt_power_discharge_max_kwdc,
Expand Down
90 changes: 50 additions & 40 deletions ssc/cmod_battery_eqns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,27 +118,25 @@ bool Reopt_size_standalone_battery_params(ssc_data_t data) {
auto reopt_params = var_data();
reopt_params.type = SSC_TABLE;
var_table* reopt_table = &reopt_params.table;
var_table reopt_scenario, reopt_site, reopt_electric, reopt_utility, reopt_load, reopt_fin, reopt_batt,
reopt_wind;
reopt_wind.assign("max_kw", 0);
var_table reopt_electric, reopt_utility, reopt_load, reopt_fin, reopt_batt, reopt_settings;

var_data* vd, * vd2;

double val1, val2, system_cap;
vt_get_number(vt, "system_capacity", &system_cap);

// financial inputs
map_optional_input(vt, "itc_fed_percent", &reopt_batt, "total_itc_pct", 0., true);
map_optional_input(vt, "itc_fed_percent", &reopt_batt, "total_itc_fraction", 0., true);
// TODO: what about reopt vars total_rebate_us_dollars_per_kw?

vd = vt->lookup("total_installed_cost");
if (vd) {
reopt_batt.assign("installed_cost_us_dollars_per_kw", vd->num[0] / system_cap);
reopt_batt.assign("installed_cost_per_kw", vd->num[0] / system_cap);
}

vd = vt->lookup("depr_bonus_fed");
if (vd) {
reopt_batt.assign("macrs_bonus_pct", vd->num[0] / 100.);
reopt_batt.assign("macrs_bonus_fraction", vd->num[0] / 100.);
}
vd = vt->lookup("depr_bonus_fed_macrs_5");
if (vd && vd->num[0] == 1) {
Expand All @@ -148,38 +146,35 @@ bool Reopt_size_standalone_battery_params(ssc_data_t data) {
// These exist in the GUI but not in the default PySAM export
vd = vt->lookup("battery_per_kW");
if (vd)
reopt_batt.assign("installed_cost_us_dollars_per_kw", vd->num[0]);
reopt_batt.assign("installed_cost_per_kw", vd->num[0]);
vd = vt->lookup("battery_per_kWh");
if (vd)
reopt_batt.assign("installed_cost_us_dollars_per_kwh", vd->num[0]);
reopt_batt.assign("installed_cost_per_kwh", vd->num[0]);

vd = vt->lookup("batt_dc_ac_efficiency");
vd2 = vt->lookup("batt_ac_dc_efficiency");
if (vd && vd2) {
// ReOpt's internal_efficient_pct = SAM's (batt_dc_ac_efficiency + batt_ac_dc_efficiency)/2
reopt_batt.assign("internal_efficiency_pct", (vd->num[0] + vd2->num[0]) / 200.);
}
else if (vd && !vd2) {
reopt_batt.assign("internal_efficiency_pct", vd->num[0] / 100.);

if (vd) {
reopt_batt.assign("inverter_efficiency_fraction", vd->num[0] / 100.);
}
else if (!vd && vd2) {
reopt_batt.assign("internal_efficiency_pct", vd2->num[0] / 100.);
if (vd2) {
reopt_batt.assign("rectifier_efficiency_fraction", vd2->num[0] / 100.);
}

vd = vt->lookup("batt_initial_SOC");
vd2 = vt->lookup("batt_minimum_SOC");
if (vd && vd2) {
reopt_batt.assign("soc_init_pct", vd->num[0] / 100.);
reopt_batt.assign("soc_min_pct", vd2->num[0] / 100.);
reopt_batt.assign("soc_init_fraction", vd->num[0] / 100.);
reopt_batt.assign("soc_min_fraction", vd2->num[0] / 100.);
}
else {
reopt_batt.assign("soc_init_pct", 0.5);
reopt_batt.assign("soc_min_pct", 0.15);
reopt_batt.assign("soc_init_fraction", 0.5);
reopt_batt.assign("soc_min_fraction", 0.15);
}

// battery replacement only enabled for pvsam, use REopt defaults otherwise
if ((vd = vt->lookup("om_batt_replacement_cost")))
reopt_batt.assign("replace_cost_us_dollars_per_kwh", vd->num[0]);
reopt_batt.assign("replace_cost_per_kwh", vd->num[0]);

// ReOpt's battery replacement single year versus SAM's array schedule
std::vector<double> vec;
Expand All @@ -190,6 +185,15 @@ bool Reopt_size_standalone_battery_params(ssc_data_t data) {
reopt_batt.assign("battery_replacement_year", vec[0]);
}

if (vt->is_assigned("batt_dispatch_auto_can_gridcharge")) {
vd = vt->lookup("batt_dispatch_auto_can_gridcharge");
reopt_batt.assign("can_grid_charge", vd->num[0]);
}
else {
// Grid charging is always on for battwatts
reopt_batt.assign("can_grid_charge", true);
}

//
// convert required utilityrate5 inputs
//
Expand All @@ -201,9 +205,9 @@ bool Reopt_size_standalone_battery_params(ssc_data_t data) {
// convert financial inputs and set variables not modeled by SAM to 0
//
map_input(vt, "analysis_period", &reopt_fin, "analysis_years");
map_input(vt, "rate_escalation", &reopt_fin, "escalation_pct", false, true);
map_optional_input(vt, "value_of_lost_load", &reopt_fin, "value_of_lost_load_us_dollars_per_kwh", 0);
reopt_fin.assign("microgrid_upgrade_cost_pct", 0);
map_input(vt, "rate_escalation", &reopt_fin, "elec_cost_escalation_rate_fraction", false, true);
map_optional_input(vt, "value_of_lost_load", &reopt_fin, "value_of_lost_load_per_kwh", 0);
reopt_fin.assign("microgrid_upgrade_cost_fraction", 0);

vd = vt->lookup("federal_tax_rate");
vd2 = vt->lookup("state_tax_rate");
Expand All @@ -215,18 +219,18 @@ bool Reopt_size_standalone_battery_params(ssc_data_t data) {
vd = vt->lookup("real_discount_rate");
if (vd) val2 = vd->num;
else val2 = 6.4;
reopt_fin.assign("offtaker_discount_pct", (1 + val1 / 100.) * (1 + val2 / 100.) - 1);
reopt_fin.assign("offtaker_discount_rate_fraction", (1 + val1 / 100.) * (1 + val2 / 100.) - 1);

vd = vt->lookup("om_fixed_escal");
vd2 = vt->lookup("om_production_escal");
if (vd && !vd2) {
reopt_fin.assign("om_cost_escalation_pct", vd->num[0] / system_cap);
reopt_fin.assign("om_cost_escalation_rate_fraction", vd->num[0] / system_cap);
}
else if (!vd && vd2) {
reopt_fin.assign("om_cost_escalation_pct", vd2->num[0]);
reopt_fin.assign("om_cost_escalation_rate_fraction", vd2->num[0]);
}
else if (vd && vd2) {
reopt_fin.assign("om_cost_escalation_pct", (vd->num[0] / system_cap) + vd2->num[0]);
reopt_fin.assign("om_cost_escalation_rate_fraction", (vd->num[0] / system_cap) + vd2->num[0]);
}

// convert load profile inputs, which are not net loads
Expand All @@ -242,23 +246,29 @@ bool Reopt_size_standalone_battery_params(ssc_data_t data) {
vd = vt->lookup("crit_load");
if (vd) {
vt_get_array_vec(vt, "crit_load", vec);
if (vec.size() != sim_len) {
vt->assign("error", var_data("Critical load profile's length must be same as for load."));
return false;
size_t vec_size = vec.size();
if (vec_size != sim_len) {
int analysis_period = vt->as_integer("analysis_period");
if (vec_size == sim_len * analysis_period) {
vec_size = sim_len;
}
else {
vt->assign("error", var_data("Critical load profile's length must be same as for load."));
return false;
}
}
reopt_load.assign("critical_loads_kw", var_data(&vec[0], vec.size()));
reopt_load.assign("critical_loads_kw", var_data(&vec[0], vec_size));
}

reopt_settings.assign_match_case("time_steps_per_hour", var_data((int)(sim_len / 8760)));

// assign the reopt parameter table and log messages
reopt_electric.assign_match_case("urdb_response", reopt_utility);
reopt_site.assign_match_case("ElectricTariff", reopt_electric);
reopt_site.assign_match_case("LoadProfile", reopt_load);
reopt_site.assign_match_case("Financial", reopt_fin);
reopt_site.assign_match_case("Storage", reopt_batt);
reopt_site.assign_match_case("Wind", reopt_wind);
reopt_scenario.assign_match_case("Site", reopt_site);
reopt_scenario.assign_match_case("time_steps_per_hour", var_data((int)(sim_len / 8760)));
reopt_table->assign_match_case("Scenario", reopt_scenario);
reopt_table->assign_match_case("ElectricTariff", reopt_electric);
reopt_table->assign_match_case("ElectricLoad", reopt_load);
reopt_table->assign_match_case("Financial", reopt_fin);
reopt_table->assign_match_case("ElectricStorage", reopt_batt);
reopt_table->assign_match_case("Settings", reopt_settings);
vt->assign_match_case("reopt_scenario", reopt_params);
vt->assign_match_case("log", log);
return true;
Expand Down
1 change: 1 addition & 0 deletions ssc/cmod_battery_eqns.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ static const char* Reopt_size_standalone_battery_params_doc =
" ++ Battery inputs ++\\n"
" 'batt_dc_ac_efficiency': optional double [%], Battery DC to AC efficiency, 0-100\\n"
" 'batt_ac_dc_efficiency': optional double [%], Inverter AC to battery DC efficiency, 0-100\\n"
" 'batt_dispatch_auto_can_gridcharge: optional boolean, Whether the battery is allowed to charge from the grid. Default is True.\\n"
" 'battery_per_kW': optional double [$/kW], Battery cost per kW\\n"
" 'battery_per_kWh': optional double [$/kWh], Battery cost per kWh\\n"
" 'batt_initial_SOC': optional double [%], Initial State-of-Charge, 0-100\\n"
Expand Down
Loading

0 comments on commit 947e4df

Please sign in to comment.