biharmonic_flux_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//====================================================================
26 // Config header generated by autoconfig
27 #ifdef HAVE_CONFIG_H
28 #include <oomph-lib-config.h>
29 #endif
30 
31 // oomph-lib includes
33 
34 
35 namespace oomph
36 {
37  //=============================================================================
38  /// Constructor, takes the pointer to the "bulk" element, the
39  /// index of the fixed local coordinate and its value represented
40  /// by an integer (+/- 1), indicating that the face is located
41  /// at the max. or min. value of the "fixed" local coordinate
42  /// in the bulk element. And the macro element position of the flux element
43  /// along the edge of the problem
44  //=============================================================================
45  template<>
47  FiniteElement* const& bulk_el_pt, const int& face_index, const unsigned& b)
49  {
50  // Let the bulk element build the FaceElement, i.e. setup the pointers
51  // to its nodes (by referring to the appropriate nodes in the bulk
52  // element), etc.
53  bulk_el_pt->build_face_element(face_index, this);
54 
55  // Initialise the prescribed-flux function pointer to zero
56  Flux0_fct_pt = 0;
57  Flux1_fct_pt = 0;
58 
59  // set the number of nodal degrees of freedom for the face element
60  Nface_nodal_dof = 2;
61 
62  //
63  Boundary = b;
64  }
65 
66 
67  //=============================================================================
68  /// Calculate the Jacobian of the mapping between local and global
69  /// coordinates at the position s for face elements for two dimensional
70  /// problems
71  /// The jacobian of the 1D face element is computed which is dt/ds_t
72  //=============================================================================
73  template<>
75  {
76  // Find the number of nodes
77  unsigned n_node = this->nnode();
78 
79  // Set up dummy memory for the shape functions
80  Shape psi(n_node, Nface_nodal_dof);
81  DShape dpsids(n_node, Nface_nodal_dof, 1);
82 
83  // Get the shape functions and local derivatives
84  this->dshape_local(s, psi, dpsids);
85 
86  // computed dx_i/ds_t along edge element
87  Vector<double> interpolated_dxds_t(2);
88 
89  // Get the bulk position type corresponding to the slope
90  const unsigned slope_index = this->bulk_position_type(1);
91  for (unsigned l = 0; l < n_node; l++)
92  {
93  for (unsigned d = 0; d < 2; d++)
94  {
95  interpolated_dxds_t[d] +=
96  this->node_pt(l)->x_gen(0, d) * dpsids(l, 0, 0) +
97  this->node_pt(l)->x_gen(slope_index, d) * dpsids(l, 1, 0);
98  }
99  }
100 
101  // dt/ds_t = dx_0/ds_t*t_0 + dx_1/ds_t*t_1
102  //
103  // given : t_0 = dx_0/ds_t / ( (dx_0/ds_t)^2 + (dx_1/ds_t)^2 )^0.5
104  // t_1 = dx_1/ds_t / ( (dx_0/ds_t)^2 + (dx_1/ds_t)^2 )^0.5
105  //
106  // then : dt/ds_t = ( (dx_0/ds_t)^2 + (dx_1/ds_t)^2 )^0.5
107  //
108  // (note : it is gaurantee that dt/ds_t is +ve, therefore do not need
109  // PARANOID
110  // check of jacobian)
111  double dtds_t = sqrt(interpolated_dxds_t[0] * interpolated_dxds_t[0] +
112  interpolated_dxds_t[1] * interpolated_dxds_t[1]);
113 
114  // Return the Jacobian
115  return dtds_t;
116  }
117 
118 
119  //=============================================================================
120  /// Compute the elemental contribution to the residual vector for 2D
121  /// problem type 0 biharmonic flux elements
122  //=============================================================================
123  template<>
125  2>::fill_in_generic_residual_contribution_biharmonic_flux(Vector<double>&
126  residual)
127  {
128  // Find out how many nodes there are in the face element
129  unsigned n_node = this->nnode();
130 
131  // set up memory for shape functions
132  Shape psi(n_node, Nface_nodal_dof);
133 
134  // setup memory for derivative of shape functions
135  DShape dpsi(n_node, Nface_nodal_dof, 1);
136 
137  // Set the value of Nintpt
138  unsigned n_intpt = this->integral_pt()->nweight();
139 
140  // local coordinate position of integration point in face element
141  Vector<double> s(1);
142 
143  // edge sign adjust
144  int edge_sign = //-int(this->s_fixed_value())*int((s_fixed_index-0.5)*2);
145  -this->normal_sign();
146 
147  // Flip for the different normal conventions (TIDY THIS UP)
148  if ((this->face_index() == 2) || (this->face_index() == -2))
149  {
150  edge_sign *= -1;
151  }
152 
153  // Get the bulk position type corresponding to the slope
154  const unsigned slope_index = this->bulk_position_type(1);
155 
156  // Ge the position type corresponding to the outer slope
157  const unsigned outer_slope_index = 3 - slope_index;
158 
159  // Loop over the integration points
160  //--------------------------------
161  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
162  {
163  // Get the integral weight
164  double w = this->integral_pt()->weight(ipt);
165 
166  // value of local coordinate s at integration point
167  s[0] = this->integral_pt()->knot(ipt, 0);
168 
169  // get the (1D) shape fn
170  this->dshape_local(s, psi, dpsi);
171 
172  // compute dx_i/ds_t and dx_i/ds_n at ipt
173  Vector<double> dxds_t(2, 0.0);
174  Vector<double> dxds_n(2, 0.0);
175  for (unsigned n = 0; n < n_node; n++)
176  {
177  for (unsigned d = 0; d < 2; d++)
178  {
179  for (unsigned k = 0; k < Nface_nodal_dof; k++)
180  {
181  dxds_t[d] += dpsi(n, k, 0) * node_pt(n)->x_gen(slope_index * k, d);
182  dxds_n[d] += psi(n, k) * node_pt(n)->x_gen(
183  outer_slope_index + slope_index * k, d);
184  }
185  }
186  }
187 
188  // compute ds_n/dn
189  double ds_ndn = -edge_sign *
190  sqrt(dxds_t[0] * dxds_t[0] + dxds_t[1] * dxds_t[1]) /
191  (-dxds_n[0] * dxds_t[1] + dxds_t[0] * dxds_n[1]);
192 
193  // compute ds_t/dn
194  double ds_tdn = edge_sign *
195  (dxds_t[1] * dxds_n[1] + dxds_t[0] * dxds_n[0]) /
196  (sqrt(dxds_t[0] * dxds_t[0] + dxds_t[1] * dxds_t[1]) *
197  (-dxds_n[0] * dxds_t[1] + dxds_t[0] * dxds_n[1]));
198 
199  // compute interpolated_m at s
200  double interpolated_m = 0.0;
201  Vector<double> m(2);
202  for (unsigned n = 0; n < n_node; n++)
203  {
204  this->node_pt(n)->get_coordinates_on_boundary(Boundary, m);
205  for (unsigned k = 0; k < Nface_nodal_dof; k++)
206  {
207  interpolated_m += psi(n, k) * m[k];
208  }
209  }
210 
211  // get the fluxes
212  double flux0 = 0.0;
213  get_flux0(interpolated_m, flux0);
214  double flux1 = 0.0;
215  get_flux1(interpolated_m, flux1);
216 
217  // get J
218  double J = J_eulerian(s);
219 
220  // Premultiply the weights and the Jacobian
221  double W = w * J;
222 
223  // Now add to the appropriate equations
224 
225 
226  // Loop over the test function nodes
227  for (unsigned n = 0; n < n_node; n++)
228  {
229  // loop over the face element position types
230  for (unsigned k = 0; k < Nface_nodal_dof; k++)
231  {
232  // apply contribution for flux0
233 
234  // determine bulk position type
235  unsigned bulk_p_type = slope_index * k;
236 
237  // local equation number
238  int local_eqn = this->nodal_local_eqn(n, bulk_p_type);
239 
240  // if node not pinned
241  if (local_eqn >= 0)
242  {
243  // add contribution to residual
244  residual[local_eqn] += flux1 * psi(n, k) * W;
245  }
246 
247  // apply first contribution for flux1
248 
249  // if node not pinned
250  if (local_eqn >= 0)
251  {
252  // add contribution to residual
253  residual[local_eqn] -= flux0 * dpsi(n, k, 0) * ds_tdn * W;
254  }
255 
256  // apply second contribution for flux1
257 
258  // determine bulk position type
259  bulk_p_type = outer_slope_index + slope_index * k;
260 
261  // local equation number
262  local_eqn = this->nodal_local_eqn(n, bulk_p_type);
263 
264  // if node not pinned
265  if (local_eqn >= 0)
266  {
267  // add contribution to residual
268  residual[local_eqn] -= flux0 * psi(n, k) * ds_ndn * W;
269  }
270  }
271  }
272  }
273  }
274 
275  // Ensure Flux elements are build
276  template class BiharmonicFluxElement<2>;
277 
278 } // namespace oomph
static char t char * s
Definition: cfortran.h:568
biharmonic element class
unsigned Nface_nodal_dof
the number of nodal degrees of freedom for the face element basis functions
double J_eulerian(const Vector< double > &s) const
Calculate the Jacobian of the mapping between local and global coordinates at the position s for face...
FluxFctPt Flux1_fct_pt
Function pointer to the prescribed flux.
FluxFctPt Flux0_fct_pt
Function pointer to the prescribed flux.
BiharmonicFluxElement()
Broken empty constructor.
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:4338
int & face_index()
Index of the face (a number that uniquely identifies the face in the element)
Definition: elements.h:4626
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
Definition: elements.h:4998
A general Finite Element class.
Definition: elements.h:1313
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:5132
A Class for shape functions. In simple cases, the shape functions have only one index that can be tho...
Definition: shape.h:76
//////////////////////////////////////////////////////////////////// ////////////////////////////////...