/home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/discretization/FEM/assembler/dg.hh Source File#

DiFfRG: /home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/discretization/FEM/assembler/dg.hh Source File
DiFfRG
Discretization Framework for functional Renormalization Group flows
dg.hh
Go to the documentation of this file.
1#pragma once
2
3// standard library
4#include <sstream>
5
6// DiFfRG
12
13namespace DiFfRG
14{
15 namespace DG
16 {
17 using namespace dealii;
18 using std::array;
19
20 template <typename... T> auto fe_tie(T &&...t)
21 {
22 return named_tuple<std::tuple<T &...>, StringSet<"fe_functions", "extractors", "variables", "cell_width">>(
23 std::tie(t...));
24 }
25
26 template <typename... T> auto i_tie(T &&...t)
27 {
28 return named_tuple<std::tuple<T &...>, StringSet<"fe_functions", "fe_derivatives", "fe_hessians">>(
29 std::tie(t...));
30 }
31
32 namespace internal
33 {
38 template <typename Discretization> struct ScratchData {
39 static constexpr int dim = Discretization::dim;
41 using VectorType = Vector<NumberType>;
42
43 ScratchData(const Mapping<dim> &mapping, const FiniteElement<dim> &fe,
44 const dealii::Quadrature<dim> &quadrature, const dealii::Quadrature<dim - 1> &quadrature_face,
45 const UpdateFlags update_flags = update_values | update_gradients | update_quadrature_points |
46 update_JxW_values,
47 const UpdateFlags interface_update_flags = update_values | update_gradients |
48 update_quadrature_points | update_JxW_values |
49 update_normal_vectors)
50 : n_components(fe.n_components()), fe_values(mapping, fe, quadrature, update_flags),
51 fe_interface_values(mapping, fe, quadrature_face, interface_update_flags)
52 {
53 solution.resize(quadrature.size(), VectorType(n_components));
54 solution_dot.resize(quadrature.size(), VectorType(n_components));
55 solution_interface[0].resize(quadrature_face.size(), VectorType(n_components));
56 solution_interface[1].resize(quadrature_face.size(), VectorType(n_components));
57 comp.resize(fe.n_dofs_per_cell());
58 for (uint i = 0; i < comp.size(); ++i)
59 comp[i] = fe.system_to_component_index(i).first;
60 }
61
63 : n_components(scratch_data.fe_values.get_fe().n_components()),
64 fe_values(scratch_data.fe_values.get_mapping(), scratch_data.fe_values.get_fe(),
65 scratch_data.fe_values.get_quadrature(), scratch_data.fe_values.get_update_flags()),
66 fe_interface_values(scratch_data.fe_interface_values.get_mapping(),
67 scratch_data.fe_interface_values.get_fe(),
68 scratch_data.fe_interface_values.get_quadrature(),
69 scratch_data.fe_interface_values.get_update_flags())
70 {
71 const auto &fe = scratch_data.fe_values.get_fe();
72 solution.resize(scratch_data.fe_values.get_quadrature().size(), VectorType(n_components));
73 solution_dot.resize(scratch_data.fe_values.get_quadrature().size(), VectorType(n_components));
74 solution_interface[0].resize(scratch_data.fe_interface_values.get_quadrature().size(),
76 solution_interface[1].resize(scratch_data.fe_interface_values.get_quadrature().size(),
78 comp.resize(fe.n_dofs_per_cell());
79 for (uint i = 0; i < comp.size(); ++i)
80 comp[i] = fe.system_to_component_index(i).first;
81 }
82
84
85 FEValues<dim> fe_values;
86 FEInterfaceValues<dim> fe_interface_values;
87
88 std::vector<VectorType> solution;
89 std::vector<VectorType> solution_dot;
90 array<std::vector<VectorType>, 2> solution_interface;
91 std::vector<uint> comp;
92 };
93
94 // TODO fewer memory allocations
95 template <typename NumberType> struct CopyData_R {
97 Vector<NumberType> cell_residual;
98 std::vector<types::global_dof_index> joint_dof_indices;
99
100 template <int dim> void reinit(const FEInterfaceValues<dim> &fe_iv)
101 {
102 cell_residual.reinit(fe_iv.n_current_interface_dofs());
103 joint_dof_indices = fe_iv.get_interface_dof_indices();
104 }
105 };
106
107 Vector<NumberType> cell_residual;
108 Vector<NumberType> cell_mass;
109 std::vector<types::global_dof_index> local_dof_indices;
110 std::vector<CopyDataFace_R> face_data;
111
112 template <class Iterator> void reinit(const Iterator &cell, uint dofs_per_cell)
113 {
114 cell_residual.reinit(dofs_per_cell);
115 cell_mass.reinit(dofs_per_cell);
116 local_dof_indices.resize(dofs_per_cell);
117 cell->get_dof_indices(local_dof_indices);
118 face_data.reserve(cell->n_faces());
119 }
120 };
121
122 // TODO fewer memory allocations
123 template <typename NumberType> struct CopyData_J {
125 FullMatrix<NumberType> cell_jacobian;
126 FullMatrix<NumberType> extractor_cell_jacobian;
127 std::vector<types::global_dof_index> joint_dof_indices;
128
129 template <int dim> void reinit(const FEInterfaceValues<dim> &fe_iv, uint n_extractors)
130 {
131 uint dofs_per_cell = fe_iv.n_current_interface_dofs();
132 cell_jacobian.reinit(dofs_per_cell, dofs_per_cell);
133 if (n_extractors > 0) extractor_cell_jacobian.reinit(dofs_per_cell, n_extractors);
134 joint_dof_indices = fe_iv.get_interface_dof_indices();
135 }
136 };
137
138 FullMatrix<NumberType> cell_jacobian;
139 FullMatrix<NumberType> extractor_cell_jacobian;
140 FullMatrix<NumberType> cell_mass_jacobian;
141 std::vector<types::global_dof_index> local_dof_indices;
142 std::vector<CopyDataFace_J> face_data;
143
144 template <class Iterator> void reinit(const Iterator &cell, uint dofs_per_cell, uint n_extractors)
145 {
146 cell_jacobian.reinit(dofs_per_cell, dofs_per_cell);
147 if (n_extractors > 0) extractor_cell_jacobian.reinit(dofs_per_cell, n_extractors);
148 cell_mass_jacobian.reinit(dofs_per_cell, dofs_per_cell);
149 local_dof_indices.resize(dofs_per_cell);
150 cell->get_dof_indices(local_dof_indices);
151 face_data.reserve(cell->n_faces());
152 }
153 };
154
155 template <typename NumberType> struct CopyData_I {
157 std::array<uint, 2> cell_indices;
158 std::array<double, 2> values;
159 };
160 std::vector<CopyFaceData_I> face_data;
161 double value = 0.;
163 };
164 } // namespace internal
165
171 template <typename Discretization_,
173 class Assembler : public FEMAssembler<Discretization_, Model_>
174 {
176
177 public:
178 using Discretization = Discretization_;
179 using Model = Model_;
183
185 static constexpr uint n_components = Components::count_fe_functions(0);
186 static constexpr uint dim = Discretization::dim;
189 quadrature(fe.degree + 1 + config.get_uint("/discretization/overintegration", 0)),
190 quadrature_face(fe.degree + 1 + config.get_uint("/discretization/overintegration", 0))
191 {
192 static_assert(Components::count_fe_subsystems() == 1, "A DG model cannot have multiple submodels!");
193 reinit();
194 }
195
196 virtual void reinit_vector(VectorType &vec) const override
197 {
198 reinit_la_vector(vec, discretization.get_locally_owned_dofs(), discretization.get_communicator());
199 }
200 virtual void reinit_matrix(SparseMatrixType &matrix) const override
201 {
202 reinit_la_matrix(matrix, get_sparsity_pattern_jacobian(), discretization.get_locally_owned_dofs(),
203 discretization.get_communicator());
204 }
205
206 virtual MPI_Comm get_communicator() const override { return discretization.get_communicator(); }
207 virtual void reinit_solution_view(SolutionView<VectorType> &view) const override
208 {
209 view.reinit(discretization.get_locally_owned_dofs(), discretization.get_locally_relevant_dofs(),
210 discretization.get_communicator());
211 }
212
213 virtual void reinit() override
214 {
215 Timer timer;
216
217 Base::reinit();
218
219 // Mass sparsity pattern
220 {
221 DynamicSparsityPattern dsp(discretization.get_locally_relevant_dofs());
222 DoFTools::make_sparsity_pattern(dof_handler, dsp, discretization.get_constraints(),
223 /*keep_constrained_dofs = */ true);
225 discretization.get_locally_relevant_dofs(),
226 discretization.get_communicator());
228 discretization.get_communicator());
229 MatrixCreator::create_mass_matrix(dof_handler, quadrature, mass_matrix, (Function<dim, NumberType> *)nullptr,
230 discretization.get_constraints());
231 }
232 // Jacobian sparsity pattern
233 {
234 DynamicSparsityPattern dsp(discretization.get_locally_relevant_dofs());
235 DoFTools::make_flux_sparsity_pattern(dof_handler, dsp, discretization.get_constraints(),
236 /*keep_constrained_dofs = */ true);
238 dsp, sparsity_pattern_jacobian, discretization.get_locally_owned_dofs(),
239 discretization.get_locally_relevant_dofs(), discretization.get_communicator());
240 }
241
242 timings_reinit.push_back(timer.wall_time());
243 }
244
245 virtual void rebuild_jacobian_sparsity() override
246 {
247 // Jacobian sparsity pattern
248 DynamicSparsityPattern dsp(discretization.get_locally_relevant_dofs());
249 DoFTools::make_flux_sparsity_pattern(dof_handler, dsp, discretization.get_constraints(),
250 /*keep_constrained_dofs = */ true);
251 for (const auto &row : discretization.get_locally_relevant_dofs())
252 for (const auto &col : extractor_dof_indices)
253 dsp.add(row, col);
255 discretization.get_locally_relevant_dofs(),
256 discretization.get_communicator());
257 }
258
263 virtual const SparseMatrixType &get_mass_matrix() const override { return mass_matrix; }
264
271 virtual void refinement_indicator(Vector<double> &indicator, const VectorType &solution_global) override
272 {
273 using Iterator = typename DoFHandler<dim>::active_cell_iterator;
275 using CopyData = internal::CopyData_I<NumberType>;
276
277 const auto cell_worker = [&](const Iterator &t_cell, Scratch &scratch_data, CopyData &copy_data) {
278 scratch_data.fe_values.reinit(t_cell);
279 const auto &fe_v = scratch_data.fe_values;
280 copy_data.cell_index = t_cell->active_cell_index();
281 copy_data.value = 0;
282
283 const auto &JxW = fe_v.get_JxW_values();
284 const auto &q_points = fe_v.get_quadrature_points();
285 const auto &q_indices = fe_v.quadrature_point_indices();
286
287 auto &solution = scratch_data.solution;
288 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad;
289 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess;
290 solution_grad.resize(q_points.size(), std::vector<Tensor<1, dim, NumberType>>(n_components));
291 solution_hess.resize(q_points.size(), std::vector<Tensor<2, dim, NumberType>>(n_components));
292 fe_v.get_function_values(solution_global, solution);
293 fe_v.get_function_gradients(solution_global, solution_grad);
294 fe_v.get_function_hessians(solution_global, solution_hess);
295
296 double local_indicator = 0.;
297 for (const auto &q_index : q_indices) {
298 const auto &x_q = q_points[q_index];
299 model.cell_indicator(local_indicator, x_q,
300 i_tie(solution[q_index], solution_grad[q_index], solution_hess[q_index]));
301 copy_data.value += JxW[q_index] * local_indicator;
302 }
303 };
304 const auto face_worker = [&](const Iterator &t_cell, const uint &f, const uint &sf, const Iterator &t_ncell,
305 const uint &nf, const unsigned int &nsf, Scratch &scratch_data,
306 CopyData &copy_data) {
307 scratch_data.fe_interface_values.reinit(t_cell, f, sf, t_ncell, nf, nsf);
308 const auto &fe_iv = scratch_data.fe_interface_values;
309 const auto &fe_iv_s = scratch_data.fe_interface_values.get_fe_face_values(0);
310 const auto &fe_iv_n = scratch_data.fe_interface_values.get_fe_face_values(1);
311
312 auto &copy_data_face = copy_data.face_data.emplace_back();
313 copy_data_face.cell_indices[0] = t_cell->active_cell_index();
314 copy_data_face.cell_indices[1] = t_ncell->active_cell_index();
315 copy_data_face.values[0] = 0;
316 copy_data_face.values[1] = 0;
317
318 const auto &JxW = fe_iv.get_JxW_values();
319 const auto &q_points = fe_iv.get_quadrature_points();
320 const auto &q_indices = fe_iv.quadrature_point_indices();
321 const std::vector<Tensor<1, dim>> &normals = fe_iv.get_normal_vectors();
322
323 auto &solution_s = scratch_data.solution_interface[0];
324 auto &solution_n = scratch_data.solution_interface[1];
325 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad_s;
326 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess_s;
327 solution_grad_s.resize(q_points.size(), std::vector<Tensor<1, dim, NumberType>>(n_components));
328 solution_hess_s.resize(q_points.size(), std::vector<Tensor<2, dim, NumberType>>(n_components));
329 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad_n;
330 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess_n;
331 solution_grad_n.resize(q_points.size(), std::vector<Tensor<1, dim, NumberType>>(n_components));
332 solution_hess_n.resize(q_points.size(), std::vector<Tensor<2, dim, NumberType>>(n_components));
333 fe_iv_s.get_function_values(solution_global, solution_s);
334 fe_iv_n.get_function_values(solution_global, solution_n);
335 fe_iv_s.get_function_gradients(solution_global, solution_grad_s);
336 fe_iv_n.get_function_gradients(solution_global, solution_grad_n);
337 fe_iv_s.get_function_hessians(solution_global, solution_hess_s);
338 fe_iv_n.get_function_hessians(solution_global, solution_hess_n);
339
340 array<double, 2> local_indicator{};
341 for (const auto &q_index : q_indices) {
342 const auto &x_q = q_points[q_index];
343 model.face_indicator(local_indicator, normals[q_index], x_q,
344 i_tie(solution_s[q_index], solution_grad_s[q_index], solution_hess_s[q_index]),
345 i_tie(solution_n[q_index], solution_grad_n[q_index], solution_hess_n[q_index]));
346
347 copy_data_face.values[0] += JxW[q_index] * local_indicator[0] * (1. + t_cell->at_boundary());
348 copy_data_face.values[1] += JxW[q_index] * local_indicator[1] * (1. + t_ncell->at_boundary());
349 }
350 };
351 const auto copier = [&](const CopyData &c) {
352 for (auto &cdf : c.face_data)
353 for (uint j = 0; j < 2; ++j)
354 indicator[cdf.cell_indices[j]] += cdf.values[j];
355 indicator[c.cell_index] += c.value;
356 };
357 const UpdateFlags update_flags =
358 update_values | update_gradients | update_quadrature_points | update_JxW_values | update_hessians;
359 const UpdateFlags interface_update_flags = update_values | update_gradients | update_quadrature_points |
360 update_JxW_values | update_normal_vectors | update_hessians;
361
362 Scratch scratch_data(mapping, fe, quadrature, quadrature_face, update_flags, interface_update_flags);
363 CopyData copy_data;
364 // The face flags are load-bearing: a face_worker is passed below, and without
365 // assemble_own_interior_faces_once mesh_loop never calls it, so model.face_indicator
366 // contributed nothing at all to the refinement indicator -- DG refined on the cell term
367 // alone. ddg.hh and ldg.hh have always set it. assemble_ghost_faces_once then gives each
368 // partition-boundary face to exactly one rank, which is what the sum_reduce of the
369 // indicator under the distributed policy expects.
370 MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells |
371 MeshWorker::assemble_own_interior_faces_once |
372 MeshWorker::assemble_ghost_faces_once;
373
374 // map() is collective and each rank visits only its own cells; see NoMapsHere.
375 const NoMapsHere no_maps_during_assembly;
376 const auto schedule = schedule_for(assembly_cost::local_fe);
377 MeshWorker::mesh_loop(locally_owned_cells(dof_handler), cell_worker, copier, scratch_data, copy_data,
378 assemble_flags, nullptr, face_worker, schedule.queue_length, schedule.chunk_size);
379 }
380
381 virtual void mass(VectorType &mass, const VectorType &solution_global, const VectorType &solution_global_dot,
382 NumberType weight) override
383 {
384 using Iterator = typename DoFHandler<dim>::active_cell_iterator;
386 using CopyData = internal::CopyData_R<NumberType>;
387 const auto &constraints = discretization.get_constraints();
388
389 const auto cell_worker = [&](const Iterator &cell, Scratch &scratch_data, CopyData &copy_data) {
390 scratch_data.fe_values.reinit(cell);
391 const auto &fe_v = scratch_data.fe_values;
392 const uint n_dofs = fe_v.get_fe().n_dofs_per_cell();
393
394 copy_data.reinit(cell, n_dofs);
395 const auto &JxW = fe_v.get_JxW_values();
396 const auto &q_points = fe_v.get_quadrature_points();
397 const auto &q_indices = fe_v.quadrature_point_indices();
398
399 auto &solution = scratch_data.solution;
400 auto &solution_dot = scratch_data.solution_dot;
401 fe_v.get_function_values(solution_global, solution);
402 fe_v.get_function_values(solution_global_dot, solution_dot);
403
404 const auto &comp = scratch_data.comp;
405
406 array<NumberType, n_components> mass{};
407 for (const auto &q_index : q_indices) {
408 const auto &x_q = q_points[q_index];
409 model.mass(mass, x_q, solution[q_index], solution_dot[q_index]);
410
411 for (uint i = 0; i < n_dofs; ++i) {
412 const auto component_i = comp[i];
413 copy_data.cell_residual(i) += weight * JxW[q_index] *
414 fe_v.shape_value_component(i, q_index, component_i) *
415 mass[component_i]; // +phi_i(x_q) * mass(x_q, u_q)
416 }
417 }
418 };
419 const auto copier = [&](const CopyData &c) {
420 constraints.distribute_local_to_global(c.cell_residual, c.local_dof_indices, mass);
421 };
422
423 Scratch scratch_data(mapping, fe, quadrature, quadrature_face);
424 CopyData copy_data;
425 MeshWorker::AssembleFlags flags = MeshWorker::assemble_own_cells;
426
427 // map() is collective and each rank visits only its own cells; see NoMapsHere.
428 const NoMapsHere no_maps_during_assembly;
429 const auto schedule = schedule_for(assembly_cost::local_fe);
430 MeshWorker::mesh_loop(locally_owned_cells(dof_handler), cell_worker, copier, scratch_data, copy_data, flags,
431 nullptr, nullptr, schedule.queue_length, schedule.chunk_size);
432 // Resolve contributions this rank made to rows it does not own. A partition-boundary
433 // face is assembled by exactly one of its two neighbours (mesh_loop hands it to the
434 // smaller subdomain id), and that rank writes BOTH sides -- so the other side's rows
435 // arrive here. A no-op for the serial types.
436 mass.compress(dealii::VectorOperation::add);
437 }
438
439 virtual void residual(VectorType &residual, const VectorType &solution_global, NumberType weight,
440 const VectorType &solution_global_dot, NumberType weight_mass,
441 const VectorType &variables = VectorType()) override
442 {
443 using Iterator = typename DoFHandler<dim>::active_cell_iterator;
445 using CopyData = internal::CopyData_R<NumberType>;
446 const auto &constraints = discretization.get_constraints();
447
448 // Find the EoM and extract whatever data is needed for the model.
449 std::array<NumberType, Components::count_extractors()> __extracted_data{{}};
450 if constexpr (Components::count_extractors() > 0)
451 this->extract(__extracted_data, solution_global, variables, true, false, true);
452 const auto &extracted_data = __extracted_data;
453
454 const auto cell_worker = [&](const Iterator &cell, Scratch &scratch_data, CopyData &copy_data) {
455 const double cell_width = DiFfRG::internal::cell_width(cell);
456 scratch_data.fe_values.reinit(cell);
457 const auto &fe_v = scratch_data.fe_values;
458 const uint n_dofs = fe_v.get_fe().n_dofs_per_cell();
459
460 copy_data.reinit(cell, n_dofs);
461 const auto &JxW = fe_v.get_JxW_values();
462 const auto &q_points = fe_v.get_quadrature_points();
463 const auto &q_indices = fe_v.quadrature_point_indices();
464
465 auto &solution = scratch_data.solution;
466 auto &solution_dot = scratch_data.solution_dot;
467 fe_v.get_function_values(solution_global, solution);
468 fe_v.get_function_values(solution_global_dot, solution_dot);
469
470 const auto &comp = scratch_data.comp;
471
472 array<NumberType, n_components> mass{};
473 array<Tensor<1, dim, NumberType>, n_components> flux{};
474 array<NumberType, n_components> source{};
475 for (const auto &q_index : q_indices) {
476 const auto &x_q = q_points[q_index];
477 model.mass(mass, x_q, solution[q_index], solution_dot[q_index]);
478 model.flux(flux, x_q, fe_tie(solution[q_index], extracted_data, variables, cell_width));
479 model.source(source, x_q, fe_tie(solution[q_index], extracted_data, variables, cell_width));
480
481 for (uint i = 0; i < n_dofs; ++i) {
482 const auto component_i = comp[i];
483 copy_data.cell_mass(i) += weight_mass * JxW[q_index] *
484 fe_v.shape_value_component(i, q_index, component_i) *
485 mass[component_i]; // +phi_i(x_q) * mass(x_q, u_q)
486 copy_data.cell_residual(i) += JxW[q_index] * weight * // dx *
487 (-scalar_product(fe_v.shape_grad_component(i, q_index, component_i),
488 flux[component_i]) // -dphi_i(x_q) * flux(x_q, u_q)
489 + fe_v.shape_value_component(i, q_index, component_i) *
490 source[component_i]); // -phi_i(x_q) * source(x_q, u_q)
491 }
492 }
493 };
494 const auto boundary_worker = [&](const Iterator &cell, const uint &face_no, Scratch &scratch_data,
495 CopyData &copy_data) {
496 const double cell_width = DiFfRG::internal::cell_width(cell);
497 scratch_data.fe_interface_values.reinit(cell, face_no);
498 const auto &fe_fv = scratch_data.fe_interface_values.get_fe_face_values(0);
499 const uint n_dofs = fe_fv.get_fe().n_dofs_per_cell();
500
501 const auto &JxW = fe_fv.get_JxW_values();
502 const auto &q_points = fe_fv.get_quadrature_points();
503 const auto &q_indices = fe_fv.quadrature_point_indices();
504 auto &solution = scratch_data.solution_interface[0];
505
506 array<Tensor<1, dim, NumberType>, n_components> numflux{};
507
508 fe_fv.get_function_values(solution_global, solution);
509 const std::vector<Tensor<1, dim>> &normals = fe_fv.get_normal_vectors();
510
511 const auto &comp = scratch_data.comp;
512
513 for (const auto &q_index : q_indices) {
514 const auto &x_q = q_points[q_index];
515 model.boundary_numflux(numflux, normals[q_index], x_q,
516 fe_tie(solution[q_index], extracted_data, variables, cell_width));
517
518 for (uint i = 0; i < n_dofs; ++i) {
519 const auto component_i = comp[i];
520 copy_data.cell_residual(i) +=
521 weight * JxW[q_index] * // dx
522 (fe_fv.shape_value_component(i, q_index, component_i) *
523 scalar_product(numflux[component_i], normals[q_index])); // phi_i(x_q) * numflux(x_q, u_q) * n(x_q)
524 }
525 }
526 };
527 const auto face_worker = [&](const Iterator &cell, const uint &f, const uint &sf, const Iterator &ncell,
528 const uint &nf, const uint &nsf, Scratch &scratch_data, CopyData &copy_data) {
529 const double cell_width = DiFfRG::internal::cell_width(cell);
530 const double ncell_width = DiFfRG::internal::cell_width(ncell);
531 scratch_data.fe_interface_values.reinit(cell, f, sf, ncell, nf, nsf);
532 const auto &fe_iv = scratch_data.fe_interface_values;
533 const auto &fe_iv_s = scratch_data.fe_interface_values.get_fe_face_values(0);
534 const auto &fe_iv_n = scratch_data.fe_interface_values.get_fe_face_values(1);
535 const uint n_dofs = fe_iv.n_current_interface_dofs();
536
537 copy_data.face_data.emplace_back();
538 auto &copy_data_face = copy_data.face_data.back();
539 copy_data_face.reinit(fe_iv);
540
541 const auto &JxW = fe_iv.get_JxW_values();
542 const auto &q_points = fe_iv.get_quadrature_points();
543 const auto &q_indices = fe_iv.quadrature_point_indices();
544 auto &solution_s = scratch_data.solution_interface[0];
545 auto &solution_n = scratch_data.solution_interface[1];
546
547 array<Tensor<1, dim, NumberType>, n_components> numflux{};
548
549 fe_iv_s.get_function_values(solution_global, solution_s);
550 fe_iv_n.get_function_values(solution_global, solution_n);
551 const std::vector<Tensor<1, dim>> &normals = fe_iv.get_normal_vectors();
552
553 // Pre-compute component indices for interface DoFs
554 const auto &comp = scratch_data.comp;
555 std::vector<uint> iface_comp(n_dofs);
556 for (uint i = 0; i < n_dofs; ++i) {
557 const auto &cd_i = fe_iv.interface_dof_to_dof_indices(i);
558 iface_comp[i] = cd_i[0] == numbers::invalid_unsigned_int ? comp[cd_i[1]] : comp[cd_i[0]];
559 }
560
561 for (const auto &q_index : q_indices) {
562 const auto &x_q = q_points[q_index];
563 model.numflux(numflux, normals[q_index], x_q,
564 fe_tie(solution_s[q_index], extracted_data, variables, cell_width),
565 fe_tie(solution_n[q_index], extracted_data, variables, ncell_width));
566
567 for (uint i = 0; i < n_dofs; ++i) {
568 const auto component_i = iface_comp[i];
569 copy_data_face.cell_residual(i) +=
570 weight * JxW[q_index] * // dx
571 (fe_iv.jump_in_shape_values(i, q_index, component_i) *
572 scalar_product(numflux[component_i],
573 normals[q_index])); // [[phi_i(x_q)]] * numflux(x_q, u_q) * n(x_q)
574 }
575 }
576 };
577 const auto copier = [&](const CopyData &c) {
578 constraints.distribute_local_to_global(c.cell_residual, c.local_dof_indices, residual);
579 constraints.distribute_local_to_global(c.cell_mass, c.local_dof_indices, residual);
580 for (auto &cdf : c.face_data)
581 constraints.distribute_local_to_global(cdf.cell_residual, cdf.joint_dof_indices, residual);
582 };
583
584 Scratch scratch_data(mapping, fe, quadrature, quadrature_face);
585 CopyData copy_data;
586 MeshWorker::AssembleFlags flags = MeshWorker::assemble_own_cells | MeshWorker::assemble_boundary_faces |
587 MeshWorker::assemble_own_interior_faces_once |
588 MeshWorker::assemble_ghost_faces_once;
589
590 Timer timer;
591 // map() is collective and each rank visits only its own cells; see NoMapsHere.
592 const NoMapsHere no_maps_during_assembly;
593 const auto schedule = schedule_for(assembly_cost::momentum_integral);
594 MeshWorker::mesh_loop(locally_owned_cells(dof_handler), cell_worker, copier, scratch_data, copy_data, flags,
595 boundary_worker, face_worker, schedule.queue_length, schedule.chunk_size);
596 // Resolve contributions this rank made to rows it does not own. A partition-boundary
597 // face is assembled by exactly one of its two neighbours (mesh_loop hands it to the
598 // smaller subdomain id), and that rank writes BOTH sides -- so the other side's rows
599 // arrive here. A no-op for the serial types.
600 residual.compress(dealii::VectorOperation::add);
601 timings_residual.push_back(timer.wall_time());
602 }
603
604 virtual void jacobian_mass(SparseMatrixType &jacobian, const VectorType &solution_global,
605 const VectorType &solution_global_dot, NumberType alpha = 1.,
606 NumberType beta = 1.) override
607 {
608 using Iterator = typename DoFHandler<dim>::active_cell_iterator;
610 using CopyData = internal::CopyData_J<NumberType>;
611 const auto &constraints = discretization.get_constraints();
612
613 const auto cell_worker = [&](const Iterator &cell, Scratch &scratch_data, CopyData &copy_data) {
614 scratch_data.fe_values.reinit(cell);
615 const auto &fe_v = scratch_data.fe_values;
616 const uint n_dofs = fe_v.get_fe().n_dofs_per_cell();
617
618 copy_data.reinit(cell, n_dofs, Components::count_extractors());
619 const auto &JxW = fe_v.get_JxW_values();
620 const auto &q_points = fe_v.get_quadrature_points();
621 const auto &q_indices = fe_v.quadrature_point_indices();
622
623 auto &solution = scratch_data.solution;
624 auto &solution_dot = scratch_data.solution_dot;
625 fe_v.get_function_values(solution_global, solution);
626 fe_v.get_function_values(solution_global_dot, solution_dot);
627
628 const auto &comp = scratch_data.comp;
629
632 for (const auto &q_index : q_indices) {
633 const auto &x_q = q_points[q_index];
634 model.template jacobian_mass<0>(j_mass, x_q, solution[q_index], solution_dot[q_index]);
635 model.template jacobian_mass<1>(j_mass_dot, x_q, solution[q_index], solution_dot[q_index]);
636
637 for (uint i = 0; i < n_dofs; ++i) {
638 const auto component_i = comp[i];
639 for (uint j = 0; j < n_dofs; ++j) {
640 const auto component_j = comp[j];
641 copy_data.cell_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 }
647 }
648 };
649 const auto copier = [&](const CopyData &c) {
650 constraints.distribute_local_to_global(c.cell_jacobian, c.local_dof_indices, jacobian);
651 };
652
653 Scratch scratch_data(mapping, fe, quadrature, quadrature_face);
654 CopyData copy_data;
655 MeshWorker::AssembleFlags flags = MeshWorker::assemble_own_cells;
656
657 Timer timer;
658 // map() is collective and each rank visits only its own cells; see NoMapsHere.
659 const NoMapsHere no_maps_during_assembly;
660 const auto schedule = schedule_for(assembly_cost::local_fe);
661 MeshWorker::mesh_loop(locally_owned_cells(dof_handler), cell_worker, copier, scratch_data, copy_data, flags,
662 nullptr, nullptr, schedule.queue_length, schedule.chunk_size);
663 // Resolve contributions this rank made to rows it does not own. A partition-boundary
664 // face is assembled by exactly one of its two neighbours (mesh_loop hands it to the
665 // smaller subdomain id), and that rank writes BOTH sides -- so the other side's rows
666 // arrive here. A no-op for the serial types.
667 jacobian.compress(dealii::VectorOperation::add);
668 timings_jacobian.push_back(timer.wall_time());
669 }
670
671 virtual void jacobian(SparseMatrixType &jacobian, const VectorType &solution_global, NumberType weight,
672 const VectorType &solution_global_dot, NumberType alpha, NumberType beta,
673 const VectorType &variables = VectorType()) override
674 {
675 using Iterator = typename DoFHandler<dim>::active_cell_iterator;
677 using CopyData = internal::CopyData_J<NumberType>;
678 const auto &constraints = discretization.get_constraints();
679
680 // Find the EoM and extract whatever data is needed for the model.
681 std::array<NumberType, Components::count_extractors()> extracted_data{{}};
682 if constexpr (Components::count_extractors() > 0) {
683 this->extract(extracted_data, solution_global, variables, true, true, true);
684 if (this->jacobian_extractors(this->extractor_jacobian, solution_global, variables))
686 discretization.get_communicator());
687 }
688
689 const auto cell_worker = [&](const Iterator &cell, Scratch &scratch_data, CopyData &copy_data) {
690 const double cell_width = DiFfRG::internal::cell_width(cell);
691 scratch_data.fe_values.reinit(cell);
692 const auto &fe_v = scratch_data.fe_values;
693 const uint n_dofs = fe_v.get_fe().n_dofs_per_cell();
694
695 copy_data.reinit(cell, n_dofs, Components::count_extractors());
696 const auto &JxW = fe_v.get_JxW_values();
697 const auto &q_points = fe_v.get_quadrature_points();
698 const auto &q_indices = fe_v.quadrature_point_indices();
699
700 auto &solution = scratch_data.solution;
701 auto &solution_dot = scratch_data.solution_dot;
702 fe_v.get_function_values(solution_global, solution);
703 fe_v.get_function_values(solution_global_dot, solution_dot);
704
705 const auto &comp = scratch_data.comp;
706
710 SimpleMatrix<Tensor<1, dim>, n_components, Components::count_extractors()> j_extr_flux;
712 SimpleMatrix<NumberType, n_components, Components::count_extractors()> j_extr_source;
713 for (const auto &q_index : q_indices) {
714 const auto &x_q = q_points[q_index];
715 model.template jacobian_mass<0>(j_mass, x_q, solution[q_index], solution_dot[q_index]);
716 model.template jacobian_mass<1>(j_mass_dot, x_q, solution[q_index], solution_dot[q_index]);
717 model.template jacobian_flux_source<0, 0>(j_flux, j_source, x_q,
718 fe_tie(solution[q_index], extracted_data, variables, cell_width));
719 if constexpr (Components::count_extractors() > 0) {
720 model.template jacobian_flux_source_extr<1>(
721 j_extr_flux, j_extr_source, x_q, fe_tie(solution[q_index], extracted_data, variables, cell_width));
722 }
723
724 for (uint i = 0; i < n_dofs; ++i) {
725 const auto component_i = comp[i];
726 for (uint j = 0; j < n_dofs; ++j) {
727 const auto component_j = comp[j];
728 copy_data.cell_jacobian(i, j) += weight * JxW[q_index] *
729 fe_v.shape_value_component(j, q_index, component_j) * // dx * phi_j * (
730 (-scalar_product(fe_v.shape_grad_component(i, q_index, component_i),
731 j_flux(component_i, component_j)) // -dphi_i * jflux
732 + fe_v.shape_value_component(i, q_index, component_i) *
733 j_source(component_i, component_j)); // -phi_i * jsource)
734 copy_data.cell_mass_jacobian(i, j) +=
735 JxW[q_index] * fe_v.shape_value_component(j, q_index, component_j) *
736 fe_v.shape_value_component(i, q_index, component_i) *
737 (alpha * j_mass_dot(component_i, component_j) + beta * j_mass(component_i, component_j));
738 }
739 // extractor contribution
740 if constexpr (Components::count_extractors() > 0)
741 for (uint e = 0; e < Components::count_extractors(); ++e)
742 copy_data.extractor_cell_jacobian(i, e) +=
743 weight * JxW[q_index] * // dx * phi_j * (
744 (-scalar_product(fe_v.shape_grad_component(i, q_index, component_i),
745 j_extr_flux(component_i, e)) // -dphi_i * jflux
746 + fe_v.shape_value_component(i, q_index, component_i) *
747 j_extr_source(component_i, e)); // -phi_i * jsource)
748 }
749 }
750 };
751 const auto boundary_worker = [&](const Iterator &cell, const uint &face_no, Scratch &scratch_data,
752 CopyData &copy_data) {
753 const double cell_width = DiFfRG::internal::cell_width(cell);
754 scratch_data.fe_interface_values.reinit(cell, face_no);
755 const auto &fe_fv = scratch_data.fe_interface_values.get_fe_face_values(0);
756 const uint n_dofs = fe_fv.get_fe().n_dofs_per_cell();
757
758 const auto &JxW = fe_fv.get_JxW_values();
759 const auto &q_points = fe_fv.get_quadrature_points();
760 const auto &q_indices = fe_fv.quadrature_point_indices();
761 auto &solution = scratch_data.solution_interface[0];
762
763 SimpleMatrix<Tensor<1, dim>, n_components> j_boundary_numflux;
764 SimpleMatrix<Tensor<1, dim>, n_components, Components::count_extractors()> j_extr_boundary_numflux;
765
766 fe_fv.get_function_values(solution_global, solution);
767 const std::vector<Tensor<1, dim>> &normals = fe_fv.get_normal_vectors();
768
769 const auto &comp = scratch_data.comp;
770
771 for (const auto &q_index : q_indices) {
772 const auto &x_q = q_points[q_index];
773 model.template jacobian_boundary_numflux<0, 0>(
774 j_boundary_numflux, normals[q_index], x_q,
775 fe_tie(solution[q_index], extracted_data, variables, cell_width));
776 if constexpr (Components::count_extractors() > 0)
777 model.template jacobian_boundary_numflux_extr<1>(
778 j_extr_boundary_numflux, normals[q_index], x_q,
779 fe_tie(solution[q_index], extracted_data, variables, cell_width));
780
781 for (uint i = 0; i < n_dofs; ++i) {
782 const auto component_i = comp[i];
783 for (uint j = 0; j < n_dofs; ++j) {
784 const auto component_j = comp[j];
785 copy_data.cell_jacobian(i, j) +=
786 weight * JxW[q_index] * fe_fv.shape_value_component(j, q_index, component_j) * // dx * phi_j(x_q)
787 (fe_fv.shape_value_component(i, q_index, component_i) *
788 scalar_product(j_boundary_numflux(component_i, component_j),
789 normals[q_index])); // phi_i(x_q) * j_numflux(x_q, u_q) * n(x_q)
790 }
791 // extractor contribution
792 if constexpr (Components::count_extractors() > 0)
793 for (uint e = 0; e < Components::count_extractors(); ++e)
794 copy_data.extractor_cell_jacobian(i, e) +=
795 weight * JxW[q_index] * // dx * phi_j(x_q)
796 (fe_fv.shape_value_component(i, q_index, component_i) *
797 scalar_product(j_extr_boundary_numflux(component_i, e),
798 normals[q_index])); // phi_i(x_q) * j_numflux(x_q, u_q) * n(x_q)
799 }
800 }
801 };
802 const auto face_worker = [&](const Iterator &cell, const uint &f, const uint &sf, const Iterator &ncell,
803 const uint &nf, const uint &nsf, Scratch &scratch_data, CopyData &copy_data) {
804 const double cell_width = DiFfRG::internal::cell_width(cell);
805 const double ncell_width = DiFfRG::internal::cell_width(ncell);
806 scratch_data.fe_interface_values.reinit(cell, f, sf, ncell, nf, nsf);
807 const auto &fe_iv = scratch_data.fe_interface_values;
808 const auto &fe_iv_s = scratch_data.fe_interface_values.get_fe_face_values(0);
809 const auto &fe_iv_n = scratch_data.fe_interface_values.get_fe_face_values(1);
810 const uint n_dofs = fe_iv.n_current_interface_dofs();
811
812 copy_data.face_data.emplace_back();
813 auto &copy_data_face = copy_data.face_data.back();
814 copy_data_face.reinit(fe_iv, Components::count_extractors());
815
816 const auto &JxW = fe_iv.get_JxW_values();
817 const auto &q_points = fe_iv.get_quadrature_points();
818 const auto &q_indices = fe_iv.quadrature_point_indices();
819 auto &solution_s = scratch_data.solution_interface[0];
820 auto &solution_n = scratch_data.solution_interface[1];
821
822 fe_iv_s.get_function_values(solution_global, solution_s);
823 fe_iv_n.get_function_values(solution_global, solution_n);
824 const std::vector<Tensor<1, dim>> &normals = fe_iv.get_normal_vectors();
825
826 // Pre-compute component indices and face numbers for interface DoFs
827 const auto &comp = scratch_data.comp;
828 std::vector<uint> iface_comp(n_dofs);
829 std::vector<uint> iface_face_no(n_dofs);
830 std::vector<uint> iface_local_dof(n_dofs);
831 for (uint i = 0; i < n_dofs; ++i) {
832 const auto &cd_i = fe_iv.interface_dof_to_dof_indices(i);
833 const uint fno = cd_i[0] == numbers::invalid_unsigned_int ? 1 : 0;
834 iface_face_no[i] = fno;
835 iface_local_dof[i] = cd_i[fno];
836 iface_comp[i] = comp[cd_i[fno]];
837 }
838
839 array<SimpleMatrix<Tensor<1, dim>, n_components>, 2> j_numflux;
840 array<SimpleMatrix<Tensor<1, dim>, n_components, Components::count_extractors()>, 2> j_extr_numflux;
841 for (const auto &q_index : q_indices) {
842 const auto &x_q = q_points[q_index];
843 model.template jacobian_numflux<0, 0>(j_numflux, normals[q_index], x_q,
844 fe_tie(solution_s[q_index], extracted_data, variables, cell_width),
845 fe_tie(solution_n[q_index], extracted_data, variables, ncell_width));
846 if constexpr (Components::count_extractors() > 0)
847 model.template jacobian_numflux_extr<1>(
848 j_extr_numflux, normals[q_index], x_q,
849 fe_tie(solution_s[q_index], extracted_data, variables, cell_width),
850 fe_tie(solution_n[q_index], extracted_data, variables, ncell_width));
851
852 for (uint i = 0; i < n_dofs; ++i) {
853 const auto component_i = iface_comp[i];
854 const uint face_no_i = iface_face_no[i];
855 for (uint j = 0; j < n_dofs; ++j) {
856 const auto component_j = iface_comp[j];
857 const uint face_no_j = iface_face_no[j];
858
859 copy_data_face.cell_jacobian(i, j) +=
860 weight * JxW[q_index] *
861 fe_iv.get_fe_face_values(face_no_j).shape_value_component(iface_local_dof[j], q_index,
862 component_j) * // dx * phi_j(x_q)
863 (fe_iv.jump_in_shape_values(i, q_index, component_i) *
864 scalar_product(j_numflux[face_no_j](component_i, component_j),
865 normals[q_index])); // [[phi_i(x_q)]] * j_numflux(x_q, u_q)
866 }
867 // extractor contribution
868 if constexpr (Components::count_extractors() > 0)
869 for (uint e = 0; e < Components::count_extractors(); ++e)
870 copy_data_face.extractor_cell_jacobian(i, e) +=
871 weight * JxW[q_index] * // dx * phi_j(x_q)
872 (fe_iv.jump_in_shape_values(i, q_index, component_i) *
873 scalar_product(j_extr_numflux[face_no_i](component_i, e),
874 normals[q_index])); // [[phi_i(x_q)]] * j_numflux(x_q, u_q)
875 }
876 }
877 };
878 const auto copier = [&](const CopyData &c) {
879 constraints.distribute_local_to_global(c.cell_jacobian, c.local_dof_indices, jacobian);
880 constraints.distribute_local_to_global(c.cell_mass_jacobian, c.local_dof_indices, jacobian);
881 for (auto &cdf : c.face_data) {
882 constraints.distribute_local_to_global(cdf.cell_jacobian, cdf.joint_dof_indices, jacobian);
883 if constexpr (Components::count_extractors() > 0) {
884 FullMatrix<NumberType> extractor_dependence(cdf.joint_dof_indices.size(), extractor_dof_indices.size());
885 cdf.extractor_cell_jacobian.mmult(extractor_dependence, this->extractor_jacobian);
886 constraints.distribute_local_to_global(extractor_dependence, cdf.joint_dof_indices, extractor_dof_indices,
887 jacobian);
888 }
889 }
890 if constexpr (Components::count_extractors() > 0) {
891 FullMatrix<NumberType> extractor_dependence(c.local_dof_indices.size(), extractor_dof_indices.size());
892 c.extractor_cell_jacobian.mmult(extractor_dependence, this->extractor_jacobian);
893 constraints.distribute_local_to_global(extractor_dependence, c.local_dof_indices, extractor_dof_indices,
894 jacobian);
895 }
896 };
897
898 Scratch scratch_data(mapping, fe, quadrature, quadrature_face);
899 CopyData copy_data;
900 MeshWorker::AssembleFlags flags = MeshWorker::assemble_own_cells | MeshWorker::assemble_boundary_faces |
901 MeshWorker::assemble_own_interior_faces_once |
902 MeshWorker::assemble_ghost_faces_once;
903
904 Timer timer;
905 // map() is collective and each rank visits only its own cells; see NoMapsHere.
906 const NoMapsHere no_maps_during_assembly;
907 const auto schedule = schedule_for(assembly_cost::momentum_integral);
908 MeshWorker::mesh_loop(locally_owned_cells(dof_handler), cell_worker, copier, scratch_data, copy_data, flags,
909 boundary_worker, face_worker, schedule.queue_length, schedule.chunk_size);
910 // Resolve contributions this rank made to rows it does not own. A partition-boundary
911 // face is assembled by exactly one of its two neighbours (mesh_loop hands it to the
912 // smaller subdomain id), and that rank writes BOTH sides -- so the other side's rows
913 // arrive here. A no-op for the serial types.
914 jacobian.compress(dealii::VectorOperation::add);
915 timings_jacobian.push_back(timer.wall_time());
916 }
917 SummaryEvent summary() const override
918 {
919 SummaryEvent result{.component = "DG"};
920 result.timing("reinit", average_time_reinit() * 1000, num_reinits())
921 .timing("residual", average_time_residual_assembly() * 1000, num_residuals())
923 return result;
924 }
925
926 double average_time_reinit() const
927 {
928 double t = 0.;
929 double n = timings_reinit.size();
930 for (const auto &t_ : timings_reinit)
931 t += t_ / n;
932 return t;
933 }
934 uint num_reinits() const { return timings_reinit.size(); }
935
937 {
938 double t = 0.;
939 double n = timings_residual.size();
940 for (const auto &t_ : timings_residual)
941 t += t_ / n;
942 return t;
943 }
944 uint num_residuals() const { return timings_residual.size(); }
945
947 {
948 double t = 0.;
949 double n = timings_jacobian.size();
950 for (const auto &t_ : timings_jacobian)
951 t += t_ / n;
952 return t;
953 }
954 uint num_jacobians() const { return timings_jacobian.size(); }
955
956 protected:
958 using Base::dof_handler;
959 using Base::fe;
960 using Base::mapping;
961 using Base::model;
962
963 QGauss<dim> quadrature;
964 QGauss<dim - 1> quadrature_face;
965 using Base::schedule_for;
966
970
971 std::vector<double> timings_reinit;
972 std::vector<double> timings_residual;
973 std::vector<double> timings_jacobian;
974
976 };
977 } // namespace DG
978} // namespace DiFfRG
A hierarchical configuration tree, readable from JSON and TOML files.
Definition config_tree.hh:32
The basic assembler that can be used for any standard DG scheme with flux and source.
Definition dg.hh:174
SparseMatrixType mass_matrix
Definition dg.hh:969
static constexpr uint n_components
Definition dg.hh:185
Model & model
Definition common.hh:405
virtual void reinit_matrix(SparseMatrixType &matrix) const override
Definition dg.hh:200
const Mapping< dim > & mapping
Definition common.hh:409
double average_time_residual_assembly() const
Definition dg.hh:936
const FiniteElement< dim > & fe
Definition common.hh:407
SummaryEvent summary() const override
Definition dg.hh:917
double average_time_jacobian_assembly() const
Definition dg.hh:946
typename Discretization::NumberType NumberType
Definition dg.hh:180
QGauss< dim - 1 > quadrature_face
Definition dg.hh:964
virtual void reinit() override
Reinitialize the assembler. This is necessary if the mesh has changed, e.g. after a mesh refinement.
Definition dg.hh:213
std::vector< double > timings_reinit
Definition dg.hh:971
typename Discretization::Components Components
Definition dg.hh:184
virtual const SparseMatrixType & get_mass_matrix() const override
Obtain the mass matrix.
Definition dg.hh:263
uint num_residuals() const
Definition dg.hh:944
virtual void mass(VectorType &mass, const VectorType &solution_global, const VectorType &solution_global_dot, NumberType weight) override
Definition dg.hh:381
typename Discretization::VectorType VectorType
Definition dg.hh:181
uint num_jacobians() const
Definition dg.hh:954
static constexpr uint dim
Definition dg.hh:186
get_type::SparsityPattern< SparseMatrixType > sparsity_pattern_jacobian
Definition dg.hh:968
virtual MPI_Comm get_communicator() const override
The communicator this assembler's linear algebra lives on.
Definition dg.hh:206
Discretization_ Discretization
Definition dg.hh:178
uint num_reinits() const
Definition dg.hh:934
Assembler(Discretization &discretization, Model &model, const ConfigTree &config)
Definition dg.hh:187
Model_ Model
Definition dg.hh:179
const DoFHandler< dim > & dof_handler
Definition common.hh:408
virtual void jacobian(SparseMatrixType &jacobian, const VectorType &solution_global, NumberType weight, const VectorType &solution_global_dot, NumberType alpha, NumberType beta, const VectorType &variables=VectorType()) override
Definition dg.hh:671
double average_time_reinit() const
Definition dg.hh:926
Discretization & discretization
Definition common.hh:404
typename Discretization::SparseMatrixType SparseMatrixType
Definition dg.hh:182
virtual void rebuild_jacobian_sparsity() override
Definition dg.hh:245
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:271
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:439
virtual void jacobian_mass(SparseMatrixType &jacobian, const VectorType &solution_global, const VectorType &solution_global_dot, NumberType alpha=1., NumberType beta=1.) override
Definition dg.hh:604
virtual void reinit_solution_view(SolutionView< VectorType > &view) const override
Definition dg.hh:207
std::vector< types::global_dof_index > extractor_dof_indices
Definition common.hh:463
virtual const get_type::SparsityPattern< SparseMatrixType > & get_sparsity_pattern_jacobian() const override
Obtain the sparsity pattern of the jacobian matrix.
Definition dg.hh:259
get_type::SparsityPattern< SparseMatrixType > sparsity_pattern_mass
Definition dg.hh:967
AssemblySchedule schedule_for(const double cost_ns) const
The mesh_loop schedule for a loop whose cell worker costs cost_ns nanoseconds.
Definition common.hh:418
virtual void reinit_vector(VectorType &vec) const override
Definition dg.hh:196
std::vector< double > timings_jacobian
Definition dg.hh:973
std::vector< double > timings_residual
Definition dg.hh:972
QGauss< dim > quadrature
Definition dg.hh:963
typename DiFfRG::internal::components_of< ModelOrComponents_ >::type Components
Definition dg.hh:48
SparseMatrixType_ SparseMatrixType
Definition dg.hh:51
VectorType_ VectorType
Definition dg.hh:50
NumberType_ NumberType
Definition dg.hh:49
static constexpr uint dim
Definition dg.hh:53
The basic assembler that can be used for any standard CG scheme with flux and source.
Definition common.hh:42
Model & model
Definition common.hh:405
const Mapping< dim > & mapping
Definition common.hh:409
FullMatrix< NumberType > extractor_jacobian
Definition common.hh:459
const FiniteElement< dim > & fe
Definition common.hh:407
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:274
bool jacobian_extractors(FullMatrix< NumberType > &extractor_jacobian, const VectorType &solution_global, const VectorType &variables)
Definition common.hh:302
virtual void reinit() override
Reinitialize the assembler. This is necessary if the mesh has changed, e.g. after a mesh refinement.
Definition common.hh:116
const DoFHandler< dim > & dof_handler
Definition common.hh:408
Discretization & discretization
Definition common.hh:404
std::vector< types::global_dof_index > extractor_dof_indices
Definition common.hh:463
AssemblySchedule schedule_for(const double cost_ns) const
The mesh_loop schedule for a loop whose cell worker costs cost_ns nanoseconds.
Definition common.hh:418
Decides, without any user input, which rank computes which part of each map().
Definition map_scheduler.hh:195
A simple NxM-matrix class, which is used for cell-wise Jacobians.
Definition tuples.hh:170
A read-only, fully-replicated view of the solution.
Definition solution_view.hh:48
void reinit(const dealii::IndexSet &, const dealii::IndexSet &, MPI_Comm)
Establish the layout. No-op for the serial policy.
Definition solution_view.hh:58
All compile-time knowledge about which linear algebra types DiFfRG uses.
auto fe_tie(T &&...t)
Definition dg.hh:20
auto i_tie(T &&...t)
Definition dg.hh:26
constexpr double local_fe
Local FE work only: mass matrices, refinement indicators. ~0.2-0.3 us/cell for CG p=3.
Definition assembly_schedule.hh:48
constexpr double momentum_integral
Definition assembly_schedule.hh:53
typename internal::_SparsityPattern< SparseMatrixType >::value SparsityPattern
Definition linear_algebra.hh:155
double cell_width(const CellIterator &cell)
The smallest face-normal width over all faces of cell.
Definition cell_geometry.hh:42
Definition complex_math.hh:10
auto locally_owned_cells(const dealii::DoFHandler< dim > &dof_handler)
The cells this rank assembles.
Definition assembly_schedule.hh:154
@ config
/discretization/threads.
void reinit_la_matrix(SparseMatrixType &matrix, const get_type::SparsityPattern< SparseMatrixType > &pattern, const dealii::IndexSet &locally_owned, MPI_Comm comm)
Size a matrix from a finalized sparsity pattern.
Definition la_policy.hh:92
void reinit_la_vector(VectorType &vec, const dealii::IndexSet &locally_owned, MPI_Comm comm)
Size a vector to the rank's share of the rows.
Definition la_policy.hh:27
unsigned int uint
Definition utils.hh:24
void finalize_la_sparsity(dealii::DynamicSparsityPattern &dsp, get_type::SparsityPattern< SparseMatrixType > &pattern, const dealii::IndexSet &locally_owned, const dealii::IndexSet &locally_relevant, MPI_Comm comm)
Turn a freshly built DynamicSparsityPattern into the pattern type the matrix wants.
Definition la_policy.hh:50
std::array< uint, 2 > cell_indices
Definition dg.hh:157
std::array< double, 2 > values
Definition dg.hh:158
std::vector< CopyFaceData_I > face_data
Definition dg.hh:160
uint cell_index
Definition dg.hh:162
double value
Definition dg.hh:161
void reinit(const FEInterfaceValues< dim > &fe_iv, uint n_extractors)
Definition dg.hh:129
FullMatrix< NumberType > extractor_cell_jacobian
Definition dg.hh:126
FullMatrix< NumberType > cell_jacobian
Definition dg.hh:125
std::vector< types::global_dof_index > joint_dof_indices
Definition dg.hh:127
FullMatrix< NumberType > cell_mass_jacobian
Definition dg.hh:140
std::vector< types::global_dof_index > local_dof_indices
Definition dg.hh:141
FullMatrix< NumberType > extractor_cell_jacobian
Definition dg.hh:139
FullMatrix< NumberType > cell_jacobian
Definition dg.hh:138
void reinit(const Iterator &cell, uint dofs_per_cell, uint n_extractors)
Definition dg.hh:144
std::vector< CopyDataFace_J > face_data
Definition dg.hh:142
Vector< NumberType > cell_residual
Definition dg.hh:97
std::vector< types::global_dof_index > joint_dof_indices
Definition dg.hh:98
void reinit(const FEInterfaceValues< dim > &fe_iv)
Definition dg.hh:100
std::vector< CopyDataFace_R > face_data
Definition dg.hh:110
Vector< NumberType > cell_mass
Definition dg.hh:108
void reinit(const Iterator &cell, uint dofs_per_cell)
Definition dg.hh:112
std::vector< types::global_dof_index > local_dof_indices
Definition dg.hh:109
Vector< NumberType > cell_residual
Definition dg.hh:107
Class to hold data for each assembly thread, i.e. FEValues for cells, interfaces, as well as pre-allo...
Definition dg.hh:38
array< std::vector< VectorType >, 2 > solution_interface
Definition dg.hh:90
typename Discretization::NumberType NumberType
Definition dg.hh:40
FEInterfaceValues< dim > fe_interface_values
Definition dg.hh:86
Vector< NumberType > VectorType
Definition dg.hh:41
std::vector< VectorType > solution
Definition dg.hh:88
ScratchData(const ScratchData< Discretization > &scratch_data)
Definition dg.hh:62
std::vector< VectorType > solution_dot
Definition dg.hh:89
FEValues< dim > fe_values
Definition dg.hh:85
ScratchData(const Mapping< dim > &mapping, const FiniteElement< dim > &fe, const dealii::Quadrature< dim > &quadrature, const dealii::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:43
static constexpr int dim
Definition dg.hh:39
const uint n_components
Definition dg.hh:83
std::vector< uint > comp
Definition dg.hh:91
Definition tuples.hh:34
Definition run_reporter.hh:73
SummaryEvent & timing(const std::string_view name, const double average_ms, const std::size_t calls)
Definition run_reporter.hh:78
std::conditional_t< CarriesModel< D >, typename D::Model, D > type
Definition types.hh:63
A class to store a tuple with elements that can be accessed by name. The names are stored as FixedStr...
Definition tuples.hh:56