1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2020 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 namespace libMesh
25 {
26
27
28
AdaptiveTimeSolver(sys_type & s)29 AdaptiveTimeSolver::AdaptiveTimeSolver (sys_type & s)
30 : FirstOrderUnsteadySolver(s),
31 core_time_solver(),
32 target_tolerance(1.e-3),
33 upper_tolerance(0.0),
34 max_deltat(0.),
35 min_deltat(0.),
36 max_growth(0.),
37 completedtimestep_deltat(1.),
38 global_tolerance(true)
39 {
40 // the child class must populate core_time_solver
41 // with whatever actual time solver is to be used
42
43 // As an UnsteadySolver, we have an old_local_nonlinear_solution, but we're
44 // going to drop it and use our core time solver's instead.
45 old_local_nonlinear_solution.reset();
46 }
47
48
49
~AdaptiveTimeSolver()50 AdaptiveTimeSolver::~AdaptiveTimeSolver ()
51 {
52 // As an UnsteadySolver, we have an old_local_nonlinear_solution, but it
53 // is being managed by our core_time_solver. Make sure we don't delete
54 // it out from under them, in case the user wants to keep using the core
55 // solver after they're done with us.
56 old_local_nonlinear_solution.release();
57 }
58
59
60
init()61 void AdaptiveTimeSolver::init()
62 {
63 libmesh_assert(core_time_solver.get());
64
65 // We override this because our core_time_solver is the one that
66 // needs to handle new vectors, diff_solver->init(), etc
67 core_time_solver->init();
68
69 // Set the core_time_solver's solution history object to be the same one as
70 // that for the outer adaptive time solver
71 core_time_solver->set_solution_history((this->get_solution_history()));
72
73 // Now that we have set the SolutionHistory object for the coretimesolver,
74 // we set the SolutionHistory type for the timesolver to be NoSolutionHistory
75 // All storage and retrieval will be handled by the coretimesolver directly.
76 NoSolutionHistory outersolver_solution_history;
77 this->set_solution_history(outersolver_solution_history);
78
79 // As an UnsteadySolver, we have an old_local_nonlinear_solution, but it
80 // isn't pointing to the right place - fix it
81 //
82 // This leaves us with two std::unique_ptrs holding the same pointer - dangerous
83 // for future use. Replace with shared_ptr?
84 old_local_nonlinear_solution =
85 std::unique_ptr<NumericVector<Number>>(core_time_solver->old_local_nonlinear_solution.get());
86 }
87
88
89
reinit()90 void AdaptiveTimeSolver::reinit()
91 {
92 libmesh_assert(core_time_solver.get());
93
94 // We override this because our core_time_solver is the one that
95 // needs to handle new vectors, diff_solver->reinit(), etc
96 core_time_solver->reinit();
97 }
98
99
advance_timestep()100 void AdaptiveTimeSolver::advance_timestep ()
101 {
102 // The first access of advance_timestep happens via solve, not user code
103 // It is used here to store any initial conditions data
104 if (!first_solve)
105 {
106 _system.time += this->completedtimestep_deltat;
107 }
108 else
109 {
110 // We are here because of a call to advance_timestep that happens
111 // via solve, the very first solve. All we are doing here is storing
112 // the initial condition. The actual solution computed via this solve
113 // will be stored when we call advance_timestep in the user's timestep loop
114 first_solve = false;
115 }
116
117 // Remember that for the adaptive time solver, all SH operations
118 // are handled by the core_time_solver's SH object
119 // The outer solver's SH object is turned into a dummy NSH object
120 // after it has been used to initialize the core_time_solver's SH object
121
122 NumericVector<Number> & old_nonlinear_soln =
123 _system.get_vector("_old_nonlinear_solution");
124 NumericVector<Number> & nonlinear_solution =
125 *(_system.solution);
126
127 old_nonlinear_soln = nonlinear_solution;
128
129 old_nonlinear_soln.localize
130 (*old_local_nonlinear_solution,
131 _system.get_dof_map().get_send_list());
132 }
133
adjoint_advance_timestep()134 void AdaptiveTimeSolver::adjoint_advance_timestep ()
135 {
136 // All calls to adjoint_advance_timestep are made in the user's
137 // code. This first call is made immediately after the adjoint initial conditions
138 // are set. This is in the user code outside the adjoint time loop.
139 if (!first_adjoint_step)
140 {
141 // The adjoint system has been solved. We need to store the adjoint solution and
142 // load the primal solutions for the next time instance (t - delta_ti).
143 _system.time -= this->completedtimestep_deltat;
144 }
145 else
146 {
147 // After setting the initial conditions, we have to retrieve the saved primal solutions
148 core_time_solver->get_solution_history().retrieve(true, _system.time);
149
150 // And store the adjoint initial condition, apart from the initial condition these retrieval
151 // and store operations are handled by the core time solver directly
152 core_time_solver->get_solution_history().store(true, _system.time);
153
154 // We also need to tell the core time solver that the adjoint initial conditions have been set
155 core_time_solver->set_first_adjoint_step(false);
156
157 // The first adjoint step simply saves the given adjoint initial condition
158 // So there is a store, but no solve, no actual timestep, so no need to change system time
159 first_adjoint_step = false;
160 }
161
162 // For an adaptive time solver, all solution history operations are handled
163 // by the core time solver.
164
165 // Dont forget to localize the old_nonlinear_solution !
166 _system.get_vector("_old_nonlinear_solution").localize
167 (*old_local_nonlinear_solution,
168 _system.get_dof_map().get_send_list());
169 }
170
retrieve_timestep()171 void AdaptiveTimeSolver::retrieve_timestep ()
172 {
173 // Ask the core time solver to retrieve all the stored vectors
174 // at the current time
175 core_time_solver->retrieve_timestep();
176 }
177
error_order()178 Real AdaptiveTimeSolver::error_order () const
179 {
180 libmesh_assert(core_time_solver.get());
181
182 return core_time_solver->error_order();
183 }
184
185
186
element_residual(bool request_jacobian,DiffContext & context)187 bool AdaptiveTimeSolver::element_residual (bool request_jacobian,
188 DiffContext & context)
189 {
190 libmesh_assert(core_time_solver.get());
191
192 return core_time_solver->element_residual(request_jacobian, context);
193 }
194
195
196
side_residual(bool request_jacobian,DiffContext & context)197 bool AdaptiveTimeSolver::side_residual (bool request_jacobian,
198 DiffContext & context)
199 {
200 libmesh_assert(core_time_solver.get());
201
202 return core_time_solver->side_residual(request_jacobian, context);
203 }
204
205
206
nonlocal_residual(bool request_jacobian,DiffContext & context)207 bool AdaptiveTimeSolver::nonlocal_residual (bool request_jacobian,
208 DiffContext & context)
209 {
210 libmesh_assert(core_time_solver.get());
211
212 return core_time_solver->nonlocal_residual(request_jacobian, context);
213 }
214
215
216
diff_solver()217 std::unique_ptr<DiffSolver> & AdaptiveTimeSolver::diff_solver()
218 {
219 return core_time_solver->diff_solver();
220 }
221
222
223
linear_solver()224 std::unique_ptr<LinearSolver<Number>> & AdaptiveTimeSolver::linear_solver()
225 {
226 return core_time_solver->linear_solver();
227 }
228
229
230
calculate_norm(System & s,NumericVector<Number> & v)231 Real AdaptiveTimeSolver::calculate_norm(System & s,
232 NumericVector<Number> & v)
233 {
234 return s.calculate_norm(v, component_norm);
235 }
236
237 } // namespace libMesh
238