linear_wave_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 #include <cmath>
27 
28 // Non-inline functions for LinearWave elements
29 #include "linear_wave_elements.h"
30 
31 
32 namespace oomph
33 {
34  /// 2D LinearWave elements
35 
36 
37  //======================================================================
38  // Set the data for the number of Variables at each node
39  //======================================================================
40  template<>
41  const unsigned QLinearWaveElement<1, 4>::Initial_Nvalue[4] = {1, 1, 1, 1};
42  template<>
43  const unsigned QLinearWaveElement<1, 3>::Initial_Nvalue[3] = {1, 1, 1};
44  template<>
45  const unsigned QLinearWaveElement<1, 2>::Initial_Nvalue[2] = {1, 1};
46 
47  template<>
49  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
50  template<>
52  1, 1, 1, 1, 1, 1, 1, 1, 1};
53  template<>
54  const unsigned QLinearWaveElement<2, 2>::Initial_Nvalue[4] = {1, 1, 1, 1};
55 
56  template<>
58  1, 1, 1, 1, 1, 1, 1, 1};
59  template<>
61  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
62  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
63  template<>
65  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
66  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
67  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
68 
69 
70  //======================================================================
71  /// Compute element residual Vector and/or element Jacobian matrix
72  ///
73  /// flag=1: compute both
74  /// flag=0: compute only residual Vector
75  ///
76  /// Pure version without hanging nodes
77  //======================================================================
78  template<unsigned DIM>
80  Vector<double>& residuals, DenseMatrix<double>& jacobian, unsigned flag)
81  {
82  // Find out how many nodes there are
83  unsigned n_node = nnode();
84 
85  // Get continuous time from timestepper of first node
86  double time = node_pt(0)->time_stepper_pt()->time_pt()->time();
87 
88  // Find the index at which the linear wave unknown is stored
89  unsigned u_nodal_index = u_index_lin_wave();
90 
91  // Set up memory for the shape and test functions
92  Shape psi(n_node), test(n_node);
93  DShape dpsidx(n_node, DIM), dtestdx(n_node, DIM);
94 
95  // Set the value of n_intpt
96  unsigned n_intpt = integral_pt()->nweight();
97 
98  // Set the Vector to hold local coordinates
99  Vector<double> s(DIM);
100 
101  // Integers to hold the local equation and unknowns
102  int local_eqn = 0, local_unknown = 0;
103 
104  // Loop over the integration points
105  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
106  {
107  // Assign values of s
108  for (unsigned i = 0; i < DIM; i++) s[i] = integral_pt()->knot(ipt, i);
109 
110  // Get the integral weight
111  double w = integral_pt()->weight(ipt);
112 
113  // Call the derivatives of the shape and test functions
114  double J = dshape_and_dtest_eulerian_at_knot_lin_wave(
115  ipt, psi, dpsidx, test, dtestdx);
116 
117  // Premultiply the weights and the Jacobian
118  double W = w * J;
119 
120  // Allocate memory for local quantities and initialise to zero
121  double interpolated_u = 0.0;
122  double ddudt = 0.0;
123  Vector<double> interpolated_x(DIM, 0.0);
124  Vector<double> interpolated_dudx(DIM, 0.0);
125 
126  // Calculate function value and derivatives:
127  // Loop over nodes
128  for (unsigned l = 0; l < n_node; l++)
129  {
130  // Get the nodal value
131  double u_value = raw_nodal_value(l, u_nodal_index);
132  interpolated_u += u_value * psi(l);
133  ddudt += d2u_dt2_lin_wave(l) * psi(l);
134  // Loop over directions
135  for (unsigned j = 0; j < DIM; j++)
136  {
137  interpolated_x[j] += raw_nodal_position(l, j) * psi(l);
138  interpolated_dudx[j] += u_value * dpsidx(l, j);
139  }
140  }
141 
142 
143  // Get source function
144  //-------------------
145  double source;
146  get_source_lin_wave(time, ipt, interpolated_x, source);
147 
148  // Assemble residuals and Jacobian
149  //--------------------------------
150 
151  // Loop over the test functions
152  for (unsigned l = 0; l < n_node; l++)
153  {
154  local_eqn = nodal_local_eqn(l, u_nodal_index);
155  /*IF it's not a boundary condition*/
156  if (local_eqn >= 0)
157  {
158  // Add body force/source term and time derivative
159  residuals[local_eqn] += (ddudt + source) * test(l) * W;
160 
161  // Laplace operator
162  for (unsigned k = 0; k < DIM; k++)
163  {
164  residuals[local_eqn] += interpolated_dudx[k] * dtestdx(l, k) * W;
165  }
166 
167 
168  // Calculate the jacobian
169  //-----------------------
170  if (flag)
171  {
172  // Loop over the velocity shape functions again
173  for (unsigned l2 = 0; l2 < n_node; l2++)
174  {
175  local_unknown = nodal_local_eqn(l2, u_nodal_index);
176  // If at a non-zero degree of freedom add in the entry
177  if (local_unknown >= 0)
178  {
179  // Mass matrix
180  jacobian(local_eqn, local_unknown) +=
181  test(l) * psi(l2) *
182  node_pt(l2)->time_stepper_pt()->weight(2, 0) * W;
183 
184  // Laplace operator
185  for (unsigned i = 0; i < DIM; i++)
186  {
187  jacobian(local_eqn, local_unknown) +=
188  dpsidx(l2, i) * dtestdx(l, i) * W;
189  }
190  }
191  }
192  }
193  }
194  }
195 
196 
197  } // End of loop over integration points
198  }
199 
200 
201  //======================================================================
202  /// Self-test: Return 0 for OK
203  //======================================================================
204  template<unsigned DIM>
206  {
207  bool passed = true;
208 
209  // Check lower-level stuff
210  if (FiniteElement::self_test() != 0)
211  {
212  passed = false;
213  }
214 
215  // Return verdict
216  if (passed)
217  {
218  return 0;
219  }
220  else
221  {
222  return 1;
223  }
224  }
225 
226 
227  //======================================================================
228  /// Output function:
229  ///
230  /// x,y,u or x,y,z,u
231  ///
232  /// nplot points in each coordinate direction
233  //======================================================================
234  template<unsigned DIM>
235  void LinearWaveEquations<DIM>::output(std::ostream& outfile,
236  const unsigned& nplot)
237  {
238  // Vector of local coordinates
239  Vector<double> s(DIM);
240 
241  // Tecplot header info
242  outfile << tecplot_zone_string(nplot);
243 
244  // Loop over plot points
245  unsigned num_plot_points = nplot_points(nplot);
246  for (unsigned iplot = 0; iplot < num_plot_points; iplot++)
247  {
248  // Get local coordinates of plot point
249  get_s_plot(iplot, nplot, s);
250  for (unsigned i = 0; i < DIM; i++)
251  {
252  outfile << interpolated_x(s, i) << " ";
253  }
254  outfile << interpolated_u_lin_wave(s) << " ";
255  outfile << interpolated_du_dt_lin_wave(s) << " ";
256  outfile << interpolated_d2u_dt2_lin_wave(s) << std::endl;
257  }
258 
259  // Write tecplot footer (e.g. FE connectivity lists)
260  write_tecplot_zone_footer(outfile, nplot);
261  }
262 
263  //======================================================================
264  /// C-style output function:
265  ///
266  /// x,y,u or x,y,z,u
267  ///
268  /// nplot points in each coordinate direction
269  //======================================================================
270  template<unsigned DIM>
271  void LinearWaveEquations<DIM>::output(FILE* file_pt, const unsigned& nplot)
272  {
273  // Vector of local coordinates
274  Vector<double> s(DIM);
275 
276  // Tecplot header info
277  fprintf(file_pt, "%s", tecplot_zone_string(nplot).c_str());
278 
279  // Loop over plot points
280  unsigned num_plot_points = nplot_points(nplot);
281  for (unsigned iplot = 0; iplot < num_plot_points; iplot++)
282  {
283  // Get local coordinates of plot point
284  get_s_plot(iplot, nplot, s);
285 
286  for (unsigned i = 0; i < DIM; i++)
287  {
288  // outfile << interpolated_x(s,i) << " ";
289  fprintf(file_pt, "%g ", interpolated_x(s, i));
290  }
291  // outfile << interpolated_u(s) << std::endl;
292  fprintf(file_pt, "%g \n", interpolated_u_lin_wave(s));
293  }
294 
295  // Write tecplot footer (e.g. FE connectivity lists)
296  write_tecplot_zone_footer(file_pt, nplot);
297  }
298 
299 
300  //======================================================================
301  /// Output exact solution
302  ///
303  /// Solution is provided via function pointer.
304  /// Plot at a given number of plot points.
305  ///
306  /// x,y,u_exact or x,y,z,u_exact
307  //======================================================================
308  template<unsigned DIM>
310  std::ostream& outfile,
311  const unsigned& nplot,
313  {
314  // Vector of local coordinates
315  Vector<double> s(DIM);
316 
317  // Vector for coordintes
318  Vector<double> x(DIM);
319 
320  // Tecplot header info
321  outfile << tecplot_zone_string(nplot);
322 
323  // Exact solution Vector (value and first and second time derivs)
324  Vector<double> exact_soln(3);
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 x position as Vector
334  interpolated_x(s, x);
335 
336  // Get exact solution at this point
337  (*exact_soln_pt)(x, exact_soln);
338 
339  // Output x,y,...,u_exact
340  for (unsigned i = 0; i < DIM; i++)
341  {
342  outfile << x[i] << " ";
343  }
344  outfile << exact_soln[0] << std::endl;
345  }
346 
347  // Write tecplot footer (e.g. FE connectivity lists)
348  write_tecplot_zone_footer(outfile, nplot);
349  }
350 
351 
352  //======================================================================
353  /// Output exact solution at time t
354  ///
355  /// Solution is provided via function pointer.
356  /// Plot at a given number of plot points.
357  ///
358  /// x,y,u_exact or x,y,z,u_exact
359  //======================================================================
360  template<unsigned DIM>
362  std::ostream& outfile,
363  const unsigned& nplot,
364  const double& time,
366  {
367  // Vector of local coordinates
368  Vector<double> s(DIM);
369 
370  // Vector for coordintes
371  Vector<double> x(DIM);
372 
373  // Tecplot header info
374  outfile << tecplot_zone_string(nplot);
375 
376  // Exact solution Vector u, dudt, d2udt2
377  Vector<double> exact_soln(3);
378 
379  // Loop over plot points
380  unsigned num_plot_points = nplot_points(nplot);
381  for (unsigned iplot = 0; iplot < num_plot_points; iplot++)
382  {
383  // Get local coordinates of plot point
384  get_s_plot(iplot, nplot, s);
385 
386  // Get x position as Vector
387  interpolated_x(s, x);
388 
389  // Get exact solution at this point
390  (*exact_soln_pt)(time, x, exact_soln);
391 
392  // Output x,y,...,u_exact
393  for (unsigned i = 0; i < DIM; i++)
394  {
395  outfile << x[i] << " ";
396  }
397  outfile << exact_soln[0] << " " << exact_soln[1] << " " << exact_soln[2]
398  << " " << std::endl;
399  }
400 
401  // Write tecplot footer (e.g. FE connectivity lists)
402  write_tecplot_zone_footer(outfile, nplot);
403  }
404 
405 
406  //======================================================================
407  /// Validate against exact solution
408  ///
409  /// Solution is provided via function pointer.
410  /// Plot error at a given number of plot points.
411  ///
412  //======================================================================
413  template<unsigned DIM>
415  std::ostream& outfile,
417  double& error,
418  double& norm)
419  {
420  // Initialise
421  error = 0.0;
422  norm = 0.0;
423 
424  // Vector of local coordinates
425  Vector<double> s(DIM);
426 
427  // Vector for coordintes
428  Vector<double> x(DIM);
429 
430 
431  // Find out how many nodes there are in the element
432  unsigned n_node = nnode();
433 
434  Shape psi(n_node);
435 
436  // Set the value of n_intpt
437  unsigned n_intpt = integral_pt()->nweight();
438 
439  // Tecplot header info
440  outfile << "ZONE" << std::endl;
441 
442  // Exact solution Vector (value, and first and second time derivs)
443  Vector<double> exact_soln(3);
444 
445  // Loop over the integration points
446  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
447  {
448  // Assign values of s
449  for (unsigned i = 0; i < DIM; i++)
450  {
451  s[i] = integral_pt()->knot(ipt, i);
452  }
453 
454  // Get the integral weight
455  double w = integral_pt()->weight(ipt);
456 
457  // Get jacobian of mapping
458  double J = J_eulerian(s);
459 
460  // Premultiply the weights and the Jacobian
461  double W = w * J;
462 
463  // Get x position as Vector
464  interpolated_x(s, x);
465 
466  // Get FE function value
467  double u_fe = interpolated_u_lin_wave(s);
468 
469  // Get exact solution at this point
470  (*exact_soln_pt)(x, exact_soln);
471 
472  // Output x,y,...,error
473  for (unsigned i = 0; i < DIM; i++)
474  {
475  outfile << x[i] << " ";
476  }
477  outfile << exact_soln[0] << " " << exact_soln[0] - u_fe << std::endl;
478 
479  // Add to error and norm
480  norm += exact_soln[0] * exact_soln[0] * W;
481  error += (exact_soln[0] - u_fe) * (exact_soln[0] - u_fe) * W;
482  }
483  }
484 
485 
486  //======================================================================
487  /// Validate against exact solution at time t.
488  ///
489  /// Solution is provided via function pointer.
490  /// Plot error at a given number of plot points.
491  ///
492  //======================================================================
493  template<unsigned DIM>
495  std::ostream& outfile,
497  const double& time,
498  double& error,
499  double& norm)
500 
501  {
502  // Initialise
503  error = 0.0;
504  norm = 0.0;
505 
506  // Vector of local coordinates
507  Vector<double> s(DIM);
508 
509  // Vector for coordintes
510  Vector<double> x(DIM);
511 
512  // Find out how many nodes there are in the element
513  unsigned n_node = nnode();
514 
515  Shape psi(n_node);
516 
517  // Set the value of n_intpt
518  unsigned n_intpt = integral_pt()->nweight();
519 
520  // Tecplot header info
521  outfile << "ZONE" << std::endl;
522 
523  // Exact solution Vector (value, and first and second time derivs)
524  Vector<double> exact_soln(3);
525 
526  // Loop over the integration points
527  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
528  {
529  // Assign values of s
530  for (unsigned i = 0; i < DIM; i++)
531  {
532  s[i] = integral_pt()->knot(ipt, i);
533  }
534 
535  // Get the integral weight
536  double w = integral_pt()->weight(ipt);
537 
538  // Get jacobian of mapping
539  double J = J_eulerian(s);
540 
541  // Premultiply the weights and the Jacobian
542  double W = w * J;
543 
544  // Get x position as Vector
545  interpolated_x(s, x);
546 
547  // Get FE function value
548  double u_fe = interpolated_u_lin_wave(s);
549 
550  // Get exact solution at this point
551  (*exact_soln_pt)(time, x, exact_soln);
552 
553  // Output x,y,...,error
554  for (unsigned i = 0; i < DIM; i++)
555  {
556  outfile << x[i] << " ";
557  }
558  outfile << exact_soln[0] << " " << exact_soln[0] - u_fe << std::endl;
559 
560  // Add to error and norm
561  norm += exact_soln[0] * exact_soln[0] * W;
562  error += (exact_soln[0] - u_fe) * (exact_soln[0] - u_fe) * W;
563  }
564  }
565 
566 
567  //====================================================================
568  // Force build of templates
569  //====================================================================
570  template class QLinearWaveElement<1, 2>;
571  template class QLinearWaveElement<1, 3>;
572  template class QLinearWaveElement<1, 4>;
573 
574  template class QLinearWaveElement<2, 2>;
575  template class QLinearWaveElement<2, 3>;
576  template class QLinearWaveElement<2, 4>;
577 
578  template class QLinearWaveElement<3, 2>;
579  template class QLinearWaveElement<3, 3>;
580  template class QLinearWaveElement<3, 4>;
581 
582 
583 } // 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
void(* SteadyExactSolutionFctPt)(const Vector< double > &, Vector< double > &)
Function pointer for function that computes vector-valued steady "exact solution" as .
Definition: elements.h:1759
void(* UnsteadyExactSolutionFctPt)(const double &, const Vector< double > &, Vector< double > &)
Function pointer for function that computes Vector-valued time-dependent function as .
Definition: elements.h:1765
virtual unsigned self_test()
Self-test: Check inversion of element & do self-test for GeneralisedElement. Return 0 if OK.
Definition: elements.cc:4440
unsigned self_test()
Self-test: Return 0 for OK.
void output_fct(std::ostream &outfile, const unsigned &nplot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
Output exact soln: x,y,u_exact or x,y,z,u_exact at nplot^DIM 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.
void output(std::ostream &outfile)
Output with default number of plot points.
virtual void fill_in_generic_residual_contribution_lin_wave(Vector< double > &residuals, DenseMatrix< double > &jacobian, unsigned flag)
Compute element residual Vector only (if flag=and/or element Jacobian matrix.
//////////////////////////////////////////////////////////////////////// ////////////////////////////...
A Class for shape functions. In simple cases, the shape functions have only one index that can be tho...
Definition: shape.h:76
//////////////////////////////////////////////////////////////////// ////////////////////////////////...