194 * We declare
class that describes the boundary conditions and
initial one for velocity:
201 * class Velocity:
public Function<dim> {
203 * Velocity(
const double initial_time = 0.0);
206 *
const unsigned int component = 0)
const override;
214 * Velocity<dim>::Velocity(
const double initial_time):
Function<dim>(dim, initial_time) {}
218 *
double Velocity<dim>::value(
const Point<dim>& p,
const unsigned int component)
const {
220 *
if(component == 0) {
221 *
const double Um = 1.5;
222 *
const double H = 4.1;
224 *
return 4.0*Um*p(1)*(H - p(1))/(H*H);
235 *
for(
unsigned int i = 0; i < dim; ++i)
242 * We
do the same
for the pressure
249 *
class Pressure:
public Function<dim> {
251 * Pressure(
const double initial_time = 0.0);
254 *
const unsigned int component = 0)
const override;
259 * Pressure<dim>::Pressure(
const double initial_time):
Function<dim>(1, initial_time) {}
263 *
double Pressure<dim>::value(
const Point<dim>& p,
const unsigned int component)
const {
267 *
return 22.0 - p(0);
274<a name=
"ann-navier_stokes_TRBDF2_DG.cc"></a>
275<h1>Annotated version of navier_stokes_TRBDF2_DG.cc</h1>
285 * We start by including all the necessary deal.II header files and some
C++
292 * #include <deal.II/base/quadrature_lib.h>
293 * #include <deal.II/base/multithread_info.h>
294 * #include <deal.II/base/thread_management.h>
295 * #include <deal.II/base/work_stream.h>
296 * #include <deal.II/base/
parallel.h>
297 * #include <deal.II/base/utilities.h>
298 * #include <deal.II/base/conditional_ostream.h>
300 * #include <deal.II/lac/vector.h>
301 * #include <deal.II/lac/solver_cg.h>
302 * #include <deal.II/lac/precondition.h>
303 * #include <deal.II/lac/solver_gmres.h>
304 * #include <deal.II/lac/affine_constraints.h>
306 * #include <deal.II/grid/
tria.h>
307 * #include <deal.II/grid/grid_generator.h>
308 * #include <deal.II/grid/grid_tools.h>
309 * #include <deal.II/grid/grid_refinement.h>
310 * #include <deal.II/grid/tria_accessor.h>
311 * #include <deal.II/grid/tria_iterator.h>
312 * #include <deal.II/distributed/grid_refinement.h>
314 * #include <deal.II/dofs/dof_handler.h>
315 * #include <deal.II/dofs/dof_accessor.h>
316 * #include <deal.II/dofs/dof_tools.h>
318 * #include <deal.II/fe/fe_q.h>
319 * #include <deal.II/fe/fe_dgq.h>
320 * #include <deal.II/fe/fe_values.h>
321 * #include <deal.II/fe/fe_tools.h>
322 * #include <deal.II/fe/fe_system.h>
324 * #include <deal.II/numerics/matrix_tools.h>
325 * #include <deal.II/numerics/vector_tools.h>
326 * #include <deal.II/numerics/data_out.h>
330 * #include <iostream>
332 * #include <deal.II/matrix_free/matrix_free.h>
333 * #include <deal.II/matrix_free/operators.h>
334 * #include <deal.II/matrix_free/fe_evaluation.h>
335 * #include <deal.II/fe/component_mask.h>
337 * #include <deal.II/base/timer.h>
338 * #include <deal.II/distributed/solution_transfer.h>
339 * #include <deal.II/numerics/error_estimator.h>
341 * #include <deal.II/multigrid/multigrid.h>
342 * #include <deal.II/multigrid/mg_transfer_matrix_free.h>
343 * #include <deal.II/multigrid/mg_tools.h>
344 * #include <deal.II/multigrid/mg_coarse.h>
345 * #include <deal.II/multigrid/mg_smoother.h>
346 * #include <deal.II/multigrid/mg_matrix.h>
348 * #include <deal.II/meshworker/
mesh_loop.h>
350 * #include
"runtime_parameters.h"
351 * #include
"equation_data.h"
355 * We include the code in a suitable
namespace:
361 *
namespace NS_TRBDF2 {
366 * The following
class is an auxiliary
one for post-processing of the vorticity
376 * std::vector<
Vector<double>>& computed_quantities)
const override;
378 *
virtual std::vector<std::string> get_names()
const override;
380 *
virtual std::vector<DataComponentInterpretation::DataComponentInterpretation>
381 * get_data_component_interpretation()
const override;
383 *
virtual UpdateFlags get_needed_update_flags()
const override;
388 * This function evaluates the vorticty in both 2D and 3D cases
397 *
const unsigned int n_quadrature_points = inputs.
solution_values.size();
414 *
for(
unsigned int q = 0; q < n_quadrature_points; ++q)
418 *
for(
unsigned int q = 0; q < n_quadrature_points; ++q) {
428 * This auxiliary function is required by the base
class DataProcessor and simply
429 * sets the name
for the output file
436 * std::vector<std::string> PostprocessorVorticity<dim>::get_names()
const {
437 * std::vector<std::string> names;
438 * names.emplace_back(
"vorticity");
440 * names.emplace_back(
"vorticity");
441 * names.emplace_back(
"vorticity");
449 * This auxiliary function is required by the base
class DataProcessor and simply
450 * specifies
if the vorticity is a
scalar (2D) or a vector (3D)
457 * std::vector<DataComponentInterpretation::DataComponentInterpretation>
458 * PostprocessorVorticity<dim>::get_data_component_interpretation()
const {
459 * std::vector<DataComponentInterpretation::DataComponentInterpretation> interpretation;
468 *
return interpretation;
473 * This auxiliary function is required by the base
class DataProcessor and simply
474 * sets which variables have to updated (only the
gradients)
481 *
UpdateFlags PostprocessorVorticity<dim>::get_needed_update_flags()
const {
488 * The following structs are auxiliary objects
for mesh refinement. ScratchData simply sets
496 *
struct ScratchData {
498 *
const unsigned int quadrature_degree,
499 *
const UpdateFlags update_flags): fe_values(fe,
QGauss<dim>(quadrature_degree), update_flags) {}
501 * ScratchData(
const ScratchData<dim>& scratch_data): fe_values(scratch_data.fe_values.get_fe(),
502 * scratch_data.fe_values.get_quadrature(),
503 * scratch_data.fe_values.get_update_flags()) {}
510 * CopyData simply sets the cell
index
519 * CopyData(
const CopyData &) =
default;
530 * @sect{ <code>NavierStokesProjectionOperator::NavierStokesProjectionOperator</code> }
534 * The following
class sets effecively the weak formulation of the problems for the different stages
535 * and
for both velocity and pressure.
536 * The
template parameters are the dimnesion of the problem, the polynomial degree
for the pressure,
537 * the polynomial degree
for the velocity, the number of quadrature points
for integrals
for the pressure step,
538 * the number of quadrature points
for integrals
for the velocity step, the type of vector
for storage and the type
539 * of floating
point data (in
general double or
float for preconditioners structures
if desired).
545 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
548 * NavierStokesProjectionOperator();
550 * NavierStokesProjectionOperator(RunTimeParameters::Data_Storage& data);
552 *
void set_dt(
const double time_step);
554 *
void set_TR_BDF2_stage(
const unsigned int stage);
556 *
void set_NS_stage(
const unsigned int stage);
558 *
void set_u_extr(
const Vec& src);
560 *
void vmult_rhs_velocity(Vec& dst,
const std::vector<Vec>& src)
const;
562 *
void vmult_rhs_pressure(Vec& dst,
const std::vector<Vec>& src)
const;
564 *
void vmult_grad_p_projection(Vec& dst,
const Vec& src)
const;
578 *
unsigned int TR_BDF2_stage;
579 *
unsigned int NS_stage;
582 *
virtual void apply_add(Vec& dst,
const Vec& src)
const override;
587 *
const double a21 = 0.5;
588 *
const double a22 = 0.5;
591 *
const double theta_v = 1.0;
592 *
const double theta_p = 1.0;
593 *
const double C_p = 1.0*(fe_degree_p + 1)*(fe_degree_p + 1);
594 *
const double C_u = 1.0*(fe_degree_v + 1)*(fe_degree_v + 1);
598 * EquationData::Velocity<dim> vel_boundary_inflow;
604 *
const std::vector<Vec>& src,
605 *
const std::pair<unsigned int, unsigned int>& cell_range)
const;
608 *
const std::vector<Vec>& src,
609 *
const std::pair<unsigned int, unsigned int>& face_range)
const;
612 *
const std::vector<Vec>& src,
613 *
const std::pair<unsigned int, unsigned int>& face_range)
const;
617 *
const std::vector<Vec>& src,
618 *
const std::pair<unsigned int, unsigned int>& cell_range)
const;
621 *
const std::vector<Vec>& src,
622 *
const std::pair<unsigned int, unsigned int>& face_range)
const;
625 *
const std::vector<Vec>& src,
626 *
const std::pair<unsigned int, unsigned int>& face_range)
const;
631 *
const std::pair<unsigned int, unsigned int>& cell_range)
const;
635 *
const std::pair<unsigned int, unsigned int>& face_range)
const;
639 *
const std::pair<unsigned int, unsigned int>& face_range)
const;
644 *
const std::pair<unsigned int, unsigned int>& cell_range)
const;
648 *
const std::pair<unsigned int, unsigned int>& face_range)
const;
652 *
const std::pair<unsigned int, unsigned int>& face_range)
const;
657 *
const std::pair<unsigned int, unsigned int>& cell_range)
const;
661 *
const std::pair<unsigned int, unsigned int>& cell_range)
const;
665 *
const unsigned int& src,
666 *
const std::pair<unsigned int, unsigned int>& cell_range)
const;
669 *
const unsigned int& src,
670 *
const std::pair<unsigned int, unsigned int>& face_range)
const;
673 *
const unsigned int& src,
674 *
const std::pair<unsigned int, unsigned int>& face_range)
const;
678 *
const unsigned int& src,
679 *
const std::pair<unsigned int, unsigned int>& cell_range)
const;
682 *
const unsigned int& src,
683 *
const std::pair<unsigned int, unsigned int>& face_range)
const;
686 *
const unsigned int& src,
687 *
const std::pair<unsigned int, unsigned int>& face_range)
const;
693 * We start with the
default constructor. It is important
for MultiGrid, so it is fundamental
694 * to properly
set the parameters of the time scheme.
700 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
701 * NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
702 * NavierStokesProjectionOperator():
704 * a32(a31), a33(1.0/(2.0 -
gamma)), TR_BDF2_stage(1), NS_stage(1), u_extr() {}
709 * We focus now on the constructor with runtime parameters storage
715 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
716 * NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
717 * NavierStokesProjectionOperator(RunTimeParameters::Data_Storage& data):
720 * a32(a31), a33(1.0/(2.0 -
gamma)), TR_BDF2_stage(1), NS_stage(1), u_extr(),
721 * vel_boundary_inflow(data.initial_time) {}
726 * Setter of time-step (called by
Multigrid and in
case a smaller time-step towards the
end is needed)
732 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
733 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
734 * set_dt(
const double time_step) {
741 * Setter of TR-BDF2 stage (
this can be known only during the effective execution
742 * and so it has to be demanded to the
class that really solves the problem)
748 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
749 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
750 * set_TR_BDF2_stage(
const unsigned int stage) {
754 * TR_BDF2_stage = stage;
760 * Setter of NS stage (
this can be known only during the effective execution
761 * and so it has to be demanded to the
class that really solves the problem)
767 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
768 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
769 * set_NS_stage(
const unsigned int stage) {
779 * Setter of extrapolated velocity
for different stages
785 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
786 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
787 * set_u_extr(
const Vec& src) {
789 * u_extr.update_ghost_values();
795 * We are in a DG-
MatrixFree framework, so it is convenient to compute separately cell contribution,
796 *
internal faces contributions and boundary faces contributions. We start by
797 * assembling the rhs cell term
for the velocity.
803 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
804 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
807 *
const std::vector<Vec>& src,
808 *
const std::pair<unsigned int, unsigned int>& cell_range)
const {
809 *
if(TR_BDF2_stage == 1) {
816 * phi_old_extr(data, 0);
820 *
for(
unsigned int cell = cell_range.first; cell < cell_range.second; ++cell) {
824 * phi_old.reinit(cell);
825 * phi_old.gather_evaluate(src[0],
true,
true);
828 * phi_old_extr.reinit(cell);
829 * phi_old_extr.gather_evaluate(src[1],
true,
false);
830 * phi_old_press.reinit(cell);
831 * phi_old_press.gather_evaluate(src[2],
true,
false);
835 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
836 *
const auto& u_n = phi_old.get_value(q);
837 *
const auto& grad_u_n = phi_old.get_gradient(q);
838 *
const auto& u_n_gamma_ov_2 = phi_old_extr.get_value(q);
839 *
const auto& tensor_product_u_n =
outer_product(u_n, u_n_gamma_ov_2);
840 *
const auto& p_n = phi_old_press.get_value(q);
841 *
auto p_n_times_identity = tensor_product_u_n;
842 * p_n_times_identity = 0;
843 *
for(
unsigned int d = 0;
d < dim; ++
d)
844 * p_n_times_identity[
d][
d] = p_n;
846 * phi.submit_value(1.0/(
gamma*dt)*u_n, q);
848 * phi.submit_gradient(-a21/Re*grad_u_n + a21*tensor_product_u_n + p_n_times_identity, q);
851 * phi.integrate_scatter(
true,
true, dst);
864 *
for(
unsigned int cell = cell_range.first; cell < cell_range.second; ++cell) {
865 * phi_old.reinit(cell);
866 * phi_old.gather_evaluate(src[0],
true,
true);
867 * phi_int.reinit(cell);
868 * phi_int.gather_evaluate(src[1],
true,
true);
869 * phi_old_press.reinit(cell);
870 * phi_old_press.gather_evaluate(src[2],
true,
false);
874 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
875 *
const auto& u_n = phi_old.get_value(q);
876 *
const auto& grad_u_n = phi_old.get_gradient(q);
877 *
const auto& u_n_gamma = phi_int.get_value(q);
878 *
const auto& grad_u_n_gamma = phi_int.get_gradient(q);
880 *
const auto& tensor_product_u_n_gamma =
outer_product(u_n_gamma, u_n_gamma);
881 *
const auto& p_n = phi_old_press.get_value(q);
882 *
auto p_n_times_identity = tensor_product_u_n;
883 * p_n_times_identity = 0;
884 *
for(
unsigned int d = 0;
d < dim; ++
d)
885 * p_n_times_identity[
d][
d] = p_n;
887 * phi.submit_value(1.0/((1.0 -
gamma)*dt)*u_n_gamma, q);
888 * phi.submit_gradient(a32*tensor_product_u_n_gamma + a31*tensor_product_u_n -
889 * a32/Re*grad_u_n_gamma - a31/Re*grad_u_n + p_n_times_identity, q);
891 * phi.integrate_scatter(
true,
true, dst);
899 * The followinf function assembles rhs face term
for the velocity
905 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
906 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
909 *
const std::vector<Vec>& src,
910 *
const std::pair<unsigned int, unsigned int>& face_range)
const {
911 *
if(TR_BDF2_stage == 1) {
916 * phi_m(data,
false, 0),
917 * phi_old_p(data,
true, 0),
918 * phi_old_m(data,
false, 0),
919 * phi_old_extr_p(data,
true, 0),
920 * phi_old_extr_m(data,
false, 0);
922 * phi_old_press_m(data,
false, 1);
925 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
926 * phi_old_p.reinit(face);
927 * phi_old_p.gather_evaluate(src[0],
true,
true);
928 * phi_old_m.reinit(face);
929 * phi_old_m.gather_evaluate(src[0],
true,
true);
930 * phi_old_extr_p.reinit(face);
931 * phi_old_extr_p.gather_evaluate(src[1],
true,
false);
932 * phi_old_extr_m.reinit(face);
933 * phi_old_extr_m.gather_evaluate(src[1],
true,
false);
934 * phi_old_press_p.reinit(face);
935 * phi_old_press_p.gather_evaluate(src[2],
true,
false);
936 * phi_old_press_m.reinit(face);
937 * phi_old_press_m.gather_evaluate(src[2],
true,
false);
938 * phi_p.reinit(face);
939 * phi_m.reinit(face);
942 *
for(
unsigned int q = 0; q < phi_p.n_q_points; ++q) {
943 *
const auto& n_plus = phi_p.get_normal_vector(q);
947 *
const auto& avg_grad_u_old = 0.5*(phi_old_p.get_gradient(q) + phi_old_m.get_gradient(q));
948 *
const auto& avg_tensor_product_u_n = 0.5*(
outer_product(phi_old_p.get_value(q), phi_old_extr_p.get_value(q)) +
949 *
outer_product(phi_old_m.get_value(q), phi_old_extr_m.get_value(q)));
950 *
const auto& avg_p_old = 0.5*(phi_old_press_p.get_value(q) + phi_old_press_m.get_value(q));
952 * phi_p.submit_value((a21/Re*avg_grad_u_old - a21*avg_tensor_product_u_n)*n_plus - avg_p_old*n_plus, q);
953 * phi_m.submit_value(-(a21/Re*avg_grad_u_old - a21*avg_tensor_product_u_n)*n_plus + avg_p_old*n_plus, q);
955 * phi_p.integrate_scatter(
true,
false, dst);
956 * phi_m.integrate_scatter(
true,
false, dst);
962 * phi_m(data,
false, 0),
963 * phi_old_p(data,
true, 0),
964 * phi_old_m(data,
false, 0),
965 * phi_int_p(data,
true, 0),
966 * phi_int_m(data,
false, 0);
968 * phi_old_press_m(data,
false, 1);
971 *
for(
unsigned int face = face_range.first; face < face_range.second; ++ face) {
972 * phi_old_p.reinit(face);
973 * phi_old_p.gather_evaluate(src[0],
true,
true);
974 * phi_old_m.reinit(face);
975 * phi_old_m.gather_evaluate(src[0],
true,
true);
976 * phi_int_p.reinit(face);
977 * phi_int_p.gather_evaluate(src[1],
true,
true);
978 * phi_int_m.reinit(face);
979 * phi_int_m.gather_evaluate(src[1],
true,
true);
980 * phi_old_press_p.reinit(face);
981 * phi_old_press_p.gather_evaluate(src[2],
true,
false);
982 * phi_old_press_m.reinit(face);
983 * phi_old_press_m.gather_evaluate(src[2],
true,
false);
984 * phi_p.reinit(face);
985 * phi_m.reinit(face);
988 *
for(
unsigned int q = 0; q < phi_p.n_q_points; ++q) {
989 *
const auto& n_plus = phi_p.get_normal_vector(q);
991 *
const auto& avg_grad_u_old = 0.5*(phi_old_p.get_gradient(q) + phi_old_m.get_gradient(q));
992 *
const auto& avg_grad_u_int = 0.5*(phi_int_p.get_gradient(q) + phi_int_m.get_gradient(q));
993 *
const auto& avg_tensor_product_u_n = 0.5*(
outer_product(phi_old_p.get_value(q), phi_old_p.get_value(q)) +
994 *
outer_product(phi_old_m.get_value(q), phi_old_m.get_value(q)));
995 *
const auto& avg_tensor_product_u_n_gamma = 0.5*(
outer_product(phi_int_p.get_value(q), phi_int_p.get_value(q)) +
996 *
outer_product(phi_int_m.get_value(q), phi_int_m.get_value(q)));
997 *
const auto& avg_p_old = 0.5*(phi_old_press_p.get_value(q) + phi_old_press_m.get_value(q));
999 * phi_p.submit_value((a31/Re*avg_grad_u_old + a32/Re*avg_grad_u_int -
1000 * a31*avg_tensor_product_u_n - a32*avg_tensor_product_u_n_gamma)*n_plus - avg_p_old*n_plus, q);
1001 * phi_m.submit_value(-(a31/Re*avg_grad_u_old + a32/Re*avg_grad_u_int -
1002 * a31*avg_tensor_product_u_n - a32*avg_tensor_product_u_n_gamma)*n_plus + avg_p_old*n_plus, q);
1004 * phi_p.integrate_scatter(
true,
false, dst);
1005 * phi_m.integrate_scatter(
true,
false, dst);
1013 * The followinf function assembles rhs boundary term
for the velocity
1019 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1020 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1023 *
const std::vector<Vec>& src,
1024 *
const std::pair<unsigned int, unsigned int>& face_range)
const {
1025 *
if(TR_BDF2_stage == 1) {
1029 * phi_old(data,
true, 0),
1030 * phi_old_extr(data,
true, 0);
1034 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
1035 * phi_old.reinit(face);
1036 * phi_old.gather_evaluate(src[0],
true,
true);
1037 * phi_old_extr.reinit(face);
1038 * phi_old_extr.gather_evaluate(src[1],
true,
false);
1039 * phi_old_press.reinit(face);
1040 * phi_old_press.gather_evaluate(src[2],
true,
false);
1044 *
const auto coef_jump = (
boundary_id == 1) ? 0.0 : C_u*
std::abs((phi.get_normal_vector(0) * phi.inverse_jacobian(0))[dim - 1]);
1045 *
const double aux_coeff = (
boundary_id == 1) ? 0.0 : 1.0;
1048 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1049 *
const auto& n_plus = phi.get_normal_vector(q);
1051 *
const auto& grad_u_old = phi_old.get_gradient(q);
1052 *
const auto& tensor_product_u_n =
outer_product(phi_old.get_value(q), phi_old_extr.get_value(q));
1053 *
const auto& p_old = phi_old_press.get_value(q);
1054 *
const auto& point_vectorized = phi.quadrature_point(q);
1057 *
for(
unsigned int v = 0; v < VectorizedArray<Number>::size(); ++v) {
1061 *
for(
unsigned int d = 0;
d < dim; ++
d)
1062 *
point[
d] = point_vectorized[
d][v];
1063 *
for(
unsigned int d = 0;
d < dim; ++
d)
1064 * u_int_m[
d][v] = vel_boundary_inflow.value(
point,
d);
1067 *
const auto tensor_product_u_int_m =
outer_product(u_int_m, phi_old_extr.get_value(q));
1070 * phi.submit_value((a21/Re*grad_u_old - a21*tensor_product_u_n)*n_plus - p_old*n_plus +
1071 * a22/Re*2.0*coef_jump*u_int_m -
1072 * aux_coeff*a22*tensor_product_u_int_m*n_plus + a22*
lambda*u_int_m, q);
1073 * phi.submit_normal_derivative(-aux_coeff*theta_v*a22/Re*u_int_m, q);
1076 * phi.integrate_scatter(
true,
true, dst);
1082 * phi_old(data,
true, 0),
1083 * phi_int(data,
true, 0),
1084 * phi_int_extr(data,
true, 0);
1088 *
for(
unsigned int face = face_range.first; face < face_range.second; ++ face) {
1089 * phi_old.reinit(face);
1090 * phi_old.gather_evaluate(src[0],
true,
true);
1091 * phi_int.reinit(face);
1092 * phi_int.gather_evaluate(src[1],
true,
true);
1093 * phi_old_press.reinit(face);
1094 * phi_old_press.gather_evaluate(src[2],
true,
false);
1095 * phi_int_extr.reinit(face);
1096 * phi_int_extr.gather_evaluate(src[3],
true,
false);
1100 *
const auto coef_jump = (
boundary_id == 1) ? 0.0 : C_u*
std::abs((phi.get_normal_vector(0) * phi.inverse_jacobian(0))[dim - 1]);
1101 *
const double aux_coeff = (
boundary_id == 1) ? 0.0 : 1.0;
1104 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1105 *
const auto& n_plus = phi.get_normal_vector(q);
1107 *
const auto& grad_u_old = phi_old.get_gradient(q);
1108 *
const auto& grad_u_int = phi_int.get_gradient(q);
1109 *
const auto& tensor_product_u_n =
outer_product(phi_old.get_value(q), phi_old.get_value(q));
1110 *
const auto& tensor_product_u_n_gamma =
outer_product(phi_int.get_value(q), phi_int.get_value(q));
1111 *
const auto& p_old = phi_old_press.get_value(q);
1112 *
const auto& point_vectorized = phi.quadrature_point(q);
1115 *
for(
unsigned int v = 0; v < VectorizedArray<Number>::size(); ++v) {
1117 *
for(
unsigned int d = 0;
d < dim; ++
d)
1118 *
point[
d] = point_vectorized[
d][v];
1119 *
for(
unsigned int d = 0;
d < dim; ++
d)
1120 * u_m[
d][v] = vel_boundary_inflow.value(
point,
d);
1123 *
const auto tensor_product_u_m =
outer_product(u_m, phi_int_extr.get_value(q));
1126 * phi.submit_value((a31/Re*grad_u_old + a32/Re*grad_u_int -
1127 * a31*tensor_product_u_n - a32*tensor_product_u_n_gamma)*n_plus - p_old*n_plus +
1128 * a33/Re*2.0*coef_jump*u_m -
1129 * aux_coeff*a33*tensor_product_u_m*n_plus + a33*
lambda*u_m, q);
1130 * phi.submit_normal_derivative(-aux_coeff*theta_v*a33/Re*u_m, q);
1132 * phi.integrate_scatter(
true,
true, dst);
1140 * Put together all the previous steps
for velocity. This is done automatically by the
loop function of
'MatrixFree' class
1146 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1147 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1148 * vmult_rhs_velocity(Vec& dst,
const std::vector<Vec>& src)
const {
1149 *
for(
unsigned int d = 0;
d < src.size(); ++
d)
1150 * src[
d].update_ghost_values();
1152 * this->data->
loop(&NavierStokesProjectionOperator::assemble_rhs_cell_term_velocity,
1153 * &NavierStokesProjectionOperator::assemble_rhs_face_term_velocity,
1154 * &NavierStokesProjectionOperator::assemble_rhs_boundary_term_velocity,
1155 *
this, dst, src,
true,
1163 * Now we focus on computing the rhs
for the projection step
for the pressure with the same ratio.
1164 * The following function assembles rhs cell term
for the pressure
1170 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1171 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1174 *
const std::vector<Vec>& src,
1175 *
const std::pair<unsigned int, unsigned int>& cell_range)
const {
1179 * phi_old(data, 1, 1);
1182 *
const double coeff = (TR_BDF2_stage == 1) ? 1.0e6*
gamma*dt*
gamma*dt : 1.0e6*(1.0 -
gamma)*dt*(1.0 -
gamma)*dt;
1184 *
const double coeff_2 = (TR_BDF2_stage == 1) ?
gamma*dt : (1.0 -
gamma)*dt;
1187 *
for(
unsigned int cell = cell_range.first; cell < cell_range.second; ++cell) {
1188 * phi_proj.reinit(cell);
1189 * phi_proj.gather_evaluate(src[0],
true,
false);
1190 * phi_old.reinit(cell);
1191 * phi_old.gather_evaluate(src[1],
true,
false);
1195 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1196 *
const auto& u_star_star = phi_proj.get_value(q);
1197 *
const auto& p_old = phi_old.get_value(q);
1199 * phi.submit_value(1.0/coeff*p_old, q);
1200 * phi.submit_gradient(1.0/coeff_2*u_star_star, q);
1202 * phi.integrate_scatter(
true,
true, dst);
1209 * The following function assembles rhs face term
for the pressure
1215 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1216 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1219 *
const std::vector<Vec>& src,
1220 *
const std::pair<unsigned int, unsigned int>& face_range)
const {
1223 * phi_m(data,
false, 1, 1);
1225 * phi_proj_m(data,
false, 0, 1);
1227 *
const double coeff = (TR_BDF2_stage == 1) ? 1.0/(
gamma*dt) : 1.0/((1.0 -
gamma)*dt);
1230 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
1231 * phi_proj_p.reinit(face);
1232 * phi_proj_p.gather_evaluate(src[0],
true,
false);
1233 * phi_proj_m.reinit(face);
1234 * phi_proj_m.gather_evaluate(src[0],
true,
false);
1235 * phi_p.reinit(face);
1236 * phi_m.reinit(face);
1239 *
for(
unsigned int q = 0; q < phi_p.n_q_points; ++q) {
1240 *
const auto& n_plus = phi_p.get_normal_vector(q);
1241 *
const auto& avg_u_star_star = 0.5*(phi_proj_p.get_value(q) + phi_proj_m.get_value(q));
1243 * phi_p.submit_value(-coeff*
scalar_product(avg_u_star_star, n_plus), q);
1244 * phi_m.submit_value(coeff*
scalar_product(avg_u_star_star, n_plus), q);
1246 * phi_p.integrate_scatter(
true,
false, dst);
1247 * phi_m.integrate_scatter(
true,
false, dst);
1254 * The following function assembles rhs boundary term
for the pressure
1260 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1261 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1264 *
const std::vector<Vec>& src,
1265 *
const std::pair<unsigned int, unsigned int>& face_range)
const {
1270 *
const double coeff = (TR_BDF2_stage == 1) ? 1.0/(
gamma*dt) : 1.0/((1.0 -
gamma)*dt);
1273 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
1274 * phi_proj.reinit(face);
1275 * phi_proj.gather_evaluate(src[0],
true,
false);
1279 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1280 *
const auto& n_plus = phi.get_normal_vector(q);
1282 * phi.submit_value(-coeff*
scalar_product(phi_proj.get_value(q), n_plus), q);
1284 * phi.integrate_scatter(
true,
false, dst);
1291 * Put together all the previous steps
for pressure
1297 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1298 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1299 * vmult_rhs_pressure(Vec& dst,
const std::vector<Vec>& src)
const {
1300 *
for(
unsigned int d = 0;
d < src.size(); ++
d)
1301 * src[
d].update_ghost_values();
1303 * this->data->
loop(&NavierStokesProjectionOperator::assemble_rhs_cell_term_pressure,
1304 * &NavierStokesProjectionOperator::assemble_rhs_face_term_pressure,
1305 * &NavierStokesProjectionOperator::assemble_rhs_boundary_term_pressure,
1306 *
this, dst, src,
true,
1314 * Now we need to build the
'matrices', i.e. the bilinear forms. We start by
1315 * assembling the cell term
for the velocity
1321 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1322 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1326 *
const std::pair<unsigned int, unsigned int>& cell_range)
const {
1327 *
if(TR_BDF2_stage == 1) {
1331 * phi_old_extr(data, 0);
1334 *
for(
unsigned int cell = cell_range.first; cell < cell_range.second; ++cell) {
1336 * phi.gather_evaluate(src,
true,
true);
1337 * phi_old_extr.reinit(cell);
1338 * phi_old_extr.gather_evaluate(u_extr,
true,
false);
1341 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1342 *
const auto& u_int = phi.get_value(q);
1343 *
const auto& grad_u_int = phi.get_gradient(q);
1344 *
const auto& u_n_gamma_ov_2 = phi_old_extr.get_value(q);
1345 *
const auto& tensor_product_u_int =
outer_product(u_int, u_n_gamma_ov_2);
1347 * phi.submit_value(1.0/(
gamma*dt)*u_int, q);
1348 * phi.submit_gradient(-a22*tensor_product_u_int + a22/Re*grad_u_int, q);
1350 * phi.integrate_scatter(
true,
true, dst);
1356 * phi_int_extr(data, 0);
1359 *
for(
unsigned int cell = cell_range.first; cell < cell_range.second; ++cell) {
1361 * phi.gather_evaluate(src,
true,
true);
1362 * phi_int_extr.reinit(cell);
1363 * phi_int_extr.gather_evaluate(u_extr,
true,
false);
1366 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1367 *
const auto& u_curr = phi.get_value(q);
1368 *
const auto& grad_u_curr = phi.get_gradient(q);
1369 *
const auto& u_n1_int = phi_int_extr.get_value(q);
1370 *
const auto& tensor_product_u_curr =
outer_product(u_curr, u_n1_int);
1372 * phi.submit_value(1.0/((1.0 -
gamma)*dt)*u_curr, q);
1373 * phi.submit_gradient(-a33*tensor_product_u_curr + a33/Re*grad_u_curr, q);
1375 * phi.integrate_scatter(
true,
true, dst);
1383 * The following function assembles face term
for the velocity
1389 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1390 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1394 *
const std::pair<unsigned int, unsigned int>& face_range)
const {
1395 *
if(TR_BDF2_stage == 1) {
1398 * phi_m(data,
false, 0),
1399 * phi_old_extr_p(data,
true, 0),
1400 * phi_old_extr_m(data,
false, 0);
1403 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
1404 * phi_p.reinit(face);
1405 * phi_p.gather_evaluate(src,
true,
true);
1406 * phi_m.reinit(face);
1407 * phi_m.gather_evaluate(src,
true,
true);
1408 * phi_old_extr_p.reinit(face);
1409 * phi_old_extr_p.gather_evaluate(u_extr,
true,
false);
1410 * phi_old_extr_m.reinit(face);
1411 * phi_old_extr_m.gather_evaluate(u_extr,
true,
false);
1413 *
const auto coef_jump = C_u*0.5*(
std::abs((phi_p.get_normal_vector(0)*phi_p.inverse_jacobian(0))[dim - 1]) +
1414 *
std::abs((phi_m.get_normal_vector(0)*phi_m.inverse_jacobian(0))[dim - 1]));
1417 *
for(
unsigned int q = 0; q < phi_p.n_q_points; ++q) {
1418 *
const auto& n_plus = phi_p.get_normal_vector(q);
1420 *
const auto& avg_grad_u_int = 0.5*(phi_p.get_gradient(q) + phi_m.get_gradient(q));
1421 *
const auto& jump_u_int = phi_p.get_value(q) - phi_m.get_value(q);
1422 *
const auto& avg_tensor_product_u_int = 0.5*(
outer_product(phi_p.get_value(q), phi_old_extr_p.get_value(q)) +
1423 *
outer_product(phi_m.get_value(q), phi_old_extr_m.get_value(q)));
1427 * phi_p.submit_value(a22/Re*(-avg_grad_u_int*n_plus + coef_jump*jump_u_int) +
1428 * a22*avg_tensor_product_u_int*n_plus + 0.5*a22*lambda*jump_u_int, q);
1429 * phi_m.submit_value(-a22/Re*(-avg_grad_u_int*n_plus + coef_jump*jump_u_int) -
1430 * a22*avg_tensor_product_u_int*n_plus - 0.5*a22*lambda*jump_u_int, q);
1431 * phi_p.submit_normal_derivative(-theta_v*a22/Re*0.5*jump_u_int, q);
1432 * phi_m.submit_normal_derivative(-theta_v*a22/Re*0.5*jump_u_int, q);
1434 * phi_p.integrate_scatter(
true,
true, dst);
1435 * phi_m.integrate_scatter(
true,
true, dst);
1441 * phi_m(data,
false, 0),
1442 * phi_extr_p(data,
true, 0),
1443 * phi_extr_m(data,
false, 0);
1446 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
1447 * phi_p.reinit(face);
1448 * phi_p.gather_evaluate(src,
true,
true);
1449 * phi_m.reinit(face);
1450 * phi_m.gather_evaluate(src,
true,
true);
1451 * phi_extr_p.reinit(face);
1452 * phi_extr_p.gather_evaluate(u_extr,
true,
false);
1453 * phi_extr_m.reinit(face);
1454 * phi_extr_m.gather_evaluate(u_extr,
true,
false);
1456 *
const auto coef_jump = C_u*0.5*(
std::abs((phi_p.get_normal_vector(0)*phi_p.inverse_jacobian(0))[dim - 1]) +
1457 *
std::abs((phi_m.get_normal_vector(0)*phi_m.inverse_jacobian(0))[dim - 1]));
1460 *
for(
unsigned int q = 0; q < phi_p.n_q_points; ++q) {
1461 *
const auto& n_plus = phi_p.get_normal_vector(q);
1463 *
const auto& avg_grad_u = 0.5*(phi_p.get_gradient(q) + phi_m.get_gradient(q));
1464 *
const auto& jump_u = phi_p.get_value(q) - phi_m.get_value(q);
1465 *
const auto& avg_tensor_product_u = 0.5*(
outer_product(phi_p.get_value(q), phi_extr_p.get_value(q)) +
1466 *
outer_product(phi_m.get_value(q), phi_extr_m.get_value(q)));
1470 * phi_p.submit_value(a33/Re*(-avg_grad_u*n_plus + coef_jump*jump_u) +
1471 * a33*avg_tensor_product_u*n_plus + 0.5*a33*lambda*jump_u, q);
1472 * phi_m.submit_value(-a33/Re*(-avg_grad_u*n_plus + coef_jump*jump_u) -
1473 * a33*avg_tensor_product_u*n_plus - 0.5*a33*lambda*jump_u, q);
1474 * phi_p.submit_normal_derivative(-theta_v*a33/Re*0.5*jump_u, q);
1475 * phi_m.submit_normal_derivative(-theta_v*a33/Re*0.5*jump_u, q);
1477 * phi_p.integrate_scatter(
true,
true, dst);
1478 * phi_m.integrate_scatter(
true,
true, dst);
1486 * The following function assembles boundary term
for the velocity
1492 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1493 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1497 *
const std::pair<unsigned int, unsigned int>& face_range)
const {
1498 *
if(TR_BDF2_stage == 1) {
1501 * phi_old_extr(data,
true, 0);
1504 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
1506 * phi.gather_evaluate(src,
true,
true);
1507 * phi_old_extr.reinit(face);
1508 * phi_old_extr.gather_evaluate(u_extr,
true,
false);
1511 *
const auto coef_jump = C_u*
std::abs((phi.get_normal_vector(0) * phi.inverse_jacobian(0))[dim - 1]);
1516 *
const double coef_trasp = 0.0;
1519 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1520 *
const auto& n_plus = phi.get_normal_vector(q);
1521 *
const auto& grad_u_int = phi.get_gradient(q);
1522 *
const auto& u_int = phi.get_value(q);
1523 *
const auto& tensor_product_u_int =
outer_product(phi.get_value(q), phi_old_extr.get_value(q));
1526 * phi.submit_value(a22/Re*(-grad_u_int*n_plus + 2.0*coef_jump*u_int) +
1527 * a22*coef_trasp*tensor_product_u_int*n_plus + a22*lambda*u_int, q);
1528 * phi.submit_normal_derivative(-theta_v*a22/Re*u_int, q);
1530 * phi.integrate_scatter(
true,
true, dst);
1534 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1535 *
const auto& n_plus = phi.get_normal_vector(q);
1536 *
const auto& grad_u_int = phi.get_gradient(q);
1537 *
const auto& u_int = phi.get_value(q);
1540 *
const auto& point_vectorized = phi.quadrature_point(q);
1541 *
auto u_int_m = u_int;
1542 *
auto grad_u_int_m = grad_u_int;
1543 *
for(
unsigned int v = 0; v < VectorizedArray<Number>::size(); ++v) {
1545 *
for(
unsigned int d = 0;
d < dim; ++
d)
1546 *
point[
d] = point_vectorized[
d][v];
1548 * u_int_m[1][v] = -u_int_m[1][v];
1550 * grad_u_int_m[0][0][v] = -grad_u_int_m[0][0][v];
1551 * grad_u_int_m[0][1][v] = -grad_u_int_m[0][1][v];
1554 * phi.submit_value(a22/Re*(-(0.5*(grad_u_int + grad_u_int_m))*n_plus + coef_jump*(u_int - u_int_m)) +
1555 * a22*
outer_product(0.5*(u_int + u_int_m), phi_old_extr.get_value(q))*n_plus +
1556 * a22*0.5*
lambda*(u_int - u_int_m), q);
1557 * phi.submit_normal_derivative(-theta_v*a22/Re*(u_int - u_int_m), q);
1559 * phi.integrate_scatter(
true,
true, dst);
1566 * phi_extr(data,
true, 0);
1569 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
1571 * phi.gather_evaluate(src,
true,
true);
1572 * phi_extr.reinit(face);
1573 * phi_extr.gather_evaluate(u_extr,
true,
false);
1576 *
const auto coef_jump = C_u*
std::abs((phi.get_normal_vector(0) * phi.inverse_jacobian(0))[dim - 1]);
1579 *
const double coef_trasp = 0.0;
1582 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1583 *
const auto& n_plus = phi.get_normal_vector(q);
1584 *
const auto& grad_u = phi.get_gradient(q);
1585 *
const auto& u = phi.get_value(q);
1586 *
const auto& tensor_product_u =
outer_product(phi.get_value(q), phi_extr.get_value(q));
1589 * phi.submit_value(a33/Re*(-grad_u*n_plus + 2.0*coef_jump*u) +
1590 * a33*coef_trasp*tensor_product_u*n_plus + a33*lambda*u, q);
1591 * phi.submit_normal_derivative(-theta_v*a33/Re*u, q);
1593 * phi.integrate_scatter(
true,
true, dst);
1597 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1598 *
const auto& n_plus = phi.get_normal_vector(q);
1599 *
const auto& grad_u = phi.get_gradient(q);
1600 *
const auto& u = phi.get_value(q);
1603 *
const auto& point_vectorized = phi.quadrature_point(q);
1605 *
auto grad_u_m = grad_u;
1606 *
for(
unsigned int v = 0; v < VectorizedArray<Number>::size(); ++v) {
1608 *
for(
unsigned int d = 0;
d < dim; ++
d)
1609 *
point[
d] = point_vectorized[
d][v];
1611 * u_m[1][v] = -u_m[1][v];
1613 * grad_u_m[0][0][v] = -grad_u_m[0][0][v];
1614 * grad_u_m[0][1][v] = -grad_u_m[0][1][v];
1617 * phi.submit_value(a33/Re*(-(0.5*(grad_u + grad_u_m))*n_plus + coef_jump*(u - u_m)) +
1618 * a33*
outer_product(0.5*(u + u_m), phi_extr.get_value(q))*n_plus + a33*0.5*
lambda*(u - u_m), q);
1619 * phi.submit_normal_derivative(-theta_v*a33/Re*(u - u_m), q);
1621 * phi.integrate_scatter(
true,
true, dst);
1630 * Next, we focus on
'matrices' to compute the pressure. We
first assemble cell term
for the pressure
1636 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1637 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1641 *
const std::pair<unsigned int, unsigned int>& cell_range)
const {
1645 *
const double coeff = (TR_BDF2_stage == 1) ? 1.0e6*
gamma*dt*
gamma*dt : 1.0e6*(1.0 -
gamma)*dt*(1.0 -
gamma)*dt;
1648 *
for(
unsigned int cell = cell_range.first; cell < cell_range.second; ++cell) {
1650 * phi.gather_evaluate(src,
true,
true);
1653 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1654 * phi.submit_gradient(phi.get_gradient(q), q);
1655 * phi.submit_value(1.0/coeff*phi.get_value(q), q);
1658 * phi.integrate_scatter(
true,
true, dst);
1665 * The following function assembles face term
for the pressure
1671 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1672 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1676 *
const std::pair<unsigned int, unsigned int>& face_range)
const {
1679 * phi_m(data,
false, 1, 1);
1682 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
1683 * phi_p.reinit(face);
1684 * phi_p.gather_evaluate(src,
true,
true);
1685 * phi_m.reinit(face);
1686 * phi_m.gather_evaluate(src,
true,
true);
1688 *
const auto coef_jump = C_p*0.5*(
std::abs((phi_p.get_normal_vector(0)*phi_p.inverse_jacobian(0))[dim - 1]) +
1689 *
std::abs((phi_m.get_normal_vector(0)*phi_m.inverse_jacobian(0))[dim - 1]));
1692 *
for(
unsigned int q = 0; q < phi_p.n_q_points; ++q) {
1693 *
const auto& n_plus = phi_p.get_normal_vector(q);
1695 *
const auto& avg_grad_pres = 0.5*(phi_p.get_gradient(q) + phi_m.get_gradient(q));
1696 *
const auto& jump_pres = phi_p.get_value(q) - phi_m.get_value(q);
1698 * phi_p.submit_value(-
scalar_product(avg_grad_pres, n_plus) + coef_jump*jump_pres, q);
1699 * phi_m.submit_value(
scalar_product(avg_grad_pres, n_plus) - coef_jump*jump_pres, q);
1700 * phi_p.submit_gradient(-theta_p*0.5*jump_pres*n_plus, q);
1701 * phi_m.submit_gradient(-theta_p*0.5*jump_pres*n_plus, q);
1703 * phi_p.integrate_scatter(
true,
true, dst);
1704 * phi_m.integrate_scatter(
true,
true, dst);
1711 * The following function assembles boundary term
for the pressure
1717 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1718 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1722 *
const std::pair<unsigned int, unsigned int>& face_range)
const {
1725 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
1727 * phi.gather_evaluate(src,
true,
true);
1729 *
const auto coef_jump = C_p*
std::abs((phi.get_normal_vector(0)*phi.inverse_jacobian(0))[dim - 1]);
1734 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1735 *
const auto& n_plus = phi.get_normal_vector(q);
1737 *
const auto& grad_pres = phi.get_gradient(q);
1738 *
const auto& pres = phi.get_value(q);
1740 * phi.submit_value(-
scalar_product(grad_pres, n_plus) + coef_jump*pres , q);
1741 * phi.submit_normal_derivative(-theta_p*pres, q);
1743 * phi.integrate_scatter(
true,
true, dst);
1751 * Before coding the
'apply_add' function, which is the
one that will perform the
loop, we focus on
1752 * the linear system that arises to
project the
gradient of the pressure into the velocity space.
1753 * The following function assembles rhs cell term
for the projection of
gradient of pressure. Since no
1754 * integration by parts is performed, only a cell term contribution is present.
1760 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1761 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1765 *
const std::pair<unsigned int, unsigned int>& cell_range)
const {
1771 *
for(
unsigned int cell = cell_range.first; cell < cell_range.second; ++cell) {
1772 * phi_pres.reinit(cell);
1773 * phi_pres.gather_evaluate(src,
false,
true);
1777 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q)
1778 * phi.submit_value(phi_pres.get_gradient(q), q);
1780 * phi.integrate_scatter(
true,
false, dst);
1787 * Put together all the previous steps
for porjection of pressure
gradient. Here we
loop only over cells
1793 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1794 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1795 * vmult_grad_p_projection(Vec& dst,
const Vec& src)
const {
1796 * this->data->
cell_loop(&NavierStokesProjectionOperator::assemble_rhs_cell_term_projection_grad_p,
1797 *
this, dst, src,
true);
1803 * Assemble now cell term
for the projection of
gradient of pressure. This is
nothing but a mass
matrix
1809 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1810 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1814 *
const std::pair<unsigned int, unsigned int>& cell_range)
const {
1818 *
for(
unsigned int cell = cell_range.first; cell < cell_range.second; ++cell) {
1820 * phi.gather_evaluate(src,
true,
false);
1823 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q)
1824 * phi.submit_value(phi.get_value(q), q);
1826 * phi.integrate_scatter(
true,
false, dst);
1833 * Put together all previous steps. This is the overriden function that effectively performs the
1834 *
matrix-vector multiplication.
1840 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1841 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1842 * apply_add(Vec& dst,
const Vec& src)
const {
1843 *
if(NS_stage == 1) {
1844 * this->data->
loop(&NavierStokesProjectionOperator::assemble_cell_term_velocity,
1845 * &NavierStokesProjectionOperator::assemble_face_term_velocity,
1846 * &NavierStokesProjectionOperator::assemble_boundary_term_velocity,
1847 *
this, dst, src,
false,
1851 *
else if(NS_stage == 2) {
1852 * this->data->
loop(&NavierStokesProjectionOperator::assemble_cell_term_pressure,
1853 * &NavierStokesProjectionOperator::assemble_face_term_pressure,
1854 * &NavierStokesProjectionOperator::assemble_boundary_term_pressure,
1855 *
this, dst, src,
false,
1859 *
else if(NS_stage == 3) {
1860 * this->data->
cell_loop(&NavierStokesProjectionOperator::assemble_cell_term_projection_grad_p,
1861 *
this, dst, src,
false);
1870 * Finally, we focus on computing the
diagonal for preconditioners and we start by assembling
1871 * the
diagonal cell term
for the velocity. Since we
do not have access to the entries of the
matrix,
1872 * in order to compute the element i, we test the
matrix against a vector which is
equal to 1 in position i and 0 elsewhere.
1873 * This is why
'src' will result as unused.
1879 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1880 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1883 *
const unsigned int& ,
1884 *
const std::pair<unsigned int, unsigned int>& cell_range)
const {
1885 *
if(TR_BDF2_stage == 1) {
1887 * phi_old_extr(data, 0);
1893 *
for(
unsigned int d = 0;
d < dim; ++
d)
1894 * tmp[
d] = make_vectorized_array<Number>(1.0);
1897 *
for(
unsigned int cell = cell_range.first; cell < cell_range.second; ++cell) {
1898 * phi_old_extr.reinit(cell);
1899 * phi_old_extr.gather_evaluate(u_extr,
true,
false);
1903 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i) {
1904 *
for(
unsigned int j = 0; j < phi.dofs_per_component; ++j)
1906 * phi.submit_dof_value(tmp, i);
1907 * phi.evaluate(
true,
true);
1910 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1911 *
const auto& u_int = phi.get_value(q);
1912 *
const auto& grad_u_int = phi.get_gradient(q);
1913 *
const auto& u_n_gamma_ov_2 = phi_old_extr.get_value(q);
1914 *
const auto& tensor_product_u_int =
outer_product(u_int, u_n_gamma_ov_2);
1916 * phi.submit_value(1.0/(
gamma*dt)*u_int, q);
1917 * phi.submit_gradient(-a22*tensor_product_u_int + a22/Re*grad_u_int, q);
1919 * phi.integrate(
true,
true);
1920 *
diagonal[i] = phi.get_dof_value(i);
1922 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i)
1923 * phi.submit_dof_value(
diagonal[i], i);
1924 * phi.distribute_local_to_global(dst);
1929 * phi_int_extr(data, 0);
1933 *
for(
unsigned int d = 0;
d < dim; ++
d)
1934 * tmp[
d] = make_vectorized_array<Number>(1.0);
1937 *
for(
unsigned int cell = cell_range.first; cell < cell_range.second; ++cell) {
1938 * phi_int_extr.reinit(cell);
1939 * phi_int_extr.gather_evaluate(u_extr,
true,
false);
1943 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i) {
1944 *
for(
unsigned int j = 0; j < phi.dofs_per_component; ++j)
1946 * phi.submit_dof_value(tmp, i);
1947 * phi.evaluate(
true,
true);
1950 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
1951 *
const auto& u_curr = phi.get_value(q);
1952 *
const auto& grad_u_curr = phi.get_gradient(q);
1953 *
const auto& u_n1_int = phi_int_extr.get_value(q);
1954 *
const auto& tensor_product_u_curr =
outer_product(u_curr, u_n1_int);
1956 * phi.submit_value(1.0/((1.0 -
gamma)*dt)*u_curr, q);
1957 * phi.submit_gradient(-a33*tensor_product_u_curr + a33/Re*grad_u_curr, q);
1959 * phi.integrate(
true,
true);
1960 *
diagonal[i] = phi.get_dof_value(i);
1962 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i)
1963 * phi.submit_dof_value(
diagonal[i], i);
1964 * phi.distribute_local_to_global(dst);
1972 * The following function assembles
diagonal face term
for the velocity
1978 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
1979 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
1982 *
const unsigned int& ,
1983 *
const std::pair<unsigned int, unsigned int>& face_range)
const {
1984 *
if(TR_BDF2_stage == 1) {
1986 * phi_m(data,
false, 0),
1987 * phi_old_extr_p(data,
true, 0),
1988 * phi_old_extr_m(data,
false, 0);
1990 *
AssertDimension(phi_p.dofs_per_component, phi_m.dofs_per_component);
1994 * diagonal_m(phi_m.dofs_per_component);
1996 *
for(
unsigned int d = 0;
d < dim; ++
d)
1997 * tmp[
d] = make_vectorized_array<Number>(1.0);
2000 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
2001 * phi_old_extr_p.reinit(face);
2002 * phi_old_extr_p.gather_evaluate(u_extr,
true,
false);
2003 * phi_old_extr_m.reinit(face);
2004 * phi_old_extr_m.gather_evaluate(u_extr,
true,
false);
2005 * phi_p.reinit(face);
2006 * phi_m.reinit(face);
2008 *
const auto coef_jump = C_u*0.5*(
std::abs((phi_p.get_normal_vector(0)*phi_p.inverse_jacobian(0))[dim - 1]) +
2009 *
std::abs((phi_m.get_normal_vector(0)*phi_m.inverse_jacobian(0))[dim - 1]));
2012 *
for(
unsigned int i = 0; i < phi_p.dofs_per_component; ++i) {
2013 *
for(
unsigned int j = 0; j < phi_p.dofs_per_component; ++j) {
2017 * phi_p.submit_dof_value(tmp, i);
2018 * phi_p.evaluate(
true,
true);
2019 * phi_m.submit_dof_value(tmp, i);
2020 * phi_m.evaluate(
true,
true);
2023 *
for(
unsigned int q = 0; q < phi_p.n_q_points; ++q) {
2024 *
const auto& n_plus = phi_p.get_normal_vector(q);
2025 *
const auto& avg_grad_u_int = 0.5*(phi_p.get_gradient(q) + phi_m.get_gradient(q));
2026 *
const auto& jump_u_int = phi_p.get_value(q) - phi_m.get_value(q);
2027 *
const auto& avg_tensor_product_u_int = 0.5*(
outer_product(phi_p.get_value(q), phi_old_extr_p.get_value(q)) +
2028 *
outer_product(phi_m.get_value(q), phi_old_extr_m.get_value(q)));
2032 * phi_p.submit_value(a22/Re*(-avg_grad_u_int*n_plus + coef_jump*jump_u_int) +
2033 * a22*avg_tensor_product_u_int*n_plus + 0.5*a22*lambda*jump_u_int , q);
2034 * phi_m.submit_value(-a22/Re*(-avg_grad_u_int*n_plus + coef_jump*jump_u_int) -
2035 * a22*avg_tensor_product_u_int*n_plus - 0.5*a22*lambda*jump_u_int, q);
2036 * phi_p.submit_normal_derivative(-theta_v*0.5*a22/Re*jump_u_int, q);
2037 * phi_m.submit_normal_derivative(-theta_v*0.5*a22/Re*jump_u_int, q);
2039 * phi_p.integrate(
true,
true);
2040 * diagonal_p[i] = phi_p.get_dof_value(i);
2041 * phi_m.integrate(
true,
true);
2042 * diagonal_m[i] = phi_m.get_dof_value(i);
2044 *
for(
unsigned int i = 0; i < phi_p.dofs_per_component; ++i) {
2045 * phi_p.submit_dof_value(diagonal_p[i], i);
2046 * phi_m.submit_dof_value(diagonal_m[i], i);
2048 * phi_p.distribute_local_to_global(dst);
2049 * phi_m.distribute_local_to_global(dst);
2054 * phi_m(data,
false, 0),
2055 * phi_extr_p(data,
true, 0),
2056 * phi_extr_m(data,
false, 0);
2058 *
AssertDimension(phi_p.dofs_per_component, phi_m.dofs_per_component);
2060 * diagonal_m(phi_m.dofs_per_component);
2062 *
for(
unsigned int d = 0;
d < dim; ++
d)
2063 * tmp[
d] = make_vectorized_array<Number>(1.0);
2066 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
2067 * phi_extr_p.reinit(face);
2068 * phi_extr_p.gather_evaluate(u_extr,
true,
false);
2069 * phi_extr_m.reinit(face);
2070 * phi_extr_m.gather_evaluate(u_extr,
true,
false);
2071 * phi_p.reinit(face);
2072 * phi_m.reinit(face);
2074 *
const auto coef_jump = C_u*0.5*(
std::abs((phi_p.get_normal_vector(0)*phi_p.inverse_jacobian(0))[dim - 1]) +
2075 *
std::abs((phi_m.get_normal_vector(0)*phi_m.inverse_jacobian(0))[dim - 1]));
2078 *
for(
unsigned int i = 0; i < phi_p.dofs_per_component; ++i) {
2079 *
for(
unsigned int j = 0; j < phi_p.dofs_per_component; ++j) {
2083 * phi_p.submit_dof_value(tmp, i);
2084 * phi_p.evaluate(
true,
true);
2085 * phi_m.submit_dof_value(tmp, i);
2086 * phi_m.evaluate(
true,
true);
2089 *
for(
unsigned int q = 0; q < phi_p.n_q_points; ++q) {
2090 *
const auto& n_plus = phi_p.get_normal_vector(q);
2091 *
const auto& avg_grad_u = 0.5*(phi_p.get_gradient(q) + phi_m.get_gradient(q));
2092 *
const auto& jump_u = phi_p.get_value(q) - phi_m.get_value(q);
2093 *
const auto& avg_tensor_product_u = 0.5*(
outer_product(phi_p.get_value(q), phi_extr_p.get_value(q)) +
2094 *
outer_product(phi_m.get_value(q), phi_extr_m.get_value(q)));
2098 * phi_p.submit_value(a33/Re*(-avg_grad_u*n_plus + coef_jump*jump_u) +
2099 * a33*avg_tensor_product_u*n_plus + 0.5*a33*lambda*jump_u, q);
2100 * phi_m.submit_value(-a33/Re*(-avg_grad_u*n_plus + coef_jump*jump_u) -
2101 * a33*avg_tensor_product_u*n_plus - 0.5*a33*lambda*jump_u, q);
2102 * phi_p.submit_normal_derivative(-theta_v*0.5*a33/Re*jump_u, q);
2103 * phi_m.submit_normal_derivative(-theta_v*0.5*a33/Re*jump_u, q);
2105 * phi_p.integrate(
true,
true);
2106 * diagonal_p[i] = phi_p.get_dof_value(i);
2107 * phi_m.integrate(
true,
true);
2108 * diagonal_m[i] = phi_m.get_dof_value(i);
2110 *
for(
unsigned int i = 0; i < phi_p.dofs_per_component; ++i) {
2111 * phi_p.submit_dof_value(diagonal_p[i], i);
2112 * phi_m.submit_dof_value(diagonal_m[i], i);
2114 * phi_p.distribute_local_to_global(dst);
2115 * phi_m.distribute_local_to_global(dst);
2123 * The following function assembles boundary term
for the velocity
2129 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
2130 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
2133 *
const unsigned int& ,
2134 *
const std::pair<unsigned int, unsigned int>& face_range)
const {
2135 *
if(TR_BDF2_stage == 1) {
2137 * phi_old_extr(data,
true, 0);
2141 *
for(
unsigned int d = 0;
d < dim; ++
d)
2142 * tmp[
d] = make_vectorized_array<Number>(1.0);
2145 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
2146 * phi_old_extr.reinit(face);
2147 * phi_old_extr.gather_evaluate(u_extr,
true,
false);
2151 *
const auto coef_jump = C_u*
std::abs((phi.get_normal_vector(0) * phi.inverse_jacobian(0))[dim - 1]);
2154 *
const double coef_trasp = 0.0;
2157 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i) {
2158 *
for(
unsigned int j = 0; j < phi.dofs_per_component; ++j)
2160 * phi.submit_dof_value(tmp, i);
2161 * phi.evaluate(
true,
true);
2164 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
2165 *
const auto& n_plus = phi.get_normal_vector(q);
2166 *
const auto& grad_u_int = phi.get_gradient(q);
2167 *
const auto& u_int = phi.get_value(q);
2168 *
const auto& tensor_product_u_int =
outer_product(phi.get_value(q), phi_old_extr.get_value(q));
2171 * phi.submit_value(a22/Re*(-grad_u_int*n_plus + 2.0*coef_jump*u_int) +
2172 * a22*coef_trasp*tensor_product_u_int*n_plus + a22*lambda*u_int, q);
2173 * phi.submit_normal_derivative(-theta_v*a22/Re*u_int, q);
2175 * phi.integrate(
true,
true);
2176 *
diagonal[i] = phi.get_dof_value(i);
2178 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i)
2179 * phi.submit_dof_value(
diagonal[i], i);
2180 * phi.distribute_local_to_global(dst);
2184 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i) {
2185 *
for(
unsigned int j = 0; j < phi.dofs_per_component; ++j)
2187 * phi.submit_dof_value(tmp, i);
2188 * phi.evaluate(
true,
true);
2191 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
2192 *
const auto& n_plus = phi.get_normal_vector(q);
2193 *
const auto& grad_u_int = phi.get_gradient(q);
2194 *
const auto& u_int = phi.get_value(q);
2197 *
const auto& point_vectorized = phi.quadrature_point(q);
2198 *
auto u_int_m = u_int;
2199 *
auto grad_u_int_m = grad_u_int;
2200 *
for(
unsigned int v = 0; v < VectorizedArray<Number>::size(); ++v) {
2202 *
for(
unsigned int d = 0;
d < dim; ++
d)
2203 *
point[
d] = point_vectorized[
d][v];
2205 * u_int_m[1][v] = -u_int_m[1][v];
2207 * grad_u_int_m[0][0][v] = -grad_u_int_m[0][0][v];
2208 * grad_u_int_m[0][1][v] = -grad_u_int_m[0][1][v];
2211 * phi.submit_value(a22/Re*(-(0.5*(grad_u_int + grad_u_int_m))*n_plus + coef_jump*(u_int - u_int_m)) +
2212 * a22*
outer_product(0.5*(u_int + u_int_m), phi_old_extr.get_value(q))*n_plus +
2213 * a22*0.5*
lambda*(u_int - u_int_m), q);
2214 * phi.submit_normal_derivative(-theta_v*a22/Re*(u_int - u_int_m), q);
2216 * phi.integrate(
true,
true);
2217 *
diagonal[i] = phi.get_dof_value(i);
2219 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i)
2220 * phi.submit_dof_value(
diagonal[i], i);
2221 * phi.distribute_local_to_global(dst);
2227 * phi_extr(data,
true, 0);
2231 *
for(
unsigned int d = 0;
d < dim; ++
d)
2232 * tmp[
d] = make_vectorized_array<Number>(1.0);
2235 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
2236 * phi_extr.reinit(face);
2237 * phi_extr.gather_evaluate(u_extr,
true,
false);
2241 *
const auto coef_jump = C_u*
std::abs((phi.get_normal_vector(0) * phi.inverse_jacobian(0))[dim - 1]);
2244 *
const double coef_trasp = 0.0;
2247 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i) {
2248 *
for(
unsigned int j = 0; j < phi.dofs_per_component; ++j)
2250 * phi.submit_dof_value(tmp, i);
2251 * phi.evaluate(
true,
true);
2254 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
2255 *
const auto& n_plus = phi.get_normal_vector(q);
2256 *
const auto& grad_u = phi.get_gradient(q);
2257 *
const auto& u = phi.get_value(q);
2258 *
const auto& tensor_product_u =
outer_product(phi.get_value(q), phi_extr.get_value(q));
2261 * phi.submit_value(a33/Re*(-grad_u*n_plus + 2.0*coef_jump*u) +
2262 * a33*coef_trasp*tensor_product_u*n_plus + a33*lambda*u, q);
2263 * phi.submit_normal_derivative(-theta_v*a33/Re*u, q);
2265 * phi.integrate(
true,
true);
2266 *
diagonal[i] = phi.get_dof_value(i);
2268 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i)
2269 * phi.submit_dof_value(
diagonal[i], i);
2270 * phi.distribute_local_to_global(dst);
2274 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i) {
2275 *
for(
unsigned int j = 0; j < phi.dofs_per_component; ++j)
2277 * phi.submit_dof_value(tmp, i);
2278 * phi.evaluate(
true,
true);
2281 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
2282 *
const auto& n_plus = phi.get_normal_vector(q);
2283 *
const auto& grad_u = phi.get_gradient(q);
2284 *
const auto& u = phi.get_value(q);
2287 *
const auto& point_vectorized = phi.quadrature_point(q);
2289 *
auto grad_u_m = grad_u;
2290 *
for(
unsigned int v = 0; v < VectorizedArray<Number>::size(); ++v) {
2292 *
for(
unsigned int d = 0;
d < dim; ++
d)
2293 *
point[
d] = point_vectorized[
d][v];
2295 * u_m[1][v] = -u_m[1][v];
2297 * grad_u_m[0][0][v] = -grad_u_m[0][0][v];
2298 * grad_u_m[0][1][v] = -grad_u_m[0][1][v];
2301 * phi.submit_value(a33/Re*(-(0.5*(grad_u + grad_u_m))*n_plus + coef_jump*(u - u_m)) +
2302 * a33*
outer_product(0.5*(u + u_m), phi_extr.get_value(q))*n_plus +
2303 * a33*0.5*
lambda*(u - u_m), q);
2304 * phi.submit_normal_derivative(-theta_v*a33/Re*(u - u_m), q);
2306 * phi.integrate(
true,
true);
2307 *
diagonal[i] = phi.get_dof_value(i);
2309 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i)
2310 * phi.submit_dof_value(
diagonal[i], i);
2311 * phi.distribute_local_to_global(dst);
2320 * Now we consider the pressure related bilinear forms. We
first assemble diagonal cell term
for the pressure
2326 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
2327 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
2330 *
const unsigned int& ,
2331 *
const std::pair<unsigned int, unsigned int>& cell_range)
const {
2338 *
const double coeff = (TR_BDF2_stage == 1) ? 1e6*
gamma*dt*
gamma*dt : 1e6*(1.0 -
gamma)*dt*(1.0 -
gamma)*dt;
2341 *
for(
unsigned int cell = cell_range.first; cell < cell_range.second; ++cell) {
2345 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i) {
2346 *
for(
unsigned int j = 0; j < phi.dofs_per_component; ++j)
2348 * phi.submit_dof_value(make_vectorized_array<Number>(1.0), i);
2351 * phi.evaluate(
true,
true);
2354 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
2355 * phi.submit_value(1.0/coeff*phi.get_value(q), q);
2356 * phi.submit_gradient(phi.get_gradient(q), q);
2358 * phi.integrate(
true,
true);
2359 *
diagonal[i] = phi.get_dof_value(i);
2361 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i)
2362 * phi.submit_dof_value(
diagonal[i], i);
2364 * phi.distribute_local_to_global(dst);
2371 * The following function assembles
diagonal face term
for the pressure
2377 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
2378 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
2381 *
const unsigned int& ,
2382 *
const std::pair<unsigned int, unsigned int>& face_range)
const {
2384 * phi_m(data,
false, 1, 1);
2386 *
AssertDimension(phi_p.dofs_per_component, phi_m.dofs_per_component);
2388 * diagonal_m(phi_m.dofs_per_component);
2393 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
2394 * phi_p.reinit(face);
2395 * phi_m.reinit(face);
2397 *
const auto coef_jump = C_p*0.5*(
std::abs((phi_p.get_normal_vector(0)*phi_p.inverse_jacobian(0))[dim - 1]) +
2398 *
std::abs((phi_m.get_normal_vector(0)*phi_m.inverse_jacobian(0))[dim - 1]));
2401 *
for(
unsigned int i = 0; i < phi_p.dofs_per_component; ++i) {
2402 *
for(
unsigned int j = 0; j < phi_p.dofs_per_component; ++j) {
2406 * phi_p.submit_dof_value(make_vectorized_array<Number>(1.0), i);
2407 * phi_m.submit_dof_value(make_vectorized_array<Number>(1.0), i);
2408 * phi_p.evaluate(
true,
true);
2409 * phi_m.evaluate(
true,
true);
2412 *
for(
unsigned int q = 0; q < phi_p.n_q_points; ++q) {
2413 *
const auto& n_plus = phi_p.get_normal_vector(q);
2415 *
const auto& avg_grad_pres = 0.5*(phi_p.get_gradient(q) + phi_m.get_gradient(q));
2416 *
const auto& jump_pres = phi_p.get_value(q) - phi_m.get_value(q);
2418 * phi_p.submit_value(-
scalar_product(avg_grad_pres, n_plus) + coef_jump*jump_pres, q);
2419 * phi_m.submit_value(
scalar_product(avg_grad_pres, n_plus) - coef_jump*jump_pres, q);
2420 * phi_p.submit_gradient(-theta_p*0.5*jump_pres*n_plus, q);
2421 * phi_m.submit_gradient(-theta_p*0.5*jump_pres*n_plus, q);
2423 * phi_p.integrate(
true,
true);
2424 * diagonal_p[i] = phi_p.get_dof_value(i);
2425 * phi_m.integrate(
true,
true);
2426 * diagonal_m[i] = phi_m.get_dof_value(i);
2428 *
for(
unsigned int i = 0; i < phi_p.dofs_per_component; ++i) {
2429 * phi_p.submit_dof_value(diagonal_p[i], i);
2430 * phi_m.submit_dof_value(diagonal_m[i], i);
2432 * phi_p.distribute_local_to_global(dst);
2433 * phi_m.distribute_local_to_global(dst);
2446 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
2447 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
2450 *
const unsigned int& ,
2451 *
const std::pair<unsigned int, unsigned int>& face_range)
const {
2456 *
for(
unsigned int face = face_range.first; face < face_range.second; ++face) {
2459 *
const auto coef_jump = C_p*
std::abs((phi.get_normal_vector(0)*phi.inverse_jacobian(0))[dim - 1]);
2464 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i) {
2465 *
for(
unsigned int j = 0; j < phi.dofs_per_component; ++j)
2467 * phi.submit_dof_value(make_vectorized_array<Number>(1.0), i);
2468 * phi.evaluate(
true,
true);
2470 *
for(
unsigned int q = 0; q < phi.n_q_points; ++q) {
2471 *
const auto& n_plus = phi.get_normal_vector(q);
2473 *
const auto& grad_pres = phi.get_gradient(q);
2474 *
const auto& pres = phi.get_value(q);
2476 * phi.submit_value(-
scalar_product(grad_pres, n_plus) + 2.0*coef_jump*pres , q);
2477 * phi.submit_normal_derivative(-theta_p*pres, q);
2479 * phi.integrate(
true,
true);
2480 *
diagonal[i] = phi.get_dof_value(i);
2482 *
for(
unsigned int i = 0; i < phi.dofs_per_component; ++i)
2483 * phi.submit_dof_value(
diagonal[i], i);
2484 * phi.distribute_local_to_global(dst);
2492 * Put together all previous steps. We create a dummy auxliary vector that serves
for the src input argument in
2493 * the previous
functions that as we have seen before is unused. Then everything is done by the
'loop' function
2494 * and it is saved in the field
'inverse_diagonal_entries' already present in the base
class. Anyway since there is
2495 * only
one field, we need to resize properly depending on whether we are considering the velocity or the pressure.
2501 *
template<
int dim,
int fe_degree_p,
int fe_degree_v,
int n_q_po
ints_1d_p,
int n_q_po
ints_1d_v,
typename Vec,
typename Number>
2502 *
void NavierStokesProjectionOperator<dim, fe_degree_p, fe_degree_v, n_q_points_1d_p, n_q_points_1d_v, Vec, Number>::
2505 *
if(NS_stage == 1) {
2507 *
auto& inverse_diagonal = this->inverse_diagonal_entries->get_vector();
2509 *
const unsigned int dummy = 0;
2511 * this->data->
loop(&NavierStokesProjectionOperator::assemble_diagonal_cell_term_velocity,
2512 * &NavierStokesProjectionOperator::assemble_diagonal_face_term_velocity,
2513 * &NavierStokesProjectionOperator::assemble_diagonal_boundary_term_velocity,
2514 *
this, inverse_diagonal, dummy,
false,
2518 *
for(
unsigned int i = 0; i < inverse_diagonal.locally_owned_size(); ++i) {
2519 *
Assert(inverse_diagonal.local_element(i) != 0.0,
2520 *
ExcMessage(
"No diagonal entry in a definite operator should be zero"));
2521 * inverse_diagonal.local_element(i) = 1.0/inverse_diagonal.local_element(i);
2524 *
else if(NS_stage == 2) {
2526 *
auto& inverse_diagonal = this->inverse_diagonal_entries->get_vector();
2528 *
const unsigned int dummy = 0;
2530 * this->data->
loop(&NavierStokesProjectionOperator::assemble_diagonal_cell_term_pressure,
2531 * &NavierStokesProjectionOperator::assemble_diagonal_face_term_pressure,
2532 * &NavierStokesProjectionOperator::assemble_diagonal_boundary_term_pressure,
2533 *
this, inverse_diagonal, dummy,
false,
2537 *
for(
unsigned int i = 0; i < inverse_diagonal.locally_owned_size(); ++i) {
2538 *
Assert(inverse_diagonal.local_element(i) != 0.0,
2539 *
ExcMessage(
"No diagonal entry in a definite operator should be zero"));
2540 * inverse_diagonal.local_element(i) = 1.0/inverse_diagonal.local_element(i);
2550 * @sect{The <code>NavierStokesProjection</code>
class}
2554 * Now we are ready
for the main
class of the program. It
implements the calls to the various steps
2555 * of the projection method for Navier-Stokes equations.
2562 * class NavierStokesProjection {
2564 * NavierStokesProjection(RunTimeParameters::Data_Storage& data);
2566 *
void run(
const bool verbose =
false,
const unsigned int output_interval = 10);
2571 *
const double gamma;
2572 *
unsigned int TR_BDF2_stage;
2576 * EquationData::Velocity<dim> vel_init;
2577 * EquationData::Pressure<dim> pres_init;
2615 * <<
" The time step " << arg1 <<
" is out of range."
2617 * <<
" The permitted range is (0," << arg2 <<
"]");
2621 *
void setup_dofs();
2623 *
void initialize();
2625 *
void interpolate_velocity();
2627 *
void diffusion_step();
2629 *
void projection_step();
2631 *
void project_grad(
const unsigned int flag);
2633 *
double get_maximal_velocity();
2635 *
double get_maximal_difference();
2637 *
void output_results(
const unsigned int step);
2639 *
void refine_mesh();
2641 *
void interpolate_max_res(
const unsigned int level);
2643 *
void save_max_res();
2646 *
void compute_lift_and_drag();
2649 * std::shared_ptr<MatrixFree<dim, double>> matrix_free_storage;
2652 * NavierStokesProjectionOperator<dim, EquationData::degree_p, EquationData::degree_p + 1,
2653 * EquationData::degree_p + 1, EquationData::degree_p + 2,
2657 *
MGLevelObject<NavierStokesProjectionOperator<dim, EquationData::degree_p, EquationData::degree_p + 1,
2658 * EquationData::degree_p + 1, EquationData::degree_p + 2,
2667 * constraints_pressure;
2670 *
unsigned int max_its;
2673 *
unsigned int max_loc_refinements;
2674 *
unsigned int min_loc_refinements;
2675 *
unsigned int refinement_iterations;
2677 * std::string saving_dir;
2682 * std::ofstream time_out;
2686 * std::ofstream output_n_dofs_velocity;
2687 * std::ofstream output_n_dofs_pressure;
2689 * std::ofstream output_lift;
2690 * std::ofstream output_drag;
2696 * In the constructor, we just read all the data from the
2697 * <code>Data_Storage</code>
object that is passed as an argument, verify that
2698 * the data we read are reasonable and,
finally, create the
triangulation and
2706 * NavierStokesProjection<dim>::NavierStokesProjection(RunTimeParameters::Data_Storage& data):
2707 * t_0(data.initial_time),
2708 *
T(data.final_time),
2711 * Re(data.Reynolds),
2713 * vel_init(data.initial_time),
2714 * pres_init(data.initial_time),
2717 * fe_velocity(
FE_DGQ<dim>(EquationData::degree_p + 1), dim),
2718 * fe_pressure(
FE_DGQ<dim>(EquationData::degree_p), 1),
2721 * quadrature_pressure(EquationData::degree_p + 1),
2722 * quadrature_velocity(EquationData::degree_p + 2),
2723 * navier_stokes_matrix(data),
2724 * max_its(data.max_iterations),
2726 * max_loc_refinements(data.max_loc_refinements),
2727 * min_loc_refinements(data.min_loc_refinements),
2728 * refinement_iterations(data.refinement_iterations),
2729 * saving_dir(data.dir),
2731 * time_out(
"./" + data.dir +
"/time_analysis_" +
2735 * output_n_dofs_velocity(
"./" + data.dir +
"/n_dofs_velocity.dat",
std::ofstream::out),
2736 * output_n_dofs_pressure(
"./" + data.dir +
"/n_dofs_pressure.dat",
std::ofstream::out),
2737 * output_lift(
"./" + data.dir +
"/lift.dat",
std::ofstream::out),
2738 * output_drag(
"./" + data.dir +
"/drag.dat",
std::ofstream::out) {
2739 *
if(EquationData::degree_p < 1) {
2741 * <<
" WARNING: The chosen pair of finite element spaces is not stable."
2743 * <<
" The obtained results will be nonsense" << std::endl;
2746 *
AssertThrow(!((dt <= 0.0) || (dt > 0.5*
T)), ExcInvalidTimeStep(dt, 0.5*
T));
2748 * matrix_free_storage = std::make_shared<MatrixFree<dim, double>>();
2758 * The method that creates the
triangulation and refines it the needed number
2769 *
GridGenerator::plate_with_a_hole(
triangulation, 0.5, 1.0, 1.0, 1.1, 1.0, 19.0,
Point<2>(2.0, 2.0), 0, 1, 1.0, 2,
true);
2772 * pcout <<
"Number of refines = " << n_refines << std::endl;
2779 * After creating the
triangulation, it creates the mesh dependent
2780 * data, i.e. it distributes degrees of freedom, and
2781 * initializes the vectors that we will use.
2788 *
void NavierStokesProjection<dim>::setup_dofs() {
2789 * pcout <<
"Number of active cells: " <<
triangulation.n_global_active_cells() << std::endl;
2790 * pcout <<
"Number of levels: " <<
triangulation.n_global_levels() << std::endl;
2793 * dof_handler_velocity.distribute_dofs(fe_velocity);
2794 * dof_handler_pressure.distribute_dofs(fe_pressure);
2796 * pcout <<
"dim (X_h) = " << dof_handler_velocity.n_dofs()
2798 * <<
"dim (M_h) = " << dof_handler_pressure.n_dofs()
2800 * <<
"Re = " << Re << std::endl
2804 * output_n_dofs_velocity << dof_handler_velocity.n_dofs() << std::endl;
2805 * output_n_dofs_pressure << dof_handler_pressure.n_dofs() << std::endl;
2817 * std::vector<const DoFHandler<dim>*> dof_handlers;
2820 * dof_handlers.push_back(&dof_handler_velocity);
2821 * dof_handlers.push_back(&dof_handler_pressure);
2823 * constraints_velocity.
clear();
2824 * constraints_velocity.close();
2825 * constraints_pressure.clear();
2826 * constraints_pressure.close();
2827 * std::vector<const AffineConstraints<double>*> constraints;
2828 * constraints.push_back(&constraints_velocity);
2829 * constraints.push_back(&constraints_pressure);
2831 * std::vector<QGauss<1>> quadratures;
2835 * quadratures.push_back(
QGauss<1>(EquationData::degree_p + 2));
2836 * quadratures.push_back(
QGauss<1>(EquationData::degree_p + 1));
2840 * matrix_free_storage->reinit(
MappingQ1<dim>(),dof_handlers, constraints, quadratures, additional_data);
2841 * matrix_free_storage->initialize_dof_vector(u_star, 0);
2842 * matrix_free_storage->initialize_dof_vector(rhs_u, 0);
2843 * matrix_free_storage->initialize_dof_vector(u_n, 0);
2844 * matrix_free_storage->initialize_dof_vector(u_extr, 0);
2845 * matrix_free_storage->initialize_dof_vector(u_n_minus_1, 0);
2846 * matrix_free_storage->initialize_dof_vector(u_n_gamma, 0);
2847 * matrix_free_storage->initialize_dof_vector(u_tmp, 0);
2848 * matrix_free_storage->initialize_dof_vector(grad_pres_int, 0);
2850 * matrix_free_storage->initialize_dof_vector(pres_int, 1);
2851 * matrix_free_storage->initialize_dof_vector(pres_n, 1);
2852 * matrix_free_storage->initialize_dof_vector(rhs_p, 1);
2858 * mg_matrices.clear_elements();
2859 * dof_handler_velocity.distribute_mg_dofs();
2860 * dof_handler_pressure.distribute_mg_dofs();
2862 *
const unsigned int nlevels =
triangulation.n_global_levels();
2863 * mg_matrices.resize(0, nlevels - 1);
2872 * std::vector<const DoFHandler<dim>*> dof_handlers_mg;
2873 * dof_handlers_mg.push_back(&dof_handler_velocity);
2874 * dof_handlers_mg.push_back(&dof_handler_pressure);
2875 * std::vector<const AffineConstraints<float>*> constraints_mg;
2877 * constraints_velocity_mg.
clear();
2878 * constraints_velocity_mg.
close();
2879 * constraints_mg.push_back(&constraints_velocity_mg);
2881 * constraints_pressure_mg.
clear();
2882 * constraints_pressure_mg.
close();
2883 * constraints_mg.push_back(&constraints_pressure_mg);
2886 * mg_mf_storage_level->reinit(
MappingQ1<dim>(),dof_handlers_mg, constraints_mg, quadratures, additional_data_mg);
2887 *
const std::vector<unsigned int> tmp = {1};
2888 * mg_matrices[
level].initialize(mg_mf_storage_level, tmp, tmp);
2889 * mg_matrices[
level].set_dt(dt);
2890 * mg_matrices[
level].set_NS_stage(2);
2893 * Linfty_error_per_cell_vel.reinit(
triangulation.n_active_cells());
2899 * This method loads the
initial data. It simply uses the class <code>Pressure</code> instance
for the pressure
2900 * and the class <code>Velocity</code> instance
for the velocity.
2907 *
void NavierStokesProjection<dim>::initialize() {
2919 * This function computes the extrapolated velocity to be used in the momentum predictor
2926 *
void NavierStokesProjection<dim>::interpolate_velocity() {
2931 * --- TR-BDF2
first step
2934 *
if(TR_BDF2_stage == 1) {
2935 * u_extr.equ(1.0 +
gamma/(2.0*(1.0 -
gamma)), u_n);
2936 * u_tmp.equ(
gamma/(2.0*(1.0 -
gamma)), u_n_minus_1);
2941 * --- TR-BDF2
second step
2945 * u_extr.equ(1.0 + (1.0 -
gamma)/
gamma, u_n_gamma);
2954 * We are
finally ready to solve the diffusion step.
2961 *
void NavierStokesProjection<dim>::diffusion_step() {
2966 *
const std::vector<unsigned int> tmp = {0};
2967 * navier_stokes_matrix.initialize(matrix_free_storage, tmp, tmp);
2970 * navier_stokes_matrix.set_NS_stage(1);
2975 *
if(TR_BDF2_stage == 1) {
2976 * navier_stokes_matrix.vmult_rhs_velocity(rhs_u, {u_n, u_extr, pres_n});
2977 * navier_stokes_matrix.set_u_extr(u_extr);
2981 * navier_stokes_matrix.vmult_rhs_velocity(rhs_u, {u_n, u_n_gamma, pres_int, u_extr});
2982 * navier_stokes_matrix.set_u_extr(u_extr);
2992 * EquationData::degree_p,
2993 * EquationData::degree_p + 1,
2994 * EquationData::degree_p + 1,
2995 * EquationData::degree_p + 2,
2997 *
double>> preconditioner;
2998 * navier_stokes_matrix.compute_diagonal();
2999 * preconditioner.initialize(navier_stokes_matrix);
3001 * gmres.solve(navier_stokes_matrix, u_star, rhs_u, preconditioner);
3007 * Next, we solve the projection step.
3014 *
void NavierStokesProjection<dim>::projection_step() {
3019 *
const std::vector<unsigned int> tmp = {1};
3020 * navier_stokes_matrix.initialize(matrix_free_storage, tmp, tmp);
3022 * navier_stokes_matrix.set_NS_stage(2);
3024 *
if(TR_BDF2_stage == 1)
3025 * navier_stokes_matrix.vmult_rhs_pressure(rhs_p, {u_star, pres_n});
3027 * navier_stokes_matrix.vmult_rhs_pressure(rhs_p, {u_star, pres_int});
3035 * mg_transfer.
build(dof_handler_pressure);
3038 * EquationData::degree_p,
3039 * EquationData::degree_p + 1,
3040 * EquationData::degree_p + 1,
3041 * EquationData::degree_p + 2,
3050 * smoother_data[
level].smoothing_range = 15.0;
3051 * smoother_data[
level].degree = 3;
3052 * smoother_data[
level].eig_cg_n_iterations = 10;
3055 * smoother_data[0].smoothing_range = 2
e-2;
3057 * smoother_data[0].eig_cg_n_iterations = mg_matrices[0].m();
3059 * mg_matrices[
level].compute_diagonal();
3060 * smoother_data[
level].preconditioner = mg_matrices[
level].get_matrix_diagonal_inverse();
3062 * mg_smoother.
initialize(mg_matrices, smoother_data);
3068 * NavierStokesProjectionOperator<dim,
3069 * EquationData::degree_p,
3070 * EquationData::degree_p + 1,
3071 * EquationData::degree_p + 1,
3072 * EquationData::degree_p + 2,
3086 *
if(TR_BDF2_stage == 1) {
3087 * pres_int = pres_n;
3088 * cg.solve(navier_stokes_matrix, pres_int, rhs_p, preconditioner);
3091 * pres_n = pres_int;
3092 * cg.solve(navier_stokes_matrix, pres_n, rhs_p, preconditioner);
3099 * This implements the projection step
for the
gradient of pressure
3106 *
void NavierStokesProjection<dim>::project_grad(
const unsigned int flag) {
3114 *
const std::vector<unsigned int> tmp = {0};
3115 * navier_stokes_matrix.initialize(matrix_free_storage, tmp, tmp);
3118 * navier_stokes_matrix.vmult_grad_p_projection(rhs_u, pres_n);
3119 *
else if(flag == 2)
3120 * navier_stokes_matrix.vmult_grad_p_projection(rhs_u, pres_int);
3123 * navier_stokes_matrix.set_NS_stage(3);
3134 * The following function is used in determining the maximal velocity
3135 * in order to compute the Courant number.
3142 *
double NavierStokesProjection<dim>::get_maximal_velocity() {
3153 * The following function is used in determining the maximal nodal difference
3155 * u_n - u_n_minus_1 against the
zero function.
3162 *
double NavierStokesProjection<dim>::get_maximal_difference() {
3164 * u_tmp -= u_n_minus_1;
3169 * pcout <<
"Maximum nodal difference = " << res <<std::endl;
3177 * This method plots the current solution. The main difficulty is that we want
3178 * to create a single output file that contains the data
for all velocity
3179 * components and the pressure. On the other hand, velocities and the pressure
3180 * live on separate
DoFHandler objects, so we need to pay attention when we use
3181 *
'add_data_vector' to select the proper space.
3188 *
void NavierStokesProjection<dim>::output_results(
const unsigned int step) {
3193 * std::vector<std::string> velocity_names(dim,
"v");
3194 * std::vector<DataComponentInterpretation::DataComponentInterpretation>
3196 * u_n.update_ghost_values();
3197 * data_out.
add_data_vector(dof_handler_velocity, u_n, velocity_names, component_interpretation_velocity);
3198 * pres_n.update_ghost_values();
3201 * std::vector<std::string> velocity_names_old(dim,
"v_old");
3202 * u_n_minus_1.update_ghost_values();
3203 * data_out.
add_data_vector(dof_handler_velocity, u_n_minus_1, velocity_names_old, component_interpretation_velocity);
3206 * PostprocessorVorticity<dim> postprocessor;
3220 * @sect{<code>NavierStokesProjection::compute_lift_and_drag</code>}
3224 * This routine computes the lift and the drag forces in a non-dimensional framework
3225 * (so basically
for the classical coefficients, it is necessary to multiply by a factor 2).
3232 *
void NavierStokesProjection<dim>::compute_lift_and_drag() {
3233 *
QGauss<dim - 1> face_quadrature_formula(EquationData::degree_p + 2);
3234 *
const int n_q_points = face_quadrature_formula.size();
3236 * std::vector<double> pressure_values(n_q_points);
3237 * std::vector<std::vector<Tensor<1, dim>>> velocity_gradients(n_q_points, std::vector<
Tensor<1, dim>>(dim));
3246 *
FEFaceValues<dim> fe_face_values_velocity(fe_velocity, face_quadrature_formula,
3251 *
double local_drag = 0.0;
3252 *
double local_lift = 0.0;
3258 *
auto tmp_cell = dof_handler_pressure.begin_active();
3259 *
for(
const auto& cell : dof_handler_velocity.active_cell_iterators()) {
3260 *
if(cell->is_locally_owned()) {
3261 *
for(
unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face) {
3262 *
if(cell->face(face)->at_boundary() && cell->face(face)->boundary_id() == 4) {
3263 * fe_face_values_velocity.reinit(cell, face);
3264 * fe_face_values_pressure.reinit(tmp_cell, face);
3266 * fe_face_values_velocity.get_function_gradients(u_n, velocity_gradients);
3267 * fe_face_values_pressure.get_function_values(pres_n, pressure_values);
3269 *
for(
int q = 0; q < n_q_points; q++) {
3270 * normal_vector = -fe_face_values_velocity.normal_vector(q);
3272 *
for(
unsigned int d = 0;
d < dim; ++
d) {
3273 * fluid_pressure[
d][
d] = pressure_values[q];
3274 *
for(
unsigned int k = 0; k < dim; ++k)
3275 * fluid_stress[
d][k] = 1.0/Re*velocity_gradients[q][
d][k];
3277 * fluid_stress = fluid_stress - fluid_pressure;
3279 * forces = fluid_stress*normal_vector*fe_face_values_velocity.JxW(q);
3281 * local_drag += forces[0];
3282 * local_lift += forces[1];
3295 * output_lift << lift << std::endl;
3296 * output_drag << drag << std::endl;
3305 * @sect{ <code>NavierStokesProjection::refine_mesh</code>}
3309 * After finding a good
initial guess on the coarse mesh, we hope to
3310 * decrease the error through refining the mesh. We also need to transfer the current solution to the
3317 *
template <
int dim>
3318 *
void NavierStokesProjection<dim>::refine_mesh() {
3325 * tmp_velocity.
reinit(dof_handler_velocity.locally_owned_dofs(), locally_relevant_dofs, MPI_COMM_WORLD);
3326 * tmp_velocity = u_n;
3334 *
auto cell_worker = [&](
const Iterator& cell,
3335 * ScratchData<dim>& scratch_data,
3336 * CopyData& copy_data) {
3338 * fe_values.
reinit(cell);
3343 * copy_data.cell_index = cell->active_cell_index();
3344 *
double vorticity_norm_square = 0.0;
3349 * vorticity_norm_square += vorticity*vorticity*fe_values.
JxW(k);
3351 * copy_data.value = cell->diameter()*cell->diameter()*vorticity_norm_square;
3356 *
auto copier = [&](
const CopyData ©_data) {
3358 * estimated_error_per_cell[copy_data.cell_index] += copy_data.value;
3362 * ScratchData scratch_data(fe_velocity, EquationData::degree_p + 2, cell_flags);
3363 * CopyData copy_data;
3365 * dof_handler_velocity.end(),
3375 *
for(
const auto& cell:
triangulation.active_cell_iterators()) {
3376 *
if(cell->refine_flag_set() &&
static_cast<unsigned int>(cell->level()) == max_loc_refinements)
3377 * cell->clear_refine_flag();
3378 *
if(cell->coarsen_flag_set() &&
static_cast<unsigned int>(cell->level()) == min_loc_refinements)
3379 * cell->clear_coarsen_flag();
3386 * std::vector<const LinearAlgebra::distributed::Vector<double>*> velocities;
3387 * velocities.push_back(&u_n);
3388 * velocities.push_back(&u_n_minus_1);
3390 * solution_transfer_velocity(dof_handler_velocity);
3391 * solution_transfer_velocity.prepare_for_coarsening_and_refinement(velocities);
3393 * solution_transfer_pressure(dof_handler_pressure);
3394 * solution_transfer_pressure.prepare_for_coarsening_and_refinement(pres_n);
3405 * transfer_velocity_minus_1,
3406 * transfer_pressure;
3407 * transfer_velocity.
reinit(u_n);
3409 * transfer_velocity_minus_1.
reinit(u_n_minus_1);
3411 * transfer_pressure.
reinit(pres_n);
3414 * std::vector<LinearAlgebra::distributed::Vector<double>*> transfer_velocities;
3415 * transfer_velocities.push_back(&transfer_velocity);
3416 * transfer_velocities.push_back(&transfer_velocity_minus_1);
3417 * solution_transfer_velocity.interpolate(transfer_velocities);
3420 * solution_transfer_pressure.interpolate(transfer_pressure);
3423 * u_n = transfer_velocity;
3424 * u_n_minus_1 = transfer_velocity_minus_1;
3425 * pres_n = transfer_pressure;
3431 * Interpolate the locally refined solution to a mesh with maximal resolution
3432 * and transfer velocity and pressure.
3439 *
void NavierStokesProjection<dim>::interpolate_max_res(
const unsigned int level) {
3441 * solution_transfer_velocity(dof_handler_velocity);
3442 * std::vector<const LinearAlgebra::distributed::Vector<double>*> velocities;
3443 * velocities.push_back(&u_n);
3444 * velocities.push_back(&u_n_minus_1);
3445 * solution_transfer_velocity.prepare_for_coarsening_and_refinement(velocities);
3448 * solution_transfer_pressure(dof_handler_pressure);
3449 * solution_transfer_pressure.prepare_for_coarsening_and_refinement(pres_n);
3452 *
if(cell->is_locally_owned())
3453 * cell->set_refine_flag();
3460 * transfer_pressure;
3462 * transfer_velocity.
reinit(u_n);
3464 * transfer_velocity_minus_1.
reinit(u_n_minus_1);
3467 * transfer_pressure.
reinit(pres_n);
3470 * std::vector<LinearAlgebra::distributed::Vector<double>*> transfer_velocities;
3472 * transfer_velocities.push_back(&transfer_velocity);
3473 * transfer_velocities.push_back(&transfer_velocity_minus_1);
3474 * solution_transfer_velocity.interpolate(transfer_velocities);
3478 * solution_transfer_pressure.interpolate(transfer_pressure);
3481 * u_n = transfer_velocity;
3482 * u_n_minus_1 = transfer_velocity_minus_1;
3483 * pres_n = transfer_pressure;
3489 * Save maximum resolution to a mesh adapted.
3496 *
void NavierStokesProjection<dim>::save_max_res() {
3498 *
GridGenerator::plate_with_a_hole(triangulation_tmp, 0.5, 1.0, 1.0, 1.1, 1.0, 19.0,
Point<2>(2.0, 2.0), 0, 1, 1.0, 2,
true);
3499 * triangulation_tmp.refine_global(
triangulation.n_global_levels() - 1);
3503 * dof_handler_velocity_tmp.distribute_dofs(fe_velocity);
3504 * dof_handler_pressure_tmp.distribute_dofs(fe_pressure);
3508 * u_n_tmp.
reinit(dof_handler_velocity_tmp.n_dofs());
3509 * pres_n_tmp.
reinit(dof_handler_pressure_tmp.n_dofs());
3512 * std::vector<std::string> velocity_names(dim,
"v");
3513 * std::vector<DataComponentInterpretation::DataComponentInterpretation>
3517 * data_out.
add_data_vector(dof_handler_velocity_tmp, u_n_tmp, velocity_names, component_interpretation_velocity);
3521 * PostprocessorVorticity<dim> postprocessor;
3522 * data_out.
add_data_vector(dof_handler_velocity_tmp, u_n_tmp, postprocessor);
3525 *
const std::string output =
"./" + saving_dir +
"/solution_max_res_end.vtu";
3538 * This is the time marching function, which starting at <code>t_0</code>
3539 * advances in time
using the projection method with time step <code>dt</code>
3540 * until <code>
T</code>.
3544 * Its
second parameter, <code>verbose</code> indicates whether the function
3545 * should output information what it is doing at any given moment:
3556 * output_results(1);
3557 *
double time = t_0 + dt;
3558 *
unsigned int n = 1;
3562 * pcout <<
"Step = " << n <<
" Time = " << time << std::endl;
3565 * TR_BDF2_stage = 1;
3566 * navier_stokes_matrix.set_TR_BDF2_stage(TR_BDF2_stage);
3568 * mg_matrices[
level].set_TR_BDF2_stage(TR_BDF2_stage);
3570 * verbose_cout <<
" Interpolating the velocity stage 1" << std::endl;
3571 * interpolate_velocity();
3573 * verbose_cout <<
" Diffusion Step stage 1 " << std::endl;
3576 * verbose_cout <<
" Projection Step stage 1" << std::endl;
3578 * u_tmp.equ(
gamma*dt, u_tmp);
3580 * projection_step();
3582 * verbose_cout <<
" Updating the Velocity stage 1" << std::endl;
3583 * u_n_gamma.equ(1.0, u_star);
3585 * grad_pres_int.equ(1.0, u_tmp);
3586 * u_tmp.equ(-
gamma*dt, u_tmp);
3587 * u_n_gamma += u_tmp;
3588 * u_n_minus_1 = u_n;
3591 * TR_BDF2_stage = 2;
3593 * mg_matrices[
level].set_TR_BDF2_stage(TR_BDF2_stage);
3594 * navier_stokes_matrix.set_TR_BDF2_stage(TR_BDF2_stage);
3596 * verbose_cout <<
" Interpolating the velocity stage 2" << std::endl;
3597 * interpolate_velocity();
3599 * verbose_cout <<
" Diffusion Step stage 2 " << std::endl;
3602 * verbose_cout <<
" Projection Step stage 2" << std::endl;
3603 * u_tmp.equ((1.0 -
gamma)*dt, grad_pres_int);
3605 * projection_step();
3607 * verbose_cout <<
" Updating the Velocity stage 2" << std::endl;
3608 * u_n.equ(1.0, u_star);
3610 * u_tmp.equ((
gamma - 1.0)*dt, u_tmp);
3613 *
const double max_vel = get_maximal_velocity();
3614 * pcout<<
"Maximal velocity = " << max_vel << std::endl;
3616 * pcout <<
"CFL = " << dt*max_vel*(EquationData::degree_p + 1)*
3618 * compute_lift_and_drag();
3619 *
if(n % output_interval == 0) {
3620 * verbose_cout <<
"Plotting Solution final" << std::endl;
3621 * output_results(n);
3624 *
if(
T - time < dt && T - time > 1
e-10) {
3626 * navier_stokes_matrix.set_dt(dt);
3628 * mg_matrices[
level].set_dt(dt);
3631 *
if(refinement_iterations > 0 && n % refinement_iterations == 0) {
3632 * verbose_cout <<
"Refining mesh" << std::endl;
3636 *
if(n % output_interval != 0) {
3637 * verbose_cout <<
"Plotting Solution final" << std::endl;
3638 * output_results(n);
3640 *
if(refinement_iterations > 0) {
3641 *
for(
unsigned int lev = 0; lev <
triangulation.n_global_levels() - 1; ++ lev)
3642 * interpolate_max_res(lev);
3654 * @sect{ The main function }
3658 * The main function looks very much like in all the other tutorial programs. We
first initialize MPI,
3659 * we initialize the
class 'NavierStokesProjection' with the dimension as template parameter and then
3660 * let the method
'run' do the job.
3666 *
int main(
int argc,
char *argv[]) {
3668 *
using namespace NS_TRBDF2;
3670 * RunTimeParameters::Data_Storage data;
3671 * data.read_data(
"parameter-file.prm");
3678 * NavierStokesProjection<2> test(data);
3679 * test.run(data.verbose, data.output_interval);
3681 *
if(curr_rank == 0)
3682 * std::cout <<
"----------------------------------------------------"
3684 * <<
"Apparently everything went fine!" << std::endl
3685 * <<
"Don't forget to brush your teeth :-)" << std::endl
3690 *
catch(std::exception &exc) {
3691 * std::cerr << std::endl
3693 * <<
"----------------------------------------------------"
3695 * std::cerr <<
"Exception on processing: " << std::endl
3696 * << exc.what() << std::endl
3697 * <<
"Aborting!" << std::endl
3698 * <<
"----------------------------------------------------"
3703 * std::cerr << std::endl
3705 * <<
"----------------------------------------------------"
3707 * std::cerr <<
"Unknown exception!" << std::endl
3708 * <<
"Aborting!" << std::endl
3709 * <<
"----------------------------------------------------"
3718<a name=
"ann-runtime_parameters.h"></a>
3719<h1>Annotated version of runtime_parameters.h</h1>
3723 * We start by including all the necessary deal.II header files
3729 * #include <deal.II/base/parameter_handler.h>
3735 * @sect{Run time parameters}
3739 * Since our method has several parameters that can be fine-tuned we put them
3740 * into an external file, so that they can be determined at
run-time.
3746 *
namespace RunTimeParameters {
3747 *
using namespace dealii;
3749 *
class Data_Storage {
3753 *
void read_data(
const std::string& filename);
3755 *
double initial_time;
3756 *
double final_time;
3761 *
unsigned int n_refines;
3762 *
unsigned int max_loc_refinements;
3763 *
unsigned int min_loc_refinements;
3767 *
unsigned int max_iterations;
3771 *
unsigned int output_interval;
3775 *
unsigned int refinement_iterations;
3783 * In the constructor of
this class we declare all the parameters in suitable (but arbitrary) subsections.
3789 * Data_Storage::Data_Storage(): initial_time(0.0),
3794 * max_loc_refinements(0),
3795 * min_loc_refinements(0),
3796 * max_iterations(1000),
3799 * output_interval(15),
3800 * refinement_iterations(0) {
3801 * prm.enter_subsection(
"Physical data");
3803 * prm.declare_entry(
"initial_time",
3806 *
" The initial time of the simulation. ");
3807 * prm.declare_entry(
"final_time",
3810 *
" The final time of the simulation. ");
3811 * prm.declare_entry(
"Reynolds",
3814 *
" The Reynolds number. ");
3816 * prm.leave_subsection();
3818 * prm.enter_subsection(
"Time step data");
3820 * prm.declare_entry(
"dt",
3823 *
" The time step size. ");
3825 * prm.leave_subsection();
3827 * prm.enter_subsection(
"Space discretization");
3829 * prm.declare_entry(
"n_of_refines",
3832 *
" The number of cells we want on each direction of the mesh. ");
3833 * prm.declare_entry(
"max_loc_refinements",
3836 *
" The number of maximum local refinements. ");
3837 * prm.declare_entry(
"min_loc_refinements",
3840 *
" The number of minimum local refinements. ");
3842 * prm.leave_subsection();
3844 * prm.enter_subsection(
"Data solve");
3846 * prm.declare_entry(
"max_iterations",
3849 *
" The maximal number of iterations linear solvers must make. ");
3850 * prm.declare_entry(
"eps",
3853 *
" The stopping criterion. ");
3855 * prm.leave_subsection();
3857 * prm.declare_entry(
"refinement_iterations",
3860 *
" This number indicates how often we need to "
3861 *
"refine the mesh");
3863 * prm.declare_entry(
"saving directory",
"SimTest");
3865 * prm.declare_entry(
"verbose",
3868 *
" This indicates whether the output of the solution "
3869 *
"process should be verbose. ");
3871 * prm.declare_entry(
"output_interval",
3874 *
" This indicates between how many time steps we print "
3875 *
"the solution. ");
3880 * We need now a routine to read all declared parameters in the constructor
3886 *
void Data_Storage::read_data(
const std::string& filename) {
3887 * std::ifstream file(filename);
3890 * prm.parse_input(file);
3892 * prm.enter_subsection(
"Physical data");
3894 * initial_time = prm.get_double(
"initial_time");
3895 * final_time = prm.get_double(
"final_time");
3896 * Reynolds = prm.get_double(
"Reynolds");
3898 * prm.leave_subsection();
3900 * prm.enter_subsection(
"Time step data");
3902 * dt = prm.get_double(
"dt");
3904 * prm.leave_subsection();
3906 * prm.enter_subsection(
"Space discretization");
3908 * n_refines = prm.get_integer(
"n_of_refines");
3909 * max_loc_refinements = prm.get_integer(
"max_loc_refinements");
3910 * min_loc_refinements = prm.get_integer(
"min_loc_refinements");
3912 * prm.leave_subsection();
3914 * prm.enter_subsection(
"Data solve");
3916 * max_iterations = prm.get_integer(
"max_iterations");
3917 *
eps = prm.get_double(
"eps");
3919 * prm.leave_subsection();
3921 * dir = prm.get(
"saving directory");
3923 * refinement_iterations = prm.get_integer(
"refinement_iterations");
3925 * verbose = prm.get_bool(
"verbose");
3927 * output_interval = prm.get_integer(
"output_interval");
void add_data_vector(const VectorType &data, const std::vector< std::string > &names, const DataVectorType type=type_automatic, const std::vector< DataComponentInterpretation::DataComponentInterpretation > &data_component_interpretation={})
virtual void build_patches(const unsigned int n_subdivisions=0)
const unsigned int n_quadrature_points
void get_function_gradients(const InputVector &fe_function, std::vector< Tensor< 1, spacedim, typename InputVector::value_type > > &gradients) const
double JxW(const unsigned int quadrature_point) const
void reinit(const TriaIterator< DoFCellAccessor< dim, spacedim, level_dof_access > > &cell)
virtual RangeNumberType value(const Point< dim > &p, const unsigned int component=0) const
virtual void vector_value(const Point< dim > &p, Vector< RangeNumberType > &values) const
unsigned int depth_console(const unsigned int n)
void resize(const unsigned int new_minlevel, const unsigned int new_maxlevel, Args &&...args)
void build(const DoFHandler< dim, dim > &dof_handler, const std::vector< std::shared_ptr< const Utilities::MPI::Partitioner > > &external_partitioners=std::vector< std::shared_ptr< const Utilities::MPI::Partitioner > >())
void loop(const std::function< void(const MatrixFree< dim, Number, VectorizedArrayType > &, OutVector &, const InVector &, const std::pair< unsigned int, unsigned int > &)> &cell_operation, const std::function< void(const MatrixFree< dim, Number, VectorizedArrayType > &, OutVector &, const InVector &, const std::pair< unsigned int, unsigned int > &)> &face_operation, const std::function< void(const MatrixFree< dim, Number, VectorizedArrayType > &, OutVector &, const InVector &, const std::pair< unsigned int, unsigned int > &)> &boundary_operation, OutVector &dst, const InVector &src, const bool zero_dst_vector=false, const DataAccessOnFaces dst_vector_face_access=DataAccessOnFaces::unspecified, const DataAccessOnFaces src_vector_face_access=DataAccessOnFaces::unspecified) const
types::boundary_id get_boundary_id(const unsigned int face_batch_index) const
void initialize_dof_vector(VectorType &vec, const unsigned int dof_handler_index=0) const
void cell_loop(const std::function< void(const MatrixFree< dim, Number, VectorizedArrayType > &, OutVector &, const InVector &, const std::pair< unsigned int, unsigned int > &)> &cell_operation, OutVector &dst, const InVector &src, const bool zero_dst_vector=false) const
void initialize(const MGLevelObject< MatrixType2 > &matrices, const typename RelaxationType::AdditionalData &additional_data=typename RelaxationType::AdditionalData())
@ update_values
Shape function values.
@ update_normal_vectors
Normal vectors.
@ update_JxW_values
Transformed quadrature weights.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
__global__ void set(Number *val, const Number s, const size_type N)
static ::ExceptionBase & ExcFileNotOpen(std::string arg1)
static ::ExceptionBase & ExcNotImplemented()
void write_vtu_in_parallel(const std::string &filename, const MPI_Comm &comm) const
#define Assert(cond, exc)
#define DeclException2(Exception2, type1, type2, outsequence)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
typename ActiveSelector::active_cell_iterator active_cell_iterator
void mesh_loop(const CellIteratorType &begin, const CellIteratorType &end, const CellWorkerFunctionType &cell_worker, const CopierType &copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const AssembleFlags flags=assemble_own_cells, const BoundaryWorkerFunctionType &boundary_worker=BoundaryWorkerFunctionType(), const FaceWorkerFunctionType &face_worker=FaceWorkerFunctionType(), const unsigned int queue_length=2 *MultithreadInfo::n_threads(), const unsigned int chunk_size=8)
void loop(ITERATOR begin, typename identity< ITERATOR >::type end, DOFINFO &dinfo, INFOBOX &info, const std::function< void(DOFINFO &, typename INFOBOX::CellInfo &)> &cell_worker, const std::function< void(DOFINFO &, typename INFOBOX::CellInfo &)> &boundary_worker, const std::function< void(DOFINFO &, DOFINFO &, typename INFOBOX::CellInfo &, typename INFOBOX::CellInfo &)> &face_worker, ASSEMBLER &assembler, const LoopControl &lctrl=LoopControl())
void zero_out_ghost_values() const
void update_ghost_values() const
void reinit(const size_type size, const bool omit_zeroing_entries=false)
@ component_is_part_of_vector
void create_triangulation(Triangulation< dim, dim > &tria, const AdditionalData &additional_data=AdditionalData())
void plate_with_a_hole(Triangulation< dim > &tria, const double inner_radius=0.4, const double outer_radius=1., const double pad_bottom=2., const double pad_top=2., const double pad_left=1., const double pad_right=1., const Point< dim > ¢er=Point< dim >(), const types::manifold_id polar_manifold_id=0, const types::manifold_id tfi_manifold_id=1, const double L=1., const unsigned int n_slices=2, const bool colorize=false)
Rectangular plate with an (offset) cylindrical hole.
static const types::blas_int zero
@ matrix
Contents is actually a matrix.
@ diagonal
Matrix is diagonal.
@ general
No special properties.
static const types::blas_int one
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
SymmetricTensor< 2, dim, Number > C(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
@ construct_multigrid_hierarchy
VectorType::value_type * end(VectorType &V)
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
T sum(const T &t, const MPI_Comm &mpi_communicator)
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
void run(const Iterator &begin, const typename identity< Iterator >::type &end, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length, const unsigned int chunk_size)
long double gamma(const unsigned int n)
int(&) functions(const void *v1, const void *v2)
void assemble(const MeshWorker::DoFInfoBox< dim, DOFINFO > &dinfo, A *assembler)
static const unsigned int invalid_unsigned_int
void refine_and_coarsen_fixed_number(parallel::distributed::Triangulation< dim, spacedim > &tria, const ::Vector< Number > &criteria, const double top_fraction_of_cells, const double bottom_fraction_of_cells, const types::global_cell_index max_n_cells=std::numeric_limits< types::global_cell_index >::max())
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation
std::vector<::Vector< double > > solution_values
std::vector< std::vector< Tensor< 1, spacedim > > > solution_gradients
TasksParallelScheme tasks_parallel_scheme
UpdateFlags mapping_update_flags_inner_faces
UpdateFlags mapping_update_flags_boundary_faces
UpdateFlags mapping_update_flags
constexpr SymmetricTensor< 4, dim, Number > outer_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)
constexpr ProductType< Number, OtherNumber >::type scalar_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, OtherNumber > &t2)
const ::Triangulation< dim, spacedim > & tria