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-2022 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 // This header contains classes and function prototypes for the Time,
27 // TimeStepper and derived objects
28 
29 // Include guard to prevent multiple inclusions of the header
30 #ifndef OOMPH_TIME_STEPPERS_HEADER
31 #define OOMPH_TIME_STEPPERS_HEADER
32 
33 // Config header generated by autoconfig
34 #ifdef HAVE_CONFIG_H
35 #include <oomph-lib-config.h>
36 #endif
37 
38 #ifdef OOMPH_HAS_MPI
39 #include "mpi.h"
40 #endif
41 
42 // oomph-lib headers
43 #include "Vector.h"
44 #include "nodes.h"
45 #include "matrices.h"
46 
47 namespace oomph
48 {
49  class Problem;
50  class ExplicitTimeStepper;
51 
52  //====================================================================
61  //====================================================================
62  class Time
63  {
64  private:
67 
70 
71  public:
74  Time() : Continuous_time(0.0) {}
75 
78  Time(const unsigned& ndt) : Continuous_time(0.0)
79  {
80  // Allocate memory for the timestep storage and initialise values to one
81  // to avoid division by zero.
82  Dt.resize(ndt, 1.0);
83  }
84 
86  Time(const Time&) = delete;
87 
89  void operator=(const Time&) = delete;
90 
93  void resize(const unsigned& n_dt)
94  {
95  Dt.resize(n_dt, 0.0);
96  }
97 
99  void initialise_dt(const double& dt_)
100  {
101  unsigned ndt = Dt.size();
102  Dt.assign(ndt, dt_);
103  }
104 
107  void initialise_dt(const Vector<double>& dt_)
108  {
109  // Assign the values from the vector dt_, but preserve the size of Dt and
110  // any Dt[i] s.t. i > dt_.size() (which is why we can't just use
111  // assignment operator).
112  unsigned n_dt = dt_.size();
113  for (unsigned i = 0; i < n_dt; i++)
114  {
115  Dt[i] = dt_[i];
116  }
117  }
118 
120  ~Time() {}
121 
123  double& time()
124  {
125  return Continuous_time;
126  }
127 
129  unsigned ndt() const
130  {
131  return Dt.size();
132  }
133 
136  double& dt(const unsigned& t = 0)
137  {
138  return Dt[t];
139  }
140 
143  double dt(const unsigned& t = 0) const
144  {
145  return Dt[t];
146  }
147 
150  double time(const unsigned& t = 0) const
151  {
152 #ifdef PARANOID
153  if (t > ndt())
154  {
155  using namespace StringConversion;
156  std::string error_msg = "Timestep " + to_string(t) + " out of range!";
157  throw OomphLibError(
159  }
160 #endif
161  // Load the current value of the time
162  double time_local = Continuous_time;
163  // Loop over the t previous timesteps and subtract each dt
164  for (unsigned i = 0; i < t; i++)
165  {
166  time_local -= Dt[i];
167  }
168  return time_local;
169  }
170 
174  void shift_dt()
175  {
176  unsigned n_dt = Dt.size();
177  // Return straight away if there are no stored timesteps
178  if (n_dt == 0)
179  {
180  return;
181  }
182  // Start from the end of the array and shift every entry back by one
183  for (unsigned i = (n_dt - 1); i > 0; i--)
184  {
185  Dt[i] = Dt[i - 1];
186  }
187  }
188  };
189 
190 
194 
195 
196  //====================================================================
229  //====================================================================
231  {
232  protected:
235 
238 
242 
246 
251  bool Is_steady;
252 
257 
261 
266 
270 
274 
275  public:
279  TimeStepper(const unsigned& tstorage, const unsigned& max_deriv)
280  : Time_pt(0),
281  Adaptive_Flag(false),
282  Is_steady(false),
283  Shut_up_in_assign_initial_data_values(false),
284  Predict_by_explicit_step(false)
285  {
286  // Resize Weights matrix and initialise each weight to zero
287  Weight.resize(max_deriv + 1, tstorage, 0.0);
288 
289  // Set the weight for zero-th derivative, which is always 1.0
290  Weight(0, 0) = 1.0;
291 
292  // Set predictor storage index to negative value so that we can catch
293  // cases where it has not been set to a correct value by the inheriting
294  // constructor.
295  Predictor_storage_index = -1;
296 
297  Explicit_predictor_pt = 0;
298  }
299 
302  {
303  throw OomphLibError("Don't call default constructor for TimeStepper!",
306  }
307 
309  TimeStepper(const TimeStepper&) = delete;
310 
312  void operator=(const TimeStepper&) = delete;
313 
315  virtual ~TimeStepper();
316 
318  unsigned highest_derivative() const
319  {
320  return Weight.nrow() - 1;
321  }
322 
324  virtual unsigned order() const
325  {
326  return 0;
327  }
328 
330  // (can't have a paranoid test for null pointers because this could be
331  // used as a set function)
332  double& time()
333  {
334  return Time_pt->time();
335  }
336 
338  double time() const
339  {
340 #ifdef PARANOID
341  if (Time_pt == 0)
342  {
343  std::string error_msg = "Time pointer is null!";
344  throw OomphLibError(
346  }
347 #endif
348  return Time_pt->time();
349  }
350 
352  virtual unsigned ndt() const = 0;
353 
360  {
361  return 1;
362  }
363 
365  virtual unsigned nprev_values() const = 0;
366 
370  virtual void set_weights() = 0;
371 
374  void make_steady()
375  {
376  // Zero the matrix
377  Weight.initialise(0);
378 
379  // Weight of current step in calculation of current step is always 1 in
380  // steady state. All other entries left at zero.
381  Weight(0, 0) = 1.0;
382 
383  // Update flag
384  Is_steady = true;
385  }
386 
389  bool is_steady() const
390  {
391  return Is_steady;
392  }
393 
397  {
398  return Predict_by_explicit_step;
399  }
400 
404  {
405  return Explicit_predictor_pt;
406  }
407 
411  {
412  Explicit_predictor_pt = _pred_pt;
413  }
414 
417  void update_predicted_time(const double& new_time)
418  {
419  Predicted_time = new_time;
420  }
421 
424  {
425 #ifdef PARANOID
426  if (std::abs(time_pt()->time() - Predicted_time) > 1e-15)
427  {
428  throw OomphLibError(
429  "Predicted values are not from the correct time step",
432  }
433 #endif
434  }
435 
438  unsigned predictor_storage_index() const
439  {
440  // Error if time stepper is non-adaptive (because then the index doesn't
441  // exist so using it would give a potentially difficult to find
442  // segault).
443 #ifdef PARANOID
444  if (Predictor_storage_index > 0)
445  {
446  return unsigned(Predictor_storage_index);
447  }
448  else
449  {
450  std::string err = "Predictor storage index is negative, this probably";
451  err += " means it hasn't been set for this timestepper.";
452  throw OomphLibError(
454  }
455 #else
456  return unsigned(Predictor_storage_index);
457 #endif
458  }
459 
463  {
464  Shut_up_in_assign_initial_data_values = false;
465  }
466 
470  {
471  Shut_up_in_assign_initial_data_values = true;
472  }
473 
476  {
477  return &Weight;
478  }
479 
482  virtual void undo_make_steady()
483  {
484  Is_steady = false;
485  set_weights();
486  }
487 
491  {
492  return Type;
493  }
494 
495  //??ds I think that the Data and Node cases below couldp robably be
496  // handled with a template argument. However they can't be handled by
497  // normal polymorphism because data.value is different to node.value and
498  // value is not a virtual function.
499 
502  void time_derivative(const unsigned& i,
503  Data* const& data_pt,
504  Vector<double>& deriv)
505  {
506  // Number of values stored in the Data object
507  unsigned nvalue = data_pt->nvalue();
508  deriv.assign(nvalue, 0.0);
509 
510  // Loop over all values
511  for (unsigned j = 0; j < nvalue; j++)
512  {
513  deriv[j] = time_derivative(i, data_pt, j);
514  }
515  }
516 
518  double time_derivative(const unsigned& i,
519  Data* const& data_pt,
520  const unsigned& j)
521  {
522  double deriv = 0.0;
523  unsigned n_tstorage = ntstorage();
524  // Loop over all history data and add the appropriate contribution
525  // to the derivative
526  for (unsigned t = 0; t < n_tstorage; t++)
527  {
528  deriv += Weight(i, t) * data_pt->value(t, j);
529  }
530  return deriv;
531  }
532 
536  void time_derivative(const unsigned& i,
537  Node* const& node_pt,
538  Vector<double>& deriv)
539  {
540  // Number of values stored in the Data object
541  unsigned nvalue = node_pt->nvalue();
542  deriv.assign(nvalue, 0.0);
543 
544  // Loop over all values
545  for (unsigned j = 0; j < nvalue; j++)
546  {
547  deriv[j] = time_derivative(i, node_pt, j);
548  }
549  }
550 
555  double time_derivative(const unsigned& i,
556  Node* const& node_pt,
557  const unsigned& j)
558  {
559  double deriv = 0.0;
560  unsigned n_tstorage = ntstorage();
561  // Loop over all history data and add the appropriate contribution
562  // to the derivative
563  for (unsigned t = 0; t < n_tstorage; t++)
564  {
565  deriv += weight(i, t) * node_pt->value(t, j);
566  }
567  return deriv;
568  }
569 
570 
572  Time* const& time_pt() const
573  {
574 #ifdef PARANOID
575  if (Time_pt == 0)
576  {
577  std::string error_msg(
578  "Time_pt is null, probably because it is a steady time stepper.");
579  throw OomphLibError(
581  }
582 #endif
583  return Time_pt;
584  }
585 
589  {
590  return Time_pt;
591  }
592 
594  virtual double weight(const unsigned& i, const unsigned& j) const
595  {
596  return Weight(i, j);
597  }
598 
601  unsigned ntstorage() const
602  {
603  return (Weight.ncol());
604  }
605 
608  virtual void assign_initial_values_impulsive(Data* const& data_pt) = 0;
609 
612  virtual void assign_initial_positions_impulsive(Node* const& node_pt) = 0;
613 
616  virtual void shift_time_values(Data* const& data_pt) = 0;
617 
620  virtual void shift_time_positions(Node* const& node_pt) = 0;
621 
623  bool adaptive_flag() const
624  {
625  return Adaptive_Flag;
626  }
627 
630  virtual void set_predictor_weights() {}
631 
634  virtual void calculate_predicted_values(Data* const& data_pt) {}
635 
638  virtual void calculate_predicted_positions(Node* const& node_pt) {}
639 
642  virtual void set_error_weights() {}
643 
646  virtual double temporal_error_in_position(Node* const& node_pt,
647  const unsigned& i)
648  {
649  return 0.0;
650  }
651 
654  virtual double temporal_error_in_value(Data* const& data_pt,
655  const unsigned& i)
656  {
657  return 0.0;
658  }
659 
662  virtual void actions_before_timestep(Problem* problem_pt) {}
663 
666  virtual void actions_after_timestep(Problem* problem_pt) {}
667  };
668 
669 
673 
674 
675  //====================================================================
678  //====================================================================
679  template<unsigned NSTEPS>
680  class Steady : virtual public TimeStepper
681  {
682  public:
687  Steady() : TimeStepper(NSTEPS + 1, 2)
688  {
689  Type = "Steady";
690  Time_pt = &Dummy_time;
691 
692  // Overwrite default assignment in base constructor -- this TimeStepper
693  // actually is steady all the time.
694  Is_steady = true;
695  }
696 
697 
699  Steady(const Steady&) = delete;
700 
702  void operator=(const Steady&) = delete;
703 
706  unsigned order() const
707  {
708  return 0;
709  }
710 
713  void assign_initial_values_impulsive(Data* const& data_pt)
714  {
715  // Find number of values stored
716  unsigned n_value = data_pt->nvalue();
717  // Loop over values
718  for (unsigned j = 0; j < n_value; j++)
719  {
720  // Set previous values to the initial value, if not a copy
721  if (data_pt->is_a_copy(j) == false)
722  {
723  for (unsigned t = 1; t <= NSTEPS; t++)
724  {
725  data_pt->set_value(t, j, data_pt->value(j));
726  }
727  }
728  }
729  }
730 
734  {
735  // Find the number of coordinates
736  unsigned n_dim = node_pt->ndim();
737  // Find the number of positoin types
738  unsigned n_position_type = node_pt->nposition_type();
739 
740  // Loop over values
741  for (unsigned i = 0; i < n_dim; i++)
742  {
743  // Set previous values to the initial value, if not a copy
744  if (node_pt->position_is_a_copy(i) == false)
745  {
746  for (unsigned k = 0; k < n_position_type; k++)
747  {
748  for (unsigned t = 1; t <= NSTEPS; t++)
749  {
750  node_pt->x_gen(t, k, i) = node_pt->x_gen(k, i);
751  }
752  }
753  }
754  }
755  }
756 
757 
760  typedef double (*InitialConditionFctPt)(const double& t);
761 
766  Data* const& data_pt, Vector<InitialConditionFctPt> initial_value_fct)
767  {
768  // The time history stores the previous function values
769  unsigned n_time_value = ntstorage();
770 
771  // Find number of values stored
772  unsigned n_value = data_pt->nvalue();
773 
774  // Loop over current and stored timesteps
775  for (unsigned t = 0; t < n_time_value; t++)
776  {
777  // Get corresponding continous time
778  double time_local = Time_pt->time(t);
779 
780  // Loop over values
781  for (unsigned j = 0; j < n_value; j++)
782  {
783  data_pt->set_value(t, j, initial_value_fct[j](time_local));
784  }
785  }
786  }
787 
791  void shift_time_values(Data* const& data_pt)
792  {
793  // Find number of values stored
794  unsigned n_value = data_pt->nvalue();
795 
796  // Loop over the values
797  for (unsigned j = 0; j < n_value; j++)
798  {
799  // Set previous values to the previous value, if not a copy
800  if (data_pt->is_a_copy(j) == false)
801  {
802  // Loop over times, in reverse order
803  for (unsigned t = NSTEPS; t > 0; t--)
804  {
805  data_pt->set_value(t, j, data_pt->value(t - 1, j));
806  }
807  }
808  }
809  }
810 
813  void shift_time_positions(Node* const& node_pt)
814  {
815  // Find the number of coordinates
816  unsigned n_dim = node_pt->ndim();
817  // Find the number of position types
818  unsigned n_position_type = node_pt->nposition_type();
819 
820  // Loop over the positions
821  for (unsigned i = 0; i < n_dim; i++)
822  {
823  // If the position is not a copy
824  if (node_pt->position_is_a_copy(i) == false)
825  {
826  for (unsigned k = 0; k < n_position_type; k++)
827  {
828  // Loop over stored times, and set values to previous values
829  for (unsigned t = NSTEPS; t > 0; t--)
830  {
831  node_pt->x_gen(t, k, i) = node_pt->x_gen(t - 1, k, i);
832  }
833  }
834  }
835  }
836  }
837 
839  void set_weights()
840  {
841  // Loop over higher derivatives
842  unsigned max_deriv = highest_derivative();
843  for (unsigned i = 0; i < max_deriv; i++)
844  {
845  for (unsigned j = 0; j < NSTEPS; j++)
846  {
847  Weight(i, j) = 0.0;
848  }
849  }
850 
851  // Zeroth derivative must return the value itself:
852  Weight(0, 0) = 1.0;
853  }
854 
856  unsigned nprev_values() const
857  {
858  return NSTEPS;
859  }
860 
862  unsigned ndt() const
863  {
864  return NSTEPS;
865  }
866 
868  double weight(const unsigned& i, const unsigned& j) const
869  {
870  if ((i == 0) && (j == 0))
871  {
872  return One;
873  }
874  else
875  {
876  return Zero;
877  }
878  }
879 
880  private:
882  static double One;
883 
885  static double Zero;
886 
887  // Default Time object
888  static Time Dummy_time;
889  };
890 
891 
895 
896 
897  //====================================================================
909  //====================================================================
910  template<unsigned NSTEPS>
911  class Newmark : public TimeStepper
912  {
913  public:
917  Newmark() : TimeStepper(NSTEPS + 3, 2)
918  {
919  Type = "Newmark";
920 
921  // Standard Newmark parameters
922  Beta1 = 0.5;
923  Beta2 = 0.5;
924  }
925 
927  Newmark(const Newmark&) = delete;
928 
930  void operator=(const Newmark&) = delete;
931 
932 
934  unsigned order() const
935  {
936  std::string error_message =
937  "Can't remember the order of the Newmark scheme";
938  error_message += " -- I think it's 2nd order...\n";
939 
941  error_message, "Newmark::order()", OOMPH_EXCEPTION_LOCATION);
942  return 2;
943  }
944 
947  void assign_initial_values_impulsive(Data* const& data_pt);
948 
951  void assign_initial_positions_impulsive(Node* const& node_pt);
952 
955  typedef double (*InitialConditionFctPt)(const double& t);
956 
960  void assign_initial_data_values(
961  Data* const& data_pt,
962  Vector<InitialConditionFctPt> initial_value_fct,
963  Vector<InitialConditionFctPt> initial_veloc_fct,
964  Vector<InitialConditionFctPt> initial_accel_fct);
965 
966 
971  typedef double (*NodeInitialConditionFctPt)(const double& t,
972  const Vector<double>& x);
973 
977  void assign_initial_data_values(
978  Node* const& node_pt,
979  Vector<NodeInitialConditionFctPt> initial_value_fct,
980  Vector<NodeInitialConditionFctPt> initial_veloc_fct,
981  Vector<NodeInitialConditionFctPt> initial_accel_fct);
982 
1005  void assign_initial_data_values_stage1(const unsigned t_deriv,
1006  Data* const& data_pt);
1007 
1017  void assign_initial_data_values_stage2(Data* const& data_pt);
1018 
1019 
1022  void shift_time_values(Data* const& data_pt);
1023 
1026  void shift_time_positions(Node* const& node_pt);
1027 
1029  void set_weights();
1030 
1032  unsigned nprev_values() const
1033  {
1034  return NSTEPS;
1035  }
1036 
1038  unsigned ndt() const
1039  {
1040  return NSTEPS;
1041  }
1042 
1043 
1044  protected:
1046  double Beta1;
1047 
1049  double Beta2;
1050  };
1051 
1052 
1056 
1057 
1058  //====================================================================
1071  //====================================================================
1072  template<unsigned NSTEPS>
1073  class NewmarkBDF : public Newmark<NSTEPS>
1074  {
1075  public:
1080  {
1081  this->Type = "NewmarkBDF";
1082  Degrade_to_bdf1_for_first_derivs = false;
1083  Newmark_veloc_weight.resize(NSTEPS + 3);
1084  }
1085 
1087  NewmarkBDF(const NewmarkBDF&) = delete;
1088 
1090  void operator=(const NewmarkBDF&) = delete;
1091 
1093  void set_weights();
1094 
1097  void shift_time_values(Data* const& data_pt);
1098 
1101  void shift_time_positions(Node* const& node_pt);
1102 
1106  {
1107  Degrade_to_bdf1_for_first_derivs = true;
1108  }
1109 
1110 
1113  {
1114  Degrade_to_bdf1_for_first_derivs = false;
1115  }
1116 
1117  private:
1122  void set_newmark_veloc_weights(const double& dt)
1123  {
1124  Newmark_veloc_weight[0] = this->Beta1 * dt * this->Weight(2, 0);
1125  Newmark_veloc_weight[1] = this->Beta1 * dt * this->Weight(2, 1);
1126  for (unsigned t = 2; t <= NSTEPS; t++)
1127  {
1128  Newmark_veloc_weight[t] = 0.0;
1129  }
1130  Newmark_veloc_weight[NSTEPS + 1] =
1131  1.0 + this->Beta1 * dt * this->Weight(2, NSTEPS + 1);
1132  Newmark_veloc_weight[NSTEPS + 2] =
1133  dt * (1.0 - this->Beta1) +
1134  this->Beta1 * dt * this->Weight(2, NSTEPS + 2);
1135  }
1136 
1140 
1146  };
1147 
1148 
1152 
1153 
1154  //====================================================================
1162  //====================================================================
1163  template<unsigned NSTEPS>
1164  class BDF : public TimeStepper
1165  {
1166  // A BDF<1> time data set consists of:
1167  // [y_np1, y_n, dy_n, y^P_np1]
1168  // Or in english:
1169  // * y-value at time being/just been solved for
1170  // * y-value at previous time
1171  // * approximation to y derivative at previous time (also refered to as
1172  // velocity in some places, presumably it corresponds to velocity in
1173  // solid mechanics).
1174  // * predicted y-value at time n+1
1175 
1176  // A BDF<2> time data set consists of:
1177  // [y_np1, y_n, y_nm1, dy_n, y^P_np1]
1178  // i.e. the same thing but with one more previous time value. Also the
1179  // derivative approximation will be more accurate.
1180 
1181  // If the adaptive flag is set to false then the final two pieces of data
1182  // in each are not stored (derivative and predictor value).
1183 
1184  private:
1187 
1190 
1191  public:
1193  BDF(const bool& adaptive = false) : TimeStepper(NSTEPS + 1, 1)
1194  {
1195  Type = "BDF";
1196 
1197  // If it's adaptive, we need to allocate additional space to
1198  // carry along a prediction and an acceleration
1199  if (adaptive)
1200  {
1201  // Set the adaptive flag to be true
1202  Adaptive_Flag = true;
1203 
1204  // Set the size of the Predictor_Weights Vector N.B. The size is
1205  // correct for BDF1 and 2, but may be wrong for others.
1206  Predictor_weight.resize(NSTEPS + 2);
1207 
1208  // Resize the weights to the appropriate size
1209  Weight.resize(2, NSTEPS + 3, 0.0);
1210 
1211  // Storing predicted values in slot after other information
1212  Predictor_storage_index = NSTEPS + 2;
1213  }
1214 
1215  // Set the weight for the zero-th derivative
1216  Weight(0, 0) = 1.0;
1217  }
1218 
1219 
1221  BDF(const BDF&) = delete;
1222 
1224  void operator=(const BDF&) = delete;
1225 
1227  unsigned order() const
1228  {
1229  return NSTEPS;
1230  }
1231 
1235  {
1236  // Find number of values stored
1237  unsigned n_value = data_pt->nvalue();
1238  // Loop over values
1239  for (unsigned j = 0; j < n_value; j++)
1240  {
1241  // Set previous values to the initial value, if not a copy
1242  if (data_pt->is_a_copy(j) == false)
1243  {
1244  for (unsigned t = 1; t <= NSTEPS; t++)
1245  {
1246  data_pt->set_value(t, j, data_pt->value(j));
1247  }
1248 
1249  // If it's adaptive
1250  if (adaptive_flag())
1251  {
1252  // Initial velocity is zero
1253  data_pt->set_value(NSTEPS + 1, j, 0.0);
1254  // Initial prediction is the value
1255  data_pt->set_value(NSTEPS + 2, j, data_pt->value(j));
1256  }
1257  }
1258  }
1259  }
1260 
1264  {
1265  // Find the dimension of the node
1266  unsigned n_dim = node_pt->ndim();
1267  // Find the number of position types at the node
1268  unsigned n_position_type = node_pt->nposition_type();
1269 
1270  // Loop over the position variables
1271  for (unsigned i = 0; i < n_dim; i++)
1272  {
1273  // If the position is not copied
1274  // We copy entire coordinates at once
1275  if (node_pt->position_is_a_copy(i) == false)
1276  {
1277  // Loop over the position types
1278  for (unsigned k = 0; k < n_position_type; k++)
1279  {
1280  // Set previous values to the initial value, if not a copy
1281  for (unsigned t = 1; t <= NSTEPS; t++)
1282  {
1283  node_pt->x_gen(t, k, i) = node_pt->x_gen(k, i);
1284  }
1285 
1286  // If it's adaptive
1287  if (adaptive_flag())
1288  {
1289  // Initial mesh velocity is zero
1290  node_pt->x_gen(NSTEPS + 1, k, i) = 0.0;
1291  // Initial prediction is the value
1292  node_pt->x_gen(NSTEPS + 2, k, i) = node_pt->x_gen(k, i);
1293  }
1294  }
1295  }
1296  }
1297  }
1298 
1299 
1302  typedef double (*InitialConditionFctPt)(const double& t);
1303 
1308  Data* const& data_pt, Vector<InitialConditionFctPt> initial_value_fct)
1309  {
1310  // The time history stores the previous function values
1311  unsigned n_time_value = ntstorage();
1312 
1313  // Find number of values stored
1314  unsigned n_value = data_pt->nvalue();
1315 
1316  // Loop over current and stored timesteps
1317  for (unsigned t = 0; t < n_time_value; t++)
1318  {
1319  // Get corresponding continous time
1320  double time_local = Time_pt->time(t);
1321 
1322  // Loop over values
1323  for (unsigned j = 0; j < n_value; j++)
1324  {
1325  data_pt->set_value(t, j, initial_value_fct[j](time_local));
1326  }
1327  }
1328  }
1329 
1333  void shift_time_values(Data* const& data_pt)
1334  {
1335  // Find number of values stored
1336  unsigned n_value = data_pt->nvalue();
1337  // Storage for velocity need to be here to be in scope
1338  Vector<double> velocity(n_value);
1339 
1340  // Find the number of history values that are stored
1341  const unsigned nt_value = nprev_values();
1342 
1343  // If adaptive, find the velocities
1344  if (adaptive_flag())
1345  {
1346  time_derivative(1, data_pt, velocity);
1347  }
1348 
1349  // Loop over the values
1350  for (unsigned j = 0; j < n_value; j++)
1351  {
1352  // Set previous values to the previous value, if not a copy
1353  if (data_pt->is_a_copy(j) == false)
1354  {
1355  // Loop over times, in reverse order
1356  for (unsigned t = nt_value; t > 0; t--)
1357  {
1358  data_pt->set_value(t, j, data_pt->value(t - 1, j));
1359  }
1360 
1361  // If we are using the adaptive scheme
1362  if (adaptive_flag())
1363  {
1364  // Set the velocity
1365  data_pt->set_value(nt_value + 1, j, velocity[j]);
1366  }
1367  }
1368  }
1369  }
1370 
1373  void shift_time_positions(Node* const& node_pt)
1374  {
1375  // Find the number of coordinates
1376  unsigned n_dim = node_pt->ndim();
1377  // Find the number of position types
1378  unsigned n_position_type = node_pt->nposition_type();
1379 
1380  // Find number of stored timesteps
1381  unsigned n_tstorage = ntstorage();
1382 
1383  // Storage for the velocity
1384  double velocity[n_position_type][n_dim];
1385 
1386  // If adaptive, find the velocities
1387  if (adaptive_flag())
1388  {
1389  // Loop over the variables
1390  for (unsigned i = 0; i < n_dim; i++)
1391  {
1392  for (unsigned k = 0; k < n_position_type; k++)
1393  {
1394  // Initialise velocity to zero
1395  velocity[k][i] = 0.0;
1396  // Loop over all history data
1397  for (unsigned t = 0; t < n_tstorage; t++)
1398  {
1399  velocity[k][i] += Weight(1, t) * node_pt->x_gen(t, k, i);
1400  }
1401  }
1402  }
1403  }
1404 
1405  // Loop over the positions
1406  for (unsigned i = 0; i < n_dim; i++)
1407  {
1408  // If the position is not a copy
1409  if (node_pt->position_is_a_copy(i) == false)
1410  {
1411  // Loop over the position types
1412  for (unsigned k = 0; k < n_position_type; k++)
1413  {
1414  // Loop over stored times, and set values to previous values
1415  for (unsigned t = NSTEPS; t > 0; t--)
1416  {
1417  node_pt->x_gen(t, k, i) = node_pt->x_gen(t - 1, k, i);
1418  }
1419 
1420  // If we are using the adaptive scheme, set the velocity
1421  if (adaptive_flag())
1422  {
1423  node_pt->x_gen(NSTEPS + 1, k, i) = velocity[k][i];
1424  }
1425  }
1426  }
1427  }
1428  }
1429 
1431  void set_weights();
1432 
1434  unsigned nprev_values() const
1435  {
1436  return NSTEPS;
1437  }
1438 
1440  unsigned ndt() const
1441  {
1442  return NSTEPS;
1443  }
1444 
1447 
1449  void calculate_predicted_positions(Node* const& node_pt);
1450 
1452  void calculate_predicted_values(Data* const& data_pt);
1453 
1456 
1458  double temporal_error_in_position(Node* const& node_pt, const unsigned& i);
1459 
1461  double temporal_error_in_value(Data* const& data_pt, const unsigned& i);
1462  };
1463 
1464 } // namespace oomph
1465 
1466 #endif
AnnoyingScalar abs(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:135
int i
Definition: BiCGSTAB_step_by_step.cpp:9
Array< double, 1, 3 > e(1./3., 0.5, 2.)
Definition: timesteppers.h:1165
void shift_time_values(Data *const &data_pt)
Definition: timesteppers.h:1333
void calculate_predicted_positions(Node *const &node_pt)
Function to calculate predicted positions at a node.
void assign_initial_positions_impulsive(Node *const &node_pt)
Definition: timesteppers.h:1263
void calculate_predicted_values(Data *const &data_pt)
Function to calculate predicted data values in a Data object.
BDF(const bool &adaptive=false)
Constructor for the case when we allow adaptive timestepping.
Definition: timesteppers.h:1193
void assign_initial_values_impulsive(Data *const &data_pt)
Definition: timesteppers.h:1234
void set_weights()
Set the weights.
double Error_weight
Private data for the error weight.
Definition: timesteppers.h:1189
unsigned ndt() const
Number of timestep increments that need to be stored by the scheme.
Definition: timesteppers.h:1440
unsigned order() const
Return the actual order of the scheme.
Definition: timesteppers.h:1227
void operator=(const BDF &)=delete
Broken assignment operator.
Vector< double > Predictor_weight
Private data for the predictor weights.
Definition: timesteppers.h:1186
void set_predictor_weights()
Function to set the predictor weights.
double temporal_error_in_value(Data *const &data_pt, const unsigned &i)
Compute the error in the value i in a Data structure.
void shift_time_positions(Node *const &node_pt)
Definition: timesteppers.h:1373
BDF(const BDF &)=delete
Broken copy constructor.
void assign_initial_data_values(Data *const &data_pt, Vector< InitialConditionFctPt > initial_value_fct)
Definition: timesteppers.h:1307
double temporal_error_in_position(Node *const &node_pt, const unsigned &i)
Compute the error in the position i at a node.
unsigned nprev_values() const
Number of previous values available.
Definition: timesteppers.h:1434
void set_error_weights()
Function to set the error weights.
Definition: nodes.h:86
void set_value(const unsigned &i, const double &value_)
Definition: nodes.h:271
virtual bool is_a_copy() const
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
Definition: nodes.h:293
A Base class for explicit timesteppers.
Definition: explicit_timesteppers.h:132
Definition: timesteppers.h:1074
void set_weights()
Set weights.
void disable_degrade_first_derivatives_to_bdf1()
Disable degradation to first order BDF.
Definition: timesteppers.h:1112
NewmarkBDF(const NewmarkBDF &)=delete
Broken copy constructor.
bool Degrade_to_bdf1_for_first_derivs
Definition: timesteppers.h:1139
NewmarkBDF()
Definition: timesteppers.h:1079
void operator=(const NewmarkBDF &)=delete
Broken assignment operator.
Vector< double > Newmark_veloc_weight
Definition: timesteppers.h:1145
void set_newmark_veloc_weights(const double &dt)
Definition: timesteppers.h:1122
void enable_degrade_first_derivatives_to_bdf1()
Definition: timesteppers.h:1105
Definition: timesteppers.h:912
double Beta2
Second Newmark parameter (usually 0.5)
Definition: timesteppers.h:1049
Newmark()
Definition: timesteppers.h:917
unsigned nprev_values() const
Number of previous values available.
Definition: timesteppers.h:1032
unsigned ndt() const
Number of timestep increments that need to be stored by the scheme.
Definition: timesteppers.h:1038
double Beta1
First Newmark parameter (usually 0.5)
Definition: timesteppers.h:1046
unsigned order() const
The actual order (accuracy of the scheme)
Definition: timesteppers.h:934
void operator=(const Newmark &)=delete
Broken assignment operator.
Newmark(const Newmark &)=delete
Broken copy constructor.
Definition: nodes.h:906
double & x_gen(const unsigned &k, const unsigned &i)
Definition: nodes.h:1126
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
Definition: nodes.h:1016
double value(const unsigned &i) const
Definition: nodes.cc:2408
Definition: oomph_definitions.h:222
Definition: oomph_definitions.h:267
Definition: problem.h:151
Definition: timesteppers.h:681
void assign_initial_values_impulsive(Data *const &data_pt)
Definition: timesteppers.h:713
void set_weights()
Set weights.
Definition: timesteppers.h:839
double weight(const unsigned &i, const unsigned &j) const
Dummy: Access function for j-th weight for the i-th derivative.
Definition: timesteppers.h:868
void operator=(const Steady &)=delete
Broken assignment operator.
void shift_time_positions(Node *const &node_pt)
Definition: timesteppers.h:813
static double One
Static variable to hold the value 1.0.
Definition: timesteppers.h:882
static Time Dummy_time
Definition: timesteppers.h:888
Steady(const Steady &)=delete
Broken copy constructor.
Steady()
Definition: timesteppers.h:687
void assign_initial_data_values(Data *const &data_pt, Vector< InitialConditionFctPt > initial_value_fct)
Definition: timesteppers.h:765
void shift_time_values(Data *const &data_pt)
Definition: timesteppers.h:791
static double Zero
Static variable to hold the value 0.0.
Definition: timesteppers.h:885
unsigned order() const
Definition: timesteppers.h:706
unsigned nprev_values() const
Number of previous values available.
Definition: timesteppers.h:856
void assign_initial_positions_impulsive(Node *const &node_pt)
Definition: timesteppers.h:733
unsigned ndt() const
Number of timestep increments that need to be stored by the scheme.
Definition: timesteppers.h:862
Definition: timesteppers.h:231
virtual unsigned ndt() const =0
Number of timestep increments that are required by the scheme.
virtual void shift_time_values(Data *const &data_pt)=0
virtual void set_weights()=0
TimeStepper(const TimeStepper &)=delete
Broken copy constructor.
DenseMatrix< double > Weight
Storage for the weights associated with the timestepper.
Definition: timesteppers.h:237
virtual unsigned nprev_values() const =0
Number of previous values available: 0 for static, 1 for BDF<1>,...
virtual void calculate_predicted_values(Data *const &data_pt)
Definition: timesteppers.h:634
bool Shut_up_in_assign_initial_data_values
Definition: timesteppers.h:256
virtual unsigned order() const
Actual order (accuracy) of the scheme.
Definition: timesteppers.h:324
virtual double temporal_error_in_value(Data *const &data_pt, const unsigned &i)
Definition: timesteppers.h:654
virtual void set_predictor_weights()
Definition: timesteppers.h:630
virtual void calculate_predicted_positions(Node *const &node_pt)
Definition: timesteppers.h:638
bool Predict_by_explicit_step
Definition: timesteppers.h:260
unsigned predictor_storage_index() const
Definition: timesteppers.h:438
Time *& time_pt()
Definition: timesteppers.h:588
void enable_warning_in_assign_initial_data_values()
Definition: timesteppers.h:462
virtual void actions_before_timestep(Problem *problem_pt)
Definition: timesteppers.h:662
void check_predicted_values_up_to_date() const
Check that the predicted values are the ones we want.
Definition: timesteppers.h:423
Time * Time_pt
Pointer to discrete time storage scheme.
Definition: timesteppers.h:234
unsigned ntstorage() const
Definition: timesteppers.h:601
std::string Type
Definition: timesteppers.h:241
virtual void actions_after_timestep(Problem *problem_pt)
Definition: timesteppers.h:666
void time_derivative(const unsigned &i, Node *const &node_pt, Vector< double > &deriv)
Definition: timesteppers.h:536
ExplicitTimeStepper * Explicit_predictor_pt
Definition: timesteppers.h:265
virtual double weight(const unsigned &i, const unsigned &j) const
Access function for j-th weight for the i-th derivative.
Definition: timesteppers.h:594
virtual void shift_time_positions(Node *const &node_pt)=0
bool Is_steady
Definition: timesteppers.h:251
virtual unsigned nprev_values_for_value_at_evaluation_time() const
Definition: timesteppers.h:359
bool adaptive_flag() const
Function to indicate whether the scheme is adaptive (false by default)
Definition: timesteppers.h:623
TimeStepper()
Broken empty constructor.
Definition: timesteppers.h:301
void operator=(const TimeStepper &)=delete
Broken assignment operator.
virtual void assign_initial_values_impulsive(Data *const &data_pt)=0
void disable_warning_in_assign_initial_data_values()
Definition: timesteppers.h:469
void time_derivative(const unsigned &i, Data *const &data_pt, Vector< double > &deriv)
Definition: timesteppers.h:502
void make_steady()
Definition: timesteppers.h:374
TimeStepper(const unsigned &tstorage, const unsigned &max_deriv)
Definition: timesteppers.h:279
unsigned highest_derivative() const
Highest order derivative that the scheme can compute.
Definition: timesteppers.h:318
virtual void undo_make_steady()
Definition: timesteppers.h:482
double time() const
Return current value of continous time.
Definition: timesteppers.h:338
ExplicitTimeStepper * explicit_predictor_pt()
Definition: timesteppers.h:403
virtual void assign_initial_positions_impulsive(Node *const &node_pt)=0
double time_derivative(const unsigned &i, Data *const &data_pt, const unsigned &j)
Evaluate i-th derivative of j-th value in Data.
Definition: timesteppers.h:518
double & time()
Return current value of continous time.
Definition: timesteppers.h:332
void update_predicted_time(const double &new_time)
Definition: timesteppers.h:417
bool predict_by_explicit_step() const
Definition: timesteppers.h:396
virtual double temporal_error_in_position(Node *const &node_pt, const unsigned &i)
Definition: timesteppers.h:646
const DenseMatrix< double > * weights_pt() const
Get a (const) pointer to the weights.
Definition: timesteppers.h:475
std::string type() const
Definition: timesteppers.h:490
bool is_steady() const
Definition: timesteppers.h:389
virtual void set_error_weights()
Definition: timesteppers.h:642
double time_derivative(const unsigned &i, Node *const &node_pt, const unsigned &j)
Definition: timesteppers.h:555
double Predicted_time
Definition: timesteppers.h:269
Time *const & time_pt() const
Access function for the pointer to time (const version)
Definition: timesteppers.h:572
int Predictor_storage_index
Definition: timesteppers.h:273
bool Adaptive_Flag
Definition: timesteppers.h:245
void set_predictor_pt(ExplicitTimeStepper *_pred_pt)
Definition: timesteppers.h:410
Definition: timesteppers.h:63
double Continuous_time
Pointer to the value of the continuous time.
Definition: timesteppers.h:66
double & dt(const unsigned &t=0)
Definition: timesteppers.h:136
Time(const Time &)=delete
Broken copy constructor.
void operator=(const Time &)=delete
Broken assignment operator.
Vector< double > Dt
Vector that stores the values of the current and previous timesteps.
Definition: timesteppers.h:69
double time(const unsigned &t=0) const
Definition: timesteppers.h:150
double dt(const unsigned &t=0) const
Definition: timesteppers.h:143
double & time()
Return the current value of the continuous time.
Definition: timesteppers.h:123
void initialise_dt(const Vector< double > &dt_)
Definition: timesteppers.h:107
void shift_dt()
Definition: timesteppers.h:174
void initialise_dt(const double &dt_)
Set all timesteps to the same value, dt.
Definition: timesteppers.h:99
unsigned ndt() const
Return the number of timesteps stored.
Definition: timesteppers.h:129
void resize(const unsigned &n_dt)
Definition: timesteppers.h:93
Time()
Definition: timesteppers.h:74
~Time()
Destructor: empty.
Definition: timesteppers.h:120
Time(const unsigned &ndt)
Definition: timesteppers.h:78
char char char int int * k
Definition: level2_impl.h:374
Time * Time_pt
Pointer to the global time object.
Definition: turek_flag_non_fsi.cc:91
double Beta1
Thermal conductivity in outer annular region.
Definition: stefan_boltzmann.cc:130
int adaptive
Definition: jeffery_hamel.cc:106
double velocity(const double &t)
Angular velocity as function of time t.
Definition: jeffery_orbit.cc:107
double Weight
NOTE: WE IMPOSE EITHER THESE ...
Definition: heated_linear_solid_contact_with_gravity.cc:2838
std::string string(const unsigned &i)
Definition: oomph_definitions.cc:286
double Zero
Definition: pseudosolid_node_update_elements.cc:35
std::string to_string(T object, unsigned float_precision=8)
Definition: oomph_utilities.h:189
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition: AnisotropicHookean.h:10
list x
Definition: plotDoE.py:28
t
Definition: plotPSD.py:36
Type
Type of JSON value.
Definition: rapidjson.h:513
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2