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)
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)
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)
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)
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)
reg_write(funcsSens['mdo_tutorial_cl']['shape'][0][13], 1e-10,1e-10) reg_write(funcsSens['mdo_tutorial_cmz']['shape'][0][13], 1e-10,1e-10) reg_write(funcsSens['mdo_tutorial_drag']['shape'][0][13], 1e-10,1e-10) else: # For the complex....we just do successive perturbation for ii in range(3): xRef = {'twist':[0.0, 0.0], 'span':[0.0], 'shape':numpy.zeros(72, dtype='D')} if ii == 0: xRef['twist'][0] += h*1j elif ii == 1: xRef['span'][0] += h*1j else: xRef['shape'][13] += h*1j CFDSolver.resetFlow(ap) DVGeo.setDesignVars(xRef) CFDSolver(ap, writeSolution=False) funcs = {} CFDSolver.evalFunctions(ap, funcs) if MPI.COMM_WORLD.rank == 0: if ii == 0: for key in ['cl','cmz','drag']: print('funcs[%s]:'%key) reg_write(numpy.real(funcs['mdo_tutorial_%s'%key]),1e-10,1e-10) if ii == 0: print('Twist[0] Derivatives:') elif ii == 1: print('Span Derivatives:') elif ii == 2:
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)
#rst Add local dvs # Comment out one or the other DVGeo.addGeoDVLocal('local', lower=-0.5, upper=0.5, axis='y', scale=1) DVGeo.addGeoDVSectionLocal('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') #rst Change dvs dvDict = DVGeo.getValues() dvDict['twist'] = numpy.linspace(0, 50, nRefAxPts)[1:] dvDict['dihedral'] = numpy.linspace(0, 3, nRefAxPts)[1:] dvDict['taper'] = numpy.array([1.2, 0.5]) dvDict['slocal'][::5] = 0.5 DVGeo.setDesignVars(dvDict) #rst Update DVGeo.update('coords') DVGeo.writePlot3d('ffd_deformed.xyz') DVGeo.writePointSet('coords', 'surf')
# Case 1: Rear Ramp angle, fixed length # Case 2: Upper and lower ramp angles, fixed length # Case 3: Nose length ( Do with global FFD) # Case 4: Overall length ( Do with global FFD) # Case 5: Shape # xDV['length'][2] = 1.75#2.0#1.05 # xDV['angleVars'][2] = 0.15 # xDV['angleVars'][0] = 0.19 # xDV['noseLen'][0] = -0.1 # xDV['angleVars'][1] = 0.18 # xDV['angleVars'][2] = 0.18 # xDV['angleVars'][3] = 0.12 DVGeo.setDesignVars(xDV) mesh.setSurfaceCoordinates(DVGeo.update(ptSetName)) mesh.warpMesh() DVGeo.writeTecplot("warpedFFD.dat") # mesh.writeOFGridTecplot('warped.dat') mesh.writeGrid() # # Repeat ================ # #xDV['length'][2] = 1.25#2.0#1.05 # xDV['angleVars'][2] = 0.3 # DVGeo.setDesignVars(xDV) # #coords = DVGeo.update(ptSetName) # # for i in range(coords0.shape[0]): # # if coords0[i,1]==0: # # print 'x',coords[i,:]
# 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)
const_offset = 0.3 * np.ones(10) local_perturb = np.cos(np.linspace(0, 4 * np.pi, 10)) / 10 + np.linspace( -0.05, 0.05, 10) newDV[idx] = const_offset + local_perturb # add a constant offset (downward) to the upper points, plus a linear ramp and a trigonometric local change # this will shrink the cylinder height-wise and make it wavy for idx in [upper_front_idx, upper_rear_idx]: const_offset = -0.3 * np.ones(10) local_perturb = np.sin(np.linspace(0, 4 * np.pi, 10)) / 20 + np.linspace( 0.05, -0.10, 10) newDV[idx] = const_offset + local_perturb # we've created an array with design variable perturbations. Now set the FFD control points with them # and update the point sets so we can see how they changed DVGeo.setDesignVars({"shape": newDV.copy()}) Xmod = DVGeo.update("cylinder") FFDmod = DVGeo.update("ffd") # Create tecplot output that contains the FFD control points, embedded volume, and pointset DVGeo.writeTecplot(fileName="deformed_embedded.dat", solutionTime=1) # rst plot # cast the 3D pointsets to 2D for plotting (ignoring depth) FFDplt = FFDptset[:, :2] FFDmodplt = FFDmod[:, :2] Xptplt = Xpt[:, :2] Xmodplt = Xmod[:, :2] # plot the new and deformed pointsets and control points
# Set the chord as well geo.scale['wing'].coef[-1] = val[3] coords = hyp.getSurfaceCoordinates() DVGeo = DVGeometry(ffd_file) 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 = pySpline.Curve(X=ref, k=2) DVGeo.addRefAxis('wing', c0) DVGeo.addGeoDVGlobal('winglet', [0, 0, 0, 1], winglet, lower=-5, upper=5) DVGeo.addPointSet(coords, 'coords') DVGeo.setDesignVars({'winglet': [1.5, 2.5, -2.0, .60]}) hyp.setSurfaceCoordinates(DVGeo.update('coords')) # Run and write grid hyp.run() hyp.writeCGNS('717.cgns')
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)
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)
def test6(): # **************************************************************************** printHeader('MDO tutorial RANS Geometric Variables') # **************************************************************************** aeroOptions = copy.deepcopy(defOpts) # Now set the options that need to be overwritten for this example: aeroOptions.update( {'gridfile': '../inputFiles/mdo_tutorial_rans.cgns', 'mgcycle':'2w', 'equationtype':'RANS', 'smoother':'dadi', 'nsubiterturb':3, 'nsubiter':3, 'cfl':1.5, 'cflcoarse':1.25, 'ncyclescoarse':250, 'ncycles':750, 'monitorvariables':['resrho','resturb','cl','cd','cmz','yplus','totalr'], 'usenksolver':True, 'l2convergence':1e-17, 'l2convergencecoarse':1e-2, 'nkswitchtol':1e-4, 'adjointl2convergence': 1e-16, 'nkls': 'non monotone', 'frozenturbulence':False, 'nkjacobianlag':2, } ) # Setup aeroproblem, cfdsolver ap = AeroProblem(name='mdo_tutorial', alpha=1.8, mach=0.80, altitude=10000.0, areaRef=45.5, chordRef=3.25, evalFuncs=['cl','cmz','drag']) ap.addDV('alpha') ap.addDV('mach') 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 xrange(nTwist): geo.rot_z['wing'].coef[i] = val[i] def span(val, geo): # Span C = geo.extractCoef('wing') s = geo.extractS('wing') for i in xrange(len(C)-1): C[-1, 2] = C[-1, 2] + val[0] geo.restoreCoef(C, 'wing') DVGeo.addGeoDVGlobal('twist', [0]*nTwist, twist, lower=-10, upper=10, scale=1.0) DVGeo.addGeoDVGlobal('span', [0], span, lower=-10, upper=10, scale=1.0) DVGeo.addGeoDVLocal('shape', lower=-0.5, upper=0.5, axis='y', scale=10.0) mesh = MBMesh(options={'gridFile':'../inputFiles/mdo_tutorial_rans.cgns'}) CFDSolver.setMesh(mesh) CFDSolver.setDVGeo(DVGeo) #Aeroproblem must be set before we can call DVGeo.setDesignVars CFDSolver.setAeroProblem(ap) if not 'complex' in sys.argv: # Solve system CFDSolver(ap, writeSolution=False) funcs = {} CFDSolver.evalFunctions(ap, funcs) # Solve sensitivities funcsSens = {} CFDSolver.evalFunctionsSens(ap, funcsSens) # Write values and derivatives out: if MPI.COMM_WORLD.rank == 0: for key in ['cl','cmz','drag']: print 'funcs[%s]:'%key reg_write(funcs['mdo_tutorial_%s'%key],1e-10,1e-10) # Now write the derivatives in the same order the CS will do them: print ('Twist[0] Derivatives:') reg_write(funcsSens['mdo_tutorial_cl']['twist'][0][0], 1e-10,1e-10) reg_write(funcsSens['mdo_tutorial_cmz']['twist'][0][0], 1e-10,1e-10) reg_write(funcsSens['mdo_tutorial_drag']['twist'][0][0], 1e-10,1e-10) print ('Span Derivatives:') reg_write(funcsSens['mdo_tutorial_cl']['span'][0], 1e-10,1e-10) reg_write(funcsSens['mdo_tutorial_cmz']['span'][0], 1e-10,1e-10) reg_write(funcsSens['mdo_tutorial_drag']['span'][0], 1e-10,1e-10) print ('shape[13] Derivatives:') reg_write(funcsSens['mdo_tutorial_cl']['shape'][0][13], 1e-10,1e-10) reg_write(funcsSens['mdo_tutorial_cmz']['shape'][0][13], 1e-10,1e-10) reg_write(funcsSens['mdo_tutorial_drag']['shape'][0][13], 1e-10,1e-10) print ('mach Derivatives:') reg_write(funcsSens['mdo_tutorial_cl']['mach_mdo_tutorial'], 1e-10,1e-10) reg_write(funcsSens['mdo_tutorial_cmz']['mach_mdo_tutorial'], 1e-10,1e-10) reg_write(funcsSens['mdo_tutorial_drag']['mach_mdo_tutorial'], 1e-10,1e-10) else: # For the complex....we just do successive perturbation for ii in range(4): xRef = {'twist':[0.0, 0.0], 'span':[0.0], 'shape':numpy.zeros(72, dtype='D'), 'mach_mdo_tutorial':0.8} if ii == 0: xRef['twist'][0] += h*1j elif ii == 1: xRef['span'][0] += h*1j elif ii == 2: xRef['shape'][13] += h*1j else: xRef['mach_mdo_tutorial']+=h*1j ap.setDesignVars(xRef) CFDSolver.resetFlow(ap) DVGeo.setDesignVars(xRef) CFDSolver(ap, writeSolution=False) funcs = {} CFDSolver.evalFunctions(ap, funcs) if MPI.COMM_WORLD.rank == 0: if ii == 0: for key in ['cl','cmz','drag']: print 'funcs[%s]:'%key reg_write(numpy.real(funcs['mdo_tutorial_%s'%key]),1e-10,1e-10) if ii == 0: print ('Twist[0] Derivatives:') elif ii == 1: print ('Span Derivatives:') elif ii == 2: print ('shape[13] Derivatives:') elif ii == 3: print ('mach Derivatives:') for key in ['cl','cmz','drag']: deriv = numpy.imag(funcs['mdo_tutorial_%s'%key])/h reg_write(deriv,1e-10,1e-10) del CFDSolver del mesh