nodes.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 // This header contains class and function prototypes for Data, Node
27 // and associated objects
28 
29 // Include guard to prevent multiple inclusions of the header
30 #ifndef OOMPH_NODES_HEADER
31 #define OOMPH_NODES_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 // C++ headers
43 #include <map>
44 #include <set>
45 #include <climits>
46 #include <string>
47 
48 // oomph-lib headers
49 #include "Vector.h"
50 #include "matrices.h"
51 #include "oomph_utilities.h"
52 
53 namespace oomph
54 {
55  // The following classes are used in the Data class,
56  // so we provide forward references here
57  class TimeStepper;
58  class SolidNode;
59  class HijackedData;
60  class CopiedData;
61  class BoundaryNodeBase;
62  template<class NODE_TYPE>
63  class BoundaryNode;
64 
65  //=====================================================================
66  /// A class that represents a collection of data;
67  /// each Data object may contain many different individual values,
68  /// as would be natural in non-scalar problems.
69  /// Data provides storage for auxiliary `history' values that are
70  /// used by TimeStepper objects to calculate the time derivatives of the
71  /// stored data and also stores a pointer to the appropriate TimeStepper
72  /// object.
73  /// In addition, an associated (global) equation number is
74  /// stored for each value.
75  ///
76  /// The Data class permits copies of the stored data values and equation
77  /// numbers into another Data object using the copy() function.
78  /// Shallow (pointer based) copies of
79  /// the values can be obtained by using specific derived classes. In such
80  /// cases pointers to the objects that contain the pointer-based copies
81  /// should be stored in the original Data class
82  /// (in the array Copy_of_data_pt)
83  /// so that resize and destruction operations can be performed safely.
84  //=====================================================================
85  class Data
86  {
87  private:
88  // We wish certain classes to have access to the internal data
89  // storage model so that the pointers to the values and equations can be
90  // used for efficiency reasons. In particular, any derived classes
91  // that contains shallow copies of Data values
92  //(BoundaryNodeBase, CopiedData and HijackedData) must have pointer-access.
93  friend class HijackedData;
94  friend class CopiedData;
95  friend class BoundaryNodeBase;
96  template<class NODE_TYPE>
97  friend class BoundaryNode;
98 
99  // SolidNodes use their knowledge of
100  // the internal storage of the data values to efficiently implement
101  // the use of positions as variables for solid mechanics problems.
102  friend class SolidNode;
103 
104  /// C-style array of pointers to data values and
105  /// possible history values. The data must be ordered in such a way
106  /// that Value[i][t] gives the i-th data value at the time value t.
107  /// The ordering is chosen so that all the time levels of a particular
108  /// value can be access from a single pointer to a double. This is
109  /// required for copying/hijacking functionality.
110  /// The data should be accessed by using the member functions
111  /// value(time,ival) and set_value(time,ival,value), where time=0: present.
112  double** Value;
113 
114  /// C-style array of pointers to the (global) equation numbers
115  /// of the values.
116  long* Eqn_number;
117 
118  /// Pointer to a Timestepper.
119  /// The inclusion of a Timestepper pointer in the Data class, ensures that
120  /// time-derivatives can be calculated and storage can be managed at the
121  /// low (Data) level.
123 
124  protected:
125  /// C-style array of any Data objects that contain copies
126  /// of the current Data object's data values.
128 
129  /// Number of Data that contain copies of this Data object's
130  /// values
131  unsigned Ncopies;
132 
133  private:
134  /// Number of values stored in the data object.
135  unsigned Nvalue;
136 
137 #ifdef OOMPH_HAS_MPI
138 
139  /// Non-halo processor ID for Data; -1 if it's not a halo.
141 
142 #endif
143 
144  /// Check that the arguments are within
145  /// the range of the stored data values and timesteps.
146  void range_check(const unsigned& t, const unsigned& i) const;
147 
148  /// Delete all storage allocated by the Data object for values
149  /// and equation numbers.
150  void delete_value_storage();
151 
152  /// Add the pointer data_pt to the array Copy_of_data_pt.
153  /// This should be used whenever copies are made of the data.
154  void add_copy(Data* const& data_pt);
155 
156  /// Remove the pointer data_pt from the array Copy_of_data_pt.
157  /// This should be used whenever copies of the data are deleted.
158  void remove_copy(Data* const& data_pt);
159 
160  protected:
161  /// Default (static) timestepper used in steady problems.
163 
164  /// Helper function that should be overloaded in derived classes
165  /// that can contain copies of Data. The function must
166  /// reset the internal pointers to the copied data. This is used
167  /// when resizing data to ensure that all the pointers remain valid.
168  /// The default implementation throws an error beacause Data cannot be
169  /// a copy.
170  virtual void reset_copied_pointers();
171 
172  public:
173  /// Helper function that should be overloaded derived classes
174  /// that contain copies of data. The function must
175  /// unset (NULL out) the internal pointers to the copied data.
176  /// This is used when destructing data to ensure that all pointers remain
177  /// valid. The default implementation throws an error because Data cannot
178  /// be a copy.
179  virtual void clear_copied_pointers();
180 
181  /// Static "Magic number" used in place of the equation number to
182  /// indicate that the value is pinned.
183  static long Is_pinned;
184 
185  /// Static "Magic number" used in place of the equation number to
186  /// indicate that the value is pinned, but only for the duration of a
187  /// segregated solve.
189 
190  /// Static "Magic number" used in place of the equation number to
191  /// denote a value that hasn't been classified as pinned or free.
192  static long Is_unclassified;
193 
194  /// Static "Magic number" used in place of the equation number to
195  /// indicate that the value is constrained because it is associated
196  /// with non-conforming element boundaries --- a hanging node ---
197  /// (and is therefore pinned)
198  static long Is_constrained;
199 
200  /// Default: Just set pointer to (steady) timestepper.
201  /// No storage for values is allocated.
202  Data();
203 
204  /// Default constructor for steady problems:
205  /// assign memory for initial_n_value values.
206  Data(const unsigned& initial_n_value);
207 
208  /// Constructor for unsteady problems: assign memory for
209  /// initial_n_value values and any memory required by the Timestepper for
210  /// the storage of history values.
211  // ALH: Note the "awkward" C++ syntax for passing a constant reference to
212  // a pointer. N.B. We cannot change the pointer, but we can change
213  // what it points to. We could use a const pointer, to prevent change of the
214  // object, but that brings in a whole additional layer of complexity.
216  const unsigned& initial_n_value,
217  const bool& allocate_storage = true);
218 
219  /// Broken copy constructor.
220  Data(const Data& data) = delete;
221 
222  /// Broken assignment operator.
223  void operator=(const Data&) = delete;
224 
225  /// Output operator: output all values at all times, along with any extra
226  /// information stored for the timestepper.
227  friend std::ostream& operator<<(std::ostream& out, const Data& d);
228 
229  /// Destructor, deallocates memory assigned for data.
230  virtual ~Data();
231 
232  /// Set a new timestepper by resizing the appropriate storage.
233  /// If already assigned the equation numbering will not be altered
235  const bool& preserve_existing_data);
236 
237  /// Return the pointer to the timestepper.
239  {
240  return Time_stepper_pt;
241  }
242 
243  /// Return the pointer to the timestepper (const version).
244  TimeStepper* const& time_stepper_pt() const
245  {
246  return Time_stepper_pt;
247  }
248 
249  /// Return a boolean to indicate whether
250  /// the Data objact contains any copied values.
251  /// A base Data object can never be a copy so the default implementation
252  /// always returns false.
253  virtual bool is_a_copy() const
254  {
255  return false;
256  }
257 
258  /// Return flag to indicate whether the i-th value is a copy.
259  /// A base Data object can never be a copy so the default implementation
260  /// always returns false.
261  virtual bool is_a_copy(const unsigned& i) const
262  {
263  return false;
264  }
265 
266  /// Set the i-th stored data value to specified value.
267  /// The only reason that we require an explicit set function is
268  /// because we redefine value() in the Node class to interpolate
269  /// the values for nodes that are hanging and so we cannot
270  /// return a reference to the value in this case.
271  void set_value(const unsigned& i, const double& value_)
272  {
273 #ifdef RANGE_CHECKING
274  range_check(0, i);
275 #endif
276  Value[i][0] = value_;
277  }
278 
279  /// Set the t-th history value of the i-th stored data value to
280  /// specified value.
281  void set_value(const unsigned& t, const unsigned& i, const double& value_)
282  {
283 #ifdef RANGE_CHECKING
284  range_check(t, i);
285 #endif
286  Value[i][t] = value_;
287  }
288 
289  /// Return i-th stored value.
290  /// This function is not virtual so that it can be inlined.
291  /// This means that if we have an explicit pointer to a Data object
292  /// Data* data_pt->value() always returns the "raw" stored value.
293  double value(const unsigned& i) const
294  {
295 #ifdef RANGE_CHECKING
296  range_check(0, i);
297 #endif
298  return Value[i][0];
299  }
300 
301  /// Return i-th value at time level t (t=0: present, t>0: previous)
302  /// This function is not virtual so that it can be inlined.
303  /// This means that if we have an explicit pointer to a Data object
304  /// Data* data_pt->value() always returns to the "raw" stored value.
305  double value(const unsigned& t, const unsigned& i) const
306  {
307 #ifdef RANGE_CHECKING
308  range_check(t, i);
309 #endif
310  return Value[i][t];
311  }
312 
313  /// Compute Vector of values for the Data value.
314  void value(Vector<double>& values) const;
315 
316  /// Compute Vector of values (dofs or pinned) in this data
317  /// at time level t (t=0: present; t>0: previous).
318  void value(const unsigned& t, Vector<double>& values) const;
319 
320  /// Return the pointer to the i-the stored value.
321  /// Typically this is required when direct access
322  /// to the stored value is required, e.g. when writing functions that
323  /// return a reference to a variable that is stored in a Data object.
324  double* value_pt(const unsigned& i) const
325  {
326 #ifdef RANGE_CHECKING
327  range_check(0, i);
328 #endif
329  return Value[i];
330  }
331 
332  /// Return the pointer to the i-th stored value,
333  /// or any of its history values (const version).
334  /// Typically this is required when direct access
335  /// to the stored value is required, e.g. when writing functions that
336  /// return a reference to a variable that is stored in a Data object.
337  double* value_pt(const unsigned& t, const unsigned& i) const
338  {
339 #ifdef RANGE_CHECKING
340  range_check(t, i);
341 #endif
342  return &Value[i][t];
343  }
344 
345  /// Check whether the pointer parameter_pt addresses internal data values
346  bool does_pointer_correspond_to_value(double* const& parameter_pt);
347 
348  /// Copy Data values from specified Data object
349  void copy(Data* orig_data_pt);
350 
351  /// Dump the data object to a file.
352  void dump(std::ostream& dump_file) const;
353 
354  /// Read data object from a file.
355  void read(std::ifstream& restart_file);
356 
357  /// Return the pointer to the equation number of the i-th stored variable.
358  long* eqn_number_pt(const unsigned& i)
359  {
360 #ifdef RANGE_CHECKING
361  range_check(0, i);
362 #endif
363  return &Eqn_number[i];
364  }
365 
366  /// Return the equation number of the i-th stored variable.
367  inline long& eqn_number(const unsigned& i)
368  {
369 #ifdef RANGE_CHECKING
370  range_check(0, i);
371 #endif
372  return Eqn_number[i];
373  }
374 
375  /// Return the equation number of the i-th stored variable.
376  inline long eqn_number(const unsigned& i) const
377  {
378 #ifdef RANGE_CHECKING
379  range_check(0, i);
380 #endif
381  return Eqn_number[i];
382  }
383 
384  /// Pin the i-th stored variable.
385  inline void pin(const unsigned& i)
386  {
388  }
389 
390  /// Unpin the i-th stored variable.
391  inline void unpin(const unsigned& i)
392  {
394  }
395 
396  /// Pin all the stored variables
397  void pin_all()
398  {
399  const unsigned n_value = Nvalue;
400  for (unsigned i = 0; i < n_value; i++)
401  {
403  }
404  }
405 
406  /// Unpin all the stored variables
407  void unpin_all()
408  {
409  const unsigned n_value = Nvalue;
410  for (unsigned i = 0; i < n_value; i++)
411  {
413  }
414  }
415 
416  /// Test whether the i-th variable is pinned (1: true; 0: false).
417  bool is_pinned(const unsigned& i) const
418  {
419  return (Eqn_number[i] == Is_pinned);
420  }
421 
422  /// Test whether the i-th variable is temporaily pinned for a
423  /// segregated solve.
424  bool is_segregated_solve_pinned(const unsigned& i)
425  {
427  }
428 
429  /// Constrain the i-th stored variable when making hanging data
430  /// If the data is already pinned leave it along, otherwise mark as
431  /// constrained (hanging)
432  inline void constrain(const unsigned& i)
433  {
434  if (eqn_number(i) != Is_pinned)
435  {
437  }
438  }
439 
440  /// Unconstrain the i-th stored variable when make the data
441  /// nonhanging. Only unconstrain if it was actually constrained (hanging)
442  inline void unconstrain(const unsigned& i)
443  {
444  if (eqn_number(i) == Is_constrained)
445  {
447  }
448  }
449 
450  /// Constrain all the stored variables when the data is made hanging
452  {
453  const unsigned n_value = Nvalue;
454  for (unsigned i = 0; i < n_value; i++)
455  {
456  constrain(i);
457  }
458  }
459 
460  /// Unconstrain all the stored variables when the data is made nonhanging
462  {
463  const unsigned n_value = Nvalue;
464  for (unsigned i = 0; i < n_value; i++)
465  {
466  unconstrain(i);
467  }
468  }
469 
470  /// Test whether the i-th variable is constrained (1: true; 0:
471  /// false).
472  bool is_constrained(const unsigned& i)
473  {
474  return (Eqn_number[i] == Is_constrained);
475  }
476 
477 
478  /// Self-test: Have all values been classified as pinned/unpinned?
479  /// Return 0 if OK.
480  unsigned self_test();
481 
482  /// Return number of values stored in data object (incl pinned ones).
483  unsigned nvalue() const
484  {
485  return Nvalue;
486  }
487 
488  /// Return total number of doubles stored per value
489  /// to record time history of each value (one for steady problems).
490  unsigned ntstorage() const;
491 
492  /// Assign global equation numbers; increment global number
493  /// of unknowns, global_ndof; and add any new dofs to the dof_pt.
494  virtual void assign_eqn_numbers(unsigned long& global_ndof,
495  Vector<double*>& dof_pt);
496 
497  /// Function to describe the dofs of the Node. The ostream
498  /// specifies the output stream to which the description
499  /// is written; the string stores the currently
500  /// assembled output that is ultimately written to the
501  /// output stream by Data::describe_dofs(...); it is typically
502  /// built up incrementally as we descend through the
503  /// call hierarchy of this function when called from
504  /// Problem::describe_dofs(...)
505  virtual void describe_dofs(std::ostream& out,
506  const std::string& current_string) const;
507 
508  /// Change (increase) the number of values that may be stored.
509  virtual void resize(const unsigned& n_value);
510 
511  /// Add pointers to all unpinned and unconstrained data to a map
512  /// indexed by (global) equation number
513  virtual void add_value_pt_to_map(
514  std::map<unsigned, double*>& map_of_value_pt);
515 
516 #ifdef OOMPH_HAS_MPI
517 
518  /// Label the node as halo and specify processor that holds
519  /// non-halo counterpart
520  void set_halo(const unsigned& non_halo_proc_ID)
521  {
523  }
524 
525  /// Label the node as not being a halo
526  void set_nonhalo()
527  {
528  Non_halo_proc_ID = -1;
529  }
530 
531  /// Is this Data a halo?
532  bool is_halo() const
533  {
534  return (Non_halo_proc_ID != -1);
535  }
536 
537  /// ID of processor ID that holds non-halo counterpart
538  /// of halo node; negative if not a halo.
540  {
541  return Non_halo_proc_ID;
542  }
543 
544  /// Add all data and time history values to the vector in
545  /// the internal storage order
546  virtual void add_values_to_vector(Vector<double>& vector_of_values);
547 
548  /// Read all data and time history values from the vector
549  /// starting from index. On return the index will be
550  /// set to the value at the end of the data that has been read in
551  virtual void read_values_from_vector(const Vector<double>& vector_of_values,
552  unsigned& index);
553 
554 
555  /// Add all equation numbers to the vector in
556  /// the internal storage order
557  virtual void add_eqn_numbers_to_vector(Vector<long>& vector_of_eqn_numbers);
558 
559  /// Read all equation numbers from the vector
560  /// starting from index. On return the index will be
561  /// set to the value at the end of the data that has been read in
562  virtual void read_eqn_numbers_from_vector(
563  const Vector<long>& vector_of_eqn_numbers, unsigned& index);
564 
565 
566 #endif
567  };
568 
569  //=========================================================================
570  /// Custom Data class that is used when HijackingData.
571  /// The class always contains a single value that is
572  /// copied from another Data object.
573  //=========================================================================
574  class HijackedData : public Data
575  {
576  private:
577  /// Pointer to the Data object from which the value is copied
579 
580  /// Index of the value that is copied from within the Data object
581  unsigned Copied_index;
582 
583  /// Reset the pointers to the copied data.
584  void reset_copied_pointers();
585 
586  public:
587  /// Clear the pointers to the copied data
588  void clear_copied_pointers();
589 
590  /// Constructor
591  HijackedData(const unsigned& copied_value, Data* const& data_pt);
592 
593  /// (Shallow) copy constructor
594  HijackedData(const Data& data) = delete;
595 
596  /// Broken assignment operator
597  void operator=(const HijackedData&) = delete;
598 
599  /// Destructor informs original object that the copy is
600  /// being deleted and clears its pointers to the stored values.
602  {
603  // Inform the Copied data that this copy is being deleted
604  // If the original has already been deleted
605  // Copied_data_pt will be set to NULL and this will not be
606  // necessary
607  if (Copied_data_pt)
608  {
610  }
611  // Now null out the storage
612  Copied_data_pt = 0;
613  Value = 0;
614  Eqn_number = 0;
615  }
616 
617  /// Return a boolean to indicate whether the data contains
618  /// any copied values. Hijacked data is always a copy
619  bool is_a_copy() const
620  {
621  return true;
622  }
623 
624  /// Return a boolean to indicate whether
625  /// the i-th value is a copied value.
626  /// Hijacked data is always a copy
627  bool is_a_copy(const unsigned& i) const
628  {
629  return true;
630  }
631 
632  /// HijackedData is always a copy, so no equation numbers
633  /// should be allocated. This function just returns.
634  void assign_eqn_numbers(unsigned long& global_ndof, Vector<double*>& dof_pt)
635  {
636  return;
637  }
638 
639 
640  /// We cannot resize HijackedData, so the resize function
641  /// throws a warning.
642  void resize(const unsigned& n_value);
643  };
644 
645 
646  //=========================================================================
647  /// Custom Data class that is used when making a shallow copy
648  /// of a data object. The class contains a copy of an entire other
649  /// Data object.
650  //=========================================================================
651  class CopiedData : public Data
652  {
653  private:
654  /// Pointer to the Data object from which the values are copied
656 
657  /// Reset the pointers to the copied data.
658  void reset_copied_pointers();
659 
660  public:
661  /// Clear the pointers to the copied data
662  void clear_copied_pointers();
663 
664  /// Constructor
665  CopiedData(Data* const& data_pt);
666 
667  /// (Shallow) copy constructor
668  CopiedData(const Data& data) = delete;
669 
670  /// Broken assignment operator
671  void operator=(const CopiedData&) = delete;
672 
673  /// Destructor informs original object that the copy is
674  /// being deleted and clears its pointers to the stored values.
676  {
677  // Inform the Copied data that this copy is being deleted
678  // If the original has already been deleted
679  // Copied_data_pt will be set to NULL and this will not be
680  // necessary
681  if (Copied_data_pt)
682  {
684  }
685  // Now null out the storage
686  Copied_data_pt = 0;
687  Value = 0;
688  Eqn_number = 0;
689  }
690 
691  /// Return a boolean to indicate whether the data contains
692  /// any copied values. Copied data is always a copy
693  bool is_a_copy() const
694  {
695  return true;
696  }
697 
698  /// Return a boolean to indicate whether
699  /// the i-th value is a copied value.
700  /// All copied data is always a copy
701  bool is_a_copy(const unsigned& i) const
702  {
703  return true;
704  }
705 
706  /// CopiedData is always a copy, so no equation numbers
707  /// should be allocated. This function just returns.
708  void assign_eqn_numbers(unsigned long& global_ndof, Vector<double*>& dof_pt)
709  {
710  return;
711  }
712 
713 
714  /// We cannot resize CopiedData, so the resize function
715  /// throws a warning.
716  void resize(const unsigned& n_value);
717  };
718 
719 
720  // Nodes are required in the HangInfo class, so we need a forward reference
721  class Node;
722 
723 
724  //=====================================================================
725  /// Class that contains data for hanging nodes.
726  ///
727  /// To ensure inter-element continuity, the values and nodal positions
728  /// of hanging nodes must be linear combinations of the
729  /// values and positions on certain adjacent "master" nodes.
730  /// For every hanging node \f$ J \f$ ,
731  /// \f[ {\bf U}_J = \sum_{K} {\bf U}_{K} \omega_{JK} \f]
732  /// and
733  /// \f[ {\bf X}_J = \sum_{K} {\bf X}_{K} \omega_{JK} \f],
734  /// where \f$ {\bf U}_I \f$ and \f$ {\bf U}_I \f$ are Vectors containing
735  /// the nodal values and positions of node
736  /// \f$ I \f$ respectively; the sum is taken over the hanging node's
737  /// master nodes \f$ K \f$ and \f$ \omega_{JK} \f$ are suitable weights.
738  /// This class provides storage and access functions for the
739  /// pointers to the master nodes and their associated weights.
740  //=====================================================================
741  class HangInfo
742  {
743  public:
744  /// Default constructor, initialise vectors to have size zero
746  {
747 #ifdef LEAK_CHECK
749 #endif
750  }
751 
752  /// Alternative constructor when the number of master nodes is known
753  HangInfo(const unsigned& n_master) : Nmaster(n_master)
754  {
755 #ifdef LEAK_CHECK
757 #endif
758  Master_nodes_pt = new Node*[n_master];
759  Master_weights = new double[n_master];
760  }
761 
762  /// Delete the storage
764  {
765 #ifdef LEAK_CHECK
767 #endif
768  // If there is any storage, then delete it
769  if (Nmaster > 0)
770  {
771  delete[] Master_nodes_pt;
772  Master_nodes_pt = 0;
773  delete[] Master_weights;
774  Master_weights = 0;
775  }
776  }
777 
778  /// Broken copy constructor
779  HangInfo(const HangInfo&) = delete;
780 
781  /// Broken assignment operator
782  void operator=(const HangInfo&) = delete;
783 
784  /// Return the number of master nodes
785  unsigned nmaster() const
786  {
787  return Nmaster;
788  }
789 
790  /// Return a pointer to the i-th master node
791  Node* const& master_node_pt(const unsigned& i) const
792  {
793 #ifdef PARANOID
794  if (Nmaster == 0)
795  {
796  throw OomphLibError("Hanging node data hasn't been setup yet \n",
797  OOMPH_CURRENT_FUNCTION,
798  OOMPH_EXCEPTION_LOCATION);
799  }
800 #endif
801 #ifdef RANGE_CHECKING
802  range_check(i);
803 #endif
804  return Master_nodes_pt[i];
805  }
806 
807  /// Return weight for dofs on i-th master node
808  double const& master_weight(const unsigned& i) const
809  {
810 #ifdef PARANOID
811  if (Nmaster == 0)
812  {
813  throw OomphLibError("Hanging node data hasn't been setup yet \n",
814  OOMPH_CURRENT_FUNCTION,
815  OOMPH_EXCEPTION_LOCATION);
816  }
817 #endif
818 #ifdef RANGE_CHECKING
819  range_check(i);
820 #endif
821  return Master_weights[i];
822  }
823 
824  /// Set the pointer to the i-th master node and its weight
825  void set_master_node_pt(const unsigned& i,
826  Node* const& master_node_pt,
827  const double& weight);
828 
829  /// Add (pointer to) master node and corresponding weight to
830  /// the internally stored (pointers to) master nodes and weights
831  void add_master_node_pt(Node* const& master_node_pt, const double& weight);
832 
833  private:
834  /// Check that the argument is within the range of
835  /// stored data values.
836  void range_check(const unsigned& i) const;
837 
838  /// C-style array of pointers to nodes that this hanging node depends on
840 
841  /// C-style array of weights for the dofs on the master nodes
842  double* Master_weights;
843 
844  /// Number of master nodes required by this hanging node
845  unsigned Nmaster;
846  };
847 
848  // Geometric objects are (now) required in the Node class, so we
849  // put a forward reference here
850  class GeomObject;
851 
852 
853  //=====================================================================
854  /// Nodes are derived from Data, but, in addition, have a
855  /// definite (Eulerian) position in a space of a given dimension.
856  ///
857  /// The nodal coordinates are used in the elements' mapping
858  /// between local and global coordinates and in the simplest
859  /// case (stationary nodes in Lagrange-type elements) this mapping
860  /// is given by
861  /// \f[ x_i = \sum_{j=1}^{N_{node}} X_{ij} \psi_{j}(s_k) \f]
862  /// so we need only access to the nodal coordinates
863  /// \f$ X_{ij}\ (i=1..DIM) \f$ of all nodes \f$ j \f$ : provided
864  /// by the Node member function
865  /// \code Node::x(i) \endcode
866  ///
867  /// If the nodal positions are time-dependent, the mapping becomes
868  /// \f[ x_i(t) = \sum_{j=1}^{N_{node}} X_{ij}(t) \ \psi_{j}(s_k). \f]
869  /// Within the computation (where time is only evaluated at discrete
870  /// levels) this becomes
871  /// \f[ x_{ti} = \sum_{j=1}^{N_{node}} X_{ijt} \ \psi_{j}(s_k). \f]
872  /// and we need access to the nodal coordinates \f$ X_{ijt} \ (i=1..DIM) \f$
873  /// of all nodes \f$ j \f$ at the present (t=0) and previous (t>0) timesteps:
874  /// provided by the Node member function
875  /// \code Node::x(t,i) \endcode
876  /// \b Note: The interpretation of the history values is slightly more
877  /// subtle than that. Depending on the positional TimeStepper
878  /// used, only a limited number of the positional history values accessed
879  /// \c Node::x(t,i) represent previous nodal positions; the others
880  /// are generalised history values that the TimeStepper uses to
881  /// determine approximations for the time-derivatives of the
882  /// nodal positions.
883  ///
884  /// Finally, some elements employ mappings
885  /// that involve additional, generalised coordinates. For instance,
886  /// in Hermite elements the mapping between local and global coordinates
887  /// is based on an independent interpolation for the global coordinates
888  /// and their derivative w.r.t. to the local coordinates. In such
889  /// elements, the mapping becomes
890  /// \f[ x_i = \sum_{j=1}^{N_{node}} \sum_{k=1}^{N_{type}} X_{ijk} \psi_{jk}(s_k) \f]
891  /// where \f$ N_{type} \f$ is the number of the different types of generalised
892  /// coordinates involved in the mapping. For instance, in 1D Hermite elements
893  /// \f$ N_{type}=2 \f$ and k=0 corresponds to the global coordinates while
894  /// k=1 corresponds to the
895  /// derivative of the global coordinates w.r.t. to the local coordinate.
896  /// In such cases we need access to the generalised nodal coordinates
897  /// \f$ X_{ijk} \ (i=1..DIM, \ k=1..N_{type}) \f$ of all nodes \f$ j \f$.
898  /// Access is provided by the Node member function
899  /// \code Node::x_gen(k,i) \endcode
900  /// and the corresponding time-dependent version
901  /// \code Node::x_gen(t,k,i) \endcode
902  /// While this is all pretty straightforward, it does make the
903  /// argument list of the Node constructors rather lengthy.
904  //=====================================================================
905  class Node : public Data
906  {
907  public:
908  /// Function pointer to auxiliary node update function
909  typedef void (*AuxNodeUpdateFctPt)(Node*);
910 
911  // The BoundaryNodeBase class must use knowledge of the internal data
912  // storage
913  /// to construct periodic Nodes
914  friend class BoundaryNodeBase;
915 
916  protected:
917  /// Private function to check that the arguemnts to the position
918  /// functions are in range
919  void x_gen_range_check(const unsigned& t,
920  const unsigned& k,
921  const unsigned& i) const;
922 
923  /// Array of pointers to the data holding the Eulerian positions.
924  /// The storage format must be the same as the internal data storage
925  /// so that we can implement the functions x() in generality here without
926  /// the need for virtual functions. The first index will be a flat array
927  /// of position types and coordinates and the second will be the number
928  /// of time history values at each position type.
929  double** X_position;
930 
931  /// Pointer to the timestepper associated with the position data.
933 
934  /// C-style array of pointers to hanging node info.
935  /// It's set to NULL if the node isn't hanging.
936  /// The first entry (0) is the geometric hanging node data.
937  /// The remaining entries correspond to the hanging data for the
938  /// other values stored at the node. Usually, these entries will be the
939  /// same as the geometric hanging node data represented by Hanging_pt[0],
940  /// but this is not necessarily the case; e.g. the pressure in Taylor Hood
941  /// has different hanging node data from the velocities.
943 
944  /// Eulerian dimension of the node
945  unsigned Ndim;
946 
947  /// Number of coordinate types used in the mapping between
948  /// local and global coordinates
949  /// (e.g. 1 for Lagrange-type elements; 2 for 1D Hermite elements; 4 for
950  /// 2D Hermite elements, etc).
951  unsigned Nposition_type;
952 
953  /// Flag to indicate that the Node has become
954  /// obsolete --- usually during mesh refinement process
955  bool Obsolete;
956 
957  /// Direct access to the pointer to the i-th stored coordinate data
958  double* x_position_pt(const unsigned& i)
959  {
960  return X_position[i];
961  }
962 
963  /// Pointer to auxiliary update function -- this
964  /// can be used to update any nodal values following the update
965  /// of the nodal position. This is needed e.g. to update the no-slip
966  /// condition on moving boundaries.
968 
969  public:
970  /// Static "Magic number" used to indicate that there is no
971  /// independent position in a periodic node.
972  static unsigned No_independent_position;
973 
974  /// Default constructor
975  Node();
976 
977  /// Steady constructor, for a Node of spatial dimension n_dim.
978  /// Allocates storage for initial_n_value values.
979  /// NPosition_type is the number of coordinate types
980  /// needed in the mapping between local and global coordinates
981  /// (e.g. 1 for Lagrange-type elements; 2 for 1D Hermite elements; 4 for
982  /// 2D Hermite elements, etc).
983  Node(const unsigned& n_dim,
984  const unsigned& n_position_type,
985  const unsigned& initial_n_value,
986  const bool& allocate_x_position = true);
987 
988  /// Unsteady constructor for a node of spatial dimension n_dim.
989  /// Allocates storage for initial_n_value values with
990  /// history values as required by the timestepper.
991  /// n_position_type: # of coordinate
992  /// types needed in the mapping between local and global coordinates
993  /// (e.g. 1 for Lagrange-type elements; 2 for 1D Hermite elements; 4 for
994  /// 2D Hermite elements).
996  const unsigned& n_dim,
997  const unsigned& n_position_type,
998  const unsigned& initial_n_value,
999  const bool& allocate_x_position = true);
1000 
1001  /// Destructor: Clean up the memory allocated for nodal position.
1002  virtual ~Node();
1003 
1004  /// Broken copy constructor
1005  Node(const Node& node) = delete;
1006 
1007  /// Broken assignment operator
1008  void operator=(const Node&) = delete;
1009 
1010  /// Output operator: output location and all values at all times, along with
1011  /// any extra information stored for the timestepper.
1012  friend std::ostream& operator<<(std::ostream& out, const Node& d);
1013 
1014  /// Number of coordinate
1015  /// types needed in the mapping between local and global coordinates.
1016  unsigned nposition_type() const
1017  {
1018  return Nposition_type;
1019  }
1020 
1021  /// Return a pointer to the position timestepper.
1023  {
1024  return Position_time_stepper_pt;
1025  }
1026 
1027  /// Return a pointer to the position timestepper (const version).
1029  {
1030  return Position_time_stepper_pt;
1031  }
1032 
1033  /// Set a new position timestepper be resizing the appropriate
1034  /// storage
1035  virtual void set_position_time_stepper(
1037  const bool& preserve_existing_data);
1038 
1039  /// Check whether the pointer parameter_pt addresses position data
1040  /// values. It never does for a standard node, because the positions are
1041  /// not data
1043  double* const& parameter_pt)
1044  {
1045  return false;
1046  }
1047 
1048  /// Assign global equation numbers; increment global number
1049  /// of unknowns, global_ndof; and add any new dofs to the dof_pt.
1050  virtual void assign_eqn_numbers(unsigned long& global_ndof,
1051  Vector<double*>& dof_pt);
1052 
1053  /// Return (Eulerian) spatial dimension of the node.
1054  unsigned ndim() const
1055  {
1056  return Ndim;
1057  }
1058 
1059  /// Return the i-th nodal coordinate.
1060  double& x(const unsigned& i)
1061  {
1062 #ifdef RANGE_CHECKING
1063  x_gen_range_check(0, 0, i);
1064 #endif
1065  return X_position[Nposition_type * i][0];
1066  }
1067 
1068  /// Return the i-th nodal coordinate (const version).
1069  const double& x(const unsigned& i) const
1070  {
1071 #ifdef RANGE_CHECKING
1072  x_gen_range_check(0, 0, i);
1073 #endif
1074  return X_position[Nposition_type * i][0];
1075  }
1076 
1077  /// Return the position x(i) at previous timestep t
1078  /// (t=0: present; t>0 previous timestep).
1079  double& x(const unsigned& t, const unsigned& i)
1080  {
1081 #ifdef RANGE_CHECKING
1082  x_gen_range_check(t, 0, i);
1083 #endif
1084  return X_position[Nposition_type * i][t];
1085  }
1086 
1087  /// Return the position x(i) at previous timestep t
1088  /// (t=0: present; t>0 previous timestep) (const version)
1089  const double& x(const unsigned& t, const unsigned& i) const
1090  {
1091 #ifdef RANGE_CHECKING
1092  x_gen_range_check(t, 0, i);
1093 #endif
1094  return X_position[Nposition_type * i][t];
1095  }
1096 
1097  /// Return the i-th component of nodal velocity: dx/dt
1098  double dx_dt(const unsigned& i) const;
1099 
1100  /// Return the i-th component of j-th derivative of nodal position:
1101  /// d^jx/dt^j.
1102  double dx_dt(const unsigned& j, const unsigned& i) const;
1103 
1104  /// Return pointer to copied node (null if the
1105  /// current node is not a copy -- always the case here; it's overloaded
1106  /// for boundary nodes)
1107  virtual Node* copied_node_pt() const
1108  {
1109  return 0;
1110  }
1111 
1112  /// Return whether any position coordinate has been copied (always false)
1113  virtual bool position_is_a_copy() const
1114  {
1115  return false;
1116  }
1117 
1118  /// Return whether the position coordinate i has been copied (always false)
1119  virtual bool position_is_a_copy(const unsigned& i) const
1120  {
1121  return false;
1122  }
1123 
1124  /// Reference to the generalised position x(k,i).
1125  /// `Type': k; Coordinate direction: i.
1126  double& x_gen(const unsigned& k, const unsigned& i)
1127  {
1128 #ifdef RANGE_CHECKING
1129  x_gen_range_check(0, k, i);
1130 #endif
1131  return X_position[Nposition_type * i + k][0];
1132  }
1133 
1134  /// Reference to the generalised position x(k,i).
1135  /// `Type': k; Coordinate direction: i (const version).
1136  const double& x_gen(const unsigned& k, const unsigned& i) const
1137  {
1138 #ifdef RANGE_CHECKING
1139  x_gen_range_check(0, k, i);
1140 #endif
1141  return X_position[Nposition_type * i + k][0];
1142  }
1143 
1144  /// Reference to the generalised position x(k,i) at the previous
1145  /// timestep [t=0: present]. `Type': k; Coordinate direction: i.
1146  double& x_gen(const unsigned& t, const unsigned& k, const unsigned& i)
1147  {
1148 #ifdef RANGE_CHECKING
1149  x_gen_range_check(t, k, i);
1150 #endif
1151  return X_position[Nposition_type * i + k][t];
1152  }
1153 
1154  /// Reference to the generalised position x(k,i) at the previous
1155  /// timestep [t=0: present]. `Type': k; Coordinate direction: i.
1156  /// (const version)
1157  const double& x_gen(const unsigned& t,
1158  const unsigned& k,
1159  const unsigned& i) const
1160  {
1161 #ifdef RANGE_CHECKING
1162  x_gen_range_check(t, k, i);
1163 #endif
1164  return X_position[Nposition_type * i + k][t];
1165  }
1166 
1167  /// i-th component of time derivative (velocity) of the
1168  /// generalised position, dx(k,i)/dt. `Type': k; Coordinate direction: i.
1169  double dx_gen_dt(const unsigned& k, const unsigned& i) const;
1170 
1171 
1172  /// i-th component of j-th time derivative (velocity) of the
1173  /// generalised position, d^jx(k,i)/dt^j. `Type': k; Coordinate direction:
1174  /// i.
1175  double dx_gen_dt(const unsigned& j,
1176  const unsigned& k,
1177  const unsigned& i) const;
1178 
1179  /// Direct access to the i-th coordinate at time level t
1180  /// (t=0: present; t>0: previous)
1181  double* x_pt(const unsigned& t, const unsigned& i)
1182  {
1183  return &X_position[Nposition_type * i][t];
1184  }
1185 
1186  /// Copy all nodal data from specified Node object
1187  void copy(Node* orig_node_pt);
1188 
1189  /// Dump nodal position and associated data to file for restart
1190  virtual void dump(std::ostream& dump_file) const;
1191 
1192  /// Read nodal position and associated data from file for restart
1193  void read(std::ifstream& restart_file);
1194 
1195  /// The pin_all() function must be overloaded by SolidNodes,
1196  /// so we put the virtual interface here to avoid virtual functions in Data
1197  virtual void pin_all()
1198  {
1199  Data::pin_all();
1200  }
1201 
1202  /// The unpin_all() function must be overloaded by SolidNode,
1203  /// so we put the virtual interface here to avoid virtual functions in Data
1204  virtual void unpin_all()
1205  {
1206  Data::unpin_all();
1207  }
1208 
1209 
1210  /// Code that encapsulates the hanging status of the node (incl. the
1211  /// geometric hanging status) as
1212  /// \f$ \sum_{i=-1}{nval-1} Node::is_hanging(i) 2^{i+1} \f$
1213  unsigned hang_code()
1214  {
1215  unsigned hang_code = 0;
1216  int nval = nvalue();
1217  for (int i = -1; i < nval; i++)
1218  {
1219  hang_code += unsigned(Node::is_hanging(i)) *
1220  unsigned(std::pow(2.0, double(i + 1)));
1221  }
1222  return hang_code;
1223  }
1224 
1225 
1226  /// Return pointer to hanging node data (this refers to the geometric
1227  /// hanging node status) (const version).
1228  HangInfo* const& hanging_pt() const
1229  {
1230 #ifdef PARANOID
1231  if (Hanging_pt == 0)
1232  {
1233  throw OomphLibError(
1234  "Vector of pointers to hanging data is not setup yet\n",
1235  OOMPH_CURRENT_FUNCTION,
1236  OOMPH_EXCEPTION_LOCATION);
1237  }
1238 #endif
1239  return Hanging_pt[0];
1240  }
1241 
1242  /// Return pointer to hanging node data for value i (const version)
1243  HangInfo* const& hanging_pt(const int& i) const
1244  {
1245 #ifdef PARANOID
1246  if (Hanging_pt == 0)
1247  {
1248  std::ostringstream error_message;
1249  error_message << "Vector of pointers to hanging data is not setup yet\n"
1250 #ifdef OOMPH_HAS_MPI
1251  << "I'm on processor "
1252  << MPI_Helpers::communicator_pt()->my_rank() << "\n"
1253 #endif
1254  << "Coordinates: \n";
1255 
1256  unsigned n_dim = ndim();
1257  for (unsigned i = 0; i < n_dim; i++)
1258  {
1259  error_message << this->x(i) << " ";
1260  }
1261  throw OomphLibError(error_message.str(),
1262  OOMPH_CURRENT_FUNCTION,
1263  OOMPH_EXCEPTION_LOCATION);
1264  }
1265 #endif
1266 #ifdef RANGE_CHECKING
1267  // Range checking code.
1268  // Need to make sure that this is an int otherwise the test
1269  // fails when it shouldn't
1270  const int n_value = static_cast<int>(this->nvalue());
1271  if ((i < -1) || (i > n_value))
1272  {
1273  std::ostringstream error_message;
1274  error_message << "Range Error: Value " << i
1275  << " is not in the range (-1," << n_value << ")";
1276  throw OomphLibError(error_message.str(),
1277  OOMPH_CURRENT_FUNCTION,
1278  OOMPH_EXCEPTION_LOCATION);
1279  }
1280 #endif
1281  return Hanging_pt[i + 1];
1282  }
1283 
1284  /// Test whether the node is geometrically hanging
1285  bool is_hanging() const
1286  {
1287  if (Hanging_pt == 0)
1288  {
1289  return false;
1290  }
1291  else
1292  {
1293  return (Hanging_pt[0] != 0);
1294  }
1295  }
1296 
1297  /// Test whether the i-th value is hanging
1298  bool is_hanging(const int& i) const
1299  {
1300 #ifdef RANGE_CHECKING
1301  // Need to make sure that this is an int otherwise the test
1302  // fails when it shouldn't
1303  const int n_value = static_cast<int>(this->nvalue());
1304  if ((i < -1) || (i > n_value))
1305  {
1306  std::ostringstream error_message;
1307  error_message << "Range Error: Value " << i
1308  << " is not in the range (-1," << n_value << ")";
1309  throw OomphLibError(error_message.str(),
1310  OOMPH_CURRENT_FUNCTION,
1311  OOMPH_EXCEPTION_LOCATION);
1312  }
1313 #endif
1314 
1315  // Test whether the node is geometrically hanging
1316  if (i == -1)
1317  {
1318  return is_hanging();
1319  }
1320  // Otherwise, is the i-th value hanging
1321  else
1322  {
1323  if (Hanging_pt == 0)
1324  {
1325  return false;
1326  }
1327  else
1328  {
1329  return (Hanging_pt[i + 1] != 0);
1330  }
1331  }
1332  }
1333 
1334  /// Set the hanging data for the i-th value. (hang_pt=0 to make non-hanging)
1335  void set_hanging_pt(HangInfo* const& hang_pt, const int& i);
1336 
1337  /// Label node as non-hanging node by removing all hanging node data.
1338  void set_nonhanging();
1339 
1340  /// Resize the number of equations
1341  void resize(const unsigned& n_value);
1342 
1343  /// Constrain the positions when the node is made hanging
1344  /// Empty virtual function that is overloaded in SolidNodes
1345  virtual void constrain_positions() {}
1346 
1347  /// Unconstrain the positions when the node is made non-hanging
1348  /// Empty virtual function that is overloaded in SolidNodes
1349  virtual void unconstrain_positions() {}
1350 
1351  /// Make the node periodic by copying the values from node_pt.
1352  /// Note that the coordinates will always remain independent, even
1353  /// though this may lead to (a little) unrequired information being stored.
1354  /// Broken virtual (only implemented in BoundaryNodes)
1355  virtual void make_periodic(Node* const& node_pt);
1356 
1357  /// Make the nodes passed in the vector periodic_nodes share the
1358  /// same data as this node.
1359  virtual void make_periodic_nodes(const Vector<Node*>& periodic_nodes_pt);
1360 
1361  /// Return a pointer to set of mesh boundaries that this
1362  /// node occupies; this will be overloaded by BoundaryNodes. The
1363  /// default behaviour is that the Node does not lie on any boundaries
1364  /// so the pointer to the set of boundaries is NULL
1365  virtual void get_boundaries_pt(std::set<unsigned>*& boundaries_pt)
1366  {
1367  boundaries_pt = 0;
1368  }
1369 
1370  /// Test whether the Node lies on a boundary. The "bulk" Node
1371  /// cannot lie on a boundary, so return false. This will be overloaded
1372  /// by BoundaryNodes
1373  virtual bool is_on_boundary() const
1374  {
1375  return false;
1376  }
1377 
1378  /// Test whether the node lies on mesh boundary b. The "bulk" Node
1379  /// cannot lie on a boundary, so return false. This will be overloaded by
1380  /// BoundaryNodes
1381  virtual bool is_on_boundary(const unsigned& b) const
1382  {
1383  return false;
1384  }
1385 
1386  /// Broken interface for adding the node to the mesh boundary b
1387  /// Essentially here for error reporting.
1388  virtual void add_to_boundary(const unsigned& b);
1389 
1390  /// Broken interface for removing the node from the mesh boundary b
1391  /// Here to provide error reporting.
1392  virtual void remove_from_boundary(const unsigned& b);
1393 
1394  /// Get the number of boundary coordinates on mesh boundary b.
1395  /// Broken virtual interface provides run-time
1396  /// error checking
1397  virtual unsigned ncoordinates_on_boundary(const unsigned& b);
1398 
1399  /// Have boundary coordinates been set up? Broken virtual interface
1400  /// provides run-time error checking
1402 
1403  /// Return the vector of the k-th generalised boundary coordinates
1404  /// on mesh boundary b. Broken virtual interface provides run-time
1405  /// error checking
1406  virtual void get_coordinates_on_boundary(const unsigned& b,
1407  const unsigned& k,
1408  Vector<double>& boundary_zeta);
1409 
1410  /// Set the vector of the k-th generalised boundary coordinates
1411  /// on mesh boundary b. Broken virtual interface provides run-time error
1412  /// checking
1413  virtual void set_coordinates_on_boundary(
1414  const unsigned& b,
1415  const unsigned& k,
1416  const Vector<double>& boundary_zeta);
1417 
1418  /// Return the vector of coordinates on mesh boundary b
1419  /// Broken virtual interface provides run-time error checking
1420  virtual void get_coordinates_on_boundary(const unsigned& b,
1421  Vector<double>& boundary_zeta)
1422  {
1423  get_coordinates_on_boundary(b, 0, boundary_zeta);
1424  }
1425 
1426  /// Set the vector of coordinates on mesh boundary b
1427  /// Broken virtual interface provides run-time error checking
1429  const unsigned& b, const Vector<double>& boundary_zeta)
1430  {
1431  set_coordinates_on_boundary(b, 0, boundary_zeta);
1432  }
1433 
1434 
1435  /// Mark node as obsolete
1437  {
1438  Obsolete = true;
1439  }
1440 
1441  /// Mark node as non-obsolete
1443  {
1444  Obsolete = false;
1445  }
1446 
1447  /// Test whether node is obsolete
1449  {
1450  return Obsolete;
1451  }
1452 
1453  /// Return the i-th value stored at the Node. This interface
1454  /// does NOT take the hanging status of the Node into account.
1455  double raw_value(const unsigned& i) const
1456  {
1457  return Data::value(i);
1458  }
1459 
1460  /// Return the i-th value at time level t
1461  /// (t=0: present, t>0: previous). This interface does NOT take the
1462  /// hanging status of the Node into account.
1463  double raw_value(const unsigned& t, const unsigned& i) const
1464  {
1465  return Data::value(t, i);
1466  }
1467 
1468  /// Return i-th value (dofs or pinned) at this node
1469  /// either directly or via hanging node representation.
1470  /// Note that this REDFINES the interface in Data
1471  /// Thus, the present function will be called
1472  /// provided that it is accessed through a pointer to a node
1473  /// i.e. Node* node_pt->value()
1474  /// will take hanging information into account.
1475  /// If a pointer to a Node has been explicitly down-cast to a pointer to
1476  /// Data then the "wrong" (Data) version of the function will be called.
1477  double value(const unsigned& i) const;
1478 
1479  /// Return i-th value at time level t (t=0: present, t>0: previous)
1480  /// either directly or via hanging node representation.
1481  /// Note that this REDEFINES the interface in Data
1482  /// Thus, the present function will be called
1483  /// provided that it is accessed through a pointer to a node
1484  /// i.e. Node* node_pt->value()
1485  /// will take hanging information into account.
1486  /// If a pointer to a Node has been explicitly down-cast to a pointer to
1487  /// Data then the "wrong" (Data) version of the function will be called.
1488  double value(const unsigned& t, const unsigned& i) const;
1489 
1490  /// Compute Vector of values for the Data value
1491  /// taking the hanging node status into account.
1492  /// Note that this REDEFINES the interface in Data
1493  /// Thus, the present function will be called
1494  /// provided that it is accessed through a pointer to a node
1495  /// i.e. Node* node_pt->value()
1496  /// will take hanging information into account.
1497  /// If a pointer to a Node has been explicitly down-cast to a pointer to
1498  /// Data then the "wrong" (Data) version of the function will be called.
1499  void value(Vector<double>& values) const;
1500 
1501  /// Return vector of values calculated using value(vector).
1503  {
1504  Vector<double> vals(nvalue(), 0.0);
1505  value(vals);
1506  return vals;
1507  }
1508 
1509  /// Compute Vector of values (dofs or pinned) in this data
1510  /// at time level t (t=0: present; t>0: previous). This interface
1511  /// explicitly takes the hanging status into account.
1512  /// Thus, the present function will be called
1513  /// provided that it is accessed through a pointer to a node
1514  /// i.e. Node* node_pt->value()
1515  /// will take hanging information into account.
1516  /// If a pointer to a Node has been explicitly down-cast to a pointer to
1517  /// Data then the "wrong" (Data) version of the function will be called.
1518  void value(const unsigned& t, Vector<double>& values) const;
1519 
1520  /// Compute Vector of nodal positions
1521  /// either directly or via hanging node representation
1522  void position(Vector<double>& pos) const;
1523 
1524  /// Return vector of position of node at current time.
1526  {
1527  Vector<double> pos(ndim(), 0.0);
1528  position(pos);
1529  return pos;
1530  }
1531 
1532  /// Compute Vector of nodal position at time level t
1533  /// (t=0: current; t>0: previous timestep),
1534  /// either directly or via hanging node representation.
1535  void position(const unsigned& t, Vector<double>& pos) const;
1536 
1537  /// Return i-th nodal coordinate
1538  /// either directly or via hanging node representation.
1539  double position(const unsigned& i) const;
1540 
1541  /// Return i-th nodal coordinate at time level t
1542  /// (t=0: current; t>0: previous time level),
1543  /// either directly or via hanging node representation.
1544  double position(const unsigned& t, const unsigned& i) const;
1545 
1546  /// Return generalised nodal coordinate
1547  /// either directly or via hanging node representation.
1548  double position_gen(const unsigned& k, const unsigned& i) const;
1549 
1550  /// Return generalised nodal coordinate at time level t
1551  /// (t=0: current; t>0: previous time level),
1552  /// either directly or via hanging node representation.
1553  double position_gen(const unsigned& t,
1554  const unsigned& k,
1555  const unsigned& i) const;
1556 
1557  /// Return the i-th component of nodal velocity: dx/dt,
1558  /// either directly or via hanging node representation.
1559  double dposition_dt(const unsigned& i) const;
1560 
1561  /// Return the i-th component of j-th derivative of nodal position:
1562  /// d^jx/dt^j either directly or via hanging node representation
1563  double dposition_dt(const unsigned& j, const unsigned& i) const;
1564 
1565  /// i-th component of time derivative (velocity) of the
1566  /// generalised position, dx(k,i)/dt. `Type': k; Coordinate direction: i.
1567  /// This function uses the hanging node representation if necessary.
1568  double dposition_gen_dt(const unsigned& k, const unsigned& i) const;
1569 
1570 
1571  /// i-th component of j-th time derivative (velocity) of the
1572  /// generalised position, d^jx(k,i)/dt^j. `Type': k; Coordinate direction:
1573  /// i. This function uses the hanging node representation if necessary
1574  double dposition_gen_dt(const unsigned& j,
1575  const unsigned& k,
1576  const unsigned& i) const;
1577 
1578  /// Interface for functions that update the nodal
1579  /// position using algebraic remeshing strategies. The
1580  /// interface is common to SpineNodes, AlgebraicNodes and
1581  /// MacroElementNodeUpdateNodes.
1582  /// The default is that the node does not "update itself"
1583  /// i.e. it is fixed in space. When implemented, this
1584  /// function should also execute the Node's auxiliary
1585  /// node update function (if any).
1586  virtual void node_update(
1587  const bool& update_all_time_levels_for_new_node = false)
1588  {
1589  }
1590 
1591 
1592  /// Set pointer to auxiliary update function -- this
1593  /// can be used to update any nodal values following the update
1594  /// of the nodal position. This is needed e.g. to update the no-slip
1595  /// condition on moving boundaries.
1597  AuxNodeUpdateFctPt aux_node_update_fct_pt)
1598  {
1599  // Set pointer (by default it's set to NULL)
1600  Aux_node_update_fct_pt = aux_node_update_fct_pt;
1601  }
1602 
1603 
1604  /// Boolean to indicate if node has a pointer to
1605  /// and auxiliary update function.
1607  {
1608  return (Aux_node_update_fct_pt != 0);
1609  }
1610 
1611  /// Execute auxiliary update function (if any) -- this
1612  /// can be used to update any nodal values following the update
1613  /// of the nodal position. This is needed e.g. to update the no-slip
1614  /// condition on moving boundaries.
1616  {
1617  if (Aux_node_update_fct_pt != 0)
1618  {
1619  Aux_node_update_fct_pt(this);
1620  }
1621  }
1622 
1623  /// Return the number of geometric data that affect the nodal
1624  /// position. The default value is zero (node is stationary)
1625  virtual inline unsigned ngeom_data() const
1626  {
1627  return 0;
1628  }
1629 
1630  /// Return a pointer to an array of all (geometric) data that affect
1631  /// the nodal position. The default value is zero (node is stationary)
1632  virtual inline Data** all_geom_data_pt()
1633  {
1634  return 0;
1635  }
1636 
1637  /// Return the number of geometric objects that affect the nodal
1638  /// position. The default value is zero (node is stationary)
1639  virtual inline unsigned ngeom_object() const
1640  {
1641  return 0;
1642  }
1643 
1644  /// Return a pointer to an array of all (geometric) objects that
1645  /// affect the nodal position. The default value is zero (node is
1646  /// stationary)
1647  virtual inline GeomObject** all_geom_object_pt()
1648  {
1649  return 0;
1650  }
1651 
1652  /// Output nodal position
1653  void output(std::ostream& outfile);
1654 
1655 
1656 #ifdef OOMPH_HAS_MPI
1657 
1658  /// Add all data and time history values to the vector.
1659  /// Overloaded to add the position information as well.
1660  void add_values_to_vector(Vector<double>& vector_of_values);
1661 
1662  /// Read all data and time history values from the vector
1663  /// starting from index. On return the index will be
1664  /// set the value at the end of the data that has been read in
1665  /// Overload to also read the position information.
1666  void read_values_from_vector(const Vector<double>& vector_of_values,
1667  unsigned& index);
1668 
1669 #endif
1670  };
1671 
1672  //=====================================================================
1673  /// A Class for nodes that deform elastically (i.e. position is an
1674  /// unknown in the problem). The idea is that the Eulerian positions are
1675  /// stored in a Data object and the Lagrangian coordinates are stored in
1676  /// addition. The pointer that addresses the Eulerian positions is
1677  /// set to the pointer to Value in the Data object. Hence,
1678  /// SolidNode uses knowledge of the internal structure of Data and
1679  /// must be a friend of the Data class.
1680  /// In order to allow a mesh to deform via an elastic-style
1681  /// equation in deforming-domain problems, the positions are stored
1682  /// separately from the values, so that elastic problems may be
1683  /// combined with any other type of problem.
1684  //=====================================================================
1685  class SolidNode : public Node
1686  {
1687  private:
1688  /// Private function to check that the arguments to the position
1689  /// functions are in range
1690  void xi_gen_range_check(const unsigned& k, const unsigned& i) const;
1691 
1692  protected:
1693  /// Number of Lagrangian coordinates of the node
1694  unsigned Nlagrangian;
1695 
1696  /// Number of types of Lagrangian coordinates used to interpolate
1697  /// the Lagrangian coordinates within the element
1699 
1700  /// Pointer to data that will hold variable positions in elastic nodes
1702 
1703  /// Storage for the Lagrangian positions
1704  double* Xi_position;
1705 
1706  public:
1707  /// Default Constructor
1708  SolidNode() : Node() {}
1709 
1710  /// Steady constructor. The node has n_lagrangian Lagrangian
1711  /// coordinates of n_lagrangian_type types (1 for Lagrange elements,
1712  /// 2 for 1D Hermite etc.).
1713  /// The Eulerian dimension of the Node is n_dim and we have n_position_type
1714  /// (generalised) Eulerian coordinates. There are
1715  /// initial_n_value values stored at
1716  /// this node.
1717  SolidNode(const unsigned& n_lagrangian,
1718  const unsigned& n_lagrangian_type,
1719  const unsigned& n_dim,
1720  const unsigned& n_position_type,
1721  const unsigned& initial_n_value);
1722 
1723  /// Unsteady constructor.
1724  /// Allocates storage for initial_n_value nodal values with history values
1725  /// as required by timestepper.
1726  /// The node has n_lagrangian Lagrangian coordinates of
1727  /// n_lagrangian_type types (1 for Lagrange elements, 2 for 1D Hermite
1728  /// etc.)/ The Eulerian dimension of the Node is n_dim and we have
1729  /// n_position_type generalised Eulerian coordinates.
1731  const unsigned& n_lagrangian,
1732  const unsigned& n_lagrangian_type,
1733  const unsigned& n_dim,
1734  const unsigned& Nposition_type,
1735  const unsigned& initial_n_value);
1736 
1737  /// Destructor that cleans up the additional memory allocated in SolidNodes
1738  virtual ~SolidNode();
1739 
1740  /// Broken copy constructor
1741  SolidNode(const SolidNode& solid_node) = delete;
1742 
1743  /// Broken assignment operator
1744  void operator=(const SolidNode&) = delete;
1745 
1746  /// Copy nodal positions and associated data from specified
1747  /// node object
1748  void copy(SolidNode* orig_node_pt);
1749 
1750  /// Dump nodal positions (variable and fixed) and associated
1751  /// data to file for restart
1752  void dump(std::ostream& dump_file) const;
1753 
1754  /// Read nodal positions (variable and fixed) and associated
1755  /// data from file for restart
1756  void read(std::ifstream& restart_file);
1757 
1758  /// Return the variable_position data (const version)
1759  const Data& variable_position() const
1760  {
1761  return *Variable_position_pt;
1762  }
1763 
1764  /// Pointer to variable_position data (const version)
1765  Data* const& variable_position_pt() const
1766  {
1767  return Variable_position_pt;
1768  }
1769 
1770  /// Set the variable position data from an external data object
1771  void set_external_variable_position_pt(Data* const& data_pt);
1772 
1773  /// Set a new position timestepper be resizing the appropriate
1774  /// storage Overloaded from the basic implementation to take into account
1775  /// the fact that position is now Data
1777  const bool& preserve_existing_data);
1778 
1779  /// Overload the check whether the pointer parameter_pt addresses
1780  /// position data values
1781  bool does_pointer_correspond_to_position_data(double* const& parameter_pt);
1782 
1783  /// Return whether any position component has been copied
1784  bool position_is_a_copy() const
1785  {
1786  return Variable_position_pt->is_a_copy();
1787  }
1788 
1789  /// Return whether the position coordinate i has been copied
1790  bool position_is_a_copy(const unsigned& i) const
1791  {
1793  }
1794 
1795  /// Return the equation number for generalised Eulerian coordinate:
1796  /// type of coordinate: k, coordinate direction: i.
1797  const long& position_eqn_number(const unsigned& k, const unsigned& i) const
1798  {
1800  }
1801 
1802  /// Test whether the i-th coordinate is pinned, 0: false; 1: true
1803  bool position_is_pinned(const unsigned& i)
1804  {
1806  }
1807 
1808  /// Test whether the k-th type of the i-th coordinate is pinned
1809  /// 0: false; 1: true
1810  bool position_is_pinned(const unsigned& k, const unsigned& i)
1811  {
1813  }
1814 
1815  /// Pin the nodal position
1816  void pin_position(const unsigned& i)
1817  {
1819  }
1820 
1821  /// Pin the generalised nodal position.
1822  /// `Type': k; Coordinate direction: i.
1823  void pin_position(const unsigned& k, const unsigned& i)
1824  {
1825  return Variable_position_pt->pin(Nposition_type * i + k);
1826  }
1827 
1828  /// Unpin the nodal position
1829  void unpin_position(const unsigned& i)
1830  {
1832  }
1833 
1834  /// Unpin the generalised nodal position.
1835  /// `Type': k; Coordinate direction: i.
1836  void unpin_position(const unsigned& k, const unsigned& i)
1837  {
1838  return Variable_position_pt->unpin(Nposition_type * i + k);
1839  }
1840 
1841  /// Pin all the stored variables (Overloaded)
1842  void pin_all()
1843  {
1844  Node::pin_all();
1846  }
1847 
1848  /// Unpin all the stored variables (Overloaded)
1849  void unpin_all()
1850  {
1851  Node::unpin_all();
1853  }
1854 
1855  /// Overload the constrain positions function to constrain all
1856  /// position values
1857  inline void constrain_positions()
1858  {
1860  }
1861 
1862  /// Overload the unconstrain positions function to unconstrain all
1863  /// position values
1865  {
1867  }
1868 
1869  /// Return number of lagrangian coordinates
1870  unsigned nlagrangian() const
1871  {
1872  return Nlagrangian;
1873  }
1874 
1875  /// Number of types of Lagrangian coordinates used to interpolate
1876  /// the Lagrangian coordinates within the element
1877  unsigned nlagrangian_type() const
1878  {
1879  return Nlagrangian_type;
1880  }
1881 
1882  /// Reference to i-th Lagrangian position
1883  double& xi(const unsigned& i)
1884  {
1885 #ifdef RANGE_CHECKING
1886  xi_gen_range_check(0, i);
1887 #endif
1888  return Xi_position[Nlagrangian_type * i];
1889  }
1890 
1891  /// Reference to i-th Lagrangian position (const version)
1892  const double& xi(const unsigned& i) const
1893  {
1894 #ifdef RANGE_CHECKING
1895  xi_gen_range_check(0, i);
1896 #endif
1897  return Xi_position[Nlagrangian_type * i];
1898  }
1899 
1900  /// Reference to the generalised Lagrangian position.
1901  /// `Type': k; 'Coordinate direction: i.
1902  double& xi_gen(const unsigned& k, const unsigned& i)
1903  {
1904 #ifdef RANGE_CHECKING
1905  xi_gen_range_check(k, i);
1906 #endif
1907  return Xi_position[Nlagrangian_type * i + k];
1908  }
1909 
1910  /// Reference to the generalised Lagrangian position.
1911  /// `Type': k; 'Coordinate direction: i. (const version
1912  const double& xi_gen(const unsigned& k, const unsigned& i) const
1913  {
1914 #ifdef RANGE_CHECKING
1915  xi_gen_range_check(k, i);
1916 #endif
1917  return Xi_position[Nlagrangian_type * i + k];
1918  }
1919 
1920  /// Return lagrangian coordinate either directly or via
1921  /// hanging node representation
1922  double lagrangian_position(const unsigned& i) const;
1923 
1924  /// Return generalised lagrangian coordinate either directly or via
1925  /// hanging node representation
1926  double lagrangian_position_gen(const unsigned& k, const unsigned& i) const;
1927 
1928  /// Overload the assign equation numbers routine
1929  void assign_eqn_numbers(unsigned long& global_number,
1930  Vector<double*>& dof_pt);
1931 
1932  /// Function to describe the dofs of the Node. The ostream
1933  /// specifies the output stream to which the description
1934  /// is written; the string stores the currently
1935  /// assembled output that is ultimately written to the
1936  /// output stream by Data::describe_dofs(...); it is typically
1937  /// built up incrementally as we descend through the
1938  /// call hierarchy of this function when called from
1939  /// Problem::describe_dofs(...)
1940  void describe_dofs(std::ostream& out,
1941  const std::string& current_string) const;
1942 
1943  /// Overload the function add_values_to_map so that it also adds
1944  /// the variable position data
1945  void add_value_pt_to_map(std::map<unsigned, double*>& map_of_value_pt);
1946 
1947 #ifdef OOMPH_HAS_MPI
1948 
1949  /// Add all data, position and time history values to the vector
1950  /// Overload to add the Lagrangian coordinates to the vector
1951  void add_values_to_vector(Vector<double>& vector_of_values);
1952 
1953  /// Read all data and time history values from the vector
1954  /// starting from index. On return the index will be
1955  /// set the value at the end of the data that has been read in
1956  /// Overload to add the position information and Lagrangian coordinates
1957  void read_values_from_vector(const Vector<double>& vector_of_values,
1958  unsigned& index);
1959 
1960 
1961  /// Add all equation numbers to the vector in
1962  /// the internal storage order. Overload to add equation numbers
1963  /// associated with the positional dofs
1964  void add_eqn_numbers_to_vector(Vector<long>& vector_of_eqn_numbers);
1965 
1966  /// Read all equation numbers from the vector
1967  /// starting from index. On return the index will be
1968  /// set to the value at the end of the data that has been read in
1969  /// Overload to include the equation numbrs associated with the
1970  /// positional dofs
1971  void read_eqn_numbers_from_vector(const Vector<long>& vector_of_eqn_numbers,
1972  unsigned& index);
1973 
1974 #endif
1975 
1976 
1977  /// Overload node update function: Since the position
1978  /// of SolidNodes is determined by unknowns, there's nothing
1979  /// to be done apart from performing the auxiliary node
1980  /// update function (if any)
1981  void node_update(const bool& update_all_time_levels_for_new_node = false)
1982  {
1984  }
1985  };
1986 
1987 
1988  //======================================================================
1989  /// A class that contains the information required by Nodes that
1990  /// are located on Mesh boundaries. A BoundaryNode of a particular type
1991  /// is obtained by combining a given Node with this class.
1992  /// By differentiating between Nodes and BoundaryNodes we avoid a lot
1993  /// of un-necessary storage in the bulk Nodes.
1994  //======================================================================
1996  {
1997  private:
1998  /// Pointer to a map of pointers to
1999  /// intrinsic boundary coordinates of the Node,
2000  /// indexed by the boundary number. If the Node does not lie
2001  /// on a boundary this map should never be queried because
2002  /// unnecessary storage will then be allocated. Hence, it
2003  /// can only be accessed via the appropriate set and get functions.
2004  std::map<unsigned, DenseMatrix<double>*>* Boundary_coordinates_pt;
2005 
2006  /// Pointer to set of mesh boundaries occupied by the Node;
2007  /// NULL if the Node is not on any boundaries
2008  std::set<unsigned>* Boundaries_pt;
2009 
2010  protected:
2011  /// Pointer to a map,
2012  /// indexed by the face element identifier it returns
2013  /// the position of the first face element value.
2014  /// If the Node does not lie on a face element
2015  /// this map should never be queried.
2016  std::map<unsigned, unsigned>*
2018 
2019  /// If the BoundaryNode is periodic, this pointer is set to
2020  /// the BoundaryNode whose data it shares
2022 
2023  /// Helper function that is used to turn BoundaryNodes into
2024  /// peridic boundary nodes by setting the data values of
2025  /// copied_node_pt to those of original_node_pt.
2026  void make_node_periodic(Node* const& node_pt,
2027  Node* const& original_node_pt);
2028 
2029  /// Helper function that is used to turn BoundaryNodes into
2030  /// periodic boundary nodes by setting the data values of the nodes
2031  /// in the vector periodic_copies_pt to be the same as those
2032  /// in node_pt.
2033  void make_nodes_periodic(Node* const& node_pt,
2034  Vector<Node*> const& periodic_copies_pt);
2035 
2036  public:
2037  /// Member function that allocates storage for a given
2038  /// number of additional degrees of freedom, n_additional_value,
2039  /// associated with a particular face_id to the Node
2040  /// node_pt
2042  const unsigned& n_additional_value, const unsigned& face_id = 0) = 0;
2043 
2044  /// Return pointer to the map giving
2045  /// the index of the first face element value.
2046  std::map<unsigned, unsigned>*& index_of_first_value_assigned_by_face_element_pt()
2047  {
2049  }
2050 
2051  /// Return the index of the first value associated with
2052  /// the i-th face element value. If no argument is specified
2053  /// we return the index associated with the first (and assumed to be only)
2054  /// face element attached to this node. Throws error only in paranoid mode
2055  /// if no values have been set by any FaceElements. If you want to
2056  /// catch such cases gracefully in all circumstances (there are examples
2057  /// with complex unstructured 3D meshes where it's not clear a priori
2058  /// if a node has been resized by FaceElements) use alternative
2059  /// version (with leading bool arguments) that always checks and throws
2060  /// so exceptions can be caught gracefully. Returns UINT_MAX if error.
2062  const unsigned& face_id = 0) const
2063  {
2064 #ifdef PARANOID
2066  {
2067  std::ostringstream error_message;
2068  error_message
2069  << "Index_of_first_value_assigned_by_face_element_pt==0;\n"
2070  << "Pointer must be set via call to: \n\n"
2071  << " BoundaryNode::assign_additional_values_with_face_id(...), \n\n"
2072  << "typically from FaceElement::add_additional_values(...).";
2073  throw OomphLibError(error_message.str(),
2074  OOMPH_CURRENT_FUNCTION,
2075  OOMPH_EXCEPTION_LOCATION);
2076  return UINT_MAX;
2077  }
2078 #endif
2080  }
2081 
2082 
2083  /// Return the index of the first value associated with
2084  /// the i-th face element value. If no argument id is specified
2085  /// we return the index associated with the first (and assumed to be only)
2086  /// face element attached to this node.
2087  /// If no values have been set by any FaceElements and
2088  /// throw_if_no_value_assigned_by_face_element is set to true, this
2089  /// is caught gracefully in all circumstances (there are examples
2090  /// with complex unstructured 3D meshes where it's not clear a priori
2091  /// if a node has been resized by FaceElements) by throwing an OomphLibError
2092  /// that can be caught gracefully. If throw_quietly is set to true
2093  /// we throw an OomphLibQuietException instead. You can catch either
2094  /// by catching the underlying std::runtime_error. In PARANOID mode
2095  /// we check regardless of the setting of
2096  /// throw_if_no_value_assigned_by_face_element (but respect the
2097  /// request for quietness). Returns UINT_MAX if error.
2099  const bool& throw_if_no_value_assigned_by_face_element,
2100  const bool& throw_quietly,
2101  const unsigned& face_id = 0) const
2102  {
2103  // Over-rule if paranoia rules
2104  bool local_throw_if_no_value_assigned_by_face_element =
2105  throw_if_no_value_assigned_by_face_element;
2106 #ifdef PARANOID
2107  local_throw_if_no_value_assigned_by_face_element = true;
2108 #endif
2109 
2110  if (local_throw_if_no_value_assigned_by_face_element)
2111  {
2113  {
2114  std::ostringstream error_message;
2115  error_message
2116  << "Index_of_first_value_assigned_by_face_element_pt==0;\n"
2117  << "Pointer must be set via call to: \n\n"
2118  << " BoundaryNode::assign_additional_values_with_face_id(...), "
2119  "\n\n"
2120  << "typically from FaceElement::add_additional_values(...).";
2121 
2122  if (throw_quietly)
2123  {
2124  throw OomphLibQuietException();
2125  }
2126  else
2127  {
2128  throw OomphLibError(error_message.str(),
2129  OOMPH_CURRENT_FUNCTION,
2130  OOMPH_EXCEPTION_LOCATION);
2131  }
2132  return UINT_MAX;
2133  }
2134  }
2136  }
2137 
2138  /// Return the number of values associated with
2139  /// the i-th face element field. If no argument is specified
2140  /// we return the value associated with the first (and assumed to be only)
2141  /// face element attached to this node. Throws error only in paranoid mode
2142  /// if no values have been set by any FaceElements. If you want to
2143  /// catch such cases gracefully in all circumstances (there are examples
2144  /// with complex unstructured 3D meshes where it's not clear a priori
2145  /// if a node has been resized by FaceElements) use alternative
2146  /// version (with leading bool arguments) that always checks and throws
2147  /// so exceptions can be caught gracefully. Returns UINT_MAX if error.
2149  const unsigned& face_id = 0) const = 0;
2150 
2151  /// Default constructor, set the pointers to the storage to NULL
2154  Boundaries_pt(0),
2156  Copied_node_pt(0)
2157  {
2158  }
2159 
2160  /// Destructor, clean up any allocated storage for the boundaries
2161  virtual ~BoundaryNodeBase();
2162 
2163  /// Broken copy constructor
2164  BoundaryNodeBase(const BoundaryNodeBase& boundary_node_base) = delete;
2165 
2166  /// Broken assignment operator
2167  void operator=(const BoundaryNodeBase&) = delete;
2168 
2169  /// Have boundary coordinates been set up?
2171  {
2172  return (Boundary_coordinates_pt != 0);
2173  }
2174 
2175  /// Access to pointer to set of mesh boundaries that this
2176  /// node occupies; NULL if the node is not on any boundary
2177  void get_boundaries_pt(std::set<unsigned>*& boundaries_pt)
2178  {
2179  boundaries_pt = Boundaries_pt;
2180  }
2181 
2182  /// Add the node to the mesh boundary b
2183  void add_to_boundary(const unsigned& b);
2184 
2185  /// Remove the node from the mesh boundary b
2186  void remove_from_boundary(const unsigned& b);
2187 
2188  /// Test whether the node lies on a boundary
2189  bool is_on_boundary() const
2190  {
2191  return !(Boundaries_pt == 0);
2192  }
2193 
2194  /// Test whether the node lies on mesh boundary b
2195  bool is_on_boundary(const unsigned& b) const;
2196 
2197  /// Get the number of boundary coordinates on mesh boundary b
2198  unsigned ncoordinates_on_boundary(const unsigned& b);
2199 
2200  /// Return the vector of boundary coordinates on mesh boundary b
2201  void get_coordinates_on_boundary(const unsigned& b,
2202  Vector<double>& boundary_zeta)
2203  {
2204  // Just return the zero-th one
2205  get_coordinates_on_boundary(b, 0, boundary_zeta);
2206  }
2207 
2208 
2209  /// Set the vector of boundary coordinates on mesh boundary b
2210  void set_coordinates_on_boundary(const unsigned& b,
2211  const Vector<double>& boundary_zeta)
2212  {
2213  // Just do the zero-th one
2214  set_coordinates_on_boundary(b, 0, boundary_zeta);
2215  }
2216 
2217  /// Return the vector of the k-th generalised boundary coordinates
2218  /// on mesh boundary b.
2219  void get_coordinates_on_boundary(const unsigned& b,
2220  const unsigned& k,
2221  Vector<double>& boundary_zeta);
2222 
2223  /// Set the vector of the k-th generalised boundary coordinates on
2224  /// mesh boundary b.
2225  void set_coordinates_on_boundary(const unsigned& b,
2226  const unsigned& k,
2227  const Vector<double>& boundary_zeta);
2228  };
2229 
2230 
2231  //====================================================================
2232  /// A template Class for BoundaryNodes; that is Nodes that MAY live
2233  /// on the boundary of a Mesh. The class is formed by a simple
2234  /// composition of the template parameter NODE_TYPE, which must be
2235  /// a Node class and the BoundaryNodeBase class.
2236  /// Final overloading of functions is always in favour of the
2237  /// BoundaryNodeBase implementation; i.e. these nodes can live on
2238  /// boundaries.
2239  //===================================================================
2240  template<class NODE_TYPE>
2241  class BoundaryNode : public NODE_TYPE, public BoundaryNodeBase
2242  {
2243  private:
2244  /// Set pointers to the copied data used when we have periodic nodes
2246  {
2247 #ifdef PARANOID
2248  if (Copied_node_pt == 0)
2249  {
2250  throw OomphLibError("BoundaryNode has not been copied",
2251  OOMPH_CURRENT_FUNCTION,
2252  OOMPH_EXCEPTION_LOCATION);
2253  }
2254 #endif
2255 
2256  // Set the number of values
2257  this->Nvalue = Copied_node_pt->nvalue();
2258  this->Value = Copied_node_pt->Value;
2259  this->Eqn_number = Copied_node_pt->Eqn_number;
2260  // We won't ever need to worry about updating position pointers
2261  // because periodic solid problems are handled using lagrange multipliers.
2262 
2263  // Cast Copied_node_pt to BoundaryNode to copy over the
2264  // Face index pointer
2265  BoundaryNode<NODE_TYPE>* cast_copied_node_pt =
2266  dynamic_cast<BoundaryNode<NODE_TYPE>*>(Copied_node_pt);
2267 
2268  // Check that dynamic cast has worked
2269  if (cast_copied_node_pt)
2270  {
2272  cast_copied_node_pt
2274  }
2275  else
2276  {
2277  std::ostringstream error_stream;
2278  error_stream << "Copied_node_pt is not of type BoundaryNode*"
2279  << std::endl;
2280  throw OomphLibError(
2281  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2282  }
2283  }
2284 
2285  /// Copy over additional information so that if the node
2286  /// is periodic it can remain active if the node that holds the periodic
2287  /// data is deleted
2289  {
2290  // Only worry about the face index if it has been assigned
2291  // which it will have been
2293  {
2294  // Allocate new storage for the index of first value assigned by face
2295  // element The other storage will be deleted
2297  new std::map<unsigned, unsigned>;
2298 
2299  // Cast copied_node_pt to BoundaryNode so that we can reset the index
2300  BoundaryNode<NODE_TYPE>* cast_copied_node_pt =
2301  dynamic_cast<BoundaryNode<NODE_TYPE>*>(Copied_node_pt);
2302 
2303  // Check that dynamic cast has worked
2304  if (cast_copied_node_pt)
2305  {
2306  // Initialise the values in the map to be those of the original data
2307  // std::map<unsigned,unsigned>::const_iterator it =
2308  // (*(cast_copied_node_pt->
2309  // index_of_first_value_assigned_by_face_element_pt())).begin();
2310  std::map<unsigned, unsigned>::const_iterator end =
2311  (*(cast_copied_node_pt
2313  .end();
2314  for (std::map<unsigned, unsigned>::const_iterator it =
2315  (*(cast_copied_node_pt
2317  .begin();
2318  it != end;
2319  it++)
2320  {
2322  [it->first] = it->second;
2323  }
2324  }
2325  }
2326  }
2327 
2328  public:
2329  /// Clear pointers to the copied data used when we have periodic
2330  /// nodes. The shallow (pointer) copy is turned into a deep copy by
2331  /// allocating new data and copying the actual values across.
2333  {
2334 #ifdef PARANOID
2335  if (Copied_node_pt == 0)
2336  {
2337  throw OomphLibError("BoundaryNode has not been copied",
2338  OOMPH_CURRENT_FUNCTION,
2339  OOMPH_EXCEPTION_LOCATION);
2340  }
2341 #endif
2342 
2343  // Simply zeroing these will cause problems during unrefinement because
2344  // the original could be deleted, but the "copy" remain. Instead we
2345  // allocate new storage and copy values over from the original.
2346 
2347  // Get the number of values and time storage
2348  //(must be the same as the original)
2349  const unsigned n_value = this->nvalue();
2350  const unsigned n_tstorage = this->ntstorage();
2351 
2352  // Allocate storage for equation numbers
2353  this->Eqn_number = new long[n_value];
2354 
2355  // Allocate storage for the values
2356  this->Value = new double*[n_value];
2357 
2358  // Allocate all data values in one big array
2359  double* values = new double[n_value * n_tstorage];
2360 
2361  // Set the pointers to the data values and equation numbers
2362  for (unsigned i = 0; i < n_value; ++i)
2363  {
2364  // Set the pointers
2365  this->Value[i] = &values[i * n_tstorage];
2366  // Initialise all the values to be those of the original data
2367  for (unsigned t = 0; t < n_tstorage; ++t)
2368  {
2369  this->Value[i][t] = Copied_node_pt->value(t, i);
2370  }
2371 
2372  // Copy over the values of the equation numbers
2373  this->Eqn_number[i] = Copied_node_pt->eqn_number(i);
2374  }
2375 
2376  // The node is no longer a copy
2377  Copied_node_pt = 0;
2378  }
2379 
2380 
2381  /// Default Constructor
2382  BoundaryNode() : NODE_TYPE(), BoundaryNodeBase() {}
2383 
2384  /// Steady constructor, for a BoundaryNode of spatial dimension
2385  /// n_dim. Simply passes all arguments through to the underlying Node
2386  /// constructor which allocates storage for initial_n_value values.
2387  /// NPosition_type is the number of coordinate types
2388  /// needed in the mapping between local and global coordinates
2389  /// (e.g. 1 for Lagrange-type elements; 2 for 1D Hermite elements; 4 for
2390  /// 2D Hermite elements, etc).
2391  BoundaryNode(const unsigned& n_dim,
2392  const unsigned& n_position_type,
2393  const unsigned& initial_n_value)
2394  : NODE_TYPE(n_dim, n_position_type, initial_n_value), BoundaryNodeBase()
2395  {
2396  }
2397 
2398  /// Unsteady constructor for a BoundaryNode
2399  /// of spatial dimension n_dim. Simply passes all arguments through to
2400  /// the underlygin Node constructor which
2401  /// allocates storage for initial_n_value values with
2402  /// history values as required by the timestepper.
2403  /// n_position_type: # of coordinate
2404  /// types needed in the mapping between local and global coordinates
2405  /// (e.g. 1 for Lagrange-type elements; 2 for 1D Hermite elements; 4 for
2406  /// 2D Hermite elements).
2407  BoundaryNode(TimeStepper* const& time_stepper_pt,
2408  const unsigned& n_dim,
2409  const unsigned& n_position_type,
2410  const unsigned& initial_n_value)
2411  : NODE_TYPE(time_stepper_pt, n_dim, n_position_type, initial_n_value),
2413  {
2414  }
2415 
2416  /// Steady constructor for Solid-type boundary nodes.
2417  /// The node has n_lagrangian Lagrangian
2418  /// coordinates of n_lagrangian_type types (1 for Lagrange elements,
2419  /// 2 for 1D Hermite etc.).
2420  /// The Eulerian dimension of the Node is n_dim and we have n_position_type
2421  /// (generalised) Eulerian coordinates. There are
2422  /// initial_n_value values stored at
2423  /// this node.
2424  BoundaryNode(const unsigned& n_lagrangian,
2425  const unsigned& n_lagrangian_type,
2426  const unsigned& n_dim,
2427  const unsigned& n_position_type,
2428  const unsigned& initial_n_value)
2429  : NODE_TYPE(n_lagrangian,
2430  n_lagrangian_type,
2431  n_dim,
2432  n_position_type,
2433  initial_n_value),
2435  {
2436  }
2437 
2438  /// Unsteady constructor for Solid-type boundary nodes
2439  /// Allocates storage for initial_n_value nodal values with history values
2440  /// as required by timestepper.
2441  /// The node has n_lagrangian Lagrangian coordinates of
2442  /// n_lagrangian_type types (1 for Lagrange elements, 2 for 1D Hermite
2443  /// etc.)/ The Eulerian dimension of the Node is n_dim and we have
2444  /// n_position_type generalised Eulerian coordinates.
2445  BoundaryNode(TimeStepper* const& time_stepper_pt,
2446  const unsigned& n_lagrangian,
2447  const unsigned& n_lagrangian_type,
2448  const unsigned& n_dim,
2449  const unsigned& n_position_type,
2450  const unsigned& initial_n_value)
2451  : NODE_TYPE(time_stepper_pt,
2452  n_lagrangian,
2453  n_lagrangian_type,
2454  n_dim,
2455  n_position_type,
2456  initial_n_value),
2458  {
2459  }
2460 
2461  /// Destructor resets pointers if
2463  {
2464  // If there are any copies of this Node
2465  // then we need to clear their pointers to information stored in
2466  // this BoundaryNode
2467  // at this level because once we are down to the Node's destructor
2468  // the information no longer exists.
2469  for (unsigned i = 0; i < this->Ncopies; i++)
2470  {
2471  // Is the copied node a boundary node (it should be)
2472  BoundaryNode<NODE_TYPE>* cast_node_pt =
2473  dynamic_cast<BoundaryNode<NODE_TYPE>*>(this->Copy_of_data_pt[i]);
2474  // We can only do this if the node is a boundary node
2475  if (cast_node_pt != 0)
2476  {
2477  // This is required to clear out any pointers to the additional
2478  // data assigned by face elements
2479  cast_node_pt->clear_additional_copied_pointers();
2480  }
2481  // Otherwise there is a problem if it's not Hijacked Data
2482 #ifdef PARANOID
2483  else
2484  {
2485  if (dynamic_cast<HijackedData*>(this->Copy_of_data_pt[i]) == 0)
2486  {
2487  OomphLibError(
2488  "Copy of a BoundaryNode is not a BoundaryNode or HijackedData",
2489  "BoundaryNode::~BoundaryNode",
2490  OOMPH_EXCEPTION_LOCATION);
2491  }
2492  }
2493 #endif
2494  }
2495 
2496  // If the node was periodic then clear the pointers before deleting
2497  if (Copied_node_pt)
2498  {
2499  // Inform the node that the copy is being deleted
2500  // If the original has been deleted Copied_node_pt will be NULL
2501  Copied_node_pt->remove_copy(this);
2502  Copied_node_pt = 0;
2503  this->Value = 0;
2504  this->Eqn_number = 0;
2505  // Remove the information about the boundary node storage scheme
2507  }
2508  }
2509 
2510  /// Broken copy constructor
2511  BoundaryNode(const BoundaryNode<NODE_TYPE>& node) = delete;
2512 
2513  /// Broken assignment operator
2514  void operator=(const BoundaryNode<NODE_TYPE>&) = delete;
2515 
2516  /// Have boundary coordinates been set up?
2518  {
2520  }
2521 
2522  /// Access to pointer to set of mesh boundaries that this
2523  /// node occupies; NULL if the node is not on any boundary
2524  /// Final overload
2525  void get_boundaries_pt(std::set<unsigned>*& boundaries_pt)
2526  {
2527  BoundaryNodeBase::get_boundaries_pt(boundaries_pt);
2528  }
2529 
2530  /// Test whether the node lies on a boundary
2531  /// Final overload
2532  bool is_on_boundary() const
2533  {
2535  }
2536 
2537  /// Test whether the node lies on mesh boundary b
2538  /// Final overload
2539  bool is_on_boundary(const unsigned& b) const
2540  {
2542  }
2543 
2544  /// Add the node to mesh boundary b, final overload
2545  void add_to_boundary(const unsigned& b)
2546  {
2548  }
2549 
2550  /// Remover the node from mesh boundary b, final overload
2551  void remove_from_boundary(const unsigned& b)
2552  {
2554  }
2555 
2556 
2557  /// Get the number of boundary coordinates on mesh boundary b.
2558  unsigned ncoordinates_on_boundary(const unsigned& b)
2559  {
2561  }
2562 
2563 
2564  /// Return the vector of coordinates on mesh boundary b
2565  /// Final overload
2566  void get_coordinates_on_boundary(const unsigned& b,
2567  Vector<double>& boundary_zeta)
2568  {
2570  }
2571 
2572  /// Set the vector of coordinates on mesh boundary b
2573  /// Final overload
2574  void set_coordinates_on_boundary(const unsigned& b,
2575  const Vector<double>& boundary_zeta)
2576  {
2578  }
2579 
2580 
2581  /// Return the vector of k-th generalised boundary coordinates
2582  /// on mesh boundary b Final overload
2583  void get_coordinates_on_boundary(const unsigned& b,
2584  const unsigned& k,
2585  Vector<double>& boundary_zeta)
2586  {
2587  BoundaryNodeBase::get_coordinates_on_boundary(b, k, boundary_zeta);
2588  }
2589 
2590  /// Set the vector of k-th generalised boundary coordinates
2591  /// on mesh boundary b. Final overload
2592  void set_coordinates_on_boundary(const unsigned& b,
2593  const unsigned& k,
2594  const Vector<double>& boundary_zeta)
2595  {
2596  BoundaryNodeBase::set_coordinates_on_boundary(b, k, boundary_zeta);
2597  }
2598 
2599 
2600  /// Return the number of values associated with
2601  /// the i-th face element field. If no argument is specified
2602  /// we return the value associated with the first (and assumed to be only)
2603  /// face element attached to this node. Throws error only in paranoid mode
2604  /// if no values have been set by any FaceElements. If you want to
2605  /// catch such cases gracefully in all circumstances (there are examples
2606  /// with complex unstructured 3D meshes where it's not clear a priori
2607  /// if a node has been resized by FaceElements) use alternative
2608  /// version (with leading bool arguments) that always checks and throws
2609  /// so exceptions can be caught gracefully. Returns UINT_MAX if error.
2610  unsigned nvalue_assigned_by_face_element(const unsigned& face_id = 0) const
2611  {
2612 #ifdef PARANOID
2614  {
2615  std::ostringstream error_message;
2616  error_message
2617  << "Index_of_first_value_assigned_by_face_element_pt==0;\n"
2618  << "Pointer must be set via call to: \n\n"
2619  << " BoundaryNode::assign_additional_values_with_face_id(), \n\n"
2620  << "typically from FaceElement::add_additional_values(...).";
2621  throw OomphLibError(error_message.str(),
2622  OOMPH_CURRENT_FUNCTION,
2623  OOMPH_EXCEPTION_LOCATION);
2624  return UINT_MAX;
2625  }
2626 #endif
2627 
2628  // How many values are there in total?
2629  unsigned nval = this->nvalue();
2630 
2631  // If ID is not present in the map then return 0
2634  {
2635  return 0;
2636  }
2637 
2638  // Otherwise the entry is present in the map
2639 
2640  // Single entry: Number of values is the difference between
2641  // number of values and first index
2642  else if ((*Index_of_first_value_assigned_by_face_element_pt).size() == 1)
2643  {
2644  return nval -
2645  (*Index_of_first_value_assigned_by_face_element_pt)[face_id];
2646  }
2647  else
2648  {
2649  // Find the next first index: Default: nvalue()
2650  unsigned next_first_index = nval;
2651  unsigned my_first_index =
2652  (*Index_of_first_value_assigned_by_face_element_pt)[face_id];
2653  for (std::map<unsigned, unsigned>::iterator it =
2654  (*Index_of_first_value_assigned_by_face_element_pt).begin();
2655  it != (*Index_of_first_value_assigned_by_face_element_pt).end();
2656  it++)
2657  {
2658  unsigned first_index = (*it).second;
2659  if ((first_index > my_first_index) &&
2660  (first_index < next_first_index))
2661  {
2662  next_first_index = first_index;
2663  }
2664  }
2665  return next_first_index - my_first_index;
2666  }
2667  }
2668 
2669 
2670  //=====================================================================
2671  /// Member function to allocates storage for a given
2672  /// number of additional degrees of freedom, n_additional_value,
2673  /// associated with a particular face_id to the Node node_pt. Needs
2674  /// to be filled in here so that access to the nodal values is
2675  /// available.
2676  //=====================================================================
2678  const unsigned& n_additional_value, const unsigned& face_id = 0)
2679  {
2680 #ifdef PARANOID
2681  // If nothing is being added warn the user
2682  if (n_additional_value == 0)
2683  {
2684  std::ostringstream warn_message;
2685  warn_message
2686  << "No additional data values are being added to the boundary node "
2687  << this << "\n"
2688  << "by face id " << face_id << ".\n"
2689  << "This means that the function \n"
2690  << "BoundaryNode::index_of_first_value_assigned_by_face_element(id) "
2691  "\n"
2692  << "will return a value that is equal to the number of values stored "
2693  "at the Node.\n"
2694  << "Calling Node::value(...) with this index will lead to an "
2695  "out-of-range error.\n"
2696  << "The anticpated usage of a loop from the index over the number of "
2697  "values.\n"
2698  << "will not cause any problems, but if you try to do anything else, "
2699  "you may be surprised.\n"
2700  << "You have been warned!\n";
2702  warn_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2703  }
2704 #endif
2705 
2706  // Allocate storage if not already assigned
2708  {
2710  new std::map<unsigned, unsigned>;
2711  }
2712 
2713  // Find the number of values already stored in the node
2714  const unsigned n_value = this->nvalue();
2715 
2716  // If this ID hasn't already been used
2718  face_id) ==
2719  this->Index_of_first_value_assigned_by_face_element_pt->end())
2720  {
2721  // Set the first index to by number of values
2722  (*Index_of_first_value_assigned_by_face_element_pt)[face_id] = n_value;
2723  }
2724  // Otherwise this ID has been used previously
2725  else
2726  {
2727  // Find the number of values associated with this id
2728  const unsigned n_value_for_id =
2729  this->nvalue_assigned_by_face_element(face_id);
2730 
2731  // If the number of current values is equal to the desired values
2732  // do nothing and return
2733  if (n_value_for_id == n_additional_value)
2734  {
2735  return;
2736  }
2737  // Otherwise
2738  else
2739  {
2740  // Safety check, are the value associated with this id
2741  // all at the end
2743  [face_id] +
2744  n_value_for_id) != n_value)
2745  {
2746 #ifdef PARANOID
2747  std::ostringstream warn_message;
2748  warn_message << "Trying to (resize) number of unknowns associated "
2749  "with face id "
2750  << face_id << "\n"
2751  << "but previous storage for this data is not at the "
2752  "end of the nodal values.\n"
2753  << "The anticipated usage here is within constructors "
2754  "that add additional equations\n"
2755  << "to existing FaceElements in which case we will "
2756  "always be at the end.\n"
2757  << "If you are trying to do something else, then try "
2758  "using a different id.\n"
2759  << " FaceElement::add_additional_values(...)."
2760  << " For consistency with earlier versions, this will "
2761  "do nothing!\n";
2762  OomphLibWarning(warn_message.str(),
2763  OOMPH_CURRENT_FUNCTION,
2764  OOMPH_EXCEPTION_LOCATION);
2765 #endif
2766  // Just return without doing anything
2767  return;
2768  }
2769  } // Case when we are actually requesting additional values
2770  } // End case when ID has already been touched
2771 
2772  // Now finally resize the storage
2773  this->resize(n_value + n_additional_value);
2774  }
2775 
2776 
2777  /// Make the node periodic
2778  void make_periodic(Node* const& node_pt)
2779  {
2780  BoundaryNodeBase::make_node_periodic(this, node_pt);
2781  }
2782 
2783  /// Make the nodes passed in periodic_nodes periodic from
2784  /// this node
2785  void make_periodic_nodes(const Vector<Node*>& periodic_nodes_pt)
2786  {
2787  BoundaryNodeBase::make_nodes_periodic(this, periodic_nodes_pt);
2788  }
2789 
2790  /// Return a boolean to indicate whether the data contains
2791  /// any copied values. If the node is periodic all values are copied
2792  bool is_a_copy() const
2793  {
2794  if (Copied_node_pt)
2795  {
2796  return true;
2797  }
2798  else
2799  {
2800  return false;
2801  }
2802  }
2803 
2804  /// Return a boolean to indicate whether
2805  /// the i-th value is a copied value.
2806  /// If the node is periodic all values are copies
2807  bool is_a_copy(const unsigned& i) const
2808  {
2809  if (Copied_node_pt)
2810  {
2811  return true;
2812  }
2813  else
2814  {
2815  return false;
2816  }
2817  }
2818 
2819 
2820  /// Return pointer to copied node (null if the
2821  /// current node is not a copy)
2823  {
2824  return Copied_node_pt;
2825  }
2826 
2827  /// Overload the equation assignment operation
2828  void assign_eqn_numbers(unsigned long& global_ndof, Vector<double*>& dof_pt)
2829  {
2830  // If the boundary node is not periodic call the ususal
2831  // assign equation numbers
2832  if (Copied_node_pt == 0)
2833  {
2834  NODE_TYPE::assign_eqn_numbers(global_ndof, dof_pt);
2835  }
2836  // Otherwise make sure that we assign equation numbers for
2837  // the variable position pointer of the solid node
2838  else
2839  {
2840  // Is it a solid node?
2841  SolidNode* solid_node_pt = dynamic_cast<SolidNode*>(this);
2842  if (solid_node_pt)
2843  {
2844  // If so we must let the variable position pointer take care of
2845  // itself
2846  solid_node_pt->variable_position_pt()->assign_eqn_numbers(global_ndof,
2847  dof_pt);
2848  }
2849  }
2850  }
2851 
2852 
2853  /// Resize the number of equations
2854  void resize(const unsigned& n_value)
2855  {
2856  // If the node is periodic, warn, but do nothing
2857  if (Copied_node_pt)
2858  {
2859 #ifdef PARANOID
2860  unsigned n_value_new = Copied_node_pt->nvalue();
2861  // Check that we have already resized the original
2862  if (n_value_new != n_value)
2863  {
2864  std::ostringstream error_stream;
2865  error_stream
2866  << "Call to resize copied node before original has been resized!"
2867  << std::endl;
2868  throw OomphLibError(error_stream.str(),
2869  OOMPH_CURRENT_FUNCTION,
2870  OOMPH_EXCEPTION_LOCATION);
2871  }
2872 #endif
2873  }
2874  // Otherwise call the underlying function
2875  else
2876  {
2877  NODE_TYPE::resize(n_value);
2878  }
2879  }
2880  };
2881 
2882 
2883  /// Make the node periodic
2884  template<>
2885  inline void BoundaryNode<SolidNode>::make_periodic(Node* const& node_pt)
2886  {
2887 #ifdef PARANOID
2888  std::ostringstream warn_message;
2889  warn_message << "You are trying to make a Solid Node Periodic.\n"
2890  << "This action will reset pointers to stored values and "
2891  << "equation numbers,\n"
2892  << "meaning that all values will be shared by this Node and "
2893  << "its master.\n"
2894  << "Unfortunately, this does not ensure that the variable "
2895  << "nodal coordinates coincide.\n"
2896  << "For matching nodal coordinates the options are:\n"
2897  << "(i) Introduce Lagrange multipliers,\n"
2898  << "(ii) Pin one side and treat the data as dependent,\n"
2899  << "(iii) Hijack the nodal coordinates on one side "
2900  << "and specify an alternative equation.\n\n"
2901  << "If you plan to use refineability, then the easiest\n"
2902  << "option is to use Lagrange multipliers.\n"
2903  << std::endl;
2905  warn_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2906 #endif
2907 
2908  BoundaryNodeBase::make_node_periodic(this, node_pt);
2909  }
2910 
2911 
2912 } // namespace oomph
2913 
2914 #endif
cstr elem_len * i
Definition: cfortran.h:603
char t
Definition: cfortran.h:568
A class that contains the information required by Nodes that are located on Mesh boundaries....
Definition: nodes.h:1996
BoundaryNodeBase()
Default constructor, set the pointers to the storage to NULL.
Definition: nodes.h:2152
unsigned ncoordinates_on_boundary(const unsigned &b)
Get the number of boundary coordinates on mesh boundary b.
Definition: nodes.cc:3119
std::set< unsigned > * Boundaries_pt
Pointer to set of mesh boundaries occupied by the Node; NULL if the Node is not on any boundaries.
Definition: nodes.h:2008
unsigned index_of_first_value_assigned_by_face_element(const bool &throw_if_no_value_assigned_by_face_element, const bool &throw_quietly, const unsigned &face_id=0) const
Return the index of the first value associated with the i-th face element value. If no argument id is...
Definition: nodes.h:2098
void get_boundaries_pt(std::set< unsigned > *&boundaries_pt)
Access to pointer to set of mesh boundaries that this node occupies; NULL if the node is not on any b...
Definition: nodes.h:2177
virtual void assign_additional_values_with_face_id(const unsigned &n_additional_value, const unsigned &face_id=0)=0
Member function that allocates storage for a given number of additional degrees of freedom,...
void set_coordinates_on_boundary(const unsigned &b, const Vector< double > &boundary_zeta)
Set the vector of boundary coordinates on mesh boundary b.
Definition: nodes.h:2210
void make_node_periodic(Node *const &node_pt, Node *const &original_node_pt)
Helper function that is used to turn BoundaryNodes into peridic boundary nodes by setting the data va...
Definition: nodes.cc:2951
BoundaryNodeBase(const BoundaryNodeBase &boundary_node_base)=delete
Broken copy constructor.
void make_nodes_periodic(Node *const &node_pt, Vector< Node * > const &periodic_copies_pt)
Helper function that is used to turn BoundaryNodes into periodic boundary nodes by setting the data v...
Definition: nodes.cc:2896
void add_to_boundary(const unsigned &b)
Add the node to the mesh boundary b.
Definition: nodes.cc:3028
Node * Copied_node_pt
If the BoundaryNode is periodic, this pointer is set to the BoundaryNode whose data it shares.
Definition: nodes.h:2021
void get_coordinates_on_boundary(const unsigned &b, Vector< double > &boundary_zeta)
Return the vector of boundary coordinates on mesh boundary b.
Definition: nodes.h:2201
bool boundary_coordinates_have_been_set_up()
Have boundary coordinates been set up?
Definition: nodes.h:2170
unsigned index_of_first_value_assigned_by_face_element(const unsigned &face_id=0) const
Return the index of the first value associated with the i-th face element value. If no argument is sp...
Definition: nodes.h:2061
std::map< unsigned, DenseMatrix< double > * > * Boundary_coordinates_pt
Pointer to a map of pointers to intrinsic boundary coordinates of the Node, indexed by the boundary n...
Definition: nodes.h:2004
void operator=(const BoundaryNodeBase &)=delete
Broken assignment operator.
std::map< unsigned, unsigned > * Index_of_first_value_assigned_by_face_element_pt
Pointer to a map, indexed by the face element identifier it returns the position of the first face el...
Definition: nodes.h:2017
bool is_on_boundary() const
Test whether the node lies on a boundary.
Definition: nodes.h:2189
void remove_from_boundary(const unsigned &b)
Remove the node from the mesh boundary b.
Definition: nodes.cc:3062
virtual ~BoundaryNodeBase()
Destructor, clean up any allocated storage for the boundaries.
Definition: nodes.cc:2993
std::map< unsigned, unsigned > *& index_of_first_value_assigned_by_face_element_pt()
Return pointer to the map giving the index of the first face element value.
Definition: nodes.h:2046
virtual unsigned nvalue_assigned_by_face_element(const unsigned &face_id=0) const =0
Return the number of values associated with the i-th face element field. If no argument is specified ...
A template Class for BoundaryNodes; that is Nodes that MAY live on the boundary of a Mesh....
Definition: nodes.h:2242
void assign_additional_values_with_face_id(const unsigned &n_additional_value, const unsigned &face_id=0)
Member function to allocates storage for a given number of additional degrees of freedom,...
Definition: nodes.h:2677
BoundaryNode(TimeStepper *const &time_stepper_pt, const unsigned &n_dim, const unsigned &n_position_type, const unsigned &initial_n_value)
Unsteady constructor for a BoundaryNode of spatial dimension n_dim. Simply passes all arguments throu...
Definition: nodes.h:2407
unsigned ncoordinates_on_boundary(const unsigned &b)
Get the number of boundary coordinates on mesh boundary b.
Definition: nodes.h:2558
~BoundaryNode()
Destructor resets pointers if.
Definition: nodes.h:2462
void operator=(const BoundaryNode< NODE_TYPE > &)=delete
Broken assignment operator.
void set_coordinates_on_boundary(const unsigned &b, const Vector< double > &boundary_zeta)
Set the vector of coordinates on mesh boundary b Final overload.
Definition: nodes.h:2574
BoundaryNode(const BoundaryNode< NODE_TYPE > &node)=delete
Broken copy constructor.
bool is_a_copy() const
Return a boolean to indicate whether the data contains any copied values. If the node is periodic all...
Definition: nodes.h:2792
Node * copied_node_pt() const
Return pointer to copied node (null if the current node is not a copy)
Definition: nodes.h:2822
BoundaryNode(const unsigned &n_dim, const unsigned &n_position_type, const unsigned &initial_n_value)
Steady constructor, for a BoundaryNode of spatial dimension n_dim. Simply passes all arguments throug...
Definition: nodes.h:2391
void make_periodic_nodes(const Vector< Node * > &periodic_nodes_pt)
Make the nodes passed in periodic_nodes periodic from this node.
Definition: nodes.h:2785
BoundaryNode(const unsigned &n_lagrangian, const unsigned &n_lagrangian_type, const unsigned &n_dim, const unsigned &n_position_type, const unsigned &initial_n_value)
Steady constructor for Solid-type boundary nodes. The node has n_lagrangian Lagrangian coordinates of...
Definition: nodes.h:2424
bool is_on_boundary() const
Test whether the node lies on a boundary Final overload.
Definition: nodes.h:2532
bool is_a_copy(const unsigned &i) const
Return a boolean to indicate whether the i-th value is a copied value. If the node is periodic all va...
Definition: nodes.h:2807
void clear_copied_pointers()
Clear pointers to the copied data used when we have periodic nodes. The shallow (pointer) copy is tur...
Definition: nodes.h:2332
void assign_eqn_numbers(unsigned long &global_ndof, Vector< double * > &dof_pt)
Overload the equation assignment operation.
Definition: nodes.h:2828
void resize(const unsigned &n_value)
Resize the number of equations.
Definition: nodes.h:2854
void remove_from_boundary(const unsigned &b)
Remover the node from mesh boundary b, final overload.
Definition: nodes.h:2551
BoundaryNode(TimeStepper *const &time_stepper_pt, const unsigned &n_lagrangian, const unsigned &n_lagrangian_type, const unsigned &n_dim, const unsigned &n_position_type, const unsigned &initial_n_value)
Unsteady constructor for Solid-type boundary nodes Allocates storage for initial_n_value nodal values...
Definition: nodes.h:2445
void make_periodic(Node *const &node_pt)
Make the node periodic.
Definition: nodes.h:2778
void add_to_boundary(const unsigned &b)
Add the node to mesh boundary b, final overload.
Definition: nodes.h:2545
BoundaryNode()
Default Constructor.
Definition: nodes.h:2382
void clear_additional_copied_pointers()
Copy over additional information so that if the node is periodic it can remain active if the node tha...
Definition: nodes.h:2288
void reset_copied_pointers()
Set pointers to the copied data used when we have periodic nodes.
Definition: nodes.h:2245
bool boundary_coordinates_have_been_set_up()
Have boundary coordinates been set up?
Definition: nodes.h:2517
unsigned nvalue_assigned_by_face_element(const unsigned &face_id=0) const
Return the number of values associated with the i-th face element field. If no argument is specified ...
Definition: nodes.h:2610
void get_coordinates_on_boundary(const unsigned &b, Vector< double > &boundary_zeta)
Return the vector of coordinates on mesh boundary b Final overload.
Definition: nodes.h:2566
void set_coordinates_on_boundary(const unsigned &b, const unsigned &k, const Vector< double > &boundary_zeta)
Set the vector of k-th generalised boundary coordinates on mesh boundary b. Final overload.
Definition: nodes.h:2592
void get_boundaries_pt(std::set< unsigned > *&boundaries_pt)
Access to pointer to set of mesh boundaries that this node occupies; NULL if the node is not on any b...
Definition: nodes.h:2525
void get_coordinates_on_boundary(const unsigned &b, const unsigned &k, Vector< double > &boundary_zeta)
Return the vector of k-th generalised boundary coordinates on mesh boundary b Final overload.
Definition: nodes.h:2583
bool is_on_boundary(const unsigned &b) const
Test whether the node lies on mesh boundary b Final overload.
Definition: nodes.h:2539
Custom Data class that is used when making a shallow copy of a data object. The class contains a copy...
Definition: nodes.h:652
void assign_eqn_numbers(unsigned long &global_ndof, Vector< double * > &dof_pt)
CopiedData is always a copy, so no equation numbers should be allocated. This function just returns.
Definition: nodes.h:708
~CopiedData()
Destructor informs original object that the copy is being deleted and clears its pointers to the stor...
Definition: nodes.h:675
Data * Copied_data_pt
Pointer to the Data object from which the values are copied.
Definition: nodes.h:655
void clear_copied_pointers()
Clear the pointers to the copied data.
Definition: nodes.cc:1398
void reset_copied_pointers()
Reset the pointers to the copied data.
Definition: nodes.cc:1381
bool is_a_copy(const unsigned &i) const
Return a boolean to indicate whether the i-th value is a copied value. All copied data is always a co...
Definition: nodes.h:701
void resize(const unsigned &n_value)
We cannot resize CopiedData, so the resize function throws a warning.
Definition: nodes.cc:1438
bool is_a_copy() const
Return a boolean to indicate whether the data contains any copied values. Copied data is always a cop...
Definition: nodes.h:693
CopiedData(const Data &data)=delete
(Shallow) copy constructor
void operator=(const CopiedData &)=delete
Broken assignment operator.
A class that represents a collection of data; each Data object may contain many different individual ...
Definition: nodes.h:86
long eqn_number(const unsigned &i) const
Return the equation number of the i-th stored variable.
Definition: nodes.h:376
static TimeStepper * Default_static_time_stepper_pt
Default (static) timestepper used in steady problems.
Definition: nodes.h:162
void add_copy(Data *const &data_pt)
Add the pointer data_pt to the array Copy_of_data_pt. This should be used whenever copies are made of...
Definition: nodes.cc:76
long & eqn_number(const unsigned &i)
Return the equation number of the i-th stored variable.
Definition: nodes.h:367
void pin_all()
Pin all the stored variables.
Definition: nodes.h:397
long * Eqn_number
C-style array of pointers to the (global) equation numbers of the values.
Definition: nodes.h:116
virtual void add_eqn_numbers_to_vector(Vector< long > &vector_of_eqn_numbers)
Add all equation numbers to the vector in the internal storage order.
Definition: nodes.cc:1236
bool does_pointer_correspond_to_value(double *const &parameter_pt)
Check whether the pointer parameter_pt addresses internal data values.
Definition: nodes.cc:568
void constrain(const unsigned &i)
Constrain the i-th stored variable when making hanging data If the data is already pinned leave it al...
Definition: nodes.h:432
virtual void describe_dofs(std::ostream &out, const std::string &current_string) const
Function to describe the dofs of the Node. The ostream specifies the output stream to which the descr...
Definition: nodes.cc:939
virtual void add_value_pt_to_map(std::map< unsigned, double * > &map_of_value_pt)
Add pointers to all unpinned and unconstrained data to a map indexed by (global) equation number.
Definition: nodes.cc:1089
Data(const unsigned &initial_n_value)
Default constructor for steady problems: assign memory for initial_n_value values.
long * eqn_number_pt(const unsigned &i)
Return the pointer to the equation number of the i-th stored variable.
Definition: nodes.h:358
unsigned Nvalue
Number of values stored in the data object.
Definition: nodes.h:135
void set_value(const unsigned &t, const unsigned &i, const double &value_)
Set the t-th history value of the i-th stored data value to specified value.
Definition: nodes.h:281
static long Is_pinned
Static "Magic number" used in place of the equation number to indicate that the value is pinned.
Definition: nodes.h:183
double value(const unsigned &t, const unsigned &i) const
Return i-th value at time level t (t=0: present, t>0: previous) This function is not virtual so that ...
Definition: nodes.h:305
void range_check(const unsigned &t, const unsigned &i) const
Check that the arguments are within the range of the stored data values and timesteps.
Definition: nodes.cc:47
void remove_copy(Data *const &data_pt)
Remove the pointer data_pt from the array Copy_of_data_pt. This should be used whenever copies of the...
Definition: nodes.cc:102
virtual void clear_copied_pointers()
Helper function that should be overloaded derived classes that contain copies of data....
Definition: nodes.cc:176
void pin(const unsigned &i)
Pin the i-th stored variable.
Definition: nodes.h:385
friend class HijackedData
Definition: nodes.h:93
bool is_segregated_solve_pinned(const unsigned &i)
Test whether the i-th variable is temporaily pinned for a segregated solve.
Definition: nodes.h:424
Data ** Copy_of_data_pt
C-style array of any Data objects that contain copies of the current Data object's data values.
Definition: nodes.h:127
void unpin(const unsigned &i)
Unpin the i-th stored variable.
Definition: nodes.h:391
int Non_halo_proc_ID
Non-halo processor ID for Data; -1 if it's not a halo.
Definition: nodes.h:140
double * value_pt(const unsigned &i) const
Return the pointer to the i-the stored value. Typically this is required when direct access to the st...
Definition: nodes.h:324
void copy(Data *orig_data_pt)
Copy Data values from specified Data object.
Definition: nodes.cc:601
void unpin_all()
Unpin all the stored variables.
Definition: nodes.h:407
TimeStepper *& time_stepper_pt()
Return the pointer to the timestepper.
Definition: nodes.h:238
void unconstrain_all()
Unconstrain all the stored variables when the data is made nonhanging.
Definition: nodes.h:461
bool is_halo() const
Is this Data a halo?
Definition: nodes.h:532
TimeStepper * Time_stepper_pt
Pointer to a Timestepper. The inclusion of a Timestepper pointer in the Data class,...
Definition: nodes.h:122
friend class CopiedData
Definition: nodes.h:94
virtual void read_values_from_vector(const Vector< double > &vector_of_values, unsigned &index)
Read all data and time history values from the vector starting from index. On return the index will b...
Definition: nodes.cc:1182
virtual void add_values_to_vector(Vector< double > &vector_of_values)
Add all data and time history values to the vector in the internal storage order.
Definition: nodes.cc:1112
static long Is_constrained
Static "Magic number" used in place of the equation number to indicate that the value is constrained ...
Definition: nodes.h:198
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
unsigned Ncopies
Number of Data that contain copies of this Data object's values.
Definition: nodes.h:131
void dump(std::ostream &dump_file) const
Dump the data object to a file.
Definition: nodes.cc:645
virtual ~Data()
Destructor, deallocates memory assigned for data.
Definition: nodes.cc: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
unsigned ntstorage() const
Return total number of doubles stored per value to record time history of each value (one for steady ...
Definition: nodes.cc:879
virtual void assign_eqn_numbers(unsigned long &global_ndof, Vector< double * > &dof_pt)
Assign global equation numbers; increment global number of unknowns, global_ndof; and add any new dof...
Definition: nodes.cc:896
double ** Value
C-style array of pointers to data values and possible history values. The data must be ordered in suc...
Definition: nodes.h:112
void set_nonhalo()
Label the node as not being a halo.
Definition: nodes.h:526
Data(const Data &data)=delete
Broken copy constructor.
void constrain_all()
Constrain all the stored variables when the data is made hanging.
Definition: nodes.h:451
friend std::ostream & operator<<(std::ostream &out, const Data &d)
Output operator: output all values at all times, along with any extra information stored for the time...
bool is_constrained(const unsigned &i)
Test whether the i-th variable is constrained (1: true; 0: false).
Definition: nodes.h:472
static long Is_unclassified
Static "Magic number" used in place of the equation number to denote a value that hasn't been classif...
Definition: nodes.h:192
void delete_value_storage()
Delete all storage allocated by the Data object for values and equation numbers.
Definition: nodes.cc:187
virtual void resize(const unsigned &n_value)
Change (increase) the number of values that may be stored.
Definition: nodes.cc:1002
void set_halo(const unsigned &non_halo_proc_ID)
Label the node as halo and specify processor that holds non-halo counterpart.
Definition: nodes.h:520
Data()
Default: Just set pointer to (steady) timestepper. No storage for values is allocated.
Definition: nodes.cc:237
void unconstrain(const unsigned &i)
Unconstrain the i-th stored variable when make the data nonhanging. Only unconstrain if it was actual...
Definition: nodes.h:442
void set_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Set a new timestepper by resizing the appropriate storage. If already assigned the equation numbering...
Definition: nodes.cc:406
TimeStepper *const & time_stepper_pt() const
Return the pointer to the timestepper (const version).
Definition: nodes.h:244
void read(std::ifstream &restart_file)
Read data object from a file.
Definition: nodes.cc:672
static long Is_segregated_solve_pinned
Static "Magic number" used in place of the equation number to indicate that the value is pinned,...
Definition: nodes.h:188
virtual bool is_a_copy(const unsigned &i) const
Return flag to indicate whether the i-th value is a copy. A base Data object can never be a copy so t...
Definition: nodes.h:261
unsigned self_test()
Self-test: Have all values been classified as pinned/unpinned? Return 0 if OK.
Definition: nodes.cc:965
int non_halo_proc_ID()
ID of processor ID that holds non-halo counterpart of halo node; negative if not a halo.
Definition: nodes.h:539
virtual void read_eqn_numbers_from_vector(const Vector< long > &vector_of_eqn_numbers, unsigned &index)
Read all equation numbers from the vector starting from index. On return the index will be set to the...
Definition: nodes.cc:1274
double * value_pt(const unsigned &t, const unsigned &i) const
Return the pointer to the i-th stored value, or any of its history values (const version)....
Definition: nodes.h:337
bool is_pinned(const unsigned &i) const
Test whether the i-th variable is pinned (1: true; 0: false).
Definition: nodes.h:417
void operator=(const Data &)=delete
Broken assignment operator.
virtual void reset_copied_pointers()
Helper function that should be overloaded in derived classes that can contain copies of Data....
Definition: nodes.cc:162
Data(TimeStepper *const &time_stepper_pt, const unsigned &initial_n_value, const bool &allocate_storage=true)
Constructor for unsteady problems: assign memory for initial_n_value values and any memory required b...
/////////////////////////////////////////////////////////////////////
Definition: geom_objects.h:101
Class that contains data for hanging nodes.
Definition: nodes.h:742
Node ** Master_nodes_pt
C-style array of pointers to nodes that this hanging node depends on.
Definition: nodes.h:839
~HangInfo()
Delete the storage.
Definition: nodes.h:763
HangInfo()
Default constructor, initialise vectors to have size zero.
Definition: nodes.h:745
double const & master_weight(const unsigned &i) const
Return weight for dofs on i-th master node.
Definition: nodes.h:808
Node *const & master_node_pt(const unsigned &i) const
Return a pointer to the i-th master node.
Definition: nodes.h:791
void operator=(const HangInfo &)=delete
Broken assignment operator.
HangInfo(const unsigned &n_master)
Alternative constructor when the number of master nodes is known.
Definition: nodes.h:753
void range_check(const unsigned &i) const
Check that the argument is within the range of stored data values.
Definition: nodes.cc:1456
unsigned Nmaster
Number of master nodes required by this hanging node.
Definition: nodes.h:845
unsigned nmaster() const
Return the number of master nodes.
Definition: nodes.h:785
double * Master_weights
C-style array of weights for the dofs on the master nodes.
Definition: nodes.h:842
void add_master_node_pt(Node *const &master_node_pt, const double &weight)
Add (pointer to) master node and corresponding weight to the internally stored (pointers to) master n...
Definition: nodes.cc:1489
HangInfo(const HangInfo &)=delete
Broken copy constructor.
void set_master_node_pt(const unsigned &i, Node *const &master_node_pt, const double &weight)
Set the pointer to the i-th master node and its weight.
Definition: nodes.cc:1474
Custom Data class that is used when HijackingData. The class always contains a single value that is c...
Definition: nodes.h:575
Data * Copied_data_pt
Pointer to the Data object from which the value is copied.
Definition: nodes.h:578
~HijackedData()
Destructor informs original object that the copy is being deleted and clears its pointers to the stor...
Definition: nodes.h:601
void assign_eqn_numbers(unsigned long &global_ndof, Vector< double * > &dof_pt)
HijackedData is always a copy, so no equation numbers should be allocated. This function just returns...
Definition: nodes.h:634
unsigned Copied_index
Index of the value that is copied from within the Data object.
Definition: nodes.h:581
bool is_a_copy(const unsigned &i) const
Return a boolean to indicate whether the i-th value is a copied value. Hijacked data is always a copy...
Definition: nodes.h:627
bool is_a_copy() const
Return a boolean to indicate whether the data contains any copied values. Hijacked data is always a c...
Definition: nodes.h:619
void resize(const unsigned &n_value)
We cannot resize HijackedData, so the resize function throws a warning.
Definition: nodes.cc:1363
void reset_copied_pointers()
Reset the pointers to the copied data.
Definition: nodes.cc:1304
void operator=(const HijackedData &)=delete
Broken assignment operator.
HijackedData(const Data &data)=delete
(Shallow) copy constructor
void clear_copied_pointers()
Clear the pointers to the copied data.
Definition: nodes.cc:1318
static OomphCommunicator * communicator_pt()
access to global communicator. This is the oomph-lib equivalent of MPI_COMM_WORLD
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:906
double dx_gen_dt(const unsigned &k, const unsigned &i) const
i-th component of time derivative (velocity) of the generalised position, dx(k,i)/dt....
Definition: nodes.cc:1865
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition: nodes.h:1060
double & x_gen(const unsigned &k, const unsigned &i)
Reference to the generalised position x(k,i). ‘Type’: k; Coordinate direction: i.
Definition: nodes.h:1126
virtual void set_coordinates_on_boundary(const unsigned &b, const Vector< double > &boundary_zeta)
Set the vector of coordinates on mesh boundary b Broken virtual interface provides run-time error che...
Definition: nodes.h:1428
HangInfo *const & hanging_pt() const
Return pointer to hanging node data (this refers to the geometric hanging node status) (const version...
Definition: nodes.h:1228
HangInfo *const & hanging_pt(const int &i) const
Return pointer to hanging node data for value i (const version)
Definition: nodes.h:1243
virtual bool position_is_a_copy(const unsigned &i) const
Return whether the position coordinate i has been copied (always false)
Definition: nodes.h:1119
void copy(Node *orig_node_pt)
Copy all nodal data from specified Node object.
Definition: nodes.cc:1916
void add_values_to_vector(Vector< double > &vector_of_values)
Add all data and time history values to the vector. Overloaded to add the position information as wel...
Definition: nodes.cc:2777
double & x_gen(const unsigned &t, const unsigned &k, const unsigned &i)
Reference to the generalised position x(k,i) at the previous timestep [t=0: present]....
Definition: nodes.h:1146
virtual void set_position_time_stepper(TimeStepper *const &position_time_stepper_pt, const bool &preserve_existing_data)
Set a new position timestepper be resizing the appropriate storage.
Definition: nodes.cc:1752
void operator=(const Node &)=delete
Broken assignment operator.
virtual unsigned ncoordinates_on_boundary(const unsigned &b)
Get the number of boundary coordinates on mesh boundary b. Broken virtual interface provides run-time...
Definition: nodes.cc:2363
void set_nonhanging()
Label node as non-hanging node by removing all hanging node data.
Definition: nodes.cc:2281
bool is_obsolete()
Test whether node is obsolete.
Definition: nodes.h:1448
virtual unsigned ngeom_object() const
Return the number of geometric objects that affect the nodal position. The default value is zero (nod...
Definition: nodes.h:1639
virtual bool is_on_boundary() const
Test whether the Node lies on a boundary. The "bulk" Node cannot lie on a boundary,...
Definition: nodes.h:1373
virtual GeomObject ** all_geom_object_pt()
Return a pointer to an array of all (geometric) objects that affect the nodal position....
Definition: nodes.h:1647
void set_obsolete()
Mark node as obsolete.
Definition: nodes.h:1436
virtual void get_boundaries_pt(std::set< unsigned > *&boundaries_pt)
Return a pointer to set of mesh boundaries that this node occupies; this will be overloaded by Bounda...
Definition: nodes.h:1365
virtual void pin_all()
The pin_all() function must be overloaded by SolidNodes, so we put the virtual interface here to avoi...
Definition: nodes.h:1197
void read(std::ifstream &restart_file)
Read nodal position and associated data from file for restart.
Definition: nodes.cc:1996
static unsigned No_independent_position
Static "Magic number" used to indicate that there is no independent position in a periodic node.
Definition: nodes.h:972
bool is_hanging(const int &i) const
Test whether the i-th value is hanging.
Definition: nodes.h:1298
TimeStepper *const & position_time_stepper_pt() const
Return a pointer to the position timestepper (const version).
Definition: nodes.h:1028
void x_gen_range_check(const unsigned &t, const unsigned &k, const unsigned &i) const
Private function to check that the arguemnts to the position functions are in range.
Definition: nodes.cc:1528
virtual void assign_eqn_numbers(unsigned long &global_ndof, Vector< double * > &dof_pt)
Assign global equation numbers; increment global number of unknowns, global_ndof; and add any new dof...
Definition: nodes.cc:534
void set_auxiliary_node_update_fct_pt(AuxNodeUpdateFctPt aux_node_update_fct_pt)
Set pointer to auxiliary update function – this can be used to update any nodal values following the ...
Definition: nodes.h:1596
virtual void remove_from_boundary(const unsigned &b)
Broken interface for removing the node from the mesh boundary b Here to provide error reporting.
Definition: nodes.cc:2350
void perform_auxiliary_node_update_fct()
Execute auxiliary update function (if any) – this can be used to update any nodal values following th...
Definition: nodes.h:1615
virtual void get_coordinates_on_boundary(const unsigned &b, Vector< double > &boundary_zeta)
Return the vector of coordinates on mesh boundary b Broken virtual interface provides run-time error ...
Definition: nodes.h:1420
void set_non_obsolete()
Mark node as non-obsolete.
Definition: nodes.h:1442
virtual Data ** all_geom_data_pt()
Return a pointer to an array of all (geometric) data that affect the nodal position....
Definition: nodes.h:1632
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition: nodes.h:1054
virtual void make_periodic_nodes(const Vector< Node * > &periodic_nodes_pt)
Make the nodes passed in the vector periodic_nodes share the same data as this node.
Definition: nodes.cc:2270
double & x(const unsigned &t, const unsigned &i)
Return the position x(i) at previous timestep t (t=0: present; t>0 previous timestep).
Definition: nodes.h:1079
virtual bool position_is_a_copy() const
Return whether any position coordinate has been copied (always false)
Definition: nodes.h:1113
const double & x_gen(const unsigned &k, const unsigned &i) const
Reference to the generalised position x(k,i). ‘Type’: k; Coordinate direction: i (const version).
Definition: nodes.h:1136
double * x_position_pt(const unsigned &i)
Direct access to the pointer to the i-th stored coordinate data.
Definition: nodes.h:958
virtual void constrain_positions()
Constrain the positions when the node is made hanging Empty virtual function that is overloaded in So...
Definition: nodes.h:1345
void output(std::ostream &outfile)
Output nodal position.
Definition: nodes.cc:2760
AuxNodeUpdateFctPt Aux_node_update_fct_pt
Pointer to auxiliary update function – this can be used to update any nodal values following the upda...
Definition: nodes.h:967
TimeStepper * Position_time_stepper_pt
Pointer to the timestepper associated with the position data.
Definition: nodes.h:932
virtual void unpin_all()
The unpin_all() function must be overloaded by SolidNode, so we put the virtual interface here to avo...
Definition: nodes.h:1204
double ** X_position
Array of pointers to the data holding the Eulerian positions. The storage format must be the same as ...
Definition: nodes.h:929
virtual void add_to_boundary(const unsigned &b)
Broken interface for adding the node to the mesh boundary b Essentially here for error reporting.
Definition: nodes.cc:2336
virtual void set_coordinates_on_boundary(const unsigned &b, const unsigned &k, const Vector< double > &boundary_zeta)
Set the vector of the k-th generalised boundary coordinates on mesh boundary b. Broken virtual interf...
Definition: nodes.cc:2394
HangInfo ** Hanging_pt
C-style array of pointers to hanging node info. It's set to NULL if the node isn't hanging....
Definition: nodes.h:942
void set_hanging_pt(HangInfo *const &hang_pt, const int &i)
Set the hanging data for the i-th value. (hang_pt=0 to make non-hanging)
Definition: nodes.cc:2068
Vector< double > value() const
Return vector of values calculated using value(vector).
Definition: nodes.h:1502
double * x_pt(const unsigned &t, const unsigned &i)
Direct access to the i-th coordinate at time level t (t=0: present; t>0: previous)
Definition: nodes.h:1181
TimeStepper *& position_time_stepper_pt()
Return a pointer to the position timestepper.
Definition: nodes.h:1022
const double & x(const unsigned &i) const
Return the i-th nodal coordinate (const version).
Definition: nodes.h:1069
const double & x(const unsigned &t, const unsigned &i) const
Return the position x(i) at previous timestep t (t=0: present; t>0 previous timestep) (const version)
Definition: nodes.h:1089
unsigned Nposition_type
Number of coordinate types used in the mapping between local and global coordinates (e....
Definition: nodes.h:951
virtual bool boundary_coordinates_have_been_set_up()
Have boundary coordinates been set up? Broken virtual interface provides run-time error checking.
Definition: nodes.cc:2323
double position_gen(const unsigned &k, const unsigned &i) const
Return generalised nodal coordinate either directly or via hanging node representation.
Definition: nodes.cc:2592
unsigned Ndim
Eulerian dimension of the node.
Definition: nodes.h:945
unsigned hang_code()
Code that encapsulates the hanging status of the node (incl. the geometric hanging status) as .
Definition: nodes.h:1213
virtual bool does_pointer_correspond_to_position_data(double *const &parameter_pt)
Check whether the pointer parameter_pt addresses position data values. It never does for a standard n...
Definition: nodes.h:1042
virtual void get_coordinates_on_boundary(const unsigned &b, const unsigned &k, Vector< double > &boundary_zeta)
Return the vector of the k-th generalised boundary coordinates on mesh boundary b....
Definition: nodes.cc:2379
double raw_value(const unsigned &i) const
Return the i-th value stored at the Node. This interface does NOT take the hanging status of the Node...
Definition: nodes.h:1455
virtual void unconstrain_positions()
Unconstrain the positions when the node is made non-hanging Empty virtual function that is overloaded...
Definition: nodes.h:1349
Node(const Node &node)=delete
Broken copy constructor.
Vector< double > position() const
Return vector of position of node at current time.
Definition: nodes.h:1525
virtual Node * copied_node_pt() const
Return pointer to copied node (null if the current node is not a copy – always the case here; it's ov...
Definition: nodes.h:1107
void read_values_from_vector(const Vector< double > &vector_of_values, unsigned &index)
Read all data and time history values from the vector starting from index. On return the index will b...
Definition: nodes.cc:2832
virtual void dump(std::ostream &dump_file) const
Dump nodal position and associated data to file for restart.
Definition: nodes.cc:1969
friend std::ostream & operator<<(std::ostream &out, const Node &d)
Output operator: output location and all values at all times, along with any extra information stored...
Definition: nodes.cc:373
virtual bool is_on_boundary(const unsigned &b) const
Test whether the node lies on mesh boundary b. The "bulk" Node cannot lie on a boundary,...
Definition: nodes.h:1381
virtual unsigned ngeom_data() const
Return the number of geometric data that affect the nodal position. The default value is zero (node i...
Definition: nodes.h:1625
const double & x_gen(const unsigned &t, const unsigned &k, const unsigned &i) const
Reference to the generalised position x(k,i) at the previous timestep [t=0: present]....
Definition: nodes.h:1157
double dposition_dt(const unsigned &i) const
Return the i-th component of nodal velocity: dx/dt, either directly or via hanging node representatio...
Definition: nodes.cc:2659
bool has_auxiliary_node_update_fct_pt()
Boolean to indicate if node has a pointer to and auxiliary update function.
Definition: nodes.h:1606
double dx_dt(const unsigned &i) const
Return the i-th component of nodal velocity: dx/dt.
Definition: nodes.cc:1817
bool Obsolete
Flag to indicate that the Node has become obsolete — usually during mesh refinement process.
Definition: nodes.h:955
void resize(const unsigned &n_value)
Resize the number of equations.
Definition: nodes.cc:2167
virtual void make_periodic(Node *const &node_pt)
Make the node periodic by copying the values from node_pt. Note that the coordinates will always rema...
Definition: nodes.cc:2257
double raw_value(const unsigned &t, const unsigned &i) const
Return the i-th value at time level t (t=0: present, t>0: previous). This interface does NOT take the...
Definition: nodes.h:1463
virtual void node_update(const bool &update_all_time_levels_for_new_node=false)
Interface for functions that update the nodal position using algebraic remeshing strategies....
Definition: nodes.h:1586
unsigned nposition_type() const
Number of coordinate types needed in the mapping between local and global coordinates.
Definition: nodes.h:1016
bool is_hanging() const
Test whether the node is geometrically hanging.
Definition: nodes.h:1285
Node()
Default constructor.
Definition: nodes.cc:1574
double dposition_gen_dt(const unsigned &k, const unsigned &i) const
i-th component of time derivative (velocity) of the generalised position, dx(k,i)/dt....
Definition: nodes.cc:2708
virtual ~Node()
Destructor: Clean up the memory allocated for nodal position.
Definition: nodes.cc:1695
void(* AuxNodeUpdateFctPt)(Node *)
Function pointer to auxiliary node update function.
Definition: nodes.h:909
double value(const unsigned &i) const
Return i-th value (dofs or pinned) at this node either directly or via hanging node representation....
Definition: nodes.cc:2408
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
void constrain_positions()
Overload the constrain positions function to constrain all position values.
Definition: nodes.h:1857
void xi_gen_range_check(const unsigned &k, const unsigned &i) const
Private function to check that the arguments to the position functions are in range.
Definition: nodes.cc:3312
void unpin_all()
Unpin all the stored variables (Overloaded)
Definition: nodes.h:1849
const double & xi(const unsigned &i) const
Reference to i-th Lagrangian position (const version)
Definition: nodes.h:1892
void set_position_time_stepper(TimeStepper *const &position_time_stepper_pt, const bool &preserve_existing_data)
Set a new position timestepper be resizing the appropriate storage Overloaded from the basic implemen...
Definition: nodes.cc:3548
unsigned Nlagrangian
Number of Lagrangian coordinates of the node.
Definition: nodes.h:1694
void unconstrain_positions()
Overload the unconstrain positions function to unconstrain all position values.
Definition: nodes.h:1864
void add_values_to_vector(Vector< double > &vector_of_values)
Add all data, position and time history values to the vector Overload to add the Lagrangian coordinat...
Definition: nodes.cc:3708
bool does_pointer_correspond_to_position_data(double *const &parameter_pt)
Overload the check whether the pointer parameter_pt addresses position data values.
Definition: nodes.cc:3573
void read_eqn_numbers_from_vector(const Vector< long > &vector_of_eqn_numbers, unsigned &index)
Read all equation numbers from the vector starting from index. On return the index will be set to the...
Definition: nodes.cc:3811
const double & xi_gen(const unsigned &k, const unsigned &i) const
Reference to the generalised Lagrangian position. ‘Type’: k; 'Coordinate direction: i....
Definition: nodes.h:1912
unsigned nlagrangian_type() const
Number of types of Lagrangian coordinates used to interpolate the Lagrangian coordinates within the e...
Definition: nodes.h:1877
void unpin_position(const unsigned &k, const unsigned &i)
Unpin the generalised nodal position. ‘Type’: k; Coordinate direction: i.
Definition: nodes.h:1836
double & xi_gen(const unsigned &k, const unsigned &i)
Reference to the generalised Lagrangian position. ‘Type’: k; 'Coordinate direction: i.
Definition: nodes.h:1902
SolidNode(const SolidNode &solid_node)=delete
Broken copy constructor.
const Data & variable_position() const
Return the variable_position data (const version)
Definition: nodes.h:1759
Data * Variable_position_pt
Pointer to data that will hold variable positions in elastic nodes.
Definition: nodes.h:1701
void add_value_pt_to_map(std::map< unsigned, double * > &map_of_value_pt)
Overload the function add_values_to_map so that it also adds the variable position data.
Definition: nodes.cc:3693
unsigned Nlagrangian_type
Number of types of Lagrangian coordinates used to interpolate the Lagrangian coordinates within the e...
Definition: nodes.h:1698
double lagrangian_position(const unsigned &i) const
Return lagrangian coordinate either directly or via hanging node representation.
Definition: nodes.cc:3586
double lagrangian_position_gen(const unsigned &k, const unsigned &i) const
Return generalised lagrangian coordinate either directly or via hanging node representation.
Definition: nodes.cc:3619
SolidNode()
Default Constructor.
Definition: nodes.h:1708
void read_values_from_vector(const Vector< double > &vector_of_values, unsigned &index)
Read all data and time history values from the vector starting from index. On return the index will b...
Definition: nodes.cc:3755
const long & position_eqn_number(const unsigned &k, const unsigned &i) const
Return the equation number for generalised Eulerian coordinate: type of coordinate: k,...
Definition: nodes.h:1797
virtual ~SolidNode()
Destructor that cleans up the additional memory allocated in SolidNodes.
Definition: nodes.cc:3416
void describe_dofs(std::ostream &out, const std::string &current_string) const
Function to describe the dofs of the Node. The ostream specifies the output stream to which the descr...
Definition: nodes.cc:3671
bool position_is_a_copy(const unsigned &i) const
Return whether the position coordinate i has been copied.
Definition: nodes.h:1790
void pin_position(const unsigned &i)
Pin the nodal position.
Definition: nodes.h:1816
bool position_is_a_copy() const
Return whether any position component has been copied.
Definition: nodes.h:1784
void dump(std::ostream &dump_file) const
Dump nodal positions (variable and fixed) and associated data to file for restart.
Definition: nodes.cc:3470
void pin_all()
Pin all the stored variables (Overloaded)
Definition: nodes.h:1842
void unpin_position(const unsigned &i)
Unpin the nodal position.
Definition: nodes.h:1829
void set_external_variable_position_pt(Data *const &data_pt)
Set the variable position data from an external data object.
Definition: nodes.cc:3532
void read(std::ifstream &restart_file)
Read nodal positions (variable and fixed) and associated data from file for restart.
Definition: nodes.cc:3490
double * Xi_position
Storage for the Lagrangian positions.
Definition: nodes.h:1704
double & xi(const unsigned &i)
Reference to i-th Lagrangian position.
Definition: nodes.h:1883
void pin_position(const unsigned &k, const unsigned &i)
Pin the generalised nodal position. ‘Type’: k; Coordinate direction: i.
Definition: nodes.h:1823
void add_eqn_numbers_to_vector(Vector< long > &vector_of_eqn_numbers)
Add all equation numbers to the vector in the internal storage order. Overload to add equation number...
Definition: nodes.cc:3799
void assign_eqn_numbers(unsigned long &global_number, Vector< double * > &dof_pt)
Overload the assign equation numbers routine.
Definition: nodes.cc:3652
void copy(SolidNode *orig_node_pt)
Copy nodal positions and associated data from specified node object.
Definition: nodes.cc:3433
void node_update(const bool &update_all_time_levels_for_new_node=false)
Overload node update function: Since the position of SolidNodes is determined by unknowns,...
Definition: nodes.h:1981
Data *const & variable_position_pt() const
Pointer to variable_position data (const version)
Definition: nodes.h:1765
bool position_is_pinned(const unsigned &k, const unsigned &i)
Test whether the k-th type of the i-th coordinate is pinned 0: false; 1: true.
Definition: nodes.h:1810
unsigned nlagrangian() const
Return number of lagrangian coordinates.
Definition: nodes.h:1870
bool position_is_pinned(const unsigned &i)
Test whether the i-th coordinate is pinned, 0: false; 1: true.
Definition: nodes.h:1803
void operator=(const SolidNode &)=delete
Broken assignment operator.
////////////////////////////////////////////////////////////////////// //////////////////////////////...
Definition: timesteppers.h:231
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...