Dune-Fufem 2.12-git
Loading...
Searching...
No Matches
improvegrid.hh
Go to the documentation of this file.
1// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set ts=8 sw=4 et sts=4:
3
4// SPDX-FileCopyrightText: Copyright © DUNE-FUFEM Project contributors, see file AUTHORS.md
5// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
6
7#ifndef DUNE_FUFEM_IMPROVEGRID_HH
8#define DUNE_FUFEM_IMPROVEGRID_HH
9
10#include <cmath>
11#include <vector>
15#include <dune/istl/bvector.hh>
16
19
20namespace Dune::Fufem::Impl {
21
22 template <class T>
24 {
26 r[0] = a[1] * b[2] - a[2] * b[1];
27 r[1] = a[2] * b[0] - a[0] * b[2];
28 r[2] = a[0] * b[1] - a[1] * b[0];
29 return r;
30 }
31
32} // end namespace Dune::Fufem::Impl
33
34template <class EntityType>
35double aspectRatio(const EntityType& entity)
36{
37 if (!entity.type().isTetrahedron())
38 DUNE_THROW(Dune::NotImplemented, "aspect ratio only for simplices!");
39
40 const int dim = EntityType::dimension;
41
42 namespace Impl = Dune::Fufem::Impl;
43 typename EntityType::Geometry geometry = entity.geometry();
44
45 const Dune::FieldVector<double,dim> a = geometry.corner(0);
46 const Dune::FieldVector<double,dim> b = geometry.corner(1);
47 const Dune::FieldVector<double,dim> c = geometry.corner(2);
48 const Dune::FieldVector<double,dim> d = geometry.corner(3);
49
53
54 Dune::FieldVector<double,dim> circumRadiusNumerator0 = Impl::crossProduct(ba,ca);
55 circumRadiusNumerator0 *= da.two_norm2();
56 Dune::FieldVector<double,dim> circumRadiusNumerator1 = Impl::crossProduct(da,ba);
57 circumRadiusNumerator1 *= ca.two_norm2();
58 Dune::FieldVector<double,dim> circumRadiusNumerator2 = Impl::crossProduct(ca,da);
59 circumRadiusNumerator2 *= ba.two_norm2();
60
61 Dune::FieldVector<double,dim> circumRadiusNumerator = circumRadiusNumerator0
62 + circumRadiusNumerator1 + circumRadiusNumerator2;
63
64 double circumRadius = circumRadiusNumerator.two_norm() / (2*(ba*Impl::crossProduct(ca,da)));
65
66 double volume = Impl::crossProduct(ba,ca) * da / 6;
67
68 double area = Impl::crossProduct(ba,ca).two_norm()/2;
69 area += Impl::crossProduct(da,ba).two_norm()/2;
70 area += Impl::crossProduct(da,ca).two_norm()/2;
71 area += Impl::crossProduct(Dune::FieldVector<double,dim>(c-b),Dune::FieldVector<double,dim>(d-b)).two_norm()/2;
72
73 double inRadius = 3*volume/area;
74
75 // May be negative due to inexact arithmetic
76 return std::abs(circumRadius / inRadius);
77
78}
79
86template <class GridType>
87int improveGridLevel(GridType& grid, double threshold, int level)
88{
89 const int dim = GridType::dimension;
90 const auto& levelView = grid.levelGridView(level);
91 const auto& indexSet = levelView.indexSet();
92
93 Dune::BitSetVector<1> isNewOnThisLevel(indexSet.size(dim), false);
94 Dune::BitSetVector<1> isTetMidPoint(indexSet.size(dim), false);
95 std::vector<Dune::FieldVector<double, dim> > bisectionPosition(indexSet.size(dim));
96
97 // ///////////////////////////////////////////////////////////////
98 // Create the whole grid boundary as a boundary patch
99 // ///////////////////////////////////////////////////////////////
100
101 BoundaryPatch<typename GridType::LevelGridView> boundary(levelView, true);
102
103 // /////////////////////////////////////////////////////////////
104 // We need to know which vertices is new on the maxlevel and which
105 // vertices are descendants of vertices on coarser levels.
106 // /////////////////////////////////////////////////////////////
107
108 double edgeMidPoints[6][3] = {{0.5,0,0},
109 {0.5,0.5,0},
110 {0,0.5,0},
111 {0,0,0.5},
112 {0.5,0,0.5},
113 {0,0.5,0.5}};
114
115 for (const auto& e : elements(levelView)) {
116
117 const auto& father = e.father();
118
119 const auto geometryInFather = e.geometryInFather();
120 for (size_t i=0; i<e.subEntities(dim); i++) {
121
122 const auto& positionInFather = geometryInFather.corner(i);
123
124 for (int j=0; j<6; j++) {
125 if ( std::abs(positionInFather[0]-edgeMidPoints[j][0]) < 0.1
126 && std::abs(positionInFather[1]-edgeMidPoints[j][1]) < 0.1
127 && std::abs(positionInFather[2]-edgeMidPoints[j][2]) < 0.1) {
128
129 isNewOnThisLevel[indexSet.subIndex(e,i,dim)][0] = true;
130 bisectionPosition[indexSet.subIndex(e,i,dim)] = father.geometry().global(positionInFather);
131 break;
132 }
133 }
134 // tetraeder mid points must be moved, too
135 if ( std::abs(positionInFather[0]-0.25) < 0.1
136 && std::abs(positionInFather[1]-0.25) < 0.1
137 && std::abs(positionInFather[2]-0.25) < 0.1) {
138
139 isNewOnThisLevel[indexSet.subIndex(e,i,dim)][0] = true;
140 isTetMidPoint[indexSet.subIndex(e,i,dim)][0] = true;
141 bisectionPosition[indexSet.subIndex(e,i,dim)] = father.geometry().global(positionInFather);
142 }
143 }
144 }
145
146 // ///////////////////////////////////////////////////////////////
147 // Mark the vertices of all 'bad' elements
148 // ///////////////////////////////////////////////////////////////
149 Dune::BitSetVector<1> badVertices(indexSet.size(dim),false);
150 for (const auto& e : elements(levelView)){
151
153
154 double indicator = aspectRatio(e);
155 if (indicator > threshold || e.geometry().jacobianInverseTransposed(dummy).determinant() < 0) {
156
157 // This element is of bad quality. Mark all its vertices
158 for (size_t i=0; i<e.subEntities(dim); i++){
159 if (boundary.containsVertex(indexSet.subIndex(e,i,dim)) || isTetMidPoint[indexSet.subIndex(e,i,dim)][0]) {
160 badVertices[indexSet.subIndex(e,i,dim)][0] = true;
161 }
162 }
163 }
164 }
165
166 // Loop over all new vertices
167 for (const auto& v : vertices(levelView)) {
168
169 // Get the index
170 int vIdx = indexSet.index(v);
171
172 if (!isNewOnThisLevel[vIdx][0] || !badVertices[vIdx][0])
173 continue;
174
175 grid.setPosition(v, bisectionPosition[vIdx]);
176 }
177
178 return badVertices.count();
179}
180
181template <class GridType>
182void improveGrid(GridType& grid, double threshold, int maxIter=10)
183{
184 const int dim = GridType::dimension;
185 int maxLevel = grid.maxLevel();
186
187 if (maxLevel==0)
188 return;
189
190 // Only works in 3d
191 if (dim!=3)
192 DUNE_THROW(Dune::GridError, "Grid improvement only for 3d grids!");
193
194 // By moving some vertices to improve certain elements other elements can worsen.
195 for(int i=0;i<maxIter;++i) {
196
197 int nBadVertices = 0;
198 // Could be, that new nodes were added on some corser level, too. So we must check all levels.
199 for(int level=maxLevel; level>0; --level) {
200 nBadVertices += improveGridLevel(grid, threshold, level);
201 }
202 std::cout << nBadVertices << " bad vertices were detected in grid improvement iteration " << i << "." << std::endl;
203 if(nBadVertices==0) break;
204 }
205}
206
207
208template <class GridView>
209void printAspectRatios(const GridView& gridView)
210{
211 double max(0);
213
214 for (const auto& e : elements(gridView)) {
215
216 double indicator = aspectRatio(e);
217
218 max = std::max(max ,indicator);
219 min = std::min(min ,indicator);
220 }
221 std::cout<<"Aspect ratios range from "<<min<<" -- "<<max<<std::endl;
222}
223
224#endif
int maxLevel() const
size_type dim() const
#define DUNE_THROW(E,...)
size_type count() const
constexpr FieldTraits< value_type >::real_type two_norm() const
constexpr FieldTraits< value_type >::real_type two_norm2() const
auto size(GeometryType type) const
IndexType subIndex(const typename Traits::template Codim< cc >::Entity &e, int i, unsigned int codim) const
IndexType index(const typename Traits::template Codim< cc >::Entity &e) const
int maxLevel() const
LevelGridView levelGridView(int level) const
Encapsulate a part of a grid boundary.
Definition boundarypatch.hh:217
T endl(T... args)
void improveGrid(GridType &grid, double threshold, int maxIter=10)
Definition improvegrid.hh:182
int improveGridLevel(GridType &grid, double threshold, int level)
Improve maximal aspect ratio of the grid by moving vertices.
Definition improvegrid.hh:87
double aspectRatio(const EntityType &entity)
Definition improvegrid.hh:35
void printAspectRatios(const GridView &gridView)
Definition improvegrid.hh:209
T max(T... args)
T min(T... args)
Contains a methods which prolongs a boundary patch defined on grid level zero to all other levels.