Mantid
Loading...
Searching...
No Matches
ParameterMap.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 +
16#include "MantidKernel/Cache.h"
17#include "MantidKernel/Logger.h"
19#include "MantidNexus/NexusFile.h"
20#include <boost/algorithm/string.hpp>
21#include <cstring>
22#include <numeric>
23
24#ifdef _WIN32
25#define strcasecmp _stricmp
26#else
27#include "strings.h"
28#endif
29
30namespace Mantid::Geometry {
31using Kernel::Quat;
32using Kernel::V3D;
33
34namespace {
35// names of common parameter types
36const std::string POS_PARAM_NAME = "pos";
37const std::string POSX_PARAM_NAME = "x";
38const std::string POSY_PARAM_NAME = "y";
39const std::string POSZ_PARAM_NAME = "z";
40
41const std::string ROT_PARAM_NAME = "rot";
42const std::string ROTX_PARAM_NAME = "rotx";
43const std::string ROTY_PARAM_NAME = "roty";
44const std::string ROTZ_PARAM_NAME = "rotz";
45
46const std::string DOUBLE_PARAM_NAME = "double";
47const std::string INT_PARAM_NAME = "int";
48const std::string BOOL_PARAM_NAME = "bool";
49const std::string STRING_PARAM_NAME = "string";
50const std::string V3D_PARAM_NAME = "V3D";
51const std::string QUAT_PARAM_NAME = "Quat";
52
53const std::string SCALE_PARAM_NAME = "sca";
54
55// static logger reference
56Kernel::Logger g_log("ParameterMap");
57
58void checkIsNotMaskingParameter(const std::string &name) {
59 if (name == std::string("masked"))
60 throw std::runtime_error("Masking data (\"masked\") cannot be stored in "
61 "ParameterMap. Use DetectorInfo instead");
62}
63} // namespace
68 : m_parameterInfo(std::make_shared<ParameterInfo>()),
69 m_cacheLocMap(std::make_unique<Kernel::Cache<const ComponentID, Kernel::V3D>>()),
70 m_cacheRotMap(std::make_unique<Kernel::Cache<const ComponentID, Kernel::Quat>>()) {}
71
73 // The store is deep-copied, not shared: a copied ParameterMap is an independent map, and
74 // sharing would make a write through either one visible to the other.
75 : m_parameterFileNames(other.m_parameterFileNames),
76 m_parameterInfo(std::make_shared<ParameterInfo>(*other.m_parameterInfo)), m_idToIndex(other.m_idToIndex),
77 m_indexToId(other.m_indexToId),
78 m_cacheLocMap(std::make_unique<Kernel::Cache<const ComponentID, Kernel::V3D>>(*other.m_cacheLocMap)),
79 m_cacheRotMap(std::make_unique<Kernel::Cache<const ComponentID, Kernel::Quat>>(*other.m_cacheRotMap)),
80 m_instrument(other.m_instrument) {
81 // Deliberately does NOT rebuild the beamline. That is now ExperimentInfo's job, via rebuildBeamlineFrom()
82}
83
85 if (!m_instrument) {
86 return;
87 }
88 auto [newComponentInfo, newDetectorInfo] = m_instrument->makeBeamline(*this, &source);
89 m_componentInfo = std::move(newComponentInfo);
90 m_detectorInfo = std::move(newDetectorInfo);
91 // Deliberately does NOT adopt m_componentInfo's store here, unlike setInstrument().
92 // This map was copy-constructed and therefore already holds its own deep copy of the parameters
94}
95
96// Defined as default in source for forward declaration with std::unique_ptr.
98
99//--------------------------------------------------------------------------------------------
100// Component pointer <-> component index translation
101//--------------------------------------------------------------------------------------------
102
103size_t ParameterMap::indexOf(const IComponent *comp) const {
104 size_t result = ComponentInfo::invalidIndex;
105 if (comp) {
106 auto const found = m_idToIndex.find(comp->getComponentID());
107 if (found != m_idToIndex.end()) {
108 result = found->second;
109 }
110 }
111 return result;
112}
113
115 size_t result = ComponentInfo::invalidIndex;
116 if (comp) {
117 const ComponentID id = comp->getComponentID();
118 auto const found = m_idToIndex.find(id);
119 if (found != m_idToIndex.end()) {
120 result = found->second;
121 } else {
122 // First time this component has been written to
123 result = m_indexToId.size();
124 m_indexToId.emplace_back(id);
125 m_idToIndex.emplace(id, result);
126 }
127 }
128 return result;
129}
130
132 return index < m_indexToId.size() ? m_indexToId[index] : nullptr;
133}
134
135std::vector<ParameterMap::Entry> ParameterMap::entries() const {
136 std::vector<Entry> result;
137 result.reserve(m_parameterInfo->size());
138 for (auto const &[index, parameters] : *m_parameterInfo) {
139 const ComponentID id = componentIdAt(index);
140 for (auto const &[parameterName, parameter] : parameters) {
141 static_cast<void>(parameterName);
142 result.emplace_back(id, parameter);
143 }
144 }
145 return result;
146}
147
148//--------------------------------------------------------------------------------------------
149
150std::shared_ptr<ParameterInfo> ParameterMap::rekey(const std::unordered_map<IComponent const *, size_t> &idToIndex) {
151 auto rekeyed = std::make_shared<ParameterInfo>();
152 for (auto const &[stagingIndex, parameters] : *m_parameterInfo) {
153 const ComponentID id = componentIdAt(stagingIndex);
154 auto const found = idToIndex.find(id);
155 if (found == idToIndex.end()) {
156 continue;
157 }
158 for (auto const &[parameterName, parameter] : parameters) {
159 static_cast<void>(parameterName);
160 // insert() rather than add(): this map's contents have already had the legacy
161 // deduplication applied
162 rekeyed->insert(found->second, parameter);
163 }
164 }
165
166 // Adopt the rekeyed store and the instrument's index domain, so that this map and the
167 // ComponentInfo built alongside it share one set of parameters from here on.
168 m_parameterInfo = rekeyed;
169 m_idToIndex = idToIndex;
170 m_indexToId.assign(idToIndex.size(), nullptr);
171 for (auto const &[id, index] : idToIndex) {
172 m_indexToId[index] = const_cast<ComponentID>(id);
173 }
174 return m_parameterInfo;
175}
176
180// Position
181const std::string &ParameterMap::pos() { return POS_PARAM_NAME; }
182
183const std::string &ParameterMap::posx() { return POSX_PARAM_NAME; }
184
185const std::string &ParameterMap::posy() { return POSY_PARAM_NAME; }
186
187const std::string &ParameterMap::posz() { return POSZ_PARAM_NAME; }
188
189// Rotation
190const std::string &ParameterMap::rot() { return ROT_PARAM_NAME; }
191
192const std::string &ParameterMap::rotx() { return ROTX_PARAM_NAME; }
193
194const std::string &ParameterMap::roty() { return ROTY_PARAM_NAME; }
195
196const std::string &ParameterMap::rotz() { return ROTZ_PARAM_NAME; }
197
198// Other types
199const std::string &ParameterMap::pDouble() { return DOUBLE_PARAM_NAME; }
200
201const std::string &ParameterMap::pInt() { return INT_PARAM_NAME; }
202
203const std::string &ParameterMap::pBool() { return BOOL_PARAM_NAME; }
204
205const std::string &ParameterMap::pString() { return STRING_PARAM_NAME; }
206
207const std::string &ParameterMap::pV3D() { return V3D_PARAM_NAME; }
208
209const std::string &ParameterMap::pQuat() { return QUAT_PARAM_NAME; }
210
211// Scale
212const std::string &ParameterMap::scale() { return SCALE_PARAM_NAME; }
213
220bool ParameterMap::operator!=(const ParameterMap &rhs) const { return !(this->operator==(rhs)); }
221
228bool ParameterMap::operator==(const ParameterMap &rhs) const { return diff(rhs, true, false, 0.).empty(); }
229
237const std::string ParameterMap::getDescription(const std::string &compName, const std::string &name) const {
238 std::string result;
239 for (auto const &entry : entries()) {
240 if (compName == entry.first->getName()) {
241 std::shared_ptr<Parameter> const param = get(entry.first, name);
242 if (param) {
243 result = param->getDescription();
244 if (!result.empty())
245 return result;
246 }
247 }
248 }
249 return result;
250}
258const std::string ParameterMap::getShortDescription(const std::string &compName, const std::string &name) const {
259 std::string result;
260 for (auto const &entry : entries()) {
261 if (compName == entry.first->getName()) {
262 std::shared_ptr<Parameter> const param = get(entry.first, name);
263 if (param) {
264 result = param->getShortDescription();
265 if (!result.empty())
266 return result;
267 }
268 }
269 }
270 return result;
271}
272
273//------------------------------------------------------------------------------------------------
287bool ParameterMap::relErr(double x1, double x2, double errorVal) const {
288 double num = std::fabs(x1 - x2);
289 // how to treat x1<0 and x2 > 0 ? probably this way
290 double den = 0.5 * (std::fabs(x1) + std::fabs(x2));
291 if (den < errorVal)
292 return (num > errorVal);
293
294 return (num / den > errorVal);
295}
296
311const std::string ParameterMap::diff(const ParameterMap &rhs, const bool &firstDiffOnly, const bool relative,
312 const double doubleTolerance) const {
313 if (this == &rhs)
314 return std::string(""); // True for the same object
315
316 // Quick size check
317 if (this->size() != rhs.size()) {
318 return std::string("Number of parameters does not match: ") + std::to_string(this->size()) + " not equal to " +
319 std::to_string(rhs.size());
320 }
321
322 // The map is unordered and the key is only valid at runtime. The
323 // asString method turns the ComponentIDs to full-qualified name identifiers
324 // so we will use the same approach to compare them
325
326 std::unordered_multimap<std::string, Parameter_sptr> thisMap, rhsMap;
327 for (auto const &entry : entries()) {
328 thisMap.emplace(entry.first->getFullName(), entry.second);
329 }
330 for (auto const &entry : rhs.entries()) {
331 rhsMap.emplace(entry.first->getFullName(), entry.second);
332 }
333
334 std::stringstream strOutput;
335 for (auto thisIt = thisMap.cbegin(); thisIt != thisMap.cend(); ++thisIt) {
336 const std::string fullName = thisIt->first;
337 const auto &param = thisIt->second;
338 bool match(false);
339 for (auto rhsIt = rhsMap.cbegin(); rhsIt != rhsMap.cend(); ++rhsIt) {
340 const std::string rhsFullName = rhsIt->first;
341 const auto &rhsParam = rhsIt->second;
342 if ((fullName == rhsFullName) && (param->name() == (rhsParam->name()))) {
343 if ((param->type() == rhsParam->type()) && (rhsParam->type() == "double")) {
344 if (relative) {
345 if (!relErr(param->value<double>(), rhsParam->value<double>(), doubleTolerance))
346 match = true;
347 } else if (std::abs(param->value<double>() - rhsParam->value<double>()) <= doubleTolerance)
348 match = true;
349 } else if (param->asString() == rhsParam->asString()) {
350 match = true;
351 }
352 if (match)
353 break;
354 }
355 }
356
357 if (!match) {
358 // output some information that helps with understanding the mismatch
359 strOutput << "Parameter mismatch LHS=RHS for LHS parameter in component "
360 "with name: "
361 << fullName << ". Parameter name is: " << (*param).name() << " and value: " << (*param).asString()
362 << '\n';
363 bool componentWithSameNameRHS = false;
364 bool parameterWithSameNameRHS = false;
365 for (auto rhsIt = rhsMap.cbegin(); rhsIt != rhsMap.cend(); ++rhsIt) {
366 const std::string rhsFullName = rhsIt->first;
367 if (fullName == rhsFullName) {
368 componentWithSameNameRHS = true;
369 if ((*param).name() == (*rhsIt->second).name()) {
370 parameterWithSameNameRHS = true;
371 strOutput << "RHS param with same name has value: " << (*rhsIt->second).asString() << '\n';
372 }
373 }
374 }
375 if (!componentWithSameNameRHS) {
376 strOutput << "No matching RHS component name\n";
377 }
378 if (componentWithSameNameRHS && !parameterWithSameNameRHS) {
379 strOutput << "Found matching RHS component name but not parameter name\n";
380 }
381 if (firstDiffOnly)
382 return strOutput.str();
383 }
384 }
385 return strOutput.str();
386}
387
393 checkIsNotMaskingParameter(name);
394 // The erase is guarded at whole operation granularity rather than per element.
395 PARALLEL_CRITICAL(unsafe_erase) { m_parameterInfo->clearParametersByName(name); }
396 // Check if the caches need invalidating
397 if (name == pos() || name == rot())
399}
400
406void ParameterMap::clearParametersByName(const std::string &name, const IComponent *comp) {
407 checkIsNotMaskingParameter(name);
408 const size_t index = indexOf(comp);
410 PARALLEL_CRITICAL(unsafe_erase) { m_parameterInfo->clearParametersByName(index, name); }
411
412 // Check if the caches need invalidating
413 if (name == pos() || name == rot())
415 }
416}
417
428void ParameterMap::add(const std::string &type, const IComponent *comp, const std::string &name,
429 const std::string &value, const std::string *const pDescription, const std::string &pVisible) {
430 auto param = ParameterFactory::create(type, name, pVisible);
431 param->fromString(value);
432 this->add(comp, param, pDescription);
433}
434
442void ParameterMap::add(const IComponent *comp, const std::shared_ptr<Parameter> &par,
443 const std::string *const pDescription) {
444 // indexForWrite() allocates an index for a component this map has not seen before; everything
445 // else is the index-addressed overload's job.
446 add(indexForWrite(comp), par, pDescription);
447}
448
449void ParameterMap::add(const size_t componentIndex, const std::shared_ptr<Parameter> &par,
450 const std::string *const pDescription) {
452 return;
453 checkIsNotMaskingParameter(par->name());
454 if (pDescription)
455 par->setDescription(*pDescription);
456
457 // As this is only an add method it should really throw if it already exists. However, this
458 // is old behavior and many things rely on this actually being an add/replace-style function
459 // -- ParameterInfo::add() implements exactly that, including the case-insensitive name match.
461}
462
463void ParameterMap::add(const std::string &type, const size_t componentIndex, const std::string &name,
464 const std::string &value, const std::string *const pDescription, const std::string &pVisible) {
465 auto param = ParameterFactory::create(type, name, pVisible);
466 param->fromString(value);
467 add(componentIndex, param, pDescription);
468}
469
484void ParameterMap::addFittingParameter(const IComponent *comp, const std::string &name,
485 const std::string &fittingFunction, const std::string &value,
486 const std::string *const pDescription, const std::string &pVisible) {
487 addFittingParameter(indexForWrite(comp), name, fittingFunction, value, pDescription, pVisible);
488}
489
490void ParameterMap::addFittingParameter(const size_t componentIndex, const std::string &name,
491 const std::string &fittingFunction, const std::string &value,
492 const std::string *const pDescription, const std::string &pVisible) {
493 checkIsNotMaskingParameter(name);
495 return;
496 auto param = ParameterFactory::create("fitting", name, pVisible);
497 param->fromString(value);
498 if (pDescription)
499 param->setDescription(*pDescription);
500
501 // Look for an existing fitting parameter on this component with the same name AND the same
502 // embedded function; only that one should be replaced.
503 // ParameterInfo applies that rule and reports which of the two happened.
504 const bool replaced = m_parameterInfo->addFittingParameter(componentIndex, param, fittingFunction);
505 g_log.debug() << "addFittingParameter: [" << (replaced ? "replace" : "insert") << "] (name='" << name
506 << "', function='" << fittingFunction << "') on component index " << componentIndex << '\n';
507}
508
518void ParameterMap::addPositionCoordinate(const IComponent *comp, const std::string &name, const double value,
519 const std::string *const pDescription) {
520 Parameter_sptr param = get(comp, pos());
522 if (param) {
523 // so "pos" already defined
524 position = param->value<V3D>();
525 } else {
526 // so "pos" is not defined - therefore get position from component
527 position = comp->getPos();
528 }
529
530 // adjust position
531
532 if (name == posx())
534 else if (name == posy())
535 position.setY(value);
536 else if (name == posz())
537 position.setZ(value);
538 else {
539 g_log.warning() << "addPositionCoordinate() called with unrecognized "
540 "coordinate symbol: "
541 << name;
542 // set description if one is provided
543 if (pDescription) {
544 param->setDescription(*pDescription);
545 }
546 return;
547 }
548
549 // clear the position cache
551 // finally add or update "pos" parameter
552 addV3D(comp, pos(), position, pDescription);
553}
554
564void ParameterMap::addRotationParam(const IComponent *comp, const std::string &name, const double deg,
565 const std::string *const pDescription) {
566 Parameter_sptr paramRotX = get(comp, rotx());
567 Parameter_sptr paramRotY = get(comp, roty());
568 Parameter_sptr paramRotZ = get(comp, rotz());
569 double rotX, rotY, rotZ;
570
571 if (paramRotX)
572 rotX = paramRotX->value<double>();
573 else
574 rotX = 0.0;
575
576 if (paramRotY)
577 rotY = paramRotY->value<double>();
578 else
579 rotY = 0.0;
580
581 if (paramRotZ)
582 rotZ = paramRotZ->value<double>();
583 else
584 rotZ = 0.0;
585
586 // adjust rotation
587 Quat quat;
588 if (name == rotx()) {
589 addDouble(comp, rotx(), deg);
590 quat = Quat(deg, V3D(1, 0, 0)) * Quat(rotY, V3D(0, 1, 0)) * Quat(rotZ, V3D(0, 0, 1));
591 } else if (name == roty()) {
592 addDouble(comp, roty(), deg);
593 quat = Quat(rotX, V3D(1, 0, 0)) * Quat(deg, V3D(0, 1, 0)) * Quat(rotZ, V3D(0, 0, 1));
594 } else if (name == rotz()) {
595 addDouble(comp, rotz(), deg);
596 quat = Quat(rotX, V3D(1, 0, 0)) * Quat(rotY, V3D(0, 1, 0)) * Quat(deg, V3D(0, 0, 1));
597 } else {
598 g_log.warning() << "addRotationParam() called with unrecognized coordinate symbol: " << name;
599 return;
600 }
601
602 // clear the position cache
604
605 // finally add or update "pos" parameter
606 addQuat(comp, rot(), quat, pDescription);
607}
608
618void ParameterMap::addDouble(const IComponent *comp, const std::string &name, const std::string &value,
619 const std::string *const pDescription, const std::string &pVisible) {
620 add(pDouble(), comp, name, value, pDescription, pVisible);
621}
622
632void ParameterMap::addDouble(const IComponent *comp, const std::string &name, double value,
633 const std::string *const pDescription, const std::string &pVisible) {
634 add(pDouble(), comp, name, value, pDescription, pVisible);
635}
636
646void ParameterMap::addInt(const IComponent *comp, const std::string &name, const std::string &value,
647 const std::string *const pDescription, const std::string &pVisible) {
648 add(pInt(), comp, name, value, pDescription, pVisible);
649}
650
660void ParameterMap::addInt(const IComponent *comp, const std::string &name, int value,
661 const std::string *const pDescription, const std::string &pVisible) {
662 add(pInt(), comp, name, value, pDescription, pVisible);
663}
664
674void ParameterMap::addBool(const IComponent *comp, const std::string &name, const std::string &value,
675 const std::string *const pDescription, const std::string &pVisible) {
676 add(pBool(), comp, name, value, pDescription, pVisible);
677}
687void ParameterMap::addBool(const IComponent *comp, const std::string &name, bool value,
688 const std::string *const pDescription, const std::string &pVisible) {
689 add(pBool(), comp, name, value, pDescription, pVisible);
690}
691
700 const std::string name("masked");
701 auto param = create(pBool(), name);
702 auto typedParam = std::dynamic_pointer_cast<ParameterType<bool>>(param);
703 typedParam->setValue(value);
704
705 // insert() rather than add(): "masked" is rejected by checkIsNotMaskingParameter() on every
706 // normal path, so this bypasses the add/replace lookup exactly as the raw insert did before.
707 m_parameterInfo->insert(indexForWrite(comp), param);
708}
709
719void ParameterMap::addString(const IComponent *comp, const std::string &name, const std::string &value,
720 const std::string *const pDescription, const std::string &pVisible) {
721 add<std::string>(pString(), comp, name, value, pDescription, pVisible);
722}
723
732void ParameterMap::addV3D(const IComponent *comp, const std::string &name, const std::string &value,
733 const std::string *const pDescription) {
734 add(pV3D(), comp, name, value, pDescription);
736}
737
746void ParameterMap::addV3D(const IComponent *comp, const std::string &name, const V3D &value,
747 const std::string *const pDescription) {
748 add(pV3D(), comp, name, value, pDescription);
750}
751
760void ParameterMap::addQuat(const IComponent *comp, const std::string &name, const Quat &value,
761 const std::string *const pDescription) {
762 add(pQuat(), comp, name, value, pDescription);
764}
765
773bool ParameterMap::contains(const IComponent *comp, const std::string &name, const std::string &type) const {
774 return contains(comp, name.c_str(), type.c_str());
775}
776
785bool ParameterMap::contains(const IComponent *comp, const char *name, const char *type) const {
786 checkIsNotMaskingParameter(name);
787 const size_t index = indexOf(comp);
788 return index != ComponentInfo::invalidIndex && m_parameterInfo->contains(index, name, type);
789}
790
796bool ParameterMap::contains(const IComponent *comp, const Parameter &parameter) const {
797 checkIsNotMaskingParameter(parameter.name());
798 const size_t index = indexOf(comp);
800 return false;
801
802 // Compares whole Parameter objects (name, type and value), not just the name, so every
803 // parameter on the component has to be examined rather than looked up by name.
804 for (auto const &[storedName, param] : m_parameterInfo->parameters(index)) {
805 static_cast<void>(storedName);
806 if (param && *param == parameter)
807 return true;
808 }
809 return false;
810}
811
818Parameter_sptr ParameterMap::get(const IComponent *comp, const std::string &name, const std::string &type) const {
819 return get(comp, name.c_str(), type.c_str());
820}
821
829std::shared_ptr<Parameter> ParameterMap::get(const IComponent *comp, const char *name, const char *type) const {
830 checkIsNotMaskingParameter(name);
831 const size_t index = indexOf(comp);
833}
834
840Parameter_sptr ParameterMap::getByType(const IComponent *comp, const std::string &type) const {
841 const size_t index = indexOf(comp);
842 return index == ComponentInfo::invalidIndex ? Parameter_sptr() : m_parameterInfo->getByType(index, type);
843}
844
851Parameter_sptr ParameterMap::getRecursiveByType(const IComponent *comp, const std::string &type) const {
852 std::shared_ptr<const IComponent> compInFocus(comp, NoDeleting());
853 while (compInFocus != nullptr) {
854 Parameter_sptr param = getByType(compInFocus.get(), type);
855 if (param) {
856 return param;
857 }
858 compInFocus = compInFocus->getParent();
859 }
860 // Nothing was found!
861 return Parameter_sptr();
862}
863
873 const std::string &type) const {
874 return getRecursive(comp, name.c_str(), type.c_str());
875}
876
885Parameter_sptr ParameterMap::getRecursive(const IComponent *comp, const char *name, const char *type) const {
886 checkIsNotMaskingParameter(name);
887 Parameter_sptr result = this->get(comp->getComponentID(), name, type);
888 if (result)
889 return result;
890
891 auto parent = comp->getParent();
892 while (parent) {
893 result = this->get(parent->getComponentID(), name, type);
894 if (result)
895 return result;
896 parent = parent->getParent();
897 }
898 return result;
899}
900
915 const std::string &fittingFunction) const {
916 checkIsNotMaskingParameter(name);
917 if (!comp || m_parameterInfo->empty())
918 return Parameter_sptr();
919
920 // Walk up the component tree using a raw pointer. Wrapping the externally-owned
921 // component in a shared_ptr (even with NoDeleting) makes Coverity flag it as being
922 // managed by two smart pointers; the parent shared_ptr keeps each level alive.
923 const IComponent *current = comp;
924 std::shared_ptr<const IComponent> parent;
925 while (current != nullptr) {
926 const size_t index = indexOf(current);
928 for (auto const &[storedName, param] : m_parameterInfo->parameters(index)) {
929 static_cast<void>(storedName);
930 if (param->type() == "fitting" && strcasecmp(param->nameAsCString(), name.c_str()) == 0) {
931 try {
932 if (param->value<FitParameter>().getFunction() == fittingFunction) {
933 return param;
934 }
935 } catch (...) {
936 // Not a FitParameter value despite the type tag, keep looking.
937 }
938 }
939 }
940 }
941 parent = current->getParent();
942 current = parent.get();
943 }
944 return Parameter_sptr();
945}
946
955std::string ParameterMap::getString(const IComponent *comp, const std::string &name, bool recursive) const {
956 Parameter_sptr param;
957 if (recursive) {
958 param = getRecursive(comp, name);
959 } else {
960 param = get(comp, name);
961 }
962 if (!param)
963 return "";
964 return param->asString();
965}
966
972std::set<std::string> ParameterMap::names(const IComponent *comp) const {
973 const size_t index = indexOf(comp);
974 return index == ComponentInfo::invalidIndex ? std::set<std::string>() : m_parameterInfo->names(index);
975}
976
983std::string ParameterMap::asString() const {
984 std::stringstream out;
985 for (auto const &entry : entries()) {
986 const std::shared_ptr<Parameter> &p = entry.second;
987 if (p && entry.first) {
988 const auto *comp = dynamic_cast<const IComponent *>(entry.first);
989 const auto *det = dynamic_cast<const IDetector *>(comp);
990 if (det) {
991 out << "detID:" << det->getID();
992 } else if (comp) {
993 out << comp->getFullName(); // Use full path name to ensure unambiguous
994 // naming
995 }
996 const auto paramVisible = "visible:" + std::string(p->visible() == 1 ? "true" : "false");
997 out << ';' << p->type() << ';' << p->name() << ';' << p->asString() << ';' << paramVisible << '|';
998 }
999 }
1000 return out.str();
1001}
1002
1010
1014void ParameterMap::setCachedLocation(const IComponent *comp, const V3D &location) const {
1015 m_cacheLocMap->setCache(comp->getComponentID(), location);
1016}
1017
1022bool ParameterMap::getCachedLocation(const IComponent *comp, V3D &location) const {
1023 return m_cacheLocMap->getCache(comp->getComponentID(), location);
1024}
1025
1030 m_cacheRotMap->setCache(comp->getComponentID(), rotation);
1031}
1032
1038 return m_cacheRotMap->getCache(comp->getComponentID(), rotation);
1039}
1040
1049 const ParameterMap *oldPMap) {
1050
1051 auto const oldParameterNames = oldPMap->names(oldComp);
1052 const size_t newIndex = indexForWrite(newComp);
1053 for (const auto &oldParameterName : oldParameterNames) {
1054 // insert() rather than add(), matching the raw insert this replaced: names() has already
1055 // deduplicated, so no add/replace lookup is wanted here.
1056 m_parameterInfo->insert(newIndex, oldPMap->get(oldComp, oldParameterName));
1057 }
1058}
1059
1060//--------------------------------------------------------------------------------------------
1065void ParameterMap::saveNexus(Nexus::File *file, const std::string &group) const {
1066 file->makeGroup(group, "NXnote", true);
1067 file->putAttr("version", 1);
1068 file->writeData("author", "");
1069 file->writeData("date", Types::Core::DateAndTime::getCurrentTime().toISO8601String());
1070 file->writeData("description", "A string representation of the parameter "
1071 "map. The format is either: "
1072 "|detID:id-value;param-type;param-name;param-"
1073 "value| for a detector or "
1074 "|comp-name;param-type;param-name;param-value|"
1075 " for other components.");
1076 file->writeData("type", "text/plain");
1077 std::string s = this->asString();
1078 file->writeData("data", s);
1079 file->closeGroup();
1080}
1081
1085const std::vector<std::string> &ParameterMap::getParameterFilenames() const { return m_parameterFileNames; }
1087
1090void ParameterMap::addParameterFilename(const std::string &filename) { m_parameterFileNames.emplace_back(filename); }
1091
1093std::shared_ptr<Parameter> ParameterMap::create(const std::string &className, const std::string &name,
1094 const std::string &visible) const {
1095 return ParameterFactory::create(className, name, visible);
1096}
1097
1104bool ParameterMap::hasDetectorInfo(const Instrument *instrument) const {
1105 if (instrument != m_instrument)
1106 return false;
1107 return static_cast<bool>(m_detectorInfo);
1108}
1109
1113bool ParameterMap::hasComponentInfo(const Instrument *instrument) const {
1114 if (instrument != m_instrument)
1115 return false;
1116 return static_cast<bool>(m_componentInfo);
1117}
1118
1122 throw std::runtime_error("Cannot return reference to NULL DetectorInfo");
1123 return *m_detectorInfo;
1124}
1125
1129 throw std::runtime_error("Cannot return reference to NULL DetectorInfo");
1130 return *m_detectorInfo;
1131}
1132
1136 throw std::runtime_error("Cannot return reference to NULL ComponentInfo");
1137 }
1138 return *m_componentInfo;
1139}
1140
1144 throw std::runtime_error("Cannot return reference to NULL ComponentInfo");
1145 }
1146 return *m_componentInfo;
1147}
1148
1151 if (!m_instrumentMetadata) {
1152 throw std::runtime_error("Cannot return reference to NULL InstrumentMetadata");
1153 }
1154 return *m_instrumentMetadata;
1155}
1156
1158size_t ParameterMap::detectorIndex(const detid_t detID) const { return m_instrument->detectorIndex(detID); }
1159
1160size_t ParameterMap::componentIndex(const ComponentID componentId) const {
1161 return m_componentInfo->indexOf(componentId);
1162}
1163
1166 if (instrument == m_instrument)
1167 return;
1168 if (!instrument) {
1169 m_componentInfo = nullptr;
1170 m_detectorInfo = nullptr;
1171 m_instrumentMetadata = nullptr;
1172 return;
1173 }
1174 if (m_instrument)
1175 throw std::logic_error("ParameterMap::setInstrument: Cannot change "
1176 "instrument once it has been set.");
1177 if (instrument->isParametrized())
1178 throw std::logic_error("ParameterMap::setInstrument must be called with "
1179 "base instrument, not a parametrized instrument");
1180 m_instrument = instrument;
1181 // Assigned one at a time rather than through std::tie: the members are shared_ptr while
1182 // makeBeamline returns unique_ptr, and the conversion is clearer spelled out.
1183 auto [newComponentInfo, newDetectorInfo] =
1185 m_componentInfo = std::move(newComponentInfo);
1186 m_detectorInfo = std::move(newDetectorInfo);
1187 // The visitor called rekey() while building the beamline, so this map and the new
1188 // ComponentInfo now share one store. Re-point at it to be certain of that even on the
1189 // makeBeamlineNew() path, where there were no parameters to rekey.
1190 if (m_componentInfo) {
1191 m_parameterInfo = m_componentInfo->sharedParameterInfo();
1192 }
1194}
1195
1198 // Mirrors Instrument::getPhysicalInstrument()'s parametrized branch: a physical
1199 // instrument must share the same ParameterMap as the owning (neutronic) instrument.
1200 Instrument_const_sptr physicalInstrument;
1201 if (const auto &basePhysicalInstrument = m_instrument->getPhysicalInstrument()) {
1202 physicalInstrument =
1203 std::make_shared<Instrument>(basePhysicalInstrument, std::shared_ptr<ParameterMap>(this, NoDeleting()));
1204 }
1205 m_instrumentMetadata = std::make_shared<InstrumentMetadata>(
1208 std::move(physicalInstrument));
1209}
1210
1215 // The parameters themselves, including the Parameter objects on the heap. Note that the
1216 // store may be shared with the owning ComponentInfo, which reports it too, so summing this
1217 // with ComponentInfo::getMemorySize() double-counts it.
1218 const size_t mapMem = m_parameterInfo->getMemorySize();
1219 // The pointer/index translation tables, which exist only here.
1220 const size_t translationMem = m_idToIndex.size() * (sizeof(std::pair<const ComponentID, size_t>) + sizeof(void *)) +
1221 m_indexToId.capacity() * sizeof(ComponentID);
1222 // m_parameterFileNames: vector of strings; sizeof(*this) covers the vector object, count the heap buffer
1223 const size_t fileNamesMem = m_parameterFileNames.size() * sizeof(std::string) +
1224 std::accumulate(m_parameterFileNames.cbegin(), m_parameterFileNames.cend(), size_t{0},
1225 [](size_t acc, const auto &s) { return acc + s.capacity(); });
1226 // m_cacheLocMap and m_cacheRotMap: count the heap Cache objects; the internal std::map entries are not
1227 // counted because Kernel::Cache::size() is non-const and cannot be called here.
1228 const size_t cacheLocMem = m_cacheLocMap ? sizeof(*m_cacheLocMap) : 0;
1229 const size_t cacheRotMem = m_cacheRotMap ? sizeof(*m_cacheRotMap) : 0;
1230 // m_detectorInfo and m_componentInfo: owned by ParameterMap for parametrized instruments
1231 const size_t detectorInfoMem = m_detectorInfo ? m_detectorInfo->getMemorySize() : 0;
1232 const size_t componentInfoMem = m_componentInfo ? m_componentInfo->getMemorySize() : 0;
1233 // m_instrument is a non-owning raw pointer to the base Instrument; its memory is counted in
1234 // Instrument::getMemorySize() and excluded here to avoid double-counting.
1235 return sizeof(*this) + mapMem + translationMem + fileNamesMem + cacheLocMem + cacheRotMem + detectorInfoMem +
1236 componentInfoMem;
1237}
1238
1239} // namespace Mantid::Geometry
std::string name
Definition Run.cpp:60
const std::vector< double > & rhs
double value
The value of the point.
Definition FitMW.cpp:51
double position
Definition GetAllEi.cpp:154
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_CRITICAL(name)
Mantid::Kernel::Quat(ComponentInfo::* rotation)(const size_t) const
ComponentInfo : Provides a component centric view on to the instrument.
static constexpr size_t invalidIndex
Returned by indexOfOrInvalid() for a component ID that is not part of this instrument.
bool isParametrized() const override
Return true if the Component is, in fact, parametrized (that is - it has a valid parameter map)
Definition Component.cpp:75
Geometry::DetectorInfo is an intermediate step towards a DetectorInfo that is part of Instrument-2....
Store information about a fitting parameter such as its value if it is constrained or tied.
const std::string & getFunction() const
get function
base class for Geometric IComponent
Definition IComponent.h:53
virtual Kernel::V3D getPos() const =0
Get the position of the IComponent. Tree structure is traverse through the.
virtual std::shared_ptr< const IComponent > getParent() const =0
Return a pointer to the current parent.
virtual ComponentID getComponentID() const =0
Returns the ComponentID - a unique identifier of the component.
Interface class for detector objects.
Definition IDetector.h:43
virtual detid_t getID() const =0
Get the detector ID.
InstrumentMetadata : metadata related to the entire instrument.
Base Instrument Class.
Definition Instrument.h:49
std::shared_ptr< const Instrument > getPhysicalInstrument() const
INDIRECT GEOMETRY INSTRUMENTS ONLY: Returns the physical instrument, if one has been specified as dis...
std::pair< std::unique_ptr< ComponentInfo >, std::unique_ptr< DetectorInfo > > makeBeamlineNew(ParameterMap &pmap) const
Return ComponentInfo and DetectorInfo for instrument given by pmap.
std::pair< std::unique_ptr< ComponentInfo >, std::unique_ptr< DetectorInfo > > makeBeamline(ParameterMap &pmap, const ParameterMap *source=nullptr) const
Return ComponentInfo and DetectorInfo for instrument given by pmap.
size_t detectorIndex(const detid_t detID) const
Returns the index for a detector ID. Used for accessing DetectorInfo.
const std::string & getFilename() const
const std::string & getDefaultView() const
Get the default type of the instrument view.
Definition Instrument.h:148
const std::string & getDefaultAxis() const
Retrieves from which side the instrument to be viewed from when the instrument viewer first starts,...
Definition Instrument.h:155
const std::string & getXmlText() const
Types::Core::DateAndTime getValidFromDate() const
Definition Instrument.h:170
Types::Core::DateAndTime getValidToDate() const
Definition Instrument.h:173
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:83
ParameterInfo : the named parameters of an instrument, addressed by component index.
Parameter map iterator typedef.
bool getCachedRotation(const IComponent *comp, Kernel::Quat &rotation) const
Attempts to retrieve a rotation from the rotation cache.
const Geometry::DetectorInfo & detectorInfo() const
Only for use by ExperimentInfo. Returns a reference to the DetectorInfo.
const std::vector< std::string > & getParameterFilenames() const
Returns a list of all the parameter files loaded.
static const std::string & pQuat()
bool getCachedLocation(const IComponent *comp, Kernel::V3D &location) const
Attempts to retrieve a location from the location cache.
void clearPositionSensitiveCaches()
Clears the location, rotation & bounding box caches.
bool contains(const IComponent *comp, const std::string &name, const std::string &type="") const
Does the named parameter exist for the given component and type (std::string version)
void copyFromParameterMap(const IComponent *oldComp, const IComponent *newComp, const ParameterMap *oldPMap)
Copy pairs (oldComp->id,Parameter) to the m_map assigning the new newComp->id.
void rebuildBeamlineFrom(const ParameterMap &source)
Rebuild the 2.0 layers for a map that was copy-constructed from source.
void addInt(const IComponent *comp, const std::string &name, const std::string &value, const std::string *const pDescription=nullptr, const std::string &pVisible="true")
Adds an int value to the parameter map.
void addPositionCoordinate(const IComponent *comp, const std::string &name, const double value, const std::string *const pDescription=nullptr)
Create or adjust "pos" parameter for a component.
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...
std::shared_ptr< ParameterInfo > rekey(const std::unordered_map< Geometry::IComponent const *, size_t > &idToIndex)
Rekey this map's parameters from the synthetic staging indices onto an instrument's real component in...
std::vector< ComponentID > m_indexToId
Reverse of m_idToIndex.
void addParameterFilename(const std::string &filename)
adds a parameter filename that has been loaded
std::shared_ptr< ParameterInfo > m_parameterInfo
The parameter store, owner of the parameter info.
void buildInstrumentMetadata()
Builds m_instrumentMetadata from m_instrument. Requires m_instrument to be set.
static const std::string & scale()
std::shared_ptr< Parameter > getRecursiveByType(const IComponent *comp, const std::string &type) const
Looks recursively upwards in the component tree for the first instance of a parameter with a specifie...
std::unordered_map< Geometry::IComponent const *, size_t > m_idToIndex
Component pointer to index translation.
std::shared_ptr< Geometry::InstrumentMetadata > m_instrumentMetadata
static const std::string & rot()
void setCachedLocation(const IComponent *comp, const Kernel::V3D &location) const
Sets a cached location on the location cache.
const Instrument * m_instrument
Pointer to the owning instrument for translating detector IDs into detector indices when accessing th...
std::string getString(const IComponent *comp, const std::string &name, bool recursive=false) const
Return the value of a parameter as a string.
static const std::string & pBool()
Geometry::InstrumentMetadata const & instrumentMetadata() const
Only for use by ExperimentInfo. Returns a reference to the InstrumentMetadata.
void saveNexus(Nexus::File *file, const std::string &group) const
Persist a representation of the Parameter map to the open Nexus file.
void setCachedRotation(const IComponent *comp, const Kernel::Quat &rotation) const
Sets a cached rotation on the rotation cache.
void clearParametersByName(const std::string &name)
Clear any parameters with the given name.
const std::string getDescription(const std::string &compName, const std::string &name) const
Get the component description by name.
std::shared_ptr< Parameter > getByType(const IComponent *comp, const std::string &type) const
Finds the parameter in the map via the parameter type.
void setInstrument(const Instrument *instrument)
Only for use by Instrument. Sets the pointer to the owning instrument.
Geometry::ComponentInfo & mutableComponentInfo()
Only for use by ExperimentInfo. Returns a reference to the ComponentInfo.
bool operator==(const ParameterMap &rhs) const
Equality comparison operator.
std::shared_ptr< Parameter > create(const std::string &className, const std::string &name, const std::string &visible="true") const
Wrapper for ParameterFactory::create to avoid include in header.
void addString(const IComponent *comp, const std::string &name, const std::string &value, const std::string *const pDescription=nullptr, const std::string &pVisible="true")
Adds a std::string value to the parameter map.
std::set< std::string > names(const IComponent *comp) const
Returns a set with all parameter names for component.
size_t indexOf(const IComponent *comp) const
Index for a component, or ComponentInfo::invalidIndex if this map holds nothing for it.
std::vector< Entry > entries() const
Every stored parameter with its owning component, in component-index order.
int size() const
Return the size of the map.
std::vector< std::string > m_parameterFileNames
internal list of parameter files loaded
static const std::string & pV3D()
std::unique_ptr< Kernel::Cache< const ComponentID, Kernel::V3D > > m_cacheLocMap
internal cache map instance for cached position values
size_t getMemorySize() const
Get the footprint in memory in bytes.
size_t indexForWrite(const IComponent *comp)
As indexOf(), but allocating a new index for a component seen for the first time.
void addDouble(const IComponent *comp, const std::string &name, const std::string &value, const std::string *const pDescription=nullptr, const std::string &pVisible="true")
Adds a double value to the parameter map.
static const std::string & posz()
std::unique_ptr< Kernel::Cache< const ComponentID, Kernel::Quat > > m_cacheRotMap
internal cache map instance for cached rotation values
bool relErr(double x1, double x2, double errorVal) const
calculate relative error for use in diff
const std::string diff(const ParameterMap &rhs, const bool &firstDiffOnly=false, const bool relative=false, const double doubleTolerance=Kernel::Tolerance) const
Output information that helps understanding the mismatch between two parameter maps.
static const std::string & pDouble()
static const std::string & pos()
Return string to be used in the map.
void addRotationParam(const IComponent *comp, const std::string &name, const double deg, const std::string *const pDescription=nullptr)
Create or adjust "rot" parameter for a component.
ParameterMap()
Default constructor.
std::string asString() const
Returns a string with all component names, parameter names and values.
void addFittingParameter(const IComponent *comp, 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.
void addQuat(const IComponent *comp, const std::string &name, const Kernel::Quat &value, const std::string *const pDescription=nullptr)
Adds a Kernel::Quat value to the parameter map.
size_t componentIndex(const Geometry::ComponentID componentId) const
void add(const std::string &type, const IComponent *comp, const std::string &name, const std::string &value, const std::string *const pDescription=nullptr, const std::string &visible="true")
Method for adding a parameter providing its value as a string.
std::shared_ptr< Parameter > getRecursiveFittingParameter(const IComponent *comp, const std::string &name, const std::string &fittingFunction) const
Look for a fitting parameter recursively, picking the one whose embedded FitParameter function name m...
static const std::string & rotz()
ComponentID componentIdAt(const size_t index) const
The component an index refers to. Only valid for an index this map issued.
const std::string getShortDescription(const std::string &compName, const std::string &name) const
Get the component tooltip by name.
size_t detectorIndex(const detid_t detID) const
Only for use by Detector. Returns a detector index for a detector ID.
static const std::string & posy()
static const std::string & posx()
std::shared_ptr< Geometry::DetectorInfo > m_detectorInfo
The 2.0 instrument layers, co-owned with the ExperimentInfo that built them.
static const std::string & pString()
void addV3D(const IComponent *comp, const std::string &name, const std::string &value, const std::string *const pDescription=nullptr)
Adds a Kernel::V3D value to the parameter map.
static const std::string & pInt()
std::shared_ptr< Geometry::ComponentInfo > m_componentInfo
void addBool(const IComponent *comp, const std::string &name, const std::string &value, const std::string *const pDescription=nullptr, const std::string &pVisible="true")
Adds a bool value to the parameter map.
bool operator!=(const ParameterMap &rhs) const
Inquality comparison operator.
bool hasComponentInfo(const Instrument *instrument) const
Only for use by ExperimentInfo.
static const std::string & rotx()
bool hasDetectorInfo(const Instrument *instrument) const
Only for use by ExperimentInfo.
std::shared_ptr< Parameter > get(const IComponent *comp, const std::string &name, const std::string &type="") const
Get a parameter with a given name and type (std::string version)
void forceUnsafeSetMasked(const IComponent *comp, bool value)
Force adding masking information.
static const std::string & roty()
const Geometry::ComponentInfo & componentInfo() const
Only for use by ExperimentInfo. Returns a reference to the ComponentInfo.
Geometry::DetectorInfo & mutableDetectorInfo()
Only for use by ExperimentInfo. Returns a reference to the DetectorInfo.
Base class for parameters of an instrument.
Definition Parameter.h:38
const std::string & name() const
Parameter name.
Definition Parameter.h:46
Cache is a generic caching storage class.
Definition Cache.h:27
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
Class for quaternions.
Definition Quat.h:39
Class for 3D vectors.
Definition V3D.h:34
void setX(const double xx) noexcept
Set is x position.
Definition V3D.h:224
This functor is used as the deleter object of a shared_ptr to effectively erase ownership Raw pointer...
Definition IComponent.h:171
std::shared_ptr< Parameter > Parameter_sptr
Typedef for the shared pointer.
Definition Parameter.h:198
Mantid::Kernel::Logger g_log("Goniometer")
IComponent * ComponentID
Define a type for a unique component identifier.
Definition IComponent.h:35
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
int32_t detid_t
Typedef for a detector ID.
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)