Mantid
Loading...
Searching...
No Matches
WorkspaceGroup.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
11#include "MantidAPI/Run.h"
13#include "MantidKernel/Logger.h"
15
16namespace Mantid::API {
17namespace {
19size_t MAXIMUM_DEPTH = 100;
21Kernel::Logger g_log("WorkspaceGroup");
22} // namespace
23
25 : Workspace(), m_deleteObserver(*this, &WorkspaceGroup::workspaceDeleteHandle),
26 m_beforeReplaceObserver(*this, &WorkspaceGroup::workspaceBeforeReplaceHandle), m_workspaces(),
27 m_observingADS(false) {}
28
30
39const std::string WorkspaceGroup::toString() const {
40 const std::string firstLine = this->id() + "\n";
41 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
42 const auto descr = std::accumulate(
43 m_workspaces.cbegin(), m_workspaces.cend(), firstLine,
44 [](const auto &string, const auto &workspace) { return string + " -- " + workspace->getName() + '\n'; });
45 return descr;
46}
47
55void WorkspaceGroup::observeADSNotifications(const bool observeADS) {
56 if (observeADS) {
57 if (!m_observingADS) {
58 AnalysisDataService::Instance().notificationCenter.addObserver(m_deleteObserver);
59 AnalysisDataService::Instance().notificationCenter.addObserver(m_beforeReplaceObserver);
60 m_observingADS = true;
61 }
62 } else {
63 if (m_observingADS) {
64 AnalysisDataService::Instance().notificationCenter.removeObserver(m_deleteObserver);
65 AnalysisDataService::Instance().notificationCenter.removeObserver(m_beforeReplaceObserver);
66 m_observingADS = false;
67 }
68 }
69}
70
75bool WorkspaceGroup::isInChildGroup(const Workspace &workspaceToCheck) const {
76 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
77 for (const auto &workspace : m_workspaces) {
78 // check child groups only
79 auto const *group = dynamic_cast<WorkspaceGroup *>(workspace.get());
80 if (group) {
81 if (group->isInGroup(workspaceToCheck))
82 return true;
83 }
84 }
85 return false;
86}
87
92 if (this->size() == 0) {
93 return;
94 }
95 std::sort(m_workspaces.begin(), m_workspaces.end(),
96 [](const Workspace_sptr &w1, const Workspace_sptr &w2) { return (w1->getName() < w2->getName()); });
97}
98
102void WorkspaceGroup::reorderMembersWithIndices(const std::vector<int> &indices) {
103 if (indices.size() != this->size()) {
104 g_log.warning("Number of indices must match the number of workspace members\n");
105 return;
106 }
107
108 if (!std::all_of(indices.cbegin(), indices.cend(),
109 [&](const int i) { return i >= 0 && i < static_cast<int>(m_workspaces.size()); })) {
110 g_log.warning("All indices must be >= 0 and < the number of workspaces in the group\n");
111 return;
112 }
113
114 // check all elements are unique by adding to a set and checking size
115 if (std::unordered_set<int>(indices.cbegin(), indices.cend()).size() != indices.size()) {
116 g_log.warning("All indices must be unique\n");
117 return;
118 }
119
120 std::vector<Mantid::API::Workspace_sptr> reordered;
121 std::transform(indices.cbegin(), indices.cend(), std::back_inserter(reordered),
122 [&](const auto &i) { return m_workspaces[i]; });
123 m_workspaces = std::move(reordered);
124}
125
133 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
134 if (this == workspace.get()) {
135 g_log.warning("Can't add a workspace as a child of itself!\n");
136 return;
137 }
138 const auto it = std::find(m_workspaces.begin(), m_workspaces.end(), workspace);
139 if (it == m_workspaces.end()) {
140 m_workspaces.emplace_back(workspace);
141 } else {
142 g_log.warning() << "Workspace already exists in a WorkspaceGroup\n";
143 }
144}
145
151bool WorkspaceGroup::containsInChildren(const std::string &wsName) const {
152 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
153
154 const auto it = std::find_if(m_workspaces.cbegin(), m_workspaces.cend(), [&wsName](const auto &workspace) {
155 if (workspace->isGroup()) {
156 const auto group = std::dynamic_pointer_cast<WorkspaceGroup>(workspace);
157 return group->containsInChildren(wsName);
158 }
159 return workspace->getName() == wsName;
160 });
161
162 return it != m_workspaces.cend();
163}
164
170bool WorkspaceGroup::contains(const std::string &wsName) const {
171 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
172 return std::any_of(m_workspaces.cbegin(), m_workspaces.cend(),
173 [&wsName](const auto &workspace) { return workspace->getName() == wsName; });
174}
175
181 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
182 auto iend = m_workspaces.end();
183 auto it = std::find(m_workspaces.begin(), iend, workspace);
184 return (it != iend);
185}
186
191void WorkspaceGroup::reportMembers(std::set<Workspace_sptr> &memberList) const {
192 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
193 memberList.insert(m_workspaces.begin(), m_workspaces.end());
194}
195
201std::vector<std::string> WorkspaceGroup::getNames() const {
202 std::vector<std::string> out;
203 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
204 out.reserve(m_workspaces.size());
205
206 std::transform(m_workspaces.begin(), m_workspaces.end(), std::back_inserter(out),
207 [](const auto &ws) { return ws->getName(); });
208
209 return out;
210}
211
218 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
219 if (index >= this->size())
220 this->throwIndexOutOfRangeError(static_cast<int>(index));
221 return m_workspaces[index];
222}
223
230Workspace_sptr WorkspaceGroup::getItem(const std::string &wsName) const {
231 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
232 const auto found = std::find_if(m_workspaces.cbegin(), m_workspaces.cend(),
233 [&wsName](const auto &workspace) { return workspace->getName() == wsName; });
234 if (found == m_workspaces.cend()) {
235 throw std::out_of_range("Workspace " + wsName + " not contained in the group");
236 } else {
237 return *found;
238 }
239}
240
243std::vector<Workspace_sptr> WorkspaceGroup::getAllItems() const {
244 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
245 return m_workspaces;
246}
247
251
256void WorkspaceGroup::removeByADS(const std::string &wsName) {
257 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
258 auto it = m_workspaces.begin();
259 for (; it != m_workspaces.end(); ++it) {
260 if ((**it).getName() == wsName) {
261 m_workspaces.erase(it);
262 break;
263 }
264 }
265}
266
270 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
271 for (const auto &workspace : m_workspaces) {
272 g_log.debug() << "Workspace name in group vector = " << workspace->getName() << '\n';
273 }
274}
275
276/*
277 * Throws an out of range error for an out of range index
278 * @param index The out of range index to be printed
279 * @throws out_of_range error
280 */
282 std::ostringstream os;
283 os << "WorkspaceGroup - index out of range. Requested=" << index << ", current size=" << this->size();
284 throw std::out_of_range(os.str());
285}
286
293std::vector<Workspace_sptr>::iterator WorkspaceGroup::begin() { return m_workspaces.begin(); }
294
301std::vector<Workspace_sptr>::const_iterator WorkspaceGroup::begin() const { return m_workspaces.begin(); }
302
309std::vector<Workspace_sptr>::iterator WorkspaceGroup::end() { return m_workspaces.end(); }
310
317std::vector<Workspace_sptr>::const_iterator WorkspaceGroup::end() const { return m_workspaces.end(); }
318
326 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
327 // do not allow this way of removing for groups in the ADS
328 if (!this->getName().empty()) {
329 throw std::runtime_error("AnalysisDataService must be used to remove a "
330 "workspace from group.");
331 }
332 if (index >= this->size()) {
333 std::ostringstream os;
334 os << "WorkspaceGroup - index out of range. Requested=" << index << ", current size=" << this->size();
335 throw std::out_of_range(os.str());
336 }
337 auto it = m_workspaces.begin() + index;
338 m_workspaces.erase(it);
339}
340
350 std::unique_lock<std::recursive_mutex> _lock(m_mutex);
351 const std::string deletedName = notice->objectName();
352 if (!this->contains(deletedName))
353 return;
354
355 if (deletedName != this->getName()) {
356 this->removeByADS(deletedName);
357 if (isEmpty()) {
358 // We are about to get deleted so we don't want to recieve any
359 // notifications
360 // The unique lock needs to be unlocked at this point as the workspace
361 // is about to destroy itself. We have to make sure that the mutex is
362 // not locked.
363 _lock.unlock();
365 AnalysisDataService::Instance().remove(this->getName());
366 }
367 }
368}
369
378 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
379
380 const auto oldObject = notice->oldObject();
381 const auto newObject = notice->newObject();
382
383 bool foundOld(false);
384 bool foundDuplicate(false);
385
386 auto duplicateIter = m_workspaces.end();
387
388 for (auto it = m_workspaces.begin(); it != m_workspaces.end(); ++it) {
389 auto &workspace = *it;
390 if (workspace == oldObject) {
391 workspace = newObject;
392 foundOld = true;
393
394 } else if (workspace == newObject) {
395 duplicateIter = it;
396 foundDuplicate = true;
397 }
398
399 if (foundOld && foundDuplicate) {
400 break;
401 }
402 }
403
404 if (foundOld && duplicateIter != m_workspaces.end()) {
405 m_workspaces.erase(duplicateIter);
406 }
407}
408
414 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
415 return m_workspaces.empty();
416}
417
418//------------------------------------------------------------------------------
426 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
427 if (m_workspaces.empty())
428 return false;
429
430 // Check all the members are of similar names
431 return std::all_of(m_workspaces.cbegin(), m_workspaces.cend(), [this](const auto &workspace) {
432 const std::string &wsName = workspace->getName();
433 // Find the last underscore _
434 std::size_t pos = wsName.find_last_of('_');
435 // No underscore = not similar
436 if (pos == std::string::npos)
437 return false;
438 // The part before the underscore has to be the same
439 // as the group name to be similar
440 std::string commonpart(wsName.substr(0, pos));
441 if (this->getName() != commonpart)
442 return false;
443 return true;
444 });
445}
446
447//------------------------------------------------------------------------------
453 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
454 if (m_workspaces.empty()) {
455 g_log.debug("Not a multiperiod-group with < 1 nested workspace.");
456 return false;
457 }
458 // Loop through all inner workspaces, checking each one in turn.
459 for (const auto &workspace : m_workspaces) {
460 if (MatrixWorkspace_sptr ws = std::dynamic_pointer_cast<MatrixWorkspace>(workspace)) {
461 try {
462 const Kernel::Property *nPeriodsProp = ws->run().getLogData("nperiods");
463 int num = -1;
464 Kernel::Strings::convert(nPeriodsProp->value(), num);
465 if (num < 1) {
466 g_log.debug("Not a multiperiod-group with nperiods log < 1.");
467 return false;
468 }
470 g_log.debug("Not a multiperiod-group without nperiods log on all "
471 "nested workspaces.");
472 return false;
473 }
474 } else {
475 g_log.debug("Not a multiperiod-group unless all inner workspaces are "
476 "Matrix Workspaces.");
477 return false;
478 }
479 }
480 return true;
481}
482
487 return std::all_of(m_workspaces.begin(), m_workspaces.end(),
488 [](auto ws) { return dynamic_cast<IPeaksWorkspace *>(ws.get()) != nullptr; });
489}
490
498bool WorkspaceGroup::isInGroup(const Workspace &workspaceToCheck, size_t level) const {
499 // Check for a cycle.
500 if (level > MAXIMUM_DEPTH) {
501 throw std::runtime_error("WorkspaceGroup nesting level is too deep.");
502 }
503 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
504 for (const auto &workspace : m_workspaces) {
505 if (workspace.get() == &workspaceToCheck)
506 return true;
507 const auto *group = dynamic_cast<WorkspaceGroup *>(workspace.get());
508 if (group) {
509 if (group->isInGroup(workspaceToCheck, level + 1))
510 return true;
511 }
512 }
513 return false;
514}
515
517 auto total = std::size_t(0);
518 // Go through each workspace
519 for (auto workspace : m_workspaces) {
520 // If the workspace is a group
521 if (workspace->getMemorySize() == 0) {
522 total = total + std::dynamic_pointer_cast<WorkspaceGroup>(workspace)->getMemorySize();
523 continue;
524 }
525 total = total + workspace->getMemorySize();
526 }
527 return total;
528}
529
530} // namespace Mantid::API
531
533
534namespace Mantid::Kernel {
535
536template <>
538IPropertyManager::getValue<Mantid::API::WorkspaceGroup_sptr>(const std::string &name) const {
539 const auto *prop = dynamic_cast<PropertyWithValue<Mantid::API::WorkspaceGroup_sptr> *>(getPointerToProperty(name));
540 if (prop) {
541 return *prop;
542 } else {
543 std::string message =
544 "Attempt to assign property " + name + " to incorrect type. Expected shared_ptr<WorkspaceGroup>.";
545 throw std::runtime_error(message);
546 }
547}
548
549template <>
551IPropertyManager::getValue<Mantid::API::WorkspaceGroup_const_sptr>(const std::string &name) const {
552 const auto *prop = dynamic_cast<PropertyWithValue<Mantid::API::WorkspaceGroup_sptr> *>(getPointerToProperty(name));
553 if (prop) {
554 return prop->operator()();
555 } else {
556 std::string message =
557 "Attempt to assign property " + name + " to incorrect type. Expected const shared_ptr<WorkspaceGroup>.";
558 throw std::runtime_error(message);
559 }
560}
561
562} // namespace Mantid::Kernel
563
std::string name
Definition Run.cpp:60
IPeaksWorkspace_sptr workspace
std::map< DeltaEMode::Type, std::string > index
Class to hold a set of workspaces.
std::vector< Workspace_sptr > getAllItems() const
Return all workspaces in the group as one call for thread safety.
void observeADSNotifications(const bool observeADS)
Turn ADS observations on/off.
void addWorkspace(const Workspace_sptr &workspace)
Adds a workspace to the group.
const std::string toString() const override
Returns a formatted string detailing the contents of the group.
std::vector< Workspace_sptr >::iterator end()
Returns a non-const iterator pointing at the last element in the workspace group.
Poco::NObserver< WorkspaceGroup, Mantid::API::WorkspaceBeforeReplaceNotification > m_beforeReplaceObserver
Observer for workspace before-replace notifications.
void removeAll()
Remove all names from the group but do not touch the ADS.
void reorderMembersWithIndices(const std::vector< int > &indices)
Reorder the group members using a list of indices (e.g the list 4,3,2,1 would reverse the order)
void workspaceDeleteHandle(Mantid::API::WorkspacePostDeleteNotification_ptr notice)
Callback when a delete notification is received.
const std::string id() const override
Return a string ID of the class.
Poco::NObserver< WorkspaceGroup, Mantid::API::WorkspacePostDeleteNotification > m_deleteObserver
Observer for workspace delete notifications.
WorkspaceGroup()
Default constructor.
~WorkspaceGroup() override
Destructor.
size_t getMemorySize() const override
Return the memory size of all workspaces in this group and subgroups.
bool m_observingADS
Flag as to whether the observers have been added to the ADS.
std::vector< Workspace_sptr >::iterator begin()
Returns a non-const iterator pointing at the first element in the workspace group.
void removeByADS(const std::string &wsName)
ADS removes a member of this group using this method.
void print() const
Prints the group to the screen using the logger at debug.
bool isEmpty() const
This method returns true if the group is empty (no member workspace)
void removeItem(const size_t index)
Remove a workspace from the group.
bool contains(const std::string &wsName) const
Does a workspace exist within the group.
Workspace_sptr getItem(const size_t index) const
Return the ith workspace.
bool containsInChildren(const std::string &wsName) const
Does a workspace exist within the group or any groups within this group.
void reportMembers(std::set< Workspace_sptr > &memberList) const
Add the members of the group to the given list.
std::vector< Workspace_sptr > m_workspaces
The list of workspace pointers in the group.
bool isInChildGroup(const Workspace &workspaceToCheck) const
Check if a workspace is included in any child groups and groups in them.
std::vector< std::string > getNames() const
Returns the names of workspaces that make up this group.
std::recursive_mutex m_mutex
Recursive mutex to avoid simultaneous access.
void sortMembersByName()
Sort the internal data structure according to member name.
void workspaceBeforeReplaceHandle(Mantid::API::WorkspaceBeforeReplaceNotification_ptr notice)
Callback when a before-replace notification is received.
void throwIndexOutOfRangeError(int index) const
Throws an out_of_range error for an invalid index.
bool isMultiperiod() const
Indicates that the workspace group can be treated as multiperiod.
bool areNamesSimilar() const
Are the members of this group of similar names, e.g.
bool isInGroup(const Workspace &workspaceToCheck, size_t level=0) const
Check if a workspace is included in this group or any nested groups.
bool isGroupPeaksWorkspaces() const
Check if the workspace group contains just peak workspaces.
size_t size() const
Return the size of the group, so it is more like a container.
Base Workspace Abstract Class.
Definition Workspace.h:29
const std::string & getName() const override
Get the workspace name.
Definition Workspace.cpp:59
Exception for when an item is not found in a collection.
Definition Exception.h:145
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
The concrete, templated class for properties.
Base class for properties.
Definition Property.h:94
virtual std::string value() const =0
Returns the value of the property as a string.
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< const WorkspaceGroup > WorkspaceGroup_const_sptr
shared pointer to Mantid::API::WorkspaceGroup, pointer to const version
const Poco::AutoPtr< Mantid::Kernel::DataService< Mantid::API::Workspace >::BeforeReplaceNotification > & WorkspaceBeforeReplaceNotification_ptr
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
const Poco::AutoPtr< Mantid::Kernel::DataService< Mantid::API::Workspace >::PostDeleteNotification > & WorkspacePostDeleteNotification_ptr
int convert(const std::string &A, T &out)
Convert a string into a number.
Definition Strings.cpp:696