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

DiFfRG: /home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/discretization/FEM/assembler/common.hh Source File
DiFfRG
common.hh
Go to the documentation of this file.
1#pragma once
2
3// external libraries
4#include <deal.II/base/multithread_info.h>
5#include <deal.II/base/quadrature_lib.h>
6#include <deal.II/base/timer.h>
7#include <deal.II/dofs/dof_handler.h>
8#include <deal.II/dofs/dof_tools.h>
9#include <deal.II/fe/fe_interface_values.h>
10#include <deal.II/fe/fe_values.h>
11#include <deal.II/lac/full_matrix.h>
12#include <deal.II/lac/sparse_matrix.h>
13#include <deal.II/lac/vector.h>
14#include <deal.II/meshworker/mesh_loop.h>
15#include <deal.II/numerics/fe_field_function.h>
16#include <deal.II/numerics/matrix_tools.h>
17#include <deal.II/numerics/vector_tools.h>
18#include <spdlog/spdlog.h>
19#include <tbb/tbb.h>
20
25
26namespace DiFfRG
27{
28 using namespace dealii;
29 using std::array;
30
36 template <typename Discretization_, typename Model_>
37 class FEMAssembler : public AbstractAssembler<typename Discretization_::VectorType,
38 typename Discretization_::SparseMatrixType, Discretization_::dim>
39 {
40 protected:
41 constexpr static int nothing = 0;
42
43 template <typename... T> static constexpr auto v_tie(T &&...t)
44 {
45 return named_tuple<std::tuple<T &...>, StringSet<"variables", "extractors">>(std::tie(t...));
46 }
47
48 template <typename... T> static constexpr auto e_tie(T &&...t)
49 {
50 return named_tuple<std::tuple<T &...>,
51 StringSet<"fe_functions", "fe_derivatives", "fe_hessians", "extractors", "variables">>(
52 std::tie(t...));
53 }
54
55 public:
56 using Discretization = Discretization_;
57 using Model = Model_;
58 using NumberType = typename Discretization::NumberType;
59 using VectorType = typename Discretization::VectorType;
60
61 using Components = typename Discretization::Components;
62 static constexpr uint dim = Discretization::dim;
63
66 dof_handler(discretization.get_dof_handler()), mapping(discretization.get_mapping()),
67 threads(json.get_uint("/discretization/threads")), batch_size(json.get_uint("/discretization/batch_size")),
68 EoM_cell(*(dof_handler.active_cell_iterators().end())),
69 old_EoM_cell(*(dof_handler.active_cell_iterators().end())),
70 EoM_abs_tol(json.get_double("/discretization/EoM_abs_tol")),
71 EoM_max_iter(json.get_uint("/discretization/EoM_max_iter"))
72 {
73 if (this->threads == 0) this->threads = dealii::MultithreadInfo::n_threads() / 2;
74 spdlog::get("log")->info("FEM: Using {} threads for assembly.", threads);
75 }
76
77 virtual IndexSet get_differential_indices() const override
78 {
79 ComponentMask component_mask(model.template differential_components<dim>());
80 return DoFTools::extract_dofs(dof_handler, component_mask);
81 }
82
83 virtual void attach_data_output(DataOutput<dim, VectorType> &data_out, const VectorType &solution,
84 const VectorType &variables, const VectorType &dt_solution = VectorType(),
85 const VectorType &residual = VectorType()) override
86 {
87 const auto fe_function_names = Components::FEFunction_Descriptor::get_names_vector();
88 std::vector<std::string> fe_function_names_residual;
89 fe_function_names_residual.reserve(fe_function_names.size());
90 for (const auto &name : fe_function_names)
91 fe_function_names_residual.push_back(name + "_residual");
92 std::vector<std::string> fe_function_names_dot;
93 fe_function_names_dot.reserve(fe_function_names.size());
94 for (const auto &name : fe_function_names)
95 fe_function_names_dot.push_back(name + "_dot");
96
97 auto &fe_out = data_out.fe_output();
98 fe_out.attach(dof_handler, solution, fe_function_names);
99 if (dt_solution.size() > 0) fe_out.attach(dof_handler, dt_solution, fe_function_names_dot);
100 if (residual.size() > 0) fe_out.attach(dof_handler, residual, fe_function_names_residual);
101
102 readouts(data_out, solution, variables);
103 }
104
105 const auto &get_discretization() const { return discretization; }
107
108 virtual void reinit() override
109 {
110 // Boundary dofs
111 std::vector<IndexSet> component_boundary_dofs(Components::count_fe_functions());
112 for (uint c = 0; c < Components::count_fe_functions(); ++c) {
113 ComponentMask component_mask(Components::count_fe_functions(), false);
114 component_mask.set(c, true);
115 component_boundary_dofs[c] = DoFTools::extract_boundary_dofs(dof_handler, component_mask);
116 }
117 std::vector<std::vector<Point<dim>>> component_boundary_points(Components::count_fe_functions());
118 for (uint c = 0; c < Components::count_fe_functions(); ++c) {
119 component_boundary_points[c].resize(component_boundary_dofs[c].n_elements());
120 for (uint i = 0; i < component_boundary_dofs[c].n_elements(); ++i)
121 component_boundary_points[c][i] =
122 discretization.get_support_point(component_boundary_dofs[c].nth_index_in_set(i));
123 }
124
125 auto &constraints = discretization.get_constraints();
126 constraints.clear();
127 DoFTools::make_hanging_node_constraints(dof_handler, constraints);
128 model.affine_constraints(constraints, component_boundary_dofs, component_boundary_points);
129 constraints.close();
130 }
131
132 virtual void rebuild_jacobian_sparsity() = 0;
133
134 virtual void set_time(double t) override { model.set_time(t); }
135
136 virtual void refinement_indicator(Vector<double> & /*indicator*/, const VectorType & /*solution*/) = 0;
137
138 virtual void residual_variables(VectorType &residual, const VectorType &variables,
139 const VectorType &spatial_solution) override
140 {
141 Timer timer;
142 std::array<NumberType, Components::count_extractors()> __extracted_data{{}};
143 if constexpr (Components::count_extractors() > 0)
144 extract(__extracted_data, spatial_solution, variables, true, false, false);
145 const auto &extracted_data = __extracted_data;
146 model.dt_variables(residual, v_tie(variables, extracted_data));
147 Kokkos::fence();
148 timings_variable_residual.push_back(timer.wall_time());
149 };
150 virtual void jacobian_variables(FullMatrix<NumberType> &jacobian, const VectorType &variables,
151 const VectorType &spatial_solution) override
152 {
153 Timer timer;
154 std::array<NumberType, Components::count_extractors()> __extracted_data{{}};
155 if constexpr (Components::count_extractors() > 0)
156 extract(__extracted_data, spatial_solution, variables, true, false, false);
157 const auto &extracted_data = __extracted_data;
158 model.template jacobian_variables<0>(jacobian, v_tie(variables, extracted_data));
159 Kokkos::fence();
160 timings_variable_jacobian.push_back(timer.wall_time());
161 };
162
163 void readouts(DataOutput<dim, VectorType> &data_out, const VectorType &solution_global,
164 const VectorType &variables) const
165 {
166 auto helper = [&](auto EoMfun, auto outputter) {
167 auto EoM_cell = this->EoM_cell;
168 auto EoM = get_EoM_point(
169 EoM_cell, solution_global, dof_handler, mapping, EoMfun, [&](const auto &p, const auto &) { return p; },
171 auto EoM_unit = mapping.transform_real_to_unit_cell(EoM_cell, EoM);
172
173 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
174 std::vector<Tensor<1, dim, typename VectorType::value_type>> gradients(dof_handler.get_fe().n_components());
175
176 FEValues<dim> fe_v(mapping, fe, EoM_unit,
177 update_values | update_gradients | update_quadrature_points | update_JxW_values |
178 update_hessians);
179 fe_v.reinit(EoM_cell);
180
181 std::vector<Vector<NumberType>> solution{Vector<NumberType>(Components::count_fe_functions())};
182 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad{
183 std::vector<Tensor<1, dim, NumberType>>(Components::count_fe_functions())};
184 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess{
185 std::vector<Tensor<2, dim, NumberType>>(Components::count_fe_functions())};
186 fe_v.get_function_values(solution_global, solution);
187 fe_v.get_function_gradients(solution_global, solution_grad);
188 fe_v.get_function_hessians(solution_global, solution_hess);
189
190 std::array<NumberType, Components::count_extractors()> __extracted_data{{}};
191 if constexpr (Components::count_extractors() > 0)
192 extract(__extracted_data, solution_global, variables, true, false, false);
193 const auto &extracted_data = __extracted_data;
194
195 outputter(data_out, EoM, e_tie(solution[0], solution_grad[0], solution_hess[0], extracted_data, variables));
196 };
197 model.readouts_multiple(helper, data_out);
198 }
199
200 void extract(std::array<NumberType, Components::count_extractors()> &data, const VectorType &solution_global,
201 const VectorType &variables, bool search_EoM, bool set_EoM, bool postprocess) const
202 {
203 auto EoM = this->EoM;
204 auto EoM_cell = this->EoM_cell;
205 if (search_EoM || EoM_cell == *(dof_handler.active_cell_iterators().end()))
207 EoM_cell, solution_global, dof_handler, mapping,
208 [&](const auto &p, const auto &values) { return model.EoM(p, values); },
209 [&](const auto &p, const auto &values) { return postprocess ? model.EoM_postprocess(p, values) : p; },
211 if (set_EoM) {
212 this->EoM = EoM;
213 this->EoM_cell = EoM_cell;
214 }
215 auto EoM_unit = mapping.transform_real_to_unit_cell(EoM_cell, EoM);
216
217 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
218 std::vector<Tensor<1, dim, typename VectorType::value_type>> gradients(dof_handler.get_fe().n_components());
219
220 FEValues<dim> fe_v(mapping, fe, EoM_unit,
221 update_values | update_gradients | update_quadrature_points | update_JxW_values |
222 update_hessians);
223 fe_v.reinit(EoM_cell);
224
225 std::vector<Vector<NumberType>> solution{Vector<NumberType>(Components::count_fe_functions())};
226 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad{
227 std::vector<Tensor<1, dim, NumberType>>(Components::count_fe_functions())};
228 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess{
229 std::vector<Tensor<2, dim, NumberType>>(Components::count_fe_functions())};
230 fe_v.get_function_values(solution_global, solution);
231 fe_v.get_function_gradients(solution_global, solution_grad);
232 fe_v.get_function_hessians(solution_global, solution_hess);
233
234 model.extract(data, EoM, e_tie(solution[0], solution_grad[0], solution_hess[0], nothing, variables));
235 }
236
237 bool jacobian_extractors(FullMatrix<NumberType> &extractor_jacobian, const VectorType &solution_global,
238 const VectorType &variables)
239 {
240 if (extractor_jacobian_u.m() != Components::count_extractors() ||
241 extractor_jacobian_u.n() != Components::count_fe_functions())
242 extractor_jacobian_u = FullMatrix<NumberType>(Components::count_extractors(), Components::count_fe_functions());
243 if (extractor_jacobian_du.m() != Components::count_extractors() ||
244 extractor_jacobian_du.n() != Components::count_fe_functions() * dim)
246 FullMatrix<NumberType>(Components::count_extractors(), Components::count_fe_functions() * dim);
247 if (extractor_jacobian_ddu.m() != Components::count_extractors() ||
248 extractor_jacobian_ddu.n() != Components::count_fe_functions() * dim * dim)
250 FullMatrix<NumberType>(Components::count_extractors(), Components::count_fe_functions() * dim * dim);
251
253 EoM_cell, solution_global, dof_handler, mapping,
254 [&](const auto &p, const auto &values) { return model.EoM(p, values); },
255 [&](const auto &p, const auto &values) { return model.EoM_postprocess(p, values); }, EoM_abs_tol,
257 auto EoM_unit = mapping.transform_real_to_unit_cell(EoM_cell, EoM);
258 bool new_cell = (old_EoM_cell != EoM_cell);
260
261 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
262 std::vector<Tensor<1, dim, typename VectorType::value_type>> gradients(dof_handler.get_fe().n_components());
263
264 FEValues<dim> fe_v(mapping, fe, EoM_unit,
265 update_values | update_gradients | update_quadrature_points | update_JxW_values |
266 update_hessians);
267 fe_v.reinit(EoM_cell);
268
269 const uint n_dofs = fe_v.get_fe().n_dofs_per_cell();
270 if (new_cell) {
271 // spdlog::get("log")->info("FEM: Rebuilding the jacobian sparsity pattern");
272 extractor_dof_indices.resize(n_dofs);
273 EoM_cell->get_dof_indices(extractor_dof_indices);
275 }
276
277 std::vector<Vector<NumberType>> solution{Vector<NumberType>(Components::count_fe_functions())};
278 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad{
279 std::vector<Tensor<1, dim, NumberType>>(Components::count_fe_functions())};
280 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess{
281 std::vector<Tensor<2, dim, NumberType>>(Components::count_fe_functions())};
282 fe_v.get_function_values(solution_global, solution);
283 fe_v.get_function_gradients(solution_global, solution_grad);
284 fe_v.get_function_hessians(solution_global, solution_hess);
285
290 e_tie(solution[0], solution_grad[0], solution_hess[0], nothing, variables));
292 e_tie(solution[0], solution_grad[0], solution_hess[0], nothing, variables));
294 e_tie(solution[0], solution_grad[0], solution_hess[0], nothing, variables));
295
296 if (extractor_jacobian.m() != Components::count_extractors() || extractor_jacobian.n() != n_dofs)
297 extractor_jacobian = FullMatrix<NumberType>(Components::count_extractors(), n_dofs);
298
299 for (uint e = 0; e < Components::count_extractors(); ++e)
300 for (uint i = 0; i < n_dofs; ++i) {
301 const auto component_i = fe_v.get_fe().system_to_component_index(i).first;
302 extractor_jacobian(e, i) =
303 extractor_jacobian_u(e, component_i) * fe_v.shape_value_component(i, 0, component_i);
304 for (uint d1 = 0; d1 < dim; ++d1) {
305 extractor_jacobian(e, i) +=
306 extractor_jacobian_du(e, component_i * dim + d1) * fe_v.shape_grad_component(i, 0, component_i)[d1];
307 for (uint d2 = 0; d2 < dim; ++d2)
308 extractor_jacobian(e, i) += extractor_jacobian_ddu(e, component_i * dim * dim + d1 * dim + d2) *
309 fe_v.shape_hessian_component(i, 0, component_i)[d1][d2];
310 }
311 }
312
313 return new_cell;
314 }
315
317 {
318 double t = 0.;
319 double n = timings_variable_residual.size();
320 for (const auto &t_ : timings_variable_residual)
321 t += t_ / n;
322 return t;
323 }
325
327 {
328 double t = 0.;
329 double n = timings_variable_jacobian.size();
330 for (const auto &t_ : timings_variable_jacobian)
331 t += t_ / n;
332 return t;
333 }
335
336 protected:
339 const FiniteElement<dim> &fe;
340 const DoFHandler<dim> &dof_handler;
341 const Mapping<dim> &mapping;
342
345
346 mutable typename DoFHandler<dim>::cell_iterator EoM_cell;
347 typename DoFHandler<dim>::cell_iterator old_EoM_cell;
348 const double EoM_abs_tol;
350 mutable Point<dim> EoM;
351 FullMatrix<NumberType> extractor_jacobian;
352 FullMatrix<NumberType> extractor_jacobian_u;
353 FullMatrix<NumberType> extractor_jacobian_du;
354 FullMatrix<NumberType> extractor_jacobian_ddu;
355 std::vector<types::global_dof_index> extractor_dof_indices;
356
357 std::vector<double> timings_variable_residual;
358 std::vector<double> timings_variable_jacobian;
359 };
360} // namespace DiFfRG
This is the general assembler interface for any kind of discretization. An assembler is responsible f...
Definition abstract_assembler.hh:39
void jacobian(SparseMatrixType &jacobian, const VectorType &solution_global, NumberType weight, NumberType mass_weight, const VectorType &variables=VectorType())
Definition abstract_assembler.hh:251
void residual(VectorType &residual, const VectorType &solution_global, NumberType weight, NumberType weight_mass, const VectorType &variables=VectorType())
Definition abstract_assembler.hh:177
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 ....
The basic assembler that can be used for any standard CG scheme with flux and source.
Definition common.hh:39
uint num_variable_jacobians() const
Definition common.hh:334
Model & model
Definition common.hh:338
const auto & get_discretization() const
Definition common.hh:105
typename Discretization::NumberType NumberType
Definition common.hh:58
const Mapping< dim > & mapping
Definition common.hh:341
static constexpr auto v_tie(T &&...t)
Definition common.hh:43
virtual void residual_variables(VectorType &residual, const VectorType &variables, const VectorType &spatial_solution) override
Definition common.hh:138
double average_time_variable_jacobian_assembly()
Definition common.hh:326
const uint EoM_max_iter
Definition common.hh:349
uint num_variable_residuals() const
Definition common.hh:324
const double EoM_abs_tol
Definition common.hh:348
FullMatrix< NumberType > extractor_jacobian
Definition common.hh:351
virtual void set_time(double t) override
Set the current time. The assembler should usually just forward this to the numerical model.
Definition common.hh:134
double average_time_variable_residual_assembly()
Definition common.hh:316
static constexpr uint dim
Definition common.hh:62
const FiniteElement< dim > & fe
Definition common.hh:339
void extract(std::array< NumberType, Components::count_extractors()> &data, const VectorType &solution_global, const VectorType &variables, bool search_EoM, bool set_EoM, bool postprocess) const
Definition common.hh:200
typename Discretization::Components Components
Definition common.hh:61
bool jacobian_extractors(FullMatrix< NumberType > &extractor_jacobian, const VectorType &solution_global, const VectorType &variables)
Definition common.hh:237
FullMatrix< NumberType > extractor_jacobian_du
Definition common.hh:353
DoFHandler< dim >::cell_iterator EoM_cell
Definition common.hh:346
virtual void refinement_indicator(Vector< double > &, const VectorType &)=0
uint threads
Definition common.hh:343
void readouts(DataOutput< dim, VectorType > &data_out, const VectorType &solution_global, const VectorType &variables) const
Definition common.hh:163
Point< dim > EoM
Definition common.hh:350
virtual void jacobian_variables(FullMatrix< NumberType > &jacobian, const VectorType &variables, const VectorType &spatial_solution) override
Definition common.hh:150
FullMatrix< NumberType > extractor_jacobian_ddu
Definition common.hh:354
Model_ Model
Definition common.hh:57
std::vector< double > timings_variable_jacobian
Definition common.hh:358
DoFHandler< dim >::cell_iterator old_EoM_cell
Definition common.hh:347
std::vector< double > timings_variable_residual
Definition common.hh:357
auto & get_discretization()
Definition common.hh:106
virtual void reinit() override
Reinitialize the assembler. This is necessary if the mesh has changed, e.g. after a mesh refinement.
Definition common.hh:108
const DoFHandler< dim > & dof_handler
Definition common.hh:340
typename Discretization::VectorType VectorType
Definition common.hh:59
Discretization & discretization
Definition common.hh:337
virtual IndexSet get_differential_indices() const override
Obtain the dofs which contain time derivatives.
Definition common.hh:77
uint batch_size
Definition common.hh:344
static constexpr auto e_tie(T &&...t)
Definition common.hh:48
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
Definition common.hh:83
std::vector< types::global_dof_index > extractor_dof_indices
Definition common.hh:355
virtual void rebuild_jacobian_sparsity()=0
FullMatrix< NumberType > extractor_jacobian_u
Definition common.hh:352
static constexpr int nothing
Definition common.hh:41
Discretization_ Discretization
Definition common.hh:56
FEMAssembler(Discretization &discretization, Model &model, const JSONValue &json)
Definition common.hh:64
A wrapper around the boost json value class.
Definition json.hh:19
Definition complex_math.hh:10
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:674
unsigned int uint
Definition utils.hh:24
Definition tuples.hh:34
A class to store a tuple with elements that can be accessed by name. The names are stored as FixedStr...
Definition tuples.hh:56