diff --git a/Common/DataModel/Testing/Cxx/TestPolyhedronDecompose.cxx b/Common/DataModel/Testing/Cxx/TestPolyhedronDecompose.cxx
index d25132e4598291670d47a1b7250faa01726cc5f2..1e61082d0f649727cdf26b9968743f5ede1fdf77 100644
--- a/Common/DataModel/Testing/Cxx/TestPolyhedronDecompose.cxx
+++ b/Common/DataModel/Testing/Cxx/TestPolyhedronDecompose.cxx
@@ -5,10 +5,12 @@
 #include <vtkActor.h>
 #include <vtkBitArray.h>
 #include <vtkCamera.h>
+#include <vtkCellArray.h>
 #include <vtkCellData.h>
 #include <vtkContourFilter.h>
 #include <vtkDoubleArray.h>
 #include <vtkGeometryFilter.h>
+#include <vtkIdTypeArray.h>
 #include <vtkNew.h>
 #include <vtkPointData.h>
 #include <vtkPoints.h>
@@ -318,10 +320,16 @@ vtkSmartPointer<vtkPolyhedron> MakePolyhedron1()
   polyhedron->GetPoints()->InsertNextPoint(6.25, -3.75, 6.25);
 
   // Faces
-  vtkIdType faces[31] = { 6, 4, 0, 1, 3, 2, 4, 0, 4, 5, 1, 4, 0, 2, 6, 4, 4, 1, 5, 7, 3, 4, 3, 7, 6,
-    2, 4, 4, 6, 7, 5 };
-
-  polyhedron->SetFaces(faces);
+  vtkIdType face_offsets[7] = { 0, 4, 8, 12, 16, 20, 24 };
+  vtkIdType face_conns[24] = { 0, 1, 3, 2, 0, 4, 5, 1, 0, 2, 6, 4, 1, 5, 7, 3, 3, 7, 6, 2, 4, 6, 7,
+    5 };
+  vtkNew<vtkCellArray> faces;
+  vtkNew<vtkIdTypeArray> offsets_arr;
+  vtkNew<vtkIdTypeArray> conns_arr;
+  offsets_arr->SetArray(face_offsets, 7, 1);
+  conns_arr->SetArray(face_conns, 24, 1);
+  faces->SetData(offsets_arr, conns_arr);
+  polyhedron->SetCellFaces(faces);
   polyhedron->Initialize();
 
   return polyhedron;
@@ -349,10 +357,16 @@ vtkSmartPointer<vtkPolyhedron> MakePolyhedron2()
   polyhedron->GetPoints()->InsertNextPoint(6.25, -13.75, 6.25);
 
   // Faces
-  vtkIdType faces[31] = { 6, 4, 10, 11, 9, 8, 4, 9, 13, 12, 8, 4, 12, 14, 10, 8, 4, 11, 15, 13, 9,
-    4, 10, 14, 15, 11, 4, 13, 15, 14, 12 };
-
-  polyhedron->SetFaces(faces);
+  vtkIdType face_offsets[7] = { 0, 4, 8, 12, 16, 20, 24 };
+  vtkIdType face_conns[24] = { 10, 11, 9, 8, 9, 13, 12, 8, 12, 14, 10, 8, 11, 15, 13, 9, 10, 14, 15,
+    11, 13, 15, 14, 12 };
+  vtkNew<vtkCellArray> faces;
+  vtkNew<vtkIdTypeArray> offsets_arr;
+  vtkNew<vtkIdTypeArray> conns_arr;
+  offsets_arr->SetArray(face_offsets, 7, 1);
+  conns_arr->SetArray(face_conns, 24, 1);
+  faces->SetData(offsets_arr, conns_arr);
+  polyhedron->SetCellFaces(faces);
   polyhedron->Initialize();
 
   return polyhedron;
diff --git a/Common/DataModel/Testing/Cxx/TestPolyhedronTriangulateFaces.cxx b/Common/DataModel/Testing/Cxx/TestPolyhedronTriangulateFaces.cxx
index 0ca5273fab7d00d9dc90d36858614cea161394df..a79bf48b2b9e7d27ef791b16f05f32c9e3f0a5b1 100644
--- a/Common/DataModel/Testing/Cxx/TestPolyhedronTriangulateFaces.cxx
+++ b/Common/DataModel/Testing/Cxx/TestPolyhedronTriangulateFaces.cxx
@@ -1,6 +1,8 @@
 // SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
 // SPDX-License-Identifier: BSD-3-Clause
+#include <vtkCellArray.h>
 #include <vtkExtractEdges.h>
+#include <vtkIdTypeArray.h>
 #include <vtkNew.h>
 #include <vtkPolyhedron.h>
 #include <vtkSmartPointer.h>
@@ -38,13 +40,28 @@ vtkSmartPointer<vtkPolyhedron> MakeDodecahedron()
   aDodecahedron->GetPoints()->InsertNextPoint(-0.375185, -1.1547, -1.58931);
   aDodecahedron->GetPoints()->InsertNextPoint(0.982247, -0.713644, -1.58931);
 
-  vtkIdType faces[73] = { 12, // number of faces
-    5, 0, 1, 2, 3, 4,         // number of ids on face, ids
-    5, 0, 5, 10, 6, 1, 5, 1, 6, 11, 7, 2, 5, 2, 7, 12, 8, 3, 5, 3, 8, 13, 9, 4, 5, 4, 9, 14, 5, 0,
-    5, 15, 10, 5, 14, 19, 5, 16, 11, 6, 10, 15, 5, 17, 12, 7, 11, 16, 5, 18, 13, 8, 12, 17, 5, 19,
-    14, 9, 13, 18, 5, 19, 18, 17, 16, 15 };
-
-  aDodecahedron->SetFaces(faces);
+  vtkIdType face_offsets[13] = { 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60 };
+  vtkIdType face_conns[60] = {
+    0, 1, 2, 3, 4,     // ids
+    0, 5, 10, 6, 1,    //
+    1, 6, 11, 7, 2,    //
+    2, 7, 12, 8, 3,    //
+    3, 8, 13, 9, 4,    //
+    4, 9, 14, 5, 0,    //
+    15, 10, 5, 14, 19, //
+    16, 11, 6, 10, 15, //
+    17, 12, 7, 11, 16, //
+    18, 13, 8, 12, 17, //
+    19, 14, 9, 13, 18, //
+    19, 18, 17, 16, 15 //
+  };
+  vtkNew<vtkCellArray> faces;
+  vtkNew<vtkIdTypeArray> offsets_arr;
+  vtkNew<vtkIdTypeArray> conns_arr;
+  offsets_arr->SetArray(face_offsets, 13, 1);
+  conns_arr->SetArray(face_conns, 60, 1);
+  faces->SetData(offsets_arr, conns_arr);
+  aDodecahedron->SetCellFaces(faces);
   aDodecahedron->Initialize();
 
   return aDodecahedron;
@@ -72,16 +89,23 @@ vtkSmartPointer<vtkPolyhedron> MakeConcavePolyhedron()
   aPolyhedron->GetPoints()->InsertNextPoint(0.0, 2.0, 2.0);
   aPolyhedron->GetPoints()->InsertNextPoint(1.0, 1.0, 2.0);
 
-  vtkIdType faces[73] = { 8, 5, 0, 1, 2, 3, 4, // poly
-    5, 5, 6, 7, 8, 9,                          // poly
-    4, 0, 4, 9, 5,                             // quad
-    4, 4, 3, 8, 9,                             // quad
-    4, 3, 2, 7, 8,                             // quad
-    4, 5, 6, 1, 0,                             // quad
-    3, 6, 7, 1,                                // tri
-    3, 7, 2, 1 };                              // tri
-
-  aPolyhedron->SetFaces(faces);
+  vtkIdType face_offsets[9] = { 0, 5, 10, 14, 18, 22, 26, 29, 32 };
+  vtkIdType face_conns[32] = { 0, 1, 2, 3, 4, // poly
+    5, 6, 7, 8, 9,                            // poly
+    0, 4, 9, 5,                               // quad
+    4, 3, 8, 9,                               // quad
+    3, 2, 7, 8,                               // quad
+    5, 6, 1, 0,                               // quad
+    6, 7, 1,                                  // tri
+    7, 2, 1 };                                // tri
+
+  vtkNew<vtkCellArray> faces;
+  vtkNew<vtkIdTypeArray> offsets_arr;
+  vtkNew<vtkIdTypeArray> conns_arr;
+  offsets_arr->SetArray(face_offsets, 9, 1);
+  conns_arr->SetArray(face_conns, 32, 1);
+  faces->SetData(offsets_arr, conns_arr);
+  aPolyhedron->SetCellFaces(faces);
   aPolyhedron->Initialize();
 
   return aPolyhedron;
@@ -109,15 +133,22 @@ vtkSmartPointer<vtkPolyhedron> MakeConcaveNonPlanarPolyhedron()
   aPolyhedron->GetPoints()->InsertNextPoint(0.0, 2.0, 2.0);
   aPolyhedron->GetPoints()->InsertNextPoint(1.0, 1.0, 2.0);
 
-  vtkIdType faces[73] = { 7, 5, 0, 1, 2, 3, 4, // planar poly
-    5, 5, 6, 7, 8, 9,                          // planar poly
-    6, 0, 4, 3, 8, 9, 5,                       // non-planar poly
-    4, 3, 2, 7, 8,                             // quad
-    4, 5, 6, 1, 0,                             // quad
-    3, 6, 7, 1,                                // tri
-    3, 7, 2, 1 };                              // tri
-
-  aPolyhedron->SetFaces(faces);
+  vtkIdType face_offsets[8] = { 0, 5, 10, 16, 20, 24, 27, 30 };
+  vtkIdType face_conns[30] = { 0, 1, 2, 3, 4, // planar poly
+    5, 6, 7, 8, 9,                            // planar poly
+    0, 4, 3, 8, 9, 5,                         // non-planar poly
+    3, 2, 7, 8,                               // quad
+    5, 6, 1, 0,                               // quad
+    6, 7, 1,                                  // tri
+    7, 2, 1 };                                // tri
+
+  vtkNew<vtkCellArray> faces;
+  vtkNew<vtkIdTypeArray> offsets_arr;
+  vtkNew<vtkIdTypeArray> conns_arr;
+  offsets_arr->SetArray(face_offsets, 8, 1);
+  conns_arr->SetArray(face_conns, 30, 1);
+  faces->SetData(offsets_arr, conns_arr);
+  aPolyhedron->SetCellFaces(faces);
   aPolyhedron->Initialize();
 
   return aPolyhedron;
