24#include <boost/algorithm/string/split.hpp>
25#include <boost/algorithm/string/trim.hpp>
26#include <boost/lexical_cast.hpp>
27#include <boost/regex.hpp>
31#include <Poco/DOM/DOMParser.h>
32#include <Poco/DOM/Document.h>
33#include <Poco/DOM/Element.h>
34#include <Poco/DOM/Node.h>
35#include <Poco/DOM/NodeList.h>
36#include <Poco/DOM/Text.h>
38#include <Poco/SAX/InputSource.h>
54using Types::Core::DateAndTime;
55using namespace Kernel;
57using namespace Geometry;
58using namespace DataObjects;
70 if (descriptor.extension() !=
".xml")
73 std::istream &is = descriptor.data();
77 Poco::XML::InputSource src(is);
79 Poco::XML::DOMParser pParser;
80 Poco::AutoPtr<Poco::XML::Document> pDoc;
82 pDoc = pParser.parse(&src);
83 }
catch (Poco::Exception &e) {
89 Poco::XML::Element *pRootElem = pDoc->documentElement();
91 if (pRootElem->tagName() ==
"SPICErack") {
103 "The name of the input xml file to load");
106 "The name of the Output workspace");
111 auto mustBePositive = std::make_shared<Kernel::BoundedValidator<double>>();
112 mustBePositive->setLower(0.0);
114 "Optional wavelength value to use when loading the data file "
115 "(Angstrom). This value will be used instead of the value "
116 "found in the data file.");
118 "Optional wavelength spread value to use when loading the "
119 "data file (Angstrom). This value will be used instead of "
120 "the value found in the data file.");
122 "Sample to detector distance to use (overrides meta data), in mm");
185 m_startTime = DateAndTime(attributes[
"start_time"]);
186 m_endTime = DateAndTime(attributes[
"end_time"]);
194 double wavelength_input =
getProperty(
"Wavelength");
195 double wavelength_spread_input =
getProperty(
"WavelengthSpread");
197 if (
isEmpty(wavelength_input)) {
203 if (
isEmpty(wavelength_spread_input)) {
207 DateAndTime changingDate(
"2016-06-13 00:00:00");
209 g_log.
debug() <<
"Using wavelength spread as a ratio..." <<
'\n';
227 std::pair<int, int> dims = std::make_pair(0, 0);
229 boost::regex b_re_sig(R
"(INT\d+\[(\d+),(\d+)\])");
230 if (boost::regex_match(dims_str, b_re_sig)) {
231 boost::match_results<std::string::const_iterator> match;
232 boost::regex_search(dims_str, match, b_re_sig);
237 if (dims.first == 0 || dims.second == 0)
238 g_log.
notice() <<
"Could not read in the number of pixels!" <<
'\n';
249 std::vector<int> data;
250 unsigned int totalDataSize = 0;
254 g_log.
debug() <<
"Number the detectors found in Xpath " << dataXpath <<
" = " << detectors.size() <<
'\n';
257 for (
const auto &detector : detectors) {
258 std::string detectorXpath = std::string(dataXpath).append(
"/").append(detector);
267 if (detectorXpath.find(
"DetectorWing") != std::string::npos && dims.first * dims.second <= 4096)
270 totalDataSize += dims.first * dims.second;
271 g_log.
debug() <<
"Parsing detector XPath " << detectorXpath <<
" with dimensions: " << dims.first <<
" x "
272 << dims.second <<
" = " << dims.first * dims.second <<
'\n';
275 g_log.
debug() <<
"The size of detector contents (xpath = " << detectorXpath <<
") is " << data_str.size()
276 <<
" bytes." <<
'\n';
279 std::stringstream iss(data_str);
281 while (iss >> number) {
282 data.emplace_back(
static_cast<int>(number));
284 g_log.
debug() <<
"Detector XPath: " << detectorXpath
285 <<
" parsed. Total size of data processed up to now = " << data.size() <<
" from a total of "
286 << totalDataSize <<
'\n';
289 if (data.size() != totalDataSize) {
290 g_log.
error() <<
"Total data size = " << totalDataSize <<
". Parsed data size = " << data.size() <<
'\n';
292 "declared in the Spice XML meta-data.");
303 const std::string &instrumentName =
m_metadata[
"Header/Instrument"];
305 if (instrumentName.compare(
"CG2") == 0 || instrumentName.compare(
"GPSANS") == 0) {
306 std::vector<int> temp(data.size());
307 size_t nTubes(std::stoul(
m_metadata[
"Header/Number_of_X_Pixels"]));
308 size_t nEightPacks = nTubes / 8;
309 size_t nPixelPerTube(std::stoul(
m_metadata[
"Header/Number_of_Y_Pixels"]));
312 std::vector<size_t> perm{0, 2, 4, 6, 1, 3, 5, 7};
313 size_t newStartPixelID, oldStartPixelID;
314 for (
size_t e = 0; e < nEightPacks; ++e) {
315 for (
size_t t = 0; t < 8; t++) {
316 newStartPixelID = (t + 8 * e) * nPixelPerTube;
317 oldStartPixelID = (perm[t] + 8 * e) * nPixelPerTube;
318 for (
size_t p = 0; p < nPixelPerTube; p++) {
319 temp[p + newStartPixelID] = data[p + oldStartPixelID];
323 for (
size_t i = 0; i < data.size(); i++) {
345 X[0] = wavelength - dwavelength / 2.0;
346 X[1] = wavelength + dwavelength / 2.0;
349 m_workspace->getSpectrum(specID).setSpectrumNo(specID);
354 std::vector<int> data =
readData(
"//Data");
357 int numSpectra =
static_cast<int>(data.size()) +
m_nMonitors;
359 m_workspace = std::dynamic_pointer_cast<DataObjects::Workspace2D>(
365 auto monitorCounts = boost::lexical_cast<double>(
m_metadata[
"Counters/monitor"]);
366 auto countingTime = boost::lexical_cast<double>(
m_metadata[
"Counters/time"]);
375 for (
auto count : data) {
379 double error = sqrt(0.5 +
fabs(
static_cast<double>(
count) - 0.5));
391 g_log.
debug() <<
"Adding Time Series Property to the Run: " <<
name <<
" -> " <<
value <<
"\n";
394 p->addValue(DateAndTime::getCurrentTime(),
value);
415 std::vector<double> trapDiameters = {76.2, 50.8, 76.2, 101.6};
417 double trapDiameterInUse = trapDiameters[1];
419 std::vector<double> trapMotorPositions;
420 trapMotorPositions.emplace_back(boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/trap_y_25mm"]));
421 trapMotorPositions.emplace_back(boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/trap_y_50mm"]));
422 trapMotorPositions.emplace_back(boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/trap_y_76mm"]));
423 trapMotorPositions.emplace_back(boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/trap_y_101mm"]));
426 std::vector<size_t> trapIndexInUse;
427 for (
size_t i = 0; i < trapMotorPositions.size(); i++) {
428 if (trapMotorPositions[i] > 26.0) {
430 trapIndexInUse.emplace_back(i);
434 g_log.
debug() <<
"trapIndexInUse length:" << trapIndexInUse.size() <<
"\n";
437 std::vector<double> trapDiametersInUse;
438 trapDiametersInUse.reserve(trapIndexInUse.size());
439 std::transform(trapIndexInUse.cbegin(), trapIndexInUse.cend(), std::back_inserter(trapDiametersInUse),
440 [&trapDiameters](
auto index) { return trapDiameters[index]; });
442 g_log.
debug() <<
"trapDiametersInUse length:" << trapDiametersInUse.size() <<
"\n";
445 auto trapDiameterInUseIt = std::max_element(trapDiametersInUse.begin(), trapDiametersInUse.end());
446 if (trapDiameterInUseIt != trapDiametersInUse.end())
447 trapDiameterInUse = *trapDiameterInUseIt;
449 g_log.
debug() <<
"trapDiameterInUse:" << trapDiameterInUse <<
"\n";
451 addRunProperty<double>(
"beam-trap-diameter", trapDiameterInUse,
"mm");
461 std::string key = keyValuePair.first;
462 std::replace(key.begin(), key.end(),
'/',
'_');
463 m_workspace->mutableRun().addProperty(key, keyValuePair.second,
true);
466 addRunProperty<std::string>(
"start_time",
m_startTime.toISO8601String(),
"");
467 addRunProperty<std::string>(
"run_start",
m_startTime.toISO8601String(),
"");
472 addRunProperty<double>(
"wavelength",
m_wavelength,
"Angstrom");
473 addRunProperty<double>(
"wavelength-spread",
m_dwavelength,
"Angstrom");
476 addRunProperty<double>(
"monitor", boost::lexical_cast<double>(
m_metadata[
"Counters/monitor"]));
477 addRunProperty<double>(
"timer", boost::lexical_cast<double>(
m_metadata[
"Counters/time"]),
"sec");
480 auto sample_thickness = boost::lexical_cast<double>(
m_metadata[
"Header/Sample_Thickness"]);
482 g_log.
debug() <<
"sans_spice_xml_format_version >= 1.03 :: "
483 "sample_thickness in mm. Converting to cm...";
484 sample_thickness *= 0.1;
486 addRunProperty<double>(
"sample-thickness", sample_thickness,
"cm");
488 addRunProperty<double>(
"source-aperture-diameter",
489 boost::lexical_cast<double>(
m_metadata[
"Header/source_aperture_size"]),
"mm");
490 addRunProperty<double>(
"source_aperture_diameter",
491 boost::lexical_cast<double>(
m_metadata[
"Header/source_aperture_size"]),
"mm");
493 addRunProperty<double>(
"sample-aperture-diameter",
494 boost::lexical_cast<double>(
m_metadata[
"Header/sample_aperture_size"]),
"mm");
495 addRunProperty<double>(
"sample_aperture_diameter",
496 boost::lexical_cast<double>(
m_metadata[
"Header/sample_aperture_size"]),
"mm");
498 addRunProperty<double>(
"number-of-guides", boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/nguides"]));
506 const std::string &instrumentName =
m_metadata[
"Header/Instrument"];
512 loadInstrumentAlgorithm->setPropertyValue(
"InstrumentName", instrumentName);
515 loadInstrumentAlgorithm->execute();
516 }
catch (std::invalid_argument &) {
518 }
catch (std::runtime_error &) {
519 g_log.
information(
"Unable to successfully run LoadInstrument Child Algorithm");
529 double angle = -boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/det_west_wing_rot"]);
530 g_log.
notice() <<
"Rotating Wing Detector " << angle <<
" degrees." <<
'\n';
531 addRunTimeSeriesProperty<double>(
"rotangle", angle);
545 <<
" from the Algorithm input property.\n";
552 auto sampleDetectorDistancePartial = boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/sample_det_dist"]);
553 sampleDetectorDistancePartial *= 1000.0;
555 auto sampleDetectorDistanceOffset = boost::lexical_cast<double>(
m_metadata[
"Header/tank_internal_offset"]);
557 auto sampleDetectorDistanceWindow = boost::lexical_cast<double>(
m_metadata[
"Header/sample_to_flange"]);
560 sampleDetectorDistancePartial + sampleDetectorDistanceOffset + sampleDetectorDistanceWindow;
579 auto translationDistance = boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/detector_trans"]);
580 g_log.
debug() <<
"Detector Translation = " << translationDistance <<
" mm." <<
'\n';
581 addRunTimeSeriesProperty<double>(
"detector-translation", translationDistance);
588 std::vector<std::string> pars =
m_workspace->getInstrument()->getStringParameter(parameter);
590 g_log.
warning() <<
"Parameter not found: " << parameter <<
" in the instrument parameter file.\n";
591 return std::string();
593 g_log.
debug() <<
"Found the parameter: " << parameter <<
" = " << pars[0] <<
" in the instrument parameter file.\n";
602 std::vector<double> pars =
m_workspace->getInstrument()->getNumberParameter(parameter);
604 g_log.
warning() <<
"Parameter not found in the instrument parameter file: " << parameter <<
"\n";
605 return std::numeric_limits<double>::quiet_NaN();
607 g_log.
debug() <<
"Found the parameter in the instrument parameter file: " << parameter <<
" = " << pars[0] <<
"\n";
624 auto sourceToSampleDistance = boost::lexical_cast<double>(
m_metadata[
"Header/source_distance"]);
627 sourceToSampleDistance *= 1000;
629 if (sourceToSampleDistance <= 0) {
630 g_log.
warning() <<
"Source To Sample Distance: Header/source_distance = " << sourceToSampleDistance
631 <<
". Trying to calculate it from the number of guides used and offset." <<
'\n';
632 const int nGuides =
static_cast<int>(boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/nguides"]));
635 std::vector<std::string> guidesDistancesSplit;
636 boost::split(guidesDistancesSplit, guidesDistances, boost::is_any_of(
"\t ,"), boost::token_compress_on);
637 sourceToSampleDistance = boost::lexical_cast<double>(guidesDistancesSplit[nGuides]);
638 g_log.
debug() <<
"Number of guides used = " << nGuides <<
" --> Raw SSD = " << sourceToSampleDistance <<
"mm.\n";
639 auto sourceToSampleDistanceOffset = boost::lexical_cast<double>(
m_metadata[
"Header/sample_aperture_to_flange"]);
640 g_log.
debug() <<
"SSD offset = " << sourceToSampleDistanceOffset <<
"mm.\n";
641 sourceToSampleDistance -= sourceToSampleDistanceOffset;
643 g_log.
information() <<
"Source To Sample Distance = " << sourceToSampleDistance <<
"mm.\n";
644 return sourceToSampleDistance;
653 addRunProperty<double>(
"source-sample-distance", sourceToSampleDistance,
"mm");
654 addRunProperty<double>(
"source_sample_distance", sourceToSampleDistance,
"mm");
656 const auto sampleAperture = boost::lexical_cast<double>(
m_metadata[
"Header/sample_aperture_size"]);
657 const auto sourceAperture = boost::lexical_cast<double>(
m_metadata[
"Header/source_aperture_size"]);
659 <<
" SourceToSampleDistance=" << sourceToSampleDistance <<
" sourceAperture= " << sourceAperture
660 <<
" sampleAperture=" << sampleAperture <<
"\n";
662 const double beamDiameter =
664 addRunProperty<double>(
"beam-diameter", beamDiameter,
"mm");
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
#define DECLARE_FILELOADER_ALGORITHM(classname)
DECLARE_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro when wri...
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.
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
@ Load
allowed here which will be passed to the algorithm
void addLogData(Kernel::Property *p)
Add a log entry.
This class stores information regarding an experimental run as a series of log entries.
A property class for workspaces.
This algorithm loads a SPICE2D file for HFIR SANS into a workspace.
void permuteTubes(std::vector< int > &data)
Reorder data to take into account that the sequence of tubes in the XML file is different than the se...
void storeMetaDataIntoWS()
Add all metadata parsed values as log entries Add any other metadata needed.
std::pair< int, int > parseDetectorDimensions(const std::string &dims_str)
Parse the 2 integers of the form: INT32[192,256].
void addRunProperty(const std::string &name, const T &value, const std::string &units="")
static const int m_nMonitors
Number of monitors.
void runLoadInstrument()
Run the Child Algorithm LoadInstrument.
Mantid::Types::Core::DateAndTime m_startTime
DataObjects::Workspace2D_sptr m_workspace
const std::vector< std::string > m_tags_to_ignore
void setBeamTrapRunProperty()
Sets the beam trap as Run Property There's several beamstrap position.
void rotateDetector()
This will rotate the detector named componentName around z-axis.
double getSourceToSampleDistance()
Source to Detector Distance is already calculated in the metadata tag source_distance (if source_dist...
double m_sansSpiceXmlFormatVersion
void setWavelength()
Sets the wavelength as class atributes.
std::vector< int > readData(const std::string &dataXpath="//Data")
Loads the data from the XML file.
void init() override
Overwrites Algorithm method.
double getInstrumentDoubleParameter(const std::string ¶meter)
From the parameters file get a double parameter.
Mantid::DataHandling::XmlHandler m_xmlHandler
void setSansSpiceXmlFormatVersion()
void moveDetector()
Places the detector at the right sample_detector_distance.
void exec() override
Overwrites Algorithm method.
void setDetectorDistance()
Calculates the detector distances and sets them as Run properties.
std::string getInstrumentStringParameter(const std::string ¶meter)
From the parameters file get a string parameter.
std::map< std::string, std::string > m_metadata
const std::string name() const override
Algorithm's name for identification overriding a virtual method.
double m_sampleDetectorDistance
void addRunTimeSeriesProperty(const std::string &name, const T &value)
void storeValue(int specID, double value, double error, double wavelength, double dwavelength)
Convenience function to store a detector value into a given spectrum.
void setInputFileAsHandler()
void setBeamDiameter()
Compute beam diameter at the detector.
Mantid::Types::Core::DateAndTime m_endTime
std::string get_text_from_tag(const std::string &)
std::map< std::string, std::string > get_metadata(const std::vector< std::string > &tags_to_ignore)
Build dictionary {string : string } of all tags in the dictionary Composed tags: / replaced by _.
std::map< std::string, std::string > get_attributes_from_tag(const std::string &)
std::vector< std::string > get_subnodes(const std::string &)
Returns list of sub-nodes for a xpath node For: xpath = //Data/ Returns: Detector ,...
Records the filename and the description of failure.
Marks code as not implemented yet.
Defines a wrapper around an open file.
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.
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.
Kernel::Logger g_log("ExperimentInfo")
static logger object
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.
int convert(const std::string &A, T &out)
Convert a string into a number.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Describes the direction (within an algorithm) of a Property.
@ Output
An output workspace.