generalised_timesteppers.h
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-2023 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 #ifndef OOMPH_GENERALISED_TIMESTEPPERS_HEADER
27 #define OOMPH_GENERALISED_TIMESTEPPERS_HEADER
28 
29 #include <typeinfo>
30 
31 // Config header generated by autoconfig
32 #ifdef HAVE_CONFIG_H
33 #include <oomph-lib-config.h>
34 #endif
35 
36 // OOMPH-LIB headers
37 #include "timesteppers.h"
38 
39 namespace oomph
40 {
41  //======================================================================
42  /// Generalised timestepper that can serve a variety of purposes
43  /// in continuation, bifurcation detection and periodic-orbit computations.
44  /// The key generalisation is that more than one of the entries is actually
45  /// a degree of freedom in the problem. These are distinct from our
46  /// standard (implict) Timesteppers in which the only dof is the current
47  /// value (first entry in the storage scheme). These objects will typically
48  /// be used to replace exisiting timesteppers for specific tasks.
49  //====================================================================
51  {
52  protected:
53  // Set the number of entries that correspond to dof storage
55 
56  // Vector that represents the storage entries
57  // Vector<unsigned> Dof_storage_index;
58 
59  /// Constructor that can only be called by derived objects.
60  /// Pass the information directly through to the TimeStepper object
61  GeneralisedTimeStepper(const unsigned& n_tstorage,
62  const unsigned& max_deriv,
63  const unsigned& ndof_storage_entries = 1)
64  : TimeStepper(n_tstorage, max_deriv),
66  {
67  // Dof_storage_index.resize(1,0.0);
68  }
69 
70  /// Broken empty constructor
72 
73  /// Broken copy constructor
75 
76  /// Broken assignment operator
77  void operator=(const GeneralisedTimeStepper&) = delete;
78 
79  public:
80  /// Return the number of entries that correspond to dof storage
81  unsigned ndof_storage_entries() const
82  {
83  return Ndof_storage_entries;
84  }
85 
86  /// Return the i-th storage index
87  // unsigned dof_storage_index(const unsigned &i) {return
88  // Dof_storage_index[i];}
89  };
90 
91  //========================================================================
92  /// GeneralisedTimestepper used to store the arclength derivatives
93  /// and pervious solutions required in continuation problems. The data
94  /// is stored as auxilliary data in the (fake) TimeStepper so that
95  /// spatial adaptivity will be handled automatically through our standard
96  /// mechanisms. The adopted storage scheme is that the continuation
97  /// derivatives will be stored at the first auxilliary value and
98  /// the previous value will be the second auixilliary value
99  //====================================================================
101  {
102  // Store the offset for the derivatives
104 
105  // Store the offset for the current values of the dofs
107 
108  public:
109  /// Constructor for the case when we allow adaptive continuation
110  /// It can evaulate up to second derivatives, but doesn't do anything
111  /// the time-derivatives evaluate to zero.
113  : GeneralisedTimeStepper(3, 2),
116  {
117  Type = "ContinuationStorageScheme";
118  Is_steady = true;
119  }
120 
121 
122  /// Broken copy constructor
124 
125  /// Modify the scheme based on the underlying timestepper
126  void modify_storage(GeneralisedTimeStepper* const& time_stepper_pt)
127  {
128  // Get the number of "dofs" in the existing timestepper
129  this->Ndof_storage_entries = time_stepper_pt->ndof_storage_entries();
130  // Get the current amount of storage
131  unsigned n_tstorage = time_stepper_pt->ntstorage();
132 
133  // Find the offsets which is always relative to the number of dofs stored
134  // in the existing timestepper
135  Dof_derivative_offset = n_tstorage;
136  Dof_current_offset = n_tstorage + this->Ndof_storage_entries;
137 
138  // Set the new amount of storage twice the dofs to store parameter
139  // derivatives and initial values plus the original storage
140  unsigned n_new_tstorage = 2 * this->Ndof_storage_entries + n_tstorage;
141 
142  // Resize the weights accordingly
143  Weight.resize(3, n_new_tstorage, 0.0);
144  // Set the weight for the zero-th derivative which is always 1.0
145  Weight(0, 0) = 1.0;
146  }
147 
148 
149  /// Broken assignment operator
150  void operator=(const ContinuationStorageScheme&) = delete;
151 
152  /// Return the actual order of the scheme. It's a steady
153  /// scheme so it's zero, but that doesn't really make sense.
154  unsigned order() const
155  {
156  return 0;
157  }
158 
159  /// This is a steady scheme, so you can't do this
161  {
162  Is_steady = true;
163  }
164 
165  /// Broken initialisation the time-history for the Data values
166  /// corresponding to an impulsive start.
167  void assign_initial_values_impulsive(Data* const& data_pt)
168  {
170  "Cannot perform impulsive start for ContinuationStorageScheme",
171  OOMPH_CURRENT_FUNCTION,
172  OOMPH_EXCEPTION_LOCATION);
173  }
174 
175  /// Broken initialisation of
176  /// the positions for the node corresponding to an impulsive start
178  {
180  "Cannot perform impulsive start for ContinuationStorageScheme",
181  OOMPH_CURRENT_FUNCTION,
182  OOMPH_EXCEPTION_LOCATION);
183  }
184 
185  /// Broken shifting of time values
186  void shift_time_values(Data* const& data_pt)
187  {
188  throw OomphLibError(
189  "Cannot shift time values forContinuationStorageScheme",
190  OOMPH_CURRENT_FUNCTION,
191  OOMPH_EXCEPTION_LOCATION);
192  }
193 
194  /// Broken shifting of time positions
195  void shift_time_positions(Node* const& node_pt)
196  {
197  throw OomphLibError(
198  "Cannot shift time positions forContinuationStorageScheme",
199  OOMPH_CURRENT_FUNCTION,
200  OOMPH_EXCEPTION_LOCATION);
201  }
202 
203  /// Set the weights (Do nothing)
204  void set_weights() {}
205 
206  /// Number of previous values available.
207  unsigned nprev_values() const
208  {
209  return 0;
210  }
211 
212  /// Number of timestep increments that need to be stored by the scheme
213  unsigned ndt() const
214  {
215  return 0;
216  }
217 
218  /// Set consistent values of the derivatives and current value when
219  /// the data is pinned. This must be done by the "timestepper" because only
220  /// it knows the local storage scheme
221  void set_consistent_pinned_values(Data* const& data_pt)
222  {
223 #ifdef PARANOID
224  // If the data is not associated with the continuation time stepper then
225  // complain
226  if (this != data_pt->time_stepper_pt())
227  {
228  std::ostringstream error_stream;
229  error_stream
230  << "Data object " << data_pt << " has timestepper of type "
231  << typeid(data_pt->time_stepper_pt()).name() << "\n"
232  << "Please set the data's timestepper to be a "
233  << "ContinuationStorageScheme before calling this function\n";
234  throw OomphLibError(
235  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
236  }
237 #endif
238 
239  // Loop over the values in the data object
240  const unsigned n_value = data_pt->nvalue();
241  for (unsigned i = 0; i < n_value; ++i)
242  {
243  // Only bother to do anything if the value is pinned and not a copy
244  if (data_pt->is_pinned(i) && (data_pt->is_a_copy(i) == false))
245  {
246  // ASSUMPTION storage is always at the "front"
247  for (unsigned t = 0; t < this->Ndof_storage_entries; t++)
248  {
249  // Set the stored derivatve to be zero
250  data_pt->set_value(Dof_derivative_offset + t, i, 0.0);
251  // Set the stored current value to be the same as the present value
252  data_pt->set_value(Dof_current_offset + t, i, data_pt->value(t, i));
253  }
254  }
255  }
256  }
257 
258  /// Set consistent values of the derivatives and current value when
259  /// the Nodes position is pinned. This must be done by the "timestepper"
260  /// because only it knows the local storage scheme
261  void set_consistent_pinned_positions(Node* const& node_pt)
262  {
263  // Only need to do anything if this is a solid node
264  if (SolidNode* const solid_node_pt = dynamic_cast<SolidNode*>(node_pt))
265  {
266 #ifdef PARANOID
267  // If the data is not associated with the continuation time stepper then
268  // complain
269  if (this != node_pt->position_time_stepper_pt())
270  {
271  std::ostringstream error_stream;
272  error_stream
273  << "Node object " << node_pt << " has position timestepper of type "
274  << typeid(node_pt->position_time_stepper_pt()).name() << "\n"
275  << "Please set the Node's position timestepper to be a "
276  << "ContinuationStorageScheme before calling this function\n";
277  throw OomphLibError(error_stream.str(),
278  OOMPH_CURRENT_FUNCTION,
279  OOMPH_EXCEPTION_LOCATION);
280  }
281 #endif
282 
283  // Find the number of coordinates
284  const unsigned n_dim = solid_node_pt->ndim();
285  // Find the number of position types
286  const unsigned n_position_type = solid_node_pt->nposition_type();
287 
288  // Loop over physical coordinates
289  for (unsigned i = 0; i < n_dim; i++)
290  {
291  // Set the appropriate values if it's not a copy
292  if (solid_node_pt->position_is_a_copy(i) == false)
293  {
294  // Loop over generalised dofs
295  for (unsigned k = 0; k < n_position_type; k++)
296  {
297  // If it's pinned then set the "history" values
298  if (solid_node_pt->position_is_pinned(k, i))
299  {
300  for (unsigned t = 0; t < Ndof_storage_entries; t++)
301  {
302  // Set the derivative to 0
303  solid_node_pt->x_gen(Dof_derivative_offset + t, k, i) = 0.0;
304  // Set the stored current value to the present value
305  solid_node_pt->x_gen(Dof_current_offset + t, k, i) =
306  solid_node_pt->x_gen(t, k, i);
307  }
308  }
309  }
310  }
311  }
312  }
313  }
314 
315  // Return the stored derivative offset
317  {
318  return Dof_derivative_offset;
319  }
320 
321  // Return the offset for the current values
323  {
324  return Dof_current_offset;
325  }
326  };
327 
328 } // namespace oomph
329 
330 #endif
cstr elem_len * i
Definition: cfortran.h:603
char t
Definition: cfortran.h:568
GeneralisedTimestepper used to store the arclength derivatives and pervious solutions required in con...
void operator=(const ContinuationStorageScheme &)=delete
Broken assignment operator.
void shift_time_positions(Node *const &node_pt)
Broken shifting of time positions.
void assign_initial_values_impulsive(Data *const &data_pt)
Broken initialisation the time-history for the Data values corresponding to an impulsive start.
void set_consistent_pinned_values(Data *const &data_pt)
Set consistent values of the derivatives and current value when the data is pinned....
ContinuationStorageScheme(const ContinuationStorageScheme &)=delete
Broken copy constructor.
void modify_storage(GeneralisedTimeStepper *const &time_stepper_pt)
Modify the scheme based on the underlying timestepper.
void set_weights()
Set the weights (Do nothing)
void assign_initial_positions_impulsive(Node *const &node_pt)
Broken initialisation of the positions for the node corresponding to an impulsive start.
void shift_time_values(Data *const &data_pt)
Broken shifting of time values.
unsigned nprev_values() const
Number of previous values available.
unsigned order() const
Return the actual order of the scheme. It's a steady scheme so it's zero, but that doesn't really mak...
void set_consistent_pinned_positions(Node *const &node_pt)
Set consistent values of the derivatives and current value when the Nodes position is pinned....
void undo_make_steady()
This is a steady scheme, so you can't do this.
unsigned ndt() const
Number of timestep increments that need to be stored by the scheme.
ContinuationStorageScheme()
Constructor for the case when we allow adaptive continuation It can evaulate up to second derivatives...
A class that represents a collection of data; each Data object may contain many different individual ...
Definition: nodes.h:86
TimeStepper *& time_stepper_pt()
Return the pointer to the timestepper.
Definition: nodes.h:238
void set_value(const unsigned &i, const double &value_)
Set the i-th stored data value to specified value. The only reason that we require an explicit set fu...
Definition: nodes.h:271
virtual bool is_a_copy() const
Return a boolean to indicate whether the Data objact contains any copied values. A base Data object c...
Definition: nodes.h:253
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
Definition: nodes.h:483
double value(const unsigned &i) const
Return i-th stored value. This function is not virtual so that it can be inlined. This means that if ...
Definition: nodes.h:293
bool is_pinned(const unsigned &i) const
Test whether the i-th variable is pinned (1: true; 0: false).
Definition: nodes.h:417
void resize(const unsigned long &n)
Resize to a square nxn matrix; any values already present will be transfered.
Definition: matrices.h:498
Generalised timestepper that can serve a variety of purposes in continuation, bifurcation detection a...
unsigned ndof_storage_entries() const
Return the number of entries that correspond to dof storage.
void operator=(const GeneralisedTimeStepper &)=delete
Broken assignment operator.
GeneralisedTimeStepper(const GeneralisedTimeStepper &)=delete
Broken copy constructor.
GeneralisedTimeStepper()
Broken empty constructor.
GeneralisedTimeStepper(const unsigned &n_tstorage, const unsigned &max_deriv, const unsigned &ndof_storage_entries=1)
Constructor that can only be called by derived objects. Pass the information directly through to the ...
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:906
TimeStepper *& position_time_stepper_pt()
Return a pointer to the position timestepper.
Definition: nodes.h:1022
An OomphLibError object which should be thrown when an run-time error is encountered....
An OomphLibWarning object which should be created as a temporary object to issue a warning....
A Class for nodes that deform elastically (i.e. position is an unknown in the problem)....
Definition: nodes.h:1686
////////////////////////////////////////////////////////////////////// //////////////////////////////...
Definition: timesteppers.h:231
DenseMatrix< double > Weight
Storage for the weights associated with the timestepper.
Definition: timesteppers.h:237
unsigned ntstorage() const
Return the number of doubles required to represent history (one for steady)
Definition: timesteppers.h:601
std::string Type
String that indicates the type of the timestepper (e.g. "BDF", "Newmark", etc.)
Definition: timesteppers.h:241
bool Is_steady
Bool to indicate if the timestepper is steady, i.e. its time-derivatives evaluate to zero....
Definition: timesteppers.h:251
//////////////////////////////////////////////////////////////////// ////////////////////////////////...