19#include <boost/algorithm/string.hpp>
21#include <Poco/DOM/AutoPtr.h>
22#include <Poco/DOM/DOMParser.h>
23#include <Poco/DOM/Document.h>
24#include <Poco/DOM/NamedNodeMap.h>
25#include <Poco/DOM/Node.h>
26#include <Poco/DOM/NodeFilter.h>
27#include <Poco/DOM/NodeIterator.h>
28#include <Poco/DOM/NodeList.h>
29#include <Poco/SAX/InputSource.h>
67 const std::string &nodedescription) {
69 if (nodetype ==
"FLOAT32") {
72 }
else if (nodetype ==
"INT32") {
78 if (!nodeunit.empty()) {
83 if (!nodedescription.empty())
142 : m_detXMLFileName(), m_detXMLNodeName(), m_numPixelX(0), m_numPixelY(0), m_loadInstrument(false),
143 m_detSampleDistanceShift(0.0), m_hasScanTable(false), m_ptNumber4Log(0), m_idfFileName() {}
156 return "Load 2-dimensional detector data file in XML format from SPICE. ";
163 std::vector<std::string> exts;
164 exts.emplace_back(
".xml");
165 exts.emplace_back(
".bin");
167 "XML file name for one scan including 2D detectors counts from SPICE");
170 "Name of output matrix workspace. "
171 "Output workspace will be an X by Y Workspace2D if instrument "
175 "Log name (i.e., XML node name) for detector counts in XML file."
176 "By default, the name is 'Detector'");
179 "A size-2 unsigned integer array [X, Y] for detector geometry. "
180 "Such that the detector contains X x Y pixels."
181 "If the input data is a binary file, input for DetectorGeometry will be "
183 "by detector geometry specified in the binary file");
186 "Flag to load instrument to output workspace. "
187 "HFIR's HB3A will be loaded if InstrumentFileName is not specified.");
190 "The filename (including its full or relative path) of an instrument "
191 "definition file. The file extension must either be .xml or .XML when "
192 "specifying an instrument definition file. Note Filename or "
193 "InstrumentName must be specified but not both.");
197 "Name of TableWorkspace loaded from SPICE scan file by LoadSpiceAscii.");
199 declareProperty(
"PtNumber", 0,
"Pt. value for the row to get sample log from. ");
202 "User can specify the wave length of the instrument if it is "
203 "drifted from the designed value."
204 "It happens often.");
207 "Amount of shift of the distance between source and detector centre."
208 "It is used to apply instrument calibration.");
211 "The amount of shift of "
212 "detector center along X "
213 "direction in the unit meter.");
216 "The amount of shift of "
217 "detector center along Y "
218 "direction in the unit meter.");
227 std::vector<size_t> vec_pixelgeom =
getProperty(
"DetectorGeometry");
228 if (vec_pixelgeom.size() == 2) {
231 }
else if (vec_pixelgeom.empty()) {
235 throw std::runtime_error(
"Input pixels geometry is not correct in format. "
236 "It either has 2 integers or left empty to get "
237 "determined automatically.");
248 if (!spicetablewsname.empty())
273 Types::Core::DateAndTime anytime(1000);
276 bool return_true =
true;
277 if (!outws->run().hasProperty(
"2theta") && outws->run().hasProperty(
"_2theta")) {
279 double logvalue = std::stod(outws->run().getProperty(
"_2theta")->value());
281 newlogproperty->
addValue(anytime, logvalue);
282 outws->mutableRun().addProperty(newlogproperty);
283 g_log.
information() <<
"Set 2theta from _2theta (as XML node) with value " << logvalue <<
"\n";
284 }
else if (!outws->run().hasProperty(
"2theta") && !outws->run().hasProperty(
"_2theta")) {
286 g_log.
warning(
"No 2theta is set up for loading instrument.");
293 outws->mutableRun().addProperty(det_dx);
297 outws->mutableRun().addProperty(det_dy);
302 distproperty->
addValue(anytime, sampledetdistance);
303 outws->mutableRun().addProperty(distproperty);
342 bool has_wavelength = !(wavelength ==
EMPTY_DBL());
346 if (has_wavelength) {
361 std::vector<SpiceXMLNode> vecspicenode;
365 ifs.open(xmlfilename.c_str());
366 if (!ifs.is_open()) {
367 std::stringstream ess;
368 ess <<
"File " << xmlfilename <<
" cannot be opened.";
369 throw std::runtime_error(ess.str());
373 Poco::XML::InputSource src(ifs);
375 Poco::XML::DOMParser parser;
376 Poco::AutoPtr<Poco::XML::Document> pDoc = parser.parse(&src);
379 Poco::XML::NodeIterator nodeIter(pDoc, Poco::XML::NodeFilter::SHOW_ELEMENT);
380 Poco::XML::Node *pNode = nodeIter.nextNode();
382 const Poco::XML::XMLString nodename = pNode->nodeName();
385 Poco::AutoPtr<Poco::XML::NodeList> children = pNode->childNodes();
386 const size_t numchildren = children->length();
387 if (numchildren > 1) {
388 g_log.
debug() <<
"Parent node " << nodename <<
" has " << numchildren <<
" children."
390 if (nodename ==
"SPICErack") {
392 Poco::AutoPtr<Poco::XML::NamedNodeMap> attributes = pNode->attributes();
393 unsigned long numattr = attributes->length();
394 for (
unsigned long j = 0; j < numattr; ++j) {
395 std::string attname = attributes->item(j)->nodeName();
396 std::string attvalue = attributes->item(j)->innerText();
399 vecspicenode.emplace_back(xmlnode);
400 g_log.
debug() <<
"SPICErack attribute " << j <<
" Name = " << attname <<
", Value = " << attvalue <<
"\n";
404 }
else if (numchildren == 1) {
405 std::string innertext = pNode->innerText();
406 Poco::AutoPtr<Poco::XML::NamedNodeMap> attributes = pNode->attributes();
407 unsigned long numattr = attributes->length();
408 g_log.
debug() <<
" Child node " << nodename <<
"'s attributes: "
412 std::string nodetype;
413 std::string nodeunit;
414 std::string nodedescription;
416 for (
unsigned long j = 0; j < numattr; ++j) {
417 std::string atttext = attributes->item(j)->innerText();
418 std::string attname = attributes->item(j)->nodeName();
419 g_log.
debug() <<
" attribute " << j <<
" name = " << attname <<
", "
420 <<
"value = " << atttext <<
"\n";
421 if (attname ==
"type") {
424 }
else if (attname ==
"unit") {
427 }
else if (attname ==
"description") {
429 nodedescription = atttext;
435 vecspicenode.emplace_back(xmlnode);
442 pNode = nodeIter.nextNode();
455 ifstream infile(binary_file_name.c_str(), ios::binary);
456 streampos begin, end;
457 begin = infile.tellg();
458 infile.seekg(0, ios::end);
459 end = infile.tellg();
462 size_t num_unsigned_int =
static_cast<size_t>(end - begin) /
sizeof(
unsigned int);
463 if (num_unsigned_int <= 2)
464 throw std::runtime_error(
"Input binary file size is too small (<= 2 unsigned int)");
466 size_t num_dets = num_unsigned_int - 2;
467 g_log.
information() <<
"File contains " << num_unsigned_int <<
" unsigned integers and thus " << num_dets
471 std::vector<unsigned int> vec_counts(num_dets);
472 infile.seekg(0, ios::beg);
478 unsigned int total_counts(0);
481 infile.read((
char *)&buffer,
sizeof(buffer));
482 auto num_rows =
static_cast<size_t>(buffer);
483 infile.read((
char *)&buffer,
sizeof(buffer));
484 auto num_cols =
static_cast<size_t>(buffer);
485 if (num_rows * num_cols != num_dets) {
486 g_log.
error() <<
"Input binary file " << binary_file_name <<
" has inconsistent specification "
487 <<
"on detector size. "
488 <<
"First 2 unsigned integers are " << num_rows <<
", " << num_cols
489 <<
", while the detector number specified in the file is " << num_dets <<
"\n";
490 throw std::runtime_error(
"Input binary file has inconsistent specification on detector size.");
493 for (
size_t i = 0; i < num_dets; ++i) {
495 infile.read((
char *)&buffer,
sizeof(buffer));
496 vec_counts[i] = buffer;
497 total_counts += buffer;
500 g_log.
information() <<
"For detector " << num_rows <<
" x " << num_cols <<
", total counts = " << total_counts
509 size_t numspec = vec_counts.size();
516 for (
size_t i = 0; i < numspec; ++i) {
517 outws->mutableX(i)[0] = 0.;
518 outws->mutableX(i)[1] = 1;
519 auto counts =
static_cast<double>(vec_counts[i]);
520 outws->mutableY(i)[0] = counts;
522 outws->mutableE(i)[0] = sqrt(counts);
524 outws->mutableE(i)[0] = 1.0;
542 const size_t &numpixelx,
const size_t &numpixely,
543 const std::string &detnodename,
const bool &loadinstrument) {
550 if (loadinstrument) {
551 size_t numspec = numpixelx * numpixely;
555 outws = std::dynamic_pointer_cast<MatrixWorkspace>(
560 size_t numxmlnodes = vecxmlnode.size();
561 bool parsedDet =
false;
562 double max_counts = 0.;
563 for (
size_t n = 0;
n < numxmlnodes; ++
n) {
566 if (xmlnode.
getName() == detnodename) {
568 const std::string detvaluestr = xmlnode.
getValue();
571 std::vector<std::string> vecLines;
572 boost::split(vecLines, detvaluestr, boost::algorithm::is_any_of(
"\n"));
573 g_log.
debug() <<
"There are " << vecLines.size() <<
" lines"
578 for (
size_t i = 0; i < vecLines.size(); ++i) {
579 std::string &line = vecLines[i];
583 g_log.
debug() <<
"\tFound empty Line at " << i <<
"\n";
588 if (i_col == numpixelx) {
589 std::stringstream errss;
590 errss <<
"Number of non-empty rows (" << i_col + 1 <<
") in detector data "
591 <<
"exceeds user defined geometry size " << numpixelx <<
".";
592 throw std::runtime_error(errss.str());
596 std::vector<std::string> veccounts;
597 boost::split(veccounts, line, boost::algorithm::is_any_of(
" \t"));
601 if (veccounts.size() != numpixely) {
602 std::stringstream errss;
603 errss <<
"[Version 1] Row " << i_col <<
" contains " << veccounts.size() <<
" items other than " << numpixely
604 <<
" counts specified by user.";
605 throw std::runtime_error(errss.str());
609 for (
size_t j_row = 0; j_row < veccounts.size(); ++j_row) {
610 double counts = std::stod(veccounts[j_row]);
611 size_t rowIndex, columnIndex;
613 if (loadinstrument) {
615 rowIndex = i_col * numpixelx + j_row;
622 outws->mutableX(rowIndex)[columnIndex] =
static_cast<double>(columnIndex);
623 outws->mutableY(rowIndex)[columnIndex] = counts;
626 outws->mutableE(rowIndex)[columnIndex] = sqrt(counts);
628 outws->mutableE(rowIndex)[columnIndex] = 1.0;
631 if (counts > max_counts) {
645 const std::string nodename = xmlnode.
getName();
646 const std::string nodevalue = xmlnode.
getValue();
648 double dvalue = std::stod(nodevalue);
650 g_log.
debug() <<
"Log name / xml node : " << xmlnode.
getName() <<
" (double) value = " << dvalue <<
"\n";
652 int ivalue = std::stoi(nodevalue);
654 g_log.
debug() <<
"Log name / xml node : " << xmlnode.
getName() <<
" (int) value = " << ivalue <<
"\n";
656 std::string str_value(nodevalue);
657 if (nodename ==
"start_time") {
659 str_value = nodevalue;
660 str_value.replace(10, 1,
"T");
661 g_log.
debug() <<
"Replace start_time " << nodevalue <<
" by Mantid time format " << str_value <<
"\n";
670 std::stringstream errss;
671 errss <<
"Unable to find an XML node of name " << detnodename <<
". Unable to load 2D detector XML file.";
672 throw std::runtime_error(errss.str());
675 g_log.
notice() <<
"Maximum detector count on it is " << max_counts <<
"\n";
685 const std::string &detnodename,
const bool &loadinstrument) {
691 size_t numxmlnodes = vecxmlnode.size();
692 bool parsedDet =
false;
693 double max_counts = 0.;
696 std::map<std::string, std::string> str_log_map;
697 std::map<std::string, double> dbl_log_map;
698 std::map<std::string, int> int_log_map;
700 for (
size_t n = 0;
n < numxmlnodes; ++
n) {
703 if (xmlnode.
getName() == detnodename) {
705 const std::string detvaluestr = xmlnode.
getValue();
714 const std::string nodename = xmlnode.
getName();
715 const std::string nodevalue = xmlnode.
getValue();
717 double dvalue = std::stod(nodevalue);
718 dbl_log_map.emplace(nodename, dvalue);
720 int ivalue = std::stoi(nodevalue);
721 int_log_map.emplace(nodename, ivalue);
723 if (nodename ==
"start_time") {
725 std::string str_value(nodevalue);
726 str_value.replace(10, 1,
"T");
727 g_log.
debug() <<
"Replace start_time " << nodevalue <<
" by Mantid time format " << str_value <<
"\n";
728 str_log_map.emplace(nodename, str_value);
730 str_log_map.emplace(nodename, nodevalue);
737 for (
auto &log_entry : str_log_map) {
740 for (
auto &log_entry : int_log_map) {
743 for (
auto &log_entry : dbl_log_map) {
750 std::stringstream errss;
751 errss <<
"Unable to find an XML node of name " << detnodename <<
". Unable to load 2D detector XML file.";
752 throw std::runtime_error(errss.str());
755 g_log.
notice() <<
"Maximum detector count on it is " << max_counts <<
"\n";
761 double &max_counts) {
763 std::vector<std::string> vecLines;
764 boost::split(vecLines, detvaluestr, boost::algorithm::is_any_of(
"\n"));
765 g_log.
debug() <<
"There are " << vecLines.size() <<
" lines"
770 size_t num_empty_line = 0;
771 size_t num_weird_line = 0;
772 for (
auto &vecLine : vecLines) {
775 else if (vecLine.size() < 100)
778 size_t num_pixel_x = vecLines.size() - num_empty_line - num_weird_line;
779 g_log.
information() <<
"There are " << num_empty_line <<
" lines and " << num_weird_line
780 <<
" lines are not regular.\n";
783 size_t first_regular_line = 0;
784 if (vecLines[first_regular_line].size() < 100)
785 ++first_regular_line;
786 std::vector<std::string> veccounts;
787 boost::split(veccounts, vecLines[first_regular_line], boost::algorithm::is_any_of(
" \t"));
788 size_t num_pixel_y = veccounts.size();
793 if (loadinstrument) {
794 size_t numspec = num_pixel_x * num_pixel_y;
798 outws = std::dynamic_pointer_cast<MatrixWorkspace>(
806 for (
size_t i = first_regular_line; i < vecLines.size(); ++i) {
807 std::string &line = vecLines[i];
810 if (line.size() < 100)
815 g_log.
debug() <<
"\tFound empty Line at " << i <<
"\n";
820 if (i_col == num_pixel_x) {
821 std::stringstream errss;
822 errss <<
"Number of non-empty rows (" << i_col + 1 <<
") in detector data "
823 <<
"exceeds user defined geometry size " << num_pixel_x <<
".";
824 throw std::runtime_error(errss.str());
827 boost::split(veccounts, line, boost::algorithm::is_any_of(
" \t"));
831 if (veccounts.size() != num_pixel_y) {
832 std::stringstream errss;
833 errss <<
"Row " << i_col <<
" contains " << veccounts.size() <<
" items other than " << num_pixel_y
834 <<
" counts specified by user.";
835 throw std::runtime_error(errss.str());
839 for (
size_t j_row = 0; j_row < veccounts.size(); ++j_row) {
840 double counts = std::stod(veccounts[j_row]);
841 size_t rowIndex, columnIndex;
843 if (loadinstrument) {
845 rowIndex = i_col * num_pixel_x + j_row;
852 outws->mutableX(rowIndex)[columnIndex] =
static_cast<double>(columnIndex);
853 outws->mutableY(rowIndex)[columnIndex] = counts;
856 outws->mutableE(rowIndex)[columnIndex] = sqrt(counts);
858 outws->mutableE(rowIndex)[columnIndex] = 1.0;
861 if (counts > max_counts) {
882 size_t numrows = spicetablews->rowCount();
883 std::vector<std::string> colnames = spicetablews->getColumnNames();
885 Types::Core::DateAndTime anytime(1000);
887 bool foundlog =
false;
888 for (
size_t ir = 0; ir < numrows; ++ir) {
890 int localpt = spicetablews->cell<
int>(ir, 0);
891 if (localpt != ptnumber)
895 for (
size_t ic = 1; ic < colnames.size(); ++ic) {
896 double logvalue = spicetablews->cell<
double>(ir, ic);
897 std::string &logname = colnames[ic];
899 newlogproperty->addValue(anytime, logvalue);
900 matrixws->mutableRun().addProperty(newlogproperty);
909 g_log.
warning() <<
"Pt. " << ptnumber <<
" is not found. Log is not loaded to output workspace."
920 bool haswavelength(
false);
926 if (dataws->run().hasProperty(
"_m1")) {
927 g_log.
notice(
"[DB] Data workspace has property _m1!");
931 if (ts && ts->
size() > 0) {
933 if (
fabs(m1pos - (-25.870000)) < 0.2) {
935 haswavelength =
true;
936 }
else if (
fabs(m1pos - (-39.17)) < 0.2) {
938 haswavelength =
true;
940 g_log.
warning() <<
"m1 position " << m1pos <<
" does not have defined mapping to "
945 g_log.
warning(
"Log _m1 is not TimeSeriesProperty. Treat it as a single "
947 double m1pos = std::stod(dataws->run().getProperty(
"_m1")->value());
948 if (
fabs(m1pos - (-25.870000)) < 0.2) {
950 haswavelength =
true;
951 }
else if (
fabs(m1pos - (-39.17)) < 0.2) {
953 haswavelength =
true;
955 g_log.
warning() <<
"m1 position " << m1pos <<
" does not have defined mapping to "
970 g_log.
notice() <<
"[DB] Wavelength = " << wavelength <<
"\n";
972 return haswavelength;
982 size_t numspec = dataws->getNumberHistograms();
983 for (
size_t iws = 0; iws < numspec; ++iws) {
984 double ki = 2. * M_PI / wavelength;
985 auto &
x = dataws->mutableX(iws);
990 dataws->getAxis(0)->setUnit(
"Momentum");
1001 loadinst->initialize();
1002 loadinst->setProperty(
"Workspace", matrixws);
1003 if (!idffilename.empty()) {
1004 loadinst->setProperty(
"Filename", idffilename);
1006 loadinst->setProperty(
"InstrumentName",
"HB3A");
1008 loadinst->execute();
1009 if (!loadinst->isExecuted())
1010 g_log.
error(
"Unable to load instrument to output workspace");
#define DECLARE_ALGORITHM(classname)
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
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.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
@ Load
allowed here which will be passed to the algorithm
A property class for workspaces.
LoadSpiceXML2DDet : Load 2D detector data in XML format form SPICE.
std::string m_detXMLNodeName
XML node name in detector counts file.
std::vector< unsigned int > binaryParseIntegers(std::string &binary_file_name)
parse binary integer file
void init() override
Declare properties.
const std::string summary() const override
Summary.
double m_detSampleDistanceShift
shift distance from sample to detector center
API::MatrixWorkspace_sptr xmlCreateMatrixWorkspaceKnownGeometry(const std::vector< SpiceXMLNode > &vecxmlnode, const size_t &numpixelx, const size_t &numpixely, const std::string &detnodename, const bool &loadinstrument)
Create output MatrixWorkspace.
void loadInstrument(const API::MatrixWorkspace_sptr &matrixws, const std::string &idffilename)
Load instrument.
void setupSampleLogFromSpiceTable(const API::MatrixWorkspace_sptr &matrixws, const API::ITableWorkspace_sptr &spicetablews, int ptnumber)
Set up sample logs from table workspace loaded where SPICE data file is loaded.
bool m_hasScanTable
Flag to show whether the SPICE scan table workspace is given.
int m_ptNumber4Log
Pt number for the sample logs to load with presense of Spice scan table workspace.
bool m_loadInstrument
Flag to show whether instrument is required to load.
~LoadSpiceXML2DDet() override
Destructor.
std::string m_detXMLFileName
SPICE detector XML file.
void exec() override
Main execution.
size_t m_numPixelY
Pixel size at Y direction.
std::string m_idfFileName
IDF file name to override Mantid's.
double m_detXShift
shift of detector on X and Y direction
API::MatrixWorkspace_sptr xmlCreateMatrixWorkspaceUnknowGeometry(const std::vector< SpiceXMLNode > &vecxmlnode, const std::string &detnodename, const bool &loadinstrument)
Create output MatrixWorkspace.
void setXtoLabQ(const API::MatrixWorkspace_sptr &dataws, const double &wavelength)
Set output workspace's X-axs as lab-frame Q space.
size_t m_numPixelX
Pixel size at X direction.
API::MatrixWorkspace_sptr createMatrixWorkspace(const std::vector< unsigned int > &vec_counts)
create workspace (good to load instrument) from vector of counts
double m_userSpecifiedWaveLength
User specified wave length.
int version() const override
Algorithm version.
bool getHB3AWavelength(const API::MatrixWorkspace_sptr &dataws, double &wavelength)
Get wavelength from workspace.
const std::string name() const override
Algoriothm name.
void processInputs()
Process inputs.
LoadSpiceXML2DDet()
Constructor.
std::vector< SpiceXMLNode > xmlParseSpice(const std::string &xmlfilename)
Parse SPICE XML file.
API::MatrixWorkspace_sptr xmlParseDetectorNode(const std::string &detvaluestr, bool loadinstrument, double &max_counts)
const std::string category() const override
Category.
bool setupSampleLogs(const API::MatrixWorkspace_sptr &outws)
Set up sample logs in the output workspace.
bool hasValue() const
Check whether XML node has value set.
bool isDouble() const
Is this node of double type?
bool isInteger() const
Is this node of integer type?
void setValue(const std::string &strvalue)
Set node value in string format.
void setParameters(const std::string &nodetype, const std::string &nodeunit, const std::string &nodedescription)
Set XML node parameters.
std::string m_typefullname
std::string m_description
const std::string getName() const
Get name of XML node.
bool hasUnit() const
Check whether XML has unit set.
const std::string getValue() const
Get node's value in string.
bool isString() const
Is this node of string type?
const std::string getUnit() const
Get unit of XML node.
const std::string getDescription() const
Get node's description.
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.
void notice(const std::string &msg)
Logs at notice level.
void error(const std::string &msg)
Logs at error level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
OptionalBool : Tri-state bool.
The concrete, templated class for properties.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
A specialised Property class for holding a series of time-value pairs.
int size() const override
Returns the number of values at UNIQUE time intervals in the time series.
std::vector< TYPE > valuesAsVector() const
Return the time series's values (unfiltered) as a vector<TYPE>
void addValue(const Types::Core::DateAndTime &time, const TYPE &value)
Add a value to the map using a DateAndTime object.
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
@ Input
An input workspace.
@ Output
An output workspace.