169 * #ifndef MFMFE_DATA_H
170 * #define MFMFE_DATA_H
172 * #include <deal.II/base/function.h>
173 * #include <deal.II/base/tensor_function.h>
178 * <a name=
"data.h-Dataandexactsolution"></a>
179 * <h3>Data and exact solution.</h3>
183 * This file declares the classes
for the given data, i.e.
184 * right-hand side, exact solution, permeability tensor and
185 * boundary conditions. For simplicity only 2
d cases are
186 * provided, but 3
d can be added straightforwardly.
197 *
class RightHandSide :
public Function<dim>
200 * RightHandSide () :
Function<dim>(1) {}
203 *
const unsigned int component = 0)
const override;
207 *
double RightHandSide<dim>::value (
const Point<dim> &p,
208 *
const unsigned int )
const
210 *
const double x = p[0];
211 *
const double y = p[1];
216 *
return -(x*(y*y*y*y)*6.0-(y*y)*
sin(x*y*2.0)*2.0+2.0)*(x*2.0+x*x+y*y+1.0)-
sin(x*y)*(
cos(x*y*2.0)+(x*x)*(y*y*y)*1.2E1
217 * -x*y*
sin(x*y*2.0)*2.0)*2.0-(x*2.0+2.0)*(x*2.0+(x*x)*(y*y*y*y)*3.0+y*
cos(x*y*2.0))+(x*x)*(
sin(x*y*2.0)
218 * -x*(y*y)*6.0)*
pow(x+1.0,2.0)*2.0-x*
cos(x*y)*(x*2.0+(x*x)*(y*y*y*y)*3.0+y*(
pow(
cos(x*y),2.0)*2.0-1.0))
219 * -x*y*
cos(x*y)*((x*x)*(y*y*y)*4.0+
pow(
cos(x*y),2.0)*2.0-1.0);
221 *
Assert(
false, ExcMessage(
"The RHS data for dim != 2 is not provided"));
228 *
class PressureBoundaryValues :
public Function<dim>
231 * PressureBoundaryValues () :
Function<dim>(1) {}
234 *
const unsigned int component = 0)
const override;
238 *
double PressureBoundaryValues<dim>::value (
const Point<dim> &p,
239 *
const unsigned int )
const
241 *
const double x = p[0];
242 *
const double y = p[1];
247 *
return (x*x*x)*(y*y*y*y)+
cos(x*y)*
sin(x*y)+x*x;
249 *
Assert(
false, ExcMessage(
"The BC data for dim != 2 is not provided"));
256 *
class ExactSolution :
public Function<dim>
259 * ExactSolution () :
Function<dim>(dim+1) {}
270 * ExactSolution<dim>::vector_value (
const Point<dim> &p,
273 *
Assert (values.size() == dim+1,
274 * ExcDimensionMismatch (values.size(), dim+1));
276 *
const double x = p[0];
277 *
const double y = p[1];
282 * values(0) = -(x*2.0+(x*x)*(y*y*y*y)*3.0+y*
cos(x*y*2.0))*(x*2.0+x*x+y*y+1.0)-x*
sin(x*y)*(
cos(x*y*2.0)+(x*x)*(y*y*y)*4.0);
283 * values(1) = -
sin(x*y)*(x*2.0+(x*x)*(y*y*y*y)*3.0+y*
cos(x*y*2.0))-x*(
cos(x*y*2.0)+(x*x)*(y*y*y)*4.0)*
pow(x+1.0,2.0);
284 * values(2) = (x*x*x)*(y*y*y*y)+
cos(x*y)*
sin(x*y)+x*x;
287 *
Assert(
false, ExcMessage(
"The exact solution for dim != 2 is not provided"));
293 * ExactSolution<dim>::vector_gradient (
const Point<dim> &p,
296 *
const double x = p[0];
297 *
const double y = p[1];
302 * grads[0][0] = -(x*(y*y*y*y)*6.0-(y*y)*
sin(x*y*2.0)*2.0+2.0)*(x*2.0+x*x+y*y+1.0)-
sin(x*y)*(
cos(x*y*2.0)
303 * +(x*x)*(y*y*y)*1.2E1-x*y*
sin(x*y*2.0)*2.0)-(x*2.0+2.0)*(x*2.0+(x*x)*(y*y*y*y)*3.0
304 * +y*
cos(x*y*2.0))-x*y*
cos(x*y)*((x*x)*(y*y*y)*4.0+
pow(
cos(x*y),2.0)*2.0-1.0);
305 * grads[0][1] = -(
cos(x*y*2.0)+(x*x)*(y*y*y)*1.2E1-x*y*
sin(x*y*2.0)*2.0)*(x*2.0+x*x+y*y+1.0)
306 * -y*(x*2.0+(x*x)*(y*y*y*y)*3.0+y*
cos(x*y*2.0))*2.0-(x*x)*
cos(x*y)*((x*x)*(y*y*y)*4.0
307 * +
pow(
cos(x*y),2.0)*2.0-1.0)+(x*x)*
sin(x*y)*(
sin(x*y*2.0)-x*(y*y)*6.0)*2.0;
308 * grads[1][0] = -
sin(x*y)*(x*(y*y*y*y)*6.0-(y*y)*
sin(x*y*2.0)*2.0+2.0)-
pow(x+1.0,2.0)*(
cos(x*y*2.0)
309 * +(x*x)*(y*y*y)*1.2E1-x*y*
sin(x*y*2.0)*2.0)-x*(
cos(x*y*2.0)+(x*x)*(y*y*y)*4.0)*(x*2.0+2.0)
310 * -y*
cos(x*y)*(x*2.0+(x*x)*(y*y*y*y)*3.0+y*(
pow(
cos(x*y),2.0)*2.0-1.0));
311 * grads[1][1] = -
sin(x*y)*(
cos(x*y*2.0)+(x*x)*(y*y*y)*1.2E1-x*y*
sin(x*y*2.0)*2.0)+(x*x)*(
sin(x*y*2.0)
312 * -x*(y*y)*6.0)*
pow(x+1.0,2.0)*2.0-x*
cos(x*y)*(x*2.0+(x*x)*(y*y*y*y)*3.0
313 * +y*(
pow(
cos(x*y),2.0)*2.0-1.0));
317 *
Assert(
false, ExcMessage(
"The exact solution's gradient for dim != 2 is not provided"));
335 * KInverse<dim>::value_list (
const std::vector<
Point<dim> > &points,
338 *
Assert (points.size() == values.size(),
339 * ExcDimensionMismatch (points.size(), values.size()));
341 *
for (
unsigned int p=0; p<points.size(); ++p)
343 * values[p].clear ();
345 *
const double x = points[p][0];
346 *
const double y = points[p][1];
351 * values[p][0][0] =
pow(x+1.0,2.0)/(x*4.0+(x*x)*(y*y)-
pow(
sin(x*y),2.0)+x*(y*y)*2.0+(x*x)*6.0+(x*x*x)*4.0+x*x*x*x+y*y+1.0);
352 * values[p][0][1] = -
sin(x*y)/(x*4.0+(x*x)*(y*y)-
pow(
sin(x*y),2.0)+x*(y*y)*2.0+(x*x)*6.0+(x*x*x)*4.0+x*x*x*x+y*y+1.0);
353 * values[p][1][0] = -
sin(x*y)/(x*4.0+(x*x)*(y*y)-
pow(
sin(x*y),2.0)+x*(y*y)*2.0+(x*x)*6.0+(x*x*x)*4.0+x*x*x*x+y*y+1.0);
354 * values[p][1][1] = (x*2.0+x*x+y*y+1.0)/(x*4.0+(x*x)*(y*y)-
pow(
sin(x*y),2.0)+x*(y*y)*2.0+(x*x)*6.0+(x*x*x)*4.0+x*x*x*x+y*y+1.0);
357 *
Assert(
false, ExcMessage(
"The inverse of permeability tensor for dim != 2 is not provided"));
367<a name=
"ann-mfmfe.cc"></a>
368<h1>Annotated version of mfmfe.cc</h1>
391 * <a name=
"mfmfe.cc-Includefiles"></a>
392 * <h3>Include files</h3>
396 * As usual, the list of necessary header files. There is not
397 * much
new here, the files are included in order
398 * base-lac-grid-dofs-numerics followed by the
C++ headers.
401 * #include <deal.II/base/convergence_table.h>
402 * #include <deal.II/base/quadrature_lib.h>
403 * #include <deal.II/base/logstream.h>
404 * #include <deal.II/base/timer.h>
405 * #include <deal.II/base/utilities.h>
406 * #include <deal.II/base/work_stream.h>
408 * #include <deal.II/lac/full_matrix.h>
409 * #include <deal.II/lac/solver_cg.h>
410 * #include <deal.II/lac/block_sparse_matrix.h>
411 * #include <deal.II/lac/block_vector.h>
412 * #include <deal.II/lac/precondition.h>
414 * #include <deal.II/grid/grid_generator.h>
415 * #include <deal.II/grid/grid_tools.h>
416 * #include <deal.II/grid/grid_in.h>
417 * #include <deal.II/grid/tria.h>
418 * #include <deal.II/dofs/dof_renumbering.h>
419 * #include <deal.II/dofs/dof_tools.h>
420 * #include <deal.II/fe/fe_dgq.h>
421 * #include <deal.II/fe/fe_system.h>
422 * #include <deal.II/fe/fe_tools.h>
423 * #include <deal.II/numerics/vector_tools.h>
424 * #include <deal.II/numerics/matrix_tools.h>
425 * #include <deal.II/numerics/data_out.h>
428 * #include <unordered_map>
432 * This is a header needed
for the purposes of the
433 * multipoint flux mixed method, as it declares the
434 *
new enhanced Raviart-Thomas finite element.
437 * #include <deal.II/fe/fe_rt_bubbles.h>
441 * For the sake of readability, the classes representing
442 * data, i.e. RHS, BCs, permeability tensor and the exact
443 * solution are placed in a file data.h which is included
451 * As
always the program is in the
namespace of its own with
452 * the deal.II classes and
functions imported into it
462 * <a name=
"mfmfe.cc-Definitionofmultipointfluxassemblydatastructures"></a>
463 * <h3>Definition of multipoint flux assembly data structures</h3>
467 * The main idea of the MFMFE method is to perform local elimination
468 * of the velocity variables in order to obtain the resulting
469 * pressure system. Since in deal.II assembly happens cell-wise,
470 * some extra work needs to be done in order to get the local
471 * mass matrices @f$A_i@f$ and the corresponding to them @f$B_i@f$.
474 *
namespace DataStructures
478 * This will be achieved by assembling cell-wise, but instead of placing
479 * the terms into a global system
matrix, they will populate node-associated
480 * full matrices. For
this, a data structure with fast lookup is crucial, hence
487 *
size_t operator()(
const Point<dim> &p)
const
490 * h1 = std::hash<double>()(p[0]);
497 * h2 = std::hash<double>()(p[1]);
500 * h2 = std::hash<double>()(p[1]);
501 * h3 = std::hash<double>()(p[2]);
502 *
return (h1 ^ (h2 << 1)) ^ h3;
504 *
Assert(
false, ExcNotImplemented());
511 * Here, the actual hash-tables are defined. We use the
C++ STL <code>unordered_map</code>,
512 * with the hash function specified above. For convenience these are aliased as follows
516 *
using PointToMatrixMap = std::unordered_map<Point<dim>, std::map<std::pair<types::global_dof_index,types::global_dof_index>,
double>, hash_points<dim>>;
519 *
using PointToVectorMap = std::unordered_map<Point<dim>, std::map<types::global_dof_index, double>, hash_points<dim>>;
522 *
using PointToIndexMap = std::unordered_map<Point<dim>, std::set<types::global_dof_index>, hash_points<dim>>;
526 * Next, since
this particular program allows
for the use of
527 * multiple threads, the helper CopyData structures
528 * are defined. There are two kinds of these, one is used
529 *
for the copying cell-wise contributions to the corresponding
530 * node-associated data structures...
534 *
struct NodeAssemblyCopyData
536 * PointToMatrixMap<dim> cell_mat;
537 * PointToVectorMap<dim> cell_vec;
538 * PointToIndexMap<dim> local_pres_indices;
539 * PointToIndexMap<dim> local_vel_indices;
540 * std::vector<types::global_dof_index> local_dof_indices;
545 * ... and the other one
for the actual process of
546 * local velocity elimination and assembling the global
551 *
struct NodeEliminationCopyData
564 * Similarly, two ScratchData classes are defined.
565 * One
for the assembly part, where we need
571 *
struct NodeAssemblyScratchData
578 * NodeAssemblyScratchData (
const NodeAssemblyScratchData &scratch_data);
582 * std::vector<unsigned int> n_faces_at_vertex;
584 *
const unsigned long num_cells;
586 * std::vector<Tensor<2,dim>> k_inverse_values;
587 * std::vector<double> rhs_values;
588 * std::vector<double> pres_bc_values;
590 * std::vector<Tensor<1,dim> > phi_u;
591 * std::vector<double> div_phi_u;
592 * std::vector<double> phi_p;
596 * NodeAssemblyScratchData<dim>::
606 * fe_face_values (fe,
610 * num_cells(tria.n_active_cells()),
611 * k_inverse_values(quad.size()),
612 * rhs_values(quad.size()),
613 * pres_bc_values(f_quad.size()),
614 * phi_u(fe.dofs_per_cell),
615 * div_phi_u(fe.dofs_per_cell),
616 * phi_p(fe.dofs_per_cell)
618 * n_faces_at_vertex.resize(tria.n_vertices(), 0);
621 *
for (; face != endf; ++face)
622 *
for (
unsigned int v=0; v<GeometryInfo<dim>::vertices_per_face; ++v)
623 * n_faces_at_vertex[face->vertex_index(v)] += 1;
627 * NodeAssemblyScratchData<dim>::
628 * NodeAssemblyScratchData (
const NodeAssemblyScratchData &scratch_data)
630 * fe_values (scratch_data.fe_values.get_fe(),
631 * scratch_data.fe_values.get_quadrature(),
634 * fe_face_values (scratch_data.fe_face_values.get_fe(),
635 * scratch_data.fe_face_values.get_quadrature(),
638 * n_faces_at_vertex(scratch_data.n_faces_at_vertex),
639 * num_cells(scratch_data.num_cells),
640 * k_inverse_values(scratch_data.k_inverse_values),
641 * rhs_values(scratch_data.rhs_values),
642 * pres_bc_values(scratch_data.pres_bc_values),
643 * phi_u(scratch_data.phi_u),
644 * div_phi_u(scratch_data.div_phi_u),
645 * phi_p(scratch_data.phi_p)
650 * ...and the other, simpler one,
for the velocity elimination and recovery
653 *
struct VertexEliminationScratchData
655 * VertexEliminationScratchData () =
default;
656 * VertexEliminationScratchData (
const VertexEliminationScratchData &scratch_data);
667 * VertexEliminationScratchData::
668 * VertexEliminationScratchData (
const VertexEliminationScratchData &scratch_data)
670 * velocity_matrix(scratch_data.velocity_matrix),
671 * pressure_rhs(scratch_data.pressure_rhs),
672 * local_pressure_solution(scratch_data.local_pressure_solution),
673 * tmp_rhs1(scratch_data.tmp_rhs1),
674 * tmp_rhs2(scratch_data.tmp_rhs2),
675 * tmp_rhs3(scratch_data.tmp_rhs3)
684 * <a name=
"mfmfe.cc-ThecodeMultipointMixedDarcyProblemcodeclasstemplate"></a>
685 * <h3>The <code>MultipointMixedDarcyProblem</code>
class template</h3>
689 * The main
class, besides the constructor and destructor, has only one
public member
690 * <code>
run()</code>, similarly to the tutorial programs. The
private members can
691 * be grouped into the ones that are used
for the cell-wise assembly, vertex elimination,
692 * pressure solve, vertex velocity recovery and postprocessing. Apart from the
693 * MFMFE-specific data structures, the rest of the members should look familiar.
697 *
class MultipointMixedDarcyProblem
700 * MultipointMixedDarcyProblem (
const unsigned int degree);
701 * ~MultipointMixedDarcyProblem ();
702 *
void run (
const unsigned int refine);
705 * DataStructures::NodeAssemblyScratchData<dim> &scratch_data,
706 * DataStructures::NodeAssemblyCopyData<dim> ©_data);
707 *
void copy_cell_to_node(
const DataStructures::NodeAssemblyCopyData<dim> ©_data);
708 *
void node_assembly();
709 *
void make_cell_centered_sp ();
710 *
void nodal_elimination(
const typename DataStructures::PointToMatrixMap<dim>::iterator &n_it,
711 * DataStructures::VertexEliminationScratchData &scratch_data,
712 * DataStructures::NodeEliminationCopyData<dim> ©_data);
713 *
void copy_node_to_system(
const DataStructures::NodeEliminationCopyData<dim> ©_data);
714 *
void pressure_assembly ();
715 *
void solve_pressure ();
716 *
void velocity_assembly (
const typename DataStructures::PointToMatrixMap<dim>::iterator &n_it,
717 * DataStructures::VertexEliminationScratchData &scratch_data,
718 * DataStructures::NodeEliminationCopyData<dim> ©_data);
719 *
void copy_node_velocity_to_global(
const DataStructures::NodeEliminationCopyData<dim> ©_data);
720 *
void velocity_recovery ();
721 *
void reset_data_structures ();
722 *
void compute_errors (
const unsigned int cycle);
723 *
void output_results (
const unsigned int cycle,
const unsigned int refine);
725 *
const unsigned int degree;
735 * std::unordered_map<Point<dim>,
FullMatrix<double>, DataStructures::hash_points<dim>> pressure_matrix;
736 * std::unordered_map<Point<dim>,
FullMatrix<double>, DataStructures::hash_points<dim>> A_inverse;
737 * std::unordered_map<Point<dim>,
Vector<double>, DataStructures::hash_points<dim>> velocity_rhs;
739 * DataStructures::PointToMatrixMap<dim> node_matrix;
740 * DataStructures::PointToVectorMap<dim> node_rhs;
742 * DataStructures::PointToIndexMap<dim> pressure_indices;
743 * DataStructures::PointToIndexMap<dim> velocity_indices;
745 *
unsigned long n_v, n_p;
757 * <a name=
"mfmfe.cc-Constructoranddestructorcodereset_data_structurescode"></a>
758 * <h4>Constructor and destructor, <code>reset_data_structures</code></h4>
762 * In the constructor of
this class, we store the
value that was
763 * passed in concerning the degree of the finite elements we shall use (a
765 * and then construct the vector valued element belonging to the space @f$V_h^k@f$ described
766 * in the introduction. The constructor also takes care of initializing the
767 * computing timer, as it is of interest
for us how well our method performs.
771 * MultipointMixedDarcyProblem<dim>::MultipointMixedDarcyProblem (
const unsigned int degree)
784 * The destructor clears the <code>dof_handler</code> and
785 * all of the data structures we used
for the method.
789 * MultipointMixedDarcyProblem<dim>::~MultipointMixedDarcyProblem()
791 * reset_data_structures ();
792 * dof_handler.clear();
798 * This method clears all the data that was used after one refinement
803 *
void MultipointMixedDarcyProblem<dim>::reset_data_structures ()
805 * pressure_indices.clear();
806 * velocity_indices.clear();
807 * velocity_rhs.clear();
809 * pressure_matrix.clear();
810 * node_matrix.clear();
818 * <a name=
"mfmfe.cc-Cellwiseassemblyandcreationofthelocalnodalbaseddatastructures"></a>
819 * <h4>Cell-wise assembly and creation of the local, nodal-based data structures</h4>
823 * First, the function that copies local cell contributions to the corresponding nodal
824 * matrices and vectors is defined. It places the values obtained from local cell integration
825 * into the correct place in a
matrix/vector corresponding to a specific node.
829 *
void MultipointMixedDarcyProblem<dim>::copy_cell_to_node(
const DataStructures::NodeAssemblyCopyData<dim> ©_data)
831 *
for (
auto m : copy_data.cell_mat)
836 *
for (
auto p : copy_data.cell_vec.at(m.
first))
839 *
for (
auto p : copy_data.local_pres_indices.at(m.
first))
842 *
for (
auto p : copy_data.local_vel_indices.at(m.
first))
851 * Second, the function that does the cell assembly is defined. While it is
852 * similar to the tutorial programs in a way it uses scrath and
copy data
853 * structures, the need to localize the DOFs leads to several differences.
857 *
void MultipointMixedDarcyProblem<dim>::
859 * DataStructures::NodeAssemblyScratchData<dim> &scratch_data,
860 * DataStructures::NodeAssemblyCopyData<dim> ©_data)
862 * copy_data.cell_mat.clear();
863 * copy_data.cell_vec.clear();
864 * copy_data.local_vel_indices.clear();
865 * copy_data.local_pres_indices.clear();
867 *
const unsigned int dofs_per_cell = fe.dofs_per_cell;
868 *
const unsigned int n_q_points = scratch_data.fe_values.get_quadrature().size();
869 *
const unsigned int n_face_q_points = scratch_data.fe_face_values.get_quadrature().size();
871 * copy_data.local_dof_indices.resize(dofs_per_cell);
872 * cell->get_dof_indices (copy_data.local_dof_indices);
874 * scratch_data.fe_values.reinit (cell);
876 *
const KInverse<dim> k_inverse;
877 *
const RightHandSide<dim> rhs;
878 *
const PressureBoundaryValues<dim> pressure_bc;
880 * k_inverse.value_list (scratch_data.fe_values.get_quadrature_points(), scratch_data.k_inverse_values);
881 * rhs.value_list(scratch_data.fe_values.get_quadrature_points(), scratch_data.rhs_values);
887 * std::unordered_map<unsigned int, std::unordered_map<unsigned int, double>> div_map;
891 * One, we need to be able to
assemble the communication between velocity and
892 * pressure variables and put it on the right place in our
final, local version
893 * of the B
matrix. This is a little messy, as such communication is not in fact
894 * local, so we
do it in two steps. First, we compute all relevant LHS and RHS
897 *
for (
unsigned int q=0; q<n_q_points; ++q)
899 *
const Point<dim> p = scratch_data.fe_values.quadrature_point(q);
901 *
for (
unsigned int k=0; k<dofs_per_cell; ++k)
903 * scratch_data.phi_u[k] = scratch_data.fe_values[velocity].value(k, q);
904 * scratch_data.div_phi_u[k] = scratch_data.fe_values[velocity].divergence (k, q);
905 * scratch_data.phi_p[k] = scratch_data.fe_values[pressure].value (k, q);
908 *
for (
unsigned int i=0; i<dofs_per_cell; ++i)
910 *
for (
unsigned int j=n_vel; j<dofs_per_cell; ++j)
912 *
double div_term = (- scratch_data.div_phi_u[i] * scratch_data.phi_p[j]
913 * - scratch_data.phi_p[i] * scratch_data.div_phi_u[j]) * scratch_data.fe_values.JxW(q);
916 * div_map[i][j] += div_term;
919 *
double source_term = -scratch_data.phi_p[i] * scratch_data.rhs_values[q] * scratch_data.fe_values.JxW(q);
921 *
if (
std::abs(scratch_data.phi_p[i]) > 1.e-12 ||
std::abs(source_term) > 1.e-12)
922 * copy_data.cell_vec[p][copy_data.local_dof_indices[i]] += source_term;
928 * Then, by making another pass, we compute the mass
matrix terms and incorporate the
929 * divergence form and RHS accordingly. This
second pass, allows us to know where
930 * the total contribution will be put in the nodal data structures, as with
this
931 * choice of quadrature rule and finite element only the basis
functions corresponding
932 * to the same quadrature points yield non-zero contribution.
935 *
for (
unsigned int q=0; q<n_q_points; ++q)
937 * std::set<types::global_dof_index> vel_indices;
938 *
const Point<dim> p = scratch_data.fe_values.quadrature_point(q);
940 *
for (
unsigned int k=0; k<dofs_per_cell; ++k)
942 * scratch_data.phi_u[k] = scratch_data.fe_values[velocity].value(k, q);
943 * scratch_data.div_phi_u[k] = scratch_data.fe_values[velocity].divergence (k, q);
944 * scratch_data.phi_p[k] = scratch_data.fe_values[pressure].value (k, q);
947 *
for (
unsigned int i=0; i<dofs_per_cell; ++i)
948 *
for (
unsigned int j=i; j<dofs_per_cell; ++j)
950 *
double mass_term = scratch_data.phi_u[i]
951 * * scratch_data.k_inverse_values[q]
952 * * scratch_data.phi_u[j]
953 * * scratch_data.fe_values.JxW(q);
957 * copy_data.cell_mat[p][std::make_pair(copy_data.local_dof_indices[i], copy_data.local_dof_indices[j])] +=
959 * vel_indices.insert(i);
960 * copy_data.local_vel_indices[p].insert(copy_data.local_dof_indices[j]);
964 *
for (
auto i : vel_indices)
965 * for (auto el : div_map[i])
968 * copy_data.cell_mat[p][
std::make_pair(copy_data.local_dof_indices[i],
969 * copy_data.local_dof_indices[el.
first])] += el.
second;
970 * copy_data.local_pres_indices[p].insert(copy_data.local_dof_indices[el.first]);
976 * The pressure boundary conditions are computed as in @ref step_20
"step-20",
979 * std::map<types::global_dof_index,double> pres_bc;
980 *
for (
unsigned int face_no=0;
981 * face_no<GeometryInfo<dim>::faces_per_cell;
983 *
if (cell->at_boundary(face_no))
985 * scratch_data.fe_face_values.reinit (cell, face_no);
986 * pressure_bc.value_list(scratch_data.fe_face_values.get_quadrature_points(), scratch_data.pres_bc_values);
988 *
for (
unsigned int q=0; q<n_face_q_points; ++q)
989 *
for (
unsigned int i = 0; i < dofs_per_cell; ++i)
991 *
double tmp = -(scratch_data.fe_face_values[velocity].value(i, q) *
992 * scratch_data.fe_face_values.normal_vector(q) *
993 * scratch_data.pres_bc_values[q] *
994 * scratch_data.fe_face_values.JxW(q));
997 * pres_bc[copy_data.local_dof_indices[i]] += tmp;
1003 * ...but we distribute them to the corresponding nodal data structures
1006 *
for (
auto m : copy_data.cell_vec)
1007 * for (unsigned
int i=0; i<dofs_per_cell; ++i)
1008 *
if (
std::abs(pres_bc[copy_data.local_dof_indices[i]]) > 1.e-12)
1009 * copy_data.cell_vec[m.first][copy_data.local_dof_indices[i]] += pres_bc[copy_data.local_dof_indices[i]];
1015 * Finally, <code>node_assembly()</code> takes care of all the
1016 * local computations via
WorkStream mechanism. Notice that the choice
1017 * of the quadrature rule here is dictated by the formulation of the
1018 * method. It has to be <code>degree+1</code> points Gauss-Lobatto
1019 *
for the
volume integrals and <code>degree</code>
for the face ones,
1020 * as mentioned in the introduction.
1023 *
template <
int dim>
1024 *
void MultipointMixedDarcyProblem<dim>::node_assembly()
1028 * dof_handler.distribute_dofs(fe);
1030 *
const std::vector<types::global_dof_index> dofs_per_component
1034 *
QGauss<dim-1> face_quad(degree);
1036 * n_v = dofs_per_component[0];
1037 * n_p = dofs_per_component[dim];
1039 * pres_rhs.reinit(n_p);
1042 * dof_handler.end(),
1044 * &MultipointMixedDarcyProblem::assemble_system_cell,
1045 * &MultipointMixedDarcyProblem::copy_cell_to_node,
1046 * DataStructures::NodeAssemblyScratchData<dim>(fe,
triangulation,quad,face_quad),
1047 * DataStructures::NodeAssemblyCopyData<dim>());
1053 * <a name=
"mfmfe.cc-Makingthesparsitypattern"></a>
1054 * <h4>Making the sparsity pattern</h4>
1058 * Having computed all the local contributions, we actually have
1059 * all the information needed to make a cell-centered sparsity
1061 * leads to a slower solution.
1064 *
template <
int dim>
1065 *
void MultipointMixedDarcyProblem<dim>::make_cell_centered_sp()
1070 * std::set<types::global_dof_index>::iterator pi_it, pj_it;
1071 *
unsigned int i, j;
1072 *
for (
auto el : node_matrix)
1073 * for (pi_it = pressure_indices[el.
first].
begin(), i = 0;
1074 * pi_it != pressure_indices[el.first].end();
1076 *
for (pj_it = pi_it, j = 0;
1077 * pj_it != pressure_indices[el.first].end();
1079 * dsp.add(*pi_it - n_v, *pj_it - n_v);
1083 * cell_centered_sp.copy_from(dsp);
1084 * pres_system_matrix.reinit (cell_centered_sp);
1091 * <a name=
"mfmfe.cc-Thelocaleliminationprocedure"></a>
1092 * <h4>The local elimination procedure</h4>
1096 * This function
finally performs the local elimination procedure.
1097 * Mathematically, it follows the same idea as in computing the
1098 * Schur complement (as mentioned in the introduction) but we
do
1099 * so locally. Namely, local velocity DOFs are expressed in terms
1100 * of corresponding pressure values, and then used
for the local
1104 *
template <
int dim>
1105 *
void MultipointMixedDarcyProblem<dim>::
1106 * nodal_elimination(
const typename DataStructures::PointToMatrixMap<dim>::iterator &n_it,
1107 * DataStructures::VertexEliminationScratchData &scratch_data,
1108 * DataStructures::NodeEliminationCopyData<dim> ©_data)
1110 *
unsigned int n_edges = velocity_indices.at((*n_it).first).size();
1111 *
unsigned int n_cells = pressure_indices.at((*n_it).first).size();
1113 * scratch_data.velocity_matrix.reinit(n_edges,n_edges);
1114 * copy_data.pressure_matrix.reinit(n_edges,n_cells);
1116 * copy_data.velocity_rhs.reinit(n_edges);
1117 * scratch_data.pressure_rhs.reinit(n_cells);
1120 * std::set<types::global_dof_index>::iterator vi_it, vj_it, p_it;
1122 *
for (vi_it = velocity_indices.at((*n_it).first).begin(), i = 0;
1123 * vi_it != velocity_indices.at((*n_it).first).end();
1127 *
for (vj_it = velocity_indices.at((*n_it).first).begin(), j = 0;
1128 * vj_it != velocity_indices.at((*n_it).first).end();
1131 * scratch_data.velocity_matrix.add(i, j, node_matrix[(*n_it).first][std::make_pair(*vi_it, *vj_it)]);
1133 * scratch_data.velocity_matrix.add(j, i, node_matrix[(*n_it).first][std::make_pair(*vi_it, *vj_it)]);
1136 *
for (p_it = pressure_indices.at((*n_it).first).begin(), j = 0;
1137 * p_it != pressure_indices.at((*n_it).first).end();
1139 * copy_data.pressure_matrix.add(i, j, node_matrix[(*n_it).first][std::make_pair(*vi_it, *p_it)]);
1141 * copy_data.velocity_rhs(i) += node_rhs.at((*n_it).first)[*vi_it];
1144 *
for (p_it = pressure_indices.at((*n_it).first).begin(), i = 0;
1145 * p_it != pressure_indices.at((*n_it).first).end();
1147 * scratch_data.pressure_rhs(i) += node_rhs.at((*n_it).first)[*p_it];
1150 * copy_data.Ainverse.reinit(n_edges,n_edges);
1152 * scratch_data.tmp_rhs1.reinit(n_edges);
1153 * scratch_data.tmp_rhs2.reinit(n_edges);
1154 * scratch_data.tmp_rhs3.reinit(n_cells);
1156 * copy_data.Ainverse.invert(scratch_data.velocity_matrix);
1157 * copy_data.node_pres_matrix.reinit(n_cells, n_cells);
1158 * copy_data.node_pres_rhs = scratch_data.pressure_rhs;
1160 * copy_data.node_pres_matrix = 0;
1161 * copy_data.node_pres_matrix.triple_product(copy_data.Ainverse,
1162 * copy_data.pressure_matrix,
1163 * copy_data.pressure_matrix,
true,
false);
1165 * copy_data.Ainverse.vmult(scratch_data.tmp_rhs1, copy_data.velocity_rhs,
false);
1166 * copy_data.pressure_matrix.Tvmult(scratch_data.tmp_rhs3, scratch_data.tmp_rhs1,
false);
1167 * copy_data.node_pres_rhs *= -1.0;
1168 * copy_data.node_pres_rhs += scratch_data.tmp_rhs3;
1170 * copy_data.p = (*n_it).first;
1176 * Each node
's pressure system is then distributed to a global pressure
1177 * system, using the indices we computed in the previous stages.
1180 * template <int dim>
1181 * void MultipointMixedDarcyProblem<dim>::
1182 * copy_node_to_system(const DataStructures::NodeEliminationCopyData<dim> ©_data)
1184 * A_inverse[copy_data.p] = copy_data.Ainverse;
1185 * pressure_matrix[copy_data.p] = copy_data.pressure_matrix;
1186 * velocity_rhs[copy_data.p] = copy_data.velocity_rhs;
1189 * std::set<types::global_dof_index>::iterator pi_it, pj_it;
1191 * for (pi_it = pressure_indices[copy_data.p].begin(), i = 0;
1192 * pi_it != pressure_indices[copy_data.p].end();
1196 * for (pj_it = pressure_indices[copy_data.p].begin(), j = 0;
1197 * pj_it != pressure_indices[copy_data.p].end();
1199 * pres_system_matrix.add(*pi_it - n_v, *pj_it - n_v, copy_data.node_pres_matrix(i, j));
1201 * pres_rhs(*pi_it - n_v) += copy_data.node_pres_rhs(i);
1209 * The @ref WorkStream mechanism is again used for the assembly
1210 * of the global system for the pressure variable, where the
1211 * previous functions are used to perform local computations.
1214 * template <int dim>
1215 * void MultipointMixedDarcyProblem<dim>::pressure_assembly()
1217 * TimerOutput::Scope t(computing_timer, "Pressure matrix assembly");
1219 * QGaussLobatto<dim> quad(degree+1);
1220 * QGauss<dim-1> face_quad(degree);
1222 * pres_rhs.reinit(n_p);
1224 * WorkStream::run(node_matrix.begin(),
1225 * node_matrix.end(),
1227 * &MultipointMixedDarcyProblem::nodal_elimination,
1228 * &MultipointMixedDarcyProblem::copy_node_to_system,
1229 * DataStructures::VertexEliminationScratchData(),
1230 * DataStructures::NodeEliminationCopyData<dim>());
1238 * <a name="mfmfe.cc-Velocitysolutionrecovery"></a>
1239 * <h4>Velocity solution recovery</h4>
1243 * After solving for the pressure variable, we want to follow
1244 * the above procedure backwards, in order to obtain the
1245 * velocity solution (again, this is similar in nature to the
1246 * Schur complement approach, see @ref step_20 "step-20", but here it is done
1247 * locally at each node). We have almost everything computed and
1248 * stored already, including inverses of local mass matrices,
1249 * so the following is a relatively straightforward implementation.
1252 * template <int dim>
1253 * void MultipointMixedDarcyProblem<dim>::
1254 * velocity_assembly (const typename DataStructures::PointToMatrixMap<dim>::iterator &n_it,
1255 * DataStructures::VertexEliminationScratchData &scratch_data,
1256 * DataStructures::NodeEliminationCopyData<dim> ©_data)
1258 * unsigned int n_edges = velocity_indices.at((*n_it).first).size();
1259 * unsigned int n_cells = pressure_indices.at((*n_it).first).size();
1261 * scratch_data.tmp_rhs1.reinit(n_edges);
1262 * scratch_data.tmp_rhs2.reinit(n_edges);
1263 * scratch_data.tmp_rhs3.reinit(n_cells);
1264 * scratch_data.local_pressure_solution.reinit(n_cells);
1266 * copy_data.vertex_vel_solution.reinit(n_edges);
1268 * std::set<types::global_dof_index>::iterator p_it;
1271 * for (p_it = pressure_indices[(*n_it).first].begin(), i = 0;
1272 * p_it != pressure_indices[(*n_it).first].end();
1274 * scratch_data.local_pressure_solution(i) = pres_solution(*p_it - n_v);
1276 * pressure_matrix[(*n_it).first].vmult(scratch_data.tmp_rhs2, scratch_data.local_pressure_solution, false);
1277 * scratch_data.tmp_rhs2 *= -1.0;
1278 * scratch_data.tmp_rhs2+=velocity_rhs[(*n_it).first];
1279 * A_inverse[(*n_it).first].vmult(copy_data.vertex_vel_solution, scratch_data.tmp_rhs2, false);
1281 * copy_data.p = (*n_it).first;
1287 * Copy nodal velocities to a global solution vector by using
1288 * local computations and indices from early stages.
1291 * template <int dim>
1292 * void MultipointMixedDarcyProblem<dim>::
1293 * copy_node_velocity_to_global(const DataStructures::NodeEliminationCopyData<dim> ©_data)
1295 * std::set<types::global_dof_index>::iterator vi_it;
1298 * for (vi_it = velocity_indices[copy_data.p].begin(), i = 0;
1299 * vi_it != velocity_indices[copy_data.p].end();
1301 * vel_solution(*vi_it) += copy_data.vertex_vel_solution(i);
1307 * Use @ref WorkStream to run everything concurrently.
1310 * template <int dim>
1311 * void MultipointMixedDarcyProblem<dim>::velocity_recovery()
1313 * TimerOutput::Scope t(computing_timer, "Velocity solution recovery");
1315 * QGaussLobatto<dim> quad(degree+1);
1316 * QGauss<dim-1> face_quad(degree);
1318 * vel_solution.reinit(n_v);
1320 * WorkStream::run(node_matrix.begin(),
1321 * node_matrix.end(),
1323 * &MultipointMixedDarcyProblem::velocity_assembly,
1324 * &MultipointMixedDarcyProblem::copy_node_velocity_to_global,
1325 * DataStructures::VertexEliminationScratchData(),
1326 * DataStructures::NodeEliminationCopyData<dim>());
1328 * solution.reinit(2);
1329 * solution.block(0) = vel_solution;
1330 * solution.block(1) = pres_solution;
1331 * solution.collect_sizes();
1339 * <a name="mfmfe.cc-Pressuresystemsolver"></a>
1340 * <h4>Pressure system solver</h4>
1344 * The solver part is trivial. We use the CG solver with no
1345 * preconditioner for simplicity.
1348 * template <int dim>
1349 * void MultipointMixedDarcyProblem<dim>::solve_pressure()
1351 * TimerOutput::Scope t(computing_timer, "Pressure CG solve");
1353 * pres_solution.reinit(n_p);
1355 * SolverControl solver_control (static_cast<int>(2.0*n_p), 1e-10);
1356 * SolverCG<> solver (solver_control);
1358 * PreconditionIdentity identity;
1359 * solver.solve(pres_system_matrix, pres_solution, pres_rhs, identity);
1367 * <a name="mfmfe.cc-Postprocessing"></a>
1368 * <h3>Postprocessing</h3>
1372 * We have two postprocessing steps here, first one computes the
1373 * errors in order to populate the convergence tables. The other
1374 * one takes care of the output of the solutions in <code>.vtk</code>
1380 * <a name="mfmfe.cc-Computeerrors"></a>
1381 * <h4>Compute errors</h4>
1385 * The implementation of this function is almost identical to @ref step_20 "step-20".
1386 * We use @ref ComponentSelectFunction as masks to use the right
1387 * solution component (velocity or pressure) and @ref integrate_difference
1388 * to compute the errors. Since we also want to compute Hdiv seminorm of the
1389 * velocity error, one must provide gradients in the <code>ExactSolution</code>
1390 * class implementation to avoid exceptions. The only noteworthy thing here
1391 * is that we again use lower order quadrature rule instead of projecting the
1392 * solution to an appropriate space in order to show superconvergence, which is
1393 * mathematically justified.
1396 * template <int dim>
1397 * void MultipointMixedDarcyProblem<dim>::compute_errors(const unsigned cycle)
1399 * TimerOutput::Scope t(computing_timer, "Compute errors");
1401 * const ComponentSelectFunction<dim> pressure_mask(dim, dim+1);
1402 * const ComponentSelectFunction<dim> velocity_mask(std::make_pair(0, dim), dim+1);
1404 * ExactSolution<dim> exact_solution;
1406 * Vector<double> cellwise_errors (triangulation.n_active_cells());
1408 * QTrapezoid<1> q_trapez;
1409 * QIterated<dim> quadrature(q_trapez,degree+2);
1410 * QGauss<dim> quadrature_super(degree);
1412 * VectorTools::integrate_difference (dof_handler, solution, exact_solution,
1413 * cellwise_errors, quadrature,
1414 * VectorTools::L2_norm,
1416 * const double p_l2_error = cellwise_errors.l2_norm();
1418 * VectorTools::integrate_difference (dof_handler, solution, exact_solution,
1419 * cellwise_errors, quadrature_super,
1420 * VectorTools::L2_norm,
1422 * const double p_l2_mid_error = cellwise_errors.l2_norm();
1424 * VectorTools::integrate_difference (dof_handler, solution, exact_solution,
1425 * cellwise_errors, quadrature,
1426 * VectorTools::L2_norm,
1428 * const double u_l2_error = cellwise_errors.l2_norm();
1430 * VectorTools::integrate_difference (dof_handler, solution, exact_solution,
1431 * cellwise_errors, quadrature,
1432 * VectorTools::Hdiv_seminorm,
1434 * const double u_hd_error = cellwise_errors.l2_norm();
1436 * const unsigned int n_active_cells=triangulation.n_active_cells();
1437 * const unsigned int n_dofs=dof_handler.n_dofs();
1439 * convergence_table.add_value("cycle", cycle);
1440 * convergence_table.add_value("cells", n_active_cells);
1441 * convergence_table.add_value("dofs", n_dofs);
1442 * convergence_table.add_value("Velocity,L2", u_l2_error);
1443 * convergence_table.add_value("Velocity,Hdiv", u_hd_error);
1444 * convergence_table.add_value("Pressure,L2", p_l2_error);
1445 * convergence_table.add_value("Pressure,L2-nodal", p_l2_mid_error);
1453 * <a name="mfmfe.cc-Outputresults"></a>
1454 * <h4>Output results</h4>
1458 * This function also follows the same idea as in @ref step_20 "step-20" tutorial
1459 * program. The only modification to it is the part involving
1460 * a convergence table.
1463 * template <int dim>
1464 * void MultipointMixedDarcyProblem<dim>::output_results(const unsigned int cycle, const unsigned int refine)
1466 * TimerOutput::Scope t(computing_timer, "Output results");
1468 * std::vector<std::string> solution_names(dim, "u");
1469 * solution_names.push_back ("p");
1470 * std::vector<DataComponentInterpretation::DataComponentInterpretation>
1471 * interpretation (dim, DataComponentInterpretation::component_is_part_of_vector);
1472 * interpretation.push_back (DataComponentInterpretation::component_is_scalar);
1474 * DataOut<dim> data_out;
1475 * data_out.add_data_vector (dof_handler, solution, solution_names, interpretation);
1476 * data_out.build_patches ();
1478 * std::ofstream output ("solution" + std::to_string(dim) + "d-" + std::to_string(cycle) + ".vtk");
1479 * data_out.write_vtk (output);
1481 * convergence_table.set_precision("Velocity,L2", 3);
1482 * convergence_table.set_precision("Velocity,Hdiv", 3);
1483 * convergence_table.set_precision("Pressure,L2", 3);
1484 * convergence_table.set_precision("Pressure,L2-nodal", 3);
1485 * convergence_table.set_scientific("Velocity,L2", true);
1486 * convergence_table.set_scientific("Velocity,Hdiv", true);
1487 * convergence_table.set_scientific("Pressure,L2", true);
1488 * convergence_table.set_scientific("Pressure,L2-nodal", true);
1489 * convergence_table.set_tex_caption("cells", "\\# cells");
1490 * convergence_table.set_tex_caption("dofs", "\\# dofs");
1491 * convergence_table.set_tex_caption("Velocity,L2", " \\|\\u - \\u_h\\|_{L^2} ");
1492 * convergence_table.set_tex_caption("Velocity,Hdiv", " \\|\\nabla\\cdot(\\u - \\u_h)\\|_{L^2} ");
1493 * convergence_table.set_tex_caption("Pressure,L2", " \\|p - p_h\\|_{L^2} ");
1494 * convergence_table.set_tex_caption("Pressure,L2-nodal", " \\|Qp - p_h\\|_{L^2} ");
1495 * convergence_table.set_tex_format("cells", "r");
1496 * convergence_table.set_tex_format("dofs", "r");
1498 * convergence_table.evaluate_convergence_rates("Velocity,L2", ConvergenceTable::reduction_rate_log2);
1499 * convergence_table.evaluate_convergence_rates("Velocity,Hdiv", ConvergenceTable::reduction_rate_log2);
1500 * convergence_table.evaluate_convergence_rates("Pressure,L2", ConvergenceTable::reduction_rate_log2);
1501 * convergence_table.evaluate_convergence_rates("Pressure,L2-nodal", ConvergenceTable::reduction_rate_log2);
1503 * std::ofstream error_table_file("error" + std::to_string(dim) + "d.tex");
1505 * if (cycle == refine-1)
1507 * convergence_table.write_text(std::cout);
1508 * convergence_table.write_tex(error_table_file);
1517 * <a name="mfmfe.cc-Runfunction"></a>
1518 * <h3>Run function</h3>
1522 * The driver method <code>run()</code>
1523 * takes care of mesh generation and arranging calls to member methods in
1524 * the right way. It also resets data structures and clear triangulation and
1525 * DOF handler as we run the method on a sequence of refinements in order
1526 * to record convergence rates.
1529 * template <int dim>
1530 * void MultipointMixedDarcyProblem<dim>::run(const unsigned int refine)
1532 * Assert(refine > 0, ExcMessage("Must at least have 1 refinement cycle!"));
1534 * dof_handler.clear();
1535 * triangulation.clear();
1536 * convergence_table.clear();
1538 * for (unsigned int cycle=0; cycle<refine; ++cycle)
1544 * We first generate the hyper cube and refine it twice
1545 * so that we could distort the grid slightly and
1546 * demonstrate the method's ability to work in such a
1558 * make_cell_centered_sp();
1559 * pressure_assembly();
1560 * solve_pressure ();
1561 * velocity_recovery ();
1562 * compute_errors (cycle);
1563 * output_results (cycle, refine);
1564 * reset_data_structures ();
1566 * computing_timer.print_summary ();
1567 * computing_timer.reset ();
1576 * <a name=
"mfmfe.cc-Thecodemaincodefunction"></a>
1577 * <h3>The <code>main</code> function</h3>
1581 * In the main functione we pass the order of the Finite Element as an argument
1582 * to the constructor of the Multipoint Flux Mixed Darcy problem, and the number
1583 * of refinement cycles as an argument
for the
run method.
1590 *
using namespace dealii;
1591 *
using namespace MFMFE;
1595 * MultipointMixedDarcyProblem<2> mfmfe_problem(2);
1596 * mfmfe_problem.run(6);
1598 *
catch (std::exception &exc)
1600 * std::cerr << std::endl << std::endl
1601 * <<
"----------------------------------------------------"
1603 * std::cerr <<
"Exception on processing: " << std::endl
1604 * << exc.what() << std::endl
1605 * <<
"Aborting!" << std::endl
1606 * <<
"----------------------------------------------------"
1613 * std::cerr << std::endl << std::endl
1614 * <<
"----------------------------------------------------"
1616 * std::cerr <<
"Unknown exception!" << std::endl
1617 * <<
"Aborting!" << std::endl
1618 * <<
"----------------------------------------------------"
virtual void vector_gradient(const Point< dim > &p, std::vector< Tensor< 1, dim, RangeNumberType > > &gradients) const
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
static void set_thread_limit(const unsigned int max_threads=numbers::invalid_unsigned_int)
virtual void value_list(const std::vector< Point< dim > > &points, std::vector< value_type > &values) const
void refine_global(const unsigned int times=1)
#define Assert(cond, exc)
typename ActiveSelector::active_cell_iterator active_cell_iterator
@ 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.
void component_wise(DoFHandler< dim, spacedim > &dof_handler, const std::vector< unsigned int > &target_component=std::vector< unsigned int >())
void hyper_cube(Triangulation< dim, spacedim > &tria, const double left=0., const double right=1., const bool colorize=false)
@ matrix
Contents is actually a matrix.
SymmetricTensor< 2, dim, Number > C(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
VectorType::value_type * begin(VectorType &V)
constexpr T pow(const T base, const int iexp)
void run(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &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)
void run(const std::vector< std::vector< Iterator > > &colored_iterators, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length=2 *MultithreadInfo::n_threads(), const unsigned int chunk_size=8)
unsigned int n_cells(const internal::TriangulationImplementation::NumberCache< 1 > &c)
void copy(const T *begin, const T *end, U *dest)
int(& functions)(const void *v1, const void *v2)
void assemble(const MeshWorker::DoFInfoBox< dim, DOFINFO > &dinfo, A *assembler)
::VectorizedArray< Number, width > cos(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sin(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation