COPASI API  4.16.103
CCopasiObject.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010 - 2014 by Pedro Mendes, Virginia Tech Intellectual
2 // Properties, Inc., University of Heidelberg, and The University
3 // of Manchester.
4 // All rights reserved.
5 
6 // Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
7 // Properties, Inc., EML Research, gGmbH, University of Heidelberg,
8 // and The University of Manchester.
9 // All rights reserved.
10 
11 // Copyright (C) 2002 - 2007 by Pedro Mendes, Virginia Tech Intellectual
12 // Properties, Inc. and EML Research, gGmbH.
13 // All rights reserved.
14 
15 /**
16  * Class CCopasiObject
17  *
18  * This class is the base class for all global accessible objects in COPASI.
19  *
20  * Copyright Stefan Hoops 2002
21  */
22 
23 #include <sstream>
24 #include <algorithm>
25 
26 #include "copasi/copasi.h"
34 #include "copasi/model/CModel.h"
38 
39 //static
41 
42 //static
43 CRenameHandler * CCopasiObject::smpRenameHandler = NULL;
44 
45 //static
47 
50  mObjectName("No Name"),
51  mObjectType("Unknown Type"),
52  mpObjectParent(NULL),
53  mpObjectDisplayName(NULL),
54  mObjectFlag(0),
55  mpUpdateMethod(&this->mDefaultUpdateMethod),
56  mpRefresh(NULL)
57 {}
58 
59 CCopasiObject::CCopasiObject(const std::string & name,
60  const CCopasiContainer * pParent,
61  const std::string & type,
62  const unsigned C_INT32 & flag):
64  mObjectName((name == "") ? "No Name" : name),
65  mObjectType(type),
66  mpObjectParent(const_cast<CCopasiContainer *>(pParent)),
67  mpObjectDisplayName(NULL),
68  mObjectFlag(flag),
69  mpUpdateMethod(&this->mDefaultUpdateMethod),
70  mpRefresh(NULL)
71 {
72  if (mpObjectParent != NULL)
74 }
75 
77  const CCopasiContainer * pParent):
79  mObjectName(src.mObjectName),
80  mObjectType(src.mObjectType),
81  mpObjectParent(const_cast<CCopasiContainer *>(pParent)),
82  mpObjectDisplayName(NULL),
83  mObjectFlag(src.mObjectFlag),
84  mpUpdateMethod(&this->mDefaultUpdateMethod),
85  mpRefresh(NULL)
86 {if (mpObjectParent != NULL) mpObjectParent->add(this);}
87 
89 {
90  if (mpObjectParent)
91  mpObjectParent->remove(this);
92 
94 
97 
99 }
100 
101 void CCopasiObject::print(std::ostream * ostream) const {(*ostream) << (*this);}
102 
104 {
106 
107  // if the object has a parent and if the object is not a datamodel,
108  // we add the name of the parent to the common name
109  if (isDataModel())
110  CN = (std::string) "CN=Root";
111  else if (mpObjectParent)
112  {
113  std::stringstream tmp;
114  tmp << mpObjectParent->getCN();
115 
117  tmp << "[" << CCopasiObjectName::escape(mObjectName) << "]";
118  else if (mpObjectParent->isVector())
119  tmp << "[" << static_cast<const CCopasiVector< CCopasiObject > *>(mpObjectParent)->getIndex(this) << "]";
120  else
123 
124  CN = tmp.str();
125  }
126  else
127  {
130  }
131 
132  return CN;
133 }
134 
135 const CObjectInterface *
137 {
138  if (cn == "")
139  {
140  return this;
141  }
142 
143  if (cn == "Property=DisplayName")
144  {
145  if (mpObjectDisplayName == NULL)
146  {
148  }
149 
151 
152  return mpObjectDisplayName;
153  }
154 
155  return NULL;
156 }
157 
158 bool CCopasiObject::setObjectName(const std::string & name)
159 {
160  std::string Name = (name == "") ? "No Name" : name;
161 
162  if (!isStaticString())
163  {
164  // We need to ensure that the name does not include any whitespace character except ' ' (space),
165  // i.e., we convert '\t' (tab), '\n' (newline) and '\r' (return) to ' ' (space).
166  std::string::iterator it = Name.begin();
167  std::string::iterator end = Name.end();
168 
169  for (; it != end; ++it)
170  {
171  switch (*it)
172  {
173  case '\t':
174  case '\n':
175  case '\r':
176  *it = ' ';
177  break;
178 
179  default:
180  break;
181  }
182  }
183  }
184 
185  if (Name == mObjectName) return true;
186 
187  if (mpObjectParent &&
190  return false;
191 
193  {
194  std::string oldCN = this->getCN();
195  mObjectName = Name;
196  std::string newCN = this->getCN();
197  smpRenameHandler->handle(oldCN, newCN);
198 
199  //TODO performance considerations.
200  //Right now after every rename the CNs are checked. In some cases
201  //we may know that this is not necessary
202  }
203  else
204  {mObjectName = Name;}
205 
206  if (mpObjectParent)
207  {
208  mpObjectParent->CCopasiContainer::remove(this);
209  mpObjectParent->CCopasiContainer::add(this, false);
210  }
211 
212  return true;
213 }
214 
215 /*virtual*/
216 std::string CCopasiObject::getObjectDisplayName(bool regular /*=true*/, bool richtext /*=false*/) const
217 {
218  std::string ret = "";
219 
220  if (mpObjectParent)
221  {
222  ret = mpObjectParent->getObjectDisplayName(regular, richtext);
223 
224  if (ret == "(CN)Root" ||
225  ret == "ModelList[]" ||
226  ret.substr(0, 7) == "(Model)")
227  {
228  ret = "";
229  }
230  }
231 
232  if (ret.length() >= 2)
233  if ((ret.substr(ret.length() - 2) == "[]") && (!isReference()))
234  {
235  ret.insert(ret.length() - 1, getObjectName());
236 
237  if (isNameVector() || isVector() || getObjectType() == "ParameterGroup")
238  ret += "[]";
239 
240  return ret;
241  }
242 
243  if ((ret.length() != 0) && (ret[ret.length() - 1] != '.'))
244  ret += ".";
245 
246  if (isNameVector() || isVector() || getObjectType() == "ParameterGroup")
247  ret += getObjectName() + "[]";
248  else if (isReference()
249  || getObjectType() == "Parameter"
250  || getObjectType() == getObjectName())
251  ret += getObjectName();
252  else
253  ret += "(" + getObjectType() + ")" + getObjectName();
254 
255  return ret;
256 }
257 
258 const std::string & CCopasiObject::getObjectName() const {return mObjectName;}
259 
260 const std::string & CCopasiObject::getObjectType() const {return mObjectType;}
261 
263 {
264  if (pParent == mpObjectParent)
265  return true;
266 
267  if (mpObjectParent != NULL &&
268  pParent != NULL)
269  mpObjectParent->remove(this);
270 
271  mpObjectParent = const_cast<CCopasiContainer *>(pParent);
272 
273  return true;
274 }
275 
277 
279 CCopasiObject::getObjectAncestor(const std::string & type) const
280 {
282 
283  while (p)
284  {
285  if (p->getObjectType() == type) return p;
286 
287  p = p->getObjectParent();
288  }
289 
290  return NULL;
291 }
292 
294 {
295  mDependencies.clear();
296 }
297 
299 {
300  mDependencies = directDependencies;
301 }
302 
305 {
306  return mDependencies;
307 }
308 
310 {
311  mDependencies.insert(pObject);
312  return;
313 }
314 
316 {
317  mDependencies.erase(pObject);
318  return;
319 }
320 
322 {
323  return * reinterpret_cast< const CObjectInterface::ObjectSet * >(&mDependencies);
324 }
325 
327  const CMath::SimulationContextFlag & /* context */,
328  const CObjectInterface::ObjectSet & changedObjects) const
329 {
330  // If the object is among the changed objects it does not depend on anything else.
331  if (changedObjects.find(this) != changedObjects.end())
332  return false;
333 
334 #ifdef COPASI_DEBUG
335  const CObjectInterface::ObjectSet & Prerequisites = getPrerequisites();
336 
337  // This method should only be called for objects which are prerequisites.
338  // We check for this only in debug mode.
339  assert(Prerequisites.find(pObject) != Prerequisites.end());
340 #endif // COPASI_DEBUG
341 
342  return true;
343 }
344 
346  const CCopasiObject::DataObjectSet & context) const
347 {
348  const CCopasiObject::DataObjectSet & DirectDependencies = getDirectDependencies(context);
349  CCopasiObject::DataObjectSet::const_iterator it = DirectDependencies.begin();
350  CCopasiObject::DataObjectSet::const_iterator end = DirectDependencies.end();
351 
352  std::pair<CCopasiObject::DataObjectSet::iterator, bool> Inserted;
353 
354  for (; it != end; ++it)
355  {
356  // Dual purpose insert
357  Inserted = dependencies.insert(*it);
358 
359  // The direct dependency *it was among the dependencies
360  // we assume also its dependencies have been added already.
361  if (!Inserted.second) continue;
362 
363  // Add all the dependencies of the direct dependency *it.
364  (*it)->getAllDependencies(dependencies, context);
365  }
366 }
367 
368 // virtual
370 {
371  bool MustBeDeleted = false;
372 
373  DataObjectSet::const_iterator it = mDependencies.begin();
374  DataObjectSet::const_iterator end = mDependencies.end();
375 
376  for (; it != end; ++it)
377  {
378  if (deletedObjects.find(*it) != deletedObjects.end())
379  {
380  MustBeDeleted = true;
381  break;
382  }
383  }
384 
385  return MustBeDeleted;
386 }
387 
389  const CCopasiObject::DataObjectSet & context) const
390 {
392  return hasCircularDependencies(candidates, verified, context);
393 }
394 
396  CCopasiObject::DataObjectSet & verified,
397  const CCopasiObject::DataObjectSet & context) const
398 {
399  bool hasCircularDependencies = false;
400 
401  if (verified.count(this) != 0)
402  return hasCircularDependencies;
403 
404  const CCopasiObject::DataObjectSet & DirectDependencies = getDirectDependencies(context);
405  CCopasiObject::DataObjectSet::const_iterator it = DirectDependencies.begin();
406  CCopasiObject::DataObjectSet::const_iterator end = DirectDependencies.end();
407 
408  std::pair<CCopasiObject::DataObjectSet::iterator, bool> Inserted;
409 
410  // Dual purpose insert
411  Inserted = candidates.insert(this);
412 
413  // Check whether the insert was successful, if not
414  // the object "this" was among the candidates. Thus we have a detected
415  // a circular dependency
416  if (Inserted.second)
417  {
418  for (; it != end && !hasCircularDependencies; ++it)
419  {
420  hasCircularDependencies = (*it)->hasCircularDependencies(candidates, verified, context);
421  }
422 
423  // Remove the inserted object this from the candidates to avoid any
424  // side effects.
425  candidates.erase(this);
426  }
427  else
428  hasCircularDependencies = true;
429 
430  // The element has been checked and does not need to be checked again.
431  verified.insert(this);
432 
434 }
435 
436 //static
437 std::vector< Refresh * >
439  const CCopasiObject::DataObjectSet & uptoDateObjects,
440  const CCopasiObject::DataObjectSet & context)
441 {
442  CCopasiObject::DataObjectSet DependencySet;
443  CCopasiObject::DataObjectSet VerifiedSet;
444 
445  CCopasiObject::DataObjectSet::const_iterator itSet;
446  CCopasiObject::DataObjectSet::const_iterator endSet = objects.end();
447  std::pair<CCopasiObject::DataObjectSet::iterator, bool> InsertedObject;
448 
449  assert(objects.count(NULL) == 0);
450 
451  // Check whether we have any circular dependencies
452  for (itSet = objects.begin(); itSet != endSet; ++itSet)
453  if ((*itSet)->hasCircularDependencies(DependencySet, VerifiedSet, context))
454  CCopasiMessage(CCopasiMessage::EXCEPTION, MCObject + 1, (*itSet)->getCN().c_str());
455 
456  // Build the complete set of dependencies
457  for (itSet = objects.begin(); itSet != endSet; ++itSet)
458  {
459  // At least the object itself needs to be up to date.
460  InsertedObject = DependencySet.insert(*itSet);
461 
462  // Add all its dependencies
463  if (InsertedObject.second)
464  (*itSet)->getAllDependencies(DependencySet, context);
465  }
466 
467  // Remove all objects which do not have any refresh method as they will
468  // be ignored anyway, i.e., no need to sort them.
469  for (itSet = DependencySet.begin(), endSet = DependencySet.end(); itSet != endSet;)
470  if ((*itSet)->getRefresh() == NULL ||
471  ((dynamic_cast< const CParticleReference * >(*itSet) != NULL ||
472  dynamic_cast< const CConcentrationReference * >(*itSet) != NULL) &&
473  (*itSet)->getDirectDependencies(context).size() == 0))
474  {
475  const CCopasiObject * pObject = *itSet;
476  ++itSet;
477  DependencySet.erase(pObject);
478  }
479  else
480  ++itSet;
481 
482  // Build the list of all up to date objects
483  CCopasiObject::DataObjectSet UpToDateSet;
484 
485  for (itSet = uptoDateObjects.begin(), endSet = uptoDateObjects.end(); itSet != endSet; ++itSet)
486  {
487  // At least the object itself is up to date.
488  InsertedObject = UpToDateSet.insert(*itSet);
489 
490  // Add all its dependencies too
491  if (InsertedObject.second)
492  (*itSet)->getAllDependencies(UpToDateSet, context);
493  }
494 
495  // Now remove all objects in the dependency set which are up to date
496  for (itSet = UpToDateSet.begin(), endSet = UpToDateSet.end(); itSet != endSet; ++itSet)
497  DependencySet.erase(*itSet);
498 
499  // Create a properly sorted list.
500  std::list< const CCopasiObject * > SortedList =
501  sortObjectsByDependency(DependencySet.begin(), DependencySet.end(), context);
502 
503  std::list< const CCopasiObject * >::iterator itList;
504  std::list< const CCopasiObject * >::iterator endList;
505 
506  // Build the vector of pointers to refresh methods
507  Refresh * pRefresh;
508 
509  std::vector< Refresh * > UpdateVector;
510  std::vector< Refresh * >::const_iterator itUpdate;
511  std::vector< Refresh * >::const_iterator endUpdate;
512 
513  itList = SortedList.begin();
514  endList = SortedList.end();
515 
516  for (; itList != endList; ++itList)
517  {
518  pRefresh = (*itList)->getRefresh();
519  itUpdate = UpdateVector.begin();
520  endUpdate = UpdateVector.end();
521 
522  while (itUpdate != endUpdate && !(*itUpdate)->isEqual(pRefresh)) ++itUpdate;
523 
524  if (itUpdate == endUpdate)
525  UpdateVector.push_back(pRefresh);
526  }
527 
528  return UpdateVector;
529 }
530 
531 #ifdef XXXX
532 // static
533 bool CCopasiObject::compare(const CCopasiObject * lhs, const CCopasiObject * rhs)
534 {
535  if (lhs != rhs)
536  {
537  CCopasiObject::DataObjectSet Candidates;
538  CCopasiObject::DataObjectSet VerifiedSet;
539 
540  Candidates.insert(lhs);
541 
542  if (rhs->hasCircularDependencies(Candidates, VerifiedSet))
543  return true;
544  }
545 
546  return false;
547 }
548 #endif
549 
551 {
552  return NULL;
553 }
554 
556 {
557  return NULL;
558 }
559 
561 {return (0 < (mObjectFlag & Container));}
562 
564 {return (0 < (mObjectFlag & Vector));}
565 
567 {return (0 < (mObjectFlag & Matrix));}
568 
570 {return (0 < (mObjectFlag & NameVector));}
571 
573 {return (0 < (mObjectFlag & Reference));}
574 
576 {return (0 < (mObjectFlag & ValueBool));}
577 
579 {return (0 < (mObjectFlag & ValueInt));}
580 
582 {return (0 < (mObjectFlag & ValueInt64));}
583 
585 {return (0 < (mObjectFlag & ValueDbl));}
586 
588 {return (0 < (mObjectFlag & NonUniqueName));}
589 
591 {return (0 < (mObjectFlag & StaticString));}
592 
594 {return (0 < (mObjectFlag & ValueString));}
595 
597 {return (0 < (mObjectFlag & Separator));}
598 
600 {return (0 < (mObjectFlag & Array));}
601 
603 {return (0 < (mObjectFlag & DataModel));}
604 
606 {return (0 < (mObjectFlag & Root));}
607 
608 const std::string & CCopasiObject::getKey() const
609 {
610  static std::string DefaultKey("");
611 
612  return DefaultKey;
613 }
614 
616 {(*mpUpdateMethod)(value);}
617 
619 {(*mpUpdateMethod)(value);}
620 
621 void CCopasiObject::setObjectValue(const bool & value)
622 {(*mpUpdateMethod)(value);}
623 
625 {return mpUpdateMethod;}
626 
629 
631 {pdelete(mpRefresh);}
632 
634 {return mpRefresh;}
635 
636 // virtual
637 std::string CCopasiObject::getUnits() const
638 {
639  if (mpObjectParent != NULL)
640  return mpObjectParent->getChildObjectUnits(this);
641 
642  return "";
643 }
644 
645 std::ostream &operator<<(std::ostream &os, const CCopasiObject & o)
646 {
647  os << "Name: " << o.getObjectDisplayName() << std::endl;
648  os << "Type: " << o.getObjectType() << std::endl;
649  os << "Container: " << o.isContainer() << std::endl;
650  os << "Vector: " << o.isVector() << std::endl;
651  os << "VectorN: " << o.isNameVector() << std::endl;
652  os << "Matrix: " << o.isMatrix() << std::endl;
653  os << "Reference: " << o.isReference() << std::endl;
654  os << "Bool: " << o.isValueBool() << std::endl;
655  os << "Int: " << o.isValueInt() << std::endl;
656  os << "Dbl: " << o.isValueDbl() << std::endl;
657 
658  return os;
659 }
660 
661 /**
662  * Returns a pointer to the CCopasiDataModel the element belongs to.
663  * If there is no instance of CCopasiDataModel in the ancestor tree, NULL
664  * is returned.
665  */
667 {
668  CCopasiObject * pObject = this;
669 
670  while (pObject != NULL)
671  {
672  if (pObject->isDataModel())
673  return static_cast<CCopasiDataModel *>(pObject);
674 
675  pObject = pObject->getObjectParent();
676  }
677 
678  return NULL;
679 }
680 
681 /**
682  * Returns a const pointer to the CCopasiDataModel the element belongs to.
683  * If there is no instance of CCopasiDataModel in the ancestor tree, NULL
684  * is returned.
685  */
687 {
688  const CCopasiObject * pObject = this;
689 
690  while (pObject != NULL)
691  {
692  if (pObject->isDataModel())
693  return static_cast<const CCopasiDataModel *>(pObject);
694 
695  pObject = pObject->getObjectParent();
696  }
697 
698  return NULL;
699 }
CCopasiDataModel * getObjectDataModel()
virtual bool setObjectParent(const CCopasiContainer *pParent)
virtual Refresh * getRefresh() const
bool isContainer() const
CCopasiContainer * getObjectAncestor(const std::string &type) const
bool isValueInt() const
bool isRoot() const
unsigned C_INT32 mObjectFlag
virtual std::string getObjectDisplayName(bool regular=true, bool richtext=false) const
void clearDirectDependencies()
CCopasiStaticString * mpObjectDisplayName
#define pdelete(p)
Definition: copasi.h:215
Header file of class CModelEntity and CModelValue.
UpdateMethod * getUpdateMethod() const
bool isNameVector() const
void setObjectValue(const C_FLOAT64 &value)
virtual CCopasiObjectName getCN() const
const std::string & getObjectName() const
virtual ~CCopasiObject()
virtual const CObjectInterface * getObject(const CCopasiObjectName &cn) const
virtual void handle(const std::string &oldCN, const std::string &newCN) const =0
bool hasCircularDependencies(DataObjectSet &candidates, DataObjectSet &verified, const DataObjectSet &context) const
static CRenameHandler * smpRenameHandler
bool isSeparator() const
void setDirectDependencies(const DataObjectSet &directDependencies)
bool isNonUniqueName() const
#define MCObject
UpdateMethod * mpUpdateMethod
const std::string & getObjectType() const
#define C_INT32
Definition: copasi.h:90
bool isMatrix() const
std::ostream & operator<<(std::ostream &os, const CCopasiObject &o)
static std::string escape(const std::string &name)
DataObjectSet mDependencies
std::string mObjectName
std::list< const CCopasiObject * > sortObjectsByDependency(ForwardAccessIterator begin, ForwardAccessIterator end, const CCopasiObject::DataObjectSet &context)
virtual const std::string & getKey() const
virtual std::string getChildObjectUnits(const CCopasiObject *pObject) const
void addDirectDependency(const CCopasiObject *pObject)
bool isReference() const
bool isDataModel() const
virtual const CObjectInterface::ObjectSet & getPrerequisites() const
static UpdateMethod mDefaultUpdateMethod
virtual bool remove(CCopasiObject *pObject)
Header file of class CCopasiContainer.
bool hasUpdateMethod() const
virtual bool mustBeDeleted(const DataObjectSet &deletedObjects) const
bool dependsOn(DataObjectSet candidates, const DataObjectSet &context=DataObjectSet()) const
long int flag
Definition: f2c.h:52
std::set< const CObjectInterface * > ObjectSet
virtual const DataObjectSet & getDirectDependencies(const DataObjectSet &context=DataObjectSet()) const
CCopasiContainer * mpObjectParent
virtual size_t getIndex(const CCopasiObject *pObject) const
virtual std::string getUnits() const
bool isValueString() const
#define C_FLOAT64
Definition: copasi.h:92
bool isValueBool() const
bool isValueInt64() const
std::string mObjectType
void removeDirectDependency(const CCopasiObject *pObject)
bool isVector() const
static std::vector< Refresh * > buildUpdateSequence(const DataObjectSet &objects, const DataObjectSet &uptoDateObjects, const DataObjectSet &context=DataObjectSet())
bool isArray() const
bool isValueDbl() const
virtual bool add(CCopasiObject *pObject, const bool &adopt=true)
virtual void * getValuePointer() const
bool isStaticString() const
void getAllDependencies(DataObjectSet &dependencies, const DataObjectSet &context) const
virtual const CObjectInterface * getObject(const CCopasiObjectName &cn) const
Refresh * mpRefresh
virtual const CCopasiObject * getValueObject() const
static const C_FLOAT64 DummyValue
bool setObjectName(const std::string &name)
std::set< const CCopasiObject * > DataObjectSet
virtual void print(std::ostream *ostream) const
CCopasiContainer * getObjectParent() const
virtual bool isPrerequisiteForContext(const CObjectInterface *pObject, const CMath::SimulationContextFlag &context, const CObjectInterface::ObjectSet &changedObjects) const