Skip to content
Snippets Groups Projects
Load.cpp 10.1 KiB
Newer Older
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidDataHandling/Load.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidDataObjects/Workspace2D.h"
#include "MantidAPI/LoadAlgorithmFactory.h"
#include<algorithm>
namespace Mantid
{
  namespace DataHandling
  {
    // Register the algorithm into the algorithm factory

    using namespace Kernel;
    using namespace API;

    /// Default constructor
    Load::Load() : IDataFileChecker(), m_header_buffer(NULL) 
    {
    }

    /**
     * Quick file always returns false here
     * @param filePath File path
     * @param nread Number of bytes read
     * @param header_buffer 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
     * @param filePath The full file path
     * @returns -1
     */
    int Load::fileCheck(const std::string& filePath)
    {
      (void)filePath;
      return -1;
    }

    /// 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, true), 
		      "The name of the workspace that will be created, filled with the\n"
		      "read-in data and stored in the Analysis Data Service.");
      declareProperty("FindLoader", false, "If true the algorithm will only be run as\n"
 		      "far as is necessary to discover the concrete Load algorithm to use");
      declareProperty("LoaderName", std::string(""), "A string containing the name of the concrete loader used", 
 		      Direction::Output);
      /** 
       * Checks this property exists in the list of algorithm properties.
       */
      struct hasProperty
      { 
	/** constructor which takes 1 arguement.
	 *@param name :: name of the property
	hasProperty(const std::string name):m_name(name){}
	
	/**This method comapres teh property name
	 *@param prop :: shared pointer to property
	 *@return true if the property exists in the list of properties.
	 */
	bool operator()(Mantid::Kernel::Property* prop)
	{
	  std::string name=prop->name();
	  return (!name.compare(m_name));
	}
	/// name of teh property
	std::string m_name;
      };
     *   Executes the algorithm.
     */
    void Load::exec()
    {
      std::string fileName = getPropertyValue("Filename");
      std::string::size_type i = fileName.find_last_of('.');
      std::string ext = fileName.substr(i+1);
      std::transform(ext.begin(),ext.end(),ext.begin(),tolower);
      //get the shared pointer to the specialised load algorithm to execute  
      API::IAlgorithm_sptr loader = getFileLoader(fileName);
      if( !loader )
      {
        throw std::runtime_error("Cannot find a loader for \"" + fileName + "\"");
      }
      else
	setPropertyValue("LoaderName", loader->name());
      bool findOnly = getProperty("FindLoader");
      if( findOnly ) return;

      g_log.information()<<"The sub load algorithm  created to execute is "
			 << loader->name() << "  and it version is  " 
			 << loader->version() <<std::endl;
      double startProgress(0.0), endProgress(1.0);
      initialiseLoadSubAlgorithm(loader,startProgress,endProgress,true,-1);
  
      //get the list of properties for this algorithm
      std::vector<Kernel::Property*> props=getProperties();
      ///get the list properties for the sub load algorithm
      std::vector<Kernel::Property*>loader_props=loader->getProperties();
      
      //loop through the properties of this algorithm 
      std::vector<Kernel::Property*>::iterator itr;
      for (itr=props.begin();itr!=props.end();++itr)
      {        
	std::vector<Mantid::Kernel::Property*>::iterator prop;
	//if  the load sub algorithm has the same property then set it.
	prop=std::find_if(loader_props.begin(),loader_props.end(),hasProperty((*itr)->name()));
	if(prop!=loader_props.end())
	{ 
	  loader->setPropertyValue((*prop)->name(),getPropertyValue((*prop)->name()));
	}
      // Execute the concrete loader
      loader->execute();
      // Set the workspace. Deals with possible multiple periods
      setOutputWorkspace(loader);          
    /** Get a shared pointer to the load algorithm with highest preference for loading
    API::IAlgorithm_sptr Load::getFileLoader(const std::string& filePath)
    {
      /* Open the file and read in the first bufferSize bytes - these will
       * be used to determine the type of the file
       */
      FILE* fp = fopen(filePath.c_str(), "rb");
      if (fp == NULL)
      {
	throw Kernel::Exception::FileError("Unable to open the file:", filePath);
      }
      //unsigned char* header_buffer = header_buffer_union.c;
      //unsigned char * header_buffer = IDataFileChecker::g_hdr_buf.get();
      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)
      {
	fclose(fp);
      }
      if (fclose(fp) != 0)
      {
	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);
      API::IAlgorithm_sptr winningLoader;
      std::vector<std::string>::const_iterator cend = loaderNames.end();
      for( std::vector<std::string>::const_iterator citr = loaderNames.begin(); citr != cend;
	   ++citr )
      {
	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;
	  }
	}
      }
      if( !winningLoader )
      {
	throw std::runtime_error("Cannot find a loader for \"" + filePath + "\"");
      }
      return winningLoader;
    }
    /** This method set the algorithm as a child algorithm.
     *  @param alg :: The shared pointer to a  algorithm
     *  @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 enableLogging :: Set to false to disable logging from the child algorithm
     *  @param version ::  The version of the child algorithm to create. 
     *  By default gives the latest version.
     */
    void Load::initialiseLoadSubAlgorithm(API::IAlgorithm_sptr alg, 
					  const double startProgress, const double endProgress, 
					  const bool enableLogging, const int& version)
      (void) version; // Avoid compiler warning.
      //Set as a child so that we are in control of output storage
      alg->initialize();
      alg->setChild(true);
      alg->setLogging(enableLogging);

      // If output workspaces are nameless, give them a temporary name to satisfy validator
      const std::vector< Property*> &props = alg->getProperties();
      for (unsigned int i = 0; i < props.size(); ++i)
      {
	if (props[i]->direction() == 1 && dynamic_cast<IWorkspaceProperty*>(props[i]) )
	{
	  if ( props[i]->value().empty() ) props[i]->setValue("LoadChildWorkspace");
	}
      if (startProgress >= 0. && endProgress > startProgress && endProgress <= 1.)
	alg->addObserver(m_progressObserver);
	alg->setChildStartProgress(startProgress);
	alg->setChildEndProgress(endProgress);
     * Set the output workspace(s) if the load's return workspace
     *  has type API::Workspace
     *@param load :: shared pointer to load algorithm
     */
    void Load::setOutputWorkspace(API::IAlgorithm_sptr& load)
    {
	Workspace_sptr ws = load->getProperty("OutputWorkspace"); 
	WorkspaceGroup_sptr wsg = boost::dynamic_pointer_cast<WorkspaceGroup>(ws);
	if (wsg)
	{
	  setProperty("OutputWorkspace",ws);
	  std::vector<std::string> names = wsg->getNames();
	  for(size_t i = 0; i < names.size(); ++i)
	  {
	    std::ostringstream propName;
	    propName << "OutputWorkspace_" << (i+1);
	    DataObjects::Workspace2D_sptr memberwsws1 = load->getProperty(propName.str());
	    std::string memberwsName = load->getPropertyValue(propName.str());
	    declareProperty(new WorkspaceProperty<>(propName.str(),memberwsName,Direction::Output));
	    setProperty(propName.str(),boost::dynamic_pointer_cast<MatrixWorkspace>(memberwsws1));
	  }
	}
	else
	{ 
	  setProperty("OutputWorkspace",ws);
	}
	MatrixWorkspace_sptr mws=load->getProperty("OutputWorkspace");
	setProperty("OutputWorkspace",boost::dynamic_pointer_cast<Workspace>(mws));
  } // namespace DataHandling
} // namespace Mantid