Exemple #1
0
    def test_22(self, train=False, refDeriv=False):
        """
        Test 22
        """
        refFile = os.path.join(self.base_path, "ref/test_DVGeometry_22.ref")
        with BaseRegTest(refFile, train=train) as handler:
            handler.root_print("Test FFD writing function")

            # Write duplicate of outerbox FFD
            axes = ["i", "k", "j"]
            slices = np.array(
                [
                    # Slice 1
                    [[[-1, -1, -1], [-1, 1, -1]], [[-1, -1, 1], [-1, 1, 1]]],
                    # Slice 2
                    [[[1, -1, -1], [1, 1, -1]], [[1, -1, 1], [1, 1, 1]]],
                    # Slice 3
                    [[[2, -1, -1], [2, 1, -1]], [[2, -1, 1], [2, 1, 1]]],
                ]
            )

            N0 = [2, 2]
            N1 = [2, 2]
            N2 = [2, 2]

            copyName = os.path.join(self.base_path, "../../input_files/test1.xyz")
            geo_utils.write_wing_FFD_file(copyName, slices, N0, N1, N2, axes=axes)

            # Load original and duplicate
            origFFD = DVGeometry(os.path.join(self.base_path, "../../input_files/outerBoxFFD.xyz"))
            copyFFD = DVGeometry(copyName)
            norm_diff = np.linalg.norm(origFFD.FFD.coef - copyFFD.FFD.coef)
            handler.par_add_norm("norm", norm_diff, rtol=1e-7, atol=1e-7)
            os.remove(copyName)
Exemple #2
0
def setDVGeo(ffdFile, cmplx=False):

    # Setup geometry/mesh
    DVGeo = DVGeometry(ffdFile, complex=cmplx)

    nTwist = 6
    DVGeo.addRefAxis(
        "wing",
        Curve(
            x=numpy.linspace(5.0 / 4.0, 1.5 / 4.0 + 7.5, nTwist),
            y=numpy.zeros(nTwist),
            z=numpy.linspace(0, 14, nTwist),
            k=2,
        ),
    )

    def twist(val, geo):
        for i in range(nTwist):
            geo.rot_z["wing"].coef[i] = val[i]

    def span(val, geo):
        C = geo.extractCoef("wing")
        s = geo.extractS("wing")
        for i in range(len(C)):
            C[i, 2] += s[i] * val[0]
        geo.restoreCoef(C, "wing")

    DVGeo.addGlobalDV("twist", [0] * nTwist, twist, lower=-10, upper=10, scale=1.0)
    DVGeo.addGlobalDV("span", [0], span, lower=-10, upper=10, scale=1.0)
    DVGeo.addLocalDV("shape", lower=-0.5, upper=0.5, axis="y", scale=10.0)

    return DVGeo
Exemple #3
0
def setup_cb(comm):

    # Create the solver
    CFDSolver = ADFLOW(options=options, comm=comm, debug=False)

    # Setup geometry/mesh
    DVGeo = DVGeometry(ffdFile)
    nTwist = 6
    DVGeo.addRefAxis(
        'wing',
        Curve(x=numpy.linspace(5.0 / 4.0, 1.5 / 4.0 + 7.5, nTwist),
              y=numpy.zeros(nTwist),
              z=numpy.linspace(0, 14, nTwist),
              k=2))

    def twist(val, geo):
        for i in range(nTwist):
            geo.rot_z['wing'].coef[i] = val[i]

    DVGeo.addGeoDVGlobal('twist', [0] * nTwist,
                         twist,
                         lower=-10,
                         upper=10,
                         scale=1.0)
    DVGeo.addGeoDVLocal('shape', lower=-0.5, upper=0.5, axis='y', scale=10.0)
    mesh = USMesh(options=meshOptions, comm=comm)
    CFDSolver.setMesh(mesh)
    CFDSolver.setDVGeo(DVGeo)

    return CFDSolver, mesh, DVGeo, None
Exemple #4
0
    def generate_dvgeo_dvcon_c172(self):
        meshfile = os.path.join(self.base_path, '../inputFiles/c172.stl')
        ffdfile = os.path.join(self.base_path, '../inputFiles/c172.xyz')
        testmesh = mesh.Mesh.from_file(meshfile)
        # test mesh dim 0 is triangle index
        # dim 1 is each vertex of the triangle
        # dim 2 is x, y, z dimension

        # create a DVGeo object with a few local thickness variables
        DVGeo = DVGeometry(ffdfile)
        nRefAxPts = DVGeo.addRefAxis("wing", xFraction=0.25, alignIndex="k")
        self.nTwist = nRefAxPts - 1
        def twist(val, geo):
            for i in range(1, nRefAxPts):
                geo.rot_z["wing"].coef[i] = val[i - 1]
        DVGeo.addGeoDVGlobal(dvName="twist", value=[0] * self.nTwist, func=twist, lower=-10, upper=10, scale=1)
        DVGeo.addGeoDVLocal("local", lower=-0.5, upper=0.5, axis="y", scale=1)

        # create a DVConstraints object for the wing
        DVCon =DVConstraints()
        DVCon.setDVGeo(DVGeo)
        p0 = testmesh.vectors[:,0,:] / 1000
        v1 = testmesh.vectors[:,1,:] / 1000 - p0
        v2 = testmesh.vectors[:,2,:] / 1000 - p0
        DVCon.setSurface([p0, v1, v2])

        return DVGeo, DVCon
Exemple #5
0
    def test_spanwise_dvs(self, train=False, refDeriv=False):
        refFile = os.path.join(self.base_path,
                               "ref/test_Cylinder_spanwise_dvs.ref")

        with BaseRegTest(refFile, train=train) as handler:
            handler.root_print("Test 1: Basic FFD, global DVs")
            radius = 1.0
            height = 10.0

            DVCon = DVConstraints()
            surf = self.make_cylinder_mesh(radius, height)
            DVCon.setSurface(surf)
            # DVCon.writeSurfaceTecplot('cylinder_surface.dat')

            ffd_name = os.path.join(self.base_path,
                                    "../inputFiles/cylinder_ffd.xyz")
            self.make_ffd(ffd_name, radius, height)
            DVGeo = DVGeometry(ffd_name)

            DVGeo.addSpanwiseLocalDV("shape",
                                     "i",
                                     lower=-0.5,
                                     upper=0.5,
                                     axis="y",
                                     scale=1.0)

            size = DVGeo._getNDVSpanwiseLocal()
            DVCon.setDVGeo(DVGeo)

            leList = [[0, 0, 0], [-radius / 2, 0, height]]
            xAxis = [-1, 0, 0]
            yAxis = [0, 1, 0]
            DVCon.addLERadiusConstraints(leList,
                                         nSpan=5,
                                         axis=yAxis,
                                         chordDir=xAxis,
                                         scaled=False)
            # DVCon.writeTecplot('cylinder_constraints.dat')

            funcs = {}
            DVCon.evalFunctions(funcs)
            print(funcs)
            handler.root_add_dict("funcs1", funcs, rtol=1e-6, atol=1e-6)

            np.random.seed(0)
            DVGeo.setDesignVars({"shape": (np.random.rand(size) - 0.5)})

            funcs = {}
            DVCon.evalFunctions(funcs)
            handler.root_add_dict("funcs2", funcs, rtol=1e-6, atol=1e-6)
            print(funcs)

            funcsSens = {}
            DVCon.evalFunctionsSens(funcsSens)
            print(funcsSens)
            handler.root_add_dict("funcsSens", funcsSens, rtol=1e-6, atol=1e-6)
            print(funcsSens)
