1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //
6 //  This software is distributed WITHOUT ANY WARRANTY; without even
7 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 //  PURPOSE.  See the above copyright notice for more information.
9 //============================================================================
10 
11 #include <vtkm/cont/DataSet.h>
12 #include <vtkm/cont/DataSetBuilderExplicit.h>
13 #include <vtkm/cont/DataSetBuilderRectilinear.h>
14 #include <vtkm/cont/DataSetBuilderUniform.h>
15 #include <vtkm/cont/testing/Testing.h>
16 
17 #include <vtkm/filter/GhostCellRemove.h>
18 
19 namespace
20 {
21 
StructuredGhostCellArray(vtkm::Id nx,vtkm::Id ny,vtkm::Id nz,int numLayers,bool addMidGhost=false)22 static vtkm::cont::ArrayHandle<vtkm::UInt8> StructuredGhostCellArray(vtkm::Id nx,
23                                                                      vtkm::Id ny,
24                                                                      vtkm::Id nz,
25                                                                      int numLayers,
26                                                                      bool addMidGhost = false)
27 {
28   vtkm::Id numCells = nx * ny;
29   if (nz > 0)
30     numCells *= nz;
31 
32   constexpr vtkm::UInt8 normalCell = vtkm::CellClassification::NORMAL;
33   constexpr vtkm::UInt8 duplicateCell = vtkm::CellClassification::GHOST;
34 
35   vtkm::cont::ArrayHandle<vtkm::UInt8> ghosts;
36   ghosts.Allocate(numCells);
37   auto portal = ghosts.WritePortal();
38   for (vtkm::Id i = 0; i < numCells; i++)
39   {
40     if (numLayers == 0)
41       portal.Set(i, normalCell);
42     else
43       portal.Set(i, duplicateCell);
44   }
45 
46   if (numLayers > 0)
47   {
48     //2D case
49     if (nz == 0)
50     {
51       for (vtkm::Id i = numLayers; i < nx - numLayers; i++)
52         for (vtkm::Id j = numLayers; j < ny - numLayers; j++)
53           portal.Set(j * nx + i, normalCell);
54     }
55     else
56     {
57       for (vtkm::Id i = numLayers; i < nx - numLayers; i++)
58         for (vtkm::Id j = numLayers; j < ny - numLayers; j++)
59           for (vtkm::Id k = numLayers; k < nz - numLayers; k++)
60             portal.Set(k * nx * ny + j * nx + i, normalCell);
61     }
62   }
63 
64   if (addMidGhost)
65   {
66     if (nz == 0)
67     {
68       vtkm::Id mi = numLayers + (nx - numLayers) / 2;
69       vtkm::Id mj = numLayers + (ny - numLayers) / 2;
70       portal.Set(mj * nx + mi, duplicateCell);
71     }
72     else
73     {
74       vtkm::Id mi = numLayers + (nx - numLayers) / 2;
75       vtkm::Id mj = numLayers + (ny - numLayers) / 2;
76       vtkm::Id mk = numLayers + (nz - numLayers) / 2;
77       portal.Set(mk * nx * ny + mj * nx + mi, duplicateCell);
78     }
79   }
80   return ghosts;
81 }
82 
MakeUniform(vtkm::Id numI,vtkm::Id numJ,vtkm::Id numK,int numLayers,bool addMidGhost=false)83 static vtkm::cont::DataSet MakeUniform(vtkm::Id numI,
84                                        vtkm::Id numJ,
85                                        vtkm::Id numK,
86                                        int numLayers,
87                                        bool addMidGhost = false)
88 {
89   vtkm::cont::DataSetBuilderUniform dsb;
90   vtkm::cont::DataSet ds;
91 
92   if (numK == 0)
93     ds = dsb.Create(vtkm::Id2(numI + 1, numJ + 1));
94   else
95     ds = dsb.Create(vtkm::Id3(numI + 1, numJ + 1, numK + 1));
96   auto ghosts = StructuredGhostCellArray(numI, numJ, numK, numLayers, addMidGhost);
97 
98   ds.AddCellField("vtkmGhostCells", ghosts);
99 
100   return ds;
101 }
102 
MakeRectilinear(vtkm::Id numI,vtkm::Id numJ,vtkm::Id numK,int numLayers,bool addMidGhost=false)103 static vtkm::cont::DataSet MakeRectilinear(vtkm::Id numI,
104                                            vtkm::Id numJ,
105                                            vtkm::Id numK,
106                                            int numLayers,
107                                            bool addMidGhost = false)
108 {
109   vtkm::cont::DataSetBuilderRectilinear dsb;
110   vtkm::cont::DataSet ds;
111   std::size_t nx(static_cast<std::size_t>(numI + 1));
112   std::size_t ny(static_cast<std::size_t>(numJ + 1));
113 
114   std::vector<float> x(nx), y(ny);
115   for (std::size_t i = 0; i < nx; i++)
116     x[i] = static_cast<float>(i);
117   for (std::size_t i = 0; i < ny; i++)
118     y[i] = static_cast<float>(i);
119 
120   if (numK == 0)
121     ds = dsb.Create(x, y);
122   else
123   {
124     std::size_t nz(static_cast<std::size_t>(numK + 1));
125     std::vector<float> z(nz);
126     for (std::size_t i = 0; i < nz; i++)
127       z[i] = static_cast<float>(i);
128     ds = dsb.Create(x, y, z);
129   }
130 
131   auto ghosts = StructuredGhostCellArray(numI, numJ, numK, numLayers, addMidGhost);
132 
133   ds.AddCellField("vtkmGhostCells", ghosts);
134 
135   return ds;
136 }
137 
138 template <class CellSetType, vtkm::IdComponent NDIM>
MakeExplicitCells(const CellSetType & cellSet,vtkm::Vec<vtkm::Id,NDIM> & dims,vtkm::cont::ArrayHandle<vtkm::IdComponent> & numIndices,vtkm::cont::ArrayHandle<vtkm::UInt8> & shapes,vtkm::cont::ArrayHandle<vtkm::Id> & conn)139 static void MakeExplicitCells(const CellSetType& cellSet,
140                               vtkm::Vec<vtkm::Id, NDIM>& dims,
141                               vtkm::cont::ArrayHandle<vtkm::IdComponent>& numIndices,
142                               vtkm::cont::ArrayHandle<vtkm::UInt8>& shapes,
143                               vtkm::cont::ArrayHandle<vtkm::Id>& conn)
144 {
145   using Connectivity = vtkm::internal::ConnectivityStructuredInternals<NDIM>;
146 
147   vtkm::Id nCells = cellSet.GetNumberOfCells();
148   vtkm::Id connLen = (NDIM == 2 ? nCells * 4 : nCells * 8);
149 
150   conn.Allocate(connLen);
151   shapes.Allocate(nCells);
152   numIndices.Allocate(nCells);
153 
154   Connectivity structured;
155   structured.SetPointDimensions(dims);
156 
157   vtkm::Id idx = 0;
158   for (vtkm::Id i = 0; i < nCells; i++)
159   {
160     auto ptIds = structured.GetPointsOfCell(i);
161     for (vtkm::IdComponent j = 0; j < NDIM; j++, idx++)
162       conn.WritePortal().Set(idx, ptIds[j]);
163 
164     shapes.WritePortal().Set(i, (NDIM == 4 ? vtkm::CELL_SHAPE_QUAD : vtkm::CELL_SHAPE_HEXAHEDRON));
165     numIndices.WritePortal().Set(i, NDIM);
166   }
167 }
168 
MakeExplicit(vtkm::Id numI,vtkm::Id numJ,vtkm::Id numK,int numLayers)169 static vtkm::cont::DataSet MakeExplicit(vtkm::Id numI, vtkm::Id numJ, vtkm::Id numK, int numLayers)
170 {
171   using CoordType = vtkm::Vec3f_32;
172 
173   vtkm::cont::DataSet dsUniform = MakeUniform(numI, numJ, numK, numLayers);
174 
175   auto coordData = dsUniform.GetCoordinateSystem(0).GetDataAsMultiplexer();
176   vtkm::Id numPts = coordData.GetNumberOfValues();
177   vtkm::cont::ArrayHandle<CoordType> explCoords;
178 
179   explCoords.Allocate(numPts);
180   auto explPortal = explCoords.WritePortal();
181   auto cp = coordData.ReadPortal();
182   for (vtkm::Id i = 0; i < numPts; i++)
183     explPortal.Set(i, cp.Get(i));
184 
185   vtkm::cont::DynamicCellSet cellSet = dsUniform.GetCellSet();
186   vtkm::cont::ArrayHandle<vtkm::Id> conn;
187   vtkm::cont::ArrayHandle<vtkm::IdComponent> numIndices;
188   vtkm::cont::ArrayHandle<vtkm::UInt8> shapes;
189   vtkm::cont::DataSet ds;
190   vtkm::cont::DataSetBuilderExplicit dsb;
191 
192   if (cellSet.IsType<vtkm::cont::CellSetStructured<2>>())
193   {
194     vtkm::Id2 dims(numI, numJ);
195     MakeExplicitCells(
196       cellSet.Cast<vtkm::cont::CellSetStructured<2>>(), dims, numIndices, shapes, conn);
197     ds = dsb.Create(explCoords, vtkm::CellShapeTagQuad(), 4, conn, "coordinates");
198   }
199   else if (cellSet.IsType<vtkm::cont::CellSetStructured<3>>())
200   {
201     vtkm::Id3 dims(numI, numJ, numK);
202     MakeExplicitCells(
203       cellSet.Cast<vtkm::cont::CellSetStructured<3>>(), dims, numIndices, shapes, conn);
204     ds = dsb.Create(explCoords, vtkm::CellShapeTagHexahedron(), 8, conn, "coordinates");
205   }
206 
207   auto ghosts = StructuredGhostCellArray(numI, numJ, numK, numLayers);
208 
209   ds.AddCellField("vtkmGhostCells", ghosts);
210 
211   return ds;
212 }
213 
TestGhostCellRemove()214 void TestGhostCellRemove()
215 {
216   // specify some 2d tests: {numI, numJ, numK, numGhostLayers}.
217   std::vector<std::vector<vtkm::Id>> tests2D = { { 4, 4, 0, 2 },  { 5, 5, 0, 2 },  { 10, 10, 0, 3 },
218                                                  { 10, 5, 0, 2 }, { 5, 10, 0, 2 }, { 20, 10, 0, 3 },
219                                                  { 10, 20, 0, 3 } };
220   std::vector<std::vector<vtkm::Id>> tests3D = { { 4, 4, 4, 2 },    { 5, 5, 5, 2 },
221                                                  { 10, 10, 10, 3 }, { 10, 5, 10, 2 },
222                                                  { 5, 10, 10, 2 },  { 20, 10, 10, 3 },
223                                                  { 10, 20, 10, 3 } };
224 
225   std::vector<std::vector<vtkm::Id>> tests;
226 
227   tests.insert(tests.end(), tests2D.begin(), tests2D.end());
228   tests.insert(tests.end(), tests3D.begin(), tests3D.end());
229 
230   for (auto& t : tests)
231   {
232     vtkm::Id nx = t[0], ny = t[1], nz = t[2];
233     int nghost = static_cast<int>(t[3]);
234     for (int layer = 0; layer < nghost; layer++)
235     {
236       std::vector<std::string> dsTypes = { "uniform", "rectilinear", "explicit" };
237       for (auto& dsType : dsTypes)
238       {
239         vtkm::cont::DataSet ds;
240         if (dsType == "uniform")
241           ds = MakeUniform(nx, ny, nz, layer);
242         else if (dsType == "rectilinear")
243           ds = MakeRectilinear(nx, ny, nz, layer);
244         else if (dsType == "explicit")
245           ds = MakeExplicit(nx, ny, nz, layer);
246 
247         std::vector<std::string> removeType = { "all", "byType" };
248         for (auto& rt : removeType)
249         {
250           vtkm::filter::GhostCellRemove ghostCellRemoval;
251           ghostCellRemoval.RemoveGhostField();
252 
253           if (rt == "all")
254             ghostCellRemoval.RemoveAllGhost();
255           else if (rt == "byType")
256             ghostCellRemoval.RemoveByType(vtkm::CellClassification::GHOST);
257 
258           auto output = ghostCellRemoval.Execute(ds);
259           vtkm::Id numCells = output.GetNumberOfCells();
260 
261           //Validate the output.
262 
263           vtkm::Id numCellsReq = (nx - 2 * layer) * (ny - 2 * layer);
264           if (nz != 0)
265             numCellsReq *= (nz - 2 * layer);
266 
267           VTKM_TEST_ASSERT(numCellsReq == numCells, "Wrong number of cells in output");
268           if (dsType == "uniform" || dsType == "rectilinear")
269           {
270             if (nz == 0)
271             {
272               VTKM_TEST_ASSERT(output.GetCellSet().IsSameType(vtkm::cont::CellSetStructured<2>()),
273                                "Wrong cell type for explicit conversion");
274             }
275             else if (nz > 0)
276             {
277               VTKM_TEST_ASSERT(output.GetCellSet().IsSameType(vtkm::cont::CellSetStructured<3>()),
278                                "Wrong cell type for explicit conversion");
279             }
280           }
281           else
282           {
283             VTKM_TEST_ASSERT(output.GetCellSet().IsType<vtkm::cont::CellSetExplicit<>>(),
284                              "Wrong cell type for explicit conversion");
285           }
286         }
287 
288         // For structured, test the case where we have a ghost in the 'middle' of the cells.
289         // This will produce an explicit cellset.
290         if (dsType == "uniform" || dsType == "rectilinear")
291         {
292           if (dsType == "uniform")
293             ds = MakeUniform(nx, ny, nz, layer, true);
294           else if (dsType == "rectilinear")
295             ds = MakeRectilinear(nx, ny, nz, layer, true);
296 
297           vtkm::filter::GhostCellRemove ghostCellRemoval;
298           ghostCellRemoval.RemoveGhostField();
299           auto output = ghostCellRemoval.Execute(ds);
300           VTKM_TEST_ASSERT(output.GetCellSet().IsType<vtkm::cont::CellSetExplicit<>>(),
301                            "Wrong cell type for explicit conversion");
302         }
303       }
304     }
305   }
306 }
307 }
308 
UnitTestGhostCellRemove(int argc,char * argv[])309 int UnitTestGhostCellRemove(int argc, char* argv[])
310 {
311   return vtkm::cont::testing::Testing::Run(TestGhostCellRemove, argc, argv);
312 }
313