From ce3e6527f2f1abdb72cf34959606e10dbb63869d Mon Sep 17 00:00:00 2001
From: Utkarsh Ayachit <utkarsh.ayachit@kitware.com>
Date: Wed, 3 Apr 2019 11:40:40 -0400
Subject: [PATCH] vtkAlgorithm: progress shift/scale

vtkAlgorithm now supports ability to specify values for shifting and
scaling progress. This enables internal vtkAlgorithm instances to report
progress for part of the work without too much work. Also allows
vtkCompositeDataPipeline to report progress was each iteration over the
composite dataset as a part of the whole rather than having the progress
be from [0, 1.0] for each block in the composite dataset.
---
 Common/ExecutionModel/vtkAlgorithm.cxx        | 44 +++++++++++++------
 Common/ExecutionModel/vtkAlgorithm.h          | 30 ++++++++++++-
 .../vtkCompositeDataPipeline.cxx              | 17 ++++++-
 IO/NetCDF/vtkNetCDFCAMReader.cxx              |  8 ++--
 Imaging/Stencil/vtkLassoStencilSource.cxx     |  6 +--
 5 files changed, 81 insertions(+), 24 deletions(-)

diff --git a/Common/ExecutionModel/vtkAlgorithm.cxx b/Common/ExecutionModel/vtkAlgorithm.cxx
index 577fa317ebd..e7b4f957c9d 100644
--- a/Common/ExecutionModel/vtkAlgorithm.cxx
+++ b/Common/ExecutionModel/vtkAlgorithm.cxx
@@ -19,6 +19,7 @@
 #include "vtkCollection.h"
 #include "vtkCollectionIterator.h"
 #include "vtkCommand.h"
+#include "vtkCompositeDataPipeline.h"
 #include "vtkDataArray.h"
 #include "vtkDataObject.h"
 #include "vtkDataSet.h"
@@ -27,25 +28,26 @@
 #include "vtkGarbageCollector.h"
 #include "vtkGraph.h"
 #include "vtkHyperTreeGrid.h"
-#include "vtkInformation.h"
 #include "vtkInformationExecutivePortKey.h"
 #include "vtkInformationExecutivePortVectorKey.h"
+#include "vtkInformation.h"
 #include "vtkInformationInformationVectorKey.h"
 #include "vtkInformationIntegerKey.h"
 #include "vtkInformationStringKey.h"
 #include "vtkInformationStringVectorKey.h"
 #include "vtkInformationVector.h"
+#include "vtkMath.h"
+#include "vtkNew.h"
 #include "vtkObjectFactory.h"
 #include "vtkPointData.h"
 #include "vtkProgressObserver.h"
 #include "vtkSmartPointer.h"
-#include "vtkCompositeDataPipeline.h"
 #include "vtkTable.h"
 #include "vtkTrivialProducer.h"
-#include "vtkNew.h"
 
 #include <set>
 #include <vector>
+#include <vtksys/SystemTools.hxx>
 
 vtkStandardNewMacro(vtkAlgorithm);
 
@@ -98,6 +100,8 @@ vtkAlgorithm::vtkAlgorithm()
   this->Information = vtkInformation::New();
   this->Information->Register(this);
   this->Information->Delete();
+  this->ProgressShift = 0.0;
+  this->ProgressScale = 1.0;
 }
 
 //----------------------------------------------------------------------------
@@ -141,12 +145,25 @@ void vtkAlgorithm::SetProgressObserver(vtkProgressObserver* po)
   }
 }
 
+//----------------------------------------------------------------------------
+void vtkAlgorithm::SetProgressShiftScale(double shift, double scale)
+{
+  this->ProgressShift = shift;
+  this->ProgressScale = scale;
+}
+
 //----------------------------------------------------------------------------
 // Update the progress of the process object. If a ProgressMethod exists,
 // executes it. Then set the Progress ivar to amount. The parameter amount
 // should range between (0,1).
 void vtkAlgorithm::UpdateProgress(double amount)
 {
+  amount = this->GetProgressShift() + this->GetProgressScale() * amount;
+
+  // clamp to [0, 1].
+  amount = vtkMath::Min(amount, 1.0);
+  amount = vtkMath::Max(amount, 0.0);
+
   if (this->ProgressObserver)
   {
     this->ProgressObserver->UpdateProgress(amount);
@@ -158,7 +175,6 @@ void vtkAlgorithm::UpdateProgress(double amount)
   }
 }
 
-
 //----------------------------------------------------------------------------
 vtkInformation *vtkAlgorithm
 ::GetInputArrayFieldInformation(int idx, vtkInformationVector **inputVector)