@@ -126,9 +157,9 @@ vtkSmartPointer<vtkPolyhedron> MakeConcaveNonPlanarPolyhedron()
 //------------------------------------------------------------------------------
 bool TestPolyhedron(vtkPolyhedron* poly, int expectedNbOfFaces, int expectedNbOfEdges)
 {
-  vtkNew<vtkIdList> newFaces;
+  vtkNew<vtkCellArray> newFaces;
   poly->TriangulateFaces(newFaces);
-  poly->SetFaces(newFaces->GetPointer(0));
+  poly->SetCellFaces(newFaces);
   poly->Initialize();
 
   if (poly->GetNumberOfFaces() != expectedNbOfFaces)
diff --git a/Common/DataModel/Testing/Cxx/UnitTestCells.cxx b/Common/DataModel/Testing/Cxx/UnitTestCells.cxx
index 1b28209f51d7da44425458318f79e0fd553d17ed..3f4f247d5422301fa0902f786cdc39a21dee4503 100644
--- a/Common/DataModel/Testing/Cxx/UnitTestCells.cxx
+++ b/Common/DataModel/Testing/Cxx/UnitTestCells.cxx
@@ -44,6 +44,7 @@
 #include "vtkCubicLine.h"
 
 #include "vtkCellArray.h"
+#include "vtkIdTypeArray.h"
 #include "vtkMath.h"
 #include "vtkMathUtilities.h"
 #include "vtkPoints.h"
@@ -753,17 +754,23 @@ vtkSmartPointer<vtkPolyhedron> MakeCube()
   aCube->GetPoints()->SetPoint(6, 1.0, 1.0, 1.0);
   aCube->GetPoints()->SetPoint(7, -1.0, 1.0, 1.0);
 
-  vtkIdType faces[31] = {
-    6,             // number of faces
-    4, 0, 3, 2, 1, //
-    4, 0, 4, 7, 3, //
-    4, 4, 5, 6, 7, //
-    4, 5, 1, 2, 6, //
-    4, 0, 1, 5, 4, //
-    4, 2, 3, 7, 6  //
+  vtkIdType face_offsets[7] = { 0, 4, 8, 12, 16, 20, 24 };
+  vtkIdType face_conns[24] = {
+    0, 3, 2, 1, //
+    0, 4, 7, 3, //
+    4, 5, 6, 7, //
+    5, 1, 2, 6, //
+    0, 1, 5, 4, //
+    2, 3, 7, 6  //
   };
-
-  aCube->SetFaces(faces);
+  vtkNew<vtkCellArray> faces;
+  vtkNew<vtkIdTypeArray> offsets_arr;
+  vtkNew<vtkIdTypeArray> conns_arr;
+  offsets_arr->SetArray(face_offsets, 7, 1);
+  conns_arr->SetArray(face_conns, 24, 1);
+  faces->SetData(offsets_arr, conns_arr);
+
+  aCube->SetCellFaces(faces);
   aCube->Initialize();
 
   return aCube;
@@ -802,23 +809,29 @@ vtkSmartPointer<vtkPolyhedron> MakeDodecahedron()
   aDodecahedron->GetPoints()->InsertNextPoint(-0.375185, -1.1547, -1.58931);
   aDodecahedron->GetPoints()->InsertNextPoint(0.982247, -0.713644, -1.58931);
 
-  vtkIdType faces[73] = {
-    12,                   // number of faces
-    5, 0, 1, 2, 3, 4,     // number of ids on face, ids
-    5, 0, 5, 10, 6, 1,    //
-    5, 1, 6, 11, 7, 2,    //
-    5, 2, 7, 12, 8, 3,    //
-    5, 3, 8, 13, 9, 4,    //
-    5, 4, 9, 14, 5, 0,    //
-    5, 15, 10, 5, 14, 19, //
-    5, 16, 11, 6, 10, 15, //
-    5, 17, 12, 7, 11, 16, //
-    5, 18, 13, 8, 12, 17, //
-    5, 19, 14, 9, 13, 18, //
-    5, 19, 18, 17, 16, 15 //
+  vtkIdType face_offsets[13] = { 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60 };
+  vtkIdType face_conns[60] = {
+    0, 1, 2, 3, 4,     // ids
+    0, 5, 10, 6, 1,    //
+    1, 6, 11, 7, 2,    //
+    2, 7, 12, 8, 3,    //
+    3, 8, 13, 9, 4,    //
+    4, 9, 14, 5, 0,    //
+    15, 10, 5, 14, 19, //
+    16, 11, 6, 10, 15, //
+    17, 12, 7, 11, 16, //
+    18, 13, 8, 12, 17, //
+    19, 14, 9, 13, 18, //
+    19, 18, 17, 16, 15 //
   };
-
-  aDodecahedron->SetFaces(faces);
+  vtkNew<vtkCellArray> faces;
+  vtkNew<vtkIdTypeArray> offsets_arr;
+  vtkNew<vtkIdTypeArray> conns_arr;
+  offsets_arr->SetArray(face_offsets, 13, 1);
+  conns_arr->SetArray(face_conns, 60, 1);
+  faces->SetData(offsets_arr, conns_arr);
+
+  aDodecahedron->SetCellFaces(faces);
   aDodecahedron->Initialize();
 
   return aDodecahedron;
diff --git a/Filters/Core/vtkExtractCells.cxx b/Filters/Core/vtkExtractCells.cxx
index c1037b6cfc70ed03a01eff8c31dac5d937d84000..f191892af9870e13d84548d9582e993a5a87543f 100644
--- a/Filters/Core/vtkExtractCells.cxx
+++ b/Filters/Core/vtkExtractCells.cxx
@@ -35,8 +35,8 @@ struct ExtractedCellsT
 {
   vtkSmartPointer<vtkCellArray> Connectivity;
   vtkSmartPointer<vtkUnsignedCharArray> CellTypes;
-  vtkSmartPointer<vtkIdTypeArray> Faces;
-  vtkSmartPointer<vtkIdTypeArray> FaceLocations;
+  vtkSmartPointer<vtkCellArray> PolyFaces;
+  vtkSmartPointer<vtkCellArray> PolyFaceLocations;
 };
 
 //=============================================================================
@@ -304,65 +304,87 @@ void ExtractPolyhedralFaces(
   ExtractedCellsT& result, vtkUnstructuredGrid* input, const CellWorkT& work)
 {
   const auto numCells = work.GetNumberOfCells();
-  auto inFaceLocations = input->GetFaceLocations();
-  auto inFaces = input->GetFaces();
+  auto inFaceLocations = input->GetPolyhedronFaceLocations();
+  auto inFaces = input->GetPolyhedronFaces();
 
-  result.FaceLocations.TakeReference(vtkIdTypeArray::New());
-  result.FaceLocations->SetNumberOfTuples(numCells);
+  vtkNew<vtkIdTypeArray> connectivityPoly;
+  vtkNew<vtkIdTypeArray> offsetsPoly;
+  vtkNew<vtkIdTypeArray> connectivityPolyFaces;
+  vtkNew<vtkIdTypeArray> offsetsPolyFaces;
 
   vtkIdType outFacesSize = 0;
+  vtkIdType outFaceLocSize = 0;
+
   for (vtkIdType cc = 0; cc < numCells; ++cc)
   {
-    const auto loc = inFaceLocations->GetValue(work.GetCellId(cc));
-    if (loc == -1)
+    const auto size = inFaceLocations->GetCellSize(work.GetCellId(cc));
+    if (size != 0)
     {
-      // not a polyhedral cell
-      result.FaceLocations->SetTypedComponent(cc, 0, -1);
+      outFaceLocSize += size;
     }
-    else
+  }
+  offsetsPoly->SetNumberOfValues(numCells + 1);
+  connectivityPoly->SetNumberOfValues(outFaceLocSize);
+  offsetsPoly->SetValue(0, 0);
+  // Prepare polyhedron cells offsets
+  vtkIdType facePos = 0;
+  vtkNew<vtkIdList> faceIds;
+  for (vtkIdType cc = 0; cc < numCells; ++cc)
+  {
+    const auto size = inFaceLocations->GetCellSize(work.GetCellId(cc));
+    if (size != 0)
     {
-      result.FaceLocations->SetTypedComponent(cc, 0, outFacesSize);
-      vtkIdType* pfaces_start = inFaces->GetPointer(loc);
-      vtkIdType* pfaces = pfaces_start;
-      const auto nfaces = (*pfaces++);
+      vtkIdType nfaces;
+      const vtkIdType* faces;
+      inFaceLocations->GetCellAtId(work.GetCellId(cc), nfaces, faces, faceIds);
       for (vtkIdType face = 0; face < nfaces; ++face)
       {
-        const auto npts = (*pfaces++);
-        pfaces += npts;
+        outFacesSize += static_cast<vtkIdType>(inFaces->GetCellSize(faces[face]));
+        // Store local to global faceId for later reuse
+        connectivityPoly->SetValue(facePos, faces[face]);
+        facePos++;
       }
-      outFacesSize += static_cast<vtkIdType>(std::distance(pfaces_start, pfaces));
     }
+    offsetsPoly->SetValue(cc + 1, facePos);
+  }
+  faceIds->Initialize();
+  offsetsPolyFaces->SetNumberOfValues(outFaceLocSize + 1);
+  connectivityPolyFaces->SetNumberOfValues(outFacesSize);
+  connectivityPolyFaces->FillValue(0);
+  offsetsPolyFaces->SetValue(0, 0);
+  // Prepare offsets needed for SMPTools
+  facePos = 0;
+  for (vtkIdType face = 0; face < outFaceLocSize; ++face)
+  {
+    const auto size = inFaces->GetCellSize(connectivityPoly->GetValue(face));
+    facePos += size;
+    offsetsPolyFaces->SetValue(face + 1, facePos);
   }
-
   // Now copy polyhedron Faces.
-  result.Faces.TakeReference(vtkIdTypeArray::New());
-  result.Faces->SetNumberOfTuples(outFacesSize);
-
-  vtkSMPTools::For(0, numCells, [&](vtkIdType start, vtkIdType end) {
+  vtkSMPTools::For(0, outFaceLocSize, [&](vtkIdType start, vtkIdType end) {
+    vtkNew<vtkIdList> facePts;
     for (vtkIdType cc = start; cc < end; ++cc)
     {
-      const auto inLoc = inFaceLocations->GetValue(work.GetCellId(cc));
-      if (inLoc == -1)
-      {
-        continue;
-      }
-      const auto outLoc = result.FaceLocations->GetValue(cc);
-
-      auto iptr = inFaces->GetPointer(inLoc);
-      auto optr = result.Faces->GetPointer(outLoc);
-      const auto nfaces = *iptr++;
-      *optr++ = nfaces;
-      for (vtkIdType face = 0; face < nfaces; ++face)
-      {
-        const auto npts = (*iptr++);
-        *optr++ = npts;
-        std::transform(
-          iptr, iptr + npts, optr, [&work](vtkIdType id) { return work.GetPointId(id); });
-        optr += npts;
-        iptr += npts;
-      }
+      vtkIdType npts;
+      const vtkIdType* pts;
+      vtkIdType faceId = connectivityPoly->GetValue(cc);
+      inFaces->GetCellAtId(faceId, npts, pts, facePts);
+      const auto loc = offsetsPolyFaces->GetValue(cc);
+      auto optr = connectivityPolyFaces->GetPointer(loc);
+      std::transform(pts, pts + npts, optr, [&work](vtkIdType id) { return work.GetPointId(id); });
     }
   });
+  // Finalize the mapping to local faces
+  facePos = 0;
+  for (vtkIdType face = 0; face < outFaceLocSize; ++face)
+  {
+    connectivityPoly->SetValue(face, face);
+  }
+  // Prepare return result
+  result.PolyFaceLocations.TakeReference(vtkCellArray::New());
+  result.PolyFaceLocations->SetData(offsetsPoly, connectivityPoly);
+  result.PolyFaces.TakeReference(vtkCellArray::New());
+  result.PolyFaces->SetData(offsetsPolyFaces, connectivityPolyFaces);
 }
 
 //------------------------------------------------------------------------------
@@ -668,12 +690,13 @@ int vtkExtractCells::RequestData(vtkInformation* vtkNotUsed(request),
 
   // Handle polyhedral cells
   auto inputUG = vtkUnstructuredGrid::SafeDownCast(input);
-  if (inputUG && inputUG->GetFaces() && inputUG->GetFaceLocations() &&
-    inputUG->GetFaceLocations()->GetRange(0)[1] != -1)
+  if (inputUG && inputUG->GetPolyhedronFaces() && inputUG->GetPolyhedronFaceLocations() &&
+    inputUG->GetPolyhedronFaceLocations()->GetOffsetsArray()->GetRange(0)[1] != 0)
   {
     ::ExtractPolyhedralFaces(cells, inputUG, work);
   }
-  output->SetCells(cells.CellTypes, cells.Connectivity, cells.FaceLocations, cells.Faces);
+  output->SetPolyhedralCells(
+    cells.CellTypes, cells.Connectivity, cells.PolyFaceLocations, cells.PolyFaces);
   this->UpdateProgress(1.00);
 
   return 1;
@@ -713,7 +736,7 @@ bool vtkExtractCells::Copy(vtkDataSet* input, vtkUnstructuredGrid* output)
 
   const auto numCells = input->GetNumberOfCells();
   auto cells = ::ExtractCells(input, AllElementsWork{ 0, numCells }, this->BatchSize);
-  output->SetCells(cells.CellTypes, cells.Connectivity, nullptr, nullptr);
+  output->SetPolyhedralCells(cells.CellTypes, cells.Connectivity, nullptr, nullptr);
 
   // copy cell/point arrays.
   output->GetPointData()->ShallowCopy(input->GetPointData());
diff --git a/Filters/Core/vtkPolyDataToUnstructuredGrid.cxx b/Filters/Core/vtkPolyDataToUnstructuredGrid.cxx
index 3a7995a6a54a8d6e6aa9b223ccbfaaaba6ebe85d..2325ccfe3b26cc856666470c8b1dce48618596de 100644
--- a/Filters/Core/vtkPolyDataToUnstructuredGrid.cxx
+++ b/Filters/Core/vtkPolyDataToUnstructuredGrid.cxx
@@ -213,19 +213,19 @@ int vtkPolyDataToUnstructuredGrid::RequestData(
 
   if (hasOnlyVerts)
   {
-    output->SetCells(cellTypes, input->GetVerts(), nullptr, nullptr);
+    output->SetPolyhedralCells(cellTypes, input->GetVerts(), nullptr, nullptr);
   }
   else if (hasOnlyLines)
   {
-    output->SetCells(cellTypes, input->GetLines(), nullptr, nullptr);
+    output->SetPolyhedralCells(cellTypes, input->GetLines(), nullptr, nullptr);
   }
   else if (hasOnlyPolys)
   {
-    output->SetCells(cellTypes, input->GetPolys(), nullptr, nullptr);
+    output->SetPolyhedralCells(cellTypes, input->GetPolys(), nullptr, nullptr);
   }
   else if (hasOnlyStrips)
   {
-    output->SetCells(cellTypes, input->GetStrips(), nullptr, nullptr);
+    output->SetPolyhedralCells(cellTypes, input->GetStrips(), nullptr, nullptr);
   }
   else
   {
@@ -276,7 +276,7 @@ int vtkPolyDataToUnstructuredGrid::RequestData(
     vtkNew<vtkCellArray> cellArray;
     cellArray->SetData(offsets, connectivity);
     // set cells
-    output->SetCells(cellTypes, cellArray, nullptr, nullptr);
+    output->SetPolyhedralCells(cellTypes, cellArray, nullptr, nullptr);
   }
 
   this->UpdateProgress(0.95);
diff --git a/Filters/Core/vtkRemoveUnusedPoints.cxx b/Filters/Core/vtkRemoveUnusedPoints.cxx
index 674b800813f12dc26b9c26c84c609b080bfe22cc..cf2e1188ba98855088e8802334455171257d33cf 100644
--- a/Filters/Core/vtkRemoveUnusedPoints.cxx
+++ b/Filters/Core/vtkRemoveUnusedPoints.cxx
@@ -99,8 +99,8 @@ bool CopyConnectivity(vtkUnstructuredGrid* input, vtkUnstructuredGrid* output,
   auto inCellArray = input->GetCells();
   auto inConnectivity = inCellArray->GetConnectivityArray();
   auto inOffsets = inCellArray->GetOffsetsArray();
-  auto inFaces = input->GetFaces();
-  auto inFaceLocations = input->GetFaceLocations();
+  auto inFaces = input->GetPolyhedronFaces();
+  auto inFaceLocations = input->GetPolyhedronFaceLocations();
 
   vtkSmartPointer<vtkDataArray> outConnectivity;
   outConnectivity.TakeReference(inConnectivity->NewInstance());
@@ -115,23 +115,30 @@ bool CopyConnectivity(vtkUnstructuredGrid* input, vtkUnstructuredGrid* output,
     return false;
   }
 
-  vtkSmartPointer<vtkIdTypeArray> outFaces;
+  vtkSmartPointer<vtkCellArray> outFaces;
   if (inFaces)
   {
-    using SupportedFacesArrays = vtkTypeList::Create<vtkIdTypeArray>;
-    outFaces.TakeReference(vtkIdTypeArray::New());
-    outFaces->SetNumberOfComponents(inFaces->GetNumberOfComponents());
-    outFaces->SetNumberOfTuples(inFaces->GetNumberOfTuples());
+    auto inFacesConnectivity = inFaces->GetConnectivityArray();
+    vtkSmartPointer<vtkDataArray> outFacesConnectivity;
+    outFacesConnectivity.TakeReference(inFacesConnectivity->NewInstance());
+    outFacesConnectivity->SetNumberOfComponents(inFacesConnectivity->GetNumberOfComponents());
+    outFacesConnectivity->SetNumberOfTuples(inFacesConnectivity->GetNumberOfTuples());
+
+    using SupportedFacesArrays = vtkCellArray::StorageArrayList;
     using DispatchFaces = vtkArrayDispatch::DispatchByArray<SupportedFacesArrays>;
-    if (!DispatchFaces::Execute(inFaces, worker, outFaces, pointMap, filter))
+
+    if (!DispatchFaces::Execute(
+          inFacesConnectivity, worker, outFacesConnectivity, pointMap, filter))
     {
       return false;
     }
+    outFaces = vtkSmartPointer<vtkCellArray>::New();
+    outFaces->SetData(inFaces->GetOffsetsArray(), outFacesConnectivity);
   }
 
   vtkNew<vtkCellArray> outCellArray;
   outCellArray->SetData(inOffsets, outConnectivity);
-  output->SetCells(input->GetCellTypesArray(), outCellArray, inFaceLocations, outFaces);
+  output->SetPolyhedralCells(input->GetCellTypesArray(), outCellArray, inFaceLocations, outFaces);
   return true;
 }
 }
diff --git a/Filters/Core/vtkStaticCleanUnstructuredGrid.cxx b/Filters/Core/vtkStaticCleanUnstructuredGrid.cxx
index 6ca160919d9a2d2857a9e970bd88f00ce90bad3f..896560e28e432a11316d6045011f285b08d7302a 100644
--- a/Filters/Core/vtkStaticCleanUnstructuredGrid.cxx
+++ b/Filters/Core/vtkStaticCleanUnstructuredGrid.cxx
@@ -313,25 +313,9 @@ void UpdateCellArrayConnectivity(vtkCellArray* ca, vtkIdType* ptMap)
 }
 
 //  Update the polyhedra face connectivity array.
-void UpdatePolyhedraFaces(vtkIdTypeArray* a, vtkIdType* ptMap)
+void UpdatePolyhedraFaces(vtkCellArray* a, vtkIdType* ptMap)
 {
-  vtkIdType num = a->GetNumberOfTuples();
-  vtkIdType* c = a->GetPointer(0);
-
-  for (vtkIdType idx = 0; idx < num;)
-  {
-    vtkIdType numFaces = c[idx++];
-    vtkIdType npts;
-    for (vtkIdType faceNum = 0; faceNum < numFaces; ++faceNum)
-    {
-      npts = c[idx++];
-      for (vtkIdType i = 0; i < npts; ++i)
-      {
-        c[idx + i] = ptMap[c[idx + i]];
-      }
-      idx += npts;
-    }
-  }
+  UpdateCellArrayConnectivity(a, ptMap);
 }
 
 } // anonymous namespace
@@ -523,15 +507,15 @@ int vtkStaticCleanUnstructuredGrid::RequestData(vtkInformation* vtkNotUsed(reque
 
   // If the unstructured grid contains polyhedra, the face connectivity needs
   // to be updated as well.
-  vtkIdTypeArray* faceLocations = input->GetFaceLocations();
-  vtkIdTypeArray* faces = input->GetFaces();
+  vtkCellArray* faceLocations = input->GetPolyhedronFaceLocations();
+  vtkCellArray* faces = input->GetPolyhedronFaces();
   if (faces != nullptr)
   {
     UpdatePolyhedraFaces(faces, pmap);
   }
 
   // Finally, assemble the filter output.
-  output->SetCells(input->GetCellTypesArray(), outCells, faceLocations, faces);
+  output->SetPolyhedralCells(input->GetCellTypesArray(), outCells, faceLocations, faces);
 
   // Free unneeded memory
   this->Locator->Initialize();
diff --git a/Filters/General/Testing/Cxx/TestCellValidator.cxx b/Filters/General/Testing/Cxx/TestCellValidator.cxx
index 78e2960599840c65d5b2eaffb312c9673852ce17..44bf54c2b7b56aa7c543df858d7089959a3afab7 100644
--- a/Filters/General/Testing/Cxx/TestCellValidator.cxx
+++ b/Filters/General/Testing/Cxx/TestCellValidator.cxx
@@ -898,17 +898,22 @@ vtkSmartPointer<vtkPolyhedron> MakeCube()
   aCube->GetPoints()->SetPoint(6, 1.0, 1.0, 1.0);
   aCube->GetPoints()->SetPoint(7, -1.0, 1.0, 1.0);
 
-  vtkIdType faces[31] = {
-    6,             // number of faces
-    4, 0, 3, 2, 1, //
-    4, 0, 4, 7, 3, //
-    4, 4, 5, 6, 7, //
-    4, 5, 1, 2, 6, //
-    4, 0, 1, 5, 4, //
-    4, 2, 3, 7, 6  //
+  vtkIdType face_offsets[7] = { 0, 4, 8, 12, 16, 20, 24 };
+  vtkIdType face_conns[24] = {
+    0, 3, 2, 1, //
+    0, 4, 7, 3, //
+    4, 5, 6, 7, //
+    5, 1, 2, 6, //
+    0, 1, 5, 4, //
+    2, 3, 7, 6  //
   };
-
-  aCube->SetFaces(faces);
+  vtkNew<vtkCellArray> faces;
+  vtkNew<vtkIdTypeArray> offsets_arr;
+  vtkNew<vtkIdTypeArray> conns_arr;
+  offsets_arr->SetArray(face_offsets, 7, 1);
+  conns_arr->SetArray(face_conns, 24, 1);
+  faces->SetData(offsets_arr, conns_arr);
+  aCube->SetCellFaces(faces);
   aCube->Initialize();
 
   return aCube;
@@ -947,23 +952,28 @@ vtkSmartPointer<vtkPolyhedron> MakeDodecahedron()
   aDodecahedron->GetPoints()->InsertNextPoint(-0.375185, -1.1547, -1.58931);
   aDodecahedron->GetPoints()->InsertNextPoint(0.982247, -0.713644, -1.58931);
 
-  vtkIdType faces[73] = {
-    12,                   // number of faces
-    5, 0, 1, 2, 3, 4,     // number of ids on face, ids
-    5, 0, 5, 10, 6, 1,    //
-    5, 1, 6, 11, 7, 2,    //
-    5, 2, 7, 12, 8, 3,    //
-    5, 3, 8, 13, 9, 4,    //
-    5, 4, 9, 14, 5, 0,    //
-    5, 15, 10, 5, 14, 19, //
-    5, 16, 11, 6, 10, 15, //
-    5, 17, 12, 7, 11, 16, //
-    5, 18, 13, 8, 12, 17, //
-    5, 19, 14, 9, 13, 18, //
-    5, 19, 18, 17, 16, 15 //
+  vtkIdType face_offsets[13] = { 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60 };
+  vtkIdType face_conns[60] = {
+    0, 1, 2, 3, 4,     // ids
+    0, 5, 10, 6, 1,    //
+    1, 6, 11, 7, 2,    //
+    2, 7, 12, 8, 3,    //
+    3, 8, 13, 9, 4,    //
+    4, 9, 14, 5, 0,    //
+    15, 10, 5, 14, 19, //
+    16, 11, 6, 10, 15, //
+    17, 12, 7, 11, 16, //
+    18, 13, 8, 12, 17, //
+    19, 14, 9, 13, 18, //
+    19, 18, 17, 16, 15 //
   };
-
-  aDodecahedron->SetFaces(faces);
+  vtkNew<vtkCellArray> faces;
+  vtkNew<vtkIdTypeArray> offsets_arr;
+  vtkNew<vtkIdTypeArray> conns_arr;
+  offsets_arr->SetArray(face_offsets, 13, 1);
+  conns_arr->SetArray(face_conns, 60, 1);
+  faces->SetData(offsets_arr, conns_arr);
+  aDodecahedron->SetCellFaces(faces);
   aDodecahedron->Initialize();
 
   return aDodecahedron;
diff --git a/Filters/General/vtkMergeCells.cxx b/Filters/General/vtkMergeCells.cxx
index 4890f8281502a7efd22def8cc49c19d6c4ff69f8..2b27af258bc6e1f9b8a0b983b99265ce7a59e03c 100644
--- a/Filters/General/vtkMergeCells.cxx
+++ b/Filters/General/vtkMergeCells.cxx
@@ -346,24 +346,26 @@ vtkIdType vtkMergeCells::AddNewCellsUnstructuredGrid(vtkDataSet* set, vtkIdType*
   // Connectivity for the merged grid so far
 
   vtkCellArray* cellArray = nullptr;
-  vtkIdType* flocs = nullptr;
-  vtkIdType* faces = nullptr;
+  vtkCellArray* flocs = nullptr;
+  vtkCellArray* faces = nullptr;
   unsigned char* types = nullptr;
 
   vtkIdType numCells = 0;
   vtkIdType numConnections = 0;
+  vtkIdType numFaces = 0;
   vtkIdType numFacesConnections = 0;
 
   if (!firstSet)
   {
     cellArray = grid->GetCells();
     types = grid->GetCellTypesArray()->GetPointer(0);
-    flocs = grid->GetFaceLocations() ? grid->GetFaceLocations()->GetPointer(0) : nullptr;
-    faces = grid->GetFaces() ? grid->GetFaces()->GetPointer(0) : nullptr;
+    flocs = grid->GetPolyhedronFaceLocations() ? grid->GetPolyhedronFaceLocations() : nullptr;
+    faces = grid->GetPolyhedronFaces() ? grid->GetPolyhedronFaces() : nullptr;
 
     numCells = cellArray->GetNumberOfCells();
     numConnections = cellArray->GetNumberOfConnectivityIds();
-    numFacesConnections = faces ? grid->GetFaces()->GetNumberOfValues() : 0;
+    numFacesConnections = faces ? grid->GetPolyhedronFaces()->GetNumberOfConnectivityIds() : 0;
+    numFaces = faces ? grid->GetPolyhedronFaces()->GetNumberOfCells() : 0;
   }
 
   // New output grid: merging of existing and incoming grids
@@ -390,28 +392,29 @@ vtkIdType vtkMergeCells::AddNewCellsUnstructuredGrid(vtkDataSet* set, vtkIdType*
   }
 
   // FACES LOCATION ARRAY
-  vtkNew<vtkIdTypeArray> facesLocationArray;
-  facesLocationArray->SetNumberOfValues(totalNumCells);
+  vtkNew<vtkCellArray> facesLocationArray;
+  facesLocationArray->Allocate(totalNumCells);
+  facesLocationArray->GetOffsetsArray()->SetNumberOfValues(totalNumCells + 1);
   if (!firstSet && flocs)
   {
-    vtkIdType* fiptr = facesLocationArray->GetPointer(0); // new output dataset
-    memcpy(fiptr, flocs, numCells * sizeof(vtkIdType));   // existing set
+    auto copycells = std::min(numCells, totalNumCells);
+    facesLocationArray->GetConnectivityArray()->DeepCopy(flocs->GetConnectivityArray());
+    flocs->GetOffsetsArray()->GetTuples(0, copycells, facesLocationArray->GetOffsetsArray());
   }
   else if (!firstSet)
   {
-    facesLocationArray->FillComponent(0, -1);
+    facesLocationArray->GetOffsetsArray()->FillComponent(0, 0);
   }
 
   bool havePolyhedron = false;
 
   // FACES ARRAY
-  vtkNew<vtkIdTypeArray> facesArray;
-  facesArray->SetNumberOfValues(numFacesConnections);
+  vtkNew<vtkCellArray> facesArray;
+  facesArray->Allocate(numFaces, numFacesConnections);
   if (!firstSet && faces)
   {
     havePolyhedron = true;
-    vtkIdType* faptr = facesArray->GetPointer(0);                  // new output dataset
-    memcpy(faptr, faces, numFacesConnections * sizeof(vtkIdType)); // existing set
+    facesArray->DeepCopy(faces);
   }
 
   // set up new cell data
@@ -455,24 +458,34 @@ vtkIdType vtkMergeCells::AddNewCellsUnstructuredGrid(vtkDataSet* set, vtkIdType*
       const vtkIdType* ptIds;
       newGrid->GetFaceStream(oldCellId, nfaces, ptIds);
 
-      facesLocationArray->SetValue(finalCellId, facesArray->GetNumberOfValues());
-      facesArray->InsertNextValue(nfaces);
+      auto faceLocOff = facesLocationArray->GetOffsetsArray();
+      auto faceLocCon = facesLocationArray->GetConnectivityArray();
+
+      auto startFace = faceLocCon->GetNumberOfValues();
+      faceLocOff->SetTuple1(finalCellId, startFace);
+      faceLocOff->SetTuple1(finalCellId + 1, startFace + nfaces);
+      for (vtkIdType loc = startFace; loc < startFace + nfaces; ++loc)
+      {
+        faceLocCon->InsertTuple1(loc, loc);
+      }
 
       for (vtkIdType i = 0; i < nfaces; i++)
       {
         vtkIdType nfpts = *ptIds++;
-        facesArray->InsertNextValue(nfpts);
+        facesArray->InsertNextCell(nfpts);
         for (vtkIdType j = 0; j < nfpts; j++)
         {
           oldPtId = *ptIds++;
           finalPtId = idMap ? idMap[oldPtId] : this->NumberOfPoints + oldPtId;
-          facesArray->InsertNextValue(finalPtId);
+          facesArray->InsertCellPoint(finalPtId);
         }
       }
     }
     else
     {
-      facesLocationArray->SetValue(finalCellId, -1);
+      // Hazardous...
+      vtkIdType tmp = facesLocationArray->GetOffsetsArray()->GetTuple1(finalCellId - 1);
+      facesLocationArray->GetOffsetsArray()->SetTuple1(finalCellId, tmp);
     }
 
     grid->GetCellData()->CopyData(
@@ -483,11 +496,11 @@ vtkIdType vtkMergeCells::AddNewCellsUnstructuredGrid(vtkDataSet* set, vtkIdType*
 
   if (havePolyhedron)
   {
-    grid->SetCells(typeArray, finalCellArray, facesLocationArray, facesArray);
+    grid->SetPolyhedralCells(typeArray, finalCellArray, facesLocationArray, facesArray);
   }
   else
   {
-    grid->SetCells(typeArray, finalCellArray, nullptr, nullptr);
+    grid->SetPolyhedralCells(typeArray, finalCellArray, nullptr, nullptr);
   }
 
   if (duplicateCellIds)
diff --git a/Filters/General/vtkTableBasedClipDataSet.cxx b/Filters/General/vtkTableBasedClipDataSet.cxx
index 5bfae09bb2305436c51f171eaf18ff0c15e12452..a43a75472484c3d4229cd8ab4ce0444bf74f2aaf 100644
--- a/Filters/General/vtkTableBasedClipDataSet.cxx
+++ b/Filters/General/vtkTableBasedClipDataSet.cxx
@@ -1363,7 +1363,7 @@ vtkSmartPointer<vtkUnstructuredGrid> vtkTableBasedClipDataSet::ClipTDataSet(
   auto outputClippedCells = vtkSmartPointer<vtkUnstructuredGrid>::New();
   outputClippedCells->SetPoints(outputPoints);
   outputClippedCells->GetPointData()->ShallowCopy(outputPointData);
-  outputClippedCells->SetCells(outputCellTypes, outputCellArray, nullptr, nullptr);
+  outputClippedCells->SetPolyhedralCells(outputCellTypes, outputCellArray, nullptr, nullptr);
   outputClippedCells->GetCellData()->ShallowCopy(outputCellData);
 
   // check if there are unsupported cell types
diff --git a/Filters/HyperTree/vtkHyperTreeGridContour.cxx b/Filters/HyperTree/vtkHyperTreeGridContour.cxx
index 394f1ee1582c71111ca59fb0797d711a9fbe213e..bd834c133d0b57b0b871a77ccd57d383417bc04e 100644
--- a/Filters/HyperTree/vtkHyperTreeGridContour.cxx
+++ b/Filters/HyperTree/vtkHyperTreeGridContour.cxx
@@ -56,7 +56,6 @@ const unsigned int* MooreCursors[3] = {
 // Conversion table of canonical ids from voxel to polyhedron
 constexpr vtkIdType CANONICAL_FACES[24] = { 2, 3, 1, 0, 1, 5, 4, 0, 4, 6, 2, 0, 3, 7, 5, 1, 2, 6, 7,
   3, 5, 7, 6, 4 };
-constexpr std::size_t POLY_FACES_SIZE = 31;
 constexpr vtkIdType POLY_FACES_NB = 6;
 constexpr vtkIdType POLY_FACES_POINTS_NB = 4;
 constexpr vtkIdType POLY_POINTS_NB = 8;
@@ -259,7 +258,7 @@ void ReplaceWithIndexedArray(const std::string& contourArrayName, vtkContourValu
 struct vtkHyperTreeGridContour::vtkInternals
 {
   // Temporary data structures related to USE_DECOMPOSED_POLYHEDRA strategy
-  std::vector<vtkIdType> Faces;
+  vtkNew<vtkCellArray> Faces;
   vtkNew<vtkPolyhedron> Polyhedron;
   vtkNew<vtkGenericCell> Tetra;
   vtkNew<vtkDoubleArray> TetraScalars;
@@ -305,7 +304,7 @@ vtkHyperTreeGridContour::vtkHyperTreeGridContour()
   // Initialize temporal structures related to USE_DECOMPOSED_POLYHEDRA strategy
   this->Internals->Polyhedron->GetPointIds()->SetNumberOfIds(::POLY_POINTS_NB);
   this->Internals->Polyhedron->GetPoints()->SetNumberOfPoints(::POLY_POINTS_NB);
-  this->Internals->Faces.reserve(::POLY_FACES_SIZE);
+  this->Internals->Faces->AllocateExact(::POLY_FACES_NB, ::POLY_FACES_POINTS_NB * ::POLY_FACES_NB);
 }
 
 //------------------------------------------------------------------------------
@@ -887,18 +886,18 @@ void vtkHyperTreeGridContour::RecursivelyProcessTree(
           }
 
           // Construct faces from voxel point ids (global ids)
-          this->Internals->Faces.clear();
-          this->Internals->Faces.emplace_back(::POLY_FACES_NB);
+          this->Internals->Faces->Reset();
           for (int faceId = 0, canonicalId = 0; faceId < ::POLY_FACES_NB; faceId++)
           {
-            this->Internals->Faces.emplace_back(::POLY_FACES_POINTS_NB);
+            this->Internals->Faces->InsertNextCell(::POLY_FACES_POINTS_NB);
             for (int i = 0; i < ::POLY_FACES_POINTS_NB; i++, canonicalId++)
             {
-              this->Internals->Faces.emplace_back(cell->GetPointId(::CANONICAL_FACES[canonicalId]));
+              this->Internals->Faces->InsertCellPoint(
+                cell->GetPointId(::CANONICAL_FACES[canonicalId]));
             }
           }
 
-          this->Internals->Polyhedron->SetFaces(this->Internals->Faces.data());
+          this->Internals->Polyhedron->SetCellFaces(this->Internals->Faces);
           this->Internals->Polyhedron->Initialize();
 
           // Decompose the this->Internals->Polyhedron
diff --git a/Filters/Parallel/vtkExtractUnstructuredGridPiece.cxx b/Filters/Parallel/vtkExtractUnstructuredGridPiece.cxx
index 988b15291a33676d015dc79baa9955365467a070..2eb462ce97b56ecf57d302da9a7e06277ac427b6 100644
--- a/Filters/Parallel/vtkExtractUnstructuredGridPiece.cxx
+++ b/Filters/Parallel/vtkExtractUnstructuredGridPiece.cxx
@@ -160,6 +160,7 @@ int vtkExtractUnstructuredGridPiece::RequestData(vtkInformation* vtkNotUsed(requ
   vtkIdType numFaces;
   vtkIdType numFacePts;
   double* x;
+  vtkNew<vtkIdList> faceStreamList;
 
   // Pipeline update piece will tell us what to generate.
   ghostLevel = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS());
@@ -263,7 +264,8 @@ int vtkExtractUnstructuredGridPiece::RequestData(vtkInformation* vtkNotUsed(requ
         }
         else
         { // Polyhedron, need to process face stream.
-          faceStream = input->GetFaces(cellId);
+          input->GetFaceStream(cellId, faceStreamList);
+          faceStream = faceStreamList->GetPointer(0);
           numFaces = *faceStream++;
           newCellPts->InsertNextId(numFaces);
           for (vtkIdType face = 0; face < numFaces; ++face)
diff --git a/Filters/ParallelDIY2/Testing/Cxx/TestGhostCellsGenerator.cxx b/Filters/ParallelDIY2/Testing/Cxx/TestGhostCellsGenerator.cxx
index 2464fe45eb031269f884c585ef80915641dc16a8..246f1e28eec9e8157f1a5cdf907ba53ba0f81579 100644
--- a/Filters/ParallelDIY2/Testing/Cxx/TestGhostCellsGenerator.cxx
+++ b/Filters/ParallelDIY2/Testing/Cxx/TestGhostCellsGenerator.cxx
@@ -1977,12 +1977,12 @@ vtkSmartPointer<vtkUnstructuredGrid> Convert3DImageToUnstructuredGrid(
   }
 
   const int* extent = input->GetExtent();
-  vtkNew<vtkIdTypeArray> faces;
-  // half cells * number of faces in voxel [6] * (number of points in face + 1) [4 + 1]
-  faces->SetNumberOfValues((numberOfCells / 2) * (6 * 5 + 1));
+  vtkNew<vtkCellArray> faces;
+  // half cells * number of faces in voxel [6] * (number of points in face) [4]
+  faces->AllocateExact((numberOfCells / 2) * 6, (numberOfCells / 2) * (6 * 4));
 
-  vtkNew<vtkIdTypeArray> faceLocations;
-  faceLocations->SetNumberOfValues(numberOfCells);
+  vtkNew<vtkCellArray> faceLocations;
+  faceLocations->AllocateExact(numberOfCells, (numberOfCells / 2) * 6);
 
   vtkNew<vtkUnsignedCharArray> types;
   types->SetNumberOfValues(numberOfCells);
@@ -2009,72 +2009,70 @@ vtkSmartPointer<vtkUnstructuredGrid> Convert3DImageToUnstructuredGrid(
 
     if (producePolyhedrons && cellId % 2)
     {
-      vtkIdType id = ((cellId / 2) * (5 * 6 + 1));
-      faceLocations->SetValue(cellId, id);
+      vtkIdType pos = (cellId / 2) * 6;
+      faceLocations->InsertNextCell(6); // 6 faces.
+      faceLocations->InsertCellPoint(pos + 0);
+      faceLocations->InsertCellPoint(pos + 1);
+      faceLocations->InsertCellPoint(pos + 2);
+      faceLocations->InsertCellPoint(pos + 3);
+      faceLocations->InsertCellPoint(pos + 4);
+      faceLocations->InsertCellPoint(pos + 5);
 
       types->SetValue(cellId, VTK_POLYHEDRON);
 
-      faces->SetValue(id, 6); // 6 faces.
-      ++id;
-
       vtkIdType offsetId = connectivityId - 8;
-      faces->SetValue(id, 4); // 4 points per face.
+      faces->InsertNextCell(4); // 4 points per face.
       // Bottom face
-      faces->SetValue(id + 1, connectivity->GetValue(offsetId + 0));
-      faces->SetValue(id + 2, connectivity->GetValue(offsetId + 1));
-      faces->SetValue(id + 3, connectivity->GetValue(offsetId + 3));
-      faces->SetValue(id + 4, connectivity->GetValue(offsetId + 2));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 0));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 1));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 3));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 2));
 
-      id += 5;
-      faces->SetValue(id, 4); // 4 points per face.
+      faces->InsertNextCell(4); // 4 points per face.
       // Top face
-      faces->SetValue(id + 1, connectivity->GetValue(offsetId + 4));
-      faces->SetValue(id + 2, connectivity->GetValue(offsetId + 5));
-      faces->SetValue(id + 3, connectivity->GetValue(offsetId + 7));
-      faces->SetValue(id + 4, connectivity->GetValue(offsetId + 6));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 4));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 5));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 7));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 6));
 
-      id += 5;
-      faces->SetValue(id, 4); // 4 points per face.
+      faces->InsertNextCell(4); // 4 points per face.
       // Front face
-      faces->SetValue(id + 1, connectivity->GetValue(offsetId + 0));
-      faces->SetValue(id + 2, connectivity->GetValue(offsetId + 1));
-      faces->SetValue(id + 3, connectivity->GetValue(offsetId + 5));
-      faces->SetValue(id + 4, connectivity->GetValue(offsetId + 4));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 0));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 1));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 5));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 4));
 
