elements.h
Go to the documentation of this file.
1 //LIC// ====================================================================
2 //LIC// This file forms part of oomph-lib, the object-oriented,
3 //LIC// multi-physics finite-element library, available
4 //LIC// at http://www.oomph-lib.org.
5 //LIC//
6 //LIC// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 //Header file for classes that define element objects
31 
32 //Include guard to prevent multiple inclusions of the header
33 #ifndef OOMPH_GENERIC_ELEMENTS_HEADER
34 #define OOMPH_GENERIC_ELEMENTS_HEADER
35 
36 // Config header generated by autoconfig
37 #ifdef HAVE_CONFIG_H
38  #include <oomph-lib-config.h>
39 #endif
40 
41 #include <map>
42 #include <deque>
43 #include<string>
44 #include <list>
45 
46 //oomph-lib includes
47 #include "integral.h"
48 #include "nodes.h"
49 #include "geom_objects.h"
50 
51 namespace oomph
52 {
53  //Forward definition for time
54  class Time;
55 
56 
57 //========================================================================
58 /// \short A Generalised Element class.
59 ///
60 /// The main components of a GeneralisedElement are:
61 /// - pointers to its internal and external Data, which are stored together
62 /// in a single array so that we need only store one pointer.
63 /// The internal Data are placed at the beginning
64 /// of the array and the external Data are stored at the end.
65 /// - a pointer to a global Time
66 /// - a lookup table that establishes the relation between local
67 /// and global equation numbers.
68 ///
69 /// We also provide interfaces for functions that compute the
70 /// element's Jacobian matrix and/or the Vector of residuals.
71 /// In addition, an interface that returns a mass matrix --- the matrix
72 /// of terms that multiply any time derivatives in the problem --- is
73 /// also provided to permit explicit time-stepping and the solution
74 /// of the generalised eigenproblems.
75 //========================================================================
77 {
78  private:
79 
80  /// \short Storage for the global equation numbers represented by the
81  /// degrees of freedom in the element.
82  unsigned long *Eqn_number;
83 
84  /// \short Storage for array of pointers to degrees of freedom ordered
85  /// by local equation number. This information is not needed, except in
86  /// continuation, bifurcation tracking and periodic orbit calculations.
87  /// It is not set up unless the control flag
88  /// Problem::Store_local_dof_pts_in_elements = true
89  double **Dof_pt;
90 
91  /// \short Storage for pointers to internal and external data.
92  /// The data is of the same type and so can be addressed by
93  /// a single pointer. The idea is that the array is of
94  /// total size Ninternal_data + Nexternal_data.
95  /// The internal data are stored at the beginning of the array
96  /// and the external data are stored at the end of the array.
98 
99  /// \short Pointer to array storage for local equation numbers associated
100  /// with internal and external data. Again, we save storage by using
101  /// a single pointer to access this information. The first index of the
102  /// array is of dimension Nineternal_data + Nexternal_data and the second
103  /// index varies with the number of values stored at the data object.
104  /// In the most general case, however, the scheme is as memory efficient
105  /// as possible.
107 
108  /// Number of degrees of freedom
109  unsigned Ndof;
110 
111  /// Number of internal data
112  unsigned Ninternal_data;
113 
114  /// Number of external data
115  unsigned Nexternal_data;
116 
117  /// \short Storage for boolean flags of size Ninternal_data + Nexternal_data
118  /// that correspond to the data used in the element. The flags
119  /// indicate whether the particular
120  /// internal or external data should be included in the general
121  /// finite-difference loop in fill_in_jacobian_from_internal_by_fd() or
122  /// fill_in_jacobian_from_external_by_fd(). The default is that all
123  /// data WILL be included in the finite-difference loop, but in many
124  /// circumstances it is possible to treat certain (external) data
125  /// analytically. The use of an STL vector is optimal for memory
126  /// use because the booleans are represented as single-bits.
127  std::vector<bool> Data_fd;
128 
129  protected:
130 
131 #ifdef OOMPH_HAS_MPI
132 
133  /// \short Non-halo processor ID for Data; -1 if it's not a halo.
135 
136  /// Does this element need to be kept as a halo element during a distribute?
138 
139 #endif
140 
141  /// \short Add a (pointer to an) internal data object to the element and
142  /// return the index required to obtain it from the access
143  /// function \c internal_data_pt(). The boolean indicates whether
144  /// the datum should be included in the general finite-difference loop
145  /// when calculating the jacobian. The default value is true, i.e.
146  /// the data will be included in the finite differencing.
147  unsigned add_internal_data(Data* const &data_pt, const bool &fd=true);
148 
149 
150  /// \short Return the status of the boolean flag indicating whether
151  /// the internal data is included in the finite difference loop
152  inline bool internal_data_fd(const unsigned &i) const
153  {
154 #ifdef RANGE_CHECKING
155  if(i >= Ninternal_data)
156  {
157  std::ostringstream error_message;
158  error_message << "Range Error: Internal data " << i
159  << " is not in the range (0,"
160  << Ninternal_data-1 << ")";
161  throw OomphLibError(error_message.str(),
162  OOMPH_CURRENT_FUNCTION,
163  OOMPH_EXCEPTION_LOCATION);
164  }
165 #endif
166  //Return the value
167  return Data_fd[i];
168  }
169 
170 
171  /// \short Set the boolean flag to exclude the internal datum from
172  /// the finite difference loop when computing the jacobian matrix
173  inline void exclude_internal_data_fd(const unsigned &i)
174  {
175 #ifdef RANGE_CHECKING
176  if(i >= Ninternal_data)
177  {
178  std::ostringstream error_message;
179  error_message << "Range Error: Internal data " << i
180  << " is not in the range (0,"
181  << Ninternal_data-1 << ")";
182  throw OomphLibError(error_message.str(),
183  OOMPH_CURRENT_FUNCTION,
184  OOMPH_EXCEPTION_LOCATION);
185  }
186 #endif
187  //Set the value
188  Data_fd[i] = false;
189  }
190 
191  /// \short Set the boolean flag to include the internal datum in
192  /// the finite difference loop when computing the jacobian matrix
193  inline void include_internal_data_fd(const unsigned &i)
194  {
195 #ifdef RANGE_CHECKING
196  if(i >= Ninternal_data)
197  {
198  std::ostringstream error_message;
199  error_message << "Range Error: Internal data " << i
200  << " is not in the range (0,"
201  << Ninternal_data-1 << ")";
202  throw OomphLibError(error_message.str(),
203  OOMPH_CURRENT_FUNCTION,
204  OOMPH_EXCEPTION_LOCATION);
205  }
206 #endif
207  //Set the value
208  Data_fd[i] = true;
209  }
210 
211  /// \short Clear the storage for the global equation numbers
212  /// and pointers to dofs (if stored)
214  {delete[] Eqn_number; Eqn_number=0; delete[] Dof_pt; Dof_pt=0; Ndof=0;}
215 
216  /// \short Add the contents of the queue global_eqn_numbers
217  /// to the local storage for the local-to-global translation scheme.
218  /// It is essential that the entries in the queue are added IN ORDER
219  /// i.e. from the front.
220  void add_global_eqn_numbers(std::deque<unsigned long>
221  const &global_eqn_numbers,
222  std::deque<double*>
223  const &global_dof_pt);
224 
225  /// \short Empty dense matrix used as a dummy argument to combined
226  /// residual and jacobian functions in the case when only the residuals
227  /// are being assembled
229 
230  /// \short Static storage for deque used to add_global_equation_numbers
231  /// when pointers to the dofs in each element are not required
232  static std::deque<double*> Dof_pt_deque;
233 
234  /// \short Assign the local equation numbers for the internal
235  /// and external Data
236  /// This must be called after the global equation numbers have all been
237  /// assigned. It is virtual so that it can be overloaded by
238  /// ElementWithExternalElements so that any external data from the
239  /// external elements in included in the numbering scheme.
240  /// If the boolean argument is true then pointers to the dofs will be
241  /// stored in Dof_pt
243  const bool &store_local_dof_pt);
244 
245  /// \short Assign all the local equation numbering schemes that can
246  /// be applied generically for the element. In most cases, this is the
247  /// function that will be overloaded by inherited classes. It is required
248  /// to ensure that assign_additional_local_eqn_numbers() can always be
249  /// called after ALL other local equation numbering has been performed.
250  /// The default for the GeneralisedElement is simply to call internal
251  /// and external local equation numbering.
252  /// If the boolean argument is true then pointers to the dofs will be stored
253  /// in Dof_pt
255  const bool &store_local_dof_pt)
256  {
257  this->assign_internal_and_external_local_eqn_numbers(store_local_dof_pt);
258  }
259 
260  /// \short Setup any additional look-up schemes for local equation numbers.
261  /// Examples of use include using local storage to refer to explicit
262  /// degrees of freedom. The additional memory cost of such storage may
263  /// or may not be offset by fast local access.
265 
266  /// \short Return the local equation number corresponding to the j-th
267  /// value stored at the i-th internal data
268  inline int internal_local_eqn(const unsigned &i, const unsigned &j) const
269  {
270 #ifdef RANGE_CHECKING
271  if(i >= Ninternal_data)
272  {
273  std::ostringstream error_message;
274  error_message << "Range Error: Internal data " << i
275  << " is not in the range (0,"
276  << Ninternal_data-1 << ")";
277  throw OomphLibError(error_message.str(),
278  OOMPH_CURRENT_FUNCTION,
279  OOMPH_EXCEPTION_LOCATION);
280  }
281  else
282  {
283  unsigned n_value = internal_data_pt(i)->nvalue();
284  if(j >= n_value)
285  {
286  std::ostringstream error_message;
287  error_message << "Range Error: value " << j << " at internal data "
288  << i
289  << " is not in the range (0,"
290  << n_value -1 << ")";
291  throw OomphLibError(error_message.str(),
292  OOMPH_CURRENT_FUNCTION,
293  OOMPH_EXCEPTION_LOCATION);
294  }
295  }
296 #endif
297  //Check that the data has been allocated
298 #ifdef PARANOID
299  if(Data_local_eqn==0)
300  {
301  throw OomphLibError(
302  "Internal local equation numbers have not been allocated",
303  OOMPH_CURRENT_FUNCTION,
304  OOMPH_EXCEPTION_LOCATION);
305  }
306 #endif
307  //Return the local equation number as stored in the Data_local_eqn array
308  return Data_local_eqn[i][j];
309  }
310 
311  /// \short Return the local equation number corresponding to the j-th
312  /// value stored at the i-th external data
313  inline int external_local_eqn(const unsigned &i, const unsigned &j)
314  {
315  //Check that the data has been allocated
316 #ifdef RANGE_CHECKING
317  if(i >= Nexternal_data)
318  {
319  std::ostringstream error_message;
320  error_message << "Range Error: External data " << i
321  << " is not in the range (0,"
322  << Nexternal_data-1 << ")";
323  throw OomphLibError(error_message.str(),
324  OOMPH_CURRENT_FUNCTION,
325  OOMPH_EXCEPTION_LOCATION);
326  }
327  else
328  {
329  unsigned n_value = external_data_pt(i)->nvalue();
330  if(j >= n_value)
331  {
332  std::ostringstream error_message;
333  error_message << "Range Error: value " << j << " at internal data "
334  << i
335  << " is not in the range (0,"
336  << n_value -1 << ")";
337  throw OomphLibError(error_message.str(),
338  OOMPH_CURRENT_FUNCTION,
339  OOMPH_EXCEPTION_LOCATION);
340  }
341  }
342 #endif
343 #ifdef PARANOID
344  if(Data_local_eqn==0)
345  {
346  throw OomphLibError(
347  "External local equation numbers have not been allocated",
348  OOMPH_CURRENT_FUNCTION,
349  OOMPH_EXCEPTION_LOCATION);
350  }
351 #endif
352  //Return the local equation number stored as the j-th value of the
353  //i-th external data object.
354  return Data_local_eqn[Ninternal_data +i][j];
355  }
356 
357  /// \short Add the elemental contribution to the residuals vector. Note that
358  /// this function will NOT initialise the residuals vector. It must be
359  /// called after the residuals vector has been initialised to zero.
361  {
362  std::string error_message =
363  "Empty fill_in_contribution_to_residuals() has been called.\n";
364  error_message +=
365  "This function is called from the default implementations of\n";
366  error_message +=
367  "get_residuals() and get_jacobian();\n";
368  error_message +=
369  "and must calculate the residuals vector without initialising any of ";
370  error_message += "its entries.\n\n";
371 
372  error_message +=
373  "If you do not wish to use these defaults, you must overload both\n";
374  error_message +=
375  "get_residuals() and get_jacobian(), which must initialise the entries\n";
376  error_message +=
377  "of the residuals vector and jacobian matrix to zero.\n";
378 
379  error_message +=
380  "N.B. the default get_jacobian() function employs finite differencing\n";
381 
382  throw OomphLibError(error_message,
383  OOMPH_CURRENT_FUNCTION,
384  OOMPH_EXCEPTION_LOCATION);
385  }
386 
387  /// \short Calculate the contributions to the jacobian from the internal
388  /// degrees of freedom using finite differences.
389  /// This version of the function assumes that the residuals vector has
390  /// already been calculated. If the boolean argument is true, the finite
391  /// differencing will be performed for all internal data, irrespective of
392  /// the information in Data_fd. The default value (false)
393  /// uses the information in Data_fd to selectively difference only
394  /// certain data.
396  DenseMatrix<double> &jacobian,
397  const bool &fd_all_data=false);
398 
399  /// \short Calculate the contributions to the jacobian from the internal
400  /// degrees of freedom using finite differences. This version computes
401  /// the residuals vector before calculating the jacobian terms.
402  /// If the boolean argument is true, the finite
403  /// differencing will be performed for all internal data, irrespective of
404  /// the information in Data_fd. The default value (false)
405  /// uses the information in Data_fd to selectively difference only
406  /// certain data.
408  const bool &fd_all_data=false)
409  {
410  //Allocate storage for the residuals
411  Vector<double> residuals(Ndof,0.0);
412  //Get the residuals for the entire element
413  get_residuals(residuals);
414  //Call the jacobian calculation
415  fill_in_jacobian_from_internal_by_fd(residuals,jacobian,fd_all_data);
416  }
417 
418 
419  /// \short Calculate the contributions to the jacobian from the external
420  /// degrees of freedom using finite differences.
421  /// This version of the function assumes that the residuals vector has
422  /// already been calculated.
423  /// If the boolean argument is true, the finite
424  /// differencing will be performed for all external data, irrespective of
425  /// the information in Data_fd. The default value (false)
426  /// uses the information in Data_fd to selectively difference only
427  /// certain data.
429  DenseMatrix<double> &jacobian,
430  const bool &fd_all_data=false);
431 
432 
433  /// \short Calculate the contributions to the jacobian from the external
434  /// degrees of freedom using finite differences. This version computes
435  /// the residuals vector before calculating the jacobian terms.
436  /// If the boolean argument is true, the finite
437  /// differencing will be performed for all internal data, irrespective of
438  /// the information in Data_fd. The default value (false)
439  /// uses the information in Data_fd to selectively difference only
440  /// certain data.
442  const bool &fd_all_data=false)
443  {
444  //Allocate storage for a residuals vector
445  Vector<double> residuals(Ndof);
446  //Get the residuals for the entire element
447  get_residuals(residuals);
448  //Call the jacobian calculation
449  fill_in_jacobian_from_external_by_fd(residuals,jacobian,fd_all_data);
450  }
451 
452  /// \short Function that is called before the finite differencing of
453  /// any internal data. This may be overloaded to update any slaved
454  /// data before finite differencing takes place.
455  virtual inline void update_before_internal_fd() { }
456 
457  /// \short Function that is call after the finite differencing of
458  /// the internal data. This may be overloaded to reset any slaved
459  /// variables that may have changed during the finite differencing.
460  virtual inline void reset_after_internal_fd() { }
461 
462  /// \short Function called within the finite difference loop for
463  /// internal data after a change in any values in the i-th
464  /// internal data object.
465  virtual inline void update_in_internal_fd(const unsigned &i) { }
466 
467  /// \short Function called within the finite difference loop for
468  /// internal data after the values in the i-th external data object
469  /// are reset. The default behaviour is to call the update function.
470  virtual inline void reset_in_internal_fd(const unsigned &i)
472 
473 
474  /// \short Function that is called before the finite differencing of
475  /// any external data. This may be overloaded to update any slaved
476  /// data before finite differencing takes place.
477  virtual inline void update_before_external_fd() { }
478 
479  /// \short Function that is call after the finite differencing of
480  /// the external data. This may be overloaded to reset any slaved
481  /// variables that may have changed during the finite differencing.
482  virtual inline void reset_after_external_fd() { }
483 
484  /// \short Function called within the finite difference loop for
485  /// external data after a change in any values in the i-th
486  /// external data object
487  virtual inline void update_in_external_fd(const unsigned &i) { }
488 
489  /// \short Function called within the finite difference loop for
490  /// external data after the values in the i-th external data object
491  /// are reset. The default behaviour is to call the update function.
492  virtual inline void reset_in_external_fd(const unsigned &i)
494 
495  /// \short Add the elemental contribution to the jacobian matrix.
496  /// and the residuals vector. Note that
497  /// this function will NOT initialise the residuals vector or the jacobian
498  /// matrix. It must be called after the residuals vector and
499  /// jacobian matrix have been initialised to zero. The default
500  /// is to use finite differences to calculate the jacobian
502  DenseMatrix<double> &jacobian)
503  {
504  //Add the contribution to the residuals
506  //Allocate storage for the full residuals (residuals of entire element)
507  Vector<double> full_residuals(Ndof);
508  //Get the residuals for the entire element
509  get_residuals(full_residuals);
510  //Calculate the contributions from the internal dofs
511  //(finite-difference the lot by default)
512  fill_in_jacobian_from_internal_by_fd(full_residuals,jacobian,true);
513  //Calculate the contributions from the external dofs
514  //(finite-difference the lot by default)
515  fill_in_jacobian_from_external_by_fd(full_residuals,jacobian,true);
516  }
517 
518  /// \short Add the elemental contribution to the mass matrix matrix.
519  /// and the residuals vector. Note that
520  /// this function should NOT initialise the residuals vector or the mass
521  /// matrix. It must be called after the residuals vector and
522  /// jacobian matrix have been initialised to zero. The default
523  /// is deliberately broken
525  Vector<double> &residuals, DenseMatrix<double> &mass_matrix);
526 
527  /// \short Add the elemental contribution to the jacobian matrix,
528  /// mass matrix and the residuals vector. Note that
529  /// this function should NOT initialise any entries.
530  /// It must be called after the residuals vector and
531  /// matrices have been initialised to zero.
533  Vector<double> &residuals,
534  DenseMatrix<double> &jacobian, DenseMatrix<double> &mass_matrix);
535 
536  /// \short Add the elemental contribution to the derivatives of
537  /// the residuals with respect to a parameter. This function should
538  /// NOT initialise any entries and must be called after the entries
539  /// have been initialised to zero
540  /// The default implementation is to use finite differences to calculate
541  /// the derivatives.
543  double* const &parameter_pt,
544  Vector<double> &dres_dparam);
545 
546 
547  /// \short Add the elemental contribution to the derivatives of
548  /// the elemental Jacobian matrix
549  /// and residuals with respect to a parameter. This function should
550  /// NOT initialise any entries and must be called after the entries
551  /// have been initialised to zero
552  /// The default implementation is to use finite differences to calculate
553  /// the derivatives.
555  double* const &parameter_pt,
556  Vector<double> &dres_dparam,
557  DenseMatrix<double> &djac_dparam);
558 
559  /// \short Add the elemental contribution to the derivative of the
560  /// jacobian matrix,
561  /// mass matrix and the residuals vector with respect to the
562  /// passed parameter. Note that
563  /// this function should NOT initialise any entries.
564  /// It must be called after the residuals vector and
565  /// matrices have been initialised to zero.
567  double* const &parameter_pt,
568  Vector<double> &dres_dparam,
569  DenseMatrix<double> &djac_dparam,
570  DenseMatrix<double> &dmass_matrix_dparam);
571 
572 
573  /// \short Fill in contribution to the product of the Hessian
574  /// (derivative of Jacobian with
575  /// respect to all variables) an eigenvector, Y, and
576  /// other specified vectors, C
577  /// (d(J_{ij})/d u_{k}) Y_{j} C_{k}
579  Vector<double> const &Y,
580  DenseMatrix<double> const &C,
581  DenseMatrix<double> &product);
582 
583  /// \short Fill in the contribution to the inner products between given
584  /// pairs of history values
586  Vector<std::pair<unsigned,unsigned> > const &history_index,
587  Vector<double> &inner_product);
588 
589  /// \short Fill in the contributions to the vectors that when taken
590  /// as dot product with other history values give the inner product
591  /// over the element
593  Vector<unsigned> const &history_index,
594  Vector<Vector<double> > &inner_product_vector);
595 
596 public:
597 
598  /// \short Constructor: Initialise all pointers and all values to zero
599  GeneralisedElement() :
600  Eqn_number(0), Dof_pt(0), Data_pt(0),
602 #ifdef OOMPH_HAS_MPI
604 #endif
605  {}
606 
607  /// Virtual destructor to clean up any memory allocated by the object.
608  virtual ~GeneralisedElement();
609 
610  /// Broken copy constructor
612  {
613  BrokenCopy::broken_copy("GeneralisedElement");
614  }
615 
616  /// Broken assignment operator
618  {
619  BrokenCopy::broken_assign("GeneralisedElement");
620  }
621 
622  /// Return a pointer to i-th internal data object.
623  Data*& internal_data_pt(const unsigned &i)
624  {
625 #ifdef RANGE_CHECKING
626  if(i >= Ninternal_data)
627  {
628  std::ostringstream error_message;
629  error_message << "Range Error: Internal data " << i
630  << " is not in the range (0,"
631  << Ninternal_data - 1 << ")";
632  throw OomphLibError(error_message.str(),
633  OOMPH_CURRENT_FUNCTION,
634  OOMPH_EXCEPTION_LOCATION);
635 
636  }
637 #endif
638  return Data_pt[i];
639  }
640 
641  /// Return a pointer to i-th internal data object (const version)
642  Data* const &internal_data_pt(const unsigned &i) const
643  {
644 #ifdef RANGE_CHECKING
645  if(i >= Ninternal_data)
646  {
647  std::ostringstream error_message;
648  error_message << "Range Error: Internal data " << i
649  << " is not in the range (0,"
650  << Ninternal_data - 1 << ")";
651  throw OomphLibError(error_message.str(),
652  OOMPH_CURRENT_FUNCTION,
653  OOMPH_EXCEPTION_LOCATION);
654 
655  }
656 #endif
657  return Data_pt[i];
658  }
659 
660 
661  /// Return a pointer to i-th external data object.
662  Data*& external_data_pt(const unsigned &i)
663  {
664 #ifdef RANGE_CHECKING
665  if(i >= Nexternal_data)
666  {
667  std::ostringstream error_message;
668  error_message << "Range Error: External data " << i
669  << " is not in the range (0,"
670  << Nexternal_data - 1 << ")";
671  throw OomphLibError(error_message.str(),
672  OOMPH_CURRENT_FUNCTION,
673  OOMPH_EXCEPTION_LOCATION);
674 
675  }
676 #endif
677  return Data_pt[Ninternal_data + i];
678  }
679 
680  /// Return a pointer to i-th external data object (const version)
681  Data* const &external_data_pt(const unsigned &i) const
682  {
683 #ifdef RANGE_CHECKING
684  if(i >= Nexternal_data)
685  {
686  std::ostringstream error_message;
687  error_message << "Range Error: External data " << i
688  << " is not in the range (0,"
689  << Nexternal_data - 1 << ")";
690  throw OomphLibError(error_message.str(),
691  OOMPH_CURRENT_FUNCTION,
692  OOMPH_EXCEPTION_LOCATION);
693 
694  }
695 #endif
696  return Data_pt[Ninternal_data + i];
697  }
698 
699  /// \short Static boolean to suppress warnings about repeated internal
700  /// data. Defaults to false.
702 
703  /// \short Static boolean to suppress warnings about repeated external
704  /// data. Defaults to true.
706 
707  /// \short Return the global equation number corresponding to the
708  /// ieqn_local-th local equation number
709  unsigned long eqn_number(const unsigned &ieqn_local) const
710  {
711 #ifdef RANGE_CHECKING
712  if(ieqn_local >= Ndof)
713  {
714  std::ostringstream error_message;
715  error_message << "Range Error: Equation number " << ieqn_local
716  << " is not in the range (0,"
717  << Ndof - 1 << ")";
718  throw OomphLibError(error_message.str(),
719  OOMPH_CURRENT_FUNCTION,
720  OOMPH_EXCEPTION_LOCATION);
721  }
722 #endif
723  return Eqn_number[ieqn_local];
724  }
725 
726 
727  ///\short Return the local equation number corresponding to the ieqn_global-th
728  ///global equation number. Returns minus one (-1) if there is no
729  ///local degree of freedom corresponding to the chosen global equation
730  ///number
731  int local_eqn_number(const unsigned long &ieqn_global) const
732  {
733  //Cache the number of degrees of freedom in the element
734  const unsigned n_dof = this->Ndof;
735  //Loop over the local equation numbers
736  for(unsigned n=0;n<n_dof;n++)
737  {
738  //If the global equation numbers match return
739  if(ieqn_global==Eqn_number[n]) {return n;}
740  }
741 
742  //If we've got all the way to the end the number has not been found
743  //return minus one.
744  return -1;
745  }
746 
747 
748  /// Add a (pointer to an) external data object to the element and return its
749  /// index (i.e. the index required to obtain it from
750  /// the access function \c external_data_pt(...). The optional boolean
751  /// flag indicates whether the data should be included in the
752  /// general finite-difference loop when calculating the jacobian.
753  /// The default value is true, i.e. the data will be included in the
754  /// finite-differencing
755  unsigned add_external_data(Data* const &data_pt, const bool &fd=true);
756 
757  /// \short Return the status of the boolean flag indicating whether
758  /// the external data is included in the finite difference loop
759  inline bool external_data_fd(const unsigned &i) const
760  {
761 #ifdef RANGE_CHECKING
762  if(i >= Nexternal_data)
763  {
764  std::ostringstream error_message;
765  error_message << "Range Error: Internal data " << i
766  << " is not in the range (0,"
767  << Nexternal_data-1 << ")";
768  throw OomphLibError(error_message.str(),
769  OOMPH_CURRENT_FUNCTION,
770  OOMPH_EXCEPTION_LOCATION);
771  }
772 #endif
773  //Return the value
774  return Data_fd[Ninternal_data + i];
775  }
776 
777 
778 
779  /// \short Set the boolean flag to exclude the external datum from the
780  /// the finite difference loop when computing the jacobian matrix
781  inline void exclude_external_data_fd(const unsigned &i)
782  {
783 #ifdef RANGE_CHECKING
784  if(i >= Nexternal_data)
785  {
786  std::ostringstream error_message;
787  error_message << "Range Error: External data " << i
788  << " is not in the range (0,"
789  << Nexternal_data - 1 << ")";
790  throw OomphLibError(error_message.str(),
791  OOMPH_CURRENT_FUNCTION,
792  OOMPH_EXCEPTION_LOCATION);
793 
794  }
795 #endif
796  //Set the value
797  Data_fd[Ninternal_data + i] = false;
798  }
799 
800  /// \short Set the boolean flag to include the external datum in the
801  /// the finite difference loop when computing the jacobian matrix
802  inline void include_external_data_fd(const unsigned &i)
803  {
804 #ifdef RANGE_CHECKING
805  if(i >= Nexternal_data)
806  {
807  std::ostringstream error_message;
808  error_message << "Range Error: External data " << i
809  << " is not in the range (0,"
810  << Nexternal_data - 1 << ")";
811  throw OomphLibError(error_message.str(),
812  OOMPH_CURRENT_FUNCTION,
813  OOMPH_EXCEPTION_LOCATION);
814 
815  }
816 #endif
817  //Set the value
818  Data_fd[Ninternal_data + i] = true;
819  }
820 
821  /// Flush all external data
822  void flush_external_data();
823 
824  /// Flush the object addressed by data_pt from the external data array
825  void flush_external_data(Data* const &data_pt);
826 
827  /// Return the number of internal data objects.
828  unsigned ninternal_data() const {return Ninternal_data;}
829 
830  /// Return the number of external data objects.
831  unsigned nexternal_data() const {return Nexternal_data;}
832 
833  /// Return the number of equations/dofs in the element.
834  unsigned ndof() const {return Ndof;}
835 
836  ///\short Return the vector of dof values at time level t
837  void dof_vector(const unsigned &t, Vector<double> &dof)
838  {
839  //Check that the internal storage has been set up
840 #ifdef PARANOID
841  if(Dof_pt==0)
842  {
843  std::stringstream error_stream;
844  error_stream << "Internal dof array not set up in element.\n"
845  << "In order to set it up you must call\n"
846  << " Problem::enable_store_local_dof_in_elements()\n"
847  << "before the call to Problem::assign_eqn_numbers()\n";
848  throw OomphLibError(error_stream.str(),
849  OOMPH_CURRENT_FUNCTION,
850  OOMPH_EXCEPTION_LOCATION);
851  }
852 #endif
853  //Resize the vector
854  dof.resize(this->Ndof);
855  //Loop over the vector and fill in the desired values
856  for(unsigned i=0;i<this->Ndof;++i)
857  {
858  dof[i] = Dof_pt[i][t];
859  }
860  }
861 
862  ///\short Return the vector of pointers to dof values
864  {
865  //Check that the internal storage has been set up
866 #ifdef PARANOID
867  if(Dof_pt==0)
868  {
869  std::stringstream error_stream;
870  error_stream << "Internal dof array not set up in element.\n"
871  << "In order to set it up you must call\n"
872  << " Problem::enable_store_local_dof_in_elements()\n"
873  << "before the call to Problem::assign_eqn_numbers()\n";
874  throw OomphLibError(error_stream.str(),
875  OOMPH_CURRENT_FUNCTION,
876  OOMPH_EXCEPTION_LOCATION);
877  }
878 #endif
879  //Resize the vector
880  dof_pt.resize(this->Ndof);
881  //Loop over the vector and fill in the desired values
882  for(unsigned i=0;i<this->Ndof;++i)
883  {
884  dof_pt[i] = Dof_pt[i];
885  }
886  }
887 
888 
889 
890  /// \short Set the timestepper associated with the i-th internal data
891  /// object
892  void set_internal_data_time_stepper(const unsigned &i,
893  TimeStepper* const &time_stepper_pt,
894  const bool &preserve_existing_data)
895  {this->internal_data_pt(i)->set_time_stepper(time_stepper_pt,
896  preserve_existing_data);}
897 
898  /// \short Assign the global equation numbers to the internal Data.
899  /// The arguments are the current highest global equation number
900  /// (which will be incremented) and a Vector of pointers to the
901  /// global variables (to which any unpinned values in the internal Data are
902  /// added).
903  void assign_internal_eqn_numbers(unsigned long &global_number,
904  Vector<double *> &Dof_pt);
905 
906  /// \short Function to describe the dofs of the element. The ostream
907  /// specifies the output stream to which the description
908  /// is written; the string stores the currently
909  /// assembled output that is ultimately written to the
910  /// output stream by Data::describe_dofs(...); it is typically
911  /// built up incrementally as we descend through the
912  /// call hierarchy of this function when called from
913  /// Problem::describe_dofs(...)
914  void describe_dofs(std::ostream& out,const std::string& current_string) const;
915 
916  /// \short Function to describe the local dofs of the element. The ostream
917  /// specifies the output stream to which the description
918  /// is written; the string stores the currently
919  /// assembled output that is ultimately written to the
920  /// output stream by Data::describe_dofs(...); it is typically
921  /// built up incrementally as we descend through the
922  /// call hierarchy of this function when called from
923  /// Problem::describe_dofs(...)
924  virtual void describe_local_dofs(std::ostream& out,
925  const std::string& current_string) const;
926 
927  /// \short Add pointers to the internal data values to map indexed
928  /// by the global equation number.
929  void add_internal_value_pt_to_map(std::map<unsigned,double*> &
930  map_of_value_pt);
931 
932 #ifdef OOMPH_HAS_MPI
933  /// \short Add all internal data and time history values to the vector in
934  /// the internal storage order
935  void add_internal_data_values_to_vector(Vector<double> &vector_of_values);
936 
937  /// \short Read all internal data and time history values from the vector
938  /// starting from index. On return the index will be
939  /// set to the value at the end of the data that has been read in
941  const Vector<double> & vector_of_values, unsigned &index);
942 
943  /// \short Add all equation numbers associated with internal data
944  /// to the vector in the internal storage order
945  void add_internal_eqn_numbers_to_vector(Vector<long> &vector_of_eqn_numbers);
946 
947  /// \short Read all equation numbers associated with internal data
948  /// from the vector
949  /// starting from index. On return the index will be
950  /// set to the value at the end of the data that has been read in
952  const Vector<long> & vector_of_eqn_numbers, unsigned &index);
953 
954 #endif
955 
956  /// \short Setup the arrays of local equation numbers for the element.
957  /// If the optional boolean argument is true, then pointers to the associated
958  /// degrees of freedom are stored locally in the array Dof_pt
959  virtual void assign_local_eqn_numbers(const bool &store_local_dof_pt);
960 
961  /// \short Complete the setup of any additional dependencies
962  /// that the element may have. Empty virtual function that may be
963  /// overloaded for specific derived elements. Used, e.g., for elements
964  /// with algebraic node update functions to determine the "geometric
965  /// Data", i.e. the Data that affects the element's shape.
966  /// This function is called (for all elements) at the very beginning of the
967  /// equation numbering procedure to ensure that all dependencies
968  /// are accounted for.
970 
971  /// \short Calculate the vector of residuals of the equations in the element.
972  /// By default initialise the vector to zero and then call the
973  /// fill_in_contribution_to_residuals() function. Note that this entire
974  /// function can be overloaded if desired.
975  virtual void get_residuals(Vector<double> &residuals)
976  {
977  //Zero the residuals vector
978  residuals.initialise(0.0);
979  //Add the elemental contribution to the residuals vector
981  }
982 
983  /// \short Calculate the elemental Jacobian matrix "d equation / d variable".
984  virtual void get_jacobian(Vector<double> &residuals,
985  DenseMatrix<double> &jacobian)
986  {
987  //Zero the residuals vector
988  residuals.initialise(0.0);
989  //Zero the jacobian matrix
990  jacobian.initialise(0.0);
991  //Add the elemental contribution to the residuals vector
992  fill_in_contribution_to_jacobian(residuals,jacobian);
993  }
994 
995  /// \short Calculate the residuals and the elemental "mass" matrix, the
996  /// matrix that multiplies the time derivative terms in a problem.
997  virtual void get_mass_matrix(Vector<double> &residuals,
998  DenseMatrix<double> &mass_matrix)
999  {
1000  //Zero the residuals vector
1001  residuals.initialise(0.0);
1002  //Zero the mass matrix
1003  mass_matrix.initialise(0.0);
1004  //Add the elemental contribution to the vector and matrix
1005  fill_in_contribution_to_mass_matrix(residuals,mass_matrix);
1006  }
1007 
1008  /// \short Calculate the residuals and jacobian and elemental "mass" matrix,
1009  /// the matrix that multiplies the time derivative terms.
1011  DenseMatrix<double> &jacobian,
1012  DenseMatrix<double> &mass_matrix)
1013  {
1014  //Zero the residuals vector
1015  residuals.initialise(0.0);
1016  //Zero the jacobian matrix
1017  jacobian.initialise(0.0);
1018  //Zero the mass matrix
1019  mass_matrix.initialise(0.0);
1020  //Add the elemental contribution to the vector and matrix
1022  mass_matrix);
1023  }
1024 
1025 
1026  /// \short Calculate the derivatives of the residuals with respect to
1027  /// a parameter
1028  virtual void get_dresiduals_dparameter(double* const &parameter_pt,
1029  Vector<double> &dres_dparam)
1030  {
1031  //Zero the dres_dparam vector
1032  dres_dparam.initialise(0.0);
1033  //Add the elemental contribution to the residuals vector
1035  dres_dparam);
1036  }
1037 
1038  /// \short Calculate the derivatives of the elemental Jacobian matrix
1039  /// and residuals with respect to a parameter
1040  virtual void get_djacobian_dparameter(double* const &parameter_pt,
1041  Vector<double> &dres_dparam,
1042  DenseMatrix<double> &djac_dparam)
1043  {
1044  //Zero the residuals vector
1045  dres_dparam.initialise(0.0);
1046  //Zero the jacobian matrix
1047  djac_dparam.initialise(0.0);
1048  //Add the elemental contribution to the residuals vector
1049  this->fill_in_contribution_to_djacobian_dparameter(parameter_pt,dres_dparam,
1050  djac_dparam);
1051  }
1052 
1053  /// \short Calculate the derivatives of the elemental Jacobian matrix
1054  /// mass matrix and residuals with respect to a parameter
1056  double* const &parameter_pt,
1057  Vector<double> &dres_dparam,
1058  DenseMatrix<double> &djac_dparam,
1059  DenseMatrix<double> &dmass_matrix_dparam)
1060  {
1061  //Zero the residuals derivative vector
1062  dres_dparam.initialise(0.0);
1063  //Zero the jacobian derivative matrix
1064  djac_dparam.initialise(0.0);
1065  //Zero the mass matrix derivative
1066  dmass_matrix_dparam.initialise(0.0);
1067  //Add the elemental contribution to the residuals vector and matrices
1069  parameter_pt,dres_dparam,djac_dparam,dmass_matrix_dparam);
1070  }
1071 
1072 
1073  /// \short Calculate the product of the Hessian (derivative of Jacobian with
1074  /// respect to all variables) an eigenvector, Y, and
1075  /// other specified vectors, C
1076  /// (d(J_{ij})/d u_{k}) Y_{j} C_{k}
1078  DenseMatrix<double> const &C,
1079  DenseMatrix<double> &product)
1080  {
1081  //Initialise the product to zero
1082  product.initialise(0.0);
1083  ///Add the elemental contribution to the product
1085  }
1086 
1087  /// \short Return the vector of inner product of the given pairs of
1088  /// history values
1089  virtual void get_inner_products(Vector<std::pair<unsigned,unsigned> >
1090  const &history_index,
1091  Vector<double> &inner_product)
1092  {
1093  inner_product.initialise(0.0);
1094  this->fill_in_contribution_to_inner_products(history_index,
1095  inner_product);
1096  }
1097 
1098  /// \short Compute the vectors that when taken as a dot product with
1099  /// other history values give the inner product over the element.
1100  virtual void get_inner_product_vectors(Vector<unsigned> const &history_index,
1101  Vector<Vector<double> > &inner_product_vector)
1102  {
1103  const unsigned n_inner_product = inner_product_vector.size();
1104  for(unsigned i=0;i<n_inner_product;++i)
1105  {inner_product_vector[i].initialise(0.0);}
1107  inner_product_vector);
1108  }
1109 
1110 
1111  /// \short Self-test: Have all internal values been classified as
1112  /// pinned/unpinned? Return 0 if OK.
1113  virtual unsigned self_test();
1114 
1115 
1116  /// \short Compute norm of solution -- broken virtual can be overloaded
1117  /// by element writer to implement whatever norm is desired for
1118  /// the specific element
1119  virtual void compute_norm(double& norm)
1120  {
1121  std::string error_message = "compute_norm undefined for this element \n";
1122  throw OomphLibError(error_message,
1123  OOMPH_CURRENT_FUNCTION,
1124  OOMPH_EXCEPTION_LOCATION);
1125 
1126  }
1127 
1128 #ifdef OOMPH_HAS_MPI
1129 
1130  /// \short Label the element as halo and specify processor that holds
1131  /// non-halo counterpart
1132  void set_halo(const unsigned& non_halo_proc_ID)
1133  {
1134  Non_halo_proc_ID=non_halo_proc_ID;
1135  }
1136 
1137  /// \short Label the element as not being a halo
1138  void set_nonhalo() {Non_halo_proc_ID=-1;}
1139 
1140  /// \short Is this element a halo?
1141  bool is_halo() const {return (Non_halo_proc_ID!=-1);}
1142 
1143  /// \short ID of processor ID that holds non-halo counterpart
1144  /// of halo element; negative if not a halo.
1146  {
1147  return Non_halo_proc_ID;
1148  }
1149 
1150  /// Insist that this element be kept as a halo element during a distribute?
1151  void set_must_be_kept_as_halo() {Must_be_kept_as_halo = true;}
1152 
1153  /// \short Do not insist that this element be kept as a halo element during
1154  /// distribution
1155  void unset_must_be_kept_as_halo() {Must_be_kept_as_halo = false;}
1156 
1157  /// \short Test whether the element must be kept as a halo element
1159 
1160 #endif
1161 
1162  /// \short Double used for the default finite difference step in elemental
1163  /// jacobian calculations
1165 
1166  /// \short The number of types of degrees of freedom in this element
1167  /// are sub-divided into
1168  virtual unsigned ndof_types() const
1169  {
1170  // error message stream
1171  std::ostringstream error_message;
1172  error_message << "ndof_types() const has not been implemented for this \n"
1173  << "element\n" << std::endl;
1174  // throw error
1175  throw OomphLibError(error_message.str(),
1176  OOMPH_CURRENT_FUNCTION,
1177  OOMPH_EXCEPTION_LOCATION);
1178  }
1179 
1180  /// \short Create a list of pairs for the unknowns that this element
1181  /// is "in charge of" -- ignore any unknowns associated with external
1182  /// \c Data. The first entry in each pair must contain the global equation
1183  /// number of the unknown, while the second one contains the number
1184  /// of the DOF type that this unknown is associated with.
1185  /// (The function can obviously only be called if the equation numbering
1186  /// scheme has been set up.)
1188  std::list<std::pair<unsigned long,unsigned> >& dof_lookup_list) const
1189  {
1190  // error message stream
1191  std::ostringstream error_message;
1192  error_message << "get_dof_numbers_for_unknowns() const has not been \n"
1193  << " implemented for this element\n" << std::endl;
1194  // throw error
1195  throw OomphLibError(error_message.str(),
1196  OOMPH_CURRENT_FUNCTION,
1197  OOMPH_EXCEPTION_LOCATION);
1198  }
1199 
1200 };
1201 
1202  /// Enumeration a finite element's geometry "type". Either "Q" (square,
1203  /// cubeoid like) or "T" (triangle, tetrahedron).
1205  {
1207  }
1208 
1209 //Forward class definitions that are used in FiniteElements
1210 class FaceElement;
1211 class MacroElement;
1212 class TimeStepper;
1213 class Shape;
1214 class DShape;
1215 class Integral;
1216 
1217 //===========================================================================
1218 /// \short Helper namespace for tolerances and iterations within the Newton
1219 /// method used in the locate_zeta function in FiniteElements.
1220 //===========================================================================
1221 namespace Locate_zeta_helpers
1222 {
1223  /// Convergence tolerance for the Newton solver
1224  extern double Newton_tolerance;
1225 
1226  /// Maximum number of Newton iterations
1227  extern unsigned Max_newton_iterations;
1228 
1229  /// \short Multiplier for (zeta-based) outer radius of element used for
1230  /// deciding that point is outside element. Set to negative value
1231  /// to suppress test.
1233 
1234  /// Number of points along one dimension of each element used
1235  /// to create coordinates within the element in order to see
1236  /// which has the smallest initial residual (and is therefore used
1237  /// as the initial guess in the Newton method for locate_zeta)
1238  extern unsigned N_local_points;
1239 
1240 }
1241 
1242 
1243  /// \short Typedef for the function that translates the face coordinate
1244  /// to the coordinate in the bulk element
1245  typedef void (*CoordinateMappingFctPt)(const Vector<double> &s,
1246  Vector<double> &s_bulk);
1247 
1248  /// \short Typedef for the function that returns the partial derivative
1249  /// of the local coordinates in the bulk element
1250  /// with respect to the coordinates along the face.
1251  /// In addition this function returns an index of one of the
1252  /// bulk local coordinates that varies away from the edge
1254  DenseMatrix<double> &ds_bulk_dsface,
1255  unsigned &interior_direction);
1256 
1257 
1258 //========================================================================
1259 /// \short A general Finite Element class.
1260 ///
1261 /// The main components of a FiniteElement are:
1262 /// - pointers to its Nodes
1263 /// - pointers to its internal Data (inherited from GeneralisedElement)
1264 /// - pointers to its external Data (inherited from GeneralisedElement)
1265 /// - a pointer to a spatial integration scheme
1266 /// - a pointer to the global Time object (inherited from GeneralisedElement)
1267 /// - a lookup table which establishes the relation between local
1268 /// and global equation numbers (inherited from GeneralisedElement)
1269 ///
1270 /// We also provide interfaces for functions that compute the
1271 /// element's Jacobian matrix and/or the Vector of residuals
1272 /// (inherited from GeneralisedElement) plus various output routines.
1273 //========================================================================
1274 class FiniteElement : public virtual GeneralisedElement, public GeomObject
1275 {
1276  private:
1277 
1278  /// Pointer to the spatial integration scheme
1280 
1281  /// Storage for pointers to the nodes in the element
1283 
1284  /// \short Storage for the local equation numbers associated with
1285  /// the values stored at the nodes
1287 
1288  /// Number of nodes in the element
1289  unsigned Nnode;
1290 
1291  /// \short The spatial dimension of the element, i.e. the number
1292  /// of local coordinates used to parametrize it.
1294 
1295  /// \short The spatial dimension of the nodes in the element.
1296  /// We assume that nodes have the same spatial dimension, because
1297  /// we cannot think of any "real" problems for which that would not
1298  /// be the case.
1300 
1301  /// \short The number of coordinate types required to interpolate
1302  /// the element's geometry between the nodes. For Lagrange elements
1303  /// it is 1 (the default). It must be over-ridden by using
1304  /// the set_nposition_type() function in the constructors of elements
1305  /// that use generalised coordinate, e.g. for 1D Hermite elements
1306  /// Nnodal_position_types =2.
1308 
1309  protected:
1310 
1311  /// \short Assemble the jacobian matrix for the mapping from local
1312  /// to Eulerian coordinates, given the derivatives of the shape function
1313  /// w.r.t the local coordinates.
1314  virtual void assemble_local_to_eulerian_jacobian(
1315  const DShape &dpsids, DenseMatrix<double> &jacobian) const;
1316 
1317  /// \short Assemble the the "jacobian" matrix of second derivatives of the
1318  /// mapping from local to Eulerian coordinates, given
1319  /// the second derivatives of the shape functions w.r.t. local coordinates.
1320  virtual void assemble_local_to_eulerian_jacobian2(
1321  const DShape &d2psids, DenseMatrix<double> &jacobian2) const;
1322 
1323  /// \short Assemble the covariant Eulerian base vectors, assuming that
1324  /// the derivatives of the shape functions with respect to the local
1325  /// coordinates have already been constructed.
1326  virtual void assemble_eulerian_base_vectors(
1327  const DShape &dpsids, DenseMatrix<double> &interpolated_G) const;
1328 
1329  /// \short Default return value for required_nvalue(n) which gives the number
1330  /// of "data" values required by the element at node n; for example, solving
1331  /// a Poisson equation would required only one "data" value at each node. The
1332  /// defaults is set to zero, because a general element is problem-less.
1333  static const unsigned Default_Initial_Nvalue;
1334 
1335  /// \short Default value for the tolerance to be used when locating nodes
1336  /// via local coordinates
1337  static const double Node_location_tolerance;
1338 
1339 public:
1340 
1341  /// \short Set the dimension of the element and initially set
1342  /// the dimension of the nodes to be the same as the dimension of the
1343  /// element.
1344  void set_dimension(const unsigned &dim)
1345  {Elemental_dimension = dim; Nodal_dimension = dim;}
1346 
1347  /// \short Set the dimension of the nodes in the element. This will
1348  /// typically only be required when constructing FaceElements or
1349  /// in beam and shell type elements where a lower dimensional surface
1350  /// is embedded in a higher dimensional space.
1351  void set_nodal_dimension(const unsigned &nodal_dim)
1352  {Nodal_dimension = nodal_dim;}
1353 
1354  /// \short Set the number of types required to interpolate the coordinate
1355  void set_nnodal_position_type(const unsigned &nposition_type)
1356  {Nnodal_position_type = nposition_type;}
1357 
1358 
1359  /// \short Set the number of nodes in the element to n, by resizing
1360  /// the storage for pointers to the Node objects.
1361  void set_n_node(const unsigned &n)
1362  {
1363  //This should only be done once, in a Node constructor
1364 //#ifdef PARANOID
1365  //if(Node_pt)
1366  // {
1367  // OomphLibWarning(
1368  // "You are resetting the number of nodes in an element -- Be careful",
1369  // "FiniteElement::set_n_node()",
1370  // OOMPH_EXCEPTION_LOCATION);
1371  // }
1372 //#endif
1373  //Delete any previous storage to avoid memory leaks
1374  //This will only happen in very special cases
1375  delete[] Node_pt;
1376  //Set the number of nodes
1377  Nnode = n;
1378  //Allocate the storage
1379  Node_pt = new Node*[n];
1380  //Initialise all the pointers to NULL
1381  for(unsigned i=0;i<n;i++) {Node_pt[i] = 0;}
1382  }
1383 
1384  /// \short Return the local equation number corresponding to the i-th
1385  /// value at the n-th local node.
1386  inline int nodal_local_eqn(const unsigned &n, const unsigned &i) const
1387  {
1388 #ifdef RANGE_CHECKING
1389  if(n >= Nnode)
1390  {
1391  std::ostringstream error_message;
1392  error_message << "Range Error: Node number " << n
1393  << " is not in the range (0,"
1394  << Nnode-1 << ")";
1395  throw OomphLibError(error_message.str(),
1396  OOMPH_CURRENT_FUNCTION,
1397  OOMPH_EXCEPTION_LOCATION);
1398  }
1399  else
1400  {
1401  unsigned n_value = node_pt(n)->nvalue();
1402  if(i >= n_value)
1403  {
1404  std::ostringstream error_message;
1405  error_message << "Range Error: value " << i << " at node " << n
1406  << " is not in the range (0,"
1407  << n_value -1 << ")";
1408  throw OomphLibError(error_message.str(),
1409  OOMPH_CURRENT_FUNCTION,
1410  OOMPH_EXCEPTION_LOCATION);
1411  }
1412  }
1413 #endif
1414 #ifdef PARANOID
1415  //Check that the equations have been allocated
1416  if(Nodal_local_eqn==0)
1417  {
1418  throw OomphLibError(
1419  "Nodal local equation numbers have not been allocated",
1420  OOMPH_CURRENT_FUNCTION,
1421  OOMPH_EXCEPTION_LOCATION);
1422  }
1423 #endif
1424  return Nodal_local_eqn[n][i];
1425  }
1426 
1427 
1428 
1429  /// \short Compute the geometric shape functions (psi) at integration point
1430  /// ipt. Return the determinant of the jacobian of the mapping (detJ).
1431  /// Additionally calculate the derivatives of "detJ" w.r.t. the
1432  /// nodal coordinates.
1433  double dJ_eulerian_at_knot(const unsigned &ipt,
1434  Shape &psi,
1435  DenseMatrix<double> &djacobian_dX) const;
1436  protected:
1437 
1438  /// \short Static array that holds the number of second derivatives
1439  /// as a function of the dimension of the element
1440  static const unsigned N2deriv[];
1441 
1442  /// \short Take the matrix passed as jacobian and return its inverse in
1443  /// inverse_jacobian. This function is templated by the dimension of the
1444  /// element because matrix inversion cannot be written efficiently in a
1445  /// generic manner.
1446  template<unsigned DIM>
1447  double invert_jacobian(const DenseMatrix<double> &jacobian,
1448  DenseMatrix<double> &inverse_jacobian) const;
1449 
1450 
1451  /// \short A template-free interface that takes the matrix passed as jacobian
1452  /// and return its inverse in inverse_jacobian. By default the function will
1453  /// use the dimension of the element to call the correct invert_jacobian(..)
1454  /// function. This should be overloaded for efficiency (removal of a switch
1455  /// statement) in specific elements.
1456  virtual double invert_jacobian_mapping(const DenseMatrix<double> &jacobian,
1457  DenseMatrix<double> &inverse_jacobian)
1458  const;
1459 
1460 
1461  /// \short Calculate the mapping from local to Eulerian coordinates,
1462  /// given the derivatives of the shape functions w.r.t. local coordinates.
1463  /// Returns the determinant of the jacobian, the jacobian and inverse jacobian
1464  virtual double local_to_eulerian_mapping(const DShape &dpsids,
1465  DenseMatrix<double> &jacobian,
1466  DenseMatrix<double> &inverse_jacobian) const
1467  {
1468  //Assemble the jacobian
1469  assemble_local_to_eulerian_jacobian(dpsids,jacobian);
1470  //Invert the jacobian (use the template-free interface)
1471  return invert_jacobian_mapping(jacobian,inverse_jacobian);
1472  }
1473 
1474 
1475  /// \short Calculate the mapping from local to Eulerian coordinates,
1476  /// given the derivatives of the shape functions w.r.t. local coordinates,
1477  /// Return only the determinant of the jacobian and the inverse of the
1478  /// mapping (ds/dx).
1479  double local_to_eulerian_mapping(const DShape &dpsids,
1480  DenseMatrix<double> &inverse_jacobian) const
1481  {
1482  //Find the dimension of the element
1483  const unsigned el_dim = dim();
1484  //Assign memory for the jacobian
1485  DenseMatrix<double> jacobian(el_dim);
1486  //Calculate the jacobian and inverse
1487  return local_to_eulerian_mapping(dpsids,jacobian,inverse_jacobian);
1488  }
1489 
1490  /// \short Calculate the mapping from local to Eulerian coordinates given
1491  /// the derivatives of the shape functions w.r.t the local coordinates.
1492  /// assuming that the coordinates are aligned in the direction of the local
1493  /// coordinates, i.e. there are no cross terms and the jacobian is diagonal.
1494  /// This function returns the determinant of the jacobian, the jacobian
1495  /// and the inverse jacobian.
1496  virtual double local_to_eulerian_mapping_diagonal(
1497  const DShape &dpsids,DenseMatrix<double> &jacobian,
1498  DenseMatrix<double> &inverse_jacobian) const;
1499 
1500  /// \short A template-free interface that calculates the derivative of the
1501  /// jacobian of a mapping with respect to the nodal coordinates X_ij.
1502  /// To do this it requires the jacobian matrix and the derivatives of the
1503  /// shape functions w.r.t. the local coordinates. By default the function
1504  /// will use the dimension of the element to call the correct
1505  /// dJ_eulerian_dnodal_coordinates_templated_helper(..) function. This
1506  /// should be overloaded for efficiency (removal of a switch statement)
1507  /// in specific elements.
1508  virtual void dJ_eulerian_dnodal_coordinates(
1509  const DenseMatrix<double> &jacobian,const DShape &dpsids,
1510  DenseMatrix<double> &djacobian_dX) const;
1511 
1512  /// \short Calculate the derivative of the jacobian of a mapping with
1513  /// respect to the nodal coordinates X_ij using the jacobian matrix
1514  /// and the derivatives of the shape functions w.r.t. the local
1515  /// coordinates. This function is templated by the dimension of the
1516  /// element.
1517  template<unsigned DIM>
1518  void dJ_eulerian_dnodal_coordinates_templated_helper(
1519  const DenseMatrix<double> &jacobian,const DShape &dpsids,
1520  DenseMatrix<double> &djacobian_dX) const;
1521 
1522  /// \short A template-free interface that calculates the derivative w.r.t.
1523  /// the nodal coordinates \f$ X_{pq} \f$ of the derivative of the shape
1524  /// functions \f$ \psi_j \f$ w.r.t. the global eulerian coordinates
1525  /// \f$ x_i \f$. I.e. this function calculates
1526  /// \f[
1527  /// \frac{\partial}{\partial X_{pq}}
1528  /// \left( \frac{\partial \psi_j}{\partial x_i} \right).
1529  /// \f]
1530  /// To do this it requires the determinant of the jacobian mapping, its
1531  /// derivative w.r.t. the nodal coordinates \f$ X_{pq} \f$, the inverse
1532  /// jacobian and the derivatives of the shape functions w.r.t. the local
1533  /// coordinates. The result is returned as a tensor of rank four.
1534  /// Numbering:
1535  /// d_dpsidx_dX(p,q,j,i) = \f$ \frac{\partial}{\partial X_{pq}}
1536  /// \left( \frac{\partial \psi_j}{\partial x_i} \right) \f$
1537  /// By default the function will use the dimension of the element to call
1538  /// the correct d_dshape_eulerian_dnodal_coordinates_templated_helper(..)
1539  /// function. This should be overloaded for efficiency (removal of a
1540  /// switch statement) in specific elements.
1541  virtual void d_dshape_eulerian_dnodal_coordinates(
1542  const double &det_jacobian,
1543  const DenseMatrix<double> &jacobian,
1544  const DenseMatrix<double> &djacobian_dX,
1545  const DenseMatrix<double> &inverse_jacobian,
1546  const DShape &dpsids,
1547  RankFourTensor<double> &d_dpsidx_dX) const;
1548 
1549  /// \short Calculate the derivative w.r.t. the nodal coordinates
1550  /// \f$ X_{pq} \f$ of the derivative of the shape functions w.r.t. the
1551  /// global eulerian coordinates \f$ x_i \f$, using the determinant of
1552  /// the jacobian mapping, its derivative w.r.t. the nodal coordinates
1553  /// \f$ X_{pq} \f$, the inverse jacobian and the derivatives of the
1554  /// shape functions w.r.t. the local coordinates. The result is returned
1555  /// as a tensor of rank four.
1556  /// Numbering:
1557  /// d_dpsidx_dX(p,q,j,i) = \f$ \frac{\partial}{\partial X_{pq}}
1558  /// \left( \frac{\partial \psi_j}{\partial x_i} \right) \f$
1559  /// This function is templated by the dimension of the element.
1560  template<unsigned DIM>
1561  void d_dshape_eulerian_dnodal_coordinates_templated_helper(
1562  const double &det_jacobian,
1563  const DenseMatrix<double> &jacobian,
1564  const DenseMatrix<double> &djacobian_dX,
1565  const DenseMatrix<double> &inverse_jacobian,
1566  const DShape &dpsids,
1567  RankFourTensor<double> &d_dpsidx_dX) const;
1568 
1569  /// \short Convert derivative w.r.t.local coordinates to derivatives
1570  /// w.r.t the coordinates used to assemble the inverse_jacobian passed
1571  /// in the mapping. On entry, dbasis must contain the basis function
1572  /// derivatives w.r.t. the local coordinates; it will contain the
1573  /// derivatives w.r.t. the new coordinates on exit.
1574  /// This is virtual so that it may be overloaded if desired
1575  /// for efficiency reasons.
1576  virtual void transform_derivatives(const DenseMatrix<double>
1577  &inverse_jacobian, DShape &dbasis) const;
1578 
1579  /// \short Convert derivative w.r.t local coordinates to derivatives
1580  /// w.r.t the coordinates used to assemble the inverse jacobian passed
1581  /// in the mapping, assuming that the coordinates are aligned in the
1582  /// direction of the local coordinates. On entry dbasis must contain
1583  /// the derivatives of the basis functions w.r.t. the local coordinates;
1584  /// it will contain the derivatives w.r.t. the new coordinates.
1585  /// are converted into the new using the mapping inverse_jacobian.
1586  void transform_derivatives_diagonal(const DenseMatrix<double>
1587  &inverse_jacobian, DShape &dbasis) const;
1588 
1589  /// \short Convert derivatives and second derivatives w.r.t. local coordiantes
1590  /// to derivatives and second derivatives w.r.t. the coordinates used to
1591  /// assemble the jacobian, inverse jacobian and jacobian2 passed to the
1592  /// function. By default this function will call
1593  /// transform_second_derivatives_template<>(...) using the dimension of
1594  /// the element as the template parameter. It is virtual so that it can
1595  /// be overloaded by a specific element to save using a switch statement.
1596  /// Optionally, the element writer may wish to use the
1597  /// transform_second_derivatives_diagonal<>(...) function
1598  /// On entry dbasis and d2basis must contain the derivatives w.r.t. the
1599  /// local coordinates; on exit they will be the derivatives w.r.t. the
1600  /// transformed coordinates.
1601  virtual void transform_second_derivatives(const DenseMatrix<double>
1602  &jacobian,
1603  const DenseMatrix<double>
1604  &inverse_jacobian,
1605  const DenseMatrix<double>
1606  &jacobian2,
1607  DShape &dbasis,
1608  DShape &d2basis) const;
1609 
1610  /// \short Convert derivatives and second derivatives w.r.t. local coordinates
1611  /// to derivatives and second derivatives w.r.t. the coordinates used to
1612  /// asssmble the jacobian, inverse jacobian and jacobian2 passed in the
1613  /// mapping. This is templated by dimension because the method of calculation
1614  /// varies significantly with the dimension.
1615  /// On entry dbasis and d2basis must contain the derivatives w.r.t. the
1616  /// local coordinates; on exit they will be the derivatives w.r.t. the
1617  /// transformed coordinates.
1618  template<unsigned DIM>
1619  void transform_second_derivatives_template(const DenseMatrix<double>
1620  &jacobian,
1621  const DenseMatrix<double>
1622  &inverse_jacobian,
1623  const DenseMatrix<double>
1624  &jacobian2,
1625  DShape &dbasis,
1626  DShape &d2basis) const;
1627 
1628  /// \short Convert derivatives and second derivatives w.r.t. local coordinates
1629  /// to derivatives and second derivatives w.r.t. the coordinates used to
1630  /// asssmble the jacobian, inverse jacobian and jacobian2 passed in the
1631  /// mapping. This version of the function assumes that the local coordinates
1632  /// are aligned with the global coordinates, i.e. the jacobians are diagonal
1633  /// On entry dbasis and d2basis must contain the derivatives w.r.t. the
1634  /// local coordinates; on exit they will be the derivatives w.r.t. the
1635  /// transformed coordinates.
1636  template<unsigned DIM>
1637  void transform_second_derivatives_diagonal(const DenseMatrix<double>
1638  &jacobian,
1639  const DenseMatrix<double>
1640  &inverse_jacobian,
1641  const DenseMatrix<double>
1642  &jacobian2,
1643  DShape &dbasis,
1644  DShape &d2basis) const;
1645 
1646  /// Pointer to the element's macro element (NULL by default)
1648 
1649  /// \short Calculate the contributions to the jacobian from the nodal
1650  /// degrees of freedom using finite differences.
1651  /// This version of the function assumes that the residuals vector has
1652  /// already been calculated
1653  virtual void fill_in_jacobian_from_nodal_by_fd(Vector<double> &residuals,
1654  DenseMatrix<double> &jacobian);
1655 
1656  /// \short Calculate the contributions to the jacobian from the nodal
1657  /// degrees of freedom using finite differences. This version computes
1658  /// the residuals vector before calculating the jacobian terms.
1660  {
1661  //Allocate storage for a residuals vector and initialise to zero
1662  unsigned n_dof = ndof();
1663  Vector<double> residuals(n_dof,0.0);
1664  //Get the residuals for the entire element
1665  get_residuals(residuals);
1666  //Call the jacobian calculation
1667  fill_in_jacobian_from_nodal_by_fd(residuals,jacobian);
1668  }
1669 
1670  /// \short Function that is called before the finite differencing of
1671  /// any nodal data. This may be overloaded to update any slaved
1672  /// data before finite differencing takes place.
1673  virtual inline void update_before_nodal_fd() { }
1674 
1675  /// \short Function that is call after the finite differencing of
1676  /// the nodal data. This may be overloaded to reset any slaved
1677  /// variables that may have changed during the finite differencing.
1678  virtual inline void reset_after_nodal_fd() { }
1679 
1680  /// \short Function called within the finite difference loop for
1681  /// nodal data after a change in the i-th nodal value.
1682  virtual inline void update_in_nodal_fd(const unsigned &i) { }
1683 
1684  /// \short Function called within the finite difference loop for
1685  /// nodal data after the i-th nodal values is reset.
1686  /// The default behaviour is to call the update function.
1687  virtual inline void reset_in_nodal_fd(const unsigned &i)
1688  {update_in_nodal_fd(i);}
1689 
1690 
1691  /// \short Add the elemental contribution to the jacobian matrix.
1692  /// and the residuals vector. Note that
1693  /// this function will NOT initialise the residuals vector or the jacobian
1694  /// matrix. It must be called after the residuals vector and
1695  /// jacobian matrix have been initialised to zero. The default
1696  /// is to use finite differences to calculate the jacobian
1698  DenseMatrix<double> &jacobian)
1699  {
1700  //Add the contribution to the residuals
1702  //Allocate storage for the full residuals (residuals of entire element)
1703  unsigned n_dof = ndof();
1704  Vector<double> full_residuals(n_dof);
1705  //Get the residuals for the entire element
1706  get_residuals(full_residuals);
1707  //Calculate the contributions from the internal dofs
1708  //(finite-difference the lot by default)
1709  fill_in_jacobian_from_internal_by_fd(full_residuals,jacobian,true);
1710  //Calculate the contributions from the external dofs
1711  //(finite-difference the lot by default)
1712  fill_in_jacobian_from_external_by_fd(full_residuals,jacobian,true);
1713  //Calculate the contributions from the nodal dofs
1714  fill_in_jacobian_from_nodal_by_fd(full_residuals,jacobian);
1715  }
1716 
1717 public:
1718 
1719 
1720  /// \short Function pointer for function that computes vector-valued
1721  /// steady "exact solution" \f$ {\bf f}({\bf x}) \f$
1722  /// as \f$ \mbox{\tt fct}({\bf x}, {\bf f}) \f$.
1723  typedef void (*SteadyExactSolutionFctPt)(const Vector<double>&,
1724  Vector<double>&);
1725 
1726  /// \short Function pointer for function that computes Vector-valued
1727  /// time-dependent function \f$ {\bf f}(t,{\bf x}) \f$
1728  /// as \f$ \mbox{\tt fct}(t, {\bf x}, {\bf f}) \f$.
1729  typedef void (*UnsteadyExactSolutionFctPt)(const double&,
1730  const Vector<double>&,
1731  Vector<double>&);
1732 
1733  /// \short Tolerance below which the jacobian is considered singular
1735 
1736  /// \short Boolean that if set to true allows a negative jacobian
1737  /// in the transform between global and local coordinates (negative surface
1738  /// area = left-handed coordinate system).
1740 
1741  /// \short Static boolean to suppress output while checking
1742  /// for inverted elements
1744 
1745  /// Constructor
1746  FiniteElement() : GeneralisedElement(), Integral_pt(0),
1747  Node_pt(0), Nodal_local_eqn(0), Nnode(0),
1748  Elemental_dimension(0), Nodal_dimension(0), Nnodal_position_type(1),
1749  Macro_elem_pt(0) {}
1750 
1751  /// \short The destructor cleans up the static memory allocated
1752  /// for shape function storage. Internal and external data get
1753  /// wiped by the GeneralisedElement destructor; nodes get
1754  /// killed in mesh destructor.
1755  virtual ~FiniteElement();
1756 
1757  /// Broken copy constructor
1759  {
1760  BrokenCopy::broken_copy("FiniteElement");
1761  }
1762 
1763  /// Broken assignment operator
1764 //Commented out broken assignment operator because this can lead to a conflict warning
1765 //when used in the virtual inheritence hierarchy. Essentially the compiler doesn't
1766 //realise that two separate implementations of the broken function are the same and so,
1767 //quite rightly, it shouts.
1768  /*void operator=(const FiniteElement&)
1769  {
1770  BrokenCopy::broken_assign("FiniteElement");
1771  }*/
1772 
1773  ///Check whether the local coordinate are valid or not
1774  virtual bool local_coord_is_valid(const Vector<double> &s)
1775  {
1776  throw OomphLibError(
1777  "local_coord_is_valid is not implemented for this element\n",
1778  OOMPH_CURRENT_FUNCTION,
1779  OOMPH_EXCEPTION_LOCATION);
1780  return true;
1781  }
1782 
1783  ///\short Adjust local coordinates so that they're located inside
1784  /// the element
1785  virtual void move_local_coord_back_into_element(Vector<double> &s) const
1786  {
1787  throw OomphLibError(
1788  "move_local_coords_back_into_element() is not implemented for this element\n",
1789  OOMPH_CURRENT_FUNCTION,
1790  OOMPH_EXCEPTION_LOCATION);
1791  }
1792 
1793 
1794  /// \short Compute centre of gravity of all nodes and radius of node that
1795  /// is furthest from it. Used to assess approximately if a point
1796  /// is likely to be contained with an element in locate_zeta-like
1797  /// operations
1798  void get_centre_of_gravity_and_max_radius_in_terms_of_zeta(
1799  Vector<double>& cog, double& max_radius) const;
1800 
1801  /// \short Get local coordinates of node j in the element; vector
1802  /// sets its own size (broken virtual)
1803  virtual void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
1804  {
1805  throw OomphLibError(
1806  "local_coordinate_of_node(...) is not implemented for this element\n",
1807  OOMPH_CURRENT_FUNCTION,
1808  OOMPH_EXCEPTION_LOCATION);
1809  }
1810 
1811  /// \short Get the local fraction of the node j in the element
1812  /// A dumb, but correct default implementation is provided.
1813  virtual void local_fraction_of_node(const unsigned &j,
1814  Vector<double> &s_fraction);
1815 
1816  /// \short Get the local fraction of any node in the n-th position
1817  /// in a one dimensional expansion along the i-th local coordinate
1818  virtual double local_one_d_fraction_of_node(const unsigned &n1d,
1819  const unsigned &i)
1820  {
1821  std::string error_message =
1822  "local one_d_fraction_of_node is not implemented for this element\n";
1823  error_message +=
1824  "It only makes sense for elements that use tensor-product expansions\n";
1825 
1826  throw OomphLibError(error_message,
1827  OOMPH_CURRENT_FUNCTION,
1828  OOMPH_EXCEPTION_LOCATION);
1829  }
1830 
1831  /// \short Set pointer to macro element -- can be overloaded in derived
1832  /// elements to perform additional tasks
1833  virtual void set_macro_elem_pt(MacroElement* macro_elem_pt)
1834  {Macro_elem_pt=macro_elem_pt;}
1835 
1836  ///Access function to pointer to macro element
1837  MacroElement* macro_elem_pt() {return Macro_elem_pt;}
1838 
1839  /// \short Global coordinates as function of local coordinates.
1840  /// Either via FE representation or via macro-element (if Macro_elem_pt!=0)
1841  void get_x(const Vector<double> &s, Vector<double> &x) const
1842  {
1843  //If there is no macro element then return interpolated x
1844  if(Macro_elem_pt==0) {interpolated_x(s,x);}
1845  //Otherwise call the macro element representation
1846  else {get_x_from_macro_element(s,x);}
1847  }
1848 
1849 
1850  /// \short Global coordinates as function of local coordinates
1851  /// at previous time "level" t (t=0: present; t>0: previous).
1852  /// Either via FE representation of QElement or
1853  /// via macro-element (if Macro_elem_pt!=0).
1854  void get_x(const unsigned &t, const Vector<double> &s,
1855  Vector<double> &x)
1856  {
1857  // Get timestepper from first node
1858  TimeStepper* time_stepper_pt=node_pt(0)->time_stepper_pt();
1859 
1860  // Number of previous values
1861  const unsigned nprev=time_stepper_pt->nprev_values();
1862 
1863  // If t > nprev_values(), we're not dealing with a previous value
1864  // but a generalised history value -- this cannot be recovered from
1865  // macro element but must be determined by finite element interpolation
1866 
1867  //If there is no macro element, or we're dealing with a generalised
1868  //history value then use the FE representation
1869  if((Macro_elem_pt==0)||(t>nprev)) {interpolated_x(t,s,x);}
1870  //Otherwise use the macro element representation
1871  else {get_x_from_macro_element(t,s,x);}
1872  }
1873 
1874 
1875  /// \short Global coordinates as function of local coordinates
1876  /// using macro element representation.
1877  /// (Broken virtual --- this must be overloaded in specific geometric
1878  /// element classes)
1879  virtual void get_x_from_macro_element(const Vector<double>& s,
1880  Vector<double>& x) const
1881  {
1882  throw OomphLibError(
1883  "get_x_from_macro_element(...) is not implemented for this element\n",
1884  OOMPH_CURRENT_FUNCTION,
1885  OOMPH_EXCEPTION_LOCATION);
1886  }
1887 
1888  /// \short Global coordinates as function of local coordinates
1889  /// at previous time "level" t (t=0: present; t>0: previous).
1890  /// using macro element representation
1891  /// (Broken virtual -- overload in specific geometric element class
1892  /// if you want to use this functionality.)
1893  virtual void get_x_from_macro_element(const unsigned& t,
1894  const Vector<double>& s,
1895  Vector<double>& x)
1896  {
1897  throw OomphLibError(
1898  "get_x_from_macro_element(...) is not implemented for this element\n",
1899  OOMPH_CURRENT_FUNCTION,
1900  OOMPH_EXCEPTION_LOCATION);
1901  }
1902 
1903 
1904  ///Set the spatial integration scheme
1905  virtual void set_integration_scheme(Integral* const &integral_pt);
1906 
1907  /// Return the pointer to the integration scheme (const version)
1908  Integral* const &integral_pt() const {return Integral_pt;}
1909 
1910  /// \short Calculate the geometric shape functions
1911  /// at local coordinate s. This function must be overloaded for each specific
1912  /// geometric element.
1913  virtual void shape(const Vector<double> &s, Shape &psi) const=0;
1914 
1915  /// \short Return the geometric shape function at the ipt-th integration point
1916  virtual void shape_at_knot(const unsigned &ipt, Shape &psi) const;
1917 
1918  /// \short Function to compute the geometric shape functions and
1919  /// derivatives w.r.t. local coordinates at local coordinate s.
1920  /// This function must be overloaded for each specific geometric element.
1921  /// (Broken virtual function --- specifies the interface)
1922  virtual void dshape_local(const Vector<double> &s, Shape &psi,
1923  DShape &dpsids) const
1924  {
1925  throw OomphLibError(
1926  "dshape_local() is not implemented for this element\n",
1927  OOMPH_CURRENT_FUNCTION,
1928  OOMPH_EXCEPTION_LOCATION);
1929  }
1930 
1931  /// \short Return the geometric shape function and its derivative w.r.t.
1932  /// the local coordinates at the ipt-th integration point.
1933  virtual void dshape_local_at_knot(const unsigned &ipt, Shape &psi,
1934  DShape &dpsids) const;
1935 
1936  /// \short Function to compute the geometric shape functions and also
1937  /// first and second derivatives w.r.t.
1938  /// local coordinates at local coordinate s. This function must
1939  /// be overloaded for each specific geometric element (if required).
1940  /// (Broken virtual function --- specifies the interface).
1941  /// Numbering:
1942  /// \b 1D:
1943  /// d2psids(i,0) = \f$ d^2 \psi_j / ds^2 \f$
1944  /// \b 2D:
1945  /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
1946  /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
1947  /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
1948  /// \b 3D:
1949  /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
1950  /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
1951  /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_2^2 \f$
1952  /// d2psids(i,3) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
1953  /// d2psids(i,4) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_2 \f$
1954  /// d2psids(i,5) = \f$ \partial^2 \psi_j / \partial s_1 \partial s_2 \f$
1955  virtual void d2shape_local(const Vector<double> &s,
1956  Shape &psi,
1957  DShape &dpsids,
1958  DShape &d2psids) const
1959  {
1960  throw OomphLibError(
1961  "d2shape_local() is not implemented for this element\n",
1962  OOMPH_CURRENT_FUNCTION,
1963  OOMPH_EXCEPTION_LOCATION);
1964  }
1965 
1966  /// \short Return the geometric shape function and its first and
1967  /// second derivatives w.r.t.
1968  /// the local coordinates at the ipt-th integration point.
1969  /// Numbering:
1970  /// \b 1D:
1971  /// d2psids(i,0) = \f$ d^2 \psi_j / ds^2 \f$
1972  /// \b 2D:
1973  /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
1974  /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
1975  /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
1976  /// \b 3D:
1977  /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
1978  /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
1979  /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_2^2 \f$
1980  /// d2psids(i,3) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
1981  /// d2psids(i,4) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_2 \f$
1982  /// d2psids(i,5) = \f$ \partial^2 \psi_j / \partial s_1 \partial s_2 \f$
1983  virtual void d2shape_local_at_knot(const unsigned &ipt, Shape &psi,
1984  DShape &dpsids, DShape &d2psids) const;
1985 
1986  /// \short Return the Jacobian of mapping from local to global
1987  /// coordinates at local position s.
1988  virtual double J_eulerian(const Vector<double> &s) const;
1989 
1990  /// \short Return the Jacobian of the mapping from local to global
1991  /// coordinates at the ipt-th integration point
1992  virtual double J_eulerian_at_knot(const unsigned &ipt) const;
1993 
1994 /// \short Check that Jacobian of mapping between local and Eulerian
1995 /// coordinates at all integration points is positive.
1996  void check_J_eulerian_at_knots(bool& passed) const;
1997 
1998  /// \short Helper function used to check for singular or negative
1999  /// Jacobians in the transform from local to global or Lagrangian
2000  /// coordinates.
2001  void check_jacobian(const double &jacobian) const;
2002 
2003  /// \short Compute the geometric shape functions and also
2004  /// first derivatives w.r.t. global coordinates at local coordinate s;
2005  /// Returns Jacobian of mapping from global to local coordinates.
2006  double dshape_eulerian(const Vector<double> &s, Shape &psi,
2007  DShape &dpsidx) const;
2008 
2009  /// \short Return the geometric shape functions and also first
2010  /// derivatives w.r.t. global coordinates at the ipt-th integration point.
2011  virtual double dshape_eulerian_at_knot(const unsigned &ipt, Shape &psi,
2012  DShape &dpsidx) const;
2013 
2014  /// \short Compute the geometric shape functions (psi) and first derivatives
2015  /// w.r.t. global coordinates (dpsidx) at the ipt-th integration point.
2016  /// Return the determinant of the jacobian of the mapping (detJ).
2017  /// Additionally calculate the derivatives of both "detJ" and "dpsidx"
2018  /// w.r.t. the nodal coordinates.
2019  virtual double dshape_eulerian_at_knot(
2020  const unsigned &ipt,Shape &psi,DShape &dpsi,
2021  DenseMatrix<double> &djacobian_dX,RankFourTensor<double> &d_dpsidx_dX) const;
2022 
2023  /// \short Compute the geometric shape functions and also first
2024  /// and second derivatives w.r.t. global coordinates at local coordinate s;
2025  /// Returns Jacobian of mapping from global to local coordinates.
2026  /// Numbering:
2027  /// \b 1D:
2028  /// d2psidx(i,0) = \f$ d^2 \psi_j / d x^2 \f$
2029  /// \b 2D:
2030  /// d2psidx(i,0) = \f$ \partial^2 \psi_j / \partial x_0^2 \f$
2031  /// d2psidx(i,1) = \f$ \partial^2 \psi_j / \partial x_1^2 \f$
2032  /// d2psidx(i,2) = \f$ \partial^2 \psi_j / \partial x_0 \partial x_1 \f$
2033  /// \b 3D:
2034  /// d2psidx(i,0) = \f$ \partial^2 \psi_j / \partial x_0^2 \f$
2035  /// d2psidx(i,1) = \f$ \partial^2 \psi_j / \partial x_1^2 \f$
2036  /// d2psidx(i,2) = \f$ \partial^2 \psi_j / \partial x_2^2 \f$
2037  /// d2psidx(i,3) = \f$ \partial^2 \psi_j / \partial x_0 \partial x_1 \f$
2038  /// d2psidx(i,4) = \f$ \partial^2 \psi_j / \partial x_0 \partial x_2 \f$
2039  /// d2psidx(i,5) = \f$ \partial^2 \psi_j / \partial x_1 \partial x_2 \f$
2040  double d2shape_eulerian(const Vector<double> &s, Shape &psi,
2041  DShape &dpsidx, DShape &d2psidx) const;
2042 
2043 
2044  /// \short Return the geometric shape functions and also first
2045  /// and second derivatives w.r.t. global coordinates at ipt-th integration
2046  /// point.
2047  /// Numbering:
2048  /// \b 1D:
2049  /// d2psidx(i,0) = \f$ d^2 \psi_j / d s^2 \f$
2050  /// \b 2D:
2051  /// d2psidx(i,0) = \f$ \partial^2 \psi_j / \partial x_0^2 \f$
2052  /// d2psidx(i,1) = \f$ \partial^2 \psi_j / \partial x_1^2 \f$
2053  /// d2psidx(i,2) = \f$ \partial^2 \psi_j / \partial x_0 \partial x_1 \f$
2054  /// \b 3D:
2055  /// d2psidx(i,0) = \f$ \partial^2 \psi_j / \partial x_0^2 \f$
2056  /// d2psidx(i,1) = \f$ \partial^2 \psi_j / \partial x_1^2 \f$
2057  /// d2psidx(i,2) = \f$ \partial^2 \psi_j / \partial x_2^2 \f$
2058  /// d2psidx(i,3) = \f$ \partial^2 \psi_j / \partial x_0 \partial x_1 \f$
2059  /// d2psidx(i,4) = \f$ \partial^2 \psi_j / \partial x_0 \partial x_2 \f$
2060  /// d2psidx(i,5) = \f$ \partial^2 \psi_j / \partial x_1 \partial x_2 \f$
2061  virtual double d2shape_eulerian_at_knot(const unsigned &ipt, Shape &psi,
2062  DShape &dpsidx,
2063  DShape &d2psidx) const;
2064 
2065  /// \short Assign the local equation numbers for Data stored at the nodes
2066  /// Virtual so that it can be overloaded by RefineableFiniteElements.
2067  /// If the boolean is true then the pointers to the degrees of freedom
2068  /// associated with each equation number are stored in Dof_pt
2069  virtual void assign_nodal_local_eqn_numbers(
2070  const bool &store_local_dof_pt);
2071 
2072  /// \short Function to describe the local dofs of the element[s]. The ostream
2073  /// specifies the output stream to which the description
2074  /// is written; the string stores the currently
2075  /// assembled output that is ultimately written to the
2076  /// output stream by Data::describe_dofs(...); it is typically
2077  /// built up incrementally as we descend through the
2078  /// call hierarchy of this function when called from
2079  /// Problem::describe_dofs(...)
2080  virtual void describe_local_dofs(std::ostream& out,
2081  const std::string& current_string) const;
2082 
2083  /// \short Function to describe the local dofs of the element[s]. The ostream
2084  /// specifies the output stream to which the description
2085  /// is written; the string stores the currently
2086  /// assembled output that is ultimately written to the
2087  /// output stream by Data::describe_dofs(...); it is typically
2088  /// built up incrementally as we descend through the
2089  /// call hierarchy of this function when called from
2090  /// Problem::describe_dofs(...)
2091  virtual void describe_nodal_local_dofs(
2092  std::ostream& out,
2093  const std::string& current_string) const;
2094 
2095  /// \short Overloaded version of the calculation of the local equation
2096  /// numbers. If the boolean argument is true then pointers to the degrees
2097  /// of freedom associated with each equation number are stored locally
2098  /// in the array Dof_pt.
2100  const bool &store_local_dof_pt)
2101  {
2102  //GeneralisedElement's version assigns internal and external data
2104  //Need simply to add the nodal numbering scheme
2105  assign_nodal_local_eqn_numbers(store_local_dof_pt);
2106  }
2107 
2108  /// Return a pointer to the local node n
2109  Node* &node_pt(const unsigned &n)
2110  {
2111 #ifdef RANGE_CHECKING
2112  if(n >= Nnode)
2113  {
2114  std::ostringstream error_message;
2115  error_message << "Range Error: " << n
2116  << " is not in the range (0,"
2117  << Nnode-1 << ")";
2118  throw OomphLibError(error_message.str(),
2119  OOMPH_CURRENT_FUNCTION,
2120  OOMPH_EXCEPTION_LOCATION);
2121  }
2122 #endif
2123  return Node_pt[n];
2124  }
2125 
2126  /// Return a pointer to the local node n (const version)
2127  Node* const &node_pt(const unsigned &n) const
2128  {
2129 #ifdef RANGE_CHECKING
2130  if(n >= Nnode)
2131  {
2132  std::ostringstream error_message;
2133  error_message << "Range Error: " << n
2134  << " is not in the range (0,"
2135  << Nnode-1 << ")";
2136  throw OomphLibError(error_message.str(),
2137  OOMPH_CURRENT_FUNCTION,
2138  OOMPH_EXCEPTION_LOCATION);
2139  }
2140 #endif
2141 
2142  return Node_pt[n];
2143  }
2144 
2145  /// Return the number of nodes
2146  unsigned nnode() const {return Nnode;}
2147 
2148  /// \short Return the number of nodes along one edge of the element
2149  /// Default is to return zero --- must be overloaded by geometric
2150  /// elements
2151  virtual unsigned nnode_1d() const {return 0;}
2152 
2153  /// \short Return the i-th coordinate at local node n. Do not use
2154  /// the hanging node representation.
2155  /// NOTE: Moved to cc file because of a possible compiler bug
2156  /// in gcc (yes, really!). The move to the cc file avoids inlining
2157  /// which appears to cause problems (only) when compiled with gcc
2158  /// and -O3; offensive "illegal read" is in optimised-out section
2159  /// of code and data that is allegedly illegal is readily readable
2160  /// (by other means) just before this function is called so I can't
2161  /// really see how we could possibly be responsible for this...
2162  double raw_nodal_position(const unsigned &n, const unsigned &i) const;
2163  /* { */
2164  /* /\* oomph_info << "n: "<< n << std::endl; *\/ */
2165  /* /\* oomph_info << "i: "<< i << std::endl; *\/ */
2166  /* /\* oomph_info << "node_pt(n): "<< node_pt(n) << std::endl; *\/ */
2167  /* /\* oomph_info << "node_pt(n)->x(i): "<< node_pt(n)->x(i) << std::endl; *\/ */
2168  /* double tmp=node_pt(n)->x(i); */
2169  /* //oomph_info << "tmp: "<< tmp << std::endl; */
2170  /* return tmp; // node_pt(n)->x(i); */
2171  /* } */
2172 
2173  /// \short Return the i-th coordinate at local node n, at time level t
2174  /// (t=0: present; t>0: previous time level).
2175  /// Do not use the hanging node representation.
2176  double raw_nodal_position(const unsigned &t, const unsigned &n,
2177  const unsigned &i) const
2178  {return node_pt(n)->x(t,i);}
2179 
2180  /// \short Return the i-th component of nodal velocity: dx/dt at local node n.
2181  /// Do not use the hanging node representation.
2182  double raw_dnodal_position_dt(const unsigned &n, const unsigned &i) const
2183  {return node_pt(n)->dx_dt(i);}
2184 
2185  /// \short Return the i-th component of j-th derivative of nodal position:
2186  /// d^jx/dt^j at node n. Do not use the hanging node representation.
2187  double raw_dnodal_position_dt(const unsigned &n, const unsigned &j,
2188  const unsigned &i) const
2189  {return node_pt(n)->dx_dt(j,i);}
2190 
2191  /// \short Return the value of the k-th type of the i-th positional variable
2192  /// at the local node n. Do not use the hanging node representation.
2193  double raw_nodal_position_gen(const unsigned &n, const unsigned &k,
2194  const unsigned &i) const
2195  {return node_pt(n)->x_gen(k,i);}
2196 
2197  /// \short Return the generalised nodal position (type k, i-th variable)
2198  /// at previous timesteps at local node n. Do not use the hanging node
2199  /// representation.
2200  double raw_nodal_position_gen(const unsigned &t, const unsigned &n,
2201  const unsigned &k, const unsigned &i) const
2202  {return node_pt(n)->x_gen(t,k,i);}
2203 
2204  /// \short i-th component of time derivative (velocity) of the
2205  /// generalised position, dx(k,i)/dt at local node n.
2206  /// `Type': k; Coordinate direction: i. Do not use the hanging node
2207  /// representation.
2208  double raw_dnodal_position_gen_dt(const unsigned &n,
2209  const unsigned &k,
2210  const unsigned &i) const
2211  {return node_pt(n)->dx_gen_dt(k,i);}
2212 
2213  /// \short i-th component of j-th time derivative of the
2214  /// generalised position, dx(k,i)/dt at local node n.
2215  /// `Type': k; Coordinate direction: i. Do not use the hanging node
2216  /// representation.
2217  double raw_dnodal_position_gen_dt(const unsigned &j,
2218  const unsigned &n,
2219  const unsigned &k,
2220  const unsigned &i) const
2221  {return node_pt(n)->dx_gen_dt(j,k,i);}
2222 
2223 
2224  /// \short Return the i-th coordinate at local node n. If the
2225  /// node is hanging, the appropriate interpolation is handled by the
2226  /// position function in the Node class.
2227  double nodal_position(const unsigned &n, const unsigned &i) const
2228  {return node_pt(n)->position(i);}
2229 
2230  /// \short Return the i-th coordinate at local node n, at time level t
2231  /// (t=0: present; t>0: previous time level)
2232  /// Returns suitably interpolated version for hanging nodes.
2233  double nodal_position(const unsigned &t, const unsigned &n,
2234  const unsigned &i) const
2235  {return node_pt(n)->position(t,i);}
2236 
2237  /// Return the i-th component of nodal velocity: dx/dt at local node n.
2238  double dnodal_position_dt(const unsigned &n, const unsigned &i) const
2239  {return node_pt(n)->dposition_dt(i);}
2240 
2241  /// \short Return the i-th component of j-th derivative of nodal position:
2242  /// d^jx/dt^j at node n.
2243  double dnodal_position_dt(const unsigned &n, const unsigned &j,
2244  const unsigned &i) const
2245  {return node_pt(n)->dposition_dt(j,i);}
2246 
2247  /// \short Return the value of the k-th type of the i-th positional variable
2248  /// at the local node n.
2249  double nodal_position_gen(const unsigned &n, const unsigned &k,
2250  const unsigned &i) const
2251  {return node_pt(n)->position_gen(k,i);}
2252 
2253  /// \short Return the generalised nodal position (type k, i-th variable)
2254  /// at previous timesteps at local node n
2255  double nodal_position_gen(const unsigned &t, const unsigned &n,
2256  const unsigned &k, const unsigned &i) const
2257  {return node_pt(n)->position_gen(t,k,i);}
2258 
2259  /// \short i-th component of time derivative (velocity) of the
2260  /// generalised position, dx(k,i)/dt at local node n.
2261  /// `Type': k; Coordinate direction: i.
2262  double dnodal_position_gen_dt(const unsigned &n,
2263  const unsigned &k,
2264  const unsigned &i) const
2265  {return node_pt(n)->dposition_gen_dt(k,i);}
2266 
2267  /// \short i-th component of j-th time derivative of the
2268  /// generalised position, dx(k,i)/dt at local node n.
2269  /// `Type': k; Coordinate direction: i.
2270  double dnodal_position_gen_dt(const unsigned &j,
2271  const unsigned &n,
2272  const unsigned &k,
2273  const unsigned &i) const
2274  {return node_pt(n)->dposition_gen_dt(j,k,i);}
2275 
2276 
2277  /// \short Compute derivatives of elemental residual vector with respect
2278  /// to nodal coordinates. Default implementation by FD can be overwritten
2279  /// for specific elements.
2280  /// dresidual_dnodal_coordinates(l,i,j) = d res(l) / dX_{ij}
2281  virtual void get_dresidual_dnodal_coordinates(RankThreeTensor<double>&
2282  dresidual_dnodal_coordinates);
2283 
2284  /// \short This is an empty function that establishes a uniform
2285  /// interface for all (derived) elements that involve time-derivatives.
2286  /// Such elements are/should be implemented in ALE form to allow
2287  /// mesh motions. The additional expense associated with the
2288  /// computation of the mesh velocities is, of course, superfluous
2289  /// if the elements are used in problems in which the mesh is
2290  /// stationary. This function should therefore be overloaded
2291  /// in all derived elements that are formulated in ALE form
2292  /// to suppress the computation of the mesh velocities.
2293  /// The user disables the ALE functionality at his/her own risk!
2294  /// If the mesh does move after all, then the results will be wrong.
2295  /// Here we simply issue a warning message stating that the empty
2296  /// function has been called.
2297  virtual void disable_ALE()
2298  {
2299  std::ostringstream warn_message;
2300  warn_message
2301  << "Warning: You have just called the default (empty) function \n\n"
2302  << " FiniteElement::disable_ALE() \n\n"
2303  << "This suggests that you've either tried to call it for an element\n"
2304  << "that \n"
2305  << "(1) does not involve time-derivatives (e.g. a Poisson element) \n"
2306  << "(2) an element for which the time-derivatives aren't implemented \n"
2307  << " in ALE form \n"
2308  << "(3) an element for which the ALE form of the equations can't be \n"
2309  << " be disabled (yet).\n";
2310  OomphLibWarning(warn_message.str(),
2311  "Problem::disable_ALE()",
2312  OOMPH_EXCEPTION_LOCATION);
2313  }
2314 
2315 
2316  /// \short (Re-)enable ALE, i.e. take possible mesh motion into account
2317  /// when evaluating the time-derivative. This function is empty
2318  /// and simply establishes a common interface for all derived
2319  /// elements that are formulated in ALE form.
2320  virtual void enable_ALE()
2321  {
2322  std::ostringstream warn_message;
2323  warn_message
2324  << "Warning: You have just called the default (empty) function \n\n"
2325  << " FiniteElement::enable_ALE() \n\n"
2326  << "This suggests that you've either tried to call it for an element\n"
2327  << "that \n"
2328  << "(1) does not involve time-derivatives (e.g. a Poisson element) \n"
2329  << "(2) an element for which the time-derivatives aren't implemented \n"
2330  << " in ALE form \n"
2331  << "(3) an element for which the ALE form of the equations can't be \n"
2332  << " be disabled (yet)\n"
2333  << "(4) an element for which this function has not been (properly) \n "
2334  << " implemented. This is likely to be a bug!\n ";
2335  OomphLibWarning(warn_message.str(),
2336  "Problem::enable_ALE()",
2337  OOMPH_EXCEPTION_LOCATION);
2338  }
2339 
2340  /// \short Number of values that must be stored at local node n by
2341  /// the element. The default is 0, until over-ridden by a particular element.
2342  /// For example, a Poisson equation requires only one value to be stored
2343  /// at each node; 2D Navier--Stokes equations require two values (velocity
2344  /// components) to be stored at each Node
2345  /// (provided that the pressure interpolation is discontinuous).
2346  virtual unsigned required_nvalue(const unsigned &n) const
2347  {return Default_Initial_Nvalue;}
2348 
2349  /// \short Return the number of coordinate types that the element requires
2350  /// to interpolate the geometry between
2351  /// the nodes. For Lagrange elements it is 1.
2352  unsigned nnodal_position_type() const {return Nnodal_position_type;}
2353 
2354  /// \short Return boolean to indicate if any of the element's nodes
2355  /// are geometrically hanging.
2356  bool has_hanging_nodes() const
2357  {
2358  unsigned nnod=nnode();
2359  for(unsigned j=0;j<nnod;j++)
2360  {
2361  if(node_pt(j)->is_hanging())
2362  {
2363  return true;
2364  }
2365  }
2366  return false;
2367  }
2368 
2369  /// Return the required Eulerian dimension of the nodes in this element
2370  unsigned nodal_dimension() const {return Nodal_dimension;}
2371 
2372  /// Return the number of vertex nodes in this element. Broken virtual
2373  /// function in "pure" finite elements.
2374  virtual unsigned nvertex_node() const
2375  {
2376  std::string error_msg = "Not implemented for FiniteElement.";
2377  throw OomphLibError(error_msg, OOMPH_CURRENT_FUNCTION,
2378  OOMPH_EXCEPTION_LOCATION);
2379  }
2380 
2381  /// \short Pointer to the j-th vertex node in the element. Broken virtual
2382  /// function in "pure" finite elements.
2383  virtual Node* vertex_node_pt(const unsigned& j) const
2384  {
2385  std::string error_msg = "Not implemented for FiniteElement.";
2386  throw OomphLibError(error_msg, OOMPH_CURRENT_FUNCTION,
2387  OOMPH_EXCEPTION_LOCATION);
2388  }
2389 
2390  /// \short Construct the local node n and return a pointer to the newly
2391  /// created node object.
2392  virtual Node* construct_node(const unsigned &n)
2393  {
2394  //Create a node and assign it to the local node pointer
2395  //The dimension and number of values are taken from internal element data
2396  node_pt(n) = new Node(Nodal_dimension, Nnodal_position_type,
2397  required_nvalue(n));
2398  //Now return a pointer to the node, so that the mesh can use it
2399  return node_pt(n);
2400  }
2401 
2402  /// \short Construct the local node n, including
2403  /// storage for history values required by timestepper, and return a pointer
2404  /// to the newly created node object.
2405  virtual Node* construct_node(const unsigned &n,
2406  TimeStepper* const &time_stepper_pt)
2407  {
2408  //Create a node and assign it to the local node pointer.
2409  //The dimension and number of values are taken from internal element data
2410  node_pt(n) = new Node(time_stepper_pt, Nodal_dimension,
2411  Nnodal_position_type,
2412  required_nvalue(n));
2413  //Now return a pointer to the node, so that the mesh can find it
2414  return node_pt(n);
2415  }
2416 
2417  /// \short Construct the local node n as a boundary node;
2418  /// that is a node that MAY be placed on a mesh boundary
2419  /// and return a pointer to the newly created node object.
2420  virtual Node* construct_boundary_node(const unsigned &n)
2421  {
2422  //Create a node and assign it to the local node pointer
2423  //The dimension and number of values are taken from internal element data
2424  node_pt(n) = new BoundaryNode<Node>(Nodal_dimension,
2425  Nnodal_position_type,
2426  required_nvalue(n));
2427  //Now return a pointer to the node, so that the mesh can use it
2428  return node_pt(n);
2429  }
2430 
2431  /// \short Construct the local node n, including
2432  /// storage for history values required by timestepper,
2433  /// as a boundary node; that is a node that MAY be placed on a mesh
2434  /// boundary and return a pointer to the newly created node object.
2435  virtual Node* construct_boundary_node(const unsigned &n,
2436  TimeStepper* const &time_stepper_pt)
2437  {
2438  //Create a node and assign it to the local node pointer.
2439  //The dimension and number of values are taken from internal element data
2440  node_pt(n) = new BoundaryNode<Node>(time_stepper_pt, Nodal_dimension,
2441  Nnodal_position_type,
2442  required_nvalue(n));
2443  //Now return a pointer to the node, so that the mesh can find it
2444  return node_pt(n);
2445  }
2446 
2447  /// \short Return the number of the node *node_pt if this node
2448  /// is in the element, else return -1;
2449  int get_node_number(Node* const &node_pt) const;
2450 
2451 
2452  /// \short If there is a node at this local coordinate, return the pointer to
2453  /// the node
2454  virtual Node* get_node_at_local_coordinate(const Vector<double> &s) const;
2455 
2456  /// \short Return the i-th value stored at local node n
2457  /// but do NOT take hanging nodes into account
2458  double raw_nodal_value(const unsigned &n, const unsigned &i) const
2459  {return node_pt(n)->raw_value(i);}
2460 
2461  /// \short Return the i-th value stored at local node n, at time level t
2462  /// (t=0: present; t>0 previous timesteps), but do NOT take hanging nodes
2463  /// into account
2464  double raw_nodal_value(const unsigned &t, const unsigned &n,
2465  const unsigned &i)
2466  const {return node_pt(n)->raw_value(t,i);}
2467 
2468  /// \short Return the i-th value stored at local node n.
2469  /// Produces suitably interpolated values for hanging nodes.
2470  double nodal_value(const unsigned &n, const unsigned &i) const
2471  {return node_pt(n)->value(i);}
2472 
2473  /// \short Return the i-th value stored at local node n, at time level t
2474  /// (t=0: present; t>0 previous timesteps). Produces suitably interpolated
2475  /// values for hanging nodes.
2476  double nodal_value(const unsigned &t, const unsigned &n, const unsigned &i)
2477  const {return node_pt(n)->value(t,i);}
2478 
2479  /// \short Return the spatial dimension of the element, i.e.
2480  /// the number of local coordinates required to parametrise its
2481  /// geometry.
2482  unsigned dim() const {return Elemental_dimension;}
2483 
2484  /// Return the geometry type of the element (either Q or T usually).
2486  {
2487  std::string err = "Broken virtual function.";
2488  throw OomphLibError(err, OOMPH_CURRENT_FUNCTION,
2489  OOMPH_EXCEPTION_LOCATION);
2490  }
2491 
2492  /// Return FE interpolated coordinate x[i] at local coordinate s
2493  virtual double interpolated_x(const Vector<double> &s,
2494  const unsigned &i) const;
2495 
2496  ///\short Return FE interpolated coordinate x[i] at local coordinate s
2497  ///at previous timestep t (t=0: present; t>0: previous timestep)
2498  virtual double interpolated_x(const unsigned& t, const Vector<double> &s,
2499  const unsigned &i) const;
2500 
2501  /// Return FE interpolated position x[] at local coordinate s as Vector
2502  virtual void interpolated_x(const Vector<double> &s,Vector<double>& x) const;
2503 
2504  /// \short Return FE interpolated position x[] at local coordinate s
2505  /// at previous timestep t as Vector (t=0: present; t>0: previous timestep)
2506  virtual void interpolated_x(const unsigned& t, const Vector<double> &s,
2507  Vector<double>& x) const;
2508 
2509  /// \short Return t-th time-derivative of the
2510  /// i-th FE-interpolated Eulerian coordinate at
2511  /// local coordinate s.
2512  virtual double interpolated_dxdt(const Vector<double> &s,
2513  const unsigned &i,
2514  const unsigned &t);
2515 
2516  /// \short Compte t-th time-derivative of the
2517  /// FE-interpolated Eulerian coordinate vector at
2518  /// local coordinate s.
2519  virtual void interpolated_dxdt(const Vector<double> &s,
2520  const unsigned &t,
2521  Vector<double>& dxdt);
2522 
2523  /// \short A standard FiniteElement is fixed, so there are no geometric
2524  /// data when viewed in its GeomObject incarnation
2525  inline unsigned ngeom_data() const {return 0;}
2526 
2527  /// \short A standard FiniteElement is fixed, so there are no geometric
2528  /// data when viewed in its GeomObject incarnation
2529  inline Data* geom_data_pt(const unsigned &j) {return 0;}
2530 
2531  /// \short Return the parametrised position of the FiniteElement in
2532  /// its incarnation as a GeomObject, r(zeta).
2533  /// The position is given by the Eulerian coordinate and the intrinsic
2534  /// coordinate (zeta) is the local coordinate of the element (s).
2535  void position(const Vector<double>& zeta, Vector<double>& r)
2536  const {this->interpolated_x(zeta,r);}
2537 
2538  /// \short Return the parametrised position of the FiniteElement
2539  /// in its GeomObject incarnation:
2540  /// r(zeta). The position is given by the Eulerian coordinate and the
2541  /// intrinsic coordinate (zeta) is the local coordinate of the element (s)
2542  /// This version of the function returns the position as a function
2543  /// of time t=0: current time; t>0: previous
2544  /// timestep. Works for t=0 but needs to be overloaded
2545  /// if genuine time-dependence is required.
2546  void position(const unsigned& t, const Vector<double>& zeta,
2547  Vector<double>& r) const
2548  {this->interpolated_x(t,zeta,r);}
2549 
2550  /// \short Return the t-th time derivative of the
2551  /// parametrised position of the FiniteElement
2552  /// in its GeomObject incarnation:
2553  /// \f$ \frac{d^{t} dr(zeta)}{d t^{t}} \f$.
2554  /// Call the t-th time derivative of the FE-interpolated Eulerian coordinate
2555  void dposition_dt(const Vector<double> &zeta, const unsigned &t,
2556  Vector<double> &drdt)
2557  {this->interpolated_dxdt(zeta,t,drdt);}
2558 
2559  /// \short Specify the values of the "global" intrinsic coordinate, zeta,
2560  /// of a compound geometric object (a mesh of elements) when
2561  /// the element is viewied as a sub-geometric object.
2562  /// The default assumption is that the element will be
2563  /// treated as a sub-geometric object in a bulk Mesh of other elements
2564  /// (geometric objects). The "global" coordinate of the compound geometric
2565  /// object is simply the Eulerian coordinate, x.
2566  /// The second default assumption is that the coordinate zeta will
2567  /// be stored at the nodes and interpolated using the shape functions
2568  /// of the element. This function returns the value of zeta stored at
2569  /// local node n, where k is the type of coordinate and i is the
2570  /// coordinate direction. The function is virtual so that it can
2571  /// be overloaded by different types of element: FaceElements
2572  /// and SolidFiniteElements
2573  virtual double zeta_nodal(const unsigned &n, const unsigned &k,
2574  const unsigned &i) const
2575  {
2576  //By default return the value for nodal_position_gen
2577  return nodal_position_gen(n,k,i);
2578  }
2579 
2580 
2581  /// \short Calculate the interpolated value of zeta, the intrinsic coordinate
2582  /// of the element when viewed as a compound geometric object within a Mesh
2583  /// as a function of the local coordinate of the element, s. The default
2584  /// assumption is the zeta is interpolated using the shape functions of
2585  /// the element with the values given by zeta_nodal().
2586  /// A MacroElement representation of the intrinsic coordinate parametrised
2587  /// by the local coordinate s is used if available.
2588  /// Choosing the MacroElement representation of zeta (Eulerian x by default)
2589  /// allows a correspondence to be established between elements on different
2590  /// Meshes covering the same curvilinear domain in cases where one element
2591  /// is much coarser than the other.
2592  void interpolated_zeta(const Vector<double> &s,
2593  Vector<double> &zeta) const;
2594 
2595  /// \short For a given value of zeta, the "global" intrinsic coordinate of
2596  /// a mesh of FiniteElements represented as a compound geometric object,
2597  /// find the local coordinate in this element that corresponds to the
2598  /// requested value of zeta.
2599  /// If zeta cannot be located in this element, geom_object_pt is set
2600  /// to NULL. If zeta is located in this element, we return its "this"
2601  /// pointer.
2602  /// By default don't use any value passed in to the local coordinate s
2603  /// as the initial guess in the Newton method
2604  void locate_zeta(const Vector<double> &zeta,
2605  GeomObject*& geom_object_pt, Vector<double> &s,
2606  const bool& use_coordinate_as_initial_guess=false);
2607 
2608 
2609  /// \short Update the positions of all nodes in the element using
2610  /// each node update function. The default implementation may
2611  /// be overloaded so that more efficient versions can be written
2612  virtual void node_update();
2613 
2614  /// \short The purpose of this function is to identify all possible
2615  /// Data that can affect the fields interpolated by the FiniteElement.
2616  /// The information will typically be used in interaction problems in
2617  /// which the FiniteElement provides a forcing term for an
2618  /// ElementWithExternalElement. The Data must be provided as
2619  /// \c paired_load data containing
2620  /// - the pointer to a Data object
2621  /// and
2622  /// - the index of the value in that Data object
2623  /// .
2624  /// The generic implementation (should be overloaded in more specific
2625  /// applications) is to include all nodal and internal Data stored in
2626  /// the FiniteElement. The geometric data, which includes the positions
2627  /// of SolidNodes, is treated separately by the function
2628  /// \c identify_geometric_data()
2629  virtual void identify_field_data_for_interactions(
2630  std::set<std::pair<Data*,unsigned> > &paired_field_data);
2631 
2632 
2633  /// \short The purpose of this
2634  /// function is to identify all \c Data objects that affect the elements'
2635  /// geometry. This function is implemented as an empty virtual
2636  /// function since it can only be implemented in conjunction
2637  /// with a node-update strategy. A specific implementation
2638  /// is provided in the ElementWithMovingNodes class.
2639  virtual void identify_geometric_data(std::set<Data*> &geometric_data_pt){}
2640 
2641 
2642  /// Min value of local coordinate
2643  virtual double s_min() const
2644  {
2645  throw OomphLibError(
2646  "s_min() isn't implemented for this element\n",
2647  OOMPH_CURRENT_FUNCTION,
2648  OOMPH_EXCEPTION_LOCATION);
2649  // Dummy return
2650  return 0.0;
2651  }
2652 
2653  /// Max. value of local coordinate
2654  virtual double s_max() const
2655  {
2656  throw OomphLibError(
2657  "s_max() isn't implemented for this element\n",
2658  OOMPH_CURRENT_FUNCTION,
2659  OOMPH_EXCEPTION_LOCATION);
2660  // Dummy return
2661  return 0.0;
2662  }
2663 
2664  /// Calculate the size of the element (length, area, volume,...)
2665  /// in Eulerian computational
2666  /// coordinates. Use suitably overloaded compute_physical_size()
2667  /// function to compute the actual size (taking into account
2668  /// factors such as 2pi or radii the integrand) -- such function
2669  /// can only be implemented on an equation-by-equation basis.
2670  double size() const;
2671 
2672 
2673  /// \short Broken virtual
2674  /// function to compute the actual size (taking into account
2675  /// factors such as 2pi or radii the integrand) -- such function
2676  /// can only be implemented on an equation-by-equation basis.
2677  virtual double compute_physical_size() const
2678  {
2679  throw OomphLibError(
2680  "compute_physical_size() isn't implemented for this element\n",
2681  OOMPH_CURRENT_FUNCTION,
2682  OOMPH_EXCEPTION_LOCATION);
2683  // Dummy return
2684  return 0.0;
2685  }
2686 
2687  /// \short Virtual function to write the double precision numbers that
2688  /// appear in a single line of output into the data vector. Empty virtual,
2689  /// can be overloaded for specific elements; used e.g. by LineVisualiser.
2690  virtual void point_output_data(const Vector<double> &s, Vector<double>& data)
2691  {}
2692 
2693  /// \short Output solution (as defined by point_output_data())
2694  /// at local cordinates s
2695  void point_output(std::ostream &outfile, const Vector<double> &s)
2696  {
2697  // Get point data
2698  Vector<double> data;
2699  this->point_output_data(s,data);
2700 
2701  // Output
2702  unsigned n=data.size();
2703  for (unsigned i=0;i<n;i++)
2704  {
2705  outfile << data[i] << " ";
2706  }
2707  }
2708 
2709  /// \short Return the number of actual plot points for paraview
2710  /// plot with parameter nplot. Broken virtual; can be overloaded
2711  /// in specific elements.
2712  virtual unsigned nplot_points_paraview(const unsigned& nplot) const
2713  {
2714  throw OomphLibError(
2715  "This function hasn't been implemented for this element",
2716  OOMPH_CURRENT_FUNCTION,
2717  OOMPH_EXCEPTION_LOCATION);
2718 
2719  // Dummy unsigned
2720  return 0;
2721  }
2722 
2723  /// \short Return the number of local sub-elements for paraview plot with
2724  /// parameter nplot. Broken virtual; can be overloaded
2725  /// in specific elements.
2726  virtual unsigned nsub_elements_paraview(const unsigned& nplot) const
2727  {
2728  throw OomphLibError(
2729  "This function hasn't been implemented for this element",
2730  OOMPH_CURRENT_FUNCTION,
2731  OOMPH_EXCEPTION_LOCATION);
2732 
2733  // Dummy unsigned
2734  return 0;
2735  }
2736 
2737  /// \short Paraview output -- this outputs the coordinates at the plot
2738  /// points (for parameter nplot) to specified output file.
2739  void output_paraview(std::ofstream& file_out, const unsigned& nplot) const
2740  {
2741  //Decide the dimensions of the nodes
2742  unsigned nnod=nnode();
2743  if (nnod==0) return;
2744  unsigned n=node_pt(0)->ndim();
2745 
2746  // Vector for local coordinates
2747  Vector<double> s(n,0.0);
2748 
2749  //Vector for cartesian coordinates
2750  Vector<double> x(n,0.0);
2751 
2752  //Determine the total number of plotpoints
2753  unsigned plot=nplot_points_paraview(nplot);
2754 
2755  // Loop over the local points
2756  for(unsigned j=0;j<plot;j++)
2757  {
2758  // Determine where in the local element the point is
2759  this->get_s_plot(j,nplot,s);
2760 
2761  // Update the cartesian coordinates vector
2762  this->interpolated_x(s,x);
2763 
2764  // Print the global coordinates. Note: no whitespace after last
2765  // coordinate or paraview is very unhappy.
2766  for(unsigned i=0;i<n-1;i++)
2767  {
2768  file_out << x[i] << " ";
2769  }
2770  file_out << x[n-1];
2771 
2772  // Since unstructured grid always needs 3 components for each
2773  // point, output 0's by default
2774  switch(n)
2775  {
2776  case 1:
2777  file_out << " 0" << " 0"<< std::endl;
2778  break;
2779 
2780  case 2:
2781  file_out << " 0"<< std::endl;
2782  break;
2783 
2784  case 3:
2785  file_out << std::endl;
2786  break;
2787 
2788  // Paraview can't handle more than 3 dimensions, output error
2789  default:
2790  throw OomphLibError(
2791  "Printing PlotPoint to .vtu failed; it has >3 dimensions.",
2792  OOMPH_CURRENT_FUNCTION,
2793  OOMPH_EXCEPTION_LOCATION);
2794  }
2795  }
2796  }
2797 
2798  /// \short Fill in the offset information for paraview plot. Broken virtual.
2799  /// Needs to be implemented for each new geometric element type; see
2800  /// http://www.vtk.org/VTK/img/file-formats.pdf
2801  virtual void write_paraview_output_offset_information(std::ofstream& file_out,
2802  const unsigned& nplot,
2803  unsigned& counter) const
2804  {
2805  throw OomphLibError(
2806  "This function hasn't been implemented for this element",
2807  OOMPH_CURRENT_FUNCTION,
2808  OOMPH_EXCEPTION_LOCATION);
2809  }
2810 
2811  /// \short Return the paraview element type. Broken virtual.
2812  /// Needs to be implemented for each new geometric element type; see
2813  /// http://www.vtk.org/VTK/img/file-formats.pdf
2814  virtual void write_paraview_type(std::ofstream& file_out,
2815  const unsigned& nplot) const
2816  {
2817  throw OomphLibError(
2818  "This function hasn't been implemented for this element",
2819  OOMPH_CURRENT_FUNCTION,
2820  OOMPH_EXCEPTION_LOCATION);
2821  }
2822 
2823  /// \short Return the offsets for the paraview sub-elements. Broken
2824  /// virtual. Needs to be implemented for each new geometric element type; see
2825  /// http://www.vtk.org/VTK/img/file-formats.pdf
2826  virtual void write_paraview_offsets(std::ofstream& file_out,
2827  const unsigned& nplot,
2828  unsigned& offset_sum) const
2829  {
2830  throw OomphLibError(
2831  "This function hasn't been implemented for this element",
2832  OOMPH_CURRENT_FUNCTION,
2833  OOMPH_EXCEPTION_LOCATION);
2834  }
2835 
2836  /// \short Number of scalars/fields output by this element. Broken
2837  /// virtual. Needs to be implemented for each new specific element type.
2838  virtual unsigned nscalar_paraview() const
2839  {
2840  throw OomphLibError(
2841  "This function hasn't been implemented for this element",
2842  OOMPH_CURRENT_FUNCTION,
2843  OOMPH_EXCEPTION_LOCATION);
2844 
2845  // Dummy unsigned
2846  return 0;
2847  }
2848 
2849  /// \short Write values of the i-th scalar field at the plot points. Broken
2850  /// virtual. Needs to be implemented for each new specific element type.
2851  virtual void scalar_value_paraview(std::ofstream& file_out,
2852  const unsigned& i,
2853  const unsigned& nplot) const
2854  {
2855  throw OomphLibError(
2856  "This function hasn't been implemented for this element",
2857  OOMPH_CURRENT_FUNCTION,
2858  OOMPH_EXCEPTION_LOCATION);
2859  }
2860 
2861  /// \short Write values of the i-th scalar field at the plot points. Broken
2862  /// virtual. Needs to be implemented for each new specific element type.
2863  virtual void scalar_value_fct_paraview(std::ofstream& file_out,
2864  const unsigned& i,
2865  const unsigned& nplot,
2866  FiniteElement::SteadyExactSolutionFctPt exact_soln_pt) const
2867  {
2868  throw OomphLibError(
2869  "This function hasn't been implemented for this element",
2870  OOMPH_CURRENT_FUNCTION,
2871  OOMPH_EXCEPTION_LOCATION);
2872  }
2873 
2874  /// \short Name of the i-th scalar field. Default implementation
2875  /// returns V1 for the first one, V2 for the second etc. Can (should!) be
2876  /// overloaded with more meaningful names in specific elements.
2877  virtual std::string scalar_name_paraview(const unsigned& i) const
2878  {
2879  return "V"+StringConversion::to_string(i);
2880  }
2881 
2882  /// \short Output the element data --- typically the values at the
2883  /// nodes in a format suitable for post-processing.
2884  virtual void output(std::ostream &outfile)
2885  {
2886  throw OomphLibError(
2887  "Output function function hasn't been implemented for this element",
2888  OOMPH_CURRENT_FUNCTION,
2889  OOMPH_EXCEPTION_LOCATION);
2890  }
2891 
2892  /// \short Output the element data --- pass (some measure of)
2893  /// the number of plot points per element
2894  virtual void output(std::ostream &outfile, const unsigned &n_plot)
2895  {
2896  throw OomphLibError(
2897  "Output function function hasn't been implemented for this element",
2898  OOMPH_CURRENT_FUNCTION,
2899  OOMPH_EXCEPTION_LOCATION);
2900  }
2901 
2902  /// \short Output the element data at time step t. This is const because
2903  /// it is newly added and so can be done easily. Really all the
2904  /// output(...) functions should be const!
2905  virtual void output(const unsigned& t,
2906  std::ostream &outfile,
2907  const unsigned &n_plot) const
2908  {
2909  throw OomphLibError(
2910  "Output function function hasn't been implemented for this element",
2911  OOMPH_CURRENT_FUNCTION,
2912  OOMPH_EXCEPTION_LOCATION);
2913  }
2914 
2915  /// \short Output the element data --- typically the values at the
2916  /// nodes in a format suitable for post-processing.
2917  /// (C style output)
2918  virtual void output(FILE* file_pt)
2919  {
2920  throw OomphLibError(
2921  "C-style otput function function hasn't been implemented for this element",
2922  OOMPH_CURRENT_FUNCTION,
2923  OOMPH_EXCEPTION_LOCATION);
2924  }
2925 
2926  /// \short Output the element data --- pass (some measure of)
2927  /// the number of plot points per element
2928  /// (C style output)
2929  virtual void output(FILE* file_pt, const unsigned &n_plot)
2930  {
2931  throw OomphLibError(
2932  "C-style output function function hasn't been implemented for this element",
2933  OOMPH_CURRENT_FUNCTION,
2934  OOMPH_EXCEPTION_LOCATION);
2935  }
2936 
2937  /// Output an exact solution over the element.
2938  virtual void output_fct(std::ostream &outfile, const unsigned &n_plot,
2940  {
2941  throw OomphLibError(
2942  "Output function function hasn't been implemented for exact solution",
2943  OOMPH_CURRENT_FUNCTION,
2944  OOMPH_EXCEPTION_LOCATION);
2945  }
2946 
2947 
2948  /// Output a time-dependent exact solution over the element.
2949  virtual void output_fct(std::ostream &outfile, const unsigned &n_plot,
2950  const double& time,
2952  {
2953  throw OomphLibError(
2954  "Output function function hasn't been implemented for exact solution",
2955  OOMPH_CURRENT_FUNCTION,
2956  OOMPH_EXCEPTION_LOCATION);
2957  }
2958 
2959  /// Output a time-dependent exact solution over the element.
2960  virtual void output_fct(std::ostream &outfile, const unsigned &n_plot,
2961  const double& time,
2962  const SolutionFunctorBase& exact_soln) const
2963  {
2964  throw OomphLibError(
2965  "Output function function hasn't been implemented for exact solution",
2966  OOMPH_CURRENT_FUNCTION,
2967  OOMPH_EXCEPTION_LOCATION);
2968  }
2969 
2970 
2971 
2972  /// \short Get cector of local coordinates of plot point i (when plotting
2973  /// nplot points in each "coordinate direction").
2974  /// Generally these plot points will be uniformly spaced across the element.
2975  /// The optional final boolean flag (default: false) allows them to
2976  /// be shifted inwards to avoid duplication of plot point points between
2977  /// elements -- useful when they are used in locate_zeta, say.
2978  virtual void get_s_plot(const unsigned& i, const unsigned& nplot,
2979  Vector<double>& s,
2980  const bool& shifted_to_interior=false) const
2981  {
2982  throw OomphLibError(
2983  "get_s_plot(...) is not implemented for this element\n",
2984  OOMPH_CURRENT_FUNCTION,
2985  OOMPH_EXCEPTION_LOCATION);
2986  };
2987 
2988  /// \short Return string for tecplot zone header (when plotting
2989  /// nplot points in each "coordinate direction")
2990  virtual std::string tecplot_zone_string(const unsigned& nplot) const
2991  {
2992  throw OomphLibError(
2993  "tecplot_zone_string(...) is not implemented for this element\n",
2994  OOMPH_CURRENT_FUNCTION,
2995  OOMPH_EXCEPTION_LOCATION);
2996  return "dummy return";
2997  }
2998 
2999  /// \short Add tecplot zone "footer" to output stream (when plotting
3000  /// nplot points in each "coordinate direction").
3001  /// Empty by default -- can be used, e.g., to add FE connectivity
3002  /// lists to elements that need it.
3003  virtual void write_tecplot_zone_footer(std::ostream& outfile,
3004  const unsigned& nplot)
3005  const {};
3006 
3007  /// \short Add tecplot zone "footer" to C-style output. (when plotting
3008  /// nplot points in each "coordinate direction").
3009  /// Empty by default -- can be used, e.g., to add FE connectivity
3010  /// lists to elements that need it.
3011  virtual void write_tecplot_zone_footer(FILE* file_pt,
3012  const unsigned& nplot)
3013  const {};
3014 
3015  /// \short Return total number of plot points (when plotting
3016  /// nplot points in each "coordinate direction")
3017  virtual unsigned nplot_points(const unsigned& nplot) const
3018  {
3019  throw OomphLibError(
3020  "nplot_points(...) is not implemented for this element",
3021  OOMPH_CURRENT_FUNCTION,
3022  OOMPH_EXCEPTION_LOCATION);
3023  // Dummy return
3024  return 0;
3025  }
3026 
3027 
3028 
3029  /// \short Plot the error when compared
3030  /// against a given exact solution \f$ {\bf f}({\bf x}) \f$.
3031  /// Also calculates the norm of the
3032  /// error and that of the exact solution.
3033  virtual void compute_error(std::ostream &outfile,
3035  double& error, double& norm)
3036  {
3037  std::string error_message = "compute_error undefined for this element \n";
3038  outfile << error_message;
3039 
3040  throw OomphLibError(error_message,
3041  OOMPH_CURRENT_FUNCTION,
3042  OOMPH_EXCEPTION_LOCATION);
3043 
3044  }
3045 
3046  /// \short Plot the error when compared
3047  /// against a given time-dependent exact solution \f$ {\bf f}(t,{\bf x}) \f$.
3048  /// Also calculates the norm of the error and that of the exact solution.
3049  virtual void compute_error(std::ostream &outfile,
3051  const double& time, double& error, double& norm)
3052  {
3053  std::string error_message =
3054  "time-dependent compute_error undefined for this element \n";
3055  outfile << error_message;
3056 
3057  throw OomphLibError(error_message,
3058  OOMPH_CURRENT_FUNCTION,
3059  OOMPH_EXCEPTION_LOCATION);
3060  }
3061 
3062  /// \short Plot the error when compared
3063  /// against a given exact solution \f$ {\bf f}({\bf x}) \f$.
3064  /// Also calculates the norm of the
3065  /// error and that of the exact solution.
3066  /// Version with vectors of norms and errors so that different variables' norms
3067  /// and errors can be returned individually
3068  virtual void compute_error(std::ostream &outfile,
3070  exact_soln_pt,
3071  Vector<double>& error, Vector<double>& norm)
3072  {
3073  std::string error_message = "compute_error undefined for this element \n";
3074  outfile << error_message;
3075 
3076  throw OomphLibError(error_message,
3077  "FiniteElement::compute_error()",
3078  OOMPH_EXCEPTION_LOCATION);
3079 
3080  }
3081 
3082  /// \short Plot the error when compared
3083  /// against a given time-dependent exact solution \f$ {\bf f}(t,{\bf x}) \f$.
3084  /// Also calculates the norm of the error and that of the exact solution.
3085  /// Version with vectors of norms and errors so that different variables' norms
3086  /// and errors can be returned individually
3087  virtual void compute_error(std::ostream &outfile,
3089  exact_soln_pt,
3090  const double& time,
3091  Vector<double>& error,
3092  Vector<double>& norm)
3093  {
3094  std::string error_message =
3095  "time-dependent compute_error undefined for this element \n";
3096  outfile << error_message;
3097 
3098  throw OomphLibError(error_message,
3099  "FiniteElement::compute_error()",
3100  OOMPH_EXCEPTION_LOCATION);
3101 
3102  }
3103 
3104  /// \short Plot the error when compared
3105  /// against a given exact solution \f$ {\bf f}({\bf x}) \f$.
3106  /// Also calculates the maximum absolute error
3107  virtual void compute_abs_error(std::ostream &outfile,
3109  exact_soln_pt,
3110  double& error)
3111  {
3112  std::string error_message =
3113  "compute_abs_error undefined for this element \n";
3114  outfile << error_message;
3115 
3116  throw OomphLibError(error_message,
3117  OOMPH_CURRENT_FUNCTION,
3118  OOMPH_EXCEPTION_LOCATION);
3119  }
3120 
3121  /// \short Evaluate integral of a Vector-valued function
3122  /// \f$ {\bf f}({\bf x}) \f$ over the element.
3123  void integrate_fct(FiniteElement::SteadyExactSolutionFctPt integrand_fct_pt,
3124  Vector<double>& integral);
3125 
3126 
3127  /// \short Evaluate integral of a Vector-valued, time-dependent function
3128  /// \f$ {\bf f}(t,{\bf x}) \f$ over the element.
3129  void integrate_fct(FiniteElement::UnsteadyExactSolutionFctPt integrand_fct_pt,
3130  const double& time,
3131  Vector<double>& integral);
3132 
3133  /// \short Function for building a lower dimensional FaceElement
3134  /// on the specified face of the FiniteElement.
3135  /// The arguments are the index of the face, an integer whose value
3136  /// depends on the particular element type, and a pointer to the
3137  /// FaceElement.
3138  virtual void build_face_element(const int &face_index,
3139  FaceElement* face_element_pt);
3140 
3141 
3142  /// \short Self-test: Check inversion of element & do self-test for
3143  /// GeneralisedElement. Return 0 if OK.
3144  virtual unsigned self_test();
3145 
3146  /// Get the number of the ith node on face face_index (in the bulk node
3147  /// vector).
3148  virtual unsigned get_bulk_node_number(const int& face_index,
3149  const unsigned& i) const
3150  {
3151  std::string err = "Not implemented for this element.";
3152  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
3153  OOMPH_CURRENT_FUNCTION);
3154  }
3155 
3156  /// Get the sign of the outer unit normal on the face given by face_index.
3157  virtual int face_outer_unit_normal_sign(const int& face_index) const
3158  {
3159  std::string err = "Not implemented for this element.";
3160  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
3161  OOMPH_CURRENT_FUNCTION);
3162  }
3163 
3164  virtual unsigned nnode_on_face() const
3165  {
3166  std::string err = "Not implemented for this element.";
3167  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
3168  OOMPH_CURRENT_FUNCTION);
3169  }
3170 
3171  /// Range check for face node numbers
3172  void face_node_number_error_check(const unsigned& i) const
3173  {
3174 #ifdef RANGE_CHECKING
3175  if(i > nnode_on_face())
3176  {
3177  std::string err = "Face node index i out of range on face.";
3178  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
3179  OOMPH_CURRENT_FUNCTION);
3180  }
3181 #endif
3182  }
3183 
3184  /// Get a pointer to the function mapping face coordinates to bulk coordinates
3185  virtual CoordinateMappingFctPt face_to_bulk_coordinate_fct_pt
3186  (const int& face_index) const
3187  {
3188  std::string err = "Not implemented for this element.";
3189  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
3190  OOMPH_CURRENT_FUNCTION);
3191  }
3192 
3193  /// Get a pointer to the derivative of the mapping from face to bulk
3194  /// coordinates.
3195  virtual BulkCoordinateDerivativesFctPt bulk_coordinate_derivatives_fct_pt
3196  (const int& face_index) const
3197  {
3198  std::string err = "Not implemented for this element.";
3199  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
3200  OOMPH_CURRENT_FUNCTION);
3201  }
3202 
3203 };
3204 
3205 
3206 //////////////////////////////////////////////////////////////////////////
3207 //////////////////////////////////////////////////////////////////////////
3208 //////////////////////////////////////////////////////////////////////////
3209 
3210 
3211 
3212 //=======================================================================
3213 /// Point element has just a single node and a single shape function
3214 /// which is identically equal to one.
3215 //=======================================================================
3216 class PointElement : public virtual FiniteElement
3217 {
3218 
3219  public:
3220 
3221  /// Constructor
3223  {
3224  /// Allocate storage for the pointers to the nodes,
3225  /// There is only one nodes
3226  this->set_n_node(1);
3227 
3228  // Set the integration scheme
3229  this->set_integration_scheme(&Default_integration_scheme);
3230  }
3231 
3232  /// Broken copy constructor
3234  {
3235  BrokenCopy::broken_copy("PointElement");
3236  }
3237 
3238  /// Broken assignment operator
3239  /*void operator=(const PointElement&)
3240  {
3241  BrokenCopy::broken_assign("PointElement");
3242  }*/
3243 
3244  /// Calculate the geometric shape functions at local coordinate s
3245  void shape(const Vector<double> &s, Shape &psi) const;
3246 
3247  /// Get local coordinates of node j in the element; vector sets its own size
3248  void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
3249  {
3250  s.resize(0);
3251  }
3252 
3253  /// \short Return spatial dimension of element (=number of local coordinates
3254  /// needed to parametrise the element)
3255  //unsigned dim() const {return 0;}
3256 
3257  private:
3258 
3259  /// \short Default integration scheme
3261 
3262 
3263 };
3264 
3265 
3266 
3267 //////////////////////////////////////////////////////////////////////////
3268 //////////////////////////////////////////////////////////////////////////
3269 //////////////////////////////////////////////////////////////////////////
3270 
3271 
3272 class GeomObject;
3273 
3274 //=======================================================================
3275 /// \short A class to specify the initial conditions for a solid body.
3276 /// Solid bodies are often discretised with
3277 /// Hermite-type elements, for which the assignment
3278 /// of the generalised nodal values is nontrivial since they represent
3279 /// derivatives w.r.t. to the local coordinates. A SolidInitialCondition
3280 /// object specifies initial position (i.e. shape), velocity and acceleration
3281 /// of the structure with a geometric object.
3282 /// An integer specifies which time-derivative derivative is currently
3283 /// assigned. See example codes for a demonstration of its use.
3284 //=======================================================================
3286 {
3287 
3288  public:
3289 
3290  /// Constructor: Pass geometric object; initialise time deriv to 0
3292  Geom_object_pt(geom_object_pt), IC_time_deriv(0)
3293  {};
3294 
3295 
3296  /// Broken copy constructor
3298  {
3299  BrokenCopy::broken_copy("SolidInitialCondition");
3300  }
3301 
3302  /// Broken assignment operator
3304  {
3305  BrokenCopy::broken_assign("SolidInitialCondition");
3306  }
3307 
3308 
3309  /// (Reference to) pointer to geom object that specifies the initial condition
3311  {
3312  return Geom_object_pt;
3313  }
3314 
3315  /// Which time derivative are we currently assigning?
3316  unsigned& ic_time_deriv()
3317  {
3318  return IC_time_deriv;
3319  }
3320 
3321 
3322  private:
3323 
3324  /// \short Pointer to the GeomObject that specifies the initial
3325  /// condition (shape, veloc and accel)
3327 
3328  /// \short Which time derivative (0,1,2) are we currently assigning
3329  unsigned IC_time_deriv;
3330 
3331 };
3332 
3333 
3334 /////////////////////////////////////////////////////////////////////////
3335 /////////////////////////////////////////////////////////////////////////
3336 /////////////////////////////////////////////////////////////////////////
3337 
3338 
3339 //============================================================================
3340 /// \short SolidFiniteElement class.
3341 ///
3342 /// Solid elements are elements whose nodal positions are unknowns
3343 /// in the problem -- their nodes are SolidNodes. In such elements,
3344 /// the nodes not only have a variable (Eulerian) but also a fixed
3345 /// (Lagrangian) position. The positional variables have their own
3346 /// local equation numbering scheme which is set up with
3347 /// \code assign_solid_local_eqn_numbers () \endcode
3348 /// The derivatives of the
3349 /// `solid equations' (i.e. the equations that determine the
3350 /// nodal positions) with respect to the nodal positions, required
3351 /// in the Jacobian matrix, are determined by finite differencing.
3352 ///
3353 /// In the present form, the SolidFiniteElement represents
3354 /// a fully functional base class for `proper' solid mechanics elements,
3355 /// but it can also be combined
3356 /// (via inheritance) with elements that solve additional equations.
3357 /// This is particularly useful in cases where the solid equations
3358 /// are merely used to update the nodal positions in a moving mesh
3359 /// problem, although this can prove costly in practice.
3360 //============================================================================
3361 class SolidFiniteElement : public virtual FiniteElement
3362 {
3363 
3364 public:
3365 
3366  /// \short Set the lagrangian dimension of the element --- the number
3367  /// of lagrangian coordinates stored at the nodes in the element.
3368  void set_lagrangian_dimension(const unsigned &lagrangian_dimension)
3369  {Lagrangian_dimension = lagrangian_dimension;}
3370 
3371  /// \short Return whether there is internal solid data (e.g. discontinuous
3372  /// solid pressure). At present, this is used to report an error in
3373  /// setting initial conditions for ElasticProblems which can't
3374  /// handle such cases. The default is false.
3375  virtual bool has_internal_solid_data() {return false;}
3376 
3377  /// \short Pointer to function that computes the "multiplier" for the
3378  /// inertia terms in the consistent determination of the initial
3379  /// conditions for Newmark timestepping.
3380  typedef double (*MultiplierFctPt)(const Vector<double>& xi);
3381 
3382  ///Constructor: Set defaults
3384  Undeformed_macro_elem_pt(0), Solid_ic_pt(0),
3385  Multiplier_fct_pt(0), Position_local_eqn(0),
3386  Lagrangian_dimension(0), Nnodal_lagrangian_type(1),
3387  Solve_for_consistent_newmark_accel_flag(false)
3388  {}
3389 
3390  ///Destructor to clean up any allocated memory
3391  virtual ~SolidFiniteElement();
3392 
3393  /// Broken copy constructor
3395  {
3396  BrokenCopy::broken_copy("SolidFiniteElement");
3397  }
3398 
3399 
3400  /// Broken assignment operator
3401  /*void operator=(const SolidFiniteElement&)
3402  {
3403  BrokenCopy::broken_assign("SolidFiniteElement");
3404  }*/
3405 
3406  ///\short The number of geometric data affecting a SolidFiniteElemnet is
3407  ///the same as the number of nodes (one variable position data per node)
3408  inline unsigned ngeom_data() const {return nnode();}
3409 
3410  /// \short Return pointer to the j-th Data item that the object's
3411  /// shape depends on. (Redirects to the nodes' positional Data).
3412  inline Data* geom_data_pt(const unsigned& j)
3413  {return static_cast<SolidNode*>(node_pt(j))->variable_position_pt();}
3414 
3415  /// \short Specify Data that affects the geometry of the element
3416  /// by adding the position Data to the set that's passed in.
3417  /// (This functionality is required in FSI problems; set is used to
3418  /// avoid double counting).
3419  void identify_geometric_data(std::set<Data*> &geometric_data_pt)
3420  {
3421  //Loop over the node update data and add to the set
3422  const unsigned n_node=this->nnode();
3423  for(unsigned n=0;n<n_node;n++)
3424  {
3425  geometric_data_pt.insert(dynamic_cast<SolidNode*>(this->node_pt(n))
3426  ->variable_position_pt());
3427  }
3428  }
3429 
3430 
3431  /// \short In a SolidFiniteElement, the "global" intrinsic coordinate
3432  /// of the element when viewed as part of a compound geometric
3433  /// object (a Mesh) is, by default, the Lagrangian coordinate
3434  /// Note the assumption here is that we are always using isoparameteric
3435  /// elements in which the lagrangian coordinate is interpolated by the
3436  /// same shape functions as the eulerian coordinate.
3437  inline double zeta_nodal(const unsigned &n, const unsigned &k,
3438  const unsigned &i) const
3439  {return lagrangian_position_gen(n,k,i);}
3440 
3441  /// \short Eulerian and Lagrangian coordinates as function of the
3442  /// local coordinates: The Eulerian position is returned in
3443  /// FE-interpolated form (\c x_fe) and then in the form obtained
3444  /// from the "current" MacroElement representation (if it exists -- if not,
3445  /// \c x is the same as \c x_fe). This allows the Domain/MacroElement-
3446  /// based representation to be used to apply displacement boundary
3447  /// conditions exactly. Ditto for the Lagrangian coordinates returned
3448  /// in xi_fe and xi.
3449  /// (Broken virtual -- overload in specific geometric element class
3450  /// if you want to use this functionality.)
3451  virtual void get_x_and_xi(const Vector<double>& s,
3452  Vector<double>& x_fe,
3453  Vector<double>& x,
3454  Vector<double>& xi_fe,
3455  Vector<double>& xi) const
3456  {
3457  throw OomphLibError(
3458  "get_x_and_xi(...) is not implemented for this element\n",
3459  OOMPH_CURRENT_FUNCTION,
3460  OOMPH_EXCEPTION_LOCATION);
3461  }
3462 
3463  /// \short Set pointer to MacroElement -- overloads generic version
3464  /// and uses the MacroElement
3465  /// also as the default for the "undeformed" configuration.
3466  /// This assignment must be overwritten with
3467  /// set_undeformed_macro_elem_pt(...) if the deformation of
3468  /// the solid body is driven by a deformation of the
3469  /// "current" Domain/MacroElement representation of it's boundary.
3470  /// Can be overloaded in derived classes to perform additional
3471  /// tasks
3472  virtual void set_macro_elem_pt(MacroElement* macro_elem_pt)
3473  {
3474  Macro_elem_pt=macro_elem_pt;
3475  Undeformed_macro_elem_pt=macro_elem_pt;
3476  }
3477 
3478  /// \short Set pointers to "current" and "undeformed" MacroElements.
3479  /// Can be overloaded in derived classes to perform additional
3480  /// tasks
3481  virtual void set_macro_elem_pt(MacroElement* macro_elem_pt,
3482  MacroElement* undeformed_macro_elem_pt)
3483  {
3484  Macro_elem_pt=macro_elem_pt;
3485  Undeformed_macro_elem_pt=undeformed_macro_elem_pt;
3486  }
3487 
3488  /// \short Set pointer to "undeformed" macro element.
3489  /// Can be overloaded in derived classes to perform additional
3490  /// tasks.
3492  undeformed_macro_elem_pt)
3493  {Undeformed_macro_elem_pt=undeformed_macro_elem_pt;}
3494 
3495 
3496  /// Access function to pointer to "undeformed" macro element
3498  {return Undeformed_macro_elem_pt;}
3499 
3500  /// \short Calculate shape functions and derivatives w.r.t. Lagrangian
3501  /// coordinates at local coordinate s. Returns the Jacobian of the mapping
3502  /// from Lagrangian to local coordinates.
3503  double dshape_lagrangian(const Vector<double> &s, Shape &psi,
3504  DShape &dpsidxi) const;
3505 
3506  /// \short Return the geometric shape functions and also first
3507  /// derivatives w.r.t. Lagrangian coordinates at ipt-th integration point.
3508  virtual double dshape_lagrangian_at_knot(const unsigned &ipt,
3509  Shape &psi, DShape &dpsidxi) const;
3510 
3511  /// \short Compute the geometric shape functions and also first
3512  /// and second derivatives w.r.t. Lagrangian coordinates at
3513  /// local coordinate s;
3514  /// Returns Jacobian of mapping from Lagrangian to local coordinates.
3515  /// Numbering:
3516  /// \b 1D:
3517  /// d2pidxi(i,0) = \f$ d^2 \psi_j / d \xi^2 \f$
3518  /// \b 2D:
3519  /// d2psidxi(i,0) = \f$ \partial^2 \psi_j / \partial \xi_0^2 \f$
3520  /// d2psidxi(i,1) = \f$ \partial^2 \psi_j / \partial \xi_1^2 \f$
3521  /// d2psidxi(i,2) = \f$ \partial^2 \psi_j / \partial \xi_0 \partial \xi_1 \f$
3522  /// \b 3D:
3523  /// d2psidxi(i,0) = \f$ \partial^2 \psi_j / \partial \xi_0^2 \f$
3524  /// d2psidxi(i,1) = \f$ \partial^2 \psi_j / \partial \xi_1^2 \f$
3525  /// d2psidxi(i,2) = \f$ \partial^2 \psi_j / \partial \xi_2^2 \f$
3526  /// d2psidxi(i,3) = \f$ \partial^2 \psi_j/\partial \xi_0 \partial \xi_1 \f$
3527  /// d2psidxi(i,4) = \f$ \partial^2 \psi_j/\partial \xi_0 \partial \xi_2 \f$
3528  /// d2psidxi(i,5) = \f$ \partial^2 \psi_j/\partial \xi_1 \partial \xi_2 \f$
3529  double d2shape_lagrangian(const Vector<double> &s, Shape &psi,
3530  DShape &dpsidxi, DShape &d2psidxi) const;
3531 
3532  /// \short Return the geometric shape functions and also first
3533  /// and second derivatives w.r.t. Lagrangian coordinates at
3534  /// the ipt-th integration point.
3535  /// Returns Jacobian of mapping from Lagrangian to local coordinates.
3536  /// Numbering:
3537  /// \b 1D:
3538  /// d2pidxi(i,0) = \f$ d^2 \psi_j / d^2 \xi^2 \f$
3539  /// \b 2D:
3540  /// d2psidxi(i,0) = \f$ \partial^2 \psi_j/\partial^2 \xi_0^2 \f$
3541  /// d2psidxi(i,1) = \f$ \partial^2 \psi_j/\partial^2 \xi_1^2 \f$
3542  /// d2psidxi(i,2) = \f$ \partial^2 \psi_j/\partial \xi_0 \partial \xi_1 \f$
3543  /// \b 3D:
3544  /// d2psidxi(i,0) = \f$ \partial^2 \psi_j / \partial^2 \xi_0^2 \f$
3545  /// d2psidxi(i,1) = \f$ \partial^2 \psi_j / \partial^2 \xi_1^2 \f$
3546  /// d2psidxi(i,2) = \f$ \partial^2 \psi_j / \partial^2 \xi_2^2 \f$
3547  /// d2psidxi(i,3) = \f$ \partial^2 \psi_j / \partial \xi_0 \partial \xi_1 \f$
3548  /// d2psidxi(i,4) = \f$ \partial^2 \psi_j/\partial \xi_0 \partial \xi_2 \f$
3549  /// d2psidxi(i,5) = \f$ \partial^2 \psi_j/\partial \xi_1 \partial \xi_2 \f$
3550  virtual double d2shape_lagrangian_at_knot(const unsigned &ipt,
3551  Shape &psi,
3552  DShape &dpsidxi,
3553  DShape &d2psidxi) const;
3554 
3555  /// \short Return the number of Lagrangian coordinates that the
3556  /// element requires at all nodes.
3557  /// This is by default the elemental dimension. If we ever need any
3558  /// other case, it can be implemented.
3559  unsigned lagrangian_dimension() const {return Lagrangian_dimension;}
3560 
3561  /// \short Return the number of types of (generalised)
3562  /// nodal Lagrangian coordinates required to
3563  /// interpolate the Lagrangian coordinates in the element. (E.g.
3564  /// 1 for Lagrange-type elements; 2 for Hermite beam elements;
3565  /// 4 for Hermite shell elements). Default value is 1. Needs to
3566  /// be overloaded for any other element.
3567  unsigned nnodal_lagrangian_type() const {return Nnodal_lagrangian_type;}
3568 
3569  /// Construct the local node n and return a pointer to it.
3570  Node* construct_node(const unsigned &n)
3571  {
3572  //Construct a solid node and assign it to the local node pointer vector.
3573  //The dimension and number of values are taken from internal element data
3574  //The number of solid pressure dofs are also taken from internal data
3575  //The number of timesteps to be stored comes from the problem!
3576  node_pt(n) = new SolidNode(lagrangian_dimension(),
3577  nnodal_lagrangian_type(),
3578  nodal_dimension(),
3579  nnodal_position_type(),
3580  required_nvalue(n));
3581  //Now return a pointer to the node, so that the mesh can find it
3582  return node_pt(n);
3583  }
3584 
3585  ///\short Construct the local node n and return
3586  /// a pointer to it. Additionally, create storage for `history'
3587  /// values as required by timestepper
3588  Node* construct_node(const unsigned &n,
3589  TimeStepper* const &time_stepper_pt)
3590  {
3591  //Construct a solid node and assign it to the local node pointer vector
3592  //The dimension and number of values are taken from internal element data
3593  //The number of solid pressure dofs are also taken from internal data
3594  node_pt(n) = new SolidNode(time_stepper_pt,
3595  lagrangian_dimension(),
3596  nnodal_lagrangian_type(),
3597  nodal_dimension(),
3598  nnodal_position_type(),
3599  required_nvalue(n));
3600  //Now return a pointer to the node, so that the mesh can find it
3601  return node_pt(n);
3602  }
3603 
3604  /// \short Construct the local node n and return a pointer to it.
3605  /// in the case when it is a boundary node; that is it MAY be
3606  /// located on a Mesh boundary
3607  Node* construct_boundary_node(const unsigned &n)
3608  {
3609  //Construct a solid node and assign it to the local node pointer vector.
3610  //The dimension and number of values are taken from internal element data
3611  //The number of solid pressure dofs are also taken from internal data
3612  //The number of timesteps to be stored comes from the problem!
3613  node_pt(n) =
3614  new BoundaryNode<SolidNode>(lagrangian_dimension(),
3615  nnodal_lagrangian_type(),
3616  nodal_dimension(),
3617  nnodal_position_type(),
3618  required_nvalue(n));
3619  //Now return a pointer to the node, so that the mesh can find it
3620  return node_pt(n);
3621  }
3622 
3623  ///\short Construct the local node n and return
3624  /// a pointer to it, in the case when the node MAY be located
3625  /// on a boundary. Additionally, create storage for `history'
3626  /// values as required by timestepper
3627  Node* construct_boundary_node(const unsigned &n,
3628  TimeStepper* const &time_stepper_pt)
3629  {
3630  //Construct a solid node and assign it to the local node pointer vector
3631  //The dimension and number of values are taken from internal element data
3632  //The number of solid pressure dofs are also taken from internal data
3633  node_pt(n) =
3634  new BoundaryNode<SolidNode>(time_stepper_pt,
3635  lagrangian_dimension(),
3636  nnodal_lagrangian_type(),
3637  nodal_dimension(),
3638  nnodal_position_type(),
3639  required_nvalue(n));
3640  //Now return a pointer to the node, so that the mesh can find it
3641  return node_pt(n);
3642  }
3643 
3644  /// \short Overload assign_all_generic_local_equation numbers to
3645  /// include the data associated with solid dofs.
3646  /// It remains virtual so that it can be overloaded
3647  /// by RefineableSolidElements. If the boolean argument is true
3648  /// then the degrees of freedom are stored in Dof_pt
3650  const bool &store_local_dof_pt)
3651  {
3652  //Call the standard finite element equation numbering
3653  //(internal, external and nodal data).
3655  //Assign the numbering for the solid dofs
3656  assign_solid_local_eqn_numbers(store_local_dof_pt);
3657  }
3658 
3659  /// \short Function to describe the local dofs of the element. The ostream
3660  /// specifies the output stream to which the description
3661  /// is written; the string stores the currently
3662  /// assembled output that is ultimately written to the
3663  /// output stream by Data::describe_dofs(...); it is typically
3664  /// built up incrementally as we descend through the
3665  /// call hierarchy of this function when called from
3666  /// Problem::describe_dofs(...)
3667  void describe_local_dofs(std::ostream& out,
3668  const std::string& current_string) const;
3669 
3670  /// \short Return i-th Lagrangian coordinate at local node n without using
3671  /// the hanging representation
3672  double raw_lagrangian_position(const unsigned &n, const unsigned &i) const
3673  {return static_cast<SolidNode*>(node_pt(n))->xi(i);}
3674 
3675  /// \short Return Generalised Lagrangian coordinate at local node n.
3676  /// `Direction' i, `Type' k. Does not use the hanging node representation
3677  double raw_lagrangian_position_gen(const unsigned &n, const unsigned &k,
3678  const unsigned &i) const
3679  {return static_cast<SolidNode*>(node_pt(n))->xi_gen(k,i);}
3680 
3681  /// Return i-th Lagrangian coordinate at local node n
3682  double lagrangian_position(const unsigned &n, const unsigned &i) const
3683  {return static_cast<SolidNode*>(node_pt(n))->lagrangian_position(i);}
3684 
3685  /// \short Return Generalised Lagrangian coordinate at local node n.
3686  /// `Direction' i, `Type' k.
3687  double lagrangian_position_gen(const unsigned &n, const unsigned &k,
3688  const unsigned &i) const
3689  {return static_cast<SolidNode*>(node_pt(n))->lagrangian_position_gen(k,i);}
3690 
3691  /// \short Return i-th FE-interpolated Lagrangian coordinate xi[i] at
3692  /// local coordinate s.
3693  virtual double interpolated_xi(const Vector<double> &s,
3694  const unsigned &i) const;
3695 
3696  /// \short Compute FE interpolated Lagrangian coordinate vector xi[] at
3697  /// local coordinate s as Vector
3698  virtual void interpolated_xi(const Vector<double> &s,
3699  Vector<double>& xi) const;
3700 
3701  /// \short Compute derivatives of FE-interpolated Lagrangian coordinates xi
3702  /// with respect to local coordinates: dxids[i][j]=dxi_i/ds_j.
3703  virtual void interpolated_dxids(const Vector<double> &s,
3704  DenseMatrix<double> &dxids) const;
3705 
3706  /// \short Return the Jacobian of mapping from local to Lagrangian
3707  /// coordinates at local position s. NOT YET IMPLEMENTED
3708  virtual void J_lagrangian(const Vector<double> &s) const
3709  {
3710  // Must be implemented and overloaded in FaceElements
3711  throw OomphLibError("Function not implemented yet",
3712  OOMPH_CURRENT_FUNCTION,
3713  OOMPH_EXCEPTION_LOCATION);
3714  }
3715 
3716  /// \short Return the Jacobian of the mapping from local to Lagrangian
3717  /// coordinates at the ipt-th integration point. NOT YET IMPLEMENTED
3718  virtual double J_lagrangian_at_knot(const unsigned &ipt) const
3719  {
3720  // Must be implemented and overloaded in FaceElements
3721  throw OomphLibError("Function not implemented yet",
3722  OOMPH_CURRENT_FUNCTION,
3723  OOMPH_EXCEPTION_LOCATION);
3724  }
3725 
3726  /// \short Pointer to object that describes the initial condition.
3728  {
3729  return Solid_ic_pt;
3730  }
3731 
3732  /// \short Set to alter the problem being solved when
3733  /// assigning the initial conditions for time-dependent problems:
3734  /// solve for the history value that
3735  /// corresponds to the acceleration in the Newmark scheme by demanding
3736  /// that the PDE is satisifed at the initial time. In this case
3737  /// the Jacobian is replaced by the mass matrix.
3739  {Solve_for_consistent_newmark_accel_flag=true;}
3740 
3741  /// \short Set to reset the problem being solved to be the standard problem
3743  {Solve_for_consistent_newmark_accel_flag=false;}
3744 
3745  /// \short Access function: Pointer to multiplicator function for assignment
3746  /// of consistent assignement of initial conditions for Newmark scheme
3747  MultiplierFctPt& multiplier_fct_pt()
3748  {
3749  return Multiplier_fct_pt;
3750  }
3751 
3752 
3753  /// \short Access function: Pointer to multiplicator function for assignment
3754  /// of consistent assignement of initial conditions for Newmark scheme
3755  /// (const version)
3756  MultiplierFctPt multiplier_fct_pt() const
3757  {
3758  return Multiplier_fct_pt;
3759  }
3760 
3761 
3762  /// \short Compute the residuals for the setup of an initial condition.
3763  /// The global equations are:
3764  /// \f[
3765  /// 0 = \int \left( \sum_{j=1}^N \sum_{k=1}^K X_{ijk} \psi_{jk}(\xi_n)
3766  /// - \frac{\partial^D R^{(IC)}_i(\xi_n)}{\partial t^D}
3767  /// \right) \psi_{lm}(\xi_n) \ dv
3768  /// \mbox{ \ \ \ \ for \ \ \ $l=1,...,N, \ \ m=1,...,K$}
3769  /// \f]
3770  /// where \f$ N \f$ is the number of nodes in the mesh and \f$ K \f$
3771  /// the number of generalised nodal coordinates. The initial shape
3772  /// of the solid body, \f$ {\bf R}^{(IC)},\f$ and its time-derivatives
3773  /// are specified via the \c GeomObject that is stored in the
3774  /// \c SolidFiniteElement::SolidInitialCondition object. The latter also
3775  /// stores the order of the time-derivative \f$ D \f$ to be assigned.
3776  virtual void get_residuals_for_solid_ic(Vector<double>& residuals)
3777  {
3778  residuals.initialise(0.0);
3779  fill_in_residuals_for_solid_ic(residuals);
3780  }
3781 
3782  /// \short Fill in the residuals for the setup of an initial condition.
3783  /// The global equations are:
3784  /// \f[
3785  /// 0 = \int \left( \sum_{j=1}^N \sum_{k=1}^K X_{ijk} \psi_{jk}(\xi_n)
3786  /// - \frac{\partial^D R^{(IC)}_i(\xi_n)}{\partial t^D}
3787  /// \right) \psi_{lm}(\xi_n) \ dv
3788  /// \mbox{ \ \ \ \ for \ \ \ $l=1,...,N, \ \ m=1,...,K$}
3789  /// \f]
3790  /// where \f$ N \f$ is the number of nodes in the mesh and \f$ K \f$
3791  /// the number of generalised nodal coordinates. The initial shape
3792  /// of the solid body, \f$ {\bf R}^{(IC)},\f$ and its time-derivatives
3793  /// are specified via the \c GeomObject that is stored in the
3794  /// \c SolidFiniteElement::SolidInitialCondition object. The latter also
3795  /// stores the order of the time-derivative \f$ D \f$ to be assigned.
3796  void fill_in_residuals_for_solid_ic(Vector<double> &residuals)
3797  {
3798  //Call the generic residuals function with flag set to 0
3799  //using a dummy matrix argument
3800  fill_in_generic_jacobian_for_solid_ic(
3801  residuals,GeneralisedElement::Dummy_matrix,0);
3802  }
3803 
3804  /// \short Fill in the residuals and Jacobian for the setup of an
3805  /// initial condition. The global equations are:
3806  /// \f[
3807  /// 0 = \int \left( \sum_{j=1}^N \sum_{k=1}^K X_{ijk} \psi_{jk}(\xi_n)
3808  /// - \frac{\partial^D R^{(IC)}_i(\xi_n)}{\partial t^D}
3809  /// \right) \psi_{lm}(\xi_n) \ dv
3810  /// \mbox{ \ \ \ \ for \ \ \ $l=1,...,N, \ \ m=1,...,K$}
3811  /// \f]
3812  /// where \f$ N \f$ is the number of nodes in the mesh and \f$ K \f$
3813  /// the number of generalised nodal coordinates. The initial shape
3814  /// of the solid body, \f$ {\bf R}^{(IC)},\f$ and its time-derivatives
3815  /// are specified via the \c GeomObject that is stored in the
3816  /// \c SolidFiniteElement::SolidInitialCondition object. The latter also
3817  /// stores the order of the time-derivative \f$ D \f$ to be assigned.
3818  void fill_in_jacobian_for_solid_ic(Vector<double> &residuals,
3819  DenseMatrix<double> &jacobian)
3820  {
3821  //Call the generic routine with the flag set to 1
3822  fill_in_generic_jacobian_for_solid_ic(residuals,jacobian,1);
3823  }
3824 
3825 
3826  /// \short Fill in the contributions of the Jacobian matrix
3827  /// for the consistent assignment of the initial "accelerations" in
3828  /// Newmark scheme. In this case the Jacobian is the mass matrix.
3829  void fill_in_jacobian_for_newmark_accel(DenseMatrix<double> &jacobian);
3830 
3831 
3832 
3833  /// \short Calculate the L2 norm of the displacement u=R-r to overload the
3834  /// compute_norm function in the GeneralisedElement base class
3835  void compute_norm(double& el_norm);
3836 
3837  protected:
3838 
3839  /// \short Helper function to fill in the residuals and (if flag==1) the
3840  /// Jacobian for the setup of an initial condition. The global equations are:
3841  /// \f[
3842  /// 0 = \int \left( \sum_{j=1}^N \sum_{k=1}^K X_{ijk} \psi_{jk}(\xi_n)
3843  /// - \frac{\partial^D R^{(IC)}_i(\xi_n)}{\partial t^D}
3844  /// \right) \psi_{lm}(\xi_n) \ dv
3845  /// \mbox{ \ \ \ \ for \ \ \ $l=1,...,N, \ \ m=1,...,K$}
3846  /// \f]
3847  /// where \f$ N \f$ is the number of nodes in the mesh and \f$ K \f$
3848  /// the number of generalised nodal coordinates. The initial shape
3849  /// of the solid body, \f$ {\bf R}^{(IC)},\f$ and its time-derivatives
3850  /// are specified via the \c GeomObject that is stored in the
3851  /// \c SolidFiniteElement::SolidInitialCondition object. The latter also
3852  /// stores the order of the time-derivative \f$ D \f$ to be assigned.
3853  void fill_in_generic_jacobian_for_solid_ic(Vector<double> &residuals,
3854  DenseMatrix<double> &jacobian,
3855  const unsigned& flag);
3856 
3857  /// \short Set the number of types required to interpolate the
3858  /// Lagrangian coordinates
3859  void set_nnodal_lagrangian_type(const unsigned &nlagrangian_type)
3860  {Nnodal_lagrangian_type = nlagrangian_type;}
3861 
3862  /// Pointer to the element's "undeformed" macro element (NULL by default)
3864 
3865  /// \short Calculate the mapping from local to lagrangian coordinates,
3866  /// given the derivatives of the shape functions w.r.t. local coorindates.
3867  /// Return the determinant of the jacobian, the jacobian and inverse jacobian
3869  const DShape &dpsids, DenseMatrix<double> &jacobian,
3870  DenseMatrix<double> &inverse_jacobian) const
3871  {
3872  //Assemble the jacobian
3873  assemble_local_to_lagrangian_jacobian(dpsids,jacobian);
3874  //Invert the jacobian
3875  return invert_jacobian_mapping(jacobian,inverse_jacobian);
3876  }
3877 
3878  /// \short Calculate the mapping from local to lagrangian coordinates,
3879  /// given the derivatives of the shape functions w.r.t. local coordinates,
3880  /// Return only the determinant of the jacobian and the inverse of the
3881  /// mapping (ds/dx)
3882  double local_to_lagrangian_mapping(const DShape &dpsids,
3883  DenseMatrix<double> &inverse_jacobian) const
3884  {
3885  //Find the dimension of the element
3886  unsigned el_dim = dim();
3887  //Assign memory for the jacobian
3888  DenseMatrix<double> jacobian(el_dim);
3889  //Calculate the jacobian and inverse
3890  return local_to_lagrangian_mapping(dpsids,jacobian,inverse_jacobian);
3891  }
3892 
3893  /// \short Calculate the mapping from local to Lagrangian coordinates given
3894  /// the derivatives of the shape functions w.r.t the local coorindates.
3895  /// assuming that the coordinates are aligned in the direction of the local
3896  /// coordinates, i.e. there are no cross terms and the jacobian is diagonal.
3897  /// This function returns the determinant of the jacobian, the jacobian
3898  /// and the inverse jacobian.
3899  virtual double local_to_lagrangian_mapping_diagonal(
3900  const DShape &dpsids,DenseMatrix<double> &jacobian,
3901  DenseMatrix<double> &inverse_jacobian) const;
3902 
3903 
3904  /// \short Assigns local equation numbers for the generic solid
3905  /// local equation numbering schemes.
3906  /// If the boolean flag is true the the degrees of freedom are stored in
3907  /// Dof_pt
3908  virtual void assign_solid_local_eqn_numbers(const bool &store_local_dof);
3909 
3910  /// \short Classifies dofs locally for solid specific aspects.
3911  void describe_solid_local_dofs(std::ostream& out,
3912  const std::string& current_string) const;
3913 
3914  /// \short Pointer to object that specifies the initial condition
3916 
3917  public:
3918 
3919  /// \short Access function that returns the local equation number that
3920  /// corresponds to the j-th coordinate of the k-th position-type at the
3921  /// n-th local node.
3922  inline int position_local_eqn(const unsigned &n, const unsigned &k,
3923  const unsigned &j) const
3924  {
3925 #ifdef RANGE_CHECKING
3926  std::ostringstream error_message;
3927  bool error=false;
3928  if(n >= nnode())
3929  {
3930  error = true;
3931  error_message << "Range Error: Nodal number " << n
3932  << " is not in the range (0,"
3933  << nnode() << ")";
3934  }
3935 
3936  if(k >= nnodal_position_type())
3937  {
3938  error = true;
3939  error_message << "Range Error: Position type " << k
3940  << " is not in the range (0,"
3941  << nnodal_position_type() << ")";
3942  }
3943 
3944  if(j >= nodal_dimension())
3945  {
3946  error=true;
3947  error_message << "Range Error: Nodal coordinate " << j
3948  << " is not in the range (0,"
3949  << nodal_dimension() << ")";
3950  }
3951 
3952  if(error)
3953  {
3954  //Throw the error
3955  throw OomphLibError(error_message.str(),
3956  OOMPH_CURRENT_FUNCTION,
3957  OOMPH_EXCEPTION_LOCATION);
3958  }
3959 #endif
3960 
3961  //Return the value
3962  return Position_local_eqn[(n*nnodal_position_type() + k)*nodal_dimension()
3963  + j];
3964  }
3965 
3966  protected:
3967 
3968 
3969  /// \short Overload the fill_in_contribution_to_jacobian() function to
3970  /// use finite
3971  /// differences to calculate the solid residuals by default
3972  void fill_in_contribution_to_jacobian(Vector<double> &residuals,
3973  DenseMatrix<double> &jacobian)
3974  {
3975  //Add the contribution to the residuals
3977 
3978  //Solve for the consistent acceleration in Newmark scheme?
3979  if(Solve_for_consistent_newmark_accel_flag)
3980  {
3981  fill_in_jacobian_for_newmark_accel(jacobian);
3982  return;
3983  }
3984 
3985  //Allocate storage for the full residuals (residuals of entire element)
3986  unsigned n_dof = ndof();
3987  Vector<double> full_residuals(n_dof);
3988  //Get the residuals for the entire element
3989  get_residuals(full_residuals);
3990  //Get the solid entries in the jacobian using finite differences
3991  fill_in_jacobian_from_solid_position_by_fd(full_residuals,jacobian);
3992  //There could be internal data
3993  //(finite-difference the lot by default)
3994  fill_in_jacobian_from_internal_by_fd(full_residuals,jacobian,true);
3995  //There could also be external data
3996  //(finite-difference the lot by default)
3997  fill_in_jacobian_from_external_by_fd(full_residuals,jacobian,true);
3998  //There could also be nodal data
3999  fill_in_jacobian_from_nodal_by_fd(full_residuals,jacobian);
4000  }
4001 
4002 
4003 
4004  /// \short Use finite differences to calculate the Jacobian entries
4005  /// corresponding to the solid positions. This version assumes
4006  /// that the residuals vector has already been computed
4007 virtual void
4008  fill_in_jacobian_from_solid_position_by_fd(Vector<double> &residuals,
4009  DenseMatrix<double> &jacobian);
4010 
4011 
4012  /// \short Use finite differences to calculate the Jacobian entries
4013  /// corresponding to the solid positions.
4015  {
4016  //Allocate storage for a residuals vector and initialise to zero
4017  unsigned n_dof = ndof();
4018  Vector<double> residuals(n_dof,0.0);
4019  //Get the residuals for the entire element
4020  get_residuals(residuals);
4021  //Call the jacobian calculation
4022  fill_in_jacobian_from_solid_position_by_fd(residuals,jacobian);
4023  }
4024 
4025  /// \short Function that is called before the finite differencing of
4026  /// any solid position data. This may be overloaded to update any slaved
4027  /// data before finite differencing takes place.
4028  virtual inline void update_before_solid_position_fd() { }
4029 
4030  /// \short Function that is call after the finite differencing of
4031  /// the solid position data. This may be overloaded to reset any slaved
4032  /// variables that may have changed during the finite differencing.
4033  virtual inline void reset_after_solid_position_fd() { }
4034 
4035  /// \short Function called within the finite difference loop for
4036  /// the solid position dat after a change in any values in the n-th
4037  /// node.
4038  virtual inline void update_in_solid_position_fd(const unsigned &i) { }
4039 
4040  /// \short Function called within the finite difference loop for
4041  /// solid position data after the values in the i-th node
4042  /// are reset. The default behaviour is to call the update function.
4043  virtual inline void reset_in_solid_position_fd(const unsigned &i)
4044  {update_in_solid_position_fd(i);}
4045 
4046 
4047 private:
4048 
4049  /// \short Assemble the jacobian matrix for the mapping from local
4050  /// to lagrangian coordinates, given the derivatives of the shape function
4051  virtual void assemble_local_to_lagrangian_jacobian(
4052  const DShape &dpsids, DenseMatrix<double> &jacobian) const;
4053 
4054 
4055  /// \short Assemble the the "jacobian" matrix of second derivatives, given
4056  /// the second derivatives of the shape functions w.r.t. local coordinates
4057  virtual void assemble_local_to_lagrangian_jacobian2(
4058  const DShape &d2psids, DenseMatrix<double> &jacobian2) const;
4059 
4060  /// \short Pointer to function that computes the "multiplier" for the
4061  /// inertia terms in the consistent determination of the initial
4062  /// conditions for Newmark timestepping.
4063  MultiplierFctPt Multiplier_fct_pt;
4064 
4065  /// \short Array to hold the local equation number information for the
4066  /// solid equations, whatever they may be.
4067  // ALH: (This is here so that the numbering can be done automatically)
4069 
4070 /// \short The Lagrangian dimension of the nodes stored in the element,
4071 //// i.e. the number of Lagrangian coordinates
4073 
4074  /// \short The number of coordinate types requried to intepolate the
4075  /// Lagrangian coordinates in the element. For Lagrange elements
4076  /// it is 1 (the default). It must be over-ridden by using
4077  /// the set_nlagrangian_type() function in the constructors of elements
4078  /// that use generalised coordinate, e.g. for 1D Hermite elements
4079  /// Nnodal_position_types =2.
4081 
4082 protected:
4083 
4084 /// \short Flag to indicate which system of equations to solve
4085 /// when assigning initial conditions for time-dependent problems.
4086 /// If true, solve for the history value that
4087 /// corresponds to the acceleration in the Newmark scheme by demanding
4088 /// that the PDE is satisifed at the initial time. In this case
4089 /// the Jacobian is replaced by the mass matrix.
4091 
4092 private:
4093 
4094  /// \short Access to the "multiplier" for the
4095  /// inertia terms in the consistent determination of the initial
4096  /// conditions for Newmark timestepping.
4097  inline double multiplier(const Vector<double>& xi)
4098  {
4099  //If no function has been set, return 1
4100  if(Multiplier_fct_pt==0)
4101  {
4102  return 1.0;
4103  }
4104  else
4105  {
4106  // Evaluate function pointer
4107  return (*Multiplier_fct_pt)(xi);
4108  }
4109  }
4110 
4111 
4112 };
4113 
4114 
4115 
4116 
4117 //========================================================================
4118 /// FaceElements are elements that coincide with the faces of
4119 /// higher-dimensional "bulk" elements. They are used on
4120 /// boundaries where additional non-trivial boundary conditions need to be
4121 /// applied. Examples include free surfaces, and applied traction conditions.
4122 /// In many cases, FaceElements need to evaluate to quantities
4123 /// in the associated bulk elements. For instance, the evaluation
4124 /// of a shear stresses on 2D FaceElement requires the evaluation
4125 /// of velocity derivatives in the associated 3D volume element etc.
4126 /// Therefore we store a pointer to the associated bulk element,
4127 /// and information about the relation between the local
4128 /// coordinates in the face and bulk elements.
4129 //========================================================================
4130 class FaceElement: public virtual FiniteElement
4131 {
4132  /// \short Typedef for the function that translates the face coordinate
4133  /// to the coordinate in the bulk element
4134  typedef void (*CoordinateMappingFctPt)(const Vector<double> &s,
4135  Vector<double> &s_bulk);
4136 
4137  /// \short Typedef for the function that returns the partial derivative
4138  /// of the local coordinates in the bulk element
4139  /// with respect to the coordinates along the face.
4140  /// In addition this function returns an index of one of the
4141  /// bulk local coordinates that varies away from the edge
4143  const Vector<double> &s, DenseMatrix<double> &ds_bulk_dsface,
4144  unsigned &interior_direction);
4145 
4146  private:
4147 
4148  /// \short Pointer to a function that translates the face coordinate
4149  /// to the coordinate in the bulk element
4151 
4152  /// \short Pointer to a function that returns the derivatives of the local
4153  /// "bulk" coordinates with respect to the local face coordinates.
4155 
4156  /// \short Vector holding integers to translate additional position types
4157  /// to those of the "bulk" element; e.g. Bulk_position_type(1) is
4158  /// the position type of the "bulk" element that corresponds to face position
4159  /// type 1. This is required in QHermiteElements, where the slope in the
4160  /// direction of the 1D element is face position type 1, but may be
4161  /// position type 1 or 2 in the "bulk" element, depending upon which face,
4162  /// we are located.
4164 
4165  /// \short Sign of outer unit normal (relative to cross-products of tangent
4166  /// vectors in the corresponding "bulk" element.
4168 
4169  /// \short Index of the face
4171 
4172  /// \short Ignores the warning when the tangent vectors from
4173  /// continuous_tangent_and_outer_unit_normal may not be continuous
4174  /// as a result of the unit normal being aligned with the z axis.
4175  /// This can be avoided by supplying a general direction vector for
4176  /// the tangent vector via set_tangent_direction(...).
4178 
4179  protected:
4180 
4181  /// The boundary number in the bulk mesh to which this element is attached
4183 
4184 #ifdef PARANOID
4185 
4186  /// \short Has the Boundary_number_in_bulk_mesh been set? Only included if
4187  /// compiled with PARANOID switched on.
4189 
4190 #endif
4191 
4192  /// \short Pointer to the associated higher-dimensional "bulk" element
4194 
4195  /// \short List of indices of the local node numbers in the "bulk" element
4196  /// that correspond to the local node numbers in the FaceElement
4198 
4199  /// \short A vector that will hold the number of data values at the nodes that
4200  /// are associated with the "bulk" element. i.e. not including any additional
4201  /// degrees of freedom that might be required for extra equations
4202  /// that are being solved by
4203  /// the FaceElement.
4204  // NOTE: This breaks if the nodes have already been resized
4205  // before calling the face element, i.e. two separate sets of equations on the
4206  // face!
4208 
4209  /// \short A general direction pointer for the tangent vectors.
4210  /// This is used in the function continuous_tangent_and_outer_unit_normal()
4211  /// for creating continuous tangent vectors in spatial dimensions.
4212  /// The general direction is projected on to the surface. This technique is
4213  /// not required in two spatial dimensions.
4214  Vector<double>* Tangent_direction_pt;
4215 
4216  /// \short Helper function adding additional values for the unknowns
4217  /// associated with the FaceElement. This function also sets the map
4218  /// containing the position of the first entry of this face element's
4219  /// additional values.The inputs are the number of additional values
4220  /// and the face element's ID. Note the same number of additonal values
4221  /// are allocated at ALL nodes.
4222  void add_additional_values(const Vector<unsigned> &nadditional_values,
4223  const unsigned &id)
4224  {
4225  // How many nodes?
4226  const unsigned n_node=nnode();
4227 
4228  // loop over the nodes
4229  for (unsigned n=0;n<n_node;n++)
4230  {
4231  //Assign the required number of additional nodes to the node
4232  dynamic_cast<BoundaryNodeBase*>(
4233  this->node_pt(n))->assign_additional_values_with_face_id(
4234  nadditional_values[n],id);
4235  }
4236  }
4237 
4238 
4239  public:
4240 
4241  /// Constructor: Initialise all appropriate member data
4242  FaceElement() : Face_to_bulk_coordinate_fct_pt(0),
4243  Bulk_coordinate_derivatives_fct_pt(0), Normal_sign(0), Face_index(0),
4244  Boundary_number_in_bulk_mesh(0), Bulk_element_pt(0), Tangent_direction_pt(0)
4245  {
4246  // Check whether things have been set
4247 #ifdef PARANOID
4248  Boundary_number_in_bulk_mesh_has_been_set = false;
4249 #endif
4250 
4251  // Bulk_position_type[0] is always 0 (the position)
4252  Bulk_position_type.push_back(0);
4253  }
4254 
4255  /// Empty virtual destructor
4256  virtual ~FaceElement() {}
4257 
4258 
4259  /// Broken copy constructor
4261  {
4262  BrokenCopy::broken_copy("FaceElement");
4263  }
4264 
4265  /// Broken assignment operator
4266  /*void operator=(const FaceElement&)
4267  {
4268  BrokenCopy::broken_assign("FaceElement");
4269  }*/
4270 
4271  /// Access function for the boundary number in bulk mesh
4272  inline const unsigned& boundary_number_in_bulk_mesh() const
4273  {return Boundary_number_in_bulk_mesh;}
4274 
4275 
4276  /// Set function for the boundary number in bulk mesh
4277  inline void set_boundary_number_in_bulk_mesh(const unsigned& b)
4278  {
4279  Boundary_number_in_bulk_mesh=b;
4280 #ifdef PARANOID
4281  Boundary_number_in_bulk_mesh_has_been_set=true;
4282 #endif
4283  }
4284 
4285  /// \short In a FaceElement, the "global" intrinsic coordinate
4286  /// of the element along the boundary, when viewed as part of
4287  /// a compound geometric object is specified using the
4288  /// boundary coordinate defined by the mesh.
4289  /// Note: Boundary coordinates will have been set up when
4290  /// creating the underlying mesh, and their values will have
4291  /// been stored at the nodes.
4292  double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i)
4293  const
4294  {
4295  //Vector in which to hold the intrinsic coordinate
4296  Vector<double> zeta(this->dim());
4297 
4298  //Get the k-th generalised boundary coordinate at node n
4299  this->node_pt(n)->get_coordinates_on_boundary(
4300  Boundary_number_in_bulk_mesh,k,zeta);
4301 
4302  //Return the individual coordinate
4303  return zeta[i];
4304  }
4305 
4306  /// \short Return the Jacobian of mapping from local to global
4307  /// coordinates at local position s.
4308  /// Overloaded from FiniteElement.
4309  double J_eulerian(const Vector<double> &s) const;
4310 
4311  /// \short Return the Jacobian of the mapping from local to global
4312  /// coordinates at the ipt-th integration point
4313  /// Overloaded from FiniteElement.
4314  double J_eulerian_at_knot(const unsigned &ipt) const;
4315 
4316  /// \short Check that Jacobian of mapping between local and Eulerian
4317 /// coordinates at all integration points is positive.
4318  void check_J_eulerian_at_knots(bool& passed) const;
4319 
4320  /// \short Return FE interpolated coordinate x[i] at local coordinate s.
4321  /// Overloaded to get information from bulk.
4322  double interpolated_x(const Vector<double> &s, const unsigned &i) const
4323  {
4324  // Local coordinates in bulk element
4325  Vector<double> s_bulk(dim()+1);
4326  s_bulk=local_coordinate_in_bulk(s);
4327 
4328  // Return Eulerian coordinate as computed by bulk
4329  return bulk_element_pt()->interpolated_x(s_bulk,i);
4330  }
4331 
4332  ///\short Return FE interpolated coordinate x[i] at local coordinate s
4333  ///at previous timestep t (t=0: present; t>0: previous timestep).
4334  /// Overloaded to get information from bulk.
4335  double interpolated_x(const unsigned& t, const Vector<double> &s,
4336  const unsigned &i) const
4337  {
4338  // Local coordinates in bulk element
4339  Vector<double> s_bulk(dim()+1);
4340  s_bulk=local_coordinate_in_bulk(s);
4341 
4342  // Return Eulerian coordinate as computed by bulk
4343  return bulk_element_pt()->interpolated_x(t,s_bulk,i);
4344  }
4345 
4346  /// \short Return FE interpolated position x[] at local coordinate s as Vector
4347  /// Overloaded to get information from bulk.
4348  void interpolated_x(const Vector<double> &s, Vector<double>& x) const
4349  {
4350  // Local coordinates in bulk element
4351  Vector<double> s_bulk(dim()+1);
4352  s_bulk=local_coordinate_in_bulk(s);
4353 
4354  // Get Eulerian position vector
4355  bulk_element_pt()->interpolated_x(s_bulk,x);
4356  }
4357 
4358  /// \short Return FE interpolated position x[] at local coordinate s
4359  /// at previous timestep t as Vector (t=0: present; t>0: previous timestep).
4360  /// Overloaded to get information from bulk.
4361  void interpolated_x(const unsigned& t, const Vector<double> &s,
4362  Vector<double>& x) const
4363  {
4364  // Local coordinates in bulk element
4365  Vector<double> s_bulk(dim()+1);
4366  s_bulk=local_coordinate_in_bulk(s);
4367 
4368  // Get Eulerian position vector
4369  bulk_element_pt()->interpolated_x(t,s_bulk,x);
4370  }
4371 
4372  /// \short Return t-th time-derivative of the
4373  /// i-th FE-interpolated Eulerian coordinate at
4374  /// local coordinate s. Overloaded to get information from bulk.
4375  double interpolated_dxdt(const Vector<double> &s,
4376  const unsigned &i,
4377  const unsigned &t)
4378  {
4379  // Local coordinates in bulk element
4380  Vector<double> s_bulk(dim()+1);
4381  s_bulk=local_coordinate_in_bulk(s);
4382 
4383  // Return Eulerian coordinate as computed by bulk
4384  return bulk_element_pt()->interpolated_dxdt(s_bulk,i,t);
4385  }
4386 
4387  /// \short Compte t-th time-derivative of the
4388  /// FE-interpolated Eulerian coordinate vector at
4389  /// local coordinate s. Overloaded to get information from bulk.
4390  void interpolated_dxdt(const Vector<double> &s,
4391  const unsigned &t,
4392  Vector<double>& dxdt)
4393  {
4394  // Local coordinates in bulk element
4395  Vector<double> s_bulk(dim()+1);
4396  s_bulk=local_coordinate_in_bulk(s);
4397 
4398  // Get Eulerian position vector
4399  bulk_element_pt()->interpolated_dxdt(s_bulk,t,dxdt);
4400  }
4401 
4402  /// \short Sign of outer unit normal (relative to cross-products of tangent
4403  /// vectors in the corresponding "bulk" element.
4404  int& normal_sign(){return Normal_sign;}
4405 
4406  /// \short Return sign of outer unit normal (relative to cross-products
4407  /// of tangent vectors in the corresponding "bulk" element. (const version)
4408  int normal_sign() const {return Normal_sign;}
4409 
4410  /// \short Index of the face (a number that uniquely identifies the face
4411  /// in the element)
4412  int& face_index(){return Face_index;}
4413 
4414  /// \short Index of the face (a number that uniquely identifies the face
4415  /// in the element) (const version)
4416  int face_index() const {return Face_index;}
4417 
4418  /// \short Public access function for the tangent direction pointer.
4419  const Vector<double> * tangent_direction_pt() const
4420  {
4421  return Tangent_direction_pt;
4422  }
4423 
4424  /// \short Set the tangent direction vector.
4425  void set_tangent_direction(Vector<double>* tangent_direction_pt)
4426  {
4427 #ifdef PARANOID
4428  // Check that tangent_direction_pt is not null.
4429  if(tangent_direction_pt == 0)
4430  {
4431  std::ostringstream error_message;
4432  error_message
4433  << "The pointer tangent_direction_pt is null.\n";
4434  throw OomphLibError(error_message.str(),
4435  OOMPH_CURRENT_FUNCTION,
4436  OOMPH_EXCEPTION_LOCATION);
4437  }
4438 
4439  // Check that the vector is the correct size.
4440  // The size of the tangent vector.
4441  unsigned tang_dir_size = tangent_direction_pt->size();
4442  unsigned spatial_dimension = this->nodal_dimension();
4443  if(tang_dir_size != spatial_dimension)
4444  {
4445  std::ostringstream error_message;
4446  error_message
4447  << "The tangent direction vector has size " << tang_dir_size << "\n"
4448  << "but this element has spatial dimension " << spatial_dimension
4449  << ".\n";
4450  throw OomphLibError(error_message.str(),
4451  OOMPH_CURRENT_FUNCTION,
4452  OOMPH_EXCEPTION_LOCATION);
4453  }
4454 
4455  if(tang_dir_size == 2)
4456  {
4457  std::ostringstream warning_message;
4458  warning_message
4459  << "The spatial dimension is " << spatial_dimension << ".\n"
4460  << "I do not need a tangent direction vector to create \n"
4461  << "continuous tangent vectors in two spatial dimensions.";
4462  OomphLibWarning(warning_message.str(),
4463  OOMPH_CURRENT_FUNCTION,
4464  OOMPH_EXCEPTION_LOCATION);
4465 
4466  }
4467 #endif
4468 
4469  // Set the direction vector for the tangent.
4470  Tangent_direction_pt = tangent_direction_pt;
4471  }
4472 
4473  /// \short Turn on warning for when there may be discontinuous tangent vectors
4474  /// from continuous_tangent_and_outer_unit_normal(...)
4476  {
4478  }
4479 
4480  /// \short Turn off warning for when there may be discontinuous tangent
4481  /// vectors from continuous_tangent_and_outer_unit_normal(...)
4483  {
4485  }
4486 
4487  /// \short Compute the tangent vector(s) and the outer unit normal
4488  /// vector at the specified local coordinate.
4489  /// In two spatial dimensions, a "tangent direction" is not required.
4490  /// In three spatial dimensions, a tangent direction is required
4491  /// (set via set_tangent_direction(...)), and we project the tanent direction
4492  /// on to the surface. The second tangent vector is taken to be the cross
4493  /// product of the projection and the unit normal.
4494  void continuous_tangent_and_outer_unit_normal
4495  (const Vector<double> &s, Vector<Vector<double> > &tang_vec,
4496  Vector<double> &unit_normal) const;
4497 
4498  /// \short Compute the tangent vector(s) and the outer unit normal
4499  /// vector at the ipt-th integration point. This is a wrapper around
4500  /// continuous_tangent_and_outer_unit_normal(...) with the integration points
4501  /// converted into local coordinates.
4502  void continuous_tangent_and_outer_unit_normal
4503  (const unsigned &ipt, Vector<Vector<double> > &tang_vec,
4504  Vector<double> &unit_normal) const;
4505 
4506  /// \short Compute outer unit normal at the specified local coordinate
4507  void outer_unit_normal(const Vector<double> &s,
4508  Vector<double> &unit_normal) const;
4509 
4510  /// \short Compute outer unit normal at ipt-th integration point
4511  void outer_unit_normal(const unsigned &ipt,
4512  Vector<double> &unit_normal) const;
4513 
4514  /// Pointer to higher-dimensional "bulk" element
4515  FiniteElement*& bulk_element_pt() {return Bulk_element_pt;}
4516 
4517 
4518  /// Pointer to higher-dimensional "bulk" element (const version)
4519  FiniteElement* bulk_element_pt() const {return Bulk_element_pt;}
4520 
4521  //Clang specific pragma's
4522 #ifdef __clang__
4523 #pragma clang diagnostic push
4524 #pragma clang diagnostic ignored "-Woverloaded-virtual"
4525 #endif
4526 
4527  /// \short Return the pointer to the function that maps the face
4528  /// coordinate to the bulk coordinate
4530  {return Face_to_bulk_coordinate_fct_pt;}
4531 
4532  /// \short Return the pointer to the function that maps the face
4533  /// coordinate to the bulk coordinate (const version)
4535  {return Face_to_bulk_coordinate_fct_pt;}
4536 
4537 
4538  /// \short Return the pointer to the function that returns the derivatives
4539  /// of the bulk coordinates wrt the face coordinates
4541  {return Bulk_coordinate_derivatives_fct_pt;}
4542 
4543  /// \short Return the pointer to the function that returns the derivatives
4544  /// of the bulk coordinates wrt the face coordinates (const version)
4546  {return Bulk_coordinate_derivatives_fct_pt;}
4547 
4548 #ifdef __clang__
4549 #pragma clang diagnostic pop
4550 #endif
4551 
4552  /// \short Return vector of local coordinates in bulk element,
4553  /// given the local coordinates in this FaceElement
4554  Vector<double> local_coordinate_in_bulk(const Vector<double>& s) const;
4555 
4556  /// \short Calculate the vector of local coordinate in the bulk element
4557  /// given the local coordinates in this FaceElement
4558  void get_local_coordinate_in_bulk(const Vector<double> &s,
4559  Vector<double> &s_bulk) const;
4560 
4561  /// \short Calculate the derivatives of the local coordinates in the
4562  /// bulk element with respect to the local coordinates in this FaceElement.
4563  /// In addition return the index of a bulk local coordinate that varies away
4564  /// from the face.
4565  void get_ds_bulk_ds_face(const Vector<double> &s,
4566  DenseMatrix<double> &dsbulk_dsface,
4567  unsigned &interior_direction) const;
4568 
4569  /// \short Return the position type in the "bulk" element that corresponds
4570  /// to position type i on the FaceElement.
4571  unsigned& bulk_position_type(const unsigned &i)
4572  {return Bulk_position_type[i];}
4573 
4574  /// \short Return the position type in the "bulk" element that corresponds
4575  /// to the position type i on the FaceElement. Const version
4576  const unsigned &bulk_position_type(const unsigned &i) const
4577  {return Bulk_position_type[i];}
4578 
4579  /// \short Resize the storage for the bulk node numbers
4580  void bulk_node_number_resize(const unsigned &i) {Bulk_node_number.resize(i);}
4581 
4582  /// \short Return the bulk node number that corresponds to the n-th
4583  /// local node number
4584  unsigned &bulk_node_number(const unsigned &n) {return Bulk_node_number[n];}
4585 
4586  /// \short Return the bulk node number that corresponds to the n-th
4587  /// local node number (const version)
4588  const unsigned &bulk_node_number(const unsigned &n) const
4589  {return Bulk_node_number[n];}
4590 
4591  /// \short Resize the storage for bulk_position_type to i entries.
4592  void bulk_position_type_resize(const unsigned &i)
4593  {Bulk_position_type.resize(i);}
4594 
4595  /// \short Return the number of values originally stored at local node n
4596  /// (before the FaceElement added additional values to it (if it did))
4597  unsigned& nbulk_value(const unsigned &n) {return Nbulk_value[n];}
4598 
4599  /// \short Return the number of values originally stored at local node n
4600  /// (before the FaceElement added additional values to it (if it did))
4601  /// (const version)
4602  unsigned nbulk_value(const unsigned &n) const
4603  {return Nbulk_value[n];}
4604 
4605  /// \short Resize the storage for the number of values originally
4606  /// stored at the local nodes to i entries.
4607  void nbulk_value_resize(const unsigned &i) {Nbulk_value.resize(i);}
4608 
4609  /// \short Provide additional storage for a specified number of
4610  /// values at the nodes of the FaceElement. (This is needed, for
4611  /// instance, in free-surface elements, if the non-penetration
4612  /// condition is imposed by Lagrange multipliers whose values
4613  /// are only stored at the surface nodes but not in the interior of
4614  /// the bulk element). \c nadditional_data_values[n] specifies the
4615  /// number of additional values required at node \c n of the
4616  /// FaceElement. \b Note: Since this function is executed separately
4617  /// for each FaceElement, nodes that are common to multiple elements
4618  /// might be resized repeatedly. To avoid this, we only allow
4619  /// a single resize operation by comparing the number of values stored
4620  /// at each node to the number of values the node had when it
4621  /// was simply a member of the associated "bulk"
4622  /// element. <b>There are cases where this will break!</b> -- e.g. if
4623  /// a node is common to two FaceElements which require
4624  /// additional storage for distinct quantities. Such cases
4625  /// need to be handled by "hand-crafted" face elements.
4626  void resize_nodes(Vector<unsigned> &nadditional_data_values)
4627  {
4628  //Locally cache the number of node
4629  unsigned n_node = nnode();
4630  //Resize the storage for values at the nodes:
4631  for(unsigned l=0;l<n_node;l++)
4632  {
4633  //Find number of values stored at the node
4634  unsigned Initial_Nvalue = node_pt(l)->nvalue();
4635  //Read out the number of additional values
4636  unsigned Nadditional = nadditional_data_values[l];
4637  //If the node has not already been resized, resize it
4638  if((Initial_Nvalue == Nbulk_value[l]) && (Nadditional > 0))
4639  {
4640  //Resize the node according to the number of additional values
4641  node_pt(l)->resize(Nbulk_value[l]+Nadditional);
4642  }
4643  } //End of loop over nodes
4644  }
4645 
4646  /// Output boundary coordinate zeta
4647  void output_zeta(std::ostream &outfile, const unsigned& nplot);
4648 
4649 };
4650 
4651 
4652 
4653 //========================================================================
4654 /// SolidFaceElements combine FaceElements and SolidFiniteElements
4655 /// and overload various functions so they work properly in the
4656 /// FaceElement context
4657 //========================================================================
4658 class SolidFaceElement: public virtual FaceElement,
4659  public virtual SolidFiniteElement
4660 {
4661 
4662  public:
4663 
4664  /// \short The "global" intrinsic coordinate of the element when
4665  /// viewed as part of a geometric object should be given by
4666  /// the FaceElement representation, by default
4667  /// This final over-ride is required because both SolidFiniteElements
4668  /// and FaceElements overload zeta_nodal
4669  double zeta_nodal(const unsigned &n, const unsigned &k,
4670  const unsigned &i) const
4671  {return FaceElement::zeta_nodal(n,k,i);}
4672 
4673 
4674 
4675  /// \short Return i-th FE-interpolated Lagrangian coordinate xi[i] at
4676  /// local coordinate s. Overloaded from SolidFiniteElement. Note that
4677  /// the Lagrangian coordinates are those defined in the bulk!
4678  /// For instance, in a 1D FaceElement that is aligned with
4679  /// the Lagrangian coordinate line xi_0=const, only xi_1 will vary
4680  /// in the FaceElement. This may confuse you if you (wrongly!) believe that
4681  /// in a 1D SolidElement there should only a single Lagrangian
4682  /// coordinate, namely xi_0!
4683  double interpolated_xi(const Vector<double> &s,
4684  const unsigned &i) const
4685  {
4686  // Local coordinates in bulk element
4687  Vector<double> s_bulk(dim()+1);
4688  s_bulk=local_coordinate_in_bulk(s);
4689 
4690  // Return Lagrangian coordinate as computed by bulk
4691  return dynamic_cast<SolidFiniteElement*>(bulk_element_pt())->
4692  interpolated_xi(s_bulk,i);
4693  }
4694 
4695 
4696  /// \short Compute FE interpolated Lagrangian coordinate vector xi[] at
4697  /// local coordinate s as Vector. Overloaded from SolidFiniteElement. Note
4698  /// that the Lagrangian coordinates are those defined in the bulk!
4699  /// For instance, in a 1D FaceElement that is aligned with
4700  /// the Lagrangian coordinate line xi_0=const, only xi_1 will vary
4701  /// in the FaceElement. This may confuse you if you (wrongly!) believe that
4702  /// in a 1D SolidElement there should only a single Lagrangian
4703  /// coordinate, namely xi_0!
4704  void interpolated_xi(const Vector<double> &s,
4705  Vector<double>& xi) const
4706  {
4707  // Local coordinates in bulk element
4708  Vector<double> s_bulk(dim()+1);
4709  s_bulk=local_coordinate_in_bulk(s);
4710 
4711  // Get Lagrangian position vector
4712  dynamic_cast<SolidFiniteElement*>(bulk_element_pt())->
4713  interpolated_xi(s_bulk,xi);
4714  }
4715 
4716 
4717 };
4718 
4719 
4720 
4721 ///////////////////////////////////////////////////////////////////////
4722 ///////////////////////////////////////////////////////////////////////
4723 ///////////////////////////////////////////////////////////////////////
4724 
4725 
4726 
4727 //=======================================================================
4728 /// Solid point element
4729 //=======================================================================
4730  class SolidPointElement : public virtual SolidFiniteElement,
4731  public virtual PointElement
4732 {
4733 };
4734 
4735 
4736 ///////////////////////////////////////////////////////////////////////
4737 ///////////////////////////////////////////////////////////////////////
4738 ///////////////////////////////////////////////////////////////////////
4739 
4740 
4741 
4742 
4743 
4744 //=======================================================================
4745 /// FaceGeometry class definition: This policy class is used to allow
4746 /// construction of face elements that solve arbitrary equations without
4747 /// having to tamper with the corresponding "bulk" elements.
4748 /// The geometrical information for the face element must be specified
4749 /// by each "bulk" element using an explicit specialisation of this class.
4750 //=======================================================================
4751 template<class ELEMENT>
4753 {
4754 
4755 };
4756 
4757 
4758 ///////////////////////////////////////////////////////////////////////
4759 ///////////////////////////////////////////////////////////////////////
4760 ///////////////////////////////////////////////////////////////////////
4761 
4762 
4763 
4764 //======================================================================
4765 /// Dummy FaceElement for use with purely geometric operations
4766 /// such as mesh generation.
4767 //======================================================================
4768 template <class ELEMENT>
4769 class DummyFaceElement : public virtual FaceGeometry<ELEMENT>,
4770 public virtual FaceElement
4771 {
4772 
4773 public:
4774 
4775  /// \short Constructor, which takes a "bulk" element and the
4776  /// face index
4777  DummyFaceElement(FiniteElement* const &element_pt,
4778  const int &face_index) :
4779  FaceGeometry<ELEMENT>(), FaceElement()
4780  {
4781  //Attach the geometrical information to the element. N.B. This function
4782  //also assigns nbulk_value from the required_nvalue of the bulk element
4783  element_pt->build_face_element(face_index,this);
4784  }
4785 
4786 
4787  /// \short Constructor
4789  FaceGeometry<ELEMENT>(), FaceElement()
4790  {
4791  }
4792 
4793 
4794  /// \short The "global" intrinsic coordinate of the element when
4795  /// viewed as part of a geometric object should be given by
4796  /// the FaceElement representation, by default
4797  double zeta_nodal(const unsigned &n, const unsigned &k,
4798  const unsigned &i) const
4799  {return FaceElement::zeta_nodal(n,k,i);}
4800 
4801  /// Output nodal coordinates
4802  void output(std::ostream &outfile)
4803  {
4804  outfile << "ZONE" << std::endl;
4805  unsigned nnod=nnode();
4806  for (unsigned j=0;j<nnod;j++)
4807  {
4808  Node* nod_pt=node_pt(j);
4809  unsigned dim=nod_pt->ndim();
4810  for (unsigned i=0;i<dim;i++)
4811  {
4812  outfile << nod_pt->x(i) << " ";
4813  }
4814  outfile << std::endl;
4815  }
4816  }
4817 
4818  /// Output at n_plot points
4819  void output(std::ostream &outfile, const unsigned &n_plot)
4820  {FiniteElement::output(outfile,n_plot);}
4821 
4822  /// C-style output
4823  void output(FILE* file_pt)
4824  {FiniteElement::output(file_pt);}
4825 
4826  /// C_style output at n_plot points
4827  void output(FILE* file_pt, const unsigned &n_plot)
4828  {FiniteElement::output(file_pt,n_plot);}
4829 
4830 };
4831 
4832 ///////////////////////////////////////////////////////////////////////
4833 ///////////////////////////////////////////////////////////////////////
4834 ///////////////////////////////////////////////////////////////////////
4835 
4836 
4837 //=========================================================================
4838 /// Base class for elements that can specify a drag and torque
4839 /// (about the origin) -- typically used for immersed particle
4840 /// computations.
4841 //=========================================================================
4843 {
4844 
4845 public:
4846 
4847  /// Empty constructor
4849 
4850  /// Empty virtual destructor
4852 
4853  /// \short Function that specifies the drag force and the torque about
4854  /// the origin
4855  virtual void get_drag_and_torque(Vector<double>& drag_force,
4856  Vector<double>& drag_torque)=0;
4857 
4858 };
4859 
4860 
4861 ///////////////////////////////////////////////////////////////////////
4862 ///////////////////////////////////////////////////////////////////////
4863 ///////////////////////////////////////////////////////////////////////
4864 
4865 
4866 //======================================================================
4867 /// Basic-ified FaceElement, without any of the functionality of
4868 /// of actual FaceElements -- it's just a surface element of the
4869 /// same geometric type as the FaceGeometry associated with
4870 /// bulk element specified by the template parameter. The element
4871 /// can be used to represent boundaries without actually being
4872 /// attached to a bulk element. Used mainly during unstructured
4873 /// mesh generation.
4874 //======================================================================
4875 template <class ELEMENT>
4876 class FreeStandingFaceElement : public virtual FaceGeometry<ELEMENT>
4877 {
4878 
4879 public:
4880 
4881  /// \short Constructor
4883  FaceGeometry<ELEMENT>(), Boundary_number_in_bulk_mesh(0)
4884  {
4885 
4886  //Check whether things have been set
4887 #ifdef PARANOID
4888  Boundary_number_in_bulk_mesh_has_been_set = false;
4889 #endif
4890 
4891  }
4892 
4893  /// Access function for the boundary number in bulk mesh
4894  inline const unsigned& boundary_number_in_bulk_mesh() const
4895  {return Boundary_number_in_bulk_mesh;}
4896 
4897 
4898  /// Set function for the boundary number in bulk mesh
4899  inline void set_boundary_number_in_bulk_mesh(const unsigned& b)
4900  {
4901  Boundary_number_in_bulk_mesh=b;
4902 #ifdef PARANOID
4903  Boundary_number_in_bulk_mesh_has_been_set=true;
4904 #endif
4905  }
4906 
4907  /// \short In a FaceElement, the "global" intrinsic coordinate
4908  /// of the element along the boundary, when viewed as part of
4909  /// a compound geometric object is specified using the
4910  /// boundary coordinate defined by the mesh.
4911  /// Note: Boundary coordinates will have been set up when
4912  /// creating the underlying mesh, and their values will have
4913  /// been stored at the nodes.
4914  double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i)
4915  const
4916  {
4917  //Vector in which to hold the intrinsic coordinate
4918  Vector<double> zeta(this->dim());
4919 
4920  //Get the k-th generalised boundary coordinate at node n
4921  this->node_pt(n)->get_coordinates_on_boundary(
4922  Boundary_number_in_bulk_mesh,k,zeta);
4923 
4924  //Return the individual coordinate
4925  return zeta[i];
4926  }
4927 
4928  protected:
4929 
4930  /// The boundary number in the bulk mesh to which this element is attached
4932 
4933 #ifdef PARANOID
4934 
4935  /// \short Has the Boundary_number_in_bulk_mesh been set? Only included if
4936  /// compiled with PARANOID switched on.
4938 
4939 #endif
4940 
4941 };
4942 
4943 
4944 
4945 ///////////////////////////////////////////////////////////////////////
4946 ///////////////////////////////////////////////////////////////////////
4947 ///////////////////////////////////////////////////////////////////////
4948 
4949 
4950 //======================================================================
4951 /// Pure virtual base class for elements that can be used with
4952 /// PressureBasedSolidLSCPreconditioner.
4953 //======================================================================
4955 {
4956 
4957  public:
4958 
4959  /// Empty constructor
4961 
4962  /// Virtual destructor
4964 
4965  /// Broken copy constructor
4968  {
4970  "SolidElementWithDiagonalMassMatrix");
4971  }
4972 
4973  /// Broken assignment operator
4974  void operator=(const
4976  {
4978  "SolidElementWithDiagonalMassMatrix");
4979  }
4980 
4981  /// \short Get the diagonal of whatever represents the mass matrix
4982  /// in the specific preconditionable element. For Navier-Stokes
4983  /// elements this is the velocity mass matrix; for incompressible solids it's
4984  /// the mass matrix; ...
4985  virtual void get_mass_matrix_diagonal(Vector<double> &mass_diag)=0;
4986 
4987 };
4988 
4989 
4990 
4991 
4992 ///////////////////////////////////////////////////////////////////////
4993 ///////////////////////////////////////////////////////////////////////
4994 ///////////////////////////////////////////////////////////////////////
4995 
4996 
4997 
4998 //======================================================================
4999 /// Pure virtual base class for elements that can be used with
5000 /// Navier-Stokes Schur complement preconditioner and provide the diagonal
5001 /// of their velocity and pressure mass matrices -- needs to be defined here
5002 /// (in generic) because this applies to a variety of Navier-Stokes
5003 /// elements (cartesian, cylindrical polar, ...)
5004 /// that can be preconditioned effectively by the Navier Stokes (!)
5005 /// preconditioners in the (cartesian) Navier-Stokes directory.
5006 //======================================================================
5008 {
5009 
5010  public:
5011 
5012  /// Empty constructor
5014 
5015  /// Virtual destructor
5017 
5018  /// Broken copy constructor
5021  {
5023  "NavierStokesElementWithDiagonalMassMatrices");
5024  }
5025 
5026  /// Broken assignment operator
5027  void operator=(const
5029  {
5031  "NavierStokesElementWithDiagonalMassMatrices");
5032  }
5033 
5034  /// \short Compute the diagonal of the velocity/pressure mass matrices.
5035  /// If which one=0, both are computed, otherwise only the pressure
5036  /// (which_one=1) or the velocity mass matrix (which_one=2 -- the
5037  /// LSC version of the preconditioner only needs that one)
5038  virtual void get_pressure_and_velocity_mass_matrix_diagonal(
5039  Vector<double> &press_mass_diag, Vector<double> &veloc_mass_diag,
5040  const unsigned& which_one=0)=0;
5041 
5042 };
5043 
5044 
5045 
5046 
5047 ///////////////////////////////////////////////////////////////////////
5048 ///////////////////////////////////////////////////////////////////////
5049 ///////////////////////////////////////////////////////////////////////
5050 
5051 } // end of oomph-lib namespace
5052 
5053 #endif
5054 
5055 
5056 
5057 
5058 
5059 
5060 
5061 
unsigned Boundary_number_in_bulk_mesh
The boundary number in the bulk mesh to which this element is attached.
Definition: elements.h:4931
virtual double local_to_lagrangian_mapping(const DShape &dpsids, DenseMatrix< double > &jacobian, DenseMatrix< double > &inverse_jacobian) const
Calculate the mapping from local to lagrangian coordinates, given the derivatives of the shape functi...
Definition: elements.h:3868
virtual std::string tecplot_zone_string(const unsigned &nplot) const
Return string for tecplot zone header (when plotting nplot points in each "coordinate direction") ...
Definition: elements.h:2990
double raw_value(const unsigned &i) const
Return the i-th value stored at the Node. This interface does NOT take the hanging status of the Node...
Definition: nodes.h:1358
virtual void enable_ALE()
(Re-)enable ALE, i.e. take possible mesh motion into account when evaluating the time-derivative. This function is empty and simply establishes a common interface for all derived elements that are formulated in ALE form.
Definition: elements.h:2320
A Generalised Element class.
Definition: elements.h:76
PointElement(const PointElement &)
Broken copy constructor.
Definition: elements.h:3233
virtual void get_residuals(Vector< double > &residuals)
Calculate the vector of residuals of the equations in the element. By default initialise the vector t...
Definition: elements.h:975
virtual void compute_error(std::ostream &outfile, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, Vector< double > &error, Vector< double > &norm)
Plot the error when compared against a given exact solution . Also calculates the norm of the error a...
Definition: elements.h:3068
virtual double compute_physical_size() const
Broken virtual function to compute the actual size (taking into account factors such as 2pi or radii ...
Definition: elements.h:2677
virtual void reset_after_internal_fd()
Function that is call after the finite differencing of the internal data. This may be overloaded to r...
Definition: elements.h:460
double raw_nodal_position_gen(const unsigned &t, const unsigned &n, const unsigned &k, const unsigned &i) const
Return the generalised nodal position (type k, i-th variable) at previous timesteps at local node n...
Definition: elements.h:2200
void assign_internal_eqn_numbers(unsigned long &global_number, Vector< double *> &Dof_pt)
Assign the global equation numbers to the internal Data. The arguments are the current highest global...
Definition: elements.cc:501
void operator=(const GeneralisedElement &)
Broken assignment operator.
Definition: elements.h:617
DummyFaceElement()
Constructor.
Definition: elements.h:4788
virtual void output_fct(std::ostream &outfile, const unsigned &n_plot, const double &time, const SolutionFunctorBase &exact_soln) const
Output a time-dependent exact solution over the element.
Definition: elements.h:2960
virtual void point_output_data(const Vector< double > &s, Vector< double > &data)
Virtual function to write the double precision numbers that appear in a single line of output into th...
Definition: elements.h:2690
virtual void compute_abs_error(std::ostream &outfile, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, double &error)
Plot the error when compared against a given exact solution . Also calculates the maximum absolute er...
Definition: elements.h:3107
void clear_global_eqn_numbers()
Clear the storage for the global equation numbers and pointers to dofs (if stored) ...
Definition: elements.h:213
void get_x(const Vector< double > &s, Vector< double > &x) const
Global coordinates as function of local coordinates. Either via FE representation or via macro-elemen...
Definition: elements.h:1841
virtual unsigned nscalar_paraview() const
Number of scalars/fields output by this element. Broken virtual. Needs to be implemented for each new...
Definition: elements.h:2838
void read_internal_data_values_from_vector(const Vector< double > &vector_of_values, unsigned &index)
Read all internal data and time history values from the vector starting from index. On return the index will be set to the value at the end of the data that has been read in.
Definition: elements.cc:612
virtual void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Get local coordinates of node j in the element; vector sets its own size (broken virtual) ...
Definition: elements.h:1803
virtual void identify_geometric_data(std::set< Data *> &geometric_data_pt)
The purpose of this function is to identify all Data objects that affect the elements&#39; geometry...
Definition: elements.h:2639
bool has_hanging_nodes() const
Return boolean to indicate if any of the element&#39;s nodes are geometrically hanging.
Definition: elements.h:2356
double raw_nodal_value(const unsigned &n, const unsigned &i) const
Return the i-th value stored at local node n but do NOT take hanging nodes into account.
Definition: elements.h:2458
void broken_copy(const std::string &class_name)
Issue error message and terminate execution.
virtual void reset_in_nodal_fd(const unsigned &i)
Function called within the finite difference loop for nodal data after the i-th nodal values is reset...
Definition: elements.h:1687
virtual void assign_additional_local_eqn_numbers()
Setup any additional look-up schemes for local equation numbers. Examples of use include using local ...
Definition: elements.h:264
void set_must_be_kept_as_halo()
Insist that this element be kept as a halo element during a distribute?
Definition: elements.h:1151
double Radius_multiplier_for_fast_exit_from_locate_zeta
Multiplier for (zeta-based) outer radius of element used for deciding that point is outside element...
Definition: elements.cc:1632
virtual void fill_in_contribution_to_residuals(Vector< double > &residuals)
Add the elemental contribution to the residuals vector. Note that this function will NOT initialise t...
Definition: elements.h:360
void add_global_eqn_numbers(std::deque< unsigned long > const &global_eqn_numbers, std::deque< double *> const &global_dof_pt)
Add the contents of the queue global_eqn_numbers to the local storage for the local-to-global transla...
Definition: elements.cc:149
virtual void get_residuals_for_solid_ic(Vector< double > &residuals)
Compute the residuals for the setup of an initial condition. The global equations are: where is the...
Definition: elements.h:3776
void initialise(const T &val)
Initialize all values in the matrix to val.
Definition: matrices.h:523
void dposition_dt(const Vector< double > &zeta, const unsigned &t, Vector< double > &drdt)
Return the t-th time derivative of the parametrised position of the FiniteElement in its GeomObject i...
Definition: elements.h:2555
std::vector< bool > Data_fd
Storage for boolean flags of size Ninternal_data + Nexternal_data that correspond to the data used in...
Definition: elements.h:127
virtual void assign_all_generic_local_eqn_numbers(const bool &store_local_dof_pt)
Overloaded version of the calculation of the local equation numbers. If the boolean argument is true ...
Definition: elements.h:2099
virtual void reset_in_internal_fd(const unsigned &i)
Function called within the finite difference loop for internal data after the values in the i-th exte...
Definition: elements.h:470
Node * construct_boundary_node(const unsigned &n, TimeStepper *const &time_stepper_pt)
Construct the local node n and return a pointer to it, in the case when the node MAY be located on a ...
Definition: elements.h:3627
virtual unsigned required_nvalue(const unsigned &n) const
Number of values that must be stored at local node n by the element. The default is 0...
Definition: elements.h:2346
virtual void assign_all_generic_local_eqn_numbers(const bool &store_local_dof_pt)
Overload assign_all_generic_local_equation numbers to include the data associated with solid dofs...
Definition: elements.h:3649
virtual void disable_ALE()
This is an empty function that establishes a uniform interface for all (derived) elements that involv...
Definition: elements.h:2297
void include_internal_data_fd(const unsigned &i)
Set the boolean flag to include the internal datum in the finite difference loop when computing the j...
Definition: elements.h:193
unsigned Nnodal_lagrangian_type
The number of coordinate types requried to intepolate the Lagrangian coordinates in the element...
Definition: elements.h:4080
Data * geom_data_pt(const unsigned &j)
Return pointer to the j-th Data item that the object&#39;s shape depends on. (Redirects to the nodes&#39; pos...
Definition: elements.h:3412
Node *const & node_pt(const unsigned &n) const
Return a pointer to the local node n (const version)
Definition: elements.h:2127
void resize_nodes(Vector< unsigned > &nadditional_data_values)
Provide additional storage for a specified number of values at the nodes of the FaceElement. (This is needed, for instance, in free-surface elements, if the non-penetration condition is imposed by Lagrange multipliers whose values are only stored at the surface nodes but not in the interior of the bulk element). nadditional_data_values[n] specifies the number of additional values required at node n of the FaceElement. Note: Since this function is executed separately for each FaceElement, nodes that are common to multiple elements might be resized repeatedly. To avoid this, we only allow a single resize operation by comparing the number of values stored at each node to the number of values the node had when it was simply a member of the associated "bulk" element. There are cases where this will break! – e.g. if a node is common to two FaceElements which require additional storage for distinct quantities. Such cases need to be handled by "hand-crafted" face elements.
Definition: elements.h:4626
static bool Ignore_discontinuous_tangent_warning
Ignores the warning when the tangent vectors from continuous_tangent_and_outer_unit_normal may not be...
Definition: elements.h:4177
unsigned nnodal_lagrangian_type() const
Return the number of types of (generalised) nodal Lagrangian coordinates required to interpolate the ...
Definition: elements.h:3567
virtual ElementGeometry::ElementGeometry element_geometry() const
Return the geometry type of the element (either Q or T usually).
Definition: elements.h:2485
Vector< unsigned > Bulk_position_type
Vector holding integers to translate additional position types to those of the "bulk" element; e...
Definition: elements.h:4163
A class to specify the initial conditions for a solid body. Solid bodies are often discretised with H...
Definition: elements.h:3285
virtual void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Function to compute the geometric shape functions and also first and second derivatives w...
Definition: elements.h:1955
virtual void get_s_plot(const unsigned &i, const unsigned &nplot, Vector< double > &s, const bool &shifted_to_interior=false) const
Get cector of local coordinates of plot point i (when plotting nplot points in each "coordinate direc...
Definition: elements.h:2978
FiniteElement * bulk_element_pt() const
Pointer to higher-dimensional "bulk" element (const version)
Definition: elements.h:4519
void interpolated_x(const Vector< double > &s, Vector< double > &x) const
Return FE interpolated position x[] at local coordinate s as Vector Overloaded to get information fro...
Definition: elements.h:4348
virtual void move_local_coord_back_into_element(Vector< double > &s) const
Adjust local coordinates so that they&#39;re located inside the element.
Definition: elements.h:1785
unsigned lagrangian_dimension() const
Return the number of Lagrangian coordinates that the element requires at all nodes. This is by default the elemental dimension. If we ever need any other case, it can be implemented.
Definition: elements.h:3559
virtual void get_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Calculate the elemental Jacobian matrix "d equation / d variable".
Definition: elements.h:984
virtual void output(std::ostream &outfile)
Output the element data — typically the values at the nodes in a format suitable for post-processing...
Definition: elements.h:2884
void operator=(const SolidElementWithDiagonalMassMatrix &)
Broken assignment operator.
Definition: elements.h:4974
unsigned long * Eqn_number
Storage for the global equation numbers represented by the degrees of freedom in the element...
Definition: elements.h:82
NavierStokesElementWithDiagonalMassMatrices(const NavierStokesElementWithDiagonalMassMatrices &)
Broken copy constructor.
Definition: elements.h:5019
unsigned & ic_time_deriv()
Which time derivative are we currently assigning?
Definition: elements.h:3316
Data * geom_data_pt(const unsigned &j)
A standard FiniteElement is fixed, so there are no geometric data when viewed in its GeomObject incar...
Definition: elements.h:2529
virtual void get_djacobian_dparameter(double *const &parameter_pt, Vector< double > &dres_dparam, DenseMatrix< double > &djac_dparam)
Calculate the derivatives of the elemental Jacobian matrix and residuals with respect to a parameter...
Definition: elements.h:1040
void fill_in_jacobian_from_internal_by_fd(Vector< double > &residuals, DenseMatrix< double > &jacobian, const bool &fd_all_data=false)
Calculate the contributions to the jacobian from the internal degrees of freedom using finite differe...
Definition: elements.cc:1064
void position(const unsigned &t, const Vector< double > &zeta, Vector< double > &r) const
Return the parametrised position of the FiniteElement in its GeomObject incarnation: r(zeta)...
Definition: elements.h:2546
double nodal_position(const unsigned &n, const unsigned &i) const
Return the i-th coordinate at local node n. If the node is hanging, the appropriate interpolation is ...
Definition: elements.h:2227
SolidInitialCondition *& solid_ic_pt()
Pointer to object that describes the initial condition.
Definition: elements.h:3727
virtual unsigned ndof_types() const
The number of types of degrees of freedom in this element are sub-divided into.
Definition: elements.h:1168
unsigned Max_newton_iterations
Maximum number of newton iterations.
Definition: elements.cc:1627
GeomObject *& geom_object_pt()
(Reference to) pointer to geom object that specifies the initial condition
Definition: elements.h:3310
virtual unsigned nplot_points_paraview(const unsigned &nplot) const
Return the number of actual plot points for paraview plot with parameter nplot. Broken virtual; can b...
Definition: elements.h:2712
void(* CoordinateMappingFctPt)(const Vector< double > &s, Vector< double > &s_bulk)
Typedef for the function that translates the face coordinate to the coordinate in the bulk element...
Definition: elements.h:1245
cstr elem_len * i
Definition: cfortran.h:607
double nodal_value(const unsigned &t, const unsigned &n, const unsigned &i) const
Return the i-th value stored at local node n, at time level t (t=0: present; t>0 previous timesteps)...
Definition: elements.h:2476
double dnodal_position_gen_dt(const unsigned &j, const unsigned &n, const unsigned &k, const unsigned &i) const
i-th component of j-th time derivative of the generalised position, dx(k,i)/dt at local node n...
Definition: elements.h:2270
double local_to_eulerian_mapping(const DShape &dpsids, DenseMatrix< double > &inverse_jacobian) const
Calculate the mapping from local to Eulerian coordinates, given the derivatives of the shape function...
Definition: elements.h:1479
int & face_index()
Index of the face (a number that uniquely identifies the face in the element)
Definition: elements.h:4412
MultiplierFctPt multiplier_fct_pt() const
Access function: Pointer to multiplicator function for assignment of consistent assignement of initia...
Definition: elements.h:3756
void position(const Vector< double > &zeta, Vector< double > &r) const
Return the parametrised position of the FiniteElement in its incarnation as a GeomObject, r(zeta). The position is given by the Eulerian coordinate and the intrinsic coordinate (zeta) is the local coordinate of the element (s).
Definition: elements.h:2535
virtual void update_in_solid_position_fd(const unsigned &i)
Function called within the finite difference loop for the solid position dat after a change in any va...
Definition: elements.h:4038
virtual void get_mass_matrix(Vector< double > &residuals, DenseMatrix< double > &mass_matrix)
Calculate the residuals and the elemental "mass" matrix, the matrix that multiplies the time derivati...
Definition: elements.h:997
virtual void fill_in_contribution_to_djacobian_and_dmass_matrix_dparameter(double *const &parameter_pt, Vector< double > &dres_dparam, DenseMatrix< double > &djac_dparam, DenseMatrix< double > &dmass_matrix_dparam)
Add the elemental contribution to the derivative of the jacobian matrix, mass matrix and the residual...
Definition: elements.cc:1416
virtual void fill_in_contribution_to_hessian_vector_products(Vector< double > const &Y, DenseMatrix< double > const &C, DenseMatrix< double > &product)
Fill in contribution to the product of the Hessian (derivative of Jacobian with respect to all variab...
Definition: elements.cc:1469
virtual void fill_in_contribution_to_inner_products(Vector< std::pair< unsigned, unsigned > > const &history_index, Vector< double > &inner_product)
Fill in the contribution to the inner products between given pairs of history values.
Definition: elements.cc:1511
double dnodal_position_gen_dt(const unsigned &n, const unsigned &k, const unsigned &i) const
i-th component of time derivative (velocity) of the generalised position, dx(k,i)/dt at local node n...
Definition: elements.h:2262
void interpolated_x(const unsigned &t, const Vector< double > &s, Vector< double > &x) const
Return FE interpolated position x[] at local coordinate s at previous timestep t as Vector (t=0: pres...
Definition: elements.h:4361
static bool Accept_negative_jacobian
Boolean that if set to true allows a negative jacobian in the transform between global and local coor...
Definition: elements.h:1739
void output(std::ostream &outfile)
Output nodal coordinates.
Definition: elements.h:4802
unsigned Boundary_number_in_bulk_mesh
The boundary number in the bulk mesh to which this element is attached.
Definition: elements.h:4182
void get_x(const unsigned &t, const Vector< double > &s, Vector< double > &x)
Global coordinates as function of local coordinates at previous time "level" t (t=0: present; t>0: pr...
Definition: elements.h:1854
unsigned Elemental_dimension
The spatial dimension of the element, i.e. the number of local coordinates used to parametrize it...
Definition: elements.h:1293
const unsigned & boundary_number_in_bulk_mesh() const
Access function for the boundary number in bulk mesh.
Definition: elements.h:4894
NavierStokesElementWithDiagonalMassMatrices()
Empty constructor.
Definition: elements.h:5013
virtual void update_in_external_fd(const unsigned &i)
Function called within the finite difference loop for external data after a change in any values in t...
Definition: elements.h:487
virtual ~NavierStokesElementWithDiagonalMassMatrices()
Virtual destructor.
Definition: elements.h:5016
virtual void compute_error(std::ostream &outfile, FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt, const double &time, double &error, double &norm)
Plot the error when compared against a given time-dependent exact solution . Also calculates the norm...
Definition: elements.h:3049
BulkCoordinateDerivativesFctPt & bulk_coordinate_derivatives_fct_pt()
Return the pointer to the function that returns the derivatives of the bulk coordinates wrt the face ...
Definition: elements.h:4540
virtual void fill_in_contribution_to_djacobian_dparameter(double *const &parameter_pt, Vector< double > &dres_dparam, DenseMatrix< double > &djac_dparam)
Add the elemental contribution to the derivatives of the elemental Jacobian matrix and residuals with...
Definition: elements.cc:1363
double raw_dnodal_position_gen_dt(const unsigned &n, const unsigned &k, const unsigned &i) const
i-th component of time derivative (velocity) of the generalised position, dx(k,i)/dt at local node n...
Definition: elements.h:2208
A general Finite Element class.
Definition: elements.h:1274
virtual void scalar_value_paraview(std::ofstream &file_out, const unsigned &i, const unsigned &nplot) const
Write values of the i-th scalar field at the plot points. Broken virtual. Needs to be implemented for...
Definition: elements.h:2851
unsigned ngeom_data() const
A standard FiniteElement is fixed, so there are no geometric data when viewed in its GeomObject incar...
Definition: elements.h:2525
GeneralisedElement() GeneralisedElement(const GeneralisedElement &)
Constructor: Initialise all pointers and all values to zero.
Definition: elements.h:611
void set_internal_data_time_stepper(const unsigned &i, TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Set the timestepper associated with the i-th internal data object.
Definition: elements.h:892
void(* UnsteadyExactSolutionFctPt)(const double &, const Vector< double > &, Vector< double > &)
Function pointer for function that computes Vector-valued time-dependent function as ...
Definition: elements.h:1729
SolidInitialCondition(GeomObject *geom_object_pt)
Constructor: Pass geometric object; initialise time deriv to 0.
Definition: elements.h:3291
void output(FILE *file_pt)
C-style output.
Definition: elements.h:4823
char t
Definition: cfortran.h:572
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
In a FaceElement, the "global" intrinsic coordinate of the element along the boundary, when viewed as part of a compound geometric object is specified using the boundary coordinate defined by the mesh. Note: Boundary coordinates will have been set up when creating the underlying mesh, and their values will have been stored at the nodes.
Definition: elements.h:4292
double interpolated_x(const Vector< double > &s, const unsigned &i) const
Return FE interpolated coordinate x[i] at local coordinate s. Overloaded to get information from bulk...
Definition: elements.h:4322
static PointIntegral Default_integration_scheme
Return spatial dimension of element (=number of local coordinates needed to parametrise the element) ...
Definition: elements.h:3260
void exclude_internal_data_fd(const unsigned &i)
Set the boolean flag to exclude the internal datum from the finite difference loop when computing the...
Definition: elements.h:173
virtual int face_outer_unit_normal_sign(const int &face_index) const
Get the sign of the outer unit normal on the face given by face_index.
Definition: elements.h:3157
bool is_halo() const
Is this element a halo?
Definition: elements.h:1141
double raw_nodal_value(const unsigned &t, const unsigned &n, const unsigned &i) const
Return the i-th value stored at local node n, at time level t (t=0: present; t>0 previous timesteps)...
Definition: elements.h:2464
virtual Node * construct_boundary_node(const unsigned &n)
Construct the local node n as a boundary node; that is a node that MAY be placed on a mesh boundary a...
Definition: elements.h:2420
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:852
void fill_in_jacobian_from_nodal_by_fd(DenseMatrix< double > &jacobian)
Calculate the contributions to the jacobian from the nodal degrees of freedom using finite difference...
Definition: elements.h:1659
void identify_geometric_data(std::set< Data *> &geometric_data_pt)
Specify Data that affects the geometry of the element by adding the position Data to the set that&#39;s p...
Definition: elements.h:3419
virtual void get_inner_products(Vector< std::pair< unsigned, unsigned > > const &history_index, Vector< double > &inner_product)
Return the vector of inner product of the given pairs of history values.
Definition: elements.h:1089
virtual void output(FILE *file_pt, const unsigned &n_plot)
Output the element data — pass (some measure of) the number of plot points per element (C style outp...
Definition: elements.h:2929
void output_paraview(std::ofstream &file_out, const unsigned &nplot) const
Paraview output – this outputs the coordinates at the plot points (for parameter nplot) to specified...
Definition: elements.h:2739
unsigned Lagrangian_dimension
The Lagrangian dimension of the nodes stored in the element, / i.e. the number of Lagrangian coordina...
Definition: elements.h:4072
Vector< double > * Tangent_direction_pt
A general direction pointer for the tangent vectors. This is used in the function continuous_tangent_...
Definition: elements.h:4214
virtual void get_inner_product_vectors(Vector< unsigned > const &history_index, Vector< Vector< double > > &inner_product_vector)
Compute the vectors that when taken as a dot product with other history values give the inner product...
Definition: elements.h:1100
void interpolated_dxdt(const Vector< double > &s, const unsigned &t, Vector< double > &dxdt)
Compte t-th time-derivative of the FE-interpolated Eulerian coordinate vector at local coordinate s...
Definition: elements.h:4390
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
Definition: nodes.h:448
CoordinateMappingFctPt Face_to_bulk_coordinate_fct_pt
Pointer to a function that translates the face coordinate to the coordinate in the bulk element...
Definition: elements.h:4150
unsigned & bulk_node_number(const unsigned &n)
Return the bulk node number that corresponds to the n-th local node number.
Definition: elements.h:4584
int * Position_local_eqn
Array to hold the local equation number information for the solid equations, whatever they may be...
Definition: elements.h:4068
void set_boundary_number_in_bulk_mesh(const unsigned &b)
Set function for the boundary number in bulk mesh.
Definition: elements.h:4277
virtual void J_lagrangian(const Vector< double > &s) const
Return the Jacobian of mapping from local to Lagrangian coordinates at local position s...
Definition: elements.h:3708
void fill_in_residuals_for_solid_ic(Vector< double > &residuals)
Fill in the residuals for the setup of an initial condition. The global equations are: where is the...
Definition: elements.h:3796
MacroElement * undeformed_macro_elem_pt()
Access function to pointer to "undeformed" macro element.
Definition: elements.h:3497
A Rank 4 Tensor class.
Definition: matrices.h:1625
void(* BulkCoordinateDerivativesFctPt)(const Vector< double > &s, DenseMatrix< double > &ds_bulk_dsface, unsigned &interior_direction)
Typedef for the function that returns the partial derivative of the local coordinates in the bulk ele...
Definition: elements.h:1253
FaceElement(const FaceElement &)
Broken copy constructor.
Definition: elements.h:4260
virtual void get_hessian_vector_products(Vector< double > const &Y, DenseMatrix< double > const &C, DenseMatrix< double > &product)
Calculate the product of the Hessian (derivative of Jacobian with respect to all variables) an eigenv...
Definition: elements.h:1077
void enable_solve_for_consistent_newmark_accel()
Set to alter the problem being solved when assigning the initial conditions for time-dependent proble...
Definition: elements.h:3738
void fill_in_jacobian_from_external_by_fd(Vector< double > &residuals, DenseMatrix< double > &jacobian, const bool &fd_all_data=false)
Calculate the contributions to the jacobian from the external degrees of freedom using finite differe...
Definition: elements.cc:1158
bool Boundary_number_in_bulk_mesh_has_been_set
Has the Boundary_number_in_bulk_mesh been set? Only included if compiled with PARANOID switched on...
Definition: elements.h:4188
unsigned add_external_data(Data *const &data_pt, const bool &fd=true)
Definition: elements.cc:293
virtual void update_before_solid_position_fd()
Function that is called before the finite differencing of any solid position data. This may be overloaded to update any slaved data before finite differencing takes place.
Definition: elements.h:4028
virtual void get_coordinates_on_boundary(const unsigned &b, const unsigned &k, Vector< double > &boundary_zeta)
Return the vector of the k-th generalised boundary coordinates on mesh boundary b. Broken virtual interface provides run-time error checking.
Definition: nodes.cc:2301
virtual unsigned nplot_points(const unsigned &nplot) const
Return total number of plot points (when plotting nplot points in each "coordinate direction") ...
Definition: elements.h:3017
unsigned Ndof
Number of degrees of freedom.
Definition: elements.h:109
MultiplierFctPt & multiplier_fct_pt()
Access function: Pointer to multiplicator function for assignment of consistent assignement of initia...
Definition: elements.h:3747
double lagrangian_position(const unsigned &n, const unsigned &i) const
Return i-th Lagrangian coordinate at local node n.
Definition: elements.h:3682
void set_n_node(const unsigned &n)
Set the number of nodes in the element to n, by resizing the storage for pointers to the Node objects...
Definition: elements.h:1361
void add_additional_values(const Vector< unsigned > &nadditional_values, const unsigned &id)
Helper function adding additional values for the unknowns associated with the FaceElement. This function also sets the map containing the position of the first entry of this face element&#39;s additional values.The inputs are the number of additional values and the face element&#39;s ID. Note the same number of additonal values are allocated at ALL nodes.
Definition: elements.h:4222
void fill_in_jacobian_from_solid_position_by_fd(DenseMatrix< double > &jacobian)
Use finite differences to calculate the Jacobian entries corresponding to the solid positions...
Definition: elements.h:4014
Node * construct_node(const unsigned &n, TimeStepper *const &time_stepper_pt)
Construct the local node n and return a pointer to it. Additionally, create storage for `history&#39; val...
Definition: elements.h:3588
void set_tangent_direction(Vector< double > *tangent_direction_pt)
Set the tangent direction vector.
Definition: elements.h:4425
virtual void compute_norm(double &norm)
Compute norm of solution – broken virtual can be overloaded by element writer to implement whatever ...
Definition: elements.h:1119
double raw_nodal_position_gen(const unsigned &n, const unsigned &k, const unsigned &i) const
Return the value of the k-th type of the i-th positional variable at the local node n...
Definition: elements.h:2193
void fill_in_jacobian_for_solid_ic(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Fill in the residuals and Jacobian for the setup of an initial condition. The global equations are: ...
Definition: elements.h:3818
void flush_external_data()
Flush all external data.
Definition: elements.cc:365
int & normal_sign()
Sign of outer unit normal (relative to cross-products of tangent vectors in the corresponding "bulk" ...
Definition: elements.h:4404
Node * construct_boundary_node(const unsigned &n)
Construct the local node n and return a pointer to it. in the case when it is a boundary node; that i...
Definition: elements.h:3607
virtual void output(FILE *file_pt)
Output the element data — typically the values at the nodes in a format suitable for post-processing...
Definition: elements.h:2918
MacroElement * Undeformed_macro_elem_pt
Pointer to the element&#39;s "undeformed" macro element (NULL by default)
Definition: elements.h:3863
unsigned nexternal_data() const
Return the number of external data objects.
Definition: elements.h:831
virtual void fill_in_contribution_to_dresiduals_dparameter(double *const &parameter_pt, Vector< double > &dres_dparam)
Add the elemental contribution to the derivatives of the residuals with respect to a parameter...
Definition: elements.cc:1317
unsigned nnodal_position_type() const
Return the number of coordinate types that the element requires to interpolate the geometry between t...
Definition: elements.h:2352
virtual void get_x_from_macro_element(const Vector< double > &s, Vector< double > &x) const
Global coordinates as function of local coordinates using macro element representation. (Broken virtual — this must be overloaded in specific geometric element classes)
Definition: elements.h:1879
void set_dimension(const unsigned &dim)
Set the dimension of the element and initially set the dimension of the nodes to be the same as the d...
Definition: elements.h:1344
virtual double s_min() const
Min value of local coordinate.
Definition: elements.h:2643
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition: nodes.h:992
virtual double local_to_eulerian_mapping(const DShape &dpsids, DenseMatrix< double > &jacobian, DenseMatrix< double > &inverse_jacobian) const
Calculate the mapping from local to Eulerian coordinates, given the derivatives of the shape function...
Definition: elements.h:1464
GeomObject * Geom_object_pt
Pointer to the GeomObject that specifies the initial condition (shape, veloc and accel) ...
Definition: elements.h:3326
double interpolated_xi(const Vector< double > &s, const unsigned &i) const
Return i-th FE-interpolated Lagrangian coordinate xi[i] at local coordinate s. Overloaded from SolidF...
Definition: elements.h:4683
virtual void write_paraview_type(std::ofstream &file_out, const unsigned &nplot) const
Return the paraview element type. Broken virtual. Needs to be implemented for each new geometric elem...
Definition: elements.h:2814
virtual bool has_internal_solid_data()
Return whether there is internal solid data (e.g. discontinuous solid pressure). At present...
Definition: elements.h:3375
virtual void write_paraview_offsets(std::ofstream &file_out, const unsigned &nplot, unsigned &offset_sum) const
Return the offsets for the paraview sub-elements. Broken virtual. Needs to be implemented for each ne...
Definition: elements.h:2826
bool must_be_kept_as_halo() const
Test whether the element must be kept as a halo element.
Definition: elements.h:1158
virtual void set_macro_elem_pt(MacroElement *macro_elem_pt)
Set pointer to macro element – can be overloaded in derived elements to perform additional tasks...
Definition: elements.h:1833
unsigned ndof() const
Return the number of equations/dofs in the element.
Definition: elements.h:834
unsigned nodal_dimension() const
Return the required Eulerian dimension of the nodes in this element.
Definition: elements.h:2370
double local_to_lagrangian_mapping(const DShape &dpsids, DenseMatrix< double > &inverse_jacobian) const
Calculate the mapping from local to lagrangian coordinates, given the derivatives of the shape functi...
Definition: elements.h:3882
virtual unsigned nnode_on_face() const
Definition: elements.h:3164
Vector< unsigned > Bulk_node_number
List of indices of the local node numbers in the "bulk" element that correspond to the local node num...
Definition: elements.h:4197
int Non_halo_proc_ID
Non-halo processor ID for Data; -1 if it&#39;s not a halo.
Definition: elements.h:134
virtual unsigned self_test()
Self-test: Have all internal values been classified as pinned/unpinned? Return 0 if OK...
Definition: elements.cc:1580
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition: nodes.h:995
void bulk_position_type_resize(const unsigned &i)
Resize the storage for bulk_position_type to i entries.
Definition: elements.h:4592
virtual void get_djacobian_and_dmass_matrix_dparameter(double *const &parameter_pt, Vector< double > &dres_dparam, DenseMatrix< double > &djac_dparam, DenseMatrix< double > &dmass_matrix_dparam)
Calculate the derivatives of the elemental Jacobian matrix mass matrix and residuals with respect to ...
Definition: elements.h:1055
A class that contains the information required by Nodes that are located on Mesh boundaries. A BoundaryNode of a particular type is obtained by combining a given Node with this class. By differentiating between Nodes and BoundaryNodes we avoid a lot of un-necessary storage in the bulk Nodes.
Definition: nodes.h:1855
virtual void get_x_from_macro_element(const unsigned &t, const Vector< double > &s, Vector< double > &x)
Global coordinates as function of local coordinates at previous time "level" t (t=0: present; t>0: pr...
Definition: elements.h:1893
void(* SteadyExactSolutionFctPt)(const Vector< double > &, Vector< double > &)
Function pointer for function that computes vector-valued steady "exact solution" as ...
Definition: elements.h:1723
int non_halo_proc_ID()
ID of processor ID that holds non-halo counterpart of halo element; negative if not a halo...
Definition: elements.h:1145
virtual Node * construct_node(const unsigned &n, TimeStepper *const &time_stepper_pt)
Construct the local node n, including storage for history values required by timestepper, and return a pointer to the newly created node object.
Definition: elements.h:2405
void set_boundary_number_in_bulk_mesh(const unsigned &b)
Set function for the boundary number in bulk mesh.
Definition: elements.h:4899
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
The "global" intrinsic coordinate of the element when viewed as part of a geometric object should be ...
Definition: elements.h:4669
double interpolated_x(const unsigned &t, const Vector< double > &s, const unsigned &i) const
Return FE interpolated coordinate x[i] at local coordinate s at previous timestep t (t=0: present; t>...
Definition: elements.h:4335
void point_output(std::ostream &outfile, const Vector< double > &s)
Output solution (as defined by point_output_data()) at local cordinates s.
Definition: elements.h:2695
FiniteElement()
Constructor.
Definition: elements.h:1746
A Rank 3 Tensor class.
Definition: matrices.h:1337
SolidInitialCondition(const SolidInitialCondition &)
Broken copy constructor.
Definition: elements.h:3297
static bool Suppress_warning_about_repeated_external_data
Static boolean to suppress warnings about repeated external data. Defaults to true.
Definition: elements.h:705
unsigned IC_time_deriv
Which time derivative (0,1,2) are we currently assigning.
Definition: elements.h:3329
FaceElement()
Constructor: Initialise all appropriate member data.
Definition: elements.h:4242
void fill_in_jacobian_from_internal_by_fd(DenseMatrix< double > &jacobian, const bool &fd_all_data=false)
Calculate the contributions to the jacobian from the internal degrees of freedom using finite differe...
Definition: elements.h:407
FreeStandingFaceElement()
Constructor.
Definition: elements.h:4882
double raw_lagrangian_position(const unsigned &n, const unsigned &i) const
Return i-th Lagrangian coordinate at local node n without using the hanging representation.
Definition: elements.h:3672
double lagrangian_position_gen(const unsigned &n, const unsigned &k, const unsigned &i) const
Return Generalised Lagrangian coordinate at local node n. `Direction&#39; i, `Type&#39; k.
Definition: elements.h:3687
int face_index() const
Index of the face (a number that uniquely identifies the face in the element) (const version) ...
Definition: elements.h:4416
Integral *const & integral_pt() const
Return the pointer to the integration scheme (const version)
Definition: elements.h:1908
virtual void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Add the elemental contribution to the jacobian matrix. and the residuals vector. Note that this funct...
Definition: elements.h:501
virtual void update_before_nodal_fd()
Function that is called before the finite differencing of any nodal data. This may be overloaded to u...
Definition: elements.h:1673
virtual void get_dof_numbers_for_unknowns(std::list< std::pair< unsigned long, unsigned > > &dof_lookup_list) const
Create a list of pairs for the unknowns that this element is "in charge of" – ignore any unknowns as...
Definition: elements.h:1187
virtual Node * construct_node(const unsigned &n)
Construct the local node n and return a pointer to the newly created node object. ...
Definition: elements.h:2392
BulkCoordinateDerivativesFctPt Bulk_coordinate_derivatives_fct_pt
Pointer to a function that returns the derivatives of the local "bulk" coordinates with respect to th...
Definition: elements.h:4154
virtual void reset_after_external_fd()
Function that is call after the finite differencing of the external data. This may be overloaded to r...
Definition: elements.h:482
bool Must_be_kept_as_halo
Does this element need to be kept as a halo element during a distribute?
Definition: elements.h:137
A template Class for BoundaryNodes; that is Nodes that MAY live on the boundary of a Mesh...
Definition: nodes.h:67
ElementWithDragFunction()
Empty constructor.
Definition: elements.h:4848
virtual void update_in_nodal_fd(const unsigned &i)
Function called within the finite difference loop for nodal data after a change in the i-th nodal val...
Definition: elements.h:1682
void set_halo(const unsigned &non_halo_proc_ID)
Label the element as halo and specify processor that holds non-halo counterpart.
Definition: elements.h:1132
virtual unsigned nsub_elements_paraview(const unsigned &nplot) const
Return the number of local sub-elements for paraview plot with parameter nplot. Broken virtual; can b...
Definition: elements.h:2726
void include_external_data_fd(const unsigned &i)
Set the boolean flag to include the external datum in the the finite difference loop when computing t...
Definition: elements.h:802
virtual unsigned nvertex_node() const
Definition: elements.h:2374
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Overload the fill_in_contribution_to_jacobian() function to use finite differences to calculate the s...
Definition: elements.h:3972
static char t char * s
Definition: cfortran.h:572
double ** Dof_pt
Storage for array of pointers to degrees of freedom ordered by local equation number. This information is not needed, except in continuation, bifurcation tracking and periodic orbit calculations. It is not set up unless the control flag Problem::Store_local_dof_pts_in_elements = true.
Definition: elements.h:89
int ** Nodal_local_eqn
Storage for the local equation numbers associated with the values stored at the nodes.
Definition: elements.h:1286
virtual void reset_in_external_fd(const unsigned &i)
Function called within the finite difference loop for external data after the values in the i-th exte...
Definition: elements.h:492
static bool Suppress_output_while_checking_for_inverted_elements
Static boolean to suppress output while checking for inverted elements.
Definition: elements.h:1743
BulkCoordinateDerivativesFctPt bulk_coordinate_derivatives_fct_pt() const
Return the pointer to the function that returns the derivatives of the bulk coordinates wrt the face ...
Definition: elements.h:4545
Data *& internal_data_pt(const unsigned &i)
Return a pointer to i-th internal data object.
Definition: elements.h:623
void dof_pt_vector(Vector< double *> &dof_pt)
Return the vector of pointers to dof values.
Definition: elements.h:863
void operator=(const NavierStokesElementWithDiagonalMassMatrices &)
Broken assignment operator.
Definition: elements.h:5027
virtual void write_tecplot_zone_footer(std::ostream &outfile, const unsigned &nplot) const
Add tecplot zone "footer" to output stream (when plotting nplot points in each "coordinate direction"...
Definition: elements.h:3003
unsigned long eqn_number(const unsigned &ieqn_local) const
Return the global equation number corresponding to the ieqn_local-th local equation number...
Definition: elements.h:709
static double Tolerance_for_singular_jacobian
Tolerance below which the jacobian is considered singular.
Definition: elements.h:1734
void set_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Set a new timestepper by resizing the appropriate storage. If already assigned the equation numbering...
Definition: nodes.cc:392
virtual void get_dresiduals_dparameter(double *const &parameter_pt, Vector< double > &dres_dparam)
Calculate the derivatives of the residuals with respect to a parameter.
Definition: elements.h:1028
virtual void write_tecplot_zone_footer(FILE *file_pt, const unsigned &nplot) const
Add tecplot zone "footer" to C-style output. (when plotting nplot points in each "coordinate directio...
Definition: elements.h:3011
FiniteElement * Bulk_element_pt
Pointer to the associated higher-dimensional "bulk" element.
Definition: elements.h:4193
void nbulk_value_resize(const unsigned &i)
Resize the storage for the number of values originally stored at the local nodes to i entries...
Definition: elements.h:4607
void describe_dofs(std::ostream &out, const std::string &current_string) const
Function to describe the dofs of the element. The ostream specifies the output stream to which the de...
Definition: elements.cc:522
virtual void set_macro_elem_pt(MacroElement *macro_elem_pt)
Set pointer to MacroElement – overloads generic version and uses the MacroElement also as the defaul...
Definition: elements.h:3472
void set_nnodal_position_type(const unsigned &nposition_type)
Set the number of types required to interpolate the coordinate.
Definition: elements.h:1355
virtual void write_paraview_output_offset_information(std::ofstream &file_out, const unsigned &nplot, unsigned &counter) const
Fill in the offset information for paraview plot. Broken virtual. Needs to be implemented for each ne...
Definition: elements.h:2801
A class that represents a collection of data; each Data object may contain many different individual ...
Definition: nodes.h:89
virtual std::string scalar_name_paraview(const unsigned &i) const
Name of the i-th scalar field. Default implementation returns V1 for the first one, V2 for the second etc. Can (should!) be overloaded with more meaningful names in specific elements.
Definition: elements.h:2877
virtual void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Function to compute the geometric shape functions and derivatives w.r.t. local coordinates at local c...
Definition: elements.h:1922
Vector< unsigned > Nbulk_value
A vector that will hold the number of data values at the nodes that are associated with the "bulk" el...
Definition: elements.h:4207
virtual void update_in_internal_fd(const unsigned &i)
Function called within the finite difference loop for internal data after a change in any values in t...
Definition: elements.h:465
double raw_dnodal_position_dt(const unsigned &n, const unsigned &j, const unsigned &i) const
Return the i-th component of j-th derivative of nodal position: d^jx/dt^j at node n...
Definition: elements.h:2187
unsigned ngeom_data() const
Broken assignment operator.
Definition: elements.h:3408
int normal_sign() const
Return sign of outer unit normal (relative to cross-products of tangent vectors in the corresponding ...
Definition: elements.h:4408
virtual bool local_coord_is_valid(const Vector< double > &s)
Broken assignment operator.
Definition: elements.h:1774
const unsigned & bulk_node_number(const unsigned &n) const
Return the bulk node number that corresponds to the n-th local node number (const version) ...
Definition: elements.h:4588
virtual void get_jacobian_and_mass_matrix(Vector< double > &residuals, DenseMatrix< double > &jacobian, DenseMatrix< double > &mass_matrix)
Calculate the residuals and jacobian and elemental "mass" matrix, the matrix that multiplies the time...
Definition: elements.h:1010
virtual void output_fct(std::ostream &outfile, const unsigned &n_plot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
Output an exact solution over the element.
Definition: elements.h:2938
Data *const & internal_data_pt(const unsigned &i) const
Return a pointer to i-th internal data object (const version)
Definition: elements.h:642
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
The "global" intrinsic coordinate of the element when viewed as part of a geometric object should be ...
Definition: elements.h:4797
void face_node_number_error_check(const unsigned &i) const
Range check for face node numbers.
Definition: elements.h:3172
Data ** Data_pt
Storage for pointers to internal and external data. The data is of the same type and so can be addres...
Definition: elements.h:97
virtual Node * construct_boundary_node(const unsigned &n, TimeStepper *const &time_stepper_pt)
Construct the local node n, including storage for history values required by timestepper, as a boundary node; that is a node that MAY be placed on a mesh boundary and return a pointer to the newly created node object.
Definition: elements.h:2435
virtual double s_max() const
Max. value of local coordinate.
Definition: elements.h:2654
static const unsigned Default_Initial_Nvalue
Default return value for required_nvalue(n) which gives the number of "data" values required by the e...
Definition: elements.h:1333
void add_internal_eqn_numbers_to_vector(Vector< long > &vector_of_eqn_numbers)
Add all equation numbers associated with internal data to the vector in the internal storage order...
Definition: elements.cc:624
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2109
virtual ~ElementWithDragFunction()
Empty virtual destructor.
Definition: elements.h:4851
void fill_in_jacobian_from_external_by_fd(DenseMatrix< double > &jacobian, const bool &fd_all_data=false)
Calculate the contributions to the jacobian from the external degrees of freedom using finite differe...
Definition: elements.h:441
int position_local_eqn(const unsigned &n, const unsigned &k, const unsigned &j) const
Access function that returns the local equation number that corresponds to the j-th coordinate of the...
Definition: elements.h:3922
double raw_dnodal_position_gen_dt(const unsigned &j, const unsigned &n, const unsigned &k, const unsigned &i) const
i-th component of j-th time derivative of the generalised position, dx(k,i)/dt at local node n...
Definition: elements.h:2217
static const double Node_location_tolerance
Default value for the tolerance to be used when locating nodes via local coordinates.
Definition: elements.h:1337
void shape(const double &s, double *Psi)
Definition for 1D Lagrange shape functions. The value of all the shape functions at the local coordin...
Definition: shape.h:549
void initialise(const _Tp &__value)
Iterate over all values and set to the desired value.
Definition: Vector.h:171
void operator=(const SolidInitialCondition &)
Broken assignment operator.
Definition: elements.h:3303
const unsigned & bulk_position_type(const unsigned &i) const
Return the position type in the "bulk" element that corresponds to the position type i on the FaceEle...
Definition: elements.h:4576
MacroElement * macro_elem_pt()
Access function to pointer to macro element.
Definition: elements.h:1837
double nodal_value(const unsigned &n, const unsigned &i) const
Return the i-th value stored at local node n. Produces suitably interpolated values for hanging nodes...
Definition: elements.h:2470
virtual void update_before_internal_fd()
Function that is called before the finite differencing of any internal data. This may be overloaded t...
Definition: elements.h:455
unsigned & bulk_position_type(const unsigned &i)
Return the position type in the "bulk" element that corresponds to position type i on the FaceElement...
Definition: elements.h:4571
Data *const & external_data_pt(const unsigned &i) const
Return a pointer to i-th external data object (const version)
Definition: elements.h:681
unsigned Nexternal_data
Number of external data.
Definition: elements.h:115
void exclude_external_data_fd(const unsigned &i)
Set the boolean flag to exclude the external datum from the the finite difference loop when computing...
Definition: elements.h:781
bool Boundary_number_in_bulk_mesh_has_been_set
Has the Boundary_number_in_bulk_mesh been set? Only included if compiled with PARANOID switched on...
Definition: elements.h:4937
void add_internal_data_values_to_vector(Vector< double > &vector_of_values)
Add all internal data and time history values to the vector in the internal storage order...
Definition: elements.cc:600
void set_nnodal_lagrangian_type(const unsigned &nlagrangian_type)
Set the number of types required to interpolate the Lagrangian coordinates.
Definition: elements.h:3859
void interpolated_xi(const Vector< double > &s, Vector< double > &xi) const
Compute FE interpolated Lagrangian coordinate vector xi[] at local coordinate s as Vector...
Definition: elements.h:4704
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
In a SolidFiniteElement, the "global" intrinsic coordinate of the element when viewed as part of a co...
Definition: elements.h:3437
double nodal_position_gen(const unsigned &n, const unsigned &k, const unsigned &i) const
Return the value of the k-th type of the i-th positional variable at the local node n...
Definition: elements.h:2249
virtual void get_x_and_xi(const Vector< double > &s, Vector< double > &x_fe, Vector< double > &x, Vector< double > &xi_fe, Vector< double > &xi) const
Eulerian and Lagrangian coordinates as function of the local coordinates: The Eulerian position is re...
Definition: elements.h:3451
Data *& external_data_pt(const unsigned &i)
Return a pointer to i-th external data object.
Definition: elements.h:662
int Face_index
Index of the face.
Definition: elements.h:4170
virtual void assign_local_eqn_numbers(const bool &store_local_dof_pt)
Setup the arrays of local equation numbers for the element. If the optional boolean argument is true...
Definition: elements.cc:656
bool Solve_for_consistent_newmark_accel_flag
Flag to indicate which system of equations to solve when assigning initial conditions for time-depend...
Definition: elements.h:4090
void set_nonhalo()
Label the element as not being a halo.
Definition: elements.h:1138
SolidElementWithDiagonalMassMatrix()
Empty constructor.
Definition: elements.h:4960
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
Definition: elements.h:2482
virtual void compute_error(std::ostream &outfile, FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt, const double &time, Vector< double > &error, Vector< double > &norm)
Plot the error when compared against a given time-dependent exact solution . Also calculates the norm...
Definition: elements.h:3087
unsigned ninternal_data() const
Return the number of internal data objects.
Definition: elements.h:828
A Class for nodes that deform elastically (i.e. position is an unknown in the problem). The idea is that the Eulerian positions are stored in a Data object and the Lagrangian coordinates are stored in addition. The pointer that addresses the Eulerian positions is set to the pointer to Value in the Data object. Hence, SolidNode uses knowledge of the internal structure of Data and must be a friend of the Data class. In order to allow a mesh to deform via an elastic-style equation in deforming-domain problems, the positions are stored separately from the values, so that elastic problems may be combined with any other type of problem.
Definition: nodes.h:1569
virtual unsigned nnode_1d() const
Return the number of nodes along one edge of the element Default is to return zero — must be overloa...
Definition: elements.h:2151
virtual void output_fct(std::ostream &outfile, const unsigned &n_plot, const double &time, FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt)
Output a time-dependent exact solution over the element.
Definition: elements.h:2949
void broken_assign(const std::string &class_name)
Issue error message and terminate execution.
void disable_solve_for_consistent_newmark_accel()
Set to reset the problem being solved to be the standard problem.
Definition: elements.h:3742
virtual void output(std::ostream &outfile, const unsigned &n_plot)
Output the element data — pass (some measure of) the number of plot points per element.
Definition: elements.h:2894
virtual ~SolidElementWithDiagonalMassMatrix()
Virtual destructor.
Definition: elements.h:4963
double dnodal_position_dt(const unsigned &n, const unsigned &j, const unsigned &i) const
Return the i-th component of j-th derivative of nodal position: d^jx/dt^j at node n...
Definition: elements.h:2243
void resize(const unsigned &n_value)
Resize the number of equations.
Definition: nodes.cc:2089
void output(std::ostream &outfile, const unsigned &n_plot)
Output at n_plot points.
Definition: elements.h:4819
virtual void fill_in_contribution_to_mass_matrix(Vector< double > &residuals, DenseMatrix< double > &mass_matrix)
Add the elemental contribution to the mass matrix matrix. and the residuals vector. Note that this function should NOT initialise the residuals vector or the mass matrix. It must be called after the residuals vector and jacobian matrix have been initialised to zero. The default is deliberately broken.
Definition: elements.cc:1248
void dof_vector(const unsigned &t, Vector< double > &dof)
Return the vector of dof values at time level t.
Definition: elements.h:837
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn&#39;t been defined.
FiniteElement *& bulk_element_pt()
Pointer to higher-dimensional "bulk" element.
Definition: elements.h:4515
Integral * Integral_pt
Pointer to the spatial integration scheme.
Definition: elements.h:1279
Node ** Node_pt
Storage for pointers to the nodes in the element.
Definition: elements.h:1282
virtual void reset_after_nodal_fd()
Function that is call after the finite differencing of the nodal data. This may be overloaded to rese...
Definition: elements.h:1678
void set_nodal_dimension(const unsigned &nodal_dim)
Set the dimension of the nodes in the element. This will typically only be required when constructing...
Definition: elements.h:1351
static std::deque< double * > Dof_pt_deque
Static storage for deque used to add_global_equation_numbers when pointers to the dofs in each elemen...
Definition: elements.h:232
SolidInitialCondition * Solid_ic_pt
Pointer to object that specifies the initial condition.
Definition: elements.h:3915
void set_undeformed_macro_elem_pt(MacroElement *undeformed_macro_elem_pt)
Set pointer to "undeformed" macro element. Can be overloaded in derived classes to perform additional...
Definition: elements.h:3491
unsigned Nnodal_position_type
The number of coordinate types required to interpolate the element&#39;s geometry between the nodes...
Definition: elements.h:1307
void read_internal_eqn_numbers_from_vector(const Vector< long > &vector_of_eqn_numbers, unsigned &index)
Read all equation numbers associated with internal data from the vector starting from index...
Definition: elements.cc:637
void turn_on_warning_for_discontinuous_tangent()
Turn on warning for when there may be discontinuous tangent vectors from continuous_tangent_and_outer...
Definition: elements.h:4475
double raw_dnodal_position_dt(const unsigned &n, const unsigned &i) const
Return the i-th component of nodal velocity: dx/dt at local node n. Do not use the hanging node repre...
Definition: elements.h:2182
virtual void fill_in_contribution_to_jacobian_and_mass_matrix(Vector< double > &residuals, DenseMatrix< double > &jacobian, DenseMatrix< double > &mass_matrix)
Add the elemental contribution to the jacobian matrix, mass matrix and the residuals vector...
Definition: elements.cc:1281
double multiplier(const Vector< double > &xi)
Access to the "multiplier" for the inertia terms in the consistent determination of the initial condi...
Definition: elements.h:4097
double dnodal_position_dt(const unsigned &n, const unsigned &i) const
Return the i-th component of nodal velocity: dx/dt at local node n.
Definition: elements.h:2238
virtual Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element. Broken virtual function in "pure" finite elements...
Definition: elements.h:2383
unsigned add_internal_data(Data *const &data_pt, const bool &fd=true)
Add a (pointer to an) internal data object to the element and return the index required to obtain it ...
Definition: elements.cc:66
virtual void build_face_element(const int &face_index, FaceElement *face_element_pt)
Function for building a lower dimensional FaceElement on the specified face of the FiniteElement...
Definition: elements.cc:5002
CoordinateMappingFctPt & face_to_bulk_coordinate_fct_pt()
Return the pointer to the function that maps the face coordinate to the bulk coordinate.
Definition: elements.h:4529
SolidFiniteElement()
Constructor: Set defaults.
Definition: elements.h:3383
double nodal_position_gen(const unsigned &t, const unsigned &n, const unsigned &k, const unsigned &i) const
Return the generalised nodal position (type k, i-th variable) at previous timesteps at local node n...
Definition: elements.h:2255
double interpolated_dxdt(const Vector< double > &s, const unsigned &i, const unsigned &t)
Return t-th time-derivative of the i-th FE-interpolated Eulerian coordinate at local coordinate s...
Definition: elements.h:4375
virtual void scalar_value_fct_paraview(std::ofstream &file_out, const unsigned &i, const unsigned &nplot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt) const
Write values of the i-th scalar field at the plot points. Broken virtual. Needs to be implemented for...
Definition: elements.h:2863
int Normal_sign
Sign of outer unit normal (relative to cross-products of tangent vectors in the corresponding "bulk" ...
Definition: elements.h:4167
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Get local coordinates of node j in the element; vector sets its own size.
Definition: elements.h:3248
virtual unsigned get_bulk_node_number(const int &face_index, const unsigned &i) const
Definition: elements.h:3148
const unsigned & boundary_number_in_bulk_mesh() const
Broken assignment operator.
Definition: elements.h:4272
FiniteElement(const FiniteElement &)
Broken copy constructor.
Definition: elements.h:1758
MultiplierFctPt Multiplier_fct_pt
Pointer to function that computes the "multiplier" for the inertia terms in the consistent determinat...
Definition: elements.h:4063
void bulk_node_number_resize(const unsigned &i)
Resize the storage for the bulk node numbers.
Definition: elements.h:4580
Node * construct_node(const unsigned &n)
Construct the local node n and return a pointer to it.
Definition: elements.h:3570
virtual double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Specify the values of the "global" intrinsic coordinate, zeta, of a compound geometric object (a mesh...
Definition: elements.h:2573
double Newton_tolerance
Convergence tolerance for the newton solver.
Definition: elements.cc:1624
unsigned & nbulk_value(const unsigned &n)
Return the number of values originally stored at local node n (before the FaceElement added additiona...
Definition: elements.h:4597
void add_internal_value_pt_to_map(std::map< unsigned, double *> &map_of_value_pt)
Add pointers to the internal data values to map indexed by the global equation number.
Definition: elements.cc:583
virtual void describe_local_dofs(std::ostream &out, const std::string &current_string) const
Function to describe the local dofs of the element. The ostream specifies the output stream to which ...
Definition: elements.cc:545
CoordinateMappingFctPt face_to_bulk_coordinate_fct_pt() const
Return the pointer to the function that maps the face coordinate to the bulk coordinate (const versio...
Definition: elements.h:4534
virtual void reset_in_solid_position_fd(const unsigned &i)
Function called within the finite difference loop for solid position data after the values in the i-t...
Definition: elements.h:4043
void turn_off_warning_for_discontinuous_tangent()
Turn off warning for when there may be discontinuous tangent vectors from continuous_tangent_and_oute...
Definition: elements.h:4482
virtual void reset_after_solid_position_fd()
Function that is call after the finite differencing of the solid position data. This may be overloade...
Definition: elements.h:4033
virtual double local_one_d_fraction_of_node(const unsigned &n1d, const unsigned &i)
Get the local fraction of any node in the n-th position in a one dimensional expansion along the i-th...
Definition: elements.h:1818
virtual void assign_all_generic_local_eqn_numbers(const bool &store_local_dof_pt)
Assign all the local equation numbering schemes that can be applied generically for the element...
Definition: elements.h:254
virtual void fill_in_contribution_to_inner_product_vectors(Vector< unsigned > const &history_index, Vector< Vector< double > > &inner_product_vector)
Fill in the contributions to the vectors that when taken as dot product with other history values giv...
Definition: elements.cc:1543
SolidElementWithDiagonalMassMatrix(const SolidElementWithDiagonalMassMatrix &)
Broken copy constructor.
Definition: elements.h:4966
DummyFaceElement(FiniteElement *const &element_pt, const int &face_index)
Constructor, which takes a "bulk" element and the face index.
Definition: elements.h:4777
virtual void output(const unsigned &t, std::ostream &outfile, const unsigned &n_plot) const
Output the element data at time step t. This is const because it is newly added and so can be done ea...
Definition: elements.h:2905
virtual unsigned nprev_values() const =0
Number of previous values available: 0 for static, 1 for BDF<1>,...
PointElement()
Constructor.
Definition: elements.h:3222
virtual void update_before_external_fd()
Function that is called before the finite differencing of any external data. This may be overloaded t...
Definition: elements.h:477
int local_eqn_number(const unsigned long &ieqn_global) const
Return the local equation number corresponding to the ieqn_global-th global equation number...
Definition: elements.h:731
unsigned Nodal_dimension
The spatial dimension of the nodes in the element. We assume that nodes have the same spatial dimensi...
Definition: elements.h:1299
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2146
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
Definition: timesteppers.h:219
virtual void compute_error(std::ostream &outfile, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, double &error, double &norm)
Plot the error when compared against a given exact solution . Also calculates the norm of the error a...
Definition: elements.h:3033
virtual void set_macro_elem_pt(MacroElement *macro_elem_pt, MacroElement *undeformed_macro_elem_pt)
Set pointers to "current" and "undeformed" MacroElements. Can be overloaded in derived classes to per...
Definition: elements.h:3481
void output(FILE *file_pt, const unsigned &n_plot)
C_style output at n_plot points.
Definition: elements.h:4827
virtual double J_lagrangian_at_knot(const unsigned &ipt) const
Return the Jacobian of the mapping from local to Lagrangian coordinates at the ipt-th integration poi...
Definition: elements.h:3718
virtual void assign_internal_and_external_local_eqn_numbers(const bool &store_local_dof_pt)
Assign the local equation numbers for the internal and external Data This must be called after the gl...
Definition: elements.cc:909
int ** Data_local_eqn
Pointer to array storage for local equation numbers associated with internal and external data...
Definition: elements.h:106
virtual ~FaceElement()
Empty virtual destructor.
Definition: elements.h:4256
unsigned Nnode
Number of nodes in the element.
Definition: elements.h:1289
static double Default_fd_jacobian_step
Double used for the default finite difference step in elemental jacobian calculations.
Definition: elements.h:1164
SolidFiniteElement class.
Definition: elements.h:3361
Solid point element.
Definition: elements.h:4730
double raw_nodal_position(const unsigned &t, const unsigned &n, const unsigned &i) const
Return the i-th coordinate at local node n, at time level t (t=0: present; t>0: previous time level)...
Definition: elements.h:2176
static bool Suppress_warning_about_repeated_internal_data
Static boolean to suppress warnings about repeated internal data. Defaults to false.
Definition: elements.h:701
SolidFiniteElement(const SolidFiniteElement &)
Broken copy constructor.
Definition: elements.h:3394
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Add the elemental contribution to the jacobian matrix. and the residuals vector. Note that this funct...
Definition: elements.h:1697
void set_lagrangian_dimension(const unsigned &lagrangian_dimension)
Set the lagrangian dimension of the element — the number of lagrangian coordinates stored at the nod...
Definition: elements.h:3368
unsigned nbulk_value(const unsigned &n) const
Return the number of values originally stored at local node n (before the FaceElement added additiona...
Definition: elements.h:4602
bool internal_data_fd(const unsigned &i) const
Return the status of the boolean flag indicating whether the internal data is included in the finite ...
Definition: elements.h:152
const Vector< double > * tangent_direction_pt() const
Public access function for the tangent direction pointer.
Definition: elements.h:4419
double value(const unsigned &i) const
Return i-th value (dofs or pinned) at this node either directly or via hanging node representation...
Definition: nodes.cc:2328
int external_local_eqn(const unsigned &i, const unsigned &j)
Return the local equation number corresponding to the j-th value stored at the i-th external data...
Definition: elements.h:313
static DenseMatrix< double > Dummy_matrix
Empty dense matrix used as a dummy argument to combined residual and jacobian functions in the case w...
Definition: elements.h:228
MacroElement * Macro_elem_pt
Pointer to the element&#39;s macro element (NULL by default)
Definition: elements.h:1647
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
In a FaceElement, the "global" intrinsic coordinate of the element along the boundary, when viewed as part of a compound geometric object is specified using the boundary coordinate defined by the mesh. Note: Boundary coordinates will have been set up when creating the underlying mesh, and their values will have been stored at the nodes.
Definition: elements.h:4914
unsigned Ninternal_data
Number of internal data.
Definition: elements.h:112
std::string to_string(T object, unsigned float_precision=8)
Conversion function that should work for anything with operator<< defined (at least all basic types)...
void unset_must_be_kept_as_halo()
Do not insist that this element be kept as a halo element during distribution.
Definition: elements.h:1155
bool external_data_fd(const unsigned &i) const
Return the status of the boolean flag indicating whether the external data is included in the finite ...
Definition: elements.h:759
double raw_lagrangian_position_gen(const unsigned &n, const unsigned &k, const unsigned &i) const
Return Generalised Lagrangian coordinate at local node n. `Direction&#39; i, `Type&#39; k. Does not use the hanging node representation.
Definition: elements.h:3677
double nodal_position(const unsigned &t, const unsigned &n, const unsigned &i) const
Return the i-th coordinate at local node n, at time level t (t=0: present; t>0: previous time level) ...
Definition: elements.h:2233
virtual void complete_setup_of_dependencies()
Complete the setup of any additional dependencies that the element may have. Empty virtual function t...
Definition: elements.h:969
int nodal_local_eqn(const unsigned &n, const unsigned &i) const
Return the local equation number corresponding to the i-th value at the n-th local node...
Definition: elements.h:1386
int internal_local_eqn(const unsigned &i, const unsigned &j) const
Return the local equation number corresponding to the j-th value stored at the i-th internal data...
Definition: elements.h:268