def setup_cb(comm): # Create the solver CFDSolver = ADFLOW(options=options, comm=comm, debug=False) # Setup geometry/mesh DVGeo = DVGeometry(ffdFile) nTwist = 6 DVGeo.addRefAxis( 'wing', Curve(x=numpy.linspace(5.0 / 4.0, 1.5 / 4.0 + 7.5, nTwist), y=numpy.zeros(nTwist), z=numpy.linspace(0, 14, nTwist), k=2)) def twist(val, geo): for i in range(nTwist): geo.rot_z['wing'].coef[i] = val[i] DVGeo.addGeoDVGlobal('twist', [0] * nTwist, twist, lower=-10, upper=10, scale=1.0) DVGeo.addGeoDVLocal('shape', lower=-0.5, upper=0.5, axis='y', scale=10.0) mesh = USMesh(options=meshOptions, comm=comm) CFDSolver.setMesh(mesh) CFDSolver.setDVGeo(DVGeo) return CFDSolver, mesh, DVGeo, None
class TestAdjoint(reg_test_classes.RegTest): """ Tests that sensitives calculated from solving an adjoint are correct. and jacobian vector products are accurate. based on old regression tests 12, and 14 """ N_PROCS = 2 options = None ap = None ref_file = None def setUp(self): if not hasattr(self, "name"): # return immediately when the setup method is being called on the based class and NOT the # classes created using parametrized # this will happen when training, but will hopefully be fixed down the line return super().setUp() options = copy.copy(adflowDefOpts) options["outputdirectory"] = os.path.join(baseDir, options["outputdirectory"]) options.update(self.options) self.ffdFile = os.path.join(baseDir, "../../input_files/mdo_tutorial_ffd.fmt") mesh_options = copy.copy(IDWarpDefOpts) mesh_options.update({"gridFile": options["gridfile"]}) self.ap = copy.deepcopy(self.aero_prob) # Setup aeroproblem self.ap.evalFuncs = self.evalFuncs # add the default dvs to the problem for dv in defaultAeroDVs: self.ap.addDV(dv) self.CFDSolver = ADFLOW(options=options, debug=True) self.CFDSolver.setMesh(USMesh(options=mesh_options)) self.CFDSolver.setDVGeo(setDVGeo(self.ffdFile, cmplx=False)) # propagates the values from the restart file throughout the code self.CFDSolver.getResidual(self.ap) def test_residuals(self): utils.assert_residuals_allclose(self.handler, self.CFDSolver, self.ap, tol=1e-10) def test_adjoint(self): utils.assert_adjoint_sens_allclose(self.handler, self.CFDSolver, self.ap, tol=1e-10) self.assert_adjoint_failure()
# rst dvconLeTe (beg) # Le/Te constraints DVCon.addLeTeConstraints(0, "iLow") DVCon.addLeTeConstraints(0, "iHigh") if comm.rank == 0: # Only make one processor do this DVCon.writeTecplot(os.path.join(args.output, "constraints.dat")) # rst dvconLeTe (end) # ====================================================================== # Mesh Warping Set-up # ====================================================================== # rst warp (beg) meshOptions = {"gridFile": args.gridFile} mesh = USMesh(options=meshOptions, comm=comm) CFDSolver.setMesh(mesh) # rst warp (end) # ====================================================================== # Functions: # ====================================================================== # rst funcs (beg) def cruiseFuncs(x): if comm.rank == 0: print(x) # Set design vars DVGeo.setDesignVars(x) ap.setDesignVars(x) # Run CFD CFDSolver(ap)
class TestSolve(reg_test_classes.RegTest): """ Tests for time spectral case for an airfoil. """ N_PROCS = 2 ref_file = "solve_euler_time_spectral_naca64A010.json" def setUp(self): # Introduce a transfer class for displacement transfer from struct to aero. class Transfer: # simplified transfer class # converting csd displacement to cfd surface nodes def __init__(self, alpha, xRot, aeroSolver): # takes in displacement history self.alpha = alpha self.ntimeintervalsspectral = len(alpha) self.aeroSolver = aeroSolver # a shallow copy of CFD solver self.xRot = xRot def getUndeformedSurfaceNodes(self): self.MDGroup = self.aeroSolver.allWallsGroup self.cfdPts0 = self.aeroSolver.getSurfaceCoordinates(self.MDGroup, includeZipper=False) def setDisplacements(self): xRot = self.xRot ntimeintervalsspectral = self.ntimeintervalsspectral alpha = self.alpha # notice a shallow copy introduced here; dont change the underlying obj! cfdPoints_init = self.cfdPts0 # notice a shallow copy introduced here; dont change the underlying obj! N_pts = cfdPoints_init.shape[0] self.cfdPts = [] for sps in range(ntimeintervalsspectral): cfdPoints_deformed = numpy.zeros((N_pts, 3)) ptch_loc = alpha[sps] cc = numpy.cos(ptch_loc) ss = numpy.sin(ptch_loc) for j in range(N_pts): cfdPoints_deformed[j, 0] = cc * (cfdPoints_init[j, 0] - xRot) + ss * cfdPoints_init[j, 1] + xRot cfdPoints_deformed[j, 1] = -ss * (cfdPoints_init[j, 0] - xRot) + cc * cfdPoints_init[j, 1] cfdPoints_deformed[j, 2] = cfdPoints_init[j, 2] self.cfdPts.append(cfdPoints_deformed) def setVolumeMesh(self): ntimeintervalsspectral = self.ntimeintervalsspectral for sps in range(ntimeintervalsspectral): self.aeroSolver.mesh.setSurfaceCoordinates(self.cfdPts[sps]) self.aeroSolver.mesh.warpMesh() m = self.aeroSolver.mesh.getSolverGrid() self.aeroSolver.adflow.warping.setgridforoneinstance(m, sps=sps + 1) self.aeroSolver._updateGeomInfo = True self.aeroSolver.updateGeometryInfo() # Set up the test for the parent RegTest class. super().setUp() gridFile = os.path.join(baseDir, "../../input_files/naca64A010_euler-L2.cgns") ntimeintervalsspectral = 3 options = copy.copy(adflowDefOpts) options.update( { "gridfile": gridFile, "outputDirectory": os.path.join(baseDir, "../output_files"), "writeVolumeSolution": False, "writeSurfaceSolution": False, "blocksplitting": True, "useblockettes": False, "equationtype": "Euler", "equationmode": "time spectral", "mgcycle": "sg", "l2convergence": 1e-15, "ncycles": 200000, "monitorvariables": ["resrho", "cl"], "usenksolver": True, "nkswitchtol": 1e-4, "NKSubSpaceSize": 400, "applypcsubspacesize": 400, "useanksolver": True, "ankswitchtol": 1e-2, "anksubspacesize": 50, "alphafollowing": False, "timeintervals": ntimeintervalsspectral, "useexternaldynamicmesh": True, "usetsinterpolatedgridvelocity": True, } ) # Grid option meshOptions = { "gridFile": gridFile, } # Setup aeroproblem self.ap = copy.copy(ap_naca64A010_time_spectral) # Motion history alpha_0 = 1.01 deltaAlpha = -alpha_0 * numpy.pi / 180.0 alpha = numpy.linspace(0.0, 2.0 * numpy.pi, ntimeintervalsspectral + 1)[:-1] alpha = -numpy.sin(alpha) alpha *= deltaAlpha # Create the solver self.CFDSolver = ADFLOW(options=options, debug=False) # self.CFDSolver.addSlices("z", [0.5]) # Deform the mesh mesh = USMesh(options=meshOptions) self.CFDSolver.setMesh(mesh) # deformation xRot = 0.25 # Hard copied from the reference file. TSTransfer = Transfer(alpha, xRot, self.CFDSolver) TSTransfer.getUndeformedSurfaceNodes() TSTransfer.setDisplacements() TSTransfer.setVolumeMesh() def test_solve(self): # do the solve self.CFDSolver(self.ap) # check if the solution failed self.assert_solution_failure() # check its accuracy utils.assert_functions_allclose(self.handler, self.CFDSolver, self.ap, tol=1e-8)
class PlateComponent(om.ExplicitComponent): """Deterministic Bump Flow Problem""" def initialize(self): # Need to modify this dictionary when we change the SA constants sys.stdout = open(os.devnull, "w") self.aoptions = aeroOptions self.woptions = warpOptions self.ooptions = optOptions # Generate FFD and DVs self.DVGeo = pf.createFFD() # starting flat mesh meshname = self.aoptions['gridFile'] gridFile = meshname # flow characteristics alpha = 0.0 mach = self.ooptions['mach']#0.95 Re = self.ooptions['Re']#50000 Re_L = 1.0 temp = 540 arearef = 2.0 chordref = 1.0 # Spalart Allmaras model constants, to be changed in UQ saconstsm = [0.41, 0.1355, 0.622, 0.66666666667, 7.1, 0.3, 2.0] self.saconsts = saconstsm + [1.0, 2.0, 1.2, 0.5, 2.0] self.aoptions['SAConsts'] = self.saconsts #self.gridSol = f'{meshname}_{saconstsm}_sol' solname = self.ooptions['prob_name'] self.gridSol = f'{solname}_sol' # Aerodynamic problem description self.ap = AeroProblem(name=self.gridSol, alpha=alpha, mach=mach, reynolds=Re, reynoldsLength=Re_L, T=temp, areaRef=arearef, chordRef=chordref, evalFuncs=['cd']) # Create solver self.CFDSolver = ADFLOW(options=self.aoptions, comm=MPI.COMM_WORLD) self.CFDSolver.setDVGeo(self.DVGeo) # Set up mesh warping self.mesh = USMesh(options=self.woptions, comm=MPI.COMM_WORLD) self.CFDSolver.setMesh(self.mesh) # Try setting the DVGeo coordinates here coords = self.CFDSolver.getSurfaceCoordinates(groupName=self.CFDSolver.allWallsGroup) self.CFDSolver.DVGeo.addPointSet(coords, 'coords') self.CFDSolver.DVGeo.getFlattenedChildren()[1].writePlot3d("ffdp_opt_def.xyz") # Set constraints self.DVCon = DVConstraints() self.DVCon2 = DVConstraints() self.DVCon.setDVGeo(self.CFDSolver.DVGeo.getFlattenedChildren()[1]) self.DVCon2.setDVGeo(self.CFDSolver.DVGeo) self.DVCon.setSurface(self.CFDSolver.getTriangulatedMeshSurface(groupName='allSurfaces')) # set extra group for surface area condition self.DVCon2.setSurface(self.CFDSolver.getTriangulatedMeshSurface(), name='wall') # DV should be same into page (not doing anything right now) #import pdb; pdb.set_trace() lIndex = self.CFDSolver.DVGeo.getFlattenedChildren()[1].getLocalIndex(0) indSetA = [] indSetB = [] nXc = optOptions['NX'] self.NC = math.trunc(((1.0 - self.ooptions['DVFraction'])*self.ooptions['NX'])) ind = [int(nXc/2) - int(self.NC/2), int(nXc/2) + int(self.NC/2)] for i in range(ind[0], ind[1]): indSetA.append(lIndex[i, 0, 1]) indSetB.append(lIndex[i, 1, 1]) # for i in range(lIndex.shape[0]): # indSetA.append(lIndex[i, 0, 1]) # indSetB.append(lIndex[i, 1, 1]) self.DVCon.addLinearConstraintsShape(indSetA, indSetB, factorA=1.0, factorB=-1.0, lower=0, upper=0, name='eqs') # Thickness constraints (one for each active DV) #import pdb; pdb.set_trace() # Maximum thickness of the domain, translates to minimum thickness of bump ub = 1.0 - self.ooptions['DCMinThick'] tcf = self.ooptions['DCThickFrac'] ra = self.ooptions['bumpBounds'] lim = self.ooptions['DCMinArea'] span = numpy.linspace(0, 1, nXc) xc = span * (ra[1] - ra[0]) + ra[0] #ind = range(int(nXc/2) - int(self.NC/2), int(nXc/2) + int(self.NC/2))) ind = [int(nXc/2) - int(tcf*self.NC/2), int(nXc/2) + int(tcf*self.NC/2)] ptList = numpy.zeros([2, 3]) ptList[:,0] = xc[ind] ptList[:,1] = 0.5 ptList[:,2] = 0.5 if self.ooptions['use_area_con']: self.DVCon2.addSurfaceAreaConstraint(lower=lim, upper=10., name='sas', surfaceName='wall') else: self.DVCon2.addThicknessConstraints1D(ptList, self.NC, [0,0,1], lower=0.5, upper=ub, name='tcs') sys.stdout = sys.__stdout__ def setup(self): #initialize shape and set deformation points as inputs a_init = self.CFDSolver.DVGeo.getValues() a_init['pnts'][:] = self.ooptions['DVInit'] # mult = numpy.linspace(1.0,1.5,num=int(0.5*len(a_init['pnts']))) # mult = numpy.concatenate((mult, mult)) # a_init['pnts'] = numpy.multiply(mult, a_init['pnts']) #if self.ooptions['run_once']: # a_init['pnts'] = self.ooptions['ro_shape'] self.add_input('a', a_init['pnts'], desc="Bump Shape Control Points") #self.add_input('a', 0.2, desc="Bump Shape Control Points") if self.ooptions['use_area_con']: self.add_output('SA', 1.0, desc='Surface Area Constraint') else: self.add_output('TC', numpy.zeros(self.NC), desc='Thickness Constraints') self.add_output('Cd', 0.0, desc="Drag Coefficient") self.add_output('EQ', numpy.zeros(int(len(a_init['pnts'])/2)), desc="Control Point Symmetry") def setup_partials(self): self.declare_partials('Cd','a', method='exact') if self.ooptions['use_area_con']: self.declare_partials('SA','a', method='exact') else: self.declare_partials('TC','a', method='exact') self.declare_partials('EQ','a', method='exact') def compute(self, inputs, outputs): # run the bump shape model # move the mesh #import pdb; pdb.set_trace() dvdict = {'pnts':inputs['a']} self.CFDSolver.DVGeo.setDesignVars(dvdict) self.ap.setDesignVars(dvdict) #self.CFDSolver.DVGeo.update("coords") # Solve and evaluate functions funcs = {} self.CFDSolver(self.ap) self.DVCon.evalFunctions(funcs, includeLinear=True) self.DVCon2.evalFunctions(funcs, includeLinear=True) self.CFDSolver.evalFunctions(self.ap, funcs) str = self.gridSol + '_cd' outputs['Cd'] = funcs[str] if self.ooptions['use_area_con']: outputs['SA'] = funcs['sas'] else: outputs['TC'] = funcs['tcs'] outputs['EQ'] = funcs['eqs'] #outputs['Cd'] = inputs['a']*inputs['a'] def compute_partials(self, inputs, J): # move the mesh #import pdb; pdb.set_trace() dvdict = {'pnts':inputs['a']} self.CFDSolver.DVGeo.setDesignVars(dvdict) self.ap.setDesignVars(dvdict) #self.CFDSolver.DVGeo.update("coords") funcSens = {} #self.CFDSolver(self.ap) #ASSUME WE ALREADY COMPUTED THE SOLUTION self.DVCon.evalFunctionsSens(funcSens, includeLinear=True) self.DVCon2.evalFunctionsSens(funcSens, includeLinear=True) self.CFDSolver.evalFunctionsSens(self.ap, funcSens, ['cd']) str = self.gridSol + '_cd' J['Cd','a'] = funcSens[str]['pnts'] if self.ooptions['use_area_con']: J['SA','a'] = funcSens['sas']['pnts'] else: J['TC','a'] = funcSens['tcs']['pnts'] J['EQ','a'] = funcSens['eqs']['pnts']