Dune-Fufem 2.11-git
Loading...
Searching...
No Matches
polyhedrondistance.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright © DUNE-FUFEM Project contributors, see file AUTHORS.md
2// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
3
4#ifndef DUNE_FUFEM_GEOMETRY_POLYHEDRONDISTANCE_HH
5#define DUNE_FUFEM_GEOMETRY_POLYHEDRONDISTANCE_HH
6
7// Based on the closest point projection from dune-contact
8
11
13
14template <class Coordinate, class Matrix>
16 Matrix &matrix) {
17 size_t const nCorners = segment.vertices.size();
18 for (size_t i = 0; i < nCorners; i++)
19 for (size_t j = 0; j <= i; j++)
20 matrix[i][j] = segment.vertices[i] * segment.vertices[j];
21 // make symmetric
22 for (size_t i = 0; i < nCorners; i++)
23 for (size_t j = i + 1; j < nCorners; j++)
24 matrix[i][j] = matrix[j][i];
25}
26
42template <class Coordinate>
43void approximate(Coordinate const &target, Dune::DynamicMatrix<double> const &A,
45 ConvexPolyhedron<Coordinate> const &segment,
47 size_t nCorners = segment.vertices.size();
48
49 // compute the residual
51 // compute rhs -= A*sol_
52 for (size_t k = 0; k < nCorners; k++)
53 for (size_t j = 0; j < nCorners; j++)
54 rhs[k] -= A[k][j] * sol[j];
55
56 // use the edge vectors as search directions
57 double alpha = 0.0;
58 for (size_t j1 = 0; j1 < nCorners - 1; ++j1) {
59 for (size_t j2 = j1 + 1; j2 < nCorners; ++j2) {
60 // compute matrix entry and rhs for edge direction
61 double a = A[j1][j1] - A[j1][j2] - A[j2][j1] + A[j2][j2];
62 double b = rhs[j1] - rhs[j2];
63
64 // compute minimizer for correction
65 if (a > 0) {
66 alpha = b / a;
67
68 double const largestAlpha = sol[j2];
69 double const smallestAlpha = -sol[j1];
70
71 // project alpha such that we stay positive
72 if (alpha > largestAlpha)
73 alpha = largestAlpha;
74 else if (alpha < smallestAlpha)
75 alpha = smallestAlpha;
76 } else {
77 // if the quadratic term vanishes, we have a linear function, which
78 // attains its extrema on the boundary
79 double sum = sol[j1] + sol[j2];
80
81 double lValue = 0.5 * A[j1][j1] * sum * sum - rhs[j1] * sum;
82 double uValue = 0.5 * A[j2][j2] * sum * sum - rhs[j2] * sum;
83
84 alpha = lValue < uValue ? sol[j2] : -sol[j1];
85 }
86 // apply correction
87 sol[j1] += alpha;
88 sol[j2] -= alpha;
89
90 // update the local residual for corrections
91 for (size_t p = 0; p < nCorners; p++)
92 rhs[p] -= (A[p][j1] - A[p][j2]) * alpha;
93 }
94 }
95}
96
97// Point-to-Polyhedron
98template <class Coordinate>
99double distance(const Coordinate &target,
100 const ConvexPolyhedron<Coordinate> &segment,
101 double correctionTolerance,
102 size_t maxIterations = 1000) {
103 size_t nCorners = segment.vertices.size();
104 if (nCorners == 0)
106 double const barycentricTolerance = 1e-14;
107
108 Dune::DynamicMatrix<double> A(nCorners, nCorners);
109 populateMatrix(segment, A);
110
111 Dune::DynamicVector<double> l(nCorners);
112 for (size_t i = 0; i < nCorners; i++)
113 l[i] = target * segment.vertices[i];
114
115 // choose a feasible initial solution
116 Dune::DynamicVector<double> sol(nCorners);
117 for (size_t i = 0; i < nCorners; i++)
118 sol[i] = 1.0 / nCorners;
119
120 Coordinate oldCoordinates = segment.barycentricToGlobal(sol);
121 Coordinate newCoordinates;
122
123 for (size_t iterations = 0; iterations < maxIterations; ++iterations) {
124 approximate(target, A, l, segment, sol);
125
126 newCoordinates = segment.barycentricToGlobal(sol);
127 if ((oldCoordinates - newCoordinates).two_norm() < correctionTolerance)
128 break;
129
130 oldCoordinates = newCoordinates;
131 }
132 segment.sanityCheck(sol, barycentricTolerance);
133 return (target - newCoordinates).two_norm();
134}
135
136// Polyhedron-to-Polyhedron
137template <class Coordinate>
140 double valueCorrectionTolerance,
141 size_t maxIterations = 1000) {
142 size_t nCorners1 = s1.vertices.size();
143 size_t nCorners2 = s2.vertices.size();
144 if (nCorners1 == 0 or nCorners2 == 0)
146 double const barycentricTolerance = 1e-14;
147
148 // choose feasible initial solutions
149 Dune::DynamicVector<double> sol1(nCorners1);
150 for (size_t i = 0; i < s1.vertices.size(); i++)
151 sol1[i] = 1.0 / nCorners1;
152 auto c1 = s1.barycentricToGlobal(sol1);
153
154 Dune::DynamicVector<double> sol2(nCorners2);
155 for (size_t i = 0; i < nCorners2; i++)
156 sol2[i] = 1.0 / nCorners2;
157 auto c2 = s2.barycentricToGlobal(sol2);
158
159 double oldDistance = (c2 - c1).two_norm();
160
161 Dune::DynamicMatrix<double> A1(nCorners1, nCorners1);
162 populateMatrix(s1, A1);
163
164 Dune::DynamicMatrix<double> A2(nCorners2, nCorners2);
165 populateMatrix(s2, A2);
166
167 for (size_t iterations = 0; iterations < maxIterations; ++iterations) {
168 Dune::DynamicVector<double> l2(nCorners2);
169 for (size_t i = 0; i < nCorners2; i++)
170 l2[i] = c1 * s2.vertices[i];
171
172 approximate(c1, A2, l2, s2, sol2);
173 c2 = s2.barycentricToGlobal(sol2);
174
175 Dune::DynamicVector<double> l1(nCorners1);
176 for (size_t i = 0; i < nCorners1; i++)
177 l1[i] = c2 * s1.vertices[i];
178 approximate(c2, A1, l1, s1, sol1);
179 c1 = s1.barycentricToGlobal(sol1);
180
181 double const newDistance = (c2 - c1).two_norm();
182 if (oldDistance - newDistance <= valueCorrectionTolerance) {
183 s1.sanityCheck(sol1, barycentricTolerance);
184 s2.sanityCheck(sol2, barycentricTolerance);
185 return newDistance;
186 }
187
188 oldDistance = newDistance;
189 }
190 return oldDistance;
191}
192
193// Point-to-Geometry convenience method
194template <class Geometry>
195double distance(typename Geometry::GlobalCoordinate const &point,
196 Geometry const &geo, double valueCorrectionTolerance) {
197 using Coordinate = typename Geometry::GlobalCoordinate;
198
200 polyhedron.vertices.resize(geo.corners());
201 for (size_t i = 0; i < polyhedron.vertices.size(); ++i)
202 polyhedron.vertices[i] = geo.corner(i);
203
204 return distance(point, polyhedron, valueCorrectionTolerance);
205}
206
207// Polyhedron-to-Geometry convenience method
208template <class Geometry>
210 Geometry const &geo, double valueCorrectionTolerance,
211 size_t maxIterations = 1000) {
212 using Coordinate = typename Geometry::GlobalCoordinate;
213
215 p2.vertices.resize(geo.corners());
216 for (size_t i = 0; i < p2.vertices.size(); ++i)
217 p2.vertices[i] = geo.corner(i);
218
219 return distance(p2, p1, valueCorrectionTolerance, maxIterations);
220}
221
222#endif
real_type two_norm() const
double alpha() const
Y & rhs()
void approximate(Coordinate const &target, Dune::DynamicMatrix< double > const &A, Dune::DynamicVector< double > const &l, ConvexPolyhedron< Coordinate > const &segment, Dune::DynamicVector< double > &sol)
Definition polyhedrondistance.hh:43
void populateMatrix(ConvexPolyhedron< Coordinate > const &segment, Matrix &matrix)
Definition polyhedrondistance.hh:15
double distance(const Coordinate &target, const ConvexPolyhedron< Coordinate > &segment, double correctionTolerance, size_t maxIterations=1000)
Definition polyhedrondistance.hh:99
Definition convexpolyhedron.hh:10
void sanityCheck(DynamicVector const &b, double tol) const
Definition convexpolyhedron.hh:24
std::vector< Coordinate > vertices
Definition convexpolyhedron.hh:11
Coordinate barycentricToGlobal(DynamicVector const &b) const
Definition convexpolyhedron.hh:14
T infinity(T... args)
T resize(T... args)
T size(T... args)