38 #include "axisym_navier_stokes.h"
41 #include "fluid_interface.h"
44 #include "meshes/horizontal_single_layer_spine_mesh.h"
47 using namespace oomph;
114 template<
class ELEMENT>
141 unsigned n_node = this->nnode();
144 const unsigned c_index = C_index;
156 for(
unsigned l=0;l<n_node;l++)
158 C += this->nodal_value(l,c_index)*psi(l);
168 TimeStepper* time_stepper_pt= this->node_pt(l)->time_stepper_pt();
173 if (time_stepper_pt->type()!=
"Steady")
176 const unsigned c_index = C_index;
179 const unsigned n_time = time_stepper_pt->ntstorage();
181 for(
unsigned t=0;t<n_time;t++)
183 dcdt += time_stepper_pt->weight(1,t)*this->nodal_value(t,l,c_index);
192 double sigma(
const Vector<double> &s)
195 const unsigned n_node = this->nnode();
202 for(
unsigned l=0;l<n_node;l++)
204 C += this->nodal_value(l,C_index)*psi(l);
208 double Beta = this->beta();
210 return (1.0 -
Beta*(C-1.0));
218 this->fill_in_generic_residual_contribution_interface(residuals,jacobian,1);
222 const unsigned n_node = this->nnode();
224 const unsigned n_dof = this->ndof();
226 Vector<double> newres(n_dof);
232 const double fd_step = this->Default_fd_jacobian_step;
235 for(
unsigned n=0;n<n_node;n++)
238 unsigned c_index = this->C_index;
241 local_unknown = this->nodal_local_eqn(n,c_index);
243 if(local_unknown >= 0)
246 double *value_pt = this->node_pt(n)->value_pt(c_index);
249 double old_var = *value_pt;
252 *value_pt += fd_step;
255 this->get_residuals(newres);
258 for(
unsigned m=0;m<n_dof;m++)
260 double sum = (newres[m] - residuals[m])/fd_step;
262 jacobian(m,local_unknown) = sum;
272 SpineElement<FaceGeometry<ELEMENT> >::fill_in_jacobian_from_geometric_data(jacobian);
280 const unsigned &flag,
const Shape &psif,
const DShape &dpsifds,
281 const DShape &dpsifdS,
const DShape &dpsifdS_div,
282 const Vector<double> &s,
283 const Vector<double> &interpolated_x,
const Vector<double> &interpolated_n,
284 const double &W,
const double &J)
288 bool Integrated_curvature =
true;
291 unsigned n_node = this->nnode();
294 int local_eqn = 0, local_unknown = 0;
299 unsigned c_index = this->C_index;
300 Vector<unsigned> u_index = this->U_index_interface;
303 const double Pe_s = this->peclet_s();
307 const double r = interpolated_x[0];
310 const double J_raw = J/r;
314 double interpolated_C = 0.0;
315 double interpolated_dCds = 0.0;
318 const unsigned ndim = this->node_pt(0)->ndim();
319 Vector<double> interpolated_tangent(ndim,0.0);
320 Vector<double> interpolated_u(ndim,0.0);
321 Vector<double> mesh_velocity(ndim,0.0);
322 Vector<double> interpolated_duds(ndim,0.0);
323 if(ndim+1 != u_index.size())
325 throw OomphLibError(
"Dimension Incompatibility",
326 OOMPH_CURRENT_FUNCTION,
327 OOMPH_EXCEPTION_LOCATION);
330 for(
unsigned l=0;l<n_node;l++)
332 const double psi = psif(l);
333 const double dpsi = dpsifds(l,0);
334 interpolated_C += this->nodal_value(l,c_index)*psi;
335 interpolated_dCds += this->nodal_value(l,c_index)*dpsi;
336 dCdt += dcdt_surface(l)*psi;
337 for(
unsigned i=0;i<ndim;i++)
339 interpolated_tangent[i] += this->nodal_position(l,i)*dpsi;
340 interpolated_u[i] += this->nodal_value(l,u_index[i])*psi;
341 interpolated_duds[i] += this->nodal_value(l,u_index[i])*dpsi;
344 for(
unsigned j=0;j<ndim;j++)
346 mesh_velocity[j] += this->dnodal_position_dt(l,j)*psi;
351 double u_tangent = 0.0, t_length = 0.0;
352 for(
unsigned i=0;i<ndim;i++)
354 u_tangent += interpolated_u[i]*interpolated_tangent[i];
355 t_length += interpolated_tangent[i]*interpolated_tangent[i];
359 Vector<double> d2xds(2,0.0);
360 for(
unsigned i=0;i<2;i++)
362 d2xds[i] = this->nodal_position(0,i) +
363 this->nodal_position(2,i) - 2.0*this->nodal_position(1,i);
368 for(
unsigned i=0;i<2;i++)
370 k1 += (d2xds[i]/(J_raw*J_raw) - interpolated_tangent[i]*(
371 interpolated_tangent[0]*d2xds[0]
372 + interpolated_tangent[1]*d2xds[1])/(J_raw*J_raw*J_raw*J_raw))*interpolated_n[i];
376 double k2 = - (interpolated_n[0] / r);
379 for(
unsigned l=0;l<n_node;l++)
382 local_eqn = this->nodal_local_eqn(l,c_index);
388 residuals[local_eqn] += dCdt*psif(l)*r*W*J_raw;
392 if(Integrated_curvature)
394 for(
unsigned i=0;i<2;i++)
397 (interpolated_u[i] - mesh_velocity[i])*interpolated_tangent[i];
400 residuals[local_eqn] += tmp*interpolated_dCds*psif(l)*r*W/J_raw;
402 residuals[local_eqn] += interpolated_C*interpolated_u[0]*psif(l)*W*J_raw;
404 residuals[local_eqn] += interpolated_C*
405 (interpolated_duds[0]*interpolated_tangent[0]
406 + interpolated_duds[1]*interpolated_tangent[1])*r*W*psif(l)/J_raw;
412 for(
unsigned i=0;i<2;i++)
414 tmp += -mesh_velocity[i]*interpolated_tangent[i];
416 residuals[local_eqn] += tmp*interpolated_dCds*psif(l)*r*W/J_raw;
418 residuals[local_eqn] -=
419 interpolated_C*(k1 + k2)*psif(l)*r*W*J_raw*(
420 interpolated_u[0]*interpolated_n[0]
421 + interpolated_u[1]*interpolated_n[1]);
423 residuals[local_eqn] -= interpolated_C*(
424 interpolated_tangent[0]*interpolated_u[0] +
425 interpolated_tangent[1]*interpolated_u[1])*dpsifds(l,0)*r*W/J_raw;
429 residuals[local_eqn] += (1.0/Pe_s)*interpolated_dCds*dpsifds(l,0)*r*W/J_raw;
435 for(
unsigned l2=0;l2<n_node;l2++)
438 TimeStepper* time_stepper_pt=this->node_pt(l2)->time_stepper_pt();
441 local_unknown =this->nodal_local_eqn(l2,c_index);
443 if(local_unknown >=0)
445 jacobian(local_eqn,local_unknown) +=
446 time_stepper_pt->weight(1,0)*psif(l2)*psif(l)*r*W*J_raw;
448 if(Integrated_curvature)
450 jacobian(local_eqn,local_unknown) += ((interpolated_u[0] - mesh_velocity[0])*interpolated_tangent[0]
451 + (interpolated_u[1] - mesh_velocity[1])*interpolated_tangent[1])*dpsifds(l2,0)
455 jacobian(local_eqn,local_unknown) += psif(l2)*interpolated_u[0]*psif(l)*W*J_raw;
457 jacobian(local_eqn,local_unknown) += psif(l2)*(interpolated_tangent[0]*interpolated_duds[0]
458 + interpolated_tangent[1]*interpolated_duds[1])*psif(l)*r*W/J_raw;
462 jacobian(local_eqn,local_unknown) -=
463 (mesh_velocity[0]*interpolated_tangent[0] + mesh_velocity[1]*interpolated_tangent[1])*dpsifds(l2,0)*psif(l)*r*W/J_raw;
465 jacobian(local_eqn,local_unknown) -= psif(l2)*(k1 + k2)*psif(l)*r*W*J_raw*(interpolated_u[0]*interpolated_n[0]
466 + interpolated_u[1]*interpolated_n[1]);
468 jacobian(local_eqn,local_unknown) -= psif(l2)*(interpolated_tangent[0]*interpolated_u[0] + interpolated_tangent[1]*
469 interpolated_u[1])*dpsifds(l,0)*r*W/J_raw;
472 jacobian(local_eqn,local_unknown) += (1.0/Pe_s)*dpsifds(l2,0)*dpsifds(l,0)*r*W/J_raw;
478 for(
unsigned i2=0;i2<ndim;i2++)
482 local_unknown = this->nodal_local_eqn(l2,u_index[i2]);
486 if(local_unknown >= 0)
490 if(Integrated_curvature)
492 jacobian(local_eqn,local_unknown) +=
493 interpolated_dCds*psif(l2)*interpolated_tangent[i2]*psif(l)*r*W/J_raw;
497 jacobian(local_eqn,local_unknown) += interpolated_C*psif(l2)*W*J_raw;
502 jacobian(local_eqn,local_unknown) -= interpolated_C*(k1 + k2)*psif(l)*r*W*J_raw*psif(l2)*interpolated_n[i2];
504 jacobian(local_eqn,local_unknown) -= interpolated_C*interpolated_tangent[i2]*psif(l2)*dpsifds(l,0)*r*W/J_raw;
507 jacobian(local_eqn,local_unknown) +=
508 interpolated_C*interpolated_tangent[i2]*dpsifds(l2,0)*psif(l)*r*W/J_raw;
522 DenseMatrix<double> &mass_matrix)
525 this->fill_in_contribution_to_jacobian(residuals,jacobian);
533 (element_pt,face_index)
536 Beta_pt = &Default_Physical_Constant_Value;
537 Peclet_S_pt = &Default_Physical_Constant_Value;
538 Peclet_Strouhal_S_pt = &Default_Physical_Constant_Value;
544 unsigned n_node_face = this->nnode();
547 Vector<unsigned> additional_data_values(n_node_face);
548 for(
unsigned i=0;i<n_node_face;i++) additional_data_values[i] = 1;
550 this->resize_nodes(additional_data_values);
554 C_index = this->node_pt(0)->nvalue()-1;
558 double beta() {
return *Beta_pt;}
575 void output(std::ostream &outfile,
const unsigned &n_plot)
577 outfile.precision(16);
583 outfile <<
"ZONE I=" << n_plot << std::endl;
585 const unsigned n_node = this->nnode();
586 const unsigned dim = this->dim();
589 DShape dpsi(n_node,dim);
592 for(
unsigned l=0;l<n_plot;l++)
594 s[0] = -1.0 + l*2.0/(n_plot-1);
596 this->dshape_local(s,psi,dpsi);
597 Vector<double> interpolated_tangent(2,0.0);
598 for(
unsigned l=0;l<n_node;l++)
600 const double dpsi_ = dpsi(l,0);
601 for(
unsigned i=0;i<2;i++)
603 interpolated_tangent[i] += this->nodal_position(l,i)*dpsi_;
608 double t_vel = (this->interpolated_u(s,0)*interpolated_tangent[0] + this->interpolated_u(s,1)*interpolated_tangent[1])/
609 sqrt(interpolated_tangent[0]*interpolated_tangent[0] + interpolated_tangent[1]*interpolated_tangent[1]);
613 for(
unsigned i=0;i<2;i++) outfile << this->interpolated_x(s,i) <<
" ";
614 for(
unsigned i=0;i<2;i++) outfile << this->interpolated_u(s,i) <<
" ";
616 outfile << 0.0 <<
" ";
618 outfile << interpolated_C(s) <<
" ";
620 outfile << sigma(s) <<
" " << t_vel << std::endl;
622 outfile << std::endl;
630 unsigned n_node = this->nnode();
634 DShape dpsifds(n_node,1);
637 unsigned n_intpt = this->integral_pt()->nweight();
646 for(
unsigned ipt=0;ipt<n_intpt;ipt++)
649 s[0] = this->integral_pt()->knot(ipt,0);
652 double W = this->integral_pt()->weight(ipt);
655 this->dshape_local_at_knot(ipt,psif,dpsifds);
658 Vector<double> interpolated_x(2,0.0);
659 Vector<double> interpolated_t(2,0.0);
660 double interpolated_c = 0.0;
664 for(
unsigned l=0;l<n_node;l++)
666 interpolated_c += this->nodal_value(l,C_index)*psif(l);
668 for(
unsigned i=0;i<2;i++)
670 interpolated_x[i] += this->nodal_position(l,i)*psif(l);
671 interpolated_t[i] += this->nodal_position(l,i)*dpsifds(l,0);
676 double r = interpolated_x[0];
679 double tlength = interpolated_t[0]*interpolated_t[0] +
680 interpolated_t[1]*interpolated_t[1];
683 double J = sqrt(tlength);
685 mass += interpolated_c*r*W*J;
694 template<
class ELEMENT>
708 template <
class ELEMENT>
710 public HorizontalSingleLayerSpineMesh<ELEMENT>
722 TimeStepper* time_stepper_pt=
723 &Mesh::Default_TimeStepper) :
724 HorizontalSingleLayerSpineMesh<ELEMENT>(nx,ny,lx,ly,time_stepper_pt) {}
731 double W = spine_node_pt->fraction();
734 double H = spine_node_pt->h();
737 spine_node_pt->x(0) = 1.0-(1.0-W)*H;
749 template<
class ELEMENT,
class TIMESTEPPER>
769 Bulk_mesh_pt->node_update();
778 const unsigned n_node = Bulk_mesh_pt->nnode();
781 for(
unsigned n=0;n<n_node;n++)
784 for(
unsigned i=0;i<3;i++)
787 Bulk_mesh_pt->node_pt(n)->set_value(i,0.0);
793 assign_initial_values_impulsive();
804 double global_error = 0.0;
807 const unsigned n_node = Bulk_mesh_pt->nnode();
810 for(
unsigned n=0;n<n_node;n++)
813 const unsigned n_dim = 1;
815 double node_position_error = 0.0;
817 for(
unsigned i=0;i<n_dim;i++)
821 Bulk_mesh_pt->node_pt(n)->position_time_stepper_pt()->
822 temporal_error_in_position(Bulk_mesh_pt->node_pt(n),i);
825 node_position_error += error*error;
829 node_position_error /= n_dim;
831 global_error += node_position_error;
835 global_error /= n_node;
838 return sqrt(global_error);
852 void unsteady_run(
const double &t_max,
const double &dt);
861 const unsigned n_interface_element = Interface_mesh_pt->nelement();
864 for(
unsigned e=0;e<n_interface_element;e++)
869 (Interface_mesh_pt->element_pt(e));
883 const unsigned n_spine = Bulk_mesh_pt->nspine();
886 for(
unsigned i=0;i<n_spine;i++)
890 double z_value = Bulk_mesh_pt->boundary_node_pt(1,i)->x(1);
893 Bulk_mesh_pt->spine_pt(i)->height() =
900 Bulk_mesh_pt->node_update();
914 template<
class ELEMENT,
class TIMESTEPPER>
922 add_time_stepper_pt(
new TIMESTEPPER(
true));
929 Interface_mesh_pt =
new Mesh;
938 unsigned n_element = Bulk_mesh_pt->nboundary_element(3);
941 for(
unsigned e=0;e<n_element;e++)
944 ELEMENT* bulk_elem_pt =
dynamic_cast<ELEMENT*
>(
945 Bulk_mesh_pt->boundary_element_pt(3,e));
948 int face_index = Bulk_mesh_pt->face_index_at_boundary(3,e);
955 Interface_mesh_pt->add_element_pt(interface_element_pt);
962 add_sub_mesh(Bulk_mesh_pt);
963 add_sub_mesh(Interface_mesh_pt);
975 unsigned n_node = this->Bulk_mesh_pt->nnode();
976 for(
unsigned n=0;n<n_node;++n)
978 this->Bulk_mesh_pt->node_pt(n)->pin(2);
985 unsigned n_node = Bulk_mesh_pt->nboundary_node(ibound);
986 for(
unsigned n=0;n<n_node;n++)
988 Bulk_mesh_pt->boundary_node_pt(ibound,n)->set_value(3,1.0);
992 const unsigned n_boundary = Bulk_mesh_pt->nboundary();
995 for(
unsigned b=0;b<n_boundary;b++)
998 const unsigned n_node = Bulk_mesh_pt->nboundary_node(b);
1001 for(
unsigned n=0;n<n_node;n++)
1004 Bulk_mesh_pt->boundary_node_pt(b,n)->pin(2);
1009 Bulk_mesh_pt->boundary_node_pt(b,n)->pin(0);
1010 Bulk_mesh_pt->boundary_node_pt(b,n)->pin(1);
1015 Bulk_mesh_pt->boundary_node_pt(b,n)->pin(1);
1025 const unsigned n_bulk = Bulk_mesh_pt->nelement();
1028 for(
unsigned e=0;e<n_bulk;e++)
1031 ELEMENT *el_pt =
dynamic_cast<ELEMENT*
>(Bulk_mesh_pt->element_pt(e));
1049 Data* external_pressure_data_pt =
new Data(1);
1054 external_pressure_data_pt->pin(0);
1055 external_pressure_data_pt->set_value(0,p_ext);
1058 const unsigned n_interface_element = Interface_mesh_pt->nelement();
1061 for(
unsigned e=0;e<n_interface_element;e++)
1066 (Interface_mesh_pt->element_pt(e));
1086 cout <<
"Number of equations: " << assign_eqn_numbers() << std::endl;
1095 template<
class ELEMENT,
class TIMESTEPPER>
1101 double t= time_pt()->time();
1102 cout <<
"Time is now " << t << std::endl;
1105 Trace_file << time_pt()->time() <<
" "
1106 << Bulk_mesh_pt->spine_pt(0)->height()
1107 <<
" " << this->compute_total_mass() << std::endl;
1113 const unsigned npts = 5;
1124 sprintf(filename,
"%s/int%i.dat",doc_info.directory().c_str(),
1126 some_file.open(filename);
1127 Interface_mesh_pt->output(some_file,npts);
1152 string file_name=
"soln"+StringConversion::to_string(doc_info.number())
1164 template<
class ELEMENT,
class TIMESTEPPER>
1173 deform_free_surface(epsilon);
1179 doc_info.set_directory(
"RESLT");
1182 doc_info.number()=0;
1186 sprintf(filename,
"%s/trace.dat",doc_info.directory().c_str());
1187 Trace_file.open(filename);
1190 Trace_file <<
"time" <<
", "
1191 <<
"edge spine height" <<
", "
1192 <<
"contact angle left" <<
", "
1193 <<
"contact angle right" <<
", " << std::endl;
1199 set_initial_condition();
1202 const unsigned n_timestep = unsigned(t_max/dt);
1207 sprintf(filename,
"%s/soln.pvd",doc_info.directory().c_str());
1212 doc_solution(doc_info);
1215 doc_info.number()++;
1220 for(
unsigned t=1;t<=n_timestep;t++)
1223 cout <<
"\nTimestep " << t <<
" of " << n_timestep << std::endl;
1226 unsteady_newton_solve(dt);
1234 doc_solution(doc_info);
1237 doc_info.number()++;
1259 CommandLineArgs::setup(argc,argv);
1262 double t_max = 1000.0;
1265 const double dt = 0.1;
1268 if(CommandLineArgs::Argc>1)
1274 const unsigned n_r = 10;
1277 const unsigned n_z = 80;
1290 problem(n_r,n_z,l_z);
Single fluid interface problem including transport of an insoluble surfactant.
void set_initial_condition()
Set initial conditions: Set all nodal velocities to zero and initialise the previous velocities to co...
void unsteady_run(const unsigned &nstep)
Run an unsteady simulation with specified number of steps.
InterfaceProblem(const unsigned &n_r, const unsigned &n_y, const unsigned &n_theta, const double &r_min, const double &r_max, const double &l_y, const double &theta_max)
Constructor: Pass number of elements in x and y directions. Also lengths of the domain in x- and y-di...
void deform_free_surface(const double &epsilon)
Deform the mesh/free surface to a prescribed function.
void doc_solution(DocInfo &doc_info)
Doc the solution.
double global_temporal_error_norm()
The global temporal error norm, based on the movement of the nodes in the radial direction only (beca...
MyHorizontalSingleLayerSpineMesh< ELEMENT > * Bulk_mesh_pt
Access function for the specific mesh.
~InterfaceProblem()
Destructor (empty)
double compute_total_mass()
Compute the total mass of the insoluble surfactant.
void actions_before_newton_convergence_check()
Spine heights/lengths are unknowns in the problem so their values get corrected during each Newton st...
Mesh * Interface_mesh_pt
Mesh for the free surface (interface) elements.
double *& ca_pt()
Pointer to the Capillary number.
void set_external_pressure_data(Data *external_pressure_data_pt)
Set the Data that contains the single pressure value that specifies the "external pressure" for the i...
Inherit from the standard Horizontal single-layer SpineMesh and modify the spine_node_update() functi...
MyHorizontalSingleLayerSpineMesh(const unsigned &nx, const unsigned &ny, const double &lx, const double &ly, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Pass number of elements in x-direction, number of elements in y-direction,...
virtual void spine_node_update(SpineNode *spine_node_pt)
Node update function assumed spines rooted at the wall fixed to be at r=1 and directed inwards to r=0...
Spine-based Marangoni surface tension elements that add a linear dependence on concentration of a sur...
double * Beta_pt
Pointer to an Elasticity number.
double peclet_strouhal_s()
Return the surface peclect strouhal number.
void add_additional_residual_contributions_interface(Vector< double > &residuals, DenseMatrix< double > &jacobian, const unsigned &flag, const Shape &psif, const DShape &dpsifds, const DShape &dpsifdS, const DShape &dpsifdS_div, const Vector< double > &s, const Vector< double > &interpolated_x, const Vector< double > &interpolated_n, const double &W, const double &J)
Overload the Helper function to calculate the residuals and jacobian entries. This particular functio...
static double Default_Physical_Constant_Value
Default value of the physical constants.
double peclet_s()
Return the surface peclect number.
double * Peclet_S_pt
Pointer to Surface Peclet number.
double sigma(const Vector< double > &s)
The surface tension function is linear in the concentration with constant of proportionality equal to...
double dcdt_surface(const unsigned &l) const
The time derivative of the surface concentration.
unsigned C_index
Index at which the surfactant concentration is stored at the nodes.
double beta()
Return the Elasticity number.
double * Peclet_Strouhal_S_pt
Pointer to the surface Peclect Strouhal number.
double interpolated_C(const Vector< double > &s)
Get the surfactant concentration.
double *& peclet_strouhal_s_pt()
Access function for pointer to the surface Peclet x Strouhal number.
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Fill in the contribution to the residuals Calculate the contribution to the jacobian.
void fill_in_contribution_to_jacobian_and_mass_matrix(Vector< double > &residuals, DenseMatrix< double > &jacobian, DenseMatrix< double > &mass_matrix)
Add the element's contribution to its residuals vector, jacobian matrix and mass matrix.
void output(std::ostream &outfile, const unsigned &n_plot)
SpineAxisymmetricMarangoniSurfactantFluidInterfaceElement(FiniteElement *const &element_pt, const int &face_index)
Constructor that passes the bulk element and face index down to the underlying.
double *& beta_pt()
Access function for pointer to the Elasticity number.
double *& peclet_s_pt()
Access function for pointer to the surface Peclet number.
double integrate_c() const
Compute the concentration intergated over the area.
Namepspace for global parameters, chosen from Campana et al. as in the axisymmetric problem.
double P_ext
External pressure.
double ReSt
Womersley = Reynolds times Strouhal.
double Epsilon
Free surface cosine deformation parameter.
double Beta
Surface Elasticity number (weak case)
ofstream Pvd_file
Pvd file – a wrapper for all the different vtu output files plus information about continuous time to...
double Ca
Capillary number.
double Peclet_S
Surface Peclet number.
double Alpha
Wavelength of the domain.
double ReInvFr
Product of Reynolds and Froude number.
double Re
Reynolds number.
double Peclet_St_S
Sufrace Peclet number multiplied by Strouhal number.
Vector< double > G(3)
Direction of gravity.
int main(int argc, char *argv[])
//////////////////////////////////////////////////////////////////// ////////////////////////////////...