DiFfRG
Loading...
Searching...
No Matches
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 &...>, "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 &...>, "fe_functions", "fe_derivatives", "fe_hessians", "extractors",
51 "variables">(std::tie(t...));
52 }
53
54 public:
55 using Discretization = Discretization_;
56 using Model = Model_;
57 using NumberType = typename Discretization::NumberType;
58 using VectorType = typename Discretization::VectorType;
59
60 using Components = typename Discretization::Components;
61 static constexpr uint dim = Discretization::dim;
62
65 dof_handler(discretization.get_dof_handler()), mapping(discretization.get_mapping()),
66 threads(json.get_uint("/discretization/threads")), batch_size(json.get_uint("/discretization/batch_size")),
67 EoM_cell(*(dof_handler.active_cell_iterators().end())),
68 old_EoM_cell(*(dof_handler.active_cell_iterators().end())),
69 EoM_abs_tol(json.get_double("/discretization/EoM_abs_tol")),
70 EoM_max_iter(json.get_uint("/discretization/EoM_max_iter"))
71 {
72 if (this->threads == 0) this->threads = dealii::MultithreadInfo::n_threads() / 2;
73 spdlog::get("log")->info("FEM: Using {} threads for assembly.", threads);
74 }
75
76 virtual IndexSet get_differential_indices() const override
77 {
78 ComponentMask component_mask(model.template differential_components<dim>());
79 return DoFTools::extract_dofs(dof_handler, component_mask);
80 }
81
82 virtual void attach_data_output(DataOutput<dim, VectorType> &data_out, const VectorType &solution,
83 const VectorType &variables, const VectorType &dt_solution = VectorType(),
84 const VectorType &residual = VectorType()) override
85 {
86 const auto fe_function_names = Components::FEFunction_Descriptor::get_names_vector();
87 std::vector<std::string> fe_function_names_residual;
88 for (const auto &name : fe_function_names)
89 fe_function_names_residual.push_back(name + "_residual");
90 std::vector<std::string> fe_function_names_dot;
91 for (const auto &name : fe_function_names)
92 fe_function_names_dot.push_back(name + "_dot");
93
94 auto &fe_out = data_out.fe_output();
95 fe_out.attach(dof_handler, solution, fe_function_names);
96 if (dt_solution.size() > 0) fe_out.attach(dof_handler, dt_solution, fe_function_names_dot);
97 if (residual.size() > 0) fe_out.attach(dof_handler, residual, fe_function_names_residual);
98
99 readouts(data_out, solution, variables);
100 }
101
102 const auto &get_discretization() const { return discretization; }
104
105 virtual void reinit() override
106 {
107 // Boundary dofs
108 std::vector<IndexSet> component_boundary_dofs(Components::count_fe_functions());
109 for (uint c = 0; c < Components::count_fe_functions(); ++c) {
110 ComponentMask component_mask(Components::count_fe_functions(), false);
111 component_mask.set(c, true);
112 component_boundary_dofs[c] = DoFTools::extract_boundary_dofs(dof_handler, component_mask);
113 }
114 std::vector<std::vector<Point<dim>>> component_boundary_points(Components::count_fe_functions());
115 for (uint c = 0; c < Components::count_fe_functions(); ++c) {
116 component_boundary_points[c].resize(component_boundary_dofs[c].n_elements());
117 for (uint i = 0; i < component_boundary_dofs[c].n_elements(); ++i)
118 component_boundary_points[c][i] =
119 discretization.get_support_point(component_boundary_dofs[c].nth_index_in_set(i));
120 }
121
122 auto &constraints = discretization.get_constraints();
123 constraints.clear();
124 DoFTools::make_hanging_node_constraints(dof_handler, constraints);
125 model.affine_constraints(constraints, component_boundary_dofs, component_boundary_points);
126 constraints.close();
127 }
128
129 virtual void rebuild_jacobian_sparsity() = 0;
130
131 virtual void set_time(double t) override { model.set_time(t); }
132
133 virtual void refinement_indicator(Vector<double> & /*indicator*/, const VectorType & /*solution*/) = 0;
134
135 virtual void residual_variables(VectorType &residual, const VectorType &variables,
136 const VectorType &spatial_solution) override
137 {
138 Timer timer;
139 std::array<NumberType, Components::count_extractors()> __extracted_data{{}};
140 if constexpr (Components::count_extractors() > 0)
141 extract(__extracted_data, spatial_solution, variables, true, false, false);
142 const auto &extracted_data = __extracted_data;
143 model.dt_variables(residual, v_tie(variables, extracted_data));
144 timings_variable_residual.push_back(timer.wall_time());
145 };
146 virtual void jacobian_variables(FullMatrix<NumberType> &jacobian, const VectorType &variables,
147 const VectorType &spatial_solution) override
148 {
149 Timer timer;
150 std::array<NumberType, Components::count_extractors()> __extracted_data{{}};
151 if constexpr (Components::count_extractors() > 0)
152 extract(__extracted_data, spatial_solution, variables, true, false, false);
153 const auto &extracted_data = __extracted_data;
154 model.template jacobian_variables<0>(jacobian, v_tie(variables, extracted_data));
155 timings_variable_jacobian.push_back(timer.wall_time());
156 };
157
158 void readouts(DataOutput<dim, VectorType> &data_out, const VectorType &solution_global,
159 const VectorType &variables) const
160 {
161 auto helper = [&](auto EoMfun, auto outputter) {
162 auto EoM_cell = this->EoM_cell;
163 auto EoM = get_EoM_point(
164 EoM_cell, solution_global, dof_handler, mapping, EoMfun, [&](const auto &p, const auto &) { return p; },
166 auto EoM_unit = mapping.transform_real_to_unit_cell(EoM_cell, EoM);
167
168 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
169 std::vector<Tensor<1, dim, typename VectorType::value_type>> gradients(dof_handler.get_fe().n_components());
170
171 FEValues<dim> fe_v(mapping, fe, EoM_unit,
172 update_values | update_gradients | update_quadrature_points | update_JxW_values |
173 update_hessians);
174 fe_v.reinit(EoM_cell);
175
176 std::vector<Vector<NumberType>> solution{Vector<NumberType>(Components::count_fe_functions())};
177 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad{
178 std::vector<Tensor<1, dim, NumberType>>(Components::count_fe_functions())};
179 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess{
180 std::vector<Tensor<2, dim, NumberType>>(Components::count_fe_functions())};
181 fe_v.get_function_values(solution_global, solution);
182 fe_v.get_function_gradients(solution_global, solution_grad);
183 fe_v.get_function_hessians(solution_global, solution_hess);
184
185 std::array<NumberType, Components::count_extractors()> __extracted_data{{}};
186 if constexpr (Components::count_extractors() > 0)
187 extract(__extracted_data, solution_global, variables, true, false, false);
188 const auto &extracted_data = __extracted_data;
189
190 outputter(data_out, EoM, e_tie(solution[0], solution_grad[0], solution_hess[0], extracted_data, variables));
191 };
192 model.template readouts_multiple(helper, data_out);
193 }
194
195 void extract(std::array<NumberType, Components::count_extractors()> &data, const VectorType &solution_global,
196 const VectorType &variables, bool search_EoM, bool set_EoM, bool postprocess) const
197 {
198 auto EoM = this->EoM;
199 auto EoM_cell = this->EoM_cell;
200 if (search_EoM || EoM_cell == *(dof_handler.active_cell_iterators().end()))
202 EoM_cell, solution_global, dof_handler, mapping,
203 [&](const auto &p, const auto &values) { return model.EoM(p, values); },
204 [&](const auto &p, const auto &values) { return postprocess ? model.EoM_postprocess(p, values) : p; },
206 if (set_EoM) {
207 this->EoM = EoM;
208 this->EoM_cell = EoM_cell;
209 }
210 auto EoM_unit = mapping.transform_real_to_unit_cell(EoM_cell, EoM);
211
212 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
213 std::vector<Tensor<1, dim, typename VectorType::value_type>> gradients(dof_handler.get_fe().n_components());
214
215 FEValues<dim> fe_v(mapping, fe, EoM_unit,
216 update_values | update_gradients | update_quadrature_points | update_JxW_values |
217 update_hessians);
218 fe_v.reinit(EoM_cell);
219
220 std::vector<Vector<NumberType>> solution{Vector<NumberType>(Components::count_fe_functions())};
221 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad{
222 std::vector<Tensor<1, dim, NumberType>>(Components::count_fe_functions())};
223 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess{
224 std::vector<Tensor<2, dim, NumberType>>(Components::count_fe_functions())};
225 fe_v.get_function_values(solution_global, solution);
226 fe_v.get_function_gradients(solution_global, solution_grad);
227 fe_v.get_function_hessians(solution_global, solution_hess);
228
229 model.template extract(data, EoM, e_tie(solution[0], solution_grad[0], solution_hess[0], nothing, variables));
230 }
231
232 bool jacobian_extractors(FullMatrix<NumberType> &extractor_jacobian, const VectorType &solution_global,
233 const VectorType &variables)
234 {
235 if (extractor_jacobian_u.m() != Components::count_extractors() ||
236 extractor_jacobian_u.n() != Components::count_fe_functions())
237 extractor_jacobian_u = FullMatrix<NumberType>(Components::count_extractors(), Components::count_fe_functions());
238 if (extractor_jacobian_du.m() != Components::count_extractors() ||
239 extractor_jacobian_du.n() != Components::count_fe_functions() * dim)
241 FullMatrix<NumberType>(Components::count_extractors(), Components::count_fe_functions() * dim);
242 if (extractor_jacobian_ddu.m() != Components::count_extractors() ||
243 extractor_jacobian_ddu.n() != Components::count_fe_functions() * dim * dim)
245 FullMatrix<NumberType>(Components::count_extractors(), Components::count_fe_functions() * dim * dim);
246
248 EoM_cell, solution_global, dof_handler, mapping,
249 [&](const auto &p, const auto &values) { return model.EoM(p, values); },
250 [&](const auto &p, const auto &values) { return model.EoM_postprocess(p, values); }, EoM_abs_tol,
252 auto EoM_unit = mapping.transform_real_to_unit_cell(EoM_cell, EoM);
253 bool new_cell = (old_EoM_cell != EoM_cell);
255
256 Vector<typename VectorType::value_type> values(dof_handler.get_fe().n_components());
257 std::vector<Tensor<1, dim, typename VectorType::value_type>> gradients(dof_handler.get_fe().n_components());
258
259 FEValues<dim> fe_v(mapping, fe, EoM_unit,
260 update_values | update_gradients | update_quadrature_points | update_JxW_values |
261 update_hessians);
262 fe_v.reinit(EoM_cell);
263
264 const uint n_dofs = fe_v.get_fe().n_dofs_per_cell();
265 if (new_cell) {
266 // spdlog::get("log")->info("FEM: Rebuilding the jacobian sparsity pattern");
267 extractor_dof_indices.resize(n_dofs);
268 EoM_cell->get_dof_indices(extractor_dof_indices);
270 }
271
272 std::vector<Vector<NumberType>> solution{Vector<NumberType>(Components::count_fe_functions())};
273 std::vector<std::vector<Tensor<1, dim, NumberType>>> solution_grad{
274 std::vector<Tensor<1, dim, NumberType>>(Components::count_fe_functions())};
275 std::vector<std::vector<Tensor<2, dim, NumberType>>> solution_hess{
276 std::vector<Tensor<2, dim, NumberType>>(Components::count_fe_functions())};
277 fe_v.get_function_values(solution_global, solution);
278 fe_v.get_function_gradients(solution_global, solution_grad);
279 fe_v.get_function_hessians(solution_global, solution_hess);
280
285 e_tie(solution[0], solution_grad[0], solution_hess[0], nothing, variables));
287 e_tie(solution[0], solution_grad[0], solution_hess[0], nothing, variables));
289 e_tie(solution[0], solution_grad[0], solution_hess[0], nothing, variables));
290
291 if (extractor_jacobian.m() != Components::count_extractors() || extractor_jacobian.n() != n_dofs)
292 extractor_jacobian = FullMatrix<NumberType>(Components::count_extractors(), n_dofs);
293
294 for (uint e = 0; e < Components::count_extractors(); ++e)
295 for (uint i = 0; i < n_dofs; ++i) {
296 const auto component_i = fe_v.get_fe().system_to_component_index(i).first;
297 extractor_jacobian(e, i) =
298 extractor_jacobian_u(e, component_i) * fe_v.shape_value_component(i, 0, component_i);
299 for (uint d1 = 0; d1 < dim; ++d1) {
300 extractor_jacobian(e, i) +=
301 extractor_jacobian_du(e, component_i * dim + d1) * fe_v.shape_grad_component(i, 0, component_i)[d1];
302 for (uint d2 = 0; d2 < dim; ++d2)
303 extractor_jacobian(e, i) += extractor_jacobian_ddu(e, component_i * dim * dim + d1 * dim + d2) *
304 fe_v.shape_hessian_component(i, 0, component_i)[d1][d2];
305 }
306 }
307
308 return new_cell;
309 }
310
312 {
313 double t = 0.;
314 double n = timings_variable_residual.size();
315 for (const auto &t_ : timings_variable_residual)
316 t += t_ / n;
317 return t;
318 }
320
322 {
323 double t = 0.;
324 double n = timings_variable_jacobian.size();
325 for (const auto &t_ : timings_variable_jacobian)
326 t += t_ / n;
327 return t;
328 }
330
331 protected:
334 const FiniteElement<dim> &fe;
335 const DoFHandler<dim> &dof_handler;
336 const Mapping<dim> &mapping;
337
340
341 mutable typename DoFHandler<dim>::cell_iterator EoM_cell;
342 typename DoFHandler<dim>::cell_iterator old_EoM_cell;
343 const double EoM_abs_tol;
345 mutable Point<dim> EoM;
346 FullMatrix<NumberType> extractor_jacobian;
347 FullMatrix<NumberType> extractor_jacobian_u;
348 FullMatrix<NumberType> extractor_jacobian_du;
349 FullMatrix<NumberType> extractor_jacobian_ddu;
350 std::vector<types::global_dof_index> extractor_dof_indices;
351
352 std::vector<double> timings_variable_residual;
353 std::vector<double> timings_variable_jacobian;
354 };
355} // 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:329
Model & model
Definition common.hh:333
const auto & get_discretization() const
Definition common.hh:102
typename Discretization::NumberType NumberType
Definition common.hh:57
const Mapping< dim > & mapping
Definition common.hh:336
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:135
double average_time_variable_jacobian_assembly()
Definition common.hh:321
const uint EoM_max_iter
Definition common.hh:344
uint num_variable_residuals() const
Definition common.hh:319
const double EoM_abs_tol
Definition common.hh:343
FullMatrix< NumberType > extractor_jacobian
Definition common.hh:346
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:131
double average_time_variable_residual_assembly()
Definition common.hh:311
static constexpr uint dim
Definition common.hh:61
const FiniteElement< dim > & fe
Definition common.hh:334
void extract(std::array< NumberType, Components::count_extractors()> &data, const VectorType &solution_global, const VectorType &variables, bool search_EoM, bool set_EoM, bool postprocess) const
Definition common.hh:195
typename Discretization::Components Components
Definition common.hh:60
bool jacobian_extractors(FullMatrix< NumberType > &extractor_jacobian, const VectorType &solution_global, const VectorType &variables)
Definition common.hh:232
FullMatrix< NumberType > extractor_jacobian_du
Definition common.hh:348
DoFHandler< dim >::cell_iterator EoM_cell
Definition common.hh:341
virtual void refinement_indicator(Vector< double > &, const VectorType &)=0
uint threads
Definition common.hh:338
void readouts(DataOutput< dim, VectorType > &data_out, const VectorType &solution_global, const VectorType &variables) const
Definition common.hh:158
Point< dim > EoM
Definition common.hh:345
virtual void jacobian_variables(FullMatrix< NumberType > &jacobian, const VectorType &variables, const VectorType &spatial_solution) override
Definition common.hh:146
FullMatrix< NumberType > extractor_jacobian_ddu
Definition common.hh:349
Model_ Model
Definition common.hh:56
std::vector< double > timings_variable_jacobian
Definition common.hh:353
DoFHandler< dim >::cell_iterator old_EoM_cell
Definition common.hh:342
std::vector< double > timings_variable_residual
Definition common.hh:352
auto & get_discretization()
Definition common.hh:103
virtual void reinit() override
Reinitialize the assembler. This is necessary if the mesh has changed, e.g. after a mesh refinement.
Definition common.hh:105
const DoFHandler< dim > & dof_handler
Definition common.hh:335
typename Discretization::VectorType VectorType
Definition common.hh:58
Discretization & discretization
Definition common.hh:332
virtual IndexSet get_differential_indices() const override
Obtain the dofs which contain time derivatives.
Definition common.hh:76
uint batch_size
Definition common.hh:339
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:82
std::vector< types::global_dof_index > extractor_dof_indices
Definition common.hh:350
virtual void rebuild_jacobian_sparsity()=0
FullMatrix< NumberType > extractor_jacobian_u
Definition common.hh:347
static constexpr int nothing
Definition common.hh:41
Discretization_ Discretization
Definition common.hh:55
FEMAssembler(Discretization &discretization, Model &model, const JSONValue &json)
Definition common.hh:63
A wrapper around the boost json value class.
Definition json.hh:19
Definition complex_math.hh:14
dealii::Point< dim > get_EoM_point(typename dealii::DoFHandler< dim >::cell_iterator &EoM_cell, const VectorType &sol, const dealii::DoFHandler< dim > &dof_handler, const dealii::Mapping< dim > &mapping, const EoMFUN &get_EoM, const EoMPFUN &EoM_postprocess=[](const auto &p, const auto &values) { return p;}, const double EoM_abs_tol=1e-5, const uint max_iter=100)
Get the EoM point for a given solution and model.
Definition EoM.hh:662
unsigned int uint
Definition utils.hh:22
A class to store a tuple with elements that can be accessed by name. The names are stored as FixedStr...
Definition tuples.hh:27