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