darcy_face_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-2022 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 elements that are used to apply surface loads to
27 // the Darcy equations
28 
29 #ifndef OOMPH_DARCY_FACE_ELEMENTS_HEADER
30 #define OOMPH_DARCY_FACE_ELEMENTS_HEADER
31 
32 // Config header generated by autoconfig
33 #ifdef HAVE_CONFIG_H
34 #include <oomph-lib-config.h>
35 #endif
36 
37 
38 // OOMPH-LIB headers
39 #include "../../../src/generic/Qelements.h"
40 
41 namespace oomph
42 {
43  //=======================================================================
46  //=======================================================================
47  namespace DarcyFaceElementHelper
48  {
49  //=======================================================================
51  //=======================================================================
52  void Zero_pressure_fct(const double& time,
53  const Vector<double>& x,
54  const Vector<double>& N,
55  double& load)
56  {
57  load = 0.0;
58  }
59 
60  } // namespace DarcyFaceElementHelper
61 
62 
63  //======================================================================
69  //======================================================================
70  template<class ELEMENT>
71  class DarcyFaceElement : public virtual FaceGeometry<ELEMENT>,
72  public virtual FaceElement
73  {
74  protected:
79  void (*Pressure_fct_pt)(const double& time,
80  const Vector<double>& x,
81  const Vector<double>& n,
82  double& result);
83 
84 
90  virtual void get_pressure(const double& time,
91  const unsigned& intpt,
92  const Vector<double>& x,
93  const Vector<double>& n,
94  double& pressure)
95  {
96  Pressure_fct_pt(time, x, n, pressure);
97  }
98 
99 
101  // This small level of indirection is required to avoid calling
102  // fill_in_contribution_to_residuals in fill_in_contribution_to_jacobian
103  // which causes all kinds of pain if overloading later on
105  Vector<double>& residuals);
106 
107 
108  public:
111  DarcyFaceElement(FiniteElement* const& element_pt, const int& face_index)
112  : FaceGeometry<ELEMENT>(), FaceElement()
113  {
114 #ifdef PARANOID
115  {
116  // Check that the element is not a refineable 3d element
117  ELEMENT* elem_pt = dynamic_cast<ELEMENT*>(element_pt);
118  // If it's three-d
119  if (elem_pt->dim() == 3)
120  {
121  // Is it refineable
122  RefineableElement* ref_el_pt =
123  dynamic_cast<RefineableElement*>(elem_pt);
124  if (ref_el_pt != 0)
125  {
126  if (this->has_hanging_nodes())
127  {
128  throw OomphLibError("This flux element will not work correctly "
129  "if nodes are hanging\n",
132  }
133  }
134  }
135  }
136 #endif
137 
138  // Attach the geometrical information to the element. N.B. This function
139  // also assigns nbulk_value from the required_nvalue of the bulk element
140  element_pt->build_face_element(face_index, this);
141 
142  // Zero pressure
144  }
145 
146 
148  void (*&pressure_fct_pt())(const double& time,
149  const Vector<double>& x,
150  const Vector<double>& n,
151  double& pressure)
152  {
153  return Pressure_fct_pt;
154  }
155 
156 
159  {
161  }
162 
163 
166  DenseMatrix<double>& jacobian)
167  {
168  // Call the residuals
170  }
171 
177  double zeta_nodal(const unsigned& n,
178  const unsigned& k,
179  const unsigned& i) const
180  {
181  return FaceElement::zeta_nodal(n, k, i);
182  }
183 
185  void output(std::ostream& outfile)
186  {
188  }
189 
191  void output(std::ostream& outfile, const unsigned& n_plot)
192  {
193  FaceGeometry<ELEMENT>::output(outfile, n_plot);
194  }
195 
197  void output(FILE* file_pt)
198  {
200  }
201 
203  void output(FILE* file_pt, const unsigned& n_plot)
204  {
205  FaceGeometry<ELEMENT>::output(file_pt, n_plot);
206  }
207 
208 
212  void pressure(const double& time,
213  const Vector<double>& s,
214  double& pressure);
215  };
216 
220 
221  //=====================================================================
225  //=====================================================================
226  template<class ELEMENT>
227  void DarcyFaceElement<ELEMENT>::pressure(const double& time,
228  const Vector<double>& s,
229  double& pressure)
230  {
231  unsigned n_dim = this->nodal_dimension();
232 
233  // Position vector
234  Vector<double> x(n_dim);
235  interpolated_x(s, x);
236 
237  // Outer unit normal
238  Vector<double> unit_normal(n_dim);
239  outer_unit_normal(s, unit_normal);
240 
241  // Dummy
242  unsigned ipt = 0;
243 
244  // Pressure value
245  get_pressure(time, ipt, x, unit_normal, pressure);
246  }
247 
248 
249  //=====================================================================
251  //=====================================================================
252  template<class ELEMENT>
254  Vector<double>& residuals)
255  {
256  // Find out how many nodes there are
257  unsigned n_node = nnode();
258 
259  // Get continuous time from timestepper of first node
260  double time = node_pt(0)->time_stepper_pt()->time_pt()->time();
261 
262 #ifdef PARANOID
263  // Find out how many positional dofs there are
264  unsigned n_position_type = this->nnodal_position_type();
265  if (n_position_type != 1)
266  {
267  throw OomphLibError("Darcy equations are not yet implemented for more "
268  "than one position type",
271  }
272 #endif
273 
274  // Find out the dimension of the node
275  unsigned n_dim = this->nodal_dimension();
276 
277  // Set the pointer to the bulk element
278  ELEMENT* bulk_el_pt = dynamic_cast<ELEMENT*>(bulk_element_pt());
279 
280  unsigned n_q_basis = bulk_el_pt->nq_basis();
281  unsigned n_q_basis_edge = bulk_el_pt->nq_basis_edge();
282 
283  // Integer to hold the local equation number
284  int local_eqn = 0;
285 
286  // Set up memory for the shape functions
287  // Note that in this case, the number of lagrangian coordinates is always
288  // equal to the dimension of the nodes
289  Shape psi(n_node);
290  DShape dpsids(n_node, n_dim - 1);
291 
292  Shape q_basis(n_q_basis, n_dim);
293 
294  // Set the value of n_intpt
295  unsigned n_intpt = integral_pt()->nweight();
296 
297  // Storage for the local coordinates
298  Vector<double> s_face(n_dim - 1, 0.0), s_bulk(n_dim, 0.0);
299 
300  // Loop over the integration points
301  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
302  {
303  // Get the integral weight
304  double w = integral_pt()->weight(ipt);
305 
306  // Only need to call the local derivatives
307  dshape_local_at_knot(ipt, psi, dpsids);
308 
309  // Assign values of s in FaceElement and local coordinates in bulk element
310  for (unsigned i = 0; i < n_dim - 1; i++)
311  {
312  s_face[i] = integral_pt()->knot(ipt, i);
313  }
314 
315  s_bulk = local_coordinate_in_bulk(s_face);
316 
317  // Get the q basis at bulk local coordinate s_bulk, corresponding to
318  // face local coordinate s_face
319  bulk_el_pt->get_q_basis(s_bulk, q_basis);
320 
321  // Calculate the Eulerian and Lagrangian coordinates
322  Vector<double> interpolated_x(n_dim, 0.0);
323 
324  // Also calculate the surface Vectors (derivatives wrt local coordinates)
325  DenseMatrix<double> interpolated_A(n_dim - 1, n_dim, 0.0);
326 
327  // Calculate displacements and derivatives
328  for (unsigned l = 0; l < n_node; l++)
329  {
330  // Loop over directions
331  for (unsigned i = 0; i < n_dim; i++)
332  {
333  // Calculate the Eulerian coords
334  const double x_local = nodal_position(l, i);
335  interpolated_x[i] += x_local * psi(l);
336 
337  // Loop over LOCAL derivative directions, to calculate the tangent(s)
338  for (unsigned j = 0; j < n_dim - 1; j++)
339  {
340  interpolated_A(j, i) += x_local * dpsids(l, j);
341  }
342  }
343  }
344 
345  // Now find the local metric tensor from the tangent vectors
346  DenseMatrix<double> A(n_dim - 1);
347  for (unsigned i = 0; i < n_dim - 1; i++)
348  {
349  for (unsigned j = 0; j < n_dim - 1; j++)
350  {
351  // Initialise surface metric tensor to zero
352  A(i, j) = 0.0;
353 
354  // Take the dot product
355  for (unsigned k = 0; k < n_dim; k++)
356  {
357  A(i, j) += interpolated_A(i, k) * interpolated_A(j, k);
358  }
359  }
360  }
361 
362  // Get the outer unit normal
363  Vector<double> interpolated_normal(n_dim);
364  outer_unit_normal(ipt, interpolated_normal);
365 
366  // Find the determinant of the metric tensor
367  double Adet = 0.0;
368  switch (n_dim)
369  {
370  case 2:
371  Adet = A(0, 0);
372  break;
373  case 3:
374  Adet = A(0, 0) * A(1, 1) - A(0, 1) * A(1, 0);
375  break;
376  default:
377  throw OomphLibError("Wrong dimension in DarcyFaceElement",
380  }
381 
382  // Premultiply the weights and the square-root of the determinant of
383  // the metric tensor
384  double W = w * sqrt(Adet);
385 
386  // Now calculate the load
387  double pressure;
388  get_pressure(time, ipt, interpolated_x, interpolated_normal, pressure);
389 
390  // Loop over the q edge test functions only (internal basis functions
391  // have zero normal component on the boundary)
392  for (unsigned l = 0; l < n_q_basis_edge; l++)
393  {
394  local_eqn = this->nodal_local_eqn(1, bulk_el_pt->q_edge_index(l));
395 
396  /*IF it's not a boundary condition*/
397  if (local_eqn >= 0)
398  {
399  // Loop over the displacement components
400  for (unsigned i = 0; i < n_dim; i++)
401  {
402  // Add the loading terms to the residuals
403  residuals[local_eqn] +=
404  pressure * q_basis(l, i) * interpolated_normal[i] * W;
405  }
406  } // End of if not boundary condition
407  } // End of loop over shape functions
408  } // End of loop over integration points
409  }
410 
411 } // namespace oomph
412 
413 #endif
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
RowVector3d w
Definition: Matrix_resize_int.cpp:3
void load(Archive &ar, ParticleHandler &handl)
Definition: Particles.h:21
Matrix< SCALARA, Dynamic, Dynamic, opt_A > A
Definition: bench_gemm.cpp:47
Definition: shape.h:278
Definition: darcy_face_elements.h:73
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Return the residuals.
Definition: darcy_face_elements.h:158
void(*&)(const double &time, const Vector< double > &x, const Vector< double > &n, double &pressure) pressure_fct_pt()
Reference to the pressure function pointer.
Definition: darcy_face_elements.h:148
void(* Pressure_fct_pt)(const double &time, const Vector< double > &x, const Vector< double > &n, double &result)
Definition: darcy_face_elements.h:79
void fill_in_contribution_to_residuals_darcy_face(Vector< double > &residuals)
Helper function that actually calculates the residuals.
Definition: darcy_face_elements.h:253
void output(FILE *file_pt)
C_style output function.
Definition: darcy_face_elements.h:197
void output(FILE *file_pt, const unsigned &n_plot)
C-style output function.
Definition: darcy_face_elements.h:203
DarcyFaceElement(FiniteElement *const &element_pt, const int &face_index)
Definition: darcy_face_elements.h:111
void output(std::ostream &outfile, const unsigned &n_plot)
Output function.
Definition: darcy_face_elements.h:191
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Fill in contribution from Jacobian.
Definition: darcy_face_elements.h:165
void pressure(const double &time, const Vector< double > &s, double &pressure)
Definition: darcy_face_elements.h:227
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Definition: darcy_face_elements.h:177
virtual void get_pressure(const double &time, const unsigned &intpt, const Vector< double > &x, const Vector< double > &n, double &pressure)
Definition: darcy_face_elements.h:90
void output(std::ostream &outfile)
Output function.
Definition: darcy_face_elements.h:185
Definition: elements.h:4338
int & face_index()
Definition: elements.h:4626
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Definition: elements.h:4497
Definition: elements.h:4998
Definition: elements.h:1313
virtual void build_face_element(const int &face_index, FaceElement *face_element_pt)
Definition: elements.cc:5132
bool has_hanging_nodes() const
Definition: elements.h:2470
Definition: oomph_definitions.h:222
Definition: refineable_elements.h:97
Definition: shape.h:76
@ N
Definition: constructor.cpp:22
RealScalar s
Definition: level1_cplx_impl.h:130
char char char int int * k
Definition: level2_impl.h:374
void get_pressure(const Vector< double > &x, double &pressure)
Pressure depending on the position (x,y)
Definition: all_foeppl_von_karman/circular_disk.cc:60
void Zero_pressure_fct(const double &time, const Vector< double > &x, const Vector< double > &N, double &load)
Default load function (zero pressure)
Definition: darcy_face_elements.h:52
@ W
Definition: quadtree.h:63
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition: AnisotropicHookean.h:10
list x
Definition: plotDoE.py:28
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86
void output(std::ostream &outfile, const unsigned &nplot)
Overload output function.
Definition: overloaded_element_body.h:490
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2