Our first "real" fluid-structure interaction problem: We study the finite-Reynolds number internal flow generated by the motion of an oscillating elastic ring and compare the results against asymptotic predictions.
#include "generic.h"
#include "navier_stokes.h"
#include "beam.h"
#include "meshes/quarter_circle_sector_mesh.h"
#include "meshes/one_d_lagrangian_mesh.h"
using namespace std;
{
{
cout << "\n\n======================================================" <<std::endl;
cout << "\nSetting parameters. \n\n";
cout << "Prescribed: Square of Womersley number: Alpha_sq = "
cout << " Density ratio: Density_ratio = "
cout << " Wall thickness: H = "
cout << " Poisson ratio: Nu = "
cout << " Pressure perturbation: Pcos = "
cout << "\nDependent: Stress ratio: Q = "
cout << " Timescale ratio: Lambda_sq = "
cout << " Reynolds number: Re = "
cout << " Womersley number: ReSt = "
cout << "\n======================================================\n\n"
<<std::endl;
}
void pcos_load(
const Vector<double>& xi,
const Vector<double> &x,
const Vector<double>&
N, Vector<double>& load)
{
for(unsigned i=0;i<2;i++)
{load[i] = (
Pext -
Pcos*cos(2.0*xi[0]))*
N[i];}
}
}
{
typedef AlgebraicElement<RefineableQCrouzeixRaviartElement<2> > FLUID_ELEMENT;
typedef FSIHermiteBeamElement SOLID_ELEMENT;
public:
const double& eps_ampl, const double& pcos_initial,
const double& pcos_duration);
void actions_after_newton_solve() {}
void actions_before_newton_solve() {}
void actions_before_newton_convergence_check()
{
Fluid_mesh_pt->node_update();
}
void actions_after_adapt()
{
unsigned n_node = Fluid_mesh_pt->nboundary_node(1);
for (unsigned n=0;n<n_node;n++)
{
Fluid_mesh_pt->boundary_node_pt(1,n)->set_auxiliary_node_update_fct_pt(
FSI_functions::apply_no_slip_on_moving_wall);
}
FSI_functions::setup_fluid_load_info_for_solid_elements<FLUID_ELEMENT,2>
(this,1,Fluid_mesh_pt,Wall_mesh_pt);
}
void doc_solution(const unsigned& i, DocInfo& doc_info, ofstream& trace_file);
void dynamic_run();
private:
void set_initial_condition();
void set_wall_initial_condition();
void set_fluid_initial_condition();
SOLID_ELEMENT* Doc_displacement_elem_pt;
OneDLagrangianMesh<SOLID_ELEMENT> *Wall_mesh_pt;
AlgebraicRefineableQuarterCircleSectorMesh<FLUID_ELEMENT> *Fluid_mesh_pt;
GeomObject* Undef_geom_pt;
Newmark<2>* Wall_time_stepper_pt;
BDF<2>* Fluid_time_stepper_pt;
Node* Veloc_trace_node_pt;
double Eps_ampl;
double Pcos_initial;
double Pcos_duration;
};
{
cout << "Setting wall ic" << std::endl;
set_wall_initial_condition();
cout << "Setting fluid ic" << std::endl;
set_fluid_initial_condition();
}
{
Fluid_mesh_pt->node_update();
unsigned n_node = Fluid_mesh_pt->nnode();
for(unsigned n=0;n<n_node;n++)
{
for(unsigned i=0;i<2;i++)
{
Fluid_mesh_pt->node_pt(n)->set_value(i,0.0);
}
}
Fluid_mesh_pt->assign_initial_values_impulsive();
}
{
GeomObject* ic_geom_object_pt=
Wall_time_stepper_pt);
static_cast<PseudoBucklingRing*>(ic_geom_object_pt)->set_T(1.0);
double time=0.25;
static_cast<PseudoBucklingRing*>(ic_geom_object_pt)->set_R_0(1.00);
SolidInitialCondition* IC_pt = new SolidInitialCondition(ic_geom_object_pt);
SolidMesh::Solid_IC_problem.set_static_initial_condition(
this,Wall_mesh_pt,IC_pt,time);
}
DocInfo& doc_info, ofstream& trace_file)
{
unsigned nskip=1;
if (i%nskip==0)
{
doc_info.enable_doc();
cout << "Full doc step " << doc_info.number()
<< " for time " << time_stepper_pt()->time_pt()->time() << std::endl;
}
else
{
doc_info.disable_doc();
cout << "Only trace for time "
<< time_stepper_pt()->time_pt()->time() << std::endl;
}
if (doc_info.is_doc_enabled())
{
ofstream some_file; char filename[100];
sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
doc_info.number());
some_file.open(filename);
Fluid_mesh_pt->output(some_file,5);
some_file.close();
}
Vector<double> s(1,1.0);
trace_file << time_pt()->time()
<< " " << Doc_displacement_elem_pt->interpolated_x(s,1)
<< " " << Veloc_trace_node_pt->x(0)
<< " " << Veloc_trace_node_pt->x(1)
<< " " << Veloc_trace_node_pt->value(0)
<< " " << Veloc_trace_node_pt->value(1)
<< " " << Fluid_mesh_pt->nelement()
<< " " << ndof()
<< " " << Fluid_mesh_pt->nrefinement_overruled()
<< " " << Fluid_mesh_pt->max_error()
<< " " << Fluid_mesh_pt->min_error()
<< " " << Fluid_mesh_pt->max_permitted_error()
<< " " << Fluid_mesh_pt->min_permitted_error()
<< " " << Fluid_mesh_pt->max_keep_unrefined();
if (doc_info.is_doc_enabled())
{trace_file << " " <<doc_info.number() << " ";}
else {trace_file << " " <<-1 << " ";}
trace_file << std::endl;
if (doc_info.is_doc_enabled()) {doc_info.number()++;}
}
const double& eps_ampl, const double& pcos_initial,
const double& pcos_duration) :
Eps_ampl(eps_ampl), Pcos_initial(pcos_initial),
Pcos_duration(pcos_duration)
{
Wall_time_stepper_pt = new Newmark<2>;
add_time_stepper_pt(Wall_time_stepper_pt);
Fluid_time_stepper_pt = new BDF<2>;
add_time_stepper_pt(Fluid_time_stepper_pt);
Undef_geom_pt = new Ellipse(1.0,1.0);
double L = 2.0*atan(1.0);
Wall_mesh_pt = new
OneDLagrangianMesh<SOLID_ELEMENT>(
N,L,Undef_geom_pt,Wall_time_stepper_pt);
Wall_mesh_pt->boundary_node_pt(0,0)->pin_position(1);
Wall_mesh_pt->boundary_node_pt(0,0)->pin_position(1,0);
Wall_mesh_pt->boundary_node_pt(1,0)->pin_position(0);
Wall_mesh_pt->boundary_node_pt(1,0)->pin_position(1,1);
double xi_lo=0.0;
double xi_hi=L;
double fract_mid=0.5;
MeshAsGeomObject *wall_mesh_as_geometric_object_pt
= new MeshAsGeomObject(Wall_mesh_pt);
Fluid_mesh_pt = new AlgebraicRefineableQuarterCircleSectorMesh<FLUID_ELEMENT >
(wall_mesh_as_geometric_object_pt,
xi_lo,fract_mid,xi_hi,Fluid_time_stepper_pt);
Z2ErrorEstimator* error_estimator_pt=new Z2ErrorEstimator;
Fluid_mesh_pt->spatial_error_estimator_pt()=error_estimator_pt;
unsigned nnode=Fluid_mesh_pt->finite_element_pt(0)->nnode();
Veloc_trace_node_pt=Fluid_mesh_pt->finite_element_pt(0)->node_pt(nnode-1);
{
unsigned n_node = Fluid_mesh_pt->nboundary_node(0);
for (unsigned n=0;n<n_node;n++)
{
Fluid_mesh_pt->boundary_node_pt(0,n)->pin(1);
}
}
{
unsigned n_node = Fluid_mesh_pt->nboundary_node(1);
for (unsigned n=0;n<n_node;n++)
{
Node* node_pt=Fluid_mesh_pt->boundary_node_pt(1,n);
node_pt->set_auxiliary_node_update_fct_pt(
FSI_functions::apply_no_slip_on_moving_wall);
for(unsigned i=0;i<2;i++) {node_pt->pin(i);}
}
}
{
unsigned n_node = Fluid_mesh_pt->nboundary_node(2);
for (unsigned n=0;n<n_node;n++)
{
Fluid_mesh_pt->boundary_node_pt(2,n)->pin(0);
}
}
add_sub_mesh(Wall_mesh_pt);
add_sub_mesh(Fluid_mesh_pt);
build_global_mesh();
unsigned n_element = Fluid_mesh_pt->nelement();
for(unsigned e=0;e<n_element;e++)
{
FLUID_ELEMENT *el_pt
= dynamic_cast<FLUID_ELEMENT*>(Fluid_mesh_pt->element_pt(e));
el_pt->evaluate_shape_derivs_by_direct_fd();
}
unsigned n_wall_element = Wall_mesh_pt->nelement();
for(unsigned e=0;e<n_wall_element;e++)
{
SOLID_ELEMENT *el_pt = dynamic_cast<SOLID_ELEMENT*>(
Wall_mesh_pt->element_pt(e));
el_pt->undeformed_beam_pt() = Undef_geom_pt;
}
Doc_displacement_elem_pt = dynamic_cast<SOLID_ELEMENT*>(
Wall_mesh_pt->element_pt(n_wall_element-1));
FSI_functions::setup_fluid_load_info_for_solid_elements<FLUID_ELEMENT,2>
(this,1,Fluid_mesh_pt,Wall_mesh_pt);
cout << "# of dofs " << assign_eqn_numbers() << std::endl;
}
{
DocInfo doc_info;
doc_info.set_directory("RESLT");
doc_info.number()=0;
ofstream trace_file("RESLT/trace_ring.dat");
trace_file << "VARIABLES=\"time\",\"V_c_t_r_l\"";
trace_file << ",\"x<sub>1</sub><sup>(track)</sup>\"";
trace_file << ",\"x<sub>2</sub><sup>(track)</sup>\"";
trace_file << ",\"u<sub>1</sub><sup>(track)</sup>\"";
trace_file << ",\"u<sub>2</sub><sup>(track)</sup>\"";
trace_file << ",\"N<sub>element</sub>\"";
trace_file << ",\"N<sub>dof</sub>\"";
trace_file << ",\"# of under-refined elements\"";
trace_file << ",\"max. error\"";
trace_file << ",\"min. error\"";
trace_file << ",\"max. permitted error\"";
trace_file << ",\"min. permitted error\"";
trace_file << ",\"max. permitted # of unrefined elements\"";
trace_file << ",\"doc number\"";
trace_file << std::endl;
unsigned nstep=300;
if (CommandLineArgs::Argc>1)
{
nstep=1;
cout << "Only doing nstep steps for validation: " << nstep << std::endl;
}
double dt=0.004;
initialise_dt(dt);
refine_uniformly();
refine_uniformly();
bool first=true;
for(unsigned i=1;i<=nstep;i++)
{
doc_info.disable_doc();
unsigned max_adapt=1;
unsteady_newton_solve(dt,max_adapt,first);
first=false;
}
}
int main(
int argc,
char* argv[])
{
CommandLineArgs::setup(argc,argv);
unsigned nelem = 13;
double pcos_initial=1.0e-6;
double pcos_duration=0.3;
double eps_ampl=0.0;
problem.dynamic_run();
}
FSI Ring problem: a fluid-structure interaction problem in which a viscous fluid bounded by an initia...
double Pcos_initial
Initial pcos.
void set_initial_condition()
Setup initial condition for both domains.
AlgebraicRefineableQuarterCircleSectorMesh< FLUID_ELEMENT > * Fluid_mesh_pt
Pointer to fluid mesh.
void set_wall_initial_condition()
Setup initial condition for wall.
void doc_solution(const unsigned &i, DocInfo &doc_info, ofstream &trace_file)
Doc solution: Pass number of timestep, i (we append to tracefile after every timestep but do a full d...
FSIRingProblem(const unsigned &nelement_wall, const double &eps_ampl, const double &pcos_initial, const double &pcos_duration)
Constructor: Number of elements in wall mesh, amplitude of the initial wall deformation,...
double Pcos_duration
Duration of initial pcos.
void dynamic_run()
Do dynamic run.
void set_fluid_initial_condition()
Setup initial condition for fluid.
int main(int argc, char *argv[])
Driver for fsi ring test problem.
Namespace for physical parameters.
double Pext
External Pressure.
double Alpha_sq
Square of Womersly number (a frequency parameter)
double ReSt
Reynolds x Strouhal number.
void set_params()
Set the parameters that are used in the code as a function of the Womersley number,...
double Lambda_sq
Timescale ratio (non-dimensation density)
void pcos_load(const Vector< double > &xi, const Vector< double > &x, const Vector< double > &N, Vector< double > &load)
Non-FSI load function, a constant external pressure plus a (small) sinusoidal perturbation of wavenum...
double Pcos
Perturbation pressure.
double Re
Reynolds number.
double Density_ratio
Density ratio of the solid and the fluid.
double H
Nondimensional thickness of the beam.