Line data Source code
1 : //* This file is part of the MOOSE framework 2 : //* https://mooseframework.inl.gov 3 : //* 4 : //* All rights reserved, see COPYRIGHT for full restrictions 5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT 6 : //* 7 : //* Licensed under LGPL 2.1, please see LICENSE for details 8 : //* https://www.gnu.org/licenses/lgpl-2.1.html 9 : 10 : // MOOSE includes 11 : #include "TransientAndAdjoint.h" 12 : #include "OptimizationAppTypes.h" 13 : #include "FEProblemBase.h" 14 : 15 : registerMooseObject("OptimizationApp", TransientAndAdjoint); 16 : 17 : InputParameters 18 244 : TransientAndAdjoint::validParams() 19 : { 20 244 : InputParameters params = Transient::validParams(); 21 244 : params += AdjointTransientSolve::validParams(); 22 244 : params.addClassDescription("Executioner for evaluating transient simulations and their adjoint."); 23 : 24 : // We need to full matrix for the adjoint solve, so set this to NEWTON 25 488 : params.set<MooseEnum>("solve_type") = "newton"; 26 244 : params.suppressParameter<MooseEnum>("solve_type"); 27 : 28 : // The adjoint system (second one) is solved by _adjoint_solve 29 : // This is a parameter of the MultiSystemSolveObject, which we set from here, the executioner. 30 : // We seek to prevent the MultiSystemSolveObject from solving both systems 31 : // This is abusing input parameters, but SolveObjects do not have their own syntax 32 : // and we need to send this parameter from the executioner to the default nested SolveObject 33 488 : params.renameParam("system_names", "forward_system", ""); 34 : 35 244 : return params; 36 0 : } 37 : 38 122 : TransientAndAdjoint::TransientAndAdjoint(const InputParameters & parameters) 39 : : Transient(parameters), 40 122 : _adjoint_solve(*this), 41 122 : _forward_times(declareRecoverableData<std::vector<Real>>("forward_times")) 42 : { 43 : // Error out on unsupported time integration schemes 44 122 : switch (getTimeScheme()) 45 : { 46 : case Moose::TI_IMPLICIT_EULER: 47 : break; 48 0 : default: 49 0 : paramError( 50 : "scheme", getParam<MooseEnum>("scheme"), " is not supported for computing adjoint."); 51 : break; 52 : } 53 122 : } 54 : 55 : void 56 563 : TransientAndAdjoint::preExecute() 57 : { 58 563 : Transient::preExecute(); 59 : 60 : // Save the forward initial condition 61 563 : _adjoint_solve.insertForwardSolution(_t_step); 62 : 63 : // Save the time of the initial condition 64 : // The vector of times should be reset unless we are recovering 65 563 : if (!_app.isRecovering()) 66 538 : _forward_times = {_time}; 67 : else 68 25 : _forward_times.push_back(_time); 69 563 : } 70 : 71 : void 72 5147 : TransientAndAdjoint::postStep() 73 : { 74 5147 : Transient::postStep(); 75 : 76 : // Save the converged forward solution and time 77 5147 : if (lastSolveConverged()) 78 : { 79 5142 : _adjoint_solve.insertForwardSolution(_t_step); 80 5142 : _forward_times.push_back(_time); 81 : } 82 5147 : } 83 : 84 : void 85 563 : TransientAndAdjoint::postExecute() 86 : { 87 563 : Transient::postExecute(); 88 : 89 : // If it is a half transient, then the app is meant to be run with recovery. Therefore, it doesn't 90 : // make sense to run the adjoint calculation since we aren't getting to the final time required 91 : // for a consistent adjoint. 92 563 : if (_app.testCheckpointHalfTransient()) 93 : return; 94 : 95 : // Looping backward through forward time steps 96 5680 : for (const auto n : make_range(_forward_times.size() - 1)) 97 : { 98 : // Set important time information so the Jacobian is properly computed in the forward system 99 5142 : _t_step = _forward_times.size() - 1 - n; 100 5142 : _time = _forward_times[_t_step]; 101 5142 : _time_old = _forward_times[_t_step - 1]; 102 5142 : _dt = _time - _time_old; 103 5142 : _dt_old = _t_step < 2 ? _dt : _time_old - _forward_times[_t_step - 2]; 104 : 105 : // Set the forward solution to the time step that is currently being solved 106 5142 : _adjoint_solve.setForwardSolution(_t_step); 107 : 108 : // Incase there are some residual objects that need this call 109 5142 : _problem.timestepSetup(); 110 5142 : _problem.onTimestepBegin(); 111 : 112 : // Solve the adjoint system 113 5142 : _last_solve_converged = _adjoint_solve.solve(); 114 5142 : if (!lastSolveConverged()) 115 : break; 116 : 117 : // FIXME: This works well enough for console and CSV output, but exodus is a mess since I don't 118 : // think it knows what to do with backward timestepping or duplicate outputs at a given time 119 10284 : _problem.outputStep(OptimizationAppTypes::EXEC_ADJOINT_TIMESTEP_END); 120 : } 121 : }