-      id += 5;
-      faces->SetValue(id, 4); // 4 points per face.
+      faces->InsertNextCell(4); // 4 points per face.
       // Back face
-      faces->SetValue(id + 1, connectivity->GetValue(offsetId + 2));
-      faces->SetValue(id + 2, connectivity->GetValue(offsetId + 3));
-      faces->SetValue(id + 3, connectivity->GetValue(offsetId + 7));
-      faces->SetValue(id + 4, connectivity->GetValue(offsetId + 6));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 2));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 3));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 7));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 6));
 
-      id += 5;
-      faces->SetValue(id, 4); // 4 points per face.
+      faces->InsertNextCell(4); // 4 points per face.
       // Left face
-      faces->SetValue(id + 1, connectivity->GetValue(offsetId + 0));
-      faces->SetValue(id + 2, connectivity->GetValue(offsetId + 2));
-      faces->SetValue(id + 3, connectivity->GetValue(offsetId + 6));
-      faces->SetValue(id + 4, connectivity->GetValue(offsetId + 4));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 0));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 2));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 6));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 4));
 
-      id += 5;
-      faces->SetValue(id, 4); // 4 points per face.
+      faces->InsertNextCell(4); // 4 points per face.
       // Right face
-      faces->SetValue(id + 1, connectivity->GetValue(offsetId + 1));
-      faces->SetValue(id + 2, connectivity->GetValue(offsetId + 3));
-      faces->SetValue(id + 3, connectivity->GetValue(offsetId + 7));
-      faces->SetValue(id + 4, connectivity->GetValue(offsetId + 5));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 1));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 3));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 7));
+      faces->InsertCellPoint(connectivity->GetValue(offsetId + 5));
     }
     else
     {
-      faceLocations->SetValue(cellId, -1);
+      faceLocations->InsertNextCell(0);
       types->SetValue(cellId, VTK_VOXEL);
     }
   }
 
   if (producePolyhedrons)
   {
-    output->SetCells(types, cells, faceLocations, faces);
+    output->SetPolyhedralCells(types, cells, faceLocations, faces);
   }
   else
   {
diff --git a/Parallel/DIY/vtkDIYGhostUtilities.cxx b/Parallel/DIY/vtkDIYGhostUtilities.cxx
index e095eaec84362d46d0a139f26c14e99db1872d2e..cc8b9f5bcd9a7c5d54991d8b4dba7c612f66f436 100644
--- a/Parallel/DIY/vtkDIYGhostUtilities.cxx
+++ b/Parallel/DIY/vtkDIYGhostUtilities.cxx
@@ -1926,11 +1926,36 @@ struct ComputePolyDataConnectivitySizeWorker
   vtkIdType TotalStripsSize = 0;
 };
 
