Skip to content
Snippets Groups Projects
LoadGSASInstrumentFileTest.h 19 KiB
Newer Older
#ifndef MANTID_DATAHANDLING_LOADGSASINSTRUMENTFILETEST_H_
#define MANTID_DATAHANDLING_LOADGSASINSTRUMENTFILETEST_H_

#include <cxxtest/TestSuite.h>

#include "MantidDataHandling/LoadGSASInstrumentFile.h"
#include "MantidDataObjects/TableWorkspace.h"
#include "MantidAPI/TableRow.h"
#include "MantidDataHandling/LoadInstrument.h"
#include "MantidDataObjects/Workspace2D.h"
#include "MantidGeometry/Instrument.h"
#include "MantidGeometry/Instrument/Component.h"
#include "MantidGeometry/Instrument/FitParameter.h"
#include <fstream>
#include <Poco/File.h>

using Mantid::DataHandling::LoadGSASInstrumentFile;

using namespace Mantid;
using namespace Mantid::DataHandling;
using namespace Mantid::DataObjects;
using namespace Mantid::Kernel;
using namespace Mantid::API;

using namespace std;

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

  //----------------------------------------------------------------------------------------------
  /** Test import from a 1-bank prm file
    */
  void test_1BankCase()
  {
    // 1. Generate file
    string filename("Test1Bank.prm");
    generate1BankPrmFile(filename);

    // 2. Load
    LoadGSASInstrumentFile alg;
    alg.initialize();

    alg.setProperty("Filename", filename);
    alg.setProperty("OutputTableWorkspace", "Test1BankTable");

    TS_ASSERT_THROWS_NOTHING(alg.execute());
    TS_ASSERT(alg.isExecuted());

    TableWorkspace_sptr outws = boost::dynamic_pointer_cast<TableWorkspace>(
    AnalysisDataService::Instance().retrieve("Test1BankTable"));
    TS_ASSERT(outws);

    TS_ASSERT_EQUALS(outws->columnCount(), 2);
    TS_ASSERT_EQUALS(outws->rowCount(), getExpectedNumberOfRows() );

    // 3. Verify name and value
    map<string, double> parammap;
    parseTableWorkspace(outws, parammap);

    TS_ASSERT_EQUALS(parammap.count("Beta0"),1);
    TS_ASSERT_EQUALS(parammap.count("Sig1"),1);
    TS_ASSERT_EQUALS(parammap.count("Gam1"),1);

    TS_ASSERT_DELTA(parammap["Beta0"], 31.793, 0.001);
    TS_ASSERT_DELTA(parammap["Sig1"], 176.802, 0.001);
    TS_ASSERT_DELTA(parammap["Gam1"], 0.007, 0.0001);

    // 4. Clean
    AnalysisDataService::Instance().remove("Test1BankTable");
    Poco::File("Test1Bank.prm").remove();

    return;
  }

  //----------------------------------------------------------------------------------------------
  /** Test import from a 2-bank prm file
    */
  void test_2BankCase()
  {
    // 1. Generate file
    string filename("Test2Bank.prm");
    generate2BankPrmFile(filename);

    // 2. Load
    LoadGSASInstrumentFile alg;
    alg.initialize();

    alg.setProperty("Filename", filename);
    alg.setProperty("OutputTableWorkspace", "Test2BankTable");

    TS_ASSERT_THROWS_NOTHING(alg.execute());
    TS_ASSERT(alg.isExecuted());

    TableWorkspace_sptr outws = boost::dynamic_pointer_cast<TableWorkspace>(
    AnalysisDataService::Instance().retrieve("Test2BankTable"));
    TS_ASSERT(outws);

    TS_ASSERT_EQUALS(outws->columnCount(), 3);
    TS_ASSERT_EQUALS(outws->rowCount(), getExpectedNumberOfRows());

    // 3. Verify name and value
    map<string, double> parammap1;
    parseTableWorkspace(outws, parammap1);
    TS_ASSERT_EQUALS(parammap1.count("Alph1"),1);
    TS_ASSERT_EQUALS(parammap1.count("Sig2"),1);
    TS_ASSERT_EQUALS(parammap1.count("Gam1"),1);

    TS_ASSERT_DELTA(parammap1["Alph1"], 0.21, 0.0001);
    TS_ASSERT_DELTA(parammap1["Sig2"], 0.0, 0.0001);
    TS_ASSERT_DELTA(parammap1["Gam1"], 0.007, 0.00001);

    map<string, double> parammap2;
    parseTableWorkspace2(outws, parammap2);
    TS_ASSERT_EQUALS(parammap2.count("Alph1"),1);
    TS_ASSERT_EQUALS(parammap2.count("Sig2"),1);
    TS_ASSERT_EQUALS(parammap2.count("Gam1"),1);

    TS_ASSERT_DELTA(parammap2["Alph1"], 0.22, 0.0001);
    TS_ASSERT_DELTA(parammap2["Sig2"], -1.34662, 0.0001);
    TS_ASSERT_DELTA(parammap2["Gam1"], 3.61229, 0.00001);

    // 4. Clean
    AnalysisDataService::Instance().remove("Test2BankTable");
    Poco::File("Test2Bank.prm").remove();

    return;
  }

  //----------------------------------------------------------------------------------------------
  /** Test import of ALFBE, GAMMA and SIGMA parameters
  *   and check they are given their expected names.
  */
  void test_ags_parameters()
  {
    // 1. Generate file
    string filename("TestAGS.prm");
    generate1BankPrmFile(filename);

    // 2. Load
    LoadGSASInstrumentFile alg;
    alg.initialize();

    alg.setProperty("Filename", filename);
    alg.setProperty("OutputTableWorkspace", "TestAGSTable");

    TS_ASSERT_THROWS_NOTHING(alg.execute());
    TS_ASSERT(alg.isExecuted());

    TableWorkspace_sptr outws = boost::dynamic_pointer_cast<TableWorkspace>(
    AnalysisDataService::Instance().retrieve("TestAGSTable"));
    TS_ASSERT(outws);

    // 3. Verify names 
    map<string, double> parammap;
    parseTableWorkspace(outws, parammap);

    // 3a. ALFBE
    TS_ASSERT_EQUALS(parammap.count("Alph0"),1);
    TS_ASSERT_EQUALS(parammap.count("Beta0"),1);
    TS_ASSERT_EQUALS(parammap.count("Alph1"),1);
    TS_ASSERT_EQUALS(parammap.count("Beta1"),1);
    // 3b. GAMMA
    TS_ASSERT_EQUALS(parammap.count("Gam2"),1);
    TS_ASSERT_EQUALS(parammap.count("Gam1"),1);
    TS_ASSERT_EQUALS(parammap.count("Gam0"),1);
    // 3c. SIGMA
    TS_ASSERT_EQUALS(parammap.count("Sig2"),1);
    TS_ASSERT_EQUALS(parammap.count("Sig1"),1);
    TS_ASSERT_EQUALS(parammap.count("Sig0"),1);

    // 4. Clean
    AnalysisDataService::Instance().remove("TestAGSTable");
    Poco::File("TestAGS.prm").remove();

    return;
  }

  //----------------------------------------------------------------------------------------------
  /** Test invalid histrogram type
    */
  void test_Invalid_Histogram_Type()
  {
    // Generate file
    string filename("TestBadHistogramType.prm");
    generateBadHistogramTypePrmFile(filename);

    // Initialise and set Properties
    LoadGSASInstrumentFile alg;
    alg.initialize();
    alg.setProperty("Filename", filename);
    alg.setProperty("OutputTableWorkspace", "TestBadHistogramTable");

   // Execute and check that execution failed
    alg.execute();
    TS_ASSERT(!alg.isExecuted());

    // 3. Clean
    Poco::File("TestBadHistogramType.prm").remove();

    return;
  }

  void test_workspace()
  {
    // Generate file with two banks
    string filename("GSASInstrumentFileTest_TestWorkspace.irf");
    generate2BankPrmFile(filename);

    // Create workspace group to put parameters into
    // This is a group of two workspaces
    createWorkspaceGroup(2,"loadGSASInstrumentFileWorkspace");

    // Set up algorithm to load into the workspace
    LoadGSASInstrumentFile alg;
    alg.initialize();
    alg.setProperty("Filename", filename);
    alg.setPropertyValue("Banks", "1,2");
    alg.setProperty("Workspace", wsName);

    // Execute
    TS_ASSERT_THROWS_NOTHING(alg.execute());
    TS_ASSERT(alg.isExecuted());

    // Check parameters in output workspace 
    // The output workspace is a workspace group with each 
    // member corresponding to each of the one banks in the prm file

    // First, check first workspace
    WorkspaceGroup_sptr gws;
    gws = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(wsName);
    auto ws = boost::dynamic_pointer_cast<MatrixWorkspace>(gws->getItem(0));
    Mantid::Geometry::ParameterMap& paramMap = ws->instrumentParameters();
    boost::shared_ptr<const Mantid::Geometry::Instrument> instr = ws->getInstrument();

    // To check parameters in workspace
    Mantid::Geometry::FitParameter fitParam;
    Mantid::Geometry::Parameter_sptr param;

    // Check Alpha0 parameter    
    param = paramMap.get(&(*instr), "Alpha0", "fitting");
    fitParam = param->value<Mantid::Geometry::FitParameter>();
    TS_ASSERT_EQUALS( boost::lexical_cast<double>(fitParam.getFormula()), 0.00);
    // Check Alpha1 parameter
    param = paramMap.get(&(*instr), "Alpha1", "fitting");
    fitParam = param->value<Mantid::Geometry::FitParameter>();
    TS_ASSERT_EQUALS( boost::lexical_cast<double>(fitParam.getFormula()), 0.21);
    // Check Beta0 parameter
    param = paramMap.get(&(*instr), "Beta0", "fitting");
    fitParam = param->value<Mantid::Geometry::FitParameter>();
    TS_ASSERT_EQUALS( boost::lexical_cast<double>(fitParam.getFormula()), 31.7927);
    // Check Beta1 parameter
    param = paramMap.get(&(*instr), "Kappa", "fitting");
    fitParam = param->value<Mantid::Geometry::FitParameter>();
    TS_ASSERT_EQUALS( boost::lexical_cast<double>(fitParam.getFormula()), 51.4205);
    // Check SigmsSquared parameter
    // This is a formula, so values are not exact
    param = paramMap.get(&(*instr), "SigmaSquared", "fitting");
    fitParam = param->value<Mantid::Geometry::FitParameter>();
    TS_ASSERT_DELTA( fitParam.getValue(0.0), 0.01, 0.000001);
    TS_ASSERT_DELTA( fitParam.getValue(0.5), 7814.7468, 0.000001);
    // Check Gamma parameter
    // Although this is a formula, all coefficients should be zero
    // and so values should be exactly 0 as well
    param = paramMap.get(&(*instr), "Gamma", "fitting");
    fitParam = param->value<Mantid::Geometry::FitParameter>();
    TS_ASSERT_EQUALS( fitParam.getValue( 0.0 ), 0.0);
    TS_ASSERT_EQUALS( fitParam.getValue( 0.0 ), 0.0);


    // Now check second workspace
    ws = boost::dynamic_pointer_cast<MatrixWorkspace>(gws->getItem(1));
    Mantid::Geometry::ParameterMap& paramMap2 = ws->instrumentParameters();
    instr = ws->getInstrument();

    // Check Alpha0 parameter
    param = paramMap2.get(&(*instr), "Alpha0", "fitting");
    fitParam = param->value<Mantid::Geometry::FitParameter>();
    TS_ASSERT_EQUALS( boost::lexical_cast<double>(fitParam.getFormula()), 0.001);
    // Check Alpha1 parameter
    param = paramMap2.get(&(*instr), "Alpha1", "fitting");
    fitParam = param->value<Mantid::Geometry::FitParameter>();
    TS_ASSERT_EQUALS( boost::lexical_cast<double>(fitParam.getFormula()), 0.22);
    // Check Beta0 parameter
    param = paramMap2.get(&(*instr), "Beta0", "fitting");
    fitParam = param->value<Mantid::Geometry::FitParameter>();
    TS_ASSERT_EQUALS( boost::lexical_cast<double>(fitParam.getFormula()), 32.7927);
    // Check Beta1 parameter
    param = paramMap2.get(&(*instr), "Kappa", "fitting");
    fitParam = param->value<Mantid::Geometry::FitParameter>();
    TS_ASSERT_EQUALS( boost::lexical_cast<double>(fitParam.getFormula()), 52.4205);
    // Check SigmsSquared parameter
    // This is a formula, so values are not exact
    param = paramMap2.get(&(*instr), "SigmaSquared", "fitting");
    fitParam = param->value<Mantid::Geometry::FitParameter>();
    TS_ASSERT_DELTA( fitParam.getValue(0.0), 0.04, 0.000001);
    TS_ASSERT_DELTA( fitParam.getValue(0.5), 21840.741796, 0.000001);
    // Check Gamma parameter
    // Although this is a formula, all coefficients should be zero
    // and so values should be exactly 0 as well
    param = paramMap2.get(&(*instr), "Gamma", "fitting");
    fitParam = param->value<Mantid::Geometry::FitParameter>();
    TS_ASSERT_EQUALS( fitParam.getValue( 0.0 ), 0.0);
    TS_ASSERT_EQUALS( fitParam.getValue( 0.0 ), 0.0);

    // Clean
    Poco::File(filename).remove();
    AnalysisDataService::Instance().remove("loadGSASInstrumentFileWorkspace");
  }

  //----------------------------------------------------------------------------------------------
  /** Parse a TableWorkspace to a map
    */
  void parseTableWorkspace(TableWorkspace_sptr tablews, map<string, double>& parammap)
  {
    parammap.clear();

    size_t numrows = tablews->rowCount();
    for (size_t i = 0; i < numrows; ++i)
    {
      TableRow row = tablews->getRow(i);
      double value;
      string name;
      row >> name >> value;
      parammap.insert(make_pair(name, value));
    }

    return;
  }


  //----------------------------------------------------------------------------------------------
  /** Parse a TableWorkspace's 2nd bank to a map
    */
  void parseTableWorkspace2(TableWorkspace_sptr tablews, map<string, double>& parammap)
  {
    parammap.clear();

    size_t numrows = tablews->rowCount();
    for (size_t i = 0; i < numrows; ++i)
    {
      TableRow row = tablews->getRow(i);
      double value1, value2;
      string name;
      row >> name >> value1 >> value2;
      parammap.insert(make_pair(name, value2));
    }

    return;
  }

  //----------------------------------------------------------------------------------------------
  /** Generate a 1 bank .prm file
    */
  void generate1BankPrmFile(string filename)
  {
    ofstream ofile;
    ofile.open(filename.c_str());

    if (ofile.is_open())
    {
      ofile << "COMM  Test file with one bank       \n";
      ofile << "INS   BANK  1                                                                  \n";
      ofile << "INS   HTYPE   PNTR      \n";
      ofile << "COMM5678901234567890                                                           \n";
      ofile << "INS  1 ICONS    746.96     -0.24      3.04                                     \n";
      ofile << "INS  1BNKPAR    2.3696      9.39      0.00    .00000     .3000    1    1       \n";
      ofile << "INS  1I ITYP    0    1.000     25.000       2                                  \n";
      ofile << "INS  1I HEAD   TIC 8983 on HRPD                                                \n";
      ofile << "INS  1PRCF      2   15   0.00100                                               \n";
      ofile << "COMM The next 15 parameters as in wiki page CreateIkedaCarpenterParametersGSAS \n";
      ofile << "INS  1PRCF 1   0.000000E+00   0.210000E+00   0.317927E+02   0.514205E+02       \n";
      ofile << "INS  1PRCF 2   0.100000E+00   0.176802E+03   0.000000E+00   0.000000E+00       \n";
      ofile << "INS  1PRCF 3   0.007000E+00   0.008000E+00   0.000000E+00   0.000000E+00       \n";
      ofile << "INS  1PRCF 4   0.000000E+00   0.000000E+00   0.000000E+00                      \n";
      ofile.close();
    }
    else
    {
      throw runtime_error("Unable to open file to write.");
    }

    return;
  }

  //----------------------------------------------------------------------------------------------
  /** Generate a 2 bank .irf file
    */
  void generate2BankPrmFile(string filename)
  {
    ofstream ofile;
    ofile.open(filename.c_str());

    if (ofile.is_open())
    {
      ofile << "COMM  Test file with two banks       \n";
      ofile << "INS   BANK  2                                                                  \n";
      ofile << "INS   HTYPE   PNTR      \n";
      ofile << "COMM5678901234567890                                                           \n";
      ofile << "INS  1 ICONS    746.96     -0.24      3.04                                     \n";
      ofile << "INS  1BNKPAR    2.3696      9.39      0.00    .00000     .3000    1    1       \n";
      ofile << "INS  1I ITYP    0    1.000     25.000       2                                  \n";
      ofile << "INS  1PRCF      2   15   0.00100                                               \n";
      ofile << "INS  1PRCF 1   0.000000E+00   0.210000E+00   0.317927E+02   0.514205E+02       \n";
      ofile << "INS  1PRCF 2   0.100000E+00   0.176802E+03   0.000000E+00   0.000000E+00       \n";
      ofile << "INS  1PRCF 3   0.007000E+00   0.000000E+00   0.000000E+00   0.000000E+00       \n";
      ofile << "INS  1PRCF 4   0.000000E+00   0.000000E+00   0.000000E+00                      \n";
      ofile << "INS  2 ICONS   1482.98      0.98     12.65                                     \n";
      ofile << "INS  2BNKPAR    1.7714     17.98      0.00    .00000     .3000    1    1       \n";
      ofile << "INS  2I ITYP    0    1.000     21.000       2                                  \n";
      ofile << "INS  2PRCF      2   15   0.00100                                               \n";
      ofile << "INS  2PRCF 1   0.001000E+00   0.220000E+00   0.327927E+02   0.524205E+02       \n";
      ofile << "INS  2PRCF 2   0.200000E+00   0.295572E+03  -0.134662E+01   0.000000E+00       \n";
      ofile << "INS  2PRCF 3   0.361229E+01   0.000000E+00   0.000000E+00   0.000000E+00       \n";
      ofile << "INS  2PRCF 4   0.000000E+00   0.000000E+00   0.000000E+00                      \n";
      ofile.close();
    }
    else
    {
      throw runtime_error("Unable to open file to write.");
    }

    return;
  }

    //----------------------------------------------------------------------------------------------
  /** Generate a 1 bank .prm file
    */
  void generateBadHistogramTypePrmFile(string filename)
  {
    ofstream ofile;
    ofile.open(filename.c_str());

    if (ofile.is_open())
    {
      ofile << "COMM  Test file with one bank       \n";
      ofile << "INS   BANK  1                                                                  \n";
      ofile << "INS   HTYPE   BLOG      \n";
      ofile << "COMM5678901234567890                                                           \n";
      ofile << "INS  1 ICONS    746.96     -0.24      3.04                                     \n";
      ofile << "INS  1BNKPAR    2.3696      9.39      0.00    .00000     .3000    1    1       \n";
      ofile << "INS  1I ITYP    0    1.000     25.000       2                                  \n";
      ofile << "INS  1PRCF      2   15   0.00100                                               \n";
      ofile << "COMM The next 15 parameters as in wiki page CreateIkedaCarpenterParametersGSAS \n";
      ofile << "INS  1PRCF 1   0.000000E+00   0.210000E+00   0.317927E+02   0.514205E+02       \n";
      ofile << "INS  1PRCF 2   0.100000E+00   0.176802E+03   0.000000E+00   0.000000E+00       \n";
      ofile << "INS  1PRCF 3   0.007000E+00   0.008000E+00   0.000000E+00   0.000000E+00       \n";
      ofile << "INS  1PRCF 4   0.000000E+00   0.000000E+00   0.000000E+00                      \n";
      ofile.close();
    }
    else
    {
      throw runtime_error("Unable to open file to write.");
    }

    return;
  }

    //----------------------------------------------------------------------------------------------
  /** Create a workspace group with specified number of workspaces.
    */
  void createWorkspaceGroup( size_t numberOfWorkspaces, std::string workspaceName)
  {
    // create a workspace with some sample data
    WorkspaceGroup_sptr gws(new API::WorkspaceGroup);

    for (size_t i=0; i < numberOfWorkspaces; ++i)
    {
      Workspace_sptr ws = WorkspaceFactory::Instance().create("Workspace2D",1,1,1);
      Workspace2D_sptr ws2D = boost::dynamic_pointer_cast<Workspace2D>(ws);
      gws->addWorkspace( ws2D );
    }

    // put this workspace in the analysis data service
    TS_ASSERT_THROWS_NOTHING(AnalysisDataService::Instance().add(workspaceName, gws));

    // save workspace name
    wsName = workspaceName;
  }

  /* Return the number of rows the table must have
  */
  int getExpectedNumberOfRows()
  {
    return 12;  // Change this value if you add or remove any rows from the OutputTableWorkspace
  }

  private:
    std::string wsName;  // For workspace property

};


#endif /* MANTID_DATAHANDLING_LOADGSASINSTRUMENTFILETEST_H_ */