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
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.addGlobalDV("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)
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)
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)
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, lower=-10, upper=10, scale=0.01) # Set up local design variables DVGeo.addLocalDV("local", lower=-0.5, upper=0.5, axis="y", scale=1) # Add DVGeo object to CFD solver CFDSolver.setDVGeo(DVGeo) # rst dvgeo (end) # ====================================================================== # DVConstraint Setup, and Thickness and Volume Constraints # ====================================================================== # rst dvconVolThick (beg) DVCon = DVConstraints() DVCon.setDVGeo(DVGeo)
# 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) DVGeo.addRefAxis("wing", c0) DVGeo.addGlobalDV("winglet", [0, 0, 0, 1], winglet, lower=-5, upper=5) DVGeo.addPointSet(coords, "coords") DVGeo.setDesignVars({"winglet": [1.5, 2.5, -2.0, 0.60]}) hyp.setSurfaceCoordinates(DVGeo.update("coords")) # Run and write grid hyp.run() hyp.writeCGNS(volumeFile)
C = geo.extractCoef("bodyAxis") length = val[0] C[1, 0] = C[2, 0] - length geo.restoreCoef(C, "bodyAxis") return # lower = [-2.,-2.,-2.,-2.,5.] # upper = [-2.,5.,5.,5.,5.] # DVGeo.addGlobalDV('length', x, length, # lower=lower, upper=upper, scale=1.0) DVGeo.addGlobalDV("noseLength", 0.3, noseLength, lower=0, upper=0.5, scale=1.0) # DVGeoChild.addGlobalDV('rampAngle', 35.1, rampAngle, # lower=0., upper=90., scale=1.0) DVGeoChild.addGlobalDV("doubleRampAngle", [35.1, -5.0], doubleRampAngle, lower=[0.0, -45.0], upper=[45.0, 5.0], scale=[1.0, 1.0]) # lowerA = [0.,0.,0.,0.] # upperA = [0.3,0.3,0.3,0.3] # DVGeoChild.addGlobalDV('angleVars', z1, angleVars, # lower=lowerA, upper=upperA, scale=1.0) # lowerL = [-1.,-1.,-1.,-1.] # upperL = [2.0,2.0,2.0,2.0]
def test_triangulatedSurface_intersected_2DVGeos(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_triangulatedSurface_intersected_2DVGeos.ref") with BaseRegTest(refFile, train=train) as handler: meshFile = os.path.join(self.base_path, "../../input_files/bwb.stl") objFile = os.path.join(self.base_path, "../../input_files/blob_bwb_wing.stl") ffdFile = os.path.join(self.base_path, "../../input_files/bwb.xyz") testMesh = mesh.Mesh.from_file(meshFile) testObj = mesh.Mesh.from_file(objFile) # 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 DVGeo1 = DVGeometry(ffdFile) nRefAxPts = DVGeo1.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] DVGeo1.addGlobalDV(dvName="twist", value=[0] * self.nTwist, func=twist, lower=-10, upper=10, scale=1) DVGeo1.addLocalDV("local", lower=-0.5, upper=0.5, axis="y", scale=1) # create a DVGeo object with a few local thickness variables DVGeo2 = DVGeometry(ffdFile, name="blobdvgeo") DVGeo2.addLocalDV("local_2", lower=-0.5, upper=0.5, axis="y", scale=1) # check that DVGeos with duplicate var names are not allowed DVGeo3 = DVGeometry(ffdFile) DVGeo3.addLocalDV("local", lower=-0.5, upper=0.5, axis="y", scale=1) # create a DVConstraints object for the wing DVCon = DVConstraints() DVCon.setDVGeo(DVGeo1) DVCon.setDVGeo(DVGeo2, name="second") with self.assertRaises(ValueError): DVCon.setDVGeo(DVGeo3, name="third") p0 = testMesh.vectors[:, 0, :] v1 = testMesh.vectors[:, 1, :] - p0 v2 = testMesh.vectors[:, 2, :] - p0 DVCon.setSurface([p0, v1, v2], addToDVGeo=True) p0b = testObj.vectors[:, 0, :] v1b = testObj.vectors[:, 1, :] - p0b v2b = testObj.vectors[:, 2, :] - p0b p0b = p0b + np.array([0.0, 0.3, 0.0]) DVCon.setSurface([p0b, v1b, v2b], name="blob", addToDVGeo=True, DVGeoName="second") DVCon.addTriangulatedSurfaceConstraint("default", "default", "blob", "second", rho=10.0, addToPyOpt=True) funcs = {} DVCon.evalFunctions(funcs, includeLinear=True) handler.root_add_dict("funcs_base", funcs, rtol=1e-6, atol=1e-6) funcsSens = {} DVCon.evalFunctionsSens(funcsSens, includeLinear=True) # regress the derivatives handler.root_add_dict("derivs_base", funcsSens, rtol=1e-6, atol=1e-6) # FD check DVGeo1 funcsSensFD = evalFunctionsSensFD(DVGeo1, DVCon, fdstep=1e-3) at_least_one_var = False for outkey in funcs.keys(): for inkey in DVGeo1.getValues().keys(): analytic = funcsSens[outkey][inkey] fd = funcsSensFD[outkey][inkey] handler.assert_allclose(analytic, fd, name="finite_diff_check", rtol=1e-3, atol=1e-3) # make sure there are actually checks happening self.assertTrue(np.abs(np.sum(fd)) > 1e-10) at_least_one_var = True self.assertTrue(at_least_one_var) # FD check DVGeo2 funcsSensFD = evalFunctionsSensFD(DVGeo2, DVCon, fdstep=1e-3) at_least_one_var = False for outkey in funcs.keys(): for inkey in DVGeo2.getValues().keys(): analytic = funcsSens[outkey][inkey] fd = funcsSensFD[outkey][inkey] handler.assert_allclose(analytic, fd, name="finite_diff_check", rtol=1e-3, atol=1e-3) self.assertTrue(np.abs(np.sum(fd)) > 1e-10) at_least_one_var = True self.assertTrue(at_least_one_var)
def generate_dvgeo_dvcon(self, geometry, addToDVGeo=False, intersected=False): """ This function creates the DVGeometry and DVConstraints objects for each geometry used in this class. The C172 wing represents a typical use case with twist and shape variables. The rectangular box is primarily used to test unscaled constraint function values against known values for thickness, volume, and surface area. The BWB is used for the triangulated surface and volume constraint tests. The RAE 2822 wing is used for the curvature constraint test. """ if geometry == "c172": meshFile = os.path.join(self.base_path, "../../input_files/c172.stl") ffdFile = os.path.join(self.base_path, "../../input_files/c172.xyz") xFraction = 0.25 meshScale = 1e-3 elif geometry == "box": meshFile = os.path.join(self.base_path, "../../input_files/2x1x8_rectangle.stl") ffdFile = os.path.join(self.base_path, "../../input_files/2x1x8_rectangle.xyz") xFraction = 0.5 meshScale = 1 elif geometry == "bwb": meshFile = os.path.join(self.base_path, "../../input_files/bwb.stl") ffdFile = os.path.join(self.base_path, "../../input_files/bwb.xyz") xFraction = 0.25 meshScale = 1 elif geometry == "rae2822": ffdFile = os.path.join(self.base_path, "../../input_files/deform_geometry_ffd.xyz") xFraction = 0.25 DVGeo = DVGeometry(ffdFile, child=self.child) DVCon = DVConstraints() nRefAxPts = DVGeo.addRefAxis("wing", xFraction=xFraction, alignIndex="k") self.nTwist = nRefAxPts - 1 if self.child: parentFFD = os.path.join(self.base_path, "../../input_files/parent.xyz") self.parentDVGeo = DVGeometry(parentFFD) self.parentDVGeo.addChild(DVGeo) DVCon.setDVGeo(self.parentDVGeo) else: DVCon.setDVGeo(DVGeo) # Add 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] * self.nTwist, func=twist, lower=-10, upper=10, scale=1) DVGeo.addLocalDV("local", lower=-0.5, upper=0.5, axis="y", scale=1) # RAE 2822 does not have a DVCon surface so we just return if geometry == "rae2822": return DVGeo, DVCon # Get the mesh from the STL testMesh = mesh.Mesh.from_file(meshFile) # dim 0 is triangle index # dim 1 is each vertex of the triangle # dim 2 is x, y, z dimension p0 = testMesh.vectors[:, 0, :] * meshScale v1 = testMesh.vectors[:, 1, :] * meshScale - p0 v2 = testMesh.vectors[:, 2, :] * meshScale - p0 DVCon.setSurface([p0, v1, v2], addToDVGeo=addToDVGeo) # Add the blob surface for the BWB if geometry == "bwb": objFile = os.path.join(self.base_path, "../../input_files/blob_bwb_wing.stl") testObj = mesh.Mesh.from_file(objFile) p0b = testObj.vectors[:, 0, :] v1b = testObj.vectors[:, 1, :] - p0b v2b = testObj.vectors[:, 2, :] - p0b if intersected: p0b = p0b + np.array([0.0, 0.3, 0.0]) DVCon.setSurface([p0b, v1b, v2b], name="blob") return DVGeo, DVCon
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]) for i in range(nRefAxPts): geo.scale_x["wing"].coef[i] = slope * (s[i] - s[0]) + val[0] # rst Add global dvs nTwist = nRefAxPts - 1 DVGeo.addGlobalDV(dvName="dihedral", value=[0] * nTwist, func=dihedral, lower=-10, upper=10, scale=1) DVGeo.addGlobalDV(dvName="twist", value=[0] * nTwist, func=twist, lower=-10, upper=10, scale=1) DVGeo.addGlobalDV(dvName="taper", value=[1] * 2, func=taper, lower=0.5, upper=1.5, scale=1) # rst Add local dvs # Comment out one or the other DVGeo.addLocalDV("local", lower=-0.5, upper=0.5, axis="y", scale=1) DVGeo.addLocalSectionDV("slocal", secIndex="k", axis=1, lower=-0.5, upper=0.5, scale=1) # rst Embed points gridFile = "wing_vol.cgns" meshOptions = {"gridFile": gridFile} mesh = USMesh(options=meshOptions) coords = mesh.getSurfaceCoordinates() DVGeo.addPointSet(coords, "coords")