action functions
|
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 if you wish to be informed of the library's "official" release. |
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
1.4.7