32 #ifndef OOMPH_FOURIER_DECOMPOSED_HELMHOLTZ_BC_ELEMENTS_HEADER 33 #define OOMPH_FOURIER_DECOMPOSED_HELMHOLTZ_BC_ELEMENTS_HEADER 38 #include <oomph-lib-config.h> 45 #include "oomph_crbond_bessel.h" 66 template <
class ELEMENT>
82 "Don't call empty constructor for FourierDecomposedHelmholtzBCElementBase",
83 OOMPH_CURRENT_FUNCTION,
84 OOMPH_EXCEPTION_LOCATION);
110 const unsigned &
i)
const 120 void output(std::ostream &outfile,
const unsigned &n_plot)
130 void output(FILE* file_pt,
const unsigned &n_plot)
147 std::ofstream outfile;
158 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(this->
bulk_element_pt());
161 unsigned nnode_bulk=bulk_elem_pt->nnode();
162 const unsigned n_node_local = this->
nnode();
165 const unsigned bulk_dim= bulk_elem_pt->dim();
166 const unsigned local_dim= this->
node_pt(0)->
ndim();
169 Shape psi(n_node_local);
172 Shape psi_bulk(nnode_bulk);
173 DShape dpsi_bulk_dx(nnode_bulk,bulk_dim);
186 if (outfile.is_open())
193 for(
unsigned ipt=0;ipt<n_intpt;ipt++)
196 for(
unsigned i=0;
i<(local_dim-1);
i++)
218 (void)bulk_elem_pt->dshape_eulerian(s_bulk,psi_bulk,dpsi_bulk_dx);
222 std::complex<double> dphi_dn(0.0,0.0);
224 std::complex<double> interpolated_phi(0.0,0.0);
230 for(
unsigned l=0;l<nnode_bulk;l++)
233 const std::complex<double> phi_value(
234 bulk_elem_pt->nodal_value(
235 l,bulk_elem_pt->u_index_fourier_decomposed_helmholtz().real()),
236 bulk_elem_pt->nodal_value(
237 l,bulk_elem_pt->u_index_fourier_decomposed_helmholtz().imag())
241 for(
unsigned i=0;
i<bulk_dim;
i++)
243 interpolated_dphidx[
i] += phi_value*dpsi_bulk_dx(l,
i);
247 for(
unsigned l=0;l<n_node_local;l++)
250 const std::complex<double> phi_value(
254 interpolated_phi += phi_value*psi(l);
258 for(
unsigned i=0;
i<bulk_dim;
i++)
260 dphi_dn += interpolated_dphidx[
i]*unit_normal[
i];
265 (interpolated_phi.real()*dphi_dn.imag()-
266 interpolated_phi.imag()*dphi_dn.real());
269 double theta=atan2(x[0],x[1]);
271 if (outfile.is_open())
273 outfile << x[0] <<
" " 276 << integrand <<
"\n";
297 unsigned nnod=
nnode();
298 for (
unsigned i=0;
i<nnod;
i++)
317 unsigned n_node =
nnode();
323 for(
unsigned i=0;
i<n_node;
i++)
325 for(
unsigned j=0;j<1;j++)
328 dtest_ds(
i,j)= dpsi_ds(
i,j);
352 template<
class ELEMENT>
360 const unsigned& n_terms) :
361 Outer_radius(outer_radius), N_terms(n_terms)
372 return Gamma_at_gauss_point[el_pt];
380 return D_Gamma_at_gauss_point[el_pt];
386 return Outer_radius ;
412 std::map<FiniteElement*,Vector<std::map<unsigned,std::complex<double> > > >
424 template<
class ELEMENT>
444 fill_in_generic_residual_contribution_fourier_decomposed_helmholtz_DtN_bc
455 fill_in_generic_residual_contribution_fourier_decomposed_helmholtz_DtN_bc
456 (residuals,jacobian,1);
464 void compute_gamma_contribution(
const double& theta,
const unsigned& n,
465 std::complex<double>& gamma_con,
466 std::map<
unsigned,std::complex<double> >&
474 return Outer_boundary_mesh_pt;
478 void set_outer_boundary_mesh_pt
481 Outer_boundary_mesh_pt=mesh_pt;
491 std::set<Node*> node_set;
492 unsigned nel=Outer_boundary_mesh_pt->nelement();
493 for (
unsigned e=0;
e<nel;
e++)
495 FiniteElement* el_pt=Outer_boundary_mesh_pt->finite_element_pt(
e);
496 unsigned nnod=el_pt->
nnode();
497 for (
unsigned j=0;j<nnod;j++)
504 node_set.insert(nod_pt);
509 unsigned nnod=this->
nnode();
510 for (
unsigned j=0;j<nnod;j++)
513 node_set.erase(nod_pt);
525 for (std::set<Node*>::iterator it=node_set.begin();
526 it!=node_set.end();it++)
539 void fill_in_generic_residual_contribution_fourier_decomposed_helmholtz_DtN_bc
541 const unsigned& flag)
544 const unsigned n_node = this->
nnode();
557 int local_eqn_real=0,local_unknown_real=0,global_unk_real=0,
558 local_eqn_imag=0,local_unknown_imag=0,global_unk_imag=0;
559 int external_global_unk_real=0, external_unknown_real=0,
560 external_global_unk_imag=0, external_unknown_imag=0;
566 gamma(Outer_boundary_mesh_pt->gamma_at_gauss_point(
this));
569 d_gamma(Outer_boundary_mesh_pt->d_gamma_at_gauss_point(
this));
573 for(
unsigned ipt=0;ipt<n_intpt;ipt++)
576 for(
unsigned i=0;
i<1;
i++)
594 for (
unsigned j=0;j<n_node;j++)
601 for(
unsigned l=0;l<n_node;l++)
610 if(local_eqn_real >= 0)
613 residuals[local_eqn_real] +=gamma[ipt].real()*test[l]*r*
W;
620 for(
unsigned l2=0;l2<n_node;l2++)
630 if(local_unknown_real >= 0)
633 global_unk_real=this->
eqn_number(local_unknown_real);
634 jacobian(local_eqn_real,local_unknown_real)
635 +=d_gamma[ipt][global_unk_real].real()*test[l]*r*
W;
637 if(local_unknown_imag >= 0)
640 global_unk_imag=this->
eqn_number(local_unknown_imag);
641 jacobian(local_eqn_real,local_unknown_imag)
642 +=d_gamma[ipt][global_unk_imag].real()*test[l]*r*
W;
649 for(
unsigned l2=0;l2<n_ext_data;l2++)
659 if(external_unknown_real >= 0)
662 external_global_unk_real=this->
eqn_number(external_unknown_real);
663 jacobian(local_eqn_real,external_unknown_real)
664 +=d_gamma[ipt][external_global_unk_real].real()*test[l]*r*
W;
666 if(external_unknown_imag >= 0)
669 external_global_unk_imag=this->
eqn_number(external_unknown_imag);
670 jacobian(local_eqn_real,external_unknown_imag)
671 +=d_gamma[ipt][external_global_unk_imag].real()*test[l]*r*
W;
677 if(local_eqn_imag >= 0)
680 residuals[local_eqn_imag] +=gamma[ipt].imag()*test[l]*r*
W;
687 for(
unsigned l2=0;l2<n_node;l2++)
697 if(local_unknown_real >= 0)
700 global_unk_real=this->
eqn_number(local_unknown_real);
701 jacobian(local_eqn_imag,local_unknown_real)
702 +=d_gamma[ipt][global_unk_real].imag()*test[l]*r*
W;
704 if(local_unknown_imag >= 0)
707 global_unk_imag=this->
eqn_number(local_unknown_imag);
708 jacobian(local_eqn_imag,local_unknown_imag)
709 +=d_gamma[ipt][global_unk_imag].imag()*test[l]*r*
W;
717 for(
unsigned l2=0;l2<n_ext_data;l2++)
727 if(external_unknown_real >= 0)
730 external_global_unk_real=this->
eqn_number(external_unknown_real);
731 jacobian(local_eqn_imag,external_unknown_real)
732 +=d_gamma[ipt][external_global_unk_real].imag()*test[l]*r*
W;
734 if(external_unknown_imag >= 0)
737 external_global_unk_imag=
739 jacobian(local_eqn_imag,external_unknown_imag)
740 +=d_gamma[ipt][external_global_unk_imag].imag()*test[l]*r*
W;
771 template<
class ELEMENT>
776 std::complex<double>& gamma_con,
777 std::map<
unsigned,std::complex<double> >& d_gamma_con)
780 int n_fourier_helmholtz=
784 const std::complex<double>
I(0.0,1.0);
787 const unsigned n_node = this->
nnode();
794 int local_unknown_real=0, local_unknown_imag=0;
795 int global_eqn_real=0,global_eqn_imag=0;
804 gamma_con=std::complex<double>(0.0,0.0);
809 for(
unsigned ipt=0;ipt<n_intpt;ipt++)
812 for(
unsigned i=0;
i<1;
i++)
828 std::complex<double> interpolated_u(0.0,0.0);
831 for(
unsigned l=0;l<n_node;l++)
834 for(
unsigned i=0;
i<2;
i++)
841 std::complex<double> u_value(
845 interpolated_u += u_value*psi(l);
853 double phi=atan2(interpolated_x[0],interpolated_x[1]);
856 double dphi_ds=-std::fabs(-interpolated_dxds[1]/interpolated_x[0]);
860 (n,n_fourier_helmholtz,cos(theta));
863 (n,n_fourier_helmholtz,cos(phi));
866 interpolated_u*p_phi*p_theta*sin(phi)*w*dphi_ds;
869 for(
unsigned l=0;l<n_node;l++)
874 if (local_unknown_real >= 0)
876 global_eqn_real=this->
eqn_number(local_unknown_real);
877 d_gamma_con[global_eqn_real]+=
878 psi(l)*p_phi*p_theta*sin(phi)*w*dphi_ds;
884 if (local_unknown_imag >= 0)
886 global_eqn_imag=this->
eqn_number(local_unknown_imag);
887 d_gamma_con[global_eqn_imag]+=
888 I*psi(l)*p_phi*p_theta*sin(phi)*w*dphi_ds;
905 namespace ToleranceForFourierDecomposedHelmholtzOuterBoundary
918 namespace ToleranceForFourierDecomposedHelmholtzOuterBoundary
936 template<
class ELEMENT>
942 unsigned nel=this->nelement();
943 for (
unsigned e=0;
e<nel;
e++)
946 unsigned nnod=fe_pt->
nnode();
947 for (
unsigned j=0;j<nnod;j++)
957 double r=sqrt(x[0]*x[0]+x[1]*x[1]);
960 if (Outer_radius==0.0)
963 "Outer radius for DtN BC must not be zero!",
964 OOMPH_CURRENT_FUNCTION,
965 OOMPH_EXCEPTION_LOCATION);
968 if(std::fabs((r-this->Outer_radius)/Outer_radius)
971 std::ostringstream error_stream;
973 <<
"Node at " << x[0] <<
" " << x[1]
974 <<
" has radius " << r <<
" which does not " 975 <<
" agree with \nspecified outer radius " 976 << this->Outer_radius <<
" within relative tolerance " 978 <<
".\nYou can adjust the tolerance via\n" 979 <<
"ToleranceForFourierDecomposedHelmholtzOuterBoundary::Tol\n" 980 <<
"or recompile without PARANOID.\n";
983 OOMPH_CURRENT_FUNCTION,
984 OOMPH_EXCEPTION_LOCATION);
995 (this->element_pt(0));
996 double k=sqrt(dynamic_cast<ELEMENT*>(el_pt->bulk_element_pt())->k_squared());
997 int n_fourier_decomposed=
998 dynamic_cast<ELEMENT*
>(el_pt->bulk_element_pt())->fourier_wavenumber();
999 double n_hankel_order_max=double(N_terms)+0.5;
1000 double n_hankel_order_tmp=0.0;
1003 std::complex<double>
I(0.0,1.0);
1007 hp_a(N_terms+1), q(N_terms+1,std::complex<double>(0.0,0.0));
1009 djv(N_terms+1), dyv(N_terms+1);
1012 CRBond_Bessel::bessjyv(n_hankel_order_max,
1019 for(
unsigned j=0; j<N_terms+1;j++)
1021 h_a[j]=jv[j]+I*yv[j];
1022 hp_a[j]=djv[j]+I*dyv[j];
1026 for (
unsigned i=n_fourier_decomposed;
i<N_terms;
i++)
1032 (hp_a[
i]-h_a[
i]/(2.0*k*Outer_radius))*
1033 (2.0*double(
i)+1.0)/
1040 unsigned nel=this->nelement();
1041 for (
unsigned e=0;
e<nel;
e++)
1046 (this->element_pt(
e));
1049 const unsigned n_intpt =el_pt->
integral_pt()->nweight();
1053 n_intpt,std::complex<double>(0.0,0.0));
1055 d_gamma_vector(n_intpt);
1058 for(
unsigned ipt=0;ipt<n_intpt;ipt++)
1065 for(
unsigned i=0;
i<el_pt->
dim();
i++)
1074 double theta=atan2(x[0],x[1]);
1077 std::complex<double> gamma_con(0.0,0.0);
1078 std::map<unsigned,std::complex<double> > d_gamma_con;
1081 for (
unsigned nn=n_fourier_decomposed;nn<N_terms;nn++)
1085 for (
unsigned ee=0;ee<nel;ee++)
1089 (this->element_pt(ee));
1093 theta,nn,gamma_con,d_gamma_con) ;
1095 unsigned n_node=eel_pt->
nnode();
1097 gamma_vector[ipt]+=q[nn]*gamma_con;
1098 for(
unsigned l=0;l<n_node;l++)
1101 int local_unknown_real=
1105 if (local_unknown_real >= 0)
1108 local_unknown_real);
1109 d_gamma_vector[ipt][global_eqn_real]+=
1110 q[nn]*d_gamma_con[global_eqn_real];
1114 int local_unknown_imag=
1118 if (local_unknown_imag >= 0)
1121 local_unknown_imag);
1122 d_gamma_vector[ipt][global_eqn_imag]+=
1123 q[nn]*d_gamma_con[global_eqn_imag];
1131 Gamma_at_gauss_point[el_pt]=gamma_vector;
1132 D_Gamma_at_gauss_point[el_pt]=d_gamma_vector;
1140 template<
class ELEMENT>
1164 "Bulk element must inherit from FourierDecomposedHelmholtzEquations.";
1167 OOMPH_CURRENT_FUNCTION,
1168 OOMPH_EXCEPTION_LOCATION);
1175 eqn_pt->u_index_fourier_decomposed_helmholtz();
void complete_setup_of_dependencies()
Complete the setup of additional dependencies arising through the far-away interaction with other nod...
void broken_copy(const std::string &class_name)
Issue error message and terminate execution.
double factorial(const unsigned &l)
Factorial.
FourierDecomposedHelmholtzDtNBoundaryElement(FiniteElement *const &bulk_el_pt, const int &face_index)
Construct element from specification of bulk element and face index.
double Tol
Relative tolerance to within radius of points on DtN boundary are allowed to deviate from specified v...
void setup_gamma()
Compute and store the gamma integral at all integration points of the constituent elements...
virtual void output(std::ostream &outfile)
Output the element data — typically the values at the nodes in a format suitable for post-processing...
double nodal_position(const unsigned &n, const unsigned &i) const
Return the i-th coordinate at local node n. If the node is hanging, the appropriate interpolation is ...
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Broken assignment operator.
int & face_index()
Index of the face (a number that uniquely identifies the face in the element)
virtual std::complex< unsigned > u_index_fourier_decomposed_helmholtz() const
Return the index at which the real/imag unknown value is stored.
const double Pi
50 digits from maple
void outer_unit_normal(const Vector< double > &s, Vector< double > &unit_normal) const
Compute outer unit normal at the specified local coordinate.
Vector< std::complex< double > > & gamma_at_gauss_point(FiniteElement *el_pt)
Gamma integral evaluated at Gauss points for specified element.
A general Finite Element class.
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 output(FILE *file_pt)
FourierDecomposedHelmholtzBCElementBase()
Broken empty constructor.
void compute_gamma_contribution(const double &theta, const unsigned &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 (for gamma integral, not the one from the Fourier decomposition of the Helmholtz equations!) and the polar angle theta as input.
virtual double weight(const unsigned &i) const =0
Return weight of i-th integration point.
unsigned & n_terms()
Number of terms used in the computation of the gamma integral.
double & outer_radius()
The outer radius.
FourierDecomposedHelmholtzDtNMesh< ELEMENT > * Outer_boundary_mesh_pt
Pointer to mesh of all DtN boundary condition elements (needed to get access to gamma values) ...
unsigned add_external_data(Data *const &data_pt, const bool &fd=true)
double J_eulerian(const Vector< double > &s) const
Return the Jacobian of mapping from local to global coordinates at local position s...
unsigned nexternal_data() const
Return the number of external data objects.
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Add the element's contribution to its residual vector.
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
double global_power_contribution()
Compute the element's contribution to the time-averaged radiated power over the artificial boundary...
double & x(const unsigned &i)
Return the i-th nodal coordinate.
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 ...
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)
double global_power_contribution(std::ofstream &outfile)
Compute the element's contribution to the time-averaged radiated power over the artificial boundary...
unsigned N_terms
Number of terms used in the Gamma computation.
virtual double knot(const unsigned &i, const unsigned &j) const =0
Return local coordinate s[j] of i-th integration point.
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 long eqn_number(const unsigned &ieqn_local) const
Return the global equation number corresponding to the ieqn_local-th local equation number...
void output(FILE *file_pt, const unsigned &n_plot)
C-style output function – forward to broken version in FiniteElement until somebody decides what exa...
FourierDecomposedHelmholtzDtNMesh< ELEMENT > * outer_boundary_mesh_pt() const
Access function to mesh of all DtN boundary condition elements (needed to get access to gamma values)...
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 void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Function to compute the geometric shape functions and derivatives w.r.t. local coordinates at local c...
double Outer_radius
Outer radius.
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
double nodal_value(const unsigned &n, const unsigned &i) const
Return the i-th value stored at local node n. Produces suitably interpolated values for hanging nodes...
FourierDecomposedHelmholtzDtNMesh(const double &outer_radius, const unsigned &n_terms)
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
std::map< FiniteElement *, Vector< std::complex< double > > > Gamma_at_gauss_point
Container to store the gamma integral for given Gauss point and element.
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...
virtual unsigned nweight() const =0
Return the number of integration points of the scheme.
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
FiniteElement *& bulk_element_pt()
Pointer to higher-dimensional "bulk" element.
void output(std::ostream &outfile, const unsigned &n_plot)
Output function – forward to broken version in FiniteElement until somebody decides what exactly the...
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...
virtual bool is_a_copy() const
Return a boolean to indicate whether the Data objact contains any copied values. A base Data object c...
void output(std::ostream &outfile)
unsigned nnode() const
Return the number of nodes.
Vector< double > local_coordinate_in_bulk(const Vector< double > &s) const
Return vector of local coordinates in bulk element, given the local coordinates in this FaceElement...
double shape_and_test(const Vector< double > &s, Shape &psi, Shape &test) const
Function to compute the test functions and to return the Jacobian of mapping between local and global...
virtual void shape(const Vector< double > &s, Shape &psi) const =0
Calculate the geometric shape functions at local coordinate s. This function must be overloaded for e...
int external_local_eqn(const unsigned &i, const unsigned &j)
Return the local equation number corresponding to the j-th value stored at the i-th external data...
static DenseMatrix< double > Dummy_matrix
Empty dense matrix used as a dummy argument to combined residual and jacobian functions in the case w...
double plgndr2(const unsigned &l, const unsigned &m, const double &x)
Legendre polynomials depending on two parameters.
A class for elements that allow the approximation of the Sommerfeld radiation BC for Fourier decompos...
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_fourier_decomposed_helmholtz
The index at which the real and imag part of the unknown is stored at the nodes.
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...
FourierDecomposedHelmholtzBCElementBase(const FourierDecomposedHelmholtzBCElementBase &dummy)
Broken copy constructor.