41 #include "helmholtz.h" 44 #include "meshes/triangle_mesh.h" 47 #include "oomph_crbond_bessel.h" 49 using namespace oomph;
83 std::complex<double>
I(0.0,1.0);
87 void get_exact_u(
const Vector<double>& x, Vector<double>& u)
91 r=sqrt(x[0]*x[0]+x[1]*x[1]);
93 theta=atan2(x[1],x[0]);
96 double rr=sqrt(K_squared)*r;
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);
110 CRBond_Bessel::bessjyna(N_fourier,sqrt(K_squared),n_actual,
112 &jnp_a[0],&ynp_a[0]);
116 if (n_actual!=
int(N_fourier))
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);
129 Hankel_functions_for_helmholtz_problem::Hankel_first(N_fourier,rr,h,hp);
132 Hankel_functions_for_helmholtz_problem::Hankel_first(N_fourier
142 u_ex-=pow(
I,i)*h[i]*jnp_a[i]*pow(exp(
I*theta),static_cast<double>(i))/hp_a[i];
146 u_ex-=pow(
I,i)*h[i]*jnp_a[i]*pow(exp(-
I*theta),static_cast<double>(i))/hp_a[i];
160 complex<double>& flux)
164 r=sqrt(x[0]*x[0]+x[1]*x[1]);
166 theta=atan2(x[1],x[0]);
169 double rr=sqrt(K_squared)*r;
172 Vector<double> jn(N_fourier+1), yn(N_fourier+1),
173 jnp(N_fourier+1), ynp(N_fourier+1);
178 CRBond_Bessel::bessjyna(N_fourier,rr,n_actual,&jn[0],&yn[0],
183 if (n_actual!=
int(N_fourier))
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);
197 flux=std::complex<double>(0.0,0.0);
200 flux+=pow(
I,i)*(sqrt(K_squared))*pow(exp(
I*theta),i)*jnp[i];
204 flux+=pow(
I,i)*(sqrt(K_squared))*pow(exp(-
I*theta),i)*jnp[i];
224 template<
class ELEMENT>
238 void doc_solution(DocInfo& doc_info);
251 Helmholtz_outer_boundary_mesh_pt->setup_gamma();
256 void actions_before_adapt();
259 void actions_after_adapt();
263 void create_outer_bc_elements(
264 const unsigned &b, Mesh*
const &bulk_mesh_pt,
265 Mesh*
const & helmholtz_outer_boundary_mesh_pt);
269 void create_flux_elements(
const unsigned &b, Mesh*
const &bulk_mesh_pt,
270 Mesh*
const & helmholtz_inner_boundary_mesh_pt);
273 void delete_face_elements( Mesh*
const & boundary_mesh_pt);
277 void set_prescribed_incoming_flux_pt();
280 void setup_outer_boundary();
296 HelmholtzDtNMesh<ELEMENT>* Helmholtz_outer_boundary_mesh_pt;
300 Mesh* Helmholtz_inner_boundary_mesh_pt;
312 template<
class ELEMENT>
318 Trace_file.open(
"RESLT/trace.dat");
334 Circle* inner_circle_pt=
new Circle(x_c,y_c,a);
335 Circle* outer_circle_pt=
new Circle(x_c,y_c,
340 TriangleMeshClosedCurve* outer_boundary_pt=0;
342 unsigned n_segments=40;
343 Vector<TriangleMeshCurveSection*> outer_boundary_line_pt(2);
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,
357 s_start = MathematicalConstants::Pi;
358 s_end = 2.0*MathematicalConstants::Pi;
360 outer_boundary_line_pt[1]=
361 new TriangleMeshCurviLine(outer_circle_pt,
368 outer_boundary_pt=
new TriangleMeshClosedCurve(outer_boundary_line_pt);
372 Vector<TriangleMeshCurveSection*> inner_boundary_line_pt(2);
376 s_end = MathematicalConstants::Pi;
378 inner_boundary_line_pt[0]=
379 new TriangleMeshCurviLine(inner_circle_pt,
386 s_start = MathematicalConstants::Pi;
387 s_end = 2.0*MathematicalConstants::Pi;
389 inner_boundary_line_pt[1]=
390 new TriangleMeshCurviLine(inner_circle_pt,
399 Vector<TriangleMeshClosedCurve*> hole_pt(1);
400 Vector<double> hole_coords(2);
403 hole_pt[0]=
new TriangleMeshClosedCurve(inner_boundary_line_pt,
411 TriangleMeshParameters triangle_mesh_parameters(outer_boundary_pt);
414 triangle_mesh_parameters.internal_closed_curve_pt() = hole_pt;
419 Bulk_mesh_pt=
new RefineableTriangleMesh<ELEMENT>(triangle_mesh_parameters);
422 Bulk_mesh_pt->spatial_error_estimator_pt()=
new Z2ErrorEstimator;
425 Bulk_mesh_pt->min_permitted_error()=0.00004;
426 Bulk_mesh_pt->max_permitted_error()=0.0001;
431 Bulk_mesh_pt=
new TriangleMesh<ELEMENT>(triangle_mesh_parameters);
438 Helmholtz_outer_boundary_mesh_pt =
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);
448 Helmholtz_inner_boundary_mesh_pt =
new 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);
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);
468 unsigned n_element = Bulk_mesh_pt->nelement();
469 for(
unsigned e=0;e<n_element;e++)
472 ELEMENT *el_pt =
dynamic_cast<ELEMENT*
>(Bulk_mesh_pt->element_pt(e));
479 setup_outer_boundary();
482 set_prescribed_incoming_flux_pt();
485 cout <<
"Number of equations: " << assign_eqn_numbers() << std::endl;
492 template<
class ELEMENT>
496 delete_face_elements(Helmholtz_outer_boundary_mesh_pt);
497 delete_face_elements(Helmholtz_inner_boundary_mesh_pt);
500 rebuild_global_mesh();
508 template<
class ELEMENT>
518 unsigned n_element = Bulk_mesh_pt->nelement();
519 for(
unsigned e=0;e<n_element;e++)
522 ELEMENT *el_pt =
dynamic_cast<ELEMENT*
>(Bulk_mesh_pt->element_pt(e));
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);
537 rebuild_global_mesh();
540 setup_outer_boundary();
541 set_prescribed_incoming_flux_pt();
550 template<
class ELEMENT>
555 unsigned n_element=Helmholtz_outer_boundary_mesh_pt->nelement();
556 for(
unsigned e=0;e<n_element;e++)
562 HelmholtzDtNBoundaryElement<ELEMENT> *el_pt =
563 dynamic_cast< HelmholtzDtNBoundaryElement<ELEMENT>*
>(
564 Helmholtz_outer_boundary_mesh_pt->element_pt(e));
568 el_pt->set_outer_boundary_mesh_pt(Helmholtz_outer_boundary_mesh_pt);
574 HelmholtzAbsorbingBCElement<ELEMENT> *el_pt =
575 dynamic_cast< HelmholtzAbsorbingBCElement<ELEMENT>*
>(
576 Helmholtz_outer_boundary_mesh_pt->element_pt(e));
592 template<
class ELEMENT>
597 unsigned n_element=Helmholtz_inner_boundary_mesh_pt->nelement();
598 for(
unsigned e=0;e<n_element;e++)
601 HelmholtzFluxElement<ELEMENT> *el_pt =
602 dynamic_cast< HelmholtzFluxElement<ELEMENT>*
>(
603 Helmholtz_inner_boundary_mesh_pt->element_pt(e));
606 el_pt->flux_fct_pt() =
615 template<
class ELEMENT>
620 ofstream some_file,some_file2;
632 sprintf(filename,
"%s/power%i.dat",doc_info.directory().c_str(),
634 some_file.open(filename);
637 unsigned nn_element=Helmholtz_outer_boundary_mesh_pt->nelement();
638 for(
unsigned e=0;e<nn_element;e++)
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);
646 oomph_info <<
"Total radiated power: " << power << std::endl;
650 sprintf(filename,
"%s/soln%i.dat",doc_info.directory().c_str(),
652 some_file.open(filename);
653 Bulk_mesh_pt->output(some_file,npts);
658 sprintf(filename,
"%s/exact_soln%i.dat",doc_info.directory().c_str(),
660 some_file.open(filename);
665 sprintf(filename,
"%s/error%i.dat",doc_info.directory().c_str(),
667 some_file.open(filename);
673 oomph_info <<
"\nNorm of error : " << sqrt(error) << std::endl;
674 oomph_info <<
"Norm of solution: " << sqrt(norm) << std::endl << std::endl;
678 Trace_file << power << std::endl;
683 for (
unsigned i=0;i<nstep;i++)
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++)
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,
714 template<
class ELEMENT>
717 Mesh*
const & helmholtz_inner_boundary_mesh_pt)
720 unsigned n_element = bulk_mesh_pt->nboundary_element(b);
721 for(
unsigned e=0;e<n_element;e++)
724 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
725 bulk_mesh_pt->boundary_element_pt(b,e));
728 int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
731 HelmholtzFluxElement<ELEMENT>* flux_element_pt =
new 732 HelmholtzFluxElement<ELEMENT>(bulk_elem_pt,face_index);
735 helmholtz_inner_boundary_mesh_pt->add_element_pt(flux_element_pt);
748 template<
class ELEMENT>
751 Mesh*
const & helmholtz_outer_boundary_mesh_pt)
754 unsigned n_element = bulk_mesh_pt->nboundary_element(b);
755 for(
unsigned e=0;e<n_element;e++)
758 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
759 bulk_mesh_pt->boundary_element_pt(b,e));
762 int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
769 HelmholtzDtNBoundaryElement<ELEMENT>* flux_element_pt =
new 770 HelmholtzDtNBoundaryElement<ELEMENT>(bulk_elem_pt,face_index);
773 helmholtz_outer_boundary_mesh_pt->add_element_pt(flux_element_pt);
778 HelmholtzAbsorbingBCElement<ELEMENT>* flux_element_pt =
new 779 HelmholtzAbsorbingBCElement<ELEMENT>(bulk_elem_pt,face_index);
782 helmholtz_outer_boundary_mesh_pt->add_element_pt(flux_element_pt);
791 template<
class ELEMENT>
796 unsigned n_element = boundary_mesh_pt->nelement();
797 for(
unsigned e=0;e<n_element;e++)
800 delete boundary_mesh_pt->element_pt(e);
804 boundary_mesh_pt->flush_element_and_node_storage();
814 int main(
int argc,
char **argv)
817 CommandLineArgs::setup(argc,argv);
821 CommandLineArgs::specify_command_line_flag(
"--case",&i_case);
824 CommandLineArgs::parse_and_assign();
827 CommandLineArgs::doc_specified_flags();
877 doc_info.set_directory(
"RESLT");
883 unsigned max_adapt=1;
887 problem.newton_solve(max_adapt);
892 problem.newton_solve();
double K_squared
Square of the wavenumber.
TriangleMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
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!)
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.
ofstream Trace_file
Trace file.
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)
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...
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.
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.