Exemple #6
0
    def test_23_xyzFraction(self, train=False):
        """
        Test 23
        This test verifies the correct implementation of the generalized `xFraction`, `yFraction` (and indirectly `zFraction`)
        Given an arbitrary input for the in-plane location of the reference axis nodes, the test sets up the axis object and compares the nodes location with a reference file.
        As the geometry of the FFD box is simple, the values can be also hand calculated:
        xFraction = 0.3, FFD x interval [-1,1] ---> 0.6 displacement from x min (% displ calculated from LE=xmin) --> x = -0.4
        yFraction = 0.6, FFD y interval [-0.5,0.5] ---> 0.6 displacement from y max (% displ calculated from top of the box=ymax) --> x = -0.1
        """
        refFile = os.path.join(self.base_path, "ref/test_DVGeometry_23.ref")
        with BaseRegTest(refFile, train=train) as handler:
            handler.root_print("Test generalized axis node location section in plane")
            DVGeo = DVGeometry(os.path.join(self.base_path, "../../input_files/2x1x8_rectangle.xyz"))
            xfraction = 0.3
            yfraction = 0.6
            rotType = 0
            DVGeo.addRefAxis("RefAx", xFraction=xfraction, yFraction=yfraction, alignIndex="k", rotType=rotType)
            nodes_loc = DVGeo.axis["RefAx"]["curve"].X

            handler.root_add_val("RefAxis_nodes_coord", nodes_loc, rtol=1e-12, atol=1e-12)
Exemple #7
0
    def test_1(self, train=False, refDeriv=False):
        refFile = os.path.join(self.base_path, 'ref/test_Cylinder_01.ref')

        with BaseRegTest(refFile, train=train) as handler:
            handler.root_print("Test 1: Basic FFD, global DVs")
            radius = 1.0
            height = 10.0

            DVCon = DVConstraints()
            surf = self.make_cylinder_mesh(radius, height)
            DVCon.setSurface(surf)
            # DVCon.writeSurfaceTecplot('cylinder_surface.dat')

            ffd_name = os.path.join(self.base_path,
                                    '../inputFiles/cylinder_ffd.xyz')
            self.make_ffd(ffd_name, radius, height)
            DVGeo = DVGeometry(ffd_name)
            nAxPts = DVGeo.addRefAxis('thru',
                                      xFraction=0.5,
                                      alignIndex='i',
                                      raySize=1.0)

            def scale_circle(val, geo):
                for i in range(nAxPts):
                    geo.scale['thru'].coef[i] = val[0]

            DVGeo.addGeoDVGlobal('scale_circle', func=scale_circle, value=[1])
            DVCon.setDVGeo(DVGeo)

            leList = [[0, 0, 0], [-radius / 2, 0, height]]
            xAxis = [-1, 0, 0]
            yAxis = [0, 1, 0]
            DVCon.addLERadiusConstraints(leList,
                                         nSpan=5,
                                         axis=yAxis,
                                         chordDir=xAxis,
                                         scaled=False)
            # DVCon.writeTecplot('cylinder_constraints.dat')

            funcs = {}
            DVCon.evalFunctions(funcs)
            print(funcs)
            handler.root_add_dict('funcs1', funcs, rtol=1e-6, atol=1e-6)

            DVGeo.setDesignVars({'scale_circle': 0.5})

            funcs = {}
            DVCon.evalFunctions(funcs)
            handler.root_add_dict('funcs2', funcs, rtol=1e-6, atol=1e-6)
            print(funcs)

            funcsSens = {}
            DVCon.evalFunctionsSens(funcsSens)
            print(funcsSens)
            handler.root_add_dict('funcsSens', funcsSens, rtol=1e-6, atol=1e-6)
            print(funcsSens)
Exemple #8
0
def deform_DVGeo(geo):
    # =========================================================================
    # Setup DVGeometry object
    # =========================================================================
    # rst DVGeometry
    DVGeo = DVGeometry(input_files + "deform_geometry_ffd.xyz")

    # Create reference axis
    nRefAxPts = DVGeo.addRefAxis("wing", xFraction=0.25, alignIndex="k")

    # Set the Twist Variable
    def twist(val, geo):
        for i in range(nRefAxPts):
            geo.rot_z["wing"].coef[i] = val[i]

    # Add the Twist Design Variable to DVGeo
    DVGeo.addGlobalDV(dvName="twist",
                      value=[0] * nRefAxPts,
                      func=twist,
                      lower=-10,
                      upper=10,
                      scale=1.0)

    # Get Design Variables
    dvDict = DVGeo.getValues()

    # Set First Twist Section to 5deg
    dvDict["twist"][0] = 5

    # Set Design Variables
    DVGeo.setDesignVars(dvDict)
    # rst DVGeometry (end)

    # =========================================================================
    # Update pyGeo Object and output result
    # =========================================================================
    # rst UpdatePyGeo
    DVGeo.updatePyGeo(geo, "tecplot", "wingNew", nRefU=10, nRefV=10)
Exemple #9
0
    def test_13b(self, train=False, refDeriv=False):
        refFile = os.path.join(self.base_path,'ref/test_DVConstraints_13b.ref')
        with BaseRegTest(refFile, train=train) as handler:
            handler.root_print("Test 13: PlanarityConstraint, rectangular box")
            ffdfile = os.path.join(self.base_path, '../inputFiles/2x1x8_rectangle.xyz')
            DVGeo = DVGeometry(ffdfile)
            DVGeo.addGeoDVLocal("local", lower=-0.5, upper=0.5, axis="y", scale=1)

            # create a DVConstraints object with a simple plane consisting of 2 triangles
            DVCon =DVConstraints()
            DVCon.setDVGeo(DVGeo)

            p0 = np.zeros(shape=(2,3))
            p1 = np.zeros(shape=(2,3))
            p2 = np.zeros(shape=(2,3))

            vertex1 = np.array([0.5, -0.25, 0.0])
            vertex2 = np.array([0.5, -0.25, 4.0])
            vertex3 = np.array([-0.5, -0.25, 0.0])
            vertex4 = np.array([-0.5, -0.25, 4.0])

            p0[:,:] = vertex1
            p2[:,:] = vertex4
            p1[0,:] = vertex2
            p1[1,:] = vertex3

            v1 = p1 - p0
            v2 = p2 - p0
            DVCon.setSurface([p0, v1, v2])

            DVCon.addPlanarityConstraint(origin=[0.,-0.25,2.0], planeAxis=[0.,1.,0.])

            funcs, funcsSens = self.generic_test_base(DVGeo, DVCon, handler, checkDerivs=False)

            # this should be coplanar and the planarity constraint shoudl be zero
            handler.assert_allclose(funcs['DVCon1_planarity_constraints_0'], np.zeros(1), 
                                    name='planarity', rtol=1e-7, atol=1e-7)
Exemple #10
0
def setupDVGeo(base_path, rotType=None):
    # create the Parent FFD
    FFDFile = os.path.join(base_path, "../inputFiles/outerBoxFFD.xyz")
    DVGeo = DVGeometry(FFDFile)

    # create a reference axis for the parent
    axisPoints = [[-1.0, 0.0, 0.0], [1.5, 0.0, 0.0]]
    c1 = Curve(X=axisPoints, k=2)
    if rotType is not None:
        DVGeo.addRefAxis("mainAxis", curve=c1, axis="y", rotType=rotType)

    else:
        DVGeo.addRefAxis("mainAxis", curve=c1, axis="y")

    # create the child FFD
    FFDFile = os.path.join(base_path, "../inputFiles/simpleInnerFFD.xyz")
    DVGeoChild = DVGeometry(FFDFile, child=True)

    # create a reference axis for the child
    axisPoints = [[-0.5, 0.0, 0.0], [0.5, 0.0, 0.0]]
    c1 = Curve(X=axisPoints, k=2)
    DVGeoChild.addRefAxis("nestedAxis", curve=c1, axis="y")

    return DVGeo, DVGeoChild
Exemple #11
0
    def setup(self):

        # create the DVGeo object that does the computations
        if self.options["ffd_file"] is not None:
            # we are doing an FFD-based DVGeo
            ffd_file = self.options["ffd_file"]
            self.DVGeo = DVGeometry(ffd_file)
        if self.options["vsp_file"] is not None:
            # we are doing a VSP based DVGeo
            vsp_file = self.options["vsp_file"]
            vsp_options = self.options["vsp_options"]
            self.DVGeo = DVGeometryVSP(vsp_file, comm=self.comm, **vsp_options)

        self.DVCon = DVConstraints()
        self.DVCon.setDVGeo(self.DVGeo)
        self.omPtSetList = []
