Skip to content

Commit

Permalink
refs #9428. Basic algorithm with tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
OwenArnold committed May 8, 2014
1 parent 9c1a438 commit 25a5ca6
Show file tree
Hide file tree
Showing 6 changed files with 313 additions and 39 deletions.
3 changes: 3 additions & 0 deletions Code/Mantid/Framework/Crystal/CMakeLists.txt
Expand Up @@ -13,6 +13,7 @@ set ( SRC_FILES
src/DiffPeaksWorkspaces.cpp
src/DisjointElement.cpp
src/FilterPeaks.cpp
src/FindClusterFaces.cpp
src/FindSXPeaks.cpp
src/FindUBUsingFFT.cpp
src/FindUBUsingIndexedPeaks.cpp
Expand Down Expand Up @@ -79,6 +80,7 @@ set ( INC_FILES
inc/MantidCrystal/DiffPeaksWorkspaces.h
inc/MantidCrystal/DisjointElement.h
inc/MantidCrystal/FilterPeaks.h
inc/MantidCrystal/FindClusterFaces.h
inc/MantidCrystal/FindSXPeaks.h
inc/MantidCrystal/FindUBUsingFFT.h
inc/MantidCrystal/FindUBUsingIndexedPeaks.h
Expand Down Expand Up @@ -145,6 +147,7 @@ set ( TEST_FILES
DiffPeaksWorkspacesTest.h
DisjointElementTest.h
FilterPeaksTest.h
FindClusterFacesTest.h
FindSXPeaksTest.h
FindUBUsingFFTTest.h
FindUBUsingIndexedPeaksTest.h
Expand Down
56 changes: 56 additions & 0 deletions Code/Mantid/Framework/Crystal/inc/MantidCrystal/FindClusterFaces.h
@@ -0,0 +1,56 @@
#ifndef MANTID_CRYSTAL_FINDCLUSTERFACES_H_
#define MANTID_CRYSTAL_FINDCLUSTERFACES_H_

#include "MantidKernel/System.h"
#include "MantidAPI/Algorithm.h"

namespace Mantid
{
namespace Crystal
{

/** FindClusterFaces : TODO: DESCRIPTION
Copyright © 2014 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory
This file is part of Mantid.
Mantid is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Mantid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
File change history is stored at: <https://github.com/mantidproject/mantid>
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
class DLLExport FindClusterFaces : public API::Algorithm
{
public:
FindClusterFaces();
virtual ~FindClusterFaces();

virtual const std::string name() const;
virtual int version() const;
virtual const std::string category() const;

private:
virtual void initDocs();
void init();
void exec();


};


} // namespace Crystal
} // namespace Mantid

#endif /* MANTID_CRYSTAL_FINDCLUSTERFACES_H_ */
136 changes: 136 additions & 0 deletions Code/Mantid/Framework/Crystal/src/FindClusterFaces.cpp
@@ -0,0 +1,136 @@
/*WIKI*
TODO: Enter a full wiki-markup description of your algorithm here. You can then use the Build/wiki_maker.py script to generate your full wiki page.
*WIKI*/

#include "MantidCrystal/FindClusterFaces.h"

#include "MantidKernel/Utils.h"
#include "MantidAPI/IMDHistoWorkspace.h"
#include "MantidAPI/ITableWorkspace.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidAPI/IMDIterator.h"
#include "MantidAPI/TableRow.h"

using namespace Mantid::Kernel;
using namespace Mantid::API;

namespace Mantid
{
namespace Crystal
{

// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(FindClusterFaces)



//----------------------------------------------------------------------------------------------
/** Constructor
*/
FindClusterFaces::FindClusterFaces()
{
}

//----------------------------------------------------------------------------------------------
/** Destructor
*/
FindClusterFaces::~FindClusterFaces()
{
}


//----------------------------------------------------------------------------------------------
/// Algorithm's name for identification. @see Algorithm::name
const std::string FindClusterFaces::name() const { return "FindClusterFaces";};

/// Algorithm's version for identification. @see Algorithm::version
int FindClusterFaces::version() const { return 1;};

/// Algorithm's category for identification. @see Algorithm::category
const std::string FindClusterFaces::category() const { return "Crystal";}

//----------------------------------------------------------------------------------------------
/// Sets documentation strings for this algorithm
void FindClusterFaces::initDocs()
{
this->setWikiSummary("Find faces for clusters in a cluster image.");
this->setOptionalMessage(this->getWikiSummary());
}

//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void FindClusterFaces::init()
{
declareProperty(new WorkspaceProperty<IMDHistoWorkspace>("InputWorkspace","",Direction::Input), "An input image workspace consisting of cluster ids.");
declareProperty(new WorkspaceProperty<ITableWorkspace>("OutputWorkspace","",Direction::Output), "An output table workspace containing cluster face information.");
}

//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void FindClusterFaces::exec()
{
IMDHistoWorkspace_sptr clusterImage = getProperty("InputWorkspace");
const int emptyLabelId = 0;

auto out = WorkspaceFactory::Instance().createTable("TableWorkspace");
out->addColumn("int", "ClusterId");
out->addColumn("double", "MDWorkspaceIndex");
out->addColumn("int", "FaceNormalDimension");
out->addColumn("bool", "MaxEdge");

std::vector<size_t> imageShape;
for(size_t i = 0; i < clusterImage->getNumDims(); ++i)
{
imageShape.push_back( clusterImage->getDimension(i)->getNBins() );
}

auto mdIterator = clusterImage->createIterator(NULL);
do
{
int id = static_cast<int>(mdIterator->getSignal());
if(id > emptyLabelId)
{
// Add index to cluster id map.
const size_t linearIndex = mdIterator->getLinearIndex();
std::vector<size_t> indexes;
Kernel::Utils::getIndicesFromLinearIndex(linearIndex, imageShape, indexes);

const auto neighbours = mdIterator->findNeighbourIndexes();
for(size_t i = 0; i < neighbours.size(); ++i)
{
size_t neighbourLinearIndex = neighbours[i];
const int neighbourId = clusterImage->getSignalAt(neighbourLinearIndex);
if(neighbourId <= emptyLabelId)
{
// We have an edge!

// In which dimension is the edge?
std::vector<size_t> neighbourIndexes;
Kernel::Utils::getIndicesFromLinearIndex(neighbourLinearIndex, imageShape, neighbourIndexes);
for(size_t j = 0; j < imageShape.size(); ++j)
{
if(indexes[j] != neighbourIndexes[j])
{
bool maxEdge = neighbourLinearIndex > linearIndex;

TableRow row = out->appendRow();
row << int(id) << double(linearIndex) << int(j) << maxEdge;
}
}
}
}
}

}
while(mdIterator->next());


setProperty("OutputWorkspace", out);
}



} // namespace Crystal
} // namespace Mantid
Expand Up @@ -15,6 +15,7 @@
#include "MantidCrystal/BackgroundStrategy.h"
#include "MantidCrystal/HardThresholdBackground.h"
#include "MantidTestHelpers/MDEventsTestHelper.h"
#include "MockObjects.h"

using namespace Mantid::Crystal;
using namespace Mantid::API;
Expand Down Expand Up @@ -57,20 +58,6 @@ class ConnectedComponentLabelingTest: public CxxTest::TestSuite
{
private:

// Mock Background strategy
class MockBackgroundStrategy: public BackgroundStrategy
{
public:
MOCK_CONST_METHOD1(configureIterator, void(Mantid::API::IMDIterator* const));
MOCK_CONST_METHOD1(isBackground, bool(Mantid::API::IMDIterator* const));
MockBackgroundStrategy* clone() const
{
throw std::runtime_error("Cannot clone the mock object");
}
virtual ~MockBackgroundStrategy()
{}
};

const size_t m_emptyLabel;

public:
Expand Down
78 changes: 78 additions & 0 deletions Code/Mantid/Framework/Crystal/test/FindClusterFacesTest.h
@@ -0,0 +1,78 @@
#ifndef MANTID_CRYSTAL_FINDCLUSTERFACESTEST_H_
#define MANTID_CRYSTAL_FINDCLUSTERFACESTEST_H_

#include <cxxtest/TestSuite.h>

#include "MantidCrystal/FindClusterFaces.h"
#include "MantidTestHelpers/MDEventsTestHelper.h"

using namespace Mantid::API;
using namespace Mantid::MDEvents;
using Mantid::Crystal::FindClusterFaces;

class FindClusterFacesTest: public CxxTest::TestSuite
{
public:
// This pair of boilerplate methods prevent the suite being created statically
// This means the constructor isn't called when running other tests
static FindClusterFacesTest *createSuite()
{
return new FindClusterFacesTest();
}
static void destroySuite(FindClusterFacesTest *suite)
{
delete suite;
}

void test_Init()
{
FindClusterFaces alg;
TS_ASSERT_THROWS_NOTHING( alg.initialize())
TS_ASSERT( alg.isInitialized())
}

ITableWorkspace_sptr doExecute(IMDHistoWorkspace_sptr& inWS)
{
FindClusterFaces alg;
alg.setRethrows(true);
alg.setChild(true);
alg.initialize();
alg.setProperty("InputWorkspace", inWS);
alg.setPropertyValue("OutputWorkspace", "dummy_value");
alg.execute();
ITableWorkspace_sptr outWS = alg.getProperty("OutputWorkspace");
return outWS;
}

void test_find_no_edges_1D()
{
IMDHistoWorkspace_sptr inWS = MDEventsTestHelper::makeFakeMDHistoWorkspace(1, 1, 3); // Makes a 1 by 3 md ws with identical signal values.

ITableWorkspace_const_sptr outWS = doExecute(inWS);

TSM_ASSERT_EQUALS("There are no edge faces", outWS->rowCount(), 0);
}

void test_find_one_edges_1D()
{
IMDHistoWorkspace_sptr inWS = MDEventsTestHelper::makeFakeMDHistoWorkspace(1, 1, 3); // Makes a 1 by 3 md ws with identical signal values.
inWS->setSignalAt(2, 0); // Now we have a single edge!

ITableWorkspace_sptr outWS = doExecute(inWS);

TSM_ASSERT_EQUALS("One face should be identified", outWS->rowCount(), 1);

auto clusterId = outWS->cell<int>(0, 0);
auto wsIndex = outWS->cell<double>(0, 1);
auto normalDimension = outWS->cell<int>(0, 2);
auto max = outWS->cell<Mantid::API::Boolean>(0, 3);

TSM_ASSERT_EQUALS("Wrong clusterId", 1, clusterId);
TSM_ASSERT_EQUALS("Wrong workspace index", 1, wsIndex);
TSM_ASSERT_EQUALS("Wrong normal dimension", 0, normalDimension);
TSM_ASSERT_EQUALS("Wrong max min. Face is greater than current liner index.", true, max);
}

};

#endif /* MANTID_CRYSTAL_FINDCLUSTERFACESTEST_H_ */

0 comments on commit 25a5ca6

Please sign in to comment.