1 /**
2 * \file TranslateSBML.cpp
3 * \brief MATLAB code for translating SBML document into MATLAB structure
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 #include <stdio.h>
43 #include <string.h>
44
45 #include <mex.h>
46
47 #ifndef USE_OCTAVE
48 #include <matrix.h>
49 #endif
50 #include <algorithm>
51
52 #include <sbml/SBMLReader.h>
53 #include <sbml/SBMLTypes.h>
54 #include <sbml/xml/XMLNode.h>
55 #include <sbml/math/ASTNode.h>
56 #include <sbml/extension/SBasePlugin.h>
57 #include <sbml/extension/SBMLExtensionRegistry.h>
58
59 LIBSBML_CPP_NAMESPACE_USE
60
61 #ifdef USE_FBC
62 #include <sbml/packages/fbc/common/FbcExtensionTypes.h>
63 #endif
64
65 ////////////////////////////////
66
67 // declarations - since a mex file cannot use local includes
68
69 typedef enum
70 {
71 TYPE_BOOL
72 , TYPE_CHAR
73 , TYPE_DOUBLE
74 , TYPE_INT
75 , TYPE_ELEMENT
76 , TYPE_UINT
77 , TYPE_UNKNOWN
78 } FieldType_t;
79
80 const char* FIELDTYPE_STRINGS[] =
81 {
82 "bool"
83 , "char"
84 , "double"
85 , "int"
86 , "structure"
87 , "uint"
88 };
89
90 typedef enum {
91 OTHER_NAME = 0
92 , SBML_NOTES
93 , SBML_ANNOT
94 , OTHER_NAMESPACES
95 , OTHER_CVTERMS
96 , SBML_MATH
97 , SBML_RULE_TYPE
98 , SBML_ISSET
99 , SBML_MESSAGE
100 , OTHER_TIME_SYMBOL
101 , OTHER_DELAY_SYMBOL
102 , OTHER_AVOGADRO_SYMBOL
103 , OTHER_RATEOF_SYMBOL
104 , OTHER_ANOMALOUS_MATH
105 , FBC_ASSOCIATION
106
107 , SBML_KNOWN_ATT_ELEM = 20
108
109 } FieldnamesType_t;
110
111 struct FieldValues_t {
112 std::string fieldName;
113 std::string sbmlName;
114 std::string prefix;
115 FieldType_t type;
116 bool isSBMLAttribute;
117 FieldnamesType_t fieldnameType;
118 std::string strValue;
119 int iValue;
120 double dValue;
121 };
122
123
124 class StructureFields
125 {
126 public:
127
128 StructureFields(SBase* obj, mxArray* structure);
129
130 StructureFields(SBase* obj);
131
132 StructureFields(std::string& tc);
133
134 ~StructureFields();
135
136
137 void addAttributes(const std::string& functionId, unsigned int index = 0,
138 unsigned int total_no = 0);
139
140 void createStructure(const std::string& functionId, SBase* base, bool usePlugin = false,
141 const std::string& prefix = "");
142
getTypeCode() const143 const std::string& getTypeCode() const { return sbmlTC; };
144
getStructure() const145 mxArray* getStructure() const { return mxStructure; };
146
147 static const std::string readString(mxArray* mxArray1, const std::string& name,
148 unsigned int index);
149
150 static unsigned int readUint(mxArray* mxArry1, const std::string& name,
151 unsigned int index);
152
153 static int readInt(mxArray* mxArry1, const std::string& name, unsigned int index);
154
155 static void reportReadError(const std::string& type, const std::string& name,
156 unsigned int index, unsigned int total_no,
157 const std::string& tc);
158
159 private:
160 void populateFields();
161
162 void determineTypeCode();
163
164 void populateStructure(const std::string& functionId, SBase* base,
165 unsigned int index);
166
167 void addStructureField(const std::string& functionId, SBase* base,
168 unsigned int index, FieldValues_t field, bool usePlugin);
169
170 void addChildElement(FieldValues_t field, unsigned int index);
171
172 void setAttribute(FieldValues_t field,
173 unsigned int index = 0, unsigned int total_no = 0);
174
175
176 const std::string getFieldname(unsigned int i, const std::string& id);
177 const std::string getDefaultValue(unsigned int i, const std::string& id);
178 void getDefaultValue(unsigned int i, const std::string& id, double& value);
179 void getDefaultValue(unsigned int i, const std::string& id, int& value);
180 const FieldType_t getValueType(unsigned int i, const std::string& id);
181 bool getIsSBMLAttribute(unsigned int i, const std::string& id);
182 const std::string getSBMLPrefix(unsigned int i, const std::string& id);
183 const std::string getSBMLName(unsigned int i, const std::string& id);
184 const FieldnamesType_t getNameEnumType(unsigned int i, const std::string& id);
185
186 // read values from structure
187 int readInt(const std::string& name, unsigned int index, unsigned int total_no);
188
189 double readDouble(const std::string& name, unsigned int index, unsigned int total_no);
190
191 const std::string readString(const std::string& name, unsigned int index, unsigned int total_no);
192
193 unsigned int readUint(const std::string& name, unsigned int index, unsigned int total_no);
194
195 // need to further work out which type of rule
196 const std::string getRuleType(mxArray* mxRuleStructure, unsigned int index);
197 std::string getRuleTypeCode(SBase* base);
198 std::string getAssociationTypeCode(SBase* base);
199
200
201 void addAnomalousChild(FieldValues_t field);
202
203 void addAnomalousChildStructure(const std::string& functionId, SBase* base,
204 unsigned int index, FieldValues_t field);
205
206 const ASTNode* getMathChild(const std::string& value);
207
208 char * convertMathFormula(const std::string& pacFormula);
209
210 void adjustForCSymbols(ASTNode * math);
211
212 // read values from model or default
213 const std::string getStringValue(const std::string& functionId, SBase* base,
214 FieldValues_t field, bool usePlugin);
215
216 double getDoubleValue(const std::string& functionId, SBase* base,
217 FieldValues_t field, bool usePlugin);
218
219 bool getBoolValue(const std::string& functionId, SBase* base,
220 FieldValues_t field, bool usePlugin);
221
222 unsigned int getUintValue(const std::string& functionId, SBase* base,
223 FieldValues_t field, bool usePlugin);
224
225 int getIntValue(const std::string& functionId, SBase* base,
226 FieldValues_t field, bool usePlugin);
227
228 std::string getMathString(SBase* base);
229
230 char * GetMatlabFormula(char * pacFormula, std::string object);
231
232 void lookForCSymbols(ASTNode* math);
233
234 void dealWithTimeSymbol(ASTNode* math);
235
236 void dealWithDelaySymbol(ASTNode* math);
237
238 void dealWithAvogadroSymbol(ASTNode* math);
239
240 void dealWithRateOfSymbol(ASTNode* math);
241
242 bool determineStatus(const std::string& name, unsigned int index);
243
244 void reportReadError(const std::string& type, const std::string& name,
245 unsigned int index, unsigned int total_no);
246
247
248 bool usingPlugin(const std::string& prefix, SBase* base = NULL);
249
250 mxArray* getNamespacesStructure();
251
252 mxArray* getCVTermsStructure(SBase* base);
253
254 void addCVTerms(unsigned int index);
255
256 void freeStructureMemory();
257
258 protected:
259
260 mxArray* mxFieldnames;
261 mxArray* mxDefaultValues;
262 mxArray* mxValueTypes;
263
264 size_t nNumberFields;
265
266 mxArray* mxStructure;
267
268 SBase* mSBase;
269 std::string sbmlTC;
270
271 std::vector<FieldValues_t> mFields;
272 };
273
274 typedef std::map<const std::string, unsigned int> PkgMap;
275 typedef PkgMap::iterator PkgIter;
276
277 class ModelDetails
278 {
279 public:
280 ModelDetails();
281
282 ModelDetails(SBMLDocument *doc);
283
~ModelDetails()284 ~ModelDetails() { };
285
getLevel()286 unsigned int getLevel() {return mLevel; } ;
getVersion()287 unsigned int getVersion() { return mVersion; } ;
288
getDelaySymbol()289 const std::string& getDelaySymbol() { return mDelaySymbol; } ;
getTimeSymbol()290 const std::string& getTimeSymbol() { return mTimeSymbol; } ;
getAvogadroSymbol()291 const std::string& getAvogadroSymbol() { return mAvogadroSymbol; } ;
getRateOfSymbol()292 const std::string& getRateOfSymbol() { return mRateOfSymbol; } ;
293
setDelaySymbol(const std::string & symbol)294 void setDelaySymbol(const std::string& symbol) { mDelaySymbol = symbol; } ;
setAvogadroSymbol(const std::string & symbol)295 void setAvogadroSymbol(const std::string& symbol) { mAvogadroSymbol = symbol; } ;
setTimeSymbol(const std::string & symbol)296 void setTimeSymbol(const std::string& symbol) { mTimeSymbol = symbol; } ;
setRateOfSymbol(const std::string & symbol)297 void setRateOfSymbol(const std::string& symbol) { mRateOfSymbol = symbol; } ;
298
getNamespaces()299 SBMLNamespaces* getNamespaces() { return mSBMLns; };
300
getPackages()301 PkgMap getPackages() { return mPackageMap; };
302
303 bool isPackagePresent(const std::string& pkg);
304
305
306 protected:
307
308 void populateNamespaces();
309 void populateNamespaces(SBMLDocument* doc);
310 void populatePkgMap();
311 void populatePkgMap(SBMLDocument* doc);
312 void populateSupportedPackages();
313
314 bool isSupportedPackageNS(const std::string& uri, const std::string prefix);
315
316 unsigned int mLevel;
317 unsigned int mVersion;
318
319 std::string mDelaySymbol;
320 std::string mTimeSymbol;
321 std::string mAvogadroSymbol;
322 std::string mRateOfSymbol;
323
324 SBMLNamespaces *mSBMLns;
325
326 IdList mSupportedPackages;
327
328 PkgMap mPackageMap;
329
330 };
331
332 ///////////////////////////////////////////////////////////////////////////////
333
334 // global variables
335 mxArray *modelArray = NULL;
336 bool freeMemory;
337 ModelDetails * details;
338
339 IdList reqdPkgPrefixes;
340 IdList unreqdPkgPrefixes;
341
342 bool fbcUsingId;
343 bool fbcAddGeneProducts;
344 bool onlyExpectedFields;
345 bool applyUserValidation;
346
347 //////////////////////////////////////////////////////////////////////////////
348 //
349 // StructureFields.cpp
350
351 //////////////////////////////////////////////////////////////////////////////
352 //
353 // report error/free memory and exit when error encountered
354
FreeMem(void)355 void FreeMem(void)
356 {
357 /* destroy arrays created */
358 mxDestroyArray(modelArray);
359 }
360
361 void
reportError(const std::string & id,const std::string & message)362 reportError(const std::string&id, const std::string& message)
363 {
364 if (freeMemory)
365 {
366 FreeMem();
367 }
368
369 mexErrMsgIdAndTxt(id.c_str(), message.c_str());
370 }
371
372 ////////////////////////////////////////////////////////////////////////////
373
374 // useful global functions
375
376 mxArray *
CreateIntScalar(int nValue)377 CreateIntScalar (int nValue)
378 {
379 mxArray * pArray;
380 int * panData;
381
382 pArray = mxCreateNumericMatrix(1,1,mxINT32_CLASS, mxREAL);
383 panData = (int *)mxGetData(pArray);
384 panData[0] = nValue;
385
386 return pArray;
387 }
388
389
390 FieldType_t
getFieldType(const char * type)391 getFieldType(const char* type)
392 {
393 if (type != NULL)
394 {
395 const FieldType_t lo = TYPE_BOOL;
396 const FieldType_t hi = (const FieldType_t)(TYPE_UNKNOWN - 1);
397
398 return (FieldType_t)util_bsearchStringsI(FIELDTYPE_STRINGS, type, lo, hi);
399 }
400 else
401 return TYPE_UNKNOWN;
402 }
403
404 // only used by OutputSBML
getRequiredStatus(const std::string & prefix)405 bool getRequiredStatus(const std::string& prefix)
406 {
407 bool required = false;
408
409 if (reqdPkgPrefixes.contains(prefix))
410 {
411 required = true;
412 }
413
414 return required;
415 }
416
populatePackageLists()417 void populatePackageLists()
418 {
419 //reqdPkgPrefixes.append("comp");
420 //reqdPkgPrefixes.append("spatial");
421
422 unreqdPkgPrefixes.append("fbc");
423 unreqdPkgPrefixes.append("qual");
424 unreqdPkgPrefixes.append("groups");
425 }
426
427 // only used by OutputSBML
428 bool
isUnknownType(std::string tc)429 isUnknownType(std::string tc)
430 {
431 // TO DO
432 if (tc == "(Unknown SBML Type)")
433 return true;
434 else if (tc == "(Unknown SBML Fbc Type)")
435 return true;
436 else if (tc == "(Unknown SBML Groups Type)")
437 return true;
438 else if (tc == "(Unknown SBML Qual Type)")
439 return true;
440 else
441 return false;
442 }
443
444 //////////////////////////////////////////////////////////////////////////////
445 //
446 // class to store the structure/retrieve fields and write the SBML Model
447
448 // only used by OutputSBML
StructureFields(SBase * obj,mxArray * structure)449 StructureFields::StructureFields(SBase* obj, mxArray* structure) :
450 mSBase ( NULL)
451 , mxStructure ( NULL )
452 , sbmlTC ("")
453 {
454 mSBase = obj;
455 mxStructure = structure;
456
457 determineTypeCode();
458 populateFields();
459 }
460
461 // only used by OutputSBML
StructureFields(SBase * obj)462 StructureFields::StructureFields(SBase* obj) :
463 mSBase ( NULL)
464 , mxStructure ( NULL )
465 , sbmlTC ("")
466 {
467 mSBase = obj;
468
469 determineTypeCode();
470 populateFields();
471 }
472
473 // only used by TranslateSBML
StructureFields(std::string & tc)474 StructureFields::StructureFields(std::string& tc) :
475 mSBase ( NULL)
476 , mxStructure ( NULL )
477 , sbmlTC ( tc )
478 {
479 populateFields();
480 }
481
482
~StructureFields()483 StructureFields::~StructureFields()
484 {
485 mFields.clear();
486 // must not do this as it can be a part of a larger model
487 // delete mSBase;
488
489 // MATLAB says dont call destroy array in a destructor
490 // https://uk.mathworks.com/help/matlab/matlab_external/memory-management-issues.html
491 //mxDestroyArray(mxStructure);
492 //mxDestroyArray(mxFieldnames);
493 //mxDestroyArray(mxDefaultValues);
494 //mxDestroyArray(mxValueTypes);
495 }
496
497 void
freeStructureMemory()498 StructureFields::freeStructureMemory()
499 {
500 mxDestroyArray(mxFieldnames);
501 mxDestroyArray(mxDefaultValues);
502 mxDestroyArray(mxValueTypes);
503 // do not delete in output as the structure is being recursively used
504 if (mxStructure) mxDestroyArray(mxStructure);
505 }
506
507 void
determineTypeCode()508 StructureFields::determineTypeCode()
509 {
510 if (!sbmlTC.empty()) return;
511 else if (mSBase == NULL) return;
512
513 PkgMap pm = details->getPackages();
514
515 sbmlTC = SBMLTypeCode_toString(mSBase->getTypeCode(), "core");
516 // check whether we are using a package object
517 PkgIter it = pm.begin();
518
519 while (isUnknownType(sbmlTC) && it != pm.end())
520 {
521 sbmlTC = SBMLTypeCode_toString(mSBase->getTypeCode(), (it->first).c_str());
522 sbmlTC[0] = tolower(sbmlTC[0]);
523 ++it;
524 }
525 }
526
527 void
populateFields()528 StructureFields::populateFields()
529 {
530 // the array size will need to accomadate all packages
531 PkgMap pm = details->getPackages();
532 mxArray *mxOutputs[4];
533 unsigned int numPlugins = (unsigned int)(pm.size());
534 if (numPlugins > 0)
535 {
536 int numberInputs = 5;
537
538 mxArray *mxInput[5];
539
540 std::string id = std::string("StructureFields:populateFields:") + sbmlTC;
541
542 // hack for level 1 rules
543 if (sbmlTC == "AssignmentRule" || sbmlTC == "RateRule")
544 {
545 int L1TC = ((Rule*)(mSBase))->getL1TypeCode();
546 if (L1TC == SBML_UNKNOWN)
547 {
548 mxInput[0] = mxCreateString(sbmlTC.c_str());
549 }
550 else
551 {
552 mxInput[0] = mxCreateString(SBMLTypeCode_toString(L1TC, "core"));
553 }
554 }
555 else
556 {
557 mxInput[0] = mxCreateString(sbmlTC.c_str());
558 }
559 mxInput[1] = CreateIntScalar(details->getLevel());
560 mxInput[2] = CreateIntScalar(details->getVersion());
561 mwSize dims[1] = { numPlugins };
562 mxInput[3] = mxCreateCellArray(1, dims);
563 mxInput[4] = mxCreateDoubleMatrix(1, numPlugins, mxREAL);
564 double *pinput4 = mxGetPr(mxInput[4]);
565 unsigned int inputCount = 0;
566 for (PkgIter it = pm.begin(); it != pm.end(); ++it)
567 {
568 mxSetCell(mxInput[3], inputCount, mxCreateString((it->first).c_str()));
569 pinput4[inputCount] = it->second;
570 inputCount++;
571 }
572
573 mxArray * exception = NULL;
574 exception = mexCallMATLABWithTrap(4, mxOutputs, numberInputs, mxInput, "getStructure");
575 if (exception != 0)
576 {
577 mexCallMATLAB(0, (mxArray **)NULL, 1, &exception, "throw");
578
579 reportError(id, "Failed to get fieldnames");
580 }
581 mxDestroyArray(mxInput[0]);
582 mxDestroyArray(mxInput[1]);
583 mxDestroyArray(mxInput[2]);
584 mxDestroyArray(mxInput[3]);
585 mxDestroyArray(mxInput[4]);
586 }
587 else
588 {
589 int numberInputs = 3;
590
591 mxArray *mxInput[3];
592
593 std::string id = std::string("StructureFields:populateFields:") + sbmlTC;
594
595 // hack for level 1 rules
596 if (sbmlTC == "AssignmentRule" || sbmlTC == "RateRule")
597 {
598 int L1TC = ((Rule*)(mSBase))->getL1TypeCode();
599 if (L1TC == SBML_UNKNOWN)
600 {
601 mxInput[0] = mxCreateString(sbmlTC.c_str());
602 }
603 else
604 {
605 mxInput[0] = mxCreateString(SBMLTypeCode_toString(L1TC, "core"));
606 }
607 }
608 else
609 {
610 mxInput[0] = mxCreateString(sbmlTC.c_str());
611 }
612 mxInput[1] = CreateIntScalar(details->getLevel());
613 mxInput[2] = CreateIntScalar(details->getVersion());
614
615 mxArray * exception = NULL;
616 exception = mexCallMATLABWithTrap(4, mxOutputs, numberInputs, mxInput, "getStructure");
617 if (exception != 0)
618 {
619 mexCallMATLAB(0, (mxArray **)NULL, 1, &exception, "throw");
620
621 reportError(id, "Failed to get fieldnames");
622 }
623 mxDestroyArray(mxInput[0]);
624 mxDestroyArray(mxInput[1]);
625 mxDestroyArray(mxInput[2]);
626 }
627
628 mxFieldnames = mxDuplicateArray(mxOutputs[0]);
629 mxDefaultValues = mxDuplicateArray(mxOutputs[1]);
630 mxValueTypes = mxDuplicateArray(mxOutputs[2]);
631 nNumberFields = (int)mxGetScalar(mxOutputs[3]);
632
633 mxDestroyArray(mxOutputs[0]);
634 mxDestroyArray(mxOutputs[1]);
635 mxDestroyArray(mxOutputs[2]);
636 mxDestroyArray(mxOutputs[3]);
637
638 for (unsigned int i = 0; i < nNumberFields; ++i)
639 {
640 FieldValues_t field;
641 field.fieldName = getFieldname(i, "populate");
642 field.type = getValueType(i, "populate");
643 field.sbmlName = getSBMLName(i, "populate");
644 field.prefix = getSBMLPrefix(i, "populate");
645 field.isSBMLAttribute = getIsSBMLAttribute(i, "populate");
646 field.fieldnameType = getNameEnumType(i, "populate");
647 switch (field.type)
648 {
649 case TYPE_BOOL:
650 case TYPE_INT:
651 case TYPE_UINT:
652 getDefaultValue(i, "populate", field.iValue);
653 break;
654 case TYPE_CHAR:
655 case TYPE_UNKNOWN:
656 field.strValue = getDefaultValue(i, "populate");
657 break;
658 case TYPE_DOUBLE:
659 getDefaultValue(i, "populate", field.dValue);
660 break;
661 default:
662 break;
663 }
664 mFields.push_back(field);
665 }
666 }
667
668
669 const std::string
getSBMLPrefix(unsigned int i,const std::string & id)670 StructureFields::getSBMLPrefix(unsigned int i, const std::string& id)
671 {
672 mxArray* mxField = mxGetCell(mxFieldnames, i);
673 mxArray* mxAttPrefix = mxGetCell(mxField, 2);
674 size_t nBuflen = (mxGetM(mxAttPrefix)*mxGetN(mxAttPrefix) + 1);
675 char * fieldname = (char *)mxCalloc(nBuflen, sizeof(char));
676 if (mxGetString(mxAttPrefix, (char *)fieldname, (mwSize)(nBuflen)) != 0)
677 {
678 reportError(id, "Failed in getSBMLPrefix");
679 }
680 const std::string f = std::string(fieldname);
681 mxFree(fieldname);
682 return f;
683 }
684
685 const std::string
getSBMLName(unsigned int i,const std::string & id)686 StructureFields::getSBMLName(unsigned int i, const std::string& id)
687 {
688 mxArray* mxField = mxGetCell(mxFieldnames, i);
689 mxArray* mxAttPrefix = mxGetCell(mxField, 1);
690 size_t nBuflen = (mxGetM(mxAttPrefix)*mxGetN(mxAttPrefix) + 1);
691 char * fieldname = (char *)mxCalloc(nBuflen, sizeof(char));
692 if (mxGetString(mxAttPrefix, (char *)fieldname, (mwSize)(nBuflen)) != 0)
693 {
694 reportError(id, "Failed in getSBMLName");
695 }
696 const std::string f = std::string(fieldname);
697 mxFree(fieldname);
698 return f;
699 }
700
701 bool
getIsSBMLAttribute(unsigned int i,const std::string & id)702 StructureFields::getIsSBMLAttribute(unsigned int i, const std::string& id)
703 {
704 mxArray* mxField = mxGetCell(mxFieldnames, i);
705 mxArray* mxSBMLAtt = mxGetCell(mxField, 3);
706 int value = (int)mxGetScalar(mxSBMLAtt);
707 if (value == 0) return false;
708 else return true;
709 }
710
711 const FieldnamesType_t
getNameEnumType(unsigned int i,const std::string & id)712 StructureFields::getNameEnumType(unsigned int i, const std::string& id)
713 {
714 mxArray* mxField = mxGetCell(mxFieldnames, i);
715 mxArray* mxSBMLAtt = mxGetCell(mxField, 4);
716 int value = (int)mxGetScalar(mxSBMLAtt);
717 return (FieldnamesType_t)(value);
718
719 }
720
721 const std::string
getFieldname(unsigned int i,const std::string & id)722 StructureFields::getFieldname(unsigned int i, const std::string& id)
723 {
724 mxArray* mxField = mxGetCell(mxFieldnames, i);
725 mxArray* mxName = mxGetCell(mxField, 0);
726 size_t nBuflen = (mxGetM(mxName)*mxGetN(mxName)+1);
727 char * fieldname = (char *) mxCalloc(nBuflen, sizeof(char));
728 if (mxGetString(mxName, (char *) fieldname, (mwSize)(nBuflen)) != 0)
729 {
730 reportError(id, "Failed in GetFieldname");
731 }
732 const std::string f = std::string(fieldname);
733 mxFree(fieldname);
734 return f;
735 }
736
737 const std::string
getDefaultValue(unsigned int i,const std::string & id)738 StructureFields::getDefaultValue(unsigned int i, const std::string& id)
739 {
740 mxArray* mxName = mxGetCell(mxDefaultValues, i);
741 size_t nBuflen = (mxGetM(mxName)*mxGetN(mxName)+1);
742 char * fieldname = (char *) mxCalloc(nBuflen, sizeof(char));
743 if (mxGetString(mxName, (char *) fieldname, (mwSize)(nBuflen)) != 0)
744 {
745 reportError(id, "Failed in GetDefaultValue");
746 }
747 const std::string f = std::string(fieldname);
748 mxFree(fieldname);
749 return f;
750 }
751
752 void
getDefaultValue(unsigned int i,const std::string & id,double & value)753 StructureFields::getDefaultValue(unsigned int i, const std::string& id, double& value)
754 {
755 mxArray* mxName = mxGetCell(mxDefaultValues, i);
756 value = (double) mxGetScalar(mxName);
757 }
758
759 void
getDefaultValue(unsigned int i,const std::string & id,int & value)760 StructureFields::getDefaultValue(unsigned int i, const std::string& id, int& value)
761 {
762 mxArray* mxName = mxGetCell(mxDefaultValues, i);
763 value = (int) mxGetScalar(mxName);
764 }
765
766 const FieldType_t
getValueType(unsigned int i,const std::string & id)767 StructureFields::getValueType(unsigned int i, const std::string& id)
768 {
769 mxArray* mxName = mxGetCell(mxValueTypes, i);
770 size_t nBuflen = (mxGetM(mxName)*mxGetN(mxName)+1);
771 char * fieldname = (char *) mxCalloc(nBuflen, sizeof(char));
772 if (mxGetString(mxName, (char *) fieldname, (mwSize)(nBuflen)) != 0)
773 {
774 mxFree(fieldname);
775 reportError(id, "Failed in GetValueType");
776 }
777 FieldType_t ft = getFieldType(fieldname);
778 mxFree(fieldname);
779 return ft;
780 }
781
782 //////////////////////////
783
784 // functions for creating structure from SBML
785
786 void
createStructure(const std::string & functionId,SBase * base,bool usePlugin,const std::string & prefix)787 StructureFields::createStructure(const std::string& functionId, SBase* base,
788 bool usePlugin, const std::string& prefix)
789 {
790 std::string fieldname;
791 unsigned int total_no = base->getNumObjects(sbmlTC);
792 if (usePlugin)
793 {
794 total_no = base->getPlugin(prefix)->getNumObjects(sbmlTC);
795 }
796 mwSize dims[2] = {1, total_no};
797
798 char **field_names = (char**)(safe_malloc(nNumberFields * sizeof(char*)));
799 for (unsigned int i = 0; i < nNumberFields; ++i)
800 {
801 fieldname = mFields.at(i).fieldName;
802 field_names[i] = (char*)(safe_malloc((fieldname.size() * sizeof(char))+ 1));
803 field_names[i] = safe_strdup(fieldname.c_str());
804 }
805
806 mxStructure = mxCreateStructArray(2, dims, nNumberFields, (const char**)(field_names));
807 safe_free(field_names);
808
809 for (unsigned int i = 0; i < total_no; ++i)
810 {
811 SBase* child = base->getObject(sbmlTC, i);
812 if (usePlugin)
813 {
814 child = base->getPlugin(prefix)->getObject(sbmlTC, i);
815 }
816 populateStructure(functionId, child, i);
817 }
818
819 }
820
821 void
populateStructure(const std::string & functionId,SBase * base,unsigned int index)822 StructureFields::populateStructure(const std::string& functionId, SBase* base, unsigned int index)
823 {
824 if (base == NULL) return;
825
826 FieldType_t type;
827 FieldnamesType_t nameType;
828
829 for (unsigned int i = 0; i < nNumberFields; ++i)
830 {
831 FieldValues_t field = mFields.at(i);
832 type = field.type;
833 nameType = field.fieldnameType;
834 bool usePlugin = usingPlugin(field.prefix, base);
835
836 if (type == TYPE_ELEMENT)
837 {
838 switch (nameType) {
839 case OTHER_NAMESPACES:
840 mxSetField(mxStructure, index, field.fieldName.c_str(), getNamespacesStructure());
841 break;
842 case OTHER_CVTERMS:
843 mxSetField(mxStructure, index, field.fieldName.c_str(), getCVTermsStructure(base));
844 break;
845 default:
846 StructureFields *sf = new StructureFields(field.sbmlName);
847 sf->createStructure(functionId + ":" + field.fieldName, base, usePlugin, field.prefix);
848 mxSetField(mxStructure, index, field.fieldName.c_str(), mxDuplicateArray(sf->getStructure()));
849 sf->freeStructureMemory();
850 delete sf;
851 break;
852 }
853 }
854 else if (field.fieldnameType == OTHER_ANOMALOUS_MATH)
855 {
856 addAnomalousChildStructure(functionId, base, index, field);
857 }
858 else
859 {
860 addStructureField(functionId, base, index, field, usePlugin);
861 }
862
863 }
864 }
865
866 void
addAnomalousChildStructure(const std::string & functionId,SBase * base,unsigned int index,FieldValues_t field)867 StructureFields::addAnomalousChildStructure(const std::string& functionId, SBase* base,
868 unsigned int index, FieldValues_t field)
869 {
870 std::string value;
871 SBase* child = base->getObject(field.fieldName, 0);
872 if (child == NULL)
873 {
874 value = field.strValue;
875 }
876 else
877 {
878 value = getMathString(child);
879 }
880
881 mxSetField(mxStructure, index, field.fieldName.c_str() ,mxCreateString(value.c_str()));
882 }
883
884 mxArray*
getNamespacesStructure()885 StructureFields::getNamespacesStructure()
886 {
887 mxArray* mxNSReturn = NULL;
888
889 const XMLNamespaces * NS = details->getNamespaces()->getNamespaces();
890 int n = NS->getLength();
891 mwSize dims[2] = {1, (mwSize)(n)};
892
893 /* fields within a namespace structure */
894 const int nNoFields = 2;
895 const char *field_names[] = {
896 "prefix",
897 "uri"
898 };
899
900
901 const char * pacPrefix = NULL;
902 const char * pacURI = NULL;
903
904 int i;
905
906 mxNSReturn = mxCreateStructArray(2, dims, nNoFields, field_names);
907
908 for (i = 0; i < n; ++i)
909 {
910 pacPrefix = safe_strdup(NS->getPrefix(i).c_str());
911 pacURI = safe_strdup(NS->getURI(i).c_str());
912
913 /**
914 * check for NULL strings - Matlab doesnt like creating
915 * a string that is NULL
916 */
917 if (pacPrefix == NULL) {
918 pacPrefix = "";
919 }
920 if (pacURI == NULL) {
921 pacURI = "";
922 }
923
924 mxSetField(mxNSReturn, i, "prefix", mxCreateString(pacPrefix));
925 mxSetField(mxNSReturn, i, "uri", mxCreateString(pacURI));
926
927 safe_free((void*)(pacPrefix));
928 safe_free((void*)(pacURI));
929 }
930
931 return mxNSReturn;
932 }
933
934 mxArray*
createCVTermStructure(int num)935 createCVTermStructure(int num)
936 {
937 mxArray* mxCVTermReturn;
938 mwSize dims[2] = {1, (mwSize)(num)};
939
940 /* fields within a cvterm structure */
941 const int nNoFields = 4;
942 const char *field_names[] = {
943 "qualifierType",
944 "qualifier",
945 "resources",
946 "cvterms"
947 };
948
949 mxCVTermReturn = mxCreateStructArray(2, dims, nNoFields, field_names);
950
951 return mxCVTermReturn;
952 }
953
954
955
956 void
addCVTerm(mxArray * mxCVTermReturn,int i,CVTerm * cv)957 addCVTerm (mxArray* mxCVTermReturn, int i, CVTerm* cv)
958 {
959 const char * pacQualifier = NULL;
960 const char * pacQualifierType = NULL;
961 mxArray* mxResources = NULL;
962
963 if (cv->getQualifierType() == BIOLOGICAL_QUALIFIER)
964 {
965 std::string bq = "biological";
966 pacQualifierType = (char*)(safe_malloc((bq.size() * sizeof(char))+ 1));
967 pacQualifierType = safe_strdup(bq.c_str());
968
969 size_t s = sizeof((const char *)(BiolQualifierType_toString(cv->getBiologicalQualifierType()))) * sizeof(char);
970 pacQualifier = (char*)(safe_malloc(s + 1));
971 pacQualifier = safe_strdup(BiolQualifierType_toString(cv->getBiologicalQualifierType()));
972 }
973 else if (cv->getQualifierType() == MODEL_QUALIFIER)
974 {
975 std::string bq = "model";
976 pacQualifierType = (char*)(safe_malloc((bq.size() * sizeof(char))+ 1));
977 pacQualifierType = safe_strdup(bq.c_str());
978
979 size_t s = sizeof((const char *)(ModelQualifierType_toString(cv->getModelQualifierType()))) * sizeof(char);
980 pacQualifier = (char*)(safe_malloc(s + 1));
981 pacQualifier = safe_strdup(ModelQualifierType_toString(cv->getModelQualifierType()));
982 }
983 else
984 {
985 std::string bq = "unknown";
986 pacQualifierType = (char*)(safe_malloc((bq.size() * sizeof(char))+ 1));
987 pacQualifierType = safe_strdup(bq.c_str());
988
989 pacQualifier = (char*)(safe_malloc((bq.size() * sizeof(char))+ 1));
990 pacQualifier = safe_strdup(bq.c_str());
991
992 }
993 mwSize num = cv->getNumResources();
994 std::string fieldname;
995
996 char **resources = (char**)(safe_malloc(num * sizeof(char*)));
997 for (unsigned int j = 0; j < num; j++)
998 {
999 fieldname = cv->getResourceURI(j);
1000 size_t s = (fieldname.size() * sizeof(char)) + 1;
1001 resources[j] = (char*)(safe_malloc(s));
1002 resources[j] = safe_strdup(fieldname.c_str());
1003 }
1004
1005 mxResources = mxCreateCellMatrix(1, num);
1006 for (unsigned int j = 0; j < num; j++)
1007 {
1008 mxSetCell(mxResources, j, mxCreateString(resources[j]));
1009 }
1010
1011 mxSetField(mxCVTermReturn, i, "qualifierType", mxCreateString(pacQualifierType));
1012 mxSetField(mxCVTermReturn, i, "qualifier", mxCreateString(pacQualifier));
1013 mxSetField(mxCVTermReturn, i, "resources", mxResources);
1014
1015 unsigned int numNested = cv->getNumNestedCVTerms();
1016 if (cv->getNumNestedCVTerms() > 0)
1017 {
1018 mxArray* mxNested = createCVTermStructure(numNested);
1019 for (unsigned int j = 0; j < numNested; j++)
1020 {
1021 addCVTerm(mxNested, j, cv->getNestedCVTerm(j));
1022 }
1023 mxSetField(mxCVTermReturn, i, "cvterms", mxNested);
1024 }
1025
1026 safe_free((void*)(pacQualifier));
1027 safe_free((void*)(pacQualifierType));
1028 safe_free(resources);
1029 }
1030
1031
1032 mxArray*
getCVTermsStructure(SBase * base)1033 StructureFields::getCVTermsStructure(SBase* base)
1034 {
1035 mxArray* mxCVTermReturn = NULL;
1036
1037 int n = base->getNumCVTerms();
1038 if (n > 0)
1039 {
1040 mxCVTermReturn = createCVTermStructure(n);
1041 }
1042
1043 for (int i = 0; i < n; ++i)
1044 {
1045 CVTerm * cv = base->getCVTerm(i);
1046 addCVTerm(mxCVTermReturn, i, cv);
1047 }
1048
1049 return mxCVTermReturn;
1050 }
1051
1052
1053 void
addStructureField(const std::string & functionId,SBase * base,unsigned int index,FieldValues_t field,bool usePlugin)1054 StructureFields::addStructureField(const std::string& functionId, SBase* base,
1055 unsigned int index, FieldValues_t field,
1056 bool usePlugin)
1057 {
1058 std::string value;
1059 int ivalue;
1060 unsigned int uvalue;
1061 bool bvalue;
1062 double dvalue;
1063 switch (field.type)
1064 {
1065 case TYPE_UNKNOWN:
1066
1067 case TYPE_CHAR:
1068 value = getStringValue(functionId, base, field, usePlugin);
1069 mxSetField(mxStructure, index, field.fieldName.c_str(), mxCreateString(value.c_str()));
1070 break;
1071 case TYPE_BOOL:
1072 bvalue = getBoolValue(functionId, base, field, usePlugin);
1073 mxSetField(mxStructure, index, field.fieldName.c_str(), CreateIntScalar(bvalue));
1074 break;
1075 case TYPE_UINT:
1076 uvalue = getUintValue(functionId, base, field, usePlugin);
1077 mxSetField(mxStructure, index, field.fieldName.c_str(), CreateIntScalar(uvalue));
1078 break;
1079 case TYPE_INT:
1080 ivalue = getIntValue(functionId, base, field, usePlugin);
1081 mxSetField(mxStructure, index, field.fieldName.c_str(), CreateIntScalar(ivalue));
1082 break;
1083 case TYPE_DOUBLE:
1084 dvalue = getDoubleValue(functionId, base, field, usePlugin);
1085 mxSetField(mxStructure, index, field.fieldName.c_str(), mxCreateDoubleScalar(dvalue));
1086 break;
1087 case TYPE_ELEMENT:
1088 default:
1089 break;
1090 }
1091 }
1092
1093 const std::string
getStringValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1094 StructureFields::getStringValue(const std::string& functionId, SBase* base,
1095 FieldValues_t field,
1096 bool usePlugin)
1097 {
1098 std::string value;
1099
1100 if (field.isSBMLAttribute)
1101 {
1102 bool useDefault = true;
1103 switch (field.fieldnameType)
1104 {
1105 case SBML_NOTES:
1106 value = base->getNotesString();
1107 useDefault = false;
1108 break;
1109 case SBML_ANNOT:
1110 value = base->getAnnotationString();
1111 useDefault = false;
1112 break;
1113 case SBML_MESSAGE:
1114 value = base->getMessageString();
1115 useDefault = false;
1116 break;
1117 case SBML_MATH:
1118 value = getMathString(base);
1119 useDefault = false;
1120 break;
1121 default:
1122 if (!usePlugin && base->isSetAttribute(field.sbmlName))
1123 {
1124 base->getAttribute(field.sbmlName, value);
1125 useDefault = false;
1126 }
1127 else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1128 {
1129 base->getPlugin(field.prefix)->getAttribute(field.sbmlName, value);
1130 useDefault = false;
1131 }
1132 break;
1133
1134 }
1135 #ifdef USE_FBC
1136
1137 if (field.fieldnameType == FBC_ASSOCIATION)
1138 {
1139 value = static_cast<FbcAssociation*>(base)->toInfix(fbcUsingId);//FbcAssociation_toInfix(static_cast<FbcAssociation*>(base));
1140 useDefault = false;
1141 }
1142 #endif
1143
1144 if (useDefault)
1145 {
1146 value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1147 }
1148 }
1149 else
1150 {
1151 switch (field.fieldnameType)
1152 {
1153 case SBML_RULE_TYPE:
1154 value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1155 if (field.fieldName == "type" && base->getTypeCode() == SBML_RATE_RULE)
1156 {
1157 value = "rate";
1158 }
1159 break;
1160 case OTHER_AVOGADRO_SYMBOL:
1161 if (!details->getAvogadroSymbol().empty())
1162 {
1163 value = details->getAvogadroSymbol();
1164 }
1165 else
1166 {
1167 value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1168 }
1169 break;
1170 case OTHER_DELAY_SYMBOL:
1171 if (!details->getDelaySymbol().empty())
1172 {
1173 value = details->getDelaySymbol();
1174 }
1175 else
1176 {
1177 value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1178 }
1179 break;
1180 case OTHER_TIME_SYMBOL:
1181 if (!details->getTimeSymbol().empty())
1182 {
1183 value = details->getTimeSymbol();
1184 }
1185 else
1186 {
1187 value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1188 }
1189 break;
1190 case OTHER_RATEOF_SYMBOL:
1191 if (!details->getRateOfSymbol().empty())
1192 {
1193 value = details->getRateOfSymbol();
1194 }
1195 else
1196 {
1197 value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1198 }
1199 break;
1200 default:
1201 value = field.strValue;// getDefaultValue(fieldIndex, functionId);
1202 /* hack for rules that all use the same fieldnames/defaults */
1203 if (value == "SBML_ALGEBRAIC_RULE")
1204 {
1205 value = getRuleTypeCode(base);
1206 }
1207 else if (value == "SBML_FBC_ASSOCIATION")
1208 {
1209 value = getAssociationTypeCode(base);
1210 }
1211 break;
1212 }
1213 }
1214
1215 return (const std::string)(value);
1216 }
1217
1218 double
getDoubleValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1219 StructureFields::getDoubleValue(const std::string& functionId, SBase* base,
1220 FieldValues_t field,
1221 bool usePlugin)
1222 {
1223 double value;
1224
1225 if (field.isSBMLAttribute)
1226 {
1227 if (!usePlugin && base->isSetAttribute(field.sbmlName))
1228 {
1229 base->getAttribute(field.sbmlName, value);
1230 }
1231 else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1232 {
1233 base->getPlugin(field.prefix)->getAttribute(field.sbmlName, value);
1234 }
1235 else
1236 {
1237 value = field.dValue;
1238 }
1239 }
1240 else
1241 {
1242 value = field.dValue;
1243 }
1244
1245 return value;
1246 }
1247
1248
1249 int
getIntValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1250 StructureFields::getIntValue(const std::string& functionId, SBase* base,
1251 FieldValues_t field,
1252 bool usePlugin)
1253 {
1254 int value;
1255
1256 if (field.isSBMLAttribute)
1257 {
1258 if (!usePlugin && base->isSetAttribute(field.sbmlName))
1259 {
1260 base->getAttribute(field.sbmlName, value);
1261 }
1262 else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1263 {
1264 base->getPlugin(field.prefix)->getAttribute(field.sbmlName, value);
1265 }
1266 else
1267 {
1268 value = field.iValue;
1269 }
1270 }
1271 else
1272 {
1273 value = field.iValue;
1274 }
1275
1276 return value;
1277 }
1278
1279
1280 unsigned int
getUintValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1281 StructureFields::getUintValue(const std::string& functionId, SBase* base,
1282 FieldValues_t field,
1283 bool usePlugin)
1284 {
1285 unsigned int value;
1286 int ivalue;
1287 bool useDefault = false;
1288 if (field.isSBMLAttribute)
1289 {
1290 if (!usePlugin && base->isSetAttribute(field.sbmlName))
1291 {
1292 base->getAttribute(field.sbmlName, value);
1293 }
1294 else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1295 {
1296 base->getPlugin(field.prefix)->getAttribute(field.sbmlName, value);
1297 }
1298 else
1299 {
1300 ivalue = field.iValue;// getDefaultValue(fieldIndex, functionId, ivalue);
1301 useDefault = true;
1302 }
1303 }
1304 else
1305 {
1306 ivalue = field.iValue;
1307 useDefault = true;
1308 }
1309
1310 if (useDefault)
1311 {
1312 return (unsigned int)(ivalue);
1313 }
1314 else
1315 {
1316 return value;
1317 }
1318 }
1319
1320
1321 bool
getBoolValue(const std::string & functionId,SBase * base,FieldValues_t field,bool usePlugin)1322 StructureFields::getBoolValue(const std::string& functionId, SBase* base,
1323 FieldValues_t field,
1324 bool usePlugin)
1325 {
1326 bool bvalue;
1327 int value;
1328 if (field.isSBMLAttribute)
1329 {
1330 if (!usePlugin && base->isSetAttribute(field.sbmlName))
1331 {
1332 base->getAttribute(field.sbmlName, bvalue);
1333 return bvalue;
1334 }
1335 else if (usePlugin && base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName))
1336 {
1337 base->getPlugin(field.prefix)->getAttribute(field.sbmlName, bvalue);
1338 return bvalue;
1339 }
1340 else
1341 {
1342 value = field.iValue;// getDefaultValue(fieldIndex, functionId, value);
1343 }
1344 }
1345 else if (field.fieldnameType == SBML_ISSET)
1346 {
1347 if (!usePlugin)
1348 {
1349 value = base->isSetAttribute(field.sbmlName);
1350 }
1351 else
1352 {
1353 value = base->getPlugin(field.prefix)->isSetAttribute(field.sbmlName);
1354 }
1355 }
1356 else
1357 {
1358 value = field.iValue;// getDefaultValue(fieldIndex, functionId, value);
1359 }
1360
1361 return (value == 0) ? false : true;
1362 }
1363
1364
1365 std::string
getMathString(SBase * base)1366 StructureFields::getMathString(SBase* base)
1367 {
1368 const ASTNode* ast = base->getMath();
1369 lookForCSymbols(const_cast<ASTNode*>(ast));
1370 char * formula = SBML_formulaToString(ast);
1371 char * matlab = GetMatlabFormula(formula, sbmlTC);
1372 std::string math = std::string(matlab);
1373 mxFree(matlab);
1374 return math;
1375
1376 }
1377
1378 char *
GetMatlabFormula(char * pacFormula,std::string object)1379 StructureFields::GetMatlabFormula(char * pacFormula, std::string object)
1380 {
1381 mxArray *mxInput[1];
1382 mxArray *mxOutput[1];
1383 int nStatus;
1384 size_t nBuflen;
1385 char * formula;
1386
1387 /* convert MathML infix formula to MATLAB */
1388
1389 mxInput[0] = mxCreateString(pacFormula);
1390 nStatus = mexCallMATLAB(1, mxOutput, 1, mxInput, "CheckAndConvert");
1391
1392 if (nStatus != 0)
1393 {
1394 std::string id = std::string("TranslateSBML:GetMatlabFormula:") + object;
1395 reportError(id.c_str(), "Failed to convert formula");
1396 }
1397
1398 /* get the formula returned */
1399 nBuflen = (mxGetM(mxOutput[0])*mxGetN(mxOutput[0])+1);
1400 formula = (char *) mxCalloc(nBuflen, sizeof(char));
1401 nStatus = mxGetString(mxOutput[0], (char *) formula, (mwSize)(nBuflen));
1402
1403 if (nStatus != 0)
1404 {
1405 std::string id = std::string("TranslateSBML:GetMatlabFormula") + object;
1406 reportError(id.c_str(), "Cannot copy formula");
1407 }
1408
1409 mxDestroyArray(mxInput[0]);
1410 mxDestroyArray(mxOutput[0]);
1411
1412 return formula;
1413 }
1414
1415 void
lookForCSymbols(ASTNode * math)1416 StructureFields::lookForCSymbols(ASTNode* math)
1417 {
1418 if (math == NULL) return;
1419
1420 unsigned int nChild = math->getNumChildren();
1421 ASTNodeType_t type = math->getType();
1422
1423 switch (type)
1424 {
1425 case AST_NAME_AVOGADRO:
1426 dealWithAvogadroSymbol(math);
1427 break;
1428 case AST_NAME_TIME:
1429 dealWithTimeSymbol(math);
1430 break;
1431 case AST_FUNCTION_DELAY:
1432 dealWithDelaySymbol(math);
1433 break;
1434 case AST_FUNCTION_RATE_OF:
1435 dealWithRateOfSymbol(math);
1436 break;
1437 default:
1438 break;
1439 }
1440
1441 for (unsigned int i = 0; i < nChild; ++i)
1442 {
1443 ASTNode* child = math->getChild(i);
1444 lookForCSymbols(child);
1445 }
1446 }
1447
1448 void
dealWithAvogadroSymbol(ASTNode * math)1449 StructureFields::dealWithAvogadroSymbol(ASTNode* math)
1450 {
1451 if (math == NULL) return;
1452 if (details->getAvogadroSymbol().empty())
1453 {
1454 details->setAvogadroSymbol(math->getName());
1455 }
1456 else
1457 {
1458 math->setName(details->getAvogadroSymbol().c_str());
1459 }
1460 }
1461
1462 void
dealWithTimeSymbol(ASTNode * math)1463 StructureFields::dealWithTimeSymbol(ASTNode* math)
1464 {
1465 if (math == NULL) return;
1466 if (details->getTimeSymbol().empty())
1467 {
1468 details->setTimeSymbol(math->getName());
1469 }
1470 else
1471 {
1472 math->setName(details->getTimeSymbol().c_str());
1473 }
1474 }
1475
1476 void
dealWithDelaySymbol(ASTNode * math)1477 StructureFields::dealWithDelaySymbol(ASTNode* math)
1478 {
1479 if (math == NULL) return;
1480 if (details->getDelaySymbol().empty())
1481 {
1482 details->setDelaySymbol(math->getName());
1483 }
1484 else
1485 {
1486 math->setName(details->getDelaySymbol().c_str());
1487 }
1488 }
1489
1490 void
dealWithRateOfSymbol(ASTNode * math)1491 StructureFields::dealWithRateOfSymbol(ASTNode* math)
1492 {
1493 if (math == NULL) return;
1494 if (details->getRateOfSymbol().empty())
1495 {
1496 details->setRateOfSymbol(math->getName());
1497 }
1498 else
1499 {
1500 math->setName(details->getRateOfSymbol().c_str());
1501 }
1502 }
1503
1504 //////////////////////////////////////////////////////////////
1505
1506 // general need to know function
1507
1508 bool
usingPlugin(const std::string & prefix,SBase * base)1509 StructureFields::usingPlugin(const std::string& prefix, SBase* base)
1510 {
1511 bool usePlugin = false;
1512 if (prefix.size() > 0)
1513 {
1514 if (mSBase != NULL && mSBase->getPackageName() != prefix)
1515 {
1516 usePlugin = true;
1517 }
1518 else if (base != NULL && base->getPlugin(prefix) != NULL)
1519 {
1520 usePlugin = true;
1521 }
1522 }
1523
1524 return usePlugin;
1525 }
1526
1527 //////////////////////////
1528
1529 // functions for creating SBML from structure
1530 void
addAttributes(const std::string & functionId,unsigned int index,unsigned int total_no)1531 StructureFields::addAttributes(const std::string& functionId, unsigned int index,
1532 unsigned int total_no)
1533 {
1534 FieldType_t type;
1535 FieldnamesType_t nameType;
1536
1537 for (unsigned int i = 0; i < nNumberFields; ++i)
1538 {
1539 FieldValues_t field = mFields.at(i);
1540 type = field.type;
1541 nameType = field.fieldnameType;
1542 if (nameType != OTHER_CVTERMS && !field.isSBMLAttribute)
1543 {
1544 continue;
1545 }
1546 if (type == TYPE_ELEMENT)
1547 {
1548 if (nameType == OTHER_CVTERMS)
1549 {
1550 addCVTerms(index);
1551 }
1552 else
1553 {
1554 addChildElement(field, index);
1555 }
1556 }
1557 else if (field.fieldnameType == OTHER_ANOMALOUS_MATH)
1558 {
1559 addAnomalousChild(field);
1560 }
1561 else
1562 {
1563 setAttribute(field, index, total_no);
1564 }
1565
1566 }
1567 }
1568
1569 CVTerm *
getCVTerm(mxArray * mxCVTerms,unsigned int i)1570 getCVTerm(mxArray* mxCVTerms, unsigned int i)
1571 {
1572 CVTerm *cv;
1573 std::string qualType = StructureFields::readString(mxCVTerms, "qualifierType", i);
1574 std::string qual = StructureFields::readString(mxCVTerms, "qualifier", i);
1575 if (qualType == "biological")
1576 {
1577 cv = new CVTerm(BIOLOGICAL_QUALIFIER);
1578 cv->setBiologicalQualifierType(qual);
1579 }
1580 else if (qualType == "model")
1581 {
1582 cv = new CVTerm(MODEL_QUALIFIER);
1583 cv->setModelQualifierType(qual);
1584 }
1585 else
1586 {
1587 cv = new CVTerm();
1588 }
1589
1590 mxArray* mxResources = mxGetField(mxCVTerms, i, "resources");
1591 size_t numRes = mxGetNumberOfElements(mxResources);
1592
1593 for (unsigned int j = 0; j < numRes; j++)
1594 {
1595 mxArray* mxField = mxGetCell(mxResources, j);
1596 char *value = mxArrayToString(mxField);
1597 if (value != NULL)
1598 {
1599 cv->addResource(std::string(value));
1600 }
1601 }
1602
1603 mxArray* mxNestedCV = mxGetField(mxCVTerms, i, "cvterms");
1604 if (mxNestedCV != NULL)
1605 {
1606 size_t numNested = mxGetNumberOfElements(mxNestedCV);
1607
1608 for (unsigned int n = 0; n < numNested; n++)
1609 {
1610 CVTerm *nested = getCVTerm(mxNestedCV, n);
1611 cv->addNestedCVTerm(nested);
1612 delete nested;
1613 }
1614 }
1615
1616 return cv;
1617 }
1618
1619 void
addCVTerms(unsigned int index)1620 StructureFields::addCVTerms(unsigned int index)
1621 {
1622 mxArray* mxCVTerms = mxGetField(mxStructure, index, "cvterms");
1623 if (mxCVTerms == NULL)
1624 return;
1625
1626 size_t numCV = mxGetNumberOfElements(mxCVTerms);
1627
1628 for (unsigned int i = 0; i < numCV; ++i)
1629 {
1630 CVTerm *cv = getCVTerm(mxCVTerms, i);
1631 if (!mSBase->isSetMetaId())
1632 mSBase->setMetaId("temp");
1633 mSBase->addCVTerm(cv);
1634 delete cv;
1635 }
1636
1637 }
1638
1639 void
addChildElement(FieldValues_t field,unsigned int index)1640 StructureFields::addChildElement(FieldValues_t field, unsigned int index)
1641 {
1642 mxArray* mxChild = mxGetField(mxStructure, index, field.fieldName.c_str());
1643 SBase *pChild = NULL;
1644
1645 size_t n = mxGetNumberOfElements(mxChild);
1646 if (mxChild == NULL) return;
1647 else if (n == 0) return;
1648
1649 bool usePlugin = usingPlugin(field.prefix);
1650
1651 for (unsigned int i = 0; i < n; ++i)
1652 {
1653 // hack for rules - since a list of rules contains assignmentRule etc..
1654 if (field.fieldName == "rule")
1655 {
1656 pChild = mSBase->createChildObject(getRuleType(mxChild, i));
1657 }
1658 else
1659 {
1660 if (usePlugin)
1661 {
1662 pChild = mSBase->getPlugin(field.prefix)->createChildObject(field.sbmlName);
1663 }
1664 else
1665 {
1666 pChild = mSBase->createChildObject(field.sbmlName);
1667 }
1668 }
1669
1670 if (pChild != NULL)
1671 {
1672 StructureFields *sf = new StructureFields(pChild, mxChild);
1673
1674 std::string id = std::string("OutputSBML:addChildElement:") + sf->getTypeCode();
1675 sf->addAttributes(id, i, n);
1676
1677 sf->freeStructureMemory();
1678 }
1679 }
1680 }
1681
1682 void
addAnomalousChild(FieldValues_t field)1683 StructureFields::addAnomalousChild(FieldValues_t field)
1684 {
1685 std::string value = readString(field.fieldName, 0, 0);
1686
1687 if (!value.empty())
1688 {
1689 SBase *pChild = mSBase->createChildObject(field.fieldName);
1690 if (pChild != NULL)
1691 {
1692 std::string value = readString(field.fieldName, 0, 0);
1693 const ASTNode* ast = getMathChild(value);
1694 pChild->setMath(ast);
1695 }
1696 }
1697 }
1698
1699 const ASTNode*
getMathChild(const std::string & value)1700 StructureFields::getMathChild(const std::string& value)
1701 {
1702 /* convert MATLAB formula to MathML infix */
1703 char * cvalue = convertMathFormula(value);
1704 L3ParserSettings settings;
1705 settings.setParseLog(L3P_PARSE_LOG_AS_LN);
1706 const ASTNode *ast = SBML_parseL3FormulaWithSettings(cvalue, &settings);
1707 adjustForCSymbols(const_cast<ASTNode*>(ast));
1708 mxFree(cvalue);
1709 return ast;
1710 }
1711
1712 void
adjustForCSymbols(ASTNode * math)1713 StructureFields::adjustForCSymbols(ASTNode * math)
1714 {
1715 if (math == NULL)
1716 {
1717 return;
1718 }
1719
1720 ASTNodeType_t type = math->getType();
1721 switch (type)
1722 {
1723 case AST_FUNCTION:
1724 if (math->getName() == details->getDelaySymbol())
1725 {
1726 math->setType(AST_FUNCTION_DELAY);
1727 }
1728 else if (math->getName() == details->getRateOfSymbol())
1729 {
1730 math->setType(AST_FUNCTION_RATE_OF);
1731 }
1732 break;
1733 case AST_NAME:
1734 if (math->getName() == details->getTimeSymbol())
1735 {
1736 math->setType(AST_NAME_TIME);
1737 }
1738 else if (math->getName() == details->getAvogadroSymbol())
1739 {
1740 math->setType(AST_NAME_AVOGADRO);
1741 }
1742 break;
1743 default:
1744 break;
1745 }
1746
1747 for (unsigned int i = 0; i < math->getNumChildren(); ++i)
1748 {
1749 adjustForCSymbols(math->getChild(i));
1750 }
1751 }
1752
1753
1754 void
setAttribute(FieldValues_t field,unsigned int index,unsigned int total_no)1755 StructureFields::setAttribute(FieldValues_t field,
1756 unsigned int index, unsigned int total_no)
1757 {
1758 std::string value;
1759 int ivalue;
1760 unsigned int uvalue;
1761 bool bvalue;
1762 double dvalue;
1763 bool usePlugin = usingPlugin(field.prefix);
1764 const ASTNode *ast = NULL;
1765
1766 switch(field.type)
1767 {
1768 case TYPE_CHAR:
1769 value = readString(field.fieldName, index, total_no);
1770 switch (field.fieldnameType) {
1771 case SBML_MATH:
1772 ast = getMathChild(value);
1773 mSBase->setMath(ast);
1774 break;
1775 case SBML_NOTES:
1776 mSBase->setNotes(value);
1777 break;
1778 case SBML_ANNOT:
1779 mSBase->setAnnotation(value);
1780 break;
1781 case SBML_MESSAGE:
1782 mSBase->setMessage(value);
1783 break;
1784 default:
1785 if (usePlugin)
1786 {
1787 mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, value);
1788 }
1789 else
1790 {
1791 mSBase->setAttribute(field.sbmlName, value);
1792 }
1793 break;
1794 }
1795 break;
1796
1797 case TYPE_INT:
1798 ivalue = readInt(field.fieldName, index, total_no);
1799 if (determineStatus(field.fieldName, index))
1800 {
1801 if (usePlugin)
1802 {
1803 mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, ivalue);
1804 }
1805 else
1806 {
1807 mSBase->setAttribute(field.sbmlName, ivalue);
1808 }
1809 }
1810 break;
1811
1812 case TYPE_UINT:
1813 uvalue = readUint(field.fieldName, index, total_no);
1814 if (determineStatus(field.fieldName, index))
1815 {
1816 if (usePlugin)
1817 {
1818 mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, uvalue);
1819 }
1820 else
1821 {
1822 mSBase->setAttribute(field.sbmlName, uvalue);
1823 }
1824 }
1825 break;
1826
1827 case TYPE_DOUBLE:
1828 dvalue = readDouble(field.fieldName, index, total_no);
1829 if (determineStatus(field.fieldName, index))
1830 {
1831 if (usePlugin)
1832 {
1833 mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, dvalue);
1834 }
1835 else
1836 {
1837 mSBase->setAttribute(field.sbmlName, dvalue);
1838 }
1839 }
1840 break;
1841
1842 case TYPE_BOOL:
1843 ivalue = readInt(field.fieldName, index, total_no);
1844 bvalue = true ? ivalue == 1 : false;
1845 if (determineStatus(field.fieldName, index))
1846 {
1847 if (usePlugin)
1848 {
1849 mSBase->getPlugin(field.prefix)->setAttribute(field.sbmlName, bvalue);
1850 }
1851 else
1852 {
1853 mSBase->setAttribute(field.sbmlName, bvalue);
1854 }
1855 }
1856
1857 case TYPE_UNKNOWN:
1858 default:
1859 break;
1860 }
1861 }
1862
1863 const std::string
getRuleType(mxArray * mxRuleStructure,unsigned int index)1864 StructureFields::getRuleType(mxArray* mxRuleStructure, unsigned int index)
1865 {
1866 std::string value = readString(mxRuleStructure, "typecode", index);
1867 std::string retvalue;
1868 if (value == "SBML_ALGEBRAIC_RULE")
1869 {
1870 retvalue = "algebraicRule";
1871 }
1872 else if (value == "SBML_ASSIGNMENT_RULE")
1873 {
1874 retvalue = "assignmentRule";
1875 }
1876 else if (value == "SBML_RATE_RULE")
1877 {
1878 retvalue = "rateRule";
1879 }
1880 else
1881 {
1882 std::string type = readString(mxRuleStructure, "type", index);
1883 if (value == "SBML_PARAMETER_RULE")
1884 if (type == "scalar")
1885 retvalue = "parameterAssignmentRule";
1886 else
1887 retvalue = "parameterRateRule";
1888 else if (value == "SBML_SPECIES_CONCENTRATION_RULE")
1889 if (type == "scalar")
1890 retvalue = "speciesAssignmentRule";
1891 else
1892 retvalue = "speciesRateRule";
1893 else if (value == "SBML_COMPARTMENT_VOLUME_RULE")
1894 if (type == "scalar")
1895 retvalue = "compartmentAssignmentRule";
1896 else
1897 retvalue = "compartmentRateRule";
1898 else
1899 retvalue = "rule";
1900 }
1901
1902 return retvalue;
1903 }
1904
1905 std::string
getAssociationTypeCode(SBase * base)1906 StructureFields::getAssociationTypeCode(SBase* base)
1907 {
1908 std::string value = SBMLTypeCode_toString(base->getTypeCode(), "fbc");
1909 std::string retvalue = "SBML_FBC_ASSOCIATION";
1910 if (value == "GeneProductRef")
1911 {
1912 retvalue = "SBML_FBC_GENE_PRODUCT_REF";
1913 }
1914 else if (value == "FbcAnd")
1915 {
1916 retvalue = "SBML_FBC_AND";
1917 }
1918 else if (value == "FbcOr")
1919 {
1920 retvalue = "SBML_FBC_OR";
1921 }
1922 return retvalue;
1923 }
1924
1925 std::string
getRuleTypeCode(SBase * base)1926 StructureFields::getRuleTypeCode(SBase* base)
1927 {
1928 std::string value = SBMLTypeCode_toString(base->getTypeCode(), "core");
1929 std::string retvalue = "rule";
1930 if (value == "AlgebraicRule")
1931 {
1932 retvalue = "SBML_ALGEBRAIC_RULE";
1933 }
1934 else if (value == "AssignmentRule")
1935 {
1936 if (base->getLevel() > 1)
1937 {
1938 retvalue = "SBML_ASSIGNMENT_RULE";
1939 }
1940 else
1941 {
1942 Model *m = static_cast<Model*>(base->getAncestorOfType(SBML_MODEL));
1943 if (m != NULL)
1944 {
1945 if (m->getCompartment(static_cast<Rule*>(base)->getVariable()) != NULL)
1946 {
1947 retvalue = "SBML_COMPARTMENT_VOLUME_RULE";
1948 }
1949 if (m->getSpecies(static_cast<Rule*>(base)->getVariable()) != NULL)
1950 {
1951 retvalue = "SBML_SPECIES_CONCENTRATION_RULE";
1952 }
1953 if (m->getParameter(static_cast<Rule*>(base)->getVariable()) != NULL)
1954 {
1955 retvalue = "SBML_PARAMETER_RULE";
1956 }
1957 }
1958 }
1959 }
1960 else if (value == "RateRule")
1961 {
1962 if (base->getLevel() > 1)
1963 {
1964 retvalue = "SBML_RATE_RULE";
1965 }
1966 else
1967 {
1968 Model *m = static_cast<Model*>(base->getAncestorOfType(SBML_MODEL));
1969 if (m != NULL)
1970 {
1971 std::string var = static_cast<Rule*>(base)->getVariable();
1972 if (m->getCompartment(var) != NULL)
1973 {
1974 retvalue = "SBML_COMPARTMENT_VOLUME_RULE";
1975 }
1976 if (m->getSpecies(var) != NULL)
1977 {
1978 retvalue = "SBML_SPECIES_CONCENTRATION_RULE";
1979 }
1980 if (m->getParameter(var) != NULL)
1981 {
1982 retvalue = "SBML_PARAMETER_RULE";
1983 }
1984 }
1985 }
1986 }
1987 return retvalue;
1988 }
1989
1990
1991 char *
convertMathFormula(const std::string & pacFormula)1992 StructureFields::convertMathFormula(const std::string& pacFormula)
1993 {
1994 mxArray *mxInput[1];
1995 mxArray *mxOutput[1];
1996 int nStatus;
1997 size_t nBuflen;
1998 char * formula;
1999
2000 /* convert MATLAB formula to MathML infix */
2001
2002 mxInput[0] = mxCreateString(pacFormula.c_str());
2003 nStatus = mexCallMATLAB(1, mxOutput, 1, mxInput, "ConvertFormulaToMathML");
2004
2005 if (nStatus != 0)
2006 {
2007 std::string id = std::string("OutputSBML:GetMathMLFormula:") + sbmlTC;
2008 reportError(id, "Failed to convert formula");
2009 }
2010
2011 /* get the formula returned */
2012 nBuflen = (mxGetM(mxOutput[0])*mxGetN(mxOutput[0])+1);
2013 formula = (char *) mxCalloc(nBuflen, sizeof(char));
2014 nStatus = mxGetString(mxOutput[0], (char *) formula, (mwSize)(nBuflen));
2015
2016 if (nStatus != 0)
2017 {
2018 std::string id = std::string("OutputSBML:GetMathMLFormula") + sbmlTC;
2019 reportError(id, "Cannot copy formula");
2020 }
2021
2022 mxDestroyArray(mxInput[0]);
2023 mxDestroyArray(mxOutput[0]);
2024
2025 return formula;
2026 }
2027
2028 int
readInt(const std::string & name,unsigned int index,unsigned int total_no)2029 StructureFields::readInt(const std::string& name, unsigned int index, unsigned int total_no)
2030 {
2031 mxArray * mxField;
2032 int value = 0;
2033 int nStatus = 1;
2034
2035 /* get field */
2036 mxField = mxGetField(mxStructure, index, name.c_str());
2037 if (mxField != NULL)
2038 {
2039 if (!mxIsEmpty(mxField))
2040 {
2041 if (mxIsNumeric(mxField))
2042 {
2043 value = (int)(mxGetScalar(mxField));
2044 nStatus = 0;
2045 }
2046 }
2047 else
2048 {
2049 value = 0;
2050 nStatus = 0;
2051 }
2052
2053 if (nStatus != 0)
2054 {
2055 reportReadError("Int", name, index, total_no);
2056 }
2057 }
2058 return value;
2059 }
2060
2061 // static version
2062 int
readInt(mxArray * mxArray1,const std::string & name,unsigned int index)2063 StructureFields::readInt(mxArray* mxArray1, const std::string& name, unsigned int index)
2064 {
2065 mxArray * mxField;
2066 int value = 0;
2067 int nStatus = 1;
2068
2069 /* get field */
2070 mxField = mxGetField(mxArray1, index, name.c_str());
2071 if (mxField != NULL)
2072 {
2073 if (!mxIsEmpty(mxField))
2074 {
2075 if (mxIsNumeric(mxField))
2076 {
2077 value = (int)(mxGetScalar(mxField));
2078 nStatus = 0;
2079 }
2080 }
2081 else
2082 {
2083 value = 0;
2084 nStatus = 0;
2085 }
2086
2087 if (nStatus != 0)
2088 {
2089 reportReadError("Int", name, index, 0, "static");
2090 }
2091 }
2092
2093 return value;
2094 }
2095
2096 double
readDouble(const std::string & name,unsigned int index,unsigned int total_no)2097 StructureFields::readDouble(const std::string& name, unsigned int index, unsigned int total_no)
2098 {
2099 mxArray * mxField;
2100 double value = 0;
2101 int nStatus = 1;
2102
2103 /* get field */
2104 mxField = mxGetField(mxStructure, index, name.c_str());
2105 if (mxField != NULL)
2106 {
2107 if (!mxIsEmpty(mxField))
2108 {
2109 if (mxIsNumeric(mxField))
2110 {
2111 value = mxGetScalar(mxField);
2112 nStatus = 0;
2113 }
2114 }
2115 else
2116 {
2117 value = util_NaN();
2118 nStatus = 0;
2119 }
2120
2121 if (nStatus != 0)
2122 {
2123 reportReadError("Double", name, index, total_no);
2124 }
2125 }
2126 return value;
2127 }
2128
2129 const std::string
readString(const std::string & name,unsigned int index,unsigned int total_no)2130 StructureFields::readString(const std::string& name, unsigned int index, unsigned int total_no)
2131 {
2132 mxArray * mxField;
2133 char *value = NULL;
2134 int nStatus = 1;
2135 std::string f = "";
2136
2137 /* get field */
2138 mxField = mxGetField(mxStructure, index, name.c_str());
2139 if (mxField != NULL)
2140 {
2141 value = mxArrayToString(mxField);
2142 if (value != NULL)
2143 {
2144 nStatus = 0;
2145 f = std::string(value);
2146 }
2147
2148 if (nStatus != 0)
2149 {
2150 reportReadError("String", name, index, total_no);
2151 }
2152 }
2153 return f;
2154 }
2155
2156 //static version
2157 const std::string
readString(mxArray * mxArray1,const std::string & name,unsigned int index)2158 StructureFields::readString(mxArray* mxArray1, const std::string& name, unsigned int index)
2159 {
2160 mxArray * mxField;
2161 char *value = NULL;
2162 int nStatus = 1;
2163 std::string f = "";
2164 /* get field */
2165 mxField = mxGetField(mxArray1, index, name.c_str());
2166 if (mxField != NULL)
2167 {
2168 value = mxArrayToString(mxField);
2169 if (value != NULL)
2170 {
2171 nStatus = 0;
2172 f = std::string(value);
2173 }
2174 if (nStatus != 0)
2175 {
2176 reportReadError("String", name, index, 0, "static");
2177 }
2178 }
2179 return f;
2180 }
2181
2182 unsigned int
readUint(const std::string & name,unsigned int index,unsigned int total_no)2183 StructureFields::readUint(const std::string& name, unsigned int index, unsigned int total_no)
2184 {
2185 mxArray * mxField;
2186 unsigned int value = 0;
2187 int nStatus = 1;
2188
2189 /* get field */
2190 mxField = mxGetField(mxStructure, index, name.c_str());
2191 if (mxField != NULL)
2192 {
2193 if (!mxIsEmpty(mxField))
2194 {
2195 if (mxIsNumeric(mxField))
2196 {
2197 value = (unsigned int)(mxGetScalar(mxField));
2198 nStatus = 0;
2199 }
2200 }
2201 else
2202 {
2203 value = 0;
2204 nStatus = 0;
2205 }
2206
2207 if (nStatus != 0)
2208 {
2209 reportReadError("Uint", name, index, total_no);
2210 }
2211 }
2212
2213 return value;
2214 }
2215
2216 // static version
2217 unsigned int
readUint(mxArray * mxArray1,const std::string & name,unsigned int index)2218 StructureFields::readUint(mxArray* mxArray1, const std::string& name,
2219 unsigned int index)
2220 {
2221 mxArray * mxField;
2222 unsigned int value = 0;
2223 int nStatus = 1;
2224
2225 /* get field */
2226 mxField = mxGetField(mxArray1, index, name.c_str());
2227 if (mxField != NULL)
2228 {
2229 if (!mxIsEmpty(mxField))
2230 {
2231 if (mxIsNumeric(mxField))
2232 {
2233 value = (unsigned int)(mxGetScalar(mxField));
2234 nStatus = 0;
2235 }
2236 }
2237 else
2238 {
2239 value = 0;
2240 nStatus = 0;
2241 }
2242
2243 if (nStatus != 0)
2244 {
2245 reportReadError("Uint", name, index, 0, "static");
2246 }
2247 }
2248 return value;
2249 }
2250
2251 bool
determineStatus(const std::string & name,unsigned int index)2252 StructureFields::determineStatus(const std::string& name, unsigned int index)
2253 {
2254 bool setStatus = true;
2255 mxArray * mxField;
2256 // if the field itself is empty then it is clearly not set
2257 mxField = mxGetField(mxStructure, index, name.c_str());
2258 if (mxField == NULL || mxIsEmpty(mxField))
2259 {
2260 return false;
2261 }
2262
2263 // want to know whether there is an isSetXYZ field coming from matlab
2264 // and if so what is its value
2265 unsigned int value = 0;
2266 int nStatus = 1;
2267 const char * cname = name.c_str();
2268 char * cpname = safe_strdup(cname);
2269 const char * isset = "isSet";
2270 char * isSet = safe_strcat(isset, cpname);
2271 cpname[0] = toupper(cpname[0]);
2272 char * isSet1 = safe_strcat(isset, cpname);
2273
2274 /* get field */
2275 mxField = mxGetField(mxStructure, index, isSet1);
2276 // possibly have isSet followed by lower case
2277 if (mxField == NULL)
2278 mxField = mxGetField(mxStructure, index, isSet);
2279 if (mxField != NULL)
2280 {
2281 if (!mxIsEmpty(mxField) && mxIsNumeric(mxField))
2282 {
2283 value = (unsigned int)(mxGetScalar(mxField));
2284 nStatus = 0;
2285 }
2286
2287 if (nStatus == 0)
2288 {
2289 setStatus = true ? value == 1 : false;
2290 }
2291 }
2292
2293 safe_free(cpname);
2294 safe_free(isSet);
2295 safe_free(isSet1);
2296
2297 return setStatus;
2298 }
2299 ///////////////////////////////////////////
2300
2301 // report error
2302
2303 void
reportReadError(const std::string & type,const std::string & name,unsigned int index,unsigned int total_no)2304 StructureFields::reportReadError(const std::string& type, const std::string& name,
2305 unsigned int index, unsigned int total_no)
2306 {
2307 std::string mid = "OutputSBML:read" + type + ":" + sbmlTC;
2308
2309 std::ostringstream errMsg;
2310 if (total_no == 0)
2311 errMsg << " Cannot copy " << sbmlTC << "." << name << " field";
2312 else
2313 errMsg << " Cannot copy " << sbmlTC << "(" << index+1 << ")." << name << " field";
2314
2315 reportError(mid, errMsg.str());
2316 }
2317
2318 // static version
2319 void
reportReadError(const std::string & type,const std::string & name,unsigned int index,unsigned int total_no,const std::string & tc)2320 StructureFields::reportReadError(const std::string& type, const std::string& name,
2321 unsigned int index, unsigned int total_no,
2322 const std::string& tc)
2323 {
2324 std::string mid = "OutputSBML:read" + type + ":" + tc;
2325
2326 std::ostringstream errMsg;
2327 if (total_no == 0)
2328 errMsg << " Cannot copy " << tc << "." << name << " field";
2329 else
2330 errMsg << " Cannot copy " << tc << "(" << index+1 << ")." << name << " field";
2331
2332 reportError(mid, errMsg.str());
2333 }
2334
2335 ///////////////////////////////////////////////////////////////////////////////
2336 //
2337 // class to store model details
2338
ModelDetails()2339 ModelDetails::ModelDetails()
2340 {
2341 mPackageMap.clear();
2342 mSupportedPackages.clear();
2343
2344 mLevel = StructureFields::readUint(modelArray, "SBML_level", 0);
2345 mVersion = StructureFields::readUint(modelArray, "SBML_version", 0);
2346
2347 mDelaySymbol = StructureFields::readString(modelArray, "delay_symbol", 0);
2348 mTimeSymbol = StructureFields::readString(modelArray, "time_symbol", 0);
2349 mAvogadroSymbol = StructureFields::readString(modelArray, "avogadro_symbol", 0);
2350
2351 populateNamespaces();
2352 populatePkgMap();
2353 }
2354
ModelDetails(SBMLDocument * doc)2355 ModelDetails::ModelDetails(SBMLDocument* doc)
2356 {
2357 mPackageMap.clear();
2358 mSupportedPackages.clear();
2359
2360 mLevel = doc->getLevel();
2361 mVersion = doc->getVersion();
2362
2363 mDelaySymbol = "";
2364 mTimeSymbol = "";
2365 mAvogadroSymbol = "";
2366
2367 populateNamespaces(doc);
2368 populatePkgMap(doc);
2369 }
2370
2371
2372 void
populateNamespaces()2373 ModelDetails::populateNamespaces()
2374 {
2375 mSBMLns = new SBMLNamespaces(getLevel(), getVersion());
2376
2377 XMLNamespaces *xmlns = new XMLNamespaces();
2378 mxArray* mxNamespaces = mxGetField(modelArray, 0, "namespaces");
2379 size_t nNoNamespaces = mxGetNumberOfElements(mxNamespaces);
2380
2381 for (unsigned int i = 0; i < nNoNamespaces; ++i)
2382 {
2383 std::string uri = StructureFields::readString(mxNamespaces, "uri", i);
2384 std::string prefix = StructureFields::readString(mxNamespaces, "prefix", i);
2385 xmlns->add(uri, prefix);
2386 }
2387
2388 mSBMLns->addNamespaces(xmlns);
2389 }
2390
2391 void
populateNamespaces(SBMLDocument * doc)2392 ModelDetails::populateNamespaces(SBMLDocument* doc)
2393 {
2394 mSBMLns = doc->getSBMLNamespaces();
2395 }
2396
2397 void
populateSupportedPackages()2398 ModelDetails::populateSupportedPackages()
2399 {
2400 for (unsigned int i = 0; i < SBMLExtensionRegistry::getNumRegisteredPackages(); ++i)
2401 {
2402 mSupportedPackages.append(SBMLExtensionRegistry::getRegisteredPackageName(i));
2403 }
2404 }
2405
2406 void
populatePkgMap()2407 ModelDetails::populatePkgMap()
2408 {
2409 populateSupportedPackages();
2410 XMLNamespaces *xmlns = mSBMLns->getNamespaces();
2411 for (int i = 0; i < xmlns->getNumNamespaces(); ++i)
2412 {
2413 if (isSupportedPackageNS(xmlns->getURI(i), xmlns->getPrefix(i)))
2414 {
2415 std::string prefix = xmlns->getPrefix(i);
2416 std::string name = prefix + "_version";
2417 unsigned int version = StructureFields::readUint(modelArray, name, 0);
2418 mPackageMap.insert(std::pair<const std::string, unsigned int>(prefix, version));
2419 }
2420 }
2421 }
2422
2423 void
populatePkgMap(SBMLDocument * doc)2424 ModelDetails::populatePkgMap(SBMLDocument* doc)
2425 {
2426 populateSupportedPackages();
2427 XMLNamespaces *xmlns = mSBMLns->getNamespaces();
2428 for (int i = 0; i < xmlns->getNumNamespaces(); ++i)
2429 {
2430 if (isSupportedPackageNS(xmlns->getURI(i), xmlns->getPrefix(i)))
2431 {
2432 std::string prefix = xmlns->getPrefix(i);
2433 unsigned int version = doc->getPlugin(prefix)->getPackageVersion();
2434 mPackageMap.insert(std::pair<const std::string, unsigned int>(prefix, version));
2435 }
2436 }
2437 }
2438
2439 bool
isSupportedPackageNS(const std::string & uri,const std::string prefix)2440 ModelDetails::isSupportedPackageNS(const std::string& uri, const std::string prefix)
2441 {
2442 bool supported = false;
2443 if (prefix.empty())
2444 return supported;
2445
2446 size_t pos = uri.find("http://www.sbml.org/sbml/level3/version");
2447 if (pos == 0 && mSupportedPackages.contains(prefix))
2448 {
2449 supported = true;
2450 }
2451
2452 return supported;
2453 }
2454
2455 bool
isPackagePresent(const std::string & pkg)2456 ModelDetails::isPackagePresent(const std::string& pkg)
2457 {
2458 bool present = false;
2459
2460 for (PkgIter it = mPackageMap.begin(); it != mPackageMap.end(); ++it)
2461 {
2462 if (it->first == pkg)
2463 {
2464 present = true;
2465 break;
2466 }
2467 }
2468 return present;
2469 }
2470
2471 ////////////////////////////////////////////////////////////////////////////
2472 //
2473 // Filenames.cpp
2474
2475 ////////////////////////////////////////////////////////////////////////////
2476 //
2477 // ensure reading of unicode filenames
2478
2479 #if defined(WIN32) && !defined(CYGWIN) && !defined(USE_OCTAVE)
2480 #define FILE_CHAR wchar_t*
2481 #define FILE_FOPEN(file) _wfopen(file, L"r")
2482 #define USE_FILE_WCHAR 1
2483 #else
2484 #define FILE_CHAR char*
2485 #define FILE_FOPEN(file) fopen(file, "r")
2486 #endif
2487
2488 #ifndef uint16_t
2489 #define uint16_t unsigned short
2490 #endif
2491
2492
readUnicodeString(const mxArray * prhs,mwSize length)2493 FILE_CHAR readUnicodeString(const mxArray *prhs, mwSize length)
2494 {
2495 #ifdef USE_OCTAVE
2496 char* ansii = (char *) mxCalloc(length, sizeof(char));
2497 mxGetString(prhs, ansii, length);
2498 return ansii;
2499 #else
2500 wchar_t* utf16 = (wchar_t *) mxCalloc(length, sizeof(wchar_t));
2501 char* utf8 = NULL;
2502 uint16_T *ch = (uint16_T *) mxGetData(prhs);
2503 wchar_t* p = utf16;
2504 mwSize i;
2505 for ( i = 0; i < length-1; ++i)
2506 *p++ = *ch++;
2507 *p = 0;
2508
2509 #if USE_FILE_WCHAR
2510 return utf16;
2511 #else
2512
2513 utf8 = (char*)mxCalloc(length*2, sizeof(char));
2514
2515 wcstombs(utf8, utf16, length*2);
2516
2517 /*mxFree(utf16);*/
2518
2519 if (utf8 != NULL && strlen(utf8) == 0 && length > 0)
2520 {
2521 reportError("readUnicodeString",
2522 "This string uses characters that cannot be "
2523 "expressed in UTF8, please rename the file.");
2524 }
2525
2526 return utf8;
2527 #endif /* USE_FILE_WCHAR */
2528
2529 #endif /* USE_OCTAVE*/
2530
2531 }
2532
2533
readUnicodeStringFromArrays(mxArray * mxFilename[2])2534 FILE_CHAR readUnicodeStringFromArrays(mxArray *mxFilename[2])
2535
2536 {
2537 mwSize nBuflen = (mxGetM(mxFilename[0])*mxGetN(mxFilename[0])+1);
2538 FILE_CHAR pacTempString1 = readUnicodeString(mxFilename[0],nBuflen);
2539
2540 mwSize nBufferLen = (mxGetM(mxFilename[1])*mxGetN(mxFilename[1])+1);
2541 FILE_CHAR pacTempString2 = readUnicodeString(mxFilename[1],nBufferLen);
2542
2543 #if USE_FILE_WCHAR
2544 FILE_CHAR pacFilename = (wchar_t *) mxCalloc(nBufferLen+nBuflen, sizeof(wchar_t));
2545 wcscpy(pacFilename, pacTempString2);
2546 wcscat(pacFilename, pacTempString1);
2547 #else
2548 FILE_CHAR pacFilename = (char *) mxCalloc(nBufferLen+nBuflen, sizeof(char));
2549 strcpy(pacFilename, pacTempString2);
2550 strcat(pacFilename, pacTempString1);
2551 #endif
2552
2553 /*mxFree(pacTempString1);*/
2554 /*mxFree(pacTempString2);*/
2555 return pacFilename;
2556 }
2557
2558 #if USE_FILE_WCHAR
2559
endsWith(const wchar_t * fileName,const char * ext)2560 int endsWith(const wchar_t* fileName, const char* ext)
2561 {
2562 size_t len = wcslen(fileName), i;
2563 size_t targetLen = strlen(ext);
2564 wchar_t* temp1 = (wchar_t*)malloc((targetLen + 1) * sizeof(wchar_t));
2565 char* temp2 = (char*)malloc((targetLen+1)*sizeof(char));
2566 int result = 0;
2567
2568 memset(temp1, 0, targetLen*sizeof(wchar_t));
2569 memset(temp2, 0, targetLen*sizeof(char));
2570
2571 for (i = 0; i < targetLen; ++i)
2572 {
2573 temp1[i] = fileName[len - targetLen + i];
2574 }
2575
2576 wcstombs(temp2,temp1, targetLen);
2577 result = strcmp_insensitive(temp2, ext);
2578
2579 /*mxFree(temp1);*/
2580 /*mxFree(temp2);*/
2581 free(temp1);
2582 free(temp2);
2583 return result;
2584 }
2585
2586 #endif
2587
2588 FILE_CHAR
browseForFilename()2589 browseForFilename()
2590 {
2591 FILE_CHAR filename = NULL;
2592 mxArray * mxFilename[2], * mxExt[1];
2593 mxExt[0] = mxCreateString(".xml");
2594 int nStatus = mexCallMATLAB(2, mxFilename, 1, mxExt, "uigetfile");
2595
2596 if (nStatus != 0)
2597 {
2598 reportError("TranslateSBML:GUIInput:filename",
2599 "Failed to read filename");
2600 }
2601
2602 /* get the filename returned */
2603 filename = readUnicodeStringFromArrays(mxFilename);
2604
2605 mxDestroyArray(mxExt[0]);
2606 mxDestroyArray(mxFilename[1]);
2607 mxDestroyArray(mxFilename[0]);
2608
2609 return filename;
2610 }
2611
2612 ////////////////////////////////////////////////////////////////////////////
2613 //
2614 // Arguments.cpp
2615
2616 /* determine whether we are in octave or matlab */
2617 unsigned int
determinePlatform()2618 determinePlatform()
2619 {
2620 unsigned int usingOctave = 0;
2621 mxArray * mxOctave[1];
2622
2623 mexCallMATLAB(1, mxOctave, 0, NULL, "isoctave");
2624
2625 size_t nBuflen = (mxGetM(mxOctave[0])*mxGetN(mxOctave[0])+1);
2626 char * pacTempString1 = (char *)(safe_calloc(nBuflen, sizeof(char)));
2627 int nStatus = mxGetString(mxOctave[0], pacTempString1, (mwSize)(nBuflen));
2628
2629 if (nStatus != 0)
2630 {
2631 reportError("OutputSBML:platformDetection",
2632 "Could not determine platform");
2633 }
2634
2635 safe_free(pacTempString1);
2636 mxDestroyArray(mxOctave[0]);
2637
2638 return usingOctave;
2639 }
2640
2641 bool
answerYesToQuestion(const std::string & question)2642 answerYesToQuestion(const std::string& question)
2643 {
2644 bool answer = false;
2645 mxArray *mxPrompt[2], *mxReply[1];
2646 char *pacReply;
2647 mxPrompt[0]= mxCreateString(question.c_str());
2648 mxPrompt[1]= mxCreateString("s");
2649 mexCallMATLAB(1, mxReply, 2, mxPrompt, "input");
2650 mxDestroyArray(mxPrompt[0]);
2651 mxDestroyArray(mxPrompt[1]);
2652
2653 size_t nBufferLen = (mxGetM(mxReply[0])*mxGetN(mxReply[0])+1);
2654 pacReply = (char *) (safe_calloc(nBufferLen, sizeof(char)));
2655 mxGetString(mxReply[0], pacReply, (mwSize)(nBufferLen));
2656 mxDestroyArray(mxReply[0]);
2657
2658 if (strcmp_insensitive(pacReply, "y") == 0)
2659 {
2660 answer = true;
2661 }
2662 safe_free(pacReply);
2663
2664 return answer;
2665 }
2666
2667 ///////////////////////////////////////////////////////////////////////////////
2668 //
2669 // functions used to check arguments for OutputSBML
2670
2671 void
validateNumberOfInputsForOutput(int nrhs,const mxArray * prhs[],unsigned int usingOctave,unsigned int & outputVersion,int nlhs)2672 validateNumberOfInputsForOutput(int nrhs, const mxArray *prhs[],
2673 unsigned int usingOctave, unsigned int& outputVersion, int nlhs)
2674 {
2675 if (nlhs > 0 && nrhs == 0)
2676 {
2677 outputVersion = 1;
2678 }
2679 else
2680 {
2681 if (nrhs < 1)
2682 {
2683 reportError("OutputSBML:inputArgs",
2684 "Must supply at least the model as an input argument\n"
2685 "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2686 }
2687 if (usingOctave == 1 && nrhs < 2)
2688 {
2689 reportError("OutputSBML:Octave:needFilename",
2690 "Octave requires the filename to be specified\n"
2691 "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2692 }
2693 if (nrhs > 5)
2694 {
2695 reportError("OutputSBML:inputArguments", "Too many input arguments\n"
2696 "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2697 }
2698
2699 if (nrhs > 1 && ((mxIsChar(prhs[1]) != 1) || (mxGetM(prhs[1]) != 1)))
2700 {
2701 reportError("OutputSBML:inputArguments:invalidFilename",
2702 "Second argument must be a filename\n"
2703 "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2704 }
2705 if (nrhs > 2 && !mxIsNumeric(prhs[2]))
2706 {
2707 reportError("OutputSBML:inputArguments:exclusiveFlag",
2708 "exclusiveFlag is an optional argument but must be a number\n"
2709 "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2710 }
2711
2712 if (nrhs > 3 && !mxIsNumeric(prhs[3]))
2713 {
2714 reportError("OutputSBML:inputArguments:applyUserValidation",
2715 "applyUserValidation is an optional argument but must be a number\n"
2716 "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2717 }
2718
2719 if (nrhs > 4 && (!mxIsNumeric(prhs[4]) || (mxGetM(prhs[4]) != 1) || (mxGetN(prhs[4]) != 2)))
2720 {
2721 reportError("OutputSBML:inputArguments:fbcGeneProductOptions",
2722 "fbcGeneProductOptions is an optional argument but must be an array with two numbers\n"
2723 "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation), (fbcGeneProductOptions))");
2724 }
2725
2726 }
2727
2728 }
2729
2730 void
validateNumberOfOutputsForOutput(int nlhs)2731 validateNumberOfOutputsForOutput(int nlhs)
2732 {
2733 if (nlhs > 0)
2734 {
2735 reportError("OutputSBML:outputArguments", "Too many output arguments\n"
2736 "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag))");
2737 }
2738 }
2739
2740 void
populateModelArray(int nrhs,const mxArray * prhs[])2741 populateModelArray(int nrhs, const mxArray *prhs[])
2742 {
2743 modelArray = mxDuplicateArray(prhs[0]);
2744
2745 /**
2746 * note second argument may be the filename
2747 *
2748 * we now have the option of a third argument that indicates that we
2749 * want the structure to ONLY contain expected fields or not
2750 *
2751 * and a fourth argument that tells us whether to apply user
2752 * specific validation
2753 *
2754 * and a fifth argument saying whether to use ids/lebels in fbc
2755 */
2756 if (nrhs > 4)
2757 {
2758 double *pr2 = mxGetPr(prhs[2]);
2759 if (*pr2 == 0)
2760 {
2761 onlyExpectedFields = false;
2762 }
2763 else
2764 {
2765 onlyExpectedFields = true;
2766 }
2767 double *pr3 = mxGetPr(prhs[3]);
2768 if (*pr3 == 0)
2769 {
2770 applyUserValidation = false;
2771 }
2772 else
2773 {
2774 applyUserValidation = true;
2775 }
2776 double *pr = mxGetPr(prhs[4]);
2777
2778 if (*pr == 0)
2779 {
2780 fbcUsingId = false;
2781 }
2782 else
2783 {
2784 fbcUsingId = true;
2785 }
2786 pr++;
2787 if (*pr == 0)
2788 {
2789 fbcAddGeneProducts = false;
2790 }
2791 else
2792 {
2793 fbcAddGeneProducts = true;
2794 }
2795 }
2796 else if (nrhs > 3)
2797 {
2798 double *pr2 = mxGetPr(prhs[2]);
2799 if (*pr2 == 0)
2800 {
2801 onlyExpectedFields = false;
2802 }
2803 else
2804 {
2805 onlyExpectedFields = true;
2806 }
2807 double *pr3 = mxGetPr(prhs[3]);
2808 if (*pr3 == 0)
2809 {
2810 applyUserValidation = false;
2811 }
2812 else
2813 {
2814 applyUserValidation = true;
2815 }
2816 fbcUsingId = false;
2817 fbcAddGeneProducts = true;
2818 }
2819 else if ( nrhs > 2)
2820 {
2821 double *pr2 = mxGetPr(prhs[2]);
2822 if (*pr2 == 0)
2823 {
2824 onlyExpectedFields = false;
2825 }
2826 else
2827 {
2828 onlyExpectedFields = true;
2829 }
2830 applyUserValidation = false;
2831 fbcUsingId = false;
2832 fbcAddGeneProducts = true;
2833 }
2834 else
2835 {
2836 onlyExpectedFields = true;
2837 applyUserValidation = false;
2838 fbcUsingId = false;
2839 fbcAddGeneProducts = true;
2840 }
2841
2842 // we have made memory - need to free it is we exit prematurely
2843 freeMemory = true;
2844 }
2845
2846 void
validateModel()2847 validateModel()
2848 {
2849 mxArray * mxCheckStructure[2];
2850 mxArray * mxModel[3];
2851 mxModel[0] = modelArray;
2852 if (onlyExpectedFields)
2853 {
2854 mxModel[1] = mxCreateDoubleScalar(1);
2855 }
2856 else
2857 {
2858
2859 mxModel[1] = mxCreateDoubleScalar(0);
2860 }
2861 if (applyUserValidation)
2862 {
2863 mxModel[2] = mxCreateDoubleScalar(1);
2864 }
2865 else
2866 {
2867
2868 mxModel[2] = mxCreateDoubleScalar(0);
2869 }
2870 int nStatus = mexCallMATLAB(2, mxCheckStructure, 3, mxModel, "isSBML_Model");
2871
2872 int value = (int)(mxGetScalar(mxCheckStructure[0]));
2873 if ((nStatus != 0) || (value != 1))
2874 {
2875 /* there are errors - use the pacTempString1 char * to list these to the user */
2876 size_t nBuflen = (mxGetM(mxCheckStructure[1])*mxGetN(mxCheckStructure[1])+1);
2877 char * pacTempString1 = (char *)safe_calloc(nBuflen, sizeof(char));
2878 nStatus = mxGetString(mxCheckStructure[1], pacTempString1, (mwSize)(nBuflen));
2879 std::ostringstream errMsg;
2880 if (nStatus == 0)
2881 {
2882 errMsg << "\nFirst input must be a valid MATLAB_SBML Structure\n\n" <<
2883 "Errors reported: " << pacTempString1 << "\nUSAGE: OutputSBML(SBMLModel"
2884 << ", (filename), (exclusiveFlag), (applyUserValidation))";
2885 reportError("OutputSBML:inputArguments:invalidModelSupplied", errMsg.str());
2886 }
2887 else
2888 {
2889 errMsg << "\nFirst input must be a valid MATLAB_SBML Structure\n\n" <<
2890 "\nUSAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag), (applyUserValidation))";
2891 reportError("OutputSBML:inputArguments:invalidStructureSupplied", errMsg.str());
2892 }
2893 safe_free(pacTempString1);
2894 }
2895
2896 mxDestroyArray(mxCheckStructure[0]);
2897 mxDestroyArray(mxCheckStructure[1]);
2898 }
2899
validateFilenameForOutput(int nrhs,const mxArray * prhs[])2900 FILE_CHAR validateFilenameForOutput(int nrhs, const mxArray *prhs[])
2901 {
2902 FILE_CHAR filename = NULL;
2903 if (nrhs >= 2)
2904 {
2905 if (mxIsChar(prhs[1]) != 1)
2906 {
2907 reportError("OutputSBML:inputArguments:invalidFilename",
2908 "Second input must be a filename\n"
2909 "USAGE: OutputSBML(SBMLModel, (filename), (exclusiveFlag))");
2910 }
2911
2912 size_t nBuflen = (mxGetM(prhs[1])*mxGetN(prhs[1])+1);
2913 filename = readUnicodeString(prhs[1], (mwSize)nBuflen);
2914 }
2915 else
2916 {
2917 filename = browseForFilename();
2918 }
2919
2920 /*
2921 * check that the extension has been used
2922 */
2923 #if USE_FILE_WCHAR
2924 if (wcsstr(filename, L".xml") == NULL)
2925 {
2926 wcscat(filename, L".xml");
2927 }
2928 #else
2929 /* check that the extension has been used */
2930 if (strstr(filename, ".xml") == NULL)
2931 {
2932 strcat(filename, ".xml");
2933 }
2934 #endif
2935
2936
2937 return filename;
2938 }
2939
2940 //////////////
2941
2942 // functions for TranslatSBML
2943 void
validateNumberOfInputsForTranslate(int nrhs,const mxArray * prhs[],unsigned int usingOctave)2944 validateNumberOfInputsForTranslate(int nrhs, const mxArray *prhs[],
2945 unsigned int usingOctave)
2946 {
2947 if (nrhs > 4)
2948 {
2949 reportError("TranslateSBML:inputArguments", "Too many input arguments\n"
2950 "USAGE: [model, (errors), (version)] = "
2951 "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2952 }
2953
2954 if (nrhs > 0 && ((mxIsChar(prhs[0]) != 1) || (mxGetM(prhs[0]) != 1)))
2955 {
2956 reportError("TranslateSBML:inputArguments:invalidFilename",
2957 "First argument must be a filename\n"
2958 "USAGE: [model, (errors), (version)] = "
2959 "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2960 }
2961 if (nrhs > 1 && !mxIsNumeric(prhs[1]))
2962 {
2963 reportError("TranslateSBML:inputArguments:validateFlag",
2964 "validateFlag is an optional argument but must be a number\n"
2965 "USAGE: [model, (errors), (version)] = "
2966 "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2967 }
2968
2969 if (nrhs > 2 && !mxIsNumeric(prhs[2]))
2970 {
2971 reportError("TranslateSBML:inputArguments:verboseFlag",
2972 "verboseFlag is an optional argument but must be a number\n"
2973 "USAGE: [model, (errors), (version)] = "
2974 "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2975 }
2976
2977 if (nrhs > 3 && (!mxIsNumeric(prhs[3]) || (mxGetM(prhs[3]) != 1) || (mxGetN(prhs[3]) != 2)))
2978 {
2979 reportError("TranslateSBML:inputArguments:fbcGeneProductOptions",
2980 "fbcGeneProductOptions is an optional argument but must be an array with two numbers\n"
2981 "USAGE: [model, (errors), (version)] = "
2982 "TranslateSBML((filename), (validateFlag), (verboseFlag), (fbcGeneProductOptions))");
2983 }
2984
2985 if (usingOctave && nrhs == 0)
2986 {
2987 reportError("TranslateSBML:Octave:needFilename",
2988 "Octave requires the filename to be specified\n"
2989 "USAGE: [model, (errors), (version)] = "
2990 "TranslateSBML(filename, (validateFlag), (verboseFlag))");
2991 }
2992 }
2993
2994 void
validateNumberOfOutputsForTranslate(int nlhs,mxArray * plhs[],unsigned int & outputErrors,unsigned int & outputVersion)2995 validateNumberOfOutputsForTranslate(int nlhs, mxArray *plhs[],
2996 unsigned int& outputErrors,
2997 unsigned int& outputVersion)
2998 {
2999 switch (nlhs)
3000 {
3001 case 3:
3002 outputErrors = 1;
3003 outputVersion = 1;
3004 break;
3005 case 2:
3006 outputErrors = 1;
3007 break;
3008 case 1:
3009 case 0:
3010 break;
3011 default:
3012 reportError("TranslateSBML:outputArguments", "Too many output arguments\n"
3013 "USAGE: [model, (errors), (version)] = "
3014 "TranslateSBML((filename), (validateFlag), (verboseFlag))");
3015 break;
3016 }
3017 }
3018
3019 void
checkFileExists(FILE_CHAR filename)3020 checkFileExists(FILE_CHAR filename)
3021 {
3022 FILE *fp;
3023 fp = FILE_FOPEN(filename);
3024 if(fp == NULL)
3025 {
3026 char * msgTxt = NULL;
3027 #if USE_FILE_WCHAR
3028 msgTxt = (char *) safe_calloc(wcslen(filename)+35, sizeof(char));
3029 sprintf(msgTxt, "File %ws does not exist on this path", filename);
3030 #else
3031 msgTxt = (char *) safe_calloc(strlen(filename)+35, sizeof(char));
3032 sprintf(msgTxt, "File %s does not exist on this path", filename);
3033 #endif
3034 reportError("TranslateSBML:inputArguments:filename", msgTxt);
3035 safe_free(msgTxt);
3036 }
3037 else
3038 {
3039 fclose(fp);
3040 }
3041
3042 }
3043
3044 FILE_CHAR
getGivenFilename(const mxArray * prhs[])3045 getGivenFilename(const mxArray* prhs[])
3046 {
3047 FILE_CHAR filename = NULL;
3048 size_t nBufferLen = mxGetNumberOfElements (prhs[0]) + 1;
3049 filename = readUnicodeString(prhs[0], nBufferLen);
3050
3051 if (filename == NULL)
3052 {
3053 reportError("TranslateSBML:inputArguments:filename",
3054 "Failed to read filename");
3055 }
3056
3057 checkFileExists(filename);
3058 return filename;
3059 }
3060
3061 FILE_CHAR
getFilename(int nrhs,const mxArray * prhs[],unsigned int & validateFlag,unsigned int & verboseFlag)3062 getFilename(int nrhs, const mxArray* prhs[], unsigned int& validateFlag,
3063 unsigned int& verboseFlag)
3064 {
3065 FILE_CHAR filename = NULL;
3066
3067 double *pr = 0;
3068 switch (nrhs)
3069 {
3070 case 4:
3071 // arg 3
3072 pr = mxGetPr(prhs[3]);
3073
3074 if (*pr == 0)
3075 {
3076 fbcUsingId = false;
3077 }
3078 else
3079 {
3080 fbcUsingId = true;
3081 }
3082 pr++;
3083 if (*pr == 0)
3084 {
3085 fbcAddGeneProducts = false;
3086 }
3087 else
3088 {
3089 fbcAddGeneProducts = true;
3090 }
3091 // arg 2
3092 verboseFlag = (int)mxGetScalar(prhs[2]);
3093 // arg 1
3094 validateFlag = (int)mxGetScalar(prhs[1]);
3095 // arg 0
3096 filename = getGivenFilename(prhs);
3097 break;
3098 case 3:
3099 // arg 2
3100 verboseFlag = (int)mxGetScalar(prhs[2]);
3101 // arg 1
3102 validateFlag = (int)mxGetScalar(prhs[1]);
3103 // arg 0
3104 filename = getGivenFilename(prhs);
3105 break;
3106 case 2:
3107 // arg 1
3108 validateFlag = (int)mxGetScalar(prhs[1]);
3109 // arg 0
3110 filename = getGivenFilename(prhs);
3111 break;
3112 case 1:
3113 // arg 0
3114 filename = getGivenFilename(prhs);
3115 break;
3116 case 0:
3117 filename = browseForFilename();
3118 if (answerYesToQuestion("Do you want to validate the model? Enter y/n "))
3119 {
3120 validateFlag = 1;
3121 }
3122 fbcUsingId = false;
3123 fbcAddGeneProducts = true;
3124 break;
3125 default:
3126 break;
3127 }
3128 return filename;
3129 }
3130
3131 ///////////////////////////////////////////////////////////////////////////
3132
3133 // functions called by main functions
3134 FILE_CHAR
validateInputOutputForOutput(int nlhs,mxArray * plhs[],int nrhs,const mxArray * prhs[],unsigned int usingOctave,unsigned int & outputVersion)3135 validateInputOutputForOutput(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[],
3136 unsigned int usingOctave, unsigned int& outputVersion)
3137 {
3138 FILE_CHAR filename = NULL;
3139 validateNumberOfInputsForOutput(nrhs, prhs, usingOctave, outputVersion, nlhs);
3140 if (outputVersion == 0)
3141 {
3142 validateNumberOfOutputsForOutput(nlhs);
3143
3144 populateModelArray(nrhs, prhs);
3145 validateModel();
3146 filename = validateFilenameForOutput(nrhs, prhs);
3147 }
3148 return filename;
3149 }
3150
3151 FILE_CHAR
validateInputOutputForTranslate(int nlhs,mxArray * plhs[],int nrhs,const mxArray * prhs[],unsigned int usingOctave,unsigned int & outputErrors,unsigned int & outputVersion,unsigned int & validateFlag,unsigned int & verboseFlag)3152 validateInputOutputForTranslate(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[],
3153 unsigned int usingOctave, unsigned int& outputErrors,
3154 unsigned int& outputVersion, unsigned int& validateFlag,
3155 unsigned int& verboseFlag)
3156 {
3157 FILE_CHAR filename = NULL;
3158 validateNumberOfInputsForTranslate(nrhs, prhs, usingOctave);
3159 validateNumberOfOutputsForTranslate(nlhs, plhs, outputErrors, outputVersion);
3160 filename = getFilename(nrhs, prhs, validateFlag, verboseFlag);
3161
3162 return filename;
3163 }
3164
3165
3166 void
OutputVersionInformation(mxArray * plhs[])3167 OutputVersionInformation(mxArray *plhs[])
3168 {
3169 const char *version_struct[] =
3170 {
3171 "libSBML_version",
3172 "libSBML_version_string",
3173 "XML_parser",
3174 "XML_parser_version",
3175 "isFBCEnabled",
3176 "packagesEnabled"
3177 };
3178
3179 const char *xml_parsers[] =
3180 {
3181 "libxml2" ,
3182 "expat" ,
3183 "xerces",
3184 "not found"
3185 };
3186
3187 mwSize dims[2] = {1, 1};
3188
3189 const char * parser = xml_parsers[0];
3190 unsigned int i = 0;
3191
3192
3193 plhs[2] = mxCreateStructArray(2, dims, 6, version_struct);
3194
3195 mxSetField(plhs[2], 0, "libSBML_version", CreateIntScalar(getLibSBMLVersion()));
3196 mxSetField(plhs[2], 0, "libSBML_version_string", mxCreateString(getLibSBMLDottedVersion()));
3197
3198 while (isLibSBMLCompiledWith(parser) == 0 && i < 3)
3199 {
3200 ++i;
3201 parser = xml_parsers[i];
3202 }
3203
3204 mxSetField(plhs[2], 0, "XML_parser", mxCreateString(parser));
3205 mxSetField(plhs[2], 0, "XML_parser_version", mxCreateString(getLibSBMLDependencyVersionOf(parser)));
3206
3207 #ifdef USE_FBC
3208 mxSetField(plhs[2], 0, "isFBCEnabled", mxCreateString("enabled"));
3209
3210 #else
3211 mxSetField(plhs[2], 0, "isFBCEnabled", mxCreateString("disabled"));
3212
3213 #endif
3214 std::ostringstream oss;
3215 bool first = true;
3216 for (unsigned int i = 0; i < SBMLExtensionRegistry::getNumRegisteredPackages(); ++i)
3217 {
3218 std::string name = SBMLExtensionRegistry::getRegisteredPackageName(i);
3219 if (reqdPkgPrefixes.contains(name) || unreqdPkgPrefixes.contains(name))
3220 {
3221 if (!first)
3222 {
3223 oss << ";";
3224 }
3225 oss << name;
3226 first = false;
3227 }
3228 }
3229
3230 std::string msg = oss.str();
3231 mxSetField(plhs[2], 0, "packagesEnabled", mxCreateString(msg.c_str()));
3232 }
3233
3234 ////////////////////////////////////////////////////////////////////////////
3235 //
3236 // TranslateSBML.cpp
3237 SBMLDocument*
readSBMLDocument(FILE_CHAR filename)3238 readSBMLDocument(FILE_CHAR filename)
3239 {
3240 SBMLDocument* doc = NULL;
3241 #if USE_FILE_WCHAR
3242 if (endsWith(filename, ".xml") == 0)
3243 {
3244 StringBuffer_t *sb = NULL;
3245 unsigned long count = 0;
3246 char buffer[1024];
3247
3248 FILE* fp = FILE_FOPEN(filename);
3249
3250 sb = StringBuffer_create(1);
3251
3252 while ((count = (unsigned long)fread(&buffer, sizeof(char), 1024, fp)) > 0)
3253 {
3254 StringBuffer_appendWithLength(sb,buffer, (unsigned long)count);
3255 memset(&buffer, 0, 1024*sizeof(char));
3256 }
3257 StringBuffer_appendChar(sb, 0);
3258
3259 fclose(fp);
3260 doc = readSBMLFromString(StringBuffer_getBuffer(sb));
3261 StringBuffer_free(sb);
3262 }
3263 else
3264 {
3265 size_t len = wcslen(filename);
3266 char* file = (char*) mxCalloc(len+1, sizeof(char));
3267 wcstombs(file, filename, len);
3268 doc = readSBML(file);
3269 mxFree(file);
3270 }
3271 #else
3272 doc = readSBML(filename);
3273 #endif
3274
3275 return doc;
3276 }
3277
3278 void
OutputErrorInformation(mxArray * plhs[],SBMLDocument * doc)3279 OutputErrorInformation(mxArray *plhs[], SBMLDocument* doc)
3280 {
3281 const char *error_struct[] =
3282 {
3283 "line",
3284 "errorId",
3285 "severity",
3286 "message"
3287 };
3288
3289 mwSize errordims[2];
3290
3291 unsigned int totalerrors = doc->getNumErrors();
3292 errordims[0] = 1;
3293 errordims[1] = totalerrors;
3294 plhs[1] = mxCreateStructArray(2, errordims, 4, error_struct);
3295 for (unsigned int i = 0; i < totalerrors; ++i)
3296 {
3297 const XMLError* e = (const XMLError*)(doc->getError(i));
3298 mxSetField(plhs[1], i, "line", CreateIntScalar(e->getLine()));
3299 mxSetField(plhs[1], i, "errorId", CreateIntScalar(e->getErrorId()));
3300 mxSetField(plhs[1], i, "severity", mxCreateString(e->getSeverityAsString().c_str()));
3301 mxSetField(plhs[1], i, "message", mxCreateString(e->getMessage().c_str()));
3302 }
3303 }
3304
3305 void
displayLine(const std::string & line)3306 displayLine(const std::string& line)
3307 {
3308 mxArray* mxErrors[1];
3309 mxErrors[0] = mxCreateString(line.c_str());
3310 mexCallMATLAB(0, NULL, 1, mxErrors, "disp");
3311 mxDestroyArray(mxErrors[0]);
3312 }
3313
3314 void
displayErrors(SBMLDocument * doc,unsigned int warnings,unsigned int errors,unsigned int verboseFlag,unsigned int & listWarningsFlag)3315 displayErrors(SBMLDocument* doc, unsigned int warnings, unsigned int errors,
3316 unsigned int verboseFlag, unsigned int& listWarningsFlag)
3317 {
3318 std::ostringstream numErrs;
3319 numErrs << "The model contains " << errors << " errors";
3320 if (warnings > 0)
3321 {
3322 numErrs << " and " << warnings << " warnings";
3323 }
3324 numErrs << "." << std::endl;
3325
3326 displayLine(numErrs.str());
3327
3328 if (verboseFlag == 1 && warnings > 0)
3329 {
3330 if (!answerYesToQuestion("Do you want to exclude the warnings from the list? Enter y/n ") )
3331 {
3332 listWarningsFlag = 1;
3333 }
3334 }
3335
3336 if (verboseFlag == 1)
3337 {
3338 numErrs.str("");
3339 numErrs.clear();
3340 numErrs << "************************************************************"
3341 << std::endl << "Line ErrorId Severity Message" << std::endl;
3342
3343 displayLine(numErrs.str());
3344
3345 for (unsigned int i = 0; i < doc->getNumErrors(); ++i)
3346 {
3347 const XMLError* e = (const XMLError_t *) doc->getError(i);
3348
3349 if (listWarningsFlag == 1 || e->getSeverity() > 1)
3350 {
3351 numErrs.str("");
3352 numErrs.clear();
3353 numErrs << e->getLine() << ": (" << e->getErrorId() << ") "
3354 << e->getSeverityAsString() << " " << e->getMessage() << std::endl;
3355
3356 displayLine(numErrs.str());
3357 }
3358 }
3359
3360 }
3361 }
3362
3363 unsigned int
validateDocument(SBMLDocument * doc,unsigned int validateFlag,unsigned int verboseFlag,unsigned int & errors,unsigned int & warnings)3364 validateDocument(SBMLDocument* doc, unsigned int validateFlag, unsigned int verboseFlag,
3365 unsigned int& errors, unsigned int& warnings)
3366 {
3367 /* check for errors at read */
3368 unsigned int totalerrors = doc->getNumErrors();
3369
3370 if (validateFlag > 0)
3371 {
3372 if (verboseFlag > 0 && totalerrors > 0)
3373 {
3374 if (!answerYesToQuestion("There are errors found during reading. Do you want to continue validation? Enter y/n "))
3375 {
3376 totalerrors += doc->checkConsistency();
3377 }
3378 }
3379 else
3380 {
3381 totalerrors += doc->checkConsistency();
3382 }
3383 }
3384
3385 /* divide the totalerrors into errors
3386 * and warnings
3387 */
3388 for (unsigned int i = 0; i < totalerrors; ++i)
3389 {
3390 const XMLError * e = (const XMLError *) doc->getError(i);
3391 if (e->getSeverity() < 2)
3392 {
3393 warnings = warnings + 1;
3394 }
3395 }
3396 errors = totalerrors - warnings;
3397
3398 return totalerrors;
3399 }
3400
3401
3402 ///////////////////////////////////////////////////////////////////////////////
3403 /**
3404 * NAME: mexFunction
3405 *
3406 * PARAMETERS: int nlhs - number of output arguments
3407 * mxArray *plhs[] - output arguments
3408 * int nrhs - number of input arguments
3409 * mxArray *prhs[] - input arguments
3410 *
3411 * RETURNS:
3412 *
3413 * FUNCTION: MATLAB standard dll export function
3414 * any returns are made through the mxArray * prhs
3415 */
3416 void
mexFunction(int nlhs,mxArray * plhs[],int nrhs,const mxArray * prhs[])3417 mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
3418 {
3419 // we have not made persistent memory
3420 freeMemory = false;
3421 std::ostringstream numErrs;
3422 /* determine whether we are in octave or matlab */
3423 unsigned int usingOctave = determinePlatform();
3424
3425 /* flags for determining what to output and whether to validate */
3426 unsigned int outputErrors = 0;
3427 unsigned int outputVersion = 0;
3428 unsigned int validateFlag = 0;
3429 unsigned int verboseFlag = 1;
3430 unsigned int listWarningsFlag = 0;
3431 bool readModel = true;
3432
3433 FILE_CHAR pacFilename = validateInputOutputForTranslate(nlhs, plhs, nrhs, prhs, usingOctave, outputErrors,
3434 outputVersion, validateFlag, verboseFlag);
3435
3436 SBMLDocument* sbmlDocument = readSBMLDocument(pacFilename);
3437
3438 if (sbmlDocument->getModel() == NULL)
3439 {
3440 /* at this point - if there have been fatal errors
3441 * dont try anything else
3442 */
3443 readModel = false;
3444 }
3445 else
3446 {
3447 ///* check for errors at read */
3448 unsigned int errors = 0, warnings = 0;
3449 unsigned int totalerrors = validateDocument(sbmlDocument, validateFlag, verboseFlag, errors, warnings);
3450
3451 ///*if errors occur report these - promt user as to whether to import the Model*/
3452 if (totalerrors != 0)
3453 {
3454 displayErrors(sbmlDocument, warnings, errors, verboseFlag, listWarningsFlag);
3455
3456 if (!(errors == 0 && listWarningsFlag == 0))
3457 {
3458 if (validateFlag == 0)
3459 {
3460 numErrs.str("");
3461 numErrs.clear();
3462 numErrs << "Error encountered during read." << std::endl;
3463 displayLine(numErrs.str());
3464 }
3465 else
3466 {
3467 if (verboseFlag == 1)
3468 {
3469 if (!answerYesToQuestion("Do you want to load the model anyway? Enter y/n "))
3470 {
3471 readModel = false;
3472 }
3473 }
3474 }
3475 }
3476 }
3477 }
3478 // output required structures
3479 if (outputVersion == 1)
3480 {
3481 OutputVersionInformation(plhs);
3482 }
3483
3484 if (outputErrors == 1)
3485 {
3486 OutputErrorInformation(plhs, sbmlDocument);
3487 }
3488
3489 if (readModel)
3490 {
3491 Model * sbmlModel = sbmlDocument->getModel();
3492 details = new ModelDetails(sbmlDocument);
3493 populatePackageLists();
3494
3495 std::string tc = "model";
3496 const std::string func = "TranslateSBML";
3497 StructureFields *sf = new StructureFields(tc);
3498 sf->createStructure(func, sbmlDocument);
3499
3500 // plhs[0] = sf->getStructure();
3501 mxArray* mxArgs[3];
3502 mxArgs[0] = mxDuplicateArray(sf->getStructure());
3503 mxArgs[1] = CreateIntScalar(sbmlDocument->getLevel());
3504 mxArgs[2] = CreateIntScalar(sbmlDocument->getVersion());
3505 mexCallMATLAB(0, &plhs[0], 3, mxArgs, "addLevelVersion");
3506 mxDestroyArray(mxArgs[0]);
3507 mxDestroyArray(mxArgs[1]);
3508 mxDestroyArray(mxArgs[2]);
3509 delete details;
3510 delete sf;
3511 }
3512 else
3513 {
3514 /* we havent read in a Model */
3515 numErrs.str("");
3516 numErrs.clear();
3517 numErrs << "No model returned." << std::endl;
3518 displayLine(numErrs.str());
3519
3520 plhs[0] = mxCreateStructArray(0, 0, 0, NULL);
3521 }
3522 }
3523
3524
3525