FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
space_transfer.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8// includes, FEAT
11#include <kernel/util/math.hpp>
12#include <kernel/lafem/base.hpp>
13#include <kernel/assembly/asm_traits.hpp>
14#include <kernel/trafo/inverse_mapping.hpp>
15#include <kernel/geometry/mesh_permutation.hpp>
16
17
18
19namespace FEAT
20{
21 namespace Assembly
22 {
24 {
25 public:
33 public FEAT::Exception
34 {
35 public:
37 Exception("local mass matrix inversion error")
38 {
39 }
40 }; // class LocalMassMatrixSingularException
41
65 template<
66 typename Matrix_,
67 typename Vector_,
68 typename TargetSpace_,
69 typename SourceSpace_>
70 static void assemble_transfer(
71 Matrix_& matrix,
72 Vector_& vector,
73 const TargetSpace_& target_space,
74 const SourceSpace_& source_space,
75 const String& cubature_name)
76 {
77 // source and target space must be defined on the same trafo and therefore on the same mesh
78 XASSERTM(&target_space.get_trafo() == &source_space.get_trafo(), "source and target space must be defined on the same trafo");
79
80 // validate matrix and vector dimensions
81 XASSERTM(matrix.rows() == target_space.get_num_dofs(), "invalid matrix dimensions");
82 XASSERTM(matrix.columns() == source_space.get_num_dofs(), "invalid matrix dimensions");
83 XASSERTM(vector.size() == target_space.get_num_dofs(), "invalid vector size");
84
85 typedef typename Matrix_::DataType DataType;
86
87 // typedefs for trafos, mesh and shape
88 typedef typename TargetSpace_::TrafoType TrafoType;
89 typedef typename SourceSpace_::ShapeType ShapeType;
90
91 // typedefs for dof-mappings
92 typedef typename TargetSpace_::DofMappingType TargetDofMapping;
93 typedef typename SourceSpace_::DofMappingType SourceDofMapping;
94
95 // typedefs for trafo evaluators
96 typedef typename TrafoType::template Evaluator<ShapeType, DataType>::Type TrafoEvaluator;
97
98 // typedefs for space evaluators
99 typedef typename TargetSpace_::template Evaluator<TrafoEvaluator>::Type TargetSpaceEvaluator;
100 typedef typename SourceSpace_::template Evaluator<TrafoEvaluator>::Type SourceSpaceEvaluator;
101
102 // define fine and coarse mesh trafo configurations
103 typedef typename TargetSpaceEvaluator::template ConfigTraits<SpaceTags::value> TargetSpaceConfigTraits;
104 typedef typename SourceSpaceEvaluator::template ConfigTraits<SpaceTags::value> SourceSpaceConfigTraits;
105 static constexpr TrafoTags trafo_config = TrafoTags::jac_det | TargetSpaceConfigTraits::trafo_config | SourceSpaceConfigTraits::trafo_config;
106
107 // typedefs for trafo data
108 typedef typename TrafoEvaluator::template ConfigTraits<trafo_config>::EvalDataType TrafoEvalData;
109 TrafoEvalData trafo_data;
110
111 // typedef for space data
112 typedef typename TargetSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType TargetSpaceEvalData;
113 typedef typename SourceSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType SourceSpaceEvalData;
114 TargetSpaceEvalData target_space_data;
115 SourceSpaceEvalData source_space_data;
116
117 // create matrix scatter-axpy
118 typename Matrix_::ScatterAxpy scatter_maxpy(matrix);
119 typename Vector_::ScatterAxpy scatter_vaxpy(vector);
120
121 // create DOF-mappings
122 TargetDofMapping target_dof_mapping(target_space);
123 SourceDofMapping source_dof_mapping(source_space);
124
125 // fetch the trafos
126 const TrafoType& trafo = target_space.get_trafo();
127
128 // create trafo evaluators
129 TrafoEvaluator trafo_eval(trafo);
130
131 // create space evaluators
132 TargetSpaceEvaluator target_space_eval(target_space);
133 SourceSpaceEvaluator source_space_eval(source_space);
134
135 // create the cubature rules
136 Cubature::DynamicFactory cubature_factory(cubature_name);
137 typename Intern::CubatureTraits<TrafoEvaluator>::RuleType cubature(Cubature::ctor_factory, cubature_factory);
138
139 // allocate fine-mesh mass matrix
141
142 // allocate local matrix data for inter-space mass matrix
144
145 // allocate local vector data for weight vector
147
148 // pivot array for factorization
149 int pivot[TargetSpaceEvaluator::max_local_dofs];
150
151 // loop over all coarse mesh cells
152 for(Index cell(0); cell < trafo_eval.get_num_cells(); ++cell)
153 {
154 // prepare trafo evaluator
155 trafo_eval.prepare(cell);
156
157 // prepare space evaluators
158 source_space_eval.prepare(trafo_eval);
159 target_space_eval.prepare(trafo_eval);
160
161 // fetch number of local DOFs
162 const int source_num_loc_dofs = source_space_eval.get_num_local_dofs();
163 const int target_num_loc_dofs = target_space_eval.get_num_local_dofs();
164
165 // prepare dof-mapping
166 source_dof_mapping.prepare(cell);
167 target_dof_mapping.prepare(cell);
168
169 // format local matrices
170 mass.format();
171 lmd.format();
172 lvd.format();
173
174 // loop over all cubature points and integrate
175 for(int k(0); k < cubature.get_num_points(); ++k)
176 {
177 // compute trafo data
178 trafo_eval(trafo_data, cubature.get_point(k));
179
180 // compute basis function data
181 target_space_eval(target_space_data, trafo_data);
182 source_space_eval(source_space_data, trafo_data);
183
184 // pre-compute cubature weight
185 const DataType omega = trafo_data.jac_det * cubature.get_weight(k);
186
187 // target mesh test function loop
188 for(int i(0); i < target_num_loc_dofs; ++i)
189 {
190 // target mesh trial function loop
191 for(int j(0); j < target_num_loc_dofs; ++j)
192 {
193 mass(i,j) += omega * target_space_data.phi[i].value * target_space_data.phi[j].value;
194 }
195
196 // source mesh trial function loop
197 for(int j(0); j < source_num_loc_dofs; ++j)
198 {
199 lmd(i,j) += omega * target_space_data.phi[i].value * source_space_data.phi[j].value;
200 }
201 }
202 }
203
204 // invert target space mass matrix
205 Math::invert_matrix(target_num_loc_dofs, mass.sn, &mass.v[0][0], pivot);
206
207 // Note:
208 // Usually, one would check whether the determinant returned by the invert_matrix
209 // function is normal. However, this can lead to false alerts when assembling in
210 // single precision, as the mass matrix entries are of magnitude h^2 (in 2D), i.e.
211 // the determinant can become subnormal or even (numerically) zero although the
212 // condition number of the matrix is still fine and the inversion was successful.
213 // Therefore, we first multiply the (hopefully) inverted mass matrix by the
214 // inter-level mass matrix and check whether the Frobenius norm of the result
215 // is normal. If our matrix inversion failed, the result is virtually guaranteed
216 // to be garbage, so this should serve well enough as a sanity check.
217
218 // compute X := M^{-1}*N
219 lid.set_mat_mat_mult(mass, lmd);
220
221 // sanity check for matrix inversion
224
225 // incorporate local matrix
226 scatter_maxpy(lid, target_dof_mapping, source_dof_mapping);
227
228 // update weights
229 lvd.format(DataType(1));
230 scatter_vaxpy(lvd, target_dof_mapping);
231
232 // finish dof-mappings
233 source_dof_mapping.finish();
234 target_dof_mapping.finish();
235
236 // finish evaluators
237 target_space_eval.finish();
238 source_space_eval.finish();
239 trafo_eval.finish();
240
241 // go for next coarse mesh cell
242 }
243 }
244
266 template<
267 typename Matrix_,
268 typename TargetSpace_,
269 typename SourceSpace_>
271 Matrix_& matrix,
272 const TargetSpace_& target_space,
273 const SourceSpace_& source_space,
274 const String& cubature_name)
275 {
276 // create a weight vector
277 auto weight = matrix.create_vector_l();
278 matrix.format();
279 weight.format();
280
281 // assemble matrix and weight
282 assemble_transfer(matrix, weight, target_space, source_space, cubature_name);
283
284 // scale prolongation matrix rows by inverse weights
285 weight.component_invert(weight);
286 matrix.scale_rows(matrix, weight);
287 }
288
321 template<
322 typename Vector_,
323 typename TargetSpace_,
324 typename SourceSpace_>
325 static void transfer_vector(
326 Vector_& vector_f,
327 Vector_& vector_w,
328 const Vector_& vector_c,
329 const TargetSpace_& target_space,
330 const SourceSpace_& source_space,
331 const String& cubature_name)
332 {
333 // source and target space must be defined on the same trafo and therefore on the same mesh
334 XASSERTM(&target_space.get_trafo() == &source_space.get_trafo(), "source and target space must be defined on the same trafo");
335
336 // validate matrix and vector dimensions
337 XASSERTM(vector_f.size() == vector_w.size(), "invalid vector sizes");
338 XASSERTM(vector_f.size() == target_space.get_num_dofs(), "invalid matrix dimensions");
339 XASSERTM(vector_c.size() == source_space.get_num_dofs(), "invalid matrix dimensions");
340 XASSERTM(vector_f.size() == target_space.get_num_dofs(), "invalid vector size");
341
342 typedef typename Vector_::DataType DataType;
343 typedef typename Vector_::ValueType ValueType;
344
345 // typedefs for trafos, mesh and shape
346 typedef typename TargetSpace_::TrafoType TrafoType;
347 typedef typename SourceSpace_::ShapeType ShapeType;
348
349 // typedefs for dof-mappings
350 typedef typename TargetSpace_::DofMappingType TargetDofMapping;
351 typedef typename SourceSpace_::DofMappingType SourceDofMapping;
352
353 // typedefs for trafo evaluators
354 typedef typename TrafoType::template Evaluator<ShapeType, DataType>::Type TrafoEvaluator;
355
356 // typedefs for space evaluators
357 typedef typename TargetSpace_::template Evaluator<TrafoEvaluator>::Type TargetSpaceEvaluator;
358 typedef typename SourceSpace_::template Evaluator<TrafoEvaluator>::Type SourceSpaceEvaluator;
359
360 // define target and source mesh trafo configurations
361 typedef typename TargetSpaceEvaluator::template ConfigTraits<SpaceTags::value> TargetSpaceConfigTraits;
362 typedef typename SourceSpaceEvaluator::template ConfigTraits<SpaceTags::value> SourceSpaceConfigTraits;
363 static constexpr TrafoTags target_trafo_config = TrafoTags::jac_det | TargetSpaceConfigTraits::trafo_config | SourceSpaceConfigTraits::trafo_config;
364
365 // typedefs for trafo data
366 typedef typename TrafoEvaluator::template ConfigTraits<target_trafo_config>::EvalDataType TrafoEvalData;
367 TrafoEvalData trafo_data;
368
369 // typedef for space data
370 typedef typename TargetSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType TargetSpaceEvalData;
371 typedef typename SourceSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType SourceSpaceEvalData;
372 TargetSpaceEvalData target_space_data;
373 SourceSpaceEvalData source_space_data;
374
375 // typedefs for cubature rule and factory
376 typedef typename Assembly::Intern::CubatureTraits<TrafoEvaluator>::RuleType CubatureRuleType;
377
378 // create gather/scatter-axpys
379 typename Vector_::GatherAxpy gather_c(vector_c);
380 typename Vector_::ScatterAxpy scatter_f(vector_f);
381 typename Vector_::ScatterAxpy scatter_w(vector_w);
382
383 // create DOF-mappings
384 TargetDofMapping target_dof_mapping(target_space);
385 SourceDofMapping source_dof_mapping(source_space);
386
387 // fetch the trafos
388 const TrafoType& trafo = target_space.get_trafo();
389
390 // create trafo evaluators
391 TrafoEvaluator trafo_eval(trafo);
392
393 // create space evaluators
394 TargetSpaceEvaluator target_space_eval(target_space);
395 SourceSpaceEvaluator source_space_eval(source_space);
396
397 // create the cubature rules
398 Cubature::DynamicFactory cubature_factory(cubature_name);
399 CubatureRuleType cubature(Cubature::ctor_factory, cubature_factory);
400
401 // allocate fine-mesh mass matrix
403
404 // allocate local matrix data for interlevel-mesh mass matrix
406
407 // allocate local vector data for weight/coarse/fine vector
410
411 // pivot array for factorization
412 int pivot[TargetSpaceEvaluator::max_local_dofs];
413
414 // loop over all coarse mesh cells
415 for(Index ccell(0); ccell < trafo_eval.get_num_cells(); ++ccell)
416 {
417 // prepare coarse trafo evaluator
418 trafo_eval.prepare(ccell);
419
420 // prepare coarse space evaluator
421 source_space_eval.prepare(trafo_eval);
422 target_space_eval.prepare(trafo_eval);
423
424 // prepare dof-mapping
425 source_dof_mapping.prepare(ccell);
426 target_dof_mapping.prepare(ccell);
427
428 // prepare coarse mesh dof-mapping
429 source_dof_mapping.prepare(ccell);
430
431 // fetch number of local coarse DOFs
432 const int source_num_loc_dofs = source_space_eval.get_num_local_dofs();
433 const int target_num_loc_dofs = target_space_eval.get_num_local_dofs();
434
435 // gather local coarse vector
436 lv_c.format();
437 gather_c(lv_c, source_dof_mapping);
438
439 // format local matrices
440 mass.format();
441 lmd.format();
442 lv_w.format();
443 lv_f.format();
444
445 // loop over all cubature points and integrate
446 for(int k(0); k < cubature.get_num_points(); ++k)
447 {
448 // compute trafo data
449 trafo_eval(trafo_data, cubature.get_point(k));
450
451 // compute basis function data
452 target_space_eval(target_space_data, trafo_data);
453 source_space_eval(source_space_data, trafo_data);
454
455 // pre-compute cubature weight
456 const DataType omega = trafo_data.jac_det * cubature.get_weight(k);
457
458 // target mesh test function loop
459 for(int i(0); i < target_num_loc_dofs; ++i)
460 {
461 // target mesh trial function loop
462 for(int j(0); j < target_num_loc_dofs; ++j)
463 {
464 mass(i,j) += omega * target_space_data.phi[i].value * target_space_data.phi[j].value;
465 }
466
467 // source mesh trial function loop
468 for(int j(0); j < source_num_loc_dofs; ++j)
469 {
470 lmd(i,j) += omega * target_space_data.phi[i].value * source_space_data.phi[j].value;
471 }
472 }
473 // go for next cubature point
474 }
475 // finish coarse mesh evaluators
476 target_space_eval.finish();
477 trafo_eval.finish();
478
479 // invert target mesh mass matrix
480 Math::invert_matrix(target_num_loc_dofs, mass.sn, &mass.v[0][0], pivot);
481
482 // Note:
483 // Usually, one would check whether the determinant returned by the invert_matrix
484 // function is normal. However, this can lead to false alerts when assembling in
485 // single precision, as the mass matrix entries are of magnitude h^2 (in 2D), i.e.
486 // the determinant can become subnormal or even (numerically) zero although the
487 // condition number of the matrix is still fine and the inversion was successful.
488 // Therefore, we first multiply the (hopefully) inverted mass matrix by the
489 // inter-level mass matrix and check whether the Frobenius norm of the result
490 // is normal. If our matrix inversion failed, the result is virtually guaranteed
491 // to be garbage, so this should serve well enough as a sanity check.
492 // compute X := M^{-1}*N
493
494 lid.set_mat_mat_mult(mass, lmd);
495
496 // sanity check for matrix inversion
499
500 // compute local target vector
501 lv_f.format();
502 for(int i(0); i < target_num_loc_dofs; ++i)
503 for(int j(0); j < source_num_loc_dofs; ++j)
504 lv_f[i] += lid[i][j] * lv_c[j];
505
506 // prepare target mesh dof-mapping
507 target_dof_mapping.prepare(ccell);
508
509 // scatter local target vector
510 scatter_f(lv_f, target_dof_mapping);
511
512 // update weights
513 lv_w.format(DataType(1));
514 scatter_w(lv_w, target_dof_mapping);
515
516 // finish target mesh dof-mapping
517 target_dof_mapping.finish();
518
519 // finish coarse mesh evaluators
520 source_space_eval.finish();
521 trafo_eval.finish();
522
523 // finish coarse mesh dof-mapping
524 source_dof_mapping.finish();
525
526 // go for next coarse mesh cell
527 }
528 }
529
553 template<
554 typename Vector_,
555 typename TargetSpace_,
556 typename SourceSpace_>
558 Vector_& vector_f,
559 const Vector_& vector_c,
560 const TargetSpace_& target_space,
561 const SourceSpace_& source_space,
562 const String& cubature_name)
563 {
564 Vector_ vector_w = vector_f.clone(LAFEM::CloneMode::Layout);
565 vector_w.format();
566
567 transfer_vector(vector_f, vector_w, vector_c, target_space, source_space, cubature_name);
568
569 // finally, scale target mesh vector by inverse weights
570 vector_w.component_invert(vector_w);
571 vector_f.component_product(vector_f, vector_w);
572 }
573 }; // class SpaceTransfer
574 } // namespace Assembly
575} // namespace FEAT
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
static void assemble_transfer(Matrix_ &matrix, Vector_ &vector, const TargetSpace_ &target_space, const SourceSpace_ &source_space, const String &cubature_name)
Assembles an inter-space transfer matrix and its corresponding weight vector.
static void assemble_transfer_direct(Matrix_ &matrix, const TargetSpace_ &target_space, const SourceSpace_ &source_space, const String &cubature_name)
Assembles an inter-space transfer matrix.
static void transfer_vector(Vector_ &vector_f, Vector_ &vector_w, const Vector_ &vector_c, const TargetSpace_ &target_space, const SourceSpace_ &source_space, const String &cubature_name)
Transfers a primal vector and assembles a compatible weight vector.
static void transfer_vector_direct(Vector_ &vector_f, const Vector_ &vector_c, const TargetSpace_ &target_space, const SourceSpace_ &source_space, const String &cubature_name)
Transfers a primal vector directly.
Base exception class.
Definition: exception.hpp:27
String class implementation.
Definition: string.hpp:47
Tiny Matrix class template.
CUDA_HOST_DEVICE Matrix & set_mat_mat_mult(const Matrix< T_, m_, la_, sma_, sna_ > &a, const Matrix< T_, lb_, n_, smb_, snb_ > &b)
Sets this matrix to the algebraic matrix-product of two other matrices.
static constexpr int sn
the column stride of the matrix
RowType v[sm_]
actual matrix data; that's an array of vectors
CUDA_HOST_DEVICE void format(DataType alpha=DataType(0))
Formats the matrix.
CUDA_HOST_DEVICE DataType norm_frobenius() const
Returns the Frobenius norm of the matrix.
Tiny Vector class template.
CUDA_HOST_DEVICE void format(DataType alpha=DataType(0))
Formats the vector.
LAFEM common type definitions.
bool isnormal(T_ x)
Checks whether a value is normal.
DT_ invert_matrix(const IT_ n, const IT_ stride, DT_ a[], IT_ p[])
Inverts a matrix and returns its determinant.
Definition: math.hpp:1292
FEAT namespace.
Definition: adjactor.hpp:12
std::uint64_t Index
Index data type.
TrafoTags
Trafo configuration tags enum.
Definition: eval_tags.hpp:22
@ jac_det
specifies whether the trafo should supply jacobian determinants