From 977046d1de6321c10b70c9699947a1ba9519b332 Mon Sep 17 00:00:00 2001 From: Michael McWilliam <mimc@dtu.dk> Date: Wed, 3 Oct 2018 08:25:32 +0200 Subject: [PATCH] Created a WETB for the new HAWC2 wrapper --- wetb/hawc2/Hawc2io.py | 8 +- wetb/hawc2/hawc2_simulation.py | 403 +++++++++++++++++++++++++++++++++ wetb/hawc2/htc_contents.py | 337 +++++++++++++++++++++++++-- wetb/hawc2/htc_file.py | 8 +- 4 files changed, 733 insertions(+), 23 deletions(-) create mode 100644 wetb/hawc2/hawc2_simulation.py diff --git a/wetb/hawc2/Hawc2io.py b/wetb/hawc2/Hawc2io.py index db691bc..dd67546 100644 --- a/wetb/hawc2/Hawc2io.py +++ b/wetb/hawc2/Hawc2io.py @@ -273,11 +273,11 @@ class ReadHawc2(object): raise Exception('The data is not set') if chid>=self.NrCh: raise KeyError('The index is too large') - return self.data[:,chid] + return self.Data[:,chid] ############################################################################ # this will get the keys def keys(self): - retval=list(range(0, self.NrCh))) + retval=list(range(0, self.NrCh)) retval.extend(list(self.alias.keys())) return retval ############################################################################ @@ -304,9 +304,9 @@ class ReadHawc2(object): # get items def __getitem__(self, key): old_key = [] - while key in alias.keys() and not key in old_key: + while key in self.alias.keys() and not key in old_key: old_key.append(key) - key = alias[key] + key = self.alias[key] if key in old_key: raise Exception('Circular alias') return self.get_signal(key) diff --git a/wetb/hawc2/hawc2_simulation.py b/wetb/hawc2/hawc2_simulation.py new file mode 100644 index 0000000..f3096d0 --- /dev/null +++ b/wetb/hawc2/hawc2_simulation.py @@ -0,0 +1,403 @@ + +import os +import shutil +import time +import math +from wetb.hawc2.htc_file import HTCFile +from wetb.hawc2.ae_file import AEFile +from wetb.hawc2.pc_file import PCData +from wetb.hawc2.st_file import StOrigData, StFPMData +from wetb.hawc2.Hawc2io import ReadHawc2 +try: + import subprocess32 as subprocess + _with_timeout = True +except: + import subprocess + _with_timeout = False + +def mkdir_for_file_in_dir(filename): + # prepare the search + mkdir_list = [] + dirname = os.path.dirname(filename) + # detect at what level we have a directory + while not os.path.exists(dirname): + dirname, mkdir_file = os.path.split(dirname) + mkdir_list.insert(0, mkdir_file) + # Make all the directories + for mkdir_file in mkdir_list: + dirname = os.path.join(dirname, mkdir_file) + os.mkdir(dirname) + +def open_file_in_dir(filename, mode): + # mkdir the path + mkdir_for_file_in_dir(filename) + # return an open file descriptor in that folder + return open(filename, mode) + +class Hawc2_Simulation(object): + + def __init__(self, source_file_in = None): + super(Hawc2_Simulation, self).__init__() + + # The htc file data structure + self.htcf = None + # this data structure contains all the input files that need to be maintained + self.input_files = None + # The file for the source + self.source_file = source_file_in + self.source_name = None + # The directories for the source and the destination + self.source_directory = None + self.write_directory = None + # indicates that the sensors in the source htc file are normalized + self.source_sensors_normalized = False + # indicates that the object should keep the sensors normalized + self.object_sensors_normalized = False + # The results of the simulation + self.results = None + + # These are the execution settings + # This is the command that launches hawc2 + self.exec_command = 'wine hawc2mb.exe' + # how many times should we re-try + self.exec_retry_count = 3 + # how long should we wait to start the first re-try + self.exec_sleep_time = 10 + # Is this just a dry run + self.exec_dry_run = False + # Indicates that the simulation is a success + self.exec_success = False + # Run the simulation within try-except (hides error messages) + self.exec_use_try_except = True + # Run the simulation with a time-out ... useful for detecting errors + self.exec_use_time_out = _with_timeout + # The time-out used in conjunction with using a time-out + self.exec_time_out = 1200 + # Send messages + self.exec_verbose = True + + # This is the reference curve + self.blade_length_x_key = 'new_htc_structure.main_body_blade1.c2_def.x' + self.blade_length_y_key = 'new_htc_structure.main_body_blade1.c2_def.x' + self.blade_length_z_key = 'new_htc_structure.main_body_blade1.c2_def.x' + + if not self.source_file is None: + self.load_simulation() + + def calculate_blade_scale(self): + retval = 1.0 + if not self.htcf is None: + all_keys = self.htcf.all_keys() + if self.blade_length_x_key in all_keys and self.blade_length_y_key in all_keys and self.blade_length_z_key in all_keys: + x = self.htcf[self.blade_length_x_key] + y = self.htcf[self.blade_length_y_key] + z = self.htcf[self.blade_length_z_key] + if x.size!=y.size or y.size!=z.size: + raise Exception('The size of the blade axis data is not consistent') + retval = 0.0 + for I in range(1,x.size): + retval += math.sqrt( (x[I]-x[I-1])**2.0 + (y[I]-y[I-1])**2.0 + (z[I]-z[I-1])**2.0) + return retval + + # Specifies that all sensors normalization settings + def set_sensor_normalization_scheme(self, source_sensors_normalized, object_sensors_normalized): + self.source_sensors_normalized = source_sensors_normalized + self.object_sensors_normalized = object_sensors_normalized + # Need to make sure that all the sensors are set in a normalized state + if self.source_sensors_normalized: + self.normalize_sensors(1.0) + # Check if we need to normalize + if self.source_sensors_normalized != self.object_sensors_normalized: + # source is scaled, but we need to normalize + if self.object_sensors_normalized: + self.normalize_sensors() + # source is normalizaed by we need to scale + else: + self.scale_sensors() + + def normalize_sensors(self, blade_scale = None): + if not self.htcf is None: + if blade_scale is None: + blade_scale = self.calculate_blade_scale() + for key in self.htcf.all_keys(): + obj = self.htcf[key] + if isinstance(obj, HTCSensor) and not isinstance(obj, HTCSensorAtTime): + obj.normalize_sensor(blade_scale) + + def scale_sensors(self, blade_scale = None): + if not self.htcf is None: + if blade_scale is None: + blade_scale = self.calculate_blade_scale() + for key in self.htcf.all_keys(): + obj = self.htcf[key] + if isinstance(obj, HTCSensor) and not isinstance(obj, HTCSensorAtTime): + obj.scale_sensors(blade_scale) + + # This is meant to delete the ersults from an old out-of-date calculation + def delete_output_files(self): + print('delete_output_files') + + # This is meant to write the input files + def write_input_files(self, write_directory = None, force_write = False): + + if not write_directory is None: + self.write_directory = os.path.abspath(os.path.realpath(write_directory)) + + if self.write_directory is None: + raise Exception('The write directory has not been specified') + + if self.write_directory == self.source_directory and not force_write: + raise Exception('Cannot write the contents into the source directory without the write being forced') + + # Get the directory + old_home = os.getcwd() + + # Change to the htc directory + os.chdir(self.write_directory) + + # scale sensors for writing + if self.object_sensors_normalized: + self.scale_sensors() + + # Start to write every thing + # First we need to write and rename the extra files + extra_files = self.input_files.get_all_extra_inputs() + for file_obj in extra_files: + if file_obj.original_file.startswith(self.source_directory): + if self.source_directory != self.write_directory: + file_obj.written_file = file_obj.original_file.replace(self.source_directory, self.write_directory) + self.htcf[file_obj.key] = file_obj.written_file + else: + file_obj.written_file = file_obj.original_file + if not file_obj.file_object is None: + fout = open_file_in_dir(file_obj.written_file, 'w') + fout.write(str(file_obj.file_object)) + fout.close() + elif file_obj.original_file != file_obj.written_file and not os.path.exists(file_obj.written_file): + is_good = False + try: + mkdir_for_file_in_dir(file_obj.written_file) + os.symlink(file_obj.original_file, file_obj.written_file) + is_good = True + except: + pass + if not is_good: + mkdir_for_file_in_dir(file_obj.written_file) + shutil.copyfile(file_obj.original_file, file_obj.written_file) + is_good = True + else: + file_obj.written_file = file_obj.original_file + # Now write the HTC file + self.input_files['htc'][0].written_file = os.path.join(self.write_directory, self.source_name) + fout = open_file_in_dir(self.input_files['htc'][0].written_file, 'w') + fout.write(str(self.htcf)) + fout.close() + + # normalize sensors + if self.object_sensors_normalized: + self.normalize_sensor() + + # return to the old directory + os.chdir(old_home) + + # This will set the write directory + def set_write_directory(self, write_directory): + self.write_directory = os.path.abspath(os.path.realpath(write_directory)) + + # Tests whether the input for the current state has already been written + def does_input_exist(self): + print('does_input_exist called') + return False + + # This will execute the simulation + def run_simulation(self): + + # Get the directory + old_home = os.getcwd() + + # Change to the htc directory + os.chdir(self.write_directory) + + # This is the point where you would specify that a file is running + print('Now the code would execute the model') + # These values allow for some second attempts at running HAWC2 (occasionally it crashed right away with wine) + exec_str = self.exec_command+' '+self.input_files['htc'][0].written_file + exec_str = exec_str.split() + if not self.exec_dry_run: + self.exec_success = False + try_count = 0 + if self.exec_use_try_except: + while not self.exec_success and try_count<self.exec_retry_count: + try_count+=1 + try: + if self.exec_use_time_out: + proc = subprocess.check_output(exec_str, timeout=self.exec_time_out) + else: + proc = subprocess.check_output(exec_str) + self.exec_success = True + if self.exec_verbose: + print(exec_str, 'output:') + print(proc) + except: + # wait a little and try again + if try_count<self.exec_retry_count: + print(exec_str, ' crashed for case __ ... About to execute another attempt') + time.sleep(self.exec_sleep_time) + else: + print(exec_str, ' crashed for case __ for the final time, it appears something fundamental is wrong') + else: + if self.exec_use_time_out: + proc = subprocess.check_output(exec_str, timeout=self.exec_time_out) + else: + proc = subprocess.check_output(exec_str) + self.exec_success = True + if self.exec_verbose: + print(exec_str, 'output:') + print(proc) + else: + print(exec_str + ' dry run...') + self.exec_success = True + + # return to the old directory + os.chdir(old_home) + + # This will load a simulation from source + def load_simulation(self, source_file_in=None): + + if not source_file_in is None: + self.source_file=source_file_in + + # Get the directory + old_home = os.getcwd() + + # Get the source directory + dirname = os.path.dirname(self.source_file) + self.source_directory = os.path.abspath(os.path.realpath(dirname)) + + # Change to the htc directory + os.chdir(self.source_directory) + + # load in the contents + # Load in the HTC file + self.source_name = os.path.basename(self.source_file) + self.htcf = HTCFile(self.source_name) + self.set_sensor_normalization_scheme(self.source_sensors_normalized, self.object_sensors_normalized) + + # load in the other files linked in the HTC file + self.input_files = self.htcf.get_input_files_and_keys() + if 'st' in self.input_files: + for body_key, input_data in self.input_files['st'].items(): + timo_input = self.htcf[input_data.key[:-11]] + if 'FPM' in timo_input and timo_input['FPM.0']==1: + input_data.file_object = StFPMData(input_data.original_file) + else: + input_data.file_object = StOrigData(input_data.original_file) + timo_input['st_object'] = input_data.file_object + if 'ae' in self.input_files: + self.input_files['ae'].file_object = AEFile(self.input_files['ae'].original_file) + self.htcf['aero.ae_object'] = self.input_files['ae'].file_object + if 'pc' in self.input_files: + self.input_files['pc'].file_object = PCData(self.input_files['pc'].original_file) + self.htcf['aero.pc_object'] = self.input_files['pc'].file_object + + # return to the old directory + os.chdir(old_home) + + def load_results(self): + + # Get the directory + old_home = os.getcwd() + + if self.htcf is None: + raise Exception('There is no simulation to load results from') + + # Change to the htc directory + os.chdir(self.write_directory) + + # load the results + file_name = self.htcf['output.filename.0'] + self.results = ReadHawc2(file_name) + self.results.load_data() + # Add the keys + sensor_list = self.htcf['output'].sensors + key_list = [] + chcnt = 0 + for sensor in sensor_list: + if sensor['__on__']: + sensor_size = sensor.get_sensor_size() + chcnt+=sensor_size + if sensor_size==1: + key_list.append(sensor.raw_line) + else: + for I in range(0,sensor_size): + key_list.append(sensor.raw_line+'['+str(I)+']') + if chcnt !=self.results.NrCh: + print('An error has been detected that corresponds to inconsistencies in the size of channels. The following is printed for debugging purposes. Compare this with the sel file (or equivalent) to determine what sensor is in error. The data in htc_contents.py needs to be updated to reflect the correct value.') + print('sensor_size', 'starts_at_channel', 'sensor_raw_line') + at_ch=0 + for sensor in sensor_list: + if sensor['__on__']: + sensor_size = sensor.get_sensor_size() + print(sensor_size, at_ch, sensor.raw_line) + at_ch+=sensor_size + raise Exception('It appears the number of channels in the results is different than the number as described by the channels') + self.results.set_keys(key_list) + + # return to the old directory + os.chdir(old_home) + + def add_sensor_from_line(self, line): + if self.htcf is None: + raise Exception('There is no simulation to add sensor to') + self.htcf['output'].add_sensor_from_line(line) + + def keys(self): + retval = [] + if not self.htcf is None: + htc_keys = self.htcf.all_keys() + for key in htc_keys: + retval.append('hawc2_input.'+str(key)) + if not self.results is None: + result_keys = self.results.keys() + for key in result_keys: + retval.append('hawc2_output.'+str(key)) + return retval + + # Retrieve some information from the object + def __getitem__(self,key): + if key == 'hawc2_input': + return self.htcf + elif key == 'hawc2_output': + return self.results + elif key.startswith('hawc2_input.'): + if self.htcf is None: + raise Exception('The HAWC2 input structure has not been created') + key = key[len('hawc2_input.'):] + return self.htcf[key] + elif key.startswith('hawc2_output.'): + if self.results is None: + raise Exception('The HAWC2 output structure has not been created') + key = key[len('hawc2_output.'):] + return self.results[key] + else: + raise KeyError('That key does not exist') + + # Set some information from on the object + def __setitem__(self,key,value): + if key == 'hawc2_input': + self.htcf = value + elif key == 'hawc2_output': + self.results = value + elif key.startswith('hawc2_input.'): + if self.htcf is None: + raise Exception('The HAWC2 input structure has not been created') + key = key[len('hawc2_input.'):] + self.htcf[key] = value + elif key.startswith('hawc2_output.'): + if self.results is None: + raise Exception('The HAWC2 output structure has not been created') + key = key[len('hawc2_output.'):] + self.results[key] = value + else: + raise KeyError('That key does not exist') + diff --git a/wetb/hawc2/htc_contents.py b/wetb/hawc2/htc_contents.py index f44977b..af7ef30 100644 --- a/wetb/hawc2/htc_contents.py +++ b/wetb/hawc2/htc_contents.py @@ -14,6 +14,7 @@ from builtins import zip from builtins import int from builtins import str from future import standard_library +from math import sqrt import os standard_library.install_aliases() from collections import OrderedDict @@ -85,7 +86,8 @@ class HTCContents(object): if isinstance(key, str): key = int(key) self.values[key] = value - value.parent=self + if isinstance(value, HTCContents): + value.parent=self def __getitem__(self, key): if key == '__on__': @@ -186,8 +188,13 @@ class HTCContents(object): else: # If this is a duplicate, replace the original as an enumerated key if key_for_object in self: - self[key_for_object+'__1'] = self[key_for_object] - del self[key_for_object] + tmp_dict = OrderedDict() + for k, v in self.contents.items(): + if k == key_for_object: + tmp_dict[key_for_object+'__1'] = v + else: + tmp_dict[k] = v + self.contents=tmp_dict ending = "__2" while key_for_object + ending in self: ending = "__%d" % (1 + float("0%s" % ending.replace("__", ""))) @@ -509,7 +516,7 @@ class HTCLine(HTCContents): ("", "\t" + self.comments)[bool(self.comments.strip())]) def str_values(self): - return " ".join([str(v).lower() for v in self.values]) + return " ".join([str(v) for v in self.values]) def __getitem__(self, key): if key == "__on__": @@ -607,7 +614,10 @@ class HTCC2DefSection(HTCSection): self.on = bool(value) return - if key == 'nsec': + elif key == 'grid': + raise KeyError('The grid property is read-only') + + elif key == 'nsec': # do nothing if there is nothing to do if self.nsec == int(value): @@ -641,20 +651,24 @@ class HTCC2DefSection(HTCSection): self.theta[:asgn] = old_val[:asgn] return - if value.size != self.nsec: - ValueError('The value size is not consistent with the object size') + else: + if value.size != self.nsec: + raise ValueError('The value size is not consistent with the object size') - if key == 'x': - self.x = value + if key == 'x': + self.x = value - if key == 'y': - self.y = value + elif key == 'y': + self.y = value - if key == 'z': - self.z = value + elif key == 'z': + self.z = value - if key == 'theta': - self.theta = value + elif key == 'theta': + self.theta = value + + else: + raise KeyError('That key does not exist') def __getitem__(self, key): if key == '__on__': @@ -669,6 +683,14 @@ class HTCC2DefSection(HTCSection): return self.z if key == 'theta': return self.theta + if key == 'grid': + retval = np.zeros(self.nsec) + at_s = 0.0 + for I in range(0, self.nsec): + retval[I]=at_s + if (I+1)<self.nsec: + at_s+=sqrt( (self.x[I+1]-self.x[I])**2.0 + (self.y[I+1]-self.y[I])**2.0 + (self.z[I+1]-self.z[I])**2.0 ) + return retval def __iter__(self): return iter([self.nsec, self.x, self.y, self.z, self.theta]) @@ -683,14 +705,14 @@ class HTCC2DefSection(HTCSection): if not self.on: return "" s = "%sbegin %s;%s\n"%(" "*level, self.name_, ("", "\t" + self.begin_comments)[bool(self.begin_comments.strip())]) - s += "%s nsec %d\n"%(" "*level, self.nsec) + s += "%s nsec %d;\n"%(" "*level, self.nsec) for I in range(0,self.nsec): s += "%s sec %d %0.17e %0.17e %0.17e %0.17e;\n"%(" "*level, I+1, self.x[I], self.y[I], self.z[I], self.theta[I]) s += "%send %s;%s\n" % (" "*level, self.name_, ("", "\t" + self.end_comments)[self.end_comments.strip() != ""]) return s def keys(self): - return ['__on__', 'nsec', 'x', 'y', 'z', 'theta'] + return ['__on__', 'nsec', 'x', 'y', 'z', 'theta', 'grid'] def all_keys(self): return self.keys() @@ -864,6 +886,8 @@ def get_sensor_scale_parameter(sensor_type, sensor): return 4 return None + + class HTCSensor(HTCLine): sns_type = "" sensor = "" @@ -877,6 +901,285 @@ class HTCSensor(HTCLine): self.values = values self.comments = comments.strip(" \t") self.is_normalized = False + + def parameter_count(self): + if self.sns_type == 'mbdy': + if self.sensor in ('forcevec', 'momentvec'): + return 4 + elif self.sensor in ('state', 'state_rot'): + return 5 + elif self.sensor in ('state_at', 'state_at2'): + return 7 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the parameter count function' + raise Exception(msg) + elif self.sns_type == 'constraint': + if self.sensor in ('bearing1', 'bearing2', 'bearing3', 'bearing4'): + return 2 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the parameter count function' + raise Exception(msg) + elif self.sns_type == 'body': + if self.sensor in ('pitchangle', 'pitchspeed'): + return 2 + elif self.sensor in ('forcevec', 'momentvec', 'node_defl', 'node_rot'): + return 4 + elif self.sensor in ('node_state',): + return 5 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the parameter count function' + raise Exception(msg) + elif self.sns_type == 'aero': + #0 'time' + #0 'omega' + #0 'torque' + #0 'thrust' + #0 'power' + #0 'induc_a_norm' + #0 'lambda' + #1 'azimuth' + #1 'induc_am_norm' + #1 'grid_radius_nd' + #2 'vrel' + #2 'alfa' + #2 'alfadot' + #2 'sideslip' + #2 'beta' + #2 'cl' + #2 'cd' + #2 'cm' + #2 'lift' + #2 'drag' + #2 'moment' + #2 'tors_e' + #2 'induc_sector_ct' + #2 'induc_sector_cq' + #2 'induc_sector_a' + #2 'induc_sector_am' + #2 'inflow_angle' + #2 'dcldalfa' + #2 'dcddalfa' + #2 'gamma' + #2 'actuatordiskload' + #2 'vawt_induc_x' + #2 'vawt_induc_y' + #3 'secforce' + #3 'secmoment' + #4 'int_force' + #4 'int_moment' + #4 'position' + #4 'rotation' + #4 'velocity' + #4 'acceleration' + #4 'windspeed' + #4 'induc' + #4 'windspeed_boom' + #9 'spinner_lidar' + if self.sensor in ('time', 'omega', 'torque', 'thrust', 'power', 'induc_a_norm', 'lambda'): + return 0 + elif self.sensor in ('azimuth', 'induc_am_norm', 'grid_radius_nd'): + return 1 + elif self.sensor in ('vrel', 'alfa', 'alfadot', 'sideslip', 'beta', 'cl', 'cd', 'cm', 'lift', 'drag', 'moment', 'tors_e', 'induc_sector_ct', 'induc_sector_cq', 'induc_sector_a', 'induc_sector_am', 'inflow_angle', 'dcldalfa', 'dcddalfa', 'gamma', 'actuatordiskload', 'vawt_induc_x', 'vawt_induc_y'): + return 2 + elif self.sensor in ('secforce', 'secmoment'): + return 3 + elif self.sensor in ('int_force', 'int_moment', 'position', 'rotation', 'velocity', 'acceleration', 'windspeed', 'induc', 'windspeed_boom'): + return 4 + elif self.sensor in ('spinner_lidar',): + return 9 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the parameter count function' + raise Exception(msg) + elif self.sns_type == 'wind': + if self.sensor in ('free_wind_hor', 'free_wind', 'free_wind_shadow'): + return 4 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the parameter count function' + raise Exception(msg) + elif self.sns_type == 'wind_wake': + if self.sensor in ('wake_pos',): + return 1 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the parameter count function' + raise Exception(msg) + elif self.sns_type == 'dll': + if self.sensor in ('inpvec', 'outvec'): + return 2 + if self.sensor in ('hawc_dll', 'type2_dll'): + return 3 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the parameter count function' + raise Exception(msg) + elif self.sns_type == 'hydro': + if self.sensor in ('water_surface',): + return 2 + elif self.sensor in ('fm', 'fd', 'water_vel_acc'): + return 3 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the parameter count function' + raise Exception(msg) + elif self.sns_type == 'general': + if self.sensor in ('time', 'deltat', 'status'): + return 0 + elif self.sensor in ('constant',): + return 1 + elif self.sensor in ('step', 'harmonic', 'random', 'impulse'): + return 3 + elif self.sensor in ('step2', 'step3'): + return 4 + elif self.sensor in ('harmonic2', 'stairs'): + return 5 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the parameter count function' + raise Exception(msg) + else: + msg='Sensor "'+str(self.sns_type)+' ..." has not been defined in the parameter count function' + raise Exception(msg) + + def has_only_option(self): + if self.sns_type == 'mbdy': + if self.sensor in ('forcevec', 'momentvec', 'state', 'state_at', 'state_at2', 'state_rot'): + return True + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the has only option function' + raise Exception(msg) + elif self.sns_type == 'constraint': + if self.sensor in ('bearing1', 'bearing2', 'bearing3', 'bearing4'): + return True + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the has only option function' + raise Exception(msg) + elif self.sns_type == 'body': + if self.sensor in ('pitchangle', 'pitchspeed', 'forcevec', 'momentvec', 'node_defl', 'node_rot', 'node_state'): + return False + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the has only option function' + raise Exception(msg) + elif self.sns_type == 'aero': + if self.sensor in ('time', 'azimuth', 'omega', 'vrel', 'alfa', 'alfadot', 'sideslip', 'beta', 'cl', 'cd', 'cm', 'lift', 'drag', 'moment', 'secforce', 'secmoment', 'int_force', 'int_moment', 'torque', 'thrust', 'position', 'power', 'rotation', 'velocity', 'acceleration', 'tors_e', 'windspeed', 'induc', 'induc_sector_ct', 'induc_sector_cq', 'induc_sector_a', 'induc_sector_am', 'induc_a_norm', 'induc_am_norm', 'inflow_angle', 'dcldalfa', 'dcddalfa', 'gamma', 'lambda', 'windspeed_boom', 'actuatordiskload', 'grid_radius_nd', 'vawt_induc_x', 'vawt_induc_y', 'spinner_lidar'): + return False + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the has only option function' + raise Exception(msg) + elif self.sns_type == 'wind': + if self.sensor in ('free_wind_hor', 'free_wind', 'free_wind_shadow'): + return True + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the has only option function' + raise Exception(msg) + elif self.sns_type == 'wind_wake': + if self.sensor in ('wake_pos',): + return True + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the has only option function' + raise Exception(msg) + elif self.sns_type == 'dll': + if self.sensor in ('inpvec', 'outvec', 'hawc_dll', 'type2_dll'): + return False + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the has only option function' + raise Exception(msg) + elif self.sns_type == 'hydro': + if self.sensor in ('water_surface',): + return False + elif self.sensor in ('fm', 'fd', 'water_vel_acc'): + return True + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the has only option function' + raise Exception(msg) + elif self.sns_type == 'general': + if self.sensor in ('constant', 'step', 'step2', 'step3', 'time', 'deltat', 'harmonic', 'harmonic2', 'stairs', 'status', 'random', 'impulse'): + return False + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the has only option function' + raise Exception(msg) + else: + msg='Sensor "'+str(self.sns_type)+' ..." has not been defined in the has only option function' + raise Exception(msg) + + def get_full_sensor_size(self): + if self.sns_type == 'mbdy': + if self.sensor in ('forcevec', 'momentvec', 'state', 'state_at', 'state_at2'): + return 3 + elif self.sensor == 'state_rot': + if self.values[0] in ('eulerang_xyz', 'omega', 'omegadot', 'proj_ang'): + return 3 + elif self.values[0] in ('axisangle', 'eulerp'): + return 4 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' '+str(self.values[0])+' ..." has not been defined in the sensor size function' + raise Exception(msg) + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the sensor size function' + raise Exception(msg) + elif self.sns_type == 'constraint': + if self.sensor in ('bearing1', 'bearing2', 'bearing3', 'bearing4'): + return 2 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the sensor size function' + raise Exception(msg) + elif self.sns_type == 'body': + if self.sensor in ('pitchangle', 'pitchspeed'): + return 1 + elif self.sensor in ('forcevec', 'momentvec', 'node_defl', 'node_rot', 'node_state'): + return 3 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the sensor size function' + raise Exception(msg) + elif self.sns_type == 'aero': + if self.sensor in ('time', 'azimuth', 'omega', 'vrel', 'alfa', 'alfadot', 'sideslip', 'beta', 'cl', 'cd', 'cm', 'lift', 'drag', 'moment', 'secforce', 'secmoment', 'int_force', 'int_moment', 'torque', 'thrust', 'position', 'power', 'rotation', 'velocity', 'acceleration', 'tors_e', 'windspeed', 'induc', 'induc_sector_ct', 'induc_sector_cq', 'induc_sector_a', 'induc_sector_am', 'induc_a_norm', 'induc_am_norm', 'inflow_angle', 'dcldalfa', 'dcddalfa', 'gamma', 'lambda', 'windspeed_boom', 'actuatordiskload', 'grid_radius_nd', 'vawt_induc_x', 'vawt_induc_y'): + return 1 + if self.sensor in ('spinner_lidar',): + return 3 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the sensor size function' + raise Exception(msg) + elif self.sns_type == 'wind': + if self.sensor in ('free_wind_hor',): + return 2 + elif self.sensor in ('free_wind', 'free_wind_shadow'): + return 3 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the sensor size function' + raise Exception(msg) + elif self.sns_type == 'wind_wake': + if self.sensor in ('wake_pos',): + return 3 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the sensor size function' + raise Exception(msg) + elif self.sns_type == 'dll': + if self.sensor in ('inpvec', 'outvec', 'hawc_dll', 'type2_dll'): + return 1 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the sensor size function' + raise Exception(msg) + elif self.sns_type == 'hydro': + if self.sensor in ('water_surface',): + return 1 + elif self.sensor in ('fm', 'fd'): + return 3 + elif self.sensor in ('water_vel_acc',): + return 6 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the sensor size function' + raise Exception(msg) + elif self.sns_type == 'general': + if self.sensor in ('constant', 'step', 'step2', 'step3', 'time', 'deltat', 'harmonic', 'harmonic2', 'stairs', 'status', 'random', 'impulse'): + return 1 + else: + msg='Sensor "'+str(self.sns_type)+' '+str(self.sensor)+' ..." has not been defined in the sensor size function' + raise Exception(msg) + else: + msg='Sensor "'+str(self.sns_type)+' ..." has not been defined in the sensor size function' + raise Exception(msg) + + def get_sensor_size(self): + if self.has_only_option(): + param_cnt = self.parameter_count() + if len(self.values)>param_cnt and self.values[param_cnt]=='only': + return 1 + return self.get_full_sensor_size() # This will take the radius an normalize it def normalize_sensor(self, scale=None): diff --git a/wetb/hawc2/htc_file.py b/wetb/hawc2/htc_file.py index b38faec..98de5f2 100644 --- a/wetb/hawc2/htc_file.py +++ b/wetb/hawc2/htc_file.py @@ -357,6 +357,7 @@ class HTCFile(HTCContents, HTCDefaults, HTCExtensions): self.wind.scale_time_start = start def get_input_files_and_keys(self): + self.contents # load if not loaded retval = HAWC2_Input_Files() @@ -457,8 +458,11 @@ class HTCFile(HTCContents, HTCDefaults, HTCExtensions): files.append(self.aero.dynstall_ateflap.get('flap', [None] * 3)[2]) if 'bemwake_method' in self.aero: files.append(self.aero.bemwake_method.get('a-ct-filename', [None] * 3)[0]) - for dll in [self.dll[dll] for dll in self.get('dll', {}).keys() if 'filename' in self.dll[dll]]: - files.append(dll.filename[0]) + for dll_object in self['dll']: + if isinstance(dll_object, HTCContents) and 'filename' in dll_object.keys(): + files.append(dll_object['filename.0']) + #for dll in [self.dll[dll] for dll in self.get('dll', {}).keys() if 'filename' in self.dll[dll]]: + # files.append(dll.filename[0]) if 'wind' in self: files.append(self.wind.get('user_defined_shear', [None])[0]) files.append(self.wind.get('user_defined_shear_turbulence', [None])[0]) -- GitLab