From e6ae090e0bf5c4374a1d35669a37c0c767ca4a31 Mon Sep 17 00:00:00 2001
From: Scott Wittenburg <scott.wittenburg@kitware.com>
Date: Tue, 11 Feb 2020 10:48:57 -0700
Subject: [PATCH] Move vtkMergeArrays into VTK proper, to be used from within
 other filters.

Also separate out the parallel functionality and move it into a subclass,
vtkPMergeArrays.
---
 Filters/General/CMakeLists.txt       |   1 +
 Filters/General/vtkMergeArrays.cxx   | 191 +++++++++++++++++++++++++++
 Filters/General/vtkMergeArrays.h     |  89 +++++++++++++
 Filters/Parallel/CMakeLists.txt      |   1 +
 Filters/Parallel/vtkPMergeArrays.cxx |  65 +++++++++
 Filters/Parallel/vtkPMergeArrays.h   |  51 +++++++
 6 files changed, 398 insertions(+)
 create mode 100644 Filters/General/vtkMergeArrays.cxx
 create mode 100644 Filters/General/vtkMergeArrays.h
 create mode 100644 Filters/Parallel/vtkPMergeArrays.cxx
 create mode 100644 Filters/Parallel/vtkPMergeArrays.h

diff --git a/Filters/General/CMakeLists.txt b/Filters/General/CMakeLists.txt
index 11d19119e0a..e20d462b779 100644
--- a/Filters/General/CMakeLists.txt
+++ b/Filters/General/CMakeLists.txt
@@ -59,6 +59,7 @@ set(classes
   vtkLoopBooleanPolyDataFilter
   vtkMarchingContourFilter
   vtkMatricizeArray
+  vtkMergeArrays
   vtkMergeCells
   vtkMultiBlockDataGroupFilter
   vtkMultiBlockFromTimeSeriesFilter
diff --git a/Filters/General/vtkMergeArrays.cxx b/Filters/General/vtkMergeArrays.cxx
new file mode 100644
index 00000000000..c6e6abe748e
--- /dev/null
+++ b/Filters/General/vtkMergeArrays.cxx
@@ -0,0 +1,191 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    vtkMergeArrays.cxx
+
+  Copyright (c) Kitware, Inc.
+  All rights reserved.
+  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+#include "vtkMergeArrays.h"
+
+#include "vtkCellData.h"
+#include "vtkCompositeDataIterator.h"
+#include "vtkCompositeDataSet.h"
+#include "vtkDataArray.h"
+#include "vtkDataSet.h"
+#include "vtkFieldData.h"
+#include "vtkInformation.h"
+#include "vtkInformationVector.h"
+#include "vtkObjectFactory.h"
+#include "vtkPointData.h"
+#include "vtkSmartPointer.h"
+
+vtkStandardNewMacro(vtkMergeArrays);
+
+//----------------------------------------------------------------------------
+vtkMergeArrays::vtkMergeArrays() {}
+
+//----------------------------------------------------------------------------
+vtkMergeArrays::~vtkMergeArrays() {}
+
+//----------------------------------------------------------------------------
+bool vtkMergeArrays::GetOutputArrayName(
+  vtkFieldData* arrays, const char* arrayName, int inputIndex, std::string& outputArrayName)
+{
+  if (arrays->GetAbstractArray(arrayName) == nullptr)
+  {
+    return false;
+  }
+  outputArrayName = std::string(arrayName) + "_input_" + std::to_string(inputIndex);
+  return true;
+}
+
+//----------------------------------------------------------------------------
+void vtkMergeArrays::MergeArrays(int inputIndex, vtkFieldData* inputFD, vtkFieldData* outputFD)
+{
+  if (inputFD == nullptr || outputFD == nullptr)
+  {
+    return;
+  }
+
+  std::string outputArrayName;
+  int numArrays = inputFD->GetNumberOfArrays();
+  for (int arrayIdx = 0; arrayIdx < numArrays; ++arrayIdx)
+  {
+    vtkAbstractArray* array = inputFD->GetAbstractArray(arrayIdx);
+    if (this->GetOutputArrayName(outputFD, array->GetName(), inputIndex, outputArrayName))
+    {
+      vtkAbstractArray* newArray = array->NewInstance();
+      if (vtkDataArray* newDataArray = vtkDataArray::SafeDownCast(newArray))
+      {
+        newDataArray->ShallowCopy(vtkDataArray::SafeDownCast(array));
+      }
+      else
+      {
+        newArray->DeepCopy(array);
+      }
+      newArray->SetName(outputArrayName.c_str());
+      outputFD->AddArray(newArray);
+      newArray->FastDelete();
+    }
+    else
+    {
+      outputFD->AddArray(array);
+    }
+  }
+}
+
+//----------------------------------------------------------------------------
+int vtkMergeArrays::MergeDataObjectFields(vtkDataObject* input, int idx, vtkDataObject* output)
+{
+  int checks[vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES];
+  for (int attr = 0; attr < vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES; attr++)
+  {
+    checks[attr] = output->GetNumberOfElements(attr) == input->GetNumberOfElements(attr) ? 0 : 1;
+  }
+  int globalChecks[vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES];
+
+  for (int i = 0; i < vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES; ++i)
+  {
+    globalChecks[i] = checks[i];
+  }
+
+  for (int attr = 0; attr < vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES; attr++)
+  {
+    if (globalChecks[attr] == 0)
+    {
+      // only merge arrays when the number of elements in the input and output are the same
+      this->MergeArrays(
+        idx, input->GetAttributesAsFieldData(attr), output->GetAttributesAsFieldData(attr));
+    }
+  }
+
+  return 1;
+}
+
+//----------------------------------------------------------------------------
+int vtkMergeArrays::FillInputPortInformation(int vtkNotUsed(port), vtkInformation* info)
+{
+  info->Set(vtkAlgorithm::INPUT_IS_REPEATABLE(), 1);
+  return 1;
+}
+
+//----------------------------------------------------------------------------
+int vtkMergeArrays::RequestData(vtkInformation* vtkNotUsed(request),
+  vtkInformationVector** inputVector, vtkInformationVector* outputVector)
+{
+  int num = inputVector[0]->GetNumberOfInformationObjects();
+  if (num < 1)
+  {
+    return 0;
+  }
+  // get the output info object
+  vtkInformation* outInfo = outputVector->GetInformationObject(0);
+  vtkDataObject* output = outInfo->Get(vtkDataObject::DATA_OBJECT());
+
+  vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
+  vtkDataObject* input = inInfo->Get(vtkDataObject::DATA_OBJECT());
+
+  vtkCompositeDataSet* cOutput = vtkCompositeDataSet::SafeDownCast(output);
+  if (cOutput)
+  {
+    vtkCompositeDataSet* cInput = vtkCompositeDataSet::SafeDownCast(input);
+    cOutput->CopyStructure(cInput);
+    vtkSmartPointer<vtkCompositeDataIterator> iter;
+    iter.TakeReference(cInput->NewIterator());
+    iter->InitTraversal();
+    for (; !iter->IsDoneWithTraversal(); iter->GoToNextItem())
+    {
+      if (vtkDataSet* tmpIn = vtkDataSet::SafeDownCast(iter->GetCurrentDataObject()))
+      {
+        vtkDataSet* tmpOut = tmpIn->NewInstance();
+        tmpOut->ShallowCopy(tmpIn);
+        cOutput->SetDataSet(iter, tmpOut);
+        tmpOut->Delete();
+      }
+    }
+  }
+  else
+  {
+    output->ShallowCopy(input);
+  }
+
+  for (int idx = 1; idx < num; ++idx)
+  {
+    inInfo = inputVector[0]->GetInformationObject(idx);
+    input = inInfo->Get(vtkDataObject::DATA_OBJECT());
+    if (!this->MergeDataObjectFields(input, idx, output))
+    {
+      return 0;
+    }
+    vtkCompositeDataSet* cInput = vtkCompositeDataSet::SafeDownCast(input);
+    if (cOutput && cInput)
+    {
+      vtkSmartPointer<vtkCompositeDataIterator> iter;
+      iter.TakeReference(cInput->NewIterator());
+      iter->InitTraversal();
+      for (; !iter->IsDoneWithTraversal(); iter->GoToNextItem())
+      {
+        vtkDataObject* tmpIn = iter->GetCurrentDataObject();
+        vtkDataObject* tmpOut = cOutput->GetDataSet(iter);
+        if (!this->MergeDataObjectFields(tmpIn, idx, tmpOut))
+        {
+          return 0;
+        }
+      }
+    }
+  }
+  return 1;
+}
+
+//----------------------------------------------------------------------------
+void vtkMergeArrays::PrintSelf(ostream& os, vtkIndent indent)
+{
+  this->Superclass::PrintSelf(os, indent);
+}
diff --git a/Filters/General/vtkMergeArrays.h b/Filters/General/vtkMergeArrays.h
new file mode 100644
index 00000000000..fe972f47e41
--- /dev/null
+++ b/Filters/General/vtkMergeArrays.h
@@ -0,0 +1,89 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    vtkMergeArrays.h
+
+  Copyright (c) Kitware, Inc.
+  All rights reserved.
+  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+/**
+ * @class   vtkMergeArrays
+ * @brief   Multiple inputs with one output.
+ *
+ * vtkMergeArrays tries to put all arrays from all inputs into one output.
+ * The output data object is the same as the first data input.
+ * The filter checks for a consistent number of points and cells with
+ * respect to the first input, but does not check any more. Any inputs
+ * which do not have the correct number of points or cells are ignored
+ * for that type of data set attribute. When adding new arrays, if there
+ * is an existing array of the same name and attribute type, the new array
+ * will have the name mangled to be the original array name plus
+ * `_input_<inputid>` where `<inputid>` is the id/index of the input filter
+ * that is providing that array.
+ */
+
+#ifndef vtkMergeArrays_h
+#define vtkMergeArrays_h
+
+#include "vtkFiltersGeneralModule.h" // For export macro
+#include "vtkPassInputTypeAlgorithm.h"
+
+#include <string> // Needed for protected method argument
+
+class vtkDataSet;
+class vtkFieldData;
+
+class VTKFILTERSGENERAL_EXPORT vtkMergeArrays : public vtkPassInputTypeAlgorithm
+{
+public:
+  static vtkMergeArrays* New();
+
+  vtkTypeMacro(vtkMergeArrays, vtkPassInputTypeAlgorithm);
+  void PrintSelf(ostream& os, vtkIndent indent) override;
+
+protected:
+  vtkMergeArrays();
+  ~vtkMergeArrays() override;
+
+  //@{
+  /**
+   * Given an existing set of output arrays and an array name and input data set
+   * index, return an appropriate name to use for the output array. Returns true
+   * if the name is a new name and false if not.
+   */
+  virtual bool GetOutputArrayName(
+    vtkFieldData* arrays, const char* inArrayName, int inputIndex, std::string& outArrayName);
+  //@}
+
+  //@{
+  /**
+   * Add input field arrays to output, mangling output array names as needed
+   * based on inputIndex.
+   */
+  void MergeArrays(int inputIndex, vtkFieldData* inputFD, vtkFieldData* outputFD);
+
+  //@{
+  /**
+   * For a given input and index, add data arrays to the output. Returns 1 for
+   * success and 0 for failure.
+   */
+  virtual int MergeDataObjectFields(vtkDataObject* input, int inputIndex, vtkDataObject* output);
+  //@}
+
+  // see algorithm for more info
+  int FillInputPortInformation(int port, vtkInformation* info) override;
+
+  int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
+
+private:
+  vtkMergeArrays(const vtkMergeArrays&) = delete;
+  void operator=(const vtkMergeArrays&) = delete;
+};
+
+#endif
diff --git a/Filters/Parallel/CMakeLists.txt b/Filters/Parallel/CMakeLists.txt
index 4014a68b46f..613c430a154 100644
--- a/Filters/Parallel/CMakeLists.txt
+++ b/Filters/Parallel/CMakeLists.txt
@@ -21,6 +21,7 @@ set(classes
   vtkPKdTree
   vtkPLinearExtrusionFilter
   vtkPMaskPoints
+  vtkPMergeArrays
   vtkPOutlineCornerFilter
   vtkPOutlineFilter
   vtkPOutlineFilterInternals
diff --git a/Filters/Parallel/vtkPMergeArrays.cxx b/Filters/Parallel/vtkPMergeArrays.cxx
new file mode 100644
index 00000000000..c2649e1ab41
--- /dev/null
+++ b/Filters/Parallel/vtkPMergeArrays.cxx
@@ -0,0 +1,65 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    vtkPMergeArrays.cxx
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+#include "vtkPMergeArrays.h"
+#include "vtkDataObject.h"
+#include "vtkMultiProcessController.h"
+#include "vtkObjectFactory.h"
+
+vtkStandardNewMacro(vtkPMergeArrays);
+
+//----------------------------------------------------------------------------
+vtkPMergeArrays::vtkPMergeArrays() {}
+
+//----------------------------------------------------------------------------
+void vtkPMergeArrays::PrintSelf(ostream& os, vtkIndent indent)
+{
+  this->Superclass::PrintSelf(os, indent);
+}
+
+//----------------------------------------------------------------------------
+int vtkPMergeArrays::MergeDataObjectFields(vtkDataObject* input, int idx, vtkDataObject* output)
+{
+  int checks[vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES];
+  for (int attr = 0; attr < vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES; attr++)
+  {
+    checks[attr] = output->GetNumberOfElements(attr) == input->GetNumberOfElements(attr) ? 0 : 1;
+  }
+  int globalChecks[vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES];
+  auto controller = vtkMultiProcessController::GetGlobalController();
+  if (controller == nullptr)
+  {
+    for (int i = 0; i < vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES; ++i)
+    {
+      globalChecks[i] = checks[i];
+    }
+  }
+  else
+  {
+    controller->AllReduce(
+      checks, globalChecks, vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES, vtkCommunicator::MAX_OP);
+  }
+
+  for (int attr = 0; attr < vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES; attr++)
+  {
+    if (globalChecks[attr] == 0)
+    {
+      // only merge arrays when the number of elements in the input and output are the same
+      this->MergeArrays(
+        idx, input->GetAttributesAsFieldData(attr), output->GetAttributesAsFieldData(attr));
+    }
+  }
+
+  return 1;
+}
diff --git a/Filters/Parallel/vtkPMergeArrays.h b/Filters/Parallel/vtkPMergeArrays.h
new file mode 100644
index 00000000000..4614fff3f8b
--- /dev/null
+++ b/Filters/Parallel/vtkPMergeArrays.h
@@ -0,0 +1,51 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    vtkPMergeArrays.h
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+/**
+ * @class   vtkPMergeArrays
+ * @brief   Multiple inputs with one output, parallel version
+ *
+ * Like it's super class, this filter tries to combine all arrays from
+ * inputs into one output.
+ *
+ * @sa
+ * vtkMergeArrays
+ */
+
+#ifndef vtkPMergeArrays_h
+#define vtkPMergeArrays_h
+
+#include "vtkFiltersParallelModule.h" // For export macro
+#include "vtkMergeArrays.h"
+
+class VTKFILTERSPARALLEL_EXPORT vtkPMergeArrays : public vtkMergeArrays
+{
+public:
+  vtkTypeMacro(vtkPMergeArrays, vtkMergeArrays);
+  void PrintSelf(ostream& os, vtkIndent indent) override;
+
+  static vtkPMergeArrays* New();
+
+protected:
+  vtkPMergeArrays();
+  ~vtkPMergeArrays() override {}
+
+  int MergeDataObjectFields(vtkDataObject* input, int idx, vtkDataObject* output) override;
+
+private:
+  vtkPMergeArrays(const vtkPMergeArrays&) = delete;
+  void operator=(const vtkPMergeArrays&) = delete;
+};
+
+#endif
-- 
GitLab