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