1 /**
2 * @file SBMLInferUnitsConverter.cpp
3 * @brief Implementation of SBMLInferUnitsConverter.
4 * @author Sarah Keating
5 *
6 * <!--------------------------------------------------------------------------
7 * This file is part of libSBML. Please visit http://sbml.org for more
8 * information about SBML, and the latest version of libSBML.
9 *
10 * Copyright (C) 2020 jointly by the following organizations:
11 * 1. California Institute of Technology, Pasadena, CA, USA
12 * 2. University of Heidelberg, Heidelberg, Germany
13 * 3. University College London, London, UK
14 *
15 * Copyright (C) 2019 jointly by the following organizations:
16 * 1. California Institute of Technology, Pasadena, CA, USA
17 * 2. University of Heidelberg, Heidelberg, Germany
18 *
19 * Copyright (C) 2013-2018 jointly by the following organizations:
20 * 1. California Institute of Technology, Pasadena, CA, USA
21 * 2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
22 * 3. University of Heidelberg, Heidelberg, Germany
23 *
24 * Copyright (C) 2009-2013 jointly by the following organizations:
25 * 1. California Institute of Technology, Pasadena, CA, USA
26 * 2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
27 *
28 * Copyright (C) 2006-2008 by the California Institute of Technology,
29 * Pasadena, CA, USA
30 *
31 * Copyright (C) 2002-2005 jointly by the following organizations:
32 * 1. California Institute of Technology, Pasadena, CA, USA
33 * 2. Japan Science and Technology Agency, Japan
34 *
35 * This library is free software; you can redistribute it and/or modify it
36 * under the terms of the GNU Lesser General Public License as published by
37 * the Free Software Foundation. A copy of the license agreement is provided
38 * in the file named "LICENSE.txt" included with this software distribution
39 * and also available online as http://sbml.org/software/libsbml/license.html
40 * ------------------------------------------------------------------------ -->
41 */
42
43 #include <sbml/conversion/SBMLInferUnitsConverter.h>
44 #include <sbml/conversion/SBMLConverterRegistry.h>
45 #include <sbml/conversion/SBMLConverterRegister.h>
46 #include <sbml/SBMLWriter.h>
47 #include <sbml/SBMLReader.h>
48 #include <sbml/SBMLDocument.h>
49 #include <sbml/Model.h>
50
51 #ifdef __cplusplus
52
53 #include <algorithm>
54 #include <string>
55
56 using namespace std;
57 LIBSBML_CPP_NAMESPACE_BEGIN
58
59
60 /** @cond doxygenLibsbmlInternal */
init()61 void SBMLInferUnitsConverter::init()
62 {
63 SBMLInferUnitsConverter converter;
64 SBMLConverterRegistry::getInstance().addConverter(&converter);
65 }
66 /** @endcond */
67
68
SBMLInferUnitsConverter()69 SBMLInferUnitsConverter::SBMLInferUnitsConverter ()
70 : SBMLConverter("SBML Infer Units Converter")
71 {
72 newIdCount = 0;
73 }
74
75
76 /*
77 * Copy constructor.
78 */
SBMLInferUnitsConverter(const SBMLInferUnitsConverter & orig)79 SBMLInferUnitsConverter::SBMLInferUnitsConverter(const SBMLInferUnitsConverter& orig) :
80 SBMLConverter(orig)
81 {
82 newIdCount = orig.newIdCount;
83 }
84
85
86 /*
87 * Destroy this object.
88 */
~SBMLInferUnitsConverter()89 SBMLInferUnitsConverter::~SBMLInferUnitsConverter ()
90 {
91 }
92
93
94 /*
95 * Assignment operator for SBMLInferUnitsConverter.
96 */
97 SBMLInferUnitsConverter&
operator =(const SBMLInferUnitsConverter & rhs)98 SBMLInferUnitsConverter::operator=(const SBMLInferUnitsConverter& rhs)
99 {
100 if(&rhs!=this)
101 {
102 this->SBMLConverter::operator =(rhs);
103 }
104
105 return *this;
106 }
107
108
109 SBMLInferUnitsConverter*
clone() const110 SBMLInferUnitsConverter::clone () const
111 {
112 return new SBMLInferUnitsConverter(*this);
113 }
114
115
116 ConversionProperties
getDefaultProperties() const117 SBMLInferUnitsConverter::getDefaultProperties() const
118 {
119 static ConversionProperties prop;
120 static bool init = false;
121
122 if (init)
123 {
124 return prop;
125 }
126 else
127 {
128 prop.addOption("inferUnits", true,
129 "Infer the units of Parameters");
130 init = true;
131 return prop;
132 }
133 }
134
135
136 bool
matchesProperties(const ConversionProperties & props) const137 SBMLInferUnitsConverter::matchesProperties(const ConversionProperties &props) const
138 {
139 if (!props.hasOption("inferUnits"))
140 return false;
141 return true;
142 }
143
144
145 int
convert()146 SBMLInferUnitsConverter::convert()
147 {
148 if (mDocument == NULL)
149 {
150 return LIBSBML_OPERATION_FAILED;
151 }
152
153 Model* mModel = mDocument->getModel();
154 if (mModel == NULL)
155 {
156 return LIBSBML_INVALID_OBJECT;
157 }
158
159 /* check consistency of model */
160 /* since this function will write to the error log we should
161 * clear anything in the log first
162 */
163 mDocument->getErrorLog()->clearLog();
164 unsigned char origValidators = mDocument->getApplicableValidators();
165
166 mDocument->setApplicableValidators(AllChecksON);
167
168 mDocument->checkConsistency();
169
170
171 /* replace original consistency checks */
172 mDocument->setApplicableValidators(origValidators);
173
174 if (mDocument->getErrorLog()->getNumFailsWithSeverity(LIBSBML_SEV_ERROR) != 0)
175 {
176 return LIBSBML_CONV_INVALID_SRC_DOCUMENT;
177 }
178
179 /* so we have a consistent model - we can try inferring units */
180 // TO DO keep a copy of model so we can revert back to it if things go wrong
181 std::string newId;
182 char number[4];
183 for (unsigned int i = 0; i < mModel->getNumParameters(); i++)
184 {
185 if (mModel->getParameter(i)->isSetUnits() == false)
186 {
187 UnitDefinition * inferred = NULL;
188 mModel->getParameter(i)->setCalculatingUnits(true);
189 inferred = mModel->getParameter(i)->getDerivedUnitDefinition();
190 mModel->getParameter(i)->setCalculatingUnits(false);
191
192 if (inferred != NULL && inferred->getNumUnits() != 0)
193 {
194 bool baseUnit = false;
195
196 newId = existsAlready(*(mModel), inferred);
197
198 if (newId.empty())
199 {
200 if (inferred->isVariantOfDimensionless())
201 {
202 newId = "dimensionless";
203 baseUnit = true;
204 }
205 else if (inferred->getNumUnits() == 1)
206 {
207 Unit * u = inferred->getUnit(0);
208 Unit * defaultU = new Unit(u->getSBMLNamespaces());
209 defaultU->initDefaults();
210 defaultU->setKind(u->getKind());
211 if (Unit::areIdentical(u, defaultU) == true)
212 {
213 newId = UnitKind_toString(u->getKind());
214 baseUnit = true;
215 }
216 delete defaultU;
217 defaultU = NULL;
218 }
219 }
220
221 if (newId.empty())
222 {
223 /* create an id for the unitDef */
224 sprintf(number, "%u", newIdCount);
225 newId = "unitSid_" + string(number);
226 newIdCount++;
227
228 /* double check that this id has not been used */
229 while (mModel->getUnitDefinition(newId) != NULL)
230 {
231 sprintf(number, "%u", newIdCount);
232 newId = "unitSid_" + string(number);
233 newIdCount++;
234 }
235 }
236
237 if (baseUnit == false)
238 {
239 inferred->setId(newId);
240 mModel->addUnitDefinition(inferred);
241 }
242
243 mModel->getParameter(i)->setUnits(newId);
244
245 delete inferred;
246 inferred = NULL;
247 }
248 }
249 }
250
251 return LIBSBML_OPERATION_SUCCESS;
252 }
253
254
255
256
257
258 /** @cond doxygenLibsbmlInternal */
259 std::string
existsAlready(Model & m,UnitDefinition * newUD)260 SBMLInferUnitsConverter::existsAlready(Model& m, UnitDefinition *newUD)
261 {
262 std::string id = "";
263 for (unsigned int i = 0; i < m.getNumUnitDefinitions(); i++)
264 {
265 if (UnitDefinition::areIdentical(m.getUnitDefinition(i), newUD))
266 {
267 return m.getUnitDefinition(i)->getId();
268 }
269 }
270
271 return id;
272 }
273 /** @endcond */
274
275
276
277 /** @cond doxygenIgnored */
278 /** @endcond */
279
280 LIBSBML_CPP_NAMESPACE_END
281
282 #endif /* __cplusplus */
283
284
285