pml_helmholtz_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// 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 //Non-inline functions for gen Helmholtz elements
31 #include "pml_helmholtz_elements.h"
32 
33 
34 
35 namespace oomph
36 {
37 
38 //======================================================================
39 /// Set the data for the number of Variables at each node, always two
40 /// (real and imag part) in every case
41 //======================================================================
42  template<unsigned DIM, unsigned NNODE_1D, class PML_ELEMENT>
44 
45  /// PML Helmholtz equations static data, so that by default we can point to a 0
46  template <unsigned DIM>
47  double PMLHelmholtzEquationsBase<DIM>::Default_Physical_Constant_Value = 0.0; // faire: why is this not const (wasn't in navier_stokes.cc), but it is above
48 
49 //======================================================================
50 /// Compute element residual Vector and/or element Jacobian matrix
51 ///
52 /// flag=1: compute both
53 /// flag=0: compute only residual Vector
54 ///
55 /// Pure version without hanging nodes
56 //======================================================================
57 template <unsigned DIM, class PML_ELEMENT>
60  DenseMatrix<double> &jacobian,
61  const unsigned& flag)
62 {
63  //Find out how many nodes there are
64  const unsigned n_node = this->nnode();
65 
66  //Set up memory for the shape and test functions
67  Shape psi(n_node), test(n_node);
68  DShape dpsidx(n_node,DIM), dtestdx(n_node,DIM);
69 
70  //Set the value of n_intpt
71  const unsigned n_intpt = integral_pt()->nweight();
72 
73  //Integers to store the local equation and unknown numbers
74  int local_eqn_real=0, local_unknown_real=0;
75  int local_eqn_imag=0, local_unknown_imag=0;
76 
77  //Loop over the integration points
78  for(unsigned ipt=0;ipt<n_intpt;ipt++)
79  {
80  //Get the integral weight
81  double w = integral_pt()->weight(ipt);
82 
83  //Call the derivatives of the shape and test functions
84  double J = this->dshape_and_dtest_eulerian_at_knot_helmholtz(
85  ipt, psi, dpsidx, test, dtestdx);
86 
87  //Premultiply the weights and the Jacobian
88  double W = w*J;
89 
90  //Calculate local values of unknown
91  //Allocate and initialise to zero
92  std::complex<double> interpolated_u(0.0,0.0);
93  Vector<double> interpolated_x(DIM,0.0);
94  Vector< std::complex<double> > interpolated_dudx(DIM);
95 
96  //Calculate function value and derivatives:
97  //-----------------------------------------
98  // Loop over nodes
99  for(unsigned l=0;l<n_node;l++)
100  {
101  // Loop over directions
102  for(unsigned j=0;j<DIM;j++)
103  {
104  interpolated_x[j] += this->raw_nodal_position(l,j)*psi(l);
105  }
106 
107  //Get the nodal value of the helmholtz unknown
108  const std::complex<double>
109  u_value(this->raw_nodal_value(l, this->u_index_helmholtz().real()),
110  this->raw_nodal_value(l, this->u_index_helmholtz().imag()));
111 
112  //Add to the interpolated value
113  interpolated_u += u_value*psi(l);
114 
115  // Loop over directions
116  for(unsigned j=0;j<DIM;j++)
117  {
118  interpolated_dudx[j] += u_value*dpsidx(l,j);
119  }
120  }
121 
122  //Get source function
123  //-------------------
124  std::complex<double> source(0.0,0.0);
125  this->get_source_helmholtz(ipt,interpolated_x,source);
126 
127 
128 
129  // All the PML weights that participate in the assemby process
130  // are computed here.
131  // The Jacobian and Laplace matrix (and therefore the det) default to the
132  // identity if the PML is disabled
133  Vector<double> s(DIM);
134  DiagonalComplexMatrix pml_jacobian(DIM);
135  this->pml_transformation_jacobian(ipt, s, interpolated_x, pml_jacobian);
136 
137  // Declare a complex number for pml weights on the mass matrix bit
138  // We will set this equal to the determinant of the pml Jacobian
139  std::complex<double> pml_k_squared_factor = std::complex<double>(1.0,0.0);
140 
141  // Declare a diagonal matrix for pml weights on the Laplace bit
142  DiagonalComplexMatrix laplace_matrix(DIM);
143 
144  this->compute_laplace_matrix_and_det(pml_jacobian, laplace_matrix,
145  pml_k_squared_factor);
146 
147  // Alpha adjusts the pml factors, the imaginary part produces cross terms
148  std::complex<double> alpha_pml_k_squared_factor = std::complex<double>(
149  pml_k_squared_factor.real() - this->alpha() * pml_k_squared_factor.imag(),
150  this->alpha() * pml_k_squared_factor.real() + pml_k_squared_factor.imag());
151 
152  // Assemble residuals and Jacobian
153  //--------------------------------
154  // Loop over the test functions
155  for(unsigned l=0;l<n_node;l++)
156  {
157 
158  // first, compute the real part contribution
159  //-------------------------------------------
160 
161  //Get the local equation
162  local_eqn_real = this->nodal_local_eqn(l,this->u_index_helmholtz().real());
163  local_eqn_imag = this->nodal_local_eqn(l,this->u_index_helmholtz().imag());
164 
165  /*IF it's not a boundary condition*/
166  if(local_eqn_real >= 0)
167  {
168  // Add body force/source term and Helmholtz bit
169  residuals[local_eqn_real] +=
170  ( source.real() -
171  (
172  alpha_pml_k_squared_factor.real() * this->k_squared() * interpolated_u.real()
173  -alpha_pml_k_squared_factor.imag() * this->k_squared() * interpolated_u.imag()
174  )
175  )*test(l)*W;
176 
177  // The Laplace bit
178  for(unsigned k=0;k<DIM;k++)
179  {
180  residuals[local_eqn_real] +=
181  (
182  laplace_matrix(k,k).real() * interpolated_dudx[k].real()
183  -laplace_matrix(k,k).imag() * interpolated_dudx[k].imag()
184  )*dtestdx(l,k)*W;
185  }
186 
187  // Calculate the jacobian
188  //-----------------------
189  if(flag)
190  {
191  //Loop over the velocity shape functions again
192  for(unsigned l2=0;l2<n_node;l2++)
193  {
194  local_unknown_real = this->nodal_local_eqn(l2,this->u_index_helmholtz().real());
195  local_unknown_imag = this->nodal_local_eqn(l2,this->u_index_helmholtz().imag());
196 
197  //If at a non-zero degree of freedom add in the entry
198  if(local_unknown_real >= 0)
199  {
200  //Add contribution to Elemental Matrix
201  for(unsigned i=0;i<DIM;i++)
202  {
203  jacobian(local_eqn_real,local_unknown_real)
204  += laplace_matrix(i,i).real() * dpsidx(l2,i)*dtestdx(l,i)*W;
205  }
206  // Add the helmholtz contribution
207  jacobian(local_eqn_real,local_unknown_real)
208  += -alpha_pml_k_squared_factor.real() * this->k_squared()*psi(l2)*test(l)*W;
209  }
210  //If at a non-zero degree of freedom add in the entry
211  if(local_unknown_imag >= 0)
212  {
213  //Add contribution to Elemental Matrix
214  for(unsigned i=0;i<DIM;i++)
215  {
216  jacobian(local_eqn_real,local_unknown_imag)
217  -= laplace_matrix(i,i).imag() * dpsidx(l2,i)*dtestdx(l,i)*W;
218 
219  }
220  // Add the helmholtz contribution
221  jacobian(local_eqn_real,local_unknown_imag)
222  += alpha_pml_k_squared_factor.imag() * this->k_squared()*psi(l2)*test(l)*W;
223  }
224  }
225  }
226  }
227 
228  // Second, compute the imaginary part contribution
229  //------------------------------------------------
230 
231  //Get the local equation
232  local_eqn_imag = this->nodal_local_eqn(l,this->u_index_helmholtz().imag());
233  local_eqn_real = this->nodal_local_eqn(l,this->u_index_helmholtz().real());
234 
235  /*IF it's not a boundary condition*/
236  if(local_eqn_imag >= 0)
237  {
238  // Add body force/source term and Helmholtz bit
239  residuals[local_eqn_imag] +=
240  ( source.imag() -
241  (
242  alpha_pml_k_squared_factor.imag() * this->k_squared()*interpolated_u.real()
243  + alpha_pml_k_squared_factor.real() * this->k_squared()*interpolated_u.imag()
244  )
245  )*test(l)*W;
246 
247  // The Laplace bit
248  for(unsigned k=0;k<DIM;k++)
249  {
250  residuals[local_eqn_imag] += (
251  laplace_matrix(k,k).imag() * interpolated_dudx[k].real()
252  +laplace_matrix(k,k).real() * interpolated_dudx[k].imag()
253  )*dtestdx(l,k)*W;
254  }
255 
256  // Calculate the jacobian
257  //-----------------------
258  if(flag)
259  {
260  //Loop over the velocity shape functions again
261  for(unsigned l2=0;l2<n_node;l2++)
262  {
263  local_unknown_imag = this->nodal_local_eqn(l2,this->u_index_helmholtz().imag());
264  local_unknown_real = this->nodal_local_eqn(l2,this->u_index_helmholtz().real());
265 
266  //If at a non-zero degree of freedom add in the entry
267  if(local_unknown_imag >= 0)
268  {
269  //Add contribution to Elemental Matrix
270  for(unsigned i=0;i<DIM;i++)
271  {
272  jacobian(local_eqn_imag,local_unknown_imag)
273  += laplace_matrix(i,i).real() * dpsidx(l2,i)*dtestdx(l,i)*W;
274  }
275  // Add the helmholtz contribution
276  jacobian(local_eqn_imag,local_unknown_imag)
277  += -alpha_pml_k_squared_factor.real()*this->k_squared() * psi(l2)*test(l)*W;
278  }
279  if(local_unknown_real >= 0)
280  {
281  //Add contribution to Elemental Matrix
282  for(unsigned i=0;i<DIM;i++)
283  {
284  jacobian(local_eqn_imag,local_unknown_real)
285  +=laplace_matrix(i,i).imag() * dpsidx(l2,i)*dtestdx(l,i)*W;
286  }
287  // Add the helmholtz contribution
288  jacobian(local_eqn_imag,local_unknown_real)
289  += -alpha_pml_k_squared_factor.imag()*this->k_squared() * psi(l2)*test(l)*W;
290  }
291  }
292  }
293  }
294  }
295  } // End of loop over integration points
296 }
297 
298 
299 //======================================================================
300 /// Self-test: Return 0 for OK
301 //======================================================================
302 template <unsigned DIM>
304 {
305 
306  bool passed=true;
307 
308  // Check lower-level stuff
309  if (FiniteElement::self_test()!=0)
310  {
311  passed=false;
312  }
313 
314  // Return verdict
315  if (passed)
316  {
317  return 0;
318  }
319  else
320  {
321  return 1;
322  }
323 
324 }
325 
326 
327 //======================================================================
328 /// Output function:
329 ///
330 /// x,y,u_re,u_imag or x,y,z,u_re,u_imag
331 ///
332 /// nplot points in each coordinate direction
333 //======================================================================
334 template <unsigned DIM>
335 void PMLHelmholtzEquationsBase<DIM>::output(std::ostream &outfile,
336  const unsigned &nplot)
337 {
338 
339  //Vector of local coordinates
340  Vector<double> s(DIM);
341 
342  // Tecplot header info
343  outfile << tecplot_zone_string(nplot);
344 
345  // Loop over plot points
346  unsigned num_plot_points=nplot_points(nplot);
347  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
348  {
349 
350  // Get local coordinates of plot point
351  get_s_plot(iplot,nplot,s);
352  std::complex<double> u(interpolated_u_pml_helmholtz(s));
353  for(unsigned i=0;i<DIM;i++)
354  {
355  outfile << interpolated_x(s,i) << " ";
356  }
357  outfile << u.real() << " " << u.imag() << std::endl;
358 
359  }
360 
361  // Write tecplot footer (e.g. FE connectivity lists)
362  write_tecplot_zone_footer(outfile,nplot);
363 
364 }
365 
366 
367 
368 
369 //======================================================================
370 /// Output function for real part of full time-dependent solution
371 ///
372 /// u = Re( (u_r +i u_i) exp(-i omega t)
373 ///
374 /// at phase angle omega t = phi.
375 ///
376 /// x,y,u or x,y,z,u
377 ///
378 /// Output at nplot points in each coordinate direction
379 //======================================================================
380 template <unsigned DIM>
382  const double& phi,
383  const unsigned &nplot)
384 {
385  // Vector of local coordinates
386  Vector<double> s(DIM);
387 
388  // Tecplot header info
389  outfile << tecplot_zone_string(nplot);
390 
391  // Loop over plot points
392  unsigned num_plot_points=nplot_points(nplot);
393  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
394  {
395  // Get local coordinates of plot point
396  get_s_plot(iplot,nplot,s);
397  std::complex<double> u(interpolated_u_pml_helmholtz(s));
398  for(unsigned i=0;i<DIM;i++)
399  {
400  outfile << interpolated_x(s,i) << " ";
401  }
402  outfile << u.real()*cos(phi)+u.imag()*sin(phi) << std::endl;
403  }
404 
405  // Write tecplot footer (e.g. FE connectivity lists)
406  write_tecplot_zone_footer(outfile,nplot);
407 
408 }
409 
410 //======================================================================
411 /// Output function for real part of full time-dependent solution
412 /// constructed by adding the scattered field
413 ///
414 /// u = Re( (u_r +i u_i) exp(-i omega t)
415 ///
416 /// at phase angle omega t = phi computed here, to the corresponding
417 /// incoming wave specified via the function pointer.
418 ///
419 /// x,y,u or x,y,z,u
420 ///
421 /// Output at nplot points in each coordinate direction
422 //======================================================================
423 template <unsigned DIM>
425  std::ostream &outfile,
426  FiniteElement::SteadyExactSolutionFctPt incoming_wave_fct_pt,
427  const double& phi,
428  const unsigned &nplot)
429 {
430  // Vector of local coordinates
431  Vector<double> s(DIM);
432 
433  // Vector for coordintes
434  Vector<double> x(DIM);
435 
436  // Real and imag part of incoming wave
437  Vector<double> incoming_soln(2);
438 
439  // Tecplot header info
440  outfile << tecplot_zone_string(nplot);
441 
442  // Loop over plot points
443  unsigned num_plot_points=nplot_points(nplot);
444  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
445  {
446  // Get local coordinates of plot point
447  get_s_plot(iplot,nplot,s);
448  std::complex<double> u(interpolated_u_pml_helmholtz(s));
449 
450  // Get x position as Vector
451  interpolated_x(s,x);
452 
453  // Get exact solution at this point
454  (*incoming_wave_fct_pt)(x,incoming_soln);
455 
456  for(unsigned i=0;i<DIM;i++)
457  {
458  outfile << interpolated_x(s,i) << " ";
459  }
460 
461  outfile << (u.real()+incoming_soln[0])*cos(phi)+
462  (u.imag()+incoming_soln[1])*sin(phi) << std::endl;
463  }
464 
465  // Write tecplot footer (e.g. FE connectivity lists)
466  write_tecplot_zone_footer(outfile,nplot);
467 
468 }
469 
470 //======================================================================
471 /// Output function for imaginary part of full time-dependent solution
472 ///
473 /// u = Im( (u_r +i u_i) exp(-i omega t))
474 ///
475 /// at phase angle omega t = phi.
476 ///
477 /// x,y,u or x,y,z,u
478 ///
479 /// Output at nplot points in each coordinate direction
480 //======================================================================
481 template <unsigned DIM>
483  const double& phi,
484  const unsigned &nplot)
485 {
486  // Vector of local coordinates
487  Vector<double> s(DIM);
488 
489  // Tecplot header info
490  outfile << tecplot_zone_string(nplot);
491 
492  // Loop over plot points
493  unsigned num_plot_points=nplot_points(nplot);
494  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
495  {
496  // Get local coordinates of plot point
497  get_s_plot(iplot,nplot,s);
498  std::complex<double> u(interpolated_u_pml_helmholtz(s));
499  for(unsigned i=0;i<DIM;i++)
500  {
501  outfile << interpolated_x(s,i) << " ";
502  }
503  outfile << u.imag()*cos(phi)-u.real()*sin(phi) << std::endl;
504  }
505 
506  // Write tecplot footer (e.g. FE connectivity lists)
507  write_tecplot_zone_footer(outfile,nplot);
508 
509 }
510 
511 
512 //======================================================================
513 /// C-style output function:
514 ///
515 /// x,y,u or x,y,z,u
516 ///
517 /// nplot points in each coordinate direction
518 //======================================================================
519 template <unsigned DIM>
521  const unsigned &nplot)
522 {
523  // Vector of local coordinates
524  Vector<double> s(DIM);
525 
526  // Tecplot header info
527  fprintf(file_pt,"%s",tecplot_zone_string(nplot).c_str());
528 
529  // Loop over plot points
530  unsigned num_plot_points=nplot_points(nplot);
531  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
532  {
533  // Get local coordinates of plot point
534  get_s_plot(iplot,nplot,s);
535  std::complex<double> u(interpolated_u_pml_helmholtz(s));
536 
537  for(unsigned i=0;i<DIM;i++)
538  {
539  fprintf(file_pt,"%g ",interpolated_x(s,i));
540  }
541 
542  for(unsigned i=0;i<DIM;i++)
543  {
544  fprintf(file_pt,"%g ",interpolated_x(s,i));
545  }
546  fprintf(file_pt,"%g ",u.real());
547  fprintf(file_pt,"%g \n",u.imag());
548 
549  }
550 
551  // Write tecplot footer (e.g. FE connectivity lists)
552  write_tecplot_zone_footer(file_pt,nplot);
553 }
554 
555 
556 
557 //======================================================================
558  /// Output exact solution
559  ///
560  /// Solution is provided via function pointer.
561  /// Plot at a given number of plot points.
562  ///
563  /// x,y,u_exact or x,y,z,u_exact
564 //======================================================================
565 template <unsigned DIM>
567 output_fct(std::ostream &outfile,const unsigned &nplot,
569 {
570  // Vector of local coordinates
571  Vector<double> s(DIM);
572 
573  // Vector for coordinates
574  Vector<double> x(DIM);
575 
576  // Tecplot header info
577  outfile << tecplot_zone_string(nplot);
578 
579  // Exact solution Vector
580  Vector<double> exact_soln(2);
581 
582  // Loop over plot points
583  unsigned num_plot_points=nplot_points(nplot);
584  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
585  {
586  // Get local coordinates of plot point
587  get_s_plot(iplot,nplot,s);
588 
589  // Get x position as Vector
590  interpolated_x(s,x);
591 
592  // Get exact solution at this point
593  (*exact_soln_pt)(x,exact_soln);
594 
595  // Output x,y,...,u_exact
596  for(unsigned i=0;i<DIM;i++)
597  {
598  outfile << x[i] << " ";
599  }
600  outfile << exact_soln[0] << " " << exact_soln[1] << std::endl;
601  }
602 
603  // Write tecplot footer (e.g. FE connectivity lists)
604  write_tecplot_zone_footer(outfile,nplot);
605 }
606 
607 
608 
609 //======================================================================
610 /// Output function for real part of full time-dependent fct
611 ///
612 /// u = Re( (u_r +i u_i) exp(-i omega t)
613 ///
614 /// at phase angle omega t = phi.
615 ///
616 /// x,y,u or x,y,z,u
617 ///
618 /// Output at nplot points in each coordinate direction
619 //======================================================================
620 template <unsigned DIM>
622  std::ostream &outfile,
623  const double& phi,
624  const unsigned &nplot,
626 {
627  // Vector of local coordinates
628  Vector<double> s(DIM);
629 
630  // Vector for coordinates
631  Vector<double> x(DIM);
632 
633  // Tecplot header info
634  outfile << tecplot_zone_string(nplot);
635 
636  // Exact solution Vector
637  Vector<double> exact_soln(2);
638 
639  // Loop over plot points
640  unsigned num_plot_points=nplot_points(nplot);
641  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
642  {
643  // Get local coordinates of plot point
644  get_s_plot(iplot,nplot,s);
645 
646  // Get x position as Vector
647  interpolated_x(s,x);
648 
649  // Get exact solution at this point
650  (*exact_soln_pt)(x,exact_soln);
651 
652  // Output x,y,...,u_exact
653  for(unsigned i=0;i<DIM;i++)
654  {
655  outfile << x[i] << " ";
656  }
657  outfile << exact_soln[0]*cos(phi)+ exact_soln[1]*sin(phi) << std::endl;
658  }
659 
660  // Write tecplot footer (e.g. FE connectivity lists)
661  write_tecplot_zone_footer(outfile,nplot);
662 }
663 
664 //======================================================================
665 /// Output function for imaginary part of full time-dependent fct
666 ///
667 /// u = Im( (u_r +i u_i) exp(-i omega t))
668 ///
669 /// at phase angle omega t = phi.
670 ///
671 /// x,y,u or x,y,z,u
672 ///
673 /// Output at nplot points in each coordinate direction
674 //======================================================================
675 template <unsigned DIM>
677  std::ostream &outfile,
678  const double& phi,
679  const unsigned &nplot,
681 {
682  //Vector of local coordinates
683  Vector<double> s(DIM);
684 
685  // Vector for coordintes
686  Vector<double> x(DIM);
687 
688  // Tecplot header info
689  outfile << tecplot_zone_string(nplot);
690 
691  // Exact solution Vector
692  Vector<double> exact_soln(2);
693 
694  // Loop over plot points
695  unsigned num_plot_points=nplot_points(nplot);
696  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
697  {
698 
699  // Get local coordinates of plot point
700  get_s_plot(iplot,nplot,s);
701 
702  // Get x position as Vector
703  interpolated_x(s,x);
704 
705  // Get exact solution at this point
706  (*exact_soln_pt)(x,exact_soln);
707 
708  //Output x,y,...,u_exact
709  for(unsigned i=0;i<DIM;i++)
710  {
711  outfile << x[i] << " ";
712  }
713  outfile << exact_soln[1]*cos(phi) - exact_soln[0]*sin(phi) << std::endl;
714  }
715 
716  // Write tecplot footer (e.g. FE connectivity lists)
717  write_tecplot_zone_footer(outfile,nplot);
718 }
719 
720 
721 
722 
723 //======================================================================
724  /// Validate against exact solution
725  ///
726  /// Solution is provided via function pointer.
727  /// Plot error at a given number of plot points.
728  ///
729 //======================================================================
730 template <unsigned DIM>
732  std::ostream &outfile,
734  double& error,
735  double& norm)
736 {
737 
738  // Initialise
739  error=0.0;
740  norm=0.0;
741 
742  //Vector of local coordinates
743  Vector<double> s(DIM);
744 
745  // Vector for coordintes
746  Vector<double> x(DIM);
747 
748  //Find out how many nodes there are in the element
749  unsigned n_node = nnode();
750 
751  Shape psi(n_node);
752 
753  //Set the value of n_intpt
754  unsigned n_intpt = integral_pt()->nweight();
755 
756  // Tecplot
757  outfile << "ZONE" << std::endl;
758 
759  // Exact solution Vector
760  Vector<double> exact_soln(2);
761 
762  //Loop over the integration points
763  for(unsigned ipt=0;ipt<n_intpt;ipt++)
764  {
765 
766  //Assign values of s
767  for(unsigned i=0;i<DIM;i++)
768  {
769  s[i] = integral_pt()->knot(ipt,i);
770  }
771 
772  //Get the integral weight
773  double w = integral_pt()->weight(ipt);
774 
775  // Get jacobian of mapping
776  double J=J_eulerian(s);
777 
778  //Premultiply the weights and the Jacobian
779  double W = w*J;
780 
781  // Get x position as Vector
782  interpolated_x(s,x);
783 
784  // Get FE function value
785  std::complex<double> u_fe=interpolated_u_pml_helmholtz(s);
786 
787  // Get exact solution at this point
788  (*exact_soln_pt)(x,exact_soln);
789 
790  //Output x,y,...,error
791  for(unsigned i=0;i<DIM;i++)
792  {
793  outfile << x[i] << " ";
794  }
795  outfile << exact_soln[0] << " " << exact_soln[1] << " "
796  << exact_soln[0]-u_fe.real() << " " << exact_soln[1]-u_fe.imag()
797  << std::endl;
798 
799  // Add to error and norm
800  norm+=(exact_soln[0]*exact_soln[0]+exact_soln[1]*exact_soln[1])*W;
801  error+=( (exact_soln[0]-u_fe.real())*(exact_soln[0]-u_fe.real())+
802  (exact_soln[1]-u_fe.imag())*(exact_soln[1]-u_fe.imag()) )*W;
803 
804  }
805 }
806 
807 
808 
809 
810 //======================================================================
811  /// Compute norm of fe solution
812 //======================================================================
813 template <unsigned DIM>
815 {
816 
817  // Initialise
818  norm=0.0;
819 
820  //Vector of local coordinates
821  Vector<double> s(2);
822 
823  // Vector for coordintes
824  Vector<double> x(2);
825 
826  //Find out how many nodes there are in the element
827  unsigned n_node = nnode();
828 
829  Shape psi(n_node);
830 
831  //Set the value of n_intpt
832  unsigned n_intpt = integral_pt()->nweight();
833 
834  //Loop over the integration points
835  for(unsigned ipt=0;ipt<n_intpt;ipt++)
836  {
837 
838  //Assign values of s
839  for(unsigned i=0;i<2;i++)
840  {
841  s[i] = integral_pt()->knot(ipt,i);
842  }
843 
844  //Get the integral weight
845  double w = integral_pt()->weight(ipt);
846 
847  // Get jacobian of mapping
848  double J=J_eulerian(s);
849 
850  //Premultiply the weights and the Jacobian
851  double W = w*J;
852 
853  // Get FE function value
854  std::complex<double> u_fe=interpolated_u_pml_helmholtz(s);
855 
856  // Add to norm
857  norm+=(u_fe.real()*u_fe.real()+u_fe.imag()*u_fe.imag())*W;
858 
859  }
860  }
861 
862 //====================================================================
863 // Force build of templates
864 //====================================================================
865 template<unsigned DIM, class PML_ELEMENT>
867 
868 template class PMLHelmholtzEquationsBase<1>;
869 template class PMLHelmholtzEquationsBase<2>;
870 template class PMLHelmholtzEquationsBase<3>;
871 
875 
879 
883 
887 
888 }
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.
cstr elem_len * i
Definition: cfortran.h:607
virtual void fill_in_generic_residual_contribution_helmholtz(Vector< double > &residuals, DenseMatrix< double > &jacobian, const unsigned &flag)
Compute element residual Vector only (if flag=and/or element Jacobian matrix.
void compute_norm(double &norm)
Compute norm of fe solution.
virtual unsigned self_test()
Self-test: Check inversion of element & do self-test for GeneralisedElement. Return 0 if OK...
Definition: elements.cc:4333
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)) a...
void output_fct(std::ostream &outfile, const unsigned &n_plot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
void output_imag(std::ostream &outfile, const double &phi, const unsigned &n_plot)
Output function for imaginary part of full time-dependent solution u = Im( (u_r +i u_i) exp(-i omega ...
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(* SteadyExactSolutionFctPt)(const Vector< double > &, Vector< double > &)
Function pointer for function that computes vector-valued steady "exact solution" as ...
Definition: elements.h:1723
static char t char * s
Definition: cfortran.h:572
static const unsigned Initial_Nvalue
Static int that holds the number of variables at nodes: always the same.
unsigned self_test()
Self-test: Return 0 for OK.
void output_imag_fct(std::ostream &outfile, const double &phi, const unsigned &n_plot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
Output function for imaginary part of full time-dependent fct u = Im( (u_r +i u_i) exp(-i omega t)) a...
static double Default_Physical_Constant_Value
Static default value for the physical constants (initialised to zero)
QPMLHelmholtzElement elements are linear/quadrilateral/ brick-shaped PMLHelmholtz elements with isopa...
void output_total_real(std::ostream &outfile, FiniteElement::SteadyExactSolutionFctPt incoming_wave_fct_pt, const double &phi, const unsigned &nplot)