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/Logger.h"
18#include "MantidNexus/NexusFile.h"
19#include <boost/algorithm/string.hpp>
20#include <cstring>
21#include <numeric>
22
23#ifdef _WIN32
24#define strcasecmp _stricmp
25#else
26#include "strings.h"
27#endif
28
29namespace Mantid::Geometry {
30using Kernel::Quat;
31using Kernel::V3D;
32
33namespace {
34// names of common parameter types
35const std::string POS_PARAM_NAME = "pos";
36const std::string POSX_PARAM_NAME = "x";
37const std::string POSY_PARAM_NAME = "y";
38const std::string POSZ_PARAM_NAME = "z";
39
40const std::string ROT_PARAM_NAME = "rot";
41const std::string ROTX_PARAM_NAME = "rotx";
42const std::string ROTY_PARAM_NAME = "roty";
43const std::string ROTZ_PARAM_NAME = "rotz";
44
45const std::string DOUBLE_PARAM_NAME = "double";
46const std::string INT_PARAM_NAME = "int";
47const std::string BOOL_PARAM_NAME = "bool";
48const std::string STRING_PARAM_NAME = "string";
49const std::string V3D_PARAM_NAME = "V3D";
50const std::string QUAT_PARAM_NAME = "Quat";
51
52const std::string SCALE_PARAM_NAME = "sca";
53
54// static logger reference
55Kernel::Logger g_log("ParameterMap");
56
57void checkIsNotMaskingParameter(const std::string &name) {
58 if (name == std::string("masked"))
59 throw std::runtime_error("Masking data (\"masked\") cannot be stored in "
60 "ParameterMap. Use DetectorInfo instead");
61}
62} // namespace
66ParameterMap::ParameterMap() : m_parameterInfo(std::make_shared<ParameterInfo>()) {}
67
69 // The store is deep-copied, not shared: a copied ParameterMap is an independent map, and
70 // sharing would make a write through either one visible to the other.
71 : m_parameterFileNames(other.m_parameterFileNames),
72 m_parameterInfo(std::make_shared<ParameterInfo>(*other.m_parameterInfo)), m_domainIds(other.m_domainIds),
73 m_domainIndices(other.m_domainIndices), m_stagedIndices(other.m_stagedIndices), m_stagedIds(other.m_stagedIds),
74 m_instrument(other.m_instrument) {
75 // Deliberately does NOT rebuild the beamline. That is now ExperimentInfo's job, via rebuildBeamlineFrom()
76}
77
79 if (!m_instrument) {
80 return;
81 }
82 auto [newComponentInfo, newDetectorInfo] = m_instrument->makeBeamline(*this, &source);
83 m_componentInfo = std::move(newComponentInfo);
84 m_detectorInfo = std::move(newDetectorInfo);
85 // Deliberately does NOT adopt m_componentInfo's store here, unlike setInstrument().
86 // This map was copy-constructed and therefore already holds its own deep copy of the parameters
87 // The metadata is read-only and refers to nothing in the source map, so it can be shared rather
88 // than rebuilt, which would walk the physical instrument again on every workspace copy.
89 if (source.m_instrumentMetadata) {
91 } else {
93 }
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 // An attached map is keyed by component index, a detached one by staging index
107 const auto &indices = m_domainIndices ? *m_domainIndices : m_stagedIndices;
108 auto const found = indices.find(comp->getComponentID());
109 if (found != indices.end()) {
110 result = found->second;
111 }
112 }
113 return result;
114}
115
117 size_t result = indexOf(comp);
118 if (comp && result == ComponentInfo::invalidIndex) {
119 if (m_domainIndices) {
120 throw std::invalid_argument("ParameterMap: cannot add a parameter to component '" + comp->getFullName() +
121 "', which is not part of the instrument this map belongs to");
122 }
123 // First time this component has been written to
124 const ComponentID id = comp->getComponentID();
125 result = m_stagedIds.size();
126 m_stagedIds.emplace_back(id);
127 m_stagedIndices.emplace(id, result);
128 }
129 return result;
130}
131
132std::string ParameterMap::componentName(const size_t index) const { return componentInfo().name(index); }
133
134std::string ParameterMap::componentFullName(const size_t index) const { return componentInfo().fullName(index); }
135
136std::vector<ParameterMap::Entry> ParameterMap::entries() const {
137 if (!m_domainIds) {
138 throw std::logic_error("ParameterMap::entries: the map is not attached to an instrument, so its components "
139 "have no component indices");
140 }
141 std::vector<Entry> result;
142 result.reserve(m_parameterInfo->size());
143 for (auto const &[index, parameters] : *m_parameterInfo) {
144 for (auto const &[parameterName, parameter] : parameters) {
145 static_cast<void>(parameterName);
146 result.emplace_back(index, parameter);
147 }
148 }
149 return result;
150}
151
152//--------------------------------------------------------------------------------------------
153
154std::shared_ptr<ParameterInfo> ParameterMap::rekey(std::shared_ptr<const ComponentIDs> componentIds,
155 std::shared_ptr<const ComponentIndices> componentIndices) {
156 if (componentIds == m_domainIds) {
157 return m_parameterInfo;
158 }
159 // The components the current indices refer to
160 const auto &oldIds = m_domainIds ? *m_domainIds : m_stagedIds;
161 auto rekeyed = std::make_shared<ParameterInfo>();
162 for (auto const &[oldIndex, parameters] : *m_parameterInfo) {
163 auto const found = componentIndices->find(oldIds[oldIndex]);
164 if (found == componentIndices->end()) {
165 continue;
166 }
167 for (auto const &[parameterName, parameter] : parameters) {
168 static_cast<void>(parameterName);
169 // insert() rather than add(): this map's contents have already had the legacy
170 // deduplication applied
171 rekeyed->insert(found->second, parameter);
172 }
173 }
174 for (auto const &[key, parameter] : m_parameterInfo->logfileParameters()) {
175 auto const found = componentIndices->find(oldIds[key.first]);
176 if (found != componentIndices->end()) {
177 rekeyed->addLogfileParameter(found->second, key.second, parameter);
178 }
179 }
180
181 // Adopt the rekeyed store and the instrument's index domain, so that this map and the
182 // ComponentInfo built alongside it share one set of parameters from here on.
183 m_parameterInfo = rekeyed;
184 m_domainIds = std::move(componentIds);
185 m_domainIndices = std::move(componentIndices);
186 m_stagedIndices.clear();
187 m_stagedIds.clear();
188 return m_parameterInfo;
189}
190
194// Position
195const std::string &ParameterMap::pos() { return POS_PARAM_NAME; }
196
197const std::string &ParameterMap::posx() { return POSX_PARAM_NAME; }
198
199const std::string &ParameterMap::posy() { return POSY_PARAM_NAME; }
200
201const std::string &ParameterMap::posz() { return POSZ_PARAM_NAME; }
202
203// Rotation
204const std::string &ParameterMap::rot() { return ROT_PARAM_NAME; }
205
206const std::string &ParameterMap::rotx() { return ROTX_PARAM_NAME; }
207
208const std::string &ParameterMap::roty() { return ROTY_PARAM_NAME; }
209
210const std::string &ParameterMap::rotz() { return ROTZ_PARAM_NAME; }
211
212// Other types
213const std::string &ParameterMap::pDouble() { return DOUBLE_PARAM_NAME; }
214
215const std::string &ParameterMap::pInt() { return INT_PARAM_NAME; }
216
217const std::string &ParameterMap::pBool() { return BOOL_PARAM_NAME; }
218
219const std::string &ParameterMap::pString() { return STRING_PARAM_NAME; }
220
221const std::string &ParameterMap::pV3D() { return V3D_PARAM_NAME; }
222
223const std::string &ParameterMap::pQuat() { return QUAT_PARAM_NAME; }
224
225// Scale
226const std::string &ParameterMap::scale() { return SCALE_PARAM_NAME; }
227
234bool ParameterMap::operator!=(const ParameterMap &rhs) const { return !(this->operator==(rhs)); }
235
242bool ParameterMap::operator==(const ParameterMap &rhs) const { return diff(rhs, true, false, 0.).empty(); }
243
251const std::string ParameterMap::getDescription(const std::string &compName, const std::string &name) const {
252 std::string result;
253 for (auto const &[index, parameters] : *m_parameterInfo) {
254 static_cast<void>(parameters);
255 if (compName == componentName(index)) {
256 std::shared_ptr<Parameter> const param = m_parameterInfo->get(index, name);
257 if (param) {
258 result = param->getDescription();
259 if (!result.empty())
260 return result;
261 }
262 }
263 }
264 return result;
265}
273const std::string ParameterMap::getShortDescription(const std::string &compName, const std::string &name) const {
274 std::string result;
275 for (auto const &[index, parameters] : *m_parameterInfo) {
276 static_cast<void>(parameters);
277 if (compName == componentName(index)) {
278 std::shared_ptr<Parameter> const param = m_parameterInfo->get(index, name);
279 if (param) {
280 result = param->getShortDescription();
281 if (!result.empty())
282 return result;
283 }
284 }
285 }
286 return result;
287}
288
289//------------------------------------------------------------------------------------------------
303bool ParameterMap::relErr(double x1, double x2, double errorVal) const {
304 double num = std::fabs(x1 - x2);
305 // how to treat x1<0 and x2 > 0 ? probably this way
306 double den = 0.5 * (std::fabs(x1) + std::fabs(x2));
307 if (den < errorVal)
308 return (num > errorVal);
309
310 return (num / den > errorVal);
311}
312
327const std::string ParameterMap::diff(const ParameterMap &rhs, const bool &firstDiffOnly, const bool relative,
328 const double doubleTolerance) const {
329 if (this == &rhs)
330 return std::string(""); // True for the same object
331
332 // Quick size check
333 if (this->size() != rhs.size()) {
334 return std::string("Number of parameters does not match: ") + std::to_string(this->size()) + " not equal to " +
335 std::to_string(rhs.size());
336 }
337
338 // The map is unordered and the key is only valid at runtime. The
339 // asString method turns the components to full-qualified name identifiers
340 // so we will use the same approach to compare them
341
342 std::unordered_multimap<std::string, Parameter_sptr> thisMap, rhsMap;
343 auto const byFullName = [](ParameterMap const &map, std::unordered_multimap<std::string, Parameter_sptr> &result) {
344 for (auto const &[index, parameters] : *map.m_parameterInfo) {
345 auto const fullName = map.componentFullName(index);
346 for (auto const &[parameterName, parameter] : parameters) {
347 static_cast<void>(parameterName);
348 result.emplace(fullName, parameter);
349 }
350 }
351 };
352 byFullName(*this, thisMap);
353 byFullName(rhs, rhsMap);
354
355 std::stringstream strOutput;
356 for (auto thisIt = thisMap.cbegin(); thisIt != thisMap.cend(); ++thisIt) {
357 const std::string fullName = thisIt->first;
358 const auto &param = thisIt->second;
359 bool match(false);
360 for (auto rhsIt = rhsMap.cbegin(); rhsIt != rhsMap.cend(); ++rhsIt) {
361 const std::string rhsFullName = rhsIt->first;
362 const auto &rhsParam = rhsIt->second;
363 if ((fullName == rhsFullName) && (param->name() == (rhsParam->name()))) {
364 if ((param->type() == rhsParam->type()) && (rhsParam->type() == "double")) {
365 if (relative) {
366 if (!relErr(param->value<double>(), rhsParam->value<double>(), doubleTolerance))
367 match = true;
368 } else if (std::abs(param->value<double>() - rhsParam->value<double>()) <= doubleTolerance)
369 match = true;
370 } else if (param->asString() == rhsParam->asString()) {
371 match = true;
372 }
373 if (match)
374 break;
375 }
376 }
377
378 if (!match) {
379 // output some information that helps with understanding the mismatch
380 strOutput << "Parameter mismatch LHS=RHS for LHS parameter in component "
381 "with name: "
382 << fullName << ". Parameter name is: " << (*param).name() << " and value: " << (*param).asString()
383 << '\n';
384 bool componentWithSameNameRHS = false;
385 bool parameterWithSameNameRHS = false;
386 for (auto rhsIt = rhsMap.cbegin(); rhsIt != rhsMap.cend(); ++rhsIt) {
387 const std::string rhsFullName = rhsIt->first;
388 if (fullName == rhsFullName) {
389 componentWithSameNameRHS = true;
390 if ((*param).name() == (*rhsIt->second).name()) {
391 parameterWithSameNameRHS = true;
392 strOutput << "RHS param with same name has value: " << (*rhsIt->second).asString() << '\n';
393 }
394 }
395 }
396 if (!componentWithSameNameRHS) {
397 strOutput << "No matching RHS component name\n";
398 }
399 if (componentWithSameNameRHS && !parameterWithSameNameRHS) {
400 strOutput << "Found matching RHS component name but not parameter name\n";
401 }
402 if (firstDiffOnly)
403 return strOutput.str();
404 }
405 }
406 return strOutput.str();
407}
408
414 checkIsNotMaskingParameter(name);
415 // The erase is guarded at whole operation granularity rather than per element.
416 PARALLEL_CRITICAL(unsafe_erase) { m_parameterInfo->clearParametersByName(name); }
417}
418
424void ParameterMap::clearParametersByName(const std::string &name, const IComponent *comp) {
425 checkIsNotMaskingParameter(name);
426 const size_t index = indexOf(comp);
428 PARALLEL_CRITICAL(unsafe_erase) { m_parameterInfo->clearParametersByName(index, name); }
429 }
430}
431
442void ParameterMap::add(const std::string &type, const IComponent *comp, const std::string &name,
443 const std::string &value, const std::string *const pDescription, const std::string &pVisible) {
444 auto param = ParameterFactory::create(type, name, pVisible);
445 param->fromString(value);
446 this->add(comp, param, pDescription);
447}
448
456void ParameterMap::add(const IComponent *comp, const std::shared_ptr<Parameter> &par,
457 const std::string *const pDescription) {
458 // indexForWrite() allocates an index for a component this map has not seen before; everything
459 // else is the index-addressed overload's job.
460 add(indexForWrite(comp), par, pDescription);
461}
462
463void ParameterMap::add(const size_t componentIndex, const std::shared_ptr<Parameter> &par,
464 const std::string *const pDescription) {
466 return;
467 checkIsNotMaskingParameter(par->name());
468 if (pDescription)
469 par->setDescription(*pDescription);
470
471 // As this is only an add method it should really throw if it already exists. However, this
472 // is old behavior and many things rely on this actually being an add/replace-style function
473 // -- ParameterInfo::add() implements exactly that, including the case-insensitive name match.
475}
476
477void ParameterMap::add(const std::string &type, const size_t componentIndex, const std::string &name,
478 const std::string &value, const std::string *const pDescription, const std::string &pVisible) {
479 auto param = ParameterFactory::create(type, name, pVisible);
480 param->fromString(value);
481 add(componentIndex, param, pDescription);
482}
483
498void ParameterMap::addFittingParameter(const IComponent *comp, const std::string &name,
499 const std::string &fittingFunction, const std::string &value,
500 const std::string *const pDescription, const std::string &pVisible) {
501 addFittingParameter(indexForWrite(comp), name, fittingFunction, value, pDescription, pVisible);
502}
503
504void ParameterMap::addFittingParameter(const size_t componentIndex, const std::string &name,
505 const std::string &fittingFunction, const std::string &value,
506 const std::string *const pDescription, const std::string &pVisible) {
507 checkIsNotMaskingParameter(name);
509 return;
510 auto param = ParameterFactory::create("fitting", name, pVisible);
511 param->fromString(value);
512 if (pDescription)
513 param->setDescription(*pDescription);
514
515 // Look for an existing fitting parameter on this component with the same name AND the same
516 // embedded function; only that one should be replaced.
517 // ParameterInfo applies that rule and reports which of the two happened.
518 const bool replaced = m_parameterInfo->addFittingParameter(componentIndex, param, fittingFunction);
519 g_log.debug() << "addFittingParameter: [" << (replaced ? "replace" : "insert") << "] (name='" << name
520 << "', function='" << fittingFunction << "') on component index " << componentIndex << '\n';
521}
522
532void ParameterMap::addPositionCoordinate(const IComponent *comp, const std::string &name, const double value,
533 const std::string *const pDescription) {
534 Parameter_sptr param = get(comp, pos());
536 if (param) {
537 // so "pos" already defined
538 position = param->value<V3D>();
539 } else {
540 // so "pos" is not defined - therefore get position from component
541 position = comp->getPos();
542 }
543
544 // adjust position
545
546 if (name == posx())
548 else if (name == posy())
549 position.setY(value);
550 else if (name == posz())
551 position.setZ(value);
552 else {
553 g_log.warning() << "addPositionCoordinate() called with unrecognized "
554 "coordinate symbol: "
555 << name;
556 // set description if one is provided
557 if (pDescription) {
558 param->setDescription(*pDescription);
559 }
560 return;
561 }
562
563 // finally add or update "pos" parameter
564 addV3D(comp, pos(), position, pDescription);
565}
566
576void ParameterMap::addRotationParam(const IComponent *comp, const std::string &name, const double deg,
577 const std::string *const pDescription) {
578 Parameter_sptr paramRotX = get(comp, rotx());
579 Parameter_sptr paramRotY = get(comp, roty());
580 Parameter_sptr paramRotZ = get(comp, rotz());
581 double rotX, rotY, rotZ;
582
583 if (paramRotX)
584 rotX = paramRotX->value<double>();
585 else
586 rotX = 0.0;
587
588 if (paramRotY)
589 rotY = paramRotY->value<double>();
590 else
591 rotY = 0.0;
592
593 if (paramRotZ)
594 rotZ = paramRotZ->value<double>();
595 else
596 rotZ = 0.0;
597
598 // adjust rotation
599 Quat quat;
600 if (name == rotx()) {
601 addDouble(comp, rotx(), deg);
602 quat = Quat(deg, V3D(1, 0, 0)) * Quat(rotY, V3D(0, 1, 0)) * Quat(rotZ, V3D(0, 0, 1));
603 } else if (name == roty()) {
604 addDouble(comp, roty(), deg);
605 quat = Quat(rotX, V3D(1, 0, 0)) * Quat(deg, V3D(0, 1, 0)) * Quat(rotZ, V3D(0, 0, 1));
606 } else if (name == rotz()) {
607 addDouble(comp, rotz(), deg);
608 quat = Quat(rotX, V3D(1, 0, 0)) * Quat(rotY, V3D(0, 1, 0)) * Quat(deg, V3D(0, 0, 1));
609 } else {
610 g_log.warning() << "addRotationParam() called with unrecognized coordinate symbol: " << name;
611 return;
612 }
613
614 // finally add or update "pos" parameter
615 addQuat(comp, rot(), quat, pDescription);
616}
617
627void ParameterMap::addDouble(const IComponent *comp, const std::string &name, const std::string &value,
628 const std::string *const pDescription, const std::string &pVisible) {
629 add(pDouble(), comp, name, value, pDescription, pVisible);
630}
631
641void ParameterMap::addDouble(const IComponent *comp, const std::string &name, double value,
642 const std::string *const pDescription, const std::string &pVisible) {
643 add(pDouble(), comp, name, value, pDescription, pVisible);
644}
645
655void ParameterMap::addInt(const IComponent *comp, const std::string &name, const std::string &value,
656 const std::string *const pDescription, const std::string &pVisible) {
657 add(pInt(), comp, name, value, pDescription, pVisible);
658}
659
669void ParameterMap::addInt(const IComponent *comp, const std::string &name, int value,
670 const std::string *const pDescription, const std::string &pVisible) {
671 add(pInt(), comp, name, value, pDescription, pVisible);
672}
673
683void ParameterMap::addBool(const IComponent *comp, const std::string &name, const std::string &value,
684 const std::string *const pDescription, const std::string &pVisible) {
685 add(pBool(), comp, name, value, pDescription, pVisible);
686}
696void ParameterMap::addBool(const IComponent *comp, const std::string &name, bool value,
697 const std::string *const pDescription, const std::string &pVisible) {
698 add(pBool(), comp, name, value, pDescription, pVisible);
699}
700
709 const std::string name("masked");
710 auto param = create(pBool(), name);
711 auto typedParam = std::dynamic_pointer_cast<ParameterType<bool>>(param);
712 typedParam->setValue(value);
713
714 // insert() rather than add(): "masked" is rejected by checkIsNotMaskingParameter() on every
715 // normal path, so this bypasses the add/replace lookup exactly as the raw insert did before.
716 m_parameterInfo->insert(indexForWrite(comp), param);
717}
718
728void ParameterMap::addString(const IComponent *comp, const std::string &name, const std::string &value,
729 const std::string *const pDescription, const std::string &pVisible) {
730 add<std::string>(pString(), comp, name, value, pDescription, pVisible);
731}
732
741void ParameterMap::addV3D(const IComponent *comp, const std::string &name, const std::string &value,
742 const std::string *const pDescription) {
743 add(pV3D(), comp, name, value, pDescription);
744}
745
754void ParameterMap::addV3D(const IComponent *comp, const std::string &name, const V3D &value,
755 const std::string *const pDescription) {
756 add(pV3D(), comp, name, value, pDescription);
757}
758
767void ParameterMap::addQuat(const IComponent *comp, const std::string &name, const Quat &value,
768 const std::string *const pDescription) {
769 add(pQuat(), comp, name, value, pDescription);
770}
771
779bool ParameterMap::contains(const IComponent *comp, const std::string &name, const std::string &type) const {
780 return contains(comp, name.c_str(), type.c_str());
781}
782
791bool ParameterMap::contains(const IComponent *comp, const char *name, const char *type) const {
792 checkIsNotMaskingParameter(name);
793 const size_t index = indexOf(comp);
794 return index != ComponentInfo::invalidIndex && m_parameterInfo->contains(index, name, type);
795}
796
802bool ParameterMap::contains(const IComponent *comp, const Parameter &parameter) const {
803 checkIsNotMaskingParameter(parameter.name());
804 const size_t index = indexOf(comp);
806 return false;
807
808 // Compares whole Parameter objects (name, type and value), not just the name, so every
809 // parameter on the component has to be examined rather than looked up by name.
810 for (auto const &[storedName, param] : m_parameterInfo->parameters(index)) {
811 static_cast<void>(storedName);
812 if (param && *param == parameter)
813 return true;
814 }
815 return false;
816}
817
824Parameter_sptr ParameterMap::get(const IComponent *comp, const std::string &name, const std::string &type) const {
825 return get(comp, name.c_str(), type.c_str());
826}
827
835std::shared_ptr<Parameter> ParameterMap::get(const IComponent *comp, const char *name, const char *type) const {
836 checkIsNotMaskingParameter(name);
837 const size_t index = indexOf(comp);
839}
840
846Parameter_sptr ParameterMap::getByType(const IComponent *comp, const std::string &type) const {
847 const size_t index = indexOf(comp);
848 return index == ComponentInfo::invalidIndex ? Parameter_sptr() : m_parameterInfo->getByType(index, type);
849}
850
857Parameter_sptr ParameterMap::getRecursiveByType(const IComponent *comp, const std::string &type) const {
858 std::shared_ptr<const IComponent> compInFocus(comp, NoDeleting());
859 while (compInFocus != nullptr) {
860 Parameter_sptr param = getByType(compInFocus.get(), type);
861 if (param) {
862 return param;
863 }
864 compInFocus = compInFocus->getParent();
865 }
866 // Nothing was found!
867 return Parameter_sptr();
868}
869
879 const std::string &type) const {
880 return getRecursive(comp, name.c_str(), type.c_str());
881}
882
891Parameter_sptr ParameterMap::getRecursive(const IComponent *comp, const char *name, const char *type) const {
892 checkIsNotMaskingParameter(name);
893 Parameter_sptr result = this->get(comp->getComponentID(), name, type);
894 if (result)
895 return result;
896
897 auto parent = comp->getParent();
898 while (parent) {
899 result = this->get(parent->getComponentID(), name, type);
900 if (result)
901 return result;
902 parent = parent->getParent();
903 }
904 return result;
905}
906
921 const std::string &fittingFunction) const {
922 checkIsNotMaskingParameter(name);
923 if (!comp || m_parameterInfo->empty())
924 return Parameter_sptr();
925
926 // Walk up the component tree using a raw pointer. Wrapping the externally-owned
927 // component in a shared_ptr (even with NoDeleting) makes Coverity flag it as being
928 // managed by two smart pointers; the parent shared_ptr keeps each level alive.
929 const IComponent *current = comp;
930 std::shared_ptr<const IComponent> parent;
931 while (current != nullptr) {
932 const size_t index = indexOf(current);
934 for (auto const &[storedName, param] : m_parameterInfo->parameters(index)) {
935 static_cast<void>(storedName);
936 if (param->type() == "fitting" && strcasecmp(param->nameAsCString(), name.c_str()) == 0) {
937 try {
938 if (param->value<FitParameter>().getFunction() == fittingFunction) {
939 return param;
940 }
941 } catch (...) {
942 // Not a FitParameter value despite the type tag, keep looking.
943 }
944 }
945 }
946 }
947 parent = current->getParent();
948 current = parent.get();
949 }
950 return Parameter_sptr();
951}
952
961std::string ParameterMap::getString(const IComponent *comp, const std::string &name, bool recursive) const {
962 Parameter_sptr param;
963 if (recursive) {
964 param = getRecursive(comp, name);
965 } else {
966 param = get(comp, name);
967 }
968 if (!param)
969 return "";
970 return param->asString();
971}
972
978std::set<std::string> ParameterMap::names(const IComponent *comp) const {
979 const size_t index = indexOf(comp);
980 return index == ComponentInfo::invalidIndex ? std::set<std::string>() : m_parameterInfo->names(index);
981}
982
989std::string ParameterMap::asString() const {
990 if (m_parameterInfo->empty()) {
991 return std::string();
992 }
994}
995
1003std::string ParameterMap::asString(const std::vector<Entry> &entries, const ComponentInfo &componentInfo,
1004 const DetectorInfo &detectorInfo) {
1005 std::stringstream out;
1006 for (auto const &[index, p] : entries) {
1007 if (p) {
1008 // Identify the component: a detector by its ID, anything else by its full path name, which
1009 // is unambiguous
1010 const std::string component = componentInfo.isDetector(index)
1013 out << asStringEntry(component, *p);
1014 }
1015 }
1016 return out.str();
1017}
1018
1025std::string ParameterMap::asStringEntry(const std::string &component, const Parameter &parameter) {
1026 const auto paramVisible = "visible:" + std::string(parameter.visible() == 1 ? "true" : "false");
1027 return component + ';' + parameter.type() + ';' + parameter.name() + ';' + parameter.asString() + ';' + paramVisible +
1028 '|';
1029}
1030
1039 const ParameterMap *oldPMap) {
1040
1041 auto const oldParameterNames = oldPMap->names(oldComp);
1042 const size_t newIndex = indexForWrite(newComp);
1043 for (const auto &oldParameterName : oldParameterNames) {
1044 // insert() rather than add(), matching the raw insert this replaced: names() has already
1045 // deduplicated, so no add/replace lookup is wanted here.
1046 m_parameterInfo->insert(newIndex, oldPMap->get(oldComp, oldParameterName));
1047 }
1048}
1049
1050//--------------------------------------------------------------------------------------------
1056void ParameterMap::saveNexus(Nexus::File *file, const std::string &group, const std::string &contents) {
1057 file->makeGroup(group, "NXnote", true);
1058 file->putAttr("version", 1);
1059 file->writeData("author", "");
1060 file->writeData("date", Types::Core::DateAndTime::getCurrentTime().toISO8601String());
1061 file->writeData("description", "A string representation of the parameter "
1062 "map. The format is either: "
1063 "|detID:id-value;param-type;param-name;param-"
1064 "value| for a detector or "
1065 "|comp-name;param-type;param-name;param-value|"
1066 " for other components.");
1067 file->writeData("type", "text/plain");
1068 file->writeData("data", contents);
1069 file->closeGroup();
1070}
1071
1075const std::vector<std::string> &ParameterMap::getParameterFilenames() const { return m_parameterFileNames; }
1077
1080void ParameterMap::addParameterFilename(const std::string &filename) { m_parameterFileNames.emplace_back(filename); }
1081
1083std::shared_ptr<Parameter> ParameterMap::create(const std::string &className, const std::string &name,
1084 const std::string &visible) const {
1085 return ParameterFactory::create(className, name, visible);
1086}
1087
1094bool ParameterMap::hasDetectorInfo(const Instrument *instrument) const {
1095 if (instrument != m_instrument)
1096 return false;
1097 return static_cast<bool>(m_detectorInfo);
1098}
1099
1103bool ParameterMap::hasComponentInfo(const Instrument *instrument) const {
1104 if (instrument != m_instrument)
1105 return false;
1106 return static_cast<bool>(m_componentInfo);
1107}
1108
1112 throw std::runtime_error("Cannot return reference to NULL DetectorInfo");
1113 return *m_detectorInfo;
1114}
1115
1119 throw std::runtime_error("Cannot return reference to NULL DetectorInfo");
1120 return *m_detectorInfo;
1121}
1122
1126 throw std::runtime_error("Cannot return reference to NULL ComponentInfo");
1127 }
1128 return *m_componentInfo;
1129}
1130
1134 throw std::runtime_error("Cannot return reference to NULL ComponentInfo");
1135 }
1136 return *m_componentInfo;
1137}
1138
1141 if (!m_instrumentMetadata) {
1142 throw std::runtime_error("Cannot return reference to NULL InstrumentMetadata");
1143 }
1144 return *m_instrumentMetadata;
1145}
1146
1148size_t ParameterMap::detectorIndex(const detid_t detID) const { return m_instrument->detectorIndex(detID); }
1149
1150size_t ParameterMap::componentIndex(const ComponentID componentId) const {
1151 return m_componentInfo->indexOf(componentId);
1152}
1153
1156 if (instrument == m_instrument)
1157 return;
1158 if (!instrument) {
1159 m_componentInfo = nullptr;
1160 m_detectorInfo = nullptr;
1161 m_instrumentMetadata = nullptr;
1162 return;
1163 }
1164 if (m_instrument)
1165 throw std::logic_error("ParameterMap::setInstrument: Cannot change "
1166 "instrument once it has been set.");
1167 if (instrument->isParametrized())
1168 throw std::logic_error("ParameterMap::setInstrument must be called with "
1169 "base instrument, not a parametrized instrument");
1170 m_instrument = instrument;
1171 // Assigned one at a time rather than through std::tie: the members are shared_ptr while
1172 // makeBeamline returns unique_ptr, and the conversion is clearer spelled out.
1173 auto [newComponentInfo, newDetectorInfo] =
1175 m_componentInfo = std::move(newComponentInfo);
1176 m_detectorInfo = std::move(newDetectorInfo);
1177 // The visitor called rekey() while building the beamline, so this map and the new
1178 // ComponentInfo now share one store. Re-point at it to be certain of that even on the
1179 // makeBeamlineNew() path, where there were no parameters to rekey.
1180 if (m_componentInfo) {
1181 m_parameterInfo = m_componentInfo->sharedParameterInfo();
1183 }
1185}
1186
1191 for (auto const &[key, parameter] : m_instrument->getLogfileCache()) {
1192 auto const index = m_componentInfo->indexOfOrInvalid(key.second);
1194 m_parameterInfo->addLogfileParameter(index, key.first, parameter);
1195 }
1196 }
1197}
1198
1201 std::shared_ptr<const ComponentInfo> physicalComponentInfo;
1202 std::shared_ptr<const DetectorInfo> physicalDetectorInfo;
1203 if (const auto &basePhysicalInstrument = m_instrument->getPhysicalInstrument()) {
1204 // This map's parameters are keyed by the neutronic instrument's components, so none apply to the
1205 // physical one and it is walked unparametrized. The visitor keeps it alive inside the DetectorInfo.
1206 InstrumentVisitor visitor(basePhysicalInstrument);
1207 visitor.walkInstrument();
1208 std::tie(physicalComponentInfo, physicalDetectorInfo) = visitor.makeWrappers();
1209 }
1210 m_instrumentMetadata = std::make_shared<InstrumentMetadata>(
1213 physicalDetectorInfo);
1214}
1215
1220 // The parameters themselves, including the Parameter objects on the heap. Note that the
1221 // store may be shared with the owning ComponentInfo, which reports it too, so summing this
1222 // with ComponentInfo::getMemorySize() double-counts it.
1223 const size_t mapMem = m_parameterInfo->getMemorySize();
1224 // The staging tables, which exist only here. The index domain is shared with ComponentInfo,
1225 // which reports it.
1226 const size_t translationMem =
1227 m_stagedIndices.size() * (sizeof(std::pair<const ComponentID, size_t>) + sizeof(void *)) +
1228 m_stagedIds.capacity() * sizeof(ComponentID);
1229 // m_parameterFileNames: vector of strings; sizeof(*this) covers the vector object, count the heap buffer
1230 const size_t fileNamesMem = m_parameterFileNames.size() * sizeof(std::string) +
1231 std::accumulate(m_parameterFileNames.cbegin(), m_parameterFileNames.cend(), size_t{0},
1232 [](size_t acc, const auto &s) { return acc + s.capacity(); });
1233 // m_detectorInfo and m_componentInfo: owned by ParameterMap for parametrized instruments
1234 const size_t detectorInfoMem = m_detectorInfo ? m_detectorInfo->getMemorySize() : 0;
1235 const size_t componentInfoMem = m_componentInfo ? m_componentInfo->getMemorySize() : 0;
1236 // m_instrument is a non-owning raw pointer to the base Instrument; its memory is counted in
1237 // Instrument::getMemorySize() and excluded here to avoid double-counting.
1238 return sizeof(*this) + mapMem + translationMem + fileNamesMem + detectorInfoMem + componentInfoMem;
1239}
1240
1241} // 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)
ComponentInfo : Provides a component centric view on to the instrument.
std::string fullName(const size_t componentIndex) const
The fully-qualified name of a component ("instrument/bank1/pixel3")
bool isDetector(const size_t componentIndex) const
const std::string & name(const size_t componentIndex) const
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....
const std::vector< detid_t > & detectorIDs() const
Returns a sorted vector of all detector IDs.
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.
virtual std::string getFullName() const =0
Get the IComponent full path name.
InstrumentMetadata : metadata related to the entire instrument.
InstrumentVisitor : Visitor for components with access to Info wrapping features.
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::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:150
const std::string & getDefaultAxis() const
Retrieves from which side the instrument to be viewed from when the instrument viewer first starts,...
Definition Instrument.h:157
const std::string & getXmlText() const
Types::Core::DateAndTime getValidFromDate() const
Definition Instrument.h:172
InstrumentParameterCache & getLogfileCache()
Get information about the parameters described in the instrument definition file and associated param...
Definition Instrument.h:139
Types::Core::DateAndTime getValidToDate() const
Definition Instrument.h:175
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
ParameterInfo : the named parameters of an instrument, addressed by component index.
Parameter map iterator typedef.
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 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)
std::vector< ComponentID > m_stagedIds
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(std::shared_ptr< const ComponentIDs > componentIds, std::shared_ptr< const ComponentIndices > componentIndices)
Attach this map to an instrument's component index domain, rekeying its parameters onto the instrumen...
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::shared_ptr< Geometry::InstrumentMetadata > m_instrumentMetadata
static const std::string & rot()
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 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::string componentName(const size_t index) const
The name of the component with this store index.
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 component's index in the instrument this map belongs to,...
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()
size_t getMemorySize() const
Get the footprint in memory in bytes.
size_t indexForWrite(const IComponent *comp)
As indexOf(), but allocating a staging index for a component of a detached map seen for the first tim...
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::unordered_map< Geometry::IComponent const *, size_t > m_stagedIndices
Staging indices, for the components of a detached map, which has no component indices yet.
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 void saveNexus(Nexus::File *file, const std::string &group, const std::string &contents)
Persist a representation of a Parameter map, as given by asString(), to the open Nexus file.
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::shared_ptr< const ComponentIndices > m_domainIndices
void seedLogfileParameters()
Copies m_instrument's logfile parameters into the store. Requires the beamline to be built.
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.
static std::string asStringEntry(const std::string &component, const Parameter &parameter)
Returns the asString() entry for one parameter of a component, given as "detID:<id>" or by full name.
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()
std::string componentFullName(const size_t index) const
The full name of the component with this store index.
const std::string getShortDescription(const std::string &compName, const std::string &name) const
Get the component tooltip by name.
const std::vector< Geometry::ComponentID > & componentIds() const
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
std::shared_ptr< const ComponentIDs > m_domainIds
The index domain: the components of the instrument this map is attached to, shared with that instrume...
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:42
const std::string & type() const
Parameter type.
Definition Parameter.h:48
const bool & visible() const
Parameter visibility in InstrumentViewer.
Definition Parameter.h:54
const std::string & name() const
Parameter name.
Definition Parameter.h:50
virtual std::string asString() const
Returns the value of the property as a string.
Definition Parameter.h:60
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:38
Class for 3D vectors.
Definition V3D.h:35
void setX(const double xx) noexcept
Set is x position.
Definition V3D.h:225
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:203
Mantid::Kernel::Logger g_log("Goniometer")
IComponent * ComponentID
Define a type for a unique component identifier.
Definition IComponent.h:35
int32_t detid_t
Typedef for a detector ID.
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)