+//----------------------------------------------------------------------------
+// Helper for ComputeFacesSizeWorker and UpdateCellBufferSize
+namespace
+{
+struct GetPolyhedronNPts
+{
+  // Insert full cell
+  template <typename CellStateT>
+  vtkIdType operator()(CellStateT& state, const vtkIdType cellId, const vtkCellArray* faces)
+  {
+    vtkIdType npts = 0;
+
+    const vtkIdType beginOffset = state.GetBeginOffset(cellId);
+    const vtkIdType endOffset = state.GetEndOffset(cellId);
+    const vtkIdType NumberOfFaces = endOffset - beginOffset;
+    const auto cellFaces = state.GetConnectivity()->GetPointer(beginOffset);
+
+    for (vtkIdType faceNum = 0; faceNum < NumberOfFaces; ++faceNum)
+    {
+      npts += faces->GetCellSize(static_cast<vtkIdType>(cellFaces[faceNum]));
+    }
+    return npts;
+  }
+};
+}
 
 //============================================================================
 struct ComputeFacesSizeWorker
 {
-  ComputeFacesSizeWorker(vtkIdTypeArray* faces, vtkIdTypeArray* faceLocations,
+  ComputeFacesSizeWorker(vtkCellArray* faces, vtkCellArray* faceLocations,
       vtkUnsignedCharArray* ghostCells)
     : Faces(faces)
     , FaceLocations(faceLocations)
@@ -1941,20 +1966,17 @@ struct ComputeFacesSizeWorker
   void operator()(vtkIdType startId, vtkIdType endId)
   {
     vtkIdType& size = this->Size.Local();
+    vtkIdType& facenum = this->FaceNum.Local();
+
     for (vtkIdType cellId = startId; cellId < endId; ++cellId)
     {
       if (!(this->GhostCells->GetValue(cellId) & ::GHOST_CELL_TO_PEEL_IN_UNSTRUCTURED_DATA))
       {
-        vtkIdType id = this->FaceLocations->GetValue(cellId);
-        if (id != -1)
+        vtkIdType id = this->FaceLocations->GetCellSize(cellId);
+        if (id != 0)
         {
-          vtkIdType numberOfFaces = this->Faces->GetValue(id++);
-          size += numberOfFaces + 1;
-          for (vtkIdType faceId = 0; faceId < numberOfFaces;
-              ++faceId, id += this->Faces->GetValue(id) + 1)
-          {
-            size += this->Faces->GetValue(id);
-          }
+          facenum += this->FaceLocations->GetCellSize(cellId);
+          size += this->FaceLocations->Visit(GetPolyhedronNPts{}, cellId, this->Faces);
         }
       }
     }
@@ -1963,6 +1985,7 @@ struct ComputeFacesSizeWorker
   void Initialize()
   {
     this->Size.Local() = 0;
+    this->FaceNum.Local() = 0;
   }
 
   void Reduce()
@@ -1971,14 +1994,20 @@ struct ComputeFacesSizeWorker
     {
       this->TotalSize += size;
     }
+    for (const vtkIdType& size : this->FaceNum)
+    {
+      this->TotalFaceNum += size;
+    }
   }
 
-  vtkIdTypeArray* Faces;
-  vtkIdTypeArray* FaceLocations;
+  vtkCellArray* Faces;
+  vtkCellArray* FaceLocations;
   vtkUnsignedCharArray* GhostCells;
 
   vtkSMPThreadLocal<vtkIdType> Size;
+  vtkSMPThreadLocal<vtkIdType> FaceNum;
   vtkIdType TotalSize = 0;
+  vtkIdType TotalFaceNum = 0;
 };
 
 #define ComputePolyDataConnectivitySizeWorkerMacro(mask)                                          \
@@ -2142,25 +2171,28 @@ void InitializeInformationIdsForUnstructuredData(vtkUnstructuredGrid* input,
       info.InputConnectivitySize = worker.TotalSize;
     }
 
-    vtkIdTypeArray* faceLocations = input->GetFaceLocations();
-    vtkIdTypeArray* faces = input->GetFaces();
+    vtkCellArray* faceLocations = input->GetPolyhedronFaceLocations();
+    vtkCellArray* faces = input->GetPolyhedronFaces();
 
-    if (faceLocations && faceLocations->GetNumberOfValues() && faces && faces->GetNumberOfValues())
+    if (faceLocations && faceLocations->GetNumberOfCells() && faces && faces->GetNumberOfCells())
     {
       ::ComputeFacesSizeWorker worker(faces, faceLocations, ghosts);
       vtkSMPTools::For(0, numberOfCells, worker);
 
       info.InputFacesSize = worker.TotalSize;
+      info.InputNumberOfFaces = worker.TotalFaceNum;
     }
   }
   else
   {
     info.InputConnectivitySize = cells->GetConnectivityArray()->GetNumberOfTuples();
-    info.InputFacesSize = input->GetFaces() ? input->GetFaces()->GetNumberOfValues() : 0;
+    info.InputFacesSize = input->GetPolyhedronFaces() ? input->GetPolyhedronFaces()->GetConnectivityArray()->GetNumberOfTuples() : 0;
+    info.InputNumberOfFaces = input->GetPolyhedronFaces() ? input->GetPolyhedronFaces()->GetOffsetsArray()->GetNumberOfTuples()-1 : 0;
   }
 
   info.CurrentConnectivitySize = info.InputConnectivitySize;
   info.CurrentFacesSize = info.InputFacesSize;
