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 +
10#include "MantidAPI/Run.h"
12#include "MantidKernel/Logger.h"
14
15namespace Mantid::API {
16namespace {
18size_t MAXIMUM_DEPTH = 100;
20Kernel::Logger g_log("WorkspaceGroup");
21} // namespace
22
23WorkspaceGroup::WorkspaceGroup(const Parallel::StorageMode storageMode)
24 : Workspace(storageMode), m_deleteObserver(*this, &WorkspaceGroup::workspaceDeleteHandle),
25 m_beforeReplaceObserver(*this, &WorkspaceGroup::workspaceBeforeReplaceHandle), m_workspaces(),
26 m_observingADS(false) {}
27
29
38const std::string WorkspaceGroup::toString() const {
39 const std::string firstLine = this->id() + "\n";
40 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
41 const auto descr = std::accumulate(
42 m_workspaces.cbegin(), m_workspaces.cend(), firstLine,
43 [](const auto &string, const auto &workspace) { return string + " -- " + workspace->getName() + '\n'; });
44 return descr;
45}
46
54void WorkspaceGroup::observeADSNotifications(const bool observeADS) {
55 if (observeADS) {
56 if (!m_observingADS) {
57 AnalysisDataService::Instance().notificationCenter.addObserver(m_deleteObserver);
58 AnalysisDataService::Instance().notificationCenter.addObserver(m_beforeReplaceObserver);
59 m_observingADS = true;
60 }
61 } else {
62 if (m_observingADS) {
63 AnalysisDataService::Instance().notificationCenter.removeObserver(m_deleteObserver);
64 AnalysisDataService::Instance().notificationCenter.removeObserver(m_beforeReplaceObserver);
65 m_observingADS = false;
66 }
67 }
68}
69
74bool WorkspaceGroup::isInChildGroup(const Workspace &workspaceToCheck) const {
75 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
76 for (const auto &workspace : m_workspaces) {
77 // check child groups only
78 auto *group = dynamic_cast<WorkspaceGroup *>(workspace.get());
79 if (group) {
80 if (group->isInGroup(workspaceToCheck))
81 return true;
82 }
83 }
84 return false;
85}
86
91 if (this->size() == 0) {
92 return;
93 }
94 std::sort(m_workspaces.begin(), m_workspaces.end(),
95 [](const Workspace_sptr &w1, const Workspace_sptr &w2) { return (w1->getName() < w2->getName()); });
96}
97
105 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
106 if (this == workspace.get()) {
107 g_log.warning("Can't add a workspace as a child of itself!\n");
108 return;
109 }
110 const auto it = std::find(m_workspaces.begin(), m_workspaces.end(), workspace);
111 if (it == m_workspaces.end()) {
112 m_workspaces.emplace_back(workspace);
113 } else {
114 g_log.warning() << "Workspace already exists in a WorkspaceGroup\n";
115 }
116}
117
123bool WorkspaceGroup::containsInChildren(const std::string &wsName) const {
124 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
125 for (const auto &workspace : m_workspaces) {
126 if (workspace->isGroup()) {
127 // Recursive containsInChildren search
128 const auto group = std::dynamic_pointer_cast<WorkspaceGroup>(workspace);
129 if (group->containsInChildren(wsName)) {
130 return true;
131 }
132 } else {
133 if (workspace->getName() == wsName)
134 return true;
135 }
136 }
137 return false;
138}
139
145bool WorkspaceGroup::contains(const std::string &wsName) const {
146 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
147 return std::any_of(m_workspaces.cbegin(), m_workspaces.cend(),
148 [&wsName](const auto &workspace) { return workspace->getName() == wsName; });
149}
150
156 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
157 auto iend = m_workspaces.end();
158 auto it = std::find(m_workspaces.begin(), iend, workspace);
159 return (it != iend);
160}
161
166void WorkspaceGroup::reportMembers(std::set<Workspace_sptr> &memberList) const {
167 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
168 memberList.insert(m_workspaces.begin(), m_workspaces.end());
169}
170
176std::vector<std::string> WorkspaceGroup::getNames() const {
177 std::vector<std::string> out;
178 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
179 out.reserve(m_workspaces.size());
180
181 std::transform(m_workspaces.begin(), m_workspaces.end(), std::back_inserter(out),
182 [](const auto &ws) { return ws->getName(); });
183
184 return out;
185}
186
193 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
194 if (index >= this->size())
195 this->throwIndexOutOfRangeError(static_cast<int>(index));
196 return m_workspaces[index];
197}
198
205Workspace_sptr WorkspaceGroup::getItem(const std::string &wsName) const {
206 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
207 const auto found = std::find_if(m_workspaces.cbegin(), m_workspaces.cend(),
208 [&wsName](const auto &workspace) { return workspace->getName() == wsName; });
209 if (found == m_workspaces.cend()) {
210 throw std::out_of_range("Workspace " + wsName + " not contained in the group");
211 } else {
212 return *found;
213 }
214}
215
218std::vector<Workspace_sptr> WorkspaceGroup::getAllItems() const {
219 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
220 return m_workspaces;
221}
222
226
231void WorkspaceGroup::removeByADS(const std::string &wsName) {
232 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
233 auto it = m_workspaces.begin();
234 for (; it != m_workspaces.end(); ++it) {
235 if ((**it).getName() == wsName) {
236 m_workspaces.erase(it);
237 break;
238 }
239 }
240}
241
245 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
246 for (const auto &workspace : m_workspaces) {
247 g_log.debug() << "Workspace name in group vector = " << workspace->getName() << '\n';
248 }
249}
250
251/*
252 * Throws an out of range error for an out of range index
253 * @param index The out of range index to be printed
254 * @throws out_of_range error
255 */
257 std::ostringstream os;
258 os << "WorkspaceGroup - index out of range. Requested=" << index << ", current size=" << this->size();
259 throw std::out_of_range(os.str());
260}
261
268std::vector<Workspace_sptr>::iterator WorkspaceGroup::begin() { return m_workspaces.begin(); }
269
276std::vector<Workspace_sptr>::const_iterator WorkspaceGroup::begin() const { return m_workspaces.begin(); }
277
284std::vector<Workspace_sptr>::iterator WorkspaceGroup::end() { return m_workspaces.end(); }
285
292std::vector<Workspace_sptr>::const_iterator WorkspaceGroup::end() const { return m_workspaces.end(); }
293
301 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
302 // do not allow this way of removing for groups in the ADS
303 if (!this->getName().empty()) {
304 throw std::runtime_error("AnalysisDataService must be used to remove a "
305 "workspace from group.");
306 }
307 if (index >= this->size()) {
308 std::ostringstream os;
309 os << "WorkspaceGroup - index out of range. Requested=" << index << ", current size=" << this->size();
310 throw std::out_of_range(os.str());
311 }
312 auto it = m_workspaces.begin() + index;
313 m_workspaces.erase(it);
314}
315
325 std::unique_lock<std::recursive_mutex> _lock(m_mutex);
326 const std::string deletedName = notice->objectName();
327 if (!this->contains(deletedName))
328 return;
329
330 if (deletedName != this->getName()) {
331 this->removeByADS(deletedName);
332 if (isEmpty()) {
333 // We are about to get deleted so we don't want to recieve any
334 // notifications
335 // The unique lock needs to be unlocked at this point as the workspace
336 // is about to destroy itself. We have to make sure that the mutex is
337 // not locked.
338 _lock.unlock();
340 AnalysisDataService::Instance().remove(this->getName());
341 }
342 }
343}
344
353 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
354
355 const auto oldObject = notice->oldObject();
356 const auto newObject = notice->newObject();
357
358 bool foundOld(false);
359 bool foundDuplicate(false);
360
361 auto duplicateIter = m_workspaces.end();
362
363 for (auto it = m_workspaces.begin(); it != m_workspaces.end(); ++it) {
364 auto &workspace = *it;
365 if (workspace == oldObject) {
366 workspace = newObject;
367 foundOld = true;
368
369 } else if (workspace == newObject) {
370 duplicateIter = it;
371 foundDuplicate = true;
372 }
373
374 if (foundOld && foundDuplicate) {
375 break;
376 }
377 }
378
379 if (foundOld && duplicateIter != m_workspaces.end()) {
380 m_workspaces.erase(duplicateIter);
381 }
382}
383
389 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
390 return m_workspaces.empty();
391}
392
393//------------------------------------------------------------------------------
401 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
402 if (m_workspaces.empty())
403 return false;
404
405 // Check all the members are of similar names
406 for (const auto &workspace : m_workspaces) {
407 const std::string &wsName = workspace->getName();
408 // Find the last underscore _
409 std::size_t pos = wsName.find_last_of('_');
410 // No underscore = not similar
411 if (pos == std::string::npos)
412 return false;
413 // The part before the underscore has to be the same
414 // as the group name to be similar
415 std::string commonpart(wsName.substr(0, pos));
416 if (this->getName() != commonpart)
417 return false;
418 }
419 return true;
420}
421
422//------------------------------------------------------------------------------
428 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
429 if (m_workspaces.empty()) {
430 g_log.debug("Not a multiperiod-group with < 1 nested workspace.");
431 return false;
432 }
433 // Loop through all inner workspaces, checking each one in turn.
434 for (const auto &workspace : m_workspaces) {
435 if (MatrixWorkspace_sptr ws = std::dynamic_pointer_cast<MatrixWorkspace>(workspace)) {
436 try {
437 Kernel::Property *nPeriodsProp = ws->run().getLogData("nperiods");
438 int num = -1;
439 Kernel::Strings::convert(nPeriodsProp->value(), num);
440 if (num < 1) {
441 g_log.debug("Not a multiperiod-group with nperiods log < 1.");
442 return false;
443 }
445 g_log.debug("Not a multiperiod-group without nperiods log on all "
446 "nested workspaces.");
447 return false;
448 }
449 } else {
450 g_log.debug("Not a multiperiod-group unless all inner workspaces are "
451 "Matrix Workspaces.");
452 return false;
453 }
454 }
455 return true;
456}
457
465bool WorkspaceGroup::isInGroup(const Workspace &workspaceToCheck, size_t level) const {
466 // Check for a cycle.
467 if (level > MAXIMUM_DEPTH) {
468 throw std::runtime_error("WorkspaceGroup nesting level is too deep.");
469 }
470 std::lock_guard<std::recursive_mutex> _lock(m_mutex);
471 for (const auto &workspace : m_workspaces) {
472 if (workspace.get() == &workspaceToCheck)
473 return true;
474 auto *group = dynamic_cast<WorkspaceGroup *>(workspace.get());
475 if (group) {
476 if (group->isInGroup(workspaceToCheck, level + 1))
477 return true;
478 }
479 }
480 return false;
481}
482
484 auto total = std::size_t(0);
485 // Go through each workspace
486 for (auto workspace : m_workspaces) {
487 // If the workspace is a group
488 if (workspace->getMemorySize() == 0) {
489 total = total + std::dynamic_pointer_cast<WorkspaceGroup>(workspace)->getMemorySize();
490 continue;
491 }
492 total = total + workspace->getMemorySize();
493 }
494 return total;
495}
496
497} // namespace Mantid::API
498
500
501namespace Mantid::Kernel {
502
503template <>
505IPropertyManager::getValue<Mantid::API::WorkspaceGroup_sptr>(const std::string &name) const {
506 auto *prop = dynamic_cast<PropertyWithValue<Mantid::API::WorkspaceGroup_sptr> *>(getPointerToProperty(name));
507 if (prop) {
508 return *prop;
509 } else {
510 std::string message =
511 "Attempt to assign property " + name + " to incorrect type. Expected shared_ptr<WorkspaceGroup>.";
512 throw std::runtime_error(message);
513 }
514}
515
516template <>
518IPropertyManager::getValue<Mantid::API::WorkspaceGroup_const_sptr>(const std::string &name) const {
519 auto *prop = dynamic_cast<PropertyWithValue<Mantid::API::WorkspaceGroup_sptr> *>(getPointerToProperty(name));
520 if (prop) {
521 return prop->operator()();
522 } else {
523 std::string message =
524 "Attempt to assign property " + name + " to incorrect type. Expected const shared_ptr<WorkspaceGroup>.";
525 throw std::runtime_error(message);
526 }
527}
528
529} // namespace Mantid::Kernel
530
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
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.
WorkspaceGroup(const Parallel::StorageMode storageMode=Parallel::StorageMode::Cloned)
Default constructor.
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() 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
Inidicates 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.
size_t size() const
Return the size of the group, so it is more like a container.
Base Workspace Abstract Class.
Definition: Workspace.h:30
const std::string & getName() const override
Get the workspace name.
Definition: Workspace.cpp:58
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:114
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
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.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Definition: Workspace_fwd.h:20
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:665