22 double matrixNorm(std::unique_ptr<mfem::HypreParMatrix>& K)
24 mfem::HypreParMatrix* H = K.get();
25 hypre_ParCSRMatrix* Hhypre =
static_cast<hypre_ParCSRMatrix*
>(*H);
27 hypre_ParCSRMatrixNormFro(Hhypre, &Hfronorm);
34 auto K_T = std::unique_ptr<mfem::HypreParMatrix>(K->Transpose());
37 mfem::HypreParMatrix* H = K_T.get();
38 hypre_ParCSRMatrix* Hhypre =
static_cast<hypre_ParCSRMatrix*
>(*H);
40 hypre_ParCSRMatrixNormFro(Hhypre, &Hfronorm);
46 std::optional<NonlinearSolverOptions> retained_nonlinear_options,
47 std::optional<LinearSolverOptions> retained_linear_options)
48 : nonlinear_solver_(std::move(s)),
52 retained_nonlinear_options_(std::move(retained_nonlinear_options)),
53 retained_linear_options_(std::move(retained_linear_options))
66 auto solver = std::make_unique<EquationSolver>(nonlinear_opts, linear_opts,
comm_);
67 return std::make_shared<NonlinearBlockSolver>(std::move(solver),
comm_, nonlinear_opts.absolute_tol,
68 nonlinear_opts.relative_tol, nonlinear_opts, linear_opts);
72 const std::vector<mfem::Vector>& residuals,
91 const FieldT* best = us[0].get();
92 for (
const auto& u : us) {
93 if (u->space().GetVDim() > best->
space().GetVDim()) best = u.get();
98 auto* amg_prec =
dynamic_cast<mfem::HypreBoomerAMG*
>(mfem_solver);
100 amg_prec->SetSystemsOptions(best->
space().GetVDim(), smith::ordering == mfem::Ordering::byNODES);
103 #ifdef SMITH_USE_PETSC
104 auto* space_dep_pc =
dynamic_cast<smith::mfem_ext::PetscPreconditionerSpaceDependent*
>(mfem_solver);
108 auto*
space =
const_cast<mfem::ParFiniteElementSpace*
>(&best->
space());
109 space_dep_pc->SetFESpace(
space);
115 const std::vector<FieldPtr>& u_guesses,
116 std::function<std::vector<mfem::Vector>(
const std::vector<FieldPtr>&)> residual_funcs,
117 std::function<std::vector<std::vector<MatrixPtr>>(
const std::vector<FieldPtr>&)> jacobian_funcs)
const
120 SLIC_ERROR_IF(!
nonlinear_solver_,
"NonlinearBlockSolver requires an EquationSolver instance before solve()");
124 int num_rows =
static_cast<int>(u_guesses.size());
125 SLIC_ERROR_IF(num_rows < 0,
"Number of residual rows must be non-negative");
127 mfem::Array<int> block_offsets;
128 block_offsets.SetSize(num_rows + 1);
129 block_offsets[0] = 0;
130 for (
int row_i = 0; row_i < num_rows; ++row_i) {
131 block_offsets[row_i + 1] = u_guesses[
static_cast<size_t>(row_i)]->
space().TrueVSize();
133 block_offsets.PartialSum();
134 auto block_u = std::make_unique<mfem::BlockVector>(block_offsets);
135 for (
int row_i = 0; row_i < num_rows; ++row_i) {
136 block_u->GetBlock(row_i) = *u_guesses[
static_cast<size_t>(row_i)];
139 auto block_r = std::make_unique<mfem::BlockVector>(block_offsets);
146 auto residual_op_ = std::make_unique<mfem_ext::StdFunctionOperator>(
148 [&residual_funcs, num_rows, &u_guesses, &block_r, &block_offsets](
const mfem::Vector& u_, mfem::Vector& r_) {
149 const mfem::BlockVector* u = dynamic_cast<const mfem::BlockVector*>(&u_);
150 mfem::BlockVector u_block_wrapper;
153 u_block_wrapper.Update(const_cast<double*>(u_.GetData()), block_offsets);
154 u = &u_block_wrapper;
156 for (
int row_i = 0; row_i < num_rows; ++row_i) {
157 *u_guesses[
static_cast<size_t>(row_i)] = u->GetBlock(row_i);
160 auto residuals = residual_funcs(u_guesses);
161 SLIC_ERROR_IF(!block_r,
"Invalid residual block cast to an mfem::BlockVector");
162 for (
int row_i = 0; row_i < num_rows; ++row_i) {
163 auto r = residuals[
static_cast<size_t>(row_i)];
164 block_r->GetBlock(row_i) = r;
168 [
this, &block_offsets, &u_guesses, jacobian_funcs, num_rows](
const mfem::Vector& u_) -> mfem::Operator& {
169 const mfem::BlockVector* u =
dynamic_cast<const mfem::BlockVector*
>(&u_);
170 mfem::BlockVector u_block_wrapper;
172 u_block_wrapper.Update(
const_cast<double*
>(u_.GetData()), block_offsets);
173 u = &u_block_wrapper;
175 for (
int row_i = 0; row_i < num_rows; ++row_i) {
176 *u_guesses[
static_cast<size_t>(row_i)] = u->GetBlock(row_i);
178 matrix_of_jacs_ = jacobian_funcs(u_guesses);
180 auto& J = matrix_of_jacs_[0][0];
181 SLIC_ERROR_IF(!J,
"Jacobian block (0,0) is null in single-block solve");
184 block_jac_ = std::make_unique<mfem::BlockOperator>(block_offsets);
185 for (
int i = 0; i < num_rows; ++i) {
186 for (
int j = 0; j < num_rows; ++j) {
187 auto& J = matrix_of_jacs_[
static_cast<size_t>(i)][
static_cast<size_t>(j)];
189 block_jac_->SetBlock(i, j, J.get());
195 nonlinear_solver_->setConvergenceTolerances(inner_tol_multiplier_ * abs_tol_, inner_tol_multiplier_ * rel_tol_,
197 nonlinear_solver_->setOperator(*residual_op_);
198 nonlinear_solver_->solve(*block_u);
200 for (
int row_i = 0; row_i < num_rows; ++row_i) {
201 *u_guesses[
static_cast<size_t>(row_i)] = block_u->GetBlock(row_i);
207 std::vector<NonlinearBlockSolverBase::FieldPtr> NonlinearBlockSolver::solveAdjoint(
208 const std::vector<DualPtr>& u_bars, std::vector<std::vector<MatrixPtr>>& jacobian_transposed)
const
212 int num_rows =
static_cast<int>(u_bars.size());
213 SLIC_ERROR_IF(num_rows < 0,
"Number of residual rows must be non-negative");
215 std::vector<NonlinearBlockSolverBase::FieldPtr> u_duals(
static_cast<size_t>(num_rows));
216 for (
int row_i = 0; row_i < num_rows; ++row_i) {
217 u_duals[
static_cast<size_t>(row_i)] = std::make_shared<NonlinearBlockSolverBase::FieldT>(
218 u_bars[
static_cast<size_t>(row_i)]->space(),
"u_dual_" + std::to_string(row_i));
221 auto& linear_solver = nonlinear_solver_->linearSolver();
225 linear_solver.SetOperator(*jacobian_transposed[0][0]);
226 linear_solver.Mult(*u_bars[0], *u_duals[0]);
230 mfem::Array<int> block_offsets;
231 block_offsets.SetSize(num_rows + 1);
232 block_offsets[0] = 0;
233 for (
int row_i = 0; row_i < num_rows; ++row_i) {
234 block_offsets[row_i + 1] = u_bars[
static_cast<size_t>(row_i)]->
space().TrueVSize();
236 block_offsets.PartialSum();
238 auto block_ds = std::make_unique<mfem::BlockVector>(block_offsets);
241 auto block_r = std::make_unique<mfem::BlockVector>(block_offsets);
242 for (
int row_i = 0; row_i < num_rows; ++row_i) {
243 block_r->GetBlock(row_i) = *u_bars[
static_cast<size_t>(row_i)];
246 auto block_jac = std::make_unique<mfem::BlockOperator>(block_offsets);
247 for (
int i = 0; i < num_rows; ++i) {
248 for (
int j = 0; j < num_rows; ++j) {
249 block_jac->SetBlock(i, j, jacobian_transposed[
static_cast<size_t>(i)][
static_cast<size_t>(j)].
get());
253 linear_solver.SetOperator(*block_jac);
254 linear_solver.Mult(*block_r, *block_ds);
256 for (
int row_i = 0; row_i < num_rows; ++row_i) {
257 *u_duals[
static_cast<size_t>(row_i)] = block_ds->GetBlock(row_i);
267 auto solid_solver = std::make_unique<EquationSolver>(nonlinear_opts, linear_opts, mesh.
getComm());
268 return std::make_shared<NonlinearBlockSolver>(std::move(solid_solver), mesh.
getComm(), nonlinear_opts.
absolute_tol,
269 nonlinear_opts.
relative_tol, nonlinear_opts, linear_opts);
This file contains the declaration of the boundary condition manager class.
Class for encapsulating the dual vector space of a finite element space (i.e. the space of linear for...
Class for encapsulating the critical MFEM components of a primal finite element field.
mfem::ParFiniteElementSpace & space()
Returns a non-owning reference to the internal FESpace.
Helper class for constructing a mesh consistent with Smith.
MPI_Comm getComm() const
Returns parallel communicator.
bool is_setup_
Records if this block solver has its preconditioner initialized.
double abs_tol_
absolute residual tolerance for convergence check
ConvergenceStatus convergenceStatus(double tolerance_multiplier, const std::vector< mfem::Vector > &residuals) const
Evaluate convergence for this solver's configured tolerance using solver-owned convergence state.
std::unique_ptr< EquationSolver > nonlinear_solver_
the nonlinear equation solver used for the forward pass
std::vector< FieldPtr > solve(const std::vector< FieldPtr > &u_guesses, std::function< std::vector< mfem::Vector >(const std::vector< FieldPtr > &)> residuals, std::function< std::vector< std::vector< MatrixPtr >>(const std::vector< FieldPtr > &)> jacobians) const override
This is an overloaded member function, provided for convenience. It differs from the above function o...
std::optional< LinearSolverOptions > retained_linear_options_
retained linear config
void primeConvergenceContext(const std::vector< mfem::Vector > &residuals, NonlinearConvergenceContext &context) const override
This is an overloaded member function, provided for convenience. It differs from the above function o...
MPI_Comm comm_
MPI communicator for parallel norm computation.
NonlinearBlockSolver(std::unique_ptr< EquationSolver > s, MPI_Comm comm, double abs_tol=1e-12, double rel_tol=1e-8, std::optional< NonlinearSolverOptions > retained_nonlinear_options=std::nullopt, std::optional< LinearSolverOptions > retained_linear_options=std::nullopt)
Construct from a nonlinear equation solver.
std::optional< NonlinearSolverOptions > retained_nonlinear_options_
retained nonlinear config
void completeSetup(const std::vector< FieldPtr > &us) const
Initialize the preconditioner in case of vector problems.
double rel_tol_
relative residual tolerance for convergence check
std::shared_ptr< NonlinearBlockSolver > cloneFresh() const
Build a fresh solver instance from retained config.
This file contains the declaration of an equation solver wrapper.
This contains a class that represents the dual of a finite element vector space, i....
This file contains the declaration of structure that manages the MFEM objects that make up the state ...
Smith mesh class which assists in constructing the appropriate parallel mfem meshes and registering a...
Accelerator functionality.
std::shared_ptr< NonlinearBlockSolver > buildNonlinearBlockSolver(NonlinearSolverOptions nonlinear_opts, LinearSolverOptions linear_opts, const smith::Mesh &mesh)
Create an equation-backed nonlinear block solver.
double skewMatrixNorm(std::unique_ptr< mfem::HypreParMatrix > &K)
Utility to compute 0.5*norm(K-K.T)
double matrixNorm(std::unique_ptr< mfem::HypreParMatrix > &K)
Utility to compute the matrix norm.
std::vector< double > computeResidualBlockNorms(const std::vector< mfem::Vector > &residuals, MPI_Comm comm)
Compute one L2 norm per residual block.
ConvergenceStatus evaluateResidualConvergence(double tolerance_multiplier, double abs_tol, double rel_tol, const std::vector< double > &block_norms, NonlinearConvergenceContext &context)
Evaluate scalar nonlinear residual convergence.
mfem::ParFiniteElementSpace & space(FieldState field)
Get the space from the primal field of a field states.
This file contains nonlinear block solver interfaces and helpers.
#define SMITH_MARK_FUNCTION
Classes for defining an mfem::Operator with std::functions.
Detailed status from evaluating nonlinear residual convergence.
Parameters for an iterative linear solution scheme.
Stores initial residual norms used for relative nonlinear convergence checks.
Nonlinear solution scheme parameters.
double relative_tol
Relative tolerance.
double absolute_tol
Absolute tolerance.