Mantid
Loading...
Searching...
No Matches
AnalysisDataService.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 +
9#include <iterator>
10#include <random>
11#include <sstream>
12
13namespace Mantid::API {
14
15//-------------------------------------------------------------------------
16// Nested class methods
17//-------------------------------------------------------------------------
23 : DataServiceNotification(name, AnalysisDataService::Instance().retrieve(name)) {}
27std::shared_ptr<const WorkspaceGroup> AnalysisDataServiceImpl::GroupUpdatedNotification::getWorkspaceGroup() const {
28 return std::dynamic_pointer_cast<const WorkspaceGroup>(this->object());
29}
30
31//-------------------------------------------------------------------------
32// Public methods
33//-------------------------------------------------------------------------
41const std::string AnalysisDataServiceImpl::isValid(const std::string &name) const {
42 std::string error;
43 const std::string &illegal = illegalCharacters();
44 if (illegal.empty())
45 return error; // Quick route out.
46 const size_t length = name.size();
47 for (size_t i = 0; i < length; ++i) {
48 if (illegal.find_first_of(name[i]) != std::string::npos) {
49 std::ostringstream strm;
50 strm << "Invalid object name '" << name << "'. Names cannot contain any of the following characters: " << illegal;
51 error = strm.str();
52 break;
53 }
54 }
55 return error;
56}
57
67void AnalysisDataServiceImpl::add(const std::string &name, const std::shared_ptr<API::Workspace> &workspace) {
68 auto group = std::dynamic_pointer_cast<WorkspaceGroup>(workspace);
70
71 // Attach the name to the workspace
72 if (workspace)
73 workspace->setName(name);
75
76 // if a group is added add its members as well
77 if (!group)
78 return;
79
80 group->observeADSNotifications(true);
81 for (size_t i = 0; i < group->size(); ++i) {
82 auto ws = group->getItem(i);
83 std::string wsName = ws->getName();
84 // if anonymous make up a name and add
85 if (wsName.empty()) {
86 wsName = name + "_" + std::to_string(i + 1);
87 } else if (doesExist(wsName)) { // if ws is already there do nothing
88 wsName.clear();
89 }
90 // add member workspace if needed
91 if (!wsName.empty()) {
92 add(wsName, ws);
93 }
94 }
95}
96
105void AnalysisDataServiceImpl::addOrReplace(const std::string &name, const std::shared_ptr<API::Workspace> &workspace) {
106 auto group = std::dynamic_pointer_cast<WorkspaceGroup>(workspace);
108
109 // Attach the name to the workspace
110 if (workspace)
111 workspace->setName(name);
113
114 if (!group)
115 return;
116 group->observeADSNotifications(true);
117 for (size_t i = 0; i < group->size(); ++i) {
118 auto ws = group->getItem(i);
119 std::string wsName = ws->getName();
120 // make up a name for an anonymous workspace
121 if (wsName.empty()) {
122 wsName = name + "_" + std::to_string(i + 1);
123 } else if (doesExist(wsName)) { // if ws is already there do nothing
124 wsName.clear();
125 }
126 // add member workspace if needed
127 if (!wsName.empty()) {
128 addOrReplace(wsName, ws);
129 }
130 }
131}
132
139void AnalysisDataServiceImpl::rename(const std::string &oldName, const std::string &newName) {
140
141 auto oldWorkspace = retrieve(oldName);
142 auto group = std::dynamic_pointer_cast<WorkspaceGroup>(oldWorkspace);
143 if (group && group->containsInChildren(newName)) {
144 throw std::invalid_argument("Unable to rename group as the new name matches its members");
145 }
146
148 // Attach the new name to the workspace
149 auto ws = retrieve(newName);
150 ws->setName(newName);
151}
152
162 try {
163 ws = retrieve(name);
164 } catch (const Kernel::Exception::NotFoundError &) {
165 // do nothing - remove will do what's needed
166 }
168 if (ws) {
169 ws->setName("");
170 }
171
172 auto group = std::dynamic_pointer_cast<WorkspaceGroup>(ws);
173 if (group) {
174 group->observeADSNotifications(false);
175 }
176 return ws;
177}
178
185 static const std::string alphabet = "abcdefghijklmnopqrstuvwxyz";
186 static std::random_device rd;
187 static std::mt19937 gen(rd());
188 static std::uniform_int_distribution<> dis(0, int(alphabet.size() - 1));
189 return alphabet[dis(gen)];
190}
191
199const std::string AnalysisDataServiceImpl::uniqueName(const int n, const std::string &prefix,
200 const std::string &suffix) {
201 if (n <= 0) {
202 throw std::invalid_argument("n must be a positive number");
203 }
204 auto randomNameGenerator = [n]() {
205 std::string name;
206 for (int i = 0; i < n; ++i) {
208 }
209 return name;
210 };
211
212 // limit of (n * 10 * size of alphabet) to avoid infinite loop in case we can't find name that doesn't collide
213 for (int i = 0; i < (n * 260); i++) {
214 std::string wsName = prefix + randomNameGenerator() + suffix;
215 if (!doesExist(wsName)) {
216 return wsName;
217 }
218 }
219 throw std::runtime_error("Unable to generate unique workspace of length " + std::to_string(n));
220}
221
227
238std::vector<Workspace_sptr> AnalysisDataServiceImpl::retrieveWorkspaces(const std::vector<std::string> &names,
239 bool unrollGroups) const {
240 using WorkspacesVector = std::vector<Workspace_sptr>;
241 WorkspacesVector workspaces;
242 workspaces.reserve(names.size());
243 std::transform(std::begin(names), std::end(names), std::back_inserter(workspaces),
244 [this](const std::string &name) { return this->retrieve(name); });
245 assert(names.size() == workspaces.size());
246 if (unrollGroups) {
247 using IteratorDifference = std::iterator_traits<WorkspacesVector::iterator>::difference_type;
248
249 bool done{workspaces.size() == 0};
250 size_t i{0};
251 while (!done) {
252 if (auto group = std::dynamic_pointer_cast<WorkspaceGroup>(workspaces.at(i))) {
253 const auto groupLength(group->size());
254 workspaces.erase(std::next(std::begin(workspaces), static_cast<IteratorDifference>(i)));
255 for (size_t j = 0; j < groupLength; ++j) {
256 workspaces.insert(std::next(std::begin(workspaces), static_cast<IteratorDifference>(i + j)),
257 group->getItem(j));
258 }
259 i += groupLength;
260 } else {
261 ++i;
262 }
263
264 if (i == workspaces.size()) {
265 done = true;
266 }
267 }
268 }
269 return workspaces;
270}
271
276void AnalysisDataServiceImpl::sortGroupByName(const std::string &groupName) {
277 WorkspaceGroup_sptr group = retrieveWS<WorkspaceGroup>(groupName);
278 if (!group) {
279 throw std::runtime_error("Workspace " + groupName + " is not a workspace group.");
280 }
281 group->sortMembersByName();
282 notificationCenter.postNotification(new GroupUpdatedNotification(groupName));
283}
284
290void AnalysisDataServiceImpl::addToGroup(const std::string &groupName, const std::string &wsName) {
291 WorkspaceGroup_sptr group = retrieveWS<WorkspaceGroup>(groupName);
292 if (!group) {
293 throw std::runtime_error("Workspace " + groupName + " is not a workspace group.");
294 }
295
296 if (groupName == wsName) {
297 throw std::runtime_error("The group name and workspace name are the same");
298 }
299
300 auto ws = retrieve(wsName);
301 group->addWorkspace(ws);
302 notificationCenter.postNotification(new GroupUpdatedNotification(groupName));
303}
304
310 WorkspaceGroup_sptr group = retrieveWS<WorkspaceGroup>(name);
311 if (!group) {
312 throw std::runtime_error("Workspace " + name + " is not a workspace group.");
313 }
314 group->observeADSNotifications(false);
315 for (size_t i = 0; i < group->size(); ++i) {
316 auto ws = group->getItem(i);
317 WorkspaceGroup_sptr gws = std::dynamic_pointer_cast<WorkspaceGroup>(ws);
318 if (gws) {
319 // if a member is a group remove its items as well
320 deepRemoveGroup(gws->getName());
321 } else {
322 remove(ws->getName());
323 }
324 }
325 remove(name);
326}
327
334void AnalysisDataServiceImpl::removeFromGroup(const std::string &groupName, const std::string &wsName) {
335 WorkspaceGroup_sptr group = retrieveWS<WorkspaceGroup>(groupName);
336 if (!group) {
337 throw std::runtime_error("Workspace " + groupName + " is not a workspace group.");
338 }
339 if (!group->contains(wsName)) {
340 throw std::runtime_error("WorkspaceGroup " + groupName + " does not containt workspace " + wsName);
341 }
342 group->removeByADS(wsName);
343 notificationCenter.postNotification(new GroupUpdatedNotification(groupName));
344}
345
351std::map<std::string, Workspace_sptr> AnalysisDataServiceImpl::topLevelItems() const {
352 std::map<std::string, Workspace_sptr> topLevel;
353 auto topLevelNames = this->getObjectNames();
354 std::set<Workspace_sptr> groupMembers;
355
356 for (const auto &topLevelName : topLevelNames) {
357 try {
358 const std::string &name = topLevelName;
359 auto ws = this->retrieve(topLevelName);
360 topLevel.emplace(name, ws);
361 if (auto group = std::dynamic_pointer_cast<WorkspaceGroup>(ws)) {
362 group->reportMembers(groupMembers);
363 }
364 } catch (const std::exception &) {
365 }
366 }
367
368 // Prune members
369 for (auto it = topLevel.begin(); it != topLevel.end();) {
370 const Workspace_sptr &item = it->second;
371 if (groupMembers.count(item) == 1) {
372 topLevel.erase(it++);
373 } else {
374 ++it;
375 }
376 }
377
378 return topLevel;
379}
380
381//-------------------------------------------------------------------------
382// Private methods
383//-------------------------------------------------------------------------
384
390
391// The following is commented using /// rather than /** to stop the compiler
392// complaining
393// about the special characters in the comment fields.
398const std::string &AnalysisDataServiceImpl::illegalCharacters() const { return m_illegalChars; }
399
406void AnalysisDataServiceImpl::setIllegalCharacterList(const std::string &illegalChars) {
407 m_illegalChars = illegalChars;
408}
409
419void AnalysisDataServiceImpl::verifyName(const std::string &name, const std::shared_ptr<API::WorkspaceGroup> &group) {
420 const std::string error = isValid(name);
421 if (!error.empty()) {
422 throw std::invalid_argument(error);
423 }
424
425 if (group && group->containsInChildren(name)) {
426 throw std::invalid_argument("Unable to add group as name matches its members");
427 }
428}
429
430} // namespace Mantid::API
std::string name
Definition Run.cpp:60
double error
IPeaksWorkspace_sptr workspace
GroupWorkspaces notification is send when a group is updated by adding or removing members.
std::shared_ptr< const WorkspaceGroup > getWorkspaceGroup() const
Returns the workspace pointer cast to WorkspaceGroup.
const std::string uniqueName(const int n=5, const std::string &prefix="", const std::string &suffix="")
Random generated unique workspace name.
const std::string isValid(const std::string &name) const
Is the given name a valid name for an object in the ADS.
void setIllegalCharacterList(const std::string &)
Set the list of illegal characters.
std::string m_illegalChars
The string of illegal characters.
const std::string & illegalCharacters() const
Return the list of illegal characters as one string.
virtual void rename(const std::string &oldName, const std::string &newName)
Overridden rename member to attach the new name to the workspace when a workspace object is renamed.
void add(const std::string &name, const std::shared_ptr< API::Workspace > &workspace) override
Overridden add member to attach the name to the workspace when a workspace object is added to the ser...
std::map< std::string, Workspace_sptr > topLevelItems() const
Return a lookup of the top level items.
void sortGroupByName(const std::string &groupName)
Sort members by Workspace name.
void deepRemoveGroup(const std::string &name)
Remove a workspace group and all its members from the ADS.
static char getRandomLowercaseLetter()
random lowercase letter used for generating workspace name in unique_name and unique_hidden_name
void addOrReplace(const std::string &name, const std::shared_ptr< API::Workspace > &workspace) override
Overridden addOrReplace member to attach the name to the workspace when a workspace object is added t...
void addToGroup(const std::string &groupName, const std::string &wsName)
Add a workspace to a group.
void verifyName(const std::string &name, const std::shared_ptr< API::WorkspaceGroup > &workspace)
Checks the name is valid, throwing if not.
std::vector< Workspace_sptr > retrieveWorkspaces(const std::vector< std::string > &names, bool unrollGroups=false) const
Given a list of names retrieve the corresponding workspace handles.
virtual Workspace_sptr remove(const std::string &name)
Overridden remove member to delete its name held by the workspace itself.
const std::string uniqueHiddenName()
Random generated unique hidden workspace name.
void removeFromGroup(const std::string &groupName, const std::string &wsName)
Remove a workspace from a group but not from the ADS.
Base Workspace Abstract Class.
Definition Workspace.h:29
DataService stores instances of a given type.
Definition DataService.h:57
virtual void add(const std::string &name, const std::shared_ptr< T > &Tobject)
Add an object to the service.
bool doesExist(const std::string &name) const
Check to see if a data object exists in the store.
void rename(const std::string &oldName, const std::string &newName)
Rename an object within the service.
std::vector< std::string > getObjectNames(DataServiceSort sortState=DataServiceSort::Unsorted, DataServiceHidden hiddenState=DataServiceHidden::Auto, const std::string &contain="") const
Returns a vector of strings containing all object names in the ADS.
std::shared_ptr< API::Workspace > retrieve(const std::string &name) const
Get a shared pointer to a stored data object.
virtual void addOrReplace(const std::string &name, const std::shared_ptr< T > &Tobject)
Add or replace an object to the service.
Poco::NotificationCenter notificationCenter
Sends notifications to observers.
void remove(const std::string &name)
Remove an object from the service.
Exception for when an item is not found in a collection.
Definition Exception.h:145
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Mantid::Kernel::SingletonHolder< AnalysisDataServiceImpl > AnalysisDataService
Helper class which provides the Collimation Length for SANS instruments.
std::string to_string(const wide_integer< Bits, Signed > &n)