Exemple #12
0
    def test_spanwise_dvs(self, train=False, refDeriv=False):
        """
        Test spanwise_dvs
        """
        # refFile = os.path.join(self.base_path,'ref/test_DVGeometry_spanwise_dvs.ref')
        # with BaseRegTest(refFile, train=train) as handler:
        #     handler.root_print("Test spanwise local variables writing function")

        meshfile = os.path.join(self.base_path, "../../input_files/c172.stl")
        ffdfile = os.path.join(self.base_path, "../../input_files/c172.xyz")
        testmesh = mesh.Mesh.from_file(meshfile)
        # test mesh dim 0 is triangle index
        # dim 1 is each vertex of the triangle
        # dim 2 is x, y, z dimension

        # create a DVGeo object with a few local thickness variables
        DVGeo = DVGeometry(ffdfile)
        DVGeo.addSpanwiseLocalDV("shape", "i", lower=-0.5, upper=0.5, axis="y", scale=1.0)

        # create a DVConstraints object for the wing
        DVCon = DVConstraints()
        DVCon.setDVGeo(DVGeo)
        p0 = testmesh.vectors[:, 0, :] / 1000
        v1 = testmesh.vectors[:, 1, :] / 1000 - p0
        v2 = testmesh.vectors[:, 2, :] / 1000 - p0
        DVCon.setSurface([p0, v1, v2])

        leList = [[0.7, 0.0, 0.1], [0.7, 0.0, 2.4]]
        teList = [[0.9, 0.0, 0.1], [0.9, 0.0, 2.4]]

        nSpan = 10
        nChord = 10
        name = "thickness_con"
        DVCon.addThicknessConstraints2D(leList, teList, nSpan, nChord, name=name)

        size = DVGeo._getNDVSpanwiseLocal()

        np.random.seed(0)
        DVGeo.setDesignVars({"shape": (np.random.rand(size) - 0.5)})

        funcs = {}
        DVCon.evalFunctions(funcs)
        # print(funcs)

        for i in range(nChord):
            for j in range(nSpan - 1):
                np.testing.assert_allclose(funcs[name][i * nChord + j + 1], funcs[name][i * nChord + j], rtol=2e-15)
Exemple #13
0
def setupDVGeo(base_path):
    #create the Parent FFD
    FFDFile =  os.path.join(base_path,'../inputFiles/outerBoxFFD.xyz')
    DVGeo = DVGeometry(FFDFile)

    # create a reference axis for the parent
    axisPoints = [[ -1.0,   0.  ,   0.],[ 1.5,   0.,   0.]]
    c1 = Curve(X=axisPoints,k=2)
    DVGeo.addRefAxis('mainAxis',curve=c1, axis='y')

    # create the child FFD
    FFDFile = os.path.join(base_path,'../inputFiles/simpleInnerFFD.xyz')
    DVGeoChild = DVGeometry(FFDFile,child=True)

    # create a reference axis for the child
    axisPoints = [[ -0.5,   0.  ,   0.],[ 0.5,   0.,   0.]]
    c1 = Curve(X=axisPoints,k=2)
    DVGeoChild.addRefAxis('nestedAxis',curve=c1, axis='y')

    return DVGeo,DVGeoChild
Exemple #14
0
def setupDVGeoD8(base_path, isComplex):
    # create the Parent FFD
    FFDFile = os.path.join(base_path, "../../input_files/bodyFFD.xyz")
    DVGeo = DVGeometry(FFDFile, isComplex=isComplex)

    # create a reference axis for the parent
    axisPoints = [[0.0, 0.0, 0.0], [26.0, 0.0, 0.0], [30.5, 0.0, 0.9], [32.5, 0.0, 1.01], [34.0, 0.0, 0.95]]
    c1 = Curve(X=axisPoints, k=2)
    DVGeo.addRefAxis("mainAxis", curve=c1, axis="y")

    # create the child FFD
    FFDFile = os.path.join(base_path, "../../input_files/nozzleFFD.xyz")
    DVGeoChild = DVGeometry(FFDFile, child=True, isComplex=isComplex)

    # create a reference axis for the child
    axisPoints = [[32.4, 1.0, 1.0], [34, 1.0, 0.9]]
    c1 = Curve(X=axisPoints, k=2)
    DVGeoChild.addRefAxis("nestedAxis", curve=c1, axis="y")

    return DVGeo, DVGeoChild
Exemple #15
0
    def test_ffdSplineOrder(self, train=False, refDeriv=False):
        """
        Test custom FFD spline order
        """
        refFile = os.path.join(self.base_path, "ref/test_ffd_spline_order.ref")
        with BaseRegTest(refFile, train=train) as handler:
            handler.root_print("Test custom FFD spline order")
            ffdfile = os.path.join(self.base_path, "../../input_files/deform_geometry_ffd.xyz")
            DVGeo = DVGeometry(ffdfile, kmax=6)

            # create local DVs
            DVGeo.addLocalDV("xdir", lower=-1.0, upper=1.0, axis="x", scale=1.0)
            DVGeo.addLocalDV("ydir", lower=-1.0, upper=1.0, axis="y", scale=1.0)
            DVGeo.addLocalDV("zdir", lower=-1.0, upper=1.0, axis="z", scale=1.0)

            commonUtils.testSensitivities(DVGeo, refDeriv, handler, pointset=3)
