21 #include "libmesh/dof_map.h" 22 #include "libmesh/equation_systems.h" 23 #include "libmesh/implicit_system.h" 24 #include "libmesh/int_range.h" 25 #include "libmesh/libmesh_logging.h" 26 #include "libmesh/linear_solver.h" 27 #include "libmesh/mesh_base.h" 28 #include "libmesh/numeric_vector.h" 29 #include "libmesh/parameters.h" 30 #include "libmesh/parameter_vector.h" 31 #include "libmesh/qoi_set.h" 32 #include "libmesh/sensitivity_data.h" 33 #include "libmesh/sparse_matrix.h" 34 #include "libmesh/diagonal_matrix.h" 35 #include "libmesh/utility.h" 36 #include "libmesh/static_condensation.h" 42 const std::string & name_in,
43 const unsigned int number_in) :
45 Parent (es, name_in, number_in),
47 zero_out_matrix_and_rhs(true),
60 auto sc = std::make_unique<StaticCondensation>(this->
get_mesh(), *
this, this->
get_dof_map());
125 std::pair<unsigned int, Real>
129 LOG_SCOPE(
"sensitivity_solve()",
"ImplicitSystem");
149 std::pair<unsigned int, Real> solver_params =
151 std::pair<unsigned int, Real> totalrval = std::make_pair(0,0.0);
157 std::pair<unsigned int, Real> rval =
161 double(solver_params.second),
162 solver_params.first);
164 totalrval.first += rval.first;
165 totalrval.second += rval.second;
169 #ifdef LIBMESH_ENABLE_CONSTRAINTS 181 std::pair<unsigned int, Real>
185 LOG_SCOPE(
"adjoint_solve()",
"ImplicitSystem");
202 std::pair<unsigned int, Real> solver_params =
204 std::pair<unsigned int, Real> totalrval = std::make_pair(0,0.0);
209 const std::pair<unsigned int, Real> rval =
212 double(solver_params.second),
213 solver_params.first);
215 totalrval.first += rval.first;
216 totalrval.second += rval.second;
220 #ifdef LIBMESH_ENABLE_CONSTRAINTS 232 std::pair<unsigned int, Real>
235 const QoISet & qoi_indices)
238 LOG_SCOPE(
"weighted_sensitivity_adjoint_solve()",
"ImplicitSystem");
254 #ifdef LIBMESH_ENABLE_DIRICHLET 266 std::vector<std::unique_ptr<NumericVector<Number>>> temprhs(this->
n_qois());
284 weights.
deep_copy(parameterperturbation);
285 parameterperturbation *= delta_p;
286 parameters_vec += parameterperturbation;
304 *(temprhs[i]) *= -1.0;
308 parameterperturbation *= -1.0;
309 parameters_vec += parameterperturbation;
324 *(temprhs[i]) /= (2.0*delta_p);
347 std::pair<unsigned int, Real> solver_params =
349 std::pair<unsigned int, Real> totalrval = std::make_pair(0,0.0);
354 const std::pair<unsigned int, Real> rval =
357 double(solver_params.second),
358 solver_params.first);
360 totalrval.first += rval.first;
361 totalrval.second += rval.second;
365 #ifdef LIBMESH_ENABLE_CONSTRAINTS 378 std::pair<unsigned int, Real>
383 LOG_SCOPE(
"weighted_sensitivity_solve()",
"ImplicitSystem");
409 weights.
deep_copy(parameterperturbation);
410 parameterperturbation *= delta_p;
411 parameters_vec += parameterperturbation;
416 std::unique_ptr<NumericVector<Number>> temprhs = this->
rhs->
clone();
419 parameterperturbation *= -1.0;
420 parameters_vec += parameterperturbation;
425 *temprhs -= *(this->
rhs);
426 *temprhs /= (2.0*delta_p);
439 std::pair<unsigned int, Real> solver_params =
442 const std::pair<unsigned int, Real> rval =
445 double(solver_params.second),
446 solver_params.first);
449 #ifdef LIBMESH_ENABLE_CONSTRAINTS 465 const unsigned int Np = cast_int<unsigned int>
466 (parameters_vec.
size());
468 for (
unsigned int p=0; p != Np; ++p)
475 Number old_parameter = *parameters_vec[p];
478 TOLERANCE * std::max(std::abs(old_parameter), 1e-3);
480 *parameters_vec[p] -= delta_p;
485 sensitivity_rhs = *this->
rhs;
487 *parameters_vec[p] = old_parameter + delta_p;
493 sensitivity_rhs -= *this->
rhs;
494 sensitivity_rhs /= (2*delta_p);
495 sensitivity_rhs.
close();
497 *parameters_vec[p] = old_parameter;
510 const unsigned int Np = cast_int<unsigned int>
511 (parameters_vec.
size());
512 const unsigned int Nq = this->
n_qois();
535 sensitivities.
allocate_data(qoi_indices, *
this, parameters_vec);
569 for (
unsigned int j=0; j != Np; ++j)
576 Number old_parameter = *parameters_vec[j];
579 TOLERANCE * std::max(std::abs(old_parameter), 1e-3);
581 *parameters_vec[j] = old_parameter - delta_p;
587 *parameters_vec[j] = old_parameter + delta_p;
591 std::vector<Number> partialq_partialp(Nq, 0);
592 for (
unsigned int i=0; i != Nq; ++i)
594 partialq_partialp[i] = (qoi_plus[i] - qoi_minus[i]) / (2.*delta_p);
597 *parameters_vec[j] = old_parameter;
599 for (
unsigned int i=0; i != Nq; ++i)
601 sensitivities[i][j] = partialq_partialp[i] +
602 neg_partialR_partialp.
dot(this->get_adjoint_solution(i));
620 const unsigned int Np = cast_int<unsigned int>
621 (parameters_vec.
size());
622 const unsigned int Nq = this->
n_qois();
640 sensitivities.
allocate_data(qoi_indices, *
this, parameters_vec);
658 for (
unsigned int j=0; j != Np; ++j)
664 Number old_parameter = *parameters_vec[j];
667 TOLERANCE * std::max(std::abs(old_parameter), 1e-3);
669 *parameters_vec[j] = old_parameter - delta_p;
673 *parameters_vec[j] = old_parameter + delta_p;
677 std::vector<Number> partialq_partialp(Nq, 0);
678 for (
unsigned int i=0; i != Nq; ++i)
680 partialq_partialp[i] = (qoi_plus[i] - qoi_minus[i]) / (2.*delta_p);
683 *parameters_vec[j] = old_parameter;
685 for (
unsigned int i=0; i != Nq; ++i)
687 sensitivities[i][j] = partialq_partialp[i] +
715 std::unique_ptr<NumericVector<Number>> tempvec = this->
solution->zero_clone();
717 const unsigned int Np = cast_int<unsigned int>
718 (parameters_vec.
size());
719 const unsigned int Nq = this->
n_qois();
746 sensitivities.
allocate_data(qoi_indices, *
this, parameters_vec);
759 for (
unsigned int k=0; k != Np; ++k)
776 parameterperturbation *= delta_p;
777 parameters_vec += parameterperturbation;
779 Number old_parameter = *parameters_vec[k];
781 *parameters_vec[k] = old_parameter + delta_p;
786 std::vector<Number> partial2R_term(this->
n_qois());
787 for (
unsigned int i=0; i != Nq; ++i)
789 partial2R_term[i] = this->
rhs->
dot(this->get_adjoint_solution(i));
791 *parameters_vec[k] = old_parameter - delta_p;
795 for (
unsigned int i=0; i != Nq; ++i)
803 parameterperturbation *= -1.0;
804 parameters_vec += parameterperturbation;
807 old_parameter = *parameters_vec[k];
809 *parameters_vec[k] = old_parameter + delta_p;
813 for (
unsigned int i=0; i != Nq; ++i)
820 *parameters_vec[k] = old_parameter - delta_p;
824 for (
unsigned int i=0; i != Nq; ++i)
831 for (
unsigned int i=0; i != Nq; ++i)
834 partial2q_term[i] /= (4. * delta_p * delta_p);
835 partial2R_term[i] /= (4. * delta_p * delta_p);
838 for (
unsigned int i=0; i != Nq; ++i)
840 sensitivities[i][k] = partial2q_term[i] - partial2R_term[i];
858 *parameters_vec[k] = old_parameter + delta_p;
868 for (
unsigned int i=0; i != Nq; ++i)
877 *parameters_vec[k] = old_parameter - delta_p;
887 for (
unsigned int i=0; i != Nq; ++i)
919 std::unique_ptr<NumericVector<Number>> tempvec = this->
solution->zero_clone();
923 std::unique_ptr<NumericVector<Number>> oldsolution = this->
solution->clone();
925 const unsigned int Np = cast_int<unsigned int>
926 (parameters_vec.
size());
927 const unsigned int Nq = this->
n_qois();
959 for (
unsigned int k=0; k != Np; ++k)
961 Number old_parameterk = *parameters_vec[k];
967 for (
unsigned int l=0; l != k+1; ++l)
980 Number old_parameterl = *parameters_vec[l];
982 *parameters_vec[k] += delta_p;
983 *parameters_vec[l] += delta_p;
988 std::vector<Number> partial2R_term(this->
n_qois());
989 for (
unsigned int i=0; i != Nq; ++i)
991 partial2R_term[i] = this->
rhs->
dot(this->get_adjoint_solution(i));
993 *parameters_vec[l] -= 2.*delta_p;
997 for (
unsigned int i=0; i != Nq; ++i)
1004 *parameters_vec[k] -= 2.*delta_p;
1008 for (
unsigned int i=0; i != Nq; ++i)
1015 *parameters_vec[l] += 2.*delta_p;
1019 for (
unsigned int i=0; i != Nq; ++i)
1024 partial2q_term[i] /= (4. * delta_p * delta_p);
1025 partial2R_term[i] /= (4. * delta_p * delta_p);
1028 for (
unsigned int i=0; i != Nq; ++i)
1031 Number current_terms = partial2q_term[i] - partial2R_term[i];
1038 *parameters_vec[l] = old_parameterl;
1039 *parameters_vec[k] = old_parameterk;
1055 *parameters_vec[k] = old_parameterk + delta_p;
1062 for (
unsigned int l=0; l != Np; ++l)
1065 for (
unsigned int i=0; i != Nq; ++i)
1081 *parameters_vec[k] = old_parameterk - delta_p;
1088 for (
unsigned int l=0; l != Np; ++l)
1091 for (
unsigned int i=0; i != Nq; ++i)
1108 *parameters_vec[k] = old_parameterk;
1138 for (
unsigned int l=0; l != k+1; ++l)
1141 for (
unsigned int i=0; i != Nq; ++i)
1167 for (
unsigned int l=0; l != k+1; ++l)
1170 for (
unsigned int i=0; i != Nq; ++i)
1225 return std::make_pair(
1227 ?
parameters.
get<
unsigned int>(
"linear solver maximum iterations")
1228 : this->get_equation_systems().parameters.get<
unsigned int>(
1229 "linear solver maximum iterations"),
1237 #ifdef LIBMESH_ENABLE_DEPRECATED 1245 libmesh_deprecated();
1247 #endif // LIBMESH_ENABLE_DEPRECATED virtual bool initialized() const
This is the EquationSystems class.
virtual void qoi_parameter_hessian_vector_product(const QoISet &qoi_indices, const ParameterVector ¶meters, const ParameterVector &vector, SensitivityData &product) override
For each of the system's quantities of interest q in qoi[qoi_indices], and for a vector of parameters...
bool have_parameter(std::string_view) const
void deep_copy(ParameterVector &target) const
Deep copy constructor: the target will now own new copies of all the parameter values I'm pointing to...
NumericVector< Number > & add_adjoint_solution(unsigned int i=0)
Data structure for specifying which Parameters should be independent variables in a parameter sensiti...
virtual void create_static_condensation()
Request that static condensation be performed for this system.
static std::unique_ptr< LinearSolver< T > > build(const libMesh::Parallel::Communicator &comm_in, const SolverPackage solver_package=libMesh::default_solver_package())
Builds a LinearSolver using the linear solver package specified by solver_package.
static constexpr Real TOLERANCE
void vector_mult(NumericVector< T > &dest, const NumericVector< T > &arg) const
Multiplies the matrix by the NumericVector arg and stores the result in NumericVector dest...
virtual std::pair< unsigned int, Real > get_linear_solve_parameters() const
Data structure for specifying which Quantities of Interest should be calculated in an adjoint or a pa...
Number get_qoi_value(unsigned int qoi_index) const
void allocate_hessian_data(const QoISet &qoi_indices, const System &sys, const ParameterVector ¶meter_vector)
Given QoISet and ParameterVector, allocates space for all required second derivative data...
unsigned int n_qois() const
Number of currently active quantities of interest.
virtual bool initialized() const
virtual std::pair< unsigned int, Real > weighted_sensitivity_solve(const ParameterVector ¶meters, const ParameterVector &weights) override
Assembles & solves the linear system(s) (dR/du)*u_w = sum(w_p*-dR/dp), for those parameters p contain...
virtual std::unique_ptr< NumericVector< T > > zero_clone() const =0
NumericVector< Number > & get_sensitivity_solution(unsigned int i=0)
NumericVector< Number > & get_sensitivity_rhs(unsigned int i=0)
const EquationSystems & get_equation_systems() const
virtual void assemble()
Prepares matrix and _dof_map for matrix assembly.
virtual void clear() override
Clear all the data structures associated with the system.
NumericVector< Number > * rhs
The system matrix.
virtual ~ImplicitSystem()
const Parallel::Communicator & comm() const
virtual std::unique_ptr< NumericVector< T > > clone() const =0
virtual LinearSolver< Number > * get_linear_solver() const
virtual std::pair< unsigned int, Real > sensitivity_solve(const ParameterVector ¶meters) override
Assembles & solves the linear system(s) (dR/du)*u_p = -dR/dp, for those parameters contained within p...
NumericVector< Number > & add_sensitivity_rhs(unsigned int i=0)
The libMesh namespace provides an interface to certain functionality in the library.
virtual T dot(const NumericVector< T > &v) const =0
bool zero_out_matrix_and_rhs
By default, the system will zero out the matrix and the right hand side.
virtual std::pair< unsigned int, Real > adjoint_solve(const QoISet &qoi_indices=QoISet()) override
Assembles & solves the linear system (dR/du)^T*z = dq/du, for those quantities of interest q specifie...
NumericVector< Number > & add_weighted_sensitivity_solution()
const SparseMatrix< Number > * request_matrix(std::string_view mat_name) const
Parameters parameters
Parameters for the system. If a parameter is not provided, it should be retrieved from the EquationSy...
const MeshBase & get_mesh() const
NumericVector< Number > & get_weighted_sensitivity_solution()
virtual void release_linear_solver(LinearSolver< Number > *) const
Currently a no-op.
virtual void zero()=0
Set all entries to zero.
void enforce_adjoint_constraints_exactly(NumericVector< Number > &v, unsigned int q) const
Heterogeneously constrains the numeric vector v, which represents an adjoint solution defined on the ...
NumericVector< Number > & add_weighted_sensitivity_adjoint_solution(unsigned int i=0)
virtual void forward_qoi_parameter_sensitivity(const QoISet &qoi_indices, const ParameterVector ¶meters, SensitivityData &sensitivities) override
Solves for the derivative of each of the system's quantities of interest q in qoi[qoi_indices] with r...
bool has_index(std::size_t) const
Return whether or not this index is in the set to be calculated.
void add_static_condensation(const StaticCondensation &sc)
Add a static condensation class.
void allocate_data(const QoISet &qoi_indices, const System &sys, const ParameterVector ¶meter_vector)
Given QoISet and ParameterVector, allocates space for all required first derivative data...
virtual void assembly(bool, bool, bool=false, bool=false)
Assembles a residual in rhs and/or a jacobian in matrix, as requested.
const T & get(std::string_view) const
virtual void zero()=0
Set all entries to 0.
bool has_adjoint_dirichlet_boundaries(unsigned int q) const
Data structure for holding completed parameter sensitivity calculations.
std::string prefix() const
virtual void adjoint_qoi_parameter_sensitivity(const QoISet &qoi_indices, const ParameterVector ¶meters, SensitivityData &sensitivities) override
Solves for the derivative of each of the system's quantities of interest q in qoi[qoi_indices] with r...
Manages consistently variables, degrees of freedom, and coefficient vectors.
virtual void add_matrices()
Insertion point for adding matrices in derived classes before init_matrices() is called.
StaticCondensation * _sc
Static condensation class.
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
virtual void disable_cache() override
Avoids use of any cached data that might affect any solve result.
virtual std::pair< unsigned int, Real > solve(SparseMatrix< T > &, NumericVector< T > &, NumericVector< T > &, const std::optional< double > tol=std::nullopt, const std::optional< unsigned int > m_its=std::nullopt)=0
This function calls the solver _solver_type preconditioned with the _preconditioner_type precondition...
unsigned int n_matrices() const
bool is_adjoint_already_solved() const
Accessor for the adjoint_already_solved boolean.
virtual void close()=0
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...
virtual void clear() override
Clear all the data structures associated with the system.
ImplicitSystem(EquationSystems &es, const std::string &name, const unsigned int number)
Constructor.
virtual void update()
Update the local values to reflect the solution on neighboring processors.
virtual void close()=0
Calls the SparseMatrix's internal assembly routines, ensuring that the values are consistent across p...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual void add_matrices() override
Adds the system matrix.
virtual void reuse_preconditioner(bool)
Set the same_preconditioner flag, which indicates if we reuse the same preconditioner for subsequent ...
void vector_mult_add(NumericVector< T > &dest, const NumericVector< T > &arg) const
Multiplies the matrix by the NumericVector arg and adds the result to the NumericVector dest...
const Number & second_derivative(unsigned int qoi_index, unsigned int parameter_index1, unsigned int parameter_index2) const
SparseMatrix< Number > * matrix
The system matrix.
virtual void get_transpose(SparseMatrix< T > &dest) const =0
Copies the transpose of the matrix into dest, which may be *this.
virtual void assemble_qoi(const QoISet &qoi_indices=QoISet()) override
Prepares qoi for quantity of interest assembly, then calls user qoi function.
virtual void assemble_residual_derivatives(const ParameterVector ¶meters) override
Residual parameter derivative function.
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
virtual void assemble_qoi_derivative(const QoISet &qoi_indices=QoISet(), bool include_liftfunc=true, bool apply_constraints=true) override
Prepares adjoint_rhs for quantity of interest derivative assembly, then calls user qoi derivative fun...
NumericVector< Number > & get_adjoint_solution(unsigned int i=0)
Parameters parameters
Data structure holding arbitrary parameters.
virtual void assemble() override
Prepares matrix and rhs for system assembly, then calls user assembly function.
bool on_command_line(std::string arg)
NumericVector< Number > & add_sensitivity_solution(unsigned int i=0)
virtual std::pair< unsigned int, Real > adjoint_solve(SparseMatrix< T > &, NumericVector< T > &, NumericVector< T > &, const std::optional< double > tol=std::nullopt, const std::optional< unsigned int > m_its=std::nullopt)
Function to solve the adjoint system.
bool assemble_before_solve
Flag which tells the system to whether or not to call the user assembly function during each call to ...
std::unique_ptr< LinearSolver< Number > > linear_solver
This class handles all the details of interfacing with various linear algebra packages like PETSc or ...
SparseMatrix< Number > & add_matrix(std::string_view mat_name, ParallelType type=PARALLEL, MatrixBuildType mat_build_type=MatrixBuildType::AUTOMATIC)
Adds the additional matrix mat_name to this system.
const DofMap & get_dof_map() const
virtual void qoi_parameter_hessian(const QoISet &qoi_indices, const ParameterVector ¶meters, SensitivityData &hessian) override
For each of the system's quantities of interest q in qoi[qoi_indices], and for a vector of parameters...
const SparseMatrix< Number > & get_matrix(std::string_view mat_name) const
virtual std::pair< unsigned int, Real > weighted_sensitivity_adjoint_solve(const ParameterVector ¶meters, const ParameterVector &weights, const QoISet &qoi_indices=QoISet()) override
Assembles & solves the linear system(s) (dR/du)^T*z_w = sum(w_p*(d^2q/dudp - d^2R/dudp*z)), for those parameters p contained within parameters, weighted by the values w_p found within weights.
const SparseMatrix< Number > & get_system_matrix() const
void value_copy(ParameterVector &target) const
Value copy method: the target, which should already have as many parameters as I do, will now have those parameters set to my values.
NumericVector< Number > & get_weighted_sensitivity_adjoint_solution(unsigned int i=0)
std::vector< Number > get_qoi_values() const
Returns a copy of qoi, not a reference.
void enforce_constraints_exactly(const System &system, NumericVector< Number > *v=nullptr, bool homogeneous=false) const
Constrains the numeric vector v, which represents a solution defined on the mesh. ...
NumericVector< Number > & get_adjoint_rhs(unsigned int i=0)
bool prefix_with_name() const