Mantid
Loading...
Searching...
No Matches
ExperimentInfo.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/Run.h"
12#include "MantidAPI/Sample.h"
14
30
31#include "MantidBeamline/ComponentInfo.h"
32#include "MantidBeamline/DetectorInfo.h"
33#include "MantidBeamline/SpectrumInfo.h"
34
44
45#include "MantidTypes/SpectrumDefinition.h"
46
47#include <boost/algorithm/string.hpp>
48#include <boost/lexical_cast.hpp>
49#include <boost/regex.hpp>
50
51#include <Poco/Path.h>
52
53#include <algorithm>
54#include <map>
55#include <memory>
56#include <tuple>
57
58using namespace Mantid::Geometry;
59using namespace Mantid::Kernel;
60using namespace Mantid::Types::Core;
61
62namespace Mantid::API {
63namespace {
65Kernel::Logger g_log("ExperimentInfo");
66
67} // namespace
68
71ExperimentInfo::ExperimentInfo() : m_parmap(new ParameterMap()), sptr_instrument(new Instrument()) {
72 m_parmap->setInstrument(sptr_instrument.get());
74}
75
81ExperimentInfo::ExperimentInfo(const ExperimentInfo &source) { *this = source; }
82
91
92// Defined as default in source for forward declaration with std::unique_ptr.
94
100 m_sample = other->m_sample;
101 m_run = other->m_run;
102 this->setInstrument(other->getInstrument());
103 // We do not copy Beamline::SpectrumInfo (which contains detector grouping
104 // information) for now:
105 // - For MatrixWorkspace, grouping information is still stored in ISpectrum
106 // and should not be overridden (copy is done in ExperimentInfo ctor, but
107 // not here since we just copy the experiment data).
108 // - For cached groupings (for MDWorkspaces), grouping was not copied in the
109 // old implementation either.
110}
111
115
117const std::string ExperimentInfo::toString() const {
118 try {
120 } catch (std::exception &) {
121 // Catch any errors so that the string returned has as much information
122 // as possible
123 }
124
125 std::ostringstream out;
126
128 const auto instName = inst->getName();
129 out << "Instrument: ";
130 if (!instName.empty()) {
131 out << instName << " (" << inst->getValidFromDate().toFormattedString("%Y-%b-%d") << " to "
132 << inst->getValidToDate().toFormattedString("%Y-%b-%d") << ")";
133 const auto instFilename = inst->getFilename();
134 if (!instFilename.empty()) {
135 out << "Instrument from: " << instFilename;
136 out << "\n";
137 }
138 } else {
139 out << "None";
140 }
141 out << "\n";
142
143 // parameter files loaded
144 auto paramFileVector = this->constInstrumentParameters().getParameterFilenames();
145 for (auto const &itFilename : paramFileVector) {
146 out << "Parameters from: " << itFilename;
147 out << "\n";
148 }
149
150 std::string runStart = getAvailableWorkspaceStartDate();
151 std::string runEnd = getAvailableWorkspaceEndDate();
152 std::string msgNA = "not available";
153 if (runStart.empty())
154 runStart = msgNA;
155 if (runEnd.empty())
156 runEnd = msgNA;
157 out << "Run start: " << runStart << "\n";
158 out << "Run end: " << runEnd << "\n"; // note extra space for pseudo/approx-alignment
159
160 if (this->sample().hasOrientedLattice()) {
162 out << "Sample: a " << std::fixed << std::setprecision(1) << latt.a() << ", b " << latt.b() << ", c " << latt.c();
163 out << "; alpha " << std::fixed << std::setprecision(0) << latt.alpha() << ", beta " << latt.beta() << ", gamma "
164 << latt.gamma();
165 out << "\n";
166 }
167 return out.str();
168}
169
170// Helpers for setInstrument and getInstrument
171namespace {
172void checkDetectorInfoSize(const Instrument &instr, const Geometry::DetectorInfo &detInfo) {
173 const auto numDets = instr.getNumberDetectors();
174 if (numDets != detInfo.size())
175 throw std::runtime_error("ExperimentInfo: size mismatch between "
176 "DetectorInfo and number of detectors in "
177 "instrument: " +
178 std::to_string(detInfo.size()) + " vs " + std::to_string(numDets));
179}
180} // namespace
181
186 m_spectrumInfoWrapper = nullptr;
187 {
188 std::lock_guard<std::mutex> lock{m_baseComponentInfoMutex};
189 m_baseComponentInfo = nullptr;
190 m_baseDetectorInfo = nullptr;
191 }
192
193 // Detector IDs that were previously dropped because they were not part of the
194 // instrument may now suddenly be valid, so we have to reinitialize the
195 // detector grouping. Also the index corresponding to specific IDs may have
196 // changed.
197 if (sptr_instrument != (instr->isParametrized() ? instr->baseInstrument() : instr)) {
199 }
200 if (instr->isParametrized()) {
201 sptr_instrument = instr->baseInstrument();
202 // We take a *copy* of the ParameterMap since we are modifying it by setting
203 // a pointer to our DetectorInfo, and in case it contains legacy parameters
204 // such as positions or rotations.
205 const auto &source = *instr->getParameterMap();
206 m_parmap = std::make_shared<ParameterMap>(source);
207 // The copy carries the source's instrument pointer, so the setInstrument() below sees no
208 // change and returns early. The beamline therefore has to be rebuilt explicitly -- this is
209 // the copy-on-write of the instrument geometry, and it used to happen implicitly inside
210 // ParameterMap's copy constructor.
211 m_parmap->rebuildBeamlineFrom(source);
212 } else {
213 sptr_instrument = instr;
214 m_parmap = std::make_shared<ParameterMap>();
215 }
216 m_parmap->setInstrument(sptr_instrument.get());
218}
219
221 m_componentInfo = m_parmap->sharedComponentInfo();
222 m_detectorInfo = m_parmap->sharedDetectorInfo();
223 m_instrumentMetadata = m_parmap->sharedInstrumentMetadata();
224}
225
236
244
252
260
261namespace {
263
267struct RTP {
268 RTP() : radius(0.0), haveRadius(false), theta(0.0), phi(0.0) {}
269 double radius;
270 bool haveRadius;
271 double theta;
272 double phi;
273};
274
275struct ParameterValue {
276 ParameterValue(const Geometry::XMLInstrumentParameter &paramInfo, const API::Run &run)
277 : info(paramInfo), runData(run) {}
278
279 operator double() {
280 if (info.m_logfileID.empty())
281 return boost::lexical_cast<double>(info.m_value);
282 else {
283 const TimeROI *roi = &runData.getTimeROI();
284 return info.createParamValue(runData.getTimeSeriesProperty<double>(info.m_logfileID), roi);
285 }
286 }
287 operator int() { return boost::lexical_cast<int>(info.m_value); }
288 operator bool() {
289 if (boost::iequals(info.m_value, "true"))
290 return true;
291 else if (boost::iequals(info.m_value, "yes"))
292 return true;
293 else
294 return false;
295 }
297 const Run &runData;
298};
300} // namespace
301
302namespace {
303bool isPositionParameter(const std::string &name) { return ParameterMap::pos() == name; }
304
305bool isRotationParameter(const std::string &name) { return ParameterMap::rot() == name; }
306
307bool isScaleParameter(const std::string &name) { return (name == "scalex" || name == "scaley"); }
308
309bool isRedundantPosOrRot(const std::string &name) {
310 // Check size first as a small optimization.
311 return (name.size() == 4) &&
312 (name == "posx" || name == "posy" || name == "posz" || name == "rotx" || name == "roty" || name == "rotz");
313}
314
315template <class T> T getParam(const std::string &paramType, const std::string &paramValue) {
316 const std::string name = "dummy";
317 auto param = ParameterFactory::create(paramType, name);
318 param->fromString(paramValue);
319 return param->value<T>();
320}
321
322void updatePosition(ComponentInfo &componentInfo, const size_t compIndex, const V3D &newRelPos) {
323 V3D position = newRelPos;
324 if (componentInfo.hasParent(compIndex)) {
325 const auto parentIndex = componentInfo.parent(compIndex);
326 componentInfo.rotation(parentIndex).rotate(position);
327 position += componentInfo.position(parentIndex);
328 }
329 componentInfo.setPosition(compIndex, position);
330}
331
332void updateRotation(ComponentInfo &componentInfo, const size_t compIndex, const Quat &newRelRot) {
333 auto rotation = newRelRot;
334 if (componentInfo.hasParent(compIndex)) {
335 const auto parentIndex = componentInfo.parent(compIndex);
336 rotation = componentInfo.rotation(parentIndex) * newRelRot;
337 }
338 componentInfo.setRotation(compIndex, rotation);
339}
340
341void adjustPositionsFromScaleFactor(ComponentInfo &componentInfo, const size_t compIndex, const std::string &paramName,
342 double factor) {
343 double ScaleX = 1.0;
344 double ScaleY = 1.0;
345 if (paramName == "scalex")
346 ScaleX = factor;
347 else
348 ScaleY = factor;
349 applyRectangularDetectorScaleToComponentInfo(componentInfo, compIndex, ScaleX, ScaleY);
350}
351} // namespace
352
361
362 // Reference to the run
363 const auto &runData = run();
364
365 // Get pointer to parameter map that we may add parameters to and information
366 // about
367 // the parameters that my be specified in the instrument definition file (IDF)
370
371 auto &compInfo = mutableComponentInfo();
372 // The logfile parameters of this workspace: those of the instrument definition, plus any added
373 // since from parameter files
374 const auto &paramInfoFromIDF = compInfo.logfileParameters();
375
376 std::map<size_t, RTP> rtpParams;
377
378 // In this loop position and rotation parameters are inserted into the
379 // temporary map paramMapForPosAndRot. In the subsequent loop, after all
380 // parameters have been parsed, we update positions and rotations in
381 // DetectorInfo and the temporary map goes out of scope. The main reason for
382 // this is that ParameterMap will then take care of assembling parameters for
383 // individual position or rotation components into a vector or quaternion. In
384 // particular, we cannot directly change DetectorInfo since the order of
385 // rotation components is not guaranteed.
386 for (const auto &[key, paramInfo] : paramInfoFromIDF) {
387 const auto compIndex = key.first;
388 // Use the parameter's short name (e.g. "Alpha0"), not the cache key. The cache key may be
389 // function-qualified (e.g. "IkedaCarpenterPV:Alpha0") to keep two functions on the same
390 // component from clobbering each other, but downstream consumers always look up by short name.
391 const std::string &paramN = paramInfo->m_paramName;
392
393 try {
394 // Special case where user has specified r-position,t-position, and/or
395 // p-position.
396 // We need to know all three first to calculate a set of X,Y,Z
397 if (paramN.compare(1, 9, "-position") == 0) {
398 auto &rtpValues = rtpParams[compIndex]; // If not found, constructs default
399 double value = ParameterValue(*paramInfo, runData);
400 if (paramN.compare(0, 1, "r") == 0) {
401 rtpValues.radius = value;
402 rtpValues.haveRadius = true;
403 } else if (paramN.compare(0, 1, "t") == 0)
404 rtpValues.theta = value;
405 else if (paramN.compare(0, 1, "p") == 0)
406 rtpValues.phi = value;
407 if (rtpValues.haveRadius) {
408 V3D pos;
409 pos.spherical(rtpValues.radius, rtpValues.theta, rtpValues.phi);
410 posAndRot.setPosition(compIndex, pos);
411 }
412 } else {
413 populateWithParameter(compInfo, posAndRot, compIndex, paramN, *paramInfo, runData);
414 }
415 } catch (std::exception &exc) {
416 g_log.information() << "Unable to add component parameter '" << paramN << "'. Error: " << exc.what();
417 continue;
418 }
419 }
420 // Each component's position and rotation is applied once, complete. The accumulator has
421 // already folded the individual x/y/z coordinates and rotx/roty/rotz angles together, so
422 // there are no partial values left to ignore here.
423 for (const auto &[compIndex, newRelPos] : posAndRot.positions()) {
424 updatePosition(compInfo, compIndex, newRelPos);
425 }
426 for (const auto &[compIndex, newRelRot] : posAndRot.rotations()) {
427 updateRotation(compInfo, compIndex, newRelRot);
428 }
429 // Special case RectangularDetector: Parameters scalex and scaley affect pixel
430 // positions.
431 for (const auto &item : paramMap.entries()) {
432 if (isScaleParameter(item.second->name())) {
433 adjustPositionsFromScaleFactor(compInfo, item.first, item.second->name(), item.second->value<double>());
434 }
435 }
436 // paramMapForPosAndRot goes out of scope, dropping all position and rotation
437 // parameters of detectors (parameters for non-detector components have been
438 // inserted into paramMap via DetectorInfo::setPosition(IComponent *)).
439}
440
448 if (m_spectrumInfo)
451 m_spectrumInfo = std::make_unique<Beamline::SpectrumInfo>(count);
452 m_spectrumInfoWrapper = nullptr;
453}
454
460
465void ExperimentInfo::setDetectorGrouping(const size_t index, const std::set<detid_t> &detIDs) const {
466 SpectrumDefinition specDef;
467 for (const auto detID : detIDs) {
468 try {
469 const size_t detIndex = detectorInfo().indexOf(detID);
470 specDef.add(detIndex);
471 } catch (std::out_of_range &) {
472 // Silently strip bad detector IDs
473 }
474 }
475 m_spectrumInfo->setSpectrumDefinition(index, std::move(specDef));
477}
478
486void ExperimentInfo::updateCachedDetectorGrouping(const size_t /*unused*/) const {
487 throw std::runtime_error("ExperimentInfo::updateCachedDetectorGrouping: "
488 "Cannot update -- grouping information not "
489 "available");
490}
491
497 return *m_sample;
498}
499
509
513const Run &ExperimentInfo::run() const {
515 return *m_run;
516}
517
525 return m_run.access();
526}
527
530
533
546Kernel::Property *ExperimentInfo::getLog(const std::string &log) const {
548 try {
549 return run().getProperty(log);
551 // No log with that name
552 }
553 // If the instrument has a parameter with that name then take the value as a
554 // log name
555 const auto &compInfo = componentInfo();
556 const std::string logName = compInfo.getParameterAsString(compInfo.root(), log, false);
557 if (logName.empty()) {
558 throw std::invalid_argument("ExperimentInfo::getLog - No instrument parameter named \"" + log +
559 "\". Cannot access full log name");
560 }
561 return run().getProperty(logName);
562}
563
572double ExperimentInfo::getLogAsSingleValue(const std::string &log) const {
574 try {
575 return run().getPropertyAsSingleValue(log);
577 // No log with that name
578 }
579 // If the instrument has a parameter with that name then take the value as a
580 // log name
581 const auto &compInfo = componentInfo();
582 const std::string logName = compInfo.getParameterAsString(compInfo.root(), log, false);
583 if (logName.empty()) {
584 throw std::invalid_argument("ExperimentInfo::getLog - No instrument parameter named \"" + log +
585 "\". Cannot access full log name");
586 }
587 return run().getPropertyAsSingleValue(logName);
588}
589
596 const Run &thisRun = run();
597 if (!thisRun.hasProperty("run_number")) {
598 // No run_number property, default to 0
599 return 0;
600 } else {
601 Property const *prop = m_run->getProperty("run_number");
602 if (prop) {
603 // Use the string representation. That way both a string and a number
604 // property will work.
605 int val;
606 if (Strings::convert(prop->value(), val))
607 return val;
608 else
609 return 0;
610 }
611 }
612 return 0;
613}
614
625 static const char *emodeTag = "deltaE-mode";
626 std::string emodeStr;
627 if (run().hasProperty(emodeTag)) {
628 emodeStr = run().getPropertyValueAsType<std::string>(emodeTag);
629 } else if (sptr_instrument && componentInfo().hasParameter(componentInfo().root(), emodeTag, false)) {
630 emodeStr = componentInfo().getParameterAsString(componentInfo().root(), emodeTag, false);
631 } else {
633 }
634 return Kernel::DeltaEMode::fromString(emodeStr);
635}
636
646double ExperimentInfo::getEFixed(const detid_t detID) const {
648 IDetector_const_sptr det = getInstrument()->getDetector(detID);
649 return getEFixed(det);
650}
651
658double ExperimentInfo::getEFixed(const std::shared_ptr<const Geometry::IDetector> &detector) const {
661 return getEFixedGivenEMode(detector, emode);
662}
663
664double ExperimentInfo::getEFixedForIndirect(const std::shared_ptr<const Geometry::IDetector> &detector,
665 const std::vector<std::string> &parameterNames) const {
666 double efixed = 0.;
667 for (auto &parameterName : parameterNames) {
668 Parameter_sptr par = constInstrumentParameters().getRecursive(detector.get(), parameterName);
669 if (par) {
670 efixed = par->value<double>();
671 } else {
672 std::vector<double> efixedVec = detector->getNumberParameter(parameterName);
673 if (efixedVec.empty()) {
674 int detid = detector->getID();
675 IDetector_const_sptr detectorSingle = getInstrument()->getDetector(detid);
676 efixedVec = detectorSingle->getNumberParameter(parameterName);
677 }
678 if (!efixedVec.empty()) {
679 efixed = efixedVec.at(0);
680 }
681 }
682 }
683 if (efixed == 0.) {
684 std::ostringstream os;
685 os << "ExperimentInfo::getEFixed - Indirect mode efixed requested but "
686 "detector has no Efixed parameter attached. ID="
687 << detector->getID();
688 throw std::runtime_error(os.str());
689 }
690 return efixed;
691}
692
700double ExperimentInfo::getEFixedGivenEMode(const std::shared_ptr<const Geometry::IDetector> &detector,
701 const Kernel::DeltaEMode::Type emode) const {
702 if (emode == Kernel::DeltaEMode::Direct) {
703 double efixed = 0.;
704 for (auto &parameterName : {"Ei", "EnergyRequested", "EnergyEstimate"}) {
705 if (run().hasProperty(parameterName)) {
706 efixed = run().getPropertyValueAsType<double>(parameterName);
707 break;
708 }
709 }
710 if (efixed == 0.) {
711 throw std::runtime_error("Experiment logs do not contain an Ei "
712 "value. Have you run GetEi?");
713 }
714 return efixed;
715 } else if (emode == Kernel::DeltaEMode::Indirect) {
716 if (!detector)
717 throw std::runtime_error("ExperimentInfo::getEFixed - Indirect mode "
718 "efixed requested without a valid detector.");
719 return getEFixedForIndirect(detector, {"Efixed", "EFixed-val"});
720 } else {
721 throw std::runtime_error("ExperimentInfo::getEFixed - EFixed requested for "
722 "elastic mode, don't know what to do!");
723 }
724}
725
726void ExperimentInfo::setEFixed(const detid_t detID, const double value) {
728 size_t detIndex;
729 try {
730 detIndex = detectorInfo().indexOf(detID);
731 } catch (const std::out_of_range &) {
732 throw Kernel::Exception::NotFoundError("Instrument: Detector with ID " + std::to_string(detID) + " not found.", "");
733 }
734 // Detector indices are also component indices
735 mutableComponentInfo().addDouble(detIndex, "Efixed", value);
736}
737
748 std::string date;
749 try {
750 date = run().startTime().toISO8601String();
751 } catch (std::runtime_error &) {
752 g_log.information("run_start/start_time not stored in workspace. Default "
753 "to current date.");
754 date = Types::Core::DateAndTime::getCurrentTime().toISO8601String();
755 }
756 return date;
757}
758
767 std::string date;
768 try {
769 date = run().startTime().toFormattedString();
770 } catch (std::runtime_error &) {
771 g_log.information("Note: run_start/start_time not stored in workspace.");
772 }
773 return date;
774}
775
784 std::string date;
785 try {
786 date = run().endTime().toFormattedString();
787 } catch (std::runtime_error &) {
788 g_log.information("Note: run_start/start_time not stored in workspace.");
789 }
790 return date;
791}
792
793//-----------------------------------------------------------------------------------------------------------------------
794
802 if (!m_detectorInfo) {
803 throw std::runtime_error("Cannot return reference to NULL DetectorInfo");
804 }
805 return *m_detectorInfo;
806}
807
811 if (!m_detectorInfo) {
812 throw std::runtime_error("Cannot return reference to NULL DetectorInfo");
813 }
814 return *m_detectorInfo;
815}
816
825 std::lock_guard<std::mutex> lock{m_spectrumInfoMutex};
826 if (!m_spectrumInfo) // this should happen only if not MatrixWorkspace
829 static_cast<void>(detectorInfo());
830 m_spectrumInfoWrapper = std::make_unique<SpectrumInfo>(*m_spectrumInfo, *this, m_parmap->mutableDetectorInfo());
831 }
832 }
833 // Rebuild any spectrum definitions that are out of date. Accessing
834 // `API::SpectrumInfo` will rebuild invalid spectrum definitions as it
835 // encounters them (if detector IDs in an `ISpectrum` are changed), however we
836 // need to deal with one special case here:
837 // If two algorithms (or two threads in the same algorithm) access the same
838 // workspace for reading at the same time, calls to
839 // `updateSpectrumDefinitionIfNecessary` done by `API::SpectrumInfo` break
840 // thread-safety. `Algorithm` sets a read-lock, but this lazy update method is
841 // `const` and will modify internals of the workspace nevertheless. We thus
842 // need explicit locking here. Note that we do not need extra locking in the
843 // case of `ExperimentInfo::mutableSpectrumInfo` or other calls to
844 // `updateSpectrumDefinitionIfNecessary` done by `API::SpectrumInfo`: If the
845 // workspace is only read-locked, this update will ensure that no updates will
846 // be triggered by SpectrumInfo, since changing detector IDs in an `ISpectrum`
847 // is not possible for a read-only workspace. If the workspace is write-locked
848 // detector IDs in ISpectrum may change, but the write-lock by `Algorithm`
849 // guarantees that there is no concurrent reader and thus updating is safe.
851 [](char i) { return i == 1; })) {
852 std::lock_guard<std::mutex> lock{m_spectrumInfoMutex};
854 [](char i) { return i == 1; })) {
855 auto size = static_cast<int64_t>(m_spectrumInfoWrapper->size());
856#pragma omp parallel for
857 for (int64_t i = 0; i < size; ++i) {
859 }
860 }
861 }
862 return *m_spectrumInfoWrapper;
863}
864
868 return const_cast<SpectrumInfo &>(static_cast<const ExperimentInfo &>(*this).spectrumInfo());
869}
870
873 if (!m_componentInfo) {
874 throw std::runtime_error("Cannot return reference to NULL ComponentInfo");
875 }
876 return *m_componentInfo;
877}
878
881 if (!m_componentInfo) {
882 throw std::runtime_error("Cannot return reference to NULL ComponentInfo");
883 }
884 return *m_componentInfo;
885}
886
896 std::lock_guard<std::mutex> lock{m_baseComponentInfoMutex};
897 if (!m_baseComponentInfo) {
898 // The wrappers refer to sptr_instrument without owning it. That is safe because setInstrument() resets them
899 // before replacing sptr_instrument, and they are declared after it, so are destroyed before it.
901 }
902 return *m_baseComponentInfo;
903}
904
908 throw std::runtime_error("Cannot return reference to NULL InstrumentMetadata");
909 }
910 return *m_instrumentMetadata;
911}
912
914void ExperimentInfo::setSpectrumDefinitions(Kernel::cow_ptr<std::vector<SpectrumDefinition>> spectrumDefinitions) {
915 if (spectrumDefinitions) {
916 m_spectrumInfo = std::make_unique<Beamline::SpectrumInfo>(std::move(spectrumDefinitions));
919 } else {
920 // Keep the old m_spectrumInfo which should have the correct size, but
921 // invalidate all definitions.
923 }
924 m_spectrumInfoWrapper = nullptr;
925}
926
930 Geometry::ComponentInfo const &compInfo = componentInfo();
931 return compInfo.name(compInfo.root());
932}
933
940 // This uses a vector of char, such that flags for different indices can be
941 // set from different threads (std::vector<bool> is not thread-safe).
943}
944
949
956 if (m_spectrumInfo && (m_spectrumInfo->size() != 0))
957 return;
958 const auto &detIDs = sptr_instrument->getDetectorIDs();
959 setNumberOfDetectorGroups(detIDs.size());
960 size_t specIndex = 0;
961 for (const auto detID : detIDs) {
962 m_det2group[detID] = specIndex;
963 const size_t detIndex = detectorInfo().indexOf(detID);
964 SpectrumDefinition specDef;
965 specDef.add(detIndex);
966 // cppcheck-suppress nullPointerRedundantCheck
967 m_spectrumInfo->setSpectrumDefinition(specIndex, std::move(specDef));
968 m_spectrumDefinitionNeedsUpdate.at(specIndex) = 0;
969 specIndex++;
970 }
971}
972
978
983void ExperimentInfo::saveExperimentInfoNexus(Nexus::File *file, bool saveLegacyInstrument) const {
985 if (saveLegacyInstrument) {
986 instrument->saveNexus(file, "instrument");
987 }
988 sample().saveNexus(file, "sample");
989 run().saveNexus(file, "logs");
990}
991
998void ExperimentInfo::saveExperimentInfoNexus(Nexus::File *file, bool saveInstrument, bool saveSample,
999 bool saveLogs) const {
1000 Instrument_const_sptr instrument = getInstrument();
1001
1002 if (saveInstrument)
1003 instrument->saveNexus(file, "instrument");
1004 if (saveSample)
1005 sample().saveNexus(file, "sample");
1006 if (saveLogs)
1007 run().saveNexus(file, "logs");
1008}
1009
1014void ExperimentInfo::loadSampleAndLogInfoNexus(Nexus::File *file, std::string const &prefix) {
1015 // First, the sample and then the logs
1016 int sampleVersion = mutableSample().loadNexus(file, "sample");
1017 if (sampleVersion == 0) {
1018 // Old-style (before Sep-9-2011) NXS processed
1019 // sample field contains both the logs and the sample details
1020 file->openGroup("sample", "NXsample");
1021 this->mutableRun().loadNexus(file, "", prefix);
1022 file->closeGroup();
1023 } else {
1024 // Newer style: separate "logs" field for the Run object
1025 this->mutableRun().loadNexus(file, "logs", prefix);
1026 }
1027}
1028
1033 // First, the sample and then the logs
1034 int sampleVersion = mutableSample().loadNexus(file, "sample");
1035 if (sampleVersion == 0) {
1036 // Old-style (before Sep-9-2011) NXS processed
1037 // sample field contains both the logs and the sample details
1038 file->openGroup("sample", "NXsample");
1039 this->mutableRun().loadNexus(file, "");
1040 file->closeGroup();
1041 } else {
1042 // Newer style: separate "logs" field for the Run object
1043 this->mutableRun().loadNexus(file, "logs");
1044 }
1045}
1046
1047void ExperimentInfo::loadExperimentInfoNexus(const std::string &nxFilename, Nexus::File *file,
1048 std::string &parameterStr, const std::string &prefix) {
1049 // TODO load sample and log info
1050 loadSampleAndLogInfoNexus(file, prefix);
1051 loadInstrumentInfoNexus(nxFilename, file, parameterStr);
1052}
1053
1064void ExperimentInfo::loadExperimentInfoNexus(const std::string &nxFilename, Nexus::File *file,
1065 std::string &parameterStr) {
1066 // load sample and log info
1068
1069 loadInstrumentInfoNexus(nxFilename, file, parameterStr);
1070}
1071
1082void ExperimentInfo::loadInstrumentInfoNexus(const std::string &nxFilename, Nexus::File *file,
1083 std::string &parameterStr) {
1084
1085 // Open instrument group
1086 file->openGroup("instrument", "NXinstrument");
1087
1088 // Try to get the instrument embedded in the Nexus file
1089 std::string instrumentName;
1090 std::string instrumentXml;
1091 loadEmbeddedInstrumentInfoNexus(file, instrumentName, instrumentXml);
1092
1093 // load parameters if found
1094 loadInstrumentParametersNexus(file, parameterStr);
1095
1096 // Close the instrument group
1097 file->closeGroup();
1098
1099 // Set the instrument given the name and and XML obtained
1100 setInstumentFromXML(nxFilename, instrumentName, instrumentXml);
1101}
1102
1112void ExperimentInfo::loadInstrumentInfoNexus(const std::string &nxFilename, Nexus::File *file) {
1113
1114 // Open instrument group
1115 file->openGroup("instrument", "NXinstrument");
1116
1117 // Try to get the instrument embedded in the Nexus file
1118 std::string instrumentName;
1119 std::string instrumentXml;
1120 loadEmbeddedInstrumentInfoNexus(file, instrumentName, instrumentXml);
1121
1122 // Close the instrument group
1123 file->closeGroup();
1124
1125 // Set the instrument given the name and and XML obtained
1126 setInstumentFromXML(nxFilename, instrumentName, instrumentXml);
1127}
1128
1135void ExperimentInfo::loadEmbeddedInstrumentInfoNexus(Nexus::File *file, std::string &instrumentName,
1136 std::string &instrumentXml) {
1137
1138 file->readData("name", instrumentName);
1139
1140 try {
1141 file->openGroup("instrument_xml", "NXnote");
1142 file->readData("data", instrumentXml);
1143 file->closeGroup();
1144 } catch (Nexus::Exception const &ex) {
1145 g_log.debug(std::string("Unable to load instrument_xml: ") + ex.what());
1146 }
1147}
1148
1158void ExperimentInfo::setInstumentFromXML(const std::string &nxFilename, std::string &instrumentName,
1159 std::string &instrumentXml) {
1160
1161 instrumentXml = Strings::strip(instrumentXml);
1162 instrumentName = Strings::strip(instrumentName);
1163 std::string instrumentFilename;
1164 if (!instrumentXml.empty()) {
1165 // instrument xml is being loaded from the nxs file, set the
1166 // instrumentFilename
1167 // to identify the Nexus file as the source of the data
1168 instrumentFilename = nxFilename;
1169 g_log.debug() << "Using instrument IDF XML text contained in nexus file.\n";
1170 } else {
1171 // XML was not included or was empty
1172 // Use the instrument name to find the file
1173 instrumentFilename = InstrumentFileFinder::getInstrumentFilename(instrumentName, getWorkspaceStartDate());
1174 // And now load the contents
1175 instrumentXml = loadInstrumentXML(instrumentFilename);
1176 }
1177
1178 // ---------- Now parse that XML to make the instrument -------------------
1179 if (!instrumentXml.empty() && !instrumentName.empty()) {
1180 InstrumentDefinitionParser parser(instrumentFilename, instrumentName, instrumentXml);
1181
1182 std::string instrumentNameMangled = parser.getMangledName();
1183 Instrument_sptr instr;
1184 // Check whether the instrument is already in the InstrumentDataService
1185 if (InstrumentDataService::Instance().doesExist(instrumentNameMangled)) {
1186 // If it does, just use the one from the one stored there
1187 instr = InstrumentDataService::Instance().retrieve(instrumentNameMangled);
1188 } else {
1189 // Really create the instrument
1190 instr = parser.parseXML(nullptr);
1191 // Parse the instrument tree (internally create ComponentInfo and
1192 // DetectorInfo). This is an optimization that avoids duplicate parsing
1193 // of the instrument tree when loading multiple workspaces with the same
1194 // instrument. As a consequence less time is spent and less memory is
1195 // used. Note that this is only possible since the tree in `instrument`
1196 // will not be modified once we add it to the IDS.
1197 instr->parseTreeAndCacheBeamline();
1198
1199 // Add to data service for later retrieval
1200 InstrumentDataService::Instance().add(instrumentNameMangled, instr);
1201 }
1202 // Now set the instrument
1203 this->setInstrument(instr);
1204 }
1205}
1206
1213std::string ExperimentInfo::loadInstrumentXML(const std::string &filename) {
1214 try {
1215 return Strings::loadFile(filename);
1216 } catch (std::exception &e) {
1217 g_log.error() << "Error loading instrument IDF file: " << filename << ".\n";
1218 g_log.debug() << e.what() << '\n';
1219 throw;
1220 }
1221}
1222
1229void ExperimentInfo::loadInstrumentParametersNexus(Nexus::File *file, std::string &parameterStr) {
1230 try {
1231 file->openGroup("instrument_parameter_map", "NXnote");
1232 file->readData("data", parameterStr);
1233 file->closeGroup();
1234 } catch (Nexus::Exception const &ex) {
1235 g_log.debug(std::string("Unable to load instrument_parameter_map: ") + ex.what());
1236 g_log.information("Parameter map entry missing from NeXus file. Continuing without it.");
1237 }
1238}
1239
1246void ExperimentInfo::readParameterMap(const std::string &parameterStr) {
1248 auto &compInfo = mutableComponentInfo();
1249 auto &detInfo = mutableDetectorInfo();
1250
1253 Mantid::Kernel::StringTokenizer splitter(parameterStr, "|", options);
1254
1255 auto iend = splitter.end();
1256
1258 const std::string visibilityKey = "visible:"; // if visibility is defined, the value will follow this key
1259 // std::string prev_name;
1260 for (auto itr = splitter.begin(); itr != iend; ++itr) {
1261 tokens = Mantid::Kernel::StringTokenizer(*itr, ";");
1262 if (tokens.count() < 4)
1263 continue;
1264 std::string comp_name = tokens[0];
1265 // if( comp_name == prev_name ) continue; this blocks reading in different
1266 // parameters of the same component. RNT
1267 // prev_name = comp_name;
1268 // Resolve the component once, to an index. Both forms written by ParameterMap::asString()
1269 // are resolvable without consulting the legacy instrument tree: "detID:<id>" through
1270 // DetectorInfo, and a full path through ComponentInfo::indexOfFullName().
1271 size_t compIndex = Geometry::ComponentInfo::invalidIndex;
1272 if (comp_name.find("detID:") != std::string::npos) {
1273 const auto detID = static_cast<detid_t>(std::stoi(comp_name.substr(6)));
1274 try {
1275 // Detectors occupy the leading component indices, so a detector index is also its
1276 // component index.
1277 compIndex = detInfo.indexOf(detID);
1278 } catch (std::out_of_range &) {
1279 g_log.warning() << "Cannot find detector " << detID << '\n';
1280 continue;
1281 }
1282 } else {
1283 compIndex = compInfo.indexOfFullName(comp_name);
1284 if (compIndex == Geometry::ComponentInfo::invalidIndex) {
1285 // indexOfFullName() resolves only exact, fully-rooted paths. getComponentByName() is
1286 // more lenient -- it accepts a bare name anywhere in the tree and lets path segments be
1287 // skipped -- so fall back to it rather than rejecting strings the old code accepted.
1288 // Reproducing that leniency on ComponentInfo is its own piece of work.
1289 const auto *comp = sptr_instrument->getComponentByName(comp_name).get();
1290 if (comp) {
1291 compIndex = compInfo.indexOfOrInvalid(comp->getComponentID());
1292 }
1293 if (compIndex == Geometry::ComponentInfo::invalidIndex) {
1294 g_log.warning() << "Cannot find component " << comp_name << '\n';
1295 continue;
1296 }
1297 }
1298 }
1299
1300 // create parameter's value as a sum of all tokens with index 3 or larger
1301 // this allow a parameter's value to contain ";"
1302 std::string paramValue = tokens[3];
1303 auto size = static_cast<int>(tokens.count());
1304 for (int i = 4; i < size; i++)
1305 paramValue += ";" + tokens[i];
1306 const auto &paramType = tokens[1];
1307 const auto &paramName = tokens[2];
1308 auto &paramVisibility = tokens[size - 1]; // parameter visibility, if defined, is the last token
1309 if (paramVisibility.find(visibilityKey) > paramVisibility.size())
1310 paramVisibility = "true"; // visibility not defined: default to visible
1311 else { // defined, the paramValue has one too many entries, -1 to remove also the semicolon
1312 paramVisibility =
1313 paramVisibility.substr(paramVisibility.find(visibilityKey) + visibilityKey.size(), paramVisibility.size());
1314 paramValue.erase(paramValue.find(visibilityKey) - 1, paramValue.size());
1315 }
1316 const auto paramDescr = std::string("");
1317 if (paramName == "masked") {
1318 auto value = getParam<bool>(paramType, paramValue);
1319 if (value) {
1320 // Do not add masking to ParameterMap, it is stored in DetectorInfo
1321 const auto componentIndex = compIndex;
1322 if (!compInfo.isDetector(componentIndex)) {
1323 throw std::runtime_error("Found masking for a non-detector "
1324 "component. This is not possible");
1325 } else
1326 detInfo.setMasked(componentIndex, value); // all detector indexes
1327 // have same component
1328 // index (guarantee)
1329 }
1330 } else if (isPositionParameter(paramName)) {
1331 // We are parsing a string obtained from a ParameterMap. The map may
1332 // contain posx, posy, and posz (in addition to pos). However, when these
1333 // component wise positions are set, 'pos' is updated accordingly. We are
1334 // thus ignoring position components below.
1335 const auto newRelPos = getParam<V3D>(paramType, paramValue);
1336 updatePosition(compInfo, compIndex, newRelPos);
1337 } else if (isRotationParameter(paramName)) {
1338 // We are parsing a string obtained from a ParameterMap. The map may
1339 // contain rotx, roty, and rotz (in addition to rot). However, when these
1340 // component wise rotations are set, 'rot' is updated accordingly. We are
1341 // thus ignoring rotation components below.
1342 const auto newRelRot = getParam<Quat>(paramType, paramValue);
1343 updateRotation(compInfo, compIndex, newRelRot);
1344 } else if (!isRedundantPosOrRot(paramName)) {
1345 // Special case RectangularDetector: Parameters scalex and scaley affect
1346 // pixel positions, but we must also add the parameter below.
1347 if (isScaleParameter(paramName))
1348 adjustPositionsFromScaleFactor(compInfo, compIndex, paramName, getParam<double>(paramType, paramValue));
1349 // For fitting parameters, route through addFittingParameter so that two functions on the same
1350 // component sharing a parameter short name (e.g. IkedaCarpenterPV:Gamma and
1351 // Bk2BkExpConvPV:Gamma) both survive a NeXus save/load round-trip. ParameterMap::add only
1352 // dedupes by (component, name) and would silently overwrite the first entry with the second.
1353 // The fitting-function name is embedded as the second comma-separated field of the value
1354 // string written by populateWithParameter().
1355
1356 // string from populateWithParameter() is expected to be " , " (space-comma-space) separated:
1357 // "m_value , m_fittingFunction , name , constraint[0] , constraint[1] , penaltyFactor , tie ,
1358 // formula , formulaUnit , resultUnit , interpolation"
1359 if (paramType == "fitting") {
1360 std::string fittingFunction;
1361 // Locate the second field by finding the first two commas; the fitting function is the
1362 // text between them. If there are fewer than two commas the value is malformed and
1363 // fittingFunction stays empty, falling back to the plain add() below.
1364 const auto firstComma = paramValue.find(',');
1365 if (firstComma != std::string::npos) {
1366 const auto secondComma = paramValue.find(',', firstComma + 1);
1367 if (secondComma != std::string::npos) {
1368 // Take the raw second field, e.g. " IkedaCarpenterPV " from "3.5 , IkedaCarpenterPV , ...".
1369 fittingFunction = paramValue.substr(firstComma + 1, secondComma - firstComma - 1);
1370 // Trim the surrounding spaces/tabs introduced by the " , " separator.
1371 const auto firstNonSpace = fittingFunction.find_first_not_of(" \t");
1372 if (firstNonSpace != std::string::npos) {
1373 const auto lastNonSpace = fittingFunction.find_last_not_of(" \t");
1374 fittingFunction = fittingFunction.substr(firstNonSpace, lastNonSpace - firstNonSpace + 1);
1375 } else
1376 // Field was entirely whitespace (e.g. "3.5 , , ..."): treat as no fitting function.
1377 fittingFunction.clear();
1378 }
1379 }
1380 if (!fittingFunction.empty()) {
1381 pmap.addFittingParameter(compIndex, paramName, fittingFunction, paramValue, &paramDescr, paramVisibility);
1382 } else {
1383 pmap.add(paramType, compIndex, paramName, paramValue, &paramDescr, paramVisibility);
1384 }
1385 } else {
1386 pmap.add(paramType, compIndex, paramName, paramValue, &paramDescr, paramVisibility);
1387 }
1388 }
1389 }
1390}
1391
1404 Geometry::PositionAndRotationAccumulator &posAndRot, const size_t compIndex,
1405 const std::string &name, const Geometry::XMLInstrumentParameter &paramInfo,
1406 const Run &runData) {
1407 const std::string &category = paramInfo.m_type;
1408 ParameterValue paramValue(paramInfo,
1409 runData); // Defines implicit conversion operator
1410
1411 const std::string *pDescription = nullptr;
1412 if (!paramInfo.m_description.empty())
1413 pDescription = &paramInfo.m_description;
1414 std::string pVisible = "true";
1415 if (!paramInfo.m_visible.empty())
1416 pVisible = paramInfo.m_visible;
1417
1418 // Some names are special. Values should be convertible to double
1419 if (name == "masked") {
1420 bool value(paramValue);
1421 if (value) {
1422 // Do not add masking to ParameterMap, it is stored in DetectorInfo
1423 if (!compInfo.isDetector(compIndex))
1424 throw std::runtime_error("Found masking for a non-detector component. This is not possible");
1425 mutableDetectorInfo().setMasked(compIndex,
1426 paramValue); // all detector indexes have
1427 // same component index
1428 // (guarantee)
1429 }
1430 } else if (name == "x" || name == "y" || name == "z") {
1431 // Seeded from the component's current position relative to its parent, so specifying one
1432 // coordinate leaves the other two alone. It must be the relative position: the accumulated
1433 // value is applied as a parent-relative one, so seeding with the absolute position would
1434 // re-apply the parent's rotation and translation on every call.
1435 posAndRot.setCoordinate(compIndex, name, paramValue, compInfo.relativePosition(compIndex));
1436 } else if (name == "rot" || name == "rotx" || name == "roty" || name == "rotz") {
1437 if (!posAndRot.setRotationAngle(compIndex, name, paramValue)) {
1438 // "rot" itself names no axis and is deliberately dropped, as it always has been.
1439 g_log.warning() << "Ignoring instrument parameter '" << name << "': it does not name a rotation axis.\n";
1440 }
1441 } else if (category == "fitting") {
1442 std::ostringstream str;
1443 // read parameter map relies on extracting m_fittingFunction from this string - edit with care
1444 str << paramInfo.m_value << " , " << paramInfo.m_fittingFunction << " , " << name << " , "
1445 << paramInfo.m_constraint[0] << " , " << paramInfo.m_constraint[1] << " , " << paramInfo.m_penaltyFactor
1446 << " , " << paramInfo.m_tie << " , " << paramInfo.m_formula << " , " << paramInfo.m_formulaUnit << " , "
1447 << paramInfo.m_resultUnit << " , " << (*(paramInfo.m_interpolation));
1448 // Dedupe by (name, fitting function) — otherwise two functions on the same component sharing
1449 // a parameter short name (e.g. Bk2BkExpConvPV:Gamma and IkedaCarpenterPV:Gamma) would clobber
1450 // each other in the map.
1451 compInfo.addFittingParameter(compIndex, name, paramInfo.m_fittingFunction, str.str(), pDescription, pVisible);
1452 } else if (category == "string") {
1453 compInfo.addString(compIndex, name, paramInfo.m_value, pDescription, pVisible);
1454 } else if (category == "bool") {
1455 compInfo.addBool(compIndex, name, paramValue, pDescription, pVisible);
1456 } else if (category == "int") {
1457 compInfo.addInt(compIndex, name, paramValue, pDescription, pVisible);
1458 } else { // assume double
1459 compInfo.addDouble(compIndex, name, paramValue, pDescription, pVisible);
1460 }
1461}
1462
1464 // The default implementation does nothing. Used by subclasses
1465 // (FileBackedExperimentInfo) to load content from files upon access.
1466}
1467
1468} // namespace Mantid::API
1469
1470namespace Mantid::Kernel {
1471
1472template <>
1474IPropertyManager::getValue<Mantid::API::ExperimentInfo_sptr>(const std::string &name) const {
1475 auto *prop = dynamic_cast<PropertyWithValue<Mantid::API::ExperimentInfo_sptr> *>(getPointerToProperty(name));
1476 if (prop) {
1477 return *prop;
1478 } else {
1479 std::string message =
1480 "Attempt to assign property " + name + " to incorrect type. Expected shared_ptr<ExperimentInfo>.";
1481 throw std::runtime_error(message);
1482 }
1483}
1484
1485template <>
1487IPropertyManager::getValue<Mantid::API::ExperimentInfo_const_sptr>(const std::string &name) const {
1488 auto const *prop = dynamic_cast<PropertyWithValue<Mantid::API::ExperimentInfo_sptr> *>(getPointerToProperty(name));
1489 if (prop) {
1490 return prop->operator()();
1491 } else {
1492 std::string message =
1493 "Attempt to assign property " + name + " to incorrect type. Expected const shared_ptr<ExperimentInfo>.";
1494 throw std::runtime_error(message);
1495 }
1496}
1497
1498} // namespace Mantid::Kernel
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
double position
Definition GetAllEi.cpp:154
std::map< DeltaEMode::Type, std::string > index
int count
counter
Definition Matrix.cpp:37
Mantid::Kernel::Quat(ComponentInfo::* rotation)(const size_t) const
This class is shared by a few Workspace types and holds information related to a particular experimen...
void loadEmbeddedInstrumentInfoNexus(Nexus::File *file, std::string &instrumentName, std::string &instrumentXml)
Attempt to load instrument embedded in Nexus file. *file must have instrument group open.
Geometry::DetectorInfo & mutableDetectorInfo()
Return a non-const reference to the DetectorInfo object.
Run & mutableRun()
Writable version of the run object.
Kernel::cow_ptr< Sample > m_sample
The information on the sample environment.
const SpectrumInfo & spectrumInfo() const
Return a reference to the SpectrumInfo object.
Geometry::InstrumentMetadata const & instrumentMetadata() const
std::shared_ptr< Geometry::ParameterMap > m_parmap
Parameters modifying the base instrument.
ExperimentInfo()
Default constructor.
void setInstumentFromXML(const std::string &nxFilename, std::string &instrumentName, std::string &instrumentXml)
Set the instrument given the name and XML leading from IDF file if XML string is empty.
std::shared_ptr< Geometry::InstrumentMetadata > m_instrumentMetadata
Geometry::ComponentInfo & mutableComponentInfo()
std::unique_ptr< Geometry::ComponentInfo > m_baseComponentInfo
const Geometry::DetectorInfo & detectorInfo() const
Return a const reference to the DetectorInfo object.
virtual ExperimentInfo * cloneExperimentInfo() const
Clone us.
std::unordered_map< detid_t, size_t > m_det2group
Detector grouping information.
std::shared_ptr< Geometry::DetectorInfo > m_detectorInfo
double getEFixed(const detid_t detID) const
Easy access to the efixed value for this run & detector ID.
void readParameterMap(const std::string &parameterStr)
Populate the parameter map given a string.
virtual void populateIfNotLoaded() const
Called as the first operation of most public methods.
void invalidateSpectrumDefinition(const size_t index)
Notifies the ExperimentInfo that a spectrum definition has changed.
void saveExperimentInfoNexus(Nexus::File *file, bool saveLegacyInstrument=true) const
Saves this experiment description to the open NeXus file.
size_t numberOfDetectorGroups() const
Returns the number of detector groups.
void updateSpectrumDefinitionIfNecessary(const size_t index) const
std::string getAvailableWorkspaceStartDate() const
Return workspace start date as a formatted string (strftime, as returned by Types::Core::DateAndTime)...
std::unique_ptr< Geometry::DetectorInfo > m_baseDetectorInfo
Lazily-built 2.0 layers of the base instrument, reset whenever the instrument is set.
std::string loadInstrumentXML(const std::string &filename)
Loads the contents of a file and returns the string The file is assumed to be an IDF,...
virtual ~ExperimentInfo()
Virtual destructor.
std::shared_ptr< Geometry::ComponentInfo > m_componentInfo
The 2.0 instrument layers, of which this object is the primary owner.
virtual void updateCachedDetectorGrouping(const size_t index) const
Update detector grouping for spectrum with given index.
void cacheDefaultDetectorGrouping() const
Sets up a default detector grouping.
void copyExperimentInfoFrom(const ExperimentInfo *other)
Copy everything from the given experiment object.
const Run & run() const
Run details object access.
Geometry::ComponentInfo const & baseComponentInfo() const
Returns a ComponentInfo for the base (unparametrized) instrument, i.e.
std::string getInstrumentName() const
Return the name of the instrument from the ComponentInfo object.
void loadSampleAndLogInfoNexus(Nexus::File *file, std::string const &prefix)
Load the sample and log info from an open NeXus file.
const Geometry::ParameterMap & constInstrumentParameters() const
Const version.
Geometry::Instrument_const_sptr getInstrument() const
Returns the parameterized instrument.
Kernel::DeltaEMode::Type getEMode() const
Returns the emode for this run.
std::unique_ptr< Beamline::SpectrumInfo > m_spectrumInfo
void loadExperimentInfoNexus(std::string const &nxFilename, Nexus::File *file, std::string &parameterStr, std::string const &prefix)
const Sample & sample() const
Sample accessors.
void setEFixed(const detid_t detID, const double value)
Set the efixed value for a given detector ID.
double getEFixedGivenEMode(const std::shared_ptr< const Geometry::IDetector > &detector, const Kernel::DeltaEMode::Type emode) const
Easy access to the efixed value for this run & detector.
double getEFixedForIndirect(const std::shared_ptr< const Geometry::IDetector > &detector, const std::vector< std::string > &parameterNames) const
const std::string toString() const
Returns a string description of the object.
const Geometry::ParameterMap & instrumentParameters() const
Returns the set of parameters modifying the base instrument (const-version)
int getRunNumber() const
Utility method to get the run number.
std::string getAvailableWorkspaceEndDate() const
Return workspace end date as a formatted string (strftime style, as returned by Kernel::DateAdnTime) ...
const Geometry::ComponentInfo & componentInfo() const
std::string getWorkspaceStartDate() const
Returns the start date for this experiment (or current time if no info available)
void setInstrument(const Geometry::Instrument_const_sptr &instr)
Instrument accessors.
std::unique_ptr< SpectrumInfo > m_spectrumInfoWrapper
void setSharedRun(Kernel::cow_ptr< Run > run)
Set the run object. Use in particular to clear run without copying old run.
void setDetectorGrouping(const size_t index, const std::set< detid_t > &detIDs) const
Sets the detector grouping for the spectrum with the given index.
Kernel::cow_ptr< Run > sharedRun()
Return the cow ptr of the run.
ExperimentInfo & operator=(const ExperimentInfo &)
Implements the copy assignment operator.
void setSpectrumDefinitions(Kernel::cow_ptr< std::vector< SpectrumDefinition > > spectrumDefinitions)
Sets the SpectrumDefinition for all spectra.
std::vector< char > m_spectrumDefinitionNeedsUpdate
double getLogAsSingleValue(const std::string &log) const
Access a single value from a log for this experiment.
SpectrumInfo & mutableSpectrumInfo()
Return a non-const reference to the SpectrumInfo object.
void adoptBeamline()
Take co-ownership of whatever m_parmap currently holds.
void loadInstrumentParametersNexus(Nexus::File *file, std::string &parameterStr)
Load instrument parameters from an open Nexus file in Instrument group if found there.
void setNumberOfDetectorGroups(const size_t count) const
Sets the number of detector groups.
Sample & mutableSample()
Writable version of the sample object.
Geometry::Instrument_const_sptr sptr_instrument
The base (unparametrized) instrument.
void loadInstrumentInfoNexus(const std::string &nxFilename, Nexus::File *file, std::string &parameterStr)
Load the instrument from an open NeXus file.
void populateInstrumentParameters()
Add parameters to the instrument parameter map that are defined in instrument definition file or para...
Kernel::Property * getLog(const std::string &log) const
Access a log for this experiment.
void invalidateAllSpectrumDefinitions()
Sets flags for all spectrum definitions indicating that they need to be updated.
Kernel::cow_ptr< Run > m_run
The run information.
void populateWithParameter(Geometry::ComponentInfo &compInfo, Geometry::PositionAndRotationAccumulator &posAndRot, const size_t compIndex, const std::string &name, const Geometry::XMLInstrumentParameter &paramInfo, const Run &runData)
Fill with given instrument parameter.
static std::string getInstrumentFilename(const std::string &instrumentName, const std::string &date="")
Get the IDF using the instrument name and date.
const Types::Core::DateAndTime endTime() const
Return the run end time.
bool hasProperty(const std::string &name) const
Does the property exist on the object.
const Types::Core::DateAndTime startTime() const
Return the run start time.
Kernel::Property * getProperty(const std::string &name) const
Returns the named property as a pointer.
double getPropertyAsSingleValue(const std::string &name, Kernel::Math::StatisticType statistic=Kernel::Math::Mean) const
Returns a property as a single double value from its name.
HeldType getPropertyValueAsType(const std::string &name) const
Get the value of a property as the given TYPE.
This class stores information regarding an experimental run as a series of log entries.
Definition Run.h:36
void saveNexus(Nexus::File *file, const std::string &group, bool keepOpen=false) const override
Save the run to a NeXus file with a given group name.
Definition Run.cpp:647
void loadNexus(Nexus::File *file, const std::string &group, const std::string &prefix, bool keepOpen=false) override
Load the run from a NeXus file with a given group name.
Definition Run.cpp:699
This class stores information about the sample used in particular run.
Definition Sample.h:35
int loadNexus(Nexus::File *file, const std::string &group)
Load the object from an open NeXus file.
Definition Sample.cpp:382
void saveNexus(Nexus::File *file, const std::string &group) const
Save the object to an open NeXus file.
Definition Sample.cpp:330
const Geometry::OrientedLattice & getOrientedLattice() const
Get a reference to the sample's OrientedLattice.
Definition Sample.cpp:198
API::SpectrumInfo is an intermediate step towards a SpectrumInfo that is part of Instrument-2....
const Kernel::cow_ptr< std::vector< SpectrumDefinition > > & sharedSpectrumDefinitions() const
ComponentInfo : Provides a component centric view on to the instrument.
bool hasParent(const size_t componentIndex) const
void setRotation(size_t componentIndex, const Kernel::Quat &newRotation)
void addFittingParameter(const size_t componentIndex, const std::string &name, const std::string &fittingFunction, const std::string &value, const std::string *const pDescription=nullptr, const std::string &pVisible="true")
Add a fitting parameter.
size_t parent(const size_t componentIndex) const
Kernel::Quat rotation(const size_t componentIndex) const
Kernel::V3D position(const size_t componentIndex) const
bool hasParameter(const size_t componentIndex, const std::string &name, bool recursive=true) const
Returns empty (or false) if the ComponentInfo was built without parameters or the parameter is unset.
void addString(const size_t componentIndex, const std::string &name, const std::string &value, const std::string *const pDescription=nullptr, const std::string &pVisible="true")
Add or replace a named string parameter at a specific component index.
bool isDetector(const size_t componentIndex) const
std::string getParameterAsString(size_t const componentIndex, std::string const &name, bool const recursive=true) const
The value of the named parameter as a string, whatever its type, or an empty string if it is unset.
void addInt(const size_t componentIndex, const std::string &name, int value, const std::string *const pDescription=nullptr, const std::string &pVisible="true")
Add or replace a named integer parameter at a specific component index.
Kernel::V3D relativePosition(const size_t componentIndex) const
const std::string & name(const size_t componentIndex) const
void setPosition(size_t componentIndex, const Kernel::V3D &newPosition)
void addDouble(const size_t componentIndex, const std::string &name, double value, const std::string *const pDescription=nullptr, const std::string &pVisible="true")
Add or replace a named double parameter at a specific component index.
static constexpr size_t invalidIndex
Returned by indexOfOrInvalid() for a component ID that is not part of this instrument.
void addBool(const size_t componentIndex, const std::string &name, bool value, const std::string *const pDescription=nullptr, const std::string &pVisible="true")
Add or replace a named boolean parameter at a specific component index.
Geometry::DetectorInfo is an intermediate step towards a DetectorInfo that is part of Instrument-2....
void setMasked(const size_t index, bool masked)
Set the mask flag of the detector with given index. Not thread safe.
size_t indexOf(const detid_t id) const
Returns the index of the detector with the given detector ID.
size_t size() const
Returns the size of the DetectorInfo, i.e., the number of detectors in the instrument.
Creates an instrument data from a XML instrument description file.
std::shared_ptr< Instrument > parseXML(Kernel::ProgressBase *progressReporter)
Parse XML contents.
std::string getMangledName()
Handle used in the singleton constructor for instrument file should append the value file sha-1 check...
InstrumentMetadata : metadata related to the entire instrument.
std::pair< std::unique_ptr< ComponentInfo >, std::unique_ptr< DetectorInfo > > makeWrappers() const
Make the wrappers from the data collected by walkInstrument(), which must be called first.
Base Instrument Class.
Definition Instrument.h:50
std::size_t getNumberDetectors(bool skipMonitors=false) const
Class to implement UB matrix.
static std::shared_ptr< Instrument > createInstrument(const std::shared_ptr< const Instrument > &base, const std::shared_ptr< ParameterMap > &map)
Create a parameterized instrument from the given base and ParameterMap.
static std::shared_ptr< Parameter > create(const std::string &className, const std::string &name, const std::string &visible="true")
Creates an instance of a parameter.
Definition Parameter.cpp:86
Parameter map iterator typedef.
const std::vector< std::string > & getParameterFilenames() const
Returns a list of all the parameter files loaded.
std::shared_ptr< Parameter > getRecursive(const IComponent *comp, const std::string &name, const std::string &type="") const
Use get() recursively to see if can find param in all parents of comp and given type (std::string ver...
static const std::string & rot()
std::vector< Entry > entries() const
Every stored parameter with its component's index in the instrument this map belongs to,...
static const std::string & pos()
Return string to be used in the map.
Collects the position and rotation an instrument definition specifies piecemeal, so that each can be ...
void setCoordinate(const size_t componentIndex, const std::string &axis, const double value, const Kernel::V3D &currentPosition)
Set one coordinate.
void setPosition(const size_t componentIndex, const Kernel::V3D &position)
Set the whole position at once, discarding any coordinates accumulated so far.
std::map< size_t, Kernel::V3D > positions() const
The accumulated position for each component that had any coordinate set.
bool setRotationAngle(const size_t componentIndex, const std::string &axis, const double degrees)
Set one rotation angle, in degrees.
std::map< size_t, Kernel::Quat > rotations() const
The composed rotation for each component that had any angle set.
double alpha() const
Get lattice parameter.
Definition UnitCell.cpp:133
double a(int nd) const
Get lattice parameter a1-a3 as function of index (0-2)
Definition UnitCell.cpp:94
double c() const
Get lattice parameter.
Definition UnitCell.cpp:128
double beta() const
Get lattice parameter.
Definition UnitCell.cpp:138
double b() const
Get lattice parameter.
Definition UnitCell.cpp:123
double gamma() const
Get lattice parameter.
Definition UnitCell.cpp:143
This class is used to store information about parameters in XML instrument definition files and instr...
const std::string m_value
rather then extracting value from logfile,
const std::string m_type
type of the data, e.g. int, double or string
const std::string m_description
if present, contains help string, describing the parameter
const std::string m_visible
if present, describes whether the parameter shall be visible in InstrumentViewer
std::shared_ptr< Kernel::Interpolation > m_interpolation
evaluating the formula
const std::string m_fittingFunction
specific to fitting parameter
std::string m_penaltyFactor
parameter specify lower and upper bound in that order
const std::string m_formula
specify fitting function
const std::string m_resultUnit
expected result (output) unit from
const std::vector< std::string > m_constraint
specific to fitting
const std::string m_tie
specific to fitting parameter specify any tie
const std::string m_formulaUnit
formula to use for setting this parameter
Exception for when an item is not found in a collection.
Definition Exception.h:145
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
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
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
The concrete, templated class for properties.
Base class for properties.
Definition Property.h:95
virtual std::string value() const =0
Returns the value of the property as a string.
Class for quaternions.
Definition Quat.h:38
void rotate(V3D &) const
Rotate a vector.
Definition Quat.cpp:397
Iterator begin()
Iterator referring to first element in the container.
@ TOK_IGNORE_EMPTY
ignore empty tokens
@ TOK_TRIM
remove leading and trailing whitespace from tokens
Iterator end()
Iterator referring to the past-the-end element in the container.
std::size_t count() const
Get the total number of tokens.
TimeROI : Object that holds information about when the time measurement was active.
Definition TimeROI.h:18
Class for 3D vectors.
Definition V3D.h:35
void spherical(const double R, const double theta, const double phi) noexcept
Sets the vector position based on spherical coordinates.
Definition V3D.cpp:56
Implements a copy on write data template.
Definition cow_ptr.h:41
Class that provides for a standard Nexus exception.
MANTID_API_DLL void applyRectangularDetectorScaleToComponentInfo(Geometry::ComponentInfo &componentInfo, const size_t componentIndex, const double scaleX, const double scaleY)
Helpers for resizing RectangularDetectors.
std::shared_ptr< const ExperimentInfo > ExperimentInfo_const_sptr
Shared pointer to const ExperimentInfo.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< ExperimentInfo > ExperimentInfo_sptr
Shared pointer to ExperimentInfo.
std::shared_ptr< Parameter > Parameter_sptr
Typedef for the shared pointer.
Definition Parameter.h:203
std::shared_ptr< const Mantid::Geometry::IDetector > IDetector_const_sptr
Shared pointer to IDetector (const version)
Definition IDetector.h:96
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.
MANTID_KERNEL_DLL std::string strip(const std::string &A)
strip pre/post spaces
Definition Strings.cpp:420
MANTID_KERNEL_DLL std::string loadFile(const std::string &filename)
Loads the entire contents of a text file into a string.
Definition Strings.cpp:27
int convert(const std::string &A, T &out)
Convert a string into a number.
Definition Strings.cpp:697
int32_t detid_t
Typedef for a detector ID.
Generate a tableworkspace to store the calibration results.
std::string to_string(const wide_integer< Bits, Signed > &n)
static Type fromString(const std::string &modeStr)
Returns the emode from the given string.
Type
Define the available energy transfer modes It is important to assign enums proper numbers,...
Definition DeltaEMode.h:29