43 #include "helmholtz.h" 46 #include "pml_helmholtz.h" 49 #include "meshes/triangle_mesh.h" 50 #include "meshes/rectangular_quadmesh.h" 53 #include "oomph_crbond_bessel.h" 55 using namespace oomph;
80 std::complex<double>
I(0.0,1.0);
88 r=sqrt(x[0]*x[0]+x[1]*x[1]);
90 theta=atan2(x[1],x[0]);
93 double rr=Wavenumber*r;
96 complex <double > u_ex(0.0,0.0);
97 Vector<double> jn(N_fourier+1), yn(N_fourier+1),
98 jnp(N_fourier+1), ynp(N_fourier+1);
99 Vector<double> jn_a(N_fourier+1),yn_a(N_fourier+1),
100 jnp_a(N_fourier+1), ynp_a(N_fourier+1);
101 Vector<complex<double> > h(N_fourier+1),h_a(N_fourier+1),
102 hp(N_fourier+1), hp_a(N_fourier+1);
107 CRBond_Bessel::bessjyna(N_fourier,Wavenumber,n_actual,
109 &jnp_a[0],&ynp_a[0]);
113 if (n_actual!=
int(N_fourier))
115 std::ostringstream error_stream;
116 error_stream <<
"CRBond_Bessel::bessjyna() only computed " 117 << n_actual <<
" rather than " << N_fourier
118 <<
" Bessel functions.\n";
119 throw OomphLibError(error_stream.str(),
120 OOMPH_CURRENT_FUNCTION,
121 OOMPH_EXCEPTION_LOCATION);
126 Hankel_functions_for_helmholtz_problem::Hankel_first(N_fourier,rr,h,hp);
129 Hankel_functions_for_helmholtz_problem::Hankel_first(N_fourier
139 u_ex-=pow(
I,i)*h[i]*jnp_a[i]*pow(exp(
I*theta),static_cast<double>(i))/hp_a[i];
143 u_ex-=pow(
I,i)*h[i]*jnp_a[i]*pow(exp(-
I*theta),static_cast<double>(i))/hp_a[i];
157 complex<double>& flux)
161 r=sqrt(x[0]*x[0]+x[1]*x[1]);
163 theta=atan2(x[1],x[0]);
166 double rr=Wavenumber*r;
169 Vector<double> jn(N_fourier+1), yn(N_fourier+1),
170 jnp(N_fourier+1), ynp(N_fourier+1);
175 CRBond_Bessel::bessjyna(N_fourier,rr,n_actual,&jn[0],&yn[0],
180 if (n_actual!=
int(N_fourier))
182 std::ostringstream error_stream;
183 error_stream <<
"CRBond_Bessel::bessjyna() only computed " 184 << n_actual <<
" rather than " << N_fourier
185 <<
" Bessel functions.\n";
186 throw OomphLibError(error_stream.str(),
187 OOMPH_CURRENT_FUNCTION,
188 OOMPH_EXCEPTION_LOCATION);
194 flux=std::complex<double>(0.0,0.0);
201 flux+=pow(
I,i)*(
Wavenumber)*pow(exp(-
I*theta),i)*jnp[i];
218 const double& wavenumber_squared,
219 const double& alpha_shift=0.0)
221 const double k = sqrt(wavenumber_squared);
228 const double& wavenumber_squared,
229 const double& alpha_shift=0.0)
231 const double k = sqrt(wavenumber_squared);
250 template<
class ELEMENT>
270 void doc_solution(DocInfo& doc_info);
273 void create_pml_meshes();
277 void create_flux_elements(
const unsigned &b, Mesh*
const &bulk_mesh_pt,
278 Mesh*
const & helmholtz_inner_boundary_mesh_pt);
282 void create_power_elements(
const unsigned &b, Mesh*
const &bulk_mesh_pt,
283 Mesh*
const & helmholtz_power_boundary_mesh_pt);
288 void actions_before_adapt();
291 void actions_after_adapt();
303 RefineableTriangleMesh<ELEMENT>* Bulk_mesh_pt;
310 TriangleMesh<ELEMENT>* Bulk_mesh_pt;
316 Mesh* PML_right_mesh_pt;
319 Mesh* PML_top_mesh_pt;
322 Mesh* PML_left_mesh_pt;
325 Mesh* PML_bottom_mesh_pt;
328 Mesh* PML_top_right_mesh_pt;
331 Mesh* PML_top_left_mesh_pt;
334 Mesh* PML_bottom_right_mesh_pt;
337 Mesh* PML_bottom_left_mesh_pt;
356 template<
class ELEMENT>
361 Trace_file.open(
"RESLT/trace.dat");
367 Circle* inner_circle_pt=
new Circle(x_c,y_c,a);
371 TriangleMeshClosedCurve* outer_boundary_pt=0;
373 unsigned n_segments = 20;
374 Vector<TriangleMeshCurveSection*> outer_boundary_line_pt(4);
378 Vector<Vector<double> > vertex_coord(2);
379 for(
unsigned i=0;i<2;i++)
381 vertex_coord[i].resize(2);
385 vertex_coord[0][0]=-2.0;
386 vertex_coord[0][1]=-2.0;
387 vertex_coord[1][0]=-2.0;
388 vertex_coord[1][1]=2.0;
391 unsigned boundary_id=2;
392 outer_boundary_line_pt[0] =
new TriangleMeshPolyLine(vertex_coord,
396 vertex_coord[0][0]=-2.0;
397 vertex_coord[0][1]=2.0;
398 vertex_coord[1][0]=2.0;
399 vertex_coord[1][1]=2.0;
403 outer_boundary_line_pt[1] =
new TriangleMeshPolyLine(vertex_coord,
407 vertex_coord[0][0]=2.0;
408 vertex_coord[0][1]=2.0;
409 vertex_coord[1][0]=2.0;
410 vertex_coord[1][1]=-2.0;
414 outer_boundary_line_pt[2] =
new TriangleMeshPolyLine(vertex_coord,
418 vertex_coord[0][0]=2.0;
419 vertex_coord[0][1]=-2.0;
420 vertex_coord[1][0]=-2.0;
421 vertex_coord[1][1]=-2.0;
425 outer_boundary_line_pt[3] =
new TriangleMeshPolyLine(vertex_coord,
429 outer_boundary_pt =
new TriangleMeshPolygon(outer_boundary_line_pt);
433 Vector<TriangleMeshCurveSection*> inner_boundary_line_pt(2);
436 double s_start = 0.0;
437 double s_end = MathematicalConstants::Pi;
439 inner_boundary_line_pt[0]=
440 new TriangleMeshCurviLine(inner_circle_pt,
447 s_start = MathematicalConstants::Pi;
448 s_end = 2.0*MathematicalConstants::Pi;
450 inner_boundary_line_pt[1]=
451 new TriangleMeshCurviLine(inner_circle_pt,
460 Vector<TriangleMeshClosedCurve*> hole_pt(1);
461 Vector<double> hole_coords(2);
464 hole_pt[0]=
new TriangleMeshClosedCurve(inner_boundary_line_pt,
471 TriangleMeshParameters triangle_mesh_parameters(outer_boundary_pt);
474 triangle_mesh_parameters.internal_closed_curve_pt() = hole_pt;
477 triangle_mesh_parameters.element_area() = 0.05;
482 Bulk_mesh_pt=
new RefineableTriangleMesh<ELEMENT>(triangle_mesh_parameters);
485 Bulk_mesh_pt->spatial_error_estimator_pt()=
new Z2ErrorEstimator;
488 Bulk_mesh_pt->min_permitted_error()=0.00004;
489 Bulk_mesh_pt->max_permitted_error()=0.0001;
494 Bulk_mesh_pt=
new TriangleMesh<ELEMENT>(triangle_mesh_parameters);
500 Helmholtz_inner_boundary_mesh_pt =
new Mesh;
504 create_flux_elements(0,Bulk_mesh_pt,Helmholtz_inner_boundary_mesh_pt);
505 create_flux_elements(1,Bulk_mesh_pt,Helmholtz_inner_boundary_mesh_pt);
509 Helmholtz_power_boundary_mesh_pt =
new Mesh;
513 create_power_elements(0,Bulk_mesh_pt,Helmholtz_power_boundary_mesh_pt);
514 create_power_elements(1,Bulk_mesh_pt,Helmholtz_power_boundary_mesh_pt);
517 add_sub_mesh(Bulk_mesh_pt);
523 add_sub_mesh(Helmholtz_inner_boundary_mesh_pt);
529 unsigned n_element = this->mesh_pt()->nelement();
530 for(
unsigned e=0;e<n_element;e++)
533 PMLHelmholtzEquations<2,AxisAlignedPMLElement<2> > *el_pt =
534 dynamic_cast<PMLHelmholtzEquations<2,AxisAlignedPMLElement<2>
>*>(mesh_pt()->element_pt(e));
547 cout <<
"Number of equations: " << assign_eqn_numbers() << std::endl;
557 template<
class ELEMENT>
563 delete PML_right_mesh_pt;
565 delete PML_top_mesh_pt;
567 delete PML_left_mesh_pt;
569 delete PML_bottom_mesh_pt;
570 PML_bottom_mesh_pt=0;
571 delete PML_top_right_mesh_pt;
572 PML_top_right_mesh_pt=0;
573 delete PML_top_left_mesh_pt;
574 PML_top_left_mesh_pt=0;
575 delete PML_bottom_right_mesh_pt;
576 PML_bottom_right_mesh_pt=0;
577 delete PML_bottom_left_mesh_pt;
578 PML_bottom_left_mesh_pt=0;
585 add_sub_mesh(Bulk_mesh_pt);
589 rebuild_global_mesh();
597 template<
class ELEMENT>
600 create_inner_bc_elements(0,Bulk_mesh_pt,Helmholtz_power_boundary_mesh_pt);
601 create_inner_bc_elements(1,Bulk_mesh_pt,Helmholtz_power_boundary_mesh_pt);
609 unsigned n_element = this->mesh_pt()->nelement();
611 for(
unsigned e=0;e<n_element;e++)
614 PMLHelmholtzEquations<2,AxisAlignedPMLElement<2> > *el_pt =
615 dynamic_cast<PMLHelmholtzEquations<2,AxisAlignedPMLElement<2>
>*>(mesh_pt()->element_pt(e));
627 create_flux_elements(0,Bulk_mesh_pt,Helmholtz_inner_boundary_mesh_pt);
628 create_flux_elements(1,Bulk_mesh_pt,Helmholtz_inner_boundary_mesh_pt);
632 create_power_elements(0,Bulk_mesh_pt,Helmholtz_power_boundary_mesh_pt);
633 create_power_elements(1,Bulk_mesh_pt,Helmholtz_power_boundary_mesh_pt);
636 add_sub_mesh(Helmholtz_inner_boundary_mesh_pt);
639 rebuild_global_mesh();
648 template<
class ELEMENT>
652 ofstream some_file,some_file2;
661 sprintf(filename,
"%s/power%i.dat",doc_info.directory().c_str(),
663 some_file.open(filename);
667 unsigned nn_element=Helmholtz_power_boundary_mesh_pt->nelement();
668 for(
unsigned e=0;e<nn_element;e++)
670 PMLHelmholtzPowerElement<ELEMENT> *el_pt =
671 dynamic_cast<PMLHelmholtzPowerElement<ELEMENT>*
>(
672 Helmholtz_power_boundary_mesh_pt->element_pt(e));
673 power += el_pt->global_power_contribution(some_file);
676 oomph_info <<
"Total radiated power: " << power << std::endl;
680 sprintf(filename,
"%s/soln%i.dat",doc_info.directory().c_str(),
682 some_file.open(filename);
683 Bulk_mesh_pt->output(some_file,npts);
688 sprintf(filename,
"%s/exact_soln%i.dat",doc_info.directory().c_str(),
690 some_file.open(filename);
695 sprintf(filename,
"%s/error%i.dat",doc_info.directory().c_str(),
697 some_file.open(filename);
703 oomph_info <<
"\nNorm of error : " << sqrt(error) << std::endl;
704 oomph_info <<
"Norm of solution: " << sqrt(norm) << std::endl << std::endl;
708 sprintf(filename,
"%s/pml_soln%i.dat",doc_info.directory().c_str(),
710 some_file.open(filename);
711 PML_right_mesh_pt->output(some_file,npts);
712 PML_left_mesh_pt->output(some_file,npts);
713 PML_top_mesh_pt->output(some_file,npts);
714 PML_bottom_mesh_pt->output(some_file,npts);
715 PML_bottom_right_mesh_pt->output(some_file,npts);
716 PML_top_right_mesh_pt->output(some_file,npts);
717 PML_bottom_left_mesh_pt->output(some_file,npts);
718 PML_top_left_mesh_pt->output(some_file,npts);
725 Bulk_mesh_pt->compute_norm(norm2);
726 Trace_file << norm2 << std::endl;
755 template<
class ELEMENT>
758 Mesh*
const & helmholtz_inner_boundary_mesh_pt)
761 unsigned n_element = bulk_mesh_pt->nboundary_element(b);
762 for(
unsigned e=0;e<n_element;e++)
765 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
766 bulk_mesh_pt->boundary_element_pt(b,e));
769 int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
772 PMLHelmholtzFluxElement<ELEMENT>* flux_element_pt =
new 773 PMLHelmholtzFluxElement<ELEMENT>(bulk_elem_pt,face_index);
776 helmholtz_inner_boundary_mesh_pt->add_element_pt(flux_element_pt);
779 flux_element_pt->flux_fct_pt() =
791 template<
class ELEMENT>
794 Mesh*
const & helmholtz_power_boundary_mesh_pt)
797 unsigned n_element = bulk_mesh_pt->nboundary_element(b);
798 for(
unsigned e=0;e<n_element;e++)
801 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
802 bulk_mesh_pt->boundary_element_pt(b,e));
805 int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
808 PMLHelmholtzPowerElement<ELEMENT>* power_element_pt =
new 809 PMLHelmholtzPowerElement<ELEMENT>(bulk_elem_pt,face_index);
812 helmholtz_power_boundary_mesh_pt->add_element_pt(power_element_pt);
822 template<
class ELEMENT>
827 unsigned int left_boundary_id = 2;
830 unsigned int top_boundary_id = 3;
833 unsigned int right_boundary_id = 4;
836 unsigned int bottom_boundary_id = 5;
839 unsigned n_x_right_pml = 3;
842 unsigned n_y_top_pml = 3;
845 unsigned n_x_left_pml = 3;
848 unsigned n_y_bottom_pml = 3;
853 double width_x_right_pml = 0.2;
854 double width_y_top_pml = 0.2;
855 double width_x_left_pml = 0.2;
856 double width_y_bottom_pml = 0.2;
860 TwoDimensionalPMLHelper::create_right_pml_mesh
861 <EquivalentQElement<ELEMENT> >
862 (Bulk_mesh_pt,right_boundary_id,
863 n_x_right_pml, width_x_right_pml);
865 TwoDimensionalPMLHelper::create_top_pml_mesh
866 <EquivalentQElement<ELEMENT> >
867 (Bulk_mesh_pt, top_boundary_id,
868 n_y_top_pml, width_y_top_pml);
870 TwoDimensionalPMLHelper::create_left_pml_mesh
871 <EquivalentQElement<ELEMENT> >
872 (Bulk_mesh_pt, left_boundary_id,
873 n_x_left_pml, width_x_left_pml);
875 TwoDimensionalPMLHelper::create_bottom_pml_mesh
876 <EquivalentQElement<ELEMENT> >
877 (Bulk_mesh_pt, bottom_boundary_id,
878 n_y_bottom_pml, width_y_bottom_pml);
881 add_sub_mesh(PML_right_mesh_pt);
882 add_sub_mesh(PML_top_mesh_pt);
883 add_sub_mesh(PML_left_mesh_pt);
884 add_sub_mesh(PML_bottom_mesh_pt);
887 PML_top_right_mesh_pt =
888 TwoDimensionalPMLHelper::create_top_right_pml_mesh
889 <EquivalentQElement<ELEMENT> >
890 (PML_right_mesh_pt, PML_top_mesh_pt,
891 Bulk_mesh_pt, right_boundary_id);
893 PML_bottom_right_mesh_pt =
894 TwoDimensionalPMLHelper::create_bottom_right_pml_mesh
895 <EquivalentQElement<ELEMENT> >
896 (PML_right_mesh_pt, PML_bottom_mesh_pt,
897 Bulk_mesh_pt, right_boundary_id);
899 PML_top_left_mesh_pt =
900 TwoDimensionalPMLHelper::create_top_left_pml_mesh
901 <EquivalentQElement<ELEMENT> >
902 (PML_left_mesh_pt, PML_top_mesh_pt,
903 Bulk_mesh_pt, left_boundary_id);
905 PML_bottom_left_mesh_pt =
906 TwoDimensionalPMLHelper::create_bottom_left_pml_mesh
907 <EquivalentQElement<ELEMENT> >
908 (PML_left_mesh_pt, PML_bottom_mesh_pt,
909 Bulk_mesh_pt, left_boundary_id);
912 add_sub_mesh(PML_top_right_mesh_pt);
913 add_sub_mesh(PML_bottom_right_mesh_pt);
914 add_sub_mesh(PML_top_left_mesh_pt);
915 add_sub_mesh(PML_bottom_left_mesh_pt);
924 int main(
int argc,
char **argv)
934 <TPMLHelmholtzElement<2,3,AxisAlignedPMLElement<2> > > > problem;
948 doc_info.set_directory(
"RESLT");
954 unsigned max_adapt=1;
958 problem.newton_solve(max_adapt);
963 problem.newton_solve();
double K_squared
Square of the wavenumber (also known as k^2)
void actions_before_newton_solve()
Update the problem specs before solve (empty)
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 create_pml_meshes()
Create PML meshes.
std::complex< double > transformed_nu(const double &nu, const double &delta, const double &wavenumber_squared, const double &alpha_shift=0.0)
std::complex< double > dtransformed_nu_dnu(const double &nu, const double &delta, const double &wavenumber_squared, const double &alpha_shift=0.0)
Overwrite the pure Pml mapping coefficient function to return the coeffcients proposed by Bermudez et...
double Wavenumber
Wavenumber (also known as k), k=omega/c.
void create_power_elements(const unsigned &b, Mesh *const &bulk_mesh_pt, Mesh *const &helmholtz_power_boundary_mesh_pt)
Create Helmholtz power elements on boundary b of the Mesh pointed to by bulk_mesh_pt and add them to ...
std::complex< double > I(0.0, 1.0)
Imaginary unit.
Namespace for the Helmholtz problem parameters.
~PMLProblem()
Destructor (empty)
void doc_solution(DocInfo &doc_info)
Doc the solution. DocInfo object stores flags/labels for where the output gets written to...
void actions_after_adapt()
Actions after adapt: Rebuild the PML meshes.
unsigned N_fourier
Number of terms used in the computation of the exact solution.
int main(int argc, char **argv)
Solve 2D Helmholtz problem.
Mesh * Helmholtz_inner_boundary_mesh_pt
Pointer to the mesh containing the Helmholtz inner boundary condition elements.
void actions_after_newton_solve()
Update the problem specs after solve (empty)
void actions_before_adapt()
Actions before adapt: Wipe the PML meshes.
TestPMLMapping * Test_pml_mapping_pt
void get_exact_u(const Vector< double > &x, Vector< double > &u)
Exact solution for scattered field (vector returns real and impaginary parts).
Mesh * Helmholtz_power_boundary_mesh_pt
Pointer to mesh of elements that compute the radiated power.
TestPMLMapping()
Default constructor (empty)
void prescribed_incoming_flux(const Vector< double > &x, complex< double > &flux)
Flux (normal derivative) on the unit disk for a planar incoming wave.