28 #ifndef OOMPH_FOURIER_DECOMPOSED_HELMHOLTZ_BC_ELEMENTS_HEADER
29 #define OOMPH_FOURIER_DECOMPOSED_HELMHOLTZ_BC_ELEMENTS_HEADER
34 #include <oomph-lib-config.h>
41 #include "oomph_crbond_bessel.h"
58 template<
class ELEMENT>
73 "FourierDecomposedHelmholtzBCElementBase",
74 OOMPH_CURRENT_FUNCTION,
75 OOMPH_EXCEPTION_LOCATION);
98 const unsigned&
i)
const
113 void output(std::ostream& outfile,
const unsigned& n_plot)
128 void output(FILE* file_pt,
const unsigned& n_plot)
138 return std::complex<unsigned>(
148 std::ofstream outfile;
159 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(this->
bulk_element_pt());
162 unsigned nnode_bulk = bulk_elem_pt->nnode();
163 const unsigned n_node_local = this->
nnode();
166 const unsigned bulk_dim = bulk_elem_pt->dim();
167 const unsigned local_dim = this->
node_pt(0)->
ndim();
170 Shape psi(n_node_local);
173 Shape psi_bulk(nnode_bulk);
174 DShape dpsi_bulk_dx(nnode_bulk, bulk_dim);
187 if (outfile.is_open())
194 for (
unsigned ipt = 0; ipt < n_intpt; ipt++)
197 for (
unsigned i = 0;
i < (local_dim - 1);
i++)
219 (void)bulk_elem_pt->dshape_eulerian(s_bulk, psi_bulk, dpsi_bulk_dx);
223 std::complex<double> dphi_dn(0.0, 0.0);
225 std::complex<double> interpolated_phi(0.0, 0.0);
231 for (
unsigned l = 0; l < nnode_bulk; l++)
234 const std::complex<double> phi_value(
235 bulk_elem_pt->nodal_value(
236 l, bulk_elem_pt->u_index_fourier_decomposed_helmholtz().real()),
237 bulk_elem_pt->nodal_value(
238 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];
264 double integrand = (interpolated_phi.real() * dphi_dn.imag() -
265 interpolated_phi.imag() * dphi_dn.real());
268 double theta = atan2(x[0], x[1]);
270 if (outfile.is_open())
272 outfile << x[0] <<
" " << x[1] <<
" " << theta <<
" " << integrand
294 unsigned nnod =
nnode();
295 for (
unsigned i = 0;
i < nnod;
i++)
315 unsigned n_node =
nnode();
321 for (
unsigned i = 0;
i < n_node;
i++)
323 for (
unsigned j = 0; j < 1; j++)
326 dtest_ds(
i, j) = dpsi_ds(
i, j);
349 template<
class ELEMENT>
408 std::map<FiniteElement*, Vector<std::map<unsigned, std::complex<double>>>>
419 template<
class ELEMENT>
449 residuals, jacobian, 1);
460 std::complex<double>& gamma_con,
461 std::map<
unsigned, std::complex<double>>& d_gamma_con);
485 std::set<Node*> node_set;
487 for (
unsigned e = 0;
e < nel;
e++)
490 unsigned nnod = el_pt->
nnode();
491 for (
unsigned j = 0; j < nnod; j++)
498 node_set.insert(nod_pt);
503 unsigned nnod = this->
nnode();
504 for (
unsigned j = 0; j < nnod; j++)
507 node_set.erase(nod_pt);
519 for (std::set<Node*>::iterator it = node_set.begin();
520 it != node_set.end();
535 const unsigned& flag)
538 const unsigned n_node = this->
nnode();
551 int local_eqn_real = 0, local_unknown_real = 0, global_unk_real = 0,
552 local_eqn_imag = 0, local_unknown_imag = 0, global_unk_imag = 0;
553 int external_global_unk_real = 0, external_unknown_real = 0,
554 external_global_unk_imag = 0, external_unknown_imag = 0;
567 for (
unsigned ipt = 0; ipt < n_intpt; ipt++)
570 for (
unsigned i = 0;
i < 1;
i++)
588 for (
unsigned j = 0; j < n_node; j++)
590 r += this->
node_pt(j)->
x(0) * psi(j);
595 for (
unsigned l = 0; l < n_node; l++)
604 if (local_eqn_real >= 0)
607 residuals[local_eqn_real] += gamma[ipt].real() * test[l] * r *
W;
614 for (
unsigned l2 = 0; l2 < n_node; l2++)
624 if (local_unknown_real >= 0)
627 global_unk_real = this->
eqn_number(local_unknown_real);
628 jacobian(local_eqn_real, local_unknown_real) +=
629 d_gamma[ipt][global_unk_real].real() * test[l] * r *
W;
631 if (local_unknown_imag >= 0)
634 global_unk_imag = this->
eqn_number(local_unknown_imag);
635 jacobian(local_eqn_real, local_unknown_imag) +=
636 d_gamma[ipt][global_unk_imag].real() * test[l] * r *
W;
643 for (
unsigned l2 = 0; l2 < n_ext_data; l2++)
653 if (external_unknown_real >= 0)
656 external_global_unk_real =
658 jacobian(local_eqn_real, external_unknown_real) +=
659 d_gamma[ipt][external_global_unk_real].real() * test[l] *
662 if (external_unknown_imag >= 0)
665 external_global_unk_imag =
667 jacobian(local_eqn_real, external_unknown_imag) +=
668 d_gamma[ipt][external_global_unk_imag].real() * test[l] *
675 if (local_eqn_imag >= 0)
678 residuals[local_eqn_imag] += gamma[ipt].imag() * test[l] * r *
W;
685 for (
unsigned l2 = 0; l2 < n_node; l2++)
695 if (local_unknown_real >= 0)
698 global_unk_real = this->
eqn_number(local_unknown_real);
699 jacobian(local_eqn_imag, local_unknown_real) +=
700 d_gamma[ipt][global_unk_real].imag() * test[l] * r *
W;
702 if (local_unknown_imag >= 0)
705 global_unk_imag = this->
eqn_number(local_unknown_imag);
706 jacobian(local_eqn_imag, local_unknown_imag) +=
707 d_gamma[ipt][global_unk_imag].imag() * test[l] * r *
W;
715 for (
unsigned l2 = 0; l2 < n_ext_data; l2++)
725 if (external_unknown_real >= 0)
728 external_global_unk_real =
730 jacobian(local_eqn_imag, external_unknown_real) +=
731 d_gamma[ipt][external_global_unk_real].imag() * test[l] *
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] *
770 template<
class ELEMENT>
775 std::complex<double>& gamma_con,
776 std::map<
unsigned, std::complex<double>>& d_gamma_con)
779 int n_fourier_helmholtz =
780 dynamic_cast<ELEMENT*
>(this->bulk_element_pt())->fourier_wavenumber();
783 const std::complex<double>
I(0.0, 1.0);
786 const unsigned n_node = this->nnode();
793 int local_unknown_real = 0, local_unknown_imag = 0;
794 int global_eqn_real = 0, global_eqn_imag = 0;
797 const unsigned n_intpt = this->integral_pt()->nweight();
803 gamma_con = std::complex<double>(0.0, 0.0);
808 for (
unsigned ipt = 0; ipt < n_intpt; ipt++)
811 for (
unsigned i = 0;
i < 1;
i++)
813 s[
i] = this->integral_pt()->knot(ipt,
i);
817 double w = this->integral_pt()->weight(ipt);
820 this->dshape_local(
s, psi, dpsi);
827 std::complex<double> interpolated_u(0.0, 0.0);
830 for (
unsigned l = 0; l < n_node; l++)
833 for (
unsigned i = 0;
i < 2;
i++)
835 interpolated_x[
i] += this->nodal_position(l,
i) * psi[l];
836 interpolated_dxds[
i] += this->nodal_position(l,
i) * dpsi(l, 0);
840 std::complex<double> u_value(
842 this->U_index_fourier_decomposed_helmholtz.real()),
844 this->U_index_fourier_decomposed_helmholtz.imag()));
846 interpolated_u += u_value * psi(l);
854 double phi = atan2(interpolated_x[0], interpolated_x[1]);
857 double dphi_ds = -std::fabs(-interpolated_dxds[1] / interpolated_x[0]);
866 gamma_con += interpolated_u * p_phi * p_theta * sin(phi) * w * dphi_ds;
869 for (
unsigned l = 0; l < n_node; l++)
872 local_unknown_real = this->nodal_local_eqn(
873 l, this->U_index_fourier_decomposed_helmholtz.real());
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;
882 local_unknown_imag = this->nodal_local_eqn(
883 l, this->U_index_fourier_decomposed_helmholtz.imag());
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;
904 namespace ToleranceForFourierDecomposedHelmholtzOuterBoundary
917 namespace ToleranceForFourierDecomposedHelmholtzOuterBoundary
935 template<
class ELEMENT>
941 unsigned nel = this->nelement();
942 for (
unsigned e = 0;
e < nel;
e++)
945 unsigned nnod = fe_pt->
nnode();
946 for (
unsigned j = 0; j < nnod; j++)
956 double r = sqrt(x[0] * x[0] + x[1] * x[1]);
959 if (Outer_radius == 0.0)
961 throw OomphLibError(
"Outer radius for DtN BC must not be zero!",
962 OOMPH_CURRENT_FUNCTION,
963 OOMPH_EXCEPTION_LOCATION);
966 if (std::fabs((r - this->Outer_radius) / Outer_radius) >
969 std::ostringstream error_stream;
971 <<
"Node at " << x[0] <<
" " << x[1] <<
" has radius " << r
972 <<
" which does not "
973 <<
" agree with \nspecified outer radius " << this->Outer_radius
974 <<
" within relative tolerance "
976 <<
".\nYou can adjust the tolerance via\n"
977 <<
"ToleranceForFourierDecomposedHelmholtzOuterBoundary::Tol\n"
978 <<
"or recompile without PARANOID.\n";
980 OOMPH_CURRENT_FUNCTION,
981 OOMPH_EXCEPTION_LOCATION);
992 this->element_pt(0));
995 int n_fourier_decomposed =
996 dynamic_cast<ELEMENT*
>(el_pt->
bulk_element_pt())->fourier_wavenumber();
997 double n_hankel_order_max = double(N_terms) + 0.5;
998 double n_hankel_order_tmp = 0.0;
1001 std::complex<double>
I(0.0, 1.0);
1005 q(N_terms + 1, std::complex<double>(0.0, 0.0));
1006 Vector<double> jv(N_terms + 1), yv(N_terms + 1), djv(N_terms + 1),
1010 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++)
1034 (hp_a[
i] - h_a[
i] / (2.0 * k * Outer_radius)) *
1035 (2.0 * double(
i) + 1.0) /
1042 unsigned nel = this->nelement();
1043 for (
unsigned e = 0;
e < nel;
e++)
1048 this->element_pt(
e));
1055 std::complex<double>(0.0, 0.0));
1059 for (
unsigned ipt = 0; ipt < n_intpt; ipt++)
1066 for (
unsigned i = 0;
i < el_pt->
dim();
i++)
1075 double theta = atan2(x[0], x[1]);
1078 std::complex<double> gamma_con(0.0, 0.0);
1079 std::map<unsigned, std::complex<double>> d_gamma_con;
1082 for (
unsigned nn = n_fourier_decomposed; nn < N_terms; nn++)
1086 for (
unsigned ee = 0; ee < nel; ee++)
1091 this->element_pt(ee));
1095 theta, nn, gamma_con, d_gamma_con);
1097 unsigned n_node = eel_pt->
nnode();
1099 gamma_vector[ipt] += q[nn] * gamma_con;
1100 for (
unsigned l = 0; l < n_node; l++)
1106 if (local_unknown_real >= 0)
1108 int global_eqn_real = eel_pt->
eqn_number(local_unknown_real);
1109 d_gamma_vector[ipt][global_eqn_real] +=
1110 q[nn] * d_gamma_con[global_eqn_real];
1117 if (local_unknown_imag >= 0)
1119 int global_eqn_imag = eel_pt->
eqn_number(local_unknown_imag);
1120 d_gamma_vector[ipt][global_eqn_imag] +=
1121 q[nn] * d_gamma_con[global_eqn_imag];
1129 Gamma_at_gauss_point[el_pt] = gamma_vector;
1130 D_Gamma_at_gauss_point[el_pt] = d_gamma_vector;
1138 template<
class ELEMENT>
1141 const int& face_index)
1162 "Bulk element must inherit from FourierDecomposedHelmholtzEquations.";
1164 error_string, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
A Class for the derivatives of shape functions The class design is essentially the same as Shape,...
virtual bool is_a_copy() const
Return a boolean to indicate whether the Data objact contains any copied values. A base Data object c...
FaceElements are elements that coincide with the faces of higher-dimensional "bulk" elements....
int & face_index()
Index of the face (a number that uniquely identifies the face in the element)
void outer_unit_normal(const Vector< double > &s, Vector< double > &unit_normal) const
Compute outer unit normal at the specified local coordinate.
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,...
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.
FiniteElement *& bulk_element_pt()
Pointer to higher-dimensional "bulk" element.
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...
double J_eulerian(const Vector< double > &s) const
Return the Jacobian of mapping from local to global coordinates at local position s....
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
A general Finite Element class.
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...
virtual void output(std::ostream &outfile)
Output the element data — typically the values at the nodes in a format suitable for post-processing.
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 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.
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
unsigned nnode() const
Return the number of nodes.
Integral *const & integral_pt() const
Return the pointer to the integration scheme (const version)
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...
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....
////////////////////////////////////////////////////////////////// //////////////////////////////////...
FourierDecomposedHelmholtzBCElementBase()
Broken empty constructor.
void output(FILE *file_pt)
C-style output function – forward to broken version in FiniteElement until somebody decides what exac...
void output(std::ostream &outfile)
Output function – forward to broken version in FiniteElement until somebody decides what exactly they...
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...
double global_power_contribution(std::ofstream &outfile)
Compute the element's contribution to the time-averaged radiated power over the artificial boundary....
void output(std::ostream &outfile, const unsigned &n_plot)
Output function – forward to broken version in FiniteElement until somebody decides what exactly they...
void output(FILE *file_pt, const unsigned &n_plot)
C-style output function – forward to broken version in FiniteElement until somebody decides what exac...
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...
FourierDecomposedHelmholtzBCElementBase(const FourierDecomposedHelmholtzBCElementBase &dummy)=delete
Broken copy constructor.
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Broken assignment operator.
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.
double global_power_contribution()
Compute the element's contribution to the time-averaged radiated power over the artificial boundary.
virtual std::complex< unsigned > u_index_fourier_decomposed_helmholtz() const
Return the index at which the real/imag unknown value is stored.
//////////////////////////////////////////////////////////////////
void fill_in_generic_residual_contribution_fourier_decomposed_helmholtz_DtN_bc(Vector< double > &residuals, DenseMatrix< double > &jacobian, const unsigned &flag)
Compute the element's residual vector Jacobian matrix. Overloaded version, using the gamma computed i...
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.
FourierDecomposedHelmholtzDtNBoundaryElement(FiniteElement *const &bulk_el_pt, const int &face_index)
Construct element from specification of bulk element and face index.
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Add the element's contribution to its residual vector.
void complete_setup_of_dependencies()
Complete the setup of additional dependencies arising through the far-away interaction with other nod...
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....
FourierDecomposedHelmholtzDtNMesh< ELEMENT > * Outer_boundary_mesh_pt
Pointer to mesh of all DtN boundary condition elements (needed to get access to gamma values)
void set_outer_boundary_mesh_pt(FourierDecomposedHelmholtzDtNMesh< ELEMENT > *mesh_pt)
Set mesh of all DtN boundary condition elements.
FourierDecomposedHelmholtzDtNMesh< ELEMENT > * outer_boundary_mesh_pt() const
Access function to mesh of all DtN boundary condition elements (needed to get access to gamma values)
/////////////////////////////////////////////////////////////////// /////////////////////////////////...
Vector< std::complex< double > > & gamma_at_gauss_point(FiniteElement *el_pt)
Gamma integral evaluated at Gauss points for specified element.
std::map< FiniteElement *, Vector< std::complex< double > > > Gamma_at_gauss_point
Container to store the gamma integral for given Gauss point and element.
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.
FourierDecomposedHelmholtzDtNMesh(const double &outer_radius, const unsigned &n_terms)
Constructor: Specify radius of outer boundary and number of terms used in the computation of the gamm...
double & outer_radius()
The outer radius.
void setup_gamma()
Compute and store the gamma integral at all integration points of the constituent elements.
unsigned N_terms
Number of terms used in the Gamma computation.
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 ...
double Outer_radius
Outer radius.
unsigned & n_terms()
Number of terms used in the computation of the gamma integral.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
virtual std::complex< unsigned > u_index_fourier_decomposed_helmholtz() const
Broken assignment operator.
unsigned nexternal_data() const
Return the number of external data objects.
unsigned long eqn_number(const unsigned &ieqn_local) const
Return the global equation number corresponding to the ieqn_local-th local equation number.
static DenseMatrix< double > Dummy_matrix
Empty dense matrix used as a dummy argument to combined residual and jacobian functions in the case w...
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.
unsigned add_external_data(Data *const &data_pt, const bool &fd=true)
Add a (pointer to an) external data object to the element and return its index (i....
virtual double knot(const unsigned &i, const unsigned &j) const =0
Return local coordinate s[j] of i-th integration point.
virtual unsigned nweight() const =0
Return the number of integration points of the scheme.
virtual double weight(const unsigned &i) const =0
Return weight of i-th integration point.
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
double & x(const unsigned &i)
Return the i-th nodal coordinate.
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
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 ov...
An OomphLibError object which should be thrown when an run-time error is encountered....
A Class for shape functions. In simple cases, the shape functions have only one index that can be tho...
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
double factorial(const unsigned &l)
Factorial.
double plgndr2(const unsigned &l, const unsigned &m, const double &x)
Legendre polynomials depending on two parameters.
const double Pi
50 digits from maple
const std::complex< double > I(0.0, 1.0)
The imaginary unit.
double Tol
Relative tolerance to within radius of points on DtN boundary are allowed to deviate from specified v...
//////////////////////////////////////////////////////////////////// ////////////////////////////////...