Skip to content

Commit

Permalink
refs #5744. Abstract algorithm added
Browse files Browse the repository at this point in the history
  • Loading branch information
OwenArnold committed Aug 13, 2012
1 parent 8550c69 commit 6a1906b
Show file tree
Hide file tree
Showing 6 changed files with 307 additions and 199 deletions.
7 changes: 5 additions & 2 deletions Code/Mantid/Framework/API/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ set ( SRC_FILES
src/MultiDomainFunction.cpp
src/MultipleExperimentInfos.cpp
src/MultipleFileProperty.cpp
src/MutliPeriodGroupAlgorithm.cpp
src/NullCoordTransform.cpp
src/NumericAxis.cpp
src/ParamFunction.cpp
Expand Down Expand Up @@ -108,6 +109,7 @@ set ( SRC_UNITY_IGNORE_FILES src/CompositeFunction.cpp
)

set ( INC_FILES
# inc/MantidAPI/BoxCtrlChangesInterface.h
inc/MantidAPI/Algorithm.h
inc/MantidAPI/AlgorithmFactory.h
inc/MantidAPI/AlgorithmHasProperty.h
Expand All @@ -119,7 +121,6 @@ set ( INC_FILES
inc/MantidAPI/AnalysisDataService.h
inc/MantidAPI/ArchiveSearchFactory.h
inc/MantidAPI/Axis.h
# inc/MantidAPI/BoxCtrlChangesInterface.h
inc/MantidAPI/BoxController.h
inc/MantidAPI/CatalogFactory.h
inc/MantidAPI/ChopperModel.h
Expand Down Expand Up @@ -205,6 +206,7 @@ set ( INC_FILES
inc/MantidAPI/MultiDomainFunction.h
inc/MantidAPI/MultipleExperimentInfos.h
inc/MantidAPI/MultipleFileProperty.h
inc/MantidAPI/MutliPeriodGroupAlgorithm.h
inc/MantidAPI/NullCoordTransform.h
inc/MantidAPI/NumericAxis.h
inc/MantidAPI/ParamFunction.h
Expand Down Expand Up @@ -268,9 +270,9 @@ set ( TEST_FILES
test/IFunctionMDTest.h
test/ILiveListenerTest.h
test/IMDWorkspaceTest.h
test/ImmutableCompositeFunctionTest.h
test/ISpectrumTest.h
test/IkedaCarpenterModeratorTest.h
test/ImmutableCompositeFunctionTest.h
test/ImplicitFunctionParserFactoryTest.h
test/InstrumentDataServiceTest.h
test/LiveListenerFactoryTest.h
Expand All @@ -281,6 +283,7 @@ set ( TEST_FILES
test/MultiDomainFunctionTest.h
test/MultipleExperimentInfosTest.h
test/MultipleFilePropertyTest.h
test/MutliPeriodGroupAlgorithmTest.h
test/NumericAxisTest.h
test/ParamFunctionAttributeHolderTest.h
test/ParameterReferenceTest.h
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#ifndef MANTID_API_MUTLIPERIODGROUPALGORITHM_H_
#define MANTID_API_MUTLIPERIODGROUPALGORITHM_H_

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

namespace Mantid
{
namespace API
{

/** MutliPeriodGroupAlgorithm : Abstract algorithm. Algorithms that need special processing for Mutli-Period group workspaces should inherit from this
algorithm rather than from Algorithm directly. This algorithm processes workspaces in each group input in a pair-wise fashion to give a group workspace output.
Copyright © 2012 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://svn.mantidproject.org/mantid/trunk/Code/Mantid>
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
class DLLExport MutliPeriodGroupAlgorithm : public Algorithm
{
public:
MutliPeriodGroupAlgorithm();
virtual ~MutliPeriodGroupAlgorithm();

private:
/// Overriden from Algorithm base
virtual bool checkGroups();
/// Overriden from Algorithm base.
virtual bool processGroups();

std::string createFormattedInputWorkspaceNames(const size_t& periodIndex) const;
void validateMultiPeriodGroupInputs(const size_t& nInputWorkspaces) const;

/// Flag used to determine whether to use base or local virtual methods.
bool m_useDefaultGroupingBehaviour;
/// Convenience typdef for workspace names.
typedef std::vector<boost::shared_ptr<Mantid::API::WorkspaceGroup> > VecWSGroupType;
/// multi period group workspaces.
VecWSGroupType m_multiPeriodGroups;

};


} // namespace API
} // namespace Mantid

#endif /* MANTID_API_MUTLIPERIODGROUPALGORITHM_H_ */
208 changes: 208 additions & 0 deletions Code/Mantid/Framework/API/src/MutliPeriodGroupAlgorithm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
#include "MantidAPI/MutliPeriodGroupAlgorithm.h"
#include "MantidAPI/AlgorithmManager.h"

using namespace Mantid::Kernel;

namespace Mantid
{
namespace API
{
//----------------------------------------------------------------------------------------------
/** Constructor
*/
MutliPeriodGroupAlgorithm::MutliPeriodGroupAlgorithm() : m_useDefaultGroupingBehaviour(true)
{
}

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

/**
Validate the multiperiods workspace groups. Gives the opportunity to exit processing if things don't look right.
@input nInputWorkspaces: Number of input workspaces.
*/
void MutliPeriodGroupAlgorithm::validateMultiPeriodGroupInputs(const size_t& nInputWorkspaces) const
{
const size_t multiPeriodGroupsSize = m_multiPeriodGroups.size();
if(multiPeriodGroupsSize != 0 && multiPeriodGroupsSize != nInputWorkspaces)
{
std::string msg = "MergeRuns can either process complete array of MatrixWorkspaces or Multi-period-groups, but mixing of types is not permitted.";
throw std::runtime_error(msg);
}

if(multiPeriodGroupsSize > 0)
{
const size_t benchMarkGroupSize = m_multiPeriodGroups[0]->size();
for(size_t i = 0; i < multiPeriodGroupsSize; ++i)
{
WorkspaceGroup_sptr currentGroup = m_multiPeriodGroups[i];
if(currentGroup->size() != benchMarkGroupSize)
{
throw std::runtime_error("Not all the input Multi-period-group input workspaces are the same size.");
}
for(size_t j = 0; j < currentGroup->size(); ++j)
{
MatrixWorkspace_const_sptr currentNestedWS = boost::dynamic_pointer_cast<const MatrixWorkspace>(currentGroup->getItem(j));
Property* nPeriodsProperty = currentNestedWS->run().getLogData("nperiods");
size_t nPeriods = atoi(nPeriodsProperty->value().c_str());
if(nPeriods != benchMarkGroupSize)
{
throw std::runtime_error("Missmatch between nperiods log and the number of workspaces in the input group: " + m_multiPeriodGroups[i]->name());
}
Property* currentPeriodProperty = currentNestedWS->run().getLogData("current_period");
size_t currentPeriod = atoi(currentPeriodProperty->value().c_str());
if(currentPeriod != (j+1))
{
throw std::runtime_error("Multiperiod group workspaces must be ordered by current_period. Correct: " + currentNestedWS->name());
}
}
}
}
}

/** Check the input workspace properties for groups.
*
* Overriden from base Algorithm class.
*
* Checks to see if the inputs are MULTIPERIOD group data.
*
* @throw std::invalid_argument if the groups sizes are incompatible.
* @throw std::invalid_argument if a member is not found
*
* This method (or an override) must NOT THROW any exception if there are no input workspace groups
*/
bool MutliPeriodGroupAlgorithm::checkGroups()
{
typedef std::vector<std::string> WorkspaceNameType;

m_multiPeriodGroups.clear();
WorkspaceNameType workspaces = this->getProperty("InputWorkspaces");
WorkspaceNameType::iterator it = workspaces.begin();

// Inspect all the input workspaces in the ArrayProperty input.
while(it != workspaces.end())
{
Workspace_sptr ws = AnalysisDataService::Instance().retrieve(*it);
if(!ws)
{
throw Kernel::Exception::NotFoundError("Workspace", *it);
}
WorkspaceGroup_sptr inputGroup = boost::dynamic_pointer_cast<WorkspaceGroup>(ws);
if(inputGroup)
{
if(inputGroup->isMultiperiod())
{
m_multiPeriodGroups.push_back(inputGroup);
}
}
++it;
}
const size_t multiPeriodGroupsSize = m_multiPeriodGroups.size();
// If there are no MULTIPERIOD group workpaces detected, we hand the checking back up toe the base class.
if(multiPeriodGroupsSize == 0)
{
// This will prevent (this) implementation of processGroups from being run. The base class proccessGroups will be used instead.
m_useDefaultGroupingBehaviour = true;
// Use the base class inmplementation.
return Algorithm::checkGroups();
}
// Check that we have correct looking group workspace indexes.
validateMultiPeriodGroupInputs(workspaces.size());

m_useDefaultGroupingBehaviour = false;
return !m_useDefaultGroupingBehaviour;
}


/**
Creates a list of input workspaces as a string for a given period using all nested workspaces at that period
within all group workspaces.
This requires a little explanation, because this is the reason that this algorithm needs a customised overriden checkGroups and processGroups
method:
Say you have two multiperiod group workspaces A and B and an output workspace C. A contains matrix workspaces A_1 and A_2, and B contains matrix workspaces B_1 and B2. Because this
is multiperiod data. A_1 and B_1 share the same period, as do A_2 and B_2. So merging must be with respect to workspaces of equivalent periods. Therefore,
merging must be A_1 + B_1 = C_1 and A_2 + B_2 = C_2. This method constructs the inputs for a nested call to MergeRuns in this manner.
@param periodIndex : zero based index denoting the period.
@return comma separated string of input workspaces.
*/
std::string MutliPeriodGroupAlgorithm::createFormattedInputWorkspaceNames(const size_t& periodIndex) const
{
std::string prefix = "";
std::string inputWorkspaces = "";
for(size_t j = 0; j < m_multiPeriodGroups.size(); ++j)
{
inputWorkspaces += prefix + m_multiPeriodGroups[j]->getItem(periodIndex)->name();
prefix = ",";
}
return inputWorkspaces;
}

//--------------------------------------------------------------------------------------------
/** Process WorkspaceGroup inputs.
*
* Overriden from Algorithm base class.
*
* This should be called after checkGroups(), which sets up required members.
* It goes through each member of the group(s), creates and sets an algorithm
* for each and executes them one by one.
*
* If there are several group input workspaces, then the member of each group
* is executed pair-wise.
*
* @return true - if all the workspace members are executed.
*/
bool MutliPeriodGroupAlgorithm::processGroups()
{
// If we are not processing multiperiod groups, use the base behaviour.
if(m_useDefaultGroupingBehaviour)
{
return Algorithm::processGroups();
}

Property* outputWorkspaceProperty = this->getProperty("OutputWorkspace");
const std::string outName = outputWorkspaceProperty->value();

size_t nPeriods = m_multiPeriodGroups[0]->size();
const bool doObserveADSNotifications = true;
WorkspaceGroup_sptr outputWS = boost::make_shared<WorkspaceGroup>(!doObserveADSNotifications);
// Loop through all the periods.
for(size_t i = 0; i < nPeriods; ++i)
{
// Create a formatted input workspace list. As this is the usual input (ArrayProperty) to the MergeRuns algorithm.
const std::string inputWorkspaces = createFormattedInputWorkspaceNames(i);

Algorithm_sptr alg_sptr = API::AlgorithmManager::Instance().createUnmanaged(this->name(), this->version());
IAlgorithm* alg = alg_sptr.get();
if(!alg)
{
g_log.error()<<"CreateAlgorithm failed for "<<this->name()<<"("<<this->version()<<")"<<std::endl;
throw std::runtime_error("Algorithm creation failed.");
}
alg->initialize();
alg->setPropertyValue("InputWorkspaces", inputWorkspaces);
// Create a name for the output workspace based upon the requested name for the overall output group workspace.
const std::string outName_i = outName + "_" + Strings::toString(i+1);
alg->setPropertyValue("OutputWorkspace", outName_i);

if (!alg->execute())
{
throw std::runtime_error("Execution of " + this->name() + " for group entry " + Strings::toString(i+1) + " failed.");
}
outputWS->add(outName_i);
}
outputWS->observeADSNotifications(doObserveADSNotifications);
this->setProperty("OutputWorkspace", outputWS);
this->setExecuted(true);
AnalysisDataService::Instance().addOrReplace(outName, outputWS);
return true;
}

} // namespace API
} // namespace Mantid
28 changes: 28 additions & 0 deletions Code/Mantid/Framework/API/test/MutliPeriodGroupAlgorithmTest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef MANTID_API_MUTLIPERIODGROUPALGORITHMTEST_H_
#define MANTID_API_MUTLIPERIODGROUPALGORITHMTEST_H_

#include <cxxtest/TestSuite.h>

#include "MantidAPI/MutliPeriodGroupAlgorithm.h"

using Mantid::API::MutliPeriodGroupAlgorithm;

class MutliPeriodGroupAlgorithmTest : 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 MutliPeriodGroupAlgorithmTest *createSuite() { return new MutliPeriodGroupAlgorithmTest(); }
static void destroySuite( MutliPeriodGroupAlgorithmTest *suite ) { delete suite; }


void test_Something()
{
TSM_ASSERT( "You forgot to write a test!", 0);
}


};


#endif /* MANTID_API_MUTLIPERIODGROUPALGORITHMTEST_H_ */

0 comments on commit 6a1906b

Please sign in to comment.