Skip to content
Snippets Groups Projects
Load.cpp 13.1 KiB
Newer Older
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidDataHandling/Load.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidAPI/LoadAlgorithmFactory.h"
namespace Mantid
{
  namespace DataHandling
  {
    // Register the algorithm into the algorithm factory
    
    /// Sets documentation strings for this algorithm
    void Load::initDocs()
    {
      this->setWikiSummary("Attempts to load a given file by finding an appropriate Load algorithm. ");
      this->setOptionalMessage("Attempts to load a given file by finding an appropriate Load algorithm.");
    }
    

    using namespace Kernel;
    using namespace API;

    //--------------------------------------------------------------------------
    // Public methods
    //--------------------------------------------------------------------------

    Load::Load() : IDataFileChecker(), m_baseProps()
    * Override setPropertyValue
    * @param name The name of the property
    * @param value The value of the property as a string
    */
    void Load::setPropertyValue(const std::string &name, const std::string &value)
    {
        // This call makes resolving the filename easier
        IDataFileChecker::setPropertyValue(name, value);
        loader = getFileLoader(getPropertyValue(name));
        const std::string loaderName = getProperty("LoaderName");
        if( !loaderName.empty() )
        {
          loader = boost::static_pointer_cast<IDataFileChecker>(
            API::AlgorithmManager::Instance().createUnmanaged(loaderName));
          loader->initialize();
        }
      if( loader ) declareLoaderProperties(loader);

      // Set the property after some may have been redeclared
      if( name != "Filename") IDataFileChecker::setPropertyValue(name, value);
    //--------------------------------------------------------------------------
    // Private methods
    //--------------------------------------------------------------------------

    /**
Janik Zikovsky's avatar
Janik Zikovsky committed
    * @param filePath :: File path
    * @param nread :: Number of bytes read
    * @param header :: A buffer containing the nread bytes
    bool Load::quickFileCheck(const std::string& filePath,size_t nread,const file_header& header)
    {
      (void)filePath; (void)nread; (void)header;
      return false;
    }

    /**
    * File check by looking at the structure of the data file
Janik Zikovsky's avatar
Janik Zikovsky committed
    * @param filePath :: The full file path
    int Load::fileCheck(const std::string& filePath)
    {
      (void)filePath;
      return -1;
    }

    /** 
    * Get a shared pointer to the load algorithm with highest preference for loading
    * @param filePath :: path of the file
    * @returns A shared pointer to the unmanaged algorithm
    */
    API::IDataFileChecker_sptr Load::getFileLoader(const std::string& filePath)
    {
      /* Open the file and read in the first bufferSize bytes - these will
      FILE* fp = fopen(filePath.c_str(), "rb");
      if (fp == NULL)
      {
        throw Kernel::Exception::FileError("Unable to open the file:", filePath);
      }
      file_header header;
      int nread = fread(&header,sizeof(unsigned char), g_hdr_bytes, fp);
      // Ensure the character string is null terminated.
      header.full_hdr[g_hdr_bytes] = '\0';
      if (nread == -1)
      {
        throw std::runtime_error("Error while closing file \"" + filePath + "\"");
      // Iterate through all loaders and attempt to find the best qualified for the job.
      // Each algorithm has a quick and long file check. The long version returns an integer
      // giving its certainty about be able to load the file. The highest wins.
      std::vector<std::string> loaderNames = API::LoadAlgorithmFactory::Instance().getKeys();
      int highestPref(0);
      std::vector<std::string>::const_iterator cend = loaderNames.end();
      for( std::vector<std::string>::const_iterator citr = loaderNames.begin(); citr != cend;
        IDataFileChecker_sptr loader = API::LoadAlgorithmFactory::Instance().create(*citr);
        if( loader->quickFileCheck(filePath, nread, header) )
        {
          int pref = loader->fileCheck(filePath);
          // Can't just pick the first as there might be one later in the list with a higher
          // preference
          if( pref > highestPref )
          {
            highestPref = pref;
            winningLoader = loader;
          }
        }
        // Clear what may have been here previously
        setPropertyValue("LoaderName", "");
        throw std::runtime_error("Cannot find a loader for \"" + filePath + "\"");
      setPropertyValue("LoaderName", winningLoader->name());
      winningLoader->initialize();
    * Declare any additional properties of the concrete loader here
    * @param loader A pointer to the concrete loader
    */
    void Load::declareLoaderProperties(const IDataFileChecker_sptr loader)
      // If we have switch loaders then the concrete loader will have different properties
      // so take care of ensuring Load has the correct ones
      const std::vector<Property*> existingProps = this->getProperties();      
      for( size_t i = 0; i < existingProps.size(); ++i )
        const std::string name = existingProps[i]->name();
        if( m_baseProps.find(name) != m_baseProps.end() ||
            loader->existsProperty(name) )
        {
          continue;
        }
        this->removeProperty(name);
      }

      const std::vector<Property*> &loaderProps = loader->getProperties();
      const std::string filePropName(loader->filePropertyName());
      size_t numProps(loaderProps.size());
      for (size_t i = 0; i < numProps; ++i)
      {
        Property* loadProp = loaderProps[i];
        if( loadProp->name() == filePropName ) continue;
        try
        {
          declareProperty(loadProp->clone(), loadProp->documentation());
        }
        catch(Exception::ExistsError&)
        {
          // Already exists as a static property
          continue;
        }
      }
    }

