35 #include "pml_fourier_decomposed_helmholtz.h"
38 #include "meshes/triangle_mesh.h"
41 #include "oomph_crbond_bessel.h"
43 using namespace oomph;
83 std::complex<double>
I(0.0,1.0);
91 double R=sqrt(x[0]*x[0]+x[1]*x[1]);
94 theta=atan2(x[0],x[1]);
100 double bessel_offset=0.5;
107 double order_max_in=double(
N_terms-1)+bessel_offset;
108 double order_max_out=0;
119 CRBond_Bessel::bessjyv(order_max_in,
127 complex<double> u_ex(0.0,0.0);
131 double p=Legendre_functions_helper::plgndr2(i,
N_fourier,
134 u_ex+=
Coeff[i]*sqrt(MathematicalConstants::Pi/(2.0*kr))*(jv[i]+
I*yv[i])*p;
152 flux=std::complex<double>(0.0,0.0);
155 double R=sqrt(x[0]*x[0]+x[1]*x[1]);
158 theta=atan2(x[0],x[1]);
164 double bessel_offset=0.5;
171 double order_max_in=double(
N_terms-1)+bessel_offset;
172 double order_max_out=0;
183 CRBond_Bessel::bessjyv(order_max_in,
192 complex<double> u_ex(0.0,0.0);
196 double p=Legendre_functions_helper::plgndr2(i,
N_fourier,
199 flux-=
Coeff[i]*sqrt(MathematicalConstants::Pi/(2.0*kr))*p*
200 ( K*(djv[i]+
I*dyv[i]) - (0.5*(jv[i]+
I*yv[i])/R) );
228 template<
class ELEMENT>
238 Point_source_magnitude=std::complex<double>(0.0,0.0);
245 void setup(
const Vector<double>& s_point_source,
246 const std::complex<double>& magnitude)
248 S_point_source=s_point_source;
249 Point_source_magnitude=magnitude;
258 ELEMENT::fill_in_generic_residual_contribution_pml_fourier_decomposed_helmholtz(
259 residuals,GeneralisedElement::Dummy_matrix,0);
262 fill_in_point_source_contribution_to_residuals(residuals);
269 DenseMatrix<double> &jacobian)
272 ELEMENT::fill_in_generic_residual_contribution_pml_fourier_decomposed_helmholtz(residuals,
276 fill_in_point_source_contribution_to_residuals(residuals);
287 if (S_point_source.size()==0)
return;
290 const unsigned n_node = this->nnode();
296 int local_eqn_real=0;
297 int local_eqn_imag=0;
300 this->shape(S_point_source,psi);
306 for(
unsigned l=0;l<n_node;l++)
313 this->nodal_local_eqn
314 (l,this->u_index_pml_fourier_decomposed_helmholtz().real());
317 if(local_eqn_real >= 0)
319 residuals[local_eqn_real] -= 2.0*Point_source_magnitude.real()*psi(l);
327 this->nodal_local_eqn
328 (l,this->u_index_pml_fourier_decomposed_helmholtz().imag());
331 if(local_eqn_imag >= 0)
334 residuals[local_eqn_imag] -= 2.0*Point_source_magnitude.imag()*psi(l);
354 template<
class ELEMENT>
356 :
public virtual FaceGeometry<ELEMENT>
367 template<
class ELEMENT>
369 :
public virtual FaceGeometry<FaceGeometry<ELEMENT> >
380 template<
class ELEMENT>
382 public virtual PMLLayerElement<ELEMENT>
400 template<
class ELEMENT>
401 class PMLLayerElement<
402 ProjectablePMLFourierDecomposedHelmholtzElement<
404 public virtual PMLLayerElement<ELEMENT>
428 template<
class ELEMENT>
448 void doc_solution(DocInfo& doc_info);
451 void create_pml_meshes();
454 void create_power_monitor_mesh();
459 void actions_before_adapt();
462 void actions_after_adapt();
468 void complete_problem_setup();
473 void create_flux_elements_on_inner_boundary();
479 unsigned n_element = boundary_mesh_pt->nelement();
480 for(
unsigned e=0;e<n_element;e++)
483 delete boundary_mesh_pt->element_pt(e);
487 boundary_mesh_pt->flush_element_and_node_storage();
491 void apply_zero_dirichlet_boundary_conditions();
500 void setup_point_source();
542 template<
class ELEMENT>
547 for (
unsigned b=1;b<4;b++)
550 unsigned n_element = Bulk_mesh_pt->nboundary_element(b);
551 for(
unsigned e=0;e<n_element;e++)
554 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
555 Bulk_mesh_pt->boundary_element_pt(b,e));
558 int face_index = Bulk_mesh_pt->face_index_at_boundary(b,e);
561 PMLFourierDecomposedHelmholtzPowerMonitorElement<ELEMENT>*
562 flux_element_pt =
new
563 PMLFourierDecomposedHelmholtzPowerMonitorElement<ELEMENT>
564 (bulk_elem_pt,face_index);
567 Power_monitor_mesh_pt->add_element_pt(flux_element_pt);
579 template<
class ELEMENT>
586 delete PML_right_mesh_pt;
588 delete PML_top_mesh_pt;
590 delete PML_bottom_mesh_pt;
591 PML_bottom_mesh_pt=0;
592 delete PML_top_right_mesh_pt;
593 PML_top_right_mesh_pt=0;
594 delete PML_bottom_right_mesh_pt;
595 PML_bottom_right_mesh_pt=0;
598 delete_face_elements(Power_monitor_mesh_pt);
605 add_sub_mesh(Bulk_mesh_pt);
608 rebuild_global_mesh();
617 template<
class ELEMENT>
626 create_power_monitor_mesh();
629 rebuild_global_mesh();
632 complete_problem_setup();
635 setup_point_source();
647 template<
class ELEMENT>
652 unsigned n_element = this->mesh_pt()->nelement();
653 for(
unsigned i=0;i<n_element;i++)
656 PMLFourierDecomposedHelmholtzEquations *el_pt =
dynamic_cast<
657 PMLFourierDecomposedHelmholtzEquations*
>(
658 mesh_pt()->element_pt(i));
675 <<
"Zero Dirichlet boundary condition has been applied on symmetry line\n";
676 cout <<
"due to an odd Fourier wavenumber\n" << std::endl;
677 apply_zero_dirichlet_boundary_conditions();
688 template<
class ELEMENT>
693 delete Mesh_as_geom_obj_pt;
694 Mesh_as_geom_obj_pt=
new MeshAsGeomObject(Bulk_mesh_pt);
697 Vector<double> x_point_source;
698 x_point_source.resize(2);
702 GeomObject* sub_geom_object_pt=0;
703 Vector<double> s_point_source(2);
704 Mesh_as_geom_obj_pt->locate_zeta(x_point_source,sub_geom_object_pt,
708 if(x_point_source[0]==0.0)
719 dynamic_cast<ELEMENT*
>(sub_geom_object_pt)->
730 template<
class ELEMENT>
743 unsigned n_node=Bulk_mesh_pt->nboundary_node(b);
744 for (
unsigned n=0;n<n_node;n++)
747 Node* nod_pt=Bulk_mesh_pt->boundary_node_pt(b,n);
754 nod_pt->set_value(0, 0.0);
755 nod_pt->set_value(1, 0.0);
765 unsigned n_node=Bulk_mesh_pt->nboundary_node(b);
766 for (
unsigned n=0;n<n_node;n++)
769 Node* nod_pt=Bulk_mesh_pt->boundary_node_pt(b,n);
776 nod_pt->set_value(0, 0.0);
777 nod_pt->set_value(1, 0.0);
788 template<
class ELEMENT>
795 Trace_file.open(trace_file_location.c_str());
804 Circle* inner_circle_pt=
new Circle(x_c,y_c,r_min);
809 Vector<TriangleMeshCurveSection*> outer_boundary_line_pt(6);
812 Vector<Vector<double> > boundary_vertices(2);
817 boundary_vertices[0].resize(2);
818 boundary_vertices[0][0]=0.0;
819 boundary_vertices[0][1]=-r_min;
820 boundary_vertices[1].resize(2);
821 boundary_vertices[1][0]=0.0;
822 boundary_vertices[1][1]=-r_max;
824 unsigned boundary_id=0;
825 outer_boundary_line_pt[0]=
826 new TriangleMeshPolyLine(boundary_vertices,boundary_id);
831 boundary_vertices[0][0]=0.0;
832 boundary_vertices[0][1]=-r_max;
833 boundary_vertices[1][0]=r_max;;
834 boundary_vertices[1][1]=-r_max;
837 outer_boundary_line_pt[1]=
838 new TriangleMeshPolyLine(boundary_vertices,boundary_id);
843 boundary_vertices[0][0]=r_max;
844 boundary_vertices[0][1]=-r_max;
845 boundary_vertices[1][0]=r_max;;
846 boundary_vertices[1][1]=r_max;
849 outer_boundary_line_pt[2]=
850 new TriangleMeshPolyLine(boundary_vertices,boundary_id);
855 boundary_vertices[0][0]=r_max;
856 boundary_vertices[0][1]=r_max;
857 boundary_vertices[1][0]=0.0;
858 boundary_vertices[1][1]=r_max;
861 outer_boundary_line_pt[3]=
862 new TriangleMeshPolyLine(boundary_vertices,boundary_id);
866 boundary_vertices[0][0]=0.0;
867 boundary_vertices[0][1]=r_max;
868 boundary_vertices[1][0]=0.0;
869 boundary_vertices[1][1]=r_min;
872 outer_boundary_line_pt[4]=
873 new TriangleMeshPolyLine(boundary_vertices,boundary_id);
880 unsigned n_segments = 20;
883 double s_start = 0.5*MathematicalConstants::Pi;
884 double s_end = -0.5*MathematicalConstants::Pi;
887 outer_boundary_line_pt[5]=
888 new TriangleMeshCurviLine(inner_circle_pt,
897 TriangleMeshClosedCurve *outer_boundary_pt =
898 new TriangleMeshClosedCurve(outer_boundary_line_pt);
904 TriangleMeshParameters triangle_mesh_parameters(outer_boundary_pt);
909 triangle_mesh_parameters.element_area() = element_area;
914 Bulk_mesh_pt=
new RefineableTriangleMesh<ELEMENT>(triangle_mesh_parameters);
917 add_sub_mesh(Bulk_mesh_pt);
920 Mesh_as_geom_obj_pt=0;
923 Bulk_mesh_pt->spatial_error_estimator_pt()=
new Z2ErrorEstimator;
926 Bulk_mesh_pt->min_permitted_error()=0.00004;
927 Bulk_mesh_pt->max_permitted_error()=0.0001;
935 Bulk_mesh_pt=
new TriangleMesh<ELEMENT>(triangle_mesh_parameters);
938 add_sub_mesh(Bulk_mesh_pt);
941 Helmholtz_inner_boundary_mesh_pt=
new Mesh;
942 create_flux_elements_on_inner_boundary();
945 add_sub_mesh(Helmholtz_inner_boundary_mesh_pt);
951 Power_monitor_mesh_pt=
new Mesh;
952 create_power_monitor_mesh();
961 complete_problem_setup();
964 cout <<
"Number of equations: " << assign_eqn_numbers() << std::endl;
973 template<
class ELEMENT>
990 sprintf(filename,
"%s/power%i.dat",doc_info.directory().c_str(),
992 some_file.open(filename);
995 unsigned nn_element=Power_monitor_mesh_pt->nelement();
996 for(
unsigned e=0;e<nn_element;e++)
998 PMLFourierDecomposedHelmholtzPowerMonitorElement<ELEMENT> *el_pt =
999 dynamic_cast<PMLFourierDecomposedHelmholtzPowerMonitorElement
1000 <ELEMENT
>*>(Power_monitor_mesh_pt->element_pt(e));
1001 power += el_pt->global_power_contribution(some_file);
1004 oomph_info <<
"Total radiated power: " << power << std::endl;
1009 sprintf(filename,
"%s/soln%i.dat",doc_info.directory().c_str(),
1011 some_file.open(filename);
1012 Bulk_mesh_pt->output(some_file,npts);
1017 sprintf(filename,
"%s/pml_soln%i.dat",doc_info.directory().c_str(),
1019 some_file.open(filename);
1020 PML_top_mesh_pt->output(some_file,npts);
1021 PML_right_mesh_pt->output(some_file,npts);
1022 PML_bottom_mesh_pt->output(some_file,npts);
1023 PML_top_right_mesh_pt->output(some_file,npts);
1024 PML_bottom_right_mesh_pt->output(some_file,npts);
1030 sprintf(filename,
"%s/exact_soln%i.dat",doc_info.directory().c_str(),
1032 some_file.open(filename);
1040 sprintf(filename,
"%s/error%i.dat",doc_info.directory().c_str(),
1042 some_file.open(filename);
1048 cout <<
"\nNorm of error : " << sqrt(error) << std::endl;
1049 cout <<
"Norm of solution: " << sqrt(norm) << std::endl << std::endl;
1051 sprintf(filename,
"%s/int_error%i.dat",doc_info.directory().c_str(),
1053 some_file.open(filename);
1055 some_file <<
"\nNorm of error : " << sqrt(error) << std::endl;
1056 some_file <<
"Norm of solution: " << sqrt(norm) << std::endl <<std::endl;
1057 some_file <<
"Relative error: " << sqrt(error)/sqrt(norm) << std::endl;
1061 Bulk_mesh_pt->compute_norm(norm);
1062 Trace_file << norm <<
" " << power << std::endl;
1070 template<
class ELEMENT>
1078 unsigned n_element = Bulk_mesh_pt->nboundary_element(b);
1079 for(
unsigned e=0;e<n_element;e++)
1082 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
1083 Bulk_mesh_pt->boundary_element_pt(b,e));
1086 int face_index = Bulk_mesh_pt->face_index_at_boundary(b,e);
1089 PMLFourierDecomposedHelmholtzFluxElement<ELEMENT>*
1090 flux_element_pt =
new
1091 PMLFourierDecomposedHelmholtzFluxElement<ELEMENT>
1092 (bulk_elem_pt,face_index);
1095 Helmholtz_inner_boundary_mesh_pt->add_element_pt(flux_element_pt);
1109 template<
class ELEMENT>
1113 unsigned int bottom_boundary_id = 1;
1116 unsigned int right_boundary_id = 2;
1119 unsigned int top_boundary_id = 3;
1138 PML_right_mesh_pt = TwoDimensionalPMLHelper::create_right_pml_mesh
1139 <PMLLayerElement<ELEMENT> >(Bulk_mesh_pt,
1143 PML_top_mesh_pt = TwoDimensionalPMLHelper::create_top_pml_mesh
1144 <PMLLayerElement<ELEMENT> >(Bulk_mesh_pt,
1148 PML_bottom_mesh_pt= TwoDimensionalPMLHelper::create_bottom_pml_mesh
1149 <PMLLayerElement<ELEMENT> >(Bulk_mesh_pt,
1152 width_y_bottom_pml);
1155 add_sub_mesh(PML_right_mesh_pt);
1156 add_sub_mesh(PML_top_mesh_pt);
1157 add_sub_mesh(PML_bottom_mesh_pt);
1160 PML_top_right_mesh_pt =
1161 TwoDimensionalPMLHelper::create_top_right_pml_mesh
1162 <PMLLayerElement<ELEMENT> >(PML_right_mesh_pt,
1167 PML_bottom_right_mesh_pt =
1168 TwoDimensionalPMLHelper::create_bottom_right_pml_mesh
1169 <PMLLayerElement<ELEMENT> >(PML_right_mesh_pt,
1175 add_sub_mesh(PML_top_right_mesh_pt);
1176 add_sub_mesh(PML_bottom_right_mesh_pt);
1187 CommandLineArgs::setup(argc,argv);
1193 CommandLineArgs::specify_command_line_flag(
"--Fourier_wavenumber",
1197 CommandLineArgs::specify_command_line_flag(
"--dir",
1201 CommandLineArgs::specify_command_line_flag(
"--pml_thick",
1205 CommandLineArgs::specify_command_line_flag(
"--npml_element",
1209 CommandLineArgs::specify_command_line_flag(
"--element_area",
1212 CommandLineArgs::specify_command_line_flag(
"--k_squared",
1216 CommandLineArgs::specify_command_line_flag(
"--validate");
1221 CommandLineArgs::specify_command_line_flag(
"--demonstrate");
1224 CommandLineArgs::parse_and_assign();
1227 CommandLineArgs::doc_specified_flags();
1243 ProjectablePMLFourierDecomposedHelmholtzElement<
1245 TPMLFourierDecomposedHelmholtzElement<3> > > > problem;
1252 <TPMLFourierDecomposedHelmholtzElement<3> >
1263 unsigned max_adapt=4;
1266 if (CommandLineArgs::command_line_flag_has_been_set(
"--validate"))
1273 problem.newton_solve(max_adapt);
1279 problem.newton_solve();
1286 problem.doc_solution(doc_info);
////////////////////////////////////////////////////////////////// //////////////////////////////////...
void actions_after_newton_solve()
Update the problem after solve (empty)
Mesh * PML_right_mesh_pt
Pointer to the right PML mesh.
MeshAsGeomObject * Mesh_as_geom_obj_pt
Mesh as geometric object representation of bulk mesh.
void delete_face_elements(Mesh *const &boundary_mesh_pt)
Delete boundary face elements and wipe the surface mesh.
Mesh * PML_top_mesh_pt
Pointer to the top PML mesh.
PMLFourierDecomposedHelmholtzProblem()
Constructor.
TriangleMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
Mesh * Helmholtz_inner_boundary_mesh_pt
Mesh of FaceElements that apply the flux bc on the inner boundary.
void setup_point_source()
Set point source.
void create_power_monitor_mesh()
Create mesh of face elements that monitor the radiated power.
Mesh * PML_bottom_right_mesh_pt
Pointer to the bottom right corner PML mesh.
ofstream Trace_file
Trace file.
Mesh * Power_monitor_mesh_pt
Pointer to mesh that stores the power monitor elements.
~PMLFourierDecomposedHelmholtzProblem()
Destructor (empty)
void complete_problem_setup()
void actions_after_adapt()
Actions after adapt: Rebuild the mesh of prescribed flux elements.
RefineableTriangleMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the refineable "bulk" mesh.
Mesh * PML_bottom_mesh_pt
Pointer to the bottom PML mesh.
void apply_zero_dirichlet_boundary_conditions()
void actions_before_adapt()
Actions before adapt: Wipe the mesh of prescribed flux elements.
void create_pml_meshes()
Create PML meshes.
Mesh * PML_top_right_mesh_pt
Pointer to the top right corner PML mesh.
void actions_before_newton_solve()
Update the problem specs before solve (empty)
void doc_solution(DocInfo &doc_info)
Doc the solution. DocInfo object stores flags/labels for where the output gets written to.
void create_flux_elements_on_inner_boundary()
Create flux elements on inner boundary.
Class to impose point source to (wrapped) Helmholtz element.
PMLHelmholtzPointSourceElement()
Constructor.
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Add the element's contribution to its residual vector and element Jacobian matrix (wrapper)
~PMLHelmholtzPointSourceElement()
Destructor (empty)
void fill_in_point_source_contribution_to_residuals(Vector< double > &residuals)
Add the point source contribution to the residual vector.
std::complex< double > Point_source_magnitude
Magnitude of point source (complex!)
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Add the element's contribution to its residual vector (wrapper)
void setup(const Vector< double > &s_point_source, const std::complex< double > &magnitude)
Set local coordinate and magnitude of point source.
Vector< double > S_point_source
Local coordinates of point at which point source is applied.
PMLLayerElement()
Constructor: Call the constructor for the appropriate Element.
PMLLayerElement()
Constructor: Call the constructor for the appropriate Element.
////////////////////////////////////////////////////////////////// //////////////////////////////////...
Vector< double > Coeff(N_terms, 1.0)
Coefficients in the exact solution.
double Z_source
Axial position of point source.
double R_source
Radial position of point source.
unsigned N_terms
Number of terms in the exact solution.
std::complex< double > I(0.0, 1.0)
Imaginary unit.
string Directory
Output directory.
double K_squared
Frequency.
void exact_minus_dudr(const Vector< double > &x, std::complex< double > &flux)
Get -du/dr (spherical r) for exact solution. Equal to prescribed flux on inner boundary.
int N_fourier
The default Fourier wave number.
double Element_area
Target area for initial mesh.
std::complex< double > Magnitude(100.0, 100.0)
Point source magnitude (Complex)
double PML_thickness
Default physical PML thickness.
unsigned Nel_pml
Default number of elements within PMLs.
void get_exact_u(const Vector< double > &x, Vector< double > &u)
Exact solution as a Vector of size 2, containing real and imag parts.
////////////////////////////////////////////////////////////////// //////////////////////////////////...
int main(int argc, char **argv)
Driver code for Pml Fourier decomposed Helmholtz problem.