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>
37#include <Poco/SAX/InputSource.h>
53using Types::Core::DateAndTime;
54using namespace Kernel;
56using namespace Geometry;
57using namespace DataObjects;
63 : m_sansSpiceXmlFormatVersion(0.0), m_wavelength(0.0), m_dwavelength(0.0), m_sampleDetectorDistance(0.0) {}
75 std::istream &is = descriptor.
data();
79 Poco::XML::InputSource src(is);
81 Poco::XML::DOMParser pParser;
82 Poco::AutoPtr<Poco::XML::Document> pDoc;
84 pDoc = pParser.parse(&src);
85 }
catch (Poco::Exception &e) {
91 Poco::XML::Element *pRootElem = pDoc->documentElement();
93 if (pRootElem->tagName() ==
"SPICErack") {
105 "The name of the input xml file to load");
108 "The name of the Output workspace");
113 auto mustBePositive = std::make_shared<Kernel::BoundedValidator<double>>();
114 mustBePositive->setLower(0.0);
116 "Optional wavelength value to use when loading the data file "
117 "(Angstrom). This value will be used instead of the value "
118 "found in the data file.");
120 "Optional wavelength spread value to use when loading the "
121 "data file (Angstrom). This value will be used instead of "
122 "the value found in the data file.");
124 "Sample to detector distance to use (overrides meta data), in mm");
187 m_startTime = DateAndTime(attributes[
"start_time"]);
188 m_endTime = DateAndTime(attributes[
"end_time"]);
196 double wavelength_input =
getProperty(
"Wavelength");
197 double wavelength_spread_input =
getProperty(
"WavelengthSpread");
199 if (
isEmpty(wavelength_input)) {
205 if (
isEmpty(wavelength_spread_input)) {
209 DateAndTime changingDate(
"2016-06-13 00:00:00");
211 g_log.
debug() <<
"Using wavelength spread as a ratio..." <<
'\n';
229 std::pair<int, int> dims = std::make_pair(0, 0);
231 boost::regex b_re_sig(R
"(INT\d+\[(\d+),(\d+)\])");
232 if (boost::regex_match(dims_str, b_re_sig)) {
233 boost::match_results<std::string::const_iterator> match;
234 boost::regex_search(dims_str, match, b_re_sig);
239 if (dims.first == 0 || dims.second == 0)
240 g_log.
notice() <<
"Could not read in the number of pixels!" <<
'\n';
251 std::vector<int> data;
252 unsigned int totalDataSize = 0;
256 g_log.
debug() <<
"Number the detectors found in Xpath " << dataXpath <<
" = " << detectors.size() <<
'\n';
259 for (
const auto &detector : detectors) {
260 std::string detectorXpath = std::string(dataXpath).append(
"/").append(detector);
269 if (detectorXpath.find(
"DetectorWing") != std::string::npos && dims.first * dims.second <= 4096)
272 totalDataSize += dims.first * dims.second;
273 g_log.
debug() <<
"Parsing detector XPath " << detectorXpath <<
" with dimensions: " << dims.first <<
" x "
274 << dims.second <<
" = " << dims.first * dims.second <<
'\n';
277 g_log.
debug() <<
"The size of detector contents (xpath = " << detectorXpath <<
") is " << data_str.size()
278 <<
" bytes." <<
'\n';
281 std::stringstream iss(data_str);
283 while (iss >> number) {
284 data.emplace_back(
static_cast<int>(number));
286 g_log.
debug() <<
"Detector XPath: " << detectorXpath
287 <<
" parsed. Total size of data processed up to now = " << data.size() <<
" from a total of "
288 << totalDataSize <<
'\n';
291 if (data.size() != totalDataSize) {
292 g_log.
error() <<
"Total data size = " << totalDataSize <<
". Parsed data size = " << data.size() <<
'\n';
294 "declared in the Spice XML meta-data.");
305 const std::string &instrumentName =
m_metadata[
"Header/Instrument"];
307 if (instrumentName.compare(
"CG2") == 0 || instrumentName.compare(
"GPSANS") == 0) {
308 std::vector<int> temp(data.size());
309 size_t nTubes(std::stoul(
m_metadata[
"Header/Number_of_X_Pixels"]));
310 size_t nEightPacks = nTubes / 8;
311 size_t nPixelPerTube(std::stoul(
m_metadata[
"Header/Number_of_Y_Pixels"]));
314 std::vector<size_t> perm{0, 2, 4, 6, 1, 3, 5, 7};
315 size_t newStartPixelID, oldStartPixelID;
316 for (
size_t e = 0; e < nEightPacks; ++e) {
317 for (
size_t t = 0; t < 8; t++) {
318 newStartPixelID = (t + 8 * e) * nPixelPerTube;
319 oldStartPixelID = (perm[t] + 8 * e) * nPixelPerTube;
320 for (
size_t p = 0; p < nPixelPerTube; p++) {
321 temp[p + newStartPixelID] = data[p + oldStartPixelID];
325 for (
size_t i = 0; i < data.size(); i++) {
347 X[0] = wavelength - dwavelength / 2.0;
348 X[1] = wavelength + dwavelength / 2.0;
351 m_workspace->getSpectrum(specID).setSpectrumNo(specID);
356 std::vector<int> data =
readData(
"//Data");
359 int numSpectra =
static_cast<int>(data.size()) +
m_nMonitors;
361 m_workspace = std::dynamic_pointer_cast<DataObjects::Workspace2D>(
364 m_workspace->getAxis(0)->unit() = Kernel::UnitFactory::Instance().create(
"Wavelength");
367 auto monitorCounts = boost::lexical_cast<double>(
m_metadata[
"Counters/monitor"]);
368 auto countingTime = boost::lexical_cast<double>(
m_metadata[
"Counters/time"]);
377 for (
auto count : data) {
381 double error = sqrt(0.5 +
fabs(
static_cast<double>(
count) - 0.5));
393 g_log.
debug() <<
"Adding Time Series Property to the Run: " <<
name <<
" -> " <<
value <<
"\n";
396 p->addValue(DateAndTime::getCurrentTime(),
value);
417 std::vector<double> trapDiameters = {76.2, 50.8, 76.2, 101.6};
419 double trapDiameterInUse = trapDiameters[1];
421 std::vector<double> trapMotorPositions;
422 trapMotorPositions.emplace_back(boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/trap_y_25mm"]));
423 trapMotorPositions.emplace_back(boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/trap_y_50mm"]));
424 trapMotorPositions.emplace_back(boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/trap_y_76mm"]));
425 trapMotorPositions.emplace_back(boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/trap_y_101mm"]));
428 std::vector<size_t> trapIndexInUse;
429 for (
size_t i = 0; i < trapMotorPositions.size(); i++) {
430 if (trapMotorPositions[i] > 26.0) {
432 trapIndexInUse.emplace_back(i);
436 g_log.
debug() <<
"trapIndexInUse length:" << trapIndexInUse.size() <<
"\n";
439 std::vector<double> trapDiametersInUse;
440 trapDiametersInUse.reserve(trapIndexInUse.size());
441 std::transform(trapIndexInUse.cbegin(), trapIndexInUse.cend(), std::back_inserter(trapDiametersInUse),
442 [&trapDiameters](
auto index) { return trapDiameters[index]; });
444 g_log.
debug() <<
"trapDiametersInUse length:" << trapDiametersInUse.size() <<
"\n";
447 auto trapDiameterInUseIt = std::max_element(trapDiametersInUse.begin(), trapDiametersInUse.end());
448 if (trapDiameterInUseIt != trapDiametersInUse.end())
449 trapDiameterInUse = *trapDiameterInUseIt;
451 g_log.
debug() <<
"trapDiameterInUse:" << trapDiameterInUse <<
"\n";
453 addRunProperty<double>(
"beam-trap-diameter", trapDiameterInUse,
"mm");
463 std::string key = keyValuePair.first;
464 std::replace(key.begin(), key.end(),
'/',
'_');
465 m_workspace->mutableRun().addProperty(key, keyValuePair.second,
true);
468 addRunProperty<std::string>(
"start_time",
m_startTime.toISO8601String(),
"");
469 addRunProperty<std::string>(
"run_start",
m_startTime.toISO8601String(),
"");
474 addRunProperty<double>(
"wavelength",
m_wavelength,
"Angstrom");
475 addRunProperty<double>(
"wavelength-spread",
m_dwavelength,
"Angstrom");
478 addRunProperty<double>(
"monitor", boost::lexical_cast<double>(
m_metadata[
"Counters/monitor"]));
479 addRunProperty<double>(
"timer", boost::lexical_cast<double>(
m_metadata[
"Counters/time"]),
"sec");
482 auto sample_thickness = boost::lexical_cast<double>(
m_metadata[
"Header/Sample_Thickness"]);
484 g_log.
debug() <<
"sans_spice_xml_format_version >= 1.03 :: "
485 "sample_thickness in mm. Converting to cm...";
486 sample_thickness *= 0.1;
488 addRunProperty<double>(
"sample-thickness", sample_thickness,
"cm");
490 addRunProperty<double>(
"source-aperture-diameter",
491 boost::lexical_cast<double>(
m_metadata[
"Header/source_aperture_size"]),
"mm");
492 addRunProperty<double>(
"source_aperture_diameter",
493 boost::lexical_cast<double>(
m_metadata[
"Header/source_aperture_size"]),
"mm");
495 addRunProperty<double>(
"sample-aperture-diameter",
496 boost::lexical_cast<double>(
m_metadata[
"Header/sample_aperture_size"]),
"mm");
497 addRunProperty<double>(
"sample_aperture_diameter",
498 boost::lexical_cast<double>(
m_metadata[
"Header/sample_aperture_size"]),
"mm");
500 addRunProperty<double>(
"number-of-guides", boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/nguides"]));
508 const std::string &instrumentName =
m_metadata[
"Header/Instrument"];
514 loadInstrumentAlgorithm->setPropertyValue(
"InstrumentName", instrumentName);
517 loadInstrumentAlgorithm->execute();
518 }
catch (std::invalid_argument &) {
520 }
catch (std::runtime_error &) {
521 g_log.
information(
"Unable to successfully run LoadInstrument Child Algorithm");
531 double angle = -boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/det_west_wing_rot"]);
532 g_log.
notice() <<
"Rotating Wing Detector " << angle <<
" degrees." <<
'\n';
533 addRunTimeSeriesProperty<double>(
"rotangle", angle);
546 <<
" from the Algorithm input property.\n";
553 auto sampleDetectorDistancePartial = boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/sample_det_dist"]);
554 sampleDetectorDistancePartial *= 1000.0;
556 auto sampleDetectorDistanceOffset = boost::lexical_cast<double>(
m_metadata[
"Header/tank_internal_offset"]);
558 auto sampleDetectorDistanceWindow = boost::lexical_cast<double>(
m_metadata[
"Header/sample_to_flange"]);
561 sampleDetectorDistancePartial + sampleDetectorDistanceOffset + sampleDetectorDistanceWindow;
580 auto translationDistance = boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/detector_trans"]);
581 g_log.
debug() <<
"Detector Translation = " << translationDistance <<
" mm." <<
'\n';
582 addRunTimeSeriesProperty<double>(
"detector-translation", translationDistance);
589 std::vector<std::string> pars =
m_workspace->getInstrument()->getStringParameter(parameter);
591 g_log.
warning() <<
"Parameter not found: " << parameter <<
" in the instrument parameter file.\n";
592 return std::string();
594 g_log.
debug() <<
"Found the parameter: " << parameter <<
" = " << pars[0] <<
" in the instrument parameter file.\n";
603 std::vector<double> pars =
m_workspace->getInstrument()->getNumberParameter(parameter);
605 g_log.
warning() <<
"Parameter not found in the instrument parameter file: " << parameter <<
"\n";
606 return std::numeric_limits<double>::quiet_NaN();
608 g_log.
debug() <<
"Found the parameter in the instrument parameter file: " << parameter <<
" = " << pars[0] <<
"\n";
625 auto sourceToSampleDistance = boost::lexical_cast<double>(
m_metadata[
"Header/source_distance"]);
628 sourceToSampleDistance *= 1000;
630 if (sourceToSampleDistance <= 0) {
631 g_log.
warning() <<
"Source To Sample Distance: Header/source_distance = " << sourceToSampleDistance
632 <<
". Trying to calculate it from the number of guides used and offset." <<
'\n';
633 const int nGuides =
static_cast<int>(boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/nguides"]));
636 std::vector<std::string> guidesDistancesSplit;
637 boost::split(guidesDistancesSplit, guidesDistances, boost::is_any_of(
"\t ,"), boost::token_compress_on);
638 sourceToSampleDistance = boost::lexical_cast<double>(guidesDistancesSplit[nGuides]);
639 g_log.
debug() <<
"Number of guides used = " << nGuides <<
" --> Raw SSD = " << sourceToSampleDistance <<
"mm.\n";
640 auto sourceToSampleDistanceOffset = boost::lexical_cast<double>(
m_metadata[
"Header/sample_aperture_to_flange"]);
641 g_log.
debug() <<
"SSD offset = " << sourceToSampleDistanceOffset <<
"mm.\n";
642 sourceToSampleDistance -= sourceToSampleDistanceOffset;
644 g_log.
information() <<
"Source To Sample Distance = " << sourceToSampleDistance <<
"mm.\n";
645 return sourceToSampleDistance;
654 addRunProperty<double>(
"source-sample-distance", sourceToSampleDistance,
"mm");
655 addRunProperty<double>(
"source_sample_distance", sourceToSampleDistance,
"mm");
657 const auto sampleAperture = boost::lexical_cast<double>(
m_metadata[
"Header/sample_aperture_size"]);
658 const auto sourceAperture = boost::lexical_cast<double>(
m_metadata[
"Header/source_aperture_size"]);
660 <<
" SourceToSampleDistance=" << sourceToSampleDistance <<
" sourceAperture= " << sourceAperture
661 <<
" sampleAperture=" << sampleAperture <<
"\n";
663 const double beamDiameter =
665 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
int confidence(Kernel::FileDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
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.
const std::string & filename() const
Access the filename.
std::istream & data()
Access the open file stream.
const std::string & extension() const
Access the file extension.
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.
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.