refineable_young_laplace_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-2023 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//====================================================================
27 
28 
29 namespace oomph
30 {
31  //======================================================================
32  /// Compute element residual vector taking hanging nodes into account
33  //======================================================================
35  Vector<double>& residuals)
36  {
37  // Find out how many nodes there are
38  unsigned n_node = nnode();
39 
40  // Set up memory for the shape (test) functions
41  Shape psi(n_node);
42  DShape dpsidzeta(n_node, 2);
43 
44  // Set the value of n_intpt
45  unsigned n_intpt = integral_pt()->nweight();
46 
47  // Integers to store the local equation numbers
48  int local_eqn = 0;
49 
50  // Loop over the integration points
51  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
52  {
53  // Get the integral weight
54  double w = integral_pt()->weight(ipt);
55 
56  // Call the derivatives of the shape (test) functions
57  double J = dshape_eulerian_at_knot(ipt, psi, dpsidzeta);
58 
59  // Premultiply the weights and the Jacobian
60  double W = w * J;
61 
62  // Calculate local values of the pressure and velocity components
63  // Allocate and initialise to zero
64  double interpolated_u = 0.0;
66  Vector<double> interpolated_du_dzeta(2, 0.0);
67 
68  // Calculate function value and derivatives:
69  //-----------------------------------------
70  // Loop over nodes
71  for (unsigned l = 0; l < n_node; l++)
72  {
73  interpolated_u += u(l) * psi(l);
74  // Loop over directions
75  for (unsigned j = 0; j < 2; j++)
76  {
77  interpolated_zeta[j] += nodal_position(l, j) * psi(l);
78  interpolated_du_dzeta[j] += u(l) * dpsidzeta(l, j);
79  }
80  }
81 
82  // Allocation and definition of variables necessary for
83  // further calculations
84 
85  /// "Simple" case
86  /// --------------
87  double nonlinearterm = 1.0;
88  double sqnorm = 0.0;
89 
90  /// Spine case
91  /// -----------
92 
93  // Derivs of position vector w.r.t. global intrinsic coords
94  Vector<Vector<double>> dRdzeta;
95  allocate_vector_of_vectors(2, 3, dRdzeta);
96 
97  // Unnormalised normal
98  Vector<double> N_unnormalised(3, 0.0);
99 
100  // Spine and spine basis vectors, entries initialised to zero
101  Vector<double> spine_base(3, 0.0), spine(3, 0.0);
102 
103  // Derivative of spine basis vector w.r.t to the intrinsic
104  // coordinates: dspine_base[i,j] = j-th component of the deriv.
105  // of the spine basis vector w.r.t. to the i-th global intrinsic
106  // coordinate
107  Vector<Vector<double>> dspine_base;
108  allocate_vector_of_vectors(2, 3, dspine_base);
109 
110  // Derivative of spine vector w.r.t to the intrinsic
111  // coordinates: dspine[i,j] = j-th component of the deriv.
112  // of the spine vector w.r.t. to the i-th global intrinsic
113  // coordinate
114  Vector<Vector<double>> dspine;
115  allocate_vector_of_vectors(2, 3, dspine);
116 
117  // Vector v_\alpha contains the numerator of the variations of the
118  // area element {\cal A}^{1/2} w.r.t. the components of dR/d\zeta_\alpha
119  Vector<double> area_variation_numerator_0(3, 0.0);
120  Vector<double> area_variation_numerator_1(3, 0.0);
121 
122  // Vector position
123  Vector<double> r(3, 0.0);
124 
125  // No spines
126  //---------
127  if (!use_spines())
128  {
129  for (unsigned j = 0; j < 2; j++)
130  sqnorm += interpolated_du_dzeta[j] * interpolated_du_dzeta[j];
131 
132  nonlinearterm = 1.0 / sqrt(1.0 + sqnorm);
133  }
134 
135  // Spines
136  //------
137  else
138  {
139  // Get the spines
140  get_spine_base(interpolated_zeta, spine_base, dspine_base);
141  get_spine(interpolated_zeta, spine, dspine);
142 
143  // calculation of dR/d\zeta_\alpha
144  for (unsigned alpha = 0; alpha < 2; alpha++)
145  {
146  // Product rule for d(u {\bf S} ) / d \zeta_\alpha
147  Vector<double> dudzeta_times_spine(3, 0.0);
149  interpolated_du_dzeta[alpha], spine, dudzeta_times_spine);
150 
151  Vector<double> u_times_dspinedzeta(3, 0.0);
153  interpolated_u, dspine[alpha], u_times_dspinedzeta);
154 
155  Vector<double> d_u_times_spine_dzeta(3, 0.0);
156  vector_sum(
157  dudzeta_times_spine, u_times_dspinedzeta, d_u_times_spine_dzeta);
158 
159  // Add derivative of spine base
160  vector_sum(d_u_times_spine_dzeta, dspine_base[alpha], dRdzeta[alpha]);
161  }
162 
163  /// Get the unnormalized normal
164  cross_product(dRdzeta[0], dRdzeta[1], N_unnormalised);
165 
166  /// Tmp storage
167  Vector<double> v_tmp_1(3, 0.0);
168  Vector<double> v_tmp_2(3, 0.0);
169 
170  // Calculation of
171  // |dR/d\zeta_1|^2 dR/d\zeta_0 - <dR/d\zeta_0,dR/d\zeta_1>dR/d\zeta_1
172  scalar_times_vector(pow(two_norm(dRdzeta[1]), 2), dRdzeta[0], v_tmp_1);
174  -1 * scalar_product(dRdzeta[0], dRdzeta[1]), dRdzeta[1], v_tmp_2);
175  vector_sum(v_tmp_1, v_tmp_2, area_variation_numerator_0);
176 
177  // Calculation of
178  // |dR/d\zeta_0|^2 dR/d\zeta_1 - <dR/d\zeta_0,dR/d\zeta_1>dR/d\zeta_0
179  scalar_times_vector(pow(two_norm(dRdzeta[0]), 2), dRdzeta[1], v_tmp_1);
181  -1 * scalar_product(dRdzeta[0], dRdzeta[1]), dRdzeta[0], v_tmp_2);
182  vector_sum(v_tmp_1, v_tmp_2, area_variation_numerator_1);
183 
184  // Global Eulerian cooordinates
185  for (unsigned j = 0; j < 3; j++)
186  {
187  r[j] = spine_base[j] + interpolated_u * spine[j];
188  }
189  }
190 
191 
192  // Assemble residuals
193  //-------------------
194 
195  // Loop over the nodes for the test functions
196  for (unsigned l = 0; l < n_node; l++)
197  {
198  // Local variables used to store the number of master nodes and the
199  // weight associated with the shape function if the node is hanging
200  unsigned n_master = 1;
201  double hang_weight = 1.0;
202 
203  // If the node is hanging, get the number of master nodes
204  if (node_pt(l)->is_hanging())
205  {
206  n_master = node_pt(l)->hanging_pt()->nmaster();
207  }
208  // Otherwise there is just one master node, the node itself
209  else
210  {
211  n_master = 1;
212  }
213 
214  // Loop over the master nodes
215  for (unsigned m = 0; m < n_master; m++)
216  {
217  // Get the local equation number and hang_weight
218  // If the node is hanging
219  if (node_pt(l)->is_hanging())
220  {
221  // Read out the local equation from the master node
222  local_eqn =
223  local_hang_eqn(node_pt(l)->hanging_pt()->master_node_pt(m), 0);
224  // Read out the weight from the master node
225  hang_weight = node_pt(l)->hanging_pt()->master_weight(m);
226  }
227  // If the node is not hanging
228  else
229  {
230  // The local equation number comes from the node itself
231  local_eqn = this->u_local_eqn(l);
232  // The hang weight is one
233  hang_weight = 1.0;
234  }
235 
236  /*IF it's not a boundary condition*/
237  if (local_eqn >= 0)
238  {
239  // "simple" calculation case
240  if (!use_spines())
241  {
242  // Add source term: The curvature
243  residuals[local_eqn] += get_kappa() * psi(l) * W * hang_weight;
244 
245  // The YoungLaplace bit itself
246  for (unsigned k = 0; k < 2; k++)
247  {
248  residuals[local_eqn] += nonlinearterm *
249  interpolated_du_dzeta[k] *
250  dpsidzeta(l, k) * W * hang_weight;
251  }
252  }
253 
254  // Spine calculation case
255  else
256  {
257  // Calculation of d(u S)/d\zeta_0
258  //-------------------------------
259  Vector<double> v_tmp_1(3, 0.0);
260  scalar_times_vector(dpsidzeta(l, 0), spine, v_tmp_1);
261 
262  Vector<double> v_tmp_2(3, 0.0);
263  scalar_times_vector(psi(l), dspine[0], v_tmp_2);
264 
265  Vector<double> d_uS_dzeta0(3, 0.0);
266  vector_sum(v_tmp_1, v_tmp_2, d_uS_dzeta0);
267 
268  // Add contribution to residual
269  residuals[local_eqn] +=
270  W * hang_weight *
271  scalar_product(area_variation_numerator_0, d_uS_dzeta0) /
272  two_norm(N_unnormalised);
273 
274  // Calculation of d(u S)/d\zeta_1
275  scalar_times_vector(dpsidzeta(l, 1), spine, v_tmp_1);
276  scalar_times_vector(psi(l), dspine[1], v_tmp_2);
277  Vector<double> d_uS_dzeta1(3, 0.0);
278  vector_sum(v_tmp_1, v_tmp_2, d_uS_dzeta1);
279 
280  // Add contribution to residual
281  residuals[local_eqn] +=
282  W * hang_weight *
283  scalar_product(area_variation_numerator_1, d_uS_dzeta1) /
284  two_norm(N_unnormalised);
285 
286  // Curvature contribution to the residual : kappa N S test
287  residuals[local_eqn] += W * hang_weight * (get_kappa()) *
288  scalar_product(N_unnormalised, spine) *
289  psi(l);
290  }
291  }
292 
293  } // End of loop over master nodes for residual
294 
295  } // End of loop over nodes
296 
297  } // End of loop over integration points
298  }
299 
300  //====================================================================
301  // Force build of templates
302  //====================================================================
303  template class RefineableQYoungLaplaceElement<2>;
304  template class RefineableQYoungLaplaceElement<3>;
305  template class RefineableQYoungLaplaceElement<4>;
306 
307 } // namespace oomph
A Class for the derivatives of shape functions The class design is essentially the same as Shape,...
Definition: shape.h:278
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2175
virtual double dshape_eulerian_at_knot(const unsigned &ipt, Shape &psi, DShape &dpsidx) const
Return the geometric shape functions and also first derivatives w.r.t. global coordinates at the ipt-...
Definition: elements.cc:3325
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:4675
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
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:2317
double const & master_weight(const unsigned &i) const
Return weight for dofs on i-th master node.
Definition: nodes.h:808
unsigned nmaster() const
Return the number of master nodes.
Definition: nodes.h:785
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.
HangInfo *const & hanging_pt() const
Return pointer to hanging node data (this refers to the geometric hanging node status) (const version...
Definition: nodes.h:1228
int local_hang_eqn(Node *const &node_pt, const unsigned &i)
Access function that returns the local equation number for the hanging node variables (values stored ...
Refineable version of 2D QYoungLaplaceElement elements.
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Compute element residual vector taking hanging nodes into account.
A Class for shape functions. In simple cases, the shape functions have only one index that can be tho...
Definition: shape.h:76
static double two_norm(const Vector< double > &v)
2-norm of a vector
static void scalar_times_vector(const double &lambda, const Vector< double > &v, Vector< double > &lambda_times_v)
Multiply a vector by a scalar.
static double scalar_product(const Vector< double > &v1, const Vector< double > &v2)
Scalar product between two vectors.
double interpolated_u(const Vector< double > &s) const
Return FE representation of function value u(s) at local coordinate s.
static void allocate_vector_of_vectors(unsigned n_rows, unsigned n_cols, Vector< Vector< double >> &v)
Helper fct: Allocate storage for a vector of vectors of doubles to v(n_rows,n_cols) and initialise ea...
virtual int u_local_eqn(const unsigned &n)
Get the local equation number of the (one and only) unknown stored at local node n (returns -1 if val...
virtual void get_spine_base(const Vector< double > &x, Vector< double > &spine_base, Vector< Vector< double >> &dspine_base) const
Get spine base vector field: Defaults to standard cartesian representation if no spine base fct point...
virtual double u(const unsigned &n) const
Access function: Nodal function value at local node n Uses suitably interpolated value for hanging no...
double get_kappa() const
Get curvature.
void get_spine(const Vector< double > &x, Vector< double > &spine, Vector< Vector< double >> &dspine) const
Get spine vector field: Defaults to standard cartesian representation if no spine base fct pointers h...
bool use_spines() const
Use spines or not? (Based on availability of function pointers to to spine and spine base vector fiel...
static void cross_product(const Vector< double > &v1, const Vector< double > &v2, Vector< double > &v_cross)
Cross-product: v_cross= v1 x v2.
static void vector_sum(const Vector< double > &v1, const Vector< double > &v2, Vector< double > &vs)
Vectorial sum of two vectors.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...