From d0a93a43e5470c7043d16897ae5ed16505e3ddf6 Mon Sep 17 00:00:00 2001
From: Tammo Jan Dijkema <dijkema@astron.nl>
Date: Tue, 3 Apr 2018 10:58:19 +0000
Subject: [PATCH] Task #11536: add stalling detection to DPPP_DDECal

---
 .../include/DPPP_DDECal/MultiDirSolver.h      | 10 +++-
 CEP/DP3/DPPP_DDECal/src/DDECal.cc             |  1 +
 CEP/DP3/DPPP_DDECal/src/MultiDirSolver.cc     | 50 +++++++++++++++----
 3 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/CEP/DP3/DPPP_DDECal/include/DPPP_DDECal/MultiDirSolver.h b/CEP/DP3/DPPP_DDECal/include/DPPP_DDECal/MultiDirSolver.h
index a18de7c186e..aa217c3fda5 100644
--- a/CEP/DP3/DPPP_DDECal/include/DPPP_DDECal/MultiDirSolver.h
+++ b/CEP/DP3/DPPP_DDECal/include/DPPP_DDECal/MultiDirSolver.h
@@ -86,6 +86,8 @@ public:
     _constraintAccuracy = constraintAccuracy;
   }
   void set_step_size(double stepSize) { _stepSize = stepSize; }
+
+  void set_detect_stalling(bool detectStalling) { _detectStalling = detectStalling; }
   
   void add_constraint(Constraint* constraint) { _constraints.push_back(constraint); }
   
@@ -110,18 +112,21 @@ private:
 
   void makeStep(const std::vector<std::vector<DComplex> >& solutions,
     std::vector<std::vector<DComplex> >& nextSolutions) const;
+
+  bool detectStall(size_t iteration, const std::vector<double>& step_magnitudes) const;
                 
   void makeSolutionsFinite(std::vector<std::vector<DComplex> >& solutions, size_t perPol) const;
                 
   /**
    * Assign the solutions in nextSolutions to the solutions.
-   * @returns whether the solutions have been converged.
+   * @returns whether the solutions have converged. Appends the current step magnitude to step_magnitudes
    */
   bool assignSolutions(
     std::vector<std::vector<DComplex> >& solutions,
     std::vector<std::vector<DComplex> >& nextSolutions,
     bool useConstraintAccuracy,
-    double& sum, double& normSum
+    double& sum, double& normSum,
+    std::vector<double>& step_magnitudes
   ) const;
                              
   size_t _nAntennas, _nDirections, _nChannels, _nChannelBlocks;
@@ -131,6 +136,7 @@ private:
   size_t _maxIterations;
   double _accuracy, _constraintAccuracy;
   double _stepSize;
+  bool _detectStalling;
   bool _phaseOnly;
   std::vector<Constraint*> _constraints;
 
