poisson_flux_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 prescribed flux
27 // boundary conditions to the Poisson equations
28 #ifndef OOMPH_POISSON_FLUX_ELEMENTS_HEADER
29 #define OOMPH_POISSON_FLUX_ELEMENTS_HEADER
30 
31 
32 // Config header generated by autoconfig
33 #ifdef HAVE_CONFIG_H
34 #include <oomph-lib-config.h>
35 #endif
36 
37 // oomph-lib includes
38 #include "../generic/Qelements.h"
39 
40 namespace oomph
41 {
42  //======================================================================
47  //======================================================================
48  template<class ELEMENT>
49  class PoissonFluxElement : public virtual FaceGeometry<ELEMENT>,
50  public virtual FaceElement
51  {
52  public:
56  double& flux);
57 
60  PoissonFluxElement(FiniteElement* const& bulk_el_pt, const int& face_index);
61 
64  {
65  throw OomphLibError("Don't call empty constructor for PoissonFluxElement",
68  }
69 
71  PoissonFluxElement(const PoissonFluxElement& dummy) = delete;
72 
74  void operator=(const PoissonFluxElement&) = delete;
75 
81  double zeta_nodal(const unsigned& n,
82  const unsigned& k,
83  const unsigned& i) const
84  {
85  return FaceElement::zeta_nodal(n, k, i);
86  }
87 
90  {
91  return Flux_fct_pt;
92  }
93 
94 
97  {
98  // Call the generic residuals function with flag set to 0
99  // using a dummy matrix argument
101  residuals, GeneralisedElement::Dummy_matrix, 0);
102  }
103 
104 
108  DenseMatrix<double>& jacobian)
109  {
110  // Call the generic routine with the flag set to 1
112  residuals, jacobian, 1);
113  }
114 
116  void output(std::ostream& outfile)
117  {
118  const unsigned n_plot = 5;
119  output(outfile, n_plot);
120  }
121 
123  void output(std::ostream& outfile, const unsigned& nplot)
124  {
125  // Dimension of element
126  unsigned el_dim = dim();
127 
128  // Vector of local coordinates
130 
131  // Tecplot header info
132  outfile << tecplot_zone_string(nplot);
133 
134  // Loop over plot points
135  unsigned num_plot_points = nplot_points(nplot);
136  for (unsigned iplot = 0; iplot < num_plot_points; iplot++)
137  {
138  // Get local coordinates of plot point
139  get_s_plot(iplot, nplot, s);
140 
141  Vector<double> x(el_dim + 1);
142  for (unsigned i = 0; i < el_dim + 1; i++)
143  {
144  x[i] = interpolated_x(s, i);
145  outfile << x[i] << " ";
146  }
147  double flux = 0.0;
148  get_flux(x, flux);
149  outfile << flux << std::endl;
150  }
151 
152  // Write tecplot footer (e.g. FE connectivity lists)
153  write_tecplot_zone_footer(outfile, nplot);
154  }
155 
156 
159  void output(FILE* file_pt)
160  {
161  FiniteElement::output(file_pt);
162  }
163 
167  void output(FILE* file_pt, const unsigned& n_plot)
168  {
169  FiniteElement::output(file_pt, n_plot);
170  }
171 
172 
173  protected:
177  inline double shape_and_test(const Vector<double>& s,
178  Shape& psi,
179  Shape& test) const
180  {
181  // Find number of nodes
182  unsigned n_node = nnode();
183 
184  // Get the shape functions
185  shape(s, psi);
186 
187  // Set the test functions to be the same as the shape functions
188  for (unsigned i = 0; i < n_node; i++)
189  {
190  test[i] = psi[i];
191  }
192 
193  // Return the value of the jacobian
194  return J_eulerian(s);
195  }
196 
197 
201  inline double shape_and_test_at_knot(const unsigned& ipt,
202  Shape& psi,
203  Shape& test) const
204  {
205  // Find number of nodes
206  unsigned n_node = nnode();
207 
208  // Get the shape functions
209  shape_at_knot(ipt, psi);
210 
211  // Set the test functions to be the same as the shape functions
212  for (unsigned i = 0; i < n_node; i++)
213  {
214  test[i] = psi[i];
215  }
216 
217  // Return the value of the jacobian
218  return J_eulerian_at_knot(ipt);
219  }
220 
221 
224  void get_flux(const Vector<double>& x, double& flux)
225  {
226  // If the function pointer is zero return zero
227  if (Flux_fct_pt == 0)
228  {
229  flux = 0.0;
230  }
231  // Otherwise call the function
232  else
233  {
234  (*Flux_fct_pt)(x, flux);
235  }
236  }
237 
238  private:
243  Vector<double>& residuals,
244  DenseMatrix<double>& jacobian,
245  const unsigned& flag);
246 
247 
250 
252  unsigned Dim;
253 
255  unsigned U_index_poisson;
256  };
257 
261 
262 
263  //===========================================================================
269  //===========================================================================
270  template<class ELEMENT>
272  FiniteElement* const& bulk_el_pt, const int& face_index)
273  : FaceGeometry<ELEMENT>(), FaceElement()
274  {
275  // Let the bulk element build the FaceElement, i.e. setup the pointers
276  // to its nodes (by referring to the appropriate nodes in the bulk
277  // element), etc.
278  bulk_el_pt->build_face_element(face_index, this);
279 
280 #ifdef PARANOID
281  {
282  // Check that the element is not a refineable 3d element
283  ELEMENT* elem_pt = dynamic_cast<ELEMENT*>(bulk_el_pt);
284  // If it's three-d
285  if (elem_pt->dim() == 3)
286  {
287  // Is it refineable
288  RefineableElement* ref_el_pt =
289  dynamic_cast<RefineableElement*>(elem_pt);
290  if (ref_el_pt != 0)
291  {
292  if (this->has_hanging_nodes())
293  {
294  throw OomphLibError("This flux element will not work correctly if "
295  "nodes are hanging\n",
298  }
299  }
300  }
301  }
302 #endif
303 
304  // Initialise the prescribed-flux function pointer to zero
305  Flux_fct_pt = 0;
306 
307  // Extract the dimension of the problem from the dimension of
308  // the first node
309  Dim = this->node_pt(0)->ndim();
310 
311  // Set up U_index_poisson. Initialise to zero, which probably won't change
312  // in most cases, oh well, the price we pay for generality
313  U_index_poisson = 0;
314 
315  // Cast to the appropriate PoissonEquation so that we can
316  // find the index at which the variable is stored
317  // We assume that the dimension of the full problem is the same
318  // as the dimension of the node, if this is not the case you will have
319  // to write custom elements, sorry
320  switch (Dim)
321  {
322  // One dimensional problem
323  case 1:
324  {
325  PoissonEquations<1>* eqn_pt =
326  dynamic_cast<PoissonEquations<1>*>(bulk_el_pt);
327  // If the cast has failed die
328  if (eqn_pt == 0)
329  {
330  std::string error_string =
331  "Bulk element must inherit from PoissonEquations.";
332  error_string +=
333  "Nodes are one dimensional, but cannot cast the bulk element to\n";
334  error_string += "PoissonEquations<1>\n.";
335  error_string += "If you desire this functionality, you must "
336  "implement it yourself\n";
337 
338  throw OomphLibError(
340  }
341  // Otherwise read out the value
342  else
343  {
344  // Read the index from the (cast) bulk element
345  U_index_poisson = eqn_pt->u_index_poisson();
346  }
347  }
348  break;
349 
350  // Two dimensional problem
351  case 2:
352  {
353  PoissonEquations<2>* eqn_pt =
354  dynamic_cast<PoissonEquations<2>*>(bulk_el_pt);
355  // If the cast has failed die
356  if (eqn_pt == 0)
357  {
358  std::string error_string =
359  "Bulk element must inherit from PoissonEquations.";
360  error_string +=
361  "Nodes are two dimensional, but cannot cast the bulk element to\n";
362  error_string += "PoissonEquations<2>\n.";
363  error_string += "If you desire this functionality, you must "
364  "implement it yourself\n";
365 
366  throw OomphLibError(
368  }
369  else
370  {
371  // Read the index from the (cast) bulk element.
372  U_index_poisson = eqn_pt->u_index_poisson();
373  }
374  }
375  break;
376 
377  // Three dimensional problem
378  case 3:
379  {
380  PoissonEquations<3>* eqn_pt =
381  dynamic_cast<PoissonEquations<3>*>(bulk_el_pt);
382  // If the cast has failed die
383  if (eqn_pt == 0)
384  {
385  std::string error_string =
386  "Bulk element must inherit from PoissonEquations.";
387  error_string += "Nodes are three dimensional, but cannot cast the "
388  "bulk element to\n";
389  error_string += "PoissonEquations<3>\n.";
390  error_string += "If you desire this functionality, you must "
391  "implement it yourself\n";
392 
393  throw OomphLibError(
395  }
396  else
397  {
398  // Read the index from the (cast) bulk element.
399  U_index_poisson = eqn_pt->u_index_poisson();
400  }
401  }
402  break;
403 
404  // Any other case is an error
405  default:
406  std::ostringstream error_stream;
407  error_stream << "Dimension of node is " << Dim
408  << ". It should be 1,2, or 3!" << std::endl;
409 
410  throw OomphLibError(
411  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
412  break;
413  }
414  }
415 
416 
417  //===========================================================================
419  //===========================================================================
420  template<class ELEMENT>
423  Vector<double>& residuals,
424  DenseMatrix<double>& jacobian,
425  const unsigned& flag)
426  {
427  // Find out how many nodes there are
428  const unsigned n_node = nnode();
429 
430  // Set up memory for the shape and test functions
431  Shape psif(n_node), testf(n_node);
432 
433  // Set the value of Nintpt
434  const unsigned n_intpt = integral_pt()->nweight();
435 
436  // Set the Vector to hold local coordinates
437  Vector<double> s(Dim - 1);
438 
439  // Integers to hold the local equation and unknown numbers
440  int local_eqn = 0;
441 
442  // Locally cache the index at which the variable is stored
443  const unsigned u_index_poisson = U_index_poisson;
444 
445  // Loop over the integration points
446  //--------------------------------
447  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
448  {
449  // Assign values of s
450  for (unsigned i = 0; i < (Dim - 1); i++)
451  {
452  s[i] = integral_pt()->knot(ipt, i);
453  }
454 
455  // Get the integral weight
456  double w = integral_pt()->weight(ipt);
457 
458  // Find the shape and test functions and return the Jacobian
459  // of the mapping
460  double J = shape_and_test(s, psif, testf);
461 
462  // Premultiply the weights and the Jacobian
463  double W = w * J;
464 
465  // Need to find position to feed into flux function, initialise to zero
466  Vector<double> interpolated_x(Dim, 0.0);
467 
468  // Calculate velocities and derivatives
469  for (unsigned l = 0; l < n_node; l++)
470  {
471  // Loop over velocity components
472  for (unsigned i = 0; i < Dim; i++)
473  {
474  interpolated_x[i] += nodal_position(l, i) * psif[l];
475  }
476  }
477 
478  // Get the imposed flux
479  double flux;
480  get_flux(interpolated_x, flux);
481 
482  // Now add to the appropriate equations
483 
484  // Loop over the test functions
485  for (unsigned l = 0; l < n_node; l++)
486  {
487  local_eqn = nodal_local_eqn(l, u_index_poisson);
488  /*IF it's not a boundary condition*/
489  if (local_eqn >= 0)
490  {
491  // Add the prescribed flux terms
492  residuals[local_eqn] -= flux * testf[l] * W;
493 
494  // Imposed traction doesn't depend upon the solution,
495  // --> the Jacobian is always zero, so no Jacobian
496  // terms are required
497  }
498  }
499  }
500  }
501 
502 
503 } // namespace oomph
504 
505 #endif
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
JacobiRotation< float > J
Definition: Jacobi_makeJacobi.cpp:3
RowVector3d w
Definition: Matrix_resize_int.cpp:3
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
double interpolated_x(const Vector< double > &s, const unsigned &i) const
Definition: elements.h:4528
double J_eulerian(const Vector< double > &s) const
Definition: elements.cc:5242
double J_eulerian_at_knot(const unsigned &ipt) const
Definition: elements.cc:5328
Definition: elements.h:4998
Definition: elements.h:1313
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2175
virtual void output(std::ostream &outfile)
Definition: elements.h:3050
virtual std::string tecplot_zone_string(const unsigned &nplot) const
Definition: elements.h:3161
virtual void build_face_element(const int &face_index, FaceElement *face_element_pt)
Definition: elements.cc:5132
virtual void shape(const Vector< double > &s, Shape &psi) const =0
unsigned dim() const
Definition: elements.h:2611
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2210
virtual void get_s_plot(const unsigned &i, const unsigned &nplot, Vector< double > &s, const bool &shifted_to_interior=false) const
Definition: elements.h:3148
virtual unsigned nplot_points(const unsigned &nplot) const
Definition: elements.h:3186
virtual void write_tecplot_zone_footer(std::ostream &outfile, const unsigned &nplot) const
Definition: elements.h:3174
virtual void shape_at_knot(const unsigned &ipt, Shape &psi) const
Definition: elements.cc:3220
bool has_hanging_nodes() const
Definition: elements.h:2470
static DenseMatrix< double > Dummy_matrix
Definition: elements.h:227
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition: nodes.h:1054
Definition: oomph_definitions.h:222
virtual unsigned u_index_poisson() const
Definition: poisson_elements.h:85
Definition: poisson_flux_elements.h:51
double shape_and_test(const Vector< double > &s, Shape &psi, Shape &test) const
Definition: poisson_flux_elements.h:177
void output(FILE *file_pt)
Definition: poisson_flux_elements.h:159
PoissonFluxElement()
Broken empty constructor.
Definition: poisson_flux_elements.h:63
PoissonFluxElement(const PoissonFluxElement &dummy)=delete
Broken copy constructor.
unsigned Dim
The spatial dimension of the problem.
Definition: poisson_flux_elements.h:252
void operator=(const PoissonFluxElement &)=delete
Broken assignment operator.
double shape_and_test_at_knot(const unsigned &ipt, Shape &psi, Shape &test) const
Definition: poisson_flux_elements.h:201
void get_flux(const Vector< double > &x, double &flux)
Definition: poisson_flux_elements.h:224
void(* PoissonPrescribedFluxFctPt)(const Vector< double > &x, double &flux)
Definition: poisson_flux_elements.h:55
void fill_in_generic_residual_contribution_poisson_flux(Vector< double > &residuals, DenseMatrix< double > &jacobian, const unsigned &flag)
Compute the element's residual vector and the (zero) Jacobian matrix.
Definition: poisson_flux_elements.h:422
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Definition: poisson_flux_elements.h:107
void output(std::ostream &outfile, const unsigned &nplot)
Output function.
Definition: poisson_flux_elements.h:123
PoissonPrescribedFluxFctPt & flux_fct_pt()
Access function for the prescribed-flux function pointer.
Definition: poisson_flux_elements.h:89
unsigned U_index_poisson
The index at which the unknown is stored at the nodes.
Definition: poisson_flux_elements.h:255
void output(std::ostream &outfile)
Output function.
Definition: poisson_flux_elements.h:116
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Add the element's contribution to its residual vector.
Definition: poisson_flux_elements.h:96
void output(FILE *file_pt, const unsigned &n_plot)
Definition: poisson_flux_elements.h:167
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Definition: poisson_flux_elements.h:81
PoissonPrescribedFluxFctPt Flux_fct_pt
Function pointer to the (global) prescribed-flux function.
Definition: poisson_flux_elements.h:249
Definition: refineable_elements.h:97
Definition: shape.h:76
RealScalar s
Definition: level1_cplx_impl.h:130
char char char int int * k
Definition: level2_impl.h:374
static const unsigned Dim
Problem dimension.
Definition: two_d_tilted_square.cc:62
void flux(const double &time, const Vector< double > &x, double &flux)
Get flux applied along boundary x=0.
Definition: pretend_melt.cc:59
std::string string(const unsigned &i)
Definition: oomph_definitions.cc:286
@ W
Definition: quadtree.h:63
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition: AnisotropicHookean.h:10
void get_flux(const Vector< double > &s, Vector< double > &flux) const
Get flux: .
Definition: gen_axisym_advection_diffusion_elements.h:424
list x
Definition: plotDoE.py:28
Definition: indexed_view.cpp:20
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86
unsigned el_dim
dimension
Definition: overloaded_cartesian_element_body.h:30