AMDiS  0.1
The Adaptive Multi-Dimensional Simulation Toolbox
PeriodicBC.inc.hpp
1 #pragma once
2 
3 #include <algorithm>
4 #include <array>
5 #include <cmath>
6 #include <limits>
7 
8 #include <dune/functions/functionspacebases/subentitydofs.hh>
9 
10 #include <amdis/LinearAlgebra.hpp>
11 #include <amdis/Output.hpp>
12 #include <amdis/functions/FunctionFromCallable.hpp>
13 #include <amdis/typetree/Traversal.hpp>
14 
15 namespace AMDiS {
16 
17 template <class Mat, class Sol, class Rhs, class Basis, class TP>
20 {
21  if (!bool(hasConnectedIntersections_)) {
22  hasConnectedIntersections_ = true;
23  const auto& gridView = basis_.gridView().grid().levelGridView(0);
24  for (auto const& element : elements(gridView)) {
25  for (const auto& intersection : intersections(gridView, element)) {
26  if (!boundarySubset_(intersection))
27  continue;
28 
29  if (!intersection.neighbor()) {
30  hasConnectedIntersections_ = false;
31  break;
32  }
33  }
34  }
35  }
36 
37  if (*hasConnectedIntersections_)
38  initAssociations();
39  else
40  initAssociations2();
41 }
42 
43 
44 template <class Mat, class Sol, class Rhs, class Basis, class TP>
47 {
48  using std::sqrt;
49  static const auto tol = sqrt(std::numeric_limits<typename Domain::field_type>::epsilon());
50  periodicNodes_.assign(basis_.dimension(), false);
51 
52  auto localView = basis_.localView();
53  auto seDOFs = Dune::Functions::subEntityDOFs(basis_);
54  const auto& gridView = basis_.gridView();
55  for (auto const& element : elements(gridView)) {
56  if (!element.hasBoundaryIntersections())
57  continue;
58 
59  localView.bind(element);
60  for (const auto& intersection : intersections(gridView, element)) {
61  if (!boundarySubset_(intersection))
62  continue;
63 
64  test_exit(intersection.neighbor(),
65  "Neighbors of periodic intersection not assigned. Use a periodic Grid instead!");
66 
67  // collect DOFs of inside element on intersection
68  localView.bind(intersection.inside());
69  seDOFs.bind(localView, intersection.indexInInside(), 1);
70  std::vector<std::size_t> insideDOFs(seDOFs.begin(), seDOFs.end());
71  std::vector<MultiIndex> insideGlobalDOFs(insideDOFs.size());
72  std::transform(insideDOFs.begin(), insideDOFs.end(), insideGlobalDOFs.begin(),
73  [&](std::size_t localIndex) { return localView.index(localIndex); });
74  auto insideCoords = coords(localView.tree(), insideDOFs);
75 
76  // collect DOFs of ouside element on intersection
77  localView.bind(intersection.outside());
78  seDOFs.bind(localView, intersection.indexInOutside(), 1);
79  std::vector<std::size_t> outsideDOFs(seDOFs.begin(), seDOFs.end());
80  auto outsideCoords = coords(localView.tree(), outsideDOFs);
81 
82  // compare mapped coords of DOFs
83  assert(insideDOFs.size() == outsideDOFs.size());
84  for (std::size_t i = 0; i < insideCoords.size(); ++i) {
85  auto x = faceTrafo_.evaluate(insideCoords[i]);
86  for (std::size_t j = 0; j < outsideCoords.size(); ++j) {
87  auto const& y = outsideCoords[j];
88  if (distance(x,y) < tol) {
89  periodicNodes_[insideGlobalDOFs[i]] = true;
90  associations_[insideGlobalDOFs[i]] = localView.index(outsideDOFs[j]);
91  }
92  }
93  }
94  }
95  }
96 }
97 
98 namespace Impl
99 {
100  template <class D>
101  class CompareTol
102  {
103  using ctype = typename D::field_type;
104 
105  public:
106  CompareTol(ctype tol)
107  : tol_(tol)
108  {}
109 
110  bool operator()(D const& lhs, D const& rhs) const
111  {
112  using std::abs;
113  for (int i = 0; i < D::dimension; i++) {
114  if (abs(lhs[i] - rhs[i]) < tol_)
115  continue;
116  return lhs[i] < rhs[i];
117  }
118  return false;
119  }
120 
121  private:
122  ctype tol_;
123  };
124 }
125 
126 
127 template <class Mat, class Sol, class Rhs, class Basis, class TP>
130 {
131  using std::sqrt;
132  static const auto tol = sqrt(std::numeric_limits<typename Domain::field_type>::epsilon());
133  periodicNodes_.assign(basis_.dimension(), false);
134 
135  // Dune::ReservedVector<std::pair<EntitySeed,int>,2>
136  using EntitySeed = typename SubspaceBasis::GridView::Grid::template Codim<0>::EntitySeed;
137  using CoordAssoc = std::map<Domain, std::vector<std::pair<EntitySeed,int>>, Impl::CompareTol<Domain>>;
138  CoordAssoc coordAssoc(Impl::CompareTol<Domain>{tol});
139 
140  // generate periodic element pairs
141  const auto& gridView = basis_.gridView();
142  for (auto const& element : elements(gridView)) {
143  for (const auto& intersection : intersections(gridView, element)) {
144  if (!boundarySubset_(intersection))
145  continue;
146 
147  auto x = intersection.geometry().center();
148  auto seed = intersection.inside().seed();
149  coordAssoc[x].push_back({seed,intersection.indexInInside()});
150  coordAssoc[faceTrafo_.evaluate(x)].push_back({seed,intersection.indexInInside()});
151  }
152  }
153 
154  auto localView = basis_.localView();
155  auto seDOFs = Dune::Functions::subEntityDOFs(basis_);
156  for (auto const& assoc : coordAssoc) {
157  auto const& seeds = assoc.second;
158  if (seeds.size() != 2)
159  continue;
160 
161  // collect DOFs of inside element on intersection
162  auto el1 = gridView.grid().entity(seeds[0].first);
163  localView.bind(el1);
164  seDOFs.bind(localView, seeds[0].second, 1);
165  std::vector<std::size_t> insideDOFs(seDOFs.begin(), seDOFs.end());
166  std::vector<MultiIndex> insideGlobalDOFs(insideDOFs.size());
167  std::transform(insideDOFs.begin(), insideDOFs.end(), insideGlobalDOFs.begin(),
168  [&](std::size_t localIndex) { return localView.index(localIndex); });
169  auto insideCoords = coords(localView.tree(), insideDOFs);
170 
171  // collect DOFs of outside element on intersection
172  auto el2 = gridView.grid().entity(seeds[1].first);
173  localView.bind(el2);
174  seDOFs.bind(localView, seeds[1].second, 1);
175  std::vector<std::size_t> outsideDOFs(seDOFs.begin(), seDOFs.end());
176  auto outsideCoords = coords(localView.tree(), outsideDOFs);
177 
178  // compare mapped coords of DOFs
179  assert(insideDOFs.size() == outsideDOFs.size());
180  for (std::size_t i = 0; i < insideCoords.size(); ++i) {
181  auto x = faceTrafo_.evaluate(insideCoords[i]);
182  for (std::size_t j = 0; j < outsideCoords.size(); ++j) {
183  auto const& y = outsideCoords[j];
184  if (distance(x,y) < tol) {
185  periodicNodes_[insideGlobalDOFs[i]] = true;
186  associations_[insideGlobalDOFs[i]] = localView.index(outsideDOFs[j]);
187  }
188  }
189  }
190  }
191 }
192 
193 
194 template <class Mat, class Sol, class Rhs, class Basis, class TP>
195  template <class Node>
197 coords(Node const& tree, std::vector<std::size_t> const& localIndices) const
198 {
199  std::vector<Domain> dofCoords(localIndices.size());
200  for_each_leaf_node(tree, [&](auto const& node, auto&&)
201  {
202  std::size_t size = node.finiteElement().size();
203  auto geometry = node.element().geometry();
204 
205  auto const& localInterpol = node.finiteElement().localInterpolation();
206  using FiniteElement = TYPEOF(node.finiteElement());
207  using DomainType = typename FiniteElement::Traits::LocalBasisType::Traits::DomainType;
208  using RangeType = typename FiniteElement::Traits::LocalBasisType::Traits::RangeType;
209 
210  std::array<std::vector<typename RangeType::field_type>, Domain::dimension> coeffs;
211  for (int d = 0; d < Domain::dimension; ++d) {
212  auto evalCoord = [&](DomainType const& local) -> RangeType { return geometry.global(local)[d]; };
213  auto evalCoordFct = functionFromCallable<RangeType(DomainType)>(evalCoord);
214  localInterpol.interpolate(evalCoordFct, coeffs[d]);
215  }
216 
217  for (std::size_t j = 0; j < localIndices.size(); ++j) {
218  Domain x;
219  for (std::size_t i = 0; i < size; ++i) {
220  if (node.localIndex(i) == localIndices[j]) {
221  for (int d = 0; d < Domain::dimension; ++d)
222  x[d] = coeffs[d][i];
223  break;
224  }
225  }
226  dofCoords[j] = std::move(x);
227  }
228  });
229 
230  return dofCoords;
231 }
232 
233 
234 template <class Mat, class Sol, class Rhs, class Basis, class TP>
236 apply(Mat& matrix, Sol& solution, Rhs& rhs)
237 {
238  periodicBC(matrix, solution, rhs, periodicNodes_, associations_);
239 }
240 
241 } // end namespace AMDiS
void for_each_leaf_node(Tree &&tree, LeafFunc &&leafFunc)
Traverse tree and visit each leaf node.
Definition: Traversal.hpp:127
void apply(Mat &matrix, Sol &solution, Rhs &rhs) override
Move matrix rows (and columns) of dependant DOFs to the corresponding master DOFs.
Definition: PeriodicBC.inc.hpp:236
Contains all classes needed for solving linear and non linear equation systems.
Definition: AdaptBase.hpp:6
Implements a periodic boundary condition.
Definition: PeriodicBC.hpp:61
void init() override
Compute the pairs of associated boundary DOFs.
Definition: PeriodicBC.inc.hpp:19
void test_exit(bool condition, std::string const &str, Args &&... args)
test for condition and in case of failure print message and exit
Definition: Output.hpp:163