libMesh
Loading...
Searching...
No Matches
newmark_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#include "libmesh/newmark_solver.h"
19
20#include "libmesh/diff_solver.h"
21#include "libmesh/diff_system.h"
22#include "libmesh/dof_map.h"
23#include "libmesh/numeric_vector.h"
24
25namespace libMesh
26{
29 _beta(0.25),
30 _gamma(0.5),
31 _is_accel_solve(false),
32 _initial_accel_set(false)
33{}
34
36
38{
39 if (_gamma == 0.5)
40 return 2.;
41 return 1.;
42}
43
45{
46 // We need to update velocity and acceleration before
47 // we update the nonlinear solution (displacement) and
48 // delta_t
49
51 _system.get_vector("_old_solution_rate");
52
54 _system.get_vector("_old_solution_accel");
55
56 if (!first_solve)
57 {
58 NumericVector<Number> & old_nonlinear_soln =
59 _system.get_vector("_old_nonlinear_solution");
60
61 NumericVector<Number> & nonlinear_solution =
63
64 // We need to cache the new solution_rate before updating the old_solution_rate
65 // so we can update acceleration with the proper old_solution_rate
66 // v_{n+1} = gamma/(beta*Delta t)*(x_{n+1}-x_n)
67 // - ((gamma/beta)-1)*v_n
68 // - (gamma/(2*beta)-1)*(Delta t)*a_n
69 std::unique_ptr<NumericVector<Number>> new_solution_rate = nonlinear_solution.clone();
70 (*new_solution_rate) -= old_nonlinear_soln;
71 (*new_solution_rate) *= (_gamma/(_beta*_system.deltat));
72 new_solution_rate->add( (1.0-_gamma/_beta), old_solution_rate );
73 new_solution_rate->add( (1.0-_gamma/(2.0*_beta))*_system.deltat, old_solution_accel );
74
75 // a_{n+1} = (1/(beta*(Delta t)^2))*(x_{n+1}-x_n)
76 // - 1/(beta*Delta t)*v_n
77 // - (1-1/(2*beta))*a_n
78 std::unique_ptr<NumericVector<Number>> new_solution_accel = old_solution_accel.clone();
79 (*new_solution_accel) *= -(1.0/(2.0*_beta)-1.0);
80 new_solution_accel->add( -1.0/(_beta*_system.deltat), old_solution_rate );
81 new_solution_accel->add( 1.0/(_beta*_system.deltat*_system.deltat), nonlinear_solution );
82 new_solution_accel->add( -1.0/(_beta*_system.deltat*_system.deltat), old_nonlinear_soln );
83
84 // Now update old_solution_rate
85 old_solution_rate = (*new_solution_rate);
86 old_solution_accel = (*new_solution_accel);
87 }
88
89 // Localize updated vectors
90 old_solution_rate.localize
93
94 old_solution_accel.localize
97
98 // Now we can finish advancing the timestep
100}
101
103{
104 libmesh_not_implemented();
105}
106
108{
109 // We need to compute the initial acceleration based off of
110 // the initial position and velocity and, thus, acceleration
111 // is the unknown in diff_solver and not the displacement. So,
112 // We swap solution and acceleration. NewmarkSolver::_general_residual
113 // will check _is_accel_solve and provide the correct
114 // values to the FEMContext assuming this swap was made.
115 this->_is_accel_solve = true;
116
117 //solution->accel, accel->solution
118 _system.solution->swap(_system.get_vector("_old_solution_accel"));
119 _system.update();
120
121 this->_diff_solver->solve();
122
123 // solution->solution, accel->accel
124 _system.solution->swap(_system.get_vector("_old_solution_accel"));
125 _system.update();
126
127 // We're done, so no longer doing an acceleration solve
128 this->_is_accel_solve = false;
129
130 this->set_initial_accel_avail(true);
131}
132
143
144void NewmarkSolver::set_initial_accel_avail( bool initial_accel_set )
145{
146 _initial_accel_set = initial_accel_set;
147}
148
150{
151 // First, check that the initial accel was set one way or another
152 libmesh_error_msg_if(!_initial_accel_set,
153 "ERROR: Must first set initial acceleration using one of:\n"
154 "NewmarkSolver::compute_initial_accel()\n"
155 "NewmarkSolver::project_initial_accel()\n");
156
157 // That satisfied, now we can solve
159}
160
172
173
174
186
187
188
200
201
202
203bool NewmarkSolver::_general_residual (bool request_jacobian,
204 DiffContext & context,
205 ResFuncType mass,
206 ResFuncType damping,
207 ResFuncType time_deriv,
208 ResFuncType constraint,
209 ReinitFuncType reinit_func)
210{
211 unsigned int n_dofs = context.get_elem_solution().size();
212
213 // We might need to save the old jacobian in case one of our physics
214 // terms later is unable to update it analytically.
215 DenseMatrix<Number> old_elem_jacobian(n_dofs, n_dofs);
216
217 // Local velocity at old time step
218 DenseVector<Number> old_elem_solution_rate(n_dofs);
219 for (unsigned int i=0; i != n_dofs; ++i)
220 old_elem_solution_rate(i) =
222
223 // The user is computing the initial acceleration
224 // So upstream we've swapped _system.solution and _old_local_solution_accel
225 // So we need to give the context the correct entries since we're solving for
226 // acceleration here.
227 if (_is_accel_solve)
228 {
229 // System._solution is actually the acceleration right now so we need
230 // to reset the elem_solution to the right thing, which in this case
231 // is the initial guess for displacement, which got swapped into
232 // _old_solution_accel vector
233 DenseVector<Number> old_elem_solution(n_dofs);
234 for (unsigned int i=0; i != n_dofs; ++i)
235 old_elem_solution(i) =
237
238 context.elem_solution_derivative = 0.0;
239 context.elem_solution_rate_derivative = 0.0;
240 context.elem_solution_accel_derivative = 1.0;
241
242 // Acceleration is currently the unknown so it's already sitting
243 // in elem_solution() thanks to FEMContext::pre_fe_reinit
244 context.get_elem_solution_accel() = context.get_elem_solution();
245
246 // Now reset elem_solution() to what the user is expecting
247 context.get_elem_solution() = old_elem_solution;
248
249 context.get_elem_solution_rate() = old_elem_solution_rate;
250
251 // The user's Jacobians will be targeting derivatives w.r.t. u_{n+1}.
252 // Although the vast majority of cases will have the correct analytic
253 // Jacobians in this iteration, since we reset elem_solution_derivative*,
254 // if there are coupled/overlapping problems, there could be
255 // mismatches in the Jacobian. So we force finite differencing for
256 // the first iteration.
257 request_jacobian = false;
258 }
259 // Otherwise, the unknowns are the displacements and everything is straight
260 // forward and is what you think it is
261 else
262 {
263 if (request_jacobian)
264 old_elem_jacobian.swap(context.get_elem_jacobian());
265
266 // Local displacement at old timestep
267 DenseVector<Number> old_elem_solution(n_dofs);
268 for (unsigned int i=0; i != n_dofs; ++i)
269 old_elem_solution(i) =
271
272 // Local acceleration at old time step
273 DenseVector<Number> old_elem_solution_accel(n_dofs);
274 for (unsigned int i=0; i != n_dofs; ++i)
275 old_elem_solution_accel(i) =
277
278 // Convenience
280
281 context.elem_solution_derivative = 1.0;
282
283 // Local velocity at current time step
284 // v_{n+1} = gamma/(beta*Delta t)*(x_{n+1}-x_n)
285 // + (1-(gamma/beta))*v_n
286 // + (1-gamma/(2*beta))*(Delta t)*a_n
288
289 context.get_elem_solution_rate() = context.get_elem_solution();
290 context.get_elem_solution_rate() -= old_elem_solution;
292 context.get_elem_solution_rate().add( (1.0-_gamma/_beta), old_elem_solution_rate);
293 context.get_elem_solution_rate().add( (1.0-_gamma/(2.0*_beta))*dt, old_elem_solution_accel);
294
295
296
297 // Local acceleration at current time step
298 // a_{n+1} = (1/(beta*(Delta t)^2))*(x_{n+1}-x_n)
299 // - 1/(beta*Delta t)*v_n
300 // - (1/(2*beta)-1)*a_n
301 context.elem_solution_accel_derivative = 1.0/(_beta*dt*dt);
302
303 context.get_elem_solution_accel() = context.get_elem_solution();
304 context.get_elem_solution_accel() -= old_elem_solution;
306 context.get_elem_solution_accel().add(-1.0/(_beta*dt), old_elem_solution_rate);
307 context.get_elem_solution_accel().add(-(1.0/(2.0*_beta)-1.0), old_elem_solution_accel);
308
309 // Move the mesh into place first if necessary, set t = t_{n+1}
310 (context.*reinit_func)(1.);
311 }
312
313 // If a fixed solution is requested, we'll use x_{n+1}
315 context.get_elem_fixed_solution() = context.get_elem_solution();
316
317 // Get the time derivative at t_{n+1}, F(u_{n+1})
318 bool jacobian_computed = (_system.get_physics()->*time_deriv)(request_jacobian, context);
319
320 // Damping at t_{n+1}, C(u_{n+1})
321 jacobian_computed = (_system.get_physics()->*damping)(jacobian_computed, context) &&
322 jacobian_computed;
323
324 // Mass at t_{n+1}, M(u_{n+1})
325 jacobian_computed = (_system.get_physics()->*mass)(jacobian_computed, context) &&
326 jacobian_computed;
327
328 // Add the constraint term
329 jacobian_computed = (_system.get_physics()->*constraint)(jacobian_computed, context) &&
330 jacobian_computed;
331
332 // Add back (or restore) the old jacobian
333 if (request_jacobian)
334 {
335 if (jacobian_computed)
336 context.get_elem_jacobian() += old_elem_jacobian;
337 else
338 context.get_elem_jacobian().swap(old_elem_jacobian);
339 }
340
341 return jacobian_computed;
342}
343
344}
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.
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.
Real elem_solution_accel_derivative
The derivative of elem_solution_accel with respect to the current nonlinear solution,...
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.
const DenseVector< Number > & get_elem_solution_accel() const
Accessor for element solution accel of change w.r.t.
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.
const std::vector< dof_id_type > & get_send_list() const
Definition dof_map.h:533
Base class for functors that can be evaluated at a point and (optionally) time.
virtual void adjoint_advance_timestep() override
This method advances the adjoint solution to the previous timestep, after an adjoint_solve() has been...
bool _is_accel_solve
Need to be able to indicate to _general_residual if we are doing an acceleration solve or not.
virtual ~NewmarkSolver()
Destructor.
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 bool nonlocal_residual(bool request_jacobian, DiffContext &) override
This method uses the DifferentiablePhysics' nonlocal_time_derivative() and nonlocal_constraint() to b...
void project_initial_accel(FunctionBase< Number > *f, FunctionBase< Gradient > *g=nullptr)
Specify non-zero initial acceleration.
Real _gamma
The value for to employ.
Real _beta
The value for the to employ.
virtual void solve() override
This method solves for the solution at the next timestep.
bool _initial_accel_set
This method requires an initial acceleration.
virtual void compute_initial_accel()
This method uses the specified initial displacement and velocity to compute the initial acceleration ...
NewmarkSolver(sys_type &s)
Constructor.
virtual bool _general_residual(bool request_jacobian, DiffContext &, ResFuncType mass, ResFuncType damping, ResFuncType time_deriv, ResFuncType constraint, ReinitFuncType reinit)
This method is the underlying implementation of the public residual methods.
virtual void advance_timestep() override
This method advances the solution to the next timestep, after a solve() has been performed.
virtual Real error_order() const override
Error convergence order: 2 for , 1 otherwise.
void set_initial_accel_avail(bool initial_accel_set)
Allow the user to (re)set whether the initial acceleration is available.
virtual bool element_residual(bool request_jacobian, DiffContext &) override
This method uses the DifferentiablePhysics' element_time_derivative() and element_constraint() to bui...
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
virtual std::unique_ptr< NumericVector< T > > clone() const =0
virtual void add(const numeric_index_type i, const T value)=0
Adds value to the vector entry specified by i.
Generic class from which second order UnsteadySolvers should subclass.
std::unique_ptr< NumericVector< Number > > _old_local_solution_rate
Serial vector of previous time step velocity .
Number old_solution_accel(const dof_id_type global_dof_number) const
Number old_solution_rate(const dof_id_type global_dof_number) const
std::unique_ptr< NumericVector< Number > > _old_local_solution_accel
Serial vector of previous time step acceleration .
void project_vector(NumericVector< Number > &new_vector, FunctionBase< Number > *f, FunctionBase< Gradient > *g=nullptr, int is_adjoint=-1, std::optional< ConstElemRange > active_local_range=std::nullopt, std::optional< std::vector< unsigned int > > variable_numbers=std::nullopt) const
Projects arbitrary functions onto a vector of degree of freedom values for the current system.
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
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition system.h:1655
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition system.C:498
const DofMap & get_dof_map() const
Definition system.h:2417
const NumericVector< Number > & get_vector(std::string_view vec_name) const
Definition system.C:931
sys_type & _system
A reference to the system we are solving.
std::unique_ptr< DiffSolver > _diff_solver
An implicit linear or nonlinear solver to use at each timestep.
virtual void advance_timestep() override
This method advances the solution to the next timestep, after a solve() has been performed.
Number old_nonlinear_solution(const dof_id_type global_dof_number) const
virtual void solve() override
This method solves for the solution at the next timestep.
bool first_solve
A bool that will be true the first time solve() is called, and false thereafter.
The libMesh namespace provides an interface to certain functionality in the library.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real