Source code for sharpy.postproc.stallcheck

import numpy as np
import sharpy.utils.cout_utils as cout
from sharpy.utils.solver_interface import solver, BaseSolver
import sharpy.utils.settings as settings_utils
from sharpy.utils.datastructures import init_matrix_structure, standalone_ctypes_pointer
import sharpy.aero.utils.uvlmlib as uvlmlib


[docs]@solver class StallCheck(BaseSolver): """ Outputs the incidence angle of every panel of the surface as cell variables for visualisation in Paraview. Note: This postprocessor appends the information to the current SHARPy timestep being run, therefore, in order to visualise the result in Paraview, it must be run prior to `AerogridPlot`. Otherwise, the panel stall check will be performed but the actual angle not produced in the Paraview visualisation. It also checks that the angles do not exceed the specified limit, with a warning in the log if the angle of attack exceeds such limits (both positive and negative). The limits are set through the setting ``airfoil_stall_angles``, which takes a dictionary where the key is the ID to the airfoil (in string format) and the value is a 2-tuple containing the negative and positive limits in radians. """ solver_id = 'StallCheck' solver_classification = 'post-processor' settings_types = dict() settings_default = dict() settings_description = dict() settings_types['print_info'] = 'bool' settings_default['print_info'] = True settings_description['print_info'] = 'Print info to screen ' settings_types['airfoil_stall_angles'] = 'dict' settings_default['airfoil_stall_angles'] = dict() settings_description['airfoil_stall_angles'] = 'Dictionary of stall angles for each airfoil as per the details ' \ 'above' settings_types['output_degrees'] = 'bool' settings_default['output_degrees'] = False settings_description['output_degrees'] = 'Output incidence angles in degrees vs radians' settings_table = settings_utils.SettingsTable() __doc__ += settings_table.generate(settings_types, settings_default, settings_description) def __init__(self): self.settings = None self.data = None self.ts_max = None self.ts = None self.caller = None def initialise(self, data, custom_settings=None, caller=None, restart=False): self.data = data if custom_settings is None: self.settings = data.settings[self.solver_id] else: self.settings = custom_settings settings_utils.to_custom_types(self.settings, self.settings_types, self.settings_default) self.ts_max = len(self.data.structure.timestep_info) self.caller = caller def run(self, **kwargs): online = settings_utils.set_value_or_default(kwargs, 'online', False) if not online: for self.ts in range(self.ts_max): self.check_stall() cout.cout_wrap('...Finished', 1) else: self.ts = len(self.data.structure.timestep_info) - 1 self.check_stall() return self.data def check_stall(self): # add entry to dictionary for postproc tstep = self.data.aero.timestep_info[self.ts] tstep.postproc_cell['incidence_angle'] = init_matrix_structure(dimensions=tstep.dimensions, with_dim_dimension=False) # create ctypes pointers tstep.postproc_cell['incidence_angle_ct_list'] = None tstep.postproc_cell['incidence_angle_ct_pointer'] = None tstep.postproc_cell['incidence_angle_ct_list'], tstep.postproc_cell['incidence_angle_ct_pointer'] = \ standalone_ctypes_pointer(tstep.postproc_cell['incidence_angle']) # call calculate uvlmlib.uvlm_calculate_incidence_angle(self.data.aero.timestep_info[self.ts], self.data.structure.timestep_info[self.ts]) # calculate ratio of stalled panels and print stalled_panels = False stalled_surfs = np.zeros((tstep.n_surf, ), dtype=int) added_panels = [] for i_surf in range(tstep.n_surf): added_panels.append([]) for i_elem in range(self.data.structure.num_elem): for i_local_node in range(self.data.structure.num_node_elem): airfoil_id = self.data.aero.data_dict['airfoil_distribution'][i_elem, i_local_node] if self.settings['airfoil_stall_angles']: i_global_node = self.data.structure.connectivities[i_elem, i_local_node] for i_dict in self.data.aero.struct2aero_mapping[i_global_node]: i_surf = i_dict['i_surf'] i_n = i_dict['i_n'] if i_n in added_panels[i_surf]: continue if i_n == tstep.dimensions[i_surf][1]: continue limits = self.settings['airfoil_stall_angles'][str(airfoil_id)] if tstep.postproc_cell['incidence_angle'][i_surf][0, i_n] < float(limits[0]): stalled_panels = True stalled_surfs[i_surf] += tstep.postproc_cell['incidence_angle'][i_surf].shape[1] elif tstep.postproc_cell['incidence_angle'][i_surf][0, i_n] > float(limits[1]): stalled_panels = True stalled_surfs[i_surf] += tstep.postproc_cell['incidence_angle'][i_surf].shape[1] if stalled_panels: if self.settings['print_info']: cout.cout_wrap('Some panel has an incidence angle out of the linear region', 1) cout.cout_wrap('The number of stalled panels per surface id are:', 1) for i_surf in range(tstep.n_surf): cout.cout_wrap('\ti_surf = ' + str(i_surf) + ': ' + str(stalled_surfs[i_surf]) + ' panels.', 1) # cout.cout_wrap('In total, the ratio of stalled panels is: ', str(stalled_surfs.sum()/)) if self.settings['output_degrees']: for i_surf in range(tstep.n_surf): tstep.postproc_cell['incidence_angle'][i_surf] *= 180/np.pi