From 337a4b2256539402b86279efb51446c231bd3c42 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Wed, 12 Apr 2023 15:34:26 -0600 Subject: [PATCH 01/94] Add sco2 htr bypass clas to tcs project --- tcs/CMakeLists.txt | 2 + tcs/sco2_htrbypass_cycle.cpp | 41 +++++ tcs/sco2_htrbypass_cycle.h | 310 +++++++++++++++++++++++++++++++++++ 3 files changed, 353 insertions(+) create mode 100644 tcs/sco2_htrbypass_cycle.cpp create mode 100644 tcs/sco2_htrbypass_cycle.h diff --git a/tcs/CMakeLists.txt b/tcs/CMakeLists.txt index fc2b9e8d78..521c4ff407 100644 --- a/tcs/CMakeLists.txt +++ b/tcs/CMakeLists.txt @@ -50,6 +50,7 @@ set(TCS_SRC ptes_solver_design_point.cpp sam_type250_input_generator.cpp sco2_cycle_components.cpp + sco2_htrbypass_cycle.cpp sco2_partialcooling_cycle.cpp sco2_pc_csp_int.cpp sco2_power_cycle.cpp @@ -145,6 +146,7 @@ set(TCS_SRC sam_csp_util.h sco2_cycle_components.h sco2_cycle_templates.h + sco2_htrbypass_cycle.h sco2_partialcooling_cycle.h sco2_pc_csp_int.h sco2_power_cycle.h diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp new file mode 100644 index 0000000000..5b2e317cff --- /dev/null +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -0,0 +1,41 @@ +/* +BSD 3-Clause License + +Copyright (c) Alliance for Sustainable Energy, LLC. See also https://github.com/NREL/ssc/blob/develop/LICENSE +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "sco2_htrbypass_cycle.h" +#include "sco2_cycle_components.h" + +#include "CO2_properties.h" + +void C_HTRBypass_Cycle::design_core_standard(int& error_code) +{ + +} diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h new file mode 100644 index 0000000000..ad20ee6d92 --- /dev/null +++ b/tcs/sco2_htrbypass_cycle.h @@ -0,0 +1,310 @@ +/* +BSD 3-Clause License + +Copyright (c) Alliance for Sustainable Energy, LLC. See also https://github.com/NREL/ssc/blob/develop/LICENSE +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __SCO2_HTRBYPASS_ +#define __SCO2_HTRBYPASS_ + +#include "sco2_cycle_components.h" +#include "sco2_cycle_templates.h" + +#include "heat_exchangers.h" +#include "CO2_properties.h" + + +class C_HTRBypass_Cycle : public C_sco2_cycle_core +{ + + enum E_htrbypass_cycle_state_points + { + // index values for c++ 0-based vectors for temperature, pressure, etc. + MC_IN = 0, // Main compressor inlet + MC_OUT, // Main compressor outlet + LTR_HP_OUT, // Low temp recuperator high pressure outlet + MIXER_OUT, // Mixer: LTR_HP_OUT + Recompressor outlet + HTR_HP_OUT, // High temp recuperator high pressure outlet + TURB_IN, // Turbine inlet + TURB_OUT, // Turbine outlet + HTR_LP_OUT, // High temp recuperator low pressure outlet + LTR_LP_OUT, // Low temp recuperator low pressure outlet + RC_OUT, // Recompresor outlet + BYPASS_OUT, + MIXER2_OUT, + + + END_SCO2_HTRBP_STATES + }; + + struct S_design_parameters + { + // HTR Bypass ONLY parameters + double m_T_HTF_bp_out; // HTF Bypass HTX Outlet Temperature + double m_bp_frac; // Fraction of flow that bypasses HTR HP via bypass HTX + + + + // Parameters SHARED with recompression + + double m_P_mc_in; //[kPa] Compressor inlet pressure + double m_P_mc_out; //[kPa] Compressor outlet pressure + + // LTR thermal design + int m_LTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness + double m_LTR_UA; //[kW/K] target LTR conductance + double m_LTR_min_dT; //[K] target LTR minimum temperature difference + double m_LTR_eff_target; //[-] target LTR effectiveness + double m_LTR_eff_max; //[-] Maximum allowable effectiveness in LT recuperator + NS_HX_counterflow_eqs::E_UA_target_type m_LTR_od_UA_target_type; + + // HTR thermal design + int m_HTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness + double m_HTR_UA; //[kW/K] target HTR conductance + double m_HTR_min_dT; //[K] target HTR min temperature difference + double m_HTR_eff_target; //[-] target HTR effectiveness + double m_HTR_eff_max; //[-] Maximum allowable effectiveness in HT recuperator + NS_HX_counterflow_eqs::E_UA_target_type m_HTR_od_UA_target_type; + + double m_recomp_frac; //[-] Fraction of flow that bypasses the precooler and the main compressor at the design point + double m_des_tol; //[-] Convergence tolerance + + // Air cooler parameters + bool m_is_des_air_cooler; //[-] False will skip physical air cooler design. UA will not be available for cost models. + + int m_des_objective_type; //[2] = min phx deltat then max eta, [else] max eta + double m_min_phx_deltaT; //[C] + + + S_design_parameters() + { + m_P_mc_in = m_P_mc_out = + m_LTR_UA = m_LTR_min_dT = m_LTR_eff_target = m_LTR_eff_max = + m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = + m_recomp_frac = + m_des_tol = + std::numeric_limits::quiet_NaN(); + + // Recuperator design target codes + m_LTR_target_code = 1; // default to target conductance + m_LTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; + m_HTR_target_code = 1; // default to target conductance + m_HTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; + + // Default to standard optimization to maximize cycle efficiency + m_des_objective_type = 1; + m_min_phx_deltaT = 0.0; //[C] + + // Air cooler default + m_is_des_air_cooler = true; + + } + + + }; + + struct S_opt_design_parameters + { + double m_UA_rec_total; //[kW/K] Total design-point recuperator UA + // LTR thermal design + int m_LTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness + double m_LTR_UA; //[kW/K] target LTR conductance + double m_LTR_min_dT; //[K] target LTR minimum temperature difference + double m_LTR_eff_target; //[-] target LTR effectiveness + double m_LTR_eff_max; //[-] Maximum allowable effectiveness in LT recuperator + NS_HX_counterflow_eqs::E_UA_target_type m_LTR_od_UA_target_type; + // HTR thermal design + int m_HTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness + double m_HTR_UA; //[kW/K] target HTR conductance + double m_HTR_min_dT; //[K] target HTR min temperature difference + double m_HTR_eff_target; //[-] target HTR effectiveness + double m_HTR_eff_max; //[-] Maximum allowable effectiveness in HT recuperator + NS_HX_counterflow_eqs::E_UA_target_type m_HTR_od_UA_target_type; + // + double m_des_tol; //[-] Convergence tolerance + double m_des_opt_tol; //[-] Optimization tolerance + + // Air cooler parameters + bool m_is_des_air_cooler; //[-] False will skip physical air cooler design. UA will not be available for cost models. + + int m_des_objective_type; //[2] = min phx deltat then max eta, [else] max eta + double m_min_phx_deltaT; //[C] + + double m_P_mc_out_guess; //[kPa] Initial guess for main compressor outlet pressure + bool m_fixed_P_mc_out; //[-] if true, P_mc_out is fixed at P_mc_out_guess + + double m_PR_HP_to_LP_guess; //[-] Initial guess for ratio of P_mc_out to P_LP_in + bool m_fixed_PR_HP_to_LP; //[-] if true, ratio of P_mc_out to P_mc_in is fixed at PR_mc_guess + + double m_recomp_frac_guess; //[-] Initial guess for design-point recompression fraction + bool m_fixed_recomp_frac; //[-] if true, recomp_frac is fixed at recomp_frac_guess + + double m_LT_frac_guess; //[-] Initial guess for fraction of UA_rec_total that is in the low-temperature recuperator + bool m_fixed_LT_frac; //[-] if true, LT_frac is fixed at LT_frac_guess + + S_opt_design_parameters() + { + m_UA_rec_total = + m_LTR_UA = m_LTR_min_dT = m_LTR_eff_target = m_LTR_eff_max = + m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = + m_des_tol = m_des_opt_tol = + m_P_mc_out_guess = m_PR_HP_to_LP_guess = m_recomp_frac_guess = m_LT_frac_guess = + std::numeric_limits::quiet_NaN(); + + // Recuperator design target codes + m_LTR_target_code = 1; // default to target conductance + m_LTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; + m_HTR_target_code = 1; // default to target conductance + m_HTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; + + // Air cooler default + m_is_des_air_cooler = true; + + // Default to standard optimization to maximize cycle efficiency + m_des_objective_type = 1; + m_min_phx_deltaT = 0.0; //[C] + + } + + + }; + +private: + + // Component classes + C_turbine m_t; + C_comp_multi_stage m_mc_ms; + C_comp_multi_stage m_rc_ms; + C_HeatExchanger m_PHX, m_PC, m_BP; + + C_HX_co2_to_co2_CRM mc_LT_recup; + C_HX_co2_to_co2_CRM mc_HT_recup; + + C_CO2_to_air_cooler mc_air_cooler; + + // Input/Ouput structures for class methods + S_design_parameters ms_des_par; + S_opt_design_parameters ms_opt_des_par; + + // Results from last 'design' solution + std::vector m_temp_last, m_pres_last, m_enth_last, m_entr_last, m_dens_last; // thermodynamic states (K, kPa, kJ/kg, kJ/kg-K, kg/m3) + double m_eta_thermal_calc_last; + double m_W_dot_net_last; + double m_m_dot_mc, m_m_dot_rc, m_m_dot_t; + double m_Q_dot_PHX, m_Q_dot_bypass, m_eta_bypass; + double m_W_dot_mc, m_W_dot_rc, m_W_dot_t, m_W_dot_mc_bypass; + double m_objective_metric_last; + + // Structures and data for optimization + S_design_parameters ms_des_par_optimal; + double m_objective_metric_opt; + + // Structures and data for auto-optimization + double m_objective_metric_auto_opt; + S_design_parameters ms_des_par_auto_opt; + + // New opt + bool m_found_opt; + double m_eta_phx_max; + double m_UA_diff_eta_max; + double m_over_deltaP_eta_max; + + void design_core(int& error_code); + + void design_core_standard(int& error_code); + + void opt_design_core(int& error_code); + + void auto_opt_design_core(int& error_code); + + void finalize_design(int& error_code); + + +public: + + C_HTRBypass_Cycle(C_sco2_cycle_core::E_turbo_gen_motor_config turbo_gen_motor_config, + double eta_generator, + double T_mc_in, + double W_dot_net, + double T_t_in, double P_high_limit, + std::vector DP_LTR, std::vector DP_HTR, + std::vector DP_PC_main, std::vector DP_PHX, + int LTR_N_sub_hxrs, int HTR_N_sub_hxrs, + double eta_mc, int mc_comp_model_code, + double eta_rc, + double eta_t, double N_turbine, + double frac_fan_power, double eta_fan, double deltaP_cooler_frac, + int N_nodes_pass, + double T_amb_des, double elevation) : + C_sco2_cycle_core(turbo_gen_motor_config, + eta_generator, + T_mc_in, + W_dot_net, + T_t_in, P_high_limit, + DP_LTR, DP_HTR, + DP_PC_main, DP_PHX, + LTR_N_sub_hxrs, HTR_N_sub_hxrs, + eta_mc, mc_comp_model_code, + eta_rc, + eta_t, N_turbine, + frac_fan_power, eta_fan, deltaP_cooler_frac, + N_nodes_pass, + T_amb_des, elevation) + { + m_temp_last.resize(END_SCO2_HTRBP_STATES); + std::fill(m_temp_last.begin(), m_temp_last.end(), std::numeric_limits::quiet_NaN()); + m_pres_last = m_enth_last = m_entr_last = m_dens_last = m_temp_last; + + m_eta_thermal_calc_last = m_m_dot_mc = m_m_dot_rc = m_m_dot_t = std::numeric_limits::quiet_NaN(); + m_Q_dot_PHX = m_Q_dot_bypass = m_eta_bypass = std::numeric_limits::quiet_NaN(); + m_W_dot_mc = m_W_dot_rc = m_W_dot_t = m_W_dot_mc_bypass = std::numeric_limits::quiet_NaN(); + m_objective_metric_last = std::numeric_limits::quiet_NaN(); + + m_W_dot_net_last = std::numeric_limits::quiet_NaN(); + + m_objective_metric_opt = std::numeric_limits::quiet_NaN(); + m_objective_metric_auto_opt = std::numeric_limits::quiet_NaN(); + + + } + + CO2_state mc_co2_props; + + ~C_HTRBypass_Cycle() {}; + + void design(S_design_parameters& des_par_in, int& error_code); + + void opt_design(S_opt_design_parameters& opt_des_par_in, int& error_code); + + void reset_ms_od_turbo_bal_csp_solved(); + + int auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in); + +}; +#endif From 930f80e258724709cc56b6a14f5b0d74889d9a4a Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Fri, 14 Apr 2023 15:45:57 -0600 Subject: [PATCH 02/94] Add blank functions to htr bypass. Begin adding call from pc_csp_int --- tcs/sco2_htrbypass_cycle.cpp | 108 +++++++++++++++++++++++++++++++++++ tcs/sco2_htrbypass_cycle.h | 53 +++++++++++++++++ tcs/sco2_pc_csp_int.cpp | 30 +++++++++- 3 files changed, 188 insertions(+), 3 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 5b2e317cff..51d0c2b185 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -35,7 +35,115 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "CO2_properties.h" + + +void C_HTRBypass_Cycle::design_core(int& error_code) +{ + design_core_standard(error_code); +} + void C_HTRBypass_Cycle::design_core_standard(int& error_code) { + int x = 0; +} + +void C_HTRBypass_Cycle::opt_design_core(int& error_code) +{ +} + +void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) +{ +} + +void C_HTRBypass_Cycle::finalize_design(int& error_code) +{ +} + +// Public Methods + +void C_HTRBypass_Cycle::design(S_design_parameters& des_par_in, int& error_code) +{ + ms_des_par = des_par_in; + + int design_error_code = 0; + + design_core(design_error_code); + + if (design_error_code != 0) + { + error_code = design_error_code; + return; + } + + finalize_design(design_error_code); + error_code = design_error_code; +} + +void C_HTRBypass_Cycle::opt_design(S_opt_design_parameters& opt_des_par_in, int& error_code) +{ +} + +void C_HTRBypass_Cycle::reset_ms_od_turbo_bal_csp_solved() +{ +} + +int C_HTRBypass_Cycle::auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in) +{ + return 0; +} + +int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg) +{ + return 0; +} + +int C_HTRBypass_Cycle::off_design_fix_shaft_speeds(S_od_par& od_phi_par_in, double od_tol) +{ + return 0; +} + +int C_HTRBypass_Cycle::solve_OD_all_coolers_fan_power(double T_amb, double od_tol, double& W_dot_fan) +{ + return 0; +} + +int C_HTRBypass_Cycle::solve_OD_mc_cooler_fan_power(double T_amb, double od_tol, double& W_dot_mc_cooler_fan, double& P_co2_out) +{ + return 0; +} + +int C_HTRBypass_Cycle::solve_OD_pc_cooler_fan_power(double T_amb, double od_tol, double& W_dot_pc_cooler_fan, double& P_co2_out) +{ + return 0; +} + +double C_HTRBypass_Cycle::get_od_temp(int n_state_point) +{ + return 0.0; +} + +double C_HTRBypass_Cycle::get_od_pres(int n_state_point) +{ + return 0.0; +} + +void C_HTRBypass_Cycle::check_od_solution(double& diff_m_dot, double& diff_E_cycle, double& diff_Q_LTR, double& diff_Q_HTR) +{ +} + +void C_HTRBypass_Cycle::set_od_temp(int n_state_point, double temp_K) +{ +} + +void C_HTRBypass_Cycle::set_od_pres(int n_state_point, double pres_kPa) +{ +} + +void C_HTRBypass_Cycle::off_design_recompressor(double T_in, double P_in, double m_dot, double P_out, double tol, int& error_code, double& T_out) +{ +} + +void C_HTRBypass_Cycle::estimate_od_turbo_operation(double T_mc_in, double P_mc_in, double f_recomp, double T_t_in, double phi_mc, int& mc_error_code, double& mc_w_tip_ratio, double& P_mc_out, int& rc_error_code, double& rc_w_tip_ratio, double& rc_phi, bool is_update_ms_od_solved) +{ } diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index ad20ee6d92..c1ff1824f4 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -42,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. class C_HTRBypass_Cycle : public C_sco2_cycle_core { +public: enum E_htrbypass_cycle_state_points { @@ -306,5 +307,57 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core int auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in); + + + + + + // Unused + + int auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg); + + int off_design_fix_shaft_speeds(S_od_par& od_phi_par_in, double od_tol /*-*/); + + virtual int solve_OD_all_coolers_fan_power(double T_amb /*K*/, double od_tol /*-*/, double& W_dot_fan /*MWe*/); + + virtual int solve_OD_mc_cooler_fan_power(double T_amb /*K*/, double od_tol /*-*/, double& W_dot_mc_cooler_fan /*MWe*/, double& P_co2_out /*kPa*/); + + virtual int solve_OD_pc_cooler_fan_power(double T_amb /*K*/, double od_tol /*-*/, double& W_dot_pc_cooler_fan /*MWe*/, double& P_co2_out /*kPa*/); + + double get_od_temp(int n_state_point); + + double get_od_pres(int n_state_point); + + virtual void check_od_solution(double& diff_m_dot, double& diff_E_cycle, + double& diff_Q_LTR, double& diff_Q_HTR); + + void set_od_temp(int n_state_point, double temp_K); + + void set_od_pres(int n_state_point, double pres_kPa); + + void off_design_recompressor(double T_in, double P_in, double m_dot, double P_out, double tol /*-*/, int& error_code, double& T_out); + + void estimate_od_turbo_operation(double T_mc_in /*K*/, double P_mc_in /*kPa*/, double f_recomp /*-*/, double T_t_in /*K*/, double phi_mc /*-*/, + int& mc_error_code, double& mc_w_tip_ratio /*-*/, double& P_mc_out /*kPa*/, + int& rc_error_code, double& rc_w_tip_ratio /*-*/, double& rc_phi /*-*/, + bool is_update_ms_od_solved = false); + + const C_comp_multi_stage::S_od_solved* get_rc_od_solved() + { + return m_rc_ms.get_od_solved(); + } + + /*const S_od_turbo_bal_csp_solved* get_od_turbo_bal_csp_solved() + { + return &ms_od_turbo_bal_csp_solved; + } + + double get_max_target() + { + return m_biggest_target; + }*/ + + + }; #endif diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index 2b15b69d6f..939ebb3391 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -35,6 +35,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //#include "sco2_pc_core.h" #include "sco2_recompression_cycle.h" #include "sco2_partialcooling_cycle.h" +#include "sco2_htrbypass_cycle.h" #include "csp_solver_util.h" #include "CO2_properties.h" @@ -126,9 +127,9 @@ void C_sco2_phx_air_cooler::design_core() mpc_sco2_cycle = std::move(c_pc_cycle); } - else + else if(ms_des_par.m_cycle_config == 3) { - std::unique_ptr c_rc_cycle = std::unique_ptr(new C_RecompCycle( + std::unique_ptr c_bp_cycle = std::unique_ptr(new C_HTRBypass_Cycle( turbo_gen_motor_config, eta_generator, T_mc_in, @@ -146,8 +147,31 @@ void C_sco2_phx_air_cooler::design_core() s_cycle_config = "recompression"; - mpc_sco2_cycle = std::move(c_rc_cycle); + mpc_sco2_cycle = std::move(c_bp_cycle); } + else + { + std::unique_ptr c_rc_cycle = std::unique_ptr(new C_RecompCycle( + turbo_gen_motor_config, + eta_generator, + T_mc_in, + ms_des_par.m_W_dot_net, + T_t_in, ms_des_par.m_P_high_limit, + ms_des_par.m_DP_LT, ms_des_par.m_DP_HT, + ms_des_par.m_DP_PC, ms_des_par.m_DP_PHX, + ms_des_par.m_LTR_N_sub_hxrs, ms_des_par.m_HTR_N_sub_hxrs, + ms_des_par.m_eta_mc, ms_des_par.m_mc_comp_type, + ms_des_par.m_eta_rc, + ms_des_par.m_eta_t, ms_des_par.m_N_turbine, + ms_des_par.m_frac_fan_power, ms_des_par.m_eta_fan, ms_des_par.m_deltaP_cooler_frac, + ms_des_par.m_N_nodes_pass, + ms_des_par.m_T_amb_des, ms_des_par.m_elevation)); + + s_cycle_config = "recompression"; + + mpc_sco2_cycle = std::move(c_rc_cycle); + } + // Set min temp m_T_mc_in_min = mpc_sco2_cycle->get_design_limits().m_T_mc_in_min; //[K] From 3856878c2523dd2df9d3ee15899cc9e776117d3d Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Wed, 19 Apr 2023 11:20:39 -0600 Subject: [PATCH 03/94] Add methods for solving htr bypass cycle. Add temporary code to cmod to launch htr bypass for debugging --- ssc/cmod_sco2_csp_system.cpp | 82 ++++ tcs/sco2_htrbypass_cycle.cpp | 921 ++++++++++++++++++++++++++++++++++- tcs/sco2_htrbypass_cycle.h | 35 +- 3 files changed, 1029 insertions(+), 9 deletions(-) diff --git a/ssc/cmod_sco2_csp_system.cpp b/ssc/cmod_sco2_csp_system.cpp index 8860e1b0ba..85aff0ac31 100644 --- a/ssc/cmod_sco2_csp_system.cpp +++ b/ssc/cmod_sco2_csp_system.cpp @@ -38,6 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "sco2_pc_csp_int.h" +#include "sco2_htrbypass_cycle.h" static var_info _cm_vtab_sco2_csp_system[] = { @@ -330,6 +331,87 @@ class cm_sco2_csp_system : public compute_module void exec() override { + // Debug to launch HTR Bypass + if (true) + { + // inputs + C_sco2_cycle_core::E_turbo_gen_motor_config turbo_gen_motor_config = static_cast(0); + double eta_generator = 1.0; + double T_mc_in = 314.15; // K + double W_dot_net = 50e3; // kW + double T_t_in = 664 + 273; // K + double P_high_limit = 25e3; // kPa + std::vector DP_LTR = { -0.0056 , -0.0311 }; + std::vector DP_HTR = { -0.0056 , -0.0311 }; + std::vector DP_PC_main = { 0.00, -0.005 }; + std::vector DP_PHX = { -0.0056, 0.0 }; + int LTR_N_sub_hxrs = 10; + int HTR_N_sub_hxrs = 10; + double eta_mc = 0.85; + double mc_comp_model_code = 1; + double eta_rc = 0.85; + double eta_t = 0.9; + double N_turbine = 30000.0; + double frac_fan_power = 0.02; + double eta_fan = 0.5; + double deltaP_cooler_frac = 0.005; + double N_nodes_pass = 10; + double T_amb_des = 35 + 273; // K + double elevation = 588; // m + + std::unique_ptr c_bp_cycle = std::unique_ptr(new C_HTRBypass_Cycle(turbo_gen_motor_config, eta_generator, T_mc_in, W_dot_net, T_t_in, P_high_limit, DP_LTR, DP_HTR, + DP_PC_main, DP_PHX, LTR_N_sub_hxrs, HTR_N_sub_hxrs, eta_mc, mc_comp_model_code, eta_rc, + eta_t, N_turbine, frac_fan_power, eta_fan, deltaP_cooler_frac, N_nodes_pass, T_amb_des, elevation)); + + + C_sco2_cycle_core::S_auto_opt_design_parameters des_params; + { + des_params.m_T_pc_in = T_mc_in; //[K] + des_params.m_DP_PC_pre = DP_PC_main; + des_params.m_UA_rec_total = 15 * 1000 * (W_dot_net) / 50.0; //[kW/K] + // LTR thermal design + des_params.m_LTR_target_code = 0; //[-] + des_params.m_LTR_UA = 7500; //[kW/K] + des_params.m_LTR_min_dT = std::numeric_limits::quiet_NaN(); //[K] + des_params.m_LTR_eff_target = std::numeric_limits::quiet_NaN(); //[-] + des_params.m_LTR_eff_max = 1.0; //[-] + //des_params.m_LTR_od_UA_target_type = 0; + // HTR thermal design + des_params.m_HTR_target_code = 0; //[-] + des_params.m_HTR_UA = 7500.0; //[kW/K] + des_params.m_HTR_min_dT = std::numeric_limits::quiet_NaN(); //[K] + des_params.m_HTR_eff_target = std::numeric_limits::quiet_NaN(); //[-] + des_params.m_HTR_eff_max = 1.0; //[-] + //des_params.m_HTR_od_UA_target_type = ms_des_par.m_HTR_od_UA_target_type; + // + des_params.m_eta_pc = 0.85; + des_params.m_des_tol = std::pow(10, -3); + des_params.m_des_opt_tol = std::pow(10, -3); + + des_params.m_is_des_air_cooler = true; //[-] + + des_params.m_des_objective_type = 0; //[-] + des_params.m_min_phx_deltaT = 0; //[C] + + des_params.m_fixed_P_mc_out = 1; //[-] + + des_params.m_PR_HP_to_LP_guess = P_high_limit; //[-] + des_params.m_fixed_PR_HP_to_LP = 1; //[-] + + des_params.m_f_PR_HP_to_IP_guess = P_high_limit; //[-] + des_params.m_fixed_f_PR_HP_to_IP = 1; //[-] + + des_params.m_is_recomp_ok = 1; + + + + c_bp_cycle->auto_opt_design(des_params); + } + + } + + + C_sco2_phx_air_cooler c_sco2_cycle; int sco2_des_err = sco2_design_cmod_common(this, c_sco2_cycle); diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 51d0c2b185..9b1e5793f0 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -35,6 +35,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "CO2_properties.h" +#include "fmin.h" + void C_HTRBypass_Cycle::design_core(int& error_code) @@ -44,21 +46,930 @@ void C_HTRBypass_Cycle::design_core(int& error_code) void C_HTRBypass_Cycle::design_core_standard(int& error_code) { - int x = 0; + // Temporary Hard coded parameters + ms_des_par.m_recomp_frac = 0.3; + m_cp_HTF = 1.482e+03; // J/kg K + m_T_HTF_PHX_inlet = 670 + 273; // K + m_T_HTF_BP_outlet = 770; // K + m_bp_frac = 0; + m_dT_BP = 0; + + // Apply scaling to the turbomachinery here + m_mc_ms.m_r_W_dot_scale = m_W_dot_net / 10.E3; //[-] + m_rc_ms.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] + m_t.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] + + CO2_state co2_props; + + // Initialize Recuperators + { + // LTR + mc_LT_recup.initialize(m_LTR_N_sub_hxrs, ms_des_par.m_LTR_od_UA_target_type); + // HTR + mc_HT_recup.initialize(m_HTR_N_sub_hxrs, ms_des_par.m_HTR_od_UA_target_type); + } + + // Initialize a few variables + { + //double m_dot_t, , m_dot_rc, Q_dot_LT, Q_dot_HT, UA_LT_calc, UA_HT_calc; + //m_dot_t = m_dot_mc = m_dot_rc = Q_dot_LT = Q_dot_HT = UA_LT_calc = UA_HT_calc = 0.0; + + m_temp_last[MC_IN] = m_T_mc_in; //[K] + m_pres_last[MC_IN] = 10000; // ms_des_par.m_P_mc_in + m_pres_last[MC_OUT] = 25000; // ms_des_par.m_P_mc_out; // 25000 + m_temp_last[TURB_IN] = 923.149; // m_T_t_in; //[K] 923.149 + } + + // Apply pressure drops to heat exchangers, fully defining the pressures at all states + { + if (m_DP_LTR[0] < 0.0) + m_pres_last[LTR_HP_OUT] = m_pres_last[MC_OUT] - m_pres_last[MC_OUT] * std::abs(m_DP_LTR[0]); // relative pressure drop specified for LT recuperator (cold stream) + else + m_pres_last[LTR_HP_OUT] = m_pres_last[MC_OUT] - m_DP_LTR[0]; // absolute pressure drop specified for LT recuperator (cold stream) + + if ((ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && ms_des_par.m_LTR_UA < 1.0E-12) + || (ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && ms_des_par.m_LTR_UA < 1.0E-12) + || (ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && ms_des_par.m_LTR_min_dT < 1.0E-12) + || (ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && ms_des_par.m_LTR_eff_target < 1.0E-12)) + m_pres_last[LTR_HP_OUT] = m_pres_last[MC_OUT]; // If there is no LT recuperator, there is no pressure drop + + m_pres_last[MIXER_OUT] = m_pres_last[LTR_HP_OUT]; // Assume no pressure drop in mixing valve + m_pres_last[RC_OUT] = m_pres_last[LTR_HP_OUT]; // Assume no pressure drop in mixing valve + + if (m_DP_HTR[0] < 0.0) + m_pres_last[HTR_HP_OUT] = m_pres_last[MIXER_OUT] - m_pres_last[MIXER_OUT] * std::abs(m_DP_HTR[0]); // relative pressure drop specified for HT recuperator (cold stream) + else + m_pres_last[HTR_HP_OUT] = m_pres_last[MIXER_OUT] - m_DP_HTR[0]; // absolute pressure drop specified for HT recuperator (cold stream) + + if ((ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && ms_des_par.m_HTR_UA < 1.0E-12) + || (ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && ms_des_par.m_HTR_UA < 1.0E-12) + || (ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && ms_des_par.m_HTR_min_dT < 1.0E-12) + || (ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && ms_des_par.m_HTR_eff_target < 1.0E-12)) + m_pres_last[HTR_HP_OUT] = m_pres_last[MIXER_OUT]; // If there is no HT recuperator, there is no pressure drop + + if (m_DP_PHX[0] < 0.0) + m_pres_last[TURB_IN] = m_pres_last[HTR_HP_OUT] - m_pres_last[HTR_HP_OUT] * std::abs(m_DP_PHX[0]); // relative pressure drop specified for PHX + else + m_pres_last[TURB_IN] = m_pres_last[HTR_HP_OUT] - m_DP_PHX[0]; // absolute pressure drop specified for PHX + + if (m_DP_PC_main[1] < 0.0) + m_pres_last[LTR_LP_OUT] = m_pres_last[MC_IN] / (1.0 - std::abs(m_DP_PC_main[1])); // relative pressure drop specified for precooler: P1=P9-P9*rel_DP => P1=P9*(1-rel_DP) + else + m_pres_last[LTR_LP_OUT] = m_pres_last[MC_IN] + m_DP_PC_main[1]; + + if (m_DP_LTR[1] < 0.0) + m_pres_last[HTR_LP_OUT] = m_pres_last[LTR_LP_OUT] / (1.0 - std::abs(m_DP_LTR[1])); // relative pressure drop specified for LT recuperator (hot stream) + else + m_pres_last[HTR_LP_OUT] = m_pres_last[LTR_LP_OUT] + m_DP_LTR[1]; // absolute pressure drop specified for LT recuperator (hot stream) + + if ((ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && ms_des_par.m_LTR_UA < 1.0E-12) + || (ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && ms_des_par.m_LTR_UA < 1.0E-12) + || (ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && ms_des_par.m_LTR_min_dT < 1.0E-12) + || (ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && ms_des_par.m_LTR_eff_target < 1.0E-12)) + m_pres_last[HTR_LP_OUT] = m_pres_last[LTR_LP_OUT]; // if there is no LT recuperator, there is no pressure drop + + if (m_DP_HTR[1] < 0.0) + m_pres_last[TURB_OUT] = m_pres_last[HTR_LP_OUT] / (1.0 - std::abs(m_DP_HTR[1])); // relative pressure drop specified for HT recuperator (hot stream) + else + m_pres_last[TURB_OUT] = m_pres_last[HTR_LP_OUT] + m_DP_HTR[1]; // absolute pressure drop specified for HT recuperator (hot stream) + + if ((ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && ms_des_par.m_HTR_UA < 1.0E-12) + || (ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && ms_des_par.m_HTR_UA < 1.0E-12) + || (ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && ms_des_par.m_HTR_min_dT < 1.0E-12) + || (ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && ms_des_par.m_HTR_eff_target < 1.0E-12)) + m_pres_last[TURB_OUT] = m_pres_last[HTR_LP_OUT]; // if there is no HT recuperator, there is no pressure drop + + + // Added pressures + m_pres_last[BYPASS_OUT] = m_pres_last[HTR_HP_OUT]; + m_pres_last[MIXER2_OUT] = m_pres_last[HTR_HP_OUT]; + + + } + + // Set isentropic efficiency (temporary) + double eta_mc_isen, eta_t_isen; + { + eta_mc_isen = m_eta_mc; + eta_t_isen = m_eta_t; + } + + // Determine the outlet state and specific work for the main compressor and turbine. + + // Main compressor + m_w_mc = std::numeric_limits::quiet_NaN(); + { + int comp_error_code = 0; + + calculate_turbomachinery_outlet_1(m_temp_last[MC_IN], m_pres_last[MC_IN], m_pres_last[MC_OUT], eta_mc_isen, true, + comp_error_code, m_enth_last[MC_IN], m_entr_last[MC_IN], m_dens_last[MC_IN], m_temp_last[MC_OUT], + m_enth_last[MC_OUT], m_entr_last[MC_OUT], m_dens_last[MC_OUT], m_w_mc); + + if (comp_error_code != 0) + { + error_code = comp_error_code; + return; + } + } + + // Turbine + m_w_t = std::numeric_limits::quiet_NaN(); + { + int turbine_error_code = 0; + + calculate_turbomachinery_outlet_1(m_temp_last[TURB_IN], m_pres_last[TURB_IN], m_pres_last[TURB_OUT], eta_t_isen, false, + turbine_error_code, m_enth_last[TURB_IN], m_entr_last[TURB_IN], m_dens_last[TURB_IN], m_temp_last[TURB_OUT], + m_enth_last[TURB_OUT], m_entr_last[TURB_OUT], m_dens_last[TURB_OUT], m_w_t); + + if (turbine_error_code != 0) + { + error_code = turbine_error_code; + return; + } + } + + // Check that this cycle can produce power + m_w_rc = std::numeric_limits::quiet_NaN(); + { + double eta_rc_isen = std::numeric_limits::quiet_NaN(); + + if (ms_des_par.m_recomp_frac >= 1.E-12) + { + if (m_eta_rc < 0.0) // need to convert polytropic efficiency to isentropic efficiency + { + int rc_error_code = 0; + + isen_eta_from_poly_eta(m_temp_last[MC_OUT], m_pres_last[LTR_LP_OUT], m_pres_last[RC_OUT], std::abs(m_eta_rc), + true, rc_error_code, eta_rc_isen); + + if (rc_error_code != 0) + { + error_code = rc_error_code; + return; + } + } + else + eta_rc_isen = m_eta_rc; + + int rc_error_code = 0; + calculate_turbomachinery_outlet_1(m_temp_last[MC_OUT], m_pres_last[LTR_LP_OUT], m_pres_last[RC_OUT], eta_rc_isen, + true, rc_error_code, m_w_rc); + + if (rc_error_code != 0) + { + error_code = rc_error_code; + return; + } + } + else + m_w_rc = 0.0; + + if (m_w_mc + m_w_rc + m_w_t <= 0.0) // positive net power is impossible; return an error + { + error_code = 25; + return; + } + } + + // **************************************************** + // **************************************************** + // Solve the recuperators + { + double T_HTR_LP_out_lower = m_temp_last[MC_OUT]; //[K] Coldest possible temperature + double T_HTR_LP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature + + double error = 1000; + double T_HTR_guess = 0.5 * (T_HTR_LP_out_lower + T_HTR_LP_out_upper); + double T_HTR_calc; + while (error > 0.1) + { + solve_HTR(T_HTR_guess, T_HTR_calc); + double guess_val = T_HTR_guess; + double calc_val = T_HTR_calc; + + error = std::abs(guess_val - calc_val); + + // Update guess value + T_HTR_guess = 0.5 * (guess_val + calc_val); + } + } + + // State 5 can now be fully defined + { + m_enth_last[HTR_HP_OUT] = m_enth_last[MIXER_OUT] + m_Q_dot_HT / m_m_dot_t; // Energy balance on cold stream of high-temp recuperator + int prop_error_code = CO2_PH(m_pres_last[HTR_HP_OUT], m_enth_last[HTR_HP_OUT], &co2_props); + if (prop_error_code != 0) + { + error_code = prop_error_code; + return; + } + m_temp_last[HTR_HP_OUT] = co2_props.temp; + m_entr_last[HTR_HP_OUT] = co2_props.entr; + m_dens_last[HTR_HP_OUT] = co2_props.dens; + } + + // Calculate cycle performance metrics (including total heat coming into cycle) + { + m_W_dot_mc = m_w_mc * m_m_dot_mc; //[kWe] + m_W_dot_rc = m_w_rc * m_m_dot_rc; //[kWe] + m_W_dot_t = m_w_t * m_m_dot_t; //[kWe] + m_W_dot_net_last = m_W_dot_mc + m_W_dot_rc + m_W_dot_t; + + m_Q_dot_pc = m_m_dot_mc * (m_enth_last[LTR_LP_OUT] - m_enth_last[MC_IN]); + + m_Q_dot_total = m_W_dot_net_last + m_Q_dot_pc; + } + + // Define bypass out temperature + if (true) + { + // Calculate Bypass Energy + { + // Set Bypass Temp based on HTR_HP_OUT + m_temp_last[BYPASS_OUT] = m_temp_last[HTR_HP_OUT] + m_dT_BP; + + // Calculate BYPASS_OUT properties + int prop_error_code = CO2_TP(this->m_temp_last[BYPASS_OUT], this->m_pres_last[BYPASS_OUT], &this->mc_co2_props); + if (prop_error_code != 0) + { + return; + } + this->m_enth_last[BYPASS_OUT] = this->mc_co2_props.enth; + this->m_entr_last[BYPASS_OUT] = this->mc_co2_props.entr; + this->m_dens_last[BYPASS_OUT] = this->mc_co2_props.dens; + + // Calculate Heat Transfer in Bypass + m_Q_dot_BP = m_m_dot_bp * (m_enth_last[BYPASS_OUT] - m_enth_last[MIXER_OUT]); + } + + // Simulate Mixer 2 + { + // If Bypass and HTR have flow + if (m_bp_frac >= 1e-12 && m_bp_frac <= (1.0 - 1e-12)) + { + m_enth_last[MIXER2_OUT] = (1.0 - m_bp_frac) * m_enth_last[HTR_HP_OUT] + + m_bp_frac * m_enth_last[BYPASS_OUT]; //[kJ/kg] + + int prop_error_code = CO2_PH(m_pres_last[MIXER2_OUT], m_enth_last[MIXER2_OUT], &mc_co2_props); + if (prop_error_code != 0) + { + return; + } + m_temp_last[MIXER2_OUT] = mc_co2_props.temp; //[K] + m_entr_last[MIXER2_OUT] = mc_co2_props.entr; //[kJ/kg-K] + m_dens_last[MIXER2_OUT] = mc_co2_props.dens; //[kg/m^3] + + } + // Flow only through HTR + else if (m_bp_frac <= (1.0 - 1e-12)) + { + m_temp_last[MIXER2_OUT] = m_temp_last[HTR_HP_OUT]; //[K] + m_enth_last[MIXER2_OUT] = m_enth_last[HTR_HP_OUT]; //[kJ/kg] + m_entr_last[MIXER2_OUT] = m_entr_last[HTR_HP_OUT]; //[kJ/kg-K] + m_dens_last[MIXER2_OUT] = m_dens_last[HTR_HP_OUT]; //[kg/m^3] + } + // Flow only through Bypass + else + { + m_temp_last[MIXER2_OUT] = m_temp_last[BYPASS_OUT]; //[K] + m_enth_last[MIXER2_OUT] = m_enth_last[BYPASS_OUT]; //[kJ/kg] + m_entr_last[MIXER2_OUT] = m_entr_last[BYPASS_OUT]; //[kJ/kg-K] + m_dens_last[MIXER2_OUT] = m_dens_last[BYPASS_OUT]; //[kg/m^3] + } + } + + // Calculate PHX Heat Transfer + { + m_Q_dot_PHX = m_m_dot_t * (m_enth_last[TURB_IN] - m_enth_last[MIXER2_OUT]); + int x = 0; + } + + // Back Calculate and Check values + { + // Bypass Temps + double bp_temp_in = m_temp_last[MIXER_OUT]; + double bp_temp_out = m_temp_last[BYPASS_OUT]; + + double real_q_dot_total = m_W_dot_t + m_Q_dot_pc; + + double qSum = m_Q_dot_total; + double qSum_calc = m_Q_dot_BP + m_Q_dot_PHX; + + int x = 0; + + } + + } + + // old bypass method + if (false) + { + // Calculate Total Heat Coming into Cycle + { + m_W_dot_mc = m_w_mc * m_m_dot_mc; + m_W_dot_rc = m_w_rc * m_m_dot_rc; + m_W_dot_t = m_w_t * m_m_dot_t; + m_Q_dot_total = m_W_dot_mc + m_W_dot_rc + m_W_dot_t + m_Q_dot_pc; + } + + // Calculate HTF Mass Flow Rate + { + m_m_dot_HTF = m_Q_dot_total / ((m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet) * m_cp_HTF); + } + + + // Solve Bypass Outlet Temperature + { + double T_BP_out_lower = m_temp_last[MIXER_OUT]; //[K] Coldest possible temperature + double T_BP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature + + double error = 1000; + double T_BP_guess = 0.5 * (T_BP_out_lower + T_BP_out_upper); + double T_BP_calc; + while (error > 0.1) + { + solve_bypass(T_BP_guess, T_BP_calc); + double guess_val = T_BP_guess; + double calc_val = T_BP_calc; + + error = std::abs(guess_val - calc_val); + + // Update guess value + T_BP_guess = 0.5 * (guess_val + calc_val); + } + } + } + + // Iterate over energy + if (false) + { + // Calculate Total Heat Coming into Cycle + { + m_W_dot_mc = m_w_mc * m_m_dot_mc; + m_W_dot_rc = m_w_rc * m_m_dot_rc; + m_W_dot_t = m_w_t * m_m_dot_t; + double m_Q_dot_pc = m_m_dot_mc * (m_enth_last[LTR_LP_OUT] - m_enth_last[MC_IN]); + m_Q_dot_total = m_W_dot_mc + m_W_dot_rc + m_W_dot_t + m_Q_dot_pc; + } + + // Solve Bypass Outlet Temperature + { + double T_BP_out_lower = m_temp_last[MIXER_OUT]; //[K] Coldest possible temperature + double T_BP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature + + double error = 1000; + double T_BP_guess = 0.5 * (T_BP_out_lower + T_BP_out_upper); + double T_BP_calc; + while (error > 0.1) + { + solve_bypass_energy(T_BP_guess, T_BP_calc); + double guess_val = T_BP_guess; + double calc_val = T_BP_calc; + + error = std::abs(guess_val - calc_val); + + // Update guess value + T_BP_guess = 0.5 * (guess_val + calc_val); + } + + int x = 0; + } + + + } + +} + + +int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out_calc) +{ + m_w_rc = m_m_dot_t = m_m_dot_rc = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT = std::numeric_limits::quiet_NaN(); + double* diff_T_HTR_LP_out; + + // Set temperature guess + m_temp_last[HTR_LP_OUT] = T_HTR_LP_OUT_guess; //[K] + + // Solve HTR_LP_OUT properties + { + int prop_error_code = CO2_TP(this->m_temp_last[HTR_LP_OUT], this->m_pres_last[HTR_LP_OUT], &this->mc_co2_props); + if (prop_error_code != 0) + { + *diff_T_HTR_LP_out = std::numeric_limits::quiet_NaN(); + return prop_error_code; + } + this->m_enth_last[HTR_LP_OUT] = this->mc_co2_props.enth; + this->m_entr_last[HTR_LP_OUT] = this->mc_co2_props.entr; + this->m_dens_last[HTR_LP_OUT] = this->mc_co2_props.dens; + } + + + // ********************************************************************************* + // ********************************************************************************* + // Solve for the LTR solution + { + double T_LTR_LP_out_lower = this->m_temp_last[MC_OUT]; //[K] Coldest possible outlet temperature + double T_LTR_LP_out_upper = this->m_temp_last[HTR_LP_OUT]; //[K] Hottest possible outlet temperature + + double error = 1000; + double T_LTR_guess = 0.5 * (T_LTR_LP_out_lower + T_LTR_LP_out_upper); + double T_LTR_calc; + while (error > 0.1) + { + solve_LTR(T_LTR_guess, T_LTR_calc); + double guess_val = T_LTR_guess; + double calc_val = T_LTR_calc; + + error = std::abs(guess_val - calc_val); + + // Update guess value + T_LTR_guess = 0.5 * (guess_val + calc_val); + + } + } + + // Know LTR performance so we can calculate the HP outlet + // Energy balance on LTR HP stream + { + this->m_enth_last[LTR_HP_OUT] = this->m_enth_last[MC_OUT] + m_Q_dot_LT / m_m_dot_mc; //[kJ/kg] + int prop_error_code = CO2_PH(this->m_pres_last[LTR_HP_OUT], this->m_enth_last[LTR_HP_OUT], &this->mc_co2_props); + if (prop_error_code != 0) + { + *diff_T_HTR_LP_out = std::numeric_limits::quiet_NaN(); + return prop_error_code; + } + this->m_temp_last[LTR_HP_OUT] = this->mc_co2_props.temp; //[K] + this->m_entr_last[LTR_HP_OUT] = this->mc_co2_props.entr; //[kJ/kg-K] + this->m_dens_last[LTR_HP_OUT] = this->mc_co2_props.dens; //[kg/m^3] + } + + // Simulate the Mixer + if (this->ms_des_par.m_recomp_frac >= 1.E-12) + { + this->m_enth_last[MIXER_OUT] = (1.0 - this->ms_des_par.m_recomp_frac) * this->m_enth_last[LTR_HP_OUT] + this->ms_des_par.m_recomp_frac * this->m_enth_last[RC_OUT]; //[kJ/kg] + int prop_error_code = CO2_PH(this->m_pres_last[MIXER_OUT], this->m_enth_last[MIXER_OUT], &this->mc_co2_props); + if (prop_error_code != 0) + { + *diff_T_HTR_LP_out = std::numeric_limits::quiet_NaN(); + return prop_error_code; + } + this->m_temp_last[MIXER_OUT] = this->mc_co2_props.temp; //[K] + this->m_entr_last[MIXER_OUT] = this->mc_co2_props.entr; //[kJ/kg-K] + this->m_dens_last[MIXER_OUT] = this->mc_co2_props.dens; //[kg/m^3] + } + else + { // No recompressor, so no mixing required, and HTR HP inlet = LTR HP outlet + this->m_temp_last[MIXER_OUT] = this->m_temp_last[LTR_HP_OUT]; //[K] + this->m_enth_last[MIXER_OUT] = this->m_enth_last[LTR_HP_OUT]; //[kJ/kg] + this->m_entr_last[MIXER_OUT] = this->m_entr_last[LTR_HP_OUT]; //[kJ/kg-K] + this->m_dens_last[MIXER_OUT] = this->m_dens_last[LTR_HP_OUT]; //[kg/m^3] + } + + // Solve Mass Flow rates for HTR_HP_OUT and Bypass + { + m_m_dot_bp = m_bp_frac * m_m_dot_t; + m_m_dot_htr_hp = m_m_dot_t - m_m_dot_bp; + } + + + // Find the design solution of the HTR + { + T_HTR_LP_out_calc = std::numeric_limits::quiet_NaN(); + this->mc_HT_recup.design_for_target__calc_outlet(this->ms_opt_des_par.m_HTR_target_code, + this->ms_opt_des_par.m_HTR_UA, this->ms_opt_des_par.m_HTR_min_dT, this->ms_opt_des_par.m_HTR_eff_target, + this->ms_opt_des_par.m_HTR_eff_max, + this->m_temp_last[MIXER_OUT], this->m_pres_last[MIXER_OUT], m_m_dot_htr_hp, this->m_pres_last[HTR_HP_OUT], + this->m_temp_last[TURB_OUT], this->m_pres_last[TURB_OUT], m_m_dot_t, this->m_pres_last[HTR_LP_OUT], + this->ms_opt_des_par.m_des_tol, + m_Q_dot_HT, this->m_temp_last[HTR_HP_OUT], T_HTR_LP_out_calc); + } + +} + +int C_HTRBypass_Cycle::solve_LTR(double T_LTR_LP_OUT_guess, double& T_LTR_LP_out_calc) +{ + m_w_rc = m_m_dot_t = m_m_dot_rc = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT = std::numeric_limits::quiet_NaN(); + double* diff_T_LTR_LP_out; + + // Set LTR_LP_OUT guess + this->m_temp_last[LTR_LP_OUT] = T_LTR_LP_OUT_guess; + + // First, solve the recompressor model as necessary + if (this->ms_des_par.m_recomp_frac >= 1.E-12) + { + double eta_rc_isen = std::numeric_limits::quiet_NaN(); + + if (this->m_eta_rc < 0.0) // recalculate isen. efficiency of recompressor because inlet temp changes + { + int rc_error_code = 0; + isen_eta_from_poly_eta(this->m_temp_last[LTR_LP_OUT], this->m_pres_last[LTR_LP_OUT], + this->m_pres_last[RC_OUT], std::abs(this->m_eta_rc), true, + rc_error_code, eta_rc_isen); + + if (rc_error_code != 0) + { + *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); + return rc_error_code; + } + } + else + { + eta_rc_isen = this->m_eta_rc; + } + + int rc_error_code = 0; + + calculate_turbomachinery_outlet_1(this->m_temp_last[LTR_LP_OUT], this->m_pres_last[LTR_LP_OUT], this->m_pres_last[RC_OUT], eta_rc_isen, true, rc_error_code, + this->m_enth_last[LTR_LP_OUT], this->m_entr_last[LTR_LP_OUT], this->m_dens_last[LTR_LP_OUT], this->m_temp_last[RC_OUT], this->m_enth_last[RC_OUT], + this->m_entr_last[RC_OUT], this->m_dens_last[RC_OUT], m_w_rc); + + if (rc_error_code != 0) + { + *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); + return rc_error_code; + } + } + else + { + m_w_rc = 0.0; // no recompressor + int prop_error_code = CO2_TP(this->m_temp_last[LTR_LP_OUT], this->m_pres_last[LTR_LP_OUT], &this->mc_co2_props); + if (prop_error_code != 0) + { + *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); + return prop_error_code; + } + this->m_enth_last[LTR_LP_OUT] = this->mc_co2_props.enth; + this->m_entr_last[LTR_LP_OUT] = this->mc_co2_props.entr; + this->m_dens_last[LTR_LP_OUT] = this->mc_co2_props.dens; + this->m_temp_last[RC_OUT] = this->m_temp_last[LTR_LP_OUT]; + this->m_enth_last[RC_OUT] = this->m_enth_last[LTR_LP_OUT]; + this->m_entr_last[RC_OUT] = this->m_entr_last[LTR_LP_OUT]; + this->m_dens_last[RC_OUT] = this->m_dens_last[LTR_LP_OUT]; + } + + // Solve Mass Flow Rates + { + m_m_dot_t = this->m_W_dot_net / ((m_w_mc * (1.0 - this->ms_des_par.m_recomp_frac) + + m_w_rc * this->ms_des_par.m_recomp_frac + m_w_t) * this->m_eta_generator); //[kg/s] + + m_m_dot_rc = m_m_dot_t * this->ms_des_par.m_recomp_frac; //[kg/s] + m_m_dot_mc = m_m_dot_t - m_m_dot_rc; + } + + // Solve LTR + T_LTR_LP_out_calc = std::numeric_limits::quiet_NaN(); + { + this->mc_LT_recup.design_for_target__calc_outlet(this->ms_opt_des_par.m_LTR_target_code, + this->ms_opt_des_par.m_LTR_UA, this->ms_opt_des_par.m_LTR_min_dT, this->ms_opt_des_par.m_LTR_eff_target, + this->ms_opt_des_par.m_LTR_eff_max, + this->m_temp_last[MC_OUT], this->m_pres_last[MC_OUT], m_m_dot_mc, this->m_pres_last[LTR_HP_OUT], + this->m_temp_last[HTR_LP_OUT], this->m_pres_last[HTR_LP_OUT], m_m_dot_t, this->m_pres_last[LTR_LP_OUT], + this->ms_opt_des_par.m_des_tol, + m_Q_dot_LT, this->m_temp_last[LTR_HP_OUT], T_LTR_LP_out_calc); + + } +} + +int C_HTRBypass_Cycle::solve_bypass(double T_BP_OUT_guess, double& T_BP_out_calc) +{ + // Set temperature guess + m_temp_last[BYPASS_OUT] = T_BP_OUT_guess; //[K] + + // Solve BYPASS_OUT properties + { + int prop_error_code = CO2_TP(this->m_temp_last[BYPASS_OUT], this->m_pres_last[BYPASS_OUT], &this->mc_co2_props); + if (prop_error_code != 0) + { + return prop_error_code; + } + this->m_enth_last[BYPASS_OUT] = this->mc_co2_props.enth; + this->m_entr_last[BYPASS_OUT] = this->mc_co2_props.entr; + this->m_dens_last[BYPASS_OUT] = this->mc_co2_props.dens; + } + + // Simulate Mixer 2 + { + // If Bypass and HTR have flow + if (m_bp_frac >= 1e-12 && m_bp_frac <= (1.0-1e-12)) + { + m_enth_last[MIXER2_OUT] = (1.0 - m_bp_frac) * m_enth_last[HTR_HP_OUT] + + m_bp_frac * m_enth_last[BYPASS_OUT]; //[kJ/kg] + + int prop_error_code = CO2_PH(m_pres_last[MIXER2_OUT], m_enth_last[MIXER2_OUT], &mc_co2_props); + if (prop_error_code != 0) + { + return prop_error_code; + } + m_temp_last[MIXER2_OUT] = mc_co2_props.temp; //[K] + m_entr_last[MIXER2_OUT] = mc_co2_props.entr; //[kJ/kg-K] + m_dens_last[MIXER2_OUT] = mc_co2_props.dens; //[kg/m^3] + + } + // Flow only through HTR + else if (m_bp_frac <= (1.0 - 1e-12)) + { + m_temp_last[MIXER2_OUT] = m_temp_last[HTR_HP_OUT]; //[K] + m_enth_last[MIXER2_OUT] = m_enth_last[HTR_HP_OUT]; //[kJ/kg] + m_entr_last[MIXER2_OUT] = m_entr_last[HTR_HP_OUT]; //[kJ/kg-K] + m_dens_last[MIXER2_OUT] = m_dens_last[HTR_HP_OUT]; //[kg/m^3] + } + // Flow only through Bypass + else + { + m_temp_last[MIXER2_OUT] = m_temp_last[BYPASS_OUT]; //[K] + m_enth_last[MIXER2_OUT] = m_enth_last[BYPASS_OUT]; //[kJ/kg] + m_entr_last[MIXER2_OUT] = m_entr_last[BYPASS_OUT]; //[kJ/kg-K] + m_dens_last[MIXER2_OUT] = m_dens_last[BYPASS_OUT]; //[kg/m^3] + } + } + + // Calculate Heat From PHX + m_Q_dot_PHX = m_m_dot_t * (m_enth_last[TURB_IN] - m_enth_last[MIXER2_OUT]); + + // Calculate HTF PHX Outlet Temp + m_T_HTF_PHX_out = m_T_HTF_PHX_inlet - (m_Q_dot_PHX / (m_cp_HTF * m_m_dot_HTF)); + + // Check if HTF PHX Outlet is higher than BP outlet + if (m_T_HTF_PHX_out < m_T_HTF_BP_outlet) + { + // Something is wrong + } + + + // Solve Bypass HTX + { + // Calculate Heat Transfer in Bypass + m_Q_dot_BP = m_m_dot_HTF * m_cp_HTF * (m_T_HTF_PHX_out - m_T_HTF_BP_outlet); + + // Calculate Enthalpy at sco2 bypass outlet + double h_bp_out_calc = (m_Q_dot_BP / m_m_dot_bp) + m_enth_last[MIXER_OUT]; + + // Calculate Temperature + int prop_error_code = CO2_PH(m_pres_last[BYPASS_OUT], h_bp_out_calc, &mc_co2_props); + if (prop_error_code != 0) + { + return prop_error_code; + } + T_BP_out_calc = mc_co2_props.temp; + + int x = 0; + } + + + return 0; +} + +int C_HTRBypass_Cycle::solve_bypass_energy(double T_BP_OUT_guess, double& T_BP_out_calc) +{ + // Set temperature guess + m_temp_last[BYPASS_OUT] = T_BP_OUT_guess; //[K] + + // Solve BYPASS_OUT properties + { + int prop_error_code = CO2_TP(this->m_temp_last[BYPASS_OUT], this->m_pres_last[BYPASS_OUT], &this->mc_co2_props); + if (prop_error_code != 0) + { + return prop_error_code; + } + this->m_enth_last[BYPASS_OUT] = this->mc_co2_props.enth; + this->m_entr_last[BYPASS_OUT] = this->mc_co2_props.entr; + this->m_dens_last[BYPASS_OUT] = this->mc_co2_props.dens; + } + + // Calculate Bypass Heat Exchanged + { + m_Q_dot_BP = m_m_dot_bp * (m_enth_last[BYPASS_OUT] - m_enth_last[MIXER_OUT]); + } + + // Simulate Mixer 2 + { + // If Bypass and HTR have flow + if (m_bp_frac >= 1e-12 && m_bp_frac <= (1.0 - 1e-12)) + { + m_enth_last[MIXER2_OUT] = (1.0 - m_bp_frac) * m_enth_last[HTR_HP_OUT] + + m_bp_frac * m_enth_last[BYPASS_OUT]; //[kJ/kg] + + int prop_error_code = CO2_PH(m_pres_last[MIXER2_OUT], m_enth_last[MIXER2_OUT], &mc_co2_props); + if (prop_error_code != 0) + { + return prop_error_code; + } + m_temp_last[MIXER2_OUT] = mc_co2_props.temp; //[K] + m_entr_last[MIXER2_OUT] = mc_co2_props.entr; //[kJ/kg-K] + m_dens_last[MIXER2_OUT] = mc_co2_props.dens; //[kg/m^3] + + } + // Flow only through HTR + else if (m_bp_frac <= (1.0 - 1e-12)) + { + m_temp_last[MIXER2_OUT] = m_temp_last[HTR_HP_OUT]; //[K] + m_enth_last[MIXER2_OUT] = m_enth_last[HTR_HP_OUT]; //[kJ/kg] + m_entr_last[MIXER2_OUT] = m_entr_last[HTR_HP_OUT]; //[kJ/kg-K] + m_dens_last[MIXER2_OUT] = m_dens_last[HTR_HP_OUT]; //[kg/m^3] + } + // Flow only through Bypass + else + { + m_temp_last[MIXER2_OUT] = m_temp_last[BYPASS_OUT]; //[K] + m_enth_last[MIXER2_OUT] = m_enth_last[BYPASS_OUT]; //[kJ/kg] + m_entr_last[MIXER2_OUT] = m_entr_last[BYPASS_OUT]; //[kJ/kg-K] + m_dens_last[MIXER2_OUT] = m_dens_last[BYPASS_OUT]; //[kg/m^3] + } + } + + // Calculate Heat From PHX + m_Q_dot_PHX = m_m_dot_t * (m_enth_last[TURB_IN] - m_enth_last[MIXER2_OUT]); + + // Back Calculate Bypass Q_dot using Sum + double q_dot_bp_calc = m_Q_dot_total - m_Q_dot_PHX; + + double error = q_dot_bp_calc - m_Q_dot_BP; + + // Negative Bypass energy means temperature is too low + /*if (q_dot_bp_calc < 0) + { + T_BP_out_calc = m_enth_last[TURB_IN]; + return 0; + }*/ + + // Back Calculate sco2 bypass outlet temperature + { + double enth_bp_out_calc = m_enth_last[MIXER_OUT] + (q_dot_bp_calc / m_m_dot_bp); + + int prop_error_code = CO2_PH(m_pres_last[BYPASS_OUT], enth_bp_out_calc, &mc_co2_props); + if (prop_error_code != 0) + { + return prop_error_code; + } + T_BP_out_calc = mc_co2_props.temp; + } + } + + + + void C_HTRBypass_Cycle::opt_design_core(int& error_code) { } void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) { + // Check that simple/recomp flag is set + if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && + ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) + { + throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" + " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); + } + + // map 'auto_opt_des_par_in' to 'ms_auto_opt_des_par' + // LTR thermal design + ms_opt_des_par.m_LTR_target_code = ms_auto_opt_des_par.m_LTR_target_code; //[-] + ms_opt_des_par.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; //[kW/K] + ms_opt_des_par.m_LTR_min_dT = ms_auto_opt_des_par.m_LTR_min_dT; //[K] + ms_opt_des_par.m_LTR_eff_target = ms_auto_opt_des_par.m_LTR_eff_target; //[-] + ms_opt_des_par.m_LTR_eff_max = ms_auto_opt_des_par.m_LTR_eff_max; //[-] + ms_opt_des_par.m_LTR_od_UA_target_type = ms_auto_opt_des_par.m_LTR_od_UA_target_type; + // HTR thermal design + ms_opt_des_par.m_HTR_target_code = ms_auto_opt_des_par.m_HTR_target_code; //[-] + ms_opt_des_par.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; //[kW/K] + ms_opt_des_par.m_HTR_min_dT = ms_auto_opt_des_par.m_HTR_min_dT; //[K] + ms_opt_des_par.m_HTR_eff_target = ms_auto_opt_des_par.m_HTR_eff_target; //[-] + ms_opt_des_par.m_HTR_eff_max = ms_auto_opt_des_par.m_HTR_eff_max; + ms_opt_des_par.m_HTR_od_UA_target_type = ms_auto_opt_des_par.m_HTR_od_UA_target_type; + // + ms_opt_des_par.m_UA_rec_total = ms_auto_opt_des_par.m_UA_rec_total; + ms_opt_des_par.m_des_tol = ms_auto_opt_des_par.m_des_tol; + ms_opt_des_par.m_des_opt_tol = ms_auto_opt_des_par.m_des_opt_tol; + + ms_opt_des_par.m_is_des_air_cooler = ms_auto_opt_des_par.m_is_des_air_cooler; //[-] + + ms_opt_des_par.m_des_objective_type = ms_auto_opt_des_par.m_des_objective_type; //[-] + ms_opt_des_par.m_min_phx_deltaT = ms_auto_opt_des_par.m_min_phx_deltaT; //[C] + + ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] + + ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] + + // Outer optimization loop + m_objective_metric_auto_opt = 0.0; + + double best_P_high = m_P_high_limit; //[kPa] + double PR_mc_guess = 2.5; //[-] + if (!ms_opt_des_par.m_fixed_P_mc_out) + { + double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] + + //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); + best_P_high = m_P_high_limit; // TEMPORARY + + // If this runs, it should set: + // ms_des_par_auto_opt + // m_objective_metric_auto_opt + // So we can update pressure ratio guess + double PR_mc_guess_calc = ms_des_par_auto_opt.m_P_mc_out / ms_des_par_auto_opt.m_P_mc_in; + + if (std::isfinite(PR_mc_guess_calc)) { + PR_mc_guess = PR_mc_guess_calc; + } + else { + best_P_high = m_P_high_limit; //[kPa] + } + } + + if (ms_auto_opt_des_par.m_is_recomp_ok != 0) + { + // Complete 'ms_opt_des_par' for recompression cycle + ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] + ms_opt_des_par.m_fixed_P_mc_out = true; + + if (ms_opt_des_par.m_fixed_PR_HP_to_LP) + { + ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + } + else + { + ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] + } + + // Is recompression fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_recomp_ok < 0.0) + { // fixed + ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); + ms_opt_des_par.m_fixed_recomp_frac = true; + } + else + { // optimized + ms_opt_des_par.m_recomp_frac_guess = 0.3; + ms_opt_des_par.m_fixed_recomp_frac = false; + } + + ms_opt_des_par.m_LT_frac_guess = 0.5; + ms_opt_des_par.m_fixed_LT_frac = false; + + if (ms_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + ms_opt_des_par.m_fixed_LT_frac = true; + } + + int rc_error_code = 0; + + opt_design_core(rc_error_code); + + if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) + { + ms_des_par_auto_opt = ms_des_par_optimal; + m_objective_metric_auto_opt = m_objective_metric_opt; + } + } + + // Is recompression fraction fixed or optimized? + // If fixed, then we don't need to try simple cycle + if (ms_auto_opt_des_par.m_is_recomp_ok == 1.0 || ms_auto_opt_des_par.m_is_recomp_ok == 0.0) + { + + // Complete 'ms_opt_des_par' for simple cycle + ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] + ms_opt_des_par.m_fixed_P_mc_out = true; + + if (ms_opt_des_par.m_fixed_PR_HP_to_LP) + { + ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + } + else + { + ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] + } + + ms_opt_des_par.m_recomp_frac_guess = 0.0; + ms_opt_des_par.m_fixed_recomp_frac = true; + ms_opt_des_par.m_LT_frac_guess = 1.0; + ms_opt_des_par.m_fixed_LT_frac = true; + + int s_error_code = 0; + + opt_design_core(s_error_code); + + if (s_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) + { + ms_des_par_auto_opt = ms_des_par_optimal; + m_objective_metric_auto_opt = m_objective_metric_opt; + } + } + + ms_des_par = ms_des_par_auto_opt; + + int optimal_design_error_code = 0; + design_core(optimal_design_error_code); } void C_HTRBypass_Cycle::finalize_design(int& error_code) { } + + // Public Methods void C_HTRBypass_Cycle::design(S_design_parameters& des_par_in, int& error_code) @@ -90,7 +1001,13 @@ void C_HTRBypass_Cycle::reset_ms_od_turbo_bal_csp_solved() int C_HTRBypass_Cycle::auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in) { - return 0; + ms_auto_opt_des_par = auto_opt_des_par_in; + + int auto_opt_des_error_code = 0; + + auto_opt_design_core(auto_opt_des_error_code); + + return auto_opt_des_error_code; } int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg) diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index c1ff1824f4..c67f8bdf6d 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -66,12 +66,6 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core struct S_design_parameters { - // HTR Bypass ONLY parameters - double m_T_HTF_bp_out; // HTF Bypass HTX Outlet Temperature - double m_bp_frac; // Fraction of flow that bypasses HTR HP via bypass HTX - - - // Parameters SHARED with recompression double m_P_mc_in; //[kPa] Compressor inlet pressure @@ -202,7 +196,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core C_turbine m_t; C_comp_multi_stage m_mc_ms; C_comp_multi_stage m_rc_ms; - C_HeatExchanger m_PHX, m_PC, m_BP; + C_HeatExchanger m_PHX, m_PC; C_HX_co2_to_co2_CRM mc_LT_recup; C_HX_co2_to_co2_CRM mc_HT_recup; @@ -230,6 +224,26 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_objective_metric_auto_opt; S_design_parameters ms_des_par_auto_opt; + // NEW Internal Variables + double m_w_t; + double m_w_mc; + double m_w_rc; + double m_Q_dot_LT, m_Q_dot_HT; + double m_bp_frac; + double m_m_dot_bp; + double m_m_dot_htr_hp; + double m_cp_HTF; + double m_m_dot_HTF; + double m_Q_dot_BP; + double m_T_HTF_PHX_inlet; + double m_T_HTF_BP_outlet; + double m_T_HTF_PHX_out; + double m_dT_BP; // BYPASS_OUT - HTR_HP_OUT + double m_Q_dot_total; + double m_Q_dot_pc; // pre cooler heat rejected + + C_HX_co2_to_co2_CRM m_BP_HTX; + // New opt bool m_found_opt; double m_eta_phx_max; @@ -247,6 +261,12 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core void finalize_design(int& error_code); + // Added + int solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out_calc); + int solve_LTR(double T_LTR_LP_OUT_guess, double& T_LTR_LP_out_calc); + int solve_bypass(double T_BP_OUT_guess, double& T_BP_out_calc); + int solve_bypass_energy(double T_BP_OUT_guess, double& T_BP_out_calc); + public: C_HTRBypass_Cycle(C_sco2_cycle_core::E_turbo_gen_motor_config turbo_gen_motor_config, @@ -360,4 +380,5 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core }; + #endif From a4bb6a2fdc59bc2b888d347ec91a1a6d06be7a3f Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Thu, 20 Apr 2023 09:10:01 -0600 Subject: [PATCH 04/94] Fix bug in htr bypass solver --- tcs/sco2_htrbypass_cycle.cpp | 204 +++++++++++++++++++++++++++-------- tcs/sco2_htrbypass_cycle.h | 2 + tcs/sco2_pc_csp_int.cpp | 2 +- 3 files changed, 161 insertions(+), 47 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 9b1e5793f0..5cf9f2898e 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -40,24 +40,84 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. void C_HTRBypass_Cycle::design_core(int& error_code) -{ - design_core_standard(error_code); -} - -void C_HTRBypass_Cycle::design_core_standard(int& error_code) { // Temporary Hard coded parameters ms_des_par.m_recomp_frac = 0.3; m_cp_HTF = 1.482e+03; // J/kg K m_T_HTF_PHX_inlet = 670 + 273; // K + m_dT_BP = 10; m_T_HTF_BP_outlet = 770; // K + ms_des_par.m_P_mc_in = 10000; + ms_des_par.m_P_mc_out = 25000; + m_T_t_in = 923.149; + + // temp + double hot_approach = m_T_HTF_PHX_inlet - m_T_t_in; + + // Iterating bp_frac so the cold approach value is correct m_bp_frac = 0; - m_dT_BP = 0; + double des_HTF_cold_approach = hot_approach; + + // local + double error = 100000; + double frac_low = 0.0; + double frac_high = 1; + m_bp_frac = 0.5 * (frac_low + frac_high); + int count = 0; + while (std::abs(error) > 0.5) + { + // Update Bypass Fraction Guess + m_bp_frac = 0.5 * (frac_low + frac_high); + + // Run Calculation + design_core_standard(error_code); + + // Get Results + double actual_approach = m_HTF_cold_approach; + error = actual_approach - des_HTF_cold_approach; + + // Update Bounds + if (error > 0) + frac_low = m_bp_frac; + else + frac_high = m_bp_frac; + + if (count > 50) + break; + + count++; + } + + + // DEBUG + if (true) + { + std::vector frac_vec = { 0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1 }; + std::vector cold_approach; + + for (int i = 0; i < frac_vec.size(); i++) + { + m_bp_frac = frac_vec[i]; + // Run Calculation + design_core_standard(error_code); + + double actual_approach = m_HTF_cold_approach; + cold_approach.push_back(actual_approach); + } + } + + +} + +void C_HTRBypass_Cycle::design_core_standard(int& error_code) +{ // Apply scaling to the turbomachinery here - m_mc_ms.m_r_W_dot_scale = m_W_dot_net / 10.E3; //[-] - m_rc_ms.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] - m_t.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] + { + m_mc_ms.m_r_W_dot_scale = m_W_dot_net / 10.E3; //[-] + m_rc_ms.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] + m_t.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] + } CO2_state co2_props; @@ -71,13 +131,10 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) // Initialize a few variables { - //double m_dot_t, , m_dot_rc, Q_dot_LT, Q_dot_HT, UA_LT_calc, UA_HT_calc; - //m_dot_t = m_dot_mc = m_dot_rc = Q_dot_LT = Q_dot_HT = UA_LT_calc = UA_HT_calc = 0.0; - m_temp_last[MC_IN] = m_T_mc_in; //[K] - m_pres_last[MC_IN] = 10000; // ms_des_par.m_P_mc_in - m_pres_last[MC_OUT] = 25000; // ms_des_par.m_P_mc_out; // 25000 - m_temp_last[TURB_IN] = 923.149; // m_T_t_in; //[K] 923.149 + m_pres_last[MC_IN] = ms_des_par.m_P_mc_in; + m_pres_last[MC_OUT] = ms_des_par.m_P_mc_out; + m_temp_last[TURB_IN] = m_T_t_in; //[K] } // Apply pressure drops to heat exchangers, fully defining the pressures at all states @@ -147,13 +204,44 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } - // Set isentropic efficiency (temporary) - double eta_mc_isen, eta_t_isen; + // Determine equivalent isentropic efficiencies for main compressor and turbine, if necessary. + double eta_mc_isen = std::numeric_limits::quiet_NaN(); + double eta_t_isen = std::numeric_limits::quiet_NaN(); { - eta_mc_isen = m_eta_mc; - eta_t_isen = m_eta_t; + if (m_eta_mc < 0.0) + { + int poly_error_code = 0; + + isen_eta_from_poly_eta(m_temp_last[MC_IN], m_pres_last[MC_IN], m_pres_last[MC_OUT], std::abs(m_eta_mc), + true, poly_error_code, eta_mc_isen); + + if (poly_error_code != 0) + { + error_code = poly_error_code; + return; + } + } + else + eta_mc_isen = m_eta_mc; + + if (m_eta_t < 0.0) + { + int poly_error_code = 0; + + isen_eta_from_poly_eta(m_temp_last[TURB_IN], m_pres_last[TURB_IN], m_pres_last[TURB_OUT], std::abs(m_eta_t), + false, poly_error_code, eta_t_isen); + + if (poly_error_code != 0) + { + error_code = poly_error_code; + return; + } + } + else + eta_t_isen = m_eta_t; } + // Determine the outlet state and specific work for the main compressor and turbine. // Main compressor @@ -234,29 +322,33 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) // **************************************************** // **************************************************** // Solve the recuperators - { - double T_HTR_LP_out_lower = m_temp_last[MC_OUT]; //[K] Coldest possible temperature - double T_HTR_LP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature + double T_HTR_LP_out_lower = m_temp_last[MC_OUT]; //[K] Coldest possible temperature + double T_HTR_LP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature - double error = 1000; - double T_HTR_guess = 0.5 * (T_HTR_LP_out_lower + T_HTR_LP_out_upper); - double T_HTR_calc; - while (error > 0.1) - { - solve_HTR(T_HTR_guess, T_HTR_calc); - double guess_val = T_HTR_guess; - double calc_val = T_HTR_calc; + double error = 1000; + double T_HTR_guess = 0.5 * (T_HTR_LP_out_lower + T_HTR_LP_out_upper); + double T_HTR_calc; + while (error > 0.1) + { + solve_HTR(T_HTR_guess, T_HTR_calc); + double guess_val = T_HTR_guess; + double calc_val = T_HTR_calc; - error = std::abs(guess_val - calc_val); + error = std::abs(guess_val - calc_val); - // Update guess value - T_HTR_guess = 0.5 * (guess_val + calc_val); - } + // Update guess value + T_HTR_guess = 0.5 * (guess_val + calc_val); } + // State 5 can now be fully defined { - m_enth_last[HTR_HP_OUT] = m_enth_last[MIXER_OUT] + m_Q_dot_HT / m_m_dot_t; // Energy balance on cold stream of high-temp recuperator + // Check if there is flow through HTR_HP + if (m_m_dot_htr_hp <= 1e-12) + m_enth_last[HTR_HP_OUT] = m_enth_last[MIXER_OUT]; + else + m_enth_last[HTR_HP_OUT] = m_enth_last[MIXER_OUT] + m_Q_dot_HT / m_m_dot_htr_hp; // Energy balance on cold stream of high-temp recuperator + int prop_error_code = CO2_PH(m_pres_last[HTR_HP_OUT], m_enth_last[HTR_HP_OUT], &co2_props); if (prop_error_code != 0) { @@ -341,7 +433,6 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) // Calculate PHX Heat Transfer { m_Q_dot_PHX = m_m_dot_t * (m_enth_last[TURB_IN] - m_enth_last[MIXER2_OUT]); - int x = 0; } // Back Calculate and Check values @@ -354,9 +445,19 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) double qSum = m_Q_dot_total; double qSum_calc = m_Q_dot_BP + m_Q_dot_PHX; + } - int x = 0; + // HTF + { + // Calculate HTF Bypass Cold Approach + m_HTF_cold_approach = m_T_HTF_BP_outlet - m_temp_last[MIXER_OUT]; + + // Calculate HTF Mdot + m_m_dot_HTF = m_Q_dot_total / ((m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet) * m_cp_HTF); + + // Calculate PHX outlet Temp + m_T_HTF_PHX_out = m_T_HTF_PHX_inlet - (m_Q_dot_PHX / (m_m_dot_HTF * m_cp_HTF)); } } @@ -439,7 +540,6 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } } - int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out_calc) { @@ -533,14 +633,26 @@ int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out // Find the design solution of the HTR { - T_HTR_LP_out_calc = std::numeric_limits::quiet_NaN(); - this->mc_HT_recup.design_for_target__calc_outlet(this->ms_opt_des_par.m_HTR_target_code, - this->ms_opt_des_par.m_HTR_UA, this->ms_opt_des_par.m_HTR_min_dT, this->ms_opt_des_par.m_HTR_eff_target, - this->ms_opt_des_par.m_HTR_eff_max, - this->m_temp_last[MIXER_OUT], this->m_pres_last[MIXER_OUT], m_m_dot_htr_hp, this->m_pres_last[HTR_HP_OUT], - this->m_temp_last[TURB_OUT], this->m_pres_last[TURB_OUT], m_m_dot_t, this->m_pres_last[HTR_LP_OUT], - this->ms_opt_des_par.m_des_tol, - m_Q_dot_HT, this->m_temp_last[HTR_HP_OUT], T_HTR_LP_out_calc); + // If there is no flow through HTR HP side + if (m_m_dot_htr_hp < 1e-12) + { + m_Q_dot_HT = 0; + T_HTR_LP_out_calc = m_temp_last[TURB_OUT]; + } + + // If there is flow through HTR HP side + else + { + T_HTR_LP_out_calc = std::numeric_limits::quiet_NaN(); + this->mc_HT_recup.design_for_target__calc_outlet(this->ms_opt_des_par.m_HTR_target_code, + this->ms_opt_des_par.m_HTR_UA, this->ms_opt_des_par.m_HTR_min_dT, this->ms_opt_des_par.m_HTR_eff_target, + this->ms_opt_des_par.m_HTR_eff_max, + this->m_temp_last[MIXER_OUT], this->m_pres_last[MIXER_OUT], m_m_dot_htr_hp, this->m_pres_last[HTR_HP_OUT], + this->m_temp_last[TURB_OUT], this->m_pres_last[TURB_OUT], m_m_dot_t, this->m_pres_last[HTR_LP_OUT], + this->ms_opt_des_par.m_des_tol, + m_Q_dot_HT, this->m_temp_last[HTR_HP_OUT], T_HTR_LP_out_calc); + } + } } diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index c67f8bdf6d..322209da56 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -241,6 +241,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_dT_BP; // BYPASS_OUT - HTR_HP_OUT double m_Q_dot_total; double m_Q_dot_pc; // pre cooler heat rejected + double m_HTF_cold_approach; C_HX_co2_to_co2_CRM m_BP_HTX; @@ -262,6 +263,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core // Added + int solve_cycle(double bypass_fraction, double& error); int solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out_calc); int solve_LTR(double T_LTR_LP_OUT_guess, double& T_LTR_LP_out_calc); int solve_bypass(double T_BP_OUT_guess, double& T_BP_out_calc); diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index 939ebb3391..c9ffffb562 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -145,7 +145,7 @@ void C_sco2_phx_air_cooler::design_core() ms_des_par.m_N_nodes_pass, ms_des_par.m_T_amb_des, ms_des_par.m_elevation)); - s_cycle_config = "recompression"; + s_cycle_config = "htr bypass"; mpc_sco2_cycle = std::move(c_bp_cycle); } From e8ffc4a94f40f24425d6b9590f03d536c05d486a Mon Sep 17 00:00:00 2001 From: taylorbrown75 Date: Mon, 1 May 2023 10:57:08 -0600 Subject: [PATCH 05/94] Change target cold approach temperature to PHX (instead of Bypass) --- tcs/sco2_htrbypass_cycle.cpp | 19 ++++++++++++------- tcs/sco2_htrbypass_cycle.h | 3 ++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 5cf9f2898e..3eaf4b1a8d 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -56,7 +56,7 @@ void C_HTRBypass_Cycle::design_core(int& error_code) // Iterating bp_frac so the cold approach value is correct m_bp_frac = 0; - double des_HTF_cold_approach = hot_approach; + double des_HTF_PHX_cold_approach = hot_approach; // local double error = 100000; @@ -73,11 +73,11 @@ void C_HTRBypass_Cycle::design_core(int& error_code) design_core_standard(error_code); // Get Results - double actual_approach = m_HTF_cold_approach; - error = actual_approach - des_HTF_cold_approach; + double actual_approach = m_HTF_PHX_cold_approach; + error = actual_approach - des_HTF_PHX_cold_approach; // Update Bounds - if (error > 0) + if (error < 0) frac_low = m_bp_frac; else frac_high = m_bp_frac; @@ -102,12 +102,14 @@ void C_HTRBypass_Cycle::design_core(int& error_code) // Run Calculation design_core_standard(error_code); - double actual_approach = m_HTF_cold_approach; + double actual_approach = m_HTF_PHX_cold_approach; cold_approach.push_back(actual_approach); } - } + int x = 0; + } + } void C_HTRBypass_Cycle::design_core_standard(int& error_code) @@ -451,13 +453,16 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) // HTF { // Calculate HTF Bypass Cold Approach - m_HTF_cold_approach = m_T_HTF_BP_outlet - m_temp_last[MIXER_OUT]; + m_HTF_BP_cold_approach = m_T_HTF_BP_outlet - m_temp_last[MIXER_OUT]; // Calculate HTF Mdot m_m_dot_HTF = m_Q_dot_total / ((m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet) * m_cp_HTF); // Calculate PHX outlet Temp m_T_HTF_PHX_out = m_T_HTF_PHX_inlet - (m_Q_dot_PHX / (m_m_dot_HTF * m_cp_HTF)); + + // Calculate PHX Cold Approach + m_HTF_PHX_cold_approach = m_T_HTF_PHX_out - m_temp_last[MIXER2_OUT]; } } diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 322209da56..3d8ef27af9 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -241,7 +241,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_dT_BP; // BYPASS_OUT - HTR_HP_OUT double m_Q_dot_total; double m_Q_dot_pc; // pre cooler heat rejected - double m_HTF_cold_approach; + double m_HTF_BP_cold_approach; + double m_HTF_PHX_cold_approach; C_HX_co2_to_co2_CRM m_BP_HTX; From aaa879ea6aad732b9553fb2a2b32f687a304f595 Mon Sep 17 00:00:00 2001 From: taylorbrown75 Date: Tue, 2 May 2023 11:21:38 -0600 Subject: [PATCH 06/94] Fix bug to make htr bypass callable from python --- ssc/cmod_sco2_csp_system.cpp | 2 +- tcs/sco2_htrbypass_cycle.cpp | 646 ++++++++++++++++++----------------- tcs/sco2_htrbypass_cycle.h | 9 +- 3 files changed, 334 insertions(+), 323 deletions(-) diff --git a/ssc/cmod_sco2_csp_system.cpp b/ssc/cmod_sco2_csp_system.cpp index 85aff0ac31..94cfe71386 100644 --- a/ssc/cmod_sco2_csp_system.cpp +++ b/ssc/cmod_sco2_csp_system.cpp @@ -332,7 +332,7 @@ class cm_sco2_csp_system : public compute_module void exec() override { // Debug to launch HTR Bypass - if (true) + if (false) { // inputs C_sco2_cycle_core::E_turbo_gen_motor_config turbo_gen_motor_config = static_cast(0); diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 3eaf4b1a8d..aab1f8e52b 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -35,6 +35,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "CO2_properties.h" +#include "nlopt.hpp" +#include "nlopt_callbacks.h" + #include "fmin.h" @@ -90,7 +93,7 @@ void C_HTRBypass_Cycle::design_core(int& error_code) // DEBUG - if (true) + if (false) { std::vector frac_vec = { 0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1 }; std::vector cold_approach; @@ -321,27 +324,26 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } } - // **************************************************** - // **************************************************** // Solve the recuperators - double T_HTR_LP_out_lower = m_temp_last[MC_OUT]; //[K] Coldest possible temperature - double T_HTR_LP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature - - double error = 1000; - double T_HTR_guess = 0.5 * (T_HTR_LP_out_lower + T_HTR_LP_out_upper); - double T_HTR_calc; - while (error > 0.1) { - solve_HTR(T_HTR_guess, T_HTR_calc); - double guess_val = T_HTR_guess; - double calc_val = T_HTR_calc; + double T_HTR_LP_out_lower = m_temp_last[MC_OUT]; //[K] Coldest possible temperature + double T_HTR_LP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature - error = std::abs(guess_val - calc_val); + double error = 1000; + double T_HTR_guess = 0.5 * (T_HTR_LP_out_lower + T_HTR_LP_out_upper); + double T_HTR_calc; + while (error > 0.1) + { + solve_HTR(T_HTR_guess, T_HTR_calc); + double guess_val = T_HTR_guess; + double calc_val = T_HTR_calc; - // Update guess value - T_HTR_guess = 0.5 * (guess_val + calc_val); - } + error = std::abs(guess_val - calc_val); + // Update guess value + T_HTR_guess = 0.5 * (guess_val + calc_val); + } + } // State 5 can now be fully defined { @@ -362,7 +364,7 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) m_dens_last[HTR_HP_OUT] = co2_props.dens; } - // Calculate cycle performance metrics (including total heat coming into cycle) + // Calculate total heat coming into cycle { m_W_dot_mc = m_w_mc * m_m_dot_mc; //[kWe] m_W_dot_rc = m_w_rc * m_m_dot_rc; //[kWe] @@ -374,174 +376,109 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) m_Q_dot_total = m_W_dot_net_last + m_Q_dot_pc; } - // Define bypass out temperature - if (true) + // Calculate Bypass Energy { - // Calculate Bypass Energy - { - // Set Bypass Temp based on HTR_HP_OUT - m_temp_last[BYPASS_OUT] = m_temp_last[HTR_HP_OUT] + m_dT_BP; + // Set Bypass Temp based on HTR_HP_OUT + m_temp_last[BYPASS_OUT] = m_temp_last[HTR_HP_OUT] + m_dT_BP; - // Calculate BYPASS_OUT properties - int prop_error_code = CO2_TP(this->m_temp_last[BYPASS_OUT], this->m_pres_last[BYPASS_OUT], &this->mc_co2_props); - if (prop_error_code != 0) - { - return; - } - this->m_enth_last[BYPASS_OUT] = this->mc_co2_props.enth; - this->m_entr_last[BYPASS_OUT] = this->mc_co2_props.entr; - this->m_dens_last[BYPASS_OUT] = this->mc_co2_props.dens; - - // Calculate Heat Transfer in Bypass - m_Q_dot_BP = m_m_dot_bp * (m_enth_last[BYPASS_OUT] - m_enth_last[MIXER_OUT]); + // Calculate BYPASS_OUT properties + int prop_error_code = CO2_TP(this->m_temp_last[BYPASS_OUT], this->m_pres_last[BYPASS_OUT], &this->mc_co2_props); + if (prop_error_code != 0) + { + return; } + this->m_enth_last[BYPASS_OUT] = this->mc_co2_props.enth; + this->m_entr_last[BYPASS_OUT] = this->mc_co2_props.entr; + this->m_dens_last[BYPASS_OUT] = this->mc_co2_props.dens; - // Simulate Mixer 2 - { - // If Bypass and HTR have flow - if (m_bp_frac >= 1e-12 && m_bp_frac <= (1.0 - 1e-12)) - { - m_enth_last[MIXER2_OUT] = (1.0 - m_bp_frac) * m_enth_last[HTR_HP_OUT] + - m_bp_frac * m_enth_last[BYPASS_OUT]; //[kJ/kg] + // Calculate Heat Transfer in Bypass + m_Q_dot_BP = m_m_dot_bp * (m_enth_last[BYPASS_OUT] - m_enth_last[MIXER_OUT]); + } - int prop_error_code = CO2_PH(m_pres_last[MIXER2_OUT], m_enth_last[MIXER2_OUT], &mc_co2_props); - if (prop_error_code != 0) - { - return; - } - m_temp_last[MIXER2_OUT] = mc_co2_props.temp; //[K] - m_entr_last[MIXER2_OUT] = mc_co2_props.entr; //[kJ/kg-K] - m_dens_last[MIXER2_OUT] = mc_co2_props.dens; //[kg/m^3] + // Simulate Mixer 2 + { + // If Bypass and HTR have flow + if (m_bp_frac >= 1e-12 && m_bp_frac <= (1.0 - 1e-12)) + { + m_enth_last[MIXER2_OUT] = (1.0 - m_bp_frac) * m_enth_last[HTR_HP_OUT] + + m_bp_frac * m_enth_last[BYPASS_OUT]; //[kJ/kg] - } - // Flow only through HTR - else if (m_bp_frac <= (1.0 - 1e-12)) - { - m_temp_last[MIXER2_OUT] = m_temp_last[HTR_HP_OUT]; //[K] - m_enth_last[MIXER2_OUT] = m_enth_last[HTR_HP_OUT]; //[kJ/kg] - m_entr_last[MIXER2_OUT] = m_entr_last[HTR_HP_OUT]; //[kJ/kg-K] - m_dens_last[MIXER2_OUT] = m_dens_last[HTR_HP_OUT]; //[kg/m^3] - } - // Flow only through Bypass - else + int prop_error_code = CO2_PH(m_pres_last[MIXER2_OUT], m_enth_last[MIXER2_OUT], &mc_co2_props); + if (prop_error_code != 0) { - m_temp_last[MIXER2_OUT] = m_temp_last[BYPASS_OUT]; //[K] - m_enth_last[MIXER2_OUT] = m_enth_last[BYPASS_OUT]; //[kJ/kg] - m_entr_last[MIXER2_OUT] = m_entr_last[BYPASS_OUT]; //[kJ/kg-K] - m_dens_last[MIXER2_OUT] = m_dens_last[BYPASS_OUT]; //[kg/m^3] + return; } - } + m_temp_last[MIXER2_OUT] = mc_co2_props.temp; //[K] + m_entr_last[MIXER2_OUT] = mc_co2_props.entr; //[kJ/kg-K] + m_dens_last[MIXER2_OUT] = mc_co2_props.dens; //[kg/m^3] - // Calculate PHX Heat Transfer - { - m_Q_dot_PHX = m_m_dot_t * (m_enth_last[TURB_IN] - m_enth_last[MIXER2_OUT]); } - - // Back Calculate and Check values + // Flow only through HTR + else if (m_bp_frac <= (1.0 - 1e-12)) { - // Bypass Temps - double bp_temp_in = m_temp_last[MIXER_OUT]; - double bp_temp_out = m_temp_last[BYPASS_OUT]; - - double real_q_dot_total = m_W_dot_t + m_Q_dot_pc; - - double qSum = m_Q_dot_total; - double qSum_calc = m_Q_dot_BP + m_Q_dot_PHX; + m_temp_last[MIXER2_OUT] = m_temp_last[HTR_HP_OUT]; //[K] + m_enth_last[MIXER2_OUT] = m_enth_last[HTR_HP_OUT]; //[kJ/kg] + m_entr_last[MIXER2_OUT] = m_entr_last[HTR_HP_OUT]; //[kJ/kg-K] + m_dens_last[MIXER2_OUT] = m_dens_last[HTR_HP_OUT]; //[kg/m^3] } - - - // HTF + // Flow only through Bypass + else { - // Calculate HTF Bypass Cold Approach - m_HTF_BP_cold_approach = m_T_HTF_BP_outlet - m_temp_last[MIXER_OUT]; - - // Calculate HTF Mdot - m_m_dot_HTF = m_Q_dot_total / ((m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet) * m_cp_HTF); - - // Calculate PHX outlet Temp - m_T_HTF_PHX_out = m_T_HTF_PHX_inlet - (m_Q_dot_PHX / (m_m_dot_HTF * m_cp_HTF)); - - // Calculate PHX Cold Approach - m_HTF_PHX_cold_approach = m_T_HTF_PHX_out - m_temp_last[MIXER2_OUT]; + m_temp_last[MIXER2_OUT] = m_temp_last[BYPASS_OUT]; //[K] + m_enth_last[MIXER2_OUT] = m_enth_last[BYPASS_OUT]; //[kJ/kg] + m_entr_last[MIXER2_OUT] = m_entr_last[BYPASS_OUT]; //[kJ/kg-K] + m_dens_last[MIXER2_OUT] = m_dens_last[BYPASS_OUT]; //[kg/m^3] } + } + // Calculate PHX Heat Transfer + { + m_Q_dot_PHX = m_m_dot_t * (m_enth_last[TURB_IN] - m_enth_last[MIXER2_OUT]); } - // old bypass method - if (false) + // Back Calculate and Check values { - // Calculate Total Heat Coming into Cycle - { - m_W_dot_mc = m_w_mc * m_m_dot_mc; - m_W_dot_rc = m_w_rc * m_m_dot_rc; - m_W_dot_t = m_w_t * m_m_dot_t; - m_Q_dot_total = m_W_dot_mc + m_W_dot_rc + m_W_dot_t + m_Q_dot_pc; - } + // Bypass Temps + double bp_temp_in = m_temp_last[MIXER_OUT]; + double bp_temp_out = m_temp_last[BYPASS_OUT]; - // Calculate HTF Mass Flow Rate - { - m_m_dot_HTF = m_Q_dot_total / ((m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet) * m_cp_HTF); - } + double real_q_dot_total = m_W_dot_t + m_Q_dot_pc; + double qSum = m_Q_dot_total; + double qSum_calc = m_Q_dot_BP + m_Q_dot_PHX; + } - // Solve Bypass Outlet Temperature - { - double T_BP_out_lower = m_temp_last[MIXER_OUT]; //[K] Coldest possible temperature - double T_BP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature + // HTF + { + // Calculate HTF Bypass Cold Approach + m_HTF_BP_cold_approach = m_T_HTF_BP_outlet - m_temp_last[MIXER_OUT]; - double error = 1000; - double T_BP_guess = 0.5 * (T_BP_out_lower + T_BP_out_upper); - double T_BP_calc; - while (error > 0.1) - { - solve_bypass(T_BP_guess, T_BP_calc); - double guess_val = T_BP_guess; - double calc_val = T_BP_calc; + // Calculate HTF Mdot + m_m_dot_HTF = m_Q_dot_total / ((m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet) * m_cp_HTF); - error = std::abs(guess_val - calc_val); + // Calculate PHX outlet Temp + m_T_HTF_PHX_out = m_T_HTF_PHX_inlet - (m_Q_dot_PHX / (m_m_dot_HTF * m_cp_HTF)); - // Update guess value - T_BP_guess = 0.5 * (guess_val + calc_val); - } - } + // Calculate PHX Cold Approach + m_HTF_PHX_cold_approach = m_T_HTF_PHX_out - m_temp_last[MIXER2_OUT]; } - // Iterate over energy - if (false) + // Set objective metric { - // Calculate Total Heat Coming into Cycle + + m_eta_thermal_calc_last = m_W_dot_net_last / m_Q_dot_total; + + if (ms_des_par.m_des_objective_type == 2) { - m_W_dot_mc = m_w_mc * m_m_dot_mc; - m_W_dot_rc = m_w_rc * m_m_dot_rc; - m_W_dot_t = m_w_t * m_m_dot_t; - double m_Q_dot_pc = m_m_dot_mc * (m_enth_last[LTR_LP_OUT] - m_enth_last[MC_IN]); - m_Q_dot_total = m_W_dot_mc + m_W_dot_rc + m_W_dot_t + m_Q_dot_pc; + double phx_deltaT = m_temp_last[TURB_IN] - m_temp_last[HTR_HP_OUT]; + double under_min_deltaT = std::max(0.0, ms_des_par.m_min_phx_deltaT - phx_deltaT); + double eta_deltaT_scale = std::exp(-under_min_deltaT); + m_objective_metric_last = m_eta_thermal_calc_last * eta_deltaT_scale; } - - // Solve Bypass Outlet Temperature + else { - double T_BP_out_lower = m_temp_last[MIXER_OUT]; //[K] Coldest possible temperature - double T_BP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature - - double error = 1000; - double T_BP_guess = 0.5 * (T_BP_out_lower + T_BP_out_upper); - double T_BP_calc; - while (error > 0.1) - { - solve_bypass_energy(T_BP_guess, T_BP_calc); - double guess_val = T_BP_guess; - double calc_val = T_BP_calc; - - error = std::abs(guess_val - calc_val); - - // Update guess value - T_BP_guess = 0.5 * (guess_val + calc_val); - } - - int x = 0; + m_objective_metric_last = m_eta_thermal_calc_last; } - - } } @@ -566,10 +503,7 @@ int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out this->m_entr_last[HTR_LP_OUT] = this->mc_co2_props.entr; this->m_dens_last[HTR_LP_OUT] = this->mc_co2_props.dens; } - - // ********************************************************************************* - // ********************************************************************************* // Solve for the LTR solution { double T_LTR_LP_out_lower = this->m_temp_last[MC_OUT]; //[K] Coldest possible outlet temperature @@ -592,8 +526,7 @@ int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out } } - // Know LTR performance so we can calculate the HP outlet - // Energy balance on LTR HP stream + // Know LTR performance so we can calculate the HP outlet (Energy balance on LTR HP stream) { this->m_enth_last[LTR_HP_OUT] = this->m_enth_last[MC_OUT] + m_Q_dot_LT / m_m_dot_mc; //[kJ/kg] int prop_error_code = CO2_PH(this->m_pres_last[LTR_HP_OUT], this->m_enth_last[LTR_HP_OUT], &this->mc_co2_props); @@ -635,7 +568,6 @@ int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out m_m_dot_htr_hp = m_m_dot_t - m_m_dot_bp; } - // Find the design solution of the HTR { // If there is no flow through HTR HP side @@ -649,12 +581,12 @@ int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out else { T_HTR_LP_out_calc = std::numeric_limits::quiet_NaN(); - this->mc_HT_recup.design_for_target__calc_outlet(this->ms_opt_des_par.m_HTR_target_code, - this->ms_opt_des_par.m_HTR_UA, this->ms_opt_des_par.m_HTR_min_dT, this->ms_opt_des_par.m_HTR_eff_target, - this->ms_opt_des_par.m_HTR_eff_max, + this->mc_HT_recup.design_for_target__calc_outlet(this->ms_des_par.m_HTR_target_code, + this->ms_des_par.m_HTR_UA, this->ms_des_par.m_HTR_min_dT, this->ms_des_par.m_HTR_eff_target, + this->ms_des_par.m_HTR_eff_max, this->m_temp_last[MIXER_OUT], this->m_pres_last[MIXER_OUT], m_m_dot_htr_hp, this->m_pres_last[HTR_HP_OUT], this->m_temp_last[TURB_OUT], this->m_pres_last[TURB_OUT], m_m_dot_t, this->m_pres_last[HTR_LP_OUT], - this->ms_opt_des_par.m_des_tol, + this->ms_des_par.m_des_tol, m_Q_dot_HT, this->m_temp_last[HTR_HP_OUT], T_HTR_LP_out_calc); } @@ -735,199 +667,157 @@ int C_HTRBypass_Cycle::solve_LTR(double T_LTR_LP_OUT_guess, double& T_LTR_LP_out // Solve LTR T_LTR_LP_out_calc = std::numeric_limits::quiet_NaN(); { - this->mc_LT_recup.design_for_target__calc_outlet(this->ms_opt_des_par.m_LTR_target_code, - this->ms_opt_des_par.m_LTR_UA, this->ms_opt_des_par.m_LTR_min_dT, this->ms_opt_des_par.m_LTR_eff_target, - this->ms_opt_des_par.m_LTR_eff_max, + this->mc_LT_recup.design_for_target__calc_outlet(this->ms_des_par.m_LTR_target_code, + this->ms_des_par.m_LTR_UA, this->ms_des_par.m_LTR_min_dT, this->ms_des_par.m_LTR_eff_target, + this->ms_des_par.m_LTR_eff_max, this->m_temp_last[MC_OUT], this->m_pres_last[MC_OUT], m_m_dot_mc, this->m_pres_last[LTR_HP_OUT], this->m_temp_last[HTR_LP_OUT], this->m_pres_last[HTR_LP_OUT], m_m_dot_t, this->m_pres_last[LTR_LP_OUT], - this->ms_opt_des_par.m_des_tol, + this->ms_des_par.m_des_tol, m_Q_dot_LT, this->m_temp_last[LTR_HP_OUT], T_LTR_LP_out_calc); } } -int C_HTRBypass_Cycle::solve_bypass(double T_BP_OUT_guess, double& T_BP_out_calc) +void C_HTRBypass_Cycle::opt_design_core(int& error_code) { - // Set temperature guess - m_temp_last[BYPASS_OUT] = T_BP_OUT_guess; //[K] - - // Solve BYPASS_OUT properties - { - int prop_error_code = CO2_TP(this->m_temp_last[BYPASS_OUT], this->m_pres_last[BYPASS_OUT], &this->mc_co2_props); - if (prop_error_code != 0) - { - return prop_error_code; - } - this->m_enth_last[BYPASS_OUT] = this->mc_co2_props.enth; - this->m_entr_last[BYPASS_OUT] = this->mc_co2_props.entr; - this->m_dens_last[BYPASS_OUT] = this->mc_co2_props.dens; - } + // Map ms_opt_des_par to ms_des_par + // LTR thermal design + ms_des_par.m_LTR_target_code = ms_opt_des_par.m_LTR_target_code; //[-] + ms_des_par.m_LTR_min_dT = ms_opt_des_par.m_LTR_min_dT; //[K] + ms_des_par.m_LTR_eff_target = ms_opt_des_par.m_LTR_eff_target; //[-] + ms_des_par.m_LTR_eff_max = ms_opt_des_par.m_LTR_eff_max; //[-] + ms_des_par.m_LTR_od_UA_target_type = ms_opt_des_par.m_LTR_od_UA_target_type; + // HTR thermal design + ms_des_par.m_HTR_target_code = ms_opt_des_par.m_HTR_target_code; //[-] + ms_des_par.m_HTR_min_dT = ms_opt_des_par.m_HTR_min_dT; //[K] + ms_des_par.m_HTR_eff_target = ms_opt_des_par.m_HTR_eff_target; //[-] + ms_des_par.m_HTR_eff_max = ms_opt_des_par.m_HTR_eff_max; //[-] + ms_des_par.m_HTR_od_UA_target_type = ms_opt_des_par.m_HTR_od_UA_target_type; + // + ms_des_par.m_des_tol = ms_opt_des_par.m_des_tol; - // Simulate Mixer 2 - { - // If Bypass and HTR have flow - if (m_bp_frac >= 1e-12 && m_bp_frac <= (1.0-1e-12)) - { - m_enth_last[MIXER2_OUT] = (1.0 - m_bp_frac) * m_enth_last[HTR_HP_OUT] + - m_bp_frac * m_enth_last[BYPASS_OUT]; //[kJ/kg] + ms_des_par.m_is_des_air_cooler = ms_opt_des_par.m_is_des_air_cooler; //[-] - int prop_error_code = CO2_PH(m_pres_last[MIXER2_OUT], m_enth_last[MIXER2_OUT], &mc_co2_props); - if (prop_error_code != 0) - { - return prop_error_code; - } - m_temp_last[MIXER2_OUT] = mc_co2_props.temp; //[K] - m_entr_last[MIXER2_OUT] = mc_co2_props.entr; //[kJ/kg-K] - m_dens_last[MIXER2_OUT] = mc_co2_props.dens; //[kg/m^3] + ms_des_par.m_des_objective_type = ms_opt_des_par.m_des_objective_type; //[-] + ms_des_par.m_min_phx_deltaT = ms_opt_des_par.m_min_phx_deltaT; //[C] - } - // Flow only through HTR - else if (m_bp_frac <= (1.0 - 1e-12)) - { - m_temp_last[MIXER2_OUT] = m_temp_last[HTR_HP_OUT]; //[K] - m_enth_last[MIXER2_OUT] = m_enth_last[HTR_HP_OUT]; //[kJ/kg] - m_entr_last[MIXER2_OUT] = m_entr_last[HTR_HP_OUT]; //[kJ/kg-K] - m_dens_last[MIXER2_OUT] = m_dens_last[HTR_HP_OUT]; //[kg/m^3] - } - // Flow only through Bypass - else - { - m_temp_last[MIXER2_OUT] = m_temp_last[BYPASS_OUT]; //[K] - m_enth_last[MIXER2_OUT] = m_enth_last[BYPASS_OUT]; //[kJ/kg] - m_entr_last[MIXER2_OUT] = m_entr_last[BYPASS_OUT]; //[kJ/kg-K] - m_dens_last[MIXER2_OUT] = m_dens_last[BYPASS_OUT]; //[kg/m^3] - } - } + // ms_des_par members to be defined by optimizer and set in 'design_point_eta': + // m_P_mc_in + // m_P_mc_out + // m_recomp_frac + // m_UA_LT + // m_UA_HT - // Calculate Heat From PHX - m_Q_dot_PHX = m_m_dot_t * (m_enth_last[TURB_IN] - m_enth_last[MIXER2_OUT]); + int index = 0; - // Calculate HTF PHX Outlet Temp - m_T_HTF_PHX_out = m_T_HTF_PHX_inlet - (m_Q_dot_PHX / (m_cp_HTF * m_m_dot_HTF)); + std::vector x(0); + std::vector lb(0); + std::vector ub(0); + std::vector scale(0); - // Check if HTF PHX Outlet is higher than BP outlet - if (m_T_HTF_PHX_out < m_T_HTF_BP_outlet) + if (!ms_opt_des_par.m_fixed_P_mc_out) { - // Something is wrong - } + x.push_back(ms_opt_des_par.m_P_mc_out_guess); + lb.push_back(100.0); + ub.push_back(m_P_high_limit); + scale.push_back(500.0); + index++; + } - // Solve Bypass HTX + if (!ms_opt_des_par.m_fixed_PR_HP_to_LP) { - // Calculate Heat Transfer in Bypass - m_Q_dot_BP = m_m_dot_HTF * m_cp_HTF * (m_T_HTF_PHX_out - m_T_HTF_BP_outlet); - - // Calculate Enthalpy at sco2 bypass outlet - double h_bp_out_calc = (m_Q_dot_BP / m_m_dot_bp) + m_enth_last[MIXER_OUT]; + x.push_back(ms_opt_des_par.m_PR_HP_to_LP_guess); + lb.push_back(0.0001); + double PR_max = m_P_high_limit / 100.0; + ub.push_back(PR_max); + scale.push_back(0.2); - // Calculate Temperature - int prop_error_code = CO2_PH(m_pres_last[BYPASS_OUT], h_bp_out_calc, &mc_co2_props); - if (prop_error_code != 0) - { - return prop_error_code; - } - T_BP_out_calc = mc_co2_props.temp; - - int x = 0; + index++; } + if (!ms_opt_des_par.m_fixed_recomp_frac) + { + x.push_back(ms_opt_des_par.m_recomp_frac_guess); + lb.push_back(0.0); + ub.push_back(1.0); + scale.push_back(0.05); - return 0; -} - -int C_HTRBypass_Cycle::solve_bypass_energy(double T_BP_OUT_guess, double& T_BP_out_calc) -{ - // Set temperature guess - m_temp_last[BYPASS_OUT] = T_BP_OUT_guess; //[K] + index++; + } - // Solve BYPASS_OUT properties + if (!ms_opt_des_par.m_fixed_LT_frac) { - int prop_error_code = CO2_TP(this->m_temp_last[BYPASS_OUT], this->m_pres_last[BYPASS_OUT], &this->mc_co2_props); - if (prop_error_code != 0) - { - return prop_error_code; - } - this->m_enth_last[BYPASS_OUT] = this->mc_co2_props.enth; - this->m_entr_last[BYPASS_OUT] = this->mc_co2_props.entr; - this->m_dens_last[BYPASS_OUT] = this->mc_co2_props.dens; + x.push_back(ms_opt_des_par.m_LT_frac_guess); + lb.push_back(0.0); + ub.push_back(1.0); + scale.push_back(0.05); + + index++; } - // Calculate Bypass Heat Exchanged + error_code = 0; + if (index > 0) { - m_Q_dot_BP = m_m_dot_bp * (m_enth_last[BYPASS_OUT] - m_enth_last[MIXER_OUT]); + // Ensure thermal efficiency is initialized to 0 + m_objective_metric_opt = 0.0; + + // Set up instance of nlopt class and set optimization parameters + nlopt::opt opt_des_cycle(nlopt::LN_SBPLX, index); + opt_des_cycle.set_lower_bounds(lb); + opt_des_cycle.set_upper_bounds(ub); + opt_des_cycle.set_initial_step(scale); + opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); + + // Set max objective function + opt_des_cycle.set_max_objective(nlopt_cb_opt_htr_bypass_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' + double max_f = std::numeric_limits::quiet_NaN(); + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + + ms_des_par = ms_des_par_optimal; + + design_core(error_code); + + /* + m_W_dot_net_last = m_W_dot_net_opt; + m_eta_thermal_last = m_eta_thermal_opt; + m_temp_last = m_temp_opt; + m_pres_last = m_pres_opt; + m_enth_last = m_enth_opt; + m_entr_last = m_entr_opt; + m_dens_last = m_dens_opt; + */ } - - // Simulate Mixer 2 + else { - // If Bypass and HTR have flow - if (m_bp_frac >= 1e-12 && m_bp_frac <= (1.0 - 1e-12)) - { - m_enth_last[MIXER2_OUT] = (1.0 - m_bp_frac) * m_enth_last[HTR_HP_OUT] + - m_bp_frac * m_enth_last[BYPASS_OUT]; //[kJ/kg] - - int prop_error_code = CO2_PH(m_pres_last[MIXER2_OUT], m_enth_last[MIXER2_OUT], &mc_co2_props); - if (prop_error_code != 0) - { - return prop_error_code; - } - m_temp_last[MIXER2_OUT] = mc_co2_props.temp; //[K] - m_entr_last[MIXER2_OUT] = mc_co2_props.entr; //[kJ/kg-K] - m_dens_last[MIXER2_OUT] = mc_co2_props.dens; //[kg/m^3] + // Finish defining ms_des_par based on current 'x' values + ms_des_par.m_P_mc_out = ms_opt_des_par.m_P_mc_out_guess; + ms_des_par.m_P_mc_in = ms_des_par.m_P_mc_out / ms_opt_des_par.m_PR_HP_to_LP_guess; + ms_des_par.m_recomp_frac = ms_opt_des_par.m_recomp_frac_guess; - } - // Flow only through HTR - else if (m_bp_frac <= (1.0 - 1e-12)) + if (ms_opt_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) { - m_temp_last[MIXER2_OUT] = m_temp_last[HTR_HP_OUT]; //[K] - m_enth_last[MIXER2_OUT] = m_enth_last[HTR_HP_OUT]; //[kJ/kg] - m_entr_last[MIXER2_OUT] = m_entr_last[HTR_HP_OUT]; //[kJ/kg-K] - m_dens_last[MIXER2_OUT] = m_dens_last[HTR_HP_OUT]; //[kg/m^3] + ms_des_par.m_LTR_UA = ms_opt_des_par.m_UA_rec_total * ms_opt_des_par.m_LT_frac_guess; + ms_des_par.m_HTR_UA = ms_opt_des_par.m_UA_rec_total * (1.0 - ms_opt_des_par.m_LT_frac_guess); } - // Flow only through Bypass else { - m_temp_last[MIXER2_OUT] = m_temp_last[BYPASS_OUT]; //[K] - m_enth_last[MIXER2_OUT] = m_enth_last[BYPASS_OUT]; //[kJ/kg] - m_entr_last[MIXER2_OUT] = m_entr_last[BYPASS_OUT]; //[kJ/kg-K] - m_dens_last[MIXER2_OUT] = m_dens_last[BYPASS_OUT]; //[kg/m^3] + ms_des_par.m_LTR_UA = ms_opt_des_par.m_LTR_UA; //[kW/K] + ms_des_par.m_HTR_UA = ms_opt_des_par.m_HTR_UA; //[kW/K] } - } - - // Calculate Heat From PHX - m_Q_dot_PHX = m_m_dot_t * (m_enth_last[TURB_IN] - m_enth_last[MIXER2_OUT]); - - // Back Calculate Bypass Q_dot using Sum - double q_dot_bp_calc = m_Q_dot_total - m_Q_dot_PHX; - - double error = q_dot_bp_calc - m_Q_dot_BP; - // Negative Bypass energy means temperature is too low - /*if (q_dot_bp_calc < 0) - { - T_BP_out_calc = m_enth_last[TURB_IN]; - return 0; - }*/ - - // Back Calculate sco2 bypass outlet temperature - { - double enth_bp_out_calc = m_enth_last[MIXER_OUT] + (q_dot_bp_calc / m_m_dot_bp); + // Ensure thermal efficiency is initialized to 0 + m_objective_metric_opt = 0.0; + double eta_local = design_cycle_return_objective_metric(x); - int prop_error_code = CO2_PH(m_pres_last[BYPASS_OUT], enth_bp_out_calc, &mc_co2_props); - if (prop_error_code != 0) + if (eta_local == 0.0) { - return prop_error_code; + error_code = -1; + return; } - T_BP_out_calc = mc_co2_props.temp; - } - -} - - - - -void C_HTRBypass_Cycle::opt_design_core(int& error_code) -{ + ms_des_par_optimal = ms_des_par; + } } void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) @@ -1127,6 +1017,116 @@ int C_HTRBypass_Cycle::auto_opt_design(S_auto_opt_design_parameters& auto_opt_de return auto_opt_des_error_code; } + + +double C_HTRBypass_Cycle::design_cycle_return_objective_metric(const std::vector& x) +{ + // 'x' is array of inputs either being adjusted by optimizer or set constant + // Finish defining ms_des_par based on current 'x' values + + int index = 0; + + // Main compressor outlet pressure + if (!ms_opt_des_par.m_fixed_P_mc_out) + { + ms_des_par.m_P_mc_out = x[index]; + if (ms_des_par.m_P_mc_out > m_P_high_limit) + return 0.0; + index++; + } + else + ms_des_par.m_P_mc_out = ms_opt_des_par.m_P_mc_out_guess; + + // Main compressor pressure ratio + double PR_mc_local = -999.9; + double P_mc_in = -999.9; + if (!ms_opt_des_par.m_fixed_PR_HP_to_LP) + { + PR_mc_local = x[index]; + if (PR_mc_local > 50.0) + return 0.0; + index++; + P_mc_in = ms_des_par.m_P_mc_out / PR_mc_local; + } + else + { + if (ms_opt_des_par.m_PR_HP_to_LP_guess >= 0.0) + { + PR_mc_local = ms_opt_des_par.m_PR_HP_to_LP_guess; + P_mc_in = ms_des_par.m_P_mc_out / PR_mc_local; //[kPa] + } + else + { + P_mc_in = std::abs(ms_opt_des_par.m_PR_HP_to_LP_guess); //[kPa] + } + } + + + if (P_mc_in >= ms_des_par.m_P_mc_out) + return 0.0; + if (P_mc_in <= 100.0) + return 0.0; + ms_des_par.m_P_mc_in = P_mc_in; + + // Recompression fraction + if (!ms_opt_des_par.m_fixed_recomp_frac) + { + ms_des_par.m_recomp_frac = x[index]; + if (ms_des_par.m_recomp_frac < 0.0) + return 0.0; + index++; + } + else + ms_des_par.m_recomp_frac = ms_opt_des_par.m_recomp_frac_guess; + + // Recuperator split fraction + double LT_frac_local = -999.9; + if (!ms_opt_des_par.m_fixed_LT_frac) + { + LT_frac_local = x[index]; + if (LT_frac_local > 1.0 || LT_frac_local < 0.0) + return 0.0; + index++; + } + else + LT_frac_local = ms_opt_des_par.m_LT_frac_guess; + + if (ms_opt_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + ms_des_par.m_LTR_UA = ms_opt_des_par.m_UA_rec_total * LT_frac_local; + ms_des_par.m_HTR_UA = ms_opt_des_par.m_UA_rec_total * (1.0 - LT_frac_local); + } + else + { + ms_des_par.m_LTR_UA = ms_opt_des_par.m_LTR_UA; //[kW/K] + ms_des_par.m_HTR_UA = ms_opt_des_par.m_HTR_UA; //[kW/K] + } + + int error_code = 0; + + design_core(error_code); + + double objective_metric = 0.0; + if (error_code == 0) + { + objective_metric = m_objective_metric_last; + + if (m_objective_metric_last > m_objective_metric_opt) + { + ms_des_par_optimal = ms_des_par; + m_objective_metric_opt = m_objective_metric_last; + } + } + + return objective_metric; +} + + + + + + + int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg) { return 0; @@ -1181,3 +1181,13 @@ void C_HTRBypass_Cycle::off_design_recompressor(double T_in, double P_in, double void C_HTRBypass_Cycle::estimate_od_turbo_operation(double T_mc_in, double P_mc_in, double f_recomp, double T_t_in, double phi_mc, int& mc_error_code, double& mc_w_tip_ratio, double& P_mc_out, int& rc_error_code, double& rc_w_tip_ratio, double& rc_phi, bool is_update_ms_od_solved) { } + + +double nlopt_cb_opt_htr_bypass_des(const std::vector& x, std::vector& grad, void* data) +{ + C_HTRBypass_Cycle* frame = static_cast(data); + if (frame != NULL) + return frame->design_cycle_return_objective_metric(x); + else + return 0.0; +} diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 3d8ef27af9..ef6a952077 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -264,11 +264,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core // Added - int solve_cycle(double bypass_fraction, double& error); int solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out_calc); int solve_LTR(double T_LTR_LP_OUT_guess, double& T_LTR_LP_out_calc); - int solve_bypass(double T_BP_OUT_guess, double& T_BP_out_calc); - int solve_bypass_energy(double T_BP_OUT_guess, double& T_BP_out_calc); public: @@ -332,7 +329,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core - + // Called by 'nlopt_callback_opt_des_1', so needs to be public + double design_cycle_return_objective_metric(const std::vector& x); // Unused @@ -384,4 +382,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core }; + +double nlopt_cb_opt_htr_bypass_des(const std::vector& x, std::vector& grad, void* data); + #endif From 49ce724bbef460712312391103b3397c8d29d6ea Mon Sep 17 00:00:00 2001 From: taylorbrown75 Date: Wed, 3 May 2023 11:07:40 -0600 Subject: [PATCH 07/94] Transition solvers to shared monotonic equation class. Modify inputs to work with Python script --- ssc/cmod_sco2_csp_system.cpp | 5 +- tcs/sco2_htrbypass_cycle.cpp | 277 ++++++++++++++++++++++++++--------- tcs/sco2_htrbypass_cycle.h | 50 ++++++- 3 files changed, 260 insertions(+), 72 deletions(-) diff --git a/ssc/cmod_sco2_csp_system.cpp b/ssc/cmod_sco2_csp_system.cpp index 94cfe71386..ce1a7b2ffd 100644 --- a/ssc/cmod_sco2_csp_system.cpp +++ b/ssc/cmod_sco2_csp_system.cpp @@ -363,7 +363,6 @@ class cm_sco2_csp_system : public compute_module DP_PC_main, DP_PHX, LTR_N_sub_hxrs, HTR_N_sub_hxrs, eta_mc, mc_comp_model_code, eta_rc, eta_t, N_turbine, frac_fan_power, eta_fan, deltaP_cooler_frac, N_nodes_pass, T_amb_des, elevation)); - C_sco2_cycle_core::S_auto_opt_design_parameters des_params; { des_params.m_T_pc_in = T_mc_in; //[K] @@ -403,11 +402,9 @@ class cm_sco2_csp_system : public compute_module des_params.m_is_recomp_ok = 1; - - c_bp_cycle->auto_opt_design(des_params); } - + } diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index aab1f8e52b..d11327d212 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -45,53 +45,84 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. void C_HTRBypass_Cycle::design_core(int& error_code) { // Temporary Hard coded parameters - ms_des_par.m_recomp_frac = 0.3; - m_cp_HTF = 1.482e+03; // J/kg K - m_T_HTF_PHX_inlet = 670 + 273; // K + //ms_des_par.m_recomp_frac = 0.3; + m_dT_BP = 10; + m_T_HTF_PHX_inlet = 670 + 273; // K m_T_HTF_BP_outlet = 770; // K - ms_des_par.m_P_mc_in = 10000; - ms_des_par.m_P_mc_out = 25000; - m_T_t_in = 923.149; - - // temp - double hot_approach = m_T_HTF_PHX_inlet - m_T_t_in; - - // Iterating bp_frac so the cold approach value is correct - m_bp_frac = 0; - double des_HTF_PHX_cold_approach = hot_approach; - - // local - double error = 100000; - double frac_low = 0.0; - double frac_high = 1; - m_bp_frac = 0.5 * (frac_low + frac_high); - int count = 0; - while (std::abs(error) > 0.5) + + + + m_cp_HTF = 1.482e+03; // J/kg K + //ms_des_par.m_P_mc_in = 10000; + //ms_des_par.m_P_mc_out = 25000; + //m_T_t_in = 923.149; + + + C_mono_htr_bypass_BP_des BP_des_eq(this); + C_monotonic_eq_solver BP_des_solver(BP_des_eq); + double BP_out_lower = 0; + double BP_out_upper = 1.0; + + double BP_out_guess_lower = 0.25; //[K] There is nothing special about these guesses... + double BP_out_guess_upper = 0.75; //[K] There is nothing special about these guesses, either... + + BP_des_solver.settings(ms_des_par.m_des_tol * m_temp_last[MC_IN], 1000, BP_out_lower, BP_out_upper, false); + + double BP_out_solved, tol_BP_out_solved; + BP_out_solved = tol_BP_out_solved = std::numeric_limits::quiet_NaN(); + int iter_BP_out = -1; + + int BP_out_code = BP_des_solver.solve(BP_out_guess_lower, BP_out_guess_upper, 0, BP_out_solved, tol_BP_out_solved, iter_BP_out); + + if (BP_out_code != C_monotonic_eq_solver::CONVERGED) + { + error_code = 35; + return; + } + + + // DEBUG + if (false) { - // Update Bypass Fraction Guess + // temp + double hot_approach = m_T_HTF_PHX_inlet - m_T_t_in; + + // Iterating bp_frac so the cold approach value is correct + m_bp_frac = 0; + double des_HTF_PHX_cold_approach = hot_approach; + + // local + double error = 100000; + double frac_low = 0.0; + double frac_high = 1; m_bp_frac = 0.5 * (frac_low + frac_high); + int count = 0; + while (std::abs(error) > 0.5) + { + // Update Bypass Fraction Guess + m_bp_frac = 0.5 * (frac_low + frac_high); - // Run Calculation - design_core_standard(error_code); + // Run Calculation + design_core_standard(error_code); - // Get Results - double actual_approach = m_HTF_PHX_cold_approach; - error = actual_approach - des_HTF_PHX_cold_approach; + // Get Results + double actual_approach = m_HTF_PHX_cold_approach; + error = actual_approach - des_HTF_PHX_cold_approach; - // Update Bounds - if (error < 0) - frac_low = m_bp_frac; - else - frac_high = m_bp_frac; + // Update Bounds + if (error < 0) + frac_low = m_bp_frac; + else + frac_high = m_bp_frac; - if (count > 50) - break; + if (count > 50) + break; - count++; + count++; + } } - // DEBUG if (false) { @@ -326,23 +357,65 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) // Solve the recuperators { - double T_HTR_LP_out_lower = m_temp_last[MC_OUT]; //[K] Coldest possible temperature - double T_HTR_LP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature + C_mono_htr_bypass_HTR_des HTR_des_eq(this); + C_monotonic_eq_solver HTR_des_solver(HTR_des_eq); + + if (ms_des_par.m_recomp_frac == 0.0) + { + double y_T_diff = std::numeric_limits::quiet_NaN(); + int no_HTR_out_code = HTR_des_solver.test_member_function(m_temp_last[TURB_OUT], &y_T_diff); - double error = 1000; - double T_HTR_guess = 0.5 * (T_HTR_LP_out_lower + T_HTR_LP_out_upper); - double T_HTR_calc; - while (error > 0.1) + if (no_HTR_out_code != 0 || std::abs(y_T_diff / m_temp_last[MC_IN]) > ms_des_par.m_des_tol) + { + error_code = 35; + return; + } + } + else { - solve_HTR(T_HTR_guess, T_HTR_calc); - double guess_val = T_HTR_guess; - double calc_val = T_HTR_calc; + double T_HTR_LP_out_lower = m_temp_last[MC_OUT]; //[K] Coldest possible temperature + double T_HTR_LP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature + + double T_HTR_LP_out_guess_lower = std::min(T_HTR_LP_out_upper - 2.0, std::max(T_HTR_LP_out_lower + 15.0, 220.0 + 273.15)); //[K] There is nothing special about these guesses... + double T_HTR_LP_out_guess_upper = std::min(T_HTR_LP_out_guess_lower + 20.0, T_HTR_LP_out_upper - 1.0); //[K] There is nothing special about these guesses, either... + + HTR_des_solver.settings(ms_des_par.m_des_tol * m_temp_last[MC_IN], 1000, T_HTR_LP_out_lower, T_HTR_LP_out_upper, false); + + double T_HTR_LP_out_solved, tol_T_HTR_LP_out_solved; + T_HTR_LP_out_solved = tol_T_HTR_LP_out_solved = std::numeric_limits::quiet_NaN(); + int iter_T_HTR_LP_out = -1; + + int T_HTR_LP_out_code = HTR_des_solver.solve(T_HTR_LP_out_guess_lower, T_HTR_LP_out_guess_upper, 0, + T_HTR_LP_out_solved, tol_T_HTR_LP_out_solved, iter_T_HTR_LP_out); + + if (T_HTR_LP_out_code != C_monotonic_eq_solver::CONVERGED) + { + error_code = 35; + return; + } - error = std::abs(guess_val - calc_val); - // Update guess value - T_HTR_guess = 0.5 * (guess_val + calc_val); } + + + + //double T_HTR_LP_out_lower = m_temp_last[MC_OUT]; //[K] Coldest possible temperature + //double T_HTR_LP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature + + //double error = 1000; + //double T_HTR_guess = 0.5 * (T_HTR_LP_out_lower + T_HTR_LP_out_upper); + //double diff = std::numeric_limits::quiet_NaN(); + //while (error > 0.1) + //{ + // solve_HTR(T_HTR_guess, &diff); + // double guess_val = T_HTR_guess; + // double calc_val = T_HTR_guess + diff; + + // error = std::abs(guess_val - calc_val); + + // // Update guess value + // T_HTR_guess = 0.5 * (guess_val + calc_val); + //} } // State 5 can now be fully defined @@ -483,10 +556,13 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } -int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out_calc) + + + + +int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out) { m_w_rc = m_m_dot_t = m_m_dot_rc = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT = std::numeric_limits::quiet_NaN(); - double* diff_T_HTR_LP_out; // Set temperature guess m_temp_last[HTR_LP_OUT] = T_HTR_LP_OUT_guess; //[K] @@ -509,21 +585,46 @@ int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out double T_LTR_LP_out_lower = this->m_temp_last[MC_OUT]; //[K] Coldest possible outlet temperature double T_LTR_LP_out_upper = this->m_temp_last[HTR_LP_OUT]; //[K] Hottest possible outlet temperature - double error = 1000; - double T_LTR_guess = 0.5 * (T_LTR_LP_out_lower + T_LTR_LP_out_upper); - double T_LTR_calc; - while (error > 0.1) - { - solve_LTR(T_LTR_guess, T_LTR_calc); - double guess_val = T_LTR_guess; - double calc_val = T_LTR_calc; + double T_LTR_LP_out_guess_upper = std::min(T_LTR_LP_out_upper, T_LTR_LP_out_lower + 15.0); //[K] There is nothing special about using 15 here... + double T_LTR_LP_out_guess_lower = std::min(T_LTR_LP_out_guess_upper * 0.99, T_LTR_LP_out_lower + 2.0); //[K] There is nothing special about using 2 here... + + C_mono_htr_bypass_LTR_des LTR_des_eq(this); + C_monotonic_eq_solver LTR_des_solver(LTR_des_eq); - error = std::abs(guess_val - calc_val); + LTR_des_solver.settings(this->ms_des_par.m_des_tol * this->m_temp_last[MC_IN], 1000, T_LTR_LP_out_lower, + T_LTR_LP_out_upper, false); - // Update guess value - T_LTR_guess = 0.5 * (guess_val + calc_val); + double T_LTR_LP_out_solved = std::numeric_limits::quiet_NaN(); + double tol_T_LTR_LP_out_solved = std::numeric_limits::quiet_NaN(); + int iter_T_LTR_LP_out = -1; + int T_LTR_LP_out_code = LTR_des_solver.solve(T_LTR_LP_out_guess_lower, T_LTR_LP_out_guess_upper, 0, T_LTR_LP_out_solved, + tol_T_LTR_LP_out_solved, iter_T_LTR_LP_out); + + if (T_LTR_LP_out_code != C_monotonic_eq_solver::CONVERGED) + { + return 31; } + + //double error = 1000; + //double T_LTR_guess = 0.5 * (T_LTR_LP_out_lower + T_LTR_LP_out_upper); + //double diff = std::numeric_limits::quiet_NaN(); + //while (error > 0.1) + //{ + // solve_LTR(T_LTR_guess, &diff); + // double guess_val = T_LTR_guess; + // double calc_val = T_LTR_guess + diff; + + // error = std::abs(guess_val - calc_val); + + // // Update guess value + // T_LTR_guess = 0.5 * (guess_val + calc_val); + + //} + + + + } // Know LTR performance so we can calculate the HP outlet (Energy balance on LTR HP stream) @@ -569,6 +670,7 @@ int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out } // Find the design solution of the HTR + double T_HTR_LP_out_calc = std::numeric_limits::quiet_NaN(); { // If there is no flow through HTR HP side if (m_m_dot_htr_hp < 1e-12) @@ -580,7 +682,6 @@ int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out // If there is flow through HTR HP side else { - T_HTR_LP_out_calc = std::numeric_limits::quiet_NaN(); this->mc_HT_recup.design_for_target__calc_outlet(this->ms_des_par.m_HTR_target_code, this->ms_des_par.m_HTR_UA, this->ms_des_par.m_HTR_min_dT, this->ms_des_par.m_HTR_eff_target, this->ms_des_par.m_HTR_eff_max, @@ -592,12 +693,14 @@ int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out } + *diff_T_HTR_LP_out = T_HTR_LP_out_calc - T_HTR_LP_OUT_guess; + + return 0; } -int C_HTRBypass_Cycle::solve_LTR(double T_LTR_LP_OUT_guess, double& T_LTR_LP_out_calc) +int C_HTRBypass_Cycle::solve_LTR(double T_LTR_LP_OUT_guess, double *diff_T_LTR_LP_out) { m_w_rc = m_m_dot_t = m_m_dot_rc = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT = std::numeric_limits::quiet_NaN(); - double* diff_T_LTR_LP_out; // Set LTR_LP_OUT guess this->m_temp_last[LTR_LP_OUT] = T_LTR_LP_OUT_guess; @@ -665,7 +768,8 @@ int C_HTRBypass_Cycle::solve_LTR(double T_LTR_LP_OUT_guess, double& T_LTR_LP_out } // Solve LTR - T_LTR_LP_out_calc = std::numeric_limits::quiet_NaN(); + *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); + double T_LTR_LP_out_calc = std::numeric_limits::quiet_NaN(); { this->mc_LT_recup.design_for_target__calc_outlet(this->ms_des_par.m_LTR_target_code, this->ms_des_par.m_LTR_UA, this->ms_des_par.m_LTR_min_dT, this->ms_des_par.m_LTR_eff_target, @@ -676,8 +780,45 @@ int C_HTRBypass_Cycle::solve_LTR(double T_LTR_LP_OUT_guess, double& T_LTR_LP_out m_Q_dot_LT, this->m_temp_last[LTR_HP_OUT], T_LTR_LP_out_calc); } + + *diff_T_LTR_LP_out = T_LTR_LP_out_calc - T_LTR_LP_OUT_guess; + + return 0; } + + +int C_HTRBypass_Cycle::C_mono_htr_bypass_LTR_des::operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out) +{ + return m_htr_bypass_cycle->solve_LTR(T_LTR_LP_OUT_guess, diff_T_LTR_LP_out); +} + + +int C_HTRBypass_Cycle::C_mono_htr_bypass_HTR_des::operator()(double T_HTR_LP_OUT_guess /*K*/, double* diff_T_HTR_LP_out) +{ + return m_htr_bypass_cycle->solve_HTR(T_HTR_LP_OUT_guess, diff_T_HTR_LP_out); +} + + +int C_HTRBypass_Cycle::C_mono_htr_bypass_BP_des::operator()(double bp_frac_guess, double* diff_PHX_cold_approach) +{ + int error_code = 0; + + this->m_htr_bypass_cycle->m_bp_frac = bp_frac_guess; + this->m_htr_bypass_cycle->design_core_standard(error_code); + + double calc_cold_approach = this->m_htr_bypass_cycle->m_HTF_PHX_cold_approach; + double hot_approach = this->m_htr_bypass_cycle->m_T_HTF_PHX_inlet - this->m_htr_bypass_cycle->m_T_t_in; + double desired_cold_approach = hot_approach; + + *diff_PHX_cold_approach = calc_cold_approach - desired_cold_approach; + + + return error_code; +} + + + void C_HTRBypass_Cycle::opt_design_core(int& error_code) { // Map ms_opt_des_par to ms_des_par @@ -715,6 +856,11 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) std::vector ub(0); std::vector scale(0); + // DEBUG + //ms_opt_des_par.m_fixed_P_mc_out = true; + //ms_opt_des_par.m_fixed_PR_HP_to_LP = true; + //ms_opt_des_par.m_fixed_LT_frac = true; + if (!ms_opt_des_par.m_fixed_P_mc_out) { x.push_back(ms_opt_des_par.m_P_mc_out_guess); @@ -742,7 +888,6 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) lb.push_back(0.0); ub.push_back(1.0); scale.push_back(0.05); - index++; } diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index ef6a952077..7faa0dcf55 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -39,6 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "heat_exchangers.h" #include "CO2_properties.h" +#include "numeric_solvers.h" class C_HTRBypass_Cycle : public C_sco2_cycle_core { @@ -264,8 +265,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core // Added - int solve_HTR(double T_HTR_LP_OUT_guess, double& T_HTR_LP_out_calc); - int solve_LTR(double T_LTR_LP_OUT_guess, double& T_LTR_LP_out_calc); + int solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out); + int solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_LP_out); public: @@ -333,6 +334,51 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double design_cycle_return_objective_metric(const std::vector& x); + class C_mono_htr_bypass_LTR_des : public C_monotonic_equation + { + private: + C_HTRBypass_Cycle *m_htr_bypass_cycle; + + public: + C_mono_htr_bypass_LTR_des(C_HTRBypass_Cycle* htr_bypass_cycle) + { + m_htr_bypass_cycle = htr_bypass_cycle; + } + + virtual int operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out /*K*/); + }; + + class C_mono_htr_bypass_HTR_des : public C_monotonic_equation + { + private: + C_HTRBypass_Cycle *m_htr_bypass_cycle; + + public: + C_mono_htr_bypass_HTR_des(C_HTRBypass_Cycle* htr_bypass_cycle) + { + m_htr_bypass_cycle = htr_bypass_cycle; + } + + virtual int operator()(double T_HTR_LP_OUT_guess /*K*/, double* diff_T_HTR_LP_out /*K*/); + }; + + class C_mono_htr_bypass_BP_des : public C_monotonic_equation + { + private: + C_HTRBypass_Cycle* m_htr_bypass_cycle; + + public: + C_mono_htr_bypass_BP_des(C_HTRBypass_Cycle* htr_bypass_cycle) + { + m_htr_bypass_cycle = htr_bypass_cycle; + } + + virtual int operator()(double bp_frac_guess, double* diff_bp_frac); + }; + + + + // Unused int auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg); From d2f248dadd13af1cdf791437ffcc578d147ccc9c Mon Sep 17 00:00:00 2001 From: taylorbrown75 Date: Fri, 5 May 2023 11:53:11 -0600 Subject: [PATCH 08/94] Add additional bypass variables to cmod. Pass through to htr bypass model --- ssc/cmod_sco2_csp_system.cpp | 80 +--------------------------- ssc/csp_common.cpp | 17 ++++++ tcs/sco2_htrbypass_cycle.cpp | 100 +++++++---------------------------- tcs/sco2_htrbypass_cycle.h | 5 ++ tcs/sco2_pc_csp_int.cpp | 47 ++++++++++++++++ tcs/sco2_pc_csp_int.h | 8 +++ 6 files changed, 98 insertions(+), 159 deletions(-) diff --git a/ssc/cmod_sco2_csp_system.cpp b/ssc/cmod_sco2_csp_system.cpp index ce1a7b2ffd..045788d081 100644 --- a/ssc/cmod_sco2_csp_system.cpp +++ b/ssc/cmod_sco2_csp_system.cpp @@ -331,84 +331,6 @@ class cm_sco2_csp_system : public compute_module void exec() override { - // Debug to launch HTR Bypass - if (false) - { - // inputs - C_sco2_cycle_core::E_turbo_gen_motor_config turbo_gen_motor_config = static_cast(0); - double eta_generator = 1.0; - double T_mc_in = 314.15; // K - double W_dot_net = 50e3; // kW - double T_t_in = 664 + 273; // K - double P_high_limit = 25e3; // kPa - std::vector DP_LTR = { -0.0056 , -0.0311 }; - std::vector DP_HTR = { -0.0056 , -0.0311 }; - std::vector DP_PC_main = { 0.00, -0.005 }; - std::vector DP_PHX = { -0.0056, 0.0 }; - int LTR_N_sub_hxrs = 10; - int HTR_N_sub_hxrs = 10; - double eta_mc = 0.85; - double mc_comp_model_code = 1; - double eta_rc = 0.85; - double eta_t = 0.9; - double N_turbine = 30000.0; - double frac_fan_power = 0.02; - double eta_fan = 0.5; - double deltaP_cooler_frac = 0.005; - double N_nodes_pass = 10; - double T_amb_des = 35 + 273; // K - double elevation = 588; // m - - std::unique_ptr c_bp_cycle = std::unique_ptr(new C_HTRBypass_Cycle(turbo_gen_motor_config, eta_generator, T_mc_in, W_dot_net, T_t_in, P_high_limit, DP_LTR, DP_HTR, - DP_PC_main, DP_PHX, LTR_N_sub_hxrs, HTR_N_sub_hxrs, eta_mc, mc_comp_model_code, eta_rc, - eta_t, N_turbine, frac_fan_power, eta_fan, deltaP_cooler_frac, N_nodes_pass, T_amb_des, elevation)); - - C_sco2_cycle_core::S_auto_opt_design_parameters des_params; - { - des_params.m_T_pc_in = T_mc_in; //[K] - des_params.m_DP_PC_pre = DP_PC_main; - des_params.m_UA_rec_total = 15 * 1000 * (W_dot_net) / 50.0; //[kW/K] - // LTR thermal design - des_params.m_LTR_target_code = 0; //[-] - des_params.m_LTR_UA = 7500; //[kW/K] - des_params.m_LTR_min_dT = std::numeric_limits::quiet_NaN(); //[K] - des_params.m_LTR_eff_target = std::numeric_limits::quiet_NaN(); //[-] - des_params.m_LTR_eff_max = 1.0; //[-] - //des_params.m_LTR_od_UA_target_type = 0; - // HTR thermal design - des_params.m_HTR_target_code = 0; //[-] - des_params.m_HTR_UA = 7500.0; //[kW/K] - des_params.m_HTR_min_dT = std::numeric_limits::quiet_NaN(); //[K] - des_params.m_HTR_eff_target = std::numeric_limits::quiet_NaN(); //[-] - des_params.m_HTR_eff_max = 1.0; //[-] - //des_params.m_HTR_od_UA_target_type = ms_des_par.m_HTR_od_UA_target_type; - // - des_params.m_eta_pc = 0.85; - des_params.m_des_tol = std::pow(10, -3); - des_params.m_des_opt_tol = std::pow(10, -3); - - des_params.m_is_des_air_cooler = true; //[-] - - des_params.m_des_objective_type = 0; //[-] - des_params.m_min_phx_deltaT = 0; //[C] - - des_params.m_fixed_P_mc_out = 1; //[-] - - des_params.m_PR_HP_to_LP_guess = P_high_limit; //[-] - des_params.m_fixed_PR_HP_to_LP = 1; //[-] - - des_params.m_f_PR_HP_to_IP_guess = P_high_limit; //[-] - des_params.m_fixed_f_PR_HP_to_IP = 1; //[-] - - des_params.m_is_recomp_ok = 1; - - c_bp_cycle->auto_opt_design(des_params); - } - - } - - - C_sco2_phx_air_cooler c_sco2_cycle; int sco2_des_err = sco2_design_cmod_common(this, c_sco2_cycle); @@ -438,7 +360,7 @@ class cm_sco2_csp_system : public compute_module bool is_od_set_control = is_assigned("od_set_control"); bool is_od_generate_udpc_assigned = is_assigned("od_generate_udpc"); if (is_od_cases_assigned && is_P_mc_in_od_sweep_assigned) - { + { log("Both off design cases and main compressor inlet pressure sweep assigned. Only modeling off design cases"); is_P_mc_in_od_sweep_assigned = false; } diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 719f80db95..f440d712b3 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -810,6 +810,14 @@ var_info vtab_sco2_design[] = { { SSC_INPUT, SSC_NUMBER, "eta_air_cooler_fan", "Air cooler fan isentropic efficiency", "", "", "Air Cooler Design", "?=0.5", "", "" }, { SSC_INPUT, SSC_NUMBER, "N_nodes_air_cooler_pass", "Number of nodes in single air cooler pass", "", "", "Air Cooler Design", "?=10", "", "" }, + + + // HTR Bypass Design + { SSC_INPUT, SSC_NUMBER, "T_htf_bypass_out", "HTF design Bypass Outlet Temperature", "C", "", "System Design", "cycle_config=3", "", "" }, + { SSC_INPUT, SSC_NUMBER, "deltaT_bypass", "sco2 Bypass Outlet Temp - HTR_HP_OUT Temp", "C", "", "System Design", "cycle_config=3", "", "" }, + + + // ** Design OUTPUTS ** // System Design Solution { SSC_OUTPUT, SSC_NUMBER, "T_htf_cold_des", "HTF design cold temperature (PHX outlet)", "C", "System Design Solution", "", "*", "", "" }, @@ -1221,6 +1229,15 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c s_sco2_des_par.m_eta_fan = cm->as_double("eta_air_cooler_fan"); // 0.5; s_sco2_des_par.m_N_nodes_pass = cm->as_integer("N_nodes_air_cooler_pass"); // 10; + // Bypass Configuration Parameters + if (s_sco2_des_par.m_cycle_config == 3) + { + s_sco2_des_par.m_T_htf_bypass_out = cm->as_double("T_htf_bypass_out") + 273.15; // [C] Convert to C + s_sco2_des_par.m_deltaT_bypass = cm->as_double("deltaT_bypass"); // [delta C] + + } + + // For try/catch below int out_type = -1; std::string out_msg = ""; diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index d11327d212..3398d5b3e9 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -46,18 +46,20 @@ void C_HTRBypass_Cycle::design_core(int& error_code) { // Temporary Hard coded parameters //ms_des_par.m_recomp_frac = 0.3; - - m_dT_BP = 10; - m_T_HTF_PHX_inlet = 670 + 273; // K - m_T_HTF_BP_outlet = 770; // K - - - - m_cp_HTF = 1.482e+03; // J/kg K + //m_dT_BP = 10; + //m_T_HTF_PHX_inlet = 670 + 273; // K + //m_T_HTF_BP_outlet = 650 + 273; // K + //m_cp_HTF = 1.482e+03; // J/kg K //ms_des_par.m_P_mc_in = 10000; //ms_des_par.m_P_mc_out = 25000; //m_T_t_in = 923.149; + // Check if HTF parameters were set + if (is_htf_set == false) + { + error_code = 560; + return; + } C_mono_htr_bypass_BP_des BP_des_eq(this); C_monotonic_eq_solver BP_des_solver(BP_des_eq); @@ -80,70 +82,6 @@ void C_HTRBypass_Cycle::design_core(int& error_code) error_code = 35; return; } - - - // DEBUG - if (false) - { - // temp - double hot_approach = m_T_HTF_PHX_inlet - m_T_t_in; - - // Iterating bp_frac so the cold approach value is correct - m_bp_frac = 0; - double des_HTF_PHX_cold_approach = hot_approach; - - // local - double error = 100000; - double frac_low = 0.0; - double frac_high = 1; - m_bp_frac = 0.5 * (frac_low + frac_high); - int count = 0; - while (std::abs(error) > 0.5) - { - // Update Bypass Fraction Guess - m_bp_frac = 0.5 * (frac_low + frac_high); - - // Run Calculation - design_core_standard(error_code); - - // Get Results - double actual_approach = m_HTF_PHX_cold_approach; - error = actual_approach - des_HTF_PHX_cold_approach; - - // Update Bounds - if (error < 0) - frac_low = m_bp_frac; - else - frac_high = m_bp_frac; - - if (count > 50) - break; - - count++; - } - } - - // DEBUG - if (false) - { - std::vector frac_vec = { 0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1 }; - std::vector cold_approach; - - for (int i = 0; i < frac_vec.size(); i++) - { - m_bp_frac = frac_vec[i]; - - // Run Calculation - design_core_standard(error_code); - - double actual_approach = m_HTF_PHX_cold_approach; - cold_approach.push_back(actual_approach); - } - - int x = 0; - } - - } void C_HTRBypass_Cycle::design_core_standard(int& error_code) @@ -557,9 +495,6 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } - - - int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out) { m_w_rc = m_m_dot_t = m_m_dot_rc = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT = std::numeric_limits::quiet_NaN(); @@ -856,11 +791,6 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) std::vector ub(0); std::vector scale(0); - // DEBUG - //ms_opt_des_par.m_fixed_P_mc_out = true; - //ms_opt_des_par.m_fixed_PR_HP_to_LP = true; - //ms_opt_des_par.m_fixed_LT_frac = true; - if (!ms_opt_des_par.m_fixed_P_mc_out) { x.push_back(ms_opt_des_par.m_P_mc_out_guess); @@ -1124,6 +1054,16 @@ void C_HTRBypass_Cycle::finalize_design(int& error_code) // Public Methods +void C_HTRBypass_Cycle::set_htf_par(double T_htf_phx_in, double T_htf_bp_out, double cp_htf, double dT_bp) +{ + m_T_HTF_PHX_inlet = T_htf_phx_in; // K + m_T_HTF_BP_outlet = T_htf_bp_out; // K + m_cp_HTF = cp_htf; + m_dT_BP = dT_bp; + + is_htf_set = true; +} + void C_HTRBypass_Cycle::design(S_design_parameters& des_par_in, int& error_code) { ms_des_par = des_par_in; diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 7faa0dcf55..55916e4b47 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -244,6 +244,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_Q_dot_pc; // pre cooler heat rejected double m_HTF_BP_cold_approach; double m_HTF_PHX_cold_approach; + bool is_htf_set = false; C_HX_co2_to_co2_CRM m_BP_HTX; @@ -316,6 +317,10 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core } + void set_htf_par(double T_htf_phx_in, double T_htf_bp_out, double cp_htf, double dT_bp); + + + CO2_state mc_co2_props; ~C_HTRBypass_Cycle() {}; diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index c9ffffb562..e255c1a458 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -147,6 +147,52 @@ void C_sco2_phx_air_cooler::design_core() s_cycle_config = "htr bypass"; + // Get and Set HTF Parameters + { + int htf_code = ms_des_par.m_hot_fl_code; + util::matrix_t htf_user_props = ms_des_par.mc_hot_fl_props; + HTFProperties htf_props; + + if (htf_code != HTFProperties::User_defined && htf_code < HTFProperties::End_Library_Fluids) + { + if (!htf_props.SetFluid(htf_code, true)) + { + throw(C_csp_exception("Hot fluid code is not recognized", "C_HX_co2_to_htf::initialization")); + } + } + else if (htf_code == HTFProperties::User_defined) + { + int n_rows = (int)htf_user_props.nrows(); + int n_cols = (int)htf_user_props.ncols(); + if (n_rows > 2 && n_cols == 7) + { + if (!htf_props.SetUserDefinedFluid(htf_user_props, true)) + { + std::string error_msg = util::format(htf_props.UserFluidErrMessage(), n_rows, n_cols); + throw(C_csp_exception(error_msg, "C_HX_co2_to_htf::initialization")); + } + } + else + { + std::string error_msg = util::format("The user defined hot fluid table must contain at least 3 rows and exactly 7 columns. The current table contains %d row(s) and %d column(s)", n_rows, n_cols); + throw(C_csp_exception(error_msg, "C_HX_co2_to_htf::initialization")); + } + } + else + { + throw(C_csp_exception("Hot fluid code is not recognized", "C_HX_co2_to_htf::initialization")); + } + + double HTF_PHX_inlet = ms_des_par.m_T_htf_hot_in; + double cp_htf = htf_props.Cp(HTF_PHX_inlet) * 1000.0; // Convert to J/kg K + double HTF_BP_outlet = ms_des_par.m_T_htf_bypass_out; + double deltaT_bp = ms_des_par.m_deltaT_bypass; + + c_bp_cycle->set_htf_par(HTF_PHX_inlet, HTF_BP_outlet, cp_htf, deltaT_bp); + + } + + mpc_sco2_cycle = std::move(c_bp_cycle); } else @@ -172,6 +218,7 @@ void C_sco2_phx_air_cooler::design_core() mpc_sco2_cycle = std::move(c_rc_cycle); } + // Set min temp m_T_mc_in_min = mpc_sco2_cycle->get_design_limits().m_T_mc_in_min; //[K] diff --git a/tcs/sco2_pc_csp_int.h b/tcs/sco2_pc_csp_int.h index 45d4d008aa..217affbf26 100644 --- a/tcs/sco2_pc_csp_int.h +++ b/tcs/sco2_pc_csp_int.h @@ -124,6 +124,14 @@ class C_sco2_phx_air_cooler double m_eta_fan; //[-] Fan isentropic efficiency int m_N_nodes_pass; //[-] Number of nodes per pass + + // Bypass Configuration Parameters + double m_T_htf_bypass_out; // [K] HTF design Bypass Outlet + double m_deltaT_bypass; // [delta K] sco2 Bypass Outlet Temp - HTR_HP_OUT Temp + + + + S_des_par() { m_hot_fl_code = m_design_method = m_LTR_N_sub_hxrs = m_LTR_N_sub_hxrs = m_phx_N_sub_hx = -1; From 145a66ec44c796aec971b23b7c7cb28297b65d85 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Tue, 9 May 2023 13:19:56 -0600 Subject: [PATCH 09/94] Solve with PHX cold approach rather than Bypass cold approach --- ssc/csp_common.cpp | 2 ++ tcs/sco2_htrbypass_cycle.cpp | 39 ++++++++++++++++++++---------------- tcs/sco2_htrbypass_cycle.h | 5 +++-- tcs/sco2_pc_csp_int.cpp | 3 ++- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index f440d712b3..b8045ff4f3 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -1235,6 +1235,8 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c s_sco2_des_par.m_T_htf_bypass_out = cm->as_double("T_htf_bypass_out") + 273.15; // [C] Convert to C s_sco2_des_par.m_deltaT_bypass = cm->as_double("deltaT_bypass"); // [delta C] + // Already assigned (above) + //s_sco2_des_par.m_phx_dt_cold_approach = cm->as_double("dT_PHX_cold_approach"); // [delta C] } diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 3398d5b3e9..f9aa8b9af6 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -66,8 +66,8 @@ void C_HTRBypass_Cycle::design_core(int& error_code) double BP_out_lower = 0; double BP_out_upper = 1.0; - double BP_out_guess_lower = 0.25; //[K] There is nothing special about these guesses... - double BP_out_guess_upper = 0.75; //[K] There is nothing special about these guesses, either... + double BP_out_guess_lower = 0; //[K] + double BP_out_guess_upper = 1; //[K] BP_des_solver.settings(ms_des_par.m_des_tol * m_temp_last[MC_IN], 1000, BP_out_lower, BP_out_upper, false); @@ -461,17 +461,22 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) // HTF { - // Calculate HTF Bypass Cold Approach - m_HTF_BP_cold_approach = m_T_HTF_BP_outlet - m_temp_last[MIXER_OUT]; + // Use HTF Bypass cold approach to calculate PHX outlet Temperature + m_T_HTF_PHX_out = m_HTF_PHX_cold_approach + m_temp_last[MIXER2_OUT]; + + // Calculate HTF mdot + m_m_dot_HTF = m_Q_dot_PHX / ((m_T_HTF_PHX_inlet - m_T_HTF_PHX_out) * m_cp_HTF); - // Calculate HTF Mdot - m_m_dot_HTF = m_Q_dot_total / ((m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet) * m_cp_HTF); + // Calculate Bypass Out Temperature + m_T_HTF_BP_outlet_calc = m_T_HTF_PHX_out - (m_Q_dot_BP / (m_m_dot_HTF * m_cp_HTF)); - // Calculate PHX outlet Temp - m_T_HTF_PHX_out = m_T_HTF_PHX_inlet - (m_Q_dot_PHX / (m_m_dot_HTF * m_cp_HTF)); + // Calculate HTF Bypass Cold Approach + m_HTF_BP_cold_approach = m_T_HTF_BP_outlet_calc - m_temp_last[MIXER_OUT]; - // Calculate PHX Cold Approach - m_HTF_PHX_cold_approach = m_T_HTF_PHX_out - m_temp_last[MIXER2_OUT]; + //// Calculate PHX outlet Temp + //m_T_HTF_PHX_out = m_T_HTF_PHX_inlet - (m_Q_dot_PHX / (m_m_dot_HTF * m_cp_HTF)); + + } // Set objective metric @@ -735,18 +740,17 @@ int C_HTRBypass_Cycle::C_mono_htr_bypass_HTR_des::operator()(double T_HTR_LP_OUT } -int C_HTRBypass_Cycle::C_mono_htr_bypass_BP_des::operator()(double bp_frac_guess, double* diff_PHX_cold_approach) +int C_HTRBypass_Cycle::C_mono_htr_bypass_BP_des::operator()(double bp_frac_guess, double* diff_T_BP_HTF_out) { int error_code = 0; this->m_htr_bypass_cycle->m_bp_frac = bp_frac_guess; this->m_htr_bypass_cycle->design_core_standard(error_code); - double calc_cold_approach = this->m_htr_bypass_cycle->m_HTF_PHX_cold_approach; - double hot_approach = this->m_htr_bypass_cycle->m_T_HTF_PHX_inlet - this->m_htr_bypass_cycle->m_T_t_in; - double desired_cold_approach = hot_approach; + double target_bp_out = this->m_htr_bypass_cycle->m_T_HTF_BP_outlet_target; + double calc_bp_out = this->m_htr_bypass_cycle->m_T_HTF_BP_outlet_calc; - *diff_PHX_cold_approach = calc_cold_approach - desired_cold_approach; + *diff_T_BP_HTF_out = calc_bp_out - target_bp_out; return error_code; @@ -1054,12 +1058,13 @@ void C_HTRBypass_Cycle::finalize_design(int& error_code) // Public Methods -void C_HTRBypass_Cycle::set_htf_par(double T_htf_phx_in, double T_htf_bp_out, double cp_htf, double dT_bp) +void C_HTRBypass_Cycle::set_htf_par(double T_htf_phx_in, double T_htf_bp_out_target, double cp_htf, double dT_bp, double htf_phx_cold_approach) { m_T_HTF_PHX_inlet = T_htf_phx_in; // K - m_T_HTF_BP_outlet = T_htf_bp_out; // K + m_T_HTF_BP_outlet_target = T_htf_bp_out_target; // K m_cp_HTF = cp_htf; m_dT_BP = dT_bp; + m_HTF_PHX_cold_approach = htf_phx_cold_approach; is_htf_set = true; } diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 55916e4b47..3a073fc778 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -237,7 +237,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_m_dot_HTF; double m_Q_dot_BP; double m_T_HTF_PHX_inlet; - double m_T_HTF_BP_outlet; + double m_T_HTF_BP_outlet_target; + double m_T_HTF_BP_outlet_calc; double m_T_HTF_PHX_out; double m_dT_BP; // BYPASS_OUT - HTR_HP_OUT double m_Q_dot_total; @@ -317,7 +318,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core } - void set_htf_par(double T_htf_phx_in, double T_htf_bp_out, double cp_htf, double dT_bp); + void set_htf_par(double T_htf_phx_in, double T_htf_bp_out_target, double cp_htf, double dT_bp, double htf_phx_cold_approach); diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index e255c1a458..498d797712 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -187,8 +187,9 @@ void C_sco2_phx_air_cooler::design_core() double cp_htf = htf_props.Cp(HTF_PHX_inlet) * 1000.0; // Convert to J/kg K double HTF_BP_outlet = ms_des_par.m_T_htf_bypass_out; double deltaT_bp = ms_des_par.m_deltaT_bypass; + double HTF_PHX_cold_approach = ms_des_par.m_phx_dt_cold_approach; - c_bp_cycle->set_htf_par(HTF_PHX_inlet, HTF_BP_outlet, cp_htf, deltaT_bp); + c_bp_cycle->set_htf_par(HTF_PHX_inlet, HTF_BP_outlet, cp_htf, deltaT_bp, HTF_PHX_cold_approach); } From 1a51ca153659cdd35e47c6b21d7e3a69e00b08c7 Mon Sep 17 00:00:00 2001 From: taylorbrown75 Date: Wed, 17 May 2023 08:21:27 -0600 Subject: [PATCH 10/94] Integrate htr bypass cycle into upstream logic. Add bypass heat exchanger design calculations. Complete finalize_design function --- ssc/csp_common.cpp | 1 + tcs/sco2_cycle_templates.h | 3 + tcs/sco2_htrbypass_cycle.cpp | 213 ++++++++++++++++++++++++++++++----- tcs/sco2_htrbypass_cycle.h | 62 +++++----- tcs/sco2_pc_csp_int.cpp | 68 +++++++++-- tcs/sco2_pc_csp_int.h | 6 +- 6 files changed, 287 insertions(+), 66 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index b8045ff4f3..fb6cd16a4f 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -1263,6 +1263,7 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c throw exec_error("sco2_csp_system", csp_exception.m_error_message); } + // If all calls were successful, log to SSC any messages from sco2_recomp_csp while (c_sco2_cycle.mc_messages.get_message(&out_type, &out_msg)) { diff --git a/tcs/sco2_cycle_templates.h b/tcs/sco2_cycle_templates.h index a4e27a75a4..d8c77e70cd 100644 --- a/tcs/sco2_cycle_templates.h +++ b/tcs/sco2_cycle_templates.h @@ -25,6 +25,8 @@ class C_sco2_cycle_core RC_OUT, // Recompresor outlet PC_IN, // Precompressor inlet (partial cooling cycle) PC_OUT, // Precompressor outlet (partial cooling cycle) + BYPASS_OUT, // Bypass outlet (htr bypass cycle) + MIXER2_OUT, // Mixer 2 Outlet (htr bypass cycle) END_SCO2_STATES }; @@ -73,6 +75,7 @@ class C_sco2_cycle_core double m_W_dot_rc; //[kWe] double m_W_dot_pc; //[kWe] double m_W_dot_t; //[kWe] + double m_bp_frac; //[-] Bypass Fraction double m_W_dot_cooler_tot; //[kWe] diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index f9aa8b9af6..b4b4cc8a89 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -54,6 +54,19 @@ void C_HTRBypass_Cycle::design_core(int& error_code) //ms_des_par.m_P_mc_out = 25000; //m_T_t_in = 923.149; + //DEBUG + if (false) + { + std::vector bp_fracs = { 0, 0.01, 0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.99,1 }; + for (double bp : bp_fracs) + { + m_bp_frac = bp; + + int temp_error = 0; + design_core_standard(temp_error); + } + } + // Check if HTF parameters were set if (is_htf_set == false) { @@ -64,12 +77,12 @@ void C_HTRBypass_Cycle::design_core(int& error_code) C_mono_htr_bypass_BP_des BP_des_eq(this); C_monotonic_eq_solver BP_des_solver(BP_des_eq); double BP_out_lower = 0; - double BP_out_upper = 1.0; + double BP_out_upper = 0.99; double BP_out_guess_lower = 0; //[K] - double BP_out_guess_upper = 1; //[K] + double BP_out_guess_upper = 0.99; //[K] - BP_des_solver.settings(ms_des_par.m_des_tol * m_temp_last[MC_IN], 1000, BP_out_lower, BP_out_upper, false); + BP_des_solver.settings(ms_des_par.m_des_tol, 1000, BP_out_lower, BP_out_upper, false); double BP_out_solved, tol_BP_out_solved; BP_out_solved = tol_BP_out_solved = std::numeric_limits::quiet_NaN(); @@ -77,8 +90,25 @@ void C_HTRBypass_Cycle::design_core(int& error_code) int BP_out_code = BP_des_solver.solve(BP_out_guess_lower, BP_out_guess_upper, 0, BP_out_solved, tol_BP_out_solved, iter_BP_out); - if (BP_out_code != C_monotonic_eq_solver::CONVERGED) + // Check if Bypass Converged + if (BP_out_code == C_monotonic_eq_solver::CONVERGED) + { + // Bypass Converged + return; + } + else if (BP_out_code == C_monotonic_eq_solver::SLOPE_NEG_NO_NEG_ERR) + { + // Target Outlet temperature not possible (too low), bypass is fully open + return; + } + else if (BP_out_code == C_monotonic_eq_solver::SLOPE_NEG_NO_POS_ERR) + { + // Target Outlet temperature not possible (too high), bypass is fully closed + return; + } + else { + // Did not converge error_code = 35; return; } @@ -335,25 +365,6 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } - - - //double T_HTR_LP_out_lower = m_temp_last[MC_OUT]; //[K] Coldest possible temperature - //double T_HTR_LP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature - - //double error = 1000; - //double T_HTR_guess = 0.5 * (T_HTR_LP_out_lower + T_HTR_LP_out_upper); - //double diff = std::numeric_limits::quiet_NaN(); - //while (error > 0.1) - //{ - // solve_HTR(T_HTR_guess, &diff); - // double guess_val = T_HTR_guess; - // double calc_val = T_HTR_guess + diff; - - // error = std::abs(guess_val - calc_val); - - // // Update guess value - // T_HTR_guess = 0.5 * (guess_val + calc_val); - //} } // State 5 can now be fully defined @@ -457,6 +468,8 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) double qSum = m_Q_dot_total; double qSum_calc = m_Q_dot_BP + m_Q_dot_PHX; + + int x = 0; } // HTF @@ -554,17 +567,11 @@ int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_L // solve_LTR(T_LTR_guess, &diff); // double guess_val = T_LTR_guess; // double calc_val = T_LTR_guess + diff; - // error = std::abs(guess_val - calc_val); - // // Update guess value // T_LTR_guess = 0.5 * (guess_val + calc_val); - //} - - - } // Know LTR performance so we can calculate the HP outlet (Energy balance on LTR HP stream) @@ -638,7 +645,7 @@ int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_L return 0; } -int C_HTRBypass_Cycle::solve_LTR(double T_LTR_LP_OUT_guess, double *diff_T_LTR_LP_out) +int C_HTRBypass_Cycle::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_LP_out) { m_w_rc = m_m_dot_t = m_m_dot_rc = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT = std::numeric_limits::quiet_NaN(); @@ -1048,10 +1055,154 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) int optimal_design_error_code = 0; design_core(optimal_design_error_code); + + if (optimal_design_error_code != 0) + { + error_code = optimal_design_error_code; + return; + } + + finalize_design(optimal_design_error_code); + + error_code = optimal_design_error_code; } void C_HTRBypass_Cycle::finalize_design(int& error_code) { + + + // Design Main Compressor + { + int mc_design_err = m_mc_ms.design_given_outlet_state(m_mc_comp_model_code, m_temp_last[MC_IN], + m_pres_last[MC_IN], + m_m_dot_mc, + m_temp_last[MC_OUT], + m_pres_last[MC_OUT], + ms_des_par.m_des_tol); + + if (mc_design_err != 0) + { + error_code = mc_design_err; + return; + } + } + + // Design Recompressor + if (ms_des_par.m_recomp_frac > 0.01) + { + int rc_des_err = m_rc_ms.design_given_outlet_state(m_rc_comp_model_code, m_temp_last[LTR_LP_OUT], + m_pres_last[LTR_LP_OUT], + m_m_dot_rc, + m_temp_last[RC_OUT], + m_pres_last[RC_OUT], + ms_des_par.m_des_tol); + + if (rc_des_err != 0) + { + error_code = rc_des_err; + return; + } + + ms_des_solved.m_is_rc = true; + } + else + { + ms_des_solved.m_is_rc = false; + } + + // Size Turbine + { + C_turbine::S_design_parameters t_des_par; + // Set turbine shaft speed + t_des_par.m_N_design = m_N_turbine; + t_des_par.m_N_comp_design_if_linked = m_mc_ms.get_design_solved()->m_N_design; //[rpm] m_mc.get_design_solved()->m_N_design; + // Turbine inlet state + t_des_par.m_P_in = m_pres_last[TURB_IN]; + t_des_par.m_T_in = m_temp_last[TURB_IN]; + t_des_par.m_D_in = m_dens_last[TURB_IN]; + t_des_par.m_h_in = m_enth_last[TURB_IN]; + t_des_par.m_s_in = m_entr_last[TURB_IN]; + // Turbine outlet state + t_des_par.m_P_out = m_pres_last[TURB_OUT]; + t_des_par.m_h_out = m_enth_last[TURB_OUT]; + // Mass flow + t_des_par.m_m_dot = m_m_dot_t; + + int turb_size_error_code = 0; + m_t.turbine_sizing(t_des_par, turb_size_error_code); + + if (turb_size_error_code != 0) + { + error_code = turb_size_error_code; + return; + } + } + + // Design air cooler + { + // Structure for design parameters that are dependent on cycle design solution + C_CO2_to_air_cooler::S_des_par_cycle_dep s_air_cooler_des_par_dep; + // Set air cooler design parameters that are dependent on the cycle design solution + s_air_cooler_des_par_dep.m_T_hot_in_des = m_temp_last[LTR_LP_OUT]; // [K] + s_air_cooler_des_par_dep.m_P_hot_in_des = m_pres_last[LTR_LP_OUT]; // [kPa] + s_air_cooler_des_par_dep.m_m_dot_total = m_m_dot_mc; // [kg/s] + + // This pressure drop is currently uncoupled from the cycle design + double cooler_deltaP = m_pres_last[LTR_LP_OUT] - m_pres_last[MC_IN]; // [kPa] + if (cooler_deltaP == 0.0) + s_air_cooler_des_par_dep.m_delta_P_des = m_deltaP_cooler_frac * m_pres_last[LTR_LP_OUT]; // [kPa] + else + s_air_cooler_des_par_dep.m_delta_P_des = cooler_deltaP; // [kPa] + + s_air_cooler_des_par_dep.m_T_hot_out_des = m_temp_last[MC_IN]; // [K] + s_air_cooler_des_par_dep.m_W_dot_fan_des = m_frac_fan_power * m_W_dot_net / 1000.0; // [MWe] + // Structure for design parameters that are independent of cycle design solution + C_CO2_to_air_cooler::S_des_par_ind s_air_cooler_des_par_ind; + s_air_cooler_des_par_ind.m_T_amb_des = m_T_amb_des; // [K] + s_air_cooler_des_par_ind.m_elev = m_elevation; // [m] + s_air_cooler_des_par_ind.m_eta_fan = m_eta_fan; // [-] + s_air_cooler_des_par_ind.m_N_nodes_pass = m_N_nodes_pass; // [-] + + if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) + && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) + { + mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, ms_des_par.m_des_tol); + } + } + + // Get 'design_solved' structure from component classes + ms_des_solved.ms_mc_ms_des_solved = *m_mc_ms.get_design_solved(); + ms_des_solved.ms_rc_ms_des_solved = *m_rc_ms.get_design_solved(); + ms_des_solved.ms_t_des_solved = *m_t.get_design_solved(); + ms_des_solved.ms_LTR_des_solved = mc_LT_recup.ms_des_solved; + ms_des_solved.ms_HTR_des_solved = mc_HT_recup.ms_des_solved; + ms_des_solved.ms_mc_air_cooler = *mc_air_cooler.get_design_solved(); + + // Set solved design point metrics + ms_des_solved.m_temp = m_temp_last; + ms_des_solved.m_pres = m_pres_last; + ms_des_solved.m_enth = m_enth_last; + ms_des_solved.m_entr = m_entr_last; + ms_des_solved.m_dens = m_dens_last; + + ms_des_solved.m_eta_thermal = m_eta_thermal_calc_last; + ms_des_solved.m_W_dot_net = m_W_dot_net_last; + ms_des_solved.m_m_dot_mc = m_m_dot_mc; + ms_des_solved.m_m_dot_rc = m_m_dot_rc; + ms_des_solved.m_m_dot_t = m_m_dot_t; + ms_des_solved.m_recomp_frac = m_m_dot_rc / m_m_dot_t; + ms_des_solved.m_bp_frac = m_bp_frac; + + ms_des_solved.m_UA_LTR = ms_des_par.m_LTR_UA; + ms_des_solved.m_UA_HTR = ms_des_par.m_HTR_UA; + + ms_des_solved.m_W_dot_t = m_W_dot_t; //[kWe] + ms_des_solved.m_W_dot_mc = m_W_dot_mc; //[kWe] + ms_des_solved.m_W_dot_rc = m_W_dot_rc; //[kWe] + + ms_des_solved.m_W_dot_cooler_tot = mc_air_cooler.get_design_solved()->m_W_dot_fan * 1.E3; //[kWe] convert from MWe + + } @@ -1062,7 +1213,7 @@ void C_HTRBypass_Cycle::set_htf_par(double T_htf_phx_in, double T_htf_bp_out_tar { m_T_HTF_PHX_inlet = T_htf_phx_in; // K m_T_HTF_BP_outlet_target = T_htf_bp_out_target; // K - m_cp_HTF = cp_htf; + m_cp_HTF = cp_htf; // kJ/kg K m_dT_BP = dT_bp; m_HTF_PHX_cold_approach = htf_phx_cold_approach; diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 3a073fc778..08a5839c16 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -45,25 +45,25 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core { public: - enum E_htrbypass_cycle_state_points - { - // index values for c++ 0-based vectors for temperature, pressure, etc. - MC_IN = 0, // Main compressor inlet - MC_OUT, // Main compressor outlet - LTR_HP_OUT, // Low temp recuperator high pressure outlet - MIXER_OUT, // Mixer: LTR_HP_OUT + Recompressor outlet - HTR_HP_OUT, // High temp recuperator high pressure outlet - TURB_IN, // Turbine inlet - TURB_OUT, // Turbine outlet - HTR_LP_OUT, // High temp recuperator low pressure outlet - LTR_LP_OUT, // Low temp recuperator low pressure outlet - RC_OUT, // Recompresor outlet - BYPASS_OUT, - MIXER2_OUT, - - - END_SCO2_HTRBP_STATES - }; + //enum E_htrbypass_cycle_state_points + //{ + // // index values for c++ 0-based vectors for temperature, pressure, etc. + // MC_IN = 0, // Main compressor inlet + // MC_OUT, // Main compressor outlet + // LTR_HP_OUT, // Low temp recuperator high pressure outlet + // MIXER_OUT, // Mixer: LTR_HP_OUT + Recompressor outlet + // HTR_HP_OUT, // High temp recuperator high pressure outlet + // TURB_IN, // Turbine inlet + // TURB_OUT, // Turbine outlet + // HTR_LP_OUT, // High temp recuperator low pressure outlet + // LTR_LP_OUT, // Low temp recuperator low pressure outlet + // RC_OUT, // Recompresor outlet + // BYPASS_OUT, + // MIXER2_OUT, + + + // END_SCO2_HTRBP_STATES + //}; struct S_design_parameters { @@ -226,23 +226,23 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core S_design_parameters ms_des_par_auto_opt; // NEW Internal Variables - double m_w_t; - double m_w_mc; - double m_w_rc; + double m_w_t; // kJ/kg + double m_w_mc; // kJ/kg + double m_w_rc; // kJ/kg double m_Q_dot_LT, m_Q_dot_HT; double m_bp_frac; double m_m_dot_bp; double m_m_dot_htr_hp; - double m_cp_HTF; - double m_m_dot_HTF; + double m_cp_HTF; // kJ/kg K + double m_m_dot_HTF; // kg/s double m_Q_dot_BP; double m_T_HTF_PHX_inlet; double m_T_HTF_BP_outlet_target; double m_T_HTF_BP_outlet_calc; double m_T_HTF_PHX_out; - double m_dT_BP; // BYPASS_OUT - HTR_HP_OUT + double m_dT_BP; // BYPASS_OUT - HTR_HP_OUT double m_Q_dot_total; - double m_Q_dot_pc; // pre cooler heat rejected + double m_Q_dot_pc; // pre cooler heat rejected double m_HTF_BP_cold_approach; double m_HTF_PHX_cold_approach; bool is_htf_set = false; @@ -301,7 +301,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core N_nodes_pass, T_amb_des, elevation) { - m_temp_last.resize(END_SCO2_HTRBP_STATES); + m_temp_last.resize(END_SCO2_STATES); std::fill(m_temp_last.begin(), m_temp_last.end(), std::numeric_limits::quiet_NaN()); m_pres_last = m_enth_last = m_entr_last = m_dens_last = m_temp_last; @@ -318,6 +318,14 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core } + /// + /// Set HTF parameters + /// + /// K + /// K + /// kJ/kg K + /// K + /// K void set_htf_par(double T_htf_phx_in, double T_htf_bp_out_target, double cp_htf, double dT_bp, double htf_phx_cold_approach); diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index 498d797712..8573bb70dc 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -184,7 +184,7 @@ void C_sco2_phx_air_cooler::design_core() } double HTF_PHX_inlet = ms_des_par.m_T_htf_hot_in; - double cp_htf = htf_props.Cp(HTF_PHX_inlet) * 1000.0; // Convert to J/kg K + double cp_htf = htf_props.Cp(HTF_PHX_inlet); double HTF_BP_outlet = ms_des_par.m_T_htf_bypass_out; double deltaT_bp = ms_des_par.m_deltaT_bypass; double HTF_PHX_cold_approach = ms_des_par.m_phx_dt_cold_approach; @@ -363,28 +363,82 @@ void C_sco2_phx_air_cooler::design_core() // Initialize the PHX mc_phx.initialize(ms_des_par.m_hot_fl_code, ms_des_par.mc_hot_fl_props, ms_des_par.m_phx_N_sub_hx, ms_des_par.m_phx_od_UA_target_type); + // Define state enumerable for sco2 into PHX + int phx_cold_inlet_state = C_sco2_cycle_core::HTR_HP_OUT; + if (ms_des_par.m_cycle_config == 3) + phx_cold_inlet_state = C_sco2_cycle_core::MIXER2_OUT; + // Design the PHX - double q_dot_des_phx = ms_des_solved.ms_rc_cycle_solved.m_W_dot_net / ms_des_solved.ms_rc_cycle_solved.m_eta_thermal; + + // Calculate q_dot_phx using sco2 enthalpies and mass flow (using thermal efficiency does not work for htr bypass) + double q_dot_des_phx_old = ms_des_solved.ms_rc_cycle_solved.m_W_dot_net / ms_des_solved.ms_rc_cycle_solved.m_eta_thermal; + double q_dot_des_phx = ms_des_solved.ms_rc_cycle_solved.m_m_dot_t + * (ms_des_solved.ms_rc_cycle_solved.m_enth[C_sco2_cycle_core::TURB_IN] + - ms_des_solved.ms_rc_cycle_solved.m_enth[phx_cold_inlet_state]); + //ms_phx_des_par.m_Q_dot_design = ms_des_solved.ms_rc_cycle_solved.m_W_dot_net / ms_des_solved.ms_rc_cycle_solved.m_eta_thermal; //[kWt] ms_phx_des_par.m_T_h_in = ms_des_par.m_T_htf_hot_in; //[K] HTF hot inlet temperature // Okay, but CO2-HTF HX is assumed here. How does "structure inheritance" work? ms_phx_des_par.m_P_h_in = 1.0; // Assuming HTF is incompressible... ms_phx_des_par.m_P_h_out = 1.0; // Assuming HTF is incompressible... // ................................................................................. - ms_phx_des_par.m_T_c_in = ms_des_solved.ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::HTR_HP_OUT]; //[K] - ms_phx_des_par.m_P_c_in = ms_des_solved.ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::HTR_HP_OUT]; //[K] - ms_phx_des_par.m_P_c_out = ms_des_solved.ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::TURB_IN]; //[K] - ms_phx_des_par.m_m_dot_cold_des = ms_des_solved.ms_rc_cycle_solved.m_m_dot_t; //[kg/s] + + + ms_phx_des_par.m_T_c_in = ms_des_solved.ms_rc_cycle_solved.m_temp[phx_cold_inlet_state]; //[K] + ms_phx_des_par.m_P_c_in = ms_des_solved.ms_rc_cycle_solved.m_pres[phx_cold_inlet_state]; //[K] + ms_phx_des_par.m_P_c_out = ms_des_solved.ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::TURB_IN]; //[K] + ms_phx_des_par.m_m_dot_cold_des = ms_des_solved.ms_rc_cycle_solved.m_m_dot_t; //[kg/s] // Calculating the HTF mass flow rate in 'design_and_calc_m_dot_htf' ms_phx_des_par.m_m_dot_hot_des = std::numeric_limits::quiet_NaN(); // Set maximum effectiveness ms_phx_des_par.m_eff_max = 1.0; - + mc_phx.design_and_calc_m_dot_htf(ms_phx_des_par, q_dot_des_phx, ms_des_par.m_phx_dt_cold_approach, ms_des_solved.ms_phx_des_solved); //************************************************************************************* //************************************************************************************* + // Solve the Bypass HX (if necessary) + if (ms_des_par.m_cycle_config == 3) + { + // hard coded + int bp_N_subs_hx = ms_des_par.m_phx_N_sub_hx; + auto bp_od_UA_target_type = ms_des_par.m_phx_od_UA_target_type; + + mc_bp.initialize(ms_des_par.m_hot_fl_code, ms_des_par.mc_hot_fl_props, bp_N_subs_hx, bp_od_UA_target_type); + + // Calculate BP heat transfer + double m_dot_bp_sco2 = ms_des_solved.ms_rc_cycle_solved.m_bp_frac * (ms_des_solved.ms_rc_cycle_solved.m_m_dot_t); + double q_dot_des_bp = m_dot_bp_sco2 * (ms_des_solved.ms_rc_cycle_solved.m_enth[C_sco2_cycle_core::BYPASS_OUT] + - ms_des_solved.ms_rc_cycle_solved.m_enth[C_sco2_cycle_core::MIXER_OUT]); + + // Hot Parameters (HTF) + ms_bp_des_par.m_T_h_in = mc_phx.ms_des_solved.m_T_h_out; // [K] Inlet to Bypass is outlet of PHX + ms_bp_des_par.m_P_h_in = 1.0; // Assuming HTF is incompressible... + ms_bp_des_par.m_P_h_out = 1.0; // Assuming HTF is incompressible... + + // Cold Parameters (sco2) + ms_bp_des_par.m_T_c_in = ms_des_solved.ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::MIXER_OUT]; //[K] + ms_bp_des_par.m_P_c_in = ms_des_solved.ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::MIXER_OUT]; //[K] + ms_bp_des_par.m_P_c_out = ms_des_solved.ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::BYPASS_OUT]; //[K] + ms_bp_des_par.m_m_dot_cold_des = m_dot_bp_sco2; //[kg/s] + + // Calculating the HTF mass flow rate in 'design_and_calc_m_dot_htf' + ms_bp_des_par.m_m_dot_hot_des = std::numeric_limits::quiet_NaN(); + + // Set maximum effectiveness + ms_bp_des_par.m_eff_max = 1.0; + + // Set Mass Flow (it is known because it is equal to PHX) + ms_bp_des_par.m_m_dot_hot_des = ms_phx_des_par.m_m_dot_hot_des; + + // Design + if (ms_bp_des_par.m_m_dot_cold_des > 0) + { + mc_bp.design_calc_UA(ms_bp_des_par, q_dot_des_bp, ms_des_solved.ms_bp_des_solved); + } + } + return; } diff --git a/tcs/sco2_pc_csp_int.h b/tcs/sco2_pc_csp_int.h index 217affbf26..82bfcadd36 100644 --- a/tcs/sco2_pc_csp_int.h +++ b/tcs/sco2_pc_csp_int.h @@ -182,6 +182,7 @@ class C_sco2_phx_air_cooler { C_HX_counterflow_CRM::S_des_solved ms_phx_des_solved; C_sco2_cycle_core::S_design_solved ms_rc_cycle_solved; + C_HX_counterflow_CRM::S_des_solved ms_bp_des_solved; }; struct S_od_par @@ -370,11 +371,14 @@ class C_sco2_phx_air_cooler std::unique_ptr mpc_sco2_cycle; C_HX_co2_to_htf mc_phx; + C_HX_co2_to_htf mc_bp; // Bypass Heat Exchanger S_des_par ms_des_par; C_sco2_cycle_core::S_auto_opt_design_hit_eta_parameters ms_cycle_des_par; C_HX_counterflow_CRM::S_des_calc_UA_par ms_phx_des_par; - + + C_HX_counterflow_CRM::S_des_calc_UA_par ms_bp_des_par; // Bypass HX Design Parameters + S_des_solved ms_des_solved; S_od_par ms_od_par; From c0df2aab9f0e1a0cb63d34336ae28ea044bac4e7 Mon Sep 17 00:00:00 2001 From: taylorbrown75 Date: Wed, 24 May 2023 11:04:18 -0600 Subject: [PATCH 11/94] Try modifying htr bypass optimizer to prevent crashes --- tcs/sco2_htrbypass_cycle.cpp | 111 ++++++++++++++++++++--------------- tcs/sco2_pc_csp_int.cpp | 53 ++++++++++++++++- 2 files changed, 116 insertions(+), 48 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index b4b4cc8a89..39889479d7 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -90,23 +90,37 @@ void C_HTRBypass_Cycle::design_core(int& error_code) int BP_out_code = BP_des_solver.solve(BP_out_guess_lower, BP_out_guess_upper, 0, BP_out_solved, tol_BP_out_solved, iter_BP_out); + + // Check if Bypass Converged - if (BP_out_code == C_monotonic_eq_solver::CONVERGED) - { - // Bypass Converged - return; - } - else if (BP_out_code == C_monotonic_eq_solver::SLOPE_NEG_NO_NEG_ERR) - { - // Target Outlet temperature not possible (too low), bypass is fully open - return; - } - else if (BP_out_code == C_monotonic_eq_solver::SLOPE_NEG_NO_POS_ERR) - { - // Target Outlet temperature not possible (too high), bypass is fully closed - return; - } - else + + //if (BP_out_code == C_monotonic_eq_solver::CONVERGED) + //{ + // // Bypass Converged + // return; + //} + //else if (BP_out_code == C_monotonic_eq_solver::SLOPE_NEG_NO_NEG_ERR) + //{ + // // Target Outlet temperature not possible (too low), bypass is fully open + // return; + //} + // else if (BP_out_code == C_monotonic_eq_solver::SLOPE_NEG_NO_POS_ERR) + //{ + // // Target Outlet temperature not possible (too high), bypass is fully closed + // return; + //} + // else + //{ + // error_code = 35; + // return; + //} + + + + + + + if (BP_out_code == C_monotonic_eq_solver::NO_SOLUTION) { // Did not converge error_code = 35; @@ -864,6 +878,9 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) design_core(error_code); + int io = 0; + design_core_standard(io); + /* m_W_dot_net_last = m_W_dot_net_opt; m_eta_thermal_last = m_eta_thermal_opt; @@ -1019,37 +1036,37 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) // Is recompression fraction fixed or optimized? // If fixed, then we don't need to try simple cycle - if (ms_auto_opt_des_par.m_is_recomp_ok == 1.0 || ms_auto_opt_des_par.m_is_recomp_ok == 0.0) - { - - // Complete 'ms_opt_des_par' for simple cycle - ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] - ms_opt_des_par.m_fixed_P_mc_out = true; - - if (ms_opt_des_par.m_fixed_PR_HP_to_LP) - { - ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] - } - else - { - ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] - } - - ms_opt_des_par.m_recomp_frac_guess = 0.0; - ms_opt_des_par.m_fixed_recomp_frac = true; - ms_opt_des_par.m_LT_frac_guess = 1.0; - ms_opt_des_par.m_fixed_LT_frac = true; - - int s_error_code = 0; - - opt_design_core(s_error_code); - - if (s_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) - { - ms_des_par_auto_opt = ms_des_par_optimal; - m_objective_metric_auto_opt = m_objective_metric_opt; - } - } + //if (ms_auto_opt_des_par.m_is_recomp_ok == 1.0 || ms_auto_opt_des_par.m_is_recomp_ok == 0.0) + //{ + + // // Complete 'ms_opt_des_par' for simple cycle + // ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] + // ms_opt_des_par.m_fixed_P_mc_out = true; + + // if (ms_opt_des_par.m_fixed_PR_HP_to_LP) + // { + // ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + // } + // else + // { + // ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] + // } + + // ms_opt_des_par.m_recomp_frac_guess = 0.0; + // ms_opt_des_par.m_fixed_recomp_frac = true; + // ms_opt_des_par.m_LT_frac_guess = 1.0; + // ms_opt_des_par.m_fixed_LT_frac = true; + + // int s_error_code = 0; + + // opt_design_core(s_error_code); + + // if (s_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) + // { + // ms_des_par_auto_opt = ms_des_par_optimal; + // m_objective_metric_auto_opt = m_objective_metric_opt; + // } + //} ms_des_par = ms_des_par_auto_opt; diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index 8573bb70dc..f65611da28 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -433,12 +433,63 @@ void C_sco2_phx_air_cooler::design_core() ms_bp_des_par.m_m_dot_hot_des = ms_phx_des_par.m_m_dot_hot_des; // Design - if (ms_bp_des_par.m_m_dot_cold_des > 0) + if (ms_bp_des_par.m_m_dot_cold_des > 0 && q_dot_des_bp > 1e-2) { mc_bp.design_calc_UA(ms_bp_des_par, q_dot_des_bp, ms_des_solved.ms_bp_des_solved); } } + + //DEBUG + if (true) + { + double cost_LTR = ms_des_solved.ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_bare_erected + ms_des_solved.ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_equipment; + double cost_HTR = ms_des_solved.ms_rc_cycle_solved.ms_HTR_des_solved.m_cost_bare_erected + ms_des_solved.ms_rc_cycle_solved.ms_HTR_des_solved.m_cost_equipment; + double cost_MC = ms_des_solved.ms_rc_cycle_solved.ms_mc_ms_des_solved.m_cost_bare_erected + ms_des_solved.ms_rc_cycle_solved.ms_mc_ms_des_solved.m_cost_equipment; + double cost_RC = ms_des_solved.ms_rc_cycle_solved.ms_rc_ms_des_solved.m_cost_bare_erected + ms_des_solved.ms_rc_cycle_solved.ms_rc_ms_des_solved.m_cost_equipment; + double cost_T = ms_des_solved.ms_rc_cycle_solved.ms_t_des_solved.m_bare_erected_cost + ms_des_solved.ms_rc_cycle_solved.ms_t_des_solved.m_equipment_cost; + double cost_PHX = mc_phx.ms_des_solved.m_cost_bare_erected + mc_phx.ms_des_solved.m_cost_equipment; + double cost_BP = mc_bp.ms_des_solved.m_cost_bare_erected + mc_bp.ms_des_solved.m_cost_equipment; + + double cost_bare_erected = ms_des_solved.ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_bare_erected + + ms_des_solved.ms_rc_cycle_solved.ms_HTR_des_solved.m_cost_bare_erected + + ms_des_solved.ms_rc_cycle_solved.ms_mc_ms_des_solved.m_cost_bare_erected + + ms_des_solved.ms_rc_cycle_solved.ms_rc_ms_des_solved.m_cost_bare_erected + + ms_des_solved.ms_rc_cycle_solved.ms_t_des_solved.m_bare_erected_cost + + mc_phx.ms_des_solved.m_cost_bare_erected; + + double cost_equipment = ms_des_solved.ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_equipment + + ms_des_solved.ms_rc_cycle_solved.ms_HTR_des_solved.m_cost_equipment + + ms_des_solved.ms_rc_cycle_solved.ms_mc_ms_des_solved.m_cost_equipment + + ms_des_solved.ms_rc_cycle_solved.ms_rc_ms_des_solved.m_cost_equipment + + ms_des_solved.ms_rc_cycle_solved.ms_t_des_solved.m_equipment_cost + + mc_phx.ms_des_solved.m_cost_equipment; + + if (std::isnan(mc_bp.ms_des_solved.m_cost_bare_erected) == false) + { + cost_bare_erected += mc_bp.ms_des_solved.m_cost_bare_erected; + cost_equipment += mc_bp.ms_des_solved.m_cost_equipment; + } + + + double total_cost = cost_bare_erected + cost_equipment; + + + // Back Calculate Heat into cycle + double W_net = ms_des_solved.ms_rc_cycle_solved.m_W_dot_mc + ms_des_solved.ms_rc_cycle_solved.m_W_dot_rc + ms_des_solved.ms_rc_cycle_solved.m_W_dot_t; + double Q_pc = ms_des_solved.ms_rc_cycle_solved.m_m_dot_mc * (ms_des_solved.ms_rc_cycle_solved.m_enth[8] - ms_des_solved.ms_rc_cycle_solved.m_enth[0]); + + double Q_tot = W_net + Q_pc; + + + + + + int x = 0; + } + + + return; } From 675a055d55194785705f7ccdc1c884faeb6d0387 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Mon, 26 Jun 2023 14:35:42 -0600 Subject: [PATCH 12/94] Change bypass fraction optimization to non linear. Add penalty to cycle optimizer, accounting for missed target outlet temperatures. Fix bug when recompression fraction == 0. Add debug output function. --- tcs/sco2_htrbypass_cycle.cpp | 405 +++++++++++++++++++++++++++++------ tcs/sco2_htrbypass_cycle.h | 24 ++- 2 files changed, 366 insertions(+), 63 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 39889479d7..24be42f3d3 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -35,8 +35,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "CO2_properties.h" -#include "nlopt.hpp" -#include "nlopt_callbacks.h" #include "fmin.h" @@ -54,17 +52,26 @@ void C_HTRBypass_Cycle::design_core(int& error_code) //ms_des_par.m_P_mc_out = 25000; //m_T_t_in = 923.149; - //DEBUG + + // DEBUG if (false) { - std::vector bp_fracs = { 0, 0.01, 0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,0.99,1 }; - for (double bp : bp_fracs) - { - m_bp_frac = bp; + ms_des_par.m_recomp_frac = 0; + m_bp_frac = 0.5; - int temp_error = 0; - design_core_standard(temp_error); - } + int temp_error = 0; + design_core_standard(temp_error); + } + + //DEBUG solar flex + if (false) + { + m_bp_frac = 0.11; + + int temp_error = 0; + design_core_standard(temp_error); + + return; } // Check if HTF parameters were set @@ -74,58 +81,125 @@ void C_HTRBypass_Cycle::design_core(int& error_code) return; } - C_mono_htr_bypass_BP_des BP_des_eq(this); - C_monotonic_eq_solver BP_des_solver(BP_des_eq); - double BP_out_lower = 0; - double BP_out_upper = 0.99; + - double BP_out_guess_lower = 0; //[K] - double BP_out_guess_upper = 0.99; //[K] + //DEBUG + if (false) + { + int temp_error = 0; - BP_des_solver.settings(ms_des_par.m_des_tol, 1000, BP_out_lower, BP_out_upper, false); + std::vector bp_frac_vec; + std::vector calc_outlet_temp; + std::vector outlet_err; + std::vector eff_vec; + std::vector obj_vec; + std::vector sig_vec; + std::vector log_vec; - double BP_out_solved, tol_BP_out_solved; - BP_out_solved = tol_BP_out_solved = std::numeric_limits::quiet_NaN(); - int iter_BP_out = -1; + for (double bp = 0.001; bp < 0.99; bp += 0.01) + { + m_objective_metric_bypass_frac_opt = -1000000000000000000; - int BP_out_code = BP_des_solver.solve(BP_out_guess_lower, BP_out_guess_upper, 0, BP_out_solved, tol_BP_out_solved, iter_BP_out); + design_bypass_frac_return_objective_metric({ bp }); - + double err = m_T_HTF_BP_outlet_calc - m_T_HTF_BP_outlet_target; + double span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; + double percent_err = std::abs(err) / span; + double sig = sigmoid(percent_err); + double log = logit(percent_err); - // Check if Bypass Converged - - //if (BP_out_code == C_monotonic_eq_solver::CONVERGED) - //{ - // // Bypass Converged - // return; - //} - //else if (BP_out_code == C_monotonic_eq_solver::SLOPE_NEG_NO_NEG_ERR) - //{ - // // Target Outlet temperature not possible (too low), bypass is fully open - // return; - //} - // else if (BP_out_code == C_monotonic_eq_solver::SLOPE_NEG_NO_POS_ERR) - //{ - // // Target Outlet temperature not possible (too high), bypass is fully closed - // return; - //} - // else - //{ - // error_code = 35; - // return; - //} + bp_frac_vec.push_back(bp); + calc_outlet_temp.push_back(m_T_HTF_BP_outlet_calc); + outlet_err.push_back(m_T_HTF_BP_outlet_calc - m_T_HTF_BP_outlet_target); + eff_vec.push_back(m_eta_thermal_calc_last); + obj_vec.push_back(m_objective_metric_bypass_frac_opt); + sig_vec.push_back(sig); + log_vec.push_back(log); + } + int x = 0; + + } + // Try Full Optization (not monotonic) + if (true) + { + m_objective_metric_bypass_frac_opt = -10000000; + + // Set up instance of nlopt class and set optimization parameters + nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); + + std::vector lb = { 0 }; + std::vector ub = { 0.99 }; + + opt_des_cycle.set_lower_bounds(lb); + opt_des_cycle.set_upper_bounds(ub); + opt_des_cycle.set_initial_step(0.01); + opt_des_cycle.set_xtol_rel(0.1); + + // Set max objective function + std::vector x; + x.push_back(0.1); + opt_des_cycle.set_max_objective(nlopt_cb_opt_bypass_frac_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' + double max_f = std::numeric_limits::quiet_NaN(); + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + + + m_bp_frac = x[0]; + design_core_standard(error_code); - if (BP_out_code == C_monotonic_eq_solver::NO_SOLUTION) + std::string s = make_result_csv_string(); + + int yx = 0; + } + + // Monotonic Solver + if(false) { - // Did not converge - error_code = 35; - return; + C_mono_htr_bypass_BP_des BP_des_eq(this); + C_monotonic_eq_solver BP_des_solver(BP_des_eq); + double BP_out_lower = 0; + double BP_out_upper = 0.99; + + double BP_out_guess_lower = 0; //[K] + double BP_out_guess_upper = 0.99; //[K] + + BP_des_solver.settings(ms_des_par.m_des_tol, 1000, BP_out_lower, BP_out_upper, false); + + double BP_out_solved, tol_BP_out_solved; + BP_out_solved = tol_BP_out_solved = std::numeric_limits::quiet_NaN(); + int iter_BP_out = -1; + + int BP_out_code = BP_des_solver.solve(BP_out_guess_lower, BP_out_guess_upper, 0, BP_out_solved, tol_BP_out_solved, iter_BP_out); + + if (BP_out_code == C_monotonic_eq_solver::NO_SOLUTION) + { + // Did not converge + error_code = 35; + return; + } + + // Modify objective function to account for hitting the target HTF outlet temperature + { + double target_bp_out = m_T_HTF_BP_outlet_target; + double calc_bp_out = m_T_HTF_BP_outlet_calc; + + double temp_err = std::abs(calc_bp_out - target_bp_out); + double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; + double percent_err = temp_err / temp_span; + + double penalty = 3 * std::pow(percent_err, 2.0); + + m_objective_metric_last -= penalty; + int x = 0; + + } } + + } void C_HTRBypass_Cycle::design_core_standard(int& error_code) @@ -139,6 +213,66 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) CO2_state co2_props; + + // DEBUG + { + // BP + double Q_dot_BP; + { + int prop_error_code = CO2_TP(194.3+273.15, 24.875 * 1e3, &co2_props); + double h1 = co2_props.enth; + + CO2_TP(471 + 273.15, 24.775 * 1e3, &co2_props); + double h2 = co2_props.enth; + + double mdot = 26.3; // kg/s + + Q_dot_BP = mdot * (h2 - h1); + } + + // PHX + double Q_dot_PHX; + { + int prop_error_code = CO2_TP(470.6 + 273.15, 24.75 * 1e3, &co2_props); + double h1 = co2_props.enth; + + CO2_TP(620 + 273.15, 24.55 * 1e3, &co2_props); + double h2 = co2_props.enth; + + double mdot = 239; // kg/s + + Q_dot_PHX = mdot * (h2 - h1); + } + + + // HTR + double Q_dot_HTR_LP; + double Q_dot_HTR_HP; + { + int prop_error_code = CO2_TP(481.6 + 273.15, 8.1 * 1e3, &co2_props); + double h1 = co2_props.enth; + + CO2_TP(240.4 + 273.15, 8.06 * 1e3, &co2_props); + double h2 = co2_props.enth; + + double mdot = 239; // kg/s + Q_dot_HTR_LP = mdot * (h2 - h1); + + + CO2_TP(194.4 + 273.15, 24.875 * 1e3, &co2_props); + double h3 = co2_props.enth; + + CO2_TP(470.6 + 273.15, 24.75 * 1e3, &co2_props); + double h4 = co2_props.enth; + + double mdot2 = 212.7; // kg/s + Q_dot_HTR_HP = mdot2 * (h4 - h3); + } + + + int x = 0; + } + // Initialize Recuperators { // LTR @@ -342,7 +476,7 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) C_mono_htr_bypass_HTR_des HTR_des_eq(this); C_monotonic_eq_solver HTR_des_solver(HTR_des_eq); - if (ms_des_par.m_recomp_frac == 0.0) + /*if (ms_des_par.m_recomp_frac == 0.0) { double y_T_diff = std::numeric_limits::quiet_NaN(); int no_HTR_out_code = HTR_des_solver.test_member_function(m_temp_last[TURB_OUT], &y_T_diff); @@ -352,8 +486,8 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) error_code = 35; return; } - } - else + }*/ + //else { double T_HTR_LP_out_lower = m_temp_last[MC_OUT]; //[K] Coldest possible temperature double T_HTR_LP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature @@ -747,6 +881,68 @@ int C_HTRBypass_Cycle::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_L return 0; } +std::string C_HTRBypass_Cycle::make_result_csv_string() +{ + std::string value_string; + std::vector value_vec; + + value_vec.push_back(this->m_T_HTF_BP_outlet_target); + value_vec.push_back(this->m_T_HTF_BP_outlet_calc); + value_vec.push_back(this->m_T_HTF_PHX_inlet - this->m_T_HTF_BP_outlet_calc); + value_vec.push_back(this->m_m_dot_HTF); + value_vec.push_back(this->m_bp_frac); + value_vec.push_back(this->ms_des_par.m_recomp_frac); + value_vec.push_back(this->m_eta_thermal_calc_last); + value_vec.push_back(this->m_pres_last[MC_IN]); + value_vec.push_back(this->m_pres_last[MC_OUT]); + value_vec.push_back(this->ms_des_par.m_LTR_UA); + value_vec.push_back(this->ms_des_par.m_HTR_UA); + value_vec.push_back(this->m_T_HTF_PHX_out); + value_vec.push_back(this->m_Q_dot_total); + value_vec.push_back(this->m_Q_dot_BP); + value_vec.push_back(this->m_Q_dot_PHX); + value_vec.push_back(this->m_m_dot_t); + value_vec.push_back(this->m_m_dot_bp); + value_vec.push_back(this->m_m_dot_htr_hp); + value_vec.push_back(this->m_m_dot_rc); + value_vec.push_back(this->m_m_dot_mc); + value_vec.push_back(this->m_objective_metric_opt); + + // Write to string + for (double val : value_vec) + { + value_string.append(std::to_string(val)); + value_string.append("\n"); + } + + + // Write Temperatures + value_string.append("\n"); + value_string.append("\n"); + for (double val : this->m_temp_last) + { + value_string.append(std::to_string(val)); + value_string.append("\n"); + } + + // Write Pressures + value_string.append("\n"); + value_string.append("\n"); + for (double val : this->m_pres_last) + { + value_string.append(std::to_string(val)); + value_string.append("\n"); + } + + + + + + + + return value_string; +} + int C_HTRBypass_Cycle::C_mono_htr_bypass_LTR_des::operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out) @@ -859,21 +1055,24 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) error_code = 0; if (index > 0) { - // Ensure thermal efficiency is initialized to 0 - m_objective_metric_opt = 0.0; - + // Ensure thermal efficiency is initialized to negative value + m_objective_metric_opt = -100000000000; + // Set up instance of nlopt class and set optimization parameters - nlopt::opt opt_des_cycle(nlopt::LN_SBPLX, index); + nlopt::opt opt_des_cycle(nlopt::GN_CRS2_LM, index); opt_des_cycle.set_lower_bounds(lb); opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(scale); - opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); + opt_des_cycle.set_xtol_rel(0.1); // Set max objective function opt_des_cycle.set_max_objective(nlopt_cb_opt_htr_bypass_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' double max_f = std::numeric_limits::quiet_NaN(); nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + // Check if forced stop + int flag = opt_des_cycle.get_force_stop(); + ms_des_par = ms_des_par_optimal; design_core(error_code); @@ -881,6 +1080,10 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) int io = 0; design_core_standard(io); + std::string val_string = make_result_csv_string(); + + int otu = 0; + /* m_W_dot_net_last = m_W_dot_net_opt; m_eta_thermal_last = m_eta_thermal_opt; @@ -1302,7 +1505,7 @@ double C_HTRBypass_Cycle::design_cycle_return_objective_metric(const std::vector { PR_mc_local = x[index]; if (PR_mc_local > 50.0) - return 0.0; + return -10000000000000.0; index++; P_mc_in = ms_des_par.m_P_mc_out / PR_mc_local; } @@ -1364,23 +1567,82 @@ double C_HTRBypass_Cycle::design_cycle_return_objective_metric(const std::vector design_core(error_code); - double objective_metric = 0.0; + + + // Set Objective + double objective_metric = -10000000000.0; if (error_code == 0) { - objective_metric = m_objective_metric_last; + double eff = m_eta_thermal_calc_last; + + double target_bp_out = m_T_HTF_BP_outlet_target; + double calc_bp_out = m_T_HTF_BP_outlet_calc; + + double temp_err = std::abs(calc_bp_out - target_bp_out); + double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; + double percent_err = temp_err / temp_span; + + double penalty = 10.0 * (sigmoid(percent_err) - 0.5); - if (m_objective_metric_last > m_objective_metric_opt) + objective_metric = eff - penalty; + + if (objective_metric > m_objective_metric_opt) { ms_des_par_optimal = ms_des_par; - m_objective_metric_opt = m_objective_metric_last; + m_objective_metric_opt = objective_metric; } } return objective_metric; } +// X is single bypass fraction value +double C_HTRBypass_Cycle::design_bypass_frac_return_objective_metric(const std::vector& x) +{ + m_bp_frac = x[0]; + + int error_code = 0; + + design_core_standard(error_code); + + double objective_metric = -10000000000.0; + if (error_code == 0) + { + double eff = m_eta_thermal_calc_last; + + double target_bp_out = m_T_HTF_BP_outlet_target; + double calc_bp_out = m_T_HTF_BP_outlet_calc; + + double temp_err = std::abs(calc_bp_out - target_bp_out); + + + + + double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; + double percent_err = temp_err / temp_span; + + //// Check if temperature hit target + //if (percent_err <= 0.000001) + //{ + // bp_frac_ptr->set_force_stop(10); + //} + + + + double penalty = std::pow(percent_err, 2.0); + + objective_metric = 0 - logit(percent_err); + if (objective_metric > m_objective_metric_bypass_frac_opt) + { + ms_des_par_bp_frac_optimal = ms_des_par; + m_objective_metric_bypass_frac_opt = objective_metric; + } + } + + return objective_metric; +} @@ -1441,6 +1703,7 @@ void C_HTRBypass_Cycle::estimate_od_turbo_operation(double T_mc_in, double P_mc_ } + double nlopt_cb_opt_htr_bypass_des(const std::vector& x, std::vector& grad, void* data) { C_HTRBypass_Cycle* frame = static_cast(data); @@ -1449,3 +1712,23 @@ double nlopt_cb_opt_htr_bypass_des(const std::vector& x, std::vector& x, std::vector& grad, void* data) +{ + C_HTRBypass_Cycle* frame = static_cast(data); + if (frame != NULL) + return frame->design_bypass_frac_return_objective_metric(x); + else + return 0.0; +} + + +double sigmoid(const double val) +{ + return 1.0 / (1.0 + std::exp(-1.0 * val)); +} + +double logit(const double val) +{ + return std::log(val / (1.0 - val)); +} diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 08a5839c16..4bd1699163 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -41,6 +41,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "numeric_solvers.h" + +#include "nlopt.hpp" +#include "nlopt_callbacks.h" + class C_HTRBypass_Cycle : public C_sco2_cycle_core { public: @@ -207,19 +211,24 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core // Input/Ouput structures for class methods S_design_parameters ms_des_par; S_opt_design_parameters ms_opt_des_par; + // Results from last 'design' solution std::vector m_temp_last, m_pres_last, m_enth_last, m_entr_last, m_dens_last; // thermodynamic states (K, kPa, kJ/kg, kJ/kg-K, kg/m3) double m_eta_thermal_calc_last; double m_W_dot_net_last; double m_m_dot_mc, m_m_dot_rc, m_m_dot_t; - double m_Q_dot_PHX, m_Q_dot_bypass, m_eta_bypass; + double m_Q_dot_PHX; double m_W_dot_mc, m_W_dot_rc, m_W_dot_t, m_W_dot_mc_bypass; double m_objective_metric_last; + double m_objective_metric_bypass_frac_last; // Structures and data for optimization S_design_parameters ms_des_par_optimal; double m_objective_metric_opt; + double m_objective_metric_bypass_frac_opt; + + S_design_parameters ms_des_par_bp_frac_optimal; // Structures and data for auto-optimization double m_objective_metric_auto_opt; @@ -270,6 +279,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core int solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out); int solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_LP_out); + std::string make_result_csv_string(); + public: C_HTRBypass_Cycle(C_sco2_cycle_core::E_turbo_gen_motor_config turbo_gen_motor_config, @@ -306,7 +317,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core m_pres_last = m_enth_last = m_entr_last = m_dens_last = m_temp_last; m_eta_thermal_calc_last = m_m_dot_mc = m_m_dot_rc = m_m_dot_t = std::numeric_limits::quiet_NaN(); - m_Q_dot_PHX = m_Q_dot_bypass = m_eta_bypass = std::numeric_limits::quiet_NaN(); + m_Q_dot_PHX = std::numeric_limits::quiet_NaN(); m_W_dot_mc = m_W_dot_rc = m_W_dot_t = m_W_dot_mc_bypass = std::numeric_limits::quiet_NaN(); m_objective_metric_last = std::numeric_limits::quiet_NaN(); @@ -347,6 +358,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core // Called by 'nlopt_callback_opt_des_1', so needs to be public double design_cycle_return_objective_metric(const std::vector& x); + // Called by 'nlopt_callback_opt_des_1', so needs to be public + double design_bypass_frac_return_objective_metric(const std::vector& x); class C_mono_htr_bypass_LTR_des : public C_monotonic_equation { @@ -445,4 +458,11 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double nlopt_cb_opt_htr_bypass_des(const std::vector& x, std::vector& grad, void* data); +double nlopt_cb_opt_bypass_frac_des(const std::vector& x, std::vector& grad, void* data); + + +double sigmoid(const double val); + +double logit(const double val); + #endif From a3a74edf2e537432dca80460642229575c4d95df Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Wed, 28 Jun 2023 10:11:49 -0600 Subject: [PATCH 13/94] Add alfani test case --- tcs/sco2_htrbypass_cycle.cpp | 94 ++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 24be42f3d3..6f4174e03b 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -52,6 +52,20 @@ void C_HTRBypass_Cycle::design_core(int& error_code) //ms_des_par.m_P_mc_out = 25000; //m_T_t_in = 923.149; + // DEBUG + if (false) + { + std::vector bp_vec = { 0.999 }; + for (double bp : bp_vec) + { + m_bp_frac = bp; + design_core_standard(error_code); + + std::string output = make_result_csv_string(); + + int o = 0; + } + } // DEBUG if (false) @@ -63,14 +77,20 @@ void C_HTRBypass_Cycle::design_core(int& error_code) design_core_standard(temp_error); } - //DEBUG solar flex - if (false) + //DEBUG Alfani + if (true) { - m_bp_frac = 0.11; + m_bp_frac = 0.17386; + m_cp_HTF = 1.15; + int temp_error = 0; design_core_standard(temp_error); + std::string output = make_result_csv_string(); + + int o = 0; + return; } @@ -137,7 +157,7 @@ void C_HTRBypass_Cycle::design_core(int& error_code) opt_des_cycle.set_lower_bounds(lb); opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(0.01); - opt_des_cycle.set_xtol_rel(0.1); + opt_des_cycle.set_xtol_rel(0.005); // Set max objective function std::vector x; @@ -215,7 +235,38 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) // DEBUG + if(true) { + { + double Q = 15.364; // MW + double mdot = 140.17; // kg/s + double pres = 18.134; //MPa + + double T2 = 346.69; // C + + // Get h2 + CO2_TP(T2 + 273.15, pres * 1e3, &co2_props); + double h2 = co2_props.enth; + + // Calculate h1 + double h1 = h2 - (Q * 1e3) / mdot; + + // Get T1 + CO2_PH(pres * 1e3, h1, &co2_props); + double T1 = co2_props.temp - 273.15; + + int oiasdf = 0; + } + + + + + + + + + + // BP double Q_dot_BP; { @@ -1052,6 +1103,21 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) index++; } + // DEBUG + if (false) + { + std::vector recomp_vec = { 0.8 }; + for (double re : recomp_vec) + { + ms_des_par.m_P_mc_out = ms_opt_des_par.m_P_mc_out_guess; + ms_des_par.m_P_mc_in = ms_des_par.m_P_mc_out / ms_opt_des_par.m_PR_HP_to_LP_guess; + ms_des_par.m_recomp_frac = re; + design_core(error_code); + } + } + + + error_code = 0; if (index > 0) { @@ -1059,11 +1125,11 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) m_objective_metric_opt = -100000000000; // Set up instance of nlopt class and set optimization parameters - nlopt::opt opt_des_cycle(nlopt::GN_CRS2_LM, index); + nlopt::opt opt_des_cycle(nlopt::LN_SBPLX, index); opt_des_cycle.set_lower_bounds(lb); opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(scale); - opt_des_cycle.set_xtol_rel(0.1); + opt_des_cycle.set_xtol_rel(0.001); // Set max objective function opt_des_cycle.set_max_objective(nlopt_cb_opt_htr_bypass_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' @@ -1614,25 +1680,13 @@ double C_HTRBypass_Cycle::design_bypass_frac_return_objective_metric(const std:: double calc_bp_out = m_T_HTF_BP_outlet_calc; double temp_err = std::abs(calc_bp_out - target_bp_out); - - - - double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; double percent_err = temp_err / temp_span; - //// Check if temperature hit target - //if (percent_err <= 0.000001) - //{ - // bp_frac_ptr->set_force_stop(10); - //} - - - double penalty = std::pow(percent_err, 2.0); - objective_metric = 0 - logit(percent_err); - + //objective_metric = 0 - logit(percent_err); + objective_metric = -temp_err; if (objective_metric > m_objective_metric_bypass_frac_opt) { From 98ca56eb1a26e7c9e18aaad076e156362a2ed5f4 Mon Sep 17 00:00:00 2001 From: taylorbrown75 Date: Sun, 16 Jul 2023 11:44:31 -0600 Subject: [PATCH 14/94] Add HX model definitions to end of cycle simulation. Add debug code for running 2020 Alfani case. Add Bypass Heat Exchanger class. --- tcs/sco2_htrbypass_cycle.cpp | 416 ++++++++++++++++++++++++++++++----- tcs/sco2_htrbypass_cycle.h | 2 +- 2 files changed, 366 insertions(+), 52 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 6f4174e03b..3a26a6e74f 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -42,16 +42,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. void C_HTRBypass_Cycle::design_core(int& error_code) { - // Temporary Hard coded parameters - //ms_des_par.m_recomp_frac = 0.3; - //m_dT_BP = 10; - //m_T_HTF_PHX_inlet = 670 + 273; // K - //m_T_HTF_BP_outlet = 650 + 273; // K - //m_cp_HTF = 1.482e+03; // J/kg K - //ms_des_par.m_P_mc_in = 10000; - //ms_des_par.m_P_mc_out = 25000; - //m_T_t_in = 923.149; - // DEBUG if (false) { @@ -77,8 +67,139 @@ void C_HTRBypass_Cycle::design_core(int& error_code) design_core_standard(temp_error); } - //DEBUG Alfani - if (true) + // DEBUG sco2 flex + if (false) + { + m_bp_frac = 0.11; + m_cp_HTF = 1.5375; + + + int temp_error = 0; + design_core_standard(temp_error); + + std::string output = make_result_csv_string(); + + int o = 0; + + // Calculate Recuperator Balances + { + // HTR + double Q_htr_lp; + double Q_htr_hp; + { + double h1_lp = m_enth_last[TURB_OUT]; + double h2_lp = m_enth_last[HTR_LP_OUT]; + double mdot_lp = m_m_dot_t; + + Q_htr_lp = mdot_lp * (h2_lp - h1_lp); + + double h1_hp = m_enth_last[MIXER_OUT]; + double h2_hp = m_enth_last[HTR_HP_OUT]; + double mdot_hp = m_m_dot_htr_hp; + + Q_htr_hp = mdot_hp * (h2_hp - h1_hp); + } + + // LTR + double Q_ltr_lp; + double Q_ltr_hp; + { + double h1_lp = m_enth_last[HTR_LP_OUT]; + double h2_lp = m_enth_last[LTR_LP_OUT]; + double mdot_lp = m_m_dot_t; + + Q_ltr_lp = mdot_lp * (h2_lp - h1_lp); + + double h1_hp = m_enth_last[MC_OUT]; + double h2_hp = m_enth_last[LTR_HP_OUT]; + double mdot_hp = m_m_dot_mc; + + Q_ltr_hp = mdot_hp * (h2_hp - h1_hp); + } + + CO2_state co2_props; + + // HTR (sco2 flex) + double Q_dot_HTR_LP_paper; + double Q_dot_HTR_HP_paper; + { + int prop_error_code = CO2_TP(481.6 + 273.15, 8.1 * 1e3, &co2_props); + double h1 = co2_props.enth; + double cp1 = co2_props.cp * 1e3; + + CO2_TP(204.4 + 273.15, 8.06 * 1e3, &co2_props); + double h2 = co2_props.enth; + double cp2 = co2_props.cp * 1e3; + + double mdot = 239; // kg/s + Q_dot_HTR_LP_paper = mdot * (h2 - h1); + + + double cp_LP = (cp1 + cp2) / 2.0; + + + + CO2_TP(194.4 + 273.15, 24.875 * 1e3, &co2_props); + double h3 = co2_props.enth; + double cp3 = co2_props.cp * 1e3; + + CO2_TP(470.6 + 273.15, 24.75 * 1e3, &co2_props); + double h4 = co2_props.enth; + double cp4 = co2_props.cp * 1e3; + + double mdot2 = 212.7; // kg/s + Q_dot_HTR_HP_paper = mdot2 * (h4 - h3); + + double cp_HP = (cp3 + cp4) / 2.0; + + double pu = 0; + } + + + // LTR (sco2 flex) + double Q_dot_LTR_LP_paper; + double Q_dot_LTR_HP_paper; + { + int prop_error_code = CO2_TP(204.4 + 273.15, 8.06 * 1e3, &co2_props); + double h1 = co2_props.enth; + double cp1 = co2_props.cp * 1e3; + + CO2_TP(80 + 273.15, 8.019 * 1e3, &co2_props); + double h2 = co2_props.enth; + double cp2 = co2_props.cp * 1e3; + + double mdot = 239; // kg/s + Q_dot_LTR_LP_paper = mdot * (h2 - h1); + + double cp_LP = (cp1 + cp2) / 2.0; + + + CO2_TP(69.9 + 273.15, 25 * 1e3, &co2_props); + double h3 = co2_props.enth; + double cp3 = co2_props.cp * 1e3; + + CO2_TP(194.3 + 273.15, 24.875 * 1e3, &co2_props); + double h4 = co2_props.enth; + double cp4 = co2_props.cp * 1e3; + + double mdot2 = 153.7; // kg/s + Q_dot_LTR_HP_paper = mdot2 * (h4 - h3); + + + double cp_HP = (cp3 + cp4) / 2.0; + + + double pu = 0; + } + + int pox = 0; + } + + return; + } + + // DEBUG Alfani 2019 + if (false) { m_bp_frac = 0.17386; m_cp_HTF = 1.15; @@ -94,6 +215,170 @@ void C_HTRBypass_Cycle::design_core(int& error_code) return; } + // DEBUG Alfani 2020 + if (true) + { + m_bp_frac = 0.114; + + int temp_error = 0; + design_core_standard(temp_error); + + std::string output = make_result_csv_string(); + + int o = 0; + + // Calculate Recuperator Balances + { + // HTR + double Q_htr_lp; + double Q_htr_hp; + { + double h1_lp = m_enth_last[TURB_OUT]; + double h2_lp = m_enth_last[HTR_LP_OUT]; + double mdot_lp = m_m_dot_t; + + Q_htr_lp = mdot_lp * (h2_lp - h1_lp); + + double h1_hp = m_enth_last[MIXER_OUT]; + double h2_hp = m_enth_last[HTR_HP_OUT]; + double mdot_hp = m_m_dot_htr_hp; + + Q_htr_hp = mdot_hp * (h2_hp - h1_hp); + } + + // LTR + double Q_ltr_lp; + double Q_ltr_hp; + { + double h1_lp = m_enth_last[HTR_LP_OUT]; + double h2_lp = m_enth_last[LTR_LP_OUT]; + double mdot_lp = m_m_dot_t; + + Q_ltr_lp = mdot_lp * (h2_lp - h1_lp); + + double h1_hp = m_enth_last[MC_OUT]; + double h2_hp = m_enth_last[LTR_HP_OUT]; + double mdot_hp = m_m_dot_mc; + + Q_ltr_hp = mdot_hp * (h2_hp - h1_hp); + } + + CO2_state co2_props; + + // HTR (sco2 flex) + double Q_dot_HTR_LP_paper; + double Q_dot_HTR_HP_paper; + { + double T1_C = 485.27; + double T2_C = 198.72; + double T3_C = 188.72; + double T4_C = 475.27; + + double P1_C = 8.422; + double P2_C = 8.380; + double P3_C = 24.995; + double P4_C = 24.984; + + double mdot_lp = 1041.54; + double mdot_hp = 1041.54 * (1.0 - 0.114); + + + + int prop_error_code = CO2_TP(T1_C + 273.15, P1_C * 1e3, &co2_props); + double h1 = co2_props.enth; + + CO2_TP(T2_C + 273.15, P2_C * 1e3, &co2_props); + double h2 = co2_props.enth; + + + Q_dot_HTR_LP_paper = mdot_lp * (h2 - h1); + + + + CO2_TP(T3_C + 273.15, P3_C * 1e3, &co2_props); + double h3 = co2_props.enth; + + CO2_TP(T4_C + 273.15, P4_C * 1e3, &co2_props); + double h4 = co2_props.enth; + + + Q_dot_HTR_HP_paper = mdot_hp * (h4 - h3); + + + + double pu = 0; + } + + + // LTR (sco2 flex) + double Q_dot_LTR_LP_paper; + double Q_dot_LTR_HP_paper; + { + double T1_C = 198.72; + double T2_C = 76.01; + double T3_C = 65.91; + double T4_C = 188.72; + + double P1_C = 8.380; + double P2_C = 8.338; + double P3_C = 25; + double P4_C = 24.995; + + double mdot_lp = 1041.54; + double mdot_hp = 677.31; + + + + int prop_error_code = CO2_TP(T1_C + 273.15, P1_C * 1e3, &co2_props); + double h1 = co2_props.enth; + + CO2_TP(T2_C + 273.15, P2_C * 1e3, &co2_props); + double h2 = co2_props.enth; + + + Q_dot_LTR_LP_paper = mdot_lp * (h2 - h1); + + + + CO2_TP(T3_C + 273.15, P3_C * 1e3, &co2_props); + double h3 = co2_props.enth; + + CO2_TP(T4_C + 273.15, P4_C * 1e3, &co2_props); + double h4 = co2_props.enth; + + + Q_dot_LTR_HP_paper = mdot_hp * (h4 - h3); + + + + double pu = 0; + } + + int pox = 0; + } + + return; + } + + // DEBUG Alfani 2020 Various BP + if (false) + { + std::vector bp_vec = { 0,0.05,0.1,0.15,0.2,0.25,0.3,0.35,0.4,0.45,0.5,0.55,0.6,0.65,0.7,0.75,0.8,0.85,0.9,0.95,0.999}; + + for (double bp : bp_vec) + { + m_bp_frac = bp; + + int temp_error = 0; + design_core_standard(temp_error); + + std::string output = make_result_csv_string(); + + int asdf = 0; + } + + } + // Check if HTF parameters were set if (is_htf_set == false) { @@ -157,7 +442,7 @@ void C_HTRBypass_Cycle::design_core(int& error_code) opt_des_cycle.set_lower_bounds(lb); opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(0.01); - opt_des_cycle.set_xtol_rel(0.005); + opt_des_cycle.set_xtol_rel(0.05); // Set max objective function std::vector x; @@ -259,14 +544,6 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } - - - - - - - - // BP double Q_dot_BP; { @@ -296,32 +573,7 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } - // HTR - double Q_dot_HTR_LP; - double Q_dot_HTR_HP; - { - int prop_error_code = CO2_TP(481.6 + 273.15, 8.1 * 1e3, &co2_props); - double h1 = co2_props.enth; - - CO2_TP(240.4 + 273.15, 8.06 * 1e3, &co2_props); - double h2 = co2_props.enth; - - double mdot = 239; // kg/s - Q_dot_HTR_LP = mdot * (h2 - h1); - - - CO2_TP(194.4 + 273.15, 24.875 * 1e3, &co2_props); - double h3 = co2_props.enth; - - CO2_TP(470.6 + 273.15, 24.75 * 1e3, &co2_props); - double h4 = co2_props.enth; - - double mdot2 = 212.7; // kg/s - Q_dot_HTR_HP = mdot2 * (h4 - h3); - } - - - int x = 0; + } // Initialize Recuperators @@ -522,6 +774,7 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } } + // Solve the recuperators { C_mono_htr_bypass_HTR_des HTR_des_eq(this); @@ -546,6 +799,9 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) double T_HTR_LP_out_guess_lower = std::min(T_HTR_LP_out_upper - 2.0, std::max(T_HTR_LP_out_lower + 15.0, 220.0 + 273.15)); //[K] There is nothing special about these guesses... double T_HTR_LP_out_guess_upper = std::min(T_HTR_LP_out_guess_lower + 20.0, T_HTR_LP_out_upper - 1.0); //[K] There is nothing special about these guesses, either... + //T_HTR_LP_out_guess_lower = T_HTR_LP_out_lower; + //T_HTR_LP_out_guess_upper = T_HTR_LP_out_upper; + HTR_des_solver.settings(ms_des_par.m_des_tol * m_temp_last[MC_IN], 1000, T_HTR_LP_out_lower, T_HTR_LP_out_upper, false); double T_HTR_LP_out_solved, tol_T_HTR_LP_out_solved; @@ -691,6 +947,58 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } + // Define Heat Exchangers and Air Cooler + { + // PHX + C_HeatExchanger::S_design_parameters PHX_des_par; + PHX_des_par.m_DP_design[0] = m_pres_last[MIXER2_OUT] - m_pres_last[TURB_IN]; + PHX_des_par.m_DP_design[1] = 0.0; + PHX_des_par.m_m_dot_design[0] = m_m_dot_t; + PHX_des_par.m_m_dot_design[1] = 0.0; + PHX_des_par.m_Q_dot_design = m_m_dot_t * (m_enth_last[TURB_IN] - m_enth_last[MIXER2_OUT]); + m_PHX.initialize(PHX_des_par); + + // BPX + C_HeatExchanger::S_design_parameters BPX_des_par; + BPX_des_par.m_DP_design[0] = m_pres_last[MIXER_OUT] - m_pres_last[BYPASS_OUT]; + BPX_des_par.m_DP_design[1] = 0.0; + BPX_des_par.m_m_dot_design[0] = m_m_dot_bp; + BPX_des_par.m_m_dot_design[1] = 0.0; + BPX_des_par.m_Q_dot_design = m_m_dot_bp * (m_enth_last[BYPASS_OUT] - m_enth_last[MIXER_OUT]); + m_BPX.initialize(BPX_des_par); + + // Design air cooler + // Structure for design parameters that are dependent on cycle design solution + C_CO2_to_air_cooler::S_des_par_cycle_dep s_air_cooler_des_par_dep; + // Set air cooler design parameters that are dependent on the cycle design solution + s_air_cooler_des_par_dep.m_T_hot_in_des = m_temp_last[C_sco2_cycle_core::LTR_LP_OUT]; //[K] + s_air_cooler_des_par_dep.m_P_hot_in_des = m_pres_last[C_sco2_cycle_core::LTR_LP_OUT]; //[kPa] + s_air_cooler_des_par_dep.m_m_dot_total = m_m_dot_mc; //[kg/s] + + // This pressure drop is currently uncoupled from the cycle design + double cooler_deltaP = m_pres_last[C_sco2_cycle_core::LTR_LP_OUT] - m_pres_last[C_sco2_cycle_core::MC_IN]; //[kPa] + if (cooler_deltaP == 0.0) + s_air_cooler_des_par_dep.m_delta_P_des = m_deltaP_cooler_frac * m_pres_last[C_sco2_cycle_core::LTR_LP_OUT]; //[kPa] + else + s_air_cooler_des_par_dep.m_delta_P_des = cooler_deltaP; //[kPa] + + s_air_cooler_des_par_dep.m_T_hot_out_des = m_temp_last[C_sco2_cycle_core::MC_IN]; //[K] + s_air_cooler_des_par_dep.m_W_dot_fan_des = m_frac_fan_power * m_W_dot_net / 1000.0; //[MWe] + // Structure for design parameters that are independent of cycle design solution + C_CO2_to_air_cooler::S_des_par_ind s_air_cooler_des_par_ind; + s_air_cooler_des_par_ind.m_T_amb_des = m_T_amb_des; //[K] + s_air_cooler_des_par_ind.m_elev = m_elevation; //[m] + s_air_cooler_des_par_ind.m_eta_fan = m_eta_fan; //[-] + s_air_cooler_des_par_ind.m_N_nodes_pass = m_N_nodes_pass; //[-] + + if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) + && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) + { + mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, ms_des_par.m_des_tol); + } + + } + // Set objective metric { @@ -740,6 +1048,9 @@ int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_L double T_LTR_LP_out_guess_upper = std::min(T_LTR_LP_out_upper, T_LTR_LP_out_lower + 15.0); //[K] There is nothing special about using 15 here... double T_LTR_LP_out_guess_lower = std::min(T_LTR_LP_out_guess_upper * 0.99, T_LTR_LP_out_lower + 2.0); //[K] There is nothing special about using 2 here... + //double T_LTR_LP_out_guess_upper = T_LTR_LP_out_lower + 273.15; + //double T_LTR_LP_out_guess_lower = T_LTR_LP_out_upper + 273.15; + C_mono_htr_bypass_LTR_des LTR_des_eq(this); C_monotonic_eq_solver LTR_des_solver(LTR_des_eq); @@ -946,8 +1257,8 @@ std::string C_HTRBypass_Cycle::make_result_csv_string() value_vec.push_back(this->m_eta_thermal_calc_last); value_vec.push_back(this->m_pres_last[MC_IN]); value_vec.push_back(this->m_pres_last[MC_OUT]); - value_vec.push_back(this->ms_des_par.m_LTR_UA); - value_vec.push_back(this->ms_des_par.m_HTR_UA); + value_vec.push_back(this->mc_LT_recup.ms_des_solved.m_UA_calc_at_eff_max); + value_vec.push_back(this->mc_HT_recup.ms_des_solved.m_UA_calc_at_eff_max); value_vec.push_back(this->m_T_HTF_PHX_out); value_vec.push_back(this->m_Q_dot_total); value_vec.push_back(this->m_Q_dot_BP); @@ -1683,10 +1994,13 @@ double C_HTRBypass_Cycle::design_bypass_frac_return_objective_metric(const std:: double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; double percent_err = temp_err / temp_span; - double penalty = std::pow(percent_err, 2.0); + //double penalty = std::pow(percent_err, 2.0); //objective_metric = 0 - logit(percent_err); - objective_metric = -temp_err; + //objective_metric = -temp_err; + + // Adjust sigmoid + objective_metric = 1 - sigmoid(temp_err); if (objective_metric > m_objective_metric_bypass_frac_opt) { diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 4bd1699163..397d5d2bea 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -201,7 +201,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core C_turbine m_t; C_comp_multi_stage m_mc_ms; C_comp_multi_stage m_rc_ms; - C_HeatExchanger m_PHX, m_PC; + C_HeatExchanger m_PHX, m_PC, m_BPX; C_HX_co2_to_co2_CRM mc_LT_recup; C_HX_co2_to_co2_CRM mc_HT_recup; From 1b69153e125e4fe7146c9f6fd029e35faa98c324 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Tue, 18 Jul 2023 13:47:02 -0600 Subject: [PATCH 15/94] Add air cooler calculations (W and Q). Begin updating debug output string. --- tcs/sco2_htrbypass_cycle.cpp | 72 +++++++++++++++++++++++++++++------- tcs/sco2_htrbypass_cycle.h | 6 ++- 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 3a26a6e74f..826a66a432 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -357,6 +357,11 @@ void C_HTRBypass_Cycle::design_core(int& error_code) int pox = 0; } + // Calculate Paper Heat Exchange + { + + } + return; } @@ -841,16 +846,28 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) m_dens_last[HTR_HP_OUT] = co2_props.dens; } - // Calculate total heat coming into cycle + // Calculate total work and heat metrics { + // Work m_W_dot_mc = m_w_mc * m_m_dot_mc; //[kWe] m_W_dot_rc = m_w_rc * m_m_dot_rc; //[kWe] m_W_dot_t = m_w_t * m_m_dot_t; //[kWe] m_W_dot_net_last = m_W_dot_mc + m_W_dot_rc + m_W_dot_t; - m_Q_dot_pc = m_m_dot_mc * (m_enth_last[LTR_LP_OUT] - m_enth_last[MC_IN]); + // Air Cooler (heat rejection unit) + m_W_dot_air_cooler = m_frac_fan_power * m_W_dot_net; + m_Q_dot_air_cooler = m_m_dot_mc * (m_enth_last[LTR_LP_OUT] - m_enth_last[MC_IN]); + + // Total Heat Entering sco2 + m_Q_dot_total = m_W_dot_net_last + m_Q_dot_air_cooler; - m_Q_dot_total = m_W_dot_net_last + m_Q_dot_pc; + // LTR + m_Q_dot_LTR_LP = m_m_dot_t * (m_enth_last[HTR_LP_OUT] - m_enth_last[LTR_LP_OUT]); + m_Q_dot_LTR_HP = m_m_dot_mc * (m_enth_last[LTR_HP_OUT] - m_enth_last[MC_OUT]); + + // LTR + m_Q_dot_HTR_LP = m_m_dot_t * (m_enth_last[TURB_OUT] - m_enth_last[HTR_LP_OUT]); + m_Q_dot_HTR_HP = m_m_dot_htr_hp * (m_enth_last[HTR_HP_OUT] - m_enth_last[MIXER_OUT]); } // Calculate Bypass Energy @@ -919,7 +936,7 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) double bp_temp_in = m_temp_last[MIXER_OUT]; double bp_temp_out = m_temp_last[BYPASS_OUT]; - double real_q_dot_total = m_W_dot_t + m_Q_dot_pc; + double real_q_dot_total = m_W_dot_t + m_Q_dot_air_cooler; double qSum = m_Q_dot_total; double qSum_calc = m_Q_dot_BP + m_Q_dot_PHX; @@ -958,6 +975,8 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) PHX_des_par.m_Q_dot_design = m_m_dot_t * (m_enth_last[TURB_IN] - m_enth_last[MIXER2_OUT]); m_PHX.initialize(PHX_des_par); + + // BPX C_HeatExchanger::S_design_parameters BPX_des_par; BPX_des_par.m_DP_design[0] = m_pres_last[MIXER_OUT] - m_pres_last[BYPASS_OUT]; @@ -983,7 +1002,7 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) s_air_cooler_des_par_dep.m_delta_P_des = cooler_deltaP; //[kPa] s_air_cooler_des_par_dep.m_T_hot_out_des = m_temp_last[C_sco2_cycle_core::MC_IN]; //[K] - s_air_cooler_des_par_dep.m_W_dot_fan_des = m_frac_fan_power * m_W_dot_net / 1000.0; //[MWe] + s_air_cooler_des_par_dep.m_W_dot_fan_des = m_W_dot_air_cooler / 1000.0; //[MWe] // Structure for design parameters that are independent of cycle design solution C_CO2_to_air_cooler::S_des_par_ind s_air_cooler_des_par_ind; s_air_cooler_des_par_ind.m_T_amb_des = m_T_amb_des; //[K] @@ -1017,6 +1036,13 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } } + + // DEBUG + // Define full HX classes + { + + } + } @@ -1251,24 +1277,44 @@ std::string C_HTRBypass_Cycle::make_result_csv_string() value_vec.push_back(this->m_T_HTF_BP_outlet_target); value_vec.push_back(this->m_T_HTF_BP_outlet_calc); value_vec.push_back(this->m_T_HTF_PHX_inlet - this->m_T_HTF_BP_outlet_calc); + value_vec.push_back(this->m_T_HTF_PHX_out); value_vec.push_back(this->m_m_dot_HTF); + + value_vec.push_back(this->m_eta_thermal_calc_last); + value_vec.push_back(this->m_objective_metric_opt); + value_vec.push_back(this->m_objective_metric_bypass_frac_opt); + value_vec.push_back(this->m_bp_frac); value_vec.push_back(this->ms_des_par.m_recomp_frac); - value_vec.push_back(this->m_eta_thermal_calc_last); - value_vec.push_back(this->m_pres_last[MC_IN]); - value_vec.push_back(this->m_pres_last[MC_OUT]); + double LTR_frac = this->mc_LT_recup.ms_des_solved.m_UA_calc_at_eff_max / + (this->mc_LT_recup.ms_des_solved.m_UA_calc_at_eff_max + this->mc_HT_recup.ms_des_solved.m_UA_calc_at_eff_max); + value_vec.push_back(LTR_frac); value_vec.push_back(this->mc_LT_recup.ms_des_solved.m_UA_calc_at_eff_max); value_vec.push_back(this->mc_HT_recup.ms_des_solved.m_UA_calc_at_eff_max); - value_vec.push_back(this->m_T_HTF_PHX_out); + value_vec.push_back(this->m_pres_last[MC_IN]); + value_vec.push_back(this->m_pres_last[MC_OUT]); + + value_vec.push_back(this->m_W_dot_t); + value_vec.push_back(this->m_W_dot_mc); + value_vec.push_back(this->m_W_dot_rc); + value_vec.push_back(this->m_W_dot_air_cooler); value_vec.push_back(this->m_Q_dot_total); - value_vec.push_back(this->m_Q_dot_BP); value_vec.push_back(this->m_Q_dot_PHX); + value_vec.push_back(this->m_Q_dot_BP); + value_vec.push_back(this->m_Q_dot_air_cooler); + value_vec.push_back(this->m_Q_dot_LTR_HP); + value_vec.push_back(this->m_Q_dot_LTR_LP); + value_vec.push_back(this->m_Q_dot_HTR_HP); + value_vec.push_back(this->m_Q_dot_HTR_LP); + value_vec.push_back(this->m_m_dot_t); + value_vec.push_back(this->m_m_dot_mc); + value_vec.push_back(this->m_m_dot_rc); value_vec.push_back(this->m_m_dot_bp); value_vec.push_back(this->m_m_dot_htr_hp); - value_vec.push_back(this->m_m_dot_rc); - value_vec.push_back(this->m_m_dot_mc); - value_vec.push_back(this->m_objective_metric_opt); + + + // Write to string for (double val : value_vec) diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 397d5d2bea..79f246bfd2 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -239,6 +239,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_w_mc; // kJ/kg double m_w_rc; // kJ/kg double m_Q_dot_LT, m_Q_dot_HT; + double m_Q_dot_LTR_LP, m_Q_dot_LTR_HP, m_Q_dot_HTR_LP, m_Q_dot_HTR_HP; double m_bp_frac; double m_m_dot_bp; double m_m_dot_htr_hp; @@ -251,12 +252,13 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_T_HTF_PHX_out; double m_dT_BP; // BYPASS_OUT - HTR_HP_OUT double m_Q_dot_total; - double m_Q_dot_pc; // pre cooler heat rejected double m_HTF_BP_cold_approach; double m_HTF_PHX_cold_approach; bool is_htf_set = false; + double m_W_dot_air_cooler; + double m_Q_dot_air_cooler; - C_HX_co2_to_co2_CRM m_BP_HTX; + // New opt bool m_found_opt; From 410f2b83bf99b901c69030871a75536ce7881656 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Wed, 19 Jul 2023 10:41:53 -0600 Subject: [PATCH 16/94] Add variables to debug output string --- tcs/sco2_htrbypass_cycle.cpp | 29 +++++++++++++++++------------ tcs/sco2_htrbypass_cycle.h | 3 ++- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 826a66a432..37ead89c93 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -1036,13 +1036,6 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } } - - // DEBUG - // Define full HX classes - { - - } - } @@ -1276,13 +1269,16 @@ std::string C_HTRBypass_Cycle::make_result_csv_string() value_vec.push_back(this->m_T_HTF_BP_outlet_target); value_vec.push_back(this->m_T_HTF_BP_outlet_calc); + value_vec.push_back(this->m_T_HTF_PHX_inlet); value_vec.push_back(this->m_T_HTF_PHX_inlet - this->m_T_HTF_BP_outlet_calc); value_vec.push_back(this->m_T_HTF_PHX_out); value_vec.push_back(this->m_m_dot_HTF); + value_vec.push_back(std::numeric_limits::quiet_NaN()); value_vec.push_back(this->m_eta_thermal_calc_last); value_vec.push_back(this->m_objective_metric_opt); value_vec.push_back(this->m_objective_metric_bypass_frac_opt); + value_vec.push_back(std::numeric_limits::quiet_NaN()); value_vec.push_back(this->m_bp_frac); value_vec.push_back(this->ms_des_par.m_recomp_frac); @@ -1293,6 +1289,7 @@ std::string C_HTRBypass_Cycle::make_result_csv_string() value_vec.push_back(this->mc_HT_recup.ms_des_solved.m_UA_calc_at_eff_max); value_vec.push_back(this->m_pres_last[MC_IN]); value_vec.push_back(this->m_pres_last[MC_OUT]); + value_vec.push_back(std::numeric_limits::quiet_NaN()); value_vec.push_back(this->m_W_dot_t); value_vec.push_back(this->m_W_dot_mc); @@ -1306,27 +1303,36 @@ std::string C_HTRBypass_Cycle::make_result_csv_string() value_vec.push_back(this->m_Q_dot_LTR_LP); value_vec.push_back(this->m_Q_dot_HTR_HP); value_vec.push_back(this->m_Q_dot_HTR_LP); + value_vec.push_back(std::numeric_limits::quiet_NaN()); value_vec.push_back(this->m_m_dot_t); value_vec.push_back(this->m_m_dot_mc); value_vec.push_back(this->m_m_dot_rc); value_vec.push_back(this->m_m_dot_bp); value_vec.push_back(this->m_m_dot_htr_hp); - - + value_vec.push_back(std::numeric_limits::quiet_NaN()); + + value_vec.push_back(this->mc_LT_recup.ms_des_solved.m_UA_calc_at_eff_max); + value_vec.push_back(this->mc_LT_recup.ms_des_solved.m_min_DT_design); + value_vec.push_back(this->mc_LT_recup.ms_des_solved.m_eff_design); + value_vec.push_back(this->mc_HT_recup.ms_des_solved.m_UA_calc_at_eff_max); + value_vec.push_back(this->mc_HT_recup.ms_des_solved.m_min_DT_design); + value_vec.push_back(this->mc_HT_recup.ms_des_solved.m_eff_design); + // Write to string for (double val : value_vec) { - value_string.append(std::to_string(val)); + if(std::isnan(val) != true) + value_string.append(std::to_string(val)); + value_string.append("\n"); } // Write Temperatures value_string.append("\n"); - value_string.append("\n"); for (double val : this->m_temp_last) { value_string.append(std::to_string(val)); @@ -1335,7 +1341,6 @@ std::string C_HTRBypass_Cycle::make_result_csv_string() // Write Pressures value_string.append("\n"); - value_string.append("\n"); for (double val : this->m_pres_last) { value_string.append(std::to_string(val)); diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 79f246bfd2..c16512c829 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -257,7 +257,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core bool is_htf_set = false; double m_W_dot_air_cooler; double m_Q_dot_air_cooler; - + C_HX_co2_to_htf c_phx; + C_HX_co2_to_htf c_bp; // Bypass Heat Exchanger // New opt From 30a9907ccee8a3053d9dfa00089e29b3bfc339bd Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Thu, 20 Jul 2023 10:50:28 -0600 Subject: [PATCH 17/94] Add bypass fraction to cmod. Add htr bypass outputs to cmod. --- ssc/csp_common.cpp | 66 ++++- tcs/sco2_cycle_templates.h | 3 +- tcs/sco2_htrbypass_cycle.cpp | 553 +++++------------------------------ tcs/sco2_htrbypass_cycle.h | 26 +- tcs/sco2_pc_csp_int.cpp | 3 +- tcs/sco2_pc_csp_int.h | 3 +- 6 files changed, 142 insertions(+), 512 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index fb6cd16a4f..22d59496a5 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -779,11 +779,12 @@ var_info vtab_sco2_design[] = { { SSC_INPUT, SSC_NUMBER, "HTR_n_sub_hx", "HTR number of model subsections", "-", "High temperature recuperator", "Heat Exchanger Design", "?=10", "", "" }, { SSC_INPUT, SSC_NUMBER, "HTR_od_model", "0: mass flow scale, 1: conductance ratio model", "-", "High temperature recuperator", "Heat Exchanger Design", "?=1", "", "" }, - { SSC_INPUT, SSC_NUMBER, "cycle_config", "1 = recompression, 2 = partial cooling", "", "High temperature recuperator", "Heat Exchanger Design", "?=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "cycle_config", "1 = recompression, 2 = partial cooling, 3 = recomp with htr bypass", "", "High temperature recuperator", "Heat Exchanger Design", "?=1", "", "" }, { SSC_INPUT, SSC_NUMBER, "is_recomp_ok", "1 = Yes, 0 = simple cycle only, < 0 = fix f_recomp to abs(input)","", "High temperature recuperator", "Heat Exchanger Design", "?=1", "", "" }, { SSC_INPUT, SSC_NUMBER, "is_P_high_fixed", "1 = Yes (=P_high_limit), 0 = No, optimized (default)", "", "High temperature recuperator", "Heat Exchanger Design", "?=0", "", "" }, { SSC_INPUT, SSC_NUMBER, "is_PR_fixed", "0 = No, >0 = fixed pressure ratio at input <0 = fixed LP at abs(input)", "High temperature recuperator", "", "Heat Exchanger Design", "?=0", "", "" }, { SSC_INPUT, SSC_NUMBER, "is_IP_fixed", "partial cooling config: 0 = No, >0 = fixed HP-IP pressure ratio at input, <0 = fixed IP at abs(input)","","High temperature recuperator","Heat Exchanger Design","?=0", "", "" }, + { SSC_INPUT, SSC_NUMBER, "is_bypass_ok", "1 = Yes, 0 = No Bypass, < 0 = fix bp_frac to abs(input)","", "High temperature recuperator", "Heat Exchanger Design", "?=1", "", "" }, { SSC_INPUT, SSC_NUMBER, "des_objective", "[2] = hit min phx deltat then max eta, [else] max eta", "", "High temperature recuperator", "Heat Exchanger Design", "?=0", "", "" }, { SSC_INPUT, SSC_NUMBER, "min_phx_deltaT", "Minimum design temperature difference across PHX", "C", "High temperature recuperator", "Heat Exchanger Design", "?=0", "", "" }, @@ -816,7 +817,8 @@ var_info vtab_sco2_design[] = { { SSC_INPUT, SSC_NUMBER, "T_htf_bypass_out", "HTF design Bypass Outlet Temperature", "C", "", "System Design", "cycle_config=3", "", "" }, { SSC_INPUT, SSC_NUMBER, "deltaT_bypass", "sco2 Bypass Outlet Temp - HTR_HP_OUT Temp", "C", "", "System Design", "cycle_config=3", "", "" }, - + // DEBUG + //{ SSC_OUTPUT, SSC_STRING, "debug_string", "output string used for debug", "C", "", "System Design", "cycle_config=3", "", "" }, // ** Design OUTPUTS ** // System Design Solution @@ -825,11 +827,13 @@ var_info vtab_sco2_design[] = { { SSC_OUTPUT, SSC_NUMBER, "eta_thermal_calc", "Calculated cycle thermal efficiency", "-", "System Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "m_dot_co2_full", "CO2 mass flow rate through HTR, PHX, turbine", "kg/s", "System Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "recomp_frac", "Recompression fraction", "-", "System Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "cycle_cost", "Cycle cost bare erected", "M$", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "bypass_frac", "Bypass fraction", "-", "System Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cycle_cost", "Cycle cost bare erected", "M$", "System Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "cycle_spec_cost", "Cycle specific cost bare erected", "$/kWe", "System Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "cycle_spec_cost_thermal", "Cycle specific (thermal) cost bare erected", "$/kWt", "System Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "W_dot_net_less_cooling", "System power output subtracting cooling parastics", "MWe," "System Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "eta_thermal_net_less_cooling_des","Calculated cycle thermal efficiency using W_dot_net_less_cooling", "-", "System Design Solution","", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_htf_bp_out_des", "HTF design cold temperature (PHX outlet)", "C", "System Design Solution", "", "cycle_config=3", "", "" }, // Compressor { SSC_OUTPUT, SSC_NUMBER, "T_comp_in", "Compressor inlet temperature", "C", "Compressor", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "P_comp_in", "Compressor inlet pressure", "MPa", "Compressor", "", "*", "", "" }, @@ -943,7 +947,20 @@ var_info vtab_sco2_design[] = { { SSC_OUTPUT, SSC_NUMBER, "PHX_cost_equipment", "PHX cost equipment", "M$", "PHX Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "PHX_cost_bare_erected","PHX cost equipment and install", "M$", "PHX Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "PHX_min_dT", "PHX min temperature difference", "C", "PHX Design Solution", "", "*", "", "" }, - // main compressor cooler + // BPX Design Solution + { SSC_OUTPUT, SSC_NUMBER, "UA_BPX", "BPX Conductance", "MW/K", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "eff_BPX", "BPX effectiveness", "", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "NTU_BPX", "BPX NTU", "", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_co2_BPX_in", "CO2 temperature at BPX inlet", "C", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "P_co2_BPX_in", "CO2 pressure at BPX inlet", "MPa", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "deltaT_HTF_BPX", "HTF temp difference across BPX", "C", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "q_dot_BPX", "BPX heat transfer", "MWt", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_co2_deltaP_des", "BPX co2 side design pressure drop", "-", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_cost_equipment", "BPX cost equipment", "M$", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_cost_bare_erected","BPX cost equipment and install", "M$", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_min_dT", "BPX min temperature difference", "C", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_m_dot", "BPX sco2 mass flow rate", "kg/s", "BPX Design Solution", "", "cycle_config=3", "", "" }, + // main compressor cooler { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_T_in", "Low pressure cross flow cooler inlet temperature", "C", "Low Pressure Cooler", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_P_in", "Low pressure cross flow cooler inlet pressure", "MPa", "Low Pressure Cooler", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_rho_in", "Low pressure cross flow cooler inlet density", "kg/m3", "Low Pressure Cooler", "", "*", "", "" }, @@ -1069,6 +1086,7 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c } s_sco2_des_par.m_is_recomp_ok = cm->as_double("is_recomp_ok"); + s_sco2_des_par.m_is_bypass_ok = cm->as_double("is_bypass_ok"); s_sco2_des_par.m_P_high_limit = cm->as_double("P_high_limit")*1000.0; //[kPa], convert from MPa s_sco2_des_par.m_fixed_P_mc_out = cm->as_integer("is_P_high_fixed"); //[-] @@ -1264,6 +1282,13 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c throw exec_error("sco2_csp_system", csp_exception.m_error_message); } + //// DEBUG + //{ + // cm->assign("debug_string", var_data("test")); + //} + + + // If all calls were successful, log to SSC any messages from sco2_recomp_csp while (c_sco2_cycle.mc_messages.get_message(&out_type, &out_msg)) { @@ -1272,7 +1297,7 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c // Helpful to know right away whether cycle contains recompressor bool is_rc = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_is_rc; - + // Get data for P-h cycle plot std::vector P_t; //[MPa] std::vector h_t; //[kJ/kg] @@ -1441,13 +1466,15 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c double comp_power_sum = 0.0; //[MWe] double m_dot_htf_design = c_sco2_cycle.get_phx_des_par()->m_m_dot_hot_des; //[kg/s] double T_htf_cold_calc = c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_T_h_out; //[K] + double T_htf_bypass_out = c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_T_h_out; //[K] cm->assign("T_htf_cold_des", (ssc_number_t)(T_htf_cold_calc - 273.15)); //[C] convert from K cm->assign("m_dot_htf_des", (ssc_number_t)m_dot_htf_design); //[kg/s] cm->assign("eta_thermal_calc", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_eta_thermal); //[-] cm->assign("m_dot_co2_full", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_t); //[kg/s] cm->assign("recomp_frac", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_recomp_frac); //[-] - // Compressor - cm->assign("T_comp_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::MC_IN] - 273.15)); //[C] convert from K + cm->assign("T_htf_bp_out_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_T_h_out); + // Compressor + cm->assign("T_comp_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::MC_IN] - 273.15)); //[C] convert from K cm->assign("P_comp_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::MC_IN] / 1000.0)); //[MPa] convert from kPa cm->assign("P_comp_out", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::MC_OUT] / 1000.0)); //[MPa] convert from kPa cm->assign("mc_T_out", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::MC_OUT] - 273.15)); //[C] convert from K @@ -1715,7 +1742,30 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c cm->assign("PHX_cost_bare_erected", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_cost_bare_erected); //[M$] cost_equip_sum += c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_cost_equipment; //[M$] cost_bare_erected_sum += c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_cost_bare_erected; //[M$]; - // Low Pressure Cooler + // BPX + if (s_sco2_des_par.m_cycle_config == 3) + { + cm->assign("bypass_frac", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_bypass_frac); + cm->assign("UA_BPX", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_UA_design * 1.E-3)); //[MW/K] convert from kW/K + cm->assign("eff_BPX", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_eff_design); //[-] + cm->assign("NTU_BPX", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_NTU_design); //[-] + cm->assign("T_co2_BPX_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::MIXER_OUT] - 273.15)); //[C] + cm->assign("P_co2_BPX_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::MIXER_OUT] * 1.E-3)); //[MPa] convert from kPa + cm->assign("deltaT_HTF_BPX", (ssc_number_t)(T_htf_cold_calc - T_htf_bypass_out)); //[K] + cm->assign("q_dot_BPX", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_Q_dot_design * 1.E-3)); //[MWt] convert from kWt + cm->assign("BPX_min_dT", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_min_DT_design)); //[C/K] + double PHX_deltaP_frac = 1.0 - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::BYPASS_OUT] / + c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::MIXER_OUT]; //[-] Fractional pressure drop through co2 side of PHX + cm->assign("BPX_co2_deltaP_des", (ssc_number_t)PHX_deltaP_frac); + cm->assign("BPX_cost_equipment", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_cost_equipment); //[M$] + cm->assign("BPX_cost_bare_erected", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_cost_bare_erected); //[M$] + cm->assign("BPX_m_dot", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_bypass_frac * + c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_t)); + cost_equip_sum += c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_cost_equipment; //[M$] + cost_bare_erected_sum += c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_cost_bare_erected; //[M$]; + } + + // Low Pressure Cooler cm->assign("mc_cooler_T_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_air_cooler.m_T_in_co2 - 273.15)); //[C] cm->assign("mc_cooler_P_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_air_cooler.m_P_in_co2 / 1.E3)); //[MPa] cm->assign("mc_cooler_rho_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_dens[C_sco2_cycle_core::LTR_LP_OUT])); //[kg/m3] diff --git a/tcs/sco2_cycle_templates.h b/tcs/sco2_cycle_templates.h index d8c77e70cd..88cf9d35f8 100644 --- a/tcs/sco2_cycle_templates.h +++ b/tcs/sco2_cycle_templates.h @@ -75,7 +75,7 @@ class C_sco2_cycle_core double m_W_dot_rc; //[kWe] double m_W_dot_pc; //[kWe] double m_W_dot_t; //[kWe] - double m_bp_frac; //[-] Bypass Fraction + double m_bypass_frac; //[-] Bypass Fraction double m_W_dot_cooler_tot; //[kWe] @@ -210,6 +210,7 @@ class C_sco2_cycle_core bool m_is_des_air_cooler; //[-] False will skip physical air cooler design. UA will not be available for cost models. double m_is_recomp_ok; //[-] 1 = Yes, 0 = simple cycle only, < 0 = fix f_recomp to abs(input) + double m_is_bypass_ok; //[-] 1 = Yes, 0 = no bypass, < 0 = fix bp_frac to abs(input) bool m_fixed_P_mc_out; //[-] if true, P_mc_out is fixed at 'm_P_high_limit' diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 37ead89c93..2559cc1a28 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -42,347 +42,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. void C_HTRBypass_Cycle::design_core(int& error_code) { - // DEBUG - if (false) - { - std::vector bp_vec = { 0.999 }; - for (double bp : bp_vec) - { - m_bp_frac = bp; - design_core_standard(error_code); - - std::string output = make_result_csv_string(); - - int o = 0; - } - } - - // DEBUG - if (false) - { - ms_des_par.m_recomp_frac = 0; - m_bp_frac = 0.5; - - int temp_error = 0; - design_core_standard(temp_error); - } - - // DEBUG sco2 flex - if (false) - { - m_bp_frac = 0.11; - m_cp_HTF = 1.5375; - - - int temp_error = 0; - design_core_standard(temp_error); - - std::string output = make_result_csv_string(); - - int o = 0; - - // Calculate Recuperator Balances - { - // HTR - double Q_htr_lp; - double Q_htr_hp; - { - double h1_lp = m_enth_last[TURB_OUT]; - double h2_lp = m_enth_last[HTR_LP_OUT]; - double mdot_lp = m_m_dot_t; - - Q_htr_lp = mdot_lp * (h2_lp - h1_lp); - - double h1_hp = m_enth_last[MIXER_OUT]; - double h2_hp = m_enth_last[HTR_HP_OUT]; - double mdot_hp = m_m_dot_htr_hp; - - Q_htr_hp = mdot_hp * (h2_hp - h1_hp); - } - - // LTR - double Q_ltr_lp; - double Q_ltr_hp; - { - double h1_lp = m_enth_last[HTR_LP_OUT]; - double h2_lp = m_enth_last[LTR_LP_OUT]; - double mdot_lp = m_m_dot_t; - - Q_ltr_lp = mdot_lp * (h2_lp - h1_lp); - - double h1_hp = m_enth_last[MC_OUT]; - double h2_hp = m_enth_last[LTR_HP_OUT]; - double mdot_hp = m_m_dot_mc; - - Q_ltr_hp = mdot_hp * (h2_hp - h1_hp); - } - - CO2_state co2_props; - - // HTR (sco2 flex) - double Q_dot_HTR_LP_paper; - double Q_dot_HTR_HP_paper; - { - int prop_error_code = CO2_TP(481.6 + 273.15, 8.1 * 1e3, &co2_props); - double h1 = co2_props.enth; - double cp1 = co2_props.cp * 1e3; - - CO2_TP(204.4 + 273.15, 8.06 * 1e3, &co2_props); - double h2 = co2_props.enth; - double cp2 = co2_props.cp * 1e3; - - double mdot = 239; // kg/s - Q_dot_HTR_LP_paper = mdot * (h2 - h1); - - - double cp_LP = (cp1 + cp2) / 2.0; - - - - CO2_TP(194.4 + 273.15, 24.875 * 1e3, &co2_props); - double h3 = co2_props.enth; - double cp3 = co2_props.cp * 1e3; - - CO2_TP(470.6 + 273.15, 24.75 * 1e3, &co2_props); - double h4 = co2_props.enth; - double cp4 = co2_props.cp * 1e3; - - double mdot2 = 212.7; // kg/s - Q_dot_HTR_HP_paper = mdot2 * (h4 - h3); - - double cp_HP = (cp3 + cp4) / 2.0; - - double pu = 0; - } - - - // LTR (sco2 flex) - double Q_dot_LTR_LP_paper; - double Q_dot_LTR_HP_paper; - { - int prop_error_code = CO2_TP(204.4 + 273.15, 8.06 * 1e3, &co2_props); - double h1 = co2_props.enth; - double cp1 = co2_props.cp * 1e3; - - CO2_TP(80 + 273.15, 8.019 * 1e3, &co2_props); - double h2 = co2_props.enth; - double cp2 = co2_props.cp * 1e3; - - double mdot = 239; // kg/s - Q_dot_LTR_LP_paper = mdot * (h2 - h1); - - double cp_LP = (cp1 + cp2) / 2.0; - - - CO2_TP(69.9 + 273.15, 25 * 1e3, &co2_props); - double h3 = co2_props.enth; - double cp3 = co2_props.cp * 1e3; - - CO2_TP(194.3 + 273.15, 24.875 * 1e3, &co2_props); - double h4 = co2_props.enth; - double cp4 = co2_props.cp * 1e3; - - double mdot2 = 153.7; // kg/s - Q_dot_LTR_HP_paper = mdot2 * (h4 - h3); - - - double cp_HP = (cp3 + cp4) / 2.0; - - - double pu = 0; - } - - int pox = 0; - } - - return; - } - - // DEBUG Alfani 2019 - if (false) - { - m_bp_frac = 0.17386; - m_cp_HTF = 1.15; - - - int temp_error = 0; - design_core_standard(temp_error); - - std::string output = make_result_csv_string(); - - int o = 0; - - return; - } - - // DEBUG Alfani 2020 - if (true) - { - m_bp_frac = 0.114; - - int temp_error = 0; - design_core_standard(temp_error); - - std::string output = make_result_csv_string(); - - int o = 0; - - // Calculate Recuperator Balances - { - // HTR - double Q_htr_lp; - double Q_htr_hp; - { - double h1_lp = m_enth_last[TURB_OUT]; - double h2_lp = m_enth_last[HTR_LP_OUT]; - double mdot_lp = m_m_dot_t; - - Q_htr_lp = mdot_lp * (h2_lp - h1_lp); - - double h1_hp = m_enth_last[MIXER_OUT]; - double h2_hp = m_enth_last[HTR_HP_OUT]; - double mdot_hp = m_m_dot_htr_hp; - - Q_htr_hp = mdot_hp * (h2_hp - h1_hp); - } - - // LTR - double Q_ltr_lp; - double Q_ltr_hp; - { - double h1_lp = m_enth_last[HTR_LP_OUT]; - double h2_lp = m_enth_last[LTR_LP_OUT]; - double mdot_lp = m_m_dot_t; - - Q_ltr_lp = mdot_lp * (h2_lp - h1_lp); - - double h1_hp = m_enth_last[MC_OUT]; - double h2_hp = m_enth_last[LTR_HP_OUT]; - double mdot_hp = m_m_dot_mc; - - Q_ltr_hp = mdot_hp * (h2_hp - h1_hp); - } - - CO2_state co2_props; - - // HTR (sco2 flex) - double Q_dot_HTR_LP_paper; - double Q_dot_HTR_HP_paper; - { - double T1_C = 485.27; - double T2_C = 198.72; - double T3_C = 188.72; - double T4_C = 475.27; - - double P1_C = 8.422; - double P2_C = 8.380; - double P3_C = 24.995; - double P4_C = 24.984; - - double mdot_lp = 1041.54; - double mdot_hp = 1041.54 * (1.0 - 0.114); - - - - int prop_error_code = CO2_TP(T1_C + 273.15, P1_C * 1e3, &co2_props); - double h1 = co2_props.enth; - - CO2_TP(T2_C + 273.15, P2_C * 1e3, &co2_props); - double h2 = co2_props.enth; - - - Q_dot_HTR_LP_paper = mdot_lp * (h2 - h1); - - - - CO2_TP(T3_C + 273.15, P3_C * 1e3, &co2_props); - double h3 = co2_props.enth; - - CO2_TP(T4_C + 273.15, P4_C * 1e3, &co2_props); - double h4 = co2_props.enth; - - - Q_dot_HTR_HP_paper = mdot_hp * (h4 - h3); - - - - double pu = 0; - } - - - // LTR (sco2 flex) - double Q_dot_LTR_LP_paper; - double Q_dot_LTR_HP_paper; - { - double T1_C = 198.72; - double T2_C = 76.01; - double T3_C = 65.91; - double T4_C = 188.72; - - double P1_C = 8.380; - double P2_C = 8.338; - double P3_C = 25; - double P4_C = 24.995; - - double mdot_lp = 1041.54; - double mdot_hp = 677.31; - - - - int prop_error_code = CO2_TP(T1_C + 273.15, P1_C * 1e3, &co2_props); - double h1 = co2_props.enth; - - CO2_TP(T2_C + 273.15, P2_C * 1e3, &co2_props); - double h2 = co2_props.enth; - - - Q_dot_LTR_LP_paper = mdot_lp * (h2 - h1); - - - - CO2_TP(T3_C + 273.15, P3_C * 1e3, &co2_props); - double h3 = co2_props.enth; - - CO2_TP(T4_C + 273.15, P4_C * 1e3, &co2_props); - double h4 = co2_props.enth; - - - Q_dot_LTR_HP_paper = mdot_hp * (h4 - h3); - - - - double pu = 0; - } - - int pox = 0; - } - - // Calculate Paper Heat Exchange - { - - } - - return; - } - - // DEBUG Alfani 2020 Various BP - if (false) - { - std::vector bp_vec = { 0,0.05,0.1,0.15,0.2,0.25,0.3,0.35,0.4,0.45,0.5,0.55,0.6,0.65,0.7,0.75,0.8,0.85,0.9,0.95,0.999}; - - for (double bp : bp_vec) - { - m_bp_frac = bp; - - int temp_error = 0; - design_core_standard(temp_error); - - std::string output = make_result_csv_string(); - - int asdf = 0; - } - - } + //// DEBUG sco2 flex + //if (false) + //{ + // m_cp_HTF = 1.5375; + // + // // LTR (sco2 flex) + // double Q_dot_LTR_LP_paper; + // double Q_dot_LTR_HP_paper; + // { + // double T1_C = 198.72; + // double T2_C = 76.01; + // double T3_C = 65.91; + // double T4_C = 188.72; + // double P1_C = 8.380; + // double P2_C = 8.338; + // double P3_C = 25; + // double P4_C = 24.995; + // double mdot_lp = 1041.54; + // double mdot_hp = 677.31; + // int prop_error_code = CO2_TP(T1_C + 273.15, P1_C * 1e3, &co2_props); + // double h1 = co2_props.enth; + // CO2_TP(T2_C + 273.15, P2_C * 1e3, &co2_props); + // double h2 = co2_props.enth; + // Q_dot_LTR_LP_paper = mdot_lp * (h2 - h1); + // CO2_TP(T3_C + 273.15, P3_C * 1e3, &co2_props); + // double h3 = co2_props.enth; + // CO2_TP(T4_C + 273.15, P4_C * 1e3, &co2_props); + // double h4 = co2_props.enth; + // Q_dot_LTR_HP_paper = mdot_hp * (h4 - h3); + // double pu = 0; + // } // Check if HTF parameters were set if (is_htf_set == false) @@ -391,50 +81,13 @@ void C_HTRBypass_Cycle::design_core(int& error_code) return; } - - - //DEBUG - if (false) + // Full Optization (not monotonic) + if (ms_opt_des_par.m_fixed_bypass_frac == true) { - int temp_error = 0; - - std::vector bp_frac_vec; - std::vector calc_outlet_temp; - std::vector outlet_err; - std::vector eff_vec; - std::vector obj_vec; - std::vector sig_vec; - std::vector log_vec; - - for (double bp = 0.001; bp < 0.99; bp += 0.01) - { - m_objective_metric_bypass_frac_opt = -1000000000000000000; - - design_bypass_frac_return_objective_metric({ bp }); - - double err = m_T_HTF_BP_outlet_calc - m_T_HTF_BP_outlet_target; - double span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; - double percent_err = std::abs(err) / span; - double sig = sigmoid(percent_err); - double log = logit(percent_err); - - bp_frac_vec.push_back(bp); - calc_outlet_temp.push_back(m_T_HTF_BP_outlet_calc); - outlet_err.push_back(m_T_HTF_BP_outlet_calc - m_T_HTF_BP_outlet_target); - eff_vec.push_back(m_eta_thermal_calc_last); - obj_vec.push_back(m_objective_metric_bypass_frac_opt); - sig_vec.push_back(sig); - log_vec.push_back(log); - - } - - int x = 0; - + ms_des_par.m_bypass_frac = ms_opt_des_par.m_bypass_frac_guess; + design_core_standard(error_code); } - - - // Try Full Optization (not monotonic) - if (true) + else { m_objective_metric_bypass_frac_opt = -10000000; @@ -456,9 +109,7 @@ void C_HTRBypass_Cycle::design_core(int& error_code) double max_f = std::numeric_limits::quiet_NaN(); nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); - - - m_bp_frac = x[0]; + ms_des_par.m_bypass_frac = x[0]; design_core_standard(error_code); std::string s = make_result_csv_string(); @@ -466,50 +117,6 @@ void C_HTRBypass_Cycle::design_core(int& error_code) int yx = 0; } - // Monotonic Solver - if(false) - { - C_mono_htr_bypass_BP_des BP_des_eq(this); - C_monotonic_eq_solver BP_des_solver(BP_des_eq); - double BP_out_lower = 0; - double BP_out_upper = 0.99; - - double BP_out_guess_lower = 0; //[K] - double BP_out_guess_upper = 0.99; //[K] - - BP_des_solver.settings(ms_des_par.m_des_tol, 1000, BP_out_lower, BP_out_upper, false); - - double BP_out_solved, tol_BP_out_solved; - BP_out_solved = tol_BP_out_solved = std::numeric_limits::quiet_NaN(); - int iter_BP_out = -1; - - int BP_out_code = BP_des_solver.solve(BP_out_guess_lower, BP_out_guess_upper, 0, BP_out_solved, tol_BP_out_solved, iter_BP_out); - - if (BP_out_code == C_monotonic_eq_solver::NO_SOLUTION) - { - // Did not converge - error_code = 35; - return; - } - - // Modify objective function to account for hitting the target HTF outlet temperature - { - double target_bp_out = m_T_HTF_BP_outlet_target; - double calc_bp_out = m_T_HTF_BP_outlet_calc; - - double temp_err = std::abs(calc_bp_out - target_bp_out); - double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; - double percent_err = temp_err / temp_span; - - double penalty = 3 * std::pow(percent_err, 2.0); - - m_objective_metric_last -= penalty; - int x = 0; - - } - } - - } void C_HTRBypass_Cycle::design_core_standard(int& error_code) @@ -892,10 +499,10 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) // Simulate Mixer 2 { // If Bypass and HTR have flow - if (m_bp_frac >= 1e-12 && m_bp_frac <= (1.0 - 1e-12)) + if (ms_des_par.m_bypass_frac >= 1e-12 && ms_des_par.m_bypass_frac <= (1.0 - 1e-12)) { - m_enth_last[MIXER2_OUT] = (1.0 - m_bp_frac) * m_enth_last[HTR_HP_OUT] + - m_bp_frac * m_enth_last[BYPASS_OUT]; //[kJ/kg] + m_enth_last[MIXER2_OUT] = (1.0 - ms_des_par.m_bypass_frac) * m_enth_last[HTR_HP_OUT] + + ms_des_par.m_bypass_frac * m_enth_last[BYPASS_OUT]; //[kJ/kg] int prop_error_code = CO2_PH(m_pres_last[MIXER2_OUT], m_enth_last[MIXER2_OUT], &mc_co2_props); if (prop_error_code != 0) @@ -908,7 +515,7 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } // Flow only through HTR - else if (m_bp_frac <= (1.0 - 1e-12)) + else if (ms_des_par.m_bypass_frac <= (1.0 - 1e-12)) { m_temp_last[MIXER2_OUT] = m_temp_last[HTR_HP_OUT]; //[K] m_enth_last[MIXER2_OUT] = m_enth_last[HTR_HP_OUT]; //[kJ/kg] @@ -1141,7 +748,7 @@ int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_L // Solve Mass Flow rates for HTR_HP_OUT and Bypass { - m_m_dot_bp = m_bp_frac * m_m_dot_t; + m_m_dot_bp = ms_des_par.m_bypass_frac * m_m_dot_t; m_m_dot_htr_hp = m_m_dot_t - m_m_dot_bp; } @@ -1280,7 +887,7 @@ std::string C_HTRBypass_Cycle::make_result_csv_string() value_vec.push_back(this->m_objective_metric_bypass_frac_opt); value_vec.push_back(std::numeric_limits::quiet_NaN()); - value_vec.push_back(this->m_bp_frac); + value_vec.push_back(this->ms_des_par.m_bypass_frac); value_vec.push_back(this->ms_des_par.m_recomp_frac); double LTR_frac = this->mc_LT_recup.ms_des_solved.m_UA_calc_at_eff_max / (this->mc_LT_recup.ms_des_solved.m_UA_calc_at_eff_max + this->mc_HT_recup.ms_des_solved.m_UA_calc_at_eff_max); @@ -1374,7 +981,7 @@ int C_HTRBypass_Cycle::C_mono_htr_bypass_BP_des::operator()(double bp_frac_guess { int error_code = 0; - this->m_htr_bypass_cycle->m_bp_frac = bp_frac_guess; + this->m_htr_bypass_cycle->ms_des_par.m_bypass_frac = bp_frac_guess; this->m_htr_bypass_cycle->design_core_standard(error_code); double target_bp_out = this->m_htr_bypass_cycle->m_T_HTF_BP_outlet_target; @@ -1565,6 +1172,19 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) } // map 'auto_opt_des_par_in' to 'ms_auto_opt_des_par' + + // Bypass Fraction + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) + { + ms_opt_des_par.m_fixed_bypass_frac = true; + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + } + else + { + ms_opt_des_par.m_fixed_bypass_frac = false; + } + + // LTR thermal design ms_opt_des_par.m_LTR_target_code = ms_auto_opt_des_par.m_LTR_target_code; //[-] ms_opt_des_par.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; //[kW/K] @@ -1656,6 +1276,9 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) int rc_error_code = 0; + + + opt_design_core(rc_error_code); if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) @@ -1665,39 +1288,6 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) } } - // Is recompression fraction fixed or optimized? - // If fixed, then we don't need to try simple cycle - //if (ms_auto_opt_des_par.m_is_recomp_ok == 1.0 || ms_auto_opt_des_par.m_is_recomp_ok == 0.0) - //{ - - // // Complete 'ms_opt_des_par' for simple cycle - // ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] - // ms_opt_des_par.m_fixed_P_mc_out = true; - - // if (ms_opt_des_par.m_fixed_PR_HP_to_LP) - // { - // ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] - // } - // else - // { - // ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] - // } - - // ms_opt_des_par.m_recomp_frac_guess = 0.0; - // ms_opt_des_par.m_fixed_recomp_frac = true; - // ms_opt_des_par.m_LT_frac_guess = 1.0; - // ms_opt_des_par.m_fixed_LT_frac = true; - - // int s_error_code = 0; - - // opt_design_core(s_error_code); - - // if (s_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) - // { - // ms_des_par_auto_opt = ms_des_par_optimal; - // m_objective_metric_auto_opt = m_objective_metric_opt; - // } - //} ms_des_par = ms_des_par_auto_opt; @@ -1839,7 +1429,7 @@ void C_HTRBypass_Cycle::finalize_design(int& error_code) ms_des_solved.m_m_dot_rc = m_m_dot_rc; ms_des_solved.m_m_dot_t = m_m_dot_t; ms_des_solved.m_recomp_frac = m_m_dot_rc / m_m_dot_t; - ms_des_solved.m_bp_frac = m_bp_frac; + ms_des_solved.m_bypass_frac = ms_des_par.m_bypass_frac; ms_des_solved.m_UA_LTR = ms_des_par.m_LTR_UA; ms_des_solved.m_UA_HTR = ms_des_par.m_HTR_UA; @@ -2003,15 +1593,20 @@ double C_HTRBypass_Cycle::design_cycle_return_objective_metric(const std::vector { double eff = m_eta_thermal_calc_last; - double target_bp_out = m_T_HTF_BP_outlet_target; - double calc_bp_out = m_T_HTF_BP_outlet_calc; - - double temp_err = std::abs(calc_bp_out - target_bp_out); - double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; - double percent_err = temp_err / temp_span; + // If fixed bypass fraction, no penalty function + double penalty = 0; + if (ms_opt_des_par.m_fixed_bypass_frac == false) + { + double target_bp_out = m_T_HTF_BP_outlet_target; + double calc_bp_out = m_T_HTF_BP_outlet_calc; - double penalty = 10.0 * (sigmoid(percent_err) - 0.5); + double temp_err = std::abs(calc_bp_out - target_bp_out); + double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; + double percent_err = temp_err / temp_span; + penalty = 10.0 * (sigmoid(percent_err) - 0.5); + } + objective_metric = eff - penalty; if (objective_metric > m_objective_metric_opt) @@ -2027,7 +1622,7 @@ double C_HTRBypass_Cycle::design_cycle_return_objective_metric(const std::vector // X is single bypass fraction value double C_HTRBypass_Cycle::design_bypass_frac_return_objective_metric(const std::vector& x) { - m_bp_frac = x[0]; + ms_des_par.m_bypass_frac = x[0]; int error_code = 0; diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index c16512c829..d4f20af668 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -49,29 +49,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core { public: - //enum E_htrbypass_cycle_state_points - //{ - // // index values for c++ 0-based vectors for temperature, pressure, etc. - // MC_IN = 0, // Main compressor inlet - // MC_OUT, // Main compressor outlet - // LTR_HP_OUT, // Low temp recuperator high pressure outlet - // MIXER_OUT, // Mixer: LTR_HP_OUT + Recompressor outlet - // HTR_HP_OUT, // High temp recuperator high pressure outlet - // TURB_IN, // Turbine inlet - // TURB_OUT, // Turbine outlet - // HTR_LP_OUT, // High temp recuperator low pressure outlet - // LTR_LP_OUT, // Low temp recuperator low pressure outlet - // RC_OUT, // Recompresor outlet - // BYPASS_OUT, - // MIXER2_OUT, - - - // END_SCO2_HTRBP_STATES - //}; - struct S_design_parameters { - // Parameters SHARED with recompression double m_P_mc_in; //[kPa] Compressor inlet pressure double m_P_mc_out; //[kPa] Compressor outlet pressure @@ -93,6 +72,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core NS_HX_counterflow_eqs::E_UA_target_type m_HTR_od_UA_target_type; double m_recomp_frac; //[-] Fraction of flow that bypasses the precooler and the main compressor at the design point + double m_bypass_frac; //[-] Fraction of flow that bypasses the HTR and passes through the Bypass HX double m_des_tol; //[-] Convergence tolerance // Air cooler parameters @@ -108,6 +88,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core m_LTR_UA = m_LTR_min_dT = m_LTR_eff_target = m_LTR_eff_max = m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = m_recomp_frac = + m_bypass_frac = m_des_tol = std::numeric_limits::quiet_NaN(); @@ -164,6 +145,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_recomp_frac_guess; //[-] Initial guess for design-point recompression fraction bool m_fixed_recomp_frac; //[-] if true, recomp_frac is fixed at recomp_frac_guess + double m_bypass_frac_guess; //[-] Initial guess for design-point bypass fraction + bool m_fixed_bypass_frac; //[-] if true, bypass_frac is fixed at bypass_frac_guess double m_LT_frac_guess; //[-] Initial guess for fraction of UA_rec_total that is in the low-temperature recuperator bool m_fixed_LT_frac; //[-] if true, LT_frac is fixed at LT_frac_guess @@ -240,7 +223,6 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_w_rc; // kJ/kg double m_Q_dot_LT, m_Q_dot_HT; double m_Q_dot_LTR_LP, m_Q_dot_LTR_HP, m_Q_dot_HTR_LP, m_Q_dot_HTR_HP; - double m_bp_frac; double m_m_dot_bp; double m_m_dot_htr_hp; double m_cp_HTF; // kJ/kg K diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index f65611da28..1ac8f2bc73 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -333,6 +333,7 @@ void C_sco2_phx_air_cooler::design_core() des_params.m_fixed_f_PR_HP_to_IP = ms_des_par.m_fixed_f_PR_HP_to_IP; //[-] des_params.m_is_recomp_ok = ms_des_par.m_is_recomp_ok; + des_params.m_is_bypass_ok = ms_des_par.m_is_bypass_ok; auto_err_code = mpc_sco2_cycle->auto_opt_design(des_params); } @@ -408,7 +409,7 @@ void C_sco2_phx_air_cooler::design_core() mc_bp.initialize(ms_des_par.m_hot_fl_code, ms_des_par.mc_hot_fl_props, bp_N_subs_hx, bp_od_UA_target_type); // Calculate BP heat transfer - double m_dot_bp_sco2 = ms_des_solved.ms_rc_cycle_solved.m_bp_frac * (ms_des_solved.ms_rc_cycle_solved.m_m_dot_t); + double m_dot_bp_sco2 = ms_des_solved.ms_rc_cycle_solved.m_bypass_frac * (ms_des_solved.ms_rc_cycle_solved.m_m_dot_t); double q_dot_des_bp = m_dot_bp_sco2 * (ms_des_solved.ms_rc_cycle_solved.m_enth[C_sco2_cycle_core::BYPASS_OUT] - ms_des_solved.ms_rc_cycle_solved.m_enth[C_sco2_cycle_core::MIXER_OUT]); diff --git a/tcs/sco2_pc_csp_int.h b/tcs/sco2_pc_csp_int.h index 82bfcadd36..8f3eb2b3e1 100644 --- a/tcs/sco2_pc_csp_int.h +++ b/tcs/sco2_pc_csp_int.h @@ -99,7 +99,8 @@ class C_sco2_phx_air_cooler double m_des_opt_tol; //[-] Optimization tolerance double m_N_turbine; //[rpm] Turbine shaft speed (negative values link turbine to compressor) double m_is_recomp_ok; //[-] 1 = Yes, 0 = simple cycle only, < 0 = fix f_recomp to abs(input) - + double m_is_bypass_ok; //[-] 1 = Yes, 0 = no bypass, < 0 = fix bp_frac to abs(input) + int m_des_objective_type; //[2] = min phx deltat then max eta, [else] max eta double m_min_phx_deltaT; //[C] From 52018613dea2920b30f745cafa945727611d3be0 Mon Sep 17 00:00:00 2001 From: taylorbrown75 Date: Mon, 24 Jul 2023 14:32:12 -0600 Subject: [PATCH 18/94] Add option to hard set HTF mass flow rate for HTR Bypass configuration. --- ssc/csp_common.cpp | 4 +++- tcs/sco2_htrbypass_cycle.cpp | 34 +++++++++++++++++++++++++--------- tcs/sco2_htrbypass_cycle.h | 4 +++- tcs/sco2_pc_csp_int.cpp | 3 ++- tcs/sco2_pc_csp_int.h | 2 +- 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 22d59496a5..3c263e99a8 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -816,6 +816,7 @@ var_info vtab_sco2_design[] = { // HTR Bypass Design { SSC_INPUT, SSC_NUMBER, "T_htf_bypass_out", "HTF design Bypass Outlet Temperature", "C", "", "System Design", "cycle_config=3", "", "" }, { SSC_INPUT, SSC_NUMBER, "deltaT_bypass", "sco2 Bypass Outlet Temp - HTR_HP_OUT Temp", "C", "", "System Design", "cycle_config=3", "", "" }, + { SSC_INPUT, SSC_NUMBER, "set_HTF_mdot", "For HTR Bypass ONLY, 0 = calculate HTF mdot (need to set dT_PHX_cold_approach), > 0 = HTF mdot kg/s", "kg/s", "", "System Design", "?=0", "", "" }, // DEBUG //{ SSC_OUTPUT, SSC_STRING, "debug_string", "output string used for debug", "C", "", "System Design", "cycle_config=3", "", "" }, @@ -1252,6 +1253,7 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c { s_sco2_des_par.m_T_htf_bypass_out = cm->as_double("T_htf_bypass_out") + 273.15; // [C] Convert to C s_sco2_des_par.m_deltaT_bypass = cm->as_double("deltaT_bypass"); // [delta C] + s_sco2_des_par.m_set_HTF_mdot = cm->as_double("set_HTF_mdot"); // [kg/s] For HTR Bypass ONLY, 0 = calculate HTF mdot (need to set dT_PHX_cold_approach), > 0 = HTF mdot // Already assigned (above) //s_sco2_des_par.m_phx_dt_cold_approach = cm->as_double("dT_PHX_cold_approach"); // [delta C] @@ -1472,7 +1474,7 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c cm->assign("eta_thermal_calc", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_eta_thermal); //[-] cm->assign("m_dot_co2_full", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_t); //[kg/s] cm->assign("recomp_frac", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_recomp_frac); //[-] - cm->assign("T_htf_bp_out_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_T_h_out); + cm->assign("T_htf_bp_out_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_T_h_out - 273.15); // [C] // Compressor cm->assign("T_comp_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::MC_IN] - 273.15)); //[C] convert from K cm->assign("P_comp_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::MC_IN] / 1000.0)); //[MPa] convert from kPa diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 2559cc1a28..e12519e2ee 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -132,7 +132,7 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) // DEBUG - if(true) + if(false) { { double Q = 15.364; // MW @@ -308,7 +308,6 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) eta_t_isen = m_eta_t; } - // Determine the outlet state and specific work for the main compressor and turbine. // Main compressor @@ -386,7 +385,6 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } } - // Solve the recuperators { C_mono_htr_bypass_HTR_des HTR_des_eq(this); @@ -553,11 +551,29 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) // HTF { - // Use HTF Bypass cold approach to calculate PHX outlet Temperature - m_T_HTF_PHX_out = m_HTF_PHX_cold_approach + m_temp_last[MIXER2_OUT]; + // Check if HTF mdot is already assigned + if (m_set_HTF_mdot > 0) + { + // Mdot is Set + m_m_dot_HTF = m_set_HTF_mdot; + + // Calculate PHX HTF Outlet Temperature + m_T_HTF_PHX_out = m_T_HTF_PHX_inlet - m_Q_dot_PHX / (m_m_dot_HTF * m_cp_HTF); - // Calculate HTF mdot - m_m_dot_HTF = m_Q_dot_PHX / ((m_T_HTF_PHX_inlet - m_T_HTF_PHX_out) * m_cp_HTF); + // Back Calculate PHX cold approach + m_HTF_PHX_cold_approach = m_T_HTF_PHX_out - m_temp_last[MIXER2_OUT]; + } + else + { + // Use HTF Bypass cold approach to calculate PHX outlet Temperature + m_T_HTF_PHX_out = m_HTF_PHX_cold_approach + m_temp_last[MIXER2_OUT]; + + // Calculate HTF mdot + m_m_dot_HTF = m_Q_dot_PHX / ((m_T_HTF_PHX_inlet - m_T_HTF_PHX_out) * m_cp_HTF); + } + + + // Calculate Bypass Out Temperature m_T_HTF_BP_outlet_calc = m_T_HTF_PHX_out - (m_Q_dot_BP / (m_m_dot_HTF * m_cp_HTF)); @@ -1447,13 +1463,14 @@ void C_HTRBypass_Cycle::finalize_design(int& error_code) // Public Methods -void C_HTRBypass_Cycle::set_htf_par(double T_htf_phx_in, double T_htf_bp_out_target, double cp_htf, double dT_bp, double htf_phx_cold_approach) +void C_HTRBypass_Cycle::set_htf_par(double T_htf_phx_in, double T_htf_bp_out_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot) { m_T_HTF_PHX_inlet = T_htf_phx_in; // K m_T_HTF_BP_outlet_target = T_htf_bp_out_target; // K m_cp_HTF = cp_htf; // kJ/kg K m_dT_BP = dT_bp; m_HTF_PHX_cold_approach = htf_phx_cold_approach; + m_set_HTF_mdot = set_HTF_mdot; is_htf_set = true; } @@ -1717,7 +1734,6 @@ void C_HTRBypass_Cycle::estimate_od_turbo_operation(double T_mc_in, double P_mc_ } - double nlopt_cb_opt_htr_bypass_des(const std::vector& x, std::vector& grad, void* data) { C_HTRBypass_Cycle* frame = static_cast(data); diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index d4f20af668..b46fdc2c47 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -233,6 +233,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_T_HTF_BP_outlet_calc; double m_T_HTF_PHX_out; double m_dT_BP; // BYPASS_OUT - HTR_HP_OUT + double m_set_HTF_mdot; double m_Q_dot_total; double m_HTF_BP_cold_approach; double m_HTF_PHX_cold_approach; @@ -322,7 +323,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core /// kJ/kg K /// K /// K - void set_htf_par(double T_htf_phx_in, double T_htf_bp_out_target, double cp_htf, double dT_bp, double htf_phx_cold_approach); + /// K + void set_htf_par(double T_htf_phx_in, double T_htf_bp_out_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot); diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index 1ac8f2bc73..2a5dc4a4e8 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -188,8 +188,9 @@ void C_sco2_phx_air_cooler::design_core() double HTF_BP_outlet = ms_des_par.m_T_htf_bypass_out; double deltaT_bp = ms_des_par.m_deltaT_bypass; double HTF_PHX_cold_approach = ms_des_par.m_phx_dt_cold_approach; + double set_HTF_mdot = ms_des_par.m_set_HTF_mdot; - c_bp_cycle->set_htf_par(HTF_PHX_inlet, HTF_BP_outlet, cp_htf, deltaT_bp, HTF_PHX_cold_approach); + c_bp_cycle->set_htf_par(HTF_PHX_inlet, HTF_BP_outlet, cp_htf, deltaT_bp, HTF_PHX_cold_approach, set_HTF_mdot); } diff --git a/tcs/sco2_pc_csp_int.h b/tcs/sco2_pc_csp_int.h index 8f3eb2b3e1..a575a71e03 100644 --- a/tcs/sco2_pc_csp_int.h +++ b/tcs/sco2_pc_csp_int.h @@ -129,7 +129,7 @@ class C_sco2_phx_air_cooler // Bypass Configuration Parameters double m_T_htf_bypass_out; // [K] HTF design Bypass Outlet double m_deltaT_bypass; // [delta K] sco2 Bypass Outlet Temp - HTR_HP_OUT Temp - + double m_set_HTF_mdot; // [kg/s] For HTR Bypass ONLY, 0 = calculate HTF mdot (need to set dT_PHX_cold_approach), > 0 = HTF mdot kg/s From f12628c111fc5a0930cba7a329874ae21e4989fb Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Fri, 28 Jul 2023 14:28:52 -0600 Subject: [PATCH 19/94] Ensure that HTR optimization sets the optimal values. --- tcs/sco2_htrbypass_cycle.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index e12519e2ee..57fe836637 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -366,6 +366,7 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) eta_rc_isen = m_eta_rc; int rc_error_code = 0; + calculate_turbomachinery_outlet_1(m_temp_last[MC_OUT], m_pres_last[LTR_LP_OUT], m_pres_last[RC_OUT], eta_rc_isen, true, rc_error_code, m_w_rc); @@ -427,6 +428,8 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) return; } + double test = 0; + solve_HTR(T_HTR_LP_out_solved, &test); } From 04a6153df7859e7d481eae5eb5a02145eb778b68 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Mon, 31 Jul 2023 16:57:44 -0600 Subject: [PATCH 20/94] Add cmod outputs. Fix bug with recomp_frac = 0 in htr bypass cycle --- ssc/csp_common.cpp | 30 +++++++++++++++++++++++++++--- tcs/sco2_htrbypass_cycle.cpp | 5 +++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 3c263e99a8..5aa36a52ef 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -834,7 +834,9 @@ var_info vtab_sco2_design[] = { { SSC_OUTPUT, SSC_NUMBER, "cycle_spec_cost_thermal", "Cycle specific (thermal) cost bare erected", "$/kWt", "System Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "W_dot_net_less_cooling", "System power output subtracting cooling parastics", "MWe," "System Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "eta_thermal_net_less_cooling_des","Calculated cycle thermal efficiency using W_dot_net_less_cooling", "-", "System Design Solution","", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_htf_bp_out_des", "HTF design cold temperature (PHX outlet)", "C", "System Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_htf_bp_out_des", "HTF design htr bypass cold temperature (BPX outlet)", "C", "System Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "dT_htf_des", "HTF temperature difference", "C", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "q_dot_in_total", "Total heat from HTF into cycle", "MW", "System Design Solution", "", "*", "", "" }, // Compressor { SSC_OUTPUT, SSC_NUMBER, "T_comp_in", "Compressor inlet temperature", "C", "Compressor", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "P_comp_in", "Compressor inlet pressure", "MPa", "Compressor", "", "*", "", "" }, @@ -936,7 +938,8 @@ var_info vtab_sco2_design[] = { { SSC_OUTPUT, SSC_NUMBER, "HTR_min_dT", "High temp recuperator min temperature difference", "C", "Recuperators", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "HTR_cost_equipment", "High temp recuperator cost equipment", "M$", "Recuperators", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "HTR_cost_bare_erected","High temp recuperator cost equipment and install", "M$", "Recuperators", "", "*", "", "" }, - // PHX Design Solution + { SSC_OUTPUT, SSC_NUMBER, "HTR_HP_m_dot", "High temp recuperator high pressure mass flow rate", "kg/s", "Recuperators", "", "*", "", "" }, + // PHX Design Solution { SSC_OUTPUT, SSC_NUMBER, "UA_PHX", "PHX Conductance", "MW/K", "PHX Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "eff_PHX", "PHX effectiveness", "", "PHX Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "NTU_PHX", "PHX NTU", "", "PHX Design Solution", "", "*", "", "" }, @@ -1488,6 +1491,18 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c cm->assign("mc_psi_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_ms_des_solved.m_psi_des); //[-] ideal head coefficient cm->assign("mc_tip_ratio_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_ms_des_solved.m_tip_ratio_max); //[-] + double htf_outlet = cm->as_double("cycle_config") == 3 ? T_htf_bypass_out : T_htf_cold_calc; + double dT_htf = cm->as_double("T_htf_hot_des") - (htf_outlet - 273.15); + cm->assign("dT_htf_des", (ssc_number_t)dT_htf); + + double q_dot_total = c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_Q_dot_design * 1.E-3; // [MWt] + if (s_sco2_des_par.m_cycle_config == 3) + { + double q_dot_BPX = c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_Q_dot_design * 1.E-3; //[MWt] convert from kWt + q_dot_total += q_dot_BPX; + } + cm->assign("q_dot_in_total", (ssc_number_t)q_dot_total); + int n_mc_stages = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_ms_des_solved.m_n_stages; cm->assign("mc_n_stages", (ssc_number_t)n_mc_stages); //[-] cm->assign("mc_N_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_ms_des_solved.m_N_design); //[rpm] @@ -1728,7 +1743,16 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c cm->assign("recup_total_UA_calculated", (ssc_number_t)(recup_total_UA_calculated)); //[MW/K] cm->assign("recup_total_cost_equipment", (ssc_number_t)(recup_total_cost_equip)); //[MW/K] cm->assign("recup_total_cost_bare_erected", (ssc_number_t)(recup_total_cost_bare_erected)); - // PHX + + double htr_hp_m_dot = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_t; + if (s_sco2_des_par.m_cycle_config == 3) + { + double mdot_t = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_t; + htr_hp_m_dot = mdot_t * (1.0 - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_bypass_frac); + } + cm->assign("HTR_HP_m_dot", (ssc_number_t)htr_hp_m_dot); + + // PHX cm->assign("UA_PHX", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_UA_design*1.E-3)); //[MW/K] convert from kW/K cm->assign("eff_PHX", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_eff_design); //[-] cm->assign("NTU_PHX", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_NTU_design); //[-] diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 57fe836637..acc7a7ce0b 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -1258,7 +1258,8 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) } } - if (ms_auto_opt_des_par.m_is_recomp_ok != 0) + // NO longer check if recompression fraction makes cycle simple + if (true) { // Complete 'ms_opt_des_par' for recompression cycle ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] @@ -1274,7 +1275,7 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) } // Is recompression fraction fixed or optimized? - if (ms_auto_opt_des_par.m_is_recomp_ok < 0.0) + if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) { // fixed ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); ms_opt_des_par.m_fixed_recomp_frac = true; From 65d2930aca4780efbe9a06689fbfa82d355a4454 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Thu, 3 Aug 2023 13:38:54 -0600 Subject: [PATCH 21/94] Fix output when bypass heat exchanger has zero flow --- ssc/csp_common.cpp | 2 +- tcs/sco2_pc_csp_int.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 5aa36a52ef..83785b2b71 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -837,7 +837,7 @@ var_info vtab_sco2_design[] = { { SSC_OUTPUT, SSC_NUMBER, "T_htf_bp_out_des", "HTF design htr bypass cold temperature (BPX outlet)", "C", "System Design Solution", "", "cycle_config=3", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "dT_htf_des", "HTF temperature difference", "C", "System Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "q_dot_in_total", "Total heat from HTF into cycle", "MW", "System Design Solution", "", "*", "", "" }, - // Compressor + // Compressor { SSC_OUTPUT, SSC_NUMBER, "T_comp_in", "Compressor inlet temperature", "C", "Compressor", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "P_comp_in", "Compressor inlet pressure", "MPa", "Compressor", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "P_comp_out", "Compressor outlet pressure", "MPa", "Compressor", "", "*", "", "" }, diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index 2a5dc4a4e8..639c0196a7 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -434,11 +434,24 @@ void C_sco2_phx_air_cooler::design_core() // Set Mass Flow (it is known because it is equal to PHX) ms_bp_des_par.m_m_dot_hot_des = ms_phx_des_par.m_m_dot_hot_des; + + // Design if (ms_bp_des_par.m_m_dot_cold_des > 0 && q_dot_des_bp > 1e-2) { mc_bp.design_calc_UA(ms_bp_des_par, q_dot_des_bp, ms_des_solved.ms_bp_des_solved); } + // No Mass Flow + else + { + ms_des_solved.ms_bp_des_solved.m_T_h_out = mc_phx.ms_des_solved.m_T_h_out; + ms_des_solved.ms_bp_des_solved.m_cost_bare_erected = 0; + ms_des_solved.ms_bp_des_solved.m_cost_equipment = 0; + ms_des_solved.ms_bp_des_solved.m_UA_design = 0; + ms_des_solved.ms_bp_des_solved.m_eff_design = 0; + ms_des_solved.ms_bp_des_solved.m_min_DT_design = 0; + ms_des_solved.ms_bp_des_solved.m_Q_dot_design = 0; + } } From f9711520053235b10359634b4b80908461348858 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Thu, 7 Sep 2023 09:38:54 -0600 Subject: [PATCH 22/94] Catch air cooler sizing exceptions. Add max evaluation limit to optimizer. --- tcs/sco2_htrbypass_cycle.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index acc7a7ce0b..c98947ae15 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -101,13 +101,17 @@ void C_HTRBypass_Cycle::design_core(int& error_code) opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(0.01); opt_des_cycle.set_xtol_rel(0.05); + opt_des_cycle.set_maxeval(50); // Set max objective function std::vector x; x.push_back(0.1); opt_des_cycle.set_max_objective(nlopt_cb_opt_bypass_frac_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' double max_f = std::numeric_limits::quiet_NaN(); + + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + ms_des_par.m_bypass_frac = x[0]; design_core_standard(error_code); @@ -639,7 +643,15 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) { - mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, ms_des_par.m_des_tol); + try + { + mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, ms_des_par.m_des_tol); + } + catch (...) + { + error_code = 35; + return; + } } } @@ -1122,7 +1134,12 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) // Set max objective function opt_des_cycle.set_max_objective(nlopt_cb_opt_htr_bypass_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' double max_f = std::numeric_limits::quiet_NaN(); + + + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + + // Check if forced stop int flag = opt_des_cycle.get_force_stop(); From f3096700f4645b4458ad348906e36c0be3d26046 Mon Sep 17 00:00:00 2001 From: taylorbrown75 Date: Thu, 7 Sep 2023 15:52:38 -0600 Subject: [PATCH 23/94] Change T_htf_cold_des to HTF outlet temperature (not necessarily PHX outlet) and add HTF PHX outlet output variable. --- ssc/csp_common.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 83785b2b71..44803f5175 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -823,8 +823,9 @@ var_info vtab_sco2_design[] = { // ** Design OUTPUTS ** // System Design Solution - { SSC_OUTPUT, SSC_NUMBER, "T_htf_cold_des", "HTF design cold temperature (PHX outlet)", "C", "System Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "m_dot_htf_des", "HTF mass flow rate", "kg/s", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_htf_cold_des", "HTF design cold temperature (HTF outlet)", "C", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_htf_phx_out_des", "HTF design phx cold temperature (PHX outlet)", "C", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "m_dot_htf_des", "HTF mass flow rate", "kg/s", "System Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "eta_thermal_calc", "Calculated cycle thermal efficiency", "-", "System Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "m_dot_co2_full", "CO2 mass flow rate through HTR, PHX, turbine", "kg/s", "System Design Solution", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "recomp_frac", "Recompression fraction", "-", "System Design Solution", "", "*", "", "" }, @@ -1472,12 +1473,22 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c double m_dot_htf_design = c_sco2_cycle.get_phx_des_par()->m_m_dot_hot_des; //[kg/s] double T_htf_cold_calc = c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_T_h_out; //[K] double T_htf_bypass_out = c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_T_h_out; //[K] - cm->assign("T_htf_cold_des", (ssc_number_t)(T_htf_cold_calc - 273.15)); //[C] convert from K + double cycle_config = cm->as_double("cycle_config"); + cm->assign("T_htf_phx_out_des", (ssc_number_t)(T_htf_cold_calc - 273.15)); //[C] convert from K PHX Outlet Temp cm->assign("m_dot_htf_des", (ssc_number_t)m_dot_htf_design); //[kg/s] cm->assign("eta_thermal_calc", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_eta_thermal); //[-] cm->assign("m_dot_co2_full", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_t); //[kg/s] cm->assign("recomp_frac", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_recomp_frac); //[-] - cm->assign("T_htf_bp_out_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_T_h_out - 273.15); // [C] + if (cycle_config == 3) + { + cm->assign("T_htf_bp_out_des", (ssc_number_t)T_htf_bypass_out - 273.15); // [C] + cm->assign("T_htf_cold_des", (ssc_number_t)(T_htf_bypass_out - 273.15)); //[C] convert from K Final HTF Temp is BPX Outlet for htr bypass cycle + } + else + { + cm->assign("T_htf_cold_des", (ssc_number_t)(T_htf_cold_calc - 273.15)); //[C] convert from K Final HTF Temp (PHX outlet for recompression and partial) + } + // Compressor cm->assign("T_comp_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::MC_IN] - 273.15)); //[C] convert from K cm->assign("P_comp_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::MC_IN] / 1000.0)); //[MPa] convert from kPa From b18ecfcb5117ed55b9b8da8de59a8baffa9505ab Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Tue, 12 Sep 2023 14:28:39 -0600 Subject: [PATCH 24/94] Begin adding option to optimize for bypass fraction outside of main optimizer. --- tcs/sco2_htrbypass_cycle.cpp | 137 +++++++++++++++++++++++------------ 1 file changed, 92 insertions(+), 45 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index c98947ae15..b095430087 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -663,10 +663,14 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) if (ms_des_par.m_des_objective_type == 2) { - double phx_deltaT = m_temp_last[TURB_IN] - m_temp_last[HTR_HP_OUT]; - double under_min_deltaT = std::max(0.0, ms_des_par.m_min_phx_deltaT - phx_deltaT); - double eta_deltaT_scale = std::exp(-under_min_deltaT); - m_objective_metric_last = m_eta_thermal_calc_last * eta_deltaT_scale; + double target_bp_out = m_T_HTF_BP_outlet_target; + double calc_bp_out = m_T_HTF_BP_outlet_calc; + + double temp_err = std::abs(calc_bp_out - target_bp_out); + double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; + double percent_err = temp_err / temp_span; + + m_objective_metric_last = m_eta_thermal_calc_last - percent_err; } else { @@ -1209,16 +1213,7 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) // map 'auto_opt_des_par_in' to 'ms_auto_opt_des_par' - // Bypass Fraction - if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) - { - ms_opt_des_par.m_fixed_bypass_frac = true; - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - } - else - { - ms_opt_des_par.m_fixed_bypass_frac = false; - } + // LTR thermal design @@ -1275,56 +1270,109 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) } } - // NO longer check if recompression fraction makes cycle simple - if (true) + // Complete 'ms_opt_des_par' for recompression cycle + ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] + ms_opt_des_par.m_fixed_P_mc_out = true; + + if (ms_opt_des_par.m_fixed_PR_HP_to_LP) { - // Complete 'ms_opt_des_par' for recompression cycle - ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] - ms_opt_des_par.m_fixed_P_mc_out = true; + ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + } + else + { + ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] + } + + // Is recompression fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) + { // fixed + ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); + ms_opt_des_par.m_fixed_recomp_frac = true; + } + else + { // optimized + ms_opt_des_par.m_recomp_frac_guess = 0.3; + ms_opt_des_par.m_fixed_recomp_frac = false; + } + + ms_opt_des_par.m_LT_frac_guess = 0.5; + ms_opt_des_par.m_fixed_LT_frac = false; + + if (ms_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + ms_opt_des_par.m_fixed_LT_frac = true; + } - if (ms_opt_des_par.m_fixed_PR_HP_to_LP) + // Default case with Bypass either set or optimized WITHIN Optimization + if (ms_auto_opt_des_par.m_des_objective_type != 2) + { + // Bypass Fraction + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) { - ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + ms_opt_des_par.m_fixed_bypass_frac = true; + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); } else { - ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] + ms_opt_des_par.m_fixed_bypass_frac = false; } - // Is recompression fraction fixed or optimized? - if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) - { // fixed - ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); - ms_opt_des_par.m_fixed_recomp_frac = true; - } - else - { // optimized - ms_opt_des_par.m_recomp_frac_guess = 0.3; - ms_opt_des_par.m_fixed_recomp_frac = false; - } + int rc_error_code = 0; - ms_opt_des_par.m_LT_frac_guess = 0.5; - ms_opt_des_par.m_fixed_LT_frac = false; + opt_design_core(rc_error_code); - if (ms_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) + if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) { - ms_opt_des_par.m_fixed_LT_frac = true; + ms_des_par_auto_opt = ms_des_par_optimal; + m_objective_metric_auto_opt = m_objective_metric_opt; } + } - int rc_error_code = 0; + // Add option for des_objective_type == 2 (optimize bypass fraction OUTSIDE other optimization (rather than INSIDE) + else // (m_des_objective_type == 2) + { + // Bypass Fraction + ms_opt_des_par.m_fixed_bypass_frac = true; - + // Hard coded Bypass Fraction, but other variables optimize to hit the correct temperature + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) + { + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + int rc_error_code = 0; - opt_design_core(rc_error_code); + opt_design_core(rc_error_code); - if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) + if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) + { + ms_des_par_auto_opt = ms_des_par_optimal; + m_objective_metric_auto_opt = m_objective_metric_opt; + } + } + + // Optimize Bypass Fraction outside other variables + else { - ms_des_par_auto_opt = ms_des_par_optimal; - m_objective_metric_auto_opt = m_objective_metric_opt; + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + + int rc_error_code = 0; + + opt_design_core(rc_error_code); + + if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) + { + ms_des_par_auto_opt = ms_des_par_optimal; + m_objective_metric_auto_opt = m_objective_metric_opt; + } } + + + } + + + ms_des_par = ms_des_par_auto_opt; @@ -1624,7 +1672,6 @@ double C_HTRBypass_Cycle::design_cycle_return_objective_metric(const std::vector design_core(error_code); - // Set Objective double objective_metric = -10000000000.0; if (error_code == 0) @@ -1633,7 +1680,7 @@ double C_HTRBypass_Cycle::design_cycle_return_objective_metric(const std::vector // If fixed bypass fraction, no penalty function double penalty = 0; - if (ms_opt_des_par.m_fixed_bypass_frac == false) + if (ms_opt_des_par.m_fixed_bypass_frac == false || ms_opt_des_par.m_des_objective_type == 2) { double target_bp_out = m_T_HTF_BP_outlet_target; double calc_bp_out = m_T_HTF_BP_outlet_calc; From a4ae6539031d22bed7e4b6cad8852668250256fc Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Wed, 27 Sep 2023 13:46:58 -0600 Subject: [PATCH 25/94] Add optimization routine to optimize bypass fraction outside other variables. Fix bug in csp_common with htr bypass cycle --- ssc/csp_common.cpp | 2 +- tcs/sco2_htrbypass_cycle.cpp | 160 ++++++++++++++++++++--------------- tcs/sco2_htrbypass_cycle.h | 7 ++ 3 files changed, 100 insertions(+), 69 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 44803f5175..10de23095a 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -1706,7 +1706,7 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c cost_equip_sum += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_equipment; //[M$] cost_bare_erected_sum += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_bare_erected; //[M$] // High-temp - if (is_rc) + if (is_rc || s_sco2_des_par.m_cycle_config == 3) // Cycle may still have HTR if it is htr bypass cycle { recup_total_UA_assigned += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_HTR_des_solved.m_UA_allocated*1.E-3; //[MW/K] convert from kW/K recup_total_UA_calculated += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_HTR_des_solved.m_UA_calc_at_eff_max*1.E-3; //[MW/K] convert from kW/K diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index b095430087..a3d1c78da5 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -42,37 +42,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. void C_HTRBypass_Cycle::design_core(int& error_code) { - //// DEBUG sco2 flex - //if (false) - //{ - // m_cp_HTF = 1.5375; - // - // // LTR (sco2 flex) - // double Q_dot_LTR_LP_paper; - // double Q_dot_LTR_HP_paper; - // { - // double T1_C = 198.72; - // double T2_C = 76.01; - // double T3_C = 65.91; - // double T4_C = 188.72; - // double P1_C = 8.380; - // double P2_C = 8.338; - // double P3_C = 25; - // double P4_C = 24.995; - // double mdot_lp = 1041.54; - // double mdot_hp = 677.31; - // int prop_error_code = CO2_TP(T1_C + 273.15, P1_C * 1e3, &co2_props); - // double h1 = co2_props.enth; - // CO2_TP(T2_C + 273.15, P2_C * 1e3, &co2_props); - // double h2 = co2_props.enth; - // Q_dot_LTR_LP_paper = mdot_lp * (h2 - h1); - // CO2_TP(T3_C + 273.15, P3_C * 1e3, &co2_props); - // double h3 = co2_props.enth; - // CO2_TP(T4_C + 273.15, P4_C * 1e3, &co2_props); - // double h4 = co2_props.enth; - // Q_dot_LTR_HP_paper = mdot_hp * (h4 - h3); - // double pu = 0; - // } // Check if HTF parameters were set if (is_htf_set == false) @@ -100,7 +69,7 @@ void C_HTRBypass_Cycle::design_core(int& error_code) opt_des_cycle.set_lower_bounds(lb); opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(0.01); - opt_des_cycle.set_xtol_rel(0.05); + opt_des_cycle.set_xtol_rel(0.1); opt_des_cycle.set_maxeval(50); // Set max objective function @@ -640,7 +609,7 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) s_air_cooler_des_par_ind.m_eta_fan = m_eta_fan; //[-] s_air_cooler_des_par_ind.m_N_nodes_pass = m_N_nodes_pass; //[-] - if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) + /*if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) { try @@ -652,7 +621,7 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) error_code = 35; return; } - } + }*/ } @@ -1107,21 +1076,6 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) index++; } - // DEBUG - if (false) - { - std::vector recomp_vec = { 0.8 }; - for (double re : recomp_vec) - { - ms_des_par.m_P_mc_out = ms_opt_des_par.m_P_mc_out_guess; - ms_des_par.m_P_mc_in = ms_des_par.m_P_mc_out / ms_opt_des_par.m_PR_HP_to_LP_guess; - ms_des_par.m_recomp_frac = re; - design_core(error_code); - } - } - - - error_code = 0; if (index > 0) { @@ -1343,39 +1297,51 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) opt_design_core(rc_error_code); - if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) - { - ms_des_par_auto_opt = ms_des_par_optimal; - m_objective_metric_auto_opt = m_objective_metric_opt; - } + + ms_des_par_auto_opt = ms_des_par_optimal; + m_objective_metric_auto_opt = m_objective_metric_opt; + } // Optimize Bypass Fraction outside other variables else { - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - int rc_error_code = 0; + m_objective_metric_bypass_frac_opt = -10000000; - opt_design_core(rc_error_code); + // Set up instance of nlopt class and set optimization parameters + nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); - if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) - { - ms_des_par_auto_opt = ms_des_par_optimal; - m_objective_metric_auto_opt = m_objective_metric_opt; - } - } + std::vector lb = { 0 }; + std::vector ub = { 0.99 }; + opt_des_cycle.set_lower_bounds(lb); + opt_des_cycle.set_upper_bounds(ub); + opt_des_cycle.set_initial_step(0.1); + opt_des_cycle.set_xtol_rel(0.1); + opt_des_cycle.set_maxeval(50); + // Set max objective function + std::vector x; + x.push_back(0.1); + opt_des_cycle.set_max_objective(nlopt_cb_opt_bypass_frac_free_var, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' + double max_f = std::numeric_limits::quiet_NaN(); - } - + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + ms_des_par = ms_des_par_full_auto_opt; + ms_des_par_auto_opt = ms_des_par_full_auto_opt; + design_core_standard(error_code); - ms_des_par = ms_des_par_auto_opt; + ms_opt_des_par.m_bypass_frac_guess = ms_des_par_auto_opt.m_bypass_frac; + //std::string s = make_result_csv_string(); + } + } + ms_des_par = ms_des_par_auto_opt; + int optimal_design_error_code = 0; design_core(optimal_design_error_code); @@ -1583,7 +1549,7 @@ int C_HTRBypass_Cycle::auto_opt_design(S_auto_opt_design_parameters& auto_opt_de } - +// Optimize UA ratio, recompression fraction, pressure ratio double C_HTRBypass_Cycle::design_cycle_return_objective_metric(const std::vector& x) { // 'x' is array of inputs either being adjusted by optimizer or set constant @@ -1704,7 +1670,7 @@ double C_HTRBypass_Cycle::design_cycle_return_objective_metric(const std::vector return objective_metric; } -// X is single bypass fraction value +// Optimize bypass fraction (only) double C_HTRBypass_Cycle::design_bypass_frac_return_objective_metric(const std::vector& x) { ms_des_par.m_bypass_frac = x[0]; @@ -1743,6 +1709,56 @@ double C_HTRBypass_Cycle::design_bypass_frac_return_objective_metric(const std:: return objective_metric; } +// Optimize bypass fraction and internally, the other free variables +double C_HTRBypass_Cycle::design_bypass_frac_free_var_return_objective_metric(const std::vector& x) +{ + ms_opt_des_par.m_bypass_frac_guess = x[0]; + + int error_code = 0; + + opt_design_core(error_code); + + // Returns ms_des_par_optimal as optimal parameters + + ms_des_par = ms_des_par_optimal; + design_core_standard(error_code); + + double objective_metric = -10000000000.0; + if (error_code == 0) + { + // Set Objective + double objective_metric = -10000000000.0; + if (error_code == 0) + { + double eff = m_eta_thermal_calc_last; + + // If fixed bypass fraction, no penalty function + double penalty = 0; + if (ms_opt_des_par.m_fixed_bypass_frac == false || ms_opt_des_par.m_des_objective_type == 2) + { + double target_bp_out = m_T_HTF_BP_outlet_target; + double calc_bp_out = m_T_HTF_BP_outlet_calc; + + double temp_err = std::abs(calc_bp_out - target_bp_out); + double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; + double percent_err = temp_err / temp_span; + + penalty = 10.0 * (sigmoid(percent_err) - 0.5); + } + + objective_metric = eff - penalty; + + if (objective_metric > m_objective_metric_full_auto_opt) + { + ms_des_par_full_auto_opt = ms_des_par; + m_objective_metric_full_auto_opt = objective_metric; + } + } + } + + return objective_metric; +} + @@ -1820,6 +1836,14 @@ double nlopt_cb_opt_bypass_frac_des(const std::vector& x, std::vector& x, std::vector& grad, void* data) +{ + C_HTRBypass_Cycle* frame = static_cast(data); + if (frame != NULL) + return frame->design_bypass_frac_free_var_return_objective_metric(x); + else + return 0.0; +} double sigmoid(const double val) { diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index b46fdc2c47..78740ffb79 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -217,6 +217,9 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_objective_metric_auto_opt; S_design_parameters ms_des_par_auto_opt; + S_design_parameters ms_des_par_full_auto_opt; + double m_objective_metric_full_auto_opt = 0; + // NEW Internal Variables double m_w_t; // kJ/kg double m_w_mc; // kJ/kg @@ -348,6 +351,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core // Called by 'nlopt_callback_opt_des_1', so needs to be public double design_bypass_frac_return_objective_metric(const std::vector& x); + double design_bypass_frac_free_var_return_objective_metric(const std::vector& x); + class C_mono_htr_bypass_LTR_des : public C_monotonic_equation { private: @@ -447,6 +452,8 @@ double nlopt_cb_opt_htr_bypass_des(const std::vector& x, std::vector& x, std::vector& grad, void* data); +double nlopt_cb_opt_bypass_frac_free_var(const std::vector& x, std::vector& grad, void* data); + double sigmoid(const double val); From 3078fa508c9232a73d7ed25aad6041df8b911a22 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Thu, 5 Oct 2023 09:25:37 -0600 Subject: [PATCH 26/94] Use user defined tolerance, rather than hardcode. --- tcs/sco2_htrbypass_cycle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index a3d1c78da5..04fee23a40 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -1087,7 +1087,7 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) opt_des_cycle.set_lower_bounds(lb); opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(scale); - opt_des_cycle.set_xtol_rel(0.001); + opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); // Set max objective function opt_des_cycle.set_max_objective(nlopt_cb_opt_htr_bypass_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' @@ -1318,7 +1318,7 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) opt_des_cycle.set_lower_bounds(lb); opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(0.1); - opt_des_cycle.set_xtol_rel(0.1); + opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); opt_des_cycle.set_maxeval(50); // Set max objective function From 89e6d80f4f1a81d1063f7b9d3fc7b0dbf9b295dc Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Mon, 29 Jan 2024 13:19:09 -0700 Subject: [PATCH 27/94] Try adding max evaluation limit --- tcs/sco2_htrbypass_cycle.cpp | 1 + tcs/sco2_partialcooling_cycle.cpp | 8 ++++++-- tcs/sco2_recompression_cycle.cpp | 10 +++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 04fee23a40..0fdf725aae 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -1088,6 +1088,7 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(scale); opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); + opt_des_cycle.set_maxeval(10); // Set max objective function opt_des_cycle.set_max_objective(nlopt_cb_opt_htr_bypass_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' diff --git a/tcs/sco2_partialcooling_cycle.cpp b/tcs/sco2_partialcooling_cycle.cpp index 35bc22b868..9a05c54510 100644 --- a/tcs/sco2_partialcooling_cycle.cpp +++ b/tcs/sco2_partialcooling_cycle.cpp @@ -308,8 +308,11 @@ int C_PartialCooling_Cycle::design_core() { double phx_deltaT = m_temp_last[TURB_IN] - m_temp_last[HTR_HP_OUT]; double under_min_deltaT = std::max(0.0, ms_des_par.m_min_phx_deltaT - phx_deltaT); - double eta_deltaT_scale = std::exp(-under_min_deltaT); - m_objective_metric_last = m_eta_thermal_calc_last * eta_deltaT_scale; + //double eta_deltaT_scale = std::exp(-under_min_deltaT); + //m_objective_metric_last = m_eta_thermal_calc_last * eta_deltaT_scale; + + double percent_err = under_min_deltaT / ms_des_par.m_min_phx_deltaT; + m_objective_metric_last = m_eta_thermal_calc_last - percent_err; } else { @@ -891,6 +894,7 @@ int C_PartialCooling_Cycle::opt_design_core() opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(scale); opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); + opt_des_cycle.set_maxeval(10); // set max objective function opt_des_cycle.set_max_objective(nlopt_cb_opt_partialcooling_des, this); diff --git a/tcs/sco2_recompression_cycle.cpp b/tcs/sco2_recompression_cycle.cpp index fe18b5aad1..e9f97c54e8 100644 --- a/tcs/sco2_recompression_cycle.cpp +++ b/tcs/sco2_recompression_cycle.cpp @@ -2114,8 +2114,12 @@ void C_RecompCycle::design_core_standard(int & error_code) { double phx_deltaT = m_temp_last[TURB_IN] - m_temp_last[HTR_HP_OUT]; double under_min_deltaT = std::max(0.0, ms_des_par.m_min_phx_deltaT - phx_deltaT); - double eta_deltaT_scale = std::exp(-under_min_deltaT); - m_objective_metric_last = m_eta_thermal_calc_last * eta_deltaT_scale; + //double eta_deltaT_scale = std::exp(-under_min_deltaT); + //m_objective_metric_last = m_eta_thermal_calc_last * eta_deltaT_scale; + + double percent_err = under_min_deltaT / ms_des_par.m_min_phx_deltaT; + m_objective_metric_last = m_eta_thermal_calc_last - percent_err; + } else { @@ -2494,7 +2498,7 @@ void C_RecompCycle::opt_design_core(int & error_code) opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(scale); opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); - + opt_des_cycle.set_maxeval(10); // Set max objective function opt_des_cycle.set_max_objective(nlopt_cb_opt_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' double max_f = std::numeric_limits::quiet_NaN(); From bb7ef44333faa05117814c585dc068a4370bb246 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Thu, 15 Feb 2024 15:45:48 -0700 Subject: [PATCH 28/94] Add ability to target low sco2 temperature --- ssc/csp_common.cpp | 11 +-- tcs/heat_exchangers.cpp | 10 +-- tcs/sco2_htrbypass_cycle.cpp | 126 +++++++++++++++++++++++++++++------ tcs/sco2_htrbypass_cycle.h | 20 +++--- tcs/sco2_pc_csp_int.cpp | 5 +- tcs/sco2_pc_csp_int.h | 3 +- 6 files changed, 131 insertions(+), 44 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 10de23095a..be3a656c96 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -784,7 +784,6 @@ var_info vtab_sco2_design[] = { { SSC_INPUT, SSC_NUMBER, "is_P_high_fixed", "1 = Yes (=P_high_limit), 0 = No, optimized (default)", "", "High temperature recuperator", "Heat Exchanger Design", "?=0", "", "" }, { SSC_INPUT, SSC_NUMBER, "is_PR_fixed", "0 = No, >0 = fixed pressure ratio at input <0 = fixed LP at abs(input)", "High temperature recuperator", "", "Heat Exchanger Design", "?=0", "", "" }, { SSC_INPUT, SSC_NUMBER, "is_IP_fixed", "partial cooling config: 0 = No, >0 = fixed HP-IP pressure ratio at input, <0 = fixed IP at abs(input)","","High temperature recuperator","Heat Exchanger Design","?=0", "", "" }, - { SSC_INPUT, SSC_NUMBER, "is_bypass_ok", "1 = Yes, 0 = No Bypass, < 0 = fix bp_frac to abs(input)","", "High temperature recuperator", "Heat Exchanger Design", "?=1", "", "" }, { SSC_INPUT, SSC_NUMBER, "des_objective", "[2] = hit min phx deltat then max eta, [else] max eta", "", "High temperature recuperator", "Heat Exchanger Design", "?=0", "", "" }, { SSC_INPUT, SSC_NUMBER, "min_phx_deltaT", "Minimum design temperature difference across PHX", "C", "High temperature recuperator", "Heat Exchanger Design", "?=0", "", "" }, @@ -814,10 +813,13 @@ var_info vtab_sco2_design[] = { // HTR Bypass Design - { SSC_INPUT, SSC_NUMBER, "T_htf_bypass_out", "HTF design Bypass Outlet Temperature", "C", "", "System Design", "cycle_config=3", "", "" }, - { SSC_INPUT, SSC_NUMBER, "deltaT_bypass", "sco2 Bypass Outlet Temp - HTR_HP_OUT Temp", "C", "", "System Design", "cycle_config=3", "", "" }, + { SSC_INPUT, SSC_NUMBER, "is_bypass_ok", "1 = Yes, 0 = No Bypass, < 0 = fix bp_frac to abs(input)","", "High temperature recuperator", "Heat Exchanger Design", "?=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "T_bypass_target", "HTR BP Cycle Target Temperature", "C", "", "System Design", "cycle_config=3", "", "" }, + { SSC_INPUT, SSC_NUMBER, "T_target_is_HTF", "Target Temperature is HTF (1) or cold sco2 at BP", "", "", "System Design", "?=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "deltaT_bypass", "sco2 Bypass Outlet Temp - HTR_HP_OUT Temp", "C", "", "System Design", "cycle_config=3", "", "" }, { SSC_INPUT, SSC_NUMBER, "set_HTF_mdot", "For HTR Bypass ONLY, 0 = calculate HTF mdot (need to set dT_PHX_cold_approach), > 0 = HTF mdot kg/s", "kg/s", "", "System Design", "?=0", "", "" }, + // DEBUG //{ SSC_OUTPUT, SSC_STRING, "debug_string", "output string used for debug", "C", "", "System Design", "cycle_config=3", "", "" }, @@ -1255,7 +1257,8 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c // Bypass Configuration Parameters if (s_sco2_des_par.m_cycle_config == 3) { - s_sco2_des_par.m_T_htf_bypass_out = cm->as_double("T_htf_bypass_out") + 273.15; // [C] Convert to C + s_sco2_des_par.m_T_bypass_target = cm->as_double("T_bypass_target") + 273.15; // [K] Convert to K + s_sco2_des_par.m_T_target_is_HTF = cm->as_integer("T_target_is_HTF"); s_sco2_des_par.m_deltaT_bypass = cm->as_double("deltaT_bypass"); // [delta C] s_sco2_des_par.m_set_HTF_mdot = cm->as_double("set_HTF_mdot"); // [kg/s] For HTR Bypass ONLY, 0 = calculate HTF mdot (need to set dT_PHX_cold_approach), > 0 = HTF mdot diff --git a/tcs/heat_exchangers.cpp b/tcs/heat_exchangers.cpp index 0f24b8b197..ddff1eba87 100644 --- a/tcs/heat_exchangers.cpp +++ b/tcs/heat_exchangers.cpp @@ -1521,11 +1521,13 @@ void NS_HX_counterflow_eqs::solve_q_dot_for_fixed_UA_enth(int hot_fl_code /*-*/, throw(C_csp_exception("Off-design heat exchanger method failed")); } - //if (!(od_hx_code == C_monotonic_eq_solver::CONVERGED || od_hx_code == C_monotonic_eq_solver::SLOPE_POS_NO_POS_ERR || od_hx_code == C_monotonic_eq_solver::SLOPE_POS_BOTH_ERRS)) - //{ - // throw(C_csp_exception("Off-design heat exchanger method failed")); - //} + /*if (!(od_hx_code == C_monotonic_eq_solver::CONVERGED || od_hx_code == C_monotonic_eq_solver::SLOPE_POS_NO_POS_ERR || od_hx_code == C_monotonic_eq_solver::SLOPE_POS_BOTH_ERRS)) + { + throw(C_csp_exception("Off-design heat exchanger method failed")); + }*/ + } + else if (test_code == 0 && diff_UA_max_eff <= 0.0) // UA_max_eff <= UA_target) { // At maximum allowable heat transfer, the calculated UA is less than target diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 0fdf725aae..7a10f5017b 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -44,7 +44,7 @@ void C_HTRBypass_Cycle::design_core(int& error_code) { // Check if HTF parameters were set - if (is_htf_set == false) + if (is_bp_par_set == false) { error_code = 560; return; @@ -70,7 +70,7 @@ void C_HTRBypass_Cycle::design_core(int& error_code) opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(0.01); opt_des_cycle.set_xtol_rel(0.1); - opt_des_cycle.set_maxeval(50); + //opt_des_cycle.set_maxeval(50); // Set max objective function std::vector x; @@ -632,14 +632,29 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) if (ms_des_par.m_des_objective_type == 2) { - double target_bp_out = m_T_HTF_BP_outlet_target; - double calc_bp_out = m_T_HTF_BP_outlet_calc; + double temp_calc = 0; + double span = 0; + + if (m_T_target_is_HTF == 0) + { + temp_calc = m_temp_last[MIXER_OUT]; + span = m_temp_last[TURB_IN] - m_T_target; + } + else + { + temp_calc = m_T_HTF_BP_outlet_calc; + span = m_T_HTF_PHX_inlet - m_T_target; + } + + /*double target_bp_out = m_T_target; double temp_err = std::abs(calc_bp_out - target_bp_out); double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; - double percent_err = temp_err / temp_span; + double percent_err = temp_err / temp_span;*/ + + double penalty = calc_penalty(m_T_target, temp_calc, span); - m_objective_metric_last = m_eta_thermal_calc_last - percent_err; + m_objective_metric_last = m_eta_thermal_calc_last - penalty; } else { @@ -873,12 +888,20 @@ int C_HTRBypass_Cycle::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_L return 0; } +double C_HTRBypass_Cycle::calc_penalty(double target, double calc, double span) +{ + double percent_error = std::abs(target - calc) / span; + double penalty = 10.0 * (100.0 * sigmoid(percent_error) - 0.5); + + return penalty; +} + std::string C_HTRBypass_Cycle::make_result_csv_string() { std::string value_string; std::vector value_vec; - value_vec.push_back(this->m_T_HTF_BP_outlet_target); + value_vec.push_back(this->m_T_target); value_vec.push_back(this->m_T_HTF_BP_outlet_calc); value_vec.push_back(this->m_T_HTF_PHX_inlet); value_vec.push_back(this->m_T_HTF_PHX_inlet - this->m_T_HTF_BP_outlet_calc); @@ -988,10 +1011,21 @@ int C_HTRBypass_Cycle::C_mono_htr_bypass_BP_des::operator()(double bp_frac_guess this->m_htr_bypass_cycle->ms_des_par.m_bypass_frac = bp_frac_guess; this->m_htr_bypass_cycle->design_core_standard(error_code); - double target_bp_out = this->m_htr_bypass_cycle->m_T_HTF_BP_outlet_target; - double calc_bp_out = this->m_htr_bypass_cycle->m_T_HTF_BP_outlet_calc; + if (this->m_htr_bypass_cycle->m_T_target_is_HTF == 0) + { + double target_out = this->m_htr_bypass_cycle->m_T_target; + double calc_sco2_out = this->m_htr_bypass_cycle->m_temp_last[MIXER_OUT]; + *diff_T_BP_HTF_out = calc_sco2_out - target_out; + } + else + { + double target_bp_out = this->m_htr_bypass_cycle->m_T_target; + double calc_bp_out = this->m_htr_bypass_cycle->m_T_HTF_BP_outlet_calc; + *diff_T_BP_HTF_out = calc_bp_out - target_bp_out; + } + - *diff_T_BP_HTF_out = calc_bp_out - target_bp_out; + return error_code; @@ -1088,7 +1122,7 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(scale); opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); - opt_des_cycle.set_maxeval(10); + opt_des_cycle.set_maxeval(50); // Set max objective function opt_des_cycle.set_max_objective(nlopt_cb_opt_htr_bypass_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' @@ -1289,6 +1323,9 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) // Bypass Fraction ms_opt_des_par.m_fixed_bypass_frac = true; + // Ensure thermal efficiency is initialized to negative value + m_objective_metric_full_auto_opt = -100000000000; + // Hard coded Bypass Fraction, but other variables optimize to hit the correct temperature if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) { @@ -1499,16 +1536,18 @@ void C_HTRBypass_Cycle::finalize_design(int& error_code) // Public Methods -void C_HTRBypass_Cycle::set_htf_par(double T_htf_phx_in, double T_htf_bp_out_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot) +void C_HTRBypass_Cycle::set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot, + int T_target_is_HTF) { m_T_HTF_PHX_inlet = T_htf_phx_in; // K - m_T_HTF_BP_outlet_target = T_htf_bp_out_target; // K + m_T_target = T_target; // K + m_T_target_is_HTF = T_target_is_HTF; m_cp_HTF = cp_htf; // kJ/kg K m_dT_BP = dT_bp; m_HTF_PHX_cold_approach = htf_phx_cold_approach; m_set_HTF_mdot = set_HTF_mdot; - is_htf_set = true; + is_bp_par_set = true; } void C_HTRBypass_Cycle::design(S_design_parameters& des_par_in, int& error_code) @@ -1649,14 +1688,29 @@ double C_HTRBypass_Cycle::design_cycle_return_objective_metric(const std::vector double penalty = 0; if (ms_opt_des_par.m_fixed_bypass_frac == false || ms_opt_des_par.m_des_objective_type == 2) { - double target_bp_out = m_T_HTF_BP_outlet_target; + double temp_calc = 0; + double span = 0; + + if (m_T_target_is_HTF == 0) + { + temp_calc = m_temp_last[MIXER_OUT]; + span = m_temp_last[TURB_IN] - m_T_target; + } + else + { + temp_calc = m_T_HTF_BP_outlet_calc; + span = m_T_HTF_PHX_inlet - m_T_target; + } + + /*double target_bp_out = m_T_HTF_BP_outlet_target; double calc_bp_out = m_T_HTF_BP_outlet_calc; double temp_err = std::abs(calc_bp_out - target_bp_out); double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; double percent_err = temp_err / temp_span; - penalty = 10.0 * (sigmoid(percent_err) - 0.5); + penalty = 10.0 * (100.0 * sigmoid(percent_err) - 0.5);*/ + penalty = calc_penalty(m_T_target, temp_calc, span); } objective_metric = eff - penalty; @@ -1683,14 +1737,28 @@ double C_HTRBypass_Cycle::design_bypass_frac_return_objective_metric(const std:: double objective_metric = -10000000000.0; if (error_code == 0) { - double eff = m_eta_thermal_calc_last; + double temp_calc = 0; + double span = 0; + + if (m_T_target_is_HTF == 0) + { + temp_calc = m_temp_last[MIXER_OUT]; + span = m_temp_last[TURB_IN] - m_T_target; + } + else + { + temp_calc = m_T_HTF_BP_outlet_calc; + span = m_T_HTF_PHX_inlet - m_T_target; + } + + /*double eff = m_eta_thermal_calc_last; double target_bp_out = m_T_HTF_BP_outlet_target; double calc_bp_out = m_T_HTF_BP_outlet_calc; double temp_err = std::abs(calc_bp_out - target_bp_out); double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; - double percent_err = temp_err / temp_span; + double percent_err = temp_err / temp_span;*/ //double penalty = std::pow(percent_err, 2.0); @@ -1698,7 +1766,7 @@ double C_HTRBypass_Cycle::design_bypass_frac_return_objective_metric(const std:: //objective_metric = -temp_err; // Adjust sigmoid - objective_metric = 1 - sigmoid(temp_err); + objective_metric = calc_penalty(m_T_target, temp_calc, span); if (objective_metric > m_objective_metric_bypass_frac_opt) { @@ -1737,14 +1805,30 @@ double C_HTRBypass_Cycle::design_bypass_frac_free_var_return_objective_metric(co double penalty = 0; if (ms_opt_des_par.m_fixed_bypass_frac == false || ms_opt_des_par.m_des_objective_type == 2) { - double target_bp_out = m_T_HTF_BP_outlet_target; + double temp_calc = 0; + double span = 0; + + if (m_T_target_is_HTF == 0) + { + temp_calc = m_temp_last[MIXER_OUT]; + span = m_temp_last[TURB_IN] - m_T_target; + } + else + { + temp_calc = m_T_HTF_BP_outlet_calc; + span = m_T_HTF_PHX_inlet - m_T_target; + } + + /*double target_bp_out = m_T_HTF_BP_outlet_target; double calc_bp_out = m_T_HTF_BP_outlet_calc; double temp_err = std::abs(calc_bp_out - target_bp_out); double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; double percent_err = temp_err / temp_span; - penalty = 10.0 * (sigmoid(percent_err) - 0.5); + penalty = 10.0 * (100.0 * sigmoid(percent_err) - 0.5);*/ + + penalty = calc_penalty(m_T_target, temp_calc, span); } objective_metric = eff - penalty; diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 78740ffb79..3356d56c81 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -232,7 +232,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_m_dot_HTF; // kg/s double m_Q_dot_BP; double m_T_HTF_PHX_inlet; - double m_T_HTF_BP_outlet_target; + double m_T_target; + int m_T_target_is_HTF; double m_T_HTF_BP_outlet_calc; double m_T_HTF_PHX_out; double m_dT_BP; // BYPASS_OUT - HTR_HP_OUT @@ -240,7 +241,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_Q_dot_total; double m_HTF_BP_cold_approach; double m_HTF_PHX_cold_approach; - bool is_htf_set = false; + bool is_bp_par_set = false; double m_W_dot_air_cooler; double m_Q_dot_air_cooler; C_HX_co2_to_htf c_phx; @@ -267,6 +268,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core // Added int solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out); int solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_LP_out); + double calc_penalty(double target, double calc, double span); + std::string make_result_csv_string(); @@ -318,16 +321,9 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core } - /// - /// Set HTF parameters - /// - /// K - /// K - /// kJ/kg K - /// K - /// K - /// K - void set_htf_par(double T_htf_phx_in, double T_htf_bp_out_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot); + // Set Bypass Specific Parameters + void set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot, + int T_target_is_HTF); diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index 639c0196a7..bfdf553af1 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -185,12 +185,13 @@ void C_sco2_phx_air_cooler::design_core() double HTF_PHX_inlet = ms_des_par.m_T_htf_hot_in; double cp_htf = htf_props.Cp(HTF_PHX_inlet); - double HTF_BP_outlet = ms_des_par.m_T_htf_bypass_out; + double T_target = ms_des_par.m_T_bypass_target; + double T_target_is_htf = ms_des_par.m_T_target_is_HTF; double deltaT_bp = ms_des_par.m_deltaT_bypass; double HTF_PHX_cold_approach = ms_des_par.m_phx_dt_cold_approach; double set_HTF_mdot = ms_des_par.m_set_HTF_mdot; - c_bp_cycle->set_htf_par(HTF_PHX_inlet, HTF_BP_outlet, cp_htf, deltaT_bp, HTF_PHX_cold_approach, set_HTF_mdot); + c_bp_cycle->set_bp_par(HTF_PHX_inlet, T_target, cp_htf, deltaT_bp, HTF_PHX_cold_approach, set_HTF_mdot, T_target_is_htf); } diff --git a/tcs/sco2_pc_csp_int.h b/tcs/sco2_pc_csp_int.h index a575a71e03..0e32421a77 100644 --- a/tcs/sco2_pc_csp_int.h +++ b/tcs/sco2_pc_csp_int.h @@ -127,7 +127,8 @@ class C_sco2_phx_air_cooler // Bypass Configuration Parameters - double m_T_htf_bypass_out; // [K] HTF design Bypass Outlet + double m_T_bypass_target; // [K] Bypass Target Temperature + int m_T_target_is_HTF; // (1) BP Target is HTF temp, (0) Target is sco2 at cold bypass double m_deltaT_bypass; // [delta K] sco2 Bypass Outlet Temp - HTR_HP_OUT Temp double m_set_HTF_mdot; // [kg/s] For HTR Bypass ONLY, 0 = calculate HTF mdot (need to set dT_PHX_cold_approach), > 0 = HTF mdot kg/s From 2bbd64b7d36cf83b99d6fec38af4b71db702885c Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Tue, 20 Feb 2024 08:57:36 -0700 Subject: [PATCH 29/94] Add cmod to calculate sco2 plotting values --- ssc/CMakeLists.txt | 1 + ssc/cmod_sco2_csp_system.cpp | 4 + ssc/csp_common.cpp | 214 +++++++++++++++++++++++++++++++++++ ssc/csp_common.h | 6 +- ssc/sscapi.cpp | 2 + 5 files changed, 226 insertions(+), 1 deletion(-) diff --git a/ssc/CMakeLists.txt b/ssc/CMakeLists.txt index c64ef74aa2..1fa5798839 100644 --- a/ssc/CMakeLists.txt +++ b/ssc/CMakeLists.txt @@ -88,6 +88,7 @@ set(SSC_SRC cmod_sco2_air_cooler.cpp cmod_sco2_csp_system.cpp cmod_sco2_csp_ud_pc_tables.cpp + cmod_sco2_helper.cpp cmod_singlediode.cpp cmod_singleowner.cpp cmod_communitysolar.cpp diff --git a/ssc/cmod_sco2_csp_system.cpp b/ssc/cmod_sco2_csp_system.cpp index 045788d081..ceeea32146 100644 --- a/ssc/cmod_sco2_csp_system.cpp +++ b/ssc/cmod_sco2_csp_system.cpp @@ -1738,3 +1738,7 @@ class cm_sco2_comp_curves : public compute_module }; DEFINE_MODULE_ENTRY(sco2_comp_curves, "Calls sCO2 auto-design cycle function", 1) + + + + diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index be3a656c96..8a35956bcc 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -1911,3 +1911,217 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c return 0; } +var_info vtab_sco2_helper[] = +{ + { SSC_INPUT, SSC_NUMBER, "cycle_config", "Cycle configuration", "", "", "", "", "", "" }, + { SSC_INPUT, SSC_ARRAY, "T_state_points", "Temperature state point array", "C", "", "", "", "", "" }, + { SSC_INPUT, SSC_ARRAY, "P_state_points", "Pressure state point array", "MPa", "", "", "", "", "" }, + { SSC_INPUT, SSC_ARRAY, "s_state_points", "Entropy state point array", "kJ/kg-K", "", "", "", "", "" }, + + // T-s plot data + { SSC_OUTPUT, SSC_ARRAY, "T_LTR_HP_data", "Temperature points along LTR HP stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_LTR_HP_data", "Entropy points along LTR HP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_HTR_HP_data", "Temperature points along HTR HP stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_HTR_HP_data", "Entropy points along HTR HP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_PHX_data", "Temperature points along PHX stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_PHX_data", "Entropy points along PHX stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_HTR_LP_data", "Temperature points along HTR LP stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_HTR_LP_data", "Entropy points along HTR LP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_LTR_LP_data", "Temperature points along LTR LP stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_LTR_LP_data", "Entropy points along LTR LP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_main_cooler_data", "Temperature points along main cooler stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_main_cooler_data", "Entropy points along main cooler stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_pre_cooler_data", "Temperature points along pre cooler stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_pre_cooler_data", "Entropy points along pre cooler stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + // P-h plot data + { SSC_OUTPUT, SSC_ARRAY, "P_t_data", "Pressure points along turbine expansion", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_t_data", "Enthalpy points along turbine expansion", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_mc_data", "Pressure points along main compression", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_mc_data", "Enthalpy points along main compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_rc_data", "Pressure points along re compression", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_rc_data", "Enthalpy points along re compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_pc_data", "Pressure points along pre compression", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_pc_data", "Enthalpy points along pre compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, + + + +var_info_invalid }; + +int sco2_helper_core(compute_module* cm) +{ + int cycle_config = cm->as_integer("cycle_config"); + std::vector T_state_points_C = cm->as_vector_double("T_state_points"); + std::vector T_state_points_K; + for (double temp : T_state_points_C) + T_state_points_K.push_back(temp + 273.15); + + std::vector P_state_points_MPa = cm->as_vector_double("P_state_points"); + std::vector P_state_points_kPa; + for (double pres : P_state_points_MPa) + P_state_points_kPa.push_back(pres * 1e3); + + std::vector s_state_points = cm->as_vector_double("s_state_points"); + + // Get data for P-h cycle plot + std::vector P_t; //[MPa] + std::vector h_t; //[kJ/kg] + std::vector P_mc; //[MPa] + std::vector h_mc; //[kJ/kg] + std::vector P_rc; //[MPa] + std::vector h_rc; //[kJ/kg] + std::vector P_pc; //[MPa] + std::vector h_pc; //[kJ/kg] + int ph_err_code = sco2_cycle_plot_data_PH(cycle_config, + T_state_points_K, + P_state_points_kPa, + P_t, + h_t, + P_mc, + h_mc, + P_rc, + h_rc, + P_pc, + h_pc); + + if (ph_err_code != 0) + throw exec_error("sco2_csp_system", "cycle plot data routine failed"); + + size_t n_v = P_t.size(); + ssc_number_t* p_P_t_data = cm->allocate("P_t_data", n_v); + ssc_number_t* p_h_t_data = cm->allocate("h_t_data", n_v); + for (size_t i = 0; i < n_v; i++) + { + p_P_t_data[i] = (ssc_number_t)(P_t[i]); //[MPa] + p_h_t_data[i] = (ssc_number_t)(h_t[i]); //[kJ/kg] + } + + n_v = P_mc.size(); + ssc_number_t* p_P_mc_data = cm->allocate("P_mc_data", n_v); + ssc_number_t* p_h_mc_data = cm->allocate("h_mc_data", n_v); + for (size_t i = 0; i < n_v; i++) + { + p_P_mc_data[i] = (ssc_number_t)(P_mc[i]); //[MPa] + p_h_mc_data[i] = (ssc_number_t)(h_mc[i]); //[kJ/kg] + } + + n_v = P_rc.size(); + ssc_number_t* p_P_rc_data = cm->allocate("P_rc_data", n_v); + ssc_number_t* p_h_rc_data = cm->allocate("h_rc_data", n_v); + for (size_t i = 0; i < n_v; i++) + { + p_P_rc_data[i] = (ssc_number_t)(P_rc[i]); //[MPa] + p_h_rc_data[i] = (ssc_number_t)(h_rc[i]); //[kJ/kg] + } + + n_v = P_pc.size(); + ssc_number_t* p_P_pc_data = cm->allocate("P_pc_data", n_v); + ssc_number_t* p_h_pc_data = cm->allocate("h_pc_data", n_v); + for (size_t i = 0; i < n_v; i++) + { + p_P_pc_data[i] = (ssc_number_t)(P_pc[i]); //[MPa] + p_h_pc_data[i] = (ssc_number_t)(h_pc[i]); //[kJ/kg] + } + + // Get data for T-s cycle plot + std::vector T_LTR_HP; //[C] + std::vector s_LTR_HP; //[kJ/kg-K] + std::vector T_HTR_HP; //[C] + std::vector s_HTR_HP; //[kJ/kg-K] + std::vector T_PHX; //[C] + std::vector s_PHX; //[kJ/kg-K] + std::vector T_HTR_LP; //[C] + std::vector s_HTR_LP; //[kJ/kg-K] + std::vector T_LTR_LP; //[C] + std::vector s_LTR_LP; //[kJ/kg-K] + std::vector T_main_cooler; //[C] + std::vector s_main_cooler; //[kJ/kg-K] + std::vector T_pre_cooler; //[C] + std::vector s_pre_cooler; //[kJ/kg-K] + int plot_data_err_code = sco2_cycle_plot_data_TS(cycle_config, + P_state_points_kPa, + s_state_points, + T_LTR_HP, + s_LTR_HP, + T_HTR_HP, + s_HTR_HP, + T_PHX, + s_PHX, + T_HTR_LP, + s_HTR_LP, + T_LTR_LP, + s_LTR_LP, + T_main_cooler, + s_main_cooler, + T_pre_cooler, + s_pre_cooler); + + if (plot_data_err_code != 0) + throw exec_error("sco2_csp_system", "cycle plot data routine failed"); + + n_v = T_LTR_HP.size(); + ssc_number_t* p_T_LTR_HP_data = cm->allocate("T_LTR_HP_data", n_v); + ssc_number_t* p_s_LTR_HP_data = cm->allocate("s_LTR_HP_data", n_v); + for (size_t i = 0; i < n_v; i++) + { + p_T_LTR_HP_data[i] = (ssc_number_t)(T_LTR_HP[i]); //[C] + p_s_LTR_HP_data[i] = (ssc_number_t)(s_LTR_HP[i]); //[kJ/kg-K] + } + + n_v = T_HTR_HP.size(); + ssc_number_t* p_T_HTR_HP_data = cm->allocate("T_HTR_HP_data", n_v); + ssc_number_t* p_s_HTR_HP_data = cm->allocate("s_HTR_HP_data", n_v); + for (size_t i = 0; i < n_v; i++) + { + p_T_HTR_HP_data[i] = (ssc_number_t)(T_HTR_HP[i]); //[C] + p_s_HTR_HP_data[i] = (ssc_number_t)(s_HTR_HP[i]); //[kJ/kg-K] + } + + n_v = T_PHX.size(); + ssc_number_t* p_T_PHX_data = cm->allocate("T_PHX_data", n_v); + ssc_number_t* p_s_PHX_data = cm->allocate("s_PHX_data", n_v); + for (size_t i = 0; i < n_v; i++) + { + p_T_PHX_data[i] = (ssc_number_t)(T_PHX[i]); //[C] + p_s_PHX_data[i] = (ssc_number_t)(s_PHX[i]); //[kJ/kg-K] + } + + n_v = T_HTR_LP.size(); + ssc_number_t* p_T_HTR_LP_data = cm->allocate("T_HTR_LP_data", n_v); + ssc_number_t* p_s_HTR_LP_data = cm->allocate("s_HTR_LP_data", n_v); + for (size_t i = 0; i < n_v; i++) + { + p_T_HTR_LP_data[i] = (ssc_number_t)(T_HTR_LP[i]); //[C] + p_s_HTR_LP_data[i] = (ssc_number_t)(s_HTR_LP[i]); //[kJ/kg-K] + } + + n_v = T_LTR_LP.size(); + ssc_number_t* p_T_LTR_LP_data = cm->allocate("T_LTR_LP_data", n_v); + ssc_number_t* p_s_LTR_LP_data = cm->allocate("s_LTR_LP_data", n_v); + for (size_t i = 0; i < n_v; i++) + { + p_T_LTR_LP_data[i] = (ssc_number_t)(T_LTR_LP[i]); //[C] + p_s_LTR_LP_data[i] = (ssc_number_t)(s_LTR_LP[i]); //[kJ/kg-K] + } + + n_v = T_main_cooler.size(); + ssc_number_t* p_T_main_cooler = cm->allocate("T_main_cooler_data", n_v); + ssc_number_t* p_s_main_cooler = cm->allocate("s_main_cooler_data", n_v); + for (size_t i = 0; i < n_v; i++) + { + p_T_main_cooler[i] = (ssc_number_t)(T_main_cooler[i]); //[C] + p_s_main_cooler[i] = (ssc_number_t)(s_main_cooler[i]); //[kJ/kg-K] + } + + n_v = T_pre_cooler.size(); + ssc_number_t* p_T_pre_cooler = cm->allocate("T_pre_cooler_data", n_v); + ssc_number_t* p_s_pre_cooler = cm->allocate("s_pre_cooler_data", n_v); + for (size_t i = 0; i < n_v; i++) + { + p_T_pre_cooler[i] = (ssc_number_t)(T_pre_cooler[i]); //[C] + p_s_pre_cooler[i] = (ssc_number_t)(s_pre_cooler[i]); //[kJ/kg-K] + } + + + + return 0; +} diff --git a/ssc/csp_common.h b/ssc/csp_common.h index e876b88223..d9e12ada65 100644 --- a/ssc/csp_common.h +++ b/ssc/csp_common.h @@ -85,6 +85,10 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c +#endif + +extern var_info vtab_sco2_helper[]; + +int sco2_helper_core(compute_module* cm); -#endif diff --git a/ssc/sscapi.cpp b/ssc/sscapi.cpp index 75f9e751ab..0550b99f0a 100644 --- a/ssc/sscapi.cpp +++ b/ssc/sscapi.cpp @@ -139,6 +139,7 @@ extern module_entry_info cm_entry_sco2_csp_ud_pc_tables, cm_entry_sco2_air_cooler, cm_entry_sco2_comp_curves, + cm_entry_sco2_helper, cm_entry_test_ud_power_cycle, cm_entry_user_htf_comparison, cm_entry_ui_tes_calcs, @@ -239,6 +240,7 @@ static module_entry_info *module_table[] = { &cm_entry_sco2_csp_ud_pc_tables, &cm_entry_sco2_air_cooler, &cm_entry_sco2_comp_curves, + &cm_entry_sco2_helper, &cm_entry_test_ud_power_cycle, &cm_entry_user_htf_comparison, &cm_entry_ui_tes_calcs, From c359ef6da0c1f442b4df29548db3d250e2ab2cb6 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Tue, 20 Feb 2024 12:36:16 -0700 Subject: [PATCH 30/94] Add sco2_helper cmod to correct folder --- ssc/cmod_sco2_helper.cpp | 56 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 ssc/cmod_sco2_helper.cpp diff --git a/ssc/cmod_sco2_helper.cpp b/ssc/cmod_sco2_helper.cpp new file mode 100644 index 0000000000..20e1a74100 --- /dev/null +++ b/ssc/cmod_sco2_helper.cpp @@ -0,0 +1,56 @@ +/* +BSD 3-Clause License + +Copyright (c) Alliance for Sustainable Energy, LLC. See also https://github.com/NREL/ssc/blob/develop/LICENSE +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "core.h" +#include "common.h" + +#include "csp_common.h" + + + + +class cm_sco2_helper : public compute_module +{ +public: + + cm_sco2_helper() + { + add_var_info(vtab_sco2_helper); + } + + void exec() override + { + sco2_helper_core(this); + } +}; + +DEFINE_MODULE_ENTRY(sco2_helper, "...", 0) \ No newline at end of file From f1f44c483391b6123224e6fca65faa7fa0463445 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Tue, 5 Mar 2024 13:18:40 -0700 Subject: [PATCH 31/94] Begin creating stand alone htr bp design point model --- tcs/sco2_htrbypass_cycle.cpp | 739 ++++++++++++++++++++++++++++++++++- tcs/sco2_htrbypass_cycle.h | 193 +++++++++ 2 files changed, 931 insertions(+), 1 deletion(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 7a10f5017b..8817991613 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -39,9 +39,747 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "fmin.h" +// ********************************************************************************** C_sco2_htrbp_core CORE MODEL + +int C_sco2_htrbp_core::Solve() +{ + InitializeSolve(); + m_error_code = -1; + + // Apply scaling to the turbomachinery here + { + m_mc_ms.m_r_W_dot_scale = m_inputs.m_W_dot_net_design / 10.E3; //[-] + m_rc_ms.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] + m_t.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] + } + + // Initialize Recuperators + { + // LTR + mc_LT_recup.initialize(m_inputs.m_LTR_N_sub_hxrs, m_inputs.m_LTR_od_UA_target_type); + // HTR + mc_HT_recup.initialize(m_inputs.m_HTR_N_sub_hxrs, m_inputs.m_HTR_od_UA_target_type); + } + + // Initialize a few variables + { + m_temp[C_sco2_cycle_core::MC_IN] = m_inputs.m_T_mc_in; //[K] + m_pres[C_sco2_cycle_core::MC_IN] = m_inputs.m_P_mc_in; + m_pres[C_sco2_cycle_core::MC_OUT] = m_inputs.m_P_mc_out; + m_temp[C_sco2_cycle_core::TURB_IN] = m_inputs.m_T_t_in; //[K] + } + + // Apply pressure drops to heat exchangers, fully defining the pressures at all states + { + if (m_inputs.m_DP_LTR[0] < 0.0) + m_pres[C_sco2_cycle_core::LTR_HP_OUT] = m_pres[C_sco2_cycle_core::MC_OUT] - m_pres[C_sco2_cycle_core::MC_OUT] * std::abs(m_inputs.m_DP_LTR[0]); // relative pressure drop specified for LT recuperator (cold stream) + else + m_pres[C_sco2_cycle_core::LTR_HP_OUT] = m_pres[C_sco2_cycle_core::MC_OUT] - m_inputs.m_DP_LTR[0]; // absolute pressure drop specified for LT recuperator (cold stream) + + if ((m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && m_inputs.m_LTR_UA < 1.0E-12) + || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && m_inputs.m_LTR_UA < 1.0E-12) + || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && m_inputs.m_LTR_min_dT < 1.0E-12) + || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && m_inputs.m_LTR_eff_target < 1.0E-12)) + m_pres[C_sco2_cycle_core::LTR_HP_OUT] = m_pres[C_sco2_cycle_core::MC_OUT]; // If there is no LT recuperator, there is no pressure drop + + m_pres[C_sco2_cycle_core::MIXER_OUT] = m_pres[C_sco2_cycle_core::LTR_HP_OUT]; // Assume no pressure drop in mixing valve + m_pres[C_sco2_cycle_core::RC_OUT] = m_pres[C_sco2_cycle_core::LTR_HP_OUT]; // Assume no pressure drop in mixing valve + + if (m_inputs.m_DP_HTR[0] < 0.0) + m_pres[C_sco2_cycle_core::HTR_HP_OUT] = m_pres[C_sco2_cycle_core::MIXER_OUT] + - m_pres[C_sco2_cycle_core::MIXER_OUT] * std::abs(m_inputs.m_DP_HTR[0]); // relative pressure drop specified for HT recuperator (cold stream) + else + m_pres[C_sco2_cycle_core::HTR_HP_OUT] = m_pres[C_sco2_cycle_core::MIXER_OUT] - m_inputs.m_DP_HTR[0]; // absolute pressure drop specified for HT recuperator (cold stream) + + if ((m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && m_inputs.m_HTR_UA < 1.0E-12) + || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && m_inputs.m_HTR_UA < 1.0E-12) + || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && m_inputs.m_HTR_min_dT < 1.0E-12) + || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && m_inputs.m_HTR_eff_target < 1.0E-12)) + m_pres[C_sco2_cycle_core::HTR_HP_OUT] = m_pres[C_sco2_cycle_core::MIXER_OUT]; // If there is no HT recuperator, there is no pressure drop + + if (m_inputs.m_DP_PHX[0] < 0.0) + m_pres[C_sco2_cycle_core::TURB_IN] = m_pres[C_sco2_cycle_core::HTR_HP_OUT] - m_pres[C_sco2_cycle_core::HTR_HP_OUT] * std::abs(m_inputs.m_DP_PHX[0]); // relative pressure drop specified for PHX + else + m_pres[C_sco2_cycle_core::TURB_IN] = m_pres[C_sco2_cycle_core::HTR_HP_OUT] - m_inputs.m_DP_PHX[0]; // absolute pressure drop specified for PHX + + if (m_inputs.m_DP_PC_main[1] < 0.0) + m_pres[C_sco2_cycle_core::LTR_LP_OUT] = m_pres[C_sco2_cycle_core::MC_IN] / (1.0 - std::abs(m_inputs.m_DP_PC_main[1])); // relative pressure drop specified for precooler: P1=P9-P9*rel_DP => P1=P9*(1-rel_DP) + else + m_pres[C_sco2_cycle_core::LTR_LP_OUT] = m_pres[C_sco2_cycle_core::MC_IN] + m_inputs.m_DP_PC_main[1]; + + if (m_inputs.m_DP_LTR[1] < 0.0) + m_pres[C_sco2_cycle_core::HTR_LP_OUT] = m_pres[C_sco2_cycle_core::LTR_LP_OUT] / (1.0 - std::abs(m_inputs.m_DP_LTR[1])); // relative pressure drop specified for LT recuperator (hot stream) + else + m_pres[C_sco2_cycle_core::HTR_LP_OUT] = m_pres[C_sco2_cycle_core::LTR_LP_OUT] + m_inputs.m_DP_LTR[1]; // absolute pressure drop specified for LT recuperator (hot stream) + + if ((m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && m_inputs.m_LTR_UA < 1.0E-12) + || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && m_inputs.m_LTR_UA < 1.0E-12) + || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && m_inputs.m_LTR_min_dT < 1.0E-12) + || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && m_inputs.m_LTR_eff_target < 1.0E-12)) + m_pres[C_sco2_cycle_core::HTR_LP_OUT] = m_pres[C_sco2_cycle_core::LTR_LP_OUT]; // if there is no LT recuperator, there is no pressure drop + + if (m_inputs.m_DP_HTR[1] < 0.0) + m_pres[C_sco2_cycle_core::TURB_OUT] = m_pres[C_sco2_cycle_core::HTR_LP_OUT] / (1.0 - std::abs(m_inputs.m_DP_HTR[1])); // relative pressure drop specified for HT recuperator (hot stream) + else + m_pres[C_sco2_cycle_core::TURB_OUT] = m_pres[C_sco2_cycle_core::HTR_LP_OUT] + m_inputs.m_DP_HTR[1]; // absolute pressure drop specified for HT recuperator (hot stream) + + if ((m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && m_inputs.m_HTR_UA < 1.0E-12) + || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && m_inputs.m_HTR_UA < 1.0E-12) + || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && m_inputs.m_HTR_min_dT < 1.0E-12) + || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && m_inputs.m_HTR_eff_target < 1.0E-12)) + m_pres[C_sco2_cycle_core::TURB_OUT] = m_pres[C_sco2_cycle_core::HTR_LP_OUT]; // if there is no HT recuperator, there is no pressure drop + + + // Added pressures + m_pres[C_sco2_cycle_core::BYPASS_OUT] = m_pres[C_sco2_cycle_core::HTR_HP_OUT]; + m_pres[C_sco2_cycle_core::MIXER2_OUT] = m_pres[C_sco2_cycle_core::HTR_HP_OUT]; + + + } + + // Determine equivalent isentropic efficiencies for main compressor and turbine, if necessary. + double eta_mc_isen = std::numeric_limits::quiet_NaN(); + double eta_t_isen = std::numeric_limits::quiet_NaN(); + { + if (m_inputs.m_eta_mc < 0.0) + { + int poly_error_code = 0; + + isen_eta_from_poly_eta(m_temp[C_sco2_cycle_core::MC_IN], m_pres[C_sco2_cycle_core::MC_IN], m_pres[C_sco2_cycle_core::MC_OUT], std::abs(m_inputs.m_eta_mc), + true, poly_error_code, eta_mc_isen); + + if (poly_error_code != 0) + { + m_error_code = poly_error_code; + return m_error_code; + } + } + else + eta_mc_isen = m_inputs.m_eta_mc; + + if (m_inputs.m_eta_t < 0.0) + { + int poly_error_code = 0; + + isen_eta_from_poly_eta(m_temp[C_sco2_cycle_core::TURB_IN], m_pres[C_sco2_cycle_core::TURB_IN], m_pres[C_sco2_cycle_core::TURB_OUT], std::abs(m_inputs.m_eta_t), + false, poly_error_code, eta_t_isen); + + if (poly_error_code != 0) + { + m_error_code = poly_error_code; + return m_error_code; + } + } + else + eta_t_isen = m_inputs.m_eta_t; + } + + // Determine the outlet state and specific work for the main compressor and turbine. + + // Main compressor + m_w_mc = std::numeric_limits::quiet_NaN(); + { + int comp_error_code = 0; + + calculate_turbomachinery_outlet_1(m_temp[C_sco2_cycle_core::MC_IN], m_pres[C_sco2_cycle_core::MC_IN], m_pres[C_sco2_cycle_core::MC_OUT], eta_mc_isen, true, + comp_error_code, m_enth[C_sco2_cycle_core::MC_IN], m_entr[C_sco2_cycle_core::MC_IN], m_dens[C_sco2_cycle_core::MC_IN], m_temp[C_sco2_cycle_core::MC_OUT], + m_enth[C_sco2_cycle_core::MC_OUT], m_entr[C_sco2_cycle_core::MC_OUT], m_dens[C_sco2_cycle_core::MC_OUT], m_w_mc); + + if (comp_error_code != 0) + { + m_error_code = comp_error_code; + return m_error_code; + } + } + + // Turbine + m_w_t = std::numeric_limits::quiet_NaN(); + { + int turbine_error_code = 0; + + calculate_turbomachinery_outlet_1(m_temp[C_sco2_cycle_core::TURB_IN], m_pres[C_sco2_cycle_core::TURB_IN], m_pres[C_sco2_cycle_core::TURB_OUT], eta_t_isen, false, + turbine_error_code, m_enth[C_sco2_cycle_core::TURB_IN], m_entr[C_sco2_cycle_core::TURB_IN], m_dens[C_sco2_cycle_core::TURB_IN], m_temp[C_sco2_cycle_core::TURB_OUT], + m_enth[C_sco2_cycle_core::TURB_OUT], m_entr[C_sco2_cycle_core::TURB_OUT], m_dens[C_sco2_cycle_core::TURB_OUT], m_w_t); + + if (turbine_error_code != 0) + { + m_error_code = turbine_error_code; + return m_error_code; + } + } + + // Check that this cycle can produce power + m_w_rc = std::numeric_limits::quiet_NaN(); + { + double eta_rc_isen = std::numeric_limits::quiet_NaN(); + + if (m_inputs.m_recomp_frac >= 1.E-12) + { + if (m_inputs.m_eta_rc < 0.0) // need to convert polytropic efficiency to isentropic efficiency + { + int rc_error_code = 0; + + isen_eta_from_poly_eta(m_temp[C_sco2_cycle_core::MC_OUT], m_pres[C_sco2_cycle_core::LTR_LP_OUT], m_pres[C_sco2_cycle_core::RC_OUT], std::abs(m_inputs.m_eta_rc), + true, rc_error_code, eta_rc_isen); + + if (rc_error_code != 0) + { + m_error_code = rc_error_code; + return m_error_code; + } + } + else + eta_rc_isen = m_inputs.m_eta_rc; + + int rc_error_code = 0; + + calculate_turbomachinery_outlet_1(m_temp[C_sco2_cycle_core::MC_OUT], m_pres[C_sco2_cycle_core::LTR_LP_OUT], m_pres[C_sco2_cycle_core::RC_OUT], eta_rc_isen, + true, rc_error_code, m_w_rc); + + if (rc_error_code != 0) + { + m_error_code = rc_error_code; + return m_error_code; + } + } + else + m_w_rc = 0.0; + + if (m_w_mc + m_w_rc + m_w_t <= 0.0) // positive net power is impossible; return an error + { + m_error_code = 25; + return m_error_code; + } + } + + // Solve the recuperators + { + C_mono_htrbp_core_HTR_des HTR_des_eq(this); + C_monotonic_eq_solver HTR_des_solver(HTR_des_eq); + + { + double T_HTR_LP_out_lower = m_temp[C_sco2_cycle_core::MC_OUT]; //[K] Coldest possible temperature + double T_HTR_LP_out_upper = m_temp[C_sco2_cycle_core::TURB_OUT]; //[K] Hottest possible temperature + + double T_HTR_LP_out_guess_lower = std::min(T_HTR_LP_out_upper - 2.0, std::max(T_HTR_LP_out_lower + 15.0, 220.0 + 273.15)); //[K] There is nothing special about these guesses... + double T_HTR_LP_out_guess_upper = std::min(T_HTR_LP_out_guess_lower + 20.0, T_HTR_LP_out_upper - 1.0); //[K] There is nothing special about these guesses, either... + + HTR_des_solver.settings(m_inputs.m_des_tol * m_temp[C_sco2_cycle_core::MC_IN], 1000, T_HTR_LP_out_lower, T_HTR_LP_out_upper, false); + + double T_HTR_LP_out_solved, tol_T_HTR_LP_out_solved; + T_HTR_LP_out_solved = tol_T_HTR_LP_out_solved = std::numeric_limits::quiet_NaN(); + int iter_T_HTR_LP_out = -1; + + int T_HTR_LP_out_code = HTR_des_solver.solve(T_HTR_LP_out_guess_lower, T_HTR_LP_out_guess_upper, 0, + T_HTR_LP_out_solved, tol_T_HTR_LP_out_solved, iter_T_HTR_LP_out); + + if (T_HTR_LP_out_code != C_monotonic_eq_solver::CONVERGED) + { + m_error_code = 35; + return m_error_code; + } + + double test = 0; + solve_HTR(T_HTR_LP_out_solved, &test); + } + + } + + // State 5 can now be fully defined + { + // Check if there is flow through HTR_HP + if (m_m_dot_htr_hp <= 1e-12) + m_enth[C_sco2_cycle_core::HTR_HP_OUT] = m_enth[C_sco2_cycle_core::MIXER_OUT]; + else + m_enth[C_sco2_cycle_core::HTR_HP_OUT] = m_enth[C_sco2_cycle_core::MIXER_OUT] + m_Q_dot_HT / m_m_dot_htr_hp; // Energy balance on cold stream of high-temp recuperator + + int prop_error_code = CO2_PH(m_pres[C_sco2_cycle_core::HTR_HP_OUT], m_enth[C_sco2_cycle_core::HTR_HP_OUT], &m_co2_props); + if (prop_error_code != 0) + { + m_error_code = prop_error_code; + return m_error_code; + } + m_temp[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.temp; + m_entr[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.entr; + m_dens[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.dens; + } + + // Calculate total work and heat metrics + { + // Work + m_W_dot_mc = m_w_mc * m_m_dot_mc; //[kWe] + m_W_dot_rc = m_w_rc * m_m_dot_rc; //[kWe] + m_W_dot_t = m_w_t * m_m_dot_t; //[kWe] + m_W_dot_net = m_W_dot_mc + m_W_dot_rc + m_W_dot_t; + + // Air Cooler (heat rejection unit) + m_W_dot_air_cooler = m_inputs.m_frac_fan_power * m_W_dot_net; + m_Q_dot_air_cooler = m_m_dot_mc * (m_enth[C_sco2_cycle_core::LTR_LP_OUT] - m_enth[C_sco2_cycle_core::MC_IN]); + + // Total Heat Entering sco2 + m_Q_dot_total = m_W_dot_net + m_Q_dot_air_cooler; + + // LTR + m_Q_dot_LTR_LP = m_m_dot_t * (m_enth[C_sco2_cycle_core::HTR_LP_OUT] - m_enth[C_sco2_cycle_core::LTR_LP_OUT]); + m_Q_dot_LTR_HP = m_m_dot_mc * (m_enth[C_sco2_cycle_core::LTR_HP_OUT] - m_enth[C_sco2_cycle_core::MC_OUT]); + + // LTR + m_Q_dot_HTR_LP = m_m_dot_t * (m_enth[C_sco2_cycle_core::TURB_OUT] - m_enth[C_sco2_cycle_core::HTR_LP_OUT]); + m_Q_dot_HTR_HP = m_m_dot_htr_hp * (m_enth[C_sco2_cycle_core::HTR_HP_OUT] - m_enth[C_sco2_cycle_core::MIXER_OUT]); + } + + // Calculate Bypass Energy + { + // Set Bypass Temp based on HTR_HP_OUT + m_temp[C_sco2_cycle_core::BYPASS_OUT] = m_temp[C_sco2_cycle_core::HTR_HP_OUT] + m_inputs.m_dT_BP; + + // Calculate BYPASS_OUT properties + int prop_error_code = CO2_TP(this->m_temp[C_sco2_cycle_core::BYPASS_OUT], this->m_pres[C_sco2_cycle_core::BYPASS_OUT], &this->m_co2_props); + if (prop_error_code != 0) + { + m_error_code = -1; + return m_error_code; + } + this->m_enth[C_sco2_cycle_core::BYPASS_OUT] = this->m_co2_props.enth; + this->m_entr[C_sco2_cycle_core::BYPASS_OUT] = this->m_co2_props.entr; + this->m_dens[C_sco2_cycle_core::BYPASS_OUT] = this->m_co2_props.dens; + + // Calculate Heat Transfer in Bypass + m_Q_dot_BP = m_m_dot_bp * (m_enth[C_sco2_cycle_core::BYPASS_OUT] - m_enth[C_sco2_cycle_core::MIXER_OUT]); + } + + // Simulate Mixer 2 + { + // If Bypass and HTR have flow + if (m_inputs.m_bypass_frac >= 1e-12 && m_inputs.m_bypass_frac <= (1.0 - 1e-12)) + { + m_enth[C_sco2_cycle_core::MIXER2_OUT] = (1.0 - m_inputs.m_bypass_frac) * m_enth[C_sco2_cycle_core::HTR_HP_OUT] + + m_inputs.m_bypass_frac * m_enth[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::kJ/kg] + + int prop_error_code = CO2_PH(m_pres[C_sco2_cycle_core::MIXER2_OUT], m_enth[C_sco2_cycle_core::MIXER2_OUT], &m_co2_props); + if (prop_error_code != 0) + { + m_error_code = -1; + return m_error_code; + } + m_temp[C_sco2_cycle_core::MIXER2_OUT] = m_co2_props.temp; //[C_sco2_cycle_core::K] + m_entr[C_sco2_cycle_core::MIXER2_OUT] = m_co2_props.entr; //[C_sco2_cycle_core::kJ/kg-K] + m_dens[C_sco2_cycle_core::MIXER2_OUT] = m_co2_props.dens; //[C_sco2_cycle_core::kg/m^3] + + } + // Flow only through HTR + else if (m_inputs.m_bypass_frac <= (1.0 - 1e-12)) + { + m_temp[C_sco2_cycle_core::MIXER2_OUT] = m_temp[C_sco2_cycle_core::HTR_HP_OUT]; //[C_sco2_cycle_core::K] + m_enth[C_sco2_cycle_core::MIXER2_OUT] = m_enth[C_sco2_cycle_core::HTR_HP_OUT]; //[C_sco2_cycle_core::kJ/kg] + m_entr[C_sco2_cycle_core::MIXER2_OUT] = m_entr[C_sco2_cycle_core::HTR_HP_OUT]; //[C_sco2_cycle_core::kJ/kg-K] + m_dens[C_sco2_cycle_core::MIXER2_OUT] = m_dens[C_sco2_cycle_core::HTR_HP_OUT]; //[C_sco2_cycle_core::kg/m^3] + } + // Flow only through Bypass + else + { + m_temp[C_sco2_cycle_core::MIXER2_OUT] = m_temp[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::K] + m_enth[C_sco2_cycle_core::MIXER2_OUT] = m_enth[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::kJ/kg] + m_entr[C_sco2_cycle_core::MIXER2_OUT] = m_entr[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::kJ/kg-K] + m_dens[C_sco2_cycle_core::MIXER2_OUT] = m_dens[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::kg/m^3] + } + } + + // Calculate PHX Heat Transfer + { + m_Q_dot_PHX = m_m_dot_t * (m_enth[C_sco2_cycle_core::TURB_IN] - m_enth[C_sco2_cycle_core::MIXER2_OUT]); + } + + // Back Calculate and Check values + { + // Bypass Temps + double bp_temp_in = m_temp[C_sco2_cycle_core::MIXER_OUT]; + double bp_temp_out = m_temp[C_sco2_cycle_core::BYPASS_OUT]; + + double real_q_dot_total = m_W_dot_t + m_Q_dot_air_cooler; + + double qSum = m_Q_dot_total; + double qSum_calc = m_Q_dot_BP + m_Q_dot_PHX; + + int x = 0; + } + + // HTF + { + // Check if HTF mdot is already assigned + if (m_inputs.m_set_HTF_mdot > 0) + { + // Mdot is Set + m_m_dot_HTF = m_inputs.m_set_HTF_mdot; + + // Calculate PHX HTF Outlet Temperature + m_T_HTF_PHX_out = m_inputs.m_T_HTF_PHX_inlet - m_Q_dot_PHX / (m_m_dot_HTF * m_inputs.m_cp_HTF); + + // Back Calculate PHX cold approach + m_HTF_PHX_cold_approach = m_T_HTF_PHX_out - m_temp[C_sco2_cycle_core::MIXER2_OUT]; + } + else + { + // Use HTF Bypass cold approach to calculate PHX outlet Temperature + m_T_HTF_PHX_out = m_HTF_PHX_cold_approach + m_temp[C_sco2_cycle_core::MIXER2_OUT]; + + // Calculate HTF mdot + m_m_dot_HTF = m_Q_dot_PHX / ((m_inputs.m_T_HTF_PHX_inlet - m_T_HTF_PHX_out) * m_inputs.m_cp_HTF); + } + + // Calculate Bypass Out Temperature + m_T_HTF_BP_outlet = m_T_HTF_PHX_out - (m_Q_dot_BP / (m_m_dot_HTF * m_inputs.m_cp_HTF)); + + // Calculate HTF Bypass Cold Approach + m_HTF_BP_cold_approach = m_T_HTF_BP_outlet - m_temp[C_sco2_cycle_core::MIXER_OUT]; + + } + + // Define Heat Exchangers and Air Cooler + { + // PHX + C_HeatExchanger::S_design_parameters PHX_des_par; + PHX_des_par.m_DP_design[0] = m_pres[C_sco2_cycle_core::MIXER2_OUT] - m_pres[C_sco2_cycle_core::TURB_IN]; + PHX_des_par.m_DP_design[1] = 0.0; + PHX_des_par.m_m_dot_design[0] = m_m_dot_t; + PHX_des_par.m_m_dot_design[1] = 0.0; + PHX_des_par.m_Q_dot_design = m_m_dot_t * (m_enth[C_sco2_cycle_core::TURB_IN] - m_enth[C_sco2_cycle_core::MIXER2_OUT]); + m_PHX.initialize(PHX_des_par); + + // BPX + C_HeatExchanger::S_design_parameters BPX_des_par; + BPX_des_par.m_DP_design[0] = m_pres[C_sco2_cycle_core::MIXER_OUT] - m_pres[C_sco2_cycle_core::BYPASS_OUT]; + BPX_des_par.m_DP_design[1] = 0.0; + BPX_des_par.m_m_dot_design[0] = m_m_dot_bp; + BPX_des_par.m_m_dot_design[1] = 0.0; + BPX_des_par.m_Q_dot_design = m_m_dot_bp * (m_enth[C_sco2_cycle_core::BYPASS_OUT] - m_enth[C_sco2_cycle_core::MIXER_OUT]); + m_BPX.initialize(BPX_des_par); + + // Design air cooler + // Structure for design parameters that are dependent on cycle design solution + C_CO2_to_air_cooler::S_des_par_cycle_dep s_air_cooler_des_par_dep; + // Set air cooler design parameters that are dependent on the cycle design solution + s_air_cooler_des_par_dep.m_T_hot_in_des = m_temp[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT]; //[K] + s_air_cooler_des_par_dep.m_P_hot_in_des = m_pres[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT]; //[kPa] + s_air_cooler_des_par_dep.m_m_dot_total = m_m_dot_mc; //[kg/s] + + // This pressure drop is currently uncoupled from the cycle design + double cooler_deltaP = m_pres[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT] - m_pres[C_sco2_cycle_core::C_sco2_cycle_core::MC_IN]; //[kPa] + if (cooler_deltaP == 0.0) + s_air_cooler_des_par_dep.m_delta_P_des = m_inputs.m_deltaP_cooler_frac * m_pres[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT]; //[kPa] + else + s_air_cooler_des_par_dep.m_delta_P_des = cooler_deltaP; //[kPa] + + s_air_cooler_des_par_dep.m_T_hot_out_des = m_temp[C_sco2_cycle_core::C_sco2_cycle_core::MC_IN]; //[K] + s_air_cooler_des_par_dep.m_W_dot_fan_des = m_W_dot_air_cooler / 1000.0; //[MWe] + // Structure for design parameters that are independent of cycle design solution + C_CO2_to_air_cooler::S_des_par_ind s_air_cooler_des_par_ind; + s_air_cooler_des_par_ind.m_T_amb_des = m_inputs.m_T_amb_des; //[K] + s_air_cooler_des_par_ind.m_elev = m_inputs.m_elevation; //[m] + s_air_cooler_des_par_ind.m_eta_fan = m_inputs.m_eta_fan; //[-] + s_air_cooler_des_par_ind.m_N_nodes_pass = m_inputs.m_N_nodes_pass; //[-] + + } + + // Calculate Thermal Efficiency + { + m_eta_thermal = m_W_dot_net / m_Q_dot_total; + } + + m_error_code = 0; + return m_error_code; +} + +int C_sco2_htrbp_core::C_mono_htrbp_core_HTR_des::operator()(double T_HTR_LP_OUT_guess /*K*/, double* diff_T_HTR_LP_out) +{ + return m_htr_bypass_cycle->solve_HTR(T_HTR_LP_OUT_guess, diff_T_HTR_LP_out); +} + +int C_sco2_htrbp_core::C_mono_htrbp_core_LTR_des::operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out) +{ + return m_htr_bypass_cycle->solve_LTR(T_LTR_LP_OUT_guess, diff_T_LTR_LP_out); +} + +int C_sco2_htrbp_core::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out) +{ + m_w_rc = m_m_dot_t = m_m_dot_rc = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT = std::numeric_limits::quiet_NaN(); + + // Set temperature guess + m_temp[C_sco2_cycle_core::HTR_LP_OUT] = T_HTR_LP_OUT_guess; //[K] + + // Solve HTR_LP_OUT properties + { + int prop_error_code = CO2_TP(this->m_temp[C_sco2_cycle_core::HTR_LP_OUT], this->m_pres[C_sco2_cycle_core::HTR_LP_OUT], &this->m_co2_props); + if (prop_error_code != 0) + { + *diff_T_HTR_LP_out = std::numeric_limits::quiet_NaN(); + return prop_error_code; + } + this->m_enth[C_sco2_cycle_core::HTR_LP_OUT] = this->m_co2_props.enth; + this->m_entr[C_sco2_cycle_core::HTR_LP_OUT] = this->m_co2_props.entr; + this->m_dens[C_sco2_cycle_core::HTR_LP_OUT] = this->m_co2_props.dens; + } + + // Solve for the LTR solution + { + double T_LTR_LP_out_lower = this->m_temp[C_sco2_cycle_core::MC_OUT]; //[K] Coldest possible outlet temperature + double T_LTR_LP_out_upper = this->m_temp[C_sco2_cycle_core::HTR_LP_OUT]; //[K] Hottest possible outlet temperature + + double T_LTR_LP_out_guess_upper = std::min(T_LTR_LP_out_upper, T_LTR_LP_out_lower + 15.0); //[K] There is nothing special about using 15 here... + double T_LTR_LP_out_guess_lower = std::min(T_LTR_LP_out_guess_upper * 0.99, T_LTR_LP_out_lower + 2.0); //[K] There is nothing special about using 2 here... + + C_mono_htrbp_core_LTR_des LTR_des_eq(this); + C_monotonic_eq_solver LTR_des_solver(LTR_des_eq); + + LTR_des_solver.settings(this->m_inputs.m_des_tol * this->m_temp[C_sco2_cycle_core::MC_IN], 1000, T_LTR_LP_out_lower, + T_LTR_LP_out_upper, false); + + double T_LTR_LP_out_solved = std::numeric_limits::quiet_NaN(); + double tol_T_LTR_LP_out_solved = std::numeric_limits::quiet_NaN(); + int iter_T_LTR_LP_out = -1; + + int T_LTR_LP_out_code = LTR_des_solver.solve(T_LTR_LP_out_guess_lower, T_LTR_LP_out_guess_upper, 0, T_LTR_LP_out_solved, + tol_T_LTR_LP_out_solved, iter_T_LTR_LP_out); + + if (T_LTR_LP_out_code != C_monotonic_eq_solver::CONVERGED) + { + return 31; + } + } + + // Know LTR performance so we can calculate the HP outlet (Energy balance on LTR HP stream) + { + this->m_enth[C_sco2_cycle_core::LTR_HP_OUT] = this->m_enth[C_sco2_cycle_core::MC_OUT] + m_Q_dot_LT / m_m_dot_mc; //[kJ/kg] + int prop_error_code = CO2_PH(this->m_pres[C_sco2_cycle_core::LTR_HP_OUT], this->m_enth[C_sco2_cycle_core::LTR_HP_OUT], &this->m_co2_props); + if (prop_error_code != 0) + { + *diff_T_HTR_LP_out = std::numeric_limits::quiet_NaN(); + return prop_error_code; + } + this->m_temp[C_sco2_cycle_core::LTR_HP_OUT] = this->m_co2_props.temp; //[K] + this->m_entr[C_sco2_cycle_core::LTR_HP_OUT] = this->m_co2_props.entr; //[kJ/kg-K] + this->m_dens[C_sco2_cycle_core::LTR_HP_OUT] = this->m_co2_props.dens; //[kg/m^3] + } + + // Simulate the Mixer + if (this->m_inputs.m_recomp_frac >= 1.E-12) + { + this->m_enth[C_sco2_cycle_core::MIXER_OUT] = (1.0 - this->m_inputs.m_recomp_frac) * this->m_enth[C_sco2_cycle_core::LTR_HP_OUT] + + this->m_inputs.m_recomp_frac * this->m_enth[C_sco2_cycle_core::RC_OUT]; //[kJ/kg] + int prop_error_code = CO2_PH(this->m_pres[C_sco2_cycle_core::MIXER_OUT], this->m_enth[C_sco2_cycle_core::MIXER_OUT], &this->m_co2_props); + if (prop_error_code != 0) + { + *diff_T_HTR_LP_out = std::numeric_limits::quiet_NaN(); + return prop_error_code; + } + this->m_temp[C_sco2_cycle_core::MIXER_OUT] = this->m_co2_props.temp; //[K] + this->m_entr[C_sco2_cycle_core::MIXER_OUT] = this->m_co2_props.entr; //[kJ/kg-K] + this->m_dens[C_sco2_cycle_core::MIXER_OUT] = this->m_co2_props.dens; //[kg/m^3] + } + else + { // No recompressor, so no mixing required, and HTR HP inlet = LTR HP outlet + this->m_temp[C_sco2_cycle_core::MIXER_OUT] = this->m_temp[C_sco2_cycle_core::LTR_HP_OUT]; //[K] + this->m_enth[C_sco2_cycle_core::MIXER_OUT] = this->m_enth[C_sco2_cycle_core::LTR_HP_OUT]; //[kJ/kg] + this->m_entr[C_sco2_cycle_core::MIXER_OUT] = this->m_entr[C_sco2_cycle_core::LTR_HP_OUT]; //[kJ/kg-K] + this->m_dens[C_sco2_cycle_core::MIXER_OUT] = this->m_dens[C_sco2_cycle_core::LTR_HP_OUT]; //[kg/m^3] + } + + // Solve Mass Flow rates for HTR_HP_OUT and Bypass + { + m_m_dot_bp = m_inputs.m_bypass_frac * m_m_dot_t; + m_m_dot_htr_hp = m_m_dot_t - m_m_dot_bp; + } + + // Find the design solution of the HTR + double T_HTR_LP_out_calc = std::numeric_limits::quiet_NaN(); + { + // If there is no flow through HTR HP side + if (m_m_dot_htr_hp < 1e-12) + { + m_Q_dot_HT = 0; + T_HTR_LP_out_calc = m_temp[C_sco2_cycle_core::TURB_OUT]; + } + + // If there is flow through HTR HP side + else + { + this->mc_HT_recup.design_for_target__calc_outlet(this->m_inputs.m_HTR_target_code, + this->m_inputs.m_HTR_UA, this->m_inputs.m_HTR_min_dT, this->m_inputs.m_HTR_eff_target, + this->m_inputs.m_HTR_eff_max, + this->m_temp[C_sco2_cycle_core::MIXER_OUT], this->m_pres[C_sco2_cycle_core::MIXER_OUT], m_m_dot_htr_hp, this->m_pres[C_sco2_cycle_core::HTR_HP_OUT], + this->m_temp[C_sco2_cycle_core::TURB_OUT], this->m_pres[C_sco2_cycle_core::TURB_OUT], m_m_dot_t, this->m_pres[C_sco2_cycle_core::HTR_LP_OUT], + this->m_inputs.m_des_tol, + m_Q_dot_HT, this->m_temp[C_sco2_cycle_core::HTR_HP_OUT], T_HTR_LP_out_calc); + } + + } + + *diff_T_HTR_LP_out = T_HTR_LP_out_calc - T_HTR_LP_OUT_guess; + + return 0; +} + +int C_sco2_htrbp_core::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_LP_out) +{ + m_w_rc = m_m_dot_t = m_m_dot_rc = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT = std::numeric_limits::quiet_NaN(); + + // Set LTR_LP_OUT guess + this->m_temp[C_sco2_cycle_core::LTR_LP_OUT] = T_LTR_LP_OUT_guess; + + // First, solve the recompressor model as necessary + if (this->m_inputs.m_recomp_frac >= 1.E-12) + { + double eta_rc_isen = std::numeric_limits::quiet_NaN(); + + if (this->m_inputs.m_eta_rc < 0.0) // recalculate isen. efficiency of recompressor because inlet temp changes + { + int rc_error_code = 0; + isen_eta_from_poly_eta(this->m_temp[C_sco2_cycle_core::LTR_LP_OUT], this->m_pres[C_sco2_cycle_core::LTR_LP_OUT], + this->m_pres[C_sco2_cycle_core::RC_OUT], std::abs(this->m_inputs.m_eta_rc), true, + rc_error_code, eta_rc_isen); + + if (rc_error_code != 0) + { + *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); + return rc_error_code; + } + } + else + { + eta_rc_isen = this->m_inputs.m_eta_rc; + } + + int rc_error_code = 0; + + calculate_turbomachinery_outlet_1(this->m_temp[C_sco2_cycle_core::LTR_LP_OUT], this->m_pres[C_sco2_cycle_core::LTR_LP_OUT], this->m_pres[C_sco2_cycle_core::RC_OUT], eta_rc_isen, true, rc_error_code, + this->m_enth[C_sco2_cycle_core::LTR_LP_OUT], this->m_entr[C_sco2_cycle_core::LTR_LP_OUT], this->m_dens[C_sco2_cycle_core::LTR_LP_OUT], this->m_temp[C_sco2_cycle_core::RC_OUT], this->m_enth[C_sco2_cycle_core::RC_OUT], + this->m_entr[C_sco2_cycle_core::RC_OUT], this->m_dens[C_sco2_cycle_core::RC_OUT], m_w_rc); + + if (rc_error_code != 0) + { + *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); + return rc_error_code; + } + } + else + { + m_w_rc = 0.0; // no recompressor + int prop_error_code = CO2_TP(this->m_temp[C_sco2_cycle_core::LTR_LP_OUT], this->m_pres[C_sco2_cycle_core::LTR_LP_OUT], &this->m_co2_props); + if (prop_error_code != 0) + { + *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); + return prop_error_code; + } + this->m_enth[C_sco2_cycle_core::LTR_LP_OUT] = this->m_co2_props.enth; + this->m_entr[C_sco2_cycle_core::LTR_LP_OUT] = this->m_co2_props.entr; + this->m_dens[C_sco2_cycle_core::LTR_LP_OUT] = this->m_co2_props.dens; + this->m_temp[C_sco2_cycle_core::RC_OUT] = this->m_temp[C_sco2_cycle_core::LTR_LP_OUT]; + this->m_enth[C_sco2_cycle_core::RC_OUT] = this->m_enth[C_sco2_cycle_core::LTR_LP_OUT]; + this->m_entr[C_sco2_cycle_core::RC_OUT] = this->m_entr[C_sco2_cycle_core::LTR_LP_OUT]; + this->m_dens[C_sco2_cycle_core::RC_OUT] = this->m_dens[C_sco2_cycle_core::LTR_LP_OUT]; + } + + // Solve Mass Flow Rates + { + m_m_dot_t = this->m_inputs.m_W_dot_net_design / ((m_w_mc * (1.0 - this->m_inputs.m_recomp_frac) + + m_w_rc * this->m_inputs.m_recomp_frac + m_w_t) * this->m_inputs.m_eta_generator); //[C_sco2_cycle_core::kg/s] + + m_m_dot_rc = m_m_dot_t * this->m_inputs.m_recomp_frac; //[C_sco2_cycle_core::kg/s] + m_m_dot_mc = m_m_dot_t - m_m_dot_rc; + } + + // Solve LTR + *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); + double T_LTR_LP_out_calc = std::numeric_limits::quiet_NaN(); + { + this->mc_LT_recup.design_for_target__calc_outlet(this->m_inputs.m_LTR_target_code, + this->m_inputs.m_LTR_UA, this->m_inputs.m_LTR_min_dT, this->m_inputs.m_LTR_eff_target, + this->m_inputs.m_LTR_eff_max, + this->m_temp[C_sco2_cycle_core::MC_OUT], this->m_pres[C_sco2_cycle_core::MC_OUT], m_m_dot_mc, this->m_pres[C_sco2_cycle_core::LTR_HP_OUT], + this->m_temp[C_sco2_cycle_core::HTR_LP_OUT], this->m_pres[C_sco2_cycle_core::HTR_LP_OUT], m_m_dot_t, this->m_pres[C_sco2_cycle_core::LTR_LP_OUT], + this->m_inputs.m_des_tol, + m_Q_dot_LT, this->m_temp[C_sco2_cycle_core::LTR_HP_OUT], T_LTR_LP_out_calc); + + } + + *diff_T_LTR_LP_out = T_LTR_LP_out_calc - T_LTR_LP_OUT_guess; + + return 0; +} + +void C_sco2_htrbp_core::InitializeSolve() +{ + m_temp.resize(C_sco2_cycle_core::END_SCO2_STATES); + std::fill(m_temp.begin(), m_temp.end(), std::numeric_limits::quiet_NaN()); + m_pres = m_enth = m_entr = m_dens = m_temp; +} + + + + + +// ********************************************************************************** END C_sco2_htrbp_core void C_HTRBypass_Cycle::design_core(int& error_code) { + // DEBUG + { + S_sco2_htrbp_in core_inputs; + core_inputs.m_dT_BP = m_dT_BP; + core_inputs.m_P_mc_in = ms_des_par.m_P_mc_in; + core_inputs.m_P_mc_out = ms_des_par.m_P_mc_out; + core_inputs.m_LTR_target_code = ms_des_par.m_LTR_target_code; + core_inputs.m_LTR_UA = ms_des_par.m_LTR_UA; + core_inputs.m_LTR_min_dT = ms_des_par.m_LTR_min_dT; + core_inputs.m_LTR_eff_target = ms_des_par.m_LTR_eff_target; + core_inputs.m_LTR_eff_max = ms_des_par.m_LTR_eff_max; + core_inputs.m_LTR_N_sub_hxrs = m_LTR_N_sub_hxrs; + core_inputs.m_LTR_od_UA_target_type = ms_des_par.m_LTR_od_UA_target_type; + + core_inputs.m_HTR_target_code = ms_des_par.m_HTR_target_code; + core_inputs.m_HTR_UA = ms_des_par.m_HTR_UA; + core_inputs.m_HTR_min_dT = ms_des_par.m_HTR_min_dT; + core_inputs.m_HTR_eff_target = ms_des_par.m_HTR_eff_target; + core_inputs.m_HTR_eff_max = ms_des_par.m_HTR_eff_max; + core_inputs.m_HTR_N_sub_hxrs = m_HTR_N_sub_hxrs; + core_inputs.m_HTR_od_UA_target_type = ms_des_par.m_HTR_od_UA_target_type; + + core_inputs.m_recomp_frac = ms_des_par.m_recomp_frac; + core_inputs.m_bypass_frac = ms_des_par.m_bypass_frac; + core_inputs.m_des_tol = ms_des_par.m_des_tol; + core_inputs.m_is_des_air_cooler = ms_des_par.m_is_des_air_cooler; + + core_inputs.m_W_dot_net_design = m_W_dot_net; + core_inputs.m_T_mc_in = m_T_mc_in; + core_inputs.m_T_t_in = m_T_t_in; + core_inputs.m_DP_LTR = m_DP_LTR; + core_inputs.m_DP_HTR = m_DP_HTR; + core_inputs.m_DP_PC_main = m_DP_PC_main; + core_inputs.m_DP_PHX = m_DP_PHX; + core_inputs.m_eta_mc = m_eta_mc; + core_inputs.m_eta_t = m_eta_t; + core_inputs.m_eta_rc = m_eta_rc; + core_inputs.m_eta_generator = m_eta_generator; + core_inputs.m_frac_fan_power = m_frac_fan_power; + core_inputs.m_set_HTF_mdot = m_set_HTF_mdot; + core_inputs.m_cp_HTF = m_cp_HTF; + core_inputs.m_T_HTF_PHX_inlet = m_T_HTF_PHX_inlet; + core_inputs.m_eta_fan = m_eta_fan; + core_inputs.m_deltaP_cooler_frac = m_deltaP_cooler_frac; + core_inputs.m_T_amb_des = m_T_amb_des; + core_inputs.m_elevation = m_elevation; + core_inputs.m_N_nodes_pass = m_N_nodes_pass; + + + C_sco2_htrbp_core sco2_core; + sco2_core.SetInputs(core_inputs); + int err = sco2_core.Solve(); + + } + + + + // Check if HTF parameters were set if (is_bp_par_set == false) @@ -664,7 +1402,6 @@ void C_HTRBypass_Cycle::design_core_standard(int& error_code) } - int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out) { m_w_rc = m_m_dot_t = m_m_dot_rc = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT = std::numeric_limits::quiet_NaN(); diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 3356d56c81..ac2cf18361 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -45,6 +45,199 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "nlopt.hpp" #include "nlopt_callbacks.h" +// Defines sco2 htr bypass input variables (no optimized variables) +struct S_sco2_htrbp_in +{ + + double m_P_mc_in; //[kPa] Compressor inlet pressure + double m_P_mc_out; //[kPa] Compressor outlet pressure + + // LTR thermal design + int m_LTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness + double m_LTR_UA; //[kW/K] target LTR conductance + double m_LTR_min_dT; //[K] target LTR minimum temperature difference + double m_LTR_eff_target; //[-] target LTR effectiveness + double m_LTR_eff_max; //[-] Maximum allowable effectiveness in LT recuperator + NS_HX_counterflow_eqs::E_UA_target_type m_LTR_od_UA_target_type; + int m_LTR_N_sub_hxrs; //[-] Number of sub-hxs to use in hx model + + // HTR thermal design + int m_HTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness + double m_HTR_UA; //[kW/K] target HTR conductance + double m_HTR_min_dT; //[K] target HTR min temperature difference + double m_HTR_eff_target; //[-] target HTR effectiveness + double m_HTR_eff_max; //[-] Maximum allowable effectiveness in HT recuperator + NS_HX_counterflow_eqs::E_UA_target_type m_HTR_od_UA_target_type; + int m_HTR_N_sub_hxrs; //[-] Number of sub-hxs to use in hx model + + double m_recomp_frac; //[-] Fraction of flow that bypasses the precooler and the main compressor at the design point + double m_bypass_frac; //[-] Fraction of flow that bypasses the HTR and passes through the Bypass HX + double m_des_tol; //[-] Convergence tolerance + + // Air cooler parameters + bool m_is_des_air_cooler; //[-] False will skip physical air cooler design. UA will not be available for cost models. + + + // Added + double m_W_dot_net_design; //[kWe] Target net cycle power + double m_T_mc_in; //[K] Compressor inlet temperature + double m_T_t_in; //[K] Turbine inlet temperature + double m_dT_BP; // [delta K/C] BYPASS_OUT - HTR_HP_OUT + std::vector m_DP_LTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + std::vector m_DP_HTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + std::vector m_DP_PC_main; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + std::vector m_DP_PHX; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + double m_eta_mc; //[-] design-point efficiency of the main compressor; isentropic if positive, polytropic if negative + double m_eta_t; //[-] design-point efficiency of the turbine; isentropic if positive, polytropic if negative + double m_eta_rc; //[-] design-point efficiency of the recompressor; isentropic if positive, polytropic if negative + double m_eta_generator; //[-] Mechanical-to-electrical efficiency of generator + double m_frac_fan_power; //[-] Fraction of total cycle power 'S_des_par_cycle_dep.m_W_dot_fan_des' consumed by air fan + double m_set_HTF_mdot; //[kg/s] > 0 set HTF mass flow, <= 0 use bypass approach temp to calculate HTF mdot + double m_cp_HTF; //[kJ/kg K] HTF specific heat + double m_T_HTF_PHX_inlet; //[K] HTF Inlet Temperature + double m_eta_fan; //[-] Fan isentropic efficiency + double m_deltaP_cooler_frac; //[-] Fraction of high side (of cycle, i.e. comp outlet) pressure that is allowed as pressure drop to design the ACC + double m_T_amb_des; //[K] Design point ambient temperature + double m_elevation; //[m] Elevation (used to calculate ambient pressure) + int m_N_nodes_pass; //[-] Number of nodes per pass + + + S_sco2_htrbp_in() + { + m_P_mc_in = m_P_mc_out = + m_LTR_UA = m_LTR_min_dT = m_LTR_eff_target = m_LTR_eff_max = + m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = + m_recomp_frac = + m_bypass_frac = + m_des_tol = + m_W_dot_net_design = + m_T_mc_in = + m_T_t_in = + m_eta_mc = + m_eta_t = + m_eta_rc = + m_eta_generator = + m_frac_fan_power = + m_set_HTF_mdot = + m_cp_HTF = + m_T_HTF_PHX_inlet = + m_eta_fan = + m_deltaP_cooler_frac = + m_T_amb_des = + m_elevation = + m_dT_BP = + std::numeric_limits::quiet_NaN(); + + m_N_nodes_pass = 0; + + // Recuperator design target codes + m_LTR_target_code = 1; // default to target conductance + m_LTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; + m_HTR_target_code = 1; // default to target conductance + m_HTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; + + + // Air cooler default + m_is_des_air_cooler = true; + + } + + +}; + +// Defines sco2 htr bypass output variables (no optimized variables) +//struct S_sco2_htrbp_out +//{ +// int m_error_code; +// double m_eta_thermal; // Thermal Efficiency +// +// S_sco2_htrbp_out() +// { +// m_error_code = m_eta_thermal +// = std::numeric_limits::quiet_NaN(); +// } +//}; + + + +// This class is purely for solving the cycle +// No optimization +class C_sco2_htrbp_core +{ +private: + CO2_state m_co2_props; + + class C_mono_htrbp_core_HTR_des : public C_monotonic_equation + { + private: + C_sco2_htrbp_core* m_htr_bypass_cycle; + + public: + C_mono_htrbp_core_HTR_des(C_sco2_htrbp_core* htr_bypass_cycle) + { + m_htr_bypass_cycle = htr_bypass_cycle; + } + + virtual int operator()(double T_HTR_LP_OUT_guess /*K*/, double* diff_T_HTR_LP_out /*K*/); + }; + + class C_mono_htrbp_core_LTR_des : public C_monotonic_equation + { + private: + C_sco2_htrbp_core* m_htr_bypass_cycle; + + public: + C_mono_htrbp_core_LTR_des(C_sco2_htrbp_core* htr_bypass_cycle) + { + m_htr_bypass_cycle = htr_bypass_cycle; + } + + virtual int operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out /*K*/); + }; + + int solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out); + int solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_LP_out); + + void InitializeSolve(); + +public: + // Inputs Struct + S_sco2_htrbp_in m_inputs; + + // Publicly Accessible Fields (Outputs) + int m_error_code; + C_turbine m_t; // Turbine model + C_comp_multi_stage m_mc_ms; // Main Compressor Model + C_comp_multi_stage m_rc_ms; // Recompressor Model + C_HeatExchanger m_PHX, m_PC, m_BPX; // Primary, Cooler, Bypass Heat Exchanger Models + C_HX_co2_to_co2_CRM mc_LT_recup; // LTR + C_HX_co2_to_co2_CRM mc_HT_recup; // HTR + C_CO2_to_air_cooler mc_air_cooler; // Air Cooler + std::vector m_temp, m_pres, m_enth, m_entr, m_dens; // thermodynamic states (K, kPa, kJ/kg, kJ/kg-K, kg/m3) + double m_w_t, m_w_mc, m_w_rc; // [kJ/kg] specific work of turbine, main compressor, recompressor + double m_m_dot_t, m_m_dot_mc, m_m_dot_rc; // [kg/s] sco2 Mass flow in main compressor, recompressor, turbine + double m_m_dot_bp, m_m_dot_htr_hp; // [kg/s] sco2 Mass flow through bypass, hot side HTR + double m_Q_dot_LT, m_Q_dot_HT; // [kWt] Heat Transfer in LTR, HTR + double m_W_dot_mc, m_W_dot_rc, m_W_dot_t; // [kWt] Energy consumed by main compressor, recompressor, produced by turbine + double m_W_dot_net; // [kWt] ACTUAL produced net work in system + double m_W_dot_air_cooler; // [kWe] Energy consumed by air cooler + double m_Q_dot_air_cooler; // [kWt] Heat rejected by air cooler + double m_Q_dot_LTR_LP, m_Q_dot_LTR_HP, m_Q_dot_HTR_LP, m_Q_dot_HTR_HP; // kWt Heat change on LTR low pressure, etc... + double m_Q_dot_total; // [kWt] Total heat entering sco2 + double m_Q_dot_PHX, m_Q_dot_BP; // [kWt] Energy exchange in PHX, BPX + double m_m_dot_HTF; // [kg/s] HTF mass flow rate + double m_T_HTF_PHX_out; // [K] HTF PHX outlet temperature + double m_HTF_PHX_cold_approach; // [delta K/C] PHX cold approach temperature + double m_T_HTF_BP_outlet; // [K] HTF BPX outlet temperature + double m_HTF_BP_cold_approach; // [K] BPX cold approach temperature + double m_eta_thermal; // Thermal Efficiency + + // Public Methods + void SetInputs(S_sco2_htrbp_in inputs) { m_inputs = inputs; }; + int Solve(); + +}; + class C_HTRBypass_Cycle : public C_sco2_cycle_core { public: From 150916f1e0ff348b60aa5bf6c9d1350995e967e6 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Wed, 6 Mar 2024 10:14:40 -0700 Subject: [PATCH 32/94] Complete core simulation model --- tcs/sco2_htrbypass_cycle.cpp | 7 +++--- tcs/sco2_htrbypass_cycle.h | 46 ++++++++++++++++++------------------ 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 8817991613..f08960e2ce 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -421,7 +421,8 @@ int C_sco2_htrbp_core::Solve() else { // Use HTF Bypass cold approach to calculate PHX outlet Temperature - m_T_HTF_PHX_out = m_HTF_PHX_cold_approach + m_temp[C_sco2_cycle_core::MIXER2_OUT]; + m_T_HTF_PHX_out = m_inputs.m_HTF_PHX_cold_approach_input + m_temp[C_sco2_cycle_core::MIXER2_OUT]; + m_HTF_PHX_cold_approach = m_inputs.m_HTF_PHX_cold_approach_input; // Calculate HTF mdot m_m_dot_HTF = m_Q_dot_PHX / ((m_inputs.m_T_HTF_PHX_inlet - m_T_HTF_PHX_out) * m_inputs.m_cp_HTF); @@ -745,7 +746,7 @@ void C_HTRBypass_Cycle::design_core(int& error_code) core_inputs.m_HTR_od_UA_target_type = ms_des_par.m_HTR_od_UA_target_type; core_inputs.m_recomp_frac = ms_des_par.m_recomp_frac; - core_inputs.m_bypass_frac = ms_des_par.m_bypass_frac; + core_inputs.m_bypass_frac = ms_opt_des_par.m_bypass_frac_guess; core_inputs.m_des_tol = ms_des_par.m_des_tol; core_inputs.m_is_des_air_cooler = ms_des_par.m_is_des_air_cooler; @@ -769,7 +770,7 @@ void C_HTRBypass_Cycle::design_core(int& error_code) core_inputs.m_T_amb_des = m_T_amb_des; core_inputs.m_elevation = m_elevation; core_inputs.m_N_nodes_pass = m_N_nodes_pass; - + core_inputs.m_HTF_PHX_cold_approach_input = m_HTF_PHX_cold_approach; C_sco2_htrbp_core sco2_core; sco2_core.SetInputs(core_inputs); diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index ac2cf18361..4663eda3a9 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -79,28 +79,28 @@ struct S_sco2_htrbp_in // Added - double m_W_dot_net_design; //[kWe] Target net cycle power - double m_T_mc_in; //[K] Compressor inlet temperature - double m_T_t_in; //[K] Turbine inlet temperature - double m_dT_BP; // [delta K/C] BYPASS_OUT - HTR_HP_OUT - std::vector m_DP_LTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) - std::vector m_DP_HTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) - std::vector m_DP_PC_main; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) - std::vector m_DP_PHX; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) - double m_eta_mc; //[-] design-point efficiency of the main compressor; isentropic if positive, polytropic if negative - double m_eta_t; //[-] design-point efficiency of the turbine; isentropic if positive, polytropic if negative - double m_eta_rc; //[-] design-point efficiency of the recompressor; isentropic if positive, polytropic if negative - double m_eta_generator; //[-] Mechanical-to-electrical efficiency of generator - double m_frac_fan_power; //[-] Fraction of total cycle power 'S_des_par_cycle_dep.m_W_dot_fan_des' consumed by air fan - double m_set_HTF_mdot; //[kg/s] > 0 set HTF mass flow, <= 0 use bypass approach temp to calculate HTF mdot - double m_cp_HTF; //[kJ/kg K] HTF specific heat - double m_T_HTF_PHX_inlet; //[K] HTF Inlet Temperature - double m_eta_fan; //[-] Fan isentropic efficiency - double m_deltaP_cooler_frac; //[-] Fraction of high side (of cycle, i.e. comp outlet) pressure that is allowed as pressure drop to design the ACC - double m_T_amb_des; //[K] Design point ambient temperature - double m_elevation; //[m] Elevation (used to calculate ambient pressure) - int m_N_nodes_pass; //[-] Number of nodes per pass - + double m_W_dot_net_design; //[kWe] Target net cycle power + double m_T_mc_in; //[K] Compressor inlet temperature + double m_T_t_in; //[K] Turbine inlet temperature + double m_dT_BP; //[delta K/C] BYPASS_OUT - HTR_HP_OUT + std::vector m_DP_LTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + std::vector m_DP_HTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + std::vector m_DP_PC_main; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + std::vector m_DP_PHX; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + double m_eta_mc; //[-] design-point efficiency of the main compressor; isentropic if positive, polytropic if negative + double m_eta_t; //[-] design-point efficiency of the turbine; isentropic if positive, polytropic if negative + double m_eta_rc; //[-] design-point efficiency of the recompressor; isentropic if positive, polytropic if negative + double m_eta_generator; //[-] Mechanical-to-electrical efficiency of generator + double m_frac_fan_power; //[-] Fraction of total cycle power 'S_des_par_cycle_dep.m_W_dot_fan_des' consumed by air fan + double m_set_HTF_mdot; //[kg/s] > 0 set HTF mass flow, <= 0 use bypass approach temp to calculate HTF mdot + double m_cp_HTF; //[kJ/kg K] HTF specific heat + double m_T_HTF_PHX_inlet; //[K] HTF Inlet Temperature + double m_eta_fan; //[-] Fan isentropic efficiency + double m_deltaP_cooler_frac; //[-] Fraction of high side (of cycle, i.e. comp outlet) pressure that is allowed as pressure drop to design the ACC + double m_T_amb_des; //[K] Design point ambient temperature + double m_elevation; //[m] Elevation (used to calculate ambient pressure) + int m_N_nodes_pass; //[-] Number of nodes per pass + double m_HTF_PHX_cold_approach_input; //[delta K] PHX cold approach temperature. Only needed if m_set_HTF_mdot < 0 S_sco2_htrbp_in() { @@ -126,6 +126,7 @@ struct S_sco2_htrbp_in m_T_amb_des = m_elevation = m_dT_BP = + m_HTF_PHX_cold_approach_input = std::numeric_limits::quiet_NaN(); m_N_nodes_pass = 0; @@ -142,7 +143,6 @@ struct S_sco2_htrbp_in } - }; // Defines sco2 htr bypass output variables (no optimized variables) From e1ba650ffdb69f5e63f0b2043766693519b2c243 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Wed, 6 Mar 2024 11:00:08 -0700 Subject: [PATCH 33/94] Move core simulation results to dedicated outputs class --- tcs/sco2_htrbypass_cycle.cpp | 442 +++++++++++++++++------------------ tcs/sco2_htrbypass_cycle.h | 104 +++++---- 2 files changed, 284 insertions(+), 262 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index f08960e2ce..9b523cc326 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -44,95 +44,95 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. int C_sco2_htrbp_core::Solve() { InitializeSolve(); - m_error_code = -1; + m_outputs.m_error_code = -1; // Apply scaling to the turbomachinery here { - m_mc_ms.m_r_W_dot_scale = m_inputs.m_W_dot_net_design / 10.E3; //[-] - m_rc_ms.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] - m_t.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] + m_outputs.m_mc_ms.m_r_W_dot_scale = m_inputs.m_W_dot_net_design / 10.E3; //[-] + m_outputs.m_rc_ms.m_r_W_dot_scale = m_outputs.m_mc_ms.m_r_W_dot_scale; //[-] + m_outputs.m_t.m_r_W_dot_scale = m_outputs.m_mc_ms.m_r_W_dot_scale; //[-] } // Initialize Recuperators { // LTR - mc_LT_recup.initialize(m_inputs.m_LTR_N_sub_hxrs, m_inputs.m_LTR_od_UA_target_type); + m_outputs.mc_LT_recup.initialize(m_inputs.m_LTR_N_sub_hxrs, m_inputs.m_LTR_od_UA_target_type); // HTR - mc_HT_recup.initialize(m_inputs.m_HTR_N_sub_hxrs, m_inputs.m_HTR_od_UA_target_type); + m_outputs.mc_HT_recup.initialize(m_inputs.m_HTR_N_sub_hxrs, m_inputs.m_HTR_od_UA_target_type); } // Initialize a few variables { - m_temp[C_sco2_cycle_core::MC_IN] = m_inputs.m_T_mc_in; //[K] - m_pres[C_sco2_cycle_core::MC_IN] = m_inputs.m_P_mc_in; - m_pres[C_sco2_cycle_core::MC_OUT] = m_inputs.m_P_mc_out; - m_temp[C_sco2_cycle_core::TURB_IN] = m_inputs.m_T_t_in; //[K] + m_outputs.m_temp[C_sco2_cycle_core::MC_IN] = m_inputs.m_T_mc_in; //[K] + m_outputs.m_pres[C_sco2_cycle_core::MC_IN] = m_inputs.m_P_mc_in; + m_outputs.m_pres[C_sco2_cycle_core::MC_OUT] = m_inputs.m_P_mc_out; + m_outputs.m_temp[C_sco2_cycle_core::TURB_IN] = m_inputs.m_T_t_in; //[K] } // Apply pressure drops to heat exchangers, fully defining the pressures at all states { if (m_inputs.m_DP_LTR[0] < 0.0) - m_pres[C_sco2_cycle_core::LTR_HP_OUT] = m_pres[C_sco2_cycle_core::MC_OUT] - m_pres[C_sco2_cycle_core::MC_OUT] * std::abs(m_inputs.m_DP_LTR[0]); // relative pressure drop specified for LT recuperator (cold stream) + m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MC_OUT] - m_outputs.m_pres[C_sco2_cycle_core::MC_OUT] * std::abs(m_inputs.m_DP_LTR[0]); // relative pressure drop specified for LT recuperator (cold stream) else - m_pres[C_sco2_cycle_core::LTR_HP_OUT] = m_pres[C_sco2_cycle_core::MC_OUT] - m_inputs.m_DP_LTR[0]; // absolute pressure drop specified for LT recuperator (cold stream) + m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MC_OUT] - m_inputs.m_DP_LTR[0]; // absolute pressure drop specified for LT recuperator (cold stream) if ((m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && m_inputs.m_LTR_UA < 1.0E-12) || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && m_inputs.m_LTR_UA < 1.0E-12) || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && m_inputs.m_LTR_min_dT < 1.0E-12) || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && m_inputs.m_LTR_eff_target < 1.0E-12)) - m_pres[C_sco2_cycle_core::LTR_HP_OUT] = m_pres[C_sco2_cycle_core::MC_OUT]; // If there is no LT recuperator, there is no pressure drop + m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MC_OUT]; // If there is no LT recuperator, there is no pressure drop - m_pres[C_sco2_cycle_core::MIXER_OUT] = m_pres[C_sco2_cycle_core::LTR_HP_OUT]; // Assume no pressure drop in mixing valve - m_pres[C_sco2_cycle_core::RC_OUT] = m_pres[C_sco2_cycle_core::LTR_HP_OUT]; // Assume no pressure drop in mixing valve + m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT] = m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT]; // Assume no pressure drop in mixing valve + m_outputs.m_pres[C_sco2_cycle_core::RC_OUT] = m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT]; // Assume no pressure drop in mixing valve if (m_inputs.m_DP_HTR[0] < 0.0) - m_pres[C_sco2_cycle_core::HTR_HP_OUT] = m_pres[C_sco2_cycle_core::MIXER_OUT] - - m_pres[C_sco2_cycle_core::MIXER_OUT] * std::abs(m_inputs.m_DP_HTR[0]); // relative pressure drop specified for HT recuperator (cold stream) + m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT] + - m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT] * std::abs(m_inputs.m_DP_HTR[0]); // relative pressure drop specified for HT recuperator (cold stream) else - m_pres[C_sco2_cycle_core::HTR_HP_OUT] = m_pres[C_sco2_cycle_core::MIXER_OUT] - m_inputs.m_DP_HTR[0]; // absolute pressure drop specified for HT recuperator (cold stream) + m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT] - m_inputs.m_DP_HTR[0]; // absolute pressure drop specified for HT recuperator (cold stream) if ((m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && m_inputs.m_HTR_UA < 1.0E-12) || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && m_inputs.m_HTR_UA < 1.0E-12) || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && m_inputs.m_HTR_min_dT < 1.0E-12) || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && m_inputs.m_HTR_eff_target < 1.0E-12)) - m_pres[C_sco2_cycle_core::HTR_HP_OUT] = m_pres[C_sco2_cycle_core::MIXER_OUT]; // If there is no HT recuperator, there is no pressure drop + m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT]; // If there is no HT recuperator, there is no pressure drop if (m_inputs.m_DP_PHX[0] < 0.0) - m_pres[C_sco2_cycle_core::TURB_IN] = m_pres[C_sco2_cycle_core::HTR_HP_OUT] - m_pres[C_sco2_cycle_core::HTR_HP_OUT] * std::abs(m_inputs.m_DP_PHX[0]); // relative pressure drop specified for PHX + m_outputs.m_pres[C_sco2_cycle_core::TURB_IN] = m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT] - m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT] * std::abs(m_inputs.m_DP_PHX[0]); // relative pressure drop specified for PHX else - m_pres[C_sco2_cycle_core::TURB_IN] = m_pres[C_sco2_cycle_core::HTR_HP_OUT] - m_inputs.m_DP_PHX[0]; // absolute pressure drop specified for PHX + m_outputs.m_pres[C_sco2_cycle_core::TURB_IN] = m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT] - m_inputs.m_DP_PHX[0]; // absolute pressure drop specified for PHX if (m_inputs.m_DP_PC_main[1] < 0.0) - m_pres[C_sco2_cycle_core::LTR_LP_OUT] = m_pres[C_sco2_cycle_core::MC_IN] / (1.0 - std::abs(m_inputs.m_DP_PC_main[1])); // relative pressure drop specified for precooler: P1=P9-P9*rel_DP => P1=P9*(1-rel_DP) + m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MC_IN] / (1.0 - std::abs(m_inputs.m_DP_PC_main[1])); // relative pressure drop specified for precooler: P1=P9-P9*rel_DP => P1=P9*(1-rel_DP) else - m_pres[C_sco2_cycle_core::LTR_LP_OUT] = m_pres[C_sco2_cycle_core::MC_IN] + m_inputs.m_DP_PC_main[1]; + m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MC_IN] + m_inputs.m_DP_PC_main[1]; if (m_inputs.m_DP_LTR[1] < 0.0) - m_pres[C_sco2_cycle_core::HTR_LP_OUT] = m_pres[C_sco2_cycle_core::LTR_LP_OUT] / (1.0 - std::abs(m_inputs.m_DP_LTR[1])); // relative pressure drop specified for LT recuperator (hot stream) + m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT] / (1.0 - std::abs(m_inputs.m_DP_LTR[1])); // relative pressure drop specified for LT recuperator (hot stream) else - m_pres[C_sco2_cycle_core::HTR_LP_OUT] = m_pres[C_sco2_cycle_core::LTR_LP_OUT] + m_inputs.m_DP_LTR[1]; // absolute pressure drop specified for LT recuperator (hot stream) + m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT] + m_inputs.m_DP_LTR[1]; // absolute pressure drop specified for LT recuperator (hot stream) if ((m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && m_inputs.m_LTR_UA < 1.0E-12) || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && m_inputs.m_LTR_UA < 1.0E-12) || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && m_inputs.m_LTR_min_dT < 1.0E-12) || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && m_inputs.m_LTR_eff_target < 1.0E-12)) - m_pres[C_sco2_cycle_core::HTR_LP_OUT] = m_pres[C_sco2_cycle_core::LTR_LP_OUT]; // if there is no LT recuperator, there is no pressure drop + m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT]; // if there is no LT recuperator, there is no pressure drop if (m_inputs.m_DP_HTR[1] < 0.0) - m_pres[C_sco2_cycle_core::TURB_OUT] = m_pres[C_sco2_cycle_core::HTR_LP_OUT] / (1.0 - std::abs(m_inputs.m_DP_HTR[1])); // relative pressure drop specified for HT recuperator (hot stream) + m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT] = m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT] / (1.0 - std::abs(m_inputs.m_DP_HTR[1])); // relative pressure drop specified for HT recuperator (hot stream) else - m_pres[C_sco2_cycle_core::TURB_OUT] = m_pres[C_sco2_cycle_core::HTR_LP_OUT] + m_inputs.m_DP_HTR[1]; // absolute pressure drop specified for HT recuperator (hot stream) + m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT] = m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT] + m_inputs.m_DP_HTR[1]; // absolute pressure drop specified for HT recuperator (hot stream) if ((m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && m_inputs.m_HTR_UA < 1.0E-12) || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && m_inputs.m_HTR_UA < 1.0E-12) || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && m_inputs.m_HTR_min_dT < 1.0E-12) || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && m_inputs.m_HTR_eff_target < 1.0E-12)) - m_pres[C_sco2_cycle_core::TURB_OUT] = m_pres[C_sco2_cycle_core::HTR_LP_OUT]; // if there is no HT recuperator, there is no pressure drop + m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT] = m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT]; // if there is no HT recuperator, there is no pressure drop // Added pressures - m_pres[C_sco2_cycle_core::BYPASS_OUT] = m_pres[C_sco2_cycle_core::HTR_HP_OUT]; - m_pres[C_sco2_cycle_core::MIXER2_OUT] = m_pres[C_sco2_cycle_core::HTR_HP_OUT]; + m_outputs.m_pres[C_sco2_cycle_core::BYPASS_OUT] = m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT]; + m_outputs.m_pres[C_sco2_cycle_core::MIXER2_OUT] = m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT]; } @@ -145,13 +145,13 @@ int C_sco2_htrbp_core::Solve() { int poly_error_code = 0; - isen_eta_from_poly_eta(m_temp[C_sco2_cycle_core::MC_IN], m_pres[C_sco2_cycle_core::MC_IN], m_pres[C_sco2_cycle_core::MC_OUT], std::abs(m_inputs.m_eta_mc), + isen_eta_from_poly_eta(m_outputs.m_temp[C_sco2_cycle_core::MC_IN], m_outputs.m_pres[C_sco2_cycle_core::MC_IN], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], std::abs(m_inputs.m_eta_mc), true, poly_error_code, eta_mc_isen); if (poly_error_code != 0) { - m_error_code = poly_error_code; - return m_error_code; + m_outputs.m_error_code = poly_error_code; + return m_outputs.m_error_code; } } else @@ -161,13 +161,13 @@ int C_sco2_htrbp_core::Solve() { int poly_error_code = 0; - isen_eta_from_poly_eta(m_temp[C_sco2_cycle_core::TURB_IN], m_pres[C_sco2_cycle_core::TURB_IN], m_pres[C_sco2_cycle_core::TURB_OUT], std::abs(m_inputs.m_eta_t), + isen_eta_from_poly_eta(m_outputs.m_temp[C_sco2_cycle_core::TURB_IN], m_outputs.m_pres[C_sco2_cycle_core::TURB_IN], m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT], std::abs(m_inputs.m_eta_t), false, poly_error_code, eta_t_isen); if (poly_error_code != 0) { - m_error_code = poly_error_code; - return m_error_code; + m_outputs.m_error_code = poly_error_code; + return m_outputs.m_error_code; } } else @@ -177,39 +177,39 @@ int C_sco2_htrbp_core::Solve() // Determine the outlet state and specific work for the main compressor and turbine. // Main compressor - m_w_mc = std::numeric_limits::quiet_NaN(); + m_outputs.m_w_mc = std::numeric_limits::quiet_NaN(); { int comp_error_code = 0; - calculate_turbomachinery_outlet_1(m_temp[C_sco2_cycle_core::MC_IN], m_pres[C_sco2_cycle_core::MC_IN], m_pres[C_sco2_cycle_core::MC_OUT], eta_mc_isen, true, - comp_error_code, m_enth[C_sco2_cycle_core::MC_IN], m_entr[C_sco2_cycle_core::MC_IN], m_dens[C_sco2_cycle_core::MC_IN], m_temp[C_sco2_cycle_core::MC_OUT], - m_enth[C_sco2_cycle_core::MC_OUT], m_entr[C_sco2_cycle_core::MC_OUT], m_dens[C_sco2_cycle_core::MC_OUT], m_w_mc); + calculate_turbomachinery_outlet_1(m_outputs.m_temp[C_sco2_cycle_core::MC_IN], m_outputs.m_pres[C_sco2_cycle_core::MC_IN], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], eta_mc_isen, true, + comp_error_code, m_outputs.m_enth[C_sco2_cycle_core::MC_IN], m_outputs.m_entr[C_sco2_cycle_core::MC_IN], m_outputs.m_dens[C_sco2_cycle_core::MC_IN], m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], + m_outputs.m_enth[C_sco2_cycle_core::MC_OUT], m_outputs.m_entr[C_sco2_cycle_core::MC_OUT], m_outputs.m_dens[C_sco2_cycle_core::MC_OUT], m_outputs.m_w_mc); if (comp_error_code != 0) { - m_error_code = comp_error_code; - return m_error_code; + m_outputs.m_error_code = comp_error_code; + return m_outputs.m_error_code; } } // Turbine - m_w_t = std::numeric_limits::quiet_NaN(); + m_outputs.m_w_t = std::numeric_limits::quiet_NaN(); { int turbine_error_code = 0; - calculate_turbomachinery_outlet_1(m_temp[C_sco2_cycle_core::TURB_IN], m_pres[C_sco2_cycle_core::TURB_IN], m_pres[C_sco2_cycle_core::TURB_OUT], eta_t_isen, false, - turbine_error_code, m_enth[C_sco2_cycle_core::TURB_IN], m_entr[C_sco2_cycle_core::TURB_IN], m_dens[C_sco2_cycle_core::TURB_IN], m_temp[C_sco2_cycle_core::TURB_OUT], - m_enth[C_sco2_cycle_core::TURB_OUT], m_entr[C_sco2_cycle_core::TURB_OUT], m_dens[C_sco2_cycle_core::TURB_OUT], m_w_t); + calculate_turbomachinery_outlet_1(m_outputs.m_temp[C_sco2_cycle_core::TURB_IN], m_outputs.m_pres[C_sco2_cycle_core::TURB_IN], m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT], eta_t_isen, false, + turbine_error_code, m_outputs.m_enth[C_sco2_cycle_core::TURB_IN], m_outputs.m_entr[C_sco2_cycle_core::TURB_IN], m_outputs.m_dens[C_sco2_cycle_core::TURB_IN], m_outputs.m_temp[C_sco2_cycle_core::TURB_OUT], + m_outputs.m_enth[C_sco2_cycle_core::TURB_OUT], m_outputs.m_entr[C_sco2_cycle_core::TURB_OUT], m_outputs.m_dens[C_sco2_cycle_core::TURB_OUT], m_outputs.m_w_t); if (turbine_error_code != 0) { - m_error_code = turbine_error_code; - return m_error_code; + m_outputs.m_error_code = turbine_error_code; + return m_outputs.m_error_code; } } // Check that this cycle can produce power - m_w_rc = std::numeric_limits::quiet_NaN(); + m_outputs.m_w_rc = std::numeric_limits::quiet_NaN(); { double eta_rc_isen = std::numeric_limits::quiet_NaN(); @@ -219,13 +219,13 @@ int C_sco2_htrbp_core::Solve() { int rc_error_code = 0; - isen_eta_from_poly_eta(m_temp[C_sco2_cycle_core::MC_OUT], m_pres[C_sco2_cycle_core::LTR_LP_OUT], m_pres[C_sco2_cycle_core::RC_OUT], std::abs(m_inputs.m_eta_rc), + isen_eta_from_poly_eta(m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT], m_outputs.m_pres[C_sco2_cycle_core::RC_OUT], std::abs(m_inputs.m_eta_rc), true, rc_error_code, eta_rc_isen); if (rc_error_code != 0) { - m_error_code = rc_error_code; - return m_error_code; + m_outputs.m_error_code = rc_error_code; + return m_outputs.m_error_code; } } else @@ -233,22 +233,22 @@ int C_sco2_htrbp_core::Solve() int rc_error_code = 0; - calculate_turbomachinery_outlet_1(m_temp[C_sco2_cycle_core::MC_OUT], m_pres[C_sco2_cycle_core::LTR_LP_OUT], m_pres[C_sco2_cycle_core::RC_OUT], eta_rc_isen, - true, rc_error_code, m_w_rc); + calculate_turbomachinery_outlet_1(m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT], m_outputs.m_pres[C_sco2_cycle_core::RC_OUT], eta_rc_isen, + true, rc_error_code, m_outputs.m_w_rc); if (rc_error_code != 0) { - m_error_code = rc_error_code; - return m_error_code; + m_outputs.m_error_code = rc_error_code; + return m_outputs.m_error_code; } } else - m_w_rc = 0.0; + m_outputs.m_w_rc = 0.0; - if (m_w_mc + m_w_rc + m_w_t <= 0.0) // positive net power is impossible; return an error + if (m_outputs.m_w_mc + m_outputs.m_w_rc + m_outputs.m_w_t <= 0.0) // positive net power is impossible; return an error { - m_error_code = 25; - return m_error_code; + m_outputs.m_error_code = 25; + return m_outputs.m_error_code; } } @@ -258,13 +258,13 @@ int C_sco2_htrbp_core::Solve() C_monotonic_eq_solver HTR_des_solver(HTR_des_eq); { - double T_HTR_LP_out_lower = m_temp[C_sco2_cycle_core::MC_OUT]; //[K] Coldest possible temperature - double T_HTR_LP_out_upper = m_temp[C_sco2_cycle_core::TURB_OUT]; //[K] Hottest possible temperature + double T_HTR_LP_out_lower = m_outputs.m_temp[C_sco2_cycle_core::MC_OUT]; //[K] Coldest possible temperature + double T_HTR_LP_out_upper = m_outputs.m_temp[C_sco2_cycle_core::TURB_OUT]; //[K] Hottest possible temperature double T_HTR_LP_out_guess_lower = std::min(T_HTR_LP_out_upper - 2.0, std::max(T_HTR_LP_out_lower + 15.0, 220.0 + 273.15)); //[K] There is nothing special about these guesses... double T_HTR_LP_out_guess_upper = std::min(T_HTR_LP_out_guess_lower + 20.0, T_HTR_LP_out_upper - 1.0); //[K] There is nothing special about these guesses, either... - HTR_des_solver.settings(m_inputs.m_des_tol * m_temp[C_sco2_cycle_core::MC_IN], 1000, T_HTR_LP_out_lower, T_HTR_LP_out_upper, false); + HTR_des_solver.settings(m_inputs.m_des_tol * m_outputs.m_temp[C_sco2_cycle_core::MC_IN], 1000, T_HTR_LP_out_lower, T_HTR_LP_out_upper, false); double T_HTR_LP_out_solved, tol_T_HTR_LP_out_solved; T_HTR_LP_out_solved = tol_T_HTR_LP_out_solved = std::numeric_limits::quiet_NaN(); @@ -275,8 +275,8 @@ int C_sco2_htrbp_core::Solve() if (T_HTR_LP_out_code != C_monotonic_eq_solver::CONVERGED) { - m_error_code = 35; - return m_error_code; + m_outputs.m_error_code = 35; + return m_outputs.m_error_code; } double test = 0; @@ -288,64 +288,64 @@ int C_sco2_htrbp_core::Solve() // State 5 can now be fully defined { // Check if there is flow through HTR_HP - if (m_m_dot_htr_hp <= 1e-12) - m_enth[C_sco2_cycle_core::HTR_HP_OUT] = m_enth[C_sco2_cycle_core::MIXER_OUT]; + if (m_outputs.m_m_dot_htr_hp <= 1e-12) + m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT] = m_outputs.m_enth[C_sco2_cycle_core::MIXER_OUT]; else - m_enth[C_sco2_cycle_core::HTR_HP_OUT] = m_enth[C_sco2_cycle_core::MIXER_OUT] + m_Q_dot_HT / m_m_dot_htr_hp; // Energy balance on cold stream of high-temp recuperator + m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT] = m_outputs.m_enth[C_sco2_cycle_core::MIXER_OUT] + m_outputs.m_Q_dot_HT / m_outputs.m_m_dot_htr_hp; // Energy balance on cold stream of high-temp recuperator - int prop_error_code = CO2_PH(m_pres[C_sco2_cycle_core::HTR_HP_OUT], m_enth[C_sco2_cycle_core::HTR_HP_OUT], &m_co2_props); + int prop_error_code = CO2_PH(m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT], &m_co2_props); if (prop_error_code != 0) { - m_error_code = prop_error_code; - return m_error_code; + m_outputs.m_error_code = prop_error_code; + return m_outputs.m_error_code; } - m_temp[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.temp; - m_entr[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.entr; - m_dens[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.dens; + m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.temp; + m_outputs.m_entr[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.entr; + m_outputs.m_dens[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.dens; } // Calculate total work and heat metrics { // Work - m_W_dot_mc = m_w_mc * m_m_dot_mc; //[kWe] - m_W_dot_rc = m_w_rc * m_m_dot_rc; //[kWe] - m_W_dot_t = m_w_t * m_m_dot_t; //[kWe] - m_W_dot_net = m_W_dot_mc + m_W_dot_rc + m_W_dot_t; + m_outputs.m_W_dot_mc = m_outputs.m_w_mc * m_outputs.m_m_dot_mc; //[kWe] + m_outputs.m_W_dot_rc = m_outputs.m_w_rc * m_outputs.m_m_dot_rc; //[kWe] + m_outputs.m_W_dot_t = m_outputs.m_w_t * m_outputs.m_m_dot_t; //[kWe] + m_outputs.m_W_dot_net = m_outputs.m_W_dot_mc + m_outputs.m_W_dot_rc + m_outputs.m_W_dot_t; // Air Cooler (heat rejection unit) - m_W_dot_air_cooler = m_inputs.m_frac_fan_power * m_W_dot_net; - m_Q_dot_air_cooler = m_m_dot_mc * (m_enth[C_sco2_cycle_core::LTR_LP_OUT] - m_enth[C_sco2_cycle_core::MC_IN]); + m_outputs.m_W_dot_air_cooler = m_inputs.m_frac_fan_power * m_outputs.m_W_dot_net; + m_outputs.m_Q_dot_air_cooler = m_outputs.m_m_dot_mc * (m_outputs.m_enth[C_sco2_cycle_core::LTR_LP_OUT] - m_outputs.m_enth[C_sco2_cycle_core::MC_IN]); // Total Heat Entering sco2 - m_Q_dot_total = m_W_dot_net + m_Q_dot_air_cooler; + m_outputs.m_Q_dot_total = m_outputs.m_W_dot_net + m_outputs.m_Q_dot_air_cooler; // LTR - m_Q_dot_LTR_LP = m_m_dot_t * (m_enth[C_sco2_cycle_core::HTR_LP_OUT] - m_enth[C_sco2_cycle_core::LTR_LP_OUT]); - m_Q_dot_LTR_HP = m_m_dot_mc * (m_enth[C_sco2_cycle_core::LTR_HP_OUT] - m_enth[C_sco2_cycle_core::MC_OUT]); + m_outputs.m_Q_dot_LTR_LP = m_outputs.m_m_dot_t * (m_outputs.m_enth[C_sco2_cycle_core::HTR_LP_OUT] - m_outputs.m_enth[C_sco2_cycle_core::LTR_LP_OUT]); + m_outputs.m_Q_dot_LTR_HP = m_outputs.m_m_dot_mc * (m_outputs.m_enth[C_sco2_cycle_core::LTR_HP_OUT] - m_outputs.m_enth[C_sco2_cycle_core::MC_OUT]); // LTR - m_Q_dot_HTR_LP = m_m_dot_t * (m_enth[C_sco2_cycle_core::TURB_OUT] - m_enth[C_sco2_cycle_core::HTR_LP_OUT]); - m_Q_dot_HTR_HP = m_m_dot_htr_hp * (m_enth[C_sco2_cycle_core::HTR_HP_OUT] - m_enth[C_sco2_cycle_core::MIXER_OUT]); + m_outputs.m_Q_dot_HTR_LP = m_outputs.m_m_dot_t * (m_outputs.m_enth[C_sco2_cycle_core::TURB_OUT] - m_outputs.m_enth[C_sco2_cycle_core::HTR_LP_OUT]); + m_outputs.m_Q_dot_HTR_HP = m_outputs.m_m_dot_htr_hp * (m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT] - m_outputs.m_enth[C_sco2_cycle_core::MIXER_OUT]); } // Calculate Bypass Energy { // Set Bypass Temp based on HTR_HP_OUT - m_temp[C_sco2_cycle_core::BYPASS_OUT] = m_temp[C_sco2_cycle_core::HTR_HP_OUT] + m_inputs.m_dT_BP; + m_outputs.m_temp[C_sco2_cycle_core::BYPASS_OUT] = m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT] + m_inputs.m_dT_BP; // Calculate BYPASS_OUT properties - int prop_error_code = CO2_TP(this->m_temp[C_sco2_cycle_core::BYPASS_OUT], this->m_pres[C_sco2_cycle_core::BYPASS_OUT], &this->m_co2_props); + int prop_error_code = CO2_TP(m_outputs.m_temp[C_sco2_cycle_core::BYPASS_OUT], m_outputs.m_pres[C_sco2_cycle_core::BYPASS_OUT], &m_co2_props); if (prop_error_code != 0) { - m_error_code = -1; - return m_error_code; + m_outputs.m_error_code = -1; + return m_outputs.m_error_code; } - this->m_enth[C_sco2_cycle_core::BYPASS_OUT] = this->m_co2_props.enth; - this->m_entr[C_sco2_cycle_core::BYPASS_OUT] = this->m_co2_props.entr; - this->m_dens[C_sco2_cycle_core::BYPASS_OUT] = this->m_co2_props.dens; + m_outputs.m_enth[C_sco2_cycle_core::BYPASS_OUT] = m_co2_props.enth; + m_outputs.m_entr[C_sco2_cycle_core::BYPASS_OUT] = m_co2_props.entr; + m_outputs.m_dens[C_sco2_cycle_core::BYPASS_OUT] = m_co2_props.dens; // Calculate Heat Transfer in Bypass - m_Q_dot_BP = m_m_dot_bp * (m_enth[C_sco2_cycle_core::BYPASS_OUT] - m_enth[C_sco2_cycle_core::MIXER_OUT]); + m_outputs.m_Q_dot_BP = m_outputs.m_m_dot_bp * (m_outputs.m_enth[C_sco2_cycle_core::BYPASS_OUT] - m_outputs.m_enth[C_sco2_cycle_core::MIXER_OUT]); } // Simulate Mixer 2 @@ -353,53 +353,53 @@ int C_sco2_htrbp_core::Solve() // If Bypass and HTR have flow if (m_inputs.m_bypass_frac >= 1e-12 && m_inputs.m_bypass_frac <= (1.0 - 1e-12)) { - m_enth[C_sco2_cycle_core::MIXER2_OUT] = (1.0 - m_inputs.m_bypass_frac) * m_enth[C_sco2_cycle_core::HTR_HP_OUT] + - m_inputs.m_bypass_frac * m_enth[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::kJ/kg] + m_outputs.m_enth[C_sco2_cycle_core::MIXER2_OUT] = (1.0 - m_inputs.m_bypass_frac) * m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT] + + m_inputs.m_bypass_frac * m_outputs.m_enth[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::kJ/kg] - int prop_error_code = CO2_PH(m_pres[C_sco2_cycle_core::MIXER2_OUT], m_enth[C_sco2_cycle_core::MIXER2_OUT], &m_co2_props); + int prop_error_code = CO2_PH(m_outputs.m_pres[C_sco2_cycle_core::MIXER2_OUT], m_outputs.m_enth[C_sco2_cycle_core::MIXER2_OUT], &m_co2_props); if (prop_error_code != 0) { - m_error_code = -1; - return m_error_code; + m_outputs.m_error_code = -1; + return m_outputs.m_error_code; } - m_temp[C_sco2_cycle_core::MIXER2_OUT] = m_co2_props.temp; //[C_sco2_cycle_core::K] - m_entr[C_sco2_cycle_core::MIXER2_OUT] = m_co2_props.entr; //[C_sco2_cycle_core::kJ/kg-K] - m_dens[C_sco2_cycle_core::MIXER2_OUT] = m_co2_props.dens; //[C_sco2_cycle_core::kg/m^3] + m_outputs.m_temp[C_sco2_cycle_core::MIXER2_OUT] = m_co2_props.temp; //[C_sco2_cycle_core::K] + m_outputs.m_entr[C_sco2_cycle_core::MIXER2_OUT] = m_co2_props.entr; //[C_sco2_cycle_core::kJ/kg-K] + m_outputs.m_dens[C_sco2_cycle_core::MIXER2_OUT] = m_co2_props.dens; //[C_sco2_cycle_core::kg/m^3] } // Flow only through HTR else if (m_inputs.m_bypass_frac <= (1.0 - 1e-12)) { - m_temp[C_sco2_cycle_core::MIXER2_OUT] = m_temp[C_sco2_cycle_core::HTR_HP_OUT]; //[C_sco2_cycle_core::K] - m_enth[C_sco2_cycle_core::MIXER2_OUT] = m_enth[C_sco2_cycle_core::HTR_HP_OUT]; //[C_sco2_cycle_core::kJ/kg] - m_entr[C_sco2_cycle_core::MIXER2_OUT] = m_entr[C_sco2_cycle_core::HTR_HP_OUT]; //[C_sco2_cycle_core::kJ/kg-K] - m_dens[C_sco2_cycle_core::MIXER2_OUT] = m_dens[C_sco2_cycle_core::HTR_HP_OUT]; //[C_sco2_cycle_core::kg/m^3] + m_outputs.m_temp[C_sco2_cycle_core::MIXER2_OUT] = m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT]; //[C_sco2_cycle_core::K] + m_outputs.m_enth[C_sco2_cycle_core::MIXER2_OUT] = m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT]; //[C_sco2_cycle_core::kJ/kg] + m_outputs.m_entr[C_sco2_cycle_core::MIXER2_OUT] = m_outputs.m_entr[C_sco2_cycle_core::HTR_HP_OUT]; //[C_sco2_cycle_core::kJ/kg-K] + m_outputs.m_dens[C_sco2_cycle_core::MIXER2_OUT] = m_outputs.m_dens[C_sco2_cycle_core::HTR_HP_OUT]; //[C_sco2_cycle_core::kg/m^3] } // Flow only through Bypass else { - m_temp[C_sco2_cycle_core::MIXER2_OUT] = m_temp[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::K] - m_enth[C_sco2_cycle_core::MIXER2_OUT] = m_enth[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::kJ/kg] - m_entr[C_sco2_cycle_core::MIXER2_OUT] = m_entr[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::kJ/kg-K] - m_dens[C_sco2_cycle_core::MIXER2_OUT] = m_dens[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::kg/m^3] + m_outputs.m_temp[C_sco2_cycle_core::MIXER2_OUT] = m_outputs.m_temp[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::K] + m_outputs.m_enth[C_sco2_cycle_core::MIXER2_OUT] = m_outputs.m_enth[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::kJ/kg] + m_outputs.m_entr[C_sco2_cycle_core::MIXER2_OUT] = m_outputs.m_entr[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::kJ/kg-K] + m_outputs.m_dens[C_sco2_cycle_core::MIXER2_OUT] = m_outputs.m_dens[C_sco2_cycle_core::BYPASS_OUT]; //[C_sco2_cycle_core::kg/m^3] } } // Calculate PHX Heat Transfer { - m_Q_dot_PHX = m_m_dot_t * (m_enth[C_sco2_cycle_core::TURB_IN] - m_enth[C_sco2_cycle_core::MIXER2_OUT]); + m_outputs.m_Q_dot_PHX = m_outputs.m_m_dot_t * (m_outputs.m_enth[C_sco2_cycle_core::TURB_IN] - m_outputs.m_enth[C_sco2_cycle_core::MIXER2_OUT]); } // Back Calculate and Check values { // Bypass Temps - double bp_temp_in = m_temp[C_sco2_cycle_core::MIXER_OUT]; - double bp_temp_out = m_temp[C_sco2_cycle_core::BYPASS_OUT]; + double bp_temp_in = m_outputs.m_temp[C_sco2_cycle_core::MIXER_OUT]; + double bp_temp_out = m_outputs.m_temp[C_sco2_cycle_core::BYPASS_OUT]; - double real_q_dot_total = m_W_dot_t + m_Q_dot_air_cooler; + double real_q_dot_total = m_outputs.m_W_dot_t + m_outputs.m_Q_dot_air_cooler; - double qSum = m_Q_dot_total; - double qSum_calc = m_Q_dot_BP + m_Q_dot_PHX; + double qSum = m_outputs.m_Q_dot_total; + double qSum_calc = m_outputs.m_Q_dot_BP + m_outputs.m_Q_dot_PHX; int x = 0; } @@ -410,29 +410,29 @@ int C_sco2_htrbp_core::Solve() if (m_inputs.m_set_HTF_mdot > 0) { // Mdot is Set - m_m_dot_HTF = m_inputs.m_set_HTF_mdot; + m_outputs.m_m_dot_HTF = m_inputs.m_set_HTF_mdot; // Calculate PHX HTF Outlet Temperature - m_T_HTF_PHX_out = m_inputs.m_T_HTF_PHX_inlet - m_Q_dot_PHX / (m_m_dot_HTF * m_inputs.m_cp_HTF); + m_outputs.m_T_HTF_PHX_out = m_inputs.m_T_HTF_PHX_inlet - m_outputs.m_Q_dot_PHX / (m_outputs.m_m_dot_HTF * m_inputs.m_cp_HTF); // Back Calculate PHX cold approach - m_HTF_PHX_cold_approach = m_T_HTF_PHX_out - m_temp[C_sco2_cycle_core::MIXER2_OUT]; + m_outputs.m_HTF_PHX_cold_approach = m_outputs.m_T_HTF_PHX_out - m_outputs.m_temp[C_sco2_cycle_core::MIXER2_OUT]; } else { // Use HTF Bypass cold approach to calculate PHX outlet Temperature - m_T_HTF_PHX_out = m_inputs.m_HTF_PHX_cold_approach_input + m_temp[C_sco2_cycle_core::MIXER2_OUT]; - m_HTF_PHX_cold_approach = m_inputs.m_HTF_PHX_cold_approach_input; + m_outputs.m_T_HTF_PHX_out = m_inputs.m_HTF_PHX_cold_approach_input + m_outputs.m_temp[C_sco2_cycle_core::MIXER2_OUT]; + m_outputs.m_HTF_PHX_cold_approach = m_inputs.m_HTF_PHX_cold_approach_input; // Calculate HTF mdot - m_m_dot_HTF = m_Q_dot_PHX / ((m_inputs.m_T_HTF_PHX_inlet - m_T_HTF_PHX_out) * m_inputs.m_cp_HTF); + m_outputs.m_m_dot_HTF = m_outputs.m_Q_dot_PHX / ((m_inputs.m_T_HTF_PHX_inlet - m_outputs.m_T_HTF_PHX_out) * m_inputs.m_cp_HTF); } // Calculate Bypass Out Temperature - m_T_HTF_BP_outlet = m_T_HTF_PHX_out - (m_Q_dot_BP / (m_m_dot_HTF * m_inputs.m_cp_HTF)); + m_outputs.m_T_HTF_BP_outlet = m_outputs.m_T_HTF_PHX_out - (m_outputs.m_Q_dot_BP / (m_outputs.m_m_dot_HTF * m_inputs.m_cp_HTF)); // Calculate HTF Bypass Cold Approach - m_HTF_BP_cold_approach = m_T_HTF_BP_outlet - m_temp[C_sco2_cycle_core::MIXER_OUT]; + m_outputs.m_HTF_BP_cold_approach = m_outputs.m_T_HTF_BP_outlet - m_outputs.m_temp[C_sco2_cycle_core::MIXER_OUT]; } @@ -440,39 +440,39 @@ int C_sco2_htrbp_core::Solve() { // PHX C_HeatExchanger::S_design_parameters PHX_des_par; - PHX_des_par.m_DP_design[0] = m_pres[C_sco2_cycle_core::MIXER2_OUT] - m_pres[C_sco2_cycle_core::TURB_IN]; + PHX_des_par.m_DP_design[0] = m_outputs.m_pres[C_sco2_cycle_core::MIXER2_OUT] - m_outputs.m_pres[C_sco2_cycle_core::TURB_IN]; PHX_des_par.m_DP_design[1] = 0.0; - PHX_des_par.m_m_dot_design[0] = m_m_dot_t; + PHX_des_par.m_m_dot_design[0] = m_outputs.m_m_dot_t; PHX_des_par.m_m_dot_design[1] = 0.0; - PHX_des_par.m_Q_dot_design = m_m_dot_t * (m_enth[C_sco2_cycle_core::TURB_IN] - m_enth[C_sco2_cycle_core::MIXER2_OUT]); - m_PHX.initialize(PHX_des_par); + PHX_des_par.m_Q_dot_design = m_outputs.m_m_dot_t * (m_outputs.m_enth[C_sco2_cycle_core::TURB_IN] - m_outputs.m_enth[C_sco2_cycle_core::MIXER2_OUT]); + m_outputs.m_PHX.initialize(PHX_des_par); // BPX C_HeatExchanger::S_design_parameters BPX_des_par; - BPX_des_par.m_DP_design[0] = m_pres[C_sco2_cycle_core::MIXER_OUT] - m_pres[C_sco2_cycle_core::BYPASS_OUT]; + BPX_des_par.m_DP_design[0] = m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT] - m_outputs.m_pres[C_sco2_cycle_core::BYPASS_OUT]; BPX_des_par.m_DP_design[1] = 0.0; - BPX_des_par.m_m_dot_design[0] = m_m_dot_bp; + BPX_des_par.m_m_dot_design[0] = m_outputs.m_m_dot_bp; BPX_des_par.m_m_dot_design[1] = 0.0; - BPX_des_par.m_Q_dot_design = m_m_dot_bp * (m_enth[C_sco2_cycle_core::BYPASS_OUT] - m_enth[C_sco2_cycle_core::MIXER_OUT]); - m_BPX.initialize(BPX_des_par); + BPX_des_par.m_Q_dot_design = m_outputs.m_m_dot_bp * (m_outputs.m_enth[C_sco2_cycle_core::BYPASS_OUT] - m_outputs.m_enth[C_sco2_cycle_core::MIXER_OUT]); + m_outputs.m_BPX.initialize(BPX_des_par); // Design air cooler // Structure for design parameters that are dependent on cycle design solution C_CO2_to_air_cooler::S_des_par_cycle_dep s_air_cooler_des_par_dep; // Set air cooler design parameters that are dependent on the cycle design solution - s_air_cooler_des_par_dep.m_T_hot_in_des = m_temp[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT]; //[K] - s_air_cooler_des_par_dep.m_P_hot_in_des = m_pres[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT]; //[kPa] - s_air_cooler_des_par_dep.m_m_dot_total = m_m_dot_mc; //[kg/s] + s_air_cooler_des_par_dep.m_T_hot_in_des = m_outputs.m_temp[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT]; //[K] + s_air_cooler_des_par_dep.m_P_hot_in_des = m_outputs.m_pres[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT]; //[kPa] + s_air_cooler_des_par_dep.m_m_dot_total = m_outputs.m_m_dot_mc; //[kg/s] // This pressure drop is currently uncoupled from the cycle design - double cooler_deltaP = m_pres[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT] - m_pres[C_sco2_cycle_core::C_sco2_cycle_core::MC_IN]; //[kPa] + double cooler_deltaP = m_outputs.m_pres[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT] - m_outputs.m_pres[C_sco2_cycle_core::C_sco2_cycle_core::MC_IN]; //[kPa] if (cooler_deltaP == 0.0) - s_air_cooler_des_par_dep.m_delta_P_des = m_inputs.m_deltaP_cooler_frac * m_pres[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT]; //[kPa] + s_air_cooler_des_par_dep.m_delta_P_des = m_inputs.m_deltaP_cooler_frac * m_outputs.m_pres[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT]; //[kPa] else s_air_cooler_des_par_dep.m_delta_P_des = cooler_deltaP; //[kPa] - s_air_cooler_des_par_dep.m_T_hot_out_des = m_temp[C_sco2_cycle_core::C_sco2_cycle_core::MC_IN]; //[K] - s_air_cooler_des_par_dep.m_W_dot_fan_des = m_W_dot_air_cooler / 1000.0; //[MWe] + s_air_cooler_des_par_dep.m_T_hot_out_des = m_outputs.m_temp[C_sco2_cycle_core::C_sco2_cycle_core::MC_IN]; //[K] + s_air_cooler_des_par_dep.m_W_dot_fan_des = m_outputs.m_W_dot_air_cooler / 1000.0; //[MWe] // Structure for design parameters that are independent of cycle design solution C_CO2_to_air_cooler::S_des_par_ind s_air_cooler_des_par_ind; s_air_cooler_des_par_ind.m_T_amb_des = m_inputs.m_T_amb_des; //[K] @@ -484,47 +484,47 @@ int C_sco2_htrbp_core::Solve() // Calculate Thermal Efficiency { - m_eta_thermal = m_W_dot_net / m_Q_dot_total; + m_outputs.m_eta_thermal = m_outputs.m_W_dot_net / m_outputs.m_Q_dot_total; } - m_error_code = 0; - return m_error_code; + m_outputs.m_error_code = 0; + return m_outputs.m_error_code; } -int C_sco2_htrbp_core::C_mono_htrbp_core_HTR_des::operator()(double T_HTR_LP_OUT_guess /*K*/, double* diff_T_HTR_LP_out) -{ - return m_htr_bypass_cycle->solve_HTR(T_HTR_LP_OUT_guess, diff_T_HTR_LP_out); -} - -int C_sco2_htrbp_core::C_mono_htrbp_core_LTR_des::operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out) -{ - return m_htr_bypass_cycle->solve_LTR(T_LTR_LP_OUT_guess, diff_T_LTR_LP_out); -} +//int C_sco2_htrbp_core::C_mono_htrbp_core_HTR_des::operator()(double T_HTR_LP_OUT_guess /*K*/, double* diff_T_HTR_LP_out) +//{ +// return m_htr_bypass_cycle->solve_HTR(T_HTR_LP_OUT_guess, diff_T_HTR_LP_out); +//} +// +//int C_sco2_htrbp_core::C_mono_htrbp_core_LTR_des::operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out) +//{ +// return m_htr_bypass_cycle->solve_LTR(T_LTR_LP_OUT_guess, diff_T_LTR_LP_out); +//} int C_sco2_htrbp_core::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out) { - m_w_rc = m_m_dot_t = m_m_dot_rc = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT = std::numeric_limits::quiet_NaN(); + m_outputs.m_w_rc = m_outputs.m_m_dot_t = m_outputs.m_m_dot_rc = m_outputs.m_m_dot_mc = m_outputs.m_Q_dot_LT = m_outputs.m_Q_dot_HT = std::numeric_limits::quiet_NaN(); // Set temperature guess - m_temp[C_sco2_cycle_core::HTR_LP_OUT] = T_HTR_LP_OUT_guess; //[K] + m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT] = T_HTR_LP_OUT_guess; //[K] // Solve HTR_LP_OUT properties { - int prop_error_code = CO2_TP(this->m_temp[C_sco2_cycle_core::HTR_LP_OUT], this->m_pres[C_sco2_cycle_core::HTR_LP_OUT], &this->m_co2_props); + int prop_error_code = CO2_TP(m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT], &m_co2_props); if (prop_error_code != 0) { *diff_T_HTR_LP_out = std::numeric_limits::quiet_NaN(); return prop_error_code; } - this->m_enth[C_sco2_cycle_core::HTR_LP_OUT] = this->m_co2_props.enth; - this->m_entr[C_sco2_cycle_core::HTR_LP_OUT] = this->m_co2_props.entr; - this->m_dens[C_sco2_cycle_core::HTR_LP_OUT] = this->m_co2_props.dens; + m_outputs.m_enth[C_sco2_cycle_core::HTR_LP_OUT] = m_co2_props.enth; + m_outputs.m_entr[C_sco2_cycle_core::HTR_LP_OUT] = m_co2_props.entr; + m_outputs.m_dens[C_sco2_cycle_core::HTR_LP_OUT] = m_co2_props.dens; } // Solve for the LTR solution { - double T_LTR_LP_out_lower = this->m_temp[C_sco2_cycle_core::MC_OUT]; //[K] Coldest possible outlet temperature - double T_LTR_LP_out_upper = this->m_temp[C_sco2_cycle_core::HTR_LP_OUT]; //[K] Hottest possible outlet temperature + double T_LTR_LP_out_lower = m_outputs.m_temp[C_sco2_cycle_core::MC_OUT]; //[K] Coldest possible outlet temperature + double T_LTR_LP_out_upper = m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT]; //[K] Hottest possible outlet temperature double T_LTR_LP_out_guess_upper = std::min(T_LTR_LP_out_upper, T_LTR_LP_out_lower + 15.0); //[K] There is nothing special about using 15 here... double T_LTR_LP_out_guess_lower = std::min(T_LTR_LP_out_guess_upper * 0.99, T_LTR_LP_out_lower + 2.0); //[K] There is nothing special about using 2 here... @@ -532,7 +532,7 @@ int C_sco2_htrbp_core::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_L C_mono_htrbp_core_LTR_des LTR_des_eq(this); C_monotonic_eq_solver LTR_des_solver(LTR_des_eq); - LTR_des_solver.settings(this->m_inputs.m_des_tol * this->m_temp[C_sco2_cycle_core::MC_IN], 1000, T_LTR_LP_out_lower, + LTR_des_solver.settings(m_inputs.m_des_tol * m_outputs.m_temp[C_sco2_cycle_core::MC_IN], 1000, T_LTR_LP_out_lower, T_LTR_LP_out_upper, false); double T_LTR_LP_out_solved = std::numeric_limits::quiet_NaN(); @@ -550,67 +550,67 @@ int C_sco2_htrbp_core::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_L // Know LTR performance so we can calculate the HP outlet (Energy balance on LTR HP stream) { - this->m_enth[C_sco2_cycle_core::LTR_HP_OUT] = this->m_enth[C_sco2_cycle_core::MC_OUT] + m_Q_dot_LT / m_m_dot_mc; //[kJ/kg] - int prop_error_code = CO2_PH(this->m_pres[C_sco2_cycle_core::LTR_HP_OUT], this->m_enth[C_sco2_cycle_core::LTR_HP_OUT], &this->m_co2_props); + m_outputs.m_enth[C_sco2_cycle_core::LTR_HP_OUT] = m_outputs.m_enth[C_sco2_cycle_core::MC_OUT] + m_outputs.m_Q_dot_LT / m_outputs.m_m_dot_mc; //[kJ/kg] + int prop_error_code = CO2_PH(m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT], m_outputs.m_enth[C_sco2_cycle_core::LTR_HP_OUT], &m_co2_props); if (prop_error_code != 0) { *diff_T_HTR_LP_out = std::numeric_limits::quiet_NaN(); return prop_error_code; } - this->m_temp[C_sco2_cycle_core::LTR_HP_OUT] = this->m_co2_props.temp; //[K] - this->m_entr[C_sco2_cycle_core::LTR_HP_OUT] = this->m_co2_props.entr; //[kJ/kg-K] - this->m_dens[C_sco2_cycle_core::LTR_HP_OUT] = this->m_co2_props.dens; //[kg/m^3] + m_outputs.m_temp[C_sco2_cycle_core::LTR_HP_OUT] = m_co2_props.temp; //[K] + m_outputs.m_entr[C_sco2_cycle_core::LTR_HP_OUT] = m_co2_props.entr; //[kJ/kg-K] + m_outputs.m_dens[C_sco2_cycle_core::LTR_HP_OUT] = m_co2_props.dens; //[kg/m^3] } // Simulate the Mixer - if (this->m_inputs.m_recomp_frac >= 1.E-12) + if (m_inputs.m_recomp_frac >= 1.E-12) { - this->m_enth[C_sco2_cycle_core::MIXER_OUT] = (1.0 - this->m_inputs.m_recomp_frac) * this->m_enth[C_sco2_cycle_core::LTR_HP_OUT] - + this->m_inputs.m_recomp_frac * this->m_enth[C_sco2_cycle_core::RC_OUT]; //[kJ/kg] - int prop_error_code = CO2_PH(this->m_pres[C_sco2_cycle_core::MIXER_OUT], this->m_enth[C_sco2_cycle_core::MIXER_OUT], &this->m_co2_props); + m_outputs.m_enth[C_sco2_cycle_core::MIXER_OUT] = (1.0 - m_inputs.m_recomp_frac) * m_outputs.m_enth[C_sco2_cycle_core::LTR_HP_OUT] + + m_inputs.m_recomp_frac * m_outputs.m_enth[C_sco2_cycle_core::RC_OUT]; //[kJ/kg] + int prop_error_code = CO2_PH(m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT], m_outputs.m_enth[C_sco2_cycle_core::MIXER_OUT], &m_co2_props); if (prop_error_code != 0) { *diff_T_HTR_LP_out = std::numeric_limits::quiet_NaN(); return prop_error_code; } - this->m_temp[C_sco2_cycle_core::MIXER_OUT] = this->m_co2_props.temp; //[K] - this->m_entr[C_sco2_cycle_core::MIXER_OUT] = this->m_co2_props.entr; //[kJ/kg-K] - this->m_dens[C_sco2_cycle_core::MIXER_OUT] = this->m_co2_props.dens; //[kg/m^3] + m_outputs.m_temp[C_sco2_cycle_core::MIXER_OUT] = m_co2_props.temp; //[K] + m_outputs.m_entr[C_sco2_cycle_core::MIXER_OUT] = m_co2_props.entr; //[kJ/kg-K] + m_outputs.m_dens[C_sco2_cycle_core::MIXER_OUT] = m_co2_props.dens; //[kg/m^3] } else { // No recompressor, so no mixing required, and HTR HP inlet = LTR HP outlet - this->m_temp[C_sco2_cycle_core::MIXER_OUT] = this->m_temp[C_sco2_cycle_core::LTR_HP_OUT]; //[K] - this->m_enth[C_sco2_cycle_core::MIXER_OUT] = this->m_enth[C_sco2_cycle_core::LTR_HP_OUT]; //[kJ/kg] - this->m_entr[C_sco2_cycle_core::MIXER_OUT] = this->m_entr[C_sco2_cycle_core::LTR_HP_OUT]; //[kJ/kg-K] - this->m_dens[C_sco2_cycle_core::MIXER_OUT] = this->m_dens[C_sco2_cycle_core::LTR_HP_OUT]; //[kg/m^3] + m_outputs.m_temp[C_sco2_cycle_core::MIXER_OUT] = m_outputs.m_temp[C_sco2_cycle_core::LTR_HP_OUT]; //[K] + m_outputs.m_enth[C_sco2_cycle_core::MIXER_OUT] = m_outputs.m_enth[C_sco2_cycle_core::LTR_HP_OUT]; //[kJ/kg] + m_outputs.m_entr[C_sco2_cycle_core::MIXER_OUT] = m_outputs.m_entr[C_sco2_cycle_core::LTR_HP_OUT]; //[kJ/kg-K] + m_outputs.m_dens[C_sco2_cycle_core::MIXER_OUT] = m_outputs.m_dens[C_sco2_cycle_core::LTR_HP_OUT]; //[kg/m^3] } // Solve Mass Flow rates for HTR_HP_OUT and Bypass { - m_m_dot_bp = m_inputs.m_bypass_frac * m_m_dot_t; - m_m_dot_htr_hp = m_m_dot_t - m_m_dot_bp; + m_outputs.m_m_dot_bp = m_inputs.m_bypass_frac * m_outputs.m_m_dot_t; + m_outputs.m_m_dot_htr_hp = m_outputs.m_m_dot_t - m_outputs.m_m_dot_bp; } // Find the design solution of the HTR double T_HTR_LP_out_calc = std::numeric_limits::quiet_NaN(); { // If there is no flow through HTR HP side - if (m_m_dot_htr_hp < 1e-12) + if (m_outputs.m_m_dot_htr_hp < 1e-12) { - m_Q_dot_HT = 0; - T_HTR_LP_out_calc = m_temp[C_sco2_cycle_core::TURB_OUT]; + m_outputs.m_Q_dot_HT = 0; + T_HTR_LP_out_calc = m_outputs.m_temp[C_sco2_cycle_core::TURB_OUT]; } // If there is flow through HTR HP side else { - this->mc_HT_recup.design_for_target__calc_outlet(this->m_inputs.m_HTR_target_code, - this->m_inputs.m_HTR_UA, this->m_inputs.m_HTR_min_dT, this->m_inputs.m_HTR_eff_target, - this->m_inputs.m_HTR_eff_max, - this->m_temp[C_sco2_cycle_core::MIXER_OUT], this->m_pres[C_sco2_cycle_core::MIXER_OUT], m_m_dot_htr_hp, this->m_pres[C_sco2_cycle_core::HTR_HP_OUT], - this->m_temp[C_sco2_cycle_core::TURB_OUT], this->m_pres[C_sco2_cycle_core::TURB_OUT], m_m_dot_t, this->m_pres[C_sco2_cycle_core::HTR_LP_OUT], - this->m_inputs.m_des_tol, - m_Q_dot_HT, this->m_temp[C_sco2_cycle_core::HTR_HP_OUT], T_HTR_LP_out_calc); + m_outputs.mc_HT_recup.design_for_target__calc_outlet(m_inputs.m_HTR_target_code, + m_inputs.m_HTR_UA, m_inputs.m_HTR_min_dT, m_inputs.m_HTR_eff_target, + m_inputs.m_HTR_eff_max, + m_outputs.m_temp[C_sco2_cycle_core::MIXER_OUT], m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT], m_outputs.m_m_dot_htr_hp, m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], + m_outputs.m_temp[C_sco2_cycle_core::TURB_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT], m_outputs.m_m_dot_t, m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT], + m_inputs.m_des_tol, + m_outputs.m_Q_dot_HT, m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT], T_HTR_LP_out_calc); } } @@ -622,21 +622,21 @@ int C_sco2_htrbp_core::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_L int C_sco2_htrbp_core::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_LP_out) { - m_w_rc = m_m_dot_t = m_m_dot_rc = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT = std::numeric_limits::quiet_NaN(); + m_outputs.m_w_rc = m_outputs.m_m_dot_t = m_outputs.m_m_dot_rc = m_outputs.m_m_dot_mc = m_outputs.m_Q_dot_LT = m_outputs.m_Q_dot_HT = std::numeric_limits::quiet_NaN(); // Set LTR_LP_OUT guess - this->m_temp[C_sco2_cycle_core::LTR_LP_OUT] = T_LTR_LP_OUT_guess; + m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT] = T_LTR_LP_OUT_guess; // First, solve the recompressor model as necessary - if (this->m_inputs.m_recomp_frac >= 1.E-12) + if (m_inputs.m_recomp_frac >= 1.E-12) { double eta_rc_isen = std::numeric_limits::quiet_NaN(); - if (this->m_inputs.m_eta_rc < 0.0) // recalculate isen. efficiency of recompressor because inlet temp changes + if (m_inputs.m_eta_rc < 0.0) // recalculate isen. efficiency of recompressor because inlet temp changes { int rc_error_code = 0; - isen_eta_from_poly_eta(this->m_temp[C_sco2_cycle_core::LTR_LP_OUT], this->m_pres[C_sco2_cycle_core::LTR_LP_OUT], - this->m_pres[C_sco2_cycle_core::RC_OUT], std::abs(this->m_inputs.m_eta_rc), true, + isen_eta_from_poly_eta(m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT], m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT], + m_outputs.m_pres[C_sco2_cycle_core::RC_OUT], std::abs(m_inputs.m_eta_rc), true, rc_error_code, eta_rc_isen); if (rc_error_code != 0) @@ -647,14 +647,14 @@ int C_sco2_htrbp_core::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_L } else { - eta_rc_isen = this->m_inputs.m_eta_rc; + eta_rc_isen = m_inputs.m_eta_rc; } int rc_error_code = 0; - calculate_turbomachinery_outlet_1(this->m_temp[C_sco2_cycle_core::LTR_LP_OUT], this->m_pres[C_sco2_cycle_core::LTR_LP_OUT], this->m_pres[C_sco2_cycle_core::RC_OUT], eta_rc_isen, true, rc_error_code, - this->m_enth[C_sco2_cycle_core::LTR_LP_OUT], this->m_entr[C_sco2_cycle_core::LTR_LP_OUT], this->m_dens[C_sco2_cycle_core::LTR_LP_OUT], this->m_temp[C_sco2_cycle_core::RC_OUT], this->m_enth[C_sco2_cycle_core::RC_OUT], - this->m_entr[C_sco2_cycle_core::RC_OUT], this->m_dens[C_sco2_cycle_core::RC_OUT], m_w_rc); + calculate_turbomachinery_outlet_1(m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT], m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT], m_outputs.m_pres[C_sco2_cycle_core::RC_OUT], eta_rc_isen, true, rc_error_code, + m_outputs.m_enth[C_sco2_cycle_core::LTR_LP_OUT], m_outputs.m_entr[C_sco2_cycle_core::LTR_LP_OUT], m_outputs.m_dens[C_sco2_cycle_core::LTR_LP_OUT], m_outputs.m_temp[C_sco2_cycle_core::RC_OUT], m_outputs.m_enth[C_sco2_cycle_core::RC_OUT], + m_outputs.m_entr[C_sco2_cycle_core::RC_OUT], m_outputs.m_dens[C_sco2_cycle_core::RC_OUT], m_outputs.m_w_rc); if (rc_error_code != 0) { @@ -664,42 +664,42 @@ int C_sco2_htrbp_core::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_L } else { - m_w_rc = 0.0; // no recompressor - int prop_error_code = CO2_TP(this->m_temp[C_sco2_cycle_core::LTR_LP_OUT], this->m_pres[C_sco2_cycle_core::LTR_LP_OUT], &this->m_co2_props); + m_outputs.m_w_rc = 0.0; // no recompressor + int prop_error_code = CO2_TP(m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT], m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT], &m_co2_props); if (prop_error_code != 0) { *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); return prop_error_code; } - this->m_enth[C_sco2_cycle_core::LTR_LP_OUT] = this->m_co2_props.enth; - this->m_entr[C_sco2_cycle_core::LTR_LP_OUT] = this->m_co2_props.entr; - this->m_dens[C_sco2_cycle_core::LTR_LP_OUT] = this->m_co2_props.dens; - this->m_temp[C_sco2_cycle_core::RC_OUT] = this->m_temp[C_sco2_cycle_core::LTR_LP_OUT]; - this->m_enth[C_sco2_cycle_core::RC_OUT] = this->m_enth[C_sco2_cycle_core::LTR_LP_OUT]; - this->m_entr[C_sco2_cycle_core::RC_OUT] = this->m_entr[C_sco2_cycle_core::LTR_LP_OUT]; - this->m_dens[C_sco2_cycle_core::RC_OUT] = this->m_dens[C_sco2_cycle_core::LTR_LP_OUT]; + m_outputs.m_enth[C_sco2_cycle_core::LTR_LP_OUT] = m_co2_props.enth; + m_outputs.m_entr[C_sco2_cycle_core::LTR_LP_OUT] = m_co2_props.entr; + m_outputs.m_dens[C_sco2_cycle_core::LTR_LP_OUT] = m_co2_props.dens; + m_outputs.m_temp[C_sco2_cycle_core::RC_OUT] = m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT]; + m_outputs.m_enth[C_sco2_cycle_core::RC_OUT] = m_outputs.m_enth[C_sco2_cycle_core::LTR_LP_OUT]; + m_outputs.m_entr[C_sco2_cycle_core::RC_OUT] = m_outputs.m_entr[C_sco2_cycle_core::LTR_LP_OUT]; + m_outputs.m_dens[C_sco2_cycle_core::RC_OUT] = m_outputs.m_dens[C_sco2_cycle_core::LTR_LP_OUT]; } // Solve Mass Flow Rates { - m_m_dot_t = this->m_inputs.m_W_dot_net_design / ((m_w_mc * (1.0 - this->m_inputs.m_recomp_frac) + - m_w_rc * this->m_inputs.m_recomp_frac + m_w_t) * this->m_inputs.m_eta_generator); //[C_sco2_cycle_core::kg/s] + m_outputs.m_m_dot_t = m_inputs.m_W_dot_net_design / ((m_outputs.m_w_mc * (1.0 - m_inputs.m_recomp_frac) + + m_outputs.m_w_rc * m_inputs.m_recomp_frac + m_outputs.m_w_t) * m_inputs.m_eta_generator); //[C_sco2_cycle_core::kg/s] - m_m_dot_rc = m_m_dot_t * this->m_inputs.m_recomp_frac; //[C_sco2_cycle_core::kg/s] - m_m_dot_mc = m_m_dot_t - m_m_dot_rc; + m_outputs.m_m_dot_rc = m_outputs.m_m_dot_t * m_inputs.m_recomp_frac; //[C_sco2_cycle_core::kg/s] + m_outputs.m_m_dot_mc = m_outputs.m_m_dot_t - m_outputs.m_m_dot_rc; } // Solve LTR *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); double T_LTR_LP_out_calc = std::numeric_limits::quiet_NaN(); { - this->mc_LT_recup.design_for_target__calc_outlet(this->m_inputs.m_LTR_target_code, - this->m_inputs.m_LTR_UA, this->m_inputs.m_LTR_min_dT, this->m_inputs.m_LTR_eff_target, - this->m_inputs.m_LTR_eff_max, - this->m_temp[C_sco2_cycle_core::MC_OUT], this->m_pres[C_sco2_cycle_core::MC_OUT], m_m_dot_mc, this->m_pres[C_sco2_cycle_core::LTR_HP_OUT], - this->m_temp[C_sco2_cycle_core::HTR_LP_OUT], this->m_pres[C_sco2_cycle_core::HTR_LP_OUT], m_m_dot_t, this->m_pres[C_sco2_cycle_core::LTR_LP_OUT], - this->m_inputs.m_des_tol, - m_Q_dot_LT, this->m_temp[C_sco2_cycle_core::LTR_HP_OUT], T_LTR_LP_out_calc); + m_outputs.mc_LT_recup.design_for_target__calc_outlet(m_inputs.m_LTR_target_code, + m_inputs.m_LTR_UA, m_inputs.m_LTR_min_dT, m_inputs.m_LTR_eff_target, + m_inputs.m_LTR_eff_max, + m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], m_outputs.m_m_dot_mc, m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT], + m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT], m_outputs.m_m_dot_t, m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT], + m_inputs.m_des_tol, + m_outputs.m_Q_dot_LT, m_outputs.m_temp[C_sco2_cycle_core::LTR_HP_OUT], T_LTR_LP_out_calc); } @@ -710,9 +710,7 @@ int C_sco2_htrbp_core::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_L void C_sco2_htrbp_core::InitializeSolve() { - m_temp.resize(C_sco2_cycle_core::END_SCO2_STATES); - std::fill(m_temp.begin(), m_temp.end(), std::numeric_limits::quiet_NaN()); - m_pres = m_enth = m_entr = m_dens = m_temp; + m_outputs.Init(); } @@ -775,7 +773,7 @@ void C_HTRBypass_Cycle::design_core(int& error_code) C_sco2_htrbp_core sco2_core; sco2_core.SetInputs(core_inputs); int err = sco2_core.Solve(); - + int ta = 0; } diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 4663eda3a9..1c3332d7cd 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -146,17 +146,60 @@ struct S_sco2_htrbp_in }; // Defines sco2 htr bypass output variables (no optimized variables) -//struct S_sco2_htrbp_out -//{ -// int m_error_code; -// double m_eta_thermal; // Thermal Efficiency -// -// S_sco2_htrbp_out() -// { -// m_error_code = m_eta_thermal -// = std::numeric_limits::quiet_NaN(); -// } -//}; +struct S_sco2_htrbp_out +{ + int m_error_code; + C_turbine m_t; // Turbine model + C_comp_multi_stage m_mc_ms; // Main Compressor Model + C_comp_multi_stage m_rc_ms; // Recompressor Model + C_HeatExchanger m_PHX, m_PC, m_BPX; // Primary, Cooler, Bypass Heat Exchanger Models + C_HX_co2_to_co2_CRM mc_LT_recup; // LTR + C_HX_co2_to_co2_CRM mc_HT_recup; // HTR + C_CO2_to_air_cooler mc_air_cooler; // Air Cooler + std::vector m_temp, m_pres, m_enth, m_entr, m_dens; // thermodynamic states (K, kPa, kJ/kg, kJ/kg-K, kg/m3) + double m_w_t, m_w_mc, m_w_rc; // [kJ/kg] specific work of turbine, main compressor, recompressor + double m_m_dot_t, m_m_dot_mc, m_m_dot_rc; // [kg/s] sco2 Mass flow in main compressor, recompressor, turbine + double m_m_dot_bp, m_m_dot_htr_hp; // [kg/s] sco2 Mass flow through bypass, hot side HTR + double m_Q_dot_LT, m_Q_dot_HT; // [kWt] Heat Transfer in LTR, HTR + double m_W_dot_mc, m_W_dot_rc, m_W_dot_t; // [kWt] Energy consumed by main compressor, recompressor, produced by turbine + double m_W_dot_net; // [kWt] ACTUAL produced net work in system + double m_W_dot_air_cooler; // [kWe] Energy consumed by air cooler + double m_Q_dot_air_cooler; // [kWt] Heat rejected by air cooler + double m_Q_dot_LTR_LP, m_Q_dot_LTR_HP, m_Q_dot_HTR_LP, m_Q_dot_HTR_HP; // kWt Heat change on LTR low pressure, etc... + double m_Q_dot_total; // [kWt] Total heat entering sco2 + double m_Q_dot_PHX, m_Q_dot_BP; // [kWt] Energy exchange in PHX, BPX + double m_m_dot_HTF; // [kg/s] HTF mass flow rate + double m_T_HTF_PHX_out; // [K] HTF PHX outlet temperature + double m_HTF_PHX_cold_approach; // [delta K/C] PHX cold approach temperature + double m_T_HTF_BP_outlet; // [K] HTF BPX outlet temperature + double m_HTF_BP_cold_approach; // [K] BPX cold approach temperature + double m_eta_thermal; // Thermal Efficiency + + S_sco2_htrbp_out() + { + Init(); + } + + void Init() + { + m_error_code = m_w_t = m_w_mc = m_w_rc + = m_m_dot_t = m_m_dot_mc = m_m_dot_rc + = m_m_dot_bp = m_m_dot_htr_hp + = m_Q_dot_LT = m_Q_dot_HT + = m_W_dot_mc = m_W_dot_rc = m_W_dot_t + = m_W_dot_net = m_W_dot_air_cooler = m_Q_dot_air_cooler + = m_Q_dot_LTR_LP = m_Q_dot_LTR_HP = m_Q_dot_HTR_LP = m_Q_dot_HTR_HP + = m_Q_dot_total = m_Q_dot_PHX = m_Q_dot_BP + = m_m_dot_HTF = m_T_HTF_PHX_out = m_HTF_PHX_cold_approach + = m_T_HTF_BP_outlet = m_HTF_BP_cold_approach = m_eta_thermal + = std::numeric_limits::quiet_NaN(); + + // Clear and Size Output Vectors + m_temp.resize(C_sco2_cycle_core::END_SCO2_STATES); + std::fill(m_temp.begin(), m_temp.end(), std::numeric_limits::quiet_NaN()); + m_pres = m_enth = m_entr = m_dens = m_temp; + } +}; @@ -178,7 +221,10 @@ class C_sco2_htrbp_core m_htr_bypass_cycle = htr_bypass_cycle; } - virtual int operator()(double T_HTR_LP_OUT_guess /*K*/, double* diff_T_HTR_LP_out /*K*/); + virtual int operator()(double T_HTR_LP_OUT_guess /*K*/, double* diff_T_HTR_LP_out /*K*/) + { + return m_htr_bypass_cycle->solve_HTR(T_HTR_LP_OUT_guess, diff_T_HTR_LP_out); + }; }; class C_mono_htrbp_core_LTR_des : public C_monotonic_equation @@ -192,7 +238,10 @@ class C_sco2_htrbp_core m_htr_bypass_cycle = htr_bypass_cycle; } - virtual int operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out /*K*/); + virtual int operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out /*K*/) + { + return m_htr_bypass_cycle->solve_LTR(T_LTR_LP_OUT_guess, diff_T_LTR_LP_out); + }; }; int solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out); @@ -204,33 +253,8 @@ class C_sco2_htrbp_core // Inputs Struct S_sco2_htrbp_in m_inputs; - // Publicly Accessible Fields (Outputs) - int m_error_code; - C_turbine m_t; // Turbine model - C_comp_multi_stage m_mc_ms; // Main Compressor Model - C_comp_multi_stage m_rc_ms; // Recompressor Model - C_HeatExchanger m_PHX, m_PC, m_BPX; // Primary, Cooler, Bypass Heat Exchanger Models - C_HX_co2_to_co2_CRM mc_LT_recup; // LTR - C_HX_co2_to_co2_CRM mc_HT_recup; // HTR - C_CO2_to_air_cooler mc_air_cooler; // Air Cooler - std::vector m_temp, m_pres, m_enth, m_entr, m_dens; // thermodynamic states (K, kPa, kJ/kg, kJ/kg-K, kg/m3) - double m_w_t, m_w_mc, m_w_rc; // [kJ/kg] specific work of turbine, main compressor, recompressor - double m_m_dot_t, m_m_dot_mc, m_m_dot_rc; // [kg/s] sco2 Mass flow in main compressor, recompressor, turbine - double m_m_dot_bp, m_m_dot_htr_hp; // [kg/s] sco2 Mass flow through bypass, hot side HTR - double m_Q_dot_LT, m_Q_dot_HT; // [kWt] Heat Transfer in LTR, HTR - double m_W_dot_mc, m_W_dot_rc, m_W_dot_t; // [kWt] Energy consumed by main compressor, recompressor, produced by turbine - double m_W_dot_net; // [kWt] ACTUAL produced net work in system - double m_W_dot_air_cooler; // [kWe] Energy consumed by air cooler - double m_Q_dot_air_cooler; // [kWt] Heat rejected by air cooler - double m_Q_dot_LTR_LP, m_Q_dot_LTR_HP, m_Q_dot_HTR_LP, m_Q_dot_HTR_HP; // kWt Heat change on LTR low pressure, etc... - double m_Q_dot_total; // [kWt] Total heat entering sco2 - double m_Q_dot_PHX, m_Q_dot_BP; // [kWt] Energy exchange in PHX, BPX - double m_m_dot_HTF; // [kg/s] HTF mass flow rate - double m_T_HTF_PHX_out; // [K] HTF PHX outlet temperature - double m_HTF_PHX_cold_approach; // [delta K/C] PHX cold approach temperature - double m_T_HTF_BP_outlet; // [K] HTF BPX outlet temperature - double m_HTF_BP_cold_approach; // [K] BPX cold approach temperature - double m_eta_thermal; // Thermal Efficiency + // Outputs Struct + S_sco2_htrbp_out m_outputs; // Public Methods void SetInputs(S_sco2_htrbp_in inputs) { m_inputs = inputs; }; From 89c1877d1522515fa2a8df5749979dc3b2f6f6ce Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Thu, 7 Mar 2024 10:41:34 -0700 Subject: [PATCH 34/94] Add basic optimization functionality --- tcs/sco2_htrbypass_cycle.cpp | 655 +++++++++++++++++++++++++++++++---- tcs/sco2_htrbypass_cycle.h | 22 +- 2 files changed, 603 insertions(+), 74 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 9b523cc326..da7a92b02a 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -41,6 +41,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ********************************************************************************** C_sco2_htrbp_core CORE MODEL +void C_sco2_htrbp_core::InitializeSolve() +{ + m_outputs.Init(); +} + int C_sco2_htrbp_core::Solve() { InitializeSolve(); @@ -491,16 +496,6 @@ int C_sco2_htrbp_core::Solve() return m_outputs.m_error_code; } -//int C_sco2_htrbp_core::C_mono_htrbp_core_HTR_des::operator()(double T_HTR_LP_OUT_guess /*K*/, double* diff_T_HTR_LP_out) -//{ -// return m_htr_bypass_cycle->solve_HTR(T_HTR_LP_OUT_guess, diff_T_HTR_LP_out); -//} -// -//int C_sco2_htrbp_core::C_mono_htrbp_core_LTR_des::operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out) -//{ -// return m_htr_bypass_cycle->solve_LTR(T_LTR_LP_OUT_guess, diff_T_LTR_LP_out); -//} - int C_sco2_htrbp_core::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out) { m_outputs.m_w_rc = m_outputs.m_m_dot_t = m_outputs.m_m_dot_rc = m_outputs.m_m_dot_mc = m_outputs.m_Q_dot_LT = m_outputs.m_Q_dot_HT = std::numeric_limits::quiet_NaN(); @@ -708,16 +703,262 @@ int C_sco2_htrbp_core::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_L return 0; } -void C_sco2_htrbp_core::InitializeSolve() +// ********************************************************************************** END C_sco2_htrbp_core + + +// ********************************************************************************** ADDED Refactored opt methods + +/// +/// Optimize cycle, target maximum efficiency +/// ONLY USE ARGUMENTS FROM FUNCTION +/// +int C_HTRBypass_Cycle::opt_max_eta(S_auto_opt_design_parameters auto_par, S_opt_design_parameters opt_par) { - m_outputs.Init(); + // Set up baseline core inputs + S_sco2_htrbp_in core_inputs; + { + + // From Auto Opt Design Parameters + core_inputs.m_LTR_target_code = auto_par.m_LTR_target_code; + core_inputs.m_LTR_UA = auto_par.m_LTR_UA; + core_inputs.m_LTR_min_dT = auto_par.m_LTR_min_dT; + core_inputs.m_LTR_eff_target = auto_par.m_LTR_eff_target; + core_inputs.m_LTR_eff_max = auto_par.m_LTR_eff_max; + + core_inputs.m_LTR_od_UA_target_type = auto_par.m_LTR_od_UA_target_type; + core_inputs.m_HTR_target_code = auto_par.m_HTR_target_code; + core_inputs.m_HTR_UA = auto_par.m_HTR_UA; + core_inputs.m_HTR_min_dT = auto_par.m_HTR_min_dT; + core_inputs.m_HTR_eff_target = auto_par.m_HTR_eff_target; + core_inputs.m_HTR_eff_max = auto_par.m_HTR_eff_max; + core_inputs.m_HTR_od_UA_target_type = auto_par.m_HTR_od_UA_target_type; + core_inputs.m_des_tol = auto_par.m_des_tol; + core_inputs.m_is_des_air_cooler = auto_par.m_is_des_air_cooler; + + // From Constructor + core_inputs.m_LTR_N_sub_hxrs = m_LTR_N_sub_hxrs; // Comes from constructor (constant) + core_inputs.m_HTR_N_sub_hxrs = m_HTR_N_sub_hxrs; // Comes from constructor (constant) + core_inputs.m_W_dot_net_design = m_W_dot_net; // Comes from constructor (constant) + core_inputs.m_T_mc_in = m_T_mc_in; // Comes from constructor (constant) + core_inputs.m_T_t_in = m_T_t_in; // Comes from constructor (constant) + core_inputs.m_DP_LTR = m_DP_LTR; // Comes from constructor (constant) + core_inputs.m_DP_HTR = m_DP_HTR; // Comes from constructor (constant) + core_inputs.m_DP_PC_main = m_DP_PC_main; // Comes from constructor (constant) + core_inputs.m_DP_PHX = m_DP_PHX; // Comes from constructor (constant) + core_inputs.m_eta_mc = m_eta_mc; // Comes from constructor (constant) + core_inputs.m_eta_t = m_eta_t; // Comes from constructor (constant) + core_inputs.m_eta_rc = m_eta_rc; // Comes from constructor (constant) + core_inputs.m_eta_generator = m_eta_generator; // Comes from constructor (constant) + core_inputs.m_frac_fan_power = m_frac_fan_power; // Comes from constructor (constant) + core_inputs.m_eta_fan = m_eta_fan; // Comes from constructor (constant) + core_inputs.m_deltaP_cooler_frac = m_deltaP_cooler_frac; // Comes from constructor (constant) + core_inputs.m_T_amb_des = m_T_amb_des; // Comes from constructor (constant) + core_inputs.m_elevation = m_elevation; // Comes from constructor (constant) + core_inputs.m_N_nodes_pass = m_N_nodes_pass; // Comes from constructor (constant) + + // From special bypass fraction function (should remove) + core_inputs.m_dT_BP = m_dT_BP; // Comes from bp par function (constant) + core_inputs.m_set_HTF_mdot = m_set_HTF_mdot; // Comes from bp par function (constant) + core_inputs.m_cp_HTF = m_cp_HTF; // Comes from bp par function (constant) + core_inputs.m_T_HTF_PHX_inlet = m_T_HTF_PHX_inlet; // Comes from bp par function (constant) + core_inputs.m_HTF_PHX_cold_approach_input = m_HTF_PHX_cold_approach; // Comes from bp par function (constant) + + + // Handle design variables (check if fixed or free) + { + // Bypass Fraction + if (opt_par.m_fixed_bypass_frac == true) + core_inputs.m_bypass_frac = opt_par.m_bypass_frac_guess; + + // Recompression Fraction + if (opt_par.m_fixed_recomp_frac == true) + core_inputs.m_recomp_frac = opt_par.m_recomp_frac_guess; + + // MC Outlet Pressure + if (opt_par.m_fixed_P_mc_out == true) + core_inputs.m_P_mc_out = opt_par.m_P_mc_out_guess; + + // Recuperator split fraction + double LT_frac_local = opt_par.m_LT_frac_guess; + if (opt_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || opt_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + core_inputs.m_LTR_UA = opt_par.m_UA_rec_total * LT_frac_local; + core_inputs.m_HTR_UA = opt_par.m_UA_rec_total * (1.0 - LT_frac_local); + } + else + { + core_inputs.m_LTR_UA = opt_par.m_LTR_UA; //[kW/K] + core_inputs.m_HTR_UA = opt_par.m_HTR_UA; //[kW/K] + } + + + // Pressure Ratio is calculated in callback + } + + + //core_inputs.m_P_mc_in = ms_des_par.m_P_mc_in; + //core_inputs.m_P_mc_out = ms_des_par.m_P_mc_out; + //core_inputs.m_recomp_frac = ms_des_par.m_recomp_frac; + //core_inputs.m_bypass_frac = ms_opt_des_par.m_bypass_frac_guess; + + + + //opt_nonbp_par(auto_par, opt_par, core_inputs); + } + + + // Call Bypass Optimizer, which will internally call optimizer for other parameters + // THE ARGUMENTS WILL NOT BE MODIFIED + + + // Create optimizer for ONLY bypass (worry about others later) + nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); + + std::vector lb = { 0 }; + std::vector ub = { 0.99 }; + + opt_des_cycle.set_lower_bounds(lb); + opt_des_cycle.set_upper_bounds(ub); + opt_des_cycle.set_initial_step(0.1); + opt_des_cycle.set_xtol_rel(auto_par.m_des_opt_tol); + opt_des_cycle.set_maxeval(50); + + // Make Tuple to pass in parameters + std::tuple par_tuple = {this, auto_par, opt_par, core_inputs}; + + // Set max objective function + std::vector x; + x.push_back(0.1); + opt_des_cycle.set_max_objective(nlopt_opt_max_eta_func, &par_tuple); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' + double max_f = std::numeric_limits::quiet_NaN(); + + if (opt_par.m_fixed_bypass_frac == false) + { + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + } + else + { + opt_nonbp_par(auto_par, opt_par, core_inputs); + } + + + + + return 0; } +/// +/// Optimize variables OTHER THAN bypass fraction +/// Auto par are from python +/// opt par process the optimized variables from auto par +/// +/// +int C_HTRBypass_Cycle::opt_nonbp_par(S_auto_opt_design_parameters auto_par, S_opt_design_parameters opt_par, S_sco2_htrbp_in core_inputs) +{ + int index = 0; + + std::vector x(0); + std::vector lb(0); + std::vector ub(0); + std::vector scale(0); + if (!auto_par.m_fixed_P_mc_out) + { + x.push_back(opt_par.m_P_mc_out_guess); + lb.push_back(100.0); + ub.push_back(m_P_high_limit); + scale.push_back(500.0); + + index++; + } + if (!auto_par.m_fixed_PR_HP_to_LP) + { + x.push_back(auto_par.m_PR_HP_to_LP_guess); + lb.push_back(0.0001); + double PR_max = m_P_high_limit / 100.0; + ub.push_back(PR_max); + scale.push_back(0.2); + index++; + } + + if (!opt_par.m_fixed_recomp_frac) + { + x.push_back(opt_par.m_recomp_frac_guess); + lb.push_back(0.0); + ub.push_back(1.0); + scale.push_back(0.05); + index++; + } + + if (!opt_par.m_fixed_LT_frac) + { + x.push_back(opt_par.m_LT_frac_guess); + lb.push_back(0.0); + ub.push_back(1.0); + scale.push_back(0.05); + + index++; + } + + int error_code = 0; + if (index > 0) + { + // Set up instance of nlopt class and set optimization parameters + nlopt::opt opt_des_cycle(nlopt::LN_SBPLX, index); + opt_des_cycle.set_lower_bounds(lb); + opt_des_cycle.set_upper_bounds(ub); + opt_des_cycle.set_initial_step(scale); + opt_des_cycle.set_xtol_rel(auto_par.m_des_opt_tol); + opt_des_cycle.set_maxeval(50); + + // Make Tuple to pass in parameters + std::tuple par_tuple = { this, auto_par, opt_par, core_inputs }; + + // Set max objective function + opt_des_cycle.set_max_objective(nlopt_opt_nonbp_par_func, &par_tuple); + double max_f = std::numeric_limits::quiet_NaN(); + + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + + // Check if forced stop + int flag = opt_des_cycle.get_force_stop(); + } + else + { + // Finish defining ms_des_par based on current 'x' values + ms_des_par.m_P_mc_out = ms_opt_des_par.m_P_mc_out_guess; + ms_des_par.m_P_mc_in = ms_des_par.m_P_mc_out / ms_opt_des_par.m_PR_HP_to_LP_guess; + ms_des_par.m_recomp_frac = ms_opt_des_par.m_recomp_frac_guess; + + if (ms_opt_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + ms_des_par.m_LTR_UA = ms_opt_des_par.m_UA_rec_total * ms_opt_des_par.m_LT_frac_guess; + ms_des_par.m_HTR_UA = ms_opt_des_par.m_UA_rec_total * (1.0 - ms_opt_des_par.m_LT_frac_guess); + } + else + { + ms_des_par.m_LTR_UA = ms_opt_des_par.m_LTR_UA; //[kW/K] + ms_des_par.m_HTR_UA = ms_opt_des_par.m_HTR_UA; //[kW/K] + } + + // Ensure thermal efficiency is initialized to 0 + m_objective_metric_opt = 0.0; + double eta_local = design_cycle_return_objective_metric(x); + + if (eta_local == 0.0) + { + error_code = -1; + return error_code; + } + + ms_des_par_optimal = ms_des_par; + } + + return error_code; +} -// ********************************************************************************** END C_sco2_htrbp_core void C_HTRBypass_Cycle::design_core(int& error_code) { @@ -749,26 +990,29 @@ void C_HTRBypass_Cycle::design_core(int& error_code) core_inputs.m_is_des_air_cooler = ms_des_par.m_is_des_air_cooler; core_inputs.m_W_dot_net_design = m_W_dot_net; - core_inputs.m_T_mc_in = m_T_mc_in; - core_inputs.m_T_t_in = m_T_t_in; - core_inputs.m_DP_LTR = m_DP_LTR; - core_inputs.m_DP_HTR = m_DP_HTR; - core_inputs.m_DP_PC_main = m_DP_PC_main; - core_inputs.m_DP_PHX = m_DP_PHX; - core_inputs.m_eta_mc = m_eta_mc; - core_inputs.m_eta_t = m_eta_t; - core_inputs.m_eta_rc = m_eta_rc; - core_inputs.m_eta_generator = m_eta_generator; - core_inputs.m_frac_fan_power = m_frac_fan_power; - core_inputs.m_set_HTF_mdot = m_set_HTF_mdot; - core_inputs.m_cp_HTF = m_cp_HTF; - core_inputs.m_T_HTF_PHX_inlet = m_T_HTF_PHX_inlet; - core_inputs.m_eta_fan = m_eta_fan; - core_inputs.m_deltaP_cooler_frac = m_deltaP_cooler_frac; - core_inputs.m_T_amb_des = m_T_amb_des; - core_inputs.m_elevation = m_elevation; - core_inputs.m_N_nodes_pass = m_N_nodes_pass; - core_inputs.m_HTF_PHX_cold_approach_input = m_HTF_PHX_cold_approach; + core_inputs.m_T_mc_in = m_T_mc_in; // Comes from constructor (constant) + core_inputs.m_T_t_in = m_T_t_in; // Comes from constructor (constant) + core_inputs.m_DP_LTR = m_DP_LTR; // Comes from constructor (constant) + core_inputs.m_DP_HTR = m_DP_HTR; // Comes from constructor (constant) + core_inputs.m_DP_PC_main = m_DP_PC_main; // Comes from constructor (constant) + core_inputs.m_DP_PHX = m_DP_PHX; // Comes from constructor (constant) + core_inputs.m_eta_mc = m_eta_mc; // Comes from constructor (constant) + core_inputs.m_eta_t = m_eta_t; // Comes from constructor (constant) + core_inputs.m_eta_rc = m_eta_rc; // Comes from constructor (constant) + core_inputs.m_eta_generator = m_eta_generator; // Comes from constructor (constant) + core_inputs.m_frac_fan_power = m_frac_fan_power; // Comes from constructor (constant) + + core_inputs.m_set_HTF_mdot = m_set_HTF_mdot; // Comes from HTF par function (constant) + core_inputs.m_cp_HTF = m_cp_HTF; // Comes from HTF par function (constant) + core_inputs.m_T_HTF_PHX_inlet = m_T_HTF_PHX_inlet; // Comes from HTF par function (constant) + core_inputs.m_HTF_PHX_cold_approach_input = m_HTF_PHX_cold_approach; // Comes from constructor (constant) + + core_inputs.m_eta_fan = m_eta_fan; // Comes from constructor (constant) + core_inputs.m_deltaP_cooler_frac = m_deltaP_cooler_frac; // Comes from constructor (constant) + core_inputs.m_T_amb_des = m_T_amb_des; // Comes from constructor (constant) + core_inputs.m_elevation = m_elevation; // Comes from constructor (constant) + core_inputs.m_N_nodes_pass = m_N_nodes_pass; // Comes from constructor (constant) + C_sco2_htrbp_core sco2_core; sco2_core.SetInputs(core_inputs); @@ -1863,12 +2107,8 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) // Set max objective function opt_des_cycle.set_max_objective(nlopt_cb_opt_htr_bypass_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' double max_f = std::numeric_limits::quiet_NaN(); - - nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); - - // Check if forced stop int flag = opt_des_cycle.get_force_stop(); @@ -2020,6 +2260,18 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) ms_opt_des_par.m_fixed_recomp_frac = false; } + // Is bypass fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0.0) + { // fixed + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + ms_opt_des_par.m_fixed_bypass_frac = true; + } + else + { // optimized + ms_opt_des_par.m_bypass_frac_guess = 0.3; + ms_opt_des_par.m_fixed_bypass_frac = false; + } + ms_opt_des_par.m_LT_frac_guess = 0.5; ms_opt_des_par.m_fixed_LT_frac = false; @@ -2028,6 +2280,37 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) ms_opt_des_par.m_fixed_LT_frac = true; } + opt_max_eta(ms_auto_opt_des_par, ms_opt_des_par); + + + // This targets maximum efficiency. Bypass fraction is ALWAYS optimized outside other variables + if (ms_auto_opt_des_par.m_des_objective_type != 2) + { + + + // Bypass Fraction + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) + { + ms_opt_des_par.m_fixed_bypass_frac = true; + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + } + else + { + ms_opt_des_par.m_fixed_bypass_frac = false; + } + + int rc_error_code = 0; + + opt_design_core(rc_error_code); + + if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) + { + ms_des_par_auto_opt = ms_des_par_optimal; + m_objective_metric_auto_opt = m_objective_metric_opt; + } + } + + // Default case with Bypass either set or optimized WITHIN Optimization if (ms_auto_opt_des_par.m_des_objective_type != 2) { @@ -2579,6 +2862,269 @@ double C_HTRBypass_Cycle::design_bypass_frac_free_var_return_objective_metric(co return objective_metric; } + + + +double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector& x, + const S_auto_opt_design_parameters auto_par, + const S_opt_design_parameters opt_par, + S_sco2_htrbp_in core_inputs) +{ + if (opt_par.m_fixed_bypass_frac == true) + { + throw std::exception("Optimizing bypass fraction even though it is fixed"); + } + + // Set Bypass Fraction + core_inputs.m_bypass_frac = x[0]; + + // Optimize all other variables + opt_nonbp_par(auto_par, opt_par, core_inputs); + + + return 0; +} + +double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, + const S_auto_opt_design_parameters auto_par, + const S_opt_design_parameters opt_par, + S_sco2_htrbp_in core_inputs) +{ + // 'x' is array of inputs either being adjusted by optimizer or set constant + // Finish defining ms_des_par based on current 'x' values + + int index = 0; + + // Main compressor outlet pressure + + if (!auto_par.m_fixed_P_mc_out) + { + double P_mc_out = x[index]; + if (P_mc_out > m_P_high_limit) + return 0.0; + index++; + + // assign P_mc_out + core_inputs.m_P_mc_out = P_mc_out; + } + + + // Main compressor pressure ratio + double PR_mc_local = -999.9; + double P_mc_in = -999.9; + if (!opt_par.m_fixed_PR_HP_to_LP) + { + PR_mc_local = x[index]; + if (PR_mc_local > 50.0) + return -10000000000000.0; + index++; + P_mc_in = core_inputs.m_P_mc_out / PR_mc_local; + } + else + { + if (opt_par.m_PR_HP_to_LP_guess >= 0.0) + { + PR_mc_local = opt_par.m_PR_HP_to_LP_guess; + P_mc_in = core_inputs.m_P_mc_out / PR_mc_local; //[kPa] + } + else + { + P_mc_in = std::abs(opt_par.m_PR_HP_to_LP_guess); //[kPa] + } + } + + if (P_mc_in >= ms_des_par.m_P_mc_out) + return 0.0; + if (P_mc_in <= 100.0) + return 0.0; + + core_inputs.m_P_mc_in = P_mc_in; + + + // Recompression fraction + if (!opt_par.m_fixed_recomp_frac) + { + core_inputs.m_recomp_frac = x[index]; + if (core_inputs.m_recomp_frac < 0.0) + return 0.0; + index++; + } + + // Recuperator split fraction + double LT_frac_local = -999.9; + double LTR_UA, HTR_UA; + if (!opt_par.m_fixed_LT_frac) + { + LT_frac_local = x[index]; + if (LT_frac_local > 1.0 || LT_frac_local < 0.0) + return 0.0; + index++; + + if (auto_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || auto_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + LTR_UA = auto_par.m_UA_rec_total * LT_frac_local; + HTR_UA = auto_par.m_UA_rec_total * (1.0 - LT_frac_local); + + // ASSIGN LTR_UA and HTR_UA + core_inputs.m_LTR_UA = LTR_UA; + core_inputs.m_HTR_UA = HTR_UA; + } + } + + + + // AT this point, will have fully defined core input struct + // Run the core model + C_sco2_htrbp_core core_model; + core_model.SetInputs(core_inputs); + int error_code = core_model.Solve(); + + // Set Objective + double objective_metric = -10000000000.0; + if (error_code == 0) + { + double eff = core_model.m_outputs.m_eta_thermal; + + // If variable bypass fraction or targeting temperature + double penalty = 0; + if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) + { + double temp_calc = 0; + double span = 0; + + if (m_T_target_is_HTF == 0) + { + temp_calc = core_model.m_outputs.m_temp[MIXER_OUT]; + span = core_model.m_outputs.m_temp[TURB_IN] - m_T_target; + } + else + { + temp_calc = core_model.m_outputs.m_T_HTF_BP_outlet; + span = core_model.m_inputs.m_T_HTF_PHX_inlet - m_T_target; + } + + penalty = calc_penalty(m_T_target, temp_calc, span); + } + + objective_metric = eff - penalty; + + /*if (objective_metric > m_objective_metric_opt) + { + ms_des_par_optimal = ms_des_par; + m_objective_metric_opt = objective_metric; + }*/ + } + + return objective_metric; +} + + + +double nlopt_cb_opt_htr_bypass_des(const std::vector& x, std::vector& grad, void* data) +{ + C_HTRBypass_Cycle* frame = static_cast(data); + if (frame != NULL) + return frame->design_cycle_return_objective_metric(x); + else + return 0.0; +} + +double nlopt_cb_opt_bypass_frac_des(const std::vector& x, std::vector& grad, void* data) +{ + C_HTRBypass_Cycle* frame = static_cast(data); + if (frame != NULL) + return frame->design_bypass_frac_return_objective_metric(x); + else + return 0.0; +} + +double nlopt_cb_opt_bypass_frac_free_var(const std::vector& x, std::vector& grad, void* data) +{ + C_HTRBypass_Cycle* frame = static_cast(data); + if (frame != NULL) + return frame->design_bypass_frac_free_var_return_objective_metric(x); + else + return 0.0; +} + +double nlopt_opt_max_eta_func(const std::vector& x, std::vector& grad, void* data) +{ + // Unpack Data Tuple + std::tuple* data_tuple + = static_cast*>(data); + + C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); + C_HTRBypass_Cycle::S_auto_opt_design_parameters auto_opt_par = std::get<1>(*data_tuple); + C_HTRBypass_Cycle::S_opt_design_parameters opt_par = std::get<2>(*data_tuple); + S_sco2_htrbp_in core_inputs = std::get<3>(*data_tuple); + + if (frame != NULL) + return frame->opt_max_eta_return_objective_metric(x, auto_opt_par, opt_par, core_inputs); + else + return 0.0; +} + +double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector& grad, void* data) +{ + // Unpack Data Tuple + std::tuple* data_tuple + = static_cast*>(data); + + C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); + C_HTRBypass_Cycle::S_auto_opt_design_parameters auto_opt_par = std::get<1>(*data_tuple); + C_HTRBypass_Cycle::S_opt_design_parameters opt_par = std::get<2>(*data_tuple); + S_sco2_htrbp_in core_inputs = std::get<3>(*data_tuple); + + if (frame != NULL) + return frame->opt_nonbp_par_return_objective_metric(x, auto_opt_par, opt_par, core_inputs); + else + return 0.0; +} + +double sigmoid(const double val) +{ + return 1.0 / (1.0 + std::exp(-1.0 * val)); +} + +double logit(const double val) +{ + return std::log(val / (1.0 - val)); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2639,39 +3185,4 @@ void C_HTRBypass_Cycle::estimate_od_turbo_operation(double T_mc_in, double P_mc_ } -double nlopt_cb_opt_htr_bypass_des(const std::vector& x, std::vector& grad, void* data) -{ - C_HTRBypass_Cycle* frame = static_cast(data); - if (frame != NULL) - return frame->design_cycle_return_objective_metric(x); - else - return 0.0; -} -double nlopt_cb_opt_bypass_frac_des(const std::vector& x, std::vector& grad, void* data) -{ - C_HTRBypass_Cycle* frame = static_cast(data); - if (frame != NULL) - return frame->design_bypass_frac_return_objective_metric(x); - else - return 0.0; -} - -double nlopt_cb_opt_bypass_frac_free_var(const std::vector& x, std::vector& grad, void* data) -{ - C_HTRBypass_Cycle* frame = static_cast(data); - if (frame != NULL) - return frame->design_bypass_frac_free_var_return_objective_metric(x); - else - return 0.0; -} - -double sigmoid(const double val) -{ - return 1.0 / (1.0 + std::exp(-1.0 * val)); -} - -double logit(const double val) -{ - return std::log(val / (1.0 - val)); -} diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 1c3332d7cd..5dfd9deb23 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -201,8 +201,6 @@ struct S_sco2_htrbp_out } }; - - // This class is purely for solving the cycle // No optimization class C_sco2_htrbp_core @@ -262,6 +260,8 @@ class C_sco2_htrbp_core }; + + class C_HTRBypass_Cycle : public C_sco2_cycle_core { public: @@ -397,6 +397,12 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core private: + // NEW REFACTOR METHODS + int opt_max_eta(S_auto_opt_design_parameters auto_par, S_opt_design_parameters opt_par); + + int opt_nonbp_par(S_auto_opt_design_parameters auto_par, S_opt_design_parameters opt_par, S_sco2_htrbp_in core_inputs); + + // Component classes C_turbine m_t; C_comp_multi_stage m_mc_ms; @@ -566,6 +572,10 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double design_bypass_frac_free_var_return_objective_metric(const std::vector& x); + double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in core_inputs); + + double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in core_inputs); + class C_mono_htr_bypass_LTR_des : public C_monotonic_equation { private: @@ -668,6 +678,14 @@ double nlopt_cb_opt_bypass_frac_des(const std::vector& x, std::vector& x, std::vector& grad, void* data); +// ADDED +double nlopt_opt_max_eta_func(const std::vector& x, std::vector& grad, void* data); + +double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector& grad, void* data); + + + + double sigmoid(const double val); double logit(const double val); From fe5164ad3ac800e51e97e6479c317a9e55e0e381 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Thu, 7 Mar 2024 14:00:25 -0700 Subject: [PATCH 35/94] Add comments and reorganize to plan optimization return values. --- tcs/sco2_htrbypass_cycle.cpp | 1514 ++++++++++++++++++---------------- 1 file changed, 795 insertions(+), 719 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index da7a92b02a..80bb1e6f5d 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -806,39 +806,45 @@ int C_HTRBypass_Cycle::opt_max_eta(S_auto_opt_design_parameters auto_par, S_opt_ //opt_nonbp_par(auto_par, opt_par, core_inputs); } - - // Call Bypass Optimizer, which will internally call optimizer for other parameters - // THE ARGUMENTS WILL NOT BE MODIFIED - - // Create optimizer for ONLY bypass (worry about others later) - nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); + + // Bypass is Variable, optimize other variables WITHIN bp optimizer + if (opt_par.m_fixed_bypass_frac == false) + { + nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); - std::vector lb = { 0 }; - std::vector ub = { 0.99 }; + std::vector lb = { 0 }; + std::vector ub = { 0.99 }; - opt_des_cycle.set_lower_bounds(lb); - opt_des_cycle.set_upper_bounds(ub); - opt_des_cycle.set_initial_step(0.1); - opt_des_cycle.set_xtol_rel(auto_par.m_des_opt_tol); - opt_des_cycle.set_maxeval(50); + opt_des_cycle.set_lower_bounds(lb); + opt_des_cycle.set_upper_bounds(ub); + opt_des_cycle.set_initial_step(0.1); + opt_des_cycle.set_xtol_rel(auto_par.m_des_opt_tol); + opt_des_cycle.set_maxeval(50); - // Make Tuple to pass in parameters - std::tuple par_tuple = {this, auto_par, opt_par, core_inputs}; + // Make Tuple to pass in parameters + std::tuple par_tuple = { this, auto_par, opt_par, core_inputs }; - // Set max objective function - std::vector x; - x.push_back(0.1); - opt_des_cycle.set_max_objective(nlopt_opt_max_eta_func, &par_tuple); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' - double max_f = std::numeric_limits::quiet_NaN(); + // Set max objective function + std::vector x; + x.push_back(0.1); + opt_des_cycle.set_max_objective(nlopt_opt_max_eta_func, &par_tuple); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' + double max_f = std::numeric_limits::quiet_NaN(); - if (opt_par.m_fixed_bypass_frac == false) - { nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + + // This will return optimal bypass frac ^ BUT + // Need to get Optimal Case from internal ^ + + // Return an optimal input case } + + // Bypass is Fixed, optimize other variables else { opt_nonbp_par(auto_par, opt_par, core_inputs); + + // Return an optimal input case } @@ -855,6 +861,7 @@ int C_HTRBypass_Cycle::opt_max_eta(S_auto_opt_design_parameters auto_par, S_opt_ /// int C_HTRBypass_Cycle::opt_nonbp_par(S_auto_opt_design_parameters auto_par, S_opt_design_parameters opt_par, S_sco2_htrbp_in core_inputs) { + // Add Applicable Design Variables to Optimizer int index = 0; std::vector x(0); @@ -902,6 +909,7 @@ int C_HTRBypass_Cycle::opt_nonbp_par(S_auto_opt_design_parameters auto_par, S_op index++; } + // Make Optimizer (if there are variables to be optimized) int error_code = 0; if (index > 0) { @@ -917,190 +925,668 @@ int C_HTRBypass_Cycle::opt_nonbp_par(S_auto_opt_design_parameters auto_par, S_op std::tuple par_tuple = { this, auto_par, opt_par, core_inputs }; // Set max objective function + opt_des_cycle.set_max_objective(nlopt_opt_nonbp_par_func, &par_tuple); double max_f = std::numeric_limits::quiet_NaN(); - nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + + // This returns optimal values ^, need to convert to core_inputs // Check if forced stop int flag = opt_des_cycle.get_force_stop(); } else { - // Finish defining ms_des_par based on current 'x' values - ms_des_par.m_P_mc_out = ms_opt_des_par.m_P_mc_out_guess; - ms_des_par.m_P_mc_in = ms_des_par.m_P_mc_out / ms_opt_des_par.m_PR_HP_to_LP_guess; - ms_des_par.m_recomp_frac = ms_opt_des_par.m_recomp_frac_guess; + // Define P_mc_in (because the ratio and mc_out are constant) + core_inputs.m_P_mc_in = core_inputs.m_P_mc_out / opt_par.m_PR_HP_to_LP_guess; - if (ms_opt_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) - { - ms_des_par.m_LTR_UA = ms_opt_des_par.m_UA_rec_total * ms_opt_des_par.m_LT_frac_guess; - ms_des_par.m_HTR_UA = ms_opt_des_par.m_UA_rec_total * (1.0 - ms_opt_des_par.m_LT_frac_guess); - } - else - { - ms_des_par.m_LTR_UA = ms_opt_des_par.m_LTR_UA; //[kW/K] - ms_des_par.m_HTR_UA = ms_opt_des_par.m_HTR_UA; //[kW/K] - } + //if (ms_opt_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + //{ + // ms_des_par.m_LTR_UA = ms_opt_des_par.m_UA_rec_total * ms_opt_des_par.m_LT_frac_guess; + // ms_des_par.m_HTR_UA = ms_opt_des_par.m_UA_rec_total * (1.0 - ms_opt_des_par.m_LT_frac_guess); + //} + //else + //{ + // ms_des_par.m_LTR_UA = ms_opt_des_par.m_LTR_UA; //[kW/K] + // ms_des_par.m_HTR_UA = ms_opt_des_par.m_HTR_UA; //[kW/K] + //} // Ensure thermal efficiency is initialized to 0 - m_objective_metric_opt = 0.0; - double eta_local = design_cycle_return_objective_metric(x); + /*m_objective_metric_opt = 0.0; + double eta_local = design_cycle_return_objective_metric(x);*/ - if (eta_local == 0.0) + /*if (eta_local == 0.0) { error_code = -1; return error_code; - } + }*/ - ms_des_par_optimal = ms_des_par; + // Simulate Case + C_sco2_htrbp_core core_model; + core_model.SetInputs(core_inputs); + error_code = core_model.Solve(); } + // Assign a core_inputs + return error_code; } -void C_HTRBypass_Cycle::design_core(int& error_code) +/// +/// Objective Function for BYPASS optimization (calls internal optimization for other variables) +/// +/// +/// +/// +/// +/// +double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector& x, + const S_auto_opt_design_parameters auto_par, + const S_opt_design_parameters opt_par, + S_sco2_htrbp_in core_inputs) { - // DEBUG + if (opt_par.m_fixed_bypass_frac == true) { - S_sco2_htrbp_in core_inputs; - core_inputs.m_dT_BP = m_dT_BP; - core_inputs.m_P_mc_in = ms_des_par.m_P_mc_in; - core_inputs.m_P_mc_out = ms_des_par.m_P_mc_out; - core_inputs.m_LTR_target_code = ms_des_par.m_LTR_target_code; - core_inputs.m_LTR_UA = ms_des_par.m_LTR_UA; - core_inputs.m_LTR_min_dT = ms_des_par.m_LTR_min_dT; - core_inputs.m_LTR_eff_target = ms_des_par.m_LTR_eff_target; - core_inputs.m_LTR_eff_max = ms_des_par.m_LTR_eff_max; - core_inputs.m_LTR_N_sub_hxrs = m_LTR_N_sub_hxrs; - core_inputs.m_LTR_od_UA_target_type = ms_des_par.m_LTR_od_UA_target_type; + throw std::exception("Optimizing bypass fraction even though it is fixed"); + } - core_inputs.m_HTR_target_code = ms_des_par.m_HTR_target_code; - core_inputs.m_HTR_UA = ms_des_par.m_HTR_UA; - core_inputs.m_HTR_min_dT = ms_des_par.m_HTR_min_dT; - core_inputs.m_HTR_eff_target = ms_des_par.m_HTR_eff_target; - core_inputs.m_HTR_eff_max = ms_des_par.m_HTR_eff_max; - core_inputs.m_HTR_N_sub_hxrs = m_HTR_N_sub_hxrs; - core_inputs.m_HTR_od_UA_target_type = ms_des_par.m_HTR_od_UA_target_type; + // Set Bypass Fraction + core_inputs.m_bypass_frac = x[0]; - core_inputs.m_recomp_frac = ms_des_par.m_recomp_frac; - core_inputs.m_bypass_frac = ms_opt_des_par.m_bypass_frac_guess; - core_inputs.m_des_tol = ms_des_par.m_des_tol; - core_inputs.m_is_des_air_cooler = ms_des_par.m_is_des_air_cooler; + // Optimize all other variables + opt_nonbp_par(auto_par, opt_par, core_inputs); - core_inputs.m_W_dot_net_design = m_W_dot_net; - core_inputs.m_T_mc_in = m_T_mc_in; // Comes from constructor (constant) - core_inputs.m_T_t_in = m_T_t_in; // Comes from constructor (constant) - core_inputs.m_DP_LTR = m_DP_LTR; // Comes from constructor (constant) - core_inputs.m_DP_HTR = m_DP_HTR; // Comes from constructor (constant) - core_inputs.m_DP_PC_main = m_DP_PC_main; // Comes from constructor (constant) - core_inputs.m_DP_PHX = m_DP_PHX; // Comes from constructor (constant) - core_inputs.m_eta_mc = m_eta_mc; // Comes from constructor (constant) - core_inputs.m_eta_t = m_eta_t; // Comes from constructor (constant) - core_inputs.m_eta_rc = m_eta_rc; // Comes from constructor (constant) - core_inputs.m_eta_generator = m_eta_generator; // Comes from constructor (constant) - core_inputs.m_frac_fan_power = m_frac_fan_power; // Comes from constructor (constant) + // ^ Get optimal core_inputs from here (which will have a fixed bypass assigned from current function) - core_inputs.m_set_HTF_mdot = m_set_HTF_mdot; // Comes from HTF par function (constant) - core_inputs.m_cp_HTF = m_cp_HTF; // Comes from HTF par function (constant) - core_inputs.m_T_HTF_PHX_inlet = m_T_HTF_PHX_inlet; // Comes from HTF par function (constant) - core_inputs.m_HTF_PHX_cold_approach_input = m_HTF_PHX_cold_approach; // Comes from constructor (constant) + // Run Optimal Case, return objective function - core_inputs.m_eta_fan = m_eta_fan; // Comes from constructor (constant) - core_inputs.m_deltaP_cooler_frac = m_deltaP_cooler_frac; // Comes from constructor (constant) - core_inputs.m_T_amb_des = m_T_amb_des; // Comes from constructor (constant) - core_inputs.m_elevation = m_elevation; // Comes from constructor (constant) - core_inputs.m_N_nodes_pass = m_N_nodes_pass; // Comes from constructor (constant) + // Need to keep track of very best core_inputs case (don't have access to best obj value here though...) + return 0; +} - C_sco2_htrbp_core sco2_core; - sco2_core.SetInputs(core_inputs); - int err = sco2_core.Solve(); - int ta = 0; - } - - +/// +/// Objective Function for NON Bypass optimization +/// +/// +/// +/// +/// +/// +double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, + const S_auto_opt_design_parameters auto_par, + const S_opt_design_parameters opt_par, + S_sco2_htrbp_in core_inputs) +{ + // 'x' is array of inputs either being adjusted by optimizer or set constant + // Finish defining ms_des_par based on current 'x' values + int index = 0; - // Check if HTF parameters were set - if (is_bp_par_set == false) + // Main compressor outlet pressure + + if (!auto_par.m_fixed_P_mc_out) { - error_code = 560; - return; + double P_mc_out = x[index]; + if (P_mc_out > m_P_high_limit) + return 0.0; + index++; + + // assign P_mc_out + core_inputs.m_P_mc_out = P_mc_out; } - // Full Optization (not monotonic) - if (ms_opt_des_par.m_fixed_bypass_frac == true) + + // Main compressor pressure ratio + double PR_mc_local = -999.9; + double P_mc_in = -999.9; + if (!opt_par.m_fixed_PR_HP_to_LP) { - ms_des_par.m_bypass_frac = ms_opt_des_par.m_bypass_frac_guess; - design_core_standard(error_code); + PR_mc_local = x[index]; + if (PR_mc_local > 50.0) + return -10000000000000.0; + index++; + P_mc_in = core_inputs.m_P_mc_out / PR_mc_local; } else { - m_objective_metric_bypass_frac_opt = -10000000; - - // Set up instance of nlopt class and set optimization parameters - nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); + if (opt_par.m_PR_HP_to_LP_guess >= 0.0) + { + PR_mc_local = opt_par.m_PR_HP_to_LP_guess; + P_mc_in = core_inputs.m_P_mc_out / PR_mc_local; //[kPa] + } + else + { + P_mc_in = std::abs(opt_par.m_PR_HP_to_LP_guess); //[kPa] + } + } - std::vector lb = { 0 }; - std::vector ub = { 0.99 }; + if (P_mc_in >= ms_des_par.m_P_mc_out) + return 0.0; + if (P_mc_in <= 100.0) + return 0.0; - opt_des_cycle.set_lower_bounds(lb); - opt_des_cycle.set_upper_bounds(ub); - opt_des_cycle.set_initial_step(0.01); - opt_des_cycle.set_xtol_rel(0.1); - //opt_des_cycle.set_maxeval(50); + core_inputs.m_P_mc_in = P_mc_in; - // Set max objective function - std::vector x; - x.push_back(0.1); - opt_des_cycle.set_max_objective(nlopt_cb_opt_bypass_frac_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' - double max_f = std::numeric_limits::quiet_NaN(); - - nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); - + // Recompression fraction + if (!opt_par.m_fixed_recomp_frac) + { + core_inputs.m_recomp_frac = x[index]; + if (core_inputs.m_recomp_frac < 0.0) + return 0.0; + index++; + } - ms_des_par.m_bypass_frac = x[0]; - design_core_standard(error_code); + // Recuperator split fraction + double LT_frac_local = -999.9; + double LTR_UA, HTR_UA; + if (!opt_par.m_fixed_LT_frac) + { + LT_frac_local = x[index]; + if (LT_frac_local > 1.0 || LT_frac_local < 0.0) + return 0.0; + index++; - std::string s = make_result_csv_string(); + if (auto_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || auto_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + LTR_UA = auto_par.m_UA_rec_total * LT_frac_local; + HTR_UA = auto_par.m_UA_rec_total * (1.0 - LT_frac_local); - int yx = 0; + // ASSIGN LTR_UA and HTR_UA + core_inputs.m_LTR_UA = LTR_UA; + core_inputs.m_HTR_UA = HTR_UA; + } } -} -void C_HTRBypass_Cycle::design_core_standard(int& error_code) -{ - // Apply scaling to the turbomachinery here - { - m_mc_ms.m_r_W_dot_scale = m_W_dot_net / 10.E3; //[-] - m_rc_ms.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] - m_t.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] - } - CO2_state co2_props; + // AT this point, will have fully defined core input struct + // Run the core model + C_sco2_htrbp_core core_model; + core_model.SetInputs(core_inputs); + int error_code = core_model.Solve(); - // DEBUG - if(false) - { - { - double Q = 15.364; // MW - double mdot = 140.17; // kg/s - double pres = 18.134; //MPa - double T2 = 346.69; // C + // Set Objective + double objective_metric = -10000000000.0; + if (error_code == 0) + { + double eff = core_model.m_outputs.m_eta_thermal; - // Get h2 - CO2_TP(T2 + 273.15, pres * 1e3, &co2_props); - double h2 = co2_props.enth; + // If variable bypass fraction or targeting temperature + double penalty = 0; + if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) + { + double temp_calc = 0; + double span = 0; - // Calculate h1 - double h1 = h2 - (Q * 1e3) / mdot; + if (m_T_target_is_HTF == 0) + { + temp_calc = core_model.m_outputs.m_temp[MIXER_OUT]; + span = core_model.m_outputs.m_temp[TURB_IN] - m_T_target; + } + else + { + temp_calc = core_model.m_outputs.m_T_HTF_BP_outlet; + span = core_model.m_inputs.m_T_HTF_PHX_inlet - m_T_target; + } + + penalty = calc_penalty(m_T_target, temp_calc, span); + } + + objective_metric = eff - penalty; + + /*if (objective_metric > m_objective_metric_opt) + { + ms_des_par_optimal = ms_des_par; + m_objective_metric_opt = objective_metric; + }*/ + } + + return objective_metric; +} + + +double nlopt_opt_max_eta_func(const std::vector& x, std::vector& grad, void* data) +{ + // Unpack Data Tuple + std::tuple* data_tuple + = static_cast*>(data); + + C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); + C_HTRBypass_Cycle::S_auto_opt_design_parameters auto_opt_par = std::get<1>(*data_tuple); + C_HTRBypass_Cycle::S_opt_design_parameters opt_par = std::get<2>(*data_tuple); + S_sco2_htrbp_in core_inputs = std::get<3>(*data_tuple); + + if (frame != NULL) + return frame->opt_max_eta_return_objective_metric(x, auto_opt_par, opt_par, core_inputs); + else + return 0.0; +} + +double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector& grad, void* data) +{ + // Unpack Data Tuple + std::tuple* data_tuple + = static_cast*>(data); + + C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); + C_HTRBypass_Cycle::S_auto_opt_design_parameters auto_opt_par = std::get<1>(*data_tuple); + C_HTRBypass_Cycle::S_opt_design_parameters opt_par = std::get<2>(*data_tuple); + S_sco2_htrbp_in core_inputs = std::get<3>(*data_tuple); + + if (frame != NULL) + return frame->opt_nonbp_par_return_objective_metric(x, auto_opt_par, opt_par, core_inputs); + else + return 0.0; +} + + +// ********************************************************************************* END added Refactored opt methods + +// Legacy functions that are used + +void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) +{ + // Check that simple/recomp flag is set + if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && + ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) + { + throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" + " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); + } + + // map 'auto_opt_des_par_in' to 'ms_auto_opt_des_par' + + + + + // LTR thermal design + ms_opt_des_par.m_LTR_target_code = ms_auto_opt_des_par.m_LTR_target_code; //[-] + ms_opt_des_par.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; //[kW/K] + ms_opt_des_par.m_LTR_min_dT = ms_auto_opt_des_par.m_LTR_min_dT; //[K] + ms_opt_des_par.m_LTR_eff_target = ms_auto_opt_des_par.m_LTR_eff_target; //[-] + ms_opt_des_par.m_LTR_eff_max = ms_auto_opt_des_par.m_LTR_eff_max; //[-] + ms_opt_des_par.m_LTR_od_UA_target_type = ms_auto_opt_des_par.m_LTR_od_UA_target_type; + // HTR thermal design + ms_opt_des_par.m_HTR_target_code = ms_auto_opt_des_par.m_HTR_target_code; //[-] + ms_opt_des_par.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; //[kW/K] + ms_opt_des_par.m_HTR_min_dT = ms_auto_opt_des_par.m_HTR_min_dT; //[K] + ms_opt_des_par.m_HTR_eff_target = ms_auto_opt_des_par.m_HTR_eff_target; //[-] + ms_opt_des_par.m_HTR_eff_max = ms_auto_opt_des_par.m_HTR_eff_max; + ms_opt_des_par.m_HTR_od_UA_target_type = ms_auto_opt_des_par.m_HTR_od_UA_target_type; + // + ms_opt_des_par.m_UA_rec_total = ms_auto_opt_des_par.m_UA_rec_total; + ms_opt_des_par.m_des_tol = ms_auto_opt_des_par.m_des_tol; + ms_opt_des_par.m_des_opt_tol = ms_auto_opt_des_par.m_des_opt_tol; + + ms_opt_des_par.m_is_des_air_cooler = ms_auto_opt_des_par.m_is_des_air_cooler; //[-] + + ms_opt_des_par.m_des_objective_type = ms_auto_opt_des_par.m_des_objective_type; //[-] + ms_opt_des_par.m_min_phx_deltaT = ms_auto_opt_des_par.m_min_phx_deltaT; //[C] + + ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] + + ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] + + // Outer optimization loop + m_objective_metric_auto_opt = 0.0; + + double best_P_high = m_P_high_limit; //[kPa] + double PR_mc_guess = 2.5; //[-] + if (!ms_opt_des_par.m_fixed_P_mc_out) + { + double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] + + //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); + best_P_high = m_P_high_limit; // TEMPORARY + + // If this runs, it should set: + // ms_des_par_auto_opt + // m_objective_metric_auto_opt + // So we can update pressure ratio guess + double PR_mc_guess_calc = ms_des_par_auto_opt.m_P_mc_out / ms_des_par_auto_opt.m_P_mc_in; + + if (std::isfinite(PR_mc_guess_calc)) { + PR_mc_guess = PR_mc_guess_calc; + } + else { + best_P_high = m_P_high_limit; //[kPa] + } + } + + // Complete 'ms_opt_des_par' for recompression cycle + ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] + ms_opt_des_par.m_fixed_P_mc_out = true; + + if (ms_opt_des_par.m_fixed_PR_HP_to_LP) + { + ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + } + else + { + ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] + } + + // Is recompression fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) + { // fixed + ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); + ms_opt_des_par.m_fixed_recomp_frac = true; + } + else + { // optimized + ms_opt_des_par.m_recomp_frac_guess = 0.3; + ms_opt_des_par.m_fixed_recomp_frac = false; + } + + // Is bypass fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0.0) + { // fixed + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + ms_opt_des_par.m_fixed_bypass_frac = true; + } + else + { // optimized + ms_opt_des_par.m_bypass_frac_guess = 0.3; + ms_opt_des_par.m_fixed_bypass_frac = false; + } + + ms_opt_des_par.m_LT_frac_guess = 0.5; + ms_opt_des_par.m_fixed_LT_frac = false; + + if (ms_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + ms_opt_des_par.m_fixed_LT_frac = true; + } + + opt_max_eta(ms_auto_opt_des_par, ms_opt_des_par); + + + // This targets maximum efficiency. Bypass fraction is ALWAYS optimized outside other variables + if (ms_auto_opt_des_par.m_des_objective_type != 2) + { + + + // Bypass Fraction + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) + { + ms_opt_des_par.m_fixed_bypass_frac = true; + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + } + else + { + ms_opt_des_par.m_fixed_bypass_frac = false; + } + + int rc_error_code = 0; + + opt_design_core(rc_error_code); + + if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) + { + ms_des_par_auto_opt = ms_des_par_optimal; + m_objective_metric_auto_opt = m_objective_metric_opt; + } + } + + + // Default case with Bypass either set or optimized WITHIN Optimization + if (ms_auto_opt_des_par.m_des_objective_type != 2) + { + // Bypass Fraction + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) + { + ms_opt_des_par.m_fixed_bypass_frac = true; + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + } + else + { + ms_opt_des_par.m_fixed_bypass_frac = false; + } + + int rc_error_code = 0; + + opt_design_core(rc_error_code); + + if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) + { + ms_des_par_auto_opt = ms_des_par_optimal; + m_objective_metric_auto_opt = m_objective_metric_opt; + } + } + + // Add option for des_objective_type == 2 (optimize bypass fraction OUTSIDE other optimization (rather than INSIDE) + else // (m_des_objective_type == 2) + { + // Bypass Fraction + ms_opt_des_par.m_fixed_bypass_frac = true; + + // Ensure thermal efficiency is initialized to negative value + m_objective_metric_full_auto_opt = -100000000000; + + // Hard coded Bypass Fraction, but other variables optimize to hit the correct temperature + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) + { + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + + int rc_error_code = 0; + + opt_design_core(rc_error_code); + + + ms_des_par_auto_opt = ms_des_par_optimal; + m_objective_metric_auto_opt = m_objective_metric_opt; + + } + + // Optimize Bypass Fraction outside other variables + else + { + + m_objective_metric_bypass_frac_opt = -10000000; + + // Set up instance of nlopt class and set optimization parameters + nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); + + std::vector lb = { 0 }; + std::vector ub = { 0.99 }; + + opt_des_cycle.set_lower_bounds(lb); + opt_des_cycle.set_upper_bounds(ub); + opt_des_cycle.set_initial_step(0.1); + opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); + opt_des_cycle.set_maxeval(50); + + // Set max objective function + std::vector x; + x.push_back(0.1); + opt_des_cycle.set_max_objective(nlopt_cb_opt_bypass_frac_free_var, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' + double max_f = std::numeric_limits::quiet_NaN(); + + + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + + + ms_des_par = ms_des_par_full_auto_opt; + ms_des_par_auto_opt = ms_des_par_full_auto_opt; + design_core_standard(error_code); + + ms_opt_des_par.m_bypass_frac_guess = ms_des_par_auto_opt.m_bypass_frac; + //std::string s = make_result_csv_string(); + } + } + + ms_des_par = ms_des_par_auto_opt; + + int optimal_design_error_code = 0; + design_core(optimal_design_error_code); + + if (optimal_design_error_code != 0) + { + error_code = optimal_design_error_code; + return; + } + + finalize_design(optimal_design_error_code); + + error_code = optimal_design_error_code; +} + +// END legacy functions + + + + + + + +void C_HTRBypass_Cycle::design_core(int& error_code) +{ + // DEBUG + { + S_sco2_htrbp_in core_inputs; + core_inputs.m_dT_BP = m_dT_BP; + core_inputs.m_P_mc_in = ms_des_par.m_P_mc_in; + core_inputs.m_P_mc_out = ms_des_par.m_P_mc_out; + core_inputs.m_LTR_target_code = ms_des_par.m_LTR_target_code; + core_inputs.m_LTR_UA = ms_des_par.m_LTR_UA; + core_inputs.m_LTR_min_dT = ms_des_par.m_LTR_min_dT; + core_inputs.m_LTR_eff_target = ms_des_par.m_LTR_eff_target; + core_inputs.m_LTR_eff_max = ms_des_par.m_LTR_eff_max; + core_inputs.m_LTR_N_sub_hxrs = m_LTR_N_sub_hxrs; + core_inputs.m_LTR_od_UA_target_type = ms_des_par.m_LTR_od_UA_target_type; + + core_inputs.m_HTR_target_code = ms_des_par.m_HTR_target_code; + core_inputs.m_HTR_UA = ms_des_par.m_HTR_UA; + core_inputs.m_HTR_min_dT = ms_des_par.m_HTR_min_dT; + core_inputs.m_HTR_eff_target = ms_des_par.m_HTR_eff_target; + core_inputs.m_HTR_eff_max = ms_des_par.m_HTR_eff_max; + core_inputs.m_HTR_N_sub_hxrs = m_HTR_N_sub_hxrs; + core_inputs.m_HTR_od_UA_target_type = ms_des_par.m_HTR_od_UA_target_type; + + core_inputs.m_recomp_frac = ms_des_par.m_recomp_frac; + core_inputs.m_bypass_frac = ms_opt_des_par.m_bypass_frac_guess; + core_inputs.m_des_tol = ms_des_par.m_des_tol; + core_inputs.m_is_des_air_cooler = ms_des_par.m_is_des_air_cooler; + + core_inputs.m_W_dot_net_design = m_W_dot_net; + core_inputs.m_T_mc_in = m_T_mc_in; // Comes from constructor (constant) + core_inputs.m_T_t_in = m_T_t_in; // Comes from constructor (constant) + core_inputs.m_DP_LTR = m_DP_LTR; // Comes from constructor (constant) + core_inputs.m_DP_HTR = m_DP_HTR; // Comes from constructor (constant) + core_inputs.m_DP_PC_main = m_DP_PC_main; // Comes from constructor (constant) + core_inputs.m_DP_PHX = m_DP_PHX; // Comes from constructor (constant) + core_inputs.m_eta_mc = m_eta_mc; // Comes from constructor (constant) + core_inputs.m_eta_t = m_eta_t; // Comes from constructor (constant) + core_inputs.m_eta_rc = m_eta_rc; // Comes from constructor (constant) + core_inputs.m_eta_generator = m_eta_generator; // Comes from constructor (constant) + core_inputs.m_frac_fan_power = m_frac_fan_power; // Comes from constructor (constant) + + core_inputs.m_set_HTF_mdot = m_set_HTF_mdot; // Comes from HTF par function (constant) + core_inputs.m_cp_HTF = m_cp_HTF; // Comes from HTF par function (constant) + core_inputs.m_T_HTF_PHX_inlet = m_T_HTF_PHX_inlet; // Comes from HTF par function (constant) + core_inputs.m_HTF_PHX_cold_approach_input = m_HTF_PHX_cold_approach; // Comes from constructor (constant) + + core_inputs.m_eta_fan = m_eta_fan; // Comes from constructor (constant) + core_inputs.m_deltaP_cooler_frac = m_deltaP_cooler_frac; // Comes from constructor (constant) + core_inputs.m_T_amb_des = m_T_amb_des; // Comes from constructor (constant) + core_inputs.m_elevation = m_elevation; // Comes from constructor (constant) + core_inputs.m_N_nodes_pass = m_N_nodes_pass; // Comes from constructor (constant) + + + C_sco2_htrbp_core sco2_core; + sco2_core.SetInputs(core_inputs); + int err = sco2_core.Solve(); + int ta = 0; + } + + + + + + // Check if HTF parameters were set + if (is_bp_par_set == false) + { + error_code = 560; + return; + } + + // Full Optization (not monotonic) + if (ms_opt_des_par.m_fixed_bypass_frac == true) + { + ms_des_par.m_bypass_frac = ms_opt_des_par.m_bypass_frac_guess; + design_core_standard(error_code); + } + else + { + m_objective_metric_bypass_frac_opt = -10000000; + + // Set up instance of nlopt class and set optimization parameters + nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); + + std::vector lb = { 0 }; + std::vector ub = { 0.99 }; + + opt_des_cycle.set_lower_bounds(lb); + opt_des_cycle.set_upper_bounds(ub); + opt_des_cycle.set_initial_step(0.01); + opt_des_cycle.set_xtol_rel(0.1); + //opt_des_cycle.set_maxeval(50); + + // Set max objective function + std::vector x; + x.push_back(0.1); + opt_des_cycle.set_max_objective(nlopt_cb_opt_bypass_frac_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' + double max_f = std::numeric_limits::quiet_NaN(); + + + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + + + ms_des_par.m_bypass_frac = x[0]; + design_core_standard(error_code); + + std::string s = make_result_csv_string(); + + int yx = 0; + } + +} + +void C_HTRBypass_Cycle::design_core_standard(int& error_code) +{ + // Apply scaling to the turbomachinery here + { + m_mc_ms.m_r_W_dot_scale = m_W_dot_net / 10.E3; //[-] + m_rc_ms.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] + m_t.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] + } + + CO2_state co2_props; + + + // DEBUG + if(false) + { + { + double Q = 15.364; // MW + double mdot = 140.17; // kg/s + double pres = 18.134; //MPa + + double T2 = 346.69; // C + + // Get h2 + CO2_TP(T2 + 273.15, pres * 1e3, &co2_props); + double h2 = co2_props.enth; + + // Calculate h1 + double h1 = h2 - (Q * 1e3) / mdot; // Get T1 CO2_PH(pres * 1e3, h1, &co2_props); @@ -1945,474 +2431,228 @@ std::string C_HTRBypass_Cycle::make_result_csv_string() } - // Write Temperatures - value_string.append("\n"); - for (double val : this->m_temp_last) - { - value_string.append(std::to_string(val)); - value_string.append("\n"); - } - - // Write Pressures - value_string.append("\n"); - for (double val : this->m_pres_last) - { - value_string.append(std::to_string(val)); - value_string.append("\n"); - } - - - - - - - - return value_string; -} - - - -int C_HTRBypass_Cycle::C_mono_htr_bypass_LTR_des::operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out) -{ - return m_htr_bypass_cycle->solve_LTR(T_LTR_LP_OUT_guess, diff_T_LTR_LP_out); -} - - -int C_HTRBypass_Cycle::C_mono_htr_bypass_HTR_des::operator()(double T_HTR_LP_OUT_guess /*K*/, double* diff_T_HTR_LP_out) -{ - return m_htr_bypass_cycle->solve_HTR(T_HTR_LP_OUT_guess, diff_T_HTR_LP_out); -} - - -int C_HTRBypass_Cycle::C_mono_htr_bypass_BP_des::operator()(double bp_frac_guess, double* diff_T_BP_HTF_out) -{ - int error_code = 0; - - this->m_htr_bypass_cycle->ms_des_par.m_bypass_frac = bp_frac_guess; - this->m_htr_bypass_cycle->design_core_standard(error_code); - - if (this->m_htr_bypass_cycle->m_T_target_is_HTF == 0) - { - double target_out = this->m_htr_bypass_cycle->m_T_target; - double calc_sco2_out = this->m_htr_bypass_cycle->m_temp_last[MIXER_OUT]; - *diff_T_BP_HTF_out = calc_sco2_out - target_out; - } - else - { - double target_bp_out = this->m_htr_bypass_cycle->m_T_target; - double calc_bp_out = this->m_htr_bypass_cycle->m_T_HTF_BP_outlet_calc; - *diff_T_BP_HTF_out = calc_bp_out - target_bp_out; - } - - - - - - return error_code; -} - - - -void C_HTRBypass_Cycle::opt_design_core(int& error_code) -{ - // Map ms_opt_des_par to ms_des_par - // LTR thermal design - ms_des_par.m_LTR_target_code = ms_opt_des_par.m_LTR_target_code; //[-] - ms_des_par.m_LTR_min_dT = ms_opt_des_par.m_LTR_min_dT; //[K] - ms_des_par.m_LTR_eff_target = ms_opt_des_par.m_LTR_eff_target; //[-] - ms_des_par.m_LTR_eff_max = ms_opt_des_par.m_LTR_eff_max; //[-] - ms_des_par.m_LTR_od_UA_target_type = ms_opt_des_par.m_LTR_od_UA_target_type; - // HTR thermal design - ms_des_par.m_HTR_target_code = ms_opt_des_par.m_HTR_target_code; //[-] - ms_des_par.m_HTR_min_dT = ms_opt_des_par.m_HTR_min_dT; //[K] - ms_des_par.m_HTR_eff_target = ms_opt_des_par.m_HTR_eff_target; //[-] - ms_des_par.m_HTR_eff_max = ms_opt_des_par.m_HTR_eff_max; //[-] - ms_des_par.m_HTR_od_UA_target_type = ms_opt_des_par.m_HTR_od_UA_target_type; - // - ms_des_par.m_des_tol = ms_opt_des_par.m_des_tol; - - ms_des_par.m_is_des_air_cooler = ms_opt_des_par.m_is_des_air_cooler; //[-] - - ms_des_par.m_des_objective_type = ms_opt_des_par.m_des_objective_type; //[-] - ms_des_par.m_min_phx_deltaT = ms_opt_des_par.m_min_phx_deltaT; //[C] - - // ms_des_par members to be defined by optimizer and set in 'design_point_eta': - // m_P_mc_in - // m_P_mc_out - // m_recomp_frac - // m_UA_LT - // m_UA_HT - - int index = 0; - - std::vector x(0); - std::vector lb(0); - std::vector ub(0); - std::vector scale(0); - - if (!ms_opt_des_par.m_fixed_P_mc_out) - { - x.push_back(ms_opt_des_par.m_P_mc_out_guess); - lb.push_back(100.0); - ub.push_back(m_P_high_limit); - scale.push_back(500.0); - - index++; - } - - if (!ms_opt_des_par.m_fixed_PR_HP_to_LP) - { - x.push_back(ms_opt_des_par.m_PR_HP_to_LP_guess); - lb.push_back(0.0001); - double PR_max = m_P_high_limit / 100.0; - ub.push_back(PR_max); - scale.push_back(0.2); - - index++; - } - - if (!ms_opt_des_par.m_fixed_recomp_frac) - { - x.push_back(ms_opt_des_par.m_recomp_frac_guess); - lb.push_back(0.0); - ub.push_back(1.0); - scale.push_back(0.05); - index++; - } - - if (!ms_opt_des_par.m_fixed_LT_frac) - { - x.push_back(ms_opt_des_par.m_LT_frac_guess); - lb.push_back(0.0); - ub.push_back(1.0); - scale.push_back(0.05); - - index++; - } - - error_code = 0; - if (index > 0) - { - // Ensure thermal efficiency is initialized to negative value - m_objective_metric_opt = -100000000000; - - // Set up instance of nlopt class and set optimization parameters - nlopt::opt opt_des_cycle(nlopt::LN_SBPLX, index); - opt_des_cycle.set_lower_bounds(lb); - opt_des_cycle.set_upper_bounds(ub); - opt_des_cycle.set_initial_step(scale); - opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); - opt_des_cycle.set_maxeval(50); - - // Set max objective function - opt_des_cycle.set_max_objective(nlopt_cb_opt_htr_bypass_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' - double max_f = std::numeric_limits::quiet_NaN(); - - nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); - - // Check if forced stop - int flag = opt_des_cycle.get_force_stop(); - - ms_des_par = ms_des_par_optimal; - - design_core(error_code); - - int io = 0; - design_core_standard(io); - - std::string val_string = make_result_csv_string(); - - int otu = 0; - - /* - m_W_dot_net_last = m_W_dot_net_opt; - m_eta_thermal_last = m_eta_thermal_opt; - m_temp_last = m_temp_opt; - m_pres_last = m_pres_opt; - m_enth_last = m_enth_opt; - m_entr_last = m_entr_opt; - m_dens_last = m_dens_opt; - */ - } - else - { - // Finish defining ms_des_par based on current 'x' values - ms_des_par.m_P_mc_out = ms_opt_des_par.m_P_mc_out_guess; - ms_des_par.m_P_mc_in = ms_des_par.m_P_mc_out / ms_opt_des_par.m_PR_HP_to_LP_guess; - ms_des_par.m_recomp_frac = ms_opt_des_par.m_recomp_frac_guess; - - if (ms_opt_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) - { - ms_des_par.m_LTR_UA = ms_opt_des_par.m_UA_rec_total * ms_opt_des_par.m_LT_frac_guess; - ms_des_par.m_HTR_UA = ms_opt_des_par.m_UA_rec_total * (1.0 - ms_opt_des_par.m_LT_frac_guess); - } - else - { - ms_des_par.m_LTR_UA = ms_opt_des_par.m_LTR_UA; //[kW/K] - ms_des_par.m_HTR_UA = ms_opt_des_par.m_HTR_UA; //[kW/K] - } - - // Ensure thermal efficiency is initialized to 0 - m_objective_metric_opt = 0.0; - double eta_local = design_cycle_return_objective_metric(x); - - if (eta_local == 0.0) - { - error_code = -1; - return; - } - - ms_des_par_optimal = ms_des_par; + // Write Temperatures + value_string.append("\n"); + for (double val : this->m_temp_last) + { + value_string.append(std::to_string(val)); + value_string.append("\n"); } -} -void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) -{ - // Check that simple/recomp flag is set - if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && - ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) + // Write Pressures + value_string.append("\n"); + for (double val : this->m_pres_last) { - throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" - " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); + value_string.append(std::to_string(val)); + value_string.append("\n"); } - // map 'auto_opt_des_par_in' to 'ms_auto_opt_des_par' + - - // LTR thermal design - ms_opt_des_par.m_LTR_target_code = ms_auto_opt_des_par.m_LTR_target_code; //[-] - ms_opt_des_par.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; //[kW/K] - ms_opt_des_par.m_LTR_min_dT = ms_auto_opt_des_par.m_LTR_min_dT; //[K] - ms_opt_des_par.m_LTR_eff_target = ms_auto_opt_des_par.m_LTR_eff_target; //[-] - ms_opt_des_par.m_LTR_eff_max = ms_auto_opt_des_par.m_LTR_eff_max; //[-] - ms_opt_des_par.m_LTR_od_UA_target_type = ms_auto_opt_des_par.m_LTR_od_UA_target_type; - // HTR thermal design - ms_opt_des_par.m_HTR_target_code = ms_auto_opt_des_par.m_HTR_target_code; //[-] - ms_opt_des_par.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; //[kW/K] - ms_opt_des_par.m_HTR_min_dT = ms_auto_opt_des_par.m_HTR_min_dT; //[K] - ms_opt_des_par.m_HTR_eff_target = ms_auto_opt_des_par.m_HTR_eff_target; //[-] - ms_opt_des_par.m_HTR_eff_max = ms_auto_opt_des_par.m_HTR_eff_max; - ms_opt_des_par.m_HTR_od_UA_target_type = ms_auto_opt_des_par.m_HTR_od_UA_target_type; - // - ms_opt_des_par.m_UA_rec_total = ms_auto_opt_des_par.m_UA_rec_total; - ms_opt_des_par.m_des_tol = ms_auto_opt_des_par.m_des_tol; - ms_opt_des_par.m_des_opt_tol = ms_auto_opt_des_par.m_des_opt_tol; - ms_opt_des_par.m_is_des_air_cooler = ms_auto_opt_des_par.m_is_des_air_cooler; //[-] - ms_opt_des_par.m_des_objective_type = ms_auto_opt_des_par.m_des_objective_type; //[-] - ms_opt_des_par.m_min_phx_deltaT = ms_auto_opt_des_par.m_min_phx_deltaT; //[C] + return value_string; +} - ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] - ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] - // Outer optimization loop - m_objective_metric_auto_opt = 0.0; +int C_HTRBypass_Cycle::C_mono_htr_bypass_LTR_des::operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out) +{ + return m_htr_bypass_cycle->solve_LTR(T_LTR_LP_OUT_guess, diff_T_LTR_LP_out); +} - double best_P_high = m_P_high_limit; //[kPa] - double PR_mc_guess = 2.5; //[-] - if (!ms_opt_des_par.m_fixed_P_mc_out) - { - double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] - //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); - best_P_high = m_P_high_limit; // TEMPORARY +int C_HTRBypass_Cycle::C_mono_htr_bypass_HTR_des::operator()(double T_HTR_LP_OUT_guess /*K*/, double* diff_T_HTR_LP_out) +{ + return m_htr_bypass_cycle->solve_HTR(T_HTR_LP_OUT_guess, diff_T_HTR_LP_out); +} - // If this runs, it should set: - // ms_des_par_auto_opt - // m_objective_metric_auto_opt - // So we can update pressure ratio guess - double PR_mc_guess_calc = ms_des_par_auto_opt.m_P_mc_out / ms_des_par_auto_opt.m_P_mc_in; - if (std::isfinite(PR_mc_guess_calc)) { - PR_mc_guess = PR_mc_guess_calc; - } - else { - best_P_high = m_P_high_limit; //[kPa] - } - } +int C_HTRBypass_Cycle::C_mono_htr_bypass_BP_des::operator()(double bp_frac_guess, double* diff_T_BP_HTF_out) +{ + int error_code = 0; - // Complete 'ms_opt_des_par' for recompression cycle - ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] - ms_opt_des_par.m_fixed_P_mc_out = true; + this->m_htr_bypass_cycle->ms_des_par.m_bypass_frac = bp_frac_guess; + this->m_htr_bypass_cycle->design_core_standard(error_code); - if (ms_opt_des_par.m_fixed_PR_HP_to_LP) + if (this->m_htr_bypass_cycle->m_T_target_is_HTF == 0) { - ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + double target_out = this->m_htr_bypass_cycle->m_T_target; + double calc_sco2_out = this->m_htr_bypass_cycle->m_temp_last[MIXER_OUT]; + *diff_T_BP_HTF_out = calc_sco2_out - target_out; } else { - ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] - } - - // Is recompression fraction fixed or optimized? - if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) - { // fixed - ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); - ms_opt_des_par.m_fixed_recomp_frac = true; - } - else - { // optimized - ms_opt_des_par.m_recomp_frac_guess = 0.3; - ms_opt_des_par.m_fixed_recomp_frac = false; + double target_bp_out = this->m_htr_bypass_cycle->m_T_target; + double calc_bp_out = this->m_htr_bypass_cycle->m_T_HTF_BP_outlet_calc; + *diff_T_BP_HTF_out = calc_bp_out - target_bp_out; } + - // Is bypass fraction fixed or optimized? - if (ms_auto_opt_des_par.m_is_bypass_ok <= 0.0) - { // fixed - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - ms_opt_des_par.m_fixed_bypass_frac = true; - } - else - { // optimized - ms_opt_des_par.m_bypass_frac_guess = 0.3; - ms_opt_des_par.m_fixed_bypass_frac = false; - } + - ms_opt_des_par.m_LT_frac_guess = 0.5; - ms_opt_des_par.m_fixed_LT_frac = false; - if (ms_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) - { - ms_opt_des_par.m_fixed_LT_frac = true; - } + return error_code; +} - opt_max_eta(ms_auto_opt_des_par, ms_opt_des_par); - // This targets maximum efficiency. Bypass fraction is ALWAYS optimized outside other variables - if (ms_auto_opt_des_par.m_des_objective_type != 2) - { - +void C_HTRBypass_Cycle::opt_design_core(int& error_code) +{ + // Map ms_opt_des_par to ms_des_par + // LTR thermal design + ms_des_par.m_LTR_target_code = ms_opt_des_par.m_LTR_target_code; //[-] + ms_des_par.m_LTR_min_dT = ms_opt_des_par.m_LTR_min_dT; //[K] + ms_des_par.m_LTR_eff_target = ms_opt_des_par.m_LTR_eff_target; //[-] + ms_des_par.m_LTR_eff_max = ms_opt_des_par.m_LTR_eff_max; //[-] + ms_des_par.m_LTR_od_UA_target_type = ms_opt_des_par.m_LTR_od_UA_target_type; + // HTR thermal design + ms_des_par.m_HTR_target_code = ms_opt_des_par.m_HTR_target_code; //[-] + ms_des_par.m_HTR_min_dT = ms_opt_des_par.m_HTR_min_dT; //[K] + ms_des_par.m_HTR_eff_target = ms_opt_des_par.m_HTR_eff_target; //[-] + ms_des_par.m_HTR_eff_max = ms_opt_des_par.m_HTR_eff_max; //[-] + ms_des_par.m_HTR_od_UA_target_type = ms_opt_des_par.m_HTR_od_UA_target_type; + // + ms_des_par.m_des_tol = ms_opt_des_par.m_des_tol; - // Bypass Fraction - if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) - { - ms_opt_des_par.m_fixed_bypass_frac = true; - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - } - else - { - ms_opt_des_par.m_fixed_bypass_frac = false; - } + ms_des_par.m_is_des_air_cooler = ms_opt_des_par.m_is_des_air_cooler; //[-] - int rc_error_code = 0; + ms_des_par.m_des_objective_type = ms_opt_des_par.m_des_objective_type; //[-] + ms_des_par.m_min_phx_deltaT = ms_opt_des_par.m_min_phx_deltaT; //[C] - opt_design_core(rc_error_code); + // ms_des_par members to be defined by optimizer and set in 'design_point_eta': + // m_P_mc_in + // m_P_mc_out + // m_recomp_frac + // m_UA_LT + // m_UA_HT - if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) - { - ms_des_par_auto_opt = ms_des_par_optimal; - m_objective_metric_auto_opt = m_objective_metric_opt; - } - } + int index = 0; + std::vector x(0); + std::vector lb(0); + std::vector ub(0); + std::vector scale(0); - // Default case with Bypass either set or optimized WITHIN Optimization - if (ms_auto_opt_des_par.m_des_objective_type != 2) + if (!ms_opt_des_par.m_fixed_P_mc_out) { - // Bypass Fraction - if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) - { - ms_opt_des_par.m_fixed_bypass_frac = true; - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - } - else - { - ms_opt_des_par.m_fixed_bypass_frac = false; - } - - int rc_error_code = 0; - - opt_design_core(rc_error_code); + x.push_back(ms_opt_des_par.m_P_mc_out_guess); + lb.push_back(100.0); + ub.push_back(m_P_high_limit); + scale.push_back(500.0); - if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) - { - ms_des_par_auto_opt = ms_des_par_optimal; - m_objective_metric_auto_opt = m_objective_metric_opt; - } + index++; } - // Add option for des_objective_type == 2 (optimize bypass fraction OUTSIDE other optimization (rather than INSIDE) - else // (m_des_objective_type == 2) + if (!ms_opt_des_par.m_fixed_PR_HP_to_LP) { - // Bypass Fraction - ms_opt_des_par.m_fixed_bypass_frac = true; - - // Ensure thermal efficiency is initialized to negative value - m_objective_metric_full_auto_opt = -100000000000; - - // Hard coded Bypass Fraction, but other variables optimize to hit the correct temperature - if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) - { - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - - int rc_error_code = 0; + x.push_back(ms_opt_des_par.m_PR_HP_to_LP_guess); + lb.push_back(0.0001); + double PR_max = m_P_high_limit / 100.0; + ub.push_back(PR_max); + scale.push_back(0.2); - opt_design_core(rc_error_code); + index++; + } - - ms_des_par_auto_opt = ms_des_par_optimal; - m_objective_metric_auto_opt = m_objective_metric_opt; - - } + if (!ms_opt_des_par.m_fixed_recomp_frac) + { + x.push_back(ms_opt_des_par.m_recomp_frac_guess); + lb.push_back(0.0); + ub.push_back(1.0); + scale.push_back(0.05); + index++; + } - // Optimize Bypass Fraction outside other variables - else - { + if (!ms_opt_des_par.m_fixed_LT_frac) + { + x.push_back(ms_opt_des_par.m_LT_frac_guess); + lb.push_back(0.0); + ub.push_back(1.0); + scale.push_back(0.05); - m_objective_metric_bypass_frac_opt = -10000000; + index++; + } - // Set up instance of nlopt class and set optimization parameters - nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); + error_code = 0; + if (index > 0) + { + // Ensure thermal efficiency is initialized to negative value + m_objective_metric_opt = -100000000000; + + // Set up instance of nlopt class and set optimization parameters + nlopt::opt opt_des_cycle(nlopt::LN_SBPLX, index); + opt_des_cycle.set_lower_bounds(lb); + opt_des_cycle.set_upper_bounds(ub); + opt_des_cycle.set_initial_step(scale); + opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); + opt_des_cycle.set_maxeval(50); - std::vector lb = { 0 }; - std::vector ub = { 0.99 }; + // Set max objective function + opt_des_cycle.set_max_objective(nlopt_cb_opt_htr_bypass_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' + double max_f = std::numeric_limits::quiet_NaN(); + + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); - opt_des_cycle.set_lower_bounds(lb); - opt_des_cycle.set_upper_bounds(ub); - opt_des_cycle.set_initial_step(0.1); - opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); - opt_des_cycle.set_maxeval(50); + // Check if forced stop + int flag = opt_des_cycle.get_force_stop(); - // Set max objective function - std::vector x; - x.push_back(0.1); - opt_des_cycle.set_max_objective(nlopt_cb_opt_bypass_frac_free_var, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' - double max_f = std::numeric_limits::quiet_NaN(); + ms_des_par = ms_des_par_optimal; + design_core(error_code); - nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + int io = 0; + design_core_standard(io); + std::string val_string = make_result_csv_string(); - ms_des_par = ms_des_par_full_auto_opt; - ms_des_par_auto_opt = ms_des_par_full_auto_opt; - design_core_standard(error_code); + int otu = 0; - ms_opt_des_par.m_bypass_frac_guess = ms_des_par_auto_opt.m_bypass_frac; - //std::string s = make_result_csv_string(); - } + /* + m_W_dot_net_last = m_W_dot_net_opt; + m_eta_thermal_last = m_eta_thermal_opt; + m_temp_last = m_temp_opt; + m_pres_last = m_pres_opt; + m_enth_last = m_enth_opt; + m_entr_last = m_entr_opt; + m_dens_last = m_dens_opt; + */ } + else + { + // Finish defining ms_des_par based on current 'x' values + ms_des_par.m_P_mc_out = ms_opt_des_par.m_P_mc_out_guess; + ms_des_par.m_P_mc_in = ms_des_par.m_P_mc_out / ms_opt_des_par.m_PR_HP_to_LP_guess; + ms_des_par.m_recomp_frac = ms_opt_des_par.m_recomp_frac_guess; - ms_des_par = ms_des_par_auto_opt; - - int optimal_design_error_code = 0; - design_core(optimal_design_error_code); + if (ms_opt_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + ms_des_par.m_LTR_UA = ms_opt_des_par.m_UA_rec_total * ms_opt_des_par.m_LT_frac_guess; + ms_des_par.m_HTR_UA = ms_opt_des_par.m_UA_rec_total * (1.0 - ms_opt_des_par.m_LT_frac_guess); + } + else + { + ms_des_par.m_LTR_UA = ms_opt_des_par.m_LTR_UA; //[kW/K] + ms_des_par.m_HTR_UA = ms_opt_des_par.m_HTR_UA; //[kW/K] + } - if (optimal_design_error_code != 0) - { - error_code = optimal_design_error_code; - return; - } + // Ensure thermal efficiency is initialized to 0 + m_objective_metric_opt = 0.0; + double eta_local = design_cycle_return_objective_metric(x); - finalize_design(optimal_design_error_code); + if (eta_local == 0.0) + { + error_code = -1; + return; + } - error_code = optimal_design_error_code; + ms_des_par_optimal = ms_des_par; + } } + void C_HTRBypass_Cycle::finalize_design(int& error_code) { @@ -2865,158 +3105,27 @@ double C_HTRBypass_Cycle::design_bypass_frac_free_var_return_objective_metric(co -double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector& x, - const S_auto_opt_design_parameters auto_par, - const S_opt_design_parameters opt_par, - S_sco2_htrbp_in core_inputs) -{ - if (opt_par.m_fixed_bypass_frac == true) - { - throw std::exception("Optimizing bypass fraction even though it is fixed"); - } - - // Set Bypass Fraction - core_inputs.m_bypass_frac = x[0]; - - // Optimize all other variables - opt_nonbp_par(auto_par, opt_par, core_inputs); - - - return 0; -} -double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, - const S_auto_opt_design_parameters auto_par, - const S_opt_design_parameters opt_par, - S_sco2_htrbp_in core_inputs) -{ - // 'x' is array of inputs either being adjusted by optimizer or set constant - // Finish defining ms_des_par based on current 'x' values - int index = 0; - // Main compressor outlet pressure - - if (!auto_par.m_fixed_P_mc_out) - { - double P_mc_out = x[index]; - if (P_mc_out > m_P_high_limit) - return 0.0; - index++; - // assign P_mc_out - core_inputs.m_P_mc_out = P_mc_out; - } - - // Main compressor pressure ratio - double PR_mc_local = -999.9; - double P_mc_in = -999.9; - if (!opt_par.m_fixed_PR_HP_to_LP) - { - PR_mc_local = x[index]; - if (PR_mc_local > 50.0) - return -10000000000000.0; - index++; - P_mc_in = core_inputs.m_P_mc_out / PR_mc_local; - } - else - { - if (opt_par.m_PR_HP_to_LP_guess >= 0.0) - { - PR_mc_local = opt_par.m_PR_HP_to_LP_guess; - P_mc_in = core_inputs.m_P_mc_out / PR_mc_local; //[kPa] - } - else - { - P_mc_in = std::abs(opt_par.m_PR_HP_to_LP_guess); //[kPa] - } - } - if (P_mc_in >= ms_des_par.m_P_mc_out) - return 0.0; - if (P_mc_in <= 100.0) - return 0.0; - core_inputs.m_P_mc_in = P_mc_in; - // Recompression fraction - if (!opt_par.m_fixed_recomp_frac) - { - core_inputs.m_recomp_frac = x[index]; - if (core_inputs.m_recomp_frac < 0.0) - return 0.0; - index++; - } - // Recuperator split fraction - double LT_frac_local = -999.9; - double LTR_UA, HTR_UA; - if (!opt_par.m_fixed_LT_frac) - { - LT_frac_local = x[index]; - if (LT_frac_local > 1.0 || LT_frac_local < 0.0) - return 0.0; - index++; - if (auto_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || auto_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) - { - LTR_UA = auto_par.m_UA_rec_total * LT_frac_local; - HTR_UA = auto_par.m_UA_rec_total * (1.0 - LT_frac_local); - // ASSIGN LTR_UA and HTR_UA - core_inputs.m_LTR_UA = LTR_UA; - core_inputs.m_HTR_UA = HTR_UA; - } - } - - // AT this point, will have fully defined core input struct - // Run the core model - C_sco2_htrbp_core core_model; - core_model.SetInputs(core_inputs); - int error_code = core_model.Solve(); - // Set Objective - double objective_metric = -10000000000.0; - if (error_code == 0) - { - double eff = core_model.m_outputs.m_eta_thermal; - // If variable bypass fraction or targeting temperature - double penalty = 0; - if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) - { - double temp_calc = 0; - double span = 0; - if (m_T_target_is_HTF == 0) - { - temp_calc = core_model.m_outputs.m_temp[MIXER_OUT]; - span = core_model.m_outputs.m_temp[TURB_IN] - m_T_target; - } - else - { - temp_calc = core_model.m_outputs.m_T_HTF_BP_outlet; - span = core_model.m_inputs.m_T_HTF_PHX_inlet - m_T_target; - } - penalty = calc_penalty(m_T_target, temp_calc, span); - } - objective_metric = eff - penalty; - /*if (objective_metric > m_objective_metric_opt) - { - ms_des_par_optimal = ms_des_par; - m_objective_metric_opt = objective_metric; - }*/ - } - return objective_metric; -} @@ -3047,39 +3156,6 @@ double nlopt_cb_opt_bypass_frac_free_var(const std::vector& x, std::vect return 0.0; } -double nlopt_opt_max_eta_func(const std::vector& x, std::vector& grad, void* data) -{ - // Unpack Data Tuple - std::tuple* data_tuple - = static_cast*>(data); - - C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); - C_HTRBypass_Cycle::S_auto_opt_design_parameters auto_opt_par = std::get<1>(*data_tuple); - C_HTRBypass_Cycle::S_opt_design_parameters opt_par = std::get<2>(*data_tuple); - S_sco2_htrbp_in core_inputs = std::get<3>(*data_tuple); - - if (frame != NULL) - return frame->opt_max_eta_return_objective_metric(x, auto_opt_par, opt_par, core_inputs); - else - return 0.0; -} - -double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector& grad, void* data) -{ - // Unpack Data Tuple - std::tuple* data_tuple - = static_cast*>(data); - - C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); - C_HTRBypass_Cycle::S_auto_opt_design_parameters auto_opt_par = std::get<1>(*data_tuple); - C_HTRBypass_Cycle::S_opt_design_parameters opt_par = std::get<2>(*data_tuple); - S_sco2_htrbp_in core_inputs = std::get<3>(*data_tuple); - - if (frame != NULL) - return frame->opt_nonbp_par_return_objective_metric(x, auto_opt_par, opt_par, core_inputs); - else - return 0.0; -} double sigmoid(const double val) { From d8a37c98ed096aa1a1775bb4c6ac3c61d3129627 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Thu, 7 Mar 2024 22:00:25 -0700 Subject: [PATCH 36/94] Change function parameters to references and const where possible. --- tcs/sco2_htrbypass_cycle.cpp | 281 +++++++++++++++++++++-------------- tcs/sco2_htrbypass_cycle.h | 20 ++- 2 files changed, 185 insertions(+), 116 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 80bb1e6f5d..55ac6ca71e 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -712,7 +712,7 @@ int C_sco2_htrbp_core::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_L /// Optimize cycle, target maximum efficiency /// ONLY USE ARGUMENTS FROM FUNCTION /// -int C_HTRBypass_Cycle::opt_max_eta(S_auto_opt_design_parameters auto_par, S_opt_design_parameters opt_par) +int C_HTRBypass_Cycle::opt_max_eta(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& optimal_inputs) { // Set up baseline core inputs S_sco2_htrbp_in core_inputs; @@ -806,11 +806,17 @@ int C_HTRBypass_Cycle::opt_max_eta(S_auto_opt_design_parameters auto_par, S_opt_ //opt_nonbp_par(auto_par, opt_par, core_inputs); } - // Create optimizer for ONLY bypass (worry about others later) - + // Declare Optimal Inputs Case + S_sco2_htrbp_in optimal_inputs_final; + // Bypass is Variable, optimize other variables WITHIN bp optimizer if (opt_par.m_fixed_bypass_frac == false) { + // Reset Metrics + m_opt_obj_internal_only = -1000000000000000; + m_optimal_inputs_internal_only = S_sco2_htrbp_in(); + + // Create Optimizer nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); std::vector lb = { 0 }; @@ -823,7 +829,7 @@ int C_HTRBypass_Cycle::opt_max_eta(S_auto_opt_design_parameters auto_par, S_opt_ opt_des_cycle.set_maxeval(50); // Make Tuple to pass in parameters - std::tuple par_tuple = { this, auto_par, opt_par, core_inputs }; + std::tuple par_tuple = { this, &auto_par, &opt_par, &core_inputs }; // Set max objective function std::vector x; @@ -833,22 +839,34 @@ int C_HTRBypass_Cycle::opt_max_eta(S_auto_opt_design_parameters auto_par, S_opt_ nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); - // This will return optimal bypass frac ^ BUT - // Need to get Optimal Case from internal ^ + /// Check to make sure optimizer worked... + if (opt_des_cycle.get_force_stop()) + { + int w = 0; + } // Return an optimal input case + optimal_inputs_final = m_optimal_inputs_internal_only; + + // Clear Optimal Input Field + m_optimal_inputs_internal_only = S_sco2_htrbp_in(); + } // Bypass is Fixed, optimize other variables else { - opt_nonbp_par(auto_par, opt_par, core_inputs); + S_sco2_htrbp_in optimal_inputs_final_temporary; + int error_code = opt_nonbp_par(auto_par, opt_par, core_inputs, optimal_inputs_final_temporary); + if (error_code != 0) + return error_code; - // Return an optimal input case + // Return optimal input case + optimal_inputs_final = optimal_inputs_final_temporary; } - + optimal_inputs = optimal_inputs_final; return 0; } @@ -857,9 +875,14 @@ int C_HTRBypass_Cycle::opt_max_eta(S_auto_opt_design_parameters auto_par, S_opt_ /// Optimize variables OTHER THAN bypass fraction /// Auto par are from python /// opt par process the optimized variables from auto par +/// core_inputs are all of the constant known inputs +/// optimal inputs is the result, optimal case /// /// -int C_HTRBypass_Cycle::opt_nonbp_par(S_auto_opt_design_parameters auto_par, S_opt_design_parameters opt_par, S_sco2_htrbp_in core_inputs) +int C_HTRBypass_Cycle::opt_nonbp_par(const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + S_sco2_htrbp_in core_inputs, + S_sco2_htrbp_in& optimal_inputs) { // Add Applicable Design Variables to Optimizer int index = 0; @@ -911,6 +934,7 @@ int C_HTRBypass_Cycle::opt_nonbp_par(S_auto_opt_design_parameters auto_par, S_op // Make Optimizer (if there are variables to be optimized) int error_code = 0; + S_sco2_htrbp_in optimal_inputs_internal; if (index > 0) { // Set up instance of nlopt class and set optimization parameters @@ -922,7 +946,7 @@ int C_HTRBypass_Cycle::opt_nonbp_par(S_auto_opt_design_parameters auto_par, S_op opt_des_cycle.set_maxeval(50); // Make Tuple to pass in parameters - std::tuple par_tuple = { this, auto_par, opt_par, core_inputs }; + std::tuple par_tuple = { this, &auto_par, &opt_par, &core_inputs }; // Set max objective function @@ -935,40 +959,29 @@ int C_HTRBypass_Cycle::opt_nonbp_par(S_auto_opt_design_parameters auto_par, S_op // Check if forced stop int flag = opt_des_cycle.get_force_stop(); + if (flag == true) + { + error_code = -1; + return error_code; + } + + // Get Optimal Input Case + error_code = x_to_inputs(x, auto_par, opt_par, core_inputs); + if (error_code != 0) + return error_code; } else { // Define P_mc_in (because the ratio and mc_out are constant) core_inputs.m_P_mc_in = core_inputs.m_P_mc_out / opt_par.m_PR_HP_to_LP_guess; - //if (ms_opt_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) - //{ - // ms_des_par.m_LTR_UA = ms_opt_des_par.m_UA_rec_total * ms_opt_des_par.m_LT_frac_guess; - // ms_des_par.m_HTR_UA = ms_opt_des_par.m_UA_rec_total * (1.0 - ms_opt_des_par.m_LT_frac_guess); - //} - //else - //{ - // ms_des_par.m_LTR_UA = ms_opt_des_par.m_LTR_UA; //[kW/K] - // ms_des_par.m_HTR_UA = ms_opt_des_par.m_HTR_UA; //[kW/K] - //} - - // Ensure thermal efficiency is initialized to 0 - /*m_objective_metric_opt = 0.0; - double eta_local = design_cycle_return_objective_metric(x);*/ - - /*if (eta_local == 0.0) - { - error_code = -1; - return error_code; - }*/ - - // Simulate Case + // Simulate Case (don't actually need to run...) C_sco2_htrbp_core core_model; core_model.SetInputs(core_inputs); error_code = core_model.Solve(); } - // Assign a core_inputs + optimal_inputs = core_inputs; return error_code; } @@ -983,9 +996,9 @@ int C_HTRBypass_Cycle::opt_nonbp_par(S_auto_opt_design_parameters auto_par, S_op /// /// double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector& x, - const S_auto_opt_design_parameters auto_par, - const S_opt_design_parameters opt_par, - S_sco2_htrbp_in core_inputs) + const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + S_sco2_htrbp_in& core_inputs) { if (opt_par.m_fixed_bypass_frac == true) { @@ -996,15 +1009,50 @@ double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector< core_inputs.m_bypass_frac = x[0]; // Optimize all other variables - opt_nonbp_par(auto_par, opt_par, core_inputs); + S_sco2_htrbp_in optimal_inputs_case; + opt_nonbp_par(auto_par, opt_par, core_inputs, optimal_inputs_case); - // ^ Get optimal core_inputs from here (which will have a fixed bypass assigned from current function) + // ^ Get optimal core_inputs from here // Run Optimal Case, return objective function + C_sco2_htrbp_core core_model; + core_model.SetInputs(optimal_inputs_case); + int error_code = core_model.Solve(); + if (error_code != 0) + return -100000000000000000; - // Need to keep track of very best core_inputs case (don't have access to best obj value here though...) + double eff = core_model.m_outputs.m_eta_thermal; - return 0; + // If variable bypass fraction or targeting temperature + double penalty = 0; + if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) + { + double temp_calc = 0; + double span = 0; + + if (m_T_target_is_HTF == 0) + { + temp_calc = core_model.m_outputs.m_temp[MIXER_OUT]; + span = core_model.m_outputs.m_temp[TURB_IN] - m_T_target; + } + else + { + temp_calc = core_model.m_outputs.m_T_HTF_BP_outlet; + span = core_model.m_inputs.m_T_HTF_PHX_inlet - m_T_target; + } + + penalty = calc_penalty(m_T_target, temp_calc, span); + } + + double obj = eff - penalty; + + if (obj > m_opt_obj_internal_only) + { + m_opt_obj_internal_only = obj; + m_optimal_inputs_internal_only = optimal_inputs_case; + } + + return obj; } @@ -1017,13 +1065,70 @@ double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector< /// /// double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, + const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + S_sco2_htrbp_in& core_inputs) +{ + // Modify Core Inputs with Variable Parameters + int error_code = x_to_inputs(x, auto_par, opt_par, core_inputs); + + // AT this point, will have fully defined core input struct + // Run the core model + C_sco2_htrbp_core core_model; + core_model.SetInputs(core_inputs); + error_code = core_model.Solve(); + + // Set Objective + double objective_metric = -10000000000.0; + if (error_code == 0) + { + double eff = core_model.m_outputs.m_eta_thermal; + + // If variable bypass fraction or targeting temperature + double penalty = 0; + if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) + { + double temp_calc = 0; + double span = 0; + + if (m_T_target_is_HTF == 0) + { + temp_calc = core_model.m_outputs.m_temp[MIXER_OUT]; + span = core_model.m_outputs.m_temp[TURB_IN] - m_T_target; + } + else + { + temp_calc = core_model.m_outputs.m_T_HTF_BP_outlet; + span = core_model.m_inputs.m_T_HTF_PHX_inlet - m_T_target; + } + + penalty = calc_penalty(m_T_target, temp_calc, span); + } + + objective_metric = eff - penalty; + + /*if (objective_metric > m_objective_metric_opt) + { + ms_des_par_optimal = ms_des_par; + m_objective_metric_opt = objective_metric; + }*/ + } + + return objective_metric; +} + +/// +/// Take x inputs from optimizer results, create S_sco2_htrbp_in inputs from this +/// +int C_HTRBypass_Cycle::x_to_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, - S_sco2_htrbp_in core_inputs) + S_sco2_htrbp_in &core_inputs) { // 'x' is array of inputs either being adjusted by optimizer or set constant - // Finish defining ms_des_par based on current 'x' values + // Finish defining core_inputs based on current 'x' values + int error_message = 0; int index = 0; // Main compressor outlet pressure @@ -1032,7 +1137,7 @@ double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vecto { double P_mc_out = x[index]; if (P_mc_out > m_P_high_limit) - return 0.0; + return -1; index++; // assign P_mc_out @@ -1047,7 +1152,7 @@ double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vecto { PR_mc_local = x[index]; if (PR_mc_local > 50.0) - return -10000000000000.0; + return -1; index++; P_mc_in = core_inputs.m_P_mc_out / PR_mc_local; } @@ -1065,19 +1170,18 @@ double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vecto } if (P_mc_in >= ms_des_par.m_P_mc_out) - return 0.0; + return -1; if (P_mc_in <= 100.0) - return 0.0; + return -1; core_inputs.m_P_mc_in = P_mc_in; - // Recompression fraction if (!opt_par.m_fixed_recomp_frac) { core_inputs.m_recomp_frac = x[index]; if (core_inputs.m_recomp_frac < 0.0) - return 0.0; + return -1; index++; } @@ -1088,7 +1192,7 @@ double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vecto { LT_frac_local = x[index]; if (LT_frac_local > 1.0 || LT_frac_local < 0.0) - return 0.0; + return -1; index++; if (auto_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || auto_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) @@ -1102,69 +1206,22 @@ double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vecto } } - - - // AT this point, will have fully defined core input struct - // Run the core model - C_sco2_htrbp_core core_model; - core_model.SetInputs(core_inputs); - int error_code = core_model.Solve(); - - - - // Set Objective - double objective_metric = -10000000000.0; - if (error_code == 0) - { - double eff = core_model.m_outputs.m_eta_thermal; - - // If variable bypass fraction or targeting temperature - double penalty = 0; - if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) - { - double temp_calc = 0; - double span = 0; - - if (m_T_target_is_HTF == 0) - { - temp_calc = core_model.m_outputs.m_temp[MIXER_OUT]; - span = core_model.m_outputs.m_temp[TURB_IN] - m_T_target; - } - else - { - temp_calc = core_model.m_outputs.m_T_HTF_BP_outlet; - span = core_model.m_inputs.m_T_HTF_PHX_inlet - m_T_target; - } - - penalty = calc_penalty(m_T_target, temp_calc, span); - } - - objective_metric = eff - penalty; - - /*if (objective_metric > m_objective_metric_opt) - { - ms_des_par_optimal = ms_des_par; - m_objective_metric_opt = objective_metric; - }*/ - } - - return objective_metric; + return 0; } - double nlopt_opt_max_eta_func(const std::vector& x, std::vector& grad, void* data) { // Unpack Data Tuple - std::tuple* data_tuple - = static_cast*>(data); + std::tuple* data_tuple + = static_cast*>(data); C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); - C_HTRBypass_Cycle::S_auto_opt_design_parameters auto_opt_par = std::get<1>(*data_tuple); - C_HTRBypass_Cycle::S_opt_design_parameters opt_par = std::get<2>(*data_tuple); - S_sco2_htrbp_in core_inputs = std::get<3>(*data_tuple); + const C_HTRBypass_Cycle::S_auto_opt_design_parameters* auto_opt_par = std::get<1>(*data_tuple); + const C_HTRBypass_Cycle::S_opt_design_parameters* opt_par = std::get<2>(*data_tuple); + S_sco2_htrbp_in* core_inputs = std::get<3>(*data_tuple); if (frame != NULL) - return frame->opt_max_eta_return_objective_metric(x, auto_opt_par, opt_par, core_inputs); + return frame->opt_max_eta_return_objective_metric(x, *auto_opt_par, *opt_par, *core_inputs); else return 0.0; } @@ -1172,16 +1229,16 @@ double nlopt_opt_max_eta_func(const std::vector& x, std::vector& double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector& grad, void* data) { // Unpack Data Tuple - std::tuple* data_tuple - = static_cast*>(data); + std::tuple* data_tuple + = static_cast*>(data); C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); - C_HTRBypass_Cycle::S_auto_opt_design_parameters auto_opt_par = std::get<1>(*data_tuple); - C_HTRBypass_Cycle::S_opt_design_parameters opt_par = std::get<2>(*data_tuple); - S_sco2_htrbp_in core_inputs = std::get<3>(*data_tuple); + const C_HTRBypass_Cycle::S_auto_opt_design_parameters* auto_opt_par = std::get<1>(*data_tuple); + const C_HTRBypass_Cycle::S_opt_design_parameters* opt_par = std::get<2>(*data_tuple); + S_sco2_htrbp_in* core_inputs = std::get<3>(*data_tuple); if (frame != NULL) - return frame->opt_nonbp_par_return_objective_metric(x, auto_opt_par, opt_par, core_inputs); + return frame->opt_nonbp_par_return_objective_metric(x, *auto_opt_par, *opt_par, *core_inputs); else return 0.0; } @@ -1305,7 +1362,9 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) ms_opt_des_par.m_fixed_LT_frac = true; } - opt_max_eta(ms_auto_opt_des_par, ms_opt_des_par); + // Find optimal inputs + S_sco2_htrbp_in optimal_inputs; + opt_max_eta(ms_auto_opt_des_par, ms_opt_des_par, optimal_inputs); // This targets maximum efficiency. Bypass fraction is ALWAYS optimized outside other variables diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 5dfd9deb23..dd24520478 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -130,6 +130,8 @@ struct S_sco2_htrbp_in std::numeric_limits::quiet_NaN(); m_N_nodes_pass = 0; + m_LTR_N_sub_hxrs = 0; + m_HTR_N_sub_hxrs = 0; // Recuperator design target codes m_LTR_target_code = 1; // default to target conductance @@ -397,11 +399,18 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core private: - // NEW REFACTOR METHODS - int opt_max_eta(S_auto_opt_design_parameters auto_par, S_opt_design_parameters opt_par); + // NEW REFACTOR Fields and methods + int opt_max_eta(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& optimal_inputs); - int opt_nonbp_par(S_auto_opt_design_parameters auto_par, S_opt_design_parameters opt_par, S_sco2_htrbp_in core_inputs); + int opt_nonbp_par(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in core_inputs, S_sco2_htrbp_in& optimal_inputs); + int x_to_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in &core_inputs); + + // Optimal inputs, for bypass optimizer DO NOT USE + S_sco2_htrbp_in m_optimal_inputs_internal_only; + double m_opt_obj_internal_only; + + // END new refactor fields and methods // Component classes C_turbine m_t; @@ -572,9 +581,9 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double design_bypass_frac_free_var_return_objective_metric(const std::vector& x); - double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in core_inputs); + double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& core_inputs); - double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in core_inputs); + double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& core_inputs); class C_mono_htr_bypass_LTR_des : public C_monotonic_equation { @@ -686,6 +695,7 @@ double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector Date: Fri, 8 Mar 2024 14:28:26 -0700 Subject: [PATCH 37/94] Pass htrbp core solve class to optimizer, rather than inputs only. --- tcs/sco2_htrbypass_cycle.cpp | 192 +++++++++++++++++------------------ tcs/sco2_htrbypass_cycle.h | 11 +- 2 files changed, 100 insertions(+), 103 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 55ac6ca71e..9cd1c7891b 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -828,8 +828,12 @@ int C_HTRBypass_Cycle::opt_max_eta(const S_auto_opt_design_parameters& auto_par, opt_des_cycle.set_xtol_rel(auto_par.m_des_opt_tol); opt_des_cycle.set_maxeval(50); + // Set up Core Model that will be passed to objective function + C_sco2_htrbp_core htrbp_core; + htrbp_core.SetInputs(core_inputs); + // Make Tuple to pass in parameters - std::tuple par_tuple = { this, &auto_par, &opt_par, &core_inputs }; + std::tuple par_tuple = { this, &auto_par, &opt_par, &htrbp_core }; // Set max objective function std::vector x; @@ -938,15 +942,19 @@ int C_HTRBypass_Cycle::opt_nonbp_par(const S_auto_opt_design_parameters& auto_pa if (index > 0) { // Set up instance of nlopt class and set optimization parameters - nlopt::opt opt_des_cycle(nlopt::LN_SBPLX, index); + nlopt::opt opt_des_cycle(nlopt::LN_SBPLX, index); opt_des_cycle.set_lower_bounds(lb); opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(scale); opt_des_cycle.set_xtol_rel(auto_par.m_des_opt_tol); opt_des_cycle.set_maxeval(50); + // Set up Core Model that will be passed to objective function + C_sco2_htrbp_core htrbp_core; + htrbp_core.SetInputs(core_inputs); + // Make Tuple to pass in parameters - std::tuple par_tuple = { this, &auto_par, &opt_par, &core_inputs }; + std::tuple par_tuple = { this, &auto_par, &opt_par, &htrbp_core }; // Set max objective function @@ -981,6 +989,7 @@ int C_HTRBypass_Cycle::opt_nonbp_par(const S_auto_opt_design_parameters& auto_pa error_code = core_model.Solve(); } + // Set Optimal Inputs optimal_inputs = core_inputs; return error_code; @@ -998,7 +1007,7 @@ int C_HTRBypass_Cycle::opt_nonbp_par(const S_auto_opt_design_parameters& auto_pa double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, - S_sco2_htrbp_in& core_inputs) + C_sco2_htrbp_core& htrbp_core) { if (opt_par.m_fixed_bypass_frac == true) { @@ -1006,22 +1015,22 @@ double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector< } // Set Bypass Fraction - core_inputs.m_bypass_frac = x[0]; + htrbp_core.m_inputs.m_bypass_frac = x[0]; // Optimize all other variables S_sco2_htrbp_in optimal_inputs_case; - opt_nonbp_par(auto_par, opt_par, core_inputs, optimal_inputs_case); + opt_nonbp_par(auto_par, opt_par, htrbp_core.m_inputs, optimal_inputs_case); // ^ Get optimal core_inputs from here // Run Optimal Case, return objective function - C_sco2_htrbp_core core_model; - core_model.SetInputs(optimal_inputs_case); - int error_code = core_model.Solve(); + + htrbp_core.SetInputs(optimal_inputs_case); + int error_code = htrbp_core.Solve(); if (error_code != 0) return -100000000000000000; - double eff = core_model.m_outputs.m_eta_thermal; + double eff = htrbp_core.m_outputs.m_eta_thermal; // If variable bypass fraction or targeting temperature double penalty = 0; @@ -1032,13 +1041,13 @@ double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector< if (m_T_target_is_HTF == 0) { - temp_calc = core_model.m_outputs.m_temp[MIXER_OUT]; - span = core_model.m_outputs.m_temp[TURB_IN] - m_T_target; + temp_calc = htrbp_core.m_outputs.m_temp[MIXER_OUT]; + span = htrbp_core.m_outputs.m_temp[TURB_IN] - m_T_target; } else { - temp_calc = core_model.m_outputs.m_T_HTF_BP_outlet; - span = core_model.m_inputs.m_T_HTF_PHX_inlet - m_T_target; + temp_calc = htrbp_core.m_outputs.m_T_HTF_BP_outlet; + span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; } penalty = calc_penalty(m_T_target, temp_calc, span); @@ -1052,6 +1061,10 @@ double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector< m_optimal_inputs_internal_only = optimal_inputs_case; } + // Reset htrbp_core + htrbp_core.m_inputs.m_bypass_frac = std::numeric_limits::quiet_NaN(); + htrbp_core.m_outputs.Init(); + return obj; } @@ -1059,30 +1072,27 @@ double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector< /// /// Objective Function for NON Bypass optimization /// -/// -/// -/// -/// -/// +/// ONLY Objective Value double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, - S_sco2_htrbp_in& core_inputs) + C_sco2_htrbp_core& htrbp_core) { // Modify Core Inputs with Variable Parameters - int error_code = x_to_inputs(x, auto_par, opt_par, core_inputs); + int error_code = x_to_inputs(x, auto_par, opt_par, htrbp_core.m_inputs); + + if (error_code != 0) + return -1000000000; // AT this point, will have fully defined core input struct // Run the core model - C_sco2_htrbp_core core_model; - core_model.SetInputs(core_inputs); - error_code = core_model.Solve(); + error_code = htrbp_core.Solve(); // Set Objective double objective_metric = -10000000000.0; if (error_code == 0) { - double eff = core_model.m_outputs.m_eta_thermal; + double eff = htrbp_core.m_outputs.m_eta_thermal; // If variable bypass fraction or targeting temperature double penalty = 0; @@ -1093,13 +1103,13 @@ double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vecto if (m_T_target_is_HTF == 0) { - temp_calc = core_model.m_outputs.m_temp[MIXER_OUT]; - span = core_model.m_outputs.m_temp[TURB_IN] - m_T_target; + temp_calc = htrbp_core.m_outputs.m_temp[MIXER_OUT]; + span = htrbp_core.m_outputs.m_temp[TURB_IN] - m_T_target; } else { - temp_calc = core_model.m_outputs.m_T_HTF_BP_outlet; - span = core_model.m_inputs.m_T_HTF_PHX_inlet - m_T_target; + temp_calc = htrbp_core.m_outputs.m_T_HTF_BP_outlet; + span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; } penalty = calc_penalty(m_T_target, temp_calc, span); @@ -1114,11 +1124,14 @@ double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vecto }*/ } + // Clear Optimized Inputs + clear_optimized_inputs(x, auto_par, opt_par, htrbp_core.m_inputs); + return objective_metric; } /// -/// Take x inputs from optimizer results, create S_sco2_htrbp_in inputs from this +/// Take x inputs from optimizer results, write appropriate values to S_sco2_htrbp_in /// int C_HTRBypass_Cycle::x_to_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, @@ -1209,19 +1222,60 @@ int C_HTRBypass_Cycle::x_to_inputs(const std::vector& x, return 0; } +/// +/// Set Optimized Variables to NaN, to save them from misuse +/// +int C_HTRBypass_Cycle::clear_optimized_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in& core_inputs) +{ + // 'x' is array of inputs either being adjusted by optimizer or set constant + // Finish defining core_inputs based on current 'x' values + + int error_message = 0; + int index = 0; + + // Main compressor outlet pressure + + if (!auto_par.m_fixed_P_mc_out) + { + core_inputs.m_P_mc_out = std::numeric_limits::quiet_NaN(); + } + + + core_inputs.m_P_mc_in = std::numeric_limits::quiet_NaN(); + + // Recompression fraction + if (!opt_par.m_fixed_recomp_frac) + { + core_inputs.m_recomp_frac = std::numeric_limits::quiet_NaN(); + } + + // Recuperator split fraction + if (!opt_par.m_fixed_LT_frac) + { + if (auto_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || auto_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + // ASSIGN LTR_UA and HTR_UA + core_inputs.m_LTR_UA = std::numeric_limits::quiet_NaN();; + core_inputs.m_HTR_UA = std::numeric_limits::quiet_NaN();; + } + } + + return 0; +} + double nlopt_opt_max_eta_func(const std::vector& x, std::vector& grad, void* data) { // Unpack Data Tuple - std::tuple* data_tuple - = static_cast*>(data); + std::tuple* data_tuple + = static_cast*>(data); C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); const C_HTRBypass_Cycle::S_auto_opt_design_parameters* auto_opt_par = std::get<1>(*data_tuple); const C_HTRBypass_Cycle::S_opt_design_parameters* opt_par = std::get<2>(*data_tuple); - S_sco2_htrbp_in* core_inputs = std::get<3>(*data_tuple); + C_sco2_htrbp_core* htrbp_core = std::get<3>(*data_tuple); if (frame != NULL) - return frame->opt_max_eta_return_objective_metric(x, *auto_opt_par, *opt_par, *core_inputs); + return frame->opt_max_eta_return_objective_metric(x, *auto_opt_par, *opt_par, *htrbp_core); else return 0.0; } @@ -1229,16 +1283,16 @@ double nlopt_opt_max_eta_func(const std::vector& x, std::vector& double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector& grad, void* data) { // Unpack Data Tuple - std::tuple* data_tuple - = static_cast*>(data); + std::tuple* data_tuple + = static_cast*>(data); C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); const C_HTRBypass_Cycle::S_auto_opt_design_parameters* auto_opt_par = std::get<1>(*data_tuple); const C_HTRBypass_Cycle::S_opt_design_parameters* opt_par = std::get<2>(*data_tuple); - S_sco2_htrbp_in* core_inputs = std::get<3>(*data_tuple); + C_sco2_htrbp_core* htrbp_core = std::get<3>(*data_tuple); if (frame != NULL) - return frame->opt_nonbp_par_return_objective_metric(x, *auto_opt_par, *opt_par, *core_inputs); + return frame->opt_nonbp_par_return_objective_metric(x, *auto_opt_par, *opt_par, *htrbp_core); else return 0.0; } @@ -1507,68 +1561,6 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) void C_HTRBypass_Cycle::design_core(int& error_code) { - // DEBUG - { - S_sco2_htrbp_in core_inputs; - core_inputs.m_dT_BP = m_dT_BP; - core_inputs.m_P_mc_in = ms_des_par.m_P_mc_in; - core_inputs.m_P_mc_out = ms_des_par.m_P_mc_out; - core_inputs.m_LTR_target_code = ms_des_par.m_LTR_target_code; - core_inputs.m_LTR_UA = ms_des_par.m_LTR_UA; - core_inputs.m_LTR_min_dT = ms_des_par.m_LTR_min_dT; - core_inputs.m_LTR_eff_target = ms_des_par.m_LTR_eff_target; - core_inputs.m_LTR_eff_max = ms_des_par.m_LTR_eff_max; - core_inputs.m_LTR_N_sub_hxrs = m_LTR_N_sub_hxrs; - core_inputs.m_LTR_od_UA_target_type = ms_des_par.m_LTR_od_UA_target_type; - - core_inputs.m_HTR_target_code = ms_des_par.m_HTR_target_code; - core_inputs.m_HTR_UA = ms_des_par.m_HTR_UA; - core_inputs.m_HTR_min_dT = ms_des_par.m_HTR_min_dT; - core_inputs.m_HTR_eff_target = ms_des_par.m_HTR_eff_target; - core_inputs.m_HTR_eff_max = ms_des_par.m_HTR_eff_max; - core_inputs.m_HTR_N_sub_hxrs = m_HTR_N_sub_hxrs; - core_inputs.m_HTR_od_UA_target_type = ms_des_par.m_HTR_od_UA_target_type; - - core_inputs.m_recomp_frac = ms_des_par.m_recomp_frac; - core_inputs.m_bypass_frac = ms_opt_des_par.m_bypass_frac_guess; - core_inputs.m_des_tol = ms_des_par.m_des_tol; - core_inputs.m_is_des_air_cooler = ms_des_par.m_is_des_air_cooler; - - core_inputs.m_W_dot_net_design = m_W_dot_net; - core_inputs.m_T_mc_in = m_T_mc_in; // Comes from constructor (constant) - core_inputs.m_T_t_in = m_T_t_in; // Comes from constructor (constant) - core_inputs.m_DP_LTR = m_DP_LTR; // Comes from constructor (constant) - core_inputs.m_DP_HTR = m_DP_HTR; // Comes from constructor (constant) - core_inputs.m_DP_PC_main = m_DP_PC_main; // Comes from constructor (constant) - core_inputs.m_DP_PHX = m_DP_PHX; // Comes from constructor (constant) - core_inputs.m_eta_mc = m_eta_mc; // Comes from constructor (constant) - core_inputs.m_eta_t = m_eta_t; // Comes from constructor (constant) - core_inputs.m_eta_rc = m_eta_rc; // Comes from constructor (constant) - core_inputs.m_eta_generator = m_eta_generator; // Comes from constructor (constant) - core_inputs.m_frac_fan_power = m_frac_fan_power; // Comes from constructor (constant) - - core_inputs.m_set_HTF_mdot = m_set_HTF_mdot; // Comes from HTF par function (constant) - core_inputs.m_cp_HTF = m_cp_HTF; // Comes from HTF par function (constant) - core_inputs.m_T_HTF_PHX_inlet = m_T_HTF_PHX_inlet; // Comes from HTF par function (constant) - core_inputs.m_HTF_PHX_cold_approach_input = m_HTF_PHX_cold_approach; // Comes from constructor (constant) - - core_inputs.m_eta_fan = m_eta_fan; // Comes from constructor (constant) - core_inputs.m_deltaP_cooler_frac = m_deltaP_cooler_frac; // Comes from constructor (constant) - core_inputs.m_T_amb_des = m_T_amb_des; // Comes from constructor (constant) - core_inputs.m_elevation = m_elevation; // Comes from constructor (constant) - core_inputs.m_N_nodes_pass = m_N_nodes_pass; // Comes from constructor (constant) - - - C_sco2_htrbp_core sco2_core; - sco2_core.SetInputs(core_inputs); - int err = sco2_core.Solve(); - int ta = 0; - } - - - - - // Check if HTF parameters were set if (is_bp_par_set == false) { diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index dd24520478..f7f998c232 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -184,7 +184,7 @@ struct S_sco2_htrbp_out void Init() { - m_error_code = m_w_t = m_w_mc = m_w_rc + m_w_t = m_w_mc = m_w_rc = m_m_dot_t = m_m_dot_mc = m_m_dot_rc = m_m_dot_bp = m_m_dot_htr_hp = m_Q_dot_LT = m_Q_dot_HT @@ -196,6 +196,8 @@ struct S_sco2_htrbp_out = m_T_HTF_BP_outlet = m_HTF_BP_cold_approach = m_eta_thermal = std::numeric_limits::quiet_NaN(); + m_error_code = -1; + // Clear and Size Output Vectors m_temp.resize(C_sco2_cycle_core::END_SCO2_STATES); std::fill(m_temp.begin(), m_temp.end(), std::numeric_limits::quiet_NaN()); @@ -406,6 +408,9 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core int x_to_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in &core_inputs); + int clear_optimized_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in& core_inputs); + + // Optimal inputs, for bypass optimizer DO NOT USE S_sco2_htrbp_in m_optimal_inputs_internal_only; double m_opt_obj_internal_only; @@ -581,9 +586,9 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double design_bypass_frac_free_var_return_objective_metric(const std::vector& x); - double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& core_inputs); + double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); - double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& core_inputs); + double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); class C_mono_htr_bypass_LTR_des : public C_monotonic_equation { From 2dba8913b5cf173a2b055fad11e070508aaf1f9f Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Fri, 8 Mar 2024 21:45:28 -0700 Subject: [PATCH 38/94] Add finalize design function. Rename optimization function --- tcs/sco2_htrbypass_cycle.cpp | 389 ++++++++++++++++++----------------- tcs/sco2_htrbypass_cycle.h | 16 +- 2 files changed, 210 insertions(+), 195 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 9cd1c7891b..f917b66b6e 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -461,39 +461,159 @@ int C_sco2_htrbp_core::Solve() BPX_des_par.m_Q_dot_design = m_outputs.m_m_dot_bp * (m_outputs.m_enth[C_sco2_cycle_core::BYPASS_OUT] - m_outputs.m_enth[C_sco2_cycle_core::MIXER_OUT]); m_outputs.m_BPX.initialize(BPX_des_par); - // Design air cooler + // Air Cooler + C_HeatExchanger::S_design_parameters PC_des_par; + PC_des_par.m_DP_design[0] = 0.0; + PC_des_par.m_DP_design[1] = m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT] - m_outputs.m_pres[C_sco2_cycle_core::MC_IN]; + PC_des_par.m_m_dot_design[0] = 0.0; + PC_des_par.m_m_dot_design[1] = m_outputs.m_m_dot_mc; + PC_des_par.m_Q_dot_design = m_outputs.m_m_dot_mc * (m_outputs.m_enth[C_sco2_cycle_core::LTR_LP_OUT] - m_outputs.m_enth[C_sco2_cycle_core::MC_IN]); + m_outputs.m_PC.initialize(PC_des_par); + } + + // Calculate Thermal Efficiency + { + m_outputs.m_eta_thermal = m_outputs.m_W_dot_net / m_outputs.m_Q_dot_total; + } + + m_outputs.m_error_code = 0; + return m_outputs.m_error_code; +} + +int C_sco2_htrbp_core::FinalizeDesign(C_sco2_cycle_core::S_design_solved& design_solved) +{ + // Design Main Compressor + { + int mc_design_err = m_outputs.m_mc_ms.design_given_outlet_state(m_inputs.m_mc_comp_model_code, m_outputs.m_temp[C_sco2_cycle_core::MC_IN], + m_outputs.m_pres[C_sco2_cycle_core::MC_IN], + m_outputs.m_m_dot_mc, + m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], + m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], + m_inputs.m_des_tol); + + if (mc_design_err != 0) + { + m_outputs.m_error_code = mc_design_err; + return m_outputs.m_error_code; + } + } + + // Design Recompressor + if (m_inputs.m_recomp_frac > 0.01) + { + int rc_des_err = m_outputs.m_rc_ms.design_given_outlet_state(m_inputs.m_rc_comp_model_code, m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT], + m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT], + m_outputs.m_m_dot_rc, + m_outputs.m_temp[C_sco2_cycle_core::RC_OUT], + m_outputs.m_pres[C_sco2_cycle_core::RC_OUT], + m_inputs.m_des_tol); + + if (rc_des_err != 0) + { + m_outputs.m_error_code = rc_des_err; + return m_outputs.m_error_code; + } + + design_solved.m_is_rc = true; + } + else + { + design_solved.m_is_rc = false; + } + + // Size Turbine + { + C_turbine::S_design_parameters t_des_par; + // Set turbine shaft speed + t_des_par.m_N_design = m_inputs.m_N_turbine; + t_des_par.m_N_comp_design_if_linked = m_outputs.m_mc_ms.get_design_solved()->m_N_design; //[rpm] m_mc.get_design_solved()->m_N_design; + // Turbine inlet state + t_des_par.m_P_in = m_outputs.m_pres[C_sco2_cycle_core::TURB_IN]; + t_des_par.m_T_in = m_outputs.m_temp[C_sco2_cycle_core::TURB_IN]; + t_des_par.m_D_in = m_outputs.m_dens[C_sco2_cycle_core::TURB_IN]; + t_des_par.m_h_in = m_outputs.m_enth[C_sco2_cycle_core::TURB_IN]; + t_des_par.m_s_in = m_outputs.m_entr[C_sco2_cycle_core::TURB_IN]; + // Turbine outlet state + t_des_par.m_P_out = m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT]; + t_des_par.m_h_out = m_outputs.m_enth[C_sco2_cycle_core::TURB_OUT]; + // Mass flow + t_des_par.m_m_dot = m_outputs.m_m_dot_t; + + int turb_size_error_code = 0; + m_outputs.m_t.turbine_sizing(t_des_par, turb_size_error_code); + + if (turb_size_error_code != 0) + { + m_outputs.m_error_code = turb_size_error_code; + return m_outputs.m_error_code; + } + } + + // Design air cooler + { // Structure for design parameters that are dependent on cycle design solution C_CO2_to_air_cooler::S_des_par_cycle_dep s_air_cooler_des_par_dep; // Set air cooler design parameters that are dependent on the cycle design solution - s_air_cooler_des_par_dep.m_T_hot_in_des = m_outputs.m_temp[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT]; //[K] - s_air_cooler_des_par_dep.m_P_hot_in_des = m_outputs.m_pres[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT]; //[kPa] - s_air_cooler_des_par_dep.m_m_dot_total = m_outputs.m_m_dot_mc; //[kg/s] + s_air_cooler_des_par_dep.m_T_hot_in_des = m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT]; // [K] + s_air_cooler_des_par_dep.m_P_hot_in_des = m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT]; // [kPa] + s_air_cooler_des_par_dep.m_m_dot_total = m_outputs.m_m_dot_mc; // [kg/s] // This pressure drop is currently uncoupled from the cycle design - double cooler_deltaP = m_outputs.m_pres[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT] - m_outputs.m_pres[C_sco2_cycle_core::C_sco2_cycle_core::MC_IN]; //[kPa] + double cooler_deltaP = m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT] - m_outputs.m_pres[C_sco2_cycle_core::MC_IN]; // [kPa] if (cooler_deltaP == 0.0) - s_air_cooler_des_par_dep.m_delta_P_des = m_inputs.m_deltaP_cooler_frac * m_outputs.m_pres[C_sco2_cycle_core::C_sco2_cycle_core::LTR_LP_OUT]; //[kPa] + s_air_cooler_des_par_dep.m_delta_P_des = m_inputs.m_deltaP_cooler_frac * m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT]; // [kPa] else - s_air_cooler_des_par_dep.m_delta_P_des = cooler_deltaP; //[kPa] + s_air_cooler_des_par_dep.m_delta_P_des = cooler_deltaP; // [kPa] - s_air_cooler_des_par_dep.m_T_hot_out_des = m_outputs.m_temp[C_sco2_cycle_core::C_sco2_cycle_core::MC_IN]; //[K] - s_air_cooler_des_par_dep.m_W_dot_fan_des = m_outputs.m_W_dot_air_cooler / 1000.0; //[MWe] + s_air_cooler_des_par_dep.m_T_hot_out_des = m_outputs.m_temp[C_sco2_cycle_core::MC_IN]; // [K] + s_air_cooler_des_par_dep.m_W_dot_fan_des = m_inputs.m_frac_fan_power * m_outputs.m_W_dot_net / 1000.0; // [MWe] // Structure for design parameters that are independent of cycle design solution C_CO2_to_air_cooler::S_des_par_ind s_air_cooler_des_par_ind; - s_air_cooler_des_par_ind.m_T_amb_des = m_inputs.m_T_amb_des; //[K] - s_air_cooler_des_par_ind.m_elev = m_inputs.m_elevation; //[m] - s_air_cooler_des_par_ind.m_eta_fan = m_inputs.m_eta_fan; //[-] - s_air_cooler_des_par_ind.m_N_nodes_pass = m_inputs.m_N_nodes_pass; //[-] + s_air_cooler_des_par_ind.m_T_amb_des = m_inputs.m_T_amb_des; // [K] + s_air_cooler_des_par_ind.m_elev = m_inputs.m_elevation; // [m] + s_air_cooler_des_par_ind.m_eta_fan = m_inputs.m_eta_fan; // [-] + s_air_cooler_des_par_ind.m_N_nodes_pass = m_inputs.m_N_nodes_pass; // [-] + if (m_inputs.m_is_des_air_cooler && std::isfinite(m_inputs.m_deltaP_cooler_frac) && std::isfinite(m_inputs.m_frac_fan_power) + && std::isfinite(m_inputs.m_T_amb_des) && std::isfinite(m_inputs.m_elevation) && std::isfinite(m_inputs.m_eta_fan) && m_inputs.m_N_nodes_pass > 0) + { + m_outputs.mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, m_inputs.m_des_tol); + } } - // Calculate Thermal Efficiency - { - m_outputs.m_eta_thermal = m_outputs.m_W_dot_net / m_outputs.m_Q_dot_total; - } + // Get 'design_solved' structure from component classes + design_solved.ms_mc_ms_des_solved = *m_outputs.m_mc_ms.get_design_solved(); + design_solved.ms_rc_ms_des_solved = *m_outputs.m_rc_ms.get_design_solved(); + design_solved.ms_t_des_solved = *m_outputs.m_t.get_design_solved(); + design_solved.ms_LTR_des_solved = m_outputs.mc_LT_recup.ms_des_solved; + design_solved.ms_HTR_des_solved = m_outputs.mc_HT_recup.ms_des_solved; + design_solved.ms_mc_air_cooler = *m_outputs.mc_air_cooler.get_design_solved(); - m_outputs.m_error_code = 0; - return m_outputs.m_error_code; + // Set solved design point metrics + design_solved.m_temp = m_outputs.m_temp; + design_solved.m_pres = m_outputs.m_pres; + design_solved.m_enth = m_outputs.m_enth; + design_solved.m_entr = m_outputs.m_entr; + design_solved.m_dens = m_outputs.m_dens; + + design_solved.m_eta_thermal = m_outputs.m_eta_thermal; + design_solved.m_W_dot_net = m_outputs.m_W_dot_net; + design_solved.m_m_dot_mc = m_outputs.m_m_dot_mc; + design_solved.m_m_dot_rc = m_outputs.m_m_dot_rc; + design_solved.m_m_dot_t = m_outputs.m_m_dot_t; + design_solved.m_recomp_frac = m_outputs.m_m_dot_rc / m_outputs.m_m_dot_t; + design_solved.m_bypass_frac = m_inputs.m_bypass_frac; + + design_solved.m_UA_LTR = m_inputs.m_LTR_UA; + design_solved.m_UA_HTR = m_inputs.m_HTR_UA; + + design_solved.m_W_dot_t = m_outputs.m_W_dot_t; //[kWe] + design_solved.m_W_dot_mc = m_outputs.m_W_dot_mc; //[kWe] + design_solved.m_W_dot_rc = m_outputs.m_W_dot_rc; //[kWe] + + design_solved.m_W_dot_cooler_tot = m_outputs.mc_air_cooler.get_design_solved()->m_W_dot_fan * 1.E3; //[kWe] convert from MWe + + return 0; } int C_sco2_htrbp_core::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out) @@ -709,10 +829,9 @@ int C_sco2_htrbp_core::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_L // ********************************************************************************** ADDED Refactored opt methods /// -/// Optimize cycle, target maximum efficiency -/// ONLY USE ARGUMENTS FROM FUNCTION +/// Optimize cycle (bypass outer loop, which calls inner loop for other design variables) /// -int C_HTRBypass_Cycle::opt_max_eta(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& optimal_inputs) +int C_HTRBypass_Cycle::optimize_cycle(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& optimal_inputs) { // Set up baseline core inputs S_sco2_htrbp_in core_inputs; @@ -755,6 +874,10 @@ int C_HTRBypass_Cycle::opt_max_eta(const S_auto_opt_design_parameters& auto_par, core_inputs.m_T_amb_des = m_T_amb_des; // Comes from constructor (constant) core_inputs.m_elevation = m_elevation; // Comes from constructor (constant) core_inputs.m_N_nodes_pass = m_N_nodes_pass; // Comes from constructor (constant) + core_inputs.m_mc_comp_model_code = m_mc_comp_model_code; // Comes from constructor (constant) + core_inputs.m_N_turbine = m_N_turbine; // Comes from constructor (constant) + + core_inputs.m_rc_comp_model_code = C_comp__psi_eta_vs_phi::E_snl_radial_via_Dyreby; // Constant // From special bypass fraction function (should remove) core_inputs.m_dT_BP = m_dT_BP; // Comes from bp par function (constant) @@ -838,10 +961,10 @@ int C_HTRBypass_Cycle::opt_max_eta(const S_auto_opt_design_parameters& auto_par, // Set max objective function std::vector x; x.push_back(0.1); - opt_des_cycle.set_max_objective(nlopt_opt_max_eta_func, &par_tuple); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' + opt_des_cycle.set_max_objective(nlopt_opt_cycle_func, &par_tuple); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' double max_f = std::numeric_limits::quiet_NaN(); - nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); /// Check to make sure optimizer worked... if (opt_des_cycle.get_force_stop()) @@ -1004,7 +1127,7 @@ int C_HTRBypass_Cycle::opt_nonbp_par(const S_auto_opt_design_parameters& auto_pa /// /// /// -double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector& x, +double C_HTRBypass_Cycle::opt_cycle_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core) @@ -1125,7 +1248,7 @@ double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vecto } // Clear Optimized Inputs - clear_optimized_inputs(x, auto_par, opt_par, htrbp_core.m_inputs); + clear_x_inputs(x, auto_par, opt_par, htrbp_core.m_inputs); return objective_metric; } @@ -1225,7 +1348,7 @@ int C_HTRBypass_Cycle::x_to_inputs(const std::vector& x, /// /// Set Optimized Variables to NaN, to save them from misuse /// -int C_HTRBypass_Cycle::clear_optimized_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in& core_inputs) +int C_HTRBypass_Cycle::clear_x_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in& core_inputs) { // 'x' is array of inputs either being adjusted by optimizer or set constant // Finish defining core_inputs based on current 'x' values @@ -1263,7 +1386,7 @@ int C_HTRBypass_Cycle::clear_optimized_inputs(const std::vector& x, cons return 0; } -double nlopt_opt_max_eta_func(const std::vector& x, std::vector& grad, void* data) +double nlopt_opt_cycle_func(const std::vector& x, std::vector& grad, void* data) { // Unpack Data Tuple std::tuple* data_tuple @@ -1275,7 +1398,7 @@ double nlopt_opt_max_eta_func(const std::vector& x, std::vector& C_sco2_htrbp_core* htrbp_core = std::get<3>(*data_tuple); if (frame != NULL) - return frame->opt_max_eta_return_objective_metric(x, *auto_opt_par, *opt_par, *htrbp_core); + return frame->opt_cycle_return_objective_metric(x, *auto_opt_par, *opt_par, *htrbp_core); else return 0.0; } @@ -1304,49 +1427,50 @@ double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector 0 && - ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) + // COPY Values (TODO) { - throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" - " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); - } - - // map 'auto_opt_des_par_in' to 'ms_auto_opt_des_par' - - + // Check that simple/recomp flag is set + if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && + ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) + { + throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" + " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); + } + // map 'auto_opt_des_par_in' to 'ms_auto_opt_des_par' - // LTR thermal design - ms_opt_des_par.m_LTR_target_code = ms_auto_opt_des_par.m_LTR_target_code; //[-] - ms_opt_des_par.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; //[kW/K] - ms_opt_des_par.m_LTR_min_dT = ms_auto_opt_des_par.m_LTR_min_dT; //[K] - ms_opt_des_par.m_LTR_eff_target = ms_auto_opt_des_par.m_LTR_eff_target; //[-] - ms_opt_des_par.m_LTR_eff_max = ms_auto_opt_des_par.m_LTR_eff_max; //[-] - ms_opt_des_par.m_LTR_od_UA_target_type = ms_auto_opt_des_par.m_LTR_od_UA_target_type; - // HTR thermal design - ms_opt_des_par.m_HTR_target_code = ms_auto_opt_des_par.m_HTR_target_code; //[-] - ms_opt_des_par.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; //[kW/K] - ms_opt_des_par.m_HTR_min_dT = ms_auto_opt_des_par.m_HTR_min_dT; //[K] - ms_opt_des_par.m_HTR_eff_target = ms_auto_opt_des_par.m_HTR_eff_target; //[-] - ms_opt_des_par.m_HTR_eff_max = ms_auto_opt_des_par.m_HTR_eff_max; - ms_opt_des_par.m_HTR_od_UA_target_type = ms_auto_opt_des_par.m_HTR_od_UA_target_type; - // - ms_opt_des_par.m_UA_rec_total = ms_auto_opt_des_par.m_UA_rec_total; - ms_opt_des_par.m_des_tol = ms_auto_opt_des_par.m_des_tol; - ms_opt_des_par.m_des_opt_tol = ms_auto_opt_des_par.m_des_opt_tol; + // LTR thermal design + ms_opt_des_par.m_LTR_target_code = ms_auto_opt_des_par.m_LTR_target_code; //[-] + ms_opt_des_par.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; //[kW/K] + ms_opt_des_par.m_LTR_min_dT = ms_auto_opt_des_par.m_LTR_min_dT; //[K] + ms_opt_des_par.m_LTR_eff_target = ms_auto_opt_des_par.m_LTR_eff_target; //[-] + ms_opt_des_par.m_LTR_eff_max = ms_auto_opt_des_par.m_LTR_eff_max; //[-] + ms_opt_des_par.m_LTR_od_UA_target_type = ms_auto_opt_des_par.m_LTR_od_UA_target_type; + // HTR thermal design + ms_opt_des_par.m_HTR_target_code = ms_auto_opt_des_par.m_HTR_target_code; //[-] + ms_opt_des_par.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; //[kW/K] + ms_opt_des_par.m_HTR_min_dT = ms_auto_opt_des_par.m_HTR_min_dT; //[K] + ms_opt_des_par.m_HTR_eff_target = ms_auto_opt_des_par.m_HTR_eff_target; //[-] + ms_opt_des_par.m_HTR_eff_max = ms_auto_opt_des_par.m_HTR_eff_max; + ms_opt_des_par.m_HTR_od_UA_target_type = ms_auto_opt_des_par.m_HTR_od_UA_target_type; + // + ms_opt_des_par.m_UA_rec_total = ms_auto_opt_des_par.m_UA_rec_total; + ms_opt_des_par.m_des_tol = ms_auto_opt_des_par.m_des_tol; + ms_opt_des_par.m_des_opt_tol = ms_auto_opt_des_par.m_des_opt_tol; - ms_opt_des_par.m_is_des_air_cooler = ms_auto_opt_des_par.m_is_des_air_cooler; //[-] + ms_opt_des_par.m_is_des_air_cooler = ms_auto_opt_des_par.m_is_des_air_cooler; //[-] - ms_opt_des_par.m_des_objective_type = ms_auto_opt_des_par.m_des_objective_type; //[-] - ms_opt_des_par.m_min_phx_deltaT = ms_auto_opt_des_par.m_min_phx_deltaT; //[C] + ms_opt_des_par.m_des_objective_type = ms_auto_opt_des_par.m_des_objective_type; //[-] + ms_opt_des_par.m_min_phx_deltaT = ms_auto_opt_des_par.m_min_phx_deltaT; //[C] - ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] + ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] - ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] + ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] - // Outer optimization loop - m_objective_metric_auto_opt = 0.0; + // Outer optimization loop + m_objective_metric_auto_opt = 0.0; + } + double best_P_high = m_P_high_limit; //[kPa] double PR_mc_guess = 2.5; //[-] @@ -1418,137 +1542,23 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) // Find optimal inputs S_sco2_htrbp_in optimal_inputs; - opt_max_eta(ms_auto_opt_des_par, ms_opt_des_par, optimal_inputs); - - - // This targets maximum efficiency. Bypass fraction is ALWAYS optimized outside other variables - if (ms_auto_opt_des_par.m_des_objective_type != 2) - { - - - // Bypass Fraction - if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) - { - ms_opt_des_par.m_fixed_bypass_frac = true; - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - } - else - { - ms_opt_des_par.m_fixed_bypass_frac = false; - } - - int rc_error_code = 0; + error_code = optimize_cycle(ms_auto_opt_des_par, ms_opt_des_par, optimal_inputs); - opt_design_core(rc_error_code); - - if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) - { - ms_des_par_auto_opt = ms_des_par_optimal; - m_objective_metric_auto_opt = m_objective_metric_opt; - } - } - - - // Default case with Bypass either set or optimized WITHIN Optimization - if (ms_auto_opt_des_par.m_des_objective_type != 2) - { - // Bypass Fraction - if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) - { - ms_opt_des_par.m_fixed_bypass_frac = true; - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - } - else - { - ms_opt_des_par.m_fixed_bypass_frac = false; - } - - int rc_error_code = 0; - - opt_design_core(rc_error_code); - - if (rc_error_code == 0 && m_objective_metric_opt > m_objective_metric_auto_opt) - { - ms_des_par_auto_opt = ms_des_par_optimal; - m_objective_metric_auto_opt = m_objective_metric_opt; - } - } - - // Add option for des_objective_type == 2 (optimize bypass fraction OUTSIDE other optimization (rather than INSIDE) - else // (m_des_objective_type == 2) - { - // Bypass Fraction - ms_opt_des_par.m_fixed_bypass_frac = true; - - // Ensure thermal efficiency is initialized to negative value - m_objective_metric_full_auto_opt = -100000000000; - - // Hard coded Bypass Fraction, but other variables optimize to hit the correct temperature - if (ms_auto_opt_des_par.m_is_bypass_ok <= 0) - { - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - - int rc_error_code = 0; - - opt_design_core(rc_error_code); - - - ms_des_par_auto_opt = ms_des_par_optimal; - m_objective_metric_auto_opt = m_objective_metric_opt; - - } - - // Optimize Bypass Fraction outside other variables - else - { - - m_objective_metric_bypass_frac_opt = -10000000; - - // Set up instance of nlopt class and set optimization parameters - nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); - - std::vector lb = { 0 }; - std::vector ub = { 0.99 }; - - opt_des_cycle.set_lower_bounds(lb); - opt_des_cycle.set_upper_bounds(ub); - opt_des_cycle.set_initial_step(0.1); - opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); - opt_des_cycle.set_maxeval(50); - - // Set max objective function - std::vector x; - x.push_back(0.1); - opt_des_cycle.set_max_objective(nlopt_cb_opt_bypass_frac_free_var, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' - double max_f = std::numeric_limits::quiet_NaN(); - - - nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); - - - ms_des_par = ms_des_par_full_auto_opt; - ms_des_par_auto_opt = ms_des_par_full_auto_opt; - design_core_standard(error_code); - - ms_opt_des_par.m_bypass_frac_guess = ms_des_par_auto_opt.m_bypass_frac; - //std::string s = make_result_csv_string(); - } - } - - ms_des_par = ms_des_par_auto_opt; + if (error_code != 0) + return; - int optimal_design_error_code = 0; - design_core(optimal_design_error_code); + // Run Optimal Case + C_sco2_htrbp_core htrbp_core; + htrbp_core.SetInputs(optimal_inputs); + error_code = htrbp_core.Solve(); - if (optimal_design_error_code != 0) - { - error_code = optimal_design_error_code; + if (error_code != 0) return; - } - finalize_design(optimal_design_error_code); + // Finalize Design (pass in reference to solved parameters) + error_code = htrbp_core.FinalizeDesign(ms_des_solved); + - error_code = optimal_design_error_code; } // END legacy functions @@ -2707,7 +2717,6 @@ void C_HTRBypass_Cycle::opt_design_core(int& error_code) void C_HTRBypass_Cycle::finalize_design(int& error_code) { - // Design Main Compressor { int mc_design_err = m_mc_ms.design_given_outlet_state(m_mc_comp_model_code, m_temp_last[MC_IN], diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index f7f998c232..e6360aa661 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -101,6 +101,9 @@ struct S_sco2_htrbp_in double m_elevation; //[m] Elevation (used to calculate ambient pressure) int m_N_nodes_pass; //[-] Number of nodes per pass double m_HTF_PHX_cold_approach_input; //[delta K] PHX cold approach temperature. Only needed if m_set_HTF_mdot < 0 + int m_mc_comp_model_code; // Main compressor model code + int m_rc_comp_model_code; // Recompressor model code + int m_N_turbine; //[rpm] Turbine rpm S_sco2_htrbp_in() { @@ -132,6 +135,9 @@ struct S_sco2_htrbp_in m_N_nodes_pass = 0; m_LTR_N_sub_hxrs = 0; m_HTR_N_sub_hxrs = 0; + m_mc_comp_model_code = -1; + m_rc_comp_model_code = -1; + m_N_turbine = -1; // Recuperator design target codes m_LTR_target_code = 1; // default to target conductance @@ -261,7 +267,7 @@ class C_sco2_htrbp_core // Public Methods void SetInputs(S_sco2_htrbp_in inputs) { m_inputs = inputs; }; int Solve(); - + int FinalizeDesign(C_sco2_cycle_core::S_design_solved& design_solved); }; @@ -402,13 +408,13 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core private: // NEW REFACTOR Fields and methods - int opt_max_eta(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& optimal_inputs); + int optimize_cycle(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& optimal_inputs); int opt_nonbp_par(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in core_inputs, S_sco2_htrbp_in& optimal_inputs); int x_to_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in &core_inputs); - int clear_optimized_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in& core_inputs); + int clear_x_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in& core_inputs); // Optimal inputs, for bypass optimizer DO NOT USE @@ -586,7 +592,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double design_bypass_frac_free_var_return_objective_metric(const std::vector& x); - double C_HTRBypass_Cycle::opt_max_eta_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); + double C_HTRBypass_Cycle::opt_cycle_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); @@ -693,7 +699,7 @@ double nlopt_cb_opt_bypass_frac_free_var(const std::vector& x, std::vect // ADDED -double nlopt_opt_max_eta_func(const std::vector& x, std::vector& grad, void* data); +double nlopt_opt_cycle_func(const std::vector& x, std::vector& grad, void* data); double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector& grad, void* data); From 01f7da06acbc59392272de1a35245fc3499f4157 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Fri, 8 Mar 2024 22:25:57 -0700 Subject: [PATCH 39/94] Remove old optimization routines and unused functions. --- tcs/sco2_htrbypass_cycle.cpp | 1714 ++-------------------------------- tcs/sco2_htrbypass_cycle.h | 157 +--- 2 files changed, 70 insertions(+), 1801 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index f917b66b6e..9f39ce0227 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -823,6 +823,12 @@ int C_sco2_htrbp_core::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_L return 0; } +void C_sco2_htrbp_core::Reset() +{ + this->m_inputs = S_sco2_htrbp_in(); + this->m_outputs.Init(); +} + // ********************************************************************************** END C_sco2_htrbp_core @@ -1305,7 +1311,7 @@ int C_HTRBypass_Cycle::x_to_inputs(const std::vector& x, } } - if (P_mc_in >= ms_des_par.m_P_mc_out) + if (P_mc_in >= core_inputs.m_P_mc_out) return -1; if (P_mc_in <= 100.0) return -1; @@ -1425,8 +1431,22 @@ double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector lb = { 0 }; - std::vector ub = { 0.99 }; - - opt_des_cycle.set_lower_bounds(lb); - opt_des_cycle.set_upper_bounds(ub); - opt_des_cycle.set_initial_step(0.01); - opt_des_cycle.set_xtol_rel(0.1); - //opt_des_cycle.set_maxeval(50); - - // Set max objective function - std::vector x; - x.push_back(0.1); - opt_des_cycle.set_max_objective(nlopt_cb_opt_bypass_frac_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' - double max_f = std::numeric_limits::quiet_NaN(); - - - nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); - - - ms_des_par.m_bypass_frac = x[0]; - design_core_standard(error_code); - - std::string s = make_result_csv_string(); - - int yx = 0; - } + double percent_error = std::abs(target - calc) / span; + double penalty = 10.0 * (100.0 * sigmoid(percent_error) - 0.5); + return penalty; } -void C_HTRBypass_Cycle::design_core_standard(int& error_code) +void C_HTRBypass_Cycle::set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot, + int T_target_is_HTF) { - // Apply scaling to the turbomachinery here - { - m_mc_ms.m_r_W_dot_scale = m_W_dot_net / 10.E3; //[-] - m_rc_ms.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] - m_t.m_r_W_dot_scale = m_mc_ms.m_r_W_dot_scale; //[-] - } - - CO2_state co2_props; - - - // DEBUG - if(false) - { - { - double Q = 15.364; // MW - double mdot = 140.17; // kg/s - double pres = 18.134; //MPa - - double T2 = 346.69; // C - - // Get h2 - CO2_TP(T2 + 273.15, pres * 1e3, &co2_props); - double h2 = co2_props.enth; - - // Calculate h1 - double h1 = h2 - (Q * 1e3) / mdot; - - // Get T1 - CO2_PH(pres * 1e3, h1, &co2_props); - double T1 = co2_props.temp - 273.15; - - int oiasdf = 0; - } - - - // BP - double Q_dot_BP; - { - int prop_error_code = CO2_TP(194.3+273.15, 24.875 * 1e3, &co2_props); - double h1 = co2_props.enth; - - CO2_TP(471 + 273.15, 24.775 * 1e3, &co2_props); - double h2 = co2_props.enth; - - double mdot = 26.3; // kg/s - - Q_dot_BP = mdot * (h2 - h1); - } - - // PHX - double Q_dot_PHX; - { - int prop_error_code = CO2_TP(470.6 + 273.15, 24.75 * 1e3, &co2_props); - double h1 = co2_props.enth; - - CO2_TP(620 + 273.15, 24.55 * 1e3, &co2_props); - double h2 = co2_props.enth; - - double mdot = 239; // kg/s - - Q_dot_PHX = mdot * (h2 - h1); - } - - - - } - - // Initialize Recuperators - { - // LTR - mc_LT_recup.initialize(m_LTR_N_sub_hxrs, ms_des_par.m_LTR_od_UA_target_type); - // HTR - mc_HT_recup.initialize(m_HTR_N_sub_hxrs, ms_des_par.m_HTR_od_UA_target_type); - } - - // Initialize a few variables - { - m_temp_last[MC_IN] = m_T_mc_in; //[K] - m_pres_last[MC_IN] = ms_des_par.m_P_mc_in; - m_pres_last[MC_OUT] = ms_des_par.m_P_mc_out; - m_temp_last[TURB_IN] = m_T_t_in; //[K] - } - - // Apply pressure drops to heat exchangers, fully defining the pressures at all states - { - if (m_DP_LTR[0] < 0.0) - m_pres_last[LTR_HP_OUT] = m_pres_last[MC_OUT] - m_pres_last[MC_OUT] * std::abs(m_DP_LTR[0]); // relative pressure drop specified for LT recuperator (cold stream) - else - m_pres_last[LTR_HP_OUT] = m_pres_last[MC_OUT] - m_DP_LTR[0]; // absolute pressure drop specified for LT recuperator (cold stream) - - if ((ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && ms_des_par.m_LTR_UA < 1.0E-12) - || (ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && ms_des_par.m_LTR_UA < 1.0E-12) - || (ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && ms_des_par.m_LTR_min_dT < 1.0E-12) - || (ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && ms_des_par.m_LTR_eff_target < 1.0E-12)) - m_pres_last[LTR_HP_OUT] = m_pres_last[MC_OUT]; // If there is no LT recuperator, there is no pressure drop - - m_pres_last[MIXER_OUT] = m_pres_last[LTR_HP_OUT]; // Assume no pressure drop in mixing valve - m_pres_last[RC_OUT] = m_pres_last[LTR_HP_OUT]; // Assume no pressure drop in mixing valve - - if (m_DP_HTR[0] < 0.0) - m_pres_last[HTR_HP_OUT] = m_pres_last[MIXER_OUT] - m_pres_last[MIXER_OUT] * std::abs(m_DP_HTR[0]); // relative pressure drop specified for HT recuperator (cold stream) - else - m_pres_last[HTR_HP_OUT] = m_pres_last[MIXER_OUT] - m_DP_HTR[0]; // absolute pressure drop specified for HT recuperator (cold stream) - - if ((ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && ms_des_par.m_HTR_UA < 1.0E-12) - || (ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && ms_des_par.m_HTR_UA < 1.0E-12) - || (ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && ms_des_par.m_HTR_min_dT < 1.0E-12) - || (ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && ms_des_par.m_HTR_eff_target < 1.0E-12)) - m_pres_last[HTR_HP_OUT] = m_pres_last[MIXER_OUT]; // If there is no HT recuperator, there is no pressure drop - - if (m_DP_PHX[0] < 0.0) - m_pres_last[TURB_IN] = m_pres_last[HTR_HP_OUT] - m_pres_last[HTR_HP_OUT] * std::abs(m_DP_PHX[0]); // relative pressure drop specified for PHX - else - m_pres_last[TURB_IN] = m_pres_last[HTR_HP_OUT] - m_DP_PHX[0]; // absolute pressure drop specified for PHX - - if (m_DP_PC_main[1] < 0.0) - m_pres_last[LTR_LP_OUT] = m_pres_last[MC_IN] / (1.0 - std::abs(m_DP_PC_main[1])); // relative pressure drop specified for precooler: P1=P9-P9*rel_DP => P1=P9*(1-rel_DP) - else - m_pres_last[LTR_LP_OUT] = m_pres_last[MC_IN] + m_DP_PC_main[1]; - - if (m_DP_LTR[1] < 0.0) - m_pres_last[HTR_LP_OUT] = m_pres_last[LTR_LP_OUT] / (1.0 - std::abs(m_DP_LTR[1])); // relative pressure drop specified for LT recuperator (hot stream) - else - m_pres_last[HTR_LP_OUT] = m_pres_last[LTR_LP_OUT] + m_DP_LTR[1]; // absolute pressure drop specified for LT recuperator (hot stream) - - if ((ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && ms_des_par.m_LTR_UA < 1.0E-12) - || (ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && ms_des_par.m_LTR_UA < 1.0E-12) - || (ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && ms_des_par.m_LTR_min_dT < 1.0E-12) - || (ms_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && ms_des_par.m_LTR_eff_target < 1.0E-12)) - m_pres_last[HTR_LP_OUT] = m_pres_last[LTR_LP_OUT]; // if there is no LT recuperator, there is no pressure drop - - if (m_DP_HTR[1] < 0.0) - m_pres_last[TURB_OUT] = m_pres_last[HTR_LP_OUT] / (1.0 - std::abs(m_DP_HTR[1])); // relative pressure drop specified for HT recuperator (hot stream) - else - m_pres_last[TURB_OUT] = m_pres_last[HTR_LP_OUT] + m_DP_HTR[1]; // absolute pressure drop specified for HT recuperator (hot stream) - - if ((ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && ms_des_par.m_HTR_UA < 1.0E-12) - || (ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && ms_des_par.m_HTR_UA < 1.0E-12) - || (ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && ms_des_par.m_HTR_min_dT < 1.0E-12) - || (ms_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && ms_des_par.m_HTR_eff_target < 1.0E-12)) - m_pres_last[TURB_OUT] = m_pres_last[HTR_LP_OUT]; // if there is no HT recuperator, there is no pressure drop - - - // Added pressures - m_pres_last[BYPASS_OUT] = m_pres_last[HTR_HP_OUT]; - m_pres_last[MIXER2_OUT] = m_pres_last[HTR_HP_OUT]; - - - } - - // Determine equivalent isentropic efficiencies for main compressor and turbine, if necessary. - double eta_mc_isen = std::numeric_limits::quiet_NaN(); - double eta_t_isen = std::numeric_limits::quiet_NaN(); - { - if (m_eta_mc < 0.0) - { - int poly_error_code = 0; - - isen_eta_from_poly_eta(m_temp_last[MC_IN], m_pres_last[MC_IN], m_pres_last[MC_OUT], std::abs(m_eta_mc), - true, poly_error_code, eta_mc_isen); - - if (poly_error_code != 0) - { - error_code = poly_error_code; - return; - } - } - else - eta_mc_isen = m_eta_mc; - - if (m_eta_t < 0.0) - { - int poly_error_code = 0; - - isen_eta_from_poly_eta(m_temp_last[TURB_IN], m_pres_last[TURB_IN], m_pres_last[TURB_OUT], std::abs(m_eta_t), - false, poly_error_code, eta_t_isen); - - if (poly_error_code != 0) - { - error_code = poly_error_code; - return; - } - } - else - eta_t_isen = m_eta_t; - } - - // Determine the outlet state and specific work for the main compressor and turbine. - - // Main compressor - m_w_mc = std::numeric_limits::quiet_NaN(); - { - int comp_error_code = 0; - - calculate_turbomachinery_outlet_1(m_temp_last[MC_IN], m_pres_last[MC_IN], m_pres_last[MC_OUT], eta_mc_isen, true, - comp_error_code, m_enth_last[MC_IN], m_entr_last[MC_IN], m_dens_last[MC_IN], m_temp_last[MC_OUT], - m_enth_last[MC_OUT], m_entr_last[MC_OUT], m_dens_last[MC_OUT], m_w_mc); - - if (comp_error_code != 0) - { - error_code = comp_error_code; - return; - } - } - - // Turbine - m_w_t = std::numeric_limits::quiet_NaN(); - { - int turbine_error_code = 0; - - calculate_turbomachinery_outlet_1(m_temp_last[TURB_IN], m_pres_last[TURB_IN], m_pres_last[TURB_OUT], eta_t_isen, false, - turbine_error_code, m_enth_last[TURB_IN], m_entr_last[TURB_IN], m_dens_last[TURB_IN], m_temp_last[TURB_OUT], - m_enth_last[TURB_OUT], m_entr_last[TURB_OUT], m_dens_last[TURB_OUT], m_w_t); - - if (turbine_error_code != 0) - { - error_code = turbine_error_code; - return; - } - } - - // Check that this cycle can produce power - m_w_rc = std::numeric_limits::quiet_NaN(); - { - double eta_rc_isen = std::numeric_limits::quiet_NaN(); - - if (ms_des_par.m_recomp_frac >= 1.E-12) - { - if (m_eta_rc < 0.0) // need to convert polytropic efficiency to isentropic efficiency - { - int rc_error_code = 0; - - isen_eta_from_poly_eta(m_temp_last[MC_OUT], m_pres_last[LTR_LP_OUT], m_pres_last[RC_OUT], std::abs(m_eta_rc), - true, rc_error_code, eta_rc_isen); - - if (rc_error_code != 0) - { - error_code = rc_error_code; - return; - } - } - else - eta_rc_isen = m_eta_rc; - - int rc_error_code = 0; - - calculate_turbomachinery_outlet_1(m_temp_last[MC_OUT], m_pres_last[LTR_LP_OUT], m_pres_last[RC_OUT], eta_rc_isen, - true, rc_error_code, m_w_rc); - - if (rc_error_code != 0) - { - error_code = rc_error_code; - return; - } - } - else - m_w_rc = 0.0; - - if (m_w_mc + m_w_rc + m_w_t <= 0.0) // positive net power is impossible; return an error - { - error_code = 25; - return; - } - } - - // Solve the recuperators - { - C_mono_htr_bypass_HTR_des HTR_des_eq(this); - C_monotonic_eq_solver HTR_des_solver(HTR_des_eq); - - /*if (ms_des_par.m_recomp_frac == 0.0) - { - double y_T_diff = std::numeric_limits::quiet_NaN(); - int no_HTR_out_code = HTR_des_solver.test_member_function(m_temp_last[TURB_OUT], &y_T_diff); - - if (no_HTR_out_code != 0 || std::abs(y_T_diff / m_temp_last[MC_IN]) > ms_des_par.m_des_tol) - { - error_code = 35; - return; - } - }*/ - //else - { - double T_HTR_LP_out_lower = m_temp_last[MC_OUT]; //[K] Coldest possible temperature - double T_HTR_LP_out_upper = m_temp_last[TURB_OUT]; //[K] Hottest possible temperature - - double T_HTR_LP_out_guess_lower = std::min(T_HTR_LP_out_upper - 2.0, std::max(T_HTR_LP_out_lower + 15.0, 220.0 + 273.15)); //[K] There is nothing special about these guesses... - double T_HTR_LP_out_guess_upper = std::min(T_HTR_LP_out_guess_lower + 20.0, T_HTR_LP_out_upper - 1.0); //[K] There is nothing special about these guesses, either... - - //T_HTR_LP_out_guess_lower = T_HTR_LP_out_lower; - //T_HTR_LP_out_guess_upper = T_HTR_LP_out_upper; - - HTR_des_solver.settings(ms_des_par.m_des_tol * m_temp_last[MC_IN], 1000, T_HTR_LP_out_lower, T_HTR_LP_out_upper, false); + m_T_HTF_PHX_inlet = T_htf_phx_in; // K + m_T_target = T_target; // K + m_T_target_is_HTF = T_target_is_HTF; + m_cp_HTF = cp_htf; // kJ/kg K + m_dT_BP = dT_bp; + m_HTF_PHX_cold_approach = htf_phx_cold_approach; + m_set_HTF_mdot = set_HTF_mdot; - double T_HTR_LP_out_solved, tol_T_HTR_LP_out_solved; - T_HTR_LP_out_solved = tol_T_HTR_LP_out_solved = std::numeric_limits::quiet_NaN(); - int iter_T_HTR_LP_out = -1; + is_bp_par_set = true; +} - int T_HTR_LP_out_code = HTR_des_solver.solve(T_HTR_LP_out_guess_lower, T_HTR_LP_out_guess_upper, 0, - T_HTR_LP_out_solved, tol_T_HTR_LP_out_solved, iter_T_HTR_LP_out); - if (T_HTR_LP_out_code != C_monotonic_eq_solver::CONVERGED) - { - error_code = 35; - return; - } +// END legacy functions - double test = 0; - solve_HTR(T_HTR_LP_out_solved, &test); +// Public Methods - } - } +void C_HTRBypass_Cycle::reset_ms_od_turbo_bal_csp_solved() +{ +} - // State 5 can now be fully defined - { - // Check if there is flow through HTR_HP - if (m_m_dot_htr_hp <= 1e-12) - m_enth_last[HTR_HP_OUT] = m_enth_last[MIXER_OUT]; - else - m_enth_last[HTR_HP_OUT] = m_enth_last[MIXER_OUT] + m_Q_dot_HT / m_m_dot_htr_hp; // Energy balance on cold stream of high-temp recuperator - - int prop_error_code = CO2_PH(m_pres_last[HTR_HP_OUT], m_enth_last[HTR_HP_OUT], &co2_props); - if (prop_error_code != 0) - { - error_code = prop_error_code; - return; - } - m_temp_last[HTR_HP_OUT] = co2_props.temp; - m_entr_last[HTR_HP_OUT] = co2_props.entr; - m_dens_last[HTR_HP_OUT] = co2_props.dens; - } - - // Calculate total work and heat metrics - { - // Work - m_W_dot_mc = m_w_mc * m_m_dot_mc; //[kWe] - m_W_dot_rc = m_w_rc * m_m_dot_rc; //[kWe] - m_W_dot_t = m_w_t * m_m_dot_t; //[kWe] - m_W_dot_net_last = m_W_dot_mc + m_W_dot_rc + m_W_dot_t; - - // Air Cooler (heat rejection unit) - m_W_dot_air_cooler = m_frac_fan_power * m_W_dot_net; - m_Q_dot_air_cooler = m_m_dot_mc * (m_enth_last[LTR_LP_OUT] - m_enth_last[MC_IN]); - - // Total Heat Entering sco2 - m_Q_dot_total = m_W_dot_net_last + m_Q_dot_air_cooler; - - // LTR - m_Q_dot_LTR_LP = m_m_dot_t * (m_enth_last[HTR_LP_OUT] - m_enth_last[LTR_LP_OUT]); - m_Q_dot_LTR_HP = m_m_dot_mc * (m_enth_last[LTR_HP_OUT] - m_enth_last[MC_OUT]); - - // LTR - m_Q_dot_HTR_LP = m_m_dot_t * (m_enth_last[TURB_OUT] - m_enth_last[HTR_LP_OUT]); - m_Q_dot_HTR_HP = m_m_dot_htr_hp * (m_enth_last[HTR_HP_OUT] - m_enth_last[MIXER_OUT]); - } - - // Calculate Bypass Energy - { - // Set Bypass Temp based on HTR_HP_OUT - m_temp_last[BYPASS_OUT] = m_temp_last[HTR_HP_OUT] + m_dT_BP; - - // Calculate BYPASS_OUT properties - int prop_error_code = CO2_TP(this->m_temp_last[BYPASS_OUT], this->m_pres_last[BYPASS_OUT], &this->mc_co2_props); - if (prop_error_code != 0) - { - return; - } - this->m_enth_last[BYPASS_OUT] = this->mc_co2_props.enth; - this->m_entr_last[BYPASS_OUT] = this->mc_co2_props.entr; - this->m_dens_last[BYPASS_OUT] = this->mc_co2_props.dens; - - // Calculate Heat Transfer in Bypass - m_Q_dot_BP = m_m_dot_bp * (m_enth_last[BYPASS_OUT] - m_enth_last[MIXER_OUT]); - } - - // Simulate Mixer 2 - { - // If Bypass and HTR have flow - if (ms_des_par.m_bypass_frac >= 1e-12 && ms_des_par.m_bypass_frac <= (1.0 - 1e-12)) - { - m_enth_last[MIXER2_OUT] = (1.0 - ms_des_par.m_bypass_frac) * m_enth_last[HTR_HP_OUT] + - ms_des_par.m_bypass_frac * m_enth_last[BYPASS_OUT]; //[kJ/kg] - - int prop_error_code = CO2_PH(m_pres_last[MIXER2_OUT], m_enth_last[MIXER2_OUT], &mc_co2_props); - if (prop_error_code != 0) - { - return; - } - m_temp_last[MIXER2_OUT] = mc_co2_props.temp; //[K] - m_entr_last[MIXER2_OUT] = mc_co2_props.entr; //[kJ/kg-K] - m_dens_last[MIXER2_OUT] = mc_co2_props.dens; //[kg/m^3] - - } - // Flow only through HTR - else if (ms_des_par.m_bypass_frac <= (1.0 - 1e-12)) - { - m_temp_last[MIXER2_OUT] = m_temp_last[HTR_HP_OUT]; //[K] - m_enth_last[MIXER2_OUT] = m_enth_last[HTR_HP_OUT]; //[kJ/kg] - m_entr_last[MIXER2_OUT] = m_entr_last[HTR_HP_OUT]; //[kJ/kg-K] - m_dens_last[MIXER2_OUT] = m_dens_last[HTR_HP_OUT]; //[kg/m^3] - } - // Flow only through Bypass - else - { - m_temp_last[MIXER2_OUT] = m_temp_last[BYPASS_OUT]; //[K] - m_enth_last[MIXER2_OUT] = m_enth_last[BYPASS_OUT]; //[kJ/kg] - m_entr_last[MIXER2_OUT] = m_entr_last[BYPASS_OUT]; //[kJ/kg-K] - m_dens_last[MIXER2_OUT] = m_dens_last[BYPASS_OUT]; //[kg/m^3] - } - } - - // Calculate PHX Heat Transfer - { - m_Q_dot_PHX = m_m_dot_t * (m_enth_last[TURB_IN] - m_enth_last[MIXER2_OUT]); - } - - // Back Calculate and Check values - { - // Bypass Temps - double bp_temp_in = m_temp_last[MIXER_OUT]; - double bp_temp_out = m_temp_last[BYPASS_OUT]; - - double real_q_dot_total = m_W_dot_t + m_Q_dot_air_cooler; - - double qSum = m_Q_dot_total; - double qSum_calc = m_Q_dot_BP + m_Q_dot_PHX; - - int x = 0; - } - - // HTF - { - // Check if HTF mdot is already assigned - if (m_set_HTF_mdot > 0) - { - // Mdot is Set - m_m_dot_HTF = m_set_HTF_mdot; - - // Calculate PHX HTF Outlet Temperature - m_T_HTF_PHX_out = m_T_HTF_PHX_inlet - m_Q_dot_PHX / (m_m_dot_HTF * m_cp_HTF); - - // Back Calculate PHX cold approach - m_HTF_PHX_cold_approach = m_T_HTF_PHX_out - m_temp_last[MIXER2_OUT]; - } - else - { - // Use HTF Bypass cold approach to calculate PHX outlet Temperature - m_T_HTF_PHX_out = m_HTF_PHX_cold_approach + m_temp_last[MIXER2_OUT]; - - // Calculate HTF mdot - m_m_dot_HTF = m_Q_dot_PHX / ((m_T_HTF_PHX_inlet - m_T_HTF_PHX_out) * m_cp_HTF); - } - - - - - // Calculate Bypass Out Temperature - m_T_HTF_BP_outlet_calc = m_T_HTF_PHX_out - (m_Q_dot_BP / (m_m_dot_HTF * m_cp_HTF)); - - // Calculate HTF Bypass Cold Approach - m_HTF_BP_cold_approach = m_T_HTF_BP_outlet_calc - m_temp_last[MIXER_OUT]; - - //// Calculate PHX outlet Temp - //m_T_HTF_PHX_out = m_T_HTF_PHX_inlet - (m_Q_dot_PHX / (m_m_dot_HTF * m_cp_HTF)); - - - } - - // Define Heat Exchangers and Air Cooler - { - // PHX - C_HeatExchanger::S_design_parameters PHX_des_par; - PHX_des_par.m_DP_design[0] = m_pres_last[MIXER2_OUT] - m_pres_last[TURB_IN]; - PHX_des_par.m_DP_design[1] = 0.0; - PHX_des_par.m_m_dot_design[0] = m_m_dot_t; - PHX_des_par.m_m_dot_design[1] = 0.0; - PHX_des_par.m_Q_dot_design = m_m_dot_t * (m_enth_last[TURB_IN] - m_enth_last[MIXER2_OUT]); - m_PHX.initialize(PHX_des_par); - - - - // BPX - C_HeatExchanger::S_design_parameters BPX_des_par; - BPX_des_par.m_DP_design[0] = m_pres_last[MIXER_OUT] - m_pres_last[BYPASS_OUT]; - BPX_des_par.m_DP_design[1] = 0.0; - BPX_des_par.m_m_dot_design[0] = m_m_dot_bp; - BPX_des_par.m_m_dot_design[1] = 0.0; - BPX_des_par.m_Q_dot_design = m_m_dot_bp * (m_enth_last[BYPASS_OUT] - m_enth_last[MIXER_OUT]); - m_BPX.initialize(BPX_des_par); - - // Design air cooler - // Structure for design parameters that are dependent on cycle design solution - C_CO2_to_air_cooler::S_des_par_cycle_dep s_air_cooler_des_par_dep; - // Set air cooler design parameters that are dependent on the cycle design solution - s_air_cooler_des_par_dep.m_T_hot_in_des = m_temp_last[C_sco2_cycle_core::LTR_LP_OUT]; //[K] - s_air_cooler_des_par_dep.m_P_hot_in_des = m_pres_last[C_sco2_cycle_core::LTR_LP_OUT]; //[kPa] - s_air_cooler_des_par_dep.m_m_dot_total = m_m_dot_mc; //[kg/s] - - // This pressure drop is currently uncoupled from the cycle design - double cooler_deltaP = m_pres_last[C_sco2_cycle_core::LTR_LP_OUT] - m_pres_last[C_sco2_cycle_core::MC_IN]; //[kPa] - if (cooler_deltaP == 0.0) - s_air_cooler_des_par_dep.m_delta_P_des = m_deltaP_cooler_frac * m_pres_last[C_sco2_cycle_core::LTR_LP_OUT]; //[kPa] - else - s_air_cooler_des_par_dep.m_delta_P_des = cooler_deltaP; //[kPa] - - s_air_cooler_des_par_dep.m_T_hot_out_des = m_temp_last[C_sco2_cycle_core::MC_IN]; //[K] - s_air_cooler_des_par_dep.m_W_dot_fan_des = m_W_dot_air_cooler / 1000.0; //[MWe] - // Structure for design parameters that are independent of cycle design solution - C_CO2_to_air_cooler::S_des_par_ind s_air_cooler_des_par_ind; - s_air_cooler_des_par_ind.m_T_amb_des = m_T_amb_des; //[K] - s_air_cooler_des_par_ind.m_elev = m_elevation; //[m] - s_air_cooler_des_par_ind.m_eta_fan = m_eta_fan; //[-] - s_air_cooler_des_par_ind.m_N_nodes_pass = m_N_nodes_pass; //[-] - - /*if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) - && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) - { - try - { - mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, ms_des_par.m_des_tol); - } - catch (...) - { - error_code = 35; - return; - } - }*/ - - } - - // Set objective metric - { - - m_eta_thermal_calc_last = m_W_dot_net_last / m_Q_dot_total; - - if (ms_des_par.m_des_objective_type == 2) - { - double temp_calc = 0; - double span = 0; - - if (m_T_target_is_HTF == 0) - { - temp_calc = m_temp_last[MIXER_OUT]; - span = m_temp_last[TURB_IN] - m_T_target; - } - else - { - temp_calc = m_T_HTF_BP_outlet_calc; - span = m_T_HTF_PHX_inlet - m_T_target; - } - - /*double target_bp_out = m_T_target; - - double temp_err = std::abs(calc_bp_out - target_bp_out); - double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; - double percent_err = temp_err / temp_span;*/ - - double penalty = calc_penalty(m_T_target, temp_calc, span); - - m_objective_metric_last = m_eta_thermal_calc_last - penalty; - } - else - { - m_objective_metric_last = m_eta_thermal_calc_last; - } - } - -} - -int C_HTRBypass_Cycle::solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out) -{ - m_w_rc = m_m_dot_t = m_m_dot_rc = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT = std::numeric_limits::quiet_NaN(); - - // Set temperature guess - m_temp_last[HTR_LP_OUT] = T_HTR_LP_OUT_guess; //[K] - - // Solve HTR_LP_OUT properties - { - int prop_error_code = CO2_TP(this->m_temp_last[HTR_LP_OUT], this->m_pres_last[HTR_LP_OUT], &this->mc_co2_props); - if (prop_error_code != 0) - { - *diff_T_HTR_LP_out = std::numeric_limits::quiet_NaN(); - return prop_error_code; - } - this->m_enth_last[HTR_LP_OUT] = this->mc_co2_props.enth; - this->m_entr_last[HTR_LP_OUT] = this->mc_co2_props.entr; - this->m_dens_last[HTR_LP_OUT] = this->mc_co2_props.dens; - } - - // Solve for the LTR solution - { - double T_LTR_LP_out_lower = this->m_temp_last[MC_OUT]; //[K] Coldest possible outlet temperature - double T_LTR_LP_out_upper = this->m_temp_last[HTR_LP_OUT]; //[K] Hottest possible outlet temperature - - double T_LTR_LP_out_guess_upper = std::min(T_LTR_LP_out_upper, T_LTR_LP_out_lower + 15.0); //[K] There is nothing special about using 15 here... - double T_LTR_LP_out_guess_lower = std::min(T_LTR_LP_out_guess_upper * 0.99, T_LTR_LP_out_lower + 2.0); //[K] There is nothing special about using 2 here... - - //double T_LTR_LP_out_guess_upper = T_LTR_LP_out_lower + 273.15; - //double T_LTR_LP_out_guess_lower = T_LTR_LP_out_upper + 273.15; - - C_mono_htr_bypass_LTR_des LTR_des_eq(this); - C_monotonic_eq_solver LTR_des_solver(LTR_des_eq); - - LTR_des_solver.settings(this->ms_des_par.m_des_tol * this->m_temp_last[MC_IN], 1000, T_LTR_LP_out_lower, - T_LTR_LP_out_upper, false); - - double T_LTR_LP_out_solved = std::numeric_limits::quiet_NaN(); - double tol_T_LTR_LP_out_solved = std::numeric_limits::quiet_NaN(); - int iter_T_LTR_LP_out = -1; - - int T_LTR_LP_out_code = LTR_des_solver.solve(T_LTR_LP_out_guess_lower, T_LTR_LP_out_guess_upper, 0, T_LTR_LP_out_solved, - tol_T_LTR_LP_out_solved, iter_T_LTR_LP_out); - - if (T_LTR_LP_out_code != C_monotonic_eq_solver::CONVERGED) - { - return 31; - } - - //double error = 1000; - //double T_LTR_guess = 0.5 * (T_LTR_LP_out_lower + T_LTR_LP_out_upper); - //double diff = std::numeric_limits::quiet_NaN(); - //while (error > 0.1) - //{ - // solve_LTR(T_LTR_guess, &diff); - // double guess_val = T_LTR_guess; - // double calc_val = T_LTR_guess + diff; - // error = std::abs(guess_val - calc_val); - // // Update guess value - // T_LTR_guess = 0.5 * (guess_val + calc_val); - //} - - } - - // Know LTR performance so we can calculate the HP outlet (Energy balance on LTR HP stream) - { - this->m_enth_last[LTR_HP_OUT] = this->m_enth_last[MC_OUT] + m_Q_dot_LT / m_m_dot_mc; //[kJ/kg] - int prop_error_code = CO2_PH(this->m_pres_last[LTR_HP_OUT], this->m_enth_last[LTR_HP_OUT], &this->mc_co2_props); - if (prop_error_code != 0) - { - *diff_T_HTR_LP_out = std::numeric_limits::quiet_NaN(); - return prop_error_code; - } - this->m_temp_last[LTR_HP_OUT] = this->mc_co2_props.temp; //[K] - this->m_entr_last[LTR_HP_OUT] = this->mc_co2_props.entr; //[kJ/kg-K] - this->m_dens_last[LTR_HP_OUT] = this->mc_co2_props.dens; //[kg/m^3] - } - - // Simulate the Mixer - if (this->ms_des_par.m_recomp_frac >= 1.E-12) - { - this->m_enth_last[MIXER_OUT] = (1.0 - this->ms_des_par.m_recomp_frac) * this->m_enth_last[LTR_HP_OUT] + this->ms_des_par.m_recomp_frac * this->m_enth_last[RC_OUT]; //[kJ/kg] - int prop_error_code = CO2_PH(this->m_pres_last[MIXER_OUT], this->m_enth_last[MIXER_OUT], &this->mc_co2_props); - if (prop_error_code != 0) - { - *diff_T_HTR_LP_out = std::numeric_limits::quiet_NaN(); - return prop_error_code; - } - this->m_temp_last[MIXER_OUT] = this->mc_co2_props.temp; //[K] - this->m_entr_last[MIXER_OUT] = this->mc_co2_props.entr; //[kJ/kg-K] - this->m_dens_last[MIXER_OUT] = this->mc_co2_props.dens; //[kg/m^3] - } - else - { // No recompressor, so no mixing required, and HTR HP inlet = LTR HP outlet - this->m_temp_last[MIXER_OUT] = this->m_temp_last[LTR_HP_OUT]; //[K] - this->m_enth_last[MIXER_OUT] = this->m_enth_last[LTR_HP_OUT]; //[kJ/kg] - this->m_entr_last[MIXER_OUT] = this->m_entr_last[LTR_HP_OUT]; //[kJ/kg-K] - this->m_dens_last[MIXER_OUT] = this->m_dens_last[LTR_HP_OUT]; //[kg/m^3] - } - - // Solve Mass Flow rates for HTR_HP_OUT and Bypass - { - m_m_dot_bp = ms_des_par.m_bypass_frac * m_m_dot_t; - m_m_dot_htr_hp = m_m_dot_t - m_m_dot_bp; - } - - // Find the design solution of the HTR - double T_HTR_LP_out_calc = std::numeric_limits::quiet_NaN(); - { - // If there is no flow through HTR HP side - if (m_m_dot_htr_hp < 1e-12) - { - m_Q_dot_HT = 0; - T_HTR_LP_out_calc = m_temp_last[TURB_OUT]; - } - - // If there is flow through HTR HP side - else - { - this->mc_HT_recup.design_for_target__calc_outlet(this->ms_des_par.m_HTR_target_code, - this->ms_des_par.m_HTR_UA, this->ms_des_par.m_HTR_min_dT, this->ms_des_par.m_HTR_eff_target, - this->ms_des_par.m_HTR_eff_max, - this->m_temp_last[MIXER_OUT], this->m_pres_last[MIXER_OUT], m_m_dot_htr_hp, this->m_pres_last[HTR_HP_OUT], - this->m_temp_last[TURB_OUT], this->m_pres_last[TURB_OUT], m_m_dot_t, this->m_pres_last[HTR_LP_OUT], - this->ms_des_par.m_des_tol, - m_Q_dot_HT, this->m_temp_last[HTR_HP_OUT], T_HTR_LP_out_calc); - } - - } - - *diff_T_HTR_LP_out = T_HTR_LP_out_calc - T_HTR_LP_OUT_guess; - - return 0; -} - -int C_HTRBypass_Cycle::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_LP_out) -{ - m_w_rc = m_m_dot_t = m_m_dot_rc = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT = std::numeric_limits::quiet_NaN(); - - // Set LTR_LP_OUT guess - this->m_temp_last[LTR_LP_OUT] = T_LTR_LP_OUT_guess; - - // First, solve the recompressor model as necessary - if (this->ms_des_par.m_recomp_frac >= 1.E-12) - { - double eta_rc_isen = std::numeric_limits::quiet_NaN(); - - if (this->m_eta_rc < 0.0) // recalculate isen. efficiency of recompressor because inlet temp changes - { - int rc_error_code = 0; - isen_eta_from_poly_eta(this->m_temp_last[LTR_LP_OUT], this->m_pres_last[LTR_LP_OUT], - this->m_pres_last[RC_OUT], std::abs(this->m_eta_rc), true, - rc_error_code, eta_rc_isen); - - if (rc_error_code != 0) - { - *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); - return rc_error_code; - } - } - else - { - eta_rc_isen = this->m_eta_rc; - } - - int rc_error_code = 0; - - calculate_turbomachinery_outlet_1(this->m_temp_last[LTR_LP_OUT], this->m_pres_last[LTR_LP_OUT], this->m_pres_last[RC_OUT], eta_rc_isen, true, rc_error_code, - this->m_enth_last[LTR_LP_OUT], this->m_entr_last[LTR_LP_OUT], this->m_dens_last[LTR_LP_OUT], this->m_temp_last[RC_OUT], this->m_enth_last[RC_OUT], - this->m_entr_last[RC_OUT], this->m_dens_last[RC_OUT], m_w_rc); - - if (rc_error_code != 0) - { - *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); - return rc_error_code; - } - } - else - { - m_w_rc = 0.0; // no recompressor - int prop_error_code = CO2_TP(this->m_temp_last[LTR_LP_OUT], this->m_pres_last[LTR_LP_OUT], &this->mc_co2_props); - if (prop_error_code != 0) - { - *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); - return prop_error_code; - } - this->m_enth_last[LTR_LP_OUT] = this->mc_co2_props.enth; - this->m_entr_last[LTR_LP_OUT] = this->mc_co2_props.entr; - this->m_dens_last[LTR_LP_OUT] = this->mc_co2_props.dens; - this->m_temp_last[RC_OUT] = this->m_temp_last[LTR_LP_OUT]; - this->m_enth_last[RC_OUT] = this->m_enth_last[LTR_LP_OUT]; - this->m_entr_last[RC_OUT] = this->m_entr_last[LTR_LP_OUT]; - this->m_dens_last[RC_OUT] = this->m_dens_last[LTR_LP_OUT]; - } - - // Solve Mass Flow Rates - { - m_m_dot_t = this->m_W_dot_net / ((m_w_mc * (1.0 - this->ms_des_par.m_recomp_frac) + - m_w_rc * this->ms_des_par.m_recomp_frac + m_w_t) * this->m_eta_generator); //[kg/s] - - m_m_dot_rc = m_m_dot_t * this->ms_des_par.m_recomp_frac; //[kg/s] - m_m_dot_mc = m_m_dot_t - m_m_dot_rc; - } - - // Solve LTR - *diff_T_LTR_LP_out = std::numeric_limits::quiet_NaN(); - double T_LTR_LP_out_calc = std::numeric_limits::quiet_NaN(); - { - this->mc_LT_recup.design_for_target__calc_outlet(this->ms_des_par.m_LTR_target_code, - this->ms_des_par.m_LTR_UA, this->ms_des_par.m_LTR_min_dT, this->ms_des_par.m_LTR_eff_target, - this->ms_des_par.m_LTR_eff_max, - this->m_temp_last[MC_OUT], this->m_pres_last[MC_OUT], m_m_dot_mc, this->m_pres_last[LTR_HP_OUT], - this->m_temp_last[HTR_LP_OUT], this->m_pres_last[HTR_LP_OUT], m_m_dot_t, this->m_pres_last[LTR_LP_OUT], - this->ms_des_par.m_des_tol, - m_Q_dot_LT, this->m_temp_last[LTR_HP_OUT], T_LTR_LP_out_calc); - - } - - *diff_T_LTR_LP_out = T_LTR_LP_out_calc - T_LTR_LP_OUT_guess; - - return 0; -} - -double C_HTRBypass_Cycle::calc_penalty(double target, double calc, double span) -{ - double percent_error = std::abs(target - calc) / span; - double penalty = 10.0 * (100.0 * sigmoid(percent_error) - 0.5); - - return penalty; -} - -std::string C_HTRBypass_Cycle::make_result_csv_string() -{ - std::string value_string; - std::vector value_vec; - - value_vec.push_back(this->m_T_target); - value_vec.push_back(this->m_T_HTF_BP_outlet_calc); - value_vec.push_back(this->m_T_HTF_PHX_inlet); - value_vec.push_back(this->m_T_HTF_PHX_inlet - this->m_T_HTF_BP_outlet_calc); - value_vec.push_back(this->m_T_HTF_PHX_out); - value_vec.push_back(this->m_m_dot_HTF); - value_vec.push_back(std::numeric_limits::quiet_NaN()); - - value_vec.push_back(this->m_eta_thermal_calc_last); - value_vec.push_back(this->m_objective_metric_opt); - value_vec.push_back(this->m_objective_metric_bypass_frac_opt); - value_vec.push_back(std::numeric_limits::quiet_NaN()); - - value_vec.push_back(this->ms_des_par.m_bypass_frac); - value_vec.push_back(this->ms_des_par.m_recomp_frac); - double LTR_frac = this->mc_LT_recup.ms_des_solved.m_UA_calc_at_eff_max / - (this->mc_LT_recup.ms_des_solved.m_UA_calc_at_eff_max + this->mc_HT_recup.ms_des_solved.m_UA_calc_at_eff_max); - value_vec.push_back(LTR_frac); - value_vec.push_back(this->mc_LT_recup.ms_des_solved.m_UA_calc_at_eff_max); - value_vec.push_back(this->mc_HT_recup.ms_des_solved.m_UA_calc_at_eff_max); - value_vec.push_back(this->m_pres_last[MC_IN]); - value_vec.push_back(this->m_pres_last[MC_OUT]); - value_vec.push_back(std::numeric_limits::quiet_NaN()); - - value_vec.push_back(this->m_W_dot_t); - value_vec.push_back(this->m_W_dot_mc); - value_vec.push_back(this->m_W_dot_rc); - value_vec.push_back(this->m_W_dot_air_cooler); - value_vec.push_back(this->m_Q_dot_total); - value_vec.push_back(this->m_Q_dot_PHX); - value_vec.push_back(this->m_Q_dot_BP); - value_vec.push_back(this->m_Q_dot_air_cooler); - value_vec.push_back(this->m_Q_dot_LTR_HP); - value_vec.push_back(this->m_Q_dot_LTR_LP); - value_vec.push_back(this->m_Q_dot_HTR_HP); - value_vec.push_back(this->m_Q_dot_HTR_LP); - value_vec.push_back(std::numeric_limits::quiet_NaN()); - - value_vec.push_back(this->m_m_dot_t); - value_vec.push_back(this->m_m_dot_mc); - value_vec.push_back(this->m_m_dot_rc); - value_vec.push_back(this->m_m_dot_bp); - value_vec.push_back(this->m_m_dot_htr_hp); - value_vec.push_back(std::numeric_limits::quiet_NaN()); - - value_vec.push_back(this->mc_LT_recup.ms_des_solved.m_UA_calc_at_eff_max); - value_vec.push_back(this->mc_LT_recup.ms_des_solved.m_min_DT_design); - value_vec.push_back(this->mc_LT_recup.ms_des_solved.m_eff_design); - value_vec.push_back(this->mc_HT_recup.ms_des_solved.m_UA_calc_at_eff_max); - value_vec.push_back(this->mc_HT_recup.ms_des_solved.m_min_DT_design); - value_vec.push_back(this->mc_HT_recup.ms_des_solved.m_eff_design); - - - - // Write to string - for (double val : value_vec) - { - if(std::isnan(val) != true) - value_string.append(std::to_string(val)); - - value_string.append("\n"); - } - - - // Write Temperatures - value_string.append("\n"); - for (double val : this->m_temp_last) - { - value_string.append(std::to_string(val)); - value_string.append("\n"); - } - - // Write Pressures - value_string.append("\n"); - for (double val : this->m_pres_last) - { - value_string.append(std::to_string(val)); - value_string.append("\n"); - } - - - - - - - - return value_string; -} - - - -int C_HTRBypass_Cycle::C_mono_htr_bypass_LTR_des::operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out) -{ - return m_htr_bypass_cycle->solve_LTR(T_LTR_LP_OUT_guess, diff_T_LTR_LP_out); -} - - -int C_HTRBypass_Cycle::C_mono_htr_bypass_HTR_des::operator()(double T_HTR_LP_OUT_guess /*K*/, double* diff_T_HTR_LP_out) -{ - return m_htr_bypass_cycle->solve_HTR(T_HTR_LP_OUT_guess, diff_T_HTR_LP_out); -} - - -int C_HTRBypass_Cycle::C_mono_htr_bypass_BP_des::operator()(double bp_frac_guess, double* diff_T_BP_HTF_out) -{ - int error_code = 0; - - this->m_htr_bypass_cycle->ms_des_par.m_bypass_frac = bp_frac_guess; - this->m_htr_bypass_cycle->design_core_standard(error_code); - - if (this->m_htr_bypass_cycle->m_T_target_is_HTF == 0) - { - double target_out = this->m_htr_bypass_cycle->m_T_target; - double calc_sco2_out = this->m_htr_bypass_cycle->m_temp_last[MIXER_OUT]; - *diff_T_BP_HTF_out = calc_sco2_out - target_out; - } - else - { - double target_bp_out = this->m_htr_bypass_cycle->m_T_target; - double calc_bp_out = this->m_htr_bypass_cycle->m_T_HTF_BP_outlet_calc; - *diff_T_BP_HTF_out = calc_bp_out - target_bp_out; - } - - - - - - return error_code; -} - - - -void C_HTRBypass_Cycle::opt_design_core(int& error_code) -{ - // Map ms_opt_des_par to ms_des_par - // LTR thermal design - ms_des_par.m_LTR_target_code = ms_opt_des_par.m_LTR_target_code; //[-] - ms_des_par.m_LTR_min_dT = ms_opt_des_par.m_LTR_min_dT; //[K] - ms_des_par.m_LTR_eff_target = ms_opt_des_par.m_LTR_eff_target; //[-] - ms_des_par.m_LTR_eff_max = ms_opt_des_par.m_LTR_eff_max; //[-] - ms_des_par.m_LTR_od_UA_target_type = ms_opt_des_par.m_LTR_od_UA_target_type; - // HTR thermal design - ms_des_par.m_HTR_target_code = ms_opt_des_par.m_HTR_target_code; //[-] - ms_des_par.m_HTR_min_dT = ms_opt_des_par.m_HTR_min_dT; //[K] - ms_des_par.m_HTR_eff_target = ms_opt_des_par.m_HTR_eff_target; //[-] - ms_des_par.m_HTR_eff_max = ms_opt_des_par.m_HTR_eff_max; //[-] - ms_des_par.m_HTR_od_UA_target_type = ms_opt_des_par.m_HTR_od_UA_target_type; - // - ms_des_par.m_des_tol = ms_opt_des_par.m_des_tol; - - ms_des_par.m_is_des_air_cooler = ms_opt_des_par.m_is_des_air_cooler; //[-] - - ms_des_par.m_des_objective_type = ms_opt_des_par.m_des_objective_type; //[-] - ms_des_par.m_min_phx_deltaT = ms_opt_des_par.m_min_phx_deltaT; //[C] - - // ms_des_par members to be defined by optimizer and set in 'design_point_eta': - // m_P_mc_in - // m_P_mc_out - // m_recomp_frac - // m_UA_LT - // m_UA_HT - - int index = 0; - - std::vector x(0); - std::vector lb(0); - std::vector ub(0); - std::vector scale(0); - - if (!ms_opt_des_par.m_fixed_P_mc_out) - { - x.push_back(ms_opt_des_par.m_P_mc_out_guess); - lb.push_back(100.0); - ub.push_back(m_P_high_limit); - scale.push_back(500.0); - - index++; - } - - if (!ms_opt_des_par.m_fixed_PR_HP_to_LP) - { - x.push_back(ms_opt_des_par.m_PR_HP_to_LP_guess); - lb.push_back(0.0001); - double PR_max = m_P_high_limit / 100.0; - ub.push_back(PR_max); - scale.push_back(0.2); - - index++; - } - - if (!ms_opt_des_par.m_fixed_recomp_frac) - { - x.push_back(ms_opt_des_par.m_recomp_frac_guess); - lb.push_back(0.0); - ub.push_back(1.0); - scale.push_back(0.05); - index++; - } - - if (!ms_opt_des_par.m_fixed_LT_frac) - { - x.push_back(ms_opt_des_par.m_LT_frac_guess); - lb.push_back(0.0); - ub.push_back(1.0); - scale.push_back(0.05); - - index++; - } - - error_code = 0; - if (index > 0) - { - // Ensure thermal efficiency is initialized to negative value - m_objective_metric_opt = -100000000000; - - // Set up instance of nlopt class and set optimization parameters - nlopt::opt opt_des_cycle(nlopt::LN_SBPLX, index); - opt_des_cycle.set_lower_bounds(lb); - opt_des_cycle.set_upper_bounds(ub); - opt_des_cycle.set_initial_step(scale); - opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); - opt_des_cycle.set_maxeval(50); - - // Set max objective function - opt_des_cycle.set_max_objective(nlopt_cb_opt_htr_bypass_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' - double max_f = std::numeric_limits::quiet_NaN(); - - nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); - - // Check if forced stop - int flag = opt_des_cycle.get_force_stop(); - - ms_des_par = ms_des_par_optimal; - - design_core(error_code); - - int io = 0; - design_core_standard(io); - - std::string val_string = make_result_csv_string(); - - int otu = 0; - - /* - m_W_dot_net_last = m_W_dot_net_opt; - m_eta_thermal_last = m_eta_thermal_opt; - m_temp_last = m_temp_opt; - m_pres_last = m_pres_opt; - m_enth_last = m_enth_opt; - m_entr_last = m_entr_opt; - m_dens_last = m_dens_opt; - */ - } - else - { - // Finish defining ms_des_par based on current 'x' values - ms_des_par.m_P_mc_out = ms_opt_des_par.m_P_mc_out_guess; - ms_des_par.m_P_mc_in = ms_des_par.m_P_mc_out / ms_opt_des_par.m_PR_HP_to_LP_guess; - ms_des_par.m_recomp_frac = ms_opt_des_par.m_recomp_frac_guess; - - if (ms_opt_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) - { - ms_des_par.m_LTR_UA = ms_opt_des_par.m_UA_rec_total * ms_opt_des_par.m_LT_frac_guess; - ms_des_par.m_HTR_UA = ms_opt_des_par.m_UA_rec_total * (1.0 - ms_opt_des_par.m_LT_frac_guess); - } - else - { - ms_des_par.m_LTR_UA = ms_opt_des_par.m_LTR_UA; //[kW/K] - ms_des_par.m_HTR_UA = ms_opt_des_par.m_HTR_UA; //[kW/K] - } - - // Ensure thermal efficiency is initialized to 0 - m_objective_metric_opt = 0.0; - double eta_local = design_cycle_return_objective_metric(x); - - if (eta_local == 0.0) - { - error_code = -1; - return; - } - - ms_des_par_optimal = ms_des_par; - } -} - - -void C_HTRBypass_Cycle::finalize_design(int& error_code) -{ - - // Design Main Compressor - { - int mc_design_err = m_mc_ms.design_given_outlet_state(m_mc_comp_model_code, m_temp_last[MC_IN], - m_pres_last[MC_IN], - m_m_dot_mc, - m_temp_last[MC_OUT], - m_pres_last[MC_OUT], - ms_des_par.m_des_tol); - - if (mc_design_err != 0) - { - error_code = mc_design_err; - return; - } - } - - // Design Recompressor - if (ms_des_par.m_recomp_frac > 0.01) - { - int rc_des_err = m_rc_ms.design_given_outlet_state(m_rc_comp_model_code, m_temp_last[LTR_LP_OUT], - m_pres_last[LTR_LP_OUT], - m_m_dot_rc, - m_temp_last[RC_OUT], - m_pres_last[RC_OUT], - ms_des_par.m_des_tol); - - if (rc_des_err != 0) - { - error_code = rc_des_err; - return; - } - - ms_des_solved.m_is_rc = true; - } - else - { - ms_des_solved.m_is_rc = false; - } - - // Size Turbine - { - C_turbine::S_design_parameters t_des_par; - // Set turbine shaft speed - t_des_par.m_N_design = m_N_turbine; - t_des_par.m_N_comp_design_if_linked = m_mc_ms.get_design_solved()->m_N_design; //[rpm] m_mc.get_design_solved()->m_N_design; - // Turbine inlet state - t_des_par.m_P_in = m_pres_last[TURB_IN]; - t_des_par.m_T_in = m_temp_last[TURB_IN]; - t_des_par.m_D_in = m_dens_last[TURB_IN]; - t_des_par.m_h_in = m_enth_last[TURB_IN]; - t_des_par.m_s_in = m_entr_last[TURB_IN]; - // Turbine outlet state - t_des_par.m_P_out = m_pres_last[TURB_OUT]; - t_des_par.m_h_out = m_enth_last[TURB_OUT]; - // Mass flow - t_des_par.m_m_dot = m_m_dot_t; - - int turb_size_error_code = 0; - m_t.turbine_sizing(t_des_par, turb_size_error_code); - - if (turb_size_error_code != 0) - { - error_code = turb_size_error_code; - return; - } - } - - // Design air cooler - { - // Structure for design parameters that are dependent on cycle design solution - C_CO2_to_air_cooler::S_des_par_cycle_dep s_air_cooler_des_par_dep; - // Set air cooler design parameters that are dependent on the cycle design solution - s_air_cooler_des_par_dep.m_T_hot_in_des = m_temp_last[LTR_LP_OUT]; // [K] - s_air_cooler_des_par_dep.m_P_hot_in_des = m_pres_last[LTR_LP_OUT]; // [kPa] - s_air_cooler_des_par_dep.m_m_dot_total = m_m_dot_mc; // [kg/s] - - // This pressure drop is currently uncoupled from the cycle design - double cooler_deltaP = m_pres_last[LTR_LP_OUT] - m_pres_last[MC_IN]; // [kPa] - if (cooler_deltaP == 0.0) - s_air_cooler_des_par_dep.m_delta_P_des = m_deltaP_cooler_frac * m_pres_last[LTR_LP_OUT]; // [kPa] - else - s_air_cooler_des_par_dep.m_delta_P_des = cooler_deltaP; // [kPa] - - s_air_cooler_des_par_dep.m_T_hot_out_des = m_temp_last[MC_IN]; // [K] - s_air_cooler_des_par_dep.m_W_dot_fan_des = m_frac_fan_power * m_W_dot_net / 1000.0; // [MWe] - // Structure for design parameters that are independent of cycle design solution - C_CO2_to_air_cooler::S_des_par_ind s_air_cooler_des_par_ind; - s_air_cooler_des_par_ind.m_T_amb_des = m_T_amb_des; // [K] - s_air_cooler_des_par_ind.m_elev = m_elevation; // [m] - s_air_cooler_des_par_ind.m_eta_fan = m_eta_fan; // [-] - s_air_cooler_des_par_ind.m_N_nodes_pass = m_N_nodes_pass; // [-] - - if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) - && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) - { - mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, ms_des_par.m_des_tol); - } - } - - // Get 'design_solved' structure from component classes - ms_des_solved.ms_mc_ms_des_solved = *m_mc_ms.get_design_solved(); - ms_des_solved.ms_rc_ms_des_solved = *m_rc_ms.get_design_solved(); - ms_des_solved.ms_t_des_solved = *m_t.get_design_solved(); - ms_des_solved.ms_LTR_des_solved = mc_LT_recup.ms_des_solved; - ms_des_solved.ms_HTR_des_solved = mc_HT_recup.ms_des_solved; - ms_des_solved.ms_mc_air_cooler = *mc_air_cooler.get_design_solved(); - - // Set solved design point metrics - ms_des_solved.m_temp = m_temp_last; - ms_des_solved.m_pres = m_pres_last; - ms_des_solved.m_enth = m_enth_last; - ms_des_solved.m_entr = m_entr_last; - ms_des_solved.m_dens = m_dens_last; - - ms_des_solved.m_eta_thermal = m_eta_thermal_calc_last; - ms_des_solved.m_W_dot_net = m_W_dot_net_last; - ms_des_solved.m_m_dot_mc = m_m_dot_mc; - ms_des_solved.m_m_dot_rc = m_m_dot_rc; - ms_des_solved.m_m_dot_t = m_m_dot_t; - ms_des_solved.m_recomp_frac = m_m_dot_rc / m_m_dot_t; - ms_des_solved.m_bypass_frac = ms_des_par.m_bypass_frac; - - ms_des_solved.m_UA_LTR = ms_des_par.m_LTR_UA; - ms_des_solved.m_UA_HTR = ms_des_par.m_HTR_UA; - - ms_des_solved.m_W_dot_t = m_W_dot_t; //[kWe] - ms_des_solved.m_W_dot_mc = m_W_dot_mc; //[kWe] - ms_des_solved.m_W_dot_rc = m_W_dot_rc; //[kWe] - - ms_des_solved.m_W_dot_cooler_tot = mc_air_cooler.get_design_solved()->m_W_dot_fan * 1.E3; //[kWe] convert from MWe - - -} - - - -// Public Methods - -void C_HTRBypass_Cycle::set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot, - int T_target_is_HTF) -{ - m_T_HTF_PHX_inlet = T_htf_phx_in; // K - m_T_target = T_target; // K - m_T_target_is_HTF = T_target_is_HTF; - m_cp_HTF = cp_htf; // kJ/kg K - m_dT_BP = dT_bp; - m_HTF_PHX_cold_approach = htf_phx_cold_approach; - m_set_HTF_mdot = set_HTF_mdot; - - is_bp_par_set = true; -} - -void C_HTRBypass_Cycle::design(S_design_parameters& des_par_in, int& error_code) -{ - ms_des_par = des_par_in; - - int design_error_code = 0; - - design_core(design_error_code); - - if (design_error_code != 0) - { - error_code = design_error_code; - return; - } - - finalize_design(design_error_code); - - error_code = design_error_code; -} - -void C_HTRBypass_Cycle::opt_design(S_opt_design_parameters& opt_des_par_in, int& error_code) -{ -} - -void C_HTRBypass_Cycle::reset_ms_od_turbo_bal_csp_solved() -{ -} - -int C_HTRBypass_Cycle::auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in) -{ - ms_auto_opt_des_par = auto_opt_des_par_in; - - int auto_opt_des_error_code = 0; - - auto_opt_design_core(auto_opt_des_error_code); - - return auto_opt_des_error_code; -} - - -// Optimize UA ratio, recompression fraction, pressure ratio -double C_HTRBypass_Cycle::design_cycle_return_objective_metric(const std::vector& x) -{ - // 'x' is array of inputs either being adjusted by optimizer or set constant - // Finish defining ms_des_par based on current 'x' values - - int index = 0; - - // Main compressor outlet pressure - if (!ms_opt_des_par.m_fixed_P_mc_out) - { - ms_des_par.m_P_mc_out = x[index]; - if (ms_des_par.m_P_mc_out > m_P_high_limit) - return 0.0; - index++; - } - else - ms_des_par.m_P_mc_out = ms_opt_des_par.m_P_mc_out_guess; - - // Main compressor pressure ratio - double PR_mc_local = -999.9; - double P_mc_in = -999.9; - if (!ms_opt_des_par.m_fixed_PR_HP_to_LP) - { - PR_mc_local = x[index]; - if (PR_mc_local > 50.0) - return -10000000000000.0; - index++; - P_mc_in = ms_des_par.m_P_mc_out / PR_mc_local; - } - else - { - if (ms_opt_des_par.m_PR_HP_to_LP_guess >= 0.0) - { - PR_mc_local = ms_opt_des_par.m_PR_HP_to_LP_guess; - P_mc_in = ms_des_par.m_P_mc_out / PR_mc_local; //[kPa] - } - else - { - P_mc_in = std::abs(ms_opt_des_par.m_PR_HP_to_LP_guess); //[kPa] - } - } - - - if (P_mc_in >= ms_des_par.m_P_mc_out) - return 0.0; - if (P_mc_in <= 100.0) - return 0.0; - ms_des_par.m_P_mc_in = P_mc_in; - - // Recompression fraction - if (!ms_opt_des_par.m_fixed_recomp_frac) - { - ms_des_par.m_recomp_frac = x[index]; - if (ms_des_par.m_recomp_frac < 0.0) - return 0.0; - index++; - } - else - ms_des_par.m_recomp_frac = ms_opt_des_par.m_recomp_frac_guess; - - // Recuperator split fraction - double LT_frac_local = -999.9; - if (!ms_opt_des_par.m_fixed_LT_frac) - { - LT_frac_local = x[index]; - if (LT_frac_local > 1.0 || LT_frac_local < 0.0) - return 0.0; - index++; - } - else - LT_frac_local = ms_opt_des_par.m_LT_frac_guess; - - if (ms_opt_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) - { - ms_des_par.m_LTR_UA = ms_opt_des_par.m_UA_rec_total * LT_frac_local; - ms_des_par.m_HTR_UA = ms_opt_des_par.m_UA_rec_total * (1.0 - LT_frac_local); - } - else - { - ms_des_par.m_LTR_UA = ms_opt_des_par.m_LTR_UA; //[kW/K] - ms_des_par.m_HTR_UA = ms_opt_des_par.m_HTR_UA; //[kW/K] - } - - int error_code = 0; - - design_core(error_code); - - - // Set Objective - double objective_metric = -10000000000.0; - if (error_code == 0) - { - double eff = m_eta_thermal_calc_last; - - // If fixed bypass fraction, no penalty function - double penalty = 0; - if (ms_opt_des_par.m_fixed_bypass_frac == false || ms_opt_des_par.m_des_objective_type == 2) - { - double temp_calc = 0; - double span = 0; - - if (m_T_target_is_HTF == 0) - { - temp_calc = m_temp_last[MIXER_OUT]; - span = m_temp_last[TURB_IN] - m_T_target; - } - else - { - temp_calc = m_T_HTF_BP_outlet_calc; - span = m_T_HTF_PHX_inlet - m_T_target; - } - - /*double target_bp_out = m_T_HTF_BP_outlet_target; - double calc_bp_out = m_T_HTF_BP_outlet_calc; - - double temp_err = std::abs(calc_bp_out - target_bp_out); - double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; - double percent_err = temp_err / temp_span; - - penalty = 10.0 * (100.0 * sigmoid(percent_err) - 0.5);*/ - penalty = calc_penalty(m_T_target, temp_calc, span); - } - - objective_metric = eff - penalty; - - if (objective_metric > m_objective_metric_opt) - { - ms_des_par_optimal = ms_des_par; - m_objective_metric_opt = objective_metric; - } - } - - return objective_metric; -} - -// Optimize bypass fraction (only) -double C_HTRBypass_Cycle::design_bypass_frac_return_objective_metric(const std::vector& x) -{ - ms_des_par.m_bypass_frac = x[0]; - - int error_code = 0; - - design_core_standard(error_code); - - double objective_metric = -10000000000.0; - if (error_code == 0) - { - double temp_calc = 0; - double span = 0; - - if (m_T_target_is_HTF == 0) - { - temp_calc = m_temp_last[MIXER_OUT]; - span = m_temp_last[TURB_IN] - m_T_target; - } - else - { - temp_calc = m_T_HTF_BP_outlet_calc; - span = m_T_HTF_PHX_inlet - m_T_target; - } - - /*double eff = m_eta_thermal_calc_last; - - double target_bp_out = m_T_HTF_BP_outlet_target; - double calc_bp_out = m_T_HTF_BP_outlet_calc; - - double temp_err = std::abs(calc_bp_out - target_bp_out); - double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; - double percent_err = temp_err / temp_span;*/ - - //double penalty = std::pow(percent_err, 2.0); - - //objective_metric = 0 - logit(percent_err); - //objective_metric = -temp_err; - - // Adjust sigmoid - objective_metric = calc_penalty(m_T_target, temp_calc, span); - - if (objective_metric > m_objective_metric_bypass_frac_opt) - { - ms_des_par_bp_frac_optimal = ms_des_par; - m_objective_metric_bypass_frac_opt = objective_metric; - } - } - - return objective_metric; -} - -// Optimize bypass fraction and internally, the other free variables -double C_HTRBypass_Cycle::design_bypass_frac_free_var_return_objective_metric(const std::vector& x) -{ - ms_opt_des_par.m_bypass_frac_guess = x[0]; - - int error_code = 0; - - opt_design_core(error_code); - - // Returns ms_des_par_optimal as optimal parameters - - ms_des_par = ms_des_par_optimal; - design_core_standard(error_code); - - double objective_metric = -10000000000.0; - if (error_code == 0) - { - // Set Objective - double objective_metric = -10000000000.0; - if (error_code == 0) - { - double eff = m_eta_thermal_calc_last; - - // If fixed bypass fraction, no penalty function - double penalty = 0; - if (ms_opt_des_par.m_fixed_bypass_frac == false || ms_opt_des_par.m_des_objective_type == 2) - { - double temp_calc = 0; - double span = 0; - - if (m_T_target_is_HTF == 0) - { - temp_calc = m_temp_last[MIXER_OUT]; - span = m_temp_last[TURB_IN] - m_T_target; - } - else - { - temp_calc = m_T_HTF_BP_outlet_calc; - span = m_T_HTF_PHX_inlet - m_T_target; - } - - /*double target_bp_out = m_T_HTF_BP_outlet_target; - double calc_bp_out = m_T_HTF_BP_outlet_calc; - - double temp_err = std::abs(calc_bp_out - target_bp_out); - double temp_span = m_T_HTF_PHX_inlet - m_T_HTF_BP_outlet_target; - double percent_err = temp_err / temp_span; - - penalty = 10.0 * (100.0 * sigmoid(percent_err) - 0.5);*/ - - penalty = calc_penalty(m_T_target, temp_calc, span); - } - - objective_metric = eff - penalty; - - if (objective_metric > m_objective_metric_full_auto_opt) - { - ms_des_par_full_auto_opt = ms_des_par; - m_objective_metric_full_auto_opt = objective_metric; - } - } - } - - return objective_metric; -} - - - - - - - - - - - - - - - - - - - - - - - - - - - -double nlopt_cb_opt_htr_bypass_des(const std::vector& x, std::vector& grad, void* data) -{ - C_HTRBypass_Cycle* frame = static_cast(data); - if (frame != NULL) - return frame->design_cycle_return_objective_metric(x); - else - return 0.0; -} - -double nlopt_cb_opt_bypass_frac_des(const std::vector& x, std::vector& grad, void* data) -{ - C_HTRBypass_Cycle* frame = static_cast(data); - if (frame != NULL) - return frame->design_bypass_frac_return_objective_metric(x); - else - return 0.0; -} - -double nlopt_cb_opt_bypass_frac_free_var(const std::vector& x, std::vector& grad, void* data) -{ - C_HTRBypass_Cycle* frame = static_cast(data); - if (frame != NULL) - return frame->design_bypass_frac_free_var_return_objective_metric(x); - else - return 0.0; -} double sigmoid(const double val) diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index e6360aa661..e1ee731351 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -268,6 +268,7 @@ class C_sco2_htrbp_core void SetInputs(S_sco2_htrbp_in inputs) { m_inputs = inputs; }; int Solve(); int FinalizeDesign(C_sco2_cycle_core::S_design_solved& design_solved); + void Reset(); }; @@ -421,101 +422,28 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core S_sco2_htrbp_in m_optimal_inputs_internal_only; double m_opt_obj_internal_only; - // END new refactor fields and methods - - // Component classes - C_turbine m_t; - C_comp_multi_stage m_mc_ms; - C_comp_multi_stage m_rc_ms; - C_HeatExchanger m_PHX, m_PC, m_BPX; - - C_HX_co2_to_co2_CRM mc_LT_recup; - C_HX_co2_to_co2_CRM mc_HT_recup; - - C_CO2_to_air_cooler mc_air_cooler; - // Input/Ouput structures for class methods - S_design_parameters ms_des_par; S_opt_design_parameters ms_opt_des_par; - - - // Results from last 'design' solution - std::vector m_temp_last, m_pres_last, m_enth_last, m_entr_last, m_dens_last; // thermodynamic states (K, kPa, kJ/kg, kJ/kg-K, kg/m3) - double m_eta_thermal_calc_last; - double m_W_dot_net_last; - double m_m_dot_mc, m_m_dot_rc, m_m_dot_t; - double m_Q_dot_PHX; - double m_W_dot_mc, m_W_dot_rc, m_W_dot_t, m_W_dot_mc_bypass; - double m_objective_metric_last; - double m_objective_metric_bypass_frac_last; - - // Structures and data for optimization - S_design_parameters ms_des_par_optimal; - double m_objective_metric_opt; - double m_objective_metric_bypass_frac_opt; - - S_design_parameters ms_des_par_bp_frac_optimal; - - // Structures and data for auto-optimization - double m_objective_metric_auto_opt; - S_design_parameters ms_des_par_auto_opt; - - S_design_parameters ms_des_par_full_auto_opt; - double m_objective_metric_full_auto_opt = 0; - - // NEW Internal Variables - double m_w_t; // kJ/kg - double m_w_mc; // kJ/kg - double m_w_rc; // kJ/kg - double m_Q_dot_LT, m_Q_dot_HT; - double m_Q_dot_LTR_LP, m_Q_dot_LTR_HP, m_Q_dot_HTR_LP, m_Q_dot_HTR_HP; - double m_m_dot_bp; - double m_m_dot_htr_hp; - double m_cp_HTF; // kJ/kg K - double m_m_dot_HTF; // kg/s - double m_Q_dot_BP; - double m_T_HTF_PHX_inlet; - double m_T_target; - int m_T_target_is_HTF; - double m_T_HTF_BP_outlet_calc; - double m_T_HTF_PHX_out; - double m_dT_BP; // BYPASS_OUT - HTR_HP_OUT - double m_set_HTF_mdot; - double m_Q_dot_total; - double m_HTF_BP_cold_approach; - double m_HTF_PHX_cold_approach; - bool is_bp_par_set = false; - double m_W_dot_air_cooler; - double m_Q_dot_air_cooler; - C_HX_co2_to_htf c_phx; - C_HX_co2_to_htf c_bp; // Bypass Heat Exchanger - - - // New opt - bool m_found_opt; - double m_eta_phx_max; - double m_UA_diff_eta_max; - double m_over_deltaP_eta_max; - - void design_core(int& error_code); - - void design_core_standard(int& error_code); - void opt_design_core(int& error_code); void auto_opt_design_core(int& error_code); - void finalize_design(int& error_code); + // Bypass Specific HTF variables + int m_T_target_is_HTF; + double m_T_target; + double m_T_HTF_PHX_inlet; + double m_set_HTF_mdot; + double m_HTF_PHX_cold_approach; + double m_dT_BP; + double m_cp_HTF; + bool is_bp_par_set; + // Optimal htrbp core class (contains all results and component data) + C_sco2_htrbp_core m_optimal_htrbp_core; // Added - int solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out); - int solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_LP_out); double calc_penalty(double target, double calc, double span); - - std::string make_result_csv_string(); - public: C_HTRBypass_Cycle(C_sco2_cycle_core::E_turbo_gen_motor_config turbo_gen_motor_config, @@ -547,7 +475,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core N_nodes_pass, T_amb_des, elevation) { - m_temp_last.resize(END_SCO2_STATES); + /*m_temp_last.resize(END_SCO2_STATES); std::fill(m_temp_last.begin(), m_temp_last.end(), std::numeric_limits::quiet_NaN()); m_pres_last = m_enth_last = m_entr_last = m_dens_last = m_temp_last; @@ -559,7 +487,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core m_W_dot_net_last = std::numeric_limits::quiet_NaN(); m_objective_metric_opt = std::numeric_limits::quiet_NaN(); - m_objective_metric_auto_opt = std::numeric_limits::quiet_NaN(); + m_objective_metric_auto_opt = std::numeric_limits::quiet_NaN();*/ } @@ -574,9 +502,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core ~C_HTRBypass_Cycle() {}; - void design(S_design_parameters& des_par_in, int& error_code); - - void opt_design(S_opt_design_parameters& opt_des_par_in, int& error_code); + void reset_ms_od_turbo_bal_csp_solved(); @@ -584,61 +510,11 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core - // Called by 'nlopt_callback_opt_des_1', so needs to be public - double design_cycle_return_objective_metric(const std::vector& x); - - // Called by 'nlopt_callback_opt_des_1', so needs to be public - double design_bypass_frac_return_objective_metric(const std::vector& x); - - double design_bypass_frac_free_var_return_objective_metric(const std::vector& x); double C_HTRBypass_Cycle::opt_cycle_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); - class C_mono_htr_bypass_LTR_des : public C_monotonic_equation - { - private: - C_HTRBypass_Cycle *m_htr_bypass_cycle; - - public: - C_mono_htr_bypass_LTR_des(C_HTRBypass_Cycle* htr_bypass_cycle) - { - m_htr_bypass_cycle = htr_bypass_cycle; - } - - virtual int operator()(double T_LTR_LP_OUT_guess /*K*/, double* diff_T_LTR_LP_out /*K*/); - }; - - class C_mono_htr_bypass_HTR_des : public C_monotonic_equation - { - private: - C_HTRBypass_Cycle *m_htr_bypass_cycle; - - public: - C_mono_htr_bypass_HTR_des(C_HTRBypass_Cycle* htr_bypass_cycle) - { - m_htr_bypass_cycle = htr_bypass_cycle; - } - - virtual int operator()(double T_HTR_LP_OUT_guess /*K*/, double* diff_T_HTR_LP_out /*K*/); - }; - - class C_mono_htr_bypass_BP_des : public C_monotonic_equation - { - private: - C_HTRBypass_Cycle* m_htr_bypass_cycle; - - public: - C_mono_htr_bypass_BP_des(C_HTRBypass_Cycle* htr_bypass_cycle) - { - m_htr_bypass_cycle = htr_bypass_cycle; - } - - virtual int operator()(double bp_frac_guess, double* diff_bp_frac); - }; - - // Unused @@ -673,7 +549,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core const C_comp_multi_stage::S_od_solved* get_rc_od_solved() { - return m_rc_ms.get_od_solved(); + return m_optimal_htrbp_core.m_outputs.m_rc_ms.get_od_solved(); + //return m_rc_ms.get_od_solved(); } /*const S_od_turbo_bal_csp_solved* get_od_turbo_bal_csp_solved() From 8fe848d00f5235cc2e432c7e4c61d8349e1c9e23 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Sun, 10 Mar 2024 22:28:35 -0600 Subject: [PATCH 40/94] Reorganize code. Add initialization to htf inputs. --- tcs/sco2_htrbypass_cycle.cpp | 716 ++++++++++++++++++----------------- tcs/sco2_htrbypass_cycle.h | 68 +--- 2 files changed, 381 insertions(+), 403 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 9f39ce0227..39a7e59bbd 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -832,7 +832,140 @@ void C_sco2_htrbp_core::Reset() // ********************************************************************************** END C_sco2_htrbp_core -// ********************************************************************************** ADDED Refactored opt methods +// ********************************************************************************** PRIVATE C_HTRBypass_Cycle (: C_sco2_cycle_core) + +void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) +{ + // Reset optimal htrbp model + m_optimal_htrbp_core.Reset(); + + // COPY Values (TODO) + { + // Check that simple/recomp flag is set + if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && + ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) + { + throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" + " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); + } + + // map 'auto_opt_des_par_in' to 'ms_auto_opt_des_par' + + // LTR thermal design + ms_opt_des_par.m_LTR_target_code = ms_auto_opt_des_par.m_LTR_target_code; //[-] + ms_opt_des_par.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; //[kW/K] + ms_opt_des_par.m_LTR_min_dT = ms_auto_opt_des_par.m_LTR_min_dT; //[K] + ms_opt_des_par.m_LTR_eff_target = ms_auto_opt_des_par.m_LTR_eff_target; //[-] + ms_opt_des_par.m_LTR_eff_max = ms_auto_opt_des_par.m_LTR_eff_max; //[-] + ms_opt_des_par.m_LTR_od_UA_target_type = ms_auto_opt_des_par.m_LTR_od_UA_target_type; + // HTR thermal design + ms_opt_des_par.m_HTR_target_code = ms_auto_opt_des_par.m_HTR_target_code; //[-] + ms_opt_des_par.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; //[kW/K] + ms_opt_des_par.m_HTR_min_dT = ms_auto_opt_des_par.m_HTR_min_dT; //[K] + ms_opt_des_par.m_HTR_eff_target = ms_auto_opt_des_par.m_HTR_eff_target; //[-] + ms_opt_des_par.m_HTR_eff_max = ms_auto_opt_des_par.m_HTR_eff_max; + ms_opt_des_par.m_HTR_od_UA_target_type = ms_auto_opt_des_par.m_HTR_od_UA_target_type; + // + ms_opt_des_par.m_UA_rec_total = ms_auto_opt_des_par.m_UA_rec_total; + ms_opt_des_par.m_des_tol = ms_auto_opt_des_par.m_des_tol; + ms_opt_des_par.m_des_opt_tol = ms_auto_opt_des_par.m_des_opt_tol; + + ms_opt_des_par.m_is_des_air_cooler = ms_auto_opt_des_par.m_is_des_air_cooler; //[-] + + ms_opt_des_par.m_des_objective_type = ms_auto_opt_des_par.m_des_objective_type; //[-] + ms_opt_des_par.m_min_phx_deltaT = ms_auto_opt_des_par.m_min_phx_deltaT; //[C] + + ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] + + ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] + } + + // LOOK AT P MC OUT + double best_P_high = m_P_high_limit; //[kPa] + double PR_mc_guess = 2.5; //[-] + if (!ms_opt_des_par.m_fixed_P_mc_out) + { + double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] + + //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); + best_P_high = m_P_high_limit; // TEMPORARY + + // If this runs, it should set: + // ms_des_par_auto_opt + // m_objective_metric_auto_opt + // So we can update pressure ratio guess + //double PR_mc_guess_calc = ms_des_par_auto_opt.m_P_mc_out / ms_des_par_auto_opt.m_P_mc_in; + // + //if (std::isfinite(PR_mc_guess_calc)) { + // PR_mc_guess = PR_mc_guess_calc; + //} + //else { + // best_P_high = m_P_high_limit; //[kPa] + //} + } + + // Complete 'ms_opt_des_par' for recompression cycle + ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] + ms_opt_des_par.m_fixed_P_mc_out = true; + + if (ms_opt_des_par.m_fixed_PR_HP_to_LP) + { + ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + } + else + { + ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] + } + + // Is recompression fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) + { // fixed + ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); + ms_opt_des_par.m_fixed_recomp_frac = true; + } + else + { // optimized + ms_opt_des_par.m_recomp_frac_guess = 0.3; + ms_opt_des_par.m_fixed_recomp_frac = false; + } + + // Is bypass fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0.0) + { // fixed + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + ms_opt_des_par.m_fixed_bypass_frac = true; + } + else + { // optimized + ms_opt_des_par.m_bypass_frac_guess = 0.3; + ms_opt_des_par.m_fixed_bypass_frac = false; + } + + ms_opt_des_par.m_LT_frac_guess = 0.5; + ms_opt_des_par.m_fixed_LT_frac = false; + + if (ms_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + ms_opt_des_par.m_fixed_LT_frac = true; + } + + // Find optimal inputs + S_sco2_htrbp_in optimal_inputs; + error_code = optimize_cycle(ms_auto_opt_des_par, ms_opt_des_par, optimal_inputs); + + if (error_code != 0) + return; + + // Run Optimal Case + m_optimal_htrbp_core.SetInputs(optimal_inputs); + error_code = m_optimal_htrbp_core.Solve(); + + if (error_code != 0) + return; + + // Finalize Design (pass in reference to solved parameters) + error_code = m_optimal_htrbp_core.FinalizeDesign(ms_des_solved); +} /// /// Optimize cycle (bypass outer loop, which calls inner loop for other design variables) @@ -1124,84 +1257,237 @@ int C_HTRBypass_Cycle::opt_nonbp_par(const S_auto_opt_design_parameters& auto_pa return error_code; } - /// -/// Objective Function for BYPASS optimization (calls internal optimization for other variables) +/// Take x inputs from optimizer results, write appropriate values to S_sco2_htrbp_in /// -/// -/// -/// -/// -/// -double C_HTRBypass_Cycle::opt_cycle_return_objective_metric(const std::vector& x, - const S_auto_opt_design_parameters& auto_par, - const S_opt_design_parameters& opt_par, - C_sco2_htrbp_core& htrbp_core) +int C_HTRBypass_Cycle::x_to_inputs(const std::vector& x, + const S_auto_opt_design_parameters auto_par, + const S_opt_design_parameters opt_par, + S_sco2_htrbp_in &core_inputs) { - if (opt_par.m_fixed_bypass_frac == true) - { - throw std::exception("Optimizing bypass fraction even though it is fixed"); - } - - // Set Bypass Fraction - htrbp_core.m_inputs.m_bypass_frac = x[0]; + // 'x' is array of inputs either being adjusted by optimizer or set constant + // Finish defining core_inputs based on current 'x' values - // Optimize all other variables - S_sco2_htrbp_in optimal_inputs_case; - opt_nonbp_par(auto_par, opt_par, htrbp_core.m_inputs, optimal_inputs_case); + int error_message = 0; + int index = 0; - // ^ Get optimal core_inputs from here + // Main compressor outlet pressure - // Run Optimal Case, return objective function + if (!auto_par.m_fixed_P_mc_out) + { + double P_mc_out = x[index]; + if (P_mc_out > m_P_high_limit) + return -1; + index++; - htrbp_core.SetInputs(optimal_inputs_case); - int error_code = htrbp_core.Solve(); - if (error_code != 0) - return -100000000000000000; + // assign P_mc_out + core_inputs.m_P_mc_out = P_mc_out; + } - double eff = htrbp_core.m_outputs.m_eta_thermal; - // If variable bypass fraction or targeting temperature - double penalty = 0; - if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) + // Main compressor pressure ratio + double PR_mc_local = -999.9; + double P_mc_in = -999.9; + if (!opt_par.m_fixed_PR_HP_to_LP) { - double temp_calc = 0; - double span = 0; - - if (m_T_target_is_HTF == 0) + PR_mc_local = x[index]; + if (PR_mc_local > 50.0) + return -1; + index++; + P_mc_in = core_inputs.m_P_mc_out / PR_mc_local; + } + else + { + if (opt_par.m_PR_HP_to_LP_guess >= 0.0) { - temp_calc = htrbp_core.m_outputs.m_temp[MIXER_OUT]; - span = htrbp_core.m_outputs.m_temp[TURB_IN] - m_T_target; + PR_mc_local = opt_par.m_PR_HP_to_LP_guess; + P_mc_in = core_inputs.m_P_mc_out / PR_mc_local; //[kPa] } else { - temp_calc = htrbp_core.m_outputs.m_T_HTF_BP_outlet; - span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; + P_mc_in = std::abs(opt_par.m_PR_HP_to_LP_guess); //[kPa] } - - penalty = calc_penalty(m_T_target, temp_calc, span); } - double obj = eff - penalty; - - if (obj > m_opt_obj_internal_only) + if (P_mc_in >= core_inputs.m_P_mc_out) + return -1; + if (P_mc_in <= 100.0) + return -1; + + core_inputs.m_P_mc_in = P_mc_in; + + // Recompression fraction + if (!opt_par.m_fixed_recomp_frac) { - m_opt_obj_internal_only = obj; - m_optimal_inputs_internal_only = optimal_inputs_case; + core_inputs.m_recomp_frac = x[index]; + if (core_inputs.m_recomp_frac < 0.0) + return -1; + index++; } - // Reset htrbp_core - htrbp_core.m_inputs.m_bypass_frac = std::numeric_limits::quiet_NaN(); - htrbp_core.m_outputs.Init(); + // Recuperator split fraction + double LT_frac_local = -999.9; + double LTR_UA, HTR_UA; + if (!opt_par.m_fixed_LT_frac) + { + LT_frac_local = x[index]; + if (LT_frac_local > 1.0 || LT_frac_local < 0.0) + return -1; + index++; - return obj; -} + if (auto_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || auto_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + LTR_UA = auto_par.m_UA_rec_total * LT_frac_local; + HTR_UA = auto_par.m_UA_rec_total * (1.0 - LT_frac_local); + + // ASSIGN LTR_UA and HTR_UA + core_inputs.m_LTR_UA = LTR_UA; + core_inputs.m_HTR_UA = HTR_UA; + } + } + return 0; +} /// -/// Objective Function for NON Bypass optimization +/// Set Optimized Variables to NaN, to save them from misuse /// -/// ONLY Objective Value +int C_HTRBypass_Cycle::clear_x_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in& core_inputs) +{ + // 'x' is array of inputs either being adjusted by optimizer or set constant + // Finish defining core_inputs based on current 'x' values + + int error_message = 0; + int index = 0; + + // Main compressor outlet pressure + + if (!auto_par.m_fixed_P_mc_out) + { + core_inputs.m_P_mc_out = std::numeric_limits::quiet_NaN(); + } + + + core_inputs.m_P_mc_in = std::numeric_limits::quiet_NaN(); + + // Recompression fraction + if (!opt_par.m_fixed_recomp_frac) + { + core_inputs.m_recomp_frac = std::numeric_limits::quiet_NaN(); + } + + // Recuperator split fraction + if (!opt_par.m_fixed_LT_frac) + { + if (auto_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || auto_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + // ASSIGN LTR_UA and HTR_UA + core_inputs.m_LTR_UA = std::numeric_limits::quiet_NaN();; + core_inputs.m_HTR_UA = std::numeric_limits::quiet_NaN();; + } + } + + return 0; +} + + + + +// ********************************************************************************* END PRIVATE methods + +// ********************************************************************************** PUBLIC C_HTRBypass_Cycle (: C_sco2_cycle_core) + +void C_HTRBypass_Cycle::set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot, + int T_target_is_HTF) +{ + m_T_HTF_PHX_inlet = T_htf_phx_in; // K + m_T_target = T_target; // K + m_T_target_is_HTF = T_target_is_HTF; + m_cp_HTF = cp_htf; // kJ/kg K + m_dT_BP = dT_bp; + m_HTF_PHX_cold_approach = htf_phx_cold_approach; + m_set_HTF_mdot = set_HTF_mdot; + + m_is_bp_par_set = true; +} + + +/// +/// Objective Function for BYPASS optimization (calls internal optimization for other variables) +/// +/// +/// +/// +/// +/// +double C_HTRBypass_Cycle::opt_cycle_return_objective_metric(const std::vector& x, + const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + C_sco2_htrbp_core& htrbp_core) +{ + if (opt_par.m_fixed_bypass_frac == true) + { + throw std::exception("Optimizing bypass fraction even though it is fixed"); + } + + // Set Bypass Fraction + htrbp_core.m_inputs.m_bypass_frac = x[0]; + + // Optimize all other variables + S_sco2_htrbp_in optimal_inputs_case; + opt_nonbp_par(auto_par, opt_par, htrbp_core.m_inputs, optimal_inputs_case); + + // ^ Get optimal core_inputs from here + + // Run Optimal Case, return objective function + + htrbp_core.SetInputs(optimal_inputs_case); + int error_code = htrbp_core.Solve(); + if (error_code != 0) + return -100000000000000000; + + double eff = htrbp_core.m_outputs.m_eta_thermal; + + // If variable bypass fraction or targeting temperature + double penalty = 0; + if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) + { + double temp_calc = 0; + double span = 0; + + if (m_T_target_is_HTF == 0) + { + temp_calc = htrbp_core.m_outputs.m_temp[MIXER_OUT]; + span = htrbp_core.m_outputs.m_temp[TURB_IN] - m_T_target; + } + else + { + temp_calc = htrbp_core.m_outputs.m_T_HTF_BP_outlet; + span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; + } + + penalty = calc_penalty(m_T_target, temp_calc, span); + } + + double obj = eff - penalty; + + if (obj > m_opt_obj_internal_only) + { + m_opt_obj_internal_only = obj; + m_optimal_inputs_internal_only = optimal_inputs_case; + } + + // Reset htrbp_core + htrbp_core.m_inputs.m_bypass_frac = std::numeric_limits::quiet_NaN(); + htrbp_core.m_outputs.Init(); + + return obj; +} + +/// +/// Objective Function for NON Bypass optimization +/// +/// ONLY Objective Value double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, @@ -1255,141 +1541,45 @@ double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vecto // Clear Optimized Inputs clear_x_inputs(x, auto_par, opt_par, htrbp_core.m_inputs); - + return objective_metric; } -/// -/// Take x inputs from optimizer results, write appropriate values to S_sco2_htrbp_in -/// -int C_HTRBypass_Cycle::x_to_inputs(const std::vector& x, - const S_auto_opt_design_parameters auto_par, - const S_opt_design_parameters opt_par, - S_sco2_htrbp_in &core_inputs) +double C_HTRBypass_Cycle::calc_penalty(double target, double calc, double span) { - // 'x' is array of inputs either being adjusted by optimizer or set constant - // Finish defining core_inputs based on current 'x' values - - int error_message = 0; - int index = 0; - - // Main compressor outlet pressure - - if (!auto_par.m_fixed_P_mc_out) - { - double P_mc_out = x[index]; - if (P_mc_out > m_P_high_limit) - return -1; - index++; - - // assign P_mc_out - core_inputs.m_P_mc_out = P_mc_out; - } - - - // Main compressor pressure ratio - double PR_mc_local = -999.9; - double P_mc_in = -999.9; - if (!opt_par.m_fixed_PR_HP_to_LP) - { - PR_mc_local = x[index]; - if (PR_mc_local > 50.0) - return -1; - index++; - P_mc_in = core_inputs.m_P_mc_out / PR_mc_local; - } - else - { - if (opt_par.m_PR_HP_to_LP_guess >= 0.0) - { - PR_mc_local = opt_par.m_PR_HP_to_LP_guess; - P_mc_in = core_inputs.m_P_mc_out / PR_mc_local; //[kPa] - } - else - { - P_mc_in = std::abs(opt_par.m_PR_HP_to_LP_guess); //[kPa] - } - } - - if (P_mc_in >= core_inputs.m_P_mc_out) - return -1; - if (P_mc_in <= 100.0) - return -1; - - core_inputs.m_P_mc_in = P_mc_in; + double percent_error = std::abs(target - calc) / span; + double penalty = 10.0 * (100.0 * sigmoid(percent_error) - 0.5); - // Recompression fraction - if (!opt_par.m_fixed_recomp_frac) - { - core_inputs.m_recomp_frac = x[index]; - if (core_inputs.m_recomp_frac < 0.0) - return -1; - index++; - } + return penalty; +} - // Recuperator split fraction - double LT_frac_local = -999.9; - double LTR_UA, HTR_UA; - if (!opt_par.m_fixed_LT_frac) - { - LT_frac_local = x[index]; - if (LT_frac_local > 1.0 || LT_frac_local < 0.0) - return -1; - index++; +int C_HTRBypass_Cycle::auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in) +{ + ms_auto_opt_des_par = auto_opt_des_par_in; - if (auto_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || auto_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) - { - LTR_UA = auto_par.m_UA_rec_total * LT_frac_local; - HTR_UA = auto_par.m_UA_rec_total * (1.0 - LT_frac_local); + int auto_opt_des_error_code = 0; - // ASSIGN LTR_UA and HTR_UA - core_inputs.m_LTR_UA = LTR_UA; - core_inputs.m_HTR_UA = HTR_UA; - } - } + auto_opt_design_core(auto_opt_des_error_code); - return 0; + return auto_opt_des_error_code; } -/// -/// Set Optimized Variables to NaN, to save them from misuse -/// -int C_HTRBypass_Cycle::clear_x_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in& core_inputs) +int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg) { - // 'x' is array of inputs either being adjusted by optimizer or set constant - // Finish defining core_inputs based on current 'x' values + return 0; +} - int error_message = 0; - int index = 0; - // Main compressor outlet pressure - if (!auto_par.m_fixed_P_mc_out) - { - core_inputs.m_P_mc_out = std::numeric_limits::quiet_NaN(); - } - core_inputs.m_P_mc_in = std::numeric_limits::quiet_NaN(); +// END legacy functions - // Recompression fraction - if (!opt_par.m_fixed_recomp_frac) - { - core_inputs.m_recomp_frac = std::numeric_limits::quiet_NaN(); - } +// Public Methods - // Recuperator split fraction - if (!opt_par.m_fixed_LT_frac) - { - if (auto_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || auto_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) - { - // ASSIGN LTR_UA and HTR_UA - core_inputs.m_LTR_UA = std::numeric_limits::quiet_NaN();; - core_inputs.m_HTR_UA = std::numeric_limits::quiet_NaN();; - } - } - return 0; +void C_HTRBypass_Cycle::reset_ms_od_turbo_bal_csp_solved() +{ } double nlopt_opt_cycle_func(const std::vector& x, std::vector& grad, void* data) @@ -1426,189 +1616,6 @@ double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector 0 && - ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) - { - throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" - " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); - } - - // map 'auto_opt_des_par_in' to 'ms_auto_opt_des_par' - - // LTR thermal design - ms_opt_des_par.m_LTR_target_code = ms_auto_opt_des_par.m_LTR_target_code; //[-] - ms_opt_des_par.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; //[kW/K] - ms_opt_des_par.m_LTR_min_dT = ms_auto_opt_des_par.m_LTR_min_dT; //[K] - ms_opt_des_par.m_LTR_eff_target = ms_auto_opt_des_par.m_LTR_eff_target; //[-] - ms_opt_des_par.m_LTR_eff_max = ms_auto_opt_des_par.m_LTR_eff_max; //[-] - ms_opt_des_par.m_LTR_od_UA_target_type = ms_auto_opt_des_par.m_LTR_od_UA_target_type; - // HTR thermal design - ms_opt_des_par.m_HTR_target_code = ms_auto_opt_des_par.m_HTR_target_code; //[-] - ms_opt_des_par.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; //[kW/K] - ms_opt_des_par.m_HTR_min_dT = ms_auto_opt_des_par.m_HTR_min_dT; //[K] - ms_opt_des_par.m_HTR_eff_target = ms_auto_opt_des_par.m_HTR_eff_target; //[-] - ms_opt_des_par.m_HTR_eff_max = ms_auto_opt_des_par.m_HTR_eff_max; - ms_opt_des_par.m_HTR_od_UA_target_type = ms_auto_opt_des_par.m_HTR_od_UA_target_type; - // - ms_opt_des_par.m_UA_rec_total = ms_auto_opt_des_par.m_UA_rec_total; - ms_opt_des_par.m_des_tol = ms_auto_opt_des_par.m_des_tol; - ms_opt_des_par.m_des_opt_tol = ms_auto_opt_des_par.m_des_opt_tol; - - ms_opt_des_par.m_is_des_air_cooler = ms_auto_opt_des_par.m_is_des_air_cooler; //[-] - - ms_opt_des_par.m_des_objective_type = ms_auto_opt_des_par.m_des_objective_type; //[-] - ms_opt_des_par.m_min_phx_deltaT = ms_auto_opt_des_par.m_min_phx_deltaT; //[C] - - ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] - - ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] - } - - // LOOK AT P MC OUT - double best_P_high = m_P_high_limit; //[kPa] - double PR_mc_guess = 2.5; //[-] - if (!ms_opt_des_par.m_fixed_P_mc_out) - { - double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] - - //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); - best_P_high = m_P_high_limit; // TEMPORARY - - // If this runs, it should set: - // ms_des_par_auto_opt - // m_objective_metric_auto_opt - // So we can update pressure ratio guess - //double PR_mc_guess_calc = ms_des_par_auto_opt.m_P_mc_out / ms_des_par_auto_opt.m_P_mc_in; - // - //if (std::isfinite(PR_mc_guess_calc)) { - // PR_mc_guess = PR_mc_guess_calc; - //} - //else { - // best_P_high = m_P_high_limit; //[kPa] - //} - } - - // Complete 'ms_opt_des_par' for recompression cycle - ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] - ms_opt_des_par.m_fixed_P_mc_out = true; - - if (ms_opt_des_par.m_fixed_PR_HP_to_LP) - { - ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] - } - else - { - ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] - } - - // Is recompression fraction fixed or optimized? - if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) - { // fixed - ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); - ms_opt_des_par.m_fixed_recomp_frac = true; - } - else - { // optimized - ms_opt_des_par.m_recomp_frac_guess = 0.3; - ms_opt_des_par.m_fixed_recomp_frac = false; - } - - // Is bypass fraction fixed or optimized? - if (ms_auto_opt_des_par.m_is_bypass_ok <= 0.0) - { // fixed - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - ms_opt_des_par.m_fixed_bypass_frac = true; - } - else - { // optimized - ms_opt_des_par.m_bypass_frac_guess = 0.3; - ms_opt_des_par.m_fixed_bypass_frac = false; - } - - ms_opt_des_par.m_LT_frac_guess = 0.5; - ms_opt_des_par.m_fixed_LT_frac = false; - - if (ms_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) - { - ms_opt_des_par.m_fixed_LT_frac = true; - } - - // Find optimal inputs - S_sco2_htrbp_in optimal_inputs; - error_code = optimize_cycle(ms_auto_opt_des_par, ms_opt_des_par, optimal_inputs); - - if (error_code != 0) - return; - - // Run Optimal Case - m_optimal_htrbp_core.SetInputs(optimal_inputs); - error_code = m_optimal_htrbp_core.Solve(); - - if (error_code != 0) - return; - - // Finalize Design (pass in reference to solved parameters) - error_code = m_optimal_htrbp_core.FinalizeDesign(ms_des_solved); -} - -double C_HTRBypass_Cycle::calc_penalty(double target, double calc, double span) -{ - double percent_error = std::abs(target - calc) / span; - double penalty = 10.0 * (100.0 * sigmoid(percent_error) - 0.5); - - return penalty; -} - -void C_HTRBypass_Cycle::set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot, - int T_target_is_HTF) -{ - m_T_HTF_PHX_inlet = T_htf_phx_in; // K - m_T_target = T_target; // K - m_T_target_is_HTF = T_target_is_HTF; - m_cp_HTF = cp_htf; // kJ/kg K - m_dT_BP = dT_bp; - m_HTF_PHX_cold_approach = htf_phx_cold_approach; - m_set_HTF_mdot = set_HTF_mdot; - - is_bp_par_set = true; -} - - -// END legacy functions - -// Public Methods - - -void C_HTRBypass_Cycle::reset_ms_od_turbo_bal_csp_solved() -{ -} - - - double sigmoid(const double val) { return 1.0 / (1.0 + std::exp(-1.0 * val)); @@ -1657,10 +1664,7 @@ double logit(const double val) -int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg) -{ - return 0; -} + int C_HTRBypass_Cycle::off_design_fix_shaft_speeds(S_od_par& od_phi_par_in, double od_tol) { diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index e1ee731351..cf600310fd 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -417,6 +417,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core int clear_x_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in& core_inputs); + CO2_state mc_co2_props; // Optimal inputs, for bypass optimizer DO NOT USE S_sco2_htrbp_in m_optimal_inputs_internal_only; @@ -425,7 +426,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core // Input/Ouput structures for class methods S_opt_design_parameters ms_opt_des_par; - + void auto_opt_design_core(int& error_code); // Bypass Specific HTF variables @@ -435,8 +436,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_set_HTF_mdot; double m_HTF_PHX_cold_approach; double m_dT_BP; - double m_cp_HTF; - bool is_bp_par_set; + double m_cp_HTF = 0; + bool m_is_bp_par_set; // Optimal htrbp core class (contains all results and component data) C_sco2_htrbp_core m_optimal_htrbp_core; @@ -444,6 +445,9 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core // Added double calc_penalty(double target, double calc, double span); +protected: + + public: C_HTRBypass_Cycle(C_sco2_cycle_core::E_turbo_gen_motor_config turbo_gen_motor_config, @@ -475,50 +479,31 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core N_nodes_pass, T_amb_des, elevation) { - /*m_temp_last.resize(END_SCO2_STATES); - std::fill(m_temp_last.begin(), m_temp_last.end(), std::numeric_limits::quiet_NaN()); - m_pres_last = m_enth_last = m_entr_last = m_dens_last = m_temp_last; - - m_eta_thermal_calc_last = m_m_dot_mc = m_m_dot_rc = m_m_dot_t = std::numeric_limits::quiet_NaN(); - m_Q_dot_PHX = std::numeric_limits::quiet_NaN(); - m_W_dot_mc = m_W_dot_rc = m_W_dot_t = m_W_dot_mc_bypass = std::numeric_limits::quiet_NaN(); - m_objective_metric_last = std::numeric_limits::quiet_NaN(); - - m_W_dot_net_last = std::numeric_limits::quiet_NaN(); - - m_objective_metric_opt = std::numeric_limits::quiet_NaN(); - m_objective_metric_auto_opt = std::numeric_limits::quiet_NaN();*/ + m_T_target = m_T_HTF_PHX_inlet = m_set_HTF_mdot + = m_HTF_PHX_cold_approach = m_dT_BP + = m_cp_HTF + = std::numeric_limits::quiet_NaN(); - + m_is_bp_par_set = false; } - // Set Bypass Specific Parameters - void set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot, - int T_target_is_HTF); - - - - CO2_state mc_co2_props; - ~C_HTRBypass_Cycle() {}; - - - void reset_ms_od_turbo_bal_csp_solved(); - + // Find optimal cycle int auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in); + // Set Bypass Specific Parameters + void set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot, + int T_target_is_HTF); - - + // Objective Functions double C_HTRBypass_Cycle::opt_cycle_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); - double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); - - // Unused + void reset_ms_od_turbo_bal_csp_solved(); + int auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg); int off_design_fix_shaft_speeds(S_od_par& od_phi_par_in, double od_tol /*-*/); @@ -567,23 +552,12 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core }; - -double nlopt_cb_opt_htr_bypass_des(const std::vector& x, std::vector& grad, void* data); - -double nlopt_cb_opt_bypass_frac_des(const std::vector& x, std::vector& grad, void* data); - -double nlopt_cb_opt_bypass_frac_free_var(const std::vector& x, std::vector& grad, void* data); - - -// ADDED +// Nlopt objective functions double nlopt_opt_cycle_func(const std::vector& x, std::vector& grad, void* data); double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector& grad, void* data); - - - - +// Penalty value methods double sigmoid(const double val); double logit(const double val); From c24621d10f01b8919a9dace65447f914ac90eb5a Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Mon, 11 Mar 2024 09:45:58 -0600 Subject: [PATCH 41/94] Clean auto_opt_design_core --- tcs/sco2_htrbypass_cycle.cpp | 158 ++++++++++++----------------------- 1 file changed, 54 insertions(+), 104 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 39a7e59bbd..05f089fd5f 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -839,7 +839,7 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) // Reset optimal htrbp model m_optimal_htrbp_core.Reset(); - // COPY Values (TODO) + // Fill in 'ms_opt_des_par' (Can this be less cumbersome?) { // Check that simple/recomp flag is set if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && @@ -880,84 +880,74 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] } - // LOOK AT P MC OUT - double best_P_high = m_P_high_limit; //[kPa] - double PR_mc_guess = 2.5; //[-] - if (!ms_opt_des_par.m_fixed_P_mc_out) + // Complete 'ms_opt_des_par' for Design Variables { - double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] + double best_P_high = m_P_high_limit; //[kPa] + double PR_mc_guess = 2.5; //[-] + if (!ms_opt_des_par.m_fixed_P_mc_out) + { + double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] - //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); - best_P_high = m_P_high_limit; // TEMPORARY + //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); + best_P_high = m_P_high_limit; + } - // If this runs, it should set: - // ms_des_par_auto_opt - // m_objective_metric_auto_opt - // So we can update pressure ratio guess - //double PR_mc_guess_calc = ms_des_par_auto_opt.m_P_mc_out / ms_des_par_auto_opt.m_P_mc_in; - // - //if (std::isfinite(PR_mc_guess_calc)) { - // PR_mc_guess = PR_mc_guess_calc; - //} - //else { - // best_P_high = m_P_high_limit; //[kPa] - //} - } - // Complete 'ms_opt_des_par' for recompression cycle - ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] - ms_opt_des_par.m_fixed_P_mc_out = true; + ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] + ms_opt_des_par.m_fixed_P_mc_out = true; - if (ms_opt_des_par.m_fixed_PR_HP_to_LP) - { - ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] - } - else - { - ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] - } + if (ms_opt_des_par.m_fixed_PR_HP_to_LP) + { + ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + } + else + { + ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] + } - // Is recompression fraction fixed or optimized? - if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) - { // fixed - ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); - ms_opt_des_par.m_fixed_recomp_frac = true; - } - else - { // optimized - ms_opt_des_par.m_recomp_frac_guess = 0.3; - ms_opt_des_par.m_fixed_recomp_frac = false; - } + // Is recompression fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) + { // fixed + ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); + ms_opt_des_par.m_fixed_recomp_frac = true; + } + else + { // optimized + ms_opt_des_par.m_recomp_frac_guess = 0.3; + ms_opt_des_par.m_fixed_recomp_frac = false; + } - // Is bypass fraction fixed or optimized? - if (ms_auto_opt_des_par.m_is_bypass_ok <= 0.0) - { // fixed - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - ms_opt_des_par.m_fixed_bypass_frac = true; - } - else - { // optimized - ms_opt_des_par.m_bypass_frac_guess = 0.3; - ms_opt_des_par.m_fixed_bypass_frac = false; - } + // Is bypass fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0.0) + { // fixed + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + ms_opt_des_par.m_fixed_bypass_frac = true; + } + else + { // optimized + ms_opt_des_par.m_bypass_frac_guess = 0.3; + ms_opt_des_par.m_fixed_bypass_frac = false; + } - ms_opt_des_par.m_LT_frac_guess = 0.5; - ms_opt_des_par.m_fixed_LT_frac = false; + ms_opt_des_par.m_LT_frac_guess = 0.5; + ms_opt_des_par.m_fixed_LT_frac = false; - if (ms_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) - { - ms_opt_des_par.m_fixed_LT_frac = true; - } + if (ms_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + ms_opt_des_par.m_fixed_LT_frac = true; + } + } + // Find optimal inputs - S_sco2_htrbp_in optimal_inputs; - error_code = optimize_cycle(ms_auto_opt_des_par, ms_opt_des_par, optimal_inputs); + S_sco2_htrbp_in optimal_inputs_out; + error_code = optimize_cycle(ms_auto_opt_des_par, ms_opt_des_par, optimal_inputs_out); if (error_code != 0) return; // Run Optimal Case - m_optimal_htrbp_core.SetInputs(optimal_inputs); + m_optimal_htrbp_core.SetInputs(optimal_inputs_out); error_code = m_optimal_htrbp_core.Solve(); if (error_code != 0) @@ -1350,7 +1340,7 @@ int C_HTRBypass_Cycle::x_to_inputs(const std::vector& x, } /// -/// Set Optimized Variables to NaN, to save them from misuse +/// Set Optimized Variables to NaN, to protect them from misuse /// int C_HTRBypass_Cycle::clear_x_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in& core_inputs) { @@ -1626,46 +1616,6 @@ double logit(const double val) return std::log(val / (1.0 - val)); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int C_HTRBypass_Cycle::off_design_fix_shaft_speeds(S_od_par& od_phi_par_in, double od_tol) { return 0; From 28cec8c8219619cbfb127935314b84ef7a3c631c Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Tue, 12 Mar 2024 11:02:36 -0600 Subject: [PATCH 42/94] Begin adding total UA optimization --- tcs/sco2_htrbypass_cycle.cpp | 471 ++++++++++++++++++++++++++++++++++- tcs/sco2_htrbypass_cycle.h | 8 + 2 files changed, 474 insertions(+), 5 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 05f089fd5f..b79b1cdf2a 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -957,6 +957,12 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) error_code = m_optimal_htrbp_core.FinalizeDesign(ms_des_solved); } +void C_HTRBypass_Cycle::auto_opt_design_hit_eta_core(int& error_code) +{ + +} + + /// /// Optimize cycle (bypass outer loop, which calls inner loop for other design variables) /// @@ -1120,8 +1126,7 @@ int C_HTRBypass_Cycle::optimize_cycle(const S_auto_opt_design_parameters& auto_p // Return optimal input case optimal_inputs_final = optimal_inputs_final_temporary; } - - + optimal_inputs = optimal_inputs_final; return 0; @@ -1380,9 +1385,6 @@ int C_HTRBypass_Cycle::clear_x_inputs(const std::vector& x, const S_auto return 0; } - - - // ********************************************************************************* END PRIVATE methods // ********************************************************************************** PUBLIC C_HTRBypass_Cycle (: C_sco2_cycle_core) @@ -1402,8 +1404,81 @@ void C_HTRBypass_Cycle::set_bp_par(double T_htf_phx_in, double T_target, double } +/// +/// Objective Function for total UA (outermost layer) +/// Total UA -> Bypass Fraction -> pressure, split UA, recomp frac +/// +/// ONLY Objective Value +double C_HTRBypass_Cycle::opt_total_UA_return_objective_metric(const std::vector& x, + const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par + ) +{ + // Copy optimal parameters + S_auto_opt_design_parameters auto_par_internal = auto_par; + S_opt_design_parameters opt_par_internal = opt_par; + + // Assign Total Recuperator UA + double total_UA = x[0]; + auto_par_internal.m_UA_rec_total = total_UA; + opt_par_internal.m_UA_rec_total = total_UA; + + // Optimize all other variables + S_sco2_htrbp_in optimal_inputs_case; + int error_code = optimize_cycle(auto_par_internal, opt_par_internal, optimal_inputs_case); + + if (error_code != 0) + return -100000000000000000; + + // ^ Get optimal core_inputs from here + + // Run Optimal Case, return objective function + C_sco2_htrbp_core htrbp_core; + htrbp_core.SetInputs(optimal_inputs_case); + error_code = htrbp_core.Solve(); + if (error_code != 0) + return -100000000000000000; + + double eff = htrbp_core.m_outputs.m_eta_thermal; + + // If variable bypass fraction or targeting temperature + double penalty = 0; + if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) + { + double temp_calc = 0; + double span = 0; + + if (m_T_target_is_HTF == 0) + { + temp_calc = htrbp_core.m_outputs.m_temp[MIXER_OUT]; + span = htrbp_core.m_outputs.m_temp[TURB_IN] - m_T_target; + } + else + { + temp_calc = htrbp_core.m_outputs.m_T_HTF_BP_outlet; + span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; + } + + penalty = calc_penalty(m_T_target, temp_calc, span); + } + + double obj = eff - penalty; + + if (obj > m_opt_obj_internal_only) + { + m_opt_obj_internal_only = obj; + m_optimal_inputs_internal_only = optimal_inputs_case; + } + + // Reset htrbp_core + htrbp_core.m_outputs.Init(); + + return obj; +} + /// /// Objective Function for BYPASS optimization (calls internal optimization for other variables) +/// Total UA -> Bypass Fraction -> pressure, split UA, recomp frac /// /// /// @@ -1476,6 +1551,7 @@ double C_HTRBypass_Cycle::opt_cycle_return_objective_metric(const std::vector /// Objective Function for NON Bypass optimization +/// Total UA -> Bypass Fraction -> pressure, split UA, recomp frac /// /// ONLY Objective Value double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, @@ -1535,6 +1611,9 @@ double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vecto return objective_metric; } + + + double C_HTRBypass_Cycle::calc_penalty(double target, double calc, double span) { double percent_error = std::abs(target - calc) / span; @@ -1554,8 +1633,373 @@ int C_HTRBypass_Cycle::auto_opt_design(S_auto_opt_design_parameters& auto_opt_de return auto_opt_des_error_code; } + +// This optimizes the TOTAL recuperator UA to hit a specific eta int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg) { + // Fill in 'ms_auto_opt_des_par' from input + { + ms_auto_opt_des_par.m_UA_rec_total = std::numeric_limits::quiet_NaN(); // ***** This method finds the UA required to hit the input efficiency! ***** + // LTR thermal design + ms_auto_opt_des_par.m_LTR_target_code = auto_opt_des_hit_eta_in.m_LTR_target_code; //[-] + ms_auto_opt_des_par.m_LTR_UA = auto_opt_des_hit_eta_in.m_LTR_UA; //[kW/K] + ms_auto_opt_des_par.m_LTR_min_dT = auto_opt_des_hit_eta_in.m_LTR_min_dT; //[K] + ms_auto_opt_des_par.m_LTR_eff_target = auto_opt_des_hit_eta_in.m_LTR_eff_target; //[-] + ms_auto_opt_des_par.m_LTR_eff_max = auto_opt_des_hit_eta_in.m_LTR_eff_max; + ms_auto_opt_des_par.m_LTR_od_UA_target_type = auto_opt_des_hit_eta_in.m_LTR_od_UA_target_type; + // HTR thermal design + ms_auto_opt_des_par.m_HTR_target_code = auto_opt_des_hit_eta_in.m_HTR_target_code; //[-] + ms_auto_opt_des_par.m_HTR_UA = auto_opt_des_hit_eta_in.m_HTR_UA; //[kW/K] + ms_auto_opt_des_par.m_HTR_min_dT = auto_opt_des_hit_eta_in.m_HTR_min_dT; //[K] + ms_auto_opt_des_par.m_HTR_eff_target = auto_opt_des_hit_eta_in.m_HTR_eff_target; //[-] + ms_auto_opt_des_par.m_HTR_eff_max = auto_opt_des_hit_eta_in.m_HTR_eff_max; //[-] + ms_auto_opt_des_par.m_HTR_od_UA_target_type = auto_opt_des_hit_eta_in.m_HTR_od_UA_target_type; + // + ms_auto_opt_des_par.m_des_tol = auto_opt_des_hit_eta_in.m_des_tol; //[-] Convergence tolerance + ms_auto_opt_des_par.m_des_opt_tol = auto_opt_des_hit_eta_in.m_des_opt_tol; //[-] Optimization tolerance + ms_auto_opt_des_par.m_is_recomp_ok = auto_opt_des_hit_eta_in.m_is_recomp_ok; //[-] 1 = yes, 0 = no, other = invalid + + ms_auto_opt_des_par.m_is_des_air_cooler = auto_opt_des_hit_eta_in.m_is_des_air_cooler; //[-] + + ms_auto_opt_des_par.m_des_objective_type = auto_opt_des_hit_eta_in.m_des_objective_type; //[-] + ms_auto_opt_des_par.m_min_phx_deltaT = auto_opt_des_hit_eta_in.m_min_phx_deltaT; //[C] + + ms_auto_opt_des_par.mf_callback_log = auto_opt_des_hit_eta_in.mf_callback_log; + ms_auto_opt_des_par.mp_mf_active = auto_opt_des_hit_eta_in.mp_mf_active; + + ms_auto_opt_des_par.m_fixed_P_mc_out = auto_opt_des_hit_eta_in.m_fixed_P_mc_out; //[-] + + ms_auto_opt_des_par.m_PR_HP_to_LP_guess = auto_opt_des_hit_eta_in.m_PR_HP_to_LP_guess; //[-] Initial guess for ratio of P_mc_out to P_mc_in + ms_auto_opt_des_par.m_fixed_PR_HP_to_LP = auto_opt_des_hit_eta_in.m_fixed_PR_HP_to_LP; //[-] if true, ratio of P_mc_out to P_mc_in is fixed at PR_mc_guess + } + + // Fill in 'ms_opt_des_par' from input + { + // Fill in 'ms_opt_des_par' (Can this be less cumbersome?) + { + // Check that simple/recomp flag is set + if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && + ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) + { + throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" + " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); + } + + // map 'auto_opt_des_par_in' to 'ms_auto_opt_des_par' + + // LTR thermal design + ms_opt_des_par.m_LTR_target_code = ms_auto_opt_des_par.m_LTR_target_code; //[-] + ms_opt_des_par.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; //[kW/K] + ms_opt_des_par.m_LTR_min_dT = ms_auto_opt_des_par.m_LTR_min_dT; //[K] + ms_opt_des_par.m_LTR_eff_target = ms_auto_opt_des_par.m_LTR_eff_target; //[-] + ms_opt_des_par.m_LTR_eff_max = ms_auto_opt_des_par.m_LTR_eff_max; //[-] + ms_opt_des_par.m_LTR_od_UA_target_type = ms_auto_opt_des_par.m_LTR_od_UA_target_type; + // HTR thermal design + ms_opt_des_par.m_HTR_target_code = ms_auto_opt_des_par.m_HTR_target_code; //[-] + ms_opt_des_par.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; //[kW/K] + ms_opt_des_par.m_HTR_min_dT = ms_auto_opt_des_par.m_HTR_min_dT; //[K] + ms_opt_des_par.m_HTR_eff_target = ms_auto_opt_des_par.m_HTR_eff_target; //[-] + ms_opt_des_par.m_HTR_eff_max = ms_auto_opt_des_par.m_HTR_eff_max; + ms_opt_des_par.m_HTR_od_UA_target_type = ms_auto_opt_des_par.m_HTR_od_UA_target_type; + // + //ms_opt_des_par.m_UA_rec_total = ms_auto_opt_des_par.m_UA_rec_total; + ms_opt_des_par.m_des_tol = ms_auto_opt_des_par.m_des_tol; + ms_opt_des_par.m_des_opt_tol = ms_auto_opt_des_par.m_des_opt_tol; + + ms_opt_des_par.m_is_des_air_cooler = ms_auto_opt_des_par.m_is_des_air_cooler; //[-] + + //ms_opt_des_par.m_des_objective_type = ms_auto_opt_des_par.m_des_objective_type; //[-] + ms_opt_des_par.m_min_phx_deltaT = ms_auto_opt_des_par.m_min_phx_deltaT; //[C] + + ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] + + ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] + } + + // Complete 'ms_opt_des_par' for Design Variables + { + double best_P_high = m_P_high_limit; //[kPa] + double PR_mc_guess = 2.5; //[-] + if (!ms_opt_des_par.m_fixed_P_mc_out) + { + double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] + + //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); + best_P_high = m_P_high_limit; + } + + + ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] + ms_opt_des_par.m_fixed_P_mc_out = true; + + if (ms_opt_des_par.m_fixed_PR_HP_to_LP) + { + ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + } + else + { + ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] + } + + // Is recompression fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) + { // fixed + ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); + ms_opt_des_par.m_fixed_recomp_frac = true; + } + else + { // optimized + ms_opt_des_par.m_recomp_frac_guess = 0.3; + ms_opt_des_par.m_fixed_recomp_frac = false; + } + + // Is bypass fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0.0) + { // fixed + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + ms_opt_des_par.m_fixed_bypass_frac = true; + } + else + { // optimized + ms_opt_des_par.m_bypass_frac_guess = 0.3; + ms_opt_des_par.m_fixed_bypass_frac = false; + } + + ms_opt_des_par.m_LT_frac_guess = 0.5; + ms_opt_des_par.m_fixed_LT_frac = false; + + if (ms_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + ms_opt_des_par.m_fixed_LT_frac = true; + } + + } + } + + // LTR HTF UA ratio can't be fixed + ms_opt_des_par.m_fixed_LT_frac = false; + + double Q_dot_rec_des = m_W_dot_net / auto_opt_des_hit_eta_in.m_eta_thermal; //[kWt] Receiver thermal input at design + + // Validate Inputs + error_msg = ""; + { + // Check that simple/recomp flag is set + if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && + ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) + { + throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" + " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); + } + // Can't operate compressore in 2-phase region + if (m_T_mc_in <= N_co2_props::T_crit) + { + error_msg.append(util::format("Only single phase cycle operation is allowed in this model." + "The compressor inlet temperature (%lg [C]) must be great than the critical temperature: %lg [C]", + m_T_mc_in - 273.15, ((N_co2_props::T_crit)-273.15))); + + return -1; + } + + // "Reasonable" ceiling on compressor inlet temp + double T_mc_in_max = 70.0 + 273.15; //[K] Arbitrary value for max compressor inlet temperature + if (m_T_mc_in > T_mc_in_max) + { + error_msg.append(util::format("The compressor inlet temperature input was %lg [C]. This value was reset internally to the max allowable inlet temperature: %lg [C]\n", + m_T_mc_in - 273.15, T_mc_in_max - 273.15)); + + m_T_mc_in = T_mc_in_max; + } + + // "Reasonable" floor on turbine inlet temp + double T_t_in_min = 300.0 + 273.15; //[K] Arbitrary value for min turbine inlet temperature + if (m_T_t_in < T_t_in_min) + { + error_msg.append(util::format("The turbine inlet temperature input was %lg [C]. This value was reset internally to the min allowable inlet temperature: %lg [C]\n", + m_T_t_in - 273.15, T_t_in_min - 273.15)); + + m_T_t_in = T_t_in_min; + } + + // Turbine inlet temperature must be hotter than compressor outlet temperature + if (m_T_t_in <= m_T_mc_in) + { + error_msg.append(util::format("The turbine inlet temperature, %lg [C], is colder than the specified compressor inlet temperature %lg [C]", + m_T_t_in - 273.15, m_T_mc_in - 273.15)); + + return -1; + } + + // Turbine inlet temperature must be colder than property limits + if (m_T_t_in >= N_co2_props::T_upper_limit) + { + error_msg.append(util::format("The turbine inlet temperature, %lg [C], is hotter than the maximum allow temperature in the CO2 property code %lg [C]", + m_T_t_in - 273.15, N_co2_props::T_upper_limit - 273.15)); + + return -1; + } + + // Check for realistic isentropic efficiencies + if (m_eta_mc > 1.0) + { + error_msg.append(util::format("The main compressor isentropic efficiency, %lg, was reset to theoretical maximum 1.0\n", + m_eta_mc)); + + m_eta_mc = 1.0; + } + if (m_eta_rc > 1.0) + { + error_msg.append(util::format("The re-compressor isentropic efficiency, %lg, was reset to theoretical maximum 1.0\n", + m_eta_rc)); + + m_eta_rc = 1.0; + } + if (m_eta_t > 1.0) + { + error_msg.append(util::format("The turbine isentropic efficiency, %lg, was reset to theoretical maximum 1.0\n", + m_eta_t)); + + m_eta_t = 1.0; + } + if (m_eta_mc < 0.1) + { + error_msg.append(util::format("The main compressor isentropic efficiency, %lg, was increased to the internal limit of 0.1 to improve solution stability\n", + m_eta_mc)); + + m_eta_mc = 0.1; + } + if (m_eta_rc < 0.1) + { + error_msg.append(util::format("The re-compressor isentropic efficiency, %lg, was increased to the internal limit of 0.1 to improve solution stability\n", + m_eta_rc)); + + m_eta_rc = 0.1; + } + if (m_eta_t < 0.1) + { + error_msg.append(util::format("The turbine isentropic efficiency, %lg, was increased to the internal limit of 0.1 to improve solution stability\n", + m_eta_t)); + + m_eta_t = 0.1; + } + + if (ms_auto_opt_des_par.m_LTR_eff_max > 1.0) + { + error_msg.append(util::format("The LT recuperator max effectiveness, %lg, was decreased to the limit of 1.0\n", ms_auto_opt_des_par.m_LTR_eff_max)); + + ms_auto_opt_des_par.m_LTR_eff_max = 1.0; + } + + if (ms_auto_opt_des_par.m_LTR_eff_max < 0.70) + { + error_msg.append(util::format("The LT recuperator max effectiveness, %lg, was increased to the internal limit of 0.70 improve convergence\n", ms_auto_opt_des_par.m_LTR_eff_max)); + + ms_auto_opt_des_par.m_LTR_eff_max = 0.7; + } + + if (ms_auto_opt_des_par.m_HTR_eff_max > 1.0) + { + error_msg.append(util::format("The HT recuperator max effectiveness, %lg, was decreased to the limit of 1.0\n", ms_auto_opt_des_par.m_HTR_eff_max)); + + ms_auto_opt_des_par.m_HTR_eff_max = 1.0; + } + + if (ms_auto_opt_des_par.m_HTR_eff_max < 0.70) + { + error_msg.append(util::format("The LT recuperator max effectiveness, %lg, was increased to the internal limit of 0.70 improve convergence\n", ms_auto_opt_des_par.m_HTR_eff_max)); + + ms_auto_opt_des_par.m_HTR_eff_max = 0.7; + } + + // Limits on high pressure limit + if (m_P_high_limit >= N_co2_props::P_upper_limit) + { + error_msg.append(util::format("The upper pressure limit, %lg [MPa], was set to the internal limit in the CO2 properties code %lg [MPa]\n", + m_P_high_limit, N_co2_props::P_upper_limit)); + + m_P_high_limit = N_co2_props::P_upper_limit; + } + double P_high_limit_min = 10.0 * 1.E3; //[kPa] + if (m_P_high_limit <= P_high_limit_min) + { + error_msg.append(util::format("The upper pressure limit, %lg [MPa], must be greater than %lg [MPa] to ensure solution stability", + m_P_high_limit, P_high_limit_min)); + + return -1; + } + + // Finally, check thermal efficiency + if (auto_opt_des_hit_eta_in.m_eta_thermal <= 0.0) + { + error_msg.append(util::format("The design cycle thermal efficiency, %lg, must be at least greater than 0 ", + auto_opt_des_hit_eta_in.m_eta_thermal)); + + return -1; + } + double eta_carnot = 1.0 - m_T_mc_in / m_T_t_in; + if (auto_opt_des_hit_eta_in.m_eta_thermal >= eta_carnot) + { + error_msg.append(util::format("To solve the cycle within the allowable recuperator conductance, the design cycle thermal efficiency, %lg, must be at least less than the Carnot efficiency: %lg ", + auto_opt_des_hit_eta_in.m_eta_thermal, eta_carnot)); + + return -1; + } + + + } + + // Send log update upstream + if (ms_auto_opt_des_par.mf_callback_log && ms_auto_opt_des_par.mp_mf_active) + { + std::string msg_log = util::format("Iterate on total recuperator conductance to hit target cycle efficiency: %lg [-]", auto_opt_des_hit_eta_in.m_eta_thermal); + std::string msg_progress = "Designing cycle..."; + if (!ms_auto_opt_des_par.mf_callback_log(msg_log, msg_progress, ms_auto_opt_des_par.mp_mf_active, 0.0, 2)) + { + std::string error_msg = "User terminated simulation..."; + std::string loc_msg = "C_MEQ_sco2_design_hit_eta__UA_total"; + throw(C_csp_exception(error_msg, loc_msg, 1)); + } + } + + // Create Optimizer + nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); + + // Generate min and max values + double UA_recup_total_max = ms_des_limits.m_UA_net_power_ratio_max * m_W_dot_net; //[kW/K] + double UA_recup_total_min = ms_des_limits.m_UA_net_power_ratio_min * m_W_dot_net; //[kW/K] + double UA_recup_guess = (UA_recup_total_max + UA_recup_total_min) / 2.0; //[kW/K] + + std::vector lb = { UA_recup_total_min }; + std::vector ub = { UA_recup_total_max }; + + opt_des_cycle.set_lower_bounds(lb); + opt_des_cycle.set_upper_bounds(ub); + opt_des_cycle.set_initial_step(0.1); + opt_des_cycle.set_xtol_rel(ms_auto_opt_des_par.m_des_opt_tol); + opt_des_cycle.set_maxeval(50); + + S_auto_opt_design_parameters auto_par = ms_auto_opt_des_par; + S_opt_design_parameters opt_par = ms_opt_des_par; + + // Make Tuple to pass in parameters + std::tuple par_tuple = { this, &auto_par, &opt_par }; + + // Set max objective function + std::vector x; + x.push_back(UA_recup_guess); + opt_des_cycle.set_max_objective(nlopt_opt_total_UA_func, &par_tuple); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' + double max_f = std::numeric_limits::quiet_NaN(); + + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + + /// Check to make sure optimizer worked... + if (opt_des_cycle.get_force_stop()) + { + int w = 0; + } + + // Need to collect optimal input somehow + return 0; } @@ -1572,6 +2016,22 @@ void C_HTRBypass_Cycle::reset_ms_od_turbo_bal_csp_solved() { } +double nlopt_opt_total_UA_func(const std::vector& x, std::vector& grad, void* data) +{ + // Unpack Data Tuple + std::tuple* data_tuple + = static_cast*>(data); + + C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); + const C_HTRBypass_Cycle::S_auto_opt_design_parameters* auto_opt_par = std::get<1>(*data_tuple); + const C_HTRBypass_Cycle::S_opt_design_parameters* opt_par = std::get<2>(*data_tuple); + + if (frame != NULL) + return frame->opt_total_UA_return_objective_metric(x, *auto_opt_par, *opt_par); + else + return 0.0; +} + double nlopt_opt_cycle_func(const std::vector& x, std::vector& grad, void* data) { // Unpack Data Tuple @@ -1606,6 +2066,7 @@ double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par); double C_HTRBypass_Cycle::opt_cycle_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); @@ -553,10 +556,15 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core }; // Nlopt objective functions +double nlopt_opt_total_UA_func(const std::vector& x, std::vector& grad, void* data); + double nlopt_opt_cycle_func(const std::vector& x, std::vector& grad, void* data); double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector& grad, void* data); + + + // Penalty value methods double sigmoid(const double val); From dc5fdcd9e1865083f30f2d18ea91e981cfba4909 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Wed, 13 Mar 2024 11:10:25 -0600 Subject: [PATCH 43/94] Complete total UA optimization. Remove unnecessary class. --- tcs/sco2_cycle_templates.h | 3 +- tcs/sco2_htrbypass_cycle.cpp | 283 ++++++++++++++++++++++++----------- tcs/sco2_htrbypass_cycle.h | 83 +++------- tcs/sco2_pc_csp_int.cpp | 1 + 4 files changed, 217 insertions(+), 153 deletions(-) diff --git a/tcs/sco2_cycle_templates.h b/tcs/sco2_cycle_templates.h index 88cf9d35f8..0265501817 100644 --- a/tcs/sco2_cycle_templates.h +++ b/tcs/sco2_cycle_templates.h @@ -130,6 +130,7 @@ class C_sco2_cycle_core bool m_is_des_air_cooler; //[-] False will skip physical air cooler design. UA will not be available for cost models. double m_is_recomp_ok; //[-] 1 = Yes, 0 = simple cycle only, < 0 = fix f_recomp to abs(input) + double m_is_bypass_ok; //[-] 1 = Yes, 0 = no bp, < 0 = fix f_bypass to abs(input) int m_des_objective_type; //[2] = min phx deltat then max eta, [else] max eta double m_min_phx_deltaT; //[C] @@ -153,7 +154,7 @@ class C_sco2_cycle_core m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = m_eta_pc = m_des_tol = m_des_opt_tol = - m_is_recomp_ok = + m_is_recomp_ok = m_is_bypass_ok = m_PR_HP_to_LP_guess = m_f_PR_HP_to_IP_guess = std::numeric_limits::quiet_NaN(); // Recuperator design target codes diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index b79b1cdf2a..afabfe85aa 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -937,6 +937,12 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) ms_opt_des_par.m_fixed_LT_frac = true; } + // Set Design Method + if (ms_opt_des_par.m_fixed_LT_frac == true) + ms_opt_des_par.m_design_method = 3; + else + ms_opt_des_par.m_design_method = 2; + } // Find optimal inputs @@ -1083,7 +1089,8 @@ int C_HTRBypass_Cycle::optimize_cycle(const S_auto_opt_design_parameters& auto_p opt_des_cycle.set_lower_bounds(lb); opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(0.1); - opt_des_cycle.set_xtol_rel(auto_par.m_des_opt_tol); + //opt_des_cycle.set_xtol_rel(auto_par.m_des_opt_tol); + opt_des_cycle.set_xtol_rel(0.1); opt_des_cycle.set_maxeval(50); // Set up Core Model that will be passed to objective function @@ -1385,11 +1392,68 @@ int C_HTRBypass_Cycle::clear_x_inputs(const std::vector& x, const S_auto return 0; } +double C_HTRBypass_Cycle::calc_penalty(double target, double calc, double span) +{ + double percent_error = std::abs(target - calc) / span; + //double penalty = 10.0 * (100.0 * sigmoid(percent_error) - 0.5); + + double penalty = percent_error; + + return penalty; +} + +double C_HTRBypass_Cycle::calc_objective(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, const C_sco2_htrbp_core& htrbp_core) +{ + double obj = 0; + double eta = htrbp_core.m_outputs.m_eta_thermal; + + // Hit a target thermal efficiency + if (opt_par.m_design_method == 1) + { + double eta_error = std::min(eta - opt_par.m_eta_thermal_target, 0.0); + obj = 1.0 - std::abs(eta_error); + + // Penalize for total UA (lower is better) + + } + // Maximize thermal efficiency + else + { + obj = eta; + } + + // Penalize for HTF outlet temp (if necessary) + double penalty = 0; + if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) + { + double temp_calc = 0; + double span = 0; + + if (m_T_target_is_HTF == 0) + { + temp_calc = htrbp_core.m_outputs.m_temp[MIXER_OUT]; + span = htrbp_core.m_outputs.m_temp[TURB_IN] - m_T_target; + } + else + { + temp_calc = htrbp_core.m_outputs.m_T_HTF_BP_outlet; + span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; + } + + penalty = calc_penalty(m_T_target, temp_calc, span); + } + + obj = obj - penalty; + + return obj; +} + // ********************************************************************************* END PRIVATE methods // ********************************************************************************** PUBLIC C_HTRBypass_Cycle (: C_sco2_cycle_core) -void C_HTRBypass_Cycle::set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot, +void C_HTRBypass_Cycle::set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, + double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot, int T_target_is_HTF) { m_T_HTF_PHX_inlet = T_htf_phx_in; // K @@ -1423,7 +1487,7 @@ double C_HTRBypass_Cycle::opt_total_UA_return_objective_metric(const std::vector auto_par_internal.m_UA_rec_total = total_UA; opt_par_internal.m_UA_rec_total = total_UA; - // Optimize all other variables + // Optimize all internal variables (bypass_frac -> recomp frac, UA ratio, pressure ratio) S_sco2_htrbp_in optimal_inputs_case; int error_code = optimize_cycle(auto_par_internal, opt_par_internal, optimal_inputs_case); @@ -1439,41 +1503,54 @@ double C_HTRBypass_Cycle::opt_total_UA_return_objective_metric(const std::vector if (error_code != 0) return -100000000000000000; - double eff = htrbp_core.m_outputs.m_eta_thermal; + // Calculate Objective Value + double obj = calc_objective(auto_par_internal, opt_par_internal, htrbp_core); - // If variable bypass fraction or targeting temperature - double penalty = 0; - if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) - { - double temp_calc = 0; - double span = 0; + // This objectve ^ targets a thermal efficiency (and tries to hit a temperature, if applicable) + // Need to incentivize lower UA value - if (m_T_target_is_HTF == 0) - { - temp_calc = htrbp_core.m_outputs.m_temp[MIXER_OUT]; - span = htrbp_core.m_outputs.m_temp[TURB_IN] - m_T_target; - } - else - { - temp_calc = htrbp_core.m_outputs.m_T_HTF_BP_outlet; - span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; - } + // Hitting eta and temperature is more important than low UA + double UA_percent = (total_UA - opt_par.m_UA_recup_total_min) / (opt_par.m_UA_recup_total_max - opt_par.m_UA_recup_total_min); // Lower is closer to 0 + double UA_penalty = UA_percent; - penalty = calc_penalty(m_T_target, temp_calc, span); - } + // Increase obj scale (making eta and temp more weighted) + double obj_weighted = obj * 1e2; - double obj = eff - penalty; + // Subtract UA_penalty + obj_weighted = obj_weighted - UA_penalty; - if (obj > m_opt_obj_internal_only) - { - m_opt_obj_internal_only = obj; - m_optimal_inputs_internal_only = optimal_inputs_case; - } + //double eff = htrbp_core.m_outputs.m_eta_thermal; - // Reset htrbp_core - htrbp_core.m_outputs.Init(); + //// If variable bypass fraction or targeting temperature + //double penalty = 0; + //if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) + //{ + // double temp_calc = 0; + // double span = 0; - return obj; + // if (m_T_target_is_HTF == 0) + // { + // temp_calc = htrbp_core.m_outputs.m_temp[MIXER_OUT]; + // span = htrbp_core.m_outputs.m_temp[TURB_IN] - m_T_target; + // } + // else + // { + // temp_calc = htrbp_core.m_outputs.m_T_HTF_BP_outlet; + // span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; + // } + + // penalty = calc_penalty(m_T_target, temp_calc, span); + //} + + //double obj = eff - penalty; + + //if (obj > m_opt_obj_internal_only) + //{ + // m_opt_obj_internal_only = obj; + // m_optimal_inputs_internal_only = optimal_inputs_case; + //} + + return obj_weighted; } /// @@ -1511,30 +1588,33 @@ double C_HTRBypass_Cycle::opt_cycle_return_objective_metric(const std::vector m_opt_obj_internal_only) { @@ -1573,30 +1653,32 @@ double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vecto double objective_metric = -10000000000.0; if (error_code == 0) { - double eff = htrbp_core.m_outputs.m_eta_thermal; + objective_metric = calc_objective(auto_par, opt_par, htrbp_core); - // If variable bypass fraction or targeting temperature - double penalty = 0; - if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) - { - double temp_calc = 0; - double span = 0; + //double eff = htrbp_core.m_outputs.m_eta_thermal; - if (m_T_target_is_HTF == 0) - { - temp_calc = htrbp_core.m_outputs.m_temp[MIXER_OUT]; - span = htrbp_core.m_outputs.m_temp[TURB_IN] - m_T_target; - } - else - { - temp_calc = htrbp_core.m_outputs.m_T_HTF_BP_outlet; - span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; - } + //// If variable bypass fraction or targeting temperature + //double penalty = 0; + //if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) + //{ + // double temp_calc = 0; + // double span = 0; - penalty = calc_penalty(m_T_target, temp_calc, span); - } + // if (m_T_target_is_HTF == 0) + // { + // temp_calc = htrbp_core.m_outputs.m_temp[MIXER_OUT]; + // span = htrbp_core.m_outputs.m_temp[TURB_IN] - m_T_target; + // } + // else + // { + // temp_calc = htrbp_core.m_outputs.m_T_HTF_BP_outlet; + // span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; + // } - objective_metric = eff - penalty; + // penalty = calc_penalty(m_T_target, temp_calc, span); + //} + + //objective_metric = eff - penalty; /*if (objective_metric > m_objective_metric_opt) { @@ -1614,13 +1696,7 @@ double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vecto -double C_HTRBypass_Cycle::calc_penalty(double target, double calc, double span) -{ - double percent_error = std::abs(target - calc) / span; - double penalty = 10.0 * (100.0 * sigmoid(percent_error) - 0.5); - return penalty; -} int C_HTRBypass_Cycle::auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in) { @@ -1658,6 +1734,7 @@ int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_paramet ms_auto_opt_des_par.m_des_tol = auto_opt_des_hit_eta_in.m_des_tol; //[-] Convergence tolerance ms_auto_opt_des_par.m_des_opt_tol = auto_opt_des_hit_eta_in.m_des_opt_tol; //[-] Optimization tolerance ms_auto_opt_des_par.m_is_recomp_ok = auto_opt_des_hit_eta_in.m_is_recomp_ok; //[-] 1 = yes, 0 = no, other = invalid + ms_auto_opt_des_par.m_is_bypass_ok = auto_opt_des_hit_eta_in.m_is_bypass_ok; //[-] 1 = yes, 0 = no, other = invalid ms_auto_opt_des_par.m_is_des_air_cooler = auto_opt_des_hit_eta_in.m_is_des_air_cooler; //[-] @@ -1673,6 +1750,8 @@ int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_paramet ms_auto_opt_des_par.m_fixed_PR_HP_to_LP = auto_opt_des_hit_eta_in.m_fixed_PR_HP_to_LP; //[-] if true, ratio of P_mc_out to P_mc_in is fixed at PR_mc_guess } + + // Fill in 'ms_opt_des_par' from input { // Fill in 'ms_opt_des_par' (Can this be less cumbersome?) @@ -1687,6 +1766,8 @@ int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_paramet // map 'auto_opt_des_par_in' to 'ms_auto_opt_des_par' + ms_opt_des_par.m_eta_thermal_target = auto_opt_des_hit_eta_in.m_eta_thermal; + // LTR thermal design ms_opt_des_par.m_LTR_target_code = ms_auto_opt_des_par.m_LTR_target_code; //[-] ms_opt_des_par.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; //[kW/K] @@ -1776,6 +1857,9 @@ int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_paramet } } + // Set design method (it is 1, because total UA is optimized for target eta) + ms_opt_des_par.m_design_method = 1; + // LTR HTF UA ratio can't be fixed ms_opt_des_par.m_fixed_LT_frac = false; @@ -1839,8 +1923,9 @@ int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_paramet return -1; } + // REMOVED CHECKS (not compatible with negative values) // Check for realistic isentropic efficiencies - if (m_eta_mc > 1.0) + /*if (m_eta_mc > 1.0) { error_msg.append(util::format("The main compressor isentropic efficiency, %lg, was reset to theoretical maximum 1.0\n", m_eta_mc)); @@ -1881,7 +1966,7 @@ int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_paramet m_eta_t)); m_eta_t = 0.1; - } + }*/ if (ms_auto_opt_des_par.m_LTR_eff_max > 1.0) { @@ -1964,18 +2049,19 @@ int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_paramet // Create Optimizer nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); - // Generate min and max values - double UA_recup_total_max = ms_des_limits.m_UA_net_power_ratio_max * m_W_dot_net; //[kW/K] - double UA_recup_total_min = ms_des_limits.m_UA_net_power_ratio_min * m_W_dot_net; //[kW/K] - double UA_recup_guess = (UA_recup_total_max + UA_recup_total_min) / 2.0; //[kW/K] + // Select min and max values + ms_opt_des_par.m_UA_recup_total_max = ms_des_limits.m_UA_net_power_ratio_max * m_W_dot_net; //[kW/K] + ms_opt_des_par.m_UA_recup_total_min = ms_des_limits.m_UA_net_power_ratio_min * m_W_dot_net; //[kW/K] + double UA_recup_guess = (ms_opt_des_par.m_UA_recup_total_max + ms_opt_des_par.m_UA_recup_total_min) / 2.0; //[kW/K] - std::vector lb = { UA_recup_total_min }; - std::vector ub = { UA_recup_total_max }; + std::vector lb = { ms_opt_des_par.m_UA_recup_total_min }; + std::vector ub = { ms_opt_des_par.m_UA_recup_total_max }; opt_des_cycle.set_lower_bounds(lb); opt_des_cycle.set_upper_bounds(ub); - opt_des_cycle.set_initial_step(0.1); - opt_des_cycle.set_xtol_rel(ms_auto_opt_des_par.m_des_opt_tol); + opt_des_cycle.set_initial_step(1000); + //opt_des_cycle.set_xtol_rel(ms_auto_opt_des_par.m_des_opt_tol); + opt_des_cycle.set_xtol_rel(1); opt_des_cycle.set_maxeval(50); S_auto_opt_design_parameters auto_par = ms_auto_opt_des_par; @@ -1998,9 +2084,28 @@ int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_paramet int w = 0; } - // Need to collect optimal input somehow + // Assign Total UA + double total_UA = x[0]; + ms_auto_opt_des_par.m_UA_rec_total = total_UA; + ms_opt_des_par.m_UA_rec_total = total_UA; - return 0; + // Have Total UA, now rerun optimizer to get other variables (redundant but shouldn't be very costly) + S_sco2_htrbp_in optimal_inputs_case; + int error_code = optimize_cycle(ms_auto_opt_des_par, ms_opt_des_par, optimal_inputs_case); + if (error_code != 0) + return error_code; + + // Run Optimal Core model and finalize design + m_optimal_htrbp_core.Reset(); + m_optimal_htrbp_core.SetInputs(optimal_inputs_case); + error_code = m_optimal_htrbp_core.Solve(); + if (error_code != 0) + return error_code; + + // Finalize Design (pass in reference to solved parameters) + error_code = m_optimal_htrbp_core.FinalizeDesign(ms_des_solved); + + return error_code; } diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 5277b349d3..c545ae8844 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -277,67 +277,6 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core { public: - struct S_design_parameters - { - - double m_P_mc_in; //[kPa] Compressor inlet pressure - double m_P_mc_out; //[kPa] Compressor outlet pressure - - // LTR thermal design - int m_LTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness - double m_LTR_UA; //[kW/K] target LTR conductance - double m_LTR_min_dT; //[K] target LTR minimum temperature difference - double m_LTR_eff_target; //[-] target LTR effectiveness - double m_LTR_eff_max; //[-] Maximum allowable effectiveness in LT recuperator - NS_HX_counterflow_eqs::E_UA_target_type m_LTR_od_UA_target_type; - - // HTR thermal design - int m_HTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness - double m_HTR_UA; //[kW/K] target HTR conductance - double m_HTR_min_dT; //[K] target HTR min temperature difference - double m_HTR_eff_target; //[-] target HTR effectiveness - double m_HTR_eff_max; //[-] Maximum allowable effectiveness in HT recuperator - NS_HX_counterflow_eqs::E_UA_target_type m_HTR_od_UA_target_type; - - double m_recomp_frac; //[-] Fraction of flow that bypasses the precooler and the main compressor at the design point - double m_bypass_frac; //[-] Fraction of flow that bypasses the HTR and passes through the Bypass HX - double m_des_tol; //[-] Convergence tolerance - - // Air cooler parameters - bool m_is_des_air_cooler; //[-] False will skip physical air cooler design. UA will not be available for cost models. - - int m_des_objective_type; //[2] = min phx deltat then max eta, [else] max eta - double m_min_phx_deltaT; //[C] - - - S_design_parameters() - { - m_P_mc_in = m_P_mc_out = - m_LTR_UA = m_LTR_min_dT = m_LTR_eff_target = m_LTR_eff_max = - m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = - m_recomp_frac = - m_bypass_frac = - m_des_tol = - std::numeric_limits::quiet_NaN(); - - // Recuperator design target codes - m_LTR_target_code = 1; // default to target conductance - m_LTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; - m_HTR_target_code = 1; // default to target conductance - m_HTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; - - // Default to standard optimization to maximize cycle efficiency - m_des_objective_type = 1; - m_min_phx_deltaT = 0.0; //[C] - - // Air cooler default - m_is_des_air_cooler = true; - - } - - - }; - struct S_opt_design_parameters { double m_UA_rec_total; //[kW/K] Total design-point recuperator UA @@ -379,6 +318,13 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_LT_frac_guess; //[-] Initial guess for fraction of UA_rec_total that is in the low-temperature recuperator bool m_fixed_LT_frac; //[-] if true, LT_frac is fixed at LT_frac_guess + // ADDED + int m_design_method; //[] Design Method [1] Optimize total UA for target eta, [2] Optimize UA split ratio, [3] set LTR HTR directly + double m_eta_thermal_target; //[] Cycle thermal efficiency target (used by total UA optimization) + double m_UA_recup_total_max; //[kW/K] Maximum recuperator conductance (for total UA optimizer) + double m_UA_recup_total_min; //[kW/K] Minimum recuperator conductance (for total UA optimizer) + + S_opt_design_parameters() { m_UA_rec_total = @@ -386,6 +332,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = m_des_tol = m_des_opt_tol = m_P_mc_out_guess = m_PR_HP_to_LP_guess = m_recomp_frac_guess = m_LT_frac_guess = + m_bypass_frac_guess = m_eta_thermal_target = + m_UA_recup_total_max = m_UA_recup_total_min = std::numeric_limits::quiet_NaN(); // Recuperator design target codes @@ -401,6 +349,13 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core m_des_objective_type = 1; m_min_phx_deltaT = 0.0; //[C] + m_design_method = -1; + m_fixed_recomp_frac = false; + m_fixed_bypass_frac = false; + m_fixed_LT_frac = false; + m_fixed_PR_HP_to_LP = false; + m_fixed_P_mc_out = false; + } @@ -447,6 +402,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core // Added double calc_penalty(double target, double calc, double span); + double calc_objective(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, const C_sco2_htrbp_core& htrbp_core); + protected: @@ -495,8 +452,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core int auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in); // Set Bypass Specific Parameters - void set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot, - int T_target_is_HTF); + void set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, + double htf_phx_cold_approach, double set_HTF_mdot, int T_target_is_HTF); // Objective Functions double C_HTRBypass_Cycle::opt_total_UA_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par); diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index bfdf553af1..744dc44c1c 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -260,6 +260,7 @@ void C_sco2_phx_air_cooler::design_core() ms_cycle_des_par.m_des_tol = ms_des_par.m_des_tol; ms_cycle_des_par.m_des_opt_tol = ms_des_par.m_des_opt_tol; ms_cycle_des_par.m_is_recomp_ok = ms_des_par.m_is_recomp_ok; + ms_cycle_des_par.m_is_bypass_ok = ms_des_par.m_is_bypass_ok; ms_cycle_des_par.m_is_des_air_cooler = ms_des_par.m_is_des_air_cooler; //[-] From 895068525c500430f0c383f31cffe98f9917fb60 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Wed, 13 Mar 2024 12:46:42 -0600 Subject: [PATCH 44/94] Remove duplicate fields from ms_opt_des_par. Initialize variables. --- tcs/sco2_cycle_templates.h | 6 +- tcs/sco2_htrbypass_cycle.cpp | 225 ++++++++++++----------------------- tcs/sco2_htrbypass_cycle.h | 48 +------- 3 files changed, 82 insertions(+), 197 deletions(-) diff --git a/tcs/sco2_cycle_templates.h b/tcs/sco2_cycle_templates.h index 0265501817..7c58ef2e0a 100644 --- a/tcs/sco2_cycle_templates.h +++ b/tcs/sco2_cycle_templates.h @@ -149,7 +149,7 @@ class C_sco2_cycle_core S_auto_opt_design_hit_eta_parameters() { - m_T_pc_in = + m_eta_thermal = m_T_pc_in = m_LTR_UA = m_LTR_min_dT = m_LTR_eff_target = m_LTR_eff_max = m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = m_eta_pc = @@ -231,12 +231,12 @@ class C_sco2_cycle_core S_auto_opt_design_parameters() { - m_T_pc_in = + m_T_pc_in = m_UA_rec_total = m_LTR_UA = m_LTR_min_dT = m_LTR_eff_target = m_LTR_eff_max = m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = m_eta_pc = m_des_tol = m_des_opt_tol = - m_is_recomp_ok = + m_is_recomp_ok = m_is_bypass_ok = m_PR_HP_to_LP_guess = m_f_PR_HP_to_IP_guess = std::numeric_limits::quiet_NaN(); // Recuperator design target codes diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index afabfe85aa..3bcc4132f7 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -839,51 +839,20 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) // Reset optimal htrbp model m_optimal_htrbp_core.Reset(); - // Fill in 'ms_opt_des_par' (Can this be less cumbersome?) + // Check that simple/recomp flag is set + if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && + ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) { - // Check that simple/recomp flag is set - if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && - ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) - { - throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" - " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); - } - - // map 'auto_opt_des_par_in' to 'ms_auto_opt_des_par' - - // LTR thermal design - ms_opt_des_par.m_LTR_target_code = ms_auto_opt_des_par.m_LTR_target_code; //[-] - ms_opt_des_par.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; //[kW/K] - ms_opt_des_par.m_LTR_min_dT = ms_auto_opt_des_par.m_LTR_min_dT; //[K] - ms_opt_des_par.m_LTR_eff_target = ms_auto_opt_des_par.m_LTR_eff_target; //[-] - ms_opt_des_par.m_LTR_eff_max = ms_auto_opt_des_par.m_LTR_eff_max; //[-] - ms_opt_des_par.m_LTR_od_UA_target_type = ms_auto_opt_des_par.m_LTR_od_UA_target_type; - // HTR thermal design - ms_opt_des_par.m_HTR_target_code = ms_auto_opt_des_par.m_HTR_target_code; //[-] - ms_opt_des_par.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; //[kW/K] - ms_opt_des_par.m_HTR_min_dT = ms_auto_opt_des_par.m_HTR_min_dT; //[K] - ms_opt_des_par.m_HTR_eff_target = ms_auto_opt_des_par.m_HTR_eff_target; //[-] - ms_opt_des_par.m_HTR_eff_max = ms_auto_opt_des_par.m_HTR_eff_max; - ms_opt_des_par.m_HTR_od_UA_target_type = ms_auto_opt_des_par.m_HTR_od_UA_target_type; - // - ms_opt_des_par.m_UA_rec_total = ms_auto_opt_des_par.m_UA_rec_total; - ms_opt_des_par.m_des_tol = ms_auto_opt_des_par.m_des_tol; - ms_opt_des_par.m_des_opt_tol = ms_auto_opt_des_par.m_des_opt_tol; - - ms_opt_des_par.m_is_des_air_cooler = ms_auto_opt_des_par.m_is_des_air_cooler; //[-] - - ms_opt_des_par.m_des_objective_type = ms_auto_opt_des_par.m_des_objective_type; //[-] - ms_opt_des_par.m_min_phx_deltaT = ms_auto_opt_des_par.m_min_phx_deltaT; //[C] - - ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] - - ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] + throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" + " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); } // Complete 'ms_opt_des_par' for Design Variables { + // Max Pressure double best_P_high = m_P_high_limit; //[kPa] double PR_mc_guess = 2.5; //[-] + ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] if (!ms_opt_des_par.m_fixed_P_mc_out) { double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] @@ -891,11 +860,11 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); best_P_high = m_P_high_limit; } - - ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] - ms_opt_des_par.m_fixed_P_mc_out = true; + //ms_opt_des_par.m_fixed_P_mc_out = true; + // Pressure Ratio (min pressure) + ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] if (ms_opt_des_par.m_fixed_PR_HP_to_LP) { ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] @@ -929,10 +898,10 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) ms_opt_des_par.m_fixed_bypass_frac = false; } + // LTR HTR UA Ratio ms_opt_des_par.m_LT_frac_guess = 0.5; ms_opt_des_par.m_fixed_LT_frac = false; - - if (ms_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) + if (ms_auto_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_auto_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) { ms_opt_des_par.m_fixed_LT_frac = true; } @@ -1044,15 +1013,15 @@ int C_HTRBypass_Cycle::optimize_cycle(const S_auto_opt_design_parameters& auto_p // Recuperator split fraction double LT_frac_local = opt_par.m_LT_frac_guess; - if (opt_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || opt_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + if (auto_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || auto_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) { - core_inputs.m_LTR_UA = opt_par.m_UA_rec_total * LT_frac_local; - core_inputs.m_HTR_UA = opt_par.m_UA_rec_total * (1.0 - LT_frac_local); + core_inputs.m_LTR_UA = auto_par.m_UA_rec_total * LT_frac_local; + core_inputs.m_HTR_UA = auto_par.m_UA_rec_total * (1.0 - LT_frac_local); } else { - core_inputs.m_LTR_UA = opt_par.m_LTR_UA; //[kW/K] - core_inputs.m_HTR_UA = opt_par.m_HTR_UA; //[kW/K] + core_inputs.m_LTR_UA = auto_par.m_LTR_UA; //[kW/K] + core_inputs.m_HTR_UA = auto_par.m_HTR_UA; //[kW/K] } @@ -1149,7 +1118,7 @@ int C_HTRBypass_Cycle::optimize_cycle(const S_auto_opt_design_parameters& auto_p /// int C_HTRBypass_Cycle::opt_nonbp_par(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, - S_sco2_htrbp_in core_inputs, + S_sco2_htrbp_in& core_inputs, S_sco2_htrbp_in& optimal_inputs) { // Add Applicable Design Variables to Optimizer @@ -1172,7 +1141,7 @@ int C_HTRBypass_Cycle::opt_nonbp_par(const S_auto_opt_design_parameters& auto_pa if (!auto_par.m_fixed_PR_HP_to_LP) { - x.push_back(auto_par.m_PR_HP_to_LP_guess); + x.push_back(opt_par.m_PR_HP_to_LP_guess); lb.push_back(0.0001); double PR_max = m_P_high_limit / 100.0; ub.push_back(PR_max); @@ -1485,7 +1454,6 @@ double C_HTRBypass_Cycle::opt_total_UA_return_objective_metric(const std::vector // Assign Total Recuperator UA double total_UA = x[0]; auto_par_internal.m_UA_rec_total = total_UA; - opt_par_internal.m_UA_rec_total = total_UA; // Optimize all internal variables (bypass_frac -> recomp frac, UA ratio, pressure ratio) S_sco2_htrbp_in optimal_inputs_case; @@ -1750,121 +1718,77 @@ int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_paramet ms_auto_opt_des_par.m_fixed_PR_HP_to_LP = auto_opt_des_hit_eta_in.m_fixed_PR_HP_to_LP; //[-] if true, ratio of P_mc_out to P_mc_in is fixed at PR_mc_guess } - - - // Fill in 'ms_opt_des_par' from input + // Check that simple/recomp flag is set + if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && + ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) { - // Fill in 'ms_opt_des_par' (Can this be less cumbersome?) - { - // Check that simple/recomp flag is set - if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && - ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) - { - throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" - " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); - } - - // map 'auto_opt_des_par_in' to 'ms_auto_opt_des_par' - - ms_opt_des_par.m_eta_thermal_target = auto_opt_des_hit_eta_in.m_eta_thermal; - - // LTR thermal design - ms_opt_des_par.m_LTR_target_code = ms_auto_opt_des_par.m_LTR_target_code; //[-] - ms_opt_des_par.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; //[kW/K] - ms_opt_des_par.m_LTR_min_dT = ms_auto_opt_des_par.m_LTR_min_dT; //[K] - ms_opt_des_par.m_LTR_eff_target = ms_auto_opt_des_par.m_LTR_eff_target; //[-] - ms_opt_des_par.m_LTR_eff_max = ms_auto_opt_des_par.m_LTR_eff_max; //[-] - ms_opt_des_par.m_LTR_od_UA_target_type = ms_auto_opt_des_par.m_LTR_od_UA_target_type; - // HTR thermal design - ms_opt_des_par.m_HTR_target_code = ms_auto_opt_des_par.m_HTR_target_code; //[-] - ms_opt_des_par.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; //[kW/K] - ms_opt_des_par.m_HTR_min_dT = ms_auto_opt_des_par.m_HTR_min_dT; //[K] - ms_opt_des_par.m_HTR_eff_target = ms_auto_opt_des_par.m_HTR_eff_target; //[-] - ms_opt_des_par.m_HTR_eff_max = ms_auto_opt_des_par.m_HTR_eff_max; - ms_opt_des_par.m_HTR_od_UA_target_type = ms_auto_opt_des_par.m_HTR_od_UA_target_type; - // - //ms_opt_des_par.m_UA_rec_total = ms_auto_opt_des_par.m_UA_rec_total; - ms_opt_des_par.m_des_tol = ms_auto_opt_des_par.m_des_tol; - ms_opt_des_par.m_des_opt_tol = ms_auto_opt_des_par.m_des_opt_tol; - - ms_opt_des_par.m_is_des_air_cooler = ms_auto_opt_des_par.m_is_des_air_cooler; //[-] + throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" + " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); + } - //ms_opt_des_par.m_des_objective_type = ms_auto_opt_des_par.m_des_objective_type; //[-] - ms_opt_des_par.m_min_phx_deltaT = ms_auto_opt_des_par.m_min_phx_deltaT; //[C] + // Complete 'ms_opt_des_par' for Design Variables + { + // Target Thermal Efficiency + ms_opt_des_par.m_eta_thermal_target = auto_opt_des_hit_eta_in.m_eta_thermal; - ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] + // Max Pressure + double best_P_high = m_P_high_limit; //[kPa] + double PR_mc_guess = 2.5; //[-] + ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] + if (!ms_opt_des_par.m_fixed_P_mc_out) + { + double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] - ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] + //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); + best_P_high = m_P_high_limit; } + ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] + //ms_opt_des_par.m_fixed_P_mc_out = true; - // Complete 'ms_opt_des_par' for Design Variables + // Pressure Ratio (min pressure) + ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] + if (ms_opt_des_par.m_fixed_PR_HP_to_LP) { - double best_P_high = m_P_high_limit; //[kPa] - double PR_mc_guess = 2.5; //[-] - if (!ms_opt_des_par.m_fixed_P_mc_out) - { - double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] - - //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); - best_P_high = m_P_high_limit; - } - - - ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] - ms_opt_des_par.m_fixed_P_mc_out = true; - - if (ms_opt_des_par.m_fixed_PR_HP_to_LP) - { - ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] - } - else - { - ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] - } - - // Is recompression fraction fixed or optimized? - if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) - { // fixed - ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); - ms_opt_des_par.m_fixed_recomp_frac = true; - } - else - { // optimized - ms_opt_des_par.m_recomp_frac_guess = 0.3; - ms_opt_des_par.m_fixed_recomp_frac = false; - } + ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + } + else + { + ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] + } - // Is bypass fraction fixed or optimized? - if (ms_auto_opt_des_par.m_is_bypass_ok <= 0.0) - { // fixed - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - ms_opt_des_par.m_fixed_bypass_frac = true; - } - else - { // optimized - ms_opt_des_par.m_bypass_frac_guess = 0.3; - ms_opt_des_par.m_fixed_bypass_frac = false; - } + // Is recompression fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) + { // fixed + ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); + ms_opt_des_par.m_fixed_recomp_frac = true; + } + else + { // optimized + ms_opt_des_par.m_recomp_frac_guess = 0.3; + ms_opt_des_par.m_fixed_recomp_frac = false; + } - ms_opt_des_par.m_LT_frac_guess = 0.5; - ms_opt_des_par.m_fixed_LT_frac = false; + // Is bypass fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0.0) + { // fixed + ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + ms_opt_des_par.m_fixed_bypass_frac = true; + } + else + { // optimized + ms_opt_des_par.m_bypass_frac_guess = 0.3; + ms_opt_des_par.m_fixed_bypass_frac = false; + } - if (ms_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) - { - ms_opt_des_par.m_fixed_LT_frac = true; - } + // LTR HTR UA Ratio (cannot be fixed because design method is varying total UA) + ms_opt_des_par.m_LT_frac_guess = 0.5; + ms_opt_des_par.m_fixed_LT_frac = false; - } } // Set design method (it is 1, because total UA is optimized for target eta) ms_opt_des_par.m_design_method = 1; - // LTR HTF UA ratio can't be fixed - ms_opt_des_par.m_fixed_LT_frac = false; - - double Q_dot_rec_des = m_W_dot_net / auto_opt_des_hit_eta_in.m_eta_thermal; //[kWt] Receiver thermal input at design - // Validate Inputs error_msg = ""; { @@ -2087,7 +2011,6 @@ int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_paramet // Assign Total UA double total_UA = x[0]; ms_auto_opt_des_par.m_UA_rec_total = total_UA; - ms_opt_des_par.m_UA_rec_total = total_UA; // Have Total UA, now rerun optimizer to get other variables (redundant but shouldn't be very costly) S_sco2_htrbp_in optimal_inputs_case; diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index c545ae8844..6b29be33d5 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -277,32 +277,9 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core { public: + // Struct to store optimization variables struct S_opt_design_parameters { - double m_UA_rec_total; //[kW/K] Total design-point recuperator UA - // LTR thermal design - int m_LTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness - double m_LTR_UA; //[kW/K] target LTR conductance - double m_LTR_min_dT; //[K] target LTR minimum temperature difference - double m_LTR_eff_target; //[-] target LTR effectiveness - double m_LTR_eff_max; //[-] Maximum allowable effectiveness in LT recuperator - NS_HX_counterflow_eqs::E_UA_target_type m_LTR_od_UA_target_type; - // HTR thermal design - int m_HTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness - double m_HTR_UA; //[kW/K] target HTR conductance - double m_HTR_min_dT; //[K] target HTR min temperature difference - double m_HTR_eff_target; //[-] target HTR effectiveness - double m_HTR_eff_max; //[-] Maximum allowable effectiveness in HT recuperator - NS_HX_counterflow_eqs::E_UA_target_type m_HTR_od_UA_target_type; - // - double m_des_tol; //[-] Convergence tolerance - double m_des_opt_tol; //[-] Optimization tolerance - - // Air cooler parameters - bool m_is_des_air_cooler; //[-] False will skip physical air cooler design. UA will not be available for cost models. - - int m_des_objective_type; //[2] = min phx deltat then max eta, [else] max eta - double m_min_phx_deltaT; //[C] double m_P_mc_out_guess; //[kPa] Initial guess for main compressor outlet pressure bool m_fixed_P_mc_out; //[-] if true, P_mc_out is fixed at P_mc_out_guess @@ -312,6 +289,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double m_recomp_frac_guess; //[-] Initial guess for design-point recompression fraction bool m_fixed_recomp_frac; //[-] if true, recomp_frac is fixed at recomp_frac_guess + double m_bypass_frac_guess; //[-] Initial guess for design-point bypass fraction bool m_fixed_bypass_frac; //[-] if true, bypass_frac is fixed at bypass_frac_guess @@ -320,34 +298,18 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core // ADDED int m_design_method; //[] Design Method [1] Optimize total UA for target eta, [2] Optimize UA split ratio, [3] set LTR HTR directly - double m_eta_thermal_target; //[] Cycle thermal efficiency target (used by total UA optimization) + double m_eta_thermal_target; //[] Cycle thermal efficiency target (used by total UA optimization) double m_UA_recup_total_max; //[kW/K] Maximum recuperator conductance (for total UA optimizer) double m_UA_recup_total_min; //[kW/K] Minimum recuperator conductance (for total UA optimizer) S_opt_design_parameters() { - m_UA_rec_total = - m_LTR_UA = m_LTR_min_dT = m_LTR_eff_target = m_LTR_eff_max = - m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = - m_des_tol = m_des_opt_tol = - m_P_mc_out_guess = m_PR_HP_to_LP_guess = m_recomp_frac_guess = m_LT_frac_guess = + m_P_mc_out_guess = m_PR_HP_to_LP_guess = m_recomp_frac_guess = m_LT_frac_guess = m_bypass_frac_guess = m_eta_thermal_target = m_UA_recup_total_max = m_UA_recup_total_min = std::numeric_limits::quiet_NaN(); - // Recuperator design target codes - m_LTR_target_code = 1; // default to target conductance - m_LTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; - m_HTR_target_code = 1; // default to target conductance - m_HTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; - - // Air cooler default - m_is_des_air_cooler = true; - - // Default to standard optimization to maximize cycle efficiency - m_des_objective_type = 1; - m_min_phx_deltaT = 0.0; //[C] m_design_method = -1; m_fixed_recomp_frac = false; @@ -366,7 +328,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core // NEW REFACTOR Fields and methods int optimize_cycle(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& optimal_inputs); - int opt_nonbp_par(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in core_inputs, S_sco2_htrbp_in& optimal_inputs); + int opt_nonbp_par(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& core_inputs, S_sco2_htrbp_in& optimal_inputs); int x_to_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in &core_inputs); From 382d6c7d0a5f3c0595baadaadc6bba339e51f29d Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Wed, 13 Mar 2024 16:07:34 -0600 Subject: [PATCH 45/94] Structure code. Synchronize naming convention. Add error check. Remove opt_des field from class. --- tcs/sco2_htrbypass_cycle.cpp | 985 +++++++++++++++++------------------ tcs/sco2_htrbypass_cycle.h | 434 +++++++-------- 2 files changed, 704 insertions(+), 715 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 3bcc4132f7..4d673dad88 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -46,7 +46,7 @@ void C_sco2_htrbp_core::InitializeSolve() m_outputs.Init(); } -int C_sco2_htrbp_core::Solve() +int C_sco2_htrbp_core::solve() { InitializeSolve(); m_outputs.m_error_code = -1; @@ -480,7 +480,7 @@ int C_sco2_htrbp_core::Solve() return m_outputs.m_error_code; } -int C_sco2_htrbp_core::FinalizeDesign(C_sco2_cycle_core::S_design_solved& design_solved) +int C_sco2_htrbp_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_solved) { // Design Main Compressor { @@ -823,7 +823,7 @@ int C_sco2_htrbp_core::solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_L return 0; } -void C_sco2_htrbp_core::Reset() +void C_sco2_htrbp_core::reset() { this->m_inputs = S_sco2_htrbp_in(); this->m_outputs.Init(); @@ -834,10 +834,13 @@ void C_sco2_htrbp_core::Reset() // ********************************************************************************** PRIVATE C_HTRBypass_Cycle (: C_sco2_cycle_core) +/// +/// Core function to optimize cycle (fixed total UA) +/// void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) { // Reset optimal htrbp model - m_optimal_htrbp_core.Reset(); + m_optimal_htrbp_core.reset(); // Check that simple/recomp flag is set if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && @@ -847,104 +850,274 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); } - // Complete 'ms_opt_des_par' for Design Variables + // Create 'ms_opt_des_par' for Design Variables + S_opt_design_parameters opt_par; { // Max Pressure double best_P_high = m_P_high_limit; //[kPa] double PR_mc_guess = 2.5; //[-] - ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] - if (!ms_opt_des_par.m_fixed_P_mc_out) + + opt_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] + if (!opt_par.m_fixed_P_mc_out) { double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); best_P_high = m_P_high_limit; } - ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] + opt_par.m_P_mc_out_guess = best_P_high; //[kPa] //ms_opt_des_par.m_fixed_P_mc_out = true; // Pressure Ratio (min pressure) - ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] - if (ms_opt_des_par.m_fixed_PR_HP_to_LP) + opt_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] + if (opt_par.m_fixed_PR_HP_to_LP) { - ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + opt_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] } else { - ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] + opt_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] } // Is recompression fraction fixed or optimized? if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) { // fixed - ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); - ms_opt_des_par.m_fixed_recomp_frac = true; + opt_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); + opt_par.m_fixed_recomp_frac = true; } else { // optimized - ms_opt_des_par.m_recomp_frac_guess = 0.3; - ms_opt_des_par.m_fixed_recomp_frac = false; + opt_par.m_recomp_frac_guess = 0.3; + opt_par.m_fixed_recomp_frac = false; } // Is bypass fraction fixed or optimized? if (ms_auto_opt_des_par.m_is_bypass_ok <= 0.0) { // fixed - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - ms_opt_des_par.m_fixed_bypass_frac = true; + opt_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + opt_par.m_fixed_bypass_frac = true; } else { // optimized - ms_opt_des_par.m_bypass_frac_guess = 0.3; - ms_opt_des_par.m_fixed_bypass_frac = false; + opt_par.m_bypass_frac_guess = 0.3; + opt_par.m_fixed_bypass_frac = false; } // LTR HTR UA Ratio - ms_opt_des_par.m_LT_frac_guess = 0.5; - ms_opt_des_par.m_fixed_LT_frac = false; + opt_par.m_LT_frac_guess = 0.5; + opt_par.m_fixed_LT_frac = false; if (ms_auto_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_auto_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) { - ms_opt_des_par.m_fixed_LT_frac = true; + opt_par.m_fixed_LT_frac = true; } // Set Design Method - if (ms_opt_des_par.m_fixed_LT_frac == true) - ms_opt_des_par.m_design_method = 3; + if (opt_par.m_fixed_LT_frac == true) + opt_par.m_design_method = 3; else - ms_opt_des_par.m_design_method = 2; + opt_par.m_design_method = 2; } // Find optimal inputs - S_sco2_htrbp_in optimal_inputs_out; - error_code = optimize_cycle(ms_auto_opt_des_par, ms_opt_des_par, optimal_inputs_out); + C_sco2_htrbp_core::S_sco2_htrbp_in optimal_inputs_out; + error_code = optimize_bp(ms_auto_opt_des_par, opt_par, optimal_inputs_out); if (error_code != 0) return; // Run Optimal Case - m_optimal_htrbp_core.SetInputs(optimal_inputs_out); - error_code = m_optimal_htrbp_core.Solve(); + m_optimal_htrbp_core.set_inputs(optimal_inputs_out); + error_code = m_optimal_htrbp_core.solve(); if (error_code != 0) return; // Finalize Design (pass in reference to solved parameters) - error_code = m_optimal_htrbp_core.FinalizeDesign(ms_des_solved); + error_code = m_optimal_htrbp_core.finalize_design(ms_des_solved); } -void C_HTRBypass_Cycle::auto_opt_design_hit_eta_core(int& error_code) +/// +/// Core function to optimize cycle for target eta (variable total UA) +/// +void C_HTRBypass_Cycle::auto_opt_design_hit_eta_core(int& error_code, double eta_thermal_target) { + // Create 'ms_opt_des_par' for Design Variables + S_opt_design_parameters opt_par; + { + // Target Thermal Efficiency + opt_par.m_eta_thermal_target = eta_thermal_target; + + // Max Pressure + double best_P_high = m_P_high_limit; //[kPa] + double PR_mc_guess = 2.5; //[-] + opt_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] + if (!opt_par.m_fixed_P_mc_out) + { + double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] + + //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); + best_P_high = m_P_high_limit; + } + opt_par.m_P_mc_out_guess = best_P_high; //[kPa] + //ms_opt_des_par.m_fixed_P_mc_out = true; + + // Pressure Ratio (min pressure) + opt_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] + if (opt_par.m_fixed_PR_HP_to_LP) + { + opt_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + } + else + { + opt_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] + } + + // Is recompression fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) + { // fixed + opt_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); + opt_par.m_fixed_recomp_frac = true; + } + else + { // optimized + opt_par.m_recomp_frac_guess = 0.3; + opt_par.m_fixed_recomp_frac = false; + } + + // Is bypass fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_bypass_ok <= 0.0) + { // fixed + opt_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); + opt_par.m_fixed_bypass_frac = true; + } + else + { // optimized + opt_par.m_bypass_frac_guess = 0.3; + opt_par.m_fixed_bypass_frac = false; + } + + // LTR HTR UA Ratio (cannot be fixed because design method is varying total UA) + opt_par.m_LT_frac_guess = 0.5; + opt_par.m_fixed_LT_frac = false; + + } + + // Set design method (it is 1, because total UA is optimized for target eta) + opt_par.m_design_method = 1; + + // Select min and max values + opt_par.m_UA_recup_total_max = ms_des_limits.m_UA_net_power_ratio_max * m_W_dot_net; //[kW/K] + opt_par.m_UA_recup_total_min = ms_des_limits.m_UA_net_power_ratio_min * m_W_dot_net; //[kW/K] + + S_auto_opt_design_parameters auto_par = ms_auto_opt_des_par; + + // Optimize Total UA + C_sco2_htrbp_core::S_sco2_htrbp_in optimal_inputs; + error_code = optimize_totalUA(auto_par, opt_par, optimal_inputs); + if (error_code != 0) + return; + + // Run Optimal Core model and finalize design + m_optimal_htrbp_core.reset(); + m_optimal_htrbp_core.set_inputs(optimal_inputs); + error_code = m_optimal_htrbp_core.solve(); + if (error_code != 0) + return; + + // Finalize Design (pass in reference to solved parameters) + error_code = m_optimal_htrbp_core.finalize_design(ms_des_solved); + + return; } +/// +/// Optimize Total Recuperator UA +/// totalUA -> bp -> UA split, pressure, recomp +/// +/// +/// +/// +/// +int C_HTRBypass_Cycle::optimize_totalUA(const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + C_sco2_htrbp_core::S_sco2_htrbp_in& optimal_inputs) +{ + // Validate Inputs + { + if (std::isnan(opt_par.m_eta_thermal_target) || + std::isnan(opt_par.m_UA_recup_total_min) || + std::isnan(opt_par.m_UA_recup_total_max)) + { + std::string warning_msg = "The target eta, and max and min UA need to be defined in S_opt_design_parameters"; + return -1; + } + } + + // Create Optimizer + nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); + int error_code = -1; + + std::vector lb = { opt_par.m_UA_recup_total_min }; + std::vector ub = { opt_par.m_UA_recup_total_max }; + double UA_recup_guess = (opt_par.m_UA_recup_total_max + opt_par.m_UA_recup_total_min) / 2.0; // [kW/K] + + opt_des_cycle.set_lower_bounds(lb); + opt_des_cycle.set_upper_bounds(ub); + opt_des_cycle.set_initial_step(1000); + //opt_des_cycle.set_xtol_rel(ms_auto_opt_des_par.m_des_opt_tol); + opt_des_cycle.set_xtol_rel(1); + opt_des_cycle.set_maxeval(50); + + // Make Tuple to pass in parameters + std::tuple par_tuple = { this, &auto_par, &opt_par }; + + // Set max objective function + std::vector x; + x.push_back(UA_recup_guess); + opt_des_cycle.set_max_objective(nlopt_optimize_totalUA_func, &par_tuple); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' + double max_f = std::numeric_limits::quiet_NaN(); + + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + + /// Check to make sure optimizer worked... + if (opt_des_cycle.get_force_stop()) + { + int w = 0; + } + + // Assign Total UA + double total_UA = x[0]; + ms_auto_opt_des_par.m_UA_rec_total = total_UA; + + // Have Total UA, now rerun optimizer to get other variables (redundant but shouldn't be very costly) + C_sco2_htrbp_core::S_sco2_htrbp_in optimal_inputs_case; + error_code = optimize_bp(ms_auto_opt_des_par, opt_par, optimal_inputs_case); + + if (error_code != 0) + return error_code; + + // Assign Optimal Inputs + optimal_inputs = optimal_inputs_case; + + return error_code; +} /// -/// Optimize cycle (bypass outer loop, which calls inner loop for other design variables) +/// Optimize Bypass Fraction +/// totalUA -> bp -> UA split, pressure, recomp /// -int C_HTRBypass_Cycle::optimize_cycle(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& optimal_inputs) +/// +/// +/// +/// +int C_HTRBypass_Cycle::optimize_bp(const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + C_sco2_htrbp_core::S_sco2_htrbp_in& optimal_inputs) { // Set up baseline core inputs - S_sco2_htrbp_in core_inputs; + C_sco2_htrbp_core::S_sco2_htrbp_in core_inputs; { // From Auto Opt Design Parameters @@ -1040,14 +1213,14 @@ int C_HTRBypass_Cycle::optimize_cycle(const S_auto_opt_design_parameters& auto_p } // Declare Optimal Inputs Case - S_sco2_htrbp_in optimal_inputs_final; + C_sco2_htrbp_core::S_sco2_htrbp_in optimal_inputs_final; // Bypass is Variable, optimize other variables WITHIN bp optimizer if (opt_par.m_fixed_bypass_frac == false) { // Reset Metrics m_opt_obj_internal_only = -1000000000000000; - m_optimal_inputs_internal_only = S_sco2_htrbp_in(); + m_optimal_inputs_internal_only = C_sco2_htrbp_core::S_sco2_htrbp_in(); // Create Optimizer nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); @@ -1064,7 +1237,7 @@ int C_HTRBypass_Cycle::optimize_cycle(const S_auto_opt_design_parameters& auto_p // Set up Core Model that will be passed to objective function C_sco2_htrbp_core htrbp_core; - htrbp_core.SetInputs(core_inputs); + htrbp_core.set_inputs(core_inputs); // Make Tuple to pass in parameters std::tuple par_tuple = { this, &auto_par, &opt_par, &htrbp_core }; @@ -1072,7 +1245,7 @@ int C_HTRBypass_Cycle::optimize_cycle(const S_auto_opt_design_parameters& auto_p // Set max objective function std::vector x; x.push_back(0.1); - opt_des_cycle.set_max_objective(nlopt_opt_cycle_func, &par_tuple); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' + opt_des_cycle.set_max_objective(nlopt_optimize_bp_func, &par_tuple); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' double max_f = std::numeric_limits::quiet_NaN(); nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); @@ -1087,15 +1260,15 @@ int C_HTRBypass_Cycle::optimize_cycle(const S_auto_opt_design_parameters& auto_p optimal_inputs_final = m_optimal_inputs_internal_only; // Clear Optimal Input Field - m_optimal_inputs_internal_only = S_sco2_htrbp_in(); + m_optimal_inputs_internal_only = C_sco2_htrbp_core::S_sco2_htrbp_in(); } // Bypass is Fixed, optimize other variables else { - S_sco2_htrbp_in optimal_inputs_final_temporary; - int error_code = opt_nonbp_par(auto_par, opt_par, core_inputs, optimal_inputs_final_temporary); + C_sco2_htrbp_core::S_sco2_htrbp_in optimal_inputs_final_temporary; + int error_code = optimize_nonbp(auto_par, opt_par, core_inputs, optimal_inputs_final_temporary); if (error_code != 0) return error_code; @@ -1109,17 +1282,18 @@ int C_HTRBypass_Cycle::optimize_cycle(const S_auto_opt_design_parameters& auto_p } /// -/// Optimize variables OTHER THAN bypass fraction -/// Auto par are from python -/// opt par process the optimized variables from auto par -/// core_inputs are all of the constant known inputs -/// optimal inputs is the result, optimal case +/// Optimize internal variables (UA split, pressure, recomp) +/// totalUA -> bp -> UA split, pressure, recomp /// +/// +/// +/// +/// /// -int C_HTRBypass_Cycle::opt_nonbp_par(const S_auto_opt_design_parameters& auto_par, - const S_opt_design_parameters& opt_par, - S_sco2_htrbp_in& core_inputs, - S_sco2_htrbp_in& optimal_inputs) +int C_HTRBypass_Cycle::optimize_nonbp(const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + C_sco2_htrbp_core::S_sco2_htrbp_in& core_inputs, + C_sco2_htrbp_core::S_sco2_htrbp_in& optimal_inputs) { // Add Applicable Design Variables to Optimizer int index = 0; @@ -1171,7 +1345,7 @@ int C_HTRBypass_Cycle::opt_nonbp_par(const S_auto_opt_design_parameters& auto_pa // Make Optimizer (if there are variables to be optimized) int error_code = 0; - S_sco2_htrbp_in optimal_inputs_internal; + C_sco2_htrbp_core::S_sco2_htrbp_in optimal_inputs_internal; if (index > 0) { // Set up instance of nlopt class and set optimization parameters @@ -1184,14 +1358,14 @@ int C_HTRBypass_Cycle::opt_nonbp_par(const S_auto_opt_design_parameters& auto_pa // Set up Core Model that will be passed to objective function C_sco2_htrbp_core htrbp_core; - htrbp_core.SetInputs(core_inputs); + htrbp_core.set_inputs(core_inputs); // Make Tuple to pass in parameters std::tuple par_tuple = { this, &auto_par, &opt_par, &htrbp_core }; // Set max objective function - opt_des_cycle.set_max_objective(nlopt_opt_nonbp_par_func, &par_tuple); + opt_des_cycle.set_max_objective(nlopt_optimize_nonbp_func, &par_tuple); double max_f = std::numeric_limits::quiet_NaN(); nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); @@ -1218,8 +1392,8 @@ int C_HTRBypass_Cycle::opt_nonbp_par(const S_auto_opt_design_parameters& auto_pa // Simulate Case (don't actually need to run...) C_sco2_htrbp_core core_model; - core_model.SetInputs(core_inputs); - error_code = core_model.Solve(); + core_model.set_inputs(core_inputs); + error_code = core_model.solve(); } // Set Optimal Inputs @@ -1229,12 +1403,12 @@ int C_HTRBypass_Cycle::opt_nonbp_par(const S_auto_opt_design_parameters& auto_pa } /// -/// Take x inputs from optimizer results, write appropriate values to S_sco2_htrbp_in +/// Take optimizer array 'x', write appropriate values to S_sco2_htrbp_in /// int C_HTRBypass_Cycle::x_to_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, - S_sco2_htrbp_in &core_inputs) + C_sco2_htrbp_core::S_sco2_htrbp_in &core_inputs) { // 'x' is array of inputs either being adjusted by optimizer or set constant // Finish defining core_inputs based on current 'x' values @@ -1321,9 +1495,12 @@ int C_HTRBypass_Cycle::x_to_inputs(const std::vector& x, } /// -/// Set Optimized Variables to NaN, to protect them from misuse +/// Set optimized variables to NaN, to protect them from misuse /// -int C_HTRBypass_Cycle::clear_x_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in& core_inputs) +int C_HTRBypass_Cycle::clear_x_inputs(const std::vector& x, + const S_auto_opt_design_parameters auto_par, + const S_opt_design_parameters opt_par, + C_sco2_htrbp_core::S_sco2_htrbp_in& core_inputs) { // 'x' is array of inputs either being adjusted by optimizer or set constant // Finish defining core_inputs based on current 'x' values @@ -1361,7 +1538,10 @@ int C_HTRBypass_Cycle::clear_x_inputs(const std::vector& x, const S_auto return 0; } -double C_HTRBypass_Cycle::calc_penalty(double target, double calc, double span) +/// +/// Calculate Temperature penalty, given target and calculated temperature +/// +double C_HTRBypass_Cycle::calc_T_penalty(double target, double calc, double span) { double percent_error = std::abs(target - calc) / span; //double penalty = 10.0 * (100.0 * sigmoid(percent_error) - 0.5); @@ -1371,7 +1551,12 @@ double C_HTRBypass_Cycle::calc_penalty(double target, double calc, double span) return penalty; } -double C_HTRBypass_Cycle::calc_objective(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, const C_sco2_htrbp_core& htrbp_core) +/// +/// Calculate Objective Value (does not consider total UA minimization) +/// +double C_HTRBypass_Cycle::calc_objective(const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + const C_sco2_htrbp_core& htrbp_core) { double obj = 0; double eta = htrbp_core.m_outputs.m_eta_thermal; @@ -1381,9 +1566,6 @@ double C_HTRBypass_Cycle::calc_objective(const S_auto_opt_design_parameters& aut { double eta_error = std::min(eta - opt_par.m_eta_thermal_target, 0.0); obj = 1.0 - std::abs(eta_error); - - // Penalize for total UA (lower is better) - } // Maximize thermal efficiency else @@ -1409,7 +1591,7 @@ double C_HTRBypass_Cycle::calc_objective(const S_auto_opt_design_parameters& aut span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; } - penalty = calc_penalty(m_T_target, temp_calc, span); + penalty = calc_T_penalty(m_T_target, temp_calc, span); } obj = obj - penalty; @@ -1417,378 +1599,90 @@ double C_HTRBypass_Cycle::calc_objective(const S_auto_opt_design_parameters& aut return obj; } -// ********************************************************************************* END PRIVATE methods - -// ********************************************************************************** PUBLIC C_HTRBypass_Cycle (: C_sco2_cycle_core) - -void C_HTRBypass_Cycle::set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, - double dT_bp, double htf_phx_cold_approach, double set_HTF_mdot, - int T_target_is_HTF) -{ - m_T_HTF_PHX_inlet = T_htf_phx_in; // K - m_T_target = T_target; // K - m_T_target_is_HTF = T_target_is_HTF; - m_cp_HTF = cp_htf; // kJ/kg K - m_dT_BP = dT_bp; - m_HTF_PHX_cold_approach = htf_phx_cold_approach; - m_set_HTF_mdot = set_HTF_mdot; - - m_is_bp_par_set = true; -} - +// ********************************************************************************** PUBLIC Methods C_HTRBypass_Cycle (: C_sco2_cycle_core) /// -/// Objective Function for total UA (outermost layer) -/// Total UA -> Bypass Fraction -> pressure, split UA, recomp frac +/// Optimize Cycle Design for FIXED total recuperator UA /// -/// ONLY Objective Value -double C_HTRBypass_Cycle::opt_total_UA_return_objective_metric(const std::vector& x, - const S_auto_opt_design_parameters& auto_par, - const S_opt_design_parameters& opt_par - ) +/// +int C_HTRBypass_Cycle::auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in) { - // Copy optimal parameters - S_auto_opt_design_parameters auto_par_internal = auto_par; - S_opt_design_parameters opt_par_internal = opt_par; - - // Assign Total Recuperator UA - double total_UA = x[0]; - auto_par_internal.m_UA_rec_total = total_UA; - - // Optimize all internal variables (bypass_frac -> recomp frac, UA ratio, pressure ratio) - S_sco2_htrbp_in optimal_inputs_case; - int error_code = optimize_cycle(auto_par_internal, opt_par_internal, optimal_inputs_case); - - if (error_code != 0) - return -100000000000000000; - - // ^ Get optimal core_inputs from here - - // Run Optimal Case, return objective function - C_sco2_htrbp_core htrbp_core; - htrbp_core.SetInputs(optimal_inputs_case); - error_code = htrbp_core.Solve(); - if (error_code != 0) - return -100000000000000000; - - // Calculate Objective Value - double obj = calc_objective(auto_par_internal, opt_par_internal, htrbp_core); - - // This objectve ^ targets a thermal efficiency (and tries to hit a temperature, if applicable) - // Need to incentivize lower UA value - - // Hitting eta and temperature is more important than low UA - double UA_percent = (total_UA - opt_par.m_UA_recup_total_min) / (opt_par.m_UA_recup_total_max - opt_par.m_UA_recup_total_min); // Lower is closer to 0 - double UA_penalty = UA_percent; + if (m_is_bp_par_set == false) + { + std::string warning_msg = "BP parameters are not defined"; + return -1; + } - // Increase obj scale (making eta and temp more weighted) - double obj_weighted = obj * 1e2; + ms_auto_opt_des_par = auto_opt_des_par_in; - // Subtract UA_penalty - obj_weighted = obj_weighted - UA_penalty; + int auto_opt_des_error_code = 0; - //double eff = htrbp_core.m_outputs.m_eta_thermal; - - //// If variable bypass fraction or targeting temperature - //double penalty = 0; - //if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) - //{ - // double temp_calc = 0; - // double span = 0; - - // if (m_T_target_is_HTF == 0) - // { - // temp_calc = htrbp_core.m_outputs.m_temp[MIXER_OUT]; - // span = htrbp_core.m_outputs.m_temp[TURB_IN] - m_T_target; - // } - // else - // { - // temp_calc = htrbp_core.m_outputs.m_T_HTF_BP_outlet; - // span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; - // } - - // penalty = calc_penalty(m_T_target, temp_calc, span); - //} - - //double obj = eff - penalty; - - //if (obj > m_opt_obj_internal_only) - //{ - // m_opt_obj_internal_only = obj; - // m_optimal_inputs_internal_only = optimal_inputs_case; - //} + auto_opt_design_core(auto_opt_des_error_code); - return obj_weighted; + return auto_opt_des_error_code; } /// -/// Objective Function for BYPASS optimization (calls internal optimization for other variables) -/// Total UA -> Bypass Fraction -> pressure, split UA, recomp frac +/// Optimize Cycle design to hit target eta (optimize total recuperator UA) /// -/// -/// -/// -/// +/// +/// /// -double C_HTRBypass_Cycle::opt_cycle_return_objective_metric(const std::vector& x, - const S_auto_opt_design_parameters& auto_par, - const S_opt_design_parameters& opt_par, - C_sco2_htrbp_core& htrbp_core) +int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg) { - if (opt_par.m_fixed_bypass_frac == true) + int error_code = -1; + + if (m_is_bp_par_set == false) { - throw std::exception("Optimizing bypass fraction even though it is fixed"); + error_msg = "BP parameters are not defined"; + return -1; } - // Set Bypass Fraction - htrbp_core.m_inputs.m_bypass_frac = x[0]; - - // Optimize all other variables - S_sco2_htrbp_in optimal_inputs_case; - opt_nonbp_par(auto_par, opt_par, htrbp_core.m_inputs, optimal_inputs_case); - - // ^ Get optimal core_inputs from here - - // Run Optimal Case, return objective function - - htrbp_core.SetInputs(optimal_inputs_case); - int error_code = htrbp_core.Solve(); - if (error_code != 0) - return -100000000000000000; - - // Calculate Objective Value - double obj = calc_objective(auto_par, opt_par, htrbp_core); + // Fill in 'ms_auto_opt_des_par' from input + { + ms_auto_opt_des_par.m_UA_rec_total = std::numeric_limits::quiet_NaN(); // ***** This method finds the UA required to hit the input efficiency! ***** + // LTR thermal design + ms_auto_opt_des_par.m_LTR_target_code = auto_opt_des_hit_eta_in.m_LTR_target_code; //[-] + ms_auto_opt_des_par.m_LTR_UA = auto_opt_des_hit_eta_in.m_LTR_UA; //[kW/K] + ms_auto_opt_des_par.m_LTR_min_dT = auto_opt_des_hit_eta_in.m_LTR_min_dT; //[K] + ms_auto_opt_des_par.m_LTR_eff_target = auto_opt_des_hit_eta_in.m_LTR_eff_target; //[-] + ms_auto_opt_des_par.m_LTR_eff_max = auto_opt_des_hit_eta_in.m_LTR_eff_max; + ms_auto_opt_des_par.m_LTR_od_UA_target_type = auto_opt_des_hit_eta_in.m_LTR_od_UA_target_type; + // HTR thermal design + ms_auto_opt_des_par.m_HTR_target_code = auto_opt_des_hit_eta_in.m_HTR_target_code; //[-] + ms_auto_opt_des_par.m_HTR_UA = auto_opt_des_hit_eta_in.m_HTR_UA; //[kW/K] + ms_auto_opt_des_par.m_HTR_min_dT = auto_opt_des_hit_eta_in.m_HTR_min_dT; //[K] + ms_auto_opt_des_par.m_HTR_eff_target = auto_opt_des_hit_eta_in.m_HTR_eff_target; //[-] + ms_auto_opt_des_par.m_HTR_eff_max = auto_opt_des_hit_eta_in.m_HTR_eff_max; //[-] + ms_auto_opt_des_par.m_HTR_od_UA_target_type = auto_opt_des_hit_eta_in.m_HTR_od_UA_target_type; + // + ms_auto_opt_des_par.m_des_tol = auto_opt_des_hit_eta_in.m_des_tol; //[-] Convergence tolerance + ms_auto_opt_des_par.m_des_opt_tol = auto_opt_des_hit_eta_in.m_des_opt_tol; //[-] Optimization tolerance + ms_auto_opt_des_par.m_is_recomp_ok = auto_opt_des_hit_eta_in.m_is_recomp_ok; //[-] 1 = yes, 0 = no, other = invalid + ms_auto_opt_des_par.m_is_bypass_ok = auto_opt_des_hit_eta_in.m_is_bypass_ok; //[-] 1 = yes, 0 = no, other = invalid - //double eff = htrbp_core.m_outputs.m_eta_thermal; + ms_auto_opt_des_par.m_is_des_air_cooler = auto_opt_des_hit_eta_in.m_is_des_air_cooler; //[-] - //// If variable bypass fraction or targeting temperature - //double penalty = 0; - //if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) - //{ - // double temp_calc = 0; - // double span = 0; + ms_auto_opt_des_par.m_des_objective_type = auto_opt_des_hit_eta_in.m_des_objective_type; //[-] + ms_auto_opt_des_par.m_min_phx_deltaT = auto_opt_des_hit_eta_in.m_min_phx_deltaT; //[C] - // if (m_T_target_is_HTF == 0) - // { - // temp_calc = htrbp_core.m_outputs.m_temp[MIXER_OUT]; - // span = htrbp_core.m_outputs.m_temp[TURB_IN] - m_T_target; - // } - // else - // { - // temp_calc = htrbp_core.m_outputs.m_T_HTF_BP_outlet; - // span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; - // } + ms_auto_opt_des_par.mf_callback_log = auto_opt_des_hit_eta_in.mf_callback_log; + ms_auto_opt_des_par.mp_mf_active = auto_opt_des_hit_eta_in.mp_mf_active; - // penalty = calc_penalty(m_T_target, temp_calc, span); - //} + ms_auto_opt_des_par.m_fixed_P_mc_out = auto_opt_des_hit_eta_in.m_fixed_P_mc_out; //[-] - //double obj = eff - penalty; + ms_auto_opt_des_par.m_PR_HP_to_LP_guess = auto_opt_des_hit_eta_in.m_PR_HP_to_LP_guess; //[-] Initial guess for ratio of P_mc_out to P_mc_in + ms_auto_opt_des_par.m_fixed_PR_HP_to_LP = auto_opt_des_hit_eta_in.m_fixed_PR_HP_to_LP; //[-] if true, ratio of P_mc_out to P_mc_in is fixed at PR_mc_guess + } - if (obj > m_opt_obj_internal_only) + // Check that simple/recomp flag is set + if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && + ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) { - m_opt_obj_internal_only = obj; - m_optimal_inputs_internal_only = optimal_inputs_case; + throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" + " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); } - // Reset htrbp_core - htrbp_core.m_inputs.m_bypass_frac = std::numeric_limits::quiet_NaN(); - htrbp_core.m_outputs.Init(); - - return obj; -} - -/// -/// Objective Function for NON Bypass optimization -/// Total UA -> Bypass Fraction -> pressure, split UA, recomp frac -/// -/// ONLY Objective Value -double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, - const S_auto_opt_design_parameters& auto_par, - const S_opt_design_parameters& opt_par, - C_sco2_htrbp_core& htrbp_core) -{ - // Modify Core Inputs with Variable Parameters - int error_code = x_to_inputs(x, auto_par, opt_par, htrbp_core.m_inputs); - - if (error_code != 0) - return -1000000000; - - // AT this point, will have fully defined core input struct - // Run the core model - error_code = htrbp_core.Solve(); - - // Set Objective - double objective_metric = -10000000000.0; - if (error_code == 0) - { - objective_metric = calc_objective(auto_par, opt_par, htrbp_core); - - //double eff = htrbp_core.m_outputs.m_eta_thermal; - - //// If variable bypass fraction or targeting temperature - //double penalty = 0; - //if (opt_par.m_fixed_bypass_frac == false || auto_par.m_des_objective_type == 2) - //{ - // double temp_calc = 0; - // double span = 0; - - // if (m_T_target_is_HTF == 0) - // { - // temp_calc = htrbp_core.m_outputs.m_temp[MIXER_OUT]; - // span = htrbp_core.m_outputs.m_temp[TURB_IN] - m_T_target; - // } - // else - // { - // temp_calc = htrbp_core.m_outputs.m_T_HTF_BP_outlet; - // span = htrbp_core.m_inputs.m_T_HTF_PHX_inlet - m_T_target; - // } - - // penalty = calc_penalty(m_T_target, temp_calc, span); - //} - - //objective_metric = eff - penalty; - - /*if (objective_metric > m_objective_metric_opt) - { - ms_des_par_optimal = ms_des_par; - m_objective_metric_opt = objective_metric; - }*/ - } - - // Clear Optimized Inputs - clear_x_inputs(x, auto_par, opt_par, htrbp_core.m_inputs); - - return objective_metric; -} - - - - - - -int C_HTRBypass_Cycle::auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in) -{ - ms_auto_opt_des_par = auto_opt_des_par_in; - - int auto_opt_des_error_code = 0; - - auto_opt_design_core(auto_opt_des_error_code); - - return auto_opt_des_error_code; -} - - -// This optimizes the TOTAL recuperator UA to hit a specific eta -int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg) -{ - // Fill in 'ms_auto_opt_des_par' from input - { - ms_auto_opt_des_par.m_UA_rec_total = std::numeric_limits::quiet_NaN(); // ***** This method finds the UA required to hit the input efficiency! ***** - // LTR thermal design - ms_auto_opt_des_par.m_LTR_target_code = auto_opt_des_hit_eta_in.m_LTR_target_code; //[-] - ms_auto_opt_des_par.m_LTR_UA = auto_opt_des_hit_eta_in.m_LTR_UA; //[kW/K] - ms_auto_opt_des_par.m_LTR_min_dT = auto_opt_des_hit_eta_in.m_LTR_min_dT; //[K] - ms_auto_opt_des_par.m_LTR_eff_target = auto_opt_des_hit_eta_in.m_LTR_eff_target; //[-] - ms_auto_opt_des_par.m_LTR_eff_max = auto_opt_des_hit_eta_in.m_LTR_eff_max; - ms_auto_opt_des_par.m_LTR_od_UA_target_type = auto_opt_des_hit_eta_in.m_LTR_od_UA_target_type; - // HTR thermal design - ms_auto_opt_des_par.m_HTR_target_code = auto_opt_des_hit_eta_in.m_HTR_target_code; //[-] - ms_auto_opt_des_par.m_HTR_UA = auto_opt_des_hit_eta_in.m_HTR_UA; //[kW/K] - ms_auto_opt_des_par.m_HTR_min_dT = auto_opt_des_hit_eta_in.m_HTR_min_dT; //[K] - ms_auto_opt_des_par.m_HTR_eff_target = auto_opt_des_hit_eta_in.m_HTR_eff_target; //[-] - ms_auto_opt_des_par.m_HTR_eff_max = auto_opt_des_hit_eta_in.m_HTR_eff_max; //[-] - ms_auto_opt_des_par.m_HTR_od_UA_target_type = auto_opt_des_hit_eta_in.m_HTR_od_UA_target_type; - // - ms_auto_opt_des_par.m_des_tol = auto_opt_des_hit_eta_in.m_des_tol; //[-] Convergence tolerance - ms_auto_opt_des_par.m_des_opt_tol = auto_opt_des_hit_eta_in.m_des_opt_tol; //[-] Optimization tolerance - ms_auto_opt_des_par.m_is_recomp_ok = auto_opt_des_hit_eta_in.m_is_recomp_ok; //[-] 1 = yes, 0 = no, other = invalid - ms_auto_opt_des_par.m_is_bypass_ok = auto_opt_des_hit_eta_in.m_is_bypass_ok; //[-] 1 = yes, 0 = no, other = invalid - - ms_auto_opt_des_par.m_is_des_air_cooler = auto_opt_des_hit_eta_in.m_is_des_air_cooler; //[-] - - ms_auto_opt_des_par.m_des_objective_type = auto_opt_des_hit_eta_in.m_des_objective_type; //[-] - ms_auto_opt_des_par.m_min_phx_deltaT = auto_opt_des_hit_eta_in.m_min_phx_deltaT; //[C] - - ms_auto_opt_des_par.mf_callback_log = auto_opt_des_hit_eta_in.mf_callback_log; - ms_auto_opt_des_par.mp_mf_active = auto_opt_des_hit_eta_in.mp_mf_active; - - ms_auto_opt_des_par.m_fixed_P_mc_out = auto_opt_des_hit_eta_in.m_fixed_P_mc_out; //[-] - - ms_auto_opt_des_par.m_PR_HP_to_LP_guess = auto_opt_des_hit_eta_in.m_PR_HP_to_LP_guess; //[-] Initial guess for ratio of P_mc_out to P_mc_in - ms_auto_opt_des_par.m_fixed_PR_HP_to_LP = auto_opt_des_hit_eta_in.m_fixed_PR_HP_to_LP; //[-] if true, ratio of P_mc_out to P_mc_in is fixed at PR_mc_guess - } - - // Check that simple/recomp flag is set - if (ms_auto_opt_des_par.m_is_recomp_ok < -1.0 || (ms_auto_opt_des_par.m_is_recomp_ok > 0 && - ms_auto_opt_des_par.m_is_recomp_ok != 1.0 && ms_auto_opt_des_par.m_is_recomp_ok != 2.0)) - { - throw(C_csp_exception("C_RecompCycle::auto_opt_design_core(...) requires that ms_auto_opt_des_par.m_is_recomp_ok" - " is either between -1 and 0 (fixed recompression fraction) or equal to 1 (recomp allowed)\n")); - } - - // Complete 'ms_opt_des_par' for Design Variables - { - // Target Thermal Efficiency - ms_opt_des_par.m_eta_thermal_target = auto_opt_des_hit_eta_in.m_eta_thermal; - - // Max Pressure - double best_P_high = m_P_high_limit; //[kPa] - double PR_mc_guess = 2.5; //[-] - ms_opt_des_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] - if (!ms_opt_des_par.m_fixed_P_mc_out) - { - double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] - - //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); - best_P_high = m_P_high_limit; - } - ms_opt_des_par.m_P_mc_out_guess = best_P_high; //[kPa] - //ms_opt_des_par.m_fixed_P_mc_out = true; - - // Pressure Ratio (min pressure) - ms_opt_des_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] - if (ms_opt_des_par.m_fixed_PR_HP_to_LP) - { - ms_opt_des_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] - } - else - { - ms_opt_des_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] - } - - // Is recompression fraction fixed or optimized? - if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) - { // fixed - ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); - ms_opt_des_par.m_fixed_recomp_frac = true; - } - else - { // optimized - ms_opt_des_par.m_recomp_frac_guess = 0.3; - ms_opt_des_par.m_fixed_recomp_frac = false; - } - - // Is bypass fraction fixed or optimized? - if (ms_auto_opt_des_par.m_is_bypass_ok <= 0.0) - { // fixed - ms_opt_des_par.m_bypass_frac_guess = std::abs(ms_auto_opt_des_par.m_is_bypass_ok); - ms_opt_des_par.m_fixed_bypass_frac = true; - } - else - { // optimized - ms_opt_des_par.m_bypass_frac_guess = 0.3; - ms_opt_des_par.m_fixed_bypass_frac = false; - } - - // LTR HTR UA Ratio (cannot be fixed because design method is varying total UA) - ms_opt_des_par.m_LT_frac_guess = 0.5; - ms_opt_des_par.m_fixed_LT_frac = false; - - } - - // Set design method (it is 1, because total UA is optimized for target eta) - ms_opt_des_par.m_design_method = 1; - // Validate Inputs error_msg = ""; { @@ -1970,139 +1864,152 @@ int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_paramet } } - // Create Optimizer - nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); + // Optimize + auto_opt_design_hit_eta_core(error_code, auto_opt_des_hit_eta_in.m_eta_thermal); - // Select min and max values - ms_opt_des_par.m_UA_recup_total_max = ms_des_limits.m_UA_net_power_ratio_max * m_W_dot_net; //[kW/K] - ms_opt_des_par.m_UA_recup_total_min = ms_des_limits.m_UA_net_power_ratio_min * m_W_dot_net; //[kW/K] - double UA_recup_guess = (ms_opt_des_par.m_UA_recup_total_max + ms_opt_des_par.m_UA_recup_total_min) / 2.0; //[kW/K] + return error_code; +} - std::vector lb = { ms_opt_des_par.m_UA_recup_total_min }; - std::vector ub = { ms_opt_des_par.m_UA_recup_total_max }; +// ********************************************************************************** PUBLIC Objective Functions (internal use only) - opt_des_cycle.set_lower_bounds(lb); - opt_des_cycle.set_upper_bounds(ub); - opt_des_cycle.set_initial_step(1000); - //opt_des_cycle.set_xtol_rel(ms_auto_opt_des_par.m_des_opt_tol); - opt_des_cycle.set_xtol_rel(1); - opt_des_cycle.set_maxeval(50); +/// +/// Objective Function for total UA (outermost layer) +/// Total UA -> Bypass Fraction -> pressure, split UA, recomp frac +/// +/// ONLY Objective Value +double C_HTRBypass_Cycle::optimize_totalUA_return_objective_metric(const std::vector& x, + const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par +) +{ + // Copy optimal parameters + S_auto_opt_design_parameters auto_par_internal = auto_par; + S_opt_design_parameters opt_par_internal = opt_par; - S_auto_opt_design_parameters auto_par = ms_auto_opt_des_par; - S_opt_design_parameters opt_par = ms_opt_des_par; + // Assign Total Recuperator UA + double total_UA = x[0]; + auto_par_internal.m_UA_rec_total = total_UA; - // Make Tuple to pass in parameters - std::tuple par_tuple = { this, &auto_par, &opt_par }; + // Optimize all internal variables (bypass_frac -> recomp frac, UA ratio, pressure ratio) + C_sco2_htrbp_core::S_sco2_htrbp_in optimal_inputs_case; + int error_code = optimize_bp(auto_par_internal, opt_par_internal, optimal_inputs_case); - // Set max objective function - std::vector x; - x.push_back(UA_recup_guess); - opt_des_cycle.set_max_objective(nlopt_opt_total_UA_func, &par_tuple); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' - double max_f = std::numeric_limits::quiet_NaN(); + if (error_code != 0) + return -100000000000000000; - nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + // ^ Get optimal core_inputs from here - /// Check to make sure optimizer worked... - if (opt_des_cycle.get_force_stop()) - { - int w = 0; - } + // Run Optimal Case, return objective function + C_sco2_htrbp_core htrbp_core; + htrbp_core.set_inputs(optimal_inputs_case); + error_code = htrbp_core.solve(); + if (error_code != 0) + return -100000000000000000; - // Assign Total UA - double total_UA = x[0]; - ms_auto_opt_des_par.m_UA_rec_total = total_UA; + // Calculate Objective Value + double obj = calc_objective(auto_par_internal, opt_par_internal, htrbp_core); - // Have Total UA, now rerun optimizer to get other variables (redundant but shouldn't be very costly) - S_sco2_htrbp_in optimal_inputs_case; - int error_code = optimize_cycle(ms_auto_opt_des_par, ms_opt_des_par, optimal_inputs_case); - if (error_code != 0) - return error_code; - - // Run Optimal Core model and finalize design - m_optimal_htrbp_core.Reset(); - m_optimal_htrbp_core.SetInputs(optimal_inputs_case); - error_code = m_optimal_htrbp_core.Solve(); - if (error_code != 0) - return error_code; + // This objectve ^ targets a thermal efficiency (and tries to hit a temperature, if applicable) + // Need to incentivize lower UA value - // Finalize Design (pass in reference to solved parameters) - error_code = m_optimal_htrbp_core.FinalizeDesign(ms_des_solved); + // Hitting eta and temperature is more important than low UA + double UA_percent = (total_UA - opt_par.m_UA_recup_total_min) / (opt_par.m_UA_recup_total_max - opt_par.m_UA_recup_total_min); // Lower is closer to 0 + double UA_penalty = UA_percent; - return error_code; -} + // Increase obj scale (making eta and temp more weighted) + double obj_weighted = obj * 1e2; + + // Subtract UA_penalty + obj_weighted = obj_weighted - UA_penalty; + return obj_weighted; +} +/// +/// Objective Function for BYPASS optimization (calls internal optimization for other variables) +/// Total UA -> Bypass Fraction -> pressure, split UA, recomp frac +/// +/// +double C_HTRBypass_Cycle::optimize_bp_return_objective_metric(const std::vector& x, + const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + C_sco2_htrbp_core& htrbp_core) +{ + if (opt_par.m_fixed_bypass_frac == true) + { + throw std::exception("Optimizing bypass fraction even though it is fixed"); + } + // Set Bypass Fraction + htrbp_core.m_inputs.m_bypass_frac = x[0]; + // Optimize all other variables + C_sco2_htrbp_core::S_sco2_htrbp_in optimal_inputs_case; + optimize_nonbp(auto_par, opt_par, htrbp_core.m_inputs, optimal_inputs_case); -// END legacy functions + // ^ Get optimal core_inputs from here -// Public Methods + // Run Optimal Case, return objective function + htrbp_core.set_inputs(optimal_inputs_case); + int error_code = htrbp_core.solve(); + if (error_code != 0) + return -100000000000000000; -void C_HTRBypass_Cycle::reset_ms_od_turbo_bal_csp_solved() -{ -} + // Calculate Objective Value + double obj = calc_objective(auto_par, opt_par, htrbp_core); -double nlopt_opt_total_UA_func(const std::vector& x, std::vector& grad, void* data) -{ - // Unpack Data Tuple - std::tuple* data_tuple - = static_cast*>(data); + if (obj > m_opt_obj_internal_only) + { + m_opt_obj_internal_only = obj; + m_optimal_inputs_internal_only = optimal_inputs_case; + } - C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); - const C_HTRBypass_Cycle::S_auto_opt_design_parameters* auto_opt_par = std::get<1>(*data_tuple); - const C_HTRBypass_Cycle::S_opt_design_parameters* opt_par = std::get<2>(*data_tuple); + // Reset htrbp_core + htrbp_core.m_inputs.m_bypass_frac = std::numeric_limits::quiet_NaN(); + htrbp_core.m_outputs.Init(); - if (frame != NULL) - return frame->opt_total_UA_return_objective_metric(x, *auto_opt_par, *opt_par); - else - return 0.0; + return obj; } -double nlopt_opt_cycle_func(const std::vector& x, std::vector& grad, void* data) +/// +/// Objective Function for NON Bypass optimization +/// Total UA -> Bypass Fraction -> pressure, split UA, recomp frac +/// +/// ONLY Objective Value +double C_HTRBypass_Cycle::optimize_nonbp_return_objective_metric(const std::vector& x, + const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + C_sco2_htrbp_core& htrbp_core) { - // Unpack Data Tuple - std::tuple* data_tuple - = static_cast*>(data); + // Modify Core Inputs with Variable Parameters + int error_code = x_to_inputs(x, auto_par, opt_par, htrbp_core.m_inputs); - C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); - const C_HTRBypass_Cycle::S_auto_opt_design_parameters* auto_opt_par = std::get<1>(*data_tuple); - const C_HTRBypass_Cycle::S_opt_design_parameters* opt_par = std::get<2>(*data_tuple); - C_sco2_htrbp_core* htrbp_core = std::get<3>(*data_tuple); + if (error_code != 0) + return -1000000000; - if (frame != NULL) - return frame->opt_cycle_return_objective_metric(x, *auto_opt_par, *opt_par, *htrbp_core); - else - return 0.0; -} + // AT this point, will have fully defined core input struct + // Run the core model + error_code = htrbp_core.solve(); -double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector& grad, void* data) -{ - // Unpack Data Tuple - std::tuple* data_tuple - = static_cast*>(data); + // Set Objective + double objective_metric = -10000000000.0; + if (error_code == 0) + { + objective_metric = calc_objective(auto_par, opt_par, htrbp_core); + } - C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); - const C_HTRBypass_Cycle::S_auto_opt_design_parameters* auto_opt_par = std::get<1>(*data_tuple); - const C_HTRBypass_Cycle::S_opt_design_parameters* opt_par = std::get<2>(*data_tuple); - C_sco2_htrbp_core* htrbp_core = std::get<3>(*data_tuple); + // Clear Optimized Inputs + clear_x_inputs(x, auto_par, opt_par, htrbp_core.m_inputs); - if (frame != NULL) - return frame->opt_nonbp_par_return_objective_metric(x, *auto_opt_par, *opt_par, *htrbp_core); - else - return 0.0; + return objective_metric; } +// ********************************************************************************** Off Design Functions -double sigmoid(const double val) -{ - return 1.0 / (1.0 + std::exp(-1.0 * val)); -} -double logit(const double val) +void C_HTRBypass_Cycle::reset_ms_od_turbo_bal_csp_solved() { - return std::log(val / (1.0 - val)); } int C_HTRBypass_Cycle::off_design_fix_shaft_speeds(S_od_par& od_phi_par_in, double od_tol) @@ -2156,4 +2063,64 @@ void C_HTRBypass_Cycle::estimate_od_turbo_operation(double T_mc_in, double P_mc_ } +// ********************************************************************************** PUBLIC Methods defined outside of any class + +double nlopt_optimize_totalUA_func(const std::vector& x, std::vector& grad, void* data) +{ + // Unpack Data Tuple + std::tuple* data_tuple + = static_cast*>(data); + + C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); + const C_HTRBypass_Cycle::S_auto_opt_design_parameters* auto_opt_par = std::get<1>(*data_tuple); + const C_HTRBypass_Cycle::S_opt_design_parameters* opt_par = std::get<2>(*data_tuple); + + if (frame != NULL) + return frame->optimize_totalUA_return_objective_metric(x, *auto_opt_par, *opt_par); + else + return 0.0; +} + +double nlopt_optimize_bp_func(const std::vector& x, std::vector& grad, void* data) +{ + // Unpack Data Tuple + std::tuple* data_tuple + = static_cast*>(data); + + C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); + const C_HTRBypass_Cycle::S_auto_opt_design_parameters* auto_opt_par = std::get<1>(*data_tuple); + const C_HTRBypass_Cycle::S_opt_design_parameters* opt_par = std::get<2>(*data_tuple); + C_sco2_htrbp_core* htrbp_core = std::get<3>(*data_tuple); + + if (frame != NULL) + return frame->optimize_bp_return_objective_metric(x, *auto_opt_par, *opt_par, *htrbp_core); + else + return 0.0; +} + +double nlopt_optimize_nonbp_func(const std::vector& x, std::vector& grad, void* data) +{ + // Unpack Data Tuple + std::tuple* data_tuple + = static_cast*>(data); + + C_HTRBypass_Cycle* frame = std::get<0>(*data_tuple); + const C_HTRBypass_Cycle::S_auto_opt_design_parameters* auto_opt_par = std::get<1>(*data_tuple); + const C_HTRBypass_Cycle::S_opt_design_parameters* opt_par = std::get<2>(*data_tuple); + C_sco2_htrbp_core* htrbp_core = std::get<3>(*data_tuple); + if (frame != NULL) + return frame->optimize_nonbp_return_objective_metric(x, *auto_opt_par, *opt_par, *htrbp_core); + else + return 0.0; +} + +double sigmoid(const double val) +{ + return 1.0 / (1.0 + std::exp(-1.0 * val)); +} + +double logit(const double val) +{ + return std::log(val / (1.0 - val)); +} diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 6b29be33d5..7011da2ed7 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -45,176 +45,181 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "nlopt.hpp" #include "nlopt_callbacks.h" -// Defines sco2 htr bypass input variables (no optimized variables) -struct S_sco2_htrbp_in + + +// This class is purely for solving the cycle +// No optimization +class C_sco2_htrbp_core { +public: - double m_P_mc_in; //[kPa] Compressor inlet pressure - double m_P_mc_out; //[kPa] Compressor outlet pressure - - // LTR thermal design - int m_LTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness - double m_LTR_UA; //[kW/K] target LTR conductance - double m_LTR_min_dT; //[K] target LTR minimum temperature difference - double m_LTR_eff_target; //[-] target LTR effectiveness - double m_LTR_eff_max; //[-] Maximum allowable effectiveness in LT recuperator - NS_HX_counterflow_eqs::E_UA_target_type m_LTR_od_UA_target_type; - int m_LTR_N_sub_hxrs; //[-] Number of sub-hxs to use in hx model - - // HTR thermal design - int m_HTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness - double m_HTR_UA; //[kW/K] target HTR conductance - double m_HTR_min_dT; //[K] target HTR min temperature difference - double m_HTR_eff_target; //[-] target HTR effectiveness - double m_HTR_eff_max; //[-] Maximum allowable effectiveness in HT recuperator - NS_HX_counterflow_eqs::E_UA_target_type m_HTR_od_UA_target_type; - int m_HTR_N_sub_hxrs; //[-] Number of sub-hxs to use in hx model - - double m_recomp_frac; //[-] Fraction of flow that bypasses the precooler and the main compressor at the design point - double m_bypass_frac; //[-] Fraction of flow that bypasses the HTR and passes through the Bypass HX - double m_des_tol; //[-] Convergence tolerance - - // Air cooler parameters - bool m_is_des_air_cooler; //[-] False will skip physical air cooler design. UA will not be available for cost models. - - - // Added - double m_W_dot_net_design; //[kWe] Target net cycle power - double m_T_mc_in; //[K] Compressor inlet temperature - double m_T_t_in; //[K] Turbine inlet temperature - double m_dT_BP; //[delta K/C] BYPASS_OUT - HTR_HP_OUT - std::vector m_DP_LTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) - std::vector m_DP_HTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) - std::vector m_DP_PC_main; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) - std::vector m_DP_PHX; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) - double m_eta_mc; //[-] design-point efficiency of the main compressor; isentropic if positive, polytropic if negative - double m_eta_t; //[-] design-point efficiency of the turbine; isentropic if positive, polytropic if negative - double m_eta_rc; //[-] design-point efficiency of the recompressor; isentropic if positive, polytropic if negative - double m_eta_generator; //[-] Mechanical-to-electrical efficiency of generator - double m_frac_fan_power; //[-] Fraction of total cycle power 'S_des_par_cycle_dep.m_W_dot_fan_des' consumed by air fan - double m_set_HTF_mdot; //[kg/s] > 0 set HTF mass flow, <= 0 use bypass approach temp to calculate HTF mdot - double m_cp_HTF; //[kJ/kg K] HTF specific heat - double m_T_HTF_PHX_inlet; //[K] HTF Inlet Temperature - double m_eta_fan; //[-] Fan isentropic efficiency - double m_deltaP_cooler_frac; //[-] Fraction of high side (of cycle, i.e. comp outlet) pressure that is allowed as pressure drop to design the ACC - double m_T_amb_des; //[K] Design point ambient temperature - double m_elevation; //[m] Elevation (used to calculate ambient pressure) - int m_N_nodes_pass; //[-] Number of nodes per pass - double m_HTF_PHX_cold_approach_input; //[delta K] PHX cold approach temperature. Only needed if m_set_HTF_mdot < 0 - int m_mc_comp_model_code; // Main compressor model code - int m_rc_comp_model_code; // Recompressor model code - int m_N_turbine; //[rpm] Turbine rpm - - S_sco2_htrbp_in() + // Defines sco2 htr bypass input variables (no optimized variables) + struct S_sco2_htrbp_in { - m_P_mc_in = m_P_mc_out = - m_LTR_UA = m_LTR_min_dT = m_LTR_eff_target = m_LTR_eff_max = - m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = - m_recomp_frac = - m_bypass_frac = - m_des_tol = - m_W_dot_net_design = - m_T_mc_in = - m_T_t_in = - m_eta_mc = - m_eta_t = - m_eta_rc = - m_eta_generator = - m_frac_fan_power = - m_set_HTF_mdot = - m_cp_HTF = - m_T_HTF_PHX_inlet = - m_eta_fan = - m_deltaP_cooler_frac = - m_T_amb_des = - m_elevation = - m_dT_BP = - m_HTF_PHX_cold_approach_input = - std::numeric_limits::quiet_NaN(); - - m_N_nodes_pass = 0; - m_LTR_N_sub_hxrs = 0; - m_HTR_N_sub_hxrs = 0; - m_mc_comp_model_code = -1; - m_rc_comp_model_code = -1; - m_N_turbine = -1; - - // Recuperator design target codes - m_LTR_target_code = 1; // default to target conductance - m_LTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; - m_HTR_target_code = 1; // default to target conductance - m_HTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; - - - // Air cooler default - m_is_des_air_cooler = true; - } + double m_P_mc_in; //[kPa] Compressor inlet pressure + double m_P_mc_out; //[kPa] Compressor outlet pressure + + // LTR thermal design + int m_LTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness + double m_LTR_UA; //[kW/K] target LTR conductance + double m_LTR_min_dT; //[K] target LTR minimum temperature difference + double m_LTR_eff_target; //[-] target LTR effectiveness + double m_LTR_eff_max; //[-] Maximum allowable effectiveness in LT recuperator + NS_HX_counterflow_eqs::E_UA_target_type m_LTR_od_UA_target_type; + int m_LTR_N_sub_hxrs; //[-] Number of sub-hxs to use in hx model + + // HTR thermal design + int m_HTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness + double m_HTR_UA; //[kW/K] target HTR conductance + double m_HTR_min_dT; //[K] target HTR min temperature difference + double m_HTR_eff_target; //[-] target HTR effectiveness + double m_HTR_eff_max; //[-] Maximum allowable effectiveness in HT recuperator + NS_HX_counterflow_eqs::E_UA_target_type m_HTR_od_UA_target_type; + int m_HTR_N_sub_hxrs; //[-] Number of sub-hxs to use in hx model + + double m_recomp_frac; //[-] Fraction of flow that bypasses the precooler and the main compressor at the design point + double m_bypass_frac; //[-] Fraction of flow that bypasses the HTR and passes through the Bypass HX + double m_des_tol; //[-] Convergence tolerance + + // Air cooler parameters + bool m_is_des_air_cooler; //[-] False will skip physical air cooler design. UA will not be available for cost models. + + + // Added + double m_W_dot_net_design; //[kWe] Target net cycle power + double m_T_mc_in; //[K] Compressor inlet temperature + double m_T_t_in; //[K] Turbine inlet temperature + double m_dT_BP; //[delta K/C] BYPASS_OUT - HTR_HP_OUT + std::vector m_DP_LTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + std::vector m_DP_HTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + std::vector m_DP_PC_main; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + std::vector m_DP_PHX; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + double m_eta_mc; //[-] design-point efficiency of the main compressor; isentropic if positive, polytropic if negative + double m_eta_t; //[-] design-point efficiency of the turbine; isentropic if positive, polytropic if negative + double m_eta_rc; //[-] design-point efficiency of the recompressor; isentropic if positive, polytropic if negative + double m_eta_generator; //[-] Mechanical-to-electrical efficiency of generator + double m_frac_fan_power; //[-] Fraction of total cycle power 'S_des_par_cycle_dep.m_W_dot_fan_des' consumed by air fan + double m_set_HTF_mdot; //[kg/s] > 0 set HTF mass flow, <= 0 use bypass approach temp to calculate HTF mdot + double m_cp_HTF; //[kJ/kg K] HTF specific heat + double m_T_HTF_PHX_inlet; //[K] HTF Inlet Temperature + double m_eta_fan; //[-] Fan isentropic efficiency + double m_deltaP_cooler_frac; //[-] Fraction of high side (of cycle, i.e. comp outlet) pressure that is allowed as pressure drop to design the ACC + double m_T_amb_des; //[K] Design point ambient temperature + double m_elevation; //[m] Elevation (used to calculate ambient pressure) + int m_N_nodes_pass; //[-] Number of nodes per pass + double m_HTF_PHX_cold_approach_input; //[delta K] PHX cold approach temperature. Only needed if m_set_HTF_mdot < 0 + int m_mc_comp_model_code; // Main compressor model code + int m_rc_comp_model_code; // Recompressor model code + int m_N_turbine; //[rpm] Turbine rpm + + S_sco2_htrbp_in() + { + m_P_mc_in = m_P_mc_out = + m_LTR_UA = m_LTR_min_dT = m_LTR_eff_target = m_LTR_eff_max = + m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = + m_recomp_frac = + m_bypass_frac = + m_des_tol = + m_W_dot_net_design = + m_T_mc_in = + m_T_t_in = + m_eta_mc = + m_eta_t = + m_eta_rc = + m_eta_generator = + m_frac_fan_power = + m_set_HTF_mdot = + m_cp_HTF = + m_T_HTF_PHX_inlet = + m_eta_fan = + m_deltaP_cooler_frac = + m_T_amb_des = + m_elevation = + m_dT_BP = + m_HTF_PHX_cold_approach_input = + std::numeric_limits::quiet_NaN(); -}; + m_N_nodes_pass = 0; + m_LTR_N_sub_hxrs = 0; + m_HTR_N_sub_hxrs = 0; + m_mc_comp_model_code = -1; + m_rc_comp_model_code = -1; + m_N_turbine = -1; + + // Recuperator design target codes + m_LTR_target_code = 1; // default to target conductance + m_LTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; + m_HTR_target_code = 1; // default to target conductance + m_HTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; -// Defines sco2 htr bypass output variables (no optimized variables) -struct S_sco2_htrbp_out -{ - int m_error_code; - C_turbine m_t; // Turbine model - C_comp_multi_stage m_mc_ms; // Main Compressor Model - C_comp_multi_stage m_rc_ms; // Recompressor Model - C_HeatExchanger m_PHX, m_PC, m_BPX; // Primary, Cooler, Bypass Heat Exchanger Models - C_HX_co2_to_co2_CRM mc_LT_recup; // LTR - C_HX_co2_to_co2_CRM mc_HT_recup; // HTR - C_CO2_to_air_cooler mc_air_cooler; // Air Cooler - std::vector m_temp, m_pres, m_enth, m_entr, m_dens; // thermodynamic states (K, kPa, kJ/kg, kJ/kg-K, kg/m3) - double m_w_t, m_w_mc, m_w_rc; // [kJ/kg] specific work of turbine, main compressor, recompressor - double m_m_dot_t, m_m_dot_mc, m_m_dot_rc; // [kg/s] sco2 Mass flow in main compressor, recompressor, turbine - double m_m_dot_bp, m_m_dot_htr_hp; // [kg/s] sco2 Mass flow through bypass, hot side HTR - double m_Q_dot_LT, m_Q_dot_HT; // [kWt] Heat Transfer in LTR, HTR - double m_W_dot_mc, m_W_dot_rc, m_W_dot_t; // [kWt] Energy consumed by main compressor, recompressor, produced by turbine - double m_W_dot_net; // [kWt] ACTUAL produced net work in system - double m_W_dot_air_cooler; // [kWe] Energy consumed by air cooler - double m_Q_dot_air_cooler; // [kWt] Heat rejected by air cooler - double m_Q_dot_LTR_LP, m_Q_dot_LTR_HP, m_Q_dot_HTR_LP, m_Q_dot_HTR_HP; // kWt Heat change on LTR low pressure, etc... - double m_Q_dot_total; // [kWt] Total heat entering sco2 - double m_Q_dot_PHX, m_Q_dot_BP; // [kWt] Energy exchange in PHX, BPX - double m_m_dot_HTF; // [kg/s] HTF mass flow rate - double m_T_HTF_PHX_out; // [K] HTF PHX outlet temperature - double m_HTF_PHX_cold_approach; // [delta K/C] PHX cold approach temperature - double m_T_HTF_BP_outlet; // [K] HTF BPX outlet temperature - double m_HTF_BP_cold_approach; // [K] BPX cold approach temperature - double m_eta_thermal; // Thermal Efficiency - - S_sco2_htrbp_out() - { - Init(); - } - void Init() + // Air cooler default + m_is_des_air_cooler = true; + + } + + }; + + // Defines sco2 htr bypass output variables (no optimized variables) + struct S_sco2_htrbp_out { - m_w_t = m_w_mc = m_w_rc - = m_m_dot_t = m_m_dot_mc = m_m_dot_rc - = m_m_dot_bp = m_m_dot_htr_hp - = m_Q_dot_LT = m_Q_dot_HT - = m_W_dot_mc = m_W_dot_rc = m_W_dot_t - = m_W_dot_net = m_W_dot_air_cooler = m_Q_dot_air_cooler - = m_Q_dot_LTR_LP = m_Q_dot_LTR_HP = m_Q_dot_HTR_LP = m_Q_dot_HTR_HP - = m_Q_dot_total = m_Q_dot_PHX = m_Q_dot_BP - = m_m_dot_HTF = m_T_HTF_PHX_out = m_HTF_PHX_cold_approach - = m_T_HTF_BP_outlet = m_HTF_BP_cold_approach = m_eta_thermal - = std::numeric_limits::quiet_NaN(); + int m_error_code; + C_turbine m_t; // Turbine model + C_comp_multi_stage m_mc_ms; // Main Compressor Model + C_comp_multi_stage m_rc_ms; // Recompressor Model + C_HeatExchanger m_PHX, m_PC, m_BPX; // Primary, Cooler, Bypass Heat Exchanger Models + C_HX_co2_to_co2_CRM mc_LT_recup; // LTR + C_HX_co2_to_co2_CRM mc_HT_recup; // HTR + C_CO2_to_air_cooler mc_air_cooler; // Air Cooler + std::vector m_temp, m_pres, m_enth, m_entr, m_dens; // thermodynamic states (K, kPa, kJ/kg, kJ/kg-K, kg/m3) + double m_w_t, m_w_mc, m_w_rc; // [kJ/kg] specific work of turbine, main compressor, recompressor + double m_m_dot_t, m_m_dot_mc, m_m_dot_rc; // [kg/s] sco2 Mass flow in main compressor, recompressor, turbine + double m_m_dot_bp, m_m_dot_htr_hp; // [kg/s] sco2 Mass flow through bypass, hot side HTR + double m_Q_dot_LT, m_Q_dot_HT; // [kWt] Heat Transfer in LTR, HTR + double m_W_dot_mc, m_W_dot_rc, m_W_dot_t; // [kWt] Energy consumed by main compressor, recompressor, produced by turbine + double m_W_dot_net; // [kWt] ACTUAL produced net work in system + double m_W_dot_air_cooler; // [kWe] Energy consumed by air cooler + double m_Q_dot_air_cooler; // [kWt] Heat rejected by air cooler + double m_Q_dot_LTR_LP, m_Q_dot_LTR_HP, m_Q_dot_HTR_LP, m_Q_dot_HTR_HP; // kWt Heat change on LTR low pressure, etc... + double m_Q_dot_total; // [kWt] Total heat entering sco2 + double m_Q_dot_PHX, m_Q_dot_BP; // [kWt] Energy exchange in PHX, BPX + double m_m_dot_HTF; // [kg/s] HTF mass flow rate + double m_T_HTF_PHX_out; // [K] HTF PHX outlet temperature + double m_HTF_PHX_cold_approach; // [delta K/C] PHX cold approach temperature + double m_T_HTF_BP_outlet; // [K] HTF BPX outlet temperature + double m_HTF_BP_cold_approach; // [K] BPX cold approach temperature + double m_eta_thermal; // Thermal Efficiency + + S_sco2_htrbp_out() + { + Init(); + } - m_error_code = -1; + void Init() + { + m_w_t = m_w_mc = m_w_rc + = m_m_dot_t = m_m_dot_mc = m_m_dot_rc + = m_m_dot_bp = m_m_dot_htr_hp + = m_Q_dot_LT = m_Q_dot_HT + = m_W_dot_mc = m_W_dot_rc = m_W_dot_t + = m_W_dot_net = m_W_dot_air_cooler = m_Q_dot_air_cooler + = m_Q_dot_LTR_LP = m_Q_dot_LTR_HP = m_Q_dot_HTR_LP = m_Q_dot_HTR_HP + = m_Q_dot_total = m_Q_dot_PHX = m_Q_dot_BP + = m_m_dot_HTF = m_T_HTF_PHX_out = m_HTF_PHX_cold_approach + = m_T_HTF_BP_outlet = m_HTF_BP_cold_approach = m_eta_thermal + = std::numeric_limits::quiet_NaN(); + + m_error_code = -1; + + // Clear and Size Output Vectors + m_temp.resize(C_sco2_cycle_core::END_SCO2_STATES); + std::fill(m_temp.begin(), m_temp.end(), std::numeric_limits::quiet_NaN()); + m_pres = m_enth = m_entr = m_dens = m_temp; + } + }; - // Clear and Size Output Vectors - m_temp.resize(C_sco2_cycle_core::END_SCO2_STATES); - std::fill(m_temp.begin(), m_temp.end(), std::numeric_limits::quiet_NaN()); - m_pres = m_enth = m_entr = m_dens = m_temp; - } -}; -// This class is purely for solving the cycle -// No optimization -class C_sco2_htrbp_core -{ private: CO2_state m_co2_props; @@ -265,10 +270,19 @@ class C_sco2_htrbp_core S_sco2_htrbp_out m_outputs; // Public Methods - void SetInputs(S_sco2_htrbp_in inputs) { m_inputs = inputs; }; - int Solve(); - int FinalizeDesign(C_sco2_cycle_core::S_design_solved& design_solved); - void Reset(); + C_sco2_htrbp_core() + { + m_outputs.Init(); + m_co2_props = CO2_state(); + } + + void set_inputs(S_sco2_htrbp_in inputs) { m_inputs = inputs; }; + + int solve(); + + int finalize_design(C_sco2_cycle_core::S_design_solved& design_solved); + + void reset(); }; @@ -325,44 +339,38 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core private: - // NEW REFACTOR Fields and methods - int optimize_cycle(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& optimal_inputs); + // Optimal inputs, for bypass optimizer DO NOT USE + C_sco2_htrbp_core::S_sco2_htrbp_in m_optimal_inputs_internal_only; + double m_opt_obj_internal_only; - int opt_nonbp_par(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, S_sco2_htrbp_in& core_inputs, S_sco2_htrbp_in& optimal_inputs); + // Bypass Specific HTF variables + int m_T_target_is_HTF; // Target Temperature is HTF (1) or cold sco2 at BP + double m_T_target; // [K] Target temperature (either HTF or sco2) + double m_T_HTF_PHX_inlet; // [K] HTF Primary Heat Exchanger Inlet Temperature + double m_set_HTF_mdot; // [kg/s] [0] calculate HTF mdot (need to set dT_PHX_cold_approach) [>0] mdot + double m_HTF_PHX_cold_approach; // [K] PHX cold approach temperature (need if m_set_HTF_mdot == 0) + double m_dT_BP; // [K] Temperature difference at second mixer inlet + double m_cp_HTF; // [kJ/kg K] HTF specific heat + bool m_is_bp_par_set; // Are bp parameters set - int x_to_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in &core_inputs); + // Optimal htrbp core class (contains all results and component data) + C_sco2_htrbp_core m_optimal_htrbp_core; - int clear_x_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, S_sco2_htrbp_in& core_inputs); + void auto_opt_design_core(int& error_code); - CO2_state mc_co2_props; + void auto_opt_design_hit_eta_core(int& error_code, double eta_thermal_target); - // Optimal inputs, for bypass optimizer DO NOT USE - S_sco2_htrbp_in m_optimal_inputs_internal_only; - double m_opt_obj_internal_only; + int optimize_totalUA(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core::S_sco2_htrbp_in& optimal_inputs); - // Input/Ouput structures for class methods - S_opt_design_parameters ms_opt_des_par; + int optimize_bp(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core::S_sco2_htrbp_in& optimal_inputs); - - void auto_opt_design_core(int& error_code); + int optimize_nonbp(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core::S_sco2_htrbp_in& core_inputs, C_sco2_htrbp_core::S_sco2_htrbp_in& optimal_inputs); - void auto_opt_design_hit_eta_core(int& error_code); + int x_to_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, C_sco2_htrbp_core::S_sco2_htrbp_in& core_inputs); - // Bypass Specific HTF variables - int m_T_target_is_HTF; - double m_T_target; - double m_T_HTF_PHX_inlet; - double m_set_HTF_mdot; - double m_HTF_PHX_cold_approach; - double m_dT_BP; - double m_cp_HTF = 0; - bool m_is_bp_par_set; - - // Optimal htrbp core class (contains all results and component data) - C_sco2_htrbp_core m_optimal_htrbp_core; + int clear_x_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, C_sco2_htrbp_core::S_sco2_htrbp_in& core_inputs); - // Added - double calc_penalty(double target, double calc, double span); + double calc_T_penalty(double target, double calc, double span); double calc_objective(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, const C_sco2_htrbp_core& htrbp_core); @@ -402,31 +410,45 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core { m_T_target = m_T_HTF_PHX_inlet = m_set_HTF_mdot = m_HTF_PHX_cold_approach = m_dT_BP - = m_cp_HTF + = m_cp_HTF = m_opt_obj_internal_only = std::numeric_limits::quiet_NaN(); + m_T_target_is_HTF = -1; + m_is_bp_par_set = false; } ~C_HTRBypass_Cycle() {}; - // Find optimal cycle - int auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in); - // Set Bypass Specific Parameters void set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, - double htf_phx_cold_approach, double set_HTF_mdot, int T_target_is_HTF); + double htf_phx_cold_approach, double set_HTF_mdot, int T_target_is_HTF) + { + m_T_HTF_PHX_inlet = T_htf_phx_in; // K + m_T_target = T_target; // K + m_T_target_is_HTF = T_target_is_HTF; + m_cp_HTF = cp_htf; // kJ/kg K + m_dT_BP = dT_bp; + m_HTF_PHX_cold_approach = htf_phx_cold_approach; + m_set_HTF_mdot = set_HTF_mdot; + + m_is_bp_par_set = true; + } - // Objective Functions - double C_HTRBypass_Cycle::opt_total_UA_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par); - double C_HTRBypass_Cycle::opt_cycle_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); - double C_HTRBypass_Cycle::opt_nonbp_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); + // Overridden - Optimize Cycle (fixed total UA) + int auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in); - // Unused + // Overridden - Optimize Cycle for target eta (variable total UA) + int auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg); - void reset_ms_od_turbo_bal_csp_solved(); + // Objective Functions (internal use only) + double C_HTRBypass_Cycle::optimize_totalUA_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par); + double C_HTRBypass_Cycle::optimize_bp_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); + double C_HTRBypass_Cycle::optimize_nonbp_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); - int auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg); + // Off Design + + void reset_ms_od_turbo_bal_csp_solved(); int off_design_fix_shaft_speeds(S_od_par& od_phi_par_in, double od_tol /*-*/); @@ -475,11 +497,11 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core }; // Nlopt objective functions -double nlopt_opt_total_UA_func(const std::vector& x, std::vector& grad, void* data); +double nlopt_optimize_totalUA_func(const std::vector& x, std::vector& grad, void* data); -double nlopt_opt_cycle_func(const std::vector& x, std::vector& grad, void* data); +double nlopt_optimize_bp_func(const std::vector& x, std::vector& grad, void* data); -double nlopt_opt_nonbp_par_func(const std::vector& x, std::vector& grad, void* data); +double nlopt_optimize_nonbp_func(const std::vector& x, std::vector& grad, void* data); From 4ca0167b9928c94f06f458221ef7c11f6a7022ef Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Wed, 13 Mar 2024 16:18:39 -0600 Subject: [PATCH 46/94] Make eta_thermal_target constant. Rename initialization function. --- tcs/sco2_htrbypass_cycle.cpp | 23 ++++++++++++++++++++--- tcs/sco2_htrbypass_cycle.h | 7 +++++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 4d673dad88..d27c70cff0 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -41,14 +41,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ********************************************************************************** C_sco2_htrbp_core CORE MODEL -void C_sco2_htrbp_core::InitializeSolve() +void C_sco2_htrbp_core::initialize_solve() { m_outputs.Init(); } int C_sco2_htrbp_core::solve() { - InitializeSolve(); + initialize_solve(); m_outputs.m_error_code = -1; // Apply scaling to the turbomachinery here @@ -940,7 +940,7 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) /// /// Core function to optimize cycle for target eta (variable total UA) /// -void C_HTRBypass_Cycle::auto_opt_design_hit_eta_core(int& error_code, double eta_thermal_target) +void C_HTRBypass_Cycle::auto_opt_design_hit_eta_core(int& error_code, const double eta_thermal_target) { // Create 'ms_opt_des_par' for Design Variables S_opt_design_parameters opt_par; @@ -1613,10 +1613,15 @@ int C_HTRBypass_Cycle::auto_opt_design(S_auto_opt_design_parameters& auto_opt_de return -1; } + // Reset Counter + m_opt_iteration_count = 0; + + // Collect auto_opt_des parameters ms_auto_opt_des_par = auto_opt_des_par_in; int auto_opt_des_error_code = 0; + // Design cycle auto_opt_design_core(auto_opt_des_error_code); return auto_opt_des_error_code; @@ -1638,6 +1643,9 @@ int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_paramet return -1; } + // Reset Counter + m_opt_iteration_count = 0; + // Fill in 'ms_auto_opt_des_par' from input { ms_auto_opt_des_par.m_UA_rec_total = std::numeric_limits::quiet_NaN(); // ***** This method finds the UA required to hit the input efficiency! ***** @@ -1882,6 +1890,9 @@ double C_HTRBypass_Cycle::optimize_totalUA_return_objective_metric(const std::ve const S_opt_design_parameters& opt_par ) { + // Update counter + m_opt_iteration_count++; // global + // Copy optimal parameters S_auto_opt_design_parameters auto_par_internal = auto_par; S_opt_design_parameters opt_par_internal = opt_par; @@ -1935,6 +1946,9 @@ double C_HTRBypass_Cycle::optimize_bp_return_objective_metric(const std::vector< const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core) { + // Update counter + m_opt_iteration_count++; // global + if (opt_par.m_fixed_bypass_frac == true) { throw std::exception("Optimizing bypass fraction even though it is fixed"); @@ -1982,6 +1996,9 @@ double C_HTRBypass_Cycle::optimize_nonbp_return_objective_metric(const std::vect const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core) { + // Update counter + m_opt_iteration_count++; // global + // Modify Core Inputs with Variable Parameters int error_code = x_to_inputs(x, auto_par, opt_par, htrbp_core.m_inputs); diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 7011da2ed7..d7f0690fab 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -260,7 +260,7 @@ class C_sco2_htrbp_core int solve_HTR(double T_HTR_LP_OUT_guess, double* diff_T_HTR_LP_out); int solve_LTR(double T_LTR_LP_OUT_guess, double* diff_T_LTR_LP_out); - void InitializeSolve(); + void initialize_solve(); public: // Inputs Struct @@ -343,6 +343,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core C_sco2_htrbp_core::S_sco2_htrbp_in m_optimal_inputs_internal_only; double m_opt_obj_internal_only; + int m_opt_iteration_count; // Counter of bypass iterations + // Bypass Specific HTF variables int m_T_target_is_HTF; // Target Temperature is HTF (1) or cold sco2 at BP double m_T_target; // [K] Target temperature (either HTF or sco2) @@ -358,7 +360,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core void auto_opt_design_core(int& error_code); - void auto_opt_design_hit_eta_core(int& error_code, double eta_thermal_target); + void auto_opt_design_hit_eta_core(int& error_code, const double eta_thermal_target); int optimize_totalUA(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core::S_sco2_htrbp_in& optimal_inputs); @@ -414,6 +416,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core = std::numeric_limits::quiet_NaN(); m_T_target_is_HTF = -1; + m_opt_iteration_count = 0; m_is_bp_par_set = false; } From 67cb2ce00397aba712f145c8756e485e01d90058 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Fri, 15 Mar 2024 13:48:09 -0600 Subject: [PATCH 47/94] Add message to report iterations out --- tcs/sco2_htrbypass_cycle.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index d27c70cff0..0735efd8c8 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -1875,6 +1875,19 @@ int C_HTRBypass_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_paramet // Optimize auto_opt_design_hit_eta_core(error_code, auto_opt_des_hit_eta_in.m_eta_thermal); + // Send log update upstream + if (ms_auto_opt_des_par.mf_callback_log && ms_auto_opt_des_par.mp_mf_active) + { + std::string msg_log = "Optimization finished in " + std::to_string(m_opt_iteration_count) + " iterations."; + std::string msg_progress = ""; + if (!ms_auto_opt_des_par.mf_callback_log(msg_log, msg_progress, ms_auto_opt_des_par.mp_mf_active, 100.0, 2)) + { + std::string error_msg = "User terminated simulation..."; + std::string loc_msg = "C_MEQ_sco2_design_hit_eta__UA_total"; + throw(C_csp_exception(error_msg, loc_msg, 1)); + } + } + return error_code; } From 794115a11a6b4fe9e339bc425e4ac3bd6d3979f5 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Tue, 2 Apr 2024 16:04:48 -0600 Subject: [PATCH 48/94] Add turbine split flow cycle files (not complete). --- tcs/CMakeLists.txt | 2 + tcs/sco2_turbinesplitflow_cycle.cpp | 393 +++++++++++++++++++++++ tcs/sco2_turbinesplitflow_cycle.h | 482 ++++++++++++++++++++++++++++ 3 files changed, 877 insertions(+) create mode 100644 tcs/sco2_turbinesplitflow_cycle.cpp create mode 100644 tcs/sco2_turbinesplitflow_cycle.h diff --git a/tcs/CMakeLists.txt b/tcs/CMakeLists.txt index 521c4ff407..0ecd3514bc 100644 --- a/tcs/CMakeLists.txt +++ b/tcs/CMakeLists.txt @@ -57,6 +57,7 @@ set(TCS_SRC sco2_rec_util.cpp sco2_recompression_cycle.cpp sco2_test_type401.cpp + sco2_turbinesplitflow_cycle.cpp tc_test_type402.cpp tcskernel.cpp trnsys_weatherreader.cpp @@ -152,6 +153,7 @@ set(TCS_SRC sco2_power_cycle.h sco2_recompression_cycle.h sco2_rec_util.h + sco2_turbinesplitflow_cycle.h storage_hx.h tcskernel.h tcstype.h diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp new file mode 100644 index 0000000000..075c1df49f --- /dev/null +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -0,0 +1,393 @@ +/* +BSD 3-Clause License + +Copyright (c) Alliance for Sustainable Energy, LLC. See also https://github.com/NREL/ssc/blob/develop/LICENSE +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "sco2_turbinesplitflow_cycle.h" +#include "sco2_cycle_components.h" + +#include "CO2_properties.h" + + +#include "fmin.h" + + +// ********************************************************************************** C_sco2_htrbp_core CORE MODEL + +void C_sco2_turbinesplitflow_core::initialize_solve() +{ + m_outputs.Init(); +} + +int C_sco2_turbinesplitflow_core::solve() +{ + return -1; +} + +int C_sco2_turbinesplitflow_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_solved) +{ + // Design Main Compressor + { + int mc_design_err = m_outputs.m_mc_ms.design_given_outlet_state(m_inputs.m_mc_comp_model_code, m_outputs.m_temp[C_sco2_cycle_core::MC_IN], + m_outputs.m_pres[C_sco2_cycle_core::MC_IN], + m_outputs.m_m_dot_mc, + m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], + m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], + m_inputs.m_des_tol); + + if (mc_design_err != 0) + { + m_outputs.m_error_code = mc_design_err; + return m_outputs.m_error_code; + } + } + + // Design Recompressor + if (m_inputs.m_recomp_frac > 0.01) + { + int rc_des_err = m_outputs.m_rc_ms.design_given_outlet_state(m_inputs.m_rc_comp_model_code, m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT], + m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT], + m_outputs.m_m_dot_rc, + m_outputs.m_temp[C_sco2_cycle_core::RC_OUT], + m_outputs.m_pres[C_sco2_cycle_core::RC_OUT], + m_inputs.m_des_tol); + + if (rc_des_err != 0) + { + m_outputs.m_error_code = rc_des_err; + return m_outputs.m_error_code; + } + + design_solved.m_is_rc = true; + } + else + { + design_solved.m_is_rc = false; + } + + // Size Turbine + { + C_turbine::S_design_parameters t_des_par; + // Set turbine shaft speed + t_des_par.m_N_design = m_inputs.m_N_turbine; + t_des_par.m_N_comp_design_if_linked = m_outputs.m_mc_ms.get_design_solved()->m_N_design; //[rpm] m_mc.get_design_solved()->m_N_design; + // Turbine inlet state + t_des_par.m_P_in = m_outputs.m_pres[C_sco2_cycle_core::TURB_IN]; + t_des_par.m_T_in = m_outputs.m_temp[C_sco2_cycle_core::TURB_IN]; + t_des_par.m_D_in = m_outputs.m_dens[C_sco2_cycle_core::TURB_IN]; + t_des_par.m_h_in = m_outputs.m_enth[C_sco2_cycle_core::TURB_IN]; + t_des_par.m_s_in = m_outputs.m_entr[C_sco2_cycle_core::TURB_IN]; + // Turbine outlet state + t_des_par.m_P_out = m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT]; + t_des_par.m_h_out = m_outputs.m_enth[C_sco2_cycle_core::TURB_OUT]; + // Mass flow + t_des_par.m_m_dot = m_outputs.m_m_dot_t; + + int turb_size_error_code = 0; + m_outputs.m_t.turbine_sizing(t_des_par, turb_size_error_code); + + if (turb_size_error_code != 0) + { + m_outputs.m_error_code = turb_size_error_code; + return m_outputs.m_error_code; + } + } + + // Design air cooler + { + // Structure for design parameters that are dependent on cycle design solution + C_CO2_to_air_cooler::S_des_par_cycle_dep s_air_cooler_des_par_dep; + // Set air cooler design parameters that are dependent on the cycle design solution + s_air_cooler_des_par_dep.m_T_hot_in_des = m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT]; // [K] + s_air_cooler_des_par_dep.m_P_hot_in_des = m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT]; // [kPa] + s_air_cooler_des_par_dep.m_m_dot_total = m_outputs.m_m_dot_mc; // [kg/s] + + // This pressure drop is currently uncoupled from the cycle design + double cooler_deltaP = m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT] - m_outputs.m_pres[C_sco2_cycle_core::MC_IN]; // [kPa] + if (cooler_deltaP == 0.0) + s_air_cooler_des_par_dep.m_delta_P_des = m_inputs.m_deltaP_cooler_frac * m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT]; // [kPa] + else + s_air_cooler_des_par_dep.m_delta_P_des = cooler_deltaP; // [kPa] + + s_air_cooler_des_par_dep.m_T_hot_out_des = m_outputs.m_temp[C_sco2_cycle_core::MC_IN]; // [K] + s_air_cooler_des_par_dep.m_W_dot_fan_des = m_inputs.m_frac_fan_power * m_outputs.m_W_dot_net / 1000.0; // [MWe] + // Structure for design parameters that are independent of cycle design solution + C_CO2_to_air_cooler::S_des_par_ind s_air_cooler_des_par_ind; + s_air_cooler_des_par_ind.m_T_amb_des = m_inputs.m_T_amb_des; // [K] + s_air_cooler_des_par_ind.m_elev = m_inputs.m_elevation; // [m] + s_air_cooler_des_par_ind.m_eta_fan = m_inputs.m_eta_fan; // [-] + s_air_cooler_des_par_ind.m_N_nodes_pass = m_inputs.m_N_nodes_pass; // [-] + + if (m_inputs.m_is_des_air_cooler && std::isfinite(m_inputs.m_deltaP_cooler_frac) && std::isfinite(m_inputs.m_frac_fan_power) + && std::isfinite(m_inputs.m_T_amb_des) && std::isfinite(m_inputs.m_elevation) && std::isfinite(m_inputs.m_eta_fan) && m_inputs.m_N_nodes_pass > 0) + { + m_outputs.mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, m_inputs.m_des_tol); + } + } + + // Get 'design_solved' structure from component classes + design_solved.ms_mc_ms_des_solved = *m_outputs.m_mc_ms.get_design_solved(); + design_solved.ms_rc_ms_des_solved = *m_outputs.m_rc_ms.get_design_solved(); + design_solved.ms_t_des_solved = *m_outputs.m_t.get_design_solved(); + design_solved.ms_LTR_des_solved = m_outputs.mc_LT_recup.ms_des_solved; + design_solved.ms_HTR_des_solved = m_outputs.mc_HT_recup.ms_des_solved; + design_solved.ms_mc_air_cooler = *m_outputs.mc_air_cooler.get_design_solved(); + + // Set solved design point metrics + design_solved.m_temp = m_outputs.m_temp; + design_solved.m_pres = m_outputs.m_pres; + design_solved.m_enth = m_outputs.m_enth; + design_solved.m_entr = m_outputs.m_entr; + design_solved.m_dens = m_outputs.m_dens; + + design_solved.m_eta_thermal = m_outputs.m_eta_thermal; + design_solved.m_W_dot_net = m_outputs.m_W_dot_net; + design_solved.m_m_dot_mc = m_outputs.m_m_dot_mc; + design_solved.m_m_dot_rc = m_outputs.m_m_dot_rc; + design_solved.m_m_dot_t = m_outputs.m_m_dot_t; + design_solved.m_recomp_frac = m_outputs.m_m_dot_rc / m_outputs.m_m_dot_t; + design_solved.m_bypass_frac = m_inputs.m_bypass_frac; + + design_solved.m_UA_LTR = m_inputs.m_LTR_UA; + design_solved.m_UA_HTR = m_inputs.m_HTR_UA; + + design_solved.m_W_dot_t = m_outputs.m_W_dot_t; //[kWe] + design_solved.m_W_dot_mc = m_outputs.m_W_dot_mc; //[kWe] + design_solved.m_W_dot_rc = m_outputs.m_W_dot_rc; //[kWe] + + design_solved.m_W_dot_cooler_tot = m_outputs.mc_air_cooler.get_design_solved()->m_W_dot_fan * 1.E3; //[kWe] convert from MWe + + return 0; +} + +int C_sco2_turbinesplitflow_core::solve_HTR_LTR(double T_HTR_HP_OUT_guess, double* diff_T_HTR_HP_out) +{ + return -1; +} + +void C_sco2_turbinesplitflow_core::reset() +{ + this->m_inputs = S_sco2_tsf_in(); + this->m_outputs.Init(); +} + +// ********************************************************************************** END C_sco2_htrbp_core + + +// ********************************************************************************** PRIVATE C_HTRBypass_Cycle (: C_sco2_cycle_core) + +/// +/// Core function to optimize cycle (fixed total UA) +/// +void C_TurbineSplitFlow_Cycle::auto_opt_design_core(int& error_code) +{ + return; +} + +/// +/// Core function to optimize cycle for target eta (variable total UA) +/// +void C_TurbineSplitFlow_Cycle::auto_opt_design_hit_eta_core(int& error_code, const double eta_thermal_target) +{ + return; +} + +/// +/// Optimize Total Recuperator UA +/// totalUA -> bp -> UA split, pressure, recomp +/// +/// +/// +/// +/// +int C_TurbineSplitFlow_Cycle::optimize_totalUA(const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + C_sco2_turbinesplitflow_core::S_sco2_tsf_in& optimal_inputs) +{ + return -1;; +} + +/// +/// Optimize internal variables (UA split, pressure, recomp) +/// totalUA -> bp -> UA split, pressure, recomp +/// +/// +/// +/// +/// +/// +int C_TurbineSplitFlow_Cycle::optimize_par(const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + C_sco2_turbinesplitflow_core::S_sco2_tsf_in& core_inputs, + C_sco2_turbinesplitflow_core::S_sco2_tsf_in& optimal_inputs) +{ + return -1; +} + +// ********************************************************************************** PUBLIC Methods C_HTRBypass_Cycle (: C_sco2_cycle_core) + +/// +/// Optimize Cycle Design for FIXED total recuperator UA +/// +/// +int C_TurbineSplitFlow_Cycle::auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in) +{ + // Reset Counter + m_opt_iteration_count = 0; + + // Collect auto_opt_des parameters + ms_auto_opt_des_par = auto_opt_des_par_in; + + int auto_opt_des_error_code = 0; + + // Design cycle + auto_opt_design_core(auto_opt_des_error_code); + + return auto_opt_des_error_code; +} + +/// +/// Optimize Cycle design to hit target eta (optimize total recuperator UA) +/// +/// +/// +/// +int C_TurbineSplitFlow_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg) +{ + return -1; +} + +// ********************************************************************************** PUBLIC Objective Functions (internal use only) + +/// +/// Objective Function for total UA (outermost layer) +/// Total UA -> Bypass Fraction -> pressure, split UA, recomp frac +/// +/// ONLY Objective Value +double C_TurbineSplitFlow_Cycle::optimize_totalUA_return_objective_metric(const std::vector& x, + const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par +) +{ + return 0; +} + +/// +/// Objective Function for NON Bypass optimization +/// Total UA -> Bypass Fraction -> pressure, split UA, recomp frac +/// +/// ONLY Objective Value +double C_TurbineSplitFlow_Cycle::optimize_par_return_objective_metric(const std::vector& x, + const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + C_sco2_turbinesplitflow_core& htrbp_core) +{ + return 0; +} + +// ********************************************************************************** Off Design Functions + + +void C_TurbineSplitFlow_Cycle::reset_ms_od_turbo_bal_csp_solved() +{ +} + +int C_TurbineSplitFlow_Cycle::off_design_fix_shaft_speeds(S_od_par& od_phi_par_in, double od_tol) +{ + return 0; +} + +int C_TurbineSplitFlow_Cycle::solve_OD_all_coolers_fan_power(double T_amb, double od_tol, double& W_dot_fan) +{ + return 0; +} + +int C_TurbineSplitFlow_Cycle::solve_OD_mc_cooler_fan_power(double T_amb, double od_tol, double& W_dot_mc_cooler_fan, double& P_co2_out) +{ + return 0; +} + +int C_TurbineSplitFlow_Cycle::solve_OD_pc_cooler_fan_power(double T_amb, double od_tol, double& W_dot_pc_cooler_fan, double& P_co2_out) +{ + return 0; +} + +double C_TurbineSplitFlow_Cycle::get_od_temp(int n_state_point) +{ + return 0.0; +} + +double C_TurbineSplitFlow_Cycle::get_od_pres(int n_state_point) +{ + return 0.0; +} + +void C_TurbineSplitFlow_Cycle::check_od_solution(double& diff_m_dot, double& diff_E_cycle, double& diff_Q_LTR, double& diff_Q_HTR) +{ +} + +void C_TurbineSplitFlow_Cycle::set_od_temp(int n_state_point, double temp_K) +{ +} + +void C_TurbineSplitFlow_Cycle::set_od_pres(int n_state_point, double pres_kPa) +{ +} + +void C_TurbineSplitFlow_Cycle::off_design_recompressor(double T_in, double P_in, double m_dot, double P_out, double tol, int& error_code, double& T_out) +{ +} + +void C_TurbineSplitFlow_Cycle::estimate_od_turbo_operation(double T_mc_in, double P_mc_in, double f_recomp, double T_t_in, double phi_mc, int& mc_error_code, double& mc_w_tip_ratio, double& P_mc_out, int& rc_error_code, double& rc_w_tip_ratio, double& rc_phi, bool is_update_ms_od_solved) +{ +} + + +// ********************************************************************************** PUBLIC Methods defined outside of any class + +double nlopt_optimize_totalUA_func(const std::vector& x, std::vector& grad, void* data) +{ + return 0; +} + +double nlopt_optimize_par_func(const std::vector& x, std::vector& grad, void* data) +{ + return 0; +} + +double sigmoid(const double val) +{ + return 1.0 / (1.0 + std::exp(-1.0 * val)); +} + +double logit(const double val) +{ + return std::log(val / (1.0 - val)); +} diff --git a/tcs/sco2_turbinesplitflow_cycle.h b/tcs/sco2_turbinesplitflow_cycle.h new file mode 100644 index 0000000000..697e5f246f --- /dev/null +++ b/tcs/sco2_turbinesplitflow_cycle.h @@ -0,0 +1,482 @@ +/* +BSD 3-Clause License + +Copyright (c) Alliance for Sustainable Energy, LLC. See also https://github.com/NREL/ssc/blob/develop/LICENSE +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __SCO2_TURBINESPLITFLOW_ +#define __SCO2_TURBINESPLITFLOW_ + +#include "sco2_cycle_components.h" +#include "sco2_cycle_templates.h" + +#include "heat_exchangers.h" +#include "CO2_properties.h" + +#include "numeric_solvers.h" + + +#include "nlopt.hpp" +#include "nlopt_callbacks.h" + + + +// This class is purely for solving the cycle +// No optimization +class C_sco2_turbinesplitflow_core +{ +public: + + // Defines sco2 htr bypass input variables (no optimized variables) + struct S_sco2_tsf_in + { + + double m_P_mc_in; //[kPa] Compressor inlet pressure + double m_P_mc_out; //[kPa] Compressor outlet pressure + + // LTR thermal design + int m_LTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness + double m_LTR_UA; //[kW/K] target LTR conductance + double m_LTR_min_dT; //[K] target LTR minimum temperature difference + double m_LTR_eff_target; //[-] target LTR effectiveness + double m_LTR_eff_max; //[-] Maximum allowable effectiveness in LT recuperator + NS_HX_counterflow_eqs::E_UA_target_type m_LTR_od_UA_target_type; + int m_LTR_N_sub_hxrs; //[-] Number of sub-hxs to use in hx model + + // HTR thermal design + int m_HTR_target_code; //[-] 1 = UA, 2 = min dT, 3 = effectiveness + double m_HTR_UA; //[kW/K] target HTR conductance + double m_HTR_min_dT; //[K] target HTR min temperature difference + double m_HTR_eff_target; //[-] target HTR effectiveness + double m_HTR_eff_max; //[-] Maximum allowable effectiveness in HT recuperator + NS_HX_counterflow_eqs::E_UA_target_type m_HTR_od_UA_target_type; + int m_HTR_N_sub_hxrs; //[-] Number of sub-hxs to use in hx model + + double m_recomp_frac; //[-] Fraction of flow that bypasses the precooler and the main compressor at the design point + double m_bypass_frac; //[-] Fraction of flow that bypasses the HTR and passes through the Bypass HX + double m_des_tol; //[-] Convergence tolerance + + // Air cooler parameters + bool m_is_des_air_cooler; //[-] False will skip physical air cooler design. UA will not be available for cost models. + + + // Added + double m_W_dot_net_design; //[kWe] Target net cycle power + double m_T_mc_in; //[K] Compressor inlet temperature + double m_T_t_in; //[K] Turbine inlet temperature + double m_dT_BP; //[delta K/C] BYPASS_OUT - HTR_HP_OUT + std::vector m_DP_LTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + std::vector m_DP_HTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + std::vector m_DP_PC_main; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + std::vector m_DP_PHX; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) + double m_eta_mc; //[-] design-point efficiency of the main compressor; isentropic if positive, polytropic if negative + double m_eta_t; //[-] design-point efficiency of the turbine; isentropic if positive, polytropic if negative + double m_eta_rc; //[-] design-point efficiency of the recompressor; isentropic if positive, polytropic if negative + double m_eta_generator; //[-] Mechanical-to-electrical efficiency of generator + double m_frac_fan_power; //[-] Fraction of total cycle power 'S_des_par_cycle_dep.m_W_dot_fan_des' consumed by air fan + double m_set_HTF_mdot; //[kg/s] > 0 set HTF mass flow, <= 0 use bypass approach temp to calculate HTF mdot + double m_cp_HTF; //[kJ/kg K] HTF specific heat + double m_T_HTF_PHX_inlet; //[K] HTF Inlet Temperature + double m_eta_fan; //[-] Fan isentropic efficiency + double m_deltaP_cooler_frac; //[-] Fraction of high side (of cycle, i.e. comp outlet) pressure that is allowed as pressure drop to design the ACC + double m_T_amb_des; //[K] Design point ambient temperature + double m_elevation; //[m] Elevation (used to calculate ambient pressure) + int m_N_nodes_pass; //[-] Number of nodes per pass + double m_HTF_PHX_cold_approach_input; //[delta K] PHX cold approach temperature. Only needed if m_set_HTF_mdot < 0 + int m_mc_comp_model_code; // Main compressor model code + int m_rc_comp_model_code; // Recompressor model code + int m_N_turbine; //[rpm] Turbine rpm + + S_sco2_tsf_in() + { + m_P_mc_in = m_P_mc_out = + m_LTR_UA = m_LTR_min_dT = m_LTR_eff_target = m_LTR_eff_max = + m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = + m_recomp_frac = + m_bypass_frac = + m_des_tol = + m_W_dot_net_design = + m_T_mc_in = + m_T_t_in = + m_eta_mc = + m_eta_t = + m_eta_rc = + m_eta_generator = + m_frac_fan_power = + m_set_HTF_mdot = + m_cp_HTF = + m_T_HTF_PHX_inlet = + m_eta_fan = + m_deltaP_cooler_frac = + m_T_amb_des = + m_elevation = + m_dT_BP = + m_HTF_PHX_cold_approach_input = + std::numeric_limits::quiet_NaN(); + + m_N_nodes_pass = 0; + m_LTR_N_sub_hxrs = 0; + m_HTR_N_sub_hxrs = 0; + m_mc_comp_model_code = -1; + m_rc_comp_model_code = -1; + m_N_turbine = -1; + + // Recuperator design target codes + m_LTR_target_code = 1; // default to target conductance + m_LTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; + m_HTR_target_code = 1; // default to target conductance + m_HTR_od_UA_target_type = NS_HX_counterflow_eqs::E_UA_target_type::E_calc_UA; + + + // Air cooler default + m_is_des_air_cooler = true; + + } + + }; + + // Defines sco2 htr bypass output variables (no optimized variables) + struct S_sco2_tsf_out + { + int m_error_code; + C_turbine m_t; // Turbine model + C_comp_multi_stage m_mc_ms; // Main Compressor Model + C_comp_multi_stage m_rc_ms; // Recompressor Model + C_HeatExchanger m_PHX, m_PC, m_BPX; // Primary, Cooler, Bypass Heat Exchanger Models + C_HX_co2_to_co2_CRM mc_LT_recup; // LTR + C_HX_co2_to_co2_CRM mc_HT_recup; // HTR + C_CO2_to_air_cooler mc_air_cooler; // Air Cooler + std::vector m_temp, m_pres, m_enth, m_entr, m_dens; // thermodynamic states (K, kPa, kJ/kg, kJ/kg-K, kg/m3) + double m_w_t, m_w_mc, m_w_rc; // [kJ/kg] specific work of turbine, main compressor, recompressor + double m_m_dot_t, m_m_dot_mc, m_m_dot_rc; // [kg/s] sco2 Mass flow in main compressor, recompressor, turbine + double m_m_dot_bp, m_m_dot_htr_hp; // [kg/s] sco2 Mass flow through bypass, hot side HTR + double m_Q_dot_LT, m_Q_dot_HT; // [kWt] Heat Transfer in LTR, HTR + double m_W_dot_mc, m_W_dot_rc, m_W_dot_t; // [kWt] Energy consumed by main compressor, recompressor, produced by turbine + double m_W_dot_net; // [kWt] ACTUAL produced net work in system + double m_W_dot_air_cooler; // [kWe] Energy consumed by air cooler + double m_Q_dot_air_cooler; // [kWt] Heat rejected by air cooler + double m_Q_dot_LTR_LP, m_Q_dot_LTR_HP, m_Q_dot_HTR_LP, m_Q_dot_HTR_HP; // kWt Heat change on LTR low pressure, etc... + double m_Q_dot_total; // [kWt] Total heat entering sco2 + double m_Q_dot_PHX, m_Q_dot_BP; // [kWt] Energy exchange in PHX, BPX + double m_m_dot_HTF; // [kg/s] HTF mass flow rate + double m_T_HTF_PHX_out; // [K] HTF PHX outlet temperature + double m_HTF_PHX_cold_approach; // [delta K/C] PHX cold approach temperature + double m_T_HTF_BP_outlet; // [K] HTF BPX outlet temperature + double m_HTF_BP_cold_approach; // [K] BPX cold approach temperature + double m_eta_thermal; // Thermal Efficiency + + S_sco2_tsf_out() + { + Init(); + } + + void Init() + { + m_w_t = m_w_mc = m_w_rc + = m_m_dot_t = m_m_dot_mc = m_m_dot_rc + = m_m_dot_bp = m_m_dot_htr_hp + = m_Q_dot_LT = m_Q_dot_HT + = m_W_dot_mc = m_W_dot_rc = m_W_dot_t + = m_W_dot_net = m_W_dot_air_cooler = m_Q_dot_air_cooler + = m_Q_dot_LTR_LP = m_Q_dot_LTR_HP = m_Q_dot_HTR_LP = m_Q_dot_HTR_HP + = m_Q_dot_total = m_Q_dot_PHX = m_Q_dot_BP + = m_m_dot_HTF = m_T_HTF_PHX_out = m_HTF_PHX_cold_approach + = m_T_HTF_BP_outlet = m_HTF_BP_cold_approach = m_eta_thermal + = std::numeric_limits::quiet_NaN(); + + m_error_code = -1; + + // Clear and Size Output Vectors + m_temp.resize(C_sco2_cycle_core::END_SCO2_STATES); + std::fill(m_temp.begin(), m_temp.end(), std::numeric_limits::quiet_NaN()); + m_pres = m_enth = m_entr = m_dens = m_temp; + } + }; + + +private: + CO2_state m_co2_props; + + class C_mono_htrbp_core_HTR_des : public C_monotonic_equation + { + private: + C_sco2_turbinesplitflow_core* m_tsf_cycle; + + public: + C_mono_htrbp_core_HTR_des(C_sco2_turbinesplitflow_core* tsf_cycle) + { + m_tsf_cycle = tsf_cycle; + } + + virtual int operator()(double T_HTR_HP_OUT_guess /*K*/, double* diff_T_HTR_HP_out /*K*/) + { + return m_tsf_cycle->solve_HTR_LTR(T_HTR_HP_OUT_guess, diff_T_HTR_HP_out); + }; + }; + + int solve_HTR_LTR(double T_HTR_HP_OUT_guess, double* diff_T_HTR_HP_out); + + void initialize_solve(); + +public: + // Inputs Struct + S_sco2_tsf_in m_inputs; + + // Outputs Struct + S_sco2_tsf_out m_outputs; + + // Public Methods + C_sco2_turbinesplitflow_core() + { + m_outputs.Init(); + m_co2_props = CO2_state(); + } + + void set_inputs(S_sco2_tsf_in inputs) { m_inputs = inputs; }; + + int solve(); + + int finalize_design(C_sco2_cycle_core::S_design_solved& design_solved); + + void reset(); +}; + + + +class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core +{ +public: + + // Struct to store optimization variables + struct S_opt_design_parameters + { + + double m_P_mc_out_guess; //[kPa] Initial guess for main compressor outlet pressure + bool m_fixed_P_mc_out; //[-] if true, P_mc_out is fixed at P_mc_out_guess + + double m_PR_HP_to_LP_guess; //[-] Initial guess for ratio of P_mc_out to P_LP_in + bool m_fixed_PR_HP_to_LP; //[-] if true, ratio of P_mc_out to P_mc_in is fixed at PR_mc_guess + + double m_recomp_frac_guess; //[-] Initial guess for design-point recompression fraction + bool m_fixed_recomp_frac; //[-] if true, recomp_frac is fixed at recomp_frac_guess + + double m_bypass_frac_guess; //[-] Initial guess for design-point bypass fraction + bool m_fixed_bypass_frac; //[-] if true, bypass_frac is fixed at bypass_frac_guess + + double m_LT_frac_guess; //[-] Initial guess for fraction of UA_rec_total that is in the low-temperature recuperator + bool m_fixed_LT_frac; //[-] if true, LT_frac is fixed at LT_frac_guess + + // ADDED + int m_design_method; //[] Design Method [1] Optimize total UA for target eta, [2] Optimize UA split ratio, [3] set LTR HTR directly + double m_eta_thermal_target; //[] Cycle thermal efficiency target (used by total UA optimization) + double m_UA_recup_total_max; //[kW/K] Maximum recuperator conductance (for total UA optimizer) + double m_UA_recup_total_min; //[kW/K] Minimum recuperator conductance (for total UA optimizer) + + + S_opt_design_parameters() + { + m_P_mc_out_guess = m_PR_HP_to_LP_guess = m_recomp_frac_guess = m_LT_frac_guess = + m_bypass_frac_guess = m_eta_thermal_target = + m_UA_recup_total_max = m_UA_recup_total_min = + std::numeric_limits::quiet_NaN(); + + + m_design_method = -1; + m_fixed_recomp_frac = false; + m_fixed_bypass_frac = false; + m_fixed_LT_frac = false; + m_fixed_PR_HP_to_LP = false; + m_fixed_P_mc_out = false; + + } + + + }; + +private: + + int m_opt_iteration_count; // Counter of bypass iterations + + // Bypass Specific HTF variables + int m_T_target_is_HTF; // Target Temperature is HTF (1) or cold sco2 at BP + double m_T_target; // [K] Target temperature (either HTF or sco2) + double m_T_HTF_PHX_inlet; // [K] HTF Primary Heat Exchanger Inlet Temperature + double m_set_HTF_mdot; // [kg/s] [0] calculate HTF mdot (need to set dT_PHX_cold_approach) [>0] mdot + double m_HTF_PHX_cold_approach; // [K] PHX cold approach temperature (need if m_set_HTF_mdot == 0) + double m_dT_BP; // [K] Temperature difference at second mixer inlet + double m_cp_HTF; // [kJ/kg K] HTF specific heat + bool m_is_bp_par_set; // Are bp parameters set + + // Optimal htrbp core class (contains all results and component data) + C_sco2_turbinesplitflow_core m_optimal_tsf_core; + + void auto_opt_design_core(int& error_code); + + void auto_opt_design_hit_eta_core(int& error_code, const double eta_thermal_target); + + int optimize_totalUA(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_turbinesplitflow_core::S_sco2_tsf_in& optimal_inputs); + + int optimize_par(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_turbinesplitflow_core::S_sco2_tsf_in& core_inputs, C_sco2_turbinesplitflow_core::S_sco2_tsf_in& optimal_inputs); + +protected: + + +public: + + C_TurbineSplitFlow_Cycle(C_sco2_cycle_core::E_turbo_gen_motor_config turbo_gen_motor_config, + double eta_generator, + double T_mc_in, + double W_dot_net, + double T_t_in, double P_high_limit, + std::vector DP_LTR, std::vector DP_HTR, + std::vector DP_PC_main, std::vector DP_PHX, + int LTR_N_sub_hxrs, int HTR_N_sub_hxrs, + double eta_mc, int mc_comp_model_code, + double eta_rc, + double eta_t, double N_turbine, + double frac_fan_power, double eta_fan, double deltaP_cooler_frac, + int N_nodes_pass, + double T_amb_des, double elevation) : + C_sco2_cycle_core(turbo_gen_motor_config, + eta_generator, + T_mc_in, + W_dot_net, + T_t_in, P_high_limit, + DP_LTR, DP_HTR, + DP_PC_main, DP_PHX, + LTR_N_sub_hxrs, HTR_N_sub_hxrs, + eta_mc, mc_comp_model_code, + eta_rc, + eta_t, N_turbine, + frac_fan_power, eta_fan, deltaP_cooler_frac, + N_nodes_pass, + T_amb_des, elevation) + { + m_T_target = m_T_HTF_PHX_inlet = m_set_HTF_mdot + = m_HTF_PHX_cold_approach = m_dT_BP + = m_cp_HTF + = std::numeric_limits::quiet_NaN(); + + m_T_target_is_HTF = -1; + m_opt_iteration_count = 0; + + m_is_bp_par_set = false; + } + + ~C_TurbineSplitFlow_Cycle() {}; + + // Set Bypass Specific Parameters + void set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, + double htf_phx_cold_approach, double set_HTF_mdot, int T_target_is_HTF) + { + m_T_HTF_PHX_inlet = T_htf_phx_in; // K + m_T_target = T_target; // K + m_T_target_is_HTF = T_target_is_HTF; + m_cp_HTF = cp_htf; // kJ/kg K + m_dT_BP = dT_bp; + m_HTF_PHX_cold_approach = htf_phx_cold_approach; + m_set_HTF_mdot = set_HTF_mdot; + + m_is_bp_par_set = true; + } + + // Overridden - Optimize Cycle (fixed total UA) + int auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in); + + // Overridden - Optimize Cycle for target eta (variable total UA) + int auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg); + + // Objective Functions (internal use only) + double C_TurbineSplitFlow_Cycle::optimize_totalUA_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par); + double C_TurbineSplitFlow_Cycle::optimize_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_turbinesplitflow_core& htrbp_core); + + // Off Design + + void reset_ms_od_turbo_bal_csp_solved(); + + int off_design_fix_shaft_speeds(S_od_par& od_phi_par_in, double od_tol /*-*/); + + virtual int solve_OD_all_coolers_fan_power(double T_amb /*K*/, double od_tol /*-*/, double& W_dot_fan /*MWe*/); + + virtual int solve_OD_mc_cooler_fan_power(double T_amb /*K*/, double od_tol /*-*/, double& W_dot_mc_cooler_fan /*MWe*/, double& P_co2_out /*kPa*/); + + virtual int solve_OD_pc_cooler_fan_power(double T_amb /*K*/, double od_tol /*-*/, double& W_dot_pc_cooler_fan /*MWe*/, double& P_co2_out /*kPa*/); + + double get_od_temp(int n_state_point); + + double get_od_pres(int n_state_point); + + virtual void check_od_solution(double& diff_m_dot, double& diff_E_cycle, + double& diff_Q_LTR, double& diff_Q_HTR); + + void set_od_temp(int n_state_point, double temp_K); + + void set_od_pres(int n_state_point, double pres_kPa); + + void off_design_recompressor(double T_in, double P_in, double m_dot, double P_out, double tol /*-*/, int& error_code, double& T_out); + + void estimate_od_turbo_operation(double T_mc_in /*K*/, double P_mc_in /*kPa*/, double f_recomp /*-*/, double T_t_in /*K*/, double phi_mc /*-*/, + int& mc_error_code, double& mc_w_tip_ratio /*-*/, double& P_mc_out /*kPa*/, + int& rc_error_code, double& rc_w_tip_ratio /*-*/, double& rc_phi /*-*/, + bool is_update_ms_od_solved = false); + + const C_comp_multi_stage::S_od_solved* get_rc_od_solved() + { + throw(C_csp_exception("Turbine split flow config does not have a recompressor")); + //return m_rc_ms.get_od_solved(); + } + + /*const S_od_turbo_bal_csp_solved* get_od_turbo_bal_csp_solved() + { + return &ms_od_turbo_bal_csp_solved; + } + + double get_max_target() + { + return m_biggest_target; + }*/ + + + +}; + +// Nlopt objective functions +double nlopt_optimize_totalUA_func(const std::vector& x, std::vector& grad, void* data); + +double nlopt_optimize_par_func(const std::vector& x, std::vector& grad, void* data); + + + + +// Penalty value methods +double sigmoid(const double val); + +double logit(const double val); + +#endif From a3e3ddd68a99ff507fd297aadc6758c29d57f467 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Tue, 2 Apr 2024 16:52:47 -0600 Subject: [PATCH 49/94] Add tsf specific inputs to cmod and shared classes. Rename core tsf model. --- ssc/csp_common.cpp | 5 + tcs/sco2_cycle_templates.h | 1 + tcs/sco2_pc_csp_int.cpp | 24 ++++ tcs/sco2_turbinesplitflow_cycle.cpp | 202 +++++++++++++++++++++++++--- tcs/sco2_turbinesplitflow_cycle.h | 43 +++--- 5 files changed, 228 insertions(+), 47 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 8a35956bcc..e76de05682 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -819,6 +819,11 @@ var_info vtab_sco2_design[] = { { SSC_INPUT, SSC_NUMBER, "deltaT_bypass", "sco2 Bypass Outlet Temp - HTR_HP_OUT Temp", "C", "", "System Design", "cycle_config=3", "", "" }, { SSC_INPUT, SSC_NUMBER, "set_HTF_mdot", "For HTR Bypass ONLY, 0 = calculate HTF mdot (need to set dT_PHX_cold_approach), > 0 = HTF mdot kg/s", "kg/s", "", "System Design", "?=0", "", "" }, + // Turbine Split Flow Design + { SSC_INPUT, SSC_NUMBER, "is_turbine_split_ok", "1 = Yes, 0 = No Second Turbine, < 0 = fix split_frac to abs(input)","", "", "", "cycle_config=4", "", "" }, + { SSC_INPUT, SSC_NUMBER, "eta_isen_t2", "Design secondary turbine isentropic efficiency (TSF only)", "-", "", "", "cycle_config=4", "", "" }, + + // DEBUG //{ SSC_OUTPUT, SSC_STRING, "debug_string", "output string used for debug", "C", "", "System Design", "cycle_config=3", "", "" }, diff --git a/tcs/sco2_cycle_templates.h b/tcs/sco2_cycle_templates.h index 7c58ef2e0a..73d410fa80 100644 --- a/tcs/sco2_cycle_templates.h +++ b/tcs/sco2_cycle_templates.h @@ -212,6 +212,7 @@ class C_sco2_cycle_core double m_is_recomp_ok; //[-] 1 = Yes, 0 = simple cycle only, < 0 = fix f_recomp to abs(input) double m_is_bypass_ok; //[-] 1 = Yes, 0 = no bypass, < 0 = fix bp_frac to abs(input) + double m_is_turbinesplit_ok; //[-] 1 = Yes, 0 = no secondary turbine, < 0 = fix split_frac to abs(input) (Turbine split flow ONLY) bool m_fixed_P_mc_out; //[-] if true, P_mc_out is fixed at 'm_P_high_limit' diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index 744dc44c1c..e42d28d771 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -36,6 +36,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "sco2_recompression_cycle.h" #include "sco2_partialcooling_cycle.h" #include "sco2_htrbypass_cycle.h" +#include "sco2_turbinesplitflow_cycle.h" #include "csp_solver_util.h" #include "CO2_properties.h" @@ -198,6 +199,29 @@ void C_sco2_phx_air_cooler::design_core() mpc_sco2_cycle = std::move(c_bp_cycle); } + else if (ms_des_par.m_cycle_config == 4) + { + std::unique_ptr c_bp_cycle = std::unique_ptr(new C_TurbineSplitFlow_Cycle( + turbo_gen_motor_config, + eta_generator, + T_mc_in, + ms_des_par.m_W_dot_net, + T_t_in, ms_des_par.m_P_high_limit, + ms_des_par.m_DP_LT, ms_des_par.m_DP_HT, + ms_des_par.m_DP_PC, ms_des_par.m_DP_PHX, + ms_des_par.m_LTR_N_sub_hxrs, ms_des_par.m_HTR_N_sub_hxrs, + ms_des_par.m_eta_mc, ms_des_par.m_mc_comp_type, + ms_des_par.m_eta_rc, + ms_des_par.m_eta_t, ms_des_par.m_N_turbine, + ms_des_par.m_frac_fan_power, ms_des_par.m_eta_fan, ms_des_par.m_deltaP_cooler_frac, + ms_des_par.m_N_nodes_pass, + ms_des_par.m_T_amb_des, ms_des_par.m_elevation)); + + s_cycle_config = "turbine split flow"; + + + mpc_sco2_cycle = std::move(c_bp_cycle); + } else { std::unique_ptr c_rc_cycle = std::unique_ptr(new C_RecompCycle( diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp index 075c1df49f..6a4471a58e 100644 --- a/tcs/sco2_turbinesplitflow_cycle.cpp +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -41,17 +41,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ********************************************************************************** C_sco2_htrbp_core CORE MODEL -void C_sco2_turbinesplitflow_core::initialize_solve() +void C_sco2_tsf_core::initialize_solve() { m_outputs.Init(); } -int C_sco2_turbinesplitflow_core::solve() +int C_sco2_tsf_core::solve() { return -1; } -int C_sco2_turbinesplitflow_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_solved) +int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_solved) { // Design Main Compressor { @@ -187,12 +187,12 @@ int C_sco2_turbinesplitflow_core::finalize_design(C_sco2_cycle_core::S_design_so return 0; } -int C_sco2_turbinesplitflow_core::solve_HTR_LTR(double T_HTR_HP_OUT_guess, double* diff_T_HTR_HP_out) +int C_sco2_tsf_core::solve_HTR_LTR(double T_HTR_HP_OUT_guess, double* diff_T_HTR_HP_out) { return -1; } -void C_sco2_turbinesplitflow_core::reset() +void C_sco2_tsf_core::reset() { this->m_inputs = S_sco2_tsf_in(); this->m_outputs.Init(); @@ -208,6 +208,177 @@ void C_sco2_turbinesplitflow_core::reset() /// void C_TurbineSplitFlow_Cycle::auto_opt_design_core(int& error_code) { + // Create 'ms_opt_des_par' for Design Variables + S_opt_design_parameters opt_par; + { + // Max Pressure + double best_P_high = m_P_high_limit; //[kPa] + double PR_mc_guess = 2.5; //[-] + + opt_par.m_fixed_P_mc_out = ms_auto_opt_des_par.m_fixed_P_mc_out; //[-] + if (!opt_par.m_fixed_P_mc_out) + { + double P_low_limit = std::min(m_P_high_limit, std::max(10.E3, m_P_high_limit * 0.2)); //[kPa] + + //best_P_high = fminbr(P_low_limit, m_P_high_limit, &fmin_cb_opt_des_fixed_P_high, this, 1.0); + best_P_high = m_P_high_limit; + } + opt_par.m_P_mc_out_guess = best_P_high; //[kPa] + //ms_opt_des_par.m_fixed_P_mc_out = true; + + // Pressure Ratio (min pressure) + opt_par.m_fixed_PR_HP_to_LP = ms_auto_opt_des_par.m_fixed_PR_HP_to_LP; //[-] + if (opt_par.m_fixed_PR_HP_to_LP) + { + opt_par.m_PR_HP_to_LP_guess = ms_auto_opt_des_par.m_PR_HP_to_LP_guess; //[-] + } + else + { + opt_par.m_PR_HP_to_LP_guess = PR_mc_guess; //[-] + } + + // Is recompression fraction fixed or optimized? + if (ms_auto_opt_des_par.m_is_turbinesplit_ok <= 0.0) + { // fixed + opt_par.m_split_frac_guess = std::abs(ms_auto_opt_des_par.m_is_turbinesplit_ok); + opt_par.m_fixed_split_frac = true; + } + else + { // optimized + opt_par.m_split_frac_guess = 0.5; + opt_par.m_fixed_split_frac = false; + } + + // LTR HTR UA Ratio + opt_par.m_LT_frac_guess = 0.5; + opt_par.m_fixed_LT_frac = false; + if (ms_auto_opt_des_par.m_LTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_auto_opt_des_par.m_HTR_target_code != NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + opt_par.m_fixed_LT_frac = true; + } + + // Set Design Method + if (opt_par.m_fixed_LT_frac == true) + opt_par.m_design_method = 3; + else + opt_par.m_design_method = 2; + + } + + // Set up baseline core inputs (will go somewhere else) + C_sco2_tsf_core::S_sco2_tsf_in core_inputs; + { + // From Auto Opt Design Parameters + core_inputs.m_LTR_target_code = ms_auto_opt_des_par.m_LTR_target_code; + core_inputs.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; + core_inputs.m_LTR_min_dT = ms_auto_opt_des_par.m_LTR_min_dT; + core_inputs.m_LTR_eff_target = ms_auto_opt_des_par.m_LTR_eff_target; + core_inputs.m_LTR_eff_max = ms_auto_opt_des_par.m_LTR_eff_max; + + core_inputs.m_LTR_od_UA_target_type = ms_auto_opt_des_par.m_LTR_od_UA_target_type; + core_inputs.m_HTR_target_code = ms_auto_opt_des_par.m_HTR_target_code; + core_inputs.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; + core_inputs.m_HTR_min_dT = ms_auto_opt_des_par.m_HTR_min_dT; + core_inputs.m_HTR_eff_target = ms_auto_opt_des_par.m_HTR_eff_target; + core_inputs.m_HTR_eff_max = ms_auto_opt_des_par.m_HTR_eff_max; + core_inputs.m_HTR_od_UA_target_type = ms_auto_opt_des_par.m_HTR_od_UA_target_type; + core_inputs.m_des_tol = ms_auto_opt_des_par.m_des_tol; + core_inputs.m_is_des_air_cooler = ms_auto_opt_des_par.m_is_des_air_cooler; + + // From Constructor + core_inputs.m_LTR_N_sub_hxrs = m_LTR_N_sub_hxrs; // Comes from constructor (constant) + core_inputs.m_HTR_N_sub_hxrs = m_HTR_N_sub_hxrs; // Comes from constructor (constant) + core_inputs.m_W_dot_net_design = m_W_dot_net; // Comes from constructor (constant) + core_inputs.m_T_mc_in = m_T_mc_in; // Comes from constructor (constant) + core_inputs.m_T_t_in = m_T_t_in; // Comes from constructor (constant) + core_inputs.m_DP_LTR = m_DP_LTR; // Comes from constructor (constant) + core_inputs.m_DP_HTR = m_DP_HTR; // Comes from constructor (constant) + core_inputs.m_DP_PC_main = m_DP_PC_main; // Comes from constructor (constant) + core_inputs.m_DP_PHX = m_DP_PHX; // Comes from constructor (constant) + core_inputs.m_eta_mc = m_eta_mc; // Comes from constructor (constant) + core_inputs.m_eta_t = m_eta_t; // Comes from constructor (constant) + core_inputs.m_eta_rc = m_eta_rc; // Comes from constructor (constant) + core_inputs.m_eta_generator = m_eta_generator; // Comes from constructor (constant) + core_inputs.m_frac_fan_power = m_frac_fan_power; // Comes from constructor (constant) + core_inputs.m_eta_fan = m_eta_fan; // Comes from constructor (constant) + core_inputs.m_deltaP_cooler_frac = m_deltaP_cooler_frac; // Comes from constructor (constant) + core_inputs.m_T_amb_des = m_T_amb_des; // Comes from constructor (constant) + core_inputs.m_elevation = m_elevation; // Comes from constructor (constant) + core_inputs.m_N_nodes_pass = m_N_nodes_pass; // Comes from constructor (constant) + core_inputs.m_mc_comp_model_code = m_mc_comp_model_code; // Comes from constructor (constant) + core_inputs.m_N_turbine = m_N_turbine; // Comes from constructor (constant) + + core_inputs.m_rc_comp_model_code = C_comp__psi_eta_vs_phi::E_snl_radial_via_Dyreby; // Constant + + // From special bypass fraction function (should remove) + core_inputs.m_dT_BP = m_dT_BP; // Comes from bp par function (constant) + core_inputs.m_set_HTF_mdot = m_set_HTF_mdot; // Comes from bp par function (constant) + core_inputs.m_cp_HTF = m_cp_HTF; // Comes from bp par function (constant) + core_inputs.m_T_HTF_PHX_inlet = m_T_HTF_PHX_inlet; // Comes from bp par function (constant) + core_inputs.m_HTF_PHX_cold_approach_input = m_HTF_PHX_cold_approach; // Comes from bp par function (constant) + + + // Handle design variables (check if fixed or free) + { + // Recompression Fraction + if (opt_par.m_fixed_split_frac == true) + core_inputs.m_recomp_frac = opt_par.m_split_frac_guess; + else + throw new C_csp_exception("not handled"); + + // MC Outlet Pressure + if (opt_par.m_fixed_P_mc_out == true) + core_inputs.m_P_mc_out = opt_par.m_P_mc_out_guess; + else + throw new C_csp_exception("not handled"); + + // Recuperator split fraction + double LT_frac_local = opt_par.m_LT_frac_guess; + if (ms_auto_opt_des_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || ms_auto_opt_des_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + core_inputs.m_LTR_UA = ms_auto_opt_des_par.m_UA_rec_total * LT_frac_local; + core_inputs.m_HTR_UA = ms_auto_opt_des_par.m_UA_rec_total * (1.0 - LT_frac_local); + } + else + { + core_inputs.m_LTR_UA = ms_auto_opt_des_par.m_LTR_UA; //[kW/K] + core_inputs.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; //[kW/K] + } + + + // Pressure Ratio is calculated in callback + } + + } + + // Handle Pressure Ratio (temporary) + double PR_mc_local = -999.9; + double P_mc_in = -999.9; + if (!opt_par.m_fixed_PR_HP_to_LP) + { + throw new C_csp_exception("not handled"); + } + else + { + if (opt_par.m_PR_HP_to_LP_guess >= 0.0) + { + PR_mc_local = opt_par.m_PR_HP_to_LP_guess; + P_mc_in = core_inputs.m_P_mc_out / PR_mc_local; //[kPa] + } + else + { + P_mc_in = std::abs(opt_par.m_PR_HP_to_LP_guess); //[kPa] + } + } + + core_inputs.m_P_mc_in = P_mc_in; + + + // Should have enough to run model (with all variables fixed) + C_sco2_tsf_core tsf_core; + tsf_core.set_inputs(core_inputs); + tsf_core.solve(); + return; } @@ -229,7 +400,7 @@ void C_TurbineSplitFlow_Cycle::auto_opt_design_hit_eta_core(int& error_code, con /// int C_TurbineSplitFlow_Cycle::optimize_totalUA(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, - C_sco2_turbinesplitflow_core::S_sco2_tsf_in& optimal_inputs) + C_sco2_tsf_core::S_sco2_tsf_in& optimal_inputs) { return -1;; } @@ -245,8 +416,8 @@ int C_TurbineSplitFlow_Cycle::optimize_totalUA(const S_auto_opt_design_parameter /// int C_TurbineSplitFlow_Cycle::optimize_par(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, - C_sco2_turbinesplitflow_core::S_sco2_tsf_in& core_inputs, - C_sco2_turbinesplitflow_core::S_sco2_tsf_in& optimal_inputs) + C_sco2_tsf_core::S_sco2_tsf_in& core_inputs, + C_sco2_tsf_core::S_sco2_tsf_in& optimal_inputs) { return -1; } @@ -307,7 +478,7 @@ double C_TurbineSplitFlow_Cycle::optimize_totalUA_return_objective_metric(const double C_TurbineSplitFlow_Cycle::optimize_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, - C_sco2_turbinesplitflow_core& htrbp_core) + C_sco2_tsf_core& htrbp_core) { return 0; } @@ -372,22 +543,13 @@ void C_TurbineSplitFlow_Cycle::estimate_od_turbo_operation(double T_mc_in, doubl // ********************************************************************************** PUBLIC Methods defined outside of any class -double nlopt_optimize_totalUA_func(const std::vector& x, std::vector& grad, void* data) +double nlopt_tsf_optimize_totalUA_func(const std::vector& x, std::vector& grad, void* data) { return 0; } -double nlopt_optimize_par_func(const std::vector& x, std::vector& grad, void* data) +double nlopt_tsf_optimize_par_func(const std::vector& x, std::vector& grad, void* data) { return 0; } -double sigmoid(const double val) -{ - return 1.0 / (1.0 + std::exp(-1.0 * val)); -} - -double logit(const double val) -{ - return std::log(val / (1.0 - val)); -} diff --git a/tcs/sco2_turbinesplitflow_cycle.h b/tcs/sco2_turbinesplitflow_cycle.h index 697e5f246f..0351f8fe4d 100644 --- a/tcs/sco2_turbinesplitflow_cycle.h +++ b/tcs/sco2_turbinesplitflow_cycle.h @@ -46,10 +46,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "nlopt_callbacks.h" - +// Core Turbine Split Flow Model // This class is purely for solving the cycle // No optimization -class C_sco2_turbinesplitflow_core +class C_sco2_tsf_core { public: @@ -226,10 +226,10 @@ class C_sco2_turbinesplitflow_core class C_mono_htrbp_core_HTR_des : public C_monotonic_equation { private: - C_sco2_turbinesplitflow_core* m_tsf_cycle; + C_sco2_tsf_core* m_tsf_cycle; public: - C_mono_htrbp_core_HTR_des(C_sco2_turbinesplitflow_core* tsf_cycle) + C_mono_htrbp_core_HTR_des(C_sco2_tsf_core* tsf_cycle) { m_tsf_cycle = tsf_cycle; } @@ -252,7 +252,7 @@ class C_sco2_turbinesplitflow_core S_sco2_tsf_out m_outputs; // Public Methods - C_sco2_turbinesplitflow_core() + C_sco2_tsf_core() { m_outputs.Init(); m_co2_props = CO2_state(); @@ -283,11 +283,8 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core double m_PR_HP_to_LP_guess; //[-] Initial guess for ratio of P_mc_out to P_LP_in bool m_fixed_PR_HP_to_LP; //[-] if true, ratio of P_mc_out to P_mc_in is fixed at PR_mc_guess - double m_recomp_frac_guess; //[-] Initial guess for design-point recompression fraction - bool m_fixed_recomp_frac; //[-] if true, recomp_frac is fixed at recomp_frac_guess - - double m_bypass_frac_guess; //[-] Initial guess for design-point bypass fraction - bool m_fixed_bypass_frac; //[-] if true, bypass_frac is fixed at bypass_frac_guess + double m_split_frac_guess; //[-] Initial guess for design-point split flow fraction (0.0 is no secondary turbine) + bool m_fixed_split_frac; //[-] if true, split_frac is fixed at split_frac_guess double m_LT_frac_guess; //[-] Initial guess for fraction of UA_rec_total that is in the low-temperature recuperator bool m_fixed_LT_frac; //[-] if true, LT_frac is fixed at LT_frac_guess @@ -301,15 +298,14 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core S_opt_design_parameters() { - m_P_mc_out_guess = m_PR_HP_to_LP_guess = m_recomp_frac_guess = m_LT_frac_guess = - m_bypass_frac_guess = m_eta_thermal_target = + m_P_mc_out_guess = m_PR_HP_to_LP_guess = m_split_frac_guess = m_LT_frac_guess = + m_eta_thermal_target = m_UA_recup_total_max = m_UA_recup_total_min = std::numeric_limits::quiet_NaN(); m_design_method = -1; - m_fixed_recomp_frac = false; - m_fixed_bypass_frac = false; + m_fixed_split_frac = false; m_fixed_LT_frac = false; m_fixed_PR_HP_to_LP = false; m_fixed_P_mc_out = false; @@ -334,15 +330,15 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core bool m_is_bp_par_set; // Are bp parameters set // Optimal htrbp core class (contains all results and component data) - C_sco2_turbinesplitflow_core m_optimal_tsf_core; + C_sco2_tsf_core m_optimal_tsf_core; void auto_opt_design_core(int& error_code); void auto_opt_design_hit_eta_core(int& error_code, const double eta_thermal_target); - int optimize_totalUA(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_turbinesplitflow_core::S_sco2_tsf_in& optimal_inputs); + int optimize_totalUA(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_tsf_core::S_sco2_tsf_in& optimal_inputs); - int optimize_par(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_turbinesplitflow_core::S_sco2_tsf_in& core_inputs, C_sco2_turbinesplitflow_core::S_sco2_tsf_in& optimal_inputs); + int optimize_par(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_tsf_core::S_sco2_tsf_in& core_inputs, C_sco2_tsf_core::S_sco2_tsf_in& optimal_inputs); protected: @@ -414,7 +410,7 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core // Objective Functions (internal use only) double C_TurbineSplitFlow_Cycle::optimize_totalUA_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par); - double C_TurbineSplitFlow_Cycle::optimize_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_turbinesplitflow_core& htrbp_core); + double C_TurbineSplitFlow_Cycle::optimize_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_tsf_core& htrbp_core); // Off Design @@ -467,16 +463,9 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core }; // Nlopt objective functions -double nlopt_optimize_totalUA_func(const std::vector& x, std::vector& grad, void* data); - -double nlopt_optimize_par_func(const std::vector& x, std::vector& grad, void* data); - - - +double nlopt_tsf_optimize_totalUA_func(const std::vector& x, std::vector& grad, void* data); -// Penalty value methods -double sigmoid(const double val); +double nlopt_tsf_optimize_par_func(const std::vector& x, std::vector& grad, void* data); -double logit(const double val); #endif From 13c86e86a2ad8265f80780e4ede7aced72f76983 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Wed, 3 Apr 2024 08:45:32 -0600 Subject: [PATCH 50/94] Add tsf specific parameters to tsf class. Handle variable exchange from cmod. --- ssc/csp_common.cpp | 12 ++++++- tcs/sco2_pc_csp_int.cpp | 8 +++-- tcs/sco2_pc_csp_int.h | 8 +++-- tcs/sco2_turbinesplitflow_cycle.cpp | 8 +---- tcs/sco2_turbinesplitflow_cycle.h | 56 +++++------------------------ 5 files changed, 31 insertions(+), 61 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index e76de05682..6fd39e55d3 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -820,7 +820,7 @@ var_info vtab_sco2_design[] = { { SSC_INPUT, SSC_NUMBER, "set_HTF_mdot", "For HTR Bypass ONLY, 0 = calculate HTF mdot (need to set dT_PHX_cold_approach), > 0 = HTF mdot kg/s", "kg/s", "", "System Design", "?=0", "", "" }, // Turbine Split Flow Design - { SSC_INPUT, SSC_NUMBER, "is_turbine_split_ok", "1 = Yes, 0 = No Second Turbine, < 0 = fix split_frac to abs(input)","", "", "", "cycle_config=4", "", "" }, + { SSC_INPUT, SSC_NUMBER, "is_turbine_split_ok", "1 = Yes, 0 = No Second Turbine, < 0 = fix split_frac to abs(input)","", "", "", "?=1", "", "" }, { SSC_INPUT, SSC_NUMBER, "eta_isen_t2", "Design secondary turbine isentropic efficiency (TSF only)", "-", "", "", "cycle_config=4", "", "" }, @@ -1099,6 +1099,7 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c s_sco2_des_par.m_is_recomp_ok = cm->as_double("is_recomp_ok"); s_sco2_des_par.m_is_bypass_ok = cm->as_double("is_bypass_ok"); + s_sco2_des_par.m_is_turbine_split_ok = cm->as_double("is_turbine_split_ok"); s_sco2_des_par.m_P_high_limit = cm->as_double("P_high_limit")*1000.0; //[kPa], convert from MPa s_sco2_des_par.m_fixed_P_mc_out = cm->as_integer("is_P_high_fixed"); //[-] @@ -1271,6 +1272,15 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c //s_sco2_des_par.m_phx_dt_cold_approach = cm->as_double("dT_PHX_cold_approach"); // [delta C] } + // Turbine Split Flow Configuration Paramters + if (s_sco2_des_par.m_cycle_config == 4) + { + s_sco2_des_par.m_eta_t2 = cm->as_double("eta_isen_t2"); + } + else + { + s_sco2_des_par.m_eta_t2 = s_sco2_des_par.m_eta_t; + } // For try/catch below int out_type = -1; diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index e42d28d771..1a376ef1b1 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -201,7 +201,7 @@ void C_sco2_phx_air_cooler::design_core() } else if (ms_des_par.m_cycle_config == 4) { - std::unique_ptr c_bp_cycle = std::unique_ptr(new C_TurbineSplitFlow_Cycle( + std::unique_ptr c_tsf_cycle = std::unique_ptr(new C_TurbineSplitFlow_Cycle( turbo_gen_motor_config, eta_generator, T_mc_in, @@ -212,7 +212,8 @@ void C_sco2_phx_air_cooler::design_core() ms_des_par.m_LTR_N_sub_hxrs, ms_des_par.m_HTR_N_sub_hxrs, ms_des_par.m_eta_mc, ms_des_par.m_mc_comp_type, ms_des_par.m_eta_rc, - ms_des_par.m_eta_t, ms_des_par.m_N_turbine, + ms_des_par.m_eta_t, ms_des_par.m_eta_t2, + ms_des_par.m_N_turbine, ms_des_par.m_frac_fan_power, ms_des_par.m_eta_fan, ms_des_par.m_deltaP_cooler_frac, ms_des_par.m_N_nodes_pass, ms_des_par.m_T_amb_des, ms_des_par.m_elevation)); @@ -220,7 +221,7 @@ void C_sco2_phx_air_cooler::design_core() s_cycle_config = "turbine split flow"; - mpc_sco2_cycle = std::move(c_bp_cycle); + mpc_sco2_cycle = std::move(c_tsf_cycle); } else { @@ -361,6 +362,7 @@ void C_sco2_phx_air_cooler::design_core() des_params.m_is_recomp_ok = ms_des_par.m_is_recomp_ok; des_params.m_is_bypass_ok = ms_des_par.m_is_bypass_ok; + des_params.m_is_turbinesplit_ok = ms_des_par.m_is_turbine_split_ok; auto_err_code = mpc_sco2_cycle->auto_opt_design(des_params); } diff --git a/tcs/sco2_pc_csp_int.h b/tcs/sco2_pc_csp_int.h index 0e32421a77..4dc529e5c4 100644 --- a/tcs/sco2_pc_csp_int.h +++ b/tcs/sco2_pc_csp_int.h @@ -94,12 +94,14 @@ class C_sco2_phx_air_cooler double m_eta_rc; //[-] design-point efficiency of the recompressor; isentropic if positive, polytropic if negative double m_eta_pc; //[-] design-point efficiency of the precompressor; isentropic if positive, polytropic if negative double m_eta_t; //[-] design-point efficiency of the turbine; isentropic if positive, polytropic if negative - double m_P_high_limit; //[kPa] maximum allowable pressure in cycle + double m_eta_t2; //[-] design-point efficiency of the secondary turbine (TSF ONLY); isentropic if positive, polytropic if negative + double m_P_high_limit; //[kPa] maximum allowable pressure in cycle double m_des_tol; //[-] Design point convergence tolerance double m_des_opt_tol; //[-] Optimization tolerance double m_N_turbine; //[rpm] Turbine shaft speed (negative values link turbine to compressor) double m_is_recomp_ok; //[-] 1 = Yes, 0 = simple cycle only, < 0 = fix f_recomp to abs(input) double m_is_bypass_ok; //[-] 1 = Yes, 0 = no bypass, < 0 = fix bp_frac to abs(input) + double m_is_turbine_split_ok; //[-] 1 = Yes, 0 = No Second Turbine, < 0 = fix split_frac to abs(input) int m_des_objective_type; //[2] = min phx deltat then max eta, [else] max eta double m_min_phx_deltaT; //[C] @@ -164,9 +166,9 @@ class C_sco2_phx_air_cooler m_LTR_UA = m_LTR_min_dT = m_LTR_eff_target = m_LTR_eff_max = m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = - m_eta_mc = m_eta_rc = m_eta_pc = m_eta_t = + m_eta_mc = m_eta_rc = m_eta_pc = m_eta_t = m_eta_t2 = m_P_high_limit = m_des_tol = m_des_opt_tol = m_N_turbine = - m_is_recomp_ok = + m_is_recomp_ok = m_is_turbine_split_ok = m_PR_HP_to_LP_guess = m_f_PR_HP_to_IP_guess = diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp index 6a4471a58e..2d57f89558 100644 --- a/tcs/sco2_turbinesplitflow_cycle.cpp +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -297,6 +297,7 @@ void C_TurbineSplitFlow_Cycle::auto_opt_design_core(int& error_code) core_inputs.m_DP_PHX = m_DP_PHX; // Comes from constructor (constant) core_inputs.m_eta_mc = m_eta_mc; // Comes from constructor (constant) core_inputs.m_eta_t = m_eta_t; // Comes from constructor (constant) + core_inputs.m_eta_t2 = m_eta_t2; // Comes from constructor (constant) core_inputs.m_eta_rc = m_eta_rc; // Comes from constructor (constant) core_inputs.m_eta_generator = m_eta_generator; // Comes from constructor (constant) core_inputs.m_frac_fan_power = m_frac_fan_power; // Comes from constructor (constant) @@ -310,13 +311,6 @@ void C_TurbineSplitFlow_Cycle::auto_opt_design_core(int& error_code) core_inputs.m_rc_comp_model_code = C_comp__psi_eta_vs_phi::E_snl_radial_via_Dyreby; // Constant - // From special bypass fraction function (should remove) - core_inputs.m_dT_BP = m_dT_BP; // Comes from bp par function (constant) - core_inputs.m_set_HTF_mdot = m_set_HTF_mdot; // Comes from bp par function (constant) - core_inputs.m_cp_HTF = m_cp_HTF; // Comes from bp par function (constant) - core_inputs.m_T_HTF_PHX_inlet = m_T_HTF_PHX_inlet; // Comes from bp par function (constant) - core_inputs.m_HTF_PHX_cold_approach_input = m_HTF_PHX_cold_approach; // Comes from bp par function (constant) - // Handle design variables (check if fixed or free) { diff --git a/tcs/sco2_turbinesplitflow_cycle.h b/tcs/sco2_turbinesplitflow_cycle.h index 0351f8fe4d..d184373d97 100644 --- a/tcs/sco2_turbinesplitflow_cycle.h +++ b/tcs/sco2_turbinesplitflow_cycle.h @@ -85,30 +85,24 @@ class C_sco2_tsf_core // Air cooler parameters bool m_is_des_air_cooler; //[-] False will skip physical air cooler design. UA will not be available for cost models. - - // Added double m_W_dot_net_design; //[kWe] Target net cycle power double m_T_mc_in; //[K] Compressor inlet temperature double m_T_t_in; //[K] Turbine inlet temperature - double m_dT_BP; //[delta K/C] BYPASS_OUT - HTR_HP_OUT std::vector m_DP_LTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) std::vector m_DP_HTR; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) std::vector m_DP_PC_main; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) std::vector m_DP_PHX; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) double m_eta_mc; //[-] design-point efficiency of the main compressor; isentropic if positive, polytropic if negative double m_eta_t; //[-] design-point efficiency of the turbine; isentropic if positive, polytropic if negative + double m_eta_t2; //[-] design-point efficiency of the secondary turbine; isentropic if positive, polytropic if negative double m_eta_rc; //[-] design-point efficiency of the recompressor; isentropic if positive, polytropic if negative double m_eta_generator; //[-] Mechanical-to-electrical efficiency of generator double m_frac_fan_power; //[-] Fraction of total cycle power 'S_des_par_cycle_dep.m_W_dot_fan_des' consumed by air fan - double m_set_HTF_mdot; //[kg/s] > 0 set HTF mass flow, <= 0 use bypass approach temp to calculate HTF mdot - double m_cp_HTF; //[kJ/kg K] HTF specific heat - double m_T_HTF_PHX_inlet; //[K] HTF Inlet Temperature double m_eta_fan; //[-] Fan isentropic efficiency double m_deltaP_cooler_frac; //[-] Fraction of high side (of cycle, i.e. comp outlet) pressure that is allowed as pressure drop to design the ACC double m_T_amb_des; //[K] Design point ambient temperature double m_elevation; //[m] Elevation (used to calculate ambient pressure) int m_N_nodes_pass; //[-] Number of nodes per pass - double m_HTF_PHX_cold_approach_input; //[delta K] PHX cold approach temperature. Only needed if m_set_HTF_mdot < 0 int m_mc_comp_model_code; // Main compressor model code int m_rc_comp_model_code; // Recompressor model code int m_N_turbine; //[rpm] Turbine rpm @@ -126,18 +120,14 @@ class C_sco2_tsf_core m_T_t_in = m_eta_mc = m_eta_t = + m_eta_t2 = m_eta_rc = m_eta_generator = m_frac_fan_power = - m_set_HTF_mdot = - m_cp_HTF = - m_T_HTF_PHX_inlet = m_eta_fan = m_deltaP_cooler_frac = m_T_amb_des = m_elevation = - m_dT_BP = - m_HTF_PHX_cold_approach_input = std::numeric_limits::quiet_NaN(); m_N_nodes_pass = 0; @@ -319,16 +309,9 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core int m_opt_iteration_count; // Counter of bypass iterations - // Bypass Specific HTF variables - int m_T_target_is_HTF; // Target Temperature is HTF (1) or cold sco2 at BP - double m_T_target; // [K] Target temperature (either HTF or sco2) - double m_T_HTF_PHX_inlet; // [K] HTF Primary Heat Exchanger Inlet Temperature - double m_set_HTF_mdot; // [kg/s] [0] calculate HTF mdot (need to set dT_PHX_cold_approach) [>0] mdot - double m_HTF_PHX_cold_approach; // [K] PHX cold approach temperature (need if m_set_HTF_mdot == 0) - double m_dT_BP; // [K] Temperature difference at second mixer inlet - double m_cp_HTF; // [kJ/kg K] HTF specific heat - bool m_is_bp_par_set; // Are bp parameters set - + // TSF specific parameters + double m_eta_t2; + // Optimal htrbp core class (contains all results and component data) C_sco2_tsf_core m_optimal_tsf_core; @@ -355,7 +338,8 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core int LTR_N_sub_hxrs, int HTR_N_sub_hxrs, double eta_mc, int mc_comp_model_code, double eta_rc, - double eta_t, double N_turbine, + double eta_t, double eta_t2, + double N_turbine, double frac_fan_power, double eta_fan, double deltaP_cooler_frac, int N_nodes_pass, double T_amb_des, double elevation) : @@ -372,36 +356,14 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core eta_t, N_turbine, frac_fan_power, eta_fan, deltaP_cooler_frac, N_nodes_pass, - T_amb_des, elevation) + T_amb_des, elevation), + m_eta_t2(eta_t2) { - m_T_target = m_T_HTF_PHX_inlet = m_set_HTF_mdot - = m_HTF_PHX_cold_approach = m_dT_BP - = m_cp_HTF - = std::numeric_limits::quiet_NaN(); - - m_T_target_is_HTF = -1; m_opt_iteration_count = 0; - - m_is_bp_par_set = false; } ~C_TurbineSplitFlow_Cycle() {}; - // Set Bypass Specific Parameters - void set_bp_par(double T_htf_phx_in, double T_target, double cp_htf, double dT_bp, - double htf_phx_cold_approach, double set_HTF_mdot, int T_target_is_HTF) - { - m_T_HTF_PHX_inlet = T_htf_phx_in; // K - m_T_target = T_target; // K - m_T_target_is_HTF = T_target_is_HTF; - m_cp_HTF = cp_htf; // kJ/kg K - m_dT_BP = dT_bp; - m_HTF_PHX_cold_approach = htf_phx_cold_approach; - m_set_HTF_mdot = set_HTF_mdot; - - m_is_bp_par_set = true; - } - // Overridden - Optimize Cycle (fixed total UA) int auto_opt_design(S_auto_opt_design_parameters& auto_opt_des_par_in); From 19048fc8b10a027914b59d0896bdc24ab4e43d8d Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Thu, 4 Apr 2024 11:53:18 -0600 Subject: [PATCH 51/94] Develop tsf design point up to HTR mono opt. --- tcs/sco2_cycle_templates.h | 1 + tcs/sco2_turbinesplitflow_cycle.cpp | 407 +++++++++++++++++++--------- tcs/sco2_turbinesplitflow_cycle.h | 45 ++- 3 files changed, 302 insertions(+), 151 deletions(-) diff --git a/tcs/sco2_cycle_templates.h b/tcs/sco2_cycle_templates.h index 73d410fa80..81b166c6aa 100644 --- a/tcs/sco2_cycle_templates.h +++ b/tcs/sco2_cycle_templates.h @@ -27,6 +27,7 @@ class C_sco2_cycle_core PC_OUT, // Precompressor outlet (partial cooling cycle) BYPASS_OUT, // Bypass outlet (htr bypass cycle) MIXER2_OUT, // Mixer 2 Outlet (htr bypass cycle) + TURB2_OUT, // Secondary Turbine Outlet (turbine split flow cycle) END_SCO2_STATES }; diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp index 2d57f89558..edbeab5e6c 100644 --- a/tcs/sco2_turbinesplitflow_cycle.cpp +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -39,7 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "fmin.h" -// ********************************************************************************** C_sco2_htrbp_core CORE MODEL +// ********************************************************************************** C_sco2_tsf_core CORE MODEL void C_sco2_tsf_core::initialize_solve() { @@ -48,147 +48,312 @@ void C_sco2_tsf_core::initialize_solve() int C_sco2_tsf_core::solve() { - return -1; -} + initialize_solve(); + m_outputs.m_error_code = -1; -int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_solved) -{ - // Design Main Compressor + // Apply scaling to the turbomachinery here { - int mc_design_err = m_outputs.m_mc_ms.design_given_outlet_state(m_inputs.m_mc_comp_model_code, m_outputs.m_temp[C_sco2_cycle_core::MC_IN], - m_outputs.m_pres[C_sco2_cycle_core::MC_IN], - m_outputs.m_m_dot_mc, - m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], - m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], - m_inputs.m_des_tol); - - if (mc_design_err != 0) - { - m_outputs.m_error_code = mc_design_err; - return m_outputs.m_error_code; - } + m_outputs.m_mc_ms.m_r_W_dot_scale = m_inputs.m_W_dot_net_design / 10.E3; //[-] + m_outputs.m_t.m_r_W_dot_scale = m_outputs.m_mc_ms.m_r_W_dot_scale; //[-] + m_outputs.m_t2.m_r_W_dot_scale = m_outputs.m_mc_ms.m_r_W_dot_scale; //[-] + } + + // Initialize Recuperators + { + // LTR + m_outputs.mc_LT_recup.initialize(m_inputs.m_LTR_N_sub_hxrs, m_inputs.m_LTR_od_UA_target_type); + // HTR + m_outputs.mc_HT_recup.initialize(m_inputs.m_HTR_N_sub_hxrs, m_inputs.m_HTR_od_UA_target_type); + } + + // Initialize a few variables + { + m_outputs.m_temp[C_sco2_cycle_core::MC_IN] = m_inputs.m_T_mc_in; //[K] + m_outputs.m_pres[C_sco2_cycle_core::MC_IN] = m_inputs.m_P_mc_in; + m_outputs.m_pres[C_sco2_cycle_core::MC_OUT] = m_inputs.m_P_mc_out; + m_outputs.m_temp[C_sco2_cycle_core::TURB_IN] = m_inputs.m_T_t_in; //[K] + } + + // Apply pressure drops to heat exchangers, fully defining the pressures at all states + { + // LTR_HP_OUT + if (m_inputs.m_DP_LTR[0] < 0.0) + m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MC_OUT] - m_outputs.m_pres[C_sco2_cycle_core::MC_OUT] * std::abs(m_inputs.m_DP_LTR[0]); // relative pressure drop specified for LT recuperator (cold stream) + else + m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MC_OUT] - m_inputs.m_DP_LTR[0]; // absolute pressure drop specified for LT recuperator (cold stream) + if ((m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && m_inputs.m_LTR_UA < 1.0E-12) + || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && m_inputs.m_LTR_UA < 1.0E-12) + || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && m_inputs.m_LTR_min_dT < 1.0E-12) + || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && m_inputs.m_LTR_eff_target < 1.0E-12)) + m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MC_OUT]; // If there is no LT recuperator, there is no pressure drop + + // TURB_IN + if (m_inputs.m_DP_PHX[0] < 0.0) + m_outputs.m_pres[C_sco2_cycle_core::TURB_IN] = m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT] - m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT] * std::abs(m_inputs.m_DP_PHX[0]); // relative pressure drop specified for PHX + else + m_outputs.m_pres[C_sco2_cycle_core::TURB_IN] = m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT] - m_inputs.m_DP_PHX[0]; // absolute pressure drop specified for PHX + + // HTR_HP_OUT + if (m_inputs.m_DP_HTR[0] < 0.0) + m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MC_OUT] - m_outputs.m_pres[C_sco2_cycle_core::MC_OUT] * std::abs(m_inputs.m_DP_HTR[0]); // relative pressure drop specified for HT recuperator (cold stream) + else + m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MC_OUT] - m_inputs.m_DP_HTR[0]; // absolute pressure drop specified for HT recuperator (cold stream) + if ((m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && m_inputs.m_HTR_UA < 1.0E-12) + || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && m_inputs.m_HTR_UA < 1.0E-12) + || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && m_inputs.m_HTR_min_dT < 1.0E-12) + || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && m_inputs.m_HTR_eff_target < 1.0E-12)) + m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MC_OUT]; // If there is no HT recuperator, there is no pressure drop + + // MIXER_OUT + if (m_inputs.m_DP_PC_main[1] < 0.0) + m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MC_IN] / (1.0 - std::abs(m_inputs.m_DP_PC_main[1])); // relative pressure drop specified for precooler: P1=P9-P9*rel_DP => P1=P9*(1-rel_DP) + else + m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MC_IN] + m_inputs.m_DP_PC_main[1]; + + // LTR_LP_OUT + m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT]; // Assume no pressure drop in mixer + + // HTR_LP_OUT + m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT] = m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT]; // Assume no pressure drop in mixer + + // TURB_OUT + if (m_inputs.m_DP_HTR[1] < 0.0) + m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT] = m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT] / (1.0 - std::abs(m_inputs.m_DP_HTR[1])); // relative pressure drop specified for HT recuperator (hot stream) + else + m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT] = m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT] + m_inputs.m_DP_HTR[1]; // absolute pressure drop specified for HT recuperator (hot stream) + if ((m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && m_inputs.m_HTR_UA < 1.0E-12) + || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && m_inputs.m_HTR_UA < 1.0E-12) + || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && m_inputs.m_HTR_min_dT < 1.0E-12) + || (m_inputs.m_HTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && m_inputs.m_HTR_eff_target < 1.0E-12)) + m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT] = m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT]; // if there is no HT recuperator, there is no pressure drop + + // TURB2_OUT + if (m_inputs.m_DP_LTR[1] < 0.0) + m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT] = m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT] / (1.0 - std::abs(m_inputs.m_DP_LTR[1])); // relative pressure drop specified for LT recuperator (hot stream) + else + m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT] = m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT] + m_inputs.m_DP_LTR[1]; // absolute pressure drop specified for HT recuperator (hot stream) + if ((m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA && m_inputs.m_LTR_UA < 1.0E-12) + || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_UA && m_inputs.m_LTR_UA < 1.0E-12) + || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_MIN_DT && m_inputs.m_LTR_min_dT < 1.0E-12) + || (m_inputs.m_LTR_target_code == NS_HX_counterflow_eqs::TARGET_EFFECTIVENESS && m_inputs.m_LTR_eff_target < 1.0E-12)) + m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT] = m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT]; // if there is no LT recuperator, there is no pressure drop + } - // Design Recompressor - if (m_inputs.m_recomp_frac > 0.01) + // Determine equivalent isentropic efficiencies for main compressor and turbine, if necessary. + double eta_mc_isen = std::numeric_limits::quiet_NaN(); + double eta_t_isen = std::numeric_limits::quiet_NaN(); { - int rc_des_err = m_outputs.m_rc_ms.design_given_outlet_state(m_inputs.m_rc_comp_model_code, m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT], - m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT], - m_outputs.m_m_dot_rc, - m_outputs.m_temp[C_sco2_cycle_core::RC_OUT], - m_outputs.m_pres[C_sco2_cycle_core::RC_OUT], - m_inputs.m_des_tol); - - if (rc_des_err != 0) + if (m_inputs.m_eta_mc < 0.0) { - m_outputs.m_error_code = rc_des_err; - return m_outputs.m_error_code; + int poly_error_code = 0; + + isen_eta_from_poly_eta(m_outputs.m_temp[C_sco2_cycle_core::MC_IN], m_outputs.m_pres[C_sco2_cycle_core::MC_IN], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], std::abs(m_inputs.m_eta_mc), + true, poly_error_code, eta_mc_isen); + + if (poly_error_code != 0) + { + m_outputs.m_error_code = poly_error_code; + return m_outputs.m_error_code; + } } + else + eta_mc_isen = m_inputs.m_eta_mc; + + if (m_inputs.m_eta_t < 0.0) + { + int poly_error_code = 0; - design_solved.m_is_rc = true; + isen_eta_from_poly_eta(m_outputs.m_temp[C_sco2_cycle_core::TURB_IN], m_outputs.m_pres[C_sco2_cycle_core::TURB_IN], m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT], std::abs(m_inputs.m_eta_t), + false, poly_error_code, eta_t_isen); + + if (poly_error_code != 0) + { + m_outputs.m_error_code = poly_error_code; + return m_outputs.m_error_code; + } + } + else + eta_t_isen = m_inputs.m_eta_t; } - else + + // Determine the outlet state and specific work for the main compressor and turbine. + + // Main compressor + m_outputs.m_w_mc = std::numeric_limits::quiet_NaN(); { - design_solved.m_is_rc = false; + int comp_error_code = 0; + + calculate_turbomachinery_outlet_1(m_outputs.m_temp[C_sco2_cycle_core::MC_IN], m_outputs.m_pres[C_sco2_cycle_core::MC_IN], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], eta_mc_isen, true, + comp_error_code, m_outputs.m_enth[C_sco2_cycle_core::MC_IN], m_outputs.m_entr[C_sco2_cycle_core::MC_IN], m_outputs.m_dens[C_sco2_cycle_core::MC_IN], m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], + m_outputs.m_enth[C_sco2_cycle_core::MC_OUT], m_outputs.m_entr[C_sco2_cycle_core::MC_OUT], m_outputs.m_dens[C_sco2_cycle_core::MC_OUT], m_outputs.m_w_mc); + + if (comp_error_code != 0) + { + m_outputs.m_error_code = comp_error_code; + return m_outputs.m_error_code; + } } - // Size Turbine + // Turbine + m_outputs.m_w_t = std::numeric_limits::quiet_NaN(); { - C_turbine::S_design_parameters t_des_par; - // Set turbine shaft speed - t_des_par.m_N_design = m_inputs.m_N_turbine; - t_des_par.m_N_comp_design_if_linked = m_outputs.m_mc_ms.get_design_solved()->m_N_design; //[rpm] m_mc.get_design_solved()->m_N_design; - // Turbine inlet state - t_des_par.m_P_in = m_outputs.m_pres[C_sco2_cycle_core::TURB_IN]; - t_des_par.m_T_in = m_outputs.m_temp[C_sco2_cycle_core::TURB_IN]; - t_des_par.m_D_in = m_outputs.m_dens[C_sco2_cycle_core::TURB_IN]; - t_des_par.m_h_in = m_outputs.m_enth[C_sco2_cycle_core::TURB_IN]; - t_des_par.m_s_in = m_outputs.m_entr[C_sco2_cycle_core::TURB_IN]; - // Turbine outlet state - t_des_par.m_P_out = m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT]; - t_des_par.m_h_out = m_outputs.m_enth[C_sco2_cycle_core::TURB_OUT]; - // Mass flow - t_des_par.m_m_dot = m_outputs.m_m_dot_t; - - int turb_size_error_code = 0; - m_outputs.m_t.turbine_sizing(t_des_par, turb_size_error_code); - - if (turb_size_error_code != 0) + int turbine_error_code = 0; + + calculate_turbomachinery_outlet_1(m_outputs.m_temp[C_sco2_cycle_core::TURB_IN], m_outputs.m_pres[C_sco2_cycle_core::TURB_IN], m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT], eta_t_isen, false, + turbine_error_code, m_outputs.m_enth[C_sco2_cycle_core::TURB_IN], m_outputs.m_entr[C_sco2_cycle_core::TURB_IN], m_outputs.m_dens[C_sco2_cycle_core::TURB_IN], m_outputs.m_temp[C_sco2_cycle_core::TURB_OUT], + m_outputs.m_enth[C_sco2_cycle_core::TURB_OUT], m_outputs.m_entr[C_sco2_cycle_core::TURB_OUT], m_outputs.m_dens[C_sco2_cycle_core::TURB_OUT], m_outputs.m_w_t); + + if (turbine_error_code != 0) { - m_outputs.m_error_code = turb_size_error_code; + m_outputs.m_error_code = turbine_error_code; return m_outputs.m_error_code; } } - // Design air cooler + // Solve Recuperators (iterate HTR_HP_OUT) { - // Structure for design parameters that are dependent on cycle design solution - C_CO2_to_air_cooler::S_des_par_cycle_dep s_air_cooler_des_par_dep; - // Set air cooler design parameters that are dependent on the cycle design solution - s_air_cooler_des_par_dep.m_T_hot_in_des = m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT]; // [K] - s_air_cooler_des_par_dep.m_P_hot_in_des = m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT]; // [kPa] - s_air_cooler_des_par_dep.m_m_dot_total = m_outputs.m_m_dot_mc; // [kg/s] - - // This pressure drop is currently uncoupled from the cycle design - double cooler_deltaP = m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT] - m_outputs.m_pres[C_sco2_cycle_core::MC_IN]; // [kPa] - if (cooler_deltaP == 0.0) - s_air_cooler_des_par_dep.m_delta_P_des = m_inputs.m_deltaP_cooler_frac * m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT]; // [kPa] - else - s_air_cooler_des_par_dep.m_delta_P_des = cooler_deltaP; // [kPa] - - s_air_cooler_des_par_dep.m_T_hot_out_des = m_outputs.m_temp[C_sco2_cycle_core::MC_IN]; // [K] - s_air_cooler_des_par_dep.m_W_dot_fan_des = m_inputs.m_frac_fan_power * m_outputs.m_W_dot_net / 1000.0; // [MWe] - // Structure for design parameters that are independent of cycle design solution - C_CO2_to_air_cooler::S_des_par_ind s_air_cooler_des_par_ind; - s_air_cooler_des_par_ind.m_T_amb_des = m_inputs.m_T_amb_des; // [K] - s_air_cooler_des_par_ind.m_elev = m_inputs.m_elevation; // [m] - s_air_cooler_des_par_ind.m_eta_fan = m_inputs.m_eta_fan; // [-] - s_air_cooler_des_par_ind.m_N_nodes_pass = m_inputs.m_N_nodes_pass; // [-] - - if (m_inputs.m_is_des_air_cooler && std::isfinite(m_inputs.m_deltaP_cooler_frac) && std::isfinite(m_inputs.m_frac_fan_power) - && std::isfinite(m_inputs.m_T_amb_des) && std::isfinite(m_inputs.m_elevation) && std::isfinite(m_inputs.m_eta_fan) && m_inputs.m_N_nodes_pass > 0) + C_mono_htrbp_core_HTR_LTR_des HTR_LTR_des_eq(this); + C_monotonic_eq_solver HTR_LTR_des_solver(HTR_LTR_des_eq); + + // Bounds + double T_HTR_HP_out_lower = m_outputs.m_temp[C_sco2_cycle_core::MC_OUT]; //[K] Coldest possible temp + double T_HTR_HP_out_upper = m_outputs.m_temp[C_sco2_cycle_core::TURB_IN]; //[K] Coldest possible temp (probably is TURB_OUT) + + // Solution Guess + double T_HTR_HP_out_guess_lower = 0.25 * (T_HTR_HP_out_upper - T_HTR_HP_out_lower) + T_HTR_HP_out_lower; // [K] + double T_HTR_HP_out_guess_upper = 0.75 * (T_HTR_HP_out_upper - T_HTR_HP_out_lower) + T_HTR_HP_out_lower; // [K] + + // Optimization Settings + HTR_LTR_des_solver.settings(m_inputs.m_des_tol* m_outputs.m_temp[C_sco2_cycle_core::MC_IN], 1000, T_HTR_HP_out_lower, T_HTR_HP_out_upper, false); + + // Optimization Output variables + double T_HTR_HP_out_solved, tol_T_HTR_HP_out_solved; + T_HTR_HP_out_solved = tol_T_HTR_HP_out_solved = std::numeric_limits::quiet_NaN(); + int iter_T_HTR_LP_out = -1; + + // Optimize + int T_HTR_HP_out_code = HTR_LTR_des_solver.solve(T_HTR_HP_out_guess_lower, T_HTR_HP_out_guess_upper, 0, + T_HTR_HP_out_solved, tol_T_HTR_HP_out_solved, iter_T_HTR_LP_out); + + // Check if converged + if (T_HTR_HP_out_code != C_monotonic_eq_solver::CONVERGED) { - m_outputs.mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, m_inputs.m_des_tol); + m_outputs.m_error_code = 25; + return m_outputs.m_error_code; } + + // Call solve_HTR_LTR to solve cycle with correct HTR_HP_out + double test = 0; + solve_HTR_LTR(T_HTR_HP_out_solved, &test); + + int x = 0; + } - // Get 'design_solved' structure from component classes - design_solved.ms_mc_ms_des_solved = *m_outputs.m_mc_ms.get_design_solved(); - design_solved.ms_rc_ms_des_solved = *m_outputs.m_rc_ms.get_design_solved(); - design_solved.ms_t_des_solved = *m_outputs.m_t.get_design_solved(); - design_solved.ms_LTR_des_solved = m_outputs.mc_LT_recup.ms_des_solved; - design_solved.ms_HTR_des_solved = m_outputs.mc_HT_recup.ms_des_solved; - design_solved.ms_mc_air_cooler = *m_outputs.mc_air_cooler.get_design_solved(); - - // Set solved design point metrics - design_solved.m_temp = m_outputs.m_temp; - design_solved.m_pres = m_outputs.m_pres; - design_solved.m_enth = m_outputs.m_enth; - design_solved.m_entr = m_outputs.m_entr; - design_solved.m_dens = m_outputs.m_dens; - - design_solved.m_eta_thermal = m_outputs.m_eta_thermal; - design_solved.m_W_dot_net = m_outputs.m_W_dot_net; - design_solved.m_m_dot_mc = m_outputs.m_m_dot_mc; - design_solved.m_m_dot_rc = m_outputs.m_m_dot_rc; - design_solved.m_m_dot_t = m_outputs.m_m_dot_t; - design_solved.m_recomp_frac = m_outputs.m_m_dot_rc / m_outputs.m_m_dot_t; - design_solved.m_bypass_frac = m_inputs.m_bypass_frac; - - design_solved.m_UA_LTR = m_inputs.m_LTR_UA; - design_solved.m_UA_HTR = m_inputs.m_HTR_UA; - - design_solved.m_W_dot_t = m_outputs.m_W_dot_t; //[kWe] - design_solved.m_W_dot_mc = m_outputs.m_W_dot_mc; //[kWe] - design_solved.m_W_dot_rc = m_outputs.m_W_dot_rc; //[kWe] - - design_solved.m_W_dot_cooler_tot = m_outputs.mc_air_cooler.get_design_solved()->m_W_dot_fan * 1.E3; //[kWe] convert from MWe + return -1; +} - return 0; +int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_solved) +{ + return -1; } int C_sco2_tsf_core::solve_HTR_LTR(double T_HTR_HP_OUT_guess, double* diff_T_HTR_HP_out) { + // Intialize + m_outputs.m_w_t2 = m_outputs.m_m_dot_mc = m_outputs.m_m_dot_t = m_outputs.m_m_dot_t2 + = m_outputs.m_Q_dot_LT = m_outputs.m_Q_dot_HT + = std::numeric_limits::quiet_NaN(); + + // Set temperature guess + m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT] = T_HTR_HP_OUT_guess; // [K] + + // Get HTR_HP_OUT co2 properties + { + int prop_error_code = CO2_TP(m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], &m_co2_props); + if (prop_error_code != 0) + { + *diff_T_HTR_HP_out = std::numeric_limits::quiet_NaN(); + return prop_error_code; + } + m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.enth; + m_outputs.m_entr[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.entr; + m_outputs.m_dens[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.dens; + } + + // Determine equivalent isentropic efficiencies for secondary turbine, if necessary + double eta_t2_isen = std::numeric_limits::quiet_NaN(); + { + if (m_inputs.m_eta_t2 < 0.0) + { + int poly_error_code = 0; + + isen_eta_from_poly_eta(m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT], std::abs(m_inputs.m_eta_t2), + false, poly_error_code, eta_t2_isen); + + if (poly_error_code != 0) + { + m_outputs.m_error_code = poly_error_code; + return m_outputs.m_error_code; + } + } + else + eta_t2_isen = m_inputs.m_eta_t2; + } + + // Simulate Secondary Turbine + { + int turbine2_error_code = 0; + + calculate_turbomachinery_outlet_1(m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT], eta_t2_isen, false, + turbine2_error_code, m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_entr[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_dens[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_temp[C_sco2_cycle_core::TURB2_OUT], + m_outputs.m_enth[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_entr[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_dens[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_w_t2); + + if (turbine2_error_code != 0) + { + m_outputs.m_error_code = turbine2_error_code; + return m_outputs.m_error_code; + } + } + + // Calculate Mass Flow Rates + { + m_outputs.m_m_dot_mc = m_inputs.m_W_dot_net_design + / (((m_outputs.m_w_t * (1.0 - m_inputs.m_split_frac)) + + (m_outputs.m_w_t2 * m_inputs.m_split_frac) + + (m_outputs.m_w_mc)) + * m_inputs.m_eta_generator); //[kg/s] + + m_outputs.m_m_dot_t = m_outputs.m_m_dot_mc * (1.0 - m_inputs.m_split_frac); //[kg/s] + m_outputs.m_m_dot_t2 = m_outputs.m_m_dot_mc * m_inputs.m_split_frac; //[kg/s] + } + + //// Simulate LTR + //{ + // m_outputs.mc_LT_recup.design_for_target__calc_outlet(m_inputs.m_LTR_target_code, + // m_inputs.m_LTR_UA, m_inputs.m_LTR_min_dT, m_inputs.m_LTR_eff_target, + // m_inputs.m_LTR_eff_max, + // m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], m_outputs.m_m_dot_t, m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT], + // m_outputs.m_temp[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_m_dot_t2, m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT], + // m_inputs.m_des_tol, + // m_outputs.m_Q_dot_LT, m_outputs.m_temp[C_sco2_cycle_core::LTR_HP_OUT], m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT]); + //} + + // Simulate HTR + double T_HTR_HP_out_calc = std::numeric_limits::quiet_NaN(); + { + m_outputs.mc_HT_recup.design_for_target__calc_outlet(m_inputs.m_HTR_target_code, + m_inputs.m_HTR_UA, m_inputs.m_HTR_min_dT, m_inputs.m_HTR_eff_target, + m_inputs.m_HTR_eff_max, + m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], m_outputs.m_m_dot_t2, m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], + m_outputs.m_temp[C_sco2_cycle_core::TURB_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT], m_outputs.m_m_dot_t, m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT], + m_inputs.m_des_tol, + m_outputs.m_Q_dot_HT, T_HTR_HP_out_calc, m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT]); + } + + *diff_T_HTR_HP_out = T_HTR_HP_out_calc - T_HTR_HP_OUT_guess; + return -1; } @@ -198,10 +363,10 @@ void C_sco2_tsf_core::reset() this->m_outputs.Init(); } -// ********************************************************************************** END C_sco2_htrbp_core +// ********************************************************************************** END C_sco2_tsf_core -// ********************************************************************************** PRIVATE C_HTRBypass_Cycle (: C_sco2_cycle_core) +// ********************************************************************************** PRIVATE C_TurbineSplitFlow_Cycle (: C_sco2_cycle_core) /// /// Core function to optimize cycle (fixed total UA) @@ -298,7 +463,6 @@ void C_TurbineSplitFlow_Cycle::auto_opt_design_core(int& error_code) core_inputs.m_eta_mc = m_eta_mc; // Comes from constructor (constant) core_inputs.m_eta_t = m_eta_t; // Comes from constructor (constant) core_inputs.m_eta_t2 = m_eta_t2; // Comes from constructor (constant) - core_inputs.m_eta_rc = m_eta_rc; // Comes from constructor (constant) core_inputs.m_eta_generator = m_eta_generator; // Comes from constructor (constant) core_inputs.m_frac_fan_power = m_frac_fan_power; // Comes from constructor (constant) core_inputs.m_eta_fan = m_eta_fan; // Comes from constructor (constant) @@ -309,14 +473,12 @@ void C_TurbineSplitFlow_Cycle::auto_opt_design_core(int& error_code) core_inputs.m_mc_comp_model_code = m_mc_comp_model_code; // Comes from constructor (constant) core_inputs.m_N_turbine = m_N_turbine; // Comes from constructor (constant) - core_inputs.m_rc_comp_model_code = C_comp__psi_eta_vs_phi::E_snl_radial_via_Dyreby; // Constant - // Handle design variables (check if fixed or free) { - // Recompression Fraction + // Turbine Split Fraction if (opt_par.m_fixed_split_frac == true) - core_inputs.m_recomp_frac = opt_par.m_split_frac_guess; + core_inputs.m_split_frac = opt_par.m_split_frac_guess; else throw new C_csp_exception("not handled"); @@ -339,6 +501,7 @@ void C_TurbineSplitFlow_Cycle::auto_opt_design_core(int& error_code) core_inputs.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; //[kW/K] } + // Pressure Ratio is calculated in callback } @@ -416,7 +579,7 @@ int C_TurbineSplitFlow_Cycle::optimize_par(const S_auto_opt_design_parameters& a return -1; } -// ********************************************************************************** PUBLIC Methods C_HTRBypass_Cycle (: C_sco2_cycle_core) +// ********************************************************************************** PUBLIC Methods C_TurbineSplitFlow_Cycle (: C_sco2_cycle_core) /// /// Optimize Cycle Design for FIXED total recuperator UA diff --git a/tcs/sco2_turbinesplitflow_cycle.h b/tcs/sco2_turbinesplitflow_cycle.h index d184373d97..e4e9c1807b 100644 --- a/tcs/sco2_turbinesplitflow_cycle.h +++ b/tcs/sco2_turbinesplitflow_cycle.h @@ -78,8 +78,8 @@ class C_sco2_tsf_core NS_HX_counterflow_eqs::E_UA_target_type m_HTR_od_UA_target_type; int m_HTR_N_sub_hxrs; //[-] Number of sub-hxs to use in hx model - double m_recomp_frac; //[-] Fraction of flow that bypasses the precooler and the main compressor at the design point - double m_bypass_frac; //[-] Fraction of flow that bypasses the HTR and passes through the Bypass HX + double m_split_frac; // [-] Fraction of flow that goes to secondary turbine (0 = no secondary turbine) + double m_des_tol; //[-] Convergence tolerance // Air cooler parameters @@ -95,7 +95,6 @@ class C_sco2_tsf_core double m_eta_mc; //[-] design-point efficiency of the main compressor; isentropic if positive, polytropic if negative double m_eta_t; //[-] design-point efficiency of the turbine; isentropic if positive, polytropic if negative double m_eta_t2; //[-] design-point efficiency of the secondary turbine; isentropic if positive, polytropic if negative - double m_eta_rc; //[-] design-point efficiency of the recompressor; isentropic if positive, polytropic if negative double m_eta_generator; //[-] Mechanical-to-electrical efficiency of generator double m_frac_fan_power; //[-] Fraction of total cycle power 'S_des_par_cycle_dep.m_W_dot_fan_des' consumed by air fan double m_eta_fan; //[-] Fan isentropic efficiency @@ -104,7 +103,6 @@ class C_sco2_tsf_core double m_elevation; //[m] Elevation (used to calculate ambient pressure) int m_N_nodes_pass; //[-] Number of nodes per pass int m_mc_comp_model_code; // Main compressor model code - int m_rc_comp_model_code; // Recompressor model code int m_N_turbine; //[rpm] Turbine rpm S_sco2_tsf_in() @@ -112,8 +110,7 @@ class C_sco2_tsf_core m_P_mc_in = m_P_mc_out = m_LTR_UA = m_LTR_min_dT = m_LTR_eff_target = m_LTR_eff_max = m_HTR_UA = m_HTR_min_dT = m_HTR_eff_target = m_HTR_eff_max = - m_recomp_frac = - m_bypass_frac = + m_split_frac = m_des_tol = m_W_dot_net_design = m_T_mc_in = @@ -121,7 +118,6 @@ class C_sco2_tsf_core m_eta_mc = m_eta_t = m_eta_t2 = - m_eta_rc = m_eta_generator = m_frac_fan_power = m_eta_fan = @@ -134,7 +130,6 @@ class C_sco2_tsf_core m_LTR_N_sub_hxrs = 0; m_HTR_N_sub_hxrs = 0; m_mc_comp_model_code = -1; - m_rc_comp_model_code = -1; m_N_turbine = -1; // Recuperator design target codes @@ -156,29 +151,23 @@ class C_sco2_tsf_core { int m_error_code; C_turbine m_t; // Turbine model + C_turbine m_t2; // Secondary Turbine model C_comp_multi_stage m_mc_ms; // Main Compressor Model - C_comp_multi_stage m_rc_ms; // Recompressor Model C_HeatExchanger m_PHX, m_PC, m_BPX; // Primary, Cooler, Bypass Heat Exchanger Models C_HX_co2_to_co2_CRM mc_LT_recup; // LTR C_HX_co2_to_co2_CRM mc_HT_recup; // HTR C_CO2_to_air_cooler mc_air_cooler; // Air Cooler std::vector m_temp, m_pres, m_enth, m_entr, m_dens; // thermodynamic states (K, kPa, kJ/kg, kJ/kg-K, kg/m3) - double m_w_t, m_w_mc, m_w_rc; // [kJ/kg] specific work of turbine, main compressor, recompressor - double m_m_dot_t, m_m_dot_mc, m_m_dot_rc; // [kg/s] sco2 Mass flow in main compressor, recompressor, turbine - double m_m_dot_bp, m_m_dot_htr_hp; // [kg/s] sco2 Mass flow through bypass, hot side HTR - double m_Q_dot_LT, m_Q_dot_HT; // [kWt] Heat Transfer in LTR, HTR - double m_W_dot_mc, m_W_dot_rc, m_W_dot_t; // [kWt] Energy consumed by main compressor, recompressor, produced by turbine + double m_w_t, m_w_t2, m_w_mc; // [kJ/kg] specific work of turbine, main compressor, recompressor + double m_m_dot_t, m_m_dot_t2, m_m_dot_mc; // [kg/s] sco2 Mass flow in turbine, secondary turbine, and main compressor (total) + double m_Q_dot_LT, m_Q_dot_HT; // [kWt] Heat Transfer in LTR, HTR + double m_W_dot_mc, m_W_dot_t, m_W_dot_t2; // [kWt] Energy consumed by main compressor, produced by turbine and secondary turbine double m_W_dot_net; // [kWt] ACTUAL produced net work in system double m_W_dot_air_cooler; // [kWe] Energy consumed by air cooler double m_Q_dot_air_cooler; // [kWt] Heat rejected by air cooler double m_Q_dot_LTR_LP, m_Q_dot_LTR_HP, m_Q_dot_HTR_LP, m_Q_dot_HTR_HP; // kWt Heat change on LTR low pressure, etc... double m_Q_dot_total; // [kWt] Total heat entering sco2 - double m_Q_dot_PHX, m_Q_dot_BP; // [kWt] Energy exchange in PHX, BPX - double m_m_dot_HTF; // [kg/s] HTF mass flow rate - double m_T_HTF_PHX_out; // [K] HTF PHX outlet temperature - double m_HTF_PHX_cold_approach; // [delta K/C] PHX cold approach temperature - double m_T_HTF_BP_outlet; // [K] HTF BPX outlet temperature - double m_HTF_BP_cold_approach; // [K] BPX cold approach temperature + double m_Q_dot_PHX; // [kWt] Energy exchange in PHX, BPX double m_eta_thermal; // Thermal Efficiency S_sco2_tsf_out() @@ -188,16 +177,14 @@ class C_sco2_tsf_core void Init() { - m_w_t = m_w_mc = m_w_rc - = m_m_dot_t = m_m_dot_mc = m_m_dot_rc - = m_m_dot_bp = m_m_dot_htr_hp + m_w_t = m_w_mc + = m_m_dot_t = m_m_dot_t2 = m_m_dot_mc = m_Q_dot_LT = m_Q_dot_HT - = m_W_dot_mc = m_W_dot_rc = m_W_dot_t + = m_W_dot_mc = m_W_dot_t = m_W_dot_t2 = m_W_dot_net = m_W_dot_air_cooler = m_Q_dot_air_cooler = m_Q_dot_LTR_LP = m_Q_dot_LTR_HP = m_Q_dot_HTR_LP = m_Q_dot_HTR_HP - = m_Q_dot_total = m_Q_dot_PHX = m_Q_dot_BP - = m_m_dot_HTF = m_T_HTF_PHX_out = m_HTF_PHX_cold_approach - = m_T_HTF_BP_outlet = m_HTF_BP_cold_approach = m_eta_thermal + = m_Q_dot_total = m_Q_dot_PHX + = m_eta_thermal = std::numeric_limits::quiet_NaN(); m_error_code = -1; @@ -213,13 +200,13 @@ class C_sco2_tsf_core private: CO2_state m_co2_props; - class C_mono_htrbp_core_HTR_des : public C_monotonic_equation + class C_mono_htrbp_core_HTR_LTR_des : public C_monotonic_equation { private: C_sco2_tsf_core* m_tsf_cycle; public: - C_mono_htrbp_core_HTR_des(C_sco2_tsf_core* tsf_cycle) + C_mono_htrbp_core_HTR_LTR_des(C_sco2_tsf_core* tsf_cycle) { m_tsf_cycle = tsf_cycle; } From e65a1aef8e760ce12543d68fb42388ca94079e2b Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:33:36 -0600 Subject: [PATCH 52/94] Complete TSF core model. --- tcs/sco2_cycle_templates.h | 4 + tcs/sco2_turbinesplitflow_cycle.cpp | 422 +++++++++++++++++++++------- tcs/sco2_turbinesplitflow_cycle.h | 23 +- 3 files changed, 333 insertions(+), 116 deletions(-) diff --git a/tcs/sco2_cycle_templates.h b/tcs/sco2_cycle_templates.h index 81b166c6aa..d0001ffc2a 100644 --- a/tcs/sco2_cycle_templates.h +++ b/tcs/sco2_cycle_templates.h @@ -69,6 +69,7 @@ class C_sco2_cycle_core double m_m_dot_rc; //[kg/s] double m_m_dot_pc; //[kg/s] double m_m_dot_t; //[kg/s] + double m_m_dot_t2; //[kg/s] double m_recomp_frac; //[-] double m_UA_LTR; //[kW/K] double m_UA_HTR; //[kW/K] @@ -76,7 +77,9 @@ class C_sco2_cycle_core double m_W_dot_rc; //[kWe] double m_W_dot_pc; //[kWe] double m_W_dot_t; //[kWe] + double m_W_dot_t2; //[kWe] double m_bypass_frac; //[-] Bypass Fraction + double m_turbine_split_frac; // [-] Turbine split fraction (TSF only) double m_W_dot_cooler_tot; //[kWe] @@ -86,6 +89,7 @@ class C_sco2_cycle_core C_comp_multi_stage::S_des_solved ms_rc_ms_des_solved; C_comp_multi_stage::S_des_solved ms_pc_ms_des_solved; C_turbine::S_design_solved ms_t_des_solved; + C_turbine::S_design_solved ms_t2_des_solved; C_HX_counterflow_CRM::S_des_solved ms_LTR_des_solved; C_HX_counterflow_CRM::S_des_solved ms_HTR_des_solved; diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp index edbeab5e6c..1d3743a4ff 100644 --- a/tcs/sco2_turbinesplitflow_cycle.cpp +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -211,150 +211,382 @@ int C_sco2_tsf_core::solve() } } - // Solve Recuperators (iterate HTR_HP_OUT) + // Solve HTR_HP_OUT Temp + double T_HTR_HP_out_calc = std::numeric_limits::quiet_NaN(); + double T_HTR_LP_out_calc = std::numeric_limits::quiet_NaN(); { - C_mono_htrbp_core_HTR_LTR_des HTR_LTR_des_eq(this); - C_monotonic_eq_solver HTR_LTR_des_solver(HTR_LTR_des_eq); + double mdot_mc_unit = 1.0; + double mdot_t_unit = mdot_mc_unit * (1.0 - m_inputs.m_split_frac); + double mdot_t2_unit = mdot_mc_unit * m_inputs.m_split_frac; - // Bounds - double T_HTR_HP_out_lower = m_outputs.m_temp[C_sco2_cycle_core::MC_OUT]; //[K] Coldest possible temp - double T_HTR_HP_out_upper = m_outputs.m_temp[C_sco2_cycle_core::TURB_IN]; //[K] Coldest possible temp (probably is TURB_OUT) + // Simulate HTR (with unit mass flow rates) + { + m_outputs.mc_HT_recup.design_for_target__calc_outlet(m_inputs.m_HTR_target_code, + m_inputs.m_HTR_UA, m_inputs.m_HTR_min_dT, m_inputs.m_HTR_eff_target, + m_inputs.m_HTR_eff_max, + m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], mdot_t2_unit, m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], + m_outputs.m_temp[C_sco2_cycle_core::TURB_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT], mdot_t_unit, m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT], + m_inputs.m_des_tol, + m_outputs.m_Q_dot_HT, T_HTR_HP_out_calc, T_HTR_LP_out_calc); + + m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT] = T_HTR_HP_out_calc; // [K] + m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT] = T_HTR_LP_out_calc; // [K] + } - // Solution Guess - double T_HTR_HP_out_guess_lower = 0.25 * (T_HTR_HP_out_upper - T_HTR_HP_out_lower) + T_HTR_HP_out_lower; // [K] - double T_HTR_HP_out_guess_upper = 0.75 * (T_HTR_HP_out_upper - T_HTR_HP_out_lower) + T_HTR_HP_out_lower; // [K] - // Optimization Settings - HTR_LTR_des_solver.settings(m_inputs.m_des_tol* m_outputs.m_temp[C_sco2_cycle_core::MC_IN], 1000, T_HTR_HP_out_lower, T_HTR_HP_out_upper, false); + } - // Optimization Output variables - double T_HTR_HP_out_solved, tol_T_HTR_HP_out_solved; - T_HTR_HP_out_solved = tol_T_HTR_HP_out_solved = std::numeric_limits::quiet_NaN(); - int iter_T_HTR_LP_out = -1; + // Simulate Secondary Turbine + { + // Determine equivalent isentropic efficiencies for secondary turbine, if necessary + double eta_t2_isen = std::numeric_limits::quiet_NaN(); + { + if (m_inputs.m_eta_t2 < 0.0) + { + int poly_error_code = 0; - // Optimize - int T_HTR_HP_out_code = HTR_LTR_des_solver.solve(T_HTR_HP_out_guess_lower, T_HTR_HP_out_guess_upper, 0, - T_HTR_HP_out_solved, tol_T_HTR_HP_out_solved, iter_T_HTR_LP_out); + isen_eta_from_poly_eta(m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT], std::abs(m_inputs.m_eta_t2), + false, poly_error_code, eta_t2_isen); - // Check if converged - if (T_HTR_HP_out_code != C_monotonic_eq_solver::CONVERGED) - { - m_outputs.m_error_code = 25; - return m_outputs.m_error_code; + if (poly_error_code != 0) + { + m_outputs.m_error_code = poly_error_code; + return m_outputs.m_error_code; + } + } + else + eta_t2_isen = m_inputs.m_eta_t2; } - // Call solve_HTR_LTR to solve cycle with correct HTR_HP_out - double test = 0; - solve_HTR_LTR(T_HTR_HP_out_solved, &test); + // Simulate Secondary Turbine + { + int turbine2_error_code = 0; - int x = 0; + calculate_turbomachinery_outlet_1(m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT], eta_t2_isen, false, + turbine2_error_code, m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_entr[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_dens[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_temp[C_sco2_cycle_core::TURB2_OUT], + m_outputs.m_enth[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_entr[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_dens[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_w_t2); + if (turbine2_error_code != 0) + { + m_outputs.m_error_code = turbine2_error_code; + return m_outputs.m_error_code; + } + } } - return -1; -} + // Calculate Mass Flow Rates + { + m_outputs.m_m_dot_mc = m_inputs.m_W_dot_net_design + / (((m_outputs.m_w_t * (1.0 - m_inputs.m_split_frac)) + + (m_outputs.m_w_t2 * m_inputs.m_split_frac) + + (m_outputs.m_w_mc)) + * m_inputs.m_eta_generator); //[kg/s] -int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_solved) -{ - return -1; -} + m_outputs.m_m_dot_t = m_outputs.m_m_dot_mc * (1.0 - m_inputs.m_split_frac); //[kg/s] + m_outputs.m_m_dot_t2 = m_outputs.m_m_dot_mc * m_inputs.m_split_frac; //[kg/s] -int C_sco2_tsf_core::solve_HTR_LTR(double T_HTR_HP_OUT_guess, double* diff_T_HTR_HP_out) -{ - // Intialize - m_outputs.m_w_t2 = m_outputs.m_m_dot_mc = m_outputs.m_m_dot_t = m_outputs.m_m_dot_t2 - = m_outputs.m_Q_dot_LT = m_outputs.m_Q_dot_HT - = std::numeric_limits::quiet_NaN(); - // Set temperature guess - m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT] = T_HTR_HP_OUT_guess; // [K] + // Back Calculate Output + double W_dot_calc = (m_outputs.m_m_dot_t * m_outputs.m_w_t) + + (m_outputs.m_m_dot_t2 * m_outputs.m_w_t2) + + (m_outputs.m_m_dot_mc * m_outputs.m_w_mc); - // Get HTR_HP_OUT co2 properties + if (std::abs(W_dot_calc - m_inputs.m_W_dot_net_design) > 0.001) + { + throw new C_csp_exception("Could not achieve target power output"); + } + } + + // Re-Solve HTR (with actual mass flow rates) + { + m_outputs.mc_HT_recup.design_for_target__calc_outlet(m_inputs.m_HTR_target_code, + m_inputs.m_HTR_UA, m_inputs.m_HTR_min_dT, m_inputs.m_HTR_eff_target, + m_inputs.m_HTR_eff_max, + m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], m_outputs.m_m_dot_t2, m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], + m_outputs.m_temp[C_sco2_cycle_core::TURB_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT], m_outputs.m_m_dot_t, m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT], + m_inputs.m_des_tol, + m_outputs.m_Q_dot_HT, T_HTR_HP_out_calc, T_HTR_LP_out_calc); + + if (T_HTR_HP_out_calc != m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT]) + { + throw new C_csp_exception("Could not converge"); + } + + if (T_HTR_LP_out_calc != m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT]) + { + throw new C_csp_exception("Could not converge"); + } + } + + // Complete HTR_HP_OUT and HTR_LP_OUT co2 properties { int prop_error_code = CO2_TP(m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], &m_co2_props); if (prop_error_code != 0) { - *diff_T_HTR_HP_out = std::numeric_limits::quiet_NaN(); - return prop_error_code; + m_outputs.m_error_code = prop_error_code; + return m_outputs.m_error_code; } m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.enth; m_outputs.m_entr[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.entr; m_outputs.m_dens[C_sco2_cycle_core::HTR_HP_OUT] = m_co2_props.dens; + + prop_error_code = CO2_TP(m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT], &m_co2_props); + if (prop_error_code != 0) + { + m_outputs.m_error_code = prop_error_code; + return m_outputs.m_error_code; + } + m_outputs.m_enth[C_sco2_cycle_core::HTR_LP_OUT] = m_co2_props.enth; + m_outputs.m_entr[C_sco2_cycle_core::HTR_LP_OUT] = m_co2_props.entr; + m_outputs.m_dens[C_sco2_cycle_core::HTR_LP_OUT] = m_co2_props.dens; } - // Determine equivalent isentropic efficiencies for secondary turbine, if necessary - double eta_t2_isen = std::numeric_limits::quiet_NaN(); + // Simulate LTR { - if (m_inputs.m_eta_t2 < 0.0) + m_outputs.mc_LT_recup.design_for_target__calc_outlet(m_inputs.m_LTR_target_code, + m_inputs.m_LTR_UA, m_inputs.m_LTR_min_dT, m_inputs.m_LTR_eff_target, + m_inputs.m_LTR_eff_max, + m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], m_outputs.m_m_dot_t, m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT], + m_outputs.m_temp[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_m_dot_t2, m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT], + m_inputs.m_des_tol, + m_outputs.m_Q_dot_LT, m_outputs.m_temp[C_sco2_cycle_core::LTR_HP_OUT], m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT]); + } + + // Complete LTR_HP_OUT and LTR_LP_OUT co2 properties + { + int prop_error_code = CO2_TP(m_outputs.m_temp[C_sco2_cycle_core::LTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT], &m_co2_props); + if (prop_error_code != 0) { - int poly_error_code = 0; + m_outputs.m_error_code = prop_error_code; + return m_outputs.m_error_code; + } + m_outputs.m_enth[C_sco2_cycle_core::LTR_HP_OUT] = m_co2_props.enth; + m_outputs.m_entr[C_sco2_cycle_core::LTR_HP_OUT] = m_co2_props.entr; + m_outputs.m_dens[C_sco2_cycle_core::LTR_HP_OUT] = m_co2_props.dens; - isen_eta_from_poly_eta(m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT], std::abs(m_inputs.m_eta_t2), - false, poly_error_code, eta_t2_isen); + prop_error_code = CO2_TP(m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT], m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT], &m_co2_props); + if (prop_error_code != 0) + { + m_outputs.m_error_code = prop_error_code; + return m_outputs.m_error_code; + } + m_outputs.m_enth[C_sco2_cycle_core::LTR_LP_OUT] = m_co2_props.enth; + m_outputs.m_entr[C_sco2_cycle_core::LTR_LP_OUT] = m_co2_props.entr; + m_outputs.m_dens[C_sco2_cycle_core::LTR_LP_OUT] = m_co2_props.dens; + } - if (poly_error_code != 0) - { - m_outputs.m_error_code = poly_error_code; - return m_outputs.m_error_code; - } + // Simulate Mixer + { + m_outputs.m_enth[C_sco2_cycle_core::MIXER_OUT] = ((1.0 - m_inputs.m_split_frac) * m_outputs.m_enth[C_sco2_cycle_core::HTR_LP_OUT]) + + (m_inputs.m_split_frac * m_outputs.m_enth[C_sco2_cycle_core::LTR_LP_OUT]); + + int prop_error_code = CO2_PH(m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT], m_outputs.m_enth[C_sco2_cycle_core::MIXER_OUT], &m_co2_props); + if (prop_error_code != 0) + { + m_outputs.m_error_code = prop_error_code; + return m_outputs.m_error_code; } - else - eta_t2_isen = m_inputs.m_eta_t2; + m_outputs.m_temp[C_sco2_cycle_core::MIXER_OUT] = m_co2_props.temp; //[K] + m_outputs.m_entr[C_sco2_cycle_core::MIXER_OUT] = m_co2_props.entr; //[kJ/kg-K] + m_outputs.m_dens[C_sco2_cycle_core::MIXER_OUT] = m_co2_props.dens; //[kg/m^3] } - - // Simulate Secondary Turbine + + // Calculate total work and heat metrics + { + // Work + m_outputs.m_W_dot_mc = m_outputs.m_w_mc * m_outputs.m_m_dot_mc; + m_outputs.m_W_dot_t = m_outputs.m_w_t * m_outputs.m_m_dot_t; + m_outputs.m_W_dot_t2 = m_outputs.m_w_t2 * m_outputs.m_m_dot_t2; + m_outputs.m_W_dot_net = m_outputs.m_W_dot_mc + m_outputs.m_W_dot_t + m_outputs.m_W_dot_t2; + + // Air Cooler (heat rejection unit) + m_outputs.m_W_dot_air_cooler = m_inputs.m_frac_fan_power * m_outputs.m_W_dot_net; + m_outputs.m_Q_dot_air_cooler = m_outputs.m_m_dot_mc * (m_outputs.m_enth[C_sco2_cycle_core::MIXER_OUT] - m_outputs.m_enth[C_sco2_cycle_core::MC_IN]); + + // Total heat entering sco2 + m_outputs.m_Q_dot_PHX = m_outputs.m_m_dot_t * (m_outputs.m_enth[C_sco2_cycle_core::TURB_IN] - m_outputs.m_enth[C_sco2_cycle_core::LTR_HP_OUT]); + m_outputs.m_Q_dot_total = m_outputs.m_Q_dot_PHX; + + // LTR + m_outputs.m_Q_dot_LTR_LP = m_outputs.m_m_dot_t2 * (m_outputs.m_enth[C_sco2_cycle_core::TURB2_OUT] - m_outputs.m_enth[C_sco2_cycle_core::LTR_LP_OUT]); + m_outputs.m_Q_dot_LTR_HP = m_outputs.m_m_dot_t * (m_outputs.m_enth[C_sco2_cycle_core::LTR_HP_OUT] - m_outputs.m_enth[C_sco2_cycle_core::MC_OUT]); + + // LTR + m_outputs.m_Q_dot_HTR_LP = m_outputs.m_m_dot_t * (m_outputs.m_enth[C_sco2_cycle_core::TURB_OUT] - m_outputs.m_enth[C_sco2_cycle_core::HTR_LP_OUT]); + m_outputs.m_Q_dot_HTR_HP = m_outputs.m_m_dot_t2 * (m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT] - m_outputs.m_enth[C_sco2_cycle_core::MC_OUT]); + + // Thermal Efficiency + m_outputs.m_eta_thermal = m_outputs.m_W_dot_net / m_outputs.m_Q_dot_total; + + // Back Calculate Heat In + double Q_in_calc = m_outputs.m_W_dot_net + m_outputs.m_Q_dot_air_cooler; + } + + // Define Heat Exchangers and Air Cooler { - int turbine2_error_code = 0; + // PHX + C_HeatExchanger::S_design_parameters PHX_des_par; + PHX_des_par.m_DP_design[0] = m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT] - m_outputs.m_pres[C_sco2_cycle_core::TURB_IN]; + PHX_des_par.m_DP_design[1] = 0.0; + PHX_des_par.m_m_dot_design[0] = m_outputs.m_m_dot_t; + PHX_des_par.m_m_dot_design[1] = 0.0; + PHX_des_par.m_Q_dot_design = m_outputs.m_m_dot_t * (m_outputs.m_enth[C_sco2_cycle_core::TURB_IN] - m_outputs.m_enth[C_sco2_cycle_core::LTR_HP_OUT]); + m_outputs.m_PHX.initialize(PHX_des_par); + + // Air Cooler + C_HeatExchanger::S_design_parameters PC_des_par; + PC_des_par.m_DP_design[0] = 0.0; + PC_des_par.m_DP_design[1] = m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT] - m_outputs.m_pres[C_sco2_cycle_core::MC_IN]; + PC_des_par.m_m_dot_design[0] = 0.0; + PC_des_par.m_m_dot_design[1] = m_outputs.m_m_dot_mc; + PC_des_par.m_Q_dot_design = m_outputs.m_m_dot_mc * (m_outputs.m_enth[C_sco2_cycle_core::MIXER_OUT] - m_outputs.m_enth[C_sco2_cycle_core::MC_IN]); + m_outputs.m_PC.initialize(PC_des_par); + } - calculate_turbomachinery_outlet_1(m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT], eta_t2_isen, false, - turbine2_error_code, m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_entr[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_dens[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_temp[C_sco2_cycle_core::TURB2_OUT], - m_outputs.m_enth[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_entr[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_dens[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_w_t2); + m_outputs.m_error_code = 0; + + return m_outputs.m_error_code; +} - if (turbine2_error_code != 0) +int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_solved) +{ + // Design Main Compressor + { + int mc_design_err = m_outputs.m_mc_ms.design_given_outlet_state(m_inputs.m_mc_comp_model_code, m_outputs.m_temp[C_sco2_cycle_core::MC_IN], + m_outputs.m_pres[C_sco2_cycle_core::MC_IN], + m_outputs.m_m_dot_mc, + m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], + m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], + m_inputs.m_des_tol); + + if (mc_design_err != 0) { - m_outputs.m_error_code = turbine2_error_code; + m_outputs.m_error_code = mc_design_err; return m_outputs.m_error_code; } } - // Calculate Mass Flow Rates + // Size Turbine { - m_outputs.m_m_dot_mc = m_inputs.m_W_dot_net_design - / (((m_outputs.m_w_t * (1.0 - m_inputs.m_split_frac)) - + (m_outputs.m_w_t2 * m_inputs.m_split_frac) - + (m_outputs.m_w_mc)) - * m_inputs.m_eta_generator); //[kg/s] + C_turbine::S_design_parameters t_des_par; + // Set turbine shaft speed + t_des_par.m_N_design = m_inputs.m_N_turbine; + t_des_par.m_N_comp_design_if_linked = m_outputs.m_mc_ms.get_design_solved()->m_N_design; //[rpm] m_mc.get_design_solved()->m_N_design; + // Turbine inlet state + t_des_par.m_P_in = m_outputs.m_pres[C_sco2_cycle_core::TURB_IN]; + t_des_par.m_T_in = m_outputs.m_temp[C_sco2_cycle_core::TURB_IN]; + t_des_par.m_D_in = m_outputs.m_dens[C_sco2_cycle_core::TURB_IN]; + t_des_par.m_h_in = m_outputs.m_enth[C_sco2_cycle_core::TURB_IN]; + t_des_par.m_s_in = m_outputs.m_entr[C_sco2_cycle_core::TURB_IN]; + // Turbine outlet state + t_des_par.m_P_out = m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT]; + t_des_par.m_h_out = m_outputs.m_enth[C_sco2_cycle_core::TURB_OUT]; + // Mass flow + t_des_par.m_m_dot = m_outputs.m_m_dot_t; + + int turb_size_error_code = 0; + m_outputs.m_t.turbine_sizing(t_des_par, turb_size_error_code); + + if (turb_size_error_code != 0) + { + m_outputs.m_error_code = turb_size_error_code; + return m_outputs.m_error_code; + } + } - m_outputs.m_m_dot_t = m_outputs.m_m_dot_mc * (1.0 - m_inputs.m_split_frac); //[kg/s] - m_outputs.m_m_dot_t2 = m_outputs.m_m_dot_mc * m_inputs.m_split_frac; //[kg/s] + // Size Secondary Turbine + { + C_turbine::S_design_parameters t2_des_par; + // Set turbine shaft speed + t2_des_par.m_N_design = m_inputs.m_N_turbine; + t2_des_par.m_N_comp_design_if_linked = m_outputs.m_mc_ms.get_design_solved()->m_N_design; //[rpm] m_mc.get_design_solved()->m_N_design; + // Turbine inlet state + t2_des_par.m_P_in = m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT]; + t2_des_par.m_T_in = m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT]; + t2_des_par.m_D_in = m_outputs.m_dens[C_sco2_cycle_core::HTR_HP_OUT]; + t2_des_par.m_h_in = m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT]; + t2_des_par.m_s_in = m_outputs.m_entr[C_sco2_cycle_core::HTR_HP_OUT]; + // Turbine outlet state + t2_des_par.m_P_out = m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT]; + t2_des_par.m_h_out = m_outputs.m_enth[C_sco2_cycle_core::TURB2_OUT]; + // Mass flow + t2_des_par.m_m_dot = m_outputs.m_m_dot_t2; + + int turb_size_error_code = 0; + m_outputs.m_t2.turbine_sizing(t2_des_par, turb_size_error_code); + + if (turb_size_error_code != 0) + { + m_outputs.m_error_code = turb_size_error_code; + return m_outputs.m_error_code; + } } - //// Simulate LTR - //{ - // m_outputs.mc_LT_recup.design_for_target__calc_outlet(m_inputs.m_LTR_target_code, - // m_inputs.m_LTR_UA, m_inputs.m_LTR_min_dT, m_inputs.m_LTR_eff_target, - // m_inputs.m_LTR_eff_max, - // m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], m_outputs.m_m_dot_t, m_outputs.m_pres[C_sco2_cycle_core::LTR_HP_OUT], - // m_outputs.m_temp[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_m_dot_t2, m_outputs.m_pres[C_sco2_cycle_core::LTR_LP_OUT], - // m_inputs.m_des_tol, - // m_outputs.m_Q_dot_LT, m_outputs.m_temp[C_sco2_cycle_core::LTR_HP_OUT], m_outputs.m_temp[C_sco2_cycle_core::LTR_LP_OUT]); - //} - - // Simulate HTR - double T_HTR_HP_out_calc = std::numeric_limits::quiet_NaN(); + // Design air cooler { - m_outputs.mc_HT_recup.design_for_target__calc_outlet(m_inputs.m_HTR_target_code, - m_inputs.m_HTR_UA, m_inputs.m_HTR_min_dT, m_inputs.m_HTR_eff_target, - m_inputs.m_HTR_eff_max, - m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], m_outputs.m_m_dot_t2, m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], - m_outputs.m_temp[C_sco2_cycle_core::TURB_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT], m_outputs.m_m_dot_t, m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT], - m_inputs.m_des_tol, - m_outputs.m_Q_dot_HT, T_HTR_HP_out_calc, m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT]); + // Structure for design parameters that are dependent on cycle design solution + C_CO2_to_air_cooler::S_des_par_cycle_dep s_air_cooler_des_par_dep; + // Set air cooler design parameters that are dependent on the cycle design solution + s_air_cooler_des_par_dep.m_T_hot_in_des = m_outputs.m_temp[C_sco2_cycle_core::MIXER_OUT]; // [K] + s_air_cooler_des_par_dep.m_P_hot_in_des = m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT]; // [kPa] + s_air_cooler_des_par_dep.m_m_dot_total = m_outputs.m_m_dot_mc; // [kg/s] + + // This pressure drop is currently uncoupled from the cycle design + double cooler_deltaP = m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT] - m_outputs.m_pres[C_sco2_cycle_core::MC_IN]; // [kPa] + if (cooler_deltaP == 0.0) + s_air_cooler_des_par_dep.m_delta_P_des = m_inputs.m_deltaP_cooler_frac * m_outputs.m_pres[C_sco2_cycle_core::MIXER_OUT]; // [kPa] + else + s_air_cooler_des_par_dep.m_delta_P_des = cooler_deltaP; // [kPa] + + s_air_cooler_des_par_dep.m_T_hot_out_des = m_outputs.m_temp[C_sco2_cycle_core::MC_IN]; // [K] + s_air_cooler_des_par_dep.m_W_dot_fan_des = m_inputs.m_frac_fan_power * m_outputs.m_W_dot_net / 1000.0; // [MWe] + // Structure for design parameters that are independent of cycle design solution + C_CO2_to_air_cooler::S_des_par_ind s_air_cooler_des_par_ind; + s_air_cooler_des_par_ind.m_T_amb_des = m_inputs.m_T_amb_des; // [K] + s_air_cooler_des_par_ind.m_elev = m_inputs.m_elevation; // [m] + s_air_cooler_des_par_ind.m_eta_fan = m_inputs.m_eta_fan; // [-] + s_air_cooler_des_par_ind.m_N_nodes_pass = m_inputs.m_N_nodes_pass; // [-] + + if (m_inputs.m_is_des_air_cooler && std::isfinite(m_inputs.m_deltaP_cooler_frac) && std::isfinite(m_inputs.m_frac_fan_power) + && std::isfinite(m_inputs.m_T_amb_des) && std::isfinite(m_inputs.m_elevation) && std::isfinite(m_inputs.m_eta_fan) && m_inputs.m_N_nodes_pass > 0) + { + m_outputs.mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, m_inputs.m_des_tol); + } } - *diff_T_HTR_HP_out = T_HTR_HP_out_calc - T_HTR_HP_OUT_guess; + // Get 'design_solved' structure from component classes + design_solved.ms_mc_ms_des_solved = *m_outputs.m_mc_ms.get_design_solved(); + design_solved.ms_t_des_solved = *m_outputs.m_t.get_design_solved(); + design_solved.ms_t2_des_solved = *m_outputs.m_t2.get_design_solved(); + design_solved.ms_LTR_des_solved = m_outputs.mc_LT_recup.ms_des_solved; + design_solved.ms_HTR_des_solved = m_outputs.mc_HT_recup.ms_des_solved; + design_solved.ms_mc_air_cooler = *m_outputs.mc_air_cooler.get_design_solved(); + + // Set solved design point metrics + design_solved.m_temp = m_outputs.m_temp; + design_solved.m_pres = m_outputs.m_pres; + design_solved.m_enth = m_outputs.m_enth; + design_solved.m_entr = m_outputs.m_entr; + design_solved.m_dens = m_outputs.m_dens; + + design_solved.m_eta_thermal = m_outputs.m_eta_thermal; + design_solved.m_W_dot_net = m_outputs.m_W_dot_net; + design_solved.m_m_dot_mc = m_outputs.m_m_dot_mc; + design_solved.m_m_dot_t = m_outputs.m_m_dot_t; + design_solved.m_m_dot_t2 = m_outputs.m_m_dot_t2; + design_solved.m_turbine_split_frac = m_inputs.m_split_frac; + + design_solved.m_UA_LTR = m_inputs.m_LTR_UA; + design_solved.m_UA_HTR = m_inputs.m_HTR_UA; + + design_solved.m_W_dot_t = m_outputs.m_W_dot_t; //[kWe] + design_solved.m_W_dot_t2 = m_outputs.m_W_dot_t2; //[kWe] + design_solved.m_W_dot_mc = m_outputs.m_W_dot_mc; //[kWe] + - return -1; + design_solved.m_W_dot_cooler_tot = m_outputs.mc_air_cooler.get_design_solved()->m_W_dot_fan * 1.E3; //[kWe] convert from MWe + + return 0; } void C_sco2_tsf_core::reset() diff --git a/tcs/sco2_turbinesplitflow_cycle.h b/tcs/sco2_turbinesplitflow_cycle.h index e4e9c1807b..6e863678a7 100644 --- a/tcs/sco2_turbinesplitflow_cycle.h +++ b/tcs/sco2_turbinesplitflow_cycle.h @@ -153,7 +153,7 @@ class C_sco2_tsf_core C_turbine m_t; // Turbine model C_turbine m_t2; // Secondary Turbine model C_comp_multi_stage m_mc_ms; // Main Compressor Model - C_HeatExchanger m_PHX, m_PC, m_BPX; // Primary, Cooler, Bypass Heat Exchanger Models + C_HeatExchanger m_PHX, m_PC; // Primary and Cooler Heat Exchanger Models C_HX_co2_to_co2_CRM mc_LT_recup; // LTR C_HX_co2_to_co2_CRM mc_HT_recup; // HTR C_CO2_to_air_cooler mc_air_cooler; // Air Cooler @@ -161,7 +161,7 @@ class C_sco2_tsf_core double m_w_t, m_w_t2, m_w_mc; // [kJ/kg] specific work of turbine, main compressor, recompressor double m_m_dot_t, m_m_dot_t2, m_m_dot_mc; // [kg/s] sco2 Mass flow in turbine, secondary turbine, and main compressor (total) double m_Q_dot_LT, m_Q_dot_HT; // [kWt] Heat Transfer in LTR, HTR - double m_W_dot_mc, m_W_dot_t, m_W_dot_t2; // [kWt] Energy consumed by main compressor, produced by turbine and secondary turbine + double m_W_dot_mc, m_W_dot_t, m_W_dot_t2; // [kWt] Energy consumed by main compressor, produced by turbine and secondary turbine double m_W_dot_net; // [kWt] ACTUAL produced net work in system double m_W_dot_air_cooler; // [kWe] Energy consumed by air cooler double m_Q_dot_air_cooler; // [kWt] Heat rejected by air cooler @@ -200,25 +200,6 @@ class C_sco2_tsf_core private: CO2_state m_co2_props; - class C_mono_htrbp_core_HTR_LTR_des : public C_monotonic_equation - { - private: - C_sco2_tsf_core* m_tsf_cycle; - - public: - C_mono_htrbp_core_HTR_LTR_des(C_sco2_tsf_core* tsf_cycle) - { - m_tsf_cycle = tsf_cycle; - } - - virtual int operator()(double T_HTR_HP_OUT_guess /*K*/, double* diff_T_HTR_HP_out /*K*/) - { - return m_tsf_cycle->solve_HTR_LTR(T_HTR_HP_OUT_guess, diff_T_HTR_HP_out); - }; - }; - - int solve_HTR_LTR(double T_HTR_HP_OUT_guess, double* diff_T_HTR_HP_out); - void initialize_solve(); public: From 3563f61b369a9ce6afb69d7f0eb620ab2ca11ec9 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Mon, 8 Apr 2024 16:04:13 -0600 Subject: [PATCH 53/94] Add tolerance to error check. --- tcs/sco2_turbinesplitflow_cycle.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp index 1d3743a4ff..d7e814be85 100644 --- a/tcs/sco2_turbinesplitflow_cycle.cpp +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -307,14 +307,16 @@ int C_sco2_tsf_core::solve() m_inputs.m_des_tol, m_outputs.m_Q_dot_HT, T_HTR_HP_out_calc, T_HTR_LP_out_calc); - if (T_HTR_HP_out_calc != m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT]) + if (std::abs(T_HTR_HP_out_calc - m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT]) > 0.1) { - throw new C_csp_exception("Could not converge"); + m_outputs.m_error_code = -1; + return m_outputs.m_error_code; } - if (T_HTR_LP_out_calc != m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT]) + if (std::abs(T_HTR_LP_out_calc - m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT]) > 0.1) { - throw new C_csp_exception("Could not converge"); + m_outputs.m_error_code = -1; + return m_outputs.m_error_code; } } From a3f5d2afcd12bc727e732ce1ce832561117308de Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Mon, 8 Apr 2024 18:06:31 -0600 Subject: [PATCH 54/94] Add optimization for design_method == 2 or 3 --- tcs/sco2_pc_csp_int.cpp | 3 + tcs/sco2_turbinesplitflow_cycle.cpp | 391 ++++++++++++++++++++++++---- tcs/sco2_turbinesplitflow_cycle.h | 13 +- 3 files changed, 356 insertions(+), 51 deletions(-) diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index 1a376ef1b1..6bc47b1472 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -397,6 +397,9 @@ void C_sco2_phx_air_cooler::design_core() int phx_cold_inlet_state = C_sco2_cycle_core::HTR_HP_OUT; if (ms_des_par.m_cycle_config == 3) phx_cold_inlet_state = C_sco2_cycle_core::MIXER2_OUT; + else if (ms_des_par.m_cycle_config == 4) + phx_cold_inlet_state = C_sco2_cycle_core::LTR_HP_OUT; + // Design the PHX diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp index d7e814be85..b93e6076cf 100644 --- a/tcs/sco2_turbinesplitflow_cycle.cpp +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -584,7 +584,8 @@ int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_ design_solved.m_W_dot_t = m_outputs.m_W_dot_t; //[kWe] design_solved.m_W_dot_t2 = m_outputs.m_W_dot_t2; //[kWe] design_solved.m_W_dot_mc = m_outputs.m_W_dot_mc; //[kWe] - + + design_solved.m_is_rc = false; design_solved.m_W_dot_cooler_tot = m_outputs.mc_air_cooler.get_design_solved()->m_W_dot_fan * 1.E3; //[kWe] convert from MWe @@ -664,7 +665,62 @@ void C_TurbineSplitFlow_Cycle::auto_opt_design_core(int& error_code) } - // Set up baseline core inputs (will go somewhere else) + C_sco2_tsf_core::S_sco2_tsf_in optimal_inputs_out; + error_code = optimize_par(ms_auto_opt_des_par, opt_par, optimal_inputs_out); + + if (error_code != 0) + return; + + // Run Optimal Case + m_optimal_tsf_core.set_inputs(optimal_inputs_out); + error_code = m_optimal_tsf_core.solve(); + + if (error_code != 0) + return; + + // Finalize Design (pass in reference to solved parameters) + error_code = m_optimal_tsf_core.finalize_design(ms_des_solved); + +} + +/// +/// Core function to optimize cycle for target eta (variable total UA) +/// +void C_TurbineSplitFlow_Cycle::auto_opt_design_hit_eta_core(int& error_code, const double eta_thermal_target) +{ + return; +} + +/// +/// Optimize Total Recuperator UA +/// totalUA -> bp -> UA split, pressure, recomp +/// +/// +/// +/// +/// +int C_TurbineSplitFlow_Cycle::optimize_totalUA(const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + C_sco2_tsf_core::S_sco2_tsf_in& optimal_inputs) +{ + return -1;; +} + +/// +/// Optimize internal variables (UA split, pressure, recomp) +/// totalUA -> bp -> UA split, pressure, recomp +/// +/// +/// +/// +/// +/// +int C_TurbineSplitFlow_Cycle::optimize_par(const S_auto_opt_design_parameters& auto_par, + const S_opt_design_parameters& opt_par, + C_sco2_tsf_core::S_sco2_tsf_in& optimal_inputs) +{ + + // Set up baseline core inputs C_sco2_tsf_core::S_sco2_tsf_in core_inputs; { // From Auto Opt Design Parameters @@ -713,14 +769,10 @@ void C_TurbineSplitFlow_Cycle::auto_opt_design_core(int& error_code) // Turbine Split Fraction if (opt_par.m_fixed_split_frac == true) core_inputs.m_split_frac = opt_par.m_split_frac_guess; - else - throw new C_csp_exception("not handled"); // MC Outlet Pressure if (opt_par.m_fixed_P_mc_out == true) core_inputs.m_P_mc_out = opt_par.m_P_mc_out_guess; - else - throw new C_csp_exception("not handled"); // Recuperator split fraction double LT_frac_local = opt_par.m_LT_frac_guess; @@ -735,19 +787,155 @@ void C_TurbineSplitFlow_Cycle::auto_opt_design_core(int& error_code) core_inputs.m_HTR_UA = ms_auto_opt_des_par.m_HTR_UA; //[kW/K] } - - // Pressure Ratio is calculated in callback } } - // Handle Pressure Ratio (temporary) + // Add applicable design variables to Optimizer + int index = 0; + + std::vector x(0); + std::vector lb(0); + std::vector ub(0); + std::vector scale(0); + + if (!auto_par.m_fixed_P_mc_out) + { + x.push_back(opt_par.m_P_mc_out_guess); + lb.push_back(100.0); + ub.push_back(m_P_high_limit); + scale.push_back(500.0); + + index++; + } + + if (!auto_par.m_fixed_PR_HP_to_LP) + { + x.push_back(opt_par.m_PR_HP_to_LP_guess); + lb.push_back(0.0001); + double PR_max = m_P_high_limit / 100.0; + ub.push_back(PR_max); + scale.push_back(0.2); + + index++; + } + + if (!opt_par.m_fixed_split_frac) + { + x.push_back(opt_par.m_split_frac_guess); + lb.push_back(0.0); + ub.push_back(0.99); + scale.push_back(0.05); + index++; + } + + if (!opt_par.m_fixed_LT_frac) + { + x.push_back(opt_par.m_LT_frac_guess); + lb.push_back(0.0); + ub.push_back(1.0); + scale.push_back(0.05); + + index++; + } + + // Make Optimizer (if there are variables to be optimized) + int error_code = 0; + C_sco2_tsf_core::S_sco2_tsf_in optimal_inputs_internal; + if (index > 0) + { + // Set up instance of nlopt class and set optimization parameters + nlopt::opt opt_des_cycle(nlopt::LN_SBPLX, index); + opt_des_cycle.set_lower_bounds(lb); + opt_des_cycle.set_upper_bounds(ub); + opt_des_cycle.set_initial_step(scale); + opt_des_cycle.set_xtol_rel(auto_par.m_des_opt_tol); + opt_des_cycle.set_maxeval(50); + + // Set up core model that will be passed to objective function + C_sco2_tsf_core tsf_core; + tsf_core.set_inputs(core_inputs); + + // Make Tuple to pass in parameters + std::tuple par_tuple = { this, &auto_par, &opt_par, &tsf_core }; + + // Set max objective function + opt_des_cycle.set_max_objective(nlopt_tsf_optimize_par_func, &par_tuple); + double max_f = std::numeric_limits::quiet_NaN(); + + // Optimize + nlopt::result result_des_cycle = opt_des_cycle.optimize(x, max_f); + + // Check if forced stop + int flag = opt_des_cycle.get_force_stop(); + if (flag == true) + { + error_code = -1; + return error_code; + } + + // Get Optimal Input Case + error_code = x_to_inputs(x, auto_par, opt_par, core_inputs); + if (error_code != 0) + return error_code; + } + // Nothing to optimize + else + { + // Define P_mc_in (because pressure ratio and mc_out are constant) + core_inputs.m_P_mc_in = core_inputs.m_P_mc_out / opt_par.m_PR_HP_to_LP_guess; + + // Simulate Case (don't actually need to run...) + C_sco2_tsf_core core_model; + core_model.set_inputs(core_inputs); + error_code = core_model.solve(); + } + + // Set Optimal Inputs + optimal_inputs = core_inputs; + + return error_code; +} + +/// +/// Take optimizer array 'x', write appropriate values to S_sco2_tsf_in +/// +int C_TurbineSplitFlow_Cycle::x_to_inputs(const std::vector& x, + const S_auto_opt_design_parameters auto_par, + const S_opt_design_parameters opt_par, + C_sco2_tsf_core::S_sco2_tsf_in& core_inputs) +{ + // 'x' is array of inputs either being adjusted by optimizer or set constant + // Finish defining core_inputs based on current 'x' values + + int error_message = 0; + int index = 0; + + // Main compressor outlet pressure + + if (!auto_par.m_fixed_P_mc_out) + { + double P_mc_out = x[index]; + if (P_mc_out > m_P_high_limit) + return -1; + index++; + + // assign P_mc_out + core_inputs.m_P_mc_out = P_mc_out; + } + + + // Main compressor pressure ratio double PR_mc_local = -999.9; double P_mc_in = -999.9; if (!opt_par.m_fixed_PR_HP_to_LP) { - throw new C_csp_exception("not handled"); + PR_mc_local = x[index]; + if (PR_mc_local > 50.0) + return -1; + index++; + P_mc_in = core_inputs.m_P_mc_out / PR_mc_local; } else { @@ -762,55 +950,127 @@ void C_TurbineSplitFlow_Cycle::auto_opt_design_core(int& error_code) } } + if (P_mc_in >= core_inputs.m_P_mc_out) + return -1; + if (P_mc_in <= 100.0) + return -1; + core_inputs.m_P_mc_in = P_mc_in; + // Turbine split fraction + if (!opt_par.m_fixed_split_frac) + { + core_inputs.m_split_frac = x[index]; + if (core_inputs.m_split_frac < 0.0) + return -1; + index++; + } - // Should have enough to run model (with all variables fixed) - C_sco2_tsf_core tsf_core; - tsf_core.set_inputs(core_inputs); - tsf_core.solve(); + // Recuperator split fraction + double LT_frac_local = -999.9; + double LTR_UA, HTR_UA; + if (!opt_par.m_fixed_LT_frac) + { + LT_frac_local = x[index]; + if (LT_frac_local > 1.0 || LT_frac_local < 0.0) + return -1; + index++; - return; -} + if (auto_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || auto_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + LTR_UA = auto_par.m_UA_rec_total * LT_frac_local; + HTR_UA = auto_par.m_UA_rec_total * (1.0 - LT_frac_local); -/// -/// Core function to optimize cycle for target eta (variable total UA) -/// -void C_TurbineSplitFlow_Cycle::auto_opt_design_hit_eta_core(int& error_code, const double eta_thermal_target) -{ - return; + // ASSIGN LTR_UA and HTR_UA + core_inputs.m_LTR_UA = LTR_UA; + core_inputs.m_HTR_UA = HTR_UA; + } + } + + return 0; } /// -/// Optimize Total Recuperator UA -/// totalUA -> bp -> UA split, pressure, recomp +/// Set optimized variables to NaN, to protect them from misuse /// -/// -/// -/// -/// -int C_TurbineSplitFlow_Cycle::optimize_totalUA(const S_auto_opt_design_parameters& auto_par, - const S_opt_design_parameters& opt_par, - C_sco2_tsf_core::S_sco2_tsf_in& optimal_inputs) +int C_TurbineSplitFlow_Cycle::clear_x_inputs(const std::vector& x, + const S_auto_opt_design_parameters auto_par, + const S_opt_design_parameters opt_par, + C_sco2_tsf_core::S_sco2_tsf_in& core_inputs) { - return -1;; + // 'x' is array of inputs either being adjusted by optimizer or set constant + // Finish defining core_inputs based on current 'x' values + + int error_message = 0; + int index = 0; + + // Main compressor outlet pressure + + if (!auto_par.m_fixed_P_mc_out) + { + core_inputs.m_P_mc_out = std::numeric_limits::quiet_NaN(); + } + + + core_inputs.m_P_mc_in = std::numeric_limits::quiet_NaN(); + + // Turbine split fraction + if (!opt_par.m_fixed_split_frac) + { + core_inputs.m_split_frac = std::numeric_limits::quiet_NaN(); + } + + // Recuperator split fraction + if (!opt_par.m_fixed_LT_frac) + { + if (auto_par.m_LTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA || auto_par.m_HTR_target_code == NS_HX_counterflow_eqs::OPTIMIZE_UA) + { + // ASSIGN LTR_UA and HTR_UA + core_inputs.m_LTR_UA = std::numeric_limits::quiet_NaN();; + core_inputs.m_HTR_UA = std::numeric_limits::quiet_NaN();; + } + } + + return 0; } /// -/// Optimize internal variables (UA split, pressure, recomp) -/// totalUA -> bp -> UA split, pressure, recomp +/// Calculate Objective Value (does not consider total UA minimization) /// -/// -/// -/// -/// -/// -int C_TurbineSplitFlow_Cycle::optimize_par(const S_auto_opt_design_parameters& auto_par, +double C_TurbineSplitFlow_Cycle::calc_objective(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, - C_sco2_tsf_core::S_sco2_tsf_in& core_inputs, - C_sco2_tsf_core::S_sco2_tsf_in& optimal_inputs) + const C_sco2_tsf_core& tsf_core) { - return -1; + double obj = 0; + double eta = tsf_core.m_outputs.m_eta_thermal; + + // Hit a target thermal efficiency + if (opt_par.m_design_method == 1) + { + double eta_error = std::min(eta - opt_par.m_eta_thermal_target, 0.0); + obj = 1.0 - std::abs(eta_error); + } + // Maximize thermal efficiency + else + { + obj = eta; + } + + // Penalize for PHX sco2 temp diff (if necessary) + double penalty = 0; + if (auto_par.m_des_objective_type == 2) + { + double phx_deltaT = tsf_core.m_outputs.m_temp[C_sco2_cycle_core::TURB_IN] - tsf_core.m_outputs.m_temp[C_sco2_cycle_core::LTR_HP_OUT]; + double under_min_deltaT = std::max(0.0, auto_par.m_min_phx_deltaT - phx_deltaT); + + double percent_err = under_min_deltaT / auto_par.m_min_phx_deltaT; + + penalty = percent_err; + } + + obj = obj - penalty; + + return obj; } // ********************************************************************************** PUBLIC Methods C_TurbineSplitFlow_Cycle (: C_sco2_cycle_core) @@ -862,16 +1122,39 @@ double C_TurbineSplitFlow_Cycle::optimize_totalUA_return_objective_metric(const } /// -/// Objective Function for NON Bypass optimization -/// Total UA -> Bypass Fraction -> pressure, split UA, recomp frac +/// Objective Function for general parameters +/// Total UA -> pressure, split UA, recomp frac /// /// ONLY Objective Value double C_TurbineSplitFlow_Cycle::optimize_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, - C_sco2_tsf_core& htrbp_core) + C_sco2_tsf_core& tsf_core) { - return 0; + // Update counter + m_opt_iteration_count++; // global + + // Modify core inputs with Variable Parameters + int error_code = x_to_inputs(x, auto_par, opt_par, tsf_core.m_inputs); + + if (error_code != 0) + return -100000; + + // At this point, have fully defined core input struct + // Run the core model + error_code = tsf_core.solve(); + + // Set Objective + double objective_metric = -10000000000.0; + if (error_code == 0) + { + objective_metric = calc_objective(auto_par, opt_par, tsf_core); + } + + // Clear optimized inputs + clear_x_inputs(x, auto_par, opt_par, tsf_core.m_inputs); + + return objective_metric; } // ********************************************************************************** Off Design Functions @@ -941,6 +1224,18 @@ double nlopt_tsf_optimize_totalUA_func(const std::vector& x, std::vector double nlopt_tsf_optimize_par_func(const std::vector& x, std::vector& grad, void* data) { - return 0; + // Unpack Data Tuple + std::tuple* data_tuple + = static_cast* > (data); + + C_TurbineSplitFlow_Cycle* frame = std::get<0>(*data_tuple); + const C_TurbineSplitFlow_Cycle::S_auto_opt_design_parameters* auto_opt_par = std::get<1>(*data_tuple); + const C_TurbineSplitFlow_Cycle::S_opt_design_parameters* opt_par = std::get<2>(*data_tuple); + C_sco2_tsf_core* tsf_core = std::get<3>(*data_tuple); + + if (frame != NULL) + return frame->optimize_par_return_objective_metric(x, *auto_opt_par, *opt_par, *tsf_core); + else + return 0.0; } diff --git a/tcs/sco2_turbinesplitflow_cycle.h b/tcs/sco2_turbinesplitflow_cycle.h index 6e863678a7..b54c4589aa 100644 --- a/tcs/sco2_turbinesplitflow_cycle.h +++ b/tcs/sco2_turbinesplitflow_cycle.h @@ -280,7 +280,7 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core // TSF specific parameters double m_eta_t2; - // Optimal htrbp core class (contains all results and component data) + // Optimal tsf core class (contains all results and component data) C_sco2_tsf_core m_optimal_tsf_core; void auto_opt_design_core(int& error_code); @@ -289,7 +289,14 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core int optimize_totalUA(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_tsf_core::S_sco2_tsf_in& optimal_inputs); - int optimize_par(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_tsf_core::S_sco2_tsf_in& core_inputs, C_sco2_tsf_core::S_sco2_tsf_in& optimal_inputs); + int optimize_par(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_tsf_core::S_sco2_tsf_in& optimal_inputs); + + int x_to_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, C_sco2_tsf_core::S_sco2_tsf_in& core_inputs); + + int clear_x_inputs(const std::vector& x, const S_auto_opt_design_parameters auto_par, const S_opt_design_parameters opt_par, C_sco2_tsf_core::S_sco2_tsf_in& core_inputs); + + double calc_objective(const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, const C_sco2_tsf_core& tsf_core); + protected: @@ -340,7 +347,7 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core // Objective Functions (internal use only) double C_TurbineSplitFlow_Cycle::optimize_totalUA_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par); - double C_TurbineSplitFlow_Cycle::optimize_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_tsf_core& htrbp_core); + double C_TurbineSplitFlow_Cycle::optimize_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_tsf_core& tsf_core); // Off Design From 70799cf4e0adc5a5870954dcf8ad748254d0db82 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Mon, 15 Apr 2024 15:26:04 -0600 Subject: [PATCH 55/94] Update plotting functions for Turbine split flow. Cmod not complete. --- ssc/csp_common.cpp | 42 ++++++- tcs/sco2_cycle_components.cpp | 215 +++++++++++++++++++++------------- tcs/sco2_cycle_components.h | 4 +- 3 files changed, 178 insertions(+), 83 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 6fd39e55d3..f6fd4259eb 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -1331,6 +1331,8 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c std::vector h_rc; //[kJ/kg] std::vector P_pc; //[MPa] std::vector h_pc; //[kJ/kg] + std::vector P_t2; //[MPa] + std::vector h_t2; //[kJ/kg] int ph_err_code = sco2_cycle_plot_data_PH(s_sco2_des_par.m_cycle_config, c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp, c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres, @@ -1341,7 +1343,9 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c P_rc, h_rc, P_pc, - h_pc); + h_pc, + P_t2, + h_t2); if (ph_err_code != 0) throw exec_error("sco2_csp_system", "cycle plot data routine failed"); @@ -1700,7 +1704,35 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c cost_equip_sum += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_equipment_cost; //[M$] cm->assign("t_cost_bare_erected", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_bare_erected_cost); //[M$] cost_bare_erected_sum += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_bare_erected_cost; - // Recuperator + + // Secondary Turbine + if (cycle_config == 4) + { + cm->assign("t2_W_dot", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_W_dot_t * 1.E-3)); //[MWe] convert from kWe + cm->assign("t_m_dot_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_t); //[kg/s] + cm->assign("T_turb_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::TURB_IN] - 273.15)); //[C] Turbine inlet temp, convert from K + cm->assign("t_P_in_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::TURB_IN] * 1.E-3)); //[MPa] Turbine inlet pressure, convert from kPa + cm->assign("t_T_out_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::TURB_OUT] - 273.15)); //[C] Turbine outlet temp, convert from K + cm->assign("t_P_out_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::TURB_OUT] * 1.E-3)); //[MPa] Turbine outlet pressure, convert from kPa + cm->assign("t_delta_h_isen_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_delta_h_isen)); //[kJ/kg] + cm->assign("t_rho_in_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_rho_in)); //[kg/m3] + cm->assign("t_nu_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_nu_design); //[-] + cm->assign("t_tip_ratio_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_w_tip_ratio); //[-] + cm->assign("t_N_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_N_design); //[rpm] + cm->assign("t_D", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_D_rotor); //[m] + cm->assign("t_cost_equipment", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_equipment_cost); //[M$] + cost_equip_sum += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_equipment_cost; //[M$] + cm->assign("t_cost_bare_erected", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_bare_erected_cost); //[M$] + cost_bare_erected_sum += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_bare_erected_cost; + } + else + { + + } + + + + // Recuperator double recup_total_UA_assigned = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_LTR_des_solved.m_UA_allocated*1.E-3; //[MW/K] convert from kW/K double recup_total_UA_calculated = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_LTR_des_solved.m_UA_calc_at_eff_max*1.E-3; //[MW/K] convert from kW/K double recup_total_cost_equip = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_equipment; //[M$] @@ -1986,6 +2018,8 @@ int sco2_helper_core(compute_module* cm) std::vector h_rc; //[kJ/kg] std::vector P_pc; //[MPa] std::vector h_pc; //[kJ/kg] + std::vector P_t2; //[MPa] + std::vector h_t2; //[kJ/kg] int ph_err_code = sco2_cycle_plot_data_PH(cycle_config, T_state_points_K, P_state_points_kPa, @@ -1996,7 +2030,9 @@ int sco2_helper_core(compute_module* cm) P_rc, h_rc, P_pc, - h_pc); + h_pc, + P_t2, + h_t2); if (ph_err_code != 0) throw exec_error("sco2_csp_system", "cycle plot data routine failed"); diff --git a/tcs/sco2_cycle_components.cpp b/tcs/sco2_cycle_components.cpp index 79978552d4..87e81e3f5c 100644 --- a/tcs/sco2_cycle_components.cpp +++ b/tcs/sco2_cycle_components.cpp @@ -326,6 +326,32 @@ int sco2_cycle_plot_data_TS(int cycle_config, int n_pres = pres.size(); int n_entr = entr.size(); + int HTR_HP_IN_ENUM = -1; + int PHX_IN_ENUM = -1; + int LTR_LP_IN_ENUM = -1; + int COOLER_IN_ENUM = -1; + if (cycle_config == 4) // Turbine Split Flow + { + HTR_HP_IN_ENUM = C_sco2_cycle_core::MC_OUT; + PHX_IN_ENUM = C_sco2_cycle_core::LTR_HP_OUT; + LTR_LP_IN_ENUM = C_sco2_cycle_core::TURB2_OUT; + COOLER_IN_ENUM = C_sco2_cycle_core::MIXER_OUT; + } + else if (cycle_config == 3) // Recompression with HTR Bypass + { + HTR_HP_IN_ENUM = C_sco2_cycle_core::MIXER_OUT; + PHX_IN_ENUM = C_sco2_cycle_core::MIXER2_OUT; + LTR_LP_IN_ENUM = C_sco2_cycle_core::HTR_LP_OUT; + COOLER_IN_ENUM = C_sco2_cycle_core::LTR_LP_OUT; + } + else + { + HTR_HP_IN_ENUM = C_sco2_cycle_core::MIXER_OUT; + PHX_IN_ENUM = C_sco2_cycle_core::HTR_HP_OUT; + LTR_LP_IN_ENUM = C_sco2_cycle_core::HTR_LP_OUT; + COOLER_IN_ENUM = C_sco2_cycle_core::LTR_LP_OUT; + } + // Get LTR HP data int err_code = Ts_data_over_linear_dP_ds(pres[C_sco2_cycle_core::MC_OUT], entr[C_sco2_cycle_core::MC_OUT], pres[C_sco2_cycle_core::LTR_HP_OUT], entr[C_sco2_cycle_core::LTR_HP_OUT], @@ -334,70 +360,72 @@ int sco2_cycle_plot_data_TS(int cycle_config, return err_code; // Get HTR HP data - err_code = Ts_data_over_linear_dP_ds(pres[C_sco2_cycle_core::MIXER_OUT], entr[C_sco2_cycle_core::MIXER_OUT], + err_code = Ts_data_over_linear_dP_ds(pres[HTR_HP_IN_ENUM], entr[HTR_HP_IN_ENUM], pres[C_sco2_cycle_core::HTR_HP_OUT], entr[C_sco2_cycle_core::HTR_HP_OUT], T_HTR_HP, s_HTR_HP, 25); if (err_code != 0) return err_code; // Get PHX data - err_code = Ts_data_over_linear_dP_ds(pres[C_sco2_cycle_core::HTR_HP_OUT], entr[C_sco2_cycle_core::HTR_HP_OUT], + err_code = Ts_data_over_linear_dP_ds(pres[PHX_IN_ENUM], entr[PHX_IN_ENUM], pres[C_sco2_cycle_core::TURB_IN], entr[C_sco2_cycle_core::TURB_IN], T_PHX, s_PHX, 25); if (err_code != 0) return err_code; - // Get HTR HP data + // Get HTR LP data err_code = Ts_data_over_linear_dP_ds(pres[C_sco2_cycle_core::TURB_OUT], entr[C_sco2_cycle_core::TURB_OUT], pres[C_sco2_cycle_core::HTR_LP_OUT], entr[C_sco2_cycle_core::HTR_LP_OUT], T_HTR_LP, s_HTR_LP, 25); if (err_code != 0) return err_code; - // Get LTR HP data - err_code = Ts_data_over_linear_dP_ds(pres[C_sco2_cycle_core::HTR_LP_OUT], entr[C_sco2_cycle_core::HTR_LP_OUT], + // Get LTR LP data + err_code = Ts_data_over_linear_dP_ds(pres[LTR_LP_IN_ENUM], entr[LTR_LP_IN_ENUM], pres[C_sco2_cycle_core::LTR_LP_OUT], entr[C_sco2_cycle_core::LTR_LP_OUT], T_LTR_LP, s_LTR_LP, 25); if (err_code != 0) return err_code; - if (cycle_config != 2) // Recompression Cycle - { - if (n_pres < C_sco2_cycle_core::RC_OUT + 1 || n_entr != n_pres) - return -1; - - // Get main cooler data - err_code = Ts_data_over_linear_dP_ds(pres[C_sco2_cycle_core::LTR_LP_OUT], entr[C_sco2_cycle_core::LTR_LP_OUT], - pres[C_sco2_cycle_core::MC_IN], entr[C_sco2_cycle_core::MC_IN], - T_main_cooler, s_main_cooler, 25); - if (err_code != 0) - return err_code; - - // Set IP data - T_pre_cooler.resize(1); - T_pre_cooler[0] = T_main_cooler[0]; - s_pre_cooler.resize(1); - s_pre_cooler[0] = s_main_cooler[0]; - } - else // Partial Cooling Cycle - { - if (n_pres < C_sco2_cycle_core::PC_OUT + 1 || n_entr != n_pres) - return -1; - - // Get pre cooler data - err_code = Ts_data_over_linear_dP_ds(pres[C_sco2_cycle_core::LTR_LP_OUT], entr[C_sco2_cycle_core::LTR_LP_OUT], - pres[C_sco2_cycle_core::PC_IN], entr[C_sco2_cycle_core::PC_IN], - T_pre_cooler, s_pre_cooler, 25); - if (err_code != 0) - return err_code; - - // Get main cooler data - err_code = Ts_data_over_linear_dP_ds(pres[C_sco2_cycle_core::PC_OUT], entr[C_sco2_cycle_core::PC_OUT], - pres[C_sco2_cycle_core::MC_IN], entr[C_sco2_cycle_core::MC_IN], - T_main_cooler, s_main_cooler, 25); - if (err_code != 0) - return err_code; - } + if (cycle_config == 1 || cycle_config == 3 || cycle_config == 4) // Recompression Cycle or Turbine split flow cycle + { + if (n_pres < C_sco2_cycle_core::RC_OUT + 1 || n_entr != n_pres) + return -1; + + // Get main cooler data + err_code = Ts_data_over_linear_dP_ds(pres[COOLER_IN_ENUM], entr[COOLER_IN_ENUM], + pres[C_sco2_cycle_core::MC_IN], entr[C_sco2_cycle_core::MC_IN], + T_main_cooler, s_main_cooler, 25); + if (err_code != 0) + return err_code; + + // Set IP data + T_pre_cooler.resize(1); + T_pre_cooler[0] = T_main_cooler[0]; + s_pre_cooler.resize(1); + s_pre_cooler[0] = s_main_cooler[0]; + } + else if (cycle_config == 2) // Partial Cooling Cycle + { + if (n_pres < C_sco2_cycle_core::PC_OUT + 1 || n_entr != n_pres) + return -1; + + // Get pre cooler data + err_code = Ts_data_over_linear_dP_ds(pres[C_sco2_cycle_core::LTR_LP_OUT], entr[C_sco2_cycle_core::LTR_LP_OUT], + pres[C_sco2_cycle_core::PC_IN], entr[C_sco2_cycle_core::PC_IN], + T_pre_cooler, s_pre_cooler, 25); + if (err_code != 0) + return err_code; + + // Get main cooler data + err_code = Ts_data_over_linear_dP_ds(pres[C_sco2_cycle_core::PC_OUT], entr[C_sco2_cycle_core::PC_OUT], + pres[C_sco2_cycle_core::MC_IN], entr[C_sco2_cycle_core::MC_IN], + T_main_cooler, s_main_cooler, 25); + if (err_code != 0) + return err_code; + } + else + return -1; // Not modeled return 0; } @@ -412,7 +440,9 @@ int sco2_cycle_plot_data_PH(int cycle_config, std::vector & P_rc /*MPa*/, std::vector & h_rc /*kJ/kg*/, std::vector & P_pc /*MPa*/, - std::vector & h_pc /*kJ/kg*/) + std::vector & h_pc /*kJ/kg*/, + std::vector & P_t2 /*MPa*/, + std::vector & h_t2 /*kJ/kg*/) { int n_pres = pres.size(); int n_temp = temp.size(); @@ -431,46 +461,73 @@ int sco2_cycle_plot_data_PH(int cycle_config, if (err_code != 0) return err_code; - if (cycle_config != 2) // Recompression Cycle - { - if (n_pres < C_sco2_cycle_core::RC_OUT + 1 || n_temp != n_pres) - return -1; - - // Recompressor - err_code = Ph_data_over_turbomachinery(temp[C_sco2_cycle_core::LTR_LP_OUT], pres[C_sco2_cycle_core::LTR_LP_OUT], - temp[C_sco2_cycle_core::RC_OUT], pres[C_sco2_cycle_core::RC_OUT], - P_rc, h_rc, 25); - - if (err_code != 0) - return err_code; - - // Precompressor - P_pc.resize(1); - P_pc[0] = P_mc[0]; - h_pc.resize(1); - h_pc[0] = h_mc[0]; - } - else // Partial Cooling Cycle - { - if (n_pres < C_sco2_cycle_core::PC_OUT + 1 || n_temp != n_pres) - return -1; + if (cycle_config == 4) // Turbine Split Flow Cycle + { + if (n_pres < C_sco2_cycle_core::TURB2_OUT + 1 || n_temp != n_pres) + return -1; + + // Secondary Turbine + int err_code = Ph_data_over_turbomachinery(temp[C_sco2_cycle_core::HTR_HP_OUT], pres[C_sco2_cycle_core::HTR_HP_OUT], + temp[C_sco2_cycle_core::TURB2_OUT], pres[C_sco2_cycle_core::TURB2_OUT], + P_t2, h_t2, 25); + + if (err_code != 0) + return err_code; + + // Recompressor + P_rc.resize(1); + P_rc[0] = P_mc[0]; + h_rc.resize(1); + h_rc[0] = h_mc[0]; + + // Precompressor + P_pc.resize(1); + P_pc[0] = P_mc[0]; + h_pc.resize(1); + h_pc[0] = h_mc[0]; + } + else if (cycle_config == 1 || cycle_config == 3) // Recompression w/o and w/ HTR Bypass + { + if (n_pres < C_sco2_cycle_core::RC_OUT + 1 || n_temp != n_pres) + return -1; + + // Recompressor + err_code = Ph_data_over_turbomachinery(temp[C_sco2_cycle_core::LTR_LP_OUT], pres[C_sco2_cycle_core::LTR_LP_OUT], + temp[C_sco2_cycle_core::RC_OUT], pres[C_sco2_cycle_core::RC_OUT], + P_rc, h_rc, 25); + + if (err_code != 0) + return err_code; + + // Precompressor + P_pc.resize(1); + P_pc[0] = P_mc[0]; + h_pc.resize(1); + h_pc[0] = h_mc[0]; + } + else if (cycle_config == 2) // Partial Cooling Cycle + { + if (n_pres < C_sco2_cycle_core::PC_OUT + 1 || n_temp != n_pres) + return -1; - // Recompressor - err_code = Ph_data_over_turbomachinery(temp[C_sco2_cycle_core::PC_OUT], pres[C_sco2_cycle_core::PC_OUT], - temp[C_sco2_cycle_core::RC_OUT], pres[C_sco2_cycle_core::RC_OUT], - P_rc, h_rc, 25); + // Recompressor + err_code = Ph_data_over_turbomachinery(temp[C_sco2_cycle_core::PC_OUT], pres[C_sco2_cycle_core::PC_OUT], + temp[C_sco2_cycle_core::RC_OUT], pres[C_sco2_cycle_core::RC_OUT], + P_rc, h_rc, 25); - if (err_code != 0) - return err_code; + if (err_code != 0) + return err_code; - // Precompressor - err_code = Ph_data_over_turbomachinery(temp[C_sco2_cycle_core::PC_IN], pres[C_sco2_cycle_core::PC_IN], - temp[C_sco2_cycle_core::PC_OUT], pres[C_sco2_cycle_core::PC_OUT], - P_pc, h_pc, 25); + // Precompressor + err_code = Ph_data_over_turbomachinery(temp[C_sco2_cycle_core::PC_IN], pres[C_sco2_cycle_core::PC_IN], + temp[C_sco2_cycle_core::PC_OUT], pres[C_sco2_cycle_core::PC_OUT], + P_pc, h_pc, 25); - if (err_code != 0) - return err_code; - } + if (err_code != 0) + return err_code; + } + else // Not modeled + return -1; return 0; } diff --git a/tcs/sco2_cycle_components.h b/tcs/sco2_cycle_components.h index 42a700a292..5ca7df20c4 100644 --- a/tcs/sco2_cycle_components.h +++ b/tcs/sco2_cycle_components.h @@ -56,7 +56,9 @@ int sco2_cycle_plot_data_PH(int cycle_config, std::vector & P_rc /*MPa*/, std::vector & h_rc /*kJ/kg*/, std::vector & P_pc /*MPa*/, - std::vector & h_pc /*kJ/kg*/); + std::vector & h_pc /*kJ/kg*/, + std::vector & P_t2 /*MPa*/, + std::vector & h_t2 /*kJ/kg*/); int Ts_arrays_over_constP(double T_cold /*C*/, double T_hot /*C*/, std::vector P_consts /*kPa*/, std::vector> & T_data /*C*/, std::vector> & s_data); From cda42dd2ab921842c81cccc0139189d1a663315e Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Tue, 16 Apr 2024 13:05:50 -0600 Subject: [PATCH 56/94] Complete cmod for TSF. --- ssc/csp_common.cpp | 116 +++++++++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 46 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index f6fd4259eb..595a496e6a 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -900,23 +900,38 @@ var_info vtab_sco2_design[] = { { SSC_OUTPUT, SSC_NUMBER, "pc_cost_equipment", "Precompressor cost equipment", "M$", "Precompressor", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "pc_cost_bare_erected", "Precompressor cost equipment plus install", "M$", "Precompressor", "", "*", "", "" }, // Compressor Totals - { SSC_OUTPUT, SSC_NUMBER, "c_tot_cost_equip", "Compressor total cost", "M$", "Compressor Totals", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "c_tot_W_dot", "Compressor total summed power", "MWe", "Compressor Totals", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "c_tot_cost_equip", "Compressor total cost", "M$", "Compressor Totals", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "c_tot_W_dot", "Compressor total summed power", "MWe", "Compressor Totals", "", "*", "", "" }, // Turbine - { SSC_OUTPUT, SSC_NUMBER, "t_W_dot", "Turbine power", "MWe", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_m_dot_des", "Turbine mass flow rate", "kg/s", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_turb_in", "Turbine inlet temperature", "C", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_P_in_des", "Turbine design inlet pressure", "MPa", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_T_out_des", "Turbine outlet temperature", "C", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_P_out_des", "Turbine design outlet pressure", "MPa", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_delta_h_isen_des", "Turbine isentropic specific work", "kJ/kg", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_rho_in_des", "Turbine inlet density", "kg/m3", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_nu_des", "Turbine design velocity ratio", "", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_tip_ratio_des", "Turbine design tip speed ratio", "", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_N_des", "Turbine design shaft speed", "rpm", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_D", "Turbine diameter", "m", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_cost_equipment", "Tubine cost - equipment", "M$", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_cost_bare_erected", "Tubine cost - equipment plus install", "M$", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_W_dot", "Turbine power", "MWe", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_m_dot_des", "Turbine mass flow rate", "kg/s", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_turb_in", "Turbine inlet temperature", "C", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_P_in_des", "Turbine design inlet pressure", "MPa", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_T_out_des", "Turbine outlet temperature", "C", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_P_out_des", "Turbine design outlet pressure", "MPa", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_delta_h_isen_des", "Turbine isentropic specific work", "kJ/kg", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_rho_in_des", "Turbine inlet density", "kg/m3", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_nu_des", "Turbine design velocity ratio", "", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_tip_ratio_des", "Turbine design tip speed ratio", "", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_N_des", "Turbine design shaft speed", "rpm", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_D", "Turbine diameter", "m", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_cost_equipment", "Tubine cost - equipment", "M$", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_cost_bare_erected", "Tubine cost - equipment plus install", "M$", "Turbine", "", "*", "", "" }, + // Secondary Turbine (TSF cycle only) + { SSC_OUTPUT, SSC_NUMBER, "t2_W_dot", "Secondary Turbine power", "MWe", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_m_dot_des", "Secondary Turbine mass flow rate", "kg/s", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_turb2_in", "Secondary Turbine inlet temperature", "C", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_P_in_des", "Secondary Turbine design inlet pressure", "MPa", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_T_out_des", "Secondary Turbine outlet temperature", "C", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_P_out_des", "Secondary Turbine design outlet pressure", "MPa", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_delta_h_isen_des", "Secondary Turbine isentropic specific work", "kJ/kg", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_rho_in_des", "Secondary Turbine inlet density", "kg/m3", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_nu_des", "Secondary Turbine design velocity ratio", "", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_tip_ratio_des", "Secondary Turbine design tip speed ratio", "", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_N_des", "Secondary Turbine design shaft speed", "rpm", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_D", "Secondary Turbine diameter", "m", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_cost_equipment", "Secondary Tubine cost - equipment", "M$", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_cost_bare_erected", "Secondary Tubine cost - equipment plus install", "M$", "Turbine 2", "", "cycle_config=4", "", "" }, // Recuperators { SSC_OUTPUT, SSC_NUMBER, "recup_total_UA_assigned", "Total recuperator UA assigned to design routine", "MW/K", "Recuperators", "", "*", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "recup_total_UA_calculated", "Total recuperator UA calculated considering max eff and/or min temp diff parameter", "MW/K", "Recuperators", "", "*", "", "" }, @@ -1508,7 +1523,7 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c } else { - cm->assign("T_htf_cold_des", (ssc_number_t)(T_htf_cold_calc - 273.15)); //[C] convert from K Final HTF Temp (PHX outlet for recompression and partial) + cm->assign("T_htf_cold_des", (ssc_number_t)(T_htf_cold_calc - 273.15)); //[C] convert from K Final HTF Temp (PHX outlet) } // Compressor @@ -1708,31 +1723,29 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c // Secondary Turbine if (cycle_config == 4) { - cm->assign("t2_W_dot", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_W_dot_t * 1.E-3)); //[MWe] convert from kWe - cm->assign("t_m_dot_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_t); //[kg/s] - cm->assign("T_turb_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::TURB_IN] - 273.15)); //[C] Turbine inlet temp, convert from K - cm->assign("t_P_in_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::TURB_IN] * 1.E-3)); //[MPa] Turbine inlet pressure, convert from kPa - cm->assign("t_T_out_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::TURB_OUT] - 273.15)); //[C] Turbine outlet temp, convert from K - cm->assign("t_P_out_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::TURB_OUT] * 1.E-3)); //[MPa] Turbine outlet pressure, convert from kPa - cm->assign("t_delta_h_isen_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_delta_h_isen)); //[kJ/kg] - cm->assign("t_rho_in_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_rho_in)); //[kg/m3] - cm->assign("t_nu_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_nu_design); //[-] - cm->assign("t_tip_ratio_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_w_tip_ratio); //[-] - cm->assign("t_N_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_N_design); //[rpm] - cm->assign("t_D", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_D_rotor); //[m] - cm->assign("t_cost_equipment", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_equipment_cost); //[M$] - cost_equip_sum += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_equipment_cost; //[M$] - cm->assign("t_cost_bare_erected", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_bare_erected_cost); //[M$] - cost_bare_erected_sum += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t_des_solved.m_bare_erected_cost; - } - else - { - + cm->assign("t2_W_dot", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_W_dot_t2 * 1.E-3)); //[MWe] convert from kWe + cm->assign("t2_m_dot_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_t2); //[kg/s] + cm->assign("T_turb2_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::HTR_HP_OUT] - 273.15)); //[C] Turbine 2 inlet temp, convert from K + cm->assign("t2_P_in_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::HTR_HP_OUT] * 1.E-3)); //[MPa] Turbine 2 inlet pressure, convert from kPa + cm->assign("t2_T_out_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::TURB2_OUT] - 273.15)); //[C] Turbine 2 outlet temp, convert from K + cm->assign("t2_P_out_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::TURB2_OUT] * 1.E-3)); //[MPa] Turbine 2 outlet pressure, convert from kPa + cm->assign("t2_delta_h_isen_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t2_des_solved.m_delta_h_isen)); //[kJ/kg] + cm->assign("t2_rho_in_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t2_des_solved.m_rho_in)); //[kg/m3] + cm->assign("t2_nu_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t2_des_solved.m_nu_design); //[-] + cm->assign("t2_tip_ratio_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t2_des_solved.m_w_tip_ratio); //[-] + cm->assign("t2_N_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t2_des_solved.m_N_design); //[rpm] + cm->assign("t2_D", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t2_des_solved.m_D_rotor); //[m] + cm->assign("t2_cost_equipment", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t2_des_solved.m_equipment_cost); //[M$] + cost_equip_sum += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t2_des_solved.m_equipment_cost; //[M$] + cm->assign("t2_cost_bare_erected", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t2_des_solved.m_bare_erected_cost); //[M$] + cost_bare_erected_sum += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_t2_des_solved.m_bare_erected_cost; } // Recuperator + int LTR_LP_IN_enum = cycle_config == 4 ? C_sco2_cycle_core::TURB2_OUT : C_sco2_cycle_core::HTR_LP_OUT; // Define LTR LP inlet state point + double recup_total_UA_assigned = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_LTR_des_solved.m_UA_allocated*1.E-3; //[MW/K] convert from kW/K double recup_total_UA_calculated = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_LTR_des_solved.m_UA_calc_at_eff_max*1.E-3; //[MW/K] convert from kW/K double recup_total_cost_equip = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_equipment; //[M$] @@ -1745,7 +1758,7 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c cm->assign("NTU_LTR", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_LTR_des_solved.m_NTU_design); //[-] cm->assign("q_dot_LTR", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_LTR_des_solved.m_Q_dot_design*1.E-3)); //[MWt] convert from kWt double LTR_LP_deltaP_frac = 1.0 - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::LTR_LP_OUT] / - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::HTR_LP_OUT]; //[-] Fractional pressure drop through LP side of LTR + c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[LTR_LP_IN_enum]; //[-] Fractional pressure drop through LP side of LTR cm->assign("LTR_LP_deltaP_des", (ssc_number_t)LTR_LP_deltaP_frac); //[-] double LTR_HP_deltaP_frac = 1.0 - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::LTR_HP_OUT] / c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::MC_OUT]; //[-] Fractional pressure drop through HP side of LTR @@ -1756,12 +1769,14 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c cost_equip_sum += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_equipment; //[M$] cost_bare_erected_sum += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_bare_erected; //[M$] // High-temp - if (is_rc || s_sco2_des_par.m_cycle_config == 3) // Cycle may still have HTR if it is htr bypass cycle + if (is_rc || cycle_config == 3 || cycle_config == 4) // Cycle may still have HTR if it is htr bypass cycle { + int HTR_HP_IN_enum = cycle_config == 4 ? C_sco2_cycle_core::MC_OUT : C_sco2_cycle_core::MIXER_OUT; + recup_total_UA_assigned += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_HTR_des_solved.m_UA_allocated*1.E-3; //[MW/K] convert from kW/K recup_total_UA_calculated += c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_HTR_des_solved.m_UA_calc_at_eff_max*1.E-3; //[MW/K] convert from kW/K cm->assign("HTR_LP_T_out_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::HTR_LP_OUT] - 273.15)); //[C] HTR LP stream outlet temp, convert from K - cm->assign("HTR_HP_T_in_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::MIXER_OUT] - 273.15)); //[C] HTR HP stream inlet temp, convert from K + cm->assign("HTR_HP_T_in_des", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[HTR_HP_IN_enum] - 273.15)); //[C] HTR HP stream inlet temp, convert from K cm->assign("HTR_UA_assigned", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_HTR_des_solved.m_UA_allocated*1.E-3)); //[MW/K] convert from kW/K cm->assign("HTR_UA_calculated", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_HTR_des_solved.m_UA_calc_at_eff_max*1.E-3)); //[MW/K] convert from kW/K cm->assign("eff_HTR", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_HTR_des_solved.m_eff_design); //[-] @@ -1780,7 +1795,7 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::TURB_OUT]; //[-] Fractional pressure drop through LP side of HTR cm->assign("HTR_LP_deltaP_des", (ssc_number_t)HTR_LP_deltaP_frac); //[-] double HTR_HP_deltaP_frac = 1.0 - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::HTR_HP_OUT] / - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::LTR_HP_OUT]; //[-] Fractional pressure drop through HP side of HTR + c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[HTR_HP_IN_enum]; //[-] Fractional pressure drop through HP side of HTR cm->assign("HTR_HP_deltaP_des", (ssc_number_t)HTR_HP_deltaP_frac); //[-] } else @@ -1811,19 +1826,26 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c double mdot_t = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_t; htr_hp_m_dot = mdot_t * (1.0 - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_bypass_frac); } + else if (cycle_config == 4) + { + htr_hp_m_dot = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_t2; //[kg/s] + } + cm->assign("HTR_HP_m_dot", (ssc_number_t)htr_hp_m_dot); // PHX + int PHX_IN_enum = cycle_config == 4 ? C_sco2_cycle_core::LTR_HP_OUT : C_sco2_cycle_core::HTR_HP_OUT; + cm->assign("UA_PHX", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_UA_design*1.E-3)); //[MW/K] convert from kW/K cm->assign("eff_PHX", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_eff_design); //[-] cm->assign("NTU_PHX", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_NTU_design); //[-] - cm->assign("T_co2_PHX_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[C_sco2_cycle_core::HTR_HP_OUT] - 273.15)); //[C] - cm->assign("P_co2_PHX_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::HTR_HP_OUT] * 1.E-3)); //[MPa] convert from kPa + cm->assign("T_co2_PHX_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_temp[PHX_IN_enum] - 273.15)); //[C] + cm->assign("P_co2_PHX_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[PHX_IN_enum] * 1.E-3)); //[MPa] convert from kPa cm->assign("deltaT_HTF_PHX", (ssc_number_t)s_sco2_des_par.m_T_htf_hot_in - T_htf_cold_calc); //[K] cm->assign("q_dot_PHX", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_Q_dot_design*1.E-3)); //[MWt] convert from kWt cm->assign("PHX_min_dT", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_min_DT_design)); //[C/K] double PHX_deltaP_frac = 1.0 - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::TURB_IN] / - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::HTR_HP_OUT]; //[-] Fractional pressure drop through co2 side of PHX + c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[PHX_IN_enum]; //[-] Fractional pressure drop through co2 side of PHX cm->assign("PHX_co2_deltaP_des", (ssc_number_t)PHX_deltaP_frac); cm->assign("PHX_cost_equipment", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_cost_equipment); //[M$] cm->assign("PHX_cost_bare_erected", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_phx_des_solved.m_cost_bare_erected); //[M$] @@ -1853,14 +1875,16 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c } // Low Pressure Cooler + int MC_COOLER_IN_enum = cycle_config == 4 ? C_sco2_cycle_core::MIXER_OUT : C_sco2_cycle_core::LTR_LP_OUT; + cm->assign("mc_cooler_T_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_air_cooler.m_T_in_co2 - 273.15)); //[C] cm->assign("mc_cooler_P_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_air_cooler.m_P_in_co2 / 1.E3)); //[MPa] - cm->assign("mc_cooler_rho_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_dens[C_sco2_cycle_core::LTR_LP_OUT])); //[kg/m3] + cm->assign("mc_cooler_rho_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_dens[MC_COOLER_IN_enum])); //[kg/m3] cm->assign("mc_cooler_m_dot_co2", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_air_cooler.m_m_dot_co2); //[kg/s] cm->assign("mc_cooler_UA", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_air_cooler.m_UA_total*1.E-6)); //[MW/K] convert from W/K cm->assign("mc_cooler_q_dot", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_air_cooler.m_q_dot*1.E-6)); //[MWt] convert from W double LP_cooler_deltaP_frac = 1.0 - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::MC_IN] / - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::LTR_LP_OUT]; //[-] Fractional pressure drop through co2 side of PHX + c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[MC_COOLER_IN_enum]; //[-] Fractional pressure drop through co2 side of PHX cm->assign("mc_cooler_co2_deltaP_des", (ssc_number_t)LP_cooler_deltaP_frac); cm->assign("mc_cooler_W_dot_fan", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_air_cooler.m_W_dot_fan)); //[MWe] cm->assign("mc_cooler_cost_equipment", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_air_cooler.m_cost_equipment); //[M$] From c7bf8528d49d76835d22a555508f757fb39cba84 Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Wed, 17 Apr 2024 09:37:11 -0600 Subject: [PATCH 57/94] Add missing t2 PH data --- ssc/csp_common.cpp | 67 +++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 595a496e6a..fc4197fd2e 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -1044,6 +1044,9 @@ var_info vtab_sco2_design[] = { { SSC_OUTPUT, SSC_ARRAY, "h_rc_data", "Enthalpy points along re compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, { SSC_OUTPUT, SSC_ARRAY, "P_pc_data", "Pressure points along pre compression", "MPa", "P-h plot data", "", "*", "", "" }, { SSC_OUTPUT, SSC_ARRAY, "h_pc_data", "Enthalpy points along pre compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_t2_data", "Pressure points along secondary turbine expansion", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_t2_data", "Enthalpy points along secondary turbine expansion", "kJ/kg", "P-h plot data", "", "*", "", "" }, + var_info_invalid }; @@ -1401,6 +1404,15 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c p_h_pc_data[i] = (ssc_number_t)(h_pc[i]); //[kJ/kg] } + n_v = P_t2.size(); + ssc_number_t* p_P_t2_data = cm->allocate("P_t2_data", n_v); + ssc_number_t* p_h_t2_data = cm->allocate("h_t2_data", n_v); + for (size_t i = 0; i < n_v; i++) + { + p_P_t2_data[i] = (ssc_number_t)(P_t2[i]); //[MPa] + p_h_t2_data[i] = (ssc_number_t)(h_t2[i]); //[kJ/kg] + } + // Get data for T-s cycle plot std::vector T_LTR_HP; //[C] std::vector s_LTR_HP; //[kJ/kg-K] @@ -1990,29 +2002,31 @@ var_info vtab_sco2_helper[] = { SSC_INPUT, SSC_ARRAY, "s_state_points", "Entropy state point array", "kJ/kg-K", "", "", "", "", "" }, // T-s plot data - { SSC_OUTPUT, SSC_ARRAY, "T_LTR_HP_data", "Temperature points along LTR HP stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_LTR_HP_data", "Entropy points along LTR HP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_HTR_HP_data", "Temperature points along HTR HP stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_HTR_HP_data", "Entropy points along HTR HP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_PHX_data", "Temperature points along PHX stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_PHX_data", "Entropy points along PHX stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_HTR_LP_data", "Temperature points along HTR LP stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_HTR_LP_data", "Entropy points along HTR LP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_LTR_LP_data", "Temperature points along LTR LP stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_LTR_LP_data", "Entropy points along LTR LP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_main_cooler_data", "Temperature points along main cooler stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_main_cooler_data", "Entropy points along main cooler stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_pre_cooler_data", "Temperature points along pre cooler stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_pre_cooler_data", "Entropy points along pre cooler stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_LTR_HP_data", "Temperature points along LTR HP stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_LTR_HP_data", "Entropy points along LTR HP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_HTR_HP_data", "Temperature points along HTR HP stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_HTR_HP_data", "Entropy points along HTR HP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_PHX_data", "Temperature points along PHX stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_PHX_data", "Entropy points along PHX stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_HTR_LP_data", "Temperature points along HTR LP stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_HTR_LP_data", "Entropy points along HTR LP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_LTR_LP_data", "Temperature points along LTR LP stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_LTR_LP_data", "Entropy points along LTR LP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_main_cooler_data", "Temperature points along main cooler stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_main_cooler_data", "Entropy points along main cooler stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_pre_cooler_data", "Temperature points along pre cooler stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_pre_cooler_data", "Entropy points along pre cooler stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, // P-h plot data - { SSC_OUTPUT, SSC_ARRAY, "P_t_data", "Pressure points along turbine expansion", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_t_data", "Enthalpy points along turbine expansion", "kJ/kg", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_mc_data", "Pressure points along main compression", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_mc_data", "Enthalpy points along main compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_rc_data", "Pressure points along re compression", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_rc_data", "Enthalpy points along re compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_pc_data", "Pressure points along pre compression", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_pc_data", "Enthalpy points along pre compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_t_data", "Pressure points along turbine expansion", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_t_data", "Enthalpy points along turbine expansion", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_mc_data", "Pressure points along main compression", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_mc_data", "Enthalpy points along main compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_rc_data", "Pressure points along re compression", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_rc_data", "Enthalpy points along re compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_pc_data", "Pressure points along pre compression", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_pc_data", "Enthalpy points along pre compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_t2_data", "Pressure points along secondary turbine expansion", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_t2_data", "Enthalpy points along secondary turbine expansion", "kJ/kg", "P-h plot data", "", "*", "", "" }, @@ -2097,6 +2111,15 @@ int sco2_helper_core(compute_module* cm) p_h_pc_data[i] = (ssc_number_t)(h_pc[i]); //[kJ/kg] } + n_v = P_t2.size(); + ssc_number_t* p_P_t2_data = cm->allocate("P_t2_data", n_v); + ssc_number_t* p_h_t2_data = cm->allocate("h_t2_data", n_v); + for (size_t i = 0; i < n_v; i++) + { + p_P_t2_data[i] = (ssc_number_t)(P_t2[i]); //[MPa] + p_h_t2_data[i] = (ssc_number_t)(h_t2[i]); //[kJ/kg] + } + // Get data for T-s cycle plot std::vector T_LTR_HP; //[C] std::vector s_LTR_HP; //[kJ/kg-K] From 5f1814222c733434e2e3d0b88726c0f7bd8bd85f Mon Sep 17 00:00:00 2001 From: Taylor Brown Date: Thu, 18 Apr 2024 12:06:09 -0600 Subject: [PATCH 58/94] Add monotonic solver for HTR. Fix Solve_HTR --- tcs/sco2_turbinesplitflow_cycle.cpp | 191 ++++++++++++++-------------- tcs/sco2_turbinesplitflow_cycle.h | 19 +++ 2 files changed, 113 insertions(+), 97 deletions(-) diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp index b93e6076cf..ef2c215d93 100644 --- a/tcs/sco2_turbinesplitflow_cycle.cpp +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -211,113 +211,42 @@ int C_sco2_tsf_core::solve() } } - // Solve HTR_HP_OUT Temp - double T_HTR_HP_out_calc = std::numeric_limits::quiet_NaN(); - double T_HTR_LP_out_calc = std::numeric_limits::quiet_NaN(); + // Solve HTR_HP_OUT Temp (iteratively) { - double mdot_mc_unit = 1.0; - double mdot_t_unit = mdot_mc_unit * (1.0 - m_inputs.m_split_frac); - double mdot_t2_unit = mdot_mc_unit * m_inputs.m_split_frac; + // Make monotonic solver + C_mono_tsf_core_HTR_des HTR_des_eq(this); + C_monotonic_eq_solver HTR_des_solver(HTR_des_eq); - // Simulate HTR (with unit mass flow rates) - { - m_outputs.mc_HT_recup.design_for_target__calc_outlet(m_inputs.m_HTR_target_code, - m_inputs.m_HTR_UA, m_inputs.m_HTR_min_dT, m_inputs.m_HTR_eff_target, - m_inputs.m_HTR_eff_max, - m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], mdot_t2_unit, m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], - m_outputs.m_temp[C_sco2_cycle_core::TURB_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT], mdot_t_unit, m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT], - m_inputs.m_des_tol, - m_outputs.m_Q_dot_HT, T_HTR_HP_out_calc, T_HTR_LP_out_calc); - - m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT] = T_HTR_HP_out_calc; // [K] - m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT] = T_HTR_LP_out_calc; // [K] - } + // Bounds + double T_HTR_HP_out_lower = m_outputs.m_temp[C_sco2_cycle_core::MC_OUT]; //[K] Coldest possible temp + double T_HTR_HP_out_upper = m_outputs.m_temp[C_sco2_cycle_core::TURB_IN]; //[K] Coldest possible temp (probably is TURB_OUT) + // Solution Guess + double T_HTR_HP_out_guess_lower = 0.25 * (T_HTR_HP_out_upper - T_HTR_HP_out_lower) + T_HTR_HP_out_lower; // [K] + double T_HTR_HP_out_guess_upper = 0.75 * (T_HTR_HP_out_upper - T_HTR_HP_out_lower) + T_HTR_HP_out_lower; // [K] - } - - // Simulate Secondary Turbine - { - // Determine equivalent isentropic efficiencies for secondary turbine, if necessary - double eta_t2_isen = std::numeric_limits::quiet_NaN(); - { - if (m_inputs.m_eta_t2 < 0.0) - { - int poly_error_code = 0; + // Optimization Settings + HTR_des_solver.settings(m_inputs.m_des_tol* m_outputs.m_temp[C_sco2_cycle_core::MC_IN], 1000, T_HTR_HP_out_lower, T_HTR_HP_out_upper, false); - isen_eta_from_poly_eta(m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT], std::abs(m_inputs.m_eta_t2), - false, poly_error_code, eta_t2_isen); - - if (poly_error_code != 0) - { - m_outputs.m_error_code = poly_error_code; - return m_outputs.m_error_code; - } - } - else - eta_t2_isen = m_inputs.m_eta_t2; - } - - // Simulate Secondary Turbine - { - int turbine2_error_code = 0; - - calculate_turbomachinery_outlet_1(m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT], eta_t2_isen, false, - turbine2_error_code, m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_entr[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_dens[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_temp[C_sco2_cycle_core::TURB2_OUT], - m_outputs.m_enth[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_entr[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_dens[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_w_t2); - - if (turbine2_error_code != 0) - { - m_outputs.m_error_code = turbine2_error_code; - return m_outputs.m_error_code; - } - } - } - - // Calculate Mass Flow Rates - { - m_outputs.m_m_dot_mc = m_inputs.m_W_dot_net_design - / (((m_outputs.m_w_t * (1.0 - m_inputs.m_split_frac)) - + (m_outputs.m_w_t2 * m_inputs.m_split_frac) - + (m_outputs.m_w_mc)) - * m_inputs.m_eta_generator); //[kg/s] - - m_outputs.m_m_dot_t = m_outputs.m_m_dot_mc * (1.0 - m_inputs.m_split_frac); //[kg/s] - m_outputs.m_m_dot_t2 = m_outputs.m_m_dot_mc * m_inputs.m_split_frac; //[kg/s] - - - // Back Calculate Output - double W_dot_calc = (m_outputs.m_m_dot_t * m_outputs.m_w_t) - + (m_outputs.m_m_dot_t2 * m_outputs.m_w_t2) - + (m_outputs.m_m_dot_mc * m_outputs.m_w_mc); - - if (std::abs(W_dot_calc - m_inputs.m_W_dot_net_design) > 0.001) - { - throw new C_csp_exception("Could not achieve target power output"); - } - } - - // Re-Solve HTR (with actual mass flow rates) - { - m_outputs.mc_HT_recup.design_for_target__calc_outlet(m_inputs.m_HTR_target_code, - m_inputs.m_HTR_UA, m_inputs.m_HTR_min_dT, m_inputs.m_HTR_eff_target, - m_inputs.m_HTR_eff_max, - m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], m_outputs.m_m_dot_t2, m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], - m_outputs.m_temp[C_sco2_cycle_core::TURB_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT], m_outputs.m_m_dot_t, m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT], - m_inputs.m_des_tol, - m_outputs.m_Q_dot_HT, T_HTR_HP_out_calc, T_HTR_LP_out_calc); + // Optimization Output variables + double tol_T_HTR_HP_out_solved; + double T_HTR_HP_out_solved = tol_T_HTR_HP_out_solved = std::numeric_limits::quiet_NaN(); + int iter_T_HTR_LP_out = -1; - if (std::abs(T_HTR_HP_out_calc - m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT]) > 0.1) - { - m_outputs.m_error_code = -1; - return m_outputs.m_error_code; - } + // Optimize + int T_HTR_HP_out_code = HTR_des_solver.solve(T_HTR_HP_out_guess_lower, T_HTR_HP_out_guess_upper, 0, + T_HTR_HP_out_solved, tol_T_HTR_HP_out_solved, iter_T_HTR_LP_out); - if (std::abs(T_HTR_LP_out_calc - m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT]) > 0.1) + // Check if converged + if (T_HTR_HP_out_code != C_monotonic_eq_solver::CONVERGED) { - m_outputs.m_error_code = -1; + m_outputs.m_error_code = 25; return m_outputs.m_error_code; } + + // Run Calculated HTR HP Out (to set correct temps) + double dummy; + solve_HTR(T_HTR_HP_out_solved, &dummy); } // Complete HTR_HP_OUT and HTR_LP_OUT co2 properties @@ -592,6 +521,74 @@ int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_ return 0; } +int C_sco2_tsf_core::solve_HTR(double T_HTR_HP_OUT_guess, double* diff_T_HTR_HP_out) +{ + // Set HTR_HP_OUT temp + m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT] = T_HTR_HP_OUT_guess; + + // Simulate Secondary Turbine + { + // Determine equivalent isentropic efficiencies for secondary turbine, if necessary + double eta_t2_isen = std::numeric_limits::quiet_NaN(); + { + if (m_inputs.m_eta_t2 < 0.0) + { + int poly_error_code = 0; + + isen_eta_from_poly_eta(m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT], std::abs(m_inputs.m_eta_t2), + false, poly_error_code, eta_t2_isen); + + if (poly_error_code != 0) + { + m_outputs.m_error_code = poly_error_code; + return m_outputs.m_error_code; + } + } + else + eta_t2_isen = m_inputs.m_eta_t2; + } + + // Simulate Secondary Turbine + { + int turbine2_error_code = 0; + + calculate_turbomachinery_outlet_1(m_outputs.m_temp[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB2_OUT], eta_t2_isen, false, + turbine2_error_code, m_outputs.m_enth[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_entr[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_dens[C_sco2_cycle_core::HTR_HP_OUT], m_outputs.m_temp[C_sco2_cycle_core::TURB2_OUT], + m_outputs.m_enth[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_entr[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_dens[C_sco2_cycle_core::TURB2_OUT], m_outputs.m_w_t2); + + if (turbine2_error_code != 0) + { + m_outputs.m_error_code = turbine2_error_code; + return m_outputs.m_error_code; + } + } + } + + // Calculate Mass Flow Rates + m_outputs.m_m_dot_mc = m_inputs.m_W_dot_net_design + / (((m_outputs.m_w_t * (1.0 - m_inputs.m_split_frac)) + + (m_outputs.m_w_t2 * m_inputs.m_split_frac) + + (m_outputs.m_w_mc)) + * m_inputs.m_eta_generator); //[kg/s] + + m_outputs.m_m_dot_t = m_outputs.m_m_dot_mc * (1.0 - m_inputs.m_split_frac); //[kg/s] + m_outputs.m_m_dot_t2 = m_outputs.m_m_dot_mc * m_inputs.m_split_frac; //[kg/s] + + // Solve HTR + double T_HTR_HP_out_calc = std::numeric_limits::quiet_NaN(); + m_outputs.mc_HT_recup.design_for_target__calc_outlet(m_inputs.m_HTR_target_code, + m_inputs.m_HTR_UA, m_inputs.m_HTR_min_dT, m_inputs.m_HTR_eff_target, + m_inputs.m_HTR_eff_max, + m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], m_outputs.m_m_dot_t2, m_outputs.m_pres[C_sco2_cycle_core::HTR_HP_OUT], + m_outputs.m_temp[C_sco2_cycle_core::TURB_OUT], m_outputs.m_pres[C_sco2_cycle_core::TURB_OUT], m_outputs.m_m_dot_t, m_outputs.m_pres[C_sco2_cycle_core::HTR_LP_OUT], + m_inputs.m_des_tol, + m_outputs.m_Q_dot_HT, T_HTR_HP_out_calc, m_outputs.m_temp[C_sco2_cycle_core::HTR_LP_OUT]); + + *diff_T_HTR_HP_out = T_HTR_HP_OUT_guess - T_HTR_HP_out_calc; + + return 0; +} + void C_sco2_tsf_core::reset() { this->m_inputs = S_sco2_tsf_in(); diff --git a/tcs/sco2_turbinesplitflow_cycle.h b/tcs/sco2_turbinesplitflow_cycle.h index b54c4589aa..609942b227 100644 --- a/tcs/sco2_turbinesplitflow_cycle.h +++ b/tcs/sco2_turbinesplitflow_cycle.h @@ -200,6 +200,25 @@ class C_sco2_tsf_core private: CO2_state m_co2_props; + class C_mono_tsf_core_HTR_des : public C_monotonic_equation + { + private: + C_sco2_tsf_core* m_tsf_cycle; + + public: + C_mono_tsf_core_HTR_des(C_sco2_tsf_core* tsf_cycle) + { + m_tsf_cycle = tsf_cycle; + } + + virtual int operator()(double T_HTR_HP_OUT_guess /*K*/, double* diff_T_HTR_HP_out /*K*/) + { + return m_tsf_cycle->solve_HTR(T_HTR_HP_OUT_guess, diff_T_HTR_HP_out); + }; + }; + + int solve_HTR(double T_HTR_HP_OUT_guess, double* diff_T_HTR_HP_out); + void initialize_solve(); public: From 046cbe88e9e6b710ef8d3dbf56e5393d2182d00b Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:13:34 -0600 Subject: [PATCH 59/94] Add error code to cmod. Allows cycle to fail and pass error out. --- ssc/csp_common.cpp | 429 +++++++++++++++------------- tcs/sco2_cycle_templates.h | 43 +++ tcs/sco2_htrbypass_cycle.cpp | 11 +- tcs/sco2_pc_csp_int.cpp | 19 +- tcs/sco2_pc_csp_int.h | 4 +- tcs/sco2_turbinesplitflow_cycle.cpp | 13 +- 6 files changed, 302 insertions(+), 217 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index fc4197fd2e..8a55d21c3b 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -829,223 +829,228 @@ var_info vtab_sco2_design[] = { //{ SSC_OUTPUT, SSC_STRING, "debug_string", "output string used for debug", "C", "", "System Design", "cycle_config=3", "", "" }, // ** Design OUTPUTS ** + { SSC_OUTPUT, SSC_NUMBER, "cycle_success", "", "", "", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "error_int", "", "", "", "", "*", "", "" }, + { SSC_OUTPUT, SSC_STRING, "error_msg", "", "", "", "", "error_int>0", "", "" }, + + // System Design Solution - { SSC_OUTPUT, SSC_NUMBER, "T_htf_cold_des", "HTF design cold temperature (HTF outlet)", "C", "System Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_htf_phx_out_des", "HTF design phx cold temperature (PHX outlet)", "C", "System Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "m_dot_htf_des", "HTF mass flow rate", "kg/s", "System Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "eta_thermal_calc", "Calculated cycle thermal efficiency", "-", "System Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "m_dot_co2_full", "CO2 mass flow rate through HTR, PHX, turbine", "kg/s", "System Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "recomp_frac", "Recompression fraction", "-", "System Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "bypass_frac", "Bypass fraction", "-", "System Design Solution", "", "cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "cycle_cost", "Cycle cost bare erected", "M$", "System Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "cycle_spec_cost", "Cycle specific cost bare erected", "$/kWe", "System Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "cycle_spec_cost_thermal", "Cycle specific (thermal) cost bare erected", "$/kWt", "System Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "W_dot_net_less_cooling", "System power output subtracting cooling parastics", "MWe," "System Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "eta_thermal_net_less_cooling_des","Calculated cycle thermal efficiency using W_dot_net_less_cooling", "-", "System Design Solution","", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_htf_bp_out_des", "HTF design htr bypass cold temperature (BPX outlet)", "C", "System Design Solution", "", "cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "dT_htf_des", "HTF temperature difference", "C", "System Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "q_dot_in_total", "Total heat from HTF into cycle", "MW", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_htf_cold_des", "HTF design cold temperature (HTF outlet)", "C", "System Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_htf_phx_out_des", "HTF design phx cold temperature (PHX outlet)", "C", "System Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "m_dot_htf_des", "HTF mass flow rate", "kg/s", "System Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "eta_thermal_calc", "Calculated cycle thermal efficiency", "-", "System Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "m_dot_co2_full", "CO2 mass flow rate through HTR, PHX, turbine", "kg/s", "System Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "recomp_frac", "Recompression fraction", "-", "System Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "bypass_frac", "Bypass fraction", "-", "System Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cycle_cost", "Cycle cost bare erected", "M$", "System Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cycle_spec_cost", "Cycle specific cost bare erected", "$/kWe", "System Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cycle_spec_cost_thermal", "Cycle specific (thermal) cost bare erected", "$/kWt", "System Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "W_dot_net_less_cooling", "System power output subtracting cooling parastics", "MWe," "System Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "eta_thermal_net_less_cooling_des","Calculated cycle thermal efficiency using W_dot_net_less_cooling", "-", "System Design Solution","", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_htf_bp_out_des", "HTF design htr bypass cold temperature (BPX outlet)", "C", "System Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "dT_htf_des", "HTF temperature difference", "C", "System Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "q_dot_in_total", "Total heat from HTF into cycle", "MW", "System Design Solution", "", "error_int=0", "", "" }, // Compressor - { SSC_OUTPUT, SSC_NUMBER, "T_comp_in", "Compressor inlet temperature", "C", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "P_comp_in", "Compressor inlet pressure", "MPa", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "P_comp_out", "Compressor outlet pressure", "MPa", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_T_out", "Compressor outlet temperature", "C", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_W_dot", "Compressor power", "MWe", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_m_dot_des", "Compressor mass flow rate", "kg/s", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_rho_in", "Compressor inlet density", "kg/m3", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_ideal_spec_work", "Compressor ideal spec work", "kJ/kg", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_phi_des", "Compressor design flow coefficient", "", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_psi_des", "Compressor design ideal head coefficient", "", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mc_tip_ratio_des", "Compressor design stage tip speed ratio", "", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_n_stages", "Compressor stages", "", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_N_des", "Compressor design shaft speed", "rpm", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mc_D", "Compressor stage diameters", "m", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_phi_surge", "Compressor flow coefficient where surge occurs", "", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_psi_max_at_N_des", "Compressor max ideal head coefficient at design shaft speed", "", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mc_eta_stages_des", "Compressor design stage isentropic efficiencies", "", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cost_equipment", "Compressor cost equipment", "M$", "Compressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cost_bare_erected", "Compressor cost equipment plus install", "M$", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_comp_in", "Compressor inlet temperature", "C", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "P_comp_in", "Compressor inlet pressure", "MPa", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "P_comp_out", "Compressor outlet pressure", "MPa", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_T_out", "Compressor outlet temperature", "C", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_W_dot", "Compressor power", "MWe", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_m_dot_des", "Compressor mass flow rate", "kg/s", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_rho_in", "Compressor inlet density", "kg/m3", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_ideal_spec_work", "Compressor ideal spec work", "kJ/kg", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_phi_des", "Compressor design flow coefficient", "", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_psi_des", "Compressor design ideal head coefficient", "", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "mc_tip_ratio_des", "Compressor design stage tip speed ratio", "", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_n_stages", "Compressor stages", "", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_N_des", "Compressor design shaft speed", "rpm", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "mc_D", "Compressor stage diameters", "m", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_phi_surge", "Compressor flow coefficient where surge occurs", "", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_psi_max_at_N_des", "Compressor max ideal head coefficient at design shaft speed", "", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "mc_eta_stages_des", "Compressor design stage isentropic efficiencies", "", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cost_equipment", "Compressor cost equipment", "M$", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cost_bare_erected", "Compressor cost equipment plus install", "M$", "Compressor", "", "error_int=0", "", "" }, // Recompressor - { SSC_OUTPUT, SSC_NUMBER, "rc_T_in_des", "Recompressor inlet temperature", "C", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_P_in_des", "Recompressor inlet pressure", "MPa", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_T_out_des", "Recompressor inlet temperature", "C", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_P_out_des", "Recompressor inlet pressure", "MPa", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_W_dot", "Recompressor power", "MWe", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_m_dot_des", "Recompressor mass flow rate", "kg/s", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_phi_des", "Recompressor design flow coefficient", "", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_psi_des", "Recompressor design ideal head coefficient", "", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "rc_tip_ratio_des", "Recompressor design stage tip speed ratio", "", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_n_stages", "Recompressor stages", "", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_N_des", "Recompressor design shaft speed", "rpm", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "rc_D", "Recompressor stage diameters", "m", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_phi_surge", "Recompressor flow coefficient where surge occurs", "", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_psi_max_at_N_des", "Recompressor max ideal head coefficient at design shaft speed", "", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "rc_eta_stages_des", "Recompressor design stage isenstropic efficiencies", "", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_cost_equipment", "Recompressor cost equipment", "M$", "Recompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_cost_bare_erected", "Recompressor cost equipment plus install", "M$", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_T_in_des", "Recompressor inlet temperature", "C", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_P_in_des", "Recompressor inlet pressure", "MPa", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_T_out_des", "Recompressor inlet temperature", "C", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_P_out_des", "Recompressor inlet pressure", "MPa", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_W_dot", "Recompressor power", "MWe", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_m_dot_des", "Recompressor mass flow rate", "kg/s", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_phi_des", "Recompressor design flow coefficient", "", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_psi_des", "Recompressor design ideal head coefficient", "", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "rc_tip_ratio_des", "Recompressor design stage tip speed ratio", "", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_n_stages", "Recompressor stages", "", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_N_des", "Recompressor design shaft speed", "rpm", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "rc_D", "Recompressor stage diameters", "m", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_phi_surge", "Recompressor flow coefficient where surge occurs", "", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_psi_max_at_N_des", "Recompressor max ideal head coefficient at design shaft speed", "", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "rc_eta_stages_des", "Recompressor design stage isenstropic efficiencies", "", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_cost_equipment", "Recompressor cost equipment", "M$", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_cost_bare_erected", "Recompressor cost equipment plus install", "M$", "Recompressor", "", "error_int=0", "", "" }, // Precompressor - { SSC_OUTPUT, SSC_NUMBER, "pc_T_in_des", "Precompressor inlet temperature", "C", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_P_in_des", "Precompressor inlet pressure", "MPa", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_W_dot", "Precompressor power", "MWe", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_m_dot_des", "Precompressor mass flow rate", "kg/s", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_rho_in_des", "Precompressor inlet density", "kg/m3", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_ideal_spec_work_des", "Precompressor ideal spec work", "kJ/kg", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_phi_des", "Precompressor design flow coefficient", "", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "pc_tip_ratio_des", "Precompressor design stage tip speed ratio", "", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_n_stages", "Precompressor stages", "", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_N_des", "Precompressor design shaft speed", "rpm", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "pc_D", "Precompressor stage diameters", "m", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_phi_surge", "Precompressor flow coefficient where surge occurs", "", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "pc_eta_stages_des", "Precompressor design stage isenstropic efficiencies", "", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cost_equipment", "Precompressor cost equipment", "M$", "Precompressor", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cost_bare_erected", "Precompressor cost equipment plus install", "M$", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_T_in_des", "Precompressor inlet temperature", "C", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_P_in_des", "Precompressor inlet pressure", "MPa", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_W_dot", "Precompressor power", "MWe", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_m_dot_des", "Precompressor mass flow rate", "kg/s", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_rho_in_des", "Precompressor inlet density", "kg/m3", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_ideal_spec_work_des", "Precompressor ideal spec work", "kJ/kg", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_phi_des", "Precompressor design flow coefficient", "", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "pc_tip_ratio_des", "Precompressor design stage tip speed ratio", "", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_n_stages", "Precompressor stages", "", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_N_des", "Precompressor design shaft speed", "rpm", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "pc_D", "Precompressor stage diameters", "m", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_phi_surge", "Precompressor flow coefficient where surge occurs", "", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "pc_eta_stages_des", "Precompressor design stage isenstropic efficiencies", "", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cost_equipment", "Precompressor cost equipment", "M$", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cost_bare_erected", "Precompressor cost equipment plus install", "M$", "Precompressor", "", "error_int=0", "", "" }, // Compressor Totals - { SSC_OUTPUT, SSC_NUMBER, "c_tot_cost_equip", "Compressor total cost", "M$", "Compressor Totals", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "c_tot_W_dot", "Compressor total summed power", "MWe", "Compressor Totals", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "c_tot_cost_equip", "Compressor total cost", "M$", "Compressor Totals", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "c_tot_W_dot", "Compressor total summed power", "MWe", "Compressor Totals", "", "error_int=0", "", "" }, // Turbine - { SSC_OUTPUT, SSC_NUMBER, "t_W_dot", "Turbine power", "MWe", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_m_dot_des", "Turbine mass flow rate", "kg/s", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_turb_in", "Turbine inlet temperature", "C", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_P_in_des", "Turbine design inlet pressure", "MPa", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_T_out_des", "Turbine outlet temperature", "C", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_P_out_des", "Turbine design outlet pressure", "MPa", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_delta_h_isen_des", "Turbine isentropic specific work", "kJ/kg", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_rho_in_des", "Turbine inlet density", "kg/m3", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_nu_des", "Turbine design velocity ratio", "", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_tip_ratio_des", "Turbine design tip speed ratio", "", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_N_des", "Turbine design shaft speed", "rpm", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_D", "Turbine diameter", "m", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_cost_equipment", "Tubine cost - equipment", "M$", "Turbine", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_cost_bare_erected", "Tubine cost - equipment plus install", "M$", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_W_dot", "Turbine power", "MWe", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_m_dot_des", "Turbine mass flow rate", "kg/s", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_turb_in", "Turbine inlet temperature", "C", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_P_in_des", "Turbine design inlet pressure", "MPa", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_T_out_des", "Turbine outlet temperature", "C", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_P_out_des", "Turbine design outlet pressure", "MPa", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_delta_h_isen_des", "Turbine isentropic specific work", "kJ/kg", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_rho_in_des", "Turbine inlet density", "kg/m3", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_nu_des", "Turbine design velocity ratio", "", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_tip_ratio_des", "Turbine design tip speed ratio", "", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_N_des", "Turbine design shaft speed", "rpm", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_D", "Turbine diameter", "m", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_cost_equipment", "Tubine cost - equipment", "M$", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_cost_bare_erected", "Tubine cost - equipment plus install", "M$", "Turbine", "", "error_int=0", "", "" }, // Secondary Turbine (TSF cycle only) - { SSC_OUTPUT, SSC_NUMBER, "t2_W_dot", "Secondary Turbine power", "MWe", "Turbine 2", "", "cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_m_dot_des", "Secondary Turbine mass flow rate", "kg/s", "Turbine 2", "", "cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_turb2_in", "Secondary Turbine inlet temperature", "C", "Turbine 2", "", "cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_P_in_des", "Secondary Turbine design inlet pressure", "MPa", "Turbine 2", "", "cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_T_out_des", "Secondary Turbine outlet temperature", "C", "Turbine 2", "", "cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_P_out_des", "Secondary Turbine design outlet pressure", "MPa", "Turbine 2", "", "cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_delta_h_isen_des", "Secondary Turbine isentropic specific work", "kJ/kg", "Turbine 2", "", "cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_rho_in_des", "Secondary Turbine inlet density", "kg/m3", "Turbine 2", "", "cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_nu_des", "Secondary Turbine design velocity ratio", "", "Turbine 2", "", "cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_tip_ratio_des", "Secondary Turbine design tip speed ratio", "", "Turbine 2", "", "cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_N_des", "Secondary Turbine design shaft speed", "rpm", "Turbine 2", "", "cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_D", "Secondary Turbine diameter", "m", "Turbine 2", "", "cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_cost_equipment", "Secondary Tubine cost - equipment", "M$", "Turbine 2", "", "cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_cost_bare_erected", "Secondary Tubine cost - equipment plus install", "M$", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_W_dot", "Secondary Turbine power", "MWe", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_m_dot_des", "Secondary Turbine mass flow rate", "kg/s", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_turb2_in", "Secondary Turbine inlet temperature", "C", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_P_in_des", "Secondary Turbine design inlet pressure", "MPa", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_T_out_des", "Secondary Turbine outlet temperature", "C", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_P_out_des", "Secondary Turbine design outlet pressure", "MPa", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_delta_h_isen_des", "Secondary Turbine isentropic specific work", "kJ/kg", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_rho_in_des", "Secondary Turbine inlet density", "kg/m3", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_nu_des", "Secondary Turbine design velocity ratio", "", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_tip_ratio_des", "Secondary Turbine design tip speed ratio", "", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_N_des", "Secondary Turbine design shaft speed", "rpm", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_D", "Secondary Turbine diameter", "m", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_cost_equipment", "Secondary Tubine cost - equipment", "M$", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_cost_bare_erected", "Secondary Tubine cost - equipment plus install", "M$", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, // Recuperators - { SSC_OUTPUT, SSC_NUMBER, "recup_total_UA_assigned", "Total recuperator UA assigned to design routine", "MW/K", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "recup_total_UA_calculated", "Total recuperator UA calculated considering max eff and/or min temp diff parameter", "MW/K", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "recup_total_cost_equipment","Total recuperator cost equipment", "M$", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "recup_total_cost_bare_erected","Total recuperator cost bare erected", "M$", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "recup_LTR_UA_frac", "Fraction of total conductance to LTR", "", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_HP_T_out_des", "Low temp recuperator HP outlet temperature", "C", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_UA_assigned", "Low temp recuperator UA assigned from total", "MW/K", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_UA_calculated", "Low temp recuperator UA calculated considering max eff and/or min temp diff parameter", "MW/K", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "eff_LTR", "Low temp recuperator effectiveness", "", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "NTU_LTR", "Low temp recuperator NTU", "", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "q_dot_LTR", "Low temp recuperator heat transfer", "MWt", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_LP_deltaP_des", "Low temp recuperator low pressure design pressure drop", "-", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_HP_deltaP_des", "Low temp recuperator high pressure design pressure drop","-", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_min_dT", "Low temp recuperator min temperature difference", "C", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_cost_equipment", "Low temp recuperator cost equipment", "M$", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_cost_bare_erected","Low temp recuperator cost equipment and install", "M$", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_LP_T_out_des", "High temp recuperator LP outlet temperature", "C", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_HP_T_in_des", "High temp recuperator HP inlet temperature", "C", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_UA_assigned", "High temp recuperator UA assigned from total", "MW/K", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_UA_calculated", "High temp recuperator UA calculated considering max eff and/or min temp diff parameter", "MW/K", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "eff_HTR", "High temp recuperator effectiveness", "", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "NTU_HTR", "High temp recuperator NTRU", "", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "q_dot_HTR", "High temp recuperator heat transfer", "MWt", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_LP_deltaP_des", "High temp recuperator low pressure design pressure drop","-", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_HP_deltaP_des", "High temp recuperator high pressure design pressure drop","-", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_min_dT", "High temp recuperator min temperature difference", "C", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_cost_equipment", "High temp recuperator cost equipment", "M$", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_cost_bare_erected","High temp recuperator cost equipment and install", "M$", "Recuperators", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_HP_m_dot", "High temp recuperator high pressure mass flow rate", "kg/s", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "recup_total_UA_assigned", "Total recuperator UA assigned to design routine", "MW/K", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "recup_total_UA_calculated", "Total recuperator UA calculated considering max eff and/or min temp diff parameter", "MW/K", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "recup_total_cost_equipment","Total recuperator cost equipment", "M$", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "recup_total_cost_bare_erected","Total recuperator cost bare erected", "M$", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "recup_LTR_UA_frac", "Fraction of total conductance to LTR", "", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_HP_T_out_des", "Low temp recuperator HP outlet temperature", "C", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_UA_assigned", "Low temp recuperator UA assigned from total", "MW/K", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_UA_calculated", "Low temp recuperator UA calculated considering max eff and/or min temp diff parameter", "MW/K", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "eff_LTR", "Low temp recuperator effectiveness", "", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "NTU_LTR", "Low temp recuperator NTU", "", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "q_dot_LTR", "Low temp recuperator heat transfer", "MWt", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_LP_deltaP_des", "Low temp recuperator low pressure design pressure drop", "-", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_HP_deltaP_des", "Low temp recuperator high pressure design pressure drop","-", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_min_dT", "Low temp recuperator min temperature difference", "C", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_cost_equipment", "Low temp recuperator cost equipment", "M$", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_cost_bare_erected","Low temp recuperator cost equipment and install", "M$", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_LP_T_out_des", "High temp recuperator LP outlet temperature", "C", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_HP_T_in_des", "High temp recuperator HP inlet temperature", "C", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_UA_assigned", "High temp recuperator UA assigned from total", "MW/K", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_UA_calculated", "High temp recuperator UA calculated considering max eff and/or min temp diff parameter", "MW/K", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "eff_HTR", "High temp recuperator effectiveness", "", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "NTU_HTR", "High temp recuperator NTRU", "", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "q_dot_HTR", "High temp recuperator heat transfer", "MWt", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_LP_deltaP_des", "High temp recuperator low pressure design pressure drop","-", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_HP_deltaP_des", "High temp recuperator high pressure design pressure drop","-", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_min_dT", "High temp recuperator min temperature difference", "C", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_cost_equipment", "High temp recuperator cost equipment", "M$", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_cost_bare_erected","High temp recuperator cost equipment and install", "M$", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_HP_m_dot", "High temp recuperator high pressure mass flow rate", "kg/s", "Recuperators", "", "error_int=0", "", "" }, // PHX Design Solution - { SSC_OUTPUT, SSC_NUMBER, "UA_PHX", "PHX Conductance", "MW/K", "PHX Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "eff_PHX", "PHX effectiveness", "", "PHX Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "NTU_PHX", "PHX NTU", "", "PHX Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_co2_PHX_in", "CO2 temperature at PHX inlet", "C", "PHX Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "P_co2_PHX_in", "CO2 pressure at PHX inlet", "MPa", "PHX Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "deltaT_HTF_PHX", "HTF temp difference across PHX", "C", "PHX Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "q_dot_PHX", "PHX heat transfer", "MWt", "PHX Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "PHX_co2_deltaP_des", "PHX co2 side design pressure drop", "-", "PHX Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "PHX_cost_equipment", "PHX cost equipment", "M$", "PHX Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "PHX_cost_bare_erected","PHX cost equipment and install", "M$", "PHX Design Solution", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "PHX_min_dT", "PHX min temperature difference", "C", "PHX Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "UA_PHX", "PHX Conductance", "MW/K", "PHX Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "eff_PHX", "PHX effectiveness", "", "PHX Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "NTU_PHX", "PHX NTU", "", "PHX Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_co2_PHX_in", "CO2 temperature at PHX inlet", "C", "PHX Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "P_co2_PHX_in", "CO2 pressure at PHX inlet", "MPa", "PHX Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "deltaT_HTF_PHX", "HTF temp difference across PHX", "C", "PHX Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "q_dot_PHX", "PHX heat transfer", "MWt", "PHX Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "PHX_co2_deltaP_des", "PHX co2 side design pressure drop", "-", "PHX Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "PHX_cost_equipment", "PHX cost equipment", "M$", "PHX Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "PHX_cost_bare_erected","PHX cost equipment and install", "M$", "PHX Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "PHX_min_dT", "PHX min temperature difference", "C", "PHX Design Solution", "", "error_int=0", "", "" }, // BPX Design Solution - { SSC_OUTPUT, SSC_NUMBER, "UA_BPX", "BPX Conductance", "MW/K", "BPX Design Solution", "", "cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "eff_BPX", "BPX effectiveness", "", "BPX Design Solution", "", "cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "NTU_BPX", "BPX NTU", "", "BPX Design Solution", "", "cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_co2_BPX_in", "CO2 temperature at BPX inlet", "C", "BPX Design Solution", "", "cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "P_co2_BPX_in", "CO2 pressure at BPX inlet", "MPa", "BPX Design Solution", "", "cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "deltaT_HTF_BPX", "HTF temp difference across BPX", "C", "BPX Design Solution", "", "cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "q_dot_BPX", "BPX heat transfer", "MWt", "BPX Design Solution", "", "cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "BPX_co2_deltaP_des", "BPX co2 side design pressure drop", "-", "BPX Design Solution", "", "cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "BPX_cost_equipment", "BPX cost equipment", "M$", "BPX Design Solution", "", "cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "BPX_cost_bare_erected","BPX cost equipment and install", "M$", "BPX Design Solution", "", "cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "BPX_min_dT", "BPX min temperature difference", "C", "BPX Design Solution", "", "cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "BPX_m_dot", "BPX sco2 mass flow rate", "kg/s", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "UA_BPX", "BPX Conductance", "MW/K", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "eff_BPX", "BPX effectiveness", "", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "NTU_BPX", "BPX NTU", "", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_co2_BPX_in", "CO2 temperature at BPX inlet", "C", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "P_co2_BPX_in", "CO2 pressure at BPX inlet", "MPa", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "deltaT_HTF_BPX", "HTF temp difference across BPX", "C", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "q_dot_BPX", "BPX heat transfer", "MWt", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_co2_deltaP_des", "BPX co2 side design pressure drop", "-", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_cost_equipment", "BPX cost equipment", "M$", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_cost_bare_erected","BPX cost equipment and install", "M$", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_min_dT", "BPX min temperature difference", "C", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_m_dot", "BPX sco2 mass flow rate", "kg/s", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, // main compressor cooler - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_T_in", "Low pressure cross flow cooler inlet temperature", "C", "Low Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_P_in", "Low pressure cross flow cooler inlet pressure", "MPa", "Low Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_rho_in", "Low pressure cross flow cooler inlet density", "kg/m3", "Low Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_in_isen_deltah_to_P_mc_out", "Low pressure cross flow cooler inlet isen enthalpy rise to mc outlet pressure", "kJ/kg", "Low Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_m_dot_co2", "Low pressure cross flow cooler CO2 mass flow rate", "kg/s", "Low Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_UA", "Low pressure cross flow cooler conductance", "MW/K", "Low Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_q_dot", "Low pressure cooler heat transfer", "MWt", "Low Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_co2_deltaP_des","Low pressure cooler co2 side design pressure drop", "-", "Low Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_W_dot_fan", "Low pressure cooler fan power", "MWe", "Low Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_cost_equipment","Low pressure cooler cost equipment", "M$", "Low Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_cost_bare_erected","Low pressure cooler cost equipment and install", "M$", "Low Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_T_in", "Low pressure cross flow cooler inlet temperature", "C", "Low Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_P_in", "Low pressure cross flow cooler inlet pressure", "MPa", "Low Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_rho_in", "Low pressure cross flow cooler inlet density", "kg/m3", "Low Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_in_isen_deltah_to_P_mc_out", "Low pressure cross flow cooler inlet isen enthalpy rise to mc outlet pressure", "kJ/kg", "Low Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_m_dot_co2", "Low pressure cross flow cooler CO2 mass flow rate", "kg/s", "Low Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_UA", "Low pressure cross flow cooler conductance", "MW/K", "Low Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_q_dot", "Low pressure cooler heat transfer", "MWt", "Low Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_co2_deltaP_des","Low pressure cooler co2 side design pressure drop", "-", "Low Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_W_dot_fan", "Low pressure cooler fan power", "MWe", "Low Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_cost_equipment","Low pressure cooler cost equipment", "M$", "Low Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_cost_bare_erected","Low pressure cooler cost equipment and install", "M$", "Low Pressure Cooler", "", "error_int=0", "", "" }, // pre compressor cooler - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_T_in", "Intermediate pressure cross flow cooler inlet temperature", "C", "Intermediate Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_P_in", "Intermediate pressure cross flow cooler inlet pressure", "MPa", "Intermediate Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_m_dot_co2", "Intermediate pressure cross flow cooler CO2 mass flow rate", "kg/s", "Intermediate Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_UA", "Intermediate pressure cross flow cooler conductance", "MW/K", "Intermediate Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_q_dot", "Intermediate pressure cooler heat transfer", "MWt", "Intermediate Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_W_dot_fan", "Intermediate pressure cooler fan power", "MWe", "Intermediate Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_cost_equipment","Intermediate pressure cooler cost equipment", "M$", "Intermediate Pressure Cooler", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_cost_bare_erected","Intermediate pressure cooler cost equipment and install", "M$", "Intermediate Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_T_in", "Intermediate pressure cross flow cooler inlet temperature", "C", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_P_in", "Intermediate pressure cross flow cooler inlet pressure", "MPa", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_m_dot_co2", "Intermediate pressure cross flow cooler CO2 mass flow rate", "kg/s", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_UA", "Intermediate pressure cross flow cooler conductance", "MW/K", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_q_dot", "Intermediate pressure cooler heat transfer", "MWt", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_W_dot_fan", "Intermediate pressure cooler fan power", "MWe", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_cost_equipment","Intermediate pressure cooler cost equipment", "M$", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_cost_bare_erected","Intermediate pressure cooler cost equipment and install", "M$", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, // piping_inventory_etc_cost - { SSC_OUTPUT, SSC_NUMBER, "piping_inventory_etc_cost","Cost of remaining cycle equipment on BEC basis", "M$", "Intermediate Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "piping_inventory_etc_cost","Cost of remaining cycle equipment on BEC basis", "M$", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, // Cooler Totals - { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_cost_equipment", "Total cooler cost equipment", "M$", "Cooler Totals", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_cost_bare_erected","Total cooler cost equipment and install", "M$", "Cooler Totals", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_UA", "Total cooler conductance", "MW/K", "Cooler Totals", "", "*", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_W_dot_fan", "Total cooler fan power", "MWe", "Cooler Totals", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_cost_equipment", "Total cooler cost equipment", "M$", "Cooler Totals", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_cost_bare_erected","Total cooler cost equipment and install", "M$", "Cooler Totals", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_UA", "Total cooler conductance", "MW/K", "Cooler Totals", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_W_dot_fan", "Total cooler fan power", "MWe", "Cooler Totals", "", "error_int=0", "", "" }, // State Points - { SSC_OUTPUT, SSC_ARRAY, "T_state_points", "Cycle temperature state points", "C", "State Points", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_state_points", "Cycle pressure state points", "MPa", "State Points", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_state_points", "Cycle entropy state points", "kJ/kg-K", "State Points", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_state_points", "Cycle enthalpy state points", "kJ/kg", "State Points", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_state_points", "Cycle temperature state points", "C", "State Points", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_state_points", "Cycle pressure state points", "MPa", "State Points", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_state_points", "Cycle entropy state points", "kJ/kg-K", "State Points", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_state_points", "Cycle enthalpy state points", "kJ/kg", "State Points", "", "error_int=0", "", "" }, // T-s plot data - { SSC_OUTPUT, SSC_ARRAY, "T_LTR_HP_data", "Temperature points along LTR HP stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_LTR_HP_data", "Entropy points along LTR HP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_HTR_HP_data", "Temperature points along HTR HP stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_HTR_HP_data", "Entropy points along HTR HP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_PHX_data", "Temperature points along PHX stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_PHX_data", "Entropy points along PHX stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_HTR_LP_data", "Temperature points along HTR LP stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_HTR_LP_data", "Entropy points along HTR LP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_LTR_LP_data", "Temperature points along LTR LP stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_LTR_LP_data", "Entropy points along LTR LP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_main_cooler_data", "Temperature points along main cooler stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_main_cooler_data", "Entropy points along main cooler stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_pre_cooler_data", "Temperature points along pre cooler stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_pre_cooler_data", "Entropy points along pre cooler stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_LTR_HP_data", "Temperature points along LTR HP stream", "C", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_LTR_HP_data", "Entropy points along LTR HP stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_HTR_HP_data", "Temperature points along HTR HP stream", "C", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_HTR_HP_data", "Entropy points along HTR HP stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_PHX_data", "Temperature points along PHX stream", "C", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_PHX_data", "Entropy points along PHX stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_HTR_LP_data", "Temperature points along HTR LP stream", "C", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_HTR_LP_data", "Entropy points along HTR LP stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_LTR_LP_data", "Temperature points along LTR LP stream", "C", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_LTR_LP_data", "Entropy points along LTR LP stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_main_cooler_data", "Temperature points along main cooler stream", "C", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_main_cooler_data", "Entropy points along main cooler stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_pre_cooler_data", "Temperature points along pre cooler stream", "C", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_pre_cooler_data", "Entropy points along pre cooler stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, // P-h plot data - { SSC_OUTPUT, SSC_ARRAY, "P_t_data", "Pressure points along turbine expansion", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_t_data", "Enthalpy points along turbine expansion", "kJ/kg", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_mc_data", "Pressure points along main compression", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_mc_data", "Enthalpy points along main compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_rc_data", "Pressure points along re compression", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_rc_data", "Enthalpy points along re compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_pc_data", "Pressure points along pre compression", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_pc_data", "Enthalpy points along pre compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_t2_data", "Pressure points along secondary turbine expansion", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_t2_data", "Enthalpy points along secondary turbine expansion", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_t_data", "Pressure points along turbine expansion", "MPa", "P-h plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_t_data", "Enthalpy points along turbine expansion", "kJ/kg", "P-h plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_mc_data", "Pressure points along main compression", "MPa", "P-h plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_mc_data", "Enthalpy points along main compression", "kJ/kg", "P-h plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_rc_data", "Pressure points along re compression", "MPa", "P-h plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_rc_data", "Enthalpy points along re compression", "kJ/kg", "P-h plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_pc_data", "Pressure points along pre compression", "MPa", "P-h plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_pc_data", "Enthalpy points along pre compression", "kJ/kg", "P-h plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_t2_data", "Pressure points along secondary turbine expansion", "MPa", "P-h plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_t2_data", "Enthalpy points along secondary turbine expansion", "kJ/kg", "P-h plot data", "", "error_int=0", "", "" }, var_info_invalid }; @@ -1308,9 +1313,11 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c c_sco2_cycle.mf_callback_update = ssc_cmod_update; c_sco2_cycle.mp_mf_update = (void*)(cm); + int cycle_error_enum; + try { - c_sco2_cycle.design(s_sco2_des_par); + cycle_error_enum = c_sco2_cycle.design(s_sco2_des_par); } catch (C_csp_exception &csp_exception) { @@ -1324,12 +1331,22 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c throw exec_error("sco2_csp_system", csp_exception.m_error_message); } - //// DEBUG - //{ - // cm->assign("debug_string", var_data("test")); - //} + // Handle cycle errors + cm->assign("error_int", cycle_error_enum); - + // Cycle failed, exit now + if (cycle_error_enum >= (int)C_sco2_cycle_core::E_cycle_error_msg::E_CANNOT_PRODUCE_POWER + && cycle_error_enum < (int)C_sco2_cycle_core::E_cycle_error_msg::E_NO_ERROR) + { + std::string error_text = C_sco2_cycle_core::E_cycle_error_msg::get_error_string(cycle_error_enum); + cm->assign("error_msg", error_text); + cm->assign("cycle_success", 0); + return 0; + } + + std::string error_text = ""; + cm->assign("error_msg", error_text); + cm->assign("cycle_success", 1); // If all calls were successful, log to SSC any messages from sco2_recomp_csp while (c_sco2_cycle.mc_messages.get_message(&out_type, &out_msg)) diff --git a/tcs/sco2_cycle_templates.h b/tcs/sco2_cycle_templates.h index d0001ffc2a..ce2c600670 100644 --- a/tcs/sco2_cycle_templates.h +++ b/tcs/sco2_cycle_templates.h @@ -38,6 +38,49 @@ class C_sco2_cycle_core E_SET_T_T_IN // Model sets turbine inlet temperature to HTF inlet temperature }; + class E_cycle_error_msg + { + public: + + // Error Types + enum E_cycle_error_types + { + E_CANNOT_PRODUCE_POWER = 200, + E_CO2_PROPS_ERROR, + E_ETA_THRESHOLD, + E_HTR_LTR_CONVERGENCE, + E_AIR_COOLER_CONVERGENCE, + E_NO_ERROR + }; + + // Get error message corresponding to error type + // NO COMMAS in message + static std::string get_error_string(int error_enum) + { + switch (error_enum) + { + case((int)E_CANNOT_PRODUCE_POWER): + return "Cycle cannot produce power"; + break; + case((int)E_CO2_PROPS_ERROR): + return "Error calculating sCO2 properties"; + case((int)E_ETA_THRESHOLD): + return "Eta below threshold"; + case((int)E_NO_ERROR): + return "No error"; + break; + case((int)E_HTR_LTR_CONVERGENCE): + return "HTR LTR convergence issue"; + case((int)E_AIR_COOLER_CONVERGENCE): + return "Air cooler did not converge"; + default: + return "Error code not recognized"; + break; + } + } + + }; + enum class E_turbo_gen_motor_config { // Options to apply motor and generator losses diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 0735efd8c8..5314780f38 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -252,7 +252,7 @@ int C_sco2_htrbp_core::solve() if (m_outputs.m_w_mc + m_outputs.m_w_rc + m_outputs.m_w_t <= 0.0) // positive net power is impossible; return an error { - m_outputs.m_error_code = 25; + m_outputs.m_error_code = (int)C_sco2_cycle_core::E_cycle_error_msg::E_CANNOT_PRODUCE_POWER; return m_outputs.m_error_code; } } @@ -280,7 +280,7 @@ int C_sco2_htrbp_core::solve() if (T_HTR_LP_out_code != C_monotonic_eq_solver::CONVERGED) { - m_outputs.m_error_code = 35; + m_outputs.m_error_code = (int)C_sco2_cycle_core::E_cycle_error_msg::E_HTR_LTR_CONVERGENCE; return m_outputs.m_error_code; } @@ -933,6 +933,13 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) if (error_code != 0) return; + // don't size system if eta is terrible + //if (m_optimal_htrbp_core.m_outputs.m_eta_thermal < 0.15) + //{ + // error_code = (int)C_sco2_cycle_core::E_cycle_error_msg::E_ETA_THRESHOLD; + // return; + //} + // Finalize Design (pass in reference to solved parameters) error_code = m_optimal_htrbp_core.finalize_design(ms_des_solved); } diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index 6bc47b1472..70acd92340 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -62,11 +62,11 @@ C_sco2_phx_air_cooler::C_sco2_phx_air_cooler() mp_mf_update = 0; // NULL } -void C_sco2_phx_air_cooler::design(S_des_par des_par) +int C_sco2_phx_air_cooler::design(S_des_par des_par) { ms_des_par = des_par; - design_core(); + return design_core(); } void C_sco2_phx_air_cooler::C_P_LP_in_iter_tracker::reset_vectors() @@ -88,7 +88,7 @@ void C_sco2_phx_air_cooler::C_P_LP_in_iter_tracker::push_back_vectors(double P_L mv_is_converged.push_back(is_converged); //[-] } -void C_sco2_phx_air_cooler::design_core() +int C_sco2_phx_air_cooler::design_core() { // using -> C_RecompCycle::S_auto_opt_design_hit_eta_parameters std::string error_msg; @@ -375,7 +375,16 @@ void C_sco2_phx_air_cooler::design_core() if (auto_err_code != 0) { - throw(C_csp_exception(error_msg.c_str())); + // Check if error code is handled (need to report out) + if (auto_err_code >= (int)C_sco2_cycle_core::E_cycle_error_msg::E_CANNOT_PRODUCE_POWER + && auto_err_code < (int)C_sco2_cycle_core::E_cycle_error_msg::E_NO_ERROR) + { + return auto_err_code; + } + + // Unhandled exception + else + throw(C_csp_exception(error_msg.c_str())); } if (error_msg.empty()) @@ -536,7 +545,7 @@ void C_sco2_phx_air_cooler::design_core() - return; + return auto_err_code; } diff --git a/tcs/sco2_pc_csp_int.h b/tcs/sco2_pc_csp_int.h index 4dc529e5c4..b4978f5334 100644 --- a/tcs/sco2_pc_csp_int.h +++ b/tcs/sco2_pc_csp_int.h @@ -404,7 +404,7 @@ class C_sco2_phx_air_cooler double m_T_co2_crit; //[K] double m_P_co2_crit; //[kPa] - void design_core(); + int design_core(); double adjust_P_mc_in_away_2phase(double T_co2 /*K*/, double P_mc_in /*kPa*/); @@ -629,7 +629,7 @@ class C_sco2_phx_air_cooler util::matrix_t & T_htf_ind, util::matrix_t & T_amb_ind, util::matrix_t & m_dot_htf_ND_ind, double od_opt_tol /*-*/, double od_tol /*-*/); - void design(S_des_par des_par); + int design(S_des_par des_par); int off_design__constant_N__calc_max_htf_massflow__T_mc_in_P_LP_in__objective(C_sco2_phx_air_cooler::S_od_par od_par, bool is_rc_N_od_at_design, double rc_N_od_f_des /*-*/, diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp index ef2c215d93..fac5428657 100644 --- a/tcs/sco2_turbinesplitflow_cycle.cpp +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -477,11 +477,20 @@ int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_ s_air_cooler_des_par_ind.m_elev = m_inputs.m_elevation; // [m] s_air_cooler_des_par_ind.m_eta_fan = m_inputs.m_eta_fan; // [-] s_air_cooler_des_par_ind.m_N_nodes_pass = m_inputs.m_N_nodes_pass; // [-] - + if (m_inputs.m_is_des_air_cooler && std::isfinite(m_inputs.m_deltaP_cooler_frac) && std::isfinite(m_inputs.m_frac_fan_power) && std::isfinite(m_inputs.m_T_amb_des) && std::isfinite(m_inputs.m_elevation) && std::isfinite(m_inputs.m_eta_fan) && m_inputs.m_N_nodes_pass > 0) { - m_outputs.mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, m_inputs.m_des_tol); + try + { + m_outputs.mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, m_inputs.m_des_tol); + } + catch (...) + { + m_outputs.m_error_code = C_sco2_cycle_core::E_cycle_error_msg::E_AIR_COOLER_CONVERGENCE; + return m_outputs.m_error_code; + } + } } From 9f52a6651a9491bf05d5b4ce6c7841a86c12cd17 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Mon, 9 Dec 2024 18:36:01 -0700 Subject: [PATCH 60/94] Add option to end simulation if efficiency is below cutoff. --- ssc/csp_common.cpp | 11 +++++--- tcs/sco2_cycle_templates.h | 8 ++++-- tcs/sco2_htrbypass_cycle.cpp | 19 ++++++++++++- tcs/sco2_partialcooling_cycle.cpp | 37 +++++++++++++++++++++++-- tcs/sco2_pc_csp_int.cpp | 5 ++++ tcs/sco2_pc_csp_int.h | 3 +- tcs/sco2_recompression_cycle.cpp | 43 ++++++++++++++++++++++------- tcs/sco2_recompression_cycle.h | 4 +-- tcs/sco2_turbinesplitflow_cycle.cpp | 9 ++++++ 9 files changed, 116 insertions(+), 23 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 8a55d21c3b..14c4edc237 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -753,8 +753,10 @@ var_info vtab_sco2_design[] = { { SSC_INPUT, SSC_NUMBER, "site_elevation", "Site elevation", "m", "", "System Design", "*", "", "" }, { SSC_INPUT, SSC_NUMBER, "W_dot_net_des", "Design cycle power output (no cooling parasitics)", "MWe", "", "System Design", "*", "", "" }, { SSC_INPUT, SSC_NUMBER, "design_method", "1 = Specify efficiency, 2 = Specify total recup UA, 3 = Specify each recup design","","","System Design","*","", "" }, - { SSC_INPUT, SSC_NUMBER, "eta_thermal_des", "Power cycle thermal efficiency", "", "", "System Design", "design_method=1","", "" }, - + { SSC_INPUT, SSC_NUMBER, "eta_thermal_des", "Power cycle thermal efficiency", "", "", "System Design", "design_method=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "eta_thermal_cutoff", "Minimum eta allowable to solve and return cmod success", "", "", "System Design", "?=0", "", "" }, + + // Heat exchanger design // Combined recuperator design parameter (design_method == 2) { SSC_INPUT, SSC_NUMBER, "UA_recup_tot_des", "Total recuperator conductance", "kW/K", "Combined recuperator design", "Heat Exchanger Design", "design_method=2","", "" }, @@ -810,8 +812,6 @@ var_info vtab_sco2_design[] = { { SSC_INPUT, SSC_NUMBER, "eta_air_cooler_fan", "Air cooler fan isentropic efficiency", "", "", "Air Cooler Design", "?=0.5", "", "" }, { SSC_INPUT, SSC_NUMBER, "N_nodes_air_cooler_pass", "Number of nodes in single air cooler pass", "", "", "Air Cooler Design", "?=10", "", "" }, - - // HTR Bypass Design { SSC_INPUT, SSC_NUMBER, "is_bypass_ok", "1 = Yes, 0 = No Bypass, < 0 = fix bp_frac to abs(input)","", "High temperature recuperator", "Heat Exchanger Design", "?=1", "", "" }, { SSC_INPUT, SSC_NUMBER, "T_bypass_target", "HTR BP Cycle Target Temperature", "C", "", "System Design", "cycle_config=3", "", "" }, @@ -1120,6 +1120,8 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c cm->log(err_msg, SSC_ERROR, -1.0); } + s_sco2_des_par.m_eta_thermal_cutoff = cm->as_double("eta_thermal_cutoff"); + s_sco2_des_par.m_is_recomp_ok = cm->as_double("is_recomp_ok"); s_sco2_des_par.m_is_bypass_ok = cm->as_double("is_bypass_ok"); s_sco2_des_par.m_is_turbine_split_ok = cm->as_double("is_turbine_split_ok"); @@ -1341,6 +1343,7 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c std::string error_text = C_sco2_cycle_core::E_cycle_error_msg::get_error_string(cycle_error_enum); cm->assign("error_msg", error_text); cm->assign("cycle_success", 0); + cm->assign("eta_thermal_calc", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_eta_thermal); //[-] return 0; } diff --git a/tcs/sco2_cycle_templates.h b/tcs/sco2_cycle_templates.h index ce2c600670..8113ae4707 100644 --- a/tcs/sco2_cycle_templates.h +++ b/tcs/sco2_cycle_templates.h @@ -173,7 +173,9 @@ class C_sco2_cycle_core double m_eta_pc; //[-] design-point efficiency of the pre-compressor; double m_des_tol; //[-] Convergence tolerance double m_des_opt_tol; //[-] Optimization tolerance - + + double m_eta_thermal_cutoff; //[] Minimum eta to fully design cycle (returns failure below value) + // Air cooler parameters bool m_is_des_air_cooler; //[-] False will skip physical air cooler design. UA will not be available for cost models. @@ -254,7 +256,9 @@ class C_sco2_cycle_core double m_des_tol; //[-] Convergence tolerance double m_des_opt_tol; //[-] Optimization tolerance - + + double m_eta_thermal_cutoff; //[] Minimum eta to fully design cycle (returns failure below value) + // Air cooler parameters bool m_is_des_air_cooler; //[-] False will skip physical air cooler design. UA will not be available for cost models. diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 5314780f38..ef8b73c206 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -577,7 +577,16 @@ int C_sco2_htrbp_core::finalize_design(C_sco2_cycle_core::S_design_solved& desig if (m_inputs.m_is_des_air_cooler && std::isfinite(m_inputs.m_deltaP_cooler_frac) && std::isfinite(m_inputs.m_frac_fan_power) && std::isfinite(m_inputs.m_T_amb_des) && std::isfinite(m_inputs.m_elevation) && std::isfinite(m_inputs.m_eta_fan) && m_inputs.m_N_nodes_pass > 0) { - m_outputs.mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, m_inputs.m_des_tol); + try + { + m_outputs.mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, m_inputs.m_des_tol); + } + catch (...) + { + design_solved.m_eta_thermal = m_outputs.m_eta_thermal; + m_outputs.m_error_code = C_sco2_cycle_core::E_cycle_error_msg::E_AIR_COOLER_CONVERGENCE; + return m_outputs.m_error_code; + } } } @@ -940,6 +949,14 @@ void C_HTRBypass_Cycle::auto_opt_design_core(int& error_code) // return; //} + // Check if cycle is below eta cutoff value + if (m_optimal_htrbp_core.m_outputs.m_eta_thermal < ms_auto_opt_des_par.m_eta_thermal_cutoff) + { + ms_des_solved.m_eta_thermal = m_optimal_htrbp_core.m_outputs.m_eta_thermal; + error_code = C_sco2_cycle_core::E_cycle_error_msg::E_ETA_THRESHOLD; + return; + } + // Finalize Design (pass in reference to solved parameters) error_code = m_optimal_htrbp_core.finalize_design(ms_des_solved); } diff --git a/tcs/sco2_partialcooling_cycle.cpp b/tcs/sco2_partialcooling_cycle.cpp index 9a05c54510..4c1b91f803 100644 --- a/tcs/sco2_partialcooling_cycle.cpp +++ b/tcs/sco2_partialcooling_cycle.cpp @@ -617,7 +617,15 @@ int C_PartialCooling_Cycle::finalize_design() if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) { - mc_pc_air_cooler.design_hx(s_LP_air_cooler_des_par_ind, s_LP_air_cooler_des_par_dep, ms_des_par.m_des_tol); + try + { + mc_pc_air_cooler.design_hx(s_LP_air_cooler_des_par_ind, s_LP_air_cooler_des_par_dep, ms_des_par.m_des_tol); + } + catch (...) + { + ms_des_solved.m_eta_thermal = m_eta_thermal_calc_last; + return C_sco2_cycle_core::E_cycle_error_msg::E_AIR_COOLER_CONVERGENCE; + } } // High Pressure @@ -647,7 +655,15 @@ int C_PartialCooling_Cycle::finalize_design() if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) { - mc_mc_air_cooler.design_hx(s_IP_air_cooler_des_par_ind, s_IP_air_cooler_des_par_dep, ms_des_par.m_des_tol); + try + { + mc_mc_air_cooler.design_hx(s_IP_air_cooler_des_par_ind, s_IP_air_cooler_des_par_dep, ms_des_par.m_des_tol); + } + catch (...) + { + ms_des_solved.m_eta_thermal = m_eta_thermal_calc_last; + return C_sco2_cycle_core::E_cycle_error_msg::E_AIR_COOLER_CONVERGENCE; + } } @@ -948,6 +964,13 @@ int C_PartialCooling_Cycle::opt_design(S_opt_des_params & opt_des_par_in) if (opt_des_err_code != 0) return opt_des_err_code; + // Check if cycle is below eta cutoff value + if (m_eta_thermal_calc_last < ms_auto_opt_des_par.m_eta_thermal_cutoff) + { + ms_des_solved.m_eta_thermal = m_eta_thermal_calc_last; + return C_sco2_cycle_core::E_cycle_error_msg::E_ETA_THRESHOLD; + } + return finalize_design(); } @@ -1081,7 +1104,15 @@ int C_PartialCooling_Cycle::auto_opt_design_core() return pc_opt_des_error_code; } - pc_opt_des_error_code = finalize_design(); + + // Check if cycle is below eta cutoff value + if (m_eta_thermal_calc_last < ms_auto_opt_des_par.m_eta_thermal_cutoff) + { + ms_des_solved.m_eta_thermal = m_eta_thermal_calc_last; + return C_sco2_cycle_core::E_cycle_error_msg::E_ETA_THRESHOLD; + } + + pc_opt_des_error_code = finalize_design(); return pc_opt_des_error_code; } diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index 7c0c62c5d2..db79b2196f 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -292,6 +292,8 @@ int C_sco2_phx_air_cooler::design_core() ms_cycle_des_par.m_des_objective_type = ms_des_par.m_des_objective_type; //[-] ms_cycle_des_par.m_min_phx_deltaT = ms_des_par.m_min_phx_deltaT; //[C] + ms_cycle_des_par.m_eta_thermal_cutoff = ms_des_par.m_eta_thermal_cutoff; //[] + ms_cycle_des_par.m_fixed_P_mc_out = ms_des_par.m_fixed_P_mc_out; //[-] ms_cycle_des_par.m_PR_HP_to_LP_guess = ms_des_par.m_PR_HP_to_LP_guess; //[-] @@ -364,6 +366,8 @@ int C_sco2_phx_air_cooler::design_core() des_params.m_is_bypass_ok = ms_des_par.m_is_bypass_ok; des_params.m_is_turbinesplit_ok = ms_des_par.m_is_turbine_split_ok; + des_params.m_eta_thermal_cutoff = ms_des_par.m_eta_thermal_cutoff; + auto_err_code = mpc_sco2_cycle->auto_opt_design(des_params); } else @@ -379,6 +383,7 @@ int C_sco2_phx_air_cooler::design_core() if (auto_err_code >= (int)C_sco2_cycle_core::E_cycle_error_msg::E_CANNOT_PRODUCE_POWER && auto_err_code < (int)C_sco2_cycle_core::E_cycle_error_msg::E_NO_ERROR) { + ms_des_solved.ms_rc_cycle_solved = *mpc_sco2_cycle->get_design_solved(); return auto_err_code; } diff --git a/tcs/sco2_pc_csp_int.h b/tcs/sco2_pc_csp_int.h index 92fde3f7cb..4dbd8e4b59 100644 --- a/tcs/sco2_pc_csp_int.h +++ b/tcs/sco2_pc_csp_int.h @@ -66,7 +66,8 @@ class C_sco2_phx_air_cooler double m_eta_thermal; //[-] Cycle thermal efficiency double m_UA_recup_tot_des; //[kW/K] Total recuperator conductance int m_cycle_config; //[-] 2 = partial cooling, [else] = recompression - + double m_eta_thermal_cutoff; //[] Minimum eta to fully design cycle (returns failure below value) + // Cycle design parameters std::vector m_DP_LT; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) std::vector m_DP_HT; //(cold, hot) positive values are absolute [kPa], negative values are relative (-) diff --git a/tcs/sco2_recompression_cycle.cpp b/tcs/sco2_recompression_cycle.cpp index e9f97c54e8..91a105b1d3 100644 --- a/tcs/sco2_recompression_cycle.cpp +++ b/tcs/sco2_recompression_cycle.cpp @@ -2387,12 +2387,12 @@ void C_RecompCycle::design(S_design_parameters & des_par_in, int & error_code) return; } - finalize_design(design_error_code); + design_error_code = finalize_design(design_error_code); error_code = design_error_code; } -void C_RecompCycle::opt_design(S_opt_design_parameters & opt_des_par_in, int & error_code) +int C_RecompCycle::opt_design(S_opt_design_parameters & opt_des_par_in, int & error_code) { ms_opt_des_par = opt_des_par_in; @@ -2402,10 +2402,17 @@ void C_RecompCycle::opt_design(S_opt_design_parameters & opt_des_par_in, int & e if(error_code != 0) { - return; + return error_code; } - finalize_design(error_code); + // Check if cycle is below eta cutoff value + if (m_eta_thermal_calc_last < ms_auto_opt_des_par.m_eta_thermal_cutoff) + { + ms_des_solved.m_eta_thermal = m_eta_thermal_calc_last; + return C_sco2_cycle_core::E_cycle_error_msg::E_ETA_THRESHOLD; + } + + return finalize_design(error_code); } void C_RecompCycle::opt_design_core(int & error_code) @@ -2820,7 +2827,15 @@ void C_RecompCycle::auto_opt_design_core(int & error_code) return; } - finalize_design(optimal_design_error_code); + // Check if cycle is below eta cutoff value + if (m_eta_thermal_calc_last < ms_auto_opt_des_par.m_eta_thermal_cutoff) + { + ms_des_solved.m_eta_thermal = m_eta_thermal_calc_last; + error_code = C_sco2_cycle_core::E_cycle_error_msg::E_ETA_THRESHOLD; + return; + } + + optimal_design_error_code = finalize_design(optimal_design_error_code); error_code = optimal_design_error_code; } @@ -3324,7 +3339,7 @@ void C_RecompCycle::check_od_solution(double & diff_m_dot, double & diff_E_cycle diff_Q_HTR = (Q_dot_HTR_HP - Q_dot_HTR_LP) / Q_dot_HTR_LP; } -void C_RecompCycle::finalize_design(int & error_code) +int C_RecompCycle::finalize_design(int & error_code) { int cpp_offset = 1; @@ -3338,7 +3353,7 @@ void C_RecompCycle::finalize_design(int & error_code) if (mc_design_err != 0) { error_code = mc_design_err; - return; + return error_code; } if( ms_des_par.m_recomp_frac > 0.01 ) @@ -3352,7 +3367,7 @@ void C_RecompCycle::finalize_design(int & error_code) if (rc_des_err != 0) { error_code = rc_des_err; - return; + return error_code; } ms_des_solved.m_is_rc = true; @@ -3382,7 +3397,7 @@ void C_RecompCycle::finalize_design(int & error_code) if(turb_size_error_code != 0) { error_code = turb_size_error_code; - return; + return error_code; } // Design air cooler @@ -3413,7 +3428,15 @@ void C_RecompCycle::finalize_design(int & error_code) if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) { - mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, ms_des_par.m_des_tol); + try + { + mc_air_cooler.design_hx(s_air_cooler_des_par_ind, s_air_cooler_des_par_dep, ms_des_par.m_des_tol); + } + catch (...) + { + ms_des_solved.m_eta_thermal = m_eta_thermal_calc_last; + return C_sco2_cycle_core::E_cycle_error_msg::E_AIR_COOLER_CONVERGENCE; + } } diff --git a/tcs/sco2_recompression_cycle.h b/tcs/sco2_recompression_cycle.h index 408e029d7b..5b1bf54cf5 100644 --- a/tcs/sco2_recompression_cycle.h +++ b/tcs/sco2_recompression_cycle.h @@ -467,7 +467,7 @@ class C_RecompCycle : public C_sco2_cycle_core void auto_opt_design_core(int & error_code); - void finalize_design(int & error_code); + int finalize_design(int & error_code); //void off_design_core(int & error_code); @@ -554,7 +554,7 @@ class C_RecompCycle : public C_sco2_cycle_core void design(S_design_parameters & des_par_in, int & error_code); - void opt_design(S_opt_design_parameters & opt_des_par_in, int & error_code); + int opt_design(S_opt_design_parameters & opt_des_par_in, int & error_code); //void od_turbo_bal_csp(const S_od_turbo_bal_csp_par & par_in); diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp index fac5428657..b1bf9d1c28 100644 --- a/tcs/sco2_turbinesplitflow_cycle.cpp +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -487,6 +487,7 @@ int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_ } catch (...) { + design_solved.m_eta_thermal = m_outputs.m_eta_thermal; m_outputs.m_error_code = C_sco2_cycle_core::E_cycle_error_msg::E_AIR_COOLER_CONVERGENCE; return m_outputs.m_error_code; } @@ -684,6 +685,14 @@ void C_TurbineSplitFlow_Cycle::auto_opt_design_core(int& error_code) if (error_code != 0) return; + // Check if cycle is below eta cutoff value + if (m_optimal_tsf_core.m_outputs.m_eta_thermal < ms_auto_opt_des_par.m_eta_thermal_cutoff) + { + ms_des_solved.m_eta_thermal = m_optimal_tsf_core.m_outputs.m_eta_thermal; + error_code = C_sco2_cycle_core::E_cycle_error_msg::E_ETA_THRESHOLD; + return; + } + // Finalize Design (pass in reference to solved parameters) error_code = m_optimal_tsf_core.finalize_design(ms_des_solved); From 9886104a708733bd606b9e490dfe2fd410e6c5e6 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:38:41 -0700 Subject: [PATCH 61/94] Fix bug returning error code in recomp. --- tcs/sco2_recompression_cycle.cpp | 19 +++++++++++-------- tcs/sco2_recompression_cycle.h | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/tcs/sco2_recompression_cycle.cpp b/tcs/sco2_recompression_cycle.cpp index 91a105b1d3..b4f5b70a18 100644 --- a/tcs/sco2_recompression_cycle.cpp +++ b/tcs/sco2_recompression_cycle.cpp @@ -2387,7 +2387,7 @@ void C_RecompCycle::design(S_design_parameters & des_par_in, int & error_code) return; } - design_error_code = finalize_design(design_error_code); + finalize_design(design_error_code); error_code = design_error_code; } @@ -2412,7 +2412,9 @@ int C_RecompCycle::opt_design(S_opt_design_parameters & opt_des_par_in, int & er return C_sco2_cycle_core::E_cycle_error_msg::E_ETA_THRESHOLD; } - return finalize_design(error_code); + finalize_design(error_code); + + return error_code; } void C_RecompCycle::opt_design_core(int & error_code) @@ -2835,7 +2837,7 @@ void C_RecompCycle::auto_opt_design_core(int & error_code) return; } - optimal_design_error_code = finalize_design(optimal_design_error_code); + finalize_design(optimal_design_error_code); error_code = optimal_design_error_code; } @@ -3339,7 +3341,7 @@ void C_RecompCycle::check_od_solution(double & diff_m_dot, double & diff_E_cycle diff_Q_HTR = (Q_dot_HTR_HP - Q_dot_HTR_LP) / Q_dot_HTR_LP; } -int C_RecompCycle::finalize_design(int & error_code) +void C_RecompCycle::finalize_design(int & error_code) { int cpp_offset = 1; @@ -3353,7 +3355,7 @@ int C_RecompCycle::finalize_design(int & error_code) if (mc_design_err != 0) { error_code = mc_design_err; - return error_code; + return; } if( ms_des_par.m_recomp_frac > 0.01 ) @@ -3367,7 +3369,7 @@ int C_RecompCycle::finalize_design(int & error_code) if (rc_des_err != 0) { error_code = rc_des_err; - return error_code; + return; } ms_des_solved.m_is_rc = true; @@ -3397,7 +3399,7 @@ int C_RecompCycle::finalize_design(int & error_code) if(turb_size_error_code != 0) { error_code = turb_size_error_code; - return error_code; + return; } // Design air cooler @@ -3435,7 +3437,8 @@ int C_RecompCycle::finalize_design(int & error_code) catch (...) { ms_des_solved.m_eta_thermal = m_eta_thermal_calc_last; - return C_sco2_cycle_core::E_cycle_error_msg::E_AIR_COOLER_CONVERGENCE; + error_code = C_sco2_cycle_core::E_cycle_error_msg::E_AIR_COOLER_CONVERGENCE; + return; } } diff --git a/tcs/sco2_recompression_cycle.h b/tcs/sco2_recompression_cycle.h index 5b1bf54cf5..d3c691d2c9 100644 --- a/tcs/sco2_recompression_cycle.h +++ b/tcs/sco2_recompression_cycle.h @@ -467,7 +467,7 @@ class C_RecompCycle : public C_sco2_cycle_core void auto_opt_design_core(int & error_code); - int finalize_design(int & error_code); + void finalize_design(int & error_code); //void off_design_core(int & error_code); From 9f9ad6274cc7d0b4f5ad3641a24b7e0a876b075a Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Fri, 6 Dec 2024 11:24:17 -0700 Subject: [PATCH 62/94] Fix HX q_dot guess bug. --- tcs/heat_exchangers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcs/heat_exchangers.cpp b/tcs/heat_exchangers.cpp index ddff1eba87..08c587ad48 100644 --- a/tcs/heat_exchangers.cpp +++ b/tcs/heat_exchangers.cpp @@ -1475,7 +1475,7 @@ void NS_HX_counterflow_eqs::solve_q_dot_for_fixed_UA_enth(int hot_fl_code /*-*/, double q_dot_mult = max(0.99, min(0.95, eff_limit) / eff_limit); if ( std::isfinite(eff_guess) ) { - q_dot_mult = max(0.99, min(0.1, eff_guess)); + q_dot_mult = min(0.99, max(0.1, eff_guess)); } double q_dot_guess_upper = q_dot_mult*q_dot_upper; From 21fdb7dba8f1aa0473fbe0267af642a1d1f997a0 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Wed, 25 Dec 2024 21:17:32 -0700 Subject: [PATCH 63/94] Update cycle_config label to include tsf. --- ssc/csp_common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 14c4edc237..762ad68055 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -781,7 +781,7 @@ var_info vtab_sco2_design[] = { { SSC_INPUT, SSC_NUMBER, "HTR_n_sub_hx", "HTR number of model subsections", "-", "High temperature recuperator", "Heat Exchanger Design", "?=10", "", "" }, { SSC_INPUT, SSC_NUMBER, "HTR_od_model", "0: mass flow scale, 1: conductance ratio model", "-", "High temperature recuperator", "Heat Exchanger Design", "?=1", "", "" }, - { SSC_INPUT, SSC_NUMBER, "cycle_config", "1 = recompression, 2 = partial cooling, 3 = recomp with htr bypass", "", "High temperature recuperator", "Heat Exchanger Design", "?=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "cycle_config", "1 = recompression, 2 = partial cooling, 3 = recomp with htr bypass, 4 = turbine split flow", "", "High temperature recuperator", "Heat Exchanger Design", "?=1", "", "" }, { SSC_INPUT, SSC_NUMBER, "is_recomp_ok", "1 = Yes, 0 = simple cycle only, < 0 = fix f_recomp to abs(input)","", "High temperature recuperator", "Heat Exchanger Design", "?=1", "", "" }, { SSC_INPUT, SSC_NUMBER, "is_P_high_fixed", "1 = Yes (=P_high_limit), 0 = No, optimized (default)", "", "High temperature recuperator", "Heat Exchanger Design", "?=0", "", "" }, { SSC_INPUT, SSC_NUMBER, "is_PR_fixed", "0 = No, >0 = fixed pressure ratio at input <0 = fixed LP at abs(input)", "High temperature recuperator", "", "Heat Exchanger Design", "?=0", "", "" }, From 611b1535efa040c778fa34a1f846a27637187af0 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Mon, 30 Dec 2024 16:27:15 -0700 Subject: [PATCH 64/94] Update air cooler solver to account for large temperature differences. --- tcs/heat_exchangers.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tcs/heat_exchangers.cpp b/tcs/heat_exchangers.cpp index 08c587ad48..edd2c11c5f 100644 --- a/tcs/heat_exchangers.cpp +++ b/tcs/heat_exchangers.cpp @@ -2872,7 +2872,8 @@ bool C_CO2_to_air_cooler::design_hx(S_des_par_ind des_par_ind, S_des_par_cycle_d solver_code = -1; i_W_par = -1; - while (solver_code != 0 || std::abs(T_hot_in_calc_2 - T_hot_in_calc) / T_hot_in_calc < 0.01) + while (solver_code != 0 || std::abs(T_hot_in_calc_2 - T_hot_in_calc) / T_hot_in_calc < 0.01 + || ms_des_par_cycle_dep.m_T_hot_in_des - T_hot_in_calc_2 > 100.0) { i_W_par++; From 34d527038b821b16d110095fa4820c758196e3ed Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Mon, 13 Jan 2025 14:19:21 -0700 Subject: [PATCH 65/94] Fix bug preventing users from setting recomp frac to zero in partial cooling cycle. --- tcs/sco2_partialcooling_cycle.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tcs/sco2_partialcooling_cycle.cpp b/tcs/sco2_partialcooling_cycle.cpp index 4c1b91f803..c5af391495 100644 --- a/tcs/sco2_partialcooling_cycle.cpp +++ b/tcs/sco2_partialcooling_cycle.cpp @@ -214,6 +214,14 @@ int C_PartialCooling_Cycle::design_core() if (comp_error_code != 0) return comp_error_code; } + else + { + // No recompressor, so set all RC_OUT equal to PC_OUT + m_temp_last[RC_OUT] = m_temp_last[PC_OUT]; + m_dens_last[RC_OUT] = m_dens_last[PC_OUT]; + m_enth_last[RC_OUT] = m_enth_last[PC_OUT]; + m_entr_last[RC_OUT] = m_entr_last[PC_OUT]; + } double w_t = std::numeric_limits::quiet_NaN(); calculate_turbomachinery_outlet_1(m_temp_last[TURB_IN], m_pres_last[TURB_IN], m_pres_last[TURB_OUT], eta_t_isen, false, @@ -1068,7 +1076,7 @@ int C_PartialCooling_Cycle::auto_opt_design_core() // Is recompression fraction fixed or optimized? - if (ms_auto_opt_des_par.m_is_recomp_ok < 0.0) + if (ms_auto_opt_des_par.m_is_recomp_ok <= 0.0) { ms_opt_des_par.m_recomp_frac_guess = std::abs(ms_auto_opt_des_par.m_is_recomp_ok); //[-] ms_opt_des_par.m_fixed_recomp_frac = true; From b2395255d8feeb573c570f3af1fc47e176f7a978 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Thu, 23 Jan 2025 09:25:20 -0700 Subject: [PATCH 66/94] Add high temperature correction to recuperator cost model. --- tcs/heat_exchangers.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tcs/heat_exchangers.cpp b/tcs/heat_exchangers.cpp index edd2c11c5f..a7eb908f61 100644 --- a/tcs/heat_exchangers.cpp +++ b/tcs/heat_exchangers.cpp @@ -1792,7 +1792,14 @@ double /*M$*/ C_HX_counterflow_CRM::calculate_equipment_cost(double UA /*kWt/K*/ case C_HX_counterflow_CRM::E_CARLSON_17_RECUP: return 1.25*1.E-3*UA; //[M$] needs UA in kWt/K case C_HX_counterflow_CRM::E_WEILAND_19_RECUP: - return 49.45*std::pow(UA*1.E3, 0.7544)*1.E-6; //[M$] needs UA in Wt/K + double C_recup = 49.45 * std::pow(UA * 1.E3, 0.7544) * 1.E-6; //[M$] needs UA in Wt/K + double T_factor = 1; + double T_max_C = std::max(T_hot_in, T_cold_in) - 273.15; + if (T_max_C >= 550) + { + T_factor = 1.0 + 0.02141 * (T_hot_in - 550); + } + return C_recup * T_factor; //[M$] case C_HX_counterflow_CRM::E_CARLSON_17_PHX: return 3.5*1.E-3*UA; //[M$] needs UA in kWt/K default: From b855cbe30559ab9a032393af8c2b017609a9973b Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Mon, 3 Feb 2025 09:18:22 -0700 Subject: [PATCH 67/94] Fix recuperator temperature correction bug. --- tcs/heat_exchangers.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tcs/heat_exchangers.cpp b/tcs/heat_exchangers.cpp index a7eb908f61..a1aa887487 100644 --- a/tcs/heat_exchangers.cpp +++ b/tcs/heat_exchangers.cpp @@ -1792,14 +1792,16 @@ double /*M$*/ C_HX_counterflow_CRM::calculate_equipment_cost(double UA /*kWt/K*/ case C_HX_counterflow_CRM::E_CARLSON_17_RECUP: return 1.25*1.E-3*UA; //[M$] needs UA in kWt/K case C_HX_counterflow_CRM::E_WEILAND_19_RECUP: + { double C_recup = 49.45 * std::pow(UA * 1.E3, 0.7544) * 1.E-6; //[M$] needs UA in Wt/K double T_factor = 1; double T_max_C = std::max(T_hot_in, T_cold_in) - 273.15; if (T_max_C >= 550) { - T_factor = 1.0 + 0.02141 * (T_hot_in - 550); + T_factor = 1.0 + 0.02141 * (T_max_C - 550); } return C_recup * T_factor; //[M$] + } case C_HX_counterflow_CRM::E_CARLSON_17_PHX: return 3.5*1.E-3*UA; //[M$] needs UA in kWt/K default: From 7f277954093bcf0d0479f50476a50db6a54b6de1 Mon Sep 17 00:00:00 2001 From: tyneises Date: Fri, 7 Feb 2025 11:35:58 -0600 Subject: [PATCH 68/94] change exception to fix linus build --- tcs/sco2_htrbypass_cycle.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index ef8b73c206..d6c84f8e5f 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -1988,7 +1988,8 @@ double C_HTRBypass_Cycle::optimize_bp_return_objective_metric(const std::vector< if (opt_par.m_fixed_bypass_frac == true) { - throw std::exception("Optimizing bypass fraction even though it is fixed"); + //throw std::exception("Optimizing bypass fraction even though it is fixed"); + throw(C_csp_exception("Optimizing bypass fraction even though it is fixed")); } // Set Bypass Fraction From 71b270160e3783aa76128ff373d2ad662d953195 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Tue, 31 Dec 2024 11:30:00 -0700 Subject: [PATCH 69/94] Add temperature correction to turbine cost. --- tcs/sco2_cycle_components.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tcs/sco2_cycle_components.cpp b/tcs/sco2_cycle_components.cpp index 87e81e3f5c..c9aebc1bcb 100644 --- a/tcs/sco2_cycle_components.cpp +++ b/tcs/sco2_cycle_components.cpp @@ -870,7 +870,17 @@ double C_turbine::calculate_equipment_cost(double T_in /*K*/, double P_in /*kPa* case C_turbine::E_CARLSON_17: return 7.79*1.E-3*std::pow(W_dot, 0.6842); //[M$] needs power in kWe case C_turbine::E_WEILAND_19__AXIAL: - return 182600*std::pow(W_dot*1.E-3, 0.5561)*1.E-6; //[M$] needs power in MWe + { + double base_cost = 182600 * std::pow(W_dot * 1.E-3, 0.5561); // [$] needs power in MWe + + double cost_mult = 1.0; + double T_in_C = T_in - 273.15; //[C] + if (T_in_C >= 550) { + cost_mult = 1.0 + ((1.106e-4) * std::pow(T_in_C - 550, 2.0)); + } + + return base_cost * cost_mult * 1e-6; //[M$] + } default: return std::numeric_limits::quiet_NaN(); } From 5ae2e7d5ee3d4219f820802d605ebdd3afbd19b1 Mon Sep 17 00:00:00 2001 From: tyneises Date: Fri, 7 Feb 2025 12:13:37 -0600 Subject: [PATCH 70/94] remove class name from method to try to resolve linux error --- tcs/sco2_htrbypass_cycle.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index d7f0690fab..c9820f29d1 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -445,9 +445,9 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core int auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg); // Objective Functions (internal use only) - double C_HTRBypass_Cycle::optimize_totalUA_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par); - double C_HTRBypass_Cycle::optimize_bp_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); - double C_HTRBypass_Cycle::optimize_nonbp_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); + double optimize_totalUA_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par); + double optimize_bp_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); + double optimize_nonbp_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_htrbp_core& htrbp_core); // Off Design From 9da26ff9fe3ad0a79fdc2b1b9678563678bdf602 Mon Sep 17 00:00:00 2001 From: tyneises Date: Fri, 7 Feb 2025 12:21:37 -0600 Subject: [PATCH 71/94] remove class name from method to try to resolve linux error --- tcs/sco2_turbinesplitflow_cycle.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcs/sco2_turbinesplitflow_cycle.h b/tcs/sco2_turbinesplitflow_cycle.h index 609942b227..37a3f8d9e4 100644 --- a/tcs/sco2_turbinesplitflow_cycle.h +++ b/tcs/sco2_turbinesplitflow_cycle.h @@ -365,8 +365,8 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core int auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg); // Objective Functions (internal use only) - double C_TurbineSplitFlow_Cycle::optimize_totalUA_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par); - double C_TurbineSplitFlow_Cycle::optimize_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_tsf_core& tsf_core); + double optimize_totalUA_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par); + double optimize_par_return_objective_metric(const std::vector& x, const S_auto_opt_design_parameters& auto_par, const S_opt_design_parameters& opt_par, C_sco2_tsf_core& tsf_core); // Off Design From 25863386ff4e7721da1f16d3cbd76f5b1842ccb8 Mon Sep 17 00:00:00 2001 From: tyneises Date: Mon, 10 Feb 2025 08:58:19 -0600 Subject: [PATCH 72/94] remove maxeval from sco2 cycle optimization --- tcs/sco2_htrbypass_cycle.cpp | 6 +++--- tcs/sco2_partialcooling_cycle.cpp | 2 +- tcs/sco2_recompression_cycle.cpp | 2 +- tcs/sco2_turbinesplitflow_cycle.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index d6c84f8e5f..fbe5c5e308 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -1092,7 +1092,7 @@ int C_HTRBypass_Cycle::optimize_totalUA(const S_auto_opt_design_parameters& auto opt_des_cycle.set_initial_step(1000); //opt_des_cycle.set_xtol_rel(ms_auto_opt_des_par.m_des_opt_tol); opt_des_cycle.set_xtol_rel(1); - opt_des_cycle.set_maxeval(50); + //opt_des_cycle.set_maxeval(50); // Make Tuple to pass in parameters std::tuple par_tuple = { this, &auto_par, &opt_par }; @@ -1257,7 +1257,7 @@ int C_HTRBypass_Cycle::optimize_bp(const S_auto_opt_design_parameters& auto_par, opt_des_cycle.set_initial_step(0.1); //opt_des_cycle.set_xtol_rel(auto_par.m_des_opt_tol); opt_des_cycle.set_xtol_rel(0.1); - opt_des_cycle.set_maxeval(50); + //opt_des_cycle.set_maxeval(50); // Set up Core Model that will be passed to objective function C_sco2_htrbp_core htrbp_core; @@ -1378,7 +1378,7 @@ int C_HTRBypass_Cycle::optimize_nonbp(const S_auto_opt_design_parameters& auto_p opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(scale); opt_des_cycle.set_xtol_rel(auto_par.m_des_opt_tol); - opt_des_cycle.set_maxeval(50); + //opt_des_cycle.set_maxeval(50); // Set up Core Model that will be passed to objective function C_sco2_htrbp_core htrbp_core; diff --git a/tcs/sco2_partialcooling_cycle.cpp b/tcs/sco2_partialcooling_cycle.cpp index c5af391495..68309cb6e4 100644 --- a/tcs/sco2_partialcooling_cycle.cpp +++ b/tcs/sco2_partialcooling_cycle.cpp @@ -918,7 +918,7 @@ int C_PartialCooling_Cycle::opt_design_core() opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(scale); opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); - opt_des_cycle.set_maxeval(10); + //opt_des_cycle.set_maxeval(10); // set max objective function opt_des_cycle.set_max_objective(nlopt_cb_opt_partialcooling_des, this); diff --git a/tcs/sco2_recompression_cycle.cpp b/tcs/sco2_recompression_cycle.cpp index b4f5b70a18..2f3184181e 100644 --- a/tcs/sco2_recompression_cycle.cpp +++ b/tcs/sco2_recompression_cycle.cpp @@ -2507,7 +2507,7 @@ void C_RecompCycle::opt_design_core(int & error_code) opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(scale); opt_des_cycle.set_xtol_rel(ms_opt_des_par.m_des_opt_tol); - opt_des_cycle.set_maxeval(10); + //opt_des_cycle.set_maxeval(10); // Set max objective function opt_des_cycle.set_max_objective(nlopt_cb_opt_des, this); // Calls wrapper/callback that calls 'design_point_eta', which optimizes design point eta through repeated calls to 'design' double max_f = std::numeric_limits::quiet_NaN(); diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp index b1bf9d1c28..0510a9c4c9 100644 --- a/tcs/sco2_turbinesplitflow_cycle.cpp +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -866,7 +866,7 @@ int C_TurbineSplitFlow_Cycle::optimize_par(const S_auto_opt_design_parameters& a opt_des_cycle.set_upper_bounds(ub); opt_des_cycle.set_initial_step(scale); opt_des_cycle.set_xtol_rel(auto_par.m_des_opt_tol); - opt_des_cycle.set_maxeval(50); + //opt_des_cycle.set_maxeval(50); // Set up core model that will be passed to objective function C_sco2_tsf_core tsf_core; From 3671fa7566b196c15e4797870061d5d347b37ec3 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Fri, 7 Feb 2025 10:44:55 -0700 Subject: [PATCH 73/94] Add inflation factor input. --- ssc/csp_common.cpp | 5 ++++ tcs/heat_exchangers.cpp | 37 ++++++++++++++++++----------- tcs/heat_exchangers.h | 19 ++++++++++----- tcs/sco2_cycle_components.cpp | 18 +++++++------- tcs/sco2_cycle_components.h | 11 +++++---- tcs/sco2_cycle_templates.h | 7 ++++-- tcs/sco2_htrbypass_cycle.cpp | 15 ++++++++---- tcs/sco2_htrbypass_cycle.h | 8 +++++-- tcs/sco2_partialcooling_cycle.cpp | 16 +++++++++---- tcs/sco2_partialcooling_cycle.h | 6 +++-- tcs/sco2_pc_csp_int.cpp | 18 +++++++++----- tcs/sco2_pc_csp_int.h | 4 +++- tcs/sco2_recompression_cycle.cpp | 13 ++++++---- tcs/sco2_recompression_cycle.h | 6 +++-- tcs/sco2_turbinesplitflow_cycle.cpp | 16 +++++++++---- tcs/sco2_turbinesplitflow_cycle.h | 10 +++++--- 16 files changed, 140 insertions(+), 69 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 762ad68055..8ba542d8c1 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -823,6 +823,8 @@ var_info vtab_sco2_design[] = { { SSC_INPUT, SSC_NUMBER, "is_turbine_split_ok", "1 = Yes, 0 = No Second Turbine, < 0 = fix split_frac to abs(input)","", "", "", "?=1", "", "" }, { SSC_INPUT, SSC_NUMBER, "eta_isen_t2", "Design secondary turbine isentropic efficiency (TSF only)", "-", "", "", "cycle_config=4", "", "" }, + // Cost Inputs + { SSC_INPUT, SSC_NUMBER, "f_inflation", "Inflation factor", "", "", "System Design", "?=1", "", "" }, // DEBUG @@ -1307,6 +1309,9 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c s_sco2_des_par.m_eta_t2 = s_sco2_des_par.m_eta_t; } + // Inflation factor + s_sco2_des_par.m_f_inflation = cm->as_double("f_inflation"); //[-] + // For try/catch below int out_type = -1; std::string out_msg = ""; diff --git a/tcs/heat_exchangers.cpp b/tcs/heat_exchangers.cpp index a1aa887487..3d0476822a 100644 --- a/tcs/heat_exchangers.cpp +++ b/tcs/heat_exchangers.cpp @@ -1785,12 +1785,13 @@ double C_HX_counterflow_CRM::calc_max_q_dot_enth(double h_h_in /*kJ/kg*/, double double /*M$*/ C_HX_counterflow_CRM::calculate_equipment_cost(double UA /*kWt/K*/, double T_hot_in /*K*/, double P_hot_in /*kPa*/, double m_dot_hot /*kg/s*/, - double T_cold_in /*K*/, double P_cold_in /*kPa*/, double m_dot_cold /*kg/s*/) + double T_cold_in /*K*/, double P_cold_in /*kPa*/, double m_dot_cold /*kg/s*/, + double f_inflation /**/) { switch (m_cost_model) { case C_HX_counterflow_CRM::E_CARLSON_17_RECUP: - return 1.25*1.E-3*UA; //[M$] needs UA in kWt/K + return 1.25*1.E-3*UA*f_inflation; //[M$] needs UA in kWt/K case C_HX_counterflow_CRM::E_WEILAND_19_RECUP: { double C_recup = 49.45 * std::pow(UA * 1.E3, 0.7544) * 1.E-6; //[M$] needs UA in Wt/K @@ -1800,10 +1801,10 @@ double /*M$*/ C_HX_counterflow_CRM::calculate_equipment_cost(double UA /*kWt/K*/ { T_factor = 1.0 + 0.02141 * (T_max_C - 550); } - return C_recup * T_factor; //[M$] + return C_recup * T_factor * f_inflation; //[M$] } case C_HX_counterflow_CRM::E_CARLSON_17_PHX: - return 3.5*1.E-3*UA; //[M$] needs UA in kWt/K + return 3.5*1.E-3*UA*f_inflation; //[M$] needs UA in kWt/K default: return std::numeric_limits::quiet_NaN(); } @@ -1869,7 +1870,8 @@ void C_HX_counterflow_CRM::design_calc_UA(C_HX_counterflow_CRM::S_des_calc_UA_pa ms_des_solved.m_cost_equipment = calculate_equipment_cost(ms_des_solved.m_UA_design, ms_des_calc_UA_par.m_T_h_in, ms_des_calc_UA_par.m_P_h_in, ms_des_calc_UA_par.m_m_dot_hot_des, - ms_des_calc_UA_par.m_T_c_in, ms_des_calc_UA_par.m_P_c_in, ms_des_calc_UA_par.m_m_dot_cold_des); + ms_des_calc_UA_par.m_T_c_in, ms_des_calc_UA_par.m_P_c_in, ms_des_calc_UA_par.m_m_dot_cold_des, + m_f_inflation); ms_des_solved.m_cost_bare_erected = calculate_bare_erected_cost(ms_des_solved.m_cost_equipment); @@ -1946,7 +1948,8 @@ void C_HX_counterflow_CRM::design_for_target__calc_outlet(int hx_target_code /*- ms_des_solved.m_cost_equipment = calculate_equipment_cost(ms_des_solved.m_UA_design, T_h_in, P_h_in, m_dot_h, - T_c_in, P_c_in, m_dot_c); + T_c_in, P_c_in, m_dot_c, + m_f_inflation); ms_des_solved.m_cost_bare_erected = calculate_bare_erected_cost(ms_des_solved.m_cost_equipment); } @@ -2560,7 +2563,8 @@ double NS_HX_counterflow_eqs::UA_scale_vs_m_dot(double m_dot_cold_over_des /*-*/ return pow(m_dot_ratio, 0.8); } -void C_HX_co2_to_co2_CRM::initialize(int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type) +void C_HX_co2_to_co2_CRM::initialize(int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type, + double f_inflation) { // Set design parameters member structure ms_init_par.m_N_sub_hx = N_sub_hx; @@ -2569,9 +2573,11 @@ void C_HX_co2_to_co2_CRM::initialize(int N_sub_hx, NS_HX_counterflow_eqs::E_UA_t m_is_HX_initialized = true; m_od_UA_target_type = od_UA_target_type; + m_f_inflation = f_inflation; } -void C_HX_co2_to_htf::initialize(int hot_fl, util::matrix_t hot_fl_props, int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type) +void C_HX_co2_to_htf::initialize(int hot_fl, util::matrix_t hot_fl_props, int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type, + double f_inflation) { // Hard-code some of the design parameters ms_init_par.m_N_sub_hx = N_sub_hx; //[-] @@ -2617,13 +2623,16 @@ void C_HX_co2_to_htf::initialize(int hot_fl, util::matrix_t hot_fl_props // Class is initialized m_is_HX_initialized = true; + m_f_inflation = f_inflation; + } -void C_HX_co2_to_htf::initialize(int hot_fl, int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type) +void C_HX_co2_to_htf::initialize(int hot_fl, int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type, + double f_inflation) { util::matrix_t null_fluid_props; - initialize(hot_fl, null_fluid_props, N_sub_hx, od_UA_target_type); + initialize(hot_fl, null_fluid_props, N_sub_hx, od_UA_target_type, f_inflation); } void C_HX_co2_to_htf::design_and_calc_m_dot_htf(C_HX_counterflow_CRM::S_des_calc_UA_par& des_par, @@ -2965,7 +2974,7 @@ bool C_CO2_to_air_cooler::design_hx(S_des_par_ind des_par_ind, S_des_par_cycle_d ms_hx_des_sol.m_W_dot_fan = ms_des_par_cycle_dep.m_W_dot_fan_des; //[MWe] ms_hx_des_sol.m_cost_equipment = calculate_equipment_cost(ms_hx_des_sol.m_UA_total*1.E-3, ms_hx_des_sol.m_V_total, - ms_hx_des_sol.m_T_in_co2, ms_hx_des_sol.m_P_in_co2, ms_hx_des_sol.m_m_dot_co2); //[M$] + ms_hx_des_sol.m_T_in_co2, ms_hx_des_sol.m_P_in_co2, ms_hx_des_sol.m_m_dot_co2, des_par_ind.m_f_inflation); //[M$] ms_hx_des_sol.m_cost_bare_erected = calculate_bare_erected_cost(ms_hx_des_sol.m_cost_equipment); @@ -3552,14 +3561,14 @@ int C_CO2_to_air_cooler::C_MEQ_target_T_hot__width_parallel::operator()(double W } double /*M$*/ C_CO2_to_air_cooler::calculate_equipment_cost(double UA /*kWt/K*/, double V_material /*m^3*/, - double T_hot_in /*K*/, double P_hot_in /*kPa*/, double m_dot_hot /*kg/s*/) + double T_hot_in /*K*/, double P_hot_in /*kPa*/, double m_dot_hot /*kg/s*/, double f_inflation/**/) { switch (m_cost_model) { case C_CO2_to_air_cooler::E_CARLSON_17: - return 2.3*1.E-3*UA; //[M$] needs UA in kWt/K + return 2.3*1.E-3*UA*f_inflation; //[M$] needs UA in kWt/K case C_CO2_to_air_cooler::E_WEILAND_19: - return 32.88*std::pow(UA*1.E3, 0.75)*1.E-6; //[M$] needs UA in Wt/K + return 32.88*std::pow(UA*1.E3, 0.75)*1.E-6*f_inflation; //[M$] needs UA in Wt/K default: return std::numeric_limits::quiet_NaN(); } diff --git a/tcs/heat_exchangers.h b/tcs/heat_exchangers.h index 2ea3c606c3..ebc8e30eda 100644 --- a/tcs/heat_exchangers.h +++ b/tcs/heat_exchangers.h @@ -478,6 +478,7 @@ class C_HX_counterflow_CRM int m_cost_model; //[-] int m_od_solution_type; //[-] + double m_f_inflation = 1.0; //[-] bool m_is_single_node_des_set; NS_HX_counterflow_eqs::S_hx_node_info ms_node_info_des; @@ -663,7 +664,8 @@ class C_HX_counterflow_CRM double calculate_equipment_cost(double UA /*kWt/K*/, double T_hot_in /*K*/, double P_hot_in /*kPa*/, double m_dot_hot /*kg/s*/, - double T_cold_in /*K*/, double P_cold_in /*kPa*/, double m_dot_cold /*kg/s*/); + double T_cold_in /*K*/, double P_cold_in /*kPa*/, double m_dot_cold /*kg/s*/, + double f_inflation /**/); double calculate_bare_erected_cost(double cost_equipment /*M$*/); @@ -751,9 +753,10 @@ class C_HX_co2_to_htf : public C_HX_counterflow_CRM void design_and_calc_m_dot_htf(C_HX_counterflow_CRM::S_des_calc_UA_par &des_par, double q_dot_design /*kWt*/, double dt_cold_approach /*C/K*/, C_HX_counterflow_CRM::S_des_solved &des_solved); - virtual void initialize(int hot_fl, util::matrix_t hot_fl_props, int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type); + virtual void initialize(int hot_fl, util::matrix_t hot_fl_props, int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type, + double f_inflation); - virtual void initialize(int hot_fl, int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type); + virtual void initialize(int hot_fl, int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type, double f_inflation); }; @@ -774,7 +777,8 @@ class C_HX_co2_to_co2_CRM : public C_HX_counterflow_CRM } - virtual void initialize(int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type); + virtual void initialize(int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type, + double f_inflation); }; namespace N_compact_hx @@ -820,10 +824,12 @@ class C_CO2_to_air_cooler double m_eta_fan; //[-] Fan isentropic efficiency int m_N_nodes_pass; //[-] Number of nodes per pass + double m_f_inflation; //[] Inflation factor S_des_par_ind() { - m_T_amb_des = m_elev = std::numeric_limits::quiet_NaN(); + m_T_amb_des = m_elev = m_f_inflation = + std::numeric_limits::quiet_NaN(); // Set realistic default values so model can solve without inputs for these values m_eta_fan = 0.5; @@ -1327,7 +1333,8 @@ class C_CO2_to_air_cooler double & k_air /*W/m-K*/, double & Pr_air); double /*M$*/ calculate_equipment_cost(double UA /*kWt/K*/, double V_material /*m^3*/, - double T_hot_in /*K*/, double P_hot_in /*kPa*/, double m_dot_hot /*kg/s*/); + double T_hot_in /*K*/, double P_hot_in /*kPa*/, double m_dot_hot /*kg/s*/, + double f_inflation /**/); double /*M$*/ calculate_bare_erected_cost(double cost_equipment /*M$*/); }; diff --git a/tcs/sco2_cycle_components.cpp b/tcs/sco2_cycle_components.cpp index c9aebc1bcb..cd526363ec 100644 --- a/tcs/sco2_cycle_components.cpp +++ b/tcs/sco2_cycle_components.cpp @@ -863,12 +863,12 @@ void C_HeatExchanger::hxr_conductance(const std::vector & m_dots, double } double C_turbine::calculate_equipment_cost(double T_in /*K*/, double P_in /*kPa*/, double m_dot /*kg/s*/, - double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/) + double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/, double f_inflation/**/) { switch (m_cost_model) { case C_turbine::E_CARLSON_17: - return 7.79*1.E-3*std::pow(W_dot, 0.6842); //[M$] needs power in kWe + return 7.79*1.E-3*std::pow(W_dot, 0.6842)*f_inflation; //[M$] needs power in kWe case C_turbine::E_WEILAND_19__AXIAL: { double base_cost = 182600 * std::pow(W_dot * 1.E-3, 0.5561); // [$] needs power in MWe @@ -879,7 +879,7 @@ double C_turbine::calculate_equipment_cost(double T_in /*K*/, double P_in /*kPa* cost_mult = 1.0 + ((1.106e-4) * std::pow(T_in_C - 550, 2.0)); } - return base_cost * cost_mult * 1e-6; //[M$] + return base_cost * cost_mult * 1e-6 * f_inflation; //[M$] } default: return std::numeric_limits::quiet_NaN(); @@ -964,7 +964,7 @@ void C_turbine::turbine_sizing(const S_design_parameters & des_par_in, int & err ms_des_solved.m_W_dot = ms_des_par.m_m_dot*(ms_des_par.m_h_in - ms_des_par.m_h_out); ms_des_solved.m_equipment_cost = calculate_equipment_cost(ms_des_par.m_T_in, ms_des_par.m_P_in, ms_des_par.m_m_dot, - T_out, ms_des_par.m_P_out, ms_des_solved.m_W_dot); + T_out, ms_des_par.m_P_out, ms_des_solved.m_W_dot, ms_des_par.m_f_inflation); ms_des_solved.m_bare_erected_cost = calculate_bare_erected_cost(ms_des_solved.m_equipment_cost); } @@ -1561,14 +1561,14 @@ int C_comp_multi_stage::C_MEQ_N_rpm__P_out::operator()(double N_rpm /*rpm*/, dou } double C_comp_multi_stage::calculate_equipment_cost(double T_in /*K*/, double P_in /*kPa*/, double m_dot /*kg/s*/, - double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/) + double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/, double f_inflation /**/) { switch (m_cost_model) { case C_comp_multi_stage::E_CARLSON_17: - return 6.898*1.E-3*std::pow(W_dot, 0.7865); //[M$] needs power in kWe + return 6.898*1.E-3*std::pow(W_dot, 0.7865)*f_inflation; //[M$] needs power in kWe case C_comp_multi_stage::E_WEILAND_19__IG: - return 1.23*std::pow(W_dot*1.E-3, 0.3992); //[M$] needs power in MWe + return 1.23*std::pow(W_dot*1.E-3, 0.3992)*f_inflation; //[M$] needs power in MWe default: return std::numeric_limits::quiet_NaN(); } @@ -1584,7 +1584,7 @@ double C_comp_multi_stage::calculate_bare_erected_cost(double cost_equipment /*M } int C_comp_multi_stage::design_given_outlet_state(int comp_model_code, double T_in /*K*/, double P_in /*kPa*/, double m_dot_cycle /*kg/s*/, - double T_out /*K*/, double P_out /*K*/, double tol /*-*/) + double T_out /*K*/, double P_out /*K*/, double tol /*-*/, double f_inflation /**/) { m_compressor_model = comp_model_code; //[-] @@ -1722,7 +1722,7 @@ int C_comp_multi_stage::design_given_outlet_state(int comp_model_code, double T_ } ms_des_solved.m_cost_equipment = calculate_equipment_cost(ms_des_solved.m_T_in, ms_des_solved.m_P_in, ms_des_solved.m_m_dot, - ms_des_solved.m_T_out, ms_des_solved.m_P_out, ms_des_solved.m_W_dot); + ms_des_solved.m_T_out, ms_des_solved.m_P_out, ms_des_solved.m_W_dot, f_inflation); ms_des_solved.m_cost_bare_erected = calculate_bare_erected_cost(ms_des_solved.m_cost_equipment); //[M$] diff --git a/tcs/sco2_cycle_components.h b/tcs/sco2_cycle_components.h index 5ca7df20c4..0a74221d52 100644 --- a/tcs/sco2_cycle_components.h +++ b/tcs/sco2_cycle_components.h @@ -164,11 +164,13 @@ class C_turbine // Mass flow rate double m_m_dot; //[kg/s] (cycle, not basis) + double m_f_inflation; //[] Inflation factor + S_design_parameters() { m_N_design = m_N_comp_design_if_linked = m_P_in = m_T_in = m_D_in = m_h_in = m_s_in = m_P_out = m_h_out = - m_m_dot = std::numeric_limits::quiet_NaN(); + m_m_dot = m_f_inflation = std::numeric_limits::quiet_NaN(); } }; @@ -248,7 +250,7 @@ class C_turbine } double calculate_equipment_cost(double T_in /*K*/, double P_in /*kPa*/, double m_dot /*kg/s*/, - double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/); + double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/, double f_inflation /**/); double /*M$*/ calculate_bare_erected_cost(double cost_equipment /*M$*/); @@ -661,12 +663,13 @@ class C_comp_multi_stage }; double calculate_equipment_cost(double T_in /*K*/, double P_in /*kPa*/, double m_dot /*kg/s*/, - double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/); + double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/, + double f_inflation /**/); double calculate_bare_erected_cost(double cost_equipment /*M$*/); int design_given_outlet_state(int comp_model_code, double T_in /*K*/, double P_in /*kPa*/, double m_dot /*kg/s*/, - double T_out /*K*/, double P_out /*K*/, double tol /*-*/); + double T_out /*K*/, double P_out /*K*/, double tol /*-*/, double f_inflation /**/); void off_design_given_N(double T_in /*K*/, double P_in /*kPa*/, double m_dot_cycle /*kg/s*/, double N_rpm /*rpm*/, int & error_code, double & T_out /*K*/, double & P_out /*kPa*/); diff --git a/tcs/sco2_cycle_templates.h b/tcs/sco2_cycle_templates.h index 8113ae4707..a20d408648 100644 --- a/tcs/sco2_cycle_templates.h +++ b/tcs/sco2_cycle_templates.h @@ -475,7 +475,7 @@ class C_sco2_cycle_core double m_T_amb_des; //[K] Design point ambient temperature double m_elevation; //[m] Elevation (used to calculate ambient pressure) int m_N_nodes_pass; //[-] Number of nodes per pass - + double m_f_inflation; //[] Inflation factor public: @@ -492,7 +492,8 @@ class C_sco2_cycle_core double eta_t /*-*/, double N_turbine /*rpm*/, double frac_fan_power /*-*/, double eta_fan /*-*/, double deltaP_cooler_frac /*-*/, int N_nodes_pass /*-*/, - double T_amb_des /*K*/, double elevation /*m*/) + double T_amb_des /*K*/, double elevation /*m*/, + double f_inflation /**/) { m_turbo_gen_motor_config = turbo_gen_motor_config; m_eta_generator = eta_generator; //[-] @@ -525,6 +526,8 @@ class C_sco2_cycle_core m_T_amb_des = T_amb_des; //[K] m_elevation = elevation; //[m] + m_f_inflation = f_inflation; //[] + // Set design limits!!!! ms_des_limits.m_UA_net_power_ratio_max = 2.0; //[-/K] ms_des_limits.m_UA_net_power_ratio_min = 1.E-5; //[-/K] diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index d6c84f8e5f..5b4c6996af 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -61,9 +61,9 @@ int C_sco2_htrbp_core::solve() // Initialize Recuperators { // LTR - m_outputs.mc_LT_recup.initialize(m_inputs.m_LTR_N_sub_hxrs, m_inputs.m_LTR_od_UA_target_type); + m_outputs.mc_LT_recup.initialize(m_inputs.m_LTR_N_sub_hxrs, m_inputs.m_LTR_od_UA_target_type, m_inputs.m_f_inflation); // HTR - m_outputs.mc_HT_recup.initialize(m_inputs.m_HTR_N_sub_hxrs, m_inputs.m_HTR_od_UA_target_type); + m_outputs.mc_HT_recup.initialize(m_inputs.m_HTR_N_sub_hxrs, m_inputs.m_HTR_od_UA_target_type, m_inputs.m_f_inflation); } // Initialize a few variables @@ -489,7 +489,8 @@ int C_sco2_htrbp_core::finalize_design(C_sco2_cycle_core::S_design_solved& desig m_outputs.m_m_dot_mc, m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], - m_inputs.m_des_tol); + m_inputs.m_des_tol, + m_inputs.m_f_inflation); if (mc_design_err != 0) { @@ -506,7 +507,8 @@ int C_sco2_htrbp_core::finalize_design(C_sco2_cycle_core::S_design_solved& desig m_outputs.m_m_dot_rc, m_outputs.m_temp[C_sco2_cycle_core::RC_OUT], m_outputs.m_pres[C_sco2_cycle_core::RC_OUT], - m_inputs.m_des_tol); + m_inputs.m_des_tol, + m_inputs.m_f_inflation); if (rc_des_err != 0) { @@ -538,6 +540,9 @@ int C_sco2_htrbp_core::finalize_design(C_sco2_cycle_core::S_design_solved& desig t_des_par.m_h_out = m_outputs.m_enth[C_sco2_cycle_core::TURB_OUT]; // Mass flow t_des_par.m_m_dot = m_outputs.m_m_dot_t; + // Inflation factor + t_des_par.m_f_inflation = m_inputs.m_f_inflation; + int turb_size_error_code = 0; m_outputs.m_t.turbine_sizing(t_des_par, turb_size_error_code); @@ -573,6 +578,7 @@ int C_sco2_htrbp_core::finalize_design(C_sco2_cycle_core::S_design_solved& desig s_air_cooler_des_par_ind.m_elev = m_inputs.m_elevation; // [m] s_air_cooler_des_par_ind.m_eta_fan = m_inputs.m_eta_fan; // [-] s_air_cooler_des_par_ind.m_N_nodes_pass = m_inputs.m_N_nodes_pass; // [-] + s_air_cooler_des_par_ind.m_f_inflation = m_inputs.m_f_inflation; // [-] if (m_inputs.m_is_des_air_cooler && std::isfinite(m_inputs.m_deltaP_cooler_frac) && std::isfinite(m_inputs.m_frac_fan_power) && std::isfinite(m_inputs.m_T_amb_des) && std::isfinite(m_inputs.m_elevation) && std::isfinite(m_inputs.m_eta_fan) && m_inputs.m_N_nodes_pass > 0) @@ -1185,6 +1191,7 @@ int C_HTRBypass_Cycle::optimize_bp(const S_auto_opt_design_parameters& auto_par, core_inputs.m_N_turbine = m_N_turbine; // Comes from constructor (constant) core_inputs.m_rc_comp_model_code = C_comp__psi_eta_vs_phi::E_snl_radial_via_Dyreby; // Constant + core_inputs.m_f_inflation = m_f_inflation; // Comes from constructor (constant) // From special bypass fraction function (should remove) core_inputs.m_dT_BP = m_dT_BP; // Comes from bp par function (constant) diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index c9820f29d1..49d57faca6 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -112,6 +112,7 @@ class C_sco2_htrbp_core int m_mc_comp_model_code; // Main compressor model code int m_rc_comp_model_code; // Recompressor model code int m_N_turbine; //[rpm] Turbine rpm + double m_f_inflation; //[] Inflation factor S_sco2_htrbp_in() { @@ -138,6 +139,7 @@ class C_sco2_htrbp_core m_elevation = m_dT_BP = m_HTF_PHX_cold_approach_input = + m_f_inflation = std::numeric_limits::quiet_NaN(); m_N_nodes_pass = 0; @@ -394,7 +396,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double eta_t, double N_turbine, double frac_fan_power, double eta_fan, double deltaP_cooler_frac, int N_nodes_pass, - double T_amb_des, double elevation) : + double T_amb_des, double elevation, + double f_inflation) : C_sco2_cycle_core(turbo_gen_motor_config, eta_generator, T_mc_in, @@ -408,7 +411,8 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core eta_t, N_turbine, frac_fan_power, eta_fan, deltaP_cooler_frac, N_nodes_pass, - T_amb_des, elevation) + T_amb_des, elevation, + f_inflation) { m_T_target = m_T_HTF_PHX_inlet = m_set_HTF_mdot = m_HTF_PHX_cold_approach = m_dT_BP diff --git a/tcs/sco2_partialcooling_cycle.cpp b/tcs/sco2_partialcooling_cycle.cpp index c5af391495..1d6c27eaf7 100644 --- a/tcs/sco2_partialcooling_cycle.cpp +++ b/tcs/sco2_partialcooling_cycle.cpp @@ -63,8 +63,8 @@ int C_PartialCooling_Cycle::design_core() } // Initialize Recuperators - mc_LTR.initialize(m_LTR_N_sub_hxrs, ms_des_par.m_LTR_od_UA_target_type); - mc_HTR.initialize(m_HTR_N_sub_hxrs, ms_des_par.m_HTR_od_UA_target_type); + mc_LTR.initialize(m_LTR_N_sub_hxrs, ms_des_par.m_LTR_od_UA_target_type, m_f_inflation); + mc_HTR.initialize(m_HTR_N_sub_hxrs, ms_des_par.m_HTR_od_UA_target_type, m_f_inflation); // Initialize known temps and pressures from design parameters m_temp_last[MC_IN] = m_T_mc_in; //[K] @@ -533,7 +533,8 @@ int C_PartialCooling_Cycle::finalize_design() m_pres_last[MC_IN], m_m_dot_mc, m_temp_last[MC_OUT], - m_pres_last[MC_OUT], ms_des_par.m_des_tol); + m_pres_last[MC_OUT], ms_des_par.m_des_tol, + m_f_inflation); if (mc_des_err != 0) { @@ -544,7 +545,8 @@ int C_PartialCooling_Cycle::finalize_design() m_pres_last[PC_IN], m_m_dot_pc, m_temp_last[PC_OUT], - m_pres_last[PC_OUT], ms_des_par.m_des_tol); + m_pres_last[PC_OUT], ms_des_par.m_des_tol, + m_f_inflation); if (pc_des_err != 0) { @@ -557,7 +559,8 @@ int C_PartialCooling_Cycle::finalize_design() m_pres_last[PC_OUT], m_m_dot_rc, m_temp_last[RC_OUT], - m_pres_last[RC_OUT], ms_des_par.m_des_tol); + m_pres_last[RC_OUT], ms_des_par.m_des_tol, + m_f_inflation); if (rc_des_err != 0) { @@ -584,6 +587,7 @@ int C_PartialCooling_Cycle::finalize_design() t_des_par.m_h_out = m_enth_last[TURB_OUT]; //[kJ/kg] // Mass flow t_des_par.m_m_dot = m_m_dot_t; //[kg/s] + t_des_par.m_f_inflation = m_f_inflation; int turb_size_err = 0; mc_t.turbine_sizing(t_des_par, turb_size_err); @@ -621,6 +625,7 @@ int C_PartialCooling_Cycle::finalize_design() s_LP_air_cooler_des_par_ind.m_elev = m_elevation; //[m] s_LP_air_cooler_des_par_ind.m_eta_fan = m_eta_fan; //[-] s_LP_air_cooler_des_par_ind.m_N_nodes_pass = m_N_nodes_pass; //[-] + s_LP_air_cooler_des_par_ind.m_f_inflation = m_f_inflation; //[] if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) @@ -659,6 +664,7 @@ int C_PartialCooling_Cycle::finalize_design() s_IP_air_cooler_des_par_ind.m_elev = m_elevation; //[m] s_IP_air_cooler_des_par_ind.m_eta_fan = m_eta_fan; //[-] s_IP_air_cooler_des_par_ind.m_N_nodes_pass = m_N_nodes_pass; //[-] + s_IP_air_cooler_des_par_ind.m_f_inflation = m_f_inflation; //[] if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) diff --git a/tcs/sco2_partialcooling_cycle.h b/tcs/sco2_partialcooling_cycle.h index 2636cb7992..c4fca1b6b2 100644 --- a/tcs/sco2_partialcooling_cycle.h +++ b/tcs/sco2_partialcooling_cycle.h @@ -270,7 +270,8 @@ class C_PartialCooling_Cycle : public C_sco2_cycle_core double eta_t /*-*/, double N_turbine /*rpm*/, double frac_fan_power /*-*/, double eta_fan /*-*/, double deltaP_cooler_frac /*-*/, int N_nodes_pass /*-*/, - double T_amb_des /*K*/, double elevation /*m*/) : + double T_amb_des /*K*/, double elevation /*m*/, + double f_inflation /**/) : C_sco2_cycle_core(turbo_gen_motor_config, eta_generator, T_mc_in, @@ -284,7 +285,8 @@ class C_PartialCooling_Cycle : public C_sco2_cycle_core eta_t, N_turbine, frac_fan_power, eta_fan, deltaP_cooler_frac, N_nodes_pass, - T_amb_des, elevation) + T_amb_des, elevation, + f_inflation) { m_temp_last.resize(END_SCO2_STATES); std::fill(m_temp_last.begin(), m_temp_last.end(), std::numeric_limits::quiet_NaN()); diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index db79b2196f..07b9a23b89 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -122,7 +122,8 @@ int C_sco2_phx_air_cooler::design_core() ms_des_par.m_eta_t, ms_des_par.m_N_turbine, ms_des_par.m_frac_fan_power, ms_des_par.m_eta_fan, ms_des_par.m_deltaP_cooler_frac, ms_des_par.m_N_nodes_pass, - ms_des_par.m_T_amb_des, ms_des_par.m_elevation)); + ms_des_par.m_T_amb_des, ms_des_par.m_elevation, + ms_des_par.m_f_inflation)); s_cycle_config = "partial cooling"; @@ -144,7 +145,8 @@ int C_sco2_phx_air_cooler::design_core() ms_des_par.m_eta_t, ms_des_par.m_N_turbine, ms_des_par.m_frac_fan_power, ms_des_par.m_eta_fan, ms_des_par.m_deltaP_cooler_frac, ms_des_par.m_N_nodes_pass, - ms_des_par.m_T_amb_des, ms_des_par.m_elevation)); + ms_des_par.m_T_amb_des, ms_des_par.m_elevation, + ms_des_par.m_f_inflation)); s_cycle_config = "htr bypass"; @@ -216,7 +218,8 @@ int C_sco2_phx_air_cooler::design_core() ms_des_par.m_N_turbine, ms_des_par.m_frac_fan_power, ms_des_par.m_eta_fan, ms_des_par.m_deltaP_cooler_frac, ms_des_par.m_N_nodes_pass, - ms_des_par.m_T_amb_des, ms_des_par.m_elevation)); + ms_des_par.m_T_amb_des, ms_des_par.m_elevation, + ms_des_par.m_f_inflation)); s_cycle_config = "turbine split flow"; @@ -239,7 +242,8 @@ int C_sco2_phx_air_cooler::design_core() ms_des_par.m_eta_t, ms_des_par.m_N_turbine, ms_des_par.m_frac_fan_power, ms_des_par.m_eta_fan, ms_des_par.m_deltaP_cooler_frac, ms_des_par.m_N_nodes_pass, - ms_des_par.m_T_amb_des, ms_des_par.m_elevation)); + ms_des_par.m_T_amb_des, ms_des_par.m_elevation, + ms_des_par.m_f_inflation)); s_cycle_config = "recompression"; @@ -405,7 +409,8 @@ int C_sco2_phx_air_cooler::design_core() ms_des_solved.ms_rc_cycle_solved = *mpc_sco2_cycle->get_design_solved(); // Initialize the PHX - mc_phx.initialize(ms_des_par.m_hot_fl_code, ms_des_par.mc_hot_fl_props, ms_des_par.m_phx_N_sub_hx, ms_des_par.m_phx_od_UA_target_type); + mc_phx.initialize(ms_des_par.m_hot_fl_code, ms_des_par.mc_hot_fl_props, ms_des_par.m_phx_N_sub_hx, + ms_des_par.m_phx_od_UA_target_type, ms_des_par.m_f_inflation); // Define state enumerable for sco2 into PHX int phx_cold_inlet_state = C_sco2_cycle_core::HTR_HP_OUT; @@ -452,7 +457,8 @@ int C_sco2_phx_air_cooler::design_core() int bp_N_subs_hx = ms_des_par.m_phx_N_sub_hx; auto bp_od_UA_target_type = ms_des_par.m_phx_od_UA_target_type; - mc_bp.initialize(ms_des_par.m_hot_fl_code, ms_des_par.mc_hot_fl_props, bp_N_subs_hx, bp_od_UA_target_type); + mc_bp.initialize(ms_des_par.m_hot_fl_code, ms_des_par.mc_hot_fl_props, bp_N_subs_hx, bp_od_UA_target_type, + ms_des_par.m_f_inflation); // Calculate BP heat transfer double m_dot_bp_sco2 = ms_des_solved.ms_rc_cycle_solved.m_bypass_frac * (ms_des_solved.ms_rc_cycle_solved.m_m_dot_t); diff --git a/tcs/sco2_pc_csp_int.h b/tcs/sco2_pc_csp_int.h index 4dbd8e4b59..89494acd08 100644 --- a/tcs/sco2_pc_csp_int.h +++ b/tcs/sco2_pc_csp_int.h @@ -135,7 +135,8 @@ class C_sco2_phx_air_cooler double m_deltaT_bypass; // [delta K] sco2 Bypass Outlet Temp - HTR_HP_OUT Temp double m_set_HTF_mdot; // [kg/s] For HTR Bypass ONLY, 0 = calculate HTF mdot (need to set dT_PHX_cold_approach), > 0 = HTF mdot kg/s - + // Inflation Factor + double m_f_inflation; // [] Inflation factor S_des_par() { @@ -174,6 +175,7 @@ class C_sco2_phx_air_cooler m_PR_HP_to_LP_guess = m_f_PR_HP_to_IP_guess = m_phx_dt_cold_approach = m_frac_fan_power = m_deltaP_cooler_frac = m_eta_fan = + m_f_inflation = std::numeric_limits::quiet_NaN(); m_fixed_P_mc_out = false; //[-] If false, then should default to optimizing this parameter diff --git a/tcs/sco2_recompression_cycle.cpp b/tcs/sco2_recompression_cycle.cpp index b4f5b70a18..abfc3aa0cd 100644 --- a/tcs/sco2_recompression_cycle.cpp +++ b/tcs/sco2_recompression_cycle.cpp @@ -1851,9 +1851,9 @@ void C_RecompCycle::design_core_standard(int & error_code) // Initialize Recuperators // LTR - mc_LT_recup.initialize(m_LTR_N_sub_hxrs, ms_des_par.m_LTR_od_UA_target_type); + mc_LT_recup.initialize(m_LTR_N_sub_hxrs, ms_des_par.m_LTR_od_UA_target_type, m_f_inflation); // HTR - mc_HT_recup.initialize(m_HTR_N_sub_hxrs, ms_des_par.m_HTR_od_UA_target_type); + mc_HT_recup.initialize(m_HTR_N_sub_hxrs, ms_des_par.m_HTR_od_UA_target_type, m_f_inflation); // Initialize a few variables double m_dot_t, m_dot_mc, m_dot_rc, Q_dot_LT, Q_dot_HT, UA_LT_calc, UA_HT_calc; @@ -3350,7 +3350,8 @@ void C_RecompCycle::finalize_design(int & error_code) m_m_dot_mc, m_temp_last[MC_OUT], m_pres_last[MC_OUT], - ms_des_par.m_des_tol); + ms_des_par.m_des_tol, + m_f_inflation); if (mc_design_err != 0) { @@ -3364,7 +3365,8 @@ void C_RecompCycle::finalize_design(int & error_code) m_pres_last[LTR_LP_OUT], m_m_dot_rc, m_temp_last[RC_OUT], - m_pres_last[RC_OUT], ms_des_par.m_des_tol); + m_pres_last[RC_OUT], ms_des_par.m_des_tol, + m_f_inflation); if (rc_des_err != 0) { @@ -3393,6 +3395,8 @@ void C_RecompCycle::finalize_design(int & error_code) t_des_par.m_h_out = m_enth_last[7-cpp_offset]; // Mass flow t_des_par.m_m_dot = m_m_dot_t; + // Inflation factor + t_des_par.m_f_inflation = m_f_inflation; int turb_size_error_code = 0; m_t.turbine_sizing(t_des_par, turb_size_error_code); @@ -3426,6 +3430,7 @@ void C_RecompCycle::finalize_design(int & error_code) s_air_cooler_des_par_ind.m_elev = m_elevation; //[m] s_air_cooler_des_par_ind.m_eta_fan = m_eta_fan; //[-] s_air_cooler_des_par_ind.m_N_nodes_pass = m_N_nodes_pass; //[-] + s_air_cooler_des_par_ind.m_f_inflation = m_f_inflation; //[] if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) diff --git a/tcs/sco2_recompression_cycle.h b/tcs/sco2_recompression_cycle.h index d3c691d2c9..9101e59084 100644 --- a/tcs/sco2_recompression_cycle.h +++ b/tcs/sco2_recompression_cycle.h @@ -496,7 +496,8 @@ class C_RecompCycle : public C_sco2_cycle_core double eta_t /*-*/, double N_turbine /*rpm*/, double frac_fan_power /*-*/, double eta_fan /*-*/, double deltaP_cooler_frac /*-*/, int N_nodes_pass /*-*/, - double T_amb_des /*K*/, double elevation /*m*/) : + double T_amb_des /*K*/, double elevation /*m*/, + double f_inflation /**/) : C_sco2_cycle_core(turbo_gen_motor_config, eta_generator, T_mc_in, @@ -510,7 +511,8 @@ class C_RecompCycle : public C_sco2_cycle_core eta_t, N_turbine, frac_fan_power, eta_fan, deltaP_cooler_frac, N_nodes_pass, - T_amb_des, elevation) + T_amb_des, elevation, + f_inflation) { m_temp_last.resize(END_SCO2_STATES); std::fill(m_temp_last.begin(), m_temp_last.end(), std::numeric_limits::quiet_NaN()); diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp index b1bf9d1c28..783642f729 100644 --- a/tcs/sco2_turbinesplitflow_cycle.cpp +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -61,9 +61,9 @@ int C_sco2_tsf_core::solve() // Initialize Recuperators { // LTR - m_outputs.mc_LT_recup.initialize(m_inputs.m_LTR_N_sub_hxrs, m_inputs.m_LTR_od_UA_target_type); + m_outputs.mc_LT_recup.initialize(m_inputs.m_LTR_N_sub_hxrs, m_inputs.m_LTR_od_UA_target_type, m_inputs.m_f_inflation); // HTR - m_outputs.mc_HT_recup.initialize(m_inputs.m_HTR_N_sub_hxrs, m_inputs.m_HTR_od_UA_target_type); + m_outputs.mc_HT_recup.initialize(m_inputs.m_HTR_N_sub_hxrs, m_inputs.m_HTR_od_UA_target_type, m_inputs.m_f_inflation); } // Initialize a few variables @@ -388,7 +388,8 @@ int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_ m_outputs.m_m_dot_mc, m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], - m_inputs.m_des_tol); + m_inputs.m_des_tol, + m_inputs.m_f_inflation); if (mc_design_err != 0) { @@ -414,6 +415,8 @@ int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_ t_des_par.m_h_out = m_outputs.m_enth[C_sco2_cycle_core::TURB_OUT]; // Mass flow t_des_par.m_m_dot = m_outputs.m_m_dot_t; + // Inflation factor + t_des_par.m_f_inflation = m_inputs.m_f_inflation; int turb_size_error_code = 0; m_outputs.m_t.turbine_sizing(t_des_par, turb_size_error_code); @@ -442,6 +445,8 @@ int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_ t2_des_par.m_h_out = m_outputs.m_enth[C_sco2_cycle_core::TURB2_OUT]; // Mass flow t2_des_par.m_m_dot = m_outputs.m_m_dot_t2; + // Inflation factor + t2_des_par.m_f_inflation = m_inputs.m_f_inflation; int turb_size_error_code = 0; m_outputs.m_t2.turbine_sizing(t2_des_par, turb_size_error_code); @@ -477,7 +482,8 @@ int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_ s_air_cooler_des_par_ind.m_elev = m_inputs.m_elevation; // [m] s_air_cooler_des_par_ind.m_eta_fan = m_inputs.m_eta_fan; // [-] s_air_cooler_des_par_ind.m_N_nodes_pass = m_inputs.m_N_nodes_pass; // [-] - + s_air_cooler_des_par_ind.m_f_inflation = m_inputs.m_f_inflation; // [-] + if (m_inputs.m_is_des_air_cooler && std::isfinite(m_inputs.m_deltaP_cooler_frac) && std::isfinite(m_inputs.m_frac_fan_power) && std::isfinite(m_inputs.m_T_amb_des) && std::isfinite(m_inputs.m_elevation) && std::isfinite(m_inputs.m_eta_fan) && m_inputs.m_N_nodes_pass > 0) { @@ -777,7 +783,7 @@ int C_TurbineSplitFlow_Cycle::optimize_par(const S_auto_opt_design_parameters& a core_inputs.m_N_nodes_pass = m_N_nodes_pass; // Comes from constructor (constant) core_inputs.m_mc_comp_model_code = m_mc_comp_model_code; // Comes from constructor (constant) core_inputs.m_N_turbine = m_N_turbine; // Comes from constructor (constant) - + core_inputs.m_f_inflation = m_f_inflation; // Comes from constructor (constant) // Handle design variables (check if fixed or free) { diff --git a/tcs/sco2_turbinesplitflow_cycle.h b/tcs/sco2_turbinesplitflow_cycle.h index 37a3f8d9e4..8c2101677d 100644 --- a/tcs/sco2_turbinesplitflow_cycle.h +++ b/tcs/sco2_turbinesplitflow_cycle.h @@ -105,6 +105,8 @@ class C_sco2_tsf_core int m_mc_comp_model_code; // Main compressor model code int m_N_turbine; //[rpm] Turbine rpm + double m_f_inflation; //[] Inflation factor + S_sco2_tsf_in() { m_P_mc_in = m_P_mc_out = @@ -124,6 +126,7 @@ class C_sco2_tsf_core m_deltaP_cooler_frac = m_T_amb_des = m_elevation = + m_f_inflation = std::numeric_limits::quiet_NaN(); m_N_nodes_pass = 0; @@ -336,7 +339,8 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core double N_turbine, double frac_fan_power, double eta_fan, double deltaP_cooler_frac, int N_nodes_pass, - double T_amb_des, double elevation) : + double T_amb_des, double elevation, + double f_inflation) : C_sco2_cycle_core(turbo_gen_motor_config, eta_generator, T_mc_in, @@ -350,8 +354,8 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core eta_t, N_turbine, frac_fan_power, eta_fan, deltaP_cooler_frac, N_nodes_pass, - T_amb_des, elevation), - m_eta_t2(eta_t2) + T_amb_des, elevation, f_inflation), + m_eta_t2(eta_t2) { m_opt_iteration_count = 0; } From 5fb73008f22e4e99541804afb6248587097b7c51 Mon Sep 17 00:00:00 2001 From: tyneises Date: Mon, 10 Feb 2025 11:33:32 -0600 Subject: [PATCH 74/94] update sco2 test results for new sco2 cost correlations --- test/ssc_test/cmod_sco2_csp_system_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ssc_test/cmod_sco2_csp_system_test.cpp b/test/ssc_test/cmod_sco2_csp_system_test.cpp index 68b0797019..8ea56a3c7a 100644 --- a/test/ssc_test/cmod_sco2_csp_system_test.cpp +++ b/test/ssc_test/cmod_sco2_csp_system_test.cpp @@ -119,7 +119,7 @@ NAMESPACE_TEST(sco2_tests, SCO2Cycle, Parametrics) EXPECT_NEAR_FRAC(sco2.GetOutput("m_dot_htf_des"), 513.344, kErrorToleranceLo); EXPECT_NEAR_FRAC(sco2.GetOutput("m_dot_co2_full"), 410.528, kErrorToleranceLo); EXPECT_NEAR_FRAC(sco2.GetOutput("P_comp_in"), 7.67490, kErrorToleranceLo); - EXPECT_NEAR_FRAC(sco2.GetOutput("cycle_cost"), 53.2909, kErrorToleranceLo); + EXPECT_NEAR_FRAC(sco2.GetOutput("cycle_cost"), 61.122, kErrorToleranceLo); std::vector eta_thermal_od_exp{ 0.50689, 0.507197 }; EXPECT_FLOATS_NEARLY_EQ(sco2.GetOutputVector("eta_thermal_od"), eta_thermal_od_exp, kErrorToleranceLo*eta_thermal_od_exp[0]); From 3e253299ca2bb13f6107c667eca09f8c15b69595 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Mon, 10 Feb 2025 12:15:43 -0700 Subject: [PATCH 75/94] Change inflation factor input to inflation year. --- ssc/csp_common.cpp | 6 ++-- tcs/heat_exchangers.cpp | 52 ++++++++++++++++++++--------- tcs/heat_exchangers.h | 16 ++++----- tcs/sco2_cycle_components.cpp | 45 ++++++++++++++++++++----- tcs/sco2_cycle_components.h | 12 ++++--- tcs/sco2_cycle_templates.h | 6 ++-- tcs/sco2_htrbypass_cycle.cpp | 16 ++++----- tcs/sco2_htrbypass_cycle.h | 8 ++--- tcs/sco2_partialcooling_cycle.cpp | 16 ++++----- tcs/sco2_partialcooling_cycle.h | 4 +-- tcs/sco2_pc_csp_int.cpp | 12 +++---- tcs/sco2_pc_csp_int.h | 6 ++-- tcs/sco2_recompression_cycle.cpp | 14 ++++---- tcs/sco2_recompression_cycle.h | 4 +-- tcs/sco2_turbinesplitflow_cycle.cpp | 18 +++++----- tcs/sco2_turbinesplitflow_cycle.h | 8 ++--- 16 files changed, 147 insertions(+), 96 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 8ba542d8c1..c4f0dc570b 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -824,7 +824,7 @@ var_info vtab_sco2_design[] = { { SSC_INPUT, SSC_NUMBER, "eta_isen_t2", "Design secondary turbine isentropic efficiency (TSF only)", "-", "", "", "cycle_config=4", "", "" }, // Cost Inputs - { SSC_INPUT, SSC_NUMBER, "f_inflation", "Inflation factor", "", "", "System Design", "?=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "yr_inflation", "Inflation target year", "yr", "", "System Design", "?=0", "", "" }, // DEBUG @@ -1309,8 +1309,8 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c s_sco2_des_par.m_eta_t2 = s_sco2_des_par.m_eta_t; } - // Inflation factor - s_sco2_des_par.m_f_inflation = cm->as_double("f_inflation"); //[-] + // Inflation target year + s_sco2_des_par.m_yr_inflation = cm->as_double("yr_inflation"); //[yr] // For try/catch below int out_type = -1; diff --git a/tcs/heat_exchangers.cpp b/tcs/heat_exchangers.cpp index 3d0476822a..46b3be8a8e 100644 --- a/tcs/heat_exchangers.cpp +++ b/tcs/heat_exchangers.cpp @@ -35,6 +35,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "sam_csp_util.h" #include #include "numeric_solvers.h" +#include "sco2_cycle_components.h" double NS_HX_counterflow_eqs::calc_max_q_dot_enth(int hot_fl_code /*-*/, HTFProperties & hot_htf_class, int cold_fl_code /*-*/, HTFProperties & cold_htf_class, @@ -1786,12 +1787,16 @@ double C_HX_counterflow_CRM::calc_max_q_dot_enth(double h_h_in /*kJ/kg*/, double double /*M$*/ C_HX_counterflow_CRM::calculate_equipment_cost(double UA /*kWt/K*/, double T_hot_in /*K*/, double P_hot_in /*kPa*/, double m_dot_hot /*kg/s*/, double T_cold_in /*K*/, double P_cold_in /*kPa*/, double m_dot_cold /*kg/s*/, - double f_inflation /**/) + double yr_inflation /*yr*/) { switch (m_cost_model) { case C_HX_counterflow_CRM::E_CARLSON_17_RECUP: - return 1.25*1.E-3*UA*f_inflation; //[M$] needs UA in kWt/K + { + double yr_base_inflation = 2017; + double f_inflation = calculate_inflation_factor(yr_base_inflation, yr_inflation); + return 1.25 * 1.E-3 * UA * f_inflation; //[M$] needs UA in kWt/K + } case C_HX_counterflow_CRM::E_WEILAND_19_RECUP: { double C_recup = 49.45 * std::pow(UA * 1.E3, 0.7544) * 1.E-6; //[M$] needs UA in Wt/K @@ -1801,10 +1806,17 @@ double /*M$*/ C_HX_counterflow_CRM::calculate_equipment_cost(double UA /*kWt/K*/ { T_factor = 1.0 + 0.02141 * (T_max_C - 550); } + double yr_base_inflation = 2017; + double f_inflation = calculate_inflation_factor(yr_base_inflation, yr_inflation); return C_recup * T_factor * f_inflation; //[M$] + break; } case C_HX_counterflow_CRM::E_CARLSON_17_PHX: - return 3.5*1.E-3*UA*f_inflation; //[M$] needs UA in kWt/K + { + double yr_base_inflation = 2017; + double f_inflation = calculate_inflation_factor(yr_base_inflation, yr_inflation); + return 3.5 * 1.E-3 * UA * f_inflation; //[M$] needs UA in kWt/K + } default: return std::numeric_limits::quiet_NaN(); } @@ -1871,7 +1883,7 @@ void C_HX_counterflow_CRM::design_calc_UA(C_HX_counterflow_CRM::S_des_calc_UA_pa ms_des_solved.m_cost_equipment = calculate_equipment_cost(ms_des_solved.m_UA_design, ms_des_calc_UA_par.m_T_h_in, ms_des_calc_UA_par.m_P_h_in, ms_des_calc_UA_par.m_m_dot_hot_des, ms_des_calc_UA_par.m_T_c_in, ms_des_calc_UA_par.m_P_c_in, ms_des_calc_UA_par.m_m_dot_cold_des, - m_f_inflation); + m_yr_inflation); ms_des_solved.m_cost_bare_erected = calculate_bare_erected_cost(ms_des_solved.m_cost_equipment); @@ -1949,7 +1961,7 @@ void C_HX_counterflow_CRM::design_for_target__calc_outlet(int hx_target_code /*- ms_des_solved.m_cost_equipment = calculate_equipment_cost(ms_des_solved.m_UA_design, T_h_in, P_h_in, m_dot_h, T_c_in, P_c_in, m_dot_c, - m_f_inflation); + m_yr_inflation); ms_des_solved.m_cost_bare_erected = calculate_bare_erected_cost(ms_des_solved.m_cost_equipment); } @@ -2564,7 +2576,7 @@ double NS_HX_counterflow_eqs::UA_scale_vs_m_dot(double m_dot_cold_over_des /*-*/ } void C_HX_co2_to_co2_CRM::initialize(int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type, - double f_inflation) + double yr_inflation) { // Set design parameters member structure ms_init_par.m_N_sub_hx = N_sub_hx; @@ -2573,11 +2585,11 @@ void C_HX_co2_to_co2_CRM::initialize(int N_sub_hx, NS_HX_counterflow_eqs::E_UA_t m_is_HX_initialized = true; m_od_UA_target_type = od_UA_target_type; - m_f_inflation = f_inflation; + m_yr_inflation = yr_inflation; } void C_HX_co2_to_htf::initialize(int hot_fl, util::matrix_t hot_fl_props, int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type, - double f_inflation) + double yr_inflation) { // Hard-code some of the design parameters ms_init_par.m_N_sub_hx = N_sub_hx; //[-] @@ -2623,16 +2635,16 @@ void C_HX_co2_to_htf::initialize(int hot_fl, util::matrix_t hot_fl_props // Class is initialized m_is_HX_initialized = true; - m_f_inflation = f_inflation; + m_yr_inflation = yr_inflation; } void C_HX_co2_to_htf::initialize(int hot_fl, int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type, - double f_inflation) + double yr_inflation) { util::matrix_t null_fluid_props; - initialize(hot_fl, null_fluid_props, N_sub_hx, od_UA_target_type, f_inflation); + initialize(hot_fl, null_fluid_props, N_sub_hx, od_UA_target_type, yr_inflation); } void C_HX_co2_to_htf::design_and_calc_m_dot_htf(C_HX_counterflow_CRM::S_des_calc_UA_par& des_par, @@ -2974,7 +2986,7 @@ bool C_CO2_to_air_cooler::design_hx(S_des_par_ind des_par_ind, S_des_par_cycle_d ms_hx_des_sol.m_W_dot_fan = ms_des_par_cycle_dep.m_W_dot_fan_des; //[MWe] ms_hx_des_sol.m_cost_equipment = calculate_equipment_cost(ms_hx_des_sol.m_UA_total*1.E-3, ms_hx_des_sol.m_V_total, - ms_hx_des_sol.m_T_in_co2, ms_hx_des_sol.m_P_in_co2, ms_hx_des_sol.m_m_dot_co2, des_par_ind.m_f_inflation); //[M$] + ms_hx_des_sol.m_T_in_co2, ms_hx_des_sol.m_P_in_co2, ms_hx_des_sol.m_m_dot_co2, des_par_ind.m_yr_inflation); //[M$] ms_hx_des_sol.m_cost_bare_erected = calculate_bare_erected_cost(ms_hx_des_sol.m_cost_equipment); @@ -3561,14 +3573,24 @@ int C_CO2_to_air_cooler::C_MEQ_target_T_hot__width_parallel::operator()(double W } double /*M$*/ C_CO2_to_air_cooler::calculate_equipment_cost(double UA /*kWt/K*/, double V_material /*m^3*/, - double T_hot_in /*K*/, double P_hot_in /*kPa*/, double m_dot_hot /*kg/s*/, double f_inflation/**/) + double T_hot_in /*K*/, double P_hot_in /*kPa*/, double m_dot_hot /*kg/s*/, double yr_inflation/**/) { switch (m_cost_model) { case C_CO2_to_air_cooler::E_CARLSON_17: - return 2.3*1.E-3*UA*f_inflation; //[M$] needs UA in kWt/K + { + double yr_base_inflation = 2017; + double f_inflation = calculate_inflation_factor(yr_base_inflation, yr_inflation); + return 2.3 * 1.E-3 * UA * f_inflation; //[M$] needs UA in kWt/K + } + case C_CO2_to_air_cooler::E_WEILAND_19: - return 32.88*std::pow(UA*1.E3, 0.75)*1.E-6*f_inflation; //[M$] needs UA in Wt/K + { + double yr_base_inflation = 2017; + double f_inflation = calculate_inflation_factor(yr_base_inflation, yr_inflation); + return 32.88 * std::pow(UA * 1.E3, 0.75) * 1.E-6 * f_inflation; //[M$] needs UA in Wt/K + } + default: return std::numeric_limits::quiet_NaN(); } diff --git a/tcs/heat_exchangers.h b/tcs/heat_exchangers.h index ebc8e30eda..f30ab33fdd 100644 --- a/tcs/heat_exchangers.h +++ b/tcs/heat_exchangers.h @@ -478,7 +478,7 @@ class C_HX_counterflow_CRM int m_cost_model; //[-] int m_od_solution_type; //[-] - double m_f_inflation = 1.0; //[-] + double m_yr_inflation = 0; //[yr] bool m_is_single_node_des_set; NS_HX_counterflow_eqs::S_hx_node_info ms_node_info_des; @@ -665,7 +665,7 @@ class C_HX_counterflow_CRM double calculate_equipment_cost(double UA /*kWt/K*/, double T_hot_in /*K*/, double P_hot_in /*kPa*/, double m_dot_hot /*kg/s*/, double T_cold_in /*K*/, double P_cold_in /*kPa*/, double m_dot_cold /*kg/s*/, - double f_inflation /**/); + double yr_inflation /*yr*/); double calculate_bare_erected_cost(double cost_equipment /*M$*/); @@ -754,9 +754,9 @@ class C_HX_co2_to_htf : public C_HX_counterflow_CRM double q_dot_design /*kWt*/, double dt_cold_approach /*C/K*/, C_HX_counterflow_CRM::S_des_solved &des_solved); virtual void initialize(int hot_fl, util::matrix_t hot_fl_props, int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type, - double f_inflation); + double yr_inflation); - virtual void initialize(int hot_fl, int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type, double f_inflation); + virtual void initialize(int hot_fl, int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type, double yr_inflation); }; @@ -778,7 +778,7 @@ class C_HX_co2_to_co2_CRM : public C_HX_counterflow_CRM } virtual void initialize(int N_sub_hx, NS_HX_counterflow_eqs::E_UA_target_type od_UA_target_type, - double f_inflation); + double yr_inflation); }; namespace N_compact_hx @@ -824,11 +824,11 @@ class C_CO2_to_air_cooler double m_eta_fan; //[-] Fan isentropic efficiency int m_N_nodes_pass; //[-] Number of nodes per pass - double m_f_inflation; //[] Inflation factor + double m_yr_inflation; //[yr] Inflation year target S_des_par_ind() { - m_T_amb_des = m_elev = m_f_inflation = + m_T_amb_des = m_elev = m_yr_inflation = std::numeric_limits::quiet_NaN(); // Set realistic default values so model can solve without inputs for these values @@ -1334,7 +1334,7 @@ class C_CO2_to_air_cooler double /*M$*/ calculate_equipment_cost(double UA /*kWt/K*/, double V_material /*m^3*/, double T_hot_in /*K*/, double P_hot_in /*kPa*/, double m_dot_hot /*kg/s*/, - double f_inflation /**/); + double yr_inflation /*yr*/); double /*M$*/ calculate_bare_erected_cost(double cost_equipment /*M$*/); }; diff --git a/tcs/sco2_cycle_components.cpp b/tcs/sco2_cycle_components.cpp index cd526363ec..53fa1b5b8a 100644 --- a/tcs/sco2_cycle_components.cpp +++ b/tcs/sco2_cycle_components.cpp @@ -828,6 +828,20 @@ int Ph_dome(double P_low /*MPa*/, std::vector & P_data /*MPa*/, std::vec return Ts_full_dome(T_P_target_solved - 273.15, T_data, s_data, P_data, h_data); } +double calculate_inflation_factor(double yr_base, double yr_target) +{ + if (yr_base == 0 || yr_target == 0) + return 1.0; + + std::vector yr_vec = std::vector(yr_base, yr_target); + + if (yr_vec == std::vector(2017, 2024)) { + return 798.8 / 567.5; + } + + return std::numeric_limits::quiet_NaN(); +} + int C_MEQ_CO2_props_at_2phase_P::operator()(double T_co2 /*K*/, double *P_calc /*kPa*/) { int prop_err_code = CO2_TQ(T_co2, 0.0, &mc_co2_props); @@ -863,12 +877,16 @@ void C_HeatExchanger::hxr_conductance(const std::vector & m_dots, double } double C_turbine::calculate_equipment_cost(double T_in /*K*/, double P_in /*kPa*/, double m_dot /*kg/s*/, - double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/, double f_inflation/**/) + double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/, double yr_inflation/*yr*/) { switch (m_cost_model) { case C_turbine::E_CARLSON_17: - return 7.79*1.E-3*std::pow(W_dot, 0.6842)*f_inflation; //[M$] needs power in kWe + { + double yr_base_inflation = 2017; + double f_inflation = calculate_inflation_factor(yr_base_inflation, yr_inflation); + return 7.79 * 1.E-3 * std::pow(W_dot, 0.6842) * f_inflation; //[M$] needs power in kWe + } case C_turbine::E_WEILAND_19__AXIAL: { double base_cost = 182600 * std::pow(W_dot * 1.E-3, 0.5561); // [$] needs power in MWe @@ -878,7 +896,8 @@ double C_turbine::calculate_equipment_cost(double T_in /*K*/, double P_in /*kPa* if (T_in_C >= 550) { cost_mult = 1.0 + ((1.106e-4) * std::pow(T_in_C - 550, 2.0)); } - + double yr_base_inflation = 2017; + double f_inflation = calculate_inflation_factor(yr_base_inflation, yr_inflation); return base_cost * cost_mult * 1e-6 * f_inflation; //[M$] } default: @@ -964,7 +983,7 @@ void C_turbine::turbine_sizing(const S_design_parameters & des_par_in, int & err ms_des_solved.m_W_dot = ms_des_par.m_m_dot*(ms_des_par.m_h_in - ms_des_par.m_h_out); ms_des_solved.m_equipment_cost = calculate_equipment_cost(ms_des_par.m_T_in, ms_des_par.m_P_in, ms_des_par.m_m_dot, - T_out, ms_des_par.m_P_out, ms_des_solved.m_W_dot, ms_des_par.m_f_inflation); + T_out, ms_des_par.m_P_out, ms_des_solved.m_W_dot, ms_des_par.m_yr_inflation); ms_des_solved.m_bare_erected_cost = calculate_bare_erected_cost(ms_des_solved.m_equipment_cost); } @@ -1561,14 +1580,22 @@ int C_comp_multi_stage::C_MEQ_N_rpm__P_out::operator()(double N_rpm /*rpm*/, dou } double C_comp_multi_stage::calculate_equipment_cost(double T_in /*K*/, double P_in /*kPa*/, double m_dot /*kg/s*/, - double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/, double f_inflation /**/) + double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/, double yr_inflation /*yr*/) { switch (m_cost_model) { case C_comp_multi_stage::E_CARLSON_17: - return 6.898*1.E-3*std::pow(W_dot, 0.7865)*f_inflation; //[M$] needs power in kWe + { + double yr_base_inflation = 2017; + double f_inflation = calculate_inflation_factor(yr_base_inflation, yr_inflation); + return 6.898 * 1.E-3 * std::pow(W_dot, 0.7865) * f_inflation; //[M$] needs power in kWe + } case C_comp_multi_stage::E_WEILAND_19__IG: - return 1.23*std::pow(W_dot*1.E-3, 0.3992)*f_inflation; //[M$] needs power in MWe + { + double yr_base_inflation = 2017; + double f_inflation = calculate_inflation_factor(yr_base_inflation, yr_inflation); + return 1.23 * std::pow(W_dot * 1.E-3, 0.3992) * f_inflation; //[M$] needs power in MWe + } default: return std::numeric_limits::quiet_NaN(); } @@ -1584,7 +1611,7 @@ double C_comp_multi_stage::calculate_bare_erected_cost(double cost_equipment /*M } int C_comp_multi_stage::design_given_outlet_state(int comp_model_code, double T_in /*K*/, double P_in /*kPa*/, double m_dot_cycle /*kg/s*/, - double T_out /*K*/, double P_out /*K*/, double tol /*-*/, double f_inflation /**/) + double T_out /*K*/, double P_out /*K*/, double tol /*-*/, double yr_inflation /*yr*/) { m_compressor_model = comp_model_code; //[-] @@ -1722,7 +1749,7 @@ int C_comp_multi_stage::design_given_outlet_state(int comp_model_code, double T_ } ms_des_solved.m_cost_equipment = calculate_equipment_cost(ms_des_solved.m_T_in, ms_des_solved.m_P_in, ms_des_solved.m_m_dot, - ms_des_solved.m_T_out, ms_des_solved.m_P_out, ms_des_solved.m_W_dot, f_inflation); + ms_des_solved.m_T_out, ms_des_solved.m_P_out, ms_des_solved.m_W_dot, yr_inflation); ms_des_solved.m_cost_bare_erected = calculate_bare_erected_cost(ms_des_solved.m_cost_equipment); //[M$] diff --git a/tcs/sco2_cycle_components.h b/tcs/sco2_cycle_components.h index 0a74221d52..e297ea6384 100644 --- a/tcs/sco2_cycle_components.h +++ b/tcs/sco2_cycle_components.h @@ -73,6 +73,8 @@ int Ts_full_dome(double T_cold /*C*/, std::vector & T_data /*C*/, std::v int Ph_dome(double P_low /*MPa*/, std::vector & P_data /*MPa*/, std::vector & h_data); +double calculate_inflation_factor(double yr_base, double yr_target); + class C_MEQ_CO2_props_at_2phase_P : public C_monotonic_equation { private: @@ -164,13 +166,13 @@ class C_turbine // Mass flow rate double m_m_dot; //[kg/s] (cycle, not basis) - double m_f_inflation; //[] Inflation factor + double m_yr_inflation; //[yr] Inflation target year S_design_parameters() { m_N_design = m_N_comp_design_if_linked = m_P_in = m_T_in = m_D_in = m_h_in = m_s_in = m_P_out = m_h_out = - m_m_dot = m_f_inflation = std::numeric_limits::quiet_NaN(); + m_m_dot = m_yr_inflation = std::numeric_limits::quiet_NaN(); } }; @@ -250,7 +252,7 @@ class C_turbine } double calculate_equipment_cost(double T_in /*K*/, double P_in /*kPa*/, double m_dot /*kg/s*/, - double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/, double f_inflation /**/); + double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/, double yr_inflation /*yr*/); double /*M$*/ calculate_bare_erected_cost(double cost_equipment /*M$*/); @@ -664,12 +666,12 @@ class C_comp_multi_stage double calculate_equipment_cost(double T_in /*K*/, double P_in /*kPa*/, double m_dot /*kg/s*/, double T_out /*K*/, double P_out /*kPa*/, double W_dot /*kWe*/, - double f_inflation /**/); + double yr_inflation /*yr*/); double calculate_bare_erected_cost(double cost_equipment /*M$*/); int design_given_outlet_state(int comp_model_code, double T_in /*K*/, double P_in /*kPa*/, double m_dot /*kg/s*/, - double T_out /*K*/, double P_out /*K*/, double tol /*-*/, double f_inflation /**/); + double T_out /*K*/, double P_out /*K*/, double tol /*-*/, double yr_inflation /*yr*/); void off_design_given_N(double T_in /*K*/, double P_in /*kPa*/, double m_dot_cycle /*kg/s*/, double N_rpm /*rpm*/, int & error_code, double & T_out /*K*/, double & P_out /*kPa*/); diff --git a/tcs/sco2_cycle_templates.h b/tcs/sco2_cycle_templates.h index a20d408648..d926f5d05b 100644 --- a/tcs/sco2_cycle_templates.h +++ b/tcs/sco2_cycle_templates.h @@ -475,7 +475,7 @@ class C_sco2_cycle_core double m_T_amb_des; //[K] Design point ambient temperature double m_elevation; //[m] Elevation (used to calculate ambient pressure) int m_N_nodes_pass; //[-] Number of nodes per pass - double m_f_inflation; //[] Inflation factor + double m_yr_inflation; //[yr] Inflation target year public: @@ -493,7 +493,7 @@ class C_sco2_cycle_core double frac_fan_power /*-*/, double eta_fan /*-*/, double deltaP_cooler_frac /*-*/, int N_nodes_pass /*-*/, double T_amb_des /*K*/, double elevation /*m*/, - double f_inflation /**/) + double yr_inflation /*yr*/) { m_turbo_gen_motor_config = turbo_gen_motor_config; m_eta_generator = eta_generator; //[-] @@ -526,7 +526,7 @@ class C_sco2_cycle_core m_T_amb_des = T_amb_des; //[K] m_elevation = elevation; //[m] - m_f_inflation = f_inflation; //[] + m_yr_inflation = yr_inflation; //[] // Set design limits!!!! ms_des_limits.m_UA_net_power_ratio_max = 2.0; //[-/K] diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index 5b4c6996af..f9cac19e25 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -61,9 +61,9 @@ int C_sco2_htrbp_core::solve() // Initialize Recuperators { // LTR - m_outputs.mc_LT_recup.initialize(m_inputs.m_LTR_N_sub_hxrs, m_inputs.m_LTR_od_UA_target_type, m_inputs.m_f_inflation); + m_outputs.mc_LT_recup.initialize(m_inputs.m_LTR_N_sub_hxrs, m_inputs.m_LTR_od_UA_target_type, m_inputs.m_yr_inflation); // HTR - m_outputs.mc_HT_recup.initialize(m_inputs.m_HTR_N_sub_hxrs, m_inputs.m_HTR_od_UA_target_type, m_inputs.m_f_inflation); + m_outputs.mc_HT_recup.initialize(m_inputs.m_HTR_N_sub_hxrs, m_inputs.m_HTR_od_UA_target_type, m_inputs.m_yr_inflation); } // Initialize a few variables @@ -490,7 +490,7 @@ int C_sco2_htrbp_core::finalize_design(C_sco2_cycle_core::S_design_solved& desig m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], m_inputs.m_des_tol, - m_inputs.m_f_inflation); + m_inputs.m_yr_inflation); if (mc_design_err != 0) { @@ -508,7 +508,7 @@ int C_sco2_htrbp_core::finalize_design(C_sco2_cycle_core::S_design_solved& desig m_outputs.m_temp[C_sco2_cycle_core::RC_OUT], m_outputs.m_pres[C_sco2_cycle_core::RC_OUT], m_inputs.m_des_tol, - m_inputs.m_f_inflation); + m_inputs.m_yr_inflation); if (rc_des_err != 0) { @@ -540,8 +540,8 @@ int C_sco2_htrbp_core::finalize_design(C_sco2_cycle_core::S_design_solved& desig t_des_par.m_h_out = m_outputs.m_enth[C_sco2_cycle_core::TURB_OUT]; // Mass flow t_des_par.m_m_dot = m_outputs.m_m_dot_t; - // Inflation factor - t_des_par.m_f_inflation = m_inputs.m_f_inflation; + // Inflation target yr + t_des_par.m_yr_inflation = m_inputs.m_yr_inflation; int turb_size_error_code = 0; @@ -578,7 +578,7 @@ int C_sco2_htrbp_core::finalize_design(C_sco2_cycle_core::S_design_solved& desig s_air_cooler_des_par_ind.m_elev = m_inputs.m_elevation; // [m] s_air_cooler_des_par_ind.m_eta_fan = m_inputs.m_eta_fan; // [-] s_air_cooler_des_par_ind.m_N_nodes_pass = m_inputs.m_N_nodes_pass; // [-] - s_air_cooler_des_par_ind.m_f_inflation = m_inputs.m_f_inflation; // [-] + s_air_cooler_des_par_ind.m_yr_inflation = m_inputs.m_yr_inflation; // [-] if (m_inputs.m_is_des_air_cooler && std::isfinite(m_inputs.m_deltaP_cooler_frac) && std::isfinite(m_inputs.m_frac_fan_power) && std::isfinite(m_inputs.m_T_amb_des) && std::isfinite(m_inputs.m_elevation) && std::isfinite(m_inputs.m_eta_fan) && m_inputs.m_N_nodes_pass > 0) @@ -1191,7 +1191,7 @@ int C_HTRBypass_Cycle::optimize_bp(const S_auto_opt_design_parameters& auto_par, core_inputs.m_N_turbine = m_N_turbine; // Comes from constructor (constant) core_inputs.m_rc_comp_model_code = C_comp__psi_eta_vs_phi::E_snl_radial_via_Dyreby; // Constant - core_inputs.m_f_inflation = m_f_inflation; // Comes from constructor (constant) + core_inputs.m_yr_inflation = m_yr_inflation; // Comes from constructor (constant) // From special bypass fraction function (should remove) core_inputs.m_dT_BP = m_dT_BP; // Comes from bp par function (constant) diff --git a/tcs/sco2_htrbypass_cycle.h b/tcs/sco2_htrbypass_cycle.h index 49d57faca6..cc0ea5eb57 100644 --- a/tcs/sco2_htrbypass_cycle.h +++ b/tcs/sco2_htrbypass_cycle.h @@ -112,7 +112,7 @@ class C_sco2_htrbp_core int m_mc_comp_model_code; // Main compressor model code int m_rc_comp_model_code; // Recompressor model code int m_N_turbine; //[rpm] Turbine rpm - double m_f_inflation; //[] Inflation factor + double m_yr_inflation; //[yr] Inflation target year S_sco2_htrbp_in() { @@ -139,7 +139,7 @@ class C_sco2_htrbp_core m_elevation = m_dT_BP = m_HTF_PHX_cold_approach_input = - m_f_inflation = + m_yr_inflation = std::numeric_limits::quiet_NaN(); m_N_nodes_pass = 0; @@ -397,7 +397,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core double frac_fan_power, double eta_fan, double deltaP_cooler_frac, int N_nodes_pass, double T_amb_des, double elevation, - double f_inflation) : + double yr_inflation) : C_sco2_cycle_core(turbo_gen_motor_config, eta_generator, T_mc_in, @@ -412,7 +412,7 @@ class C_HTRBypass_Cycle : public C_sco2_cycle_core frac_fan_power, eta_fan, deltaP_cooler_frac, N_nodes_pass, T_amb_des, elevation, - f_inflation) + yr_inflation) { m_T_target = m_T_HTF_PHX_inlet = m_set_HTF_mdot = m_HTF_PHX_cold_approach = m_dT_BP diff --git a/tcs/sco2_partialcooling_cycle.cpp b/tcs/sco2_partialcooling_cycle.cpp index 1d6c27eaf7..15a8a6dcb0 100644 --- a/tcs/sco2_partialcooling_cycle.cpp +++ b/tcs/sco2_partialcooling_cycle.cpp @@ -63,8 +63,8 @@ int C_PartialCooling_Cycle::design_core() } // Initialize Recuperators - mc_LTR.initialize(m_LTR_N_sub_hxrs, ms_des_par.m_LTR_od_UA_target_type, m_f_inflation); - mc_HTR.initialize(m_HTR_N_sub_hxrs, ms_des_par.m_HTR_od_UA_target_type, m_f_inflation); + mc_LTR.initialize(m_LTR_N_sub_hxrs, ms_des_par.m_LTR_od_UA_target_type, m_yr_inflation); + mc_HTR.initialize(m_HTR_N_sub_hxrs, ms_des_par.m_HTR_od_UA_target_type, m_yr_inflation); // Initialize known temps and pressures from design parameters m_temp_last[MC_IN] = m_T_mc_in; //[K] @@ -534,7 +534,7 @@ int C_PartialCooling_Cycle::finalize_design() m_m_dot_mc, m_temp_last[MC_OUT], m_pres_last[MC_OUT], ms_des_par.m_des_tol, - m_f_inflation); + m_yr_inflation); if (mc_des_err != 0) { @@ -546,7 +546,7 @@ int C_PartialCooling_Cycle::finalize_design() m_m_dot_pc, m_temp_last[PC_OUT], m_pres_last[PC_OUT], ms_des_par.m_des_tol, - m_f_inflation); + m_yr_inflation); if (pc_des_err != 0) { @@ -560,7 +560,7 @@ int C_PartialCooling_Cycle::finalize_design() m_m_dot_rc, m_temp_last[RC_OUT], m_pres_last[RC_OUT], ms_des_par.m_des_tol, - m_f_inflation); + m_yr_inflation); if (rc_des_err != 0) { @@ -587,7 +587,7 @@ int C_PartialCooling_Cycle::finalize_design() t_des_par.m_h_out = m_enth_last[TURB_OUT]; //[kJ/kg] // Mass flow t_des_par.m_m_dot = m_m_dot_t; //[kg/s] - t_des_par.m_f_inflation = m_f_inflation; + t_des_par.m_yr_inflation = m_yr_inflation; int turb_size_err = 0; mc_t.turbine_sizing(t_des_par, turb_size_err); @@ -625,7 +625,7 @@ int C_PartialCooling_Cycle::finalize_design() s_LP_air_cooler_des_par_ind.m_elev = m_elevation; //[m] s_LP_air_cooler_des_par_ind.m_eta_fan = m_eta_fan; //[-] s_LP_air_cooler_des_par_ind.m_N_nodes_pass = m_N_nodes_pass; //[-] - s_LP_air_cooler_des_par_ind.m_f_inflation = m_f_inflation; //[] + s_LP_air_cooler_des_par_ind.m_yr_inflation = m_yr_inflation; //[yr] if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) @@ -664,7 +664,7 @@ int C_PartialCooling_Cycle::finalize_design() s_IP_air_cooler_des_par_ind.m_elev = m_elevation; //[m] s_IP_air_cooler_des_par_ind.m_eta_fan = m_eta_fan; //[-] s_IP_air_cooler_des_par_ind.m_N_nodes_pass = m_N_nodes_pass; //[-] - s_IP_air_cooler_des_par_ind.m_f_inflation = m_f_inflation; //[] + s_IP_air_cooler_des_par_ind.m_yr_inflation = m_yr_inflation; //[yr] if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) diff --git a/tcs/sco2_partialcooling_cycle.h b/tcs/sco2_partialcooling_cycle.h index c4fca1b6b2..97d46c89ef 100644 --- a/tcs/sco2_partialcooling_cycle.h +++ b/tcs/sco2_partialcooling_cycle.h @@ -271,7 +271,7 @@ class C_PartialCooling_Cycle : public C_sco2_cycle_core double frac_fan_power /*-*/, double eta_fan /*-*/, double deltaP_cooler_frac /*-*/, int N_nodes_pass /*-*/, double T_amb_des /*K*/, double elevation /*m*/, - double f_inflation /**/) : + double yr_inflation /*yr*/) : C_sco2_cycle_core(turbo_gen_motor_config, eta_generator, T_mc_in, @@ -286,7 +286,7 @@ class C_PartialCooling_Cycle : public C_sco2_cycle_core frac_fan_power, eta_fan, deltaP_cooler_frac, N_nodes_pass, T_amb_des, elevation, - f_inflation) + yr_inflation) { m_temp_last.resize(END_SCO2_STATES); std::fill(m_temp_last.begin(), m_temp_last.end(), std::numeric_limits::quiet_NaN()); diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index 07b9a23b89..e173ed7a4c 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -123,7 +123,7 @@ int C_sco2_phx_air_cooler::design_core() ms_des_par.m_frac_fan_power, ms_des_par.m_eta_fan, ms_des_par.m_deltaP_cooler_frac, ms_des_par.m_N_nodes_pass, ms_des_par.m_T_amb_des, ms_des_par.m_elevation, - ms_des_par.m_f_inflation)); + ms_des_par.m_yr_inflation)); s_cycle_config = "partial cooling"; @@ -146,7 +146,7 @@ int C_sco2_phx_air_cooler::design_core() ms_des_par.m_frac_fan_power, ms_des_par.m_eta_fan, ms_des_par.m_deltaP_cooler_frac, ms_des_par.m_N_nodes_pass, ms_des_par.m_T_amb_des, ms_des_par.m_elevation, - ms_des_par.m_f_inflation)); + ms_des_par.m_yr_inflation)); s_cycle_config = "htr bypass"; @@ -219,7 +219,7 @@ int C_sco2_phx_air_cooler::design_core() ms_des_par.m_frac_fan_power, ms_des_par.m_eta_fan, ms_des_par.m_deltaP_cooler_frac, ms_des_par.m_N_nodes_pass, ms_des_par.m_T_amb_des, ms_des_par.m_elevation, - ms_des_par.m_f_inflation)); + ms_des_par.m_yr_inflation)); s_cycle_config = "turbine split flow"; @@ -243,7 +243,7 @@ int C_sco2_phx_air_cooler::design_core() ms_des_par.m_frac_fan_power, ms_des_par.m_eta_fan, ms_des_par.m_deltaP_cooler_frac, ms_des_par.m_N_nodes_pass, ms_des_par.m_T_amb_des, ms_des_par.m_elevation, - ms_des_par.m_f_inflation)); + ms_des_par.m_yr_inflation)); s_cycle_config = "recompression"; @@ -410,7 +410,7 @@ int C_sco2_phx_air_cooler::design_core() // Initialize the PHX mc_phx.initialize(ms_des_par.m_hot_fl_code, ms_des_par.mc_hot_fl_props, ms_des_par.m_phx_N_sub_hx, - ms_des_par.m_phx_od_UA_target_type, ms_des_par.m_f_inflation); + ms_des_par.m_phx_od_UA_target_type, ms_des_par.m_yr_inflation); // Define state enumerable for sco2 into PHX int phx_cold_inlet_state = C_sco2_cycle_core::HTR_HP_OUT; @@ -458,7 +458,7 @@ int C_sco2_phx_air_cooler::design_core() auto bp_od_UA_target_type = ms_des_par.m_phx_od_UA_target_type; mc_bp.initialize(ms_des_par.m_hot_fl_code, ms_des_par.mc_hot_fl_props, bp_N_subs_hx, bp_od_UA_target_type, - ms_des_par.m_f_inflation); + ms_des_par.m_yr_inflation); // Calculate BP heat transfer double m_dot_bp_sco2 = ms_des_solved.ms_rc_cycle_solved.m_bypass_frac * (ms_des_solved.ms_rc_cycle_solved.m_m_dot_t); diff --git a/tcs/sco2_pc_csp_int.h b/tcs/sco2_pc_csp_int.h index 89494acd08..a172b5e769 100644 --- a/tcs/sco2_pc_csp_int.h +++ b/tcs/sco2_pc_csp_int.h @@ -135,8 +135,8 @@ class C_sco2_phx_air_cooler double m_deltaT_bypass; // [delta K] sco2 Bypass Outlet Temp - HTR_HP_OUT Temp double m_set_HTF_mdot; // [kg/s] For HTR Bypass ONLY, 0 = calculate HTF mdot (need to set dT_PHX_cold_approach), > 0 = HTF mdot kg/s - // Inflation Factor - double m_f_inflation; // [] Inflation factor + // Inflation target year + double m_yr_inflation; // [yr] Inflation target year S_des_par() { @@ -175,7 +175,7 @@ class C_sco2_phx_air_cooler m_PR_HP_to_LP_guess = m_f_PR_HP_to_IP_guess = m_phx_dt_cold_approach = m_frac_fan_power = m_deltaP_cooler_frac = m_eta_fan = - m_f_inflation = + m_yr_inflation = std::numeric_limits::quiet_NaN(); m_fixed_P_mc_out = false; //[-] If false, then should default to optimizing this parameter diff --git a/tcs/sco2_recompression_cycle.cpp b/tcs/sco2_recompression_cycle.cpp index abfc3aa0cd..7f7a4b7ba5 100644 --- a/tcs/sco2_recompression_cycle.cpp +++ b/tcs/sco2_recompression_cycle.cpp @@ -1851,9 +1851,9 @@ void C_RecompCycle::design_core_standard(int & error_code) // Initialize Recuperators // LTR - mc_LT_recup.initialize(m_LTR_N_sub_hxrs, ms_des_par.m_LTR_od_UA_target_type, m_f_inflation); + mc_LT_recup.initialize(m_LTR_N_sub_hxrs, ms_des_par.m_LTR_od_UA_target_type, m_yr_inflation); // HTR - mc_HT_recup.initialize(m_HTR_N_sub_hxrs, ms_des_par.m_HTR_od_UA_target_type, m_f_inflation); + mc_HT_recup.initialize(m_HTR_N_sub_hxrs, ms_des_par.m_HTR_od_UA_target_type, m_yr_inflation); // Initialize a few variables double m_dot_t, m_dot_mc, m_dot_rc, Q_dot_LT, Q_dot_HT, UA_LT_calc, UA_HT_calc; @@ -3351,7 +3351,7 @@ void C_RecompCycle::finalize_design(int & error_code) m_temp_last[MC_OUT], m_pres_last[MC_OUT], ms_des_par.m_des_tol, - m_f_inflation); + m_yr_inflation); if (mc_design_err != 0) { @@ -3366,7 +3366,7 @@ void C_RecompCycle::finalize_design(int & error_code) m_m_dot_rc, m_temp_last[RC_OUT], m_pres_last[RC_OUT], ms_des_par.m_des_tol, - m_f_inflation); + m_yr_inflation); if (rc_des_err != 0) { @@ -3395,8 +3395,8 @@ void C_RecompCycle::finalize_design(int & error_code) t_des_par.m_h_out = m_enth_last[7-cpp_offset]; // Mass flow t_des_par.m_m_dot = m_m_dot_t; - // Inflation factor - t_des_par.m_f_inflation = m_f_inflation; + // Inflation target year + t_des_par.m_yr_inflation = m_yr_inflation; //[yr] int turb_size_error_code = 0; m_t.turbine_sizing(t_des_par, turb_size_error_code); @@ -3430,7 +3430,7 @@ void C_RecompCycle::finalize_design(int & error_code) s_air_cooler_des_par_ind.m_elev = m_elevation; //[m] s_air_cooler_des_par_ind.m_eta_fan = m_eta_fan; //[-] s_air_cooler_des_par_ind.m_N_nodes_pass = m_N_nodes_pass; //[-] - s_air_cooler_des_par_ind.m_f_inflation = m_f_inflation; //[] + s_air_cooler_des_par_ind.m_yr_inflation = m_yr_inflation; //[yr] if (ms_des_par.m_is_des_air_cooler && std::isfinite(m_deltaP_cooler_frac) && std::isfinite(m_frac_fan_power) && std::isfinite(m_T_amb_des) && std::isfinite(m_elevation) && std::isfinite(m_eta_fan) && m_N_nodes_pass > 0) diff --git a/tcs/sco2_recompression_cycle.h b/tcs/sco2_recompression_cycle.h index 9101e59084..43d8ca5032 100644 --- a/tcs/sco2_recompression_cycle.h +++ b/tcs/sco2_recompression_cycle.h @@ -497,7 +497,7 @@ class C_RecompCycle : public C_sco2_cycle_core double frac_fan_power /*-*/, double eta_fan /*-*/, double deltaP_cooler_frac /*-*/, int N_nodes_pass /*-*/, double T_amb_des /*K*/, double elevation /*m*/, - double f_inflation /**/) : + double m_yr_inflation /*yr*/) : C_sco2_cycle_core(turbo_gen_motor_config, eta_generator, T_mc_in, @@ -512,7 +512,7 @@ class C_RecompCycle : public C_sco2_cycle_core frac_fan_power, eta_fan, deltaP_cooler_frac, N_nodes_pass, T_amb_des, elevation, - f_inflation) + m_yr_inflation) { m_temp_last.resize(END_SCO2_STATES); std::fill(m_temp_last.begin(), m_temp_last.end(), std::numeric_limits::quiet_NaN()); diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp index 783642f729..380502072f 100644 --- a/tcs/sco2_turbinesplitflow_cycle.cpp +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -61,9 +61,9 @@ int C_sco2_tsf_core::solve() // Initialize Recuperators { // LTR - m_outputs.mc_LT_recup.initialize(m_inputs.m_LTR_N_sub_hxrs, m_inputs.m_LTR_od_UA_target_type, m_inputs.m_f_inflation); + m_outputs.mc_LT_recup.initialize(m_inputs.m_LTR_N_sub_hxrs, m_inputs.m_LTR_od_UA_target_type, m_inputs.m_yr_inflation); // HTR - m_outputs.mc_HT_recup.initialize(m_inputs.m_HTR_N_sub_hxrs, m_inputs.m_HTR_od_UA_target_type, m_inputs.m_f_inflation); + m_outputs.mc_HT_recup.initialize(m_inputs.m_HTR_N_sub_hxrs, m_inputs.m_HTR_od_UA_target_type, m_inputs.m_yr_inflation); } // Initialize a few variables @@ -389,7 +389,7 @@ int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_ m_outputs.m_temp[C_sco2_cycle_core::MC_OUT], m_outputs.m_pres[C_sco2_cycle_core::MC_OUT], m_inputs.m_des_tol, - m_inputs.m_f_inflation); + m_inputs.m_yr_inflation); if (mc_design_err != 0) { @@ -415,8 +415,8 @@ int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_ t_des_par.m_h_out = m_outputs.m_enth[C_sco2_cycle_core::TURB_OUT]; // Mass flow t_des_par.m_m_dot = m_outputs.m_m_dot_t; - // Inflation factor - t_des_par.m_f_inflation = m_inputs.m_f_inflation; + // Inflation target year + t_des_par.m_yr_inflation = m_inputs.m_yr_inflation; int turb_size_error_code = 0; m_outputs.m_t.turbine_sizing(t_des_par, turb_size_error_code); @@ -445,8 +445,8 @@ int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_ t2_des_par.m_h_out = m_outputs.m_enth[C_sco2_cycle_core::TURB2_OUT]; // Mass flow t2_des_par.m_m_dot = m_outputs.m_m_dot_t2; - // Inflation factor - t2_des_par.m_f_inflation = m_inputs.m_f_inflation; + // Inflation target year + t2_des_par.m_yr_inflation = m_inputs.m_yr_inflation; int turb_size_error_code = 0; m_outputs.m_t2.turbine_sizing(t2_des_par, turb_size_error_code); @@ -482,7 +482,7 @@ int C_sco2_tsf_core::finalize_design(C_sco2_cycle_core::S_design_solved& design_ s_air_cooler_des_par_ind.m_elev = m_inputs.m_elevation; // [m] s_air_cooler_des_par_ind.m_eta_fan = m_inputs.m_eta_fan; // [-] s_air_cooler_des_par_ind.m_N_nodes_pass = m_inputs.m_N_nodes_pass; // [-] - s_air_cooler_des_par_ind.m_f_inflation = m_inputs.m_f_inflation; // [-] + s_air_cooler_des_par_ind.m_yr_inflation = m_inputs.m_yr_inflation; // [yr] if (m_inputs.m_is_des_air_cooler && std::isfinite(m_inputs.m_deltaP_cooler_frac) && std::isfinite(m_inputs.m_frac_fan_power) && std::isfinite(m_inputs.m_T_amb_des) && std::isfinite(m_inputs.m_elevation) && std::isfinite(m_inputs.m_eta_fan) && m_inputs.m_N_nodes_pass > 0) @@ -783,7 +783,7 @@ int C_TurbineSplitFlow_Cycle::optimize_par(const S_auto_opt_design_parameters& a core_inputs.m_N_nodes_pass = m_N_nodes_pass; // Comes from constructor (constant) core_inputs.m_mc_comp_model_code = m_mc_comp_model_code; // Comes from constructor (constant) core_inputs.m_N_turbine = m_N_turbine; // Comes from constructor (constant) - core_inputs.m_f_inflation = m_f_inflation; // Comes from constructor (constant) + core_inputs.m_yr_inflation = m_yr_inflation; // Comes from constructor (constant) // Handle design variables (check if fixed or free) { diff --git a/tcs/sco2_turbinesplitflow_cycle.h b/tcs/sco2_turbinesplitflow_cycle.h index 8c2101677d..d96aa80971 100644 --- a/tcs/sco2_turbinesplitflow_cycle.h +++ b/tcs/sco2_turbinesplitflow_cycle.h @@ -105,7 +105,7 @@ class C_sco2_tsf_core int m_mc_comp_model_code; // Main compressor model code int m_N_turbine; //[rpm] Turbine rpm - double m_f_inflation; //[] Inflation factor + double m_yr_inflation; //[yr] Inflation target year S_sco2_tsf_in() { @@ -126,7 +126,7 @@ class C_sco2_tsf_core m_deltaP_cooler_frac = m_T_amb_des = m_elevation = - m_f_inflation = + m_yr_inflation = std::numeric_limits::quiet_NaN(); m_N_nodes_pass = 0; @@ -340,7 +340,7 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core double frac_fan_power, double eta_fan, double deltaP_cooler_frac, int N_nodes_pass, double T_amb_des, double elevation, - double f_inflation) : + double m_yr_inflation) : C_sco2_cycle_core(turbo_gen_motor_config, eta_generator, T_mc_in, @@ -354,7 +354,7 @@ class C_TurbineSplitFlow_Cycle : public C_sco2_cycle_core eta_t, N_turbine, frac_fan_power, eta_fan, deltaP_cooler_frac, N_nodes_pass, - T_amb_des, elevation, f_inflation), + T_amb_des, elevation, m_yr_inflation), m_eta_t2(eta_t2) { m_opt_iteration_count = 0; From 1e7700f7ccdfe4788dd6eda11b1c52103a9b9ccd Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Mon, 10 Feb 2025 12:15:43 -0700 Subject: [PATCH 76/94] Change inflation factor input to inflation year. --- tcs/sco2_cycle_components.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcs/sco2_cycle_components.cpp b/tcs/sco2_cycle_components.cpp index 53fa1b5b8a..1828cdae90 100644 --- a/tcs/sco2_cycle_components.cpp +++ b/tcs/sco2_cycle_components.cpp @@ -836,7 +836,7 @@ double calculate_inflation_factor(double yr_base, double yr_target) std::vector yr_vec = std::vector(yr_base, yr_target); if (yr_vec == std::vector(2017, 2024)) { - return 798.8 / 567.5; + return 1.407577; } return std::numeric_limits::quiet_NaN(); From 1effbcf4dd470f07a4e4ee7a09feb93a21e51a67 Mon Sep 17 00:00:00 2001 From: tyneises Date: Tue, 11 Feb 2025 13:38:29 -0600 Subject: [PATCH 77/94] update function calls with inflation year that was required after branch merge --- ssc/cmod_csp_heatsink.cpp | 2 +- tcs/heat_exchangers.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ssc/cmod_csp_heatsink.cpp b/ssc/cmod_csp_heatsink.cpp index 7df3705bfa..6ef462d09b 100644 --- a/ssc/cmod_csp_heatsink.cpp +++ b/ssc/cmod_csp_heatsink.cpp @@ -60,7 +60,7 @@ class cm_csp_heatsink : public compute_module NS_HX_counterflow_eqs::E_UA_target_type ua_type = NS_HX_counterflow_eqs::E_UA_target_type::E_constant_UA; - mc_phx.initialize(hot_fl, 10, ua_type); + mc_phx.initialize(hot_fl, 10, ua_type, 2024.0); double q_dot = 1000.0; //[kWt] double T_co2_hot = 700.0; //[C] diff --git a/tcs/heat_exchangers.cpp b/tcs/heat_exchangers.cpp index 6a78f0237c..10e8f5e850 100644 --- a/tcs/heat_exchangers.cpp +++ b/tcs/heat_exchangers.cpp @@ -2006,7 +2006,7 @@ void C_HX_counterflow_CRM::design_calc_UA_TP_to_PH(C_HX_counterflow_CRM::S_des_c ms_des_solved.m_cost_equipment = calculate_equipment_cost(ms_des_solved.m_UA_design, ms_des_calc_UA_par.m_T_h_in, ms_des_calc_UA_par.m_P_h_in, ms_des_calc_UA_par.m_m_dot_hot_des, - ms_des_calc_UA_par.m_T_c_in, ms_des_calc_UA_par.m_P_c_in, ms_des_calc_UA_par.m_m_dot_cold_des); + ms_des_calc_UA_par.m_T_c_in, ms_des_calc_UA_par.m_P_c_in, ms_des_calc_UA_par.m_m_dot_cold_des, 2024.0); ms_des_solved.m_cost_bare_erected = calculate_bare_erected_cost(ms_des_solved.m_cost_equipment); From 0ec0747464353bb4af1ad2e47e709ebb603909ff Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:27:15 -0600 Subject: [PATCH 78/94] Remove sco2 helper cmod. --- ssc/CMakeLists.txt | 1 - ssc/cmod_sco2_helper.cpp | 56 ---------- ssc/csp_common.cpp | 230 --------------------------------------- ssc/csp_common.h | 6 - ssc/sscapi.cpp | 2 - 5 files changed, 295 deletions(-) delete mode 100644 ssc/cmod_sco2_helper.cpp diff --git a/ssc/CMakeLists.txt b/ssc/CMakeLists.txt index 5cae657e2d..112af2a6ff 100644 --- a/ssc/CMakeLists.txt +++ b/ssc/CMakeLists.txt @@ -84,7 +84,6 @@ set(SSC_SRC cmod_sco2_air_cooler.cpp cmod_sco2_csp_system.cpp cmod_sco2_csp_ud_pc_tables.cpp - cmod_sco2_helper.cpp cmod_singlediode.cpp cmod_singleowner.cpp cmod_singleowner_heat.cpp diff --git a/ssc/cmod_sco2_helper.cpp b/ssc/cmod_sco2_helper.cpp deleted file mode 100644 index 20e1a74100..0000000000 --- a/ssc/cmod_sco2_helper.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* -BSD 3-Clause License - -Copyright (c) Alliance for Sustainable Energy, LLC. See also https://github.com/NREL/ssc/blob/develop/LICENSE -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "core.h" -#include "common.h" - -#include "csp_common.h" - - - - -class cm_sco2_helper : public compute_module -{ -public: - - cm_sco2_helper() - { - add_var_info(vtab_sco2_helper); - } - - void exec() override - { - sco2_helper_core(this); - } -}; - -DEFINE_MODULE_ENTRY(sco2_helper, "...", 0) \ No newline at end of file diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index c4f0dc570b..b08e159365 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -2018,233 +2018,3 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c return 0; } - -var_info vtab_sco2_helper[] = -{ - { SSC_INPUT, SSC_NUMBER, "cycle_config", "Cycle configuration", "", "", "", "", "", "" }, - { SSC_INPUT, SSC_ARRAY, "T_state_points", "Temperature state point array", "C", "", "", "", "", "" }, - { SSC_INPUT, SSC_ARRAY, "P_state_points", "Pressure state point array", "MPa", "", "", "", "", "" }, - { SSC_INPUT, SSC_ARRAY, "s_state_points", "Entropy state point array", "kJ/kg-K", "", "", "", "", "" }, - - // T-s plot data - { SSC_OUTPUT, SSC_ARRAY, "T_LTR_HP_data", "Temperature points along LTR HP stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_LTR_HP_data", "Entropy points along LTR HP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_HTR_HP_data", "Temperature points along HTR HP stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_HTR_HP_data", "Entropy points along HTR HP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_PHX_data", "Temperature points along PHX stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_PHX_data", "Entropy points along PHX stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_HTR_LP_data", "Temperature points along HTR LP stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_HTR_LP_data", "Entropy points along HTR LP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_LTR_LP_data", "Temperature points along LTR LP stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_LTR_LP_data", "Entropy points along LTR LP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_main_cooler_data", "Temperature points along main cooler stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_main_cooler_data", "Entropy points along main cooler stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_pre_cooler_data", "Temperature points along pre cooler stream", "C", "T-s plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_pre_cooler_data", "Entropy points along pre cooler stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, - // P-h plot data - { SSC_OUTPUT, SSC_ARRAY, "P_t_data", "Pressure points along turbine expansion", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_t_data", "Enthalpy points along turbine expansion", "kJ/kg", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_mc_data", "Pressure points along main compression", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_mc_data", "Enthalpy points along main compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_rc_data", "Pressure points along re compression", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_rc_data", "Enthalpy points along re compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_pc_data", "Pressure points along pre compression", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_pc_data", "Enthalpy points along pre compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_t2_data", "Pressure points along secondary turbine expansion", "MPa", "P-h plot data", "", "*", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_t2_data", "Enthalpy points along secondary turbine expansion", "kJ/kg", "P-h plot data", "", "*", "", "" }, - - - -var_info_invalid }; - -int sco2_helper_core(compute_module* cm) -{ - int cycle_config = cm->as_integer("cycle_config"); - std::vector T_state_points_C = cm->as_vector_double("T_state_points"); - std::vector T_state_points_K; - for (double temp : T_state_points_C) - T_state_points_K.push_back(temp + 273.15); - - std::vector P_state_points_MPa = cm->as_vector_double("P_state_points"); - std::vector P_state_points_kPa; - for (double pres : P_state_points_MPa) - P_state_points_kPa.push_back(pres * 1e3); - - std::vector s_state_points = cm->as_vector_double("s_state_points"); - - // Get data for P-h cycle plot - std::vector P_t; //[MPa] - std::vector h_t; //[kJ/kg] - std::vector P_mc; //[MPa] - std::vector h_mc; //[kJ/kg] - std::vector P_rc; //[MPa] - std::vector h_rc; //[kJ/kg] - std::vector P_pc; //[MPa] - std::vector h_pc; //[kJ/kg] - std::vector P_t2; //[MPa] - std::vector h_t2; //[kJ/kg] - int ph_err_code = sco2_cycle_plot_data_PH(cycle_config, - T_state_points_K, - P_state_points_kPa, - P_t, - h_t, - P_mc, - h_mc, - P_rc, - h_rc, - P_pc, - h_pc, - P_t2, - h_t2); - - if (ph_err_code != 0) - throw exec_error("sco2_csp_system", "cycle plot data routine failed"); - - size_t n_v = P_t.size(); - ssc_number_t* p_P_t_data = cm->allocate("P_t_data", n_v); - ssc_number_t* p_h_t_data = cm->allocate("h_t_data", n_v); - for (size_t i = 0; i < n_v; i++) - { - p_P_t_data[i] = (ssc_number_t)(P_t[i]); //[MPa] - p_h_t_data[i] = (ssc_number_t)(h_t[i]); //[kJ/kg] - } - - n_v = P_mc.size(); - ssc_number_t* p_P_mc_data = cm->allocate("P_mc_data", n_v); - ssc_number_t* p_h_mc_data = cm->allocate("h_mc_data", n_v); - for (size_t i = 0; i < n_v; i++) - { - p_P_mc_data[i] = (ssc_number_t)(P_mc[i]); //[MPa] - p_h_mc_data[i] = (ssc_number_t)(h_mc[i]); //[kJ/kg] - } - - n_v = P_rc.size(); - ssc_number_t* p_P_rc_data = cm->allocate("P_rc_data", n_v); - ssc_number_t* p_h_rc_data = cm->allocate("h_rc_data", n_v); - for (size_t i = 0; i < n_v; i++) - { - p_P_rc_data[i] = (ssc_number_t)(P_rc[i]); //[MPa] - p_h_rc_data[i] = (ssc_number_t)(h_rc[i]); //[kJ/kg] - } - - n_v = P_pc.size(); - ssc_number_t* p_P_pc_data = cm->allocate("P_pc_data", n_v); - ssc_number_t* p_h_pc_data = cm->allocate("h_pc_data", n_v); - for (size_t i = 0; i < n_v; i++) - { - p_P_pc_data[i] = (ssc_number_t)(P_pc[i]); //[MPa] - p_h_pc_data[i] = (ssc_number_t)(h_pc[i]); //[kJ/kg] - } - - n_v = P_t2.size(); - ssc_number_t* p_P_t2_data = cm->allocate("P_t2_data", n_v); - ssc_number_t* p_h_t2_data = cm->allocate("h_t2_data", n_v); - for (size_t i = 0; i < n_v; i++) - { - p_P_t2_data[i] = (ssc_number_t)(P_t2[i]); //[MPa] - p_h_t2_data[i] = (ssc_number_t)(h_t2[i]); //[kJ/kg] - } - - // Get data for T-s cycle plot - std::vector T_LTR_HP; //[C] - std::vector s_LTR_HP; //[kJ/kg-K] - std::vector T_HTR_HP; //[C] - std::vector s_HTR_HP; //[kJ/kg-K] - std::vector T_PHX; //[C] - std::vector s_PHX; //[kJ/kg-K] - std::vector T_HTR_LP; //[C] - std::vector s_HTR_LP; //[kJ/kg-K] - std::vector T_LTR_LP; //[C] - std::vector s_LTR_LP; //[kJ/kg-K] - std::vector T_main_cooler; //[C] - std::vector s_main_cooler; //[kJ/kg-K] - std::vector T_pre_cooler; //[C] - std::vector s_pre_cooler; //[kJ/kg-K] - int plot_data_err_code = sco2_cycle_plot_data_TS(cycle_config, - P_state_points_kPa, - s_state_points, - T_LTR_HP, - s_LTR_HP, - T_HTR_HP, - s_HTR_HP, - T_PHX, - s_PHX, - T_HTR_LP, - s_HTR_LP, - T_LTR_LP, - s_LTR_LP, - T_main_cooler, - s_main_cooler, - T_pre_cooler, - s_pre_cooler); - - if (plot_data_err_code != 0) - throw exec_error("sco2_csp_system", "cycle plot data routine failed"); - - n_v = T_LTR_HP.size(); - ssc_number_t* p_T_LTR_HP_data = cm->allocate("T_LTR_HP_data", n_v); - ssc_number_t* p_s_LTR_HP_data = cm->allocate("s_LTR_HP_data", n_v); - for (size_t i = 0; i < n_v; i++) - { - p_T_LTR_HP_data[i] = (ssc_number_t)(T_LTR_HP[i]); //[C] - p_s_LTR_HP_data[i] = (ssc_number_t)(s_LTR_HP[i]); //[kJ/kg-K] - } - - n_v = T_HTR_HP.size(); - ssc_number_t* p_T_HTR_HP_data = cm->allocate("T_HTR_HP_data", n_v); - ssc_number_t* p_s_HTR_HP_data = cm->allocate("s_HTR_HP_data", n_v); - for (size_t i = 0; i < n_v; i++) - { - p_T_HTR_HP_data[i] = (ssc_number_t)(T_HTR_HP[i]); //[C] - p_s_HTR_HP_data[i] = (ssc_number_t)(s_HTR_HP[i]); //[kJ/kg-K] - } - - n_v = T_PHX.size(); - ssc_number_t* p_T_PHX_data = cm->allocate("T_PHX_data", n_v); - ssc_number_t* p_s_PHX_data = cm->allocate("s_PHX_data", n_v); - for (size_t i = 0; i < n_v; i++) - { - p_T_PHX_data[i] = (ssc_number_t)(T_PHX[i]); //[C] - p_s_PHX_data[i] = (ssc_number_t)(s_PHX[i]); //[kJ/kg-K] - } - - n_v = T_HTR_LP.size(); - ssc_number_t* p_T_HTR_LP_data = cm->allocate("T_HTR_LP_data", n_v); - ssc_number_t* p_s_HTR_LP_data = cm->allocate("s_HTR_LP_data", n_v); - for (size_t i = 0; i < n_v; i++) - { - p_T_HTR_LP_data[i] = (ssc_number_t)(T_HTR_LP[i]); //[C] - p_s_HTR_LP_data[i] = (ssc_number_t)(s_HTR_LP[i]); //[kJ/kg-K] - } - - n_v = T_LTR_LP.size(); - ssc_number_t* p_T_LTR_LP_data = cm->allocate("T_LTR_LP_data", n_v); - ssc_number_t* p_s_LTR_LP_data = cm->allocate("s_LTR_LP_data", n_v); - for (size_t i = 0; i < n_v; i++) - { - p_T_LTR_LP_data[i] = (ssc_number_t)(T_LTR_LP[i]); //[C] - p_s_LTR_LP_data[i] = (ssc_number_t)(s_LTR_LP[i]); //[kJ/kg-K] - } - - n_v = T_main_cooler.size(); - ssc_number_t* p_T_main_cooler = cm->allocate("T_main_cooler_data", n_v); - ssc_number_t* p_s_main_cooler = cm->allocate("s_main_cooler_data", n_v); - for (size_t i = 0; i < n_v; i++) - { - p_T_main_cooler[i] = (ssc_number_t)(T_main_cooler[i]); //[C] - p_s_main_cooler[i] = (ssc_number_t)(s_main_cooler[i]); //[kJ/kg-K] - } - - n_v = T_pre_cooler.size(); - ssc_number_t* p_T_pre_cooler = cm->allocate("T_pre_cooler_data", n_v); - ssc_number_t* p_s_pre_cooler = cm->allocate("s_pre_cooler_data", n_v); - for (size_t i = 0; i < n_v; i++) - { - p_T_pre_cooler[i] = (ssc_number_t)(T_pre_cooler[i]); //[C] - p_s_pre_cooler[i] = (ssc_number_t)(s_pre_cooler[i]); //[kJ/kg-K] - } - - - - return 0; -} diff --git a/ssc/csp_common.h b/ssc/csp_common.h index d9e12ada65..5e36f1ab27 100644 --- a/ssc/csp_common.h +++ b/ssc/csp_common.h @@ -83,12 +83,6 @@ extern var_info vtab_sco2_design[]; int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_cycle); - - #endif -extern var_info vtab_sco2_helper[]; - -int sco2_helper_core(compute_module* cm); - diff --git a/ssc/sscapi.cpp b/ssc/sscapi.cpp index 1c71cfbe34..549f912191 100644 --- a/ssc/sscapi.cpp +++ b/ssc/sscapi.cpp @@ -132,7 +132,6 @@ extern module_entry_info cm_entry_sco2_csp_ud_pc_tables, cm_entry_sco2_air_cooler, cm_entry_sco2_comp_curves, - cm_entry_sco2_helper, cm_entry_test_ud_power_cycle, cm_entry_user_htf_comparison, cm_entry_ui_udpc_checks, @@ -228,7 +227,6 @@ static module_entry_info *module_table[] = { &cm_entry_sco2_csp_ud_pc_tables, &cm_entry_sco2_air_cooler, &cm_entry_sco2_comp_curves, - &cm_entry_sco2_helper, &cm_entry_test_ud_power_cycle, &cm_entry_user_htf_comparison, &cm_entry_ui_udpc_checks, From cd8f24d289ce5a7d6602b1842e52ea526b242a43 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Tue, 23 Sep 2025 16:29:56 -0600 Subject: [PATCH 79/94] Modify htr bypass vartable inputs. --- ssc/csp_common.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index b08e159365..e115480950 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -813,10 +813,10 @@ var_info vtab_sco2_design[] = { { SSC_INPUT, SSC_NUMBER, "N_nodes_air_cooler_pass", "Number of nodes in single air cooler pass", "", "", "Air Cooler Design", "?=10", "", "" }, // HTR Bypass Design - { SSC_INPUT, SSC_NUMBER, "is_bypass_ok", "1 = Yes, 0 = No Bypass, < 0 = fix bp_frac to abs(input)","", "High temperature recuperator", "Heat Exchanger Design", "?=1", "", "" }, + { SSC_INPUT, SSC_NUMBER, "is_bypass_ok", "1 = Yes, 0 = No Bypass, < 0 = fix bp_frac to abs(input)","", "", "System Design", "?=1", "", "" }, { SSC_INPUT, SSC_NUMBER, "T_bypass_target", "HTR BP Cycle Target Temperature", "C", "", "System Design", "cycle_config=3", "", "" }, { SSC_INPUT, SSC_NUMBER, "T_target_is_HTF", "Target Temperature is HTF (1) or cold sco2 at BP", "", "", "System Design", "?=1", "", "" }, - { SSC_INPUT, SSC_NUMBER, "deltaT_bypass", "sco2 Bypass Outlet Temp - HTR_HP_OUT Temp", "C", "", "System Design", "cycle_config=3", "", "" }, + { SSC_INPUT, SSC_NUMBER, "deltaT_bypass", "sco2 Bypass Outlet Temp - HTR_HP_OUT Temp", "C", "", "System Design", "?=0", "", "" }, { SSC_INPUT, SSC_NUMBER, "set_HTF_mdot", "For HTR Bypass ONLY, 0 = calculate HTF mdot (need to set dT_PHX_cold_approach), > 0 = HTF mdot kg/s", "kg/s", "", "System Design", "?=0", "", "" }, // Turbine Split Flow Design From 9ba8a1d3c08c207d56a1d8134b19f3a67b4e0a7d Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Tue, 23 Sep 2025 16:45:50 -0600 Subject: [PATCH 80/94] Add turbine split frac to cmod outputs. --- ssc/csp_common.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index e115480950..0507b9555e 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -852,6 +852,8 @@ var_info vtab_sco2_design[] = { { SSC_OUTPUT, SSC_NUMBER, "T_htf_bp_out_des", "HTF design htr bypass cold temperature (BPX outlet)", "C", "System Design Solution", "", "error_int=0&cycle_config=3", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "dT_htf_des", "HTF temperature difference", "C", "System Design Solution", "", "error_int=0", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "q_dot_in_total", "Total heat from HTF into cycle", "MW", "System Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "turbine_split_frac", "Turbine Split Fraction Solved", "", "System Design Solution", "", "error_int=0&cycle_config=4", "", "" }, + // Compressor { SSC_OUTPUT, SSC_NUMBER, "T_comp_in", "Compressor inlet temperature", "C", "Compressor", "", "error_int=0", "", "" }, { SSC_OUTPUT, SSC_NUMBER, "P_comp_in", "Compressor inlet pressure", "MPa", "Compressor", "", "error_int=0", "", "" }, @@ -1911,6 +1913,12 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c cost_bare_erected_sum += c_sco2_cycle.get_design_solved()->ms_bp_des_solved.m_cost_bare_erected; //[M$]; } + // Add turbine split flow specific outputs + if (s_sco2_des_par.m_cycle_config == 4) + { + cm->assign("turbine_split_frac", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_turbine_split_frac); + } + // Low Pressure Cooler int MC_COOLER_IN_enum = cycle_config == 4 ? C_sco2_cycle_core::MIXER_OUT : C_sco2_cycle_core::LTR_LP_OUT; From f53d9c768830acc6527cda75726af6300bdc6b9c Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Tue, 23 Sep 2025 16:48:47 -0600 Subject: [PATCH 81/94] Remove debug code. --- tcs/sco2_pc_csp_int.cpp | 51 ----------------------------------------- 1 file changed, 51 deletions(-) diff --git a/tcs/sco2_pc_csp_int.cpp b/tcs/sco2_pc_csp_int.cpp index e173ed7a4c..beb6a6d672 100644 --- a/tcs/sco2_pc_csp_int.cpp +++ b/tcs/sco2_pc_csp_int.cpp @@ -505,57 +505,6 @@ int C_sco2_phx_air_cooler::design_core() } } - - //DEBUG - if (true) - { - double cost_LTR = ms_des_solved.ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_bare_erected + ms_des_solved.ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_equipment; - double cost_HTR = ms_des_solved.ms_rc_cycle_solved.ms_HTR_des_solved.m_cost_bare_erected + ms_des_solved.ms_rc_cycle_solved.ms_HTR_des_solved.m_cost_equipment; - double cost_MC = ms_des_solved.ms_rc_cycle_solved.ms_mc_ms_des_solved.m_cost_bare_erected + ms_des_solved.ms_rc_cycle_solved.ms_mc_ms_des_solved.m_cost_equipment; - double cost_RC = ms_des_solved.ms_rc_cycle_solved.ms_rc_ms_des_solved.m_cost_bare_erected + ms_des_solved.ms_rc_cycle_solved.ms_rc_ms_des_solved.m_cost_equipment; - double cost_T = ms_des_solved.ms_rc_cycle_solved.ms_t_des_solved.m_bare_erected_cost + ms_des_solved.ms_rc_cycle_solved.ms_t_des_solved.m_equipment_cost; - double cost_PHX = mc_phx.ms_des_solved.m_cost_bare_erected + mc_phx.ms_des_solved.m_cost_equipment; - double cost_BP = mc_bp.ms_des_solved.m_cost_bare_erected + mc_bp.ms_des_solved.m_cost_equipment; - - double cost_bare_erected = ms_des_solved.ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_bare_erected - + ms_des_solved.ms_rc_cycle_solved.ms_HTR_des_solved.m_cost_bare_erected - + ms_des_solved.ms_rc_cycle_solved.ms_mc_ms_des_solved.m_cost_bare_erected - + ms_des_solved.ms_rc_cycle_solved.ms_rc_ms_des_solved.m_cost_bare_erected - + ms_des_solved.ms_rc_cycle_solved.ms_t_des_solved.m_bare_erected_cost - + mc_phx.ms_des_solved.m_cost_bare_erected; - - double cost_equipment = ms_des_solved.ms_rc_cycle_solved.ms_LTR_des_solved.m_cost_equipment - + ms_des_solved.ms_rc_cycle_solved.ms_HTR_des_solved.m_cost_equipment - + ms_des_solved.ms_rc_cycle_solved.ms_mc_ms_des_solved.m_cost_equipment - + ms_des_solved.ms_rc_cycle_solved.ms_rc_ms_des_solved.m_cost_equipment - + ms_des_solved.ms_rc_cycle_solved.ms_t_des_solved.m_equipment_cost - + mc_phx.ms_des_solved.m_cost_equipment; - - if (std::isnan(mc_bp.ms_des_solved.m_cost_bare_erected) == false) - { - cost_bare_erected += mc_bp.ms_des_solved.m_cost_bare_erected; - cost_equipment += mc_bp.ms_des_solved.m_cost_equipment; - } - - - double total_cost = cost_bare_erected + cost_equipment; - - - // Back Calculate Heat into cycle - double W_net = ms_des_solved.ms_rc_cycle_solved.m_W_dot_mc + ms_des_solved.ms_rc_cycle_solved.m_W_dot_rc + ms_des_solved.ms_rc_cycle_solved.m_W_dot_t; - double Q_pc = ms_des_solved.ms_rc_cycle_solved.m_m_dot_mc * (ms_des_solved.ms_rc_cycle_solved.m_enth[8] - ms_des_solved.ms_rc_cycle_solved.m_enth[0]); - - double Q_tot = W_net + Q_pc; - - - - - - int x = 0; - } - - - return auto_err_code; } From 075cb649b906e3b612e9f87aeebeaa4c8ee205ac Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:08:56 -0600 Subject: [PATCH 82/94] Add unsupported error ENUM. --- tcs/sco2_cycle_templates.h | 3 +++ tcs/sco2_turbinesplitflow_cycle.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tcs/sco2_cycle_templates.h b/tcs/sco2_cycle_templates.h index d926f5d05b..2c0a185fbf 100644 --- a/tcs/sco2_cycle_templates.h +++ b/tcs/sco2_cycle_templates.h @@ -50,6 +50,7 @@ class C_sco2_cycle_core E_ETA_THRESHOLD, E_HTR_LTR_CONVERGENCE, E_AIR_COOLER_CONVERGENCE, + E_NOT_SUPPORTED, E_NO_ERROR }; @@ -73,6 +74,8 @@ class C_sco2_cycle_core return "HTR LTR convergence issue"; case((int)E_AIR_COOLER_CONVERGENCE): return "Air cooler did not converge"; + case((int)E_NOT_SUPPORTED): + return "Feature not supported"; default: return "Error code not recognized"; break; diff --git a/tcs/sco2_turbinesplitflow_cycle.cpp b/tcs/sco2_turbinesplitflow_cycle.cpp index 13c083f64e..7ee71df601 100644 --- a/tcs/sco2_turbinesplitflow_cycle.cpp +++ b/tcs/sco2_turbinesplitflow_cycle.cpp @@ -1124,7 +1124,7 @@ int C_TurbineSplitFlow_Cycle::auto_opt_design(S_auto_opt_design_parameters& auto /// int C_TurbineSplitFlow_Cycle::auto_opt_design_hit_eta(S_auto_opt_design_hit_eta_parameters& auto_opt_des_hit_eta_in, std::string& error_msg) { - return -1; + return C_sco2_cycle_core::E_cycle_error_msg::E_NOT_SUPPORTED; } // ********************************************************************************** PUBLIC Objective Functions (internal use only) From b04ddf0f3901ce9bbd1b14d23e66012aa4415d9d Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:16:10 -0600 Subject: [PATCH 83/94] Modify exception definition to fix Mac bug. --- tcs/csp_solver_util.cpp | 2 +- tcs/csp_solver_util.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tcs/csp_solver_util.cpp b/tcs/csp_solver_util.cpp index 38d2d650ed..500abc709e 100644 --- a/tcs/csp_solver_util.cpp +++ b/tcs/csp_solver_util.cpp @@ -439,7 +439,7 @@ bool C_csp_messages::get_message(std::string *msg) return get_message(&itemp, msg); } -const char* C_csp_exception::what() +const char* C_csp_exception::what() const noexcept { return "CSP exception"; } diff --git a/tcs/csp_solver_util.h b/tcs/csp_solver_util.h index 820e84ef21..9add81103d 100644 --- a/tcs/csp_solver_util.h +++ b/tcs/csp_solver_util.h @@ -235,7 +235,7 @@ class C_csp_exception : public std::exception int m_error_code; // Useful in case exception goes uncatched - virtual const char* what(); + virtual const char* what() const noexcept override; C_csp_exception( const char *msg ); C_csp_exception(const std::string &error_message, const std::string &code_location); From 1ae2933a704f6c6b1010ad7d40526596c9c2fa31 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Wed, 24 Sep 2025 11:04:38 -0600 Subject: [PATCH 84/94] Revert "Modify exception definition to fix Mac bug." This reverts commit b04ddf0f3901ce9bbd1b14d23e66012aa4415d9d. --- tcs/csp_solver_util.cpp | 2 +- tcs/csp_solver_util.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tcs/csp_solver_util.cpp b/tcs/csp_solver_util.cpp index 500abc709e..38d2d650ed 100644 --- a/tcs/csp_solver_util.cpp +++ b/tcs/csp_solver_util.cpp @@ -439,7 +439,7 @@ bool C_csp_messages::get_message(std::string *msg) return get_message(&itemp, msg); } -const char* C_csp_exception::what() const noexcept +const char* C_csp_exception::what() { return "CSP exception"; } diff --git a/tcs/csp_solver_util.h b/tcs/csp_solver_util.h index 9add81103d..820e84ef21 100644 --- a/tcs/csp_solver_util.h +++ b/tcs/csp_solver_util.h @@ -235,7 +235,7 @@ class C_csp_exception : public std::exception int m_error_code; // Useful in case exception goes uncatched - virtual const char* what() const noexcept override; + virtual const char* what(); C_csp_exception( const char *msg ); C_csp_exception(const std::string &error_message, const std::string &code_location); From 5e2c5d00d60fec10dbabec48c26b51aa04edf669 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Thu, 25 Sep 2025 13:40:37 -0600 Subject: [PATCH 85/94] Add check for off design unsupported configs. --- ssc/cmod_sco2_csp_system.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ssc/cmod_sco2_csp_system.cpp b/ssc/cmod_sco2_csp_system.cpp index dfc850bb5a..792f35fe2f 100644 --- a/ssc/cmod_sco2_csp_system.cpp +++ b/ssc/cmod_sco2_csp_system.cpp @@ -453,11 +453,18 @@ class cm_sco2_csp_system : public compute_module P_LP_comp_in_des = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::MC_IN] / 1000.0; //[MPa] convert from kPa delta_P = 10.0; } - else + else if (cycle_config == 2) { P_LP_comp_in_des = c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_pres[C_sco2_cycle_core::PC_IN] / 1000.0; //[MPa] convert from kPa delta_P = 6.0; } + else + { + log("Cycle configuration not supported for off-design"); + std::string err_msg = util::format("Cycle configuration not supported for off-design"); + throw exec_error("sco2_csp_system", err_msg); + return; + } // Get turbine inlet mode int T_t_in_mode = as_integer("od_T_t_in_mode"); From be2bd761f522b55633a1c41517fbd522f801a6f2 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Thu, 25 Sep 2025 15:47:27 -0600 Subject: [PATCH 86/94] Throw error instead of passing through vartable. Add sco2 tests. --- ssc/csp_common.cpp | 7 +- tcs/sco2_cycle_templates.h | 8 +- test/ssc_test/cmod_sco2_csp_system_test.cpp | 129 ++++++++++++++++++++ 3 files changed, 137 insertions(+), 7 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 0507b9555e..ff887c49d8 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -1344,14 +1344,15 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c cm->assign("error_int", cycle_error_enum); // Cycle failed, exit now - if (cycle_error_enum >= (int)C_sco2_cycle_core::E_cycle_error_msg::E_CANNOT_PRODUCE_POWER - && cycle_error_enum < (int)C_sco2_cycle_core::E_cycle_error_msg::E_NO_ERROR) + // tmb 2025-09-25 Now throwing exception, rather than exiting gracefully + if (cycle_error_enum >= (int)C_sco2_cycle_core::E_cycle_error_msg::E_CANNOT_PRODUCE_POWER) { std::string error_text = C_sco2_cycle_core::E_cycle_error_msg::get_error_string(cycle_error_enum); cm->assign("error_msg", error_text); cm->assign("cycle_success", 0); cm->assign("eta_thermal_calc", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_eta_thermal); //[-] - return 0; + + throw exec_error("sco2_csp_system", error_text); } std::string error_text = ""; diff --git a/tcs/sco2_cycle_templates.h b/tcs/sco2_cycle_templates.h index 2c0a185fbf..846ca4f69e 100644 --- a/tcs/sco2_cycle_templates.h +++ b/tcs/sco2_cycle_templates.h @@ -60,6 +60,9 @@ class C_sco2_cycle_core { switch (error_enum) { + case((int)E_NO_ERROR): + return "No error"; + break; case((int)E_CANNOT_PRODUCE_POWER): return "Cycle cannot produce power"; break; @@ -67,15 +70,12 @@ class C_sco2_cycle_core return "Error calculating sCO2 properties"; case((int)E_ETA_THRESHOLD): return "Eta below threshold"; - case((int)E_NO_ERROR): - return "No error"; - break; case((int)E_HTR_LTR_CONVERGENCE): return "HTR LTR convergence issue"; case((int)E_AIR_COOLER_CONVERGENCE): return "Air cooler did not converge"; case((int)E_NOT_SUPPORTED): - return "Feature not supported"; + return "Feature not supported by configuration"; default: return "Error code not recognized"; break; diff --git a/test/ssc_test/cmod_sco2_csp_system_test.cpp b/test/ssc_test/cmod_sco2_csp_system_test.cpp index 8ea56a3c7a..24214e6533 100644 --- a/test/ssc_test/cmod_sco2_csp_system_test.cpp +++ b/test/ssc_test/cmod_sco2_csp_system_test.cpp @@ -35,12 +35,100 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //#include "tcsmolten_salt_defaults.h" #include "csp_common_test.h" #include "vs_google_test_explorer_namespace.h" +#include //#include "../input_cases/code_generator_utilities.h" namespace sco2_tests {} using namespace sco2_tests; +// Helper functions + +ssc_data_t get_default_sco2_pars() +{ + ssc_data_t data = ssc_data_create(); + + // Basic design parameters + ssc_data_set_number(data, "htf", 17); // Solar salt + ssc_data_set_number(data, "T_htf_hot_des", 670.0); // [C] HTF design hot temperature + ssc_data_set_number(data, "dT_PHX_hot_approach", 20.0); // [C/K] Temperature difference between hot HTF and turbine inlet + ssc_data_set_number(data, "T_amb_des", 35.0); // [C] Ambient temperature at design + ssc_data_set_number(data, "dT_mc_approach", 6.0); // [C] Temperature difference between main compressor CO2 inlet and ambient air + ssc_data_set_number(data, "site_elevation", 588); // [m] Elevation + ssc_data_set_number(data, "W_dot_net_des", 50.0); // [MWe] Design cycle power output + + // Cycle configuration + ssc_data_set_number(data, "cycle_config", 1); // [1] = RC, [2] = PC + ssc_data_set_number(data, "design_method", 2); // [-] 1 = specify efficiency, 2 = specify total recup UA, 3 = Specify each recup design + ssc_data_set_number(data, "eta_thermal_des", 0.44); // [-] Target power cycle thermal efficiency + ssc_data_set_number(data, "UA_recup_tot_des", 15000.0); // [kW/K] Total recuperator UA (15 * 1000 * 50.0 / 50.0) + + // Pressure and recompression settings + ssc_data_set_number(data, "is_recomp_ok", 1); // 1 = Yes, 0 = simple cycle only + ssc_data_set_number(data, "is_P_high_fixed", 1); // 0 = No, optimize. 1 = Yes + ssc_data_set_number(data, "is_PR_fixed", 0); // 0 = No, >0 = fixed pressure ratio + ssc_data_set_number(data, "is_IP_fixed", 0); // 0 = No, >0 = fixed HP-IP pressure ratio + + // Convergence criteria + ssc_data_set_number(data, "rel_tol", 3); // [-] Solver relative tolerance exponent + + // Component efficiencies + ssc_data_set_number(data, "eta_isen_mc", 0.85); // [-] Main compressor isentropic efficiency + ssc_data_set_number(data, "eta_isen_rc", 0.85); // [-] Recompressor isentropic efficiency + ssc_data_set_number(data, "eta_isen_pc", 0.85); // [-] Precompressor isentropic efficiency + ssc_data_set_number(data, "eta_isen_t", 0.90); // [-] Turbine isentropic efficiency + + // Pressure limits + ssc_data_set_number(data, "P_high_limit", 25); // [MPa] Cycle high pressure limit + + // Recuperators + double eff_max = 1.0; + double deltaP_recup_HP = 0.0056; // [-] = 0.14[MPa]/25[MPa] + double deltaP_recup_LP = 0.0311; // [-] = 0.28[MPa]/9[MPa] + + // LTR (Low Temperature Recuperator) + ssc_data_set_number(data, "LTR_design_code", 3); // 1 = UA, 2 = min dT, 3 = effectiveness + ssc_data_set_number(data, "LTR_UA_des_in", 2200.0); // [kW/K] + ssc_data_set_number(data, "LTR_min_dT_des_in", 12.0); // [C] + ssc_data_set_number(data, "LTR_eff_des_in", 0.895); // [-] + ssc_data_set_number(data, "LT_recup_eff_max", eff_max); // [-] + ssc_data_set_number(data, "LTR_LP_deltaP_des_in", deltaP_recup_LP); // [-] + ssc_data_set_number(data, "LTR_HP_deltaP_des_in", deltaP_recup_HP); // [-] + + // HTR (High Temperature Recuperator) + ssc_data_set_number(data, "HTR_design_code", 3); // 1 = UA, 2 = min dT, 3 = effectiveness + ssc_data_set_number(data, "HTR_UA_des_in", 2800.0); // [kW/K] + ssc_data_set_number(data, "HTR_min_dT_des_in", 19.2); // [C] + ssc_data_set_number(data, "HTR_eff_des_in", 0.945); // [-] + ssc_data_set_number(data, "HT_recup_eff_max", eff_max); // [-] + ssc_data_set_number(data, "HTR_LP_deltaP_des_in", deltaP_recup_LP); // [-] + ssc_data_set_number(data, "HTR_HP_deltaP_des_in", deltaP_recup_HP); // [-] + + // PHX (Primary Heat Exchanger) + ssc_data_set_number(data, "PHX_co2_deltaP_des_in", deltaP_recup_HP); // [-] + ssc_data_set_number(data, "dT_PHX_cold_approach", 20); // [C/K] + + // Air Cooler + ssc_data_set_number(data, "deltaP_cooler_frac", 0.005); // [-] + ssc_data_set_number(data, "fan_power_frac", 0.02); // [-] + + return data; +} + +void check_result_vals(CmodUnderTest& sco2, std::unordered_map result_map) +{ + for (const auto& result : result_map) + { + std::string key = result.first; + double result_expected = result.second; + double result_actual = sco2.GetOutput(key); + + ASSERT_NEAR(result_expected, result_actual, 1e-5); + } + + return; +} + //========Tests=================================================================================== NAMESPACE_TEST(sco2_tests, SCO2Cycle, Parametrics) { @@ -133,3 +221,44 @@ NAMESPACE_TEST(sco2_tests, SCO2Cycle, Parametrics) } } + +// Using different namespace test name to call directly +NAMESPACE_TEST(sco2_design_tests, SCO2Design, recompression_default) +{ + ssc_data_t data = get_default_sco2_pars(); + CmodUnderTest sco2 = CmodUnderTest("sco2_csp_system", data); + int errors = sco2.RunModule(); + + // Check for errors + ASSERT_TRUE(errors == 0); + + // Define known results + std::unordered_map result_dict; + result_dict["eta_thermal_calc"] = 0.463262886458404; + result_dict["T_htf_cold_des"] = 509.748924586394; + + // Check expected vs actual results + check_result_vals(sco2, result_dict); +} + +// Using different namespace test name to call directly +NAMESPACE_TEST(sco2_design_tests, SCO2Design, tsf_des1_fail) +{ + // Get default parameters + ssc_data_t data = get_default_sco2_pars(); + + // Assign TSF specific pars + ssc_data_set_number(data, "cycle_config", 4); + ssc_data_set_number(data, "is_turbine_split_ok", 1); + ssc_data_set_number(data, "eta_isen_t2", 0.90); + + // Set design method 1 (which TSF does not support) + ssc_data_set_number(data, "design_method", 1); + + // Run cmod + CmodUnderTest sco2 = CmodUnderTest("sco2_csp_system", data); + int errors = sco2.RunModule(); + + // Expect to have errors + ASSERT_FALSE(errors == 0); +} From f5bf2f82ac1c53d7667aa04378426983147addc6 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Thu, 25 Sep 2025 16:42:03 -0600 Subject: [PATCH 87/94] Add sco2 tests. --- test/ssc_test/cmod_sco2_csp_system_test.cpp | 172 +++++++++++++++++++- 1 file changed, 168 insertions(+), 4 deletions(-) diff --git a/test/ssc_test/cmod_sco2_csp_system_test.cpp b/test/ssc_test/cmod_sco2_csp_system_test.cpp index 24214e6533..26c9cb48d7 100644 --- a/test/ssc_test/cmod_sco2_csp_system_test.cpp +++ b/test/ssc_test/cmod_sco2_csp_system_test.cpp @@ -222,10 +222,42 @@ NAMESPACE_TEST(sco2_tests, SCO2Cycle, Parametrics) } -// Using different namespace test name to call directly + +// Design method 2 (optimize with fixed total UA) NAMESPACE_TEST(sco2_design_tests, SCO2Design, recompression_default) { + // This test is design method 2, maximizing efficiency using a fixed total UA, + // optimizing min pressure, UA split, and flow fractions. + + ssc_data_t data = get_default_sco2_pars(); + CmodUnderTest sco2 = CmodUnderTest("sco2_csp_system", data); + int errors = sco2.RunModule(); + + // Check for errors + ASSERT_TRUE(errors == 0); + + // Define known results + std::unordered_map result_dict; + result_dict["eta_thermal_calc"] = 0.46326288645840497; + result_dict["T_htf_cold_des"] = 509.7489245863944; + result_dict["cycle_cost"] = 62.85323351704139; + + // Check expected vs actual results + check_result_vals(sco2, result_dict); +} + +NAMESPACE_TEST(sco2_design_tests, SCO2Design, simple_default) +{ + // This test is design method 2, maximizing efficiency using a fixed total UA, + // optimizing min pressure, UA split, and flow fractions. + + // Get default parameters ssc_data_t data = get_default_sco2_pars(); + + // Set test specific values + ssc_data_set_number(data, "is_recomp_ok", 0); + + // Call cmod CmodUnderTest sco2 = CmodUnderTest("sco2_csp_system", data); int errors = sco2.RunModule(); @@ -234,16 +266,148 @@ NAMESPACE_TEST(sco2_design_tests, SCO2Design, recompression_default) // Define known results std::unordered_map result_dict; - result_dict["eta_thermal_calc"] = 0.463262886458404; - result_dict["T_htf_cold_des"] = 509.748924586394; + result_dict["eta_thermal_calc"] = 0.43185849042562524; + result_dict["T_htf_cold_des"] = 466.8855038441511; + result_dict["cycle_cost"] = 57.323164238332325; // Check expected vs actual results check_result_vals(sco2, result_dict); } -// Using different namespace test name to call directly +NAMESPACE_TEST(sco2_design_tests, SCO2Design, partial_default) +{ + // This test is design method 2, maximizing efficiency using a fixed total UA, + // optimizing min pressure, UA split, and flow fractions. + + // Get default parameters + ssc_data_t data = get_default_sco2_pars(); + + // Set test specific values + ssc_data_set_number(data, "cycle_config", 2); + + // Call cmod + CmodUnderTest sco2 = CmodUnderTest("sco2_csp_system", data); + int errors = sco2.RunModule(); + + // Check for errors + ASSERT_TRUE(errors == 0); + + // Define known results + std::unordered_map result_dict; + result_dict["eta_thermal_calc"] = 0.4680242988429887; + result_dict["T_htf_cold_des"] = 454.4556200450701; + result_dict["cycle_cost"] = 66.2574259286688; + + // Check expected vs actual results + check_result_vals(sco2, result_dict); +} + +NAMESPACE_TEST(sco2_design_tests, SCO2Design, htrbp_default) +{ + // This test is design method 2, maximizing efficiency using a fixed total UA, + // optimizing min pressure, UA split, and flow fractions. + // ALSO, htr bp is varying the bp frac to hit the target outlet temperature + + // Get default parameters + ssc_data_t data = get_default_sco2_pars(); + + // Set test specific values + ssc_data_set_number(data, "cycle_config", 3); + ssc_data_set_number(data, "is_bypass_ok", 1); + ssc_data_set_number(data, "T_bypass_target", 400); + ssc_data_set_number(data, "T_target_is_HTF", 1); + ssc_data_set_number(data, "deltaT_bypass", 0); + ssc_data_set_number(data, "set_HTF_mdot", 0); + + // Call cmod + CmodUnderTest sco2 = CmodUnderTest("sco2_csp_system", data); + int errors = sco2.RunModule(); + + // Check for errors + ASSERT_TRUE(errors == 0); + + // Define known results + std::unordered_map result_dict; + result_dict["eta_thermal_calc"] = 0.33776551440239994; + result_dict["T_htf_cold_des"] = 400.0; + result_dict["cycle_cost"] = 68.82623980549134; + + // Check expected vs actual results + check_result_vals(sco2, result_dict); +} + +NAMESPACE_TEST(sco2_design_tests, SCO2Design, tsf_default) +{ + // This test is design method 2, maximizing efficiency using a fixed total UA, + // optimizing min pressure, UA split, and flow fractions. + + // Get default parameters + ssc_data_t data = get_default_sco2_pars(); + + // Set test specific values + ssc_data_set_number(data, "cycle_config", 4); + ssc_data_set_number(data, "is_turbine_split_ok", 1); + ssc_data_set_number(data, "eta_isen_t2", 0.90); + + // Call cmod + CmodUnderTest sco2 = CmodUnderTest("sco2_csp_system", data); + int errors = sco2.RunModule(); + + // Check for errors + ASSERT_TRUE(errors == 0); + + // Define known results + std::unordered_map result_dict; + result_dict["eta_thermal_calc"] = 0.40642770633106834; + result_dict["T_htf_cold_des"] = 306.45863972890197; + result_dict["cycle_cost"] = 60.89798090322589; + + // Check expected vs actual results + check_result_vals(sco2, result_dict); +} + +// Design method 1 (hit target eta by varying total UA) +NAMESPACE_TEST(sco2_design_tests, SCO2Design, htrbp_des1) +{ + // Design method 2, vary total UA to hit target eta, + // AND vary bypass frac to hit target outlet temp + + // Get default parameters + ssc_data_t data = get_default_sco2_pars(); + + // Set test specific values + ssc_data_set_number(data, "cycle_config", 3); + ssc_data_set_number(data, "design_method", 1); // Hit target eta, vary total UA + ssc_data_set_number(data, "eta_thermal_des", 0.33); // Target eta + ssc_data_set_number(data, "is_bypass_ok", 1); + ssc_data_set_number(data, "T_bypass_target", 400); + ssc_data_set_number(data, "T_target_is_HTF", 1); + ssc_data_set_number(data, "deltaT_bypass", 0); + ssc_data_set_number(data, "set_HTF_mdot", 0); + + // Call cmod + CmodUnderTest sco2 = CmodUnderTest("sco2_csp_system", data); + int errors = sco2.RunModule(); + + // Check for errors + ASSERT_TRUE(errors == 0); + + // Define known results + std::unordered_map result_dict; + result_dict["eta_thermal_calc"] = 0.3377427765707046; + result_dict["T_htf_cold_des"] = 400.00000000000114; + result_dict["cycle_cost"] = 92.73527550752384; + + // Check expected vs actual results + check_result_vals(sco2, result_dict); +} + + +// Fail tests NAMESPACE_TEST(sco2_design_tests, SCO2Design, tsf_des1_fail) { + // This test purposefully fails, by trying to run TSF with design method 1 + // Get default parameters ssc_data_t data = get_default_sco2_pars(); From a02451d5409fe80cc91cb944727482cae25d4c92 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Fri, 26 Sep 2025 08:43:34 -0600 Subject: [PATCH 88/94] Update sco2 tolerance for tests. --- test/ssc_test/cmod_sco2_csp_system_test.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/ssc_test/cmod_sco2_csp_system_test.cpp b/test/ssc_test/cmod_sco2_csp_system_test.cpp index 26c9cb48d7..5586540ce3 100644 --- a/test/ssc_test/cmod_sco2_csp_system_test.cpp +++ b/test/ssc_test/cmod_sco2_csp_system_test.cpp @@ -42,6 +42,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace sco2_tests {} using namespace sco2_tests; +double kTol = 0.01; + // Helper functions ssc_data_t get_default_sco2_pars() @@ -123,7 +125,7 @@ void check_result_vals(CmodUnderTest& sco2, std::unordered_map Date: Mon, 29 Sep 2025 14:20:21 -0600 Subject: [PATCH 89/94] Fix bug with reported mc mdot for TSF. --- ssc/csp_common.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index ff887c49d8..427beebb1a 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -1574,11 +1574,19 @@ int sco2_design_cmod_common(compute_module *cm, C_sco2_phx_air_cooler & c_sco2_c cm->assign("mc_W_dot", (ssc_number_t)(-c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_W_dot_mc*1.E-3)); //[MWe] convert kWe cm->assign("mc_rho_in", (ssc_number_t)(c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_dens[C_sco2_cycle_core::MC_IN])); //[kg/m3] cm->assign("mc_ideal_spec_work", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_ms_des_solved.m_isen_spec_work); //[kJ/kg] - cm->assign("mc_m_dot_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_t*(1.0 - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_recomp_frac)); //[kg/s] - cm->assign("mc_phi_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_ms_des_solved.m_phi_des); //[-] + cm->assign("mc_phi_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_ms_des_solved.m_phi_des); //[-] cm->assign("mc_psi_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_ms_des_solved.m_psi_des); //[-] ideal head coefficient cm->assign("mc_tip_ratio_des", (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.ms_mc_ms_des_solved.m_tip_ratio_max); //[-] + ssc_number_t mc_m_dot_des = std::numeric_limits::quiet_NaN(); + if (cycle_config != 4) + mc_m_dot_des = (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_t * (1.0 - c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_recomp_frac); + else + mc_m_dot_des = (ssc_number_t)c_sco2_cycle.get_design_solved()->ms_rc_cycle_solved.m_m_dot_mc; + + cm->assign("mc_m_dot_des", mc_m_dot_des); //[kg/s] + + double htf_outlet = cm->as_double("cycle_config") == 3 ? T_htf_bypass_out : T_htf_cold_calc; double dT_htf = cm->as_double("T_htf_hot_des") - (htf_outlet - 273.15); cm->assign("dT_htf_des", (ssc_number_t)dT_htf); From 52843d3056000c0af0711983ea5840c7dd0af021 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Tue, 30 Sep 2025 08:55:04 -0600 Subject: [PATCH 90/94] Remove error_int check from vartable outputs. --- ssc/csp_common.cpp | 402 ++++++++++++++++++++++----------------------- 1 file changed, 201 insertions(+), 201 deletions(-) diff --git a/ssc/csp_common.cpp b/ssc/csp_common.cpp index 427beebb1a..7bc6d56235 100644 --- a/ssc/csp_common.cpp +++ b/ssc/csp_common.cpp @@ -837,224 +837,224 @@ var_info vtab_sco2_design[] = { // System Design Solution - { SSC_OUTPUT, SSC_NUMBER, "T_htf_cold_des", "HTF design cold temperature (HTF outlet)", "C", "System Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_htf_phx_out_des", "HTF design phx cold temperature (PHX outlet)", "C", "System Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "m_dot_htf_des", "HTF mass flow rate", "kg/s", "System Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "eta_thermal_calc", "Calculated cycle thermal efficiency", "-", "System Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "m_dot_co2_full", "CO2 mass flow rate through HTR, PHX, turbine", "kg/s", "System Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "recomp_frac", "Recompression fraction", "-", "System Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "bypass_frac", "Bypass fraction", "-", "System Design Solution", "", "error_int=0&cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "cycle_cost", "Cycle cost bare erected", "M$", "System Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "cycle_spec_cost", "Cycle specific cost bare erected", "$/kWe", "System Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "cycle_spec_cost_thermal", "Cycle specific (thermal) cost bare erected", "$/kWt", "System Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "W_dot_net_less_cooling", "System power output subtracting cooling parastics", "MWe," "System Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "eta_thermal_net_less_cooling_des","Calculated cycle thermal efficiency using W_dot_net_less_cooling", "-", "System Design Solution","", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_htf_bp_out_des", "HTF design htr bypass cold temperature (BPX outlet)", "C", "System Design Solution", "", "error_int=0&cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "dT_htf_des", "HTF temperature difference", "C", "System Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "q_dot_in_total", "Total heat from HTF into cycle", "MW", "System Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "turbine_split_frac", "Turbine Split Fraction Solved", "", "System Design Solution", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_htf_cold_des", "HTF design cold temperature (HTF outlet)", "C", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_htf_phx_out_des", "HTF design phx cold temperature (PHX outlet)", "C", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "m_dot_htf_des", "HTF mass flow rate", "kg/s", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "eta_thermal_calc", "Calculated cycle thermal efficiency", "-", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "m_dot_co2_full", "CO2 mass flow rate through HTR, PHX, turbine", "kg/s", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "recomp_frac", "Recompression fraction", "-", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "bypass_frac", "Bypass fraction", "-", "System Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cycle_cost", "Cycle cost bare erected", "M$", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cycle_spec_cost", "Cycle specific cost bare erected", "$/kWe", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cycle_spec_cost_thermal", "Cycle specific (thermal) cost bare erected", "$/kWt", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "W_dot_net_less_cooling", "System power output subtracting cooling parastics", "MWe," "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "eta_thermal_net_less_cooling_des","Calculated cycle thermal efficiency using W_dot_net_less_cooling", "-", "System Design Solution","", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_htf_bp_out_des", "HTF design htr bypass cold temperature (BPX outlet)", "C", "System Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "dT_htf_des", "HTF temperature difference", "C", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "q_dot_in_total", "Total heat from HTF into cycle", "MW", "System Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "turbine_split_frac", "Turbine Split Fraction Solved", "", "System Design Solution", "", "cycle_config=4", "", "" }, // Compressor - { SSC_OUTPUT, SSC_NUMBER, "T_comp_in", "Compressor inlet temperature", "C", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "P_comp_in", "Compressor inlet pressure", "MPa", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "P_comp_out", "Compressor outlet pressure", "MPa", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_T_out", "Compressor outlet temperature", "C", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_W_dot", "Compressor power", "MWe", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_m_dot_des", "Compressor mass flow rate", "kg/s", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_rho_in", "Compressor inlet density", "kg/m3", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_ideal_spec_work", "Compressor ideal spec work", "kJ/kg", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_phi_des", "Compressor design flow coefficient", "", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_psi_des", "Compressor design ideal head coefficient", "", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mc_tip_ratio_des", "Compressor design stage tip speed ratio", "", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_n_stages", "Compressor stages", "", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_N_des", "Compressor design shaft speed", "rpm", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mc_D", "Compressor stage diameters", "m", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_phi_surge", "Compressor flow coefficient where surge occurs", "", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_psi_max_at_N_des", "Compressor max ideal head coefficient at design shaft speed", "", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "mc_eta_stages_des", "Compressor design stage isentropic efficiencies", "", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cost_equipment", "Compressor cost equipment", "M$", "Compressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cost_bare_erected", "Compressor cost equipment plus install", "M$", "Compressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_comp_in", "Compressor inlet temperature", "C", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "P_comp_in", "Compressor inlet pressure", "MPa", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "P_comp_out", "Compressor outlet pressure", "MPa", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_T_out", "Compressor outlet temperature", "C", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_W_dot", "Compressor power", "MWe", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_m_dot_des", "Compressor mass flow rate", "kg/s", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_rho_in", "Compressor inlet density", "kg/m3", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_ideal_spec_work", "Compressor ideal spec work", "kJ/kg", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_phi_des", "Compressor design flow coefficient", "", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_psi_des", "Compressor design ideal head coefficient", "", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "mc_tip_ratio_des", "Compressor design stage tip speed ratio", "", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_n_stages", "Compressor stages", "", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_N_des", "Compressor design shaft speed", "rpm", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "mc_D", "Compressor stage diameters", "m", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_phi_surge", "Compressor flow coefficient where surge occurs", "", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_psi_max_at_N_des", "Compressor max ideal head coefficient at design shaft speed", "", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "mc_eta_stages_des", "Compressor design stage isentropic efficiencies", "", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cost_equipment", "Compressor cost equipment", "M$", "Compressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cost_bare_erected", "Compressor cost equipment plus install", "M$", "Compressor", "", "*", "", "" }, // Recompressor - { SSC_OUTPUT, SSC_NUMBER, "rc_T_in_des", "Recompressor inlet temperature", "C", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_P_in_des", "Recompressor inlet pressure", "MPa", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_T_out_des", "Recompressor inlet temperature", "C", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_P_out_des", "Recompressor inlet pressure", "MPa", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_W_dot", "Recompressor power", "MWe", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_m_dot_des", "Recompressor mass flow rate", "kg/s", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_phi_des", "Recompressor design flow coefficient", "", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_psi_des", "Recompressor design ideal head coefficient", "", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "rc_tip_ratio_des", "Recompressor design stage tip speed ratio", "", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_n_stages", "Recompressor stages", "", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_N_des", "Recompressor design shaft speed", "rpm", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "rc_D", "Recompressor stage diameters", "m", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_phi_surge", "Recompressor flow coefficient where surge occurs", "", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_psi_max_at_N_des", "Recompressor max ideal head coefficient at design shaft speed", "", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "rc_eta_stages_des", "Recompressor design stage isenstropic efficiencies", "", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_cost_equipment", "Recompressor cost equipment", "M$", "Recompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "rc_cost_bare_erected", "Recompressor cost equipment plus install", "M$", "Recompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_T_in_des", "Recompressor inlet temperature", "C", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_P_in_des", "Recompressor inlet pressure", "MPa", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_T_out_des", "Recompressor inlet temperature", "C", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_P_out_des", "Recompressor inlet pressure", "MPa", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_W_dot", "Recompressor power", "MWe", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_m_dot_des", "Recompressor mass flow rate", "kg/s", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_phi_des", "Recompressor design flow coefficient", "", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_psi_des", "Recompressor design ideal head coefficient", "", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "rc_tip_ratio_des", "Recompressor design stage tip speed ratio", "", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_n_stages", "Recompressor stages", "", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_N_des", "Recompressor design shaft speed", "rpm", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "rc_D", "Recompressor stage diameters", "m", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_phi_surge", "Recompressor flow coefficient where surge occurs", "", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_psi_max_at_N_des", "Recompressor max ideal head coefficient at design shaft speed", "", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "rc_eta_stages_des", "Recompressor design stage isenstropic efficiencies", "", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_cost_equipment", "Recompressor cost equipment", "M$", "Recompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "rc_cost_bare_erected", "Recompressor cost equipment plus install", "M$", "Recompressor", "", "*", "", "" }, // Precompressor - { SSC_OUTPUT, SSC_NUMBER, "pc_T_in_des", "Precompressor inlet temperature", "C", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_P_in_des", "Precompressor inlet pressure", "MPa", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_W_dot", "Precompressor power", "MWe", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_m_dot_des", "Precompressor mass flow rate", "kg/s", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_rho_in_des", "Precompressor inlet density", "kg/m3", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_ideal_spec_work_des", "Precompressor ideal spec work", "kJ/kg", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_phi_des", "Precompressor design flow coefficient", "", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "pc_tip_ratio_des", "Precompressor design stage tip speed ratio", "", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_n_stages", "Precompressor stages", "", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_N_des", "Precompressor design shaft speed", "rpm", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "pc_D", "Precompressor stage diameters", "m", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_phi_surge", "Precompressor flow coefficient where surge occurs", "", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "pc_eta_stages_des", "Precompressor design stage isenstropic efficiencies", "", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cost_equipment", "Precompressor cost equipment", "M$", "Precompressor", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cost_bare_erected", "Precompressor cost equipment plus install", "M$", "Precompressor", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_T_in_des", "Precompressor inlet temperature", "C", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_P_in_des", "Precompressor inlet pressure", "MPa", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_W_dot", "Precompressor power", "MWe", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_m_dot_des", "Precompressor mass flow rate", "kg/s", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_rho_in_des", "Precompressor inlet density", "kg/m3", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_ideal_spec_work_des", "Precompressor ideal spec work", "kJ/kg", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_phi_des", "Precompressor design flow coefficient", "", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "pc_tip_ratio_des", "Precompressor design stage tip speed ratio", "", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_n_stages", "Precompressor stages", "", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_N_des", "Precompressor design shaft speed", "rpm", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "pc_D", "Precompressor stage diameters", "m", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_phi_surge", "Precompressor flow coefficient where surge occurs", "", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "pc_eta_stages_des", "Precompressor design stage isenstropic efficiencies", "", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cost_equipment", "Precompressor cost equipment", "M$", "Precompressor", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cost_bare_erected", "Precompressor cost equipment plus install", "M$", "Precompressor", "", "*", "", "" }, // Compressor Totals - { SSC_OUTPUT, SSC_NUMBER, "c_tot_cost_equip", "Compressor total cost", "M$", "Compressor Totals", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "c_tot_W_dot", "Compressor total summed power", "MWe", "Compressor Totals", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "c_tot_cost_equip", "Compressor total cost", "M$", "Compressor Totals", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "c_tot_W_dot", "Compressor total summed power", "MWe", "Compressor Totals", "", "*", "", "" }, // Turbine - { SSC_OUTPUT, SSC_NUMBER, "t_W_dot", "Turbine power", "MWe", "Turbine", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_m_dot_des", "Turbine mass flow rate", "kg/s", "Turbine", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_turb_in", "Turbine inlet temperature", "C", "Turbine", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_P_in_des", "Turbine design inlet pressure", "MPa", "Turbine", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_T_out_des", "Turbine outlet temperature", "C", "Turbine", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_P_out_des", "Turbine design outlet pressure", "MPa", "Turbine", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_delta_h_isen_des", "Turbine isentropic specific work", "kJ/kg", "Turbine", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_rho_in_des", "Turbine inlet density", "kg/m3", "Turbine", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_nu_des", "Turbine design velocity ratio", "", "Turbine", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_tip_ratio_des", "Turbine design tip speed ratio", "", "Turbine", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_N_des", "Turbine design shaft speed", "rpm", "Turbine", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_D", "Turbine diameter", "m", "Turbine", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_cost_equipment", "Tubine cost - equipment", "M$", "Turbine", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t_cost_bare_erected", "Tubine cost - equipment plus install", "M$", "Turbine", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_W_dot", "Turbine power", "MWe", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_m_dot_des", "Turbine mass flow rate", "kg/s", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_turb_in", "Turbine inlet temperature", "C", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_P_in_des", "Turbine design inlet pressure", "MPa", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_T_out_des", "Turbine outlet temperature", "C", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_P_out_des", "Turbine design outlet pressure", "MPa", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_delta_h_isen_des", "Turbine isentropic specific work", "kJ/kg", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_rho_in_des", "Turbine inlet density", "kg/m3", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_nu_des", "Turbine design velocity ratio", "", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_tip_ratio_des", "Turbine design tip speed ratio", "", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_N_des", "Turbine design shaft speed", "rpm", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_D", "Turbine diameter", "m", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_cost_equipment", "Tubine cost - equipment", "M$", "Turbine", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t_cost_bare_erected", "Tubine cost - equipment plus install", "M$", "Turbine", "", "*", "", "" }, // Secondary Turbine (TSF cycle only) - { SSC_OUTPUT, SSC_NUMBER, "t2_W_dot", "Secondary Turbine power", "MWe", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_m_dot_des", "Secondary Turbine mass flow rate", "kg/s", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_turb2_in", "Secondary Turbine inlet temperature", "C", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_P_in_des", "Secondary Turbine design inlet pressure", "MPa", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_T_out_des", "Secondary Turbine outlet temperature", "C", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_P_out_des", "Secondary Turbine design outlet pressure", "MPa", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_delta_h_isen_des", "Secondary Turbine isentropic specific work", "kJ/kg", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_rho_in_des", "Secondary Turbine inlet density", "kg/m3", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_nu_des", "Secondary Turbine design velocity ratio", "", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_tip_ratio_des", "Secondary Turbine design tip speed ratio", "", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_N_des", "Secondary Turbine design shaft speed", "rpm", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_D", "Secondary Turbine diameter", "m", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_cost_equipment", "Secondary Tubine cost - equipment", "M$", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "t2_cost_bare_erected", "Secondary Tubine cost - equipment plus install", "M$", "Turbine 2", "", "error_int=0&cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_W_dot", "Secondary Turbine power", "MWe", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_m_dot_des", "Secondary Turbine mass flow rate", "kg/s", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_turb2_in", "Secondary Turbine inlet temperature", "C", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_P_in_des", "Secondary Turbine design inlet pressure", "MPa", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_T_out_des", "Secondary Turbine outlet temperature", "C", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_P_out_des", "Secondary Turbine design outlet pressure", "MPa", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_delta_h_isen_des", "Secondary Turbine isentropic specific work", "kJ/kg", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_rho_in_des", "Secondary Turbine inlet density", "kg/m3", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_nu_des", "Secondary Turbine design velocity ratio", "", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_tip_ratio_des", "Secondary Turbine design tip speed ratio", "", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_N_des", "Secondary Turbine design shaft speed", "rpm", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_D", "Secondary Turbine diameter", "m", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_cost_equipment", "Secondary Tubine cost - equipment", "M$", "Turbine 2", "", "cycle_config=4", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "t2_cost_bare_erected", "Secondary Tubine cost - equipment plus install", "M$", "Turbine 2", "", "cycle_config=4", "", "" }, // Recuperators - { SSC_OUTPUT, SSC_NUMBER, "recup_total_UA_assigned", "Total recuperator UA assigned to design routine", "MW/K", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "recup_total_UA_calculated", "Total recuperator UA calculated considering max eff and/or min temp diff parameter", "MW/K", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "recup_total_cost_equipment","Total recuperator cost equipment", "M$", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "recup_total_cost_bare_erected","Total recuperator cost bare erected", "M$", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "recup_LTR_UA_frac", "Fraction of total conductance to LTR", "", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_HP_T_out_des", "Low temp recuperator HP outlet temperature", "C", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_UA_assigned", "Low temp recuperator UA assigned from total", "MW/K", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_UA_calculated", "Low temp recuperator UA calculated considering max eff and/or min temp diff parameter", "MW/K", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "eff_LTR", "Low temp recuperator effectiveness", "", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "NTU_LTR", "Low temp recuperator NTU", "", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "q_dot_LTR", "Low temp recuperator heat transfer", "MWt", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_LP_deltaP_des", "Low temp recuperator low pressure design pressure drop", "-", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_HP_deltaP_des", "Low temp recuperator high pressure design pressure drop","-", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_min_dT", "Low temp recuperator min temperature difference", "C", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_cost_equipment", "Low temp recuperator cost equipment", "M$", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "LTR_cost_bare_erected","Low temp recuperator cost equipment and install", "M$", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_LP_T_out_des", "High temp recuperator LP outlet temperature", "C", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_HP_T_in_des", "High temp recuperator HP inlet temperature", "C", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_UA_assigned", "High temp recuperator UA assigned from total", "MW/K", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_UA_calculated", "High temp recuperator UA calculated considering max eff and/or min temp diff parameter", "MW/K", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "eff_HTR", "High temp recuperator effectiveness", "", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "NTU_HTR", "High temp recuperator NTRU", "", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "q_dot_HTR", "High temp recuperator heat transfer", "MWt", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_LP_deltaP_des", "High temp recuperator low pressure design pressure drop","-", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_HP_deltaP_des", "High temp recuperator high pressure design pressure drop","-", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_min_dT", "High temp recuperator min temperature difference", "C", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_cost_equipment", "High temp recuperator cost equipment", "M$", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_cost_bare_erected","High temp recuperator cost equipment and install", "M$", "Recuperators", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "HTR_HP_m_dot", "High temp recuperator high pressure mass flow rate", "kg/s", "Recuperators", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "recup_total_UA_assigned", "Total recuperator UA assigned to design routine", "MW/K", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "recup_total_UA_calculated", "Total recuperator UA calculated considering max eff and/or min temp diff parameter", "MW/K", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "recup_total_cost_equipment","Total recuperator cost equipment", "M$", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "recup_total_cost_bare_erected","Total recuperator cost bare erected", "M$", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "recup_LTR_UA_frac", "Fraction of total conductance to LTR", "", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_HP_T_out_des", "Low temp recuperator HP outlet temperature", "C", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_UA_assigned", "Low temp recuperator UA assigned from total", "MW/K", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_UA_calculated", "Low temp recuperator UA calculated considering max eff and/or min temp diff parameter", "MW/K", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "eff_LTR", "Low temp recuperator effectiveness", "", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "NTU_LTR", "Low temp recuperator NTU", "", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "q_dot_LTR", "Low temp recuperator heat transfer", "MWt", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_LP_deltaP_des", "Low temp recuperator low pressure design pressure drop", "-", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_HP_deltaP_des", "Low temp recuperator high pressure design pressure drop","-", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_min_dT", "Low temp recuperator min temperature difference", "C", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_cost_equipment", "Low temp recuperator cost equipment", "M$", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "LTR_cost_bare_erected","Low temp recuperator cost equipment and install", "M$", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_LP_T_out_des", "High temp recuperator LP outlet temperature", "C", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_HP_T_in_des", "High temp recuperator HP inlet temperature", "C", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_UA_assigned", "High temp recuperator UA assigned from total", "MW/K", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_UA_calculated", "High temp recuperator UA calculated considering max eff and/or min temp diff parameter", "MW/K", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "eff_HTR", "High temp recuperator effectiveness", "", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "NTU_HTR", "High temp recuperator NTRU", "", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "q_dot_HTR", "High temp recuperator heat transfer", "MWt", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_LP_deltaP_des", "High temp recuperator low pressure design pressure drop","-", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_HP_deltaP_des", "High temp recuperator high pressure design pressure drop","-", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_min_dT", "High temp recuperator min temperature difference", "C", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_cost_equipment", "High temp recuperator cost equipment", "M$", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_cost_bare_erected","High temp recuperator cost equipment and install", "M$", "Recuperators", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "HTR_HP_m_dot", "High temp recuperator high pressure mass flow rate", "kg/s", "Recuperators", "", "*", "", "" }, // PHX Design Solution - { SSC_OUTPUT, SSC_NUMBER, "UA_PHX", "PHX Conductance", "MW/K", "PHX Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "eff_PHX", "PHX effectiveness", "", "PHX Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "NTU_PHX", "PHX NTU", "", "PHX Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_co2_PHX_in", "CO2 temperature at PHX inlet", "C", "PHX Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "P_co2_PHX_in", "CO2 pressure at PHX inlet", "MPa", "PHX Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "deltaT_HTF_PHX", "HTF temp difference across PHX", "C", "PHX Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "q_dot_PHX", "PHX heat transfer", "MWt", "PHX Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "PHX_co2_deltaP_des", "PHX co2 side design pressure drop", "-", "PHX Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "PHX_cost_equipment", "PHX cost equipment", "M$", "PHX Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "PHX_cost_bare_erected","PHX cost equipment and install", "M$", "PHX Design Solution", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "PHX_min_dT", "PHX min temperature difference", "C", "PHX Design Solution", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "UA_PHX", "PHX Conductance", "MW/K", "PHX Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "eff_PHX", "PHX effectiveness", "", "PHX Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "NTU_PHX", "PHX NTU", "", "PHX Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_co2_PHX_in", "CO2 temperature at PHX inlet", "C", "PHX Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "P_co2_PHX_in", "CO2 pressure at PHX inlet", "MPa", "PHX Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "deltaT_HTF_PHX", "HTF temp difference across PHX", "C", "PHX Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "q_dot_PHX", "PHX heat transfer", "MWt", "PHX Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "PHX_co2_deltaP_des", "PHX co2 side design pressure drop", "-", "PHX Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "PHX_cost_equipment", "PHX cost equipment", "M$", "PHX Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "PHX_cost_bare_erected","PHX cost equipment and install", "M$", "PHX Design Solution", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "PHX_min_dT", "PHX min temperature difference", "C", "PHX Design Solution", "", "*", "", "" }, // BPX Design Solution - { SSC_OUTPUT, SSC_NUMBER, "UA_BPX", "BPX Conductance", "MW/K", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "eff_BPX", "BPX effectiveness", "", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "NTU_BPX", "BPX NTU", "", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "T_co2_BPX_in", "CO2 temperature at BPX inlet", "C", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "P_co2_BPX_in", "CO2 pressure at BPX inlet", "MPa", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "deltaT_HTF_BPX", "HTF temp difference across BPX", "C", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "q_dot_BPX", "BPX heat transfer", "MWt", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "BPX_co2_deltaP_des", "BPX co2 side design pressure drop", "-", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "BPX_cost_equipment", "BPX cost equipment", "M$", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "BPX_cost_bare_erected","BPX cost equipment and install", "M$", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "BPX_min_dT", "BPX min temperature difference", "C", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "BPX_m_dot", "BPX sco2 mass flow rate", "kg/s", "BPX Design Solution", "", "error_int=0&cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "UA_BPX", "BPX Conductance", "MW/K", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "eff_BPX", "BPX effectiveness", "", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "NTU_BPX", "BPX NTU", "", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "T_co2_BPX_in", "CO2 temperature at BPX inlet", "C", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "P_co2_BPX_in", "CO2 pressure at BPX inlet", "MPa", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "deltaT_HTF_BPX", "HTF temp difference across BPX", "C", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "q_dot_BPX", "BPX heat transfer", "MWt", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_co2_deltaP_des", "BPX co2 side design pressure drop", "-", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_cost_equipment", "BPX cost equipment", "M$", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_cost_bare_erected","BPX cost equipment and install", "M$", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_min_dT", "BPX min temperature difference", "C", "BPX Design Solution", "", "cycle_config=3", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "BPX_m_dot", "BPX sco2 mass flow rate", "kg/s", "BPX Design Solution", "", "cycle_config=3", "", "" }, // main compressor cooler - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_T_in", "Low pressure cross flow cooler inlet temperature", "C", "Low Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_P_in", "Low pressure cross flow cooler inlet pressure", "MPa", "Low Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_rho_in", "Low pressure cross flow cooler inlet density", "kg/m3", "Low Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_in_isen_deltah_to_P_mc_out", "Low pressure cross flow cooler inlet isen enthalpy rise to mc outlet pressure", "kJ/kg", "Low Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_m_dot_co2", "Low pressure cross flow cooler CO2 mass flow rate", "kg/s", "Low Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_UA", "Low pressure cross flow cooler conductance", "MW/K", "Low Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_q_dot", "Low pressure cooler heat transfer", "MWt", "Low Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_co2_deltaP_des","Low pressure cooler co2 side design pressure drop", "-", "Low Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_W_dot_fan", "Low pressure cooler fan power", "MWe", "Low Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_cost_equipment","Low pressure cooler cost equipment", "M$", "Low Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_cost_bare_erected","Low pressure cooler cost equipment and install", "M$", "Low Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_T_in", "Low pressure cross flow cooler inlet temperature", "C", "Low Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_P_in", "Low pressure cross flow cooler inlet pressure", "MPa", "Low Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_rho_in", "Low pressure cross flow cooler inlet density", "kg/m3", "Low Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_in_isen_deltah_to_P_mc_out", "Low pressure cross flow cooler inlet isen enthalpy rise to mc outlet pressure", "kJ/kg", "Low Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_m_dot_co2", "Low pressure cross flow cooler CO2 mass flow rate", "kg/s", "Low Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_UA", "Low pressure cross flow cooler conductance", "MW/K", "Low Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_q_dot", "Low pressure cooler heat transfer", "MWt", "Low Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_co2_deltaP_des","Low pressure cooler co2 side design pressure drop", "-", "Low Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_W_dot_fan", "Low pressure cooler fan power", "MWe", "Low Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_cost_equipment","Low pressure cooler cost equipment", "M$", "Low Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "mc_cooler_cost_bare_erected","Low pressure cooler cost equipment and install", "M$", "Low Pressure Cooler", "", "*", "", "" }, // pre compressor cooler - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_T_in", "Intermediate pressure cross flow cooler inlet temperature", "C", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_P_in", "Intermediate pressure cross flow cooler inlet pressure", "MPa", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_m_dot_co2", "Intermediate pressure cross flow cooler CO2 mass flow rate", "kg/s", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_UA", "Intermediate pressure cross flow cooler conductance", "MW/K", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_q_dot", "Intermediate pressure cooler heat transfer", "MWt", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_W_dot_fan", "Intermediate pressure cooler fan power", "MWe", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_cost_equipment","Intermediate pressure cooler cost equipment", "M$", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_cost_bare_erected","Intermediate pressure cooler cost equipment and install", "M$", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_T_in", "Intermediate pressure cross flow cooler inlet temperature", "C", "Intermediate Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_P_in", "Intermediate pressure cross flow cooler inlet pressure", "MPa", "Intermediate Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_m_dot_co2", "Intermediate pressure cross flow cooler CO2 mass flow rate", "kg/s", "Intermediate Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_UA", "Intermediate pressure cross flow cooler conductance", "MW/K", "Intermediate Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_q_dot", "Intermediate pressure cooler heat transfer", "MWt", "Intermediate Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_W_dot_fan", "Intermediate pressure cooler fan power", "MWe", "Intermediate Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_cost_equipment","Intermediate pressure cooler cost equipment", "M$", "Intermediate Pressure Cooler", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "pc_cooler_cost_bare_erected","Intermediate pressure cooler cost equipment and install", "M$", "Intermediate Pressure Cooler", "", "*", "", "" }, // piping_inventory_etc_cost - { SSC_OUTPUT, SSC_NUMBER, "piping_inventory_etc_cost","Cost of remaining cycle equipment on BEC basis", "M$", "Intermediate Pressure Cooler", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "piping_inventory_etc_cost","Cost of remaining cycle equipment on BEC basis", "M$", "Intermediate Pressure Cooler", "", "*", "", "" }, // Cooler Totals - { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_cost_equipment", "Total cooler cost equipment", "M$", "Cooler Totals", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_cost_bare_erected","Total cooler cost equipment and install", "M$", "Cooler Totals", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_UA", "Total cooler conductance", "MW/K", "Cooler Totals", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_W_dot_fan", "Total cooler fan power", "MWe", "Cooler Totals", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_cost_equipment", "Total cooler cost equipment", "M$", "Cooler Totals", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_cost_bare_erected","Total cooler cost equipment and install", "M$", "Cooler Totals", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_UA", "Total cooler conductance", "MW/K", "Cooler Totals", "", "*", "", "" }, + { SSC_OUTPUT, SSC_NUMBER, "cooler_tot_W_dot_fan", "Total cooler fan power", "MWe", "Cooler Totals", "", "*", "", "" }, // State Points - { SSC_OUTPUT, SSC_ARRAY, "T_state_points", "Cycle temperature state points", "C", "State Points", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_state_points", "Cycle pressure state points", "MPa", "State Points", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_state_points", "Cycle entropy state points", "kJ/kg-K", "State Points", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_state_points", "Cycle enthalpy state points", "kJ/kg", "State Points", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_state_points", "Cycle temperature state points", "C", "State Points", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_state_points", "Cycle pressure state points", "MPa", "State Points", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_state_points", "Cycle entropy state points", "kJ/kg-K", "State Points", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_state_points", "Cycle enthalpy state points", "kJ/kg", "State Points", "", "*", "", "" }, // T-s plot data - { SSC_OUTPUT, SSC_ARRAY, "T_LTR_HP_data", "Temperature points along LTR HP stream", "C", "T-s plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_LTR_HP_data", "Entropy points along LTR HP stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_HTR_HP_data", "Temperature points along HTR HP stream", "C", "T-s plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_HTR_HP_data", "Entropy points along HTR HP stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_PHX_data", "Temperature points along PHX stream", "C", "T-s plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_PHX_data", "Entropy points along PHX stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_HTR_LP_data", "Temperature points along HTR LP stream", "C", "T-s plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_HTR_LP_data", "Entropy points along HTR LP stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_LTR_LP_data", "Temperature points along LTR LP stream", "C", "T-s plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_LTR_LP_data", "Entropy points along LTR LP stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_main_cooler_data", "Temperature points along main cooler stream", "C", "T-s plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_main_cooler_data", "Entropy points along main cooler stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "T_pre_cooler_data", "Temperature points along pre cooler stream", "C", "T-s plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "s_pre_cooler_data", "Entropy points along pre cooler stream", "kJ/kg-K", "T-s plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_LTR_HP_data", "Temperature points along LTR HP stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_LTR_HP_data", "Entropy points along LTR HP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_HTR_HP_data", "Temperature points along HTR HP stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_HTR_HP_data", "Entropy points along HTR HP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_PHX_data", "Temperature points along PHX stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_PHX_data", "Entropy points along PHX stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_HTR_LP_data", "Temperature points along HTR LP stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_HTR_LP_data", "Entropy points along HTR LP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_LTR_LP_data", "Temperature points along LTR LP stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_LTR_LP_data", "Entropy points along LTR LP stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_main_cooler_data", "Temperature points along main cooler stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_main_cooler_data", "Entropy points along main cooler stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "T_pre_cooler_data", "Temperature points along pre cooler stream", "C", "T-s plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "s_pre_cooler_data", "Entropy points along pre cooler stream", "kJ/kg-K", "T-s plot data", "", "*", "", "" }, // P-h plot data - { SSC_OUTPUT, SSC_ARRAY, "P_t_data", "Pressure points along turbine expansion", "MPa", "P-h plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_t_data", "Enthalpy points along turbine expansion", "kJ/kg", "P-h plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_mc_data", "Pressure points along main compression", "MPa", "P-h plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_mc_data", "Enthalpy points along main compression", "kJ/kg", "P-h plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_rc_data", "Pressure points along re compression", "MPa", "P-h plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_rc_data", "Enthalpy points along re compression", "kJ/kg", "P-h plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_pc_data", "Pressure points along pre compression", "MPa", "P-h plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_pc_data", "Enthalpy points along pre compression", "kJ/kg", "P-h plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "P_t2_data", "Pressure points along secondary turbine expansion", "MPa", "P-h plot data", "", "error_int=0", "", "" }, - { SSC_OUTPUT, SSC_ARRAY, "h_t2_data", "Enthalpy points along secondary turbine expansion", "kJ/kg", "P-h plot data", "", "error_int=0", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_t_data", "Pressure points along turbine expansion", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_t_data", "Enthalpy points along turbine expansion", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_mc_data", "Pressure points along main compression", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_mc_data", "Enthalpy points along main compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_rc_data", "Pressure points along re compression", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_rc_data", "Enthalpy points along re compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_pc_data", "Pressure points along pre compression", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_pc_data", "Enthalpy points along pre compression", "kJ/kg", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "P_t2_data", "Pressure points along secondary turbine expansion", "MPa", "P-h plot data", "", "*", "", "" }, + { SSC_OUTPUT, SSC_ARRAY, "h_t2_data", "Enthalpy points along secondary turbine expansion", "kJ/kg", "P-h plot data", "", "*", "", "" }, var_info_invalid }; From 11a6f1e488f0b8bef9c3d38000e422b82e8a17f3 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Thu, 9 Oct 2025 12:00:44 -0600 Subject: [PATCH 91/94] Replace hardcoded inflation year with variable. --- tcs/heat_exchangers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcs/heat_exchangers.cpp b/tcs/heat_exchangers.cpp index 10e8f5e850..eecb3d4eaa 100644 --- a/tcs/heat_exchangers.cpp +++ b/tcs/heat_exchangers.cpp @@ -2006,7 +2006,7 @@ void C_HX_counterflow_CRM::design_calc_UA_TP_to_PH(C_HX_counterflow_CRM::S_des_c ms_des_solved.m_cost_equipment = calculate_equipment_cost(ms_des_solved.m_UA_design, ms_des_calc_UA_par.m_T_h_in, ms_des_calc_UA_par.m_P_h_in, ms_des_calc_UA_par.m_m_dot_hot_des, - ms_des_calc_UA_par.m_T_c_in, ms_des_calc_UA_par.m_P_c_in, ms_des_calc_UA_par.m_m_dot_cold_des, 2024.0); + ms_des_calc_UA_par.m_T_c_in, ms_des_calc_UA_par.m_P_c_in, ms_des_calc_UA_par.m_m_dot_cold_des, m_yr_inflation); ms_des_solved.m_cost_bare_erected = calculate_bare_erected_cost(ms_des_solved.m_cost_equipment); From 1605250d7a02553388a86b422e9b2af04ee50b79 Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Thu, 9 Oct 2025 12:01:40 -0600 Subject: [PATCH 92/94] Fix tsf comment. --- tcs/sco2_turbinesplitflow_cycle.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcs/sco2_turbinesplitflow_cycle.h b/tcs/sco2_turbinesplitflow_cycle.h index d96aa80971..21360294f1 100644 --- a/tcs/sco2_turbinesplitflow_cycle.h +++ b/tcs/sco2_turbinesplitflow_cycle.h @@ -53,7 +53,7 @@ class C_sco2_tsf_core { public: - // Defines sco2 htr bypass input variables (no optimized variables) + // Defines turbine split flow input variables (no optimized variables) struct S_sco2_tsf_in { From 4350dc0956b4b0b35f7f25799e414db09f31858c Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Thu, 9 Oct 2025 12:04:00 -0600 Subject: [PATCH 93/94] Remove unnecessary semi colons --- tcs/sco2_htrbypass_cycle.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tcs/sco2_htrbypass_cycle.cpp b/tcs/sco2_htrbypass_cycle.cpp index b12fcdf788..b69e3bdc9a 100644 --- a/tcs/sco2_htrbypass_cycle.cpp +++ b/tcs/sco2_htrbypass_cycle.cpp @@ -1075,15 +1075,14 @@ int C_HTRBypass_Cycle::optimize_totalUA(const S_auto_opt_design_parameters& auto C_sco2_htrbp_core::S_sco2_htrbp_in& optimal_inputs) { // Validate Inputs + if (std::isnan(opt_par.m_eta_thermal_target) || + std::isnan(opt_par.m_UA_recup_total_min) || + std::isnan(opt_par.m_UA_recup_total_max)) { - if (std::isnan(opt_par.m_eta_thermal_target) || - std::isnan(opt_par.m_UA_recup_total_min) || - std::isnan(opt_par.m_UA_recup_total_max)) - { - std::string warning_msg = "The target eta, and max and min UA need to be defined in S_opt_design_parameters"; - return -1; - } + std::string warning_msg = "The target eta, and max and min UA need to be defined in S_opt_design_parameters"; + return -1; } + // Create Optimizer nlopt::opt opt_des_cycle(nlopt::GN_DIRECT, 1); From 1e7fc7d740bd1dbd56a578b0323af96da70a525f Mon Sep 17 00:00:00 2001 From: Taylor Brown <60201147+taylorbrown75@users.noreply.github.com> Date: Thu, 9 Oct 2025 12:15:46 -0600 Subject: [PATCH 94/94] Fix inflation year bug. --- tcs/sco2_cycle_components.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcs/sco2_cycle_components.cpp b/tcs/sco2_cycle_components.cpp index 1828cdae90..64233ea304 100644 --- a/tcs/sco2_cycle_components.cpp +++ b/tcs/sco2_cycle_components.cpp @@ -833,9 +833,9 @@ double calculate_inflation_factor(double yr_base, double yr_target) if (yr_base == 0 || yr_target == 0) return 1.0; - std::vector yr_vec = std::vector(yr_base, yr_target); + std::vector yr_vec = std::vector{ yr_base, yr_target }; - if (yr_vec == std::vector(2017, 2024)) { + if (yr_vec[0] == 2017 && yr_vec[1] == 2024) { return 1.407577; }