def test_rotate_symmetry(self):
        symmetry = True
        mesh = get_mesh(symmetry)

        prob = Problem()
        group = prob.model

        val = np.random.random(NY)

        comp = Rotate(val=val, mesh_shape=mesh.shape, symmetry=symmetry)
        group.add_subsystem('comp', comp)

        prob.setup()

        prob['comp.in_mesh'] = mesh

        prob.run_model()

        check = prob.check_partials(compact_print=True, abs_err_tol=1e-5, rel_err_tol=1e-5)
        assert_check_partials(check, atol=1e-6, rtol=1e-6)
예제 #2
0
    def setup(self):
        surface = self.options['surface']

        mesh = surface['mesh']
        ny = mesh.shape[1]
        mesh_shape = mesh.shape
        symmetry = surface['symmetry']

        # This flag determines whether or not changes in z (dihedral) add an
        # additional rotation matrix to modify the twist direction
        self.rotate_x = True

        # 1. Taper

        if 'taper' in surface:
            val = surface['taper']
            promotes = ['taper']
        else:
            val = 1.
            promotes = []

        self.add_subsystem('taper',
                           Taper(val=val, mesh=mesh, symmetry=symmetry),
                           promotes_inputs=promotes)

        # 2. Scale X

        val = np.ones(ny)
        if 'chord_cp' in surface:
            promotes = ['chord']
        else:
            promotes = []

        self.add_subsystem('scale_x',
                           ScaleX(val=val, mesh_shape=mesh_shape),
                           promotes_inputs=promotes)

        # 3. Sweep

        if 'sweep' in surface:
            val = surface['sweep']
            promotes = ['sweep']
        else:
            val = 0.
            promotes = []

        self.add_subsystem('sweep',
                           Sweep(val=val,
                                 mesh_shape=mesh_shape,
                                 symmetry=symmetry),
                           promotes_inputs=promotes)

        # 4. Shear X

        val = np.zeros(ny)
        if 'xshear_cp' in surface:
            promotes = ['xshear']
        else:
            promotes = []

        self.add_subsystem('shear_x',
                           ShearX(val=val, mesh_shape=mesh_shape),
                           promotes_inputs=promotes)

        # 5. Stretch

        if 'span' in surface:
            promotes = ['span']
            val = surface['span']
        else:
            # Compute span. We need .real to make span to avoid OpenMDAO warnings.
            quarter_chord = 0.25 * mesh[-1, :, :] + 0.75 * mesh[0, :, :]
            span = max(quarter_chord[:, 1]).real - min(quarter_chord[:,
                                                                     1]).real
            if symmetry:
                span *= 2.
            val = span
            promotes = []

        self.add_subsystem('stretch',
                           Stretch(val=val,
                                   mesh_shape=mesh_shape,
                                   symmetry=symmetry),
                           promotes_inputs=promotes)

        # 6. Shear Y

        val = np.zeros(ny)
        if 'yshear_cp' in surface:
            promotes = ['yshear']
        else:
            promotes = []

        self.add_subsystem('shear_y',
                           ShearY(val=val, mesh_shape=mesh_shape),
                           promotes_inputs=promotes)

        # 7. Dihedral

        if 'dihedral' in surface:
            val = surface['dihedral']
            promotes = ['dihedral']
        else:
            val = 0.
            promotes = []

        self.add_subsystem('dihedral',
                           Dihedral(val=val,
                                    mesh_shape=mesh_shape,
                                    symmetry=symmetry),
                           promotes_inputs=promotes)

        # 8. Shear Z

        val = np.zeros(ny)
        if 'zshear_cp' in surface:
            promotes = ['zshear']
        else:
            promotes = []

        self.add_subsystem('shear_z',
                           ShearZ(val=val, mesh_shape=mesh_shape),
                           promotes_inputs=promotes)

        #Ajout Rémy :
        # 10. Dihedral Distrib
        val = np.zeros(ny - 1)
        if 'dihedral_distrib_cp' in surface:
            promotes = ['dihedral_distrib']
        else:
            val = np.zeros(ny - 1)
            promotes = []

        self.add_subsystem('dihedral_distrib',
                           Dihedral_distrib(val=val,
                                            mesh_shape=mesh_shape,
                                            symmetry=symmetry),
                           promotes_inputs=promotes)

        # 9. Rotate

        val = np.zeros(ny)
        if 'twist_cp' in surface:
            promotes = ['twist']
        else:
            val = np.zeros(ny)
            promotes = []

        self.add_subsystem('rotate',
                           Rotate(val=val,
                                  mesh_shape=mesh_shape,
                                  symmetry=symmetry),
                           promotes_inputs=promotes,
                           promotes_outputs=['mesh'])

        # #Ajout Rémy :
        # # 10. Dihedral Distrib
        # val = np.zeros(ny)
        # if 'dihedral_distrib_cp' in surface:
        #     promotes = ['dihedral_distrib']
        # else:
        #     val = np.zeros(ny)
        #     promotes = []

        # self.add_subsystem('dihedral_distrib', Dihedral_distrib(val=val, mesh_shape=mesh_shape, symmetry=symmetry),
        #                    promotes_inputs=promotes, promotes_outputs=['mesh'])

        # names = ['taper', 'scale_x', 'sweep', 'shear_x', 'stretch', 'shear_y', 'dihedral',
        #          'shear_z', 'rotate']
        #Ajout rémy :
        names = [
            'taper', 'scale_x', 'sweep', 'shear_x', 'stretch', 'shear_y',
            'dihedral', 'shear_z', 'dihedral_distrib', 'rotate'
        ]

        for j in np.arange(len(names) - 1):
            self.connect(names[j] + '.mesh', names[j + 1] + '.in_mesh')
