COPASI API  4.16.103
CFunctionAnalyzer.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010 - 2013 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) 2007 by Pedro Mendes, Virginia Tech Intellectual
12 // Properties, Inc. and EML Research, gGmbH.
13 // All rights reserved.
14 
15 #include <sstream>
16 
17 #include "CFunctionAnalyzer.h"
18 
19 #include "CEvaluationNode.h"
20 //#include "CEvaluationNodeOperator.h"
21 #include "CFunction.h"
22 #include "model/CModel.h"
23 #include "report/CKeyFactory.h"
26 
27 #ifdef WIN32
28 // we can't call this truncate because truncate
29 // is the name of a system function under linux
30 // and probably mac os x
31 double trunc(double x)
32 {return (x < 0.0) ? -floor(fabs(x)) : floor(x);}
33 #endif
34 
35 //this define specifies whether debug output is written to std::cout
36 //#define C_DBG_FA
37 
38 std::ostream & operator<<(std::ostream &os, const CFunctionAnalyzer::CValue & v)
39 {
40  os << "{";
41 
42  if (v.mStatus & CFunctionAnalyzer::CValue::negative) os << "- ";
43 
44  if (v.mStatus & CFunctionAnalyzer::CValue::zero) os << "0 ";
45 
46  if (v.mStatus & CFunctionAnalyzer::CValue::positive) os << "+ ";
47 
48  if (v.mStatus & CFunctionAnalyzer::CValue::invalid) os << "E ";
49 
50  if (v.mStatus & CFunctionAnalyzer::CValue::known) os << "v" << v.mDouble << " ";
51 
52  os << "}";
53 
54  return os;
55 }
56 
58 {
59  CValue ret;
60 
61  //invalid
62  if ((this->getStatus() & invalid) || (rhs.getStatus() & invalid))
63  ret.Or(invalid);
64 
65  const CValue* v1, *v2;
66  v1 = this; v2 = &rhs;
67 
68  if ((v1->mStatus & negative) && (v2->mStatus & negative)) ret.Or(positive);
69 
70  if ((v1->mStatus & negative) && (v2->mStatus & zero)) ret.Or(zero);
71 
72  if ((v1->mStatus & negative) && (v2->mStatus & positive)) ret.Or(negative);
73 
74  if ((v1->mStatus & zero) && (v2->mStatus & negative)) ret.Or(zero);
75 
76  if ((v1->mStatus & zero) && (v2->mStatus & zero)) ret.Or(zero);
77 
78  if ((v1->mStatus & zero) && (v2->mStatus & positive)) ret.Or(zero);
79 
80  if ((v1->mStatus & positive) && (v2->mStatus & negative)) ret.Or(negative);
81 
82  if ((v1->mStatus & positive) && (v2->mStatus & zero)) ret.Or(zero);
83 
84  if ((v1->mStatus & positive) && (v2->mStatus & positive)) ret.Or(positive);
85 
86  //known values
87  if ((this->mStatus & known) && (rhs.mStatus & known))
88  ret.orValue(this->mDouble * rhs.mDouble);
89  else if (this->mStatus & known)
90  ret.Or(generalize(this->mDouble) * rhs);
91  else if (rhs.mStatus & known)
92  ret.Or(*this * generalize(rhs.mDouble));
93 
94 #ifdef C_DBG_FA
95  std::cout << " *: " << *this << " * " << rhs << " = " << ret << std::endl;
96 #endif
97 
98  return ret;
99 }
100 
102 {
103  CValue ret;
104 
105  //invalid
106  if ((this->getStatus() & invalid) || (rhs.getStatus() & invalid))
107  ret.Or(invalid);
108 
109  if (rhs.getStatus() & zero)
110  ret.Or(invalid);
111 
112  const CValue* v1, *v2;
113  v1 = this; v2 = &rhs;
114 
115  if ((v1->mStatus & negative) && (v2->mStatus & negative)) ret.Or(positive);
116 
117  if ((v1->mStatus & negative) && (v2->mStatus & positive)) ret.Or(negative);
118 
119  if ((v1->mStatus & zero) && (v2->mStatus & negative)) ret.Or(zero);
120 
121  if ((v1->mStatus & zero) && (v2->mStatus & positive)) ret.Or(zero);
122 
123  if ((v1->mStatus & positive) && (v2->mStatus & negative)) ret.Or(negative);
124 
125  if ((v1->mStatus & positive) && (v2->mStatus & positive)) ret.Or(positive);
126 
127  //known values
128  if ((this->mStatus & known) && (rhs.mStatus & known))
129  ret.orValue(this->mDouble / rhs.mDouble);
130  else if (this->mStatus & known)
131  ret.Or(generalize(this->mDouble) / rhs);
132  else if (rhs.mStatus & known)
133  ret.Or(*this / generalize(rhs.mDouble));
134 
135 #ifdef C_DBG_FA
136  std::cout << " /: " << *this << " / " << rhs << " = " << ret << std::endl;
137 #endif
138 
139  return ret;
140 }
141 
143 {
144  CValue ret;
145 
146  //invalid
147  if ((this->getStatus() & invalid) || (rhs.getStatus() & invalid))
148  ret.Or(invalid);
149 
150  //zero
151  if (this->getStatus() & zero)
152  ret.Or(rhs);
153 
154  if (rhs.getStatus() & zero)
155  ret.Or(*this);
156 
157  //symmetry
158  const CValue* v1, *v2;
159  v1 = this; v2 = &rhs;
160 
161  if ((v1->mStatus & negative) && (v2->mStatus & negative)) ret.Or(negative);
162 
163  if ((v1->mStatus & negative) && (v2->mStatus & positive)) ret.Or(negative | zero | positive);
164 
165  if ((v1->mStatus & positive) && (v2->mStatus & negative)) ret.Or(negative | zero | positive);
166 
167  if ((v1->mStatus & positive) && (v2->mStatus & positive)) ret.Or(positive);
168 
169  //known values
170  if ((this->mStatus & known) && (rhs.mStatus & known)) ret.orValue(this->mDouble + rhs.mDouble);
171 
172  if ((this->mStatus & negative) && (rhs.mStatus & known)) ret.Or(*this + generalize(rhs.mDouble));
173 
174  if ((this->mStatus & positive) && (rhs.mStatus & known)) ret.Or(*this + generalize(rhs.mDouble));
175 
176  if ((this->mStatus & known) && (rhs.mStatus & negative)) ret.Or(generalize(this->mDouble) + rhs);
177 
178  if ((this->mStatus & known) && (rhs.mStatus & positive)) ret.Or(generalize(this->mDouble) + rhs);
179 
180 #ifdef C_DBG_FA
181  std::cout << " +: " << *this << " + " << rhs << " = " << ret << std::endl;
182 #endif
183 
184  return ret;
185 }
186 
188 {
189  CValue ret;
190  ret.mStatus = Status(this->mStatus & (zero | invalid | known));
191 
192  if (this->mStatus & known) ret.mDouble = -this->mDouble;
193 
194  if (this->mStatus & positive) ret.Or(negative);
195 
196  if (this->mStatus & negative) ret.Or(positive);
197 
198  return ret;
199 }
200 
202 {
203  return *this + rhs.invert();
204 }
205 
207 {
208  CValue ret;
209 
210  //invalid
211  if ((this->getStatus() & invalid) || (rhs.getStatus() & invalid))
212  ret.Or(invalid);
213 
214  const CValue* v1, *v2;
215  v1 = this; v2 = &rhs;
216 
217  if ((v1->mStatus & negative) && (v2->mStatus & negative)) ret.Or(negative | positive | invalid);
218 
219  if ((v1->mStatus & negative) && (v2->mStatus & zero)) ret.orValue(1.0);
220 
221  if ((v1->mStatus & negative) && (v2->mStatus & positive)) ret.Or(negative | positive | invalid);
222 
223  if ((v1->mStatus & zero) && (v2->mStatus & negative)) ret.Or(invalid);
224 
225  if ((v1->mStatus & zero) && (v2->mStatus & zero)) ret.Or(invalid);
226 
227  if ((v1->mStatus & zero) && (v2->mStatus & positive)) ret.Or(zero);
228 
229  if ((v1->mStatus & positive) && (v2->mStatus & negative)) ret.Or(positive);
230 
231  if ((v1->mStatus & positive) && (v2->mStatus & zero)) ret.orValue(1.0);
232 
233  if ((v1->mStatus & positive) && (v2->mStatus & positive)) ret.Or(positive);
234 
235  //known values
236 
237  //base and exponent are known
238  if ((this->mStatus & known) && (rhs.mStatus & known)) ret.orValue(pow(this->mDouble, rhs.mDouble));
239 
240  //base is known
241  if ((this->mStatus & known) && ((rhs.mStatus & negative)
242  || (rhs.mStatus & zero)
243  || (rhs.mStatus & positive)))
244  {
245  if (this->mDouble == 1.0) // base is 1
246  ret.orValue(1.0);
247  else
248  ret.Or(generalize(this->mDouble) ^ rhs);
249  }
250 
251  //exponent is known
252  if (((this->mStatus & negative)
253  || (this->mStatus & zero)
254  || (this->mStatus & positive)) && (rhs.mStatus & known))
255  {
256  if ((rhs.mDouble == trunc(rhs.mDouble)) && (rhs.mDouble != 0.0)) //exponent is integer but not 0
257  {
258  if (rhs.mDouble / 2.0 == trunc(rhs.mDouble / 2.0)) //exponent is even
259  {
260  if (this->mStatus & negative) ret.Or(positive);
261 
262  if (this->mStatus & zero) ret.Or(zero);
263 
264  if (this->mStatus & positive) ret.Or(positive);
265  }
266  else //uneven
267  {
268  if (this->mStatus & negative) ret.Or(negative);
269 
270  if (this->mStatus & zero) ret.Or(zero);
271 
272  if (this->mStatus & positive) ret.Or(positive);
273  }
274  }
275  else
276  ret.Or(*this ^ generalize(rhs.mDouble));
277  }
278 
279 #ifdef C_DBG_FA
280  std::cout << " ^: " << *this << " ^ " << rhs << " = " << ret << std::endl;
281 #endif
282 
283  return ret;
284 }
285 
286 // CFunctionAnalyzer::CValue CFunctionAnalyzer::CValue::generalize() const
287 // {
288 // if (mStatus==known)
289 // {
290 // if (mDouble==0.0) return zero;
291 // if (mDouble>0.0) return positive;
292 // if (mDouble<0.0) return negative;
293 // return invalid;
294 //}
295 // else
296 // return *this;
297 //}
298 
299 //static
301 {
302  if (d == 0.0) return zero;
303  else if (d > 0.0) return positive;
304  else if (d < 0.0) return negative;
305  else return invalid;
306 }
307 
308 void CFunctionAnalyzer::CValue::Or(const CValue & v) // {mStatus = Status(mStatus | s);};
309 {
310  if ((this->mStatus & known) && (v.mStatus & known) && (this->mDouble != v.mDouble))
311  {
312  //the two CValues have different known values
313  CValue tmp = generalize(this->mDouble);
314  tmp.Or(generalize(v.mDouble));
315  *this = tmp;
316  return;
317  }
318 
319  Or(v.mStatus);
320 
321  if (v.mStatus & known) this->mDouble = v.mDouble;
322 }
323 
325 {
326  if (mStatus == positive) return true;
327 
328  if ((mStatus == known) && (mDouble > 0.0)) return true;
329 
330  return false;
331 }
332 
334 {
335  if (mStatus & positive) return true;
336 
337  if ((mStatus & known) && (mDouble > 0.0)) return true;
338 
339  return false;
340 }
341 
343 {
344  if (mStatus == zero) return true;
345 
346  if ((mStatus == known) && (mDouble == 0.0)) return true;
347 
348  return false;
349 }
350 
352 {
353  if (mStatus & zero) return true;
354 
355  if ((mStatus & known) && (mDouble == 0.0)) return true;
356 
357  return false;
358 }
359 
361 {
362  if (mStatus == negative) return true;
363 
364  if ((mStatus == known) && (mDouble < 0.0)) return true;
365 
366  return false;
367 }
368 
370 {
371  if (mStatus & negative) return true;
372 
373  if ((mStatus & known) && (mDouble < 0.0)) return true;
374 
375  return false;
376 }
377 
379 {
380  if (mStatus == invalid) return true;
381 
382  return false;
383 }
384 
386 {
387  if (mStatus & invalid) return true;
388 
389  return false;
390 }
391 
393 {
394  if (mStatus != rhs.mStatus) return false;
395 
396  if ((mStatus & known) && (mDouble != rhs.mDouble)) return false;
397 
398  return true;
399 }
400 
401 //***********************************************************************************************
402 
404  : mpFunction(NULL),
405  mIrreversibleKineticsWithProducts(false),
406  mReversibleNonSplitable(false)
407 {};
408 
409 bool CFunctionAnalyzer::Result::writeResult(std::ostream & os, bool rt, bool verbose) const
410 {
411  bool ret = false;
412 
413  if (!mpFunction) return false;
414 
415  //function name
416  if (rt) os << "<h3>";
417 
418  os << mpFunction->getObjectName();
419 
420  if (rt) os << "</h3>";
421 
422  os << "\n";
423 
424  if (mIrreversibleKineticsWithProducts)
425  {
426  os << write(1, rt, "The kinetic function is marked as irreversible but at least one of its variables is labeled as product.\n", "");
427  ret = true;
428  }
429 
430  //interpret the CValues
431  bool isReversible = (mpFunction->isReversible() == TriTrue);
432 
433  std::ostringstream tmpss;
434 
435  //only interprete the results if the kinetic law has specified reversibility.
436  bool eee = true;
437  if (mpFunction->isReversible() != TriUnspecified)
438  eee = mOriginalFunction.writeAnalysis(tmpss, rt, isReversible);
439 
440  if (eee) ret = true;
441 
442  if (eee || verbose)
443  {
444  os << tmpss.str();
445  mOriginalFunction.writeTable(os, rt);
446  }
447 
448  //deal with splitted reversible functions
449  if (mReversibleNonSplitable)
450  {
451  os << write(1, rt, "Copasi is not able to split the reversible kinetic function into two irreversible functions.\n", "");
452  ret = true;
453  }
454  else if (isReversible)
455  {
456  std::ostringstream tmpss1;
457  bool eee1 = mFPart.writeAnalysis(tmpss1, rt, false);
458 
459  std::ostringstream tmpss2;
460  bool eee2 = mBPart.writeAnalysis(tmpss2, rt, false);
461 
462  if (eee1 || eee2) ret = true;
463 
464  if (eee1 || eee2 || verbose)
465  {
466  os << "The function was split into forward and backwards parts. Forward part:\n";
467 
468  if (rt) os << "<br>";
469 
470  os << tmpss1.str();
471  mFPart.writeTable(os, rt);
472  os << " Backwards part:\n";
473 
474  if (rt) os << "<br>";
475 
476  os << tmpss2.str();
477  mBPart.writeTable(os, rt);
478  }
479  }
480 
481  return ret;
482 }
483 
484 bool CFunctionAnalyzer::Result::FunctionInformation::writeAnalysis(std::ostream & os, bool rt, bool reversible /*const CFunction * pF*/) const
485 {
486  bool ret = false;
487 
488  if (reversible) //reversible function
489  {
490  //unchanged values
491  assert(mUnchangedParameters.size() >= 2);
492 
493  //first for positive parameter values
494  if (!mUnchangedParameters[1].containsPositive())
495  {
496  os << write(1, rt, "The kinetic function cannot take positive values for positive parameter values.\n",
497  "This means the reaction will never proceed in the forward direction.");
498  ret = true;
499  }
500 
501  if (!mUnchangedParameters[1].containsZero())
502  {
503  os << write(1, rt, "The kinetic function never equals zero for positive parameter values.\n",
504  "This is unexpected for reversible reactions.");
505  ret = true;
506  }
507 
508  if (!mUnchangedParameters[1].containsNegative())
509  {
510  os << write(1, rt, "The kinetic function cannot take negative values for positive parameter values.\n",
511  "This means the reaction will never proceed in the backwards direction.");
512  ret = true;
513  }
514 
515  if (mUnchangedParameters[1].isInvalid())
516  {
517  os << write(2, rt, "The kinetic function is always invalid for positive parameter values.\n", "");
518  ret = true;
519  }
520  else if (mUnchangedParameters[1].containsInvalid())
521  {
522  os << write(1, rt, "The kinetic function can be invalid even if metabolite concentrations and parameter values are positive.\n", "");
523  ret = true;
524  }
525 
526  //now report if the result is different for the actual parameters values
527  if ((mUnchangedParameters.size() > 2) && (!(mUnchangedParameters[1] == mUnchangedParameters[2])))
528  {
529  if (!mUnchangedParameters[2].containsPositive())
530  {
531  os << write(1, rt, "The kinetic function cannot take positive values for the actual parameter values.\n",
532  "This means the reaction will never proceed in the forward direction.");
533  ret = true;
534  }
535 
536  if (!mUnchangedParameters[2].containsZero())
537  {
538  os << write(1, rt, "The kinetic function never equals zero for the actual parameter values.\n",
539  "This is unexpected for reversible reactions.");
540  ret = true;
541  }
542 
543  if (!mUnchangedParameters[2].containsNegative())
544  {
545  os << write(1, rt, "The kinetic function cannot take negative values for the actual parameter values.\n",
546  "This means the reaction will never proceed in the backwards direction.");
547  ret = true;
548  }
549 
550  if (mUnchangedParameters[2].isInvalid())
551  {
552  os << write(2, rt, "The kinetic function is always invalid for the actual parameter values.\n", "");
553  ret = true;
554  }
555  else if (mUnchangedParameters[2].containsInvalid())
556  {
557  os << write(1, rt, "The kinetic function can be invalid for the actual parameter values even if metabolite concentrations are positive.\n", "");
558  ret = true;
559  }
560  }
561 
562  size_t i, imax;
563 
564  // Substrate concentrations set to zero
565  imax = mSubstrateZero.size();
566 
567  for (i = 0; i < imax; ++i)
568  {
569  assert(mSubstrateZero[i].second.size() >= 2);
570 
571  //first for positive parameter values
572  if (mSubstrateZero[i].second[1].isNegative())
573  {
574  os << write(0, rt, "The kinetic function is always negative for positive parameter values if substrate \""
575  + mSubstrateZero[i].first.second // pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
576  + "\" is set to zero.\n" ,
577  "This is the expected behaviour for reversible reactions. Without substrates the reaction can only proceed backwards.");
578  }
579  else if (mSubstrateZero[i].second[1].containsNegative())
580  {
581  os << write(1, rt, "Copasi could not show that the kinetic function is always negative for positive parameter values if substrate \""
582  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
583  + "\" is set to zero.\n" , "");
584  ret = true;
585  }
586  else
587  {
588  os << write(2, rt, "The kinetic function is never negative for positive parameter values if substrate \""
589  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
590  + "\" is set to zero.\n" ,
591  "This means the reaction never proceeds backwards even if no substrate is present. This is unexpected for a reversible reaction.");
592  ret = true;
593  }
594 
595  if (mSubstrateZero[i].second[1].isInvalid())
596  {
597  os << write(2, rt, "The kinetic function is always invalid for positive parameter values if substrate \""
598  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
599  + "\" is set to zero.\n" , "");
600  ret = true;
601  }
602  else if (mSubstrateZero[i].second[1].containsInvalid())
603  {
604  os << write(1, rt, "The kinetic function can be invalid for positive parameter values if substrate \""
605  + mSubstrateZero[i].first.second // pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
606  + "\" is set to zero.\n" , "");
607  ret = true;
608  }
609 
610  //now report if the result is different for the actual parameters values
611  if ((mSubstrateZero[i].second.size() > 2) && (!(mSubstrateZero[i].second[1] == mSubstrateZero[i].second[2])))
612  {
613  if (mSubstrateZero[i].second[2].isNegative())
614  {
615  os << write(0, rt, "The kinetic function is always negative for the actual parameter values if substrate \""
616  + mSubstrateZero[i].first.second // pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
617  + "\" is set to zero.\n" ,
618  "This is the expected behaviour for reversible reactions. Without substrates the reaction can only proceed backwards.");
619  }
620  else if (mSubstrateZero[i].second[2].containsNegative())
621  {
622  os << write(1, rt, "Copasi could not show that the kinetic function is always negative for the actual parameter values if substrate \""
623  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
624  + "\" is set to zero.\n" , "");
625  ret = true;
626  }
627  else
628  {
629  os << write(2, rt, "The kinetic function is never negative for the actual parameter values if substrate \""
630  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
631  + "\" is set to zero.\n" ,
632  "This means the reaction never proceeds backwards even if no substrate is present. This is unexpected for a reversible reaction.");
633  ret = true;
634  }
635 
636  if (mSubstrateZero[i].second[2].isInvalid())
637  {
638  os << write(2, rt, "The kinetic function is always invalid for the actual parameter values if substrate \""
639  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
640  + "\" is set to zero.\n" , "");
641  ret = true;
642  }
643  else if (mSubstrateZero[i].second[2].containsInvalid())
644  {
645  os << write(1, rt, "The kinetic function can be invalid for the actual parameter values if substrate \""
646  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
647  + "\" is set to zero.\n" , "");
648  ret = true;
649  }
650  }
651  } //loop over substrates that are set to zero
652 
653  // Product concentrations set to zero
654  imax = mProductZero.size();
655 
656  for (i = 0; i < imax; ++i)
657  {
658  assert(mProductZero[i].second.size() >= 2);
659 
660  //first for positive parameter values
661  if (mProductZero[i].second[1].isPositive())
662  {
663  os << write(0, rt, "The kinetic function is always positive for positive parameter values if product \""
664  + mProductZero[i].first.second // pF->getVariables()[mProductZero[i].first]->getObjectName()
665  + "\" is set to zero.\n" ,
666  "This is the expected behaviour for reversible reactions. With products absent the reaction can only proceed forward.");
667  }
668  else if (mProductZero[i].second[1].containsPositive())
669  {
670  os << write(1, rt, "Copasi could not show that the kinetic function is always positive for positive parameter values if product \""
671  + mProductZero[i].first.second //pF->getVariables()[mProductZero[i].first]->getObjectName()
672  + "\" is set to zero.\n" , "");
673  ret = true;
674  }
675  else
676  {
677  os << write(2, rt, "The kinetic function is never positive for positive parameter values if product \""
678  + mProductZero[i].first.second //pF->getVariables()[mProductZero[i].first]->getObjectName()
679  + "\" is set to zero.\n" ,
680  "This means the reaction never proceeds forward even if no product is present. This is unexpected for a reversible reaction.");
681  ret = true;
682  }
683 
684  if (mProductZero[i].second[1].isInvalid())
685  {
686  os << write(2, rt, "The kinetic function is always invalid for positive parameter values if product \""
687  + mProductZero[i].first.second //pF->getVariables()[mProductZero[i].first]->getObjectName()
688  + "\" is set to zero.\n" , "");
689  ret = true;
690  }
691  else if (mProductZero[i].second[1].containsInvalid())
692  {
693  os << write(1, rt, "The kinetic function can be invalid for positive parameter values if product \""
694  + mProductZero[i].first.second // pF->getVariables()[mProductZero[i].first]->getObjectName()
695  + "\" is set to zero.\n" , "");
696  ret = true;
697  }
698 
699  //now report if the result is different for the actual parameters values
700  if ((mProductZero[i].second.size() > 2) && (!(mProductZero[i].second[1] == mProductZero[i].second[2])))
701  {
702  if (mProductZero[i].second[2].isPositive())
703  {
704  os << write(0, rt, "The kinetic function is always positive for the actual parameter values if product \""
705  + mProductZero[i].first.second // pF->getVariables()[mProductZero[i].first]->getObjectName()
706  + "\" is set to zero.\n" ,
707  "This is the expected behaviour for reversible reactions. With products absent the reaction can only proceed forward.");
708  }
709  else if (mProductZero[i].second[2].containsPositive())
710  {
711  os << write(1, rt, "Copasi could not show that the kinetic function is always positive for the actual parameter values if product \""
712  + mProductZero[i].first.second //pF->getVariables()[mProductZero[i].first]->getObjectName()
713  + "\" is set to zero.\n" , "");
714  ret = true;
715  }
716  else
717  {
718  os << write(2, rt, "The kinetic function is never positive for the actual parameter values if product \""
719  + mProductZero[i].first.second //pF->getVariables()[mProductZero[i].first]->getObjectName()
720  + "\" is set to zero.\n" ,
721  "This means the reaction never proceeds forward even if no product is present. This is unexpected for a reversible reaction.");
722  ret = true;
723  }
724 
725  if (mProductZero[i].second[2].isInvalid())
726  {
727  os << write(2, rt, "The kinetic function is always invalid for the actual parameter values if substrate \""
728  + mProductZero[i].first.second //pF->getVariables()[mProductZero[i].first]->getObjectName()
729  + "\" is set to zero.\n" , "");
730  ret = true;
731  }
732  else if (mProductZero[i].second[2].containsInvalid())
733  {
734  os << write(1, rt, "The kinetic function can be invalid for the actual parameter values if substrate \""
735  + mProductZero[i].first.second //pF->getVariables()[mProductZero[i].first]->getObjectName()
736  + "\" is set to zero.\n" , "");
737  ret = true;
738  }
739  }
740  } //loop over products that are set to zero
741  }
742  else //irreversible function
743  {
744  //unchanged values
745  assert(mUnchangedParameters.size() >= 2);
746 
747  //first for positive parameter values
748  if (mUnchangedParameters[1].isPositive())
749  {
750  os << write(0, rt, "The kinetic function is positive for positive parameter values.\n", "");
751  }
752  else
753  {
754  os << write(1, rt, "Copasi could not show that the kinetic function is positive for positive parameter values.\n", "");
755  ret = true;
756  }
757 
758  if (mUnchangedParameters[1].isZero())
759  {
760  os << write(2, rt, "The kinetic function is always zero for positive parameter values.\n", "");
761  ret = true;
762  }
763  else if (mUnchangedParameters[1].containsZero())
764  {
765  os << write(1, rt, "The kinetic function can be zero even if substrate concentrations and parameter values are positive.\n", "");
766  ret = true;
767  }
768 
769  if (mUnchangedParameters[1].isNegative())
770  {
771  os << write(2, rt, "The kinetic function is always negative for positive parameter values.\n", "");
772  ret = true;
773  }
774  else if (mUnchangedParameters[1].containsNegative())
775  {
776  os << write(1, rt, "The kinetic function can be negative even if substrate concentrations and parameter values are positive.\n", "");
777  ret = true;
778  }
779 
780  if (mUnchangedParameters[1].isInvalid())
781  {
782  os << write(2, rt, "The kinetic function is always invalid for positive parameter values.\n", "");
783  ret = true;
784  }
785  else if (mUnchangedParameters[1].containsInvalid())
786  {
787  os << write(1, rt, "The kinetic function can be invalid even if substrate concentrations and parameter values are positive.\n", "");
788  ret = true;
789  }
790 
791  //now report if the result is different for the actual parameters values
792  if ((mUnchangedParameters.size() > 2) && (!(mUnchangedParameters[1] == mUnchangedParameters[2])))
793  {
794  if (mUnchangedParameters[2].isPositive())
795  {
796  os << write(0, rt, "The kinetic function is positive for the actual parameter values.\n", "");
797  }
798  else
799  {
800  os << write(1, rt, "Copasi could not show that the kinetic function is positive for the actual parameter values.\n", "");
801  ret = true;
802  }
803 
804  if (mUnchangedParameters[2].isZero())
805  {
806  os << write(2, rt, "The kinetic function is always zero for the actual parameter values.\n", "");
807  ret = true;
808  }
809  else if (mUnchangedParameters[2].containsZero())
810  {
811  os << write(1, rt, "The kinetic function can be zero for the actual parameter values even if substrate concentrations are positive.\n", "");
812  ret = true;
813  }
814 
815  if (mUnchangedParameters[2].isNegative())
816  {
817  os << write(2, rt, "The kinetic function is always negative for the actual parameter values.\n", "");
818  ret = true;
819  }
820  else if (mUnchangedParameters[2].containsNegative())
821  {
822  os << write(1, rt, "The kinetic function can be negative for the actual parameter values even if substrate concentrations are positive.\n", "");
823  ret = true;
824  }
825 
826  if (mUnchangedParameters[2].isInvalid())
827  {
828  os << write(2, rt, "The kinetic function is always invalid for the actual parameter values.\n", "");
829  ret = true;
830  }
831  else if (mUnchangedParameters[2].containsInvalid())
832  {
833  os << write(1, rt, "The kinetic function can be invalid for the actual parameter values even if substrate concentrations are positive.\n", "");
834  ret = true;
835  }
836  }
837 
838  size_t i, imax;
839 
840  // Substrate concentrations set to zero
841  imax = mSubstrateZero.size();
842 
843  for (i = 0; i < imax; ++i)
844  {
845  assert(mSubstrateZero[i].second.size() >= 2);
846 
847  //first for positive parameter values
848  if (mSubstrateZero[i].second[1].isZero())
849  {
850  os << write(0, rt, "The kinetic function is always zero for positive parameter values if substrate \""
851  + mSubstrateZero[i].first.second // pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
852  + "\" is set to zero.\n" , "");
853  }
854  else if (mSubstrateZero[i].second[1].containsZero())
855  {
856  os << write(1, rt, "Copasi could not show that the kinetic function is always zero for positive parameter values if substrate \""
857  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
858  + "\" is set to zero.\n" , "");
859  ret = true;
860  }
861  else
862  {
863  os << write(2, rt, "The kinetic function is never zero for positive parameter values if substrate \""
864  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
865  + "\" is set to zero.\n" , "");
866  ret = true;
867  }
868 
869  if (mSubstrateZero[i].second[1].isInvalid())
870  {
871  os << write(2, rt, "The kinetic function is always invalid for positive parameter values if substrate \""
872  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
873  + "\" is set to zero.\n" , "");
874  ret = true;
875  }
876  else if (mSubstrateZero[i].second[1].containsInvalid())
877  {
878  os << write(1, rt, "The kinetic function can be invalid for positive parameter values if substrate \""
879  + mSubstrateZero[i].first.second // pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
880  + "\" is set to zero.\n" , "");
881  ret = true;
882  }
883 
884  //now report if the result is different for the actual parameters values
885  if ((mSubstrateZero[i].second.size() > 2) && (!(mSubstrateZero[i].second[1] == mSubstrateZero[i].second[2])))
886  {
887  if (mSubstrateZero[i].second[2].isZero())
888  {
889  os << write(0, rt, "The kinetic function is always zero for the actual parameter values if substrate \""
890  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
891  + "\" is set to zero.\n" , "");
892  }
893  else if (mSubstrateZero[i].second[2].containsZero())
894  {
895  os << write(1, rt, "Copasi could not show that the kinetic function is always zero for the actual parameter values if substrate \""
896  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
897  + "\" is set to zero.\n" , "");
898  ret = true;
899  }
900  else
901  {
902  os << write(2, rt, "The kinetic function is never zero for the actual parameter values if substrate \""
903  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
904  + "\" is set to zero.\n" , "");
905  ret = true;
906  }
907 
908  if (mSubstrateZero[i].second[2].isInvalid())
909  {
910  os << write(2, rt, "The kinetic function is always invalid for the actual parameter values if substrate \""
911  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
912  + "\" is set to zero.\n" , "");
913  ret = true;
914  }
915  else if (mSubstrateZero[i].second[2].containsInvalid())
916  {
917  os << write(1, rt, "The kinetic function can be invalid for the actual parameter values if substrate \""
918  + mSubstrateZero[i].first.second //pF->getVariables()[mSubstrateZero[i].first]->getObjectName()
919  + "\" is set to zero.\n" , "");
920  ret = true;
921  }
922  }
923  } //loop over substrates that are set to zero
924  } //irreversible
925 
926  //mUnchangedParameters
927  //mSubstrateZero
928  //mProductZero
929 
930  return ret;
931 }
932 
934 {
935  //if (!pF) return;
936 
937  size_t i, imax;
938 
939  if (rt)
940  {
941  os << "<font color=\"#505080\"><TABLE>\n";
942 
943  os << " <TR>\n";
944  os << " <TD></TD>\n";
945  //CValue results
946  size_t j, jmax = mUnchangedParameters.size();
947 
948  for (j = 0; j < jmax; ++j)
949  os << " <TD>" << mUnchangedParameters[j] << "</TD>\n";
950 
951  os << " </TR>\n";
952 
953  imax = mSubstrateZero.size();
954 
955  for (i = 0; i < imax; ++i)
956  {
957  os << " <TR>\n";
958  //parameter name
959  os << " <TD>Substrate \"" << mSubstrateZero[i].first.second /*pF->getVariables()[mSubstrateZero[i].first]->getObjectName()*/ << "\" set to 0:</TD>\n";
960 
961  //CValue results
962  size_t j, jmax = mSubstrateZero[i].second.size();
963 
964  for (j = 0; j < jmax; ++j)
965  os << " <TD>" << mSubstrateZero[i].second[j] << "</TD>\n";
966 
967  os << " </TR>\n";
968  }
969 
970  imax = mProductZero.size();
971 
972  for (i = 0; i < imax; ++i)
973  {
974  os << " <TR>\n";
975  //parameter name
976  os << " <TD>Product \"" << mProductZero[i].first.second << "\" set to 0: </TD>\n";
977 
978  //CValue results
979  size_t j, jmax = mProductZero[i].second.size();
980 
981  for (j = 0; j < jmax; ++j)
982  os << " <TD>" << mProductZero[i].second[j] << "</TD>\n";
983 
984  os << " </TR>\n";
985  }
986 
987  os << "</TABLE></font>\n";
988  }
989 }
990 
991 //***********************************************************************************************
992 
993 //static
994 void CFunctionAnalyzer::constructCallParameters(const CFunctionParameters & fp, std::vector<CValue> & callParameters, bool posi)
995 {
996  size_t i, imax = fp.size();
997  callParameters.resize(imax);
998 
999  for (i = 0; i < imax; ++i)
1000  {
1001  CFunctionParameter::Role role = fp[i]->getUsage();
1002 
1003  switch (role)
1004  {
1009  callParameters[i] = CValue::positive;
1010  break;
1011 
1016  callParameters[i] = posi ? CValue::positive : CValue::unknown;
1017  break;
1018  }
1019  }
1020 }
1021 
1022 //static
1023 void CFunctionAnalyzer::constructCallParametersActualValues(std::vector<CValue> & callParameters, /*const CModel* model,*/ const CReaction* reaction)
1024 {
1025  size_t i, imax = reaction->getFunctionParameters().size();
1026  callParameters.resize(imax);
1027 
1028  for (i = 0; i < imax; ++i)
1029  {
1030  const CModelEntity * pME;
1031  const CCopasiParameter * pCP;
1032 
1033  CFunctionParameter::Role role = reaction->getFunctionParameters()[i]->getUsage();
1034 
1035  switch (role)
1036  {
1042  callParameters[i] = CValue::unknown;
1043  pME = dynamic_cast<const CModelEntity*>(CCopasiRootContainer::getKeyFactory()->get(reaction->getParameterMappings()[i][0]));
1044 
1045  if (pME)
1046  {
1047  if (pME->getStatus() == CModelEntity::FIXED)
1048  callParameters[i] = CValue(pME->getInitialValue());
1049  else
1050  callParameters[i] = CValue::positive;
1051  }
1052 
1053  pCP = dynamic_cast<const CCopasiParameter*>(CCopasiRootContainer::getKeyFactory()->get(reaction->getParameterMappings()[i][0]));
1054 
1055  if (pCP)
1056  {
1057  callParameters[i] = CValue(*pCP->getValue().pDOUBLE);
1058  }
1059 
1060  break;
1061 
1065  callParameters[i] = CValue::unknown;
1066  break;
1067  }
1068  }
1069 }
1070 
1071 //static
1072 CFunctionAnalyzer::CValue CFunctionAnalyzer::evaluateNode(const CEvaluationNode * pNode, const std::vector<CValue> & callParameters,
1073  Mode mode)
1074 {
1077 
1078  while (itNode.next() != itNode.end())
1079  {
1080  if (*itNode == NULL)
1081  {
1082  continue;
1083  }
1084 
1085  switch (CEvaluationNode::type(itNode->getType()))
1086  {
1088 
1090  {
1092  Result = itNode.context()[0] * itNode.context()[1];
1093  break;
1094 
1096  Result = itNode.context()[0] / itNode.context()[1];
1097  break;
1098 
1100  Result = itNode.context()[0] + itNode.context()[1];
1101  break;
1102 
1104  Result = itNode.context()[0] - itNode.context()[1];
1105  break;
1106 
1108  Result = itNode.context()[0] ^ itNode.context()[1];
1109  break;
1110 
1111  // case MODULUS:
1112  // Value = (C_FLOAT64) (((size_t) mpLeft->value()) % ((size_t) mpRight->value()));
1113  // break;
1114  //
1115 
1116  default:
1117  Result = CValue::unknown;
1118  break;
1119  }
1120 
1121  break;
1122 
1124  Result = itNode->getValue();
1125  break;
1126 
1128  {
1129  const CEvaluationNodeVariable * pENV = static_cast<const CEvaluationNodeVariable*>(*itNode);
1130 
1131  if (callParameters.size() < pENV->getIndex() + 1)
1132  {
1133  Result = CValue::invalid;
1134  }
1135  else
1136  {
1137  Result = callParameters[pENV->getIndex()];
1138  }
1139  }
1140 
1141  break;
1142 
1144 
1146  {
1148  Result = itNode.context()[0].invert();
1149  break;
1150 
1151  default:
1152  Result = CValue::unknown;
1153  break;
1154  }
1155 
1156  break;
1157 
1159  //TODO: implement
1160  Result = CValue::unknown;
1161  break;
1162 
1163  case CEvaluationNode::CALL:
1164  {
1165  const CEvaluationNodeCall * pENCall = static_cast<const CEvaluationNodeCall*>(*itNode);
1166 
1167  //some checks
1168  if (pENCall->getCalledTree() && pENCall->getCalledTree()->getRoot())
1169  {
1170  const CFunction * tmpFunc = dynamic_cast<const CFunction*>(pENCall->getCalledTree());
1171 
1172  if (tmpFunc && tmpFunc->getVariables().size() == pENCall->getListOfChildNodes().size())
1173  {
1174  Result = evaluateNode(pENCall->getCalledTree()->getRoot(), itNode.context(), mode);
1175  }
1176  else
1177  {
1178  Result = CValue::invalid;
1179  }
1180  }
1181  else
1182  {
1183  Result = CValue::invalid;
1184  }
1185  }
1186  break;
1187 
1189 
1190  if (mode == NOOBJECT)
1191  {
1192  Result = CValue::invalid;
1193  }
1194  else if (mode == POSITIVE)
1195  {
1196  Result = CValue::positive;
1197  }
1198  else
1199  {
1200  //TODO: implement GENERAL and ACTUAL
1201  Result = CValue::unknown;
1202  }
1203 
1204  break;
1205 
1206  default:
1207  Result = CValue::unknown;
1208  break;
1209  }
1210 
1211  if (itNode.parentContextPtr() != NULL)
1212  {
1213  itNode.parentContextPtr()->push_back(Result);
1214  }
1215  }
1216 
1217  return Result;
1218 }
1219 
1221 {
1222  mResult.clear();
1223  mResult.mpFunction = f;
1224 
1225  //assume mass action is ok.
1226  if (dynamic_cast<const CMassAction*>(f)) return;
1227 
1228  if (f->isReversible() == TriFalse)
1230  {
1231  // An irreversible kinetics should not depend on products.
1233  }
1234 
1235  std::vector<CValue> callParameters;
1236  CValue tmpValue;
1237 
1238  //***** just the kinetic function *****
1239 
1240  //construct call parameter vector
1241  constructCallParameters(f->getVariables(), callParameters, false);
1242  tmpValue = CFunctionAnalyzer::evaluateNode(f->getRoot(), callParameters, NOOBJECT);
1243  mResult.mOriginalFunction.mUnchangedParameters.push_back(tmpValue);
1244 
1245  //construct call parameter vector
1246  constructCallParameters(f->getVariables(), callParameters, true);
1247  tmpValue = CFunctionAnalyzer::evaluateNode(f->getRoot(), callParameters, NOOBJECT);
1248  mResult.mOriginalFunction.mUnchangedParameters.push_back(tmpValue);
1249 
1250  if (reaction)
1251  {
1252  //construct call parameter vector
1253  constructCallParametersActualValues(callParameters, reaction);
1254  tmpValue = CFunctionAnalyzer::evaluateNode(f->getRoot(), callParameters, NOOBJECT);
1255  mResult.mOriginalFunction.mUnchangedParameters.push_back(tmpValue);
1256  }
1257  else
1258  {
1259  }
1260 
1261  //***** now the kinetic function with single substrates or products == zero ******
1262  std::vector<CValue> tmpValueVector;
1263 
1264  size_t i, imax = f->getVariables().size();
1265 
1266  for (i = 0; i < imax; ++i)
1267  {
1268  if (f->getVariables()[i]->getUsage() == CFunctionParameter::SUBSTRATE)
1269  {
1270  tmpValueVector.clear();
1271 
1272  //construct call parameter vector
1273  constructCallParameters(f->getVariables(), callParameters, false);
1274  //set one substrate to zero
1275  callParameters[i] = CValue::zero;
1276  tmpValue = CFunctionAnalyzer::evaluateNode(f->getRoot(), callParameters, NOOBJECT);
1277  tmpValueVector.push_back(tmpValue);
1278 
1279  //construct call parameter vector
1280  constructCallParameters(f->getVariables(), callParameters, true);
1281  //set one substrate to zero
1282  callParameters[i] = CValue::zero;
1283  tmpValue = CFunctionAnalyzer::evaluateNode(f->getRoot(), callParameters, NOOBJECT);
1284  tmpValueVector.push_back(tmpValue);
1285 
1286  if (reaction)
1287  {
1288  //construct call parameter vector
1289  constructCallParametersActualValues(callParameters, reaction);
1290  //set one substrate to zero
1291  callParameters[i] = CValue::zero;
1292  tmpValue = CFunctionAnalyzer::evaluateNode(f->getRoot(), callParameters, NOOBJECT);
1293 
1294  //test if result is indeed 0 (as is required)
1295  tmpValueVector.push_back(tmpValue);
1296  }
1297  else
1298  {
1299  }
1300 
1301  mResult.mOriginalFunction.mSubstrateZero.push_back(std::pair<std::pair<size_t, std::string>, std::vector<CValue> >(std::pair<size_t, std::string>(i, f->getVariables()[i]->getObjectName()), tmpValueVector));
1302  }
1303 
1304  if (f->getVariables()[i]->getUsage() == CFunctionParameter::PRODUCT)
1305  {
1306  tmpValueVector.clear();
1307 
1308  //construct call parameter vector
1309  constructCallParameters(f->getVariables(), callParameters, false);
1310  //set one product to zero
1311  callParameters[i] = CValue::zero;
1312  tmpValue = CFunctionAnalyzer::evaluateNode(f->getRoot(), callParameters, NOOBJECT);
1313  tmpValueVector.push_back(tmpValue);
1314 
1315  //construct call parameter vector
1316  constructCallParameters(f->getVariables(), callParameters, true);
1317  //set one substrate to zero
1318  callParameters[i] = CValue::zero;
1319  tmpValue = CFunctionAnalyzer::evaluateNode(f->getRoot(), callParameters, NOOBJECT);
1320  tmpValueVector.push_back(tmpValue);
1321 
1322  if (reaction)
1323  {
1324  //construct call parameter vector
1325  constructCallParametersActualValues(callParameters, reaction);
1326  //set one substrate to zero
1327  callParameters[i] = CValue::zero;
1328  tmpValue = CFunctionAnalyzer::evaluateNode(f->getRoot(), callParameters, NOOBJECT);
1329  tmpValueVector.push_back(tmpValue);
1330  }
1331  else
1332  {
1333  }
1334 
1335  mResult.mOriginalFunction.mProductZero.push_back(std::pair<std::pair<size_t, std::string>, std::vector<CValue> >(std::pair<size_t, std::string>(i, f->getVariables()[i]->getObjectName()), tmpValueVector));
1336  }
1337  }
1338 
1339  //try to split reversible functions
1340  if ((f->isReversible() == TriTrue))
1341  {
1342  std::pair<CFunction *, CFunction *> tmp;
1343  tmp = f->splitFunction(NULL, "f", "b");
1344 
1345  if ((tmp.first == NULL) || (tmp.second == NULL))
1346  {
1348  }
1349  else
1350  {
1351  CFunctionAnalyzer fa1(tmp.first);
1353 
1354  CFunctionAnalyzer fa2(tmp.second);
1356  }
1357 
1358  pdelete(tmp.first);
1359  pdelete(tmp.second);
1360  }
1361 }
1362 
1363 //static
1364 std::string CFunctionAnalyzer::write(int level, bool rt, const std::string & text, const std::string & longText)
1365 {
1366  std::string color;
1367 
1368  switch (level)
1369  {
1370  case 0: color = "\"#008000\""; break;
1371 
1372  case 1: color = "\"#909000\""; break;
1373 
1374  case 2: color = "\"#800000\""; break;
1375 
1376  case 3: color = "\"#c04040\""; break;
1377 
1378  default: color = "\"#0000a0\""; break;
1379  }
1380 
1381  std::string ret;
1382 
1383  if (rt) ret += "<p><font color=" + color + ">";
1384 
1385  ret += (text + "\n");
1386 
1387  if (longText != "")
1388  {
1389  if (rt) ret += "<br>";
1390 
1391  ret += longText + "\n";
1392  }
1393 
1394  if (rt) ret += "</font></p>";
1395 
1396  return ret;
1397 }
void orValue(const double &value)
const CEvaluationTree * getCalledTree() const
#define pdelete(p)
Definition: copasi.h:215
std::vector< std::pair< std::pair< size_t, std::string >, std::vector< CValue > > > mProductZero
const std::string & getObjectName() const
static CValue evaluateNode(const CEvaluationNode *node, const std::vector< CValue > &callParameters, Mode mode)
CValue operator/(const CValue &rhs) const
const C_FLOAT64 & getValue() const
CCopasiObject * get(const std::string &key)
CValue operator-(const CValue &rhs) const
const Type & getType() const
size_t getNumberOfParametersByUsage(CFunctionParameter::Role usage) const
static void constructCallParametersActualValues(std::vector< CValue > &callParameters, const CReaction *reaction)
static CValue generalize(const double &d)
FunctionInformation mBPart
const Result & getResult() const
const CNodeIteratorMode::State & next()
const std::vector< CEvaluationNode * > getListOfChildNodes() const
static void constructCallParameters(const CFunctionParameters &fp, std::vector< CValue > &callParameters, bool posi)
const C_FLOAT64 & getInitialValue() const
static Type type(const Type &type)
const Status & getStatus() const
std::ostream & operator<<(std::ostream &os, const CFunctionAnalyzer::CValue &v)
CValue operator^(const CValue &rhs) const
const CFunctionParameters & getFunctionParameters() const
Definition: CReaction.cpp:576
const TriLogic & isReversible() const
Definition: CFunction.cpp:145
std::pair< CFunction *, CFunction * > splitFunction(const CEvaluationNode *node, const std::string &name1, const std::string &name2) const
Definition: CFunction.cpp:445
const Value & getValue() const
static std::string write(int level, bool rt, const std::string &text, const std::string &longText)
FunctionInformation mOriginalFunction
Context * parentContextPtr()
CValue operator*(const CValue &rhs) const
std::vector< std::pair< std::pair< size_t, std::string >, std::vector< CValue > > > mSubstrateZero
bool operator==(const CValue &rhs) const
void checkKineticFunction(const CFunction *f, const CReaction *reaction=NULL)
static Type subType(const Type &type)
static CKeyFactory * getKeyFactory()
const CFunction * mpFunction
The class for handling a chemical kinetic function.
Definition: CFunction.h:29
void writeTable(std::ostream &os, bool rt) const
const CModelEntity::Status & getStatus() const
CNodeIteratorMode::State end() const
const std::vector< std::vector< std::string > > & getParameterMappings() const
Definition: CReaction.h:285
bool writeResult(std::ostream &os, bool rt, bool verbose) const
CEvaluationNode * getRoot()
CFunctionParameters & getVariables()
Definition: CFunction.cpp:148
FunctionInformation mFPart
bool writeAnalysis(std::ostream &os, bool rt, bool reversible) const
CValue operator+(const CValue &rhs) const