axisym_fvk_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 // Non-inline functions for axisym FoepplvonKarman elements
27 
28 #include "axisym_fvk_elements.h"
29 
30 namespace oomph
31 {
32  //======================================================================
33  /// Set the data for the number of Variables at each node: 6
34  //======================================================================
35  template<unsigned NNODE_1D>
37 
38 
39  //======================================================================
40  /// Default value physical constants
41  //======================================================================
43 
44 
45  //======================================================================
46  /// Compute contribution to element residual Vector
47  ///
48  /// Pure version without hanging nodes
49  //======================================================================
51  Vector<double>& residuals)
52  {
53  // Find out how many nodes there are
54  const unsigned n_node = nnode();
55 
56  // Set up memory for the shape and test functions
57  Shape psi(n_node), test(n_node);
58  DShape dpsidr(n_node, 1), dtestdr(n_node, 1);
59 
60  // Indices at which the unknowns are stored
61  const unsigned w_nodal_index = nodal_index_fvk(0);
62  const unsigned laplacian_w_nodal_index = nodal_index_fvk(1);
63  const unsigned phi_nodal_index = nodal_index_fvk(2);
64  const unsigned laplacian_phi_nodal_index = nodal_index_fvk(3);
65  const unsigned smooth_dwdr_nodal_index = nodal_index_fvk(4);
66  const unsigned smooth_dphidr_nodal_index = nodal_index_fvk(5);
67 
68  // Set the value of n_intpt
69  const unsigned n_intpt = integral_pt()->nweight();
70 
71  // Integers to store the local equation numbers
72  int local_eqn = 0;
73 
74  // Loop over the integration points
75  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
76  {
77  // Get the integral weight
78  double w = integral_pt()->weight(ipt);
79 
80  // Call the derivatives of the shape and test functions
82  ipt, psi, dpsidr, test, dtestdr);
83 
84  // Allocate and initialise to zero storage for the interpolated values
85  double interpolated_r = 0;
86 
87  double interpolated_w = 0;
88  double interpolated_laplacian_w = 0;
89  double interpolated_phi = 0;
90  double interpolated_laplacian_phi = 0;
91 
92  double interpolated_dwdr = 0;
93  double interpolated_dlaplacian_wdr = 0;
94  double interpolated_dphidr = 0;
95  double interpolated_dlaplacian_phidr = 0;
96 
97  double interpolated_smooth_dwdr = 0;
98  double interpolated_smooth_dphidr = 0;
99  double interpolated_continuous_d2wdr2 = 0;
100  double interpolated_continuous_d2phidr2 = 0;
101 
102  // Calculate function values and derivatives:
103  //-----------------------------------------
104  Vector<double> nodal_value(6, 0.0);
105  // Loop over nodes
106  for (unsigned l = 0; l < n_node; l++)
107  {
108  // Get the nodal values
109  nodal_value[0] = raw_nodal_value(l, w_nodal_index);
110  nodal_value[1] = raw_nodal_value(l, laplacian_w_nodal_index);
111 
113  {
114  nodal_value[2] = raw_nodal_value(l, phi_nodal_index);
115  nodal_value[3] = raw_nodal_value(l, laplacian_phi_nodal_index);
116  nodal_value[4] = raw_nodal_value(l, smooth_dwdr_nodal_index);
117  nodal_value[5] = raw_nodal_value(l, smooth_dphidr_nodal_index);
118  }
119 
120  // Add contributions from current node/shape function
121  interpolated_w += nodal_value[0] * psi(l);
122  interpolated_laplacian_w += nodal_value[1] * psi(l);
123 
125  {
126  interpolated_phi += nodal_value[2] * psi(l);
127  interpolated_laplacian_phi += nodal_value[3] * psi(l);
128  interpolated_smooth_dwdr += nodal_value[4] * psi(l);
129  interpolated_smooth_dphidr += nodal_value[5] * psi(l);
130 
131  interpolated_continuous_d2wdr2 += nodal_value[4] * dpsidr(l, 0);
132  interpolated_continuous_d2phidr2 += nodal_value[5] * dpsidr(l, 0);
133  }
134 
135  interpolated_r += raw_nodal_position(l, 0) * psi(l);
136  interpolated_dwdr += nodal_value[0] * dpsidr(l, 0);
137  interpolated_dlaplacian_wdr += nodal_value[1] * dpsidr(l, 0);
138 
140  {
141  interpolated_dphidr += nodal_value[2] * dpsidr(l, 0);
142  interpolated_dlaplacian_phidr += nodal_value[3] * dpsidr(l, 0);
143  }
144  } // End of loop over the nodes
145 
146 
147  // Premultiply the weights and the Jacobian
148  double W = w * interpolated_r * J;
149 
150  // Get pressure function
151  //-------------------
152  double pressure;
153  get_pressure_fvk(ipt, interpolated_r, pressure);
154 
155  double airy_forcing;
156  get_airy_forcing_fvk(ipt, interpolated_r, airy_forcing);
157 
158 
159  // Assemble residuals and Jacobian
160  //--------------------------------
161 
162  // Loop over the test functions
163  for (unsigned l = 0; l < n_node; l++)
164  {
165  // Get the local equation
166  local_eqn = nodal_local_eqn(l, w_nodal_index);
167 
168  // IF it's not a boundary condition
169  if (local_eqn >= 0)
170  {
171  residuals[local_eqn] += pressure * test(l) * W;
172 
173  // Reduced order biharmonic operator
174  residuals[local_eqn] +=
175  interpolated_dlaplacian_wdr * dtestdr(l, 0) * W;
176 
178  {
179  // Monge-Ampere part
180  residuals[local_eqn] +=
181  eta() *
182  (interpolated_continuous_d2wdr2 * interpolated_dphidr +
183  interpolated_dwdr * interpolated_continuous_d2phidr2) /
184  interpolated_r * test(l) * W;
185  }
186  }
187 
188  // Get the local equation
189  local_eqn = nodal_local_eqn(l, laplacian_w_nodal_index);
190 
191  // IF it's not a boundary condition
192  if (local_eqn >= 0)
193  {
194  // The coupled Poisson equations for the biharmonic operator
195  residuals[local_eqn] += interpolated_laplacian_w * test(l) * W;
196  residuals[local_eqn] += interpolated_dwdr * dtestdr(l, 0) * W;
197  }
198 
199  // Get the local equation
200  local_eqn = nodal_local_eqn(l, phi_nodal_index);
201 
202  // IF it's not a boundary condition
203  if (local_eqn >= 0)
204  {
205  residuals[local_eqn] += airy_forcing * test(l) * W;
206 
207  // Reduced order biharmonic operator
208  residuals[local_eqn] +=
209  interpolated_dlaplacian_phidr * dtestdr(l, 0) * W;
210 
211  // Monge-Ampere part
212  residuals[local_eqn] -= interpolated_continuous_d2wdr2 *
213  interpolated_dwdr / interpolated_r * test(l) *
214  W;
215  }
216 
217  // Get the local equation
218  local_eqn = nodal_local_eqn(l, laplacian_phi_nodal_index);
219 
220  // IF it's not a boundary condition
221  if (local_eqn >= 0)
222  {
223  // The coupled Poisson equations for the biharmonic operator
224  residuals[local_eqn] += interpolated_laplacian_phi * test(l) * W;
225  residuals[local_eqn] += interpolated_dphidr * dtestdr(l, 0) * W;
226  }
227 
228  // Residuals for the smooth derivatives
229  local_eqn = nodal_local_eqn(l, smooth_dwdr_nodal_index);
230  if (local_eqn >= 0)
231  {
232  residuals[local_eqn] +=
233  (interpolated_dwdr - interpolated_smooth_dwdr) * test(l) * W;
234  }
235 
236  local_eqn = nodal_local_eqn(l, smooth_dphidr_nodal_index);
237  if (local_eqn >= 0)
238  {
239  residuals[local_eqn] +=
240  (interpolated_dphidr - interpolated_smooth_dphidr) * test(l) * W;
241  }
242 
243  } // End of loop over test functions
244  } // End of loop over integration points
245  }
246 
247 
248  //======================================================================
249  /// Self-test: Return 0 for OK
250  //======================================================================
252  {
253  bool passed = true;
254 
255  // Check lower-level stuff
256  if (FiniteElement::self_test() != 0)
257  {
258  passed = false;
259  }
260 
261  // Return verdict
262  if (passed)
263  {
264  return 0;
265  }
266  else
267  {
268  return 1;
269  }
270  }
271 
272 
273  //======================================================================
274  /// Compute in-plane stresses. Return boolean to indicate success
275  /// (false if attempt to evaluate stresses at zero radius)
276  //======================================================================
278  const Vector<double>& s, double& sigma_r_r, double& sigma_phi_phi)
279 
280  {
281  // No in plane stresses if linear bending
283  {
284  sigma_r_r = 0.0;
285  sigma_phi_phi = 0.0;
286 
287  // Success!
288  return true;
289  }
290  else
291  {
292  // Get shape fcts and derivs
293  unsigned n_dim = this->dim();
294  unsigned n_node = this->nnode();
295  Shape psi(n_node);
296  DShape dpsi_dr(n_node, n_dim);
297 
298  // Check if we're dividing by zero
299  Vector<double> r(1);
300  this->interpolated_x(s, r);
301  if (r[0] == 0.0)
302  {
303  sigma_r_r = 0.0;
304  sigma_phi_phi = 0.0;
305  return false;
306  }
307 
308  // Get shape fcts and derivs
309  dshape_eulerian(s, psi, dpsi_dr);
310 
311  // Indices at which the unknowns are stored
312  const unsigned smooth_dphi_dr_nodal_index = nodal_index_fvk(5);
313 
314  // Allocate and initialise to zero storage for the interpolated values
315  double interpolated_r = 0;
316  double interpolated_dphi_dr = 0;
317  double interpolated_continuous_d2phi_dr2 = 0;
318 
319 
320  // Calculate function values and derivatives:
321  //-----------------------------------------
322  // Loop over nodes
323  for (unsigned l = 0; l < n_node; l++)
324  {
325  // Add contributions from current node/shape function
326  interpolated_r += raw_nodal_position(l, 0) * psi(l);
327  interpolated_dphi_dr +=
328  this->nodal_value(l, smooth_dphi_dr_nodal_index) * psi(l);
329  interpolated_continuous_d2phi_dr2 +=
330  this->nodal_value(l, smooth_dphi_dr_nodal_index) * dpsi_dr(l, 0);
331  } // End of loop over nodes
332 
333  // Compute stresses
334  sigma_r_r = interpolated_dphi_dr / interpolated_r;
335  sigma_phi_phi = interpolated_continuous_d2phi_dr2;
336 
337  // Success!
338  return true;
339 
340  } // End if
341 
342  } // End of interpolated_stress function
343 
344 
345  //======================================================================
346  /// Output function:
347  /// r, w, sigma_r_r, sigma_phi_phi
348  /// nplot points
349  //======================================================================
350  void AxisymFoepplvonKarmanEquations::output(std::ostream& outfile,
351  const unsigned& nplot)
352  {
353  // Vector of local coordinates
354  Vector<double> s(1);
355 
356  // Tecplot header info
357  outfile << "ZONE\n";
358 
359  // Loop over plot points
360  unsigned num_plot_points = nplot_points(nplot);
361  for (unsigned iplot = 0; iplot < num_plot_points; iplot++)
362  {
363  // Get local coordinates of plot point
364  get_s_plot(iplot, nplot, s);
365 
366  // Get stress
367  double sigma_r_r = 0.0;
368  double sigma_phi_phi = 0.0;
369  bool success = interpolated_stress(s, sigma_r_r, sigma_phi_phi);
370  if (success)
371  {
372  outfile << interpolated_x(s, 0) << " " << interpolated_w_fvk(s) << " "
373  << sigma_r_r << " " << sigma_phi_phi << std::endl;
374  }
375  }
376  }
377 
378 
379  //======================================================================
380  /// C-style output function:
381  /// r,w
382  /// nplot points
383  //======================================================================
384  void AxisymFoepplvonKarmanEquations::output(FILE* file_pt,
385  const unsigned& nplot)
386  {
387  // Vector of local coordinates
388  Vector<double> s(1);
389 
390  // Tecplot header info
391  fprintf(file_pt, "%s", tecplot_zone_string(nplot).c_str());
392 
393  // Loop over plot points
394  unsigned num_plot_points = nplot_points(nplot);
395  for (unsigned iplot = 0; iplot < num_plot_points; iplot++)
396  {
397  // Get local coordinates of plot point
398  get_s_plot(iplot, nplot, s);
399 
400  fprintf(file_pt, "%g ", interpolated_x(s, 0));
401  fprintf(file_pt, "%g \n", interpolated_w_fvk(s));
402  }
403 
404  // Write tecplot footer (e.g. FE connectivity lists)
405  write_tecplot_zone_footer(file_pt, nplot);
406  }
407 
408 
409  //======================================================================
410  /// Output exact solution
411  ///
412  /// Solution is provided via function pointer.
413  /// Plot at a given number of plot points.
414  ///
415  /// r,w_exact
416  //======================================================================
418  std::ostream& outfile,
419  const unsigned& nplot,
421  {
422  // Vector of local coordinates
423  Vector<double> s(1);
424 
425  // Vector for coordinates
426  Vector<double> r(1);
427 
428  // Tecplot header info
429  outfile << tecplot_zone_string(nplot);
430 
431  // Exact solution Vector (here a scalar)
432  // Vector<double> exact_soln(1);
433  Vector<double> exact_soln(1);
434 
435  // Loop over plot points
436  unsigned num_plot_points = nplot_points(nplot);
437  for (unsigned iplot = 0; iplot < num_plot_points; iplot++)
438  {
439  // Get local coordinates of plot point
440  get_s_plot(iplot, nplot, s);
441 
442  // Get r position as Vector
443  interpolated_x(s, r);
444 
445  // Get exact solution at this point
446  (*exact_soln_pt)(r, exact_soln);
447 
448  // Output r,w_exact
449  outfile << r[0] << " ";
450  outfile << exact_soln[0] << std::endl;
451  }
452 
453  // Write tecplot footer (e.g. FE connectivity lists)
454  write_tecplot_zone_footer(outfile, nplot);
455  }
456 
457 
458  //======================================================================
459  /// Validate against exact solution
460  ///
461  /// Solution is provided via function pointer.
462  /// Plot error at a given number of plot points.
463  ///
464  //======================================================================
466  std::ostream& outfile,
468  double& error,
469  double& norm)
470  {
471  // Initialise
472  error = 0.0;
473  norm = 0.0;
474 
475  // Vector of local coordinates
476  Vector<double> s(1);
477 
478  // Vector for coordintes
479  Vector<double> r(1);
480 
481  // Find out how many nodes there are in the element
482  unsigned n_node = nnode();
483 
484  Shape psi(n_node);
485 
486  // Set the value of n_intpt
487  unsigned n_intpt = integral_pt()->nweight();
488 
489  // Tecplot
490  outfile << "ZONE" << std::endl;
491 
492  // Exact solution Vector (here a scalar)
493  // Vector<double> exact_soln(1);
494  Vector<double> exact_soln(1);
495 
496  // Loop over the integration points
497  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
498  {
499  // Assign values of s
500  s[0] = integral_pt()->knot(ipt, 0);
501 
502  // Get the integral weight
503  double w = integral_pt()->weight(ipt);
504 
505  // Get jacobian of mapping
506  double J = J_eulerian(s);
507 
508  // Premultiply the weights and the Jacobian
509  double W = w * J;
510 
511  // Get r position as Vector
512  interpolated_x(s, r);
513 
514  // Get FE function value
515  double w_fe = interpolated_w_fvk(s);
516 
517  // Get exact solution at this point
518  (*exact_soln_pt)(r, exact_soln);
519 
520  // Output r,error
521  outfile << r[0] << " ";
522  outfile << exact_soln[0] << " " << exact_soln[0] - w_fe << std::endl;
523 
524  // Add to error and norm
525  norm += exact_soln[0] * exact_soln[0] * W;
526  error += (exact_soln[0] - w_fe) * (exact_soln[0] - w_fe) * W;
527  }
528 
529  {
530  // Initialise
531  error = 0.0;
532  norm = 0.0;
533 
534  // Vector of local coordinates
535  Vector<double> s(1);
536 
537  // Vector for coordintes
538  Vector<double> r(1);
539 
540  // Find out how many nodes there are in the element
541  unsigned n_node = nnode();
542 
543  Shape psi(n_node);
544 
545  // Set the value of n_intpt
546  unsigned n_intpt = integral_pt()->nweight();
547 
548  // Tecplot
549  outfile << "ZONE" << std::endl;
550 
551  // Exact solution Vector (here a scalar)
552  // Vector<double> exact_soln(1);
553  Vector<double> exact_soln(1);
554 
555  // Loop over the integration points
556  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
557  {
558  // Assign values of s
559  s[0] = integral_pt()->knot(ipt, 0);
560 
561  // Get the integral weight
562  double w = integral_pt()->weight(ipt);
563 
564  // Get jacobian of mapping
565  double J = J_eulerian(s);
566 
567  // Premultiply the weights and the Jacobian
568  double W = w * J;
569 
570  // Get r position as Vector
571  interpolated_x(s, r);
572 
573  // Get FE function value
574  double w_fe = interpolated_w_fvk(s);
575 
576  // Get exact solution at this point
577  (*exact_soln_pt)(r, exact_soln);
578 
579  // Output r error
580  outfile << r[0] << " ";
581  outfile << exact_soln[0] << " " << exact_soln[0] - w_fe << std::endl;
582 
583  // Add to error and norm
584  norm += exact_soln[0] * exact_soln[0] * W;
585  error += (exact_soln[0] - w_fe) * (exact_soln[0] - w_fe) * W;
586  }
587  }
588  }
589 
590 
591  //====================================================================
592  // Force build of templates
593  //====================================================================
594  template class AxisymFoepplvonKarmanElement<2>;
595  template class AxisymFoepplvonKarmanElement<3>;
596  template class AxisymFoepplvonKarmanElement<4>;
597 
598 } // namespace oomph
static char t char * s
Definition: cfortran.h:568
static const unsigned Initial_Nvalue
Static int that holds the number of variables at nodes: always the same.
static double Default_Physical_Constant_Value
Default value for physical constants.
void output(std::ostream &outfile)
Output with default number of plot points.
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Fill in the residuals with this element's contribution.
bool interpolated_stress(const Vector< double > &s, double &sigma_r_r, double &sigma_phi_phi) const
Compute in-plane stresses. Return boolean to indicate success (false if attempt to evaluate stresses ...
unsigned self_test()
Self-test: Return 0 for OK.
virtual double dshape_and_dtest_eulerian_at_knot_axisym_fvk(const unsigned &ipt, Shape &psi, DShape &dpsidr, Shape &test, DShape &dtestdr) const =0
Shape/test functions and derivs w.r.t. to global coords at integration point ipt; return Jacobian of ...
virtual unsigned nodal_index_fvk(const unsigned &i=0) const
Return the index at which the i-th unknown value is stored. The default value, i, is appropriate for ...
bool Linear_bending_model
Flag which stores whether we are using a linear, pure bending model instead of the full non-linear Fo...
const double & eta() const
FvK parameter.
void output_fct(std::ostream &outfile, const unsigned &n_plot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
Output exact soln: r,w_exact at n_plot plot points.
void compute_error(std::ostream &outfile, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, double &error, double &norm)
Get error against and norm of exact solution.
double interpolated_w_fvk(const Vector< double > &s) const
Return FE representation of transverse displacement.
virtual void get_pressure_fvk(const unsigned &ipt, const double &r, double &pressure) const
Get pressure term at (Eulerian) position r. This function is virtual to allow overloading in multi-ph...
virtual void get_airy_forcing_fvk(const unsigned &ipt, const double &r, double &airy_forcing) const
Get Airy forcing term at (Eulerian) position r. This function is virtual to allow overloading in mult...
A Class for the derivatives of shape functions The class design is essentially the same as Shape,...
Definition: shape.h:278
virtual double J_eulerian(const Vector< double > &s) const
Return the Jacobian of mapping from local to global coordinates at local position s.
Definition: elements.cc:4103
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:2593
virtual std::string tecplot_zone_string(const unsigned &nplot) const
Return string for tecplot zone header (when plotting nplot points in each "coordinate direction")
Definition: elements.h:3161
virtual double interpolated_x(const Vector< double > &s, const unsigned &i) const
Return FE interpolated coordinate x[i] at local coordinate s.
Definition: elements.cc:3962
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:1432
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
Definition: elements.h:2611
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2210
void(* SteadyExactSolutionFctPt)(const Vector< double > &, Vector< double > &)
Function pointer for function that computes vector-valued steady "exact solution" as .
Definition: elements.h:1759
Integral *const & integral_pt() const
Return the pointer to the integration scheme (const version)
Definition: elements.h:1963
virtual void get_s_plot(const unsigned &i, const unsigned &nplot, Vector< double > &s, const bool &shifted_to_interior=false) const
Get cector of local coordinates of plot point i (when plotting nplot points in each "coordinate direc...
Definition: elements.h:3148
virtual unsigned nplot_points(const unsigned &nplot) const
Return total number of plot points (when plotting nplot points in each "coordinate direction")
Definition: elements.h:3186
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:3298
double raw_nodal_value(const unsigned &n, const unsigned &i) const
Return the i-th value stored at local node n but do NOT take hanging nodes into account.
Definition: elements.h:2576
double raw_nodal_position(const unsigned &n, const unsigned &i) const
Return the i-th coordinate at local node n. Do not use the hanging node representation....
Definition: elements.cc:1686
virtual void write_tecplot_zone_footer(std::ostream &outfile, const unsigned &nplot) const
Add tecplot zone "footer" to output stream (when plotting nplot points in each "coordinate direction"...
Definition: elements.h:3174
virtual unsigned self_test()
Self-test: Check inversion of element & do self-test for GeneralisedElement. Return 0 if OK.
Definition: elements.cc:4440
virtual double knot(const unsigned &i, const unsigned &j) const =0
Return local coordinate s[j] of i-th integration point.
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.
A Class for shape functions. In simple cases, the shape functions have only one index that can be tho...
Definition: shape.h:76
//////////////////////////////////////////////////////////////////// ////////////////////////////////...