Exemple #16
0
def create_fresh_dvgeo():
    # The Plot3D file ffdbox.xyz contains the coordinates of the free-form deformation (FFD) volume
    # The "i" direction of the cube consists of 10 points along the x (streamwise) axis
    # The "j" direction of the cube is 2 points up and down (y axis direction)
    # The "k" direction of the cube is 8 along the span (z axis direction)
    FFDfile = "ffdbox.xyz"

    # initialize the DVGeometry object with the FFD file
    DVGeo = DVGeometry(FFDfile)

    stlmesh = mesh.Mesh.from_file("baseline_wing.stl")
    # create a pointset. pointsets are of shape npts by 3 (the second dim is xyz coordinate)
    # already have the wing mesh as a triangulated surface (stl file)
    # each vertex set is its own pointset, so we actually add three pointsets
    DVGeo.addPointSet(stlmesh.v0, "mesh_v0")
    DVGeo.addPointSet(stlmesh.v1, "mesh_v1")
    DVGeo.addPointSet(stlmesh.v2, "mesh_v2")
    return DVGeo, stlmesh
    def test(self):

        from openaerostruct.geometry.utils import generate_mesh, write_FFD_file
        from openaerostruct.geometry.geometry_group import Geometry
        from openaerostruct.transfer.displacement_transfer import DisplacementTransfer

        from openaerostruct.aerodynamics.aero_groups import AeroPoint

        from openmdao.api import IndepVarComp, Problem, Group, NewtonSolver, ScipyIterativeSolver, LinearBlockGS, NonlinearBlockGS, DirectSolver, LinearBlockGS, PetscKSP, ScipyOptimizeDriver# TODO, SqliteRecorder, CaseReader, profile
        from openmdao.devtools import iprofile
        from openmdao.api import view_model
        from six import iteritems
        from pygeo import DVGeometry

        # Create a dictionary to store options about the surface
        mesh_dict = {'num_y' : 7,
                     'num_x' : 3,
                     'wing_type' : 'CRM',
                     'symmetry' : True,
                     'num_twist_cp' : 5,
                     'span_cos_spacing' : 0.}

        mesh, _ = generate_mesh(mesh_dict)

        surf_dict = {
                    # Wing definition
                    'name' : 'wing',        # name of the surface
                    'symmetry' : True,     # if true, model one half of wing
                                            # reflected across the plane y = 0
                    'S_ref_type' : 'wetted', # how we compute the wing area,
                                             # can be 'wetted' or 'projected'
                    'fem_model_type' : 'tube',

                    'DVGeo' : True,
                    'mesh' : mesh,
                    'mx' : 2,
                    'my' : 3,

                    # 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.015,            # 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_cp' : np.array([0.15]),      # thickness over chord ratio (NACA0015)
                    'c_max_t' : .303,       # chordwise location of maximum (NACA0015)
                                            # thickness
                    'with_viscous' : True,  # if true, compute viscous drag
                    'with_wave' : False,     # if true, compute wave drag
                    }

        surfaces = [surf_dict]

        # Create the problem and the model group
        prob = Problem()

        indep_var_comp = IndepVarComp()
        indep_var_comp.add_output('v', val=248.136, units='m/s')
        indep_var_comp.add_output('alpha', val=6.64, units='deg')
        indep_var_comp.add_output('Mach_number', val=0.84)
        indep_var_comp.add_output('re', val=1.e6, units='1/m')
        indep_var_comp.add_output('rho', val=0.38, units='kg/m**3')
        indep_var_comp.add_output('cg', val=np.zeros((3)), units='m')

        prob.model.add_subsystem('prob_vars',
            indep_var_comp,
            promotes=['*'])

        # Loop over each surface in the surfaces list
        for surface in surfaces:

            filename = write_FFD_file(surface, surface['mx'], surface['my'])
            DVGeo = DVGeometry(filename)
            geom_group = Geometry(surface=surface, DVGeo=DVGeo)

            # Add tmp_group to the problem as the name of the surface.
            # Note that is a group and performance group for each
            # individual surface.
            prob.model.add_subsystem(surface['name'], geom_group)

        # Loop through and add a certain number of aero points
        for i in range(1):

            # Create the aero point group and add it to the model
            aero_group = AeroPoint(surfaces=surfaces)
            point_name = 'aero_point_{}'.format(i)
            prob.model.add_subsystem(point_name, aero_group)

            # Connect flow properties to the analysis point
            prob.model.connect('v', point_name + '.v')
            prob.model.connect('alpha', point_name + '.alpha')
            prob.model.connect('Mach_number', point_name + '.Mach_number')
            prob.model.connect('re', point_name + '.re')
            prob.model.connect('rho', point_name + '.rho')
            prob.model.connect('cg', point_name + '.cg')

            # Connect the parameters within the model for each aero point
            for surface in surfaces:

                name = surface['name']

                # Connect the mesh from the geometry component to the analysis point
                prob.model.connect(name + '.mesh', point_name + '.' + name + '.def_mesh')

                # Perform the connections with the modified names within the
                # 'aero_states' group.
                prob.model.connect(name + '.mesh', point_name + '.aero_states.' + name + '_def_mesh')

                prob.model.connect(name + '.t_over_c', point_name + '.' + name + '_perf.' + 't_over_c')

        from openmdao.api import pyOptSparseDriver
        prob.driver = pyOptSparseDriver()
        prob.driver.options['optimizer'] = "SNOPT"
        prob.driver.opt_settings = {'Major optimality tolerance': 1.0e-6,
                                    'Major feasibility tolerance': 1.0e-6}

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('alpha', lower=-15, upper=15)
        prob.model.add_design_var('wing.shape', lower=-3, upper=2)

        # prob.model.add_constraint('wing.shape', equals=0., indices=range(surf_dict['my'] * 2), linear=True)
        prob.model.add_constraint(point_name + '.wing_perf.CL', equals=0.5)
        prob.model.add_objective(point_name + '.wing_perf.CD', scaler=1e4)

        # Set up the problem
        prob.setup()

        # view_model(prob, outfile='aero.html', show_browser=False)

        # prob.run_model()
        prob.run_driver()

        assert_rel_error(self, prob['aero_point_0.wing_perf.CD'][0], 0.03398038, 1e-6)
        assert_rel_error(self, prob['aero_point_0.wing_perf.CL'][0], 0.5, 1e-6)
        assert_rel_error(self, prob['aero_point_0.CM'][1], -1.7736315914915437, 1e-5)
Exemple #18
0
     'nkswitchtol':1e-2,
     'adjointl2convergence': 1e-15,
     'nkls':'non monotone',
     'blocksplitting': True
 }
)
h = 1e-40

# Setup aeroproblem, cfdsolver
ap = AeroProblem(name='mdo_tutorial', alpha=1.8, mach=0.80, R=287.87,
                 altitude=10000.0, areaRef=45.5, chordRef=3.25,
                 evalFuncs=['cl','cmz','drag'])

CFDSolver = ADFLOW(options=aeroOptions)
if 'complex' in sys.argv:
    DVGeo = DVGeometry('../inputFiles/mdo_tutorial_ffd.fmt', complex=True)
else:
    DVGeo = DVGeometry('../inputFiles/mdo_tutorial_ffd.fmt', complex=False)

nTwist = 2
DVGeo.addRefAxis('wing', pyspline.Curve(x=numpy.linspace(5.0/4.0, 1.5/4.0+7.5, nTwist),
                                        y=numpy.zeros(nTwist),
                                        z=numpy.linspace(0,14, nTwist), k=2))
def twist(val, geo):
    for i in range(nTwist):
        geo.rot_z['wing'].coef[i] = val[i]

def span(val, geo):
    # Span
    C = geo.extractCoef('wing')
    s = geo.extractS('wing')
Exemple #19
0
        areaRef=1.0,
        chordRef=1.0,
        evalFuncs=["cl", "cd"],
    )
    # Add angle of attack variable
    ap.addDV("alpha", value=alpha[i], lower=0, upper=10.0, scale=1.0)
    aeroProblems.append(ap)
# rst aeroproblem (end)
# ======================================================================
#         Geometric Design Variable Set-up
# ======================================================================
# rst dvgeo (beg)
# Create DVGeometry object
FFDFile = "ffd.xyz"

DVGeo = DVGeometry(FFDFile)  # DVGeo = DVGeometry_FFD(FFDFile)
DVGeo.addGeoDVLocal("shape", lower=-0.05, upper=0.05, axis="y", scale=1.0)

span = 1.0
pos = np.array([0.5]) * span
CFDSolver.addSlices("z", pos, sliceType="absolute")

# Add DVGeo object to CFD solver
CFDSolver.setDVGeo(DVGeo)
# rst dvgeo (end)
# ======================================================================
#         DVConstraint Setup
# ======================================================================
# rst dvcon (beg)
DVCon = DVConstraints()  # DVCon = DVConstraints_FFD_data()
DVCon.setDVGeo(DVGeo)
Exemple #20
0
        C = geo.extractCoef("wing")

        C[-1, 0] += val[0]
        C[-1, 1] += val[1]
        C[-1, 2] += val[2]

        # Also need to get "dihedral" angle for this section
        theta = numpy.arctan(val[1] / (C[-1, 2] - C[-2, 2]))
        geo.rot_x["wing"].coef[-1] = -theta * 180 / numpy.pi
        geo.restoreCoef(C, "wing")

        # Set the chord as well
        geo.scale["wing"].coef[-1] = val[3]

    coords = hyp.getSurfaceCoordinates()
    DVGeo = DVGeometry(ffdFile)
    coef = DVGeo.FFD.vols[0].coef.copy()

    # First determine the reference chord lengths:
    nSpan = coef.shape[2]
    ref = numpy.zeros((nSpan, 3))

    for k in range(nSpan):
        max_x = numpy.max(coef[:, :, k, 0])
        min_x = numpy.min(coef[:, :, k, 0])

        ref[k, 0] = min_x + 0.25 * (max_x - min_x)
        ref[k, 1] = numpy.average(coef[:, :, k, 1])
        ref[k, 2] = numpy.average(coef[:, :, k, 2])

    c0 = Curve(X=ref, k=2)
