DiFfRG
Loading...
Searching...
No Matches
dg.hh
Go to the documentation of this file.
1#pragma once
2
3// standard library
4#include <sstream>
5
6// DiFfRG
8
9namespace DiFfRG
10{
11 namespace DG
12 {
13 using namespace dealii;
14 using std::array;
15
16 template <typename... T> auto fe_tie(T &&...t)
17 {
18 return named_tuple<std::tuple<T &...>, "fe_functions", "extractors", "variables">(std::tie(t...));
19 }
20
21 template <typename... T> auto i_tie(T &&...t)
22 {
23 return named_tuple<std::tuple<T &...>, "fe_functions", "fe_derivatives", "fe_hessians">(std::tie(t...));
24 }
25
26 namespace internal
27 {
32 template <typename Discretization> struct ScratchData {
33 static constexpr int dim = Discretization::dim;
35 using VectorType = Vector<NumberType>;
36
37 ScratchData(const Mapping<dim> &mapping, const FiniteElement<dim> &fe, const Quadrature<dim> &quadrature,
38 const Quadrature<dim - 1> &quadrature_face,
39 const UpdateFlags update_flags = update_values | update_gradients | update_quadrature_points |
40 update_JxW_values,
41 const UpdateFlags interface_update_flags = update_values | update_gradients |
42 update_quadrature_points | update_JxW_values |
43 update_normal_vectors)
44 : n_components(fe.n_components()), fe_values(mapping, fe, quadrature, update_flags),
45 fe_interface_values(mapping, fe, quadrature_face, interface_update_flags)
46 {
47 solution.resize(quadrature.size(), VectorType(n_components));
48 solution_dot.resize(quadrature.size(), VectorType(n_components));
49 solution_interface[0].resize(quadrature_face.size(), VectorType(n_components));
50 solution_interface[1].resize(quadrature_face.size(), VectorType(n_components));
51 }
52
54 : n_components(scratch_data.fe_values.get_fe().n_components()),
55 fe_values(scratch_data.fe_values.get_mapping(), scratch_data.fe_values.get_fe(),
56 scratch_data.fe_values.get_quadrature(), scratch_data.fe_values.get_update_flags()),
57 fe_interface_values(scratch_data.fe_interface_values.get_mapping(),
58 scratch_data.fe_interface_values.get_fe(),
59 scratch_data.fe_interface_values.get_quadrature(),
60 scratch_data.fe_interface_values.get_update_flags())
61 {
62 solution.resize(scratch_data.fe_values.get_quadrature().size(), VectorType(n_components));
63 solution_dot.resize(scratch_data.fe_values.get_quadrature().size(), VectorType(n_components));
64 solution_interface[0].resize(scratch_data.fe_interface_values.get_quadrature().size(),
66 solution_interface[1].resize(scratch_data.fe_interface_values.get_quadrature().size(),
68 }
69
71
72 FEValues<dim> fe_values;
73 FEInterfaceValues<dim> fe_interface_values;
74
75 std::vector<VectorType> solution;
76 std::vector<VectorType> solution_dot;
77 array<std::vector<VectorType>, 2> solution_interface;
78 };
79
80 // TODO fewer memory allocations
81 template <typename NumberType> struct CopyData_R {
83 Vector<NumberType> cell_residual;
84 std::vector<types::global_dof_index> joint_dof_indices;
85
86 template <int dim> void reinit(const FEInterfaceValues<dim> &fe_iv)
87 {
88 cell_residual.reinit(fe_iv.n_current_interface_dofs());
89 joint_dof_indices = fe_iv.get_interface_dof_indices();
90 }
91 };
92
93 Vector<NumberType> cell_residual;
94 Vector<NumberType> cell_mass;
95 std::vector<types::global_dof_index> local_dof_indices;
96 std::vector<CopyDataFace_R> face_data;
97
98 template <class Iterator> void reinit(const Iterator &cell, uint dofs_per_cell)
99 {
100 cell_residual.reinit(dofs_per_cell);
101 cell_mass.reinit(dofs_per_cell);
102 local_dof_indices.resize(dofs_per_cell);
103 cell->get_dof_indices(local_dof_indices);
104 }
105 };
106
107 // TODO fewer memory allocations
108 template <typename NumberType> struct CopyData_J {
110 FullMatrix<NumberType> cell_jacobian;
111 FullMatrix<NumberType> extractor_cell_jacobian;
112 std::vector<types::global_dof_index> joint_dof_indices;
113
114 template <int dim> void reinit(const FEInterfaceValues<dim> &fe_iv, uint n_extractors)
115 {
116 uint dofs_per_cell = fe_iv.n_current_interface_dofs();
117 cell_jacobian.reinit(dofs_per_cell, dofs_per_cell);
118 if (n_extractors > 0) extractor_cell_jacobian.reinit(dofs_per_cell, n_extractors);
119 joint_dof_indices = fe_iv.get_interface_dof_indices();
120 }
121 };
122
123 FullMatrix<NumberType> cell_jacobian;
124 FullMatrix<NumberType> extractor_cell_jacobian;
125 FullMatrix<NumberType> cell_mass_jacobian;
126 std::vector<types::global_dof_index> local_dof_indices;
127 std::vector<CopyDataFace_J> face_data;
128
129 template <class Iterator> void reinit(const Iterator &cell, uint dofs_per_cell, uint n_extractors)
130 {
131 cell_jacobian.reinit(dofs_per_cell, dofs_per_cell);
132 if (n_extractors > 0) extractor_cell_jacobian.reinit(dofs_per_cell, n_extractors);
133 cell_mass_jacobian.reinit(dofs_per_cell, dofs_per_cell);
134 local_dof_indices.resize(dofs_per_cell);
135 cell->get_dof_indices(local_dof_indices);
136 }
137 };
138
139 template <typename NumberType> struct CopyData_I {
141 std::array<uint, 2> cell_indices;
142 std::array<double, 2> values;
143 };
144 std::vector<CopyFaceData_I> face_data;
145 double value;
147 };
148 } // namespace internal
149
155 template <typename Discretization_, typename Model_> class Assembler : public FEMAssembler<Discretization_, Model_>
156 {
158
159 public:
160 using Discretization = Discretization_;
161 using Model = Model_;
164
166 static constexpr uint n_components = Components::count_fe_functions(0);
167 static constexpr uint dim = Discretization::dim;
168
170 : Base(discretization, model, json),
171 quadrature(fe.degree + 1 + json.get_uint("/discretization/overintegration")),
172 quadrature_face(fe.degree + 1 + json.get_uint("/discretization/overintegration"))
173 {
174 static_assert(Components::count_fe_subsystems() == 1, "A DG model cannot have multiple submodels!");
175 reinit();
176 }
177
178 virtual void reinit_vector(VectorType &vec) const override { vec.reinit(dof_handler.n_dofs()); }
179
180 virtual void reinit() override
181 {
182 Timer timer;
183
184 Base::reinit();
185
186 // Mass sparsity pattern
187 {
188 DynamicSparsityPattern dsp(dof_handler.n_dofs());
189 DoFTools::make_sparsity_pattern(dof_handler, dsp, discretization.get_constraints(),
190 /*keep_constrained_dofs = */ true);
191 sparsity_pattern_mass.copy_from(dsp);
193 MatrixCreator::create_mass_matrix(dof_handler, quadrature, mass_matrix,
194 (const Function<dim, NumberType> *const)nullptr,
195 discretization.get_constraints());
196 }
197 // Jacobian sparsity pattern
198 {
199 DynamicSparsityPattern dsp(dof_handler.n_dofs());
200 DoFTools::make_flux_sparsity_pattern(dof_handler, dsp, discretization.get_constraints(),
201 /*keep_constrained_dofs = */ true);
202 sparsity_pattern_jacobian.copy_from(dsp);
203 }
204
205 timings_reinit.push_back(timer.wall_time());
206 }
207
208 virtual void rebuild_jacobian_sparsity() override
209 {
210 // Jacobian sparsity pattern
211 DynamicSparsityPattern dsp(dof_handler.n_dofs());
212 DoFTools::make_flux_sparsity_pattern(dof_handler, dsp, discretization.get_constraints(),
213 /*keep_constrained_dofs = */ true);
214 for (uint row = 0; row < dsp.n_rows(); ++row)
215 dsp.add_row_entries(row, extractor_dof_indices);
216 sparsity_pattern_jacobian.copy_from(dsp);
217 }
218
219 virtual const SparsityPattern &get_sparsity_pattern_jacobian() const override
220 {
222 }
223 virtual const SparseMatrix<NumberType> &get_mass_matrix() const override { return mass_matrix; }
224
231 virtual void refinement_indicator(Vector<double> &indicator, const VectorType &solution_global) override
232 {
233 using Iterator = typename DoFHandler<dim>::active_cell_iterator;
235 using CopyData = internal::CopyData_I<NumberType>;
236
237 const auto cell_worker = [&](const Iterator &t_cell, Scratch &scratch_data, CopyData &copy_data) {
238 scratch_data.fe_values.reinit(t_cell);
239 const auto &fe_v = scratch_data.fe_values;
240 copy_data.cell_index = t_cell->active_cell_index();
241 copy_data.value = 0;
242
243 const auto &JxW = fe_v.get_JxW_values();
244 const auto &q_points = fe_v.get_quadrature_points();
245 const auto &q_indices = fe_v.quadrature_point_indices();
246
247 auto &solution = scratch_data.solution;
248 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad;
249 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess;
250 solution_grad.resize(q_points.size(), std::vector<Tensor<1, dim, NumberType>>(n_components));
251 solution_hess.resize(q_points.size(), std::vector<Tensor<2, dim, NumberType>>(n_components));
252 fe_v.get_function_values(solution_global, solution);
253 fe_v.get_function_gradients(solution_global, solution_grad);
254 fe_v.get_function_hessians(solution_global, solution_hess);
255
256 double local_indicator = 0.;
257 for (const auto &q_index : q_indices) {
258 const auto &x_q = q_points[q_index];
259 const std::vector<double> nothing = {};
260 model.cell_indicator(local_indicator, x_q,
261 i_tie(solution[q_index], solution_grad[q_index], solution_hess[q_index]));
262 copy_data.value += JxW[q_index] * local_indicator;
263 }
264 };
265 const auto face_worker = [&](const Iterator &t_cell, const uint &f, const uint &sf, const Iterator &t_ncell,
266 const uint &nf, const unsigned int &nsf, Scratch &scratch_data,
267 CopyData &copy_data) {
268 scratch_data.fe_interface_values.reinit(t_cell, f, sf, t_ncell, nf, nsf);
269 const auto &fe_iv = scratch_data.fe_interface_values;
270 const auto &fe_iv_s = scratch_data.fe_interface_values.get_fe_face_values(0);
271 const auto &fe_iv_n = scratch_data.fe_interface_values.get_fe_face_values(1);
272
273 copy_data.face_data.emplace_back();
274 auto &copy_data_face = copy_data.face_data.emplace_back();
275 copy_data_face.cell_indices[0] = t_cell->active_cell_index();
276 copy_data_face.cell_indices[1] = t_ncell->active_cell_index();
277 copy_data_face.values[0] = 0;
278 copy_data_face.values[1] = 0;
279
280 const auto &JxW = fe_iv.get_JxW_values();
281 const auto &q_points = fe_iv.get_quadrature_points();
282 const auto &q_indices = fe_iv.quadrature_point_indices();
283 const std::vector<Tensor<1, dim>> &normals = fe_iv.get_normal_vectors();
284
285 auto &solution_s = scratch_data.solution_interface[0];
286 auto &solution_n = scratch_data.solution_interface[1];
287 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad_s;
288 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess_s;
289 solution_grad_s.resize(q_points.size(), std::vector<Tensor<1, dim, NumberType>>(n_components));
290 solution_hess_s.resize(q_points.size(), std::vector<Tensor<2, dim, NumberType>>(n_components));
291 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad_n;
292 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess_n;
293 solution_grad_n.resize(q_points.size(), std::vector<Tensor<1, dim, NumberType>>(n_components));
294 solution_hess_n.resize(q_points.size(), std::vector<Tensor<2, dim, NumberType>>(n_components));
295 fe_iv_s.get_function_values(solution_global, solution_s);
296 fe_iv_n.get_function_values(solution_global, solution_n);
297 fe_iv_s.get_function_gradients(solution_global, solution_grad_s);
298 fe_iv_n.get_function_gradients(solution_global, solution_grad_n);
299 fe_iv_s.get_function_hessians(solution_global, solution_hess_s);
300 fe_iv_n.get_function_hessians(solution_global, solution_hess_n);
301
302 array<double, 2> local_indicator{};
303 for (const auto &q_index : q_indices) {
304 const auto &x_q = q_points[q_index];
305 model.face_indicator(local_indicator, normals[q_index], x_q,
306 i_tie(solution_s[q_index], solution_grad_s[q_index], solution_hess_s[q_index]),
307 i_tie(solution_n[q_index], solution_grad_n[q_index], solution_hess_n[q_index]));
308
309 copy_data_face.values[0] += JxW[q_index] * local_indicator[0] * (1. + t_cell->at_boundary());
310 copy_data_face.values[1] += JxW[q_index] * local_indicator[1] * (1. + t_ncell->at_boundary());
311 }
312 };
313 const auto copier = [&](const CopyData &c) {
314 for (auto &cdf : c.face_data)
315 for (uint j = 0; j < 2; ++j)
316 indicator[cdf.cell_indices[j]] += cdf.values[j];
317 indicator[c.cell_index] += c.value;
318 };
319 const UpdateFlags update_flags =
320 update_values | update_gradients | update_quadrature_points | update_JxW_values | update_hessians;
321 const UpdateFlags interface_update_flags = update_values | update_gradients | update_quadrature_points |
322 update_JxW_values | update_normal_vectors | update_hessians;
323
324 Scratch scratch_data(mapping, fe, quadrature, quadrature_face, update_flags, interface_update_flags);
325 CopyData copy_data;
326 MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells;
327
328 MeshWorker::mesh_loop(dof_handler.begin_active(), dof_handler.end(), cell_worker, copier, scratch_data,
329 copy_data, assemble_flags, nullptr, face_worker, threads, batch_size);
330 }
331
332 virtual void mass(VectorType &mass, const VectorType &solution_global, const VectorType &solution_global_dot,
333 NumberType weight) override
334 {
335 using Iterator = typename DoFHandler<dim>::active_cell_iterator;
337 using CopyData = internal::CopyData_R<NumberType>;
338 const auto &constraints = discretization.get_constraints();
339
340 const auto cell_worker = [&](const Iterator &cell, Scratch &scratch_data, CopyData &copy_data) {
341 scratch_data.fe_values.reinit(cell);
342 const auto &fe_v = scratch_data.fe_values;
343 const uint n_dofs = fe_v.get_fe().n_dofs_per_cell();
344
345 copy_data.reinit(cell, n_dofs);
346 const auto &JxW = fe_v.get_JxW_values();
347 const auto &q_points = fe_v.get_quadrature_points();
348 const auto &q_indices = fe_v.quadrature_point_indices();
349
350 auto &solution = scratch_data.solution;
351 auto &solution_dot = scratch_data.solution_dot;
352 fe_v.get_function_values(solution_global, solution);
353 fe_v.get_function_values(solution_global_dot, solution_dot);
354
355 array<NumberType, n_components> mass{};
356 for (const auto &q_index : q_indices) {
357 const auto &x_q = q_points[q_index];
358 model.mass(mass, x_q, solution[q_index], solution_dot[q_index]);
359
360 for (uint i = 0; i < n_dofs; ++i) {
361 const auto component_i =
362 fe.system_to_component_index(i).first; // TODO is this `fe` equivalent to? `fe_v[0]->get_fe()`?
363 copy_data.cell_residual(i) += weight * JxW[q_index] *
364 fe_v.shape_value_component(i, q_index, component_i) *
365 mass[component_i]; // +phi_i(x_q) * mass(x_q, u_q)
366 }
367 }
368 };
369 const auto copier = [&](const CopyData &c) {
370 constraints.distribute_local_to_global(c.cell_residual, c.local_dof_indices, mass);
371 };
372
373 Scratch scratch_data(mapping, fe, quadrature, quadrature_face);
374 CopyData copy_data;
375 MeshWorker::AssembleFlags flags = MeshWorker::assemble_own_cells;
376
377 MeshWorker::mesh_loop(dof_handler.begin_active(), dof_handler.end(), cell_worker, copier, scratch_data,
378 copy_data, flags, nullptr, nullptr, threads, batch_size);
379 }
380
381 virtual void residual(VectorType &residual, const VectorType &solution_global, NumberType weight,
382 const VectorType &solution_global_dot, NumberType weight_mass,
383 const VectorType &variables = VectorType()) override
384 {
385 using Iterator = typename DoFHandler<dim>::active_cell_iterator;
387 using CopyData = internal::CopyData_R<NumberType>;
388 const auto &constraints = discretization.get_constraints();
389
390 // Find the EoM and extract whatever data is needed for the model.
391 std::array<NumberType, Components::count_extractors()> __extracted_data{{}};
392 if constexpr (Components::count_extractors() > 0)
393 this->extract(__extracted_data, solution_global, variables, true, false, true);
394 const auto &extracted_data = __extracted_data;
395
396 const auto cell_worker = [&](const Iterator &cell, Scratch &scratch_data, CopyData &copy_data) {
397 scratch_data.fe_values.reinit(cell);
398 const auto &fe_v = scratch_data.fe_values;
399 const uint n_dofs = fe_v.get_fe().n_dofs_per_cell();
400
401 copy_data.reinit(cell, n_dofs);
402 const auto &JxW = fe_v.get_JxW_values();
403 const auto &q_points = fe_v.get_quadrature_points();
404 const auto &q_indices = fe_v.quadrature_point_indices();
405
406 auto &solution = scratch_data.solution;
407 auto &solution_dot = scratch_data.solution_dot;
408 fe_v.get_function_values(solution_global, solution);
409 fe_v.get_function_values(solution_global_dot, solution_dot);
410
411 array<NumberType, n_components> mass{};
412 array<Tensor<1, dim, NumberType>, n_components> flux{};
413 array<NumberType, n_components> source{};
414 for (const auto &q_index : q_indices) {
415 const auto &x_q = q_points[q_index];
416 model.mass(mass, x_q, solution[q_index], solution_dot[q_index]);
417 model.flux(flux, x_q, fe_tie(solution[q_index], extracted_data, variables));
418 model.source(source, x_q, fe_tie(solution[q_index], extracted_data, variables));
419
420 for (uint i = 0; i < n_dofs; ++i) {
421 const auto component_i = fe.system_to_component_index(i).first;
422 copy_data.cell_mass(i) += weight_mass * JxW[q_index] *
423 fe_v.shape_value_component(i, q_index, component_i) *
424 mass[component_i]; // +phi_i(x_q) * mass(x_q, u_q)
425 copy_data.cell_residual(i) += JxW[q_index] * weight * // dx *
426 (-scalar_product(fe_v.shape_grad_component(i, q_index, component_i),
427 flux[component_i]) // -dphi_i(x_q) * flux(x_q, u_q)
428 + fe_v.shape_value_component(i, q_index, component_i) *
429 source[component_i]); // -phi_i(x_q) * source(x_q, u_q)
430 }
431 }
432 };
433 const auto boundary_worker = [&](const Iterator &cell, const uint &face_no, Scratch &scratch_data,
434 CopyData &copy_data) {
435 scratch_data.fe_interface_values.reinit(cell, face_no);
436 const auto &fe_fv = scratch_data.fe_interface_values.get_fe_face_values(0);
437 const uint n_dofs = fe_fv.get_fe().n_dofs_per_cell();
438
439 const auto &JxW = fe_fv.get_JxW_values();
440 const auto &q_points = fe_fv.get_quadrature_points();
441 const auto &q_indices = fe_fv.quadrature_point_indices();
442 auto &solution = scratch_data.solution_interface[0];
443
444 array<Tensor<1, dim, NumberType>, n_components> numflux{};
445
446 fe_fv.get_function_values(solution_global, solution);
447 const std::vector<Tensor<1, dim>> &normals = fe_fv.get_normal_vectors();
448
449 for (const auto &q_index : q_indices) {
450 const auto &x_q = q_points[q_index];
451 model.boundary_numflux(numflux, normals[q_index], x_q,
452 fe_tie(solution[q_index], extracted_data, variables));
453
454 for (uint i = 0; i < n_dofs; ++i) {
455 const auto component_i = fe.system_to_component_index(i).first;
456 copy_data.cell_residual(i) +=
457 weight * JxW[q_index] * // dx
458 (fe_fv.shape_value_component(i, q_index, component_i) *
459 scalar_product(numflux[component_i], normals[q_index])); // phi_i(x_q) * numflux(x_q, u_q) * n(x_q)
460 }
461 }
462 };
463 const auto face_worker = [&](const Iterator &cell, const uint &f, const uint &sf, const Iterator &ncell,
464 const uint &nf, const uint &nsf, Scratch &scratch_data, CopyData &copy_data) {
465 scratch_data.fe_interface_values.reinit(cell, f, sf, ncell, nf, nsf);
466 const auto &fe_iv = scratch_data.fe_interface_values;
467 const auto &fe_iv_s = scratch_data.fe_interface_values.get_fe_face_values(0);
468 const auto &fe_iv_n = scratch_data.fe_interface_values.get_fe_face_values(1);
469 const uint n_dofs = fe_iv.n_current_interface_dofs();
470
471 copy_data.face_data.emplace_back();
472 auto &copy_data_face = copy_data.face_data.back();
473 copy_data_face.reinit(fe_iv);
474
475 const auto &JxW = fe_iv.get_JxW_values();
476 const auto &q_points = fe_iv.get_quadrature_points();
477 const auto &q_indices = fe_iv.quadrature_point_indices();
478 auto &solution_s = scratch_data.solution_interface[0];
479 auto &solution_n = scratch_data.solution_interface[1];
480
481 array<Tensor<1, dim, NumberType>, n_components> numflux{};
482
483 fe_iv_s.get_function_values(solution_global, solution_s);
484 fe_iv_n.get_function_values(solution_global, solution_n);
485 const std::vector<Tensor<1, dim>> &normals = fe_iv.get_normal_vectors();
486
487 for (const auto &q_index : q_indices) {
488 const auto &x_q = q_points[q_index];
489 model.numflux(numflux, normals[q_index], x_q, fe_tie(solution_s[q_index], extracted_data, variables),
490 fe_tie(solution_n[q_index], extracted_data, variables));
491
492 for (uint i = 0; i < n_dofs; ++i) {
493 const auto &cd_i = fe_iv.interface_dof_to_dof_indices(i);
494 const auto component_i = cd_i[0] == numbers::invalid_unsigned_int
495 ? fe.system_to_component_index(cd_i[1]).first
496 : fe.system_to_component_index(cd_i[0]).first;
497 copy_data_face.cell_residual(i) +=
498 weight * JxW[q_index] * // dx
499 (fe_iv.jump_in_shape_values(i, q_index, component_i) *
500 scalar_product(numflux[component_i],
501 normals[q_index])); // [[phi_i(x_q)]] * numflux(x_q, u_q) * n(x_q)
502 }
503 }
504 };
505 const auto copier = [&](const CopyData &c) {
506 constraints.distribute_local_to_global(c.cell_residual, c.local_dof_indices, residual);
507 constraints.distribute_local_to_global(c.cell_mass, c.local_dof_indices, residual);
508 for (auto &cdf : c.face_data)
509 constraints.distribute_local_to_global(cdf.cell_residual, cdf.joint_dof_indices, residual);
510 };
511
512 Scratch scratch_data(mapping, fe, quadrature, quadrature_face);
513 CopyData copy_data;
514 MeshWorker::AssembleFlags flags = MeshWorker::assemble_own_cells | MeshWorker::assemble_boundary_faces |
515 MeshWorker::assemble_own_interior_faces_once;
516
517 Timer timer;
518 MeshWorker::mesh_loop(dof_handler.begin_active(), dof_handler.end(), cell_worker, copier, scratch_data,
519 copy_data, flags, boundary_worker, face_worker, threads, batch_size);
520 timings_residual.push_back(timer.wall_time());
521 }
522
523 virtual void jacobian_mass(SparseMatrix<NumberType> &jacobian, const VectorType &solution_global,
524 const VectorType &solution_global_dot, NumberType alpha = 1.,
525 NumberType beta = 1.) override
526 {
527 using Iterator = typename DoFHandler<dim>::active_cell_iterator;
529 using CopyData = internal::CopyData_J<NumberType>;
530 const auto &constraints = discretization.get_constraints();
531
532 const auto cell_worker = [&](const Iterator &cell, Scratch &scratch_data, CopyData &copy_data) {
533 scratch_data.fe_values.reinit(cell);
534 const auto &fe_v = scratch_data.fe_values;
535 const uint n_dofs = fe_v.get_fe().n_dofs_per_cell();
536
537 copy_data.reinit(cell, n_dofs, Components::count_extractors());
538 const auto &JxW = fe_v.get_JxW_values();
539 const auto &q_points = fe_v.get_quadrature_points();
540 const auto &q_indices = fe_v.quadrature_point_indices();
541
542 auto &solution = scratch_data.solution;
543 auto &solution_dot = scratch_data.solution_dot;
544 fe_v.get_function_values(solution_global, solution);
545 fe_v.get_function_values(solution_global_dot, solution_dot);
546
549 for (const auto &q_index : q_indices) {
550 const auto &x_q = q_points[q_index];
551 model.template jacobian_mass<0>(j_mass, x_q, solution[q_index], solution_dot[q_index]);
552 model.template jacobian_mass<1>(j_mass_dot, x_q, solution[q_index], solution_dot[q_index]);
553
554 for (uint i = 0; i < n_dofs; ++i) {
555 const auto component_i = fe.system_to_component_index(i).first;
556 for (uint j = 0; j < n_dofs; ++j) {
557 const auto component_j = fe.system_to_component_index(j).first;
558 copy_data.cell_jacobian(i, j) +=
559 JxW[q_index] * fe_v.shape_value_component(j, q_index, component_j) *
560 fe_v.shape_value_component(i, q_index, component_i) *
561 (alpha * j_mass_dot(component_i, component_j) + beta * j_mass(component_i, component_j));
562 }
563 }
564 }
565 };
566 const auto copier = [&](const CopyData &c) {
567 constraints.distribute_local_to_global(c.cell_jacobian, c.local_dof_indices, jacobian);
568 };
569
570 Scratch scratch_data(mapping, fe, quadrature, quadrature_face);
571 CopyData copy_data;
572 MeshWorker::AssembleFlags flags = MeshWorker::assemble_own_cells;
573
574 Timer timer;
575 MeshWorker::mesh_loop(dof_handler.begin_active(), dof_handler.end(), cell_worker, copier, scratch_data,
576 copy_data, flags, nullptr, nullptr, threads, batch_size);
577 timings_jacobian.push_back(timer.wall_time());
578 }
579
580 virtual void jacobian(SparseMatrix<NumberType> &jacobian, const VectorType &solution_global, NumberType weight,
581 const VectorType &solution_global_dot, NumberType alpha, NumberType beta,
582 const VectorType &variables = VectorType()) override
583 {
584 using Iterator = typename DoFHandler<dim>::active_cell_iterator;
586 using CopyData = internal::CopyData_J<NumberType>;
587 const auto &constraints = discretization.get_constraints();
588
589 // Find the EoM and extract whatever data is needed for the model.
590 std::array<NumberType, Components::count_extractors()> extracted_data{{}};
591 if constexpr (Components::count_extractors() > 0) {
592 this->extract(extracted_data, solution_global, variables, true, true, true);
593 if (this->jacobian_extractors(this->extractor_jacobian, solution_global, variables))
595 }
596
597 const auto cell_worker = [&](const Iterator &cell, Scratch &scratch_data, CopyData &copy_data) {
598 scratch_data.fe_values.reinit(cell);
599 const auto &fe_v = scratch_data.fe_values;
600 const uint n_dofs = fe_v.get_fe().n_dofs_per_cell();
601
602 copy_data.reinit(cell, n_dofs, Components::count_extractors());
603 const auto &JxW = fe_v.get_JxW_values();
604 const auto &q_points = fe_v.get_quadrature_points();
605 const auto &q_indices = fe_v.quadrature_point_indices();
606
607 auto &solution = scratch_data.solution;
608 auto &solution_dot = scratch_data.solution_dot;
609 fe_v.get_function_values(solution_global, solution);
610 fe_v.get_function_values(solution_global_dot, solution_dot);
611
615 SimpleMatrix<Tensor<1, dim>, n_components, Components::count_extractors()> j_extr_flux;
617 SimpleMatrix<NumberType, n_components, Components::count_extractors()> j_extr_source;
618 for (const auto &q_index : q_indices) {
619 const auto &x_q = q_points[q_index];
620 model.template jacobian_mass<0>(j_mass, x_q, solution[q_index], solution_dot[q_index]);
621 model.template jacobian_mass<1>(j_mass_dot, x_q, solution[q_index], solution_dot[q_index]);
622 model.template jacobian_flux<0, 0>(j_flux, x_q, fe_tie(solution[q_index], extracted_data, variables));
623 model.template jacobian_source<0, 0>(j_source, x_q, fe_tie(solution[q_index], extracted_data, variables));
624 if constexpr (Components::count_extractors() > 0) {
625 model.template jacobian_flux_extr<1>(j_extr_flux, x_q,
626 fe_tie(solution[q_index], extracted_data, variables));
627 model.template jacobian_source_extr<1>(j_extr_source, x_q,
628 fe_tie(solution[q_index], extracted_data, variables));
629 }
630
631 for (uint i = 0; i < n_dofs; ++i) {
632 const auto component_i = fe.system_to_component_index(i).first;
633 for (uint j = 0; j < n_dofs; ++j) {
634 const auto component_j = fe.system_to_component_index(j).first;
635 copy_data.cell_jacobian(i, j) += weight * JxW[q_index] *
636 fe_v.shape_value_component(j, q_index, component_j) * // dx * phi_j * (
637 (-scalar_product(fe_v.shape_grad_component(i, q_index, component_i),
638 j_flux(component_i, component_j)) // -dphi_i * jflux
639 + fe_v.shape_value_component(i, q_index, component_i) *
640 j_source(component_i, component_j)); // -phi_i * jsource)
641 copy_data.cell_mass_jacobian(i, j) +=
642 JxW[q_index] * fe_v.shape_value_component(j, q_index, component_j) *
643 fe_v.shape_value_component(i, q_index, component_i) *
644 (alpha * j_mass_dot(component_i, component_j) + beta * j_mass(component_i, component_j));
645 }
646 // extractor contribution
647 if constexpr (Components::count_extractors() > 0)
648 for (uint e = 0; e < Components::count_extractors(); ++e)
649 copy_data.extractor_cell_jacobian(i, e) +=
650 weight * JxW[q_index] * // dx * phi_j * (
651 (-scalar_product(fe_v.shape_grad_component(i, q_index, component_i),
652 j_extr_flux(component_i, e)) // -dphi_i * jflux
653 + fe_v.shape_value_component(i, q_index, component_i) *
654 j_extr_source(component_i, e)); // -phi_i * jsource)
655 }
656 }
657 };
658 const auto boundary_worker = [&](const Iterator &cell, const uint &face_no, Scratch &scratch_data,
659 CopyData &copy_data) {
660 scratch_data.fe_interface_values.reinit(cell, face_no);
661 const auto &fe_fv = scratch_data.fe_interface_values.get_fe_face_values(0);
662 const uint n_dofs = fe_fv.get_fe().n_dofs_per_cell();
663
664 const auto &JxW = fe_fv.get_JxW_values();
665 const auto &q_points = fe_fv.get_quadrature_points();
666 const auto &q_indices = fe_fv.quadrature_point_indices();
667 auto &solution = scratch_data.solution_interface[0];
668
669 SimpleMatrix<Tensor<1, dim>, n_components> j_boundary_numflux;
670 SimpleMatrix<Tensor<1, dim>, n_components, Components::count_extractors()> j_extr_boundary_numflux;
671
672 fe_fv.get_function_values(solution_global, solution);
673 const std::vector<Tensor<1, dim>> &normals = fe_fv.get_normal_vectors();
674
675 for (const auto &q_index : q_indices) {
676 const auto &x_q = q_points[q_index];
677 model.template jacobian_boundary_numflux<0, 0>(j_boundary_numflux, normals[q_index], x_q,
678 fe_tie(solution[q_index], extracted_data, variables));
679 if constexpr (Components::count_extractors() > 0)
680 model.template jacobian_boundary_numflux_extr<1>(j_extr_boundary_numflux, normals[q_index], x_q,
681 fe_tie(solution[q_index], extracted_data, variables));
682
683 for (uint i = 0; i < n_dofs; ++i) {
684 const auto component_i = fe.system_to_component_index(i).first;
685 for (uint j = 0; j < n_dofs; ++j) {
686 const auto component_j = fe.system_to_component_index(j).first;
687 copy_data.cell_jacobian(i, j) +=
688 weight * JxW[q_index] * fe_fv.shape_value_component(j, q_index, component_j) * // dx * phi_j(x_q)
689 (fe_fv.shape_value_component(i, q_index, component_i) *
690 scalar_product(j_boundary_numflux(component_i, component_j),
691 normals[q_index])); // phi_i(x_q) * j_numflux(x_q, u_q) * n(x_q)
692 }
693 // extractor contribution
694 if constexpr (Components::count_extractors() > 0)
695 for (uint e = 0; e < Components::count_extractors(); ++e)
696 copy_data.extractor_cell_jacobian(i, e) +=
697 weight * JxW[q_index] * // dx * phi_j(x_q)
698 (fe_fv.shape_value_component(i, q_index, component_i) *
699 scalar_product(j_extr_boundary_numflux(component_i, e),
700 normals[q_index])); // phi_i(x_q) * j_numflux(x_q, u_q) * n(x_q)
701 }
702 }
703 };
704 const auto face_worker = [&](const Iterator &cell, const uint &f, const uint &sf, const Iterator &ncell,
705 const uint &nf, const uint &nsf, Scratch &scratch_data, CopyData &copy_data) {
706 scratch_data.fe_interface_values.reinit(cell, f, sf, ncell, nf, nsf);
707 const auto &fe_iv = scratch_data.fe_interface_values;
708 const auto &fe_iv_s = scratch_data.fe_interface_values.get_fe_face_values(0);
709 const auto &fe_iv_n = scratch_data.fe_interface_values.get_fe_face_values(1);
710 const uint n_dofs = fe_iv.n_current_interface_dofs();
711
712 copy_data.face_data.emplace_back();
713 auto &copy_data_face = copy_data.face_data.back();
714 copy_data_face.reinit(fe_iv, Components::count_extractors());
715
716 const auto &JxW = fe_iv.get_JxW_values();
717 const auto &q_points = fe_iv.get_quadrature_points();
718 const auto &q_indices = fe_iv.quadrature_point_indices();
719 auto &solution_s = scratch_data.solution_interface[0];
720 auto &solution_n = scratch_data.solution_interface[1];
721
722 fe_iv_s.get_function_values(solution_global, solution_s);
723 fe_iv_n.get_function_values(solution_global, solution_n);
724 const std::vector<Tensor<1, dim>> &normals = fe_iv.get_normal_vectors();
725
726 array<SimpleMatrix<Tensor<1, dim>, n_components>, 2> j_numflux;
727 array<SimpleMatrix<Tensor<1, dim>, n_components, Components::count_extractors()>, 2> j_extr_numflux;
728 for (const auto &q_index : q_indices) {
729 const auto &x_q = q_points[q_index];
730 model.template jacobian_numflux<0, 0>(j_numflux, normals[q_index], x_q,
731 fe_tie(solution_s[q_index], extracted_data, variables),
732 fe_tie(solution_n[q_index], extracted_data, variables));
733 if constexpr (Components::count_extractors() > 0)
734 model.template jacobian_numflux_extr<1>(j_extr_numflux, normals[q_index], x_q,
735 fe_tie(solution_s[q_index], extracted_data, variables),
736 fe_tie(solution_n[q_index], extracted_data, variables));
737
738 for (uint i = 0; i < n_dofs; ++i) {
739 const auto &cd_i = fe_iv.interface_dof_to_dof_indices(i);
740 const uint face_no_i = cd_i[0] == numbers::invalid_unsigned_int ? 1 : 0;
741 const auto &component_i = fe.system_to_component_index(cd_i[face_no_i]).first;
742 for (uint j = 0; j < n_dofs; ++j) {
743 const auto &cd_j = fe_iv.interface_dof_to_dof_indices(j);
744 const uint face_no_j = cd_j[0] == numbers::invalid_unsigned_int ? 1 : 0;
745 const auto &component_j = fe.system_to_component_index(cd_j[face_no_j]).first;
746
747 copy_data_face.cell_jacobian(i, j) +=
748 weight * JxW[q_index] *
749 fe_iv.get_fe_face_values(face_no_j).shape_value_component(cd_j[face_no_j], q_index,
750 component_j) * // dx * phi_j(x_q)
751 (fe_iv.jump_in_shape_values(i, q_index, component_i) *
752 scalar_product(j_numflux[face_no_j](component_i, component_j),
753 normals[q_index])); // [[phi_i(x_q)]] * j_numflux(x_q, u_q)
754 }
755 // extractor contribution
756 if constexpr (Components::count_extractors() > 0)
757 for (uint e = 0; e < Components::count_extractors(); ++e)
758 copy_data_face.extractor_cell_jacobian(i, e) +=
759 weight * JxW[q_index] * // dx * phi_j(x_q)
760 (fe_iv.jump_in_shape_values(i, q_index, component_i) *
761 scalar_product(j_extr_numflux[face_no_i](component_i, e),
762 normals[q_index])); // [[phi_i(x_q)]] * j_numflux(x_q, u_q)
763 }
764 }
765 };
766 const auto copier = [&](const CopyData &c) {
767 constraints.distribute_local_to_global(c.cell_jacobian, c.local_dof_indices, jacobian);
768 constraints.distribute_local_to_global(c.cell_mass_jacobian, c.local_dof_indices, jacobian);
769 for (auto &cdf : c.face_data) {
770 constraints.distribute_local_to_global(cdf.cell_jacobian, cdf.joint_dof_indices, jacobian);
771 if constexpr (Components::count_extractors() > 0) {
772 FullMatrix<NumberType> extractor_dependence(cdf.joint_dof_indices.size(), extractor_dof_indices.size());
773 cdf.extractor_cell_jacobian.mmult(extractor_dependence, this->extractor_jacobian);
774 constraints.distribute_local_to_global(extractor_dependence, cdf.joint_dof_indices, extractor_dof_indices,
775 jacobian);
776 }
777 }
778 if constexpr (Components::count_extractors() > 0) {
779 FullMatrix<NumberType> extractor_dependence(c.local_dof_indices.size(), extractor_dof_indices.size());
780 c.extractor_cell_jacobian.mmult(extractor_dependence, this->extractor_jacobian);
781 constraints.distribute_local_to_global(extractor_dependence, c.local_dof_indices, extractor_dof_indices,
782 jacobian);
783 }
784 };
785
786 Scratch scratch_data(mapping, fe, quadrature, quadrature_face);
787 CopyData copy_data;
788 MeshWorker::AssembleFlags flags = MeshWorker::assemble_own_cells | MeshWorker::assemble_boundary_faces |
789 MeshWorker::assemble_own_interior_faces_once;
790
791 Timer timer;
792 MeshWorker::mesh_loop(dof_handler.begin_active(), dof_handler.end(), cell_worker, copier, scratch_data,
793 copy_data, flags, boundary_worker, face_worker, threads, batch_size);
794 timings_jacobian.push_back(timer.wall_time());
795 }
796
797 void log(const std::string logger)
798 {
799 std::stringstream ss;
800 ss << "DG Assembler: " << std::endl;
801 ss << " Reinit: " << average_time_reinit() * 1000 << "ms (" << num_reinits() << ")" << std::endl;
802 ss << " Residual: " << average_time_residual_assembly() * 1000 << "ms (" << num_residuals() << ")"
803 << std::endl;
804 ss << " Jacobian: " << average_time_jacobian_assembly() * 1000 << "ms (" << num_jacobians() << ")"
805 << std::endl;
806 spdlog::get(logger)->info(ss.str());
807 }
808
809 double average_time_reinit() const
810 {
811 double t = 0.;
812 double n = timings_reinit.size();
813 for (const auto &t_ : timings_reinit)
814 t += t_ / n;
815 return t;
816 }
817 uint num_reinits() const { return timings_reinit.size(); }
818
820 {
821 double t = 0.;
822 double n = timings_residual.size();
823 for (const auto &t_ : timings_residual)
824 t += t_ / n;
825 return t;
826 }
827 uint num_residuals() const { return timings_residual.size(); }
828
830 {
831 double t = 0.;
832 double n = timings_jacobian.size();
833 for (const auto &t_ : timings_jacobian)
834 t += t_ / n;
835 return t;
836 }
837 uint num_jacobians() const { return timings_jacobian.size(); }
838
839 protected:
841 using Base::dof_handler;
842 using Base::fe;
843 using Base::mapping;
844 using Base::model;
845
846 QGauss<dim> quadrature;
847 QGauss<dim - 1> quadrature_face;
848 using Base::batch_size;
849 using Base::threads;
850
851 SparsityPattern sparsity_pattern_mass;
853 SparseMatrix<NumberType> mass_matrix;
854
855 std::vector<double> timings_reinit;
856 std::vector<double> timings_residual;
857 std::vector<double> timings_jacobian;
858
860 };
861 } // namespace DG
862} // namespace DiFfRG
The basic assembler that can be used for any standard DG scheme with flux and source.
Definition dg.hh:156
static constexpr uint n_components
Definition dg.hh:166
Model & model
Definition common.hh:333
virtual void jacobian(SparseMatrix< NumberType > &jacobian, const VectorType &solution_global, NumberType weight, const VectorType &solution_global_dot, NumberType alpha, NumberType beta, const VectorType &variables=VectorType()) override
Definition dg.hh:580
SparsityPattern sparsity_pattern_mass
Definition dg.hh:851
const Mapping< dim > & mapping
Definition common.hh:336
virtual const SparsityPattern & get_sparsity_pattern_jacobian() const override
Obtain the sparsity pattern of the jacobian matrix.
Definition dg.hh:219
void log(const std::string logger)
Definition dg.hh:797
SparsityPattern sparsity_pattern_jacobian
Definition dg.hh:852
const FiniteElement< dim > & fe
Definition common.hh:334
typename Discretization::NumberType NumberType
Definition dg.hh:162
double average_time_residual_assembly()
Definition dg.hh:819
QGauss< dim - 1 > quadrature_face
Definition dg.hh:847
virtual void reinit() override
Reinitialize the assembler. This is necessary if the mesh has changed, e.g. after a mesh refinement.
Definition dg.hh:180
std::vector< double > timings_reinit
Definition dg.hh:855
typename Discretization::Components Components
Definition dg.hh:165
SparseMatrix< NumberType > mass_matrix
Definition dg.hh:853
uint num_residuals() const
Definition dg.hh:827
virtual void mass(VectorType &mass, const VectorType &solution_global, const VectorType &solution_global_dot, NumberType weight) override
Definition dg.hh:332
typename Discretization::VectorType VectorType
Definition dg.hh:163
uint threads
Definition common.hh:338
uint num_jacobians() const
Definition dg.hh:837
static constexpr uint dim
Definition dg.hh:167
Assembler(Discretization &discretization, Model &model, const JSONValue &json)
Definition dg.hh:169
Discretization_ Discretization
Definition dg.hh:160
uint num_reinits() const
Definition dg.hh:817
virtual void jacobian_mass(SparseMatrix< NumberType > &jacobian, const VectorType &solution_global, const VectorType &solution_global_dot, NumberType alpha=1., NumberType beta=1.) override
Definition dg.hh:523
Model_ Model
Definition dg.hh:161
const DoFHandler< dim > & dof_handler
Definition common.hh:335
double average_time_reinit() const
Definition dg.hh:809
Discretization & discretization
Definition common.hh:332
virtual void rebuild_jacobian_sparsity() override
Definition dg.hh:208
virtual void refinement_indicator(Vector< double > &indicator, const VectorType &solution_global) override
refinement indicator for adaptivity. Calls the model's cell_indicator and face_indicator functions.
Definition dg.hh:231
virtual void residual(VectorType &residual, const VectorType &solution_global, NumberType weight, const VectorType &solution_global_dot, NumberType weight_mass, const VectorType &variables=VectorType()) override
Definition dg.hh:381
uint batch_size
Definition common.hh:339
std::vector< types::global_dof_index > extractor_dof_indices
Definition common.hh:350
virtual const SparseMatrix< NumberType > & get_mass_matrix() const override
Obtain the mass matrix.
Definition dg.hh:223
virtual void reinit_vector(VectorType &vec) const override
Definition dg.hh:178
std::vector< double > timings_jacobian
Definition dg.hh:857
double average_time_jacobian_assembly()
Definition dg.hh:829
std::vector< double > timings_residual
Definition dg.hh:856
QGauss< dim > quadrature
Definition dg.hh:846
static constexpr uint dim
Definition dg.hh:38
Vector< NumberType > VectorType
Definition dg.hh:35
NumberType_ NumberType
Definition dg.hh:34
Components_ Components
Definition dg.hh:33
The basic assembler that can be used for any standard CG scheme with flux and source.
Definition common.hh:39
Model & model
Definition common.hh:333
const Mapping< dim > & mapping
Definition common.hh:336
FullMatrix< NumberType > extractor_jacobian
Definition common.hh:346
const FiniteElement< dim > & fe
Definition common.hh:334
void extract(std::array< NumberType, Components::count_extractors()> &data, const VectorType &solution_global, const VectorType &variables, bool search_EoM, bool set_EoM, bool postprocess) const
Definition common.hh:195
bool jacobian_extractors(FullMatrix< NumberType > &extractor_jacobian, const VectorType &solution_global, const VectorType &variables)
Definition common.hh:232
uint threads
Definition common.hh:338
virtual void reinit() override
Reinitialize the assembler. This is necessary if the mesh has changed, e.g. after a mesh refinement.
Definition common.hh:105
const DoFHandler< dim > & dof_handler
Definition common.hh:335
Discretization & discretization
Definition common.hh:332
uint batch_size
Definition common.hh:339
std::vector< types::global_dof_index > extractor_dof_indices
Definition common.hh:350
static constexpr int nothing
Definition common.hh:41
A wrapper around the boost json value class.
Definition json.hh:19
Definition quadrature.hh:50
size_t size() const
A simple NxM-matrix class, which is used for cell-wise Jacobians.
Definition tuples.hh:153
auto fe_tie(T &&...t)
Definition dg.hh:16
auto i_tie(T &&...t)
Definition dg.hh:21
Definition complex_math.hh:14
unsigned int uint
Definition utils.hh:22
std::array< uint, 2 > cell_indices
Definition dg.hh:141
std::array< double, 2 > values
Definition dg.hh:142
std::vector< CopyFaceData_I > face_data
Definition dg.hh:144
uint cell_index
Definition dg.hh:146
double value
Definition dg.hh:145
void reinit(const FEInterfaceValues< dim > &fe_iv, uint n_extractors)
Definition dg.hh:114
FullMatrix< NumberType > extractor_cell_jacobian
Definition dg.hh:111
FullMatrix< NumberType > cell_jacobian
Definition dg.hh:110
std::vector< types::global_dof_index > joint_dof_indices
Definition dg.hh:112
FullMatrix< NumberType > cell_mass_jacobian
Definition dg.hh:125
std::vector< types::global_dof_index > local_dof_indices
Definition dg.hh:126
FullMatrix< NumberType > extractor_cell_jacobian
Definition dg.hh:124
FullMatrix< NumberType > cell_jacobian
Definition dg.hh:123
void reinit(const Iterator &cell, uint dofs_per_cell, uint n_extractors)
Definition dg.hh:129
std::vector< CopyDataFace_J > face_data
Definition dg.hh:127
Vector< NumberType > cell_residual
Definition dg.hh:83
std::vector< types::global_dof_index > joint_dof_indices
Definition dg.hh:84
void reinit(const FEInterfaceValues< dim > &fe_iv)
Definition dg.hh:86
std::vector< CopyDataFace_R > face_data
Definition dg.hh:96
Vector< NumberType > cell_mass
Definition dg.hh:94
void reinit(const Iterator &cell, uint dofs_per_cell)
Definition dg.hh:98
std::vector< types::global_dof_index > local_dof_indices
Definition dg.hh:95
Vector< NumberType > cell_residual
Definition dg.hh:93
Class to hold data for each assembly thread, i.e. FEValues for cells, interfaces, as well as pre-allo...
Definition dg.hh:32
array< std::vector< VectorType >, 2 > solution_interface
Definition dg.hh:77
typename Discretization::NumberType NumberType
Definition dg.hh:34
FEInterfaceValues< dim > fe_interface_values
Definition dg.hh:73
Vector< NumberType > VectorType
Definition dg.hh:35
std::vector< VectorType > solution
Definition dg.hh:75
ScratchData(const ScratchData< Discretization > &scratch_data)
Definition dg.hh:53
std::vector< VectorType > solution_dot
Definition dg.hh:76
ScratchData(const Mapping< dim > &mapping, const FiniteElement< dim > &fe, const Quadrature< dim > &quadrature, const Quadrature< dim - 1 > &quadrature_face, const UpdateFlags update_flags=update_values|update_gradients|update_quadrature_points|update_JxW_values, const UpdateFlags interface_update_flags=update_values|update_gradients|update_quadrature_points|update_JxW_values|update_normal_vectors)
Definition dg.hh:37
FEValues< dim > fe_values
Definition dg.hh:72
static constexpr int dim
Definition dg.hh:33
const uint n_components
Definition dg.hh:70
A class to store a tuple with elements that can be accessed by name. The names are stored as FixedStr...
Definition tuples.hh:27