def execute(self): # FAST version specific initialization if self.FAST_ver.lower() == 'fast7': reader = InputReader_FAST7(FAST_ver=self.FAST_ver) writer = InputWriter_FAST7(FAST_ver=self.FAST_ver) elif self.FAST_ver.lower() in ['fast8','openfast']: reader = InputReader_OpenFAST(FAST_ver=self.FAST_ver) writer = InputWriter_OpenFAST(FAST_ver=self.FAST_ver) wrapper = FastWrapper(FAST_ver=self.FAST_ver, debug_level=self.debug_level) # Read input model, FAST files or Yaml if self.fst_vt == {}: if self.read_yaml: reader.FAST_yamlfile = self.FAST_yamlfile_in reader.read_yaml() else: reader.FAST_InputFile = self.FAST_InputFile reader.FAST_directory = self.FAST_directory reader.execute() # Initialize writer variables with input model writer.fst_vt = reader.fst_vt else: writer.fst_vt = self.fst_vt writer.FAST_runDirectory = self.FAST_runDirectory writer.FAST_namingOut = self.FAST_namingOut # Make any case specific variable changes if self.case: writer.update(fst_update=self.case) # Modify any specified output channels if self.channels: writer.update_outlist(self.channels) # Write out FAST model writer.execute() if self.write_yaml: writer.FAST_yamlfile = self.FAST_yamlfile_out writer.write_yaml() # Run FAST wrapper.FAST_exe = self.FAST_exe wrapper.FAST_InputFile = os.path.split(writer.FAST_InputFileOut)[1] wrapper.FAST_directory = os.path.split(writer.FAST_InputFileOut)[0] FAST_Output = os.path.join(wrapper.FAST_directory, wrapper.FAST_InputFile[:-3]+'outb') FAST_Output_txt = os.path.join(wrapper.FAST_directory, wrapper.FAST_InputFile[:-3]+'out') #check if OpenFAST is set not to overwrite existing output files, TODO: move this further up in the workflow for minor computation savings if self.overwrite_outfiles or (not self.overwrite_outfiles and not (os.path.exists(FAST_Output) or os.path.exists(FAST_Output_txt))): wrapper.execute() else: if self.debug_level>0: print('OpenFAST not execute: Output file "%s" already exists. To overwrite this output file, set "overwrite_outfiles = True".'%FAST_Output) return FAST_Output
def gen_linear_model(wind_speeds, Tmax=600.): """ Generate OpenFAST linearizations across wind speeds Only needs to be performed once for each model """ linear = LinearFAST(FAST_ver='OpenFAST', dev_branch=True) # fast info linear.weis_dir = os.path.dirname( os.path.dirname(os.path.dirname(__file__))) + os.sep linear.FAST_InputFile = 'IEA-15-240-RWT-UMaineSemi.fst' # FAST input file (ext=.fst) linear.FAST_directory = os.path.join( linear.weis_dir, 'examples/01_aeroelasticse/OpenFAST_models/IEA-15-240-RWT/IEA-15-240-RWT-UMaineSemi' ) # Path to fst directory files linear.FAST_steadyDirectory = os.path.join(linear.weis_dir, 'outputs', 'iea_semi_steady') linear.FAST_linearDirectory = os.path.join(linear.weis_dir, 'outputs', 'iea_semi_lin') linear.debug_level = 2 linear.dev_branch = True linear.write_yaml = True # do a read to get gearbox ratio fastRead = InputReader_OpenFAST(FAST_ver='OpenFAST', dev_branch=True) fastRead.FAST_InputFile = linear.FAST_InputFile # FAST input file (ext=.fst) fastRead.FAST_directory = linear.FAST_directory # Path to fst directory files fastRead.execute() # linearization setup linear.v_rated = 10.74 # needed as input from RotorSE or something, to determine TrimCase for linearization linear.GBRatio = fastRead.fst_vt['ElastoDyn']['GBRatio'] linear.WindSpeeds = wind_speeds #[8.,10.,12.,14.,24.] linear.DOFs = ['GenDOF'] #,'TwFADOF1','PtfmPDOF'] # enable with linear.TMax = Tmax # should be 1000-2000 sec or more with hydrodynamic states linear.NLinTimes = 12 #if true, there will be a lot of hydronamic states, equal to num. states in ss_exct and ss_radiation models linear.HydroStates = False # taking out to speed up for test # simulation setup linear.parallel = False linear.cores = 8 # overwrite steady & linearizations linear.overwrite = False # run steady state sims linear.runFAST_steady() # process results linear.postFAST_steady() # run linearizations linear.runFAST_linear()
def set_openfast_data(self): # Openfast if self.modeling_options['Level3']['flag'] == True: fast = InputReader_OpenFAST(FAST_ver='OpenFAST') self.modeling_options['openfast']['fst_vt'] = {} self.modeling_options['openfast']['fst_vt']['outlist'] = fast.fst_vt['outlist'] if self.modeling_options['openfast']['file_management']['FAST_directory'] != 'none': # Load Input OpenFAST model variable values fast.FAST_InputFile = self.modeling_options['openfast']['file_management']['FAST_InputFile'] if os.path.isabs(self.modeling_options['openfast']['file_management']['FAST_directory']): fast.FAST_directory = self.modeling_options['openfast']['file_management']['FAST_directory'] else: fast.FAST_directory = os.path.join(os.path.dirname(self.modeling_options['fname_input_modeling']), self.modeling_options['openfast']['file_management']['FAST_directory']) # Find the controller run_dir = os.path.dirname( os.path.dirname( os.path.dirname( os.path.realpath(__file__) ) ) ) + os.sep if platform.system() == 'Windows': path2dll = os.path.join(run_dir, 'local/lib/libdiscon.dll') elif platform.system() == 'Darwin': path2dll = os.path.join(run_dir, 'local/lib/libdiscon.dylib') else: path2dll = os.path.join(run_dir, 'local/lib/libdiscon.so') if self.modeling_options['openfast']['file_management']['path2dll'] == 'none': self.modeling_options['openfast']['file_management']['path2dll'] = path2dll if os.path.isabs(self.modeling_options['openfast']['file_management']['path2dll']) == False: self.modeling_options['openfast']['file_management']['path2dll'] = os.path.join(os.path.dirname(self.modeling_options['fname_input_modeling']), self.modeling_options['openfast']['file_management']['path2dll']) if self.modeling_options['openfast']['file_management']['FAST_directory'] != 'none': fast.path2dll = self.modeling_options['openfast']['file_management']['path2dll'] fast.execute() if self.modeling_options['openfast']['analysis_settings']['Analysis_Level'] == 2 and self.modeling_options['openfast']['dlc_settings']['run_power_curve'] == False and self.modeling_options['openfast']['dlc_settings']['run_IEC'] == False: raise Exception('WEIS is set to run OpenFAST, but both flags for power curve and IEC cases are set to False among the modeling options. Set at least one of the two to True to proceed.') # XFoil if not os.path.isfile(self.modeling_options["xfoil"]["path"]) and self.modeling_options['Level3']['ROSCO']['Flp_Mode']: raise Exception("A distributed aerodynamic control device is defined in the geometry yaml, but the path to XFoil in the modeling options is not defined correctly")
def load_from_fast(self, FAST_InputFile, FAST_directory, FAST_ver='OpenFAST', dev_branch=True, rot_source=None, txt_filename=None): """ Load the parameter files directly from a FAST input deck Parameters: ----------- Fast_InputFile: str Primary fast model input file (*.fst) FAST_directory: str Directory for primary fast model input file FAST_ver: string, optional fast version, usually OpenFAST dev_branch: bool, optional dev_branch input to InputReader_OpenFAST, probably True rot_source: str, optional desired source for rotor to get Cp, Ct, Cq tables. Default is to run cc-blade. options: cc-blade - run cc-blade txt - from *.txt file txt_filename: str, optional filename for *.txt, only used if rot_source='txt' """ from weis.aeroelasticse.FAST_reader import InputReader_OpenFAST print('Loading FAST model: %s ' % FAST_InputFile) self.TurbineName = FAST_InputFile.strip('.fst') fast = self.fast = InputReader_OpenFAST(FAST_ver=FAST_ver, dev_branch=dev_branch) fast.FAST_InputFile = FAST_InputFile fast.FAST_directory = FAST_directory fast.execute() if txt_filename: self.rotor_performance_filename = txt_filename else: self.rotor_performance_filename = 'Cp_Ct_Cq.txt' # Grab general turbine parameters self.TipRad = fast.fst_vt['ElastoDyn']['TipRad'] self.Rhub = fast.fst_vt['ElastoDyn']['HubRad'] self.hubHt = fast.fst_vt['ElastoDyn']['TowerHt'] + fast.fst_vt[ 'ElastoDyn']['Twr2Shft'] self.NumBl = fast.fst_vt['ElastoDyn']['NumBl'] self.TowerHt = fast.fst_vt['ElastoDyn']['TowerHt'] self.shearExp = 0.2 #HARD CODED FOR NOW self.rho = fast.fst_vt['AeroDyn15']['AirDens'] self.mu = fast.fst_vt['AeroDyn15']['KinVisc'] self.Ng = fast.fst_vt['ElastoDyn']['GBRatio'] self.GenEff = fast.fst_vt['ServoDyn']['GenEff'] self.GBoxEff = fast.fst_vt['ElastoDyn']['GBoxEff'] self.DTTorSpr = fast.fst_vt['ElastoDyn']['DTTorSpr'] self.generator_inertia = fast.fst_vt['ElastoDyn']['GenIner'] self.tilt = fast.fst_vt['ElastoDyn']['ShftTilt'] try: self.precone = fast.fst_vt['ElastoDyn'][ 'PreCone1'] # May need to change to PreCone(1) depending on OpenFAST files except: self.precone = fast.fst_vt['ElastoDyn']['PreCone(1)'] self.yaw = 0.0 self.J = self.rotor_inertia + self.generator_inertia * self.Ng**2 self.rated_torque = self.rated_power / ( self.GenEff / 100 * self.rated_rotor_speed * self.Ng) self.max_torque = self.rated_torque * 1.1 self.rotor_radius = self.TipRad # self.omega_dt = np.sqrt(self.DTTorSpr/self.J) # Load blade information self.load_blade_info() # Load Cp, Ct, Cq tables if rot_source == 'cc-blade': # Use cc-blade self.load_from_ccblade() elif rot_source == 'txt': # Use specified text file self.pitch_initial_rad, self.TSR_initial, self.Cp_table, self.Ct_table, self.Cq_table = load_from_txt( txt_filename) else: # Use text file from DISCON.in if os.path.exists( os.path.join(FAST_directory, fast.fst_vt['ServoDyn']['DLL_InFile'])): try: self.pitch_initial_rad = fast.fst_vt['DISCON_in'][ 'Cp_pitch_initial_rad'] self.TSR_initial = fast.fst_vt['DISCON_in'][ 'Cp_TSR_initial'] self.Cp_table = fast.fst_vt['DISCON_in']['Cp_table'] self.Ct_table = fast.fst_vt['DISCON_in']['Ct_table'] self.Cq_table = fast.fst_vt['DISCON_in']['Cq_table'] except: # Load from cc-blade print( 'No rotor performance data source available, running CC-Blade.' ) self.load_from_ccblade() # Parse rotor performance data self.Cp = RotorPerformance(self.Cp_table, self.pitch_initial_rad, self.TSR_initial) self.Ct = RotorPerformance(self.Ct_table, self.pitch_initial_rad, self.TSR_initial) self.Cq = RotorPerformance(self.Cq_table, self.pitch_initial_rad, self.TSR_initial) # Define operational TSR if not self.TSR_operational: self.TSR_operational = self.Cp.TSR_opt # Pull out some floating-related data wave_tp = fast.fst_vt['HydroDyn']['WaveTp'] try: self.wave_peak_period = 1 / wave_tp # Will work if HydroDyn exists and a peak period is defined... except: self.wave_peak_period = 0.0 # Set as 0.0 when HydroDyn doesn't exist (fixed bottom)
def execute(self): # FAST version specific initialization if self.FAST_ver.lower() == 'fast7': reader = InputReader_FAST7(FAST_ver=self.FAST_ver) writer = InputWriter_FAST7(FAST_ver=self.FAST_ver) elif self.FAST_ver.lower() in ['fast8','openfast']: reader = InputReader_OpenFAST(FAST_ver=self.FAST_ver) writer = InputWriter_OpenFAST(FAST_ver=self.FAST_ver) # Read input model, FAST files or Yaml if self.fst_vt == {}: if self.read_yaml: reader.FAST_yamlfile = self.FAST_yamlfile_in reader.read_yaml() else: reader.FAST_InputFile = self.FAST_InputFile reader.FAST_directory = self.FAST_directory reader.execute() # Initialize writer variables with input model writer.fst_vt = self.fst_vt = reader.fst_vt else: writer.fst_vt = self.fst_vt writer.FAST_runDirectory = self.FAST_runDirectory writer.FAST_namingOut = self.FAST_namingOut # Make any case specific variable changes if self.case: writer.update(fst_update=self.case) # Modify any specified output channels if self.channels: writer.update_outlist(self.channels) # Write out FAST model writer.execute() if self.write_yaml: writer.FAST_yamlfile = self.FAST_yamlfile_out writer.write_yaml() FAST_directory = os.path.split(writer.FAST_InputFileOut)[0] input_file_name = create_string_buffer(os.path.abspath(writer.FAST_InputFileOut).encode('utf-8')) t_max = c_double(self.fst_vt['Fst']['TMax']) orig_dir = os.getcwd() os.chdir(FAST_directory) openfastlib = FastLibAPI(self.FAST_lib, input_file_name, t_max) openfastlib.fast_run() output_dict = {} for i, channel in enumerate(openfastlib.output_channel_names): output_dict[channel] = openfastlib.output_values[:,i] del(openfastlib) output = OpenFASTOutput.from_dict(output_dict, self.FAST_namingOut, magnitude_channels=magnitude_channels) if self.fst_vt['Fst']['TStart'] > 0.0: output.trim_data(tmin=self.fst_vt['Fst']['TStart'], tmax=self.fst_vt['Fst']['TMax']) case_name, sum_stats, extremes, dels = la._process_output(output) # if save_file: write_fast os.chdir(orig_dir) if not self.keep_time: output_dict = None return case_name, sum_stats, extremes, dels, output_dict
def set_openfast_data(self): # Openfast if self.modeling_options['Analysis_Flags']['OpenFAST'] == True: # Load Input OpenFAST model variable values fast = InputReader_OpenFAST(FAST_ver='OpenFAST') fast.FAST_InputFile = self.modeling_options['openfast'][ 'file_management']['FAST_InputFile'] if os.path.isabs(self.modeling_options['openfast'] ['file_management']['FAST_directory']): fast.FAST_directory = self.modeling_options['openfast'][ 'file_management']['FAST_directory'] else: fast.FAST_directory = os.path.join( os.path.dirname( self.modeling_options['fname_input_modeling']), self.modeling_options['openfast']['file_management'] ['FAST_directory']) # Find the controller run_dir = os.path.dirname( os.path.dirname(os.path.dirname( os.path.realpath(__file__)))) + os.sep if platform.system() == 'Windows': path2dll = os.path.join(run_dir, 'local/lib/libdiscon.dll') elif platform.system() == 'Darwin': path2dll = os.path.join(run_dir, 'local/lib/libdiscon.dylib') else: path2dll = os.path.join(run_dir, 'local/lib/libdiscon.so') if self.modeling_options['openfast']['file_management'][ 'path2dll'] != 'none': if os.path.isabs(self.modeling_options['openfast'] ['file_management']['path2dll']): fast.path2dll = self.modeling_options['openfast'][ 'file_management']['path2dll'] else: fast.path2dll = os.path.join( os.path.dirname( self.modeling_options['fname_input_modeling']), self.modeling_options['openfast']['file_management'] ['path2dll']) else: fast.path2dll = path2dll fast.execute() self.modeling_options['openfast']['fst_vt'] = fast.fst_vt if os.path.isabs(self.modeling_options['openfast'] ['file_management']['Simulation_Settings_File']): path2settings = self.modeling_options['openfast'][ 'file_management']['Simulation_Settings_File'] else: path2settings = os.path.join( os.path.dirname( self.modeling_options['fname_input_modeling']), self.modeling_options['openfast']['file_management'] ['Simulation_Settings_File']) if os.path.exists(path2settings): self.modeling_options['openfast']['fst_settings'] = dict( sch.load_yaml(path2settings)) else: print( 'WARNING: OpenFAST is called, but no file with settings is found.' ) self.modeling_options['openfast']['fst_settings'] = {} if os.path.isabs(self.modeling_options['xfoil']['path']): self.modeling_options['airfoils'][ 'xfoil_path'] = self.modeling_options['xfoil']['path'] else: self.modeling_options['airfoils']['xfoil_path'] = os.path.join( os.path.dirname( self.modeling_options['fname_input_modeling']), self.modeling_options['xfoil']['path']) if self.modeling_options['openfast']['analysis_settings'][ 'Analysis_Level'] == 2 and self.modeling_options[ 'openfast']['dlc_settings'][ 'run_power_curve'] == False and self.modeling_options[ 'openfast']['dlc_settings']['run_IEC'] == False: raise ValueError( 'WEIS is set to run OpenFAST, but both flags for power curve and IEC cases are set to False among the modeling options. Set at least one of the two to True to proceed.' ) else: self.modeling_options['openfast']['fst_vt'] = {} self.modeling_options['airfoils']['xfoil_path'] = ''