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<double> trapDiametersInUse;
429 auto posIt = trapMotorPositions.cbegin();
430 std::copy_if(trapDiameters.cbegin(), trapDiameters.cend(), std::back_inserter(trapDiametersInUse),
431 [&posIt](
double) { return *posIt++ > 26.0; });
433 g_log.
debug() <<
"trapDiametersInUse length:" << trapDiametersInUse.size() <<
"\n";
436 auto trapDiameterInUseIt = std::max_element(trapDiametersInUse.begin(), trapDiametersInUse.end());
437 if (trapDiameterInUseIt != trapDiametersInUse.end())
438 trapDiameterInUse = *trapDiameterInUseIt;
440 g_log.
debug() <<
"trapDiameterInUse:" << trapDiameterInUse <<
"\n";
442 addRunProperty<double>(
"beam-trap-diameter", trapDiameterInUse,
"mm");
452 std::string key = keyValuePair.first;
453 std::replace(key.begin(), key.end(),
'/',
'_');
454 m_workspace->mutableRun().addProperty(key, keyValuePair.second,
true);
457 addRunProperty<std::string>(
"start_time",
m_startTime.toISO8601String(),
"");
458 addRunProperty<std::string>(
"run_start",
m_startTime.toISO8601String(),
"");
463 addRunProperty<double>(
"wavelength",
m_wavelength,
"Angstrom");
464 addRunProperty<double>(
"wavelength-spread",
m_dwavelength,
"Angstrom");
467 addRunProperty<double>(
"monitor", boost::lexical_cast<double>(
m_metadata[
"Counters/monitor"]));
468 addRunProperty<double>(
"timer", boost::lexical_cast<double>(
m_metadata[
"Counters/time"]),
"sec");
471 auto sample_thickness = boost::lexical_cast<double>(
m_metadata[
"Header/Sample_Thickness"]);
473 g_log.
debug() <<
"sans_spice_xml_format_version >= 1.03 :: "
474 "sample_thickness in mm. Converting to cm...";
475 sample_thickness *= 0.1;
477 addRunProperty<double>(
"sample-thickness", sample_thickness,
"cm");
479 addRunProperty<double>(
"source-aperture-diameter",
480 boost::lexical_cast<double>(
m_metadata[
"Header/source_aperture_size"]),
"mm");
481 addRunProperty<double>(
"source_aperture_diameter",
482 boost::lexical_cast<double>(
m_metadata[
"Header/source_aperture_size"]),
"mm");
484 addRunProperty<double>(
"sample-aperture-diameter",
485 boost::lexical_cast<double>(
m_metadata[
"Header/sample_aperture_size"]),
"mm");
486 addRunProperty<double>(
"sample_aperture_diameter",
487 boost::lexical_cast<double>(
m_metadata[
"Header/sample_aperture_size"]),
"mm");
489 addRunProperty<double>(
"number-of-guides", boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/nguides"]));
497 const std::string &instrumentName =
m_metadata[
"Header/Instrument"];
503 loadInstrumentAlgorithm->setPropertyValue(
"InstrumentName", instrumentName);
506 loadInstrumentAlgorithm->execute();
507 }
catch (std::invalid_argument &) {
509 }
catch (std::runtime_error &) {
510 g_log.
information(
"Unable to successfully run LoadInstrument Child Algorithm");
520 double angle = -boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/det_west_wing_rot"]);
521 g_log.
notice() <<
"Rotating Wing Detector " << angle <<
" degrees." <<
'\n';
522 addRunTimeSeriesProperty<double>(
"rotangle", angle);
535 <<
" from the Algorithm input property.\n";
542 auto sampleDetectorDistancePartial = boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/sample_det_dist"]);
543 sampleDetectorDistancePartial *= 1000.0;
545 auto sampleDetectorDistanceOffset = boost::lexical_cast<double>(
m_metadata[
"Header/tank_internal_offset"]);
547 auto sampleDetectorDistanceWindow = boost::lexical_cast<double>(
m_metadata[
"Header/sample_to_flange"]);
550 sampleDetectorDistancePartial + sampleDetectorDistanceOffset + sampleDetectorDistanceWindow;
569 auto translationDistance = boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/detector_trans"]);
570 g_log.
debug() <<
"Detector Translation = " << translationDistance <<
" mm." <<
'\n';
571 addRunTimeSeriesProperty<double>(
"detector-translation", translationDistance);
578 std::vector<std::string> pars =
m_workspace->getInstrument()->getStringParameter(parameter);
580 g_log.
warning() <<
"Parameter not found: " << parameter <<
" in the instrument parameter file.\n";
581 return std::string();
583 g_log.
debug() <<
"Found the parameter: " << parameter <<
" = " << pars[0] <<
" in the instrument parameter file.\n";
592 std::vector<double> pars =
m_workspace->getInstrument()->getNumberParameter(parameter);
594 g_log.
warning() <<
"Parameter not found in the instrument parameter file: " << parameter <<
"\n";
595 return std::numeric_limits<double>::quiet_NaN();
597 g_log.
debug() <<
"Found the parameter in the instrument parameter file: " << parameter <<
" = " << pars[0] <<
"\n";
614 auto sourceToSampleDistance = boost::lexical_cast<double>(
m_metadata[
"Header/source_distance"]);
617 sourceToSampleDistance *= 1000;
619 if (sourceToSampleDistance <= 0) {
620 g_log.
warning() <<
"Source To Sample Distance: Header/source_distance = " << sourceToSampleDistance
621 <<
". Trying to calculate it from the number of guides used and offset." <<
'\n';
622 const int nGuides =
static_cast<int>(boost::lexical_cast<double>(
m_metadata[
"Motor_Positions/nguides"]));
625 std::vector<std::string> guidesDistancesSplit;
626 boost::split(guidesDistancesSplit, guidesDistances, boost::is_any_of(
"\t ,"), boost::token_compress_on);
627 sourceToSampleDistance = boost::lexical_cast<double>(guidesDistancesSplit[nGuides]);
628 g_log.
debug() <<
"Number of guides used = " << nGuides <<
" --> Raw SSD = " << sourceToSampleDistance <<
"mm.\n";
629 auto sourceToSampleDistanceOffset = boost::lexical_cast<double>(
m_metadata[
"Header/sample_aperture_to_flange"]);
630 g_log.
debug() <<
"SSD offset = " << sourceToSampleDistanceOffset <<
"mm.\n";
631 sourceToSampleDistance -= sourceToSampleDistanceOffset;
633 g_log.
information() <<
"Source To Sample Distance = " << sourceToSampleDistance <<
"mm.\n";
634 return sourceToSampleDistance;
643 addRunProperty<double>(
"source-sample-distance", sourceToSampleDistance,
"mm");
644 addRunProperty<double>(
"source_sample_distance", sourceToSampleDistance,
"mm");
646 const auto sampleAperture = boost::lexical_cast<double>(
m_metadata[
"Header/sample_aperture_size"]);
647 const auto sourceAperture = boost::lexical_cast<double>(
m_metadata[
"Header/source_aperture_size"]);
649 <<
" SourceToSampleDistance=" << sourceToSampleDistance <<
" sourceAperture= " << sourceAperture
650 <<
" sampleAperture=" << sampleAperture <<
"\n";
652 const double beamDiameter =
654 addRunProperty<double>(
"beam-diameter", beamDiameter,
"mm");
double value
The value of the point.
#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.