8#include <deal.II/base/multithread_info.h>
9#include <deal.II/base/quadrature_lib.h>
10#include <deal.II/base/timer.h>
11#include <deal.II/dofs/dof_handler.h>
12#include <deal.II/dofs/dof_tools.h>
13#include <deal.II/fe/fe_interface_values.h>
14#include <deal.II/fe/fe_values.h>
15#include <deal.II/lac/block_sparse_matrix.h>
16#include <deal.II/lac/block_vector.h>
17#include <deal.II/lac/full_matrix.h>
18#include <deal.II/lac/vector.h>
19#include <deal.II/lac/vector_memory.h>
20#include <deal.II/meshworker/mesh_loop.h>
21#include <deal.II/numerics/matrix_tools.h>
22#include <deal.II/numerics/vector_tools.h>
35 using namespace dealii;
36 using std::array, std::vector, std::unique_ptr;
38 template <
typename Discretization_,
typename Model_>
40 typename Discretization_::SparseMatrixType, Discretization_::dim>
54 threads(json.get_uint(
"/discretization/threads")),
batch_size(json.get_uint(
"/discretization/batch_size")),
57 EoM_abs_tol(json.get_double(
"/discretization/EoM_abs_tol")),
58 EoM_max_iter(json.get_uint(
"/discretization/EoM_max_iter"))
60 if (this->
threads == 0) this->
threads = dealii::MultithreadInfo::n_threads() / 2;
61 spdlog::get(
"log")->info(
"FEM: Using {} threads for assembly.",
threads);
66 ComponentMask component_mask(
model.template differential_components<dim>());
67 return DoFTools::extract_dofs(
dof_handler, component_mask);
76 std::vector<IndexSet> component_boundary_dofs(Components::count_fe_functions());
77 for (
uint c = 0; c < Components::count_fe_functions(); ++c) {
78 ComponentMask component_mask(Components::count_fe_functions(),
false);
79 component_mask.set(c,
true);
80 component_boundary_dofs[c] = DoFTools::extract_boundary_dofs(
dof_handler, component_mask);
82 std::vector<std::vector<Point<dim>>> component_boundary_points(Components::count_fe_functions());
83 for (
uint c = 0; c < Components::count_fe_functions(); ++c) {
84 component_boundary_points[c].resize(component_boundary_dofs[c].n_elements());
85 for (
uint i = 0; i < component_boundary_dofs[c].n_elements(); ++i)
86 component_boundary_points[c][i] =
87 discretization.get_support_point(component_boundary_dofs[c].nth_index_in_set(i));
92 DoFTools::make_hanging_node_constraints(
dof_handler, constraints);
93 model.affine_constraints(constraints, component_boundary_dofs, component_boundary_points);
126 const FiniteElement<dim> &
fe;
133 mutable typename DoFHandler<dim>::cell_iterator
EoM_cell;
158 using Iterator =
typename DoFHandler<dim>::active_cell_iterator;
159 using t_Iterator =
typename Triangulation<dim>::active_cell_iterator;
161 ScratchData(
const Mapping<dim> &mapping,
const vector<
const DoFHandler<dim> *> &dofh,
163 const UpdateFlags update_flags = update_values | update_gradients | update_quadrature_points |
165 const UpdateFlags interface_update_flags = update_values | update_gradients |
166 update_quadrature_points | update_JxW_values |
167 update_normal_vectors)
170 StandardExceptions::ExcDimensionMismatch(dofh.size(),
n_fe_subsystems));
173 const auto &fe = dofh[i]->get_fe();
174 fe_values[i] = unique_ptr<FEValues<dim>>(
new FEValues<dim>(mapping, fe, quadrature, update_flags));
176 new FEInterfaceValues<dim>(mapping, fe, quadrature_face, interface_update_flags));
178 new FEFaceValues<dim>(mapping, fe, quadrature_face, interface_update_flags));
185 cell[i] = dofh[i]->begin_active();
186 ncell[i] = dofh[i]->begin_active();
194 const auto &old_fe = scratch_data.
fe_values[i];
198 fe_values[i] = unique_ptr<FEValues<dim>>(
new FEValues<dim>(
199 old_fe->get_mapping(), old_fe->get_fe(), old_fe->get_quadrature(), old_fe->get_update_flags()));
201 old_fe_i->get_mapping(), old_fe_i->get_fe(), old_fe_i->get_quadrature(), old_fe_i->get_update_flags()));
203 old_fe_b->get_mapping(), old_fe_b->get_fe(), old_fe_b->get_quadrature(), old_fe_b->get_update_flags()));
221 cell[i]->copy_from(*t_cell);
227 uint nf,
unsigned int nsf)
230 cell[i]->copy_from(*t_cell);
231 ncell[i]->copy_from(*t_ncell);
239 cell[i]->copy_from(*t_cell);
246 array<Iterator, n_fe_subsystems>
cell;
247 array<Iterator, n_fe_subsystems>
ncell;
269 template <
class Iterator>
void reinit(
const Iterator &cell,
uint dofs_per_cell)
281 copy_data_face.
cell_residual.reinit(fe_iv.n_current_interface_dofs());
282 copy_data_face.joint_dof_indices = fe_iv.get_interface_dof_indices();
283 return copy_data_face;
299 template <
class Iterator>
300 void reinit(
const Iterator &cell_from,
const Iterator &cell_to,
uint dofs_per_cell_from,
uint dofs_per_cell_to)
312 auto ©_data_face =
face_data.emplace_back();
313 copy_data_face.
cell_jacobian.reinit(fe_iv_to.n_current_interface_dofs(),
314 fe_iv_from.n_current_interface_dofs());
315 copy_data_face.joint_dof_indices_from = fe_iv_from.get_interface_dof_indices();
316 copy_data_face.joint_dof_indices_to = fe_iv_to.get_interface_dof_indices();
317 return copy_data_face;
336 template <
class Iterator>
void reinit(
const array<Iterator, n_fe_subsystems> &cell,
const uint n_extractors)
338 const uint n_dofs = cell[0]->get_fe().n_dofs_per_cell();
340 for (
uint i = 0; i < n_fe_subsystems; ++i) {
341 const uint from_n_dofs = cell[i]->get_fe().n_dofs_per_cell();
352 const uint n_extractors)
354 auto ©_data_face =
face_data.emplace_back();
355 for (
uint i = 0; i < n_fe_subsystems; ++i) {
356 copy_data_face.cell_jacobian[i].reinit(fe_iv[0]->n_current_interface_dofs(),
357 fe_iv[i]->n_current_interface_dofs());
358 copy_data_face.joint_dof_indices[i] = fe_iv[i]->get_interface_dof_indices();
360 if (n_extractors > 0)
362 return copy_data_face;
383 template <
typename Discretization_,
typename Model_>
396 static constexpr uint stencil = Components::count_fe_subsystems();
399 template <
typename... T>
auto fe_conv(std::tuple<T &...> &t)
const
402 return named_tuple<std::tuple<T &...>,
"fe_functions",
"LDG1",
"extractors",
"variables">(t);
403 else if constexpr (
stencil == 3)
404 return named_tuple<std::tuple<T &...>,
"fe_functions",
"LDG1",
"LDG2",
"extractors",
"variables">(t);
405 else if constexpr (
stencil == 4)
406 return named_tuple<std::tuple<T &...>,
"fe_functions",
"LDG1",
"LDG2",
"LDG3",
"extractors",
"variables">(t);
408 throw std::runtime_error(
"Only <= 3 LDG subsystems are supported.");
411 template <
typename... T>
auto fe_more_conv(std::tuple<T &...> &t)
const
414 return named_tuple<std::tuple<T &...>,
"fe_functions",
"LDG1",
"fe_derivatives",
"fe_hessians",
"extractors",
416 else if constexpr (
stencil == 3)
417 return named_tuple<std::tuple<T &...>,
"fe_functions",
"LDG1",
"LDG2",
"fe_derivatives",
"fe_hessians",
418 "extractors",
"variables">(t);
419 else if constexpr (
stencil == 4)
420 return named_tuple<std::tuple<T &...>,
"fe_functions",
"LDG1",
"LDG2",
"LDG3",
"fe_derivatives",
421 "fe_hessians",
"extractors",
"variables">(t);
423 throw std::runtime_error(
"Only <= 3 LDG subsystems are supported.");
426 template <
typename... T>
auto ref_conv(std::tuple<T &...> &t)
const
429 return named_tuple<std::tuple<T &...>,
"fe_functions",
"LDG1">(t);
430 else if constexpr (
stencil == 3)
431 return named_tuple<std::tuple<T &...>,
"fe_functions",
"LDG1",
"LDG2">(t);
432 else if constexpr (
stencil == 4)
433 return named_tuple<std::tuple<T &...>,
"fe_functions",
"LDG1",
"LDG2",
"LDG3">(t);
435 throw std::runtime_error(
"Only <= 3 LDG subsystems are supported.");
441 quadrature(
fe.degree + 1 + json.get_uint(
"/discretization/overintegration")),
442 quadrature_face(
fe.degree + 1 + json.get_uint(
"/discretization/overintegration")),
445 static_assert(Components::count_fe_subsystems() > 1,
"LDG must have a submodel with index 1.");
462 readouts(data_out, solution, variables);
464 const auto fe_function_names = Components::FEFunction_Descriptor::get_names_vector();
465 std::vector<std::string> fe_function_names_residual;
466 for (
const auto &name : fe_function_names)
467 fe_function_names_residual.push_back(name +
"_residual");
468 std::vector<std::string> fe_function_names_dot;
469 for (
const auto &name : fe_function_names)
470 fe_function_names_dot.push_back(name +
"_dot");
474 if (dt_solution.size() > 0) fe_out.attach(
dof_handler, dt_solution, fe_function_names_dot);
476 for (
uint k = 1; k < Components::count_fe_subsystems(); ++k) {
484 const auto init_mass = [&](
uint i) {
486 auto dofs_per_component = DoFTools::count_dofs_per_fe_component(*(
dof_handler_list[i]));
489 auto n_fe = dofs_per_component.size();
490 for (
uint j = 1; j < n_fe; ++j)
491 if (dofs_per_component[j] != dofs_per_component[0])
492 throw std::runtime_error(
"For LDG the FE basis of all systems must be equal!");
494 BlockDynamicSparsityPattern dsp(n_fe, n_fe);
495 for (
uint i = 0; i < n_fe; ++i)
496 for (
uint j = 0; j < n_fe; ++j)
497 dsp.block(i, j).reinit(dofs_per_component[0], dofs_per_component[0]);
507 (
const Function<dim, NumberType> *
const)
nullptr,
518 const auto init_jacobian = [&](
uint i) {
523 for (
uint k = 1; k < Components::count_fe_subsystems(); ++k)
531 auto init_ldg = [&](
uint i) {
547 for (
uint i = 0; i < Components::count_fe_subsystems(); ++i)
548 threads.emplace_back(std::thread(init_mass, i));
549 for (
uint i = 0; i < Components::count_fe_subsystems(); ++i)
550 threads.emplace_back(std::thread(init_jacobian, i));
551 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i)
552 threads.emplace_back(std::thread(init_ldg, i));
562 for (
uint k = 1; k < Components::count_fe_subsystems(); ++k)
568 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
572 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
573 const auto &fe_v = scratch_data.new_fe_values(t_cell);
574 copy_data.cell_index = t_cell->active_cell_index();
577 const auto &JxW = fe_v[0]->get_JxW_values();
578 const auto &q_points = fe_v[0]->get_quadrature_points();
579 const auto &q_indices = fe_v[0]->quadrature_point_indices();
581 auto &solution = scratch_data.solution;
582 fe_v[0]->get_function_values(solution_global, solution[0]);
583 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i)
584 fe_v[i]->get_function_values(
sol_vector[i], solution[i]);
586 double local_indicator = 0.;
587 for (
const auto &q_index : q_indices) {
588 const auto &x_q = q_points[q_index];
592 copy_data.value += JxW[q_index] * local_indicator;
595 const auto face_worker = [&](
const Iterator &t_cell,
const uint &f,
const uint &sf,
const Iterator &t_ncell,
596 const uint &nf,
const unsigned int &nsf, Scratch &scratch_data,
597 CopyData ©_data) {
598 const auto &fe_iv = scratch_data.new_fe_interface_values(t_cell, f, sf, t_ncell, nf, nsf);
600 auto ©_data_face = copy_data.face_data.emplace_back();
601 copy_data_face.cell_indices[0] = t_cell->active_cell_index();
602 copy_data_face.cell_indices[1] = t_ncell->active_cell_index();
603 copy_data_face.values[0] = 0;
604 copy_data_face.values[1] = 0;
606 const auto &JxW = fe_iv[0]->get_JxW_values();
607 const auto &q_points = fe_iv[0]->get_quadrature_points();
608 const auto &q_indices = fe_iv[0]->quadrature_point_indices();
609 const std::vector<Tensor<1, dim>> &normals = fe_iv[0]->get_normal_vectors();
610 array<double, 2> local_indicator{};
612 auto &solution = scratch_data.solution_interface;
613 fe_iv[0]->get_fe_face_values(0).get_function_values(solution_global, solution[0][0]);
614 fe_iv[0]->get_fe_face_values(1).get_function_values(solution_global, solution[1][0]);
615 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i) {
616 fe_iv[i]->get_fe_face_values(0).get_function_values(
sol_vector[i], solution[0][i]);
617 fe_iv[i]->get_fe_face_values(1).get_function_values(
sol_vector[i], solution[1][i]);
620 for (
const auto &q_index : q_indices) {
621 const auto &x_q = q_points[q_index];
626 copy_data_face.values[0] += JxW[q_index] * local_indicator[0] * (1. + t_cell->at_boundary());
627 copy_data_face.values[1] += JxW[q_index] * local_indicator[1] * (1. + t_ncell->at_boundary());
630 const auto copier = [&](
const CopyData &c) {
631 for (
auto &cdf : c.face_data)
632 for (
uint j = 0; j < 2; ++j)
633 indicator[cdf.cell_indices[j]] += cdf.values[j];
634 indicator[c.cell_index] += c.value;
637 const UpdateFlags update_flags = update_values | update_quadrature_points | update_JxW_values;
640 MeshWorker::AssembleFlags assemble_flags =
641 MeshWorker::assemble_own_cells | MeshWorker::assemble_own_interior_faces_once;
664 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
669 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
670 const auto &fe_v = scratch_data.new_fe_values(t_cell);
671 const uint n_dofs = fe_v[0]->get_fe().n_dofs_per_cell();
672 copy_data.reinit(scratch_data.cell[0], n_dofs);
674 const auto &JxW = fe_v[0]->get_JxW_values();
675 const auto &q_points = fe_v[0]->get_quadrature_points();
676 const auto &q_indices = fe_v[0]->quadrature_point_indices();
678 auto &solution = scratch_data.solution;
679 auto &solution_dot = scratch_data.solution_dot;
680 fe_v[0]->get_function_values(solution_global, solution[0]);
681 fe_v[0]->get_function_values(solution_global_dot, solution_dot);
684 for (
const auto &q_index : q_indices) {
685 const auto &x_q = q_points[q_index];
686 model.mass(
mass, x_q, solution[0][q_index], solution_dot[q_index]);
688 for (
uint i = 0; i < n_dofs; ++i) {
689 const auto component_i = fe_v[0]->get_fe().system_to_component_index(i).first;
690 copy_data.cell_residual(i) += weight * JxW[q_index] *
691 fe_v[0]->shape_value_component(i, q_index, component_i) *
696 const auto copier = [&](
const CopyData &c) {
697 constraints.distribute_local_to_global(c.cell_residual, c.local_dof_indices,
residual);
700 const UpdateFlags update_flags = update_values | update_quadrature_points | update_JxW_values;
701 const MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells;
720 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
726 std::array<
NumberType, Components::count_extractors()> __extracted_data{{}};
727 if constexpr (Components::count_extractors() > 0)
728 this->
extract(__extracted_data, solution_global, variables,
true,
false,
true);
729 const auto &extracted_data = __extracted_data;
731 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
732 const auto &fe_v = scratch_data.new_fe_values(t_cell);
733 const uint n_dofs = fe_v[0]->get_fe().n_dofs_per_cell();
734 copy_data.reinit(scratch_data.cell[0], n_dofs);
736 const auto &JxW = fe_v[0]->get_JxW_values();
737 const auto &q_points = fe_v[0]->get_quadrature_points();
738 const auto &q_indices = fe_v[0]->quadrature_point_indices();
740 auto &solution = scratch_data.solution;
741 auto &solution_dot = scratch_data.solution_dot;
742 fe_v[0]->get_function_values(solution_global, solution[0]);
743 fe_v[0]->get_function_values(solution_global_dot, solution_dot);
744 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i)
745 fe_v[i]->get_function_values(
sol_vector[i], solution[i]);
748 array<Tensor<1, dim, NumberType>, Components::count_fe_functions(0)> flux{};
749 array<
NumberType, Components::count_fe_functions(0)> source{};
750 for (
const auto &q_index : q_indices) {
751 const auto &x_q = q_points[q_index];
752 auto sol_q = std::tuple_cat(
local_sol_q(solution, q_index), std::tie(extracted_data, variables));
753 model.mass(
mass, x_q, solution[0][q_index], solution_dot[q_index]);
757 for (
uint i = 0; i < n_dofs; ++i) {
758 const auto component_i = fe_v[0]->get_fe().system_to_component_index(i).first;
759 copy_data.cell_residual(i) += weight * JxW[q_index] *
760 (-scalar_product(fe_v[0]->shape_grad_component(i, q_index, component_i),
762 + fe_v[0]->shape_value_component(i, q_index, component_i) *
763 (source[component_i]));
764 copy_data.cell_mass(i) += weight_mass * JxW[q_index] *
765 fe_v[0]->shape_value_component(i, q_index, component_i) *
770 const auto boundary_worker = [&](
const Iterator &t_cell,
const uint &face_no, Scratch &scratch_data,
771 CopyData ©_data) {
772 const auto &fe_fv = scratch_data.new_fe_boundary_values(t_cell, face_no);
773 const uint n_dofs = fe_fv[0]->get_fe().n_dofs_per_cell();
775 const auto &JxW = fe_fv[0]->get_JxW_values();
776 const auto &q_points = fe_fv[0]->get_quadrature_points();
777 const auto &q_indices = fe_fv[0]->quadrature_point_indices();
778 const auto &normals = fe_fv[0]->get_normal_vectors();
780 auto &solution = scratch_data.solution;
781 fe_fv[0]->get_function_values(solution_global, solution[0]);
782 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i)
783 fe_fv[i]->get_function_values(
sol_vector[i], solution[i]);
785 array<Tensor<1, dim, NumberType>, Components::count_fe_functions(0)> numflux{};
786 for (
const auto &q_index : q_indices) {
787 const auto &x_q = q_points[q_index];
788 auto sol_q = std::tuple_cat(
local_sol_q(solution, q_index), std::tie(extracted_data, variables));
789 model.boundary_numflux(numflux, normals[q_index], x_q,
fe_conv(sol_q));
791 for (
uint i = 0; i < n_dofs; ++i) {
792 const auto component_i = fe_fv[0]->get_fe().system_to_component_index(i).first;
793 copy_data.cell_residual(i) +=
794 weight * JxW[q_index] *
795 (fe_fv[0]->shape_value_component(i, q_index, component_i) *
796 scalar_product(numflux[component_i], normals[q_index]));
800 const auto face_worker = [&](
const Iterator &t_cell,
const uint &f,
const uint &sf,
const Iterator &t_ncell,
801 const uint &nf,
const unsigned int &nsf, Scratch &scratch_data,
802 CopyData ©_data) {
803 const auto &fe_iv = scratch_data.new_fe_interface_values(t_cell, f, sf, t_ncell, nf, nsf);
804 const uint n_dofs = fe_iv[0]->n_current_interface_dofs();
805 auto ©_data_face = copy_data.new_face_data(*(fe_iv[0]));
807 const auto &JxW = fe_iv[0]->get_JxW_values();
808 const auto &q_points = fe_iv[0]->get_quadrature_points();
809 const auto &q_indices = fe_iv[0]->quadrature_point_indices();
810 const auto &normals = fe_iv[0]->get_normal_vectors();
812 auto &solution = scratch_data.solution_interface;
813 fe_iv[0]->get_fe_face_values(0).get_function_values(solution_global, solution[0][0]);
814 fe_iv[0]->get_fe_face_values(1).get_function_values(solution_global, solution[1][0]);
815 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i) {
816 fe_iv[i]->get_fe_face_values(0).get_function_values(
sol_vector[i], solution[0][i]);
817 fe_iv[i]->get_fe_face_values(1).get_function_values(
sol_vector[i], solution[1][i]);
820 array<Tensor<1, dim, NumberType>, Components::count_fe_functions(0)> numflux{};
821 for (
const auto &q_index : q_indices) {
822 const auto &x_q = q_points[q_index];
823 auto sol_q_s = std::tuple_cat(
local_sol_q(solution[0], q_index), std::tie(extracted_data, variables));
824 auto sol_q_n = std::tuple_cat(
local_sol_q(solution[1], q_index), std::tie(extracted_data, variables));
827 for (
uint i = 0; i < n_dofs; ++i) {
828 const auto &cd_i = fe_iv[0]->interface_dof_to_dof_indices(i);
829 const auto component_i = cd_i[0] == numbers::invalid_unsigned_int
830 ? fe_iv[0]->get_fe().system_to_component_index(cd_i[1]).first
831 : fe_iv[0]->get_fe().system_to_component_index(cd_i[0]).first;
832 copy_data_face.cell_residual(i) +=
833 weight * JxW[q_index] *
834 (fe_iv[0]->jump_in_shape_values(i, q_index, component_i) *
835 scalar_product(numflux[component_i],
840 const auto copier = [&](
const CopyData &c) {
841 constraints.distribute_local_to_global(c.cell_residual, c.local_dof_indices,
residual);
842 constraints.distribute_local_to_global(c.cell_mass, c.local_dof_indices,
residual);
843 for (
auto &cdf : c.face_data)
844 constraints.distribute_local_to_global(cdf.cell_residual, cdf.joint_dof_indices,
residual);
847 const UpdateFlags update_flags =
848 update_values | update_gradients | update_quadrature_points | update_JxW_values;
849 const MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells |
850 MeshWorker::assemble_boundary_faces |
851 MeshWorker::assemble_own_interior_faces_once;
868 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
873 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
874 const auto &fe_v = scratch_data.new_fe_values(t_cell);
875 const uint to_n_dofs = fe_v[0]->get_fe().n_dofs_per_cell();
876 copy_data.reinit(scratch_data.cell, Components::count_extractors());
878 const auto &JxW = fe_v[0]->get_JxW_values();
879 const auto &q_points = fe_v[0]->get_quadrature_points();
880 const auto &q_indices = fe_v[0]->quadrature_point_indices();
882 auto &solution = scratch_data.solution;
883 auto &solution_dot = scratch_data.solution_dot;
885 fe_v[0]->get_function_values(solution_global, solution[0]);
886 fe_v[0]->get_function_values(solution_global_dot, solution_dot);
891 const uint from_n_dofs = fe_v[0]->get_fe().n_dofs_per_cell();
892 for (
const auto &q_index : q_indices) {
893 const auto &x_q = q_points[q_index];
898 for (
uint i = 0; i < to_n_dofs; ++i) {
899 const auto component_i = fe_v[0]->get_fe().system_to_component_index(i).first;
900 for (
uint j = 0; j < from_n_dofs; ++j) {
901 const auto component_j = fe_v[0]->get_fe().system_to_component_index(j).first;
902 copy_data.cell_jacobian[0](i, j) +=
903 JxW[q_index] * fe_v[0]->shape_value_component(j, q_index, component_j) *
904 fe_v[0]->shape_value_component(i, q_index, component_i) *
905 (alpha * j_mass_dot(component_i, component_j) +
906 beta * j_mass(component_i, component_j));
911 const auto copier = [&](
const CopyData &c) {
912 constraints.distribute_local_to_global(c.cell_jacobian[0], c.local_dof_indices[0],
jacobian);
915 const UpdateFlags update_flags = update_values | update_quadrature_points | update_JxW_values;
916 const MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells;
936 throw std::runtime_error(
"Please call jacobian_mass instead of jacobian for weight == 0).");
937 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
943 std::array<
NumberType, Components::count_extractors()> __extracted_data{{}};
944 if constexpr (Components::count_extractors() > 0) {
945 this->
extract(__extracted_data, solution_global, variables,
true,
true,
true);
949 const auto &extracted_data = __extracted_data;
951 bool exception =
false;
953 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
954 const auto &fe_v = scratch_data.new_fe_values(t_cell);
955 const uint to_n_dofs = fe_v[0]->get_fe().n_dofs_per_cell();
956 copy_data.reinit(scratch_data.cell, Components::count_extractors());
958 const auto &JxW = fe_v[0]->get_JxW_values();
959 const auto &q_points = fe_v[0]->get_quadrature_points();
960 const auto &q_indices = fe_v[0]->quadrature_point_indices();
962 auto &solution = scratch_data.solution;
963 auto &solution_dot = scratch_data.solution_dot;
965 fe_v[0]->get_function_values(solution_global, solution[0]);
966 fe_v[0]->get_function_values(solution_global_dot, solution_dot);
967 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i)
968 fe_v[i]->get_function_values(
sol_vector[i], solution[i]);
980 const uint from_n_dofs = fe_v[k]->get_fe().n_dofs_per_cell();
981 for (
const auto &q_index : q_indices) {
982 const auto &x_q = q_points[q_index];
983 auto sol_q = std::tuple_cat(
local_sol_q(solution, q_index), std::tie(extracted_data, variables));
985 if constexpr (k == 0) {
988 if constexpr (Components::count_extractors() > 0) {
989 this->
model.template jacobian_flux_extr<stencil>(j_extr_flux, x_q,
fe_conv(sol_q));
990 this->
model.template jacobian_source_extr<stencil>(j_extr_source, x_q,
fe_conv(sol_q));
998 for (
uint i = 0; i < to_n_dofs; ++i) {
999 const auto component_i = fe_v[0]->get_fe().system_to_component_index(i).first;
1000 for (
uint j = 0; j < from_n_dofs; ++j) {
1001 const auto component_j = fe_v[k]->get_fe().system_to_component_index(j).first;
1003 copy_data.cell_jacobian[k](i, j) +=
1005 fe_v[k]->shape_value_component(j, q_index, component_j) *
1006 (-scalar_product(fe_v[0]->shape_grad_component(i, q_index, component_i),
1008 + fe_v[0]->shape_value_component(i, q_index, component_i) *
1010 if constexpr (k == 0) {
1011 copy_data.cell_mass_jacobian(i, j) +=
1013 fe_v[0]->shape_value_component(j, q_index, component_j) *
1014 fe_v[0]->shape_value_component(i, q_index, component_i) *
1015 (alpha / weight * j_mass_dot(component_i, component_j) +
1016 beta / weight * j_mass(component_i, component_j));
1021 if constexpr (k == 0)
1022 if constexpr (Components::count_extractors() > 0)
1023 for (
uint e = 0; e < Components::count_extractors(); ++e)
1024 copy_data.extractor_cell_jacobian(i, e) +=
1025 weight * JxW[q_index] *
1026 (-scalar_product(fe_v[0]->shape_grad_component(i, q_index, component_i),
1027 j_extr_flux(component_i, e))
1028 + fe_v[0]->shape_value_component(i, q_index, component_i) *
1029 j_extr_source(component_i, e));
1034 const auto boundary_worker = [&](
const Iterator &t_cell,
const uint &face_no, Scratch &scratch_data,
1035 CopyData ©_data) {
1036 const auto &fe_fv = scratch_data.new_fe_boundary_values(t_cell, face_no);
1037 const uint to_n_dofs = fe_fv[0]->get_fe().n_dofs_per_cell();
1039 const auto &JxW = fe_fv[0]->get_JxW_values();
1040 const auto &q_points = fe_fv[0]->get_quadrature_points();
1041 const auto &q_indices = fe_fv[0]->quadrature_point_indices();
1042 const auto &normals = fe_fv[0]->get_normal_vectors();
1043 auto &solution = scratch_data.solution;
1045 fe_fv[0]->get_function_values(solution_global, solution[0]);
1046 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i)
1047 fe_fv[i]->get_function_values(
sol_vector[i], solution[i]);
1052 for (
const auto &q_index : q_indices) {
1053 const auto &x_q = q_points[q_index];
1054 auto sol_q = std::tuple_cat(
local_sol_q(solution, q_index), std::tie(extracted_data, variables));
1056 const uint from_n_dofs = fe_fv[k]->get_fe().n_dofs_per_cell();
1058 model.template jacobian_boundary_numflux<k, 0>(
std::get<k>(j_boundary_numflux), normals[q_index], x_q,
1061 if (!
std::get<k>(j_boundary_numflux).is_finite()) exception =
true;
1063 for (
uint i = 0; i < to_n_dofs; ++i) {
1064 const auto component_i = fe_fv[0]->get_fe().system_to_component_index(i).first;
1065 for (
uint j = 0; j < from_n_dofs; ++j) {
1066 const auto component_j = fe_fv[k]->get_fe().system_to_component_index(j).first;
1068 copy_data.cell_jacobian[k](i, j) +=
1070 fe_fv[k]->shape_value_component(j, q_index, component_j) *
1071 (fe_fv[0]->shape_value_component(i, q_index, component_i) *
1072 scalar_product(
std::get<k>(j_boundary_numflux)(component_i, component_j),
1079 const auto face_worker = [&](
const Iterator &t_cell,
const uint &f,
const uint &sf,
const Iterator &t_ncell,
1080 const uint &nf,
const unsigned int &nsf, Scratch &scratch_data,
1081 CopyData ©_data) {
1082 const auto &fe_iv = scratch_data.new_fe_interface_values(t_cell, f, sf, t_ncell, nf, nsf);
1083 const uint to_n_dofs = fe_iv[0]->n_current_interface_dofs();
1084 auto ©_data_face = copy_data.new_face_data(fe_iv, Components::count_extractors());
1086 const auto &JxW = fe_iv[0]->get_JxW_values();
1087 const auto &q_points = fe_iv[0]->get_quadrature_points();
1088 const auto &q_indices = fe_iv[0]->quadrature_point_indices();
1089 const auto &normals = fe_iv[0]->get_normal_vectors();
1091 auto &solution = scratch_data.solution_interface;
1092 fe_iv[0]->get_fe_face_values(0).get_function_values(solution_global, solution[0][0]);
1093 fe_iv[0]->get_fe_face_values(1).get_function_values(solution_global, solution[1][0]);
1094 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i) {
1095 fe_iv[i]->get_fe_face_values(0).get_function_values(
sol_vector[i], solution[0][i]);
1096 fe_iv[i]->get_fe_face_values(1).get_function_values(
sol_vector[i], solution[1][i]);
1102 for (
const auto &q_index : q_indices) {
1103 const auto &x_q = q_points[q_index];
1104 auto sol_q_s = std::tuple_cat(
local_sol_q(solution[0], q_index), std::tie(extracted_data, variables));
1105 auto sol_q_n = std::tuple_cat(
local_sol_q(solution[1], q_index), std::tie(extracted_data, variables));
1107 const uint from_n_dofs = fe_iv[k]->n_current_interface_dofs();
1114 for (
uint i = 0; i < to_n_dofs; ++i) {
1115 const auto &cd_i = fe_iv[0]->interface_dof_to_dof_indices(i);
1116 const uint face_no_i = cd_i[0] == numbers::invalid_unsigned_int ? 1 : 0;
1117 const auto &component_i = fe_iv[0]->get_fe().system_to_component_index(cd_i[face_no_i]).first;
1118 for (
uint j = 0; j < from_n_dofs; ++j) {
1119 const auto &cd_j = fe_iv[k]->interface_dof_to_dof_indices(j);
1120 const uint face_no_j = cd_j[0] == numbers::invalid_unsigned_int ? 1 : 0;
1121 const auto &component_j = fe_iv[k]->get_fe().system_to_component_index(cd_j[face_no_j]).first;
1123 copy_data_face.cell_jacobian[k](i, j) +=
1125 fe_iv[k]->get_fe_face_values(face_no_j).shape_value_component(
1126 cd_j[face_no_j], q_index, component_j) *
1127 (fe_iv[0]->jump_in_shape_values(i, q_index, component_i) *
1128 scalar_product(
std::get<k>(j_numflux)[face_no_j](component_i, component_j),
1135 const auto copier = [&](
const CopyData &c) {
1137 constraints.distribute_local_to_global(c.cell_jacobian[0], c.local_dof_indices[0],
jacobian);
1138 constraints.distribute_local_to_global(c.cell_mass_jacobian, c.local_dof_indices[0],
jacobian);
1139 for (
auto &cdf : c.face_data) {
1140 constraints.distribute_local_to_global(cdf.cell_jacobian[0], cdf.joint_dof_indices[0],
jacobian);
1141 if constexpr (Components::count_extractors() > 0) {
1142 FullMatrix<NumberType> extractor_dependence(cdf.joint_dof_indices[0].size(),
1145 constraints.distribute_local_to_global(extractor_dependence, cdf.joint_dof_indices[0],
1149 if constexpr (Components::count_extractors() > 0) {
1150 FullMatrix<NumberType> extractor_dependence(c.local_dof_indices[0].size(),
extractor_dof_indices.size());
1152 constraints.distribute_local_to_global(extractor_dependence, c.local_dof_indices[0],
1158 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i) {
1160 j_ug[i].add(c.local_dof_indices[0], c.local_dof_indices[i], c.cell_jacobian[i]);
1162 for (
auto &cdf : c.face_data) {
1163 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i) {
1165 j_ug[i].add(cdf.joint_dof_indices[0], cdf.joint_dof_indices[i], cdf.cell_jacobian[i]);
1173 const UpdateFlags update_flags =
1174 update_values | update_gradients | update_quadrature_points | update_JxW_values;
1175 const MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells |
1176 MeshWorker::assemble_boundary_faces |
1177 MeshWorker::assemble_own_interior_faces_once;
1193 if (exception)
throw std::runtime_error(
"Infinity encountered in jacobian construction");
1196 tbb::blocked_range<uint>(1, Components::count_fe_subsystems()), [&](tbb::blocked_range<uint> rk) {
1197 for (
uint k = rk.begin(); k < rk.end(); ++k) {
1201 tbb::blocked_range<uint>(0, Components::count_fe_functions(0)), [&](tbb::blocked_range<uint> r) {
1202 for (
uint q = r.begin(); q < r.end(); ++q)
1203 for (
const auto &c :
model.get_components().ldg_couplings(k, 0))
1205 Vector<NumberType>(),
false);
1213 tbb::blocked_range<uint>(0, Components::count_fe_functions(0)), [&](tbb::blocked_range<uint> rc1) {
1214 tbb::parallel_for(tbb::blocked_range<uint>(0, Components::count_fe_functions(0)),
1215 [&](tbb::blocked_range<uint> rc2) {
1216 for (
uint c1 = rc1.begin(); c1 < rc1.end(); ++c1)
1217 for (
uint c2 = rc2.begin(); c2 < rc2.end(); ++c2) {
1218 for (
uint k = 1; k < Components::count_fe_subsystems(); ++k)
1228 void log(
const std::string logger)
1230 std::stringstream ss;
1231 ss <<
"LDG Assembler: " << std::endl;
1237 spdlog::get(logger)->info(ss.str());
1284 mutable array<BlockVector<NumberType>, Components::count_fe_subsystems()>
sol_vector;
1285 mutable array<BlockVector<NumberType>, Components::count_fe_subsystems()>
sol_vector_tmp;
1294 array<BlockSparseMatrix<NumberType>, Components::count_fe_subsystems()>
jacobian_tmp;
1298 array<BlockSparseMatrix<NumberType>, Components::count_fe_subsystems()>
j_ug;
1299 mutable array<BlockSparseMatrix<NumberType>, Components::count_fe_subsystems()>
j_gu;
1300 mutable array<BlockSparseMatrix<NumberType>, Components::count_fe_subsystems()>
j_wg;
1301 mutable array<BlockSparseMatrix<NumberType>, Components::count_fe_subsystems()>
j_wg_tmp;
1317 if (!
model.get_components().jacobians_constant(k, k - 1)) {
1332 static_assert(k > 0);
1334 if constexpr (k == 1)
1339 for (
const auto &c :
model.get_components().ldg_couplings(k, 0))
1340 for (
const auto &b :
model.get_components().ldg_couplings(k, k - 1))
1344 .mmult(
j_gu[k].block(c[0], c[1]),
j_gu[k - 1].block(b[1], c[1]), Vector<NumberType>(),
false);
1357 template <
int from,
int to,
typename VectorType,
typename VectorTypeldg>
1359 VectorTypeldg &ldg_vector_tmp)
const
1361 static_assert(to - from == 1,
"can only build LDG from last level!");
1362 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
1367 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
1368 const auto &fe_v = scratch_data.new_fe_values(t_cell);
1369 const uint to_n_dofs = fe_v[to]->get_fe().n_dofs_per_cell();
1370 copy_data.reinit(scratch_data.cell[to], to_n_dofs);
1372 const auto &JxW = fe_v[to]->get_JxW_values();
1373 const auto &q_points = fe_v[to]->get_quadrature_points();
1374 const auto &q_indices = fe_v[to]->quadrature_point_indices();
1375 auto &solution = scratch_data.solution;
1377 fe_v[from]->get_function_values(solution_global, solution[from]);
1379 array<Tensor<1, dim, NumberType>, Components::count_fe_functions(to)> flux{};
1380 array<
NumberType, Components::count_fe_functions(to)> source{};
1381 for (
const auto &q_index : q_indices) {
1382 const auto &x_q = q_points[q_index];
1383 model.template ldg_flux<to>(flux, x_q, solution[from][q_index]);
1384 model.template ldg_source<to>(source, x_q, solution[from][q_index]);
1386 for (
uint i = 0; i < to_n_dofs; ++i) {
1387 const auto component_i = fe_v[to]->get_fe().system_to_component_index(i).first;
1388 copy_data.cell_residual(i) += JxW[q_index] *
1389 (-scalar_product(fe_v[to]->shape_grad_component(i, q_index, component_i),
1391 + fe_v[to]->shape_value_component(i, q_index, component_i) *
1392 source[component_i]);
1396 const auto boundary_worker = [&](
const Iterator &t_cell,
const uint &face_no, Scratch &scratch_data,
1397 CopyData ©_data) {
1398 const auto &fe_fv = scratch_data.new_fe_boundary_values(t_cell, face_no);
1399 const uint to_n_dofs = fe_fv[to]->get_fe().n_dofs_per_cell();
1401 const auto &JxW = fe_fv[to]->get_JxW_values();
1402 const auto &q_points = fe_fv[to]->get_quadrature_points();
1403 const auto &q_indices = fe_fv[to]->quadrature_point_indices();
1404 const std::vector<Tensor<1, dim>> &normals = fe_fv[from]->get_normal_vectors();
1405 auto &solution = scratch_data.solution;
1407 fe_fv[from]->get_function_values(solution_global, solution[from]);
1409 array<Tensor<1, dim, NumberType>, Components::count_fe_functions(to)> numflux{};
1410 for (
const auto &q_index : q_indices) {
1411 const auto &x_q = q_points[q_index];
1412 model.template ldg_boundary_numflux<to>(numflux, normals[q_index], x_q, solution[from][q_index]);
1414 for (
uint i = 0; i < to_n_dofs; ++i) {
1415 const auto component_i = fe_fv[to]->get_fe().system_to_component_index(i).first;
1416 copy_data.cell_residual(i) +=
1418 (fe_fv[to]->shape_value_component(i, q_index, component_i) *
1419 scalar_product(numflux[component_i], normals[q_index]));
1423 const auto face_worker = [&](
const Iterator &t_cell,
const uint &f,
const uint &sf,
const Iterator &t_ncell,
1424 const uint &nf,
const unsigned int &nsf, Scratch &scratch_data,
1425 CopyData ©_data) {
1426 const auto &fe_iv = scratch_data.new_fe_interface_values(t_cell, f, sf, t_ncell, nf, nsf);
1427 const uint to_n_dofs = fe_iv[to]->n_current_interface_dofs();
1428 auto ©_data_face = copy_data.new_face_data(*(fe_iv[to]));
1430 const auto &JxW = fe_iv[to]->get_JxW_values();
1431 const auto &q_points = fe_iv[to]->get_quadrature_points();
1432 const auto &q_indices = fe_iv[to]->quadrature_point_indices();
1434 const std::vector<Tensor<1, dim>> &normals = fe_iv[to]->get_normal_vectors();
1435 auto &solution = scratch_data.solution_interface;
1437 fe_iv[from]->get_fe_face_values(0).get_function_values(solution_global, solution[0][from]);
1438 fe_iv[from]->get_fe_face_values(1).get_function_values(solution_global, solution[1][from]);
1440 array<Tensor<1, dim, NumberType>, Components::count_fe_functions(to)> numflux{};
1441 for (
const auto &q_index : q_indices) {
1442 const auto &x_q = q_points[q_index];
1443 model.template ldg_numflux<to>(numflux, normals[q_index], x_q, solution[0][from][q_index],
1444 solution[1][from][q_index]);
1446 for (
uint i = 0; i < to_n_dofs; ++i) {
1447 const auto &cd_i = fe_iv[to]->interface_dof_to_dof_indices(i);
1448 const auto component_i = cd_i[0] == numbers::invalid_unsigned_int
1449 ? fe_iv[to]->get_fe().system_to_component_index(cd_i[1]).first
1450 : fe_iv[to]->get_fe().system_to_component_index(cd_i[0]).first;
1451 copy_data_face.cell_residual(i) +=
1453 (fe_iv[to]->jump_in_shape_values(i, q_index, component_i) *
1454 scalar_product(numflux[component_i],
1459 const auto copier = [&](
const CopyData &c) {
1460 constraints.distribute_local_to_global(c.cell_residual, c.local_dof_indices, ldg_vector_tmp);
1461 for (
auto &cdf : c.face_data)
1462 constraints.distribute_local_to_global(cdf.cell_residual, cdf.joint_dof_indices, ldg_vector_tmp);
1465 const MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells |
1466 MeshWorker::assemble_boundary_faces |
1467 MeshWorker::assemble_own_interior_faces_once;
1475 for (
uint i = 0; i < Components::count_fe_functions(to); ++i)
1488 template <
int from,
int to,
typename VectorType>
1490 BlockSparseMatrix<NumberType> &ldg_jacobian_tmp)
const
1492 static_assert(to - from == 1,
"can only build LDG from last level!");
1493 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
1497 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
1498 const auto &fe_v = scratch_data.new_fe_values(t_cell);
1499 const uint to_n_dofs = fe_v[to]->get_fe().n_dofs_per_cell();
1500 const uint from_n_dofs = fe_v[from]->get_fe().n_dofs_per_cell();
1501 copy_data.reinit(scratch_data.cell[from], scratch_data.cell[to], from_n_dofs, to_n_dofs);
1503 const auto &JxW = fe_v[to]->get_JxW_values();
1504 const auto &q_points = fe_v[to]->get_quadrature_points();
1505 const auto &q_indices = fe_v[to]->quadrature_point_indices();
1506 auto &solution = scratch_data.solution;
1508 fe_v[from]->get_function_values(solution_global, solution[from]);
1511 SimpleMatrix<
NumberType, Components::count_fe_functions(to), Components::count_fe_functions(from)> j_source;
1512 for (
const auto &q_index : q_indices) {
1513 const auto &x_q = q_points[q_index];
1514 model.template jacobian_flux<from, to>(j_flux, x_q, solution[from][q_index]);
1515 model.template jacobian_source<from, to>(j_source, x_q, solution[from][q_index]);
1517 for (
uint i = 0; i < to_n_dofs; ++i) {
1518 const auto component_i = fe_v[to]->get_fe().system_to_component_index(i).first;
1519 for (
uint j = 0; j < from_n_dofs; ++j) {
1520 const auto component_j = fe_v[from]->get_fe().system_to_component_index(j).first;
1521 copy_data.cell_jacobian(i, j) +=
1523 fe_v[from]->shape_value_component(j, q_index, component_j) *
1524 (-scalar_product(fe_v[to]->shape_grad_component(i, q_index, component_i),
1525 j_flux(component_i, component_j))
1526 + fe_v[to]->shape_value_component(i, q_index, component_i) *
1527 j_source(component_i, component_j));
1532 const auto boundary_worker = [&](
const Iterator &t_cell,
const uint &face_no, Scratch &scratch_data,
1533 CopyData ©_data) {
1534 const auto &fe_fv = scratch_data.new_fe_boundary_values(t_cell, face_no);
1535 const uint to_n_dofs = fe_fv[to]->get_fe().n_dofs_per_cell();
1536 const uint from_n_dofs = fe_fv[from]->get_fe().n_dofs_per_cell();
1538 const auto &JxW = fe_fv[to]->get_JxW_values();
1539 const auto &q_points = fe_fv[to]->get_quadrature_points();
1540 const auto &q_indices = fe_fv[to]->quadrature_point_indices();
1541 const std::vector<Tensor<1, dim>> &normals = fe_fv[to]->get_normal_vectors();
1542 auto &solution = scratch_data.solution;
1544 fe_fv[from]->get_function_values(solution_global, solution[from]);
1548 for (
const auto &q_index : q_indices) {
1549 const auto &x_q = q_points[q_index];
1550 model.template jacobian_boundary_numflux<from, to>(j_boundary_numflux, normals[q_index], x_q,
1551 solution[from][q_index]);
1553 for (
uint i = 0; i < to_n_dofs; ++i) {
1554 const auto component_i = fe_fv[to]->get_fe().system_to_component_index(i).first;
1555 for (
uint j = 0; j < from_n_dofs; ++j) {
1556 const auto component_j = fe_fv[from]->get_fe().system_to_component_index(j).first;
1557 copy_data.cell_jacobian(i, j) +=
1559 fe_fv[from]->shape_value_component(j, q_index, component_j) *
1560 (fe_fv[to]->shape_value_component(i, q_index, component_i) *
1561 scalar_product(j_boundary_numflux(component_i, component_j),
1567 const auto face_worker = [&](
const Iterator &t_cell,
const uint &f,
const uint &sf,
const Iterator &t_ncell,
1568 const uint &nf,
const unsigned int &nsf, Scratch &scratch_data,
1569 CopyData ©_data) {
1570 const auto &fe_iv = scratch_data.new_fe_interface_values(t_cell, f, sf, t_ncell, nf, nsf);
1571 const uint to_n_dofs = fe_iv[to]->n_current_interface_dofs();
1572 const uint from_n_dofs = fe_iv[from]->n_current_interface_dofs();
1573 auto ©_data_face = copy_data.new_face_data(*(fe_iv[from]), *(fe_iv[to]));
1575 const auto &JxW = fe_iv[to]->get_JxW_values();
1576 const auto &q_points = fe_iv[to]->get_quadrature_points();
1577 const auto &q_indices = fe_iv[to]->quadrature_point_indices();
1578 const std::vector<Tensor<1, dim>> &normals = fe_iv[to]->get_normal_vectors();
1579 auto &solution = scratch_data.solution_interface;
1581 fe_iv[from]->get_fe_face_values(0).get_function_values(solution_global, solution[0][from]);
1582 fe_iv[from]->get_fe_face_values(1).get_function_values(solution_global, solution[1][from]);
1584 array<SimpleMatrix<Tensor<1, dim>, Components::count_fe_functions(to), Components::count_fe_functions(from)>,
1587 for (
const auto &q_index : q_indices) {
1588 const auto &x_q = q_points[q_index];
1589 model.template jacobian_numflux<from, to>(j_numflux, normals[q_index], x_q, solution[0][from][q_index],
1590 solution[1][from][q_index]);
1592 for (
uint i = 0; i < to_n_dofs; ++i) {
1593 const auto &cd_i = fe_iv[to]->interface_dof_to_dof_indices(i);
1594 const uint face_no_i = cd_i[0] == numbers::invalid_unsigned_int ? 1 : 0;
1595 const auto &component_i = fe_iv[to]->get_fe().system_to_component_index(cd_i[face_no_i]).first;
1596 for (
uint j = 0; j < from_n_dofs; ++j) {
1597 const auto &cd_j = fe_iv[from]->interface_dof_to_dof_indices(j);
1598 const uint face_no_j = cd_j[0] == numbers::invalid_unsigned_int ? 1 : 0;
1599 const auto &component_j = fe_iv[from]->get_fe().system_to_component_index(cd_j[face_no_j]).first;
1601 copy_data_face.cell_jacobian(i, j) +=
1603 fe_iv[from]->get_fe_face_values(face_no_j).shape_value_component(
1604 cd_j[face_no_j], q_index, component_j) *
1605 (fe_iv[to]->jump_in_shape_values(i, q_index, component_i) *
1606 scalar_product(j_numflux[face_no_j](component_i, component_j),
1612 const auto copier = [&](
const CopyData &c) {
1613 ldg_jacobian_tmp.add(c.local_dof_indices_to, c.local_dof_indices_from, c.cell_jacobian);
1614 for (
auto &cdf : c.face_data)
1615 ldg_jacobian_tmp.add(cdf.joint_dof_indices_to, cdf.joint_dof_indices_from, cdf.cell_jacobian);
1618 const MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells |
1619 MeshWorker::assemble_boundary_faces |
1620 MeshWorker::assemble_own_interior_faces_once;
1624 ldg_jacobian_tmp = 0;
1628 for (
const auto &c :
model.get_components().ldg_couplings(to, from))
1630 Vector<NumberType>(),
false);
1642 const DoFHandler<dim> &from_dofh,
const int stencil = 1,
1643 bool add_extractor_dofs =
false)
const
1646 auto to_dofs_per_component = DoFTools::count_dofs_per_fe_component(to_dofh);
1647 auto from_dofs_per_component = DoFTools::count_dofs_per_fe_component(from_dofh);
1648 auto to_n_fe = to_dofs_per_component.size();
1649 auto from_n_fe = from_dofs_per_component.size();
1650 for (
uint j = 1; j < from_dofs_per_component.size(); ++j)
1651 if (from_dofs_per_component[j] != from_dofs_per_component[0])
1652 throw std::runtime_error(
"For LDG the FE basis of all systems must be equal!");
1653 for (
uint j = 1; j < to_dofs_per_component.size(); ++j)
1654 if (to_dofs_per_component[j] != to_dofs_per_component[0])
1655 throw std::runtime_error(
"For LDG the FE basis of all systems must be equal!");
1657 BlockDynamicSparsityPattern dsp(to_n_fe, from_n_fe);
1658 for (
uint i = 0; i < to_n_fe; ++i)
1659 for (
uint j = 0; j < from_n_fe; ++j)
1660 dsp.block(i, j).reinit(to_dofs_per_component[i], from_dofs_per_component[j]);
1661 dsp.collect_sizes();
1663 const auto to_dofs_per_cell = to_dofh.get_fe().dofs_per_cell;
1664 const auto from_dofs_per_cell = from_dofh.get_fe().dofs_per_cell;
1666 for (
const auto &t_cell : triangulation.active_cell_iterators()) {
1667 std::vector<types::global_dof_index> to_dofs(to_dofs_per_cell);
1668 std::vector<types::global_dof_index> from_dofs(from_dofs_per_cell);
1669 const auto to_cell = t_cell->as_dof_handler_iterator(to_dofh);
1670 const auto from_cell = t_cell->as_dof_handler_iterator(from_dofh);
1671 to_cell->get_dof_indices(to_dofs);
1672 from_cell->get_dof_indices(from_dofs);
1674 std::function<void(
decltype(from_cell) &,
const int)> add_all_neighbor_dofs = [&](
const auto &from_cell,
1675 const int stencil_level) {
1676 for (
const auto face_no : from_cell->face_indices()) {
1677 const auto face = from_cell->face(face_no);
1678 if (!face->at_boundary()) {
1679 auto neighbor_cell = from_cell->neighbor(face_no);
1682 while (neighbor_cell->has_children())
1683 neighbor_cell = neighbor_cell->child(face_no == 0 ? 1 : 0);
1686 else if (neighbor_cell->has_children()) {
1687 throw std::runtime_error(
"not yet implemented lol");
1690 if (!neighbor_cell->is_active())
continue;
1692 std::vector<types::global_dof_index> tmp(from_dofs_per_cell);
1693 neighbor_cell->get_dof_indices(tmp);
1695 from_dofs.insert(std::end(from_dofs), std::begin(tmp), std::end(tmp));
1697 if (stencil_level <
stencil) add_all_neighbor_dofs(neighbor_cell, stencil_level + 1);
1702 add_all_neighbor_dofs(from_cell, 1);
1704 for (
const auto i : to_dofs)
1705 for (
const auto j : from_dofs)
1709 if (add_extractor_dofs)
1710 for (
uint row = 0; row < dsp.n_rows(); ++row)
1713 sparsity_pattern.copy_from(dsp);
1722 void build_inverse(
const SparseMatrix<NumberType> &in, SparseMatrix<NumberType> &out)
const
1724 GrowingVectorMemory<Vector<NumberType>> mem;
1725 SparseDirectUMFPACK inverse;
1726 inverse.initialize(in);
1729 tbb::parallel_for(tbb::blocked_range<int>(0, out.n()), [&](tbb::blocked_range<int> r) {
1730 typename VectorMemory<Vector<NumberType>>::Pointer tmp(mem);
1731 tmp->reinit(out.m());
1732 for (int n = r.begin(); n < r.end(); ++n) {
1735 inverse.solve(*tmp);
1736 for (auto it = out.begin(n); it != out.end(n); ++it)
1737 it->value() = (*tmp)[it->column()];
1743 constexpr static int nothing = 0;
1745 using Base::EoM_cell;
1746 using Base::extractor_jacobian_u;
1747 using Base::old_EoM_cell;
1752 auto helper = [&](
auto EoMfun,
auto outputter) {
1753 auto EoM_cell = this->EoM_cell;
1755 EoM_cell, solution_global, dof_handler, mapping, EoMfun, [&](
const auto &p,
const auto &) {
return p; },
1756 EoM_abs_tol, EoM_max_iter);
1757 auto EoM_unit = mapping.transform_real_to_unit_cell(EoM_cell, EoM);
1759 using t_Iterator =
typename Triangulation<dim>::active_cell_iterator;
1761 std::vector<std::shared_ptr<FEValues<dim>>> fe_v;
1762 for (
uint k = 0; k < Components::count_fe_subsystems(); ++k) {
1763 fe_v.emplace_back(std::make_shared<FEValues<dim>>(
1764 mapping, discretization.get_fe(k), EoM_unit,
1765 update_values | update_gradients | update_quadrature_points | update_JxW_values | update_hessians));
1767 auto cell = dof_handler_list[k]->begin_active();
1768 cell->copy_from(*t_Iterator(EoM_cell));
1769 fe_v[k]->reinit(cell);
1772 std::vector<std::vector<Vector<NumberType>>> solutions;
1773 for (
uint k = 0; k < Components::count_fe_subsystems(); ++k) {
1774 solutions.push_back({Vector<NumberType>(Components::count_fe_functions(k))});
1776 fe_v[0]->get_function_values(solution_global, solutions[k]);
1778 fe_v[k]->get_function_values(sol_vector[k], solutions[k]);
1780 std::vector<Vector<NumberType>> solutions_vector;
1781 for (
uint k = 0; k < Components::count_fe_subsystems(); ++k)
1782 solutions_vector.push_back(solutions[k][0]);
1784 std::array<
NumberType, Components::count_extractors()> __extracted_data{{}};
1785 if constexpr (Components::count_extractors() > 0)
1786 extract(__extracted_data, solution_global, variables,
true,
false,
false);
1787 const auto &extracted_data = __extracted_data;
1789 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad{
1790 std::vector<Tensor<1, dim, NumberType>>(Components::count_fe_functions())};
1791 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess{
1792 std::vector<Tensor<2, dim, NumberType>>(Components::count_fe_functions())};
1793 fe_v[0]->get_function_gradients(solution_global, solution_grad);
1794 fe_v[0]->get_function_hessians(solution_global, solution_hess);
1796 auto solution_tuple = std::tuple_cat(
vector_to_tuple<Components::count_fe_subsystems()>(solutions_vector),
1797 std::tie(solution_grad[0], solution_hess[0], extracted_data, variables));
1799 outputter(data_out, EoM, fe_more_conv(solution_tuple));
1801 model.template readouts_multiple(helper, data_out);
1805 const VectorType &variables,
bool search_EoM,
bool set_EoM,
bool postprocess)
const
1807 auto EoM = this->EoM;
1808 auto EoM_cell = this->EoM_cell;
1809 if (search_EoM || EoM_cell == *(dof_handler.active_cell_iterators().end()))
1811 EoM_cell, solution_global, dof_handler, mapping,
1812 [&](
const auto &p,
const auto &values) {
return model.EoM(p, values); },
1813 [&](
const auto &p,
const auto &values) {
return postprocess ? model.EoM_postprocess(p, values) : p; },
1814 EoM_abs_tol, EoM_max_iter);
1817 this->EoM_cell = EoM_cell;
1819 auto EoM_unit = mapping.transform_real_to_unit_cell(EoM_cell, EoM);
1821 rebuild_ldg_vectors(solution_global);
1823 using t_Iterator =
typename Triangulation<dim>::active_cell_iterator;
1825 std::vector<std::shared_ptr<FEValues<dim>>> fe_v;
1826 for (
uint k = 0; k < Components::count_fe_subsystems(); ++k) {
1827 fe_v.emplace_back(std::make_shared<FEValues<dim>>(
1828 mapping, discretization.get_fe(k), EoM_unit,
1829 update_values | update_gradients | update_quadrature_points | update_JxW_values | update_hessians));
1831 auto cell = dof_handler_list[k]->begin_active();
1832 cell->copy_from(*t_Iterator(EoM_cell));
1833 fe_v[k]->reinit(cell);
1836 std::vector<std::vector<Vector<NumberType>>> solutions;
1837 for (
uint k = 0; k < Components::count_fe_subsystems(); ++k) {
1838 solutions.push_back({Vector<NumberType>(Components::count_fe_functions(k))});
1840 fe_v[0]->get_function_values(solution_global, solutions[k]);
1842 fe_v[k]->get_function_values(sol_vector[k], solutions[k]);
1844 std::vector<Vector<NumberType>> solutions_vector;
1845 for (
uint k = 0; k < Components::count_fe_subsystems(); ++k)
1846 solutions_vector.push_back(solutions[k][0]);
1848 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad{
1849 std::vector<Tensor<1, dim, NumberType>>(Components::count_fe_functions())};
1850 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess{
1851 std::vector<Tensor<2, dim, NumberType>>(Components::count_fe_functions())};
1852 fe_v[0]->get_function_gradients(solution_global, solution_grad);
1853 fe_v[0]->get_function_hessians(solution_global, solution_hess);
1855 auto solution_tuple = std::tuple_cat(
vector_to_tuple<Components::count_fe_subsystems()>(solutions_vector),
1856 std::tie(solution_grad[0], solution_hess[0], this->nothing, variables));
1858 model.template extract(data, EoM, fe_more_conv(solution_tuple));
1864 if (extractor_jacobian_u.m() != Components::count_extractors() ||
1865 extractor_jacobian_u.n() != Components::count_fe_functions())
1866 extractor_jacobian_u =
1867 FullMatrix<NumberType>(Components::count_extractors(), Components::count_fe_functions());
1870 EoM_cell, solution_global, dof_handler, mapping,
1871 [&](
const auto &p,
const auto &values) {
return model.EoM(p, values); },
1872 [&](
const auto &p,
const auto &values) {
return model.EoM_postprocess(p, values); }, EoM_abs_tol,
1874 auto EoM_unit = mapping.transform_real_to_unit_cell(EoM_cell, EoM);
1875 bool new_cell = (old_EoM_cell != EoM_cell);
1876 old_EoM_cell = EoM_cell;
1878 using t_Iterator =
typename Triangulation<dim>::active_cell_iterator;
1880 std::vector<std::shared_ptr<FEValues<dim>>> fe_v;
1881 for (
uint k = 0; k < Components::count_fe_subsystems(); ++k) {
1882 fe_v.emplace_back(std::make_shared<FEValues<dim>>(
1883 mapping, discretization.get_fe(k), EoM_unit,
1884 update_values | update_gradients | update_quadrature_points | update_JxW_values | update_hessians));
1886 auto cell = dof_handler_list[k]->begin_active();
1887 cell->copy_from(*t_Iterator(EoM_cell));
1888 fe_v[k]->reinit(cell);
1891 const uint n_dofs = fe_v[0]->get_fe().n_dofs_per_cell();
1894 extractor_dof_indices.resize(n_dofs);
1895 EoM_cell->get_dof_indices(extractor_dof_indices);
1896 rebuild_jacobian_sparsity();
1899 std::vector<std::vector<Vector<NumberType>>> solutions;
1900 for (
uint k = 0; k < Components::count_fe_subsystems(); ++k) {
1901 solutions.push_back({Vector<NumberType>(Components::count_fe_functions(k))});
1903 fe_v[0]->get_function_values(solution_global, solutions[k]);
1905 fe_v[k]->get_function_values(sol_vector[k], solutions[k]);
1907 std::vector<Vector<NumberType>> solutions_vector;
1908 for (
uint k = 0; k < Components::count_fe_subsystems(); ++k)
1909 solutions_vector.push_back(solutions[k][0]);
1911 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad{
1912 std::vector<Tensor<1, dim, NumberType>>(Components::count_fe_functions())};
1913 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess{
1914 std::vector<Tensor<2, dim, NumberType>>(Components::count_fe_functions())};
1915 fe_v[0]->get_function_gradients(solution_global, solution_grad);
1916 fe_v[0]->get_function_hessians(solution_global, solution_hess);
1918 auto solution_tuple = std::tuple_cat(
vector_to_tuple<Components::count_fe_subsystems()>(solutions_vector),
1919 std::tie(solution_grad[0], solution_hess[0], this->nothing, variables));
1921 extractor_jacobian_u = 0;
1922 model.template jacobian_extractors<0>(extractor_jacobian_u, EoM, fe_more_conv(solution_tuple));
1924 if (extractor_jacobian.m() != Components::count_extractors() || extractor_jacobian.n() != n_dofs)
1925 extractor_jacobian = FullMatrix<NumberType>(Components::count_extractors(), n_dofs);
1927 for (
uint e = 0; e < Components::count_extractors(); ++e)
1928 for (
uint i = 0; i < n_dofs; ++i) {
1929 const auto component_i = fe_v[0]->get_fe().system_to_component_index(i).first;
1930 extractor_jacobian(e, i) =
1931 extractor_jacobian_u(e, component_i) * fe_v[0]->shape_value_component(i, 0, component_i);
1937 using Base::timings_variable_jacobian;
1938 using Base::timings_variable_residual;
1939 template <
typename... T>
static constexpr auto v_tie(T &&...t)
1941 return named_tuple<std::tuple<T &...>,
"variables",
"extractors">(std::tie(t...));
1944 template <
typename... T>
static constexpr auto e_tie(T &&...t)
1946 return named_tuple<std::tuple<T &...>,
"fe_functions",
"fe_derivatives",
"fe_hessians",
"extractors",
1947 "variables">(std::tie(t...));
1954 std::array<
NumberType, Components::count_extractors()> __extracted_data{{}};
1955 if constexpr (Components::count_extractors() > 0)
1956 extract(__extracted_data, spatial_solution, variables,
true,
false,
false);
1957 const auto &extracted_data = __extracted_data;
1958 model.dt_variables(residual, v_tie(variables, extracted_data));
1959 timings_variable_residual.push_back(timer.wall_time());
1966 std::array<
NumberType, Components::count_extractors()> __extracted_data{{}};
1967 if constexpr (Components::count_extractors() > 0)
1968 extract(__extracted_data, spatial_solution, variables,
true,
false,
false);
1969 const auto &extracted_data = __extracted_data;
1970 model.template jacobian_variables<0>(jacobian, v_tie(variables, extracted_data));
1971 timings_variable_jacobian.push_back(timer.wall_time());
This is the general assembler interface for any kind of discretization. An assembler is responsible f...
Definition abstract_assembler.hh:39
Class to manage writing to files. FEM functions are written to vtk files and other data is written to...
Definition data_output.hh:20
FEOutput< dim, VectorType > & fe_output()
Returns a reference to the FEOutput object used to write FEM functions to .vtu files and ....
A wrapper around the boost json value class.
Definition json.hh:19
The LDG assembler that can be used for any LDG scheme, with as many levels as one wants.
Definition ldg.hh:385
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 ldg.hh:1804
double average_time_residual_assembly() const
Definition ldg.hh:1250
array< BlockVector< NumberType >, Components::count_fe_subsystems()> sol_vector
Definition ldg.hh:1284
void build_ldg_jacobian(const VectorType &solution_global, BlockSparseMatrix< NumberType > &ldg_jacobian, BlockSparseMatrix< NumberType > &ldg_jacobian_tmp) const
Build the LDG jacobian at level 'to', which takes information from level 'from'.
Definition ldg.hh:1489
const FiniteElement< dim > & fe
Definition ldg.hh:126
SparseMatrix< NumberType > component_mass_matrix_inverse
Definition ldg.hh:1297
BlockSparsityPattern sparsity_pattern_jacobian
Definition ldg.hh:1288
virtual void residual(VectorType &residual, const VectorType &solution_global, NumberType weight, const VectorType &solution_global_dot, NumberType weight_mass, const VectorType &variables=VectorType()) override
Construct the system residual, i.e. Res = grad(flux) - source.
Definition ldg.hh:716
virtual void jacobian_mass(BlockSparseMatrix< NumberType > &jacobian, const VectorType &solution_global, const VectorType &solution_global_dot, NumberType alpha=1., NumberType beta=1.) override
Definition ldg.hh:864
uint num_residuals() const
Definition ldg.hh:1258
array< BlockSparseMatrix< NumberType >, Components::count_fe_subsystems()> j_wg_tmp
Definition ldg.hh:1301
virtual const BlockSparseMatrix< NumberType > & get_mass_matrix() const override
Obtain the mass matrix.
Definition ldg.hh:652
void build_ldg_sparsity(BlockSparsityPattern &sparsity_pattern, const DoFHandler< dim > &to_dofh, const DoFHandler< dim > &from_dofh, const int stencil=1, bool add_extractor_dofs=false) const
Create a sparsity pattern for matrices between the DoFs of two DoFHandlers, with given stencil size.
Definition ldg.hh:1641
double average_time_jacobian_assembly() const
Definition ldg.hh:1260
void readouts(DataOutput< dim, VectorType > &data_out, const VectorType &solution_global, const VectorType &variables) const
Definition ldg.hh:1749
typename Discretization::NumberType NumberType
Definition ldg.hh:391
static constexpr auto v_tie(T &&...t)
Definition ldg.hh:1939
const Mapping< dim > & mapping
Definition ldg.hh:128
std::vector< double > timings_residual
Definition ldg.hh:1304
array< BlockSparsityPattern, Components::count_fe_subsystems()> sparsity_pattern_ug
Definition ldg.hh:1290
array< BlockVector< NumberType >, Components::count_fe_subsystems()> sol_vector_tmp
Definition ldg.hh:1285
static constexpr uint stencil
Definition ldg.hh:396
auto fe_more_conv(std::tuple< T &... > &t) const
Definition ldg.hh:411
virtual void residual_variables(VectorType &residual, const VectorType &variables, const VectorType &spatial_solution) override
Definition ldg.hh:1950
typename Discretization::VectorType VectorType
Definition ldg.hh:392
BlockSparsityPattern sparsity_pattern_mass
Definition ldg.hh:1289
virtual void reinit_vector(VectorType &vec) const override
Definition ldg.hh:449
virtual void jacobian_variables(FullMatrix< NumberType > &jacobian, const VectorType &variables, const VectorType &spatial_solution) override
Definition ldg.hh:1962
typename Discretization::Components Components
Definition ldg.hh:394
static constexpr auto e_tie(T &&...t)
Definition ldg.hh:1944
uint num_jacobians() const
Definition ldg.hh:1268
virtual void attach_data_output(DataOutput< dim, VectorType > &data_out, const VectorType &solution, const VectorType &variables, const VectorType &dt_solution=VectorType(), const VectorType &residual=VectorType()) override
Attach all intermediate (ldg) vectors to the data output.
Definition ldg.hh:457
virtual void mass(VectorType &residual, const VectorType &solution_global, const VectorType &solution_global_dot, NumberType weight) override
Construct the mass.
Definition ldg.hh:661
std::vector< const DoFHandler< dim > * > dof_handler_list
Definition ldg.hh:1282
auto fe_conv(std::tuple< T &... > &t) const
Definition ldg.hh:399
Model & model
Definition ldg.hh:125
QGauss< dim - 1 > quadrature_face
Definition ldg.hh:1278
array< BlockSparsityPattern, Components::count_fe_subsystems()> sparsity_pattern_wg
Definition ldg.hh:1292
void rebuild_ldg_jacobian(const VectorType &sol) const
Definition ldg.hh:1330
static constexpr uint dim
Definition ldg.hh:395
void log(const std::string logger)
Definition ldg.hh:1228
array< bool, Components::count_fe_subsystems()> ldg_matrix_built
Definition ldg.hh:1307
array< BlockSparseMatrix< NumberType >, Components::count_fe_subsystems()> j_ug
Definition ldg.hh:1298
virtual void reinit() override
Reinitialize the assembler. This is necessary if the mesh has changed, e.g. after a mesh refinement.
Definition ldg.hh:482
virtual void rebuild_jacobian_sparsity() override
Definition ldg.hh:559
auto ref_conv(std::tuple< T &... > &t) const
Definition ldg.hh:426
bool jacobian_extractors(FullMatrix< NumberType > &extractor_jacobian, const VectorType &solution_global, const VectorType &variables)
Definition ldg.hh:1861
void build_inverse(const SparseMatrix< NumberType > &in, SparseMatrix< NumberType > &out) const
Build the inverse of matrix in and save the result to out.
Definition ldg.hh:1722
Discretization_ Discretization
Definition ldg.hh:389
array< BlockSparsityPattern, Components::count_fe_subsystems()> sparsity_pattern_gu
Definition ldg.hh:1291
Discretization & discretization
Definition ldg.hh:124
uint batch_size
Definition ldg.hh:131
uint threads
Definition ldg.hh:130
array< BlockSparseMatrix< NumberType >, Components::count_fe_subsystems()> jacobian_tmp
Definition ldg.hh:1294
virtual const BlockSparsityPattern & get_sparsity_pattern_jacobian() const override
Obtain the sparsity pattern of the jacobian matrix.
Definition ldg.hh:648
Assembler(Discretization &discretization, Model &model, const JSONValue &json)
Definition ldg.hh:439
BlockSparseMatrix< NumberType > mass_matrix
Definition ldg.hh:1296
virtual void jacobian(BlockSparseMatrix< NumberType > &jacobian, const VectorType &solution_global, NumberType weight, const VectorType &solution_global_dot, NumberType alpha, NumberType beta, const VectorType &variables=VectorType()) override
Construct the system jacobian, i.e. dRes/du.
Definition ldg.hh:931
array< BlockSparseMatrix< NumberType >, Components::count_fe_subsystems()> j_wg
Definition ldg.hh:1300
std::vector< types::global_dof_index > extractor_dof_indices
Definition ldg.hh:142
uint num_reinits() const
Definition ldg.hh:1248
void rebuild_ldg_vectors(const VectorType &sol) const
Definition ldg.hh:1314
array< bool, Components::count_fe_subsystems()> jacobian_tmp_built
Definition ldg.hh:1308
QGauss< dim > quadrature
Definition ldg.hh:1277
std::vector< double > timings_reinit
Definition ldg.hh:1303
array< Vector< NumberType >, Components::count_fe_subsystems()> sol_vector_vec_tmp
Definition ldg.hh:1286
std::vector< double > timings_jacobian
Definition ldg.hh:1305
Model_ Model
Definition ldg.hh:390
double average_time_reinit() const
Definition ldg.hh:1240
array< BlockSparseMatrix< NumberType >, Components::count_fe_subsystems()> j_gu
Definition ldg.hh:1299
void build_ldg_vector(const VectorType &solution_global, VectorTypeldg &ldg_vector, VectorTypeldg &ldg_vector_tmp) const
Build the LDG vector at level 'to', which takes information from level 'from'.
Definition ldg.hh:1358
virtual void refinement_indicator(Vector< double > &indicator, const VectorType &solution_global) override
Definition ldg.hh:566
const DoFHandler< dim > & dof_handler
Definition ldg.hh:127
NumberType_ NumberType
Definition ldg.hh:33
Components_ Components
Definition ldg.hh:32
static constexpr uint dim
Definition ldg.hh:37
Vector< NumberType > VectorType
Definition ldg.hh:34
FullMatrix< NumberType > extractor_jacobian_du
Definition ldg.hh:140
const double EoM_abs_tol
Definition ldg.hh:135
const FiniteElement< dim > & fe
Definition ldg.hh:126
uint num_variable_jacobians() const
Definition ldg.hh:121
FullMatrix< NumberType > extractor_jacobian_u
Definition ldg.hh:139
FullMatrix< NumberType > extractor_jacobian_ddu
Definition ldg.hh:141
typename Discretization::NumberType NumberType
Definition ldg.hh:45
auto & get_discretization()
Definition ldg.hh:71
double average_time_variable_residual_assembly()
Definition ldg.hh:103
const Mapping< dim > & mapping
Definition ldg.hh:128
static constexpr uint dim
Definition ldg.hh:49
FullMatrix< NumberType > extractor_jacobian
Definition ldg.hh:138
DoFHandler< dim >::cell_iterator old_EoM_cell
Definition ldg.hh:134
Discretization_ Discretization
Definition ldg.hh:43
typename Discretization::VectorType VectorType
Definition ldg.hh:46
virtual void set_time(double t) override
Set the current time. The assembler should usually just forward this to the numerical model.
Definition ldg.hh:99
const auto & get_discretization() const
Definition ldg.hh:70
Model & model
Definition ldg.hh:125
virtual void refinement_indicator(Vector< double > &, const VectorType &)=0
virtual void reinit() override
Reinitialize the assembler. This is necessary if the mesh has changed, e.g. after a mesh refinement.
Definition ldg.hh:73
double average_time_variable_jacobian_assembly()
Definition ldg.hh:113
const uint EoM_max_iter
Definition ldg.hh:136
virtual IndexSet get_differential_indices() const override
Obtain the dofs which contain time derivatives.
Definition ldg.hh:64
std::vector< double > timings_variable_residual
Definition ldg.hh:144
std::vector< double > timings_variable_jacobian
Definition ldg.hh:145
typename Discretization::Components Components
Definition ldg.hh:48
Discretization & discretization
Definition ldg.hh:124
uint batch_size
Definition ldg.hh:131
uint threads
Definition ldg.hh:130
LDGAssemblerBase(Discretization &discretization, Model &model, const JSONValue &json)
Definition ldg.hh:51
Point< dim > EoM
Definition ldg.hh:137
DoFHandler< dim >::cell_iterator EoM_cell
Definition ldg.hh:133
std::vector< types::global_dof_index > extractor_dof_indices
Definition ldg.hh:142
uint num_variable_residuals() const
Definition ldg.hh:111
Model_ Model
Definition ldg.hh:44
virtual void rebuild_jacobian_sparsity()=0
const DoFHandler< dim > & dof_handler
Definition ldg.hh:127
Definition quadrature.hh:50
A simple NxM-matrix class, which is used for cell-wise Jacobians.
Definition tuples.hh:153
Definition complex_math.hh:14
dealii::Point< dim > get_EoM_point(typename dealii::DoFHandler< dim >::cell_iterator &EoM_cell, const VectorType &sol, const dealii::DoFHandler< dim > &dof_handler, const dealii::Mapping< dim > &mapping, const EoMFUN &get_EoM, const EoMPFUN &EoM_postprocess=[](const auto &p, const auto &values) { return p;}, const double EoM_abs_tol=1e-5, const uint max_iter=100)
Get the EoM point for a given solution and model.
Definition EoM.hh:662
auto local_sol_q(const std::array< T, N > &a, uint q_index)
Definition tuples.hh:278
bool __forceinline__ __host__ __device__ is_close(T1 a, T2 b, T3 eps_)
Function to evaluate whether two floats are equal to numerical precision. Tests for both relative and...
Definition math.hh:160
auto jacobian_tuple()
Definition tuples.hh:288
auto vector_to_tuple(const std::vector< T > &v)
Definition tuples.hh:216
constexpr void constexpr_for(F &&f)
A compile-time for loop, which calls the lambda f of signature void(integer) for each index.
Definition utils.hh:27
auto jacobian_2_tuple()
Definition tuples.hh:299
unsigned int uint
Definition utils.hh:22
constexpr auto & get(DiFfRG::named_tuple< tuple_type, strs... > &ob)
Definition tuples.hh:119
std::array< uint, 2 > cell_indices
Definition ldg.hh:368
std::array< double, 2 > values
Definition ldg.hh:369
uint cell_index
Definition ldg.hh:373
double value
Definition ldg.hh:372
std::vector< CopyFaceData_I > face_data
Definition ldg.hh:371
FullMatrix< NumberType > cell_jacobian
Definition ldg.hh:289
std::vector< types::global_dof_index > joint_dof_indices_from
Definition ldg.hh:290
std::vector< types::global_dof_index > joint_dof_indices_to
Definition ldg.hh:291
FullMatrix< NumberType > extractor_cell_jacobian
Definition ldg.hh:324
array< FullMatrix< NumberType >, n_fe_subsystems > cell_jacobian
Definition ldg.hh:323
array< vector< types::global_dof_index >, n_fe_subsystems > joint_dof_indices
Definition ldg.hh:325
void reinit(const array< Iterator, n_fe_subsystems > &cell, const uint n_extractors)
Definition ldg.hh:336
CopyDataFace_J & new_face_data(const array< unique_ptr< FEInterfaceValues< dim > >, n_fe_subsystems > &fe_iv, const uint n_extractors)
Definition ldg.hh:351
FullMatrix< NumberType > cell_mass_jacobian
Definition ldg.hh:329
array< FullMatrix< NumberType >, n_fe_subsystems > cell_jacobian
Definition ldg.hh:328
vector< CopyDataFace_J > face_data
Definition ldg.hh:332
FullMatrix< NumberType > extractor_cell_jacobian
Definition ldg.hh:330
array< vector< types::global_dof_index >, n_fe_subsystems > local_dof_indices
Definition ldg.hh:331
uint dofs_per_cell
Definition ldg.hh:334
CopyDataFace_J & new_face_data(const FEInterfaceValues< dim > &fe_iv_from, const FEInterfaceValues< dim > &fe_iv_to)
Definition ldg.hh:310
std::vector< types::global_dof_index > local_dof_indices_to
Definition ldg.hh:296
FullMatrix< NumberType > cell_jacobian
Definition ldg.hh:294
std::vector< CopyDataFace_J > face_data
Definition ldg.hh:297
std::vector< types::global_dof_index > local_dof_indices_from
Definition ldg.hh:295
void reinit(const Iterator &cell_from, const Iterator &cell_to, uint dofs_per_cell_from, uint dofs_per_cell_to)
Definition ldg.hh:300
Vector< NumberType > cell_residual
Definition ldg.hh:260
std::vector< types::global_dof_index > joint_dof_indices
Definition ldg.hh:261
std::vector< CopyDataFace_R > face_data
Definition ldg.hh:267
void reinit(const Iterator &cell, uint dofs_per_cell)
Definition ldg.hh:269
Vector< NumberType > cell_mass
Definition ldg.hh:265
std::vector< types::global_dof_index > local_dof_indices
Definition ldg.hh:266
Vector< NumberType > cell_residual
Definition ldg.hh:264
CopyDataFace_R & new_face_data(const FEInterfaceValues< dim > &fe_iv)
Definition ldg.hh:277
Class to hold data for each assembly thread, i.e. FEValues for cells, interfaces, as well as pre-allo...
Definition ldg.hh:154
array< uint, n_fe_subsystems > n_components
Definition ldg.hh:245
typename Discretization::NumberType NumberType
Definition ldg.hh:156
vector< Vector< NumberType > > solution_dot
Definition ldg.hh:254
static constexpr uint n_fe_subsystems
Definition ldg.hh:157
const auto & new_fe_values(const t_Iterator &t_cell)
Definition ldg.hh:218
static constexpr uint dim
Definition ldg.hh:155
array< Iterator, n_fe_subsystems > cell
Definition ldg.hh:246
array< unique_ptr< FEFaceValues< dim > >, n_fe_subsystems > fe_boundary_values
Definition ldg.hh:251
typename Triangulation< dim >::active_cell_iterator t_Iterator
Definition ldg.hh:159
ScratchData(const ScratchData< Discretization > &scratch_data)
Definition ldg.hh:191
typename DoFHandler< dim >::active_cell_iterator Iterator
Definition ldg.hh:158
array< unique_ptr< FEInterfaceValues< dim > >, n_fe_subsystems > fe_interface_values
Definition ldg.hh:250
array< array< vector< Vector< NumberType > >, n_fe_subsystems >, 2 > solution_interface
Definition ldg.hh:255
ScratchData(const Mapping< dim > &mapping, const vector< const DoFHandler< dim > * > &dofh, const Quadrature< dim > &quadrature, const Quadrature< dim - 1 > &quadrature_face, const UpdateFlags update_flags=update_values|update_gradients|update_quadrature_points|update_JxW_values, const UpdateFlags interface_update_flags=update_values|update_gradients|update_quadrature_points|update_JxW_values|update_normal_vectors)
Definition ldg.hh:161
const auto & new_fe_interface_values(const t_Iterator &t_cell, uint f, uint sf, const t_Iterator &t_ncell, uint nf, unsigned int nsf)
Definition ldg.hh:226
array< Iterator, n_fe_subsystems > ncell
Definition ldg.hh:247
array< unique_ptr< FEValues< dim > >, n_fe_subsystems > fe_values
Definition ldg.hh:249
array< vector< Vector< NumberType > >, n_fe_subsystems > solution
Definition ldg.hh:253
const auto & new_fe_boundary_values(const t_Iterator &t_cell, uint face_no)
Definition ldg.hh:236
A class to store a tuple with elements that can be accessed by name. The names are stored as FixedStr...
Definition tuples.hh:27