From f6690133080b7bddc6dab5398b2a2a1a13d67b96 Mon Sep 17 00:00:00 2001 From: dangerski Date: Thu, 14 Jan 2021 10:58:19 -0700 Subject: [PATCH 01/12] Fix for SSC issue #505 (#506) * Fix for SSC issue 505 * Update CMakeLists.txt --- CMakeLists.txt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ec88bc37..7dd726ae1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,12 +140,7 @@ endfunction() # turn off examples, tests and install for jsoncpp set(JSONCPP_WITH_EXAMPLE 0) set(JSONCPP_WITH_TESTS 0) -macro (install) -endmacro () -add_subdirectory(jsoncpp) -macro (install) - _install(${ARGV}) -endmacro(install) +add_subdirectory(jsoncpp EXCLUDE_FROM_ALL) add_subdirectory(splinter) add_subdirectory(shared) From d7ae17127cd02b863e6ec48606930a0c41f4ff8c Mon Sep 17 00:00:00 2001 From: Darice L Guittet Date: Fri, 15 Jan 2021 10:47:42 -0700 Subject: [PATCH 02/12] check for divide by zero and replace with nan (#512) --- shared/lib_pvshade.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shared/lib_pvshade.cpp b/shared/lib_pvshade.cpp index 4bc6c0f67..6c9b8367a 100644 --- a/shared/lib_pvshade.cpp +++ b/shared/lib_pvshade.cpp @@ -302,7 +302,10 @@ double sssky_diffuse_table::compute(double surface_tilt) { double Asky_shade[1000]; for (int n = 0; n < 1000; n++) { - arg[n] = (1 / tand_stilt) - (1 / (gcr * sind_stilt * (1 - n * step))); + if (surface_tilt != 0) + arg[n] = (1 / tand_stilt) - (1 / (gcr * sind_stilt * (1 - n * step))); + else + arg[n] = std::numeric_limits::quiet_NaN(); gamma[n] = (-M_PI / 2) + atan(arg[n]); tan_tilt_gamma[n] = tan(surface_tilt * DTOR + gamma[n]); Asky_shade[n] = M_PI + M_PI / pow((1 + tan_tilt_gamma[n] * tan_tilt_gamma[n]), 0.5); From 4f99be27d9ece46de176c87ecec2bff97b72d019 Mon Sep 17 00:00:00 2001 From: Prilliman Date: Thu, 28 Jan 2021 16:42:55 -0700 Subject: [PATCH 03/12] Added lcos calculations and variables to singleowner, updated variable names in common --- ssc/cmod_singleowner.cpp | 65 +++++++++++++++++++++++++++++++++------- ssc/common.cpp | 10 +++---- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/ssc/cmod_singleowner.cpp b/ssc/cmod_singleowner.cpp index 31ccb80d9..427fa1dc3 100644 --- a/ssc/cmod_singleowner.cpp +++ b/ssc/cmod_singleowner.cpp @@ -44,6 +44,11 @@ static var_info _cm_vtab_singleowner[] = { { SSC_INPUT, SSC_ARRAY, "gen", "Net power to or from the grid", "kW", "", "System Output", "*", "", "" }, { SSC_INPUT, SSC_ARRAY, "gen_without_battery", "Electricity to or from the renewable system, without the battery", "kW", "", "System Output", "", "", "" }, + { SSC_INPUT, SSC_ARRAY, "batt_annual_charge_from_system", "Battery annual energy charged from system", "kWh", "", "Battery", "en_batt=1", "", "" }, + { SSC_INPUT, SSC_ARRAY, "batt_annual_charge_from_grid", "Battery annual energy charged from grid", "kWh", "", "Battery", "en_batt=1", "", "" }, + { SSC_INPUT, SSC_ARRAY, "batt_annual_charge_energy", "Battery annual energy charged", "kWh", "", "Battery", "en_batt=1", "", "" }, + { SSC_INPUT, SSC_ARRAY, "batt_annual_discharge_energy", "Battery annual energy discharged", "kWh", "", "Battery", "en_batt=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "battery_total_cost_lcos", "Battery total investment cost", "$", "", "Battery", "en_batt=1", "", "" }, { SSC_INPUT, SSC_ARRAY, "degradation", "Annual energy degradation", "", "", "System Output", "*", "", "" }, @@ -208,6 +213,8 @@ static var_info _cm_vtab_singleowner[] = { /* salvage value */ { SSC_INPUT, SSC_NUMBER, "salvage_percentage", "Net pre-tax cash salvage value", "%", "", "Financial Parameters", "?=10", "MIN=0,MAX=100", "" }, + { SSC_INPUT, SSC_NUMBER, "batt_salvage_percentage", "Net pre-tax cash battery salvage value", "%", "", "Financial Parameters", "?=0", "MIN=0,MAX=100", "" }, + /* market specific inputs - leveraged partnership flip */ /* construction period */ @@ -556,9 +563,9 @@ static var_info _cm_vtab_singleowner[] = { { SSC_OUTPUT, SSC_ARRAY, "cf_om_production1_expense", "Battery production-based expense", "$", "", "Cash Flow Expenses", "*", "LENGTH_EQUAL=cf_length", "" }, { SSC_OUTPUT, SSC_ARRAY, "cf_om_capacity1_expense", "Battery capacity-based expense", "$", "", "Cash Flow Expenses", "*", "LENGTH_EQUAL=cf_length", "" }, - { SSC_OUTPUT, SSC_ARRAY, "cf_om_fixed2_expense", "Fuel cell fixed expense", "$", "", "Cash Flow Expenses", "*", "LENGTH_EQUAL=cf_length", "" }, - { SSC_OUTPUT, SSC_ARRAY, "cf_om_production2_expense", "Fuel cell production-based expense", "$", "", "Cash Flow Expenses", "*", "LENGTH_EQUAL=cf_length", "" }, - { SSC_OUTPUT, SSC_ARRAY, "cf_om_capacity2_expense", "Fuel cell capacity-based expense", "$", "", "Cash Flow Expenses", "*", "LENGTH_EQUAL=cf_length", "" }, + { SSC_OUTPUT, SSC_ARRAY, "cf_om_fixed2_expense", "Fuel cell fixed expense", "$", "", "Cash Flow Expenses", "", "LENGTH_EQUAL=cf_length", "" }, + { SSC_OUTPUT, SSC_ARRAY, "cf_om_production2_expense", "Fuel cell production-based expense", "$", "", "Cash Flow Expenses", "", "LENGTH_EQUAL=cf_length", "" }, + { SSC_OUTPUT, SSC_ARRAY, "cf_om_capacity2_expense", "Fuel cell capacity-based expense", "$", "", "Cash Flow Expenses", "", "LENGTH_EQUAL=cf_length", "" }, @@ -669,6 +676,10 @@ static var_info _cm_vtab_singleowner[] = { { SSC_OUTPUT, SSC_NUMBER, "npv_salvage_value", "Present value of salvage value", "$", "", "Metrics", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "npv_thermal_value", "Present value of thermal value", "$", "", "Metrics", "*", "", "" }, + //lcos + { SSC_OUTPUT, SSC_NUMBER, "lcos_nom", "Nominal levelized cost of storage", "$/kWh", "", "Metrics", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "lcos_real", "Real levelized cost of storage", "$/kWh", "", "Metrics", "*", "", "" }, + var_info_invalid }; @@ -883,7 +894,12 @@ enum { CF_energy_without_battery, - CF_max }; + CF_max, + + CF_energy_charged_grid, + CF_energy_charged_pv, + CF_energy_discharged + }; @@ -1036,14 +1052,14 @@ class cm_singleowner : public compute_module ssc_number_t nameplate1 = 0; ssc_number_t nameplate2 = 0; - if (add_om_num_types > 0) + if (add_om_num_types > 0) //PV Battery { - escal_or_annual(CF_om_fixed1_expense, nyears, "om_fixed1", inflation_rate, 1.0, false, as_double("om_fixed_escal")*0.01); - escal_or_annual(CF_om_production1_expense, nyears, "om_production1", inflation_rate, 0.001, false, as_double("om_production_escal")*0.01); - escal_or_annual(CF_om_capacity1_expense, nyears, "om_capacity1", inflation_rate, 1.0, false, as_double("om_capacity_escal")*0.01); - nameplate1 = as_number("om_capacity1_nameplate"); + escal_or_annual(CF_om_fixed1_expense, nyears, "om_batt_fixed_cost", inflation_rate, 1.0, false, as_double("om_fixed_escal")*0.01); + escal_or_annual(CF_om_production1_expense, nyears, "om_batt_variable_cost", inflation_rate, 0.001, false, as_double("om_production_escal")*0.01); + escal_or_annual(CF_om_capacity1_expense, nyears, "om_batt_capacity_cost", inflation_rate, 1.0, false, as_double("om_capacity_escal")*0.01); + nameplate1 = as_number("ui_batt_capacity"); } - if (add_om_num_types > 1) + if (add_om_num_types > 1) // PV Battery Fuel Cell { escal_or_annual(CF_om_fixed2_expense, nyears, "om_fixed2", inflation_rate, 1.0, false, as_double("om_fixed_escal")*0.01); escal_or_annual(CF_om_production2_expense, nyears, "om_production2", inflation_rate, 0.001, false, as_double("om_production_escal")*0.01); @@ -1072,7 +1088,7 @@ class cm_singleowner : public compute_module } double batt_cap = as_double("batt_computed_bank_capacity"); // updated 10/17/15 per 10/14/15 meeting - escal_or_annual(CF_battery_replacement_cost_schedule, nyears, "om_replacement_cost1", inflation_rate, batt_cap, false, as_double("om_replacement_cost_escal") * 0.01); + escal_or_annual(CF_battery_replacement_cost_schedule, nyears, "om_batt_replacement_cost", inflation_rate, batt_cap, false, as_double("om_replacement_cost_escal") * 0.01); for (i = 0; i < nyears && i < (int)count; i++) { // batt_rep and the cash flow sheets are 1 indexed, replacement_percent is zero indexed @@ -2961,6 +2977,33 @@ class cm_singleowner : public compute_module assign("npv_annual_costs", var_data((ssc_number_t)npv_annual_costs)); save_cf(CF_Annual_Costs, nyears, "cf_annual_costs"); + double lcos_investment_cost = as_double("battery_total_cost_lcos"); //does not include replacement costs + lcos_investment_cost += npv(cf.at(CF_battery_replacement_cost), nyears, nom_discount_rate); + double lcos_om_cost = npv(cf.at(CF_om_capacity1_expense), nyears, nom_discount_rate); //Todo: include variable om due to charging + std::vector charged_grid = as_vector_double("batt_annual_charge_from_grid"); + std::vector charged_pv = as_vector_double("batt_annual_charge_from_pv"); + std::vector lcos_energy_discharged = as_vector_double("battery_annual_energy_discharged"); + std::vector charged_total; + for (int a = 0; a < nyears; a++) { + charged_grid[a] *= ppa; + charged_pv[a] *= lcoe_nom; + charged_total[a] = charged_grid[a] + charged_pv[a]; + cf.at(CF_energy_charged_grid, a) = charged_total[a]; + cf.at(CF_om_production1_expense, a) *= charged_total[a]; + cf.at(CF_energy_discharged, a) = lcos_energy_discharged[a]; + } + lcos_om_cost += npv(CF_om_production1_expense, nyears, nom_discount_rate); + lcos_om_cost += npv(CF_om_fixed1_expense, nyears, nom_discount_rate); + double lcos_charging_cost = npv(CF_energy_charged_grid, nyears, nom_discount_rate); + double batt_salvage_value_frac = as_double("batt_salvage_percentage") * 0.01; + double lcos_salvage_value = lcos_investment_cost * batt_salvage_value_frac / pow(1 + nom_discount_rate, nyears + 1); //set as a percentage or direct salvage value + double lcos_denominator = npv(CF_energy_discharged, nyears, nom_discount_rate); + double lcos_denominator_real = npv(CF_energy_discharged, nyears, disc_real); + double lcos_numerator = (lcos_investment_cost + lcos_om_cost + lcos_charging_cost + lcos_salvage_value); + double lcos_nom = lcos_numerator / lcos_denominator; + double lcos_real = lcos_numerator / lcos_denominator_real; + assign("lcos_nom", lcos_nom); + assign("lcos_real", lcos_real); // DSCR calculations for (i = 0; i <= nyears; i++) diff --git a/ssc/common.cpp b/ssc/common.cpp index 1038a4227..54aac74e3 100644 --- a/ssc/common.cpp +++ b/ssc/common.cpp @@ -101,7 +101,7 @@ var_info vtab_oandm[] = { { SSC_INPUT, SSC_ARRAY, "annual_fuel_usage_lifetime", "Fuel usage (lifetime)", "kWht", "", "System Costs", "", "", "" }, // replacements -{ SSC_INPUT,SSC_ARRAY , "om_replacement_cost1" , "Replacement cost 1" , "$/kWh" , "" , "System Costs" , "?=0.0" , "" , ""}, +{ SSC_INPUT,SSC_ARRAY , "om_batt_replacement_cost" , "Replacement cost 1" , "$/kWh" , "" , "System Costs" , "?=0.0" , "" , ""}, { SSC_INPUT,SSC_ARRAY , "om_replacement_cost2" , "Replacement cost 2" , "$/kW" , "" , "System Costs" , "?=0.0" , "" , ""}, { SSC_INPUT,SSC_NUMBER , "om_replacement_cost_escal" , "Replacement cost escalation" , "%/year" , "" , "System Costs" , "?=0.0" , "" , ""}, @@ -115,12 +115,12 @@ var_info vtab_oandm[] = { // optional additional base o and m types { SSC_INPUT,SSC_NUMBER , "add_om_num_types" , "Number of O and M types" , "" , "" , "System Costs" , "?=0" , "INTEGER,MIN=0,MAX=2" , ""}, -{ SSC_INPUT,SSC_NUMBER , "om_capacity1_nameplate" , "Battery capacity for System Costs values" , "kW" , "" , "System Costs" , "?=0" , "" , ""}, +{ SSC_INPUT,SSC_NUMBER , "ui_batt_capacity" , "Battery capacity for System Costs values" , "kW" , "" , "System Costs" , "?=0" , "" , ""}, { SSC_INPUT,SSC_ARRAY , "om_production1_values" , "Battery production for System Costs values" , "kWh" , "" , "System Costs" , "?=0" , "" , ""}, -{ SSC_INPUT,SSC_ARRAY , "om_fixed1" , "Battery fixed System Costs annual amount" , "$/year" , "" , "System Costs" , "?=0.0" , "" , ""}, -{ SSC_INPUT,SSC_ARRAY , "om_production1" , "Battery production-based System Costs amount" , "$/MWh" , "" , "System Costs" , "?=0.0" , "" , ""}, -{ SSC_INPUT,SSC_ARRAY , "om_capacity1" , "Battery capacity-based System Costs amount" , "$/kWcap" , "" , "System Costs" , "?=0.0" , "" , ""}, +{ SSC_INPUT,SSC_ARRAY , "om_batt_fixed_cost" , "Battery fixed System Costs annual amount" , "$/year" , "" , "System Costs" , "?=0.0" , "" , ""}, +{ SSC_INPUT,SSC_ARRAY , "om_batt_variable_cost" , "Battery production-based System Costs amount" , "$/MWh" , "" , "System Costs" , "?=0.0" , "" , ""}, +{ SSC_INPUT,SSC_ARRAY , "om_batt_capacity_cost" , "Battery capacity-based System Costs amount" , "$/kWcap" , "" , "System Costs" , "?=0.0" , "" , ""}, { SSC_INPUT,SSC_NUMBER , "om_capacity2_nameplate" , "Fuel cell capacity for System Costs values" , "kW" , "" , "System Costs" , "?=0" , "" , ""}, { SSC_INPUT,SSC_ARRAY , "om_production2_values" , "Fuel cell production for System Costs values" , "kWh" , "" , "System Costs" , "?=0" , "" , ""}, From 62a2b155c35930bdf625979ae6e62b5c8cd2b6ef Mon Sep 17 00:00:00 2001 From: Prilliman Date: Thu, 28 Jan 2021 16:54:44 -0700 Subject: [PATCH 04/12] Revert "Added lcos calculations and variables to singleowner, updated variable" This reverts commit 4f99be27d9ece46de176c87ecec2bff97b72d019. --- ssc/cmod_singleowner.cpp | 65 +++++++--------------------------------- ssc/common.cpp | 10 +++---- 2 files changed, 16 insertions(+), 59 deletions(-) diff --git a/ssc/cmod_singleowner.cpp b/ssc/cmod_singleowner.cpp index 427fa1dc3..31ccb80d9 100644 --- a/ssc/cmod_singleowner.cpp +++ b/ssc/cmod_singleowner.cpp @@ -44,11 +44,6 @@ static var_info _cm_vtab_singleowner[] = { { SSC_INPUT, SSC_ARRAY, "gen", "Net power to or from the grid", "kW", "", "System Output", "*", "", "" }, { SSC_INPUT, SSC_ARRAY, "gen_without_battery", "Electricity to or from the renewable system, without the battery", "kW", "", "System Output", "", "", "" }, - { SSC_INPUT, SSC_ARRAY, "batt_annual_charge_from_system", "Battery annual energy charged from system", "kWh", "", "Battery", "en_batt=1", "", "" }, - { SSC_INPUT, SSC_ARRAY, "batt_annual_charge_from_grid", "Battery annual energy charged from grid", "kWh", "", "Battery", "en_batt=1", "", "" }, - { SSC_INPUT, SSC_ARRAY, "batt_annual_charge_energy", "Battery annual energy charged", "kWh", "", "Battery", "en_batt=1", "", "" }, - { SSC_INPUT, SSC_ARRAY, "batt_annual_discharge_energy", "Battery annual energy discharged", "kWh", "", "Battery", "en_batt=1", "", "" }, - { SSC_INPUT, SSC_NUMBER, "battery_total_cost_lcos", "Battery total investment cost", "$", "", "Battery", "en_batt=1", "", "" }, { SSC_INPUT, SSC_ARRAY, "degradation", "Annual energy degradation", "", "", "System Output", "*", "", "" }, @@ -213,8 +208,6 @@ static var_info _cm_vtab_singleowner[] = { /* salvage value */ { SSC_INPUT, SSC_NUMBER, "salvage_percentage", "Net pre-tax cash salvage value", "%", "", "Financial Parameters", "?=10", "MIN=0,MAX=100", "" }, - { SSC_INPUT, SSC_NUMBER, "batt_salvage_percentage", "Net pre-tax cash battery salvage value", "%", "", "Financial Parameters", "?=0", "MIN=0,MAX=100", "" }, - /* market specific inputs - leveraged partnership flip */ /* construction period */ @@ -563,9 +556,9 @@ static var_info _cm_vtab_singleowner[] = { { SSC_OUTPUT, SSC_ARRAY, "cf_om_production1_expense", "Battery production-based expense", "$", "", "Cash Flow Expenses", "*", "LENGTH_EQUAL=cf_length", "" }, { SSC_OUTPUT, SSC_ARRAY, "cf_om_capacity1_expense", "Battery capacity-based expense", "$", "", "Cash Flow Expenses", "*", "LENGTH_EQUAL=cf_length", "" }, - { SSC_OUTPUT, SSC_ARRAY, "cf_om_fixed2_expense", "Fuel cell fixed expense", "$", "", "Cash Flow Expenses", "", "LENGTH_EQUAL=cf_length", "" }, - { SSC_OUTPUT, SSC_ARRAY, "cf_om_production2_expense", "Fuel cell production-based expense", "$", "", "Cash Flow Expenses", "", "LENGTH_EQUAL=cf_length", "" }, - { SSC_OUTPUT, SSC_ARRAY, "cf_om_capacity2_expense", "Fuel cell capacity-based expense", "$", "", "Cash Flow Expenses", "", "LENGTH_EQUAL=cf_length", "" }, + { SSC_OUTPUT, SSC_ARRAY, "cf_om_fixed2_expense", "Fuel cell fixed expense", "$", "", "Cash Flow Expenses", "*", "LENGTH_EQUAL=cf_length", "" }, + { SSC_OUTPUT, SSC_ARRAY, "cf_om_production2_expense", "Fuel cell production-based expense", "$", "", "Cash Flow Expenses", "*", "LENGTH_EQUAL=cf_length", "" }, + { SSC_OUTPUT, SSC_ARRAY, "cf_om_capacity2_expense", "Fuel cell capacity-based expense", "$", "", "Cash Flow Expenses", "*", "LENGTH_EQUAL=cf_length", "" }, @@ -676,10 +669,6 @@ static var_info _cm_vtab_singleowner[] = { { SSC_OUTPUT, SSC_NUMBER, "npv_salvage_value", "Present value of salvage value", "$", "", "Metrics", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "npv_thermal_value", "Present value of thermal value", "$", "", "Metrics", "*", "", "" }, - //lcos - { SSC_OUTPUT, SSC_NUMBER, "lcos_nom", "Nominal levelized cost of storage", "$/kWh", "", "Metrics", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "lcos_real", "Real levelized cost of storage", "$/kWh", "", "Metrics", "*", "", "" }, - var_info_invalid }; @@ -894,12 +883,7 @@ enum { CF_energy_without_battery, - CF_max, - - CF_energy_charged_grid, - CF_energy_charged_pv, - CF_energy_discharged - }; + CF_max }; @@ -1052,14 +1036,14 @@ class cm_singleowner : public compute_module ssc_number_t nameplate1 = 0; ssc_number_t nameplate2 = 0; - if (add_om_num_types > 0) //PV Battery + if (add_om_num_types > 0) { - escal_or_annual(CF_om_fixed1_expense, nyears, "om_batt_fixed_cost", inflation_rate, 1.0, false, as_double("om_fixed_escal")*0.01); - escal_or_annual(CF_om_production1_expense, nyears, "om_batt_variable_cost", inflation_rate, 0.001, false, as_double("om_production_escal")*0.01); - escal_or_annual(CF_om_capacity1_expense, nyears, "om_batt_capacity_cost", inflation_rate, 1.0, false, as_double("om_capacity_escal")*0.01); - nameplate1 = as_number("ui_batt_capacity"); + escal_or_annual(CF_om_fixed1_expense, nyears, "om_fixed1", inflation_rate, 1.0, false, as_double("om_fixed_escal")*0.01); + escal_or_annual(CF_om_production1_expense, nyears, "om_production1", inflation_rate, 0.001, false, as_double("om_production_escal")*0.01); + escal_or_annual(CF_om_capacity1_expense, nyears, "om_capacity1", inflation_rate, 1.0, false, as_double("om_capacity_escal")*0.01); + nameplate1 = as_number("om_capacity1_nameplate"); } - if (add_om_num_types > 1) // PV Battery Fuel Cell + if (add_om_num_types > 1) { escal_or_annual(CF_om_fixed2_expense, nyears, "om_fixed2", inflation_rate, 1.0, false, as_double("om_fixed_escal")*0.01); escal_or_annual(CF_om_production2_expense, nyears, "om_production2", inflation_rate, 0.001, false, as_double("om_production_escal")*0.01); @@ -1088,7 +1072,7 @@ class cm_singleowner : public compute_module } double batt_cap = as_double("batt_computed_bank_capacity"); // updated 10/17/15 per 10/14/15 meeting - escal_or_annual(CF_battery_replacement_cost_schedule, nyears, "om_batt_replacement_cost", inflation_rate, batt_cap, false, as_double("om_replacement_cost_escal") * 0.01); + escal_or_annual(CF_battery_replacement_cost_schedule, nyears, "om_replacement_cost1", inflation_rate, batt_cap, false, as_double("om_replacement_cost_escal") * 0.01); for (i = 0; i < nyears && i < (int)count; i++) { // batt_rep and the cash flow sheets are 1 indexed, replacement_percent is zero indexed @@ -2977,33 +2961,6 @@ class cm_singleowner : public compute_module assign("npv_annual_costs", var_data((ssc_number_t)npv_annual_costs)); save_cf(CF_Annual_Costs, nyears, "cf_annual_costs"); - double lcos_investment_cost = as_double("battery_total_cost_lcos"); //does not include replacement costs - lcos_investment_cost += npv(cf.at(CF_battery_replacement_cost), nyears, nom_discount_rate); - double lcos_om_cost = npv(cf.at(CF_om_capacity1_expense), nyears, nom_discount_rate); //Todo: include variable om due to charging - std::vector charged_grid = as_vector_double("batt_annual_charge_from_grid"); - std::vector charged_pv = as_vector_double("batt_annual_charge_from_pv"); - std::vector lcos_energy_discharged = as_vector_double("battery_annual_energy_discharged"); - std::vector charged_total; - for (int a = 0; a < nyears; a++) { - charged_grid[a] *= ppa; - charged_pv[a] *= lcoe_nom; - charged_total[a] = charged_grid[a] + charged_pv[a]; - cf.at(CF_energy_charged_grid, a) = charged_total[a]; - cf.at(CF_om_production1_expense, a) *= charged_total[a]; - cf.at(CF_energy_discharged, a) = lcos_energy_discharged[a]; - } - lcos_om_cost += npv(CF_om_production1_expense, nyears, nom_discount_rate); - lcos_om_cost += npv(CF_om_fixed1_expense, nyears, nom_discount_rate); - double lcos_charging_cost = npv(CF_energy_charged_grid, nyears, nom_discount_rate); - double batt_salvage_value_frac = as_double("batt_salvage_percentage") * 0.01; - double lcos_salvage_value = lcos_investment_cost * batt_salvage_value_frac / pow(1 + nom_discount_rate, nyears + 1); //set as a percentage or direct salvage value - double lcos_denominator = npv(CF_energy_discharged, nyears, nom_discount_rate); - double lcos_denominator_real = npv(CF_energy_discharged, nyears, disc_real); - double lcos_numerator = (lcos_investment_cost + lcos_om_cost + lcos_charging_cost + lcos_salvage_value); - double lcos_nom = lcos_numerator / lcos_denominator; - double lcos_real = lcos_numerator / lcos_denominator_real; - assign("lcos_nom", lcos_nom); - assign("lcos_real", lcos_real); // DSCR calculations for (i = 0; i <= nyears; i++) diff --git a/ssc/common.cpp b/ssc/common.cpp index 54aac74e3..1038a4227 100644 --- a/ssc/common.cpp +++ b/ssc/common.cpp @@ -101,7 +101,7 @@ var_info vtab_oandm[] = { { SSC_INPUT, SSC_ARRAY, "annual_fuel_usage_lifetime", "Fuel usage (lifetime)", "kWht", "", "System Costs", "", "", "" }, // replacements -{ SSC_INPUT,SSC_ARRAY , "om_batt_replacement_cost" , "Replacement cost 1" , "$/kWh" , "" , "System Costs" , "?=0.0" , "" , ""}, +{ SSC_INPUT,SSC_ARRAY , "om_replacement_cost1" , "Replacement cost 1" , "$/kWh" , "" , "System Costs" , "?=0.0" , "" , ""}, { SSC_INPUT,SSC_ARRAY , "om_replacement_cost2" , "Replacement cost 2" , "$/kW" , "" , "System Costs" , "?=0.0" , "" , ""}, { SSC_INPUT,SSC_NUMBER , "om_replacement_cost_escal" , "Replacement cost escalation" , "%/year" , "" , "System Costs" , "?=0.0" , "" , ""}, @@ -115,12 +115,12 @@ var_info vtab_oandm[] = { // optional additional base o and m types { SSC_INPUT,SSC_NUMBER , "add_om_num_types" , "Number of O and M types" , "" , "" , "System Costs" , "?=0" , "INTEGER,MIN=0,MAX=2" , ""}, -{ SSC_INPUT,SSC_NUMBER , "ui_batt_capacity" , "Battery capacity for System Costs values" , "kW" , "" , "System Costs" , "?=0" , "" , ""}, +{ SSC_INPUT,SSC_NUMBER , "om_capacity1_nameplate" , "Battery capacity for System Costs values" , "kW" , "" , "System Costs" , "?=0" , "" , ""}, { SSC_INPUT,SSC_ARRAY , "om_production1_values" , "Battery production for System Costs values" , "kWh" , "" , "System Costs" , "?=0" , "" , ""}, -{ SSC_INPUT,SSC_ARRAY , "om_batt_fixed_cost" , "Battery fixed System Costs annual amount" , "$/year" , "" , "System Costs" , "?=0.0" , "" , ""}, -{ SSC_INPUT,SSC_ARRAY , "om_batt_variable_cost" , "Battery production-based System Costs amount" , "$/MWh" , "" , "System Costs" , "?=0.0" , "" , ""}, -{ SSC_INPUT,SSC_ARRAY , "om_batt_capacity_cost" , "Battery capacity-based System Costs amount" , "$/kWcap" , "" , "System Costs" , "?=0.0" , "" , ""}, +{ SSC_INPUT,SSC_ARRAY , "om_fixed1" , "Battery fixed System Costs annual amount" , "$/year" , "" , "System Costs" , "?=0.0" , "" , ""}, +{ SSC_INPUT,SSC_ARRAY , "om_production1" , "Battery production-based System Costs amount" , "$/MWh" , "" , "System Costs" , "?=0.0" , "" , ""}, +{ SSC_INPUT,SSC_ARRAY , "om_capacity1" , "Battery capacity-based System Costs amount" , "$/kWcap" , "" , "System Costs" , "?=0.0" , "" , ""}, { SSC_INPUT,SSC_NUMBER , "om_capacity2_nameplate" , "Fuel cell capacity for System Costs values" , "kW" , "" , "System Costs" , "?=0" , "" , ""}, { SSC_INPUT,SSC_ARRAY , "om_production2_values" , "Fuel cell production for System Costs values" , "kWh" , "" , "System Costs" , "?=0" , "" , ""}, From 5d8e0d1bf86a32dd134ab7a80001fbc8155ee0b6 Mon Sep 17 00:00:00 2001 From: janinefreeman Date: Fri, 29 Jan 2021 14:34:32 -0700 Subject: [PATCH 05/12] updated hour_of_year function to assign the same hours as feb 28 when feb 29 is present, and tested that this now gives results --- shared/lib_util.cpp | 10 ++++++--- test/ssc_test/cmod_pvsamv1_test.cpp | 34 +++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/shared/lib_util.cpp b/shared/lib_util.cpp index 8105ef8de..bf34187a8 100644 --- a/shared/lib_util.cpp +++ b/shared/lib_util.cpp @@ -902,15 +902,19 @@ size_t util::hour_of_year(size_t month, size_t day, size_t hour) size_t h = 0; bool ok = true; std::vector days_in_months = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + //first add the days from all the preceding completed months if (month >= 1 && month <= 12) { for (size_t m = 0; m < (month - 1); m++) h += days_in_months[m] * 24; } else ok = false; - if (day >= 1 && day <= days_in_months[month - 1]) - h += (day - 1) * 24; - else ok = false; + //then add days in the current month up to the current day + if (day >= 1 && day <= days_in_months[month - 1]) + h += (day - 1) * 24; + else if (month == 2 && day == 29) //special check for leap day present in data + h += (27 * 24); //for leap day, repeat Feb 28 in annual indexes, because hour_of_year is used to index 8760 non-leap-year arrays. + else ok = false; if (hour >= 0 && hour <= 23) h += hour; else ok = false; diff --git a/test/ssc_test/cmod_pvsamv1_test.cpp b/test/ssc_test/cmod_pvsamv1_test.cpp index 5df3ad6a6..bfaa330db 100644 --- a/test/ssc_test/cmod_pvsamv1_test.cpp +++ b/test/ssc_test/cmod_pvsamv1_test.cpp @@ -761,3 +761,37 @@ TEST_F(CMPvsamv1PowerIntegration_cmod_pvsamv1, NonAnnual) EXPECT_NEAR(gen, 3.0525, 0.01) << "Gen at noon"; free_weatherdata_array(weather_data); } + +//test non-annual run that includes Feb 29 +TEST_F(CMPvsamv1PowerIntegration_cmod_pvsamv1, NonAnnualWithLeapDay) +{ + //set up a weather data array containing leap day and assign it to the solar resource data + const int length = 24; + double month[length] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; + double day[length] = { 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; + + var_data month_vd = var_data(month, length); + var_data day_vd = var_data(day, length); + + auto weather_data = create_weatherdata_array(length); + weather_data->table.assign("month", month_vd); + weather_data->table.assign("day", day_vd); + + ssc_data_unassign(data, "solar_resource_file"); + ssc_data_set_table(data, "solar_resource_data", &weather_data->table); + + std::vector load(length, 1); + ssc_data_set_array(data, "load", &load[0], (int)load.size()); + + //run the tests + EXPECT_FALSE(run_module(data, "pvsamv1")); + + ssc_number_t dc_net, gen; + dc_net = ssc_data_get_array(data, "dc_net", nullptr)[12]; + EXPECT_NEAR(dc_net, 2.7319, 0.01) << "DC Net Energy at noon"; + + gen = ssc_data_get_array(data, "gen", nullptr)[12]; + EXPECT_NEAR(gen, 2.6189, 0.01) << "Gen at noon"; + free_weatherdata_array(weather_data); +} + From ef23ee9cc50d89ec317e3b8982582e22f89efc42 Mon Sep 17 00:00:00 2001 From: tyneises Date: Thu, 4 Feb 2021 15:00:53 -0600 Subject: [PATCH 06/12] merge rec outlet to cold tank changes from daotk --- tcs/csp_solver_core.cpp | 752 +++++++++++++++++++++++++---- tcs/csp_solver_core.h | 115 ++++- tcs/csp_solver_mono_eq_methods.cpp | 30 +- tcs/csp_solver_two_tank_tes.cpp | 363 +++++++++----- tcs/csp_solver_two_tank_tes.h | 24 +- 5 files changed, 1025 insertions(+), 259 deletions(-) diff --git a/tcs/csp_solver_core.cpp b/tcs/csp_solver_core.cpp index 18db41fcf..267ae4981 100644 --- a/tcs/csp_solver_core.cpp +++ b/tcs/csp_solver_core.cpp @@ -87,7 +87,21 @@ std::string C_csp_solver::tech_operating_modes_str[] = "CR_DF__PC_SU__TES_FULL__AUX_OFF", - "CR_DF__PC_SU__TES_OFF__AUX_OFF" + "CR_DF__PC_SU__TES_OFF__AUX_OFF", + + "CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF", + + "CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF", + + "CR_TO_COLD__PC_SB__TES_DC__AUX_OFF", + + "CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF", + + "CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF", + + "SKIP_40", + + "CR_TO_COLD__PC_SU__TES_DC__AUX_OFF" }; void C_timestep_fixed::init(double time_start /*s*/, double step /*s*/) @@ -206,8 +220,10 @@ static C_csp_reported_outputs::S_output_info S_solver_output_info[] = {C_csp_solver::C_solver_outputs::PRICING_MULT, C_csp_reported_outputs::TS_1ST}, //[-] PPA price multiplier {C_csp_solver::C_solver_outputs::PC_Q_DOT_SB, C_csp_reported_outputs::TS_1ST}, //[MWt] PC required standby thermal power {C_csp_solver::C_solver_outputs::PC_Q_DOT_MIN, C_csp_reported_outputs::TS_1ST}, //[MWt] PC required min thermal power - {C_csp_solver::C_solver_outputs::PC_Q_DOT_TARGET, C_csp_reported_outputs::TS_1ST}, //[MWt] PC target thermal power - {C_csp_solver::C_solver_outputs::PC_Q_DOT_MAX, C_csp_reported_outputs::TS_1ST}, //[MWt] PC allowable max thermal power + {C_csp_solver::C_solver_outputs::PC_Q_DOT_TARGET, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[MWt] PC target thermal power + {C_csp_solver::C_solver_outputs::PC_Q_DOT_MAX, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[MWt] PC allowable max thermal power + {C_csp_solver::C_solver_outputs::PC_Q_DOT_TARGET_SU, C_csp_reported_outputs::TS_MAX}, //[MWt] PC target thermal power for startup + {C_csp_solver::C_solver_outputs::PC_Q_DOT_TARGET_ON, C_csp_reported_outputs::TS_MAX}, //[MWt] PC target thermal power for startup {C_csp_solver::C_solver_outputs::CTRL_IS_REC_SU, C_csp_reported_outputs::TS_1ST}, //[-] Control decision: is receiver startup allowed? {C_csp_solver::C_solver_outputs::CTRL_IS_PC_SU, C_csp_reported_outputs::TS_1ST}, //[-] Control decision: is power cycle startup allowed? {C_csp_solver::C_solver_outputs::CTRL_IS_PC_SB, C_csp_reported_outputs::TS_1ST}, //[-] Control decision: is power cycle standby allowed? @@ -254,11 +270,14 @@ static C_csp_reported_outputs::S_output_info S_solver_output_info[] = {C_csp_solver::C_solver_outputs::TES_Q_DOT_DC, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[MWt] TES discharge thermal power {C_csp_solver::C_solver_outputs::TES_Q_DOT_CH, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[MWt] TES charge thermal power {C_csp_solver::C_solver_outputs::TES_E_CH_STATE, C_csp_reported_outputs::TS_LAST}, //[MWht] TES charge state at the end of the time step - + {C_csp_solver::C_solver_outputs::TES_T_COLD_IN, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[MWt] Inlet temperature to cold TES + {C_csp_solver::C_solver_outputs::M_DOT_CR_TO_TES_HOT, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] + {C_csp_solver::C_solver_outputs::M_DOT_CR_TO_TES_COLD, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] {C_csp_solver::C_solver_outputs::M_DOT_TES_HOT_OUT, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] {C_csp_solver::C_solver_outputs::M_DOT_PC_TO_TES_COLD, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] {C_csp_solver::C_solver_outputs::M_DOT_TES_COLD_OUT, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] + {C_csp_solver::C_solver_outputs::M_DOT_TES_COLD_IN, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] {C_csp_solver::C_solver_outputs::M_DOT_FIELD_TO_CYCLE, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] {C_csp_solver::C_solver_outputs::M_DOT_CYCLE_TO_FIELD, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] @@ -403,6 +422,13 @@ void C_csp_solver::reset_hierarchy_logic() m_is_CR_DF__PC_SU__TES_FULL__AUX_OFF_avail = true; m_is_CR_DF__PC_SU__TES_OFF__AUX_OFF_avail = true; + + m_is_CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF_avail = true; + m_is_CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF_avail = true; + m_is_CR_TO_COLD__PC_SB__TES_DC__AUX_OFF_avail = true; + m_is_CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF_avail = true; + m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail = true; + m_is_CR_TO_COLD__PC_SU__TES_DC__AUX_OFF_avail = true; } void C_csp_solver::turn_off_plant() @@ -455,6 +481,13 @@ void C_csp_solver::turn_off_plant() m_is_CR_DF__PC_SU__TES_FULL__AUX_OFF_avail = false; m_is_CR_DF__PC_SU__TES_OFF__AUX_OFF_avail = false; + + m_is_CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF_avail = false; + m_is_CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF_avail = false; + m_is_CR_TO_COLD__PC_SB__TES_DC__AUX_OFF_avail = false; + m_is_CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF_avail = false; + m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail = false; + m_is_CR_TO_COLD__PC_SU__TES_DC__AUX_OFF_avail = false; } double C_csp_solver::get_cr_aperture_area() @@ -513,8 +546,21 @@ void C_csp_solver::init() mc_tou.init_parent(); // Thermal Storage m_is_tes = mc_tes.does_tes_exist(); - - + bool m_does_tes_enable_cr_to_cold_tank = mc_tes.is_cr_to_cold_allowed(); + + // System control logic + m_is_rec_to_coldtank_allowed = ms_system_params.m_is_rec_to_coldtank_allowed; + m_T_htf_hot_tank_in_min = (ms_system_params.f_htf_hot_des__T_htf_hot_tank_in_min * cr_solved_params.m_T_htf_cold_des + + (1.0 - ms_system_params.f_htf_hot_des__T_htf_hot_tank_in_min) * cr_solved_params.m_T_htf_hot_des) - 273.15; //[C] convert from K + //m_T_htf_hot_tank_in_min = (0.5 * cr_solved_params.m_T_htf_cold_des + 0.5 * cr_solved_params.m_T_htf_hot_des) - 273.15; //[C] convert from K + + // Can't send HTF outlet to cold tank if no cold tank + // or if TES class isn't configured to do so (parallel tanks in two-tank tes can't at the moment) + // or if hot tank in min is nan or "too hot" + m_is_rec_to_coldtank_allowed = m_is_rec_to_coldtank_allowed && m_is_tes && + m_does_tes_enable_cr_to_cold_tank && + std::isfinite(m_T_htf_hot_tank_in_min) && + m_T_htf_hot_tank_in_min < (m_cycle_T_htf_hot_des); m_is_cr_config_recirc = true; @@ -701,6 +747,17 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double progress_msg_frac_current = progress_msg_interval_frac; double V_hot_tank_frac_initial; + + double pc_state_persist = 0.; // Time [hr] that current pc operating state (on/off/standby) has persisted + double rec_state_persist = 0.; // Time [hr] that current receiver operating state (on/off/standby) has persisted + int prev_pc_state = mc_power_cycle.get_operating_state(); + int prev_rec_state = mc_collector_receiver.get_operating_state(); + + double q_pb_last = 0.0; // Cycle thermal input at end of last time step [kWt] + double w_pb_last = 0.0; // Cycle gross generation at end of last time step [kWt] + double f_op_last = 0.0; // Fraction of last time step that cycle was operating or in standby + + /* ************************** MAIN TIME-SERIES LOOP ************************** */ @@ -737,10 +794,8 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) mc_csp_messages.add_message(C_csp_messages::WARNING, util::format("End time: %f", end_time) ); int operating_mode = ENTRY_MODE; - std::string operating_mode_str = tech_operating_modes_str[operating_mode]; - std::string operating_mode_str_prev = ""; + std::string op_mode_str = ""; - std::string op_mode_str_prev = ""; while( mc_kernel.mc_sim_info.ms_ts.m_time <= mc_kernel.get_sim_setup()->m_sim_time_end ) { @@ -771,13 +826,16 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) pc_operating_state = mc_power_cycle.get_operating_state(); if (m_is_first_timestep && f_turbine_tou <= 0.) pc_operating_state = C_csp_power_cycle::OFF; + double q_pb_last = mc_pc_out_solver.m_q_dot_htf * 1000.; //[kWt] + double w_pb_last = mc_pc_out_solver.m_P_cycle * 1000.; //[kWt] + // Calculate maximum thermal power to power cycle for startup. This will be zero if power cycle is on. double q_dot_pc_su_max = mc_power_cycle.get_max_q_pc_startup(); //[MWt] // Get weather at this timestep. Should only be called once per timestep. (Except converged() function) mc_weather.timestep_call(mc_kernel.mc_sim_info); - // Get volume of hot hot tank, for debugging + // Get volume of hot tank, for debugging V_hot_tank_frac_initial = mc_tes.get_hot_tank_vol_frac(); // Get or set decision variables @@ -829,7 +887,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) mc_pc_out_solver, mc_kernel.mc_sim_info); - + bool is_rec_outlet_to_hottank = true; m_T_htf_pc_cold_est = mc_pc_out_solver.m_T_htf_cold; //[C] // Solve collector/receiver at steady state with design inputs and weather to estimate output mc_cr_htf_state_in.m_temp = m_T_htf_pc_cold_est; //[C] @@ -845,6 +903,13 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) if (cr_operating_state != C_csp_collector_receiver::ON) T_htf_hot_cr_on = m_cycle_T_htf_hot_des - 273.15; //[C] + // Is receiver on and will it likely remain on + if (cr_operating_state == C_csp_collector_receiver::ON && m_dot_cr_on > 0.0 + && m_is_rec_to_coldtank_allowed + && T_htf_hot_cr_on < m_T_htf_hot_tank_in_min) { + is_rec_outlet_to_hottank = false; + } + // Get TES operating state info at end of last time step double q_dot_tes_dc, q_dot_tes_ch; //[MWt] q_dot_tes_dc = q_dot_tes_ch = std::numeric_limits::quiet_NaN(); @@ -1131,6 +1196,17 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } + // Split up reported q_dot_pc target into 'startup' and 'on' so input dispatch can specify both for a single full timestep + double q_dot_pc_su_target_reporting = 0.0; + double q_dot_pc_on_target_reporting = 0.0; + if (pc_operating_state == C_csp_power_cycle::OFF || pc_operating_state == C_csp_power_cycle::STARTUP) { + q_dot_pc_su_target_reporting = q_pc_target; + } + else { + q_dot_pc_on_target_reporting = q_pc_target; + } + + /* ------------ Controller/Solver iteration loop ------------- */ @@ -1189,16 +1265,23 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } - // Check if receiver can be defocused enough to stay under cycle+TES max thermal power and mass flow (this will usually be the case unless using clear-sky control or constrained cycle thermal input) - if (cr_operating_state == C_csp_collector_receiver::ON && q_dot_cr_on>0.0 && is_rec_su_allowed && m_is_tes) + // Check if receiver can be defocused enough to stay under cycle+TES max thermal power and mass flow (if cold recirculation is not enabled) + // (this will usually be the case unless using clear-sky control or constrained cycle thermal input) + if (cr_operating_state == C_csp_collector_receiver::ON && (q_dot_cr_on >0.0 || m_dot_cr_on > 0.0) && is_rec_su_allowed && is_rec_outlet_to_hottank && m_is_tes) { double qpcmax = m_q_dot_pc_max; if (pc_operating_state == C_csp_power_cycle::OFF || C_csp_power_cycle::STARTUP) qpcmax = q_dot_pc_su_max; - double qmax = (m_q_dot_pc_max + q_dot_tes_ch) / (1.0 - tol_mode_switching); - double mmax = (m_m_dot_pc_max + m_dot_tes_ch_est) / (1.0 - tol_mode_switching); - if (q_dot_cr_on > qmax || m_dot_cr_on > mmax) + double qmax = q_dot_tes_ch / (1.0 - tol_mode_switching); + double mmax = m_dot_tes_ch_est / (1.0 - tol_mode_switching); + if (is_pc_su_allowed) + { + qmax += m_q_dot_pc_max / (1.0 - tol_mode_switching); + mmax += m_m_dot_pc_max / (1.0 - tol_mode_switching); + } + + if (q_dot_cr_on > qmax || m_dot_cr_on > mmax) // Receiver will need to be defocused { double df = fmin(qmax / q_dot_cr_on, mmax / m_dot_cr_on); mc_collector_receiver.on(mc_weather.ms_outputs, mc_cr_htf_state_in, df, mc_cr_out_solver, mc_kernel.mc_sim_info); @@ -1250,7 +1333,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) else if( cr_operating_state == C_csp_collector_receiver::ON && (pc_operating_state == C_csp_power_cycle::OFF || pc_operating_state == C_csp_power_cycle::STARTUP) ) { - if( q_dot_cr_on > 0.0 && is_rec_su_allowed ) + if( q_dot_cr_on > 0.0 && is_rec_su_allowed && is_rec_outlet_to_hottank ) { // Receiver is allowed to remain on, and it can produce useful energy. Now, need to find a home for it if( is_pc_su_allowed && @@ -1310,10 +1393,31 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) operating_mode = CR_OFF__PC_OFF__TES_OFF__AUX_OFF; } } - else if( q_dot_tes_dc > 0.0 && is_pc_su_allowed && - m_is_CR_OFF__PC_SU__TES_DC__AUX_OFF_avail ) + else + { + if ((q_dot_cr_on >0.0 || m_dot_cr_on>0.0) && is_rec_su_allowed) + { + if (q_dot_tes_dc > 0.0 && is_pc_su_allowed && + m_is_CR_TO_COLD__PC_SU__TES_DC__AUX_OFF_avail) { // Can power cycle startup using TES? + operating_mode = CR_TO_COLD__PC_SU__TES_DC__AUX_OFF; + } + else if(m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail) + { + operating_mode = CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF; + } + else + { + operating_mode = CR_OFF__PC_OFF__TES_OFF__AUX_OFF; + } + } + else + { + if (q_dot_tes_dc > 0.0 && is_pc_su_allowed && + m_is_CR_OFF__PC_SU__TES_DC__AUX_OFF_avail) + { // Can power cycle startup using TES? + operating_mode = CR_OFF__PC_SU__TES_DC__AUX_OFF; } else @@ -1321,6 +1425,8 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) operating_mode = CR_OFF__PC_OFF__TES_OFF__AUX_OFF; } } + } + } else if( (cr_operating_state == C_csp_collector_receiver::OFF || cr_operating_state == C_csp_collector_receiver::STARTUP) && (pc_operating_state == C_csp_power_cycle::ON || pc_operating_state == C_csp_power_cycle::STANDBY) ) @@ -1433,7 +1539,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) else if( cr_operating_state == C_csp_collector_receiver::ON && (pc_operating_state == C_csp_power_cycle::ON || pc_operating_state == C_csp_power_cycle::STANDBY) ) { - if( q_dot_cr_on > 0.0 && is_rec_su_allowed ) + if( q_dot_cr_on > 0.0 && is_rec_su_allowed && is_rec_outlet_to_hottank ) { // Receiver operation is allowed and possible - find a home for output if( is_pc_su_allowed || is_pc_sb_allowed ) @@ -1685,6 +1791,79 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } // End logic else 'pc su is NOT allowed' } // End logic if(q_dot_cr_output > 0.0 && is_rec_su_allowed) + // 'else if' loop for receiver 'on' but sending htf to cold tank + else if ((q_dot_cr_on > 0.0 || m_dot_cr_on > 0.0)&& is_rec_su_allowed) { + + if (is_pc_su_allowed || is_pc_sb_allowed) + { + if (q_dot_tes_dc > 0.0) + { // Storage dispatch is available + + if (((q_dot_tes_dc * (1.0 + tol_mode_switching) > q_pc_target + && m_dot_tes_dc_est * (1.0 + tol_mode_switching) > m_m_dot_pc_min) + || m_dot_tes_dc_est * (1.0 + tol_mode_switching) > m_m_dot_pc_max) + && is_pc_su_allowed && + m_is_CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF_avail) + { // Storage can provide enough dispatch to reach power cycle target + // Tolerance is applied so that if TES is *close* to reaching PC target, the controller tries that mode + + operating_mode = CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF; + } + else if (q_dot_tes_dc * (1.0 + tol_mode_switching) > q_pc_min + && m_dot_tes_dc_est * (1.0 + tol_mode_switching) > m_m_dot_pc_min + && is_pc_su_allowed && + m_is_CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF_avail) + { // Storage can provide enough dispatch to at least meet power cycle minimum operation fraction + // Run at highest possible PC fraction by dispatching all remaining storage + // Tolerance is applied so that if CR + TES is *close* to reaching PC min, the controller tries that mode + + operating_mode = CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF; + } + else if (q_dot_tes_dc * (1.0 + tol_mode_switching) > q_pc_sb + && m_dot_tes_dc_est * (1.0 + tol_mode_switching) > m_m_dot_pc_min + && is_pc_sb_allowed && + m_is_CR_TO_COLD__PC_SB__TES_DC__AUX_OFF_avail) + { // Tolerance is applied so that if CR + TES is *close* to reaching standby, the controller tries that mode + + operating_mode = CR_TO_COLD__PC_SB__TES_DC__AUX_OFF; + } + else if (is_pc_su_allowed && + m_is_CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF_avail) + { // If not enough thermal power to stay in standby, then run at min PC load until TES is fully discharged + + operating_mode = CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF; + } + else if (m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail) + { + operating_mode = CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF; + } + else + { + operating_mode = CR_OFF__PC_OFF__TES_OFF__AUX_OFF; + } + } // End logic for if( q_dot_tes_dc > 0.0 ) + else if(m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail) + { // Storage dispatch is not available + + // No thermal power available to power cycle + operating_mode = CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF; + } + else + { + operating_mode = CR_OFF__PC_OFF__TES_OFF__AUX_OFF; + } + } // End logic if( is_pc_su_allowed ) + else if (m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail) + { // If neither receiver nor power cycle operation is allowed, then shut everything off + + operating_mode = CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF; + } + else + { + operating_mode = CR_OFF__PC_OFF__TES_OFF__AUX_OFF; + } + + } else // Receiver is off - determine if power cycle can remain on { if( is_pc_su_allowed || is_pc_sb_allowed ) @@ -1751,7 +1930,6 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) // Store operating mode m_op_mode_tracking.push_back(operating_mode); - operating_mode_str = tech_operating_modes_str[operating_mode]; op_mode_str = ""; @@ -1777,7 +1955,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -1819,7 +1997,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -1850,7 +2028,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -1899,7 +2077,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -1957,7 +2135,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2055,7 +2233,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_target, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_target, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2103,7 +2281,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2116,6 +2294,31 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } break; + case CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF: + { + int cr_mode = C_csp_collector_receiver::E_csp_cr_modes::ON; + C_csp_power_cycle::E_csp_power_cycle_modes pc_mode = C_csp_power_cycle::OFF; + C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode = C_MEQ__m_dot_tes::E__CR_OUT__0; + C_MEQ__timestep::E_timestep_target_modes step_target_mode = C_MEQ__timestep::E_STEP_FIXED; + bool is_defocus = false; + op_mode_str = "CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF"; + double defocus_solved = std::numeric_limits::quiet_NaN(); + + int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, + std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + + if (mode_code != 0) + { + throw(C_csp_exception(util::format("At time = %lg, CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF failed", mc_kernel.mc_sim_info.ms_ts.m_time), "")); + } + + // Set member defocus + m_defocus = defocus_solved; + + are_models_converged = true; + } + break; + case CR_OFF__PC_OFF__TES_OFF__AUX_OFF: { int cr_mode = C_csp_collector_receiver::E_csp_cr_modes::OFF; @@ -2127,7 +2330,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2141,6 +2344,46 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } break; // exit switch() after CR_OFF__PC_OFF__TES_OFF__AUX_OFF: + case CR_TO_COLD__PC_SU__TES_DC__AUX_OFF: + { + // Use thermal storage to startup power cycle + // This solver iterates to find the thermal storage outlet temperature to the power cycle + // and the power cycle demand mass flow rate that reach system equilibrium + + double t_ts_initial = mc_kernel.mc_sim_info.ms_ts.m_step; //[s] + + if (!mc_collector_receiver.m_is_sensible_htf) + { + std::string err_msg = util::format("Operating mode, %d, is not configured for DSG mode", operating_mode); + throw(C_csp_exception(err_msg, "CSP Solver")); + } + + int cr_mode = C_csp_collector_receiver::ON; + C_csp_power_cycle::E_csp_power_cycle_modes pc_mode = C_csp_power_cycle::STARTUP_CONTROLLED; + + C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode = C_MEQ__m_dot_tes::E__CR_OUT__ITER_M_DOT_SU_DC_ONLY; + C_MEQ__timestep::E_timestep_target_modes step_target_mode = C_MEQ__timestep::E_STEP_FROM_COMPONENT; + bool is_defocus = false; + op_mode_str = "CR_TO_COLD__PC_SU__TES_DC__AUX_OFF"; + double defocus_solved = std::numeric_limits::quiet_NaN(); + + int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, + std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + + if (mode_code != 0) + { + m_is_CR_TO_COLD__PC_SU__TES_DC__AUX_OFF_avail = false; + are_models_converged = false; + break; + } + + // Set member defocus + m_defocus = defocus_solved; + + are_models_converged = true; + } + break; + case CR_OFF__PC_SU__TES_DC__AUX_OFF: { // Use thermal storage to startup power cycle @@ -2164,7 +2407,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2200,7 +2443,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2238,7 +2481,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2309,7 +2552,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2372,7 +2615,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2437,9 +2680,9 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) m_defocus = defocus_solved; are_models_converged = true; - } // end outer bracket for case CR_ON__PC_OFF__TES_CH__AUX_OFF + } // end outer bracket for case CR_ON__PC_TARGET__TES_DC__AUX_OFF - break; // break case CR_ON__PC_OFF__TES_CH__AUX_OFF + break; // break case CR_ON__PC_TARGET__TES_DC__AUX_OFF case CR_ON__PC_RM_LO__TES_EMPTY__AUX_OFF: { @@ -2464,7 +2707,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2568,7 +2811,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2584,6 +2827,78 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } break; // break case CR_DF__PC_OFF__TES_FULL__AUX_OFF + case CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF: + { + //The collector receiver is off + //The power cycle runs at its minimum operating fraction until storage is depleted + //A new, shorter timestep is calculated here + + if (!mc_collector_receiver.m_is_sensible_htf) + { + std::string err_msg = util::format("Operating mode, %d, is not configured for DSG mode", operating_mode); + throw(C_csp_exception(err_msg, "CSP Solver")); + } + + double t_ts_initial = mc_kernel.mc_sim_info.ms_ts.m_step; //[s] + + int cr_mode = C_csp_collector_receiver::ON; + C_csp_power_cycle::E_csp_power_cycle_modes pc_mode = C_csp_power_cycle::ON; + C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode = C_MEQ__m_dot_tes::E__CR_OUT__CR_OUT_PLUS_TES_EMPTY; + C_MEQ__timestep::E_timestep_target_modes step_target_mode = C_MEQ__timestep::E_STEP_Q_DOT_PC; + bool is_defocus = false; + double q_dot_pc_target = q_pc_min; //[MWt] + op_mode_str = "CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF"; + double defocus_solved = std::numeric_limits::quiet_NaN(); + + int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, + q_dot_pc_target, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + + if (mode_code != 0) + { + m_is_CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF_avail = false; + are_models_converged = false; + break; + } + + // Check if solved thermal power is greater than target + if (mc_pc_out_solver.m_q_dot_htf > q_pc_target) + { + if (mc_pc_out_solver.m_q_dot_htf > m_q_dot_pc_max) + { + error_msg = util::format("At time = %lg CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" + " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", + mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, m_q_dot_pc_max); + + mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); + + turn_off_plant(); + reset_time(t_ts_initial); + are_models_converged = false; + break; + } + } + + if (mc_pc_out_solver.m_m_dot_htf > m_m_dot_pc_max) + { + error_msg = util::format("At time = %lg CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF converged to a HTF mass flow rate %lg [kg/s]" + " larger than the maximum PC mass flow rate %lg [kg/s]. Controller shut off plant", + mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_m_dot_htf / 3600.0, m_m_dot_pc_max / 3600.0); + + mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); + + turn_off_plant(); + reset_time(t_ts_initial); + are_models_converged = false; + break; + } + + // Set member defocus + m_defocus = defocus_solved; + + are_models_converged = true; + } + break; + case CR_OFF__PC_MIN__TES_EMPTY__AUX_OFF: { //The collector receiver is off @@ -2608,7 +2923,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_target, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_target, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2622,7 +2937,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) { if (mc_pc_out_solver.m_q_dot_htf > m_q_dot_pc_max) { - error_msg = util::format("At time = %lg CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" + error_msg = util::format("At time = %lg CR_OFF__PC_MIN__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, m_q_dot_pc_max); @@ -2637,7 +2952,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) if (mc_pc_out_solver.m_m_dot_htf > m_m_dot_pc_max) { - error_msg = util::format("At time = %lg CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a HTF mass flow rate %lg [kg/s]" + error_msg = util::format("At time = %lg CR_OFF__PC_MIN__TES_EMPTY__AUX_OFF converged to a HTF mass flow rate %lg [kg/s]" " larger than the maximum PC mass flow rate %lg [kg/s]. Controller shut off plant", mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_m_dot_htf / 3600.0, m_m_dot_pc_max / 3600.0); @@ -2656,6 +2971,85 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } break; // break case CR_OFF__PC_MIN__TES_EMPTY__AUX_OFF + case CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF: + { + // The collector-receiver is off + // The power cycle runs somewhere between its minimum operating fraction and target operation, with thermal input from TES, which is depleted at the end of the timestep + + if (!mc_collector_receiver.m_is_sensible_htf) + { + std::string err_msg = util::format("Operating mode, %d, is not configured for DSG mode", operating_mode); + throw(C_csp_exception(err_msg, "CSP Solver")); + } + + int cr_mode = C_csp_collector_receiver::ON; + C_csp_power_cycle::E_csp_power_cycle_modes pc_mode = C_csp_power_cycle::ON; + C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode = C_MEQ__m_dot_tes::E__CR_OUT__CR_OUT_PLUS_TES_EMPTY; + C_MEQ__timestep::E_timestep_target_modes step_target_mode = C_MEQ__timestep::E_STEP_FIXED; + bool is_defocus = false; + op_mode_str = "CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF"; + double defocus_solved = std::numeric_limits::quiet_NaN(); + + int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, + std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + + if (mode_code != 0) + { + m_is_CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF_avail = false; + are_models_converged = false; + break; + } + + if (mc_pc_out_solver.m_q_dot_htf < q_pc_min || mc_pc_out_solver.m_m_dot_htf < m_m_dot_pc_min) + { + m_is_CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF_avail = false; + are_models_converged = false; + break; + } + + // Check if solved thermal power is greater than target + if (mc_pc_out_solver.m_q_dot_htf > q_pc_target) + { + if (mc_pc_out_solver.m_q_dot_htf > m_q_dot_pc_max) + { + error_msg = util::format("At time = %lg CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" + " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", + mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, m_q_dot_pc_max); + + mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); + + turn_off_plant(); + are_models_converged = false; + break; + } + else + { + error_msg = util::format("At time = %lg CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" + " larger than the target PC thermal power %lg [MWt] but less than the maximum thermal power %lg [MWt]", + mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, q_pc_target, m_q_dot_pc_max); + mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); + } + } + + if (mc_pc_out_solver.m_m_dot_htf > m_m_dot_pc_max) + { + error_msg = util::format("At time = %lg CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a HTF mass flow rate %lg [kg/s]" + " larger than the maximum PC mass flow rate %lg [kg/s]. Controller shut off plant", + mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_m_dot_htf / 3600.0, m_m_dot_pc_max / 3600.0); + + mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); + + turn_off_plant(); + are_models_converged = false; + break; + } + + // Set member defocus + m_defocus = defocus_solved; + + are_models_converged = true; + } + break; case CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF: { @@ -2677,7 +3071,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2760,7 +3154,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_target, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_target, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2783,18 +3177,9 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) { if (mc_pc_out_solver.m_q_dot_htf > m_q_dot_pc_max) { - if (operating_mode == CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF) - { - error_msg = util::format("At time = %lg CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" - " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", - mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, m_q_dot_pc_max); - } - else if (operating_mode == CR_SU__PC_RM_LO__TES_EMPTY__AUX_OFF) - { error_msg = util::format("At time = %lg CR_SU__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, m_q_dot_pc_max); - } mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); @@ -2805,36 +3190,19 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } else { - if (operating_mode == CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF) - { - error_msg = util::format("At time = %lg CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" - " larger than the target PC thermal power %lg [MWt] but less than the maximum thermal power %lg [MWt]", - mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, q_pc_target, m_q_dot_pc_max); - } - else if (operating_mode == CR_SU__PC_RM_LO__TES_EMPTY__AUX_OFF) - { error_msg = util::format("At time = %lg CR_SU__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" " larger than the target PC thermal power %lg [MWt] but less than the maximum thermal power %lg [MWt]", mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, q_pc_target, m_q_dot_pc_max); - } + mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); } } if (mc_pc_out_solver.m_m_dot_htf > m_m_dot_pc_max) { - if (operating_mode == CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF) - { - error_msg = util::format("At time = %lg CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a HTF mass flow rate %lg [kg/s]" - " larger than the maximum PC mass flow rate %lg [kg/s]. Controller shut off plant", - mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_m_dot_htf/3600.0, m_m_dot_pc_max/3600.0); - } - else if (operating_mode == CR_SU__PC_RM_LO__TES_EMPTY__AUX_OFF) - { error_msg = util::format("At time = %lg CR_SU__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a HTF mass flow rate %lg [kg/s]" " larger than the maximum PC mass flow rate %lg [kg/s]. Controller shut off plant", mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_m_dot_htf/3600.0, m_m_dot_pc_max/3600.0); - } mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); @@ -2877,7 +3245,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_target, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_target, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2977,7 +3345,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3048,6 +3416,83 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) break; + case CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF: + { + if (!mc_collector_receiver.m_is_sensible_htf) + { + std::string err_msg = util::format("Operating mode, %d, is not configured for DSG mode", operating_mode); + throw(C_csp_exception(err_msg, "CSP Solver")); + } + + int cr_mode = C_csp_collector_receiver::ON; + C_csp_power_cycle::E_csp_power_cycle_modes pc_mode = C_csp_power_cycle::ON; + + C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode = C_MEQ__m_dot_tes::E__CR_OUT__ITER_Q_DOT_TARGET_DC_ONLY; + C_MEQ__timestep::E_timestep_target_modes step_target_mode = C_MEQ__timestep::E_STEP_FIXED; + bool is_defocus = false; + + double q_dot_pc_fixed = q_pc_target; //[MWt] + op_mode_str = "CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF"; + double defocus_solved = std::numeric_limits::quiet_NaN(); + + int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + + if (mode_code != 0) + { + m_is_CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF_avail = false; + are_models_converged = false; + break; + } + + double q_dot_pc_solved = mc_pc_out_solver.m_q_dot_htf; //[MWt] + double m_dot_pc_solved = mc_pc_out_solver.m_m_dot_htf; //[kg/hr] + + // Check if solved thermal power is greater than target + if ((q_dot_pc_solved - q_dot_pc_fixed) / q_dot_pc_fixed > 1.E-3) + { + if ((q_dot_pc_solved - m_q_dot_pc_max) / m_q_dot_pc_max > 1.E-3) + { + error_msg = util::format("At time = %lg %s converged to a PC thermal power %lg [MWt]" + " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", + mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, op_mode_str.c_str(), q_dot_pc_solved, m_q_dot_pc_max); + mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); + + turn_off_plant(); + are_models_converged = false; + break; + } + else + { + error_msg = util::format("At time = %lg %s converged to a PC thermal power %lg [MWt]" + " larger than the target PC thermal power %lg [MWt] but less than the maximum thermal power %lg [MWt]", + mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, op_mode_str.c_str(), q_dot_pc_solved, q_dot_pc_fixed, m_q_dot_pc_max); + + mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); + } + } + else if ((q_dot_pc_solved - q_dot_pc_fixed) / q_dot_pc_fixed < -1.E-3) + { + if (m_dot_pc_solved < m_m_dot_pc_max) + { // TES cannot provide enough thermal power - step down to next operating mode + + m_is_CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF_avail = false; + are_models_converged = false; + break; + } + // Notes: + //else + //{ // PC maximum mass flow is constraining the thermal power that TES can send the PC. Changing modes wont' help + // + //} + } + + // Set member defocus + m_defocus = defocus_solved; + + are_models_converged = true; + } + break; case CR_OFF__PC_TARGET__TES_DC__AUX_OFF: { @@ -3068,7 +3513,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3147,7 +3592,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3209,6 +3654,92 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } break; + case CR_TO_COLD__PC_SB__TES_DC__AUX_OFF: + { + if (!mc_collector_receiver.m_is_sensible_htf) + { + std::string err_msg = util::format("Operating mode, %d, is not configured for DSG mode", operating_mode); + throw(C_csp_exception(err_msg, "CSP Solver")); + } + + int cr_mode = C_csp_collector_receiver::ON; + C_csp_power_cycle::E_csp_power_cycle_modes pc_mode = C_csp_power_cycle::STANDBY; + + C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode = C_MEQ__m_dot_tes::E__CR_OUT__ITER_Q_DOT_TARGET_DC_ONLY; + C_MEQ__timestep::E_timestep_target_modes step_target_mode = C_MEQ__timestep::E_STEP_FIXED; + bool is_defocus = false; + + double q_dot_pc_fixed = q_pc_sb; //[MWt] + + op_mode_str = "CR_TO_COLD__PC_SB__TES_DC__AUX_OFF"; + + double defocus_solved = std::numeric_limits::quiet_NaN(); + + int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + + if (mode_code != 0) + { + m_is_CR_TO_COLD__PC_SB__TES_DC__AUX_OFF_avail = false; + are_models_converged = false; + break; + } + + double q_dot_pc_solved = mc_pc_out_solver.m_q_dot_htf; //[MWt] + double m_dot_pc_solved = mc_pc_out_solver.m_m_dot_htf; //[kg/hr] + + error_msg = util::format("At time = %lg plant controller tried operating mode %s which hasn't been tested", + mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, op_mode_str.c_str()); + mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); + + // Check if solved thermal power is greater than target + if ((q_dot_pc_solved - q_dot_pc_fixed) / q_dot_pc_fixed > 1.E-3) + { + if ((q_dot_pc_solved - m_q_dot_pc_max) / m_q_dot_pc_max > 1.E-3) + { + error_msg = util::format("At time = %lg %s converged to a PC thermal power %lg [MWt]" + " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", + mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, op_mode_str.c_str(), q_dot_pc_solved, m_q_dot_pc_max); + mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); + + turn_off_plant(); + are_models_converged = false; + break; + } + else + { + error_msg = util::format("At time = %lg %s converged to a PC thermal power %lg [MWt]" + " larger than the target PC thermal power %lg [MWt] but less than the maximum thermal power %lg [MWt]", + mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, op_mode_str.c_str(), q_dot_pc_solved, q_dot_pc_fixed, m_q_dot_pc_max); + + mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); + } + } + else if ((q_dot_pc_solved - q_dot_pc_fixed) / q_dot_pc_fixed < -1.E-3) + { + if (m_dot_pc_solved < m_m_dot_pc_max) + { // TES cannot provide enough thermal power - step down to next operating mode + m_is_CR_TO_COLD__PC_SB__TES_DC__AUX_OFF_avail = false; + + are_models_converged = false; + break; + } + // Notes: + //else + //{ // PC maximum mass flow is constraining the thermal power that TES can send the PC. Changing modes wont' help + // + //} + } + + // Set member defocus + m_defocus = defocus_solved; + + // If convergence was successful, finalize this timestep and get out + // Have solved CR, TES, and PC in this operating mode, so only need to set flag to get out of Mode Iteration + are_models_converged = true; + } + break; + case CR_OFF__PC_SB__TES_DC__AUX_OFF: { if (!mc_collector_receiver.m_is_sensible_htf) @@ -3230,7 +3761,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3317,7 +3848,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3377,7 +3908,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) // Have solved CR, TES, and PC in this operating mode, so only need to set flag to get out of Mode Iteration are_models_converged = true; - } // end 'CR_OFF__PC_TARGET__TES_DC__AUX_OFF' + } // end 'CR_SU__PC_SB__TES_DC__AUX_OFF' break; @@ -3405,7 +3936,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3468,7 +3999,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_target, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_target, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3575,7 +4106,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3620,7 +4151,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3661,7 +4192,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3719,7 +4250,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3761,7 +4292,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3849,6 +4380,32 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) mcold_avail = mdot_ch * mc_kernel.mc_sim_info.ms_ts.m_step; //kg } + // Update the cycle state persistance + if (mc_power_cycle.get_operating_state() == prev_pc_state) + pc_state_persist += mc_kernel.mc_sim_info.ms_ts.m_step / 3600.; + else + { + pc_state_persist = 0.; + prev_pc_state = mc_power_cycle.get_operating_state(); + } + + // Update the receiver state persistance + if (mc_collector_receiver.get_operating_state() == prev_rec_state) + rec_state_persist += mc_kernel.mc_sim_info.ms_ts.m_step / 3600.; + else + { + rec_state_persist = 0.; + prev_rec_state = mc_collector_receiver.get_operating_state(); + } + + + + double f_op_last = 0.0; + if (mc_power_cycle.get_operating_state() == C_csp_power_cycle::ON || mc_power_cycle.get_operating_state() == C_csp_power_cycle::STANDBY) + f_op_last = mc_kernel.mc_sim_info.ms_ts.m_step / baseline_step; // Fraction of timestep cycle was in this state + + + // Save timestep outputs // This is after timestep convergence, so be sure convergence() methods don't unexpectedly change outputs @@ -3892,24 +4449,33 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_SB, q_pc_sb); //[MW] mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_MIN, q_pc_min); //[MW] mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_TARGET, q_pc_target); //[MW] - mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_MAX, m_q_dot_pc_max); //[MW] + mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_MAX, m_q_dot_pc_max); //[MW] + mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_TARGET_SU, q_dot_pc_su_target_reporting); //[MW] + mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_TARGET_ON, q_dot_pc_on_target_reporting); //[MW] mc_reported_outputs.value(C_solver_outputs::CTRL_IS_REC_SU, is_rec_su_allowed); //[-] mc_reported_outputs.value(C_solver_outputs::CTRL_IS_PC_SU, is_pc_su_allowed); //[-] mc_reported_outputs.value(C_solver_outputs::CTRL_IS_PC_SB, is_pc_sb_allowed); //[-] - mc_reported_outputs.value(C_solver_outputs::EST_Q_DOT_CR_SU, is_pc_sb_allowed); //[-] + mc_reported_outputs.value(C_solver_outputs::EST_Q_DOT_CR_SU, q_dot_cr_startup); //[-] mc_reported_outputs.value(C_solver_outputs::EST_Q_DOT_CR_ON, q_dot_cr_on); //[MWt] mc_reported_outputs.value(C_solver_outputs::EST_Q_DOT_DC, q_dot_tes_dc); //[MWt] mc_reported_outputs.value(C_solver_outputs::EST_Q_DOT_CH, q_dot_tes_ch); //[MWt] - double m_dot_bal_hot = (mc_cr_out_solver.m_m_dot_salt_tot + + double m_dot_cr_out_to_tes_hot = mc_cr_out_solver.m_m_dot_salt_tot; //[kg/hr] + double m_dot_cr_out_to_tes_cold = 0.0; + if (!is_rec_outlet_to_hottank) { + m_dot_cr_out_to_tes_cold = mc_cr_out_solver.m_m_dot_salt_tot; //[kg/hr] + m_dot_cr_out_to_tes_hot = 0.0; + } + + double m_dot_bal_hot = (m_dot_cr_out_to_tes_hot + mc_tes_outputs.m_m_dot_tes_hot_out*3600.0 - mc_pc_inputs.m_m_dot - mc_tes_outputs.m_m_dot_cr_to_tes_hot*3600.0) / m_m_dot_pc_des; //[-] - double m_dot_bal_cold = (mc_pc_inputs.m_m_dot + + double m_dot_bal_cold = (m_dot_cr_out_to_tes_cold + mc_pc_inputs.m_m_dot + mc_tes_outputs.m_m_dot_tes_cold_out*3600.0 - mc_cr_out_solver.m_m_dot_salt_tot - - mc_tes_outputs.m_m_dot_pc_to_tes_cold*3600.0) / m_m_dot_pc_des; //[-] + mc_tes_outputs.m_m_dot_tes_cold_in*3600.0) / m_m_dot_pc_des; //[-] double m_dot_bal_max = max(fabs(m_dot_bal_hot), fabs(m_dot_bal_cold)); @@ -3935,11 +4501,14 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) mc_reported_outputs.value(C_solver_outputs::TES_Q_DOT_DC, mc_tes_outputs.m_q_dot_dc_to_htf); //[MWt] TES discharge thermal power mc_reported_outputs.value(C_solver_outputs::TES_Q_DOT_CH, mc_tes_outputs.m_q_dot_ch_from_htf); //[MWt] TES charge thermal power mc_reported_outputs.value(C_solver_outputs::TES_E_CH_STATE, e_tes_disch); //[MWht] TES charge state + mc_reported_outputs.value(C_solver_outputs::TES_T_COLD_IN, mc_tes_outputs.m_T_tes_cold_in - 273.15); //[C] mc_reported_outputs.value(C_solver_outputs::M_DOT_CR_TO_TES_HOT, mc_tes_outputs.m_m_dot_cr_to_tes_hot); //[kg/s] + mc_reported_outputs.value(C_solver_outputs::M_DOT_CR_TO_TES_COLD, mc_tes_outputs.m_m_dot_cr_to_tes_cold); //[kg/s] mc_reported_outputs.value(C_solver_outputs::M_DOT_TES_HOT_OUT, mc_tes_outputs.m_m_dot_tes_hot_out); //[kg/s] mc_reported_outputs.value(C_solver_outputs::M_DOT_PC_TO_TES_COLD, mc_tes_outputs.m_m_dot_pc_to_tes_cold); //[kg/s] mc_reported_outputs.value(C_solver_outputs::M_DOT_TES_COLD_OUT, mc_tes_outputs.m_m_dot_tes_cold_out); //[kg/s] + mc_reported_outputs.value(C_solver_outputs::M_DOT_TES_COLD_IN, mc_tes_outputs.m_m_dot_tes_cold_in); //[kg/s] mc_reported_outputs.value(C_solver_outputs::M_DOT_FIELD_TO_CYCLE, mc_tes_outputs.m_m_dot_field_to_cycle); //[kg/s] mc_reported_outputs.value(C_solver_outputs::M_DOT_CYCLE_TO_FIELD, mc_tes_outputs.m_m_dot_cycle_to_field); //[kg/s] @@ -4022,14 +4591,9 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } mc_reported_outputs.value(C_solver_outputs::CTRL_OP_MODE_SEQ_C, op_mode_key); - operating_mode_str_prev = operating_mode_str; - op_mode_str_prev = op_mode_str; - mc_reported_outputs.set_timestep_outputs(); - - // **************************************************** // End saving timestep outputs // **************************************************** diff --git a/tcs/csp_solver_core.h b/tcs/csp_solver_core.h index 3c42e93f6..c57fe501e 100644 --- a/tcs/csp_solver_core.h +++ b/tcs/csp_solver_core.h @@ -664,35 +664,40 @@ class C_csp_tes struct S_csp_tes_outputs { - double m_q_heater = //[MWe] Heating power required to keep tanks at a minimum temperature - std::numeric_limits::quiet_NaN(); - double m_q_dot_dc_to_htf = //[MWt] Thermal power to the HTF from storage - std::numeric_limits::quiet_NaN(); - double m_q_dot_ch_from_htf = //[MWt] Thermal power from the HTF to storage - std::numeric_limits::quiet_NaN(); + double m_q_heater; //[MWe] Heating power required to keep tanks at a minimum temperature + double m_q_dot_dc_to_htf; //[MWt] Thermal power to the HTF from storage + double m_q_dot_ch_from_htf; //[MWt] Thermal power from the HTF to storage + + double m_m_dot_cr_to_tes_hot; //[kg/s] + double m_m_dot_cr_to_tes_cold; //[kg/s] + double m_m_dot_tes_hot_out; //[kg/s] + double m_m_dot_pc_to_tes_cold; //[kg/s] + double m_m_dot_tes_cold_out; //[kg/s] + double m_m_dot_tes_cold_in; //[kg/s] + double m_m_dot_field_to_cycle; //[kg/s] + double m_m_dot_cycle_to_field; //[kg/s] - double m_m_dot_cr_to_tes_hot = //[kg/s] - std::numeric_limits::quiet_NaN(); - double m_m_dot_tes_hot_out = //[kg/s] - std::numeric_limits::quiet_NaN(); - double m_m_dot_pc_to_tes_cold = //[kg/s] - std::numeric_limits::quiet_NaN(); - double m_m_dot_tes_cold_out = //[kg/s] - std::numeric_limits::quiet_NaN(); - double m_m_dot_field_to_cycle = //[kg/s] - std::numeric_limits::quiet_NaN(); - double m_m_dot_cycle_to_field = //[kg/s] - std::numeric_limits::quiet_NaN(); + double m_T_tes_cold_in; //[K] - // Mass flow rate from one tank directly to another. = -1; 0 for direct systems - double m_m_dot_cold_tank_to_hot_tank = //[kg/s] - std::numeric_limits::quiet_NaN(); + // Mass flow rate from one tank directly to another. = 0 for direct systems + double m_m_dot_cold_tank_to_hot_tank; //[kg/s] + + S_csp_tes_outputs() + { + m_q_heater = m_q_dot_dc_to_htf = m_q_dot_ch_from_htf = + m_m_dot_cr_to_tes_hot = m_m_dot_cr_to_tes_cold = m_m_dot_pc_to_tes_cold = m_m_dot_pc_to_tes_cold = + m_m_dot_tes_cold_out = m_m_dot_tes_cold_in = m_m_dot_field_to_cycle = m_m_dot_cycle_to_field = + m_T_tes_cold_in = + m_m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); + } }; virtual void init(const C_csp_tes::S_csp_tes_init_inputs init_inputs) = 0; virtual bool does_tes_exist() = 0; + virtual bool is_cr_to_cold_allowed() = 0; + virtual double get_hot_temp() = 0; virtual double get_cold_temp() = 0; @@ -707,11 +712,14 @@ class C_csp_tes virtual double get_degradation_rate() = 0; // s^-1 + virtual void reset_storage_to_initial_state() = 0; + virtual void discharge_avail_est(double T_cold_K, double step_s, double &q_dot_dc_est, double &m_dot_field_est, double &T_hot_field_est) = 0; virtual void charge_avail_est(double T_hot_K, double step_s, double &q_dot_ch_est, double &m_dot_field_est /*kg/s*/, double &T_cold_field_est /*K*/) = 0; - virtual int solve_tes_off_design(double timestep /*s*/, double T_amb /*K*/, double m_dot_field /*kg/s*/, double m_dot_cycle /*kg/s*/, + virtual int solve_tes_off_design(double timestep /*s*/, double T_amb /*K*/, + double m_dot_cr_to_cv_hot /*kg/s*/, double m_dot_cv_hot_to_cycle /*kg/s*/, double m_dot_cr_to_cv_cold /*kg/s*/, double T_field_htf_out_hot /*K*/, double T_cycle_htf_out_cold /*K*/, double & T_cycle_htf_in_hot /*K*/, double & T_field_htf_in_cold /*K*/, C_csp_tes::S_csp_tes_outputs& outputs) = 0; @@ -761,6 +769,8 @@ class C_csp_solver PC_Q_DOT_MIN, //[MWt] PC required min thermal power PC_Q_DOT_TARGET, //[MWt] PC target thermal power PC_Q_DOT_MAX, //[MWt] PC allowable max thermal power + PC_Q_DOT_TARGET_SU, //[MWt] PC target thermal power for startup + PC_Q_DOT_TARGET_ON, //[MWt] PC target thermal power for cycle on CTRL_IS_REC_SU, //[-] Control decision: is receiver startup allowed? CTRL_IS_PC_SU, //[-] Control decision: is power cycle startup allowed? CTRL_IS_PC_SB, //[-] Control decision: is power cycle standby allowed? @@ -806,10 +816,13 @@ class C_csp_solver TES_Q_DOT_DC, //[MWt] TES discharge thermal power TES_Q_DOT_CH, //[MWt] TES charge thermal power TES_E_CH_STATE, //[MWht] TES charge state at the end of the time step - M_DOT_CR_TO_TES_HOT, //[kg/s] + TES_T_COLD_IN, //[C] Inlet temperature to cold TES + M_DOT_CR_TO_TES_HOT, //[kg/s] + M_DOT_CR_TO_TES_COLD, //[kg/s] M_DOT_TES_HOT_OUT, //[kg/s] M_DOT_PC_TO_TES_COLD, //[kg/s] M_DOT_TES_COLD_OUT, //[kg/s] + M_DOT_TES_COLD_IN, //[kg/s] M_DOT_FIELD_TO_CYCLE, //[kg/s] M_DOT_CYCLE_TO_FIELD, //[kg/s] //TES_M_DOT_DC, //[MWt] TES discharge mass flow rate @@ -893,11 +906,22 @@ class C_csp_solver double m_bop_par_1; //[-] double m_bop_par_2; //[-] + bool m_is_rec_to_coldtank_allowed; + + // If receiver outlet to cold tank is allowed + // outlet temps colder than this value go to the cold tank + // calculate T_htf_hot_tank_in_min = f*T_hot_des + (1-f)*T_cold_des + double f_htf_hot_des__T_htf_hot_tank_in_min; //[-] + S_csp_system_params() { m_pb_fixed_par = m_bop_par = m_bop_par_f = m_bop_par_0 = m_bop_par_1 = m_bop_par_2 = std::numeric_limits::quiet_NaN(); + + f_htf_hot_des__T_htf_hot_tank_in_min = std::numeric_limits::quiet_NaN(); + + m_is_rec_to_coldtank_allowed = false; } }; @@ -973,6 +997,13 @@ class C_csp_solver bool m_is_CR_DF__PC_SU__TES_OFF__AUX_OFF_avail; + bool m_is_CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF_avail; + bool m_is_CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF_avail; + bool m_is_CR_TO_COLD__PC_SB__TES_DC__AUX_OFF_avail; + bool m_is_CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF_avail; + bool m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail; + bool m_is_CR_TO_COLD__PC_SU__TES_DC__AUX_OFF_avail; + // member string for exception messages std::string error_msg; @@ -1005,6 +1036,12 @@ class C_csp_solver bool m_is_tes; //[-] True: plant has storage bool m_is_cr_config_recirc; //[-] True: Receiver "off" and "startup" are recirculated from outlet to inlet + // System control logic + // True: allows control to consider sending rec exit HTF to cold tank if colder than some threshold + bool m_is_rec_to_coldtank_allowed; //[-] + // if 'm_is_rec_to_coldtank_allowed' then T_cr_out < this temp go to cold tank + double m_T_htf_hot_tank_in_min; //[C] + // Field-side HTF double m_T_field_cold_limit; //[C] double m_T_field_in_hot_limit; //[C] @@ -1112,7 +1149,21 @@ class C_csp_solver CR_DF__PC_SU__TES_FULL__AUX_OFF, - CR_DF__PC_SU__TES_OFF__AUX_OFF + CR_DF__PC_SU__TES_OFF__AUX_OFF, + + CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF, + + CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF, + + CR_TO_COLD__PC_SB__TES_DC__AUX_OFF, + + CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF, + + CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF, + + SKIP_40, + + CR_TO_COLD__PC_SU__TES_DC__AUX_OFF }; static std::string tech_operating_modes_str[]; @@ -1175,6 +1226,7 @@ class C_csp_solver C_csp_power_cycle::E_csp_power_cycle_modes m_pc_mode; //[-] int m_cr_mode; //[-] + bool m_is_rec_outlet_to_hottank; //[-] double m_q_dot_pc_target; //[MWt] @@ -1194,6 +1246,7 @@ class C_csp_solver C_MEQ__m_dot_tes(E_m_dot_solver_modes solver_mode, C_csp_solver* pc_csp_solver, C_csp_power_cycle::E_csp_power_cycle_modes pc_mode, int cr_mode, + bool is_rec_outlet_to_hottank, double q_dot_pc_target /*MWt*/, double defocus /*-*/, double t_ts /*s*/, double P_field_in /*kPa*/, double x_field_in /*-*/, @@ -1204,6 +1257,9 @@ class C_csp_solver mpc_csp_solver = pc_csp_solver; m_pc_mode = pc_mode; //[-] m_cr_mode = cr_mode; //[-] + + m_is_rec_outlet_to_hottank = is_rec_outlet_to_hottank; + m_q_dot_pc_target = q_dot_pc_target; //[MWt] m_defocus = defocus; //[-] m_t_ts_in = t_ts; //[s] @@ -1231,6 +1287,7 @@ class C_csp_solver C_csp_power_cycle::E_csp_power_cycle_modes m_pc_mode; //[-] int m_cr_mode; //[-] + bool m_is_rec_outlet_to_hottank; //[-] double m_defocus; //[-] double m_t_ts_in; //[s] @@ -1244,6 +1301,7 @@ class C_csp_solver C_MEQ__T_field_cold(C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode, C_csp_solver* pc_csp_solver, double q_dot_pc_target /*MWt*/, C_csp_power_cycle::E_csp_power_cycle_modes pc_mode, int cr_mode, + bool is_rec_outlet_to_hottank, double defocus /*-*/, double t_ts /*s*/, double P_field_in /*kPa*/, double x_field_in /*-*/) { @@ -1255,6 +1313,7 @@ class C_csp_solver m_pc_mode = pc_mode; m_cr_mode = cr_mode; + m_is_rec_outlet_to_hottank = is_rec_outlet_to_hottank; m_defocus = defocus; m_t_ts_in = t_ts; //[s] @@ -1289,6 +1348,7 @@ class C_csp_solver C_csp_power_cycle::E_csp_power_cycle_modes m_pc_mode; //[-] int m_cr_mode; //[-] + bool m_is_rec_outlet_to_hottank; //[-] double m_defocus; //[-] @@ -1297,6 +1357,7 @@ class C_csp_solver C_csp_solver* pc_csp_solver, double q_dot_pc_target /*MWt*/, C_csp_power_cycle::E_csp_power_cycle_modes pc_mode, int cr_mode, + bool is_rec_outlet_to_hottank, double defocus /*-*/) { m_solver_mode = solver_mode; @@ -1308,6 +1369,7 @@ class C_csp_solver m_pc_mode = pc_mode; m_cr_mode = cr_mode; + m_is_rec_outlet_to_hottank = is_rec_outlet_to_hottank; m_defocus = defocus; } @@ -1334,6 +1396,7 @@ class C_csp_solver C_csp_power_cycle::E_csp_power_cycle_modes m_pc_mode; //[-] int m_cr_mode; //[-] + bool m_is_rec_outlet_to_hottank; //[-] double m_t_ts_initial; //[s] @@ -1344,6 +1407,7 @@ class C_csp_solver C_csp_solver *pc_csp_solver, double q_dot_pc_target /*MWt*/, C_csp_power_cycle::E_csp_power_cycle_modes pc_mode, int cr_mode, + bool is_rec_outlet_to_hottank, double t_ts_initial /*s*/) { m_solver_mode = solver_mode; @@ -1356,6 +1420,7 @@ class C_csp_solver m_pc_mode = pc_mode; m_cr_mode = cr_mode; + m_is_rec_outlet_to_hottank = is_rec_outlet_to_hottank; m_t_ts_initial = t_ts_initial; //[s] } @@ -1367,7 +1432,7 @@ class C_csp_solver int solve_operating_mode(int cr_mode, C_csp_power_cycle::E_csp_power_cycle_modes pc_mode, C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode, C_MEQ__timestep::E_timestep_target_modes step_target_mode, - double q_dot_pc_target /*MWt*/, bool is_defocus, + double q_dot_pc_target /*MWt*/, bool is_defocus, bool is_rec_outlet_to_hottank, std::string op_mode_str, double& defocus_solved); diff --git a/tcs/csp_solver_mono_eq_methods.cpp b/tcs/csp_solver_mono_eq_methods.cpp index 703e7995a..07e2680b7 100644 --- a/tcs/csp_solver_mono_eq_methods.cpp +++ b/tcs/csp_solver_mono_eq_methods.cpp @@ -38,7 +38,7 @@ void C_csp_solver::reset_time(double step /*s*/) int C_csp_solver::solve_operating_mode(int cr_mode, C_csp_power_cycle::E_csp_power_cycle_modes pc_mode, C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode, C_MEQ__timestep::E_timestep_target_modes step_target_mode, - double q_dot_pc_target /*MWt*/, bool is_defocus, + double q_dot_pc_target /*MWt*/, bool is_defocus, bool is_rec_outlet_to_hottank, std::string op_mode_str, double & defocus_solved) { double t_ts_initial = mc_kernel.mc_sim_info.ms_ts.m_step; //[s] @@ -46,6 +46,7 @@ int C_csp_solver::solve_operating_mode(int cr_mode, C_csp_power_cycle::E_csp_pow C_MEQ__defocus c_mdot_eq(solver_mode, C_MEQ__defocus::E_M_DOT_BAL, step_target_mode, this, q_dot_pc_target, pc_mode, cr_mode, + is_rec_outlet_to_hottank, t_ts_initial); //, step_tolerance); C_monotonic_eq_solver c_mdot_solver(c_mdot_eq); @@ -141,6 +142,7 @@ int C_csp_solver::solve_operating_mode(int cr_mode, C_csp_power_cycle::E_csp_pow this, q_dot_pc_target, pc_mode, cr_mode, + is_rec_outlet_to_hottank, t_ts_initial); C_monotonic_eq_solver c_q_dot_solver(c_q_dot_eq); @@ -229,6 +231,7 @@ int C_csp_solver::solve_operating_mode(int cr_mode, C_csp_power_cycle::E_csp_pow //m_dot_tes, q_dot_pc_target, pc_mode, cr_mode, + is_rec_outlet_to_hottank, t_ts_initial); // , step_tolerance); C_monotonic_eq_solver c_bal_solver(c_bal_eq); @@ -278,7 +281,9 @@ int C_csp_solver::C_MEQ__defocus::operator()(double defocus /*-*/, double *targe { C_MEQ__timestep c_T_cold_eq(m_solver_mode, m_ts_target_mode, mpc_csp_solver, m_q_dot_pc_target, - m_pc_mode, m_cr_mode, defocus); + m_pc_mode, m_cr_mode, + m_is_rec_outlet_to_hottank, + defocus); C_monotonic_eq_solver c_T_cold_solver(c_T_cold_eq); double t_ts_solved = std::numeric_limits::quiet_NaN(); @@ -528,6 +533,7 @@ int C_csp_solver::C_MEQ__timestep::operator()(double t_ts_guess /*s*/, double *t C_MEQ__T_field_cold c_eq(m_solver_mode, mpc_csp_solver, m_q_dot_pc_target, m_pc_mode, m_cr_mode, + m_is_rec_outlet_to_hottank, m_defocus, t_ts_guess, mpc_csp_solver->m_P_cold_des, mpc_csp_solver->m_x_cold_des); C_monotonic_eq_solver c_solver(c_eq); @@ -646,6 +652,7 @@ int C_csp_solver::C_MEQ__m_dot_tes::operator()(double f_m_dot_tes /*-*/, double mpc_csp_solver->mc_cr_htf_state_in.m_qual = m_x_field_in; //[-] double m_dot_field_out = std::numeric_limits::quiet_NaN(); //[kg/hr] + double m_dot_field_out_to_cold_tank = 0.0; //[kg/hr] double t_ts_cr_su = m_t_ts_in; if (m_cr_mode == C_csp_collector_receiver::ON) { @@ -661,7 +668,14 @@ int C_csp_solver::C_MEQ__m_dot_tes::operator()(double f_m_dot_tes /*-*/, double return -1; } + if (m_is_rec_outlet_to_hottank) { m_dot_field_out = mpc_csp_solver->mc_cr_out_solver.m_m_dot_salt_tot; //[kg/hr] + m_dot_field_out_to_cold_tank = 0.0; + } + else { + m_dot_field_out_to_cold_tank = mpc_csp_solver->mc_cr_out_solver.m_m_dot_salt_tot; //[kg/hr] + m_dot_field_out = 0.0; + } } else if (m_cr_mode == C_csp_collector_receiver::STARTUP) { @@ -846,13 +860,15 @@ int C_csp_solver::C_MEQ__m_dot_tes::operator()(double f_m_dot_tes /*-*/, double m_m_dot_pc_in = 0.0; } + // Solve TES with solved CR outlet temperature and guessed PC outlet temperature + // to get the cycle inlet temperature double T_cycle_hot = std::numeric_limits::quiet_NaN(); //[K] double T_field_cold_calc = std::numeric_limits::quiet_NaN(); //[K] if (mpc_csp_solver->m_is_tes) { int tes_code = mpc_csp_solver->mc_tes.solve_tes_off_design(mpc_csp_solver->mc_kernel.mc_sim_info.ms_ts.m_step, mpc_csp_solver->mc_weather.ms_outputs.m_tdry + 273.15, - m_dot_hot_to_tes / 3600.0, m_m_dot_pc_in / 3600.0, + m_dot_hot_to_tes / 3600.0, m_m_dot_pc_in / 3600.0, m_dot_field_out_to_cold_tank / 3600.0, mpc_csp_solver->mc_cr_out_solver.m_T_salt_hot + 273.15, m_T_field_cold_guess + 273.15, T_cycle_hot, T_field_cold_calc, mpc_csp_solver->mc_tes_outputs); @@ -868,7 +884,8 @@ int C_csp_solver::C_MEQ__m_dot_tes::operator()(double f_m_dot_tes /*-*/, double T_cycle_hot = mpc_csp_solver->mc_cr_out_solver.m_T_salt_hot + 273.15; //[K] } - // Power Cycle + // Solve power cycle with solved inlet temperature + // get outlet temperature mpc_csp_solver->mc_pc_htf_state_in.m_temp = T_cycle_hot - 273.15; //[C], convert from K mpc_csp_solver->mc_pc_htf_state_in.m_pres = mpc_csp_solver->mc_cr_out_solver.m_P_htf_hot; //[kPa] mpc_csp_solver->mc_pc_htf_state_in.m_qual = mpc_csp_solver->mc_cr_out_solver.m_xb_htf_hot; //[-] @@ -896,11 +913,12 @@ int C_csp_solver::C_MEQ__m_dot_tes::operator()(double f_m_dot_tes /*-*/, double t_ts_pc_su = mpc_csp_solver->mc_pc_out_solver.m_time_required_max; //[s] } + // Solve TES again, this time with both the solved CR outlet and PC outlet temperatures if (mpc_csp_solver->m_is_tes) { int tes_code = mpc_csp_solver->mc_tes.solve_tes_off_design(mpc_csp_solver->mc_kernel.mc_sim_info.ms_ts.m_step, mpc_csp_solver->mc_weather.ms_outputs.m_tdry + 273.15, - m_dot_hot_to_tes / 3600.0, m_m_dot_pc_in / 3600.0, + m_dot_hot_to_tes / 3600.0, m_m_dot_pc_in / 3600.0, m_dot_field_out_to_cold_tank / 3600.0, mpc_csp_solver->mc_cr_out_solver.m_T_salt_hot + 273.15, mpc_csp_solver->mc_pc_out_solver.m_T_htf_cold + 273.15, T_cycle_hot, T_field_cold_calc, mpc_csp_solver->mc_tes_outputs); @@ -956,7 +974,7 @@ int C_csp_solver::C_MEQ__T_field_cold::operator()(double T_field_cold /*C*/, dou init_calc_member_vars(); C_MEQ__m_dot_tes c_eq(m_solver_mode, mpc_csp_solver, - m_pc_mode, m_cr_mode, + m_pc_mode, m_cr_mode, m_is_rec_outlet_to_hottank, m_q_dot_pc_target, m_defocus, m_t_ts_in, m_P_field_in, m_x_field_in, T_field_cold); diff --git a/tcs/csp_solver_two_tank_tes.cpp b/tcs/csp_solver_two_tank_tes.cpp index 6935637d8..43e50ee03 100644 --- a/tcs/csp_solver_two_tank_tes.cpp +++ b/tcs/csp_solver_two_tank_tes.cpp @@ -434,7 +434,7 @@ double C_storage_tank::get_m_T_calc() double C_storage_tank::get_m_m_calc() //ARD new getter for current mass { - return m_m_calc; + return m_m_calc; //[kg] } double C_storage_tank::get_vol_frac() @@ -442,13 +442,18 @@ double C_storage_tank::get_vol_frac() return (m_V_prev - m_V_inactive) / m_V_active; } +double C_storage_tank::get_mass_avail() +{ + return std::max(m_m_prev - m_mass_inactive, 0.0); //[kg] +} + double C_storage_tank::m_dot_available(double f_unavail, double timestep) { //double rho = mc_htf.dens(m_T_prev, 1.0); //[kg/m^3] //double V = m_m_prev / rho; //[m^3] Volume available in tank (one temperature) //double V_avail = fmax(V - m_V_inactive, 0.0); //[m^3] Volume that is active - need to maintain minimum height (corresponding m_V_inactive) - double mass_avail = std::max(m_m_prev - m_mass_inactive, 0.0); //[kg] + double mass_avail = get_mass_avail(); //[kg] double m_dot_avail = std::max(mass_avail - m_mass_active * f_unavail, 0.0) / timestep; //[kg/s] // "Unavailable" fraction now applied to one temperature tank volume, not total tank volume @@ -465,7 +470,8 @@ void C_storage_tank::converged() m_m_prev = m_m_calc; //[kg] } -void C_storage_tank::energy_balance(double timestep /*s*/, double m_dot_in, double m_dot_out, double T_in /*K*/, double T_amb /*K*/, +void C_storage_tank::energy_balance(double timestep /*s*/, double m_dot_in /*kg/s*/, double m_dot_out /*kg/s*/, + double T_in /*K*/, double T_amb /*K*/, double &T_ave /*K*/, double & q_heater /*MW*/, double & q_dot_loss /*MW*/) { // Get properties from tank state at the end of last time step @@ -690,6 +696,7 @@ static C_csp_reported_outputs::S_output_info S_output_info[] = {C_csp_two_tank_tes::E_M_DOT_TANK_TO_TANK, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[MWt] TES thermal losses {C_csp_two_tank_tes::E_MASS_COLD_TANK, C_csp_reported_outputs::TS_LAST}, //[kg] Mass in cold tank at end of timestep {C_csp_two_tank_tes::E_MASS_HOT_TANK, C_csp_reported_outputs::TS_LAST}, //[kg] Mass in hot tank at end of timestep + {C_csp_two_tank_tes::E_HOT_TANK_HTF_PERC_FINAL, C_csp_reported_outputs::TS_LAST}, //[%] Final percent fill of available hot tank mass csp_info_invalid }; @@ -697,7 +704,7 @@ static C_csp_reported_outputs::S_output_info S_output_info[] = C_csp_two_tank_tes::C_csp_two_tank_tes() { m_vol_tank = m_V_tank_active = m_q_pb_design = - m_V_tank_hot_ini = m_cp_field_avg = m_m_dot_tes_des_over_m_dot_field_des = std::numeric_limits::quiet_NaN(); + m_V_tank_hot_ini = m_mass_total_active = m_cp_field_avg = m_m_dot_tes_des_over_m_dot_field_des = std::numeric_limits::quiet_NaN(); // m_m_dot_tes_dc_max = m_m_dot_tes_ch_max = std::numeric_limits::quiet_NaN(); @@ -807,6 +814,13 @@ void C_csp_two_tank_tes::init(const C_csp_tes::S_csp_tes_init_inputs init_inputs ms_params.tanks_in_parallel = true; } + if (ms_params.tanks_in_parallel) { + m_is_cr_to_cold_tank_allowed = false; + } + else { + m_is_cr_to_cold_tank_allowed = true; + } + // Calculate thermal power to PC at design m_q_pb_design = ms_params.m_W_dot_pc_design/ms_params.m_eta_pc*1.E6; //[Wt] @@ -839,9 +853,33 @@ void C_csp_two_tank_tes::init(const C_csp_tes::S_csp_tes_init_inputs init_inputs // The 'duty' definition should allow the tanks to accept whatever the field and/or power cycle can provide... // Calculate initial storage values + + // Initial storage charge based on % mass + double T_tes_ave = 0.5*(ms_params.m_T_field_out_des + ms_params.m_T_field_in_des); + double cp_ave = mc_store_htfProps.Cp(T_tes_ave); //[kJ/kg-K] Specific heat at average temperature + m_mass_total_active = Q_tes_des*3600.0 / (cp_ave / 1000.0 * (ms_params.m_T_field_out_des - ms_params.m_T_field_in_des)); //[kg] Total HTF mass at design point inlet/outlet T double V_inactive = m_vol_tank - m_V_tank_active; - double V_hot_ini = ms_params.m_f_V_hot_ini*0.01*m_V_tank_active + V_inactive; //[m^3] - double V_cold_ini = (1.0 - ms_params.m_f_V_hot_ini*0.01)*m_V_tank_active + V_inactive; //[m^3] + + double rho_hot_des = mc_store_htfProps.dens(ms_params.m_T_field_out_des, 1.0); + double rho_cold_des = mc_store_htfProps.dens(ms_params.m_T_field_in_des, 1.0); + double rho_hot = mc_store_htfProps.dens(ms_params.m_T_tank_hot_ini, 1.0); + double rho_cold = mc_store_htfProps.dens(ms_params.m_T_tank_cold_ini, 1.0); + double m_hot_ini = ms_params.m_f_V_hot_ini * 0.01 * m_mass_total_active + V_inactive * rho_hot_des; // Updating intiial storage charge calculation to avoid variation in total mass with specified initial T + double m_cold_ini = (1.0 - ms_params.m_f_V_hot_ini * 0.01) * m_mass_total_active + V_inactive * rho_cold_des; + double V_hot_ini = m_hot_ini / rho_hot; + double V_cold_ini = m_cold_ini / rho_cold; + + //double rho_hot = mc_store_htfProps.dens(ms_params.m_T_tank_hot_ini, 1.0); + //double rho_cold = mc_store_htfProps.dens(ms_params.m_T_tank_cold_ini, 1.0); + + //double V_inactive = m_vol_tank - m_V_tank_active; + //double V_hot_ini = ms_params.m_f_V_hot_ini*0.01*m_mass_total_active / rho_hot + V_inactive; //[m^3] + //double V_cold_ini = (1.0 - ms_params.m_f_V_hot_ini*0.01)*m_mass_total_active / rho_cold + V_inactive; //[m^3] + + // Initial storage charge based on % volume + //double V_inactive = m_vol_tank - m_V_tank_active; + //double V_hot_ini = ms_params.m_f_V_hot_ini*0.01*m_V_tank_active + V_inactive; //[m^3] + //double V_cold_ini = (1.0 - ms_params.m_f_V_hot_ini*0.01)*m_V_tank_active + V_inactive; //[m^3] double T_hot_ini = ms_params.m_T_tank_hot_ini; //[K] double T_cold_ini = ms_params.m_T_tank_cold_ini; //[K] @@ -912,6 +950,11 @@ bool C_csp_two_tank_tes::does_tes_exist() return m_is_tes; } +bool C_csp_two_tank_tes::is_cr_to_cold_allowed() +{ + return m_is_cr_to_cold_tank_allowed; +} + double C_csp_two_tank_tes::get_hot_temp() { return mc_hot_tank.get_m_T_prev(); //[K] @@ -965,6 +1008,34 @@ double C_csp_two_tank_tes::get_degradation_rate() return e_loss / (m_q_pb_design * ms_params.m_ts_hours * 3600.); //s^-1 -- fraction of heat loss per second based on full charge } +void C_csp_two_tank_tes::reset_storage_to_initial_state() +{ + // Initial storage charge based on % mass + double Q_tes_des = m_q_pb_design / 1.E6 * ms_params.m_ts_hours; //[MWt-hr] TES thermal capacity at design + double T_tes_ave = 0.5*(ms_params.m_T_field_out_des + ms_params.m_T_field_in_des); + double cp_ave = mc_store_htfProps.Cp(T_tes_ave); //[kJ/kg-K] Specific heat at average temperature + double mtot = Q_tes_des*3600.0 / (cp_ave / 1000.0 * (ms_params.m_T_field_out_des - ms_params.m_T_field_in_des)); //[kg] Total HTF mass + double rho_hot = mc_store_htfProps.dens(ms_params.m_T_field_out_des, 1.0); + double rho_cold = mc_store_htfProps.dens(ms_params.m_T_field_in_des, 1.0); + + double V_inactive = m_vol_tank - m_V_tank_active; + double V_hot_ini = ms_params.m_f_V_hot_ini*0.01*mtot / rho_hot + V_inactive; //[m^3] + double V_cold_ini = (1.0 - ms_params.m_f_V_hot_ini*0.01)*mtot / rho_cold + V_inactive; //[m^3] + + double T_hot_ini = ms_params.m_T_tank_hot_ini; //[K] + double T_cold_ini = ms_params.m_T_tank_cold_ini; //[K] + + // Initialize cold and hot tanks + // Hot tank + mc_hot_tank.init(mc_store_htfProps, m_vol_tank, ms_params.m_h_tank, ms_params.m_h_tank_min, + ms_params.m_u_tank, ms_params.m_tank_pairs, ms_params.m_hot_tank_Thtr, ms_params.m_hot_tank_max_heat, + V_hot_ini, T_hot_ini, ms_params.m_T_field_out_des); + // Cold tank + mc_cold_tank.init(mc_store_htfProps, m_vol_tank, ms_params.m_h_tank, ms_params.m_h_tank_min, + ms_params.m_u_tank, ms_params.m_tank_pairs, ms_params.m_cold_tank_Thtr, ms_params.m_cold_tank_max_heat, + V_cold_ini, T_cold_ini, ms_params.m_T_field_in_des); +} + double C_csp_two_tank_tes::get_tes_m_dot(double m_dot_field /*kg/s*/) { return m_dot_field * m_m_dot_tes_des_over_m_dot_field_des; @@ -1048,84 +1119,103 @@ void C_csp_two_tank_tes::charge_avail_est(double T_hot_K, double step_s, } } -int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_amb /*K*/, - double m_dot_field /*kg/s*/, double m_dot_cycle /*kg/s*/, - double T_field_htf_out_hot /*K*/, double T_cycle_htf_out_cold /*K*/, - double & T_cycle_htf_in_hot /*K*/, double & T_field_htf_in_cold /*K*/, - C_csp_tes::S_csp_tes_outputs & s_outputs) //, C_csp_solver_htf_state & s_tes_ch_htf, C_csp_solver_htf_state & s_tes_dc_htf) +int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_amb /*K*/, + double m_dot_cr_to_cv_hot /*kg/s*/, double m_dot_cv_hot_to_cycle /*kg/s*/, double m_dot_cr_to_cv_cold /*kg/s*/, + double T_cr_out_hot /*K*/, double T_cycle_out_cold /*K*/, + double& T_cycle_htf_in_hot /*K*/, double& T_cr_in_cold /*K*/, + C_csp_tes::S_csp_tes_outputs& s_outputs) //, C_csp_solver_htf_state & s_tes_ch_htf, C_csp_solver_htf_state & s_tes_dc_htf) { - s_outputs = S_csp_tes_outputs(); + // Enthalpy balance on inlet to cold cv + double T_htf_cold_cv_in = T_cycle_out_cold; //[K] + double m_dot_total_to_cv_cold = m_dot_cv_hot_to_cycle + m_dot_cr_to_cv_cold; //[kg/s] + if (m_dot_total_to_cv_cold > 0.0) { + T_htf_cold_cv_in = (m_dot_cv_hot_to_cycle*T_cycle_out_cold + m_dot_cr_to_cv_cold*T_cr_out_hot) / (m_dot_total_to_cv_cold); + } - double m_dot_cr_to_tes_hot, m_dot_tes_hot_out, m_dot_pc_to_tes_cold, m_dot_tes_cold_out; - m_dot_cr_to_tes_hot = m_dot_tes_hot_out = m_dot_pc_to_tes_cold = m_dot_tes_cold_out = std::numeric_limits::quiet_NaN(); - double m_dot_field_to_cycle, m_dot_cycle_to_field; - m_dot_field_to_cycle = m_dot_cycle_to_field = std::numeric_limits::quiet_NaN(); + // Total mass flow leaving cold tank to cr + // One of the RHS should always be 0... + double m_dot_cv_cold_to_cr = m_dot_cr_to_cv_hot + m_dot_cr_to_cv_cold; - if (ms_params.tanks_in_parallel) - { - if (m_dot_field >= m_dot_cycle) - { - m_dot_cr_to_tes_hot = m_dot_field - m_dot_cycle; //[kg/s] - m_dot_tes_hot_out = 0.0; //[kg/s] - m_dot_pc_to_tes_cold = 0.0; //[kg/s] - m_dot_tes_cold_out = m_dot_cr_to_tes_hot; //[kg/s] - m_dot_field_to_cycle = m_dot_cycle; //[kg/s] - m_dot_cycle_to_field = m_dot_cycle; //[kg/s] - } - else - { - m_dot_cr_to_tes_hot = 0.0; //[kg/s] - m_dot_tes_hot_out = m_dot_cycle - m_dot_field; //[kg/s] - m_dot_pc_to_tes_cold = m_dot_tes_hot_out; //[kg/s] - m_dot_tes_cold_out = 0.0; //[kg/s] - m_dot_field_to_cycle = m_dot_field; //[kg/s] - m_dot_cycle_to_field = m_dot_field; //[kg/s] - } - } - else - { - if (ms_params.m_is_hx) - { - throw(C_csp_exception("Serial operation of C_csp_two_tank_tes not available if there is a storage HX")); - } + s_outputs = S_csp_tes_outputs(); - m_dot_cr_to_tes_hot = m_dot_field; //[kg/s] - m_dot_tes_hot_out = m_dot_cycle; //[kg/s] - m_dot_pc_to_tes_cold = m_dot_cycle; //[kg/s] - m_dot_tes_cold_out = m_dot_field; //[kg/s] - m_dot_field_to_cycle = 0.0; //[kg/s] - m_dot_cycle_to_field = 0.0; //[kg/s] - } + double m_dot_cr_to_tes_hot, m_dot_cr_to_tes_cold, m_dot_tes_hot_out, m_dot_pc_to_tes_cold, m_dot_tes_cold_out, m_dot_tes_cold_in; + m_dot_cr_to_tes_hot = m_dot_cr_to_tes_cold = m_dot_tes_hot_out = m_dot_pc_to_tes_cold = m_dot_tes_cold_out = m_dot_tes_cold_in = std::numeric_limits::quiet_NaN(); + double m_dot_field_to_cycle, m_dot_cycle_to_field; + m_dot_field_to_cycle = m_dot_cycle_to_field = std::numeric_limits::quiet_NaN(); + if (ms_params.tanks_in_parallel) + { + // Receiver bypass is possible in a parallel configuration, + // but need to determine if it actually makes sense and how to model it + if (m_dot_cr_to_cv_cold != 0.0) { + throw(C_csp_exception("Receiver output to cold tank not allowed in parallel TES configuration")); + } + m_dot_cr_to_tes_cold = 0.0; - double q_dot_heater = std::numeric_limits::quiet_NaN(); //[MWe] Heating power required to keep tanks at a minimum temperature - double m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); //[kg/s] Hot tank mass flow rate, valid for direct and indirect systems - double W_dot_rhtf_pump = std::numeric_limits::quiet_NaN(); //[MWe] Pumping power, just for tank-to-tank in indirect storage - double q_dot_loss = std::numeric_limits::quiet_NaN(); //[MWt] Storage thermal losses - double q_dot_dc_to_htf = std::numeric_limits::quiet_NaN(); //[MWt] Thermal power to the HTF from storage - double q_dot_ch_from_htf = std::numeric_limits::quiet_NaN(); //[MWt] Thermal power from the HTF to storage - double T_hot_ave = std::numeric_limits::quiet_NaN(); //[K] Average hot tank temperature over timestep - double T_cold_ave = std::numeric_limits::quiet_NaN(); //[K] Average cold tank temperature over timestep - double T_hot_final = std::numeric_limits::quiet_NaN(); //[K] Hot tank temperature at end of timestep - double T_cold_final = std::numeric_limits::quiet_NaN(); //[K] Cold tank temperature at end of timestep + if (m_dot_cr_to_cv_hot >= m_dot_cv_hot_to_cycle) + { + m_dot_cr_to_tes_hot = m_dot_cr_to_cv_hot - m_dot_cv_hot_to_cycle; //[kg/s] + m_dot_tes_hot_out = 0.0; //[kg/s] + m_dot_pc_to_tes_cold = 0.0; //[kg/s] + m_dot_tes_cold_out = m_dot_cr_to_tes_hot; //[kg/s] + m_dot_field_to_cycle = m_dot_cv_hot_to_cycle; //[kg/s] + m_dot_cycle_to_field = m_dot_cv_hot_to_cycle; //[kg/s] + } + else + { + m_dot_cr_to_tes_hot = 0.0; //[kg/s] + m_dot_tes_hot_out = m_dot_cv_hot_to_cycle - m_dot_cr_to_cv_hot; //[kg/s] + m_dot_pc_to_tes_cold = m_dot_tes_hot_out; //[kg/s] + m_dot_tes_cold_out = 0.0; //[kg/s] + m_dot_field_to_cycle = m_dot_cr_to_cv_hot; //[kg/s] + m_dot_cycle_to_field = m_dot_cr_to_cv_hot; //[kg/s] + } + m_dot_tes_cold_in = m_dot_pc_to_tes_cold; + } + else + { // Serial configuration + if (ms_params.m_is_hx) + { + throw(C_csp_exception("Serial operation of C_csp_two_tank_tes not available if there is a storage HX")); + } + m_dot_cr_to_tes_hot = m_dot_cr_to_cv_hot; //[kg/s] + m_dot_cr_to_tes_cold = m_dot_cr_to_cv_cold; //[kg/s] + m_dot_tes_hot_out = m_dot_cv_hot_to_cycle; //[kg/s] + m_dot_pc_to_tes_cold = m_dot_cv_hot_to_cycle; //[kg/s] + m_dot_tes_cold_out = m_dot_cr_to_cv_hot + m_dot_cr_to_cv_cold; //[kg/s] + m_dot_tes_cold_in = m_dot_total_to_cv_cold; //[kg/s] + m_dot_field_to_cycle = 0.0; //[kg/s] + m_dot_cycle_to_field = 0.0; //[kg/s] + } - if (ms_params.tanks_in_parallel) + double q_dot_heater = std::numeric_limits::quiet_NaN(); //[MWe] Heating power required to keep tanks at a minimum temperature + double m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); //[kg/s] Hot tank mass flow rate, valid for direct and indirect systems + double W_dot_rhtf_pump = std::numeric_limits::quiet_NaN(); //[MWe] Pumping power, just for tank-to-tank in indirect storage + double q_dot_loss = std::numeric_limits::quiet_NaN(); //[MWt] Storage thermal losses + double q_dot_dc_to_htf = std::numeric_limits::quiet_NaN(); //[MWt] Thermal power to the HTF from storage + double q_dot_ch_from_htf = std::numeric_limits::quiet_NaN(); //[MWt] Thermal power from the HTF to storage + double T_hot_ave = std::numeric_limits::quiet_NaN(); //[K] Average hot tank temperature over timestep + double T_cold_ave = std::numeric_limits::quiet_NaN(); //[K] Average cold tank temperature over timestep + double T_hot_final = std::numeric_limits::quiet_NaN(); //[K] Hot tank temperature at end of timestep + double T_cold_final = std::numeric_limits::quiet_NaN(); //[K] Cold tank temperature at end of timestep + + if (ms_params.tanks_in_parallel) { - if (m_dot_field >= m_dot_cycle) // Charging + if (m_dot_cr_to_cv_hot >= m_dot_cv_hot_to_cycle) // Charging { - T_cycle_htf_in_hot = T_field_htf_out_hot; //[K] - double m_dot_tes_ch = m_dot_field - m_dot_cycle; //[kg/s] + T_cycle_htf_in_hot = T_cr_out_hot; //[K] + double m_dot_tes_ch = m_dot_cr_to_cv_hot - m_dot_cv_hot_to_cycle; //[kg/s] double T_htf_tes_cold = std::numeric_limits::quiet_NaN(); //[K] bool ch_solved = charge(timestep, T_amb, m_dot_tes_ch, - T_field_htf_out_hot, + T_cr_out_hot, T_htf_tes_cold, q_dot_heater, m_dot_cold_tank_to_hot_tank, W_dot_rhtf_pump, - q_dot_loss, q_dot_dc_to_htf, q_dot_ch_from_htf, - T_hot_ave, T_cold_ave, T_hot_final, T_cold_final); + q_dot_loss, q_dot_dc_to_htf, q_dot_ch_from_htf, + T_hot_ave, T_cold_ave, T_hot_final, T_cold_final); // Check if TES.charge method solved if (!ch_solved) @@ -1134,30 +1224,30 @@ int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_am } // Enthalpy balance to calculate T_htf_cold to CR - if (m_dot_field == 0.0) + if (m_dot_cr_to_cv_hot == 0.0) { - T_field_htf_in_cold = T_htf_tes_cold; //[K] + T_cr_in_cold = T_htf_tes_cold; //[K] } else { - T_field_htf_in_cold = (m_dot_tes_ch*T_htf_tes_cold + m_dot_cycle * T_cycle_htf_out_cold) / m_dot_field; //[K] - } + T_cr_in_cold = (m_dot_tes_ch*T_htf_tes_cold + m_dot_cv_hot_to_cycle*T_cycle_out_cold) / m_dot_cr_to_cv_hot; //[K] + } } else // Discharging { - T_field_htf_in_cold = T_cycle_htf_out_cold; //[K] - double m_dot_tes_dc = m_dot_cycle - m_dot_field; //[kg/s] + T_cr_in_cold = T_cycle_out_cold; //[K] + double m_dot_tes_dc = m_dot_cv_hot_to_cycle - m_dot_cr_to_cv_hot; //[kg/s] double T_htf_tes_hot = std::numeric_limits::quiet_NaN(); bool is_tes_success = discharge(timestep, T_amb, m_dot_tes_dc, - T_cycle_htf_out_cold, + T_cycle_out_cold, T_htf_tes_hot, - q_dot_heater, m_dot_cold_tank_to_hot_tank, W_dot_rhtf_pump, - q_dot_loss, q_dot_dc_to_htf, q_dot_ch_from_htf, - T_hot_ave, T_cold_ave, T_hot_final, T_cold_final); + q_dot_heater, m_dot_cold_tank_to_hot_tank, W_dot_rhtf_pump, + q_dot_loss, q_dot_dc_to_htf, q_dot_ch_from_htf, + T_hot_ave, T_cold_ave, T_hot_final, T_cold_final); - m_dot_cold_tank_to_hot_tank *= -1.0; + m_dot_cold_tank_to_hot_tank *= -1.0; // Check if discharge method solved if (!is_tes_success) @@ -1165,7 +1255,7 @@ int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_am return -4; } - T_cycle_htf_in_hot = (m_dot_tes_dc*T_htf_tes_hot + m_dot_field * T_field_htf_out_hot) / m_dot_cycle; //[K] + T_cycle_htf_in_hot = (m_dot_tes_dc*T_htf_tes_hot + m_dot_cr_to_cv_hot*T_cr_out_hot) / m_dot_cv_hot_to_cycle; //[K] } } else // Serial tank operation @@ -1176,19 +1266,20 @@ int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_am } // Inputs are: - // 1) Mass flow rate of HTF through the field - // 2) Mass flow rate of HTF - // 3) Temperature of HTF leaving field and entering hot tank - // 4) Temperature of HTF leaving the power cycle and entering the cold tank + // 1) Mass flow rate of HTF from field to hot tank + // 2) Mass flow rate of HTF from field to cold tank + // 3) Mass flow rate of HTF from hot tank to cycle + // 4) Temperature of HTF leaving field and entering hot tank + // 5) Temperature of HTF leaving the power cycle and entering the cold tank - double q_dot_ch_est, m_dot_tes_ch_max, T_cold_to_field_est; - q_dot_ch_est = m_dot_tes_ch_max = T_cold_to_field_est = std::numeric_limits::quiet_NaN(); - charge_avail_est(T_field_htf_out_hot, timestep, q_dot_ch_est, m_dot_tes_ch_max, T_cold_to_field_est); + double q_dot_ch_est, m_dot_tes_ch_max, T_cold_to_field_est; + q_dot_ch_est = m_dot_tes_ch_max = T_cold_to_field_est = std::numeric_limits::quiet_NaN(); + charge_avail_est(T_cr_out_hot, timestep, q_dot_ch_est, m_dot_tes_ch_max, T_cold_to_field_est); - if (m_dot_field > m_dot_cycle && std::max(1.E-4,(m_dot_field - m_dot_cycle)) > 1.0001*std::max(1.E-4,m_dot_tes_ch_max)) + if (m_dot_cr_to_cv_hot > m_dot_cv_hot_to_cycle && std::max(1.E-4, (m_dot_cr_to_cv_hot - m_dot_cv_hot_to_cycle)) > 1.0001 * std::max(1.E-4, m_dot_tes_ch_max)) { q_dot_heater = std::numeric_limits::quiet_NaN(); - m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); + m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); W_dot_rhtf_pump = std::numeric_limits::quiet_NaN(); q_dot_loss = std::numeric_limits::quiet_NaN(); q_dot_dc_to_htf = std::numeric_limits::quiet_NaN(); @@ -1201,14 +1292,16 @@ int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_am return -1; } - double q_dot_dc_est, m_dot_tes_dc_max, T_hot_to_pc_est; - q_dot_dc_est = m_dot_tes_dc_max = T_hot_to_pc_est = std::numeric_limits::quiet_NaN(); - discharge_avail_est(T_cycle_htf_out_cold, timestep, q_dot_dc_est, m_dot_tes_dc_max, T_hot_to_pc_est); + double q_dot_dc_est, m_dot_tes_dc_max, T_hot_to_pc_est; + q_dot_dc_est = m_dot_tes_dc_max = T_hot_to_pc_est = std::numeric_limits::quiet_NaN(); + // Use temperature downstream of cycle-out and cr-to-cold-tank mixer + discharge_avail_est(T_htf_cold_cv_in, timestep, q_dot_dc_est, m_dot_tes_dc_max, T_hot_to_pc_est); - if (m_dot_cycle > m_dot_field && std::max(1.E-4,(m_dot_cycle - m_dot_field)) > 1.0001*std::max(1.E-4,m_dot_tes_dc_max)) + // If mass flow into the cold tank *from the cycle* is greater than mass flow going from cold tank to field to hot tank + if (m_dot_cv_hot_to_cycle > m_dot_cr_to_cv_hot && std::max(1.E-4, (m_dot_cv_hot_to_cycle - m_dot_cr_to_cv_hot)) > 1.0001 * std::max(1.E-4, m_dot_tes_dc_max)) { q_dot_heater = std::numeric_limits::quiet_NaN(); - m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); + m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); W_dot_rhtf_pump = std::numeric_limits::quiet_NaN(); q_dot_loss = std::numeric_limits::quiet_NaN(); q_dot_dc_to_htf = std::numeric_limits::quiet_NaN(); @@ -1221,78 +1314,78 @@ int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_am return -2; } - // serial operation constrained to direct configuration, so HTF leaving TES must pass through another plant component - m_dot_cold_tank_to_hot_tank = 0.0; //[kg/s] + // serial operation constrained to direct configuration, so HTF leaving TES must pass through another plant component + m_dot_cold_tank_to_hot_tank = 0.0; //[kg/s] double q_heater_hot, q_dot_loss_hot, q_heater_cold, q_dot_loss_cold; q_heater_hot = q_dot_loss_hot = q_heater_cold = q_dot_loss_cold = std::numeric_limits::quiet_NaN(); // Call energy balance on hot tank discharge to get average outlet temperature over timestep - mc_hot_tank.energy_balance(timestep, m_dot_field, m_dot_cycle, T_field_htf_out_hot, T_amb, + mc_hot_tank.energy_balance(timestep, m_dot_cr_to_cv_hot, m_dot_cv_hot_to_cycle, + T_cr_out_hot, T_amb, T_cycle_htf_in_hot, q_heater_hot, q_dot_loss_hot); // Call energy balance on cold tank charge to track tank mass and temperature - mc_cold_tank.energy_balance(timestep, m_dot_cycle, m_dot_field, T_cycle_htf_out_cold, T_amb, - T_field_htf_in_cold, q_heater_cold, q_dot_loss_cold); + // Use mass flow and temperature downstream of cycle-out and cr-to-cold-tank mixer + mc_cold_tank.energy_balance(timestep, m_dot_total_to_cv_cold, m_dot_cv_cold_to_cr, + T_htf_cold_cv_in, T_amb, + T_cr_in_cold, q_heater_cold, q_dot_loss_cold); // Set output structure q_dot_heater = q_heater_cold + q_heater_hot; //[MWt] - double m_dot_tes_abs_net = fabs(m_dot_cycle - m_dot_field); //[kg/s] W_dot_rhtf_pump = 0; //[MWe] Tank-to-tank pumping power q_dot_loss = q_dot_loss_cold + q_dot_loss_hot; //[MWt] q_dot_ch_from_htf = 0.0; //[MWt] T_hot_ave = T_cycle_htf_in_hot; //[K] - T_cold_ave = T_field_htf_in_cold; //[K] + T_cold_ave = T_cr_in_cold; //[K] T_hot_final = mc_hot_tank.get_m_T_calc(); //[K] T_cold_final = mc_cold_tank.get_m_T_calc(); //[K] // Net TES discharge - double q_dot_tes_net_discharge = m_cp_field_avg * (m_dot_tes_hot_out * T_hot_ave + m_dot_tes_cold_out * T_cold_ave - - m_dot_cr_to_tes_hot * T_field_htf_out_hot - m_dot_pc_to_tes_cold * T_cycle_htf_out_cold) / 1000.0; //[MWt] + double q_dot_tes_net_discharge = m_cp_field_avg*(m_dot_tes_hot_out*T_hot_ave + m_dot_tes_cold_out*T_cold_ave - + m_dot_cr_to_tes_hot*T_cr_out_hot - m_dot_total_to_cv_cold*T_htf_cold_cv_in) / 1000.0; //[MWt] - if (m_dot_cycle >= m_dot_field) + if (m_dot_cv_hot_to_cycle >= m_dot_cr_to_cv_hot) { - //double T_htf_ave = 0.5*(T_cycle_htf_in_hot + T_cycle_htf_out_cold); //[K] - //double cp_htf_ave = mc_field_htfProps.Cp(T_htf_ave); //[kJ/kg-K] - //q_dot_dc_to_htf = (m_dot_cycle - m_dot_field) * cp_htf_ave*(T_cycle_htf_in_hot - T_cycle_htf_out_cold) / 1000.0; //[MWt] q_dot_ch_from_htf = 0.0; - q_dot_dc_to_htf = q_dot_tes_net_discharge; //[MWt] + q_dot_dc_to_htf = q_dot_tes_net_discharge; //[MWt] } else { - //double T_htf_ave = 0.5*(T_field_htf_out_hot + T_field_htf_in_cold); //[K] - //double cp_htf_ave = mc_field_htfProps.Cp(T_htf_ave); //[kJ/kg-K] q_dot_dc_to_htf = 0.0; - //q_dot_ch_from_htf = (m_dot_field - m_dot_cycle) * cp_htf_ave*(T_field_htf_out_hot - T_field_htf_in_cold) / 1000.0; //[MWt] - q_dot_ch_from_htf = -q_dot_tes_net_discharge; //[MWt] + q_dot_ch_from_htf = -q_dot_tes_net_discharge; //[MWt] } } - s_outputs.m_q_heater = q_dot_heater; - s_outputs.m_q_dot_dc_to_htf = q_dot_dc_to_htf; - s_outputs.m_q_dot_ch_from_htf = q_dot_ch_from_htf; + s_outputs.m_q_heater = q_dot_heater; + s_outputs.m_q_dot_dc_to_htf = q_dot_dc_to_htf; + s_outputs.m_q_dot_ch_from_htf = q_dot_ch_from_htf; - s_outputs.m_m_dot_cr_to_tes_hot = m_dot_cr_to_tes_hot; //[kg/s] - s_outputs.m_m_dot_tes_hot_out = m_dot_tes_hot_out; //[kg/s] - s_outputs.m_m_dot_pc_to_tes_cold = m_dot_pc_to_tes_cold; //[kg/s] - s_outputs.m_m_dot_tes_cold_out = m_dot_tes_cold_out; //[kg/s] - s_outputs.m_m_dot_field_to_cycle = m_dot_field_to_cycle; //[kg/s] - s_outputs.m_m_dot_cycle_to_field = m_dot_cycle_to_field; //[kg/s] + s_outputs.m_m_dot_cr_to_tes_hot = m_dot_cr_to_tes_hot; //[kg/s] + s_outputs.m_m_dot_cr_to_tes_cold = m_dot_cr_to_tes_cold; //[kg/s] + s_outputs.m_m_dot_tes_hot_out = m_dot_tes_hot_out; //[kg/s] + s_outputs.m_m_dot_pc_to_tes_cold = m_dot_pc_to_tes_cold; //[kg/s] + s_outputs.m_m_dot_tes_cold_out = m_dot_tes_cold_out; //[kg/s] + s_outputs.m_m_dot_tes_cold_in = m_dot_tes_cold_in; //[kg/s] + s_outputs.m_m_dot_field_to_cycle = m_dot_field_to_cycle; //[kg/s] + s_outputs.m_m_dot_cycle_to_field = m_dot_cycle_to_field; //[kg/s] - s_outputs.m_m_dot_cold_tank_to_hot_tank = m_dot_cold_tank_to_hot_tank; + s_outputs.m_T_tes_cold_in = T_htf_cold_cv_in; //[K] - mc_reported_outputs.value(E_Q_DOT_LOSS, q_dot_loss); //[MWt] - mc_reported_outputs.value(E_W_DOT_HEATER, q_dot_heater); //[MWt] - mc_reported_outputs.value(E_TES_T_HOT, T_hot_final - 273.15); //[C] - mc_reported_outputs.value(E_TES_T_COLD, T_cold_final - 273.15); //[C] - mc_reported_outputs.value(E_M_DOT_TANK_TO_TANK, m_dot_cold_tank_to_hot_tank); //[kg/s] - mc_reported_outputs.value(E_MASS_COLD_TANK, mc_cold_tank.get_m_m_calc()); //[kg] - mc_reported_outputs.value(E_MASS_HOT_TANK, mc_hot_tank.get_m_m_calc()); //[kg] + s_outputs.m_m_dot_cold_tank_to_hot_tank = m_dot_cold_tank_to_hot_tank; + + mc_reported_outputs.value(E_Q_DOT_LOSS, q_dot_loss); //[MWt] + mc_reported_outputs.value(E_W_DOT_HEATER, q_dot_heater); //[MWt] + mc_reported_outputs.value(E_TES_T_HOT, T_hot_final - 273.15); //[C] + mc_reported_outputs.value(E_TES_T_COLD, T_cold_final - 273.15); //[C] + mc_reported_outputs.value(E_M_DOT_TANK_TO_TANK, m_dot_cold_tank_to_hot_tank); //[kg/s] + mc_reported_outputs.value(E_MASS_COLD_TANK, mc_cold_tank.get_m_m_calc()); //[kg] + mc_reported_outputs.value(E_MASS_HOT_TANK, mc_hot_tank.get_m_m_calc()); //[kg] return 0; } @@ -1729,7 +1822,10 @@ void C_csp_two_tank_tes::converged() mc_cold_tank.converged(); mc_hot_tank.converged(); //mc_hx.converged(); - + + // Set reported cycle converged values + mc_reported_outputs.value(E_HOT_TANK_HTF_PERC_FINAL, mc_hot_tank.get_mass_avail() / m_mass_total_active * 100.0); + mc_reported_outputs.set_timestep_outputs(); // The max charge and discharge flow rates should be set at the beginning of each timestep @@ -1737,6 +1833,13 @@ void C_csp_two_tank_tes::converged() // m_m_dot_tes_dc_max = m_m_dot_tes_ch_max = std::numeric_limits::quiet_NaN(); } +void C_csp_two_tank_tes::get_final_from_converged(double& f_V_hot, double& T_hot_tank /*K*/, double& T_cold_tank /*K*/) +{ + f_V_hot = mc_hot_tank.get_mass_avail() / m_mass_total_active; //[-] + T_hot_tank = mc_hot_tank.get_m_T_prev(); //[K] + T_cold_tank = mc_cold_tank.get_m_T_prev(); //[K] +} + void C_csp_two_tank_tes::write_output_intervals(double report_time_start, const std::vector& v_temp_ts_time_end, double report_time_end) { @@ -2308,6 +2411,8 @@ double C_csp_cold_tes::get_degradation_rate() return e_loss / (m_q_pb_design * ms_params.m_ts_hours * 3600.); //s^-1 -- fraction of heat loss per second based on full charge } +void C_csp_cold_tes::reset_storage_to_initial_state() {} + void C_csp_cold_tes::discharge_avail_est(double T_cold_K, double step_s, double &q_dot_dc_est, double &m_dot_field_est, double &T_hot_field_est) { double f_storage = 0.0; // for now, hardcode such that storage always completely discharges diff --git a/tcs/csp_solver_two_tank_tes.h b/tcs/csp_solver_two_tank_tes.h index ee71ca86e..ceb5cc392 100644 --- a/tcs/csp_solver_two_tank_tes.h +++ b/tcs/csp_solver_two_tank_tes.h @@ -102,6 +102,8 @@ class C_storage_tank double get_vol_frac(); + double get_mass_avail(); //[kg] + void init(HTFProperties htf_class_in, double V_tank /*m3*/, double h_tank /*m*/, double h_min /*m*/, double u_tank /*W/m2-K*/, double tank_pairs /*-*/, double T_htr /*K*/, double max_q_htr /*MWt*/, @@ -110,7 +112,7 @@ class C_storage_tank double m_dot_available(double f_unavail, double timestep); - void energy_balance(double timestep /*s*/, double m_dot_in, double m_dot_out, + void energy_balance(double timestep /*s*/, double m_dot_in /*kg/s*/, double m_dot_out /*kg/s*/, double T_in /*K*/, double T_amb /*K*/, double &T_ave /*K*/, double &q_heater /*MW*/, double &q_dot_loss /*MW*/); @@ -141,10 +143,12 @@ class C_csp_two_tank_tes : public C_csp_tes // Member data bool m_is_tes; + bool m_is_cr_to_cold_tank_allowed; double m_vol_tank; //[m3] volume of *one temperature*, i.e. vol_tank = total cold storage = total hot storage double m_V_tank_active; //[m^3] available volume (considering h_min) of *one temperature* double m_q_pb_design; //[Wt] thermal power to power cycle at design double m_V_tank_hot_ini; //[m^3] Initial volume in hot storage tank + double m_mass_total_active; //[kg] Total HTF mass at design point inlet/outlet T double m_cp_field_avg; //[kJ/kg-K] @@ -164,7 +168,8 @@ class C_csp_two_tank_tes : public C_csp_tes E_TES_T_COLD, //[C] TES final cold tank temperature E_M_DOT_TANK_TO_TANK, //[kg/s] Tank to tank mass flow rate (indirect TES) E_MASS_COLD_TANK, //[kg] Mass in cold tank at end of timestep - E_MASS_HOT_TANK //[kg] Mass in hot tank at end of timestep + E_MASS_HOT_TANK, //[kg] Mass in hot tank at end of timestep + E_HOT_TANK_HTF_PERC_FINAL //[%] Final percent fill of available hot tank mass }; C_csp_reported_outputs mc_reported_outputs; @@ -266,6 +271,8 @@ class C_csp_two_tank_tes : public C_csp_tes virtual bool does_tes_exist(); + virtual bool is_cr_to_cold_allowed(); + virtual double get_hot_temp(); virtual double get_cold_temp(); @@ -280,6 +287,8 @@ class C_csp_two_tank_tes : public C_csp_tes virtual double get_degradation_rate(); // s^-1 + virtual void reset_storage_to_initial_state(); + virtual void discharge_avail_est(double T_cold_K, double step_s, double &q_dot_dc_est /*MWt*/, double &m_dot_field_est /*kg/s*/, double &T_hot_field_est /*K*/); @@ -293,9 +302,10 @@ class C_csp_two_tank_tes : public C_csp_tes double & q_dot_loss /*MWt*/, double & q_dot_dc_to_htf /*MWt*/, double & q_dot_ch_from_htf /*MWt*/, double & T_hot_ave /*K*/, double & T_cold_ave /*K*/, double & T_hot_final /*K*/, double & T_cold_final /*K*/); - virtual int solve_tes_off_design(double timestep /*s*/, double T_amb /*K*/, double m_dot_field /*kg/s*/, double m_dot_cycle /*kg/s*/, - double T_field_htf_out_hot /*K*/, double T_cycle_htf_out_cold /*K*/, - double & T_cycle_htf_in_hot /*K*/, double & T_field_htf_in_cold /*K*/, + virtual int solve_tes_off_design(double timestep /*s*/, double T_amb /*K*/, + double m_dot_cr_to_cv_hot /*kg/s*/, double m_dot_cv_hot_to_cycle /*kg/s*/, double m_dot_cr_to_cv_cold /*kg/s*/, + double T_cr_out_hot /*K*/, double T_cycle_out_cold /*K*/, + double & T_cycle_htf_in_hot /*K*/, double & T_cr_in_cold /*K*/, C_csp_tes::S_csp_tes_outputs& outputs); bool charge(double timestep /*s*/, double T_amb /*K*/, double m_dot_htf_in /*kg/s*/, @@ -306,6 +316,8 @@ class C_csp_two_tank_tes : public C_csp_tes virtual void converged(); + void get_final_from_converged(double& f_V_hot /*-*/, double& T_hot_tank /*K*/, double& T_cold_tank /*K*/); + virtual void write_output_intervals(double report_time_start, const std::vector& v_temp_ts_time_end, double report_time_end); @@ -521,6 +533,8 @@ class C_csp_cold_tes //Class for cold storage based on two tank tes ARD double get_degradation_rate(); // s^-1 + virtual void reset_storage_to_initial_state(); + void discharge_avail_est(double T_cold_K, double step_s, double &q_dot_dc_est, double &m_dot_field_est, double &T_hot_field_est); void charge_avail_est(double T_hot_K, double step_s, double &q_dot_ch_est, double &m_dot_field_est, double &T_cold_field_est); From 904192971032fd8378737b384cf430ce840b9764 Mon Sep 17 00:00:00 2001 From: Matthew Boyd Date: Fri, 5 Feb 2021 10:44:56 -0700 Subject: [PATCH 07/12] Update tes_lengths default handling --- ssc/cmod_trough_physical.cpp | 10 ++++++++-- tcs/csp_solver_two_tank_tes.cpp | 7 ------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/ssc/cmod_trough_physical.cpp b/ssc/cmod_trough_physical.cpp index 063d88a41..d60b29ca6 100644 --- a/ssc/cmod_trough_physical.cpp +++ b/ssc/cmod_trough_physical.cpp @@ -280,7 +280,7 @@ static var_info _cm_vtab_trough_physical[] = { { SSC_INPUT, SSC_NUMBER, "custom_tes_pipe_sizes", "Use custom TES pipe diams, wallthks, and lengths", "-", "", "controller", "*", "", "" }, { SSC_INPUT, SSC_MATRIX, "tes_diams", "Custom TES diameters", "m", "", "controller", "*", "", "" }, { SSC_INPUT, SSC_MATRIX, "tes_wallthicks", "Custom TES wall thicknesses", "m", "", "controller", "*", "", "" }, - { SSC_INPUT, SSC_MATRIX, "tes_lengths", "Custom TES lengths", "m", "", "controller", "*", "", "" }, + { SSC_INPUT, SSC_MATRIX, "tes_lengths", "Custom TES lengths", "m", "", "controller", "", "", "" }, { SSC_INPUT, SSC_NUMBER, "DP_SGS", "Pressure drop within the steam generator", "bar", "", "controller", "*", "", "" }, @@ -919,10 +919,16 @@ class cm_trough_physical : public compute_module tes->custom_tes_pipe_sizes = as_boolean("custom_tes_pipe_sizes"); //[-] tes->tes_diams = as_matrix("tes_diams"); //[m] tes->tes_wallthicks = as_matrix("tes_wallthicks"); //[m] - tes->tes_lengths = as_matrix("tes_lengths"); //[m] tes->calc_design_pipe_vals = as_boolean("calc_design_pipe_vals"); //[-] tes->pipe_rough = as_double("HDR_rough"); //[m] tes->DP_SGS = as_double("DP_SGS"); //[bar] + if (is_assigned("tes_lengths")) { + tes->tes_lengths = as_matrix("tes_lengths"); //[m] + } + if (!is_assigned("tes_lengths") || tes->tes_lengths.ncells() < 11) { + double vals1[11] = { 0., 90., 100., 120., 0., 30., 90., 80., 80., 120., 80. }; + tes->tes_lengths.assign(vals1, 11); + } // Set storage outputs storage.mc_reported_outputs.assign(C_csp_two_tank_tes::E_Q_DOT_LOSS, allocate("tank_losses", n_steps_fixed), n_steps_fixed); diff --git a/tcs/csp_solver_two_tank_tes.cpp b/tcs/csp_solver_two_tank_tes.cpp index 43e50ee03..b4947a66e 100644 --- a/tcs/csp_solver_two_tank_tes.cpp +++ b/tcs/csp_solver_two_tank_tes.cpp @@ -894,13 +894,6 @@ void C_csp_two_tank_tes::init(const C_csp_tes::S_csp_tes_init_inputs init_inputs ms_params.m_u_tank, ms_params.m_tank_pairs, ms_params.m_cold_tank_Thtr, ms_params.m_cold_tank_max_heat, V_cold_ini, T_cold_ini, ms_params.m_T_field_in_des); - // Size TES piping and output values - if (ms_params.tes_lengths.ncells() < 11) { - // set defaults - double vals1[11] = { 0., 90., 100., 120., 0., 0., 0., 0., 80., 120., 80. }; - ms_params.tes_lengths.assign(vals1, 11); - } - if (ms_params.custom_tes_pipe_sizes && (ms_params.tes_diams.ncells() != N_tes_pipe_sections || ms_params.tes_wallthicks.ncells() != N_tes_pipe_sections)) { From d41fde8dae3178f5f8cd3fc7103335dc18fb98e0 Mon Sep 17 00:00:00 2001 From: tyneises Date: Mon, 8 Feb 2021 09:50:38 -0600 Subject: [PATCH 08/12] use for csp tests kerrortolerancehi instead of low --- test/ssc_test/cmod_tcsdirect_steam_test.cpp | 48 +++---- .../cmod_tcsfresnel_molten_salt_test.cpp | 64 ++++----- test/ssc_test/cmod_tcsmolten_salt_test.cpp | 78 +++++------ .../cmod_tcstrough_empirical_test.cpp | 128 +++++++++--------- .../cmod_trough_physical_iph_test.cpp | 14 +- test/ssc_test/cmod_trough_physical_test.cpp | 18 +-- 6 files changed, 175 insertions(+), 175 deletions(-) diff --git a/test/ssc_test/cmod_tcsdirect_steam_test.cpp b/test/ssc_test/cmod_tcsdirect_steam_test.cpp index d5e9b97f3..f7781c4b3 100644 --- a/test/ssc_test/cmod_tcsdirect_steam_test.cpp +++ b/test/ssc_test/cmod_tcsdirect_steam_test.cpp @@ -15,14 +15,14 @@ NAMESPACE_TEST(csp_tower, SteamTowerCmod, Default_NoFinancial) int errors = steam_tower.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 263809742, kErrorToleranceLo); - EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 30.08, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 296630582, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2635, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 92.64, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 55716, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 263809742, kErrorToleranceHi); + EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 30.08, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 296630582, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2635, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 92.64, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 55716, kErrorToleranceHi); } } @@ -39,14 +39,14 @@ NAMESPACE_TEST(csp_tower, SteamTowerCmod, EvaporativeCondenser_NoFinancial) int errors = steam_tower.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 280975356, kErrorToleranceLo); - EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 32.03, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 307624737, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2806, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 95.14, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 893431, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 280975356, kErrorToleranceHi); + EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 32.03, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 307624737, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2806, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 95.14, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 893431, kErrorToleranceHi); } } @@ -63,14 +63,14 @@ NAMESPACE_TEST(csp_tower, SteamTowerCmod, HybridCondenser_NoFinancial) int errors = steam_tower.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 268116066, kErrorToleranceLo); - EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 30.57, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 304066728, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2678, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 91.85, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 55716, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 268116066, kErrorToleranceHi); + EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 30.57, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 304066728, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2678, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 91.85, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 55716, kErrorToleranceHi); } } diff --git a/test/ssc_test/cmod_tcsfresnel_molten_salt_test.cpp b/test/ssc_test/cmod_tcsfresnel_molten_salt_test.cpp index 036165f1d..1fced5be9 100644 --- a/test/ssc_test/cmod_tcsfresnel_molten_salt_test.cpp +++ b/test/ssc_test/cmod_tcsfresnel_molten_salt_test.cpp @@ -14,14 +14,14 @@ NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, Default_NoFinancial) int errors = power_fresnel.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 337249089, kErrorToleranceLo); - EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.50, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 372639466, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3372, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.27, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 30058, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 337249089, kErrorToleranceHi); + EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.50, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 372639466, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3372, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.27, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 30058, kErrorToleranceHi); } } @@ -35,14 +35,14 @@ NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, SequencedDefocusing_NoFinancial) int errors = power_fresnel.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 337249089, kErrorToleranceLo); - EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.50, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 372639466, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3372, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.27, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 30058, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 337249089, kErrorToleranceHi); + EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.50, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 372639466, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3372, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.27, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 30058, kErrorToleranceHi); } } @@ -60,14 +60,14 @@ NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, TherminolVp1Htf_NoFinancial) int errors = power_fresnel.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 336171001, kErrorToleranceLo); - EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.38, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 371306661, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3362, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.31, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 29944, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 336171001, kErrorToleranceHi); + EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.38, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 371306661, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3362, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.31, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 29944, kErrorToleranceHi); } } @@ -81,14 +81,14 @@ NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, SolarPositioinOpticalChar_NoFinanc int errors = power_fresnel.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 228344862, kErrorToleranceLo); - EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 26.07, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 255036717, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 2283, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 93.26, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 21776, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 228344862, kErrorToleranceHi); + EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 26.07, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 255036717, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 2283, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 93.26, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 21776, kErrorToleranceHi); } } diff --git a/test/ssc_test/cmod_tcsmolten_salt_test.cpp b/test/ssc_test/cmod_tcsmolten_salt_test.cpp index 48e00f90c..cdc9fa847 100644 --- a/test/ssc_test/cmod_tcsmolten_salt_test.cpp +++ b/test/ssc_test/cmod_tcsmolten_salt_test.cpp @@ -15,19 +15,19 @@ NAMESPACE_TEST(csp_tower, PowerTowerCmod, Default_NoFinancial) int errors = power_tower.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 63.02, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 638478912, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5521, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 89.55, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98402, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 571408807, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 63.02, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 638478912, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5521, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 89.55, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98402, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceHi); } //ssc_data_t defaults = singleowner_defaults(); @@ -48,19 +48,19 @@ NAMESPACE_TEST(csp_tower, PowerTowerCmod, SlidingPressure_NoFinancial) EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 578111750, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 63.76, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 645396296, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5586, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 89.57, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98238, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 578111750, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 63.76, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 645396296, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5586, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 89.57, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98238, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceHi); } } @@ -73,19 +73,19 @@ NAMESPACE_TEST(csp_tower, PowerTowerCmod, FlowPattern_NoFinancial) EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 519995603, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 57.35, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 642716926, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5024, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 80.90, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98678, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 519995603, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 57.35, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 642716926, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5024, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 80.90, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98678, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceHi); } } diff --git a/test/ssc_test/cmod_tcstrough_empirical_test.cpp b/test/ssc_test/cmod_tcstrough_empirical_test.cpp index ba5e008d1..e3a7551b4 100644 --- a/test/ssc_test/cmod_tcstrough_empirical_test.cpp +++ b/test/ssc_test/cmod_tcstrough_empirical_test.cpp @@ -14,14 +14,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, Default_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 344049128, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.31, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403814011, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3444, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.75, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 344049128, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.31, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403814011, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3444, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.75, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); } } @@ -37,14 +37,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, SolarSaltHtf_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 340377809, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 38.89, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 399556634, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3407, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.74, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 340377809, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 38.89, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 399556634, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3407, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.74, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); } } @@ -68,14 +68,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, EuroTrough_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 343687390, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.27, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 402926405, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3440, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.85, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 343687390, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.27, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 402926405, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3440, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.85, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); } } @@ -103,14 +103,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, LuzCermetHce_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 310891768, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 35.53, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 369630914, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3112, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 87.61, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 310891768, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 35.53, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 369630914, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3112, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 87.61, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); } } @@ -147,14 +147,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, PowerCycle_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 350313341, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 40.03, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 427283458, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3507, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 85.40, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 350313341, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 40.03, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 427283458, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3507, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 85.40, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); } } @@ -169,14 +169,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, TherminolHtf_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 343856219, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.29, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403443026, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3444, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.78, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 343856219, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.29, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403443026, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3444, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.78, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); } } @@ -196,14 +196,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, ParasiticElectric_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 357850265, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 40.89, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403814011, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3582, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 92.31, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 357850265, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 40.89, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403814011, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3582, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 92.31, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); } } @@ -219,14 +219,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, Phoenix_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 332549669, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 38.00, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 391115710, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3329, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.56, kErrorToleranceLo); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 332549669, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 38.00, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 391115710, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3329, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.56, kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); } } diff --git a/test/ssc_test/cmod_trough_physical_iph_test.cpp b/test/ssc_test/cmod_trough_physical_iph_test.cpp index 6ce20846c..9c4dc17be 100644 --- a/test/ssc_test/cmod_trough_physical_iph_test.cpp +++ b/test/ssc_test/cmod_trough_physical_iph_test.cpp @@ -14,12 +14,12 @@ NAMESPACE_TEST(csp_trough, HeatTroughCmod, Default_NoFinancial) int errors = heat_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_gross_energy"), 24328026, kErrorToleranceLo); - EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_energy"), 24327778, kErrorToleranceLo); - EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_electricity_consumption"), 93310, kErrorToleranceLo); - EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_thermal_consumption"), 247.67, kErrorToleranceLo); - EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_tes_freeze_protection"), 247.67, kErrorToleranceLo); - EXPECT_NEAR(heat_trough.GetOutput("annual_field_freeze_protection"), 0., kErrorToleranceLo); - EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_total_water_use"), 176.3, kErrorToleranceLo); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_gross_energy"), 24328026, kErrorToleranceHi); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_energy"), 24327778, kErrorToleranceHi); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_electricity_consumption"), 93310, kErrorToleranceHi); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_thermal_consumption"), 247.67, kErrorToleranceHi); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_tes_freeze_protection"), 247.67, kErrorToleranceHi); + EXPECT_NEAR(heat_trough.GetOutput("annual_field_freeze_protection"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_total_water_use"), 176.3, kErrorToleranceHi); } } diff --git a/test/ssc_test/cmod_trough_physical_test.cpp b/test/ssc_test/cmod_trough_physical_test.cpp index e5a11f701..ad44e1745 100644 --- a/test/ssc_test/cmod_trough_physical_test.cpp +++ b/test/ssc_test/cmod_trough_physical_test.cpp @@ -14,15 +14,15 @@ NAMESPACE_TEST(csp_trough, PowerTroughCmod, Default_NoFinancial) int errors = power_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_energy"), 369272759, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_thermal_consumption"), 596547, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_tes_freeze_protection"), 558505, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_field_freeze_protection"), 38042, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_trough.GetOutput("capacity_factor"), 42.20, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_W_cycle_gross"), 420379150, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_trough.GetOutput("kwh_per_kw"), 3696, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_trough.GetOutput("conversion_factor"), 87.84, kErrorToleranceLo); - EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_total_water_use"), 80708, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_energy"), 369272759, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_thermal_consumption"), 596547, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_tes_freeze_protection"), 558505, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_field_freeze_protection"), 38042, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_trough.GetOutput("capacity_factor"), 42.20, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_W_cycle_gross"), 420379150, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_trough.GetOutput("kwh_per_kw"), 3696, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_trough.GetOutput("conversion_factor"), 87.84, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_total_water_use"), 80708, kErrorToleranceHi); } //ssc_data_t defaults = singleowner_defaults(); From b85ab01ec484c1623cc670957da65fc572ceb2ad Mon Sep 17 00:00:00 2001 From: janinefreeman Date: Tue, 16 Feb 2021 09:14:33 -0700 Subject: [PATCH 09/12] updated pvsamv1 tests for additional feb 29 test --- test/ssc_test/cmod_pvsamv1_test.cpp | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/ssc_test/cmod_pvsamv1_test.cpp b/test/ssc_test/cmod_pvsamv1_test.cpp index bfaa330db..655c38650 100644 --- a/test/ssc_test/cmod_pvsamv1_test.cpp +++ b/test/ssc_test/cmod_pvsamv1_test.cpp @@ -795,3 +795,35 @@ TEST_F(CMPvsamv1PowerIntegration_cmod_pvsamv1, NonAnnualWithLeapDay) free_weatherdata_array(weather_data); } + +//test 8760 run that includes Feb 29 but not Dec 31 when loaded as "data" rather than weather file +TEST_F(CMPvsamv1PowerIntegration_cmod_pvsamv1, WeatherDataWithFeb29WithoutDec31) +{ + //set up a weather data array containing leap day and assign it to the solar resource data + const int length = 8760; + double month[length] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 }; + double day[length] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 }; + + var_data month_vd = var_data(month, length); + var_data day_vd = var_data(day, length); + + delete month; + delete day; + + auto weather_data = create_weatherdata_array(length); + weather_data->table.assign("month", month_vd); + weather_data->table.assign("day", day_vd); + + ssc_data_unassign(data, "solar_resource_file"); + ssc_data_set_table(data, "solar_resource_data", &weather_data->table); + + std::vector load(length, 1); + ssc_data_set_array(data, "load", &load[0], (int)load.size()); + + //run the tests + EXPECT_FALSE(run_module(data, "pvsamv1")); + + ssc_number_t annualEnergy; + annualEnergy = ssc_data_get_number(data, "annual_energy", &annualEnergy); + EXPECT_NEAR(annualEnergy, 9139, 1.0) << "Annual energy produced by 8760 with Feb29 without Dec 31"; +} From ae1d22d4afda39827f4ff61c88c97633947b9e4c Mon Sep 17 00:00:00 2001 From: janinefreeman Date: Wed, 17 Feb 2021 14:38:09 -0700 Subject: [PATCH 10/12] add tests for leap day in weather data --- ssc/common.cpp | 21 +++++++++++---- test/ssc_test/cmod_pvsamv1_test.cpp | 41 ++++++++++++++++------------- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/ssc/common.cpp b/ssc/common.cpp index ed6213eb7..f37b53a41 100644 --- a/ssc/common.cpp +++ b/ssc/common.cpp @@ -1222,19 +1222,27 @@ double shading_factor_calculator::dc_shade_factor() //HOWEVER, the year value may vary (i.e., TMY) so only checking month, day, hour, minute timesteps, not actual year vector bool weatherdata::check_continuous_single_year(bool leapyear) { + //first, set up some timestep variables int ts_per_hour = 0; //determine the number of timesteps in each hour if (leapyear) ts_per_hour = (int)(m_nRecords / 8784); else ts_per_hour = (int)(m_nRecords / 8760); double ts_min = 60. / ts_per_hour; //determine the number of minutes of each timestep + + //next, check if the data has leap day (feb 29). need to do this because some toold pass in 8760 data that contains feb 29 and not dec 31 + bool has_leapday = false; + int leapDayNoon = 1429 * ts_per_hour; //look for the index of noon on leap day. noon on leap day is hour 1429 of the year + if (this->m_data[leapDayNoon]->month == 2 && this->m_data[leapDayNoon]->day == 29) //check noon on what would be feb 29 if it's in the data + has_leapday = true; + + //last, go through each index in order and make sure that the timestamps all correspond to a single, serially complete year with even timesteps int idx = 0; // index to keep track of where we are in the timestamp vectors - // now, check that the month, hour, day, and minute vectors are consistent with a single, continuous year with an - // even timestep that starts on jan 1 and ends dec 31 for (int m = 1; m <= 12; m++) { int daymax = util::days_in_month(m - 1); - if (m == 2 && leapyear) daymax = 29; //make sure to account for leap day in Feb + if (m == 2 && has_leapday) daymax = 29; //make sure to account for leap day in Feb if it's in the data + if (m == 12 && has_leapday && !leapyear) daymax = 30; //if the data is 8760 but has Feb 29, then it won't have Dec 31 for (int d = 1; d <= daymax; d++) { for (int h = 0; h < 24; h++) @@ -1242,8 +1250,11 @@ bool weatherdata::check_continuous_single_year(bool leapyear) double min = this->m_data[idx]->minute; for (int tsph = 0; tsph < ts_per_hour; tsph++) { - min += tsph * ts_min; - //if any of the month, day, hour, or minute don't line up with what we've calculated, then it doesn't fit our criteria for a continuous year + //first check that the index isn't out of bounds + if (idx > m_nRecords - 1) + return false; + //if any of the month, day, hour, or minute don't line up with what we've calculated, then it doesn't fit our criteria for a continuous year + min += tsph * ts_min; if (this->m_data[idx]->month != m || this->m_data[idx]->day != d || this->m_data[idx]->hour != h || this->m_data[idx]->minute != min) return false; diff --git a/test/ssc_test/cmod_pvsamv1_test.cpp b/test/ssc_test/cmod_pvsamv1_test.cpp index 655c38650..45c928026 100644 --- a/test/ssc_test/cmod_pvsamv1_test.cpp +++ b/test/ssc_test/cmod_pvsamv1_test.cpp @@ -796,34 +796,37 @@ TEST_F(CMPvsamv1PowerIntegration_cmod_pvsamv1, NonAnnualWithLeapDay) } -//test 8760 run that includes Feb 29 but not Dec 31 when loaded as "data" rather than weather file -TEST_F(CMPvsamv1PowerIntegration_cmod_pvsamv1, WeatherDataWithFeb29WithoutDec31) +//a couple of 8760 weather data array tests, one base case and one that includes Feb 29 but not Dec 31 +TEST_F(CMPvsamv1PowerIntegration_cmod_pvsamv1, WeatherDataCases) { - //set up a weather data array containing leap day and assign it to the solar resource data + //set up a weather data array assign it to the solar resource data const int length = 8760; - double month[length] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 }; - double day[length] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 }; - - var_data month_vd = var_data(month, length); - var_data day_vd = var_data(day, length); - - delete month; - delete day; - auto weather_data = create_weatherdata_array(length); - weather_data->table.assign("month", month_vd); - weather_data->table.assign("day", day_vd); - ssc_data_unassign(data, "solar_resource_file"); ssc_data_set_table(data, "solar_resource_data", &weather_data->table); + //assign the required load variable std::vector load(length, 1); ssc_data_set_array(data, "load", &load[0], (int)load.size()); - //run the tests + //run a base case test EXPECT_FALSE(run_module(data, "pvsamv1")); - ssc_number_t annualEnergy; - annualEnergy = ssc_data_get_number(data, "annual_energy", &annualEnergy); - EXPECT_NEAR(annualEnergy, 9139, 1.0) << "Annual energy produced by 8760 with Feb29 without Dec 31"; + ssc_data_get_number(data, "annual_energy", &annualEnergy); + EXPECT_NEAR(annualEnergy, 4993.42, 1.0) << "Weather data base case test, annual energy produced by 8760 array"; + + //now change the weather data array to include Feb 29 but not Dec 31, so still 8760 in length + double month[length] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 }; + double day[length] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 }; + var_data month_vd = var_data(month, length); + var_data day_vd = var_data(day, length); + weather_data->table.assign("month", month_vd); + weather_data->table.assign("day", day_vd); + ssc_data_set_table(data, "solar_resource_data", &weather_data->table); + + //run this new case + EXPECT_FALSE(run_module(data, "pvsamv1")); + ssc_data_get_number(data, "annual_energy", &annualEnergy); + //annual energy should be a little different because the solar position angles are calculated at different times with the new dates, but not too different + EXPECT_NEAR(annualEnergy, 4990.15, 1.0) << "Annual energy produced by 8760 with Feb29 without Dec 31"; } From 6d4f58499ba53b40676ca1b703ff46eaabd1cd4a Mon Sep 17 00:00:00 2001 From: janinefreeman Date: Wed, 17 Feb 2021 14:39:23 -0700 Subject: [PATCH 11/12] Revert "Merge branch 'develop' into feb_29_hacky_fix" This reverts commit 4a0cd979dfa02fdb5bd4e8dfedf3b7104f7376f0. --- ssc/cmod_trough_physical.cpp | 10 +- tcs/csp_solver_core.cpp | 752 +++--------------- tcs/csp_solver_core.h | 115 +-- tcs/csp_solver_mono_eq_methods.cpp | 30 +- tcs/csp_solver_two_tank_tes.cpp | 370 ++++----- tcs/csp_solver_two_tank_tes.h | 24 +- test/ssc_test/cmod_tcsdirect_steam_test.cpp | 48 +- .../cmod_tcsfresnel_molten_salt_test.cpp | 64 +- test/ssc_test/cmod_tcsmolten_salt_test.cpp | 78 +- .../cmod_tcstrough_empirical_test.cpp | 128 +-- .../cmod_trough_physical_iph_test.cpp | 14 +- test/ssc_test/cmod_trough_physical_test.cpp | 18 +- 12 files changed, 443 insertions(+), 1208 deletions(-) diff --git a/ssc/cmod_trough_physical.cpp b/ssc/cmod_trough_physical.cpp index d60b29ca6..063d88a41 100644 --- a/ssc/cmod_trough_physical.cpp +++ b/ssc/cmod_trough_physical.cpp @@ -280,7 +280,7 @@ static var_info _cm_vtab_trough_physical[] = { { SSC_INPUT, SSC_NUMBER, "custom_tes_pipe_sizes", "Use custom TES pipe diams, wallthks, and lengths", "-", "", "controller", "*", "", "" }, { SSC_INPUT, SSC_MATRIX, "tes_diams", "Custom TES diameters", "m", "", "controller", "*", "", "" }, { SSC_INPUT, SSC_MATRIX, "tes_wallthicks", "Custom TES wall thicknesses", "m", "", "controller", "*", "", "" }, - { SSC_INPUT, SSC_MATRIX, "tes_lengths", "Custom TES lengths", "m", "", "controller", "", "", "" }, + { SSC_INPUT, SSC_MATRIX, "tes_lengths", "Custom TES lengths", "m", "", "controller", "*", "", "" }, { SSC_INPUT, SSC_NUMBER, "DP_SGS", "Pressure drop within the steam generator", "bar", "", "controller", "*", "", "" }, @@ -919,16 +919,10 @@ class cm_trough_physical : public compute_module tes->custom_tes_pipe_sizes = as_boolean("custom_tes_pipe_sizes"); //[-] tes->tes_diams = as_matrix("tes_diams"); //[m] tes->tes_wallthicks = as_matrix("tes_wallthicks"); //[m] + tes->tes_lengths = as_matrix("tes_lengths"); //[m] tes->calc_design_pipe_vals = as_boolean("calc_design_pipe_vals"); //[-] tes->pipe_rough = as_double("HDR_rough"); //[m] tes->DP_SGS = as_double("DP_SGS"); //[bar] - if (is_assigned("tes_lengths")) { - tes->tes_lengths = as_matrix("tes_lengths"); //[m] - } - if (!is_assigned("tes_lengths") || tes->tes_lengths.ncells() < 11) { - double vals1[11] = { 0., 90., 100., 120., 0., 30., 90., 80., 80., 120., 80. }; - tes->tes_lengths.assign(vals1, 11); - } // Set storage outputs storage.mc_reported_outputs.assign(C_csp_two_tank_tes::E_Q_DOT_LOSS, allocate("tank_losses", n_steps_fixed), n_steps_fixed); diff --git a/tcs/csp_solver_core.cpp b/tcs/csp_solver_core.cpp index 267ae4981..18db41fcf 100644 --- a/tcs/csp_solver_core.cpp +++ b/tcs/csp_solver_core.cpp @@ -87,21 +87,7 @@ std::string C_csp_solver::tech_operating_modes_str[] = "CR_DF__PC_SU__TES_FULL__AUX_OFF", - "CR_DF__PC_SU__TES_OFF__AUX_OFF", - - "CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF", - - "CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF", - - "CR_TO_COLD__PC_SB__TES_DC__AUX_OFF", - - "CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF", - - "CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF", - - "SKIP_40", - - "CR_TO_COLD__PC_SU__TES_DC__AUX_OFF" + "CR_DF__PC_SU__TES_OFF__AUX_OFF" }; void C_timestep_fixed::init(double time_start /*s*/, double step /*s*/) @@ -220,10 +206,8 @@ static C_csp_reported_outputs::S_output_info S_solver_output_info[] = {C_csp_solver::C_solver_outputs::PRICING_MULT, C_csp_reported_outputs::TS_1ST}, //[-] PPA price multiplier {C_csp_solver::C_solver_outputs::PC_Q_DOT_SB, C_csp_reported_outputs::TS_1ST}, //[MWt] PC required standby thermal power {C_csp_solver::C_solver_outputs::PC_Q_DOT_MIN, C_csp_reported_outputs::TS_1ST}, //[MWt] PC required min thermal power - {C_csp_solver::C_solver_outputs::PC_Q_DOT_TARGET, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[MWt] PC target thermal power - {C_csp_solver::C_solver_outputs::PC_Q_DOT_MAX, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[MWt] PC allowable max thermal power - {C_csp_solver::C_solver_outputs::PC_Q_DOT_TARGET_SU, C_csp_reported_outputs::TS_MAX}, //[MWt] PC target thermal power for startup - {C_csp_solver::C_solver_outputs::PC_Q_DOT_TARGET_ON, C_csp_reported_outputs::TS_MAX}, //[MWt] PC target thermal power for startup + {C_csp_solver::C_solver_outputs::PC_Q_DOT_TARGET, C_csp_reported_outputs::TS_1ST}, //[MWt] PC target thermal power + {C_csp_solver::C_solver_outputs::PC_Q_DOT_MAX, C_csp_reported_outputs::TS_1ST}, //[MWt] PC allowable max thermal power {C_csp_solver::C_solver_outputs::CTRL_IS_REC_SU, C_csp_reported_outputs::TS_1ST}, //[-] Control decision: is receiver startup allowed? {C_csp_solver::C_solver_outputs::CTRL_IS_PC_SU, C_csp_reported_outputs::TS_1ST}, //[-] Control decision: is power cycle startup allowed? {C_csp_solver::C_solver_outputs::CTRL_IS_PC_SB, C_csp_reported_outputs::TS_1ST}, //[-] Control decision: is power cycle standby allowed? @@ -270,14 +254,11 @@ static C_csp_reported_outputs::S_output_info S_solver_output_info[] = {C_csp_solver::C_solver_outputs::TES_Q_DOT_DC, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[MWt] TES discharge thermal power {C_csp_solver::C_solver_outputs::TES_Q_DOT_CH, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[MWt] TES charge thermal power {C_csp_solver::C_solver_outputs::TES_E_CH_STATE, C_csp_reported_outputs::TS_LAST}, //[MWht] TES charge state at the end of the time step - {C_csp_solver::C_solver_outputs::TES_T_COLD_IN, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[MWt] Inlet temperature to cold TES - + {C_csp_solver::C_solver_outputs::M_DOT_CR_TO_TES_HOT, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] - {C_csp_solver::C_solver_outputs::M_DOT_CR_TO_TES_COLD, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] {C_csp_solver::C_solver_outputs::M_DOT_TES_HOT_OUT, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] {C_csp_solver::C_solver_outputs::M_DOT_PC_TO_TES_COLD, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] {C_csp_solver::C_solver_outputs::M_DOT_TES_COLD_OUT, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] - {C_csp_solver::C_solver_outputs::M_DOT_TES_COLD_IN, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] {C_csp_solver::C_solver_outputs::M_DOT_FIELD_TO_CYCLE, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] {C_csp_solver::C_solver_outputs::M_DOT_CYCLE_TO_FIELD, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[kg/s] @@ -422,13 +403,6 @@ void C_csp_solver::reset_hierarchy_logic() m_is_CR_DF__PC_SU__TES_FULL__AUX_OFF_avail = true; m_is_CR_DF__PC_SU__TES_OFF__AUX_OFF_avail = true; - - m_is_CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF_avail = true; - m_is_CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF_avail = true; - m_is_CR_TO_COLD__PC_SB__TES_DC__AUX_OFF_avail = true; - m_is_CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF_avail = true; - m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail = true; - m_is_CR_TO_COLD__PC_SU__TES_DC__AUX_OFF_avail = true; } void C_csp_solver::turn_off_plant() @@ -481,13 +455,6 @@ void C_csp_solver::turn_off_plant() m_is_CR_DF__PC_SU__TES_FULL__AUX_OFF_avail = false; m_is_CR_DF__PC_SU__TES_OFF__AUX_OFF_avail = false; - - m_is_CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF_avail = false; - m_is_CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF_avail = false; - m_is_CR_TO_COLD__PC_SB__TES_DC__AUX_OFF_avail = false; - m_is_CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF_avail = false; - m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail = false; - m_is_CR_TO_COLD__PC_SU__TES_DC__AUX_OFF_avail = false; } double C_csp_solver::get_cr_aperture_area() @@ -546,21 +513,8 @@ void C_csp_solver::init() mc_tou.init_parent(); // Thermal Storage m_is_tes = mc_tes.does_tes_exist(); - bool m_does_tes_enable_cr_to_cold_tank = mc_tes.is_cr_to_cold_allowed(); - - // System control logic - m_is_rec_to_coldtank_allowed = ms_system_params.m_is_rec_to_coldtank_allowed; - m_T_htf_hot_tank_in_min = (ms_system_params.f_htf_hot_des__T_htf_hot_tank_in_min * cr_solved_params.m_T_htf_cold_des + - (1.0 - ms_system_params.f_htf_hot_des__T_htf_hot_tank_in_min) * cr_solved_params.m_T_htf_hot_des) - 273.15; //[C] convert from K - //m_T_htf_hot_tank_in_min = (0.5 * cr_solved_params.m_T_htf_cold_des + 0.5 * cr_solved_params.m_T_htf_hot_des) - 273.15; //[C] convert from K - - // Can't send HTF outlet to cold tank if no cold tank - // or if TES class isn't configured to do so (parallel tanks in two-tank tes can't at the moment) - // or if hot tank in min is nan or "too hot" - m_is_rec_to_coldtank_allowed = m_is_rec_to_coldtank_allowed && m_is_tes && - m_does_tes_enable_cr_to_cold_tank && - std::isfinite(m_T_htf_hot_tank_in_min) && - m_T_htf_hot_tank_in_min < (m_cycle_T_htf_hot_des); + + m_is_cr_config_recirc = true; @@ -747,17 +701,6 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double progress_msg_frac_current = progress_msg_interval_frac; double V_hot_tank_frac_initial; - - double pc_state_persist = 0.; // Time [hr] that current pc operating state (on/off/standby) has persisted - double rec_state_persist = 0.; // Time [hr] that current receiver operating state (on/off/standby) has persisted - int prev_pc_state = mc_power_cycle.get_operating_state(); - int prev_rec_state = mc_collector_receiver.get_operating_state(); - - double q_pb_last = 0.0; // Cycle thermal input at end of last time step [kWt] - double w_pb_last = 0.0; // Cycle gross generation at end of last time step [kWt] - double f_op_last = 0.0; // Fraction of last time step that cycle was operating or in standby - - /* ************************** MAIN TIME-SERIES LOOP ************************** */ @@ -794,8 +737,10 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) mc_csp_messages.add_message(C_csp_messages::WARNING, util::format("End time: %f", end_time) ); int operating_mode = ENTRY_MODE; - + std::string operating_mode_str = tech_operating_modes_str[operating_mode]; + std::string operating_mode_str_prev = ""; std::string op_mode_str = ""; + std::string op_mode_str_prev = ""; while( mc_kernel.mc_sim_info.ms_ts.m_time <= mc_kernel.get_sim_setup()->m_sim_time_end ) { @@ -826,16 +771,13 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) pc_operating_state = mc_power_cycle.get_operating_state(); if (m_is_first_timestep && f_turbine_tou <= 0.) pc_operating_state = C_csp_power_cycle::OFF; - double q_pb_last = mc_pc_out_solver.m_q_dot_htf * 1000.; //[kWt] - double w_pb_last = mc_pc_out_solver.m_P_cycle * 1000.; //[kWt] - // Calculate maximum thermal power to power cycle for startup. This will be zero if power cycle is on. double q_dot_pc_su_max = mc_power_cycle.get_max_q_pc_startup(); //[MWt] // Get weather at this timestep. Should only be called once per timestep. (Except converged() function) mc_weather.timestep_call(mc_kernel.mc_sim_info); - // Get volume of hot tank, for debugging + // Get volume of hot hot tank, for debugging V_hot_tank_frac_initial = mc_tes.get_hot_tank_vol_frac(); // Get or set decision variables @@ -887,7 +829,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) mc_pc_out_solver, mc_kernel.mc_sim_info); - bool is_rec_outlet_to_hottank = true; + m_T_htf_pc_cold_est = mc_pc_out_solver.m_T_htf_cold; //[C] // Solve collector/receiver at steady state with design inputs and weather to estimate output mc_cr_htf_state_in.m_temp = m_T_htf_pc_cold_est; //[C] @@ -903,13 +845,6 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) if (cr_operating_state != C_csp_collector_receiver::ON) T_htf_hot_cr_on = m_cycle_T_htf_hot_des - 273.15; //[C] - // Is receiver on and will it likely remain on - if (cr_operating_state == C_csp_collector_receiver::ON && m_dot_cr_on > 0.0 - && m_is_rec_to_coldtank_allowed - && T_htf_hot_cr_on < m_T_htf_hot_tank_in_min) { - is_rec_outlet_to_hottank = false; - } - // Get TES operating state info at end of last time step double q_dot_tes_dc, q_dot_tes_ch; //[MWt] q_dot_tes_dc = q_dot_tes_ch = std::numeric_limits::quiet_NaN(); @@ -1196,17 +1131,6 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } - // Split up reported q_dot_pc target into 'startup' and 'on' so input dispatch can specify both for a single full timestep - double q_dot_pc_su_target_reporting = 0.0; - double q_dot_pc_on_target_reporting = 0.0; - if (pc_operating_state == C_csp_power_cycle::OFF || pc_operating_state == C_csp_power_cycle::STARTUP) { - q_dot_pc_su_target_reporting = q_pc_target; - } - else { - q_dot_pc_on_target_reporting = q_pc_target; - } - - /* ------------ Controller/Solver iteration loop ------------- */ @@ -1265,23 +1189,16 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } - // Check if receiver can be defocused enough to stay under cycle+TES max thermal power and mass flow (if cold recirculation is not enabled) - // (this will usually be the case unless using clear-sky control or constrained cycle thermal input) - if (cr_operating_state == C_csp_collector_receiver::ON && (q_dot_cr_on >0.0 || m_dot_cr_on > 0.0) && is_rec_su_allowed && is_rec_outlet_to_hottank && m_is_tes) + // Check if receiver can be defocused enough to stay under cycle+TES max thermal power and mass flow (this will usually be the case unless using clear-sky control or constrained cycle thermal input) + if (cr_operating_state == C_csp_collector_receiver::ON && q_dot_cr_on>0.0 && is_rec_su_allowed && m_is_tes) { double qpcmax = m_q_dot_pc_max; if (pc_operating_state == C_csp_power_cycle::OFF || C_csp_power_cycle::STARTUP) qpcmax = q_dot_pc_su_max; - double qmax = q_dot_tes_ch / (1.0 - tol_mode_switching); - double mmax = m_dot_tes_ch_est / (1.0 - tol_mode_switching); - if (is_pc_su_allowed) - { - qmax += m_q_dot_pc_max / (1.0 - tol_mode_switching); - mmax += m_m_dot_pc_max / (1.0 - tol_mode_switching); - } - - if (q_dot_cr_on > qmax || m_dot_cr_on > mmax) // Receiver will need to be defocused + double qmax = (m_q_dot_pc_max + q_dot_tes_ch) / (1.0 - tol_mode_switching); + double mmax = (m_m_dot_pc_max + m_dot_tes_ch_est) / (1.0 - tol_mode_switching); + if (q_dot_cr_on > qmax || m_dot_cr_on > mmax) { double df = fmin(qmax / q_dot_cr_on, mmax / m_dot_cr_on); mc_collector_receiver.on(mc_weather.ms_outputs, mc_cr_htf_state_in, df, mc_cr_out_solver, mc_kernel.mc_sim_info); @@ -1333,7 +1250,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) else if( cr_operating_state == C_csp_collector_receiver::ON && (pc_operating_state == C_csp_power_cycle::OFF || pc_operating_state == C_csp_power_cycle::STARTUP) ) { - if( q_dot_cr_on > 0.0 && is_rec_su_allowed && is_rec_outlet_to_hottank ) + if( q_dot_cr_on > 0.0 && is_rec_su_allowed ) { // Receiver is allowed to remain on, and it can produce useful energy. Now, need to find a home for it if( is_pc_su_allowed && @@ -1393,31 +1310,10 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) operating_mode = CR_OFF__PC_OFF__TES_OFF__AUX_OFF; } } - else - { - if ((q_dot_cr_on >0.0 || m_dot_cr_on>0.0) && is_rec_su_allowed) - { - if (q_dot_tes_dc > 0.0 && is_pc_su_allowed && - m_is_CR_TO_COLD__PC_SU__TES_DC__AUX_OFF_avail) + else if( q_dot_tes_dc > 0.0 && is_pc_su_allowed && + m_is_CR_OFF__PC_SU__TES_DC__AUX_OFF_avail ) { // Can power cycle startup using TES? - operating_mode = CR_TO_COLD__PC_SU__TES_DC__AUX_OFF; - } - else if(m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail) - { - operating_mode = CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF; - } - else - { - operating_mode = CR_OFF__PC_OFF__TES_OFF__AUX_OFF; - } - } - else - { - if (q_dot_tes_dc > 0.0 && is_pc_su_allowed && - m_is_CR_OFF__PC_SU__TES_DC__AUX_OFF_avail) - { // Can power cycle startup using TES? - operating_mode = CR_OFF__PC_SU__TES_DC__AUX_OFF; } else @@ -1425,8 +1321,6 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) operating_mode = CR_OFF__PC_OFF__TES_OFF__AUX_OFF; } } - } - } else if( (cr_operating_state == C_csp_collector_receiver::OFF || cr_operating_state == C_csp_collector_receiver::STARTUP) && (pc_operating_state == C_csp_power_cycle::ON || pc_operating_state == C_csp_power_cycle::STANDBY) ) @@ -1539,7 +1433,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) else if( cr_operating_state == C_csp_collector_receiver::ON && (pc_operating_state == C_csp_power_cycle::ON || pc_operating_state == C_csp_power_cycle::STANDBY) ) { - if( q_dot_cr_on > 0.0 && is_rec_su_allowed && is_rec_outlet_to_hottank ) + if( q_dot_cr_on > 0.0 && is_rec_su_allowed ) { // Receiver operation is allowed and possible - find a home for output if( is_pc_su_allowed || is_pc_sb_allowed ) @@ -1791,79 +1685,6 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } // End logic else 'pc su is NOT allowed' } // End logic if(q_dot_cr_output > 0.0 && is_rec_su_allowed) - // 'else if' loop for receiver 'on' but sending htf to cold tank - else if ((q_dot_cr_on > 0.0 || m_dot_cr_on > 0.0)&& is_rec_su_allowed) { - - if (is_pc_su_allowed || is_pc_sb_allowed) - { - if (q_dot_tes_dc > 0.0) - { // Storage dispatch is available - - if (((q_dot_tes_dc * (1.0 + tol_mode_switching) > q_pc_target - && m_dot_tes_dc_est * (1.0 + tol_mode_switching) > m_m_dot_pc_min) - || m_dot_tes_dc_est * (1.0 + tol_mode_switching) > m_m_dot_pc_max) - && is_pc_su_allowed && - m_is_CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF_avail) - { // Storage can provide enough dispatch to reach power cycle target - // Tolerance is applied so that if TES is *close* to reaching PC target, the controller tries that mode - - operating_mode = CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF; - } - else if (q_dot_tes_dc * (1.0 + tol_mode_switching) > q_pc_min - && m_dot_tes_dc_est * (1.0 + tol_mode_switching) > m_m_dot_pc_min - && is_pc_su_allowed && - m_is_CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF_avail) - { // Storage can provide enough dispatch to at least meet power cycle minimum operation fraction - // Run at highest possible PC fraction by dispatching all remaining storage - // Tolerance is applied so that if CR + TES is *close* to reaching PC min, the controller tries that mode - - operating_mode = CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF; - } - else if (q_dot_tes_dc * (1.0 + tol_mode_switching) > q_pc_sb - && m_dot_tes_dc_est * (1.0 + tol_mode_switching) > m_m_dot_pc_min - && is_pc_sb_allowed && - m_is_CR_TO_COLD__PC_SB__TES_DC__AUX_OFF_avail) - { // Tolerance is applied so that if CR + TES is *close* to reaching standby, the controller tries that mode - - operating_mode = CR_TO_COLD__PC_SB__TES_DC__AUX_OFF; - } - else if (is_pc_su_allowed && - m_is_CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF_avail) - { // If not enough thermal power to stay in standby, then run at min PC load until TES is fully discharged - - operating_mode = CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF; - } - else if (m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail) - { - operating_mode = CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF; - } - else - { - operating_mode = CR_OFF__PC_OFF__TES_OFF__AUX_OFF; - } - } // End logic for if( q_dot_tes_dc > 0.0 ) - else if(m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail) - { // Storage dispatch is not available - - // No thermal power available to power cycle - operating_mode = CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF; - } - else - { - operating_mode = CR_OFF__PC_OFF__TES_OFF__AUX_OFF; - } - } // End logic if( is_pc_su_allowed ) - else if (m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail) - { // If neither receiver nor power cycle operation is allowed, then shut everything off - - operating_mode = CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF; - } - else - { - operating_mode = CR_OFF__PC_OFF__TES_OFF__AUX_OFF; - } - - } else // Receiver is off - determine if power cycle can remain on { if( is_pc_su_allowed || is_pc_sb_allowed ) @@ -1930,6 +1751,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) // Store operating mode m_op_mode_tracking.push_back(operating_mode); + operating_mode_str = tech_operating_modes_str[operating_mode]; op_mode_str = ""; @@ -1955,7 +1777,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -1997,7 +1819,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2028,7 +1850,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2077,7 +1899,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2135,7 +1957,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2233,7 +2055,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_target, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_target, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2281,7 +2103,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2294,31 +2116,6 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } break; - case CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF: - { - int cr_mode = C_csp_collector_receiver::E_csp_cr_modes::ON; - C_csp_power_cycle::E_csp_power_cycle_modes pc_mode = C_csp_power_cycle::OFF; - C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode = C_MEQ__m_dot_tes::E__CR_OUT__0; - C_MEQ__timestep::E_timestep_target_modes step_target_mode = C_MEQ__timestep::E_STEP_FIXED; - bool is_defocus = false; - op_mode_str = "CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF"; - double defocus_solved = std::numeric_limits::quiet_NaN(); - - int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); - - if (mode_code != 0) - { - throw(C_csp_exception(util::format("At time = %lg, CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF failed", mc_kernel.mc_sim_info.ms_ts.m_time), "")); - } - - // Set member defocus - m_defocus = defocus_solved; - - are_models_converged = true; - } - break; - case CR_OFF__PC_OFF__TES_OFF__AUX_OFF: { int cr_mode = C_csp_collector_receiver::E_csp_cr_modes::OFF; @@ -2330,7 +2127,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2344,46 +2141,6 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } break; // exit switch() after CR_OFF__PC_OFF__TES_OFF__AUX_OFF: - case CR_TO_COLD__PC_SU__TES_DC__AUX_OFF: - { - // Use thermal storage to startup power cycle - // This solver iterates to find the thermal storage outlet temperature to the power cycle - // and the power cycle demand mass flow rate that reach system equilibrium - - double t_ts_initial = mc_kernel.mc_sim_info.ms_ts.m_step; //[s] - - if (!mc_collector_receiver.m_is_sensible_htf) - { - std::string err_msg = util::format("Operating mode, %d, is not configured for DSG mode", operating_mode); - throw(C_csp_exception(err_msg, "CSP Solver")); - } - - int cr_mode = C_csp_collector_receiver::ON; - C_csp_power_cycle::E_csp_power_cycle_modes pc_mode = C_csp_power_cycle::STARTUP_CONTROLLED; - - C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode = C_MEQ__m_dot_tes::E__CR_OUT__ITER_M_DOT_SU_DC_ONLY; - C_MEQ__timestep::E_timestep_target_modes step_target_mode = C_MEQ__timestep::E_STEP_FROM_COMPONENT; - bool is_defocus = false; - op_mode_str = "CR_TO_COLD__PC_SU__TES_DC__AUX_OFF"; - double defocus_solved = std::numeric_limits::quiet_NaN(); - - int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); - - if (mode_code != 0) - { - m_is_CR_TO_COLD__PC_SU__TES_DC__AUX_OFF_avail = false; - are_models_converged = false; - break; - } - - // Set member defocus - m_defocus = defocus_solved; - - are_models_converged = true; - } - break; - case CR_OFF__PC_SU__TES_DC__AUX_OFF: { // Use thermal storage to startup power cycle @@ -2407,7 +2164,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2443,7 +2200,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2481,7 +2238,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2552,7 +2309,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2615,7 +2372,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2680,9 +2437,9 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) m_defocus = defocus_solved; are_models_converged = true; - } // end outer bracket for case CR_ON__PC_TARGET__TES_DC__AUX_OFF + } // end outer bracket for case CR_ON__PC_OFF__TES_CH__AUX_OFF - break; // break case CR_ON__PC_TARGET__TES_DC__AUX_OFF + break; // break case CR_ON__PC_OFF__TES_CH__AUX_OFF case CR_ON__PC_RM_LO__TES_EMPTY__AUX_OFF: { @@ -2707,7 +2464,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2811,7 +2568,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2827,78 +2584,6 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } break; // break case CR_DF__PC_OFF__TES_FULL__AUX_OFF - case CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF: - { - //The collector receiver is off - //The power cycle runs at its minimum operating fraction until storage is depleted - //A new, shorter timestep is calculated here - - if (!mc_collector_receiver.m_is_sensible_htf) - { - std::string err_msg = util::format("Operating mode, %d, is not configured for DSG mode", operating_mode); - throw(C_csp_exception(err_msg, "CSP Solver")); - } - - double t_ts_initial = mc_kernel.mc_sim_info.ms_ts.m_step; //[s] - - int cr_mode = C_csp_collector_receiver::ON; - C_csp_power_cycle::E_csp_power_cycle_modes pc_mode = C_csp_power_cycle::ON; - C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode = C_MEQ__m_dot_tes::E__CR_OUT__CR_OUT_PLUS_TES_EMPTY; - C_MEQ__timestep::E_timestep_target_modes step_target_mode = C_MEQ__timestep::E_STEP_Q_DOT_PC; - bool is_defocus = false; - double q_dot_pc_target = q_pc_min; //[MWt] - op_mode_str = "CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF"; - double defocus_solved = std::numeric_limits::quiet_NaN(); - - int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_target, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); - - if (mode_code != 0) - { - m_is_CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF_avail = false; - are_models_converged = false; - break; - } - - // Check if solved thermal power is greater than target - if (mc_pc_out_solver.m_q_dot_htf > q_pc_target) - { - if (mc_pc_out_solver.m_q_dot_htf > m_q_dot_pc_max) - { - error_msg = util::format("At time = %lg CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" - " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", - mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, m_q_dot_pc_max); - - mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); - - turn_off_plant(); - reset_time(t_ts_initial); - are_models_converged = false; - break; - } - } - - if (mc_pc_out_solver.m_m_dot_htf > m_m_dot_pc_max) - { - error_msg = util::format("At time = %lg CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF converged to a HTF mass flow rate %lg [kg/s]" - " larger than the maximum PC mass flow rate %lg [kg/s]. Controller shut off plant", - mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_m_dot_htf / 3600.0, m_m_dot_pc_max / 3600.0); - - mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); - - turn_off_plant(); - reset_time(t_ts_initial); - are_models_converged = false; - break; - } - - // Set member defocus - m_defocus = defocus_solved; - - are_models_converged = true; - } - break; - case CR_OFF__PC_MIN__TES_EMPTY__AUX_OFF: { //The collector receiver is off @@ -2923,7 +2608,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_target, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_target, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -2937,7 +2622,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) { if (mc_pc_out_solver.m_q_dot_htf > m_q_dot_pc_max) { - error_msg = util::format("At time = %lg CR_OFF__PC_MIN__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" + error_msg = util::format("At time = %lg CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, m_q_dot_pc_max); @@ -2952,7 +2637,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) if (mc_pc_out_solver.m_m_dot_htf > m_m_dot_pc_max) { - error_msg = util::format("At time = %lg CR_OFF__PC_MIN__TES_EMPTY__AUX_OFF converged to a HTF mass flow rate %lg [kg/s]" + error_msg = util::format("At time = %lg CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a HTF mass flow rate %lg [kg/s]" " larger than the maximum PC mass flow rate %lg [kg/s]. Controller shut off plant", mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_m_dot_htf / 3600.0, m_m_dot_pc_max / 3600.0); @@ -2971,85 +2656,6 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } break; // break case CR_OFF__PC_MIN__TES_EMPTY__AUX_OFF - case CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF: - { - // The collector-receiver is off - // The power cycle runs somewhere between its minimum operating fraction and target operation, with thermal input from TES, which is depleted at the end of the timestep - - if (!mc_collector_receiver.m_is_sensible_htf) - { - std::string err_msg = util::format("Operating mode, %d, is not configured for DSG mode", operating_mode); - throw(C_csp_exception(err_msg, "CSP Solver")); - } - - int cr_mode = C_csp_collector_receiver::ON; - C_csp_power_cycle::E_csp_power_cycle_modes pc_mode = C_csp_power_cycle::ON; - C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode = C_MEQ__m_dot_tes::E__CR_OUT__CR_OUT_PLUS_TES_EMPTY; - C_MEQ__timestep::E_timestep_target_modes step_target_mode = C_MEQ__timestep::E_STEP_FIXED; - bool is_defocus = false; - op_mode_str = "CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF"; - double defocus_solved = std::numeric_limits::quiet_NaN(); - - int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); - - if (mode_code != 0) - { - m_is_CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF_avail = false; - are_models_converged = false; - break; - } - - if (mc_pc_out_solver.m_q_dot_htf < q_pc_min || mc_pc_out_solver.m_m_dot_htf < m_m_dot_pc_min) - { - m_is_CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF_avail = false; - are_models_converged = false; - break; - } - - // Check if solved thermal power is greater than target - if (mc_pc_out_solver.m_q_dot_htf > q_pc_target) - { - if (mc_pc_out_solver.m_q_dot_htf > m_q_dot_pc_max) - { - error_msg = util::format("At time = %lg CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" - " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", - mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, m_q_dot_pc_max); - - mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); - - turn_off_plant(); - are_models_converged = false; - break; - } - else - { - error_msg = util::format("At time = %lg CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" - " larger than the target PC thermal power %lg [MWt] but less than the maximum thermal power %lg [MWt]", - mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, q_pc_target, m_q_dot_pc_max); - mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); - } - } - - if (mc_pc_out_solver.m_m_dot_htf > m_m_dot_pc_max) - { - error_msg = util::format("At time = %lg CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a HTF mass flow rate %lg [kg/s]" - " larger than the maximum PC mass flow rate %lg [kg/s]. Controller shut off plant", - mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_m_dot_htf / 3600.0, m_m_dot_pc_max / 3600.0); - - mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); - - turn_off_plant(); - are_models_converged = false; - break; - } - - // Set member defocus - m_defocus = defocus_solved; - - are_models_converged = true; - } - break; case CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF: { @@ -3071,7 +2677,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3154,7 +2760,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_target, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_target, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3177,9 +2783,18 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) { if (mc_pc_out_solver.m_q_dot_htf > m_q_dot_pc_max) { + if (operating_mode == CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF) + { + error_msg = util::format("At time = %lg CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" + " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", + mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, m_q_dot_pc_max); + } + else if (operating_mode == CR_SU__PC_RM_LO__TES_EMPTY__AUX_OFF) + { error_msg = util::format("At time = %lg CR_SU__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, m_q_dot_pc_max); + } mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); @@ -3190,19 +2805,36 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } else { + if (operating_mode == CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF) + { + error_msg = util::format("At time = %lg CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" + " larger than the target PC thermal power %lg [MWt] but less than the maximum thermal power %lg [MWt]", + mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, q_pc_target, m_q_dot_pc_max); + } + else if (operating_mode == CR_SU__PC_RM_LO__TES_EMPTY__AUX_OFF) + { error_msg = util::format("At time = %lg CR_SU__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a PC thermal power %lg [MWt]" " larger than the target PC thermal power %lg [MWt] but less than the maximum thermal power %lg [MWt]", mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_q_dot_htf, q_pc_target, m_q_dot_pc_max); - + } mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); } } if (mc_pc_out_solver.m_m_dot_htf > m_m_dot_pc_max) { + if (operating_mode == CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF) + { + error_msg = util::format("At time = %lg CR_OFF__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a HTF mass flow rate %lg [kg/s]" + " larger than the maximum PC mass flow rate %lg [kg/s]. Controller shut off plant", + mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_m_dot_htf/3600.0, m_m_dot_pc_max/3600.0); + } + else if (operating_mode == CR_SU__PC_RM_LO__TES_EMPTY__AUX_OFF) + { error_msg = util::format("At time = %lg CR_SU__PC_RM_LO__TES_EMPTY__AUX_OFF converged to a HTF mass flow rate %lg [kg/s]" " larger than the maximum PC mass flow rate %lg [kg/s]. Controller shut off plant", mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, mc_pc_out_solver.m_m_dot_htf/3600.0, m_m_dot_pc_max/3600.0); + } mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); @@ -3245,7 +2877,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_target, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_target, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3345,7 +2977,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3416,83 +3048,6 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) break; - case CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF: - { - if (!mc_collector_receiver.m_is_sensible_htf) - { - std::string err_msg = util::format("Operating mode, %d, is not configured for DSG mode", operating_mode); - throw(C_csp_exception(err_msg, "CSP Solver")); - } - - int cr_mode = C_csp_collector_receiver::ON; - C_csp_power_cycle::E_csp_power_cycle_modes pc_mode = C_csp_power_cycle::ON; - - C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode = C_MEQ__m_dot_tes::E__CR_OUT__ITER_Q_DOT_TARGET_DC_ONLY; - C_MEQ__timestep::E_timestep_target_modes step_target_mode = C_MEQ__timestep::E_STEP_FIXED; - bool is_defocus = false; - - double q_dot_pc_fixed = q_pc_target; //[MWt] - op_mode_str = "CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF"; - double defocus_solved = std::numeric_limits::quiet_NaN(); - - int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); - - if (mode_code != 0) - { - m_is_CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF_avail = false; - are_models_converged = false; - break; - } - - double q_dot_pc_solved = mc_pc_out_solver.m_q_dot_htf; //[MWt] - double m_dot_pc_solved = mc_pc_out_solver.m_m_dot_htf; //[kg/hr] - - // Check if solved thermal power is greater than target - if ((q_dot_pc_solved - q_dot_pc_fixed) / q_dot_pc_fixed > 1.E-3) - { - if ((q_dot_pc_solved - m_q_dot_pc_max) / m_q_dot_pc_max > 1.E-3) - { - error_msg = util::format("At time = %lg %s converged to a PC thermal power %lg [MWt]" - " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", - mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, op_mode_str.c_str(), q_dot_pc_solved, m_q_dot_pc_max); - mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); - - turn_off_plant(); - are_models_converged = false; - break; - } - else - { - error_msg = util::format("At time = %lg %s converged to a PC thermal power %lg [MWt]" - " larger than the target PC thermal power %lg [MWt] but less than the maximum thermal power %lg [MWt]", - mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, op_mode_str.c_str(), q_dot_pc_solved, q_dot_pc_fixed, m_q_dot_pc_max); - - mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); - } - } - else if ((q_dot_pc_solved - q_dot_pc_fixed) / q_dot_pc_fixed < -1.E-3) - { - if (m_dot_pc_solved < m_m_dot_pc_max) - { // TES cannot provide enough thermal power - step down to next operating mode - - m_is_CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF_avail = false; - are_models_converged = false; - break; - } - // Notes: - //else - //{ // PC maximum mass flow is constraining the thermal power that TES can send the PC. Changing modes wont' help - // - //} - } - - // Set member defocus - m_defocus = defocus_solved; - - are_models_converged = true; - } - break; case CR_OFF__PC_TARGET__TES_DC__AUX_OFF: { @@ -3513,7 +3068,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3592,7 +3147,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3654,92 +3209,6 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } break; - case CR_TO_COLD__PC_SB__TES_DC__AUX_OFF: - { - if (!mc_collector_receiver.m_is_sensible_htf) - { - std::string err_msg = util::format("Operating mode, %d, is not configured for DSG mode", operating_mode); - throw(C_csp_exception(err_msg, "CSP Solver")); - } - - int cr_mode = C_csp_collector_receiver::ON; - C_csp_power_cycle::E_csp_power_cycle_modes pc_mode = C_csp_power_cycle::STANDBY; - - C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode = C_MEQ__m_dot_tes::E__CR_OUT__ITER_Q_DOT_TARGET_DC_ONLY; - C_MEQ__timestep::E_timestep_target_modes step_target_mode = C_MEQ__timestep::E_STEP_FIXED; - bool is_defocus = false; - - double q_dot_pc_fixed = q_pc_sb; //[MWt] - - op_mode_str = "CR_TO_COLD__PC_SB__TES_DC__AUX_OFF"; - - double defocus_solved = std::numeric_limits::quiet_NaN(); - - int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); - - if (mode_code != 0) - { - m_is_CR_TO_COLD__PC_SB__TES_DC__AUX_OFF_avail = false; - are_models_converged = false; - break; - } - - double q_dot_pc_solved = mc_pc_out_solver.m_q_dot_htf; //[MWt] - double m_dot_pc_solved = mc_pc_out_solver.m_m_dot_htf; //[kg/hr] - - error_msg = util::format("At time = %lg plant controller tried operating mode %s which hasn't been tested", - mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, op_mode_str.c_str()); - mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); - - // Check if solved thermal power is greater than target - if ((q_dot_pc_solved - q_dot_pc_fixed) / q_dot_pc_fixed > 1.E-3) - { - if ((q_dot_pc_solved - m_q_dot_pc_max) / m_q_dot_pc_max > 1.E-3) - { - error_msg = util::format("At time = %lg %s converged to a PC thermal power %lg [MWt]" - " larger than the maximum PC thermal power %lg [MWt]. Controller shut off plant", - mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, op_mode_str.c_str(), q_dot_pc_solved, m_q_dot_pc_max); - mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); - - turn_off_plant(); - are_models_converged = false; - break; - } - else - { - error_msg = util::format("At time = %lg %s converged to a PC thermal power %lg [MWt]" - " larger than the target PC thermal power %lg [MWt] but less than the maximum thermal power %lg [MWt]", - mc_kernel.mc_sim_info.ms_ts.m_time / 3600.0, op_mode_str.c_str(), q_dot_pc_solved, q_dot_pc_fixed, m_q_dot_pc_max); - - mc_csp_messages.add_message(C_csp_messages::NOTICE, error_msg); - } - } - else if ((q_dot_pc_solved - q_dot_pc_fixed) / q_dot_pc_fixed < -1.E-3) - { - if (m_dot_pc_solved < m_m_dot_pc_max) - { // TES cannot provide enough thermal power - step down to next operating mode - m_is_CR_TO_COLD__PC_SB__TES_DC__AUX_OFF_avail = false; - - are_models_converged = false; - break; - } - // Notes: - //else - //{ // PC maximum mass flow is constraining the thermal power that TES can send the PC. Changing modes wont' help - // - //} - } - - // Set member defocus - m_defocus = defocus_solved; - - // If convergence was successful, finalize this timestep and get out - // Have solved CR, TES, and PC in this operating mode, so only need to set flag to get out of Mode Iteration - are_models_converged = true; - } - break; - case CR_OFF__PC_SB__TES_DC__AUX_OFF: { if (!mc_collector_receiver.m_is_sensible_htf) @@ -3761,7 +3230,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3848,7 +3317,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3908,7 +3377,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) // Have solved CR, TES, and PC in this operating mode, so only need to set flag to get out of Mode Iteration are_models_converged = true; - } // end 'CR_SU__PC_SB__TES_DC__AUX_OFF' + } // end 'CR_OFF__PC_TARGET__TES_DC__AUX_OFF' break; @@ -3936,7 +3405,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -3999,7 +3468,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_target, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_target, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -4106,7 +3575,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -4151,7 +3620,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -4192,7 +3661,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - q_dot_pc_fixed, is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + q_dot_pc_fixed, is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -4250,7 +3719,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -4292,7 +3761,7 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) double defocus_solved = std::numeric_limits::quiet_NaN(); int mode_code = solve_operating_mode(cr_mode, pc_mode, solver_mode, step_target_mode, - std::numeric_limits::quiet_NaN(), is_defocus, is_rec_outlet_to_hottank, op_mode_str, defocus_solved); + std::numeric_limits::quiet_NaN(), is_defocus, op_mode_str, defocus_solved); if (mode_code != 0) { @@ -4380,32 +3849,6 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) mcold_avail = mdot_ch * mc_kernel.mc_sim_info.ms_ts.m_step; //kg } - // Update the cycle state persistance - if (mc_power_cycle.get_operating_state() == prev_pc_state) - pc_state_persist += mc_kernel.mc_sim_info.ms_ts.m_step / 3600.; - else - { - pc_state_persist = 0.; - prev_pc_state = mc_power_cycle.get_operating_state(); - } - - // Update the receiver state persistance - if (mc_collector_receiver.get_operating_state() == prev_rec_state) - rec_state_persist += mc_kernel.mc_sim_info.ms_ts.m_step / 3600.; - else - { - rec_state_persist = 0.; - prev_rec_state = mc_collector_receiver.get_operating_state(); - } - - - - double f_op_last = 0.0; - if (mc_power_cycle.get_operating_state() == C_csp_power_cycle::ON || mc_power_cycle.get_operating_state() == C_csp_power_cycle::STANDBY) - f_op_last = mc_kernel.mc_sim_info.ms_ts.m_step / baseline_step; // Fraction of timestep cycle was in this state - - - // Save timestep outputs // This is after timestep convergence, so be sure convergence() methods don't unexpectedly change outputs @@ -4449,33 +3892,24 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_SB, q_pc_sb); //[MW] mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_MIN, q_pc_min); //[MW] mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_TARGET, q_pc_target); //[MW] - mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_MAX, m_q_dot_pc_max); //[MW] - mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_TARGET_SU, q_dot_pc_su_target_reporting); //[MW] - mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_TARGET_ON, q_dot_pc_on_target_reporting); //[MW] + mc_reported_outputs.value(C_solver_outputs::PC_Q_DOT_MAX, m_q_dot_pc_max); //[MW] mc_reported_outputs.value(C_solver_outputs::CTRL_IS_REC_SU, is_rec_su_allowed); //[-] mc_reported_outputs.value(C_solver_outputs::CTRL_IS_PC_SU, is_pc_su_allowed); //[-] mc_reported_outputs.value(C_solver_outputs::CTRL_IS_PC_SB, is_pc_sb_allowed); //[-] - mc_reported_outputs.value(C_solver_outputs::EST_Q_DOT_CR_SU, q_dot_cr_startup); //[-] + mc_reported_outputs.value(C_solver_outputs::EST_Q_DOT_CR_SU, is_pc_sb_allowed); //[-] mc_reported_outputs.value(C_solver_outputs::EST_Q_DOT_CR_ON, q_dot_cr_on); //[MWt] mc_reported_outputs.value(C_solver_outputs::EST_Q_DOT_DC, q_dot_tes_dc); //[MWt] mc_reported_outputs.value(C_solver_outputs::EST_Q_DOT_CH, q_dot_tes_ch); //[MWt] - double m_dot_cr_out_to_tes_hot = mc_cr_out_solver.m_m_dot_salt_tot; //[kg/hr] - double m_dot_cr_out_to_tes_cold = 0.0; - if (!is_rec_outlet_to_hottank) { - m_dot_cr_out_to_tes_cold = mc_cr_out_solver.m_m_dot_salt_tot; //[kg/hr] - m_dot_cr_out_to_tes_hot = 0.0; - } - - double m_dot_bal_hot = (m_dot_cr_out_to_tes_hot + + double m_dot_bal_hot = (mc_cr_out_solver.m_m_dot_salt_tot + mc_tes_outputs.m_m_dot_tes_hot_out*3600.0 - mc_pc_inputs.m_m_dot - mc_tes_outputs.m_m_dot_cr_to_tes_hot*3600.0) / m_m_dot_pc_des; //[-] - double m_dot_bal_cold = (m_dot_cr_out_to_tes_cold + mc_pc_inputs.m_m_dot + + double m_dot_bal_cold = (mc_pc_inputs.m_m_dot + mc_tes_outputs.m_m_dot_tes_cold_out*3600.0 - mc_cr_out_solver.m_m_dot_salt_tot - - mc_tes_outputs.m_m_dot_tes_cold_in*3600.0) / m_m_dot_pc_des; //[-] + mc_tes_outputs.m_m_dot_pc_to_tes_cold*3600.0) / m_m_dot_pc_des; //[-] double m_dot_bal_max = max(fabs(m_dot_bal_hot), fabs(m_dot_bal_cold)); @@ -4501,14 +3935,11 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) mc_reported_outputs.value(C_solver_outputs::TES_Q_DOT_DC, mc_tes_outputs.m_q_dot_dc_to_htf); //[MWt] TES discharge thermal power mc_reported_outputs.value(C_solver_outputs::TES_Q_DOT_CH, mc_tes_outputs.m_q_dot_ch_from_htf); //[MWt] TES charge thermal power mc_reported_outputs.value(C_solver_outputs::TES_E_CH_STATE, e_tes_disch); //[MWht] TES charge state - mc_reported_outputs.value(C_solver_outputs::TES_T_COLD_IN, mc_tes_outputs.m_T_tes_cold_in - 273.15); //[C] mc_reported_outputs.value(C_solver_outputs::M_DOT_CR_TO_TES_HOT, mc_tes_outputs.m_m_dot_cr_to_tes_hot); //[kg/s] - mc_reported_outputs.value(C_solver_outputs::M_DOT_CR_TO_TES_COLD, mc_tes_outputs.m_m_dot_cr_to_tes_cold); //[kg/s] mc_reported_outputs.value(C_solver_outputs::M_DOT_TES_HOT_OUT, mc_tes_outputs.m_m_dot_tes_hot_out); //[kg/s] mc_reported_outputs.value(C_solver_outputs::M_DOT_PC_TO_TES_COLD, mc_tes_outputs.m_m_dot_pc_to_tes_cold); //[kg/s] mc_reported_outputs.value(C_solver_outputs::M_DOT_TES_COLD_OUT, mc_tes_outputs.m_m_dot_tes_cold_out); //[kg/s] - mc_reported_outputs.value(C_solver_outputs::M_DOT_TES_COLD_IN, mc_tes_outputs.m_m_dot_tes_cold_in); //[kg/s] mc_reported_outputs.value(C_solver_outputs::M_DOT_FIELD_TO_CYCLE, mc_tes_outputs.m_m_dot_field_to_cycle); //[kg/s] mc_reported_outputs.value(C_solver_outputs::M_DOT_CYCLE_TO_FIELD, mc_tes_outputs.m_m_dot_cycle_to_field); //[kg/s] @@ -4591,9 +4022,14 @@ void C_csp_solver::Ssimulate(C_csp_solver::S_sim_setup & sim_setup) } mc_reported_outputs.value(C_solver_outputs::CTRL_OP_MODE_SEQ_C, op_mode_key); + operating_mode_str_prev = operating_mode_str; + op_mode_str_prev = op_mode_str; + mc_reported_outputs.set_timestep_outputs(); + + // **************************************************** // End saving timestep outputs // **************************************************** diff --git a/tcs/csp_solver_core.h b/tcs/csp_solver_core.h index c57fe501e..3c42e93f6 100644 --- a/tcs/csp_solver_core.h +++ b/tcs/csp_solver_core.h @@ -664,40 +664,35 @@ class C_csp_tes struct S_csp_tes_outputs { - double m_q_heater; //[MWe] Heating power required to keep tanks at a minimum temperature - double m_q_dot_dc_to_htf; //[MWt] Thermal power to the HTF from storage - double m_q_dot_ch_from_htf; //[MWt] Thermal power from the HTF to storage - - double m_m_dot_cr_to_tes_hot; //[kg/s] - double m_m_dot_cr_to_tes_cold; //[kg/s] - double m_m_dot_tes_hot_out; //[kg/s] - double m_m_dot_pc_to_tes_cold; //[kg/s] - double m_m_dot_tes_cold_out; //[kg/s] - double m_m_dot_tes_cold_in; //[kg/s] - double m_m_dot_field_to_cycle; //[kg/s] - double m_m_dot_cycle_to_field; //[kg/s] - - double m_T_tes_cold_in; //[K] + double m_q_heater = //[MWe] Heating power required to keep tanks at a minimum temperature + std::numeric_limits::quiet_NaN(); + double m_q_dot_dc_to_htf = //[MWt] Thermal power to the HTF from storage + std::numeric_limits::quiet_NaN(); + double m_q_dot_ch_from_htf = //[MWt] Thermal power from the HTF to storage + std::numeric_limits::quiet_NaN(); - // Mass flow rate from one tank directly to another. = 0 for direct systems - double m_m_dot_cold_tank_to_hot_tank; //[kg/s] + double m_m_dot_cr_to_tes_hot = //[kg/s] + std::numeric_limits::quiet_NaN(); + double m_m_dot_tes_hot_out = //[kg/s] + std::numeric_limits::quiet_NaN(); + double m_m_dot_pc_to_tes_cold = //[kg/s] + std::numeric_limits::quiet_NaN(); + double m_m_dot_tes_cold_out = //[kg/s] + std::numeric_limits::quiet_NaN(); + double m_m_dot_field_to_cycle = //[kg/s] + std::numeric_limits::quiet_NaN(); + double m_m_dot_cycle_to_field = //[kg/s] + std::numeric_limits::quiet_NaN(); - S_csp_tes_outputs() - { - m_q_heater = m_q_dot_dc_to_htf = m_q_dot_ch_from_htf = - m_m_dot_cr_to_tes_hot = m_m_dot_cr_to_tes_cold = m_m_dot_pc_to_tes_cold = m_m_dot_pc_to_tes_cold = - m_m_dot_tes_cold_out = m_m_dot_tes_cold_in = m_m_dot_field_to_cycle = m_m_dot_cycle_to_field = - m_T_tes_cold_in = - m_m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); - } + // Mass flow rate from one tank directly to another. = -1; 0 for direct systems + double m_m_dot_cold_tank_to_hot_tank = //[kg/s] + std::numeric_limits::quiet_NaN(); }; virtual void init(const C_csp_tes::S_csp_tes_init_inputs init_inputs) = 0; virtual bool does_tes_exist() = 0; - virtual bool is_cr_to_cold_allowed() = 0; - virtual double get_hot_temp() = 0; virtual double get_cold_temp() = 0; @@ -712,14 +707,11 @@ class C_csp_tes virtual double get_degradation_rate() = 0; // s^-1 - virtual void reset_storage_to_initial_state() = 0; - virtual void discharge_avail_est(double T_cold_K, double step_s, double &q_dot_dc_est, double &m_dot_field_est, double &T_hot_field_est) = 0; virtual void charge_avail_est(double T_hot_K, double step_s, double &q_dot_ch_est, double &m_dot_field_est /*kg/s*/, double &T_cold_field_est /*K*/) = 0; - virtual int solve_tes_off_design(double timestep /*s*/, double T_amb /*K*/, - double m_dot_cr_to_cv_hot /*kg/s*/, double m_dot_cv_hot_to_cycle /*kg/s*/, double m_dot_cr_to_cv_cold /*kg/s*/, + virtual int solve_tes_off_design(double timestep /*s*/, double T_amb /*K*/, double m_dot_field /*kg/s*/, double m_dot_cycle /*kg/s*/, double T_field_htf_out_hot /*K*/, double T_cycle_htf_out_cold /*K*/, double & T_cycle_htf_in_hot /*K*/, double & T_field_htf_in_cold /*K*/, C_csp_tes::S_csp_tes_outputs& outputs) = 0; @@ -769,8 +761,6 @@ class C_csp_solver PC_Q_DOT_MIN, //[MWt] PC required min thermal power PC_Q_DOT_TARGET, //[MWt] PC target thermal power PC_Q_DOT_MAX, //[MWt] PC allowable max thermal power - PC_Q_DOT_TARGET_SU, //[MWt] PC target thermal power for startup - PC_Q_DOT_TARGET_ON, //[MWt] PC target thermal power for cycle on CTRL_IS_REC_SU, //[-] Control decision: is receiver startup allowed? CTRL_IS_PC_SU, //[-] Control decision: is power cycle startup allowed? CTRL_IS_PC_SB, //[-] Control decision: is power cycle standby allowed? @@ -816,13 +806,10 @@ class C_csp_solver TES_Q_DOT_DC, //[MWt] TES discharge thermal power TES_Q_DOT_CH, //[MWt] TES charge thermal power TES_E_CH_STATE, //[MWht] TES charge state at the end of the time step - TES_T_COLD_IN, //[C] Inlet temperature to cold TES - M_DOT_CR_TO_TES_HOT, //[kg/s] - M_DOT_CR_TO_TES_COLD, //[kg/s] + M_DOT_CR_TO_TES_HOT, //[kg/s] M_DOT_TES_HOT_OUT, //[kg/s] M_DOT_PC_TO_TES_COLD, //[kg/s] M_DOT_TES_COLD_OUT, //[kg/s] - M_DOT_TES_COLD_IN, //[kg/s] M_DOT_FIELD_TO_CYCLE, //[kg/s] M_DOT_CYCLE_TO_FIELD, //[kg/s] //TES_M_DOT_DC, //[MWt] TES discharge mass flow rate @@ -906,22 +893,11 @@ class C_csp_solver double m_bop_par_1; //[-] double m_bop_par_2; //[-] - bool m_is_rec_to_coldtank_allowed; - - // If receiver outlet to cold tank is allowed - // outlet temps colder than this value go to the cold tank - // calculate T_htf_hot_tank_in_min = f*T_hot_des + (1-f)*T_cold_des - double f_htf_hot_des__T_htf_hot_tank_in_min; //[-] - S_csp_system_params() { m_pb_fixed_par = m_bop_par = m_bop_par_f = m_bop_par_0 = m_bop_par_1 = m_bop_par_2 = std::numeric_limits::quiet_NaN(); - - f_htf_hot_des__T_htf_hot_tank_in_min = std::numeric_limits::quiet_NaN(); - - m_is_rec_to_coldtank_allowed = false; } }; @@ -997,13 +973,6 @@ class C_csp_solver bool m_is_CR_DF__PC_SU__TES_OFF__AUX_OFF_avail; - bool m_is_CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF_avail; - bool m_is_CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF_avail; - bool m_is_CR_TO_COLD__PC_SB__TES_DC__AUX_OFF_avail; - bool m_is_CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF_avail; - bool m_is_CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF_avail; - bool m_is_CR_TO_COLD__PC_SU__TES_DC__AUX_OFF_avail; - // member string for exception messages std::string error_msg; @@ -1036,12 +1005,6 @@ class C_csp_solver bool m_is_tes; //[-] True: plant has storage bool m_is_cr_config_recirc; //[-] True: Receiver "off" and "startup" are recirculated from outlet to inlet - // System control logic - // True: allows control to consider sending rec exit HTF to cold tank if colder than some threshold - bool m_is_rec_to_coldtank_allowed; //[-] - // if 'm_is_rec_to_coldtank_allowed' then T_cr_out < this temp go to cold tank - double m_T_htf_hot_tank_in_min; //[C] - // Field-side HTF double m_T_field_cold_limit; //[C] double m_T_field_in_hot_limit; //[C] @@ -1149,21 +1112,7 @@ class C_csp_solver CR_DF__PC_SU__TES_FULL__AUX_OFF, - CR_DF__PC_SU__TES_OFF__AUX_OFF, - - CR_TO_COLD__PC_TARGET__TES_DC__AUX_OFF, - - CR_TO_COLD__PC_RM_LO__TES_EMPTY__AUX_OFF, - - CR_TO_COLD__PC_SB__TES_DC__AUX_OFF, - - CR_TO_COLD__PC_MIN__TES_EMPTY__AUX_OFF, - - CR_TO_COLD__PC_OFF__TES_OFF__AUX_OFF, - - SKIP_40, - - CR_TO_COLD__PC_SU__TES_DC__AUX_OFF + CR_DF__PC_SU__TES_OFF__AUX_OFF }; static std::string tech_operating_modes_str[]; @@ -1226,7 +1175,6 @@ class C_csp_solver C_csp_power_cycle::E_csp_power_cycle_modes m_pc_mode; //[-] int m_cr_mode; //[-] - bool m_is_rec_outlet_to_hottank; //[-] double m_q_dot_pc_target; //[MWt] @@ -1246,7 +1194,6 @@ class C_csp_solver C_MEQ__m_dot_tes(E_m_dot_solver_modes solver_mode, C_csp_solver* pc_csp_solver, C_csp_power_cycle::E_csp_power_cycle_modes pc_mode, int cr_mode, - bool is_rec_outlet_to_hottank, double q_dot_pc_target /*MWt*/, double defocus /*-*/, double t_ts /*s*/, double P_field_in /*kPa*/, double x_field_in /*-*/, @@ -1257,9 +1204,6 @@ class C_csp_solver mpc_csp_solver = pc_csp_solver; m_pc_mode = pc_mode; //[-] m_cr_mode = cr_mode; //[-] - - m_is_rec_outlet_to_hottank = is_rec_outlet_to_hottank; - m_q_dot_pc_target = q_dot_pc_target; //[MWt] m_defocus = defocus; //[-] m_t_ts_in = t_ts; //[s] @@ -1287,7 +1231,6 @@ class C_csp_solver C_csp_power_cycle::E_csp_power_cycle_modes m_pc_mode; //[-] int m_cr_mode; //[-] - bool m_is_rec_outlet_to_hottank; //[-] double m_defocus; //[-] double m_t_ts_in; //[s] @@ -1301,7 +1244,6 @@ class C_csp_solver C_MEQ__T_field_cold(C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode, C_csp_solver* pc_csp_solver, double q_dot_pc_target /*MWt*/, C_csp_power_cycle::E_csp_power_cycle_modes pc_mode, int cr_mode, - bool is_rec_outlet_to_hottank, double defocus /*-*/, double t_ts /*s*/, double P_field_in /*kPa*/, double x_field_in /*-*/) { @@ -1313,7 +1255,6 @@ class C_csp_solver m_pc_mode = pc_mode; m_cr_mode = cr_mode; - m_is_rec_outlet_to_hottank = is_rec_outlet_to_hottank; m_defocus = defocus; m_t_ts_in = t_ts; //[s] @@ -1348,7 +1289,6 @@ class C_csp_solver C_csp_power_cycle::E_csp_power_cycle_modes m_pc_mode; //[-] int m_cr_mode; //[-] - bool m_is_rec_outlet_to_hottank; //[-] double m_defocus; //[-] @@ -1357,7 +1297,6 @@ class C_csp_solver C_csp_solver* pc_csp_solver, double q_dot_pc_target /*MWt*/, C_csp_power_cycle::E_csp_power_cycle_modes pc_mode, int cr_mode, - bool is_rec_outlet_to_hottank, double defocus /*-*/) { m_solver_mode = solver_mode; @@ -1369,7 +1308,6 @@ class C_csp_solver m_pc_mode = pc_mode; m_cr_mode = cr_mode; - m_is_rec_outlet_to_hottank = is_rec_outlet_to_hottank; m_defocus = defocus; } @@ -1396,7 +1334,6 @@ class C_csp_solver C_csp_power_cycle::E_csp_power_cycle_modes m_pc_mode; //[-] int m_cr_mode; //[-] - bool m_is_rec_outlet_to_hottank; //[-] double m_t_ts_initial; //[s] @@ -1407,7 +1344,6 @@ class C_csp_solver C_csp_solver *pc_csp_solver, double q_dot_pc_target /*MWt*/, C_csp_power_cycle::E_csp_power_cycle_modes pc_mode, int cr_mode, - bool is_rec_outlet_to_hottank, double t_ts_initial /*s*/) { m_solver_mode = solver_mode; @@ -1420,7 +1356,6 @@ class C_csp_solver m_pc_mode = pc_mode; m_cr_mode = cr_mode; - m_is_rec_outlet_to_hottank = is_rec_outlet_to_hottank; m_t_ts_initial = t_ts_initial; //[s] } @@ -1432,7 +1367,7 @@ class C_csp_solver int solve_operating_mode(int cr_mode, C_csp_power_cycle::E_csp_power_cycle_modes pc_mode, C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode, C_MEQ__timestep::E_timestep_target_modes step_target_mode, - double q_dot_pc_target /*MWt*/, bool is_defocus, bool is_rec_outlet_to_hottank, + double q_dot_pc_target /*MWt*/, bool is_defocus, std::string op_mode_str, double& defocus_solved); diff --git a/tcs/csp_solver_mono_eq_methods.cpp b/tcs/csp_solver_mono_eq_methods.cpp index 07e2680b7..703e7995a 100644 --- a/tcs/csp_solver_mono_eq_methods.cpp +++ b/tcs/csp_solver_mono_eq_methods.cpp @@ -38,7 +38,7 @@ void C_csp_solver::reset_time(double step /*s*/) int C_csp_solver::solve_operating_mode(int cr_mode, C_csp_power_cycle::E_csp_power_cycle_modes pc_mode, C_MEQ__m_dot_tes::E_m_dot_solver_modes solver_mode, C_MEQ__timestep::E_timestep_target_modes step_target_mode, - double q_dot_pc_target /*MWt*/, bool is_defocus, bool is_rec_outlet_to_hottank, + double q_dot_pc_target /*MWt*/, bool is_defocus, std::string op_mode_str, double & defocus_solved) { double t_ts_initial = mc_kernel.mc_sim_info.ms_ts.m_step; //[s] @@ -46,7 +46,6 @@ int C_csp_solver::solve_operating_mode(int cr_mode, C_csp_power_cycle::E_csp_pow C_MEQ__defocus c_mdot_eq(solver_mode, C_MEQ__defocus::E_M_DOT_BAL, step_target_mode, this, q_dot_pc_target, pc_mode, cr_mode, - is_rec_outlet_to_hottank, t_ts_initial); //, step_tolerance); C_monotonic_eq_solver c_mdot_solver(c_mdot_eq); @@ -142,7 +141,6 @@ int C_csp_solver::solve_operating_mode(int cr_mode, C_csp_power_cycle::E_csp_pow this, q_dot_pc_target, pc_mode, cr_mode, - is_rec_outlet_to_hottank, t_ts_initial); C_monotonic_eq_solver c_q_dot_solver(c_q_dot_eq); @@ -231,7 +229,6 @@ int C_csp_solver::solve_operating_mode(int cr_mode, C_csp_power_cycle::E_csp_pow //m_dot_tes, q_dot_pc_target, pc_mode, cr_mode, - is_rec_outlet_to_hottank, t_ts_initial); // , step_tolerance); C_monotonic_eq_solver c_bal_solver(c_bal_eq); @@ -281,9 +278,7 @@ int C_csp_solver::C_MEQ__defocus::operator()(double defocus /*-*/, double *targe { C_MEQ__timestep c_T_cold_eq(m_solver_mode, m_ts_target_mode, mpc_csp_solver, m_q_dot_pc_target, - m_pc_mode, m_cr_mode, - m_is_rec_outlet_to_hottank, - defocus); + m_pc_mode, m_cr_mode, defocus); C_monotonic_eq_solver c_T_cold_solver(c_T_cold_eq); double t_ts_solved = std::numeric_limits::quiet_NaN(); @@ -533,7 +528,6 @@ int C_csp_solver::C_MEQ__timestep::operator()(double t_ts_guess /*s*/, double *t C_MEQ__T_field_cold c_eq(m_solver_mode, mpc_csp_solver, m_q_dot_pc_target, m_pc_mode, m_cr_mode, - m_is_rec_outlet_to_hottank, m_defocus, t_ts_guess, mpc_csp_solver->m_P_cold_des, mpc_csp_solver->m_x_cold_des); C_monotonic_eq_solver c_solver(c_eq); @@ -652,7 +646,6 @@ int C_csp_solver::C_MEQ__m_dot_tes::operator()(double f_m_dot_tes /*-*/, double mpc_csp_solver->mc_cr_htf_state_in.m_qual = m_x_field_in; //[-] double m_dot_field_out = std::numeric_limits::quiet_NaN(); //[kg/hr] - double m_dot_field_out_to_cold_tank = 0.0; //[kg/hr] double t_ts_cr_su = m_t_ts_in; if (m_cr_mode == C_csp_collector_receiver::ON) { @@ -668,14 +661,7 @@ int C_csp_solver::C_MEQ__m_dot_tes::operator()(double f_m_dot_tes /*-*/, double return -1; } - if (m_is_rec_outlet_to_hottank) { m_dot_field_out = mpc_csp_solver->mc_cr_out_solver.m_m_dot_salt_tot; //[kg/hr] - m_dot_field_out_to_cold_tank = 0.0; - } - else { - m_dot_field_out_to_cold_tank = mpc_csp_solver->mc_cr_out_solver.m_m_dot_salt_tot; //[kg/hr] - m_dot_field_out = 0.0; - } } else if (m_cr_mode == C_csp_collector_receiver::STARTUP) { @@ -860,15 +846,13 @@ int C_csp_solver::C_MEQ__m_dot_tes::operator()(double f_m_dot_tes /*-*/, double m_m_dot_pc_in = 0.0; } - // Solve TES with solved CR outlet temperature and guessed PC outlet temperature - // to get the cycle inlet temperature double T_cycle_hot = std::numeric_limits::quiet_NaN(); //[K] double T_field_cold_calc = std::numeric_limits::quiet_NaN(); //[K] if (mpc_csp_solver->m_is_tes) { int tes_code = mpc_csp_solver->mc_tes.solve_tes_off_design(mpc_csp_solver->mc_kernel.mc_sim_info.ms_ts.m_step, mpc_csp_solver->mc_weather.ms_outputs.m_tdry + 273.15, - m_dot_hot_to_tes / 3600.0, m_m_dot_pc_in / 3600.0, m_dot_field_out_to_cold_tank / 3600.0, + m_dot_hot_to_tes / 3600.0, m_m_dot_pc_in / 3600.0, mpc_csp_solver->mc_cr_out_solver.m_T_salt_hot + 273.15, m_T_field_cold_guess + 273.15, T_cycle_hot, T_field_cold_calc, mpc_csp_solver->mc_tes_outputs); @@ -884,8 +868,7 @@ int C_csp_solver::C_MEQ__m_dot_tes::operator()(double f_m_dot_tes /*-*/, double T_cycle_hot = mpc_csp_solver->mc_cr_out_solver.m_T_salt_hot + 273.15; //[K] } - // Solve power cycle with solved inlet temperature - // get outlet temperature + // Power Cycle mpc_csp_solver->mc_pc_htf_state_in.m_temp = T_cycle_hot - 273.15; //[C], convert from K mpc_csp_solver->mc_pc_htf_state_in.m_pres = mpc_csp_solver->mc_cr_out_solver.m_P_htf_hot; //[kPa] mpc_csp_solver->mc_pc_htf_state_in.m_qual = mpc_csp_solver->mc_cr_out_solver.m_xb_htf_hot; //[-] @@ -913,12 +896,11 @@ int C_csp_solver::C_MEQ__m_dot_tes::operator()(double f_m_dot_tes /*-*/, double t_ts_pc_su = mpc_csp_solver->mc_pc_out_solver.m_time_required_max; //[s] } - // Solve TES again, this time with both the solved CR outlet and PC outlet temperatures if (mpc_csp_solver->m_is_tes) { int tes_code = mpc_csp_solver->mc_tes.solve_tes_off_design(mpc_csp_solver->mc_kernel.mc_sim_info.ms_ts.m_step, mpc_csp_solver->mc_weather.ms_outputs.m_tdry + 273.15, - m_dot_hot_to_tes / 3600.0, m_m_dot_pc_in / 3600.0, m_dot_field_out_to_cold_tank / 3600.0, + m_dot_hot_to_tes / 3600.0, m_m_dot_pc_in / 3600.0, mpc_csp_solver->mc_cr_out_solver.m_T_salt_hot + 273.15, mpc_csp_solver->mc_pc_out_solver.m_T_htf_cold + 273.15, T_cycle_hot, T_field_cold_calc, mpc_csp_solver->mc_tes_outputs); @@ -974,7 +956,7 @@ int C_csp_solver::C_MEQ__T_field_cold::operator()(double T_field_cold /*C*/, dou init_calc_member_vars(); C_MEQ__m_dot_tes c_eq(m_solver_mode, mpc_csp_solver, - m_pc_mode, m_cr_mode, m_is_rec_outlet_to_hottank, + m_pc_mode, m_cr_mode, m_q_dot_pc_target, m_defocus, m_t_ts_in, m_P_field_in, m_x_field_in, T_field_cold); diff --git a/tcs/csp_solver_two_tank_tes.cpp b/tcs/csp_solver_two_tank_tes.cpp index b4947a66e..6935637d8 100644 --- a/tcs/csp_solver_two_tank_tes.cpp +++ b/tcs/csp_solver_two_tank_tes.cpp @@ -434,7 +434,7 @@ double C_storage_tank::get_m_T_calc() double C_storage_tank::get_m_m_calc() //ARD new getter for current mass { - return m_m_calc; //[kg] + return m_m_calc; } double C_storage_tank::get_vol_frac() @@ -442,18 +442,13 @@ double C_storage_tank::get_vol_frac() return (m_V_prev - m_V_inactive) / m_V_active; } -double C_storage_tank::get_mass_avail() -{ - return std::max(m_m_prev - m_mass_inactive, 0.0); //[kg] -} - double C_storage_tank::m_dot_available(double f_unavail, double timestep) { //double rho = mc_htf.dens(m_T_prev, 1.0); //[kg/m^3] //double V = m_m_prev / rho; //[m^3] Volume available in tank (one temperature) //double V_avail = fmax(V - m_V_inactive, 0.0); //[m^3] Volume that is active - need to maintain minimum height (corresponding m_V_inactive) - double mass_avail = get_mass_avail(); //[kg] + double mass_avail = std::max(m_m_prev - m_mass_inactive, 0.0); //[kg] double m_dot_avail = std::max(mass_avail - m_mass_active * f_unavail, 0.0) / timestep; //[kg/s] // "Unavailable" fraction now applied to one temperature tank volume, not total tank volume @@ -470,8 +465,7 @@ void C_storage_tank::converged() m_m_prev = m_m_calc; //[kg] } -void C_storage_tank::energy_balance(double timestep /*s*/, double m_dot_in /*kg/s*/, double m_dot_out /*kg/s*/, - double T_in /*K*/, double T_amb /*K*/, +void C_storage_tank::energy_balance(double timestep /*s*/, double m_dot_in, double m_dot_out, double T_in /*K*/, double T_amb /*K*/, double &T_ave /*K*/, double & q_heater /*MW*/, double & q_dot_loss /*MW*/) { // Get properties from tank state at the end of last time step @@ -696,7 +690,6 @@ static C_csp_reported_outputs::S_output_info S_output_info[] = {C_csp_two_tank_tes::E_M_DOT_TANK_TO_TANK, C_csp_reported_outputs::TS_WEIGHTED_AVE}, //[MWt] TES thermal losses {C_csp_two_tank_tes::E_MASS_COLD_TANK, C_csp_reported_outputs::TS_LAST}, //[kg] Mass in cold tank at end of timestep {C_csp_two_tank_tes::E_MASS_HOT_TANK, C_csp_reported_outputs::TS_LAST}, //[kg] Mass in hot tank at end of timestep - {C_csp_two_tank_tes::E_HOT_TANK_HTF_PERC_FINAL, C_csp_reported_outputs::TS_LAST}, //[%] Final percent fill of available hot tank mass csp_info_invalid }; @@ -704,7 +697,7 @@ static C_csp_reported_outputs::S_output_info S_output_info[] = C_csp_two_tank_tes::C_csp_two_tank_tes() { m_vol_tank = m_V_tank_active = m_q_pb_design = - m_V_tank_hot_ini = m_mass_total_active = m_cp_field_avg = m_m_dot_tes_des_over_m_dot_field_des = std::numeric_limits::quiet_NaN(); + m_V_tank_hot_ini = m_cp_field_avg = m_m_dot_tes_des_over_m_dot_field_des = std::numeric_limits::quiet_NaN(); // m_m_dot_tes_dc_max = m_m_dot_tes_ch_max = std::numeric_limits::quiet_NaN(); @@ -814,13 +807,6 @@ void C_csp_two_tank_tes::init(const C_csp_tes::S_csp_tes_init_inputs init_inputs ms_params.tanks_in_parallel = true; } - if (ms_params.tanks_in_parallel) { - m_is_cr_to_cold_tank_allowed = false; - } - else { - m_is_cr_to_cold_tank_allowed = true; - } - // Calculate thermal power to PC at design m_q_pb_design = ms_params.m_W_dot_pc_design/ms_params.m_eta_pc*1.E6; //[Wt] @@ -853,33 +839,9 @@ void C_csp_two_tank_tes::init(const C_csp_tes::S_csp_tes_init_inputs init_inputs // The 'duty' definition should allow the tanks to accept whatever the field and/or power cycle can provide... // Calculate initial storage values - - // Initial storage charge based on % mass - double T_tes_ave = 0.5*(ms_params.m_T_field_out_des + ms_params.m_T_field_in_des); - double cp_ave = mc_store_htfProps.Cp(T_tes_ave); //[kJ/kg-K] Specific heat at average temperature - m_mass_total_active = Q_tes_des*3600.0 / (cp_ave / 1000.0 * (ms_params.m_T_field_out_des - ms_params.m_T_field_in_des)); //[kg] Total HTF mass at design point inlet/outlet T double V_inactive = m_vol_tank - m_V_tank_active; - - double rho_hot_des = mc_store_htfProps.dens(ms_params.m_T_field_out_des, 1.0); - double rho_cold_des = mc_store_htfProps.dens(ms_params.m_T_field_in_des, 1.0); - double rho_hot = mc_store_htfProps.dens(ms_params.m_T_tank_hot_ini, 1.0); - double rho_cold = mc_store_htfProps.dens(ms_params.m_T_tank_cold_ini, 1.0); - double m_hot_ini = ms_params.m_f_V_hot_ini * 0.01 * m_mass_total_active + V_inactive * rho_hot_des; // Updating intiial storage charge calculation to avoid variation in total mass with specified initial T - double m_cold_ini = (1.0 - ms_params.m_f_V_hot_ini * 0.01) * m_mass_total_active + V_inactive * rho_cold_des; - double V_hot_ini = m_hot_ini / rho_hot; - double V_cold_ini = m_cold_ini / rho_cold; - - //double rho_hot = mc_store_htfProps.dens(ms_params.m_T_tank_hot_ini, 1.0); - //double rho_cold = mc_store_htfProps.dens(ms_params.m_T_tank_cold_ini, 1.0); - - //double V_inactive = m_vol_tank - m_V_tank_active; - //double V_hot_ini = ms_params.m_f_V_hot_ini*0.01*m_mass_total_active / rho_hot + V_inactive; //[m^3] - //double V_cold_ini = (1.0 - ms_params.m_f_V_hot_ini*0.01)*m_mass_total_active / rho_cold + V_inactive; //[m^3] - - // Initial storage charge based on % volume - //double V_inactive = m_vol_tank - m_V_tank_active; - //double V_hot_ini = ms_params.m_f_V_hot_ini*0.01*m_V_tank_active + V_inactive; //[m^3] - //double V_cold_ini = (1.0 - ms_params.m_f_V_hot_ini*0.01)*m_V_tank_active + V_inactive; //[m^3] + double V_hot_ini = ms_params.m_f_V_hot_ini*0.01*m_V_tank_active + V_inactive; //[m^3] + double V_cold_ini = (1.0 - ms_params.m_f_V_hot_ini*0.01)*m_V_tank_active + V_inactive; //[m^3] double T_hot_ini = ms_params.m_T_tank_hot_ini; //[K] double T_cold_ini = ms_params.m_T_tank_cold_ini; //[K] @@ -894,6 +856,13 @@ void C_csp_two_tank_tes::init(const C_csp_tes::S_csp_tes_init_inputs init_inputs ms_params.m_u_tank, ms_params.m_tank_pairs, ms_params.m_cold_tank_Thtr, ms_params.m_cold_tank_max_heat, V_cold_ini, T_cold_ini, ms_params.m_T_field_in_des); + // Size TES piping and output values + if (ms_params.tes_lengths.ncells() < 11) { + // set defaults + double vals1[11] = { 0., 90., 100., 120., 0., 0., 0., 0., 80., 120., 80. }; + ms_params.tes_lengths.assign(vals1, 11); + } + if (ms_params.custom_tes_pipe_sizes && (ms_params.tes_diams.ncells() != N_tes_pipe_sections || ms_params.tes_wallthicks.ncells() != N_tes_pipe_sections)) { @@ -943,11 +912,6 @@ bool C_csp_two_tank_tes::does_tes_exist() return m_is_tes; } -bool C_csp_two_tank_tes::is_cr_to_cold_allowed() -{ - return m_is_cr_to_cold_tank_allowed; -} - double C_csp_two_tank_tes::get_hot_temp() { return mc_hot_tank.get_m_T_prev(); //[K] @@ -1001,34 +965,6 @@ double C_csp_two_tank_tes::get_degradation_rate() return e_loss / (m_q_pb_design * ms_params.m_ts_hours * 3600.); //s^-1 -- fraction of heat loss per second based on full charge } -void C_csp_two_tank_tes::reset_storage_to_initial_state() -{ - // Initial storage charge based on % mass - double Q_tes_des = m_q_pb_design / 1.E6 * ms_params.m_ts_hours; //[MWt-hr] TES thermal capacity at design - double T_tes_ave = 0.5*(ms_params.m_T_field_out_des + ms_params.m_T_field_in_des); - double cp_ave = mc_store_htfProps.Cp(T_tes_ave); //[kJ/kg-K] Specific heat at average temperature - double mtot = Q_tes_des*3600.0 / (cp_ave / 1000.0 * (ms_params.m_T_field_out_des - ms_params.m_T_field_in_des)); //[kg] Total HTF mass - double rho_hot = mc_store_htfProps.dens(ms_params.m_T_field_out_des, 1.0); - double rho_cold = mc_store_htfProps.dens(ms_params.m_T_field_in_des, 1.0); - - double V_inactive = m_vol_tank - m_V_tank_active; - double V_hot_ini = ms_params.m_f_V_hot_ini*0.01*mtot / rho_hot + V_inactive; //[m^3] - double V_cold_ini = (1.0 - ms_params.m_f_V_hot_ini*0.01)*mtot / rho_cold + V_inactive; //[m^3] - - double T_hot_ini = ms_params.m_T_tank_hot_ini; //[K] - double T_cold_ini = ms_params.m_T_tank_cold_ini; //[K] - - // Initialize cold and hot tanks - // Hot tank - mc_hot_tank.init(mc_store_htfProps, m_vol_tank, ms_params.m_h_tank, ms_params.m_h_tank_min, - ms_params.m_u_tank, ms_params.m_tank_pairs, ms_params.m_hot_tank_Thtr, ms_params.m_hot_tank_max_heat, - V_hot_ini, T_hot_ini, ms_params.m_T_field_out_des); - // Cold tank - mc_cold_tank.init(mc_store_htfProps, m_vol_tank, ms_params.m_h_tank, ms_params.m_h_tank_min, - ms_params.m_u_tank, ms_params.m_tank_pairs, ms_params.m_cold_tank_Thtr, ms_params.m_cold_tank_max_heat, - V_cold_ini, T_cold_ini, ms_params.m_T_field_in_des); -} - double C_csp_two_tank_tes::get_tes_m_dot(double m_dot_field /*kg/s*/) { return m_dot_field * m_m_dot_tes_des_over_m_dot_field_des; @@ -1112,103 +1048,84 @@ void C_csp_two_tank_tes::charge_avail_est(double T_hot_K, double step_s, } } -int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_amb /*K*/, - double m_dot_cr_to_cv_hot /*kg/s*/, double m_dot_cv_hot_to_cycle /*kg/s*/, double m_dot_cr_to_cv_cold /*kg/s*/, - double T_cr_out_hot /*K*/, double T_cycle_out_cold /*K*/, - double& T_cycle_htf_in_hot /*K*/, double& T_cr_in_cold /*K*/, - C_csp_tes::S_csp_tes_outputs& s_outputs) //, C_csp_solver_htf_state & s_tes_ch_htf, C_csp_solver_htf_state & s_tes_dc_htf) +int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_amb /*K*/, + double m_dot_field /*kg/s*/, double m_dot_cycle /*kg/s*/, + double T_field_htf_out_hot /*K*/, double T_cycle_htf_out_cold /*K*/, + double & T_cycle_htf_in_hot /*K*/, double & T_field_htf_in_cold /*K*/, + C_csp_tes::S_csp_tes_outputs & s_outputs) //, C_csp_solver_htf_state & s_tes_ch_htf, C_csp_solver_htf_state & s_tes_dc_htf) { - // Enthalpy balance on inlet to cold cv - double T_htf_cold_cv_in = T_cycle_out_cold; //[K] - double m_dot_total_to_cv_cold = m_dot_cv_hot_to_cycle + m_dot_cr_to_cv_cold; //[kg/s] - if (m_dot_total_to_cv_cold > 0.0) { - T_htf_cold_cv_in = (m_dot_cv_hot_to_cycle*T_cycle_out_cold + m_dot_cr_to_cv_cold*T_cr_out_hot) / (m_dot_total_to_cv_cold); - } + s_outputs = S_csp_tes_outputs(); - // Total mass flow leaving cold tank to cr - // One of the RHS should always be 0... - double m_dot_cv_cold_to_cr = m_dot_cr_to_cv_hot + m_dot_cr_to_cv_cold; + double m_dot_cr_to_tes_hot, m_dot_tes_hot_out, m_dot_pc_to_tes_cold, m_dot_tes_cold_out; + m_dot_cr_to_tes_hot = m_dot_tes_hot_out = m_dot_pc_to_tes_cold = m_dot_tes_cold_out = std::numeric_limits::quiet_NaN(); + double m_dot_field_to_cycle, m_dot_cycle_to_field; + m_dot_field_to_cycle = m_dot_cycle_to_field = std::numeric_limits::quiet_NaN(); - s_outputs = S_csp_tes_outputs(); + if (ms_params.tanks_in_parallel) + { + if (m_dot_field >= m_dot_cycle) + { + m_dot_cr_to_tes_hot = m_dot_field - m_dot_cycle; //[kg/s] + m_dot_tes_hot_out = 0.0; //[kg/s] + m_dot_pc_to_tes_cold = 0.0; //[kg/s] + m_dot_tes_cold_out = m_dot_cr_to_tes_hot; //[kg/s] + m_dot_field_to_cycle = m_dot_cycle; //[kg/s] + m_dot_cycle_to_field = m_dot_cycle; //[kg/s] + } + else + { + m_dot_cr_to_tes_hot = 0.0; //[kg/s] + m_dot_tes_hot_out = m_dot_cycle - m_dot_field; //[kg/s] + m_dot_pc_to_tes_cold = m_dot_tes_hot_out; //[kg/s] + m_dot_tes_cold_out = 0.0; //[kg/s] + m_dot_field_to_cycle = m_dot_field; //[kg/s] + m_dot_cycle_to_field = m_dot_field; //[kg/s] + } + } + else + { + if (ms_params.m_is_hx) + { + throw(C_csp_exception("Serial operation of C_csp_two_tank_tes not available if there is a storage HX")); + } - double m_dot_cr_to_tes_hot, m_dot_cr_to_tes_cold, m_dot_tes_hot_out, m_dot_pc_to_tes_cold, m_dot_tes_cold_out, m_dot_tes_cold_in; - m_dot_cr_to_tes_hot = m_dot_cr_to_tes_cold = m_dot_tes_hot_out = m_dot_pc_to_tes_cold = m_dot_tes_cold_out = m_dot_tes_cold_in = std::numeric_limits::quiet_NaN(); - double m_dot_field_to_cycle, m_dot_cycle_to_field; - m_dot_field_to_cycle = m_dot_cycle_to_field = std::numeric_limits::quiet_NaN(); + m_dot_cr_to_tes_hot = m_dot_field; //[kg/s] + m_dot_tes_hot_out = m_dot_cycle; //[kg/s] + m_dot_pc_to_tes_cold = m_dot_cycle; //[kg/s] + m_dot_tes_cold_out = m_dot_field; //[kg/s] + m_dot_field_to_cycle = 0.0; //[kg/s] + m_dot_cycle_to_field = 0.0; //[kg/s] + } - if (ms_params.tanks_in_parallel) - { - // Receiver bypass is possible in a parallel configuration, - // but need to determine if it actually makes sense and how to model it - if (m_dot_cr_to_cv_cold != 0.0) { - throw(C_csp_exception("Receiver output to cold tank not allowed in parallel TES configuration")); - } - m_dot_cr_to_tes_cold = 0.0; - if (m_dot_cr_to_cv_hot >= m_dot_cv_hot_to_cycle) - { - m_dot_cr_to_tes_hot = m_dot_cr_to_cv_hot - m_dot_cv_hot_to_cycle; //[kg/s] - m_dot_tes_hot_out = 0.0; //[kg/s] - m_dot_pc_to_tes_cold = 0.0; //[kg/s] - m_dot_tes_cold_out = m_dot_cr_to_tes_hot; //[kg/s] - m_dot_field_to_cycle = m_dot_cv_hot_to_cycle; //[kg/s] - m_dot_cycle_to_field = m_dot_cv_hot_to_cycle; //[kg/s] - } - else - { - m_dot_cr_to_tes_hot = 0.0; //[kg/s] - m_dot_tes_hot_out = m_dot_cv_hot_to_cycle - m_dot_cr_to_cv_hot; //[kg/s] - m_dot_pc_to_tes_cold = m_dot_tes_hot_out; //[kg/s] - m_dot_tes_cold_out = 0.0; //[kg/s] - m_dot_field_to_cycle = m_dot_cr_to_cv_hot; //[kg/s] - m_dot_cycle_to_field = m_dot_cr_to_cv_hot; //[kg/s] - } - m_dot_tes_cold_in = m_dot_pc_to_tes_cold; - } - else - { // Serial configuration - if (ms_params.m_is_hx) - { - throw(C_csp_exception("Serial operation of C_csp_two_tank_tes not available if there is a storage HX")); - } + double q_dot_heater = std::numeric_limits::quiet_NaN(); //[MWe] Heating power required to keep tanks at a minimum temperature + double m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); //[kg/s] Hot tank mass flow rate, valid for direct and indirect systems + double W_dot_rhtf_pump = std::numeric_limits::quiet_NaN(); //[MWe] Pumping power, just for tank-to-tank in indirect storage + double q_dot_loss = std::numeric_limits::quiet_NaN(); //[MWt] Storage thermal losses + double q_dot_dc_to_htf = std::numeric_limits::quiet_NaN(); //[MWt] Thermal power to the HTF from storage + double q_dot_ch_from_htf = std::numeric_limits::quiet_NaN(); //[MWt] Thermal power from the HTF to storage + double T_hot_ave = std::numeric_limits::quiet_NaN(); //[K] Average hot tank temperature over timestep + double T_cold_ave = std::numeric_limits::quiet_NaN(); //[K] Average cold tank temperature over timestep + double T_hot_final = std::numeric_limits::quiet_NaN(); //[K] Hot tank temperature at end of timestep + double T_cold_final = std::numeric_limits::quiet_NaN(); //[K] Cold tank temperature at end of timestep - m_dot_cr_to_tes_hot = m_dot_cr_to_cv_hot; //[kg/s] - m_dot_cr_to_tes_cold = m_dot_cr_to_cv_cold; //[kg/s] - m_dot_tes_hot_out = m_dot_cv_hot_to_cycle; //[kg/s] - m_dot_pc_to_tes_cold = m_dot_cv_hot_to_cycle; //[kg/s] - m_dot_tes_cold_out = m_dot_cr_to_cv_hot + m_dot_cr_to_cv_cold; //[kg/s] - m_dot_tes_cold_in = m_dot_total_to_cv_cold; //[kg/s] - m_dot_field_to_cycle = 0.0; //[kg/s] - m_dot_cycle_to_field = 0.0; //[kg/s] - } - double q_dot_heater = std::numeric_limits::quiet_NaN(); //[MWe] Heating power required to keep tanks at a minimum temperature - double m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); //[kg/s] Hot tank mass flow rate, valid for direct and indirect systems - double W_dot_rhtf_pump = std::numeric_limits::quiet_NaN(); //[MWe] Pumping power, just for tank-to-tank in indirect storage - double q_dot_loss = std::numeric_limits::quiet_NaN(); //[MWt] Storage thermal losses - double q_dot_dc_to_htf = std::numeric_limits::quiet_NaN(); //[MWt] Thermal power to the HTF from storage - double q_dot_ch_from_htf = std::numeric_limits::quiet_NaN(); //[MWt] Thermal power from the HTF to storage - double T_hot_ave = std::numeric_limits::quiet_NaN(); //[K] Average hot tank temperature over timestep - double T_cold_ave = std::numeric_limits::quiet_NaN(); //[K] Average cold tank temperature over timestep - double T_hot_final = std::numeric_limits::quiet_NaN(); //[K] Hot tank temperature at end of timestep - double T_cold_final = std::numeric_limits::quiet_NaN(); //[K] Cold tank temperature at end of timestep - - if (ms_params.tanks_in_parallel) + if (ms_params.tanks_in_parallel) { - if (m_dot_cr_to_cv_hot >= m_dot_cv_hot_to_cycle) // Charging + if (m_dot_field >= m_dot_cycle) // Charging { - T_cycle_htf_in_hot = T_cr_out_hot; //[K] - double m_dot_tes_ch = m_dot_cr_to_cv_hot - m_dot_cv_hot_to_cycle; //[kg/s] + T_cycle_htf_in_hot = T_field_htf_out_hot; //[K] + double m_dot_tes_ch = m_dot_field - m_dot_cycle; //[kg/s] double T_htf_tes_cold = std::numeric_limits::quiet_NaN(); //[K] bool ch_solved = charge(timestep, T_amb, m_dot_tes_ch, - T_cr_out_hot, + T_field_htf_out_hot, T_htf_tes_cold, q_dot_heater, m_dot_cold_tank_to_hot_tank, W_dot_rhtf_pump, - q_dot_loss, q_dot_dc_to_htf, q_dot_ch_from_htf, - T_hot_ave, T_cold_ave, T_hot_final, T_cold_final); + q_dot_loss, q_dot_dc_to_htf, q_dot_ch_from_htf, + T_hot_ave, T_cold_ave, T_hot_final, T_cold_final); // Check if TES.charge method solved if (!ch_solved) @@ -1217,30 +1134,30 @@ int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_am } // Enthalpy balance to calculate T_htf_cold to CR - if (m_dot_cr_to_cv_hot == 0.0) + if (m_dot_field == 0.0) { - T_cr_in_cold = T_htf_tes_cold; //[K] + T_field_htf_in_cold = T_htf_tes_cold; //[K] } else { - T_cr_in_cold = (m_dot_tes_ch*T_htf_tes_cold + m_dot_cv_hot_to_cycle*T_cycle_out_cold) / m_dot_cr_to_cv_hot; //[K] - } + T_field_htf_in_cold = (m_dot_tes_ch*T_htf_tes_cold + m_dot_cycle * T_cycle_htf_out_cold) / m_dot_field; //[K] + } } else // Discharging { - T_cr_in_cold = T_cycle_out_cold; //[K] - double m_dot_tes_dc = m_dot_cv_hot_to_cycle - m_dot_cr_to_cv_hot; //[kg/s] + T_field_htf_in_cold = T_cycle_htf_out_cold; //[K] + double m_dot_tes_dc = m_dot_cycle - m_dot_field; //[kg/s] double T_htf_tes_hot = std::numeric_limits::quiet_NaN(); bool is_tes_success = discharge(timestep, T_amb, m_dot_tes_dc, - T_cycle_out_cold, + T_cycle_htf_out_cold, T_htf_tes_hot, - q_dot_heater, m_dot_cold_tank_to_hot_tank, W_dot_rhtf_pump, - q_dot_loss, q_dot_dc_to_htf, q_dot_ch_from_htf, - T_hot_ave, T_cold_ave, T_hot_final, T_cold_final); + q_dot_heater, m_dot_cold_tank_to_hot_tank, W_dot_rhtf_pump, + q_dot_loss, q_dot_dc_to_htf, q_dot_ch_from_htf, + T_hot_ave, T_cold_ave, T_hot_final, T_cold_final); - m_dot_cold_tank_to_hot_tank *= -1.0; + m_dot_cold_tank_to_hot_tank *= -1.0; // Check if discharge method solved if (!is_tes_success) @@ -1248,7 +1165,7 @@ int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_am return -4; } - T_cycle_htf_in_hot = (m_dot_tes_dc*T_htf_tes_hot + m_dot_cr_to_cv_hot*T_cr_out_hot) / m_dot_cv_hot_to_cycle; //[K] + T_cycle_htf_in_hot = (m_dot_tes_dc*T_htf_tes_hot + m_dot_field * T_field_htf_out_hot) / m_dot_cycle; //[K] } } else // Serial tank operation @@ -1259,20 +1176,19 @@ int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_am } // Inputs are: - // 1) Mass flow rate of HTF from field to hot tank - // 2) Mass flow rate of HTF from field to cold tank - // 3) Mass flow rate of HTF from hot tank to cycle - // 4) Temperature of HTF leaving field and entering hot tank - // 5) Temperature of HTF leaving the power cycle and entering the cold tank + // 1) Mass flow rate of HTF through the field + // 2) Mass flow rate of HTF + // 3) Temperature of HTF leaving field and entering hot tank + // 4) Temperature of HTF leaving the power cycle and entering the cold tank - double q_dot_ch_est, m_dot_tes_ch_max, T_cold_to_field_est; - q_dot_ch_est = m_dot_tes_ch_max = T_cold_to_field_est = std::numeric_limits::quiet_NaN(); - charge_avail_est(T_cr_out_hot, timestep, q_dot_ch_est, m_dot_tes_ch_max, T_cold_to_field_est); + double q_dot_ch_est, m_dot_tes_ch_max, T_cold_to_field_est; + q_dot_ch_est = m_dot_tes_ch_max = T_cold_to_field_est = std::numeric_limits::quiet_NaN(); + charge_avail_est(T_field_htf_out_hot, timestep, q_dot_ch_est, m_dot_tes_ch_max, T_cold_to_field_est); - if (m_dot_cr_to_cv_hot > m_dot_cv_hot_to_cycle && std::max(1.E-4, (m_dot_cr_to_cv_hot - m_dot_cv_hot_to_cycle)) > 1.0001 * std::max(1.E-4, m_dot_tes_ch_max)) + if (m_dot_field > m_dot_cycle && std::max(1.E-4,(m_dot_field - m_dot_cycle)) > 1.0001*std::max(1.E-4,m_dot_tes_ch_max)) { q_dot_heater = std::numeric_limits::quiet_NaN(); - m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); + m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); W_dot_rhtf_pump = std::numeric_limits::quiet_NaN(); q_dot_loss = std::numeric_limits::quiet_NaN(); q_dot_dc_to_htf = std::numeric_limits::quiet_NaN(); @@ -1285,16 +1201,14 @@ int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_am return -1; } - double q_dot_dc_est, m_dot_tes_dc_max, T_hot_to_pc_est; - q_dot_dc_est = m_dot_tes_dc_max = T_hot_to_pc_est = std::numeric_limits::quiet_NaN(); - // Use temperature downstream of cycle-out and cr-to-cold-tank mixer - discharge_avail_est(T_htf_cold_cv_in, timestep, q_dot_dc_est, m_dot_tes_dc_max, T_hot_to_pc_est); + double q_dot_dc_est, m_dot_tes_dc_max, T_hot_to_pc_est; + q_dot_dc_est = m_dot_tes_dc_max = T_hot_to_pc_est = std::numeric_limits::quiet_NaN(); + discharge_avail_est(T_cycle_htf_out_cold, timestep, q_dot_dc_est, m_dot_tes_dc_max, T_hot_to_pc_est); - // If mass flow into the cold tank *from the cycle* is greater than mass flow going from cold tank to field to hot tank - if (m_dot_cv_hot_to_cycle > m_dot_cr_to_cv_hot && std::max(1.E-4, (m_dot_cv_hot_to_cycle - m_dot_cr_to_cv_hot)) > 1.0001 * std::max(1.E-4, m_dot_tes_dc_max)) + if (m_dot_cycle > m_dot_field && std::max(1.E-4,(m_dot_cycle - m_dot_field)) > 1.0001*std::max(1.E-4,m_dot_tes_dc_max)) { q_dot_heater = std::numeric_limits::quiet_NaN(); - m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); + m_dot_cold_tank_to_hot_tank = std::numeric_limits::quiet_NaN(); W_dot_rhtf_pump = std::numeric_limits::quiet_NaN(); q_dot_loss = std::numeric_limits::quiet_NaN(); q_dot_dc_to_htf = std::numeric_limits::quiet_NaN(); @@ -1307,78 +1221,78 @@ int C_csp_two_tank_tes::solve_tes_off_design(double timestep /*s*/, double T_am return -2; } - // serial operation constrained to direct configuration, so HTF leaving TES must pass through another plant component - m_dot_cold_tank_to_hot_tank = 0.0; //[kg/s] + // serial operation constrained to direct configuration, so HTF leaving TES must pass through another plant component + m_dot_cold_tank_to_hot_tank = 0.0; //[kg/s] double q_heater_hot, q_dot_loss_hot, q_heater_cold, q_dot_loss_cold; q_heater_hot = q_dot_loss_hot = q_heater_cold = q_dot_loss_cold = std::numeric_limits::quiet_NaN(); // Call energy balance on hot tank discharge to get average outlet temperature over timestep - mc_hot_tank.energy_balance(timestep, m_dot_cr_to_cv_hot, m_dot_cv_hot_to_cycle, - T_cr_out_hot, T_amb, + mc_hot_tank.energy_balance(timestep, m_dot_field, m_dot_cycle, T_field_htf_out_hot, T_amb, T_cycle_htf_in_hot, q_heater_hot, q_dot_loss_hot); // Call energy balance on cold tank charge to track tank mass and temperature - // Use mass flow and temperature downstream of cycle-out and cr-to-cold-tank mixer - mc_cold_tank.energy_balance(timestep, m_dot_total_to_cv_cold, m_dot_cv_cold_to_cr, - T_htf_cold_cv_in, T_amb, - T_cr_in_cold, q_heater_cold, q_dot_loss_cold); + mc_cold_tank.energy_balance(timestep, m_dot_cycle, m_dot_field, T_cycle_htf_out_cold, T_amb, + T_field_htf_in_cold, q_heater_cold, q_dot_loss_cold); // Set output structure q_dot_heater = q_heater_cold + q_heater_hot; //[MWt] + double m_dot_tes_abs_net = fabs(m_dot_cycle - m_dot_field); //[kg/s] W_dot_rhtf_pump = 0; //[MWe] Tank-to-tank pumping power q_dot_loss = q_dot_loss_cold + q_dot_loss_hot; //[MWt] q_dot_ch_from_htf = 0.0; //[MWt] T_hot_ave = T_cycle_htf_in_hot; //[K] - T_cold_ave = T_cr_in_cold; //[K] + T_cold_ave = T_field_htf_in_cold; //[K] T_hot_final = mc_hot_tank.get_m_T_calc(); //[K] T_cold_final = mc_cold_tank.get_m_T_calc(); //[K] // Net TES discharge - double q_dot_tes_net_discharge = m_cp_field_avg*(m_dot_tes_hot_out*T_hot_ave + m_dot_tes_cold_out*T_cold_ave - - m_dot_cr_to_tes_hot*T_cr_out_hot - m_dot_total_to_cv_cold*T_htf_cold_cv_in) / 1000.0; //[MWt] + double q_dot_tes_net_discharge = m_cp_field_avg * (m_dot_tes_hot_out * T_hot_ave + m_dot_tes_cold_out * T_cold_ave - + m_dot_cr_to_tes_hot * T_field_htf_out_hot - m_dot_pc_to_tes_cold * T_cycle_htf_out_cold) / 1000.0; //[MWt] - if (m_dot_cv_hot_to_cycle >= m_dot_cr_to_cv_hot) + if (m_dot_cycle >= m_dot_field) { + //double T_htf_ave = 0.5*(T_cycle_htf_in_hot + T_cycle_htf_out_cold); //[K] + //double cp_htf_ave = mc_field_htfProps.Cp(T_htf_ave); //[kJ/kg-K] + //q_dot_dc_to_htf = (m_dot_cycle - m_dot_field) * cp_htf_ave*(T_cycle_htf_in_hot - T_cycle_htf_out_cold) / 1000.0; //[MWt] q_dot_ch_from_htf = 0.0; - q_dot_dc_to_htf = q_dot_tes_net_discharge; //[MWt] + q_dot_dc_to_htf = q_dot_tes_net_discharge; //[MWt] } else { + //double T_htf_ave = 0.5*(T_field_htf_out_hot + T_field_htf_in_cold); //[K] + //double cp_htf_ave = mc_field_htfProps.Cp(T_htf_ave); //[kJ/kg-K] q_dot_dc_to_htf = 0.0; + //q_dot_ch_from_htf = (m_dot_field - m_dot_cycle) * cp_htf_ave*(T_field_htf_out_hot - T_field_htf_in_cold) / 1000.0; //[MWt] - q_dot_ch_from_htf = -q_dot_tes_net_discharge; //[MWt] + q_dot_ch_from_htf = -q_dot_tes_net_discharge; //[MWt] } } - s_outputs.m_q_heater = q_dot_heater; - s_outputs.m_q_dot_dc_to_htf = q_dot_dc_to_htf; - s_outputs.m_q_dot_ch_from_htf = q_dot_ch_from_htf; - - s_outputs.m_m_dot_cr_to_tes_hot = m_dot_cr_to_tes_hot; //[kg/s] - s_outputs.m_m_dot_cr_to_tes_cold = m_dot_cr_to_tes_cold; //[kg/s] - s_outputs.m_m_dot_tes_hot_out = m_dot_tes_hot_out; //[kg/s] - s_outputs.m_m_dot_pc_to_tes_cold = m_dot_pc_to_tes_cold; //[kg/s] - s_outputs.m_m_dot_tes_cold_out = m_dot_tes_cold_out; //[kg/s] - s_outputs.m_m_dot_tes_cold_in = m_dot_tes_cold_in; //[kg/s] - s_outputs.m_m_dot_field_to_cycle = m_dot_field_to_cycle; //[kg/s] - s_outputs.m_m_dot_cycle_to_field = m_dot_cycle_to_field; //[kg/s] + s_outputs.m_q_heater = q_dot_heater; + s_outputs.m_q_dot_dc_to_htf = q_dot_dc_to_htf; + s_outputs.m_q_dot_ch_from_htf = q_dot_ch_from_htf; - s_outputs.m_T_tes_cold_in = T_htf_cold_cv_in; //[K] + s_outputs.m_m_dot_cr_to_tes_hot = m_dot_cr_to_tes_hot; //[kg/s] + s_outputs.m_m_dot_tes_hot_out = m_dot_tes_hot_out; //[kg/s] + s_outputs.m_m_dot_pc_to_tes_cold = m_dot_pc_to_tes_cold; //[kg/s] + s_outputs.m_m_dot_tes_cold_out = m_dot_tes_cold_out; //[kg/s] + s_outputs.m_m_dot_field_to_cycle = m_dot_field_to_cycle; //[kg/s] + s_outputs.m_m_dot_cycle_to_field = m_dot_cycle_to_field; //[kg/s] - s_outputs.m_m_dot_cold_tank_to_hot_tank = m_dot_cold_tank_to_hot_tank; + s_outputs.m_m_dot_cold_tank_to_hot_tank = m_dot_cold_tank_to_hot_tank; - mc_reported_outputs.value(E_Q_DOT_LOSS, q_dot_loss); //[MWt] - mc_reported_outputs.value(E_W_DOT_HEATER, q_dot_heater); //[MWt] - mc_reported_outputs.value(E_TES_T_HOT, T_hot_final - 273.15); //[C] - mc_reported_outputs.value(E_TES_T_COLD, T_cold_final - 273.15); //[C] - mc_reported_outputs.value(E_M_DOT_TANK_TO_TANK, m_dot_cold_tank_to_hot_tank); //[kg/s] - mc_reported_outputs.value(E_MASS_COLD_TANK, mc_cold_tank.get_m_m_calc()); //[kg] - mc_reported_outputs.value(E_MASS_HOT_TANK, mc_hot_tank.get_m_m_calc()); //[kg] + mc_reported_outputs.value(E_Q_DOT_LOSS, q_dot_loss); //[MWt] + mc_reported_outputs.value(E_W_DOT_HEATER, q_dot_heater); //[MWt] + mc_reported_outputs.value(E_TES_T_HOT, T_hot_final - 273.15); //[C] + mc_reported_outputs.value(E_TES_T_COLD, T_cold_final - 273.15); //[C] + mc_reported_outputs.value(E_M_DOT_TANK_TO_TANK, m_dot_cold_tank_to_hot_tank); //[kg/s] + mc_reported_outputs.value(E_MASS_COLD_TANK, mc_cold_tank.get_m_m_calc()); //[kg] + mc_reported_outputs.value(E_MASS_HOT_TANK, mc_hot_tank.get_m_m_calc()); //[kg] return 0; } @@ -1815,10 +1729,7 @@ void C_csp_two_tank_tes::converged() mc_cold_tank.converged(); mc_hot_tank.converged(); //mc_hx.converged(); - - // Set reported cycle converged values - mc_reported_outputs.value(E_HOT_TANK_HTF_PERC_FINAL, mc_hot_tank.get_mass_avail() / m_mass_total_active * 100.0); - + mc_reported_outputs.set_timestep_outputs(); // The max charge and discharge flow rates should be set at the beginning of each timestep @@ -1826,13 +1737,6 @@ void C_csp_two_tank_tes::converged() // m_m_dot_tes_dc_max = m_m_dot_tes_ch_max = std::numeric_limits::quiet_NaN(); } -void C_csp_two_tank_tes::get_final_from_converged(double& f_V_hot, double& T_hot_tank /*K*/, double& T_cold_tank /*K*/) -{ - f_V_hot = mc_hot_tank.get_mass_avail() / m_mass_total_active; //[-] - T_hot_tank = mc_hot_tank.get_m_T_prev(); //[K] - T_cold_tank = mc_cold_tank.get_m_T_prev(); //[K] -} - void C_csp_two_tank_tes::write_output_intervals(double report_time_start, const std::vector& v_temp_ts_time_end, double report_time_end) { @@ -2404,8 +2308,6 @@ double C_csp_cold_tes::get_degradation_rate() return e_loss / (m_q_pb_design * ms_params.m_ts_hours * 3600.); //s^-1 -- fraction of heat loss per second based on full charge } -void C_csp_cold_tes::reset_storage_to_initial_state() {} - void C_csp_cold_tes::discharge_avail_est(double T_cold_K, double step_s, double &q_dot_dc_est, double &m_dot_field_est, double &T_hot_field_est) { double f_storage = 0.0; // for now, hardcode such that storage always completely discharges diff --git a/tcs/csp_solver_two_tank_tes.h b/tcs/csp_solver_two_tank_tes.h index ceb5cc392..ee71ca86e 100644 --- a/tcs/csp_solver_two_tank_tes.h +++ b/tcs/csp_solver_two_tank_tes.h @@ -102,8 +102,6 @@ class C_storage_tank double get_vol_frac(); - double get_mass_avail(); //[kg] - void init(HTFProperties htf_class_in, double V_tank /*m3*/, double h_tank /*m*/, double h_min /*m*/, double u_tank /*W/m2-K*/, double tank_pairs /*-*/, double T_htr /*K*/, double max_q_htr /*MWt*/, @@ -112,7 +110,7 @@ class C_storage_tank double m_dot_available(double f_unavail, double timestep); - void energy_balance(double timestep /*s*/, double m_dot_in /*kg/s*/, double m_dot_out /*kg/s*/, + void energy_balance(double timestep /*s*/, double m_dot_in, double m_dot_out, double T_in /*K*/, double T_amb /*K*/, double &T_ave /*K*/, double &q_heater /*MW*/, double &q_dot_loss /*MW*/); @@ -143,12 +141,10 @@ class C_csp_two_tank_tes : public C_csp_tes // Member data bool m_is_tes; - bool m_is_cr_to_cold_tank_allowed; double m_vol_tank; //[m3] volume of *one temperature*, i.e. vol_tank = total cold storage = total hot storage double m_V_tank_active; //[m^3] available volume (considering h_min) of *one temperature* double m_q_pb_design; //[Wt] thermal power to power cycle at design double m_V_tank_hot_ini; //[m^3] Initial volume in hot storage tank - double m_mass_total_active; //[kg] Total HTF mass at design point inlet/outlet T double m_cp_field_avg; //[kJ/kg-K] @@ -168,8 +164,7 @@ class C_csp_two_tank_tes : public C_csp_tes E_TES_T_COLD, //[C] TES final cold tank temperature E_M_DOT_TANK_TO_TANK, //[kg/s] Tank to tank mass flow rate (indirect TES) E_MASS_COLD_TANK, //[kg] Mass in cold tank at end of timestep - E_MASS_HOT_TANK, //[kg] Mass in hot tank at end of timestep - E_HOT_TANK_HTF_PERC_FINAL //[%] Final percent fill of available hot tank mass + E_MASS_HOT_TANK //[kg] Mass in hot tank at end of timestep }; C_csp_reported_outputs mc_reported_outputs; @@ -271,8 +266,6 @@ class C_csp_two_tank_tes : public C_csp_tes virtual bool does_tes_exist(); - virtual bool is_cr_to_cold_allowed(); - virtual double get_hot_temp(); virtual double get_cold_temp(); @@ -287,8 +280,6 @@ class C_csp_two_tank_tes : public C_csp_tes virtual double get_degradation_rate(); // s^-1 - virtual void reset_storage_to_initial_state(); - virtual void discharge_avail_est(double T_cold_K, double step_s, double &q_dot_dc_est /*MWt*/, double &m_dot_field_est /*kg/s*/, double &T_hot_field_est /*K*/); @@ -302,10 +293,9 @@ class C_csp_two_tank_tes : public C_csp_tes double & q_dot_loss /*MWt*/, double & q_dot_dc_to_htf /*MWt*/, double & q_dot_ch_from_htf /*MWt*/, double & T_hot_ave /*K*/, double & T_cold_ave /*K*/, double & T_hot_final /*K*/, double & T_cold_final /*K*/); - virtual int solve_tes_off_design(double timestep /*s*/, double T_amb /*K*/, - double m_dot_cr_to_cv_hot /*kg/s*/, double m_dot_cv_hot_to_cycle /*kg/s*/, double m_dot_cr_to_cv_cold /*kg/s*/, - double T_cr_out_hot /*K*/, double T_cycle_out_cold /*K*/, - double & T_cycle_htf_in_hot /*K*/, double & T_cr_in_cold /*K*/, + virtual int solve_tes_off_design(double timestep /*s*/, double T_amb /*K*/, double m_dot_field /*kg/s*/, double m_dot_cycle /*kg/s*/, + double T_field_htf_out_hot /*K*/, double T_cycle_htf_out_cold /*K*/, + double & T_cycle_htf_in_hot /*K*/, double & T_field_htf_in_cold /*K*/, C_csp_tes::S_csp_tes_outputs& outputs); bool charge(double timestep /*s*/, double T_amb /*K*/, double m_dot_htf_in /*kg/s*/, @@ -316,8 +306,6 @@ class C_csp_two_tank_tes : public C_csp_tes virtual void converged(); - void get_final_from_converged(double& f_V_hot /*-*/, double& T_hot_tank /*K*/, double& T_cold_tank /*K*/); - virtual void write_output_intervals(double report_time_start, const std::vector& v_temp_ts_time_end, double report_time_end); @@ -533,8 +521,6 @@ class C_csp_cold_tes //Class for cold storage based on two tank tes ARD double get_degradation_rate(); // s^-1 - virtual void reset_storage_to_initial_state(); - void discharge_avail_est(double T_cold_K, double step_s, double &q_dot_dc_est, double &m_dot_field_est, double &T_hot_field_est); void charge_avail_est(double T_hot_K, double step_s, double &q_dot_ch_est, double &m_dot_field_est, double &T_cold_field_est); diff --git a/test/ssc_test/cmod_tcsdirect_steam_test.cpp b/test/ssc_test/cmod_tcsdirect_steam_test.cpp index f7781c4b3..d5e9b97f3 100644 --- a/test/ssc_test/cmod_tcsdirect_steam_test.cpp +++ b/test/ssc_test/cmod_tcsdirect_steam_test.cpp @@ -15,14 +15,14 @@ NAMESPACE_TEST(csp_tower, SteamTowerCmod, Default_NoFinancial) int errors = steam_tower.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 263809742, kErrorToleranceHi); - EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 30.08, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 296630582, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2635, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 92.64, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 55716, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 263809742, kErrorToleranceLo); + EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 30.08, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 296630582, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2635, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 92.64, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 55716, kErrorToleranceLo); } } @@ -39,14 +39,14 @@ NAMESPACE_TEST(csp_tower, SteamTowerCmod, EvaporativeCondenser_NoFinancial) int errors = steam_tower.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 280975356, kErrorToleranceHi); - EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 32.03, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 307624737, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2806, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 95.14, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 893431, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 280975356, kErrorToleranceLo); + EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 32.03, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 307624737, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2806, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 95.14, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 893431, kErrorToleranceLo); } } @@ -63,14 +63,14 @@ NAMESPACE_TEST(csp_tower, SteamTowerCmod, HybridCondenser_NoFinancial) int errors = steam_tower.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 268116066, kErrorToleranceHi); - EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 30.57, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 304066728, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2678, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 91.85, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 55716, kErrorToleranceHi); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_energy"), 268116066, kErrorToleranceLo); + EXPECT_NEAR(steam_tower.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("capacity_factor"), 30.57, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_W_cycle_gross"), 304066728, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("kwh_per_kw"), 2678, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("conversion_factor"), 91.85, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(steam_tower.GetOutput("annual_total_water_use"), 55716, kErrorToleranceLo); } } diff --git a/test/ssc_test/cmod_tcsfresnel_molten_salt_test.cpp b/test/ssc_test/cmod_tcsfresnel_molten_salt_test.cpp index 1fced5be9..036165f1d 100644 --- a/test/ssc_test/cmod_tcsfresnel_molten_salt_test.cpp +++ b/test/ssc_test/cmod_tcsfresnel_molten_salt_test.cpp @@ -14,14 +14,14 @@ NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, Default_NoFinancial) int errors = power_fresnel.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 337249089, kErrorToleranceHi); - EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.50, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 372639466, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3372, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.27, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 30058, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 337249089, kErrorToleranceLo); + EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.50, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 372639466, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3372, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.27, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 30058, kErrorToleranceLo); } } @@ -35,14 +35,14 @@ NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, SequencedDefocusing_NoFinancial) int errors = power_fresnel.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 337249089, kErrorToleranceHi); - EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.50, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 372639466, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3372, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.27, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 30058, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 337249089, kErrorToleranceLo); + EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.50, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 372639466, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3372, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.27, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 30058, kErrorToleranceLo); } } @@ -60,14 +60,14 @@ NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, TherminolVp1Htf_NoFinancial) int errors = power_fresnel.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 336171001, kErrorToleranceHi); - EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.38, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 371306661, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3362, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.31, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 29944, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 336171001, kErrorToleranceLo); + EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 38.38, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 371306661, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 3362, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 94.31, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 29944, kErrorToleranceLo); } } @@ -81,14 +81,14 @@ NAMESPACE_TEST(csp_fresnel, PowerFresnelCmod, SolarPositioinOpticalChar_NoFinanc int errors = power_fresnel.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 228344862, kErrorToleranceHi); - EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 26.07, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 255036717, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 2283, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 93.26, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 21776, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_energy"), 228344862, kErrorToleranceLo); + EXPECT_NEAR(power_fresnel.GetOutput("annual_fuel_usage"), 0, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("capacity_factor"), 26.07, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_W_cycle_gross"), 255036717, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("kwh_per_kw"), 2283, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("conversion_factor"), 93.26, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_fresnel.GetOutput("annual_total_water_use"), 21776, kErrorToleranceLo); } } diff --git a/test/ssc_test/cmod_tcsmolten_salt_test.cpp b/test/ssc_test/cmod_tcsmolten_salt_test.cpp index cdc9fa847..48e00f90c 100644 --- a/test/ssc_test/cmod_tcsmolten_salt_test.cpp +++ b/test/ssc_test/cmod_tcsmolten_salt_test.cpp @@ -15,19 +15,19 @@ NAMESPACE_TEST(csp_tower, PowerTowerCmod, Default_NoFinancial) int errors = power_tower.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 571408807, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 63.02, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 638478912, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5521, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 89.55, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98402, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 571408807, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 63.02, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 638478912, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5521, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 89.55, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98402, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceLo); } //ssc_data_t defaults = singleowner_defaults(); @@ -48,19 +48,19 @@ NAMESPACE_TEST(csp_tower, PowerTowerCmod, SlidingPressure_NoFinancial) EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 578111750, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 63.76, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 645396296, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5586, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 89.57, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98238, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 578111750, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 63.76, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 645396296, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5586, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 89.57, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98238, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceLo); } } @@ -73,19 +73,19 @@ NAMESPACE_TEST(csp_tower, PowerTowerCmod, FlowPattern_NoFinancial) EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 519995603, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 57.35, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 642716926, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5024, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 80.90, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98678, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_energy"), 519995603, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("land_area_base"), 1847, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("capacity_factor"), 57.35, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_W_cycle_gross"), 642716926, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("kwh_per_kw"), 5024, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("conversion_factor"), 80.90, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("N_hel"), 8790, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("rec_height"), 21.60, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("A_sf"), 1269054, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("D_rec"), 17.65, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("annual_total_water_use"), 98678, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("csp.pt.cost.total_land_area"), 1892, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_tower.GetOutput("h_tower"), 193.5, kErrorToleranceLo); } } diff --git a/test/ssc_test/cmod_tcstrough_empirical_test.cpp b/test/ssc_test/cmod_tcstrough_empirical_test.cpp index e3a7551b4..ba5e008d1 100644 --- a/test/ssc_test/cmod_tcstrough_empirical_test.cpp +++ b/test/ssc_test/cmod_tcstrough_empirical_test.cpp @@ -14,14 +14,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, Default_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 344049128, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.31, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403814011, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3444, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.75, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 344049128, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.31, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403814011, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3444, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.75, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); } } @@ -37,14 +37,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, SolarSaltHtf_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 340377809, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 38.89, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 399556634, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3407, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.74, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 340377809, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 38.89, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 399556634, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3407, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.74, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); } } @@ -68,14 +68,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, EuroTrough_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 343687390, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.27, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 402926405, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3440, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.85, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 343687390, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.27, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 402926405, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3440, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.85, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); } } @@ -103,14 +103,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, LuzCermetHce_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 310891768, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 35.53, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 369630914, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3112, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 87.61, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 310891768, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 35.53, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 369630914, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3112, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 87.61, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); } } @@ -147,14 +147,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, PowerCycle_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 350313341, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 40.03, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 427283458, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3507, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 85.40, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 350313341, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 40.03, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 427283458, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3507, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 85.40, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); } } @@ -169,14 +169,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, TherminolHtf_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 343856219, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.29, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403443026, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3444, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.78, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 343856219, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 39.29, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403443026, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3444, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.78, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); } } @@ -196,14 +196,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, ParasiticElectric_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 357850265, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 40.89, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403814011, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3582, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 92.31, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 357850265, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 40.89, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 403814011, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3582, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 92.31, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); } } @@ -219,14 +219,14 @@ NAMESPACE_TEST(csp_trough, EmpiricalTroughCmod, Phoenix_NoFinancial) int errors = empirical_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 332549669, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 38.00, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 391115710, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3329, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.56, kErrorToleranceHi); - EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceHi); - EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceHi); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_energy"), 332549669, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("annual_fuel_usage"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("capacity_factor"), 38.00, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("annual_W_cycle_gross"), 391115710, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("kwh_per_kw"), 3329, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("conversion_factor"), 88.56, kErrorToleranceLo); + EXPECT_NEAR_FRAC(empirical_trough.GetOutput("system_heat_rate"), 3.413, kErrorToleranceLo); + EXPECT_NEAR(empirical_trough.GetOutput("system_use_lifetime_output"), 0., kErrorToleranceLo); } } diff --git a/test/ssc_test/cmod_trough_physical_iph_test.cpp b/test/ssc_test/cmod_trough_physical_iph_test.cpp index 9c4dc17be..6ce20846c 100644 --- a/test/ssc_test/cmod_trough_physical_iph_test.cpp +++ b/test/ssc_test/cmod_trough_physical_iph_test.cpp @@ -14,12 +14,12 @@ NAMESPACE_TEST(csp_trough, HeatTroughCmod, Default_NoFinancial) int errors = heat_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_gross_energy"), 24328026, kErrorToleranceHi); - EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_energy"), 24327778, kErrorToleranceHi); - EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_electricity_consumption"), 93310, kErrorToleranceHi); - EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_thermal_consumption"), 247.67, kErrorToleranceHi); - EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_tes_freeze_protection"), 247.67, kErrorToleranceHi); - EXPECT_NEAR(heat_trough.GetOutput("annual_field_freeze_protection"), 0., kErrorToleranceHi); - EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_total_water_use"), 176.3, kErrorToleranceHi); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_gross_energy"), 24328026, kErrorToleranceLo); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_energy"), 24327778, kErrorToleranceLo); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_electricity_consumption"), 93310, kErrorToleranceLo); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_thermal_consumption"), 247.67, kErrorToleranceLo); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_tes_freeze_protection"), 247.67, kErrorToleranceLo); + EXPECT_NEAR(heat_trough.GetOutput("annual_field_freeze_protection"), 0., kErrorToleranceLo); + EXPECT_NEAR_FRAC(heat_trough.GetOutput("annual_total_water_use"), 176.3, kErrorToleranceLo); } } diff --git a/test/ssc_test/cmod_trough_physical_test.cpp b/test/ssc_test/cmod_trough_physical_test.cpp index ad44e1745..e5a11f701 100644 --- a/test/ssc_test/cmod_trough_physical_test.cpp +++ b/test/ssc_test/cmod_trough_physical_test.cpp @@ -14,15 +14,15 @@ NAMESPACE_TEST(csp_trough, PowerTroughCmod, Default_NoFinancial) int errors = power_trough.RunModule(); EXPECT_FALSE(errors); if (!errors) { - EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_energy"), 369272759, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_thermal_consumption"), 596547, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_tes_freeze_protection"), 558505, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_field_freeze_protection"), 38042, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_trough.GetOutput("capacity_factor"), 42.20, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_W_cycle_gross"), 420379150, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_trough.GetOutput("kwh_per_kw"), 3696, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_trough.GetOutput("conversion_factor"), 87.84, kErrorToleranceHi); - EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_total_water_use"), 80708, kErrorToleranceHi); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_energy"), 369272759, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_thermal_consumption"), 596547, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_tes_freeze_protection"), 558505, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_field_freeze_protection"), 38042, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("capacity_factor"), 42.20, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_W_cycle_gross"), 420379150, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("kwh_per_kw"), 3696, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("conversion_factor"), 87.84, kErrorToleranceLo); + EXPECT_NEAR_FRAC(power_trough.GetOutput("annual_total_water_use"), 80708, kErrorToleranceLo); } //ssc_data_t defaults = singleowner_defaults(); From 5f331ff9fa71a1c29044cefece1c3d6402d44395 Mon Sep 17 00:00:00 2001 From: janinefreeman Date: Tue, 23 Feb 2021 17:05:50 -0700 Subject: [PATCH 12/12] fix typo in comment --- ssc/common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssc/common.cpp b/ssc/common.cpp index f37b53a41..9ea611e08 100644 --- a/ssc/common.cpp +++ b/ssc/common.cpp @@ -1230,7 +1230,7 @@ bool weatherdata::check_continuous_single_year(bool leapyear) ts_per_hour = (int)(m_nRecords / 8760); double ts_min = 60. / ts_per_hour; //determine the number of minutes of each timestep - //next, check if the data has leap day (feb 29). need to do this because some toold pass in 8760 data that contains feb 29 and not dec 31 + //next, check if the data has leap day (feb 29). need to do this because some tools pass in 8760 data that contains feb 29 and not dec 31 bool has_leapday = false; int leapDayNoon = 1429 * ts_per_hour; //look for the index of noon on leap day. noon on leap day is hour 1429 of the year if (this->m_data[leapDayNoon]->month == 2 && this->m_data[leapDayNoon]->day == 29) //check noon on what would be feb 29 if it's in the data