@@ -1732,16 +1748,7 @@ void vtkAlgorithm::SetProgressText(const char* ptext)
     return;
   }
   delete[] this->ProgressText;
-  this->ProgressText = nullptr;
-
-  if (ptext)
-  {
-    size_t n = strlen(ptext) + 1;
-    char *cp1 =  new char[n];
-    const char *cp2 = ptext;
-    this->ProgressText = cp1;
-    do { *cp1++ = *cp2++; } while ( --n );
-  }
+  this->ProgressText = vtksys::SystemTools::DuplicateString(ptext);
 }
 
 // This is here to shut off warnings about deprecated functions
@@ -1877,3 +1884,12 @@ void vtkAlgorithm::AddInputDataObject(int port, vtkDataObject *input)
     tp->Delete();
   }
 }
+
+//----------------------------------------------------------------------------
+#if !defined(VTK_LEGACY_REMOVE)
+void vtkAlgorithm::SetProgress(double val)
+{
+  VTK_LEGACY_REPLACED_BODY(vtkAlgorithm::SetProgress, "VTK 8.3", vtkAlgorithm::UpdateProgress);
+  this->UpdateProgress(val);
+}
+#endif
diff --git a/Common/ExecutionModel/vtkAlgorithm.h b/Common/ExecutionModel/vtkAlgorithm.h
index 59c975f663e..e58bebde84f 100644
--- a/Common/ExecutionModel/vtkAlgorithm.h
+++ b/Common/ExecutionModel/vtkAlgorithm.h
@@ -213,12 +213,17 @@ public:
 
   //@{
   /**
-   * Set/Get the execution progress of a process object.
+   * Get the execution progress of a process object.
    */
-  vtkSetClampMacro(Progress,double,0.0,1.0);
   vtkGetMacro(Progress,double);
   //@}
 
+  /**
+   * `SetProgress` is deprecated. Subclasses should use `UpdateProgress` to
+   * report progress updates.
+   */
+  VTK_LEGACY(void SetProgress(double));
+
   /**
    * Update the progress of the process object. If a ProgressMethod exists,
    * executes it.  Then set the Progress ivar to amount. The parameter amount
@@ -226,6 +231,24 @@ public:
    */
   void UpdateProgress(double amount);
 
