28 #ifndef OOMPH_PML_HELMHOLTZ_FLUX_ELEMENTS_HEADER
29 #define OOMPH_PML_HELMHOLTZ_FLUX_ELEMENTS_HEADER
34 #include <oomph-lib-config.h>
38 #include "../generic/Qelements.h"
50 template<
class ELEMENT>
64 "Don't call empty constructor for PMLHelmholtzPowerElement",
65 OOMPH_CURRENT_FUNCTION,
66 OOMPH_EXCEPTION_LOCATION);
88 const unsigned&
i)
const
108 std::ofstream outfile;
119 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(this->
bulk_element_pt());
122 unsigned nnode_bulk = bulk_elem_pt->nnode();
123 const unsigned n_node_local =
nnode();
126 const unsigned bulk_dim = bulk_elem_pt->dim();
127 const unsigned local_dim = this->
dim();
130 Shape psi(n_node_local);
133 Shape psi_bulk(nnode_bulk);
134 DShape dpsi_bulk_dx(nnode_bulk, bulk_dim);
147 if (outfile.is_open())
154 for (
unsigned ipt = 0; ipt < n_intpt; ipt++)
157 for (
unsigned i = 0;
i < local_dim;
i++)
179 (void)bulk_elem_pt->dshape_eulerian(s_bulk, psi_bulk, dpsi_bulk_dx);
183 std::complex<double> dphi_dn(0.0, 0.0);
185 bulk_dim, std::complex<double>(0.0, 0.0));
186 std::complex<double> interpolated_phi(0.0, 0.0);
192 for (
unsigned l = 0; l < nnode_bulk; l++)
195 const std::complex<double> phi_value(
196 bulk_elem_pt->nodal_value(l,
197 bulk_elem_pt->u_index_helmholtz().real()),
198 bulk_elem_pt->nodal_value(
199 l, bulk_elem_pt->u_index_helmholtz().imag()));
202 for (
unsigned i = 0;
i < bulk_dim;
i++)
204 interpolated_dphidx[
i] += phi_value * dpsi_bulk_dx(l,
i);
208 for (
unsigned l = 0; l < n_node_local; l++)
211 const std::complex<double> phi_value(
215 interpolated_phi += phi_value * psi(l);
219 for (
unsigned i = 0;
i < bulk_dim;
i++)
221 dphi_dn += interpolated_dphidx[
i] * unit_normal[
i];
225 double integrand = 0.5 * (interpolated_phi.real() * dphi_dn.imag() -
226 interpolated_phi.imag() * dphi_dn.real());
229 if (outfile.is_open())
232 double phi = atan2(x[1], x[0]);
233 outfile << x[0] <<
" " << x[1] <<
" " << phi <<
" " << integrand
238 power += integrand *
W;
250 std::ofstream outfile;
261 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(this->
bulk_element_pt());
264 unsigned nnode_bulk = bulk_elem_pt->nnode();
265 const unsigned n_node_local =
nnode();
268 const unsigned bulk_dim = bulk_elem_pt->dim();
269 const unsigned local_dim = this->
dim();
272 Shape psi(n_node_local);
275 Shape psi_bulk(nnode_bulk);
276 DShape dpsi_bulk_dx(nnode_bulk, bulk_dim);
286 std::complex<double> flux(0.0, 0.0);
289 if (outfile.is_open())
296 for (
unsigned ipt = 0; ipt < n_intpt; ipt++)
299 for (
unsigned i = 0;
i < local_dim;
i++)
321 (void)bulk_elem_pt->dshape_eulerian(s_bulk, psi_bulk, dpsi_bulk_dx);
325 std::complex<double> dphi_dn(0.0, 0.0);
327 bulk_dim, std::complex<double>(0.0, 0.0));
333 for (
unsigned l = 0; l < nnode_bulk; l++)
336 const std::complex<double> phi_value(
337 bulk_elem_pt->nodal_value(l,
338 bulk_elem_pt->u_index_helmholtz().real()),
339 bulk_elem_pt->nodal_value(
340 l, bulk_elem_pt->u_index_helmholtz().imag()));
343 for (
unsigned i = 0;
i < bulk_dim;
i++)
345 interpolated_dphidx[
i] += phi_value * dpsi_bulk_dx(l,
i);
351 for (
unsigned i = 0;
i < bulk_dim;
i++)
353 dphi_dn += interpolated_dphidx[
i] * unit_normal[
i];
357 if (outfile.is_open())
360 outfile << x[0] <<
" " << x[1] <<
" " << dphi_dn.real() <<
" "
361 << dphi_dn.imag() <<
"\n";
393 template<
class ELEMENT>
401 ELEMENT* elem_pt =
dynamic_cast<ELEMENT*
>(bulk_el_pt);
403 if (elem_pt->dim() == 3)
412 throw OomphLibError(
"This flux element will not work correctly if "
413 "nodes are hanging\n",
414 OOMPH_CURRENT_FUNCTION,
415 OOMPH_EXCEPTION_LOCATION);
451 "Bulk element must inherit from PMLHelmholtzEquations.";
453 "Nodes are one dimensional, but cannot cast the bulk element to\n";
454 error_string +=
"PMLHelmholtzEquations<1>\n.";
455 error_string +=
"If you desire this functionality, you must "
456 "implement it yourself\n";
459 error_string, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
479 "Bulk element must inherit from PMLHelmholtzEquations.";
481 "Nodes are two dimensional, but cannot cast the bulk element to\n";
482 error_string +=
"PMLHelmholtzEquations<2>\n.";
483 error_string +=
"If you desire this functionality, you must "
484 "implement it yourself\n";
487 error_string, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
507 "Bulk element must inherit from PMLHelmholtzEquations.";
508 error_string +=
"Nodes are three dimensional, but cannot cast the "
510 error_string +=
"PMLHelmholtzEquations<3>\n.";
511 error_string +=
"If you desire this functionality, you must "
512 "implement it yourself\n";
515 error_string, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
527 std::ostringstream error_stream;
528 error_stream <<
"Dimension of node is " <<
Dim
529 <<
". It should be 1,2, or 3!" << std::endl;
532 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
549 template<
class ELEMENT>
558 std::complex<double>& flux);
569 "Don't call empty constructor for PMLHelmholtzFluxElement",
570 OOMPH_CURRENT_FUNCTION,
571 OOMPH_EXCEPTION_LOCATION);
605 residuals, jacobian, 1);
616 const unsigned&
i)
const
631 void output(std::ostream& outfile,
const unsigned& n_plot)
647 void output(FILE* file_pt,
const unsigned& n_plot)
676 std::list<std::pair<unsigned long, unsigned>>& dof_lookup_list)
const
679 std::pair<unsigned, unsigned> dof_lookup;
682 unsigned n_node = this->
nnode();
685 for (
unsigned n = 0; n < n_node; n++)
692 if (local_eqn_number >= 0)
696 dof_lookup.first = this->
eqn_number(local_eqn_number);
697 dof_lookup.second = 0;
700 dof_lookup_list.push_front(dof_lookup);
708 if (local_eqn_number >= 0)
712 dof_lookup.first = this->
eqn_number(local_eqn_number);
713 dof_lookup.second = 1;
716 dof_lookup_list.push_front(dof_lookup);
730 unsigned n_node =
nnode();
736 for (
unsigned i = 0;
i < n_node;
i++)
754 unsigned n_node =
nnode();
760 for (
unsigned i = 0;
i < n_node;
i++)
777 flux = std::complex<double>(0.0, 0.0);
782 (*Flux_fct_pt)(x, flux);
798 const unsigned& flag);
820 template<
class ELEMENT>
828 ELEMENT* elem_pt =
dynamic_cast<ELEMENT*
>(bulk_el_pt);
830 if (elem_pt->dim() == 3)
839 throw OomphLibError(
"This flux element will not work correctly if "
840 "nodes are hanging\n",
841 OOMPH_CURRENT_FUNCTION,
842 OOMPH_EXCEPTION_LOCATION);
881 "Bulk element must inherit from PMLHelmholtzEquations.";
883 "Nodes are one dimensional, but cannot cast the bulk element to\n";
884 error_string +=
"PMLHelmholtzEquations<1>\n.";
885 error_string +=
"If you desire this functionality, you must "
886 "implement it yourself\n";
889 error_string, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
909 "Bulk element must inherit from PMLHelmholtzEquations.";
911 "Nodes are two dimensional, but cannot cast the bulk element to\n";
912 error_string +=
"PMLHelmholtzEquations<2>\n.";
913 error_string +=
"If you desire this functionality, you must "
914 "implement it yourself\n";
917 error_string, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
937 "Bulk element must inherit from PMLHelmholtzEquations.";
938 error_string +=
"Nodes are three dimensional, but cannot cast the "
940 error_string +=
"PMLHelmholtzEquations<3>\n.";
941 error_string +=
"If you desire this functionality, you must "
942 "implement it yourself\n";
945 error_string, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
957 std::ostringstream error_stream;
958 error_stream <<
"Dimension of node is " <<
Dim
959 <<
". It should be 1,2, or 3!" << std::endl;
962 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
971 template<
class ELEMENT>
976 const unsigned& flag)
979 const unsigned n_node = nnode();
982 Shape psif(n_node), testf(n_node);
985 const unsigned n_intpt = integral_pt()->nweight();
991 int local_eqn_real = 0, local_eqn_imag = 0;
995 for (
unsigned ipt = 0; ipt < n_intpt; ipt++)
998 for (
unsigned i = 0;
i < (
Dim - 1);
i++)
1000 s[
i] = integral_pt()->knot(ipt,
i);
1004 double w = integral_pt()->weight(ipt);
1008 double J = shape_and_test(
s, psif, testf);
1017 for (
unsigned l = 0; l < n_node; l++)
1019 for (
unsigned i = 0;
i <
Dim;
i++)
1021 interpolated_x[
i] += nodal_position(l,
i) * psif[l];
1026 std::complex<double> flux(0.0, 0.0);
1027 get_flux(interpolated_x, flux);
1031 for (
unsigned l = 0; l < n_node; l++)
1033 local_eqn_real = nodal_local_eqn(l, U_index_helmholtz.real());
1035 if (local_eqn_real >= 0)
1038 residuals[local_eqn_real] -= flux.real() * testf[l] *
W;
1044 local_eqn_imag = nodal_local_eqn(l, U_index_helmholtz.imag());
1046 if (local_eqn_imag >= 0)
1049 residuals[local_eqn_imag] -= flux.imag() * testf[l] *
W;
A Class for the derivatives of shape functions The class design is essentially the same as Shape,...
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....
double J_eulerian_at_knot(const unsigned &ipt) const
Return the Jacobian of the mapping from local to global coordinates at the ipt-th integration point O...
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
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 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 void shape_at_knot(const unsigned &ipt, Shape &psi) const
Return the geometric shape function at the ipt-th integration point.
bool has_hanging_nodes() const
Return boolean to indicate if any of the element's nodes are geometrically hanging.
unsigned long eqn_number(const unsigned &ieqn_local) const
Return the global equation number corresponding to the ieqn_local-th local equation number.
int local_eqn_number(const unsigned long &ieqn_global) const
Return the local equation number corresponding to the ieqn_global-th global 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...
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.
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
An OomphLibError object which should be thrown when an run-time error is encountered....
A class for all isoparametric elements that solve the Helmholtz equations with pml capabilities....
virtual std::complex< unsigned > u_index_helmholtz() const
Broken assignment operator.
/////////////////////////////////////////////////////////////////////// /////////////////////////////...
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.
virtual std::complex< unsigned > u_index_helmholtz() const
Return the index at which the unknown value is stored.
void output(FILE *file_pt, const unsigned &n_plot)
C-style output function – forward to broken version in FiniteElement until somebody decides what exac...
std::complex< unsigned > U_index_helmholtz
The index at which the real and imag part of the unknown is stored at the nodes.
void output(std::ostream &outfile, const unsigned &n_plot)
Output function – forward to broken version in FiniteElement until somebody decides what exactly they...
double shape_and_test(const Vector< double > &s, Shape &psi, Shape &test) const
Function to compute the shape and test functions and to return the Jacobian of mapping between local ...
void get_dof_numbers_for_unknowns(std::list< std::pair< unsigned long, unsigned >> &dof_lookup_list) const
Create a list of pairs for all unknowns in this element, so that the first entry in each pair contain...
PMLHelmholtzFluxElement(const PMLHelmholtzFluxElement &dummy)=delete
Broken copy constructor.
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Specify the value of nodal zeta from the face geometry The "global" intrinsic coordinate of the eleme...
unsigned Dim
The spatial dimension of the problem.
unsigned ndof_types() const
The number of "DOF types" that degrees of freedom in this element are sub-divided into: real and imag...
PMLHelmholtzPrescribedFluxFctPt Flux_fct_pt
Function pointer to the (global) prescribed-flux function.
PMLHelmholtzPrescribedFluxFctPt & flux_fct_pt()
Broken assignment operator.
void get_flux(const Vector< double > &x, std::complex< double > &flux)
Function to calculate the prescribed flux at a given spatial position.
virtual void fill_in_generic_residual_contribution_helmholtz_flux(Vector< double > &residuals, DenseMatrix< double > &jacobian, const unsigned &flag)
Add the element's contribution to its residual vector. flag=1(or 0): do (or don't) compute the contri...
void output(FILE *file_pt)
C-style output function – forward to broken version in FiniteElement until somebody decides what exac...
PMLHelmholtzFluxElement()
Broken empty constructor.
double shape_and_test_at_knot(const unsigned &ipt, Shape &psi, Shape &test) const
Function to compute the shape and test functions and to return the Jacobian of mapping between local ...
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Add the element's contribution to its residual vector.
void(* PMLHelmholtzPrescribedFluxFctPt)(const Vector< double > &x, std::complex< double > &flux)
Function pointer to the prescribed-flux function fct(x,f(x)) – x is a Vector and the flux is a comple...
void output(std::ostream &outfile)
Output function – forward to broken version in FiniteElement until somebody decides what exactly they...
A class for elements that allow the post-processing of radiated power and flux on the boundaries of P...
double global_power_contribution(std::ofstream &outfile)
Compute the element's contribution to the time-averaged radiated power over the artificial boundary....
std::complex< unsigned > U_index_helmholtz
The index at which the real and imag part of the unknown is stored at the nodes.
std::complex< double > global_flux_contribution()
Compute the element's contribution to the time-averaged flux.
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Broken assignment operator.
double global_power_contribution()
Compute the element's contribution to the time-averaged radiated power over the artificial boundary.
unsigned Dim
The spatial dimension of the problem.
PMLHelmholtzPowerElement()
Broken empty constructor.
PMLHelmholtzPowerElement(const PMLHelmholtzPowerElement &dummy)=delete
Broken copy constructor.
std::complex< double > global_flux_contribution(std::ofstream &outfile)
Compute the element's contribution to the integral of the flux over the artificial boundary....
virtual std::complex< unsigned > u_index_helmholtz() const
Return the index at which the unknown value is stored.
RefineableElements are FiniteElements that may be subdivided into children to provide a better local ...
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.
unsigned Dim
Dimension of zeta tuples (set by get_dim_helper) – needed because we store the scalar coordinates in ...
//////////////////////////////////////////////////////////////////// ////////////////////////////////...