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