+  //@{
+  /**
+   * Specify the shift and scale values to use to apply to the progress amount
+   * when `UpdateProgress` is called. By default shift is set to 0, and scale is
+   * set to 1.0. This is useful when the vtkAlgorithm instance is used as an
+   * internal algorithm to solve only a part of a whole problem.
+   *
+   * If calling on a internal vtkAlgorithm, make sure you take into
+   * consideration that values set of the outer vtkAlgorithm as well since the
+   * outer vtkAlgorithm itself may be nested in another algorithm.
+   *
+   * @note SetProgressShiftScale does not modify the MTime of the algorithm.
+   */
+  void SetProgressShiftScale(double shift, double scale);
+  vtkGetMacro(ProgressShift, double);
+  vtkGetMacro(ProgressScale, double);
+  //@}
+
   //@{
   /**
    * Set the current text message associated with the progress state.
@@ -937,6 +960,9 @@ private:
 private:
   vtkAlgorithm(const vtkAlgorithm&) = delete;
   void operator=(const vtkAlgorithm&) = delete;
+
+  double ProgressShift;
+  double ProgressScale;
 };
 
 #endif
diff --git a/Common/ExecutionModel/vtkCompositeDataPipeline.cxx b/Common/ExecutionModel/vtkCompositeDataPipeline.cxx
index 07efe655e77..cb257ae8266 100644
--- a/Common/ExecutionModel/vtkCompositeDataPipeline.cxx
+++ b/Common/ExecutionModel/vtkCompositeDataPipeline.cxx
@@ -281,13 +281,26 @@ void vtkCompositeDataPipeline::ExecuteEach(vtkCompositeDataIterator* iter,
                                            vtkInformation* request,
                                            std::vector<vtkSmartPointer<vtkCompositeDataSet>>& compositeOutputs)
 {
-  vtkInformation* inInfo  =inInfoVec[compositePort]->GetInformationObject(connection);
+  vtkInformation* inInfo = inInfoVec[compositePort]->GetInformationObject(connection);
 
+  vtkIdType num_blocks = 0;
+  // a quick iteration to get the total number of blocks to iterate over which
+  // is necessary to scale progress events.
   for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem())
+  {
+    ++num_blocks;
+  }
+
+  const double progress_scale = 1.0 / num_blocks;
+  vtkIdType block_index = 0;
+
+  auto algo = this->GetAlgorithm();
+  for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem(), ++block_index)
   {
     vtkDataObject* dobj = iter->GetCurrentDataObject();
     if (dobj)
     {
+      algo->SetProgressShiftScale(progress_scale * block_index, progress_scale);
       // Note that since VisitOnlyLeaves is ON on the iterator,
       // this method is called only for leaves, hence, we are assured that
       // neither dobj nor outObj are vtkCompositeDataSet subclasses.
@@ -309,6 +322,8 @@ void vtkCompositeDataPipeline::ExecuteEach(vtkCompositeDataIterator* iter,
       }
     }
   }
+
+  algo->SetProgressShiftScale(0.0, 1.0);
 }
 
 //----------------------------------------------------------------------------
diff --git a/IO/NetCDF/vtkNetCDFCAMReader.cxx b/IO/NetCDF/vtkNetCDFCAMReader.cxx
index 784bdd9300a..a4175a40d86 100644
--- a/IO/NetCDF/vtkNetCDFCAMReader.cxx
+++ b/IO/NetCDF/vtkNetCDFCAMReader.cxx
@@ -581,7 +581,7 @@ int vtkNetCDFCAMReader::RequestData(
     outInfo->Get(vtkDataObject::DATA_OBJECT()));
 
   vtkDebugMacro(<<"Reading NetCDF CAM file.");
-  this->SetProgress(0);
+  this->UpdateProgress(0);
   if(this->CurrentConnectivityFileName != nullptr &&
      strcmp(this->CurrentConnectivityFileName, this->ConnectivityFileName) != 0)
   {
@@ -715,7 +715,7 @@ int vtkNetCDFCAMReader::RequestData(
       points->SetPoint(static_cast<vtkIdType>(i), array[i], array[i+numFilePoints], numLevels - 1);
     }
   }
-  this->SetProgress(.25);  // educated guess for progress
+  this->UpdateProgress(.25);  // educated guess for progress
 
   // now read in the cell connectivity.  note that this is a periodic
   // domain and only the points on the left boundary are included in
@@ -896,7 +896,7 @@ int vtkNetCDFCAMReader::RequestData(
   points->Modified();
   points->Squeeze();
 
-  this->SetProgress(.5);  // educated guess for progress
+  this->UpdateProgress(.5);  // educated guess for progress
 
   // Collect the time step requested
   vtkInformationDoubleKey* timeKey =
@@ -1124,7 +1124,7 @@ int vtkNetCDFCAMReader::RequestData(
     output->GetPointData()->AddArray(levelPointData);
   }
 
-  this->SetProgress(.75);  // educated guess for progress
+  this->UpdateProgress(.75);  // educated guess for progress
 
   // now we actually create the cells
   if(this->VerticalDimension == VERTICAL_DIMENSION_SINGLE_LAYER ||
diff --git a/Imaging/Stencil/vtkLassoStencilSource.cxx b/Imaging/Stencil/vtkLassoStencilSource.cxx
index 349268fd3ae..756c0269a8a 100644
--- a/Imaging/Stencil/vtkLassoStencilSource.cxx
+++ b/Imaging/Stencil/vtkLassoStencilSource.cxx
@@ -527,7 +527,7 @@ int vtkLassoStencilSource::RequestData(
 
   while (iter != maxiter && result != 0)
   {
-    this->SetProgress((slabExtent[2*zj] - zmin)*1.0/(zmax - zmin + 1));
+    this->UpdateProgress((slabExtent[2*zj] - zmin)*1.0/(zmax - zmin + 1));
 
     int i = iter->first;
     vtkPoints *points = iter->second;
@@ -558,7 +558,7 @@ int vtkLassoStencilSource::RequestData(
     ++iter;
   }
 
-  this->SetProgress((slabExtent[2*zj] - zmin)*1.0/(zmax - zmin + 1));
+  this->UpdateProgress((slabExtent[2*zj] - zmin)*1.0/(zmax - zmin + 1));
 
   // fill in the rest
   if (result && slabExtent[2*zj] <= zmax)
@@ -569,7 +569,7 @@ int vtkLassoStencilSource::RequestData(
       this->Points, data, &raster, slabExtent, origin, spacing,
       this->Shape, xj, yj, this->SplineX, this->SplineY);
 
-    this->SetProgress(1.0);
+    this->UpdateProgress(1.0);
   }
 
   return result;
-- 
GitLab