From 118743c65fd9c947ca5d497cd74594d74cf95ae3 Mon Sep 17 00:00:00 2001 From: Elias Pipping <elias.pipping@fu-berlin.de> Date: Tue, 7 Oct 2014 00:15:43 +0200 Subject: [PATCH] [Algorit] Use heterogeneous grid (requires UG) --- dune/tectonic/closestpointprojection.hh | 114 ++++++++++++++++++++++++ src/gridselector.hh | 2 +- src/sand-wedge-data/parset.cfg | 4 +- src/sand-wedge.cc | 57 +++++++++++- 4 files changed, 171 insertions(+), 6 deletions(-) create mode 100644 dune/tectonic/closestpointprojection.hh diff --git a/dune/tectonic/closestpointprojection.hh b/dune/tectonic/closestpointprojection.hh new file mode 100644 index 00000000..75a513e9 --- /dev/null +++ b/dune/tectonic/closestpointprojection.hh @@ -0,0 +1,114 @@ +// Based on the class from dune-contact + +#ifndef CLOSEST_POINT_PROJECTION_HH +#define CLOSEST_POINT_PROJECTION_HH + +template <class Coordinate> struct BoundarySegment { + int nVertices; + std::vector<Coordinate> vertices; +}; + +template <class Coordinate> +Coordinate computeClosestPoint(const Coordinate &target, + const BoundarySegment<Coordinate> &segment, + int gaussSeidelIterations) { + /** + * The functional to be minimized is: 0.5*norm(\sum_i lambda_i corner_i - + *target)^2 + * where lambda_i are barycentric coordinates, i.e. 0\leq lambda_i \leq 1 and + *\sum_i lambda_i=1 + * + * The resulting quadratic minimization problem is given by 0.5 + *Lambda^T*A*Lambda - l^T*Lambda + * with + * A_ij = (corner_i,corner_j) and l_i = (corner_i, target) + */ + int nCorners = segment.nVertices; + double A[nCorners][nCorners]; + + for (int i = 0; i < nCorners; i++) + for (int j = 0; j <= i; j++) + A[i][j] = segment.vertices[i] * segment.vertices[j]; + + // make symmetric + for (int i = 0; i < nCorners; i++) + for (int j = i + 1; j < nCorners; j++) + A[i][j] = A[j][i]; + + std::vector<double> l(nCorners); + for (int i = 0; i < nCorners; i++) + l[i] = target * segment.vertices[i]; + + // choose a feasible initial solution + std::vector<double> sol(nCorners); + for (int i = 0; i < nCorners; i++) + sol[i] = 1.0 / nCorners; + + // use a Gauß-Seidel like method for possibly non-convex quadratic problems + // with simplex constraints. + for (int i = 0; i < gaussSeidelIterations; i++) { + + // compute the residual + std::vector<double> rhs = l; + + // compute rhs -= A*sol_ + for (int k = 0; k < nCorners; k++) + for (int j = 0; j < nCorners; j++) + rhs[k] -= A[k][j] * sol[j]; + + // use the edge vectors as search directions + double alpha = 0.0; + for (int j1 = 0; j1 < (nCorners - 1); ++j1) + for (int j2 = j1 + 1; j2 < nCorners; ++j2) { + // compute matrix entry and rhs for edge direction + double a = A[j1][j1] - A[j1][j2] - A[j2][j1] + A[j2][j2]; + double b = rhs[j1] - rhs[j2]; + + // compute minimizer for correction + if (a > 0) { + alpha = b / a; + // project alpha such that we stay positiv + if ((sol[j2] - alpha) < -1e-14) { + alpha = sol[j2]; + } else if ((alpha < -1e-14) && ((sol[j1] + alpha) < -1e-14)) { + alpha = -sol[j1]; + } + } else { + // if concave the minimum is achieved at one of the boundaries, + // i.e. at sol_[j2] or -sol_[j1] + + double sum = sol[j1] + sol[j2]; + + double lValue = 0.5 * A[j1][j1] * sum * sum - rhs[j1] * sum; + double uValue = 0.5 * A[j2][j2] * sum * sum - rhs[j2] * sum; + + alpha = (lValue < uValue) ? sol[j2] : -sol[j1]; + } + // apply correction + sol[j1] += alpha; + sol[j2] -= alpha; + + // update the local residual for corrections + for (int p = 0; p < nCorners; p++) + rhs[p] -= (A[p][j1] - A[p][j2]) * alpha; + } + } + + double eps = 1e-5; + double sum = 0; + for (size_t i = 0; i < sol.size(); i++) { + if (sol[i] < -eps) + DUNE_THROW(Dune::Exception, "No barycentric coords " << sol[1] << " nr. " + << i); + sum += sol[i]; + } + if (sum > 1 + eps) + DUNE_THROW(Dune::Exception, "No barycentric coords, sum: " << sum); + + Coordinate projected(0); + for (int i = 0; i < nCorners; i++) + projected.axpy(sol[i], segment.vertices[i]); + + return projected; +} +#endif diff --git a/src/gridselector.hh b/src/gridselector.hh index 0e27a54f..a07b0610 100644 --- a/src/gridselector.hh +++ b/src/gridselector.hh @@ -5,7 +5,7 @@ #define WANT_ALUGRID 0 #define WANT_UG 1 -#define WANT_GRID WANT_ALUGRID +#define WANT_GRID WANT_UG #if WANT_GRID == WANT_ALUGRID diff --git a/src/sand-wedge-data/parset.cfg b/src/sand-wedge-data/parset.cfg index 5d254440..ab6670d0 100644 --- a/src/sand-wedge-data/parset.cfg +++ b/src/sand-wedge-data/parset.cfg @@ -21,6 +21,7 @@ shearViscosity = 1e4 # [Pas] bulkViscosity = 1e4 # [Pas] [boundary.friction] +smallestDiameter= 1e-3 # [m] C = 10 # [Pa] mu0 = 0.7 # [1] V0 = 5e-5 # [m/s] @@ -40,9 +41,6 @@ refinementTolerance = 1e-5 number = 100000 scheme = newmark -[grid] -refinements = 4 - [u0.solver] tolerance = 1e-10 maximumIterations = 100000 diff --git a/src/sand-wedge.cc b/src/sand-wedge.cc index cf831898..799b6509 100644 --- a/src/sand-wedge.cc +++ b/src/sand-wedge.cc @@ -97,6 +97,32 @@ template <class Geometry> double diameter(Geometry const &geometry) { return diameter; } +#include <dune/tectonic/closestpointprojection.hh> + +// we assume the weakening region to be a line segment for now +template <class Geometry> double distanceToWeakeningRegion(Geometry const &g) { + TwoNorm<typename Geometry::GlobalCoordinate> twoNorm; + + BoundarySegment<typename Geometry::GlobalCoordinate> bs; + bs.nVertices = 2; + bs.vertices.resize(bs.nVertices); + bs.vertices[0] = MyGeometry::X; + bs.vertices[1] = MyGeometry::Y; + + double distance = std::numeric_limits<double>::infinity(); + auto const numCorners = g.corners(); + for (int i = 0; i < numCorners; ++i) { + auto const corner = g.corner(i); + auto const projection = computeClosestPoint(corner, bs, 10); // FIXME + distance = std::min(distance, twoNorm.diff(corner, projection)); + } + return distance; +} + +double computeAdmissibleDiameter(double distance, double smallestDiameter) { + return (distance / 0.0125 + 1.0) * smallestDiameter; +} + int main(int argc, char *argv[]) { try { Dune::ParameterTree parset; @@ -110,8 +136,35 @@ int main(int argc, char *argv[]) { GridConstructor<Grid> gridConstructor; auto grid = gridConstructor.getGrid(); - auto const refinements = parset.get<size_t>("grid.refinements"); - grid->globalRefine(refinements); + auto const smallestDiameter = + parset.get<double>("boundary.friction.smallestDiameter"); + bool needRefine = true; + + while (true) { + needRefine = false; + for (auto it = grid->template leafbegin<0>(); + it != grid->template leafend<0>(); ++it) { + auto const geometry = it->geometry(); + + auto const weakeningRegionDistance = + distanceToWeakeningRegion(geometry); + auto const admissibleDiameter = computeAdmissibleDiameter( + weakeningRegionDistance, smallestDiameter); + + if (diameter(geometry) <= admissibleDiameter) + continue; + + needRefine = true; + grid->mark(1, *it); + } + if (!needRefine) + break; + + grid->preAdapt(); + grid->adapt(); + grid->postAdapt(); + } + auto const refinements = grid->maxLevel(); double minDiameter = std::numeric_limits<double>::infinity(); double maxDiameter = 0.0; -- GitLab