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