1 #include "channel_flow.h" 2 #include <deal.II/dofs/dof_tools.h> 3 #include <deal.II/fe/fe_values.h> 5 #include <deal.II/base/quadrature_lib.h> 6 #include <deal.II/grid/grid_generator.h> 7 #include <deal.II/grid/grid_tools.h> 9 #include "physics/physics_factory.h" 13 namespace FlowSolver {
18 template <
int dim,
int nspecies,
int nstate>
21 , channel_height(this->all_param.flow_solver_param.turbulent_channel_domain_length_y_direction)
22 , half_channel_height(channel_height/2.0)
23 , channel_friction_velocity_reynolds_number(this->all_param.flow_solver_param.turbulent_channel_friction_velocity_reynolds_number)
24 , number_of_cells_x_direction(this->all_param.flow_solver_param.turbulent_channel_number_of_cells_x_direction)
25 , number_of_cells_y_direction(this->all_param.flow_solver_param.turbulent_channel_number_of_cells_y_direction)
26 , number_of_cells_z_direction(this->all_param.flow_solver_param.turbulent_channel_number_of_cells_z_direction)
27 , pi_val(3.141592653589793238)
28 , domain_length_x(this->all_param.flow_solver_param.turbulent_channel_domain_length_x_direction)
29 , domain_length_y(channel_height)
30 , domain_length_z(this->all_param.flow_solver_param.turbulent_channel_domain_length_z_direction)
31 , domain_volume(domain_length_x*domain_length_y*domain_length_z)
32 , channel_bulk_velocity_reynolds_number(pow(0.073, -4.0/7.0)*pow(2.0, 5.0/7.0)*pow(channel_friction_velocity_reynolds_number, 8.0/7.0))
33 , channel_centerline_velocity_reynolds_number(1.28*pow(2.0, -0.0116)*pow(channel_bulk_velocity_reynolds_number,1.0-0.0116))
36 for (
int d1=0; d1<dim; ++d1) {
37 for (
int d2=0; d2<dim; ++d2) {
45 parameters_navier_stokes_channel_flow_constant_source_term_wall_model.
pde_type = PDE_enum::navier_stokes_channel_flow_constant_source_term_wall_model;
51 template <
int dim,
int nspecies,
int nstate>
55 const std::shared_ptr <dealii::TableHandler> unsteady_data_table,
56 const bool do_write_unsteady_data_table_file)
59 const unsigned int current_iteration = ode_solver->current_iteration;
60 const double current_time = ode_solver->current_time;
64 double average_wall_shear_stress = 0.0;
79 if(do_write_unsteady_data_table_file) {
81 unsteady_data_table->write_text(unsteady_data_table_file);
86 this->
pcout <<
" Iter: " << current_iteration
87 <<
" Time: " << current_time
88 <<
" Cf: " << skin_friction_coefficient
96 if(std::isnan(average_wall_shear_stress)) {
97 this->
pcout <<
" ERROR: Wall shear stress at time " << current_time <<
" is nan." << std::endl;
98 this->
pcout <<
" Consider decreasing the time step / CFL number." << std::endl;
106 template <
int dim,
int nspecies,
int nstate>
122 template <
int dim,
int nspecies,
int nstate>
125 const std::string grid_type_string =
"subdivided_hyper_rectangle_for_channel_flow";
127 this->
pcout <<
"- Grid type: " << grid_type_string << std::endl;
129 this->
pcout <<
"- - Domain dimensionality: " << dim << std::endl;
138 std::string turbulent_channel_mesh_stretching_function_type_string;
139 if(turbulent_channel_mesh_stretching_function_type == turbulent_channel_mesh_stretching_function_enum::gullbrand){
140 turbulent_channel_mesh_stretching_function_type_string =
"Gullbrand";
141 }
else if(turbulent_channel_mesh_stretching_function_type == turbulent_channel_mesh_stretching_function_enum::hopw){
142 turbulent_channel_mesh_stretching_function_type_string =
"HOPW";
143 }
else if(turbulent_channel_mesh_stretching_function_type == turbulent_channel_mesh_stretching_function_enum::carton_de_wiart_et_al){
144 turbulent_channel_mesh_stretching_function_type_string =
"carton_de_wiart_et_al";
145 }
else if(turbulent_channel_mesh_stretching_function_type == turbulent_channel_mesh_stretching_function_enum::uniform_mesh_no_stretching){
146 turbulent_channel_mesh_stretching_function_type_string =
"uniform_mesh_no_stretching";
148 this->
pcout <<
"- - Mesh stretching function: " << turbulent_channel_mesh_stretching_function_type_string << std::endl;
151 template <
int dim,
int nspecies,
int nstate>
160 template <
int dim,
int nspecies,
int nstate>
173 template <
int dim,
int nspecies,
int nstate>
178 std::vector<double> step_size_y_direction;
179 if(turbulent_channel_mesh_stretching_function_type == turbulent_channel_mesh_stretching_function_enum::gullbrand){
181 }
else if(turbulent_channel_mesh_stretching_function_type == turbulent_channel_mesh_stretching_function_enum::hopw){
183 }
else if(turbulent_channel_mesh_stretching_function_type == turbulent_channel_mesh_stretching_function_enum::carton_de_wiart_et_al){
185 }
else if(turbulent_channel_mesh_stretching_function_type == turbulent_channel_mesh_stretching_function_enum::uniform_mesh_no_stretching){
189 step_size_y_direction.push_back(uniform_spacing_y);
192 this->
pcout <<
"ERROR: Invalid turbulent_channel_mesh_stretching_function_type. Aborting..." << std::endl;
195 return step_size_y_direction;
198 template <
int dim,
int nspecies,
int nstate>
202 std::vector<double> element_edges_y_direction(number_of_edges_y_direction);
204 const double N_streching_param = 1.0;
205 const double r_streching_param = pow(1.2,N_streching_param/2.0);
207 const double h0_streching_param = 0.5*(1.0-r_streching_param)/(1.0-pow(r_streching_param,(num_cells_y/2.0)));
208 const int max_loop_index = (int)((num_cells_y-2.0)/2.0);
209 double h_streching_param = 0.0;
210 element_edges_y_direction[0] = h_streching_param;
211 for (
int i=0; i<max_loop_index; i++) {
212 h_streching_param += h0_streching_param*pow(r_streching_param,(
double)i);
213 element_edges_y_direction[i+1] = h_streching_param;
216 element_edges_y_direction[(int)(num_cells_y/2.0)] = 0.5;
219 for (
int j=0; j<number_of_edges_y_direction; j++) {
225 step_size_y_direction[j] = element_edges_y_direction[j+1] - element_edges_y_direction[j];
227 return step_size_y_direction;
230 template <
int dim,
int nspecies,
int nstate>
234 const double desired_domain_lower_bound_y = 0.0;
235 const double domain_shift = desired_domain_lower_bound_y+1.0;
238 std::vector<double> element_edges_y_direction(number_of_edges_y_direction);
243 const double stretching_parameter = 2.75;
244 const double tanh_stretching_parameter = tanh(stretching_parameter);
245 for (
int j=0; j<number_of_edges_y_direction; j++) {
246 element_edges_y_direction[j] = -1.0*tanh(stretching_parameter*(1.0 - 2.0*((
double)j)/num_cells_y))/tanh_stretching_parameter;
250 for (
int j=0; j<number_of_edges_y_direction; j++) {
251 element_edges_y_direction[j] += domain_shift;
252 element_edges_y_direction[j] /= 2.0;
258 step_size_y_direction[j] = element_edges_y_direction[j+1] - element_edges_y_direction[j];
260 return step_size_y_direction;
263 template <
int dim,
int nspecies,
int nstate>
268 std::vector<double> element_edges_y_direction(number_of_edges_y_direction);
275 element_edges_y_direction[j] = 1.0 - cos(this->
pi_val*((
double)j)*uniform_spacing/2.0);
281 step_size_y_direction[j] = element_edges_y_direction[j+1] - element_edges_y_direction[j];
283 return step_size_y_direction;
286 template <
int dim,
int nspecies,
int nstate>
309 std::vector<std::vector<double> > step_sizes(dim);
312 step_sizes[0].push_back(uniform_spacing_x);
316 step_sizes[1].push_back(step_size_y_direction[j]);
320 step_sizes[2].push_back(uniform_spacing_z);
324 std::shared_ptr<Triangulation> grid = std::make_shared<Triangulation> (this->
mpi_communicator);
325 const bool colorize =
true;
326 dealii::GridGenerator::subdivided_hyper_rectangle(*grid, step_sizes, p1, p2, colorize);
329 std::vector<dealii::GridTools::PeriodicFacePair<typename dealii::Triangulation<dim>::cell_iterator> > matched_pairs;
330 dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs);
331 dealii::GridTools::collect_periodic_faces(*grid,4,5,2,matched_pairs);
332 grid->add_periodicity(matched_pairs);
335 for (
typename Triangulation::active_cell_iterator cell = grid->begin_active(); cell != grid->end(); ++cell) {
336 if (!cell->is_locally_owned())
continue;
338 for (
unsigned int face=0; face<dealii::GeometryInfo<dim>::faces_per_cell; ++face) {
339 if (cell->face(face)->at_boundary()) {
340 unsigned int current_id = cell->face(face)->boundary_id();
341 if (current_id == 2 || current_id == 3) cell->face(face)->set_boundary_id (1001);
349 template <
int dim,
int nspecies,
int nstate>
362 template <
int dim,
int nspecies,
int nstate>
369 return number_of_degrees_of_freedom_per_state;
372 template<
int dim,
int nspecies,
int nstate>
376 const dealii::UpdateFlags face_update_flags = dealii::update_values | dealii::update_gradients | dealii::update_quadrature_points | dealii::update_JxW_values | dealii::update_normal_vectors;
377 double integral_value = 0.0;
378 double integral_area_value = 0.0;
381 int overintegrate = 10;
382 dealii::QGauss<dim-1> quad_extra(dg.
max_degree+1+overintegrate);
387 std::array<double,nstate> soln_at_q;
388 std::array<dealii::Tensor<1,dim,double>,nstate> soln_grad_at_q;
390 std::vector<dealii::types::global_dof_index> dofs_indices (fe_face_values_extra.dofs_per_cell);
391 for (
auto cell : dg.
dof_handler.active_cell_iterators()) {
392 if (!cell->is_locally_owned())
continue;
394 cell->get_dof_indices (dofs_indices);
396 for(
unsigned int iface = 0; iface < dealii::GeometryInfo<dim>::faces_per_cell; ++iface){
397 auto face = cell->face(iface);
399 if(face->at_boundary()){
400 const unsigned int boundary_id = face->boundary_id();
401 if(boundary_id==1001){
402 fe_face_values_extra.reinit (cell,iface);
403 const unsigned int n_quad_pts = fe_face_values_extra.n_quadrature_points;
404 for (
unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
405 std::fill(soln_at_q.begin(), soln_at_q.end(), 0.0);
406 for (
int s=0; s<nstate; ++s) {
407 for (
int d=0; d<dim; ++d) {
408 soln_grad_at_q[s][d] = 0.0;
411 for (
unsigned int idof=0; idof<fe_face_values_extra.dofs_per_cell; ++idof) {
412 const unsigned int istate = fe_face_values_extra.get_fe().system_to_component_index(idof).first;
413 soln_at_q[istate] += dg.
solution[dofs_indices[idof]] * fe_face_values_extra.shape_value_component(idof, iquad, istate);
414 soln_grad_at_q[istate] += dg.
solution[dofs_indices[idof]] * fe_face_values_extra.shape_grad_component(idof,iquad,istate);
417 const dealii::Tensor<1,dim,double> normal_vector = -fe_face_values_extra.normal_vector(iquad);
418 const double integrand_value = this->
navier_stokes_physics->compute_wall_shear_stress(soln_at_q,soln_grad_at_q,normal_vector);
419 integral_value += integrand_value * fe_face_values_extra.JxW(iquad);
420 integral_area_value += fe_face_values_extra.JxW(iquad);
426 const double mpi_sum_integral_value = dealii::Utilities::MPI::sum(integral_value, this->
mpi_communicator);
427 const double mpi_sum_integral_area_value = dealii::Utilities::MPI::sum(integral_area_value, this->
mpi_communicator);
428 const double averaged_value = mpi_sum_integral_value/mpi_sum_integral_area_value;
429 return averaged_value;
432 template<
int dim,
int nspecies,
int nstate>
436 const dealii::UpdateFlags face_update_flags = dealii::update_values | dealii::update_quadrature_points | dealii::update_JxW_values | dealii::update_normal_vectors;
437 double integral_value = 0.0;
438 double integral_area_value = 0.0;
441 int overintegrate = 10;
442 dealii::QGauss<dim-1> quad_extra(dg.
max_degree+1+overintegrate);
447 std::array<double,nstate> soln_at_q;
450 std::vector<dealii::types::global_dof_index> dofs_indices (fe_face_values_extra.dofs_per_cell);
451 for (
auto cell : dg.
dof_handler.active_cell_iterators()) {
452 if (!cell->is_locally_owned())
continue;
454 cell->get_dof_indices (dofs_indices);
456 for(
unsigned int iface = 0; iface < dealii::GeometryInfo<dim>::faces_per_cell; ++iface){
457 auto face = cell->face(iface);
459 if(face->at_boundary()){
460 const unsigned int boundary_id = face->boundary_id();
461 if(boundary_id==1001){
464 const int opposite_iface = (iface == 0) ? 1 : (
469 (iface == 5) ? 4 : -1)))));
470 if(opposite_iface == -1) {
471 this->
pcout <<
"ERROR: Invalid iface, opposite_iface is -1. Aborting..."<<std::endl;
475 fe_face_values_extra.reinit (cell,opposite_iface);
476 const unsigned int n_quad_pts = fe_face_values_extra.n_quadrature_points;
477 for (
unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
478 std::fill(soln_at_q.begin(), soln_at_q.end(), 0.0);
484 for (
unsigned int idof=0; idof<fe_face_values_extra.dofs_per_cell; ++idof) {
485 const unsigned int istate = fe_face_values_extra.get_fe().system_to_component_index(idof).first;
486 soln_at_q[istate] += dg.
solution[dofs_indices[idof]] * fe_face_values_extra.shape_value_component(idof, iquad, istate);
493 const double density = soln_at_q[0];
502 const dealii::Tensor<1,dim,double> normal = -fe_face_values_extra.normal_vector(iquad);
506 const double velocity_parallel_to_wall =
509 const double wall_shear_stress_magnitude =
511 velocity_parallel_to_wall,
513 viscosity_coefficient,
515 reynolds_number_inf);
517 const double integrand_value = wall_shear_stress_magnitude;
518 integral_value += integrand_value * fe_face_values_extra.JxW(iquad);
519 integral_area_value += fe_face_values_extra.JxW(iquad);
525 const double mpi_sum_integral_value = dealii::Utilities::MPI::sum(integral_value, this->
mpi_communicator);
526 const double mpi_sum_integral_area_value = dealii::Utilities::MPI::sum(integral_area_value, this->
mpi_communicator);
527 const double averaged_value = mpi_sum_integral_value/mpi_sum_integral_area_value;
528 return averaged_value;
531 template <
int dim,
int nspecies,
int nstate>
536 return skin_friction_coefficient;
539 template <
int dim,
int nspecies,
int nstate>
545 template <
int dim,
int nspecies,
int nstate>
551 template <
int dim,
int nspecies,
int nstate>
557 template <
int dim,
int nspecies,
int nstate>
567 std::array<double,NUMBER_OF_INTEGRATED_QUANTITIES> integral_values;
568 std::fill(integral_values.begin(), integral_values.end(), 0.0);
571 int overintegrate = 10;
572 dealii::QGauss<dim> quad_extra(dg.
max_degree+1+overintegrate);
574 dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
576 const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
577 std::array<double,nstate> soln_at_q;
580 std::vector<dealii::types::global_dof_index> dofs_indices (fe_values_extra.dofs_per_cell);
581 for (
auto cell : dg.
dof_handler.active_cell_iterators()) {
582 if (!cell->is_locally_owned())
continue;
583 fe_values_extra.reinit (cell);
584 cell->get_dof_indices (dofs_indices);
587 for (
unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
589 std::fill(soln_at_q.begin(), soln_at_q.end(), 0.0);
595 for (
unsigned int idof=0; idof<fe_values_extra.dofs_per_cell; ++idof) {
596 const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
597 soln_at_q[istate] += dg.
solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
602 std::array<double,NUMBER_OF_INTEGRATED_QUANTITIES> integrand_values;
603 std::fill(integrand_values.begin(), integrand_values.end(), 0.0);
604 integrand_values[IntegratedQuantitiesEnum::bulk_density] = soln_at_q[0];
605 integrand_values[IntegratedQuantitiesEnum::bulk_mass_flow_rate] = soln_at_q[1];
610 integral_values[i_quantity] += integrand_values[i_quantity] * fe_values_extra.JxW(iquad);
620 integrated_quantities[i_quantity] = dealii::Utilities::MPI::sum(integral_values[i_quantity], this->
mpi_communicator);
624 this->
bulk_density = integrated_quantities[IntegratedQuantitiesEnum::bulk_density];
625 this->bulk_mass_flow_rate = integrated_quantities[IntegratedQuantitiesEnum::bulk_mass_flow_rate];
void update_maximum_local_wave_speed(DGBase< dim, nspecies, double > &dg) override
Updates the maximum local wave speed.
double get_adaptive_time_step_initial(std::shared_ptr< DGBase< dim, nspecies, double >> dg) override
Function to compute the initial adaptive time step.
const double half_channel_height
Half channel height.
PartialDifferentialEquation pde_type
Store the PDE type to be solved.
double bulk_density
Bulk density.
const Parameters::AllParameters all_param
All parameters.
double courant_friedrichs_lewy_number
Courant-Friedrichs-Lewy (CFL) number for constant time step.
bool adaptive_time_step
Flag for computing the time step on the fly.
FlowSolverParam flow_solver_param
Contains the parameters for simulation cases (flow solver test)
const double channel_bulk_velocity_reynolds_number
double get_skin_friction_coefficient_from_average_wall_shear_stress(const double avg_wall_shear_stress) const
Get the skin friction coefficient from the average wall shear stress.
double get_bulk_velocity() const
Getter for the bulk velocity.
unsigned int grid_degree
Parameters related to mesh generation.
double constant_time_step
Constant time step.
TurbulentChannelMeshStretchingFunctionType
For turbulent channel flow, selects the type of mesh stretching function.
double mach_inf
Mach number at infinity.
const double domain_length_x
Domain length in x-direction.
std::shared_ptr< Physics::NavierStokes_ChannelFlowConstantSourceTerm_WallModel< dim, nspecies, dim+2, double > > navier_stokes_channel_flow_constant_source_term_wall_model_physics
Pointer to Navier-Stokes physics object for computing things on the fly.
std::shared_ptr< Triangulation > generate_grid() const override
Function to generate the grid.
PartialDifferentialEquation
Possible Partial Differential Equations to solve.
const double domain_length_y
Domain length in y-direction.
Files for the baseline physics.
const double pi_val
Value of pi.
std::array< double, NUMBER_OF_INTEGRATED_QUANTITIES > integrated_quantities
Array for storing the integrated quantities; done for computational efficiency.
std::shared_ptr< Physics::NavierStokes< dim, nspecies, dim+2, double > > navier_stokes_physics
Pointer to Navier-Stokes physics object for computing things on the fly.
double get_average_wall_shear_stress_from_wall_model(DGBase< dim, nspecies, double > &dg) const
Get the average wall shear stress from wall model.
ChannelFlow(const Parameters::AllParameters *const parameters_input)
Constructor.
std::shared_ptr< HighOrderGrid< dim, real, MeshType > > high_order_grid
High order grid that will provide the MappingFEField.
unsigned int get_number_of_degrees_of_freedom_per_state_from_poly_degree(const unsigned int poly_degree_input) const override
Get the number of degrees of freedom per state from a given poly degree.
double reynolds_number_inf
Farfield Reynolds number.
void display_grid_parameters() const override
Display grid parameters.
EulerParam euler_param
Contains parameters for the Euler equations non-dimensionalization.
double bulk_velocity
Bulk velocity.
double get_adaptive_time_step(std::shared_ptr< DGBase< dim, nspecies, double >> dg) const override
Function to compute the adaptive time step.
unsigned int poly_degree
Polynomial order (P) of the basis functions for DG.
Main parameter class that contains the various other sub-parameter classes.
dealii::DoFHandler< dim > dof_handler
Finite Element Collection to represent the high-order grid.
const double domain_length_z
Domain length in z-direction.
const std::string unsteady_data_table_filename_with_extension
Filename (with extension) for the unsteady data table.
NavierStokesParam navier_stokes_param
Contains parameters for the Navier-Stokes equations non-dimensionalization.
const double domain_volume
Domain volume.
const int number_of_cells_y_direction
Number of cells in y-direction.
double get_bulk_mass_flow_rate() const
Getter for the bulk mass flow rate.
double get_bulk_density() const
Getter for the bulk density.
const int number_of_cells_z_direction
Number of cells in z-direction.
double time_step
Current time step.
dealii::LinearAlgebra::distributed::Vector< double > solution
Current modal coefficients of the solution.
dealii::Tensor< 2, dim, double > zero_tensor
Tensor of zeros.
std::vector< double > get_mesh_step_size_y_direction_HOPW() const
const int number_of_cells_x_direction
Number of cells in x-direction.
TurbulentChannelMeshStretchingFunctionType turbulent_channel_mesh_stretching_function_type
Selected DensityInitialConditionType from the input file.
Navier-Stokes equations with constant physical source term for the turbulent channel flow case and wa...
const unsigned int max_degree
Maximum degree used for p-refi1nement.
static std::shared_ptr< PhysicsBase< dim, nspecies, nstate, real > > create_Physics(const Parameters::AllParameters *const parameters_input, std::shared_ptr< ModelBase< dim, nspecies, nstate, real > > model_input=nullptr)
Factory to return the correct physics given input file.
void output_velocity_field_if_current_time_is_output_time(const double current_time, const std::shared_ptr< DGBase< dim, nspecies, double >> dg)
Outputs the velocity field if the current time is an output time for the velocity field...
const MPI_Comm mpi_communicator
MPI communicator.
IntegratedQuantitiesEnum
List of possible integrated quantities over the domain.
double get_average_wall_shear_stress(DGBase< dim, nspecies, double > &dg) const
Get the average wall shear stress.
dealii::ConditionalOStream pcout
ConditionalOStream.
static const int NUMBER_OF_INTEGRATED_QUANTITIES
double minimum_approximate_grid_spacing
Minimum approximate grid spacing.
void set_bulk_flow_quantities(DGBase< dim, nspecies, double > &dg)
Set the bulk flow quantities.
std::vector< double > get_mesh_step_size_y_direction_Gullbrand() const
void add_value_to_data_table(const double value, const std::string value_string, const std::shared_ptr< dealii::TableHandler > data_table) const
Add a value to a given data table with scientific format.
std::vector< double > get_mesh_step_size_y_direction_carton_de_wiart_et_al() const
void set_higher_order_grid(std::shared_ptr< DGBase< dim, nspecies, double >> dg) const override
Function to set the higher order grid.
const dealii::hp::FECollection< dim > fe_collection
Finite Element Collection for p-finite-element to represent the solution.
const double channel_friction_velocity_reynolds_number
Channel Reynolds number based on wall friction velocity.
DGBase is independent of the number of state variables.
std::vector< double > get_mesh_step_size_y_direction() const
Return a vector of mesh step sizes in the y-direction based on the desired stretching function...
void display_additional_flow_case_specific_parameters() const override
Display additional more specific flow case parameters.
double bulk_mass_flow_rate
Bulk mass flow rate.
const int mpi_rank
MPI rank.
void compute_unsteady_data_and_write_to_table(const std::shared_ptr< ODE::ODESolverBase< dim, nspecies, double >> ode_solver, const std::shared_ptr< DGBase< dim, nspecies, double >> dg, const std::shared_ptr< dealii::TableHandler > unsteady_data_table, const bool do_write_unsteady_data_table_file) override
Compute the desired unsteady data and write it to a table.
const double channel_centerline_velocity_reynolds_number
bool using_wall_model
Flag for using wall model (initialized as false)