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