7 #include "imstkDataArray.h" 8 #include "imstkImageData.h" 9 #include "imstkLevelSetModel.h" 10 #include "imstkLogger.h" 11 #include "imstkMacros.h" 12 #include "imstkParallelFor.h" 13 #include "imstkTaskGraph.h" 17 LevelSetModel::LevelSetModel() :
18 m_config(
std::make_shared<LevelSetModelConfig>())
24 m_generateVelocitiesBegin = std::make_shared<TaskNode>(
nullptr,
"Compute Velocities Begin");
25 m_generateVelocitiesEnd = std::make_shared<TaskNode>(
nullptr,
"Compute Velocities End");
28 m_evolveQuantitiesNodes.push_back(std::make_shared<TaskNode>(std::bind(&LevelSetModel::evolve,
this),
"Evolve Distances"));
30 m_taskGraph->addNode(m_generateVelocitiesBegin);
31 m_taskGraph->addNode(m_generateVelocitiesEnd);
32 m_taskGraph->addNode(m_evolveQuantitiesNodes.back());
40 LOG(WARNING) <<
"Levelset missing geometry";
44 if (
auto imageData = std::dynamic_pointer_cast<ImageData>(
m_geometry))
46 if (imageData->getScalarType() != IMSTK_DOUBLE)
48 LOG(WARNING) <<
"Levelset only works with double image types";
52 m_mesh = std::make_shared<SignedDistanceField>(imageData);
58 m_forwardGrad.setFunction(m_mesh);
59 m_backwardGrad.setFunction(m_mesh);
60 m_curvature.setFunction(m_mesh);
62 if (
auto sdf = std::dynamic_pointer_cast<SignedDistanceField>(m_mesh))
64 std::shared_ptr<ImageData> sdfImage = sdf->getImage();
65 if (!m_config->m_sparseUpdate)
67 m_gradientMagnitudes = std::make_shared<ImageData>();
68 m_gradientMagnitudes->allocate(IMSTK_DOUBLE, 2, sdfImage->getDimensions(), sdfImage->getSpacing(), sdfImage->getOrigin());
73 m_velocities = std::make_shared<ImageData>();
74 m_velocities->allocate(IMSTK_DOUBLE, 1, sdfImage->getDimensions(), sdfImage->getSpacing(), sdfImage->getOrigin());
77 const Vec3d actualSpacing = sdf->getImage()->getSpacing();
78 m_forwardGrad.setDx(Vec3i(1, 1, 1), actualSpacing);
79 m_backwardGrad.setDx(Vec3i(1, 1, 1), actualSpacing);
80 m_curvature.setDx(Vec3i(1, 1, 1), actualSpacing);
83 m_nodeUpdatePool.resize(5000);
84 noteUpdatePoolSize = 0;
92 LOG_IF(FATAL, (!this->
getModelGeometry())) <<
"LevelSetModel::configure - Set LevelSetModel geometry before configuration!";
98 LevelSetModel::evolve()
101 auto imageData = std::dynamic_pointer_cast<
ImageData>(sdf->getImage());
102 double* imgPtr =
static_cast<double*
>(imageData->getVoidPointer());
104 const double dt = m_config->m_dt / m_config->m_substeps;
107 if (m_config->m_sparseUpdate)
110 if (m_nodesToUpdate.size() == 0)
116 std::vector<size_t> baseIndexToImageIndex;
117 baseIndexToImageIndex.reserve(m_nodesToUpdate.size());
118 for (std::unordered_map<
size_t, std::tuple<Vec3i, double>>::iterator iter = m_nodesToUpdate.begin(); iter != m_nodesToUpdate.end(); iter++)
120 baseIndexToImageIndex.push_back(iter->first);
123 DISABLE_WARNING_PADDING
126 const double constantVel = m_config->m_constantVelocity;
127 std::tuple<size_t, Vec3i, double, Vec2d> val;
128 for (
int j = 0; j < m_config->m_substeps; j++)
130 ParallelUtils::parallelFor(baseIndexToImageIndex.size(), [&](
const size_t i)
132 std::tuple<size_t, Vec3i, double, Vec2d, double>& outputVal = m_nodeUpdatePool[i];
133 const size_t& index = std::get<0>(outputVal) = baseIndexToImageIndex[i];
135 std::tuple<Vec3i, double>& inputVal = m_nodesToUpdate[index];
137 const Vec3i& coords = std::get<1>(outputVal) = std::get<0>(inputVal);
138 std::get<2>(outputVal) = std::get<1>(inputVal);
141 const Vec3d gradPos = m_forwardGrad(Vec3d(coords[0], coords[1], coords[2]));
142 const Vec3d gradNeg = m_backwardGrad(Vec3d(coords[0], coords[1], coords[2]));
144 Vec3d gradNegMax = gradNeg.cwiseMax(0.0);
145 Vec3d gradNegMin = gradNeg.cwiseMin(0.0);
146 Vec3d gradPosMax = gradPos.cwiseMax(0.0);
147 Vec3d gradPosMin = gradPos.cwiseMin(0.0);
150 gradNegMax = gradNegMax.cwiseProduct(gradNegMax);
151 gradNegMin = gradNegMin.cwiseProduct(gradNegMin);
152 gradPosMax = gradPosMax.cwiseProduct(gradPosMax);
153 gradPosMin = gradPosMin.cwiseProduct(gradPosMin);
155 const double posMag =
156 gradNegMax[0] + gradNegMax[1] + gradNegMax[2] +
157 gradPosMin[0] + gradPosMin[1] + gradPosMin[2];
159 const double negMag =
160 gradNegMin[0] + gradNegMin[1] + gradNegMin[2] +
161 gradPosMax[0] + gradPosMax[1] + gradPosMax[2];
163 std::get<3>(outputVal) = Vec2d(negMag, posMag);
167 }, baseIndexToImageIndex.size() > 50);
170 ParallelUtils::parallelFor(baseIndexToImageIndex.size(), [&](
const size_t& i)
172 const size_t index = std::get<0>(m_nodeUpdatePool[i]);
173 const double vel = std::get<2>(m_nodeUpdatePool[i]) + constantVel;
174 const Vec2d& g = std::get<3>(m_nodeUpdatePool[i]);
180 imgPtr[index] += dt * (vel * std::sqrt(g[0]) );
185 imgPtr[index] += dt * (vel * std::sqrt(g[1]) );
187 }, noteUpdatePoolSize > m_maxVelocitiesParallel);
190 m_nodesToUpdate.clear();
195 double* gradientMagPtr =
static_cast<double*
>(m_gradientMagnitudes->getScalars()->getVoidPointer());
197 double* velocityMagPtr =
static_cast<double*
>(m_velocities->getScalars()->getVoidPointer());
200 ParallelUtils::parallelFor(dim[2],
203 int i = z * dim[0] * dim[1];
204 for (
int y = 0; y < dim[1]; y++)
206 for (
int x = 0; x < dim[0]; x++, i++)
209 const Vec3d gradPos = m_forwardGrad(Vec3d(x, y, z));
210 const Vec3d gradNeg = m_backwardGrad(Vec3d(x, y, z));
213 Vec3d gradNegMax = gradNeg.cwiseMax(0.0);
214 Vec3d gradNegMin = gradNeg.cwiseMin(0.0);
215 Vec3d gradPosMax = gradPos.cwiseMax(0.0);
216 Vec3d gradPosMin = gradPos.cwiseMin(0.0);
219 gradNegMax = gradNegMax.cwiseProduct(gradNegMax);
220 gradNegMin = gradNegMin.cwiseProduct(gradNegMin);
221 gradPosMax = gradPosMax.cwiseProduct(gradPosMax);
222 gradPosMin = gradPosMin.cwiseProduct(gradPosMin);
225 gradientMagPtr[i * 2 + 1] =
226 gradNegMax[0] + gradNegMax[1] + gradNegMax[2] +
227 gradPosMin[0] + gradPosMin[1] + gradPosMin[2];
230 gradientMagPtr[i * 2] =
231 gradNegMin[0] + gradNegMin[1] + gradNegMin[2] +
232 gradPosMax[0] + gradPosMax[1] + gradPosMax[2];
237 const double constantVel = m_config->m_constantVelocity;
238 ParallelUtils::parallelFor(dim[0] * dim[1] * dim[2],
241 const double vel = constantVel + velocityMagPtr[i];
243 if (constantVel > 0.0)
245 imgPtr[i] += dt * (vel * std::sqrt(gradientMagPtr[i * 2]) );
248 else if (constantVel < 0.0)
250 imgPtr[i] += dt * (vel * std::sqrt(gradientMagPtr[i * 2 + 1]) );
260 auto imageData = std::dynamic_pointer_cast<
ImageData>(sdf->getImage());
263 if (coord[0] >= 0 && coord[0] < dim[0]
264 && coord[1] >= 0 && coord[1] < dim[1]
265 && coord[2] >= 0 && coord[2] < dim[2])
267 const size_t index = coord[0] + coord[1] * dim[0] + coord[2] * dim[0] * dim[1];
268 if (m_config->m_sparseUpdate)
270 if (m_nodesToUpdate.count(index) > 0)
272 m_nodesToUpdate[index] = std::tuple<Vec3i, double>(coord, std::max(std::get<1>(m_nodesToUpdate[index]), f));
276 m_nodesToUpdate[index] = std::tuple<Vec3i, double>(coord, f);
281 double* velocitiesPtr =
static_cast<double*
>(m_velocities->getScalars()->getVoidPointer());
282 velocitiesPtr[index] = std::max(velocitiesPtr[index], f);
291 auto imageData = std::dynamic_pointer_cast<
ImageData>(sdf->getImage());
294 if (coord[0] >= 0 && coord[0] < dim[0]
295 && coord[1] >= 0 && coord[1] < dim[1]
296 && coord[2] >= 0 && coord[2] < dim[2])
298 const size_t index = coord[0] + coord[1] * dim[0] + coord[2] * dim[0] * dim[1];
299 if (m_config->m_sparseUpdate)
301 m_nodesToUpdate[index] = std::tuple<Vec3i, double>(coord, f);
305 double* velocitiesPtr =
static_cast<double*
>(m_velocities->getScalars()->getVoidPointer());
306 velocitiesPtr[index] = f;
315 LOG(WARNING) <<
"LevelSetModel cannot reset";
321 m_taskGraph->addEdge(source, m_generateVelocitiesBegin);
322 m_taskGraph->addEdge(m_generateVelocitiesBegin, m_generateVelocitiesEnd);
325 for (
size_t i = 0; i < m_evolveQuantitiesNodes.size(); i++)
327 m_taskGraph->addEdge(m_generateVelocitiesEnd, m_evolveQuantitiesNodes[i]);
328 m_taskGraph->addEdge(m_evolveQuantitiesNodes[i], sink);
void setImpulse(const Vec3i &coord, double f)
Set the impulse in the velocity field, replaces.
void configure(std::shared_ptr< LevelSetModelConfig > config)
Configure the model.
void resetToInitialState() override
Reset the current state to the initial state.
std::shared_ptr< Geometry > getModelGeometry() const
Gets the model geometry.
const Vec3i & getDimensions() const
Returns the dimensions of the image.
void addImpulse(const Vec3i &coord, double f)
Add an impulse to the velocity field of the levelset This actually takes the max of the current and p...
bool initialize() override
Initialize the LevelSet model.
std::set< std::string > m_validGeometryTypes
Valid geometry types of this model.
Structured field of signed distances implemented with ImageData The SDF differs in that when you scal...
Class that can represent the geometry of multiple implicit geometries as boolean functions One may su...
std::shared_ptr< Geometry > m_geometry
Physics geometry of the model.
Class to represent 1, 2, or 3D image data (i.e. structured points)
void initGraphEdges()
Initializes the edges of the graph.