iMSTK
Interactive Medical Simulation Toolkit
GeometryMapperBenchmark.cpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkCapsule.h"
8 #include "imstkCollisionHandling.h"
9 #include "imstkGeometry.h"
10 #include "imstkMath.h"
11 #include "imstkMeshIO.h"
12 #include "imstkPbdModel.h"
13 #include "imstkPbdModelConfig.h"
14 #include "imstkPbdObject.h"
15 #include "imstkPbdObjectCollision.h"
16 #include "imstkPointSetToCapsuleCD.h"
17 #include "imstkPointwiseMap.h"
18 #include "imstkRbdConstraint.h"
19 #include "imstkScene.h"
20 #include "imstkSphere.h"
21 #include "imstkSurfaceMesh.h"
22 #include "imstkSurfaceMeshToCapsuleCD.h"
23 #include "imstkTetrahedralMesh.h"
24 
25 #include <benchmark/benchmark.h>
26 
27 using namespace imstk;
28 
35 static std::shared_ptr<TetrahedralMesh>
36 makeTetGrid(const Vec3d& size, const Vec3i& dim, const Vec3d& center)
37 {
38  auto prismMesh = std::make_shared<TetrahedralMesh>();
39  auto verticesPtr = std::make_shared<VecDataArray<double, 3>>(dim[0] * dim[1] * dim[2]);
40 
41  VecDataArray<double, 3>& vertices = *verticesPtr.get();
42  const Vec3d dx = size.cwiseQuotient((dim - Vec3i(1, 1, 1)).cast<double>());
43  for (int z = 0; z < dim[2]; z++)
44  {
45  for (int y = 0; y < dim[1]; y++)
46  {
47  for (int x = 0; x < dim[0]; x++)
48  {
49  vertices[x + dim[0] * (y + dim[1] * z)] = Vec3i(x, y, z).cast<double>().cwiseProduct(dx) - size * 0.5 + center;
50  }
51  }
52  }
53 
54  // Add connectivity data
55  auto indicesPtr = std::make_shared<VecDataArray<int, 4>>();
56 
57  VecDataArray<int, 4>& indices = *indicesPtr.get();
58  for (int z = 0; z < dim[2] - 1; z++)
59  {
60  for (int y = 0; y < dim[1] - 1; y++)
61  {
62  for (int x = 0; x < dim[0] - 1; x++)
63  {
64  int cubeIndices[8] =
65  {
66  x + dim[0] * (y + dim[1] * z),
67  (x + 1) + dim[0] * (y + dim[1] * z),
68  (x + 1) + dim[0] * (y + dim[1] * (z + 1)),
69  x + dim[0] * (y + dim[1] * (z + 1)),
70  x + dim[0] * ((y + 1) + dim[1] * z),
71  (x + 1) + dim[0] * ((y + 1) + dim[1] * z),
72  (x + 1) + dim[0] * ((y + 1) + dim[1] * (z + 1)),
73  x + dim[0] * ((y + 1) + dim[1] * (z + 1))
74  };
75 
76  // Alternate the pattern so the edges line up on the sides of each voxel
77  if ((z % 2 ^ x % 2) ^ y % 2)
78  {
79  indices.push_back(Vec4i(cubeIndices[0], cubeIndices[7], cubeIndices[5], cubeIndices[4]));
80  indices.push_back(Vec4i(cubeIndices[3], cubeIndices[7], cubeIndices[2], cubeIndices[0]));
81  indices.push_back(Vec4i(cubeIndices[2], cubeIndices[7], cubeIndices[5], cubeIndices[0]));
82  indices.push_back(Vec4i(cubeIndices[1], cubeIndices[2], cubeIndices[0], cubeIndices[5]));
83  indices.push_back(Vec4i(cubeIndices[2], cubeIndices[6], cubeIndices[7], cubeIndices[5]));
84  }
85  else
86  {
87  indices.push_back(Vec4i(cubeIndices[3], cubeIndices[7], cubeIndices[6], cubeIndices[4]));
88  indices.push_back(Vec4i(cubeIndices[1], cubeIndices[3], cubeIndices[6], cubeIndices[4]));
89  indices.push_back(Vec4i(cubeIndices[3], cubeIndices[6], cubeIndices[2], cubeIndices[1]));
90  indices.push_back(Vec4i(cubeIndices[1], cubeIndices[6], cubeIndices[5], cubeIndices[4]));
91  indices.push_back(Vec4i(cubeIndices[0], cubeIndices[3], cubeIndices[1], cubeIndices[4]));
92  }
93  }
94  }
95  }
96 
97  auto uvCoordsPtr = std::make_shared<VecDataArray<float, 2>>(dim[0] * dim[1] * dim[2]);
98 
99  VecDataArray<float, 2>& uvCoords = *uvCoordsPtr.get();
100  for (int z = 0; z < dim[2]; z++)
101  {
102  for (int y = 0; y < dim[1]; y++)
103  {
104  for (int x = 0; x < dim[0]; x++)
105  {
106  uvCoords[x + dim[0] * (y + dim[1] * z)] = Vec2f(static_cast<float>(x) / dim[0], static_cast<float>(z) / dim[2]) * 3.0;
107  }
108  }
109  }
110 
111  // Ensure correct windings
112  for (int i = 0; i < indices.size(); i++)
113  {
114  if (tetVolume(vertices[indices[i][0]], vertices[indices[i][1]], vertices[indices[i][2]], vertices[indices[i][3]]) < 0.0)
115  {
116  std::swap(indices[i][0], indices[i][2]);
117  }
118  }
119 
120  prismMesh->initialize(verticesPtr, indicesPtr);
121  prismMesh->setVertexTCoords("uvs", uvCoordsPtr);
122 
123  return prismMesh;
124 }
125 
129 static void
130 BM_CopyLoop(benchmark::State& state)
131 {
132  std::shared_ptr<PointSet> parent = std::make_shared<PointSet>();
133  std::shared_ptr<PointSet> child = std::make_shared<PointSet>();
134 
135  const int numPoints = state.range(0);
136 
137  auto parentVerticesPtr = std::make_shared<VecDataArray<double, 3>>(numPoints);
138  auto childVerticesPtr = std::make_shared<VecDataArray<double, 3>>(numPoints);
139 
140  // randomize parent vertices
141  for (int i = 0; i < numPoints; i++)
142  {
143  (*parentVerticesPtr)[i] = Vec3d::Random();
144  }
145  parent->setInitialVertexPositions(parentVerticesPtr);
146  child->setInitialVertexPositions(childVerticesPtr);
147 
148  // Create the map
149 
150  std::vector<std::pair<int, int>> map;
151  for (int i = 0; i < numPoints; i++)
152  {
153  map.push_back({ i, numPoints - i - 1 });
154  }
155 
156  // Copy loop
157  for (auto _ : state)
158  {
159  for (int i = 0; i < numPoints; i++)
160  {
161  (*childVerticesPtr)[map[i].second] = (*parentVerticesPtr)[map[i].first];
162  }
163  }
164 }
165 
166 BENCHMARK(BM_CopyLoop)
167 ->Unit(benchmark::kMicrosecond)
168 ->Name("Copy vertices in loop")
169 ->RangeMultiplier(2)->Range(8, 16 << 10);
170 
171 static void
172 BM_CopyParallel(benchmark::State& state)
173 {
174  std::shared_ptr<PointSet> parent = std::make_shared<PointSet>();
175  std::shared_ptr<PointSet> child = std::make_shared<PointSet>();
176 
177  const int numPoints = state.range(0);
178 
179  auto parentVerticesPtr = std::make_shared<VecDataArray<double, 3>>(numPoints);
180  auto childVerticesPtr = std::make_shared<VecDataArray<double, 3>>(numPoints);
181 
182  // randomize parent vertices
183  for (int i = 0; i < numPoints; i++)
184  {
185  (*parentVerticesPtr)[i] = Vec3d::Random();
186  }
187  parent->setInitialVertexPositions(parentVerticesPtr);
188  child->setInitialVertexPositions(childVerticesPtr);
189 
190  // Create the map
191 
192  std::vector<std::pair<int, int>> map;
193  for (int i = 0; i < numPoints; i++)
194  {
195  map.push_back({ i, numPoints - i - 1 });
196  }
197 
198  VecDataArray<double, 3>& parentVertices = *parentVerticesPtr;
199  VecDataArray<double, 3>& childVertices = *childVerticesPtr;
200 
201  // Copy loop
202  for (auto _ : state)
203  {
204  const int size = map.size();
205  ParallelUtils::parallelFor(map.size(),
206  [&](const size_t idx)
207  {
208  const auto& mapValue = map[idx];
209  childVertices[mapValue.first] = parentVertices[mapValue.second];
210  }, size > 8191);
211  }
212 }
213 
214 BENCHMARK(BM_CopyParallel)
215 ->Unit(benchmark::kMicrosecond)
216 ->Name("Copy vertices in parallel")
217 ->RangeMultiplier(2)->Range(8, 16 << 10);
218 
219 // Run the benchmark
220 BENCHMARK_MAIN();
Compound Geometry.
void push_back(const ValueType &val)
Append the data array to hold the new value, resizes if neccesary.
VecDataArray< U, N > cast()
Templated copy the current array with a new internal data type, does not change the number of compone...