diff --git a/environment.yml b/environment.yml index eec45c3ad..fd83ecf7c 100644 --- a/environment.yml +++ b/environment.yml @@ -28,7 +28,7 @@ dependencies: - pyvista - rosco>=2.10.1 - trimesh - - wisdem>=4.2 + - wisdem>=4.2.5 - pip: - control - dash-vtk diff --git a/examples/04_frequency_domain_analysis_design/oc3_raft_analysis.yaml b/examples/04_frequency_domain_analysis_design/oc3_raft_analysis.yaml index c66633e5e..fff790adf 100644 --- a/examples/04_frequency_domain_analysis_design/oc3_raft_analysis.yaml +++ b/examples/04_frequency_domain_analysis_design/oc3_raft_analysis.yaml @@ -39,7 +39,7 @@ driver: max_major_iter: 10 # Maximum number of major design iterations (SNOPT) max_minor_iter: 100 # Maximum number of minor design iterations (SNOPT) max_iter: 10 # Maximum number of iterations (SLSQP) - solver: SLSQP # Optimization solver. Other options are 'SLSQP' - 'CONMIN' + solver: LN_COBYLA # Optimization solver. Other options are 'SLSQP' - 'CONMIN' step_size: 1.e-3 # Step size for finite differencing form: central # Finite differencing mode, either forward or central diff --git a/examples/04_frequency_domain_analysis_design/oc3_raft_driver.py b/examples/04_frequency_domain_analysis_design/oc3_raft_driver.py index 967cc8290..d9c22e509 100644 --- a/examples/04_frequency_domain_analysis_design/oc3_raft_driver.py +++ b/examples/04_frequency_domain_analysis_design/oc3_raft_driver.py @@ -2,7 +2,7 @@ from weis import weis_main # TEST_RUN will reduce the number and duration of simulations -TEST_RUN = False +TEST_RUN = True ## File management run_dir = os.path.dirname( os.path.realpath(__file__) ) diff --git a/weis/aeroelasticse/openmdao_openfast.py b/weis/aeroelasticse/openmdao_openfast.py index dceb699d5..249f0e91e 100644 --- a/weis/aeroelasticse/openmdao_openfast.py +++ b/weis/aeroelasticse/openmdao_openfast.py @@ -222,6 +222,9 @@ def setup(self): # ServoDyn Inputs self.add_input('generator_efficiency', val=1.0, desc='Generator efficiency') self.add_input('max_pitch_rate', val=0.0, units='deg/s', desc='Maximum allowed blade pitch rate') + self.add_input('VS_RefSpd', val=0.0, units='rad/s', desc='Rated generator speed from ROSCO tuning') + self.add_input('VS_RtTq', val=0.0, units='N*m', desc='Rated generator torque from ROSCO tuning') + self.add_input('VS_Rgn2K', val=0.0, units='N*m/(rad/s)**2', desc='Region 2 torque constant from ROSCO tuning') # StC or TMD inputs; structural control and tuned mass dampers @@ -1112,9 +1115,9 @@ def update_FAST_model(self, fst_vt, inputs, discrete_inputs): fst_vt['ServoDyn']['PitManRat(2)'] = float(inputs['max_pitch_rate'][0]) fst_vt['ServoDyn']['PitManRat(3)'] = float(inputs['max_pitch_rate'][0]) # Tune simple variable speed controller in ServoDyn, mostly to support free-free rotor configurations during linearization - fst_vt['ServoDyn']['VS_RtGnSp'] = fst_vt['DISCON_in']['VS_RefSpd'] * 30. / np.pi # rpm - fst_vt['ServoDyn']['VS_RtTq'] = fst_vt['DISCON_in']['VS_RtTq'] # Nm - fst_vt['ServoDyn']['VS_Rgn2K'] = fst_vt['DISCON_in']['VS_Rgn2K'] / (30./np.pi)**2. # N-m/rpm^2 + fst_vt['ServoDyn']['VS_RtGnSp'] = float(inputs['VS_RefSpd'][0]) * 30. / np.pi # rpm + fst_vt['ServoDyn']['VS_RtTq'] = float(inputs['VS_RtTq'][0]) # Nm + fst_vt['ServoDyn']['VS_Rgn2K'] = float(inputs['VS_Rgn2K'][0]) / (30./np.pi)**2. # N-m/rpm^2 # Prevent error in OpenFAST if fst_vt['ServoDyn']['VS_Rgn2K']*fst_vt['ServoDyn']['VS_RtGnSp']**2. > fst_vt['ServoDyn']['VS_RtTq']: fst_vt['ServoDyn']['VS_Rgn2K'] = fst_vt['ServoDyn']['VS_RtTq']/fst_vt['ServoDyn']['VS_RtGnSp']**2. diff --git a/weis/control/tune_rosco.py b/weis/control/tune_rosco.py index 74dc037df..afb157731 100644 --- a/weis/control/tune_rosco.py +++ b/weis/control/tune_rosco.py @@ -226,7 +226,10 @@ def setup(self): self.add_output('PC_GS_Ki', val=np.zeros(rosco_init_options['PC_GS_n']), desc='Gain-schedule table: pitch controller ki gains') self.add_output('Fl_Kp', val=0.0, desc='Floating feedback gain') - # self.add_output('VS_Rgn2K', val=0.0, units='N*m/(rad/s)**2', desc='Generator torque constant in Region 2 (HSS side), [N-m/(rad/s)^2]') + # ServoDyn parameters passed to FASTLoadCases via formal OpenMDAO connection + self.add_output('VS_RefSpd', val=0.0, units='rad/s', desc='Rated generator speed for ServoDyn') + self.add_output('VS_RtTq', val=0.0, units='N*m', desc='Rated generator torque for ServoDyn') + self.add_output('VS_Rgn2K', val=0.0, units='N*m/(rad/s)**2', desc='Generator torque constant in Region 2 (HSS side)') def compute(self,inputs,outputs, discrete_inputs, discrete_outputs): ''' @@ -426,6 +429,11 @@ def compute(self,inputs,outputs, discrete_inputs, discrete_outputs): # outputs['VS_Rgn2K'] = controller.vs_rgn2K outputs['VS_Kp'] = controller.vs_gain_schedule.Kp[0] outputs['VS_Ki'] = controller.vs_gain_schedule.Ki[0] + + # ServoDyn parameters for FASTLoadCases + outputs['VS_RefSpd'] = ROSCO_input['VS_RefSpd'] + outputs['VS_RtTq'] = ROSCO_input['VS_RtTq'] + outputs['VS_Rgn2K'] = ROSCO_input['VS_Rgn2K'] class Cp_Ct_Cq_Tables(ExplicitComponent): def initialize(self): diff --git a/weis/glue_code/glue_code.py b/weis/glue_code/glue_code.py index c8b8776ae..d03f7fc51 100644 --- a/weis/glue_code/glue_code.py +++ b/weis/glue_code/glue_code.py @@ -496,6 +496,9 @@ def setup(self): self.connect("drivetrain.gear_ratio", "aeroelastic.gearbox_ratio") self.connect("rotorse.rp.powercurve.rated_efficiency", "aeroelastic.generator_efficiency") self.connect("tune_rosco_ivc.max_pitch_rate" , "aeroelastic.max_pitch_rate") + self.connect("sse_tune.tune_rosco.VS_RefSpd", "aeroelastic.VS_RefSpd") + self.connect("sse_tune.tune_rosco.VS_RtTq", "aeroelastic.VS_RtTq") + self.connect("sse_tune.tune_rosco.VS_Rgn2K", "aeroelastic.VS_Rgn2K") self.connect("drivetrain.gearbox_efficiency", "aeroelastic.gearbox_efficiency") self.connect("drivetrain.uptilt", "aeroelastic.tilt") self.connect("drivetrain.overhang", "aeroelastic.overhang") @@ -758,12 +761,6 @@ def setup(self): self.connect("drivetrain.mb2Type", "drivese_post.bear2.bearing_type") self.connect("drivetrain.lss_diameter", "drivese_post.lss_diameter") self.connect("drivetrain.lss_wall_thickness", "drivese_post.lss_wall_thickness") - if modeling_options["WISDEM"]["DriveSE"]["direct"]: - self.connect("drivetrain.nose_diameter", "drivese_post.bear1.D_shaft", src_indices=[0]) - self.connect("drivetrain.nose_diameter", "drivese_post.bear2.D_shaft", src_indices=[-1]) - else: - self.connect("drivetrain.lss_diameter", "drivese_post.bear1.D_shaft", src_indices=[0]) - self.connect("drivetrain.lss_diameter", "drivese_post.bear2.D_shaft", src_indices=[-1]) self.connect("drivetrain.uptower", "drivese_post.uptower") self.connect("drivetrain.brake_mass_user", "drivese_post.brake_mass_user") self.connect("drivetrain.hvac_mass_coeff", "drivese_post.hvac_mass_coeff")