diff --git a/CEP/DP3/DPPP_DDECal/src/DDECal.cc b/CEP/DP3/DPPP_DDECal/src/DDECal.cc
index 522049c290d..eae0aa3352b 100644
--- a/CEP/DP3/DPPP_DDECal/src/DDECal.cc
+++ b/CEP/DP3/DPPP_DDECal/src/DDECal.cc
@@ -111,6 +111,7 @@ namespace LOFAR {
       itsMultiDirSolver.set_accuracy(tolerance);
       itsMultiDirSolver.set_constraint_accuracy(parset.getDouble(prefix + "approxtolerance", tolerance*10.0));
       itsMultiDirSolver.set_step_size(parset.getDouble(prefix + "stepsize", 0.2));
+      itsMultiDirSolver.set_detect_stalling(parset.getBool(prefix + "detectstalling", true));
 
       if(!itsStatFilename.empty())
 	itsStatStream.reset(new std::ofstream(itsStatFilename));
diff --git a/CEP/DP3/DPPP_DDECal/src/MultiDirSolver.cc b/CEP/DP3/DPPP_DDECal/src/MultiDirSolver.cc
index 367432b02bb..2e432c30fa3 100644
--- a/CEP/DP3/DPPP_DDECal/src/MultiDirSolver.cc
+++ b/CEP/DP3/DPPP_DDECal/src/MultiDirSolver.cc
@@ -87,7 +87,7 @@ void MultiDirSolver::makeSolutionsFinite(std::vector<std::vector<DComplex> >& so
 
 bool MultiDirSolver::assignSolutions(std::vector<std::vector<DComplex> >& solutions,
   std::vector<std::vector<DComplex> >& nextSolutions, bool useConstraintAccuracy,
-  double& sum, double& normSum) const
+  double& sum, double& normSum, std::vector<double>& step_magnitudes) const
 {
   sum = 0.0;
   normSum = 0.0;
@@ -107,6 +107,9 @@ bool MultiDirSolver::assignSolutions(std::vector<std::vector<DComplex> >& soluti
   }
   sum /= n;
   normSum /= n;
+
+  step_magnitudes.push_back(sqrt(normSum/sum)*_stepSize);
+
   if(useConstraintAccuracy)
     return sqrt(normSum/sum)*_stepSize <= _constraintAccuracy;
   else
@@ -173,7 +176,12 @@ MultiDirSolver::SolveResult MultiDirSolver::processScalar(std::vector<Complex *>
   bool
     hasConverged = false,
     hasPreviouslyConverged = false,
-    constraintsSatisfied = false;
+    constraintsSatisfied = false,
+    hasStalled = false;
+
+  std::vector<double> step_magnitudes;
+  step_magnitudes.reserve(_maxIterations);
+
   do {
     makeSolutionsFinite(solutions, 1);
     
@@ -204,7 +212,7 @@ MultiDirSolver::SolveResult MultiDirSolver::processScalar(std::vector<Complex *>
       constrainedIterations = iteration+1;
     
     double sum, normSum;
-    hasConverged = assignSolutions(solutions, nextSolutions, !constraintsSatisfied, sum, normSum);
+    hasConverged = assignSolutions(solutions, nextSolutions, !constraintsSatisfied, sum, normSum, step_magnitudes);
     if(statStream != nullptr)
     {
       (*statStream) << iteration << '\t' << normSum*_stepSize/sum << '\t' << normSum << '\n';
@@ -212,8 +220,11 @@ MultiDirSolver::SolveResult MultiDirSolver::processScalar(std::vector<Complex *>
     iteration++;
     
     hasPreviouslyConverged = hasConverged || hasPreviouslyConverged;
-    
-  } while(iteration < _maxIterations && (!hasConverged || !constraintsSatisfied));
+
+    if (_detectStalling)
+      hasStalled = detectStall(iteration, step_magnitudes);
+
+  } while(iteration < _maxIterations && (!hasConverged || !constraintsSatisfied) && !hasStalled);
   
   if(hasConverged)
     result.iterations = iteration;
@@ -393,7 +404,14 @@ MultiDirSolver::SolveResult MultiDirSolver::processFullMatrix(std::vector<Comple
   /// Start iterating
   ///
   size_t iteration = 0, constrainedIterations = 0;
-  bool hasConverged = false, hasPreviouslyConverged = false, constraintsSatisfied = false;
+  bool hasConverged = false,
+       hasPreviouslyConverged = false,
+       constraintsSatisfied = false,
+       hasStalled = false;
+
+  std::vector<double> step_magnitudes;
+  step_magnitudes.reserve(_maxIterations);
+
   do {
     makeSolutionsFinite(solutions, 4);
     
@@ -419,7 +437,7 @@ MultiDirSolver::SolveResult MultiDirSolver::processFullMatrix(std::vector<Comple
       constrainedIterations = iteration+1;
     
     double sum, normSum;
-    hasConverged = assignSolutions(solutions, nextSolutions, !constraintsSatisfied, sum, normSum);
+    hasConverged = assignSolutions(solutions, nextSolutions, !constraintsSatisfied, sum, normSum, step_magnitudes);
     if(statStream != nullptr)
     {
       (*statStream) << iteration << '\t' << normSum*_stepSize/sum << '\t' << normSum << '\n';
@@ -427,8 +445,12 @@ MultiDirSolver::SolveResult MultiDirSolver::processFullMatrix(std::vector<Comple
     iteration++;
     
     hasPreviouslyConverged = hasConverged || hasPreviouslyConverged;
-  } while(iteration < _maxIterations && (!hasConverged || !constraintsSatisfied));
-  
+
+    if (_detectStalling)
+      hasStalled = detectStall(iteration, step_magnitudes);
+
+  } while(iteration < _maxIterations && (!hasConverged || !constraintsSatisfied) && !hasStalled);
+ 
   if(hasConverged)
     result.iterations = iteration;
   else
@@ -437,6 +459,16 @@ MultiDirSolver::SolveResult MultiDirSolver::processFullMatrix(std::vector<Comple
   return result;
 }
 
+bool MultiDirSolver::detectStall(size_t iteration, const std::vector<double>& step_magnitudes) const
+{
+  if (iteration<30) {
+    return false;
+  } else {
+    return std::abs(step_magnitudes[iteration-1]/step_magnitudes[iteration-2]-1) < 1.e-4 &&
+           std::abs(step_magnitudes[iteration-2]/step_magnitudes[iteration-3]-1) < 1.e-4;
+  }
+}
+
 void MultiDirSolver::performFullMatrixIteration(size_t channelBlockIndex,
                              std::vector<Matrix>& gTimesCs,
                              std::vector<Matrix>& vs,
-- 
GitLab