44 #include "helmholtz.h" 47 #include "meshes/annular_mesh.h" 50 #include "oomph_crbond_bessel.h" 52 using namespace oomph;
86 std::complex<double>
I(0.0,1.0);
94 r=sqrt(x[0]*x[0]+x[1]*x[1]);
96 theta=atan2(x[1],x[0]);
99 double rr=sqrt(K_squared)*r;
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);
113 CRBond_Bessel::bessjyna(N_fourier,sqrt(K_squared),n_actual,
115 &jnp_a[0],&ynp_a[0]);
119 if (n_actual!=
int(N_fourier))
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);
132 Hankel_functions_for_helmholtz_problem::Hankel_first(N_fourier,rr,h,hp);
135 Hankel_functions_for_helmholtz_problem::Hankel_first(N_fourier
143 u_ex-=pow(
I,i)*h[i]*((jnp_a[i])/hp_a[i])*pow(exp(
I*theta),i);
147 u_ex-=pow(
I,i)*h[i]*((jnp_a[i])/hp_a[i])*pow(exp(-
I*theta),i);
161 complex<double>& flux)
165 r=sqrt(x[0]*x[0]+x[1]*x[1]);
167 theta=atan2(x[1],x[0]);
170 double rr=sqrt(K_squared)*r;
173 Vector<double> jn(N_fourier+1), yn(N_fourier+1),
174 jnp(N_fourier+1), ynp(N_fourier+1);
179 CRBond_Bessel::bessjyna(N_fourier,rr,n_actual,&jn[0],&yn[0],
184 if (n_actual!=
int(N_fourier))
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);
198 flux=std::complex<double>(0.0,0.0);
201 flux+=pow(
I,i)*(sqrt(K_squared))*pow(exp(
I*theta),i)*jnp[i];
205 flux+=pow(
I,i)*(sqrt(K_squared))*pow(exp(-
I*theta),i)*jnp[i];
225 template<
class ELEMENT>
239 void doc_solution(DocInfo& doc_info);
252 Helmholtz_outer_boundary_mesh_pt->setup_gamma();
257 void actions_before_adapt();
260 void actions_after_adapt();
264 void create_outer_bc_elements(
265 const unsigned &b, Mesh*
const &bulk_mesh_pt,
266 Mesh*
const & helmholtz_outer_boundary_mesh_pt);
270 void create_flux_elements(
const unsigned &b, Mesh*
const &bulk_mesh_pt,
271 Mesh*
const & helmholtz_inner_boundary_mesh_pt);
274 void delete_face_elements( Mesh*
const & boundary_mesh_pt);
278 void set_prescribed_incoming_flux_pt();
281 void setup_outer_boundary();
310 template<
class ELEMENT>
336 double azimuthal_fraction=1.0;
342 new RefineableTwoDAnnularMesh<ELEMENT>(periodic,
343 azimuthal_fraction,n_theta,n_r,a,h);
346 Bulk_mesh_pt->spatial_error_estimator_pt()=
new Z2ErrorEstimator;
349 Bulk_mesh_pt->min_permitted_error()=0.004;
350 Bulk_mesh_pt->max_permitted_error()=0.01;
356 new TwoDAnnularMesh<ELEMENT>(periodic,
357 azimuthal_fraction,n_theta,n_r,a,h);
364 Helmholtz_outer_boundary_mesh_pt =
369 Helmholtz_inner_boundary_mesh_pt =
new Mesh;
373 create_flux_elements(0,Bulk_mesh_pt,Helmholtz_inner_boundary_mesh_pt);
377 create_outer_bc_elements(2,Bulk_mesh_pt,Helmholtz_outer_boundary_mesh_pt);
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);
392 unsigned n_element = Bulk_mesh_pt->nelement();
393 for(
unsigned e=0;e<n_element;e++)
396 ELEMENT *el_pt =
dynamic_cast<ELEMENT*
>(Bulk_mesh_pt->element_pt(e));
403 setup_outer_boundary();
406 set_prescribed_incoming_flux_pt();
409 cout <<
"Number of equations: " << assign_eqn_numbers() << std::endl;
416 template<
class ELEMENT>
420 delete_face_elements(Helmholtz_outer_boundary_mesh_pt);
421 delete_face_elements(Helmholtz_inner_boundary_mesh_pt);
424 rebuild_global_mesh();
432 template<
class ELEMENT>
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);
442 rebuild_global_mesh();
445 setup_outer_boundary();
446 set_prescribed_incoming_flux_pt();
454 template<
class ELEMENT>
459 unsigned n_element=Helmholtz_outer_boundary_mesh_pt->nelement();
460 for(
unsigned e=0;e<n_element;e++)
466 HelmholtzDtNBoundaryElement<ELEMENT> *el_pt =
467 dynamic_cast< HelmholtzDtNBoundaryElement<ELEMENT>*
>(
468 Helmholtz_outer_boundary_mesh_pt->element_pt(e));
472 el_pt->set_outer_boundary_mesh_pt(Helmholtz_outer_boundary_mesh_pt);
478 HelmholtzAbsorbingBCElement<ELEMENT> *el_pt =
479 dynamic_cast< HelmholtzAbsorbingBCElement<ELEMENT>*
>(
480 Helmholtz_outer_boundary_mesh_pt->element_pt(e));
496 template<
class ELEMENT>
501 unsigned n_element=Helmholtz_inner_boundary_mesh_pt->nelement();
502 for(
unsigned e=0;e<n_element;e++)
505 HelmholtzFluxElement<ELEMENT> *el_pt =
506 dynamic_cast< HelmholtzFluxElement<ELEMENT>*
>(
507 Helmholtz_inner_boundary_mesh_pt->element_pt(e));
510 el_pt->flux_fct_pt() =
519 template<
class ELEMENT>
524 ofstream some_file,some_file2;
533 sprintf(filename,
"%s/power%i.dat",doc_info.directory().c_str(),
535 some_file.open(filename);
539 unsigned nn_element=Helmholtz_outer_boundary_mesh_pt->nelement();
540 for(
unsigned e=0;e<nn_element;e++)
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);
548 oomph_info <<
"Total radiated power: " << power << std::endl;
552 sprintf(filename,
"%s/soln%i.dat",doc_info.directory().c_str(),
554 some_file.open(filename);
555 Bulk_mesh_pt->output(some_file,npts);
560 sprintf(filename,
"%s/exact_soln%i.dat",doc_info.directory().c_str(),
562 some_file.open(filename);
567 sprintf(filename,
"%s/error%i.dat",doc_info.directory().c_str(),
569 some_file.open(filename);
575 oomph_info <<
"\nNorm of error : " << sqrt(error) << std::endl;
576 oomph_info <<
"Norm of solution: " << sqrt(norm) << std::endl << std::endl;
582 for (
unsigned i=0;i<nstep;i++)
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++)
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,
613 template<
class ELEMENT>
616 Mesh*
const & helmholtz_inner_boundary_mesh_pt)
619 unsigned n_element = bulk_mesh_pt->nboundary_element(b);
620 for(
unsigned e=0;e<n_element;e++)
623 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
624 bulk_mesh_pt->boundary_element_pt(b,e));
627 int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
630 HelmholtzFluxElement<ELEMENT>* flux_element_pt =
new 631 HelmholtzFluxElement<ELEMENT>(bulk_elem_pt,face_index);
634 helmholtz_inner_boundary_mesh_pt->add_element_pt(flux_element_pt);
647 template<
class ELEMENT>
650 Mesh*
const & helmholtz_outer_boundary_mesh_pt)
653 unsigned n_element = bulk_mesh_pt->nboundary_element(b);
654 for(
unsigned e=0;e<n_element;e++)
657 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
658 bulk_mesh_pt->boundary_element_pt(b,e));
661 int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
668 HelmholtzDtNBoundaryElement<ELEMENT>* flux_element_pt =
new 669 HelmholtzDtNBoundaryElement<ELEMENT>(bulk_elem_pt,face_index);
672 helmholtz_outer_boundary_mesh_pt->add_element_pt(flux_element_pt);
677 HelmholtzAbsorbingBCElement<ELEMENT>* flux_element_pt =
new 678 HelmholtzAbsorbingBCElement<ELEMENT>(bulk_elem_pt,face_index);
681 helmholtz_outer_boundary_mesh_pt->add_element_pt(flux_element_pt);
690 template<
class ELEMENT>
695 unsigned n_element = boundary_mesh_pt->nelement();
696 for(
unsigned e=0;e<n_element;e++)
699 delete boundary_mesh_pt->element_pt(e);
703 boundary_mesh_pt->flush_element_and_node_storage();
713 int main(
int argc,
char **argv)
717 CommandLineArgs::setup(argc,argv);
721 CommandLineArgs::specify_command_line_flag(
"--case",&i_case);
724 CommandLineArgs::parse_and_assign();
727 CommandLineArgs::doc_specified_flags();
778 doc_info.set_directory(
"RESLT");
784 unsigned max_adapt=1;
788 problem.newton_solve(max_adapt);
793 problem.newton_solve();
double K_squared
Square of the wavenumber.
Mesh * Helmholtz_inner_boundary_mesh_pt
Pointer to the mesh containing the Helmholtz inner boundary condition elements.
ScatteringProblem()
Constructor.
void delete_face_elements(Mesh *const &boundary_mesh_pt)
Delete boundary face elements and wipe the surface mesh.
void doc_solution(DocInfo &doc_info)
Doc the solution. DocInfo object stores flags/labels for where the output gets written to...
double Outer_radius
Radius of outer boundary (must be a circle!)
RefineableTwoDAnnularMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
void actions_before_adapt()
Actions before adapt: Wipe the mesh of prescribed flux elements.
Namespace for "global" problem parameters.
bool DtN_BC
Flag to choose the Dirichlet to Neumann BC or ABC BC.
Problem class to compute scattering of planar wave from unit disk.
void setup_outer_boundary()
Set up boundary condition elements on outer boundary.
unsigned N_fourier
Number of terms used in the computation of the exact solution.
~ScatteringProblem()
Destructor (empty)
void actions_before_newton_solve()
Update the problem specs before solve (empty)
TwoDAnnularMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
void actions_before_newton_convergence_check()
Recompute gamma integral before checking Newton residuals.
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...
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...
std::complex< double > I(0.0, 1.0)
Imaginary unit.
unsigned ABC_order
Flag to choose wich order to use.
HelmholtzDtNMesh< ELEMENT > * Helmholtz_outer_boundary_mesh_pt
Pointer to mesh containing the DtN (or ABC) boundary condition elements.
void actions_after_adapt()
Actions after adapt: Rebuild the mesh of prescribed flux elements.
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...
void get_exact_u(const Vector< double > &x, Vector< double > &u)
Exact solution for scattered field (vector returns real and impaginary parts).
void prescribed_incoming_flux(const Vector< double > &x, complex< double > &flux)
Flux (normal derivative) on the unit disk for a planar incoming wave.