Permalink
Browse files

Add second strategy for parallel implementation of SampleSurfaceMesh (#…

…835)

This new strategy kicks in when the number of features is less then the number
of cores on the hardware. The alternate strategy parallelizes over the number
of triangle points.

Add a prebuilt pipeline to generate a synthetic tensile specimen with an
equiaxed microstructure.

Signed-off-by: Michael Jackson <mike.jackson@bluequartz.net>
  • Loading branch information...
imikejackson committed Oct 30, 2018
1 parent 6a42d92 commit bb34251252531e8a3dad9f0daf9c7a063a1d34f6
@@ -35,11 +35,17 @@
#include "SampleSurfaceMesh.h"
#include <mutex>
#include <thread>
#include <QtCore/QDateTime>
#ifdef SIMPL_USE_PARALLEL_ALGORITHMS
#include <tbb/blocked_range.h>
#include <tbb/parallel_for.h>
#include <tbb/partitioner.h>
#include <tbb/task_scheduler_init.h>
#include <tbb/tbb_machine.h>
#endif
#include "SIMPLib/Common/Constants.h"
@@ -51,10 +57,89 @@
#include "SIMPLib/Geometry/VertexGeom.h"
#include "SIMPLib/Math/GeometryMath.h"
#include "SIMPLib/Math/SIMPLibRandom.h"
#include "SIMPLib/Utilities/TimeUtilities.h"
#include "Sampling/SamplingConstants.h"
#include "Sampling/SamplingVersion.h"
class SampleSurfaceMeshImplByPoints
{
SampleSurfaceMesh* m_Filter = nullptr;
TriangleGeom::Pointer m_Faces;
Int32Int32DynamicListArray::Pointer m_FaceIds;
VertexGeom::Pointer m_FaceBBs;
VertexGeom::Pointer m_Points;
size_t m_FeatureId = 0;
int32_t* m_PolyIds = nullptr;
public:
SampleSurfaceMeshImplByPoints(SampleSurfaceMesh* filter, TriangleGeom::Pointer faces, Int32Int32DynamicListArray::Pointer faceIds, VertexGeom::Pointer faceBBs, VertexGeom::Pointer points,
size_t featureId, int32_t* polyIds)
: m_Filter(filter)
, m_Faces(faces)
, m_FaceIds(faceIds)
, m_FaceBBs(faceBBs)
, m_Points(points)
, m_FeatureId(featureId)
, m_PolyIds(polyIds)
{
}
virtual ~SampleSurfaceMeshImplByPoints() = default;
void checkPoints(size_t start, size_t end) const
{
float radius = 0.0f;
float distToBoundary = 0.0f;
int64_t numPoints = m_Points->getNumberOfVertices();
FloatArrayType::Pointer llPtr = FloatArrayType::CreateArray(3, "_INTERNAL_USE_ONLY_Lower");
FloatArrayType::Pointer urPtr = FloatArrayType::CreateArray(3, "_INTERNAL_USE_ONLY_Upper_Right");
float* ll = llPtr->getPointer(0);
float* ur = urPtr->getPointer(0);
float* point = nullptr;
char code = ' ';
size_t iter = m_FeatureId;
// find bounding box for current feature
GeometryMath::FindBoundingBoxOfFaces(m_Faces.get(), m_FaceIds->getElementList(iter), ll, ur);
GeometryMath::FindDistanceBetweenPoints(ll, ur, radius);
int64_t pointsVisited = 0;
// check points in vertex array to see if they are in the bounding box of the feature
for(int64_t i = start; i < end; i++)
{
// Check for the filter being cancelled.
if(m_Filter->getCancel())
{
return;
}
point = m_Points->getVertexPointer(i);
if(m_PolyIds[i] == 0 && GeometryMath::PointInBox(point, ll, ur) == true)
{
code = GeometryMath::PointInPolyhedron(m_Faces.get(), m_FaceIds->getElementList(iter), m_FaceBBs.get(), point, ll, ur, radius, distToBoundary);
if(code == 'i' || code == 'V' || code == 'E' || code == 'F')
{
m_PolyIds[i] = iter;
}
}
pointsVisited++;
if(pointsVisited % 1000 == 0)
{
m_Filter->sendThreadSafeProgressMessage(m_FeatureId, 1000, numPoints);
}
}
}
#ifdef SIMPL_USE_PARALLEL_ALGORITHMS
void operator()(const tbb::blocked_range<size_t>& r) const
{
checkPoints(r.begin(), r.end());
}
#endif
private:
};
/**
* @brief The SampleSurfaceMeshImpl class implements a threaded algorithm that samples a surface mesh based on points passed from subclassed Filters.
*/
@@ -77,9 +162,7 @@ class SampleSurfaceMeshImpl
, m_PolyIds(polyIds)
{
}
virtual ~SampleSurfaceMeshImpl()
{
}
virtual ~SampleSurfaceMeshImpl() = default;
void checkPoints(size_t start, size_t end) const
{
@@ -95,7 +178,6 @@ class SampleSurfaceMeshImpl
for(size_t iter = start; iter < end; iter++)
{
// find bounding box for current feature
GeometryMath::FindBoundingBoxOfFaces(m_Faces.get(), m_FaceIds->getElementList(iter), ll, ur);
GeometryMath::FindDistanceBetweenPoints(ll, ur, radius);
@@ -254,11 +336,6 @@ void SampleSurfaceMesh::execute()
DataContainer::Pointer sm = getDataContainerArray()->getDataContainer(m_SurfaceMeshFaceLabelsArrayPath.getDataContainerName());
SIMPL_RANDOMNG_NEW()
#ifdef SIMPL_USE_PARALLEL_ALGORITHMS
tbb::task_scheduler_init init;
bool doParallel = true;
#endif
TriangleGeom::Pointer triangleGeom = sm->getGeometryAs<TriangleGeom>();
// pull down faces
@@ -380,22 +457,75 @@ void SampleSurfaceMesh::execute()
notifyStatusMessage(getMessagePrefix(), getHumanLabel(), "Sampling triangle geometry ...");
#ifdef SIMPL_USE_PARALLEL_ALGORITHMS
if(doParallel == true)
tbb::task_scheduler_init init;
bool doParallel = true;
#endif
// C++11 RIGHT HERE....
unsigned int nthreads = std::thread::hardware_concurrency();
// If the number of featurs is larger than the number of cores to do the work then parallelize over the number of features
// otherwise parallelize over the number of triangle points.
if(numFeatures > nthreads)
{
tbb::parallel_for(tbb::blocked_range<size_t>(0, numFeatures), SampleSurfaceMeshImpl(this, triangleGeom, faceLists, faceBBs, points, polyIds), tbb::auto_partitioner());
#ifdef SIMPL_USE_PARALLEL_ALGORITHMS
if(doParallel == true)
{
tbb::parallel_for(tbb::blocked_range<size_t>(0, numFeatures), SampleSurfaceMeshImpl(this, triangleGeom, faceLists, faceBBs, points, polyIds), tbb::auto_partitioner());
}
else
#endif
{
SampleSurfaceMeshImpl serial(this, triangleGeom, faceLists, faceBBs, points, polyIds);
serial.checkPoints(0, numFeatures);
}
}
else
#endif
{
SampleSurfaceMeshImpl serial(this, triangleGeom, faceLists, faceBBs, points, polyIds);
serial.checkPoints(0, numFeatures);
for(int featureId = 0; featureId < numFeatures; featureId++)
{
m_NumCompleted = 0;
m_StartMillis = QDateTime::currentMSecsSinceEpoch();
m_Millis = m_StartMillis;
size_t numPoints = points->getNumberOfVertices();
#ifdef SIMPL_USE_PARALLEL_ALGORITHMS
if(doParallel == true)
{
tbb::parallel_for(tbb::blocked_range<size_t>(0, numPoints), SampleSurfaceMeshImplByPoints(this, triangleGeom, faceLists, faceBBs, points, featureId, polyIds), tbb::auto_partitioner());
}
else
#endif
{
SampleSurfaceMeshImplByPoints serial(this, triangleGeom, faceLists, faceBBs, points, featureId, polyIds);
serial.checkPoints(0, numPoints);
}
}
}
assign_points(iArray);
notifyStatusMessage(getMessagePrefix(), getHumanLabel(), "Complete");
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void SampleSurfaceMesh::sendThreadSafeProgressMessage(int featureId, size_t numCompleted, size_t totalFeatures)
{
static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
qint64 currentMillis = QDateTime::currentMSecsSinceEpoch();
m_NumCompleted = m_NumCompleted + numCompleted;
if(currentMillis - m_Millis > 1000)
{
float inverseRate = static_cast<float>(currentMillis - m_Millis) / static_cast<float>(m_NumCompleted - m_LastCompletedPoints);
qint64 remainMillis = inverseRate * (totalFeatures - m_NumCompleted);
QString ss = QObject::tr("Feature %3 | Points Completed: %1 of %2").arg(m_NumCompleted).arg(totalFeatures).arg(featureId);
ss = ss + QObject::tr(" || Est. Time Remain: %1").arg(DREAM3D::convertMillisToHrsMinSecs(remainMillis));
notifyStatusMessage(getMessagePrefix(), getHumanLabel(), ss);
m_Millis = QDateTime::currentMSecsSinceEpoch();
m_LastCompletedPoints = m_NumCompleted;
}
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
@@ -125,6 +125,13 @@ class Sampling_EXPORT SampleSurfaceMesh : public AbstractFilter
*/
void preflight() override;
/**
* @brief sendThreadSafeProgressMessage
* @param counter
* @param max
*/
void sendThreadSafeProgressMessage(int featureId, size_t numCompleted, size_t totalFeatures);
signals:
/**
* @brief updateFilterParameters Emitted when the Filter requests all the latest Filter parameters
@@ -175,6 +182,10 @@ class Sampling_EXPORT SampleSurfaceMesh : public AbstractFilter
private:
DEFINE_DATAARRAY_VARIABLE(int32_t, SurfaceMeshFaceLabels)
size_t m_NumCompleted = 0;
qint64 m_StartMillis = 0;
qint64 m_Millis = 0;
int64_t m_LastCompletedPoints = 0;
public:
SampleSurfaceMesh(const SampleSurfaceMesh&) = delete; // Copy Constructor Not Implemented
Oops, something went wrong.

0 comments on commit bb34251

Please sign in to comment.