Skip to content

Commit

Permalink
Re #6267. Allow default values for min/max log value.
Browse files Browse the repository at this point in the history
Can now leave MinimumValue or MaximumValue empty in FilterByLogValue
and the filter will be one-sided on the value that is given.

Required addition of minValue & maxValue methods on TimeSeriesProperty.
  • Loading branch information
RussellTaylor committed Dec 11, 2012
1 parent 86d622e commit be398aa
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 131 deletions.
8 changes: 3 additions & 5 deletions Code/Mantid/Framework/Algorithms/src/FilterByLogValue.cpp
Expand Up @@ -165,9 +165,9 @@ void FilterByLogValue::exec()
// Get the properties.
double min = getProperty("MinimumValue");
double max = getProperty("MaximumValue");
double tolerance = getProperty("TimeTolerance");
std::string logname = getPropertyValue("LogName");
bool PulseFilter = getProperty("PulseFilter");
const double tolerance = getProperty("TimeTolerance");
const std::string logname = getPropertyValue("LogName");
const bool PulseFilter = getProperty("PulseFilter");

// Find the start and stop times of the run, but handle it if they are not found.
DateAndTime run_start(0), run_stop("2100-01-01");
Expand Down Expand Up @@ -208,8 +208,6 @@ void FilterByLogValue::exec()
else
{
// ----- Filter by value ------
if (max < min)
throw std::invalid_argument("MaximumValue should be >= MinimumValue. Aborting.");

//This function creates the splitter vector we will use to filter out stuff.
const std::string logBoundary(this->getPropertyValue("LogBoundary"));
Expand Down
13 changes: 4 additions & 9 deletions Code/Mantid/Framework/Algorithms/src/SumEventsByLogValue.cpp
Expand Up @@ -64,9 +64,8 @@ namespace Algorithms
// This is the int log version that ignores binning parameters and has a data point per log value
// TODO: add the ability to specify binning for integer logs

const auto values = intLog->valuesAsVector();
const int minVal = *std::min_element(values.begin(),values.end());
const int maxVal = *std::max_element(values.begin(),values.end());
const int minVal = intLog->minValue();
const int maxVal = intLog->maxValue();
const int xLength = maxVal - minVal + 1;
// Create a point-like workspace to hold the sum. The factory will give back a Workspace2Ds
MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create(inputWorkspace,1,xLength,xLength);
Expand Down Expand Up @@ -116,13 +115,9 @@ namespace Algorithms
// If only the number of bins was given, add the min & max values of the log
if ( binningParams.size() == 1 )
{
// TODO: Move determination of min/max into property itself
const auto values = dblLog->valuesAsVector();
const double minVal = *std::min_element(values.begin(),values.end());
const double maxVal = *std::max_element(values.begin(),values.end());
// TODO: What if min & max are the same (for example if there's only one entry in the property)
binningParams.insert(binningParams.begin(),minVal);
binningParams.push_back(maxVal*1.000001); // Make it a tiny bit larger to cover full range
binningParams.insert( binningParams.begin(), dblLog->minValue() );
binningParams.push_back(dblLog->maxValue()*1.000001); // Make it a tiny bit larger to cover full range
}
MantidVec XValues;
const int XLength = VectorHelper::createAxisFromRebinParams(binningParams, XValues);
Expand Down
62 changes: 52 additions & 10 deletions Code/Mantid/Framework/Algorithms/test/FilterByLogValueTest.h
Expand Up @@ -184,17 +184,9 @@ class FilterByLogValueTest : public CxxTest::TestSuite
* temp = 10 C at 10 sec up to 50C at 50 sec, every 10 seconds
* press = -10 seconds to +150 seconds, every 10 seconds
*
* @param log_name
* @param min
* @param max
* @param seconds_kept
* @param add_proton_charge
* @param do_in_place
* @param PulseFilter :: PulseFilter parameter
*/
void do_test_fake(std::string log_name, double min, double max, int seconds_kept,
bool add_proton_charge = true, bool do_in_place = false,
bool PulseFilter = false)
EventWorkspace_sptr createInputWS(bool add_proton_charge = true)
{
// Default Event Workspace with times from 0-99
EventWorkspace_sptr ew = WorkspaceCreationHelper::CreateEventWorkspace2();
Expand Down Expand Up @@ -243,10 +235,27 @@ class FilterByLogValueTest : public CxxTest::TestSuite
// Finalize the needed stuff
WorkspaceCreationHelper::EventWorkspace_Finalize(ew);

return ew;
}

/** Run the algorithm on a workspace generated by createInputWS()
*
* @param log_name
* @param min
* @param max
* @param seconds_kept
* @param add_proton_charge
* @param do_in_place
* @param PulseFilter :: PulseFilter parameter
*/
void do_test_fake(std::string log_name, double min, double max, int seconds_kept,
bool add_proton_charge = true, bool do_in_place = false,
bool PulseFilter = false)
{
EventWorkspace_sptr ew = createInputWS(add_proton_charge);
std::string inputName = "input_filtering";
AnalysisDataService::Instance().addOrReplace(inputName, boost::dynamic_pointer_cast<MatrixWorkspace>(ew) );


// Save some of the starting values
size_t start_blocksize = ew->blocksize();
size_t num_events = ew->getNumberEvents();
Expand Down Expand Up @@ -385,6 +394,39 @@ class FilterByLogValueTest : public CxxTest::TestSuite
do_test_fake("single_middle", 0, 0, 99, true, false /* not in place*/, true /*PulseFilter*/);
}

std::size_t min_max_helper(bool useMin, bool useMax, double min, double max)
{
FilterByLogValue alg;
alg.initialize();
alg.setChild(true);
alg.setProperty("InputWorkspace",createInputWS());
alg.setProperty("OutputWorkspace","dontmatter");
alg.setProperty("LogName","press");
alg.setProperty("LogBoundary","Left");
if ( useMin ) alg.setProperty("MinimumValue",min);
if ( useMax ) alg.setProperty("MaximumValue",max);

TS_ASSERT( alg.execute() );

EventWorkspace_const_sptr outWS = alg.getProperty("OutputWorkspace");
return outWS->getNumberEvents();
}

// Test that leaving one or both of MinimumValue & MaximumValue properties empty does the right thing
void test_default_min_max()
{
// Test that leaving both empty gives back an unchanged workspace
TS_ASSERT_EQUALS( min_max_helper(false,false,0.0,0.0), 10000 );
// Test that setting min higher that max value in log wipes out all events
TS_ASSERT_EQUALS( min_max_helper(true,false,200.0,0.0), 0 );
// Test that setting max lower that min value in log wipes out all events
TS_ASSERT_EQUALS( min_max_helper(false,true,0.0,-20.0), 0 );
// Test that default max on it's own works for an in-range min
TS_ASSERT_EQUALS( min_max_helper(true,false,70.0,0.0), 3000 );
// Test that default min on it's own works for an in-range max
TS_ASSERT_EQUALS( min_max_helper(false,true,0.0,70.0), 8000 );
}

// // Very slow
// void xtest_HYSPEC()
// {
Expand Down
Expand Up @@ -105,6 +105,10 @@ namespace Mantid
return mvalue;
}

