diff --git a/sharpy/aero/models/aerogrid.py b/sharpy/aero/models/aerogrid.py index 4ba0d4f74..72794ce01 100644 --- a/sharpy/aero/models/aerogrid.py +++ b/sharpy/aero/models/aerogrid.py @@ -34,6 +34,8 @@ def __init__(self): self.cs_generators = [] + self.initial_strip_z_rot = None + def generate(self, data_dict, beam, settings, ts): super().generate(data_dict, beam, settings, ts) @@ -44,6 +46,15 @@ def generate(self, data_dict, beam, settings, ts): self.ini_info = AeroTimeStepInfo(self.dimensions, self.dimensions_star) + # Initial panel orientation, used when aligned grid is off + self.initial_strip_z_rot = np.zeros([self.n_elem, 3]) + if not settings['aligned_grid'] and settings['initial_align']: + for i_elem in range(self.n_elem): + for i_local_node in range(3): + Cab = algebra.crv2rotation(beam.ini_info.psi[i_elem, i_local_node, :]) + self.initial_strip_z_rot[i_elem, i_local_node] = \ + algebra.angle_between_vectors_sign(settings['freestream_dir'], Cab[:, 1], Cab[:, 2]) + # load airfoils db # for i_node in range(self.n_node): for i_elem in range(self.n_elem): @@ -288,6 +299,7 @@ def generate_zeta_timestep_info(self, structure_tstep, aero_tstep, beam, setting generate_strip(node_info, self.airfoil_db, self.aero_settings['aligned_grid'], + initial_strip_z_rot=self.initial_strip_z_rot[i_elem, i_local_node], orientation_in=self.aero_settings['freestream_dir'], calculate_zeta_dot=True)) # set junction boundary conditions for later phantom cell creation in UVLM @@ -300,8 +312,6 @@ def generate_phantom_panels_at_junction(self, aero_tstep): for i_surf in range(self.n_surf): aero_tstep.flag_zeta_phantom[0, i_surf] = self.data_dict["junction_boundary_condition"][0,i_surf] - - @staticmethod def compute_gamma_dot(dt, tstep, previous_tsteps): r""" @@ -372,6 +382,7 @@ def compute_gamma_dot(dt, tstep, previous_tsteps): def generate_strip(node_info, airfoil_db, aligned_grid, + initial_strip_z_rot, orientation_in=np.array([1, 0, 0]), calculate_zeta_dot = False, first_twist=True): @@ -447,11 +458,10 @@ def generate_strip(node_info, airfoil_db, aligned_grid, # Cab transformation Cab = algebra.crv2rotation(node_info['beam_psi']) - rot_angle = algebra.angle_between_vectors_sign(orientation_in, Cab[:, 1], Cab[:, 2]) - if np.sign(np.dot(orientation_in, Cab[:, 1])) >= 0: - rot_angle += 0.0 + if aligned_grid: + rot_angle = algebra.angle_between_vectors_sign(orientation_in, Cab[:, 1], Cab[:, 2]) else: - rot_angle += -2*np.pi + rot_angle = initial_strip_z_rot Crot = algebra.rotation3d_z(-rot_angle) c_sweep = np.eye(3) diff --git a/sharpy/solvers/aerogridloader.py b/sharpy/solvers/aerogridloader.py index af8098676..d38de2292 100644 --- a/sharpy/solvers/aerogridloader.py +++ b/sharpy/solvers/aerogridloader.py @@ -29,6 +29,10 @@ class AerogridLoader(GridLoader): surface is simply static, an empty string should be parsed. See the documentation for ``DynamicControlSurface`` generators for accepted key-value pairs as settings. + The ``initial_align`` setting aligns the wing panel discretization with the freestream for the undeformed structure, + and applies this Z rotation at every timestep (panels become misaligned when the wing deforms). The ``aligned_grid`` + setting aligns the wing panel discretization with the flow at every time step and takes precedence. + Args: data (PreSharpy): ``ProblemData`` class structure @@ -59,6 +63,10 @@ class AerogridLoader(GridLoader): settings_default['aligned_grid'] = True settings_description['aligned_grid'] = 'Align grid' + settings_types['initial_align'] = 'bool' + settings_default['initial_align'] = True + settings_description['initial_align'] = "Initially align grid" + settings_types['freestream_dir'] = 'list(float)' settings_default['freestream_dir'] = [1.0, 0.0, 0.0] settings_description['freestream_dir'] = 'Free stream flow direction'