+  info.CurrentMaxFaceId = info.InputNumberOfFaces;
 }
 
 //----------------------------------------------------------------------------
@@ -2525,23 +2557,21 @@ struct FillUnstructuredDataTopologyBufferFunctor<InputArrayT, OutputArrayT, vtkU
     vtkCellArray* inputCellArray = input->GetCells();
     vtkIdType outputId = 0;
 
-    vtkIdTypeArray* inputFaces = input->GetFaces();
-    vtkIdTypeArray* inputFaceLocations = input->GetFaceLocations();
+    vtkCellArray* inputFaces = input->GetPolyhedronFaces();
+    vtkCellArray* inputFaceLocations = input->GetPolyhedronFaceLocations();
 
     // faces and faceLocations deal with VTK_POLYHEDRON. If there are VTK_POLYHEDRON cells in the
     // input, we instantiate those arrays for our buffers.
-    if (inputFaces && inputFaces->GetNumberOfValues())
+    if (inputFaces && inputFaces->GetNumberOfCells())
     {
-      buffer.Faces = vtkSmartPointer<vtkIdTypeArray>::New();
-      buffer.Faces->SetNumberOfValues(blockStructure.FacesSize);
-      buffer.FaceLocations = vtkSmartPointer<vtkIdTypeArray>::New();
-      buffer.FaceLocations->SetNumberOfValues(numberOfCellsToSend);
-      buffer.FaceLocations->FillValue(-1);
-
+      buffer.Faces = vtkSmartPointer<vtkCellArray>::New();
+      buffer.Faces->AllocateExact(blockStructure.FacesNum, blockStructure.FacesSize);
+      buffer.FaceLocations = vtkSmartPointer<vtkCellArray>::New();
+      buffer.FaceLocations->AllocateExact(numberOfCellsToSend, blockStructure.FacesNum);
     }
 
-    vtkIdTypeArray* faces = buffer.Faces;
-    vtkIdTypeArray* faceLocations = buffer.FaceLocations;
+    vtkCellArray* faces = buffer.Faces;
+    vtkCellArray* faceLocations = buffer.FaceLocations;
 
     vtkIdType currentFacesId = 0;
 
@@ -2555,36 +2585,42 @@ struct FillUnstructuredDataTopologyBufferFunctor<InputArrayT, OutputArrayT, vtkU
 
       if (cellType == VTK_POLYHEDRON)
       {
-        faceLocations->SetValue(outputId, currentFacesId);
-        vtkIdType id = inputFaceLocations->GetValue(cellId);
-        vtkIdType numberOfFaces = inputFaces->GetValue(id++);
-        faces->SetValue(currentFacesId++, numberOfFaces);
+        vtkIdType numberOfFaces =0;
+        vtkIdType const* faceIds;
+        vtkNew<vtkIdList> faceTmp;
+        vtkNew<vtkIdList> ptsTmp;
+        inputFaceLocations->GetCellAtId(cellId, numberOfFaces, faceIds, faceTmp);
+        faceLocations->InsertNextCell(numberOfFaces);
         for (vtkIdType faceId = 0; faceId < numberOfFaces; ++faceId)
         {
-          vtkIdType numberOfPoints = inputFaces->GetValue(id++);
-          faces->SetValue(currentFacesId++, numberOfPoints);
+          vtkIdType numberOfPoints;
+          vtkIdType const* facePointIds;
+          inputFaces->GetCellAtId(faceIds[faceId], numberOfPoints, facePointIds, ptsTmp);
+          faceLocations->InsertCellPoint(currentFacesId++);
+          faces->InsertNextCell(numberOfPoints);
           for (vtkIdType facePointId = 0; facePointId < numberOfPoints; ++facePointId)
           {
-            vtkIdType pointId = inputFaces->GetValue(id + facePointId);
+            vtkIdType pointId = facePointIds[facePointId];
             auto it = pointIdsToSendWithIndex.find(pointId);
             // We will find a valid it of the point of id pointId is not on the interface between us
             // and the current connected block
             if (it != pointIdsToSendWithIndex.end())
             {
-              faces->SetValue(currentFacesId + facePointId, it->second);
+              faces->InsertCellPoint(it->second);
             }
             else
             {
               // We put a negative id here to tell the block who will receive this
               // that this point is part of the interfacing points: the neighboring block already owns
               // a copy of this point.
-              faces->SetValue(currentFacesId + facePointId, -seedPointIdsToSendWithIndex.at(pointId));
+              faces->InsertCellPoint(-seedPointIdsToSendWithIndex.at(pointId));
             }
-          }
-          currentFacesId += numberOfPoints;
-          id += numberOfPoints;
+          }          
         }
       }
+      else if (faceLocations){
+          faceLocations->InsertNextCell(0);
+      }
       types->SetValue(outputId++, cellType);
     }
   }
@@ -2700,20 +2736,17 @@ void UpdateCellBufferSize<vtkUnstructuredGrid>(vtkIdType cellIdToSend,
 {
   blockStructure.ConnectivitySize += info.Input->GetCells()->GetCellSize(cellIdToSend);
 
-  vtkIdTypeArray* faces = info.Faces;
-  vtkIdTypeArray* faceLocations = info.FaceLocations;
-  if (faces && faceLocations && faceLocations->GetValue(cellIdToSend) != -1) // i.e. is polyhedron
+  vtkCellArray* faces = info.Faces;
+  vtkCellArray* faceLocations = info.FaceLocations;
+  if (faces && faceLocations && faceLocations->GetCellSize(cellIdToSend) != 0) // i.e. is polyhedron
   {
     vtkIdType& facesSize = blockStructure.FacesSize;
-    vtkIdType locationId = faceLocations->GetValue(cellIdToSend);
-    vtkIdType numberOfFaces = faces->GetValue(locationId++);
-    facesSize += 1 + numberOfFaces;
-    for (vtkIdType faceId = 0; faceId < numberOfFaces; ++faceId)
-    {
-      vtkIdType faceSize = faces->GetValue(locationId);
-      facesSize += faceSize;
-      locationId += faceSize + 1;
-    }
+    vtkIdType& facesNum = blockStructure.FacesNum;
+    vtkIdType numberOfFaces = 0;
+    //
+    numberOfFaces = faceLocations->GetCellSize(cellIdToSend);
+    facesNum += numberOfFaces;
+    facesSize += faceLocations->Visit(GetPolyhedronNPts{}, cellIdToSend, faces);
   }
 }
 
@@ -3788,46 +3821,115 @@ void DeepCopyCells(vtkCellArray* inputCells, vtkCellArray* outputCells,
   }
 }
 
+
 //----------------------------------------------------------------------------
