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