impose_impenetrability_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_IMPENETRABLE_ELEMENTS_HEADER
27#define OOMPH_IMPOSE_IMPENETRABLE_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 /// ImposeImpenetrabilityElement
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 impenetrability.
41 //========================================================================
42 template<class ELEMENT>
43 class ImposeImpenetrabilityElement : public virtual FaceGeometry<ELEMENT>,
44 public virtual FaceElement
45 {
46 private:
47 /// Lagrange Id
48 unsigned Id;
49
50 public:
51 /// Constructor takes a "bulk" element, the
52 /// index that identifies which face the
53 /// ImposeImpenetrabilityElement is supposed
54 /// to be attached to, and the face element ID
56 const int& face_index,
57 const unsigned& id = 0)
58 : FaceGeometry<ELEMENT>(), FaceElement()
59 {
60 // set the Id
61 Id = id;
62
63 // Build the face element
64 element_pt->build_face_element(face_index, this);
65
66 // we need 1 additional values for each FaceElement node
68
69 // add storage for lagrange multipliers and set the map containing
70 // the position of the first entry of this face element's
71 // additional values.
73 }
74
75
76 /// Fill in the residuals
83
84 /// Fill in contribution from Jacobian
86 DenseMatrix<double>& jacobian)
87 {
88 // Call the generic routine with the flag set to 1
90 residuals, jacobian, 1);
91 }
92
93 /// Overload the output function
94 void output(std::ostream& outfile)
95 {
97 }
98
99 /// Output function: x,y,[z],u,v,[w],p in tecplot format
100 void output(std::ostream& outfile, const unsigned& nplot)
101 {
103 }
104
105 /// The "global" intrinsic coordinate of the element when
106 /// viewed as part of a geometric object should be given by
107 /// the FaceElement representation, by default
108 /// This final over-ride is required because both SolidFiniteElements
109 /// and FaceElements overload zeta_nodal
110 double zeta_nodal(const unsigned& n,
111 const unsigned& k,
112 const unsigned& i) const
113 {
114 return FaceElement::zeta_nodal(n, k, i);
115 }
116
117 protected:
118 /// Helper function to compute the residuals and, if flag==1, the
119 /// Jacobian
122 DenseMatrix<double>& jacobian,
123 const unsigned& flag)
124 {
125 // Find out how many nodes there are
126 unsigned n_node = nnode();
127
128 // Dimension of element
129 unsigned dim_el = dim();
130
131 // Set up memory for the shape functions
133
134 // Set the value of n_intpt
135 unsigned n_intpt = integral_pt()->nweight();
136
137 // to store local equation number
138 int local_eqn = 0;
139 int local_unknown = 0;
140
141 // to store normal vector
143
144 // get the value at which the velocities are stored
145 Vector<unsigned> u_index(dim_el + 1);
146 ELEMENT* el_pt = dynamic_cast<ELEMENT*>(this->bulk_element_pt());
147 for (unsigned i = 0; i < dim_el + 1; i++)
148 {
149 u_index[i] = el_pt->u_index_nst(i);
150 }
151
152 // Loop over the integration points
153 for (unsigned ipt = 0; ipt < n_intpt; ipt++)
154 {
155 // Get the integral weight
156 double w = integral_pt()->weight(ipt);
157
158 // Jacobian of mapping
159 double J = J_eulerian_at_knot(ipt);
160
161 // Premultiply the weights and the Jacobian
162 double W = w * J;
163
164 // Calculate the shape functions
166
167 // compute the velocity and the Lagrange multiplier
168 Vector<double> interpolated_u(dim_el + 1, 0.0);
169 double lambda = 0.0;
170
171 // Loop over nodes
172 for (unsigned j = 0; j < n_node; j++)
173 {
174 // Assemble the velocity component
175 for (unsigned i = 0; i < dim_el + 1; i++)
176 {
177 interpolated_u[i] += nodal_value(j, u_index[i]) * psi(j);
178 }
179
180 // Cast to a boundary node
182 dynamic_cast<BoundaryNodeBase*>(node_pt(j));
183
184 // get the node
185 Node* nod_pt = node_pt(j);
186
187 // Get the index of the first nodal value associated with
188 // this FaceElement
189 unsigned first_index =
190 bnod_pt->index_of_first_value_assigned_by_face_element(Id);
191
192 // Assemble the Lagrange multiplier
193 lambda += nod_pt->value(first_index) * psi(j);
194 }
195
196 // compute the normal vector
198
199 // Assemble residuals and jacobian
200
201 // Loop over the nodes
202 for (unsigned j = 0; j < n_node; j++)
203 {
204 // Cast to a boundary node
206 dynamic_cast<BoundaryNodeBase*>(node_pt(j));
207
208 // Get the index of the first nodal value associated with
209 // this FaceElement
210 unsigned first_index =
211 bnod_pt->index_of_first_value_assigned_by_face_element(Id);
212
213 // Local eqn number for the l-th component of lamdba
214 // in the j-th element
216
217 if (local_eqn >= 0)
218 {
219 for (unsigned i = 0; i < dim_el + 1; i++)
220 {
221 // Assemble residual for lagrange multiplier
223 interpolated_u[i] * norm_vec[i] * psi(j) * W;
224
225 // Assemble Jacobian for Lagrange multiplier:
226 if (flag == 1)
227 {
228 // Loop over the nodes again for unknowns
229 for (unsigned jj = 0; jj < n_node; jj++)
230 {
231 // Local eqn number for the i-th component
232 // of the velocity in the jj-th element
233 local_unknown = nodal_local_eqn(jj, u_index[i]);
234 if (local_unknown >= 0)
235 {
236 jacobian(local_eqn, local_unknown) +=
237 norm_vec[i] * psi(jj) * psi(j) * W;
238 }
239 }
240 }
241 }
242 }
243
244 // Loop over the directions
245 for (unsigned i = 0; i < dim_el + 1; i++)
246 {
247 // Local eqn number for the i-th component of the
248 // velocity in the j-th element
249 local_eqn = nodal_local_eqn(j, u_index[i]);
250
251 if (local_eqn >= 0)
252 {
253 // Add lagrange multiplier contribution to the bulk equation
254 // Add to residual
255 residuals[local_eqn] += norm_vec[i] * psi(j) * lambda * W;
256
257 // Do Jacobian too?
258 if (flag == 1)
259 {
260 // Loop over the nodes again for unknowns
261 for (unsigned jj = 0; jj < n_node; jj++)
262 {
263 // Cast to a boundary node
265 dynamic_cast<BoundaryNodeBase*>(node_pt(jj));
266
267 // Local eqn number for the l-th component of lamdba
268 // in the jj-th element
270 jj,
271 bnode_pt->index_of_first_value_assigned_by_face_element(
272 Id));
273 if (local_unknown >= 0)
274 {
275 jacobian(local_eqn, local_unknown) +=
276 norm_vec[i] * psi(jj) * psi(j) * W;
277 }
278 }
279 }
280 }
281 }
282 }
283 }
284 }
285
286
287 /// The number of "DOF types" that degrees of freedom in this element
288 /// are sub-divided into: Just the solid degrees of freedom themselves.
289 unsigned ndof_types() const
290 {
291 // There is only ever one normal. Plus the constrained velocities.
292 // unsigned ndofndof = 1 + additional_ndof_types();
293 // std::cout << "ndof: " << ndofndof << std::endl;
294
295 return (1 + additional_ndof_types());
296 }
297
298
299 unsigned additional_ndof_types() const
300 {
301 // Additional dof types for the constained bulk velocities
302 // two velocities for a 2D problem, 3 for 3D.
303 return (this->dim() + 1);
304 }
305
306 /// Create a list of pairs for all unknowns in this element,
307 /// so that the first entry in each pair contains the global equation
308 /// number of the unknown, while the second one contains the number
309 /// of the "DOF type" that this unknown is associated with.
310 /// (Function can obviously only be called if the equation numbering
311 /// scheme has been set up.)
313 std::list<std::pair<unsigned long, unsigned>>& dof_lookup_list) const
314 {
315 // temporary pair (used to store dof lookup prior to
316 // being added to list)
317 std::pair<unsigned, unsigned> dof_lookup;
318
319 // number of nodes
320 const unsigned n_node = this->nnode();
321
322 // Loop over directions in this Face(!)Element
323 unsigned dim_el = this->dim();
324 // for(unsigned i=0;i<dim_el;i++)
325 {
326 unsigned i = 0;
327 // Loop over the nodes
328 for (unsigned j = 0; j < n_node; j++)
329 {
330 // Cast to a boundary node
332 dynamic_cast<BoundaryNodeBase*>(node_pt(j));
333
334 // Local eqn number:
336 j, bnod_pt->index_of_first_value_assigned_by_face_element(Id) + i);
337 if (local_eqn >= 0)
338 {
339 // store dof lookup in temporary pair: First entry in pair
340 // is global equation number; second entry is dof type
341 dof_lookup.first = this->eqn_number(local_eqn);
343
344 // add to list
345 dof_lookup_list.push_front(dof_lookup);
346 }
347 }
348 }
349
350 //*
351 // Now we do the bulk elements. Each velocity component of a constrained
352 // dof of a different type of FaceElement has a different dof_type. E.g.
353 // Consider the Navier Stokes equations in three spatial dimensions with
354 // parallel outflow (using ImposeParallelOutflowElement with Boundary_id =
355 // 1) and tangential flow (using ImposeTangentialFlowElement with
356 // Boundary_id = 2) imposed along two different boundaries. There will be
357 // 10 dof types: 0 1 2 3 4 5 6 7 8 9 u v w p u1 v1 w1 u2 v2 w2
358
359 // Loop over only the nodes of the "bulk" element that are associated
360 // with this "face" element.
361 // cout << "n_node: " << n_node << endl;
362 unsigned const bulk_dim = dim_el + 1;
363 // cout << "bulk_dim: " << bulk_dim << endl;
364 for (unsigned node_i = 0; node_i < n_node; node_i++)
365 {
366 // Loop over the velocity components
367 for (unsigned velocity_i = 0; velocity_i < bulk_dim; velocity_i++)
368 {
369 // Calculating the offset for this Boundary_id.
370 // 0 1 2 3 4 5 6 7 8 9
371 // u v w p u1 v1 w1 u2 v2 w2
372 //
373 // for the first surface mesh, offset = 4
374 // for the second surface mesh, offset = 7
375 // unsigned offset = bulk_dim * Boundary_id + 1;
376
377 // The local equation number is required to check if the value is
378 // pinned, if it is not pinned, the local equation number is required
379 // to get the global equation number.
382
383 // ignore pinned values
384 if (local_eqn >= 0)
385 {
386 // store the dof lookup in temporary pair: First entry in pair
387 // is the global equation number; second entry is the dof type
389 dof_lookup.second = velocity_i;
390 dof_lookup_list.push_front(dof_lookup);
391
392 // RRRcout << "Face v: " << dof_lookup.first
393 // RRR << ", doftype: " << dof_lookup.second << endl;
394
395 } // ignore pinned nodes "if(local-eqn>=0)"
396 } // for loop over the velocity components
397 } // for loop over bulk nodes only
398
399 } // get unknowns...
400 };
401} // namespace oomph
402#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
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
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:6037
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
ImposeImpenetrabilityElement are elements that coincide with the faces of higher-dimensional "bulk" e...
unsigned ndof_types() const
The number of "DOF types" that degrees of freedom in this element are sub-divided into: Just the soli...
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Fill in the residuals.
void output(std::ostream &outfile)
Overload the output function.
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.
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Fill in contribution from Jacobian.
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 ...
void output(std::ostream &outfile, const unsigned &nplot)
Output function: x,y,[z],u,v,[w],p in tecplot format.
ImposeImpenetrabilityElement(FiniteElement *const &element_pt, const int &face_index, const unsigned &id=0)
Constructor takes a "bulk" element, the index that identifies which face the ImposeImpenetrabilityEle...
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).