Example codes
and tutorials
The (Not-so) Quick Guide
List of tutorials/demo codes
Single-Physics Problems
Poisson
Adaptivity illustrated for Poisson
Advection-Diffusion
Unsteady heat equation
Linear wave equation
The Young-Laplace equation
Navier-Stokes
Free-surface Navier-Stokes
Axisymmetric Navier-Stokes
Solid mechanics
Beam structures
Shell structures
Multi-physics Problems
Fluid-structure interaction
Boussinesq convection
Steady thermoelasticity
Methods-based example codes and tutorials
Mesh generation
Linear solvers and preconditioners
Visualisation of the results
Parallel processing
How to write a new element
How to write a new refineable element
Default nonlinear solvers -- the sequence of action functions
...
Documentation
FE theory and top-down discussion of the data structure
The (Not-so) Quick Guide
Comprehensive bottom-up discussion of the data structure
List of available structured and unstructured meshes
Linear solvers and preconditioners
Visualisation of the results
Parallel processing
Coding conventions and C++ style
Creating documentation
Optimisation - robustness vs. "raw speed"
Linear vs. nonlinear problems
Storing shape functions
Changing the default "full" integration scheme
Disabling the ALE formulation of unsteady equations
C vs. C++ output
Different sparse assembly techniques and the STL memory pool
Publications
Publications
Talks
Journal publications
Theses
Picture show
Download
Copyright
Download/installation instructions
Download page
FAQ & Contact
FAQ
Change log
Bugs and other known problems
Completeness of the library & our "To-Do List"
Contact the developers
Get involved

 


Beta release!

Please note that the library has not been "officially" released. While we continue to work on the documentation, these web pages are likely to contain broken links and documents in draft form. Please send an email to

oomph-lib AT maths DOT man DOT ac DOT uk

if you wish to be informed of the library's "official" release.

nodes.h

