libMesh
Loading...
Searching...
No Matches
diff_system.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19// libMesh includes
20#include "libmesh/diff_solver.h"
21#include "libmesh/diff_system.h"
22#include "libmesh/time_solver.h"
23#include "libmesh/unsteady_solver.h"
24#include "libmesh/dirichlet_boundaries.h"
25#include "libmesh/dof_map.h"
26#include "libmesh/zero_function.h"
27
28// C++ includes
29#include <utility> // std::swap
30
31namespace libMesh
32{
33
34
35
37 const std::string & name_in,
38 const unsigned int number_in) :
39 Parent (es, name_in, number_in),
40 time_solver (),
41 deltat(1.),
42 postprocess_sides(false),
43 print_solution_norms(false),
44 print_solutions(false),
45 print_residual_norms(false),
46 print_residuals(false),
47 print_jacobian_norms(false),
48 print_jacobians(false),
49 print_element_solutions(false),
50 print_element_residuals(false),
51 print_element_jacobians(false),
52 _constrain_in_solver(true),
53 _diff_physics(),
54 _diff_qoi()
55{
56}
57
58
59
61
62
63
65{
66 // If we had no attached Physics object, clear our own Physics data
67 if (this->_diff_physics.empty())
68 this->clear_physics();
69
70 this->_diff_physics = {}; // No stack::clear
71 this->_diff_qoi = {};
72
73 // If we had no attached QoI object, clear our own QoI data
74 if (this->_diff_qoi.empty())
75 this->clear_qoi();
76
77 use_fixed_solution = false;
78}
79
80
81
83{
85
87 libmesh_assert_equal_to (&(time_solver->system()), this);
88
89 time_solver->reinit();
90}
91
92
93
95{
96 // If it isn't a separate initialized-upon-attachment object, do any
97 // initialization our physics needs.
98 if (this->_diff_physics.empty())
99 this->init_physics(*this);
100
101 // Do any initialization our solvers need
103 libmesh_assert_equal_to (&(time_solver->system()), this);
104
105 // Now check for second order variables and add their velocities to the System.
106 if (!time_solver->is_steady())
107 {
108 const UnsteadySolver & unsteady_solver =
109 cast_ref<const UnsteadySolver &>(*(time_solver.get()));
110
111 if (unsteady_solver.time_order() == 1)
113 }
114
115 time_solver->init();
116
117 // Next initialize ImplicitSystem data
119
120 time_solver->init_data();
121}
122
123std::unique_ptr<DiffContext> DifferentiableSystem::build_context ()
124{
125 auto context = std::make_unique<DiffContext>(*this);
126 context->set_deltat_pointer( &this->deltat );
127 return context;
128}
129
130
132{
133 this->assembly(true, true);
134}
135
136
137
139{
140 // Get the time solver object associated with the system, and tell it that
141 // we are not solving the adjoint problem
142 this->get_time_solver().set_is_adjoint(false);
143
144 libmesh_assert_equal_to (&(time_solver->system()), this);
145 time_solver->solve();
146}
147
148
149
150std::pair<unsigned int, Real> DifferentiableSystem::adjoint_solve (const QoISet & qoi_indices)
151{
152 // Get the time solver object associated with the system, and tell it that
153 // we are solving the adjoint problem
154 this->get_time_solver().set_is_adjoint(true);
155
156 return time_solver->adjoint_solve(qoi_indices);
157
158 //return this->ImplicitSystem::adjoint_solve(qoi_indices);
159}
160
161
162
164{
166 libmesh_assert_equal_to (&(time_solver->system()), this);
167 return this->time_solver->linear_solver().get();
168}
169
170
171
172std::pair<unsigned int, Real> DifferentiableSystem::get_linear_solve_parameters() const
173{
175 libmesh_assert_equal_to (&(time_solver->system()), this);
176 return std::make_pair(this->time_solver->diff_solver()->max_linear_iterations,
177 this->time_solver->diff_solver()->relative_residual_tolerance);
178}
179
180
181
183{
184 const std::set<unsigned int> & second_order_vars = this->get_second_order_vars();
185 if (!second_order_vars.empty())
186 {
187 for (const auto & var_id : second_order_vars)
188 {
189 const Variable & var = this->variable(var_id);
190 std::string new_var_name = std::string("dot_")+var.name();
191
192 unsigned int v_var_idx;
193
194 if (var.active_subdomains().empty())
195 v_var_idx = this->add_variable( new_var_name, var.type() );
196 else
197 v_var_idx = this->add_variable( new_var_name, var.type(), &var.active_subdomains() );
198
199 _second_order_dot_vars.insert(std::pair<unsigned int, unsigned int>(var_id, v_var_idx));
200
201 // The new velocities are time evolving variables of first order
202 this->time_evolving( v_var_idx, 1 );
203
204#ifdef LIBMESH_ENABLE_DIRICHLET
205 // And if there are any boundary conditions set on the second order
206 // variable, we also need to set it on its velocity variable.
207 this->add_dot_var_dirichlet_bcs(var_id, v_var_idx);
208#endif
209 }
210 }
211}
212
213#ifdef LIBMESH_ENABLE_DIRICHLET
215 unsigned int dot_var_idx )
216{
217 // We're assuming that there could be a lot more variables than
218 // boundary conditions, so we search each of the boundary conditions
219 // for this variable rather than looping over boundary conditions
220 // in a separate loop and searching through all the variables.
221 const DirichletBoundaries * all_dbcs =
223
224 if (all_dbcs)
225 {
226 // We need to cache the DBCs to be added so that we add them
227 // after looping over the existing DBCs. Otherwise, we're polluting
228 // the thing we're looping over.
229 std::vector<DirichletBoundary> new_dbcs;
230
231 for (const auto & dbc : *all_dbcs)
232 {
233 libmesh_assert(dbc);
234
235 // Look for second order variable in the current
236 // DirichletBoundary object
237 std::vector<unsigned int>::const_iterator dbc_var_it =
238 std::find( dbc->variables.begin(), dbc->variables.end(), var_idx );
239
240 // If we found it, then we also need to add it's corresponding
241 // "dot" variable to a DirichletBoundary
242 std::vector<unsigned int> vars_to_add;
243 if (dbc_var_it != dbc->variables.end())
244 vars_to_add.push_back(dot_var_idx);
245
246 if (!vars_to_add.empty())
247 {
248 // We need to check if the boundary condition is time-dependent.
249 // Currently, we cannot automatically differentiate w.r.t. time
250 // so if the user supplies a time-dependent Dirichlet BC, then
251 // we can't automatically support the Dirichlet BC for the
252 // "velocity" boundary condition, so we error. Otherwise,
253 // the "velocity boundary condition will just be zero.
254 bool is_time_evolving_bc = false;
255 if (dbc->f)
256 is_time_evolving_bc = dbc->f->is_time_dependent();
257 else if (dbc->f_fem)
258 // We it's a FEMFunctionBase object, it will be implicitly
259 // time-dependent since it is assumed to depend on the solution.
260 is_time_evolving_bc = true;
261 else
262 libmesh_error_msg("Could not find valid boundary function!");
263
264 libmesh_error_msg_if(is_time_evolving_bc, "Cannot currently support time-dependent Dirichlet BC for dot variables!");
265 libmesh_error_msg_if(!dbc->f, "Expected valid DirichletBoundary function");
266
267 new_dbcs.emplace_back(dbc->b, vars_to_add, ZeroFunction<Number>());
268 }
269 }
270
271 // Let the DofMap make its own deep copy of the DirichletBC objects
272 for (const auto & dbc : new_dbcs)
274
275 } // if (all_dbcs)
276}
277#endif // LIBMESH_ENABLE_DIRICHLET
278
280{
281 this->_diff_qoi = {};
282 this->_diff_qoi.push(qoi_in->clone());
283
284 auto & dq = this->_diff_qoi.top();
285 dq->init_qoi_count( *this );
286}
287
288unsigned int DifferentiableSystem::get_second_order_dot_var( unsigned int var ) const
289{
290 // For SteadySolver or SecondOrderUnsteadySolvers, we just give back var
291 unsigned int dot_var = var;
292
293 if (!time_solver->is_steady())
294 {
295 const UnsteadySolver & unsteady_solver =
296 cast_ref<const UnsteadySolver &>(*(time_solver.get()));
297
298 if (unsteady_solver.time_order() == 1)
299 dot_var = this->_second_order_dot_vars.find(var)->second;
300 }
301
302 return dot_var;
303}
304
306{
307 bool have_first_order_scalar_vars = false;
308
309 if (this->have_first_order_vars())
310 for (const auto & var : this->get_first_order_vars())
311 if (this->variable(var).type().family == SCALAR)
313
315}
316
318{
320
321 if (this->have_second_order_vars())
322 for (const auto & var : this->get_second_order_vars())
323 if (this->variable(var).type().family == SCALAR)
325
327}
328
329
330
332{
333 this->_diff_physics.push(new_physics.clone_physics());
334
335 // If the physics has been changed, we will reassemble
336 // the matrix from scratch before doing an adjoint solve
337 // rather than just transposing
338 this->disable_cache();
339}
340
341
342
344{
345 libmesh_assert(!this->_diff_physics.empty());
346
347 this->_diff_physics.pop();
348
349 // If the physics has been changed, we will reassemble
350 // the matrix from scratch before doing an adjoint solve
351 // rather than just transposing
352 this->disable_cache();
353}
354
355
357{
358 _constrain_in_solver = enable;
359 this->time_solver->diff_solver()->set_exact_constraint_enforcement(enable);
360}
361
362
363} // namespace libMesh
This class provides a specific system class.
virtual void clear_physics()
Clear any data structures associated with the physics.
const std::set< unsigned int > & get_second_order_vars() const
virtual void init_physics(const System &sys)
Initialize any data structures associated with the physics.
virtual std::unique_ptr< DifferentiablePhysics > clone_physics()=0
Copy of this object.
const std::set< unsigned int > & get_first_order_vars() const
std::map< unsigned int, unsigned int > _second_order_dot_vars
If the user adds any second order variables, then we need to also cache the map to their correspondin...
virtual void time_evolving(unsigned int var, unsigned int order)
Tells the DiffSystem that variable var is evolving with respect to time.
This class provides a specific system class.
Definition diff_qoi.h:53
virtual void clear_qoi()
Clear all the data structures associated with the QoI.
Definition diff_qoi.h:77
virtual std::unique_ptr< DifferentiableQoI > clone()=0
Copy of this object.
unsigned int get_second_order_dot_var(unsigned int var) const
For a given second order (in time) variable var, this method will return the index to the correspondi...
void pop_physics()
Pop a physics object off of our stack.
Real deltat
For time-dependent problems, this is the amount delta t to advance the solution in time.
std::stack< std::unique_ptr< DifferentiablePhysics >, std::vector< std::unique_ptr< DifferentiablePhysics > > > _diff_physics
Stack of pointers to objects to use for physics assembly evaluations.
virtual void set_constrain_in_solver(bool enable)
set_constrain_in_solver to false to apply constraints only via residual terms in the systems to be so...
bool have_second_order_scalar_vars() const
Check for any second order vars that are also belong to FEFamily::SCALAR.
void push_physics(DifferentiablePhysics &new_physics)
Push a clone of a new physics object onto our stack, overriding the current physics until the new phy...
DifferentiableSystem(EquationSystems &es, const std::string &name, const unsigned int number)
Constructor.
Definition diff_system.C:36
std::stack< std::unique_ptr< DifferentiableQoI >, std::vector< std::unique_ptr< DifferentiableQoI > > > _diff_qoi
Pointer to object to use for quantity of interest assembly evaluations.
virtual void assembly(bool get_residual, bool get_jacobian, bool apply_heterogeneous_constraints=false, bool apply_no_constraints=false) override=0
Assembles a residual in rhs and/or a jacobian in matrix, as requested.
bool have_first_order_scalar_vars() const
Check for any first order vars that are also belong to FEFamily::SCALAR.
void attach_qoi(DifferentiableQoI *qoi_in)
Attach external QoI object.
void add_second_order_dot_vars()
Helper function to add "velocity" variables that are cousins to second order-in-time variables in the...
virtual LinearSolver< Number > * get_linear_solver() const override
bool _constrain_in_solver
_constrain_in_solver defaults to true; if false then we apply constraints only via residual terms in ...
virtual std::pair< unsigned int, Real > get_linear_solve_parameters() const override
virtual std::pair< unsigned int, Real > adjoint_solve(const QoISet &qoi_indices=QoISet()) override
This function sets the _is_adjoint boolean member of TimeSolver to true and then calls the adjoint_so...
virtual void clear() override
Clear all the data structures associated with the system.
Definition diff_system.C:64
void add_dot_var_dirichlet_bcs(unsigned int var_idx, unsigned int dot_var_idx)
Helper function to and Dirichlet boundary conditions to "dot" variable cousins of second order variab...
virtual void init_data() override
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used.
Definition diff_system.C:94
virtual std::unique_ptr< DiffContext > build_context()
Builds a DiffContext object with enough information to do evaluations on each element.
std::unique_ptr< TimeSolver > time_solver
A pointer to the solver object we're going to use.
virtual void reinit() override
Reinitializes the member data fields associated with the system, so that, e.g., assemble() may be use...
Definition diff_system.C:82
virtual void solve() override
Invokes the solver associated with the system.
virtual void assemble() override
Prepares matrix and rhs for matrix assembly.
We're using a class instead of a typedef to allow forward declarations and future flexibility.
const DirichletBoundaries * get_dirichlet_boundaries() const
Definition dof_map.h:1636
void add_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary)
Adds a copy of the specified Dirichlet boundary to the system.
This is the EquationSystems class.
FEFamily family
The type of finite element.
Definition fe_type.h:228
Manages consistently variables, degrees of freedom, coefficient vectors, and matrices for implicit sy...
virtual void disable_cache() override
Avoids use of any cached data that might affect any solve result.
This base class can be inherited from to provide interfaces to linear solvers from different packages...
Data structure for specifying which Quantities of Interest should be calculated in an adjoint or a pa...
Definition qoi_set.h:46
virtual void reinit()
Reinitializes degrees of freedom and other required data on the current mesh.
Definition system.C:442
bool use_fixed_solution
A boolean to be set to true by systems using elem_fixed_solution, for optional use by e....
Definition system.h:1625
const Variable & variable(unsigned int var) const
Return a constant reference to Variable var.
Definition system.C:2704
unsigned int add_variable(std::string_view var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition system.C:1344
virtual void init_data()
Initializes the data for the system.
Definition system.C:207
const DofMap & get_dof_map() const
Definition system.h:2417
void set_is_adjoint(bool _is_adjoint_value)
Accessor for setting whether we need to do a primal or adjoint solve.
This is a generic class that defines a solver to handle time integration of DifferentiableSystems.
virtual unsigned int time_order() const =0
This class defines the notion of a variable in the system.
Definition variable.h:51
const std::set< subdomain_id_type > & active_subdomains() const
Definition variable.h:181
const std::string & name() const
Definition variable.h:122
const FEType & type() const
Definition variable.h:144
ConstFunction that simply returns 0.
The libMesh namespace provides an interface to certain functionality in the library.
libmesh_assert(ctx)