32 #ifndef OOMPH_HELMHOLTZ_BC_ELEMENTS_HEADER 33 #define OOMPH_HELMHOLTZ_BC_ELEMENTS_HEADER 37 #include <oomph-lib-config.h> 44 #include "oomph_crbond_bessel.h" 59 namespace Hankel_functions_for_helmholtz_problem
68 Vector<std::complex<double> >& h,
69 Vector<std::complex<double> >& hp)
73 CRBond_Bessel::bessjyna(
int(n),x,n_actual,&jn[0],&yn[0],&jnp[0],&ynp[0]);
79 std::ostringstream error_stream;
80 error_stream <<
"CRBond_Bessel::bessjyna() only computed " 81 << n_actual <<
" rather than " << n
82 <<
" Bessel functions.\n";
84 OOMPH_CURRENT_FUNCTION,
85 OOMPH_EXCEPTION_LOCATION);
88 for (
unsigned i=0;
i<=n;
i++)
104 const std::complex<double>& x,
105 Vector<std::complex<double> >& h,
106 Vector<std::complex<double> >& hp)
124 CRBond_Bessel::cbessjyna(
int(n),x,n_actual,&jn[0],&yn[0],&jnp[0],&ynp[0]);
128 if (n_actual!=
int(n))
131 std::ostringstream error_message_stream;
134 error_message_stream <<
"CRBond_Bessel::cbessjyna() only computed " 135 << n_actual <<
" rather than " << n
136 <<
" Bessel functions.\n";
140 OOMPH_CURRENT_FUNCTION,
141 OOMPH_EXCEPTION_LOCATION);
147 for (
unsigned i=0;
i<=n;
i++)
172 template <
class ELEMENT>
181 const int& face_index);
187 "Don't call empty constructor for HelmholtzBCElementBase",
188 OOMPH_CURRENT_FUNCTION,
189 OOMPH_EXCEPTION_LOCATION);
215 const unsigned &
i)
const 225 void output(std::ostream &outfile,
const unsigned &n_plot)
235 void output(FILE* file_pt,
const unsigned &n_plot)
242 return std::complex<unsigned>(U_index_helmholtz.real(),
243 U_index_helmholtz.imag());
251 std::ofstream outfile;
252 return global_power_contribution(outfile);
262 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(this->bulk_element_pt());
265 unsigned nnode_bulk=bulk_elem_pt->nnode();
266 const unsigned n_node_local = nnode();
269 const unsigned bulk_dim= bulk_elem_pt->dim();
270 const unsigned local_dim= this->dim();
273 Shape psi(n_node_local);
276 Shape psi_bulk(nnode_bulk);
277 DShape dpsi_bulk_dx(nnode_bulk,bulk_dim);
283 const unsigned n_intpt = integral_pt()->nweight();
290 if (outfile.is_open())
297 for(
unsigned ipt=0;ipt<n_intpt;ipt++)
300 for(
unsigned i=0;
i<local_dim;
i++)
302 s[
i] = integral_pt()->knot(ipt,
i);
305 this->outer_unit_normal(s,unit_normal);
308 double w = integral_pt()->weight(ipt);
311 double J=J_eulerian(s);
322 (void)bulk_elem_pt->dshape_eulerian(s_bulk,psi_bulk,dpsi_bulk_dx);
326 std::complex<double> dphi_dn(0.0,0.0);
328 std::complex<double> interpolated_phi(0.0,0.0);
334 for(
unsigned l=0;l<nnode_bulk;l++)
337 const std::complex<double> phi_value(
338 bulk_elem_pt->nodal_value(l,bulk_elem_pt->u_index_helmholtz().real()),
339 bulk_elem_pt->nodal_value(l,bulk_elem_pt->u_index_helmholtz().imag()));
342 for(
unsigned i=0;
i<bulk_dim;
i++)
344 interpolated_dphidx[
i] += phi_value*dpsi_bulk_dx(l,
i);
348 for(
unsigned l=0;l<n_node_local;l++)
351 const std::complex<double> phi_value(
352 nodal_value(l,u_index_helmholtz().real()),
353 nodal_value(l,u_index_helmholtz().imag()));
355 interpolated_phi += phi_value*psi(l);
359 for(
unsigned i=0;
i<bulk_dim;
i++)
361 dphi_dn += interpolated_dphidx[
i]*unit_normal[
i];
365 double integrand=0.5*
366 (interpolated_phi.real()*dphi_dn.imag()-
367 interpolated_phi.imag()*dphi_dn.real());
370 if (outfile.is_open())
373 double phi=atan2(x[1],x[0]);
374 outfile << x[0] <<
" " 377 << integrand <<
"\n";
392 Vector<std::complex<double> >& a_coeff_pos,
393 Vector<std::complex<double> >& a_coeff_neg)
397 if (a_coeff_pos.size()!=a_coeff_neg.size())
399 std::ostringstream error_stream;
400 error_stream <<
"a_coeff_pos and a_coeff_neg must have " 401 <<
"the same size. \n";
404 OOMPH_CURRENT_FUNCTION,
405 OOMPH_EXCEPTION_LOCATION);
410 const std::complex<double>
I(0.0,1.0);
413 const unsigned n_node = this->nnode();
420 const unsigned n_intpt=this->integral_pt()->nweight();
426 unsigned n=a_coeff_pos.size();
427 for (
unsigned i=0;
i<n;
i++)
429 a_coeff_pos[
i]=std::complex<double>(0.0,0.0);
430 a_coeff_neg[
i]=std::complex<double>(0.0,0.0);
435 for(
unsigned ipt=0;ipt<n_intpt;ipt++)
438 for(
unsigned i=0;
i<(this->
Dim-1);
i++)
440 s[
i]=this->integral_pt()->knot(ipt,
i);
444 double w=this->integral_pt()->weight(ipt);
447 this->dshape_local(s,psi,dpsi);
454 std::complex<double> interpolated_u(0.0,0.0);
457 for(
unsigned l=0;l<n_node;l++)
460 for(
unsigned i=0;
i<this->
Dim;
i++)
462 interpolated_x[
i]+=this->nodal_position(l,
i)*psi[l];
463 interpolated_dxds[
i]+=this->nodal_position(l,
i)*dpsi(l,0);
467 const std::complex<double> u_value(
468 this->nodal_value(l,this->U_index_helmholtz.real()),
469 this->nodal_value(l,this->U_index_helmholtz.imag()));
472 interpolated_u += u_value*psi(l);
479 double phi=atan2(interpolated_x[1],interpolated_x[0]);
482 double denom =(interpolated_x[0]*interpolated_x[0])+
483 (interpolated_x[1]*interpolated_x[1]);
484 double nom =-interpolated_dxds[1]*interpolated_x[0]+
485 interpolated_dxds[0]*interpolated_x[1];
486 double dphi_ds=std::fabs(nom/denom);
489 for (
unsigned i=0;
i<n;
i++)
491 a_coeff_pos[
i]+=interpolated_u*exp(-I*phi*
double(
i))*dphi_ds*w;
494 for (
unsigned i=1;
i<n;
i++)
496 a_coeff_neg[
i]+=interpolated_u*exp(I*phi*
double(
i))*dphi_ds*w;
517 return J_eulerian(s);
530 unsigned n_node = nnode();
533 dshape_local(s,psi,dpsi_ds);
536 for(
unsigned i=0;
i<n_node;
i++)
538 for(
unsigned j=0;j<(
Dim-1);j++)
541 dtest_ds(
i,j)= dpsi_ds(
i,j);
545 return J_eulerian(s);
568 template<
class ELEMENT>
576 const unsigned& nfourier_terms) :
577 Outer_radius(outer_radius), Nfourier_terms(nfourier_terms)
586 void compute_fourier_components(
Vector<std::complex<double> >& a_coeff_pos,
587 Vector<std::complex<double> >& a_coeff_neg);
593 return Gamma_at_gauss_point[el_pt];
601 return D_Gamma_at_gauss_point[el_pt];
607 return Outer_radius ;
614 return Nfourier_terms;
633 std::map<FiniteElement*,Vector<std::map<unsigned,std::complex<double> > > >
649 template<
class ELEMENT>
659 const int& face_index) :
681 fill_in_generic_residual_contribution_helmholtz_abc(
691 fill_in_generic_residual_contribution_helmholtz_abc(residuals,jacobian,1);
698 return Outer_radius_pt;
708 const unsigned& flag)
716 "Order of ABC hasn't been set!",
717 OOMPH_CURRENT_FUNCTION,
718 OOMPH_EXCEPTION_LOCATION);
721 if (this->Outer_radius_pt==0)
724 "Pointer to outer radius hasn't been set!",
725 OOMPH_CURRENT_FUNCTION,
726 OOMPH_EXCEPTION_LOCATION);
732 const unsigned n_node = this->nnode();
735 Shape psi(n_node), test(n_node);
737 dtest_ds(n_node,this->
Dim-1),
738 dtest_dS(n_node,this->
Dim-1),
739 dpsi_dS (n_node,this->
Dim-1);
742 const unsigned n_intpt = this->integral_pt()->nweight();
748 int local_eqn_real=0,local_unknown_real=0;
749 int local_eqn_imag=0,local_unknown_imag=0;
752 double R=*Outer_radius_pt;
753 double k=sqrt(dynamic_cast<ELEMENT*>(this->bulk_element_pt())->k_squared());
757 for(
unsigned ipt=0;ipt<n_intpt;ipt++)
760 for(
unsigned i=0;
i<(this->
Dim-1);
i++)
762 s[
i] = this->integral_pt()->knot(ipt,
i);
766 double w = this->integral_pt()->weight(ipt);
771 double J = this->d_shape_and_test_local(s,psi,test,dpsi_ds,dtest_ds);
780 std::complex<double> interpolated_u(0.0,0.0);
781 std::complex<double> du_dS(0.0,0.0);
784 for(
unsigned l=0;l<n_node;l++)
788 const std::complex<double> u_value(
789 this->nodal_value(l,this->U_index_helmholtz.real()),
790 this->nodal_value(l,this->U_index_helmholtz.imag()));
792 interpolated_u += u_value*psi[l];
794 du_dS += u_value*dpsi_ds(l,0)*inv_J;
797 dtest_dS(l,0)=dtest_ds(l,0)*inv_J;
799 dpsi_dS(l,0)=dpsi_ds(l,0)*inv_J;
803 if (*ABC_order_pt==1)
807 for(
unsigned l=0;l<n_node;l++)
809 local_eqn_real = this->nodal_local_eqn
810 (l,this->U_index_helmholtz.real());
811 local_eqn_imag = this->nodal_local_eqn
812 (l,this->U_index_helmholtz.imag());
817 if(local_eqn_real >= 0)
821 residuals[local_eqn_real] +=
822 (k*interpolated_u.imag()+(0.5/
R)
823 *interpolated_u.real())*test[l]*W;
830 for(
unsigned l2=0;l2<n_node;l2++)
832 local_unknown_real = this->nodal_local_eqn(
833 l2,this->U_index_helmholtz.real());
834 local_unknown_imag = this->nodal_local_eqn(
835 l2,this->U_index_helmholtz.imag());
837 if(local_unknown_real >= 0)
839 jacobian(local_eqn_real,local_unknown_real)
840 +=(0.5/
R)*psi[l2]*test[l]*W;
844 if(local_unknown_imag >= 0)
846 jacobian(local_eqn_real,local_unknown_imag)
847 += k *psi[l2]*test[l]*
W;
857 if(local_eqn_imag >= 0)
860 residuals[local_eqn_imag] +=
861 (-k*interpolated_u.real()+(0.5/
R)
862 *interpolated_u.imag())*test[l]*W;
870 for(
unsigned l2=0;l2<n_node;l2++)
872 local_unknown_real = this->nodal_local_eqn(
873 l2,this->U_index_helmholtz.real());
874 local_unknown_imag = this->nodal_local_eqn(
875 l2,this->U_index_helmholtz.imag());
877 if(local_unknown_real >= 0)
879 jacobian(local_eqn_imag,local_unknown_real)
880 += (-k) *psi[l2]*test[l]*W;
884 if(local_unknown_imag >= 0)
886 jacobian(local_eqn_imag,local_unknown_imag)
887 +=(0.5/
R)*psi[l2]*test[l]*W;
900 for(
unsigned l=0;l<n_node;l++)
902 local_eqn_real = this->nodal_local_eqn
903 (l,this->U_index_helmholtz.real());
904 local_eqn_imag = this->nodal_local_eqn
905 (l,this->U_index_helmholtz.imag());
910 if(local_eqn_real >= 0)
914 residuals[local_eqn_real] +=
915 (k*interpolated_u.imag()+(0.5/
R)
916 *interpolated_u.real())*test[l]*W
917 + ((0.125/(k*R*R))*interpolated_u.imag())*test[l]*W;
919 residuals[local_eqn_real] +=
920 (-0.5/k)*du_dS.imag()*dtest_dS(l,0)*
W;
927 for(
unsigned l2=0;l2<n_node;l2++)
929 local_unknown_real = this->nodal_local_eqn(
930 l2,this->U_index_helmholtz.real());
931 local_unknown_imag = this->nodal_local_eqn(
932 l2,this->U_index_helmholtz.imag());
934 if(local_unknown_real >= 0)
936 jacobian(local_eqn_real,local_unknown_real)
937 +=(0.5/
R)*psi[l2]*test[l]*W;
941 if(local_unknown_imag >= 0)
943 jacobian(local_eqn_real,local_unknown_imag)
944 += k *psi[l2]*test[l]*W
945 + (0.125/(k*R*
R))*psi[l2]*test[l]*
W;
947 jacobian(local_eqn_real,local_unknown_imag)
948 +=(-0.5/k)*dpsi_dS(l2,0)*dtest_dS(l,0)*
W;
957 if(local_eqn_imag >= 0)
960 residuals[local_eqn_imag] +=
961 (-k*interpolated_u.real()+(0.5/
R)
962 *interpolated_u.imag())*test[l]*W
963 + ((-0.125/(k*R*R))*interpolated_u.real())*test[l]*W;
965 residuals[local_eqn_imag] +=
966 (0.5/k)*du_dS.real()*dtest_dS(l,0)*
W;
973 for(
unsigned l2=0;l2<n_node;l2++)
975 local_unknown_real = this->nodal_local_eqn(
976 l2,this->U_index_helmholtz.real());
977 local_unknown_imag = this->nodal_local_eqn(
978 l2,this->U_index_helmholtz.imag());
980 if(local_unknown_real >= 0)
982 jacobian(local_eqn_imag,local_unknown_real)
983 += (-k) *psi[l2]*test[l]*W
984 -(0.125/(k*R*R))*psi[l2]*test[l]*W;
986 jacobian(local_eqn_imag,local_unknown_real)
987 +=(0.5/k)*dpsi_dS(l2,0)*dtest_dS(l,0)*
W;
991 if(local_unknown_imag >= 0)
993 jacobian(local_eqn_imag,local_unknown_imag)
994 +=(0.5/
R)*psi[l2]*test[l]*W;
1002 if(*ABC_order_pt==3)
1006 for(
unsigned l=0;l<n_node;l++)
1008 local_eqn_real = this->nodal_local_eqn
1009 (l,this->U_index_helmholtz.real());
1010 local_eqn_imag = this->nodal_local_eqn
1011 (l,this->U_index_helmholtz.imag());
1016 if(local_eqn_real >= 0)
1019 residuals[local_eqn_real] +=
1020 ((k*(1+0.125/(k*k*R*
R)))*interpolated_u.imag()
1021 +(0.5/R-0.125/(k*k*R*R*
R))*interpolated_u.real())
1024 residuals[local_eqn_real] +=
1025 ((-0.5/k)*du_dS.imag()+(0.5/(k*k*
R))*du_dS.real())
1033 for(
unsigned l2=0;l2<n_node;l2++)
1035 local_unknown_real = this->nodal_local_eqn(
1036 l2,this->U_index_helmholtz.real());
1037 local_unknown_imag = this->nodal_local_eqn(
1038 l2,this->U_index_helmholtz.imag());
1040 if(local_unknown_real >= 0)
1042 jacobian(local_eqn_real,local_unknown_real)
1043 +=(0.5/R-0.125/(k*k*R*R*
R))*psi[l2]*test[l]*
W;
1045 jacobian(local_eqn_real,local_unknown_real)
1046 +=(0.5/(k*k*
R))*dpsi_dS(l2,0)*dtest_dS(l,0)*
W;
1050 if(local_unknown_imag >= 0)
1052 jacobian(local_eqn_real,local_unknown_imag)
1053 +=(k*(1+0.125/(k*k*R*
R)))*psi[l2]*test[l]*W;
1055 jacobian(local_eqn_real,local_unknown_imag)
1056 +=(-0.5/k)*dpsi_dS(l2,0)*dtest_dS(l,0)*
W;
1065 if(local_eqn_imag >= 0)
1068 residuals[local_eqn_imag] +=
1069 ((-k*(1+0.125/(k*k*R*
R)))*interpolated_u.real()
1070 +(0.5/R-0.125/(k*k*R*R*
R))*interpolated_u.imag())
1073 residuals[local_eqn_imag] +=
1074 ((0.5/k)*du_dS.real()+(0.5/(k*k*
R))*du_dS.imag())
1082 for(
unsigned l2=0;l2<n_node;l2++)
1084 local_unknown_real = this->nodal_local_eqn(
1085 l2,this->U_index_helmholtz.real());
1086 local_unknown_imag = this->nodal_local_eqn(
1087 l2,this->U_index_helmholtz.imag());
1089 if(local_unknown_real >= 0)
1091 jacobian(local_eqn_imag,local_unknown_real)
1092 +=(-k*(1+0.125/(k*k*R*
R)))*psi[l2]*test[l]*W;
1094 jacobian(local_eqn_imag,local_unknown_real)
1095 +=(0.5/k)*dpsi_dS(l2,0)*dtest_dS(l,0)*
W;
1098 if(local_unknown_imag >= 0)
1100 jacobian(local_eqn_imag,local_unknown_imag)
1101 +=(0.5/R-0.125/(k*k*R*R*
R))*psi[l2]*test[l]*
W;
1103 jacobian(local_eqn_imag,local_unknown_imag)
1104 +=(0.5/(k*k*
R))*dpsi_dS(l2,0)*dtest_dS(l,0)*
W;
1129 template<
class ELEMENT>
1138 const int& face_index) :
1147 fill_in_generic_residual_contribution_helmholtz_DtN_bc
1157 fill_in_generic_residual_contribution_helmholtz_DtN_bc
1158 (residuals,jacobian,1);
1165 void compute_gamma_contribution(
const double& phi,
const int& n,
1166 std::complex<double>& gamma_con,
1167 std::map<
unsigned,std::complex<double> >&
1175 return Outer_boundary_mesh_pt;
1179 void set_outer_boundary_mesh_pt
1182 Outer_boundary_mesh_pt=mesh_pt;
1192 std::set<Node*> node_set;
1193 unsigned nel=Outer_boundary_mesh_pt->nelement();
1194 for (
unsigned e=0;
e<nel;
e++)
1196 FiniteElement* el_pt=Outer_boundary_mesh_pt->finite_element_pt(
e);
1197 unsigned nnod=el_pt->
nnode();
1198 for (
unsigned j=0;j<nnod;j++)
1205 node_set.insert(nod_pt);
1210 unsigned nnod=this->nnode();
1211 for (
unsigned j=0;j<nnod;j++)
1213 Node* nod_pt=this->node_pt(j);
1214 node_set.erase(nod_pt);
1226 for (std::set<Node*>::iterator it=node_set.begin();
1227 it!=node_set.end();it++)
1229 this->add_external_data(*it);
1239 void fill_in_generic_residual_contribution_helmholtz_DtN_bc
1241 const unsigned& flag)
1244 const unsigned n_node = this->nnode();
1250 const unsigned n_intpt = this->integral_pt()->nweight();
1256 int local_eqn_real=0,local_unknown_real=0,global_eqn_real=0,
1257 local_eqn_imag=0,local_unknown_imag=0,global_eqn_imag=0;
1258 int external_global_eqn_real=0, external_unknown_real=0,
1259 external_global_eqn_imag=0, external_unknown_imag=0;
1265 gamma(Outer_boundary_mesh_pt->gamma_at_gauss_point(
this));
1268 d_gamma(Outer_boundary_mesh_pt->d_gamma_at_gauss_point(
this));
1272 for(
unsigned ipt=0;ipt<n_intpt;ipt++)
1275 for(
unsigned i=0;
i<(this->
Dim-1);
i++)
1277 s[
i] = this->integral_pt()->knot(ipt,
i);
1281 double w = this->integral_pt()->weight(ipt);
1286 double J = this->test_only(s,test);
1293 for(
unsigned l=0;l<n_node;l++)
1295 local_eqn_real = this->nodal_local_eqn
1296 (l,this->U_index_helmholtz.real());
1297 local_eqn_imag = this->nodal_local_eqn
1298 (l,this->U_index_helmholtz.imag());
1301 if(local_eqn_real >= 0)
1304 residuals[local_eqn_real] -=gamma[ipt].real()*test[l]*
W;
1311 for(
unsigned l2=0;l2<n_node;l2++)
1314 local_unknown_real = this->nodal_local_eqn(
1315 l2,this->U_index_helmholtz.real());
1317 local_unknown_imag = this->nodal_local_eqn(
1318 l2,this->U_index_helmholtz.imag());
1321 if(local_unknown_real >= 0)
1323 global_eqn_real=this->eqn_number(local_unknown_real);
1326 jacobian(local_eqn_real,local_unknown_real)
1327 -=d_gamma[ipt][global_eqn_real].real()*test[l]*
W;
1329 if(local_unknown_imag >= 0)
1331 global_eqn_imag=this->eqn_number(local_unknown_imag);
1334 jacobian(local_eqn_real,local_unknown_imag)
1335 -=d_gamma[ipt][global_eqn_imag].real()*test[l]*
W;
1340 unsigned n_ext_data=this->nexternal_data();
1342 for(
unsigned l2=0;l2<n_ext_data;l2++)
1345 external_unknown_real = this->external_local_eqn(
1346 l2,this->U_index_helmholtz.real());
1348 external_unknown_imag = this->external_local_eqn(
1349 l2,this->U_index_helmholtz.imag());
1352 if(external_unknown_real >= 0)
1354 external_global_eqn_real=this->eqn_number(external_unknown_real);
1357 jacobian(local_eqn_real,external_unknown_real)
1358 -=d_gamma[ipt][external_global_eqn_real].real()*test[l]*
W;
1360 if(external_unknown_imag >= 0)
1362 external_global_eqn_imag=this->eqn_number(external_unknown_imag);
1365 jacobian(local_eqn_real,external_unknown_imag)
1366 -=d_gamma[ipt][external_global_eqn_imag].real()*test[l]*
W;
1372 if(local_eqn_imag >= 0)
1375 residuals[local_eqn_imag] -=gamma[ipt].imag()*test[l]*
W;
1382 for(
unsigned l2=0;l2<n_node;l2++)
1385 local_unknown_real = this->nodal_local_eqn(
1386 l2,this->U_index_helmholtz.real());
1388 local_unknown_imag = this->nodal_local_eqn(
1389 l2,this->U_index_helmholtz.imag());
1392 if(local_unknown_real >= 0)
1394 global_eqn_real=this->eqn_number(local_unknown_real);
1397 jacobian(local_eqn_imag,local_unknown_real)
1398 -=d_gamma[ipt][global_eqn_real].imag()*test[l]*
W;
1400 if(local_unknown_imag >= 0)
1402 global_eqn_imag=this->eqn_number(local_unknown_imag);
1405 jacobian(local_eqn_imag,local_unknown_imag)
1406 -=d_gamma[ipt][global_eqn_imag].imag()*test[l]*
W;
1411 unsigned n_ext_data=this->nexternal_data();
1413 for(
unsigned l2=0;l2<n_ext_data;l2++)
1416 external_unknown_real = this->external_local_eqn(
1417 l2,this->U_index_helmholtz.real());
1419 external_unknown_imag = this->external_local_eqn(
1420 l2,this->U_index_helmholtz.imag());
1423 if(external_unknown_real >= 0)
1425 external_global_eqn_real=this->eqn_number(external_unknown_real);
1428 jacobian(local_eqn_imag,external_unknown_real)
1429 -=d_gamma[ipt][external_global_eqn_real].imag()*test[l]*
W;
1431 if(external_unknown_imag >= 0)
1433 external_global_eqn_imag=this->eqn_number(external_unknown_imag);
1436 jacobian(local_eqn_imag,external_unknown_imag)
1437 -=d_gamma[ipt][external_global_eqn_imag].imag()*test[l]*
W;
1466 template<
class ELEMENT>
1471 std::complex<double>& gamma_con,
1472 std::map<
unsigned,std::complex<double> >& d_gamma_con)
1475 const std::complex<double>
I(0.0,1.0);
1478 const unsigned n_node = this->nnode();
1485 int local_unknown_real=0, local_unknown_imag=0;
1486 int global_unknown_real=0,global_unknown_imag=0;
1489 const unsigned n_intpt=this->integral_pt()->nweight();
1495 gamma_con=std::complex<double>(0.0,0.0);
1496 d_gamma_con.clear();
1500 for(
unsigned ipt=0;ipt<n_intpt;ipt++)
1503 for(
unsigned i=0;
i<(this->
Dim-1);
i++)
1505 s[
i]=this->integral_pt()->knot(ipt,
i);
1509 double w=this->integral_pt()->weight(ipt);
1512 this->dshape_local(s,psi,dpsi);
1519 std::complex<double> interpolated_u(0.0,0.0);
1522 for(
unsigned l=0;l<n_node;l++)
1525 for(
unsigned i=0;
i<this->
Dim;
i++)
1527 interpolated_x[
i]+=this->nodal_position(l,
i)*psi[l];
1528 interpolated_dxds[
i]+=this->nodal_position(l,
i)*dpsi(l,0);
1532 std::complex<double> u_value(
1533 this->nodal_value(l,this->U_index_helmholtz.real()),
1534 this->nodal_value(l,this->U_index_helmholtz.imag()));
1536 interpolated_u += u_value*psi(l);
1542 double phi_p=atan2(interpolated_x[1],interpolated_x[0]);
1545 double denom =(interpolated_x[0]*interpolated_x[0])+
1546 (interpolated_x[1]*interpolated_x[1]);
1547 double nom =-interpolated_dxds[1]*interpolated_x[0]+
1548 interpolated_dxds[0]*interpolated_x[1];
1549 double dphi_ds=std::fabs(nom/denom);
1555 gamma_con+=(dphi_ds)*w*pow(exp(I*(phi-phi_p)),
static_cast<double>(n))
1559 for(
unsigned l=0;l<n_node;l++)
1562 local_unknown_real = this->nodal_local_eqn(
1563 l,this->U_index_helmholtz.real());
1564 if (local_unknown_real >= 0)
1566 global_unknown_real=this->eqn_number(local_unknown_real);
1567 d_gamma_con[global_unknown_real]+=
1568 (dphi_ds)*w*exp(I*(phi-phi_p)*double(n))*psi(l);
1572 local_unknown_imag = this->nodal_local_eqn(
1573 l,this->U_index_helmholtz.imag());
1574 if (local_unknown_imag >= 0)
1576 global_unknown_imag=this->eqn_number(local_unknown_imag);
1580 d_gamma_con[global_unknown_imag]+=
1581 I* (dphi_ds)*w*pow(exp(I*(phi-phi_p)),
static_cast<double>(n))*psi(l);
1598 namespace ToleranceForHelmholtzOuterBoundary
1611 namespace ToleranceForHelmholtzOuterBoundary
1628 template<
class ELEMENT>
1630 Vector<std::complex<double> >& a_coeff_pos,
1631 Vector<std::complex<double> >& a_coeff_neg)
1635 if (a_coeff_pos.size()!=a_coeff_neg.size())
1637 std::ostringstream error_stream;
1638 error_stream <<
"a_coeff_pos and a_coeff_neg must have " 1639 <<
"the same size. \n";
1642 OOMPH_CURRENT_FUNCTION,
1643 OOMPH_EXCEPTION_LOCATION);
1648 unsigned n=a_coeff_pos.size();
1651 for (
unsigned i=0;
i<n;
i++)
1653 a_coeff_pos[
i]=std::complex<double>(0.0,0.0);
1654 a_coeff_neg[
i]=std::complex<double>(0.0,0.0);
1658 unsigned nel=this->nelement();
1659 for (
unsigned e=0;
e<nel;
e++)
1670 for (
unsigned i=0;
i<n;
i++)
1672 a_coeff_pos[
i]+=el_a_coeff_pos[
i];
1673 a_coeff_neg[
i]+=el_a_coeff_neg[
i];
1687 template<
class ELEMENT>
1694 unsigned nel=this->nelement();
1695 for (
unsigned e=0;
e<nel;
e++)
1698 unsigned nnod=fe_pt->
nnode();
1699 for (
unsigned j=0;j<nnod;j++)
1709 double r=sqrt(x[0]*x[0]+x[1]*x[1]);
1712 if (Outer_radius==0.0)
1715 "Outer radius for DtN BC must not be zero!",
1716 OOMPH_CURRENT_FUNCTION,
1717 OOMPH_EXCEPTION_LOCATION);
1720 if(std::fabs((r-this->Outer_radius)/Outer_radius)
1723 std::ostringstream error_stream;
1724 error_stream <<
"Node at " << x[0] <<
" " << x[1]
1725 <<
" has radius " << r <<
" which does not " 1726 <<
" agree with \nspecified outer radius " 1727 << this->Outer_radius <<
" within relative tolerance " 1729 <<
".\nYou can adjust the tolerance via\n" 1730 <<
"ToleranceForHelmholtzOuterBoundary::Tol\n" 1731 <<
"or recompile without PARANOID.\n";
1734 OOMPH_CURRENT_FUNCTION,
1735 OOMPH_EXCEPTION_LOCATION);
1746 (this->element_pt(0));
1747 double k=sqrt(dynamic_cast<ELEMENT*>(el_pt->bulk_element_pt())->k_squared());
1753 Hankel_first(Nfourier_terms-1,Outer_radius*k,h_a,hp_a);
1754 for (
unsigned i=0;
i<Nfourier_terms;
i++)
1760 unsigned nel=this->nelement();
1761 for (
unsigned e=0;
e<nel;
e++)
1766 (this->element_pt(
e));
1769 const unsigned n_intpt =el_pt->
integral_pt()->nweight();
1773 n_intpt,std::complex<double>(0.0,0.0));
1775 d_gamma_vector(n_intpt);
1778 for(
unsigned ipt=0;ipt<n_intpt;ipt++)
1781 unsigned ndim_local=el_pt->
dim();
1786 for(
unsigned i=0;
i<ndim_local;
i++)
1795 double phi=atan2(x[1],x[0]);
1798 std::complex<double> gamma_con_p(0.0,0.0),gamma_con_n(0.0,0.0);
1799 std::map<unsigned,std::complex<double> > d_gamma_con_p,d_gamma_con_n;
1802 for (
unsigned nn=0;nn<Nfourier_terms;nn++)
1806 for (
unsigned ee=0;ee<nel;ee++)
1810 (this->element_pt(ee));
1814 phi,
int(nn),gamma_con_p,d_gamma_con_p) ;
1818 phi,-
int(nn),gamma_con_n,d_gamma_con_n) ;
1820 unsigned n_node=eel_pt->
nnode();
1823 gamma_vector[ipt]+=q[nn]*gamma_con_p;
1824 for(
unsigned l=0;l<n_node;l++)
1829 if (local_unknown_p_real >= 0)
1831 int global_unknown_p_real=eel_pt->
eqn_number(
1832 local_unknown_p_real);
1833 d_gamma_vector[ipt][global_unknown_p_real]+=
1834 q[nn]*d_gamma_con_p[global_unknown_p_real];
1838 int local_unknown_p_imag=
1842 if (local_unknown_p_imag >= 0)
1844 int global_unknown_p_imag=eel_pt->
eqn_number(
1845 local_unknown_p_imag);
1847 d_gamma_vector[ipt][global_unknown_p_imag]+=
1848 q[nn]*d_gamma_con_p[global_unknown_p_imag];
1854 gamma_vector[ipt]+=q[nn]*(gamma_con_p+gamma_con_n);
1855 for(
unsigned l=0;l<n_node;l++)
1860 if (local_unknown_real >= 0)
1862 int global_unknown_real=eel_pt->
eqn_number(local_unknown_real);
1863 d_gamma_vector[ipt][global_unknown_real]+=
1864 q[nn]*(d_gamma_con_p[global_unknown_real]+
1865 d_gamma_con_n[global_unknown_real]);
1870 if (local_unknown_imag >= 0)
1872 int global_unknown_imag=eel_pt->
eqn_number(local_unknown_imag);
1873 d_gamma_vector[ipt][global_unknown_imag]+=
1874 q[nn]*(d_gamma_con_p[global_unknown_imag]+
1875 d_gamma_con_n[global_unknown_imag]);
1884 Gamma_at_gauss_point[el_pt]=gamma_vector;
1885 D_Gamma_at_gauss_point[el_pt]=d_gamma_vector;
1893 template<
class ELEMENT>
1896 const int &face_index) :
1902 ELEMENT* elem_pt =
new ELEMENT;
1904 if(elem_pt->dim()==3)
1907 if(dynamic_cast<RefineableElement*>(elem_pt))
1911 "This flux element will not" 1912 "work correctly if nodes are hanging\n",
1913 "HelmholtzBCElementBase::Constructor",
1914 OOMPH_EXCEPTION_LOCATION);
1949 "Bulk element must inherit from HelmholtzEquations.";
1951 "Nodes are one dimensional, but cannot cast the bulk element to\n";
1952 error_string +=
"HelmholtzEquations<1>\n.";
1954 "If you desire this functionality, you must implement it yourself\n";
1957 OOMPH_CURRENT_FUNCTION,
1958 OOMPH_EXCEPTION_LOCATION);
1978 "Bulk element must inherit from HelmholtzEquations.";
1980 "Nodes are two dimensional, but cannot cast the bulk element to\n";
1981 error_string +=
"HelmholtzEquations<2>\n.";
1983 "If you desire this functionality, you must implement it yourself\n";
1986 OOMPH_CURRENT_FUNCTION,
1987 OOMPH_EXCEPTION_LOCATION);
2007 "Bulk element must inherit from HelmholtzEquations.";
2009 "Nodes are three dimensional, but cannot cast the bulk element to\n";
2010 error_string +=
"HelmholtzEquations<3>\n.";
2012 "If you desire this functionality, you must implement it yourself\n";
2015 OOMPH_CURRENT_FUNCTION,
2016 OOMPH_EXCEPTION_LOCATION);
2028 std::ostringstream error_stream;
2029 error_stream <<
"Dimension of node is " <<
Dim 2030 <<
". It should be 1,2, or 3!" << std::endl;
2033 OOMPH_CURRENT_FUNCTION,
2034 OOMPH_EXCEPTION_LOCATION);
HelmholtzBCElementBase()
Broken empty constructor.
double global_power_contribution()
Compute the element's contribution to the time-averaged radiated power over the artificial boundary...
void broken_copy(const std::string &class_name)
Issue error message and terminate execution.
unsigned * ABC_order_pt
Pointer to order of absorbing boundary condition.
virtual void output(std::ostream &outfile)
Output the element data — typically the values at the nodes in a format suitable for post-processing...
double & outer_radius()
The outer radius.
HelmholtzDtNMesh(const double &outer_radius, const unsigned &nfourier_terms)
void Hankel_first(const unsigned &n, const double &x, Vector< std::complex< double > > &h, Vector< std::complex< double > > &hp)
void complete_setup_of_dependencies()
Complete the setup of additional dependencies arising through the far-away interaction with other nod...
const double Pi
50 digits from maple
A general Finite Element class.
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Broken assignment operator.
double test_only(const Vector< double > &s, Shape &test) const
Function to compute the shape and test functions and to return the Jacobian of mapping between local ...
HelmholtzDtNMesh< ELEMENT > * Outer_boundary_mesh_pt
Pointer to mesh of all DtN boundary condition elements (needed to get access to gamma values) ...
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
In a FaceElement, the "global" intrinsic coordinate of the element along the boundary, when viewed as part of a compound geometric object is specified using the boundary coordinate defined by the mesh. Note: Boundary coordinates will have been set up when creating the underlying mesh, and their values will have been stored at the nodes.
double interpolated_x(const Vector< double > &s, const unsigned &i) const
Return FE interpolated coordinate x[i] at local coordinate s. Overloaded to get information from bulk...
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
void compute_contribution_to_fourier_components(Vector< std::complex< double > > &a_coeff_pos, Vector< std::complex< double > > &a_coeff_neg)
Compute element's contribution to Fourier components of the solution – length of vector indicates nu...
void CHankel_first(const unsigned &n, const std::complex< double > &x, Vector< std::complex< double > > &h, Vector< std::complex< double > > &hp)
void output(std::ostream &outfile)
double global_power_contribution(std::ofstream &outfile)
Compute the element's contribution to the time-averaged radiated power over the artificial boundary...
void output(FILE *file_pt, const unsigned &n_plot)
C-style output function – forward to broken version in FiniteElement until somebody decides what exa...
unsigned Dim
Dimension of zeta tuples (set by get_dim_helper) – needed because we store the scalar coordinates in...
Vector< std::map< unsigned, std::complex< double > > > & d_gamma_at_gauss_point(FiniteElement *el_pt)
Derivative of Gamma integral w.r.t global unknown, evaluated at Gauss points for specified element...
std::complex< unsigned > U_index_helmholtz
The index at which the real and imag part of the unknown is stored at the nodes.
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
double & x(const unsigned &i)
Return the i-th nodal coordinate.
HelmholtzDtNBoundaryElement(FiniteElement *const &bulk_el_pt, const int &face_index)
Construct element from specification of bulk element and face index.
A class for elements that allow the approximation of the Sommerfeld radiation BC. The element geometr...
const std::complex< double > I(0.0, 1.0)
The imaginary unit.
Integral *const & integral_pt() const
Return the pointer to the integration scheme (const version)
void output(std::ostream &outfile, const unsigned &n_plot)
Output function – forward to broken version in FiniteElement until somebody decides what exactly the...
std::map< FiniteElement *, Vector< std::complex< double > > > Gamma_at_gauss_point
Container to store the gamma integral for given Gauss point and element.
double * Outer_radius_pt
Pointer to radius of outer boundary (must be a circle!)
unsigned long eqn_number(const unsigned &ieqn_local) const
Return the global equation number corresponding to the ieqn_local-th local equation number...
void setup_gamma()
Compute and store the gamma integral at all integration points of the constituent elements...
void output(FILE *file_pt)
double Outer_radius
Outer radius.
void compute_fourier_components(Vector< std::complex< double > > &a_coeff_pos, Vector< std::complex< double > > &a_coeff_neg)
Compute Fourier components of the solution – length of vector indicates number of terms to be comput...
virtual std::complex< unsigned > u_index_helmholtz() const
Return the index at which the real/imag unknown value is stored.
void fill_in_generic_residual_contribution_helmholtz_abc(Vector< double > &residuals, DenseMatrix< double > &jacobian, const unsigned &flag)
Compute the element's residual vector and the ( Jacobian matrix. Overloaded version, using the abc approximation.
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
void shape(const double &s, double *Psi)
Definition for 1D Lagrange shape functions. The value of all the shape functions at the local coordin...
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Add the element's contribution to its residual vector and its Jacobian matrix.
unsigned & nfourier_terms()
Number of Fourier terms used in the computation of the gamma integral.
double d_shape_and_test_local(const Vector< double > &s, Shape &psi, Shape &test, DShape &dpsi_ds, DShape &dtest_ds) const
Function to compute the shape, test functions and derivates and to return the Jacobian of mapping bet...
virtual std::complex< unsigned > u_index_helmholtz() const
Broken assignment operator.
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
HelmholtzBCElementBase(const HelmholtzBCElementBase &dummy)
Broken copy constructor.
HelmholtzAbsorbingBCElement(FiniteElement *const &bulk_el_pt, const int &face_index)
Construct element from specification of bulk element and face index.
unsigned *& abc_order_pt()
Pointer to order of absorbing boundary condition.
std::map< FiniteElement *, Vector< std::map< unsigned, std::complex< double > > > > D_Gamma_at_gauss_point
Container to store the derivate of Gamma integral w.r.t global unknown evaluated at Gauss points for ...
virtual Node * copied_node_pt() const
Return pointer to copied node (null if the current node is not a copy – always the case here; it's o...
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
unsigned Nfourier_terms
Nbr of Fourier terms used in the Gamma computation.
virtual void build_face_element(const int &face_index, FaceElement *face_element_pt)
Function for building a lower dimensional FaceElement on the specified face of the FiniteElement...
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Add the element's contribution to its residual vector.
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Add the element's contribution to its residual vector.
virtual bool is_a_copy() const
Return a boolean to indicate whether the Data objact contains any copied values. A base Data object c...
double Tol
Relative tolerance to within radius of points on DtN boundary are allowed to deviate from specified v...
Vector< std::complex< double > > & gamma_at_gauss_point(FiniteElement *el_pt)
Gamma integral evaluated at Gauss points for specified element.
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Add the element's contribution to its residual vector and its Jacobian matrix.
unsigned nnode() const
Return the number of nodes.
void compute_gamma_contribution(const double &phi, const int &n, std::complex< double > &gamma_con, std::map< unsigned, std::complex< double > > &d_gamma_con)
Compute the contribution of the element to the Gamma integral and its derivates w.r.t to global unknows; the function takes the wavenumber and the polar angle phi as input.
unsigned Dim
The spatial dimension of the problem.
static DenseMatrix< double > Dummy_matrix
Empty dense matrix used as a dummy argument to combined residual and jacobian functions in the case w...
double *& outer_radius_pt()
Get pointer to radius of outer boundary (must be a cirle)
HelmholtzDtNMesh< ELEMENT > * outer_boundary_mesh_pt() const
Access function to mesh of all DtN boundary condition elements (needed to get access to gamma values)...
int nodal_local_eqn(const unsigned &n, const unsigned &i) const
Return the local equation number corresponding to the i-th value at the n-th local node...