From 58800dafd1745aa03fdb8ccd084647bd9488b812 Mon Sep 17 00:00:00 2001 From: pibo Date: Thu, 19 Nov 2020 11:48:23 -0700 Subject: [PATCH] stall margin from OF --- weis/aeroelasticse/openmdao_openfast.py | 33 +++++++++++++++++++++++++ weis/glue_code/glue_code.py | 13 ++++++---- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/weis/aeroelasticse/openmdao_openfast.py b/weis/aeroelasticse/openmdao_openfast.py index 01461b1c7..e0d138852 100644 --- a/weis/aeroelasticse/openmdao_openfast.py +++ b/weis/aeroelasticse/openmdao_openfast.py @@ -265,6 +265,9 @@ def setup(self): self.add_output('C_miners_SC_PS', val=np.zeros((n_span, n_mat, 2)), desc="Miner's rule cummulative damage to Spar Cap, pressure side") # self.add_output('C_miners_TE_SS', val=np.zeros((n_span, n_mat, 2)), desc="Miner's rule cummulative damage to Trailing-Edge reinforcement, suction side") # self.add_output('C_miners_TE_PS', val=np.zeros((n_span, n_mat, 2)), desc="Miner's rule cummulative damage to Trailing-Edge reinforcement, pressure side") + self.add_output('max_aoa', val=np.zeros(n_span), units='deg', desc='distributed angles of attack - max') + self.add_output('std_aoa', val=np.zeros(n_span), units='deg', desc='distributed angles of attack - std') + self.add_output('mean_aoa', val=np.zeros(n_span), units='deg', desc='distributed angles of attack - mean') self.add_discrete_output('fst_vt_out', val={}) @@ -539,10 +542,12 @@ def run_FAST(self, inputs, discrete_inputs, fst_vt): channels_out += ["Spn1MLyb1", "Spn2MLyb1", "Spn3MLyb1", "Spn4MLyb1", "Spn5MLyb1", "Spn6MLyb1", "Spn7MLyb1", "Spn8MLyb1", "Spn9MLyb1"] channels_out += ["RtAeroFxh", "RtAeroFyh", "RtAeroFzh"] channels_out += ["RotThrust", "LSShftFys", "LSShftFzs", "RotTorq", "LSSTipMys", "LSSTipMzs"] + channels_out += ["B1N1Alpha", "B1N2Alpha", "B1N3Alpha", "B1N4Alpha", "B1N5Alpha", "B1N6Alpha", "B1N7Alpha", "B1N8Alpha", "B1N9Alpha", "B2N1Alpha", "B2N2Alpha", "B2N3Alpha", "B2N4Alpha", "B2N5Alpha", "B2N6Alpha", "B2N7Alpha", "B2N8Alpha","B2N9Alpha"] if self.n_blades > 2: channels_out += ["TipDxc3", "TipDyc3", "TipDzc3", "RootMxc3", "RootMyc3", "RootMzc3", "TipDxb3", "TipDyb3", "TipDzb3", "RootMxb3", "RootMyb3", "RootMzb3", "RootFxc3", "RootFyc3", "RootFzc3", "RootFxb3", "RootFyb3", "RootFzb3", "BldPitch3"] channels_out += ["B3N1Fx", "B3N2Fx", "B3N3Fx", "B3N4Fx", "B3N5Fx", "B3N6Fx", "B3N7Fx", "B3N8Fx", "B3N9Fx", "B3N1Fy", "B3N2Fy", "B3N3Fy", "B3N4Fy", "B3N5Fy", "B3N6Fy", "B3N7Fy", "B3N8Fy", "B3N9Fy"] + channels_out += ["B3N1Alpha", "B3N2Alpha", "B3N3Alpha", "B3N4Alpha", "B3N5Alpha", "B3N6Alpha", "B3N7Alpha", "B3N8Alpha", "B3N9Alpha"] # Add additional options if ('channels_out',) in self.options['modeling_options']['openfast']['fst_settings']: @@ -852,6 +857,34 @@ def post_process(self, FAST_Output, case_list, dlc_list, inputs, discrete_inputs extreme_table['LSShftM'][np.argmax(sum_stats['LSShftM']['max'])]['LSSTipMys']['val'], extreme_table['LSShftM'][np.argmax(sum_stats['LSShftM']['max'])]['LSSTipMzs']['val']])*1.e3 + ## Post process aerodynamic data + # Angles of attack - max, std, mean + blade1_chans_aoa = ["B1N1Alpha", "B1N2Alpha", "B1N3Alpha", "B1N4Alpha", "B1N5Alpha", "B1N6Alpha", "B1N7Alpha", "B1N8Alpha", "B1N9Alpha"] + blade2_chans_aoa = ["B2N1Alpha", "B2N2Alpha", "B2N3Alpha", "B2N4Alpha", "B2N5Alpha", "B2N6Alpha", "B2N7Alpha", "B2N8Alpha", "B2N9Alpha"] + aoa_max_B1 = [np.max(sum_stats[var]['max']) for var in blade1_chans_aoa] + aoa_mean_B1 = [np.mean(sum_stats[var]['mean']) for var in blade1_chans_aoa] + aoa_std_B1 = [np.mean(sum_stats[var]['std']) for var in blade1_chans_aoa] + aoa_max_B2 = [np.max(sum_stats[var]['max']) for var in blade2_chans_aoa] + aoa_mean_B2 = [np.mean(sum_stats[var]['mean']) for var in blade2_chans_aoa] + aoa_std_B2 = [np.mean(sum_stats[var]['std']) for var in blade2_chans_aoa] + if self.n_blades == 2: + spline_aoa_max = PchipInterpolator(self.R_out, np.max([aoa_max_B1, aoa_max_B2], axis=0)) + spline_aoa_std = PchipInterpolator(self.R_out, np.mean([aoa_std_B1, aoa_std_B2], axis=0)) + spline_aoa_mean = PchipInterpolator(self.R_out, np.mean([aoa_mean_B1, aoa_mean_B2], axis=0)) + elif self.n_blades == 3: + blade3_chans_aoa = ["B3N1Alpha", "B3N2Alpha", "B3N3Alpha", "B3N4Alpha", "B3N5Alpha", "B3N6Alpha", "B3N7Alpha", "B3N8Alpha", "B3N9Alpha"] + aoa_max_B3 = [np.max(sum_stats[var]['max']) for var in blade3_chans_aoa] + aoa_mean_B3 = [np.mean(sum_stats[var]['mean']) for var in blade3_chans_aoa] + aoa_std_B3 = [np.mean(sum_stats[var]['std']) for var in blade3_chans_aoa] + spline_aoa_max = PchipInterpolator(self.R_out, np.max([aoa_max_B1, aoa_max_B2, aoa_max_B3], axis=0)) + spline_aoa_std = PchipInterpolator(self.R_out, np.mean([aoa_max_B1, aoa_std_B2, aoa_std_B3], axis=0)) + spline_aoa_mean = PchipInterpolator(self.R_out, np.mean([aoa_mean_B1, aoa_mean_B2, aoa_mean_B3], axis=0)) + else: + raise Exception('The calculations only support 2 or 3 bladed rotors') + outputs['max_aoa'] = spline_aoa_max(r) + outputs['std_aoa'] = spline_aoa_std(r) + outputs['mean_aoa'] = spline_aoa_mean(r) + if self.FASTpref['dlc_settings']['run_blade_fatigue']: # determine which dlc will be used for fatigue calculations, checks for dlc 1.2, then dlc 1.1 diff --git a/weis/glue_code/glue_code.py b/weis/glue_code/glue_code.py index f8b554f19..568c17eca 100644 --- a/weis/glue_code/glue_code.py +++ b/weis/glue_code/glue_code.py @@ -81,6 +81,7 @@ def setup(self): self.add_subsystem('freq_tower', TowerSE(modeling_options=modeling_options)) self.add_subsystem('sse_tune', ServoSE_ROSCO(modeling_options = modeling_options)) # Aero analysis self.add_subsystem('aeroelastic', FASTLoadCases(modeling_options = modeling_options, opt_options = opt_options)) + self.add_subsystem('stall_check_of', NoStallConstraint(modeling_options = modeling_options)) self.add_subsystem('rlds', RotorLoadsDeflStrainsWEIS(modeling_options = modeling_options, opt_options = opt_options, freq_run=False)) @@ -255,15 +256,17 @@ def setup(self): self.connect('configuration.turb_class', 'sse.gust.turbulence_class') # Connections to the stall check - self.connect('blade.outer_shape_bem.s', 'stall_check.s') - self.connect('airfoils.aoa', 'stall_check.airfoils_aoa') - self.connect('xf.cl_interp_flaps', 'stall_check.airfoils_cl') - self.connect('xf.cd_interp_flaps', 'stall_check.airfoils_cd') - self.connect('xf.cm_interp_flaps', 'stall_check.airfoils_cm') + self.connect('blade.outer_shape_bem.s', ['stall_check.s', 'stall_check_of.s']) + self.connect('airfoils.aoa', ['stall_check.airfoils_aoa', 'stall_check_of.airfoils_aoa']) + self.connect('xf.cl_interp_flaps', ['stall_check.airfoils_cl', 'stall_check_of.airfoils_cl']) + self.connect('xf.cd_interp_flaps', ['stall_check.airfoils_cd', 'stall_check_of.airfoils_cd']) + self.connect('xf.cm_interp_flaps', ['stall_check.airfoils_cm', 'stall_check_of.airfoils_cm']) if modeling_options['Analysis_Flags']['ServoSE']: self.connect('sse.powercurve.aoa_regII', 'stall_check.aoa_along_span') else: self.connect('ccblade.alpha', 'stall_check.aoa_along_span') + if modeling_options['Analysis_Flags']['OpenFAST']: + self.connect('aeroelastic.max_aoa', 'stall_check_of.aoa_along_span') if modeling_options['Analysis_Flags']['OpenFAST'] and modeling_options['Analysis_Flags']['ServoSE']: self.connect('sse.powercurve.rated_V', ['sse_tune.tune_rosco.v_rated'])