https://mooseframework.inl.gov
Loading...
Searching...
No Matches
AdjointSolve.C
Go to the documentation of this file.
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#include "AdjointSolve.h"
12
13#include "FEProblem.h"
14#include "NonlinearSystemBase.h"
15#include "NonlinearSystem.h"
16#include "NodalBCBase.h"
17#include "Executioner.h"
18
19#include "libmesh/fuzzy_equals.h"
20#include "libmesh/petsc_matrix.h"
21#include "libmesh/petsc_vector.h"
22#include "petscmat.h"
23
24using namespace libMesh;
25
28{
30 params.addRequiredParam<std::vector<SolverSystemName>>(
31 "forward_system",
32 "Name of the nonlinear system representing the forward problem. Multiple and linear solver "
33 "systems are not currently supported.");
34 params.addRequiredParam<NonlinearSystemName>(
35 "adjoint_system", "Name of the system representing the adjoint problem.");
36 return params;
37}
38
40 : SolveObject(ex),
41 _forward_sys_num(
42 _problem.nlSysNum(getParam<std::vector<SolverSystemName>>("forward_system")[0])),
43 _adjoint_sys_num(_problem.nlSysNum(getParam<NonlinearSystemName>("adjoint_system"))),
44 _nl_forward(_problem.getNonlinearSystemBase(_forward_sys_num)),
45 _nl_adjoint(_problem.getNonlinearSystemBase(_adjoint_sys_num))
46{
47 // Disallow vectors of systems
48 if (getParam<std::vector<SolverSystemName>>("forward_system").size() != 1)
49 paramError("forward_system",
50 "Multiple nonlinear forward systems is not supported at the moment");
51
52 // These should never be hit, but just in case
53 if (!dynamic_cast<NonlinearSystem *>(&_nl_forward))
54 paramError("forward_system", "Forward system does not appear to be a 'NonlinearSystem'.");
55 if (!dynamic_cast<NonlinearSystem *>(&_nl_adjoint))
56 paramError("adjoint_system", "Adjoint system does not appear to be a 'NonlinearSystem'.");
57 // Adjoint system should never perform its own automatic scaling. Scaling factors from the forward
58 // system are applied.
60
61 // We need to force the forward system to have a scaling vector. This is
62 // in case a user provides scaling for an individual variables but doesn't have any
63 // AD objects.
65
66 // Set the solver options for the adjoint system
67 mooseAssert(_problem.numSolverSystems() > 1,
68 "We should have forward and adjoint systems as evidenced by our initialization list");
69 const auto prefix = _nl_adjoint.prefix();
72 // Set solver parameter prefix
73 auto & solver_params = _problem.solverParams(_nl_adjoint.number());
74 solver_params._prefix = prefix;
75 solver_params._solver_sys_num = _nl_adjoint.number();
76}
77
78bool
80{
81 TIME_SECTION("execute", 1, "Executing adjoint problem", false);
82
83 mooseAssert(!_inner_solve,
84 "I don't see any code path in which this class winds up with an inner solve");
85
86 // enforce PETSc options are passed to the adjoint solve as well, as set in the user file
87 auto & petsc_options = _problem.getPetscOptions();
88 auto & pars = _problem.solverParams(_nl_adjoint.number());
89 Moose::PetscSupport::petscSetOptions(petsc_options, pars);
90
92
94 {
95 _console << "MultiApps failed to converge on ADJOINT_TIMESTEP_BEGIN!" << std::endl;
96 return false;
97 }
98 // Output results between the forward and adjoint solve.
100
102
103 // Convenient references
104 // Adjoint matrix, solution, and right-hand-side
105 auto & matrix = static_cast<ImplicitSystem &>(_nl_forward.system()).get_system_matrix();
106 auto & solution = _nl_adjoint.solution();
108 // Linear solver parameters
109 auto & es = _problem.es();
110 const auto tol = es.parameters.get<Real>("linear solver tolerance");
111 const auto maxits = es.parameters.get<unsigned int>("linear solver maximum iterations");
112 // Linear solver for adjoint system
113 auto & solver = *static_cast<ImplicitSystem &>(_nl_adjoint.system()).get_linear_solver();
114
115 // Assemble adjoint system by evaluating the forward Jacobian, computing the adjoint
116 // residual/source, and homogenizing nodal BCs
117 assembleAdjointSystem(matrix, solution, rhs);
118 applyNodalBCs(matrix, solution, rhs);
119
120 // Solve the adjoint system
121 solver.adjoint_solve(matrix, solution, rhs, tol, maxits);
122
123 // For scaling of the forward problem we need to apply correction factor
124 solution *= _nl_forward.getVector("scaling_factors");
125
127 if (solver.get_converged_reason() < 0)
128 {
129 _console << "Adjoint solve failed to converge with reason: "
130 << Utility::enum_to_string(solver.get_converged_reason()) << std::endl;
131 return false;
132 }
133
136 {
137 _console << "MultiApps failed to converge on ADJOINT_TIMESTEP_END!" << std::endl;
138 return false;
139 }
140
141 return true;
142}
143
144void
157
158void
160 const NumericVector<Number> & solution,
162{
163 std::vector<dof_id_type> nbc_dofs;
164 auto & nbc_warehouse = _nl_forward.getNodalBCWarehouse();
165 if (nbc_warehouse.hasActiveObjects())
166 {
167 for (const auto & bnode : *_mesh.getBoundaryNodeRange())
168 {
169 BoundaryID boundary_id = bnode->_bnd_id;
170 Node * node = bnode->_node;
171
172 if (!nbc_warehouse.hasActiveBoundaryObjects(boundary_id) ||
173 node->processor_id() != processor_id())
174 continue;
175
176 for (const auto & bc : nbc_warehouse.getActiveBoundaryObjects(boundary_id))
177 if (bc->shouldApply())
178 for (unsigned int c = 0; c < bc->variable().count(); ++c)
179 nbc_dofs.push_back(node->dof_number(_forward_sys_num, bc->variable().number() + c, 0));
180 }
181
182 // Petsc has a nice interface for zeroing rows and columns, so we'll use it
183 auto petsc_matrix = dynamic_cast<PetscMatrix<Number> *>(&matrix);
184 auto petsc_solution = dynamic_cast<const PetscVector<Number> *>(&solution);
185 auto petsc_rhs = dynamic_cast<PetscVector<Number> *>(&rhs);
186 if (petsc_matrix && petsc_solution && petsc_rhs)
187 LibmeshPetscCall(MatZeroRowsColumns(petsc_matrix->mat(),
188 cast_int<PetscInt>(nbc_dofs.size()),
189 numeric_petsc_cast(nbc_dofs.data()),
190 1.0,
191 petsc_solution->vec(),
192 petsc_rhs->vec()));
193 else
194 mooseError("Using PETSc matrices and vectors is required for applying homogenized boundary "
195 "conditions.");
196 }
197}
198
199void
201{
202 const auto adj_vars = _nl_adjoint.getVariables(0);
203 for (const auto & adj_var : adj_vars)
204 // If the user supplies any scaling factors for individual variables the
205 // adjoint system won't be consistent.
206 if (!absolute_fuzzy_equals(adj_var->scalingFactor(), 1.0))
208 "User cannot supply scaling factors for adjoint variables. Adjoint system is scaled "
209 "automatically by the forward system.");
210
211 // This is to prevent automatic scaling of the adjoint system. Scaling is
212 // taken from the forward system
213 if (_nl_adjoint.hasVector("scaling_factors"))
214 _nl_adjoint.removeVector("scaling_factors");
215
216 // Main thing is that the number of dofs in each system is the same
219 "The forward and adjoint systems do not seem to be the same size. This could be due to (1) "
220 "the number of variables added to each system is not the same, (2) variables do not have "
221 "consistent family/order, (3) variables do not have the same block restriction.");
222}
boundary_id_type BoundaryID
const double tol
InputParameters emptyInputParameters()
void applyNodalBCs(SparseMatrix< Number > &matrix, const NumericVector< Number > &solution, NumericVector< Number > &rhs)
Helper function for applying nodal BCs to the adjoint matrix and RHS.
virtual bool solve() override
Solve the adjoint system with the following procedure:
const unsigned int _forward_sys_num
The number of the nonlinear system representing the forward model.
NonlinearSystemBase & _nl_forward
The nonlinear system representing the forward model.
const unsigned int _adjoint_sys_num
The number of the nonlinear system representing the adjoint model.
AdjointSolve(Executioner &ex)
virtual void assembleAdjointSystem(SparseMatrix< Number > &matrix, const NumericVector< Number > &solution, NumericVector< Number > &rhs)
Assembles adjoint system.
NonlinearSystemBase & _nl_adjoint
The nonlinear system representing the adjoint model.
void checkIntegrity()
Checks whether the forward and adjoint systems are consistent.
static InputParameters validParams()
const ConsoleStream _console
virtual void computeJacobian(const NumericVector< libMesh::Number > &soln, libMesh::SparseMatrix< libMesh::Number > &jacobian, const unsigned int nl_sys_num)
virtual libMesh::EquationSystems & es() override
virtual std::size_t numSolverSystems() const override
void setCurrentNonlinearSystem(const unsigned int nl_sys_num)
SolverParams & solverParams(unsigned int solver_sys_num=0)
bool execMultiApps(ExecFlagType type, bool auto_advance=true)
virtual void computeResidualTag(const NumericVector< libMesh::Number > &soln, NumericVector< libMesh::Number > &residual, TagID tag)
virtual void execute(const ExecFlagType &exec_type)
Moose::PetscSupport::PetscOptions & getPetscOptions()
virtual void outputStep(ExecFlagType type)
void addRequiredParam(const std::string &name, const std::string &doc_string)
void paramError(const std::string &param, Args... args) const
void mooseError(Args &&... args) const
const T & getParam(const std::string &name) const
libMesh::StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode * > * getBoundaryNodeRange()
NumericVector< Number > & getResidualNonTimeVector()
const MooseObjectTagWarehouse< NodalBCBase > & getNodalBCWarehouse() const
TagID nonTimeVectorTag() const override
virtual libMesh::System & system() override
FEProblemBase & _problem
SolveObject * _inner_solve
MooseMesh & _mesh
std::string _prefix
virtual const NumericVector< Number > *const & currentSolution() const override final
bool automaticScaling() const
std::string prefix() const
bool hasVector(const std::string &tag_name) const
unsigned int number() const
void removeVector(const std::string &name)
virtual NumericVector< Number > & getVector(const std::string &name)
const std::vector< MooseVariableFieldBase * > & getVariables(THREAD_ID tid)
NumericVector< Number > & solution()
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
processor_id_type processor_id() const
virtual void close()=0
virtual void scale(const T factor)=0
processor_id_type processor_id() const
const T & get(std::string_view) const
dof_id_type n_dofs() const
void petscSetOptions(const PetscOptions &po, const SolverParams &solver_params, FEProblemBase *const problem=nullptr)
void setConvergedReasonFlags(FEProblemBase &fe_problem, std::string prefix)
void storePetscOptions(FEProblemBase &fe_problem, const std::string &prefix, const ParallelParamObject &param_object)
const ExecFlagType EXEC_ADJOINT_TIMESTEP_END
const ExecFlagType EXEC_ADJOINT_TIMESTEP_BEGIN
std::string enum_to_string(const T e)
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
bool absolute_fuzzy_equals(const T &var1, const T2 &var2, const Real tol=TOLERANCE *TOLERANCE)
PetscInt * numeric_petsc_cast(const numeric_index_type *p)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real