26 #ifndef OOMPH_QUARTER_TUBE_MESH_TEMPLATE_CC
27 #define OOMPH_QUARTER_TUBE_MESH_TEMPLATE_CC
43 template<
class ELEMENT>
46 const double& fract_mid,
48 const unsigned& nlayer,
50 : Wall_pt(wall_pt), Xi_lo(xi_lo), Fract_mid(fract_mid), Xi_hi(xi_hi)
53 MeshChecker::assert_geometric_element<QElementGeometricBase, ELEMENT>(3);
65 unsigned nelem = 3 * nlayer;
69 ELEMENT* dummy_el_pt =
new ELEMENT;
72 unsigned n_p = dummy_el_pt->nnode_1d();
78 unsigned nnodes_total =
79 (n_p * n_p + (n_p - 1) * n_p + (n_p - 1) * (n_p - 1)) *
80 (1 + nlayer * (n_p - 1));
91 for (
unsigned ielem = 0; ielem < nelem; ielem++)
97 for (
unsigned i2 = 0; i2 < n_p; i2++)
100 for (
unsigned i1 = 0; i1 < n_p; i1++)
103 for (
unsigned i0 = 0; i0 < n_p; i0++)
106 unsigned jnod_local = i0 + i1 * n_p + i2 * n_p * n_p;
110 jnod_local, time_stepper_pt);
113 s[0] = -1.0 + 2.0 * double(i0) / double(n_p - 1);
114 s[1] = -1.0 + 2.0 * double(i1) / double(n_p - 1);
115 s[2] = -1.0 + 2.0 * double(i2) / double(n_p - 1);
127 unsigned node_count = 0;
130 double node_kill_tol = 1.0e-12;
136 for (
unsigned ielem = 0; ielem < nelem; ielem++)
139 unsigned ilayer = unsigned(ielem / 3);
150 for (
unsigned i2 = 0; i2 < n_p; i2++)
153 for (
unsigned i1 = 0; i1 < n_p; i1++)
156 for (
unsigned i0 = 0; i0 < n_p; i0++)
159 unsigned jnod_local = i0 + i1 * n_p + i2 * n_p * n_p;
166 if ((i2 == 0) && (ilayer > 0))
169 unsigned ielem_neigh = ielem - 3;
172 unsigned i0_neigh = i0;
173 unsigned i1_neigh = i1;
174 unsigned i2_neigh = n_p - 1;
175 unsigned jnod_local_neigh =
176 i0_neigh + i1_neigh * n_p + i2_neigh * n_p * n_p;
179 for (
unsigned i = 0;
i < 3;
i++)
181 double error = std::fabs(
186 if (error > node_kill_tol)
188 oomph_info <<
"Error in node killing for i " <<
i <<
" "
189 << error << std::endl;
212 if ((i2 == 0) && (ilayer == 0))
219 if ((i2 == n_p - 1) && (ilayer == nlayer - 1))
255 for (
unsigned i2 = 0; i2 < n_p; i2++)
258 for (
unsigned i1 = 0; i1 < n_p; i1++)
261 for (
unsigned i0 = 0; i0 < n_p; i0++)
264 unsigned jnod_local = i0 + i1 * n_p + i2 * n_p * n_p;
271 if ((i2 == 0) && (ilayer > 0))
274 unsigned ielem_neigh = ielem - 3;
277 unsigned i0_neigh = i0;
278 unsigned i1_neigh = i1;
279 unsigned i2_neigh = n_p - 1;
280 unsigned jnod_local_neigh =
281 i0_neigh + i1_neigh * n_p + i2_neigh * n_p * n_p;
285 for (
unsigned i = 0;
i < 3;
i++)
287 double error = std::fabs(
292 if (error > node_kill_tol)
294 oomph_info <<
"Error in node killing for i " <<
i <<
" "
295 << error << std::endl;
315 unsigned ielem_neigh = ielem - 1;
318 unsigned i0_neigh = n_p - 1;
319 unsigned i1_neigh = i1;
320 unsigned i2_neigh = i2;
321 unsigned jnod_local_neigh =
322 i0_neigh + i1_neigh * n_p + i2_neigh * n_p * n_p;
326 for (
unsigned i = 0;
i < 3;
i++)
328 double error = std::fabs(
333 if (error > node_kill_tol)
335 oomph_info <<
"Error in node killing for i " <<
i <<
" "
336 << error << std::endl;
360 if ((i2 == 0) && (ilayer == 0))
367 if ((i2 == n_p - 1) && (ilayer == nlayer - 1))
389 (double(ilayer) + double(i2) / double(n_p - 1)) *
393 zeta[1] =
Xi_lo[1] + double(i1) / double(n_p - 1) * 0.5 *
396 Node_pt[node_count]->set_coordinates_on_boundary(3, zeta);
414 for (
unsigned i2 = 0; i2 < n_p; i2++)
417 for (
unsigned i1 = 0; i1 < n_p; i1++)
420 for (
unsigned i0 = 0; i0 < n_p; i0++)
423 unsigned jnod_local = i0 + i1 * n_p + i2 * n_p * n_p;
430 if ((i2 == 0) && (ilayer > 0))
433 unsigned ielem_neigh = ielem - 3;
436 unsigned i0_neigh = i0;
437 unsigned i1_neigh = i1;
438 unsigned i2_neigh = n_p - 1;
439 unsigned jnod_local_neigh =
440 i0_neigh + i1_neigh * n_p + i2_neigh * n_p * n_p;
443 for (
unsigned i = 0;
i < 3;
i++)
445 double error = std::fabs(
450 if (error > node_kill_tol)
452 oomph_info <<
"Error in node killing for i " <<
i <<
" "
453 << error << std::endl;
474 unsigned ielem_neigh = ielem - 1;
477 unsigned i0_neigh = i1;
478 unsigned i1_neigh = n_p - 1;
479 unsigned i2_neigh = i2;
480 unsigned jnod_local_neigh =
481 i0_neigh + i1_neigh * n_p + i2_neigh * n_p * n_p;
484 for (
unsigned i = 0;
i < 3;
i++)
486 double error = std::fabs(
491 if (error > node_kill_tol)
493 oomph_info <<
"Error in node killing for i " <<
i <<
" "
494 << error << std::endl;
510 if ((i1 == 0) && (i0 != n_p - 1))
513 unsigned ielem_neigh = ielem - 2;
516 unsigned i0_neigh = i0;
517 unsigned i1_neigh = n_p - 1;
518 unsigned i2_neigh = i2;
519 unsigned jnod_local_neigh =
520 i0_neigh + i1_neigh * n_p + i2_neigh * n_p * n_p;
523 for (
unsigned i = 0;
i < 3;
i++)
525 double error = std::fabs(
530 if (error > node_kill_tol)
532 oomph_info <<
"Error in node killing for i " <<
i <<
" "
533 << error << std::endl;
556 if ((i2 == 0) && (ilayer == 0))
563 if ((i2 == n_p - 1) && (ilayer == nlayer - 1))
587 (double(ilayer) + double(i2) / double(n_p - 1)) *
591 zeta[1] =
Xi_hi[1] - double(i0) / double(n_p - 1) * 0.5 *
594 Node_pt[node_count]->set_coordinates_on_boundary(3, zeta);
612 std::ostringstream error_stream;
613 error_stream <<
"Error in killing nodes\n"
614 <<
"The most probable cause is that the domain is not\n"
615 <<
"compatible with the mesh.\n"
616 <<
"For the QuarterTubeMesh, the domain must be\n"
617 <<
"topologically consistent with a quarter tube with a\n"
618 <<
"non-curved centreline.\n";
620 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
658 template<
class ELEMENT>
660 ELEMENT>::setup_algebraic_node_update()
667 if (algebraic_element_pt == 0)
669 std::ostringstream error_message;
671 <<
"Element in AlgebraicRefineableQuarterTubeMesh must be\n ";
672 error_message <<
"derived from AlgebraicElementBase\n";
673 error_message <<
"but it is of type: "
675 std::string function_name =
"AlgebraicRefineableQuarterTubeMesh::";
676 function_name +=
"setup_algebraic_node_update()";
678 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
687 unsigned nnodes_2d = nnodes_1d * nnodes_1d;
691 unsigned tl_node = nnodes_2d - nnodes_1d;
692 unsigned br_node = nnodes_1d - 1;
708 Lambda_x = Centre_box_size * x_c_element / x_wall;
709 Lambda_y = Centre_box_size * y_c_element / y_wall;
715 for (
unsigned e = 0;
e < nelements;
e++)
721 unsigned region_id =
e % 3;
725 unsigned nstart = nnodes_2d;
732 for (
unsigned n = nstart; n < nnodes_3d; n++)
749 this->Wall_pt->locate_zeta(xi, obj_br_pt, s_br);
756 this->Wall_pt->locate_zeta(xi, obj_tl_pt, s_tl);
770 geom_object_pt[0] = obj_br_pt;
773 geom_object_pt[1] = obj_tl_pt;
779 ref_value[0] = x / x_c_element;
782 ref_value[1] = y / y_c_element;
793 ref_value[3] = s_br[0];
794 ref_value[4] = s_br[1];
798 ref_value[5] = s_tl[0];
799 ref_value[6] = s_tl[1];
803 ->add_node_update_info(Central_region,
811 else if (region_id == 1)
814 double fract = 1.0 / double(nnodes_1d - 1);
817 double rho_0 = fract * double(n % nnodes_1d);
820 double rho_1 = fract * double((n / nnodes_1d) % nnodes_1d);
832 this->Wall_pt->locate_zeta(xi, obj_wall_pt, s_wall);
838 geom_object_pt[0] = obj_br_pt;
841 geom_object_pt[1] = obj_tl_pt;
844 geom_object_pt[2] = obj_wall_pt;
850 ref_value[0] = rho_0;
853 ref_value[1] = rho_1;
860 ref_value[3] = s_br[0];
861 ref_value[4] = s_br[1];
865 ref_value[5] = s_tl[0];
866 ref_value[6] = s_tl[1];
870 ref_value[7] = s_wall[0];
871 ref_value[8] = s_wall[1];
875 ->add_node_update_info(Lower_right_region,
883 else if (region_id == 2)
886 double fract = 1.0 / double(nnodes_1d - 1);
889 double rho_0 = fract * double(n % nnodes_1d);
892 double rho_1 = fract * double((n / nnodes_1d) % nnodes_1d);
904 this->Wall_pt->locate_zeta(xi, obj_wall_pt, s_wall);
910 geom_object_pt[0] = obj_br_pt;
913 geom_object_pt[1] = obj_tl_pt;
916 geom_object_pt[2] = obj_wall_pt;
922 ref_value[0] = rho_0;
925 ref_value[1] = rho_1;
932 ref_value[3] = s_br[0];
933 ref_value[4] = s_br[1];
937 ref_value[5] = s_tl[0];
938 ref_value[6] = s_tl[1];
942 ref_value[7] = s_wall[0];
943 ref_value[8] = s_wall[1];
947 ->add_node_update_info(Upper_left_region,
960 template<
class ELEMENT>
981 "Trying to update the nodal position at a time level\n";
982 error_message +=
"beyond the number of previous values in the nodes'\n";
983 error_message +=
"position timestepper. This seems highly suspect!\n";
984 error_message +=
"If you're sure the code behaves correctly\n";
985 error_message +=
"in your application, remove this warning \n";
986 error_message +=
"or recompile with PARNOID switched off.\n";
988 std::string function_name =
"AlgebraicRefineableQuarterTubeMesh::";
989 function_name +=
"node_update_central_region()",
991 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1004 double rho_x = ref_value[0];
1007 double rho_y = ref_value[1];
1016 s_br[0] = ref_value[3];
1017 s_br[1] = ref_value[4];
1020 unsigned n_dim = obj_br_pt->
ndim();
1031 s_tl[0] = ref_value[5];
1032 s_tl[1] = ref_value[6];
1039 node_pt->
x(
t, 0) = r_br[0] * Lambda_x * rho_x;
1040 node_pt->
x(
t, 1) = r_tl[1] * Lambda_y * rho_y;
1041 node_pt->
x(
t, 2) = (r_br[2] + r_tl[2]) * 0.5;
1049 template<
class ELEMENT>
1051 ELEMENT>::node_update_lower_right_region(
const unsigned&
t,
1071 "Trying to update the nodal position at a time level";
1072 error_message +=
"beyond the number of previous values in the nodes'";
1073 error_message +=
"position timestepper. This seems highly suspect!";
1074 error_message +=
"If you're sure the code behaves correctly";
1075 error_message +=
"in your application, remove this warning ";
1076 error_message +=
"or recompile with PARNOID switched off.";
1078 std::string function_name =
"AlgebraicRefineableQuarterTubeSectorMesh::";
1079 function_name +=
"node_update_lower_right_region()",
1081 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1094 double rho_0 = ref_value[0];
1097 rho_0 = this->Domain_pt->s_squashed(rho_0);
1100 double rho_1 = ref_value[1];
1109 s_br[0] = ref_value[3];
1110 s_br[1] = ref_value[4];
1113 unsigned n_dim = obj_br_pt->
ndim();
1126 s_tl[0] = ref_value[5];
1127 s_tl[1] = ref_value[6];
1139 s_wall[0] = ref_value[7];
1140 s_wall[1] = ref_value[8];
1143 obj_wall_pt->
position(
t, s_wall, r_wall);
1147 r_corner[0] = Lambda_x * r_br[0];
1148 r_corner[1] = Lambda_y * r_tl[1];
1149 r_corner[2] = (r_br[2] + r_tl[2]) * 0.5;
1153 r_left[0] = r_corner[0];
1154 r_left[1] = rho_1 * r_corner[1];
1155 r_left[2] = r_corner[2];
1158 node_pt->
x(
t, 0) = r_left[0] + rho_0 * (r_wall[0] - r_left[0]);
1159 node_pt->
x(
t, 1) = r_left[1] + rho_0 * (r_wall[1] - r_left[1]);
1160 node_pt->
x(
t, 2) = r_left[2] + rho_0 * (r_wall[2] - r_left[2]);
1166 template<
class ELEMENT>
1168 ELEMENT>::node_update_upper_left_region(
const unsigned&
t,
1188 "Trying to update the nodal position at a time level";
1189 error_message +=
"beyond the number of previous values in the nodes'";
1190 error_message +=
"position timestepper. This seems highly suspect!";
1191 error_message +=
"If you're sure the code behaves correctly";
1192 error_message +=
"in your application, remove this warning ";
1193 error_message +=
"or recompile with PARNOID switched off.";
1195 std::string function_name =
"AlgebraicRefineableQuarterTubeMesh::";
1196 function_name +=
"node_update_upper_left_region()";
1199 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1212 double rho_0 = ref_value[0];
1215 double rho_1 = ref_value[1];
1218 rho_1 = this->Domain_pt->s_squashed(rho_1);
1226 unsigned n_dim = obj_br_pt->
ndim();
1230 s_br[0] = ref_value[3];
1231 s_br[1] = ref_value[4];
1244 s_tl[0] = ref_value[5];
1245 s_tl[1] = ref_value[6];
1257 s_wall[0] = ref_value[7];
1258 s_wall[1] = ref_value[8];
1261 obj_wall_pt->
position(
t, s_wall, r_wall);
1265 r_corner[0] = Lambda_x * r_br[0];
1266 r_corner[1] = Lambda_y * r_tl[1];
1267 r_corner[2] = (r_br[2] + r_tl[2]) * 0.5;
1271 r_top[0] = rho_0 * r_corner[0];
1272 r_top[1] = r_corner[1];
1273 r_top[2] = r_corner[2];
1276 node_pt->
x(
t, 0) = r_top[0] + rho_1 * (r_wall[0] - r_top[0]);
1277 node_pt->
x(
t, 1) = r_top[1] + rho_1 * (r_wall[1] - r_top[1]);
1278 node_pt->
x(
t, 2) = r_top[2] + rho_1 * (r_wall[2] - r_top[2]);
1286 template<
class ELEMENT>
1313 double z = ref_value[2];
1326 this->Wall_pt->locate_zeta(xi, obj_br_pt, s_br);
1329 geom_object_pt[0] = obj_br_pt;
1332 ref_value[3] = s_br[0];
1333 ref_value[4] = s_br[1];
1345 this->Wall_pt->locate_zeta(xi, obj_tl_pt, s_tl);
1348 geom_object_pt[1] = obj_tl_pt;
1351 ref_value[5] = s_tl[0];
1352 ref_value[6] = s_tl[1];
1354 if (region_id != Central_region)
1360 if (region_id == Lower_right_region)
1363 double rho_1 = ref_value[1];
1366 xi[1] = xi_lo + rho_1 * fract_mid * (xi_hi - xi_lo);
1371 double rho_0 = ref_value[0];
1374 xi[1] = xi_hi - rho_0 * (1.0 - fract_mid) * (xi_hi - xi_lo);
1381 this->Wall_pt->locate_zeta(xi, obj_wall_pt, s_wall);
1384 geom_object_pt[2] = obj_wall_pt;
1387 ref_value[7] = s_wall[0];
1388 ref_value[8] = s_wall[1];
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
GeomObject * geom_object_pt(const unsigned &i)
Return pointer to i-th geometric object involved in default (usually first) update function.
void kill_node_update_info(const int &id=0)
Erase algebraic node update information for id-th node update function. Id defaults to 0.
Vector< GeomObject * > & vector_geom_object_pt(const int &id)
Return vector of geometric objects involved in id-th update function.
void add_node_update_info(const int &id, AlgebraicMesh *mesh_pt, const Vector< GeomObject * > &geom_object_pt, const Vector< double > &ref_value, const bool &called_from_constructor=false)
Add algebraic update information for node: What's the ID of the mesh update function (typically used ...
Vector< double > & vector_ref_value()
Return vector of reference values involved in default (usually first) update function.
AlgebraicMesh version of RefineableQuarterTubeMesh.
void node_update_central_region(const unsigned &t, AlgebraicNode *&node_pt)
Algebraic update function for a node that is located in the central region.
void setup_boundary_element_info()
Setup lookup schemes which establish whic elements are located next to mesh's boundaries (wrapper to ...
MacroElement * macro_element_pt(const unsigned &i)
Access to i-th macro element.
A general Finite Element class.
virtual Node * construct_node(const unsigned &n)
Construct the local node n and return a pointer to the newly created node object.
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
unsigned nnode() const
Return the number of nodes.
virtual unsigned nnode_1d() const
Return the number of nodes along one edge of the element Default is to return zero — must be overload...
/////////////////////////////////////////////////////////////////////
unsigned ndim() const
Access function to # of Eulerian coordinates.
virtual void position(const Vector< double > &zeta, Vector< double > &r) const =0
Parametrised position on object at current time: r(zeta).
void macro_map(const Vector< double > &s, Vector< double > &r)
The mapping from local to global coordinates at the current time : r(s)
void add_boundary_node(const unsigned &b, Node *const &node_pt)
Add a (pointer to) a node to the b-th boundary.
Vector< Node * > Node_pt
Vector of pointers to nodes.
std::vector< bool > Boundary_coordinate_exists
Vector of boolean data that indicates whether the boundary coordinates have been set for the boundary...
FiniteElement * finite_element_pt(const unsigned &e) const
Upcast (downcast?) to FiniteElement (needed to access FiniteElement member functions).
void set_nboundary(const unsigned &nbound)
Set the number of boundaries in the mesh.
void convert_to_boundary_node(Node *&node_pt, const Vector< FiniteElement * > &finite_element_pt)
A function that upgrades an ordinary node to a boundary node We shouldn't ever really use this,...
const Vector< GeneralisedElement * > & element_pt() const
Return reference to the Vector of elements.
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Vector< GeneralisedElement * > Element_pt
Vector of pointers to generalised elements.
unsigned long nelement() const
Return number of elements in the mesh.
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.
TimeStepper *& position_time_stepper_pt()
Return a pointer to the position timestepper.
An OomphLibError object which should be thrown when an run-time error is encountered....
Quarter tube as domain. Domain is bounded by curved boundary which is represented by a GeomObject....
3D quarter tube mesh class. The domain is specified by the GeomObject that identifies boundary 3....
QuarterTubeDomain * Domain_pt
Pointer to domain.
Vector< double > Xi_lo
Lower limits for the coordinates along the wall.
QuarterTubeMesh(GeomObject *wall_pt, const Vector< double > &xi_lo, const double &fract_mid, const Vector< double > &xi_hi, const unsigned &nlayer, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Pass pointer to geometric object that specifies the wall, start and end coordinates on t...
Vector< double > Xi_hi
Upper limits for the coordinates along the wall.
GeomObject *& wall_pt()
Access function to GeomObject representing wall.
////////////////////////////////////////////////////////////////////// //////////////////////////////...
virtual unsigned nprev_values() const =0
Number of previous values available: 0 for static, 1 for BDF<1>,...
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...