    /// Initialisation method.
    void Load::init()
    {

      std::vector<std::string> exts;
      exts.push_back(".raw");
      exts.push_back(".s*");
      exts.push_back(".add");
      exts.push_back(".nxs");
      exts.push_back(".nx5");
      exts.push_back(".xml");
      exts.push_back(".n*");

      exts.push_back(".dat");
      exts.push_back(".txt");
      exts.push_back(".csv");

      exts.push_back(".spe");

      declareProperty(new FileProperty("Filename", "", FileProperty::Load, exts),
        "The name of the file to read, including its full or relative\n"
        "path. (N.B. case sensitive if running on Linux).");
      declareProperty(new WorkspaceProperty<Workspace>("OutputWorkspace", "",Direction::Output), 
        "The name of the workspace that will be created, filled with the\n"
        "read-in data and stored in the Analysis Data Service.");
      declareProperty("LoaderName", std::string(""), "A string containing the name of the concrete loader used", 
      // Save for later what the base Load properties are
      const std::vector<Property*> & props = this->getProperties();
      for( size_t i = 0; i < this->propertyCount(); ++i )
      {
      const std::string loaderName = getPropertyValue("LoaderName");
      if( loaderName.empty() )
      {
        throw std::invalid_argument("Cannot find loader, LoaderName property has not been set.");
      IDataFileChecker_sptr loader = createLoader(loaderName,0,1);
      g_log.information() << "Using " << loaderName << " version " << loader->version() << ".\n";
      ///get the list properties for the concrete loader load algorithm
      const std::vector<Kernel::Property*> & loader_props = loader->getProperties();
      // Loop through and set the properties on the sub algorithm
      std::vector<Kernel::Property*>::const_iterator itr;
      for (itr = loader_props.begin(); itr != loader_props.end(); ++itr)
        const std::string propName = (*itr)->name();
        if( this->existsProperty(propName) )
        {
          loader->setPropertyValue(propName, getPropertyValue(propName));
        }
        else if( propName == loader->filePropertyName() )
        {
          loader->setPropertyValue(propName, getPropertyValue("Filename"));
        }
      // Execute the concrete loader
      loader->execute();
      // Set the workspace. Deals with possible multiple periods
      setOutputWorkspace(loader);
    }

    /** 
    * Create the concrete instance use for the actual loading.
    * @param name :: The name of the loader to instantiate
    * @param startProgress :: The percentage progress value of the overall 
    * algorithm where this child algorithm starts
    * @param endProgress :: The percentage progress value of the overall 
    * algorithm where this child algorithm ends
    * @param logging :: Set to false to disable logging from the child algorithm
    */
    API::IDataFileChecker_sptr Load::createLoader(const std::string & name, const double startProgress, 
      const double endProgress, const bool logging) const
      IDataFileChecker_sptr loader = boost::static_pointer_cast<IDataFileChecker>(
        API::AlgorithmManager::Instance().createUnmanaged(name));
        throw std::runtime_error("Cannot create loader for \"" + getPropertyValue("Filename") + "\"");
      }

      //Set as a child so that we are in control of output storage
      loader->setChild(true);
      loader->setLogging(logging);
      // If output workspaces are nameless, give them a temporary name to satisfy validator
      const std::vector< Property*> &props = loader->getProperties();
      for (unsigned int i = 0; i < props.size(); ++i)
      {
        if (props[i]->direction() == Direction::Output && 
          dynamic_cast<IWorkspaceProperty*>(props[i]) )
        {
          if ( props[i]->value().empty() ) props[i]->setValue("LoadChildWorkspace");
        }
      if (startProgress >= 0. && endProgress > startProgress && endProgress <= 1.)
        setChildStartProgress(startProgress);
        setChildEndProgress(endProgress);
    * Set the output workspace(s) if the load's return workspace has type API::Workspace
    * @param loader :: Shared pointer to load algorithm
    */
    void Load::setOutputWorkspace(const API::IDataFileChecker_sptr loader)
      // Go through each OutputWorkspace property and check whether we need to make a counterpart here
      const std::vector<Property*> loaderProps = loader->getProperties();
      const size_t count = loader->propertyCount();
      for( size_t i = 0; i < count; ++i )
        Property *prop = loaderProps[i];
        if( dynamic_cast<IWorkspaceProperty*>(prop) && prop->direction() == Direction::Output )
        {
          const std::string & name = prop->name();
          if( !this->existsProperty(name) )
          {
            declareProperty(new WorkspaceProperty<Workspace>(name, loader->getPropertyValue(name),
              Direction::Output));
          }
          Workspace_sptr wkspace = getOutputWorkspace(name, loader);
          setProperty(name, wkspace);
        }
    * Return an output workspace property dealing with the lack of connection between of 
    * WorkspaceProperty types
    * @param propName :: The name of the property
    * @param loader :: The loader algorithm
    * @returns A pointer to the OutputWorkspace property of the sub algorithm
    */
    API::Workspace_sptr Load::getOutputWorkspace(const std::string & propName,
      const API::IDataFileChecker_sptr loader) const
      // @todo Need to try and find a better way using the getValue methods
      }
      catch(std::runtime_error&)
      {
      }
      // Try a MatrixWorkspace
      try
      {
        MatrixWorkspace_sptr childWS = loader->getProperty(propName);
        return childWS;
        IEventWorkspace_sptr childWS = loader->getProperty(propName);
        return childWS;
  } // namespace DataHandling
} // namespace Mantid