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()
class TestJacVecFwd(reg_test_classes.RegTest): """ Tests that given a flow state the FWD jacobian vector products are agree the privous values recorded in the ref file. """ N_PROCS = 2 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 testing, 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) # Create the solver self.CFDSolver = ADFLOW(options=copy.deepcopy(options), debug=True) self.ap = copy.deepcopy(self.aero_prob) # add the default dvs to the problem for dv in defaultAeroDVs: self.ap.addDV(dv) # propagates the values from the restart file throughout the code self.CFDSolver.getResidual(self.ap) # ------------------- Derivative routine checks ---------------------------- def test_wDot(self): utils.assert_fwd_mode_wdot_allclose(self.handler, self.CFDSolver, self.ap, seed=314, tol=5e-9) def test_xVDot(self): utils.assert_fwd_mode_xVDot_allclose(self.handler, self.CFDSolver, self.ap, seed=314, tol=1e-10) def test_xDvDot(self): utils.assert_fwd_mode_xDvDot_allclose(self.handler, self.CFDSolver, self.ap, seed=1.0, tol=1e-10)
def test_import(self): CFDSolver = ADFLOW(options=self.options, debug=False) res = CFDSolver.getResidual(ap_tutorial_wing) res_norm = np.linalg.norm(res) np.testing.assert_allclose(res_norm, 0.0, atol=1e-11, err_msg="residual")
def test_import_block_splitting(self): self.options["partitionLikeNProc"] = 50 CFDSolver = ADFLOW(options=self.options, debug=False) res = CFDSolver.getResidual(ap_tutorial_wing) res_norm = np.linalg.norm(res) np.testing.assert_allclose(res_norm, 0.0, atol=1e-11, err_msg="residual")
class TestSolveOverset(reg_test_classes.RegTest): """ Tests that ADflow can converge the wing from the mdo tutorial using the euler equation to the required accuracy as meassure by the norm of the residuals, and states, and the accuracy of the functions based on the old regression test 17 and 18 """ N_PROCS = 2 options = { "gridfile": os.path.join(baseDir, "../../input_files/conic_conv_nozzle.cgns"), "outputdirectory": os.path.join(baseDir, "../output_files"), # Physics Parameters "equationType": "Euler", "smoother": "DADI", "nsubiter": 3, "CFL": 4.0, "CFLCoarse": 1.25, "MGCycle": "sg", "MGStartLevel": -1, "nCyclesCoarse": 250, "nCycles": 1000, "monitorvariables": ["cpu", "resrho", "cl", "cd"], "volumevariables": ["blank"], "surfacevariables": ["mach", "cp", "vx", "vy", "vz", "blank"], "useNKSolver": True, "nkswitchtol": 0.01, "nkadpc": True, "nkjacobianlag": 5, "nkouterpreconits": 3, "nkinnerpreconits": 2, # Convergence Parameters "L2Convergence": 1e-10, "L2ConvergenceCoarse": 1e-4, "adjointl2convergence": 1e-6, "forcesAsTractions": True, "debugzipper": True, "nearwalldist": 0.001, # 'nkls':'none', "solutionprecision": "double", "adjointsubspacesize": 200, "outerpreconits": 3, "zipperSurfaceFamily": "output_fam", "flowtype": "internal", "blocksplitting": True, } ap = copy.copy(ap_conic_conv_nozzle) ref_file = "solve_conic_overset.json" def setUp(self): super().setUp() options = copy.copy(adflowDefOpts) options.update(self.options) # Setup aeroproblem self.ap.setBCVar("Pressure", 79326.7, "downstream") self.ap.addDV("Pressure", family="downstream") self.ap.setBCVar("PressureStagnation", 100000.0, "upstream") self.ap.addDV("PressureStagnation", family="upstream") self.ap.setBCVar("TemperatureStagnation", 500.0, "upstream") self.ap.addDV("TemperatureStagnation", family="upstream") # Create the solver self.CFDSolver = ADFLOW(options=options, debug=False) self.CFDSolver.addFamilyGroup("upstream", ["inlet"]) self.CFDSolver.addFamilyGroup("downstream", ["outlet"]) self.CFDSolver.addFamilyGroup("all_flow", ["inlet", "outlet"]) self.CFDSolver.addFamilyGroup("output_fam", ["all_flow", "allWalls"]) self.CFDSolver.addFunction("mdot", "upstream", name="mdot_up") self.CFDSolver.addFunction("mdot", "downstream", name="mdot_down") self.CFDSolver.addFunction("mavgptot", "downstream", name="mavgptot_down") self.CFDSolver.addFunction("mavgptot", "upstream", name="mavgptot_up") self.CFDSolver.addFunction("aavgptot", "downstream", name="aavgptot_down") self.CFDSolver.addFunction("aavgptot", "upstream", name="aavgptot_up") self.CFDSolver.addFunction("mavgttot", "downstream", name="mavgttot_down") self.CFDSolver.addFunction("mavgttot", "upstream", name="mavgttot_up") self.CFDSolver.addFunction("mavgps", "downstream", name="mavgps_down") self.CFDSolver.addFunction("mavgps", "upstream", name="mavgps_up") self.CFDSolver.addFunction("aavgps", "downstream", name="aavgps_down") self.CFDSolver.addFunction("aavgps", "upstream", name="aavgps_up") def test_solve(self): # do the solve self.CFDSolver(self.ap) # check its accuracy utils.assert_functions_allclose(self.handler, self.CFDSolver, self.ap, tol=1e-9) utils.assert_states_allclose(self.handler, self.CFDSolver, tol=1e-10) # Check the residual res = self.CFDSolver.getResidual(self.ap) totalR0 = self.CFDSolver.getFreeStreamResidual(self.ap) res /= totalR0 reducedSum = self.CFDSolver.comm.reduce(np.sum(res**2)) if self.CFDSolver.comm.rank == 0: self.assertLessEqual(np.sqrt(reducedSum), self.options["L2Convergence"])
class TestFunctionals(reg_test_classes.RegTest): """ Tests that given a flow state the residuals, function, forces/tractions, and jacobian vector products are accurate. """ N_PROCS = 2 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 testing, 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) # Create the solver self.CFDSolver = ADFLOW(options=copy.deepcopy(options), debug=True) self.ap = copy.deepcopy(self.aero_prob) # add the default dvs to the problem for dv in defaultAeroDVs: self.ap.addDV(dv) # propagates the values from the restart file throughout the code self.CFDSolver.getResidual(self.ap) def test_restart_read(self): utils.assert_problem_size_equal(self.handler, self.CFDSolver, tol=1e-10) utils.assert_states_allclose(self.handler, self.CFDSolver, tol=1e-10) def test_residuals(self): utils.assert_residuals_allclose(self.handler, self.CFDSolver, self.ap, tol=1e-10) def test_functions(self): utils.assert_functions_allclose(self.handler, self.CFDSolver, self.ap, tol=1e-9) def test_forces_and_tractions(self): utils.assert_forces_allclose(self.handler, self.CFDSolver, tol=1e-10) utils.assert_tractions_allclose(self.handler, self.CFDSolver, tol=1e-10) # Reset the option self.CFDSolver.setOption("forcesAsTractions", True) # Make sure we can write the force file. forces_file = os.path.join(self.CFDSolver.getOption("outputdirectory"), "forces.txt") self.CFDSolver.writeForceFile(forces_file) # ------------------- Derivative routine checks ---------------------------- def test_jac_vec_prod_fwd(self): utils.assert_fwd_mode_allclose(self.handler, self.CFDSolver, self.ap, tol=5e-9) def test_jac_vec_prod_bwd(self): utils.assert_bwd_mode_allclose(self.handler, self.CFDSolver, self.ap, tol=1e-10) def test_dot_products(self): utils.assert_dot_products_allclose(self.handler, self.CFDSolver, tol=1e-10)
class TestJacVecBWDFast(reg_test_classes.RegTest): """ Tests that given a flow state the state jacobian vector products are accurate. """ N_PROCS = 2 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 testing, 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) # Create the solver self.CFDSolver = ADFLOW(options=copy.deepcopy(options), debug=True) self.ap = copy.deepcopy(self.aero_prob) # add the default dvs to the problem for dv in defaultAeroDVs: self.ap.addDV(dv) # propagates the values from the restart file throughout the code self.CFDSolver.getResidual(self.ap) # ------------------- Derivative routine checks ---------------------------- def test_BWD(self): # dwBar = self.CFDSolver.getStatePerturbation(314) wBar = self.CFDSolver.computeJacobianVectorProductBwd( resBar=dwBar, wDeriv=True, ) wBarfast = self.CFDSolver.computeJacobianVectorProductBwdFast( resBar=dwBar) np.testing.assert_allclose(wBar, wBarfast, atol=1e-16, err_msg="w wrt res") def test_repeated_calls(self): dwBar = self.CFDSolver.getStatePerturbation(314) wBarfast1 = self.CFDSolver.computeJacobianVectorProductBwdFast( resBar=dwBar) wBarfast2 = self.CFDSolver.computeJacobianVectorProductBwdFast( resBar=dwBar) np.testing.assert_allclose(wBarfast1, wBarfast2, atol=1e-16, err_msg="w wrt res double call")
class TestJacVecFwdFD(reg_test_classes.RegTest): """ Tests that given a flow state the FWD jacobian vector products are agree with FD. """ N_PROCS = 2 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 testing, 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) # Create the solver self.CFDSolver = ADFLOW(options=copy.deepcopy(options), debug=True) self.ap = copy.deepcopy(self.aero_prob) # add the default dvs to the problem for dv in defaultAeroDVs: self.ap.addDV(dv) # propagates the values from the restart file throughout the code self.CFDSolver.getResidual(self.ap) # ------------------- Derivative routine checks ---------------------------- def test_wDot(self): # perturb each input and check that the outputs match the FD to with in reason wDot = self.CFDSolver.getStatePerturbation(321) resDot, funcsDot, fDot = self.CFDSolver.computeJacobianVectorProductFwd( wDot=wDot, residualDeriv=True, funcDeriv=True, fDeriv=True) resDot_FD, funcsDot_FD, fDot_FD = self.CFDSolver.computeJacobianVectorProductFwd( wDot=wDot, residualDeriv=True, funcDeriv=True, fDeriv=True, mode="FD", h=1e-8) np.testing.assert_allclose(resDot_FD, resDot, rtol=8e-4, err_msg="residual") for func in funcsDot: np.testing.assert_allclose(funcsDot_FD[func], funcsDot[func], rtol=1e-5, err_msg=func) np.testing.assert_allclose(fDot_FD, fDot, rtol=5e-4, err_msg="forces") def test_xVDot(self): # perturb each input and check that the outputs match the FD to with in reason xVDot = self.CFDSolver.getSpatialPerturbation(314) resDot, funcsDot, fDot = self.CFDSolver.computeJacobianVectorProductFwd( xVDot=xVDot, residualDeriv=True, funcDeriv=True, fDeriv=True) resDot_FD, funcsDot_FD, fDot_FD = self.CFDSolver.computeJacobianVectorProductFwd( xVDot=xVDot, residualDeriv=True, funcDeriv=True, fDeriv=True, mode="FD", h=1e-8) idx_max = np.argmax((resDot_FD - resDot) / resDot) print(resDot[idx_max], resDot_FD[idx_max]) np.testing.assert_allclose(resDot_FD, resDot, atol=5e-4, err_msg="residual") for func in funcsDot: np.testing.assert_allclose(funcsDot_FD[func], funcsDot[func], rtol=5e-6, err_msg=func) np.testing.assert_allclose(fDot_FD, fDot, rtol=5e-4, err_msg="forces") def test_xDvDot(self): # perturb each input and check that the outputs match the FD to with in reason step_size = { "alpha": 1e-4, "beta": 1e-5, "mach": 1e-5, "P": 1e-1, "T": 1e-4, "xRef": 1e-5, "yRef": 1e-5, "zRef": 1e-5, } for aeroDV in self.ap.DVs.values(): key = aeroDV.key xDvDot = {key: 1.0} resDot, funcsDot, fDot = self.CFDSolver.computeJacobianVectorProductFwd( xDvDot=xDvDot, residualDeriv=True, funcDeriv=True, fDeriv=True) resDot_FD, funcsDot_FD, fDot_FD = self.CFDSolver.computeJacobianVectorProductFwd( xDvDot=xDvDot, residualDeriv=True, funcDeriv=True, fDeriv=True, mode="FD", h=step_size[key]) # the tolerances here are loose becuase different ouputs have different optimal steps np.testing.assert_allclose(resDot_FD, resDot, atol=5e-5, err_msg=f"residual wrt {key}") for func in funcsDot: if np.abs(funcsDot[func]) <= 1e-16: np.testing.assert_allclose(funcsDot_FD[func], funcsDot[func], atol=5e-5, err_msg=f"{func} wrt {key}") else: np.testing.assert_allclose(funcsDot_FD[func], funcsDot[func], rtol=1e-3, err_msg=f"{func} wrt {key}") np.testing.assert_allclose(fDot_FD, fDot, atol=5e-7, err_msg=f"forces wrt {key}")