The problem of steady flow in a curved tube is considered with a prescribed Poiseuille flow at the inlet and a traction-free outlet condition. It is not clear that the latter is appropriate, but the main aim of this example is to check that the TubeMesh
works correctly.
A detailed comparison between the flow field and the Dean solution should be performed for validation purposes, but the qualitative features seem reasonable.
Detailed documentation to be written. Here's the driver code...
#include "generic.h"
#include "navier_stokes.h"
#include "meshes/tube_mesh.h"
using namespace std;
using namespace oomph;
{
public:
void position (
const Vector<double>& xi, Vector<double>& r)
const
{
r[0] = (1.0/
Delta)*cos(xi[0]) + xi[2]*
Radius*cos(xi[0])*cos(xi[1]);
r[1] = (1.0/
Delta)*sin(xi[0]) + xi[2]*
Radius*sin(xi[0])*cos(xi[1]);
r[2] = -xi[2]*
Radius*sin(xi[1]);
}
const Vector<double>& xi, Vector<double>& r) const
{
}
private:
};
{
}
template<class ELEMENT>
{
public:
const double& max_error_target);
{
RefineableNavierStokesEquations<3>::
pin_redundant_nodal_pressures(
mesh_pt()->element_pt());
}
RefineableTubeMesh<ELEMENT>*
mesh_pt()
{
return dynamic_cast<RefineableTubeMesh<ELEMENT>*>(Problem::mesh_pt());
}
private:
};
template<class ELEMENT>
const double& min_error_target,
const double& max_error_target)
: Doc_info(doc_info)
{
const double pi = MathematicalConstants::Pi;
Vector<double> centreline_limits(2);
centreline_limits[0] = 0.0;
centreline_limits[1] = pi;
Vector<double> theta_positions(4);
theta_positions[0] = -0.75*pi;
theta_positions[1] = -0.25*pi;
theta_positions[2] = 0.25*pi;
theta_positions[3] = 0.75*pi;
Vector<double> radial_frac(4,0.5);
unsigned nlayer=6;
Problem::mesh_pt()= new RefineableTubeMesh<ELEMENT>(Volume_pt,
centreline_limits,
theta_positions,
radial_frac,
nlayer);
Z2ErrorEstimator* error_estimator_pt=new Z2ErrorEstimator;
mesh_pt()->spatial_error_estimator_pt()=error_estimator_pt;
mesh_pt()->max_permitted_error()=max_error_target;
mesh_pt()->min_permitted_error()=min_error_target;
ELEMENT::Gamma[0] = 0.0;
ELEMENT::Gamma[1] = 0.0;
ELEMENT::Gamma[2] = 0.0;
unsigned num_bound = mesh_pt()->nboundary();
for(unsigned ibound=0;ibound<num_bound;ibound++)
{
unsigned num_nod= mesh_pt()->nboundary_node(ibound);
for (unsigned inod=0;inod<num_nod;inod++)
{
if((ibound==0) || (ibound==1))
{
mesh_pt()->boundary_node_pt(ibound,inod)->pin(0);
mesh_pt()->boundary_node_pt(ibound,inod)->pin(1);
mesh_pt()->boundary_node_pt(ibound,inod)->pin(2);
}
}
}
unsigned n_element = mesh_pt()->nelement();
for(unsigned i=0;i<n_element;i++)
{
ELEMENT* el_pt = dynamic_cast<ELEMENT*>(mesh_pt()->element_pt(i));
}
RefineableNavierStokesEquations<3>::
pin_redundant_nodal_pressures(mesh_pt()->element_pt());
cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
}
template<class ELEMENT>
{
unsigned ibound=0;
unsigned num_nod= mesh_pt()->nboundary_node(ibound);
for (unsigned inod=0;inod<num_nod;inod++)
{
double x=mesh_pt()->boundary_node_pt(ibound,inod)->x(0) -
double z=mesh_pt()->boundary_node_pt(ibound,inod)->x(2);
double r=sqrt(x*x+z*z);
mesh_pt()->boundary_node_pt(ibound,inod)->
set_value(1,(1.0-pow(r,2.0)));
}
}
template<class ELEMENT>
{
ofstream some_file;
char filename[100];
unsigned npts;
npts=5;
snprintf(filename, sizeof(filename), "%s/soln_Re%g.dat",Doc_info.directory().c_str(),
some_file.open(filename);
mesh_pt()->output(some_file,npts);
some_file.close();
}
int main(
int argc,
char* argv[])
{
CommandLineArgs::setup(argc,argv);
unsigned max_adapt;
double max_error_target,min_error_target;
if (CommandLineArgs::Argc==1)
{
max_adapt=2;
max_error_target=0.001;
min_error_target=0.00001;
}
else
{
max_adapt=1;
max_error_target=0.02;
min_error_target=0.002;
}
DocInfo doc_info;
{
doc_info.set_directory("RESLT_TH");
doc_info.number()=0;
problem(doc_info,min_error_target,max_error_target);
cout << " Doing Taylor-Hood elements " << std::endl;
problem.newton_solve(max_adapt);
problem.doc_solution();
}
{
doc_info.set_directory("RESLT_CR");
doc_info.number()=0;
problem(doc_info,min_error_target,max_error_target);
cout << " Doing Crouzeix-Raviart elements " << std::endl;
problem.newton_solve(max_adapt);
problem.doc_solution();
}
}
void position(const Vector< double > &xi, Vector< double > &r) const
Lagrangian coordinate xi.
double Radius
Storage for the radius of the tube.
virtual ~MyCurvedCylinder()
Destructor.
Entry flow problem in tapered tube domain.
GeomObject * Volume_pt
Pointer to GeomObject that specifies the domain volume.
DocInfo Doc_info
Doc info object.
~SteadyCurvedTubeProblem()
Destructor (empty)
void actions_after_adapt()
After adaptation: Pin redudant pressure dofs.
void doc_solution()
Doc the solution.
RefineableTubeMesh< ELEMENT > * mesh_pt()
Overload generic access function by one that returns a pointer to the specific mesh.
void actions_before_newton_solve()
Update the problem specs before solve.
SteadyCurvedTubeProblem(DocInfo &doc_info, const double &min_error_target, const double &max_error_target)
Constructor: Pass DocInfo object and target errors.
int main(int argc, char *argv[])
Driver for 3D entry flow into a curved tube. If there are any command line arguments,...
Namespace for physical parameters.
double Re
Reynolds number.
double Delta
The desired curvature of the pipe.