prescribed_displ_lagr_mult_precond.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-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 // Driver for Solid deformation -- driven by boundary motion which
27 // is imposed via Lagrange multipliers
28 
29 
30 //Oomph-lib includes
31 #include "generic.h"
32 #include "solid.h"
33 #include "constitutive.h"
34 
35 //The mesh
36 #include "meshes/rectangular_quadmesh.h"
37 
38 // The preconditioner
39 #include "multi_physics/pseudo_elastic_preconditioner.h"
40 
41 
42 using namespace std;
43 
44 using namespace oomph;
45 
46 namespace oomph {
47 
48 //=============start_wrapper==================================================
49 /// Pseudo-Elastic Solid element class to overload the block preconditioner
50 /// methods ndof_types() and get_dof_numbers_for_unknowns() to differentiate
51 /// between DOFs subject to Lagrange multiplier and those that are not.
52 //============================================================================
53 template <class ELEMENT>
55  public virtual ELEMENT
56 {
57 
58 public:
59 
60  /// Constructor
61  PseudoElasticBulkElement() : ELEMENT() {}
62 
63  /// Returns the number of DOF types associated with this element: Twice
64  /// the number of spatial dimensions (for the constrained and
65  /// unconstrained nodal positions).
66  unsigned ndof_types() const
67  {
68  return 2*ELEMENT::dim();
69  }
70 
71  /// Create a list of pairs for all unknowns in this element,
72  /// so that the first entry in each pair contains the global equation
73  /// number of the unknown, while the second one contains the number
74  /// of the "DOF" that this unknown is associated with.
75  /// (Function can obviously only be called if the equation numbering
76  /// scheme has been set up.)\n
77  /// E.g. in a 3D problem there are 6 types of DOF:\n
78  /// 0 - x displacement (without lagr mult traction)\n
79  /// 1 - y displacement (without lagr mult traction)\n
80  /// 2 - z displacement (without lagr mult traction)\n
81  /// 4 - x displacement (with lagr mult traction)\n
82  /// 5 - y displacement (with lagr mult traction)\n
83  /// 6 - z displacement (with lagr mult traction)\n
85  std::list<std::pair<unsigned long,unsigned> >& dof_lookup_list) const
86  {
87  // temporary pair (used to store dof lookup prior to being added to list
88  std::pair<unsigned,unsigned> dof_lookup;
89 
90  // number of nodes
91  const unsigned n_node = this->nnode();
92 
93  //Get the number of position dofs and dimensions at the node
94  const unsigned n_position_type = ELEMENT::nnodal_position_type();
95  const unsigned nodal_dim = ELEMENT::nodal_dimension();
96 
97  //Integer storage for local unknown
98  int local_unknown=0;
99 
100  //Loop over the nodes
101  for(unsigned n=0;n<n_node;n++)
102  {
103  unsigned offset = 0;
104  if (this->node_pt(n)->nvalue() != this->required_nvalue(n))
105  {
106  offset = ELEMENT::dim();
107  }
108 
109  //Loop over position dofs
110  for(unsigned k=0;k<n_position_type;k++)
111  {
112  //Loop over dimension
113  for(unsigned i=0;i<nodal_dim;i++)
114  {
115  //If the variable is unpinned
116  local_unknown = ELEMENT::position_local_eqn(n,k,i);
117  if (local_unknown >= 0)
118  {
119  // store dof lookup in temporary pair: First entry in pair
120  // is global equation number; second entry is dof type
121  dof_lookup.first = this->eqn_number(local_unknown);
122  dof_lookup.second = offset+i;
123 
124  // add to list
125  dof_lookup_list.push_front(dof_lookup);
126  }
127  }
128  }
129  }
130  }
131 };
132 
133 
134 
135 
136 
137 //===========start_face_geometry==============================================
138 /// FaceGeometry of wrapped element is the same as the underlying element
139 //============================================================================
140 template<class ELEMENT>
141 class FaceGeometry<PseudoElasticBulkElement<ELEMENT> > :
142  public virtual FaceGeometry<ELEMENT>
143 {
144 
145 public:
146 
147  /// Constructor -- required for more recent versions of gcc
149 
150 };
151 
152 
153 
154 }
155 
156 
157 
158 
159 /// ///////////////////////////////////////////////////////////////////
160 /// ///////////////////////////////////////////////////////////////////
161 /// ///////////////////////////////////////////////////////////////////
162 
163 
164 
165 //================================================================
166 /// Namespace to "hide" global function that creates an instance
167 /// of oomph-lib's diagonal preconditioner.
168 //================================================================
170 {
171 
172 /// Create a matrix-based diagonal preconditioner for
173 /// subsidiary linear systems
174  Preconditioner* get_diagonal_preconditioner()
175  {
176  MatrixBasedDiagPreconditioner* prec_pt=
177  new MatrixBasedDiagPreconditioner;
178  return prec_pt;
179  }
180 
181 }
182 
183 
184 /// ///////////////////////////////////////////////////////////////////
185 /// ///////////////////////////////////////////////////////////////////
186 /// ///////////////////////////////////////////////////////////////////
187 
188 
189 
190 //================================================================
191 /// Function-type-object to compare finite elements based on
192 /// their x coordinate
193 //================================================================
194 class FiniteElementComp
195 {
196 
197 public:
198 
199  /// Comparison. Is x coordinate of el1_pt less than that of el2_pt?
200  bool operator()(FiniteElement* const& el1_pt, FiniteElement* const& el2_pt)
201  const
202  {
203  return el1_pt->node_pt(0)->x(0) < el2_pt->node_pt(0)->x(0);
204  }
205 
206 };
207 
208 
209 
210 //======Start_of_warped_line===============================================
211 /// Warped line in 2D space
212 //=========================================================================
213 class WarpedLine : public GeomObject
214 {
215 
216 public:
217 
218  /// Constructor: Specify amplitude of deflection from straight horizontal line
219  WarpedLine(const double& ampl) : GeomObject(1,2)
220  {
221  Ampl=ampl;
222  }
223 
224  /// Broken copy constructor
225  WarpedLine(const WarpedLine& dummy)
226  {
227  BrokenCopy::broken_copy("WarpedLine");
228  }
229 
230  /// Broken assignment operator
231  void operator=(const WarpedLine&)
232  {
233  BrokenCopy::broken_assign("WarpedLine");
234  }
235 
236 
237  /// Empty Destructor
239 
240  /// Position vector at Lagrangian coordinate zeta
241  void position(const Vector<double>& zeta, Vector<double>& r) const
242  {
243  // Position vector
244  r[0] = zeta[0]+5.0*Ampl*zeta[0]*(zeta[0]-1.0)*(zeta[0]-0.7);
245  r[1] = 1.0+Ampl*0.5*(1.0-cos(2.0*MathematicalConstants::Pi*zeta[0]));
246  }
247 
248  /// Parametrised position on object: r(zeta). Evaluated at
249  /// previous timestep. t=0: current time; t>0: previous
250  /// timestep. Forward to steady version
251  void position(const unsigned& t, const Vector<double>& zeta,
252  Vector<double>& r) const
253  {
254  position(zeta,r);
255  }
256 
257  /// Access to amplitude
258  double& ampl() {return Ampl;}
259 
260  /// How many items of Data does the shape of the object depend on?
261  /// None.
262  unsigned ngeom_data() const
263  {
264  return 0;
265  }
266 
267 private:
268 
269  /// Amplitude of perturbation
270  double Ampl;
271 
272 };
273 
274 
275 
276 /// ////////////////////////////////////////////////////////////////////
277 /// ////////////////////////////////////////////////////////////////////
278 /// ////////////////////////////////////////////////////////////////////
279 
280 
281 //=======start_namespace==========================================
282 /// Global parameters
283 //================================================================
285 {
286 
287  /// GeomObject specifying the shape of the boundary: Initially it's flat.
289 
290  /// Poisson's ratio
291  double Nu=0.3;
292 
293  // Generalised Hookean constitutive equations
294  GeneralisedHookean Constitutive_law(&Global_Physical_Variables::Nu);
295 
296 } //end namespace
297 
298 
299 
300 //=============begin_problem============================================
301 /// Problem class for deformation of elastic DOF type by prescribed
302 /// boundary motion.
303 //======================================================================
304 template<class ELEMENT>
305 class PrescribedBoundaryDisplacementProblem : public Problem
306 {
307 
308 public:
309 
310  /// Constructor: Pass in number of elements along axes
311  PrescribedBoundaryDisplacementProblem(const unsigned& nel_1d);
312 
313  /// Update function (empty)
315 
316  /// Update function (empty)
318 
319  /// Access function for the solid mesh
320  ElasticRefineableRectangularQuadMesh<ELEMENT>*& solid_mesh_pt()
321  {return Solid_mesh_pt;}
322 
323  /// Actions before adapt: Wipe the mesh of Lagrange multiplier elements
325 
326  /// Actions after adapt: Rebuild the mesh of Lagrange multiplier elements
328 
329  /// Doc the solution
330  void doc_solution();
331 
332 private:
333 
334  /// Create elements that enforce prescribed boundary motion
335  /// by Lagrange multiplilers
337 
338  /// Delete elements that enforce prescribed boundary motion
339  /// by Lagrange multiplilers
341 
342  /// Pointer to solid mesh
343  ElasticRefineableRectangularQuadMesh<ELEMENT>* Solid_mesh_pt;
344 
345  /// Pointers to meshes of Lagrange multiplier elements
346  SolidMesh* Lagrange_multiplier_mesh_pt;
347 
348  /// DocInfo object for output
349  DocInfo Doc_info;
350 
351 };
352 
353 
354 //===========start_of_constructor=======================================
355 /// Constructor: Pass in number of elements along axes
356 //======================================================================
357 template<class ELEMENT>
359 PrescribedBoundaryDisplacementProblem(const unsigned& nel_1d)
360 {
361 
362  // Create the mesh
363 
364  // # of elements in x-direction
365  unsigned n_x=nel_1d;
366 
367  // # of elements in y-direction
368  unsigned n_y=nel_1d;
369 
370  // Domain length in x-direction
371  double l_x=1.0;
372 
373  // Domain length in y-direction
374  double l_y=1.0;
375 
376  //Now create the mesh
377  solid_mesh_pt() = new ElasticRefineableRectangularQuadMesh<ELEMENT>(
378  n_x,n_y,l_x,l_y);
379 
380  // Set error estimator
381  solid_mesh_pt()->spatial_error_estimator_pt()=new Z2ErrorEstimator;
382 
383  //Assign the physical properties to the elements before any refinement
384  //Loop over the elements in the main mesh
385  unsigned n_element =solid_mesh_pt()->nelement();
386  for(unsigned i=0;i<n_element;i++)
387  {
388  //Cast to a solid element
389  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(solid_mesh_pt()->element_pt(i));
390 
391  // Set the constitutive law
392  el_pt->constitutive_law_pt()=&Global_Physical_Variables::Constitutive_law;
393  }
394 
395  // Refine the mesh uniformly
396  solid_mesh_pt()->refine_uniformly();
397 
398  // Construct the mesh of elements that enforce prescribed boundary motion
399  // by Lagrange multipliers
400  Lagrange_multiplier_mesh_pt=new SolidMesh;
401  create_lagrange_multiplier_elements();
402 
403  // Solid mesh is first sub-mesh
404  add_sub_mesh(solid_mesh_pt());
405 
406  // Add Lagrange multiplier sub-mesh
407  add_sub_mesh(Lagrange_multiplier_mesh_pt);
408 
409  // Build combined "global" mesh
410  build_global_mesh();
411 
412  // Pin nodal positions on all boundaries apart from the top one (2)
413  for (unsigned b=0;b<4;b++)
414  {
415  if (b!=2)
416  {
417  unsigned n_side = solid_mesh_pt()->nboundary_node(b);
418 
419  //Loop over the nodes
420  for(unsigned i=0;i<n_side;i++)
421  {
422  solid_mesh_pt()->boundary_node_pt(b,i)->pin_position(0);
423  solid_mesh_pt()->boundary_node_pt(b,i)->pin_position(1);
424  }
425  }
426  }
427 
428  // Pin the redundant solid pressures (if any)
429  PVDEquationsBase<2>::pin_redundant_nodal_solid_pressures(
430  solid_mesh_pt()->element_pt());
431 
432  // Setup equation numbering scheme
433  cout << "Number of dofs: " << assign_eqn_numbers() << std::endl;
434 
435  // Set output directory
436  Doc_info.set_directory("RESLT");
437 
438  // Create the linear solver
439  IterativeLinearSolver* solver_pt=0;
440 
441  // If we have trilinos, use it
442 #ifdef OOMPH_HAS_TRILINOS
443 
444  // Create solver
445  solver_pt = new TrilinosAztecOOSolver;
446 
447  // Use GMRES
448  dynamic_cast<TrilinosAztecOOSolver*>(solver_pt)->solver_type()
449  = TrilinosAztecOOSolver::GMRES;
450 
451 #else
452 
453  // Use oomph-lib's own GMRES
454  solver_pt = new GMRES<CRDoubleMatrix>;
455 
456 #endif
457 
458  // Set solver
459  linear_solver_pt() = solver_pt;
460 
461  // Create the preconditioner
462  PseudoElasticPreconditioner * prec_pt = new PseudoElasticPreconditioner;
463 
464  // Set solid and lagrange multiplier meshes
465  prec_pt->set_elastic_mesh(Solid_mesh_pt);
466  prec_pt->set_lagrange_multiplier_mesh(Lagrange_multiplier_mesh_pt);
467 
468  // Set the preconditioner
469  solver_pt->preconditioner_pt() = prec_pt;
470 
471  // Use upper block triangular preconditioner for elastic block?
472  if (CommandLineArgs::command_line_flag_has_been_set
473  ("--block_upper_for_elastic_block"))
474  {
475  prec_pt->elastic_preconditioner_type()=
476  PseudoElasticPreconditioner::Block_upper_triangular_preconditioner;
477  }
478 
479 #ifdef OOMPH_HAS_HYPRE
480 
481  // Use Hypre as subsidiary preconditioner (inexact solver) for
482  // linear (sub-)systems to be solved in the elastic block?
483  if (CommandLineArgs::command_line_flag_has_been_set
484  ("--hypre_for_elastic_blocks"))
485  {
486  prec_pt->set_elastic_subsidiary_preconditioner
487  (Pseudo_Elastic_Preconditioner_Subsidiary_Operator_Helper::
488  get_elastic_preconditioner_hypre);
489  }
490 
491 #endif
492 
493 
494 #ifdef OOMPH_HAS_TRILINOS
495 
496  // Use Trilinos CG as subsidiary preconditioner (inexact solver) for
497  // linear (sub-)systems to be solved in the Lagrange multiplier block?
498  if (CommandLineArgs::command_line_flag_has_been_set
499  ("--trilinos_cg_for_lagrange_multiplier_blocks"))
500  {
501  prec_pt->set_lagrange_multiplier_subsidiary_preconditioner
502  (Pseudo_Elastic_Preconditioner_Subsidiary_Operator_Helper::
503  get_lagrange_multiplier_preconditioner);
504  }
505 
506 #endif
507 
508  // Use diagonal scaling as subsidiary preconditioner (inexact solver) for
509  // linear (sub-)systems to be solved in the elastic block?
510  if (CommandLineArgs::command_line_flag_has_been_set
511  ("--diagonal_scaling_for_elastic_blocks"))
512  {
513  prec_pt->set_elastic_subsidiary_preconditioner(
515  }
516 
517 } //end of constructor
518 
519 
520 //=====================start_of_actions_before_adapt======================
521 /// Actions before adapt: Wipe the mesh of elements that impose
522 /// the prescribed boundary displacements
523 //========================================================================
524 template<class ELEMENT>
526 {
527  // Kill the elements and wipe surface mesh
528  delete_lagrange_multiplier_elements();
529 
530  // Rebuild the Problem's global mesh from its various sub-meshes
531  rebuild_global_mesh();
532 
533 }// end of actions_before_adapt
534 
535 
536 
537 //=====================start_of_actions_after_adapt=======================
538 /// Actions after adapt: Rebuild the mesh of elements that impose
539 /// the prescribed boundary displacements
540 //========================================================================
541 template<class ELEMENT>
543 {
544  // Create the elements that impose the displacement constraint
545  // and attach them to the bulk elements that are
546  // adjacent to boundary 2
547  create_lagrange_multiplier_elements();
548 
549  // Rebuild the Problem's global mesh from its various sub-meshes
550  rebuild_global_mesh();
551 
552  // Pin the redundant solid pressures (if any)
553  PVDEquationsBase<2>::pin_redundant_nodal_solid_pressures(
554  solid_mesh_pt()->element_pt());
555 
556 }// end of actions_after_adapt
557 
558 
559 
560 //============start_of_create_lagrange_multiplier_elements===============
561 /// Create elements that impose the prescribed boundary displacement
562 //=======================================================================
563 template<class ELEMENT>
566 {
567  // Lagrange multiplier elements are located on boundary 2:
568  unsigned b=2;
569 
570  // How many bulk elements are adjacent to boundary b?
571  unsigned n_element = solid_mesh_pt()->nboundary_element(b);
572 
573  // Loop over the bulk elements adjacent to boundary b?
574  for(unsigned e=0;e<n_element;e++)
575  {
576  // Get pointer to the bulk element that is adjacent to boundary b
577  ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
578  solid_mesh_pt()->boundary_element_pt(b,e));
579 
580  //Find the index of the face of element e along boundary b
581  int face_index = solid_mesh_pt()->face_index_at_boundary(b,e);
582 
583  // Create new element and add to mesh
584  Lagrange_multiplier_mesh_pt->add_element_pt(
585  new ImposeDisplacementByLagrangeMultiplierElement<ELEMENT>(
586  bulk_elem_pt,face_index));
587  }
588 
589 
590  // Loop over the elements in the Lagrange multiplier element mesh
591  // for elements on the top boundary (boundary 2)
592  n_element=Lagrange_multiplier_mesh_pt->nelement();
593  for(unsigned i=0;i<n_element;i++)
594  {
595  //Cast to a Lagrange multiplier element
596  ImposeDisplacementByLagrangeMultiplierElement<ELEMENT> *el_pt =
597  dynamic_cast<ImposeDisplacementByLagrangeMultiplierElement<ELEMENT>*>
598  (Lagrange_multiplier_mesh_pt->element_pt(i));
599 
600  // Set the GeomObject that defines the boundary shape and
601  // specify which bulk boundary we are attached to (needed to extract
602  // the boundary coordinate from the bulk nodes)
603  el_pt->set_boundary_shape_geom_object_pt(
605 
606  // Loop over the nodes
607  unsigned nnod=el_pt->nnode();
608  for (unsigned j=0;j<nnod;j++)
609  {
610  Node* nod_pt = el_pt->node_pt(j);
611 
612  // Is the node also on boundary 1 or 3?
613  if ((nod_pt->is_on_boundary(1))||(nod_pt->is_on_boundary(3)))
614  {
615  // How many nodal values were used by the "bulk" element
616  // that originally created this node?
617  unsigned n_bulk_value=el_pt->nbulk_value(j);
618 
619  // The remaining ones are Lagrange multipliers and we pin them.
620  unsigned nval=nod_pt->nvalue();
621  for (unsigned j=n_bulk_value;j<nval;j++)
622  {
623  nod_pt->pin(j);
624  }
625  }
626  }
627  }
628 
629 } // end of create_lagrange_multiplier_elements
630 
631 
632 
633 
634 //====start_of_delete_lagrange_multiplier_elements=======================
635 /// Delete elements that impose the prescribed boundary displacement
636 /// and wipe the associated mesh
637 //=======================================================================
638 template<class ELEMENT>
640 {
641  // How many surface elements are in the surface mesh
642  unsigned n_element = Lagrange_multiplier_mesh_pt->nelement();
643 
644  // Loop over the surface elements
645  for(unsigned e=0;e<n_element;e++)
646  {
647  // Kill surface element
648  delete Lagrange_multiplier_mesh_pt->element_pt(e);
649  }
650 
651  // Wipe the mesh
652  Lagrange_multiplier_mesh_pt->flush_element_and_node_storage();
653 
654 } // end of delete_lagrange_multiplier_elements
655 
656 
657 
658 //==============start_doc===========================================
659 /// Doc the solution
660 //==================================================================
661 template<class ELEMENT>
663 {
664 
665  ofstream some_file;
666  char filename[100];
667 
668  // Number of plot points
669  unsigned n_plot = 5;
670 
671 
672  // Output shape of deformed body
673  //------------------------------
674  sprintf(filename,"%s/soln%i.dat",Doc_info.directory().c_str(),
675  Doc_info.number());
676  some_file.open(filename);
677  solid_mesh_pt()->output(some_file,n_plot);
678  some_file.close();
679 
680  // Output Lagrange multipliers
681  //----------------------------
682  sprintf(filename,"%s/lagr%i.dat",Doc_info.directory().c_str(),
683  Doc_info.number());
684  some_file.open(filename);
685 
686  // This makes sure the elements are ordered in same way every time
687  // the code is run -- necessary for validation tests.
688  std::vector<FiniteElement*> el_pt;
689  unsigned nelem=Lagrange_multiplier_mesh_pt->nelement();
690  for (unsigned e=0;e<nelem;e++)
691  {
692  el_pt.push_back(Lagrange_multiplier_mesh_pt->finite_element_pt(e));
693  }
694  std::sort(el_pt.begin(),el_pt.end(),FiniteElementComp());
695  for (unsigned e=0;e<nelem;e++)
696  {
697  el_pt[e]->output(some_file);
698  }
699  some_file.close();
700 
701  // Increment label for output files
702  Doc_info.number()++;
703 
704 } //end doc
705 
706 
707 
708 //=======start_of_main==================================================
709 /// Driver code
710 //======================================================================
711 int main(int argc, char* argv[])
712 {
713 
714 
715 #ifdef OOMPH_HAS_MPI
716 
717  // Start up mpi if oomph-lib has been compiled with parallel support
718  // because parallel versions of trilinos and hypre which are then called
719  // by default) need it.
720  MPI_Helpers::init(argc,argv,false);
721 
722 #endif
723 
724  // Store command line arguments
725  CommandLineArgs::setup(argc,argv);
726 
727  // Define possible command line arguments and parse the ones that
728  // were actually specified
729 
730  // Number of elements along axes
731  unsigned nel_1d=5;
732  CommandLineArgs::specify_command_line_flag("--nel_1d",&nel_1d);
733 
734  // Suppress adaptation (for study of iteration count vs uniform mesh
735  // refinement, say)
736  CommandLineArgs::specify_command_line_flag("--no_adapt");
737 
738  // Use block upper triangular preconditioner for elasticity block
739  CommandLineArgs::specify_command_line_flag("--block_upper_for_elastic_block");
740 
741  // Use Hypre as subsidiary preconditioner (inexact solver) for
742  // linear (sub-)systems to be solved in the elastic block?
743  CommandLineArgs::specify_command_line_flag("--hypre_for_elastic_blocks");
744 
745  // Use Trilinos CG as subsidiary preconditioner (inexact solver) for
746  // linear (sub-)systems to be solved in the Lagrange multiplier block?
747  CommandLineArgs::specify_command_line_flag
748  ("--trilinos_cg_for_lagrange_multiplier_blocks");
749 
750  // Use diagonal scaling as subsidiary preconditioner (inexact solver) for
751  // linear (sub-)systems to be solved in the elastic block?
752  // [only used for exercise]
753  CommandLineArgs::specify_command_line_flag
754  ("--diagonal_scaling_for_elastic_blocks");
755 
756  // Parse command line
757  CommandLineArgs::parse_and_assign();
758 
759  // Doc what has actually been specified on the command line
760  CommandLineArgs::doc_specified_flags();
761 
762  //Set up the problem with specified number of elements along axes.
765 
766  // Doc initial domain shape
767  problem.doc_solution();
768 
769  // Max. number of adaptations per solve
770  unsigned max_adapt=1;
771  if (CommandLineArgs::command_line_flag_has_been_set("--no_adapt"))
772  {
773  max_adapt=0;
774  }
775 
776  //Parameter incrementation
777  unsigned nstep=2;
778  for(unsigned i=0;i<nstep;i++)
779  {
780  // Increment imposed boundary displacement
782 
783  // Solve the problem with Newton's method, allowing
784  // up to max_adapt mesh adaptations after every solve.
785  problem.newton_solve(max_adapt);
786 
787  // Doc solution
788  problem.doc_solution();
789 
790  // For maximum stability: Reset the current nodal positions to be
791  // the "stress-free" ones -- this assignment means that the
792  // parameter study no longer corresponds to a physical experiment
793  // but is what we'd do if we wanted to use the solid solve
794  // to update a fluid mesh in an FSI problem, say.
795  problem.solid_mesh_pt()->set_lagrangian_nodal_coordinates();
796 
797  }
798 
799 } //end of main
800 
801 
802 
803 
804 
805 
806 
807 
Function-type-object to compare finite elements based on their x coordinate.
bool operator()(FiniteElement *const &el1_pt, FiniteElement *const &el2_pt) const
Comparison. Is x coordinate of el1_pt less than that of el2_pt?
Problem class for deformation of elastic block by prescribed boundary motion.
void delete_lagrange_multiplier_elements()
Delete elements that enforce prescribed boundary motion by Lagrange multiplilers.
void actions_before_adapt()
Actions before adapt: Wipe the mesh of Lagrange multiplier elements.
void actions_after_adapt()
Actions after adapt: Rebuild the mesh of Lagrange multiplier elements.
void doc_solution()
Doc the solution.
ElasticRefineableRectangularQuadMesh< ELEMENT > *& solid_mesh_pt()
Access function for the solid mesh.
void create_lagrange_multiplier_elements()
Create elements that enforce prescribed boundary motion by Lagrange multiplilers.
Warped line in 2D space.
void position(const unsigned &t, const Vector< double > &zeta, Vector< double > &r) const
Parametrised position on object: r(zeta). Evaluated at previous timestep. t=0: current time; t>0: pre...
WarpedLine(const WarpedLine &dummy)
Broken copy constructor.
WarpedLine(const double &ampl)
Constructor: Specify amplitude of deflection from straight horizontal line.
unsigned ngeom_data() const
How many items of Data does the shape of the object depend on? None.
void position(const Vector< double > &zeta, Vector< double > &r) const
Position vector at Lagrangian coordinate zeta.
void operator=(const WarpedLine &)
Broken assignment operator.
double & ampl()
Access to amplitude.
FaceGeometry()
Constructor – required for more recent versions of gcc.
Pseudo-Elastic Solid element class to overload the block preconditioner methods ndof_types() and get_...
unsigned ndof_types() const
Returns the number of DOF types associated with this element: Twice the number of spatial dimensions ...
void get_dof_numbers_for_unknowns(std::list< std::pair< unsigned long, unsigned > > &dof_lookup_list) const
Create a list of pairs for all unknowns in this element, so that the first entry in each pair contain...
/////////////////////////////////////////////////////////////////// /////////////////////////////////...
Preconditioner * get_diagonal_preconditioner()
Create a matrix-based diagonal preconditioner for subsidiary linear systems.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
WarpedLine Boundary_geom_object(0.0)
GeomObject specifying the shape of the boundary: Initially it's flat.
int main(int argc, char *argv[])
Driver code.