impose_parallel_outflow_element.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 #ifndef OOMPH_IMPOSE_PARALL_ELEMENTS_HEADER
27 #define OOMPH_IMPOSE_PARALL_ELEMENTS_HEADER
28 
29 // Config header generated by autoconfig
30 #ifdef HAVE_CONFIG_H
31 #include <oomph-lib-config.h>
32 #endif
33 
34 namespace oomph
35 {
36  //========================================================================
42  //========================================================================
43  template<class ELEMENT>
44  class ImposeParallelOutflowElement : public virtual FaceGeometry<ELEMENT>,
45  public virtual FaceElement
46  {
47  private:
49  double* Pressure_pt;
50 
52  unsigned Id;
53 
54 
55  public:
61  const int& face_index,
62  const unsigned& id = 0)
63  : FaceGeometry<ELEMENT>(), FaceElement()
64  {
65  // set the Id
66  Id = id;
67 
68  // Build the face element
69  element_pt->build_face_element(face_index, this);
70 
71  // dimension of the bulk element
72  unsigned dim = element_pt->dim();
73 
74  // we need dim-1 additional values for each FaceElement node
75  Vector<unsigned> n_additional_values(nnode(), dim - 1);
76 
77  // add storage for lagrange multipliers and set the map containing
78  // the position of the first entry of this face element's
79  // additional values.
80  add_additional_values(n_additional_values, id);
81 
82  // set the pressure pointer to zero
83  Pressure_pt = 0;
84  }
85 
88  {
89  // Call the generic routine with the flag set to 0
91  residuals, GeneralisedElement::Dummy_matrix, 0);
92  }
93 
96  DenseMatrix<double>& jacobian)
97  {
98  // Call the generic routine with the flag set to 1
100  residuals, jacobian, 1);
101  }
102 
104  void output(std::ostream& outfile)
105  {
106  FiniteElement::output(outfile);
107  }
108 
110  void output(std::ostream& outfile, const unsigned& nplot)
111  {
112  FiniteElement::output(outfile, nplot);
113  }
114 
120  double zeta_nodal(const unsigned& n,
121  const unsigned& k,
122  const unsigned& i) const
123  {
124  return FaceElement::zeta_nodal(n, k, i);
125  }
126 
127 
129  double*& pressure_pt()
130  {
131  return Pressure_pt;
132  }
133 
134  protected:
138  Vector<double>& residuals,
139  DenseMatrix<double>& jacobian,
140  const unsigned& flag)
141  {
142  // Find out how many nodes there are
143  unsigned n_node = nnode();
144 
145  // Dimension of element
146  unsigned dim_el = dim();
147 
148  // Set up memory for the shape functions
149  Shape psi(n_node);
150 
151  // Set the value of n_intpt
152  unsigned n_intpt = integral_pt()->nweight();
153 
154  // to store local equation number
155  int local_eqn = 0;
156  int local_unknown = 0;
157 
158  // to store normal vector
159  Vector<double> norm_vec(dim_el + 1);
160 
161  // to store tangantial vectors
162  Vector<Vector<double>> tang_vec(dim_el, Vector<double>(dim_el + 1));
163 
164  // get the value at which the velocities are stored
165  Vector<unsigned> u_index(dim_el + 1);
166  ELEMENT* el_pt = dynamic_cast<ELEMENT*>(this->bulk_element_pt());
167  for (unsigned i = 0; i < dim_el + 1; i++)
168  {
169  u_index[i] = el_pt->u_index_nst(i);
170  }
171 
172  // Loop over the integration points
173  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
174  {
175  // Get the integral weight
176  double w = integral_pt()->weight(ipt);
177 
178  // Jacobian of mapping
179  double J = J_eulerian_at_knot(ipt);
180 
181  // Premultiply the weights and the Jacobian
182  double W = w * J;
183 
184  // Calculate the shape functions
185  shape_at_knot(ipt, psi);
186 
187  // compute the velocity and the Lagrange multiplier
188  Vector<double> interpolated_u(dim_el + 1, 0.0);
189  Vector<double> lambda(dim_el, 0.0);
190  // Loop over nodes
191  for (unsigned j = 0; j < n_node; j++)
192  {
193  // Assemble the velocity component
194  for (unsigned i = 0; i < dim_el + 1; i++)
195  {
196  interpolated_u[i] += nodal_value(j, u_index[i]) * psi(j);
197  }
198 
199  // Cast to a boundary node
200  BoundaryNodeBase* bnod_pt =
201  dynamic_cast<BoundaryNodeBase*>(node_pt(j));
202 
203  // get the node
204  Node* nod_pt = node_pt(j);
205 
206  // Get the index of the first nodal value associated with
207  // this FaceElement
208  unsigned first_index =
210 
211  // Assemble the Lagrange multiplier
212  for (unsigned l = 0; l < dim_el; l++)
213  {
214  lambda[l] += nod_pt->value(first_index + l) * psi(j);
215  }
216  }
217 
218  this->continuous_tangent_and_outer_unit_normal(ipt, tang_vec, norm_vec);
219 
220  // Assemble residuals and jacobian
221 
222  // Loop over the nodes
223  for (unsigned j = 0; j < n_node; j++)
224  {
225  // Cast to a boundary node
226  BoundaryNodeBase* bnod_pt =
227  dynamic_cast<BoundaryNodeBase*>(node_pt(j));
228 
229  // Get the index of the first nodal value associated with
230  // this FaceElement
231  unsigned first_index =
233 
234  // loop over the lagrange multiplier components
235  for (unsigned l = 0; l < dim_el; l++)
236  {
237  // Local eqn number for the l-th component of lamdba
238  // in the j-th element
239  local_eqn = nodal_local_eqn(j, first_index + l);
240 
241  if (local_eqn >= 0)
242  {
243  for (unsigned i = 0; i < dim_el + 1; i++)
244  {
245  // Assemble residual for lagrange multiplier
246  residuals[local_eqn] +=
247  interpolated_u[i] * tang_vec[l][i] * psi(j) * W;
248 
249  // Assemble Jacobian for Lagrange multiplier:
250  if (flag == 1)
251  {
252  // Loop over the nodes again for unknowns
253  for (unsigned jj = 0; jj < n_node; jj++)
254  {
255  // Local eqn number for the i-th component
256  // of the velocity in the jj-th element
257  local_unknown = nodal_local_eqn(jj, u_index[i]);
258  if (local_unknown >= 0)
259  {
260  jacobian(local_eqn, local_unknown) +=
261  tang_vec[l][i] * psi(jj) * psi(j) * W;
262  }
263  }
264  }
265  }
266  }
267  }
268 
269  // Loop over the directions
270  for (unsigned i = 0; i < dim_el + 1; i++)
271  {
272  // Local eqn number for the i-th component of the
273  // velocity in the j-th element
274  local_eqn = nodal_local_eqn(j, u_index[i]);
275 
276  if (local_eqn >= 0)
277  {
278  // Add the contribution of the imposed pressure
279  if (Pressure_pt != 0)
280  {
281  residuals[local_eqn] -=
282  (*Pressure_pt) * norm_vec[i] * psi(j) * W;
283  }
284 
285  // Add lagrange multiplier contribution to the bulk equation
286  for (unsigned l = 0; l < dim_el; l++)
287  {
288  // Add to residual
289  residuals[local_eqn] += tang_vec[l][i] * psi(j) * lambda[l] * W;
290 
291  // Do Jacobian too?
292  if (flag == 1)
293  {
294  // Loop over the nodes again for unknowns
295  for (unsigned jj = 0; jj < n_node; jj++)
296  {
297  // Cast to a boundary node
298  BoundaryNodeBase* bnode_pt =
299  dynamic_cast<BoundaryNodeBase*>(node_pt(jj));
300 
301  // Local eqn number for the l-th component of lamdba
302  // in the jj-th element
303  local_unknown = nodal_local_eqn(
304  jj,
306  Id) +
307  l);
308  if (local_unknown >= 0)
309  {
310  jacobian(local_eqn, local_unknown) +=
311  tang_vec[l][i] * psi(jj) * psi(j) * W;
312  }
313  }
314  }
315  }
316  }
317  }
318  }
319  }
320  }
321 
327  unsigned ndof_types() const
328  {
329  // The the dof types in this element is 1 in 2D, 2 in 3D, so we use the
330  // elemental dimension function this->dim().
331  // In addition, we have the number of constrained velocity dof types, this
332  // is this->dim()+1 dof types.
333  // In total we have 2*(this->dim()) + 1 dof types.
334  return 2 * (this->dim()) + 1;
335  }
336 
354  std::list<std::pair<unsigned long, unsigned>>& dof_lookup_list) const
355  {
356  // Temporary pair (used to store dof lookup prior to being added to list)
357  std::pair<unsigned, unsigned> dof_lookup;
358 
359  // Number of nodes in this element.
360  const unsigned n_node = this->nnode();
361 
362  // The elemental dimension.
363  const unsigned dim_el = this->dim();
364 
365  // The spatial dimension, since this is a face element, as assume that the
366  // spatial dimension is one higher than the elemental dimension.
367  const unsigned dim_bulk = dim_el + 1;
368 
369  // The classification of the constrained bulk velocity dof types is
370  // i, i = 0, ..., dim_bulk.
371  //
372  // The classification of the lagrange multiplier dof types is
373  // i + dim_bulk, i = 0, ..., dim_el
374  // as it is offset by the spatial dimension.
375 
376  // Loop over the nodes
377  for (unsigned node_i = 0; node_i < n_node; node_i++)
378  {
379  // First we classify the constrained velocity dof types from the bulk
380  // element. NOTE: This is a RE-CLASSIFICATION, since the dof types we
381  // are classifying should already be classified at least once by the
382  // bulk element. Furthermore, we assume that the velocity dof types
383  // comes first, then the pressure dof types. This is indeed true with
384  // OOMPH-LIB's implementation of Navier-Stokes elements.
385  for (unsigned velocity_i = 0; velocity_i < dim_bulk; velocity_i++)
386  {
387  // We only concern ourselves with the nodes of the "bulk" element
388  // that are associated with this "face" element. Bulk_node_number
389  // gives us the mapping from the face element's node to the bulk
390  // element's node. The local equation number is required to check if
391  // the value is pinned, if it is not pinned, the local equation number
392  // is required to get the global equation number.
393  int local_eqn = Bulk_element_pt->nodal_local_eqn(
394  Bulk_node_number[node_i], velocity_i);
395 
396  // Ignore pinned values.
397  if (local_eqn >= 0)
398  {
399  // Store the dof lookup in temporary pair: First entry in pair
400  // is the global equation number; second entry is the LOCAL dof
401  // type. It is assumed that the velocity dof types comes first. We
402  // do not re-classify the pressure dof types as they are not
403  // constrained.
404  dof_lookup.first = Bulk_element_pt->eqn_number(local_eqn);
405  dof_lookup.second = velocity_i;
406  dof_lookup_list.push_front(dof_lookup);
407  } // ignore pinned nodes "if(local-eqn>=0)"
408  } // for loop over the velocity components
409 
410  // Now we classify the dof types of this face element.
411  // Cast to a boundary node
412  BoundaryNodeBase* bnod_pt =
413  dynamic_cast<BoundaryNodeBase*>(node_pt(node_i));
414 
415  // Loop over directions in this Face(!)Element
416  for (unsigned dim_i = 0; dim_i < dim_el; dim_i++)
417  {
418  // Local eqn number:
419  int local_eqn = nodal_local_eqn(
420  node_i,
422 
423  if (local_eqn >= 0)
424  {
425  // Store dof lookup in temporary pair: First entry in pair
426  // is global equation number; second entry is dof type.
427  // We assume that the first 2(3) types are fluid dof types in
428  // 2(3) spatial dimensions (classified above):
429  //
430  // 0 1 2 3 4
431  // up vp wp L1 L2
432  //
433  // Thus the offset is the dim_bulk.
434  dof_lookup.first = this->eqn_number(local_eqn);
435  dof_lookup.second = dim_i + dim_bulk;
436 
437  // Add to list
438  dof_lookup_list.push_front(dof_lookup);
439  } // if local_eqn > 0
440  } // for: loop over the directions in the face element.
441  } // for: loop over the nodes in the face element.
442 
443  } // get_dof_numbers_for_unknowns
444 
445  }; // End of ImposeParallelOutflowElement class
446 
447 } // namespace oomph
448 
449 #endif
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
cout<< "The eigenvalues of A are:"<< endl<< ces.eigenvalues()<< endl;cout<< "The matrix of eigenvectors, V, is:"<< endl<< ces.eigenvectors()<< endl<< endl;complex< float > lambda
Definition: ComplexEigenSolver_compute.cpp:9
JacobiRotation< float > J
Definition: Jacobi_makeJacobi.cpp:3
RowVector3d w
Definition: Matrix_resize_int.cpp:3
Definition: nodes.h:1996
unsigned index_of_first_value_assigned_by_face_element(const unsigned &face_id=0) const
Definition: nodes.h:2061
Definition: elements.h:4338
Vector< unsigned > Bulk_node_number
Definition: elements.h:4403
FiniteElement * Bulk_element_pt
Pointer to the associated higher-dimensional "bulk" element.
Definition: elements.h:4399
int & face_index()
Definition: elements.h:4626
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Definition: elements.h:4497
void add_additional_values(const Vector< unsigned > &nadditional_values, const unsigned &id)
Definition: elements.h:4428
FiniteElement *& bulk_element_pt()
Pointer to higher-dimensional "bulk" element.
Definition: elements.h:4735
double J_eulerian_at_knot(const unsigned &ipt) const
Definition: elements.cc:5328
void continuous_tangent_and_outer_unit_normal(const Vector< double > &s, Vector< Vector< double >> &tang_vec, Vector< double > &unit_normal) const
Definition: elements.cc:5512
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
double nodal_value(const unsigned &n, const unsigned &i) const
Definition: elements.h:2593
virtual void output(std::ostream &outfile)
Definition: elements.h:3050
virtual void build_face_element(const int &face_index, FaceElement *face_element_pt)
Definition: elements.cc:5132
int nodal_local_eqn(const unsigned &n, const unsigned &i) const
Definition: elements.h:1432
unsigned dim() const
Definition: elements.h:2611
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2210
Integral *const & integral_pt() const
Return the pointer to the integration scheme (const version)
Definition: elements.h:1963
virtual void shape_at_knot(const unsigned &ipt, Shape &psi) const
Definition: elements.cc:3220
unsigned long eqn_number(const unsigned &ieqn_local) const
Definition: elements.h:704
static DenseMatrix< double > Dummy_matrix
Definition: elements.h:227
Definition: impose_parallel_outflow_element.h:46
void fill_in_generic_contribution_to_residuals_parall_lagr_multiplier(Vector< double > &residuals, DenseMatrix< double > &jacobian, const unsigned &flag)
Definition: impose_parallel_outflow_element.h:137
unsigned ndof_types() const
Definition: impose_parallel_outflow_element.h:327
void get_dof_numbers_for_unknowns(std::list< std::pair< unsigned long, unsigned >> &dof_lookup_list) const
Definition: impose_parallel_outflow_element.h:353
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Fill in the residuals.
Definition: impose_parallel_outflow_element.h:87
unsigned Id
Lagrange Id.
Definition: impose_parallel_outflow_element.h:52
double * Pressure_pt
pointer to imposed pressure – if null then no pressure imposed.
Definition: impose_parallel_outflow_element.h:49
void output(std::ostream &outfile, const unsigned &nplot)
Output function: x,y,[z],u,v,[w],p in tecplot format.
Definition: impose_parallel_outflow_element.h:110
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Fill in contribution from Jacobian.
Definition: impose_parallel_outflow_element.h:95
double *& pressure_pt()
Access function for the pressure.
Definition: impose_parallel_outflow_element.h:129
void output(std::ostream &outfile)
Overload the output function.
Definition: impose_parallel_outflow_element.h:104
ImposeParallelOutflowElement(FiniteElement *const &element_pt, const int &face_index, const unsigned &id=0)
Definition: impose_parallel_outflow_element.h:60
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Definition: impose_parallel_outflow_element.h:120
virtual unsigned nweight() const =0
Return the number of integration points of the scheme.
virtual double weight(const unsigned &i) const =0
Return weight of i-th integration point.
Definition: nodes.h:906
double value(const unsigned &i) const
Definition: nodes.cc:2408
Definition: shape.h:76
char char char int int * k
Definition: level2_impl.h:374
@ W
Definition: quadtree.h:63
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition: AnisotropicHookean.h:10
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2