From a95a943224b8ae43471b34993e35c8faf6499f49 Mon Sep 17 00:00:00 2001 From: Steven Janzou Date: Wed, 13 Nov 2024 04:24:24 -0700 Subject: [PATCH 1/2] PVWatts-Wind-FuelCell / Host Developer running with Thermal Rates and Thermal Loads --- ssc/cmod_hybrid.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/ssc/cmod_hybrid.cpp b/ssc/cmod_hybrid.cpp index 104653ca9..a430bc3bb 100644 --- a/ssc/cmod_hybrid.cpp +++ b/ssc/cmod_hybrid.cpp @@ -414,7 +414,6 @@ class cm_hybrid : public compute_module prepend_to_output((var_table*)compute_module_outputs, "annual_fuel_usage_lifetime", arr_length, yr_0_value); prepend_to_output((var_table*)compute_module_outputs, "fuelcell_annual_energy_discharged", arr_length, yr_0_value); - ssc_data_set_table(outputs, compute_module.c_str(), compute_module_outputs); ssc_module_free(module); ssc_data_free(compute_module_outputs); @@ -591,9 +590,23 @@ class cm_hybrid : public compute_module pHybridOMSum[y] += om_landlease[y]; } } + + ssc_number_t* pThermalPower = ((var_table*)outputs)->allocate("fuelcell_power_thermal", genLength); + size_t thermalPowerLen = 0; + + for (size_t f = 0; f < fuelcells.size(); f++) { var_table fuelcell_outputs = ((var_table*)outputs)->lookup(fuelcells[f])->table; size_t count_fc; + ssc_number_t* fc_thermalpower = fuelcell_outputs.as_array("fuelcell_power_thermal", &thermalPowerLen); + if(thermalPowerLen != genLength) { + throw exec_error("hybrid", util::format("fuel cell power thermal size (%d) incorrect", (int)thermalPowerLen)); + } + else { + for (size_t i = 0; i < genLength; i++) + pThermalPower[i] = fc_thermalpower[i]; + } + ssc_number_t* om_production = fuelcell_outputs.as_array("cf_om_production", &count_fc); ssc_number_t* om_fixed = fuelcell_outputs.as_array("cf_om_fixed", &count_fc); ssc_number_t* om_capacity = fuelcell_outputs.as_array("cf_om_capacity", &count_fc); @@ -631,6 +644,9 @@ class cm_hybrid : public compute_module if (batteries.size() > 0) ssc_data_set_number(static_cast(&input), "is_hybrid", 1); // for updating battery outputs to annual length in update_battery_outputs in common_financial.cpp + if (fuelcells.size() > 0) + ssc_data_set_array(static_cast(&input), "fuelcell_power_thermal", pThermalPower, (int)thermalPowerLen); // for running cmod_thermalrate + ssc_data_set_number(static_cast(&input), "system_use_lifetime_output", 1); // set additional inputs from previous results - note - remove these from UI? From 7e52c1baa3f03ae4fd570ad047a07437663b9456 Mon Sep 17 00:00:00 2001 From: Steven Janzou Date: Fri, 15 Nov 2024 03:39:06 -0700 Subject: [PATCH 2/2] Update host developer to account for thermal savings for SAM #1903 --- ssc/cmod_host_developer.cpp | 24 ++++++++++++++++++------ ssc/cmod_thermalrate.cpp | 8 +++++--- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/ssc/cmod_host_developer.cpp b/ssc/cmod_host_developer.cpp index 444ff3bed..485a8fa71 100644 --- a/ssc/cmod_host_developer.cpp +++ b/ssc/cmod_host_developer.cpp @@ -51,8 +51,8 @@ static var_info _cm_vtab_host_developer[] = { { SSC_INPUT, SSC_ARRAY, "utility_bill_w_sys", "Electricity bill for system", "$", "", "Charges by Month", "*", "", "" }, { SSC_INPUT, SSC_MATRIX, "charge_w_sys_dc_tou_ym", "Demand charge with system (TOU)", "$", "", "Charges by Month", "*", "", "COL_LABEL=MONTHS,FORMAT_SPEC=CURRENCY,GROUP=UR_AM" }, - { SSC_INPUT, SSC_ARRAY, "annual_energy_value", "Energy value", "$", "", "System Output", "*", "", "" }, - { SSC_INPUT, SSC_ARRAY, "annual_thermal_value", "Energy value", "$", "", "System Output", "", "", "" }, + // { SSC_INPUT, SSC_ARRAY, "annual_energy_value", "Energy value", "$", "", "System Output", "*", "", "" }, + { SSC_INPUT, SSC_ARRAY, "annual_thermal_value", "Host thermal value", "$", "", "System Output", "", "", "" }, { SSC_INPUT, SSC_ARRAY, "gen", "Power generated by renewable resource", "kW", "", "System Output", "*", "", "" }, // { SSC_OUTPUT, SSC_ARRAY, "gen_purchases", "Electricity from grid", "kW", "", "System Output", "", "", "" }, @@ -852,6 +852,7 @@ enum { CF_cumulative_payback_with_expenses, CF_nte, CF_host_energy_value, + CF_host_thermal_value, @@ -1017,6 +1018,8 @@ class cm_host_developer : public compute_module double om_opt_fuel_1_usage = as_double("om_opt_fuel_1_usage"); double om_opt_fuel_2_usage = as_double("om_opt_fuel_2_usage"); + + // additional o and m sub types (e.g. batteries and fuel cells) int add_om_num_types = as_integer("add_om_num_types"); ssc_number_t nameplate1 = 0; @@ -2822,7 +2825,16 @@ class cm_host_developer : public compute_module // ---------------------------------------------------------------------------- // Host calculations based on thirdpartyownership with PPA agreement - + if (is_assigned("annual_thermal_value")) { + arrp = as_array("annual_thermal_value", &count); + if ((int)count != nyears + 1) + throw exec_error("host developer", util::format("thermal value input wrong length (%d) shouCF_host_energy_valueld be (%d)", count, nyears + 1)); + i = 0; + while (i < nyears && i < (int)count) { + cf.at(CF_host_thermal_value, i + 1) = (double)arrp[i + 1]; + i++; + } + } // output from utility rate already nyears+1 - no offset arrp = as_array("annual_energy_value", &count); if ((int)count != nyears + 1) @@ -2840,7 +2852,7 @@ class cm_host_developer : public compute_module cf.at(CF_after_tax_cash_flow, i) = cf.at(CF_after_tax_net_equity_cost_flow, i) - + cf.at(CF_host_energy_value, i); + + cf.at(CF_host_energy_value, i) + cf.at(CF_host_thermal_value, i); cf.at(CF_payback_with_expenses, i) = cf.at(CF_after_tax_cash_flow, i); @@ -3346,8 +3358,8 @@ class cm_host_developer : public compute_module save_cf( CF_debt_payment_principal, nyears, "cf_debt_payment_principal" ); save_cf( CF_debt_balance, nyears, "cf_debt_balance" ); - save_cf( CF_energy_value, nyears, "cf_energy_value" ); - save_cf( CF_ppa_price, nyears, "cf_ppa_price" ); + save_cf(CF_energy_value, nyears, "cf_energy_value"); + save_cf( CF_ppa_price, nyears, "cf_ppa_price" ); save_cf( CF_om_fixed_expense, nyears, "cf_om_fixed_expense" ); save_cf( CF_om_production_expense, nyears, "cf_om_production_expense" ); save_cf( CF_om_capacity_expense, nyears, "cf_om_capacity_expense" ); diff --git a/ssc/cmod_thermalrate.cpp b/ssc/cmod_thermalrate.cpp index c6bcf6030..69363b81b 100644 --- a/ssc/cmod_thermalrate.cpp +++ b/ssc/cmod_thermalrate.cpp @@ -72,9 +72,11 @@ static var_info vtab_thermal_rate[] = { { SSC_OUTPUT, SSC_ARRAY, "annual_thermal_value", "Thermal value", "$", "", "Annual", "*", "", "" }, // { SSC_OUTPUT, SSC_ARRAY, "annual_thermal_revenue_with_system", "Thermal value with system", "$", "", "Annual", "*", "", "" }, // { SSC_OUTPUT, SSC_ARRAY, "annual_thermal_revenue_without_system", "Thermal value without system", "$", "", "Annual", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "thermal_revenue_with_system", "Thermal revenue with system", "$", "", "Time Series", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "thermal_revenue_without_system", "Thermal revenue without system", "$", "", "Time Series", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "thermal_load_year1", "Thermal load (year 1)", "$", "", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "thermal_revenue_with_system", "Thermal revenue with system", "$", "", "Time Series", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "thermal_revenue_without_system", "Thermal revenue without system", "$", "", "Time Series", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "thermal_cost_with_system", "Thermal cost with system", "$", "", "Time Series", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "thermal_cost_without_system", "Thermal cost without system", "$", "", "Time Series", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "thermal_load_year1", "Thermal load (year 1)", "$", "", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "thermal_savings_year1", "Thermal savings (year 1)", "$", "", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "thermal_cost_with_system_year1", "Thermal cost with sytem (year 1)", "$", "", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "thermal_cost_without_system_year1", "Thermal cost without system (year 1)", "$", "", "", "*", "", "" },