Esempio n. 1
0
    def run_wagner(self, Nsurf, integr_ord, RemovePred, UseSparse, RollNodes):
        """
        see test_wagner
        """

        ### ----- set reference solution
        self.setUp_from_params(Nsurf, integr_ord, RemovePred, UseSparse,
                               RollNodes)
        tsaero0 = self.tsaero0
        ws = self.ws
        M = self.M
        N = self.N
        Mstar_fact = self.Mstar_fact
        Uinf0 = self.Uinf0

        ### ----- linearisation
        uvlm = linuvlm.Dynamic(tsaero0,
                               dynamic_settings=ws.config['LinearUvlm'])
        uvlm.assemble_ss()
        zeta_pole = np.array([0., 0., 0.])
        uvlm.get_total_forces_gain(zeta_pole=zeta_pole)
        uvlm.get_rigid_motion_gains(zeta_rotation=zeta_pole)
        uvlm.get_sect_forces_gain()

        ### ----- Scale gains
        Fref_tot = self.Fref_tot
        Fref_span = self.Fref_span
        uvlm.Kftot = uvlm.Kftot / Fref_tot
        uvlm.Kmtot = uvlm.Kmtot / Fref_tot / ws.c_ref
        uvlm.Kfsec /= Fref_span
        uvlm.Kmsec /= (Fref_span * ws.c_ref)

        ### ----- step input
        # rotate incoming flow, wing lattice and wing lattice speed about
        # the (rolled) wing elastic axis to create an effective angle of attack.
        # Rotation is expressed through a CRV.
        delta_AlphaEffDeg = 1e-2
        delta_AlphaEffRad = 1e-2 * np.pi / 180.

        Roll0Rad = self.Roll0Deg / 180. * np.pi
        dcrv = -delta_AlphaEffRad * np.array(
            [0., np.cos(Roll0Rad), np.sin(Roll0Rad)])
        uvec0 = np.array([Uinf0, 0, 0])
        uvec = np.dot(algebra.crv2rotation(dcrv), uvec0)
        duvec = uvec - uvec0
        dzeta = np.zeros((Nsurf, 3, M + 1, N // Nsurf + 1))
        dzeta_dot = np.zeros((Nsurf, 3, M + 1, N // Nsurf + 1))
        du_ext = np.zeros((Nsurf, 3, M + 1, N // Nsurf + 1))

        for ss in range(Nsurf):
            for mm in range(M + 1):
                for nn in range(N // Nsurf + 1):
                    dzeta_dot[ss, :, mm, nn] = -1. / 3 * duvec
                    du_ext[ss, :, mm, nn] = +1. / 3 * duvec
                    dzeta = 1. / 3 * np.dot(uvlm.Krot, dcrv)
        Uaero = np.concatenate(
            (dzeta.reshape(-1), dzeta_dot.reshape(-1), du_ext.reshape(-1)))

        ### ----- Steady state solution
        xste, yste = uvlm.solve_steady(Uaero)
        Ftot_ste = np.dot(uvlm.Kftot, yste)
        Mtot_ste = np.dot(uvlm.Kmtot, yste)
        # first check of gain matrices...
        Ftot_ste_ref = np.zeros((3, ))
        Mtot_ste_ref = np.zeros((3, ))
        fnodes = yste.reshape((Nsurf, 3, M + 1, N // Nsurf + 1))
        for ss in range(Nsurf):
            for nn in range(N // Nsurf + 1):
                for mm in range(M + 1):
                    Ftot_ste_ref += fnodes[ss, :, mm, nn]
                    Mtot_ste_ref += np.cross(uvlm.MS.Surfs[ss].zeta[:, mm, nn],
                                             fnodes[ss, :, mm, nn])
        Ftot_ste_ref /= Fref_tot
        Mtot_ste_ref /= (Fref_tot * ws.c_ref)
        Fmag = np.linalg.norm(Ftot_ste_ref)
        er_f = np.max(np.abs(Ftot_ste - Ftot_ste_ref)) / Fmag
        er_m = np.max(np.abs(Mtot_ste - Mtot_ste_ref)) / Fmag / ws.c_ref
        assert (er_f < 1e-8 and er_m < 1e-8), \
            'Error of total forces (%.2e) and moment (%.2e) too large!' % (er_f, er_m) + \
            'Verify gains produced by linuvlm.Dynamic.get_total_forces_gain.'

        # then compare against analytical ...
        Cl_inf = delta_AlphaEffRad * np.pi * 2.
        Cfvec_inf = Cl_inf * np.array(
            [0., -np.sin(Roll0Rad), np.cos(Roll0Rad)])
        er_f = np.abs(np.linalg.norm(Ftot_ste) / Cl_inf - 1.)
        assert (er_f < 1e-2), \
            'Error of total lift coefficient (%.2e) too large!' % (er_f,) + \
            'Verify linuvlm.Dynamic.'
        er_f = np.abs(np.linalg.norm(Ftot_ste - Cfvec_inf) / Cl_inf)
        assert (er_f < 1e-2), \
            'Error of total aero force (%.2e) too large!' % (er_f,) + \
            'Verify linuvlm.Dynamic.'

        # ... and finally compare against non-linear UVLM
        # ps: here we roll the wing and rotate the incoming flow to generate an effective
        # angle of attack
        case_pert = 'wagner_r%.4daeff%.2d_rnodes%s_Nsurf%.2dM%.2dN%.2dwk%.2d' \
                    % (int(np.round(100 * self.Roll0Deg)),
                       int(np.round(100 * delta_AlphaEffDeg)),
                       RollNodes,
                       Nsurf, M, N, Mstar_fact)
        ws_pert = flying_wings.QuasiInfinite(M=M,
                                             N=N,
                                             Mstar_fact=Mstar_fact,
                                             n_surfaces=Nsurf,
                                             u_inf=Uinf0,
                                             alpha=self.Alpha0Deg,
                                             roll=self.Roll0Deg,
                                             aspect_ratio=1e5,
                                             route=self.route_main,
                                             case_name=case_pert,
                                             RollNodes=RollNodes)
        ws_pert.u_inf_direction = uvec / Uinf0
        ws_pert.main_ea = ws.main_ea
        ws_pert.clean_test_files()
        ws_pert.update_derived_params()
        ws_pert.generate_fem_file()
        ws_pert.generate_aero_file()

        # solution flow
        ws_pert.set_default_config_dict()
        ws_pert.config['SHARPy']['flow'] = ws.config['SHARPy']['flow']
        ws_pert.config['SHARPy']['write_screen'] = 'off'
        ws_pert.config['SHARPy']['write_log'] = 'off'
        ws_pert.config['SHARPy'][
            'log_folder'] = self.route_test_dir + '/output/' + self.case_code + '/'
        ws_pert.config.write()

        # solve at perturbed point
        data_pert = sharpy.sharpy_main.main(
            ['...', self.route_main + case_pert + '.sharpy'])
        tsaero = data_pert.aero.timestep_info[0]

        self.start_writer()

        # get total forces
        Ftot_ste_pert = np.zeros((3, ))
        Mtot_ste_pert = np.zeros((3, ))
        for ss in range(Nsurf):
            for nn in range(N // Nsurf + 1):
                for mm in range(M + 1):
                    Ftot_ste_pert += tsaero.forces[ss][:3, mm, nn]
                    Mtot_ste_pert += np.cross(
                        uvlm.MS.Surfs[ss].zeta[:, mm, nn],
                        tsaero.forces[ss][:3, mm, nn])
        Ftot_ste_pert /= Fref_tot
        Mtot_ste_pert /= (Fref_tot * ws.c_ref)
        Fmag = np.linalg.norm(Ftot_ste_pert)
        er_f = np.max(np.abs(Ftot_ste - Ftot_ste_pert)) / Fmag
        er_m = np.max(np.abs(Mtot_ste - Mtot_ste_pert)) / Fmag / ws.c_ref
        assert (er_f < 2e-4 and er_m < 2e-4), \
            'Error of total forces (%.2e) and moment (%.2e) ' % (er_f, er_m) + \
            'with respect to geometrically-exact UVLM too large!'

        # and check non-linear uvlm against analytical solution
        er_f = np.abs(np.linalg.norm(Ftot_ste_pert - Cfvec_inf) / Cl_inf)
        assert (er_f <= 1.5e-2), \
            'Error of total aero force components (%.2e) too large!' % (er_f,) + \
            'Verify StaticUvlm'

        ### ----- Analytical step response (Wagner solution)

        NT = 251
        tv = np.linspace(0., uvlm.dt * (NT - 1), NT)
        Clv_an = an.wagner_imp_start(delta_AlphaEffRad, Uinf0, ws.c_ref, tv)
        assert np.abs(Clv_an[-1] / Cl_inf - 1.) < 1e-2, \
            'Did someone modify this test case?! The time should be enough to reach ' \
            'the steady-state CL with a 1 perc. tolerance...'

        Cfvec_an = np.zeros((NT, 3))
        Cfvec_an[:, 1] = -np.sin(Roll0Rad) * Clv_an
        Cfvec_an[:, 2] = np.cos(Roll0Rad) * Clv_an

        ### ----- Dynamic step response

        Fsect = np.zeros((NT, Nsurf, 3, N // Nsurf + 1))
        # Fbeam=np.zeros((NT,6,N//Nsurf+1))
        Ftot = np.zeros((NT, 3))
        Er_f_tot = np.zeros((NT, ))

        # Ybeam=[]
        gamma = np.zeros((NT, Nsurf, M, N // Nsurf))
        gamma_dot = np.zeros((NT, Nsurf, M, N // Nsurf))
        gamma_star = np.zeros((NT, Nsurf, int(M * Mstar_fact), N // Nsurf))
        xold = np.zeros((uvlm.SS.A.shape[0], ))
        for tt in range(1, NT):
            xnew, ynew = uvlm.solve_step(xold, Uaero)
            change = np.linalg.norm(xnew - xold)
            xold = xnew

            # record state ?
            if uvlm.remove_predictor is False:
                gv, gvstar, gvdot = uvlm.unpack_state(xnew)
                gamma[tt, :, :, :] = gv.reshape((Nsurf, M, N // Nsurf))
                gamma_dot[tt, :, :, :] = gvdot.reshape((Nsurf, M, N // Nsurf))
                gamma_star[tt, :, :, :] = gvstar.reshape(
                    (Nsurf, int(M * Mstar_fact), N // Nsurf))

            # calculate forces (and error)
            Ftot[tt, :3] = np.dot(uvlm.Kftot, ynew)
            Er_f_tot[tt] = np.linalg.norm(Ftot[tt, :] -
                                          Cfvec_an[tt, :]) / Clv_an[tt]
            Fsect[tt, :, :, :] = np.dot(uvlm.Kfsec, ynew).reshape(
                (Nsurf, 3, N // Nsurf + 1))

            # ### beam forces
            # Ybeam.append(np.dot(Sol.Kforces[:-10,:],ynew))
            # Fdummy=Ybeam[-1].reshape((N//Nsurf,6)).T
            # Fbeam[tt,:,:N//Nsurf]=Fdummy[:,:N//Nsurf]
            # Fbeam[tt,:,N//Nsurf+1:]=Fdummy[:,N//Nsurf:]

        if RemovePred:
            ts2perc, ts1perc = 6, 6
        else:
            ts2perc, ts1perc = 16, 36
        er_th_2perc = np.max(Er_f_tot[ts2perc:])
        er_th_1perc = np.max(Er_f_tot[ts1perc:])

        ### ----- generate plot
        if self.ProducePlots:

            # sections to plot
            if Nsurf == 1:
                Nplot = [0, N // 2, N]
                labs = [r'tip', r'root', r'tip']
            elif Nsurf == 2:
                Nplot = [0, N // 2 - 1]
                labs = [r'tip', r'near root', r'tip', r'near root']
            axtitle = [r'$C_{F_y}$', r'$C_{F_z}$']

            # non-dimensional time
            sv = 2.0 * Uinf0 * tv / ws.c_ref

            # generate figure
            clist = ['#003366', '#CC3333', '#336633', '#FF6600'] * 4
            fontlabel = 12
            std_params = {
                'legend.fontsize': 10,
                'font.size': fontlabel,
                'xtick.labelsize': fontlabel - 2,
                'ytick.labelsize': fontlabel - 2,
                'figure.autolayout': True,
                'legend.numpoints': 1
            }
            # plt.rcParams.update(std_params)

            # fig = plt.figure('Lift time-history', (12, 6))
            # axvec = fig.subplots(1, 2)
            # for aa in [0, 1]:
            # comp = aa + 1
            # axvec[aa].set_title(axtitle[aa])
            # axvec[aa].plot(sv, Cfvec_an[:, comp] / Cl_inf, lw=4, ls='-',
            # alpha=0.5, color='r', label=r'Wagner')
            # axvec[aa].plot(sv, Ftot[:, comp] / Cl_inf, lw=5, ls=':',
            # alpha=0.7, color='k', label=r'Total')
            # cc = 0
            # for ss in range(Nsurf):
            # for nn in Nplot:
            # axvec[aa].plot(sv, Fsect[:, ss, comp, nn] / Cl_inf,
            # lw=4 - cc, ls='--', alpha=0.7, color=clist[cc],
            # label=r'Surf. %.1d, n=%.2d (%s)' % (ss, nn, labs[cc]))
            # cc += 1
            # axvec[aa].grid(color='0.8', ls='-')
            # axvec[aa].grid(color='0.85', ls='-', which='minor')
            # axvec[aa].set_xlabel(r'normalised time $t=2 U_\infty \tilde{t}/c$')
            # axvec[aa].set_ylabel(axtitle[aa] + r'$/C_{l_\infty}$')
            # axvec[aa].set_xlim(0, sv[-1])
            # if Cfvec_inf[comp] > 0.:
            # axvec[aa].set_ylim(0, 1.1)
            # else:
            # axvec[aa].set_ylim(-1.1, 0)
            # plt.legend(ncol=1)
            # # plt.show()
            # fig.savefig(self.figfold + self.case_main + '.png')
            # fig.savefig(self.figfold + self.case_main + '.pdf')
            # plt.close()

        assert er_th_2perc < 2e-2 and er_th_1perc < 1e-2, \
            'Error of dynamic step response at time-steps 16 and 36 ' + \
            '(%.2e and %.2e) too large. Verify Linear UVLM.' % (er_th_2perc, er_th_1perc)
Esempio n. 2
0
    def __init__(self,
                 data,
                 custom_settings_linear=None,
                 uvlm_block=False,
                 chosen_ts=None):

        self.data = data
        if custom_settings_linear is None:
            settings_here = data.settings['LinearUvlm']
        else:
            settings_here = custom_settings_linear

        sharpy.utils.settings.to_custom_types(settings_here,
                                              linuvlm.settings_types_dynamic,
                                              linuvlm.settings_default_dynamic)

        if chosen_ts is None:
            self.chosen_ts = self.data.ts
        else:
            self.chosen_ts = chosen_ts

        ## TEMPORARY - NEED TO INCLUDE PROPER INTEGRATION OF SETTINGS
        try:
            self.rigid_body_motions = settings_here['rigid_body_motion']
        except KeyError:
            self.rigid_body_motions = False

        try:
            self.use_euler = settings_here['use_euler']
        except KeyError:
            self.use_euler = False

        if self.rigid_body_motions and settings_here['track_body']:
            self.track_body = True
        else:
            self.track_body = False
        ## -------

        ### extract aeroelastic info
        self.dt = settings_here['dt'].value

        ### reference to timestep_info
        # aero
        aero = data.aero
        self.tsaero = aero.timestep_info[self.chosen_ts]
        # structure
        structure = data.structure
        self.tsstr = structure.timestep_info[self.chosen_ts]

        # --- backward compatibility
        try:
            rho = settings_here['density'].value
        except KeyError:
            warnings.warn(
                "Key 'density' not found in 'LinearUvlm' solver settings. '\
                                      'Trying to read it from 'StaticCoupled'."
            )
            rho = data.settings['StaticCoupled']['aero_solver_settings']['rho']
            if type(rho) == str:
                rho = np.float(rho)
            if hasattr(rho, 'value'):
                rho = rho.value
        self.tsaero.rho = rho
        # --- backward compatibility

        ### gebm
        if self.use_euler:
            self.num_dof_rig = 9
        else:
            self.num_dof_rig = 10

        self.num_dof_flex = np.sum(self.data.structure.vdof >= 0) * 6
        self.num_dof_str = self.num_dof_flex + self.num_dof_rig
        self.reshape_struct_input()

        try:
            beam_settings = settings_here['beam_settings']
        except KeyError:
            beam_settings = dict()
        self.lingebm_str = lingebm.FlexDynamic(self.tsstr, structure,
                                               beam_settings)

        cga = algebra.quat2rotation(self.tsstr.quat)
        ### uvlm
        if uvlm_block:
            self.linuvlm = linuvlm.DynamicBlock(
                self.tsaero,
                dt=settings_here['dt'].value,
                dynamic_settings=settings_here,
                RemovePredictor=settings_here['remove_predictor'].value,
                UseSparse=settings_here['use_sparse'].value,
                integr_order=settings_here['integr_order'].value,
                ScalingDict=settings_here['ScalingDict'],
                for_vel=np.hstack((cga.dot(self.tsstr.for_vel[:3]),
                                   cga.dot(self.tsstr.for_vel[3:]))))
        else:
            self.linuvlm = linuvlm.Dynamic(
                self.tsaero,
                dt=settings_here['dt'].value,
                dynamic_settings=settings_here,
                RemovePredictor=settings_here['remove_predictor'].value,
                UseSparse=settings_here['use_sparse'].value,
                integr_order=settings_here['integr_order'].value,
                ScalingDict=settings_here['ScalingDict'],
                for_vel=np.hstack((cga.dot(self.tsstr.for_vel[:3]),
                                   cga.dot(self.tsstr.for_vel[3:]))))
Esempio n. 3
0
    def initialise(self, data, custom_settings=None):

        if custom_settings:
            self.settings = custom_settings
        else:
            try:
                self.settings = data.settings['LinearAssembler'][
                    'linear_system_settings']  # Load settings, the settings should be stored in data.linear.settings
            except KeyError:
                pass

        settings.to_custom_types(self.settings,
                                 self.settings_types,
                                 self.settings_default,
                                 self.settings_options,
                                 no_ctype=True)
        settings.to_custom_types(self.settings['ScalingDict'],
                                 self.scaling_settings_types,
                                 self.scaling_settings_default,
                                 no_ctype=True)

        data.linear.tsaero0.rho = float(self.settings['density'])

        self.scaled = not all(
            scale == 1.0 for scale in self.settings['ScalingDict'].values())

        for_vel = data.linear.tsstruct0.for_vel
        cga = data.linear.tsstruct0.cga()
        uvlm = linuvlm.Dynamic(data.linear.tsaero0,
                               dt=None,
                               dynamic_settings=self.settings,
                               for_vel=np.hstack((cga.dot(for_vel[:3]),
                                                  cga.dot(for_vel[3:]))))

        self.tsaero0 = data.linear.tsaero0
        self.sys = uvlm

        input_variables_database = {
            'zeta': [0, 3 * self.sys.Kzeta],
            'zeta_dot': [3 * self.sys.Kzeta, 6 * self.sys.Kzeta],
            'u_gust': [6 * self.sys.Kzeta, 9 * self.sys.Kzeta]
        }
        state_variables_database = {
            'gamma': [0, self.sys.K],
            'gamma_w': [self.sys.K, self.sys.K_star],
            'dtgamma_dot':
            [self.sys.K + self.sys.K_star, 2 * self.sys.K + self.sys.K_star],
            'gamma_m1': [
                2 * self.sys.K + self.sys.K_star,
                3 * self.sys.K + self.sys.K_star
            ]
        }

        self.linearisation_vectors['zeta'] = np.concatenate([
            self.tsaero0.zeta[i_surf].reshape(-1, order='C')
            for i_surf in range(self.tsaero0.n_surf)
        ])
        self.linearisation_vectors['zeta_dot'] = np.concatenate([
            self.tsaero0.zeta_dot[i_surf].reshape(-1, order='C')
            for i_surf in range(self.tsaero0.n_surf)
        ])
        self.linearisation_vectors['u_ext'] = np.concatenate([
            self.tsaero0.u_ext[i_surf].reshape(-1, order='C')
            for i_surf in range(self.tsaero0.n_surf)
        ])
        self.linearisation_vectors['forces_aero'] = np.concatenate([
            self.tsaero0.forces[i_surf][:3].reshape(-1, order='C')
            for i_surf in range(self.tsaero0.n_surf)
        ])

        self.input_variables = ss_interface.LinearVector(
            input_variables_database, self.sys_id)
        self.state_variables = ss_interface.LinearVector(
            state_variables_database, self.sys_id)

        if data.aero.n_control_surfaces >= 1:
            import sharpy.linear.assembler.lincontrolsurfacedeflector as lincontrolsurfacedeflector
            self.control_surface = lincontrolsurfacedeflector.LinControlSurfaceDeflector(
            )
            self.control_surface.initialise(data, uvlm)

        if self.settings['rom_method'] != '':
            # Initialise ROM
            self.rom = dict()
            for rom_name in self.settings['rom_method']:
                self.rom[rom_name] = rom_interface.initialise_rom(rom_name)
                self.rom[rom_name].initialise(
                    self.settings['rom_method_settings'][rom_name])

        if 'u_gust' not in self.settings['remove_inputs'] and self.settings[
                'gust_assembler'] == 'leading_edge':
            import sharpy.linear.assembler.lineargustassembler as lineargust
            self.gust_assembler = lineargust.LinearGustGenerator()
            self.gust_assembler.initialise(data.aero)