unstructured_scattering.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 //Driver for a specific 2D Helmholtz problem with flux boundary conditions
31 //uses two separate meshes for bulk and surface mesh
32 
33 #include "math.h"
34 #include <complex>
35 
36 
37 //Generic routines
38 #include "generic.h"
39 
40 // The Helmholtz equations
41 #include "helmholtz.h"
42 
43 // The mesh
44 #include "meshes/triangle_mesh.h"
45 
46 // Get the Bessel functions
47 #include "oomph_crbond_bessel.h"
48 
49 using namespace oomph;
50 using namespace std;
51 
52 
53 
54 /////////////////////////////////////////////////////////////////////
55 /////////////////////////////////////////////////////////////////////
56 /////////////////////////////////////////////////////////////////////
57 
58 //===== start_of_namespace=============================================
59 /// Namespace for the Helmholtz problem parameters
60 //=====================================================================
61 namespace GlobalParameters
62 {
63 
64  /// \short Square of the wavenumber
65  double K_squared=10.0;
66 
67  /// \short Number of terms used in the computation
68  /// of the exact solution
69  unsigned N_fourier=10;
70 
71  /// \short Flag to choose the Dirichlet to Neumann BC
72  /// or ABC BC
73  bool DtN_BC=false;
74 
75  /// \short Flag to choose wich order to use
76  // in the ABCs BC: 1 for ABC 1st order...
77  unsigned ABC_order=3;
78 
79  /// Radius of outer boundary (must be a circle!)
80  double Outer_radius=1.5;
81 
82  /// Imaginary unit
83  std::complex<double> I(0.0,1.0);
84 
85  /// \short Exact solution for scattered field
86  /// (vector returns real and impaginary parts).
87  void get_exact_u(const Vector<double>& x, Vector<double>& u)
88  {
89  // Switch to polar coordinates
90  double r;
91  r=sqrt(x[0]*x[0]+x[1]*x[1]);
92  double theta;
93  theta=atan2(x[1],x[0]);
94 
95  // Argument for Bessel/Hankel functions
96  double rr=sqrt(K_squared)*r;
97 
98  // Evaluate Bessel/Hankel functions
99  complex <double > u_ex(0.0,0.0);
100  Vector<double> jn(N_fourier+1), yn(N_fourier+1),
101  jnp(N_fourier+1), ynp(N_fourier+1);
102  Vector<double> jn_a(N_fourier+1),yn_a(N_fourier+1),
103  jnp_a(N_fourier+1), ynp_a(N_fourier+1);
104  Vector<complex<double> > h(N_fourier+1),h_a(N_fourier+1),
105  hp(N_fourier+1), hp_a(N_fourier+1);
106 
107  // We want to compute N_fourier terms but the function
108  // may return fewer than that.
109  int n_actual=0;
110  CRBond_Bessel::bessjyna(N_fourier,sqrt(K_squared),n_actual,
111  &jn_a[0],&yn_a[0],
112  &jnp_a[0],&ynp_a[0]);
113 
114  // Shout if things went wrong
115 #ifdef PARANOID
116  if (n_actual!=int(N_fourier))
117  {
118  std::ostringstream error_stream;
119  error_stream << "CRBond_Bessel::bessjyna() only computed "
120  << n_actual << " rather than " << N_fourier
121  << " Bessel functions.\n";
122  throw OomphLibError(error_stream.str(),
123  OOMPH_CURRENT_FUNCTION,
124  OOMPH_EXCEPTION_LOCATION);
125  }
126 #endif
127 
128  // Evaluate Hankel at actual radius
129  Hankel_functions_for_helmholtz_problem::Hankel_first(N_fourier,rr,h,hp);
130 
131  // Evaluate Hankel at inner (unit) radius
132  Hankel_functions_for_helmholtz_problem::Hankel_first(N_fourier
133  ,sqrt(K_squared),
134  h_a,hp_a);
135 
136  // Compute the sum: Separate the computation of the negative
137  // and positive terms
138  // ALH: The construction with the static cast to a double is to avoid
139  // a floating point exception when running unoptimised on my machine
140  for (unsigned i=0;i<N_fourier;i++)
141  {
142  u_ex-=pow(I,i)*h[i]*jnp_a[i]*pow(exp(I*theta),static_cast<double>(i))/hp_a[i];
143  }
144  for (unsigned i=1;i<N_fourier;i++)
145  {
146  u_ex-=pow(I,i)*h[i]*jnp_a[i]*pow(exp(-I*theta),static_cast<double>(i))/hp_a[i];
147  }
148 
149  // Get the real & imaginary part of the result
150  u[0]=real(u_ex);
151  u[1]=imag(u_ex);
152 
153  }// end of get_exact_u
154 
155 
156 
157  /// \short Flux (normal derivative) on the unit disk
158  /// for a planar incoming wave
159  void prescribed_incoming_flux(const Vector<double>& x,
160  complex<double>& flux)
161  {
162  // Switch to polar coordinates
163  double r;
164  r=sqrt(x[0]*x[0]+x[1]*x[1]);
165  double theta;
166  theta=atan2(x[1],x[0]);
167 
168  // Argument of the Bessel/Hankel fcts
169  double rr=sqrt(K_squared)*r;
170 
171  // Compute Bessel/Hankel functions
172  Vector<double> jn(N_fourier+1), yn(N_fourier+1),
173  jnp(N_fourier+1), ynp(N_fourier+1);
174 
175  // We want to compute N_fourier terms but the function
176  // may return fewer than that.
177  int n_actual=0;
178  CRBond_Bessel::bessjyna(N_fourier,rr,n_actual,&jn[0],&yn[0],
179  &jnp[0],&ynp[0]);
180 
181  // Shout if things went wrong...
182 #ifdef PARANOID
183  if (n_actual!=int(N_fourier))
184  {
185  std::ostringstream error_stream;
186  error_stream << "CRBond_Bessel::bessjyna() only computed "
187  << n_actual << " rather than " << N_fourier
188  << " Bessel functions.\n";
189  throw OomphLibError(error_stream.str(),
190  OOMPH_CURRENT_FUNCTION,
191  OOMPH_EXCEPTION_LOCATION);
192  }
193 #endif
194 
195  // Compute the sum: Separate the computation of the negative and
196  // positive terms
197  flux=std::complex<double>(0.0,0.0);
198  for (unsigned i=0;i<N_fourier;i++)
199  {
200  flux+=pow(I,i)*(sqrt(K_squared))*pow(exp(I*theta),i)*jnp[i];
201  }
202  for (unsigned i=1;i<N_fourier;i++)
203  {
204  flux+=pow(I,i)*(sqrt(K_squared))*pow(exp(-I*theta),i)*jnp[i];
205  }
206 
207 
208  }// end of prescribed_incoming_flux
209 
210 } // end of namespace
211 
212 
213 
214 
215 /////////////////////////////////////////////////////////////////////
216 /////////////////////////////////////////////////////////////////////
217 /////////////////////////////////////////////////////////////////////
218 
219 
220 
221 //========= start_of_problem_class=====================================
222 /// Problem class to compute scattering of planar wave from unit disk
223 //=====================================================================
224 template<class ELEMENT>
225 class ScatteringProblem : public Problem
226 {
227 
228 public:
229 
230  /// Constructor
232 
233  /// Destructor (empty)
235 
236  /// \short Doc the solution. DocInfo object stores flags/labels for where the
237  /// output gets written to
238  void doc_solution(DocInfo& doc_info);
239 
240  /// \short Update the problem specs before solve (empty)
242 
243  /// Update the problem specs after solve (empty)
245 
246  /// Recompute gamma integral before checking Newton residuals
248  {
250  {
251  Helmholtz_outer_boundary_mesh_pt->setup_gamma();
252  }
253  }
254 
255  /// Actions before adapt: Wipe the mesh of prescribed flux elements
256  void actions_before_adapt();
257 
258  /// Actions after adapt: Rebuild the mesh of prescribed flux elements
259  void actions_after_adapt();
260 
261  /// \short Create BC elements on boundary b of the Mesh pointed
262  /// to by bulk_mesh_pt and add them to the specified survace Mesh
263  void create_outer_bc_elements(
264  const unsigned &b, Mesh* const &bulk_mesh_pt,
265  Mesh* const & helmholtz_outer_boundary_mesh_pt);
266 
267  /// \short Create Helmholtz flux elements on boundary b of the Mesh pointed
268  /// to by bulk_mesh_pt and add them to the specified surface Mesh
269  void create_flux_elements(const unsigned &b, Mesh* const &bulk_mesh_pt,
270  Mesh* const & helmholtz_inner_boundary_mesh_pt);
271 
272  /// \short Delete boundary face elements and wipe the surface mesh
273  void delete_face_elements( Mesh* const & boundary_mesh_pt);
274 
275  /// \short Set pointer to prescribed-flux function for all
276  /// elements in the surface mesh on the surface of the unit disk
277  void set_prescribed_incoming_flux_pt();
278 
279  /// \short Set up boundary condition elements on outer boundary
280  void setup_outer_boundary();
281 
282 #ifdef ADAPTIVE
283 
284  /// Pointer to the "bulk" mesh
285  RefineableTriangleMesh<ELEMENT>* Bulk_mesh_pt;
286 
287 #else
288 
289  /// Pointer to the "bulk" mesh
290  TriangleMesh<ELEMENT>* Bulk_mesh_pt;
291 
292 #endif
293 
294  /// \short Pointer to mesh containing the DtN (or ABC) boundary
295  /// condition elements
296  HelmholtzDtNMesh<ELEMENT>* Helmholtz_outer_boundary_mesh_pt;
297 
298  /// \short Pointer to the mesh containing
299  /// the Helmholtz inner boundary condition elements
300  Mesh* Helmholtz_inner_boundary_mesh_pt;
301 
302  /// Trace file
303  ofstream Trace_file;
304 
305 }; // end of problem class
306 
307 
308 
309 //=======start_of_constructor=============================================
310 /// Constructor for Helmholtz problem
311 //========================================================================
312 template<class ELEMENT>
315 {
316 
317  // Open trace file
318  Trace_file.open("RESLT/trace.dat");
319 
320  // Setup "bulk" mesh
321 
322  // Inner radius
323  double a=1.0;
324 
325  // Thickness of annular computational domain
326  double h=0.5;
327 
328  // Set outer radius
330 
331  // Create circles representing inner and outer boundary
332  double x_c=0.0;
333  double y_c=0.0;
334  Circle* inner_circle_pt=new Circle(x_c,y_c,a);
335  Circle* outer_circle_pt=new Circle(x_c,y_c,
337 
338  // Outer boundary
339  //---------------
340  TriangleMeshClosedCurve* outer_boundary_pt=0;
341 
342  unsigned n_segments=40;
343  Vector<TriangleMeshCurveSection*> outer_boundary_line_pt(2);
344 
345  // The intrinsic coordinates for the beginning and end of the curve
346  double s_start = 0.0;
347  double s_end = MathematicalConstants::Pi;
348  unsigned boundary_id = 2;
349  outer_boundary_line_pt[0]=
350  new TriangleMeshCurviLine(outer_circle_pt,
351  s_start,
352  s_end,
353  n_segments,
354  boundary_id);
355 
356  // The intrinsic coordinates for the beginning and end of the curve
357  s_start = MathematicalConstants::Pi;
358  s_end = 2.0*MathematicalConstants::Pi;
359  boundary_id = 3;
360  outer_boundary_line_pt[1]=
361  new TriangleMeshCurviLine(outer_circle_pt,
362  s_start,
363  s_end,
364  n_segments,
365  boundary_id);
366 
367  // Create closed curve for outer boundary
368  outer_boundary_pt=new TriangleMeshClosedCurve(outer_boundary_line_pt);
369 
370  // Inner circular boundary
371  //------------------------
372  Vector<TriangleMeshCurveSection*> inner_boundary_line_pt(2);
373 
374  // The intrinsic coordinates for the beginning and end of the curve
375  s_start = 0.0;
376  s_end = MathematicalConstants::Pi;
377  boundary_id = 0;
378  inner_boundary_line_pt[0]=
379  new TriangleMeshCurviLine(inner_circle_pt,
380  s_start,
381  s_end,
382  n_segments,
383  boundary_id);
384 
385  // The intrinsic coordinates for the beginning and end of the curve
386  s_start = MathematicalConstants::Pi;
387  s_end = 2.0*MathematicalConstants::Pi;
388  boundary_id = 1;
389  inner_boundary_line_pt[1]=
390  new TriangleMeshCurviLine(inner_circle_pt,
391  s_start,
392  s_end,
393  n_segments,
394  boundary_id);
395 
396 
397  // Combine to hole
398  //----------------
399  Vector<TriangleMeshClosedCurve*> hole_pt(1);
400  Vector<double> hole_coords(2);
401  hole_coords[0]=0.0;
402  hole_coords[1]=0.0;
403  hole_pt[0]=new TriangleMeshClosedCurve(inner_boundary_line_pt,
404  hole_coords);
405 
406 
407 
408  // Use the TriangleMeshParameters object for helping on the manage of the
409  // TriangleMesh parameters. The only parameter that needs to take is the
410  // outer boundary.
411  TriangleMeshParameters triangle_mesh_parameters(outer_boundary_pt);
412 
413  // Specify the closed curve using the TriangleMeshParameters object
414  triangle_mesh_parameters.internal_closed_curve_pt() = hole_pt;
415 
416 #ifdef ADAPTIVE
417 
418  // Build "bulk" mesh
419  Bulk_mesh_pt=new RefineableTriangleMesh<ELEMENT>(triangle_mesh_parameters);
420 
421  // Create/set error estimator
422  Bulk_mesh_pt->spatial_error_estimator_pt()=new Z2ErrorEstimator;
423 
424  // Choose error tolerances to force some uniform refinement
425  Bulk_mesh_pt->min_permitted_error()=0.00004;
426  Bulk_mesh_pt->max_permitted_error()=0.0001;
427 
428 #else
429 
430  // Build "bulk" mesh
431  Bulk_mesh_pt=new TriangleMesh<ELEMENT>(triangle_mesh_parameters);
432 
433 #endif
434 
435  // Pointer to mesh containing the Helmholtz outer boundary condition
436  // elements. Specify outer radius and number of Fourier terms to be
437  // used in gamma integral
438  Helmholtz_outer_boundary_mesh_pt =
439  new HelmholtzDtNMesh<ELEMENT>(a+h,GlobalParameters::N_fourier);
440 
441  // Create outer boundary elements from all elements that are
442  // adjacent to the outer boundary , but add them to a separate mesh.
443  create_outer_bc_elements(2,Bulk_mesh_pt,Helmholtz_outer_boundary_mesh_pt);
444  create_outer_bc_elements(3,Bulk_mesh_pt,Helmholtz_outer_boundary_mesh_pt);
445 
446  // Pointer to mesh containing the Helmholtz inner boundary condition
447  // elements. Specify outer radius
448  Helmholtz_inner_boundary_mesh_pt = new Mesh;
449 
450  // Create prescribed-flux elements from all elements that are
451  // adjacent to the inner boundary , but add them to a separate mesh.
452  create_flux_elements(0,Bulk_mesh_pt,Helmholtz_inner_boundary_mesh_pt);
453  create_flux_elements(1,Bulk_mesh_pt,Helmholtz_inner_boundary_mesh_pt);
454 
455  // Add the several sub meshes to the problem
456  add_sub_mesh(Bulk_mesh_pt);
457  add_sub_mesh(Helmholtz_outer_boundary_mesh_pt);
458  add_sub_mesh(Helmholtz_inner_boundary_mesh_pt);
459 
460  // Build the Problem's global mesh from its various sub-meshes
461  build_global_mesh();
462 
463  // Complete the build of all elements so they are fully functional
464 
465  // Loop over the Helmholtz bulk elements to set up element-specific
466  // things that cannot be handled by constructor: Pass pointer to
467  // wave number squared
468  unsigned n_element = Bulk_mesh_pt->nelement();
469  for(unsigned e=0;e<n_element;e++)
470  {
471  // Upcast from GeneralisedElement to Helmholtz bulk element
472  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(e));
473 
474  //Set the k_squared pointer
475  el_pt->k_squared_pt() = &GlobalParameters::K_squared;
476  }
477 
478  // Set up elements on outer boundary
479  setup_outer_boundary();
480 
481  // Set pointer to prescribed flux function for flux elements
482  set_prescribed_incoming_flux_pt();
483 
484  // Setup equation numbering scheme
485  cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
486 
487 } // end of constructor
488 
489 //=====================start_of_actions_before_adapt======================
490 /// Actions before adapt: Wipe the mesh of face elements
491 //========================================================================
492 template<class ELEMENT>
494 {
495  // Kill the flux elements and wipe the boundary meshs
496  delete_face_elements(Helmholtz_outer_boundary_mesh_pt);
497  delete_face_elements(Helmholtz_inner_boundary_mesh_pt);
498 
499  // Rebuild the Problem's global mesh from its various sub-meshes
500  rebuild_global_mesh();
501 
502 }// end of actions_before_adapt
503 
504 
505 //=====================start_of_actions_after_adapt=======================
506 /// Actions after adapt: Rebuild the face element meshes
507 //========================================================================
508 template<class ELEMENT>
510 {
511 
512 
513  // Complete the build of all elements so they are fully functional
514 
515  // Loop over the Helmholtz bulk elements to set up element-specific
516  // things that cannot be handled by constructor: Pass pointer to
517  // wave number squared
518  unsigned n_element = Bulk_mesh_pt->nelement();
519  for(unsigned e=0;e<n_element;e++)
520  {
521  // Upcast from GeneralisedElement to Helmholtz bulk element
522  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(e));
523 
524  //Set the k_squared pointer
525  el_pt->k_squared_pt() = &GlobalParameters::K_squared;
526  }
527 
528  // Create prescribed-flux elements and BC elements
529  // from all elements that are adjacent to the boundaries and add them to
530  // Helmholtz_boundary_meshes
531  create_flux_elements(0,Bulk_mesh_pt,Helmholtz_inner_boundary_mesh_pt);
532  create_flux_elements(1,Bulk_mesh_pt,Helmholtz_inner_boundary_mesh_pt);
533  create_outer_bc_elements(2,Bulk_mesh_pt,Helmholtz_outer_boundary_mesh_pt);
534  create_outer_bc_elements(3,Bulk_mesh_pt,Helmholtz_outer_boundary_mesh_pt);
535 
536  // Rebuild the Problem's global mesh from its various sub-meshes
537  rebuild_global_mesh();
538 
539  // Set pointer to prescribed flux function and DtN mesh
540  setup_outer_boundary();
541  set_prescribed_incoming_flux_pt();
542 
543 
544 }// end of actions_after_adapt
545 
546 
547 //==================start_of_setup_outer_boundary=========================
548 /// Set pointers for elements on outer boundary
549 //========================================================================
550 template<class ELEMENT>
552 {
553  // Loop over the flux elements to pass pointer to DtN
554  // BC for the outer boundary
555  unsigned n_element=Helmholtz_outer_boundary_mesh_pt->nelement();
556  for(unsigned e=0;e<n_element;e++)
557  {
558  // Dirichlet to Neumann BC
560  {
561  // Upcast from GeneralisedElement to Helmholtz flux element
562  HelmholtzDtNBoundaryElement<ELEMENT> *el_pt =
563  dynamic_cast< HelmholtzDtNBoundaryElement<ELEMENT>*>(
564  Helmholtz_outer_boundary_mesh_pt->element_pt(e));
565 
566  // Set pointer to the mesh that contains all the boundary condition
567  // elements on this boundary
568  el_pt->set_outer_boundary_mesh_pt(Helmholtz_outer_boundary_mesh_pt);
569  }
570  // ABCs BC
571  else
572  {
573  // Upcast from GeneralisedElement to appropriate type
574  HelmholtzAbsorbingBCElement<ELEMENT> *el_pt =
575  dynamic_cast< HelmholtzAbsorbingBCElement<ELEMENT>*>(
576  Helmholtz_outer_boundary_mesh_pt->element_pt(e));
577 
578  // Set pointer to outer radius of artificial boundary
579  el_pt->outer_radius_pt()=&GlobalParameters::Outer_radius;
580 
581  // Set order of absorbing boundary condition
582  el_pt->abc_order_pt()=&GlobalParameters::ABC_order;
583  }
584  }
585 }
586 
587 
588 //==================start_of_set_prescribed_incoming_flux_pt==============
589 /// Set pointer to prescribed incoming-flux function for all
590 /// elements in the inner boundary
591 //========================================================================
592 template<class ELEMENT>
594 {
595  // Loop over the flux elements to pass pointer to prescribed
596  // flux function for the inner boundary
597  unsigned n_element=Helmholtz_inner_boundary_mesh_pt->nelement();
598  for(unsigned e=0;e<n_element;e++)
599  {
600  // Upcast from GeneralisedElement to Helmholtz flux element
601  HelmholtzFluxElement<ELEMENT> *el_pt =
602  dynamic_cast< HelmholtzFluxElement<ELEMENT>*>(
603  Helmholtz_inner_boundary_mesh_pt->element_pt(e));
604 
605  // Set the pointer to the prescribed flux function
606  el_pt->flux_fct_pt() =
608  }
609 
610 }// end of set prescribed_incoming_flux pt
611 
612 //=====================start_of_doc=======================================
613 /// Doc the solution: doc_info contains labels/output directory etc.
614 //========================================================================
615 template<class ELEMENT>
617  doc_info)
618 {
619 
620  ofstream some_file,some_file2;
621  char filename[100];
622 
623  // Number of plot points
624  unsigned npts;
625  npts=5;
626 
627  // Total radiated power
628  double power=0.0;
629 
630  // Compute/output the radiated power
631  //----------------------------------
632  sprintf(filename,"%s/power%i.dat",doc_info.directory().c_str(),
633  doc_info.number());
634  some_file.open(filename);
635 
636  // Accumulate contribution from elements
637  unsigned nn_element=Helmholtz_outer_boundary_mesh_pt->nelement();
638  for(unsigned e=0;e<nn_element;e++)
639  {
640  HelmholtzBCElementBase<ELEMENT> *el_pt =
641  dynamic_cast< HelmholtzBCElementBase<ELEMENT>*>(
642  Helmholtz_outer_boundary_mesh_pt->element_pt(e));
643  power += el_pt->global_power_contribution(some_file);
644  }
645  some_file.close();
646  oomph_info << "Total radiated power: " << power << std::endl;
647 
648  // Output solution
649  //-----------------
650  sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
651  doc_info.number());
652  some_file.open(filename);
653  Bulk_mesh_pt->output(some_file,npts);
654  some_file.close();
655 
656  // Output exact solution
657  //----------------------
658  sprintf(filename,"%s/exact_soln%i.dat",doc_info.directory().c_str(),
659  doc_info.number());
660  some_file.open(filename);
661  Bulk_mesh_pt->output_fct(some_file,npts,GlobalParameters::get_exact_u);
662  some_file.close();
663 
664  double error,norm;
665  sprintf(filename,"%s/error%i.dat",doc_info.directory().c_str(),
666  doc_info.number());
667  some_file.open(filename);
668  Bulk_mesh_pt->compute_error(some_file,GlobalParameters::get_exact_u,
669  error,norm);
670  some_file.close();
671 
672  // Doc L2 error and norm of solution
673  oomph_info << "\nNorm of error : " << sqrt(error) << std::endl;
674  oomph_info << "Norm of solution: " << sqrt(norm) << std::endl << std::endl;
675 
676 
677  // Write power to trace file
678  Trace_file << power << std::endl;
679 
680  // Do animation of Helmholtz solution
681  //-----------------------------------
682  unsigned nstep=40;
683  for (unsigned i=0;i<nstep;i++)
684  {
685  sprintf(filename,"%s/helmholtz_animation%i_frame%i.dat",
686  doc_info.directory().c_str(),
687  doc_info.number(),i);
688  some_file.open(filename);
689  sprintf(filename,"%s/exact_helmholtz_animation%i_frame%i.dat",
690  doc_info.directory().c_str(),
691  doc_info.number(),i);
692  some_file2.open(filename);
693  double phi=2.0*MathematicalConstants::Pi*double(i)/double(nstep-1);
694  unsigned nelem=Bulk_mesh_pt->nelement();
695  for (unsigned e=0;e<nelem;e++)
696  {
697  ELEMENT* el_pt=dynamic_cast<ELEMENT*>(
698  Bulk_mesh_pt->element_pt(e));
699  el_pt->output_real(some_file,phi,npts);
700  el_pt->output_real_fct(some_file2,phi,npts,
702  }
703  some_file.close();
704  some_file2.close();
705  }
706 
707 } // end of doc
708 
709 //============start_of_create_flux_elements==================================
710 /// Create Helmholtz inner Flux Elements on the b-th boundary of
711 /// the Mesh object pointed to by bulk_mesh_pt and add the elements
712 /// to the Mesh object pointed to by helmholtz_inner_boundary_mesh_pt
713 //============================================================================
714 template<class ELEMENT>
716 create_flux_elements(const unsigned &b, Mesh* const &bulk_mesh_pt,
717  Mesh* const & helmholtz_inner_boundary_mesh_pt)
718 {
719  // Loop over the bulk elements adjacent to boundary b
720  unsigned n_element = bulk_mesh_pt->nboundary_element(b);
721  for(unsigned e=0;e<n_element;e++)
722  {
723  // Get pointer to the bulk element that is adjacent to boundary b
724  ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
725  bulk_mesh_pt->boundary_element_pt(b,e));
726 
727  //Find the index of the face of element e along boundary b
728  int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
729 
730  // Build the corresponding prescribed incoming-flux element
731  HelmholtzFluxElement<ELEMENT>* flux_element_pt = new
732  HelmholtzFluxElement<ELEMENT>(bulk_elem_pt,face_index);
733 
734  //Add the prescribed incoming-flux element to the surface mesh
735  helmholtz_inner_boundary_mesh_pt->add_element_pt(flux_element_pt);
736 
737  } //end of loop over bulk elements adjacent to boundary b
738 
739 } // end of create_flux_elements
740 
741 
742 
743 //============start_of_create_outer_bc_elements==============================
744 /// Create outer BC elements on the b-th boundary of
745 /// the Mesh object pointed to by bulk_mesh_pt and add the elements
746 /// to the Mesh object pointed to by helmholtz_outer_boundary_mesh_pt.
747 //===========================================================================
748 template<class ELEMENT>
750 create_outer_bc_elements(const unsigned &b, Mesh* const &bulk_mesh_pt,
751  Mesh* const & helmholtz_outer_boundary_mesh_pt)
752 {
753  // Loop over the bulk elements adjacent to boundary b?
754  unsigned n_element = bulk_mesh_pt->nboundary_element(b);
755  for(unsigned e=0;e<n_element;e++)
756  {
757  // Get pointer to the bulk element that is adjacent to boundary b
758  ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
759  bulk_mesh_pt->boundary_element_pt(b,e));
760 
761  //Find the index of the face of element e along boundary b
762  int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
763 
764  // Build the corresponding outer flux element
765 
766  // Dirichlet to Neumann boundary conditon
768  {
769  HelmholtzDtNBoundaryElement<ELEMENT>* flux_element_pt = new
770  HelmholtzDtNBoundaryElement<ELEMENT>(bulk_elem_pt,face_index);
771 
772  //Add the flux boundary element to the helmholtz_outer_boundary_mesh
773  helmholtz_outer_boundary_mesh_pt->add_element_pt(flux_element_pt);
774  }
775  // ABCs BC
776  else
777  {
778  HelmholtzAbsorbingBCElement<ELEMENT>* flux_element_pt = new
779  HelmholtzAbsorbingBCElement<ELEMENT>(bulk_elem_pt,face_index);
780 
781  //Add the flux boundary element to the helmholtz_outer_boundary_mesh
782  helmholtz_outer_boundary_mesh_pt->add_element_pt(flux_element_pt);
783  }
784  } //end of loop over bulk elements adjacent to boundary b
785 } // end of create_outer_bc_elements
786 
787 
788 //============start_of_delete_face_elements================
789 /// Delete face elements and wipe the boundary mesh
790 //==========================================================
791 template<class ELEMENT>
793 delete_face_elements(Mesh* const & boundary_mesh_pt)
794 {
795  // Loop over the surface elements
796  unsigned n_element = boundary_mesh_pt->nelement();
797  for(unsigned e=0;e<n_element;e++)
798  {
799  // Kill surface element
800  delete boundary_mesh_pt->element_pt(e);
801  }
802 
803  // Wipe the mesh
804  boundary_mesh_pt->flush_element_and_node_storage();
805 
806 } // end of delete_outer_face_elements
807 
808 
809 
810 //==========start_of_main=================================================
811 /// Solve 2D Helmholtz problem for scattering of a planar wave from a
812 /// unit disk
813 //========================================================================
814 int main(int argc, char **argv)
815 {
816  // Store command line arguments
817  CommandLineArgs::setup(argc,argv);
818 
819  // Define case to be run
820  unsigned i_case=0;
821  CommandLineArgs::specify_command_line_flag("--case",&i_case);
822 
823  // Parse command line
824  CommandLineArgs::parse_and_assign();
825 
826  // Doc what has actually been specified on the command line
827  CommandLineArgs::doc_specified_flags();
828 
829  // Now set flags accordingly
830  switch(i_case)
831  {
832  case 0:
834  break;
835 
836  case 1:
839  break;
840 
841  case 2:
844  break;
845 
846  case 3:
849  break;
850  }
851 
852 
853  //Set up the problem
854  //------------------
855 
856 #ifdef ADAPTIVE
857 
858  //Set up the problem with 2D nine-node elements from the
859  //QHelmholtzElement family.
861  problem;
862 
863 #else
864 
865  // Set up the problem with 2D six-node elements from the
866  // THelmholtzElement family.
868 
869 
870 #endif
871 
872  // Create label for output
873  //------------------------
874  DocInfo doc_info;
875 
876  // Set output directory
877  doc_info.set_directory("RESLT");
878 
879 
880 #ifdef ADAPTIVE
881 
882  // Max. number of adaptations
883  unsigned max_adapt=1;
884 
885  // Solve the problem with Newton's method, allowing
886  // up to max_adapt mesh adaptations after every solve.
887  problem.newton_solve(max_adapt);
888 
889 #else
890 
891  // Solve the problem with Newton's method
892  problem.newton_solve();
893 
894 #endif
895 
896  //Output solution
897  problem.doc_solution(doc_info);
898 
899 } //end of main
900 
901 
double K_squared
Square of the wavenumber.
Definition: scattering.cc:68
TriangleMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
ScatteringProblem()
Constructor.
Definition: scattering.cc:312
void delete_face_elements(Mesh *const &boundary_mesh_pt)
Delete boundary face elements and wipe the surface mesh.
Definition: scattering.cc:692
void doc_solution(DocInfo &doc_info)
Doc the solution. DocInfo object stores flags/labels for where the output gets written to...
Definition: scattering.cc:520
double Outer_radius
Radius of outer boundary (must be a circle!)
Definition: scattering.cc:83
void actions_before_adapt()
Actions before adapt: Wipe the mesh of prescribed flux elements.
Definition: scattering.cc:417
Namespace for "global" problem parameters.
Definition: barrel.cc:48
bool DtN_BC
Flag to choose the Dirichlet to Neumann BC or ABC BC.
Definition: scattering.cc:76
Problem class to compute scattering of planar wave from unit disk.
Definition: scattering.cc:226
void setup_outer_boundary()
Set up boundary condition elements on outer boundary.
Definition: scattering.cc:455
ofstream Trace_file
Trace file.
unsigned N_fourier
Number of terms used in the computation of the exact solution.
Definition: scattering.cc:72
~ScatteringProblem()
Destructor (empty)
void actions_before_newton_solve()
Update the problem specs before solve (empty)
void actions_before_newton_convergence_check()
Recompute gamma integral before checking Newton residuals.
RefineableTriangleMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
void create_flux_elements(const unsigned &b, Mesh *const &bulk_mesh_pt, Mesh *const &helmholtz_inner_boundary_mesh_pt)
Create Helmholtz flux elements on boundary b of the Mesh pointed to by bulk_mesh_pt and add them to t...
Definition: scattering.cc:615
void actions_after_newton_solve()
Update the problem specs after solve (empty)
int main(int argc, char **argv)
void set_prescribed_incoming_flux_pt()
Set pointer to prescribed-flux function for all elements in the surface mesh on the surface of the un...
Definition: scattering.cc:497
std::complex< double > I(0.0, 1.0)
Imaginary unit.
unsigned ABC_order
Flag to choose wich order to use.
Definition: scattering.cc:80
void actions_after_adapt()
Actions after adapt: Rebuild the mesh of prescribed flux elements.
Definition: scattering.cc:433
void create_outer_bc_elements(const unsigned &b, Mesh *const &bulk_mesh_pt, Mesh *const &helmholtz_outer_boundary_mesh_pt)
Create BC elements on boundary b of the Mesh pointed to by bulk_mesh_pt and add them to the specified...
Definition: scattering.cc:649
void get_exact_u(const Vector< double > &x, Vector< double > &u)
Exact solution for scattered field (vector returns real and impaginary parts).
Definition: scattering.cc:90
void prescribed_incoming_flux(const Vector< double > &x, complex< double > &flux)
Flux (normal derivative) on the unit disk for a planar incoming wave.
Definition: scattering.cc:160