Skip to content

Commit

Permalink
Merge pull request #249 from mantidproject/11125_copy_detector_mappin…
Browse files Browse the repository at this point in the history
…g_algorithm

Copy spectra-detector mapping algorithm
  • Loading branch information
raquelalvarezbanos committed Mar 2, 2015
2 parents 9315e6c + aa32d36 commit ff99c4e
Show file tree
Hide file tree
Showing 9 changed files with 331 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ class MANTID_API_DLL SpectrumDetectorMapping {
typedef boost::unordered_map<specid_t, std::set<detid_t>> sdmap;

public:
explicit SpectrumDetectorMapping(const MatrixWorkspace *const workspace);
explicit SpectrumDetectorMapping(const MatrixWorkspace *const workspace,
bool useSpecNoIndex = true);
SpectrumDetectorMapping(
const std::vector<specid_t> &spectrumNumbers,
const std::vector<detid_t> &detectorIDs,
Expand All @@ -67,7 +68,10 @@ class MANTID_API_DLL SpectrumDetectorMapping {
std::set<specid_t> getSpectrumNumbers() const;
const std::set<detid_t> &
getDetectorIDsForSpectrumNo(const specid_t spectrumNo) const;
const std::set<detid_t> &
getDetectorIDsForSpectrumIndex(const size_t index) const;
const sdmap &getMapping() const;
bool indexIsSpecNumber() const;

private:
void fillMapFromArray(const specid_t *const spectrumNumbers,
Expand All @@ -77,6 +81,7 @@ class MANTID_API_DLL SpectrumDetectorMapping {
const std::vector<detid_t> &detectorIDs,
const std::vector<detid_t> &ignoreDetIDs);

bool m_indexIsSpecNo;
/// The mapping of a spectrum number to zero or more detector IDs
sdmap m_mapping;
};
Expand Down
8 changes: 6 additions & 2 deletions Code/Mantid/Framework/API/src/MatrixWorkspace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,12 @@ void MatrixWorkspace::updateSpectraUsing(const SpectrumDetectorMapping &map) {
for (size_t j = 0; j < getNumberHistograms(); ++j) {
auto spec = getSpectrum(j);
try {
spec->setDetectorIDs(
map.getDetectorIDsForSpectrumNo(spec->getSpectrumNo()));
if(map.indexIsSpecNumber())
spec->setDetectorIDs(
map.getDetectorIDsForSpectrumNo(spec->getSpectrumNo()));
else
spec->setDetectorIDs(
map.getDetectorIDsForSpectrumIndex(j));
} catch (std::out_of_range &e) {
// Get here if the spectrum number is not in the map.
spec->clearDetectorIDs();
Expand Down
30 changes: 26 additions & 4 deletions Code/Mantid/Framework/API/src/SpectrumDetectorMapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,23 @@ namespace API {
* @throws std::invalid_argument if a null workspace pointer is passed in
*/
SpectrumDetectorMapping::SpectrumDetectorMapping(
const MatrixWorkspace *const workspace) {
const MatrixWorkspace *const workspace,
bool useSpecNoIndex): m_indexIsSpecNo(useSpecNoIndex) {
if (!workspace) {
throw std::invalid_argument(
"SpectrumDetectorMapping: Null workspace pointer passed");
}

for (size_t i = 0; i < workspace->getNumberHistograms(); ++i) {
auto spectrum = workspace->getSpectrum(i);
m_mapping[spectrum->getSpectrumNo()] = spectrum->getDetectorIDs();

int index;
if(m_indexIsSpecNo)
index = spectrum->getSpectrumNo();
else
index = static_cast<int>(i);

m_mapping[index] = spectrum->getDetectorIDs();
}
}

Expand All @@ -28,7 +36,8 @@ SpectrumDetectorMapping::SpectrumDetectorMapping(
SpectrumDetectorMapping::SpectrumDetectorMapping(
const std::vector<specid_t> &spectrumNumbers,
const std::vector<detid_t> &detectorIDs,
const std::vector<detid_t> &ignoreDetIDs) {
const std::vector<detid_t> &ignoreDetIDs):
m_indexIsSpecNo(true) {
if (spectrumNumbers.size() != detectorIDs.size()) {
throw std::invalid_argument("SpectrumDetectorMapping: Different length "
"spectrum number & detector ID array passed");
Expand All @@ -43,7 +52,7 @@ SpectrumDetectorMapping::SpectrumDetectorMapping(
*/
SpectrumDetectorMapping::SpectrumDetectorMapping(
const specid_t *const spectrumNumbers, const detid_t *const detectorIDs,
size_t arrayLengths) {
size_t arrayLengths): m_indexIsSpecNo(true) {
if (spectrumNumbers == NULL || detectorIDs == NULL) {
throw std::invalid_argument(
"SpectrumDetectorMapping: Null array pointer passed");
Expand Down Expand Up @@ -93,13 +102,26 @@ std::set<specid_t> SpectrumDetectorMapping::getSpectrumNumbers() const {

const std::set<detid_t> &SpectrumDetectorMapping::getDetectorIDsForSpectrumNo(
const specid_t spectrumNo) const {
if(!m_indexIsSpecNo)
throw std::runtime_error("Indicies are in spectrum index, not number.");
return m_mapping.at(spectrumNo);
}

const std::set<detid_t> &SpectrumDetectorMapping::getDetectorIDsForSpectrumIndex(
const size_t spectrumIndex) const {
if(m_indexIsSpecNo)
throw std::runtime_error("Indicies are in spectrum number, not index.");
return m_mapping.at(static_cast<int>(spectrumIndex));
}

const SpectrumDetectorMapping::sdmap &
SpectrumDetectorMapping::getMapping() const {
return m_mapping;
}

bool SpectrumDetectorMapping::indexIsSpecNumber() const {
return m_indexIsSpecNo;
}

} // namespace API
} // namespace Mantid
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class SpectrumDetectorMappingTest : public CxxTest::TestSuite

void test_getDetectorIDsForSpectrumNo()
{
auto ws = boost::make_shared<WorkspaceTester>();
MatrixWorkspace_sptr ws = boost::make_shared<WorkspaceTester>();
SpectrumDetectorMapping map(ws.get());
// The happy path is tested in the methods above. Just test invalid entry here.
TS_ASSERT_THROWS( map.getDetectorIDsForSpectrumNo(1), std::out_of_range );
Expand Down
3 changes: 3 additions & 0 deletions Code/Mantid/Framework/Algorithms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ set ( SRC_FILES
src/ConvertToMatrixWorkspace.cpp
src/ConvertToPointData.cpp
src/ConvertUnits.cpp
src/CopyDetectorMapping.cpp
src/CopyInstrumentParameters.cpp
src/CopyLogs.cpp
src/CopySample.cpp
Expand Down Expand Up @@ -306,6 +307,7 @@ set ( INC_FILES
inc/MantidAlgorithms/ConvertToMatrixWorkspace.h
inc/MantidAlgorithms/ConvertToPointData.h
inc/MantidAlgorithms/ConvertUnits.h
inc/MantidAlgorithms/CopyDetectorMapping.h
inc/MantidAlgorithms/CopyInstrumentParameters.h
inc/MantidAlgorithms/CopyLogs.h
inc/MantidAlgorithms/CopySample.h
Expand Down Expand Up @@ -571,6 +573,7 @@ set ( TEST_FILES
ConvertToMatrixWorkspaceTest.h
ConvertToPointDataTest.h
ConvertUnitsTest.h
CopyDetectorMappingTest.h
CopyInstrumentParametersTest.h
CopyLogsTest.h
CopySampleTest.h
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#ifndef MANTID_ALGORITHMS_COPYDETECTORMAPPING_H_
#define MANTID_ALGORITHMS_COPYDETECTORMAPPING_H_

//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAPI/Algorithm.h"

namespace Mantid {
namespace Algorithms {

/**
Algorithm to copy spectra-detector mapping from one matrix workspace
to another.
@author Dan Nixon
Copyright &copy; 2010 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
National Laboratory & European Spallation Source
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 CopyDetectorMapping : public API::Algorithm {
public:
/// (Empty) Constructor
CopyDetectorMapping() : API::Algorithm() {}
/// Virtual destructor
virtual ~CopyDetectorMapping() {}
/// Algorithm's name
virtual const std::string name() const { return "CopyDetectorMapping"; }
/// Summary of algorithms purpose
virtual const std::string summary() const {
return "Copies spectra to detector mapping from one Matrix Workspace to another.";
}

/// Algorithm's version
virtual int version() const { return (1); }
/// Algorithm's category for identification
virtual const std::string category() const {
return "DataHandling";
}

/// Input property validation
virtual std::map<std::string, std::string> validateInputs();

private:
/// Initialisation code
void init();
/// Execution code
void exec();
};

} // namespace Algorithms
} // namespace Mantid

#endif /*MANTID_ALGORITHMS_COPYDETECTORMAPPING_H_*/
71 changes: 71 additions & 0 deletions Code/Mantid/Framework/Algorithms/src/CopyDetectorMapping.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAlgorithms/CopyDetectorMapping.h"
#include "MantidAPI/SpectrumDetectorMapping.h"

namespace Mantid {
namespace Algorithms {

DECLARE_ALGORITHM(CopyDetectorMapping)

using namespace Kernel;
using namespace API;

void CopyDetectorMapping::init() {
declareProperty(new WorkspaceProperty<MatrixWorkspace>("WorkspaceToMatch", "",
Direction::Input));

declareProperty(new WorkspaceProperty<MatrixWorkspace>("WorkspaceToRemap", "",
Direction::InOut));

declareProperty(
new PropertyWithValue<bool>("IndexBySpectrumNumber", false,
Direction::Input),
"Will use mapping indexed by spectrum number rather than the default of"
"spectrum index (recommended when both workspaces have a vertical axis "
"in spectrum number).");
}

void CopyDetectorMapping::exec() {
MatrixWorkspace_const_sptr wsToMatch = getProperty("WorkspaceToMatch");
MatrixWorkspace_sptr wsToRemap = getProperty("WorkspaceToRemap");
bool indexBySpecNumber = getProperty("IndexBySpectrumNumber");

// Copy detector mapping
SpectrumDetectorMapping detMap(wsToMatch.get(), indexBySpecNumber);
wsToRemap->updateSpectraUsing(detMap);

setProperty("WorkspaceToRemap", wsToRemap);
}

std::map<std::string, std::string> CopyDetectorMapping::validateInputs() {
std::map<std::string, std::string> issues;

MatrixWorkspace_sptr wsToMatch = getProperty("WorkspaceToMatch");
MatrixWorkspace_sptr wsToRemap = getProperty("WorkspaceToRemap");

// Check that the workspaces actually are MatrixWorkspaces
bool validWorkspaces = true;

if (wsToMatch == NULL) {
issues["WorkspaceToMatch"] = "Must be a MatrixWorkspace";
validWorkspaces = false;
}

if (wsToRemap == NULL) {
issues["WorkspaceToRemap"] = "Must be a MatrixWorkspace";
validWorkspaces = false;
}

// Check histohram counts match (assuming both are MatrixWorkspaces)
if (validWorkspaces &&
wsToMatch->getNumberHistograms() != wsToRemap->getNumberHistograms())
issues["WorkspaceToRemap"] =
"Number of histograms must match WorkspaceToMatch";

return issues;
}

} // namespace Algorithms
} // namespace Mantid
87 changes: 87 additions & 0 deletions Code/Mantid/Framework/Algorithms/test/CopyDetectorMappingTest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#ifndef COPYDETECTORMAPPINGTEST_H_
#define COPYDETECTORMAPPINGTEST_H_

#include <cxxtest/TestSuite.h>
#include "MantidAlgorithms/CopyDetectorMapping.h"
#include "MantidTestHelpers/WorkspaceCreationHelper.h"

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

class CopyDetectorMappingTest : public CxxTest::TestSuite
{
public:
void testInit()
{
Mantid::Algorithms::CopyDetectorMapping copyMapping;

TS_ASSERT_THROWS_NOTHING( copyMapping.initialize() )
TS_ASSERT( copyMapping.isInitialized() )
}

void testSimple()
{
Mantid::Algorithms::CopyDetectorMapping copyMapping;
TS_ASSERT_THROWS_NOTHING( copyMapping.initialize() )

auto toMatch = WorkspaceCreationHelper::Create2DWorkspace(10, 10);

// Set the detector map for a spectra in the to match workspace
std::set<detid_t> detIDs;
detIDs.insert(5);
detIDs.insert(9);
detIDs.insert(6);
detIDs.insert(2);
toMatch->getSpectrum(0)->setDetectorIDs(detIDs);

// Add workspaces to ADS
AnalysisDataService::Instance().add("to_match", toMatch);
AnalysisDataService::Instance().add("to_remap", WorkspaceCreationHelper::Create2DWorkspace(10, 10));

// Run algorithm
TS_ASSERT_THROWS_NOTHING( copyMapping.setPropertyValue("WorkspaceToMatch", "to_match") );
TS_ASSERT_THROWS_NOTHING( copyMapping.setPropertyValue("WorkspaceToRemap", "to_remap") );

TS_ASSERT_THROWS_NOTHING( copyMapping.execute() );
TS_ASSERT( copyMapping.isExecuted() );

// Check the detector map in the to remap workspace matches that of the to match workspace
MatrixWorkspace_const_sptr result;
TS_ASSERT_THROWS_NOTHING( result = boost::dynamic_pointer_cast<MatrixWorkspace>
(AnalysisDataService::Instance().retrieve("to_remap")) );
std::set<detid_t> resultDetIDs = result->getSpectrum(0)->getDetectorIDs();
TS_ASSERT( detIDs == resultDetIDs );

// Clean up workspace
AnalysisDataService::Instance().remove("to_match");
AnalysisDataService::Instance().remove("to_remap");
}

void testFailWithDifferingSpecSize()
{
Mantid::Algorithms::CopyDetectorMapping copyMapping;
TS_ASSERT_THROWS_NOTHING( copyMapping.initialize() )

// Add workspaces to ADS
AnalysisDataService::Instance().add("to_match", WorkspaceCreationHelper::Create2DWorkspace(10, 10));
AnalysisDataService::Instance().add("to_remap", WorkspaceCreationHelper::Create2DWorkspace(20, 10));

// Run algorithm
TS_ASSERT_THROWS_NOTHING( copyMapping.setPropertyValue("WorkspaceToMatch", "to_match") );
TS_ASSERT_THROWS_NOTHING( copyMapping.setPropertyValue("WorkspaceToRemap", "to_remap") );

auto validationIssues = copyMapping.validateInputs();
TS_ASSERT_DIFFERS( validationIssues.size(), 0 );

TS_ASSERT_THROWS_ANYTHING( copyMapping.execute() );
TS_ASSERT( !copyMapping.isExecuted() );

// Clean up workspace
AnalysisDataService::Instance().remove("to_match");
AnalysisDataService::Instance().remove("to_remap");
}

};

#endif /*COPYDETECTORMAPPINGTEST_H_*/

0 comments on commit ff99c4e

Please sign in to comment.