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