41 #include "navier_stokes.h" 42 #include "fluid_interface.h" 43 #include "constitutive.h" 47 #include "meshes/two_layer_spine_mesh.h" 48 #include "meshes/rectangular_quadmesh.h" 53 using namespace oomph;
66 Vector<double> &normal)
77 template<
class ELEMENT>
87 CapProblem(
const unsigned &Nx,
const unsigned &Nh1,
91 void parameter_study();
94 void finish_problem_setup();
100 Mesh* Surface_mesh_pt;
109 void create_volume_constraint_elements();
112 void doc_solution(DocInfo& doc_info);
126 Mesh* Volume_constraint_mesh_pt;
132 Data* Traded_pressure_data_pt;
141 template<
class ELEMENT>
143 (
const unsigned &Nx,
const unsigned &Nh1,
const unsigned &Nh2) :
146 Angle(0.5*MathematicalConstants::Pi)
153 Bulk_mesh_pt =
new TwoLayerSpineMesh<SpineElement<ELEMENT> >
154 (Nx,Nh1,Nh2,0.5,1.0,1.0);
156 Surface_mesh_pt =
new Mesh;
159 unsigned n_interface_lower = Bulk_mesh_pt->ninterface_lower();
160 for(
unsigned i=0;i<n_interface_lower;i++)
163 FiniteElement *interface_element_pt =
new 164 SpineLineFluidInterfaceElement<SpineElement<ELEMENT> >(
165 Bulk_mesh_pt->interface_lower_boundary_element_pt(i),
166 Bulk_mesh_pt->interface_lower_face_index_at_boundary(i));
168 this->Surface_mesh_pt->add_element_pt(interface_element_pt);
172 Point_mesh_pt =
new Mesh;
175 FiniteElement* point_element_pt =
176 dynamic_cast<SpineLineFluidInterfaceElement<
177 SpineElement<ELEMENT>
>*>(Surface_mesh_pt->element_pt(n_interface_lower-1))
178 ->make_bounding_element(1);
181 this->Point_mesh_pt->add_element_pt(point_element_pt);
187 Traded_pressure_data_pt =
dynamic_cast<ELEMENT*
>(
188 Bulk_mesh_pt->upper_layer_element_pt(0))->hijack_internal_value(0,0);
193 unsigned n_interface = Surface_mesh_pt->nelement();
194 for(
unsigned e=0;e<n_interface;e++)
197 SpineLineFluidInterfaceElement<SpineElement<ELEMENT> >*el_pt=
198 dynamic_cast<SpineLineFluidInterfaceElement<
199 SpineElement<ELEMENT>
>*>
200 (Surface_mesh_pt->element_pt(e));
202 el_pt->ca_pt() = &Ca;
210 for (
unsigned b=0;b<6;b++)
213 unsigned n_boundary_node = Bulk_mesh_pt->nboundary_node(b);
215 for(
unsigned n=0;n<n_boundary_node;n++)
217 Bulk_mesh_pt->boundary_node_pt(b,n)->pin(0);
218 if ((b!=4) && (b!=5))
220 Bulk_mesh_pt->boundary_node_pt(b,n)->pin(1);
225 dynamic_cast<FluidInterfaceBoundingElement*
>(
226 Point_mesh_pt->element_pt(0))->set_contact_angle(&Angle);
228 dynamic_cast<FluidInterfaceBoundingElement*
>(
229 Point_mesh_pt->element_pt(0))->ca_pt() = &Ca;
231 dynamic_cast<FluidInterfaceBoundingElement*
>(
232 Point_mesh_pt->element_pt(0))->wall_unit_normal_fct_pt() =
237 dynamic_cast<ELEMENT*
>(Bulk_mesh_pt->lower_layer_element_pt(0))
238 ->fix_pressure(0,0.0);
240 this->create_volume_constraint_elements();
242 this->add_sub_mesh(Bulk_mesh_pt);
243 this->add_sub_mesh(Surface_mesh_pt);
244 this->add_sub_mesh(Point_mesh_pt);
245 this->add_sub_mesh(Volume_constraint_mesh_pt);
247 this->build_global_mesh();
250 cout <<
"Number of unknowns: " << assign_eqn_numbers() << std::endl;
259 template<
class ELEMENT>
263 Volume_constraint_mesh_pt =
new Mesh;
264 VolumeConstraintElement* vol_constraint_element =
265 new VolumeConstraintElement(&Volume,Traded_pressure_data_pt,0);
266 Volume_constraint_mesh_pt->add_element_pt(vol_constraint_element);
269 unsigned lower_boundaries[3]={0,1,5};
270 for(
unsigned i=0;i<3;i++)
273 unsigned b = lower_boundaries[i];
276 unsigned n_element = Bulk_mesh_pt->nboundary_element(b);
279 for(
unsigned e=0;e<n_element;e++)
283 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
284 Bulk_mesh_pt->boundary_element_pt(b,e));
287 int face_index = Bulk_mesh_pt->face_index_at_boundary(b,e);
290 SpineLineVolumeConstraintBoundingElement<ELEMENT>* el_pt =
291 new SpineLineVolumeConstraintBoundingElement<ELEMENT>(
292 bulk_elem_pt,face_index);
295 el_pt->set_volume_constraint_element(vol_constraint_element);
298 Volume_constraint_mesh_pt->add_element_pt(el_pt);
305 unsigned n_element = Bulk_mesh_pt->ninterface_lower();
308 for(
unsigned e=0;e<n_element;e++)
312 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
313 Bulk_mesh_pt->interface_lower_boundary_element_pt(e));
316 int face_index = Bulk_mesh_pt->interface_lower_face_index_at_boundary(e);
319 SpineLineVolumeConstraintBoundingElement<ELEMENT>* el_pt =
320 new SpineLineVolumeConstraintBoundingElement<ELEMENT>(
321 bulk_elem_pt,face_index);
324 el_pt->set_volume_constraint_element(vol_constraint_element);
327 Volume_constraint_mesh_pt->add_element_pt(el_pt);
338 template<
class ELEMENT>
344 doc_info.set_directory(
"RESLT");
350 sprintf(filename,
"%s/trace.dat",doc_info.directory().c_str());
351 Trace_file.open(filename);
352 Trace_file <<
"VARIABLES=\"<greek>a</greek><sub>prescribed</sub>\",";
353 Trace_file <<
"\"h<sub>left</sub>\",\"h<sub>right</sub>\",";
354 Trace_file <<
"\"<greek>a</greek><sub>left</sub>\",";
355 Trace_file <<
"\"<greek>a</greek><sub>right</sub>\",";
356 Trace_file <<
"\"p<sub>upper</sub>\",";
357 Trace_file <<
"\"p<sub>lower</sub>\",";
358 Trace_file <<
"\"p<sub>exact</sub>\"";
359 Trace_file << std::endl;
362 doc_solution(doc_info);
368 for(
unsigned i=0;i<6;i++)
371 steady_newton_solve();
374 doc_solution(doc_info);
380 Angle -= 5.0*MathematicalConstants::Pi/180.0;
391 template<
class ELEMENT>
403 sprintf(filename,
"%s/soln%i.dat",doc_info.directory().c_str(),
405 some_file.open(filename);
406 Bulk_mesh_pt->output(some_file,npts);
407 Surface_mesh_pt->output(some_file,npts);
415 unsigned nspine=Bulk_mesh_pt->nspine();
418 Trace_file << Angle*180.0/MathematicalConstants::Pi;
419 Trace_file <<
" " << Bulk_mesh_pt->spine_pt(0)->height();
420 Trace_file <<
" " << Bulk_mesh_pt->spine_pt(nspine-1)->height();
422 <<
dynamic_cast<ELEMENT*
>(
423 Bulk_mesh_pt->upper_layer_element_pt(0))->p_nst(0);
425 <<
dynamic_cast<ELEMENT*
>(
426 Bulk_mesh_pt->lower_layer_element_pt(0))->p_nst(0);
427 Trace_file <<
" " << 2.0*cos(Angle)/Ca;
428 Trace_file << std::endl;
455 template <
class ELEMENT>
457 public ElasticRectangularQuadMesh<ELEMENT>
473 const bool& periodic_in_x=
false,
474 TimeStepper* time_stepper_pt=
475 &Mesh::Default_TimeStepper)
477 RectangularQuadMesh<ELEMENT>(nx,ny1+ny2,lx,h1+h2,
478 periodic_in_x,time_stepper_pt),
479 ElasticRectangularQuadMesh<ELEMENT>(nx,ny1+ny2,lx,h1+h2,
480 periodic_in_x,time_stepper_pt)
484 unsigned long n_lower = nx*ny1;
485 unsigned long n_upper = nx*ny2;
487 Lower_layer_element_pt.resize(n_lower);
488 for(
unsigned e=0;e<n_lower;e++)
490 Lower_layer_element_pt[e] = this->finite_element_pt(e);
493 Upper_layer_element_pt.resize(n_upper);
494 for(
unsigned e=0;e<n_upper;e++)
496 Upper_layer_element_pt[e] = this->finite_element_pt(n_lower + e);
501 Interface_lower_boundary_element_pt.resize(nx);
502 Interface_upper_boundary_element_pt.resize(nx);
504 unsigned count_lower=nx*(ny1-1);
505 unsigned count_upper= count_lower + nx;
506 for(
unsigned e=0;e<nx;e++)
508 Interface_lower_boundary_element_pt[e] =
509 this->finite_element_pt(count_lower); ++count_lower;
510 Interface_upper_boundary_element_pt[e] =
511 this->finite_element_pt(count_upper); ++count_upper;
517 this->set_nboundary(7);
521 Vector<double> b_coord;
524 const double y_interface = h1 - this->Ymin;
527 unsigned n_boundary_node = this->nboundary_node(3);
530 for(
unsigned n=0;n<n_boundary_node;n++)
533 Node*
const nod_pt = this->boundary_node_pt(3,n);
535 if(this->boundary_coordinate_exists(3))
537 b_coord.resize(nod_pt->ncoordinates_on_boundary(3));
538 nod_pt->get_coordinates_on_boundary(3,b_coord);
541 this->Boundary_coordinate_exists[4]=
true;
542 this->Boundary_coordinate_exists[5]=
true;
546 nod_pt->remove_from_boundary(3);
549 double y = nod_pt->x(1);
553 this->add_boundary_node(4,nod_pt);
555 if(this->Boundary_coordinate_exists[4])
557 nod_pt->set_coordinates_on_boundary(4,b_coord);
563 this->add_boundary_node(5,nod_pt);
565 if(this->Boundary_coordinate_exists[5])
567 nod_pt->set_coordinates_on_boundary(5,b_coord);
573 this->Boundary_node_pt[3].clear();
576 n_boundary_node = this->nboundary_node(2);
579 for(
unsigned n=0;n<n_boundary_node;n++)
582 Node*
const nod_pt = this->boundary_node_pt(2,n);
584 if(this->boundary_coordinate_exists(2))
586 b_coord.resize(nod_pt->ncoordinates_on_boundary(2));
587 nod_pt->get_coordinates_on_boundary(2,b_coord);
588 this->Boundary_coordinate_exists[3]=
true;
592 nod_pt->remove_from_boundary(2);
594 this->add_boundary_node(3,nod_pt);
595 if(this->Boundary_coordinate_exists[3])
597 nod_pt->set_coordinates_on_boundary(3,b_coord);
602 this->Boundary_node_pt[2].clear();
605 std::list<Node*> nodes_to_be_removed;
608 n_boundary_node = this->nboundary_node(1);
610 for(
unsigned n=0;n<n_boundary_node;n++)
613 Node*
const nod_pt = this->boundary_node_pt(1,n);
616 double y = nod_pt->x(1);
621 if(this->boundary_coordinate_exists(1))
623 b_coord.resize(nod_pt->ncoordinates_on_boundary(1));
624 nod_pt->get_coordinates_on_boundary(1,b_coord);
625 this->Boundary_coordinate_exists[2]=
true;
631 nodes_to_be_removed.push_back(nod_pt);
634 this->add_boundary_node(2,nod_pt);
636 if(this->Boundary_coordinate_exists[2])
638 nod_pt->set_coordinates_on_boundary(2,b_coord);
645 for(std::list<Node*>::iterator it=nodes_to_be_removed.begin();
646 it!=nodes_to_be_removed.end();++it)
648 this->remove_boundary_node(1,*it);
650 nodes_to_be_removed.clear();
656 unsigned n_p =
dynamic_cast<ELEMENT*
> 657 (this->finite_element_pt(0))->nnode_1d();
662 this->Boundary_coordinate_exists[6];
665 for(
unsigned e=0;e<nx;e++)
670 FiniteElement* el_pt = this->finite_element_pt(nx*ny1+e);
672 for(
unsigned n=n_start;n<n_p;n++)
674 Node* nod_pt = el_pt->node_pt(n);
675 this->convert_to_boundary_node(nod_pt);
676 this->add_boundary_node(6,nod_pt);
677 b_coord[0] = nod_pt->x(0);
678 nod_pt->set_coordinates_on_boundary(6,b_coord);
683 this->setup_boundary_element_info();
688 {
return Upper_layer_element_pt[i];}
692 {
return Lower_layer_element_pt[i];}
695 unsigned long nupper()
const {
return Upper_layer_element_pt.size();}
698 unsigned long nlower()
const {
return Lower_layer_element_pt.size();}
702 {
return Interface_upper_boundary_element_pt[i];}
706 {
return Interface_lower_boundary_element_pt[i];}
710 {
return Interface_upper_boundary_element_pt.size();}
714 {
return Interface_lower_boundary_element_pt.size();}
752 template<
class ELEMENT>
760 const unsigned &Nx,
const unsigned &Nh1,
const unsigned &Nh2);
767 void parameter_study(
const string& dir_name);
770 void doc_solution(DocInfo& doc_info);
776 void create_free_surface_elements();
779 void create_volume_constraint_elements();
782 void create_contact_angle_element();
797 ConstitutiveLaw *Constitutive_law_pt;
802 Data* Traded_pressure_data_pt;
811 Mesh* Free_surface_mesh_pt;
814 Mesh* Free_surface_bounding_mesh_pt;
817 Mesh* Volume_computation_mesh_pt;
820 Mesh* Volume_constraint_mesh_pt;
831 template<
class ELEMENT>
833 const unsigned &Nx,
const unsigned &Nh1,
const unsigned &Nh2) :
837 Angle(0.5*MathematicalConstants::Pi)
852 Bulk_mesh_pt->upper_layer_element_pt(0))->hijack_internal_value(0,0);
860 for(
unsigned e=0;e<n_bulk;e++)
873 for (
unsigned b=0;b<6;b++)
876 unsigned n_boundary_node =
Bulk_mesh_pt->nboundary_node(b);
878 for(
unsigned n=0;n<n_boundary_node;n++)
889 for(
unsigned b=0;b<6;b++)
892 unsigned n_boundary_node =
Bulk_mesh_pt->nboundary_node(b);
894 for(
unsigned n=0;n<n_boundary_node;n++)
899 static_cast<SolidNode*
>(
Bulk_mesh_pt->boundary_node_pt(b,n))
903 if((b==1) || (b==2) || (b==4) || (b==5))
905 static_cast<SolidNode*
>(
Bulk_mesh_pt->boundary_node_pt(b,n))
914 for(
unsigned n=0;n<n_node;n++)
916 static_cast<SolidNode*
>(
Bulk_mesh_pt->node_pt(n))->pin_position(0);
922 dynamic_cast<ELEMENT*
>(
Bulk_mesh_pt->element_pt(0))->fix_pressure(0,0.0);
941 this->build_global_mesh();
944 cout <<
"Number of unknowns: " << assign_eqn_numbers() << std::endl;
953 template<
class ELEMENT>
964 for(
unsigned e=0;e<n_element;e++)
972 for(
unsigned e=0;e<n_element;e++)
989 template<
class ELEMENT>
998 for(
unsigned e=0;e<n_element;e++)
1001 ElasticLineFluidInterfaceElement<ELEMENT>* el_pt =
1002 new ElasticLineFluidInterfaceElement<ELEMENT>(
1004 Bulk_mesh_pt->interface_lower_face_index_at_boundary(e));
1010 el_pt->ca_pt() = &
Ca;
1019 template<
class ELEMENT>
1024 VolumeConstraintElement* vol_constraint_element =
1032 unsigned lower_boundaries[3]={0,1,5};
1034 for(
unsigned i=0;i<3;i++)
1037 unsigned b= lower_boundaries[i];
1039 unsigned n_element =
Bulk_mesh_pt->nboundary_element(b);
1042 for(
unsigned e=0;e<n_element;e++)
1046 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
1050 int face_index =
Bulk_mesh_pt->face_index_at_boundary(b,e);
1053 ElasticLineVolumeConstraintBoundingElement<ELEMENT>* el_pt =
1054 new ElasticLineVolumeConstraintBoundingElement<ELEMENT>(
1055 bulk_elem_pt,face_index);
1058 el_pt->set_volume_constraint_element(vol_constraint_element);
1072 for(
unsigned e=0;e<n_element;e++)
1076 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
1080 int face_index =
Bulk_mesh_pt->interface_lower_face_index_at_boundary(e);
1083 ElasticLineVolumeConstraintBoundingElement<ELEMENT>* el_pt =
1084 new ElasticLineVolumeConstraintBoundingElement<ELEMENT>(
1085 bulk_elem_pt,face_index);
1088 el_pt->set_volume_constraint_element(vol_constraint_element);
1101 template<
class ELEMENT>
1112 FluidInterfaceBoundingElement* el_pt =
1113 dynamic_cast<ElasticLineFluidInterfaceElement<ELEMENT>*
> 1115 make_bounding_element(1);
1118 el_pt->set_contact_angle(&
Angle);
1121 el_pt->ca_pt() = &
Ca;
1124 el_pt->wall_unit_normal_fct_pt()
1138 template<
class ELEMENT>
1143 doc_info.set_directory(dir_name);
1144 doc_info.number()=0;
1148 sprintf(filename,
"%s/trace.dat",doc_info.directory().c_str());
1150 Trace_file <<
"VARIABLES=\"<greek>a</greek><sub>prescribed</sub>\",";
1151 Trace_file <<
"\"h<sub>left</sub>\",\"h<sub>right</sub>\",";
1152 Trace_file <<
"\"p<sub>fluid</sub>-p<sub>ext</sub>\",";
1153 Trace_file <<
"\"<greek>D</greek>p<sub>exact</sub>\"";
1160 doc_info.number()++;
1163 for(
unsigned i=0;i<6;i++)
1166 steady_newton_solve();
1172 doc_info.number()++;
1175 Angle -= 5.0*MathematicalConstants::Pi/180.0;
1186 template<
class ELEMENT>
1197 sprintf(filename,
"%s/soln%i.dat",doc_info.directory().c_str(),
1199 some_file.open(filename);
1217 ->node_pt(np-1)->x(1);
1219 <<
dynamic_cast<ELEMENT*
>(
1222 <<
dynamic_cast<ELEMENT*
>(
1246 PseudoSolidNodeUpdateElement<QCrouzeixRaviartElement<2>,
1247 QPVDElementWithPressure<2> > > >
1251 problem.parameter_study(
"RESLT_elastic");
void parameter_study(const string &dir_name)
ConstitutiveLaw * Constitutive_law_pt
Constitutive law used to determine the mesh deformation.
TwoLayerSpineMesh< SpineElement< ELEMENT > > * Bulk_mesh_pt
Pointer to the mesh.
void create_contact_angle_element()
Create the contact angle element.
Vector< double > Wall_normal
Direction of the wall normal vector.
void actions_before_newton_convergence_check()
Update the spine mesh after every Newton step.
Data * Traded_pressure_data_pt
void parameter_study()
Peform a parameter study: Solve problem for a range of contact angles.
unsigned long nupper() const
Number of elements in upper layer.
void create_free_surface_elements()
Create the free surface elements.
ElasticTwoLayerMesh< ELEMENT > * Bulk_mesh_pt
Storage for the bulk mesh.
Vector< FiniteElement * > Lower_layer_element_pt
Vector of pointers to element in the upper layer.
FiniteElement *& upper_layer_element_pt(const unsigned long &i)
Access functions for pointers to elements in upper layer.
void parameter_study(const string &dir_name)
double Angle
The contact angle.
Mesh * Free_surface_bounding_mesh_pt
Storage for the element bounding the free surface.
void create_volume_constraint_elements()
Create the volume constraint elements.
int main()
Main driver: Build problem and initiate parameter study.
unsigned long nlower() const
Number of elements in top layer.
Mesh * Free_surface_mesh_pt
Storage for the free surface mesh.
void create_volume_constraint_elements()
Create the volume constraint elements.
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) ...
Vector< FiniteElement * > Upper_layer_element_pt
Vector of pointers to element in the lower layer.
double Volume
The prescribed volume of the fluid.
FiniteElement *& interface_upper_boundary_element_pt(const unsigned long &i)
Access functions for pointers to elements in upper layer.
FiniteElement *& interface_lower_boundary_element_pt(const unsigned long &i)
Access functions for pointers to elements in bottom layer.
void wall_unit_normal_fct(const Vector< double > &x, Vector< double > &normal)
Function that specifies the wall unit normal.
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) ...
Mesh * Volume_constraint_mesh_pt
Storage for the volume constraint.
CapProblem(const bool &hijack_internal)
~PseudoSolidCapProblem()
Destructor: clean up memory allocated by the object.
ofstream Trace_file
Trace file.
PseudoSolidCapProblem(const bool &hijack_internal)
void doc_solution(DocInfo &doc_info)
Doc the solution.
Namespace for phyical parameters.
A class that solves the Navier–Stokes equations to compute the shape of a static interface in a rect...
Vector< FiniteElement * > Interface_upper_boundary_element_pt
Vector of pointers to the element adjacent to the interface on the upper layer.
void doc_solution(DocInfo &doc_info)
Doc the solution.
double Ca
The Capillary number.
unsigned long ninterface_lower() const
Number of elements in top layer.
Vector< FiniteElement * > Interface_lower_boundary_element_pt
Vector of pointers to the elements adjacent to the interface on the lower layer.
Mesh * Volume_computation_mesh_pt
Storage for the elements that compute the enclosed volume.
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 ...
double Nu
Pseudo-solid Poisson ratio.
Mesh * Bulk_mesh_pt
Storage for the bulk mesh.
unsigned long ninterface_upper() const
Number of elements in upper layer.
FiniteElement *& lower_layer_element_pt(const unsigned long &i)
Access functions for pointers to elements in bottom layer.