Commit 89140a2d authored by Sreekanth Arikatla's avatar Sreekanth Arikatla
Browse files

Merge branch 'PhysicsUpdateRefactorFixes' into 'master'

REFAC: Renames and fixes for TaskGraph, graphviz node coloring

See merge request iMSTK/iMSTK!471
parents dbdac854 a3ce98f3
cmake_minimum_required(VERSION 3.9)
project(iMSTK VERSION 2.0.0 LANGUAGES C CXX)
project(iMSTK VERSION 3.0.0 LANGUAGES C CXX)
if(UNIX AND NOT APPLE)
set(LINUX TRUE)
......
......@@ -36,7 +36,7 @@ Setup for Development
=====================
iMSTK and its external dependencies can be configured and built from
scratch Cmake to create a super-build on UNIX (MAC, Linux) and Windows
scratch with Cmake to create a super-build on UNIX (MAC, Linux) and Windows
platforms. The instructions below describe this process in detail.
Configuration and Build
......@@ -1011,7 +1011,7 @@ An example code on how to instantiate a haptic device is shown below
sdk->addModule(server);
Paralle Support
Parallel Support
===============
iMSTK allows CPU based shared memory parallelization using Intel TBB library.
......@@ -1041,6 +1041,99 @@ options to parallelize over a dimension of choice.
Miscellaneous Topics
====================
Task Graphs
------------------
iMSTK provides Task Graphs. These are used internally but may also be used by the user.
A TaskGraph contains a set of TaskNode's. Each node accomplishes some computation.
The TaskGraph also contains edges establishing successor/predeccessor relationships between
the tasks. For example, one could specify that a task may only happen after two others have
completed. Additionally a TaskGraph will always contain a source and sink node.
This TaskGraph may be then executed by the user using one of the TaskGraphControllers.
Currently, there are two provided TaskGraphControllers. SequentialTaskGraphController and
TbbTaskGraphController. Sequential executes the tasks one by one in topological order while
Tbb executes them in parallel.
To use a TaskGraph, create one and begin adding functions/nodes to it. One can either
create a TaskNode or use the overloaded function in TaskGraph to directly supply a function
pointer. Then we can establish edges between the nodes and execute.
::
// Inputs
const int x = 0;
const int y = 2;
const int z = 3;
const int w = 5;
// Results
int a = 0;
int b = 0;
int c = 0;
std::shared_ptr<TaskGraph> graph = std::make_shared<TaskGraph>();
// Setup Nodes
std::shared_ptr<TaskNode> addXYNode = graph->addFunction([&]() { a = x + y; });
std::shared_ptr<TaskNode> multZWNode = graph->addFunction([&]() { b = z * w; });
std::shared_ptr<TaskNode> addABNode = graph->addFunction([&]() { c = a + b; });
// Setup Edges
graph->addEdge(graph->getSource(), addXYNode);
graph->addEdge(graph->getSource(), multZWNode);
graph->addEdge(addXYNode, addABNode);
graph->addEdge(multZWNode, addABNode);
graph->addEdge(addABNode, graph->getSink());
// Finally, execute
std::shared_ptr<TbbTaskGraphController> controller = std::make_shared<TbbTaskGraphController>();
controller->setInput(graph);
controller->init(); // Possible preprocessing steps
controller->execute();
TaskGraphs are also used internally in iMSTK's physics loop. This allows one to reconfigure
iMSTK's sequence of events. The Scene, SceneObject, and AbstractDynamicalModel classes all contain
member TaskGraphs which are composited into each other. To modify the main physics loop one should
modify the top level TaskGraph, that would be the Scene TaskGraph. Keep in mind that the Scene's TaskGraph
is rebuilt on initialize. One can have their own step within initialization like so:
::
scene->setComputeGraphConfigureCallback([&](Scene* scene)
{
// Insert nodes or edges
});
Additionally many of the classes in iMSTK expose getters for their nodes. This is useful, for example,
if one wanted to insert a step after PbdModel does its position integration.
::
std::shared_ptr<PbdModel> pbdModel = clothObj->getPbdModel();
...
scene->setComputeGraphConfigureCallback([&](Scene* scene)
{
std::shared_ptr<ComputeGraph> graph = scene->getComputeGraph();
// A TaskNode to print all velocities
std::shared_ptr<TaskNode> printVelocities = std::make_shared<TaskNode>([&]()
{
const StdVectorOfVec3d& velocities = *pbdModel->getCurrentState()->getVelocities();
for (size_t i = 0; i < velocities.size(); i++)
{
printf("Velocity: %f, %f, %f\n", velocities[i].x(), velocities[i].y(), velocities[i].z());
}
});
// Add to the graph, after positions are integrated
graph->insertAfter(pbdModel->getIntegratePositionNode(), printVelocities);
});
Lastly, the TaskGraph comes with a number of graph functions. Static functions such as sum, nest, topological sort,
transitive reduction, cyclic check, etc. Member functions such as addNode, addFunction, addEdge, insertAfter,
insertBefore, ... The graph sum and nest are especially useful when maintaining multiple decoupled graphs with identical
nodes between them that you would then like to combine.
Object Controllers
------------------
......
......@@ -105,13 +105,9 @@ main()
auto objController = std::make_shared<SceneObjectController>(drill, deviceTracker);
scene->addObjectController(objController);
// Create a collision graph
auto graph = scene->getCollisionGraph();
auto pair = graph->addInteractionPair(bone,
drill,
CollisionDetection::Type::PointSetToSphere,
CollisionHandling::Type::BoneDrilling,
CollisionHandling::Type::None);
// Add interaction
scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(bone, drill,
InteractionType::FemObjToCollidingObjBoneDrilling, CollisionDetection::Type::PointSetToSphere));
#endif
......
......@@ -250,7 +250,7 @@ main()
pbdObjs.push_back(pbdObj);
scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(pbdObj, floorObj,
InteractionType::PbdObjToPbdObj_Collision, CollisionDetection::Type::SurfaceMeshToSurfaceMesh));
InteractionType::PbdObjToPbdObjCollision, CollisionDetection::Type::SurfaceMeshToSurfaceMesh));
}
}
}
......@@ -260,7 +260,7 @@ main()
for (size_t j = i + 1; j < pbdObjs.size(); ++j)
{
scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(pbdObjs[i], pbdObjs[j],
InteractionType::PbdObjToPbdObj_Collision, CollisionDetection::Type::SurfaceMeshToSurfaceMesh));
InteractionType::PbdObjToPbdObjCollision, CollisionDetection::Type::SurfaceMeshToSurfaceMesh));
}
}
......
......@@ -19,18 +19,18 @@
=========================================================================*/
#include "imstkSimulationManager.h"
#include "imstkCollisionGraph.h"
#include "imstkCamera.h"
#include "imstkCollisionGraph.h"
#include "imstkLight.h"
#include "imstkPbdModel.h"
#include "imstkMeshIO.h"
#include "imstkObjectInteractionFactory.h"
#include "imstkOneToOneMap.h"
#include "imstkTetraTriangleMap.h"
#include "imstkSurfaceMesh.h"
#include "imstkPbdModel.h"
#include "imstkScene.h"
#include "imstkComputeGraphVizWriter.h"
#include "imstkObjectInteractionFactory.h"
#include "imstkSimulationManager.h"
#include "imstkSurfaceMesh.h"
#include "imstkTaskGraphVizWriter.h"
#include "imstkTetraTriangleMap.h"
using namespace imstk;
......@@ -160,7 +160,7 @@ main()
// Collision
scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(deformableObj, floor,
InteractionType::PbdObjToPbdObj_Collision, CollisionDetection::Type::MeshToMeshBruteForce));
InteractionType::PbdObjToPbdObjCollision, CollisionDetection::Type::MeshToMeshBruteForce));
// Light
auto light = std::make_shared<DirectionalLight>("light");
......
......@@ -195,7 +195,7 @@ main()
// Collision
scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(pbdDragon1, stairObj,
InteractionType::PbdObjToPbdObj_Collision, CollisionDetection::Type::MeshToMeshBruteForce));
InteractionType::PbdObjToPbdObjCollision, CollisionDetection::Type::MeshToMeshBruteForce));
// Light
auto light = std::make_shared<DirectionalLight>("Light");
......
......@@ -220,7 +220,7 @@ main()
// Collisions
scene->getCollisionGraph()->addInteraction(makeObjectInteractionPair(deformableObj, floor,
InteractionType::PbdObjToPbdObj_Collision, CollisionDetection::Type::MeshToMeshBruteForce));
InteractionType::PbdObjToPbdObjCollision, CollisionDetection::Type::MeshToMeshBruteForce));
// Light (white)
auto whiteLight = std::make_shared<DirectionalLight>("whiteLight");
......
......@@ -108,12 +108,12 @@ main(int argc, char* argv[])
if (std::dynamic_pointer_cast<Plane>(solid->getCollidingGeometry()))
{
collisionGraph->addInteraction(makeObjectInteractionPair(fluidObj, solid,
InteractionType::SphObjToCollidingObj_Collision, CollisionDetection::Type::PointSetToPlane));
InteractionType::SphObjToCollidingObjCollision, CollisionDetection::Type::PointSetToPlane));
}
else if (std::dynamic_pointer_cast<Sphere>(solid->getCollidingGeometry()))
{
collisionGraph->addInteraction(makeObjectInteractionPair(fluidObj, solid,
InteractionType::SphObjToCollidingObj_Collision, CollisionDetection::Type::PointSetToSphere));
InteractionType::SphObjToCollidingObjCollision, CollisionDetection::Type::PointSetToSphere));
}
else
{
......
......@@ -16,17 +16,17 @@
#
###########################################################################
project(Example-ComputeGraphBenchmark)
project(Example-TaskGraphConfigure)
#-----------------------------------------------------------------------------
# Create executable
#-----------------------------------------------------------------------------
imstk_add_executable(${PROJECT_NAME} computeGraphBenchmarkExample.cpp)
imstk_add_executable(${PROJECT_NAME} taskGraphConfigureExample.cpp)
#-----------------------------------------------------------------------------
# Add the target to Examples folder
#-----------------------------------------------------------------------------
SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/ComputeGraph)
SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/TaskGraph)
#-----------------------------------------------------------------------------
# Link libraries to executable
......
......@@ -21,20 +21,14 @@
#include "imstkAPIUtilities.h"
#include "imstkCamera.h"
#include "imstkComputeGraph.h"
#include "imstkComputeGraphVizWriter.h"
#include "imstkLight.h"
#include "imstkParallelReduce.h"
#include "imstkPbdModel.h"
#include "imstkPbdObject.h"
#include "imstkScene.h"
#include "imstkSceneManager.h"
#include "imstkSimulationManager.h"
#include "imstkSurfaceMesh.h"
#include "imstkVTKRenderer.h"
#include "VTKRenderer.h"
#include "vtkRenderWindowInteractor.h"
#include "imstkTaskGraph.h"
#include "imstkTaskGraphVizWriter.h"
using namespace imstk;
......@@ -138,7 +132,7 @@ makeClothObj(const std::string& name, double width, double height, int nRows, in
}
///
/// \brief This example demonstrates how to modify the computational graph, post initialization
/// \brief This example demonstrates how to modify the task graph
///
int
main()
......@@ -175,20 +169,19 @@ main()
// Adds a custom physics step to print out intermediate velocities
{
std::shared_ptr<PbdModel> pbdModel = clothObj->getPbdModel();
scene->setComputeGraphConfigureCallback([&](Scene* scene)
scene->setTaskGraphConfigureCallback([&](Scene* scene)
{
// Get the graph
std::shared_ptr<ComputeGraph> graph = scene->getComputeGraph();
std::shared_ptr<TaskGraph> graph = scene->getTaskGraph();
// First write the graph before we make modifications, just to show the changes
ComputeGraphVizWriter writer;
TaskGraphVizWriter writer;
writer.setInput(graph);
writer.setFileName("computeGraphConfigureExampleOld.svg");
writer.setFileName("taskGraphConfigureExampleOld.svg");
writer.write();
std::shared_ptr<ComputeNode> printVelocities = std::make_shared<ComputeNode>([&]()
std::shared_ptr<TaskNode> printVelocities = std::make_shared<TaskNode>([&]()
{
// Make the timestep a function of max velocity
const StdVectorOfVec3d& velocities = *pbdModel->getCurrentState()->getVelocities();
for (size_t i = 0; i < velocities.size(); i++)
{
......@@ -200,7 +193,7 @@ main()
graph->insertAfter(pbdModel->getIntegratePositionNode(), printVelocities);
// Write the modified graph
writer.setFileName("computeGraphConfigureExampleNew.svg");
writer.setFileName("taskGraphConfigureExampleNew.svg");
writer.write();
});
}
......
......@@ -16,17 +16,17 @@
#
###########################################################################
project(Example-ComputeGraphConfigure)
project(Example-TaskGraph)
#-----------------------------------------------------------------------------
# Create executable
#-----------------------------------------------------------------------------
imstk_add_executable(${PROJECT_NAME} computeGraphConfigureExample.cpp)
imstk_add_executable(${PROJECT_NAME} taskGraphExample.cpp)
#-----------------------------------------------------------------------------
# Add the target to Examples folder
#-----------------------------------------------------------------------------
SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/ComputeGraph)
SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/TaskGraph)
#-----------------------------------------------------------------------------
# Link libraries to executable
......
/*=========================================================================
Library: iMSTK
Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
& Imaging in Medicine, Rensselaer Polytechnic Institute.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.txt
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=========================================================================*/
#include "imstkParallelFor.h"
#include "imstkSequentialTaskGraphController.h"
#include "imstkTaskGraph.h"
#include "imstkTbbTaskGraphController.h"
#include <iostream>
using namespace imstk;
///
/// \brief This example how to use a TaskGraph standalone
///
int
main()
{
const bool runExampleInParallel = true;
// Initialize some data arrays
const int countA = 100;
const int countB = 255;
int x[countA];
int y[countA];
int w[countB];
int z[countB];
for (int i = 0; i < 100; i++)
{
x[i] = i + 5;
y[i] = i * 6 + 1;
}
for (int i = 0; i < 255; i++)
{
w[i] = i % 10;
z[i] = i;
}
int sumA = 0;
int sumB = 0;
// Now create a graph that computes results = sum_i(x_i + y_i) * sum_i(w_i * z_i)
std::shared_ptr<TaskGraph> graph = std::make_shared<TaskGraph>();
// Create and add the nodes
std::shared_ptr<TaskNode> addNode = graph->addFunction("Add Step", [&]()
{
for (int i = 0; i < countA; i++)
{
sumA += (x[i] + y[i]);
}
});
std::shared_ptr<TaskNode> multNode = graph->addFunction("Mult Step", [&]()
{
for (int i = 0; i < countB; i++)
{
sumB += (w[i] * z[i]);
}
});
// Define the edges, add and mult steps will be done in parallel
graph->addEdge(graph->getSource(), addNode);
graph->addEdge(graph->getSource(), multNode);
graph->addEdge(addNode, graph->getSink());
graph->addEdge(multNode, graph->getSink());
// Set which controller to use
std::shared_ptr<TaskGraphController> controller = nullptr;
if (runExampleInParallel)
{
controller = std::make_shared<TbbTaskGraphController>();
}
else
{
controller = std::make_shared<SequentialTaskGraphController>();
}
// Compute
controller->setTaskGraph(graph);
if (!controller->initialize())
{
std::cout << "TaskGraph failed to initialize" << std::endl;
return 1;
}
controller->execute();
std::cout << "Results: " << sumA + sumB << std::endl;
return 0;
}
###########################################################################
#
# Copyright (c) Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0.txt
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
###########################################################################
project(Example-TaskGraphTiming)
#-----------------------------------------------------------------------------
# Create executable
#-----------------------------------------------------------------------------
imstk_add_executable(${PROJECT_NAME} taskGraphTimingExample.cpp)
#-----------------------------------------------------------------------------
# Add the target to Examples folder
#-----------------------------------------------------------------------------
SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/TaskGraph)
#-----------------------------------------------------------------------------
# Link libraries to executable
#-----------------------------------------------------------------------------
target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities)
......@@ -21,27 +21,27 @@ limitations under the License.
#include "imstkAPIUtilities.h"
#include "imstkCamera.h"
#include "imstkComputeGraphVizWriter.h"
#include "imstkLineMesh.h"
#include "imstkPbdModel.h"
#include "imstkPbdObject.h"
#include "imstkScene.h"
#include "imstkSceneManager.h"
#include "imstkSimulationManager.h"
#include "imstkTaskGraphVizWriter.h"
using namespace imstk;
///
/// \brief This examples uses the benchmarking features of the computational graph
/// This allows one to see the elapsed time of every step of iMSTK as well as
/// export the computational graph and show information such as the critical path
/// \brief This examples uses the timing features of the task graph This allows one
/// to see the elapsed time of every step of iMSTK as well as export the computational
/// graph and show information such as the critical path
///
int
main()
{
auto simManager = std::make_shared<SimulationManager>();
auto scene = simManager->createNewScene("PBDString");
scene->getConfig()->benchmarkingEnabled = true;
scene->getConfig()->taskTimingEnabled = true;
// Setup N separate string simulations with varying bend stiffnesses
const unsigned int numStrings = 8;
......@@ -148,11 +148,12 @@ main()
simManager->start();
// Write the graph, highlighting the critical path and putting the completion time in the name
ComputeGraphVizWriter writer;
writer.setInput(scene->getComputeGraph());
writer.setFileName("computeGraphBenchmarkExample.svg");
TaskGraphVizWriter writer;
writer.setInput(scene->getTaskGraph());
writer.setFileName("taskGraphBenchmarkExample.svg");
writer.setHighlightCriticalPath(true);
writer.setWriteTimes(true);
writer.setWriteNodeComputeTimesColor(true);
writer.setWriteNodeComputeTimesText(true);
writer.write();
return 0;
......
......@@ -94,17 +94,20 @@ main()
auto objController = std::make_shared<SceneObjectController>(obj, deviceTracker);
scene->addObjectController(objController);
// Create a collision graph
auto graph = scene->getCollisionGraph();
auto pair = graph->addInteractionPair(planeObj, obj,
CollisionDetection::Type::UnidirectionalPlaneToSphere,
CollisionHandling::Type::None,
CollisionHandling::Type::VirtualCoupling);
// Customize collision handling algorithm
auto colHandlingAlgo = std::dynamic_pointer_cast<VirtualCouplingCH>(pair->getCollisionHandlingB());
colHandlingAlgo->setStiffness(5e-01);
colHandlingAlgo->setDamping(0.005);
{
// Setup CD, and collision data
auto colData = std::make_shared<CollisionData>();
std::shared_ptr<CollisionDetection> colDetect = makeCollisionDetectionObject(CollisionDetection::Type::UnidirectionalPlaneToSphere,
planeObj, obj, colData);
// Setup the handler
auto colHandler = std::make_shared<VirtualCouplingCH>(CollisionHandling::Side::B, colData, planeObj, obj);
colHandler->setStiffness(5e-01);
colHandler->setDamping(0.005);
auto pair = std::make_shared<CollisionPair>(planeObj, obj, colDetect, nullptr, colHandler);
scene->getCollisionGraph()->addInteractionPair(pair);
}
// Camera
auto cam = scene->getCamera();
......
......@@ -21,7 +21,7 @@
#include "imstkCollisionDetection.h"
#include "imstkCollisionData.h"
#include "imstkComputeNode.h"
#include "imstkTaskNode.h"
#include "imstkLogger.h"
#include "imstkOctreeBasedCD.h"
#include "imstkSurfaceMesh.h"
......@@ -30,7 +30,7 @@ namespace imstk
{
CollisionDetection::CollisionDetection(const CollisionDetection::Type& type, std::shared_ptr<CollisionData> colData) : m_type(type),
m_colData((colData == nullptr) ? std::make_shared<CollisionData>() : colData),
m_computeNode(std::make_shared<ComputeNode>(std::bind(&CollisionDetection::computeCollisionData, this), "CollisionDetection"))
m_taskNode(std::make_shared<TaskNode>(std::bind(&CollisionDetection::computeCollisionData, this), "CollisionDetection"))
{
}
......
......@@ -28,9 +28,9 @@ namespace imstk
struct CollisionData;
class CollidingObject;
class ComputeNode;
class OctreeBasedCD;
class Geometry;
class OctreeBasedCD;
class TaskNode;