static bool valueCmp(const TimeValueUnit& lhs, const TimeValueUnit& rhs)
{
return ( lhs.mvalue < rhs.mvalue );
}
};

//================================================================================================
Expand Down Expand Up @@ -199,6 +203,11 @@ namespace Mantid
/// Returns the last value
TYPE lastValue() const;

/// Returns the minimum value found in the series
TYPE minValue() const;
/// Returns the maximum value found in the series
TYPE maxValue() const;

/// Returns the number of values at UNIQUE time intervals in the time series
int size() const;
/// Returns the real size of the time series property map:
Expand Down
32 changes: 30 additions & 2 deletions Code/Mantid/Framework/Kernel/src/TimeSeriesProperty.cpp
@@ -1,4 +1,5 @@
#include "MantidKernel/TimeSeriesProperty.h"
#include "MantidKernel/EmptyValues.h"
#include "MantidKernel/Exception.h"

#include <sstream>
Expand Down Expand Up @@ -440,6 +441,7 @@ namespace Mantid
* Fill a TimeSplitterType that will filter the events by matching
* log values >= min and <= max. Creates SplittingInterval's where
* times match the log values, and going to index==0.
* This method is used by the FilterByLogValue algorithm.
*
* @param split :: Splitter that will be filled.
* @param min :: min value
Expand All @@ -450,14 +452,21 @@ namespace Mantid
template<typename TYPE>
void TimeSeriesProperty<TYPE>::makeFilterByValue(TimeSplitterType& split, double min, double max, double TimeTolerance, bool centre) const
{
if ( max < min )
const bool emptyMin = (min == EMPTY_DBL());
const bool emptyMax = (max == EMPTY_DBL());

if ( !emptyMin && !emptyMax && max < min )
{
std::stringstream ss;
ss << "TimeSeriesProperty::makeFilterByValue: 'max' argument must be greater than 'min' "
<< "(got min=" << min << " max=" << max << ")";
throw std::invalid_argument(ss.str());
}

// If min or max were unset ("empty") in the algorithm, set to the min or max value of the log
if ( emptyMin ) min = minValue();
if ( emptyMax ) max = maxValue();

// Make sure the splitter starts out empty
split.clear();

Expand Down Expand Up @@ -529,6 +538,7 @@ namespace Mantid

/** If the first and/or last values in a log are between min & max, expand and existing TimeSplitter
* (created by makeFilterByValue) if necessary to cover the full TimeInterval given.
* This method is used by the FilterByLogValue algorithm.
* @param split The splitter to modify if necessary
* @param min The minimum 'good' value
* @param max The maximum 'good' value
Expand All @@ -537,14 +547,21 @@ namespace Mantid
template<typename TYPE>
void TimeSeriesProperty<TYPE>::expandFilterToRange(TimeSplitterType& split, double min, double max, const TimeInterval & range) const
{
if ( max < min )
const bool emptyMin = (min == EMPTY_DBL());
const bool emptyMax = (max == EMPTY_DBL());

if ( !emptyMin && !emptyMax && max < min )
{
std::stringstream ss;
ss << "TimeSeriesProperty::expandFilterToRange: 'max' argument must be greater than 'min' "
<< "(got min=" << min << " max=" << max << ")";
throw std::invalid_argument(ss.str());
}

// If min or max were unset ("empty") in the algorithm, set to the min or max value of the log
if ( emptyMin ) min = minValue();
if ( emptyMax ) max = maxValue();

// Assume everything before the 1st value is constant
double val = firstValue();
if ((val >= min) && (val <= max))
Expand Down Expand Up @@ -795,6 +812,17 @@ namespace Mantid
return m_values.rbegin()->value();
}

template<typename TYPE>
TYPE TimeSeriesProperty<TYPE>::minValue() const
{
return std::min_element(m_values.begin(),m_values.end(),TimeValueUnit<TYPE>::valueCmp)->value();
}

template<typename TYPE>
TYPE TimeSeriesProperty<TYPE>::maxValue() const
{
return std::max_element(m_values.begin(),m_values.end(),TimeValueUnit<TYPE>::valueCmp)->value();
}

/// Returns the number of values at UNIQUE time intervals in the time series
/// @returns The number of unique time interfaces
Expand Down

0 comments on commit be398aa

Please sign in to comment.