KASKADE 7 development version
fetransfer.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library KASKADE 7 */
4/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
5/* */
6/* Copyright (C) 2002-2023 Zuse Institute Berlin */
7/* */
8/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
9/* see $KASKADE/academic.txt */
10/* */
11/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13#ifndef FETRANSFER_HH
14#define FETRANSFER_HH
15
16
22#include <limits>
23#include <memory> // std::unique_ptr
24#include <vector>
25#include <map>
26#include <set>
27#include <stack>
28#include <iterator>
29#include <utility> // std::move
30
31
32#include "dune/grid/common/grid.hh"
33#include "dune/istl/bcrsmatrix.hh"
34#include "dune/common/fvector.hh"
35#include "dune/common/fmatrix.hh"
36#include "dune/grid/io/file/dgfparser/dgfparser.hh"
37//#include "dune/grid/geometrygrid.hh" // why should this be needed?
38
39#include "fem/fixdune.hh"
40#include "fem/gridmanager.hh"
41#include "fem/mllgeometry.hh"
43
44namespace Kaskade
45{
46 template<class G, class T> class CellData;
47 template <class Space, class CP> class TransferData;
48 struct AdaptationCoarseningPolicy ;
49
50
51 //---------------------------------------------------------------------
52 //---------------------------------------------------------------------
53
68 template <class Space, class ShapeFunctionSet>
69 void evaluateGlobalShapeFunctions(Space const& space,
71 std::vector<LocalPosition<typename Space::GridView>> const& xi,
73 ShapeFunctionSet const& shapeFunctionSet)
74 {
75
76 sfValues.setSize(xi.size(),shapeFunctionSet.size());
77
78 // Evaluation and transformation of shape function values. This
79 // realizes \Phi.
80 shapeFunctionSet.evaluate(xi,sfValues);
81
82 // Convert the local to global values. This realizes \Psi
83 typename Space::Mapper::Converter psi(cell);
84 for (int i=0; i<sfValues.N(); ++i)
85 {
86 psi.setLocalPosition(xi[i]);
87 for (int j=0; j<sfValues.M(); ++j)
88 sfValues[i][j] = psi.global(sfValues[i][j]);
89 }
90 }
91
92 template <class Space>
93 void evaluateGlobalShapeFunctions(Space const& space,
95 std::vector<LocalPosition<typename Space::GridView>> const& x,
97 {
98 evaluateGlobalShapeFunctions(space,cell,x,sfValues,space.mapper().shapefunctions(cell));
99 }
100
132 template <class Space, class ShapeFunctionSet>
133 void approximateGlobalValues(Space const& space,
134 typename Space::Grid::template Codim<0>::Entity const& cell,
137 ShapeFunctionSet const& sfs)
138 {
139 // Transform global values to local values. This is \Psi^{-1}.
140 typename Space::Mapper::Converter psi(cell);
141
142 auto const& iNodes = sfs.interpolationNodes();
143
144 for (int i=0; i<globalValues.N(); ++i)
145 {
146 psi.setLocalPosition(iNodes[i]);
147 for (int j=0; j<globalValues.M(); ++j)
148 globalValues[i][j] = psi.local(globalValues[i][j]);
149 }
150 // Interpolate local values, giving shape function coefficients. This is \Phi^+.
151 sfs.interpolate(globalValues,coeff);
152 }
153
158 template <class Space>
159 void approximateGlobalValues(Space const& space,
160 typename Space::Grid::template Codim<0>::Entity const& cell,
163 {
164 approximateGlobalValues(space,cell,globalValues,coeff,space.mapper().shapefunctions(cell));
165 }
166
194 template <class ChildSpace, class FatherSpace>
195 void localProlongationMatrix(ChildSpace const& childSpace,
197 FatherSpace const& fatherSpace,
200 typename ChildSpace::Mapper::ShapeFunctionSet const& childSfs,
201 typename FatherSpace::Mapper::ShapeFunctionSet const& fatherSfs)
202 {
203 using GridView = typename ChildSpace::GridView;
204 typedef typename ChildSpace::Grid Grid;
205 typedef typename ChildSpace::Scalar Scalar;
206 int const sfComponents = ChildSpace::sfComponents;
207
208 // Obtain the child interpolation nodes and map them to the father.
209 std::vector<LocalPosition<GridView>> iNodes(childSfs.interpolationNodes());
210
211 std::vector<int> dummy(iNodes.size());
212 MultiLevelLocalGeometry<Grid> const mlGeometry(childSpace.grid(),child,father,MultiLevelLocalGeometry<Grid>::ChildIsGlobal);
213 mlGeometry.local(iNodes,dummy);
214 assert(dummy.size()==iNodes.size()); // \todo: we assume the child is contained in the father. Is this guaranteed?
215
216 // Evaluate global shape functions on father cell.
218 evaluateGlobalShapeFunctions(fatherSpace,father,iNodes,afValues,fatherSfs);
219
220 // Interpolate global values on the child cell.
221 approximateGlobalValues(childSpace,child,afValues,prolongation,childSfs);
222 }
223
231 template <class ChildSpace, class FatherSpace>
232 void localProlongationMatrix(ChildSpace const& childSpace,
234 FatherSpace const& fatherSpace,
237 {
238 localProlongationMatrix(childSpace,child,fatherSpace,father,prolongation,
239 childSpace.mapper().shapefunctions(child),fatherSpace.mapper().shapefunctions(father));
240 }
241
253 {
254 void update (int) { }
255
256 template <class Cell>
257 bool accept(Cell const& cell) const
258 {
259 return cell.isLeaf();
260 }
261
262 template <class Cell>
263 bool operator()(Cell const& cell) const
264 {
265 return cell.mightBeCoarsened();
266 }
267 };
268
280 {
282 level(level_)
283 {}
284
285 void update( int level_ ) { level = level_ ; }
286
287 template <class Cell>
288 bool accept(Cell const& cell) const
289 {
290 return cell.level()==level;
291 }
292
293 template <class Cell>
294 bool operator()(Cell const& cell) const
295 {
296 return false;
297 }
298
299 private:
300 int level;
301 };
302
320 template <class Space, class CoarseningPolicy=AdaptationCoarseningPolicy>
322 {
323 public:
324 typedef typename Space::Grid Grid;
325 typedef typename Space::IndexSet IndexSet;
326 typedef typename Space::Scalar Scalar;
327 typedef typename Grid::GlobalIdSet::IdType Id;
330
332
333
334 private:
335 using ShapeFunctionSet = typename Space::Mapper::ShapeFunctionSet;
336
337 public:
343 LocalTransfer() = default;
344
349 : globalIndices(std::forward<std::vector<size_t>>(other.globalIndices))
352 { }
353
359 {
360 globalIndices = std::forward<std::vector<size_t>>(other.globalIndices);
361 restrictionMatrix = std::forward<LocalTransferMatrix>(other.restrictionMatrix);
362 shapeFunctionSet = other.shapeFunctionSet;
363 return *this;
364 }
365
369 LocalTransfer(LocalTransfer const& other) = default;
370
377 LocalTransfer(Space const& space,
378 Cell father,
379 CoarseningPolicy const& relevancePolicy = CoarseningPolicy())
380 {
381 // TODO: if father.isLeaf() is true, the local transfer matrix is essentially the identity
382 // (ok, it's the combiner). Check and implement a shortcut. After all, at least half of
383 // the cells visited here are leafs, and extracting the identity is tremendously cheap.
384 // TODO: Higher performance solution (for special case, though) has been developed in coarsening.hh.
385 // See whether this can be used to improve the performance here.
386 Grid const& grid = space.grid();
387 assert(&grid == &space.grid());
388
389 // Collect all relevant children descending from the father cell. "Relevant" meaning that
390 // projection to the father shall be done from that child cell. For normal grid transfer,
391 // these are the leaf cells, for multilevel projections, these are children on a certain
392 // level.
393 std::vector<Cell> children;
394 if ( relevancePolicy.accept(father) )
395 children.push_back(father);
396 else
397 {
398 auto end = father.hend(grid.maxLevel());
399 for (auto hi=father.hbegin(grid.maxLevel()); hi!=end; ++hi)
400 if (relevancePolicy.accept(*hi))
401 children.push_back(Cell(*hi));
402 }
403
404 // Get the shape function set of the father cell.
405 auto const& fatherShapeFunctions = space.mapper().shapefunctions(father);
406
407 // Compute the global indices associated to the relevant child cells
408 // (possibly including the father itself).
409 for (Cell const& child: children)
410 {
411 auto gi = space.mapper().globalIndices(child);
412 globalIndices.insert(globalIndices.end(),gi.begin(),gi.end());
413 }
414 std::sort(globalIndices.begin(),globalIndices.end());
415 globalIndices.erase(std::unique(globalIndices.begin(),globalIndices.end()),globalIndices.end());
416
417 // Initialize local restriction data.
418 // The restriction data stores for each interpolation point of the father cell (corresponding
419 // to the rows of the restrictionData matrix) the value of all child's global ansatz functions
420 // (corresponding to the rows of the restrictionData matrix) - considering only those ansatz
421 // functions with a support intersecting the father cell.
422 typedef typename Space::Mapper::ShapeFunctionSet::SfValueArray SfValueArray;
423 SfValueArray restrictionData;
424 restrictionData.setSize(fatherShapeFunctions.interpolationNodes().size(),globalIndices.size());
425 restrictionData = 0;
426
427 // Compute local restriction matrices.
428 // First declare variables that allocate memory in front of the loop to prevent frequent reallocations.
429 std::vector<int> fCount(restrictionData.N(),0);
430 // LocalTransferMatrix p;
431 SfValueArray afValues;
432 std::vector<size_t> globIdx;
433 using Position = LocalPosition<Grid>;
434 std::vector<Position> iNodes;
435 std::vector<int> nodesInside;
436
437 for (Cell const& child: children)
438 {
439 // Compute the mapping "globIdx" of degrees of freedom on the child to
440 // the set of dofs on all relevant children.
441 auto gi = space.mapper().globalIndices(child);
442 globIdx.resize(gi.size());
443 for (int j=0; j<gi.size(); ++j)
444 {
445 globIdx[j] = std::lower_bound(globalIndices.begin(),globalIndices.end(),gi[j]) - globalIndices.begin();
446 assert(globIdx[j]<globalIndices.size());
447 }
448
449 // Compute and scatter prolongation. First compute "p" as the matrix with p_kj the contribution
450 // of the k-th child shape function to the j-th father shape function.
451 // localProlongationMatrix(space,child,space,father,p,
452 // space.mapper().shapefunctions(child),
453 // space.mapper().shapefunctions(child)); // this makes only sense if the father and child shape functions are the same... TODO: replace this by father - however, as the father cell is not guaranteed to be a leaf cell, there need not be a father shape function set associated with the father cell. Maybe we can extract a "generic" shape function set from the father space?
454
455
456 // Compute and scatter restriction
457 // Create a geometry mapping from the child coordinate system (local) to father (global).
459
460 shapeFunctionSet = &fatherShapeFunctions;
461
462 iNodes = fatherShapeFunctions.interpolationNodes();
463 nodesInside.resize(iNodes.size());
464 std::iota(begin(nodesInside),end(nodesInside),0);
465 mlGeometry.local(iNodes,nodesInside);
466
467 // Evaluate the global shape functions at the interpolation nodes...
468 evaluateGlobalShapeFunctions(space,child,iNodes,afValues);
469
470 // ... and translate them into ansatz function values.
471 space.mapper().combiner(child,space.indexSet().index(child)).rightTransform(afValues);
472 assert(afValues.M() == globIdx.size()); // make sure the number of ansatz functions is consistent
473
474 for (int k=0; k<afValues.N(); ++k)
475 {
476 int rIdx = nodesInside[k];
477 assert(0<=rIdx && rIdx<fCount.size());
478 ++fCount[rIdx];
479 for (int i=0; i<afValues.M(); ++i)
480 {
481 assert(!std::isnan(restrictionData[rIdx][globIdx[i]]));
482 restrictionData[rIdx][globIdx[i]] += afValues[k][i];
483 assert(!std::isnan(restrictionData[rIdx][globIdx[i]]));
484 }
485 }
486 }
487
488 // Do averaging of restriction of discontinuous FE functions.
489 for (int i=0; i<restrictionData.N(); ++i)
490 {
491 assert(fCount[i]>0);
492 double avg = 1.0 / fCount[i];
493
494 for (int j=0; j<restrictionData.M(); ++j)
495 {
496 assert(!std::isnan(restrictionData[i][j]));
497 restrictionData[i][j] *= avg;
498 }
499 }
500
501 // Interpolate father shape functions.
502 approximateGlobalValues(space,father,restrictionData,restrictionMatrix);
503 }
504
505 std::vector<size_t> globalIndices;
507 ShapeFunctionSet const* shapeFunctionSet;
508 };
509
510
511 //---------------------------------------------------------------------
512
513
530 template <class Space, class CoarseningPolicy=AdaptationCoarseningPolicy>
532 {
533 public:
534 typedef typename Space::Grid Grid;
535 typedef typename Space::GridView GridView;
536 typedef typename Space::IndexSet IndexSet;
537 typedef typename Space::Scalar Scalar;
538 typedef typename Grid::GlobalIdSet::IdType Id;
540 typedef typename Grid::template Codim<0>::Entity Cell;
541
542 private:
545 typedef std::map<Id, RestrictionData> HistoryMap;
546
547 public:
548
556 {
557 public:
562 template <class StorageValue>
563 std::unique_ptr<Dune::BlockVector<StorageValue>> apply(Dune::BlockVector<StorageValue> const& oldCoeff) const
564 {
565 std::unique_ptr<Dune::BlockVector<StorageValue>> newCoeff(new Dune::BlockVector<StorageValue>(tm.size()));
566 for (int i=0; i<tm.size(); ++i)
567 {
568 StorageValue tmp(0.0);
569 for (int j=0; j<tm[i].first.size(); ++j)
570 tmp += tm[i].first[j].second * oldCoeff[tm[i].first[j].first];
571 (*newCoeff)[i] = tmp;
572 }
573 return newCoeff;
574 }
575
576 TransferMatrix(size_t rows, size_t cols):
577 tm(rows), nrows(rows), ncols(cols)
578 {
579 for (int i=0; i<tm.size(); ++i)
580 tm[i].second = std::numeric_limits<int>::max(); // sentinel: restriction level
581 }
582
583 private:
584
585 friend class TransferData;
586
587 // Enters transfer matrix entries for a specific row.
588 // This is done only if there have not yet been data entered with a smaller
589 // restriction level. Transfer coefficients are potentially stored for a whole
590 // cell hierarchy - we make sure that transfer is done only from the topmost
591 // grid level.
592 template <class ColIter, class EntryIter>
593 void storeRow(int row, int restrictionLevel, ColIter firstCol, ColIter lastCol,
594 EntryIter firstEntry)
595 {
596 if (tm[row].second > restrictionLevel)
597 {
598 tm[row].second = restrictionLevel;
599 tm[row].first.clear();
600 tm[row].first.reserve(std::distance(firstCol,lastCol));
601 while (firstCol != lastCol)
602 {
603 if (std::abs(*firstEntry)>1e-14)
604 tm[row].first.push_back(std::make_pair(*firstCol,*firstEntry));
605 ++firstCol;
606 ++firstEntry;
607 }
608 }
609 }
610
611 public:
612 void out(std::ostream& o) const
613 {
614 o << "shape=[" << nrows << ' ' << ncols << "];\n";
615 o << "data=[\n";
616 for (int i=0; i<tm.size(); ++i)
617 for (int j=0; j<tm[i].first.size(); ++j)
618 o << i+1 << ' ' << tm[i].first[j].first+1 << ' ' << tm[i].first[j].second << '\n';
619 o << "];\n";
620
621 }
622
623 int nRows() const { return nrows; }
624 int nCols() const { return ncols; }
625
626
627 private:
628 // Data for TransferMatrix - a vector with one entry for each row
629 // tm.first: sparse column-vector <index,value> tm.second: globalIdx
630 std::vector<std::pair<std::vector<std::pair<int,Scalar> >,int>> tm;
631 int nrows,ncols;
632 }; // end of class TransferMatrix
633
634
635
640 TransferData(Space const& space_, CoarseningPolicy const& mightBeCoarsened=CoarseningPolicy())
641 : space(space_), DOFcoarseSpace(space.degreesOfFreedom())
642 {
643 auto const& idSet = space.grid().globalIdSet();
644
645 typename Space::Evaluator evaluator(space);
646
647 std::set<Id> processedAncestors;
648
649
650 // Gather all information that is necessary to create local restriction matrices.
651 // We reach down from the leaf cells to father cells. Since a father cell has
652 // multiple children, father cells are visited several times, but need to be
653 // processed only once. We thus check whether the father has already been processed.
654 // This requires synchronization of the differen threads running in parallel on
655 // leaf cell ranges.
656 std::mutex mutex;
657 auto const& cellRanges = space.gridManager().cellRanges(space.gridView());
658 int nTasks = std::min(NumaThreadPool::instance().cpus(),cellRanges.maxRanges());
659 parallelFor([&](int i, int n)
660 {
661 HistoryMap myHistoryData; // thread-local result data
662
663 std::vector<std::pair<Id,Cell>> ancestors; // for storing the ancestors to be processed in this thread
664 // (defined here to prevent frequent reallocations)
665 for (auto const& cell: cellRanges.range(n,i))
666 {
667 // obtain and store only global indices of ansatz functions for all leaf cells.
668 // This does not conflict with other leaf cells in different threads and need
669 // not synchronized
670 myHistoryData.insert(std::pair(idSet.id(cell),
671 RestrictionData(space,cell,mightBeCoarsened)));
672
673 // lower level cells might be important for grid transfer
674 // todo@ !(entity->mightBeCoarsened) does not mean that this entity will exist after a grid change.
675 // e.g. if an entity with the same father is marked for coarsening, then there are problems.
676 {
677 Cell ancestor = cell;
678 std::lock_guard<std::mutex> lock(mutex);
679
680 while (ancestor.mightVanish() && ancestor.level()>0)
681 {
682 ancestor = ancestor.father();
683 Id id = idSet.id(ancestor);
684
685 // If no data for the current ancestor exists, create some. Mark taking over responsibility
686 // to prevent concurrent threads from processing the same ancestor.
687 if (processedAncestors.find(id) == processedAncestors.end())
688 {
689 processedAncestors.insert(id);
690 ancestors.push_back(std::pair(id,ancestor));
691 }
692 }
693 }
694
695 // Now process all the ancestors in our responsibility.
696 for (auto const& [id,ancestor]: ancestors)
697 myHistoryData.insert(std::pair(id,RestrictionData(space,ancestor,
698 mightBeCoarsened)));
699 ancestors.clear();
700 }
701
702 // Now we need to move our local leaf-level history data over to the global history data map.
703 // This requires synchronization.
704 std::lock_guard<std::mutex> lock(mutex);
705 historyData.merge(myHistoryData);
706 },nTasks);
707 }
708
709
727 std::unique_ptr<TransferMatrix> transferMatrix() const
728 {
729 typename Grid::GlobalIdSet const& idSet = space.grid().globalIdSet();
730 auto transfer = std::make_unique<TransferMatrix>(space.degreesOfFreedom(),DOFcoarseSpace);
731
732
733 for (auto cell: elements(space.gridView()))
734 {
735 // Among the ancestors of the current cell that have a
736 // restriction matrix stored, we select the one with the highest
737 // refinement level (i.e. the most exact representation of the
738 // FE functions before mesh adaptation.
739 Cell ancestor(cell);
740 typename HistoryMap::const_iterator restriction;
741 int colevel = 0; // The restriction level, i.e. the distance from the target grid view.
742 while((restriction=historyData.find(idSet.id(ancestor))) == historyData.end() && ancestor.level()> 0)
743 {
744 colevel++;
745 ancestor = ancestor.father();
746 }
747 assert(restriction != historyData.end());
748 RestrictionMatrix const& rm = restriction->second.restrictionMatrix;
749
750 auto index = space.indexSet().index(cell);
751
753 // WARNING: having the same shape function set for child and father makes only sense if these are the same...
754 //localProlongationMatrix(space,Cell(ci),space,ancestor,prolongation,*(restriction->second.shapeFunctionSet),*(restriction->second.shapeFunctionSet));
755 // Then let's try the following.
756 localProlongationMatrix(space,cell,space,ancestor,prolongation,
757 space.mapper().shapefunctions(index),*(restriction->second.shapeFunctionSet));
758
759 // compute matrix product prolongation * restriction
760 RestrictionMatrix localTransfer;
761 MatMult(localTransfer,prolongation,rm);
762
763
764 // apply K^+
765 space.mapper().combiner(cell,index).leftPseudoInverse(localTransfer);
766
767
768
769 // scatter the local transfer
770 auto rowIdx = space.mapper().globalIndices(index);
771 std::vector<size_t> const& columnIdx = restriction->second.globalIndices;
772 for (int i=0; i<localTransfer.N(); ++i)
773 {
774 transfer->storeRow(rowIdx[i], colevel,
775 columnIdx.begin(), columnIdx.end(),
776 localTransfer[i].begin());
777 }
778 }
779
780 return transfer;
781 }
782
783 private:
784 Space const& space;
785 HistoryMap historyData;
786 int DOFcoarseSpace;
787 };
788
789
790 // ----------------------------------------------------------------------------------------------
791
797 {
798 template<class Entity>
799 double operator()(Entity const& e) {return 1.0/e.geometry().volume();}
800 double scalingFactor() {return 1.0;}
801 double offset() {return 0.0;}
802 };
803
808 struct Volume
809 {
810 template<class Entity>
811 double operator()(Entity const& e) {return e.geometry().volume();}
812 double scalingFactor() {return 1.0;}
813 double offset() {return 0.0;}
814 };
815
821 {
822 template<class Entity>
823 double operator()(Entity const& e) {return 1.0;}
824 double scalingFactor() {return 1.0;}
825 double offset() {return 0.0;}
826 };
827
828 template<int scl=1>
829 struct SumUp
830 {
831 template<class Entity>
832 double operator()(Entity const& e) {return 1.0;}
833 double scalingFactor() {return 0.0;}
834 double offset() {return scl;}
835 };
836
837
854 template<typename Weighing=PlainAverage, typename FSElement, typename Function>
855 void interpolateGlobally(FSElement& fse, Function const& fu)
856 {
857 typedef typename FSElement::Space ImageSpace;
858 typedef typename ImageSpace::Grid Grid;
859
862 std::vector<typename Grid::ctype> sumOfWeights(fse.space().degreesOfFreedom(),0.0);
863
864 // Initialize the target to zero.
865 fse.coefficients() = typename FSElement::Scalar(0.0);
866
867 typename ImageSpace::Evaluator isfs(fse.space());
868 typename Function::Space::Evaluator dsfs(fu.space());
869 Weighing w;
870
871 using DirectValueType = decltype(fu.value(dsfs));
872 using ValueType = std::conditional_t<std::is_arithmetic<DirectValueType>::value,
874 DirectValueType>;
875 std::vector<ValueType> fuvalue; // function values - declare here to prevent reallocations
876
877 // Step through all the cells and perform local interpolation on each cell.
878 for (auto const& cell: elements(fse.space().gridView()))
879 {
880 auto index = fse.space().indexSet().index(cell);
881
882 isfs.moveTo(cell);
883 dsfs.moveTo(cell);
884
885 typename Grid::ctype myWeight = w(cell);
886 for (int i=0; i<isfs.size(); ++i)
887 sumOfWeights[isfs.globalIndices()[i]] += myWeight;
888
889 // Obtain interpolation nodes of target on this cell
890 auto const& iNodes(isfs.shapeFunctions().interpolationNodes());
891
892 // Evaluate source
893 globalValues.setSize(iNodes.size(),1);
894 localCoefficients.setSize(iNodes.size(),1);
895 fuvalue.resize(iNodes.size());
896 for (int i=0; i<iNodes.size(); ++i)
897 {
898 dsfs.evaluateAt(iNodes[i]);
899 fuvalue[i] = fu.value(dsfs);
900 }
901
902 // Perform local interpolation
903 for(int k=0; k<FSElement::components/ImageSpace::sfComponents; ++k)
904 {
905 for (int i=0; i<iNodes.size(); ++i)
906 for(int j=0; j<ImageSpace::sfComponents; ++j)
907 globalValues[i][0][j][0] = myWeight*fuvalue[i][ImageSpace::sfComponents*k+j];
908
909 approximateGlobalValues(fse.space(),cell,globalValues,localCoefficients);
910
911 assert(localCoefficients.N() == isfs.globalIndices().size());
912
913 // transform global values onto shape function coefficients
914 fse.space().mapper().combiner(cell,index).leftPseudoInverse(localCoefficients);
915
916 // add up the shape function coefficients to the ansatz function coefficients
917 for (int i=0; i<localCoefficients.N(); ++i)
918 fse.coefficients()[isfs.globalIndices()[i]][k] += localCoefficients[i][0];
919 }
920 }
921
922 // On vertices, edges, and faces, degrees of freedom may have received
923 // updates from multiple cells. Average this out.
924 for(int i=0; i<sumOfWeights.size(); ++i)
925 fse.coefficients()[i] /= (sumOfWeights[i]*w.scalingFactor()+w.offset());
926 }
927
928
929
945 template<typename Weighing=PlainAverage, typename Target, typename Source>
946 void interpolateGloballyWeak(Target& target, Source const& fu)
947 {
948 typedef typename Target::Space ImageSpace;
949 typedef typename ImageSpace::Grid Grid;
950 using Scalar = typename ImageSpace::Scalar;
951
952 auto const& space = target.space();
953
956 std::vector<typename Grid::ctype> sumOfWeights(space.degreesOfFreedom(),0.0);
957
958 // Initialize the target to zero.
959 target = 0.0;
960
961 typename ImageSpace::Evaluator isfs(space);
962 Weighing w;
963
964
965 using ValueType = decltype(fu.value(*space.gridView().template end<0>(),
967 static_assert(std::is_same_v<ValueType,typename Target::ValueType>,
968 "return type of the weak function view must agree with the value type of the assignment target");
969
970 std::vector<ValueType> fuvalue; // function values - declare here to prevent reallocations
971
972 for (auto const& cell: elements(space.gridView()))
973 {
974 auto index = space.indexSet().index(cell);
975 isfs.moveTo(cell);
976
977 typename Grid::ctype myWeight = w(cell);
978 for (int i=0; i<isfs.size(); ++i)
979 sumOfWeights[isfs.globalIndices()[i]] += myWeight;
980
981 // Obtain interpolation nodes of target on this cell
982 auto const& iNodes(isfs.shapeFunctions().interpolationNodes());
983
984 // Evaluate source
985 globalValues.setSize(iNodes.size(),1);
986 localCoefficients.setSize(iNodes.size(),1);
987 fuvalue.resize(iNodes.size());
988 for (int i=0; i<iNodes.size(); ++i)
989 fuvalue[i] = fu.value(cell,iNodes[i]);
990
991 // Perform local interpolation
992 for(int k=0; k<Target::components/ImageSpace::sfComponents; ++k)
993 {
994 for (int i=0; i<iNodes.size(); ++i)
995 for(int j=0; j<ImageSpace::sfComponents; ++j)
996 globalValues[i][0][j][0] = myWeight*fuvalue[i][ImageSpace::sfComponents*k+j];
997
998 approximateGlobalValues(space,cell,globalValues,localCoefficients);
999
1000 if (isfs.globalIndices().size()!=0)
1001 {
1002 assert(localCoefficients.N() == isfs.globalIndices().size());
1003
1004 // transform global values onto shape function coefficients
1005 space.mapper().combiner(cell,index).leftPseudoInverse(localCoefficients);
1006
1007 // add up the shape function coefficients to the ansatz function coefficients
1008 for (int i=0; i<localCoefficients.N(); ++i)
1009 target.coefficients()[isfs.globalIndices()[i]][k]+= localCoefficients[i][0];
1010 }
1011 }
1012 }
1013
1014 // On vertices, edges, and faces, degrees of freedom may have received
1015 // updates from multiple cells. Average this out.
1016 for(int i=0; i<sumOfWeights.size(); ++i)
1017 target.coefficients()[i] /= sumOfWeights[i]*w.scalingFactor()+w.offset();
1018 }
1019
1020
1021
1022 // ----------------------------------------------------------------------------------------------
1023
1024
1025
1031 template <class Functor>
1033 {
1034 public:
1035 WeakFunctionViewAdaptor(Functor const& g_)
1036 : g(g_)
1037 {}
1038
1039 template <class ...Args>
1040 auto value(Args... args) const
1041 {
1042 return g(std::forward<Args>(args)...);
1043 }
1044
1045 private:
1046 Functor g;
1047 };
1048
1058 template <class Functor>
1059 auto makeWeakFunctionView(Functor const& g)
1060 {
1062 }
1063
1072 template <class Space_, class Functor>
1074 {
1075 public:
1076 using Space = Space_;
1077
1078 FunctionViewAdaptor(Space const& space, Functor const& g_): g(g_), sp(space)
1079 {}
1080
1081 Space const& space() const
1082 {
1083 return sp;
1084 }
1085
1086 template <class ...Args>
1087 auto value(Args... args) const
1088 {
1089 return g(std::forward<Args>(args)...);
1090 }
1091
1092
1093 private:
1094 Functor g;
1095 Space const& sp;
1096 };
1097
1106 template <class Space, class Functor>
1107 auto makeFunctionView(Space const& space, Functor const& g)
1108 {
1109 return FunctionViewAdaptor<Space,Functor>(space,g);
1110 }
1111
1112 // ----------------------------------------------------------------------------------------------
1113
1117 template <class Fu1, class Fu2>
1118 [[deprecated]]
1119 void spaceTransfer(Fu1& f1, Fu2 const& f2)
1120 {
1121 // typedef TransferData<typename Fu2::Space> TrData;
1122 //
1123 // TrData trdata(f2.space());
1124 // std::unique_ptr<typename TrData::TransferMatrix> trMat=trdata.transferMatrix(f1.space());
1125 //
1126 //
1127 // (*f1) = *(trMat->apply(*f2));
1128 interpolateGlobally(*f1,*f2);
1129 }
1130
1131
1132
1133
1134
1135} /* end of namespace Kaskade */
1136#endif
Function is the interface for evaluatable functions .
Definition: concepts.hh:324
ValueType value(Cell const &cell, Dune::FieldVector< typename Cell::Geometry::ctype, Cell::dimension > const &localCoordinate) const
unspecified Space
The type of finite element space the evaluators of which are required for evaluating this FunctionVie...
Definition: concepts.hh:578
A LAPACK-compatible dense matrix class with shape specified at runtime.
void setSize(size_type r, size_type c)
Resizes the matrix to r x c, leaving the entries in an undefined state.
An adaptor that allows to turn lambda functions into function views.
Definition: fetransfer.hh:1074
Space const & space() const
Definition: fetransfer.hh:1081
auto value(Args... args) const
Definition: fetransfer.hh:1087
FunctionViewAdaptor(Space const &space, Functor const &g_)
Definition: fetransfer.hh:1078
Class that stores for a cell ("this entity" or "father") a local projection matrix.
Definition: fetransfer.hh:322
LocalTransferMatrix restrictionMatrix
Definition: fetransfer.hh:506
LocalTransfer()=default
default constructor leaves the object in a valid but undefined state.
DynamicMatrix< Dune::FieldMatrix< Scalar, 1, 1 > > LocalTransferMatrix
Definition: fetransfer.hh:331
Space::IndexSet IndexSet
Definition: fetransfer.hh:325
LocalTransfer(LocalTransfer const &other)=default
copy constructor
ShapeFunctionSet const * shapeFunctionSet
Definition: fetransfer.hh:507
LocalTransfer< Space, CoarseningPolicy > & operator=(LocalTransfer &&other)
move assignment
Definition: fetransfer.hh:358
Space::Scalar Scalar
Definition: fetransfer.hh:326
Grid::GlobalIdSet::IdType Id
Definition: fetransfer.hh:327
Kaskade::Cell< Grid > Cell
Definition: fetransfer.hh:329
std::vector< size_t > globalIndices
Definition: fetransfer.hh:505
LocalTransfer(Space const &space, Cell father, CoarseningPolicy const &relevancePolicy=CoarseningPolicy())
constructor
Definition: fetransfer.hh:377
LocalTransfer(LocalTransfer &&other)
move constructor
Definition: fetransfer.hh:348
Dune::FieldVector< Scalar, Space::sfComponents > SfValue
Definition: fetransfer.hh:328
Transformation of coordinates between ancestor and child.
Definition: mllgeometry.hh:51
void local(std::vector< Dune::FieldVector< ctype, dim > > &x, std::vector< int > &componentsInside) const
Transformation from global to local.
Definition: mllgeometry.hh:169
static NumaThreadPool & instance(int maxThreads=std::numeric_limits< int >::max())
Returns a globally unique thread pool instance.
A set of shape functions.
void evaluate(InterpolationNodes const &iNodes, SfValueArray &phi) const
Evaluate shape function set at a set of points. In notation of the LocalToGlobalMapperConcept,...
InterpolationNodes const & interpolationNodes() const
Interpolation points.
virtual int size() const
Number of shape functions in the set.
virtual void interpolate(SfValueArray const &A, Matrix &IA) const =0
Left-multiplies the provided matrix with the interpolation matrix of the shape function set.
Matrix that transforms a data vector v_1 corresponding to the old grid to a data vector v_2 correspon...
Definition: fetransfer.hh:556
void out(std::ostream &o) const
Definition: fetransfer.hh:612
TransferMatrix(size_t rows, size_t cols)
Definition: fetransfer.hh:576
std::unique_ptr< Dune::BlockVector< StorageValue > > apply(Dune::BlockVector< StorageValue > const &oldCoeff) const
Transforms oldCoeff, which lives on the old grid to an equivalent vector that lives on the new grid.
Definition: fetransfer.hh:563
A class storing data collected before grid adaptation that is necessary to transfer FE functions....
Definition: fetransfer.hh:532
Dune::FieldVector< Scalar, Space::sfComponents > SfValue
Definition: fetransfer.hh:539
Space::Scalar Scalar
Definition: fetransfer.hh:537
Space::GridView GridView
Definition: fetransfer.hh:535
Grid::GlobalIdSet::IdType Id
Definition: fetransfer.hh:538
TransferData(Space const &space_, CoarseningPolicy const &mightBeCoarsened=CoarseningPolicy())
Gathers all information that might be lost after the refinement process. To be called after preAdapt(...
Definition: fetransfer.hh:640
Space::IndexSet IndexSet
Definition: fetransfer.hh:536
std::unique_ptr< TransferMatrix > transferMatrix() const
Create a TransferMatrix.
Definition: fetransfer.hh:727
Grid::template Codim< 0 >::Entity Cell
Definition: fetransfer.hh:540
An adaptor that turns callables (e.g., lambdas) into weak function views.
Definition: fetransfer.hh:1033
WeakFunctionViewAdaptor(Functor const &g_)
Definition: fetransfer.hh:1035
auto value(Args... args) const
Definition: fetransfer.hh:1040
This file contains various utility functions that augment the basic functionality of Dune.
void approximateGlobalValues(Space const &space, typename Space::Grid::template Codim< 0 >::Entity const &cell, DynamicMatrix< Dune::FieldMatrix< typename Space::Scalar, Space::sfComponents, 1 > > &globalValues, DynamicMatrix< Dune::FieldMatrix< typename Space::Scalar, 1, 1 > > &coeff, ShapeFunctionSet const &sfs)
Computes global shape function coefficients such that the given set of global function values at the ...
Definition: fetransfer.hh:133
auto makeFunctionView(Space const &space, Functor const &g)
A convenience functor that supports the easy creation of function view adaptors.
Definition: fetransfer.hh:1107
auto makeWeakFunctionView(Functor const &g)
A convenience function turning callables (e.g., lambda functions) into weak function views.
Definition: fetransfer.hh:1059
void interpolateGlobally(FSElement &fse, Function const &fu)
Interpolates FunctionSpaceElement to FunctionSpaceElement.
Definition: fetransfer.hh:855
void evaluateGlobalShapeFunctions(Space const &space, Cell< typename Space::GridView > const &cell, std::vector< LocalPosition< typename Space::GridView > > const &xi, DynamicMatrix< Dune::FieldMatrix< typename Space::Scalar, Space::sfComponents, 1 > > &sfValues, ShapeFunctionSet const &shapeFunctionSet)
Computes the values of global shape functions at the given points (which are supposed to be local coo...
Definition: fetransfer.hh:69
void interpolateGloballyWeak(Target &target, Source const &fu)
Interpolates WeakFunctionViews to FunctionSpaceElement.
Definition: fetransfer.hh:946
typename GridView::template Codim< 0 >::Entity Cell
The type of cells (entities of codimension 0) in the grid view.
Definition: gridBasics.hh:35
Dune::FieldVector< T, n > max(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise maximum.
Definition: fixdune.hh:110
void MatMult(MatrixZ &z, Matrix const &x, Matrix const &y)
Computes Z = X*Y. X and Y need to be compatible, i.e. X.M()==Y.N() has to hold. No aliasing may occur...
Definition: fixdune.hh:614
Dune::FieldVector< T, n > min(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise minimum.
Definition: fixdune.hh:122
NumaBCRSMatrix< Dune::FieldMatrix< typename FineSpace::Scalar, 1, 1 >, SparseIndex > prolongation(CoarseSpace const &coarseSpace, FineSpace const &fineSpace)
Computes an interpolation-based prolongation matrix from a (supposedly) coarser space to a finer spac...
Definition: prolongation.hh:43
void parallelFor(Func const &f, int maxTasks=std::numeric_limits< int >::max())
A parallel for loop that executes the given functor in parallel on different CPUs.
Definition: threading.hh:489
Class for transformations between ancestors and their children.
Scalar distance(Point< Scalar, dim > const &first, Point< Scalar, dim > const &second)
void approximateGlobalValues(Space const &space, typename Space::Grid::template Codim< 0 >::Entity const &cell, DynamicMatrix< Dune::FieldMatrix< typename Space::Scalar, Space::sfComponents, 1 > > &globalValues, DynamicMatrix< Dune::FieldMatrix< typename Space::Scalar, 1, 1 > > &coeff)
Definition: fetransfer.hh:159
void localProlongationMatrix(ChildSpace const &childSpace, Cell< typename ChildSpace::Grid > const &child, FatherSpace const &fatherSpace, Cell< typename FatherSpace::Grid > const &father, DynamicMatrix< Dune::FieldMatrix< typename ChildSpace::Scalar, 1, 1 > > &prolongation, typename ChildSpace::Mapper::ShapeFunctionSet const &childSfs, typename FatherSpace::Mapper::ShapeFunctionSet const &fatherSfs)
Computes a local prolongation matrix for global shape functions from father cell to child cell.
Definition: fetransfer.hh:195
void spaceTransfer(Fu1 &f1, Fu2 const &f2)
DEPRECATED. Use interpolateGlobally instead.
Definition: fetransfer.hh:1119
policy class for LocalTransfer These two structures are used for determining whether to perform a "no...
Definition: fetransfer.hh:253
bool operator()(Cell const &cell) const
Definition: fetransfer.hh:263
bool accept(Cell const &cell) const
Definition: fetransfer.hh:257
A Weighing that associates to each cell its inverse volume.
Definition: fetransfer.hh:797
double operator()(Entity const &e)
Definition: fetransfer.hh:799
policy class for LocalTransfer These two structures are used for determining whether to perform a "no...
Definition: fetransfer.hh:280
bool accept(Cell const &cell) const
Definition: fetransfer.hh:288
bool operator()(Cell const &cell) const
Definition: fetransfer.hh:294
A Weighing that associates to each cell a constant weight of 1.
Definition: fetransfer.hh:821
double operator()(Entity const &e)
Definition: fetransfer.hh:823
double offset()
Definition: fetransfer.hh:834
double operator()(Entity const &e)
Definition: fetransfer.hh:832
double scalingFactor()
Definition: fetransfer.hh:833
A Weighing that associates to each cell its volume.
Definition: fetransfer.hh:809
double operator()(Entity const &e)
Definition: fetransfer.hh:811
double offset()
Definition: fetransfer.hh:813
double scalingFactor()
Definition: fetransfer.hh:812
A Weighing is a class that allows to compute weighted averages of values associated to cells of a gri...
Definition: concepts.hh:375
double scalingFactor() const
Defines the global scaling factor .
double offset() const
Defines the global offset .