Exemple #21
0
    def test_boxes(self, train=False):

        # box1 and box2 intersect
        # box3 does not intersect anything
        comps = ["box1", "box2", "box3"]
        ffdFiles = [os.path.join(inputDir, f"{comp}.xyz") for comp in comps]
        triMeshFiles = [os.path.join(inputDir, f"{comp}.cgns") for comp in comps]

        # Set up component DVGeo objects
        DVGeoBox1 = DVGeometry(ffdFiles[0])
        DVGeoBox2 = DVGeometry(ffdFiles[1])
        DVGeoBox3 = DVGeometry(ffdFiles[2])

        # Set up DVGeometryMulti object
        DVGeo = DVGeometryMulti()
        DVGeo.addComponent("box1", DVGeoBox1, triMeshFiles[0])
        DVGeo.addComponent("box2", DVGeoBox2, triMeshFiles[1])
        DVGeo.addComponent("box3", DVGeoBox3, None)

        # Define some feature curves
        featureCurves = [
            # Curves on box1
            "part_15_1d",
            # Curves on box2
            "part_35_1d",
            "part_37_1d",
            "part_39_1d",
        ]
        curveEpsDict = {
            # Curves on box1
            "part_15_1d": 1e-3,
            # Curves on box2
            "part_35_1d": 1e-3,
            "part_37_1d": 1e-3,
            "part_39_1d": 1e-3,
            # Intersection curve
            "intersection": 1e-3,
        }

        # Track some intersecting surfaces
        trackSurfaces = {
            # box1
            "part_14": 1e-3,
            # box2
            "part_39": 1e-3,
        }

        # Exclude some intersecting surfaces
        excludeSurfaces = {
            # box1
            "part_15": 1e-3,
            # box2
            "part_40": 1e-3,
        }

        # Add the intersection between box1 and box2
        DVGeo.addIntersection(
            "box1",
            "box2",
            dStarA=0.15,
            dStarB=0.15,
            featureCurves=featureCurves,
            project=True,
            includeCurves=True,
            curveEpsDict=curveEpsDict,
            trackSurfaces=trackSurfaces,
            excludeSurfaces=excludeSurfaces,
        )

        # Add a few design variables
        DVGeoDict = DVGeo.getDVGeoDict()
        for comp in comps:
            # Create reference axis
            nRefAxPts = DVGeoDict[comp].addRefAxis("box", xFraction=0.5, alignIndex="j", rotType=4)
            nTwist = nRefAxPts - 1

            # Set up a twist variable
            def twist(val, geo, nRefAxPts=nRefAxPts):
                for i in range(1, nRefAxPts):
                    geo.rot_z["box"].coef[i] = val[i - 1]

            DVGeoDict[comp].addGlobalDV(dvName=f"{comp}_twist", value=[0] * nTwist, func=twist)

        # Define a test point set
        pts = np.array(
            [
                # Points on box1 away from intersection
                [0.0, 0.0, 0.0],
                [0.5, 0.1, -0.5],
                # Points on box2 away from intersection
                [0.5, 0.0, 2.0],
                [0.375, 0.125, 2.0],
                # Point on box3
                [2.5, 0.5, 0.0],
                # Point on curve part_15_1d
                [0.3, 0.0, 0.5],
                # Point on curve part_35_1d
                [0.75, -0.25, 0.6],
                # Point on curve part_37_1d
                [0.25, -0.25, 0.6],
                # Point on curve part_39_1d
                [0.25, 0.25, 0.6],
                # Point on intersection curve
                [0.25, 0.1, 0.5],
                # Point on tracked surface part_14, box1
                [0.5, -0.3, 0.5],
                # Point on tracked surface part_39, box2
                [0.25, 0.12, 0.51],
                # Point on excluded surface part_15, box1
                [0.5, 0.3, 0.5],
                # Point on excluded surface part_40, box2
                [0.375, 0.25, 0.6],
                # Other points near the intersection
                [0.25, 0.251, 0.5],
                [0.5, 0.251, 0.5],
                [0.51, 0.25, 0.4],
                [0.75, 0.25, 0.6],
                [0.5, 0.25, 0.6],
                [0.25, 0.5, 0.6],
                [0.5, -0.25, 0.6],
                [0.25, -0.5, 0.6],
            ]
        )

        # Add the point set
        ptSetName = "test_set"
        comm = MPI.COMM_WORLD
        DVGeo.addPointSet(pts, ptSetName, comm=comm, applyIC=True)

        # Apply twist to the two intersecting boxes
        dvDict = DVGeo.getValues()
        dvDict["box1_twist"] = 2
        dvDict["box2_twist"] = 2
        DVGeo.setDesignVars(dvDict)

        # Update the point set
        ptsUpdated = DVGeo.update(ptSetName)

        # Regression test the updated points
        refFile = os.path.join(baseDir, "ref/test_DVGeometryMulti.ref")
        with BaseRegTest(refFile, train=train) as handler:
            handler.par_add_val("ptsUpdated", ptsUpdated, tol=1e-14)

        # Now we will test the derivatives

        # Build a dIdpt array
        # We will have nNodes*3 many functions of interest
        nNodes = pts.shape[0]
        dIdpt = np.zeros((nNodes * 3, nNodes, 3))

        # Set the seeds to one such that we get individual derivatives for each coordinate of each point
        # The first function of interest gets the first coordinate of the first point
        # The second function gets the second coordinate of first point, and so on
        for i in range(nNodes):
            for j in range(3):
                dIdpt[i * 3 + j, i, j] = 1

        # Get the derivatives from DVGeo
        funcSens = DVGeo.totalSensitivity(dIdpt, ptSetName)

        # Perturb the DVs with finite differences and compute FD gradients
        dvDict = DVGeo.getValues()
        funcSensFD = {}
        dh = 1e-5

        for x in dvDict:

            nx = len(dvDict[x])
            funcSensFD[x] = np.zeros((nx, nNodes * 3))
            for i in range(nx):

                xRef = dvDict[x][i].copy()

                # Compute the central difference
                dvDict[x][i] = xRef + dh
                DVGeo.setDesignVars(dvDict)
                ptsNewPlus = DVGeo.update(ptSetName)

                dvDict[x][i] = xRef - dh
                DVGeo.setDesignVars(dvDict)
                ptsNewMinus = DVGeo.update(ptSetName)

                funcSensFD[x][i, :] = (ptsNewPlus.flatten() - ptsNewMinus.flatten()) / (2 * dh)

                # Set the DV back to the original value
                dvDict[x][i] = xRef.copy()

        # Check that the analytic derivatives are consistent with FD
        for x in dvDict:
            np.testing.assert_allclose(funcSens[x].T, funcSensFD[x], rtol=1e-4, atol=1e-10)

        # Test that adding a point outside any FFD raises an Error
        with self.assertRaises(Error):
            DVGeo.addPointSet(np.array([[-1.0, 0.0, 0.0]]), "test_error")
    def test(self):
        from openaerostruct.geometry.utils import generate_mesh, write_FFD_file

        from openaerostruct.integration.aerostruct_groups import AerostructGeometry, AerostructPoint

        import openmdao.api as om
        from pygeo import DVGeometry


        # Create a dictionary to store options about the surface
        mesh_dict = {'num_y' : 5,
                     'num_x' : 2,
                     'wing_type' : 'CRM',
                     'symmetry' : True,
                     'num_twist_cp' : 5}

        mesh, twist_cp = generate_mesh(mesh_dict)

        surf_dict = {
                    # Wing definition
                    'name' : 'wing',        # name of the surface
                    'symmetry' : True,     # if true, model one half of wing
                                            # reflected across the plane y = 0
                    'S_ref_type' : 'wetted', # how we compute the wing area,
                                             # can be 'wetted' or 'projected'
                    'fem_model_type' : 'tube',

                    'thickness_cp' : np.array([.1, .2, .3]),

                    'mesh' : mesh,

                    'geom_manipulator' : 'FFD',
                    'mx' : 2,
                    'my' : 3,

                    # 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.015,            # 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_cp' : np.array([0.15]),      # thickness over chord ratio (NACA0015)
                    'c_max_t' : .303,       # chordwise location of maximum (NACA0015)
                                            # thickness
                    'with_viscous' : True,
                    'with_wave' : False,     # if true, compute wave drag

                    # Structural values are based on aluminum 7075
                    'E' : 70.e9,            # [Pa] Young's modulus of the spar
                    'G' : 30.e9,            # [Pa] shear modulus of the spar
                    'yield' : 500.e6 / 2.5, # [Pa] yield stress divided by 2.5 for limiting case
                    'mrho' : 3.e3,          # [kg/m^3] material density
                    'fem_origin' : 0.35,    # normalized chordwise location of the spar
                    'wing_weight_ratio' : 2.,
                    'struct_weight_relief' : False,    # True to add the weight of the structure to the loads on the structure
                    'distributed_fuel_weight' : False,
                    # Constraints
                    'exact_failure_constraint' : False, # if false, use KS function
                    }

        surfaces = [surf_dict]

        # Create the problem and assign the model group
        prob = om.Problem()

        # Add problem information as an independent variables component
        indep_var_comp = om.IndepVarComp()
        indep_var_comp.add_output('v', val=248.136, units='m/s')
        indep_var_comp.add_output('alpha', val=5., units='deg')
        indep_var_comp.add_output('Mach_number', val=0.84)
        indep_var_comp.add_output('re', val=1.e6, units='1/m')
        indep_var_comp.add_output('rho', val=0.38, units='kg/m**3')
        indep_var_comp.add_output('CT', val=grav_constant * 17.e-6, units='1/s')
        indep_var_comp.add_output('R', val=11.165e6, units='m')
        indep_var_comp.add_output('W0', val=0.4 * 3e5,  units='kg')
        indep_var_comp.add_output('speed_of_sound', val=295.4, units='m/s')
        indep_var_comp.add_output('load_factor', val=1.)
        indep_var_comp.add_output('empty_cg', val=np.zeros((3)), units='m')

        prob.model.add_subsystem('prob_vars',
             indep_var_comp,
             promotes=['*'])

        # Loop over each surface in the surfaces list
        for surface in surfaces:

            # Get the surface name and create a group to contain components
            # only for this surface
            name = surface['name']

            filename = write_FFD_file(surface, surface['mx'], surface['my'])
            DVGeo = DVGeometry(filename)
            aerostruct_group = AerostructGeometry(surface=surface, DVGeo=DVGeo)

            # Add tmp_group to the problem with the name of the surface.
            prob.model.add_subsystem(name, aerostruct_group)

        # Loop through and add a certain number of aero points
        for i in range(1):

            point_name = 'AS_point_{}'.format(i)
            # Connect the parameters within the model for each aero point

            # Create the aero point group and add it to the model
            AS_point = AerostructPoint(surfaces=surfaces)

            prob.model.add_subsystem(point_name, AS_point)

            # Connect flow properties to the analysis point
            prob.model.connect('v', point_name + '.v')
            prob.model.connect('alpha', point_name + '.alpha')
            prob.model.connect('Mach_number', point_name + '.Mach_number')
            prob.model.connect('re', point_name + '.re')
            prob.model.connect('rho', point_name + '.rho')
            prob.model.connect('CT', point_name + '.CT')
            prob.model.connect('R', point_name + '.R')
            prob.model.connect('W0', point_name + '.W0')
            prob.model.connect('speed_of_sound', point_name + '.speed_of_sound')
            prob.model.connect('empty_cg', point_name + '.empty_cg')
            prob.model.connect('load_factor', point_name + '.load_factor')

            for surface in surfaces:

                com_name = point_name + '.' + name + '_perf'
                prob.model.connect(name + '.local_stiff_transformed', point_name + '.coupled.' + name + '.local_stiff_transformed')
                prob.model.connect(name + '.nodes', point_name + '.coupled.' + name + '.nodes')

                # Connect aerodyamic mesh to coupled group mesh
                prob.model.connect(name + '.mesh', point_name + '.coupled.' + name + '.mesh')

                # Connect performance calculation variables
                prob.model.connect(name + '.radius', com_name + '.radius')
                prob.model.connect(name + '.thickness', com_name + '.thickness')
                prob.model.connect(name + '.nodes', com_name + '.nodes')
                prob.model.connect(name + '.cg_location', point_name + '.' + 'total_perf.' + name + '_cg_location')
                prob.model.connect(name + '.structural_mass', point_name + '.' + 'total_perf.' + name + '_structural_mass')
                prob.model.connect(name + '.t_over_c', com_name + '.t_over_c')

        # Import the Scipy Optimizer and set the driver of the problem to use
        # it, which defaults to an SLSQP optimization method
        prob.driver = om.ScipyOptimizeDriver()

        recorder = om.SqliteRecorder("aerostruct_ffd.db")
        prob.driver.add_recorder(recorder)
        prob.driver.recording_options['record_derivatives'] = True
        prob.driver.recording_options['includes'] = ['*']

        # Setup problem and add design variables, constraint, and objective
        prob.model.add_design_var('wing.shape', lower=-3, upper=2)
        prob.model.add_design_var('wing.thickness_cp', lower=0.01, upper=0.5, scaler=1e2)
        prob.model.add_constraint('AS_point_0.wing_perf.failure', upper=0.)
        prob.model.add_constraint('AS_point_0.wing_perf.thickness_intersects', upper=0.)

        # Add design variables, constraisnt, and objective on the problem
        prob.model.add_design_var('alpha', lower=-10., upper=10.)
        prob.model.add_constraint('AS_point_0.L_equals_W', equals=0.)
        prob.model.add_objective('AS_point_0.fuelburn', scaler=1e-5)

        # iprofile.setup()
        # iprofile.start()

        # Set up the problem
        prob.setup()

        # om.view_model(prob, outfile='aerostruct_ffd', show_browser=False)

        # prob.run_model()
        prob.run_driver()

        # prob.check_partials(compact_print=True)

        # print("\nWing CL:", prob['aero_point_0.wing_perf.CL'])
        # print("Wing CD:", prob['aero_point_0.wing_perf.CD'])


        # from helper import plot_3d_points
        #
        # mesh = prob['aero_point_0.wing.def_mesh']
        # plot_3d_points(mesh)
        #
        # filename = mesh_dict['wing_type'] + '_' + str(mesh_dict['num_x']) + '_' + str(mesh_dict['num_y'])
        # filename += '_' + str(surf_dict['mx']) + '_' + str(surf_dict['my']) + '.mesh'
        # np.save(filename, mesh)

        assert_rel_error(self, prob['AS_point_0.fuelburn'][0], 97680.8964568375, 1e-3)
