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.