예제 #3
0
    def setup(self):
        nx = int(self.options["num_x"])
        ny = int(self.options["num_y"])
        n_twist = int(self.options["num_twist"])

        # =================================================================
        #                            Set up mesh
        # =================================================================
        self.add_subsystem(
            "mesh",
            PlanformMesh(num_x=nx, num_y=ny),
            promotes_inputs=[
                ("S", "ac|geom|wing|S_ref"),
                ("AR", "ac|geom|wing|AR"),
                ("taper", "ac|geom|wing|taper"),
                ("sweep", "ac|geom|wing|c4sweep"),
            ],
        )

        # Add bspline component for twist
        x_interp = np.linspace(0.0, 1.0, ny)
        comp = self.add_subsystem(
            "twist_bsp",
            om.SplineComp(method="bsplines",
                          x_interp_val=x_interp,
                          num_cp=n_twist,
                          interp_options={"order": min(n_twist, 4)}),
            promotes_inputs=[("twist_cp", "ac|geom|wing|twist")],
        )
        comp.add_spline(y_cp_name="twist_cp",
                        y_interp_name="twist",
                        y_units="deg")

        # Apply twist spline to mesh
        self.add_subsystem(
            "twist_mesh",
            Rotate(val=np.zeros(ny), mesh_shape=(nx, ny, 3), symmetry=True))
        self.connect("twist_bsp.twist", "twist_mesh.twist")
        self.connect("mesh.mesh", "twist_mesh.in_mesh")

        # =================================================================
        #              Compute atmospheric and fluid properties
        # =================================================================
        self.add_subsystem(
            "temp",
            TemperatureComp(num_nodes=1),
            promotes_inputs=["fltcond|h", "fltcond|TempIncrement"])
        self.add_subsystem("pressure",
                           PressureComp(num_nodes=1),
                           promotes_inputs=["fltcond|h"])
        self.add_subsystem("density", DensityComp(num_nodes=1))
        self.connect("temp.fltcond|T", "density.fltcond|T")
        self.connect("pressure.fltcond|p", "density.fltcond|p")
        self.add_subsystem("sound_speed", SpeedOfSoundComp(num_nodes=1))
        self.connect("temp.fltcond|T", "sound_speed.fltcond|T")
        self.add_subsystem(
            "airspeed",
            om.ExecComp("Utrue = Mach * a",
                        Utrue={
                            "units": "m/s",
                            "val": 200.0
                        },
                        a={
                            "units": "m/s",
                            "val": 300.0
                        }),
            promotes_inputs=[("Mach", "fltcond|M")],
        )
        self.connect("sound_speed.fltcond|a", "airspeed.a")

        # Compute dimensionalized Reynolds number (use linear interpolation from standard atmosphere up
        # to 35k ft to estimate dynamic viscosity)
        self.add_subsystem(
            "Re_calc",
            om.ExecComp(
                "re = rho * u / (-3.329134*10**(-10) * h + 1.792398*10**(-5))",
                re={
                    "units": "1/m",
                    "val": 1e6
                },
                rho={
                    "units": "kg/m**3",
                    "val": 1.0
                },
                u={
                    "units": "m/s",
                    "val": 100.0
                },
                h={
                    "units": "m",
                    "val": 1.0
                },
            ),
            promotes_inputs=[("h", "fltcond|h")],
        )
        self.connect("density.fltcond|rho", "Re_calc.rho")
        self.connect("airspeed.Utrue", "Re_calc.u")

        # =================================================================
        #                       Call OpenAeroStruct
        # =================================================================
        surf_dict = {
            "name": "wing",
            "mesh": np.zeros((nx, ny, 3)),  # this must be defined
            # because the VLMGeometry component uses the shape of the mesh in this
            # dictionary to determine the size of the mesh; the values don't matter
            "symmetry": True,  # if true, model one half of wing
            # reflected across the plane y = 0
            "S_ref_type": "projected",  # how we compute the wing area,
            # can be 'wetted' or 'projected'
            # Aerodynamic performance of the lifting surface at
            # an angle of attack of 0 (alpha=0).
            # These CL0 and CD0 values are added to the CL and CD
            # obtained from aerodynamic analysis of the surface to get
            # the total CL and CD.
            # These CL0 and CD0 values do not vary wrt alpha.
            "CL0": 0.0,  # CL of the surface at alpha=0
            "CD0": 0.0,  # CD of the surface at alpha=0
            # Airfoil properties for viscous drag calculation
            "k_lam": 0.05,  # percentage of chord with laminar
            # flow, used for viscous drag
            "t_over_c":
            np.array([0.12]),  # thickness over chord ratio (NACA SC2-0612)
            "c_max_t": 0.37,  # chordwise location of maximum (NACA SC2-0612)
            # thickness
            "with_viscous": True,  # if true, compute viscous drag
            "with_wave": True,  # if true, compute wave drag
        }

        # Overwrite any options in the surface dict with those provided in the options
        if self.options["surf_options"] is not None:
            for key in self.options["surf_options"]:
                surf_dict[key] = self.options["surf_options"][key]

        self.add_subsystem(
            "aero_point",
            AeroPoint(surfaces=[surf_dict]),
            promotes_inputs=[("Mach_number", "fltcond|M"),
                             ("alpha", "fltcond|alpha")],
            promotes_outputs=[
                (f"{surf_dict['name']}_perf.CD", "fltcond|CD"),
                (f"{surf_dict['name']}_perf.CL", "fltcond|CL"),
            ],
        )
        self.connect(
            "twist_mesh.mesh",
            [
                f"aero_point.{surf_dict['name']}.def_mesh",
                f"aero_point.aero_states.{surf_dict['name']}_def_mesh"
            ],
        )
        self.connect("airspeed.Utrue", "aero_point.v")
        self.connect("density.fltcond|rho", "aero_point.rho")
        self.connect("Re_calc.re", "aero_point.re")

        # Set input defaults for inputs that go to multiple locations
        self.set_input_defaults("fltcond|M", 0.1)
        self.set_input_defaults("fltcond|alpha", 0.0)

        # Set the thickness to chord ratio for wave and viscous drag calculation.
        # It must have a thickness to chord ratio for each panel, so there must be
        # ny-1 elements. Allow either one value (and duplicate it ny-1 times) or
        # an array of length ny-1, but nothing else.
        # NOTE: for aerostructural cases, this should be a design variable with control points over a spline
        if isinstance(surf_dict["t_over_c"],
                      (int, float)) or surf_dict["t_over_c"].size == 1:
            self.set_input_defaults(
                f"aero_point.{surf_dict['name']}_perf.t_over_c",
                val=surf_dict["t_over_c"] * np.ones(ny - 1))
        elif surf_dict["t_over_c"].size == ny - 1:
            self.set_input_defaults(
                f"aero_point.{surf_dict['name']}_perf.t_over_c",
                val=surf_dict["t_over_c"])
        else:
            raise ValueError(
                f"t_over_c in the surface dict must be either a number or an ndarray "
                f"with either one or ny-1 elements, not {surf_dict['t_over_c']}"
            )