Exemple #23
0
Xpt[:100, 1] = 0.5 * np.sin(t)
Xpt[:100, 2] = 0.0
Xpt[100:, 0] = 0.5 * np.cos(t) + 0.5
Xpt[100:, 1] = 0.5 * np.sin(t)
Xpt[100:, 2] = 1.0

# rst create DVGeo
# The Plot3D file ffdbox.xyz contains the coordinates of the free-form deformation (FFD)volume
# we will be using for this problem. It's a cube with sides of length 1 centered on (0, 0,0.5).
# The "i" direction of the cube consists of 10 points along the x axis
# The "j" direction of the cube is 2 points up and down (y axis direction)
# The "k" direction of the cube is 2 points into the page (z axis direction)
FFDfile = "ffdbox.xyz"

# initialize the DVGeometry object with the FFD file
DVGeo = DVGeometry(FFDfile)

# rst add pointset
# add the cylinder pointset to the FFD under the name 'cylinder'
DVGeo.addPointSet(Xpt.copy(), "cylinder")
DVGeo.writePointSet("cylinder", "pointset")

# rst add shape DV
# Now that we have pointsets added, we should parameterize the geometry.

# Adding local geometric design to make local modifications to FFD box
# This option will perturb all the control points but only the y (up-down) direction
DVGeo.addLocalDV("shape", lower=-0.5, upper=0.5, axis="y", scale=1.0)

# rst getLocalIndex
# The control points of the FFD are the same as the coordinates of the points in the input file
Exemple #24
0
                 mach=0.8,
                 altitude=10000,
                 areaRef=45.5,
                 chordRef=3.25,
                 evalFuncs=["cl", "cd"])

