37 #include "navier_stokes.h"
38 #include "fluid_interface.h"
39 #include "constitutive.h"
43 #include "meshes/two_layer_spine_mesh.h"
44 #include "meshes/rectangular_quadmesh.h"
49 using namespace oomph;
62 Vector<double> &normal)
73 template<
class ELEMENT>
83 CapProblem(
const unsigned &Nx,
const unsigned &Nh1,
87 void parameter_study();
96 Mesh* Surface_mesh_pt;
122 Mesh* Volume_constraint_mesh_pt;
128 Data* Traded_pressure_data_pt;
137 template<
class ELEMENT>
139 (
const unsigned &Nx,
const unsigned &Nh1,
const unsigned &Nh2) :
142 Angle(0.5*MathematicalConstants::Pi)
149 Bulk_mesh_pt =
new TwoLayerSpineMesh<SpineElement<ELEMENT> >
150 (Nx,Nh1,Nh2,0.5,1.0,1.0);
155 unsigned n_interface_lower =
Bulk_mesh_pt->ninterface_lower();
156 for(
unsigned i=0;i<n_interface_lower;i++)
159 FiniteElement *interface_element_pt =
new
160 SpineLineFluidInterfaceElement<SpineElement<ELEMENT> >(
162 Bulk_mesh_pt->interface_lower_face_index_at_boundary(i));
164 this->Surface_mesh_pt->add_element_pt(interface_element_pt);
171 FiniteElement* point_element_pt =
172 dynamic_cast<SpineLineFluidInterfaceElement<
173 SpineElement<ELEMENT>
>*>(
Surface_mesh_pt->element_pt(n_interface_lower-1))
174 ->make_bounding_element(1);
184 Bulk_mesh_pt->upper_layer_element_pt(0))->hijack_internal_value(0,0);
190 for(
unsigned e=0;e<n_interface;e++)
193 SpineLineFluidInterfaceElement<SpineElement<ELEMENT> >*el_pt=
194 dynamic_cast<SpineLineFluidInterfaceElement<
195 SpineElement<ELEMENT>
>*>
198 el_pt->ca_pt() = &
Ca;
206 for (
unsigned b=0;b<6;b++)
209 unsigned n_boundary_node =
Bulk_mesh_pt->nboundary_node(b);
211 for(
unsigned n=0;n<n_boundary_node;n++)
214 if ((b!=4) && (b!=5))
221 dynamic_cast<FluidInterfaceBoundingElement*
>(
224 dynamic_cast<FluidInterfaceBoundingElement*
>(
227 dynamic_cast<FluidInterfaceBoundingElement*
>(
233 dynamic_cast<ELEMENT*
>(
Bulk_mesh_pt->lower_layer_element_pt(0))
234 ->fix_pressure(0,0.0);
243 this->build_global_mesh();
246 cout <<
"Number of unknowns: " << assign_eqn_numbers() << std::endl;
255 template<
class ELEMENT>
259 Volume_constraint_mesh_pt =
new Mesh;
260 VolumeConstraintElement* vol_constraint_element =
261 new VolumeConstraintElement(&Volume,Traded_pressure_data_pt,0);
262 Volume_constraint_mesh_pt->add_element_pt(vol_constraint_element);
265 unsigned lower_boundaries[3]={0,1,5};
266 for(
unsigned i=0;i<3;i++)
269 unsigned b = lower_boundaries[i];
272 unsigned n_element = Bulk_mesh_pt->nboundary_element(b);
275 for(
unsigned e=0;e<n_element;e++)
279 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
280 Bulk_mesh_pt->boundary_element_pt(b,e));
283 int face_index = Bulk_mesh_pt->face_index_at_boundary(b,e);
286 SpineLineVolumeConstraintBoundingElement<ELEMENT>* el_pt =
287 new SpineLineVolumeConstraintBoundingElement<ELEMENT>(
288 bulk_elem_pt,face_index);
291 el_pt->set_volume_constraint_element(vol_constraint_element);
294 Volume_constraint_mesh_pt->add_element_pt(el_pt);
301 unsigned n_element = Bulk_mesh_pt->ninterface_lower();
304 for(
unsigned e=0;e<n_element;e++)
308 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
309 Bulk_mesh_pt->interface_lower_boundary_element_pt(e));
312 int face_index = Bulk_mesh_pt->interface_lower_face_index_at_boundary(e);
315 SpineLineVolumeConstraintBoundingElement<ELEMENT>* el_pt =
316 new SpineLineVolumeConstraintBoundingElement<ELEMENT>(
317 bulk_elem_pt,face_index);
320 el_pt->set_volume_constraint_element(vol_constraint_element);
323 Volume_constraint_mesh_pt->add_element_pt(el_pt);
334 template<
class ELEMENT>
340 doc_info.set_directory(
"RESLT");
346 sprintf(filename,
"%s/trace.dat",doc_info.directory().c_str());
347 Trace_file.open(filename);
348 Trace_file <<
"VARIABLES=\"<greek>a</greek><sub>prescribed</sub>\",";
349 Trace_file <<
"\"h<sub>left</sub>\",\"h<sub>right</sub>\",";
350 Trace_file <<
"\"<greek>a</greek><sub>left</sub>\",";
351 Trace_file <<
"\"<greek>a</greek><sub>right</sub>\",";
352 Trace_file <<
"\"p<sub>upper</sub>\",";
353 Trace_file <<
"\"p<sub>lower</sub>\",";
354 Trace_file <<
"\"p<sub>exact</sub>\"";
355 Trace_file << std::endl;
358 doc_solution(doc_info);
364 for(
unsigned i=0;i<6;i++)
367 steady_newton_solve();
370 doc_solution(doc_info);
376 Angle -= 5.0*MathematicalConstants::Pi/180.0;
387 template<
class ELEMENT>
399 sprintf(filename,
"%s/soln%i.dat",doc_info.directory().c_str(),
401 some_file.open(filename);
402 Bulk_mesh_pt->output(some_file,npts);
403 Surface_mesh_pt->output(some_file,npts);
411 unsigned nspine=Bulk_mesh_pt->nspine();
414 Trace_file << Angle*180.0/MathematicalConstants::Pi;
415 Trace_file <<
" " << Bulk_mesh_pt->spine_pt(0)->height();
416 Trace_file <<
" " << Bulk_mesh_pt->spine_pt(nspine-1)->height();
418 <<
dynamic_cast<ELEMENT*
>(
419 Bulk_mesh_pt->upper_layer_element_pt(0))->p_nst(0);
421 <<
dynamic_cast<ELEMENT*
>(
422 Bulk_mesh_pt->lower_layer_element_pt(0))->p_nst(0);
423 Trace_file <<
" " << 2.0*cos(Angle)/Ca;
424 Trace_file << std::endl;
451 template <
class ELEMENT>
453 public ElasticRectangularQuadMesh<ELEMENT>
469 const bool& periodic_in_x=
false,
470 TimeStepper* time_stepper_pt=
471 &Mesh::Default_TimeStepper)
473 RectangularQuadMesh<ELEMENT>(nx,ny1+ny2,lx,h1+h2,
474 periodic_in_x,time_stepper_pt),
475 ElasticRectangularQuadMesh<ELEMENT>(nx,ny1+ny2,lx,h1+h2,
476 periodic_in_x,time_stepper_pt)
480 unsigned long n_lower = nx*ny1;
481 unsigned long n_upper = nx*ny2;
484 for(
unsigned e=0;e<n_lower;e++)
490 for(
unsigned e=0;e<n_upper;e++)
500 unsigned count_lower=nx*(ny1-1);
501 unsigned count_upper= count_lower + nx;
502 for(
unsigned e=0;e<nx;e++)
505 this->finite_element_pt(count_lower); ++count_lower;
507 this->finite_element_pt(count_upper); ++count_upper;
513 this->set_nboundary(7);
517 Vector<double> b_coord;
520 const double y_interface = h1 - this->Ymin;
523 unsigned n_boundary_node = this->nboundary_node(3);
526 for(
unsigned n=0;n<n_boundary_node;n++)
529 Node*
const nod_pt = this->boundary_node_pt(3,n);
531 if(this->boundary_coordinate_exists(3))
533 b_coord.resize(nod_pt->ncoordinates_on_boundary(3));
534 nod_pt->get_coordinates_on_boundary(3,b_coord);
537 this->Boundary_coordinate_exists[4]=
true;
538 this->Boundary_coordinate_exists[5]=
true;
542 nod_pt->remove_from_boundary(3);
545 double y = nod_pt->x(1);
549 this->add_boundary_node(4,nod_pt);
551 if(this->Boundary_coordinate_exists[4])
553 nod_pt->set_coordinates_on_boundary(4,b_coord);
559 this->add_boundary_node(5,nod_pt);
561 if(this->Boundary_coordinate_exists[5])
563 nod_pt->set_coordinates_on_boundary(5,b_coord);
569 this->Boundary_node_pt[3].clear();
572 n_boundary_node = this->nboundary_node(2);
575 for(
unsigned n=0;n<n_boundary_node;n++)
578 Node*
const nod_pt = this->boundary_node_pt(2,n);
580 if(this->boundary_coordinate_exists(2))
582 b_coord.resize(nod_pt->ncoordinates_on_boundary(2));
583 nod_pt->get_coordinates_on_boundary(2,b_coord);
584 this->Boundary_coordinate_exists[3]=
true;
588 nod_pt->remove_from_boundary(2);
590 this->add_boundary_node(3,nod_pt);
591 if(this->Boundary_coordinate_exists[3])
593 nod_pt->set_coordinates_on_boundary(3,b_coord);
598 this->Boundary_node_pt[2].clear();
601 std::list<Node*> nodes_to_be_removed;
604 n_boundary_node = this->nboundary_node(1);
606 for(
unsigned n=0;n<n_boundary_node;n++)
609 Node*
const nod_pt = this->boundary_node_pt(1,n);
612 double y = nod_pt->x(1);
617 if(this->boundary_coordinate_exists(1))
619 b_coord.resize(nod_pt->ncoordinates_on_boundary(1));
620 nod_pt->get_coordinates_on_boundary(1,b_coord);
621 this->Boundary_coordinate_exists[2]=
true;
627 nodes_to_be_removed.push_back(nod_pt);
630 this->add_boundary_node(2,nod_pt);
632 if(this->Boundary_coordinate_exists[2])
634 nod_pt->set_coordinates_on_boundary(2,b_coord);
641 for(std::list<Node*>::iterator it=nodes_to_be_removed.begin();
642 it!=nodes_to_be_removed.end();++it)
644 this->remove_boundary_node(1,*it);
646 nodes_to_be_removed.clear();
652 unsigned n_p =
dynamic_cast<ELEMENT*
>
653 (this->finite_element_pt(0))->nnode_1d();
658 this->Boundary_coordinate_exists[6];
661 for(
unsigned e=0;e<nx;e++)
666 FiniteElement* el_pt = this->finite_element_pt(nx*ny1+e);
668 for(
unsigned n=n_start;n<n_p;n++)
670 Node* nod_pt = el_pt->node_pt(n);
671 this->convert_to_boundary_node(nod_pt);
672 this->add_boundary_node(6,nod_pt);
673 b_coord[0] = nod_pt->x(0);
674 nod_pt->set_coordinates_on_boundary(6,b_coord);
679 this->setup_boundary_element_info();
748 template<
class ELEMENT>
756 const unsigned &Nx,
const unsigned &Nh1,
const unsigned &Nh2);
827 template<
class ELEMENT>
829 const unsigned &Nx,
const unsigned &Nh1,
const unsigned &Nh2) :
833 Angle(0.5*MathematicalConstants::Pi)
848 Bulk_mesh_pt->upper_layer_element_pt(0))->hijack_internal_value(0,0);
856 for(
unsigned e=0;e<n_bulk;e++)
869 for (
unsigned b=0;b<6;b++)
872 unsigned n_boundary_node =
Bulk_mesh_pt->nboundary_node(b);
874 for(
unsigned n=0;n<n_boundary_node;n++)
885 for(
unsigned b=0;b<6;b++)
888 unsigned n_boundary_node =
Bulk_mesh_pt->nboundary_node(b);
890 for(
unsigned n=0;n<n_boundary_node;n++)
895 static_cast<SolidNode*
>(
Bulk_mesh_pt->boundary_node_pt(b,n))
899 if((b==1) || (b==2) || (b==4) || (b==5))
901 static_cast<SolidNode*
>(
Bulk_mesh_pt->boundary_node_pt(b,n))
910 for(
unsigned n=0;n<n_node;n++)
912 static_cast<SolidNode*
>(
Bulk_mesh_pt->node_pt(n))->pin_position(0);
918 dynamic_cast<ELEMENT*
>(
Bulk_mesh_pt->element_pt(0))->fix_pressure(0,0.0);
937 this->build_global_mesh();
940 cout <<
"Number of unknowns: " << assign_eqn_numbers() << std::endl;
949 template<
class ELEMENT>
953 delete Free_surface_bounding_mesh_pt->element_pt(0);
954 Free_surface_bounding_mesh_pt->flush_element_and_node_storage();
955 delete Free_surface_bounding_mesh_pt;
957 delete Volume_constraint_mesh_pt;
959 unsigned n_element = Volume_computation_mesh_pt->nelement();
960 for(
unsigned e=0;e<n_element;e++)
961 {
delete Volume_computation_mesh_pt->element_pt(e);}
963 Volume_computation_mesh_pt->flush_element_and_node_storage();
965 delete Volume_computation_mesh_pt;
967 n_element = Free_surface_mesh_pt->nelement();
968 for(
unsigned e=0;e<n_element;e++)
969 {
delete Free_surface_mesh_pt->element_pt(e);}
971 Free_surface_mesh_pt->flush_element_and_node_storage();
973 delete Free_surface_mesh_pt;
976 delete Constitutive_law_pt;
985 template<
class ELEMENT>
989 Free_surface_mesh_pt =
new Mesh;
992 unsigned n_element = Bulk_mesh_pt->ninterface_lower();
994 for(
unsigned e=0;e<n_element;e++)
997 ElasticLineFluidInterfaceElement<ELEMENT>* el_pt =
998 new ElasticLineFluidInterfaceElement<ELEMENT>(
999 Bulk_mesh_pt->interface_lower_boundary_element_pt(e),
1000 Bulk_mesh_pt->interface_lower_face_index_at_boundary(e));
1003 Free_surface_mesh_pt->add_element_pt(el_pt);
1006 el_pt->ca_pt() = &Ca;
1015 template<
class ELEMENT>
1019 Volume_constraint_mesh_pt =
new Mesh;
1020 VolumeConstraintElement* vol_constraint_element =
1021 new VolumeConstraintElement(&Volume,Traded_pressure_data_pt,0);
1022 Volume_constraint_mesh_pt->add_element_pt(vol_constraint_element);
1025 Volume_computation_mesh_pt =
new Mesh;
1028 unsigned lower_boundaries[3]={0,1,5};
1030 for(
unsigned i=0;i<3;i++)
1033 unsigned b= lower_boundaries[i];
1035 unsigned n_element = Bulk_mesh_pt->nboundary_element(b);
1038 for(
unsigned e=0;e<n_element;e++)
1042 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
1043 Bulk_mesh_pt->boundary_element_pt(b,e));
1046 int face_index = Bulk_mesh_pt->face_index_at_boundary(b,e);
1049 ElasticLineVolumeConstraintBoundingElement<ELEMENT>* el_pt =
1050 new ElasticLineVolumeConstraintBoundingElement<ELEMENT>(
1051 bulk_elem_pt,face_index);
1054 el_pt->set_volume_constraint_element(vol_constraint_element);
1057 Volume_computation_mesh_pt->add_element_pt(el_pt);
1065 unsigned n_element = Bulk_mesh_pt->ninterface_lower();
1068 for(
unsigned e=0;e<n_element;e++)
1072 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
1073 Bulk_mesh_pt->interface_lower_boundary_element_pt(e));
1076 int face_index = Bulk_mesh_pt->interface_lower_face_index_at_boundary(e);
1079 ElasticLineVolumeConstraintBoundingElement<ELEMENT>* el_pt =
1080 new ElasticLineVolumeConstraintBoundingElement<ELEMENT>(
1081 bulk_elem_pt,face_index);
1084 el_pt->set_volume_constraint_element(vol_constraint_element);
1087 Volume_constraint_mesh_pt->add_element_pt(el_pt);
1097 template<
class ELEMENT>
1100 Free_surface_bounding_mesh_pt =
new Mesh;
1104 unsigned n_free_surface = Free_surface_mesh_pt->nelement();
1108 FluidInterfaceBoundingElement* el_pt =
1109 dynamic_cast<ElasticLineFluidInterfaceElement<ELEMENT>*
>
1110 (Free_surface_mesh_pt->element_pt(n_free_surface-1))->
1111 make_bounding_element(1);
1114 el_pt->set_contact_angle(&Angle);
1117 el_pt->ca_pt() = &Ca;
1120 el_pt->wall_unit_normal_fct_pt()
1124 Free_surface_bounding_mesh_pt->add_element_pt(el_pt);
1134 template<
class ELEMENT>
1139 doc_info.set_directory(dir_name);
1140 doc_info.number()=0;
1144 sprintf(filename,
"%s/trace.dat",doc_info.directory().c_str());
1145 Trace_file.open(filename);
1146 Trace_file <<
"VARIABLES=\"<greek>a</greek><sub>prescribed</sub>\",";
1147 Trace_file <<
"\"h<sub>left</sub>\",\"h<sub>right</sub>\",";
1148 Trace_file <<
"\"p<sub>fluid</sub>-p<sub>ext</sub>\",";
1149 Trace_file <<
"\"<greek>D</greek>p<sub>exact</sub>\"";
1150 Trace_file << std::endl;
1153 doc_solution(doc_info);
1156 doc_info.number()++;
1159 for(
unsigned i=0;i<6;i++)
1162 steady_newton_solve();
1165 doc_solution(doc_info);
1168 doc_info.number()++;
1171 Angle -= 5.0*MathematicalConstants::Pi/180.0;
1182 template<
class ELEMENT>
1193 sprintf(filename,
"%s/soln%i.dat",doc_info.directory().c_str(),
1195 some_file.open(filename);
1196 Bulk_mesh_pt->output(some_file,npts);
1201 unsigned ninterface=Free_surface_mesh_pt->nelement();
1203 unsigned np = Free_surface_mesh_pt->finite_element_pt(ninterface-1)->nnode();
1208 Trace_file << Angle*180.0/MathematicalConstants::Pi;
1209 Trace_file <<
" " << Free_surface_mesh_pt->finite_element_pt(0)
1212 << Free_surface_mesh_pt->finite_element_pt(ninterface-1)
1213 ->node_pt(np-1)->x(1);
1215 <<
dynamic_cast<ELEMENT*
>(
1216 Bulk_mesh_pt->upper_layer_element_pt(0))->p_nst(0);
1218 <<
dynamic_cast<ELEMENT*
>(
1219 Bulk_mesh_pt->lower_layer_element_pt(0))->p_nst(0);
1220 Trace_file <<
" " << 2.0*cos(Angle)/Ca;
1221 Trace_file << std::endl;
1242 PseudoSolidNodeUpdateElement<QCrouzeixRaviartElement<2>,
1243 QPVDElementWithPressure<2> > > >
1247 problem.parameter_study(
"RESLT_elastic");
A Problem class that solves the Navier–Stokes equations + free surface in a 2D geometry using a spine...
Mesh * Volume_constraint_mesh_pt
The volume constraint mesh.
Data * Traded_pressure_data_pt
Data that is traded for the volume constraint.
Mesh * Surface_mesh_pt
The mesh for the interface elements.
void finish_problem_setup()
Finish full specification of the elements.
void parameter_study()
Peform a parameter study: Solve problem for a range of contact angles.
SingleLayerSpineMesh< SpineElement< ELEMENT > > * Bulk_mesh_pt
The bulk mesh of fluid elements.
double Angle
The contact angle.
void doc_solution(DocInfo &doc_info)
Doc the solution.
TwoLayerSpineMesh< SpineElement< ELEMENT > > * Bulk_mesh_pt
Pointer to the mesh.
void create_volume_constraint_elements()
Create the volume constraint elements.
CapProblem(const bool &hijack_internal)
Constructor: Pass boolean flag to indicate if the volume constraint is applied by hijacking an intern...
void actions_before_newton_convergence_check()
Update the spine mesh after every Newton step.
Mesh * Point_mesh_pt
The mesh for the element at the contact point.
double Ca
The Capillary number.
void parameter_study(const string &dir_name)
Perform a parameter study: Solve problem for a range of contact angles Pass name of output directory ...
Two layer mesh which employs a pseudo-solid node-update strategy. This class is essentially a wrapper...
int interface_upper_face_index_at_boundary(const unsigned &e)
Index of the face of the elements next to the interface in the upper region (always -2)
int interface_lower_face_index_at_boundary(const unsigned &e)
Index of the face of the elements next to the interface in the lower region (always 2)
unsigned long nlower() const
Number of elements in top layer.
FiniteElement *& lower_layer_element_pt(const unsigned long &i)
Access functions for pointers to elements in bottom layer.
Vector< FiniteElement * > Lower_layer_element_pt
Vector of pointers to element in the upper layer.
FiniteElement *& interface_upper_boundary_element_pt(const unsigned long &i)
Access functions for pointers to elements in upper layer.
unsigned long ninterface_upper() const
Number of elements in upper layer.
ElasticTwoLayerMesh(const unsigned &nx, const unsigned &ny1, const unsigned &ny2, const double &lx, const double &h1, const double &h2, const bool &periodic_in_x=false, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Pass number of elements in x-direction, number of elements in y-direction in bottom and ...
FiniteElement *& interface_lower_boundary_element_pt(const unsigned long &i)
Access functions for pointers to elements in bottom layer.
FiniteElement *& upper_layer_element_pt(const unsigned long &i)
Access functions for pointers to elements in upper layer.
Vector< FiniteElement * > Interface_lower_boundary_element_pt
Vector of pointers to the elements adjacent to the interface on the lower layer.
Vector< FiniteElement * > Upper_layer_element_pt
Vector of pointers to element in the lower layer.
unsigned long nupper() const
Number of elements in upper layer.
unsigned long ninterface_lower() const
Number of elements in top layer.
Vector< FiniteElement * > Interface_upper_boundary_element_pt
Vector of pointers to the element adjacent to the interface on the upper layer.
A class that solves the Navier–Stokes equations to compute the shape of a static interface in a recta...
void create_volume_constraint_elements()
Create the volume constraint elements.
Mesh * Volume_computation_mesh_pt
Storage for the elements that compute the enclosed volume.
ElasticTwoLayerMesh< ELEMENT > * Bulk_mesh_pt
Storage for the bulk mesh.
void doc_solution(DocInfo &doc_info)
Doc the solution.
double Volume
The prescribed volume of the fluid.
PseudoSolidCapProblem(const bool &hijack_internal)
Constructor: Boolean flag indicates if volume constraint is applied by hijacking internal or external...
double Angle
The contact angle.
Data * Traded_pressure_data_pt
Mesh * Volume_constraint_mesh_pt
Storage for the volume constraint.
Mesh * Bulk_mesh_pt
Storage for the bulk mesh.
ofstream Trace_file
Trace file.
void create_contact_angle_element()
Create the contact angle element.
ConstitutiveLaw * Constitutive_law_pt
Constitutive law used to determine the mesh deformation.
Mesh * Free_surface_bounding_mesh_pt
Storage for the element bounding the free surface.
void create_free_surface_elements()
Create the free surface elements.
Mesh * Free_surface_mesh_pt
Storage for the free surface mesh.
double Ca
The Capillary number.
void parameter_study(const string &dir_name)
Peform a parameter study: Solve problem for a range of contact angles Pass name of output directory a...
~PseudoSolidCapProblem()
Destructor: clean up memory allocated by the object.
double Pext
The external pressure.
Namespace for phyical parameters.
void wall_unit_normal_fct(const Vector< double > &x, Vector< double > &normal)
Function that specifies the wall unit normal.
double Nu
Pseudo-solid Poisson ratio.
Vector< double > Wall_normal
Direction of the wall normal vector.
int main()
Main driver: Build problem and initiate parameter study.