39 #include "pml_fourier_decomposed_helmholtz.h" 42 #include "meshes/triangle_mesh.h" 45 #include "oomph_crbond_bessel.h" 47 using namespace oomph;
84 Vector<double>
Coeff(N_terms,1.0);
87 std::complex<double>
I(0.0,1.0);
92 double K = sqrt(K_squared);
95 double R=sqrt(x[0]*x[0]+x[1]*x[1]);
98 theta=atan2(x[0],x[1]);
104 double bessel_offset=0.5;
107 Vector<double> jv(N_terms);
108 Vector<double> yv(N_terms);
109 Vector<double> djv(N_terms);
110 Vector<double> dyv(N_terms);
111 double order_max_in=double(N_terms-1)+bessel_offset;
112 double order_max_out=0;
123 CRBond_Bessel::bessjyv(order_max_in,
131 complex<double> u_ex(0.0,0.0);
132 for(
unsigned i=N_fourier;i<
N_terms;i++)
135 double p=Legendre_functions_helper::plgndr2(i,N_fourier,
138 u_ex+=
Coeff[i]*sqrt(MathematicalConstants::Pi/(2.0*kr))*(jv[i]+
I*yv[i])*p;
153 double K = sqrt(K_squared);
156 flux=std::complex<double>(0.0,0.0);
159 double R=sqrt(x[0]*x[0]+x[1]*x[1]);
162 theta=atan2(x[0],x[1]);
168 double bessel_offset=0.5;
171 Vector<double> jv(N_terms);
172 Vector<double> yv(N_terms);
173 Vector<double> djv(N_terms);
174 Vector<double> dyv(N_terms);
175 double order_max_in=double(N_terms-1)+bessel_offset;
176 double order_max_out=0;
187 CRBond_Bessel::bessjyv(order_max_in,
196 complex<double> u_ex(0.0,0.0);
197 for(
unsigned i=N_fourier;i<
N_terms;i++)
200 double p=Legendre_functions_helper::plgndr2(i,N_fourier,
203 flux-=
Coeff[i]*sqrt(MathematicalConstants::Pi/(2.0*kr))*p*
204 ( K*(djv[i]+
I*dyv[i]) - (0.5*(jv[i]+
I*yv[i])/R) );
216 std::complex<double>
Magnitude(100.0,100.0);
232 template<
class ELEMENT>
242 Point_source_magnitude=std::complex<double>(0.0,0.0);
249 void setup(
const Vector<double>& s_point_source,
250 const std::complex<double>& magnitude)
252 S_point_source=s_point_source;
253 Point_source_magnitude=magnitude;
262 ELEMENT::fill_in_generic_residual_contribution_pml_fourier_decomposed_helmholtz(
263 residuals,GeneralisedElement::Dummy_matrix,0);
266 fill_in_point_source_contribution_to_residuals(residuals);
273 DenseMatrix<double> &jacobian)
276 ELEMENT::fill_in_generic_residual_contribution_pml_fourier_decomposed_helmholtz(residuals,
280 fill_in_point_source_contribution_to_residuals(residuals);
291 if (S_point_source.size()==0)
return;
294 const unsigned n_node = this->nnode();
300 int local_eqn_real=0;
301 int local_eqn_imag=0;
304 this->shape(S_point_source,psi);
310 for(
unsigned l=0;l<n_node;l++)
317 this->nodal_local_eqn
318 (l,this->u_index_pml_fourier_decomposed_helmholtz().real());
321 if(local_eqn_real >= 0)
323 residuals[local_eqn_real] -= 2.0*Point_source_magnitude.real()*psi(l);
331 this->nodal_local_eqn
332 (l,this->u_index_pml_fourier_decomposed_helmholtz().imag());
335 if(local_eqn_imag >= 0)
338 residuals[local_eqn_imag] -= 2.0*Point_source_magnitude.imag()*psi(l);
358 template<
class ELEMENT>
360 :
public virtual FaceGeometry<ELEMENT>
371 template<
class ELEMENT>
373 :
public virtual FaceGeometry<FaceGeometry<ELEMENT> >
384 template<
class ELEMENT>
386 public virtual EquivalentQElement<ELEMENT>
404 template<
class ELEMENT>
405 class EquivalentQElement<
406 ProjectablePMLFourierDecomposedHelmholtzElement<
408 public virtual EquivalentQElement<ELEMENT>
432 template<
class ELEMENT>
452 void doc_solution(DocInfo& doc_info);
455 void create_pml_meshes();
458 void create_power_monitor_mesh();
463 void actions_before_adapt();
466 void actions_after_adapt();
472 void complete_problem_setup();
477 void create_flux_elements_on_inner_boundary();
483 unsigned n_element = boundary_mesh_pt->nelement();
484 for(
unsigned e=0;e<n_element;e++)
487 delete boundary_mesh_pt->element_pt(e);
491 boundary_mesh_pt->flush_element_and_node_storage();
495 void apply_zero_dirichlet_boundary_conditions();
504 void setup_point_source();
546 template<
class ELEMENT>
551 for (
unsigned b=1;b<4;b++)
554 unsigned n_element = Bulk_mesh_pt->nboundary_element(b);
555 for(
unsigned e=0;e<n_element;e++)
558 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
559 Bulk_mesh_pt->boundary_element_pt(b,e));
562 int face_index = Bulk_mesh_pt->face_index_at_boundary(b,e);
565 PMLFourierDecomposedHelmholtzPowerMonitorElement<ELEMENT>*
566 flux_element_pt =
new 567 PMLFourierDecomposedHelmholtzPowerMonitorElement<ELEMENT>
568 (bulk_elem_pt,face_index);
571 Power_monitor_mesh_pt->add_element_pt(flux_element_pt);
583 template<
class ELEMENT>
590 delete PML_right_mesh_pt;
592 delete PML_top_mesh_pt;
594 delete PML_bottom_mesh_pt;
595 PML_bottom_mesh_pt=0;
596 delete PML_top_right_mesh_pt;
597 PML_top_right_mesh_pt=0;
598 delete PML_bottom_right_mesh_pt;
599 PML_bottom_right_mesh_pt=0;
602 delete_face_elements(Power_monitor_mesh_pt);
609 add_sub_mesh(Bulk_mesh_pt);
612 rebuild_global_mesh();
621 template<
class ELEMENT>
630 create_power_monitor_mesh();
633 rebuild_global_mesh();
636 complete_problem_setup();
639 setup_point_source();
651 template<
class ELEMENT>
656 unsigned n_element = this->mesh_pt()->nelement();
657 for(
unsigned i=0;i<n_element;i++)
660 PMLFourierDecomposedHelmholtzEquationsBase *el_pt
661 =
dynamic_cast<PMLFourierDecomposedHelmholtzEquationsBase*
>(
662 mesh_pt()->element_pt(i));
679 <<
"Zero Dirichlet boundary condition has been applied on symmetry line\n";
680 cout <<
"due to an odd Fourier wavenumber\n" << std::endl;
681 apply_zero_dirichlet_boundary_conditions();
692 template<
class ELEMENT>
697 delete Mesh_as_geom_obj_pt;
698 Mesh_as_geom_obj_pt=
new MeshAsGeomObject(Bulk_mesh_pt);
701 Vector<double> x_point_source;
702 x_point_source.resize(2);
706 GeomObject* sub_geom_object_pt=0;
707 Vector<double> s_point_source(2);
708 Mesh_as_geom_obj_pt->locate_zeta(x_point_source,sub_geom_object_pt,
712 if(x_point_source[0]==0.0)
723 dynamic_cast<ELEMENT*
>(sub_geom_object_pt)->
734 template<
class ELEMENT>
747 unsigned n_node=Bulk_mesh_pt->nboundary_node(b);
748 for (
unsigned n=0;n<n_node;n++)
751 Node* nod_pt=Bulk_mesh_pt->boundary_node_pt(b,n);
758 nod_pt->set_value(0, 0.0);
759 nod_pt->set_value(1, 0.0);
769 unsigned n_node=Bulk_mesh_pt->nboundary_node(b);
770 for (
unsigned n=0;n<n_node;n++)
773 Node* nod_pt=Bulk_mesh_pt->boundary_node_pt(b,n);
780 nod_pt->set_value(0, 0.0);
781 nod_pt->set_value(1, 0.0);
792 template<
class ELEMENT>
799 Trace_file.open(trace_file_location.c_str());
808 Circle* inner_circle_pt=
new Circle(x_c,y_c,r_min);
813 Vector<TriangleMeshCurveSection*> outer_boundary_line_pt(6);
816 Vector<Vector<double> > boundary_vertices(2);
821 boundary_vertices[0].resize(2);
822 boundary_vertices[0][0]=0.0;
823 boundary_vertices[0][1]=-r_min;
824 boundary_vertices[1].resize(2);
825 boundary_vertices[1][0]=0.0;
826 boundary_vertices[1][1]=-r_max;
828 unsigned boundary_id=0;
829 outer_boundary_line_pt[0]=
830 new TriangleMeshPolyLine(boundary_vertices,boundary_id);
835 boundary_vertices[0][0]=0.0;
836 boundary_vertices[0][1]=-r_max;
837 boundary_vertices[1][0]=r_max;;
838 boundary_vertices[1][1]=-r_max;
841 outer_boundary_line_pt[1]=
842 new TriangleMeshPolyLine(boundary_vertices,boundary_id);
847 boundary_vertices[0][0]=r_max;
848 boundary_vertices[0][1]=-r_max;
849 boundary_vertices[1][0]=r_max;;
850 boundary_vertices[1][1]=r_max;
853 outer_boundary_line_pt[2]=
854 new TriangleMeshPolyLine(boundary_vertices,boundary_id);
859 boundary_vertices[0][0]=r_max;
860 boundary_vertices[0][1]=r_max;
861 boundary_vertices[1][0]=0.0;
862 boundary_vertices[1][1]=r_max;
865 outer_boundary_line_pt[3]=
866 new TriangleMeshPolyLine(boundary_vertices,boundary_id);
870 boundary_vertices[0][0]=0.0;
871 boundary_vertices[0][1]=r_max;
872 boundary_vertices[1][0]=0.0;
873 boundary_vertices[1][1]=r_min;
876 outer_boundary_line_pt[4]=
877 new TriangleMeshPolyLine(boundary_vertices,boundary_id);
884 unsigned n_segments = 20;
887 double s_start = 0.5*MathematicalConstants::Pi;
888 double s_end = -0.5*MathematicalConstants::Pi;
891 outer_boundary_line_pt[5]=
892 new TriangleMeshCurviLine(inner_circle_pt,
901 TriangleMeshClosedCurve *outer_boundary_pt =
902 new TriangleMeshClosedCurve(outer_boundary_line_pt);
908 TriangleMeshParameters triangle_mesh_parameters(outer_boundary_pt);
913 triangle_mesh_parameters.element_area() = element_area;
918 Bulk_mesh_pt=
new RefineableTriangleMesh<ELEMENT>(triangle_mesh_parameters);
921 add_sub_mesh(Bulk_mesh_pt);
924 Mesh_as_geom_obj_pt=0;
927 Bulk_mesh_pt->spatial_error_estimator_pt()=
new Z2ErrorEstimator;
930 Bulk_mesh_pt->min_permitted_error()=0.00004;
931 Bulk_mesh_pt->max_permitted_error()=0.0001;
939 Bulk_mesh_pt=
new TriangleMesh<ELEMENT>(triangle_mesh_parameters);
942 add_sub_mesh(Bulk_mesh_pt);
945 Helmholtz_inner_boundary_mesh_pt=
new Mesh;
946 create_flux_elements_on_inner_boundary();
949 add_sub_mesh(Helmholtz_inner_boundary_mesh_pt);
955 Power_monitor_mesh_pt=
new Mesh;
956 create_power_monitor_mesh();
965 complete_problem_setup();
968 cout <<
"Number of equations: " << assign_eqn_numbers() << std::endl;
977 template<
class ELEMENT>
994 sprintf(filename,
"%s/power%i.dat",doc_info.directory().c_str(),
996 some_file.open(filename);
999 unsigned nn_element=Power_monitor_mesh_pt->nelement();
1000 for(
unsigned e=0;e<nn_element;e++)
1002 PMLFourierDecomposedHelmholtzPowerMonitorElement<ELEMENT> *el_pt =
1003 dynamic_cast<PMLFourierDecomposedHelmholtzPowerMonitorElement
1004 <ELEMENT
>*>(Power_monitor_mesh_pt->element_pt(e));
1005 power += el_pt->global_power_contribution(some_file);
1008 oomph_info <<
"Total radiated power: " << power << std::endl;
1013 sprintf(filename,
"%s/soln%i.dat",doc_info.directory().c_str(),
1015 some_file.open(filename);
1016 Bulk_mesh_pt->output(some_file,npts);
1021 sprintf(filename,
"%s/pml_soln%i.dat",doc_info.directory().c_str(),
1023 some_file.open(filename);
1024 PML_top_mesh_pt->output(some_file,npts);
1025 PML_right_mesh_pt->output(some_file,npts);
1026 PML_bottom_mesh_pt->output(some_file,npts);
1027 PML_top_right_mesh_pt->output(some_file,npts);
1028 PML_bottom_right_mesh_pt->output(some_file,npts);
1034 sprintf(filename,
"%s/exact_soln%i.dat",doc_info.directory().c_str(),
1036 some_file.open(filename);
1044 sprintf(filename,
"%s/error%i.dat",doc_info.directory().c_str(),
1046 some_file.open(filename);
1052 cout <<
"\nNorm of error : " << sqrt(error) << std::endl;
1053 cout <<
"Norm of solution: " << sqrt(norm) << std::endl << std::endl;
1055 sprintf(filename,
"%s/int_error%i.dat",doc_info.directory().c_str(),
1057 some_file.open(filename);
1059 some_file <<
"\nNorm of error : " << sqrt(error) << std::endl;
1060 some_file <<
"Norm of solution: " << sqrt(norm) << std::endl <<std::endl;
1061 some_file <<
"Relative error: " << sqrt(error)/sqrt(norm) << std::endl;
1065 Bulk_mesh_pt->compute_norm(norm);
1066 Trace_file << norm <<
" " << power << std::endl;
1074 template<
class ELEMENT>
1082 unsigned n_element = Bulk_mesh_pt->nboundary_element(b);
1083 for(
unsigned e=0;e<n_element;e++)
1086 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
1087 Bulk_mesh_pt->boundary_element_pt(b,e));
1090 int face_index = Bulk_mesh_pt->face_index_at_boundary(b,e);
1093 PMLFourierDecomposedHelmholtzFluxElement<ELEMENT>*
1094 flux_element_pt =
new 1095 PMLFourierDecomposedHelmholtzFluxElement<ELEMENT>
1096 (bulk_elem_pt,face_index);
1099 Helmholtz_inner_boundary_mesh_pt->add_element_pt(flux_element_pt);
1113 template<
class ELEMENT>
1117 unsigned int bottom_boundary_id = 1;
1120 unsigned int right_boundary_id = 2;
1123 unsigned int top_boundary_id = 3;
1142 PML_right_mesh_pt = TwoDimensionalPMLHelper::create_right_pml_mesh
1143 <EquivalentQElement<ELEMENT> >(Bulk_mesh_pt,
1147 PML_top_mesh_pt = TwoDimensionalPMLHelper::create_top_pml_mesh
1148 <EquivalentQElement<ELEMENT> >(Bulk_mesh_pt,
1152 PML_bottom_mesh_pt= TwoDimensionalPMLHelper::create_bottom_pml_mesh
1153 <EquivalentQElement<ELEMENT> >(Bulk_mesh_pt,
1156 width_y_bottom_pml);
1159 add_sub_mesh(PML_right_mesh_pt);
1160 add_sub_mesh(PML_top_mesh_pt);
1161 add_sub_mesh(PML_bottom_mesh_pt);
1164 PML_top_right_mesh_pt =
1165 TwoDimensionalPMLHelper::create_top_right_pml_mesh
1166 <EquivalentQElement<ELEMENT> >(PML_right_mesh_pt,
1171 PML_bottom_right_mesh_pt =
1172 TwoDimensionalPMLHelper::create_bottom_right_pml_mesh
1173 <EquivalentQElement<ELEMENT> >(PML_right_mesh_pt,
1179 add_sub_mesh(PML_top_right_mesh_pt);
1180 add_sub_mesh(PML_bottom_right_mesh_pt);
1191 CommandLineArgs::setup(argc,argv);
1197 CommandLineArgs::specify_command_line_flag(
"--Fourier_wavenumber",
1201 CommandLineArgs::specify_command_line_flag(
"--dir",
1205 CommandLineArgs::specify_command_line_flag(
"--pml_thick",
1209 CommandLineArgs::specify_command_line_flag(
"--npml_element",
1213 CommandLineArgs::specify_command_line_flag(
"--element_area",
1216 CommandLineArgs::specify_command_line_flag(
"--k_squared",
1220 CommandLineArgs::specify_command_line_flag(
"--validate");
1225 CommandLineArgs::specify_command_line_flag(
"--demonstrate");
1228 CommandLineArgs::parse_and_assign();
1231 CommandLineArgs::doc_specified_flags();
1247 ProjectablePMLFourierDecomposedHelmholtzElement<
1249 TPMLFourierDecomposedHelmholtzElement<3,AxisAlignedPMLElement<2> > > > > problem;
1256 <TPMLFourierDecomposedHelmholtzElement<3,AxisAlignedPMLElement<2> > >
1267 unsigned max_adapt=4;
1270 if (CommandLineArgs::command_line_flag_has_been_set(
"--validate"))
1277 problem.newton_solve(max_adapt);
1283 problem.newton_solve();
1290 problem.doc_solution(doc_info);
Mesh * Helmholtz_inner_boundary_mesh_pt
Mesh of FaceElements that apply the flux bc on the inner boundary.
~PMLHelmholtzPointSourceElement()
Destructor (empty)
unsigned N_terms
Number of terms in the exact solution.
void setup(const Vector< double > &s_point_source, const std::complex< double > &magnitude)
Set local coordinate and magnitude of point source.
Mesh * PML_top_mesh_pt
Pointer to the top PML mesh.
void delete_face_elements(Mesh *const &boundary_mesh_pt)
Delete boundary face elements and wipe the surface mesh.
double Z_source
Axial position of point source.
MeshAsGeomObject * Mesh_as_geom_obj_pt
Mesh as geometric object representation of bulk mesh.
TriangleMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
Namespace for the Fourier decomposed Helmholtz problem parameters.
void apply_zero_dirichlet_boundary_conditions()
double Element_area
Target area for initial mesh.
void fill_in_point_source_contribution_to_residuals(Vector< double > &residuals)
Add the point source contribution to the residual vector.
Class to impose point source to (wrapped) Helmholtz element.
Vector< double > Coeff(N_terms, 1.0)
Coefficients in the exact solution.
double PML_thickness
Default physical PML thickness.
RefineableTriangleMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the refineable "bulk" mesh.
Mesh * PML_right_mesh_pt
Pointer to the right PML mesh.
void create_pml_meshes()
Create PML meshes.
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) ...
void actions_before_newton_solve()
Update the problem specs before solve (empty)
unsigned Nel_pml
Default number of elements within PMLs.
double R_source
Radial position of point source.
string Directory
Output directory.
void doc_solution(DocInfo &doc_info)
Doc the solution. DocInfo object stores flags/labels for where the output gets written to...
std::complex< double > I(0.0, 1.0)
Imaginary unit.
void actions_before_adapt()
Actions before adapt: Wipe the mesh of prescribed flux elements.
Mesh * PML_bottom_mesh_pt
Pointer to the bottom PML mesh.
void actions_after_newton_solve()
Update the problem after solve (empty)
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Add the element's contribution to its residual vector (wrapper)
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.
void setup_point_source()
Set point source.
double K_squared
Frequency.
Mesh * Power_monitor_mesh_pt
Pointer to mesh that stores the power monitor elements.
void actions_after_adapt()
Actions after adapt: Rebuild the mesh of prescribed flux elements.
std::complex< double > Point_source_magnitude
Magnitude of point source (complex!)
int N_fourier
The default Fourier wave number.
~PMLFourierDecomposedHelmholtzProblem()
Destructor (empty)
EquivalentQElement()
Constructor: Call the constructor for the appropriate Element.
void complete_problem_setup()
PMLHelmholtzPointSourceElement()
Constructor.
Mesh * PML_bottom_right_mesh_pt
Pointer to the bottom right corner PML mesh.
std::complex< double > Magnitude(100.0, 100.0)
Point source magnitude (Complex)
void create_flux_elements_on_inner_boundary()
Create flux elements on inner boundary.
Vector< double > S_point_source
Local coordinates of point at which point source is applied.
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.
ofstream Trace_file
Trace file.
PMLFourierDecomposedHelmholtzProblem()
Constructor.
void create_power_monitor_mesh()
Create mesh of face elements that monitor the radiated power.
Mesh * PML_top_right_mesh_pt
Pointer to the top right corner PML mesh.
EquivalentQElement()
Constructor: Call the constructor for the appropriate Element.