1 /**
2  * @cond doxygenLibsbmlInternal
3  *
4  * @file    LocalParameterMathCheck.cpp
5  * @brief   checks <ci> element of local parameter not used elsewhere
6  * @author  Sarah Keating
7  *
8  * <!--------------------------------------------------------------------------
9  * This file is part of libSBML.  Please visit http://sbml.org for more
10  * information about SBML, and the latest version of libSBML.
11  *
12  * Copyright (C) 2020 jointly by the following organizations:
13  *     1. California Institute of Technology, Pasadena, CA, USA
14  *     2. University of Heidelberg, Heidelberg, Germany
15  *     3. University College London, London, UK
16  *
17  * Copyright (C) 2019 jointly by the following organizations:
18  *     1. California Institute of Technology, Pasadena, CA, USA
19  *     2. University of Heidelberg, Heidelberg, Germany
20  *
21  * Copyright (C) 2013-2018 jointly by the following organizations:
22  *     1. California Institute of Technology, Pasadena, CA, USA
23  *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
24  *     3. University of Heidelberg, Heidelberg, Germany
25  *
26  * Copyright (C) 2009-2013 jointly by the following organizations:
27  *     1. California Institute of Technology, Pasadena, CA, USA
28  *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
29  *
30  * Copyright (C) 2006-2008 by the California Institute of Technology,
31  *     Pasadena, CA, USA
32  *
33  * Copyright (C) 2002-2005 jointly by the following organizations:
34  *     1. California Institute of Technology, Pasadena, CA, USA
35  *     2. Japan Science and Technology Agency, Japan
36  *
37  * This library is free software; you can redistribute it and/or modify it
38  * under the terms of the GNU Lesser General Public License as published by
39  * the Free Software Foundation.  A copy of the license agreement is provided
40  * in the file named "LICENSE.txt" included with this software distribution
41  * and also available online as http://sbml.org/software/libsbml/license.html
42  * ---------------------------------------------------------------------- -->*/
43 
44 #include <sbml/Model.h>
45 #include <sbml/Compartment.h>
46 #include <sbml/Species.h>
47 #include <sbml/Parameter.h>
48 #include <sbml/UnitDefinition.h>
49 #include <sbml/Event.h>
50 #include <sbml/Reaction.h>
51 #include <sbml/EventAssignment.h>
52 #include <sbml/SpeciesReference.h>
53 #include <sbml/Rule.h>
54 #include <sbml/math/FormulaFormatter.h>
55 #include <sbml/SBMLTypeCodes.h>
56 
57 #include <sbml/units/UnitFormulaFormatter.h>
58 
59 #include "LocalParameterMathCheck.h"
60 
61 /** @cond doxygenIgnored */
62 using namespace std;
63 /** @endcond */
64 
65 LIBSBML_CPP_NAMESPACE_BEGIN
66 #ifdef __cplusplus
67 
68 static const char* PREAMBLE =
69     "The 'id' value of a <parameter> defined within a <kineticLaw> can only "
70     "be used in 'ci' elements within the MathML content of that same "
71     "<kineticLaw>; the identifier is not visible to other parts of the "
72     "model. (References: L2V2 Section 3.5.3.)";
73 
74 
75 /*
76  * Creates a new Constraint with the given @p id.
77  */
LocalParameterMathCheck(unsigned int id,Validator & v)78 LocalParameterMathCheck::LocalParameterMathCheck (unsigned int id, Validator& v) : MathMLBase(id, v)
79 {
80 }
81 
82 
83 /*
84  * Destroys this Constraint.
85  */
~LocalParameterMathCheck()86 LocalParameterMathCheck::~LocalParameterMathCheck ()
87 {
88 }
89 
90 
91 /*
92  * @return the preamble to use when logging constraint violations.
93  */
94 const char*
getPreamble()95 LocalParameterMathCheck::getPreamble ()
96 {
97   return PREAMBLE;
98 }
99 
100 
101 /*
102   * Checks the MathML of the ASTnode
103   * is appropriate for the function being performed
104   *
105   * If an inconsistency is found, an error message is logged.
106   */
107 void
checkMath(const Model & m,const ASTNode & node,const SBase & sb)108 LocalParameterMathCheck::checkMath (const Model& m, const ASTNode& node, const SBase & sb)
109 {
110 
111   ASTNodeType_t type = node.getType();
112 
113   /* if the node is a &lt;ci&gt; element it will have type AST_NAME
114    * check that this name is an appropriate component of the model */
115 
116   switch (type)
117   {
118     case AST_NAME:
119 
120       checkCiElement(m, node, sb);
121       break;
122 
123     default:
124 
125       checkChildren(m, node, sb);
126       break;
127 
128   }
129 }
130 
131 
132 /*
133   * Checks any &lt;ci&gt; elements in the MathML of the ASTnode
134   * contain the id of an appropriate component of the model
135   *
136   * If an inconsistency is found, an error message is logged.
137   */
138 void
checkCiElement(const Model & m,const ASTNode & node,const SBase & sb)139 LocalParameterMathCheck::checkCiElement (const Model& m,
140                                         const ASTNode& node,
141                                         const SBase & sb)
142 {
143   std::string name = node.getName();
144   const KineticLaw * kl;
145 
146   if (m.getCompartment(name) == NULL &&
147       m.getSpecies(name)     == NULL &&
148       m.getParameter(name)   == NULL &&
149       m.getReaction(name)    == NULL)
150   {
151     if (m.getLevel() >= 3 || (m.getLevel() == 2 && m.getVersion() == 5))
152     {
153       for (unsigned int rxn = 0; rxn < m.getNumReactions(); rxn++)
154       {
155         const Reaction* reaction = m.getReaction(rxn);
156         for (unsigned int reactant = 0; reactant < reaction->getNumReactants(); reactant++)
157         {
158           if (reaction->getReactant(reactant)->getIdAttribute() == name)
159           {
160             return;
161           }
162         }
163         for (unsigned int product = 0; product < reaction->getNumProducts(); product++)
164         {
165           if (reaction->getProduct(product)->getIdAttribute() == name)
166           {
167             return;
168           }
169         }
170       }
171     }
172 
173     /* check whether we are in a kinetic law since there
174      * may be local parameters to this law that are allowed
175      */
176 
177     if (sb.getTypeCode() == SBML_KINETIC_LAW)
178     {
179       kl = m.getReaction(mKLCount)->getKineticLaw();
180 
181       if (kl->getParameter(name) == NULL && mLocalParameters.contains(name))
182       {
183         logMathConflict(node, sb);
184       }
185     }
186     else if (mLocalParameters.contains(name))
187     {
188         logMathConflict(node, sb);
189     }
190   }
191 
192 }
193 
194 
195 /*
196  * @return the error message to use when logging constraint violations.
197  * This method is called by logFailure.
198  *
199  * Returns a message that the given @p id and its corresponding object are
200  * in  conflict with an object previously defined.
201  */
202 const string
getMessage(const ASTNode & node,const SBase & object)203 LocalParameterMathCheck::getMessage (const ASTNode& node, const SBase& object)
204 {
205 
206   ostringstream oss_msg;
207 
208   //oss_msg << getPreamble();
209 
210   oss_msg << "The <" << getFieldname() << "> element of the <" << object.getElementName();
211   oss_msg << "> ";
212   switch(object.getTypeCode()) {
213   case SBML_INITIAL_ASSIGNMENT:
214   case SBML_EVENT_ASSIGNMENT:
215   case SBML_ASSIGNMENT_RULE:
216   case SBML_RATE_RULE:
217     //LS DEBUG:  could use other attribute values, or 'isSetActualId'.
218     break;
219   default:
220     if (object.isSetId()) {
221       oss_msg << "with id '" << object.getId() << "' ";
222     }
223     break;
224   }
225   oss_msg << "uses '" << node.getName() << "' that is the id of a local parameter.";
226 
227   return oss_msg.str();
228 }
229 
230 #endif /* __cplusplus */
231 
232 LIBSBML_CPP_NAMESPACE_END
233 /** @endcond */
234 
235