-void DeepCopyPolyhedrons(vtkUnstructuredGrid* ug, vtkUnstructuredGrid* clone,
-    ::UnstructuredGridInformation& info)
+template<class InputArrayT, class OutputArrayT>
+void DeepCopyPolyhedronImpl(vtkCellArray* inputFaceLocations, vtkCellArray* inputFaces,
+                              vtkCellArray* outputFaceLocations, vtkCellArray* outputFaces,
+                              vtkIdList* cellRedirectionMap, vtkIdList* pointRedirectionMap)
 {
-  vtkIdTypeArray* ugFaceLocations = ug->GetFaceLocations();
-  vtkIdTypeArray* cloneFaceLocations = clone->GetFaceLocations();
+  InputArrayT* inputConnectivity = vtkArrayDownCast<InputArrayT>(inputFaceLocations->GetConnectivityArray());
+  InputArrayT* inputOffsets = vtkArrayDownCast<InputArrayT>(inputFaceLocations->GetOffsetsArray());
+  InputArrayT* inputFacesConnectivity = vtkArrayDownCast<InputArrayT>(inputFaces->GetConnectivityArray());
+  InputArrayT* inputFacesOffsets = vtkArrayDownCast<InputArrayT>(inputFaces->GetOffsetsArray());
 
-  vtkIdList* cellRedirectionMap = info.OutputToInputCellIdRedirectionMap;
-  vtkIdList* pointRedirectionMap = info.OutputToInputPointIdRedirectionMap;
+  OutputArrayT* outputConnectivity = vtkArrayDownCast<OutputArrayT>(outputFaceLocations->GetConnectivityArray());
+  OutputArrayT* outputOffsets = vtkArrayDownCast<OutputArrayT>(outputFaceLocations->GetOffsetsArray());
+  OutputArrayT* outputFacesConnectivity = vtkArrayDownCast<OutputArrayT>(outputFaces->GetConnectivityArray());
+  OutputArrayT* outputFacesOffsets = vtkArrayDownCast<OutputArrayT>(outputFaces->GetOffsetsArray());
 
-  ugFaceLocations->GetTuples(cellRedirectionMap, cloneFaceLocations);
+  auto inputConnectivityRange = vtk::DataArrayValueRange<1>(inputConnectivity);
+  auto inputOffsetsRange = vtk::DataArrayValueRange<1>(inputOffsets);
+  auto inputFacesRange = vtk::DataArrayValueRange<1>(inputFacesOffsets);
+  auto inputFacesConnectivityRange = vtk::DataArrayValueRange<1>(inputFacesConnectivity);
 
-  vtkIdType outputFacesId = 0;
+  auto outputConnectivityRange = vtk::DataArrayValueRange<1>(outputConnectivity);
+  auto outputOffsetsRange = vtk::DataArrayValueRange<1>(outputOffsets);
+  auto outputFacesRange = vtk::DataArrayValueRange<1>(outputFacesOffsets);
+  auto outputFacesConnectivityRange = vtk::DataArrayValueRange<1>(outputFacesConnectivity);
 
-  vtkIdTypeArray* ugFaces = ug->GetFaces();
-  vtkIdTypeArray* cloneFaces = clone->GetFaces();
 
-  for (vtkIdType outputCellId = 0; outputCellId < clone->GetNumberOfCells(); ++outputCellId)
+  vtkIdType outputFacesId = 0;
+  outputOffsetsRange[0] = 0;
+  outputFacesRange[0] = 0;
+  for (vtkIdType outputCellId = 0; outputCellId < cellRedirectionMap->GetNumberOfIds(); ++outputCellId)
   {
-    if (cloneFaceLocations->GetValue(outputCellId) != -1)
-    {
-      vtkIdType inputCellId = cellRedirectionMap->GetId(outputCellId);
-      vtkIdType inputFacesId = ugFaceLocations->GetValue(inputCellId);
-      vtkIdType numberOfFaces = ugFaces->GetValue(inputFacesId++);
-      cloneFaces->SetValue(outputFacesId++, numberOfFaces);
-
-      for (vtkIdType faceId = 0; faceId < numberOfFaces; ++faceId)
-      {
-        vtkIdType numberOfPoints = ugFaces->GetValue(inputFacesId++);
-        cloneFaces->SetValue(outputFacesId++, numberOfPoints);
-
-        for (vtkIdType pointId = 0; pointId < numberOfPoints; ++pointId)
+    vtkIdType inputCellId = cellRedirectionMap->GetId(outputCellId);
+    vtkIdType inputOffset = inputOffsetsRange[inputCellId];
+    vtkIdType nextInputOffset = inputOffsetsRange[inputCellId + 1];
+    vtkIdType cellSize = nextInputOffset - inputOffset;
+    outputOffsetsRange[outputCellId + 1] = outputOffsetsRange[outputCellId] + cellSize;
+    vtkIdType outputOffset = outputOffsetsRange[outputCellId];
+    // Prepare cloneFaceLocations
+    for (vtkIdType faceId = 0; faceId < cellSize; ++faceId)
+    {
+      outputConnectivityRange[outputOffset + faceId] = outputFacesId++;
+    }
+    // copy polyhedron faces
+    for (vtkIdType faceSrcId = inputOffset, faceDstId = outputConnectivityRange[outputOffset] ; faceSrcId < nextInputOffset; ++faceSrcId, ++faceDstId)
+    {
+        vtkIdType faceSrcLoc = inputConnectivityRange[faceSrcId];
+        vtkIdType faceSrcOffset =  inputFacesRange[faceSrcLoc];
+        vtkIdType nextSrcFaceOffset =  inputFacesRange[faceSrcLoc+1];
+        outputFacesRange[faceDstId+1] = outputFacesRange[faceDstId] + (nextSrcFaceOffset-faceSrcOffset);
+        for (vtkIdType pointSrcId=faceSrcOffset, pointDestId=outputFacesRange[faceDstId]; pointSrcId < nextSrcFaceOffset; ++pointSrcId, ++pointDestId)
         {
-          cloneFaces->SetValue(outputFacesId + pointId,
-              pointRedirectionMap->GetId(ugFaces->GetValue(inputFacesId + pointId)));
+            outputFacesConnectivityRange[pointDestId] = pointRedirectionMap->GetId(inputFacesConnectivityRange[pointSrcId]);
         }
-      }
     }
   }
 }
+//----------------------------------------------------------------------------
+void DeepCopyPolyhedrons(vtkUnstructuredGrid* ug, vtkUnstructuredGrid* clone,
+    ::UnstructuredGridInformation& info)
+{
+
+  using ArrayType32 = vtkCellArray::ArrayType32;
+  using ArrayType64 = vtkCellArray::ArrayType64;
+
+  vtkCellArray* ugFaceLocations = ug->GetPolyhedronFaceLocations();
+  vtkCellArray* ugFaces = ug->GetPolyhedronFaces();
+  vtkCellArray* cloneFaceLocations = clone->GetPolyhedronFaceLocations();
+  vtkCellArray* cloneFaces = clone->GetPolyhedronFaces();
+
+  vtkIdList* cellRedirectionMap = info.OutputToInputCellIdRedirectionMap;
+  vtkIdList* pointRedirectionMap = info.OutputToInputPointIdRedirectionMap;
+
+  // Protection against mismatch storage
+  if (ugFaceLocations->IsStorage64Bit() != ugFaces->IsStorage64Bit())
+  {
+    ugFaceLocations->ConvertTo64BitStorage();
+    ugFaces->ConvertTo64BitStorage();
+  }
+  if (cloneFaceLocations->IsStorage64Bit() != cloneFaces->IsStorage64Bit())
+  {
+    cloneFaceLocations->ConvertTo64BitStorage();
+    cloneFaces->ConvertTo64BitStorage();
+  }
+
+  // compute storage mask
+  int mask = static_cast<int>(ugFaceLocations->IsStorage64Bit()) | (static_cast<int>(cloneFaceLocations->IsStorage64Bit()) << 1);
+
+  switch(mask)
+  {
+    case 0:
+      ::DeepCopyPolyhedronImpl<ArrayType32, ArrayType32>(ugFaceLocations, ugFaces, cloneFaceLocations, cloneFaces, cellRedirectionMap,
+          pointRedirectionMap);
+      break;
+    case 1:
+      ::DeepCopyPolyhedronImpl<ArrayType64, ArrayType32>(ugFaceLocations, ugFaces, cloneFaceLocations, cloneFaces, cellRedirectionMap,
+          pointRedirectionMap);
+      break;
+    case 2:
+      ::DeepCopyPolyhedronImpl<ArrayType32, ArrayType64>(ugFaceLocations, ugFaces, cloneFaceLocations, cloneFaces, cellRedirectionMap,
+          pointRedirectionMap);
+      break;
+    case 3:
+      ::DeepCopyPolyhedronImpl<ArrayType64, ArrayType64>(ugFaceLocations, ugFaces, cloneFaceLocations, cloneFaces, cellRedirectionMap,
+          pointRedirectionMap);
+      break;
+  }
+}
 
 //----------------------------------------------------------------------------
 /**
@@ -3842,14 +3944,56 @@ void CloneUnstructuredGrid(vtkUnstructuredGrid* ug, vtkUnstructuredGrid* clone,
   ::ClonePoints(ug, clone, info);
   ::CloneCellData(ug, clone, info);
 
+  if (!ug->GetPolyhedronFaces() && clone->GetPolyhedronFaces()
+      && clone->GetPolyhedronFaceLocations())
+  {
+    //initialize empty polyhedron when none are present but they are required for output.
+    using ArrayType32 = vtkCellArray::ArrayType32;
+    using ArrayType64 = vtkCellArray::ArrayType64;
+
+    if (clone->GetPolyhedronFaceLocations()->IsStorage64Bit())
+    {
+      auto faceLocRange = vtkArrayDownCast<ArrayType64>(clone->GetPolyhedronFaceLocations()->GetOffsetsArray());
+      for (vtkIdType pos=0; pos<ug->GetNumberOfCells()+1; ++pos)
+      {
+        faceLocRange->SetValue(pos, 0);
+      }
+    }
+    else
+    {
+      auto faceLocRange = vtkArrayDownCast<ArrayType32>(clone->GetPolyhedronFaceLocations()->GetOffsetsArray());
+      for (vtkIdType pos=0; pos<ug->GetNumberOfCells()+1; ++pos)
+      {
+        faceLocRange->SetValue(pos, 0);
+      }
+    }
+
+    if (clone->GetPolyhedronFaces()->IsStorage64Bit())
+    {
+      auto faceLocRange = vtkArrayDownCast<ArrayType64>(clone->GetPolyhedronFaces()->GetOffsetsArray());    
+      for (vtkIdType pos=0; pos<clone->GetPolyhedronFaces()->GetOffsetsArray()->GetNumberOfTuples(); ++pos)
+      {
+        faceLocRange->SetValue(pos, 0);
+      }
+    }
+    else
+    {
+      auto faceLocRange = vtkArrayDownCast<ArrayType32>(clone->GetPolyhedronFaces()->GetOffsetsArray());
+      for (vtkIdType pos=0; pos<clone->GetPolyhedronFaces()->GetOffsetsArray()->GetNumberOfTuples(); ++pos)
+      {
+        faceLocRange->SetValue(pos, 0);
+      }
+    }
+  }
+
   if (vtkIdList* redirectionMap = info.OutputToInputCellIdRedirectionMap)
   {
     ::DeepCopyCells(ug->GetCells(), clone->GetCells(), redirectionMap,
         info.InputToOutputPointIdRedirectionMap);
     ug->GetCellTypesArray()->GetTuples(redirectionMap, clone->GetCellTypesArray());
 
-    vtkIdTypeArray* ugFaceLocations = ug->GetFaceLocations();
-    if (clone->GetFaceLocations() && ugFaceLocations && ugFaceLocations->GetNumberOfValues())
+    vtkCellArray* ugFaceLocations = ug->GetPolyhedronFaceLocations();
+    if (clone->GetPolyhedronFaceLocations() && ugFaceLocations && ugFaceLocations->GetNumberOfCells())
     {
       ::DeepCopyPolyhedrons(ug, clone, info);
     }
@@ -3861,16 +4005,22 @@ void CloneUnstructuredGrid(vtkUnstructuredGrid* ug, vtkUnstructuredGrid* clone,
     vtkDataArray* ugConnectivity = ugCellArray->GetConnectivityArray();
     vtkDataArray* ugOffsets = ugCellArray->GetOffsetsArray();
 
-    ugConnectivity->GetTuples(0, ugConnectivity->GetNumberOfTuples() - 1,
-        cloneCellArray->GetConnectivityArray());
+    ugConnectivity->GetTuples(0, ugConnectivity->GetNumberOfTuples() - 1, cloneCellArray->GetConnectivityArray());
     ugOffsets->GetTuples(0, ugOffsets->GetNumberOfTuples() - 1, cloneCellArray->GetOffsetsArray());
     ug->GetCellTypesArray()->GetTuples(0, ug->GetNumberOfCells() - 1, clone->GetCellTypesArray());
 
-    vtkIdTypeArray* ugFaces = ug->GetFaces();
-    if (clone->GetFaces() && ugFaces && ugFaces->GetNumberOfValues())
+    vtkCellArray* ugFaces = ug->GetPolyhedronFaces();
+
+    if (clone->GetPolyhedronFaces() && ugFaces && ugFaces->GetNumberOfCells())
     {
-      ug->GetFaceLocations()->GetTuples(0, ug->GetNumberOfCells() - 1, clone->GetFaceLocations());
-      ug->GetFaces()->GetTuples(0, ug->GetFaces()->GetNumberOfValues() - 1, clone->GetFaces());
+      vtkDataArray* ugFaceConnectivity = ug->GetPolyhedronFaces()->GetConnectivityArray();
+      vtkDataArray* ugFaceOffsets = ug->GetPolyhedronFaces()->GetOffsetsArray();
+      vtkDataArray* ugPolyConnectivity = ug->GetPolyhedronFaceLocations()->GetConnectivityArray();
+      vtkDataArray* ugPolyOffsets = ug->GetPolyhedronFaceLocations()->GetOffsetsArray();
+      ugFaceConnectivity->GetTuples(0, ugFaceConnectivity->GetNumberOfTuples() - 1, clone->GetPolyhedronFaces()->GetConnectivityArray());
+      ugFaceOffsets->GetTuples(0, ugFaceOffsets->GetNumberOfTuples() - 1, clone->GetPolyhedronFaces()->GetOffsetsArray());
+      ugPolyConnectivity->GetTuples(0, ugPolyConnectivity->GetNumberOfTuples() - 1, clone->GetPolyhedronFaceLocations()->GetConnectivityArray());
+      ugPolyOffsets->GetTuples(0, ugPolyOffsets->GetNumberOfTuples() - 1, clone->GetPolyhedronFaceLocations()->GetOffsetsArray());
     }
   }
 }
@@ -4095,8 +4245,19 @@ void EnqueueCellsForUnstructuredData<vtkUnstructuredGrid>(const diy::Master::Pro
   cp.enqueue<vtkDataArray*>(blockId, buffer.Types);
   cp.enqueue<vtkDataArray*>(blockId, buffer.CellArray->GetOffsetsArray());
   cp.enqueue<vtkDataArray*>(blockId, buffer.CellArray->GetConnectivityArray());
-  cp.enqueue<vtkDataArray*>(blockId, buffer.Faces);
-  cp.enqueue<vtkDataArray*>(blockId, buffer.FaceLocations);
+  if (buffer.Faces && buffer.FaceLocations){
+    cp.enqueue<vtkDataArray*>(blockId, buffer.Faces->GetOffsetsArray());
+    cp.enqueue<vtkDataArray*>(blockId, buffer.Faces->GetConnectivityArray());
+    cp.enqueue<vtkDataArray*>(blockId, buffer.FaceLocations->GetOffsetsArray());
+    cp.enqueue<vtkDataArray*>(blockId, buffer.FaceLocations->GetConnectivityArray());
+  }
+  else
+  {
+    cp.enqueue<vtkDataArray*>(blockId, vtkSmartPointer<vtkIdTypeArray>(nullptr) );
+    cp.enqueue<vtkDataArray*>(blockId, vtkSmartPointer<vtkIdTypeArray>(nullptr));
+    cp.enqueue<vtkDataArray*>(blockId, vtkSmartPointer<vtkIdTypeArray>(nullptr));
+    cp.enqueue<vtkDataArray*>(blockId, vtkSmartPointer<vtkIdTypeArray>(nullptr));
+  }
 }
 
 //----------------------------------------------------------------------------
@@ -4211,25 +4372,56 @@ void DequeueCellsForUnstructuredData<::UnstructuredGridBlockStructure>(
   vtkDataArray* types = nullptr;
   vtkDataArray* offsets = nullptr;
   vtkDataArray* connectivity = nullptr;
+  vtkDataArray* faces_offsets = nullptr;
   vtkDataArray* faces = nullptr;
+  vtkDataArray* faceLocations_offsets = nullptr;
   vtkDataArray* faceLocations = nullptr;
 
   cp.dequeue<vtkDataArray*>(gid, types);
   cp.dequeue<vtkDataArray*>(gid, offsets);
   cp.dequeue<vtkDataArray*>(gid, connectivity);
+  cp.dequeue<vtkDataArray*>(gid, faces_offsets);
   cp.dequeue<vtkDataArray*>(gid, faces);
+  cp.dequeue<vtkDataArray*>(gid, faceLocations_offsets);
   cp.dequeue<vtkDataArray*>(gid, faceLocations);
 
   buffer.Types = vtkSmartPointer<vtkUnsignedCharArray>::Take(
       vtkArrayDownCast<vtkUnsignedCharArray>(types));
-  buffer.Faces = vtkSmartPointer<vtkIdTypeArray>::Take(
-      vtkArrayDownCast<vtkIdTypeArray>(faces));
-  buffer.FaceLocations = vtkSmartPointer<vtkIdTypeArray>::Take(
-      vtkArrayDownCast<vtkIdTypeArray>(faceLocations));
 
   using ArrayType32 = vtkCellArray::ArrayType32;
   using ArrayType64 = vtkCellArray::ArrayType64;
 
+  if (faces && faces_offsets)
+  {
+    buffer.Faces = vtkSmartPointer<vtkCellArray>::New();
+    if (ArrayType32* offsets32 = vtkArrayDownCast<ArrayType32>(faces_offsets))
+    {
+      buffer.Faces->SetData(offsets32, vtkArrayDownCast<ArrayType32>(faces));
+    }
+    else
+    {
+      buffer.Faces->SetData(vtkArrayDownCast<ArrayType64>(faces_offsets),
+          vtkArrayDownCast<ArrayType64>(faces));
+    }
+    faces_offsets->FastDelete();
+    faces->FastDelete();
+  }
+
+  if (faceLocations && faceLocations_offsets){
+    buffer.FaceLocations = vtkSmartPointer<vtkCellArray>::New();
+    if (ArrayType32* offsets32 = vtkArrayDownCast<ArrayType32>(faceLocations_offsets))
+    {
+      buffer.FaceLocations->SetData(offsets32, vtkArrayDownCast<ArrayType32>(faceLocations));
+    }
+    else
+    {
+      buffer.FaceLocations->SetData(vtkArrayDownCast<ArrayType64>(faceLocations_offsets),
+        vtkArrayDownCast<ArrayType64>(faceLocations));
+    }
+    faceLocations_offsets->FastDelete();
+    faceLocations->FastDelete();
+  }
+
   if (ArrayType32* offsets32 = vtkArrayDownCast<ArrayType32>(offsets))
   {
     buffer.CellArray->SetData(offsets32, vtkArrayDownCast<ArrayType32>(connectivity));
@@ -4433,8 +4625,7 @@ struct CellArrayInserter
   void operator()(vtkIdType startId, vtkIdType endId)
   {
     ArrayT* offsetsSource = vtkArrayDownCast<ArrayT>(this->SourceCells->GetOffsetsArray());
-    ArrayT* connectivitySource = vtkArrayDownCast<ArrayT>(
-        this->SourceCells->GetConnectivityArray());
+    ArrayT* connectivitySource = vtkArrayDownCast<ArrayT>(this->SourceCells->GetConnectivityArray());
     ArrayT* offsetsDest = vtkArrayDownCast<ArrayT>(this->DestCells->GetOffsetsArray());
     ArrayT* connectivityDest = vtkArrayDownCast<ArrayT>(this->DestCells->GetConnectivityArray());
 
@@ -4549,14 +4740,16 @@ void InsertCells(vtkCellArray* srcCells, vtkCellArray* dstCells,
 }
 
 //============================================================================
+template<class ArrayT>
 struct PolyhedronsInserter
 {
-  PolyhedronsInserter(vtkIdTypeArray* srcFaceLocations, vtkIdTypeArray* srcFaces,
-      vtkIdTypeArray* dstFaceLocations, vtkIdTypeArray* dstFaces,
+  PolyhedronsInserter(vtkCellArray* srcFaceLocations, vtkCellArray* srcFaces,
+      vtkCellArray* dstFaceLocations, vtkCellArray* dstFaces,
       vtkIdList* matchingReceivedPointIds,
       const std::map<vtkIdType, vtkIdType>& redirectionMapForDuplicatePointIds,
       const std::map<vtkIdType, vtkIdType>& pointIdOffsetIntervals,
-      vtkIdType pointIdOffset, vtkIdType cellIdOffset, vtkIdType facesOffset)
+      vtkIdType pointIdOffset, vtkIdType cellIdOffset,
+      vtkIdType facesIdOffset, vtkIdType facesOffset)
   : SourceFaceLocations(srcFaceLocations)
   , SourceFaces(srcFaces)
   , DestFaceLocations(dstFaceLocations)
@@ -4566,81 +4759,101 @@ struct PolyhedronsInserter
   , PointIdOffsetIntervals(pointIdOffsetIntervals)
   , PointIdOffset(pointIdOffset)
   , CellIdOffset(cellIdOffset)
+  , FacesIdOffset(facesIdOffset)
   , FacesOffset(facesOffset)
   {
+    ArrayT* offsetsFacesDest = vtkArrayDownCast<ArrayT>(this->DestFaces->GetOffsetsArray());
+    ArrayT* offsetsFacesSource = vtkArrayDownCast<ArrayT>(this->SourceFaces->GetOffsetsArray());
+    ArrayT* offsetsFaceLocDest = vtkArrayDownCast<ArrayT>(this->DestFaceLocations->GetOffsetsArray());
+    ArrayT* offsetsFaceLocSource = vtkArrayDownCast<ArrayT>(this->SourceFaceLocations->GetOffsetsArray());
+
+    // Last location of offsets will never be set in the loop, as it has
+    // numberOfCells + 1 values.
+    offsetsFaceLocDest->SetValue(this->CellIdOffset + this->SourceFaceLocations->GetNumberOfCells(),
+                  offsetsFaceLocDest->GetValue(this->CellIdOffset) +
+                  offsetsFaceLocSource->GetValue(this->SourceFaceLocations->GetNumberOfCells()));
+    offsetsFacesDest->SetValue(this->FacesIdOffset + this->SourceFaces->GetNumberOfCells(),
+                               offsetsFacesDest->GetValue(this->FacesIdOffset) +
+                               offsetsFacesSource->GetValue(this->SourceFaces->GetNumberOfCells()));
   }
 
   void operator()(vtkIdType startId, vtkIdType endId)
   {
+    ArrayT *srcOffsets = vtkArrayDownCast<ArrayT>(this->SourceFaceLocations->GetOffsetsArray());
+    ArrayT *srcConnectivity = vtkArrayDownCast<ArrayT>(this->SourceFaceLocations->GetConnectivityArray());
+    ArrayT *srcFacesOffsets = vtkArrayDownCast<ArrayT>(this->SourceFaces->GetOffsetsArray());
+    ArrayT *srcFacesConnectivity = vtkArrayDownCast<ArrayT>(this->SourceFaces->GetConnectivityArray());
+    //
+    ArrayT *destOffsets = vtkArrayDownCast<ArrayT>(this->DestFaceLocations->GetOffsetsArray());
+    ArrayT *destConnectivity = vtkArrayDownCast<ArrayT>(this->DestFaceLocations->GetConnectivityArray());
+    ArrayT *destFacesOffsets = vtkArrayDownCast<ArrayT>(this->DestFaces->GetOffsetsArray());
+    ArrayT *destFacesConnectivity = vtkArrayDownCast<ArrayT>(this->DestFaces->GetConnectivityArray());
+
     for (vtkIdType cellId = startId; cellId < endId; ++cellId)
     {
-      // We enter the following if statement if current cell is a VTK_POLYHEDRON
-      if (this->SourceFaceLocations->GetValue(cellId) != -1)
-      {
-        vtkIdType id = this->SourceFaceLocations->GetValue(cellId);
-        vtkIdType currentFacesOffset = this->FacesOffset + id;
-
-        vtkIdType numberOfFaces = this->SourceFaces->GetValue(id++);
+      vtkIdType offset = srcOffsets->GetValue(cellId);
+      vtkIdType nextOffset = srcOffsets->GetValue(cellId + 1);
+      destOffsets->SetValue(this->CellIdOffset + cellId, this->FacesIdOffset + offset);
 
-
-        this->DestFaceLocations->SetValue(this->CellIdOffset + cellId, currentFacesOffset);
-        this->DestFaces->SetValue(currentFacesOffset++, numberOfFaces);
-
-        for (vtkIdType faceId = 0; faceId < numberOfFaces; ++faceId)
+      // We enter the following if statement if current cell is a VTK_POLYHEDRON
+      if ((nextOffset-offset) > 0)
+      {               
+        for (vtkIdType id = offset; id < nextOffset; ++id)
         {
-          vtkIdType faceSize = this->SourceFaces->GetValue(id++);
-          this->DestFaces->SetValue(currentFacesOffset++, faceSize);
-
-          for (vtkIdType facePointId = 0; facePointId < faceSize; ++facePointId)
+          vtkIdType faceId = srcConnectivity->GetValue(id);
+          //
+          vtkIdType faceOffset = srcFacesOffsets->GetValue(faceId);
+          vtkIdType nextFaceOffset = srcFacesOffsets->GetValue(faceId+1);
+          //
+          destConnectivity->SetValue(this->FacesIdOffset+id, this->FacesIdOffset+id);
+          destFacesOffsets->SetValue(this->FacesIdOffset+id, this->FacesOffset+faceOffset);
+          //
+          for (vtkIdType locPt = faceOffset; locPt<nextFaceOffset; ++locPt)
           {
-            // The following follows the same logic as for the connectivity array:
-            // Depending of if we already own a copy of the point, we map the connectivity
-            // to the point that is already stored. Otherwise, we create a new point.
-            vtkIdType pointId = this->SourceFaces->GetValue(id + facePointId);
-            if (pointId >= 0)
-            {
-              if (this->RedirectionMapForDuplicatePointIds.empty())
+              vtkIdType pointId = srcFacesConnectivity->GetValue(locPt);
+              if (pointId >= 0)
               {
-                this->DestFaces->SetValue(currentFacesOffset + facePointId,
-                    this->PointIdOffset + pointId);
-              }
-              else
-              {
-                auto it = this->RedirectionMapForDuplicatePointIds.find(pointId);
-                if (it == this->RedirectionMapForDuplicatePointIds.end())
+                if (this->RedirectionMapForDuplicatePointIds.empty())
                 {
-                  this->DestFaces->SetValue(currentFacesOffset + facePointId,
-                      this->PointIdOffset + pointId -
-                      this->PointIdOffsetIntervals.lower_bound(pointId)->second);
+                  destFacesConnectivity->SetValue(this->FacesOffset + locPt,
+                      this->PointIdOffset + pointId);
                 }
                 else
                 {
-                  this->DestFaces->SetValue(currentFacesOffset + facePointId, it->second);
+                  auto it = this->RedirectionMapForDuplicatePointIds.find(pointId);
+                  if (it == this->RedirectionMapForDuplicatePointIds.end())
+                  {
+                    destFacesConnectivity->SetValue(this->FacesOffset + locPt,
+                        this->PointIdOffset + pointId -
+                        this->PointIdOffsetIntervals.lower_bound(pointId)->second);
+                  }
+                  else
+                  {
+                    destFacesConnectivity->SetValue(this->FacesOffset + locPt, it->second);
+                  }
                 }
               }
-            }
-            else
-            {
-              this->DestFaces->SetValue(currentFacesOffset + facePointId,
-                  this->MatchingReceivedPointIds->GetId(-pointId - 1));
-            }
+              else
+              {
+                destFacesConnectivity->SetValue(this->FacesOffset + locPt,
+                    this->MatchingReceivedPointIds->GetId(-pointId - 1));
+              }
           }
-          id += faceSize;
-          currentFacesOffset += faceSize;
         }
       }
     }
   }
 
-  vtkIdTypeArray* SourceFaceLocations;
-  vtkIdTypeArray* SourceFaces;
-  vtkIdTypeArray* DestFaceLocations;
-  vtkIdTypeArray* DestFaces;
+  vtkCellArray* SourceFaceLocations;
+  vtkCellArray* SourceFaces;
+  vtkCellArray* DestFaceLocations;
+  vtkCellArray* DestFaces;
   vtkIdList* MatchingReceivedPointIds;
   const std::map<vtkIdType, vtkIdType>& RedirectionMapForDuplicatePointIds;
   const std::map<vtkIdType, vtkIdType>& PointIdOffsetIntervals;
   vtkIdType PointIdOffset;
   vtkIdType CellIdOffset;
+  vtkIdType FacesIdOffset;
   vtkIdType FacesOffset;
 };
 
@@ -4683,6 +4896,7 @@ void DeepCopyInputAndAllocateGhosts(::UnstructuredGridBlock* block,
 
   vtkIdType connectivitySize = info.InputConnectivitySize;
   vtkIdType facesSize = info.InputFacesSize;
+  vtkIdType facesNum = info.InputNumberOfFaces;
 
   for (auto& pair : block->BlockStructures)
   {
@@ -4692,8 +4906,9 @@ void DeepCopyInputAndAllocateGhosts(::UnstructuredGridBlock* block,
     numberOfCells += blockStructure.ReceiveBuffer.Types->GetNumberOfValues();
     connectivitySize +=
       blockStructure.ReceiveBuffer.CellArray->GetConnectivityArray()->GetNumberOfValues();
-    vtkIdTypeArray* faces = blockStructure.ReceiveBuffer.Faces;
-    facesSize += faces ? faces->GetNumberOfValues() : 0;
+    vtkCellArray* faces = blockStructure.ReceiveBuffer.Faces;
+    facesSize += faces ? faces->GetConnectivityArray()->GetNumberOfValues() : 0;
+    facesNum += faces ? faces->GetOffsetsArray()->GetNumberOfValues() - 1 : 0;
   }
 
   vtkPoints* inputPoints = input->GetPoints();
@@ -4710,16 +4925,19 @@ void DeepCopyInputAndAllocateGhosts(::UnstructuredGridBlock* block,
   vtkNew<vtkUnsignedCharArray> types;
   types->SetNumberOfValues(numberOfCells);
 
-  vtkSmartPointer<vtkIdTypeArray> outputFaces = nullptr;
-  vtkSmartPointer<vtkIdTypeArray> outputFaceLocations = nullptr;
+  vtkSmartPointer<vtkCellArray> outputFaces = nullptr;
+  vtkSmartPointer<vtkCellArray> outputFaceLocations = nullptr;
 
   if (facesSize)
   {
-    outputFaces = vtkSmartPointer<vtkIdTypeArray>::New();
-    outputFaces->SetNumberOfValues(facesSize);
-    outputFaceLocations = vtkSmartPointer<vtkIdTypeArray>::New();
-    outputFaceLocations->SetNumberOfValues(numberOfCells);
-    outputFaceLocations->FillValue(-1);
+    outputFaces = vtkSmartPointer<vtkCellArray>::New();
+    outputFaces->AllocateExact(facesNum, facesSize);
+    outputFaces->GetConnectivityArray()->SetNumberOfTuples(facesSize);
+    outputFaces->GetOffsetsArray()->SetNumberOfTuples(facesNum+1);
+    outputFaceLocations = vtkSmartPointer<vtkCellArray>::New();
+    outputFaceLocations->AllocateExact(numberOfCells, facesNum);
+    outputFaceLocations->GetConnectivityArray()->SetNumberOfTuples(facesNum);
+    outputFaceLocations->GetOffsetsArray()->SetNumberOfTuples(numberOfCells+1);
   }
 
 // We're being careful to account for different storage options in cell arrays
@@ -4733,7 +4951,7 @@ void DeepCopyInputAndAllocateGhosts(::UnstructuredGridBlock* block,
   outputCellArray->GetConnectivityArray()->SetNumberOfTuples(connectivitySize);
   outputCellArray->GetOffsetsArray()->SetNumberOfTuples(numberOfCells + 1);
 
-  output->SetCells(types, outputCellArray,
+  output->SetPolyhedralCells(types, outputCellArray,
       outputFaceLocations, outputFaces);
 
   ::CloneUnstructuredGrid(input, output, info);
@@ -5447,8 +5665,8 @@ void FillReceivedGhosts(::UnstructuredGridBlock* block, int myGid,
 
   vtkCellArray* outputCellArray = output->GetCells();
   vtkUnsignedCharArray* outputTypes = output->GetCellTypesArray();
-  vtkIdTypeArray* outputFaceLocations = output->GetFaceLocations();
-  vtkIdTypeArray* outputFaces = output->GetFaces();
+  vtkCellArray* outputFaceLocations = output->GetPolyhedronFaceLocations();
+  vtkCellArray* outputFaces = output->GetPolyhedronFaces();
 
   auto& buffer = blockStructure.ReceiveBuffer;
   vtkIdType numberOfAddedCells = buffer.Types->GetNumberOfValues();
@@ -5463,14 +5681,58 @@ void FillReceivedGhosts(::UnstructuredGridBlock* block, int myGid,
       blockStructure.RedirectionMapForDuplicatePointIds, pointIdOffsetIntervals,
       info.CurrentMaxPointId, info.CurrentMaxCellId, info.CurrentConnectivitySize);
 
-  if (vtkIdTypeArray* faceLocations = buffer.FaceLocations)
+  if (vtkCellArray* faceLocations = buffer.FaceLocations)
   {
-    ::PolyhedronsInserter inserter(faceLocations, buffer.Faces, outputFaceLocations, outputFaces,
-        blockStructure.RemappedMatchingReceivedPointIdsSortedLikeTarget,
-        blockStructure.RedirectionMapForDuplicatePointIds, pointIdOffsetIntervals,
-        info.CurrentMaxPointId, info.CurrentMaxCellId, info.CurrentFacesSize);
+    using ArrayType32 = vtkCellArray::ArrayType32;
+    using ArrayType64 = vtkCellArray::ArrayType64;
 
-    vtkSMPTools::For(0, faceLocations->GetNumberOfValues(), inserter);
+    if (!faceLocations->GetNumberOfCells())
+    {
+      return;
+    }
+
+    if (faceLocations->IsStorage64Bit())
+    {
+      ::PolyhedronsInserter<ArrayType64> inserter(faceLocations, buffer.Faces, outputFaceLocations, outputFaces,
+              blockStructure.RemappedMatchingReceivedPointIdsSortedLikeTarget,
+              blockStructure.RedirectionMapForDuplicatePointIds, pointIdOffsetIntervals,
+              info.CurrentMaxPointId, info.CurrentMaxCellId, info.CurrentMaxFaceId, info.CurrentFacesSize);
+      vtkSMPTools::For(0, faceLocations->GetNumberOfCells(), inserter);
+    }
+    else
+    {
+      ::PolyhedronsInserter<ArrayType32> inserter(faceLocations, buffer.Faces, outputFaceLocations, outputFaces,
+                blockStructure.RemappedMatchingReceivedPointIdsSortedLikeTarget,
+                blockStructure.RedirectionMapForDuplicatePointIds, pointIdOffsetIntervals,
+                info.CurrentMaxPointId, info.CurrentMaxCellId, info.CurrentMaxFaceId, info.CurrentFacesSize);
+       vtkSMPTools::For(0, faceLocations->GetNumberOfCells(), inserter);
+    }
+  }
+  else
+  {
+    // Take care of polyhedron when buffer do not have them but they are needed in the end
+    // Insert empty faces
+    if (outputFaceLocations)
+    {
+      using ArrayType32 = vtkCellArray::ArrayType32;
+      using ArrayType64 = vtkCellArray::ArrayType64;
+      if (outputFaceLocations->IsStorage64Bit())
+      {
+        auto faceLocRange = vtkArrayDownCast<ArrayType64>(outputFaceLocations->GetOffsetsArray());
+        for (vtkIdType pos=0; pos<numberOfAddedCells; ++pos)
+        {
+          faceLocRange->SetValue(info.CurrentMaxCellId+pos+1,faceLocRange->GetValue(info.CurrentMaxCellId+pos));
+        }
+      }
+      else
+      {
+        auto faceLocRange = vtkArrayDownCast<ArrayType32>(outputFaceLocations->GetOffsetsArray());
+        for (vtkIdType pos=0; pos<numberOfAddedCells; ++pos)
+        {
+          faceLocRange->SetValue(info.CurrentMaxCellId+pos+1,faceLocRange->GetValue(info.CurrentMaxCellId+pos));
+        }
+      }
+    }
   }
 
   ::FillDuplicateCellGhostArrayForUnstructureData(block->GhostCellArray,
@@ -5481,7 +5743,8 @@ void FillReceivedGhosts(::UnstructuredGridBlock* block, int myGid,
   info.CurrentMaxPointId += numberOfAddedPoints;
   info.CurrentMaxCellId += numberOfAddedCells;
   info.CurrentConnectivitySize += buffer.CellArray->GetConnectivityArray()->GetNumberOfTuples();
-  info.CurrentFacesSize += buffer.Faces ? buffer.Faces->GetNumberOfValues() : 0;
+  info.CurrentFacesSize += buffer.Faces ? buffer.Faces->GetConnectivityArray()->GetNumberOfTuples():0;
+  info.CurrentMaxFaceId += buffer.Faces ? buffer.Faces->GetOffsetsArray()->GetNumberOfTuples()-1:0;
 }
 
 //----------------------------------------------------------------------------
@@ -6200,13 +6463,13 @@ void vtkDIYGhostUtilities::InitializeBlocks(diy::Master& master,
     BlockType* block = master.block<BlockType>(localId);
     typename BlockType::InformationType& information = block->Information;
 
-    vtkIdTypeArray* faces = input->GetFaces();
-    information.Faces = faces && faces->GetNumberOfValues()
+    vtkCellArray* faces = input->GetPolyhedronFaces();
+    information.Faces = faces && faces->GetNumberOfCells()
       ? faces
       : nullptr;
 
-    vtkIdTypeArray* faceLocations = input->GetFaceLocations();
-    information.FaceLocations = faceLocations && faceLocations->GetNumberOfValues()
+    vtkCellArray* faceLocations = input->GetPolyhedronFaceLocations();
+    information.FaceLocations = faceLocations && faceLocations->GetNumberOfCells()
       ? faceLocations
       : nullptr;
   }
diff --git a/Parallel/DIY/vtkDIYGhostUtilities.h b/Parallel/DIY/vtkDIYGhostUtilities.h
index 3492231605e0d44d53e628f98e5ba69d331c783d..0d692610b1ab2c4f3b0baea90c50e82ecf77bed9 100644
--- a/Parallel/DIY/vtkDIYGhostUtilities.h
+++ b/Parallel/DIY/vtkDIYGhostUtilities.h
@@ -568,14 +568,20 @@ protected:
      */
     vtkIdType CurrentFacesSize = 0;
 
+    /**
+     * This is a cursor telling the amount of faces information, that has
+     * already been added to the output. This variable is used at the very end of the pipeline.
+     */
+    vtkIdType CurrentMaxFaceId = 0;
+
     /**
      * This is a cursor telling how much the output connectivity array is filled.
      * This is used at the very end of the pipeline.
      */
     vtkIdType CurrentConnectivitySize = 0;
 
-    vtkIdTypeArray* Faces = nullptr;
-    vtkIdTypeArray* FaceLocations = nullptr;
+    vtkCellArray* Faces = nullptr;
+    vtkCellArray* FaceLocations = nullptr;
 
     vtkUnstructuredGrid* Input;
 
@@ -588,6 +594,11 @@ protected:
      * Faces array size of the input if the ghost cells are removed.
      */
     vtkIdType InputFacesSize = 0;
+
+    /**
+     * Number of Faces stored in Faces array of the input if the ghost cells are removed.
+     */
+    vtkIdType InputNumberOfFaces = 0;
   };
 
   struct UnstructuredGridBlockStructure : public UnstructuredDataBlockStructure
@@ -598,8 +609,8 @@ protected:
     struct TopologyBufferType
     {
       vtkSmartPointer<vtkUnsignedCharArray> Types = nullptr;
-      vtkSmartPointer<vtkIdTypeArray> Faces = nullptr;
-      vtkSmartPointer<vtkIdTypeArray> FaceLocations = nullptr;
+      vtkSmartPointer<vtkCellArray> Faces = nullptr;
+      vtkSmartPointer<vtkCellArray> FaceLocations = nullptr;
       vtkNew<vtkCellArray> CellArray;
     };
 
@@ -611,6 +622,7 @@ protected:
      * Handle to the faces / connectivity size that we have to send to the neighboring block.
      */
     vtkIdType FacesSize = 0;
+    vtkIdType FacesNum = 0;
     vtkIdType ConnectivitySize = 0;
     ///@}
   };