FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
grid_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
10#include <kernel/lafem/base.hpp>
11#include <kernel/assembly/asm_traits.hpp>
13#include <kernel/util/math.hpp>
14#include <kernel/geometry/intern/coarse_fine_cell_mapping.hpp>
15#include <kernel/geometry/mesh_permutation.hpp>
16#include <kernel/trafo/inverse_mapping.hpp>
17
18// includes, system
19#include <set>
20#include <map>
21#include <vector>
22
23namespace FEAT
24{
25 namespace Assembly
26 {
35 {
36 public:
44 public FEAT::Exception
45 {
46 public:
48 Exception("local mass matrix inversion error")
49 {
50 }
51 }; // class LocalMassMatrixSingularException
52
76 template<
77 typename Matrix_,
78 typename Vector_,
79 typename FineSpace_,
80 typename CoarseSpace_>
82 Matrix_& matrix,
83 Vector_& vector,
84 const FineSpace_& fine_space,
85 const CoarseSpace_& coarse_space,
86 const String& cubature_name)
87 {
88 Cubature::DynamicFactory cubature_factory(cubature_name);
89 assemble_prolongation(matrix, vector, fine_space, coarse_space, cubature_factory);
90 }
91
115 template<
116 typename Matrix_,
117 typename Vector_,
118 typename FineSpace_,
119 typename CoarseSpace_>
121 Matrix_& matrix,
122 Vector_& vector,
123 const FineSpace_& fine_space,
124 const CoarseSpace_& coarse_space,
125 const Cubature::DynamicFactory& cubature_factory)
126 {
127 // validate matrix and vector dimensions
128 XASSERTM(matrix.rows() == fine_space.get_num_dofs(), "invalid matrix dimensions");
129 XASSERTM(matrix.columns() == coarse_space.get_num_dofs(), "invalid matrix dimensions");
130 XASSERTM(vector.size() == fine_space.get_num_dofs(), "invalid vector size");
131
132 typedef typename Matrix_::DataType DataType;
133
134 // typedefs for trafos, mesh and shape
135 typedef typename FineSpace_::TrafoType FineTrafoType;
136 typedef typename CoarseSpace_::TrafoType CoarseTrafoType;
137 typedef typename CoarseSpace_::ShapeType ShapeType;
138
139 // typedefs for dof-mappings
140 typedef typename FineSpace_::DofMappingType FineDofMapping;
141 typedef typename CoarseSpace_::DofMappingType CoarseDofMapping;
142
143 // typedefs for trafo evaluators
144 typedef typename FineTrafoType::template Evaluator<ShapeType, DataType>::Type FineTrafoEvaluator;
145 typedef typename CoarseTrafoType::template Evaluator<ShapeType, DataType>::Type CoarseTrafoEvaluator;
146
147 // typedefs for space evaluators
148 typedef typename FineSpace_::template Evaluator<FineTrafoEvaluator>::Type FineSpaceEvaluator;
149 typedef typename CoarseSpace_::template Evaluator<CoarseTrafoEvaluator>::Type CoarseSpaceEvaluator;
150
151 // define fine and coarse mesh trafo configurations
152 typedef typename FineSpaceEvaluator::template ConfigTraits<SpaceTags::value> FineSpaceConfigTraits;
153 typedef typename CoarseSpaceEvaluator::template ConfigTraits<SpaceTags::value> CoarseSpaceConfigTraits;
154 static constexpr TrafoTags fine_trafo_config = TrafoTags::jac_det | FineSpaceConfigTraits::trafo_config;
155 static constexpr TrafoTags coarse_trafo_config = TrafoTags::jac_det | CoarseSpaceConfigTraits::trafo_config;
156
157 // typedefs for trafo data
158 typedef typename FineTrafoEvaluator::template ConfigTraits<fine_trafo_config>::EvalDataType FineTrafoEvalData;
159 typedef typename CoarseTrafoEvaluator::template ConfigTraits<coarse_trafo_config>::EvalDataType CoarseTrafoEvalData;
160
161 // typedef for space data
162 typedef typename FineSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType FineSpaceEvalData;
163 typedef typename CoarseSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType CoarseSpaceEvalData;
164
165 // typedefs for cubature rule and factory
166 typedef typename Intern::CubatureTraits<FineTrafoEvaluator>::RuleType CubatureRuleType;
167
168 // fetch the trafos
169 const FineTrafoType& fine_trafo = fine_space.get_trafo();
170 const CoarseTrafoType& coarse_trafo = coarse_space.get_trafo();
171
172 // get fine mesh element inverse permutation
173 const Adjacency::Permutation& coarse_perm =
174 coarse_trafo.get_mesh().get_mesh_permutation().get_perm();
175 const Adjacency::Permutation& fine_perm =
176 fine_trafo.get_mesh().get_mesh_permutation().get_inv_perm();
177
178 // create the cubature rules
179 CubatureRuleType fine_cubature(Cubature::ctor_factory, cubature_factory);
180 CubatureRuleType refine_cubature;
181 Cubature::RefineFactoryCore::create(refine_cubature, fine_cubature);
182
183 // helper struct to calculate fine mesh cell index
185 typename FineSpace_::MeshType, typename CoarseSpace_::MeshType>
186 cfmapping(fine_trafo.get_mesh(), coarse_trafo.get_mesh());
187
188 // OpenMP parallel region
189 FEAT_PRAGMA_OMP(parallel)
190 {
191 FineTrafoEvalData fine_trafo_data;
192 CoarseTrafoEvalData coarse_trafo_data;
193
194 FineSpaceEvalData fine_space_data;
195 CoarseSpaceEvalData coarse_space_data;
196
197 // create matrix scatter-axpy
198 typename Matrix_::ScatterAxpy scatter_maxpy(matrix);
199 typename Vector_::ScatterAxpy scatter_vaxpy(vector);
200
201 // create DOF-mappings
202 FineDofMapping fine_dof_mapping(fine_space);
203 CoarseDofMapping coarse_dof_mapping(coarse_space);
204
205 // create trafo evaluators
206 FineTrafoEvaluator fine_trafo_eval(fine_trafo);
207 CoarseTrafoEvaluator coarse_trafo_eval(coarse_trafo);
208
209 // create space evaluators
210 FineSpaceEvaluator fine_space_eval(fine_space);
211 CoarseSpaceEvaluator coarse_space_eval(coarse_space);
212
213 // allocate fine-mesh mass matrix
215
216 // allocate local matrix data for interlevel-mesh mass matrix
218
219 // allocate local vector data for weight vector
221
222 // pivot array for factorization
223 int pivot[FineSpaceEvaluator::max_local_dofs];
224
225 // loop over all coarse mesh cells
226 FEAT_PRAGMA_OMP(for)
227 for(Index ccell = 0; ccell < coarse_trafo_eval.get_num_cells(); ++ccell)
228 {
229 // prepare coarse trafo evaluator
230 coarse_trafo_eval.prepare(ccell);
231
232 // prepare coarse space evaluator
233 coarse_space_eval.prepare(coarse_trafo_eval);
234
235 // fetch number of local coarse DOFs
236 const int coarse_num_loc_dofs = coarse_space_eval.get_num_local_dofs();
237
238 // prepare coarse mesh dof-mapping
239 coarse_dof_mapping.prepare(ccell);
240
241 // get coarse cell index with respect to 2-level ordering
242 const Index ccell_2lvl = (coarse_perm.empty() ? ccell : coarse_perm.map(ccell));
243
244 // loop over all child cells
245 for(Index child(0); child < cfmapping.get_num_children(); ++child)
246 {
247 // calculate fine mesh cell index with respect to 2 level ordering
248 const Index fcell_2lvl = cfmapping.calc_fcell(ccell_2lvl, child);
249
250 // get fine cell index with respect to potential permutation
251 const Index fcell = (fine_perm.empty() ? fcell_2lvl : fine_perm.map(fcell_2lvl));
252
253 // prepare fine trafo evaluator
254 fine_trafo_eval.prepare(fcell);
255
256 // prepare fine space evaluator
257 fine_space_eval.prepare(fine_trafo_eval);
258
259 // fetch number of local fine DOFs
260 const int fine_num_loc_dofs = fine_space_eval.get_num_local_dofs();
261
262 // format local matrices
263 mass.format();
264 lmd.format();
265 lvd.format();
266
267 // loop over all cubature points and integrate
268 for(int k(0); k < fine_cubature.get_num_points(); ++k)
269 {
270 // compute coarse mesh cubature point index
271 const int l(int(child) * fine_cubature.get_num_points() + k);
272
273 // compute trafo data
274 fine_trafo_eval(fine_trafo_data, fine_cubature.get_point(k));
275 coarse_trafo_eval(coarse_trafo_data, refine_cubature.get_point(l));
276
277 // compute basis function data
278 fine_space_eval(fine_space_data, fine_trafo_data);
279 coarse_space_eval(coarse_space_data, coarse_trafo_data);
280
281 // fine mesh test function loop
282 for(int i(0); i < fine_num_loc_dofs; ++i)
283 {
284 // fine mesh trial function loop
285 for(int j(0); j < fine_num_loc_dofs; ++j)
286 {
287 mass(i,j) += fine_trafo_data.jac_det * fine_cubature.get_weight(k) *
288 fine_space_data.phi[i].value * fine_space_data.phi[j].value;
289 // go for next fine mesh trial DOF
290 }
291
292 // coarse mesh trial function loop
293 for(int j(0); j < coarse_num_loc_dofs; ++j)
294 {
295 lmd(i,j) +=
296 fine_trafo_data.jac_det * fine_cubature.get_weight(k) *
297 fine_space_data.phi[i].value * coarse_space_data.phi[j].value;
298 // go for next fine mesh trial DOF
299 }
300 // go for next fine mesh test DOF
301 }
302 // go for next cubature point
303 }
304
305 // finish coarse mesh evaluators
306 fine_space_eval.finish();
307 fine_trafo_eval.finish();
308
309 // invert fine mesh mass matrix
310 Math::invert_matrix(fine_num_loc_dofs, mass.sn, &mass.v[0][0], pivot);
311
312 // Note:
313 // Usually, one would check whether the determinant returned by the invert_matrix
314 // function is normal. However, this can lead to false alerts when assembling in
315 // single precision, as the mass matrix entries are of magnitude h^2 (in 2D), i.e.
316 // the determinant can become subnormal or even (numerically) zero although the
317 // condition number of the matrix is still fine and the inversion was successful.
318 // Therefore, we first multiply the (hopefully) inverted mass matrix by the
319 // inter-level mass matrix and check whether the Frobenius norm of the result
320 // is normal. If our matrix inversion failed, the result is virtually guaranteed
321 // to be garbage, so this should serve well enough as a sanity check.
322
323 // compute X := M^{-1}*N
324 lid.set_mat_mat_mult(mass, lmd);
325
326 // sanity check for matrix inversion
329
330 // prepare fine mesh dof-mapping
331 fine_dof_mapping.prepare(fcell);
332 lvd.format(DataType(1));
333
334 FEAT_PRAGMA_OMP(critical)
335 {
336 // incorporate local matrix
337 scatter_maxpy(lid, fine_dof_mapping, coarse_dof_mapping);
338
339 // update weights
340 scatter_vaxpy(lvd, fine_dof_mapping);
341 }
342
343 // finish fine mesh dof-mapping
344 fine_dof_mapping.finish();
345
346 // go for next child cell
347 }
348
349 // finish coarse mesh evaluators
350 coarse_space_eval.finish();
351 coarse_trafo_eval.finish();
352
353 // finish coarse mesh dof-mapping
354 coarse_dof_mapping.finish();
355
356 // go for next coarse mesh cell
357 } // FEAT_PRAGMA_OMP(for)
358 } // FEAT_PRAGMA_OMP(parallel)
359 }
360
382 template<
383 typename Matrix_,
384 typename FineSpace_,
385 typename CoarseSpace_>
387 Matrix_& matrix,
388 const FineSpace_& fine_space,
389 const CoarseSpace_& coarse_space,
390 const String& cubature_name)
391 {
392 Cubature::DynamicFactory cubature_factory(cubature_name);
393 assemble_prolongation_direct(matrix, fine_space, coarse_space, cubature_factory);
394 }
395
417 template<
418 typename Matrix_,
419 typename FineSpace_,
420 typename CoarseSpace_>
422 Matrix_& matrix,
423 const FineSpace_& fine_space,
424 const CoarseSpace_& coarse_space,
425 const Cubature::DynamicFactory& cubature_factory)
426 {
427 // create a weight vector
428 auto weight = matrix.create_vector_l();
429 matrix.format();
430 weight.format();
431
432 // assemble matrix and weight
433 assemble_prolongation(matrix, weight, fine_space, coarse_space, cubature_factory);
434
435 // scale prolongation matrix rows by inverse weights
436 weight.component_invert(weight);
437 matrix.scale_rows(matrix, weight);
438 }
439
463 template<
464 typename Matrix_,
465 typename Vector_,
466 typename FineSpace_,
467 typename CoarseSpace_>
469 Matrix_& matrix,
470 Vector_& vector,
471 const FineSpace_& fine_space,
472 const CoarseSpace_& coarse_space,
473 const String& cubature_name)
474 {
475 Cubature::DynamicFactory cubature_factory(cubature_name);
476 assemble_truncation(matrix, vector, fine_space, coarse_space, cubature_factory);
477 }
478
502 template<
503 typename Matrix_,
504 typename Vector_,
505 typename FineSpace_,
506 typename CoarseSpace_>
508 Matrix_& matrix,
509 Vector_& vector,
510 const FineSpace_& fine_space,
511 const CoarseSpace_& coarse_space,
512 const Cubature::DynamicFactory& cubature_factory)
513 {
514 // validate matrix and vector dimensions
515 XASSERTM(matrix.rows() == coarse_space.get_num_dofs(), "invalid matrix dimensions");
516 XASSERTM(matrix.columns() == fine_space.get_num_dofs(), "invalid matrix dimensions");
517 XASSERTM(vector.size() == coarse_space.get_num_dofs(), "invalid vector size");
518
519 typedef typename Matrix_::DataType DataType;
520
521 // typedefs for trafos, mesh and shape
522 typedef typename FineSpace_::TrafoType FineTrafoType;
523 typedef typename CoarseSpace_::TrafoType CoarseTrafoType;
524 typedef typename CoarseSpace_::ShapeType ShapeType;
525
526 // typedefs for dof-mappings
527 typedef typename FineSpace_::DofMappingType FineDofMapping;
528 typedef typename CoarseSpace_::DofMappingType CoarseDofMapping;
529
530 // typedefs for trafo evaluators
531 typedef typename FineTrafoType::template Evaluator<ShapeType, DataType>::Type FineTrafoEvaluator;
532 typedef typename CoarseTrafoType::template Evaluator<ShapeType, DataType>::Type CoarseTrafoEvaluator;
533
534 // typedefs for space evaluators
535 typedef typename FineSpace_::template Evaluator<FineTrafoEvaluator>::Type FineSpaceEvaluator;
536 typedef typename CoarseSpace_::template Evaluator<CoarseTrafoEvaluator>::Type CoarseSpaceEvaluator;
537
538 // define fine and coarse mesh trafo configurations
539 typedef typename FineSpaceEvaluator::template ConfigTraits<SpaceTags::value> FineSpaceConfigTraits;
540 typedef typename CoarseSpaceEvaluator::template ConfigTraits<SpaceTags::value> CoarseSpaceConfigTraits;
541 static constexpr TrafoTags fine_trafo_config = TrafoTags::jac_det | FineSpaceConfigTraits::trafo_config;
542 static constexpr TrafoTags coarse_trafo_config = TrafoTags::jac_det | CoarseSpaceConfigTraits::trafo_config;
543
544 // typedefs for trafo data
545 typedef typename FineTrafoEvaluator::template ConfigTraits<fine_trafo_config>::EvalDataType FineTrafoEvalData;
546 typedef typename CoarseTrafoEvaluator::template ConfigTraits<coarse_trafo_config>::EvalDataType CoarseTrafoEvalData;
547
548 // typedef for space data
549 typedef typename FineSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType FineSpaceEvalData;
550 typedef typename CoarseSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType CoarseSpaceEvalData;
551
552 // typedefs for cubature rule and factory
553 typedef typename Intern::CubatureTraits<FineTrafoEvaluator>::RuleType CubatureRuleType;
554
555 // fetch the trafos
556 const FineTrafoType& fine_trafo = fine_space.get_trafo();
557 const CoarseTrafoType& coarse_trafo = coarse_space.get_trafo();
558
559 // helper struct to calculate fine mesh cell index
561 typename FineSpace_::MeshType, typename CoarseSpace_::MeshType>
562 cfmapping(fine_trafo.get_mesh(), coarse_trafo.get_mesh());
563
564 // get fine mesh element inverse permutation
565 const Adjacency::Permutation& coarse_perm =
566 coarse_trafo.get_mesh().get_mesh_permutation().get_perm();
567 const Adjacency::Permutation& fine_perm =
568 fine_trafo.get_mesh().get_mesh_permutation().get_inv_perm();
569
570 // create the cubature rules
571 CubatureRuleType coarse_cubature(Cubature::ctor_factory, cubature_factory);
572 CubatureRuleType fine_cubature(Cubature::ctor_factory, cubature_factory);
573 CubatureRuleType refine_cubature;
574 Cubature::RefineFactoryCore::create(refine_cubature, fine_cubature);
575
576 FEAT_PRAGMA_OMP(parallel)
577 {
578 FineTrafoEvalData fine_trafo_data;
579 CoarseTrafoEvalData coarse_trafo_data;
580 FineSpaceEvalData fine_space_data;
581 CoarseSpaceEvalData coarse_space_data;
582
583 // create matrix scatter-axpy
584 typename Matrix_::ScatterAxpy scatter_maxpy(matrix);
585 typename Vector_::ScatterAxpy scatter_vaxpy(vector);
586
587 // create DOF-mappings
588 FineDofMapping fine_dof_mapping(fine_space);
589 CoarseDofMapping coarse_dof_mapping(coarse_space);
590
591 // create trafo evaluators
592 FineTrafoEvaluator fine_trafo_eval(fine_trafo);
593 CoarseTrafoEvaluator coarse_trafo_eval(coarse_trafo);
594
595 // create space evaluators
596 FineSpaceEvaluator fine_space_eval(fine_space);
597 CoarseSpaceEvaluator coarse_space_eval(coarse_space);
598
599 // allocate fine-mesh mass matrix
601
602 // allocate local matrix data for interlevel-mesh mass matrix
604
605 // allocate local vector data for weight vector
607
608 // pivot array for factorization
609 int pivot[CoarseSpaceEvaluator::max_local_dofs];
610
611 // loop over all coarse mesh cells
612 FEAT_PRAGMA_OMP(for)
613 for(Index ccell = 0; ccell < coarse_trafo_eval.get_num_cells(); ++ccell)
614 {
615 // prepare coarse trafo evaluator
616 coarse_trafo_eval.prepare(ccell);
617
618 // prepare coarse space evaluator
619 coarse_space_eval.prepare(coarse_trafo_eval);
620
621 // fetch number of local coarse DOFs
622 const int coarse_num_loc_dofs = coarse_space_eval.get_num_local_dofs();
623
624 // prepare coarse mesh dof-mapping
625 coarse_dof_mapping.prepare(ccell);
626
627 // Let's assemble the coarse-mesh mass matrix first
628 mass.format();
629 for(int k(0); k < coarse_cubature.get_num_points(); ++k)
630 {
631 // compute trafo and space data
632 coarse_trafo_eval(coarse_trafo_data, coarse_cubature.get_point(k));
633 coarse_space_eval(coarse_space_data, coarse_trafo_data);
634
635 // coarse mesh test function loop
636 for(int i(0); i < coarse_num_loc_dofs; ++i)
637 {
638 // coarse mesh trial function loop
639 for(int j(0); j < coarse_num_loc_dofs; ++j)
640 {
641 mass(i,j) += coarse_trafo_data.jac_det * coarse_cubature.get_weight(k) *
642 coarse_space_data.phi[i].value * coarse_space_data.phi[j].value;
643 }
644 }
645 }
646
647 // invert coarse mesh mass matrix
648 Math::invert_matrix(coarse_num_loc_dofs, mass.sn, &mass.v[0][0], pivot);
649
650 // get coarse cell index with respect to 2-level ordering
651 const Index ccell_2lvl = (coarse_perm.empty() ? ccell : coarse_perm.map(ccell));
652
653 // loop over all child cells
654 for(Index child(0); child < cfmapping.get_num_children(); ++child)
655 {
656 // calculate fine mesh cell index with respect to 2 level ordering
657 const Index fcell_2lvl = cfmapping.calc_fcell(ccell_2lvl, child);
658
659 // get fine cell index with respect to potential permutation
660 const Index fcell = (fine_perm.empty() ? fcell_2lvl : fine_perm.map(fcell_2lvl));
661
662 // prepare fine trafo evaluator
663 fine_trafo_eval.prepare(fcell);
664
665 // prepare fine space evaluator
666 fine_space_eval.prepare(fine_trafo_eval);
667
668 // fetch number of local fine DOFs
669 const int fine_num_loc_dofs = fine_space_eval.get_num_local_dofs();
670
671 // format local matrices
672 lmd.format();
673
674 // loop over all cubature points and integrate
675 for(int k(0); k < fine_cubature.get_num_points(); ++k)
676 {
677 // compute coarse mesh cubature point index
678 const int l(int(child) * fine_cubature.get_num_points() + k);
679
680 // compute trafo data
681 fine_trafo_eval(fine_trafo_data, fine_cubature.get_point(k));
682 coarse_trafo_eval(coarse_trafo_data, refine_cubature.get_point(l));
683
684 // compute basis function data
685 fine_space_eval(fine_space_data, fine_trafo_data);
686 coarse_space_eval(coarse_space_data, coarse_trafo_data);
687
688 // coarse mesh test function loop
689 for(int i(0); i < coarse_num_loc_dofs; ++i)
690 {
691 // fine mesh trial function loop
692 for(int j(0); j < fine_num_loc_dofs; ++j)
693 {
694 lmd(i,j) +=
695 fine_trafo_data.jac_det * fine_cubature.get_weight(k) *
696 coarse_space_data.phi[i].value * fine_space_data.phi[j].value;
697 // go for next fine mesh trial DOF
698 }
699 // go for next coarse mesh test DOF
700 }
701 // go for next cubature point
702 }
703
704 // finish coarse mesh evaluators
705 fine_space_eval.finish();
706 fine_trafo_eval.finish();
707
708 // compute X := M^{-1}*N
709 lid.set_mat_mat_mult(mass, lmd);
710
711 // sanity check for matrix inversion
714
715 // prepare fine mesh dof-mapping
716 fine_dof_mapping.prepare(fcell);
717
718 // incorporate local matrix
719 FEAT_PRAGMA_OMP(critical)
720 {
721 scatter_maxpy(lid, coarse_dof_mapping, fine_dof_mapping);
722 }
723
724 // finish fine mesh dof-mapping
725 fine_dof_mapping.finish();
726
727 // go for next child cell
728 }
729
730 // update weights
731 lvd.format(DataType(1));
732 FEAT_PRAGMA_OMP(critical)
733 {
734 scatter_vaxpy(lvd, coarse_dof_mapping);
735 }
736
737 // finish coarse mesh dof-mapping
738 coarse_dof_mapping.finish();
739
740 // finish coarse mesh evaluators
741 coarse_space_eval.finish();
742 coarse_trafo_eval.finish();
743
744 // go for next coarse mesh cell
745 } // FEAT_PRAGMA_OMP(for)
746 } // FEAT_PRAGMA_OMP(parallel)
747 }
748
770 template<
771 typename Matrix_,
772 typename FineSpace_,
773 typename CoarseSpace_>
775 Matrix_& matrix,
776 const FineSpace_& fine_space,
777 const CoarseSpace_& coarse_space,
778 const String& cubature_name)
779 {
780 Cubature::DynamicFactory cubature_factory(cubature_name);
781 assemble_truncation_direct(matrix, fine_space, coarse_space, cubature_factory);
782 }
783
805 template<
806 typename Matrix_,
807 typename FineSpace_,
808 typename CoarseSpace_>
810 Matrix_& matrix,
811 const FineSpace_& fine_space,
812 const CoarseSpace_& coarse_space,
813 const Cubature::DynamicFactory& cubature_factory)
814 {
815 // create a weight vector
816 auto weight = matrix.create_vector_l();
817 matrix.format();
818 weight.format();
819
820 // assemble matrix and weight
821 assemble_truncation(matrix, weight, fine_space, coarse_space, cubature_factory);
822
823 // scale truncation matrix rows by inverse weights
824 weight.component_invert(weight);
825 matrix.scale_rows(matrix, weight);
826 }
827
869 template<
870 typename Matrix_,
871 typename Vector_,
872 typename TargetSpace_,
873 typename SourceSpace_,
874 typename Target2SourceAdjactor_>
876 Matrix_& matrix,
877 Vector_& vector,
878 const TargetSpace_& space_target,
879 const SourceSpace_& space_source,
880 const Target2SourceAdjactor_& trg2src,
881 const String& cubature_name)
882 {
883 // validate matrix and vector dimensions
884 XASSERTM(matrix.rows() == space_target.get_num_dofs(), "invalid matrix dimensions");
885 XASSERTM(matrix.columns() == space_source.get_num_dofs(), "invalid matrix dimensions");
886 XASSERTM(vector.size() == space_target.get_num_dofs(), "invalid vector size");
887
888 typedef typename Matrix_::DataType DataType;
889
890 // typedefs for trafos, mesh and shape
891 typedef typename TargetSpace_::TrafoType TargetTrafoType;
892 typedef typename SourceSpace_::TrafoType SourceTrafoType;
893 typedef typename SourceSpace_::ShapeType ShapeType;
894
895 // typedefs for dof-mappings
896 typedef typename TargetSpace_::DofMappingType TargetDofMapping;
897 typedef typename SourceSpace_::DofMappingType SourceDofMapping;
898
899 // typedefs for trafo evaluators
900 typedef typename TargetTrafoType::template Evaluator<ShapeType, DataType>::Type TargetTrafoEvaluator;
901 typedef typename SourceTrafoType::template Evaluator<ShapeType, DataType>::Type SourceTrafoEvaluator;
902
903 // typedefs for space evaluators
904 typedef typename TargetSpace_::template Evaluator<TargetTrafoEvaluator>::Type TargetSpaceEvaluator;
905 typedef typename SourceSpace_::template Evaluator<SourceTrafoEvaluator>::Type SourceSpaceEvaluator;
906
907 // define target and source mesh trafo configurations
908 typedef typename TargetSpaceEvaluator::template ConfigTraits<SpaceTags::value> TargetSpaceConfigTraits;
909 typedef typename SourceSpaceEvaluator::template ConfigTraits<SpaceTags::value> SourceSpaceConfigTraits;
910 static constexpr TrafoTags target_trafo_config = TrafoTags::img_point | TrafoTags::jac_det | TargetSpaceConfigTraits::trafo_config;
911 static constexpr TrafoTags source_trafo_config = TrafoTags::jac_det | SourceSpaceConfigTraits::trafo_config;
912
913 // typedefs for trafo data
914 typedef typename TargetTrafoEvaluator::template ConfigTraits<target_trafo_config>::EvalDataType TargetTrafoEvalData;
915 typedef typename SourceTrafoEvaluator::template ConfigTraits<source_trafo_config>::EvalDataType SourceTrafoEvalData;
916
917 // typedef for space data
918 typedef typename TargetSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType TargetSpaceEvalData;
919 typedef typename SourceSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType SourceSpaceEvalData;
920
921 // typedef for source inverse mapping data
922 typedef Trafo::InverseMapping<SourceTrafoType, DataType> SourceInverseMappingType;
923 typedef typename SourceInverseMappingType::InvMapDataType SourceInvMapData;
924
925 // typedefs for cubature rule and factory
926 typedef typename Intern::CubatureTraits<TargetTrafoEvaluator>::RuleType CubatureRuleType;
927
928 // local target mass matrix
930
931 // local target-source inter-mesh matrix
933
934 // fetch the trafos
935 const TargetTrafoType& target_trafo = space_target.get_trafo();
936 const SourceTrafoType& source_trafo = space_source.get_trafo();
937
938 // create the cubature rule
939 Cubature::DynamicFactory cubature_factory(cubature_name);
940 CubatureRuleType target_cubature(Cubature::ctor_factory, cubature_factory);
941 const std::size_t num_cub_pts = std::size_t(target_cubature.get_num_points());
942
943 // number of failed cubature points
944 int failed_points = 0;
945
946 // we open a OpenMP section here since this is a quite expensive assembly
947 FEAT_PRAGMA_OMP(parallel reduction(+:failed_points))
948 {
949 // create matrix scatter-axpy
950 typename Matrix_::ScatterAxpy scatter_maxpy(matrix);
951 typename Vector_::ScatterAxpy scatter_vaxpy(vector);
952
953 // create DOF-mappings
954 TargetDofMapping target_dof_mapping(space_target);
955 SourceDofMapping source_dof_mapping(space_source);
956
957 // create trafo evaluators
958 TargetTrafoEvaluator target_trafo_eval(target_trafo);
959 SourceTrafoEvaluator source_trafo_eval(source_trafo);
960
961 // create space evaluators
962 TargetSpaceEvaluator space_target_eval(space_target);
963 SourceSpaceEvaluator space_source_eval(space_source);
964
965 TargetTrafoEvalData target_trafo_data;
966 SourceTrafoEvalData source_trafo_data;
967 TargetSpaceEvalData space_target_data;
968 SourceSpaceEvalData space_source_data;
969
970 // target space basis values, pre-multiplied by cubature weights and jacobian determinants
972 std::vector<TargetBasisValueVector> target_basis_values;
973 target_basis_values.resize(num_cub_pts);
974
975 // create an inverse mapping object for the source
976 SourceInverseMappingType source_inv_map(source_trafo);
977
978 // the inverse mapping data object
979 std::vector<SourceInvMapData> source_inv_map_data;
980 source_inv_map_data.resize(num_cub_pts);
981
982 // [local source cell index] = (inverse map cell index, cubature point index)
983 std::vector<std::vector<std::pair<std::size_t, std::size_t>>> source_cell_map;
984 source_cell_map.reserve(30);
985
986 // allocate target-mesh mass matrix
987 LocTrgMatrixType trg_mass;
988
989 // allocate local matrix data for inter-mesh mass matrix
990 LocTSIMatrixType tsi_mass;
991
992 // local transfer matrix
993 std::vector<LocTSIMatrixType> loc_trans;
994 loc_trans.reserve(30);
995
996 // allocate local vector data for weight vector and set all entries to 1
998 lvd.format(DataType(1));
999
1000 // pivot array for factorization
1001 int pivot[TargetSpaceEvaluator::max_local_dofs];
1002
1003 // loop over all target mesh cells
1004 // note: OpenMP (sometimes) requires a signed iteration variable
1005 FEAT_PRAGMA_OMP(for schedule(dynamic,16))
1006 for(std::int64_t itrg_cell = 0ull; itrg_cell < std::int64_t(target_trafo_eval.get_num_cells()); ++itrg_cell)
1007 {
1008 // cast target cell index
1009 const Index trg_cell = Index(itrg_cell);
1010
1011 // collect all source cells that intersect with the current target cell
1012 std::vector<Index> source_cells;
1013 for(auto it = trg2src.image_begin(trg_cell); it != trg2src.image_end(trg_cell); ++it)
1014 source_cells.push_back(*it);
1015
1016 // allocate source cell map to correct size
1017 source_cell_map.resize(source_cells.size());
1018
1019 // allocate local transfer matrices
1020 loc_trans.resize(source_cells.size());
1021
1022 // prepare target trafo evaluator
1023 target_trafo_eval.prepare(trg_cell);
1024
1025 // prepare target space evaluator
1026 space_target_eval.prepare(target_trafo_eval);
1027
1028 // fetch number of local target DOFs
1029 const int target_num_loc_dofs = space_target_eval.get_num_local_dofs();
1030
1031 // format local matrices
1032 trg_mass.format();
1033
1034 // first of all, let's loop over all target cubature points and unmap them onto the source mesh
1035 // we will also integrate the target mesh mass matrix while we're at it
1036 for(std::size_t k(0); k < num_cub_pts; ++k)
1037 {
1038 // compute trafo data
1039 target_trafo_eval(target_trafo_data, target_cubature.get_point(int(k)));
1040
1041 // compute basis function data
1042 space_target_eval(space_target_data, target_trafo_data);
1043
1044 // integrate target mesh mass matrix entries
1045 for(int i(0); i < target_num_loc_dofs; ++i)
1046 {
1047 // save pre-weighted target basis value for later use
1048 target_basis_values.at(k)[i] = target_trafo_data.jac_det * target_cubature.get_weight(int(k)) * space_target_data.phi[i].value;
1049 for(int j(0); j < target_num_loc_dofs; ++j)
1050 {
1051 trg_mass(i,j) += target_basis_values.at(k)[i] * space_target_data.phi[j].value;
1052 }
1053 }
1054
1055 // try to unmap cubature point from real coordinates onto source cell reference coordinates
1056 SourceInvMapData& simd = source_inv_map_data.at(k);
1057 simd = source_inv_map.unmap_point(target_trafo_data.img_point, source_cells, false);
1058
1059 // did we fail to unmap the point?
1060 if(simd.empty())
1061 {
1062 ++failed_points;
1063 continue;
1064 }
1065
1066 // now let's loop over all source cells that were found to contain/intersect the current cubature
1067 // point and update our source-cell-to-cubature-point map
1068 for(std::size_t i(0); i < simd.size(); ++i)
1069 {
1070 // find the local source cell index that corresponds to this source cell index
1071 std::size_t loc_idx = 0u;
1072 for(; loc_idx < source_cells.size(); ++loc_idx)
1073 if(source_cells.at(loc_idx) == simd.cells.at(i))
1074 break;
1075 XASSERT(loc_idx < source_cells.size());
1076
1077 // add this cubature point to the set of points for this source cell
1078 source_cell_map.at(loc_idx).push_back(std::make_pair(i, k));
1079 }
1080 }
1081
1082 // finish target mesh evaluators
1083 space_target_eval.finish();
1084 target_trafo_eval.finish();
1085
1086 // invert target mesh mass matrix
1087 Math::invert_matrix(target_num_loc_dofs, trg_mass.sn, &trg_mass.v[0][0], pivot);
1088
1089 // Note:
1090 // Usually, one would check whether the determinant returned by the invert_matrix
1091 // function is normal. However, this can lead to false alerts when assembling in
1092 // single precision, as the mass matrix entries are of magnitude h^2 (in 2D), i.e.
1093 // the determinant can become subnormal or even (numerically) zero although the
1094 // condition number of the matrix is still fine and the inversion was successful.
1095 // Therefore, we first multiply the (hopefully) inverted mass matrix by the
1096 // inter-level mass matrix and check whether the Frobenius norm of the result
1097 // is normal. If our matrix inversion failed, the result is virtually guaranteed
1098 // to be garbage, so this should serve well enough as a sanity check.
1099
1100 // now let's loop over all source cells that were found
1101 for(std::size_t is = 0u; is < source_cell_map.size(); ++is)
1102 {
1103 // get source cell index
1104 const Index src_cell = source_cells.at(is);
1105
1106 // get the cubature points map
1107 std::vector<std::pair<std::size_t, std::size_t>> cub_pts_map = source_cell_map.at(is);
1108
1109 // no cubature points on this source cell?
1110 if(cub_pts_map.empty())
1111 continue;
1112
1113 // prepare source trafo evaluator
1114 source_trafo_eval.prepare(src_cell);
1115
1116 // prepare source space evaluator
1117 space_source_eval.prepare(source_trafo_eval);
1118
1119 // fetch number of local source DOFs
1120 const int source_num_loc_dofs = space_source_eval.get_num_local_dofs();
1121
1122 // format our inter-mesh mass matrix
1123 tsi_mass.format();
1124
1125 // loop over all cubature points and integrate
1126 for(auto cit = cub_pts_map.begin(); cit != cub_pts_map.end(); ++cit)
1127 {
1128 // get the index of the source cell in the inverse mapping data object
1129 const std::size_t src_i = cit->first;
1130
1131 // get the index of the cubature point
1132 const std::size_t cub_k = cit->second;
1133
1134 // get the source inverse mapping data for this cubature point
1135 SourceInvMapData& simd = source_inv_map_data.at(cub_k);
1136
1137 // ensure that this is the right cell
1138 XASSERT(simd.cells.at(src_i) == src_cell);
1139
1140 // compute our averaging weight: we have to normalize in case that this cubature
1141 // point is intersecting more than one source cell
1142 DataType weight = DataType(1) / DataType(simd.size());
1143
1144 // alright, evaluate our source trafo and space
1145 source_trafo_eval(source_trafo_data, simd.dom_points.at(src_i));
1146
1147 // compute basis function data
1148 space_source_eval(space_source_data, source_trafo_data);
1149
1150 // integrate inter-mesh mass matrix
1151 for(int i(0); i < target_num_loc_dofs; ++i)
1152 for(int j(0); j < source_num_loc_dofs; ++j)
1153 tsi_mass(i, j) += weight * target_basis_values.at(cub_k)[i] * space_source_data.phi[j].value;
1154
1155 } // go for next cubature point
1156
1157 // finish source mesh evaluators
1158 space_source_eval.finish();
1159 source_trafo_eval.finish();
1160
1161 // compute X := M^{-1}*N
1162 loc_trans.at(is).set_mat_mat_mult(trg_mass, tsi_mass);
1163
1164 // sanity check for matrix inversion
1165 if(!Math::isnormal(loc_trans.at(is).norm_frobenius()))
1167
1168 } // continue with next source cell
1169
1170 // prepare target mesh dof-mapping
1171 target_dof_mapping.prepare(trg_cell);
1172
1173 // scattering is a potential data race
1174 FEAT_PRAGMA_OMP(critical)
1175 {
1176 // loop over all intersecting source cells
1177 for(std::size_t is = 0u; is < source_cells.size(); ++is)
1178 {
1179 // no cubature points on this source cell?
1180 if(source_cell_map.at(is).empty())
1181 continue;
1182
1183 // prepare source mesh dof-mapping
1184 source_dof_mapping.prepare(source_cells.at(is));
1185
1186 // incorporate local matrix
1187 scatter_maxpy(loc_trans.at(is), target_dof_mapping, source_dof_mapping);
1188
1189 // finish source mesh dof-mapping
1190 source_dof_mapping.finish();
1191
1192 // clear the cubature point map for this source cell
1193 source_cell_map.at(is).clear();
1194 }
1195
1196 // update target weights
1197 scatter_vaxpy(lvd, target_dof_mapping);
1198 } // pragma omp critical
1199
1200 // finish target mesh dof-mapping
1201 target_dof_mapping.finish();
1202 } // go for next target mesh cell
1203 } // pragma omp parallel
1204
1205 // return number of failed points
1206 return failed_points;
1207 }
1208
1240 template<
1241 typename Matrix_,
1242 typename TargetSpace_,
1243 typename SourceSpace_,
1244 typename Target2SourceAdjactor_>
1246 Matrix_& matrix,
1247 const TargetSpace_& space_target,
1248 const SourceSpace_& space_source,
1249 const Target2SourceAdjactor_& trg2src,
1250 const String& cubature_name)
1251 {
1252 // create a weight vector
1253 auto weight = matrix.create_vector_l();
1254 matrix.format();
1255 weight.format();
1256
1257 // assemble matrix and weight
1258 int rtn = assemble_intermesh_transfer(matrix, weight, space_target, space_source, trg2src, cubature_name);
1259
1260 // scale transfer matrix rows by inverse weights
1261 weight.component_invert(weight);
1262 matrix.scale_rows(matrix, weight);
1263
1264 return rtn;
1265 }
1266
1299 template<
1300 typename Vector_,
1301 typename FineSpace_,
1302 typename CoarseSpace_>
1304 Vector_& vector_f,
1305 Vector_& vector_w,
1306 const Vector_& vector_c,
1307 const FineSpace_& fine_space,
1308 const CoarseSpace_& coarse_space,
1309 const String& cubature_name)
1310 {
1311 // validate matrix and vector dimensions
1312 XASSERTM(vector_f.size() == vector_w.size(), "invalid vector sizes");
1313 XASSERTM(vector_f.size() == fine_space.get_num_dofs(), "invalid matrix dimensions");
1314 XASSERTM(vector_c.size() == coarse_space.get_num_dofs(), "invalid matrix dimensions");
1315 XASSERTM(vector_f.size() == fine_space.get_num_dofs(), "invalid vector size");
1316
1317 typedef typename Vector_::DataType DataType;
1318 typedef typename Vector_::ValueType ValueType;
1319
1320 // typedefs for trafos, mesh and shape
1321 typedef typename FineSpace_::TrafoType FineTrafoType;
1322 typedef typename CoarseSpace_::TrafoType CoarseTrafoType;
1323 typedef typename CoarseSpace_::ShapeType ShapeType;
1324
1325 // typedefs for dof-mappings
1326 typedef typename FineSpace_::DofMappingType FineDofMapping;
1327 typedef typename CoarseSpace_::DofMappingType CoarseDofMapping;
1328
1329 // typedefs for trafo evaluators
1330 typedef typename FineTrafoType::template Evaluator<ShapeType, DataType>::Type FineTrafoEvaluator;
1331 typedef typename CoarseTrafoType::template Evaluator<ShapeType, DataType>::Type CoarseTrafoEvaluator;
1332
1333 // typedefs for space evaluators
1334 typedef typename FineSpace_::template Evaluator<FineTrafoEvaluator>::Type FineSpaceEvaluator;
1335 typedef typename CoarseSpace_::template Evaluator<CoarseTrafoEvaluator>::Type CoarseSpaceEvaluator;
1336
1337 // define fine and coarse mesh trafo configurations
1338 typedef typename FineSpaceEvaluator::template ConfigTraits<SpaceTags::value> FineSpaceConfigTraits;
1339 typedef typename CoarseSpaceEvaluator::template ConfigTraits<SpaceTags::value> CoarseSpaceConfigTraits;
1340 static constexpr TrafoTags fine_trafo_config = TrafoTags::jac_det | FineSpaceConfigTraits::trafo_config;
1341 static constexpr TrafoTags coarse_trafo_config = TrafoTags::jac_det | CoarseSpaceConfigTraits::trafo_config;
1342
1343 // typedefs for trafo data
1344 typedef typename FineTrafoEvaluator::template ConfigTraits<fine_trafo_config>::EvalDataType FineTrafoEvalData;
1345 typedef typename CoarseTrafoEvaluator::template ConfigTraits<coarse_trafo_config>::EvalDataType CoarseTrafoEvalData;
1346 FineTrafoEvalData fine_trafo_data;
1347 CoarseTrafoEvalData coarse_trafo_data;
1348
1349 // typedef for space data
1350 typedef typename FineSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType FineSpaceEvalData;
1351 typedef typename CoarseSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType CoarseSpaceEvalData;
1352 FineSpaceEvalData fine_space_data;
1353 CoarseSpaceEvalData coarse_space_data;
1354
1355 // typedefs for cubature rule and factory
1356 typedef typename Assembly::Intern::CubatureTraits<FineTrafoEvaluator>::RuleType CubatureRuleType;
1357
1358 // create gather/scatter-axpys
1359 typename Vector_::GatherAxpy gather_c(vector_c);
1360 typename Vector_::ScatterAxpy scatter_f(vector_f);
1361 typename Vector_::ScatterAxpy scatter_w(vector_w);
1362
1363 // create DOF-mappings
1364 FineDofMapping fine_dof_mapping(fine_space);
1365 CoarseDofMapping coarse_dof_mapping(coarse_space);
1366
1367 // fetch the trafos
1368 const FineTrafoType& fine_trafo = fine_space.get_trafo();
1369 const CoarseTrafoType& coarse_trafo = coarse_space.get_trafo();
1370
1371 // create trafo evaluators
1372 FineTrafoEvaluator fine_trafo_eval(fine_trafo);
1373 CoarseTrafoEvaluator coarse_trafo_eval(coarse_trafo);
1374
1375 // create space evaluators
1376 FineSpaceEvaluator fine_space_eval(fine_space);
1377 CoarseSpaceEvaluator coarse_space_eval(coarse_space);
1378
1379 // create the cubature rules
1380 Cubature::DynamicFactory cubature_factory(cubature_name);
1381 CubatureRuleType fine_cubature(Cubature::ctor_factory, cubature_factory);
1382 CubatureRuleType refine_cubature;
1383 Cubature::RefineFactoryCore::create(refine_cubature, fine_cubature);
1384
1385 // allocate fine-mesh mass matrix
1387
1388 // allocate local matrix data for interlevel-mesh mass matrix
1390
1391 // allocate local vector data for weight/coarse/fine vector
1393
1394 // pivot array for factorization
1395 int pivot[FineSpaceEvaluator::max_local_dofs];
1396
1397 // helper struct to calculate fine mesh cell index
1399 typename FineSpace_::MeshType, typename CoarseSpace_::MeshType>
1400 cfmapping(fine_trafo.get_mesh(), coarse_trafo.get_mesh());
1401
1402 // get fine mesh element inverse permutation
1403 const Adjacency::Permutation& coarse_perm =
1404 coarse_trafo.get_mesh().get_mesh_permutation().get_perm();
1405 const Adjacency::Permutation& fine_perm =
1406 fine_trafo.get_mesh().get_mesh_permutation().get_inv_perm();
1407
1408 // loop over all coarse mesh cells
1409 for(Index ccell(0); ccell < coarse_trafo_eval.get_num_cells(); ++ccell)
1410 {
1411 // prepare coarse trafo evaluator
1412 coarse_trafo_eval.prepare(ccell);
1413
1414 // prepare coarse space evaluator
1415 coarse_space_eval.prepare(coarse_trafo_eval);
1416
1417 // fetch number of local coarse DOFs
1418 const int coarse_num_loc_dofs = coarse_space_eval.get_num_local_dofs();
1419
1420 // prepare coarse mesh dof-mapping
1421 coarse_dof_mapping.prepare(ccell);
1422
1423 // gather local coarse vector
1424 lv_c.format();
1425 gather_c(lv_c, coarse_dof_mapping);
1426
1427 // get coarse cell index with respect to 2-level ordering
1428 const Index ccell_2lvl = (coarse_perm.empty() ? ccell : coarse_perm.map(ccell));
1429
1430 // loop over all child cells
1431 for(Index child(0); child < cfmapping.get_num_children(); ++child)
1432 {
1433 // calculate fine mesh cell index with respect to 2 level ordering
1434 const Index fcell_2lvl = cfmapping.calc_fcell(ccell_2lvl, child);
1435
1436 // get fine cell index with respect to potential permutation
1437 const Index fcell = (fine_perm.empty() ? fcell_2lvl : fine_perm.map(fcell_2lvl));
1438
1439 // prepare fine trafo evaluator
1440 fine_trafo_eval.prepare(fcell);
1441
1442 // prepare fine space evaluator
1443 fine_space_eval.prepare(fine_trafo_eval);
1444
1445 // fetch number of local fine DOFs
1446 const int fine_num_loc_dofs = fine_space_eval.get_num_local_dofs();
1447
1448 // format local matrices
1449 mass.format();
1450 lmd.format();
1451 lv_w.format();
1452 lv_f.format();
1453
1454 // loop over all cubature points and integrate
1455 for(int k(0); k < fine_cubature.get_num_points(); ++k)
1456 {
1457 // compute coarse mesh cubature point index
1458 const int l(int(child) * fine_cubature.get_num_points() + k);
1459
1460 // compute trafo data
1461 fine_trafo_eval(fine_trafo_data, fine_cubature.get_point(k));
1462 coarse_trafo_eval(coarse_trafo_data, refine_cubature.get_point(l));
1463
1464 // compute basis function data
1465 fine_space_eval(fine_space_data, fine_trafo_data);
1466 coarse_space_eval(coarse_space_data, coarse_trafo_data);
1467
1468 // fine mesh test function loop
1469 for(int i(0); i < fine_num_loc_dofs; ++i)
1470 {
1471 // fine mesh trial function loop
1472 for(int j(0); j < fine_num_loc_dofs; ++j)
1473 {
1474 mass(i,j) += fine_trafo_data.jac_det * fine_cubature.get_weight(k) *
1475 fine_space_data.phi[i].value * fine_space_data.phi[j].value;
1476 // go for next fine mesh trial DOF
1477 }
1478
1479 // coarse mesh trial function loop
1480 for(int j(0); j < coarse_num_loc_dofs; ++j)
1481 {
1482 lmd(i,j) +=
1483 fine_trafo_data.jac_det * fine_cubature.get_weight(k) *
1484 fine_space_data.phi[i].value * coarse_space_data.phi[j].value;
1485 // go for next fine mesh trial DOF
1486 }
1487 // go for next fine mesh test DOF
1488 }
1489 // go for next cubature point
1490 }
1491
1492 // finish coarse mesh evaluators
1493 fine_space_eval.finish();
1494 fine_trafo_eval.finish();
1495
1496 // invert fine mesh mass matrix
1497 Math::invert_matrix(fine_num_loc_dofs, mass.sn, &mass.v[0][0], pivot);
1498
1499 // Note:
1500 // Usually, one would check whether the determinant returned by the invert_matrix
1501 // function is normal. However, this can lead to false alerts when assembling in
1502 // single precision, as the mass matrix entries are of magnitude h^2 (in 2D), i.e.
1503 // the determinant can become subnormal or even (numerically) zero although the
1504 // condition number of the matrix is still fine and the inversion was successful.
1505 // Therefore, we first multiply the (hopefully) inverted mass matrix by the
1506 // inter-level mass matrix and check whether the Frobenius norm of the result
1507 // is normal. If our matrix inversion failed, the result is virtually guaranteed
1508 // to be garbage, so this should serve well enough as a sanity check.
1509
1510 // compute X := M^{-1}*N
1511 lid.set_mat_mat_mult(mass, lmd);
1512
1513 // sanity check for matrix inversion
1514 if(!Math::isnormal(lid.norm_frobenius()))
1516
1517 // compute local fine vector
1518 lv_f.format();
1519 for(int i(0); i < fine_num_loc_dofs; ++i)
1520 for(int j(0); j < coarse_num_loc_dofs; ++j)
1521 lv_f[i] += lid[i][j] * lv_c[j];
1522
1523 // prepare fine mesh dof-mapping
1524 fine_dof_mapping.prepare(fcell);
1525
1526 // scatter local fine vector
1527 scatter_f(lv_f, fine_dof_mapping);
1528
1529 // update weights
1530 lv_w.format(DataType(1));
1531 scatter_w(lv_w, fine_dof_mapping);
1532
1533 // finish fine mesh dof-mapping
1534 fine_dof_mapping.finish();
1535
1536 // go for next child cell
1537 }
1538
1539 // finish coarse mesh evaluators
1540 coarse_space_eval.finish();
1541 coarse_trafo_eval.finish();
1542
1543 // finish coarse mesh dof-mapping
1544 coarse_dof_mapping.finish();
1545
1546 // go for next coarse mesh cell
1547 }
1548 }
1549
1573 template<
1574 typename Vector_,
1575 typename FineSpace_,
1576 typename CoarseSpace_>
1578 Vector_& vector_f,
1579 const Vector_& vector_c,
1580 const FineSpace_& fine_space,
1581 const CoarseSpace_& coarse_space,
1582 const String& cubature_name)
1583 {
1584 Vector_ vector_w = vector_f.clone(LAFEM::CloneMode::Layout);
1585 vector_w.format();
1586
1587 prolongate_vector(vector_f, vector_w, vector_c, fine_space, coarse_space, cubature_name);
1588
1589 // finally, scale fine mesh vector by inverse weights
1590 vector_w.component_invert(vector_w);
1591 vector_f.component_product(vector_f, vector_w);
1592 }
1593
1640 template<
1641 typename Vector_,
1642 typename TargetSpace_,
1643 typename SourceSpace_,
1644 typename Target2SourceAdjactor_>
1646 Vector_& vector_target,
1647 Vector_& vector_weight,
1648 const Vector_& vector_source,
1649 const TargetSpace_& space_target,
1650 const SourceSpace_& space_source,
1651 const Target2SourceAdjactor_& trg2src,
1652 const String& cubature_name)
1653 {
1654 // validate matrix and vector dimensions
1655 XASSERTM(vector_target.size() == space_target.get_num_dofs(), "invalid vector size");
1656 XASSERTM(vector_weight.size() == space_target.get_num_dofs(), "invalid vector size");
1657 XASSERTM(vector_source.size() == space_source.get_num_dofs(), "invalid vector size");
1658
1659 typedef typename Vector_::DataType DataType;
1660 typedef typename Vector_::ValueType ValueType;
1661
1662 // typedefs for trafos, mesh and shape
1663 typedef typename TargetSpace_::TrafoType TargetTrafoType;
1664 typedef typename SourceSpace_::TrafoType SourceTrafoType;
1665 typedef typename SourceSpace_::ShapeType ShapeType;
1666
1667 // typedefs for dof-mappings
1668 typedef typename TargetSpace_::DofMappingType TargetDofMapping;
1669 typedef typename SourceSpace_::DofMappingType SourceDofMapping;
1670
1671 // typedefs for trafo evaluators
1672 typedef typename TargetTrafoType::template Evaluator<ShapeType, DataType>::Type TargetTrafoEvaluator;
1673 typedef typename SourceTrafoType::template Evaluator<ShapeType, DataType>::Type SourceTrafoEvaluator;
1674
1675 // typedefs for space evaluators
1676 typedef typename TargetSpace_::template Evaluator<TargetTrafoEvaluator>::Type TargetSpaceEvaluator;
1677 typedef typename SourceSpace_::template Evaluator<SourceTrafoEvaluator>::Type SourceSpaceEvaluator;
1678
1679 // define target and source mesh trafo configurations
1680 typedef typename TargetSpaceEvaluator::template ConfigTraits<SpaceTags::value> TargetSpaceConfigTraits;
1681 typedef typename SourceSpaceEvaluator::template ConfigTraits<SpaceTags::value> SourceSpaceConfigTraits;
1682 static constexpr TrafoTags target_trafo_config = TrafoTags::img_point | TrafoTags::jac_det | TargetSpaceConfigTraits::trafo_config;
1683 static constexpr TrafoTags source_trafo_config = TrafoTags::jac_det | SourceSpaceConfigTraits::trafo_config;
1684
1685 // typedefs for trafo data
1686 typedef typename TargetTrafoEvaluator::template ConfigTraits<target_trafo_config>::EvalDataType TargetTrafoEvalData;
1687 typedef typename SourceTrafoEvaluator::template ConfigTraits<source_trafo_config>::EvalDataType SourceTrafoEvalData;
1688
1689 // typedef for space data
1690 typedef typename TargetSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType TargetSpaceEvalData;
1691 typedef typename SourceSpaceEvaluator::template ConfigTraits<SpaceTags::value>::EvalDataType SourceSpaceEvalData;
1692
1693 // typedef for source inverse mapping data
1694 typedef Trafo::InverseMapping<SourceTrafoType, DataType> SourceInverseMappingType;
1695 typedef typename SourceInverseMappingType::InvMapDataType SourceInvMapData;
1696
1697 // typedefs for cubature rule and factory
1698 typedef typename Intern::CubatureTraits<TargetTrafoEvaluator>::RuleType CubatureRuleType;
1699
1700 // local target mass matrix
1702
1703 // local target-source inter-mesh matrix
1705
1706 // local target and source vectors
1709
1710 // fetch the trafos
1711 const TargetTrafoType& target_trafo = space_target.get_trafo();
1712 const SourceTrafoType& source_trafo = space_source.get_trafo();
1713
1714 // create the cubature rule
1715 Cubature::DynamicFactory cubature_factory(cubature_name);
1716 CubatureRuleType target_cubature(Cubature::ctor_factory, cubature_factory);
1717 const std::size_t num_cub_pts = std::size_t(target_cubature.get_num_points());
1718
1719 // number of failed cubature points
1720 int failed_points = 0;
1721
1722 // we open a OpenMP section here since this is a quite expensive assembly
1723 FEAT_PRAGMA_OMP(parallel reduction(+:failed_points))
1724 {
1725 // create gather/scatter-axpys
1726 typename Vector_::GatherAxpy gather_s(vector_source);
1727 typename Vector_::ScatterAxpy scatter_t(vector_target);
1728 typename Vector_::ScatterAxpy scatter_w(vector_weight);
1729
1730 // create DOF-mappings
1731 TargetDofMapping target_dof_mapping(space_target);
1732 SourceDofMapping source_dof_mapping(space_source);
1733
1734 // create trafo evaluators
1735 TargetTrafoEvaluator target_trafo_eval(target_trafo);
1736 SourceTrafoEvaluator source_trafo_eval(source_trafo);
1737
1738 // create space evaluators
1739 TargetSpaceEvaluator space_target_eval(space_target);
1740 SourceSpaceEvaluator space_source_eval(space_source);
1741
1742 TargetTrafoEvalData target_trafo_data;
1743 SourceTrafoEvalData source_trafo_data;
1744 TargetSpaceEvalData space_target_data;
1745 SourceSpaceEvalData space_source_data;
1746
1747 // target space basis values, pre-multiplied by cubature weights and jacobian determinants
1749 std::vector<TargetBasisValueVector> target_basis_values;
1750 target_basis_values.resize(num_cub_pts);
1751
1752 // create an inverse mapping object for the source
1753 SourceInverseMappingType source_inv_map(source_trafo);
1754
1755 // the inverse mapping data object
1756 std::vector<SourceInvMapData> source_inv_map_data;
1757 source_inv_map_data.resize(num_cub_pts);
1758
1759 // [local source cell index] = (inverse map cell index, cubature point index)
1760 std::vector<std::vector<std::pair<std::size_t, std::size_t>>> source_cell_map;
1761 source_cell_map.reserve(30);
1762
1763 // allocate local stuff
1764 LocTrgMatrixType trg_mass;
1765 LocTSIMatrixType tsi_mass, loc_trans;
1766 LocTrgVectorType loc_trg, loc_weight;
1767 LocSrcVectorType loc_src;
1768
1769 // format local weights to 1
1770 loc_weight.format(DataType(1));
1771
1772 // pivot array for factorization
1773 int pivot[TargetSpaceEvaluator::max_local_dofs];
1774
1775 // loop over all target mesh cells
1776 // note: OpenMP (sometimes) requires a signed iteration variable
1777 FEAT_PRAGMA_OMP(for schedule(dynamic,16))
1778 for(std::int64_t itrg_cell = 0ull; itrg_cell < std::int64_t(target_trafo_eval.get_num_cells()); ++itrg_cell)
1779 {
1780 // cast target cell index
1781 const Index trg_cell = Index(itrg_cell);
1782
1783 // collect all source cells that intersect with the current target cell
1784 std::vector<Index> source_cells;
1785 for(auto it = trg2src.image_begin(trg_cell); it != trg2src.image_end(trg_cell); ++it)
1786 source_cells.push_back(*it);
1787
1788 // allocate source cell map to correct size
1789 source_cell_map.resize(source_cells.size());
1790
1791 // allocate local transfer matrices
1792 //loc_trg_vec.resize(source_cells.size());
1793 loc_trg.format();
1794
1795 // prepare target trafo evaluator
1796 target_trafo_eval.prepare(trg_cell);
1797
1798 // prepare target space evaluator
1799 space_target_eval.prepare(target_trafo_eval);
1800
1801 // fetch number of local target DOFs
1802 const int target_num_loc_dofs = space_target_eval.get_num_local_dofs();
1803
1804 // format local matrices
1805 trg_mass.format();
1806
1807 // first of all, let's loop over all target cubature points and unmap them onto the source mesh
1808 // we will also integrate the target mesh mass matrix while we're at it
1809 for(std::size_t k(0); k < num_cub_pts; ++k)
1810 {
1811 // compute trafo data
1812 target_trafo_eval(target_trafo_data, target_cubature.get_point(int(k)));
1813
1814 // compute basis function data
1815 space_target_eval(space_target_data, target_trafo_data);
1816
1817 // integrate target mesh mass matrix entries
1818 for(int i(0); i < target_num_loc_dofs; ++i)
1819 {
1820 // save pre-weighted target basis value for later use
1821 target_basis_values.at(k)[i] = target_trafo_data.jac_det * target_cubature.get_weight(int(k)) * space_target_data.phi[i].value;
1822 for(int j(0); j < target_num_loc_dofs; ++j)
1823 {
1824 trg_mass(i,j) += target_basis_values.at(k)[i] * space_target_data.phi[j].value;
1825 }
1826 }
1827
1828 // try to unmap cubature point from real coordinates onto source cell reference coordinates
1829 SourceInvMapData& simd = source_inv_map_data.at(k);
1830 simd = source_inv_map.unmap_point(target_trafo_data.img_point, source_cells, false);
1831
1832 // did we fail to unmap the point?
1833 if(simd.empty())
1834 {
1835 ++failed_points;
1836 continue;
1837 }
1838
1839 // now let's loop over all source cells that were found to contain/intersect the current cubature
1840 // point and update our source-cell-to-cubature-point map
1841 for(std::size_t i(0); i < simd.size(); ++i)
1842 {
1843 // find the local source cell index that corresponds to this source cell index
1844 std::size_t loc_idx = 0u;
1845 for(; loc_idx < source_cells.size(); ++loc_idx)
1846 if(source_cells.at(loc_idx) == simd.cells.at(i))
1847 break;
1848 XASSERT(loc_idx < source_cells.size());
1849
1850 // add this cubature point to the set of points for this source cell
1851 source_cell_map.at(loc_idx).push_back(std::make_pair(i, k));
1852 }
1853 }
1854
1855 // finish target mesh evaluators
1856 space_target_eval.finish();
1857 target_trafo_eval.finish();
1858
1859 // invert target mesh mass matrix
1860 Math::invert_matrix(target_num_loc_dofs, trg_mass.sn, &trg_mass.v[0][0], pivot);
1861
1862 // Note:
1863 // Usually, one would check whether the determinant returned by the invert_matrix
1864 // function is normal. However, this can lead to false alerts when assembling in
1865 // single precision, as the mass matrix entries are of magnitude h^2 (in 2D), i.e.
1866 // the determinant can become subnormal or even (numerically) zero although the
1867 // condition number of the matrix is still fine and the inversion was successful.
1868 // Therefore, we first multiply the (hopefully) inverted mass matrix by the
1869 // inter-level mass matrix and check whether the Frobenius norm of the result
1870 // is normal. If our matrix inversion failed, the result is virtually guaranteed
1871 // to be garbage, so this should serve well enough as a sanity check.
1872
1873 // now let's loop over all source cells that were found
1874 for(std::size_t is = 0u; is < source_cell_map.size(); ++is)
1875 {
1876 // get source cell index
1877 const Index src_cell = source_cells.at(is);
1878
1879 // get the cubature points map
1880 std::vector<std::pair<std::size_t, std::size_t>> cub_pts_map = source_cell_map.at(is);
1881
1882 // no cubature points on this source cell?
1883 if(cub_pts_map.empty())
1884 continue;
1885
1886 // prepare source trafo evaluator
1887 source_trafo_eval.prepare(src_cell);
1888
1889 // prepare source space evaluator
1890 space_source_eval.prepare(source_trafo_eval);
1891
1892 // fetch number of local source DOFs
1893 const int source_num_loc_dofs = space_source_eval.get_num_local_dofs();
1894
1895 // format our inter-mesh mass matrix
1896 tsi_mass.format();
1897
1898 // loop over all cubature points and integrate
1899 for(auto cit = cub_pts_map.begin(); cit != cub_pts_map.end(); ++cit)
1900 {
1901 // get the index of the source cell in the inverse mapping data object
1902 const std::size_t src_i = cit->first;
1903
1904 // get the index of the cubature point
1905 const std::size_t cub_k = cit->second;
1906
1907 // get the source inverse mapping data for this cubature point
1908 SourceInvMapData& simd = source_inv_map_data.at(cub_k);
1909
1910 // ensure that this is the right cell
1911 XASSERT(simd.cells.at(src_i) == src_cell);
1912
1913 // compute our averaging weight: we have to normalize in case that this cubature
1914 // point is intersecting more than one source cell
1915 DataType weight = DataType(1) / DataType(simd.size());
1916
1917 // alright, evaluate our source trafo and space
1918 source_trafo_eval(source_trafo_data, simd.dom_points.at(src_i));
1919
1920 // compute basis function data
1921 space_source_eval(space_source_data, source_trafo_data);
1922
1923 // integrate inter-mesh mass matrix
1924 for(int i(0); i < target_num_loc_dofs; ++i)
1925 for(int j(0); j < source_num_loc_dofs; ++j)
1926 tsi_mass(i, j) += weight * target_basis_values.at(cub_k)[i] * space_source_data.phi[j].value;
1927
1928 } // go for next cubature point
1929
1930 // finish source mesh evaluators
1931 space_source_eval.finish();
1932 source_trafo_eval.finish();
1933
1934 // compute X := M^{-1}*N
1935 loc_trans.set_mat_mat_mult(trg_mass, tsi_mass);
1936
1937 // sanity check for matrix inversion
1938 if(!Math::isnormal(loc_trans.norm_frobenius()))
1940
1941 // prepare source mesh dof-mapping
1942 source_dof_mapping.prepare(source_cells.at(is));
1943
1944 // gather the local vector
1945 loc_src.format();
1946 gather_s(loc_src, source_dof_mapping);
1947
1948 // finish source mesh dof-mapping
1949 source_dof_mapping.finish();
1950
1951 // update local target vector
1952 for(int i(0); i < target_num_loc_dofs; ++i)
1953 for(int j(0); j < source_num_loc_dofs; ++j)
1954 loc_trg[i] += loc_trans[i][j] * loc_src[j];
1955
1956 } // continue with next source cell
1957
1958 // prepare target mesh dof-mapping
1959 target_dof_mapping.prepare(trg_cell);
1960
1961 // scattering is a potential data race
1962 FEAT_PRAGMA_OMP(critical)
1963 {
1964 // update target weights
1965 scatter_t(loc_trg, target_dof_mapping);
1966 scatter_w(loc_weight, target_dof_mapping);
1967 } // pragma omp critical
1968
1969 // finish target mesh dof-mapping
1970 target_dof_mapping.finish();
1971 } // go for next target mesh cell
1972 } // pragma omp parallel
1973
1974 // return number of failed points
1975 return failed_points;
1976 }
1977
2013 template<
2014 typename Vector_,
2015 typename TargetSpace_,
2016 typename SourceSpace_,
2017 typename Target2SourceAdjactor_>
2019 Vector_& vector_target,
2020 const Vector_& vector_source,
2021 const TargetSpace_& space_target,
2022 const SourceSpace_& space_source,
2023 const Target2SourceAdjactor_& trg2src,
2024 const String& cubature_name)
2025 {
2026 // create a weight vector
2027 Vector_ weight = vector_target.clone(LAFEM::CloneMode::Layout);
2028 weight.format();
2029
2030 // assemble matrix and weight
2031 int rtn = transfer_intermesh_vector_direct(vector_target, weight, vector_source, space_target, space_source, trg2src, cubature_name);
2032
2033 // scale transfer matrix rows by inverse weights
2034 weight.component_invert(weight);
2035 vector_target.component_product(vector_target, weight);
2036
2037 return rtn;
2038 }
2039 }; // class GridTransfer<...>
2040 } // namespace Assembly
2041} // namespace FEAT
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
bool empty() const
Checks whether the permutation is empty.
Grid-Transfer assembly class template.
static int assemble_intermesh_transfer(Matrix_ &matrix, Vector_ &vector, const TargetSpace_ &space_target, const SourceSpace_ &space_source, const Target2SourceAdjactor_ &trg2src, const String &cubature_name)
Assembles a generic inter-mesh transfer matrix and its corresponding weight vector.
static void assemble_truncation(Matrix_ &matrix, Vector_ &vector, const FineSpace_ &fine_space, const CoarseSpace_ &coarse_space, const String &cubature_name)
Assembles a truncation matrix and its corresponding weight vector.
static void assemble_prolongation_direct(Matrix_ &matrix, const FineSpace_ &fine_space, const CoarseSpace_ &coarse_space, const Cubature::DynamicFactory &cubature_factory)
Assembles a prolongation matrix.
static void assemble_truncation_direct(Matrix_ &matrix, const FineSpace_ &fine_space, const CoarseSpace_ &coarse_space, const String &cubature_name)
Assembles a truncation matrix.
static void assemble_truncation(Matrix_ &matrix, Vector_ &vector, const FineSpace_ &fine_space, const CoarseSpace_ &coarse_space, const Cubature::DynamicFactory &cubature_factory)
Assembles a truncation matrix and its corresponding weight vector.
static int transfer_intermesh_vector_direct(Vector_ &vector_target, const Vector_ &vector_source, const TargetSpace_ &space_target, const SourceSpace_ &space_source, const Target2SourceAdjactor_ &trg2src, const String &cubature_name)
Performs a generic inter-mesh transfer of a primal vector directly.
static void assemble_prolongation(Matrix_ &matrix, Vector_ &vector, const FineSpace_ &fine_space, const CoarseSpace_ &coarse_space, const Cubature::DynamicFactory &cubature_factory)
Assembles a prolongation matrix and its corresponding weight vector.
static void assemble_truncation_direct(Matrix_ &matrix, const FineSpace_ &fine_space, const CoarseSpace_ &coarse_space, const Cubature::DynamicFactory &cubature_factory)
Assembles a truncation matrix.
static int transfer_intermesh_vector(Vector_ &vector_target, Vector_ &vector_weight, const Vector_ &vector_source, const TargetSpace_ &space_target, const SourceSpace_ &space_source, const Target2SourceAdjactor_ &trg2src, const String &cubature_name)
Performs a generic inter-mesh transfer of a primal vector and assembles a compatible weight vector.
static int assemble_intermesh_transfer_direct(Matrix_ &matrix, const TargetSpace_ &space_target, const SourceSpace_ &space_source, const Target2SourceAdjactor_ &trg2src, const String &cubature_name)
Assembles a generic inter-mesh transfer matrix and its corresponding weight vector.
static void prolongate_vector(Vector_ &vector_f, Vector_ &vector_w, const Vector_ &vector_c, const FineSpace_ &fine_space, const CoarseSpace_ &coarse_space, const String &cubature_name)
Prolongates a primal vector and assembles a compatible weight vector.
static void assemble_prolongation(Matrix_ &matrix, Vector_ &vector, const FineSpace_ &fine_space, const CoarseSpace_ &coarse_space, const String &cubature_name)
Assembles a prolongation matrix and its corresponding weight vector.
static void assemble_prolongation_direct(Matrix_ &matrix, const FineSpace_ &fine_space, const CoarseSpace_ &coarse_space, const String &cubature_name)
Assembles a prolongation matrix.
static void prolongate_vector_direct(Vector_ &vector_f, const Vector_ &vector_c, const FineSpace_ &fine_space, const CoarseSpace_ &coarse_space, const String &cubature_name)
Prolongates a primal vector directly.
Base exception class.
Definition: exception.hpp:27
A coarse cell to fine cell mapping class.
String class implementation.
Definition: string.hpp:46
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.
Inverse Trafo mapping class template.
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
@ img_point
specifies whether the trafo should supply image point coordinates
@ jac_det
specifies whether the trafo should supply jacobian determinants