pml_fourier_decomposed_helmholtz_elements.h
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// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 //Header file for Fourier-decomposed Helmholtz elements
31 #ifndef OOMPH_PML_FOURIER_DECOMPOSED_HELMHOLTZ_ELEMENTS_HEADER
32 #define OOMPH_PML_FOURIER_DECOMPOSED_HELMHOLTZ_ELEMENTS_HEADER
33 
34 
35 // Config header generated by autoconfig
36 #ifdef HAVE_CONFIG_H
37  #include <oomph-lib-config.h>
38 #endif
39 
40 #include "math.h"
41 #include <complex>
42 
43 
44 //OOMPH-LIB headers
45 #include "../generic/projection.h"
46 #include "../generic/nodes.h"
47 #include "../generic/Qelements.h"
48 #include "../generic/oomph_utilities.h"
49 #include "../generic/pml_meshes.h"
50 #include "../generic/projection.h"
51 #include "../generic/oomph_definitions.h"
52 
53 
54 namespace oomph
55 {
56 
57 
58 //========================================================================
59 /// Helper namespace for functions required for Helmholtz computations
60 //========================================================================
61  namespace Legendre_functions_helper
62  {
63 
64  /// Factorial
65  extern double factorial(const unsigned& l);
66 
67  /// Legendre polynomials depending on one parameter
68  extern double plgndr1(const unsigned& n, const double& x);
69 
70  /// Legendre polynomials depending on two parameters
71  extern double plgndr2(const unsigned& l, const unsigned& m, const double& x);
72 
73  } // end namespace
74 
75 
76 ////////////////////////////////////////////////////////////////////////
77 ////////////////////////////////////////////////////////////////////////
78 ////////////////////////////////////////////////////////////////////////
79 
80 
81 
82 //=============================================================
83 /// A class for all isoparametric elements that solve the
84 /// Helmholtz equations with pml capabilities.
85 /// in Fourier decomposed form (cylindrical polars):
86 /// \f[
87 /// U(r,\varphi,z) = \Re( u^{(n)}(r,z) \exp(-i n \varphi))
88 /// \f]
89 /// We are solving for \f$ u^{(n)}(r,z)\f$ for given parameters
90 /// \f$ k^2 \f$ and \f$ n \f$ .
91 /// This contains the generic maths. Shape functions, geometric
92 /// mapping etc. must get implemented in derived class.
93 //=============================================================
95  public virtual FiniteElement
96  {
97 
98  public:
99 
100  /// \short Function pointer to source function fct(x,f(x)) --
101  /// x is a Vector!
102  typedef void (*PMLFourierDecomposedHelmholtzSourceFctPt)(
103  const Vector<double>& x,
104  std::complex<double>& f);
105 
106  /// Constructor
108  K_squared_pt(0), N_pml_fourier_pt(0)
109  {
110  // Provide pointer to static data (Save memory)
112  }
113 
114 
115  /// Broken copy constructor
118  {
119  BrokenCopy::broken_copy("PMLFourierDecomposedHelmholtzEquationsBase");
120  }
121 
122  /// Broken assignment operator
123 //Commented out broken assignment operator because this can lead to a conflict warning
124 //when used in the virtual inheritence hierarchy. Essentially the compiler doesn't
125 //realise that two separate implementations of the broken function are the same and so,
126 //quite rightly, it shouts.
127  /*void operator=(const PMLFourierDecomposedHelmholtzEquations&)
128  {
129  BrokenCopy::broken_assign
130  ("PMLFourierDecomposedHelmholtzEquations");
131  }*/
132 
133  /// \short Return the index at which the unknown value
134  /// is stored: Real/imag part of index contains (real) index of
135  /// real/imag part.
136  virtual inline std::complex<unsigned>
138  const
139  {return std::complex<unsigned>(0,1);}
140 
141 
142  /// Get pointer to frequency
143  double*& k_squared_pt()
144  {
145  return K_squared_pt;
146  }
147 
148 
149  /// Get k squared
150  double k_squared() const
151  {
152  #ifdef PARANOID
153  if (K_squared_pt==0)
154  {
155  throw OomphLibError(
156  "Please set pointer to k_squared using access fct to pointer!",
157  OOMPH_CURRENT_FUNCTION,
158  OOMPH_EXCEPTION_LOCATION);
159  }
160  #endif
161  return *K_squared_pt;
162  }
163 
164  /// Get pointer to complex shift
165  double*& alpha_pt()
166  {
167  return Alpha_pt;
168  }
169 
170 
171  /// Get complex shift
172  double alpha()
173  {
174  return *Alpha_pt;
175  }
176 
177  /// Get pointer to Fourier wavenumber
179  {
180  return N_pml_fourier_pt;
181  }
182 
183  /// Get the Fourier wavenumber
185  {
186  if (N_pml_fourier_pt==0)
187  {
188  return 0;
189  }
190  else
191  {
192  return *N_pml_fourier_pt;
193  }
194  }
195 
196 
197  /// Output with default number of plot points
198  void output(std::ostream &outfile)
199  {
200  const unsigned n_plot=5;
201  output(outfile,n_plot);
202  }
203 
204  /// \short Output FE representation of soln: x,y,u_re,u_im or
205  /// x,y,z,u_re,u_im at n_plot^2 plot points
206  void output(std::ostream &outfile, const unsigned &n_plot);
207 
208  /// \short Output function for real part of full time-dependent solution
209  /// u = Re( (u_r +i u_i) exp(-i omega t)
210  /// at phase angle omega t = phi.
211  /// r,z,u at n_plot plot points in each coordinate
212  /// direction
213  void output_real(std::ostream &outfile, const double& phi,
214  const unsigned &n_plot);
215 
216  /// C_style output with default number of plot points
217  void output(FILE* file_pt)
218  {
219  const unsigned n_plot=5;
220  output(file_pt,n_plot);
221  }
222 
223  /// \short C-style output FE representation of soln: r,z,u_re,u_im or
224  /// at n_plot^2 plot points
225  void output(FILE* file_pt, const unsigned &n_plot);
226 
227  /// Output exact soln: r,z,u_re_exact,u_im_exact
228  /// at n_plot^2 plot points
229  void output_fct(std::ostream &outfile, const unsigned &n_plot,
231 
232  /// \short Output exact soln: (dummy time-dependent version to
233  /// keep intel compiler happy)
234  virtual void output_fct(std::ostream &outfile, const unsigned &n_plot,
235  const double& time,
237  exact_soln_pt)
238  {
239  throw OomphLibError(
240  "There is no time-dependent output_fct() for PMLFourierDecomposedHelmholtz elements ",
241  OOMPH_CURRENT_FUNCTION,
242  OOMPH_EXCEPTION_LOCATION);
243  }
244 
245 
246  /// \short Output function for real part of full time-dependent fct
247  /// u = Re( (u_r +i u_i) exp(-i omega t)
248  /// at phase angle omega t = phi.
249  /// r,z,u at n_plot plot points in each coordinate
250  /// direction
251  void output_real_fct(std::ostream &outfile,
252  const double& phi,
253  const unsigned &n_plot,
255 
256 
257  /// Get error against and norm of exact solution
258  void compute_error(std::ostream &outfile,
260  double& error, double& norm);
261 
262 
263  /// Dummy, time dependent error checker
264  void compute_error(std::ostream &outfile,
266  const double& time, double& error, double& norm)
267  {
268  throw OomphLibError(
269  "There is no time-dependent compute_error() for PMLFourierDecomposedHelmholtz elements",
270  OOMPH_CURRENT_FUNCTION,
271  OOMPH_EXCEPTION_LOCATION);
272  }
273 
274  /// Compute norm of fe solution
275  void compute_norm(double& norm);
276 
277 
278  /// Access function: Pointer to source function
279  PMLFourierDecomposedHelmholtzSourceFctPt& source_fct_pt()
280  {return Source_fct_pt;}
281 
282 
283  /// Access function: Pointer to source function. Const version
284  PMLFourierDecomposedHelmholtzSourceFctPt source_fct_pt() const
285  {return Source_fct_pt;}
286 
287 
288  /// Get source term at (Eulerian) position x. This function is
289  /// virtual to allow overloading in multi-physics problems where
290  /// the strength of the source function might be determined by
291  /// another system of equations.
293  const unsigned& ipt,
294  const Vector<double>& x,
295  std::complex<double>& source) const
296  {
297  //If no source function has been set, return zero
298  if(Source_fct_pt==0)
299  {
300  source = std::complex<double>(0.0,0.0);
301  }
302  else
303  {
304  // Get source strength
305  (*Source_fct_pt)(x,source);
306  }
307  }
308 
309  /// \short Pure virtual function in which we specify the
310  /// values to be pinned (and set to zero) on the outer edge of
311  /// the pml layer. All of them! Vector is resized internally.
313  values_to_pin)
314  {
315  values_to_pin.resize(2);
316  for (unsigned j=0;j<2;j++)
317  {
318  values_to_pin[j]=j;
319  }
320  }
321 
322 
323  /// Get flux: flux[i] = du/dx_i for real and imag part
324  void get_flux(const Vector<double>& s,
325  Vector<std::complex <double> >& flux) const
326  {
327  //Find out how many nodes there are in the element
328  const unsigned n_node = nnode();
329 
330  //Set up memory for the shape and test functions
331  Shape psi(n_node);
332  DShape dpsidx(n_node,2);
333 
334  //Call the derivatives of the shape and test functions
335  dshape_eulerian(s,psi,dpsidx);
336 
337  //Initialise to zero
338  const std::complex<double> zero(0.0,0.0);
339  for(unsigned j=0;j<2;j++)
340  {
341  flux[j] = zero;
342  }
343 
344  // Loop over nodes
345  for(unsigned l=0;l<n_node;l++)
346  {
347  //Cache the complex value of the unknown
348  const std::complex<double> u_value(
349  this->nodal_value
350  (l,u_index_pml_fourier_decomposed_helmholtz().real()),
351  this->nodal_value
352  (l,u_index_pml_fourier_decomposed_helmholtz().imag()));
353 
354  //Loop over derivative directions
355  for(unsigned j=0;j<2;j++)
356  {
357  flux[j] += u_value*dpsidx(l,j);
358  }
359  }
360  }
361 
362  /// \short Return FE representation of function value u(s)
363  /// at local coordinate s
364  inline std::complex<double>
366  const Vector<double> &s) const
367  {
368  //Find number of nodes
369  const unsigned n_node = nnode();
370 
371  //Local shape function
372  Shape psi(n_node);
373 
374  //Find values of shape function
375  shape(s,psi);
376 
377  //Initialise value of u
378  std::complex<double> interpolated_u(0.0,0.0);
379 
380  //Get the index at which the helmholtz unknown is stored
381  const unsigned u_nodal_index_real =
382  u_index_pml_fourier_decomposed_helmholtz().real();
383  const unsigned u_nodal_index_imag =
384  u_index_pml_fourier_decomposed_helmholtz().imag();
385 
386  //Loop over the local nodes and sum
387  for(unsigned l=0;l<n_node;l++)
388  {
389  //Make a temporary complex number from the stored data
390  const std::complex<double> u_value(
391  this->nodal_value(l,u_nodal_index_real),
392  this->nodal_value(l,u_nodal_index_imag));
393  //Add to the interpolated value
394  interpolated_u += u_value*psi[l];
395  }
396  return interpolated_u;
397  }
398 
399 
400  /// \short Self-test: Return 0 for OK
401  unsigned self_test();
402 
403 
404 protected:
405 
406 
407  /// \short Shape/test functions and derivs w.r.t. to global coords at
408  /// local coord. s; return Jacobian of mapping
409  virtual double
410  dshape_and_dtest_eulerian_pml_fourier_decomposed_helmholtz(
411  const Vector<double> &s,
412  Shape &psi,
413  DShape &dpsidx, Shape &test,
414  DShape &dtestdx) const=0;
415 
416 
417  /// \short Shape/test functions and derivs w.r.t. to global coords at
418  /// integration point ipt; return Jacobian of mapping
419  virtual double
420  dshape_and_dtest_eulerian_at_knot_pml_fourier_decomposed_helmholtz(
421  const unsigned &ipt,
422  Shape &psi,
423  DShape &dpsidx,
424  Shape &test,
425  DShape &dtestdx) const=0;
426 
427  /// Pointer to source function:
428  PMLFourierDecomposedHelmholtzSourceFctPt Source_fct_pt;
429 
430  /// Pointer to k^2 (wavenumber squared)
431  double* K_squared_pt;
432 
433  /// Pointer to wavenumber complex shift
434  double *Alpha_pt;
435 
436  /// Static default value for the physical constants (initialised to zero)
438 
439  /// Pointer to Fourier wave number
441 
442  };
443 
444 
445 
446 // Create base class without PML elements, then create PMLFourier.... with element
447 template <class PML_ELEMENT>
449  public virtual FiniteElement,
450  public virtual PML_ELEMENT,
452 {
453 
454  public:
455  /// Constructor
457  {
458  // Provide pointer to static method (Save memory)
459  this->Pml_mapping_pt =
461  }
462 
463  /// Wavenumber used in PML
464  double wavenumber() const { return std::sqrt(this->k_squared()); }
465 
466  ///
468  values_to_pin)
469  {
472  }
473 
474  /// Add the element's contribution to its residual vector (wrapper)
476  {
477  //Call the generic residuals function with flag set to 0
478  //using a dummy matrix argument
479  fill_in_generic_residual_contribution_pml_fourier_decomposed_helmholtz(
481  }
482 
483  /// \short Add the element's contribution to its residual vector and
484  /// element Jacobian matrix (wrapper)
486  DenseMatrix<double> &jacobian)
487  {
488  //Call the generic routine with the flag set to 1
489  fill_in_generic_residual_contribution_pml_fourier_decomposed_helmholtz(
490  residuals,jacobian,1);
491  }
492 
493  protected:
494 
495  /// \short Compute element residual Vector only (if flag=and/or element
496  /// Jacobian matrix
497  virtual void
498  fill_in_generic_residual_contribution_pml_fourier_decomposed_helmholtz(
499  Vector<double> &residuals, DenseMatrix<double> &jacobian,
500  const unsigned& flag);
501 
502 
503  /// Static so that the class doesn't need to instantiate a new default
504  /// everytime it uses it
506 };
507 
508 ///////////////////////////////////////////////////////////////////////////
509 ///////////////////////////////////////////////////////////////////////////
510 ///////////////////////////////////////////////////////////////////////////
511 
512 
513 
514 //======================================================================
515 /// QPMLFourierDecomposedHelmholtzElement elements are
516 /// linear/quadrilateral/brick-shaped PMLFourierDecomposedHelmholtz
517 /// elements with isoparametric interpolation for the function.
518 //======================================================================
519  template <unsigned NNODE_1D, class PML_ELEMENT>
521  public virtual QElement<2,NNODE_1D>,
522  public virtual PMLFourierDecomposedHelmholtzEquations<PML_ELEMENT>
523  {
524 
525  private:
526 
527  /// \short Static int that holds the number of variables at
528  /// nodes: always the same
529  static const unsigned Initial_Nvalue;
530 
531  public:
532 
533 
534  ///\short Constructor: Call constructors for QElement and
535  /// PMLFourierDecomposedHelmholtz equations
537  QElement<2,NNODE_1D>(), PMLFourierDecomposedHelmholtzEquations<PML_ELEMENT>()
538  {}
539 
540  /// Broken copy constructor
543  {
544  BrokenCopy::broken_copy("QPMLFourierDecomposedHelmholtzElement");
545  }
546 
547  /// Broken assignment operator
548  /*void operator=(const
549  QPMLFourierDecomposedHelmholtzElement<NNODE_1D>&)
550  {
551  BrokenCopy::broken_assign
552  ("QPMLFourierDecomposedHelmholtzElement");
553  }*/
554 
555 
556  /// \short Required # of `values' (pinned or dofs)
557  /// at node n
558  inline unsigned required_nvalue(const unsigned &n) const
559  {return Initial_Nvalue;}
560 
561  /// \short Output function: r,z,u
562  void output(std::ostream &outfile)
564 
565  /// \short Output function:
566  /// r,z,u at n_plot^2 plot points
567  void output(std::ostream &outfile, const unsigned &n_plot)
569 
570  /// \short Output function for real part of full time-dependent solution
571  /// u = Re( (u_r +i u_i) exp(-i omega t)
572  /// at phase angle omega t = phi.
573  /// r,z,u at n_plot plot points in each coordinate
574  /// direction
575  void output_real(std::ostream &outfile, const double& phi,
576  const unsigned &n_plot)
578  (outfile,phi,n_plot);}
579 
580  /// \short C-style output function: r,z,u
581  void output(FILE* file_pt)
583 
584  /// \short C-style output function:
585  /// r,z,u at n_plot^2 plot points
586  void output(FILE* file_pt, const unsigned &n_plot)
588 
589  /// \short Output function for an exact solution:
590  /// r,z,u_exact at n_plot^2 plot points
591  void output_fct(std::ostream &outfile, const unsigned &n_plot,
593  {
595  output_fct(outfile, n_plot, exact_soln_pt);
596  }
597 
598  /// \short Output function for real part of full time-dependent fct
599  /// u = Re( (u_r +i u_i) exp(-i omega t)
600  /// at phase angle omega t = phi.
601  /// r,z,u at n_plot plot points in each coordinate
602  /// direction
603  void output_real_fct(std::ostream &outfile,
604  const double& phi,
605  const unsigned &n_plot,
607  {
609  output_real_fct(outfile, phi, n_plot, exact_soln_pt);
610  }
611 
612 
613  /// \short Output function for a time-dependent exact solution.
614  /// r,z,u_exact at n_plot^2 plot points
615  /// (Calls the steady version)
616  void output_fct(std::ostream &outfile, const unsigned &n_plot,
617  const double& time,
619  {
621  (outfile,n_plot,time,exact_soln_pt);
622  }
623 
624  protected:
625 
626  /// Shape, test functions & derivs. w.r.t. to global coords.
627  /// Return Jacobian.
628  inline double
629  dshape_and_dtest_eulerian_pml_fourier_decomposed_helmholtz(
630  const Vector<double> &s, Shape &psi, DShape &dpsidx,
631  Shape &test, DShape &dtestdx) const;
632 
633 
634  /// \short Shape, test functions & derivs. w.r.t. to global coords. at
635  /// integration point ipt. Return Jacobian.
636  inline double
637  dshape_and_dtest_eulerian_at_knot_pml_fourier_decomposed_helmholtz(
638  const unsigned& ipt,
639  Shape &psi,
640  DShape &dpsidx,
641  Shape &test,
642  DShape &dtestdx) const;
643 
644  };
645 
646 
647 
648 
649 //Inline functions:
650 
651 
652 //======================================================================
653 /// Define the shape functions and test functions and derivatives
654 /// w.r.t. global coordinates and return Jacobian of mapping.
655 ///
656 /// Galerkin: Test functions = shape functions
657 //======================================================================
658  template<unsigned NNODE_1D, class PML_ELEMENT>
661  const Vector<double> &s,
662  Shape &psi,
663  DShape &dpsidx,
664  Shape &test,
665  DShape &dtestdx) const
666  {
667  //Call the geometrical shape functions and derivatives
668  const double J = this->dshape_eulerian(s,psi,dpsidx);
669 
670  //Set the test functions equal to the shape functions
671  test = psi;
672  dtestdx= dpsidx;
673 
674  //Return the jacobian
675  return J;
676  }
677 
678 
679 
680 
681 //======================================================================
682 /// Define the shape functions and test functions and derivatives
683 /// w.r.t. global coordinates and return Jacobian of mapping.
684 ///
685 /// Galerkin: Test functions = shape functions
686 //======================================================================
687  template<unsigned NNODE_1D, class PML_ELEMENT>
690  const unsigned &ipt,
691  Shape &psi,
692  DShape &dpsidx,
693  Shape &test,
694  DShape &dtestdx) const
695  {
696  //Call the geometrical shape functions and derivatives
697  const double J = this->dshape_eulerian_at_knot(ipt,psi,dpsidx);
698 
699  //Set the pointers of the test functions
700  test = psi;
701  dtestdx = dpsidx;
702 
703  //Return the jacobian
704  return J;
705  }
706 
707 ////////////////////////////////////////////////////////////////////////
708 ////////////////////////////////////////////////////////////////////////
709 ////////////////////////////////////////////////////////////////////////
710 
711 
712 
713 //=======================================================================
714 /// Face geometry for the QPMLFourierDecomposedHelmholtzElement
715 /// elements:
716 /// The spatial dimension of the face elements is one lower than that of the
717 /// bulk element but they have the same number of points
718 /// along their 1D edges.
719 //=======================================================================
720  template<unsigned NNODE_1D, class PML_ELEMENT>
722  public virtual QElement<1,NNODE_1D>
723  {
724 
725  public:
726 
727  /// \short Constructor: Call the constructor for the
728  /// appropriate lower-dimensional QElement
729  FaceGeometry() : QElement<1,NNODE_1D>() {}
730  };
731 
732 
733 ////////////////////////////////////////////////////////////////////////
734 ////////////////////////////////////////////////////////////////////////
735 ////////////////////////////////////////////////////////////////////////
736 
737 
738 
739 //==========================================================
740 /// Fourier decomposed Helmholtz upgraded to become projectable
741 //==========================================================
742  template<class FOURIER_DECOMPOSED_HELMHOLTZ_ELEMENT>
744  public virtual ProjectableElement<FOURIER_DECOMPOSED_HELMHOLTZ_ELEMENT>
745  {
746 
747  public:
748 
749 
750  /// \short Constructor [this was only required explicitly
751  /// from gcc 4.5.2 onwards...]
753 
754  /// \short Specify the values associated with field fld.
755  /// The information is returned in a vector of pairs which comprise
756  /// the Data object and the value within it, that correspond to field fld.
758  {
759 
760 #ifdef PARANOID
761  if (fld>1)
762  {
763  std::stringstream error_stream;
764  error_stream
765  << "Fourier decomposed Helmholtz elements only store 2 fields so fld = "
766  << fld << " is illegal \n";
767  throw OomphLibError(
768  error_stream.str(),
769  OOMPH_CURRENT_FUNCTION,
770  OOMPH_EXCEPTION_LOCATION);
771  }
772 #endif
773 
774  // Create the vector
775  unsigned nnod=this->nnode();
776  Vector<std::pair<Data*,unsigned> > data_values(nnod);
777 
778  // Loop over all nodes
779  for (unsigned j=0;j<nnod;j++)
780  {
781  // Add the data value associated field: The node itself
782  data_values[j]=std::make_pair(this->node_pt(j),fld);
783  }
784 
785  // Return the vector
786  return data_values;
787  }
788 
789  /// \short Number of fields to be projected: 2 (real and imag part)
791  {
792  return 2;
793  }
794 
795  /// \short Number of history values to be stored for fld-th field.
796  /// (Note: count includes current value!)
797  unsigned nhistory_values_for_projection(const unsigned &fld)
798  {
799 #ifdef PARANOID
800  if (fld>1)
801  {
802  std::stringstream error_stream;
803  error_stream
804  << "Helmholtz elements only store two fields so fld = "
805  << fld << " is illegal\n";
806  throw OomphLibError(
807  error_stream.str(),
808  OOMPH_CURRENT_FUNCTION,
809  OOMPH_EXCEPTION_LOCATION);
810  }
811 #endif
812  return this->node_pt(0)->ntstorage();
813  }
814 
815  ///\short Number of positional history values
816  /// (Note: count includes current value!)
818  {
819  return this->node_pt(0)->position_time_stepper_pt()->ntstorage();
820  }
821 
822  /// \short Return Jacobian of mapping and shape functions of field fld
823  /// at local coordinate s
824  double jacobian_and_shape_of_field(const unsigned &fld,
825  const Vector<double> &s,
826  Shape &psi)
827  {
828 #ifdef PARANOID
829  if (fld>1)
830  {
831  std::stringstream error_stream;
832  error_stream
833  << "Helmholtz elements only store two fields so fld = "
834  << fld << " is illegal.\n";
835  throw OomphLibError(
836  error_stream.str(),
837  OOMPH_CURRENT_FUNCTION,
838  OOMPH_EXCEPTION_LOCATION);
839  }
840 #endif
841  unsigned n_dim=this->dim();
842  unsigned n_node=this->nnode();
843  Shape test(n_node);
844  DShape dpsidx(n_node,n_dim), dtestdx(n_node,n_dim);
845  double J=this->
846  dshape_and_dtest_eulerian_pml_fourier_decomposed_helmholtz(
847  s,psi,dpsidx,
848  test,dtestdx);
849  return J;
850  }
851 
852 
853 
854  /// \short Return interpolated field fld at local coordinate s, at time level
855  /// t (t=0: present; t>0: history values)
856  double get_field(const unsigned &t,
857  const unsigned &fld,
858  const Vector<double>& s)
859  {
860 #ifdef PARANOID
861  if (fld>1)
862  {
863  std::stringstream error_stream;
864  error_stream
865  << "Helmholtz elements only store two fields so fld = "
866  << fld << " is illegal\n";
867  throw OomphLibError(
868  error_stream.str(),
869  OOMPH_CURRENT_FUNCTION,
870  OOMPH_EXCEPTION_LOCATION);
871  }
872 #endif
873  //Find the index at which the variable is stored
874  std::complex<unsigned> complex_u_nodal_index =
875  this->u_index_pml_fourier_decomposed_helmholtz();
876  unsigned u_nodal_index = 0;
877  if (fld==0)
878  {
879  u_nodal_index = complex_u_nodal_index.real();
880  }
881  else
882  {
883  u_nodal_index = complex_u_nodal_index.imag();
884  }
885 
886 
887  //Local shape function
888  unsigned n_node=this->nnode();
889  Shape psi(n_node);
890 
891  //Find values of shape function
892  this->shape(s,psi);
893 
894  //Initialise value of u
895  double interpolated_u = 0.0;
896 
897  //Sum over the local nodes
898  for(unsigned l=0;l<n_node;l++)
899  {
900  interpolated_u += this->nodal_value(t,l,u_nodal_index)*psi[l];
901  }
902  return interpolated_u;
903  }
904 
905 
906 
907 
908  ///Return number of values in field fld: One per node
909  unsigned nvalue_of_field(const unsigned &fld)
910  {
911 #ifdef PARANOID
912  if (fld>1)
913  {
914  std::stringstream error_stream;
915  error_stream
916  << "Helmholtz elements only store two fields so fld = "
917  << fld << " is illegal\n";
918  throw OomphLibError(
919  error_stream.str(),
920  OOMPH_CURRENT_FUNCTION,
921  OOMPH_EXCEPTION_LOCATION);
922  }
923 #endif
924  return this->nnode();
925  }
926 
927 
928  ///Return local equation number of value j in field fld.
929  int local_equation(const unsigned &fld,
930  const unsigned &j)
931  {
932 #ifdef PARANOID
933  if (fld>1)
934  {
935  std::stringstream error_stream;
936  error_stream
937  << "Helmholtz elements only store two fields so fld = "
938  << fld << " is illegal\n";
939  throw OomphLibError(
940  error_stream.str(),
941  OOMPH_CURRENT_FUNCTION,
942  OOMPH_EXCEPTION_LOCATION);
943  }
944 #endif
945  std::complex<unsigned> complex_u_nodal_index =
946  this->u_index_pml_fourier_decomposed_helmholtz();
947  unsigned u_nodal_index = 0;
948  if (fld==0)
949  {
950  u_nodal_index = complex_u_nodal_index.real();
951  }
952  else
953  {
954  u_nodal_index = complex_u_nodal_index.imag();
955  }
956  return this->nodal_local_eqn(j,u_nodal_index);
957  }
958 
959 
960 
961 
962  /// \short Output FE representation of soln: x,y,u or x,y,z,u at
963  /// n_plot^DIM plot points
964  void output(std::ostream &outfile, const unsigned &nplot)
965  {
967  }
968 
969 
970  };
971 
972 
973 //=======================================================================
974 /// Face geometry for element is the same as that for the underlying
975 /// wrapped element
976 //=======================================================================
977  template<class ELEMENT>
980  : public virtual FaceGeometry<ELEMENT>
981  {
982  public:
983  FaceGeometry() : FaceGeometry<ELEMENT>() {}
984  };
985 
986 
987 //=======================================================================
988 /// Face geometry of the Face Geometry for element is the same as
989 /// that for the underlying wrapped element
990 //=======================================================================
991  template<class ELEMENT>
994  : public virtual FaceGeometry<FaceGeometry<ELEMENT> >
995  {
996  public:
998  };
999 
1000 
1001 
1002 ////////////////////////////////////////////////////////////////////////
1003 ////////////////////////////////////////////////////////////////////////
1004 ////////////////////////////////////////////////////////////////////////
1005 
1006 //=======================================================================
1007 /// Policy class defining the elements to be used in the actual
1008 /// PML layers. Same!
1009 //=======================================================================
1010  template<unsigned NNODE_1D, class PML_ELEMENT>
1012  QPMLFourierDecomposedHelmholtzElement<NNODE_1D,PML_ELEMENT> > :
1013  public virtual QPMLFourierDecomposedHelmholtzElement<NNODE_1D, PML_ELEMENT>
1014 {
1015 
1016  public:
1017 
1018  /// \short Constructor: Call the constructor for the
1019  /// appropriate QElement
1021  QPMLFourierDecomposedHelmholtzElement<NNODE_1D,PML_ELEMENT>()
1022  {}
1023 
1024 };
1025 
1026 }
1027 
1028 #endif
double dshape_and_dtest_eulerian_pml_fourier_decomposed_helmholtz(const Vector< double > &s, Shape &psi, DShape &dpsidx, Shape &test, DShape &dtestdx) const
QPMLFourierDecomposedHelmholtzElement()
Constructor: Call constructors for QElement and PMLFourierDecomposedHelmholtz equations.
unsigned nhistory_values_for_projection(const unsigned &fld)
Number of history values to be stored for fld-th field. (Note: count includes current value!) ...
void broken_copy(const std::string &class_name)
Issue error message and terminate execution.
double factorial(const unsigned &l)
Factorial.
GeneralisedAxisymAdvectionDiffusionSourceFctPt Source_fct_pt
Pointer to source function:
void output_fct(std::ostream &outfile, const unsigned &n_plot, const double &time, FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt)
Output function for a time-dependent exact solution. r,z,u_exact at n_plot^2 plot points (Calls the s...
void output_real_fct(std::ostream &outfile, const double &phi, const unsigned &n_plot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
Output function for real part of full time-dependent fct u = Re( (u_r +i u_i) exp(-i omega t) at phas...
unsigned nvalue_of_field(const unsigned &fld)
Return number of values in field fld: One per node.
void compute_error(std::ostream &outfile, FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt, const double &time, double &error, double &norm)
Dummy, time dependent error checker.
virtual void output(std::ostream &outfile)
Output the element data — typically the values at the nodes in a format suitable for post-processing...
Definition: elements.h:2884
Fourier decomposed Helmholtz upgraded to become projectable.
virtual std::complex< unsigned > u_index_pml_fourier_decomposed_helmholtz() const
Broken assignment operator.
PMLFourierDecomposedHelmholtzEquationsBase(const PMLFourierDecomposedHelmholtzEquationsBase &dummy)
Broken copy constructor.
void output_fct(std::ostream &outfile, const unsigned &nplot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
Output exact soln: r,z,u_exact at nplot^2 plot points.
double dshape_and_dtest_eulerian_at_knot_pml_fourier_decomposed_helmholtz(const unsigned &ipt, Shape &psi, DShape &dpsidx, Shape &test, DShape &dtestdx) const
Shape, test functions & derivs. w.r.t. to global coords. at integration point ipt. Return Jacobian.
PMLFourierDecomposedHelmholtzSourceFctPt & source_fct_pt()
Access function: Pointer to source function.
A general Finite Element class.
Definition: elements.h:1274
void(* UnsteadyExactSolutionFctPt)(const double &, const Vector< double > &, Vector< double > &)
Function pointer for function that computes Vector-valued time-dependent function as ...
Definition: elements.h:1729
char t
Definition: cfortran.h:572
void output_fct(std::ostream &outfile, const unsigned &n_plot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
Output function for an exact solution: r,z,u_exact at n_plot^2 plot points.
virtual void output_fct(std::ostream &outfile, const unsigned &n_plot, const double &time, FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt)
Output exact soln: (dummy time-dependent version to keep intel compiler happy)
double jacobian_and_shape_of_field(const unsigned &fld, const Vector< double > &s, Shape &psi)
Return Jacobian of mapping and shape functions of field fld at local coordinate s.
double plgndr1(const unsigned &n, const double &x)
Legendre polynomials depending on one parameter.
QPMLFourierDecomposedHelmholtzElement(const QPMLFourierDecomposedHelmholtzElement< NNODE_1D, PML_ELEMENT > &dummy)
Broken copy constructor.
static const unsigned Initial_Nvalue
Static int that holds the number of variables at nodes: always the same.
unsigned required_nvalue(const unsigned &n) const
Broken assignment operator.
void output(std::ostream &outfile, const unsigned &n_plot)
Output function: r,z,u at n_plot^2 plot points.
void output_real(std::ostream &outfile, const double &phi, const unsigned &n_plot)
Output function for real part of full time-dependent solution u = Re( (u_r +i u_i) exp(-i omega t) at...
void(* SteadyExactSolutionFctPt)(const Vector< double > &, Vector< double > &)
Function pointer for function that computes vector-valued steady "exact solution" as ...
Definition: elements.h:1723
void get_flux(const Vector< double > &s, Vector< std::complex< double > > &flux) const
Get flux: flux[i] = du/dx_i for real and imag part.
unsigned self_test()
Self-test: Return 0 for OK.
static double Default_Physical_Constant_Value
Static default value for the physical constants (initialised to zero)
void output(FILE *file_pt, const unsigned &n_plot)
C-style output function: r,z,u at n_plot^2 plot points.
double get_field(const unsigned &t, const unsigned &fld, const Vector< double > &s)
Return interpolated field fld at local coordinate s, at time level t (t=0: present; t>0: history valu...
static char t char * s
Definition: cfortran.h:572
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Add the element&#39;s contribution to its residual vector (wrapper)
void output(FILE *file_pt)
C-style output function: r,z,u.
virtual void output_fct(std::ostream &outfile, const unsigned &n_plot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
Output an exact solution over the element.
Definition: elements.h:2938
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Add the element&#39;s contribution to its residual vector and element Jacobian matrix (wrapper) ...
void shape(const double &s, double *Psi)
Definition for 1D Lagrange shape functions. The value of all the shape functions at the local coordin...
Definition: shape.h:549
void output(std::ostream &outfile)
Output with default number of plot points.
double Default_Physical_Constant_Value
Default value for physical constants.
FaceGeometry()
Constructor: Call the constructor for the appropriate lower-dimensional QElement. ...
void compute_error(std::ostream &outfile, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, double &error, double &norm)
Get error against and norm of exact solution.
Vector< std::pair< Data *, unsigned > > data_values_of_field(const unsigned &fld)
Specify the values associated with field fld. The information is returned in a vector of pairs which ...
void output(FILE *file_pt)
C_style output with default number of plot points.
unsigned nfields_for_projection()
Number of fields to be projected: 2 (real and imag part)
unsigned nhistory_values_for_coordinate_projection()
Number of positional history values (Note: count includes current value!)
void output_real(std::ostream &outfile, const double &phi, const unsigned &n_plot)
Output function for real part of full time-dependent solution u = Re( (u_r +i u_i) exp(-i omega t) at...
int local_equation(const unsigned &fld, const unsigned &j)
Return local equation number of value j in field fld.
PMLFourierDecomposedHelmholtzSourceFctPt source_fct_pt() const
Access function: Pointer to source function. Const version.
void output(std::ostream &outfile)
Output function: r,z,u.
virtual void get_source_pml_fourier_decomposed_helmholtz(const unsigned &ipt, const Vector< double > &x, std::complex< double > &source) const
PMLFourierDecomposedHelmholtzSourceFctPt Source_fct_pt
Pointer to source function:
void output(std::ostream &outfile)
Output with default number of plot points.
void output_real_fct(std::ostream &outfile, const double &phi, const unsigned &n_plot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
Output function for real part of full time-dependent fct u = Re( (u_r +i u_i) exp(-i omega t) at phas...
void values_to_be_pinned_on_outer_pml_boundary(Vector< unsigned > &values_to_pin)
std::complex< double > interpolated_u_pml_fourier_decomposed_helmholtz(const Vector< double > &s) const
Return FE representation of function value u(s) at local coordinate s.
ProjectablePMLFourierDecomposedHelmholtzElement()
Constructor [this was only required explicitly from gcc 4.5.2 onwards...].
void values_to_be_pinned_on_outer_pml_boundary(Vector< unsigned > &values_to_pin)
Pure virtual function in which we specify the values to be pinned (and set to zero) on the outer edge...
static DenseMatrix< double > Dummy_matrix
Empty dense matrix used as a dummy argument to combined residual and jacobian functions in the case w...
Definition: elements.h:228
double plgndr2(const unsigned &l, const unsigned &m, const double &x)
Legendre polynomials depending on two parameters.
void output(std::ostream &outfile, const unsigned &nplot)
Output FE representation of soln: x,y,u or x,y,z,u at n_plot^DIM plot points.