31using LabelMap = std::map<int, int>;
33using OptionalLabelPeakIndexMap = boost::optional<LabelMap>;
44OptionalLabelPeakIndexMap createOptionalLabelFilter(
size_t dimensionality,
int emptyLabelId,
47 OptionalLabelPeakIndexMap optionalAllowedLabels;
49 if (filterWorkspace) {
50 if (dimensionality < 3) {
51 throw std::invalid_argument(
"A FilterWorkspace has been given, but the "
52 "dimensionality of the labeled workspace is "
55 LabelMap allowedLabels;
58 for (
int i = 0; i < filterWorkspace->getNumberPeaks(); ++i) {
60 const auto labelIdAtPeakCenter =
static_cast<int>(projection.signalAtPeakCenter(peak));
61 if (labelIdAtPeakCenter > emptyLabelId) {
62 allowedLabels.emplace(labelIdAtPeakCenter, i);
65 optionalAllowedLabels = allowedLabels;
67 return optionalAllowedLabels;
75 size_t workspaceIndex;
76 int faceNormalDimension;
81using ClusterFaces = std::deque<ClusterFace>;
82using VecClusterFaces = std::vector<ClusterFaces>;
90void checkDataPoint(
const size_t &linearIndex,
const double signalValue) {
94 if (std::modf(signalValue, &intPart) != 0.0) {
95 std::stringstream buffer;
96 buffer <<
"Problem at linear index: " << linearIndex <<
" SignalValue is not an integer: " << signalValue
97 <<
" Suggests wrong input IMDHistoWorkspace passed to "
100 throw std::runtime_error(buffer.str());
118 const double &
radius,
const int &
id,
const int &emptyLabelId,
119 const std::vector<size_t> &imageShape, ClusterFaces &localClusterFaces) {
123 for (
auto neighbourLinearIndex : neighbours) {
124 const auto neighbourId =
static_cast<int>(clusterImage->getSignalAt(neighbourLinearIndex));
126 if (neighbourId <= emptyLabelId) {
131 for (
size_t j = 0; j < imageShape.size(); ++j) {
132 if (indexes[j] != neighbourIndexes[j]) {
133 const bool maxEdge = neighbourLinearIndex > linearIndex;
137 face.workspaceIndex = linearIndex;
138 face.faceNormalDimension =
static_cast<int>(j);
139 face.maxEdge = maxEdge;
142 localClusterFaces.emplace_back(face);
160void executeUnFiltered(
IMDIterator *mdIterator, ClusterFaces &localClusterFaces,
Progress &progress,
162 const int emptyLabelId = 0;
166 const auto id =
static_cast<int>(signalValue);
168 if (
id > emptyLabelId) {
172 checkDataPoint(linearIndex, signalValue);
177 findFacesAtIndex(linearIndex, mdIterator, clusterImage,
radius,
id, emptyLabelId, imageShape, localClusterFaces);
179 }
while (mdIterator->
next());
196void executeFiltered(
IMDIterator *mdIterator, ClusterFaces &localClusterFaces,
Progress &progress,
198 PeaksWorkspace_sptr &filterWorkspace,
const OptionalLabelPeakIndexMap &optionalAllowedLabels) {
199 const int emptyLabelId = 0;
203 const auto id =
static_cast<int>(signalValue);
205 auto it = optionalAllowedLabels->find(
id);
206 if (it != optionalAllowedLabels->end()) {
208 if (
id > emptyLabelId) {
213 checkDataPoint(linearIndex, signalValue);
216 const int &peakIndex = it->second;
217 const IPeak &peak = filterWorkspace->getPeak(peakIndex);
218 V3D peakCenter = projection.peakCenter(peak);
222 V3D cellPosition(positionND[0], positionND[1], positionND[2]);
223 double radius = cellPosition.distance(peakCenter);
228 findFacesAtIndex(linearIndex, mdIterator, clusterImage,
radius,
id, emptyLabelId, imageShape,
233 }
while (mdIterator->
next());
259 "An input image workspace consisting of cluster ids.");
263 "Optional filtering peaks workspace. Used to restrict face finding to "
264 "clusters in image which correspond to peaks in the workspace.");
266 declareProperty(
"LimitRows",
true,
"Limit the report output to a maximum number of rows");
270 "The number of neighbours to utilise. Defaults to 100000.");
274 "An output table workspace containing cluster face information.");
277 "Indicates that the output results were truncated if True");
285 const int emptyLabelId = 0;
287 std::vector<size_t> imageShape;
288 const size_t dimensionality = clusterImage->getNumDims();
289 for (
size_t i = 0; i < dimensionality; ++i) {
290 imageShape.emplace_back(clusterImage->getDimension(i)->getNBins());
297 OptionalLabelPeakIndexMap optionalAllowedLabels =
298 createOptionalLabelFilter(dimensionality, emptyLabelId, filterWorkspace, clusterImage);
301 auto mdIterators = clusterImage->createIterators(nThreads);
302 const auto nIterators =
static_cast<int>(mdIterators.size());
303 VecClusterFaces clusterFaces(nIterators);
304 size_t nSteps = 1000;
305 if (optionalAllowedLabels.is_initialized()) {
306 nSteps = optionalAllowedLabels->size();
308 const bool usingFiltering = optionalAllowedLabels.is_initialized();
312 for (
int it = 0; it < nIterators; ++it) {
314 ClusterFaces &localClusterFaces = clusterFaces[it];
315 auto mdIterator = mdIterators[it].get();
317 if (usingFiltering) {
318 executeFiltered(mdIterator, localClusterFaces,
progress, clusterImage, imageShape, filterWorkspace,
319 optionalAllowedLabels);
321 executeUnFiltered(mdIterator, localClusterFaces,
progress, clusterImage, imageShape);
333 out->addColumn(
"int",
"ClusterId");
334 out->addColumn(
"double",
"MDWorkspaceIndex");
335 out->addColumn(
"int",
"FaceNormalDimension");
336 out->addColumn(
"bool",
"MaxEdge");
337 out->addColumn(
"double",
"Radius");
338 size_t totalFaces = 0;
339 for (
int i = 0; i < nIterators; ++i) {
340 const ClusterFaces &localClusterFaces = clusterFaces[i];
342 for (
const auto &clusterFace : localClusterFaces) {
343 if (!limitRows || (out->rowCount() <
size_t(maxRows))) {
345 row << clusterFace.clusterId << double(clusterFace.workspaceIndex) << clusterFace.faceNormalDimension
346 << clusterFace.maxEdge << clusterFace.radius;
352 bool truncatedOutput =
false;
353 if (limitRows && out->rowCount() ==
size_t(maxRows)) {
354 truncatedOutput =
true;
355 std::stringstream buffer;
356 buffer <<
"More faces found than can be reported given the MaximumRows "
357 "limit. Row limit at: "
358 << maxRows <<
" Total faces available: " << totalFaces;
#define DECLARE_ALGORITHM(classname)
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_FOR_NO_WSP_CHECK()
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
This is an interface to an iterator of an IMDWorkspace.
virtual std::vector< size_t > findNeighbourIndexesFaceTouching() const =0
Find neighbouring indexes face touching.
virtual bool next()=0
Advance to the next cell.
virtual signal_t getSignal() const =0
Returns the total signal for this box.
virtual size_t getLinearIndex() const =0
Get the linear index.
Helper class for reporting progress from algorithms.
TableRow represents a row in a TableWorkspace.
A property class for workspaces.
FindClusterFaces : Algorithm to find faces of clusters in an MDHistoWorkspace (image)
void exec() override
Execute the algorithm.
const std::string category() const override
Algorithm's category for identification.
void init() override
Initialize the algorithm's properties.
int version() const override
Algorithm's version for identification.
PeakClusterProjection : Maps peaks onto IMDHistoWorkspaces and returns the signal value at the peak c...
The class PeaksWorkspace stores information about a set of SCD peaks.
Structure describing a single-crystal peak.
BoundedValidator is a validator that requires the values to be between upper or lower bounds,...
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
void warning(const std::string &msg)
Logs at warning level.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
The concrete, templated class for properties.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< IPeaksWorkspace > IPeaksWorkspace_sptr
shared pointer to Mantid::API::IPeaksWorkspace
std::shared_ptr< IMDHistoWorkspace > IMDHistoWorkspace_sptr
shared pointer to Mantid::API::IMDHistoWorkspace
std::shared_ptr< PeaksWorkspace > PeaksWorkspace_sptr
Typedef for a shared pointer to a peaks workspace.
void getIndicesFromLinearIndex(const size_t linear_index, size_t const *const numBins, const size_t numDims, size_t *const out_indices)
Convert an linear index in nDim workspace into vector of loop indexes of nDim depth loop Unsafe (poin...
double signal_t
Typedef for the signal recorded in a MDBox, etc.
@ Input
An input workspace.
@ Output
An output workspace.