42#include "pml_helmholtz.h"
45#include "meshes/triangle_mesh.h"
46#include "meshes/rectangular_quadmesh.h"
49#include "oomph_crbond_bessel.h"
76 std::complex<double>
I(0.0,1.0);
84 r=sqrt(x[0]*x[0]+x[1]*x[1]);
86 theta=atan2(x[1],x[0]);
92 complex <double > u_ex(0.0,0.0);
105 &jnp_a[0],&ynp_a[0]);
111 std::ostringstream error_stream;
112 error_stream <<
"CRBond_Bessel::bessjyna() only computed "
113 << n_actual <<
" rather than " <<
N_fourier
114 <<
" Bessel functions.\n";
115 throw OomphLibError(error_stream.str(),
116 OOMPH_CURRENT_FUNCTION,
117 OOMPH_EXCEPTION_LOCATION);
122 Hankel_functions_for_helmholtz_problem::Hankel_first(
N_fourier,rr,h,hp);
125 Hankel_functions_for_helmholtz_problem::Hankel_first(
N_fourier
135 u_ex-=pow(
I,i)*h[i]*jnp_a[i]*pow(exp(
I*theta),
static_cast<double>(i))/hp_a[i];
139 u_ex-=pow(
I,i)*h[i]*jnp_a[i]*pow(exp(-
I*theta),
static_cast<double>(i))/hp_a[i];
153 complex<double>& flux)
157 r=sqrt(x[0]*x[0]+x[1]*x[1]);
159 theta=atan2(x[1],x[0]);
171 CRBond_Bessel::bessjyna(
N_fourier,rr,n_actual,&jn[0],&yn[0],
178 std::ostringstream error_stream;
179 error_stream <<
"CRBond_Bessel::bessjyna() only computed "
180 << n_actual <<
" rather than " <<
N_fourier
181 <<
" Bessel functions.\n";
182 throw OomphLibError(error_stream.str(),
183 OOMPH_CURRENT_FUNCTION,
184 OOMPH_EXCEPTION_LOCATION);
190 flux=std::complex<double>(0.0,0.0);
197 flux+=pow(
I,i)*(
Wavenumber)*pow(exp(-
I*theta),i)*jnp[i];
212 std::complex<double>
gamma(
const double& nu_i,
213 const double& pml_width_i,
214 const double& k_squared_local,
215 const double& alpha_shift=0.0)
221 return 1.0 + (1.0 / std::complex<double> (sqrt(k_squared_local), 0))
222 * std::complex<double>
223 (0.0, 2.0/(std::fabs(pml_width_i - nu_i)));
241template<
class ELEMENT>
269 Mesh*
const & helmholtz_inner_boundary_mesh_pt);
274 Mesh*
const & helmholtz_power_boundary_mesh_pt);
347template<
class ELEMENT>
352 Trace_file.open(
"RESLT/trace.dat");
358 Circle* inner_circle_pt=
new Circle(x_c,y_c,a);
362 TriangleMeshClosedCurve* outer_boundary_pt=0;
364 unsigned n_segments = 20;
365 Vector<TriangleMeshCurveSection*> outer_boundary_line_pt(4);
369 Vector<Vector<double> > vertex_coord(2);
370 for(
unsigned i=0;i<2;i++)
372 vertex_coord[i].resize(2);
376 vertex_coord[0][0]=-2.0;
377 vertex_coord[0][1]=-2.0;
378 vertex_coord[1][0]=-2.0;
379 vertex_coord[1][1]=2.0;
382 unsigned boundary_id=2;
383 outer_boundary_line_pt[0] =
new TriangleMeshPolyLine(vertex_coord,
387 vertex_coord[0][0]=-2.0;
388 vertex_coord[0][1]=2.0;
389 vertex_coord[1][0]=2.0;
390 vertex_coord[1][1]=2.0;
394 outer_boundary_line_pt[1] =
new TriangleMeshPolyLine(vertex_coord,
398 vertex_coord[0][0]=2.0;
399 vertex_coord[0][1]=2.0;
400 vertex_coord[1][0]=2.0;
401 vertex_coord[1][1]=-2.0;
405 outer_boundary_line_pt[2] =
new TriangleMeshPolyLine(vertex_coord,
409 vertex_coord[0][0]=2.0;
410 vertex_coord[0][1]=-2.0;
411 vertex_coord[1][0]=-2.0;
412 vertex_coord[1][1]=-2.0;
416 outer_boundary_line_pt[3] =
new TriangleMeshPolyLine(vertex_coord,
420 outer_boundary_pt =
new TriangleMeshPolygon(outer_boundary_line_pt);
424 Vector<TriangleMeshCurveSection*> inner_boundary_line_pt(2);
427 double s_start = 0.0;
428 double s_end = MathematicalConstants::Pi;
430 inner_boundary_line_pt[0]=
431 new TriangleMeshCurviLine(inner_circle_pt,
438 s_start = MathematicalConstants::Pi;
439 s_end = 2.0*MathematicalConstants::Pi;
441 inner_boundary_line_pt[1]=
442 new TriangleMeshCurviLine(inner_circle_pt,
451 Vector<TriangleMeshClosedCurve*> hole_pt(1);
452 Vector<double> hole_coords(2);
455 hole_pt[0]=
new TriangleMeshClosedCurve(inner_boundary_line_pt,
462 TriangleMeshParameters triangle_mesh_parameters(outer_boundary_pt);
465 triangle_mesh_parameters.internal_closed_curve_pt() = hole_pt;
468 triangle_mesh_parameters.element_area() = 0.05;
473 Bulk_mesh_pt=
new RefineableTriangleMesh<ELEMENT>(triangle_mesh_parameters);
476 Bulk_mesh_pt->spatial_error_estimator_pt()=
new Z2ErrorEstimator;
479 Bulk_mesh_pt->min_permitted_error()=0.00004;
480 Bulk_mesh_pt->max_permitted_error()=0.0001;
485 Bulk_mesh_pt=
new TriangleMesh<ELEMENT>(triangle_mesh_parameters);
491 Helmholtz_inner_boundary_mesh_pt =
new Mesh;
495 create_flux_elements(0,Bulk_mesh_pt,Helmholtz_inner_boundary_mesh_pt);
496 create_flux_elements(1,Bulk_mesh_pt,Helmholtz_inner_boundary_mesh_pt);
500 Helmholtz_power_boundary_mesh_pt =
new Mesh;
504 create_power_elements(0,Bulk_mesh_pt,Helmholtz_power_boundary_mesh_pt);
505 create_power_elements(1,Bulk_mesh_pt,Helmholtz_power_boundary_mesh_pt);
508 add_sub_mesh(Bulk_mesh_pt);
514 add_sub_mesh(Helmholtz_inner_boundary_mesh_pt);
520 unsigned n_element = this->mesh_pt()->nelement();
521 for(
unsigned e=0;e<n_element;e++)
524 PMLHelmholtzEquations<2> *el_pt =
525 dynamic_cast<PMLHelmholtzEquations<2>*
>(mesh_pt()->element_pt(e));
538 cout <<
"Number of equations: " << assign_eqn_numbers() << std::endl;
548template<
class ELEMENT>
554 delete PML_right_mesh_pt;
556 delete PML_top_mesh_pt;
558 delete PML_left_mesh_pt;
560 delete PML_bottom_mesh_pt;
561 PML_bottom_mesh_pt=0;
562 delete PML_top_right_mesh_pt;
563 PML_top_right_mesh_pt=0;
564 delete PML_top_left_mesh_pt;
565 PML_top_left_mesh_pt=0;
566 delete PML_bottom_right_mesh_pt;
567 PML_bottom_right_mesh_pt=0;
568 delete PML_bottom_left_mesh_pt;
569 PML_bottom_left_mesh_pt=0;
576 add_sub_mesh(Bulk_mesh_pt);
580 rebuild_global_mesh();
588template<
class ELEMENT>
591 create_inner_bc_elements(0,Bulk_mesh_pt,Helmholtz_power_boundary_mesh_pt);
592 create_inner_bc_elements(1,Bulk_mesh_pt,Helmholtz_power_boundary_mesh_pt);
600 unsigned n_element = this->mesh_pt()->nelement();
602 for(
unsigned e=0;e<n_element;e++)
605 PMLHelmholtzEquations<2> *el_pt =
606 dynamic_cast<PMLHelmholtzEquations<2>*
>(mesh_pt()->element_pt(e));
618 create_flux_elements(0,Bulk_mesh_pt,Helmholtz_inner_boundary_mesh_pt);
619 create_flux_elements(1,Bulk_mesh_pt,Helmholtz_inner_boundary_mesh_pt);
623 create_power_elements(0,Bulk_mesh_pt,Helmholtz_power_boundary_mesh_pt);
624 create_power_elements(1,Bulk_mesh_pt,Helmholtz_power_boundary_mesh_pt);
627 add_sub_mesh(Helmholtz_inner_boundary_mesh_pt);
630 rebuild_global_mesh();
639template<
class ELEMENT>
643 ofstream some_file,some_file2;
652 snprintf(filename,
sizeof(filename),
"%s/power%i.dat",doc_info.directory().c_str(),
654 some_file.open(filename);
658 unsigned nn_element=Helmholtz_power_boundary_mesh_pt->nelement();
659 for(
unsigned e=0;e<nn_element;e++)
661 PMLHelmholtzPowerElement<ELEMENT> *el_pt =
662 dynamic_cast<PMLHelmholtzPowerElement<ELEMENT>*
>(
663 Helmholtz_power_boundary_mesh_pt->element_pt(e));
664 power += el_pt->global_power_contribution(some_file);
667 oomph_info <<
"Total radiated power: " << power << std::endl;
671 snprintf(filename,
sizeof(filename),
"%s/soln%i.dat",doc_info.directory().c_str(),
673 some_file.open(filename);
674 Bulk_mesh_pt->output(some_file,npts);
679 snprintf(filename,
sizeof(filename),
"%s/exact_soln%i.dat",doc_info.directory().c_str(),
681 some_file.open(filename);
686 snprintf(filename,
sizeof(filename),
"%s/error%i.dat",doc_info.directory().c_str(),
688 some_file.open(filename);
694 oomph_info <<
"\nNorm of error : " << sqrt(error) << std::endl;
695 oomph_info <<
"Norm of solution: " << sqrt(norm) << std::endl << std::endl;
699 snprintf(filename,
sizeof(filename),
"%s/pml_soln%i.dat",doc_info.directory().c_str(),
701 some_file.open(filename);
702 PML_right_mesh_pt->output(some_file,npts);
703 PML_left_mesh_pt->output(some_file,npts);
704 PML_top_mesh_pt->output(some_file,npts);
705 PML_bottom_mesh_pt->output(some_file,npts);
706 PML_bottom_right_mesh_pt->output(some_file,npts);
707 PML_top_right_mesh_pt->output(some_file,npts);
708 PML_bottom_left_mesh_pt->output(some_file,npts);
709 PML_top_left_mesh_pt->output(some_file,npts);
716 Bulk_mesh_pt->compute_norm(norm2);
717 Trace_file << norm2 << std::endl;
746template<
class ELEMENT>
749 Mesh*
const & helmholtz_inner_boundary_mesh_pt)
752 unsigned n_element = bulk_mesh_pt->nboundary_element(b);
753 for(
unsigned e=0;e<n_element;e++)
756 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
757 bulk_mesh_pt->boundary_element_pt(b,e));
760 int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
763 PMLHelmholtzFluxElement<ELEMENT>* flux_element_pt =
new
764 PMLHelmholtzFluxElement<ELEMENT>(bulk_elem_pt,face_index);
767 helmholtz_inner_boundary_mesh_pt->add_element_pt(flux_element_pt);
770 flux_element_pt->flux_fct_pt() =
782template<
class ELEMENT>
785 Mesh*
const & helmholtz_power_boundary_mesh_pt)
788 unsigned n_element = bulk_mesh_pt->nboundary_element(b);
789 for(
unsigned e=0;e<n_element;e++)
792 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
793 bulk_mesh_pt->boundary_element_pt(b,e));
796 int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
799 PMLHelmholtzPowerElement<ELEMENT>* power_element_pt =
new
800 PMLHelmholtzPowerElement<ELEMENT>(bulk_elem_pt,face_index);
803 helmholtz_power_boundary_mesh_pt->add_element_pt(power_element_pt);
813template<
class ELEMENT>
818 unsigned int left_boundary_id = 2;
821 unsigned int top_boundary_id = 3;
824 unsigned int right_boundary_id = 4;
827 unsigned int bottom_boundary_id = 5;
830 unsigned n_x_right_pml = 3;
833 unsigned n_y_top_pml = 3;
836 unsigned n_x_left_pml = 3;
839 unsigned n_y_bottom_pml = 3;
844 double width_x_right_pml = 0.2;
845 double width_y_top_pml = 0.2;
846 double width_x_left_pml = 0.2;
847 double width_y_bottom_pml = 0.2;
851 TwoDimensionalPMLHelper::create_right_pml_mesh
852 <PMLLayerElement<ELEMENT> >
853 (Bulk_mesh_pt,right_boundary_id,
854 n_x_right_pml, width_x_right_pml);
856 TwoDimensionalPMLHelper::create_top_pml_mesh
857 <PMLLayerElement<ELEMENT> >
858 (Bulk_mesh_pt, top_boundary_id,
859 n_y_top_pml, width_y_top_pml);
861 TwoDimensionalPMLHelper::create_left_pml_mesh
862 <PMLLayerElement<ELEMENT> >
863 (Bulk_mesh_pt, left_boundary_id,
864 n_x_left_pml, width_x_left_pml);
866 TwoDimensionalPMLHelper::create_bottom_pml_mesh
867 <PMLLayerElement<ELEMENT> >
868 (Bulk_mesh_pt, bottom_boundary_id,
869 n_y_bottom_pml, width_y_bottom_pml);
872 add_sub_mesh(PML_right_mesh_pt);
873 add_sub_mesh(PML_top_mesh_pt);
874 add_sub_mesh(PML_left_mesh_pt);
875 add_sub_mesh(PML_bottom_mesh_pt);
878 PML_top_right_mesh_pt =
879 TwoDimensionalPMLHelper::create_top_right_pml_mesh
880 <PMLLayerElement<ELEMENT> >
881 (PML_right_mesh_pt, PML_top_mesh_pt,
882 Bulk_mesh_pt, right_boundary_id);
884 PML_bottom_right_mesh_pt =
885 TwoDimensionalPMLHelper::create_bottom_right_pml_mesh
886 <PMLLayerElement<ELEMENT> >
887 (PML_right_mesh_pt, PML_bottom_mesh_pt,
888 Bulk_mesh_pt, right_boundary_id);
890 PML_top_left_mesh_pt =
891 TwoDimensionalPMLHelper::create_top_left_pml_mesh
892 <PMLLayerElement<ELEMENT> >
893 (PML_left_mesh_pt, PML_top_mesh_pt,
894 Bulk_mesh_pt, left_boundary_id);
896 PML_bottom_left_mesh_pt =
897 TwoDimensionalPMLHelper::create_bottom_left_pml_mesh
898 <PMLLayerElement<ELEMENT> >
899 (PML_left_mesh_pt, PML_bottom_mesh_pt,
900 Bulk_mesh_pt, left_boundary_id);
903 add_sub_mesh(PML_top_right_mesh_pt);
904 add_sub_mesh(PML_bottom_right_mesh_pt);
905 add_sub_mesh(PML_top_left_mesh_pt);
906 add_sub_mesh(PML_bottom_left_mesh_pt);
925 <TPMLHelmholtzElement<2,3> > > problem;
939 doc_info.set_directory(
"RESLT");
945 unsigned max_adapt=1;
949 problem.newton_solve(max_adapt);
954 problem.newton_solve();
std::complex< double > gamma(const double &nu_i, const double &pml_width_i, const double &k_squared_local, const double &alpha_shift=0.0)
Overwrite the pure PML mapping coefficient function to return the coeffcients proposed by Bermudez et...
TestPMLMapping()
Default constructor (empty)
Problem class to demonstrate use of perfectly matched layers for Helmholtz problems.
Mesh * PML_bottom_left_mesh_pt
Pointer to the bottom left corner PML mesh.
void actions_before_newton_solve()
Update the problem specs before solve (empty)
void actions_before_adapt()
Actions before adapt: Wipe the PML meshes.
~PMLProblem()
Destructor (empty)
Mesh * PML_bottom_right_mesh_pt
Pointer to the bottom right corner PML mesh.
Mesh * PML_bottom_mesh_pt
Pointer to the bottom PML mesh.
ofstream Trace_file
Trace file.
void actions_after_adapt()
Actions after adapt: Rebuild the PML meshes.
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...
Mesh * Helmholtz_inner_boundary_mesh_pt
Pointer to the mesh containing the Helmholtz inner boundary condition elements.
Mesh * PML_top_mesh_pt
Pointer to the top PML mesh.
Mesh * PML_top_right_mesh_pt
Pointer to the top right corner PML mesh.
void create_pml_meshes()
Create PML meshes.
Mesh * PML_right_mesh_pt
Pointer to the right PML mesh.
Mesh * PML_top_left_mesh_pt
Pointer to the top left corner PML mesh.
Mesh * PML_left_mesh_pt
Pointer to the left PML mesh.
Mesh * Helmholtz_power_boundary_mesh_pt
Pointer to mesh of elements that compute the radiated power.
void actions_after_newton_solve()
Update the problem specs after solve (empty)
RefineableTriangleMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the refineable "bulk" mesh.
void doc_solution(DocInfo &doc_info)
Doc the solution. DocInfo object stores flags/labels for where the output gets written to.
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 ...
Namespace for the Helmholtz problem parameters.
void prescribed_incoming_flux(const Vector< double > &x, complex< double > &flux)
Flux (normal derivative) on the unit disk for a planar incoming wave.
double Wavenumber
Wavenumber (also known as k), k=omega/c.
TestPMLMapping * Test_pml_mapping_pt
std::complex< double > I(0.0, 1.0)
Imaginary unit.
double K_squared
Square of the wavenumber (also known as k^2)
void get_exact_u(const Vector< double > &x, Vector< double > &u)
Exact solution for scattered field (vector returns real and impaginary parts).
unsigned N_fourier
Number of terms used in the computation of the exact solution.
int main(int argc, char **argv)
Solve 2D Helmholtz problem.