1 // -*- C++ -*-
2 /**
3 * @brief Study keeps all PersistentObjects in a file
4 *
5 * Copyright 2005-2021 Airbus-EDF-IMACS-ONERA-Phimeca
6 *
7 * This library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21 #include <algorithm>
22 #include "openturns/InterfaceObject.hxx"
23 #include "openturns/Study.hxx"
24 #include "openturns/StorageManager.hxx"
25 #if defined OPENTURNS_HAVE_LIBXML2
26 #include "openturns/XMLStorageManager.hxx"
27 #endif
28 #include "openturns/Exception.hxx"
29 #include "openturns/Catalog.hxx"
30 #include "openturns/PersistentObjectFactory.hxx"
31
32 BEGIN_NAMESPACE_OPENTURNS
33
34
35
CLASSNAMEINIT(Study)36 CLASSNAMEINIT(Study)
37
38 /*
39 * Default constructor
40 */
41 Study::Study()
42 : map_(),
43 labelMap_(),
44 p_storageManager_(new StorageManager)
45 {
46 p_storageManager_->setStudy(this);
47 }
48
49 /*
50 * Parameter constructor
51 */
Study(const FileName & fileName,const UnsignedInteger compressionLevel)52 Study::Study(const FileName & fileName,
53 const UnsignedInteger compressionLevel)
54 : map_(),
55 labelMap_(),
56 #if defined OPENTURNS_HAVE_LIBXML2
57 p_storageManager_(new XMLStorageManager(fileName, compressionLevel))
58 #else
59 p_storageManager_(new StorageManager)
60 #endif /* OPENTURNS_HAVE_LIBXML2 */
61 {
62 #if defined OPENTURNS_HAVE_LIBXML2
63 p_storageManager_->setStudy(this);
64 #else
65 (void)fileName;
66 (void)compressionLevel;
67 throw NotYetImplementedException(HERE) << "Error: no XML support for Study";
68 #endif /* OPENTURNS_HAVE_LIBXML2 */
69 }
70
71 /* String converter */
__repr__() const72 String Study::__repr__() const
73 {
74 OSS oss;
75 oss << "class=" << getClassName();
76
77 const char * separator = " ";
78 for(Map::const_iterator it = map_.begin();
79 it != map_.end();
80 ++it, separator = "\n ")
81 {
82 #if 0
83 oss << separator << (*it).first << " => " << ((*it).second)->getClassName()
84 << " name='" << ((*it).second)->getName()
85 << "' id=" << ((*it).second)->getId();
86 #endif
87 #if 0
88 if (((*it).second)->getVisibility())
89 oss << separator << (*it).first << " => id=" << ((*it).second)->getId()
90 << " " << ((*it).second)->__repr__();
91 #endif
92 #if 1
93 oss << separator << (*it).first << " => " << (((*it).second)->getVisibility() ? "*" : " ") << " id=" << ((*it).second)->getId()
94 << " " << ((*it).second)->__repr__();
95 #endif
96 }
97
98 oss << "\n";
99 separator = " ";
100 for(LabelMap::const_iterator it = labelMap_.begin();
101 it != labelMap_.end();
102 ++it, separator = "\n ")
103 {
104 oss << separator << "'" << (*it).first << "' is aliased to " << (*it).second;
105 }
106 return oss;
107 }
108
109 /* String converter */
__str__(const String &) const110 String Study::__str__(const String & ) const
111 {
112 OSS oss(false);
113 const char * separator = " ";
114 for(Map::const_iterator it = map_.begin(); it != map_.end(); ++it, separator = "\n ")
115 {
116 oss << separator << (*it).first << " => " << ((*it).second)->getClassName() << "\n"
117 << ((*it).second)->__str__( String( 7 + int( ((*it).first != 0 ? log10(static_cast<double>((*it).first)) : 1) ), ' ') );
118 }
119 oss << "\n";
120 separator = " ";
121 for(LabelMap::const_iterator it = labelMap_.begin();
122 it != labelMap_.end();
123 ++it, separator = "\n ")
124 {
125 oss << separator << "'" << (*it).first << "' is aliased to " << (*it).second;
126 }
127 return oss;
128 }
129
130 /* This method saves the study through the storage manager */
save()131 void Study::save()
132 {
133 assert(p_storageManager_);
134 StorageManager & mgr = *p_storageManager_;
135
136 mgr.initialize( SaveAction() );
137
138 for(LabelMap::const_iterator it = labelMap_.begin();
139 it != labelMap_.end(); ++it)
140 {
141 mgr.save(*map_[ it->second ], it->first, true);
142 }
143
144 for(Map::const_iterator it = map_.begin();
145 it != map_.end(); ++it)
146 {
147 mgr.save(*(it->second), "", true);
148 }
149
150 mgr.write();
151 mgr.finalize( SaveAction() );
152 }
153
154 /* This method reloads the study from the storage manager */
load()155 void Study::load()
156 {
157 assert(p_storageManager_);
158 StorageManager & mgr = *p_storageManager_;
159
160 mgr.initialize( LoadAction() );
161 mgr.read();
162 mgr.load(*this);
163 mgr.finalize( LoadAction() );
164
165 cleanUnvisibleObject();
166 translateId();
167 }
168
169 /* This method purges the study from the reloaded objects that are tagged unvisible */
cleanUnvisibleObject()170 void Study::cleanUnvisibleObject()
171 {
172 Map newMap;
173 for(Map::const_iterator it = map_.begin(); it != map_.end(); ++it)
174 {
175 if (it->second->getVisibility())
176 newMap[ it->second->getShadowedId() ] = it->second;
177 }
178 map_ = newMap;
179 }
180
181 /* This method performs the translation of ids after a study load */
translateId()182 void Study::translateId()
183 {
184 std::map<Id, Id> translationTable;
185
186 Map newMap;
187 for(Map::const_iterator it = map_.begin(); it != map_.end(); ++it)
188 {
189 translationTable[ it->first ] = it->second->getId();
190 newMap[ it->second->getId() ] = it->second;
191 }
192
193 LabelMap newLabelMap;
194 for(LabelMap::const_iterator it = labelMap_.begin(); it != labelMap_.end(); ++it)
195 newLabelMap[ it->first ] = translationTable[ it->second ];
196
197 map_ = newMap;
198 labelMap_ = newLabelMap;
199 }
200
201
202
203
204
205
206 /* Query if object is stored in study */
hasObject(Id id) const207 Bool Study::hasObject(Id id) const
208 {
209 Map::const_iterator it = map_.find( id );
210 return ( it != map_.end() );
211 }
212
213 /* Get object whose id is given */
getObject(Id id) const214 Study::MapElement Study::getObject(Id id) const
215 {
216 MapElement element;
217 Map::const_iterator it = map_.find( id );
218 if (it != map_.end())
219 {
220 element = (*it).second;
221 }
222 return element;
223 }
224
225
226
227
228 /* Query if object is stored in study */
hasObject(const String & label) const229 Bool Study::hasObject(const String & label) const
230 {
231 if (label.empty()) return false;
232 LabelMap::const_iterator it = labelMap_.find( label );
233 return (it == labelMap_.end()) ? false : hasObject( it->second );
234 }
235
236 /* Get object whose id is given */
getObject(const String & label) const237 Study::MapElement Study::getObject(const String & label) const
238 {
239 LabelMap::const_iterator it_label = labelMap_.find( label );
240 if (it_label == labelMap_.end()) throw InvalidArgumentException(HERE) << "No object with label '" << label << "' in study";
241 return getObject( it_label->second );
242 }
243
244
245
246
247
248 /* Local class for the following method. Should have been declared inside the method but find_if crashes */
249 struct element_whose_class_and_name_are
250 {
251 const String & className_;
252 const String & name_;
element_whose_class_and_name_areelement_whose_class_and_name_are253 element_whose_class_and_name_are(const String & className, const String & name) : className_(className), name_(name) {}
operator ()element_whose_class_and_name_are254 Bool operator()(const Study::Map::value_type & element) const
255 {
256 return (element.second->getClassName() == className_) && (element.second->getName() == name_);
257 }
258 };
259
260 /* Get object whose class and name are given */
getObjectByName(const String & className,const String & name) const261 Study::MapElement Study::getObjectByName(const String & className, const String & name) const
262 {
263 MapElement element;
264 Map::const_iterator it = std::find_if(map_.begin(), map_.end(), element_whose_class_and_name_are(className, name));
265 if (it != map_.end())
266 {
267 element = (*it).second;
268 }
269 return element;
270 }
271
272
273 /* Fill an object with one got from study */
fillObjectByName(PersistentObject & po,const String & name) const274 void Study::fillObjectByName(PersistentObject & po, const String & name) const
275 {
276 MapElement element = getObjectByName(po.getClassName(), name);
277 if (! element) throw InvalidArgumentException(HERE) << "No object of name " << name << " in study";
278 Catalog::Get(po.getClassName()).assign(po, *element);
279 }
280
fillObjectByName(InterfaceObject & io,const String & name) const281 void Study::fillObjectByName(InterfaceObject & io, const String & name) const
282 {
283 MapElement element = getObjectByName(io.getImplementationAsPersistentObject()->getClassName(), name);
284 if (! element) throw InvalidArgumentException(HERE) << "No object of name " << name << " in study";
285 io.setImplementationAsPersistentObject(element);
286 }
287
fillObject(Id id,PersistentObject & po) const288 void Study::fillObject(Id id, PersistentObject & po) const
289 {
290 MapElement element = getObject(id);
291 if (! element) throw InvalidArgumentException(HERE) << "No object of id " << id << " in study";
292 Catalog::Get(po.getClassName()).assign(po, *element);
293 }
294
fillObject(Id id,InterfaceObject & io) const295 void Study::fillObject(Id id, InterfaceObject & io) const
296 {
297 MapElement element = getObject(id);
298 if (! element) throw InvalidArgumentException(HERE) << "No object of id " << id << " in study";
299 io.setImplementationAsPersistentObject(element);
300 }
301
fillObject(const String & label,PersistentObject & po) const302 void Study::fillObject(const String & label, PersistentObject & po) const
303 {
304 MapElement element = getObject(label);
305 if (! element) throw InvalidArgumentException(HERE) << "No object labelled '" << label << "' in study";
306 Catalog::Get(po.getClassName()).assign(po, *element);
307 }
308
fillObject(const String & label,InterfaceObject & io) const309 void Study::fillObject(const String & label, InterfaceObject & io) const
310 {
311 MapElement element = getObject(label);
312 if (! element) throw InvalidArgumentException(HERE) << "No object labelled '" << label << "' in study";
313 io.setImplementationAsPersistentObject(element);
314 }
315
316
317 /* Storage manager accessor */
setStorageManager(const StorageManager & smgr)318 void Study::setStorageManager(const StorageManager & smgr)
319 {
320 p_storageManager_.reset(smgr.clone());
321 p_storageManager_->setStudy(this);
322 }
323
324 /* Storage manager accessor */
getStorageManager() const325 Study::StorageManagerImplementation Study::getStorageManager() const
326 {
327 return p_storageManager_;
328 }
329
330 /* Define a label for an object */
defineLabel(Id id,const String & label)331 void Study::defineLabel(Id id, const String & label)
332 {
333 if (! label.empty()) labelMap_[ label ] = id;
334 }
335
336
337 /* Define the visibility of an object */
defineVisibility(Id id,Bool visible)338 void Study::defineVisibility(Id id, Bool visible)
339 {
340 MapElement elt = getObject( id );
341 elt->setVisibility( visible );
342 }
343
344 /* Add a PersistentObject to the study */
add(const InterfaceObject & io)345 void Study::add(const InterfaceObject & io)
346 {
347 map_[ io.getId() ] = io.getImplementationAsPersistentObject();
348 }
349
350 /* Add a PersistentObject to the study */
add(const String & label,const InterfaceObject & io,Bool force)351 void Study::add(const String & label, const InterfaceObject & io, Bool force)
352 {
353 if ( hasObject( label ) )
354 {
355 if (force) remove( label );
356 else throw InvalidArgumentException(HERE) << "Label '" << label << "' already defined in study. Use 'force = true' to remove previously saved element before saving this one";
357 }
358 map_[ io.getId() ] = io.getImplementationAsPersistentObject();
359 defineLabel( io.getId(), label );
360 }
361
362 /* Remove a PersistentObject from the study */
remove(const InterfaceObject & io)363 void Study::remove(const InterfaceObject & io)
364 {
365 Map::iterator it = map_.find( io.getId() );
366 map_.erase(it);
367 }
368
369 /* Remove a PersistentObject from the study */
remove(const String & label)370 void Study::remove(const String & label)
371 {
372 LabelMap::iterator it_label = labelMap_.find( label );
373 if (it_label == labelMap_.end()) throw InvalidArgumentException(HERE) << "No object with label '" << label << "' in study";
374 Map::iterator it_obj = map_.find( it_label->second );
375 map_.erase(it_obj);
376 labelMap_.erase( it_label );
377 }
378
379 /* Add a PersistentObject to the study */
add(const PersistentObject & po)380 void Study::add(const PersistentObject & po)
381 {
382 add(po.clone());
383 }
384
385 /* Add a PersistentObject to the study */
add(const String & label,const PersistentObject & po,Bool force)386 void Study::add(const String & label, const PersistentObject & po, Bool force)
387 {
388 add(label, po.clone(), force);
389 }
390
391 /* Add a PersistentObject to the study (any map) */
add(const PersistentObject * po)392 void Study::add(const PersistentObject * po)
393 {
394 if (! po) throw InvalidArgumentException(HERE) << "Null pointer passed to method";
395 map_[ po->getShadowedId() ] = const_cast<PersistentObject *>(po);
396 }
397
398 /* Add a PersistentObject to the study (any map) */
add(const String & label,const PersistentObject * po,Bool force)399 void Study::add(const String & label, const PersistentObject * po, Bool force)
400 {
401 if (! po) throw InvalidArgumentException(HERE) << "Null pointer passed to method";
402 if ( hasObject( label ) )
403 {
404 if (force) remove( label );
405 else throw InvalidArgumentException(HERE) << "Label '" << label << "' already defined in study. Use 'force = true' to remove previously saved element before saving this one";
406 }
407 map_[ po->getShadowedId() ] = const_cast<PersistentObject *>(po);
408 defineLabel( po->getShadowedId(), label );
409 }
410
411 /* Print all the labels in the study */
printLabels() const412 String Study::printLabels() const
413 {
414 OSS oss;
415 String separator("");
416 for(LabelMap::const_iterator it = labelMap_.begin(); it != labelMap_.end(); ++it, separator = ";") oss << separator << (*it).first;
417 return oss;
418 }
419
420 END_NAMESPACE_OPENTURNS
421