implicit_midpoint_rule.cc
Go to the documentation of this file.
1// LIC// ====================================================================
2// LIC// This file forms part of oomph-lib, the object-oriented,
3// LIC// multi-physics finite-element library, available
4// LIC// at http://www.oomph-lib.org.
5// LIC//
6// LIC// Copyright (C) 2006-2025 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
26
28#include "problem.h"
29
30// Needed for mipoint update...
31#include "mesh.h"
32#include "elements.h"
33#include "nodes.h"
34
35namespace oomph
36{
37 /// This function advances the Data's time history so that
38 /// we can move on to the next timestep
40 {
41 // Loop over the values, set previous values to the previous value, if
42 // not a copy.
43 for (unsigned j = 0, nj = data_pt->nvalue(); j < nj; j++)
44 {
45 if (!data_pt->is_a_copy(j))
46 {
47 for (unsigned t = ndt(); t > 0; t--)
48 {
49 data_pt->set_value(t, j, data_pt->value(t - 1, j));
50 }
51 }
52 }
53 }
54
55 /// This function advances the time history of the positions
56 /// at a node. ??ds Untested: I have no problems with moving nodes.
57 void IMRBase::shift_time_positions(Node* const& node_pt)
58 {
59 // Find the number of coordinates
60 unsigned n_dim = node_pt->ndim();
61 // Find the number of position types
62 unsigned n_position_type = node_pt->nposition_type();
63
64 // Find number of stored timesteps
65 unsigned n_tstorage = ntstorage();
66
67 // Storage for the velocity
69
70 // If adaptive, find the velocities
71 if (adaptive_flag())
72 {
73 // Loop over the variables
74 for (unsigned i = 0; i < n_dim; i++)
75 {
76 for (unsigned k = 0; k < n_position_type; k++)
77 {
78 // Initialise velocity to zero
79 velocity[k][i] = 0.0;
80 // Loop over all history data
81 for (unsigned t = 0; t < n_tstorage; t++)
82 {
83 velocity[k][i] += Weight(1, t) * node_pt->x_gen(t, k, i);
84 }
85 }
86 }
87 }
88
89 // Loop over the positions
90 for (unsigned i = 0; i < n_dim; i++)
91 {
92 // If the position is not a copy
93 if (node_pt->position_is_a_copy(i) == false)
94 {
95 // Loop over the position types
96 for (unsigned k = 0; k < n_position_type; k++)
97 {
98 // Loop over stored times, and set values to previous values
99 for (unsigned t = ndt(); t > 0; t--)
100 {
101 node_pt->x_gen(t, k, i) = node_pt->x_gen(t - 1, k, i);
102 }
103 }
104 }
105 }
106 }
107
108
109 /// Dummy - just check that the values that
110 /// problem::calculate_predicted_values() has been called right.
112 {
113 if (adaptive_flag())
114 {
115 // Can't do it here, but we can check that the predicted values have
116 // been updated.
118 }
119 }
120
121
123 const unsigned& i)
124 {
125 if (adaptive_flag())
126 {
127 // predicted value is more accurate so just compare with that
128 return data_pt->value(i) - data_pt->value(Predictor_storage_index, i);
129 }
130 else
131 {
132 std::string err("Tried to get the temporal error from a non-adaptive");
133 err += " time stepper.";
134 throw OomphLibError(
136 }
137 }
138
139 /// Half the timestep before starting solve
141 {
142 // Check that this is the only time stepper
143#ifdef PARANOID
144 if (problem_pt->ntime_stepper() != 1)
145 {
146 std::string err = "This implementation of midpoint can only work with a ";
147 err += "single time stepper, try using IMR instead (but check ";
148 err += "your Jacobian and residual calculations very carefully for "
149 "compatability).";
150 throw OomphLibError(
152 }
153#endif
154
155 time_pt()->dt() /= 2;
156 time_pt()->time() -= time_pt()->dt();
157
158 // Set the weights again because we just changed the step size
159 set_weights();
160
161
163 {
164 // Shift the initial guess to the midpoint so that it is an initial
165 // guess for the newton step that we actually take.
166
167 // Optimisation possiblity: here we update all values three time
168 // (initial prediction, copy into initial guess, interpolate to
169 // midpoint), could probably avoid this with more fancy code if
170 // needed.
171
172 // Get dofs at previous time step
174 problem_pt->get_dofs(1, dof_n);
175
176 // Update dofs at current step to be the average of current and previous
177 for (unsigned i = 0; i < problem_pt->ndof(); i++)
178 {
179 problem_pt->dof(i) = (problem_pt->dof(i) + dof_n[i]) / 2;
180 }
181 }
182 }
183
184 /// Local (not exported in header) helper function to handle midpoint
185 /// update on a data object.
187 {
188 if (!dat_pt->is_a_copy())
189 {
190 for (unsigned j = 0, nj = dat_pt->nvalue(); j < nj; j++)
191 {
192 int eqn = dat_pt->eqn_number(j);
193 if (update_pinned || eqn >= 0)
194 {
195 double ynp1 = 2 * dat_pt->value(0, j) - dat_pt->value(1, j);
196 dat_pt->set_value(0, j, ynp1);
197 }
198 }
199 }
200 }
201
202 /// Take problem from t={n+1/2} to t=n+1 by algebraic update and restore
203 /// time step.
205 {
206#ifdef PARANOID
207 // Do it as dofs too to compare
208 const unsigned ndof = problem_pt->ndof();
210 problem_pt->get_dofs(1, dof_n);
211 problem_pt->get_dofs(dof_np1);
212
213 for (unsigned i = 0; i < ndof; i++)
214 {
215 dof_np1[i] += dof_np1[i] - dof_n[i];
216 }
217#endif
218
219 // First deal with global data
220 for (unsigned i = 0, ni = problem_pt->nglobal_data(); i < ni; i++)
221 {
223 }
224
225 // Next element internal data
226 for (unsigned i = 0, ni = problem_pt->mesh_pt()->nelement(); i < ni; i++)
227 {
228 GeneralisedElement* ele_pt = problem_pt->mesh_pt()->element_pt(i);
229 for (unsigned j = 0, nj = ele_pt->ninternal_data(); j < nj; j++)
230 {
232 }
233 }
234
235 // Now the nodes
236 for (unsigned i = 0, ni = problem_pt->mesh_pt()->nnode(); i < ni; i++)
237 {
239 }
240
241 // Update time
242 problem_pt->time_pt()->time() += problem_pt->time_pt()->dt();
243
244 // Return step size to its full value
245 problem_pt->time_pt()->dt() *= 2;
246
247#ifdef PARANOID
248 using namespace StringConversion;
250 problem_pt->get_dofs(actual_dof_np1);
251
252 for (unsigned j = 0; j < actual_dof_np1.nrow(); j++)
253 {
254 if (std::abs(actual_dof_np1[j] - dof_np1[j]) > 1e-8)
255 {
256 std::string err = "Got different values doing midpoint update via "
257 "extracted dofs than doing it in place!";
258 err += to_string(actual_dof_np1[j]) + " vs " + to_string(dof_np1[j]);
259 throw OomphLibError(
261 }
262 }
263
264#endif
265 }
266
267} // namespace oomph
e
Definition cfortran.h:571
cstr elem_len * i
Definition cfortran.h:603
char t
Definition cfortran.h:568
A class that represents a collection of data; each Data object may contain many different individual ...
Definition nodes.h:86
A vector in the mathematical sense, initially developed for linear algebra type applications....
A Generalised Element class.
Definition elements.h:73
unsigned long eqn_number(const unsigned &ieqn_local) const
Return the global equation number corresponding to the ieqn_local-th local equation number.
Definition elements.h:691
Data *& internal_data_pt(const unsigned &i)
Return a pointer to i-th internal data object.
Definition elements.h:605
unsigned ninternal_data() const
Return the number of internal data objects.
Definition elements.h:810
void calculate_predicted_values(Data *const &data_pt)
Dummy - just check that the values that problem::calculate_predicted_values() has been called right.
void shift_time_values(Data *const &data_pt)
This function advances the Data's time history so that we can move on to the next timestep.
void shift_time_positions(Node *const &node_pt)
This function advances the time history of the positions at a node.
unsigned ndt() const
Number of timestep increments that are required by the scheme.
double temporal_error_in_value(Data *const &data_pt, const unsigned &i)
Compute the error in the value i in a Data structure zero here – overwrite for specific scheme.
bool Update_pinned
Should we update pinned variables after the half-step?
void actions_after_timestep(Problem *problem_pt)
Take problem from t={n+1/2} to t=n+1 by algebraic update and restore time step.
void set_weights()
Setup weights for time derivative calculations.
void actions_before_timestep(Problem *problem_pt)
Half the timestep before starting solve.
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Definition mesh.h:440
unsigned long nnode() const
Return number of nodes in the mesh.
Definition mesh.h:604
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition mesh.h:452
unsigned long nelement() const
Return number of elements in the mesh.
Definition mesh.h:598
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition nodes.h:906
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition nodes.h:1054
virtual bool position_is_a_copy() const
Return whether any position coordinate has been copied (always false)
Definition nodes.h:1113
unsigned nposition_type() const
Number of coordinate types needed in the mapping between local and global coordinates.
Definition nodes.h:1016
double & x_gen(const unsigned &k, const unsigned &i)
Reference to the generalised position x(k,i). ‘Type’: k; Coordinate direction: i.
Definition nodes.h:1126
An OomphLibError object which should be thrown when an run-time error is encountered....
////////////////////////////////////////////////////////////////// //////////////////////////////////...
Definition problem.h:154
unsigned long ndof() const
Return the number of dofs.
Definition problem.h:1704
double & dof(const unsigned &i)
i-th dof in the problem
Definition problem.h:1843
bool & use_predictor_values_as_initial_guess()
Definition problem.h:2099
unsigned nglobal_data() const
Return the number of global data values.
Definition problem.h:1716
Data *& global_data_pt(const unsigned &i)
Return a pointer to the the i-th global data object.
Definition problem.h:1673
unsigned ntime_stepper() const
Return the number of time steppers.
Definition problem.h:1710
Mesh *& mesh_pt()
Return a pointer to the global mesh.
Definition problem.h:1300
void get_dofs(DoubleVector &dofs) const
Return the vector of dofs, i.e. a vector containing the current values of all unknowns.
Definition problem.cc:2575
Time *& time_pt()
Return a pointer to the global time object.
Definition problem.h:1524
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
DenseMatrix< double > Weight
Storage for the weights associated with the timestepper.
void check_predicted_values_up_to_date() const
Check that the predicted values are the ones we want.
unsigned ntstorage() const
Return the number of doubles required to represent history (one for steady)
bool adaptive_flag() const
Function to indicate whether the scheme is adaptive (false by default)
Time *const & time_pt() const
Access function for the pointer to time (const version)
int Predictor_storage_index
The time-index in each Data object where predicted values are stored. -1 if not set.
double & time()
Return the current value of the continuous time.
double & dt(const unsigned &t=0)
Return the value of the t-th stored timestep (t=0: present; t>0: previous).
std::string to_string(T object, unsigned float_precision=8)
Conversion function that should work for anything with operator<< defined (at least all basic types).
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
void post_midpoint_update(Data *dat_pt, const bool &update_pinned)
Local (not exported in header) helper function to handle midpoint update on a data object.