elastic_problems.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 #ifndef OOMPH_ELASTIC_PROBLEMS_HEADER
27 #define OOMPH_ELASTIC_PROBLEMS_HEADER
28 
29 // Config header generated by autoconfig
30 #ifdef HAVE_CONFIG_H
31 #include <oomph-lib-config.h>
32 #endif
33 
34 
35 // oomph-lib headers
36 #include "geom_objects.h"
37 #include "timesteppers.h"
38 #include "problem.h"
39 #include "frontal_solver.h"
40 #include "mesh.h"
41 
42 namespace oomph
43 {
47 
48 
49  //======================================================================
52  //======================================================================
53  class DummyMesh : public Mesh
54  {
55  public:
56  // Empty constructor
57  DummyMesh(){};
58  };
59 
63 
64 
65  //======================================================================
86  //======================================================================
87  class SolidICProblem : public Problem
88  {
89  public:
95  {
97  mesh_pt() = new DummyMesh;
98 
99  // Default value for checking of consistent assignment of Newmark IC
101  }
102 
103 
105  SolidICProblem(const SolidICProblem&) = delete;
106 
108  void operator=(const SolidICProblem&) = delete;
109 
112 
115 
119  void set_static_initial_condition(Problem* problem_pt,
120  Mesh* mesh_pt,
121  SolidInitialCondition* ic_pt,
122  const double& time);
123 
127  Mesh* mesh_pt,
128  SolidInitialCondition* ic_pt)
129  {
130  double time;
131  set_static_initial_condition(problem_pt, mesh_pt, ic_pt, time);
132  }
133 
138  template<class TIMESTEPPER>
140  Mesh* mesh_pt,
141  TIMESTEPPER* timestepper_pt,
142  SolidInitialCondition* ic_pt,
143  const double& dt);
144 
145 
159  template<class TIMESTEPPER>
161  Problem* problem_pt,
162  Mesh* mesh_pt,
163  TIMESTEPPER* timestepper_pt,
164  SolidInitialCondition* ic_pt,
165  const double& dt,
166  SolidFiniteElement::MultiplierFctPt multiplier_fct_pt = 0);
167 
168 
173  {
175  }
176 
177 
178  private:
180  void backup_original_state();
181 
183  void reset_original_state();
184 
187  void setup_problem();
188 
191 
194 
197 
202  };
203 
204 
205  //======================================================================
210  //======================================================================
211  template<class TIMESTEPPER>
213  Problem* problem_pt,
214  Mesh* wall_mesh_pt,
215  TIMESTEPPER* timestepper_pt,
216  SolidInitialCondition* ic_pt,
217  const double& dt)
218  {
219 #ifdef PARANOID
220  if (timestepper_pt->type() != "Newmark")
221  {
222  std::ostringstream error_message;
223  error_message
224  << "SolidICProblem::set_newmark_initial_condition_directly()\n"
225  << "can only be called for Newmark type timestepper whereas\n "
226  << "you've called it for " << timestepper_pt->type() << std::endl;
227 
228  throw OomphLibError(
229  error_message.str(),
230  "SolidICProblem::set_newmark_initial_condition_directly()",
232  }
233 #endif
234 
235  // Set value of dt
236  timestepper_pt->time_pt()->dt() = dt;
237 
238  // Set the weights
239  timestepper_pt->set_weights();
240 
241  // Delete dummy mesh
242  delete mesh_pt();
243 
244  // Set pointer to mesh
245  mesh_pt() = wall_mesh_pt;
246 
247  // Set pointer to initial condition object
248  IC_pt = ic_pt;
249 
250  // Backup the pinned status of all dofs and remove external data
251  // of all elements
253 
254  // Now alter the pinned status so that the IC problem for the
255  // positional variables can be solved; setup equation numbering
256  // scheme
257  setup_problem();
258 
259 
260  // Store times at which we need to assign ic:
261  double current_time = timestepper_pt->time_pt()->time();
262  double previous_time = timestepper_pt->time_pt()->time(1);
263 
264  // Stage 1: Set values and time derivs at current time
265  //----------------------------------------------------
266 
267  // [Note: this acts on time everywhere!]
269  current_time;
270 
271  // Loop over time-derivatives
272  for (unsigned t_deriv = 0; t_deriv <= 2; t_deriv++)
273  {
274  // Set flag to ensure that the t_deriv-th time derivative
275  // of the prescribed solution gets stored in displacements
276  IC_pt->ic_time_deriv() = t_deriv;
277 
278  // Solve the problem for initial shape
279  newton_solve();
280 
281  // Loop over all the nodes
282  unsigned n_node = mesh_pt()->nnode();
283  for (unsigned n = 0; n < n_node; n++)
284  {
285  // Assign current time derivative in its temporary storage
286  // position
287  timestepper_pt->assign_initial_data_values_stage1(
288  t_deriv,
289  dynamic_cast<SolidNode*>(mesh_pt()->node_pt(n))
290  ->variable_position_pt());
291  }
292  }
293 
294 
295  // Stage 2: Now get position at previous time and adjust previous
296  //---------------------------------------------------------------
297  // values of veloc and accel in Newmark scheme so that current
298  //---------------------------------------------------------------
299  // veloc and accel (specified in step 1) are represented exactly.
300  //---------------------------------------------------------------
301 
302  // [Note: this acts on time everywhere and needs to be reset!]
304  previous_time;
305 
306  // Set flag to ensure that the t_deriv-th time derivative
307  // of the prescribed solution gets stored in displacements
308  IC_pt->ic_time_deriv() = 0;
309 
310  // Solve the problem for initial shape
311  newton_solve();
312 
313  // Loop over all the nodes and make the final adjustments
314  unsigned n_node = mesh_pt()->nnode();
315  for (unsigned n = 0; n < n_node; n++)
316  {
317  timestepper_pt->assign_initial_data_values_stage2(
318  dynamic_cast<SolidNode*>(mesh_pt()->node_pt(n))
319  ->variable_position_pt());
320  }
321 
322  // Reset time
324  current_time;
325 
326  // Reset the pinned status and re-attach the external data to the elements
328 
329  // Set pointer to dummy mesh so there's something that can be deleted
330  // when static problem finally goes out of scope.
331  mesh_pt() = new DummyMesh;
332 
333  // We have temporarily over-written equation numbers -- need
334  // to reset them now
335  oomph_info << "Number of equations in big problem: "
336  << problem_pt->assign_eqn_numbers() << std::endl;
337  }
338 
339 
340  //======================================================================
354  //======================================================================
355  template<class TIMESTEPPER>
357  Problem* problem_pt,
358  Mesh* wall_mesh_pt,
359  TIMESTEPPER* timestepper_pt,
360  SolidInitialCondition* ic_pt,
361  const double& dt,
362  SolidFiniteElement::MultiplierFctPt multiplier_fct_pt)
363  {
364 #ifdef PARANOID
365  if (timestepper_pt->type() != "Newmark")
366  {
367  std::ostringstream error_message;
368  error_message
369  << "SolidICProblem::set_newmark_initial_condition_consistently()\n"
370  << "can only be called for Newmark type timestepper whereas\n "
371  << "you've called it for " << timestepper_pt->type() << std::endl;
372 
373  throw OomphLibError(
374  error_message.str(),
375  "SolidICProblem::set_newmark_initial_condition_consistently()",
377  }
378 #endif
379 
380  // Set value of dt
381  timestepper_pt->time_pt()->dt() = dt;
382 
383  // Set the weights
384  timestepper_pt->set_weights();
385 
386  // Delete dummy mesh
387  delete mesh_pt();
388 
389  // Set pointer to mesh
390  mesh_pt() = wall_mesh_pt;
391 
392  // Set pointer to initial condition object
393  IC_pt = ic_pt;
394 
395  // Backup the pinned status of all dofs and remove external data
396  // of all elements
398 
399  // Now alter the pinned status so that the IC problem for the
400  // positional variables can be solved; setup equation numbering
401  // scheme
402  setup_problem();
403 
404  // Number of history values
405  unsigned ntstorage =
407 
408  // Set values at previous time
409  //----------------------------
410 
411  // Loop over number of previous times stored
412  unsigned nprevtime =
414 
415  // Backup previous times:
416  Vector<double> prev_time(nprevtime + 1);
417  for (unsigned i = 0; i <= nprevtime; i++)
418  {
419  prev_time[i] =
421  }
422 
423  // Loop over previous times & set values themselves
424  //-------------------------------------------------
425  for (unsigned i = 1; i <= nprevtime; i++)
426  {
427  // Set time for geometric object that specifies initial condition
428  // [Note: this acts on time everywhere!]
430  prev_time[i];
431 
432  // Set flag to ensure that the t_deriv-th time derivative
433  // of the prescribed solution gets stored in displacements
434  IC_pt->ic_time_deriv() = 0;
435 
436  // Solve the problem for initial shape: After this solve
437  // The nodes's current positions represent the position at
438  // previous time level i.
439  newton_solve();
440 
441  // Loop over all the nodes
442  unsigned n_node = mesh_pt()->nnode();
443  for (unsigned n = 0; n < n_node; n++)
444  {
445  // Get the variable position data
446  Data* position_data_pt = dynamic_cast<SolidNode*>(mesh_pt()->node_pt(n))
447  ->variable_position_pt();
448  // Get number of values
449  unsigned nval = position_data_pt->nvalue();
450 
451  // Assign values at previous times into their corresponding
452  // slots
453  for (unsigned ival = 0; ival < nval; ival++)
454  {
455  position_data_pt->set_value(
456  i, ival, position_data_pt->value(0, ival));
457  }
458  }
459  }
460 
461  // Set veloc (1st time deriv) at previous time and store in appropriate
462  //---------------------------------------------------------------------
463  // history value. Also assign zero value for 2nd time deriv. at
464  //-------------------------------------------------------------
465  // previous time
466  //--------------
467 
468  // Set time for geometric object that specifies initial condition
469  // to previous time [Note: this acts on time everywhere!]
471  prev_time[1];
472 
473  // Set flag to ensure that the t_deriv-th time derivative
474  // of the prescribed solution gets stored in displacements
475  IC_pt->ic_time_deriv() = 1;
476 
477  // Solve the problem for initial shape: After this solve
478  // The nodes's current positions represent the time derivatives of at
479  // the positons at previous time level.
480  newton_solve();
481 
482  // Loop over all the nodes
483  unsigned n_node = mesh_pt()->nnode();
484  for (unsigned n = 0; n < n_node; n++)
485  {
486  // Get the position data
487  Data* position_data_pt =
488  dynamic_cast<SolidNode*>(mesh_pt()->node_pt(n))->variable_position_pt();
489 
490  // Get number of values
491  unsigned nval = position_data_pt->nvalue();
492 
493  // Assign values at previous times into their corresponding
494  // slots (last but one history value of Newmark scheme)
495  for (unsigned ival = 0; ival < nval; ival++)
496  {
497  position_data_pt->set_value(
498  ntstorage - 2, ival, position_data_pt->value(0, ival));
499  position_data_pt->set_value(ntstorage - 1, ival, 0.0);
500  }
501  }
502 
503 
504  // Set values at current time
505  //---------------------------
506 
507  // Reset time to current value
508  // [Note: this acts on time everywhere!]
510  prev_time[0];
511 
512  // Set flag to ensure that the t_deriv-th time derivative
513  // of the prescribed solution gets stored in displacements
514  IC_pt->ic_time_deriv() = 0;
515 
516  // Solve the problem for initial shape
517  newton_solve();
518 
519 
520  // Now solve for the correction to the Newmark accelerations
521  //----------------------------------------------------------
522  // at previous time:
523  //------------------
524 
525  // Loop over the elements
526  unsigned Nelement = mesh_pt()->nelement();
527  for (unsigned i = 0; i < Nelement; i++)
528  {
529  // Cast to proper element type
530  SolidFiniteElement* elem_pt =
531  dynamic_cast<SolidFiniteElement*>(mesh_pt()->element_pt(i));
532 
533  // Switch system to the one that determines the Newmark accelerations
534  // by setting the Jacobian to the mass matrix
536 
537  // Set pointer to multiplier function
538  elem_pt->multiplier_fct_pt() = multiplier_fct_pt;
539 
540  // Switch off pointer to initial condition object
541  elem_pt->solid_ic_pt() = 0;
542  }
543 
544  // Correction vector
545  DoubleVector correction;
546 
548  typedef void (LinearSolver::*SolverMemPtr)(Problem* const& problem,
549  DoubleVector& result);
550  SolverMemPtr solver_mem_pt = &LinearSolver::solve;
551 
552  // Now do the linear solve
553  (linear_solver_pt()->*solver_mem_pt)(this, correction);
554 
555  // Update discrete 2nd deriv at previous time so that it's consistent
556  // with PDE at current time
557 
558  // Loop over all the nodes
559  for (unsigned n = 0; n < n_node; n++)
560  {
561  // Get the pointer to the position data
562  Data* position_data_pt =
563  dynamic_cast<SolidNode*>(mesh_pt()->node_pt(n))->variable_position_pt();
564 
565  // Get number of values
566  unsigned nval = position_data_pt->nvalue();
567 
568  // Assign values for the history value that corresponds to the
569  // previous accel in Newmark scheme so that the PDE is satsified
570  // at current time
571  for (unsigned ival = 0; ival < nval; ival++)
572  {
573  // Global equation number
574  int ieqn = position_data_pt->eqn_number(ival);
575 
576 #ifdef PARANOID
577  if (ieqn < 0)
578  {
579  throw OomphLibError(
580  "No positional dofs should be pinned at this stage!",
583  }
584 #endif
585 
586  // Update the value
587  *(position_data_pt->value_pt(ntstorage - 1, ival)) -= correction[ieqn];
588  }
589  }
590 
591 
592 #ifdef PARANOID
593  // Check the residual
594  DoubleVector residuals;
595  get_residuals(residuals);
596  double res_max = residuals.max();
597  oomph_info
598  << "Max. residual after assigning consistent initial conditions: "
599  << res_max << std::endl;
601  {
602  std::ostringstream error_message;
603  error_message << "Residual is bigger than allowed! [Current tolerance: "
605  error_message << "This is probably because you've not specified the "
606  << "correct multiplier \n(the product of growth factor "
607  << "and timescale ratio [the non-dim density]). \nPlease "
608  << "check the Solid Mechanics Theory Tutorial for "
609  << "details. \n\n"
610  << "If you're sure that the residual is OK, overwrite "
611  << "the default tolerance using\n";
612  error_message
613  << "SolidICProblem::max_residual_after_consistent_newton_ic()"
614  << std::endl
615  << "or recompile without the PARANOID flag." << std::endl;
616 
617  throw OomphLibError(
618  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
619  }
620 #endif
621 
622  // Reset the pinned status and re-attach the external data to the elements
624 
625  // Set pointer to dummy mesh so there's something that can be deleted
626  // when static problem finally goes out of scope.
627  mesh_pt() = new DummyMesh;
628 
629  // We have temporarily over-written equation numbers -- need
630  // to reset them now
631  oomph_info << "Number of equations in big problem: "
632  << problem_pt->assign_eqn_numbers() << std::endl;
633  }
634 
635 } // namespace oomph
636 
637 #endif
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
Definition: nodes.h:86
long & eqn_number(const unsigned &i)
Return the equation number of the i-th stored variable.
Definition: nodes.h:367
double * value_pt(const unsigned &i) const
Definition: nodes.h:324
void set_value(const unsigned &i, const double &value_)
Definition: nodes.h:271
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
Definition: double_vector.h:58
double max() const
returns the maximum coefficient
Definition: double_vector.cc:604
Definition: elastic_problems.h:54
DummyMesh()
Definition: elastic_problems.h:57
TimeStepper *& time_stepper_pt()
Definition: geom_objects.h:192
Definition: linear_solver.h:68
virtual void solve(Problem *const &problem_pt, DoubleVector &result)=0
Definition: mesh.h:67
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition: mesh.h:448
unsigned long nnode() const
Return number of nodes in the mesh.
Definition: mesh.h:596
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Definition: mesh.h:436
unsigned long nelement() const
Return number of elements in the mesh.
Definition: mesh.h:590
Definition: oomph_definitions.h:222
Definition: problem.h:151
virtual void get_residuals(DoubleVector &residuals)
Get the total residuals Vector for the problem.
Definition: problem.cc:3714
LinearSolver *& linear_solver_pt()
Return a pointer to the linear solver object.
Definition: problem.h:1466
Mesh *& mesh_pt()
Return a pointer to the global mesh.
Definition: problem.h:1280
void newton_solve()
Use Newton method to solve the problem.
Definition: problem.cc:8783
unsigned long assign_eqn_numbers(const bool &assign_local_eqn_numbers=true)
Definition: problem.cc:1989
double & time()
Return the current value of continuous time.
Definition: problem.cc:11531
Definition: elements.h:3561
double(* MultiplierFctPt)(const Vector< double > &xi)
Definition: elements.h:3582
void enable_solve_for_consistent_newmark_accel()
Definition: elements.h:3966
MultiplierFctPt & multiplier_fct_pt()
Definition: elements.h:3979
SolidInitialCondition *& solid_ic_pt()
Pointer to object that describes the initial condition.
Definition: elements.h:3955
Definition: elastic_problems.h:88
void set_newmark_initial_condition_consistently(Problem *problem_pt, Mesh *mesh_pt, TIMESTEPPER *timestepper_pt, SolidInitialCondition *ic_pt, const double &dt, SolidFiniteElement::MultiplierFctPt multiplier_fct_pt=0)
Definition: elastic_problems.h:356
void backup_original_state()
Backup original state of all data associated with mesh.
Definition: elastic_problems.cc:191
double & max_residual_after_consistent_newton_ic()
Definition: elastic_problems.h:172
Vector< Vector< Data * > > Backup_ext_data
Vector of Vectors to store pointers to exernal data in the elements.
Definition: elastic_problems.h:196
void operator=(const SolidICProblem &)=delete
Broken assignment operator.
void setup_problem()
Definition: elastic_problems.cc:48
void set_static_initial_condition(Problem *problem_pt, Mesh *mesh_pt, SolidInitialCondition *ic_pt, const double &time)
Definition: elastic_problems.cc:522
SolidICProblem(const SolidICProblem &)=delete
Broken copy constructor.
Vector< int > Backup_pinned
Vector to store pinned status of all data.
Definition: elastic_problems.h:193
double Max_residual_after_consistent_newton_ic
Definition: elastic_problems.h:201
void reset_original_state()
Reset original state of all data associated with mesh.
Definition: elastic_problems.cc:343
SolidInitialCondition * IC_pt
Pointer to initial condition object.
Definition: elastic_problems.h:190
void set_newmark_initial_condition_directly(Problem *problem_pt, Mesh *mesh_pt, TIMESTEPPER *timestepper_pt, SolidInitialCondition *ic_pt, const double &dt)
Definition: elastic_problems.h:212
void actions_before_newton_solve()
Update the problem specs before solve. (empty)
Definition: elastic_problems.h:114
SolidICProblem()
Definition: elastic_problems.h:94
void set_static_initial_condition(Problem *problem_pt, Mesh *mesh_pt, SolidInitialCondition *ic_pt)
Definition: elastic_problems.h:126
void actions_after_newton_solve()
Update after solve (empty)
Definition: elastic_problems.h:111
Definition: elements.h:3496
GeomObject *& geom_object_pt()
Definition: elements.h:3511
unsigned & ic_time_deriv()
Which time derivative are we currently assigning?
Definition: elements.h:3517
Definition: nodes.h:1686
virtual unsigned nprev_values() const =0
Number of previous values available: 0 for static, 1 for BDF<1>,...
unsigned ntstorage() const
Definition: timesteppers.h:601
Time *const & time_pt() const
Access function for the pointer to time (const version)
Definition: timesteppers.h:572
double & time()
Return the current value of the continuous time.
Definition: timesteppers.h:123
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition: AnisotropicHookean.h:10
OomphInfo oomph_info
Definition: oomph_definitions.cc:319
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86
Constructor for SteadyAxisymAdvectionDiffusion problem
Definition: steady_axisym_advection_diffusion.cc:213