young_laplace_contact_angle_elements.cc
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//====================================================================
29
30
31namespace oomph
32{
33 //===========================================================================
34 /// Constructor, takes the pointer to the "bulk" element and the
35 /// index of the face to which the element is attached.
36 //===========================================================================
37 template<class ELEMENT>
39 FiniteElement* const& bulk_el_pt, const int& face_index)
40 : FaceGeometry<ELEMENT>(), FaceElement()
41 {
42 // Let the bulk element build the FaceElement, i.e. setup the pointers
43 // to its nodes (by referring to the appropriate nodes in the bulk
44 // element), etc.
46
47 // Initialise the prescribed contact angle pointer to zero
49
50#ifdef PARANOID
51 // Extract the dimension of the problem from the dimension of
52 // the first node
53 unsigned dim = node_pt(0)->ndim();
54 if (dim != 2)
55 {
56 throw OomphLibError(
57 "YoungLaplaceContactAngleElement only work with 2D nodes",
60 }
61#endif
62 }
63
64
65 //================================================================
66 /// Compute the element's contribution to the residual vector
67 //================================================================
68 template<class ELEMENT>
70 ELEMENT>::fill_in_contribution_to_residuals(Vector<double>& residuals)
71 {
72 // Find out how many nodes there are
73 unsigned n_node = nnode();
74
75 // Set up memory for the shape functions
77
78 // Number of integration points
79 unsigned n_intpt = integral_pt()->nweight();
80
81 // Set the Vector to hold local coordinates
82 // Note: We need the coordinate itself below for the evaluation
83 // of the contact line vectors even though we use the *at_knot
84 // version for the various shape-function-related functions
86
87 // Integers to hold the local equation and unknown numbers
88 int local_eqn = 0;
89
90 // Loop over the integration points
91 for (unsigned ipt = 0; ipt < n_intpt; ipt++)
92 {
93 // Assign value of s
94 s[0] = integral_pt()->knot(ipt, 0);
95
96 // Get the integral weight
97 double w = integral_pt()->weight(ipt);
98
99 // Find the shape functions
100 shape_at_knot(ipt, psi);
101
102 // Get the prescribed cos_gamma
103 double cos_gamma = prescribed_cos_gamma();
104
105 // Get the various contact line vectors
109 double norm_of_drds;
110 contact_line_vectors(s, tangent, normal, spine, norm_of_drds);
111
112 // Get beta factor:
113
114 // Cross product of spine and tangent to contact line is
115 // the wall normal
117 ELEMENT::cross_product(spine, tangent, wall_normal);
118
119 // Normalise
120 double norm = ELEMENT::two_norm(wall_normal);
121 for (unsigned i = 0; i < 3; i++) wall_normal[i] /= norm;
122
123 // Take cross product with tangent to get the normal to the
124 // contact line parallel to wall
126 ELEMENT::cross_product(
128
129 double beta =
130 ELEMENT::scalar_product(spine, normal_to_contact_line_parallel_to_wall);
131
132
133 // Now add to the appropriate equations
134
135 // Loop over the test functions
136 for (unsigned l = 0; l < n_node; l++)
137 {
138 local_eqn = u_local_eqn(l);
139 /*IF it's not a boundary condition*/
140 if (local_eqn >= 0)
141 {
142 // Add to residual:
143 residuals[local_eqn] -= beta * cos_gamma * psi[l] * norm_of_drds * w;
144 }
145 }
146 }
147 }
148
149
150 //========================================================================
151 /// Get the actual contact angle
152 //========================================================================
153 template<class ELEMENT>
155 const Vector<double>& s)
156 {
157 // Get pointer to bulk element
158 ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(this->bulk_element_pt());
159
160 double cos_gamma = 0.0;
161
162 // Spine case
163 if (bulk_elem_pt->use_spines())
164 {
165 // Get various contact line vectors
169 double norm_of_drds;
170 contact_line_vectors(s, tangent, normal, spine, norm_of_drds);
171
172 // Get the wall normal: Both the tangent to the contact line
173 // and the spine vector are tangential to the wall:
175 Vector<double> axe_ez(3, 0.0);
176 axe_ez[2] = 1.0;
177 ELEMENT::cross_product(axe_ez, tangent, wall_normal);
178
179 // Normalise
180 double norm = 0.0;
181 for (unsigned i = 0; i < 3; i++) norm += wall_normal[i] * wall_normal[i];
182 for (unsigned i = 0; i < 3; i++)
183 {
184 wall_normal[i] /= sqrt(norm);
185 }
186
187 // Get the auxiliary unit vector that's normal to
188 // the contact line and tangent to the wall
190 ELEMENT::cross_product(tangent, wall_normal, aux);
191
192 // Cos of contact angle is dot product with wall normal
193 cos_gamma = ELEMENT::scalar_product(aux, normal);
194 }
195
196 // Cartesian case
197 else
198 {
199 // Get local coordinates in bulk element by copy construction
200 Vector<double> s_bulk(local_coordinate_in_bulk(s));
201
202 // Number of nodes in bulk element
203 unsigned nnode_bulk = bulk_elem_pt->nnode();
204
205
206#ifdef PARANOID
207 // Dimension of (= number of local coordinates in) bulk element
208 unsigned dim_bulk = bulk_elem_pt->dim();
209
210 if (dim_bulk != 2)
211 {
212 throw OomphLibError(
213 "YoungLaplaceContactAngleElements only work with 2D bulk elements",
216 }
217#endif
218
219 // Set up memory for the shape functions
222
223 // Call the derivatives of the shape and test functions
224 // in the bulk -- must do this via s because this point
225 // is not an integration point the bulk element!
227
228 // Get the gradient at s
230
231 // Calculate function value and derivatives:
232 //-----------------------------------------
233 // Loop over nodes
234 for (unsigned l = 0; l < nnode_bulk; l++)
235 {
236 // Loop over directions
237 for (unsigned j = 0; j < 2; j++)
238 {
239 gradient_u[j] += bulk_elem_pt->u(l) * dpsidzeta(l, j);
240 }
241 }
242
243 // Get the outer unit normal to boundary
245 outer_unit_normal(s, outer_normal);
246
247 // Compute the cosinus of the angle
248 double gradient_norm_2 =
249 ELEMENT::two_norm(gradient_u) * ELEMENT::two_norm(gradient_u);
250 cos_gamma = ELEMENT::scalar_product(gradient_u, outer_normal) /
252 }
253
254 return cos_gamma;
255 }
256
257
258 //========================================================================
259 /// Get unit tangent and normal to contact line and the spine itself (this
260 /// allows the wall normal to be worked out by a cross product). Final
261 /// argument gives the norm of dR/ds where R is the vector to the
262 /// contact line and s the local coordinate in the element.
263 //========================================================================
264 template<class ELEMENT>
266 const Vector<double>& s,
270 double& norm_of_drds)
271 {
272 // Get pointer to bulk element
273 ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(this->bulk_element_pt());
274
275 // Dimension of (= number of local coordinates in) bulk element
276 unsigned dim_bulk = bulk_elem_pt->dim();
277
278#ifdef PARANOID
279 if (dim_bulk != 2)
280 {
281 throw OomphLibError(
282 "YoungLaplaceContactAngleElements only work with 2D bulk elements",
285 }
286#endif
287
288 // Which local coordinate is const in bulk element?
289 unsigned s_fixed_index_in_bulk;
290
292 this->get_ds_bulk_ds_face(s, ds_bulk_ds_face, s_fixed_index_in_bulk);
293
294 // Get local coordinates in bulk element by copy construction
295 Vector<double> s_bulk(local_coordinate_in_bulk(s));
296
297 // Number of nodes in bulk element
298 unsigned nnode_bulk = bulk_elem_pt->nnode();
299
300 // Get the shape functions and their derivatives w.r.t.
301 // to the local coordinates in the bulk element
305
306 // Displacement along spine
307 double interpolated_u = 0.0;
308
309 // Derivative of u w.r.t. tangential and pseudo-normal bulk coordinate
310 double interpolated_du_ds_tangent = 0.0;
312
313 // Global intrinsic coordinates of current point for evaluation of
314 // spine and spine base
316
317
318 // Derivatives of zeta (in bulk) w.r.t. to tangent and pseudo-normal
319 // local coordinate
322
323 // Loop over nodes
324 for (unsigned l = 0; l < nnode_bulk; l++)
325 {
326 interpolated_u += bulk_elem_pt->u(l) * psi_bulk(l);
327
328 // Chain rule for tangent derivative
329 double aux = 0.0;
330 for (unsigned i = 0; i < dim_bulk; i++)
331 {
332 aux += dpsi_bulk(l, i) * ds_bulk_ds_face(i, 0);
333 }
335
336 // Straight derivative w.r.t. one of the bulk coordinates
337 // that's fixed along the face
340
341 // Loop over directions
342 for (unsigned j = 0; j < dim_bulk; j++)
343 {
346
347 // Chain rule for tangent derivative
348 double aux = 0.0;
349 for (unsigned i = 0; i < dim_bulk; i++)
350 {
351 aux += dpsi_bulk(l, i) * ds_bulk_ds_face(i, 0);
352 }
355
356 // Straight derivative w.r.t. one of the bulk coordinates
357 // that's fixed along the face
361 }
362 }
363
364 // Auxiliary vector (tangent to non-fixed bulk coordinate but
365 // not necessarily normal to contact line)
367 double tang_norm = 0.0;
368 double aux_norm = 0.0;
369
370 if (bulk_elem_pt->use_spines())
371 {
372 // Get the spine and spine base vector at this point from the bulk element
375 ELEMENT::allocate_vector_of_vectors(2, 3, dspine);
377 ELEMENT::allocate_vector_of_vectors(2, 3, dspine_base);
380
381 // Derivative of spine and spine base w.r.t. local coordinate in
382 // FaceElement:
387 for (unsigned i = 0; i < 3; i++)
388 {
392
396
400
404 }
405
406 // Auxiliary vector (tangent to non-fixed bulk coordinate but
407 // not necessarily normal to contact line)
408 for (unsigned i = 0; i < 3; i++)
409 {
412 interpolated_u * dspine_ds_tangent[i];
413 tang_norm += tangent[i] * tangent[i];
414
415
418 interpolated_u * dspine_ds_pseudo_normal[i];
420 }
421 }
422
423 // Cartesian case
424 else
425 {
426 for (unsigned i = 0; i < 2; i++)
427 {
429 tang_norm += tangent[i] * tangent[i];
432 }
433
435 tang_norm += tangent[2] * tangent[2];
437 aux_norm += aux_vector[2] * aux_vector[2];
438 }
439
440 // Norm of the rate of change
442
443 // Normalise
444 double tang_norm_fact = 1.0 / sqrt(tang_norm);
445 double aux_norm_fact = 1.0 / sqrt(aux_norm);
446 for (unsigned i = 0; i < 3; i++)
447 {
450 }
451
452
453 // Normal to meniscus is the cross product between the
454 // two contact line vectors:
456 ELEMENT::cross_product(tangent, aux_vector, meniscus_normal);
457
458 // Calculate the norm
459 double men_norm_fact = 0.0;
460 for (unsigned i = 0; i < 3; i++)
461 {
463 }
464
465 // Normalise and adjust direction
466 double sign = -double(normal_sign());
467 for (unsigned i = 0; i < 3; i++)
468 {
470 }
471
472 // The actual (bi) normal to the contact line is given
473 // by another cross product
474 ELEMENT::cross_product(meniscus_normal, tangent, normal);
475 }
476
477
478 //============================================================
479 // Build the required elements
480 //============================================================
484
485 template class YoungLaplaceContactAngleElement<
487 template class YoungLaplaceContactAngleElement<
489 template class YoungLaplaceContactAngleElement<
491
492} // namespace oomph
static char t char * s
Definition cfortran.h:568
cstr elem_len * i
Definition cfortran.h:603
A Class for the derivatives of shape functions The class design is essentially the same as Shape,...
Definition shape.h:278
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
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
void interpolated_zeta(const Vector< double > &s, Vector< double > &zeta) const
Calculate the interpolated value of zeta, the intrinsic coordinate of the element when viewed as a co...
Definition elements.cc:4705
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
double nodal_position(const unsigned &n, const unsigned &i) const
Return the i-th coordinate at local node n. If the node is hanging, the appropriate interpolation is ...
Definition elements.h:2321
double dshape_eulerian(const Vector< double > &s, Shape &psi, DShape &dpsidx) const
Compute the geometric shape functions and also first derivatives w.r.t. global coordinates at local c...
Definition elements.cc:3328
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition elements.h:2179
virtual void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Function to compute the geometric shape functions and derivatives w.r.t. local coordinates at local c...
Definition elements.h:1985
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
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition nodes.h:1054
An OomphLibError object which should be thrown when an run-time error is encountered....
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...
TAdvectionDiffusionReactionElement()
Constructor: Call constructors for TElement and AdvectionDiffusionReaction equations.
A class for elements that allow the imposition of an contact angle bcs for Young Laplace elements....
double actual_cos_contact_angle(const Vector< double > &s)
Compute cosinus of actual contact angle.
void contact_line_vectors(const Vector< double > &s, Vector< double > &tangent, Vector< double > &normal)
Get unit tangent and normal vectors to contact line.
double * Prescribed_cos_gamma_pt
Pointer to prescribed cos gamma.
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).