diff --git a/openfast_io/openfast_io/FAST_reader.py b/openfast_io/openfast_io/FAST_reader.py index b8dbc4199d..24047417a9 100644 --- a/openfast_io/openfast_io/FAST_reader.py +++ b/openfast_io/openfast_io/FAST_reader.py @@ -236,7 +236,7 @@ def loop_dict(vartree, search_var, branch): var = var.replace(' ', '') loop_dict(vartree_head, var, []) - def read_outlist_freeForm(self,f,module): + def read_outlist_freeForm(self, f, module): ''' Replacement for set_outlist that doesn't care about whether the channel is in the outlist vartree Easier, but riskier because OpenFAST can crash @@ -244,37 +244,78 @@ def read_outlist_freeForm(self,f,module): Inputs: f - file handle module - of OpenFAST, e.g. SubDyn, SeaState (these modules use this) ''' + all_channels = [] data = f.readline() - while data.split()[0] != 'END': - pattern = r'"?(.*?)"?' # grab only the text between quotes - data = re.findall(pattern, data)[0] - channels = data.split(',') # split on commas - channels = [c.strip() for c in channels] # strip whitespace - for c in channels: - self.fst_vt['outlist'][module][c] = True + + # Handle the case if there are blank lines before actual data + while data.strip() == '': + data = f.readline() + + while not data.strip().startswith('END'): + # Get part before the dash (comment) + line = data.split('-')[0] + + # Replace all delimiters with spaces + for delim in ['"', "'", ',', ';', '\t']: + line = line.replace(delim, ' ') + + # Split into words and add non-empty ones to the channel list + line_channels = [word.strip() for word in line.split() if word.strip()] + if line_channels: + all_channels.extend(line_channels) + + # Read next line data = f.readline() + + # Handle the case if there are blank lines + while data.strip() == '': + data = f.readline() + + # Store all channels in the outlist + for channel in all_channels: + self.fst_vt['outlist'][module][channel] = True - def read_outlist(self,f,module): + def read_outlist(self, f, module): ''' - Read the outlist section of the FAST input file, genralized for most modules + Read the outlist section of the FAST input file, generalized for most modules Inputs: f - file handle module - of OpenFAST, e.g. ElastoDyn, ServoDyn, AeroDyn, AeroDisk, etc. + Returns: List of channel names ''' - data = f.readline().split()[0] # to counter if we dont have any quotes - while data != 'END': - if data.find('"')>=0: - channels = data.split('"') - channel_list = channels[1].split(',') - else: - row_string = data.split(',') - if len(row_string)==1: - channel_list = [row_string[0].split('\n')[0]] - else: - channel_list = row_string - self.set_outlist(self.fst_vt['outlist'][module], channel_list) - data = f.readline().split()[0] # to counter if we dont have any quotes + all_channels = [] + data = f.readline() + + # Handle the case if there are blank lines before actual data + while data.strip() == '': + data = f.readline() + + while not data.strip().startswith('END'): + # Get part before the dash (comment) + line = data.split('-')[0] + + # Replace all delimiters with spaces + for delim in ['"', "'", ',', ';', '\t']: + line = line.replace(delim, ' ') + + # Split into words and add non-empty ones to the channel list + line_channels = [word.strip() for word in line.split() if word.strip()] + if line_channels: + all_channels.extend(line_channels) + + # Read next line + data = f.readline() + + # Handle the case if there are blank lines + while data.strip() == '': + data = f.readline() + + # Store all channels in the outlist + if all_channels: + self.set_outlist(self.fst_vt['outlist'][module], all_channels) + + return all_channels def read_MainInput(self): # Main FAST v8.16-v8.17 Input File @@ -557,38 +598,10 @@ def read_ElastoDyn(self, ed_file): self.fst_vt['ElastoDyn']['BldGagNd'] = read_array(f,self.fst_vt['ElastoDyn']['NBlGages'], array_type=int) else: self.fst_vt['ElastoDyn']['BldGagNd'] = 0 - f.readline() - - # Loop through output channel lines + + f.readline() - data = f.readline() - # if data != '': - # while data.split()[0] != 'END': - # channels = data.split('"') - # channel_list = channels[1].split(',') - # self.set_outlist(self.fst_vt['outlist']['ElastoDyn'], channel_list) - - # data = f.readline() - # else: - # # there is a blank line between the outlist and the END of the file - # f.readline() - - # Handle the case if there are blank lines before the END statement, check if blank line - while data.split().__len__() == 0: - data = f.readline() - - while data.split()[0] != 'END': - if data.find('"')>=0: - channels = data.split('"') - channel_list = channels[1].split(',') - else: - row_string = data.split(',') - if len(row_string)==1: - channel_list = row_string[0].split('\n')[0] - else: - channel_list = row_string - self.set_outlist(self.fst_vt['outlist']['ElastoDyn'], channel_list) - data = f.readline() + self.read_outlist(f,'ElastoDyn') # ElastoDyn optional outlist try: @@ -597,19 +610,7 @@ def read_ElastoDyn(self, ed_file): self.fst_vt['ElastoDyn']['BldNd_BlOutNd'] = f.readline().split()[0] f.readline() - data = f.readline() - while data.split()[0] != 'END': - if data.find('"')>=0: - channels = data.split('"') - opt_channel_list = channels[1].split(',') - else: - row_string = data.split(',') - if len(row_string)==1: - opt_channel_list = row_string[0].split('\n')[0] - else: - opt_channel_list = row_string - self.set_outlist(self.fst_vt['outlist']['ElastoDyn_Nodes'], opt_channel_list) - data = f.readline() + self.read_outlist(f,'ElastoDyn') except: # The optinal outlist does not exist. None @@ -856,13 +857,9 @@ def read_BeamDyn(self, bd_file, BladeNumber = 0): self.fst_vt['BeamDyn'][BladeNumber]['OutNd'] = [idx.strip() for idx in f.readline().split('OutNd')[0].split(',')] # BeamDyn Outlist f.readline() - data = f.readline() - while data.split()[0] != 'END': - channels = data.split('"') - channel_list = channels[1].split(',') - self.set_outlist(self.fst_vt['outlist']['BeamDyn'], channel_list) - data = f.readline() - + + self.read_outlist(f,'BeamDyn') + # BeamDyn optional outlist try: f.readline() @@ -870,19 +867,8 @@ def read_BeamDyn(self, bd_file, BladeNumber = 0): self.fst_vt['BeamDyn'][BladeNumber]['BldNd_BlOutNd'] = f.readline().split()[0] f.readline() - data = f.readline() - while data.split()[0] != 'END': - if data.find('"')>=0: - channels = data.split('"') - opt_channel_list = channels[1].split(',') - else: - row_string = data.split(',') - if len(row_string)==1: - opt_channel_list = row_string[0].split('\n')[0] - else: - opt_channel_list = row_string - self.set_outlist(self.fst_vt['outlist']['BeamDyn_Nodes'], opt_channel_list) - data = f.readline() + + self.read_outlist(f,'BeamDyn_Nodes') except: # The optinal outlist does not exist. None @@ -1025,19 +1011,7 @@ def read_InflowWind(self): # InflowWind Outlist f.readline() - data = f.readline() - while data.split()[0] != 'END': - if data.find('"')>=0: - channels = data.split('"') - channel_list = channels[1].split(',') - else: - row_string = data.split(',') - if len(row_string)==1: - channel_list = row_string[0].split('\n')[0] - else: - channel_list = row_string - self.set_outlist(self.fst_vt['outlist']['InflowWind'], channel_list) - data = f.readline() + self.read_outlist(f,'InflowWind') f.close() @@ -1194,25 +1168,9 @@ def read_AeroDyn(self): # AeroDyn Outlist f.readline() - data = f.readline() - - # Handle the case if there are blank lines before the END statement, check if blank line - while data.split().__len__() == 0: - data = f.readline() + self.read_outlist(f,'AeroDyn') - while data.split()[0] != 'END': - if data.find('"')>=0: - channels = data.split('"') - channel_list = channels[1].split(',') - else: - row_string = data.split(',') - if len(row_string)==1: - channel_list = row_string[0].split('\n')[0] - else: - channel_list = row_string - self.set_outlist(self.fst_vt['outlist']['AeroDyn'], channel_list) - data = f.readline() # AeroDyn optional outlist try: @@ -1221,19 +1179,7 @@ def read_AeroDyn(self): self.fst_vt['AeroDyn']['BldNd_BlOutNd'] = f.readline().split()[0] f.readline() - data = f.readline() - while data.split()[0] != 'END': - if data.find('"')>=0: - channels = data.split('"') - opt_channel_list = channels[1].split(',') - else: - row_string = data.split(',') - if len(row_string)==1: - opt_channel_list = row_string[0].split('\n')[0] - else: - opt_channel_list = row_string - self.set_outlist(self.fst_vt['outlist']['AeroDyn_Nodes'], opt_channel_list) - data = f.readline() + self.read_outlist(f,'AeroDyn_Nodes') except: # The optinal outlist does not exist. None @@ -1702,12 +1648,7 @@ def read_ServoDyn(self): # ServoDyn Outlist f.readline() - data = f.readline() - while data.split()[0] != 'END': - channels = data.split('"') - channel_list = channels[1].split(',') - self.set_outlist(self.fst_vt['outlist']['ServoDyn'], channel_list) - data = f.readline() + self.read_outlist(f,'ServoDyn') f.close() @@ -2230,19 +2171,7 @@ def read_HydroDyn(self, hd_file): # HydroDyn Outlist f.readline() - data = f.readline() - while data.split()[0] != 'END': - if data.find('"')>=0: - channels = data.split('"') - channel_list = channels[1].split(',') - else: - row_string = data.split(',') - if len(row_string)==1: - channel_list = row_string[0].split('\n')[0] - else: - channel_list = row_string - self.set_outlist(self.fst_vt['outlist']['AeroDyn'], channel_list) - data = f.readline() + self.read_outlist(f, 'HydroDyn') f.close() diff --git a/openfast_io/pyproject.toml b/openfast_io/pyproject.toml index 6eb3e86f8d..dff12fefa0 100644 --- a/openfast_io/pyproject.toml +++ b/openfast_io/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "hatchling.build" [project] name = "openfast_io" # dynamic = ["version"] -version = "4.0.4" +version = "4.0.5" description = "Readers and writers for OpenFAST files." license = {file = "../LICENSE"} authors = [ @@ -39,7 +39,6 @@ classifiers = [ # Optional # Specify the Python versions you support here. In particular, ensure # that you indicate you support Python 3. These classifiers are *not* # checked by "pip install". See instead "python_requires" below. - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", diff --git a/reg_tests/r-test b/reg_tests/r-test index a4b4fdb20a..60ff5f7edb 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit a4b4fdb20a1a97554eb7c8fabfbbcb147a05150e +Subproject commit 60ff5f7edb0f938f1bc127c4bae17de54789a68b