Mantid
Loading...
Searching...
No Matches
LoadGSASInstrumentFile.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
11#include "MantidAPI/TableRow.h"
19
20#include <boost/algorithm/string.hpp>
21#include <boost/algorithm/string/finder.hpp>
22#include <boost/algorithm/string/iter_find.hpp>
23#include <boost/algorithm/string/predicate.hpp>
24#include <boost/algorithm/string/trim.hpp>
25
26#include <Poco/DOM/AutoPtr.h>
27#include <Poco/DOM/DOMWriter.h>
28#include <Poco/DOM/Element.h>
29
30#include <algorithm>
31#include <fstream>
32
33using namespace Mantid;
34using namespace Mantid::API;
35using namespace Mantid::DataObjects;
36using namespace Mantid::Kernel;
37using namespace std;
38using namespace Poco::XML;
39
42
43namespace Mantid::DataHandling {
44
46
47//----------------------------------------------------------------------------------------------
51 // Input file name
52 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Load, ".prm"),
53 "Path to an GSAS file to load.");
54
55 // Output table workspace
56 auto wsprop = std::make_unique<WorkspaceProperty<API::ITableWorkspace>>("OutputTableWorkspace", "", Direction::Output,
58 declareProperty(std::move(wsprop), "Name of the output TableWorkspace containing "
59 "instrument parameter information read from file. ");
60
61 // Use bank numbers as given in file
62 declareProperty(std::make_unique<PropertyWithValue<bool>>("UseBankIDsInFile", true, Direction::Input),
63 "Use bank IDs as given in file rather than ordinal number of bank. "
64 "If the bank IDs in the file are not unique, it is advised to set this "
65 "to false.");
66
67 // Bank to import
68 declareProperty(std::make_unique<ArrayProperty<int>>("Banks"), "ID(s) of specified bank(s) to load, "
69 "The IDs are as specified by UseBankIDsInFile. "
70 "Default is all banks contained in input .prm file.");
71
72 // Workspace to put parameters into. It must be a workspace group with one
73 // worskpace per bank from the prm file
74 declareProperty(
76 "A workspace group with the instrument to which we add the "
77 "parameters from the GSAS instrument file, with one "
78 "workspace for each bank of the .prm file");
79
80 // Workspaces for each bank
81 declareProperty(std::make_unique<ArrayProperty<int>>("WorkspacesForBanks"),
82 "For each bank,"
83 " the ID of the corresponding workspace in same order as the "
84 "banks are specified. "
85 "ID=1 refers to the first workspace in the workspace group, "
86 "ID=2 refers to the second workspace and so on. "
87 "Default is all workspaces in numerical order. "
88 "If default banks are specified, they too are taken to be in "
89 "numerical order");
90}
91
92//----------------------------------------------------------------------------------------------
96 // Get input
97 string datafile = getProperty("Filename");
98
99 // Import data
100 vector<string> lines;
101 loadFile(datafile, lines);
102
103 // Check Histogram type - only PNTR is currently supported
104 std::string histType = getHistogramType(lines);
105 if (histType != "PNTR") {
106 throw std::runtime_error("Error on checking histogram type: " + histType + "\n");
107 }
108
109 size_t numBanks = getNumberOfBanks(lines);
110 g_log.debug() << numBanks << "banks in file \n";
111
112 // Examine bank information
113 vector<size_t> bankStartIndex;
114 scanBanks(lines, bankStartIndex);
115
116 if (bankStartIndex.empty()) {
117 throw std::runtime_error("No nanks found in file. \n");
118 }
119
120 if (numBanks != bankStartIndex.size()) { // The stated number of banks does
121 // not equal the number of banks
122 // found
123 g_log.warning() << "The number of banks found" << bankStartIndex.size()
124 << "is not equal to the number of banks stated" << numBanks << ".\n";
125 g_log.warning() << "Number of banks found is used.";
126 numBanks = bankStartIndex.size();
127 }
128
129 // Parse banks and export profile parameters
130 map<size_t, map<string, double>> bankparammap;
131 for (size_t i = 0; i < numBanks; ++i) {
132 size_t bankid = i + 1;
133 g_log.debug() << "Parse bank " << bankid << " of total " << numBanks << ".\n";
134 map<string, double> parammap;
135 parseBank(parammap, lines, bankid, bankStartIndex[bankid - 1]);
136 bankparammap.emplace(bankid, parammap);
137 g_log.debug() << "Bank starts at line" << bankStartIndex[i] + 1 << "\n";
138 }
139
140 // Get Workspace property
141 WorkspaceGroup_sptr wsg = getProperty("Workspace");
142 // Generate output table workspace
143 API::ITableWorkspace_sptr outTabWs = genTableWorkspace(bankparammap);
144 if (!getPropertyValue("OutputTableWorkspace").empty()) {
145 // Output the output table workspace
146 setProperty("OutputTableWorkspace", outTabWs);
147 }
148 if (wsg) {
149 vector<int> bankIds = getProperty("Banks");
150 vector<int> workspaceIds = getProperty("WorkspacesForBanks");
151 map<int, size_t> workspaceOfBank;
152
153 // Deal with bankIds
154 if (!bankIds.empty()) {
155 // If user provided a list of banks, check that they exist in the .prm
156 // file
157 const auto it = std::find_if(bankIds.cbegin(), bankIds.cend(),
158 [&bankparammap](const auto &bankId) { return !bankparammap.count(bankId); });
159 if (it != bankIds.cend()) {
160 std::stringstream errorString;
161 errorString << "Bank " << (*it) << " not found in .prm file";
162 throw runtime_error(errorString.str());
163 }
164 } else {
165 // Else, use all available banks
166 bankIds.reserve(bankparammap.size());
167 std::transform(bankparammap.cbegin(), bankparammap.cend(), std::back_inserter(bankIds),
168 [](const auto &bank) { return static_cast<int>(bank.first); });
169 }
170
171 // Generate workspaceOfBank
172 LoadFullprofResolution::createBankToWorkspaceMap(bankIds, workspaceIds, workspaceOfBank);
173 // Put parameters into workspace group
175 for (size_t i = 0; i < bankIds.size(); ++i) {
176 int bankId = bankIds[i];
177 size_t wsId = workspaceOfBank[bankId];
178 Workspace_sptr wsi = wsg->getItem(wsId - 1);
179 auto workspace = std::dynamic_pointer_cast<MatrixWorkspace>(wsi);
180 // Get column from table workspace
181 API::Column_const_sptr OutTabColumn = outTabWs->getColumn(i + 1);
182 std::string parameterXMLString;
184 OutTabColumn, workspace, static_cast<int>(bankparammap[i]["NPROF"]), parameterXMLString);
185 // Load the string into the workspace
186 Algorithm_sptr loadParamAlg = createChildAlgorithm("LoadParameterFile");
187 loadParamAlg->setProperty("ParameterXML", parameterXMLString);
188 loadParamAlg->setProperty("Workspace", workspace);
189 loadParamAlg->execute();
190 }
191 }
192}
193
194//----------------------------------------------------------------------------------------------
199void LoadGSASInstrumentFile::loadFile(const string &filename, vector<string> &lines) {
200 ifstream myfile(filename.c_str());
201
202 if (myfile.is_open()) {
203 while (!myfile.eof()) {
204 string line;
205 getline(myfile, line);
206
207 boost::algorithm::trim(line);
208 if (!line.empty())
209 lines.emplace_back(line);
210 }
211
212 myfile.close();
213 } else {
214 stringstream errmsg;
215 errmsg << "Input .prm file " << filename << " cannot be open. ";
216 g_log.error(errmsg.str());
217 throw runtime_error(errmsg.str());
218 }
219}
220
221/* Get the histogram type
222 * @param lines :: vector of strings for each non-empty line in .irf file
223 * @return Histogram type code
224 */
225std::string LoadGSASInstrumentFile::getHistogramType(const vector<string> &lines) {
226 // We assume there is just one HTYPE line, look for it from beginning and
227 // return its value.
228 std::string lookFor = "INS HTYPE";
229 for (size_t i = 0; i < lines.size(); ++i) {
230 if (lines[i].substr(0, lookFor.size()) == lookFor) {
231 if (lines[i].size() < lookFor.size() + 7) {
232 // line too short
233 return "HTYPE line too short";
234 }
235 return lines[i].substr(lookFor.size() + 3, 4); // Found
236 }
237 }
238 return "HTYPE line not found";
239}
240
241/* Get number of banks
242 * @param lines :: vector of strings for each non-empty line in .irf file
243 * @return number of banks
244 */
245size_t LoadGSASInstrumentFile::getNumberOfBanks(const vector<string> &lines) {
246 // We assume there is just one BANK line, look for it from beginning and
247 // return its value.
248 std::string lookFor = "INS BANK";
249 for (size_t i = 0; i < lines.size(); ++i) {
250 if (lines[i].substr(0, lookFor.size()) == lookFor) {
251 if (lines[i].size() < lookFor.size() + 3) {
252 // line too short
253 return 0;
254 }
255 return boost::lexical_cast<size_t>(lines[i].substr(lookFor.size() + 2, 1)); // Found
256 }
257 }
258 return 0;
259}
260
266void LoadGSASInstrumentFile::scanBanks(const std::vector<std::string> &lines, std::vector<size_t> &bankStartIndex) {
267 // We look for each line that contains 'BNKPAR' and take it to be the first
268 // line of a bank.
269 // We currently ignore the bank number and assume they are numbered according
270 // to their order in the file.
271 for (size_t i = 0; i < lines.size(); ++i) {
272 string line = lines[i];
273 if (line.substr(0, 3) == "INS") { // Ignore all lines that don't begin with INS
274 if (line.find("BNKPAR") != string::npos) { // We've found start of a new bank
275 bankStartIndex.emplace_back(i);
276 }
277 } // INS
278 } // for(i)
279}
280
281//----------------------------------------------------------------------------------------------
289void LoadGSASInstrumentFile::parseBank(std::map<std::string, double> &parammap, const std::vector<std::string> &lines,
290 size_t bankid, size_t startlineindex) {
291 double param1, param2, param3, param4;
292
293 // We ignore the first lines of the bank
294 // The first useful line starts with "INS nPRCF", where n is the bank number
295 // From this line we get the profile function and number of parameters
296 size_t currentLineIndex = findINSPRCFLine(lines, startlineindex, param1, param2, param3, param4);
297
298 parammap["NPROF"] = param2;
299
300 // Ikeda-Carpenter PV
301 // Then read 15 parameters from the next four INS lines.
302 currentLineIndex = findINSPRCFLine(lines, currentLineIndex + 1, param1, param2, param3, param4);
303 parammap["Alph0"] = param1;
304 parammap["Alph1"] = param2;
305 parammap["Beta0"] = param3;
306 parammap["Beta1"] = param4; // Kappa
307
308 currentLineIndex = findINSPRCFLine(lines, currentLineIndex + 1, param1, param2, param3, param4);
309 parammap["Sig0"] = param1;
310 parammap["Sig1"] = param2;
311 parammap["Sig2"] = param3;
312 parammap["Gam0"] = param4;
313
314 findINSPRCFLine(lines, currentLineIndex + 1, param1, param2, param3, param4);
315 parammap["Gam1"] = param1;
316 parammap["Gam2"] = param2;
317 if (param3 != 0.0) {
318 g_log.warning() << "Bank" << bankid << "stec not 0, but " << param3;
319 }
320 if (param4 != 0.0) {
321 g_log.warning() << "Bank" << bankid << "ptec not 0, but " << param4;
322 }
323}
324
325//----------------------------------------------------------------------------------------------
336size_t LoadGSASInstrumentFile::findINSPRCFLine(const std::vector<std::string> &lines, size_t lineIndex, double &param1,
337 double &param2, double &param3, double &param4) {
338 for (size_t i = lineIndex; i < lines.size(); ++i) {
339 string line = lines[i];
340 if ((line.substr(0, 3) == "INS") && (line.substr(6, 4) == "PRCF")) {
341 std::istringstream paramLine;
342 paramLine.str(lines[i].substr(15));
343 paramLine >> param1 >> param2 >> param3 >> param4;
344 return i;
345 }
346 }
347 throw std::runtime_error("Unexpected end of file reached while searching for INS line. \n");
348}
349
350//----------------------------------------------------------------------------------------------
356TableWorkspace_sptr LoadGSASInstrumentFile::genTableWorkspace(map<size_t, map<string, double>> bankparammap) {
357 g_log.notice() << "Start to generate table workspace ...."
358 << ".\n";
359
360 // Retrieve some information
361 size_t numbanks = bankparammap.size();
362 if (numbanks == 0)
363 throw runtime_error("Unable to generate a table from an empty map!");
364
365 auto bankmapiter = bankparammap.begin();
366 size_t numparams = bankmapiter->second.size();
367
368 // vector of all parameter name
369 vector<string> vec_parname;
370 vector<size_t> vec_bankids;
371
372 map<string, double>::iterator parmapiter;
373 for (parmapiter = bankmapiter->second.begin(); parmapiter != bankmapiter->second.end(); ++parmapiter) {
374 string parname = parmapiter->first;
375 vec_parname.emplace_back(parname);
376 }
377
378 for (bankmapiter = bankparammap.begin(); bankmapiter != bankparammap.end(); ++bankmapiter) {
379 size_t bankid = bankmapiter->first;
380 vec_bankids.emplace_back(bankid);
381 }
382
383 g_log.debug() << "[DBx240] Number of imported parameters is " << numparams
384 << ", Number of banks = " << vec_bankids.size() << "."
385 << "\n";
386
387 // Create TableWorkspace
388 auto tablews = std::make_shared<TableWorkspace>();
389
390 // set columns :
391 // Any 2 columns cannot have the same name.
392 tablews->addColumn("str", "Name");
393 for (size_t i = 0; i < numbanks; ++i) {
394 stringstream colnamess;
395 size_t bankid = vec_bankids[i];
396 colnamess << "Value_" << bankid;
397 tablews->addColumn("double", colnamess.str());
398 }
399
400 g_log.debug() << "Number of column = " << tablews->columnCount() << ".\n";
401
402 // add BANK ID row
403 TableRow newrow = tablews->appendRow();
404 newrow << "BANK";
405 for (size_t i = 0; i < numbanks; ++i)
406 newrow << static_cast<double>(vec_bankids[i]);
407
408 g_log.debug() << "Number of row now = " << tablews->rowCount() << ".\n";
409
410 // add profile parameter rows
411 for (size_t i = 0; i < numparams; ++i) {
412 newrow = tablews->appendRow();
413
414 string parname = vec_parname[i];
415 newrow << parname;
416
417 for (size_t j = 0; j < numbanks; ++j) {
418 size_t bankid = vec_bankids[j];
419
420 // Locate map of bank 'bankid'
421 map<size_t, map<string, double>>::iterator bpmapiter;
422 bpmapiter = bankparammap.find(bankid);
423 if (bpmapiter == bankparammap.end()) {
424 throw runtime_error("Bank cannot be found in map.");
425 }
426
427 // Locate parameter
428 parmapiter = bpmapiter->second.find(parname);
429 if (parmapiter == bpmapiter->second.end()) {
430 throw runtime_error("Parameter cannot be found in a bank's map.");
431 } else {
432 double pvalue = parmapiter->second;
433 newrow << pvalue;
434 }
435
436 } // END(j)
437 } // END(i)
438
439 return tablews;
440}
441
442} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
IPeaksWorkspace_sptr workspace
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Kernel::Logger & g_log
Definition Algorithm.h:422
@ Load
allowed here which will be passed to the algorithm
TableRow represents a row in a TableWorkspace.
Definition TableRow.h:39
A property class for workspaces.
static void getTableRowNumbers(const API::ITableWorkspace_sptr &tablews, std::map< std::string, size_t > &parammap)
Get row numbers of the parameters in the table workspace.
static void putParametersIntoWorkspace(const API::Column_const_sptr &, const API::MatrixWorkspace_sptr &ws, int nProf, std::string &parameterXMLString)
Put parameters into a matrix workspace.
static void createBankToWorkspaceMap(const std::vector< int > &banks, const std::vector< int > &workspaces, std::map< int, size_t > &workspaceOfBank)
Create Bank to Workspace Correspondence.
static std::map< std::string, size_t > m_rowNumbers
Place to store the row numbers.
LoadGSASInstrumentFile : Load GSAS instrument file to TableWorkspace(s)
std::string getHistogramType(const std::vector< std::string > &lines)
Get Histogram type.
size_t findINSPRCFLine(const std::vector< std::string > &lines, size_t lineIndex, double &param1, double &param2, double &param3, double &param4)
Find first INS line at or after lineIndex.
size_t getNumberOfBanks(const std::vector< std::string > &lines)
Get Number of banks.
DataObjects::TableWorkspace_sptr genTableWorkspace(std::map< size_t, std::map< std::string, double > > bankparammap)
Generate output workspace.
void scanBanks(const std::vector< std::string > &lines, std::vector< size_t > &bankStartIndex)
Scan imported file for bank information.
void exec() override
Implement abstract Algorithm methods.
void loadFile(const std::string &filename, std::vector< std::string > &lines)
Load file to a vector of strings.
void parseBank(std::map< std::string, double > &parammap, const std::vector< std::string > &lines, size_t bankid, size_t startlineindex)
Parse bank in file to a map.
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void notice(const std::string &msg)
Logs at notice level.
Definition Logger.cpp:126
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
The concrete, templated class for properties.
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< const Column > Column_const_sptr
Definition Column.h:233
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition Algorithm.h:52
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
std::shared_ptr< Instrument > Instrument_sptr
Shared pointer to an instrument object.
Helper class which provides the Collimation Length for SANS instruments.
STL namespace.
@ InOut
Both an input & output workspace.
Definition Property.h:55
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54