# Add angle of attack variable
ap.addDV("alpha", value=1.5, lower=0, upper=10.0, scale=0.1)
# rst aeroproblem (end)
# ======================================================================
#         Geometric Design Variable Set-up
# ======================================================================
# rst dvgeo (beg)
# Create DVGeometry object
FFDFile = "ffd.xyz"
DVGeo = DVGeometry(FFDFile)

# Create reference axis
nRefAxPts = DVGeo.addRefAxis("wing", xFraction=0.25, alignIndex="k")
nTwist = nRefAxPts - 1


# Set up global design variables
def twist(val, geo):
    for i in range(1, nRefAxPts):
        geo.rot_z["wing"].coef[i] = val[i - 1]


DVGeo.addGlobalDV(dvName="twist",
                  value=[0] * nTwist,
                  func=twist,
Exemple #25
0
    def test_24_rot0_nonaligned(self, train=False, refDeriv=False):
        """
        Test 24
        This test ensures that the scaling attributes (scale_x, scale_y, and scale_z) are effective when rotType=0 is selected.
        Moreover, this test ensures that rotType=0 reference axis can handle (given appropriate input parameters) FFD blocks that are not aligned with the main system of reference, e.g. the blades of a 3-bladed wind turbine rotor.
        The newly added input parameters rot0ang and rot0axis are used to provide the user control on this.
        The operations that pyGeo performs for this test are the following:
        We start from an initial "vertical" FFD box which, using the combination of rotType=0, rot0ang=-90, and rot0axis=[1,0,0] for addRefAxis(), is first rotated to have its "spanwise" axis along the y axis.
        Then, the script scales the 2nd section along the z axis for a "thickness" increase and the 4th section along the x axis for "chord" increase, it adds a +/- 30 deg twist respectively, and finally rotates the deformed FFD back in the initial position.
        The twist is added to ensure that the operation order is maintained, and the scaling preserves the orthogonality of the FFD in the section plane.
        This is a particular case as the FFD box is already aligned with the main axis and we "flip" the y and z axes, but the same criteria can be applied to a general rotation.
        """
        refFile = os.path.join(self.base_path, "ref/test_DVGeometry_24.ref")
        with BaseRegTest(refFile, train=train) as handler:
            handler.root_print("Test twist and scaling for FFDs non-aligned to main system of reference")
            DVGeo = DVGeometry(os.path.join(self.base_path, "../../input_files/2x1x8_rectangle.xyz"))
            rotType = 0
            xfraction = 0.5
            nRefAxPts = DVGeo.addRefAxis("RefAx", xFraction=xfraction, alignIndex="k", rotType=rotType, rot0ang=-90)

            fix_root_sect = 1
            nTwist = nRefAxPts - fix_root_sect

            DVGeo.addGlobalDV(dvName="twist", value=[0] * nTwist, func=commonUtils.twist, lower=-90, upper=90, scale=1)
            DVGeo.addGlobalDV(
                dvName="thickness", value=[1.0] * nTwist, func=commonUtils.thickness, lower=0.7, upper=5.0, scale=1
            )
            DVGeo.addGlobalDV(
                dvName="chord", value=[1.0] * nTwist, func=commonUtils.chord, lower=0.7, upper=5.0, scale=1
            )

            commonUtils.testSensitivities(DVGeo, refDeriv, handler, pointset=2)

            x = DVGeo.getValues()

            # Modifying the twist
            keyName = "twist"
            twistTest = [30, 0, -30]
            x[keyName] = twistTest

            # Modifying the chord
            keyName = "thickness"
            thickTest = [3.0, 1.0, 1.0]
            x[keyName] = thickTest

            # Modifying the chord
            keyName = "chord"
            chordTest = [1.0, 1.0, 2.0]
            x[keyName] = chordTest

            DVGeo.setDesignVars(x)

            DVGeo.update("testPoints")
            FFD_coords = DVGeo.FFD.coef.copy()

            handler.root_add_val("Updated FFD coordinates", FFD_coords, rtol=1e-12, atol=1e-12)
Exemple #26
0
    def setup_blocks(self, testID, isComplex=False):
        # Make tiny FFD
        ffd_name = '../inputFiles/tiny_cube_{:02d}.xyz'.format(testID)
        file_name = os.path.join(self.base_path, ffd_name)
        self.make_cube_ffd(file_name, 1, 1, 1, 1, 1, 1)
        tiny = DVGeometry(file_name, child=True, complex=isComplex)
        os.remove(file_name)
        tiny.addRefAxis('ref', xFraction=0.5, alignIndex='j', rotType=7)

        # Make tiny FFD
        ffd_name = '../inputFiles/small_cube_{:02d}.xyz'.format(testID)
        file_name = os.path.join(self.base_path, ffd_name)
        self.make_cube_ffd(file_name, 0, 0, 0, 2, 2, 2)
        small = DVGeometry(file_name, child=True, complex=isComplex)
        os.remove(file_name)
        small.addRefAxis('ref', xFraction=0.5, alignIndex='j')

        # Make big FFD
        ffd_name = '../inputFiles/big_cube_{:02d}.xyz'.format(testID)
        file_name = os.path.join(self.base_path, ffd_name)
        self.make_cube_ffd(file_name, 0, 0, 0, 3, 3, 3)
        big = DVGeometry(file_name, complex=isComplex)
        os.remove(file_name)
        big.addRefAxis('ref', xFraction=0.5, alignIndex='i')
        big.addChild(small)
        small.addChild(tiny)

        # Add point set
        points = numpy.array([
                [0.5, 0.5, 0.5],
                [1.25, 1.25, 1.25],
                [1.5, 1.5, 1.5],
                [2.0, 2.5, 0.5],
                ])
        big.addPointSet(points, 'X')

        return big, small, tiny
Exemple #27
0
    "gridFile": os.getcwd(),
    "fileType": "OpenFOAM",
    "symmetryPlanes": [[[0, 0, 0], [0, 1, 0]]],
    "aExp": 3.0,
    "bExp": 5.0,
    "alpha": 1.0,
    "LdefFact": 0.20,
}

mesh = USMesh(options=meshOptions, comm=gcomm)

coords0 = mesh.getSurfaceCoordinates()

# setup FFD
FFDFile = "./FFD/globalFFD.fmt"
DVGeo = DVGeometry(FFDFile)
# Setup curves for ref_axis
x = [-2.0, 0.0, 0.1, 1.044, 5.0]
y = [0.1, 0.1, 0.1, 0.1, 0.1]
z = [0.1, 0.1, 0.1, 0.1, 0.1]

nLength = len(x)

c1 = Curve(x=x, y=y, z=z, k=2)
DVGeo.addRefAxis("bodyAxis", curve=c1, axis="z")

DVGeoChild = DVGeometry("./FFD/bodyFittedFFD.fmt", child=True)

