Skip to content
Snippets Groups Projects
Commit 5c32a6c9 authored by Russell Taylor's avatar Russell Taylor
Browse files

Re #6349. Add an algorithm to filter events by X (e.g. TOF) value.

Doesn't pay any attention to any binning, which will be unchanged.
parent f71ed341
No related branches found
No related tags found
No related merge requests found
......@@ -85,6 +85,7 @@ set ( SRC_FILES
src/FilterByLogValue.cpp
src/FilterByTime.cpp
src/FilterByTime2.cpp
src/FilterByXValue.cpp
src/FilterEvents.cpp
src/FilterEventsHighFrequency.cpp
src/FindCenterOfMassPosition.cpp
......@@ -291,6 +292,7 @@ set ( INC_FILES
inc/MantidAlgorithms/FilterByLogValue.h
inc/MantidAlgorithms/FilterByTime.h
inc/MantidAlgorithms/FilterByTime2.h
inc/MantidAlgorithms/FilterByXValue.h
inc/MantidAlgorithms/FilterEvents.h
inc/MantidAlgorithms/FilterEventsHighFrequency.h
inc/MantidAlgorithms/FindCenterOfMassPosition.h
......@@ -427,6 +429,7 @@ set ( TEST_FILES
# CalMuonDeadTimeTest.h
# CountEventsInPulsesTest.h
# UpdatePeakParameterTableTest.h
#SassenaFFTTest.h
AddLogDerivativeTest.h
AddPeakTest.h
AddSampleLogTest.h
......@@ -499,6 +502,7 @@ set ( TEST_FILES
FilterByLogValueTest.h
FilterByTime2Test.h
FilterByTimeTest.h
FilterByXValueTest.h
FilterEventsHighFrequencyTest.h
FilterEventsTest.h
FindCenterOfMassPosition2Test.h
......@@ -572,7 +576,6 @@ set ( TEST_FILES
ResampleXTest.h
ResetNegativesTest.h
ResizeRectangularDetectorTest.h
#SassenaFFTTest.h
ScaleTest.h
ScaleXTest.h
ShiftLogTimeTest.h
......
#ifndef MANTID_ALGORITHMS_FILTERBYXVALUE_H_
#define MANTID_ALGORITHMS_FILTERBYXVALUE_H_
#include "MantidKernel/System.h"
#include "MantidAPI/Algorithm.h"
namespace Mantid
{
namespace Algorithms
{
/** FilterByXValue : TODO: DESCRIPTION
Copyright © 2013 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 FilterByXValue : public API::Algorithm
{
public:
FilterByXValue();
virtual ~FilterByXValue();
virtual const std::string name() const;
virtual int version() const;
virtual const std::string category() const;
std::map<std::string, std::string> validateInputs();
private:
virtual void initDocs();
void init();
void exec();
};
} // namespace Algorithms
} // namespace Mantid
#endif /* MANTID_ALGORITHMS_FILTERBYXVALUE_H_ */
/*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 "MantidAlgorithms/FilterByXValue.h"
#include "MantidDataObjects/EventWorkspace.h"
namespace Mantid
{
namespace Algorithms
{
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(FilterByXValue)
using namespace Kernel;
using namespace API;
using namespace DataObjects;
/// Constructor
FilterByXValue::FilterByXValue()
{
}
/// Destructor
FilterByXValue::~FilterByXValue()
{
}
/// Algorithm's name for identification. @see Algorithm::name
const std::string FilterByXValue::name() const { return "FilterByXValue";};
/// Algorithm's version for identification. @see Algorithm::version
int FilterByXValue::version() const { return 1;};
/// Algorithm's category for identification. @see Algorithm::category
const std::string FilterByXValue::category() const { return "Events\\EventFiltering";}
/// Sets documentation strings for this algorithm
void FilterByXValue::initDocs()
{
this->setWikiSummary("TODO: Enter a quick description of your algorithm.");
this->setOptionalMessage("TODO: Enter a quick description of your algorithm.");
}
void FilterByXValue::init()
{
declareProperty(new WorkspaceProperty<EventWorkspace>("InputWorkspace","",Direction::Input), "The input workspace.");
declareProperty(new WorkspaceProperty<EventWorkspace>("OutputWorkspace","",Direction::Output), "The output workspace.");
declareProperty("XMin", EMPTY_DBL(),
"The minimum X value (in the units of the input workspace) for which events will be retained\n"
"(default: event list min)");
declareProperty("XMax", EMPTY_DBL(),
"The maximum X value (in the units of the input workspace) for which events will be retained\n"
"(default: event list max)");
}
std::map<std::string, std::string> FilterByXValue::validateInputs()
{
std::map<std::string, std::string> errors;
const double xmin = getProperty("XMin");
const double xmax = getProperty("XMax");
if ( isEmpty(xmin) && isEmpty(xmax) )
{
errors["XMin"] = "At least one of XMin/XMax must be specified.";
errors["XMax"] = "At least one of XMin/XMax must be specified.";
return errors;
}
if ( !isEmpty(xmin) && !isEmpty(xmax) && xmax <= xmin )
{
errors["XMin"] = "XMin must be less than XMax.";
errors["XMax"] = "XMin must be less than XMax.";
}
return errors;
}
void FilterByXValue::exec()
{
// Get the properties
EventWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
EventWorkspace_sptr outputWS = getProperty("OutputWorkspace");
double xmin = getProperty("XMin");
double xmax = getProperty("XMax");
// We need to reduce XMin & increase XMax slightly as we want to keep events with exactly those values
xmin *= 0.999999999;
xmax *= 1.000000001;
const int numSpec = static_cast<int>(inputWS->getNumberHistograms());
// Check if we're doing thing in-place.
bool inPlace = true;
if ( inputWS != outputWS )
{
inPlace = false;
// Create a new output workspace if not doing things in place. Preserve event-ness.
outputWS =
boost::dynamic_pointer_cast<EventWorkspace>( WorkspaceFactory::Instance().create("EventWorkspace",
numSpec, inputWS->blocksize()+inputWS->isHistogramData(), inputWS->blocksize()) );
WorkspaceFactory::Instance().initializeFromParent(inputWS, outputWS, false);
// Copy over the data.
// TODO: Make this more efficient by only copying over the events that pass the
// filter rather than copying everything and then removing some. This should
// entail new methods (e.g. iterators) on EventList as this algorithm shouldn't
// need to know about the type of the events (e.g. weighted).
outputWS->copyDataFrom(*inputWS);
setProperty("OutputWorkspace",outputWS);
}
Progress prog(this,0.0,1.0,numSpec);
// Loop over the workspace, removing the events that don't pass the filter
PARALLEL_FOR1(outputWS)
for ( int spec = 0; spec < numSpec; ++spec )
{
PARALLEL_START_INTERUPT_REGION
EventList& events = outputWS->getEventList(spec);
// Sort to make getting the tof min/max faster (& since maskTof will sort anyway)
events.sortTof();
if ( !isEmpty(xmin) )
{
const double list_xmin = events.getTofMin();
if ( xmin > list_xmin ) events.maskTof(list_xmin,xmin);
// Despite the name, maskTof really only does filtering which is what we want
}
if ( !isEmpty(xmax) )
{
const double list_xmax = events.getTofMax();
// Need to scale up list_xmax slightly to avoid retaining the last event in the list
if ( xmax < list_xmax ) events.maskTof(xmax,list_xmax*1.000000001);
}
prog.report();
PARALLEL_END_INTERUPT_REGION
}
PARALLEL_CHECK_INTERUPT_REGION
}
} // namespace Algorithms
} // namespace Mantid
#ifndef MANTID_ALGORITHMS_FILTERBYXVALUETEST_H_
#define MANTID_ALGORITHMS_FILTERBYXVALUETEST_H_
#include <cxxtest/TestSuite.h>
#include "MantidAlgorithms/FilterByXValue.h"
#include "MantidTestHelpers/WorkspaceCreationHelper.h"
using Mantid::Algorithms::FilterByXValue;
class FilterByXValueTest : 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 FilterByXValueTest *createSuite() { return new FilterByXValueTest(); }
static void destroySuite( FilterByXValueTest *suite ) { delete suite; }
void test_validation()
{
FilterByXValue alg;
TS_ASSERT_THROWS_NOTHING( alg.initialize() );
TS_ASSERT( alg.isInitialized() );
// InputWorkspace has to be an EventWorkspace
TS_ASSERT_THROWS( alg.setProperty("InputWorkspace", WorkspaceCreationHelper::Create2DWorkspace(1,1)), std::invalid_argument );
TS_ASSERT_THROWS_NOTHING( alg.setProperty("InputWorkspace", WorkspaceCreationHelper::CreateEventWorkspace()) );
// At least one of XMin & XMax must be specified
auto errorMap = alg.validateInputs();
TS_ASSERT_EQUALS( errorMap.size(), 2);
TS_ASSERT_EQUALS( errorMap.begin()->first, "XMax" );
TS_ASSERT_EQUALS( errorMap.rbegin()->first, "XMin" );
TS_ASSERT_THROWS_NOTHING( alg.setProperty("XMin", 10.0) );
TS_ASSERT( alg.validateInputs().empty() );
// XMax must be > XMin
TS_ASSERT_THROWS_NOTHING( alg.setProperty("XMax", 9.0) );
errorMap = alg.validateInputs();
TS_ASSERT_EQUALS( errorMap.size(), 2);
TS_ASSERT_EQUALS( errorMap.begin()->first, "XMax" );
TS_ASSERT_EQUALS( errorMap.rbegin()->first, "XMin" );
}
void test_exec()
{
using Mantid::DataObjects::EventWorkspace_sptr;
EventWorkspace_sptr inputWS = WorkspaceCreationHelper::CreateEventWorkspace2(5,1);
// Add the workspace to the ADS so that it gets a name (stops validation complaints)
Mantid::API::AnalysisDataService::Instance().add("inWS",inputWS);
FilterByXValue alg;
TS_ASSERT_THROWS_NOTHING( alg.initialize() );
TS_ASSERT_THROWS_NOTHING( alg.setProperty("InputWorkspace", inputWS) );
TS_ASSERT_THROWS_NOTHING( alg.setProperty("OutputWorkspace", "inWS") );
TS_ASSERT_THROWS_NOTHING( alg.setProperty("XMin", 20.5) );
TS_ASSERT_THROWS_NOTHING( alg.setProperty("XMax", 30.5) );
TS_ASSERT( alg.execute() );
TS_ASSERT_EQUALS ( inputWS->getNumberEvents(), 110 );
TS_ASSERT_EQUALS ( inputWS->getEventXMin(), 20.5 );
TS_ASSERT_EQUALS ( inputWS->getEventXMax(), 30.5 );
}
};
class FilterByXValueTestPerformance : 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 FilterByXValueTestPerformance *createSuite() { return new FilterByXValueTestPerformance(); }
static void destroySuite( FilterByXValueTestPerformance *suite ) { delete suite; }
void setUp()
{
Mantid::API::AnalysisDataService::Instance().add("ToFilter",
WorkspaceCreationHelper::CreateEventWorkspace(5000,1000,8000, 0.0, 1.0, 3) );
}
void tearDown()
{
Mantid::API::AnalysisDataService::Instance().remove("ToFilter");
}
void test_crop_events_inplace()
{
FilterByXValue filter;
filter.initialize();
filter.setPropertyValue("InputWorkspace","ToFilter");
filter.setPropertyValue("OutputWorkspace","ToFilter");
filter.setProperty("XMin",5000.0);
filter.setProperty("XMax",7500.0);
TS_ASSERT( filter.execute() );
}
};
#endif /* MANTID_ALGORITHMS_FILTERBYXVALUETEST_H_ */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment