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-2025 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
30#ifdef HAVE_CONFIG_H
31#include <oomph-lib-config.h>
32#endif
33
34namespace oomph
35{
36 //========================================================================
37 /// ImposeParallelOutflowElement
38 /// are elements that coincide with the faces of
39 /// higher-dimensional "bulk" elements. They are used on
40 /// boundaries where we would like to impose parallel outflow and
41 /// impose the pressure.
42 //========================================================================
43 template<class ELEMENT>
44 class ImposeParallelOutflowElement : public virtual FaceGeometry<ELEMENT>,
45 public virtual FaceElement
46 {
47 private:
48 /// pointer to imposed pressure -- if null then no pressure imposed.
49 double* Pressure_pt;
50
51 /// Lagrange Id
52 unsigned Id;
53
54
55 public:
56 /// Constructor takes a "bulk" element, the
57 /// index that identifies which face the
58 /// ImposeParallelOutflowElement is supposed
59 /// to be attached to, and the face element ID
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
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.
81
82 // set the pressure pointer to zero
83 Pressure_pt = 0;
84 }
85
86 /// Fill in the residuals
93
94 /// Fill in contribution from Jacobian
96 DenseMatrix<double>& jacobian)
97 {
98 // Call the generic routine with the flag set to 1
100 residuals, jacobian, 1);
101 }
102
103 /// Overload the output function
104 void output(std::ostream& outfile)
105 {
107 }
108
109 /// Output function: x,y,[z],u,v,[w],p in tecplot format
110 void output(std::ostream& outfile, const unsigned& nplot)
111 {
113 }
114
115 /// The "global" intrinsic coordinate of the element when
116 /// viewed as part of a geometric object should be given by
117 /// the FaceElement representation, by default
118 /// This final over-ride is required because both SolidFiniteElements
119 /// and FaceElements overload zeta_nodal
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
128 /// Access function for the pressure
129 double*& pressure_pt()
130 {
131 return Pressure_pt;
132 }
133
134 protected:
135 /// Helper function to compute the residuals and, if flag==1, the
136 /// Jacobian
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
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
160
161 // to store tangantial vectors
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
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
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 =
209 bnod_pt->index_of_first_value_assigned_by_face_element(Id);
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
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
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 =
232 bnod_pt->index_of_first_value_assigned_by_face_element(Id);
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
240
241 if (local_eqn >= 0)
242 {
243 for (unsigned i = 0; i < dim_el + 1; i++)
244 {
245 // Assemble residual for lagrange multiplier
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 {
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
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
304 jj,
305 bnode_pt->index_of_first_value_assigned_by_face_element(
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
322 /// The number of degrees of freedom types that this element is
323 /// divided into: The ImposeParallelOutflowElement is responsible for 1(2)
324 /// of it's own degrees of freedom. In addition to this, it also classifies
325 /// the 2(3) constrained velocity bulk degrees of freedom which this face
326 /// element is attached to.
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
337 /// Create a list of pairs for all unknowns in this element,
338 /// so that the first entry in each pair contains the global equation
339 /// number of the unknown, while the second one contains the LOCAL number
340 /// of the "DOF types" that this unknown is associated with.
341 /// (Function can obviously only be called if the equation numbering
342 /// scheme has been set up.)
343 ///
344 /// For the ImposeParallelOutflowElement, we need to classify both the
345 /// constrained velocity from the bulk element and the dof types from this
346 /// element. In 3D, let up, vp, wp be the constrained velocity dof types
347 /// associated with the ImposeParallelOutflowElement. Let Lp1 and Lp2 be the
348 /// two Lagrange multiplier dof types associated with the
349 /// ImposeParallelOutflowElement. Then we have:
350 ///
351 /// 0 1 2 3 4
352 /// up vp wp L1 L2
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.
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.
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
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:
420 node_i,
421 bnod_pt->index_of_first_value_assigned_by_face_element(Id) + dim_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
cstr elem_len * i
Definition cfortran.h:603
A class that contains the information required by Nodes that are located on Mesh boundaries....
Definition nodes.h:1996
FaceElements are elements that coincide with the faces of higher-dimensional "bulk" elements....
Definition elements.h:4342
int & face_index()
Index of the face (a number that uniquely identifies the face in the element)
Definition elements.h:4630
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:5543
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
FiniteElement * Bulk_element_pt
Pointer to the associated higher-dimensional "bulk" element.
Definition elements.h:4403
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
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
FiniteElement *& bulk_element_pt()
Pointer to higher-dimensional "bulk" element.
Definition elements.h:4739
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:5359
FaceGeometry class definition: This policy class is used to allow construction of face elements that ...
Definition elements.h:5002
A general Finite Element class.
Definition elements.h:1317
Integral *const & integral_pt() const
Return the pointer to the integration scheme (const version)
Definition elements.h:1967
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(std::ostream &outfile)
Output the element data — typically the values at the nodes in a format suitable for post-processing.
Definition elements.h:3054
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
unsigned nnode() const
Return the number of nodes.
Definition elements.h:2214
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition elements.h:2179
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:5163
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
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:691
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
ImposeParallelOutflowElement are elements that coincide with the faces of higher-dimensional "bulk" e...
void get_dof_numbers_for_unknowns(std::list< std::pair< unsigned long, unsigned > > &dof_lookup_list) const
Create a list of pairs for all unknowns in this element, so that the first entry in each pair contain...
void fill_in_generic_contribution_to_residuals_parall_lagr_multiplier(Vector< double > &residuals, DenseMatrix< double > &jacobian, const unsigned &flag)
Helper function to compute the residuals and, if flag==1, the Jacobian.
unsigned ndof_types() const
The number of degrees of freedom types that this element is divided into: The ImposeParallelOutflowEl...
double *& pressure_pt()
Access function for the pressure.
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Fill in the residuals.
double * Pressure_pt
pointer to imposed pressure – if null then no pressure imposed.
void output(std::ostream &outfile, const unsigned &nplot)
Output function: x,y,[z],u,v,[w],p in tecplot format.
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Fill in contribution from Jacobian.
void output(std::ostream &outfile)
Overload the output function.
ImposeParallelOutflowElement(FiniteElement *const &element_pt, const int &face_index, const unsigned &id=0)
Constructor takes a "bulk" element, the index that identifies which face the ImposeParallelOutflowEle...
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 ...
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.
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition nodes.h:906
A Class for shape functions. In simple cases, the shape functions have only one index that can be tho...
Definition shape.h:76
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).