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
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)
scale=[1.0, 1.0]) # lowerA = [0.,0.,0.,0.] # upperA = [0.3,0.3,0.3,0.3] # DVGeoChild.addGeoDVGlobal('angleVars', z1, angleVars, # lower=lowerA, upper=upperA, scale=1.0) # lowerL = [-1.,-1.,-1.,-1.] # upperL = [2.0,2.0,2.0,2.0] # DVGeoChild.addGeoDVGlobal('noseLen', x1, noseLength, # lower=lowerL, upper=upperL, scale=1.0) # DVGeo.addGeoDVGlobal('angleVars', z1, angleVars, # lower=lowerA, upper=upperA, scale=1.0) # Add the child to the parent DVGeo.addChild(DVGeoChild) ptSetName = "allSurfs" freezeDict = { } # '0':['jLow'],'1':['jLow'],'2':['jLow']}#'0':['jLow'],'1':['jHigh','jLow']} DVGeo.addPointSet(coords0, ptSetName, faceFreeze=freezeDict) xDV = DVGeo.getValues() # Required design variables # Rear ramp angle, fixed 200 mm length # overall length # nose length # Ramp shape # Ground separation # Lower ramp angle
def test_parent_shape_child_rot(self, train=False, refDeriv=False): ffd_name = "../../input_files/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 = np.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 = "../../input_files/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 = np.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 = np.deg2rad(ang) # Modify design variables x = big.getValues() # add a local shape change x["local_z_big"] = np.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 = np.array([[np.cos(ang_r), 0, np.sin(ang_r)], [0, 1, 0], [-np.sin(ang_r), 0, np.cos(ang_r)]]) Xrot = np.dot(rot_mat, (Xs - points).T) + points.T np.testing.assert_array_almost_equal(Xrot_ffd.T, Xrot)
def createFFD(): # Bounding box for bump x_root_range = [-0.1, 3.1] y_root_range = [-0.1, 1.1] z_root_range = [-0.1, 1.1] # Number of FFD control points per dimension nX = 10 # streamwise nY = 2 nZ = 2 # only modify the top control points # Compute grid points span_dist = np.linspace(0, 1, nX) x_sections = span_dist * (x_root_range[1] - x_root_range[0]) + x_root_range[0] z_sections = z_root_range X = np.zeros((nX, nY, nZ)) Y = np.zeros((nX, nY, nZ)) Z = np.zeros((nX, nY, nZ)) for i in range(nX): for j in range(nY): for k in range(nZ): X[i, j, k] = x_sections[i] Y[i, j, k] = y_root_range[j] Z[i, j, k] = z_sections[k] # rst Write # Write FFD to file filename = "plateffdp.xyz" f = open(filename, "w") f.write("\t\t1\n") f.write("\t\t%d\t\t%d\t\t%d\n" % (nX, nY, nZ)) for set in [X, Y, Z]: for k in range(nZ): for j in range(nY): for i in range(nX): f.write("\t%3.8f" % (set[i, j, k])) f.write("\n") f.close() # Create the child FFD, actual DVs defined on this # Bounding box for bump x_root_range_c = optOptions['bumpBounds'] y_root_range_c = [-0.05, 1.05] z_root_range_c = [-0.05, 0.95] # Number of FFD control points per dimension nXc = optOptions['NX'] # streamwise nYc = 2 nZc = 3 # only modify the top control points # Compute grid points span_dist_c = np.linspace(0, 1, nXc) x_sections_c = span_dist_c * (x_root_range_c[1] - x_root_range_c[0]) + x_root_range_c[0] z_span_dist_c = np.linspace(0, 1, nZc) z_sections_c = z_span_dist_c * (z_root_range_c[1] - z_root_range_c[0]) + z_root_range_c[0] Xc = np.zeros((nXc, nYc, nZc)) Yc = np.zeros((nXc, nYc, nZc)) Zc = np.zeros((nXc, nYc, nZc)) for i in range(nXc): for j in range(nYc): for k in range(nZc): Xc[i, j, k] = x_sections_c[i] Yc[i, j, k] = y_root_range_c[j] Zc[i, j, k] = z_sections_c[k] # rst Write # Write FFD to file filenamec = "plateffdc.xyz" fc = open(filenamec, "w") fc.write("\t\t1\n") fc.write("\t\t%d\t\t%d\t\t%d\n" % (nXc, nYc, nZc)) for set in [Xc, Yc, Zc]: for k in range(nZc): for j in range(nYc): for i in range(nXc): fc.write("\t%3.8f" % (set[i, j, k])) fc.write("\n") fc.close() # define the design variables #add point set here? no # meshOptions = warpOptions # mesh = USMesh(options=meshOptions) # coords = mesh.getSurfaceCoordinates() DVGeo = DVGeometry(filename) #DVGeo.addPointSet(coords, "coords") DVGeoc = DVGeometry(filenamec, child=True) DVGeoc.addRefAxis('dummy_axis', xFraction=0.1, alignIndex='i') DVGeo.addChild(DVGeoc) # local design vars are just the Z-positions of (some) upper control points length = x_root_range_c[1] - x_root_range_c[0] z_mid = (z_root_range_c[1] + z_root_range_c[0]) / 2 frac = optOptions['DVFraction'] P1 = [x_root_range_c[0] + frac * length, 0, z_mid / 2] P2 = [x_root_range_c[1] - frac * length, 0, 3 * z_mid / 2] PS = geo_utils.PointSelect(psType='y', pt1=P1, pt2=P2) # vname = "pnts" UB = optOptions['DVUpperBound'] DVGeoc.addGeoDVLocal(dvName=vname, lower=0.0, upper=UB, axis="z", scale=1, pointSelect=PS) return DVGeo # # test out on a mesh # gridFile = "grid_struct_69x49_vol_mod2.cgns" # meshOptions = warpOptions # meshOptions["gridfile"] = gridFile # mesh = USMesh(options=meshOptions) # coords = mesh.getSurfaceCoordinates() # DVGeo.addPointSet(coords, "coords") # dvDict = DVGeoc.getValues() # #for i in range(int(nXc/2)): # dvDict["pnts"][:] = 0.2 # # dvDict["pnts"][2] = 0.2 # # dvDict["pnts"][3] = 0.2 # # dvDict["pnts"][4] = 0.1 # # dvDict["pnts"][5] = 0.1 # # dvDict["pnts"][6] = 0.1 # # dvDict["pnts"][7] = 0.1 # DVGeoc.setDesignVars(dvDict) # DVGeoc.printDesignVariables() # new_coords = DVGeo.update("coords") # DVGeoc.writePlot3d("ffdc_deformed.xyz") # #DVGeo.writePointSet("coords", "surf") # # move the mesh using idwarp # # Reset the newly computed surface coordiantes # mesh.setSurfaceCoordinates(new_coords) # # Actually run the mesh warping # mesh.warpMesh() # # Write the new grid file. # mesh.writeGrid(f'ffd_warped.cgns')
class RegTestPyGeo(unittest.TestCase): N_PROCS = 1 def setUp(self): # Store the path where this current script lives # This all paths in the script are relative to this path # This is needed to support testflo running directories and files as inputs self.base_path = os.path.dirname(os.path.abspath(__file__)) 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 wing_test_twist(self, DVGeo, DVCon, handler): funcs = {} funcsSens = {} # change the DVs xDV = DVGeo.getValues() xDV["twist"] = np.linspace(0, 10, len(xDV["twist"])) if self.child: # Twist needs to be set on the parent FFD to get accurate derivatives self.parentDVGeo.setDesignVars(xDV) else: DVGeo.setDesignVars(xDV) # check the constraint values changed DVCon.evalFunctions(funcs, includeLinear=True) handler.root_add_dict("funcs_twisted", funcs, rtol=1e-6, atol=1e-6) # check the derivatives are still right DVCon.evalFunctionsSens(funcsSens, includeLinear=True) # regress the derivatives handler.root_add_dict("derivs_twisted", funcsSens, rtol=1e-6, atol=1e-6) return funcs, funcsSens def wing_test_deformed(self, DVGeo, DVCon, handler): funcs = {} funcsSens = {} xDV = DVGeo.getValues() np.random.seed(37) xDV["local"] = np.random.normal(0.0, 0.05, len(xDV["local"])) DVGeo.setDesignVars(xDV) DVCon.evalFunctions(funcs, includeLinear=True) DVCon.evalFunctionsSens(funcsSens, includeLinear=True) handler.root_add_dict("funcs_deformed", funcs, rtol=1e-6, atol=1e-6) handler.root_add_dict("derivs_deformed", funcsSens, rtol=1e-6, atol=1e-6) return funcs, funcsSens def test_thickness1D(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_thickness1D.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("c172") ptList = [[0.8, 0.0, 0.1], [0.8, 0.0, 5.0]] DVCon.addThicknessConstraints1D(ptList, nCon=10, axis=[0, 1, 0]) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler, checkDerivs=True) # 1D thickness should be all ones at the start handler.assert_allclose( funcs["DVCon1_thickness_constraints_0"], np.ones(10), name="thickness_base", rtol=1e-7, atol=1e-7 ) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) # 1D thickness shouldn't change much under only twist handler.assert_allclose( funcs["DVCon1_thickness_constraints_0"], np.ones(10), name="thickness_twisted", rtol=1e-2, atol=1e-2 ) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) def test_thickness1D_box(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_thickness1D_box.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("box") ptList = [[0.0, 0.0, 0.1], [0.0, 0.0, 5.0]] ptList2 = [[-0.5, 0.0, 2.0], [0.5, 0.0, 2.0]] DVCon.addThicknessConstraints1D(ptList, nCon=3, axis=[0, 1, 0], scaled=False) DVCon.addThicknessConstraints1D(ptList, nCon=3, axis=[1, 0, 0], scaled=False) DVCon.addThicknessConstraints1D(ptList2, nCon=3, axis=[0, 0, 1], scaled=False) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) # Check that unscaled thicknesses are computed correctly at baseline handler.assert_allclose( funcs["DVCon1_thickness_constraints_0"], np.ones(3), name="thickness_base", rtol=1e-7, atol=1e-7 ) handler.assert_allclose( funcs["DVCon1_thickness_constraints_1"], 2.0 * np.ones(3), name="thickness_base", rtol=1e-7, atol=1e-7 ) handler.assert_allclose( funcs["DVCon1_thickness_constraints_2"], 8.0 * np.ones(3), name="thickness_base", rtol=1e-7, atol=1e-7 ) def test_thickness2D(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_thickness2D.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("c172") leList = [[0.7, 0.0, 0.1], [0.7, 0.0, 5.0]] teList = [[0.9, 0.0, 0.1], [0.9, 0.0, 5.0]] DVCon.addThicknessConstraints2D(leList, teList, 5, 5) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) # 2D thickness should be all ones at the start handler.assert_allclose( funcs["DVCon1_thickness_constraints_0"], np.ones(25), name="thickness_base", rtol=1e-7, atol=1e-7 ) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) # 2D thickness shouldn't change much under only twist handler.assert_allclose( funcs["DVCon1_thickness_constraints_0"], np.ones(25), name="thickness_twisted", rtol=1e-2, atol=1e-2 ) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) def test_thickness2D_box(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_thickness2D_box.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("box") leList = [[-0.25, 0.0, 0.1], [-0.25, 0.0, 7.9]] teList = [[0.75, 0.0, 0.1], [0.75, 0.0, 7.9]] leList2 = [[0.0, -0.25, 0.1], [0.0, -0.25, 7.9]] teList2 = [[0.0, 0.25, 0.1], [0.0, 0.25, 7.9]] leList3 = [[-0.5, -0.25, 0.1], [0.5, -0.25, 0.1]] teList3 = [[-0.5, 0.25, 0.1], [0.5, 0.25, 0.1]] DVCon.addThicknessConstraints2D(leList, teList, 2, 2, scaled=False) DVCon.addThicknessConstraints2D(leList2, teList2, 2, 2, scaled=False) DVCon.addThicknessConstraints2D(leList3, teList3, 2, 2, scaled=False) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) # Check that unscaled thicknesses are computed correctly at baseline handler.assert_allclose( funcs["DVCon1_thickness_constraints_0"], np.ones(4), name="thickness_base", rtol=1e-7, atol=1e-7 ) handler.assert_allclose( funcs["DVCon1_thickness_constraints_1"], 2.0 * np.ones(4), name="thickness_base", rtol=1e-7, atol=1e-7 ) handler.assert_allclose( funcs["DVCon1_thickness_constraints_2"], 8.0 * np.ones(4), name="thickness_base", rtol=1e-7, atol=1e-7 ) def test_volume(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_volume.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("c172") leList = [[0.7, 0.0, 0.1], [0.7, 0.0, 5.0]] teList = [[0.9, 0.0, 0.1], [0.9, 0.0, 5.0]] DVCon.addVolumeConstraint(leList, teList, 5, 5) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) # Volume should be normalized to 1 at the start handler.assert_allclose( funcs["DVCon1_volume_constraint_0"], np.ones(1), name="volume_base", rtol=1e-7, atol=1e-7 ) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) # Volume shouldn't change much with twist only handler.assert_allclose( funcs["DVCon1_volume_constraint_0"], np.ones(1), name="volume_twisted", rtol=1e-2, atol=1e-2 ) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) def test_volume_box(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_volume_box.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("box") # this projects in the z direction which is of dimension 8 # 1x0.5x8 = 4 leList = [[-0.5, -0.25, 0.1], [0.5, -0.25, 0.1]] teList = [[-0.5, 0.25, 0.1], [0.5, 0.25, 0.1]] DVCon.addVolumeConstraint(leList, teList, 4, 4, scaled=False) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) # Check that unscaled volume is computed correctly at baseline handler.assert_allclose( funcs["DVCon1_volume_constraint_0"], 4.0 * np.ones(1), name="volume_base", rtol=1e-7, atol=1e-7 ) def test_LeTe(self, train=False, refDeriv=False): """ LeTe constraint test using the iLow, iHigh method """ refFile = os.path.join(self.base_path, "ref/test_DVConstraints_LeTe.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("c172") if self.child: DVCon.addLeTeConstraints(0, "iLow", childIdx=0) DVCon.addLeTeConstraints(0, "iHigh", childIdx=0) else: DVCon.addLeTeConstraints(0, "iLow") DVCon.addLeTeConstraints(0, "iHigh") funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) # LeTe constraints should be all zero at the start for i in range(2): handler.assert_allclose( funcs["DVCon1_lete_constraint_" + str(i)], np.zeros(4), name="lete_" + str(i), rtol=1e-7, atol=1e-7 ) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) # Global DVs should produce no change, especially twist for i in range(2): handler.assert_allclose( funcs["DVCon1_lete_constraint_" + str(i)], np.zeros(4), name="lete_twisted_" + str(i), rtol=1e-7, atol=1e-7, ) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) def test_thicknessToChord(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_thicknessToChord.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("c172") ptList = [[0.8, 0.0, 0.1], [0.8, 0.0, 5.0]] DVCon.addThicknessToChordConstraints1D(ptList, nCon=10, axis=[0, 1, 0], chordDir=[1, 0, 0]) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) handler.assert_allclose( funcs["DVCon1_thickness_to_chord_constraints_0"], np.ones(10), name="toverc_base", rtol=1e-7, atol=1e-7 ) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) handler.assert_allclose( funcs["DVCon1_thickness_to_chord_constraints_0"], np.ones(10), name="toverc_twisted", rtol=1e-3, atol=1e-3, ) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) def test_surfaceArea(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_surfaceArea.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("c172") DVCon.addSurfaceAreaConstraint() funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) handler.assert_allclose( funcs["DVCon1_surfaceArea_constraints_0"], np.ones(1), name="surface_area_base", rtol=1e-7, atol=1e-7 ) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) handler.assert_allclose( funcs["DVCon1_surfaceArea_constraints_0"], np.ones(1), name="surface_area_twisted", rtol=1e-3, atol=1e-3 ) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) def test_surfaceArea_box(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_surfaceArea_box.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("box") DVCon.addSurfaceAreaConstraint(scaled=False) # 2x1x8 box has surface area 2*(8*2+1*2+8*1) = 52 funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) handler.assert_allclose( funcs["DVCon1_surfaceArea_constraints_0"], 52.0 * np.ones(1), name="surface_area_base", rtol=1e-7, atol=1e-7, ) def test_projectedArea(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_projectedArea.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("c172") DVCon.addProjectedAreaConstraint() funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) handler.assert_allclose( funcs["DVCon1_projectedArea_constraints_0"], np.ones(1), name="projected_area_base", rtol=1e-7, atol=1e-7, ) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) def test_projectedArea_box(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_projectedArea_box.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("box") DVCon.addProjectedAreaConstraint(scaled=False) DVCon.addProjectedAreaConstraint(axis="z", scaled=False) DVCon.addProjectedAreaConstraint(axis="x", scaled=False) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler, checkDerivs=False) handler.assert_allclose( funcs["DVCon1_projectedArea_constraints_0"], 8 * 2 * np.ones(1), name="projected_area_base", rtol=1e-7, atol=1e-7, ) handler.assert_allclose( funcs["DVCon1_projectedArea_constraints_1"], 1 * 2 * np.ones(1), name="projected_area_base", rtol=1e-7, atol=1e-7, ) handler.assert_allclose( funcs["DVCon1_projectedArea_constraints_2"], 8 * 1 * np.ones(1), name="projected_area_base", rtol=1e-7, atol=1e-7, ) def test_circularity(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_circularity.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("c172") DVCon.addCircularityConstraint( origin=[0.8, 0.0, 2.5], rotAxis=[0.0, 0.0, 1.0], radius=0.1, zeroAxis=[0.0, 1.0, 0.0], angleCW=180.0, angleCCW=180.0, nPts=10, ) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) handler.assert_allclose( funcs["DVCon1_circularity_constraints_0"], np.ones(9), name="circularity_base", rtol=1e-7, atol=1e-7 ) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) handler.assert_allclose( funcs["DVCon1_circularity_constraints_0"], np.ones(9), name="circularity_twisted", rtol=1e-7, atol=1e-7 ) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) def test_colinearity(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_colinearity.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("c172") DVCon.addColinearityConstraint( np.array([0.7, 0.0, 1.0]), lineAxis=np.array([0.0, 0.0, 1.0]), distances=[0.0, 1.0, 2.5] ) # Skip derivatives check here because true zero values cause difficulties for the partials funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler, checkDerivs=False) handler.assert_allclose( funcs["DVCon1_colinearity_constraints_0"], np.zeros(3), name="colinearity_base", rtol=1e-7, atol=1e-7 ) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) def test_linearConstraintShape(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_linearConstraintShape.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("c172") lIndex = DVGeo.getLocalIndex(0) indSetA = [] indSetB = [] for i in range(lIndex.shape[0]): indSetA.append(lIndex[i, 0, 0]) indSetB.append(lIndex[i, 0, 1]) if self.child: DVCon.addLinearConstraintsShape( indSetA, indSetB, factorA=1.0, factorB=-1.0, lower=0, upper=0, childIdx=0 ) else: DVCon.addLinearConstraintsShape(indSetA, indSetB, factorA=1.0, factorB=-1.0, lower=0, upper=0) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) def test_compositeVolume_box(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_compositeVolume_box.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("box") # this projects in the z direction which is of dimension 8 # 1x0.5x8 = 4 leList = [[-0.5, -0.25, 0.1], [0.5, -0.25, 0.1]] teList = [[-0.5, 0.25, 0.1], [0.5, 0.25, 0.1]] # this projects in the x direction which is of dimension 2 # 2x0.6x7.8 = 9.36 leList2 = [[0.0, -0.25, 0.1], [0.0, -0.25, 7.9]] teList2 = [[0.0, 0.35, 0.1], [0.0, 0.35, 7.9]] DVCon.addVolumeConstraint(leList, teList, 4, 4, scaled=False, addToPyOpt=False) DVCon.addVolumeConstraint(leList2, teList2, 4, 4, scaled=False, addToPyOpt=False) vols = ["DVCon1_volume_constraint_0", "DVCon1_volume_constraint_1"] DVCon.addCompositeVolumeConstraint(vols=vols, scaled=False) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) # Check that unscaled volumes are computed correctly at baseline handler.assert_allclose( funcs["DVCon1_volume_constraint_0"], 4.0 * np.ones(1), name="volume1_base", rtol=1e-7, atol=1e-7 ) handler.assert_allclose( funcs["DVCon1_volume_constraint_1"], 9.36 * np.ones(1), name="volume2_base", rtol=1e-7, atol=1e-7 ) handler.assert_allclose( funcs["DVCon1_composite_volume_constraint_2"], 13.36 * np.ones(1), name="volume_composite_base", rtol=1e-7, atol=1e-7, ) def test_location_box(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_location_box.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("box") ptList = [[0.0, 0.0, 0.0], [0.0, 0.0, 8.0]] ptList2 = [[0.0, 0.2, 0.0], [0.0, -0.2, 8.0]] # TODO this constraint seems buggy. for example, when scaled, returns a bunch of NaNs DVCon.addLocationConstraints1D(ptList=ptList, nCon=10, scaled=False) DVCon.addProjectedLocationConstraints1D(ptList=ptList2, nCon=10, scaled=False, axis=[0.0, 1.0, 0.0]) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) exact_vals = np.zeros((30,)) exact_vals[2::3] = np.linspace(0, 8, 10) # should be 10 evenly spaced points along the z axis originating from 0,0,0 handler.assert_allclose( funcs["DVCon1_location_constraints_0"], exact_vals, name="locations_match", rtol=1e-7, atol=1e-7 ) handler.assert_allclose( funcs["DVCon1_location_constraints_1"], exact_vals, name="projected_locations_match", rtol=1e-7, atol=1e-7, ) def test_planarity_box(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_planarity_box.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("box") DVCon.addPlanarityConstraint(origin=[0.0, 0.5, 0.0], planeAxis=[0.0, 1.0, 0.0]) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) def test_planarity_tri(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_planarity_tri.ref") with BaseRegTest(refFile, train=train) as handler: # Set up a dummy DVGeo and DVCon DVGeo, DVCon = self.generate_dvgeo_dvcon("box") # Set a DVConstraints surface consisting of a simple plane with 2 triangles 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], name="tri") DVCon.addPlanarityConstraint(origin=[0.0, -0.25, 2.0], planeAxis=[0.0, 1.0, 0.0], surfaceName="tri") funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler, checkDerivs=False) # this should be coplanar and the planarity constraint should be zero handler.assert_allclose( funcs["DVCon1_planarity_constraints_0"], np.zeros(1), name="planarity", rtol=1e-7, atol=1e-7 ) def test_monotonic(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_monotonic.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("c172") if self.child: DVCon.addMonotonicConstraints("twist", childIdx=0) DVCon.addMonotonicConstraints("twist", start=1, stop=2, childIdx=0) else: DVCon.addMonotonicConstraints("twist") DVCon.addMonotonicConstraints("twist", start=1, stop=2) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) handler.assert_allclose( funcs["DVCon1_monotonic_constraint_0"], np.zeros(2), name="monotonicity", rtol=1e-7, atol=1e-7 ) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) handler.assert_allclose( funcs["DVCon1_monotonic_constraint_0"], -5.0 * np.ones(2), name="monotonicity_twisted", rtol=1e-7, atol=1e-7, ) funcs = {} funcsSens = {} # change the DVs arbitrarily xDV = DVGeo.getValues() xDV["twist"][0] = 1.0 xDV["twist"][1] = -3.5 xDV["twist"][2] = -2.5 DVGeo.setDesignVars(xDV) # check the constraint values changed DVCon.evalFunctions(funcs, includeLinear=True) handler.root_add_dict("funcs_arb_twist", funcs, rtol=1e-6, atol=1e-6) # check the derivatives are still right DVCon.evalFunctionsSens(funcsSens, includeLinear=True) # regress the derivatives handler.root_add_dict("derivs_arb_twist", funcsSens, rtol=1e-6, atol=1e-6) handler.assert_allclose( funcs["DVCon1_monotonic_constraint_0"], np.array([4.5, -1.0]), name="monotonicity_arb_twist", rtol=1e-7, atol=1e-7, ) handler.assert_allclose( funcs["DVCon1_monotonic_constraint_1"], np.array([-1.0]), name="monotonicity_arb_twist_1", rtol=1e-7, atol=1e-7, ) @unittest.skipIf(missing_geograd, "requires geograd") def test_triangulatedSurface(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_triangulatedSurface.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("bwb", addToDVGeo=True) DVCon.addTriangulatedSurfaceConstraint("default", "default", "blob", None, rho=10.0, addToPyOpt=True) DVCon.addTriangulatedSurfaceConstraint("default", "default", "blob", None, rho=1000.0, addToPyOpt=True) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler, fdstep=1e-3) handler.assert_allclose( funcs["DVCon1_trisurf_constraint_0_KS"], 0.34660627481696404, name="KS", rtol=1e-7, atol=1e-7 ) handler.assert_allclose(funcs["DVCon1_trisurf_constraint_0_perim"], 0.0, name="perim", rtol=1e-7, atol=1e-7) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) @unittest.skipIf(missing_geograd, "requires geograd") def test_triangulatedSurface_intersected(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_triangulatedSurface_intersected.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("bwb", addToDVGeo=True, intersected=True) DVCon.addTriangulatedSurfaceConstraint("default", "default", "blob", None, rho=10.0, addToPyOpt=True) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) np.testing.assert_array_less(np.zeros(1), funcs["DVCon1_trisurf_constraint_0_perim"]) def test_triangulatedVolume_box(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_triangulatedVolume_box.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("box", addToDVGeo=True) DVCon.addTriangulatedVolumeConstraint(scaled=False, name="unscaled_vol_con") DVCon.addTriangulatedVolumeConstraint(scaled=True) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) # Check that the scaled and unscaled volumes are computed correctly at baseline handler.assert_allclose( funcs["DVCon1_trivolume_constraint_1"], 1.0, name="scaled_volume_base", rtol=1e-7, atol=1e-7 ) handler.assert_allclose(funcs["unscaled_vol_con"], 16.0, name="unscaled_volume_base", rtol=1e-7, atol=1e-7) def test_triangulatedVolume_bwb(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_triangulatedVolume_bwb.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("bwb", addToDVGeo=True) DVCon.addTriangulatedVolumeConstraint(scaled=False, name="unscaled_vol_con") DVCon.addTriangulatedVolumeConstraint(scaled=True) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) # Check that the scaled and unscaled volumes are computed correctly at baseline handler.assert_allclose( funcs["DVCon1_trivolume_constraint_1"], 1.0, name="scaled_volume_base", rtol=1e-7, atol=1e-7 ) # BWB volume computed with meshmixer handler.assert_allclose( funcs["unscaled_vol_con"], 1103.57, name="unscaled_volume_base", rtol=1e-7, atol=1e-7 ) def test_curvature(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_curvature.ref") with BaseRegTest(refFile, train=train) as handler: # Use the RAE 2822 wing because we have a PLOT3D surface file for it DVGeo, DVCon = self.generate_dvgeo_dvcon("rae2822", addToDVGeo=True) surfFile = os.path.join(self.base_path, "../../input_files/deform_geometry_wing.xyz") # Add both scaled and unscaled curvature constraints DVCon.addCurvatureConstraint(surfFile, curvatureType="mean") DVCon.addCurvatureConstraint(surfFile, curvatureType="mean", scaled=False, name="unscaled_curvature_con") funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler, fdstep=1e-5) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) def test_curvature1D(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_curvature1D.ref") with BaseRegTest(refFile, train=train) as handler: # Use the RAE 2822 wing because we have a PLOT3D surface file for it DVGeo, DVCon = self.generate_dvgeo_dvcon("c172", addToDVGeo=True) # Add both scaled and unscaled curvature constraints startP = [0.1, 0, 1.0] endP = [1.5, 0, 1.0] axis = [0, 1, 0] nPts = 10 DVCon.addCurvatureConstraint1D(startP, endP, nPts, axis, "mean") DVCon.addCurvatureConstraint1D( startP, endP, nPts, axis, "mean", scaled=False, name="unscaled_curvature_con" ) DVCon.addCurvatureConstraint1D(startP, endP, nPts, axis, "aggregated", KSCoeff=10.0) DVCon.addCurvatureConstraint1D( startP, endP, nPts, axis, "aggregated", KSCoeff=10.0, scaled=False, name="unscaled_curvature_con" ) funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler, checkDerivs=False) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) def test_LERadius(self, train=False, refDeriv=False): refFile = os.path.join(self.base_path, "ref/test_DVConstraints_LERadius.ref") with BaseRegTest(refFile, train=train) as handler: DVGeo, DVCon = self.generate_dvgeo_dvcon("c172") leList = [[1e-4, 0, 1e-3], [1e-3, 0, 2.5], [0.15, 0, 5.0]] # Add both scaled and unscaled LE radius constraints DVCon.addLERadiusConstraints(leList, 5, [0, 1, 0], [-1, 0, 0]) DVCon.addLERadiusConstraints(leList, 5, [0, 1, 0], [-1, 0, 0], scaled=False, name="unscaled_radius_con") funcs, funcsSens = generic_test_base(DVGeo, DVCon, handler) funcs, funcsSens = self.wing_test_twist(DVGeo, DVCon, handler) funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler)
nTwist_front = nRefAxPts_front - 1 # Create DVGeometry object for back wing FFDFile_back = 'ffd_back_wing.xyz' DVGeo_back = DVGeometry(FFDFile_back, child=True) # Create reference axis for the back wing nRefAxPts_back = DVGeo_back.addRefAxis('wing_back', xFraction=0.25, alignIndex='k') nTwist_back = nRefAxPts_back - 1 # Set up global DVGeometry object FFDFile_GLOBAL = 'ffd_global.xyz' DVGeo_GLOBAL = DVGeometry(FFDFile_GLOBAL) DVGeo_GLOBAL.addChild(DVGeo_front) DVGeo_GLOBAL.addChild(DVGeo_back) #rst dvgeos # Set up global design variables def twist_front(val, geo): for i in range(1, nRefAxPts_front): geo.rot_z['wing_front'].coef[i] = val[i - 1] def twist_back(val, geo): for i in range(1, nRefAxPts_back): geo.rot_z['wing_back'].coef[i] = val[i - 1]