libMesh
Loading...
Searching...
No Matches
euler_solver.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#include "libmesh/euler_solver.h"
20
21#include "libmesh/adjoint_refinement_estimator.h"
22#include "libmesh/diff_system.h"
23#include "libmesh/error_vector.h"
24#include "libmesh/int_range.h"
25#include "libmesh/numeric_vector.h"
26
27namespace libMesh
28{
29
30
31
36
37
38
39EulerSolver::~EulerSolver () = default;
40
41
42
44{
45 if (theta == 0.5)
46 return 2.;
47 return 1.;
48}
49
50
51
52
67
68
69
82
83
84
99
100
101
102bool EulerSolver::_general_residual (bool request_jacobian,
103 DiffContext & context,
104 ResFuncType mass,
105 ResFuncType damping,
106 ResFuncType time_deriv,
107 ResFuncType constraint,
108 ReinitFuncType reinit_func,
109 bool compute_second_order_eqns)
110{
111 unsigned int n_dofs = context.get_elem_solution().size();
112
113 // We might need to save the old jacobian in case one of our physics
114 // terms later is unable to update it analytically.
115 DenseMatrix<Number> old_elem_jacobian(n_dofs, n_dofs);
116 if (request_jacobian)
117 old_elem_jacobian.swap(context.get_elem_jacobian());
118
119 // Local nonlinear solution at old timestep
120 DenseVector<Number> old_elem_solution(n_dofs);
121 for (unsigned int i=0; i != n_dofs; ++i)
122 old_elem_solution(i) =
124
125 // Local time derivative of solution
126 context.get_elem_solution_rate() = context.get_elem_solution();
127 context.get_elem_solution_rate() -= old_elem_solution;
129 context.get_elem_solution_rate() *=
131
132 // If we are asked to compute residuals for second order variables,
133 // we also populate the acceleration part so the user can use that.
135 this->prepare_accel(context);
136
137 // Local nonlinear solution at time t_theta
138 DenseVector<Number> theta_solution(context.get_elem_solution());
139 theta_solution *= theta;
140 theta_solution.add(1. - theta, old_elem_solution);
141
144
145 // If a fixed solution is requested, we'll use theta_solution
147 context.get_elem_fixed_solution() = theta_solution;
148
149 // Move theta_->elem_, elem_->theta_
150 context.get_elem_solution().swap(theta_solution);
151
152 // Move the mesh into place first if necessary, set t = t_{\theta}
153 (context.*reinit_func)(theta);
154
155 // Get the time derivative at t_theta
156 bool jacobian_computed =
157 (_system.get_physics()->*time_deriv)(request_jacobian, context);
158
159 jacobian_computed = (_system.get_physics()->*mass)(jacobian_computed, context) &&
160 jacobian_computed;
161
162 // If we have second-order variables, we need to get damping terms
163 // and the velocity equations
165 {
166 jacobian_computed = (_system.get_physics()->*damping)(jacobian_computed, context) &&
167 jacobian_computed;
168
169 jacobian_computed = this->compute_second_order_eqns(jacobian_computed, context) &&
170 jacobian_computed;
171 }
172
173 // Restore the elem position if necessary, set t = t_{n+1}
174 (context.*reinit_func)(1);
175
176 // Move elem_->elem_, theta_->theta_
177 context.get_elem_solution().swap(theta_solution);
178 context.elem_solution_derivative = 1;
179
180 // Add the constraint term
181 jacobian_computed = (_system.get_physics()->*constraint)(jacobian_computed, context) &&
182 jacobian_computed;
183
184 // Add back (or restore) the old jacobian
185 if (request_jacobian)
186 {
187 if (jacobian_computed)
188 context.get_elem_jacobian() += old_elem_jacobian;
189 else
190 context.get_elem_jacobian().swap(old_elem_jacobian);
191 }
192
193 return jacobian_computed;
194}
195
197{
198 // We use a numerical integration scheme consistent with the theta used for the timesolver.
199
200 // Zero out the system.qoi vector
201 for (auto j : make_range(_system.n_qois()))
202 {
203 _system.set_qoi(j, 0.0);
204 }
205
206 // Left and right side contributions
207 std::vector<Number> left_contribution(_system.n_qois(), 0.0);
208 Number time_left = 0.0;
209 std::vector<Number> right_contribution(_system.n_qois(), 0.0);
210 Number time_right = 0.0;
211
212 time_left = _system.time;
213
214 // Base class assumes a direct steady evaluation
215 this->_system.assemble_qoi();
216
217 // Also get the spatially integrated errors for all the QoIs in the QoI set
218 for (auto j : make_range(_system.n_qois()))
219 {
220 left_contribution[j] = _system.get_qoi_value(j);
221 }
222
223 // Advance to t_j+1
225
226 time_right = _system.time;
227
228 // Load the solution at the next timestep
230
231 // Zero out the system.qoi vector
232 for (auto j : make_range(_system.n_qois()))
233 {
234 _system.set_qoi(j, 0.0);
235 }
236
237 // Base class assumes a direct steady evaluation
238 this->_system.assemble_qoi();
239
240 for(auto j : make_range(_system.n_qois()))
241 {
242 right_contribution[j] = _system.get_qoi_value(j);
243 }
244
245 // Combine the left and right side contributions as per the specified theta
246 // theta = 0.5 (Crank-Nicholson) gives the trapezoidal rule.
247 for (auto j : make_range(_system.n_qois()))
248 {
249 _system.set_qoi(j, ( ((1.0 - theta)*left_contribution[j]) + (theta*right_contribution[j]) )*(time_right - time_left));
250 }
251}
252
253#ifdef LIBMESH_ENABLE_AMR
254void EulerSolver::integrate_adjoint_refinement_error_estimate(AdjointRefinementEstimator & adjoint_refinement_error_estimator, ErrorVector & QoI_elementwise_error)
255{
256 // Currently, we only support this functionality when Backward-Euler time integration is used.
257 if (theta != 1.0)
258 libmesh_not_implemented();
259
260 // There are two possibilities regarding the integration rule we need to use for time integration.
261 // If we have a instantaneous QoI, then we need to use a left sided Riemann sum, otherwise the trapezoidal rule for temporally smooth QoIs.
262
263 // Create left and right error estimate vectors of the right size
264 std::vector<Number> qoi_error_estimates_left(_system.n_qois());
265 std::vector<Number> qoi_error_estimates_right(_system.n_qois());
266
267 // Get t_j
268 Real time_left = _system.time;
269
270 // Get f(t_j)
271 ErrorVector QoI_elementwise_error_left;
272
273 // If we are at the very initial step, the error contribution is zero,
274 // otherwise the old ajoint vector has been filled and we are the left end
275 // of a subsequent timestep or sub-timestep
276 if(old_adjoints[0] != nullptr)
277 {
278 // For evaluating the residual, we need to use the deltat that was used
279 // to get us to this solution, so we save the current deltat as next_step_deltat
280 // and set _system.deltat to the last completed deltat.
283
284 // The adjoint error estimate expression for a backwards facing step
285 // scheme needs the adjoint for the last time instant, so save the current adjoint for future use
286 for (auto j : make_range(_system.n_qois()))
287 {
288 // Swap for residual weighting
290 }
291
292 _system.update();
293
294 // The residual has to be evaluated at the last time
296
297 adjoint_refinement_error_estimator.estimate_error(_system, QoI_elementwise_error_left);
298
299 // Shift the time back
301
302 // Swap back the current and old adjoints
303 for (auto j : make_range(_system.n_qois()))
304 {
306 }
307
308 // Set the system deltat back to what it should be to march to the next time
310
311 }
312 else
313 {
314 for (auto i : index_range(QoI_elementwise_error))
315 QoI_elementwise_error_left[i] = 0.0;
316 }
317
318 // Also get the left side contributions for the spatially integrated errors for all the QoIs in the QoI set
319 for (auto j : make_range(_system.n_qois()))
320 {
321 // Skip this QoI if not in the QoI Set
322 if (adjoint_refinement_error_estimator.qoi_set().has_index(j))
323 {
324 // If we are at the initial time, the error contribution is zero
325 if(std::abs(_system.time) > TOLERANCE*sqrt(TOLERANCE))
326 {
327 qoi_error_estimates_left[j] = adjoint_refinement_error_estimator.get_global_QoI_error_estimate(j);
328 }
329 else
330 {
331 qoi_error_estimates_left[j] = 0.0;
332 }
333 }
334 }
335
336 // Advance to t_j+1
338
339 // Get t_j+1
340 Real time_right = _system.time;
341
342 // We will need to use the last step deltat for the weighted residual evaluation
344
345 // The adjoint error estimate expression for a backwards facing step
346 // scheme needs the adjoint for the last time instant, so save the current adjoint for future use
347 for (auto j : make_range(_system.n_qois()))
348 {
350 }
351
352 // Retrieve the state and adjoint vectors for the next time instant
354
355 // Swap for residual weighting
356 for (auto j : make_range(_system.n_qois()))
357 {
359 }
360
361 // Swap out the deltats as we did for the left side
364
365 // Get f(t_j+1)
366 ErrorVector QoI_elementwise_error_right;
367
368 _system.update();
369
370 // The residual has to be evaluated at the last time
372
373 adjoint_refinement_error_estimator.estimate_error(_system, QoI_elementwise_error_right);
374
375 // Shift the time back
377
378 // Set the system deltat back to what it needs to be able to march to the next time
380
381 // Swap back now that the residual weighting is done
382 for (auto j : make_range(_system.n_qois()))
383 {
385 }
386
387 // Also get the right side contributions for the spatially integrated errors for all the QoIs in the QoI set
388 for (auto j : make_range(_system.n_qois()))
389 {
390 // Skip this QoI if not in the QoI Set
391 if (adjoint_refinement_error_estimator.qoi_set().has_index(j))
392 {
393 qoi_error_estimates_right[j] = adjoint_refinement_error_estimator.get_global_QoI_error_estimate(j);
394 }
395 }
396
397 // Error contribution from this timestep
398 for (auto i : index_range(QoI_elementwise_error))
399 QoI_elementwise_error[i] = float(((QoI_elementwise_error_right[i] + QoI_elementwise_error_left[i])/2)
400 * (time_right - time_left));
401
402 // QoI set spatially integrated errors contribution from this timestep
403 for (auto j : make_range(_system.n_qois()))
404 {
405 // Skip this QoI if not in the QoI Set
406 if (adjoint_refinement_error_estimator.qoi_set().has_index(j))
407 {
408 _system.set_qoi_error_estimate(j, ( (1.0 - theta)*qoi_error_estimates_left[j] + theta*qoi_error_estimates_right[j] )*last_step_deltat);
409 }
410 }
411
412}
413#endif // LIBMESH_ENABLE_AMR
414
415} // namespace libMesh
This class implements a "brute force" goal-oriented error estimator which computes an estimate of err...
QoISet & qoi_set()
Access to the QoISet (default: weight all QoIs equally) to use when computing errors.
Number & get_global_QoI_error_estimate(unsigned int qoi_index)
This is an accessor function to access the computed global QoI error estimates.
virtual void estimate_error(const System &system, ErrorVector &error_per_cell, const NumericVector< Number > *solution_vector=nullptr, bool estimate_parent_error=false) override
This function does uniform refinements and an adjoint solve to get an adjoint solution on each cell,...
Defines a dense matrix for use in Finite Element-type computations.
void swap(DenseMatrix< T > &other_matrix)
STL-like swap method.
Defines a dense vector for use in Finite Element-type computations.
std::enable_if< ScalarTraits< T2 >::value, void >::type add(const T2 factor, const DenseVector< T3 > &vec)
Adds factor times vec to this vector.
void swap(DenseVector< T > &other_vector)
STL-like swap method.
virtual unsigned int size() const override final
This class provides all data required for a physics package (e.g.
Real elem_solution_derivative
The derivative of elem_solution with respect to the current nonlinear solution.
const DenseVector< Number > & get_elem_solution_rate() const
Accessor for element solution rate of change w.r.t.
virtual void elem_reinit(Real)
Gives derived classes the opportunity to reinitialize data (FE objects in FEMSystem,...
virtual void elem_side_reinit(Real)
Gives derived classes the opportunity to reinitialize data needed for a side integration at a new poi...
const std::vector< dof_id_type > & get_dof_indices() const
Accessor for element dof indices.
Real elem_solution_rate_derivative
The derivative of elem_solution_rate with respect to the current nonlinear solution,...
const DenseVector< Number > & get_elem_solution() const
Accessor for element solution.
Real fixed_solution_derivative
The derivative of elem_fixed_solution with respect to the nonlinear solution, for use by systems cons...
const DenseVector< Number > & get_elem_fixed_solution() const
Accessor for element fixed solution.
virtual void nonlocal_reinit(Real)
Gives derived classes the opportunity to reinitialize data needed for nonlocal calculations at a new ...
const DenseMatrix< Number > & get_elem_jacobian() const
Const accessor for element Jacobian.
virtual bool element_constraint(bool request_jacobian, DiffContext &)
Adds the constraint contribution on elem to elem_residual.
virtual bool side_mass_residual(bool request_jacobian, DiffContext &)
Subtracts a mass vector contribution on side of elem from elem_residual.
virtual bool side_time_derivative(bool request_jacobian, DiffContext &)
Adds the time derivative contribution on side of elem to elem_residual.
virtual bool side_constraint(bool request_jacobian, DiffContext &)
Adds the constraint contribution on side of elem to elem_residual.
virtual bool nonlocal_constraint(bool request_jacobian, DiffContext &)
Adds any nonlocal constraint contributions (e.g.
virtual bool nonlocal_time_derivative(bool request_jacobian, DiffContext &)
Adds any nonlocal time derivative contributions (e.g.
virtual bool nonlocal_damping_residual(bool request_jacobian, DiffContext &)
Subtracts any nonlocal damping vector contributions (e.g.
virtual bool damping_residual(bool request_jacobian, DiffContext &)
Subtracts a damping vector contribution on elem from elem_residual.
bool _eulerian_time_deriv(bool request_jacobian, DiffContext &)
This method simply combines element_time_derivative() and eulerian_residual(), which makes its addres...
virtual bool side_damping_residual(bool request_jacobian, DiffContext &)
Subtracts a damping vector contribution on side of elem from elem_residual.
virtual bool mass_residual(bool request_jacobian, DiffContext &)
Subtracts a mass vector contribution on elem from elem_residual.
virtual bool nonlocal_mass_residual(bool request_jacobian, DiffContext &c)
Subtracts any nonlocal mass vector contributions (e.g.
This class provides a specific system class.
Definition diff_system.h:57
const DifferentiablePhysics * get_physics() const
Real deltat
For time-dependent problems, this is the amount delta t to advance the solution in time.
bool have_second_order_scalar_vars() const
Check for any second order vars that are also belong to FEFamily::SCALAR.
The ErrorVector is a specialization of the StatisticsVector for error data computed on a finite eleme...
virtual ~EulerSolver()
Destructor.
virtual bool nonlocal_residual(bool request_jacobian, DiffContext &) override
This method uses the DifferentiablePhysics' nonlocal_time_derivative() and nonlocal_constraint() to b...
virtual Real error_order() const override
Error convergence order: 2 for Crank-Nicolson, 1 otherwise.
virtual void integrate_qoi_timestep() override
A method to integrate the system::QoI functionals.
virtual bool side_residual(bool request_jacobian, DiffContext &) override
This method uses the DifferentiablePhysics' side_time_derivative() and side_constraint() to build a f...
virtual void integrate_adjoint_refinement_error_estimate(AdjointRefinementEstimator &adjoint_refinement_error_estimator, ErrorVector &QoI_elementwise_error) override
A method to compute the adjoint refinement error estimate at the current timestep.
EulerSolver(sys_type &s)
Constructor.
Real theta
The value for the theta method to employ: 1.0 corresponds to backwards Euler, 0.0 corresponds to forw...
virtual bool element_residual(bool request_jacobian, DiffContext &) override
This method uses the DifferentiablePhysics' element_time_derivative() and element_constraint() to bui...
virtual bool _general_residual(bool request_jacobian, DiffContext &, ResFuncType mass, ResFuncType damping, ResFuncType time_deriv, ResFuncType constraint, ReinitFuncType reinit, bool compute_second_order_eqns)
This method is the underlying implementation of the public residual methods.
virtual void assemble_qoi(const QoISet &qoi_indices=QoISet()) override
Prepares qoi for quantity of interest assembly, then calls user qoi function.
Generic class from which first order UnsteadySolvers should subclass.
bool compute_second_order_eqns(bool compute_jacobian, DiffContext &c)
If there are second order variables, then we need to compute their residual equations and correspondi...
void prepare_accel(DiffContext &context)
If there are second order variables in the system, then we also prepare the accel for those variables...
virtual void swap(NumericVector< T > &v)
Swaps the contents of this with v.
virtual std::unique_ptr< NumericVector< T > > clone() const =0
bool has_index(std::size_t) const
Return whether or not this index is in the set to be calculated.
Definition qoi_set.h:224
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
void set_qoi(unsigned int qoi_index, Number qoi_value)
Definition system.C:2176
Number get_qoi_value(unsigned int qoi_index) const
Definition system.C:2184
Real time
For time-dependent problems, this is the time t at the beginning of the current timestep.
Definition system.h:1677
unsigned int n_qois() const
Number of currently active quantities of interest.
Definition system.h:2562
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition system.C:498
void set_qoi_error_estimate(unsigned int qoi_index, Number qoi_error_estimate)
Definition system.C:2204
NumericVector< Number > & get_adjoint_solution(unsigned int i=0)
Definition system.C:1232
sys_type & _system
A reference to the system we are solving.
std::vector< std::unique_ptr< NumericVector< Number > > > old_adjoints
A vector of pointers to vectors holding the adjoint solution at the last time step.
virtual void retrieve_timestep() override
This method retrieves all the stored solutions at the current system.time.
Number old_nonlinear_solution(const dof_id_type global_dof_number) const
Real last_step_deltat
We will need to move the system.time around to ensure that residuals are built with the right deltat ...
The libMesh namespace provides an interface to certain functionality in the library.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
static constexpr Real TOLERANCE
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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:176