axisym_displ_based_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 
29 
30 
31 namespace oomph
32 {
33  //======================================================================
34  /// Set the data for the number of Variables at each node - 3
35  //======================================================================
36  template<unsigned NNODE_1D>
38 
39 
40  //======================================================================
41  /// Compute contribution to element residual Vector
42  ///
43  /// Pure version without hanging nodes
44  //======================================================================
46  Vector<double>& residuals)
47  {
48  // Find out how many nodes there are
49  const unsigned n_node = nnode();
50 
51  // Set up memory for the shape and test functions
52  Shape psi(n_node), test(n_node);
53  DShape dpsidr(n_node, 1), dtestdr(n_node, 1);
54 
55  // Set the value of n_intpt
56  const unsigned n_intpt = integral_pt()->nweight();
57 
58  // Indices at which the unknowns are stored
59  const unsigned w_nodal_index = nodal_index_fvk(0);
60  const unsigned laplacian_w_nodal_index = nodal_index_fvk(1);
61  const unsigned u_r_nodal_index = nodal_index_fvk(2);
62 
63  // Local copy of parameters
64  const double nu_local = nu();
65  const double eta_local = eta();
66 
67  // Integers to store the local equation numbers
68  int local_eqn = 0;
69 
70  // Loop over the integration points
71  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
72  {
73  // Get the integral weight
74  double w = integral_pt()->weight(ipt);
75 
76  // Call the derivatives of the shape and test functions
78  ipt, psi, dpsidr, test, dtestdr);
79 
80  // Allocate and initialise to zero storage for the interpolated values
81  double interpolated_r = 0.0;
82 
83  double interpolated_w = 0.0;
84  double interpolated_laplacian_w = 0.0;
85  double interpolated_u_r = 0.0;
86 
87  double interpolated_dwdr = 0.0;
88  double interpolated_dlaplacian_wdr = 0.0;
89  double interpolated_du_rdr = 0.0;
90 
92 
93  // Calculate function values and derivatives:
94  //-----------------------------------------
95  // Loop over nodes
96  for (unsigned l = 0; l < n_node; l++)
97  {
98  // Get the nodal values
99  nodal_value[0] = raw_nodal_value(l, w_nodal_index);
100  nodal_value[1] = raw_nodal_value(l, laplacian_w_nodal_index);
101  nodal_value[2] = raw_nodal_value(l, u_r_nodal_index);
102 
103  // Add contributions from current node/shape function
104  interpolated_w += nodal_value[0] * psi(l);
105  interpolated_laplacian_w += nodal_value[1] * psi(l);
106  interpolated_u_r += nodal_value[2] * psi(l);
107 
108  interpolated_r += raw_nodal_position(l, 0) * psi(l);
109 
110  interpolated_dwdr += nodal_value[0] * dpsidr(l, 0);
111  interpolated_dlaplacian_wdr += nodal_value[1] * dpsidr(l, 0);
112  interpolated_du_rdr += nodal_value[2] * dpsidr(l, 0);
113 
114  } // End of loop over the nodes
115 
116  // Premultiply the weights and the Jacobian
117  double W = w * interpolated_r * J;
118 
119  // Get pressure function
120  //---------------------
121  double pressure = 0.0;
122  get_pressure_fvk(ipt, interpolated_r, pressure);
123 
124  // Determine the stresses
125  //-----------------------
126 
127  double sigma_r_r = 0.0;
128  double sigma_phi_phi = 0.0;
129 
131  {
132  sigma_r_r =
133  1.0 / (1.0 - nu_local * nu_local) *
134  (interpolated_du_rdr + 0.5 * interpolated_dwdr * interpolated_dwdr +
135  nu_local * 1.0 / interpolated_r * interpolated_u_r);
136 
137  sigma_phi_phi =
138  1.0 / (1.0 - nu_local * nu_local) *
139  (1.0 / interpolated_r * interpolated_u_r +
140  nu_local * (interpolated_du_rdr +
141  0.5 * interpolated_dwdr * interpolated_dwdr));
142  }
143  else
144  {
145  sigma_r_r = 1.0 / (1.0 - nu_local * nu_local) *
146  (interpolated_du_rdr +
147  nu_local * 1.0 / interpolated_r * interpolated_u_r);
148 
149  sigma_phi_phi = 1.0 / (1.0 - nu_local * nu_local) *
150  (1.0 / interpolated_r * interpolated_u_r +
151  nu_local * interpolated_du_rdr);
152  }
153 
154 
155  // Assemble residuals and Jacobian:
156  //--------------------------------
157  // Loop over the test functions
158  for (unsigned l = 0; l < n_node; l++)
159  {
160  // Get the local equation
161  local_eqn = nodal_local_eqn(l, w_nodal_index);
162 
163  // IF it's not a boundary condition
164  if (local_eqn >= 0)
165  {
166  residuals[local_eqn] +=
167  (pressure * test(l) +
168  (dtestdr(l, 0)) * interpolated_dlaplacian_wdr) *
169  W;
171  {
172  residuals[local_eqn] -=
173  eta_local * sigma_r_r * (dtestdr(l, 0)) * interpolated_dwdr * W;
174  }
175  }
176 
177  // Get the local equation
178  local_eqn = nodal_local_eqn(l, laplacian_w_nodal_index);
179 
180  // IF it's not a boundary condition
181  if (local_eqn >= 0)
182  {
183  residuals[local_eqn] += (test(l) * interpolated_laplacian_w +
184  (dtestdr(l, 0)) * interpolated_dwdr) *
185  W;
186  }
187 
188  // Get the local equation
189  local_eqn = nodal_local_eqn(l, u_r_nodal_index);
190 
191  // IF it's not a boundary condition
192  if (local_eqn >= 0)
193  {
194  residuals[local_eqn] +=
195  (sigma_r_r * dtestdr(l, 0) +
196  1.0 / interpolated_r * sigma_phi_phi * test(l)) *
197  W;
198  }
199 
200  } // End of loop over test functions
201  } // End of loop over integration points
202  }
203 
204 
205  //======================================================================
206  /// Self-test: Return 0 for OK
207  //======================================================================
209  {
210  bool passed = true;
211 
212  // Check lower-level stuff
213  if (FiniteElement::self_test() != 0)
214  {
215  passed = false;
216  }
217 
218  // Return verdict
219  if (passed)
220  {
221  return 0;
222  }
223  else
224  {
225  return 1;
226  }
227  }
228 
229 
230  //======================================================================
231  /// Compute in-plane stresses. Return boolean to indicate success
232  /// (false if attempt to evaluate stresses at zero radius)
233  //======================================================================
235  const Vector<double>& s, double& sigma_r_r, double& sigma_phi_phi) const
236  {
237  // No in plane stresses if linear bending
239  {
240  sigma_r_r = 0.0;
241  sigma_phi_phi = 0.0;
242 
243  // Success!
244  return true;
245  }
246  else
247  {
248  // Get shape fcts and derivs
249  unsigned n_dim = this->dim();
250  unsigned n_node = this->nnode();
251  Shape psi(n_node);
252  DShape dpsidr(n_node, n_dim);
253 
254  // Check if we're dividing by zero
255  Vector<double> r(1);
256  this->interpolated_x(s, r);
257  if (r[0] == 0.0)
258  {
259  sigma_r_r = 0.0;
260  sigma_phi_phi = 0.0;
261  return false;
262  }
263 
264  // Get shape fcts and derivs
265  dshape_eulerian(s, psi, dpsidr);
266 
267  // Allocate and initialise to zero storage for the interpolated values
268  double interpolated_r = 0.0;
269  double interpolated_u_r = 0.0;
270 
271  double interpolated_dwdr = 0.0;
272  double interpolated_du_rdr = 0.0;
273 
274  double nu_local = nu();
275 
276 
277  // Calculate function values and derivatives:
278  //-----------------------------------------
279  // Loop over nodes
280  for (unsigned l = 0; l < n_node; l++)
281  {
282  // Add contributions from current node/shape function
283  interpolated_r += raw_nodal_position(l, 0) * psi(l);
284  interpolated_u_r +=
285  this->raw_nodal_value(l, nodal_index_fvk(2)) * psi(l);
286  interpolated_dwdr +=
287  this->raw_nodal_value(l, nodal_index_fvk(0)) * dpsidr(l, 0);
288  interpolated_du_rdr +=
289  this->raw_nodal_value(l, nodal_index_fvk(2)) * dpsidr(l, 0);
290  } // End of loop over nodes
291 
292  // Compute the stresses:
293  //---------------------
294  sigma_r_r =
295  1.0 / (1.0 - nu_local * nu_local) *
296  (interpolated_du_rdr + 0.5 * interpolated_dwdr * interpolated_dwdr +
297  nu_local * 1.0 / interpolated_r * interpolated_u_r);
298 
299  sigma_phi_phi =
300  1.0 / (1.0 - nu_local * nu_local) *
301  (1.0 / interpolated_r * interpolated_u_r +
302  nu_local *
303  (interpolated_du_rdr + 0.5 * interpolated_dwdr * interpolated_dwdr));
304 
305  // Success!
306  return true;
307 
308  } // End if
309 
310  } // End of interpolated_stress function
311 
312  //======================================================================
313  /// Output function:
314  /// r, w, u, sigma_r_r, sigma_phi_phi
315  /// nplot points
316  //======================================================================
317  void AxisymFoepplvonKarmanEquations::output(std::ostream& outfile,
318  const unsigned& nplot)
319  {
320  // Vector of local coordinates
321  Vector<double> s(1);
322 
323  // Tecplot header info
324  outfile << "ZONE\n";
325 
326  // Loop over plot points
327  unsigned num_plot_points = nplot_points(nplot);
328  for (unsigned iplot = 0; iplot < num_plot_points; iplot++)
329  {
330  // Get local coordinates of plot point
331  get_s_plot(iplot, nplot, s);
332 
333  // Get stress
334  double sigma_r_r = 0.0;
335  double sigma_phi_phi = 0.0;
336  bool success = interpolated_stress(s, sigma_r_r, sigma_phi_phi);
337  if (success)
338  {
339  outfile << interpolated_x(s, 0) << " " << interpolated_w_fvk(s) << " "
340  << interpolated_u_fvk(s) << " " << sigma_r_r << " "
341  << sigma_phi_phi << std::endl;
342  }
343  }
344  }
345 
346  //======================================================================
347  /// C-style output function:
348  /// r,w,u
349  /// nplot points
350  //======================================================================
352  const unsigned& nplot)
353  {
354  // Vector of local coordinates
355  Vector<double> s(1);
356 
357  // Tecplot header info
358  fprintf(file_pt, "%s", tecplot_zone_string(nplot).c_str());
359 
360  // Loop over plot points
361  unsigned num_plot_points = nplot_points(nplot);
362  for (unsigned iplot = 0; iplot < num_plot_points; iplot++)
363  {
364  // Get local coordinates of plot point
365  get_s_plot(iplot, nplot, s);
366 
367  fprintf(file_pt, "%g ", interpolated_x(s, 0));
368  fprintf(file_pt, "%g \n", interpolated_w_fvk(s));
369  fprintf(file_pt, "%g \n", interpolated_u_fvk(s));
370  }
371 
372  // Write tecplot footer (e.g. FE connectivity lists)
373  write_tecplot_zone_footer(file_pt, nplot);
374  }
375 
376 
377  //======================================================================
378  /// Output exact solution
379  ///
380  /// Solution is provided via function pointer.
381  /// Plot at a given number of plot points.
382  ///
383  /// r,w_exact
384  //======================================================================
386  std::ostream& outfile,
387  const unsigned& nplot,
389  {
390  // Vector of local coordinates
391  Vector<double> s(1);
392 
393  // Vector for coordinates
394  Vector<double> r(1);
395 
396  // Tecplot header info
397  outfile << tecplot_zone_string(nplot);
398 
399  // Exact solution Vector (here a scalar)
400  // Vector<double> exact_soln(1);
401  Vector<double> exact_soln(1);
402 
403  // Loop over plot points
404  unsigned num_plot_points = nplot_points(nplot);
405  for (unsigned iplot = 0; iplot < num_plot_points; iplot++)
406  {
407  // Get local coordinates of plot point
408  get_s_plot(iplot, nplot, s);
409 
410  // Get r position as Vector
411  interpolated_x(s, r);
412 
413  // Get exact solution at this point
414  (*exact_soln_pt)(r, exact_soln);
415 
416  // Output r,w_exact
417  outfile << r[0] << " ";
418  outfile << exact_soln[0] << std::endl;
419  }
420 
421  // Write tecplot footer (e.g. FE connectivity lists)
422  write_tecplot_zone_footer(outfile, nplot);
423  }
424 
425 
426  //======================================================================
427  /// Validate against exact solution
428  ///
429  /// Solution is provided via function pointer.
430  /// Plot error at a given number of plot points.
431  ///
432  //======================================================================
434  std::ostream& outfile,
436  double& error,
437  double& norm)
438  {
439  // Initialise
440  error = 0.0;
441  norm = 0.0;
442 
443  // Vector of local coordinates
444  Vector<double> s(1);
445 
446  // Vector for coordintes
447  Vector<double> r(1);
448 
449  // Find out how many nodes there are in the element
450  unsigned n_node = nnode();
451 
452  Shape psi(n_node);
453 
454  // Set the value of n_intpt
455  unsigned n_intpt = integral_pt()->nweight();
456 
457  // Tecplot
458  outfile << "ZONE" << std::endl;
459 
460  // Exact solution Vector (here a scalar)
461  // Vector<double> exact_soln(1);
462  Vector<double> exact_soln(1);
463 
464  // Loop over the integration points
465  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
466  {
467  // Assign values of s
468  s[0] = integral_pt()->knot(ipt, 0);
469 
470  // Get the integral weight
471  double w = integral_pt()->weight(ipt);
472 
473  // Get jacobian of mapping
474  double J = J_eulerian(s);
475 
476  // Premultiply the weights and the Jacobian
477  double W = w * J;
478 
479  // Get r position as Vector
480  interpolated_x(s, r);
481 
482  // Get FE function value
483  double w_fe = interpolated_w_fvk(s);
484 
485  // Get exact solution at this point
486  (*exact_soln_pt)(r, exact_soln);
487 
488  // Output r,error
489  outfile << r[0] << " ";
490  outfile << exact_soln[0] << " " << exact_soln[0] - w_fe << std::endl;
491 
492  // Add to error and norm
493  norm += exact_soln[0] * exact_soln[0] * W;
494  error += (exact_soln[0] - w_fe) * (exact_soln[0] - w_fe) * W;
495  }
496 
497  {
498  // Initialise
499  error = 0.0;
500  norm = 0.0;
501 
502  // Vector of local coordinates
503  Vector<double> s(1);
504 
505  // Vector for coordintes
506  Vector<double> r(1);
507 
508  // Find out how many nodes there are in the element
509  unsigned n_node = nnode();
510 
511  Shape psi(n_node);
512 
513  // Set the value of n_intpt
514  unsigned n_intpt = integral_pt()->nweight();
515 
516  // Tecplot
517  outfile << "ZONE" << std::endl;
518 
519  // Exact solution Vector (here a scalar)
520  // Vector<double> exact_soln(1);
521  Vector<double> exact_soln(1);
522 
523  // Loop over the integration points
524  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
525  {
526  // Assign values of s
527  s[0] = integral_pt()->knot(ipt, 0);
528 
529  // Get the integral weight
530  double w = integral_pt()->weight(ipt);
531 
532  // Get jacobian of mapping
533  double J = J_eulerian(s);
534 
535  // Premultiply the weights and the Jacobian
536  double W = w * J;
537 
538  // Get r position as Vector
539  interpolated_x(s, r);
540 
541  // Get FE function value
542  double w_fe = interpolated_w_fvk(s);
543 
544  // Get exact solution at this point
545  (*exact_soln_pt)(r, exact_soln);
546 
547  // Output r error
548  outfile << r[0] << " ";
549  outfile << exact_soln[0] << " " << exact_soln[0] - w_fe << std::endl;
550 
551  // Add to error and norm
552  norm += exact_soln[0] * exact_soln[0] * W;
553  error += (exact_soln[0] - w_fe) * (exact_soln[0] - w_fe) * W;
554  }
555  }
556  }
557 
558 
559  //====================================================================
560  // Force build of templates
561  //====================================================================
562  template class AxisymFoepplvonKarmanElement<2>;
563  template class AxisymFoepplvonKarmanElement<3>;
564  template class AxisymFoepplvonKarmanElement<4>;
565 
566 } // 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.
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_u_fvk(const Vector< double > &s) const
Return FE representation of radial displacement.
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...
const double & nu() const
Poisson's ratio.
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
//////////////////////////////////////////////////////////////////// ////////////////////////////////...