Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy spectra-detector mapping algorithm #249

Merged
merged 10 commits into from
Mar 2, 2015
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_*/