31 #include "navier_stokes.h"
32 #include "fluid_interface.h"
35 #include "meshes/bretherton_spine_mesh.h"
39 using namespace oomph;
76 void inflow(
const Vector<double>& x, Vector<double>& veloc)
79 std::ostringstream error_stream;
80 bool throw_error=
false;
83 error_stream <<
"You must set H_lo_pt\n";
88 error_stream <<
"You must set H_up_pt\n";
93 error_stream <<
"You must set Y_lo_pt\n";
98 error_stream <<
"You must set Y_up_pt\n";
105 throw OomphLibError(error_stream.str(),
106 OOMPH_CURRENT_FUNCTION,
107 OOMPH_EXCEPTION_LOCATION);
120 double C =6.0*(2.0*h_av+y_lo-y_up)/
121 (y_up*y_up*y_up-y_lo*y_lo*y_lo-h_av*y_up*
122 y_up*y_up+h_av*y_lo*y_lo*y_lo-3.0*y_lo*y_up*y_up+
123 3.0*y_lo*y_lo*y_up+3.0*y_lo*y_up*y_up*h_av-3.0*y_lo*y_lo*y_up*h_av);
129 veloc[0]=-1.0+C*(1.0-h_av)*((y_lo-y)*(y_up-y));
152 template<
class ELEMENT>
160 typedef void (*InflowFctPt)(
const Vector<double>& x, Vector<double>& veloc);
172 const Vector<Data*>& inflow_ext_data,
173 const unsigned& inflow_boundary,
174 InflowFctPt inflow_fct_pt)
177 unsigned n_ext=inflow_ext_data.size();
178 Inflow_ext_data.resize(n_ext);
179 for (
unsigned i=0;i<n_ext;i++)
181 Inflow_ext_data[i]=inflow_ext_data[i];
184 Inflow_boundary=inflow_boundary;
186 Inflow_fct_pt=inflow_fct_pt;
195 ELEMENT::assign_local_eqn_numbers(store_local_dof_pt);
201 unsigned local_eqn_count = this->ndof();
205 unsigned max_nvalue=0;
206 unsigned n_ext=Inflow_ext_data.size();
207 for (
unsigned i=0;i<n_ext;i++)
210 Data* data_pt=Inflow_ext_data[i];
212 unsigned n_val=data_pt->nvalue();
213 if (n_val>max_nvalue) max_nvalue=n_val;
217 Inflow_ext_data_eqn.resize(n_ext,max_nvalue);
220 std::deque<unsigned long> global_eqn_number_queue;
223 for (
unsigned i=0;i<n_ext;i++)
226 Data* data_pt=Inflow_ext_data[i];
229 unsigned n_val=data_pt->nvalue();
230 for (
unsigned ival=0;ival<n_val;ival++)
234 long eqn_number=data_pt->eqn_number(ival);
238 global_eqn_number_queue.push_back(eqn_number);
240 Inflow_ext_data_eqn(i,ival)=local_eqn_count;
246 Inflow_ext_data_eqn(i,ival)=-1;
252 this->add_global_eqn_numbers(global_eqn_number_queue,
253 GeneralisedElement::Dof_pt_deque);
262 DenseMatrix<double>& jacobian)
265 unsigned n_ext=Inflow_ext_data.size();
268 ELEMENT::get_jacobian(residuals,jacobian);
270 if (n_ext==0)
return;
273 Vector<double> residuals_plus(residuals.size());
274 double fd_step=1.0e-8;
277 for (
unsigned i=0;i<n_ext;i++)
280 Data* data_pt=Inflow_ext_data[i];
283 unsigned n_val=data_pt->nvalue();
284 for (
unsigned ival=0;ival<n_val;ival++)
287 int local_eqn=Inflow_ext_data_eqn(i,ival);
293 double *value_pt = data_pt->value_pt(ival);
296 double backup = *value_pt;
299 *value_pt += fd_step;
306 unsigned n_dof = this->ndof();
308 for(
unsigned idof=0;idof<n_dof;idof++) {residuals_plus[idof] = 0.0;}
310 this->get_residuals(residuals_plus);
312 for(
unsigned idof=0;idof<n_dof;idof++)
314 jacobian(idof,local_eqn)=
315 (residuals_plus[idof]-residuals[idof])/fd_step;
344 Vector<double> veloc(2);
345 unsigned n_nod = this->nnode();
346 for (
unsigned j=0;j<n_nod;j++)
348 Node* nod_pt = this->node_pt(j);
350 if(nod_pt->is_on_boundary(Inflow_boundary))
353 for (
unsigned i=0;i<2;i++)
355 if (nod_pt->eqn_number(0)>=0)
357 std::ostringstream error_stream;
359 <<
"We're assigning a Dirichlet condition for the "
361 <<
"velocity, even though it is not pinned!\n"
362 <<
"This can't be right! I'm bailing out..."
365 throw OomphLibError(error_stream.str(),
366 OOMPH_CURRENT_FUNCTION,
367 OOMPH_EXCEPTION_LOCATION);
374 Inflow_fct_pt(x,veloc);
375 nod_pt->set_value(0,veloc[0]);
376 nod_pt->set_value(1,veloc[1]);
408 class FaceGeometry<
BrethertonElement<SpineElement<QCrouzeixRaviartElement<2> > > >:
public virtual QElement<1,3>
420 class FaceGeometry<
BrethertonElement<SpineElement<QTaylorHoodElement<2> > > >:
public virtual QElement<1,3>
433 SpineElement<QCrouzeixRaviartElement<2> > > > >:
public virtual PointElement
446 class FaceGeometry<FaceGeometry<
BrethertonElement<SpineElement<QTaylorHoodElement<2> > > > >:
public virtual PointElement
463 template<
class ELEMENT>
480 Bulk_mesh_pt->node_update();
484 unsigned num_nod=mesh_pt()->nboundary_node(ibound);
488 Vector<double> veloc(2);
491 for (
unsigned inod=0;inod<num_nod;inod++)
494 x[0]=mesh_pt()->boundary_node_pt(ibound,inod)->x(0);
495 x[1]=mesh_pt()->boundary_node_pt(ibound,inod)->x(1);
499 mesh_pt()->boundary_node_pt(ibound,inod)->set_value(0,veloc[0]);
500 mesh_pt()->boundary_node_pt(ibound,inod)->set_value(1,veloc[1]);
513 const double &pvalue)
516 dynamic_cast<ELEMENT *
>(Bulk_mesh_pt->element_pt(e))->
517 fix_pressure(l,pvalue);
523 void activate_inflow_dependency();
526 void parameter_study(
const unsigned& nsteps);
529 void doc_solution(DocInfo& doc_info);
541 BrethertonSpineMesh<ELEMENT,SpineLineFluidInterfaceElement<ELEMENT> >*
550 template<
class ELEMENT>
575 GeomObject* lower_wall_pt=
new StraightLine(-1.0);
576 GeomObject* upper_wall_pt=
new StraightLine( 1.0);
588 Bulk_mesh_pt =
new BrethertonSpineMesh<ELEMENT,
589 SpineLineFluidInterfaceElement<ELEMENT> >
590 (nx1,nx2,nx3,nh,nhalf,h,lower_wall_pt,upper_wall_pt,xi0,0.0,xi1,xi2);
593 mesh_pt()=Bulk_mesh_pt;
596 Control_element_pt=Bulk_mesh_pt->control_element_pt();
603 Bulk_mesh_pt->spine_pt(0)->spine_height_pt()->value_pt(0);
606 unsigned last_spine=Bulk_mesh_pt->nfree_surface_spines()-1;
608 Bulk_mesh_pt->spine_pt(last_spine)->spine_height_pt()->value_pt(0);
613 Bulk_mesh_pt->boundary_node_pt(ibound,0)->x_pt(0,1);
616 unsigned nnod=Bulk_mesh_pt->nboundary_node(ibound);
618 Bulk_mesh_pt->boundary_node_pt(ibound,nnod-1)->x_pt(0,1);
621 activate_inflow_dependency();
628 for(
unsigned ibound=0;ibound<=2;ibound++)
630 unsigned num_nod=mesh_pt()->nboundary_node(ibound);
631 for (
unsigned inod=0;inod<num_nod;inod++)
633 mesh_pt()->boundary_node_pt(ibound,inod)->pin(0);
634 mesh_pt()->boundary_node_pt(ibound,inod)->pin(1);
639 for(
unsigned ibound=3;ibound<=5;ibound+=2)
641 unsigned num_nod=mesh_pt()->nboundary_node(ibound);
642 for (
unsigned inod=0;inod<num_nod;inod++)
644 mesh_pt()->boundary_node_pt(ibound,inod)->pin(0);
645 mesh_pt()->boundary_node_pt(ibound,inod)->pin(1);
650 unsigned central_spine=(Bulk_mesh_pt->nfree_surface_spines()-1)/2;
651 Bulk_mesh_pt->spine_pt(central_spine)->spine_height_pt()->pin(0);
655 for (
unsigned ibound=0;ibound<=2;ibound+=2)
657 unsigned num_nod=mesh_pt()->nboundary_node(ibound);
658 for (
unsigned inod=0;inod<num_nod;inod++)
661 mesh_pt()->boundary_node_pt(ibound,inod)->set_value(0,-1.0);
662 mesh_pt()->boundary_node_pt(ibound,inod)->set_value(1, 0.0);
668 for (
unsigned ibound=3;ibound<=5;ibound+=2)
670 unsigned num_nod=mesh_pt()->nboundary_node(ibound);
671 for (
unsigned inod=0;inod<num_nod;inod++)
674 mesh_pt()->boundary_node_pt(ibound,inod)->set_value(0,-1.0);
675 mesh_pt()->boundary_node_pt(ibound,inod)->set_value(1, 0.0);
684 unsigned n_bulk=Bulk_mesh_pt->nbulk();
685 for(
unsigned i=0;i<n_bulk;i++)
688 ELEMENT *el_pt =
dynamic_cast<ELEMENT*
>(Bulk_mesh_pt->
698 unsigned interface_element_pt_range = Bulk_mesh_pt->ninterface_element();
699 for(
unsigned i=0;i<interface_element_pt_range;i++)
702 SpineLineFluidInterfaceElement<ELEMENT>* el_pt =
703 dynamic_cast<SpineLineFluidInterfaceElement<ELEMENT>*
>
704 (Bulk_mesh_pt->interface_element_pt(i));
712 Bulk_mesh_pt->node_update();
715 cout <<
"Number of unknowns: " << assign_eqn_numbers() << std::endl;
725 template<
class ELEMENT>
730 Vector<Data*> outflow_spines(2);
733 outflow_spines[0]=Bulk_mesh_pt->spine_pt(0)->spine_height_pt();
736 unsigned last_spine=Bulk_mesh_pt->nfree_surface_spines()-1;
737 outflow_spines[1]=Bulk_mesh_pt->spine_pt(last_spine)->spine_height_pt();;
743 unsigned nel=Bulk_mesh_pt->nboundary_element(ibound);
744 for (
unsigned e=0;e<nel;e++)
747 ELEMENT* el_pt=
dynamic_cast<ELEMENT*
>(Bulk_mesh_pt->
748 boundary_element_pt(ibound,e));
750 el_pt->activate_inflow_dependency_on_external_data(
761 template<
class ELEMENT>
777 unsigned last_spine=Bulk_mesh_pt->nfree_surface_spines()-1;
781 Trace_file <<
" " << Bulk_mesh_pt->spine_pt(0)->height();
782 Trace_file <<
" " << Bulk_mesh_pt->spine_pt(last_spine)->height();
784 Trace_file <<
" " << -Control_element_pt->interpolated_p_nst(s)*
787 Trace_file <<
" " << Control_element_pt->interpolated_u_nst(s,0);
788 Trace_file <<
" " << Control_element_pt->interpolated_u_nst(s,1);
789 Trace_file << std::endl;
793 sprintf(filename,
"%s/soln%i.dat",doc_info.directory().c_str(),
795 some_file.open(filename);
796 Bulk_mesh_pt->output(some_file,npts);
801 sprintf(filename,
"%s/boundaries%i.dat",doc_info.directory().c_str(),
803 some_file.open(filename);
804 Bulk_mesh_pt->output_boundaries(some_file);
815 template<
class ELEMENT>
820 Problem::Max_residuals=100.0;
824 doc_info.set_directory(
"RESLT");
830 sprintf(filename,
"%s/trace.dat",doc_info.directory().c_str());
831 Trace_file.open(filename);
833 Trace_file <<
"VARIABLES=\"Ca\",";
834 Trace_file <<
"\"h<sub>bottom</sub>\",\"h<sub>too</sub>\",";
835 Trace_file <<
"\"h<sub>Bretherton</sub>\",\"p<sub>tip</sub>\",";
836 Trace_file <<
"\"p<sub>tip (Bretherton)</sub>\",\"u<sub>stag</sub>\",";
837 Trace_file <<
"\"v<sub>stag</sub>\"";
838 Trace_file <<
"\"<greek>a</greek><sub>bottom</sub>\",";
839 Trace_file <<
"\"<greek>a</greek><sub>top</sub>\"";
840 Trace_file << std::endl;
846 doc_solution(doc_info);
849 for (
unsigned step=1;step<=nsteps;step++)
851 cout << std::endl <<
"STEP " << step << std::endl;
860 cout <<
"Checking max. res for Ca = "
864 DoubleVector residuals;
865 actions_before_newton_solve();
866 actions_before_newton_convergence_check();
867 get_residuals(residuals);
868 double max_res=residuals.max();
874 cout <<
". Too big!" << std::endl;
878 factor=1.0+(factor-1.0)/1.5;
879 cout <<
"New reduction factor: " << factor << std::endl;
888 cout <<
". OK" << std::endl << std::endl;
895 cout <<
"Solving for capillary number: "
901 doc_solution(doc_info);
916 int main(
int argc,
char* argv[])
921 CommandLineArgs::setup(argc,argv);
947 if (CommandLineArgs::Argc>1)
int main(int argc, char *argv[])
Driver code for unsteady two-layer fluid problem. If there are any command line arguments,...
"Bretherton element" is a fluid element (of type ELEMENT) for which the (inflow) velocity at those no...
unsigned Inflow_boundary
Number of the inflow boundary in the global mesh.
void assign_local_eqn_numbers(const bool &store_local_dof_pt)
Overload assign local equation numbers: Add the dependency on the external Data that affects the infl...
void activate_inflow_dependency_on_external_data(const Vector< Data * > &inflow_ext_data, const unsigned &inflow_boundary, InflowFctPt inflow_fct_pt)
Activate the dependency of the "inflow" on the external data. Pass the vector of pointers to the exte...
InflowFctPt Inflow_fct_pt
Function pointer to the global function that specifies the inflow velocity profile on the global mesh...
void reassign_inflow()
For all nodes that are located on specified boundary re-assign the inflow velocity,...
Vector< Data * > Inflow_ext_data
Storage for the external Data that affects the inflow.
void get_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Overloaded Jacobian computation: Computes the Jacobian of the underlying element and then adds the FD...
BrethertonElement()
Constructor: Call the constructor of the underlying element.
DenseMatrix< int > Inflow_ext_data_eqn
Storage for the local equation numbers associated the Data values that affect the inflow.
////////////////////////////////////////////////////////////////// //////////////////////////////////...
void activate_inflow_dependency()
Activate the dependency of the inflow velocity on the spine heights at the outflow.
BrethertonProblem()
Constructor:
void actions_after_newton_solve()
Update after solve can remain empty, because the update is performed automatically after every Newton...
void actions_before_newton_convergence_check()
Spine heights/lengths are unknowns in the problem so their values get corrected during each Newton st...
void actions_before_newton_solve()
Update before solve: empty.
void fix_pressure(const unsigned &e, const unsigned &l, const double &pvalue)
Fix pressure value l in element e to value p_value.
ELEMENT * Control_element_pt
Pointer to control element.
void doc_solution(DocInfo &doc_info)
Doc the solution.
void parameter_study(const unsigned &nsteps)
Run a parameter study; perform specified number of steps.
ofstream Trace_file
Trace file.
BrethertonSpineMesh< ELEMENT, SpineLineFluidInterfaceElement< ELEMENT > > * Bulk_mesh_pt
Pointer to bulk mesh.
Namepspace for global parameters.
double ReSt
Womersley = Reynolds times Strouhal.
void inflow(const Vector< double > &x, Vector< double > &veloc)
Set inflow velocity, based on spine heights at outflow and channel width at inflow.
double * H_lo_pt
Pointer to film thickness at outflow on the lower wall.
Vector< double > G(2)
Direction of gravity.
double * Y_up_pt
Pointer to y-position at inflow on the upper wall.
double * H_up_pt
Pointer to film thickness at outflow on the upper wall.
double * Y_lo_pt
Pointer to y-position at inflow on the lower wall.
double Ca
Capillary number.
double ReInvFr
Product of Reynolds and Froude number.
double Re
Reynolds number.