From ce7308670920e4500ef32b73d6d6da5d62679fc7 Mon Sep 17 00:00:00 2001
From: Elias Pipping <elias.pipping@fu-berlin.de>
Date: Mon, 11 Jul 2016 23:52:03 +0200
Subject: [PATCH] Tests: Use proper obstacles for ::ProjectedBlockGSStep

---
 dune/solvers/test/gssteptest.cc | 51 +++++++++++++++++++++++++++++----
 1 file changed, 46 insertions(+), 5 deletions(-)

diff --git a/dune/solvers/test/gssteptest.cc b/dune/solvers/test/gssteptest.cc
index 763e11d0..b9cae7fb 100644
--- a/dune/solvers/test/gssteptest.cc
+++ b/dune/solvers/test/gssteptest.cc
@@ -46,7 +46,7 @@ struct GSTestSuite {
     std::vector<BoxConstraint<double, BlockSize>> obstacles(size);
     for (size_t i = 0; i < size; ++i)
       for (size_t j = 0; j < BlockSize; ++j)
-          obstacles[i][j] = { -1, +1 };
+          obstacles[i][j] = { p.u_ex[i][j] + 2.0, p.u_ex[i][j] + 3.0 };
 
     using LoopSolver = ::LoopSolver<Vector>;
     using Step = LinearIterationStep<Matrix, Vector>;
@@ -182,6 +182,8 @@ struct GSTestSuite {
     // test projected block GS
     if (trivialDirichletOnly) // TODO: missing feature in ProjectedBlockGS
     {
+      // Test 1: Without obstacles, we should get the same solution as with an
+      // unconstrained solver
       size_t size = p.u.size();
       using GSStep = ProjectedBlockGSStep<Matrix, Vector>;
       typename GSStep::HasObstacle hasObstacle(size, false);
@@ -191,11 +193,50 @@ struct GSTestSuite {
         test(&gsStep, "ProjectedBlockGS free");
       }
       hasObstacle.setAll();
+      // Test2: Different initial iterates should lead to the same solution,
+      // which should, furthermore, not intersect the obstacles
       {
-        ProjectedBlockGSStep<Matrix, Vector> gsStep;
-        gsStep.hasObstacle_ = &hasObstacle;
-        gsStep.obstacles_ = &obstacles;
-        test(&gsStep, "ProjectedBlockGS obstacle");
+        ProjectedBlockGSStep<Matrix, Vector> pGSStep1;
+        pGSStep1.hasObstacle_ = &hasObstacle;
+        pGSStep1.obstacles_ = &obstacles;
+        ProjectedBlockGSStep<Matrix, Vector> pGSStep2;
+        pGSStep2.hasObstacle_ = &hasObstacle;
+        pGSStep2.obstacles_ = &obstacles;
+
+        Vector u_copy1 = p.u;
+        for (size_t i = 0; i < p.u.size(); ++i)
+          for (size_t j = 0; j < blocksize; ++j)
+            if (p.ignore[i][j])
+              u_copy1[i][j] += 2.25;
+        Vector u_copy2 = p.u;
+        for (size_t i = 0; i < p.u.size(); ++i)
+          for (size_t j = 0; j < blocksize; ++j)
+            if (p.ignore[i][j])
+              u_copy2[i][j] += 2.75;
+
+        auto result1 = solve(&pGSStep1, u_copy1, 1e-12, 2000);
+        auto result2 = solve(&pGSStep2, u_copy2, 1e-12, 2000);
+
+        for (size_t i = 0; i < p.u.size(); ++i)
+          for (size_t j = 0; j < blocksize; ++j)
+            if (std::abs(result1[i][j] -
+                         obstacles[i][j].projectIn(result1[i][j])) > 1e-12 or
+                std::abs(result2[i][j] -
+                         obstacles[i][j].projectIn(result2[i][j])) > 1e-12) {
+              std::cerr << "### error: obstacles not respected!" << std::endl;
+              passed = false;
+              break;
+            }
+        auto normDiff = p.energyNorm.diff(result1, result2);
+        // We cannot expect too much here (hence the low tolerance):
+        // We are solving a potentially large system using nothing but
+        // a smoother. Convergence will be very slow.
+        if (normDiff > 1e-6) {
+          std::cerr << "### error: Different initial iterates lead to "
+                       "different solutions! (diff = "
+                    << normDiff << ")" << std::endl;
+          passed = false;
+        }
       }
     }
 
-- 
GitLab