# Setup curves for ref_axis
x1 = [0.0, 0.1, 0.862, 1.044]
y1 = [0.1, 0.1, 0.1, 0.1]
    def test_parent_shape_child_rot(self, train=False, refDeriv=False):
        ffd_name = '../../tests/inputFiles/small_cube.xyz'
        self.make_cube_ffd(ffd_name, 0.1, 0.1, 0.1, 0.8, 0.8, 0.8)
        small = DVGeometry(ffd_name, child=True)
        small.addRefAxis('ref', xFraction=0.5, alignIndex='j')

        x0 = 0.0
        y0 = 0.0
        z0 = 0.0
        dx = 1.0
        dy = 1.0
        dz = 1.0

        axes = ['k', 'j', 'i']
        slices = numpy.array(
            # Slice 1
            [
                [[[x0, y0, z0], [x0 + dx, y0, z0], [x0 + 2 * dx, y0, z0]],
                 [[x0, y0 + dy, z0], [x0 + dx, y0 + dy, z0],
                  [x0 + 2 * dx, y0 + dy, z0]]],
                # Slice 2
                [[[x0, y0, z0 + dz], [x0 + dx, y0, z0 + dz],
                  [x0 + 2 * dx, y0, z0 + dz]],
                 [[x0, y0 + dy, z0 + dz], [x0 + dx, y0 + dy, z0 + dz],
                  [x0 + 2 * dx, y0 + dy, z0 + dz]]]
            ],
            dtype='d')

        N0 = [2]
        N1 = [2]
        N2 = [3]
        ffd_name = '../../tests/inputFiles/big_cube.xyz'

        geo_utils.write_wing_FFD_file(ffd_name, slices, N0, N1, N2, axes=axes)
        big = DVGeometry(ffd_name)
        big.addRefAxis('ref', xFraction=0.5, alignIndex='j')
        big.addChild(small)

        # Add point set
        points = numpy.array([[0.5, 0.5, 0.5]])
        big.addPointSet(points, 'X')

        # Add only translation variables
        add_vars(big, 'big', local='z', rotate='y')
        add_vars(small, 'small', rotate='y')

        ang = 45
        ang_r = numpy.deg2rad(ang)

        # Modify design variables
        x = big.getValues()

        # add a local shape change
        x['local_z_big'] = numpy.array(
            [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.5, 0.5, 0.5])
        big.setDesignVars(x)
        Xs = big.update('X')

        # add a rotation of the child FFD
        x['rotate_y_small'] = ang
        big.setDesignVars(x)
        Xrot_ffd = big.update('X')

        # the modification caused by the child FFD should be the same as rotating the deformed point of the parent
        # (you would think)
        rot_mat = numpy.array([[numpy.cos(ang_r), 0,
                                numpy.sin(ang_r)], [0, 1, 0],
                               [-numpy.sin(ang_r), 0,
                                numpy.cos(ang_r)]])
        Xrot = numpy.dot(rot_mat, (Xs - points).T) + points.T

        numpy.testing.assert_array_almost_equal(Xrot_ffd.T, Xrot)
    def test(self):

        from openaerostruct.geometry.utils import generate_mesh, write_FFD_file
        from openaerostruct.geometry.geometry_group import Geometry
        from openaerostruct.aerodynamics.aero_groups import AeroPoint
        from openaerostruct.integration.multipoint_comps import MultiCD

        import openmdao.api as om
        from openmdao.utils.assert_utils import assert_check_partials
        from pygeo import DVGeometry

        # Create a dictionary to store options about the surface
        mesh_dict = {
            'num_y': 5,
            'num_x': 3,
            'wing_type': 'CRM',
            'symmetry': True,
            'num_twist_cp': 5,
            'span_cos_spacing': 0.0,
        }

        mesh, _ = generate_mesh(mesh_dict)

        surf_dict = {
            # Wing definition
            'name': 'wing',  # name of the surface
            'symmetry': True,  # if true, model one half of wing
            # reflected across the plane y = 0
            'S_ref_type': 'wetted',  # how we compute the wing area,
            # can be 'wetted' or 'projected'
            'fem_model_type': 'tube',
            'mesh': mesh,
            'mx': 2,
            'my': 3,
            'geom_manipulator': 'FFD',
            # 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.015,  # 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_cp':
            np.array([0.15]),  # thickness over chord ratio (NACA0015)
            'c_max_t': 0.303,  # chordwise location of maximum (NACA0015)
            # thickness
            'with_viscous': True,  # if true, compute viscous drag
            'with_wave': False,  # if true, compute wave drag
        }

        surfaces = [surf_dict]

        n_points = 2

        # Create the problem and the model group
        prob = om.Problem()

        indep_var_comp = om.IndepVarComp()
        indep_var_comp.add_output('v', val=248.136, units='m/s')
        indep_var_comp.add_output('alpha',
                                  val=np.ones(n_points) * 6.64,
                                  units='deg')
        indep_var_comp.add_output('Mach_number', val=0.84)
        indep_var_comp.add_output('re', val=1.0e6, units='1/m')
        indep_var_comp.add_output('rho', val=0.38, units='kg/m**3')
        indep_var_comp.add_output('cg', val=np.zeros((3)), units='m')

        prob.model.add_subsystem('prob_vars', indep_var_comp, promotes=['*'])

        # Loop over each surface in the surfaces list
        for surface in surfaces:
            # Get the surface name and create a group to contain components
            # only for this surface
            name = surface['name']

            # FFD setup
            filename = write_FFD_file(surface, surface['mx'], surface['my'])
            DVGeo = DVGeometry(filename)
            geom_group = Geometry(surface=surface, DVGeo=DVGeo)

            # Add tmp_group to the problem with the name of the surface.
            prob.model.add_subsystem(name + '_geom', geom_group)

        # Loop through and add a certain number of aero points
        for i in range(n_points):

            # Create the aero point group and add it to the model
            aero_group = AeroPoint(surfaces=surfaces)
            point_name = 'aero_point_{}'.format(i)
            prob.model.add_subsystem(point_name, aero_group)

            # Connect flow properties to the analysis point
            prob.model.connect('v', point_name + '.v')
            prob.model.connect('alpha', point_name + '.alpha', src_indices=[i])
            prob.model.connect('Mach_number', point_name + '.Mach_number')
            prob.model.connect('re', point_name + '.re')
            prob.model.connect('rho', point_name + '.rho')
            prob.model.connect('cg', point_name + '.cg')

            # Connect the parameters within the model for each aero point
            for surface in surfaces:
                name = surface['name']

                # Connect the drag coeff at this point to the multi_CD component, which does the summation.
                prob.model.connect(point_name + '.CD',
                                   'multi_CD.' + str(i) + '_CD')

                # Connect the mesh from the geometry component to the analysis point
                prob.model.connect(name + '_geom.mesh',
                                   point_name + '.' + name + '.def_mesh')

                # Perform the connections with the modified names within the
                # 'aero_states' group.
                prob.model.connect(
                    name + '_geom.mesh',
                    point_name + '.aero_states.' + name + '_def_mesh')
                prob.model.connect(
                    name + '_geom.t_over_c',
                    point_name + '.' + name + '_perf.' + 't_over_c')

        prob.model.add_subsystem('multi_CD',
                                 MultiCD(n_points=n_points),
                                 promotes_outputs=['CD'])

        prob.driver = om.ScipyOptimizeDriver()

        # Setup problem and add design variables, constraint, and objective
        # design variable is the wing shape, and angle-of-attack at each point.
        prob.model.add_design_var('alpha', lower=-15, upper=15)
        prob.model.add_design_var('wing_geom.shape', lower=-3, upper=2)

        # set different target CL value at each point.
        prob.model.add_constraint('aero_point_0.wing_perf.CL', equals=0.45)
        prob.model.add_constraint('aero_point_1.wing_perf.CL', equals=0.5)

        # objective is the sum of CDs at each point.
        prob.model.add_objective('CD', scaler=1e4)

        # Set up the problem
        prob.setup()
        prob.run_model()

        # Check the partials at this point in the design space
        data = prob.check_partials(compact_print=True,
                                   out_stream=None,
                                   method='fd',
                                   step=1e-5)
        assert_check_partials(data, atol=1e20, rtol=1e-3)
Exemple #30
0
#rst Import libraries
import numpy
from pygeo import DVGeometry
from idwarp import USMesh

#rst Create DVGeometry object
FFDFile = 'ffd.xyz'
DVGeo = DVGeometry(FFDFile)

#rst Create reference axis
nRefAxPts = DVGeo.addRefAxis('wing', xFraction=0.25, alignIndex='k')


#rst Dihedral
def dihedral(val, geo):
    C = geo.extractCoef('wing')
    for i in range(1, nRefAxPts):
        C[i, 1] += val[i - 1]
    geo.restoreCoef(C, 'wing')


#rst Twist
def twist(val, geo):
    for i in range(1, nRefAxPts):
        geo.rot_z['wing'].coef[i] = val[i - 1]


#rst Taper
def taper(val, geo):
    s = geo.extractS('wing')
    slope = (val[1] - val[0]) / (s[-1] - s[0])