Newer
Older
Russell Taylor
committed
#ifndef MANTID_API_WORKSPACEPROPERTY_H_
#define MANTID_API_WORKSPACEPROPERTY_H_
Russell Taylor
committed
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/PropertyWithValue.h"
Russell Taylor
committed
#include "MantidAPI/AnalysisDataService.h"
#include <boost/shared_ptr.hpp>
#include "MantidKernel/Logger.h"
Janik Zikovsky
committed
#include "MantidKernel/Exception.h"
#include "MantidAPI/WorkspaceGroup.h"
Russell Taylor
committed
Steve Williams
committed
#include <string>
Russell Taylor
committed
namespace Mantid
{
Gigg, Martyn Anthony
committed
namespace API
{
/** A property class for workspaces. Inherits from PropertyWithValue, with the value being
Russell Taylor
committed
a pointer to the workspace type given to the WorkspaceProperty constructor. This kind
of property also holds the name of the workspace (as used by the AnalysisDataService)
and an indication of whether it is an input or output to an algorithm (or both).
Russell Taylor
committed
The pointers to the workspaces are fetched from the ADS when the properties are validated
(i.e. when the PropertyManager::validateProperties() method calls isValid() ).
Pointers to output workspaces are also fetched, if they exist, and can then be used within
an algorithm. (An example of when this might be useful is if the user wants to write the
output into the same workspace as is used for input - this avoids creating a new workspace
and the overwriting the old one at the end.)
Russell Taylor
committed
@author Russell Taylor, Tessella Support Services plc
@date 10/12/2007
Russell Taylor
committed
Copyright © 2007-2010 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory
Russell Taylor
committed
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/>.
Russell Taylor
committed
Russell Taylor
committed
File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>.
Code Documentation is available at: <http://doxygen.mantidproject.org>
Gigg, Martyn Anthony
committed
*/
template <typename TYPE = MatrixWorkspace>
class WorkspaceProperty : public Kernel::PropertyWithValue< boost::shared_ptr<TYPE> >, public IWorkspaceProperty
{
public:
/** Constructor.
* Sets the property and workspace names but initialises the workspace pointer to null.
Janik Zikovsky
committed
* @param name :: The name to assign to the property
* @param wsName :: The name of the workspace
* @param direction :: Whether this is a Direction::Input, Direction::Output or Direction::InOut (Input & Output) workspace
* @param validator :: The (optional) validator to use for this property
Gigg, Martyn Anthony
committed
* @throw std::out_of_range if the direction argument is not a member of the Direction enum (i.e. 0-2)
*/
WorkspaceProperty( const std::string &name, const std::string &wsName, const unsigned int direction,
Kernel::IValidator<boost::shared_ptr<TYPE> > *validator = new Kernel::NullValidator<boost::shared_ptr<TYPE> > ) :
Kernel::PropertyWithValue <boost::shared_ptr<TYPE> >( name, boost::shared_ptr<TYPE>( ), validator, direction ),
m_workspaceName( wsName ), m_initialWSName( wsName ), m_optional(false)
Gigg, Martyn Anthony
committed
{
}
Russell Taylor
committed
Gigg, Martyn Anthony
committed
/** Constructor.
* Sets the property and workspace names but initialises the workspace pointer to null.
Janik Zikovsky
committed
* @param name :: The name to assign to the property
* @param wsName :: The name of the workspace
* @param direction :: Whether this is a Direction::Input, Direction::Output or Direction::InOut (Input & Output) workspace
* @param optional :: A boolean indicating whether the property is mandatory or not. Only matters
* for input properties
* @param validator :: The (optional) validator to use for this property
Gigg, Martyn Anthony
committed
* @throw std::out_of_range if the direction argument is not a member of the Direction enum (i.e. 0-2)
*/
explicit WorkspaceProperty(const std::string &name, const std::string &wsName, const unsigned int direction, bool optional,
Kernel::IValidator<boost::shared_ptr<TYPE> > *validator = new Kernel::NullValidator<boost::shared_ptr<TYPE> > ) :
Kernel::PropertyWithValue <boost::shared_ptr<TYPE> >( name, boost::shared_ptr<TYPE>( ), validator, direction ),
Gigg, Martyn Anthony
committed
m_workspaceName( wsName ), m_initialWSName( wsName ), m_optional(optional)
{
}
Gigg, Martyn Anthony
committed
/// Copy constructor, the default name stored in the new object is the same as the default name from the original object
WorkspaceProperty( const WorkspaceProperty& right ) :
Kernel::PropertyWithValue< boost::shared_ptr<TYPE> >( right ),
Gigg, Martyn Anthony
committed
m_workspaceName( right.m_workspaceName ), m_initialWSName( right.m_initialWSName ), m_optional(right.m_optional)
Gigg, Martyn Anthony
committed
{
}
Russell Taylor
committed
Gigg, Martyn Anthony
committed
/// Copy assignment operator. Only copies the value (i.e. the pointer to the workspace)
WorkspaceProperty& operator=( const WorkspaceProperty& right )
{
if ( &right == this ) return *this;
Kernel::PropertyWithValue< boost::shared_ptr<TYPE> >::operator=( right );
return *this;
}
Russell Taylor
committed
/** Bring in the PropertyWithValue assignment operator explicitly (avoids VSC++ warning)
Janik Zikovsky
committed
* @param value :: The value to set to
* @return assigned PropertyWithValue
*/
Peterson, Peter
committed
virtual boost::shared_ptr<TYPE>& operator=( const boost::shared_ptr<TYPE>& value )
{
return Kernel::PropertyWithValue< boost::shared_ptr<TYPE> >::operator=( value );
}
Steve Williams
committed
Janik Zikovsky
committed
//--------------------------------------------------------------------------------------
///Add the value of another property
virtual WorkspaceProperty& operator+=( Kernel::Property const * )
Janik Zikovsky
committed
{
throw Kernel::Exception::NotImplementedError("+= operator is not implemented for WorkspaceProperty.");
return *this;
}
Russell Taylor
committed
/// 'Virtual copy constructor'
Kernel::Property* clone() { return new WorkspaceProperty<TYPE>(*this); }
Gigg, Martyn Anthony
committed
/// Virtual destructor
virtual ~WorkspaceProperty()
Steve Williams
committed
{
}
Gigg, Martyn Anthony
committed
/** Get the name of the workspace
* @return The workspace's name
*/
virtual std::string value() const
Steve Williams
committed
{
Gigg, Martyn Anthony
committed
return m_workspaceName;
Steve Williams
committed
}
Russell Taylor
committed
Peterson, Peter
committed
/** Get the value the property was initialised with -its default value
* @return The default value
*/
virtual std::string getDefault() const
{
return m_initialWSName;
}
Gigg, Martyn Anthony
committed
/** Set the name of the workspace.
* Also tries to retrieve it from the AnalysisDataService.
Janik Zikovsky
committed
* @param value :: The new name for the workspace
Gigg, Martyn Anthony
committed
* @return
*/
virtual std::string setValue( const std::string& value )
Gigg, Martyn Anthony
committed
m_workspaceName = value;
Peterson, Peter
committed
// Try and get the workspace from the ADS, but don't worry if we can't
try {
Kernel::PropertyWithValue< boost::shared_ptr<TYPE> >::m_value =
boost::dynamic_pointer_cast<TYPE>(AnalysisDataService::Instance().retrieve(m_workspaceName));
}
catch (Kernel::Exception::NotFoundError &)
{
// Set to null property if not found
this->clear();
//the workspace name is not reset here, however.
Steve Williams
committed
}
Gigg, Martyn Anthony
committed
return isValid();
}
/** Checks whether the entered workspace is valid.
* To be valid, in addition to satisfying the conditions of any validators,
* an output property must not have an empty name and an input one must point to
* a workspace of the correct type.
* @returns A user level description of the problem or "" if it is valid.
*/
std::string isValid() const
{
//start with the no error condition
std::string error = "";
// If an output workspace it must have a name, although it might not exist in the ADS yet
if ( this->direction() == Kernel::Direction::Output )
Steve Williams
committed
{
Gigg, Martyn Anthony
committed
if ( !this->value().empty() )
{
//it has a name and that is enough so return the success
return "";
}
else
Steve Williams
committed
{
Russell Taylor
committed
if( m_optional ) return "";
Gigg, Martyn Anthony
committed
//Return a user level error
Gigg, Martyn Anthony
committed
error = "Enter a name for the Output workspace";
Gigg, Martyn Anthony
committed
//the debug message has more detail to put it in context
Steve Williams
committed
g_log.debug() << "Problem validating workspace: " << error << std::endl;
return error;
}
}
Gigg, Martyn Anthony
committed
// If an input (or inout) workspace, must point to something, although it doesn't have to have a name
Russell Taylor
committed
// unless it's optional
Gigg, Martyn Anthony
committed
if ( this->direction() == Kernel::Direction::Input || this->direction() == Kernel::Direction::InOut )
{
// Workspace groups will not have a value since they are not of type TYPE
if ( !Kernel::PropertyWithValue< boost::shared_ptr<TYPE> >::m_value )
{
Mantid::API::Workspace_sptr wksp;
try
{
wksp = AnalysisDataService::Instance().retrieve(m_workspaceName);
}
catch( Kernel::Exception::NotFoundError &)
{
if( m_workspaceName.empty() )
{
Russell Taylor
committed
if( m_optional )
{
error = "";
}
else
{
error = "Enter a name for the Input/InOut workspace";
}
}
else
{
error = "Workspace \"" + this->value() + "\" was not found in the Analysis Data Service";
}
Russell Taylor
committed
if( !error.empty() )
g_log.debug() << "Problem validating workspace: " << error << "." << std::endl;
Gigg, Martyn Anthony
committed
return error;
}
//At this point we have a valid pointer to a Workspace so we need to test whether it is a group
if( boost::dynamic_pointer_cast<Mantid::API::WorkspaceGroup>(wksp) )
{
g_log.debug() << " Input WorkspaceGroup found " <<std::endl;
}
else
{
error = "Workspace " + this->value() + " is not of the correct type";
g_log.debug() << "Problem validating workspace: " << error << ". \""
<< m_workspaceName << "\" is not of type " << Kernel::PropertyWithValue< boost::shared_ptr<TYPE> >::type() << std::endl;
}
return error;
}
}
// Call superclass method to access any attached validators (which do their own logging)
return Kernel::PropertyWithValue<boost::shared_ptr<TYPE> >::isValid();
Steve Williams
committed
/** Indicates if the object is still pointing to the same workspace, using the workspace name
Gigg, Martyn Anthony
committed
* @return true if the value is the same as the initial value or false otherwise
*/
bool isDefault() const
{
return m_initialWSName == m_workspaceName;
}
Russell Taylor
committed
Gigg, Martyn Anthony
committed
/** Returns the current contents of the AnalysisDataService for input workspaces.
* For output workspaces, an empty set is returned
* @return set of objects in AnalysisDataService
*/
virtual std::set<std::string> allowedValues() const
Gigg, Martyn Anthony
committed
{
Russell Taylor
committed
if ( this->direction() == Kernel::Direction::Input || this->direction() == Kernel::Direction::InOut )
Gigg, Martyn Anthony
committed
{
// If an input workspace, get the list of workspaces currently in the ADS
Russell Taylor
committed
std::set<std::string> vals = AnalysisDataService::Instance().getObjectNames();
Gigg, Martyn Anthony
committed
if (m_optional) // Insert an empty option
Russell Taylor
committed
{
vals.insert("");
}
Gigg, Martyn Anthony
committed
// Copy-construct a temporary workspace property to test the validity of each workspace
WorkspaceProperty<TYPE> tester(*this);
std::set<std::string>::iterator it;
for (it = vals.begin(); it != vals.end();)
Russell Taylor
committed
{
Gigg, Martyn Anthony
committed
// Remove any workspace that's not valid for this algorithm
if (!tester.setValue(*it).empty())
{
vals.erase(it++); //Post-fix so that it erase the previous when returned
Russell Taylor
committed
}
Gigg, Martyn Anthony
committed
else ++it;
Russell Taylor
committed
}
Russell Taylor
committed
return vals;
Gigg, Martyn Anthony
committed
}
else
{
// For output workspaces, just return an empty set
return std::set<std::string>();
Gigg, Martyn Anthony
committed
}
}
Russell Taylor
committed
/// Create a history record
/// @return A populated PropertyHistory for this class
Gigg, Martyn Anthony
committed
virtual const Kernel::PropertyHistory createHistory() const
{
return Kernel::PropertyHistory(this->name(),this->value(),this->type(),this->isDefault(),Kernel::PropertyWithValue<boost::shared_ptr<TYPE> >::direction());
}
Russell Taylor
committed
Gigg, Martyn Anthony
committed
/** If this is an output workspace, store it into the AnalysisDataService
* @return True if the workspace is an output workspace and has been stored
* @throw std::runtime_error if unable to store the workspace successfully
*/
virtual bool store()
{
bool result = false;
Russell Taylor
committed
if ( ! this->operator()() && m_optional ) return result;
Gigg, Martyn Anthony
committed
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
if ( this->direction() ) // Output or InOut
{
// Check that workspace exists
if ( ! this->operator()() ) throw std::runtime_error("WorkspaceProperty doesn't point to a workspace");
// Note use of addOrReplace rather than add
API::AnalysisDataService::Instance().addOrReplace(m_workspaceName, this->operator()() );
result = true;
}
//always clear the internal pointer after storing
clear();
return result;
}
Workspace_sptr getWorkspace() const
{
return this->operator()();
}
private:
/// Reset the pointer to the workspace
void clear()
{
Kernel::PropertyWithValue< boost::shared_ptr<TYPE> >::m_value = boost::shared_ptr<TYPE>();
}
/** Attempts to retreive the data from the ADS
* if the data is not foung the internal pointer is set to null.
*/
void retrieveWorkspaceFromADS()
{
// Try and get the workspace from the ADS, but don't worry if we can't
try {
Kernel::PropertyWithValue< boost::shared_ptr<TYPE> >::m_value =
boost::dynamic_pointer_cast<TYPE>(AnalysisDataService::Instance().retrieve(m_workspaceName));
}
catch (Kernel::Exception::NotFoundError &)
Gigg, Martyn Anthony
committed
{
// Set to null property if not found
this->clear();
}
}
Steve Williams
committed
Gigg, Martyn Anthony
committed
/// The name of the workspace (as used by the AnalysisDataService)
std::string m_workspaceName;
/// The name of the workspace that the this this object was created for
std::string m_initialWSName;
Gigg, Martyn Anthony
committed
/// A flag indicating whether the property should be considered optional. Only matters for input workspaces
bool m_optional;
Gigg, Martyn Anthony
committed
/// for access to logging streams
static Kernel::Logger& g_log;
Peterson, Peter
committed
};
Gigg, Martyn Anthony
committed
template <typename TYPE>
Kernel::Logger& WorkspaceProperty<TYPE>::g_log = Kernel::Logger::get("WorkspaceProperty");
Russell Taylor
committed
Gigg, Martyn Anthony
committed
} // namespace API
} // namespace Mantid
Russell Taylor
committed
#endif /*MANTID_API_WORKSPACEPROPERTY_H_*/