libMesh
adaptive_time_solver.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 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 #include "libmesh/adaptive_time_solver.h"
19 #include "libmesh/diff_system.h"
20 #include "libmesh/dof_map.h"
21 #include "libmesh/numeric_vector.h"
22 #include "libmesh/no_solution_history.h"
23 
24 // Debug
25 #include "libmesh/system_norm.h"
26 #include "libmesh/enum_norm_type.h"
27 
28 namespace libMesh
29 {
30 
31 
32 
35  core_time_solver(),
36  target_tolerance(1.e-3),
37  upper_tolerance(0.0),
38  max_deltat(0.),
39  min_deltat(0.),
40  max_growth(0.),
41  completed_timestep_size(s.deltat),
42  global_tolerance(true)
43 {
44  // the child class must populate core_time_solver
45  // with whatever actual time solver is to be used
46 }
47 
48 
49 
51 
52 
53 
55 {
57 
58  // We override this because our core_time_solver is the one that
59  // needs to handle new vectors, diff_solver->init(), etc
60  core_time_solver->init();
61 
62  // Set the core_time_solver's solution history object to be the same one as
63  // that for the outer adaptive time solver
64  core_time_solver->set_solution_history((this->get_solution_history()));
65 
66  // Now that we have set the SolutionHistory object for the coretimesolver,
67  // we set the SolutionHistory type for the timesolver to be NoSolutionHistory
68  // All storage and retrieval will be handled by the coretimesolver directly.
69  NoSolutionHistory outersolver_solution_history;
70  this->set_solution_history(outersolver_solution_history);
71 
72  // As an UnsteadySolver, we have an old_local_nonlinear_solution, but it
73  // isn't pointing to the right place - fix it
74  old_local_nonlinear_solution = core_time_solver->old_local_nonlinear_solution;
75 }
76 
77 
78 
80 {
82 
83  // We override this because our core_time_solver is the one that
84  // needs to handle new vectors, diff_solver->reinit(), etc
85  core_time_solver->reinit();
86 }
87 
88 
90 {
91  // The first access of advance_timestep happens via solve, not user code
92  // It is used here to store any initial conditions data
93  if (!first_solve)
94  {
96  }
97  else
98  {
99  // We are here because of a call to advance_timestep that happens
100  // via solve, the very first solve. All we are doing here is storing
101  // the initial condition. The actual solution computed via this solve
102  // will be stored when we call advance_timestep in the user's timestep loop
103  first_solve = false;
104  core_time_solver->set_first_solve(false);
105  }
106 
107  // For the adaptive time solver, all SH operations
108  // are handled by the core_time_solver's SH object
109  // Sub solution storage is handled internally by the core time solver,
110  // but the 'full step' solution is stored here to maintain consistency
111  // with the fixed timestep scheme.
112  core_time_solver->get_solution_history().store(false, _system.time);
113 
114  NumericVector<Number> & old_nonlinear_soln =
115  _system.get_vector("_old_nonlinear_solution");
116  NumericVector<Number> & nonlinear_solution =
117  *(_system.solution);
118 
119  old_nonlinear_soln = nonlinear_solution;
120 
121  old_nonlinear_soln.localize
124 }
125 
127 {
128  // Store the computed full step adjoint solution for future use (sub steps are handled internally by the core time solver)
129  core_time_solver->get_solution_history().store(true, _system.time);
130 
131  // For the first adjoint step ensure that we use the last primal timestep.
132  if (first_adjoint_step)
133  {
134  _system.deltat = dynamic_cast<DifferentiableSystem &>(_system).time_solver->TimeSolver::last_completed_timestep_size();
135  first_adjoint_step = false;
136  }
137 
138  // Before moving to the next time instant, copy over the current adjoint solutions into _old_adjoint_solutions
139  for(auto i : make_range(_system.n_qois()))
140  {
141  std::string old_adjoint_solution_name = "_old_adjoint_solution";
142  old_adjoint_solution_name+= std::to_string(i);
143  NumericVector<Number> & old_adjoint_solution_i = _system.get_vector(old_adjoint_solution_name);
144  NumericVector<Number> & adjoint_solution_i = _system.get_adjoint_solution(i);
145  old_adjoint_solution_i = adjoint_solution_i;
146  }
147 
149 
150  // For the adaptive time solver, all SH operations
151  // are handled by the core_time_solver's SH object
152  // Retrieve the primal solution for the next adjoint calculation,
153  // by using the core time solver's solution history object.
154  core_time_solver->get_solution_history().retrieve(true, _system.time);
155 
156  // We also need to tell the core time solver that the adjoint initial conditions have been set
157  core_time_solver->set_first_adjoint_step(false);
158 
159  // Dont forget to localize the old_nonlinear_solution !
160  _system.get_vector("_old_nonlinear_solution").localize
163 }
164 
166 {
167  // Ask the core time solver to retrieve all the stored vectors
168  // at the current time
169  core_time_solver->retrieve_timestep();
170 }
171 
173 {
175 
176  return core_time_solver->error_order();
177 }
178 
179 
180 
181 bool AdaptiveTimeSolver::element_residual (bool request_jacobian,
182  DiffContext & context)
183 {
185 
186  return core_time_solver->element_residual(request_jacobian, context);
187 }
188 
189 
190 
191 bool AdaptiveTimeSolver::side_residual (bool request_jacobian,
192  DiffContext & context)
193 {
195 
196  return core_time_solver->side_residual(request_jacobian, context);
197 }
198 
199 
200 
201 bool AdaptiveTimeSolver::nonlocal_residual (bool request_jacobian,
202  DiffContext & context)
203 {
205 
206  return core_time_solver->nonlocal_residual(request_jacobian, context);
207 }
208 
209 
210 
211 std::unique_ptr<DiffSolver> & AdaptiveTimeSolver::diff_solver()
212 {
213  return core_time_solver->diff_solver();
214 }
215 
216 
217 
218 std::unique_ptr<LinearSolver<Number>> & AdaptiveTimeSolver::linear_solver()
219 {
220  return core_time_solver->linear_solver();
221 }
222 
223 
224 
227 {
228  return s.calculate_norm(v, component_norm);
229 }
230 
231 } // namespace libMesh
virtual Real calculate_norm(System &, NumericVector< Number > &)
A helper function to calculate error norms.
Real time
For time-dependent problems, this is the time t at the beginning of the current timestep.
Definition: system.h:1615
Real completed_timestep_size
The adaptive time solver&#39;s have two notions of deltat.
This class provides all data required for a physics package (e.g.
Definition: diff_context.h:55
virtual bool side_residual(bool get_jacobian, DiffContext &) override
This method is passed on to the core_time_solver.
SystemNorm component_norm
Error calculations are done in this norm, DISCRETE_L2 by default.
unsigned int n_qois() const
Number of currently active quantities of interest.
Definition: system.h:2621
virtual void adjoint_advance_timestep() override
This method advances the adjoint solution to the previous timestep, after an adjoint_solve() has been...
virtual Real error_order() const override
This method is passed on to the core_time_solver.
virtual std::unique_ptr< DiffSolver > & diff_solver() override
An implicit linear or nonlinear solver to use at each timestep.
The libMesh namespace provides an interface to certain functionality in the library.
AdaptiveTimeSolver(sys_type &s)
Constructor.
This class provides a specific system class.
Definition: diff_system.h:54
sys_type & _system
A reference to the system we are solving.
Definition: time_solver.h:312
Generic class from which first order UnsteadySolvers should subclass.
std::shared_ptr< NumericVector< Number > > old_local_nonlinear_solution
Serial vector of _system.get_vector("_old_nonlinear_solution") This is a shared_ptr so that it can be...
&#39;Save nothing&#39; subclass of Solution History, this is the default.
Real deltat
For time-dependent problems, this is the amount delta t to advance the solution in time...
Definition: diff_system.h:280
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:96
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1593
Real calculate_norm(const NumericVector< Number > &v, unsigned int var, FEMNormType norm_type, std::set< unsigned int > *skip_dimensions=nullptr) const
Definition: system.C:1724
libmesh_assert(ctx)
virtual bool nonlocal_residual(bool get_jacobian, DiffContext &) override
This method is passed on to the core_time_solver.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void set_solution_history(const SolutionHistory &_solution_history)
A setter function users will employ if they need to do something other than save no solution history...
Definition: time_solver.C:119
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...
Definition: int_range.h:140
NumericVector< Number > & get_adjoint_solution(unsigned int i=0)
Definition: system.C:1245
virtual ~AdaptiveTimeSolver()
Destructor.
virtual void reinit() override
The reinitialization function.
virtual void retrieve_timestep() override
This method retrieves all the stored solutions at the current system.time.
virtual void advance_timestep() override
This method advances the solution to the next timestep, after a solve() has been performed.
virtual bool element_residual(bool get_jacobian, DiffContext &) override
This method is passed on to the core_time_solver.
const DofMap & get_dof_map() const
Definition: system.h:2374
std::unique_ptr< UnsteadySolver > core_time_solver
This object is used to take timesteps.
virtual std::unique_ptr< LinearSolver< Number > > & linear_solver() override
An implicit linear solver to use for adjoint and sensitivity problems.
const std::vector< dof_id_type > & get_send_list() const
Definition: dof_map.h:526
SolutionHistory & get_solution_history()
A getter function that returns a reference to the solution history object owned by TimeSolver...
Definition: time_solver.C:124
bool first_adjoint_step
A bool that will be true the first time adjoint_advance_timestep() is called, (when the primal soluti...
virtual void init() override
The initialization function.
const NumericVector< Number > & get_vector(std::string_view vec_name) const
Definition: system.C:943
bool first_solve
A bool that will be true the first time solve() is called, and false thereafter.
virtual void localize(std::vector< T > &v_local) const =0
Creates a copy of the global vector in the local vector v_local.