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>
39 using namespace dealii;
40 using std::array, std::vector, std::unique_ptr;
42 template <
typename Discretization_,
typename Model_>
44 typename Discretization_::SparseMatrixType, Discretization_::dim>
71 ComponentMask component_mask(
model.template differential_components<dim>());
72 return DoFTools::extract_dofs(
dof_handler, component_mask);
85 DoFTools::make_hanging_node_constraints(
dof_handler, constraints);
122 const FiniteElement<dim> &
fe;
138 if (unchanged)
return;
143 report_port.
info(
"FEM: Assembling {} cells on {} threads -- {}x{} workers/cells for a cheap cell loop, "
144 "{}x{} for an integral one.",
145 n_owned_cells, threads, cheap.queue_length, cheap.chunk_size, integral.queue_length,
146 integral.chunk_size);
152 if constexpr (Model::extract_uses_potential)
155 [&](
const auto &p,
const auto &values) {
return model.raw_potential_gradient(p, values); },
EoM_config,
162 std::pair<Point<dim>,
typename DoFHandler<dim>::cell_iterator>
164 [[maybe_unused]]
const VectorType &solution_global)
const
168 const auto point =
model.template extractor_point<dim, NumberType>(EoM_point, sample);
169 if (point == EoM_point)
return {EoM_point, EoM_cell_};
170 return {point, GridTools::find_active_cell_around_point(
dof_handler, point)};
172 return {EoM_point, EoM_cell_};
179 mutable typename DoFHandler<dim>::cell_iterator
EoM_cell;
208 using Iterator =
typename DoFHandler<dim>::active_cell_iterator;
209 using t_Iterator =
typename Triangulation<dim>::active_cell_iterator;
211 ScratchData(
const Mapping<dim> &mapping,
const vector<
const DoFHandler<dim> *> &dofh,
212 const dealii::Quadrature<dim> &quadrature,
const dealii::Quadrature<dim - 1> &quadrature_face,
213 const UpdateFlags update_flags = update_values | update_gradients | update_quadrature_points |
215 const UpdateFlags interface_update_flags = update_values | update_gradients |
216 update_quadrature_points | update_JxW_values |
217 update_normal_vectors)
220 StandardExceptions::ExcDimensionMismatch(dofh.size(),
n_fe_subsystems));
223 const auto &fe = dofh[i]->get_fe();
224 fe_values[i] = std::make_unique<FEValues<dim>>(mapping, fe, quadrature, update_flags);
226 std::make_unique<FEInterfaceValues<dim>>(mapping, fe, quadrature_face, interface_update_flags);
228 std::make_unique<FEFaceValues<dim>>(mapping, fe, quadrature_face, interface_update_flags);
235 const uint n_dofs_per_cell = fe.n_dofs_per_cell();
236 comp[i].resize(n_dofs_per_cell);
237 for (
uint d = 0; d < n_dofs_per_cell; ++d)
238 comp[i][d] = fe.system_to_component_index(d).first;
240 cell[i] = dofh[i]->begin_active();
241 ncell[i] = dofh[i]->begin_active();
249 const auto &old_fe = scratch_data.
fe_values[i];
253 fe_values[i] = unique_ptr<FEValues<dim>>(
new FEValues<dim>(
254 old_fe->get_mapping(), old_fe->get_fe(), old_fe->get_quadrature(), old_fe->get_update_flags()));
256 old_fe_i->get_mapping(), old_fe_i->get_fe(), old_fe_i->get_quadrature(), old_fe_i->get_update_flags()));
258 old_fe_b->get_mapping(), old_fe_b->get_fe(), old_fe_b->get_quadrature(), old_fe_b->get_update_flags()));
277 cell[i]->copy_from(*t_cell);
283 uint nf,
unsigned int nsf)
286 cell[i]->copy_from(*t_cell);
287 ncell[i]->copy_from(*t_ncell);
295 cell[i]->copy_from(*t_cell);
302 array<Iterator, n_fe_subsystems>
cell;
303 array<Iterator, n_fe_subsystems>
ncell;
327 template <
class Iterator>
void reinit(
const Iterator &cell,
uint dofs_per_cell)
341 copy_data_face.
cell_residual.reinit(fe_iv.n_current_interface_dofs());
342 copy_data_face.joint_dof_indices = fe_iv.get_interface_dof_indices();
343 return copy_data_face;
359 template <
class Iterator>
360 void reinit(
const Iterator &cell_from,
const Iterator &cell_to,
uint dofs_per_cell_from,
uint dofs_per_cell_to)
372 auto ©_data_face =
face_data.emplace_back();
373 copy_data_face.
cell_jacobian.reinit(fe_iv_to.n_current_interface_dofs(),
374 fe_iv_from.n_current_interface_dofs());
375 copy_data_face.joint_dof_indices_from = fe_iv_from.get_interface_dof_indices();
376 copy_data_face.joint_dof_indices_to = fe_iv_to.get_interface_dof_indices();
377 return copy_data_face;
396 template <
class Iterator>
void reinit(
const array<Iterator, n_fe_subsystems> &cell,
const uint n_extractors)
398 const uint n_dofs = cell[0]->get_fe().n_dofs_per_cell();
400 for (
uint i = 0; i < n_fe_subsystems; ++i) {
401 const uint from_n_dofs = cell[i]->get_fe().n_dofs_per_cell();
414 const uint n_extractors)
416 auto ©_data_face =
face_data.emplace_back();
417 for (
uint i = 0; i < n_fe_subsystems; ++i) {
418 copy_data_face.cell_jacobian[i].reinit(fe_iv[0]->n_current_interface_dofs(),
419 fe_iv[i]->n_current_interface_dofs());
420 copy_data_face.joint_dof_indices[i] = fe_iv[i]->get_interface_dof_indices();
422 if (n_extractors > 0)
424 return copy_data_face;
445 template <
typename Discretization_,
460 static constexpr uint stencil = Components::count_fe_subsystems();
463 template <
typename... T>
auto fe_conv(std::tuple<T &...> &t)
const
468 else if constexpr (
stencil == 3)
471 else if constexpr (
stencil == 4)
472 return named_tuple<std::tuple<T &...>,
StringSet<
"fe_functions",
"LDG1",
"LDG2",
"LDG3",
"extractors",
473 "variables",
"cell_width">>(t);
475 throw std::runtime_error(
"Only <= 3 LDG subsystems are supported.");
478 template <
typename... T>
auto fe_more_conv(std::tuple<T &...> &t)
const
482 StringSet<
"fe_functions",
"LDG1",
"fe_derivatives",
"fe_hessians",
"extractors",
483 "variables",
"potential",
"potential_gradient",
"potential_hessian">>(t);
484 else if constexpr (
stencil == 3)
486 StringSet<
"fe_functions",
"LDG1",
"LDG2",
"fe_derivatives",
"fe_hessians",
"extractors",
487 "variables",
"potential",
"potential_gradient",
"potential_hessian">>(t);
488 else if constexpr (
stencil == 4)
489 return named_tuple<std::tuple<T &...>,
StringSet<
"fe_functions",
"LDG1",
"LDG2",
"LDG3",
"fe_derivatives",
490 "fe_hessians",
"extractors",
"variables",
"potential",
491 "potential_gradient",
"potential_hessian">>(t);
493 throw std::runtime_error(
"Only <= 3 LDG subsystems are supported.");
496 template <
typename... T>
auto ref_conv(std::tuple<T &...> &t)
const
500 else if constexpr (
stencil == 3)
502 else if constexpr (
stencil == 4)
505 throw std::runtime_error(
"Only <= 3 LDG subsystems are supported.");
515 static_assert(Components::count_fe_subsystems() > 1,
"LDG must have a submodel with index 1.");
544 readouts(data_out, solution, variables);
546 const auto fe_function_names = Components::FEFunction_Descriptor::get_names_vector();
547 std::vector<std::string> fe_function_names_residual;
548 for (
const auto &name : fe_function_names)
549 fe_function_names_residual.push_back(name +
"_residual");
550 std::vector<std::string> fe_function_names_dot;
551 for (
const auto &name : fe_function_names)
552 fe_function_names_dot.push_back(name +
"_dot");
554 auto fe_out = data_out.
fields();
556 if (dt_solution.size() > 0) fe_out.attach(
dof_handler, dt_solution, fe_function_names_dot);
558 for (
uint k = 1; k < Components::count_fe_subsystems(); ++k) {
566 const auto init_mass = [&](
uint i) {
568 auto dofs_per_component = DoFTools::count_dofs_per_fe_component(*(
dof_handler_list[i]));
571 auto n_fe = dofs_per_component.size();
572 for (
uint j = 1; j < n_fe; ++j)
573 if (dofs_per_component[j] != dofs_per_component[0])
574 throw std::runtime_error(
"For LDG the FE basis of all systems must be equal!");
576 BlockDynamicSparsityPattern dsp(n_fe, n_fe);
577 for (
uint i = 0; i < n_fe; ++i)
578 for (
uint j = 0; j < n_fe; ++j)
579 dsp.block(i, j).reinit(dofs_per_component[0], dofs_per_component[0]);
589 (Function<dim, NumberType> *)
nullptr,
discretization.get_constraints(0));
599 const auto init_jacobian = [&](
uint i) {
604 for (
uint k = 1; k < Components::count_fe_subsystems(); ++k)
612 auto init_ldg = [&](
uint i) {
627 vector<std::thread> init_threads;
628 for (
uint i = 0; i < Components::count_fe_subsystems(); ++i)
629 init_threads.emplace_back(std::thread(init_mass, i));
630 for (
uint i = 0; i < Components::count_fe_subsystems(); ++i)
631 init_threads.emplace_back(std::thread(init_jacobian, i));
632 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i)
633 init_threads.emplace_back(std::thread(init_ldg, i));
634 for (
auto &t : init_threads)
643 for (
uint k = 1; k < Components::count_fe_subsystems(); ++k)
649 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
653 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
654 const auto &fe_v = scratch_data.new_fe_values(t_cell);
655 copy_data.cell_index = t_cell->active_cell_index();
658 const auto &JxW = fe_v[0]->get_JxW_values();
659 const auto &q_points = fe_v[0]->get_quadrature_points();
660 const auto &q_indices = fe_v[0]->quadrature_point_indices();
662 auto &solution = scratch_data.solution;
663 fe_v[0]->get_function_values(solution_global, solution[0]);
664 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i)
665 fe_v[i]->get_function_values(
sol_vector[i], solution[i]);
667 double local_indicator = 0.;
668 for (
const auto &q_index : q_indices) {
669 const auto &x_q = q_points[q_index];
673 copy_data.value += JxW[q_index] * local_indicator;
676 const auto face_worker = [&](
const Iterator &t_cell,
const uint &f,
const uint &sf,
const Iterator &t_ncell,
677 const uint &nf,
const unsigned int &nsf, Scratch &scratch_data,
678 CopyData ©_data) {
679 const auto &fe_iv = scratch_data.new_fe_interface_values(t_cell, f, sf, t_ncell, nf, nsf);
681 auto ©_data_face = copy_data.face_data.emplace_back();
682 copy_data_face.cell_indices[0] = t_cell->active_cell_index();
683 copy_data_face.cell_indices[1] = t_ncell->active_cell_index();
684 copy_data_face.values[0] = 0;
685 copy_data_face.values[1] = 0;
687 const auto &JxW = fe_iv[0]->get_JxW_values();
688 const auto &q_points = fe_iv[0]->get_quadrature_points();
689 const auto &q_indices = fe_iv[0]->quadrature_point_indices();
690 const std::vector<Tensor<1, dim>> &normals = fe_iv[0]->get_normal_vectors();
691 array<double, 2> local_indicator{};
693 auto &solution = scratch_data.solution_interface;
694 fe_iv[0]->get_fe_face_values(0).get_function_values(solution_global, solution[0][0]);
695 fe_iv[0]->get_fe_face_values(1).get_function_values(solution_global, solution[1][0]);
696 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i) {
697 fe_iv[i]->get_fe_face_values(0).get_function_values(
sol_vector[i], solution[0][i]);
698 fe_iv[i]->get_fe_face_values(1).get_function_values(
sol_vector[i], solution[1][i]);
701 for (
const auto &q_index : q_indices) {
702 const auto &x_q = q_points[q_index];
707 copy_data_face.values[0] += JxW[q_index] * local_indicator[0] * (1. + t_cell->at_boundary());
708 copy_data_face.values[1] += JxW[q_index] * local_indicator[1] * (1. + t_ncell->at_boundary());
711 const auto copier = [&](
const CopyData &c) {
712 for (
auto &cdf : c.face_data)
713 for (
uint j = 0; j < 2; ++j)
714 indicator[cdf.cell_indices[j]] += cdf.values[j];
715 indicator[c.cell_index] += c.value;
718 const UpdateFlags update_flags = update_values | update_quadrature_points | update_JxW_values;
721 MeshWorker::AssembleFlags assemble_flags =
722 MeshWorker::assemble_own_cells | MeshWorker::assemble_own_interior_faces_once;
727 assemble_flags,
nullptr, face_worker, schedule.queue_length, schedule.chunk_size);
746 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
751 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
752 const auto &fe_v = scratch_data.new_fe_values(t_cell);
753 const uint n_dofs = fe_v[0]->get_fe().n_dofs_per_cell();
754 copy_data.reinit(scratch_data.cell[0], n_dofs);
756 const auto &JxW = fe_v[0]->get_JxW_values();
757 const auto &q_points = fe_v[0]->get_quadrature_points();
758 const auto &q_indices = fe_v[0]->quadrature_point_indices();
760 auto &solution = scratch_data.solution;
761 auto &solution_dot = scratch_data.solution_dot;
762 fe_v[0]->get_function_values(solution_global, solution[0]);
763 fe_v[0]->get_function_values(solution_global_dot, solution_dot);
765 const auto &comp_0 = scratch_data.comp[0];
767 for (
const auto &q_index : q_indices) {
768 const auto &x_q = q_points[q_index];
769 model.mass(
mass, x_q, solution[0][q_index], solution_dot[q_index]);
771 for (
uint i = 0; i < n_dofs; ++i) {
772 const auto component_i = comp_0[i];
773 copy_data.cell_residual(i) += weight * JxW[q_index] *
774 fe_v[0]->shape_value_component(i, q_index, component_i) *
779 const auto copier = [&](
const CopyData &c) {
780 constraints.distribute_local_to_global(c.cell_residual, c.local_dof_indices,
residual);
783 const UpdateFlags update_flags = update_values | update_quadrature_points | update_JxW_values;
784 const MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells;
790 assemble_flags,
nullptr,
nullptr, schedule.queue_length, schedule.chunk_size);
804 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
810 std::array<
NumberType, Components::count_extractors()> __extracted_data{{}};
811 if constexpr (Components::count_extractors() > 0)
812 this->
extract(__extracted_data, solution_global, variables,
true,
false,
true);
813 const auto &extracted_data = __extracted_data;
815 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
817 const auto &fe_v = scratch_data.new_fe_values(t_cell);
818 const uint n_dofs = fe_v[0]->get_fe().n_dofs_per_cell();
819 copy_data.reinit(scratch_data.cell[0], n_dofs);
821 const auto &JxW = fe_v[0]->get_JxW_values();
822 const auto &q_points = fe_v[0]->get_quadrature_points();
823 const auto &q_indices = fe_v[0]->quadrature_point_indices();
825 auto &solution = scratch_data.solution;
826 auto &solution_dot = scratch_data.solution_dot;
827 fe_v[0]->get_function_values(solution_global, solution[0]);
828 fe_v[0]->get_function_values(solution_global_dot, solution_dot);
829 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i)
830 fe_v[i]->get_function_values(
sol_vector[i], solution[i]);
832 const auto &comp_0 = scratch_data.comp[0];
834 array<Tensor<1, dim, NumberType>, Components::count_fe_functions(0)> flux{};
835 array<
NumberType, Components::count_fe_functions(0)> source{};
836 for (
const auto &q_index : q_indices) {
837 const auto &x_q = q_points[q_index];
839 std::tuple_cat(
local_sol_q(solution, q_index), std::tie(extracted_data, variables, cell_width));
840 model.mass(
mass, x_q, solution[0][q_index], solution_dot[q_index]);
844 for (
uint i = 0; i < n_dofs; ++i) {
845 const auto component_i = comp_0[i];
846 copy_data.cell_residual(i) += weight * JxW[q_index] *
847 (-scalar_product(fe_v[0]->shape_grad_component(i, q_index, component_i),
849 + fe_v[0]->shape_value_component(i, q_index, component_i) *
850 (source[component_i]));
851 copy_data.cell_mass(i) += weight_mass * JxW[q_index] *
852 fe_v[0]->shape_value_component(i, q_index, component_i) *
857 const auto boundary_worker = [&](
const Iterator &t_cell,
const uint &face_no, Scratch &scratch_data,
858 CopyData ©_data) {
860 const auto &fe_fv = scratch_data.new_fe_boundary_values(t_cell, face_no);
861 const uint n_dofs = fe_fv[0]->get_fe().n_dofs_per_cell();
863 const auto &JxW = fe_fv[0]->get_JxW_values();
864 const auto &q_points = fe_fv[0]->get_quadrature_points();
865 const auto &q_indices = fe_fv[0]->quadrature_point_indices();
866 const auto &normals = fe_fv[0]->get_normal_vectors();
868 auto &solution = scratch_data.solution;
869 fe_fv[0]->get_function_values(solution_global, solution[0]);
870 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i)
871 fe_fv[i]->get_function_values(
sol_vector[i], solution[i]);
873 const auto &comp_0 = scratch_data.comp[0];
874 array<Tensor<1, dim, NumberType>, Components::count_fe_functions(0)> numflux{};
875 for (
const auto &q_index : q_indices) {
876 const auto &x_q = q_points[q_index];
878 std::tuple_cat(
local_sol_q(solution, q_index), std::tie(extracted_data, variables, cell_width));
879 model.boundary_numflux(numflux, normals[q_index], x_q,
fe_conv(sol_q));
881 for (
uint i = 0; i < n_dofs; ++i) {
882 const auto component_i = comp_0[i];
883 copy_data.cell_residual(i) +=
884 weight * JxW[q_index] *
885 (fe_fv[0]->shape_value_component(i, q_index, component_i) *
886 scalar_product(numflux[component_i], normals[q_index]));
890 const auto face_worker = [&](
const Iterator &t_cell,
const uint &f,
const uint &sf,
const Iterator &t_ncell,
891 const uint &nf,
const unsigned int &nsf, Scratch &scratch_data,
892 CopyData ©_data) {
895 const auto &fe_iv = scratch_data.new_fe_interface_values(t_cell, f, sf, t_ncell, nf, nsf);
896 const uint n_dofs = fe_iv[0]->n_current_interface_dofs();
897 auto ©_data_face = copy_data.new_face_data(*(fe_iv[0]));
899 const auto &JxW = fe_iv[0]->get_JxW_values();
900 const auto &q_points = fe_iv[0]->get_quadrature_points();
901 const auto &q_indices = fe_iv[0]->quadrature_point_indices();
902 const auto &normals = fe_iv[0]->get_normal_vectors();
904 auto &solution = scratch_data.solution_interface;
905 fe_iv[0]->get_fe_face_values(0).get_function_values(solution_global, solution[0][0]);
906 fe_iv[0]->get_fe_face_values(1).get_function_values(solution_global, solution[1][0]);
907 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i) {
908 fe_iv[i]->get_fe_face_values(0).get_function_values(
sol_vector[i], solution[0][i]);
909 fe_iv[i]->get_fe_face_values(1).get_function_values(
sol_vector[i], solution[1][i]);
913 std::vector<uint> iface_comp_0(n_dofs);
914 for (
uint i = 0; i < n_dofs; ++i) {
915 const auto &cd_i = fe_iv[0]->interface_dof_to_dof_indices(i);
916 iface_comp_0[i] = cd_i[0] == numbers::invalid_unsigned_int
917 ? fe_iv[0]->get_fe().system_to_component_index(cd_i[1]).first
918 : fe_iv[0]->get_fe().system_to_component_index(cd_i[0]).first;
921 array<Tensor<1, dim, NumberType>, Components::count_fe_functions(0)> numflux{};
922 for (
const auto &q_index : q_indices) {
923 const auto &x_q = q_points[q_index];
925 std::tuple_cat(
local_sol_q(solution[0], q_index), std::tie(extracted_data, variables, cell_width));
927 std::tuple_cat(
local_sol_q(solution[1], q_index), std::tie(extracted_data, variables, ncell_width));
930 for (
uint i = 0; i < n_dofs; ++i) {
931 const auto component_i = iface_comp_0[i];
932 copy_data_face.cell_residual(i) +=
933 weight * JxW[q_index] *
934 (fe_iv[0]->jump_in_shape_values(i, q_index, component_i) *
935 scalar_product(numflux[component_i],
940 const auto copier = [&](
const CopyData &c) {
941 constraints.distribute_local_to_global(c.cell_residual, c.local_dof_indices,
residual);
942 constraints.distribute_local_to_global(c.cell_mass, c.local_dof_indices,
residual);
943 for (
auto &cdf : c.face_data)
944 constraints.distribute_local_to_global(cdf.cell_residual, cdf.joint_dof_indices,
residual);
947 const UpdateFlags update_flags =
948 update_values | update_gradients | update_quadrature_points | update_JxW_values;
949 const MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells |
950 MeshWorker::assemble_boundary_faces |
951 MeshWorker::assemble_own_interior_faces_once;
960 assemble_flags, boundary_worker, face_worker, schedule.queue_length, schedule.chunk_size);
969 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
974 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
975 const auto &fe_v = scratch_data.new_fe_values(t_cell);
976 const uint to_n_dofs = fe_v[0]->get_fe().n_dofs_per_cell();
977 copy_data.reinit(scratch_data.cell, Components::count_extractors());
979 const auto &JxW = fe_v[0]->get_JxW_values();
980 const auto &q_points = fe_v[0]->get_quadrature_points();
981 const auto &q_indices = fe_v[0]->quadrature_point_indices();
983 auto &solution = scratch_data.solution;
984 auto &solution_dot = scratch_data.solution_dot;
986 fe_v[0]->get_function_values(solution_global, solution[0]);
987 fe_v[0]->get_function_values(solution_global_dot, solution_dot);
989 const auto &comp_0 = scratch_data.comp[0];
993 const uint from_n_dofs = fe_v[0]->get_fe().n_dofs_per_cell();
994 for (
const auto &q_index : q_indices) {
995 const auto &x_q = q_points[q_index];
1000 for (
uint i = 0; i < to_n_dofs; ++i) {
1001 const auto component_i = comp_0[i];
1002 for (
uint j = 0; j < from_n_dofs; ++j) {
1003 const auto component_j = comp_0[j];
1004 copy_data.cell_jacobian[0](i, j) +=
1005 JxW[q_index] * fe_v[0]->shape_value_component(j, q_index, component_j) *
1006 fe_v[0]->shape_value_component(i, q_index, component_i) *
1007 (alpha * j_mass_dot(component_i, component_j) +
1008 beta * j_mass(component_i, component_j));
1013 const auto copier = [&](
const CopyData &c) {
1014 constraints.distribute_local_to_global(c.cell_jacobian[0], c.local_dof_indices[0],
jacobian);
1017 const UpdateFlags update_flags = update_values | update_quadrature_points | update_JxW_values;
1018 const MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells;
1024 assemble_flags,
nullptr,
nullptr, schedule.queue_length, schedule.chunk_size);
1039 throw std::runtime_error(
"Please call jacobian_mass instead of jacobian for weight == 0).");
1040 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
1046 std::array<
NumberType, Components::count_extractors()> __extracted_data{{}};
1047 if constexpr (Components::count_extractors() > 0) {
1048 this->
extract(__extracted_data, solution_global, variables,
true,
true,
true);
1052 const auto &extracted_data = __extracted_data;
1054 bool exception =
false;
1056 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
1058 const auto &fe_v = scratch_data.new_fe_values(t_cell);
1059 const uint to_n_dofs = fe_v[0]->get_fe().n_dofs_per_cell();
1060 copy_data.reinit(scratch_data.cell, Components::count_extractors());
1062 const auto &JxW = fe_v[0]->get_JxW_values();
1063 const auto &q_points = fe_v[0]->get_quadrature_points();
1064 const auto &q_indices = fe_v[0]->quadrature_point_indices();
1066 auto &solution = scratch_data.solution;
1067 auto &solution_dot = scratch_data.solution_dot;
1069 fe_v[0]->get_function_values(solution_global, solution[0]);
1070 fe_v[0]->get_function_values(solution_global_dot, solution_dot);
1071 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i)
1072 fe_v[i]->get_function_values(
sol_vector[i], solution[i]);
1080 SimpleMatrix<
NumberType, Components::count_fe_functions(), Components::count_extractors()> j_extr_source;
1084 const uint from_n_dofs = fe_v[k]->get_fe().n_dofs_per_cell();
1085 for (
const auto &q_index : q_indices) {
1086 const auto &x_q = q_points[q_index];
1088 std::tuple_cat(
local_sol_q(solution, q_index), std::tie(extracted_data, variables, cell_width));
1090 if constexpr (k == 0) {
1092 this->
model.template
jacobian_mass<1>(j_mass_dot, x_q, solution[0][q_index], solution_dot[q_index]);
1093 if constexpr (Components::count_extractors() > 0) {
1094 this->
model.template jacobian_flux_source_extr<stencil>(j_extr_flux, j_extr_source, x_q,
1098 model.template jacobian_flux_source<k, 0>(std::get<k>(j_flux), std::get<k>(j_source), x_q,
1101 if (!std::get<k>(j_flux).is_finite() || !std::get<k>(j_source).is_finite()) exception =
true;
1103 const auto &comp_0 = scratch_data.comp[0];
1104 const auto &comp_k = scratch_data.comp[k];
1105 for (
uint i = 0; i < to_n_dofs; ++i) {
1106 const auto component_i = comp_0[i];
1107 for (
uint j = 0; j < from_n_dofs; ++j) {
1108 const auto component_j = comp_k[j];
1110 copy_data.cell_jacobian[k](i, j) +=
1112 fe_v[k]->shape_value_component(j, q_index, component_j) *
1113 (-scalar_product(fe_v[0]->shape_grad_component(i, q_index, component_i),
1114 std::get<k>(j_flux)(component_i, component_j))
1115 + fe_v[0]->shape_value_component(i, q_index, component_i) *
1116 std::get<k>(j_source)(component_i, component_j));
1117 if constexpr (k == 0) {
1118 copy_data.cell_mass_jacobian(i, j) +=
1120 fe_v[0]->shape_value_component(j, q_index, component_j) *
1121 fe_v[0]->shape_value_component(i, q_index, component_i) *
1122 (alpha / weight * j_mass_dot(component_i, component_j) +
1123 beta / weight * j_mass(component_i, component_j));
1128 if constexpr (k == 0)
1129 if constexpr (Components::count_extractors() > 0)
1130 for (
uint e = 0; e < Components::count_extractors(); ++e)
1131 copy_data.extractor_cell_jacobian(i, e) +=
1132 weight * JxW[q_index] *
1133 (-scalar_product(fe_v[0]->shape_grad_component(i, q_index, component_i),
1134 j_extr_flux(component_i, e))
1135 + fe_v[0]->shape_value_component(i, q_index, component_i) *
1136 j_extr_source(component_i, e));
1141 const auto boundary_worker = [&](
const Iterator &t_cell,
const uint &face_no, Scratch &scratch_data,
1142 CopyData ©_data) {
1144 const auto &fe_fv = scratch_data.new_fe_boundary_values(t_cell, face_no);
1145 const uint to_n_dofs = fe_fv[0]->get_fe().n_dofs_per_cell();
1147 const auto &JxW = fe_fv[0]->get_JxW_values();
1148 const auto &q_points = fe_fv[0]->get_quadrature_points();
1149 const auto &q_indices = fe_fv[0]->quadrature_point_indices();
1150 const auto &normals = fe_fv[0]->get_normal_vectors();
1151 auto &solution = scratch_data.solution;
1153 fe_fv[0]->get_function_values(solution_global, solution[0]);
1154 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i)
1155 fe_fv[i]->get_function_values(
sol_vector[i], solution[i]);
1160 for (
const auto &q_index : q_indices) {
1161 const auto &x_q = q_points[q_index];
1163 std::tuple_cat(
local_sol_q(solution, q_index), std::tie(extracted_data, variables, cell_width));
1165 const uint from_n_dofs = fe_fv[k]->get_fe().n_dofs_per_cell();
1167 model.template jacobian_boundary_numflux<k, 0>(std::get<k>(j_boundary_numflux), normals[q_index], x_q,
1170 if (!std::get<k>(j_boundary_numflux).is_finite()) exception =
true;
1172 const auto &comp_0 = scratch_data.comp[0];
1173 const auto &comp_k = scratch_data.comp[k];
1174 for (
uint i = 0; i < to_n_dofs; ++i) {
1175 const auto component_i = comp_0[i];
1176 for (
uint j = 0; j < from_n_dofs; ++j) {
1177 const auto component_j = comp_k[j];
1179 copy_data.cell_jacobian[k](i, j) +=
1181 fe_fv[k]->shape_value_component(j, q_index, component_j) *
1182 (fe_fv[0]->shape_value_component(i, q_index, component_i) *
1183 scalar_product(std::get<k>(j_boundary_numflux)(component_i, component_j),
1190 const auto face_worker = [&](
const Iterator &t_cell,
const uint &f,
const uint &sf,
const Iterator &t_ncell,
1191 const uint &nf,
const unsigned int &nsf, Scratch &scratch_data,
1192 CopyData ©_data) {
1195 const auto &fe_iv = scratch_data.new_fe_interface_values(t_cell, f, sf, t_ncell, nf, nsf);
1196 const uint to_n_dofs = fe_iv[0]->n_current_interface_dofs();
1197 auto ©_data_face = copy_data.new_face_data(fe_iv, Components::count_extractors());
1199 const auto &JxW = fe_iv[0]->get_JxW_values();
1200 const auto &q_points = fe_iv[0]->get_quadrature_points();
1201 const auto &q_indices = fe_iv[0]->quadrature_point_indices();
1202 const auto &normals = fe_iv[0]->get_normal_vectors();
1204 auto &solution = scratch_data.solution_interface;
1205 fe_iv[0]->get_fe_face_values(0).get_function_values(solution_global, solution[0][0]);
1206 fe_iv[0]->get_fe_face_values(1).get_function_values(solution_global, solution[1][0]);
1207 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i) {
1208 fe_iv[i]->get_fe_face_values(0).get_function_values(
sol_vector[i], solution[0][i]);
1209 fe_iv[i]->get_fe_face_values(1).get_function_values(
sol_vector[i], solution[1][i]);
1216 const uint from_n_dofs = fe_iv[k]->n_current_interface_dofs();
1219 std::vector<uint> iface_comp_0(to_n_dofs);
1220 std::vector<uint> iface_face_0(to_n_dofs);
1221 for (
uint i = 0; i < to_n_dofs; ++i) {
1222 const auto &cd_i = fe_iv[0]->interface_dof_to_dof_indices(i);
1223 iface_face_0[i] = cd_i[0] == numbers::invalid_unsigned_int ? 1 : 0;
1224 iface_comp_0[i] = fe_iv[0]->get_fe().system_to_component_index(cd_i[iface_face_0[i]]).first;
1226 std::vector<uint> iface_comp_k(from_n_dofs);
1227 std::vector<uint> iface_face_k(from_n_dofs);
1228 std::vector<uint> iface_dof_k(from_n_dofs);
1229 for (
uint j = 0; j < from_n_dofs; ++j) {
1230 const auto &cd_j = fe_iv[k]->interface_dof_to_dof_indices(j);
1231 iface_face_k[j] = cd_j[0] == numbers::invalid_unsigned_int ? 1 : 0;
1232 iface_dof_k[j] = cd_j[iface_face_k[j]];
1233 iface_comp_k[j] = fe_iv[k]->get_fe().system_to_component_index(iface_dof_k[j]).first;
1236 for (
const auto &q_index : q_indices) {
1237 const auto &x_q = q_points[q_index];
1239 std::tuple_cat(
local_sol_q(solution[0], q_index), std::tie(extracted_data, variables, cell_width));
1241 std::tuple_cat(
local_sol_q(solution[1], q_index), std::tie(extracted_data, variables, ncell_width));
1243 model.template jacobian_numflux<k, 0>(std::get<k>(j_numflux), normals[q_index], x_q,
fe_conv(sol_q_s),
1246 if (!std::get<k>(j_numflux)[0].is_finite() || !std::get<k>(j_numflux)[1].is_finite()) exception =
true;
1248 for (
uint i = 0; i < to_n_dofs; ++i) {
1249 const auto component_i = iface_comp_0[i];
1250 for (
uint j = 0; j < from_n_dofs; ++j) {
1251 const auto component_j = iface_comp_k[j];
1252 const uint face_no_j = iface_face_k[j];
1254 copy_data_face.cell_jacobian[k](i, j) +=
1256 fe_iv[k]->get_fe_face_values(face_no_j).shape_value_component(
1257 iface_dof_k[j], q_index, component_j) *
1258 (fe_iv[0]->jump_in_shape_values(i, q_index, component_i) *
1259 scalar_product(std::get<k>(j_numflux)[face_no_j](component_i, component_j),
1266 const auto copier = [&](
const CopyData &c) {
1268 constraints.distribute_local_to_global(c.cell_jacobian[0], c.local_dof_indices[0],
jacobian);
1269 constraints.distribute_local_to_global(c.cell_mass_jacobian, c.local_dof_indices[0],
jacobian);
1270 for (
auto &cdf : c.face_data) {
1271 constraints.distribute_local_to_global(cdf.cell_jacobian[0], cdf.joint_dof_indices[0],
jacobian);
1272 if constexpr (Components::count_extractors() > 0) {
1273 FullMatrix<NumberType> extractor_dependence(cdf.joint_dof_indices[0].size(),
1276 constraints.distribute_local_to_global(extractor_dependence, cdf.joint_dof_indices[0],
1280 if constexpr (Components::count_extractors() > 0) {
1281 FullMatrix<NumberType> extractor_dependence(c.local_dof_indices[0].size(),
extractor_dof_indices.size());
1283 constraints.distribute_local_to_global(extractor_dependence, c.local_dof_indices[0],
1289 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i) {
1291 j_ug[i].add(c.local_dof_indices[0], c.local_dof_indices[i], c.cell_jacobian[i]);
1293 for (
auto &cdf : c.face_data) {
1294 for (
uint i = 1; i < Components::count_fe_subsystems(); ++i) {
1296 j_ug[i].add(cdf.joint_dof_indices[0], cdf.joint_dof_indices[i], cdf.cell_jacobian[i]);
1304 const UpdateFlags update_flags =
1305 update_values | update_gradients | update_quadrature_points | update_JxW_values;
1306 const MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells |
1307 MeshWorker::assemble_boundary_faces |
1308 MeshWorker::assemble_own_interior_faces_once;
1323 assemble_flags, boundary_worker, face_worker, schedule.queue_length, schedule.chunk_size);
1325 if (exception)
throw std::runtime_error(
"Infinity encountered in jacobian construction");
1328 tbb::blocked_range<uint>(1, Components::count_fe_subsystems()), [&](tbb::blocked_range<uint> rk) {
1329 for (
uint k = rk.begin(); k < rk.end(); ++k) {
1333 tbb::blocked_range<uint>(0, Components::count_fe_functions(0)), [&](tbb::blocked_range<uint> r) {
1334 for (
uint q = r.begin(); q < r.end(); ++q)
1335 for (
const auto &c :
model.get_components().ldg_couplings(k, 0))
1337 Vector<NumberType>(),
false);
1345 tbb::blocked_range<uint>(0, Components::count_fe_functions(0)), [&](tbb::blocked_range<uint> rc1) {
1346 tbb::parallel_for(tbb::blocked_range<uint>(0, Components::count_fe_functions(0)),
1347 [&](tbb::blocked_range<uint> rc2) {
1348 for (
uint c1 = rc1.begin(); c1 < rc1.end(); ++c1)
1349 for (
uint c2 = rc2.begin(); c2 < rc2.end(); ++c2) {
1350 for (
uint k = 1; k < Components::count_fe_subsystems(); ++k)
1411 mutable array<BlockVector<NumberType>, Components::count_fe_subsystems()>
sol_vector;
1412 mutable array<BlockVector<NumberType>, Components::count_fe_subsystems()>
sol_vector_tmp;
1421 array<BlockSparseMatrix<NumberType>, Components::count_fe_subsystems()>
jacobian_tmp;
1425 array<BlockSparseMatrix<NumberType>, Components::count_fe_subsystems()>
j_ug;
1426 mutable array<BlockSparseMatrix<NumberType>, Components::count_fe_subsystems()>
j_gu;
1427 mutable array<BlockSparseMatrix<NumberType>, Components::count_fe_subsystems()>
j_wg;
1428 mutable array<BlockSparseMatrix<NumberType>, Components::count_fe_subsystems()>
j_wg_tmp;
1443 if (!
model.get_components().jacobians_constant(k, k - 1)) {
1458 static_assert(k > 0);
1460 if constexpr (k == 1)
1465 for (
const auto &c :
model.get_components().ldg_couplings(k, 0))
1466 for (
const auto &b :
model.get_components().ldg_couplings(k, k - 1))
1470 .mmult(
j_gu[k].block(c[0], c[1]),
j_gu[k - 1].block(b[1], c[1]), Vector<NumberType>(),
false);
1483 template <
int from,
int to,
typename VectorType,
typename VectorTypeldg>
1485 VectorTypeldg &ldg_vector_tmp)
const
1487 static_assert(to - from == 1,
"can only build LDG from last level!");
1488 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
1493 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
1494 const auto &fe_v = scratch_data.new_fe_values(t_cell);
1495 const uint to_n_dofs = fe_v[to]->get_fe().n_dofs_per_cell();
1496 copy_data.reinit(scratch_data.cell[to], to_n_dofs);
1498 const auto &JxW = fe_v[to]->get_JxW_values();
1499 const auto &q_points = fe_v[to]->get_quadrature_points();
1500 const auto &q_indices = fe_v[to]->quadrature_point_indices();
1501 auto &solution = scratch_data.solution;
1503 fe_v[from]->get_function_values(solution_global, solution[from]);
1505 array<Tensor<1, dim, NumberType>, Components::count_fe_functions(to)> flux{};
1506 array<
NumberType, Components::count_fe_functions(to)> source{};
1507 for (
const auto &q_index : q_indices) {
1508 const auto &x_q = q_points[q_index];
1509 model.template ldg_flux<to>(flux, x_q, solution[from][q_index]);
1510 model.template ldg_source<to>(source, x_q, solution[from][q_index]);
1512 for (
uint i = 0; i < to_n_dofs; ++i) {
1513 const auto component_i = fe_v[to]->get_fe().system_to_component_index(i).first;
1514 copy_data.cell_residual(i) += JxW[q_index] *
1515 (-scalar_product(fe_v[to]->shape_grad_component(i, q_index, component_i),
1517 + fe_v[to]->shape_value_component(i, q_index, component_i) *
1518 source[component_i]);
1522 const auto boundary_worker = [&](
const Iterator &t_cell,
const uint &face_no, Scratch &scratch_data,
1523 CopyData ©_data) {
1524 const auto &fe_fv = scratch_data.new_fe_boundary_values(t_cell, face_no);
1525 const uint to_n_dofs = fe_fv[to]->get_fe().n_dofs_per_cell();
1527 const auto &JxW = fe_fv[to]->get_JxW_values();
1528 const auto &q_points = fe_fv[to]->get_quadrature_points();
1529 const auto &q_indices = fe_fv[to]->quadrature_point_indices();
1530 const std::vector<Tensor<1, dim>> &normals = fe_fv[from]->get_normal_vectors();
1531 auto &solution = scratch_data.solution;
1533 fe_fv[from]->get_function_values(solution_global, solution[from]);
1535 array<Tensor<1, dim, NumberType>, Components::count_fe_functions(to)> numflux{};
1536 for (
const auto &q_index : q_indices) {
1537 const auto &x_q = q_points[q_index];
1538 model.template ldg_boundary_numflux<to>(numflux, normals[q_index], x_q, solution[from][q_index]);
1540 for (
uint i = 0; i < to_n_dofs; ++i) {
1541 const auto component_i = fe_fv[to]->get_fe().system_to_component_index(i).first;
1542 copy_data.cell_residual(i) +=
1544 (fe_fv[to]->shape_value_component(i, q_index, component_i) *
1545 scalar_product(numflux[component_i], normals[q_index]));
1549 const auto face_worker = [&](
const Iterator &t_cell,
const uint &f,
const uint &sf,
const Iterator &t_ncell,
1550 const uint &nf,
const unsigned int &nsf, Scratch &scratch_data,
1551 CopyData ©_data) {
1552 const auto &fe_iv = scratch_data.new_fe_interface_values(t_cell, f, sf, t_ncell, nf, nsf);
1553 const uint to_n_dofs = fe_iv[to]->n_current_interface_dofs();
1554 auto ©_data_face = copy_data.new_face_data(*(fe_iv[to]));
1556 const auto &JxW = fe_iv[to]->get_JxW_values();
1557 const auto &q_points = fe_iv[to]->get_quadrature_points();
1558 const auto &q_indices = fe_iv[to]->quadrature_point_indices();
1560 const std::vector<Tensor<1, dim>> &normals = fe_iv[to]->get_normal_vectors();
1561 auto &solution = scratch_data.solution_interface;
1563 fe_iv[from]->get_fe_face_values(0).get_function_values(solution_global, solution[0][from]);
1564 fe_iv[from]->get_fe_face_values(1).get_function_values(solution_global, solution[1][from]);
1566 array<Tensor<1, dim, NumberType>, Components::count_fe_functions(to)> numflux{};
1567 for (
const auto &q_index : q_indices) {
1568 const auto &x_q = q_points[q_index];
1569 model.template ldg_numflux<to>(numflux, normals[q_index], x_q, solution[0][from][q_index],
1570 solution[1][from][q_index]);
1572 for (
uint i = 0; i < to_n_dofs; ++i) {
1573 const auto &cd_i = fe_iv[to]->interface_dof_to_dof_indices(i);
1574 const auto component_i = cd_i[0] == numbers::invalid_unsigned_int
1575 ? fe_iv[to]->get_fe().system_to_component_index(cd_i[1]).first
1576 : fe_iv[to]->get_fe().system_to_component_index(cd_i[0]).first;
1577 copy_data_face.cell_residual(i) +=
1579 (fe_iv[to]->jump_in_shape_values(i, q_index, component_i) *
1580 scalar_product(numflux[component_i],
1585 const auto copier = [&](
const CopyData &c) {
1586 constraints.distribute_local_to_global(c.cell_residual, c.local_dof_indices, ldg_vector_tmp);
1587 for (
auto &cdf : c.face_data)
1588 constraints.distribute_local_to_global(cdf.cell_residual, cdf.joint_dof_indices, ldg_vector_tmp);
1591 const MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells |
1592 MeshWorker::assemble_boundary_faces |
1593 MeshWorker::assemble_own_interior_faces_once;
1600 assemble_flags, boundary_worker, face_worker, schedule.queue_length, schedule.chunk_size);
1602 for (
uint i = 0; i < Components::count_fe_functions(to); ++i)
1615 template <
int from,
int to,
typename VectorType>
1617 BlockSparseMatrix<NumberType> &ldg_jacobian_tmp)
const
1619 static_assert(to - from == 1,
"can only build LDG from last level!");
1620 using Iterator =
typename Triangulation<dim>::active_cell_iterator;
1624 const auto cell_worker = [&](
const Iterator &t_cell, Scratch &scratch_data, CopyData ©_data) {
1625 const auto &fe_v = scratch_data.new_fe_values(t_cell);
1626 const uint to_n_dofs = fe_v[to]->get_fe().n_dofs_per_cell();
1627 const uint from_n_dofs = fe_v[from]->get_fe().n_dofs_per_cell();
1628 copy_data.reinit(scratch_data.cell[from], scratch_data.cell[to], from_n_dofs, to_n_dofs);
1630 const auto &JxW = fe_v[to]->get_JxW_values();
1631 const auto &q_points = fe_v[to]->get_quadrature_points();
1632 const auto &q_indices = fe_v[to]->quadrature_point_indices();
1633 auto &solution = scratch_data.solution;
1635 fe_v[from]->get_function_values(solution_global, solution[from]);
1638 SimpleMatrix<
NumberType, Components::count_fe_functions(to), Components::count_fe_functions(from)> j_source;
1639 for (
const auto &q_index : q_indices) {
1640 const auto &x_q = q_points[q_index];
1641 model.template jacobian_flux_source<from, to>(j_flux, j_source, x_q, solution[from][q_index]);
1643 for (
uint i = 0; i < to_n_dofs; ++i) {
1644 const auto component_i = fe_v[to]->get_fe().system_to_component_index(i).first;
1645 for (
uint j = 0; j < from_n_dofs; ++j) {
1646 const auto component_j = fe_v[from]->get_fe().system_to_component_index(j).first;
1647 copy_data.cell_jacobian(i, j) +=
1649 fe_v[from]->shape_value_component(j, q_index, component_j) *
1650 (-scalar_product(fe_v[to]->shape_grad_component(i, q_index, component_i),
1651 j_flux(component_i, component_j))
1652 + fe_v[to]->shape_value_component(i, q_index, component_i) *
1653 j_source(component_i, component_j));
1658 const auto boundary_worker = [&](
const Iterator &t_cell,
const uint &face_no, Scratch &scratch_data,
1659 CopyData ©_data) {
1660 const auto &fe_fv = scratch_data.new_fe_boundary_values(t_cell, face_no);
1661 const uint to_n_dofs = fe_fv[to]->get_fe().n_dofs_per_cell();
1662 const uint from_n_dofs = fe_fv[from]->get_fe().n_dofs_per_cell();
1664 const auto &JxW = fe_fv[to]->get_JxW_values();
1665 const auto &q_points = fe_fv[to]->get_quadrature_points();
1666 const auto &q_indices = fe_fv[to]->quadrature_point_indices();
1667 const std::vector<Tensor<1, dim>> &normals = fe_fv[to]->get_normal_vectors();
1668 auto &solution = scratch_data.solution;
1670 fe_fv[from]->get_function_values(solution_global, solution[from]);
1674 for (
const auto &q_index : q_indices) {
1675 const auto &x_q = q_points[q_index];
1676 model.template jacobian_boundary_numflux<from, to>(j_boundary_numflux, normals[q_index], x_q,
1677 solution[from][q_index]);
1679 for (
uint i = 0; i < to_n_dofs; ++i) {
1680 const auto component_i = fe_fv[to]->get_fe().system_to_component_index(i).first;
1681 for (
uint j = 0; j < from_n_dofs; ++j) {
1682 const auto component_j = fe_fv[from]->get_fe().system_to_component_index(j).first;
1683 copy_data.cell_jacobian(i, j) +=
1685 fe_fv[from]->shape_value_component(j, q_index, component_j) *
1686 (fe_fv[to]->shape_value_component(i, q_index, component_i) *
1687 scalar_product(j_boundary_numflux(component_i, component_j),
1693 const auto face_worker = [&](
const Iterator &t_cell,
const uint &f,
const uint &sf,
const Iterator &t_ncell,
1694 const uint &nf,
const unsigned int &nsf, Scratch &scratch_data,
1695 CopyData ©_data) {
1696 const auto &fe_iv = scratch_data.new_fe_interface_values(t_cell, f, sf, t_ncell, nf, nsf);
1697 const uint to_n_dofs = fe_iv[to]->n_current_interface_dofs();
1698 const uint from_n_dofs = fe_iv[from]->n_current_interface_dofs();
1699 auto ©_data_face = copy_data.new_face_data(*(fe_iv[from]), *(fe_iv[to]));
1701 const auto &JxW = fe_iv[to]->get_JxW_values();
1702 const auto &q_points = fe_iv[to]->get_quadrature_points();
1703 const auto &q_indices = fe_iv[to]->quadrature_point_indices();
1704 const std::vector<Tensor<1, dim>> &normals = fe_iv[to]->get_normal_vectors();
1705 auto &solution = scratch_data.solution_interface;
1707 fe_iv[from]->get_fe_face_values(0).get_function_values(solution_global, solution[0][from]);
1708 fe_iv[from]->get_fe_face_values(1).get_function_values(solution_global, solution[1][from]);
1710 array<SimpleMatrix<Tensor<1, dim>, Components::count_fe_functions(to), Components::count_fe_functions(from)>,
1713 for (
const auto &q_index : q_indices) {
1714 const auto &x_q = q_points[q_index];
1715 model.template jacobian_numflux<from, to>(j_numflux, normals[q_index], x_q, solution[0][from][q_index],
1716 solution[1][from][q_index]);
1718 for (
uint i = 0; i < to_n_dofs; ++i) {
1719 const auto &cd_i = fe_iv[to]->interface_dof_to_dof_indices(i);
1720 const uint face_no_i = cd_i[0] == numbers::invalid_unsigned_int ? 1 : 0;
1721 const auto &component_i = fe_iv[to]->get_fe().system_to_component_index(cd_i[face_no_i]).first;
1722 for (
uint j = 0; j < from_n_dofs; ++j) {
1723 const auto &cd_j = fe_iv[from]->interface_dof_to_dof_indices(j);
1724 const uint face_no_j = cd_j[0] == numbers::invalid_unsigned_int ? 1 : 0;
1725 const auto &component_j = fe_iv[from]->get_fe().system_to_component_index(cd_j[face_no_j]).first;
1727 copy_data_face.cell_jacobian(i, j) +=
1729 fe_iv[from]->get_fe_face_values(face_no_j).shape_value_component(
1730 cd_j[face_no_j], q_index, component_j) *
1731 (fe_iv[to]->jump_in_shape_values(i, q_index, component_i) *
1732 scalar_product(j_numflux[face_no_j](component_i, component_j),
1738 const auto copier = [&](
const CopyData &c) {
1739 ldg_jacobian_tmp.add(c.local_dof_indices_to, c.local_dof_indices_from, c.cell_jacobian);
1740 for (
auto &cdf : c.face_data)
1741 ldg_jacobian_tmp.add(cdf.joint_dof_indices_to, cdf.joint_dof_indices_from, cdf.cell_jacobian);
1744 const MeshWorker::AssembleFlags assemble_flags = MeshWorker::assemble_own_cells |
1745 MeshWorker::assemble_boundary_faces |
1746 MeshWorker::assemble_own_interior_faces_once;
1750 ldg_jacobian_tmp = 0;
1754 assemble_flags, boundary_worker, face_worker, schedule.queue_length, schedule.chunk_size);
1755 for (
const auto &c :
model.get_components().ldg_couplings(to, from))
1757 Vector<NumberType>(),
false);
1769 const DoFHandler<dim> &from_dofh,
const int stencil = 1,
1770 bool add_extractor_dofs =
false)
const
1773 auto to_dofs_per_component = DoFTools::count_dofs_per_fe_component(to_dofh);
1774 auto from_dofs_per_component = DoFTools::count_dofs_per_fe_component(from_dofh);
1775 auto to_n_fe = to_dofs_per_component.size();
1776 auto from_n_fe = from_dofs_per_component.size();
1777 for (
uint j = 1; j < from_dofs_per_component.size(); ++j)
1778 if (from_dofs_per_component[j] != from_dofs_per_component[0])
1779 throw std::runtime_error(
"For LDG the FE basis of all systems must be equal!");
1780 for (
uint j = 1; j < to_dofs_per_component.size(); ++j)
1781 if (to_dofs_per_component[j] != to_dofs_per_component[0])
1782 throw std::runtime_error(
"For LDG the FE basis of all systems must be equal!");
1784 BlockDynamicSparsityPattern dsp(to_n_fe, from_n_fe);
1785 for (
uint i = 0; i < to_n_fe; ++i)
1786 for (
uint j = 0; j < from_n_fe; ++j)
1787 dsp.block(i, j).reinit(to_dofs_per_component[i], from_dofs_per_component[j]);
1788 dsp.collect_sizes();
1790 const auto to_dofs_per_cell = to_dofh.get_fe().dofs_per_cell;
1791 const auto from_dofs_per_cell = from_dofh.get_fe().dofs_per_cell;
1793 for (
const auto &t_cell : triangulation.active_cell_iterators()) {
1794 std::vector<types::global_dof_index> to_dofs(to_dofs_per_cell);
1795 std::vector<types::global_dof_index> from_dofs(from_dofs_per_cell);
1796 const auto to_cell =
typename DoFHandler<dim>::active_cell_iterator(
1797 &to_dofh.get_triangulation(), t_cell->level(), t_cell->index(), &to_dofh);
1798 const auto from_cell =
typename DoFHandler<dim>::active_cell_iterator(
1799 &from_dofh.get_triangulation(), t_cell->level(), t_cell->index(), &from_dofh);
1800 to_cell->get_dof_indices(to_dofs);
1801 from_cell->get_dof_indices(from_dofs);
1803 std::function<void(
decltype(from_cell) &,
const int)> add_all_neighbor_dofs = [&](
const auto &from_cell,
1804 const int stencil_level) {
1805 for (
const auto face_no : from_cell->face_indices()) {
1806 const auto face = from_cell->face(face_no);
1807 if (!face->at_boundary()) {
1808 auto neighbor_cell = from_cell->neighbor(face_no);
1811 while (neighbor_cell->has_children())
1812 neighbor_cell = neighbor_cell->child(face_no == 0 ? 1 : 0);
1815 else if (neighbor_cell->has_children()) {
1816 throw std::runtime_error(
"not yet implemented lol");
1819 if (!neighbor_cell->is_active())
continue;
1821 std::vector<types::global_dof_index> tmp(from_dofs_per_cell);
1822 neighbor_cell->get_dof_indices(tmp);
1824 from_dofs.insert(std::end(from_dofs), std::begin(tmp), std::end(tmp));
1826 if (stencil_level <
stencil) add_all_neighbor_dofs(neighbor_cell, stencil_level + 1);
1831 add_all_neighbor_dofs(from_cell, 1);
1833 for (
const auto i : to_dofs)
1834 for (
const auto j : from_dofs)
1838 if (add_extractor_dofs)
1839 for (
uint row = 0; row < dsp.n_rows(); ++row)
1843 sparsity_pattern.copy_from(dsp);
1852 void build_inverse(
const SparseMatrix<NumberType> &in, SparseMatrix<NumberType> &out)
const
1854 GrowingVectorMemory<Vector<NumberType>> mem;
1855 SparseDirectUMFPACK inverse;
1856 inverse.initialize(in);
1859 tbb::parallel_for(tbb::blocked_range<int>(0, out.n()), [&](tbb::blocked_range<int> r) {
1860 typename VectorMemory<Vector<NumberType>>::Pointer tmp(mem);
1861 tmp->reinit(out.m());
1862 for (int n = r.begin(); n < r.end(); ++n) {
1865 inverse.solve(*tmp);
1866 for (auto it = out.begin(n); it != out.end(n); ++it)
1867 it->value() = (*tmp)[it->column()];
1873 constexpr static int nothing = 0;
1875 using Base::EoM_cell;
1876 using Base::EoM_minimum_guess;
1877 using Base::extractor_jacobian_u;
1878 using Base::old_EoM_cell;
1879 using Base::old_extractor_cell;
1883 template <
typename PotentialEvaluation = RawPotentialEvaluation<dim, NumberType>>
struct PointEvaluation {
1885 std::vector<std::vector<Tensor<1, dim, NumberType>>> gradients{
1886 std::vector<Tensor<1, dim, NumberType>>(Components::count_fe_functions())};
1887 std::vector<std::vector<Tensor<2, dim, NumberType>>> hessians{
1888 std::vector<Tensor<2, dim, NumberType>>(Components::count_fe_functions())};
1901 template <
typename RawPotential>
1902 auto evaluate_at(
const Point<dim> &x,
const typename DoFHandler<dim>::cell_iterator &x_cell,
1903 const VectorType &solution_global,
const RawPotential &raw_potential)
const
1905 using t_Iterator =
typename Triangulation<dim>::active_cell_iterator;
1906 const auto x_unit = mapping.transform_real_to_unit_cell(x_cell, x);
1908 std::vector<std::shared_ptr<FEValues<dim>>> fe_v;
1909 for (
uint k = 0; k < Components::count_fe_subsystems(); ++k) {
1910 fe_v.emplace_back(std::make_shared<FEValues<dim>>(
1911 mapping, discretization.get_fe(k), x_unit,
1912 update_values | update_gradients | update_quadrature_points | update_JxW_values | update_hessians));
1913 auto cell = dof_handler_list[k]->begin_active();
1914 cell->copy_from(*t_Iterator(x_cell));
1915 fe_v[k]->reinit(cell);
1919 for (
uint k = 0; k < Components::count_fe_subsystems(); ++k) {
1920 std::vector<Vector<NumberType>> values{Vector<NumberType>(Components::count_fe_functions(k))};
1922 fe_v[0]->get_function_values(solution_global, values);
1924 fe_v[k]->get_function_values(sol_vector[k], values);
1925 evaluation.solutions.push_back(values[0]);
1927 fe_v[0]->get_function_gradients(solution_global, evaluation.gradients);
1928 fe_v[0]->get_function_hessians(solution_global, evaluation.hessians);
1930 evaluation.fe_values = fe_v[0];
1938 solution_global, dof_handler, mapping,
1939 [&](
const auto &p,
const auto &values) {
return model.raw_potential_gradient(p, values); }, EoM_config,
1940 &this->potential_cache);
1941 auto helper = [&](
auto &&...args) {
1942 if constexpr (
sizeof...(args) == 3) {
1943 auto &&[id, EoMfun, outputter] = std::forward_as_tuple(std::forward<
decltype(args)>(args)...);
1945 auto EoM_cell = this->EoM_cell;
1947 EoM_cell, solution_global, this->dof_handler, this->mapping, EoMfun,
1948 [&](
const auto &p,
const auto &) {
return p; }, this->EoM_config, this->EoM_minimum_guess,
1949 &this->potential_cache);
1950 if (EoM_result.potential) this->EoM_minimum_guess = EoM_result.potential->minimum;
1951 const auto EoM = EoM_result.point;
1954 const auto readout_solution = this->evaluate_at(EoM, EoM_cell, solution_global, raw_potential);
1955 const auto &potential = readout_solution.potential;
1960 std::array<
NumberType, Components::count_extractors()> __extracted_data{{}};
1961 if constexpr (Components::count_extractors() > 0) {
1962 const auto [x, cell] = this->resolve_extractor_point(EoM, EoM_cell, solution_global);
1963 const auto evaluation = this->evaluate_at(x, cell, solution_global, raw_potential);
1964 auto extractor_tuple = std::tuple_cat(
1965 vector_to_tuple<Components::count_fe_subsystems()>(evaluation.solutions),
1966 std::tie(evaluation.gradients[0], evaluation.hessians[0], this->nothing, variables,
1967 evaluation.potential.value, evaluation.potential.gradient, evaluation.potential.mass_hessian));
1968 this->model.extract(__extracted_data, x, fe_more_conv(extractor_tuple));
1970 const auto &extracted_data = __extracted_data;
1972 auto solution_tuple =
1973 std::tuple_cat(
vector_to_tuple<Components::count_fe_subsystems()>(readout_solution.solutions),
1974 std::tie(readout_solution.gradients[0], readout_solution.hessians[0], extracted_data,
1975 variables, potential.value, potential.gradient, potential.mass_hessian));
1977 outputter(data_out, EoM, fe_more_conv(solution_tuple));
1983 model.readouts_multiple(helper, data_out);
1988 const VectorType &variables,
bool search_EoM,
bool set_EoM,
bool postprocess)
const
1990 auto EoM = this->EoM;
1991 auto EoM_cell = this->EoM_cell;
1992 if (search_EoM || EoM_cell == *(dof_handler.active_cell_iterators().end())) {
1994 EoM_cell, solution_global, dof_handler, mapping,
1995 [&](
const auto &p,
const auto &values) {
return model.EoM(p, values); },
1996 [&](
const auto &p,
const auto &values) {
return postprocess ? model.EoM_postprocess(p, values) : p; },
1997 EoM_config, EoM_minimum_guess, &this->potential_cache);
1998 EoM = EoM_result.point;
1999 if (EoM_result.potential) EoM_minimum_guess = EoM_result.potential->minimum;
2003 this->EoM_cell = EoM_cell;
2005 rebuild_ldg_vectors(solution_global);
2007 const auto raw_potential = this->extractor_raw_potential(solution_global);
2009 const auto [x, cell] = this->resolve_extractor_point(EoM, EoM_cell, solution_global);
2010 const auto evaluation = evaluate_at(x, cell, solution_global, raw_potential);
2012 auto solution_tuple = std::tuple_cat(
vector_to_tuple<Components::count_fe_subsystems()>(evaluation.solutions),
2013 std::tie(evaluation.gradients[0], evaluation.hessians[0], this->nothing,
2014 variables, evaluation.potential.value,
2015 evaluation.potential.gradient, evaluation.potential.mass_hessian));
2017 model.extract(data, x, fe_more_conv(solution_tuple));
2023 if (extractor_jacobian_u.m() != Components::count_extractors() ||
2024 extractor_jacobian_u.n() != Components::count_fe_functions())
2025 extractor_jacobian_u =
2026 FullMatrix<NumberType>(Components::count_extractors(), Components::count_fe_functions());
2029 EoM_cell, solution_global, dof_handler, mapping,
2030 [&](
const auto &p,
const auto &values) {
return model.EoM(p, values); },
2031 [&](
const auto &p,
const auto &values) {
return model.EoM_postprocess(p, values); }, EoM_config,
2032 EoM_minimum_guess, &this->potential_cache);
2033 EoM = EoM_result.point;
2034 if (EoM_result.potential) EoM_minimum_guess = EoM_result.potential->minimum;
2035 const auto raw_potential = this->extractor_raw_potential(solution_global);
2039 const auto [x, cell] = this->resolve_extractor_point(EoM, EoM_cell, solution_global);
2040 bool new_cell = (old_extractor_cell != cell);
2041 old_EoM_cell = EoM_cell;
2042 old_extractor_cell = cell;
2044 const auto evaluation = evaluate_at(x, cell, solution_global, raw_potential);
2045 const auto &fe_v = *evaluation.fe_values;
2046 const uint n_dofs = fe_v.get_fe().n_dofs_per_cell();
2048 extractor_dof_indices.resize(n_dofs);
2049 cell->get_dof_indices(extractor_dof_indices);
2050 rebuild_jacobian_sparsity();
2053 auto solution_tuple = std::tuple_cat(
vector_to_tuple<Components::count_fe_subsystems()>(evaluation.solutions),
2054 std::tie(evaluation.gradients[0], evaluation.hessians[0], this->nothing,
2055 variables, evaluation.potential.value,
2056 evaluation.potential.gradient, evaluation.potential.mass_hessian));
2058 extractor_jacobian_u = 0;
2059 model.template jacobian_extractors<0>(extractor_jacobian_u, x, fe_more_conv(solution_tuple));
2061 if (extractor_jacobian.m() != Components::count_extractors() || extractor_jacobian.n() != n_dofs)
2062 extractor_jacobian = FullMatrix<NumberType>(Components::count_extractors(), n_dofs);
2064 for (
uint e = 0; e < Components::count_extractors(); ++e)
2065 for (
uint i = 0; i < n_dofs; ++i) {
2066 const auto component_i = fe_v.get_fe().system_to_component_index(i).first;
2067 extractor_jacobian(e, i) =
2068 extractor_jacobian_u(e, component_i) * fe_v.shape_value_component(i, 0, component_i);
2074 using Base::timings_variable_jacobian;
2075 using Base::timings_variable_residual;
2076 template <
typename... T>
static constexpr auto v_tie(T &&...t)
2081 template <
typename... T>
static constexpr auto e_tie(T &&...t)
2084 StringSet<
"fe_functions",
"fe_derivatives",
"fe_hessians",
"extractors",
"variables">>(
2092 std::array<
NumberType, Components::count_extractors()> __extracted_data{{}};
2093 if constexpr (Components::count_extractors() > 0)
2094 extract(__extracted_data, spatial_solution, variables,
true,
false,
false);
2095 const auto &extracted_data = __extracted_data;
2096 model.dt_variables(residual, v_tie(variables, extracted_data));
2098 timings_variable_residual.push_back(timer.wall_time());
2105 std::array<
NumberType, Components::count_extractors()> __extracted_data{{}};
2106 if constexpr (Components::count_extractors() > 0)
2107 extract(__extracted_data, spatial_solution, variables,
true,
false,
false);
2108 const auto &extracted_data = __extracted_data;
2109 model.template jacobian_variables<0>(jacobian, v_tie(variables, extracted_data));
2111 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:54
Definition affine_constraint_metadata.hh:24
A hierarchical configuration tree, readable from JSON and TOML files.
Definition config_tree.hh:32
The LDG assembler that can be used for any LDG scheme, with as many levels as one wants.
Definition ldg.hh:448
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:1987
double average_time_residual_assembly() const
Definition ldg.hh:1378
SummaryEvent summary() const override
Definition ldg.hh:1359
array< BlockVector< NumberType >, Components::count_fe_subsystems()> sol_vector
Definition ldg.hh:1411
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:1616
const FiniteElement< dim > & fe
Definition ldg.hh:122
SparseMatrix< NumberType > component_mass_matrix_inverse
Definition ldg.hh:1424
BlockSparsityPattern sparsity_pattern_jacobian
Definition ldg.hh:1415
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:800
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:965
uint num_residuals() const
Definition ldg.hh:1386
array< BlockSparseMatrix< NumberType >, Components::count_fe_subsystems()> j_wg_tmp
Definition ldg.hh:1428
virtual const BlockSparseMatrix< NumberType > & get_mass_matrix() const override
Obtain the mass matrix.
Definition ldg.hh:734
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:1768
double average_time_jacobian_assembly() const
Definition ldg.hh:1388
virtual void attach_data_output(OutputFrame< 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:539
typename Discretization::NumberType NumberType
Definition ldg.hh:454
static constexpr auto v_tie(T &&...t)
Definition ldg.hh:2076
const Mapping< dim > & mapping
Definition ldg.hh:124
std::vector< double > timings_residual
Definition ldg.hh:1431
array< BlockSparsityPattern, Components::count_fe_subsystems()> sparsity_pattern_ug
Definition ldg.hh:1417
array< BlockVector< NumberType >, Components::count_fe_subsystems()> sol_vector_tmp
Definition ldg.hh:1412
static constexpr uint stencil
Definition ldg.hh:460
virtual void reinit_solution_view(SolutionView< VectorType > &view) const override
Definition ldg.hh:527
auto fe_more_conv(std::tuple< T &... > &t) const
Definition ldg.hh:478
virtual void residual_variables(VectorType &residual, const VectorType &variables, const VectorType &spatial_solution) override
Definition ldg.hh:2088
typename Discretization::SparseMatrixType SparseMatrixType
Definition ldg.hh:456
typename Discretization::VectorType VectorType
Definition ldg.hh:455
BlockSparsityPattern sparsity_pattern_mass
Definition ldg.hh:1416
Assembler(Discretization &discretization, Model &model, const ConfigTree &config)
Definition ldg.hh:509
virtual void reinit_vector(VectorType &vec) const override
Definition ldg.hh:519
virtual void jacobian_variables(FullMatrix< NumberType > &jacobian, const VectorType &variables, const VectorType &spatial_solution) override
Definition ldg.hh:2101
typename Discretization::Components Components
Definition ldg.hh:458
static constexpr auto e_tie(T &&...t)
Definition ldg.hh:2081
uint num_jacobians() const
Definition ldg.hh:1396
virtual void mass(VectorType &residual, const VectorType &solution_global, const VectorType &solution_global_dot, NumberType weight) override
Construct the mass.
Definition ldg.hh:743
std::vector< const DoFHandler< dim > * > dof_handler_list
Definition ldg.hh:1409
AssemblySchedule schedule_for(const double cost_ns) const
Definition ldg.hh:127
auto fe_conv(std::tuple< T &... > &t) const
Definition ldg.hh:463
Model & model
Definition ldg.hh:120
QGauss< dim - 1 > quadrature_face
Definition ldg.hh:1406
array< BlockSparsityPattern, Components::count_fe_subsystems()> sparsity_pattern_wg
Definition ldg.hh:1419
void rebuild_ldg_jacobian(const VectorType &sol) const
Definition ldg.hh:1456
static constexpr uint dim
Definition ldg.hh:459
virtual void reinit_matrix(SparseMatrixType &matrix) const override
Definition ldg.hh:522
array< bool, Components::count_fe_subsystems()> ldg_matrix_built
Definition ldg.hh:1434
array< BlockSparseMatrix< NumberType >, Components::count_fe_subsystems()> j_ug
Definition ldg.hh:1425
virtual void reinit() override
Reinitialize the assembler. This is necessary if the mesh has changed, e.g. after a mesh refinement.
Definition ldg.hh:564
virtual void rebuild_jacobian_sparsity() override
Definition ldg.hh:640
auto ref_conv(std::tuple< T &... > &t) const
Definition ldg.hh:496
bool jacobian_extractors(FullMatrix< NumberType > &extractor_jacobian, const VectorType &solution_global, const VectorType &variables)
Definition ldg.hh:2020
virtual MPI_Comm get_communicator() const override
The communicator this assembler's linear algebra lives on.
Definition ldg.hh:526
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:1852
auto evaluate_at(const Point< dim > &x, const typename DoFHandler< dim >::cell_iterator &x_cell, const VectorType &solution_global, const RawPotential &raw_potential) const
Evaluate every LDG subsystem at x, which lies in x_cell.
Definition ldg.hh:1902
Discretization_ Discretization
Definition ldg.hh:452
array< BlockSparsityPattern, Components::count_fe_subsystems()> sparsity_pattern_gu
Definition ldg.hh:1418
Discretization & discretization
Definition ldg.hh:119
array< BlockSparseMatrix< NumberType >, Components::count_fe_subsystems()> jacobian_tmp
Definition ldg.hh:1421
virtual const BlockSparsityPattern & get_sparsity_pattern_jacobian() const override
Obtain the sparsity pattern of the jacobian matrix.
Definition ldg.hh:730
BlockSparseMatrix< NumberType > mass_matrix
Definition ldg.hh:1423
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:1034
array< BlockSparseMatrix< NumberType >, Components::count_fe_subsystems()> j_wg
Definition ldg.hh:1427
std::vector< types::global_dof_index > extractor_dof_indices
Definition ldg.hh:192
uint num_reinits() const
Definition ldg.hh:1376
void rebuild_ldg_vectors(const VectorType &sol) const
Definition ldg.hh:1440
array< bool, Components::count_fe_subsystems()> jacobian_tmp_built
Definition ldg.hh:1435
QGauss< dim > quadrature
Definition ldg.hh:1405
std::vector< double > timings_reinit
Definition ldg.hh:1430
array< Vector< NumberType >, Components::count_fe_subsystems()> sol_vector_vec_tmp
Definition ldg.hh:1413
std::vector< double > timings_jacobian
Definition ldg.hh:1432
Model_ Model
Definition ldg.hh:453
double average_time_reinit() const
Definition ldg.hh:1368
array< BlockSparseMatrix< NumberType >, Components::count_fe_subsystems()> j_gu
Definition ldg.hh:1426
void readouts(OutputFrame< dim, VectorType > &data_out, const VectorType &solution_global, const VectorType &variables) const
Definition ldg.hh:1934
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:1484
virtual void refinement_indicator(Vector< double > &indicator, const VectorType &solution_global) override
Definition ldg.hh:647
const DoFHandler< dim > & dof_handler
Definition ldg.hh:123
static constexpr uint dim
Definition ldg.hh:44
Vector< NumberType > VectorType
Definition ldg.hh:41
typename DiFfRG::internal::components_of< ModelOrComponents_ >::type Components
Definition ldg.hh:39
BlockSparseMatrix< NumberType > SparseMatrixType
Definition ldg.hh:42
NumberType_ NumberType
Definition ldg.hh:40
void update_assembly_schedules()
Definition ldg.hh:133
DoFHandler< dim >::cell_iterator old_extractor_cell
Definition ldg.hh:182
LDGAssemblerBase(Discretization &discretization, Model &model, const ConfigTree &config)
Definition ldg.hh:55
auto extractor_raw_potential(const VectorType &solution_global) const
Definition ldg.hh:150
FullMatrix< NumberType > extractor_jacobian_du
Definition ldg.hh:190
const FiniteElement< dim > & fe
Definition ldg.hh:122
uint num_variable_jacobians() const
Definition ldg.hh:116
FullMatrix< NumberType > extractor_jacobian_u
Definition ldg.hh:189
std::optional< Point< dim > > EoM_minimum_guess
Definition ldg.hh:185
FullMatrix< NumberType > extractor_jacobian_ddu
Definition ldg.hh:191
typename Discretization::NumberType NumberType
Definition ldg.hh:49
auto & get_discretization()
Definition ldg.hh:76
double average_time_variable_residual_assembly()
Definition ldg.hh:98
const Mapping< dim > & mapping
Definition ldg.hh:124
const Config::EoMConfig EoM_config
Definition ldg.hh:183
static constexpr uint dim
Definition ldg.hh:54
FullMatrix< NumberType > extractor_jacobian
Definition ldg.hh:188
DoFHandler< dim >::cell_iterator old_EoM_cell
Definition ldg.hh:180
Discretization_ Discretization
Definition ldg.hh:47
uint n_owned_cells
Definition ldg.hh:176
typename Discretization::SparseMatrixType SparseMatrixType
Definition ldg.hh:51
DiFfRG::internal::PotentialSystemCache< dim, NumberType > potential_cache
Definition ldg.hh:187
AssemblySchedule schedule_for(const double cost_ns) const
Definition ldg.hh:127
typename Discretization::VectorType VectorType
Definition ldg.hh:50
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:94
const auto & get_discretization() const
Definition ldg.hh:75
Model & model
Definition ldg.hh:120
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:78
double average_time_variable_jacobian_assembly()
Definition ldg.hh:108
virtual IndexSet get_differential_indices() const override
Obtain the dofs which contain time derivatives.
Definition ldg.hh:69
std::vector< double > timings_variable_residual
Definition ldg.hh:194
std::pair< Point< dim >, typename DoFHandler< dim >::cell_iterator > resolve_extractor_point(const Point< dim > &EoM_point, const typename DoFHandler< dim >::cell_iterator &EoM_cell_, const VectorType &solution_global) const
Definition ldg.hh:163
std::vector< double > timings_variable_jacobian
Definition ldg.hh:195
typename Discretization::Components Components
Definition ldg.hh:53
Discretization & discretization
Definition ldg.hh:119
Point< dim > EoM
Definition ldg.hh:184
DoFHandler< dim >::cell_iterator EoM_cell
Definition ldg.hh:179
std::vector< types::global_dof_index > extractor_dof_indices
Definition ldg.hh:192
uint num_variable_residuals() const
Definition ldg.hh:106
Model_ Model
Definition ldg.hh:48
const AssemblyScheduleOverrides schedule_overrides
Definition ldg.hh:177
virtual void rebuild_jacobian_sparsity()=0
ReportPort report_port
Definition ldg.hh:121
const DoFHandler< dim > & dof_handler
Definition ldg.hh:123
void attach(const DoFHandler< dim > &dof_handler, const VectorType &solution, const std::string &name)
Definition output_session.hh:47
Definition output_session.hh:42
void attach_raw_potential(ReconstructedRawPotential< dim, typename VectorType::value_type > potential)
Definition output_session.hh:141
FieldCollector fields()
Definition output_session.hh:92
void register_readout(const std::string &id)
Definition output_session.hh:154
void attach_eom_potential(EoMResult< dim, typename VectorType::value_type > result)
Definition output_session.hh:136
Definition run_reporter.hh:96
void info(spdlog::format_string_t< Args... > format, Args &&...args) const
Definition run_reporter.hh:103
A simple NxM-matrix class, which is used for cell-wise Jacobians.
Definition tuples.hh:170
A read-only, fully-replicated view of the solution.
Definition solution_view.hh:48
void reinit(const dealii::IndexSet &, const dealii::IndexSet &, MPI_Comm)
Establish the layout. No-op for the serial policy.
Definition solution_view.hh:58
The mesh-dependent half of solve_potential, retained across calls.
Definition eom.hh:315
constexpr double algebraic
Algebraic couplings without momentum quadrature, e.g. LDG's level-to-level transfers.
Definition assembly_schedule.hh:50
constexpr double local_fe
Local FE work only: mass matrices, refinement indicators. ~0.2-0.3 us/cell for CG p=3.
Definition assembly_schedule.hh:48
constexpr double momentum_integral
Definition assembly_schedule.hh:53
AffineConstraintMetadata< dim > build_affine_constraint_metadata(const Discretization &discretization)
Definition affine_constraint_metadata.hh:99
double cell_width(const CellIterator &cell)
The smallest face-normal width over all faces of cell.
Definition cell_geometry.hh:42
void apply_model_affine_constraints(Model &model, Constraints &constraints, const Context &context)
Definition affine_constraint_metadata.hh:79
constexpr void validate_readout_helper_arity()
Definition abstract_assembler.hh:17
Definition complex_math.hh:10
auto locally_owned_cells(const dealii::DoFHandler< dim > &dof_handler)
The cells this rank assembles.
Definition assembly_schedule.hh:154
ReconstructedRawPotential< dim, typename VectorType::value_type > reconstruct_raw_potential(const VectorType &sol, const dealii::DoFHandler< dim > &dof_handler, const dealii::Mapping< dim > &mapping, const GradientFUN &get_gradient, const Config::EoMConfig &config, internal::PotentialSystemCache< dim, typename VectorType::value_type > *cache=nullptr)
Reconstruct a scalar raw potential without locating its minimum.
Definition eom.hh:1411
AssemblySchedule make_assembly_schedule(const uint n_local_cells, const uint thread_budget, const double cost_ns, const AssemblyScheduleOverrides &overrides={})
Derive one mesh_loop schedule from the cost of a cell.
Definition assembly_schedule.hh:114
uint n_locally_owned_cells(const Discretization &discretization)
How many cells locally_owned_cells() yields.
Definition assembly_schedule.hh:167
auto local_sol_q(const std::array< T, N > &a, uint q_index)
Definition tuples.hh:292
auto jacobian_tuple()
Definition tuples.hh:302
@ config
/discretization/threads.
unsigned int n_threads()
The CPU thread budget this process resolved.
UnusedPotentialEvaluation evaluate_raw_potential(const UnusedPotential &, const dealii::Mapping< dim > &, const dealii::Point< dim > &)
Definition eom.hh:149
auto vector_to_tuple(const std::vector< T > &v)
Definition tuples.hh:231
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:31
auto jacobian_2_tuple()
Definition tuples.hh:313
unsigned int uint
Definition utils.hh:24
bool KOKKOS_INLINE_FUNCTION 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:177
EoMResult< dim, typename VectorType::value_type > get_EoM_point_with_potential(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 Config::EoMConfig &config, const std::optional< dealii::Point< dim > > &initial_guess=std::nullopt, internal::PotentialSystemCache< dim, typename VectorType::value_type > *cache=nullptr)
Reconstruct a potential whose gradient approximates the model EoM vector field and return a sampled a...
Definition eom.hh:1486
SolutionSample< dim, NumberType > make_solution_sample(const dealii::DoFHandler< dim > &dof_handler, const dealii::Mapping< dim > &mapping, const uint n_components, const FillFUN &fill)
Build a SolutionSample, taking values and gradients from a callback.
Definition solution_sample.hh:154
Overrides, if really wanted by the user: /discretization/{mesh_workers,batch_size}...
Definition assembly_schedule.hh:82
The two trailing arguments of dealii::MeshWorker::mesh_loop.
Definition assembly_schedule.hh:30
Definition eom_config.hh:10
PotentialEvaluation potential
Definition ldg.hh:1889
std::vector< Vector< NumberType > > solutions
Definition ldg.hh:1884
std::shared_ptr< FEValues< dim > > fe_values
Subsystem 0's FEValues at the point, kept for the shape values the extractor jacobian needs.
Definition ldg.hh:1891
std::array< uint, 2 > cell_indices
Definition ldg.hh:430
std::array< double, 2 > values
Definition ldg.hh:431
uint cell_index
Definition ldg.hh:435
double value
Definition ldg.hh:434
std::vector< CopyFaceData_I > face_data
Definition ldg.hh:433
FullMatrix< NumberType > cell_jacobian
Definition ldg.hh:349
std::vector< types::global_dof_index > joint_dof_indices_from
Definition ldg.hh:350
std::vector< types::global_dof_index > joint_dof_indices_to
Definition ldg.hh:351
FullMatrix< NumberType > extractor_cell_jacobian
Definition ldg.hh:384
array< FullMatrix< NumberType >, n_fe_subsystems > cell_jacobian
Definition ldg.hh:383
array< vector< types::global_dof_index >, n_fe_subsystems > joint_dof_indices
Definition ldg.hh:385
void reinit(const array< Iterator, n_fe_subsystems > &cell, const uint n_extractors)
Definition ldg.hh:396
CopyDataFace_J & new_face_data(const array< unique_ptr< FEInterfaceValues< dim > >, n_fe_subsystems > &fe_iv, const uint n_extractors)
Definition ldg.hh:413
FullMatrix< NumberType > cell_mass_jacobian
Definition ldg.hh:389
array< FullMatrix< NumberType >, n_fe_subsystems > cell_jacobian
Definition ldg.hh:388
vector< CopyDataFace_J > face_data
Definition ldg.hh:392
FullMatrix< NumberType > extractor_cell_jacobian
Definition ldg.hh:390
array< vector< types::global_dof_index >, n_fe_subsystems > local_dof_indices
Definition ldg.hh:391
uint dofs_per_cell
Definition ldg.hh:394
CopyDataFace_J & new_face_data(const FEInterfaceValues< dim > &fe_iv_from, const FEInterfaceValues< dim > &fe_iv_to)
Definition ldg.hh:370
std::vector< types::global_dof_index > local_dof_indices_to
Definition ldg.hh:356
FullMatrix< NumberType > cell_jacobian
Definition ldg.hh:354
std::vector< CopyDataFace_J > face_data
Definition ldg.hh:357
std::vector< types::global_dof_index > local_dof_indices_from
Definition ldg.hh:355
void reinit(const Iterator &cell_from, const Iterator &cell_to, uint dofs_per_cell_from, uint dofs_per_cell_to)
Definition ldg.hh:360
Vector< NumberType > cell_residual
Definition ldg.hh:318
std::vector< types::global_dof_index > joint_dof_indices
Definition ldg.hh:319
std::vector< CopyDataFace_R > face_data
Definition ldg.hh:325
void reinit(const Iterator &cell, uint dofs_per_cell)
Definition ldg.hh:327
Vector< NumberType > cell_mass
Definition ldg.hh:323
std::vector< types::global_dof_index > local_dof_indices
Definition ldg.hh:324
Vector< NumberType > cell_residual
Definition ldg.hh:322
CopyDataFace_R & new_face_data(const FEInterfaceValues< dim > &fe_iv)
Definition ldg.hh:337
Class to hold data for each assembly thread, i.e. FEValues for cells, interfaces, as well as pre-allo...
Definition ldg.hh:204
array< uint, n_fe_subsystems > n_components
Definition ldg.hh:301
typename Discretization::NumberType NumberType
Definition ldg.hh:206
vector< Vector< NumberType > > solution_dot
Definition ldg.hh:312
static constexpr uint n_fe_subsystems
Definition ldg.hh:207
const auto & new_fe_values(const t_Iterator &t_cell)
Definition ldg.hh:274
static constexpr uint dim
Definition ldg.hh:205
array< Iterator, n_fe_subsystems > cell
Definition ldg.hh:302
array< unique_ptr< FEFaceValues< dim > >, n_fe_subsystems > fe_boundary_values
Definition ldg.hh:307
typename Triangulation< dim >::active_cell_iterator t_Iterator
Definition ldg.hh:209
ScratchData(const ScratchData< Discretization > &scratch_data)
Definition ldg.hh:246
typename DoFHandler< dim >::active_cell_iterator Iterator
Definition ldg.hh:208
array< unique_ptr< FEInterfaceValues< dim > >, n_fe_subsystems > fe_interface_values
Definition ldg.hh:306
array< array< vector< Vector< NumberType > >, n_fe_subsystems >, 2 > solution_interface
Definition ldg.hh:313
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:282
array< Iterator, n_fe_subsystems > ncell
Definition ldg.hh:303
array< std::vector< uint >, n_fe_subsystems > comp
Definition ldg.hh:309
array< unique_ptr< FEValues< dim > >, n_fe_subsystems > fe_values
Definition ldg.hh:305
array< vector< Vector< NumberType > >, n_fe_subsystems > solution
Definition ldg.hh:311
ScratchData(const Mapping< dim > &mapping, const vector< const DoFHandler< dim > * > &dofh, const dealii::Quadrature< dim > &quadrature, const dealii::Quadrature< dim - 1 > &quadrature_face, const UpdateFlags update_flags=update_values|update_gradients|update_quadrature_points|update_JxW_values, const UpdateFlags interface_update_flags=update_values|update_gradients|update_quadrature_points|update_JxW_values|update_normal_vectors)
Definition ldg.hh:211
const auto & new_fe_boundary_values(const t_Iterator &t_cell, uint face_no)
Definition ldg.hh:292
Definition run_reporter.hh:73
SummaryEvent & timing(const std::string_view name, const double average_ms, const std::size_t calls)
Definition run_reporter.hh:78
Stand-in for a raw potential that a model has declared it does not read.
Definition eom.hh:140
std::conditional_t< CarriesModel< D >, typename D::Model, D > type
Definition types.hh:63
A class to store a tuple with elements that can be accessed by name. The names are stored as FixedStr...
Definition tuples.hh:56