Go to the documentation of this file.
00001 //LIC// ====================================================================
00002 //LIC// This file forms part of oomph-lib, the object-oriented, 
00003 //LIC// multi-physics finite-element library, available 
00004 //LIC// at http://www.oomph-lib.org.
00005 //LIC// 
00006 //LIC//           Version 0.90. August 3, 2009.
00007 //LIC// 
00008 //LIC// Copyright (C) 2006-2009 Matthias Heil and Andrew Hazel
00009 //LIC// 
00010 //LIC// This library is free software; you can redistribute it and/or
00011 //LIC// modify it under the terms of the GNU Lesser General Public
00012 //LIC// License as published by the Free Software Foundation; either
00013 //LIC// version 2.1 of the License, or (at your option) any later version.
00014 //LIC// 
00015 //LIC// This library is distributed in the hope that it will be useful,
00016 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 //LIC// Lesser General Public License for more details.
00019 //LIC// 
00020 //LIC// You should have received a copy of the GNU Lesser General Public
00021 //LIC// License along with this library; if not, write to the Free Software
00022 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00023 //LIC// 02110-1301  USA.
00024 //LIC// 
00025 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
00026 //LIC// 
00027 //LIC//====================================================================
00028 //This header contains class and function prototypes for Data, Node 
00029 //and associated objects
00030 
00031 //Include guard to prevent multiple inclusions of the header
00032 #ifndef OOMPH_NODES_HEADER
00033 #define OOMPH_NODES_HEADER
00034  
00035 
00036 // Config header generated by autoconfig
00037 #ifdef HAVE_CONFIG_H
00038   #include <oomph-lib-config.h>
00039 #endif
00040 
00041 // C++ headers
00042 #include<map>
00043 #include<set>
00044 
00045 
00046 //oomph-lib headers
00047 #include "Vector.h"
00048 #include "matrices.h"
00049 #include "oomph_utilities.h"
00050 
00051 namespace oomph
00052 {
00053 
00054  //The following classes are used in the Data class, 
00055  //so we provide forward references here
00056 class TimeStepper;
00057 class SolidNode;
00058 class HijackedData;
00059 class CopiedData;
00060 class BoundaryNodeBase; 
00061 template<class NODE_TYPE> class BoundaryNode;
00062  
00063 //=====================================================================
00064 /// \short A class that represents a collection of data;
00065 /// each Data object may contain many different individual values, 
00066 /// as would be natural in non-scalar problems.
00067 /// Data provides storage for auxiliary `history' values that are 
00068 /// used by TimeStepper objects to calculate the time derivatives of the 
00069 /// stored data and also stores a pointer to the appropriate TimeStepper 
00070 /// object. 
00071 /// In addition, an associated (global) equation number is 
00072 /// stored for each value.
00073 ///
00074 /// The Data class permits copies of the stored data values and equation
00075 /// numbers into another Data object using the copy() function. 
00076 /// Shallow (pointer based) copies of 
00077 /// the values can be obtained by using specific derived classes. In such
00078 /// cases pointers to the objects that contain the pointer-based copies 
00079 /// should be stored in the original Data class 
00080 /// (in the array Copy_of_data_pt)
00081 /// so that resize and destruction operations can be performed safely. 
00082 //=====================================================================
00083 class Data
00084 {
00085   private:
00086 
00087  //We wish certain classes to have access to the internal data
00088  //storage model so that the pointers to the values and equations can be
00089  //used for efficiency reasons. In particular, any derived classes 
00090  //that contains shallow copies of Data values 
00091  //(BoundaryNodeBase, CopiedData  and HijackedData) must have pointer-access.
00092  friend class HijackedData;
00093  friend class CopiedData;
00094  friend class BoundaryNodeBase;
00095  template<class NODE_TYPE> friend class BoundaryNode;
00096 
00097  //SolidNodes use their knowledge of
00098  //the internal storage of the data values to efficiently implement 
00099  //the use of positions as variables for solid mechanics problems.
00100  friend class SolidNode;
00101 
00102  /// \short C-style array of pointers to data values and 
00103  /// possible history values. The data must be ordered in such a way
00104  /// that Value[i][t] gives the i-th data value at the time value t.
00105  /// The ordering is chosen so that all the time levels of a particular
00106  /// value can be access from a single pointer to a double. This is
00107  /// required for copying/hijacking functionality.
00108  /// The data should be accessed by using the member functions value(time,ival)
00109  /// and set_value(time,ival,value), where time=0: present. 
00110  double **Value;
00111  
00112  /// \short C-style array of pointers to the (global) equation numbers 
00113  /// of the values. This is an array of pointers, rather than long's so that
00114  /// the values and their equation numbers can be copied/hijacked.
00115  long **Eqn_number_pt;
00116  
00117  /// \short Pointer to a Timestepper. 
00118  /// The inclusion of a Timestepper pointer in the Data class, ensures that
00119  /// time-derivatives can be calculated and storage can be managed at the 
00120  /// low (Data) level.
00121  TimeStepper* Time_stepper_pt;
00122 
00123  /// \short C-style array of any Data objects that contain copies 
00124  /// of the current Data object's data values.
00125  Data **Copy_of_data_pt;
00126  
00127  /// \short Number of values stored in the data object.
00128  unsigned Nvalue;
00129  
00130  /// \short Number of Data that contain copies of this Data object's 
00131  /// values
00132  unsigned Ncopies;
00133 
00134 #ifdef OOMPH_HAS_MPI
00135 
00136  /// \short Is the Data a halo?
00137  bool Is_halo;
00138 
00139 #endif
00140 
00141  /// \short Check that the arguments are within
00142  /// the range of the stored data values and timesteps.
00143  void range_check(const unsigned &t, const unsigned &i) const;
00144  
00145  /// \short Delete all storage allocated by the Data object for values
00146  /// and equation numbers.
00147  void delete_value_storage();
00148  
00149  /// \short Add the pointer data_pt to the array Copy_of_data_pt.
00150  /// This should be used whenever copies are made of the data.
00151  void add_copy(Data* const &data_pt);
00152 
00153  /// \short Remove the pointer data_pt from the array Copy_of_data_pt.
00154  /// This should be used whenever copies of the data are deleted.
00155  void remove_copy(Data* const &data_pt);
00156  
00157   protected: 
00158 
00159  /// Default (static) timestepper used in steady problems.
00160  static TimeStepper* Default_static_time_stepper_pt;
00161 
00162  /// \short Helper function that should be overloaded in derived classes
00163  /// that can contain copies of Data. The function must 
00164  /// reset the internal pointers to the copied data. This is used
00165  /// when resizing data to ensure that all the pointers remain valid.
00166  /// The default implementation throws an error beacause Data cannot be
00167  /// a copy.
00168  virtual void reset_copied_pointers();
00169 
00170  /// \short Helper function that should be overloaded derived classes
00171  /// that contain copies of data. The function must
00172  /// unset (NULL out) the internal pointers to the copied data.
00173  /// This is used when destructing data to ensure that all pointers remain
00174  /// valid. The default implementation throws an error because Data cannot
00175  /// be a copy.
00176  virtual void clear_copied_pointers();
00177 
00178   public:
00179  
00180  /// \short Static "Magic number" used in place of the equation number to 
00181  ///indicate that the value is pinned.
00182  static long Is_pinned;
00183 
00184  /// \short Static "Magic number" used in place of the equation number to 
00185  /// denote a value that hasn't been classified as pinned or free.
00186  static long Is_unclassified;
00187 
00188  ///\short Static "Magic number" used in place of the equation number to
00189  ///indicate that the value is constrained because it is associated 
00190  ///with non-conforming element boundaries --- a hanging node ---
00191  ///(and is therefore pinned)
00192  static long Is_constrained;
00193 
00194  ///\short Default: Just set pointer to (steady) timestepper.
00195  /// No storage for values is allocated.
00196  Data(); 
00197 
00198  ///\short Default constructor for steady problems: 
00199  /// assign memory for initial_n_value values. 
00200  Data(const unsigned &initial_n_value); 
00201 
00202  /// \short Constructor for unsteady problems: assign memory for 
00203  /// initial_n_value values and any memory required by the Timestepper for 
00204  /// the storage of history values.
00205  //ALH: Note the "awkward" C++ syntax for passing a constant reference to 
00206  //a pointer. N.B. We cannot change the pointer, but we can change 
00207  //what it points to. We could use a const pointer, to prevent change of the
00208  //object, but that brings in a whole additional layer of complexity.
00209  Data(TimeStepper* const &time_stepper_pt, const unsigned &initial_n_value,
00210       const bool &allocate_storage=true);
00211 
00212  /// \short Broken copy constructor.
00213  Data(const Data& data) {BrokenCopy::broken_copy("Data");}
00214 
00215  /// Broken assignment operator.
00216  void operator=(const Data&) {BrokenCopy::broken_assign("Data");}
00217 
00218   /// Destructor, deallocates memory assigned for data.
00219  virtual ~Data();
00220 
00221  /// Return the pointer to the timestepper.
00222  TimeStepper*& time_stepper_pt() {return Time_stepper_pt;}
00223 
00224  /// Return the pointer to the timestepper (const version).
00225  TimeStepper* const &time_stepper_pt() const {return Time_stepper_pt;}
00226  
00227  /// \short Return a boolean to indicate whether 
00228  /// the Data objact contains any copied values.
00229  /// A base Data object can never be a copy so the default implementation
00230  /// always returns false.
00231  virtual bool is_a_copy() const {return false;}
00232 
00233  /// \short Return flag to indicate whether the i-th value is a copy.
00234  /// A base Data object can never be a copy so the default implementation
00235  /// always returns false.
00236  virtual bool is_a_copy(const unsigned &i) const {return false;}
00237 
00238  /// \short Set the i-th stored data value to specified value.
00239  /// The only reason that we require an explicit set function is
00240  /// because we redefine value() in the Node class to interpolate
00241  /// the values for nodes that are hanging and so we cannot 
00242  /// return a reference to the value in this case.
00243  void set_value(const unsigned &i, const double &value)
00244   {
00245 #ifdef RANGE_CHECKING
00246    range_check(0,i);
00247 #endif
00248    Value[i][0] = value;
00249   }
00250  
00251  /// \short Set the t-th history value of the i-th stored data value to 
00252  /// specified value.
00253  void set_value(const unsigned &t, 
00254                 const unsigned &i,
00255                 const double &value)
00256   {
00257 #ifdef RANGE_CHECKING
00258    range_check(t,i);
00259 #endif
00260    Value[i][t] = value;
00261   }
00262  
00263  /// \short Return i-th stored value. 
00264  /// This function is not virtual so that it can be inlined.
00265  /// This means that if we have an explicit pointer to a Data object 
00266  /// Data* data_pt->value() always returns the "raw" stored value.
00267  double value(const unsigned &i) const
00268   {
00269 #ifdef RANGE_CHECKING
00270    range_check(0,i);
00271 #endif
00272    return Value[i][0];
00273   }
00274 
00275  /// \short Return i-th value at time level t (t=0: present, t>0: previous)
00276  /// This function is not virtual so that it can be inlined.
00277  /// This means that if we have an explicit pointer to a Data object 
00278  /// Data* data_pt->value() always returns to the "raw" stored value.
00279  double value(const unsigned &t, const unsigned &i) const
00280   {
00281 #ifdef RANGE_CHECKING
00282    range_check(t,i);
00283 #endif
00284    return Value[i][t];
00285   }
00286 
00287  /// Compute Vector of values for the Data value.
00288  void value(Vector<double> &values) const;
00289 
00290  /// \short Compute Vector of values (dofs or pinned) in this data
00291  /// at time level t (t=0: present; t>0: previous).
00292  void value(const unsigned &t, Vector<double> &values) const;
00293  
00294  /// \short Return the pointer to the i-the stored value. 
00295  /// Typically this is required when direct access 
00296  /// to the stored value is required, e.g. when writing functions that
00297  /// return a reference to a variable that is stored in a Data object.
00298  double* value_pt(const unsigned &i) const 
00299   {
00300 #ifdef RANGE_CHECKING
00301    range_check(0,i);
00302 #endif
00303    return Value[i];
00304   }
00305  
00306  /// \short Return the pointer to the i-th stored value,
00307  /// or any of its history values (const version).
00308  /// Typically this is required when direct access 
00309  /// to the stored value is required, e.g. when writing functions that
00310  /// return a reference to a variable that is stored in a Data object.
00311  double* value_pt(const unsigned &t, const unsigned &i) const 
00312   {
00313 #ifdef RANGE_CHECKING
00314    range_check(t,i);
00315 #endif
00316    return &Value[i][t];
00317   }
00318 
00319  /// Copy Data values from specified Data object
00320  void copy(Data* orig_data_pt);
00321 
00322  /// Dump the data object to a file. 
00323  void dump(std::ostream& dump_file);
00324 
00325  /// Read data object from a file.
00326  void read(std::ifstream& restart_file);
00327 
00328  /// Return the pointer to the equation number of the i-th stored variable.
00329  long* eqn_number_pt(const unsigned &i) 
00330   {
00331 #ifdef RANGE_CHECKING
00332    range_check(0,i);
00333 #endif
00334    return Eqn_number_pt[i];
00335   }
00336 
00337  /// Return the equation number of the i-th stored variable.
00338  inline long &eqn_number(const unsigned &i) 
00339   {
00340 #ifdef RANGE_CHECKING
00341    range_check(0,i);
00342 #endif
00343    return *Eqn_number_pt[i];
00344   }
00345 
00346  /// \short Pin the i-th stored variable.
00347  inline void pin(const unsigned &i) {eqn_number(i)=Is_pinned;}
00348 
00349  /// \short Unpin the i-th stored variable.
00350  inline void unpin(const unsigned &i) {eqn_number(i)=Is_unclassified;}
00351 
00352  /// Pin all the stored variables 
00353  void pin_all()
00354   {
00355    const unsigned n_value = Nvalue;
00356    for(unsigned i=0;i<n_value;i++) {*Eqn_number_pt[i]=Is_pinned;}
00357   }
00358 
00359  /// Unpin all the stored variables
00360  void unpin_all()
00361   {
00362    const unsigned n_value = Nvalue;
00363    for(unsigned i=0;i<n_value;i++) {*Eqn_number_pt[i]=Is_unclassified;}
00364   }
00365 
00366  /// \short Test whether the i-th variable is pinned (1: true; 0: false).
00367  bool is_pinned(const unsigned &i) {return (*Eqn_number_pt[i]==Is_pinned);}
00368 
00369  /// \short Constrain the i-th stored variable when making hanging data
00370  /// If the data is already pinned leave it along, otherwise mark as
00371  /// constrained (hanging)
00372  inline void constrain(const unsigned &i) 
00373   {if(eqn_number(i)!=Is_pinned) {eqn_number(i) = Is_constrained;}}
00374 
00375  /// \short Unconstrain the i-th stored variable when make the data 
00376  /// nonhanging. Only unconstrain if it was actually constrained (hanging)
00377  inline void unconstrain(const unsigned &i)
00378   {if(eqn_number(i)==Is_constrained) {eqn_number(i) = Is_unclassified;}}
00379 
00380  /// Constrain all the stored variables when the data is made hanging
00381  void constrain_all()
00382   {
00383    const unsigned n_value = Nvalue;
00384    for(unsigned i=0;i<n_value;i++) {constrain(i);}
00385   }
00386 
00387  /// Unconstrain all the stored variables when the data is made nonhanging
00388  void unconstrain_all()
00389   {
00390    const unsigned n_value = Nvalue;
00391    for(unsigned i=0;i<n_value;i++) {unconstrain(i);}
00392   }
00393 
00394  /// \short Test whether the i-th variable is constrained (1: true; 0: false).
00395  bool is_constrained(const unsigned &i) 
00396   {return (*Eqn_number_pt[i]==Is_constrained);}
00397 
00398 
00399  /// \short Self-test: Have all values been classified as pinned/unpinned?
00400  /// Return 0 if OK. 
00401  unsigned self_test();
00402 
00403  /// Return number of values stored in data object (incl pinned ones).
00404  unsigned nvalue() const {return Nvalue;}
00405 
00406  /// \short Return total number of doubles stored per value 
00407  /// to record time history of each value (one for steady problems).
00408  unsigned ntstorage() const;
00409 
00410  /// \short Assign global equation numbers; increment global number 
00411  /// of unknowns, global_ndof; and add any new dofs to the dof_pt.
00412  virtual void assign_eqn_numbers(unsigned long &global_ndof, 
00413                                  Vector<double *> &dof_pt);
00414  
00415  /// Change (increase) the number of values that may be stored.
00416  virtual void resize(const unsigned &n_value);
00417  
00418 #ifdef OOMPH_HAS_MPI
00419 
00420  /// \short Is this Data a halo?
00421  bool& is_halo() 
00422   {
00423    return Is_halo;
00424   } 
00425 
00426 #endif
00427 
00428 };
00429 
00430 //=========================================================================
00431 /// \short Custom Data class that is used when HijackingData. 
00432 /// The class always contains a single value that is 
00433 /// copied from another Data object.
00434 //=========================================================================
00435  class HijackedData : public Data 
00436   {
00437     private:
00438  
00439    ///\short Pointer to the Data object from which the value is copied
00440    Data* Copied_data_pt;
00441 
00442    ///\short Index of the value that is copied from within the Data object
00443    unsigned Copied_index;
00444 
00445    /// \short Reset the pointers to the copied data.
00446    void reset_copied_pointers();
00447 
00448    /// \short Clear the pointers to the copied data
00449    void clear_copied_pointers();
00450 
00451     public:
00452    
00453    ///\short Constructor
00454    HijackedData(const unsigned &copied_value, Data* const &data_pt);
00455  
00456    /// \short (Shallow) copy constructor
00457    HijackedData(const Data &data) : Data(data) { }
00458    
00459    /// Broken assignment operator
00460    void operator=(const HijackedData&) 
00461     {
00462      BrokenCopy::broken_assign("HijackedData");
00463     }
00464 
00465    /// \short Destructor informs original object that the copy is
00466    /// being deleted and clears its pointers to the stored values.
00467    ~HijackedData() 
00468     {
00469      //Inform the Copied data that this copy is being deleted
00470      //If the original has already been deleted
00471      //Copied_data_pt will be set to NULL and this will not be
00472      //necessary
00473      if(Copied_data_pt) {Copied_data_pt->remove_copy(this);}
00474      //Now null out the storage
00475      Copied_data_pt=0; Value=0; Eqn_number_pt=0;
00476     }
00477 
00478    /// \short Return a boolean to indicate whether the data contains 
00479    /// any copied values. Hijacked data is always a copy
00480    bool is_a_copy() const {return true;}
00481    
00482    /// \short Return a boolean to indicate whether
00483    /// the i-th value is a copied value.
00484    /// Hijacked data is always a copy
00485    bool is_a_copy(const unsigned &i) const {return true;}
00486 
00487    /// \short HijackedData is always a copy, so no equation numbers 
00488    /// should be allocated. This function just returns.
00489    void assign_eqn_numbers(unsigned long &global_ndof, 
00490                             Vector<double *> &dof_pt) {return;}
00491 
00492 
00493    /// \short We cannot resize HijackedData, so the resize function
00494    /// throws a warning.
00495    void resize(const unsigned &n_value); 
00496 
00497   };
00498 
00499 
00500 //=========================================================================
00501 /// \short Custom Data class that is used when making a shallow copy
00502 /// of a data object. The class contains a copy of an entire other
00503 /// Data object.
00504 //=========================================================================
00505  class CopiedData : public Data 
00506   {
00507     private:
00508  
00509    ///\short Pointer to the Data object from which the values are copied
00510    Data* Copied_data_pt;
00511 
00512    /// \short Reset the pointers to the copied data.
00513    void reset_copied_pointers();
00514 
00515    /// \short Clear the pointers to the copied data
00516    void clear_copied_pointers();
00517 
00518     public:
00519    
00520    ///\short Constructor
00521    CopiedData(Data* const &data_pt);
00522  
00523    /// \short (Shallow) copy constructor
00524    CopiedData(const Data &data) : Data(data) { }
00525    
00526    /// Broken assignment operator
00527    void operator=(const CopiedData&) 
00528     {
00529      BrokenCopy::broken_assign("CopiedData");
00530     }
00531 
00532    /// \short Destructor informs original object that the copy is
00533    /// being deleted and clears its pointers to the stored values.
00534    ~CopiedData() 
00535     {
00536      //Inform the Copied data that this copy is being deleted
00537      //If the original has already been deleted
00538      //Copied_data_pt will be set to NULL and this will not be
00539      //necessary
00540      if(Copied_data_pt) {Copied_data_pt->remove_copy(this);}
00541      //Now null out the storage
00542      Copied_data_pt=0; Value=0; Eqn_number_pt=0;
00543     }
00544 
00545    /// \short Return a boolean to indicate whether the data contains 
00546    /// any copied values. Copied data is always a copy
00547    bool is_a_copy() const {return true;}
00548    
00549    /// \short Return a boolean to indicate whether
00550    /// the i-th value is a copied value.
00551    /// All copied data is always a copy
00552    bool is_a_copy(const unsigned &i) const {return true;}
00553 
00554    /// \short CopiedData is always a copy, so no equation numbers 
00555    /// should be allocated. This function just returns.
00556    void assign_eqn_numbers(unsigned long &global_ndof, 
00557                             Vector<double *> &dof_pt) {return;}
00558 
00559 
00560    /// \short We cannot resize CopiedData, so the resize function
00561    /// throws a warning.
00562    void resize(const unsigned &n_value); 
00563 
00564   };
00565 
00566    
00567    
00568 //Nodes are required in the HangInfo class, so we need a forward reference
00569 class Node;
00570 
00571 
00572 //=====================================================================
00573 ///\short Class that contains data for hanging nodes.
00574 ///
00575 /// To ensure inter-element continuity, the values and nodal positions 
00576 /// of hanging nodes must be linear combinations of the 
00577 /// values and positions on certain adjacent "master" nodes.
00578 /// For every hanging node \f$ J \f$ ,
00579 ///  \f[ {\bf U}_J = \sum_{K} {\bf U}_{K} \omega_{JK}  \f] 
00580 /// and 
00581 ///  \f[ {\bf X}_J = \sum_{K} {\bf X}_{K} \omega_{JK} \f],
00582 /// where \f$ {\bf U}_I \f$ and \f$ {\bf U}_I \f$ are Vectors containing
00583 /// the nodal values and positions of node
00584 /// \f$ I \f$ respectively; the sum is taken over the hanging node's 
00585 /// master nodes \f$ K \f$ and \f$ \omega_{JK} \f$ are suitable weights.
00586 /// This class provides storage and access functions for the
00587 /// pointers to the master nodes and their associated weights.
00588 //=====================================================================
00589 class HangInfo
00590 {
00591   public:
00592  
00593  /// Default constructor, initialise vectors to have size zero
00594  HangInfo() : Master_nodes_pt(0), Master_weights(0), Nmaster(0)
00595   {
00596 #ifdef LEAK_CHECK
00597    LeakCheckNames::HangInfo_build+=1;
00598 #endif
00599   }
00600 
00601  /// Alternative constructor when the number of master nodes is known
00602  HangInfo(const unsigned &nmaster) : Nmaster(nmaster)
00603   {
00604 #ifdef LEAK_CHECK
00605    LeakCheckNames::HangInfo_build+=1;
00606 #endif
00607    Master_nodes_pt = new Node*[nmaster];
00608    Master_weights = new double[nmaster];
00609   }
00610 
00611  /// Delete the storage
00612  ~HangInfo()
00613   {
00614 #ifdef LEAK_CHECK
00615    LeakCheckNames::HangInfo_build-=1;
00616 #endif
00617    //If there is any storage, then delete it
00618    if(Nmaster > 0)
00619     {
00620      delete[] Master_nodes_pt; Master_nodes_pt=0;
00621      delete[] Master_weights; Master_weights=0;
00622     }
00623   }
00624  
00625  /// Broken copy constructor
00626  HangInfo(const HangInfo&) 
00627   { 
00628    BrokenCopy::broken_copy("HangInfo");
00629   } 
00630  
00631  /// Broken assignment operator
00632  void operator=(const HangInfo&) 
00633   {
00634    BrokenCopy::broken_assign("HangInfo");
00635   }
00636  
00637  /// Return the number of master nodes
00638  unsigned nmaster() const {return Nmaster;}
00639 
00640  /// Return a pointer to the i-th master node 
00641  Node* const &master_node_pt(const unsigned &i) const
00642   {
00643 #ifdef PARANOID
00644    if (Nmaster==0)
00645     {
00646      throw OomphLibError("Hanging node data hasn't been setup yet \n",
00647                          "HangInfo::master_node_pt()",
00648                          OOMPH_EXCEPTION_LOCATION);
00649     }
00650 #endif
00651 #ifdef RANGE_CHECKING
00652    range_check(i);
00653 #endif
00654    return Master_nodes_pt[i];
00655   }
00656 
00657  /// Return weight for dofs on i-th master node
00658  double const &master_weight(const unsigned &i) const
00659   {
00660 #ifdef PARANOID
00661    if (Nmaster==0)
00662     {
00663      throw OomphLibError("Hanging node data hasn't been setup yet \n",
00664                          "HangInfo::master_weight()",
00665                          OOMPH_EXCEPTION_LOCATION);
00666     }
00667 #endif
00668 #ifdef RANGE_CHECKING
00669    range_check(i);
00670 #endif
00671    return Master_weights[i];
00672   }
00673 
00674  /// \short Set the pointer to the i-th master node and its weight
00675  void set_master_node_pt(const unsigned &i, Node* const &master_node_pt,
00676                          const double &weight);
00677 
00678  /// \short Add (pointer to) master node and corresponding weight to 
00679  /// the internally stored (pointers to) master nodes and weights
00680  void add_master_node_pt(Node* const &master_node_pt,const double &weight);
00681 
00682 private:
00683 
00684  /// \short Check that the argument is within the range of 
00685  /// stored data values.
00686  void range_check(const unsigned &i) const;
00687 
00688  /// C-style array of pointers to nodes that this hanging node depends on
00689  Node* *Master_nodes_pt;
00690 
00691  /// C-style array of weights for the dofs on the master nodes
00692  double *Master_weights;
00693 
00694  /// Number of master nodes required by this hanging node
00695  unsigned Nmaster;
00696 
00697 };
00698 
00699 //Geometric objects are (now) required in the Node class, so we 
00700 //put a forward reference here
00701 class GeomObject;
00702 
00703 
00704 //=====================================================================
00705 /// \short Nodes are derived from Data, but, in addition, have a 
00706 /// definite (Eulerian) position in a space of a given dimension. 
00707 /// \n \n 
00708 /// The nodal coordinates are used in the elements' mapping
00709 /// between local and global coordinates and in the simplest
00710 /// case (stationary nodes in Lagrange-type elements) this mapping
00711 /// is given by
00712 /// \f[  x_i = \sum_{j=1}^{N_{node}} X_{ij} \psi_{j}(s_k) \f]
00713 /// so we need only access to the nodal coordinates 
00714 /// \f$ X_{ij}\ (i=1..DIM) \f$ of all nodes \f$ j \f$ : provided
00715 /// by the Node member function
00716 /// \code Node::x(i) \endcode
00717 /// \n \n 
00718 /// If the nodal positions are time-dependent, the mapping becomes
00719 /// \f[  x_i(t) = \sum_{j=1}^{N_{node}}  X_{ij}(t) \ \psi_{j}(s_k). \f]
00720 /// Within the computation (where time is only evaluated at discrete
00721 /// levels) this becomes
00722 /// \f[  x_{ti} = \sum_{j=1}^{N_{node}} X_{ijt} \ \psi_{j}(s_k). \f]
00723 /// and we need access to the nodal coordinates \f$ X_{ijt} \ (i=1..DIM) \f$ of
00724 /// all nodes \f$ j \f$ at the present (t=0) and previous (t>0) timesteps:
00725 /// provided by the Node member function
00726 /// \code Node::x(t,i) \endcode
00727 /// \b Note: The interpretation of the history values is slightly more
00728 /// subtle than that. Depending on the positional TimeStepper
00729 /// used, only a limited number of the positional history values accessed 
00730 /// \c Node::x(t,i) represent previous nodal positions; the others
00731 /// are generalised history values that the TimeStepper uses to 
00732 /// determine approximations for the time-derivatives of the
00733 /// nodal positions. 
00734 /// \n \n
00735 /// Finally, some elements employ mappings 
00736 /// that involve additional, generalised coordinates. For instance,
00737 /// in Hermite elements the mapping between local and global coordinates
00738 /// is based on an independent interpolation for the global coordinates
00739 /// and their derivative w.r.t. to the local coordinates. In such
00740 /// elements, the mapping becomes
00741 /// \f[  x_i = \sum_{j=1}^{N_{node}} \sum_{k=1}^{N_{type}} X_{ijk} 
00742 ///    \psi_{jk}(s_k) \f]
00743 /// where \f$ N_{type} \f$ is the number of the different types of generalised 
00744 /// coordinates involved in the mapping. For instance, in 1D Hermite elements
00745 /// \f$ N_{type}=2 \f$ and k=0 corresponds to the global coordinates while
00746 /// k=1 corresponds to the
00747 /// derivative of the global coordinates w.r.t. to the local coordinate.
00748 /// In such cases we need access to the generalised nodal coordinates 
00749 /// \f$ X_{ijk}  \ (i=1..DIM, \ k=1..N_{type}) \f$ of all nodes \f$ j \f$.
00750 /// Access is provided by the Node member function
00751 /// \code Node::x_gen(k,i) \endcode
00752 /// and the corresponding time-dependent version
00753 /// \code Node::x_gen(t,k,i) \endcode
00754 /// While this is all pretty straightforward, it does make the 
00755 /// argument list of the Node constructors rather lengthy.
00756 //=====================================================================
00757 class Node : public Data
00758 {
00759 
00760 
00761 public:
00762 
00763   /// Function pointer to auxiliary node update function
00764   typedef void(*AuxNodeUpdateFctPt)(Node*);  
00765 
00766  //The BoundaryNodeBase class must use knowledge of the internal data storage
00767  ///to construct periodic Nodes
00768  friend class BoundaryNodeBase;
00769  
00770   protected:
00771 
00772  /// \short Private function to check that the arguemnts to the position
00773  /// functions are in range
00774  void x_gen_range_check(const unsigned &t, const unsigned &k,
00775                         const unsigned &i) const;
00776  
00777  /// \short Array of pointers to the data holding the Eulerian positions. 
00778  /// The storage format must be the same as the internal data storage
00779  /// so that we can implement the functions x() in generality here without
00780  /// the need for virtual functions. The first index will be a flat array
00781  /// of position types and coordinates and the second will be the number
00782  /// of time history values at each position type.
00783  double **X_position;
00784  
00785  /// \short Pointer to the timestepper associated with the position data.
00786  TimeStepper *Position_time_stepper_pt; 
00787   
00788  /// \short C-style array of pointers to hanging node info.
00789  /// It's set to NULL if the node isn't hanging. 
00790  /// The first entry (0) is the geometric hanging node data. 
00791  /// The remaining entries correspond to the hanging data for the
00792  /// other values stored at the node. Usually, these entries will be the 
00793  /// same as the geometric hanging node data represented by Hanging_pt[0], 
00794  /// but this is not necessarily  the case; e.g. the pressure in Taylor Hood
00795  /// has different hanging node data from the velocities.
00796  HangInfo* *Hanging_pt;
00797 
00798  /// Eulerian dimension of the node
00799  unsigned Ndim;
00800 
00801  /// \short Number of coordinate types used in the mapping between 
00802  /// local and global coordinates 
00803  /// (e.g. 1 for Lagrange-type elements; 2 for 1D Hermite elements; 4 for
00804  /// 2D Hermite elements, etc).
00805  unsigned Nposition_type;
00806 
00807  /// \short Flag to indicate that the Node has become 
00808  /// obsolete --- usually during mesh refinement process 
00809  bool Obsolete;
00810 
00811  /// \short Direct access to the pointer to the i-th stored coordinate data
00812  double* x_position_pt(const unsigned &i) {return X_position[i];}
00813 
00814  /// \short Pointer to auxiliary update function -- this 
00815  /// can be used to update any nodal values following the update
00816  /// of the nodal position. This is needed e.g. to update the no-slip
00817  /// condition on moving boundaries. 
00818  AuxNodeUpdateFctPt Aux_node_update_fct_pt;
00819 
00820 public:
00821 
00822  /// \short Static "Magic number" used to indicate that there is no 
00823  /// independent position in a periodic node. 
00824  static unsigned No_independent_position;
00825 
00826  /// \short Default constructor
00827  Node();
00828 
00829  /// \short Steady constructor, for a Node of spatial dimension n_dim. 
00830  /// Allocates storage for initial_n_value values.
00831  /// NPosition_type is the number of coordinate types 
00832  /// needed in the mapping between local and global coordinates 
00833  /// (e.g. 1 for Lagrange-type elements; 2 for 1D Hermite elements; 4 for
00834  /// 2D Hermite elements, etc). 
00835  Node(const unsigned &n_dim, const unsigned &n_position_type,
00836       const unsigned &initial_n_value, 
00837       const bool &allocate_x_position=true);
00838 
00839  /// \short Unsteady constructor for a node of spatial dimension n_dim. 
00840  /// Allocates storage for initial_n_value values with 
00841  /// history values as required by the timestepper. 
00842  /// n_position_type: # of coordinate 
00843  /// types needed in the mapping between local and global coordinates  
00844  /// (e.g. 1 for Lagrange-type elements; 2 for 1D Hermite elements; 4 for 
00845  /// 2D Hermite elements).
00846  Node(TimeStepper* const &time_stepper_pt, const unsigned &n_dim, 
00847       const unsigned &n_position_type, const unsigned &initial_n_value,
00848       const bool &allocate_x_position=true);
00849 
00850  ///Destructor: Clean up the memory allocated for nodal position.
00851  virtual ~Node();
00852 
00853  /// Broken copy constructor
00854  Node(const Node& node) 
00855   { 
00856    BrokenCopy::broken_copy("Node");
00857   } 
00858  
00859  /// Broken assignment operator
00860  void operator=(const Node&) 
00861   {
00862    BrokenCopy::broken_assign("Node");
00863   }
00864  
00865  /// \short Number of coordinate 
00866  /// types needed in the mapping between local and global coordinates. 
00867  unsigned nposition_type() const {return Nposition_type;}
00868 
00869  /// \short Return a pointer to the position timestepper. 
00870  TimeStepper* &position_time_stepper_pt() {return Position_time_stepper_pt;}
00871 
00872  /// \short Return a pointer to the position timestepper (const version).
00873  TimeStepper* const &position_time_stepper_pt() const
00874   {return Position_time_stepper_pt;}
00875 
00876  /// \short Return (Eulerian) spatial dimension of the node.
00877  unsigned ndim() const {return Ndim;}
00878 
00879 ///Return the i-th nodal coordinate.
00880  double &x(const unsigned &i) 
00881   {
00882 #ifdef RANGE_CHECKING
00883    x_gen_range_check(0,0,i);
00884 #endif
00885    return X_position[Nposition_type*i][0];
00886   }
00887 
00888  ///Return the i-th nodal coordinate (const version).
00889  const double &x(const unsigned &i) const 
00890   {
00891 #ifdef RANGE_CHECKING
00892    x_gen_range_check(0,0,i);
00893 #endif
00894    return X_position[Nposition_type*i][0];
00895   }
00896 
00897  /// \short Return the position x(i) at previous timestep t 
00898  /// (t=0: present; t>0 previous timestep).
00899  double &x(const unsigned &t, const unsigned &i) 
00900   {
00901 #ifdef RANGE_CHECKING
00902    x_gen_range_check(t,0,i);
00903 #endif
00904    return X_position[Nposition_type*i][t];
00905   }
00906 
00907  /// \short Return the position x(i) at previous timestep t 
00908  /// (t=0: present; t>0 previous timestep) (const version)
00909  const double &x(const unsigned &t, const unsigned &i) const 
00910   {
00911 #ifdef RANGE_CHECKING
00912    x_gen_range_check(t,0,i);
00913 #endif
00914    return X_position[Nposition_type*i][t];
00915   }
00916  
00917  /// \short  Return the i-th component of nodal velocity: dx/dt
00918  double dx_dt(const unsigned &i) const;
00919 
00920  /// \short Return the i-th component of j-th derivative of nodal position: 
00921  /// d^jx/dt^j.
00922  double dx_dt(const unsigned &j, const unsigned &i) const;
00923 
00924  ///Return whether any position coordinate has been copied (always false)
00925  virtual bool position_is_a_copy() const {return false;}
00926 
00927  ///Return whether the position coordinate i has been copied (always false)
00928  virtual bool position_is_a_copy(const unsigned &i) const {return false;}
00929 
00930 /// \short Reference to the generalised position x(k,i). 
00931  /// `Type': k; Coordinate direction: i.
00932  double &x_gen(const unsigned &k, const unsigned &i)
00933   {
00934 #ifdef RANGE_CHECKING
00935    x_gen_range_check(0,k,i);
00936 #endif
00937    return X_position[Nposition_type*i + k][0];
00938   }
00939 
00940  /// \short Reference to the generalised position x(k,i). 
00941  /// `Type': k; Coordinate direction: i (const version).
00942  const double &x_gen(const unsigned &k, const unsigned &i) 
00943   const 
00944   {
00945 #ifdef RANGE_CHECKING
00946    x_gen_range_check(0,k,i);
00947 #endif
00948    return X_position[Nposition_type*i + k][0];
00949   }
00950 
00951  /// \short Reference to the generalised position x(k,i) at the previous 
00952  /// timestep [t=0: present].  `Type': k; Coordinate direction: i.
00953  double &x_gen(const unsigned &t, const unsigned &k,
00954                const unsigned &i)
00955   {
00956 #ifdef RANGE_CHECKING
00957    x_gen_range_check(t,k,i);
00958 #endif
00959    return X_position[Nposition_type*i + k][t];
00960   }
00961  
00962  /// \short Reference to the generalised position x(k,i) at the previous 
00963  /// timestep [t=0: present].  `Type': k; Coordinate direction: i.
00964  /// (const version)
00965  const double &x_gen(const unsigned &t, const unsigned &k,
00966                      const unsigned &i) const
00967   {
00968 #ifdef RANGE_CHECKING
00969    x_gen_range_check(t,k,i);
00970 #endif
00971    return X_position[Nposition_type*i + k][t];
00972   }
00973 
00974  /// \short  i-th component of time derivative (velocity) of the 
00975  /// generalised position, dx(k,i)/dt. `Type': k; Coordinate direction: i.
00976  double dx_gen_dt(const unsigned &k, const unsigned &i) const;
00977 
00978 
00979  /// \short  i-th component of j-th time derivative (velocity) of the 
00980  /// generalised position, d^jx(k,i)/dt^j. `Type': k; Coordinate direction: i.
00981  double dx_gen_dt(const unsigned &j, const unsigned &k, 
00982                   const unsigned &i) const;
00983 
00984 /// \short Direct access to the i-th coordinate at time level t 
00985  /// (t=0: present; t>0: previous)
00986  double* x_pt(const unsigned &t, const unsigned &i)
00987   {return &X_position[Nposition_type*i][t];}
00988 
00989  /// Copy all nodal data from specified Node object
00990  void copy(Node* orig_node_pt);
00991 
00992  /// Dump nodal position and associated data to file for restart
00993  virtual void dump(std::ostream& dump_file);
00994 
00995 ///Read nodal position and associated data from file for restart
00996  void read(std::ifstream& restart_file);
00997 
00998  ///\short The pin_all() function must be overloaded by SolidNodes,
00999  ///so we put the virtual interface here to avoid virtual functions in Data
01000  virtual void pin_all() {Data::pin_all();}
01001 
01002  ///\short The unpin_all() function must be overloaded by SolidNode,
01003  ///so we put the virtual interface here to avoid virtual functions in Data
01004  virtual void unpin_all() {Data::unpin_all();}
01005 
01006  /// \short Return pointer to hanging node data (this refers to the geometric
01007  /// hanging node status) (const version).
01008  HangInfo* const &hanging_pt() const
01009   {
01010 #ifdef PARANOID
01011    if (Hanging_pt==0)
01012     {
01013      throw OomphLibError(
01014       "Vector of pointers to hanging data is not setup yet\n",
01015       "Node::hanging_pt()",
01016       OOMPH_EXCEPTION_LOCATION);
01017     }
01018 #endif
01019    return Hanging_pt[0];
01020   }
01021 
01022  /// Return pointer to hanging node data for value i (const version)
01023  HangInfo* const &hanging_pt(const int &i) const
01024   {
01025 #ifdef PARANOID
01026    if(Hanging_pt==0)
01027     {
01028      throw OomphLibError(
01029       "Vector of pointers to hanging data is not setup yet\n",
01030       "Node::hanging_pt()",
01031       OOMPH_EXCEPTION_LOCATION);
01032     }
01033 #endif
01034    return Hanging_pt[i+1]; 
01035   }
01036 
01037  /// Test whether the node is geometrically hanging
01038  bool is_hanging() const
01039   {
01040    if(Hanging_pt==0)
01041     {
01042      return false;
01043     }
01044    else
01045     {
01046      return (Hanging_pt[0]!=0);
01047     }
01048   }
01049  
01050  /// Test whether the i-th value is hanging 
01051  bool is_hanging(const int &i) const
01052   {
01053    //Test whether the node is geometrically hanging
01054    if(i==-1) {return is_hanging();}
01055    //Otherwise, is the i-th value hanging
01056    else
01057     {
01058      if(Hanging_pt==0)
01059       {
01060        return false;
01061       }
01062      else
01063       {
01064        return (Hanging_pt[i+1]!=0);
01065       }
01066     }
01067   }
01068 
01069  /// Set the hanging data for the i-th value.
01070  void set_hanging_pt(HangInfo* const &hang_pt, const int &i);
01071 
01072  /// Label node as non-hanging node by removing all hanging node data.
01073  void set_nonhanging();
01074 
01075  /// \short Constrain the positions when the node is made hanging
01076  /// Empty virtual function that is overloaded in SolidNodes
01077  virtual void constrain_positions() {}
01078 
01079  /// \short Unconstrain the positions when the node is made non-hanging
01080  /// Empty virtual function that is overloaded in SolidNodes
01081  virtual void unconstrain_positions() {}
01082 
01083  /// \short Make the node periodic by copying the values from node_pt. 
01084  /// Note that the coordinates will always remain independent, even
01085  /// though this may lead to (a little) unrequired information being stored.
01086  /// Broken virtual (only implemented in BoundaryNodes)
01087  virtual void make_periodic(Node* const &node_pt);
01088 
01089  /// \short Make the nodes passed in the vector periodic_nodes share the
01090  /// same data as this node.
01091  virtual void make_periodic_nodes(const Vector<Node*> &periodic_nodes_pt);
01092 
01093  /// \short Return a pointer to set of mesh boundaries that this 
01094  /// node occupies; this will be overloaded by BoundaryNodes. The
01095  /// default behaviour is that the Node does not lie on any boundaries
01096  /// so the pointer to the set of boundaries is NULL
01097  virtual void get_boundaries_pt(std::set<unsigned>* &boundaries_pt) 
01098   {boundaries_pt = 0;}
01099  
01100  /// \short Test whether the Node lies on a boundary. The "bulk" Node
01101  /// cannot lie on a boundary, so return false. This will be overloaded
01102  /// by BoundaryNodes
01103  virtual bool is_on_boundary() {return false;}
01104 
01105  /// \short Test whether the node lies on mesh boundary b. The "bulk" Node
01106  /// cannot lie on a boundary, so return false. This will be overloaded by
01107  /// BoundaryNodes
01108  virtual bool is_on_boundary(const unsigned &b) {return false;}
01109 
01110  /// \short Broken interface for adding the node to the mesh boundary b
01111  /// Essentially here for error reporting.
01112  virtual void add_to_boundary(const unsigned &b);
01113 
01114  /// \short Broken interface for removing the node from the mesh boundary b
01115  /// Here to provide error reporting.
01116  virtual void remove_from_boundary(const unsigned &b);
01117 
01118  /// \short Get the number of boundary coordinates on mesh boundary b. 
01119  /// Broken virtual interface provides run-time 
01120  /// error checking
01121  virtual unsigned ncoordinates_on_boundary(const unsigned &b);
01122 
01123  /// \short Return the vector of the k-th generalised boundary coordinates 
01124  /// on mesh boundary b. Broken virtual interface provides run-time 
01125  /// error checking
01126  virtual void get_coordinates_on_boundary(const unsigned &b, const unsigned& k,
01127                                           Vector<double> &boundary_zeta);
01128 
01129  /// \short Set the vector of the k-th generalised boundary coordinates 
01130  /// on mesh boundary b. Broken virtual interface provides run-time error 
01131  /// checking
01132  virtual void set_coordinates_on_boundary(const unsigned &b, const unsigned& k,
01133                                           const Vector<double> &boundary_zeta);
01134 
01135  /// \short Return the vector of coordinates on mesh boundary b
01136  /// Broken virtual interface provides run-time error checking
01137  virtual void get_coordinates_on_boundary(const unsigned &b, 
01138                                           Vector<double> &boundary_zeta)
01139   {
01140    get_coordinates_on_boundary(b,0,boundary_zeta);
01141   }
01142 
01143  /// \short Set the vector of coordinates on mesh boundary b
01144  /// Broken virtual interface provides run-time error checking
01145  virtual void set_coordinates_on_boundary(const unsigned &b,
01146                                           const Vector<double> &boundary_zeta)
01147   {
01148    set_coordinates_on_boundary(b,0,boundary_zeta);
01149   }
01150 
01151 
01152 
01153 
01154 
01155 
01156  /// Mark node as obsolete
01157  void set_obsolete() {Obsolete=true;}
01158 
01159  /// Mark node as non-obsolete
01160  void set_non_obsolete() {Obsolete=false;}
01161 
01162  /// Test whether node is obsolete
01163  bool is_obsolete() {return Obsolete;}
01164 
01165  /// \short Return the i-th value stored at the Node. This interface
01166  /// does NOT take the hanging status of the Node into account.
01167  double raw_value(const unsigned &i) const {return Data::value(i);}
01168  
01169  /// \short Return the i-th value at time level t 
01170  /// (t=0: present, t>0: previous). This interface does NOT take the
01171  /// hanging status of the Node into account.
01172  double raw_value(const unsigned &t, const unsigned &i) const
01173   {return Data::value(t,i);}
01174  
01175  /// \short Return i-th value (dofs or pinned) at this node
01176  /// either directly or via hanging node representation.
01177  /// Note that this REDFINES the interface in Data
01178  /// Thus, the present function will be called 
01179  /// provided that it is accessed through a pointer to a node 
01180  /// i.e. Node* node_pt->value()
01181  /// will take hanging information into account.
01182  /// If a pointer to a Node has been explicitly down-cast to a pointer to
01183  /// Data then the "wrong" (Data) version of the function will be called.
01184  double value(const unsigned &i) const;
01185 
01186  /// \short Return i-th value at time level t (t=0: present, t>0: previous)
01187  /// either directly or via hanging node representation.
01188  /// Note that this REDEFINES the interface in Data
01189  /// Thus, the present function will be called 
01190  /// provided that it is accessed through a pointer to a node 
01191  /// i.e. Node* node_pt->value()
01192  /// will take hanging information into account.
01193  /// If a pointer to a Node has been explicitly down-cast to a pointer to
01194  /// Data then the "wrong" (Data) version of the function will be called.
01195  double value(const unsigned &t, const unsigned &i) const;
01196  
01197  /// \short Compute Vector of values for the Data value 
01198  /// taking the hanging node status into account.
01199  /// Note that this REDEFINES the interface in Data
01200  /// Thus, the present function will be called 
01201  /// provided that it is accessed through a pointer to a node 
01202  /// i.e. Node* node_pt->value()
01203  /// will take hanging information into account.
01204  /// If a pointer to a Node has been explicitly down-cast to a pointer to
01205  /// Data then the "wrong" (Data) version of the function will be called.
01206  void value(Vector<double>& values) const;
01207  
01208  /// \short Compute Vector of values (dofs or pinned) in this data
01209  /// at time level t (t=0: present; t>0: previous). This interface 
01210  /// explicitly takes the hanging status into account.
01211  /// Thus, the present function will be called 
01212  /// provided that it is accessed through a pointer to a node 
01213  /// i.e. Node* node_pt->value()
01214  /// will take hanging information into account.
01215  /// If a pointer to a Node has been explicitly down-cast to a pointer to
01216  /// Data then the "wrong" (Data) version of the function will be called.
01217  void value(const unsigned& t, Vector<double>& values) const;
01218 
01219  /// \short Compute Vector of nodal positions
01220  /// either directly or via hanging node representation
01221  void position(Vector<double>& pos) const;
01222 
01223  /// \short Compute Vector of nodal position at time level t
01224  /// (t=0: current; t>0: previous timestep),
01225  /// either directly or via hanging node representation.
01226  void position(const unsigned &t, Vector<double>& pos) const;
01227 
01228  /// \short Return i-th nodal coordinate
01229  /// either directly or via hanging node representation.
01230  double position(const unsigned &i) const;
01231 
01232  /// \short Return i-th nodal coordinate at time level t
01233  /// (t=0: current; t>0: previous time level),
01234  /// either directly or via hanging node representation.
01235  double position(const unsigned &t, const unsigned &i) const;
01236 
01237  /// \short Return generalised nodal coordinate
01238  /// either directly or via hanging node representation.
01239  double position_gen(const unsigned &k, const unsigned &i) const;
01240 
01241  /// \short Return generalised nodal coordinate at time level t
01242  /// (t=0: current; t>0: previous time level),
01243  /// either directly or via hanging node representation.
01244  double position_gen(const unsigned &t, const unsigned &k,
01245                      const unsigned &i) const;
01246 
01247  /// \short  Return the i-th component of nodal velocity: dx/dt,
01248  /// either directly or via hanging node representation.
01249  double dposition_dt(const unsigned &i) const;
01250 
01251  /// \short Return the i-th component of j-th derivative of nodal position: 
01252  /// d^jx/dt^j either directly or via hanging node representation
01253  double dposition_dt(const unsigned &j, const unsigned &i) const;
01254 
01255  /// \short  i-th component of time derivative (velocity) of the 
01256  /// generalised position, dx(k,i)/dt. `Type': k; Coordinate direction: i.
01257  /// This function uses the hanging node representation if necessary.
01258  double dposition_gen_dt(const unsigned &k, const unsigned &i) const;
01259 
01260 
01261  /// \short  i-th component of j-th time derivative (velocity) of the 
01262  /// generalised position, d^jx(k,i)/dt^j. `Type': k; Coordinate direction: i.
01263  /// This function uses the hanging node representation if necessary
01264  double dposition_gen_dt(const unsigned &j, const unsigned &k, 
01265                          const unsigned &i) const;
01266 
01267  /// \short Interface for functions that update the nodal
01268  /// position using algebraic remeshing strategies. The
01269  /// interface is common to SpineNodes, AlgebraicNodes and
01270  /// MacroElementNodeUpdateNodes.
01271  /// The default is that the node does not "update itself"
01272  /// i.e. it is fixed in space. When implemented, this
01273  /// function should also execute the Node's auxiliary
01274  /// node update function (if any).
01275  virtual void node_update(const bool&
01276                           update_all_time_levels_for_new_node=false) { }
01277 
01278 
01279  /// \short Set pointer to auxiliary update function -- this 
01280  /// can be used to update any nodal values following the update
01281  /// of the nodal position. This is needed e.g. to update the no-slip
01282  /// condition on moving boundaries. 
01283  void set_auxiliary_node_update_fct_pt(AuxNodeUpdateFctPt 
01284                                        aux_node_update_fct_pt) 
01285   {
01286    // Set pointer (by default it's set to NULL)
01287    Aux_node_update_fct_pt=aux_node_update_fct_pt;
01288   }
01289 
01290 
01291 
01292  /// \short Boolean to indicate if node has a pointer to 
01293  /// and auxiliary update function. 
01294  bool has_auxiliary_node_update_fct_pt()
01295   {
01296    return (Aux_node_update_fct_pt!=0);
01297   }
01298 
01299  /// \short Execute auxiliary update function (if any) -- this 
01300  /// can be used to update any nodal values following the update
01301  /// of the nodal position. This is needed e.g. to update the no-slip
01302  /// condition on moving boundaries.
01303  void perform_auxiliary_node_update_fct() 
01304   {
01305    if (Aux_node_update_fct_pt!=0)
01306     {
01307      Aux_node_update_fct_pt(this);
01308     }
01309   }
01310   
01311  /// \short Return the number of geometric data that affect the nodal
01312  /// position. The default value is zero (node is stationary)
01313  virtual inline unsigned ngeom_data() const {return 0;}
01314 
01315  /// \short Return a pointer to an array of all (geometric) data that affect
01316  /// the nodal position. The default value is zero (node is stationary)
01317  virtual inline Data** all_geom_data_pt() {return 0;}
01318 
01319  /// \short Return the number of geometric objects that affect the nodal
01320  /// position. The default value is zero (node is stationary)
01321  virtual inline unsigned ngeom_object() const {return 0;}
01322 
01323  /// \short Return a pointer to an array of all (geometric) objects that affect
01324  /// the nodal position. The default value is zero (node is stationary)
01325  virtual inline GeomObject** all_geom_object_pt() {return 0;}
01326 
01327  ///Output nodal position
01328  void output(std::ostream &outfile); 
01329 
01330 };
01331 
01332 //=====================================================================
01333 /// \short A Class for nodes that deform elastically (i.e. position is an
01334 /// unknown in the problem). The idea is that the Eulerian positions are 
01335 /// stored in a Data object and the Lagrangian coordinates are stored in 
01336 /// addition. The pointer that addresses the Eulerian positions is
01337 /// set to the pointer to Value in the Data object. Hence,
01338 /// SolidNode uses knowledge of the internal structure of Data and
01339 /// must be a friend of the Data class.
01340 /// In order to allow a mesh to deform via an elastic-style
01341 /// equation in deforming-domain problems,  the positions are stored 
01342 /// separately from the values, so that elastic problems may be 
01343 /// combined with any other type of problem. 
01344 //=====================================================================
01345 class SolidNode : public Node
01346 {
01347   private:
01348 
01349  /// \short Private function to check that the arguments to the position 
01350  /// functions are in range
01351  void xi_gen_range_check(const unsigned &k, const unsigned &i) const;
01352 
01353   protected:
01354 
01355  /// Number of Lagrangian coordinates of the node
01356  unsigned Nlagrangian;
01357 
01358  /// \short Number of types of Lagrangian coordinates used to interpolate
01359  /// the Lagrangian coordinates within the element
01360  unsigned Nlagrangian_type;
01361 
01362   /// Pointer to data that will hold variable positions in elastic nodes
01363  Data* Variable_position_pt;
01364 
01365  /// \short Storage for the Lagrangian positions
01366  double *Xi_position;
01367 
01368 public:
01369 
01370  /// \short Default Constructor
01371  SolidNode() : Node() {}
01372 
01373  /// \short Steady constructor. The node has n_lagrangian Lagrangian 
01374  /// coordinates of n_lagrangian_type types (1 for Lagrange elements, 
01375  /// 2 for 1D Hermite etc.).
01376  /// The Eulerian dimension of the Node is n_dim and we have n_position_type
01377  /// (generalised) Eulerian coordinates. There are 
01378  /// initial_n_value values stored at
01379  /// this node.
01380  SolidNode(const unsigned &n_lagrangian, 
01381            const unsigned &n_lagrangian_type,
01382            const unsigned &n_dim, 
01383            const unsigned &n_position_type,
01384            const unsigned &initial_n_value);
01385 
01386  /// \short Unsteady constructor.  
01387  /// Allocates storage for initial_n_value nodal values with history values
01388  /// as required by timestepper.
01389  /// The node has n_lagrangian Lagrangian coordinates of
01390  /// n_lagrangian_type types (1 for Lagrange elements, 2 for 1D Hermite etc.)/
01391  /// The Eulerian dimension of the Node is n_dim and we have n_position_type
01392  /// generalised Eulerian coordinates. 
01393  SolidNode(TimeStepper* const &time_stepper_pt, 
01394              const unsigned &n_lagrangian,
01395              const unsigned &n_lagrangian_type,
01396              const unsigned &n_dim, 
01397              const unsigned &Nposition_type,
01398              const unsigned &initial_n_value);
01399 
01400  ///Destructor that cleans up the additional memory allocated in SolidNodes
01401  virtual ~SolidNode();
01402 
01403  /// Broken copy constructor
01404  SolidNode(const SolidNode& solid_node) 
01405   {
01406    BrokenCopy::broken_copy("SolidNode");
01407   } 
01408  
01409  /// Broken assignment operator
01410  void operator=(const SolidNode&) 
01411   {
01412    BrokenCopy::broken_assign("SolidNode");
01413   }
01414 
01415  /// \short Copy nodal positions and associated data from specified
01416  /// node object
01417  void copy(SolidNode* orig_node_pt);
01418 
01419  /// \short Dump nodal positions (variable and fixed) and associated 
01420  /// data to file for restart
01421  void dump(std::ostream& dump_file);
01422 
01423  /// \short Read nodal positions (variable and fixed) and associated 
01424  /// data from file for restart
01425  void read(std::ifstream& restart_file);
01426 
01427  ///Return the variable_position data (const version)
01428  const Data &variable_position() const {return *Variable_position_pt;}
01429 
01430  ///Pointer to variable_position data (const version)
01431  Data* const &variable_position_pt() const {return Variable_position_pt;}
01432 
01433  ///Set the variable position data from an external data object
01434  void set_external_variable_position_pt(Data* const &data_pt); 
01435 
01436  ///Return whether any position component has been copied
01437  bool position_is_a_copy() const {return Variable_position_pt->is_a_copy();}
01438  
01439  ///Return whether the position coordinate i has been copied
01440  bool position_is_a_copy(const unsigned &i) const
01441   {return Variable_position_pt->is_a_copy(Nposition_type*i);}
01442 
01443  /// \short Return the equation number for generalised Eulerian coordinate:
01444  /// type of coordinate: k, coordinate direction: i. 
01445  const long &position_eqn_number(const unsigned &k, 
01446                                  const unsigned &i) const
01447   {return Variable_position_pt->eqn_number(Nposition_type*i+k);}
01448 
01449  /// Test whether the i-th coordinate is pinned, 0: false; 1: true
01450  bool position_is_pinned(const unsigned &i) 
01451   {return Variable_position_pt->is_pinned(Nposition_type*i);}
01452 
01453  /// \short Test whether the k-th type of the i-th coordinate is pinned 
01454  /// 0: false; 1: true
01455  bool position_is_pinned(const unsigned &k, const unsigned &i)
01456   {return Variable_position_pt->is_pinned(Nposition_type*i+k);}
01457 
01458  /// Pin the nodal position
01459  void pin_position(const unsigned &i) 
01460   {return Variable_position_pt->pin(Nposition_type*i);}
01461 
01462  /// \short Pin the generalised nodal position. 
01463  /// `Type': k; Coordinate direction: i.
01464  void pin_position(const unsigned &k, const unsigned &i)
01465   {return Variable_position_pt->pin(Nposition_type*i+k);}
01466  
01467  /// Unpin the nodal position
01468  void unpin_position(const unsigned &i) 
01469   {return Variable_position_pt->unpin(Nposition_type*i);}
01470 
01471  /// \short Unpin the generalised nodal position. 
01472  /// `Type': k; Coordinate direction: i.
01473  void unpin_position(const unsigned &k, const unsigned &i)
01474   {return Variable_position_pt->unpin(Nposition_type*i+k);}
01475  
01476  /// Pin all the stored variables (Overloaded)
01477  void pin_all()
01478   {
01479    Node::pin_all();
01480    Variable_position_pt->pin_all();
01481   }
01482 
01483  /// Unpin all the stored variables (Overloaded)
01484  void unpin_all()
01485   {
01486    Node::unpin_all();
01487    Variable_position_pt->unpin_all();
01488   }
01489 
01490  /// \short Overload the constrain positions function to constrain all position
01491  /// values
01492  inline void constrain_positions() {Variable_position_pt->constrain_all();}
01493 
01494  /// \short Overload the unconstrain positions function to unconstrain all
01495  /// position values
01496  inline void unconstrain_positions() {Variable_position_pt->unconstrain_all();}
01497 
01498  ///Return number of lagrangian coordinates
01499  unsigned nlagrangian() const {return Nlagrangian;}
01500 
01501  ///\short Number of types of Lagrangian coordinates used to interpolate
01502  /// the Lagrangian coordinates within the element
01503  unsigned nlagrangian_type() const {return Nlagrangian_type;}
01504 
01505  /// Reference to i-th Lagrangian position
01506  double &xi(const unsigned &i) 
01507   {
01508 #ifdef RANGE_CHECKING
01509    xi_gen_range_check(0,i);
01510 #endif
01511    return Xi_position[Nlagrangian_type*i];
01512   }
01513 
01514  /// Reference to i-th Lagrangian position (const version)
01515  const double &xi(const unsigned &i) const 
01516   {
01517 #ifdef RANGE_CHECKING
01518    xi_gen_range_check(0,i);
01519 #endif
01520    return Xi_position[Nlagrangian_type*i];
01521   }
01522 
01523  /// \short Reference to the generalised Lagrangian position.
01524  /// `Type': k; 'Coordinate direction: i.
01525  double &xi_gen(const unsigned &k, const unsigned &i)
01526   {
01527 #ifdef RANGE_CHECKING
01528    xi_gen_range_check(k,i);
01529 #endif
01530    return Xi_position[Nlagrangian_type*i + k];
01531   }
01532 
01533  /// \short Reference to the generalised Lagrangian position.
01534  /// `Type': k; 'Coordinate direction: i. (const version
01535  const double &xi_gen(const unsigned &k, const unsigned &i) const
01536   {
01537 #ifdef RANGE_CHECKING
01538    xi_gen_range_check(k,i);
01539 #endif
01540    return Xi_position[Nlagrangian_type*i + k];
01541   }
01542  
01543  ///\short Return lagrangian coordinate either directly or via
01544  ///hanging node representation
01545  double lagrangian_position(const unsigned &i) const;
01546 
01547  ///\short Return generalised lagrangian coordinate either directly or via
01548  ///hanging node representation
01549  double lagrangian_position_gen(const unsigned &k, const unsigned &i)
01550   const;
01551 
01552  ///Overload the assign equation numbers routine
01553  void assign_eqn_numbers(unsigned long &global_number, 
01554                                  Vector<double *> &dof_pt);
01555 
01556  /// \short Overload node update function: Since the position 
01557  /// of SolidNodes is determined by unknowns, there's nothing
01558  /// to be done apart from performing the auxiliary node
01559  /// update function (if any)
01560  void node_update(const bool& update_all_time_levels_for_new_node=false)
01561   {
01562    perform_auxiliary_node_update_fct();
01563   }
01564 
01565 };
01566 
01567 
01568 
01569 //======================================================================
01570 /// \short A class that contains the information required by Nodes that
01571 /// are located on Mesh boundaries. A BoundaryNode of a particular type
01572 /// is obtained by combining a given Node with this class. 
01573 /// By differentiating between Nodes and BoundaryNodes we avoid a lot
01574 /// of un-necessary storage in the bulk Nodes.
01575 //======================================================================
01576 class BoundaryNodeBase
01577 {
01578  private:
01579  /// \short Pointer to a map,  
01580  /// indexed by the face element identifier it returns
01581  /// the position of the first face element value.
01582  /// If the Node does not lie on a face element 
01583  /// this map should never be queried.
01584  std::map<unsigned, unsigned>* Index_of_first_value_assigned_by_face_element_pt;
01585 
01586  /// \short Pointer to a map of pointers to 
01587  /// intrinsic boundary coordinates of the Node,
01588  /// indexed by the boundary number. If the Node does not lie
01589  /// on a boundary this map should never be queried because
01590  /// unnecessary storage will then be allocated. Hence, it
01591  /// can only be accessed via the appropriate set and get functions.
01592  std::map<unsigned, DenseMatrix<double>*>* Boundary_coordinates_pt;
01593   
01594  /// \short Pointer to set of mesh boundaries occupied by the Node; 
01595  /// NULL if the Node is not on any boundaries 
01596  std::set<unsigned>* Boundaries_pt;
01597  
01598   protected:
01599  
01600  /// \short If the BoundaryNode is periodic, this pointer is set to
01601  /// the BoundaryNode whose data it shares
01602  Node* Copied_node_pt;
01603  
01604  /// \short Helper function that is used to turn BoundaryNodes into
01605  /// peridic boundary nodes by setting the data values of
01606  /// copied_node_pt to those of original_node_pt. 
01607  void make_node_periodic(Node* const &node_pt, 
01608                          Node* const &original_node_pt);
01609 
01610  /// \short Helper function that is used to turn BoundaryNodes into
01611  /// periodic boundary nodes by setting the data values of the nodes
01612  /// in the vector periodic_copies_pt to be the same as those
01613  /// in node_pt.
01614  void make_nodes_periodic(Node* const &node_pt,
01615                           Vector<Node*> const &periodic_copies_pt);
01616 
01617  public:
01618 
01619 
01620  /// \short Return pointer to the map giving
01621  /// the index of the first face element value.
01622  std::map<unsigned, unsigned>* &index_of_first_value_assigned_by_face_element_pt()
01623   {
01624    return Index_of_first_value_assigned_by_face_element_pt;
01625   }
01626 
01627  /// \short Return the index of the first value associated with
01628  /// the i-th face element value. If no argument is specified
01629  /// we return the index associated with the first (and assumed to be only)
01630  /// face element attached to this node. 
01631  unsigned index_of_first_value_assigned_by_face_element(const unsigned& face_id=0) const
01632   {
01633 #ifdef PARANOID
01634    if (Index_of_first_value_assigned_by_face_element_pt==0)
01635     {
01636      std::ostringstream error_message;
01637      error_message 
01638       << "Index_of_first_value_assigned_by_face_element_pt==0;\n"
01639       << "Pointer must be set via call to: \n\n"
01640       << "  BoundaryNode::index_of_first_value_assigned_by_face_element_pt(), \n\n" 
01641       << "typically from FaceElement::add_additional_values(...).";
01642       throw OomphLibError(error_message.str(),
01643                           "BoundaryNode::index_of_first_value_assigned_by_face_element()",
01644                           OOMPH_EXCEPTION_LOCATION);
01645     }
01646 #endif
01647    return (*Index_of_first_value_assigned_by_face_element_pt)[face_id];
01648   }
01649  
01650  /// \short Default constructor, set the pointers to the storage to NULL
01651   BoundaryNodeBase() :  Index_of_first_value_assigned_by_face_element_pt(0), 
01652   Boundary_coordinates_pt(0), 
01653   Boundaries_pt(0), Copied_node_pt(0) {}
01654  
01655  /// \short Destructor, clean up any allocated storage for the boundaries
01656  ~BoundaryNodeBase();
01657  
01658  /// Broken copy constructor
01659  BoundaryNodeBase(const BoundaryNodeBase& boundary_node_base) 
01660   { BrokenCopy::broken_copy("BoundaryNodeBase");} 
01661  
01662  /// Broken assignment operator
01663  void operator=(const BoundaryNodeBase&) 
01664   {BrokenCopy::broken_assign("BoundaryNodeBase");}
01665 
01666  /// \short Access to pointer to set of mesh boundaries that this 
01667  /// node occupies; NULL if the node is not on any boundary
01668  void get_boundaries_pt(std::set<unsigned>* &boundaries_pt) 
01669   {boundaries_pt = Boundaries_pt;}
01670 
01671  /// \short Add the node to the mesh boundary b
01672  void add_to_boundary(const unsigned &b);
01673 
01674  /// \short Remove the node from the mesh boundary b
01675  void remove_from_boundary(const unsigned &b);
01676 
01677  /// \short Test whether the node lies on a boundary
01678  bool is_on_boundary() {return (!Boundaries_pt==0);}
01679 
01680  /// \short Test whether the node lies on mesh boundary b
01681  bool is_on_boundary(const unsigned &b);
01682 
01683  /// \short Get the number of boundary coordinates on mesh boundary b
01684  unsigned ncoordinates_on_boundary(const unsigned &b);
01685 
01686  /// \short Return the vector of boundary coordinates on mesh boundary b
01687  void get_coordinates_on_boundary(const unsigned &b, 
01688                                   Vector<double> &boundary_zeta)
01689   {
01690    // Just return the zero-th one
01691    get_coordinates_on_boundary(b,0,boundary_zeta);
01692   }
01693   
01694 
01695  /// \short Set the vector of boundary coordinates on mesh boundary b
01696  void set_coordinates_on_boundary(const unsigned &b,
01697                                   const Vector<double> &boundary_zeta)
01698   {
01699    // Just do the zero-th one
01700    set_coordinates_on_boundary(b,0,boundary_zeta);
01701   }
01702 
01703  /// \short Return the vector of the k-th generalised boundary coordinates 
01704  /// on mesh boundary b.
01705  void get_coordinates_on_boundary(const unsigned &b, const unsigned& k,
01706                                   Vector<double> &boundary_zeta);
01707 
01708  /// \short Set the vector of the k-th generalised boundary coordinates on 
01709  /// mesh boundary b.
01710  void set_coordinates_on_boundary(const unsigned &b, const unsigned& k,
01711                                   const Vector<double> &boundary_zeta);
01712 
01713 };
01714 
01715 
01716 //====================================================================
01717 /// \short A template Class for BoundaryNodes; that is Nodes that MAY live
01718 /// on the boundary of a Mesh. The class is formed by a simple
01719 /// composition of the template parameter NODE_TYPE, which must be 
01720 /// a Node class and the BoundaryNodeBase class. 
01721 /// Final overloading of functions is always in favour of the 
01722 /// BoundaryNodeBase implementation; i.e. these nodes can live on 
01723 /// boundaries.
01724 //===================================================================
01725 template<class NODE_TYPE>
01726 class BoundaryNode: public NODE_TYPE, public BoundaryNodeBase
01727 {
01728   private:
01729 
01730  /// \short Set pointers to the copied data used when we have periodic nodese
01731  void reset_copied_pointers()
01732   {
01733 #ifdef PARANOID
01734    if(Copied_node_pt==0)
01735     {
01736      throw OomphLibError("BoundaryNode has not been copied",
01737                          "BoundaryNode::reset_copied_pointers()",
01738                          OOMPH_EXCEPTION_LOCATION);
01739     }
01740 #endif
01741    this->Value = Copied_node_pt->Value;
01742    this->Eqn_number_pt = Copied_node_pt->Eqn_number_pt;
01743    //We don't yet need to worry about updating position pointers
01744   }
01745 
01746  /// \short Clear pointers to the copied data used when we have periodic nodes
01747  /// Simply zero the pointers to the memory rather than deleting them
01748  void clear_copied_pointers()
01749   {
01750 #ifdef PARANOID
01751    if(Copied_node_pt==0)
01752     {
01753      throw OomphLibError("BoundaryNode has not been copied",
01754                          "BoundaryNode::clear_copied_pointers()",
01755                          OOMPH_EXCEPTION_LOCATION);
01756     }
01757 #endif
01758    Copied_node_pt=0;
01759    this->Value=0;
01760    this->Eqn_number_pt=0;
01761   }
01762 
01763 
01764   public:
01765  
01766  /// \short Default Constructor
01767  BoundaryNode() : NODE_TYPE(), BoundaryNodeBase() { }
01768 
01769  /// \short Steady constructor, for a BoundaryNode of spatial dimension n_dim. 
01770  /// Simply passes all arguments through to the underlying Node constructor
01771  /// which allocates storage for initial_n_value values.
01772  /// NPosition_type is the number of coordinate types 
01773  /// needed in the mapping between local and global coordinates 
01774  /// (e.g. 1 for Lagrange-type elements; 2 for 1D Hermite elements; 4 for
01775  /// 2D Hermite elements, etc). 
01776  BoundaryNode(const unsigned &n_dim, const unsigned &n_position_type,
01777               const unsigned &initial_n_value) :
01778   NODE_TYPE(n_dim,n_position_type,initial_n_value), BoundaryNodeBase() { }
01779 
01780  /// \short Unsteady constructor for a BoundaryNode 
01781  /// of spatial dimension n_dim. Simply passes all arguments through to
01782  /// the underlygin Node constructor which
01783  /// allocates storage for initial_n_value values with 
01784  /// history values as required by the timestepper. 
01785  /// n_position_type: # of coordinate 
01786  /// types needed in the mapping between local and global coordinates  
01787  /// (e.g. 1 for Lagrange-type elements; 2 for 1D Hermite elements; 4 for 
01788  /// 2D Hermite elements).
01789  BoundaryNode(TimeStepper* const &time_stepper_pt, const unsigned &n_dim, 
01790               const unsigned &n_position_type, 
01791               const unsigned &initial_n_value) :
01792   NODE_TYPE(time_stepper_pt,n_dim,n_position_type,initial_n_value),
01793   BoundaryNodeBase() { }
01794  
01795  /// \short Steady constructor for Solid-type boundary nodes. 
01796  /// The node has n_lagrangian Lagrangian 
01797  /// coordinates of n_lagrangian_type types (1 for Lagrange elements, 
01798  /// 2 for 1D Hermite etc.).
01799  /// The Eulerian dimension of the Node is n_dim and we have n_position_type
01800  /// (generalised) Eulerian coordinates. There are 
01801  /// initial_n_value values stored at
01802  /// this node.
01803  BoundaryNode(const unsigned &n_lagrangian, 
01804               const unsigned &n_lagrangian_type,
01805               const unsigned &n_dim, 
01806               const unsigned &n_position_type,
01807               const unsigned &initial_n_value) :
01808   NODE_TYPE(n_lagrangian,n_lagrangian_type,n_dim,n_position_type,
01809             initial_n_value), BoundaryNodeBase() {}
01810  
01811  /// \short Unsteady constructor for Solid-type boundary nodes
01812  /// Allocates storage for initial_n_value nodal values with history values
01813  /// as required by timestepper.
01814  /// The node has n_lagrangian Lagrangian coordinates of
01815  /// n_lagrangian_type types (1 for Lagrange elements, 2 for 1D Hermite etc.)/
01816  /// The Eulerian dimension of the Node is n_dim and we have n_position_type
01817  /// generalised Eulerian coordinates.
01818  BoundaryNode(TimeStepper* const &time_stepper_pt, 
01819               const unsigned &n_lagrangian,
01820               const unsigned &n_lagrangian_type,
01821               const unsigned &n_dim, 
01822               const unsigned &n_position_type,
01823               const unsigned &initial_n_value)
01824    : NODE_TYPE(time_stepper_pt,n_lagrangian,n_lagrangian_type,n_dim,
01825                n_position_type,initial_n_value),
01826   BoundaryNodeBase() {}
01827  
01828  /// \short Destructor resets pointers if 
01829  ~BoundaryNode() 
01830   {
01831    //If the node was periodic then clear the pointers before deleting
01832    if(Copied_node_pt)
01833     {
01834      //Inform the node that the copy is being deleted
01835      //If the original has been deleted Copied_node_pt will be NULL
01836      Copied_node_pt->remove_copy(this);
01837      Copied_node_pt=0;
01838      this->Value=0;
01839      this->Eqn_number_pt=0;
01840     }
01841   }
01842 
01843  /// Broken copy constructor
01844  BoundaryNode(const BoundaryNode<NODE_TYPE>& node) 
01845   { 
01846    BrokenCopy::broken_copy("BouandryNode");
01847   } 
01848  
01849  /// Broken assignment operator
01850  void operator=(const BoundaryNode<NODE_TYPE>&) 
01851   {
01852    BrokenCopy::broken_assign("BoundaryNode");
01853   }
01854 
01855  /// \short Access to pointer to set of mesh boundaries that this 
01856  /// node occupies; NULL if the node is not on any boundary
01857  /// Final overload
01858  void get_boundaries_pt(std::set<unsigned>* &boundaries_pt) 
01859   {BoundaryNodeBase::get_boundaries_pt(boundaries_pt);}
01860 
01861  /// \short Test whether the node lies on a boundary
01862  /// Final overload
01863  bool is_on_boundary() {return BoundaryNodeBase::is_on_boundary();}
01864  
01865  /// \short Test whether the node lies on mesh boundary b
01866  /// Final overload
01867  bool is_on_boundary(const unsigned &b) 
01868   {return BoundaryNodeBase::is_on_boundary(b);}
01869 
01870  /// \short Add the node to mesh boundary b, final overload
01871  void add_to_boundary(const unsigned &b)
01872   {BoundaryNodeBase::add_to_boundary(b);}
01873 
01874  /// \short Remover the node from mesh boundary b, final overload
01875  void remove_from_boundary(const unsigned &b)
01876   {BoundaryNodeBase::remove_from_boundary(b);}
01877 
01878 
01879  /// \short Get the number of boundary coordinates on mesh boundary b. 
01880  unsigned ncoordinates_on_boundary(const unsigned &b)
01881   {
01882    return BoundaryNodeBase::ncoordinates_on_boundary(b);
01883   }
01884 
01885 
01886  /// \short Return the vector of coordinates on mesh boundary b
01887  /// Final overload
01888  void get_coordinates_on_boundary(const unsigned &b, 
01889                                   Vector<double> &boundary_zeta)
01890   {BoundaryNodeBase::get_coordinates_on_boundary(b,boundary_zeta);}
01891 
01892  /// \short Set the vector of coordinates on mesh boundary b
01893  /// Final overload
01894  void set_coordinates_on_boundary(const unsigned &b,
01895                                   const Vector<double> &boundary_zeta)
01896   {BoundaryNodeBase::set_coordinates_on_boundary(b,boundary_zeta);}
01897 
01898 
01899  /// \short Return the vector of k-th generalised boundary coordinates 
01900  /// on mesh boundary b Final overload
01901  void get_coordinates_on_boundary(const unsigned &b, const unsigned& k,
01902                                   Vector<double> &boundary_zeta)
01903   {BoundaryNodeBase::get_coordinates_on_boundary(b,k,boundary_zeta);}
01904 
01905  /// \short Set the vector of k-th generalised boundary coordinates 
01906  /// on mesh boundary b. Final overload
01907  void set_coordinates_on_boundary(const unsigned &b, const unsigned& k,
01908                                   const Vector<double> &boundary_zeta)
01909   {BoundaryNodeBase::set_coordinates_on_boundary(b,k,boundary_zeta);}
01910 
01911 
01912 
01913  /// \short Make the node periodic
01914  void make_periodic(Node* const &node_pt)
01915   {BoundaryNodeBase::make_node_periodic(this,node_pt);}
01916 
01917  /// \short Make the nodes passed in periodic_nodes periodic from 
01918  /// this node
01919  void make_periodic_nodes(const Vector<Node*> &periodic_nodes_pt)
01920   {BoundaryNodeBase::make_nodes_periodic(this,periodic_nodes_pt);}
01921 
01922  /// \short Return a boolean to indicate whether the data contains 
01923  /// any copied values. If the node is periodic all values are copied
01924  bool is_a_copy() const 
01925   {if(Copied_node_pt) {return true;} else{return false;}}
01926  
01927  /// \short Return a boolean to indicate whether
01928  /// the i-th value is a copied value.
01929  /// If the node is periodic all values are copies
01930  bool is_a_copy(const unsigned &i) const 
01931   {if(Copied_node_pt) {return true;} else{return false;}}
01932 
01933   /// \short Overload the equation assignment operation
01934  void assign_eqn_numbers(unsigned long &global_ndof, 
01935                          Vector<double *> &dof_pt)
01936   {
01937    //If the boundary node is not periodic call the ususal
01938    //assign equation numbers
01939    if(Copied_node_pt==0) 
01940     {NODE_TYPE::assign_eqn_numbers(global_ndof,dof_pt);}
01941    //Otherwise make sure that we assign equation numbers for
01942    //the variable position pointer of the solid node
01943    else
01944     {
01945      //Is it a solid node?
01946      SolidNode* solid_node_pt = dynamic_cast<SolidNode*>(this);
01947      if(solid_node_pt)
01948       {
01949        //If so we must let the variable position pointer take care of
01950        //itself
01951        solid_node_pt->variable_position_pt()
01952         ->assign_eqn_numbers(global_ndof,dof_pt);
01953       }
01954     }
01955   }
01956 
01957 
01958  /// \short Resize the number of equations
01959  void resize(const unsigned &n_value) 
01960   {
01961    //If the node is periodic, warn, but do nothing
01962    if(Copied_node_pt) 
01963     {
01964 #ifdef PARANOID
01965      unsigned n_value_new = Copied_node_pt->nvalue();
01966      //Check that we have already resized the original
01967      if(n_value_new != n_value)
01968       {
01969        std::ostringstream error_stream;
01970        error_stream 
01971         << "Call to resize copied node before original has been resized!"
01972         << std::endl;
01973        throw OomphLibError(error_stream.str(),
01974                            "Data::resize()",
01975                            OOMPH_EXCEPTION_LOCATION);
01976       }
01977 #endif
01978     }
01979    //Otherwise call the underlying function
01980    else
01981     {
01982      NODE_TYPE::resize(n_value);
01983     }
01984   }
01985 
01986  
01987 
01988 
01989 };
01990 
01991 
01992 
01993 }
01994 
01995 #endif

Generated on Mon Aug 10 11:23:48 2009 by  doxygen 1.4.7