"""
PySCeS - Python Simulator for Cellular Systems (http://pysces.sourceforge.net)
Copyright (C) 2004-2009 B.G. Olivier, J.M. Rohwer, J.-H.S Hofmeyr all rights reserved,
Brett G. Olivier (bgoli@users.sourceforge.net)
Triple-J Group for Molecular Cell Physiology
Stellenbosch University, South Africa.
Permission to use, modify, and distribute this software is given under the
terms of the PySceS (BSD style) license. See LICENSE.txt that came with
this distribution for specifics.
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
Brett G. Olivier
"""
from version import __version__
import os, copy, re, time
from getpass import getuser
from xml.etree import ElementTree
import StringIO
import itertools
CurrentDirectory = os.getcwd() # temporary thing
from InfixParser import MyInfixParser
InfixParser = MyInfixParser()
InfixParser.buildlexer()
InfixParser.buildparser(debug=0, debugfile='infix.dbg', tabmodule='infix_tabmodule')
InfixParser.setNameStr('self.', '()')
class CoreToPsc(object):
core = None
name = ''
header_block = ''
fixed_block = ''
compartment_block = ''
function_block = ''
reaction_block = ''
species_block = ''
parameter_block = ''
rrule_block = ''
arule_block = ''
event_block = ''
notes_block = ''
SPECIES_CURRENT_VALUE = False
FIXED_SPECIES_CURRENT_VALUE = False
PARAMETER_CURRENT_VALUE = False
time = None
pw_symbols = None
__DEBUG__ = False
# future
compartment_block = ''
def __init__(self, core):
self.core = core
self.name = self.core.name.replace('.psc','')
self.name = self.core.name.replace('.xml','')
self.pw_symbols = [pw.name for pw in self.core.piecewise_functions]
def setHeader(self, s=''):
out = '# Generated by PySCeS %s (%s)\n' % (__version__,time.strftime("20%y-%m-%d %H:%M"))
if len(s) > 0:
out += '\n# '
ccount = 0
for c in range(len(s)):
ccount += 1
if ccount >= 60 and ccount <=75 and s[c] in [' ', '\t', '\n', '-']:
out += s[c]+'\n# '
ccount = 0
else:
out += s[c]
out += ' \n# Keywords\n'
kk = self.core.__KeyWords__.keys()
kk.sort()
for key in kk:
if self.core.__KeyWords__[key] != None:
out += '%s: %s\n' % (key, self.core.__KeyWords__[key])
out += ' \n# GlobalUnitDefinitions\n'
for key in self.core.__uDict__.keys():
if key in ['substance','volume','time','length','area']:
k1, k2 = key[0].upper(), key[1:]
k = k1 + k2
v = self.core.__uDict__[key]
out += 'Unit%s: %s, %s, %s, %s\n' % (k, v['kind'], v['multiplier'],\
v['scale'], v['exponent'])
out += ' \n'
self.header_block = out
def setFixed(self):
out = ''
fcnt = 0
for f in self.core.species:
if f.fixed:
fcnt += 1
out += '%s ' % f.name
if fcnt > 0:
out = 'FIX: ' + out
out += '\n \n'
self.fixed_block = out
def setCompartments(self):
out = ''
if len(self.core.compartments) > 0:
out += '# Compartments\n'
for c in self.core.compartments:
ra = ''
if c.area != None:
ra = ', '+ c.area
out += 'Compartment: %s, %s, %s %s\n' % (c.name, c.size, c.dimensions, ra)
out += ' \n'
self.compartment_block = out
def setFunctions(self):
out = ''
start = True
for f in self.core.functions:
if start:
out = '# Function definitions\n'
start = False
out += 'Function: %s' % f.name
for a in f.args:
out += ', %s ' % a
out += ' {\n%s\n}\n' % f.formula
if out != '':
out += ' \n'
self.function_block = out
def setReactions(self):
out = '# Reactions'
for r in self.core.reactions:
C = ''
if not r.hasCompartment() and len(self.core.compartments) == 1:
print 'Info: single compartment model: locating \"%s\" in default compartment' % r.name
C = '@%s' % self.core.compartments[0].getName()
elif not r.hasCompartment() and len(self.core.compartments) > 1:
print 'Info: multiple compartments defined but reaction %s is not located in any of them.' % r.name
elif r.hasCompartment():
C = '@%s' % r.getCompartment().getName()
rout = '\n%s%s:\n ' % (r.name, C)
cnt = 0
for lh in r.hasSubstrates():
if cnt != 0:
rout += ' + '
if abs(r.stoichiometry[lh]) == 1.0:
rout += '%s' % lh
else:
rout += '{%s}%s' % (abs(r.stoichiometry[lh]), lh)
cnt += 1
if len(r.hasSubstrates()) == 0:
rout += '$pool'
if r.reversible:
rout += ' = '
else:
rout += ' > '
cnt = 0
for rh in r.hasProducts():
if cnt != 0:
rout += ' + '
if abs(r.stoichiometry[rh]) == 1.0:
rout += '%s' % rh
else:
rout += '{%s}%s' % (abs(r.stoichiometry[rh]), rh)
cnt += 1
if len(r.hasProducts()) == 0:
rout += '$pool'
# if we have piecewise symbols test if they are in the formula
# and replace them with the piecewise expression
formula = r.formula
if len(self.pw_symbols) > 0:
pwreplace = 'piecewise('
for pwd in self.pw_symbols:
if pwd in r.formula:
for pwc in self.core.__piecewises__[pwd]:
if pwc != 'other':
pwreplace +=\
'%s,%s,' % (self.core.__piecewises__[pwd][pwc][1],self.core.__piecewises__[pwd][pwc][0])
if self.core.__piecewises__[pwd]['other'] != None:
pwreplace += '%s) ' % self.core.__piecewises__[pwd]['other']
else:
pwreplace = pwreplace[:-1] + ')'
formula = formula.replace(pwd, pwreplace)
rout += '\n %s\n' % formula
if len(r.hasModifiers()) > 0:
rout += '# %s has modifier(s): ' % r.name
for m in r.hasModifiers():
rout += '%s ' % m
rout += ' \n'
out += rout
out += ' \n'
self.reaction_block = out
def setSpecies(self):
out = ''
fixed = ''
var = ''
for f in self.core.species:
C = ''
if not f.hasCompartment() and len(self.core.compartments) == 1:
print 'Info: single compartment model %s is in default compartment' % f.name
C = '@%s' % self.core.compartments[0].getName()
elif not f.hasCompartment() and len(self.core.compartments) > 1:
print 'Warning: multiple compartments defined but species %s is not located in any of them.' % f.name
elif f.hasCompartment():
C = '@%s' % f.getCompartment().getName()
if not f.fixed:
if not self.SPECIES_CURRENT_VALUE:
value = f.value_initial
else:
value = f()
var += '%s%s = %s\n' % (f.name, C, value)
else:
if not self.FIXED_SPECIES_CURRENT_VALUE:
value = f.value_initial
else:
value = f()
fixed += '%s%s = %s\n' % (f.name, C, value)
out += '# Fixed species\n'
out += fixed
out += ' \n'
out += '# Variable species\n'
out += var
out += ' \n'
self.species_block = out
def setParameters(self):
out = '# Parameters\n'
processed = []
def setP(p2, out2, proced):
if not self.PARAMETER_CURRENT_VALUE:
# take into account that parameters can be compartments now as well
# brett 2008
if hasattr(p2, 'value_initial') and p2.value_initial != None:
value = p2.value_initial
else:
value = p2()
else:
value = p2()
if p2.name in proced:
# out2 += '# '
pass
else:
out2 += '%s = %s' % (p2.name, value)
if not hasattr(p2, 'code_string'):
if p2.name in proced:
pass
# out2 += '\t# (initialised)'
else:
out2 += '\n'
else:
if p2.name in proced:
pass
# out2 += '\t# (initialised)\n'
else:
out2 += '\t# (rule)\n'
return out2
for r in self.core.reactions:
## out += '# %s parameters\n' % r.name
for p in r.parameters:
if p.name not in self.core.hasCompartments():
out = setP(p, out, processed)
processed.append(p.name)
## out += '\n'
## if len(processed) != len(self.core.hasGlobalParameters()):
## out += '# Additional (global) parameters\n'
for p in self.core.hasGlobalParameters():
if p not in processed:
p = self.core.get(p)
out = setP(p, out, processed)
processed.append(p.name)
out += ' \n'
self.parameter_block = out
def setAssignmentRules(self):
out = ''
start = True
for p in self.core.global_parameters + self.core.species:
if hasattr(p, 'type') and getattr(p, 'type') == 'assignment':
if start:
out = '# Assignment rules\n'
start = False
# if we have piecewise symbols test if they are in the formula
# and replace them with the piecewise expression
formula = p.formula
if len(self.pw_symbols) > 0:
pwreplace = ' piecewise('
for pwd in self.pw_symbols:
if pwd in p.formula:
for pwc in self.core.__piecewises__[pwd]:
if pwc != 'other':
pwreplace +=\
'%s,%s,' % (self.core.__piecewises__[pwd][pwc][1],self.core.__piecewises__[pwd][pwc][0])
if self.core.__piecewises__[pwd]['other'] != None:
pwreplace += '%s) ' % self.core.__piecewises__[pwd]['other']
else:
pwreplace = pwreplace[:-1] + ')'
formula = formula.replace(pwd, pwreplace)
out += '!F %s = %s\n' % (p.name, formula)
if out != '':
out += ' \n'
self.arule_block = out
def setRateRules(self):
out = ''
start = True
if len(self.core.rate_rules) > 0:
for rr in self.core.rate_rules:
if start:
out = '# Rate rules\n'
start = False
out += 'RateRule: %s {\n%s\n}\n' % (rr.name, rr.formula)
out += '\n'
self.rrule_block = out
def setEvents(self):
out = ''
start = True
for ev in self.core.events:
if start:
out = '# Event definitions\n'
start = False
## formula = ev.code_string.split('=',1)
formula = ev.formula
out += 'Event: %s, %s, %s \n{\n' % (ev.name, formula, ev.delay)
for ass in ev.assignments:
out += '%s = %s\n' % (ass.variable.name, ass.formula)
out += '}\n'
if out != '':
out += ' \n'
self.event_block = out
def setNotes(self, s=''):
if len(s) > 1:
out = '# Notes\n# '
out += '"""%s\n"""\n' % s
## ccount = 0
## for c in range(len(s)):
## ccount += 1
## if ccount >= 55 and ccount <=75 and s[c] in [' ', '\t', '\n', '-']:
## out += s[c]+'\n# '
## ccount = 0
## else:
## out += s[c]
## out += ' \n'
self.notes_block = out
else:
self.notes_block = '\n'
def write(self, filename=None, directory=None, getstrbuf=False):
if filename == None:
filename = self.name+'.psc'
if directory != None:
assert os.path.exists(directory), '\n%s does not exist.' % directory
filename = os.path.join(directory, filename)
print 'Writing file: %s' % filename
outF = file(filename, 'w')
outF.write(self.header_block)
outF.write(self.fixed_block)
outF.write(self.compartment_block)
outF.write(self.function_block)
outF.write(self.reaction_block)
outF.write(self.rrule_block)
outF.write(self.arule_block)
outF.write(self.event_block)
outF.write(self.species_block)
outF.write(self.parameter_block)
outF.write(self.notes_block)
outF.flush()
outF.close()
if getstrbuf:
fb = StringIO.StringIO()
outF = file(filename, 'r')
fb.write(outF.read())
outF.flush()
outF.close()
return fb
class PscToCore(object):
ModelDir = None
WorkDir = None
# old
ModelFile = None
_PysMod__InitStrings = None
InitParams = None #suspect
fixed_species = None
species = None
parameters = None
reactions = None
modifiers = None
## __function_forced_str__ = None
_Function_time = None
_Function_user = None
_Function_init = None
__nDict__ = None
__functions__ = None
__rules__ = None
time = None
__events__ = None
__uDict__ = None
def __init__(self):
try:
from pysces.PyscesParse import PySCeSParser
self.pscParser = PySCeSParser(debug=0)
except:
print "\nYou need PySCeS installed to use this module"
def getPSCFileFromDisk(self, ModelFile, ModelDir=None, WorkDir=None):
"""
find and set up an existing psc file for parsing
"""
if ModelFile[-4:] != '.psc':
print "Assuming .psc extension"
ModelFile += '.psc'
if ModelDir == None:
# this will probably change in future - bgoli
ModelDir = CurrentDirectory
if WorkDir == None:
WorkDir = CurrentDirectory
assert os.path.exists(os.path.join(ModelDir, ModelFile)), \
'\nFile %s does not exist' % os.path.join(ModelDir, ModelFile)
setattr(self, 'ModelFile', ModelFile)
setattr(self, 'ModelDir', ModelDir)
assert os.path.exists(WorkDir), \
'\nDirectory %s does not exist' % WorkDir
setattr(self, 'WorkDir', WorkDir)
def getPSCFileFromString(self, ModelString, WorkDir=None):
"""
set up a temporary psc file for parsing from model string
"""
if WorkDir == None:
WorkDir = CurrentDirectory
assert os.path.exists(WorkDir), \
'\nDirectory %s does not exist' % WorkDir
setattr(self, 'WorkDir', WorkDir)
setattr(self, 'ModelDir', WorkDir)
ModelFile = '%s.psc' % time.time()
Mfile = file(os.path.join(WorkDir,ModelFile),'w')
Mfile.write(ModelString)
Mfile.close()
setattr(self, 'ModelFile', ModelFile)
def getParsedModel(self):
"""
Parse the input file associated with the PySCeS model instance and assign the basic model attributes
"""
self.pscParser.ParsePSC(self.ModelFile,self.ModelDir,self.WorkDir)
# from __nDict__
self._PysMod__InitStrings = [s.replace('self.','') for s in self.pscParser.InitStrings]
for s in self.pscParser.InitStrings:
exec(s)
self.InitParams = [s.replace('self.','') for s in self.pscParser.InitParams]
self.fixed_species = copy.copy(self.pscParser.fixed_species)
self.species = copy.copy(self.pscParser.species)
self.parameters = copy.copy(self.pscParser.parameters)
self.reactions = copy.copy(self.pscParser.reactions)
self.modifiers = copy.copy(self.pscParser.modifiers)
self.__functions__ = copy.copy(self.pscParser.functions)
#print self.modifiers
self._Function_forced = self.pscParser.ForceFunc.replace('self.','')
self._Function_forced = self.pscParser.ForceFunc.replace('scipy.','')
self._Function_time = self.pscParser.TimeFunc.replace('self.','')
self._Function_user = self.pscParser.UserFunc.replace('self.','')
self._Function_init = self.pscParser.InitFunc.replace('self.','')
self.__nDict__ = self.pscParser.NetworkDict.copy()
self.__sDict__ = self.pscParser.sDict.copy()
self.__compartments__ = self.pscParser.Compartments.copy()
self.__uDict__ = self.pscParser.uDict.copy()
# new
def getModel(self):
return self
# TODO: PIECEWISE WRITING
class CoreToSBML(object):
core = None
name = None
SBML = None
level = 2
version = 1
model = None
document = None
time = None
__events__ = None
__DEBUG__ = False
NumpyToMathML = {
'numpy.greater_equal' : 'geq',
'numpy.greater' : 'gt',
'numpy.less_equal' : 'leq',
'numpy.less' : 'lt',
'numpy.not_equal' : 'neq',
'numpy.equal' : 'eq',
'numpy.arcsinh' : 'arcsinh',
'numpy.arccosh' : 'arccosh',
'numpy.arctanh' : 'arctanh',
'numpy.arcsin' : 'arcsin',
'numpy.arccos' : 'arccos',
'numpy.arctan' : 'arctan',
'numpy.sinh' : 'sinh',
'numpy.cosh' : 'cosh',
'numpy.tanh' : 'tanh',
'numpy.sin' : 'sin',
'numpy.cos' : 'cos',
'numpy.tan' : 'tan',
'math.log10' : 'log',
'math.log' : 'ln',
'numpy.floor' : 'floor',
'numpy.ceil' : 'ceil',
'numpy.sqrt' : 'sqrt',
'math.sqrt' : 'sqrt',
'math.exp' : 'exp',
'operator.eq' : 'eq',
'operator.ne' : 'neq',
'operator.gt' : 'gt',
'operator.ge' : 'geq',
'operator.lt' : 'lt',
'operator.le' : 'leq',
'operator.eq' : 'equal',
'operator.ne' : 'neq',
'self._piecewise_' : 'piecewise',
'_piecewise_' : 'piecewise',
'operator.not_' : 'not'
}
NumpyToMathMLkeys = [
'numpy.greater_equal' ,
'numpy.greater' ,
'numpy.less_equal' ,
'numpy.less' ,
'numpy.not_equal' ,
'numpy.equal' ,
'numpy.arcsinh' ,
'numpy.arccosh' ,
'numpy.arctanh' ,
'numpy.arcsin' ,
'numpy.arccos' ,
'numpy.arctan' ,
'numpy.sinh' ,
'numpy.cosh' ,
'numpy.tanh' ,
'numpy.sin' ,
'numpy.cos' ,
'numpy.tan' ,
'math.log10' ,
'math.log' ,
'numpy.floor' ,
'numpy.ceil' ,
'numpy.sqrt' ,
'math.sqrt' ,
'math.exp' ,
'operator.eq',
'operator.ne',
'operator.gt',
'operator.ge',
'operator.lt',
'operator.le',
'operator.eq',
'operator.ne',
'self._piecewise_',
'_piecewise_',
'operator.not_'
]
def __init__(self, core):
self.core = core
self.name = self.core.getName().replace('.psc','').replace('.xml','')
try:
import libsbml as SBML
self.SBML = SBML
except Exception, e:
print e
print 'Posix sbml load error'
self.SBML = None
def createModel(self):
if self.SBML.getLibSBMLVersion() < 40000:
self.model = self.SBML.Model()
self.model.setName(self.name)
self.document = self.SBML.SBMLDocument()
self.document.setLevelAndVersion(self.level, self.version)
else:
self.model = self.SBML.Model(self.level, self.version)
self.model.setName(self.name)
self.document = self.SBML.SBMLDocument(self.level, self.version)
def setCompartments(self):
if len(self.core.compartments) < 1:
print 'Warning: no compartments defined adding one called \"Cell\"'
self.core.addOneCompartment('Cell', 1.0, 3)
for cs in self.core.compartments:
comp_def = self.model.createCompartment()
comp_def.setId(cs.name)
comp_def.setName(cs.name)
comp_def.setVolume(float(cs.size))
def setDescription(self, txt=None):
if txt == None:
txt = self.core.getDescription()
else:
self.core.setDescription(txt)
notes = ''
notes += '<html xhtml="http://www.w3.org/1999/xhtml">\n'
notes += '<head>\n<title>PySCeS (%s) generated model (%s)</title>\n</head>\n<body>\n' % (__version__, self.core.getName())
notes += '<p><span style="font-family: Courier New,Courier,monospace;">\n%s\n</span></p>\n' % txt
notes += '<p><span style="font-family: Courier New,Courier,monospace;"><a href="http://pysces.sourceforge.net">PySCeS</a> (%s) generated model (%s)</span></p>\n' % (__version__, self.core.getName())
notes += '</body></html>'
self.model.setNotes(notes)
def setUnits(self):
ud = self.core.getGlobalUnits()
for un in ud.keys():
# for now just the basic stuff
if un in ['substance','volume','time','length','area']:
vdef = self.model.createUnitDefinition()
vdef.setId(un)
vdef.setName(un)
vu = self.model.createUnit()
vu.setKind(self.SBML.UnitKind_forName(ud[un]['kind']))
vu.setMultiplier(ud[un]['multiplier'])
vu.setScale(int(ud[un]['scale']))
vu.setExponent(int(ud[un]['exponent']))
vu.setOffset(0)
def setSpecies(self):
for spe in self.core.species:
s = self.model.createSpecies()
s.setId(spe.name)
s.setName(spe.name)
if not spe.hasCompartment() and len(self.core.compartments) == 1:
print 'Warning: species %s does not have a compartment locating it in \"%s\"' % (spe.getName(), self.core.compartments[0].getName())
spe.setCompartment(self.core.compartments[0])
elif not spe.hasCompartment() and len(self.core.compartments) >= 1:
raise UserWarning, "%s does not have a compartment and there are more than 1 to choose from!" % spe.getName()
s.setCompartment(spe.getCompartment().getName())
if spe.name in self.core.hasFixedSpecies():
s.setBoundaryCondition(True)
s.setConstant(True)
else:
s.setBoundaryCondition(False)
## print 'FUCK (%s) %s' % (spe.getName(), spe())
if spe() == None:
print 'Warning, species %s has not been initialised setting to 1.0' % spe.getName()
if spe.isAmount():
s.setInitialAmount(spe())
s.setHasOnlySubstanceUnits(True)
else:
s.setInitialConcentration(spe())
s.setHasOnlySubstanceUnits(False)
def setParameters(self):
for par in self.core.global_parameters:
p = self.model.createParameter()
p.setId(par.name)
p.setName(par.name)
p.setValue(par())
# first attempt, check for a formula ... could be done with introspection
if hasattr(par, 'formula'):
p.setConstant(False)
r = self.model.createAssignmentRule()
r.setVariable(par.name)
formula = par.code_string.split('=')[1].replace('self.','').replace('()','')
formula = self.infixPSC2SBML(formula)
r.setFormula(par.formula)
def infixPSC2SBML(self, infix):
"""replace NumPy infix with libSBMl infix"""
# symbol replacement parse (sometimes simple is better)
infix2 = str(infix)
for f in self.NumpyToMathMLkeys:
infix2 = infix2.replace(f, self.NumpyToMathML[f])
return infix2
def astSetCSymbolTime(self, ast):
"""set ASTNode type <cn> _TIME_ </cn> to <csymbol> time </csymbol>"""
strBuf = StringIO.StringIO()
mathMLin = self.SBML.writeMathMLToString(ast)
strBuf.write(mathMLin)
strBuf.seek(0)
etree = ElementTree.parse(strBuf)
root = etree.getroot()
counter = itertools.count(1)
def idxNode(node,idx=0):
if node.text != None and node.text.strip() == '_TIME_':
# <csymbol encoding="text" definitionURL="http://www.sbml.org/sbml/symbols/time"> t </csymbol>
node.text = node.text.replace('_TIME_','time')
node.tag = "{http://www.sbml.org/sbml/symbols/time}csymbol"
node.attrib.update({'encoding':'text'})
node.attrib.update({'definitionURL':'http://www.sbml.org/sbml/symbols/time'})
children = node.getchildren()
for child in range(len(children)):
idxNode(children[child], counter.next())
idxNode(root, idx=0)
strBuf = StringIO.StringIO()
etree.write(strBuf)
strBuf.seek(0)
mathMLout = strBuf.read()
return self.SBML.readMathMLFromString(mathMLout)
def setRules(self):
"""Set rate rules"""
for rule in self.core.rate_rules:
RR = self.model.createRateRule()
RR.setVariable(rule.getName())
# replace PySCeS infix with libSBML infix
form = rule.code_string.split('=')[1].replace('self.','').replace('()','')
form = self.infixPSC2SBML(form)
req_replacements = {}
for symb in rule._names:
if symb in self.core.hasReactions():
req_replacements.update({symb : '(%s)' % self.infixPSC2SBML(self.core.get(symb).code_string.split('=')[1].replace('self.','').replace('()',''))})
if len(req_replacements.keys()) > 0:
InfixParser.setNameStr('', '')
InfixParser.SymbolReplacements = req_replacements
InfixParser.parse(form)
form = InfixParser.output
ASTnode = self.SBML.parseFormula(form)
assert ASTnode != None, "ERROR: unable to parse formula (%s) to AST" % form
if self.__DEBUG__: print 'Adding RateRule: %s = %s' % (rule.getName(),form)
# set _TIME_ ASTnode tag to <csymbol> time </csymbol>
ASTnode = self.astSetCSymbolTime(ASTnode)
RR.setMath(ASTnode)
# after creating the rule set the parameter to be non constant
rpar = self.model.getParameter(rule.getName())
if rpar == None:
rpar = self.model.getCompartment(rule.getName())
if rpar == None:
rpar = self.model.getSpecies(rule.getName())
if rpar != None:
rpar.setConstant(False)
def setEvents(self):
"""Set events"""
for ev in self.core.events:
if self.__DEBUG__: print 'Adding event: %s' % ev.getName()
EV = self.model.createEvent()
EV.setName(ev.getName())
EV.setId(ev.getName())
## print ev.formula
# replace PySCeS infix with libSBML infix
form = ev.code_string.split('=')[1].replace('self.','').replace('()','')
form = self.infixPSC2SBML(form)
if self.__DEBUG__: print '\tTrigger: %s' % form
ASTnode = self.SBML.parseFormula(form)
assert ASTnode != None, "ERROR: unable to parse formula (%s) to AST" % form
# set _TIME_ ASTnode tag to <csymbol> time
ASTnode = self.astSetCSymbolTime(ASTnode)
tr = self.SBML.Trigger(ASTnode)
EV.setTrigger(tr)
for ass in ev.assignments:
if self.__DEBUG__: print '\tAssignment: %s = %s' % (ass.getName(), ass.formula)
form = self.infixPSC2SBML(ass.formula)
ASTnode = self.SBML.parseFormula(form)
eass = self.SBML.EventAssignment(ass.getName(), ASTnode)
EV.addEventAssignment(eass)
if ev.delay != 0:
dform = self.infixPSC2SBML(ev.delay)
ASTnodeD = self.SBML.parseFormula(dform)
ASTnodeD = self.astSetCSymbolTime(ASTnodeD)
D = self.SBML.Delay(ASTnodeD)
EV.setDelay(D)
def setReactions(self):
for rxn in self.core.reactions:
# print 'Adding reaction:', rxn.name
r = self.model.createReaction()
r.setId(rxn.name)
r.setName(rxn.name)
for s in rxn.substrates:
## print '\t' + rxn.name +' has substrate: ' + s.name + ' (%s)' % abs(rxn.stoichiometry[s.name])
if self.SBML.getLibSBMLVersion() < 40000:
sref = self.SBML.SpeciesReference(s.name, abs(rxn.stoichiometry[s.name]))
else:
sref = self.SBML.SpeciesReference(self.level, self.version)
sref.setStoichiometry(abs(rxn.stoichiometry[s.name]))
sref.setSpecies(s.name)
r.addReactant(sref)
for p in rxn.products:
## print '\t' + rxn.name +' has product: ' + p.name + ' (%s)' % abs(rxn.stoichiometry[p.name])
if self.SBML.getLibSBMLVersion() < 40000:
pref = self.SBML.SpeciesReference(p.name, abs(rxn.stoichiometry[p.name]))
else:
pref = self.SBML.SpeciesReference(self.level, self.version)
pref.setStoichiometry(abs(rxn.stoichiometry[p.name]))
pref.setSpecies(p.name)
r.addProduct(pref)
for m in rxn.modifiers:
## print '\t' + rxn.name +' has modifier: ' + m.name
self.model.createModifier().setSpecies(m.name)
formula = rxn.code_string.split('=')[1].replace('self.','').replace('()','')
formula = self.infixPSC2SBML(formula)
if self.SBML.getLibSBMLVersion() < 40000:
sb_kl = self.SBML.KineticLaw(formula)
else:
sb_kl = self.SBML.KineticLaw(self.level, self.version)
sb_kl.setFormula(formula)
r.setKineticLaw(sb_kl)
if rxn.reversible:
r.setReversible(True)
else:
r.setReversible(False)
def getSBMLmodel(self):
return self.model
def getSBMLdocument(self):
self.document.setModel(self.model)
return self.document
def getSBML(self):
return self.getSBMLdocument().toSBML()
def getSBMLFileAsStrBuf(self):
try: UseR = getuser()
except: UseR = ''
fb = StringIO.StringIO()
h1 = '<?xml version="1.0" encoding="utf-8"?>\n'
h1 += '<!-- Created with PySCeS ('+ __version__ + ') on ' + time.strftime("%a, %d %b %Y %H:%M:%S") + ' by '+UseR+' -->\n'
fb.write(h1 + self.getSBML())
return fb
def writeSBML2file(self, filename=None, directory=None):
if filename == None:
filename = self.name+'.xml'
if directory != None:
assert os.path.exists(directory), '\n%s does not exist.' % directory
filename = os.path.join(directory, filename)
print 'Writing file: %s' % filename
try: UseR = getuser()
except: UseR = ''
h1 = '<?xml version="1.0" encoding="utf-8"?>\n'
h1 += '<!-- Created with PySCeS ('+ __version__ + ') on ' + time.strftime("%a, %d %b %Y %H:%M:%S") + ' by '+UseR+' -->\n'
F = file(filename, 'w')
F.write(h1 + self.getSBML())
F.flush()
F.close()
print 'Model %s exported as: %s' % (self.name, filename)
class SbmlToCore(object):
SBML = None
level = 2
sbml_string = None
sbml_file = None
model = None
document = None
core = None
# old
ModelFile = None
InitParams = None
fixed_species = None
species = None
parameters = None
reactions = None
modifiers = None
compartments = None
_Function_time = None
_Function_user = None
_Function_init = None
__nDict__ = None
__functions__ = None
__rules__ = None
time = None
__eDict__ = None
notes = None
IS_SINGLE_COMPARTMENT = False
SPECIES_IN_AMOUNTS = False
__reserved__ = None
__sDict__ = None
__InitDict__ = None
__KeyWords__ = None
__Errors__ = None
__piecewises__ = None
__error_sleep_time__ = 1
_ecount = None
__uDict__ = None
__DEBUG__ = False
COMP_FUDGE_FACTOR = 1.0
def __init__(self):
try:
import libsbml as SBML
self.SBML = SBML
except Exception, e:
print e
print 'SBML load error'
self.SBML = None
assert self.SBML != None, '\nNo SBML library available'
self.__reserved__ = {'lambda':'Lambda'}
self.__KeyWords__ = {'Description': 'ModelDescription',
'Modelname': 'PySCeSModel',
'Species_In_Conc': True,
'Output_In_Conc' : True}
self.__piecewises__ = {}
def setReservedTerm(self, term, replacement):
self.__reserved__.update({term : replacement})
def getSbmlStringFromDisk(self, sbml, Dir=None):
if sbml[-4:] != '.xml':
print "Assuming .xml extension"
sbml += '.xml'
if Dir == None:
Dir = CurrentDirectory
assert os.path.exists(os.path.join(Dir, sbml)), \
'\nFile %s does not exist' % os.path.join(Dir, sbml)
self.sbml_file = os.path.join(Dir, sbml)
sbmlF = file(self.sbml_file, 'r')
self.sbml_string = sbmlF.read()
sbmlF.close()
def getSbmlStringFromString(self, sbml_string):
self.sbml_string = sbml_string
self.sbml_file = os.path.join(CurrentDirectory, 'sbml_string_loader.xml')
def getSbmlModel(self, document=None):
r = self.SBML.SBMLReader()
if document == None:
self.document = r.readSBMLFromString(self.sbml_string)
else:
self.document = document
self.sbml_string = self.document.toSBML()
self.sbml_file = os.path.join(CurrentDirectory, 'sbml_string_loader.xml')
self.model = self.document.getModel()
if self.model.getId() != 'untitled':
self.__KeyWords__['Modelname'] = self.model.getId()
else:
self.__KeyWords__['Modelname'] = self.model.getName()
self.__KeyWords__['Description'] = self.model.getName()
def getUnits(self):
self.__uDict__ = {'substance': {'exponent': 1, 'multiplier': 1.0, 'scale': 0, 'kind': 'mole'},
'volume': {'exponent': 1, 'multiplier': 1.0, 'scale': 0, 'kind': 'litre'},
'time': {'exponent': 1, 'multiplier': 1.0, 'scale': 0, 'kind': 'second'},
'length': {'exponent': 1, 'multiplier': 1.0, 'scale': 0, 'kind': 'metre'},
'area': {'exponent': 2, 'multiplier': 1.0, 'scale': 0, 'kind': 'metre'}
}
for ud in self.model.getListOfUnitDefinitions():
self.__uDict__.update({ud.getId() : {}})
if ud.getNumUnits() == 1:
u = ud.getListOfUnits()[0]
self.__uDict__[ud.getId()].update({'multiplier' : u.getMultiplier(),
'exponent' : u.getExponent(),
'scale' : u.getScale(),
'kind' : self.SBML.UnitKind_toString(u.getKind())
})
else:
for u in ud.getListOfUnits():
self.__uDict__[ud.getId()].update({self.SBML.UnitKind_toString(u.getKind()) :
{'multiplier' : u.getMultiplier(),
'exponent' : u.getExponent(),
'scale' : u.getScale(),
'kind' : self.SBML.UnitKind_toString(u.getKind())
}})
def getEvents(self):
self.__eDict__ = {}
for ev in self.model.getListOfEvents():
name = self.getId(ev)
trigger = ev.getTrigger()
triggerf = self.SBML.formulaToString(trigger.getMath())
# check for csymbol time
csymb = r'<csymbol encoding="text" definitionURL="http://www.sbml.org/sbml/symbols/time">.*<'
hasTimeS = re.search(csymb, self.SBML.writeMathMLToString(trigger.getMath()))
tSymb = None
if hasTimeS != None:
tSymb = hasTimeS.group()[hasTimeS.group().find('>'):]
tSymb = tSymb.replace('>','').replace('<','').strip()
print 'csymbol time defined as \"%s\" in event %s' % (tSymb,trigger.getId())
delay = ev.getDelay()
if delay != None:
delay = self.SBML.formulaToString(ev.getDelay().getMath())
else:
delay = 0.0
self.__eDict__.update({name : {'name' : name,
'trigger' : triggerf,
'delay' : delay,
'assignments' : {},
'tsymb' : tSymb
}
})
for a in ev.getListOfEventAssignments():
self.__eDict__[name]['assignments'].update({a.getVariable() :
self.SBML.formulaToString(a.getMath())
})
def checkParsedInfix(self):
assert len(InfixParser.SymbolErrors) == 0, '\nUndefined symbols:\n%s' % InfixParser.SymbolErrors
assert InfixParser.LexOK, '\nLexer Failure:\n%s' % InfixParser.LexErrors
assert InfixParser.ParseOK, '\nParser Failure:\n%s' % InfixParser.ParseErrors
def getId(self, e):
name = e.getId()
if name in self.__reserved__:
print '%s is a reserved symbol, replacing with %s' % (name, self.__reserved__[name])
self.__Errors__.update({self._ecount.next() : 'Reserved symbol %s replaced with %s' % (name, self.__reserved__[name])})
name = self.__reserved__[name]
return name
def updatePiecewiseDict(self, piecewises):
if len(piecewises.keys()) > 0:
for p in piecewises:
if len(piecewises[p].keys()) == 2:
piecewises[p][0].reverse()
self.__piecewises__.update({p : piecewises[p]})
def getParsedModel(self):
init_fixed = {}
init_var = {}
init_par = {}
self.__compartments__ = {}
# new stuff
self.__functions__ = {}
self.SPECIES_IN_AMOUNTS = False
self.__sDict__ = {}
self.__InitDict__ = {}
self.__Errors__ = {}
self._ecount = itertools.count()
# Initialise compartment volumes as a parameter - brett 20050908
for comp in self.model.getListOfCompartments():
cont = comp.getOutside()
if cont == '': cont = None
cSize = float(comp.getSize())
self.__compartments__.update({self.getId(comp):{'name':self.getId(comp),
## 'volume': float(comp.getVolume()),
'size': cSize,
'dimensions' : int(comp.getSpatialDimensions()),
'compartment': cont,
'area' : None
}})
self.COMP_FUDGE_FACTOR = 1.0
startFudging = 1.0e-6
I_AM_FUDGING = False
tmp = min([abs(self.__compartments__[c]['size']) for c in self.__compartments__.keys()])
if tmp < startFudging:
self.COMP_FUDGE_FACTOR = tmp # sneaky b%*))_)%$^&*@rds
for c in self.__compartments__.keys():
if self.COMP_FUDGE_FACTOR < startFudging:
newsize = self.__compartments__[c]['size']/self.COMP_FUDGE_FACTOR
print 'INFO: Rescaling compartment with size %s to %s' % (self.__compartments__[c]['size'], newsize)
self.__compartments__[c]['size'] = newsize
self.__compartments__[c].update({'scale' : self.COMP_FUDGE_FACTOR})
I_AM_FUDGING = True
if len(self.__compartments__) == 1:
self.IS_SINGLE_COMPARTMENT = True
else:
self.IS_SINGLE_COMPARTMENT = False
if len(self.model.getListOfSpecies()) < 1:
self.__Errors__.update({self._ecount.next() : 'No free species!? ... help I\'m confused!'})
for i in self.model.getListOfSpecies():
specname = self.getId(i)
if i.getHasOnlySubstanceUnits():
if not self.SPECIES_IN_AMOUNTS:
self.SPECIES_IN_AMOUNTS = True
if self.SPECIES_IN_AMOUNTS:
self.__KeyWords__['Species_In_Conc'] = False
else:
self.__KeyWords__['Species_In_Conc'] = True
self.__KeyWords__['Output_In_Conc'] = True
for i in self.model.getListOfSpecies():
specname = self.getId(i)
if self.__DEBUG__: print '%s has only substance units: %s' % (specname, i.getHasOnlySubstanceUnits())
IS_CONC = i.isSetInitialConcentration()
IS_AMNT = i.isSetInitialAmount()
Conc = float(i.getInitialConcentration())
Amount = float(i.getInitialAmount())
if self.SPECIES_IN_AMOUNTS or IS_AMNT:
if I_AM_FUDGING:
Conc = Amount/self.COMP_FUDGE_FACTOR
else:
Conc = Amount
fxd = None
if i.getBoundaryCondition() or i.getConstant():
if i.getConstant() and not i.getBoundaryCondition():
print '%s is set as constant, assuming: BoundaryCondition = True' % specname
init_fixed.setdefault(specname, Conc)
fxd = True
else:
init_var.setdefault(specname, Conc)
fxd = False
self.__sDict__.update({specname : {
'name' : specname,
'initial' : Conc,
'compartment' : i.getCompartment(),
'fixed' : fxd,
'isamount' : i.getHasOnlySubstanceUnits(),
}})
reactions = self.model.getListOfReactions()
NetworkDict = dict([(i, dict.fromkeys(['Params',
'RateEq',
'Reagents',
'Modifiers',
'Type'])) for i in [self.getId(j) for j in reactions]])
# Add global parameters
Punits = []
if len(self.model.getListOfParameters()) > 0:
for xp in self.model.getListOfParameters():
if xp.isSetUnits():
Punits.append(self.getId(xp))
init_par.update({self.getId(xp) : float(xp.getValue())})
if len(Punits) > 0:
self.__Errors__.update({self._ecount.next() : 'Parameter units ignored for parameters:\n%s' % Punits})
# add any function definitions
if self.model.getNumFunctionDefinitions() > 0:
for fnc in self.model.getListOfFunctionDefinitions():
name = self.getId(fnc)
func = self.SBML.formulaToString(fnc.getMath()).replace('lambda','')[1:-1]
args = []
for ar in range(fnc.getNumArguments()):
arg = func[:func.find(',')]
func = func[func.find(',')+1:]
args.append(arg)
args = [s.strip() for s in args]
func = func.strip()
csymb = r'<csymbol encoding="text" definitionURL="http://www.sbml.org/sbml/symbols/time">.*<'
hasTimeS = re.search(csymb, self.SBML.writeMathMLToString(fnc.getMath()))
tSymb = None
if hasTimeS != None:
tSymb = hasTimeS.group()[hasTimeS.group().find('>'):]
tSymb = tSymb.replace('>','').replace('<','').strip()
print 'csymbol time defined as \"%s\" in formula %s' % (tSymb,self.getId(fnc))
SRs = {tSymb:'_TIME_'}
SRs.update(self.__reserved__)
InfixParser.SymbolReplacements = SRs
InfixParser.setNameStr('', '')
InfixParser.parse(func)
p_names = InfixParser.names
func = InfixParser.output
self.checkParsedInfix()
# update piecewise dict ... don't ask!
self.updatePiecewiseDict(InfixParser.piecewises)
self.__functions__.update({name : {
'args' : args,
'formula' : func,
'name' : name }
})
# ======= per reaction stuff ========
hasFast = []
Punits = []
delayignore = []
for i in reactions:
rDict = NetworkDict[self.getId(i)]
rDict.update({'name':self.getId(i)})
j = i.getKineticLaw()
# ignore fast and warn
if i.isSetFast():
hasFast.append(self.getId(i))
par = []
req = j.getFormula()
p_names = None
# check for csymbol time
csymb = r'<csymbol encoding="text" definitionURL="http://www.sbml.org/sbml/symbols/time">.*<'
hasTimeS = re.search(csymb, self.SBML.writeMathMLToString(j.getMath()))
tSymb = None
if hasTimeS != None:
tSymb = hasTimeS.group()[hasTimeS.group().find('>'):]
tSymb = tSymb.replace('>','').replace('<','').strip()
print 'csymbol time defined as \"%s\" in reaction %s' % (tSymb,self.getId(i))
#if there are local parameters hash them to R_P
if len(j.getListOfParameters()) > 0:
InfixParser.setNameStr('@', '@')
if hasTimeS != None:
SRs = {tSymb:'_TIME_'}
SRs.update(self.__reserved__)
InfixParser.SymbolReplacements = SRs
else:
InfixParser.SymbolReplacements = self.__reserved__
InfixParser.parse(req)
p_names = InfixParser.names
# catch delay and friends (ie check for shitty rate equations)
self.checkParsedInfix()
req = InfixParser.output
if InfixParser.DelayRemoved:
delayignore.append(self.getId(i))
if self.__DEBUG__: print 'Setting local parameter:'
for k in j.getListOfParameters():
if k.isSetUnits() and self.getId(k) not in Punits:
Punits.append(self.getId(k))
#TODO: replace with a regular expression based strategy
req = req.replace('@'+self.getId(k)+'@', self.getId(i) + '_' + self.getId(k))
par.append(self.getId(i) + '_' + self.getId(k))
init_par.setdefault(self.getId(i) + '_' + self.getId(k), k.getValue())
# local parameters are hashed with reaction name
if self.__DEBUG__: print '%s_%s' % (self.getId(i), self.getId(k)),
if self.__DEBUG__: print ''
req = req.replace('@','')
else:
InfixParser.setNameStr('', '')
if hasTimeS != None:
SRs = {tSymb:'_TIME_'}
SRs.update(self.__reserved__)
InfixParser.SymbolReplacements = SRs
else:
InfixParser.SymbolReplacements = self.__reserved__
InfixParser.parse(req)
p_names = InfixParser.names
req = InfixParser.output
if InfixParser.DelayRemoved:
delayignore.append(self.getId(i))
self.checkParsedInfix()
# update piecewise dict ... don't ask!
self.updatePiecewiseDict(InfixParser.piecewises)
if req == None: raw_input('Error in file: %s' % self.sbml_file)
rDict['Params'] = par
rDict['RateEq'] = req
rDict['compartment'] = None
Substrates = []
Products = []
for k in i.getListOfReactants():
species = k.getSpecies()
stoich = -k.getStoichiometry()
Substrates.append((species,stoich))
# kill/collect stoichiometrymath for future processing
smath = k.getStoichiometryMath()
if smath != None:
self.__Errors__.update({self._ecount.next() : 'StoichiometryMath (%s) not supported and ignored' % k.getSpecies()})
for k in i.getListOfProducts():
species = k.getSpecies()
stoich = k.getStoichiometry()
Products.append((species,stoich))
# kill/collect stoichiometrymath for future processing
smath = k.getStoichiometryMath()
if smath != None:
self.__Errors__.update({self._ecount.next() : 'StoichiometryMath (%s) not supported and ignored' % k.getSpecies()})
# work with net stoichiometries
rDict['Reagents'] = {}
rtmp = rDict['Reagents']
for sp in Substrates+Products:
if not rtmp.has_key(sp[0]):
rtmp.update({sp[0] : sp[1]})
else:
rtmp[sp[0]] += sp[1]
for r in rtmp.keys():
if abs(rtmp[r]) < 1.0e-14:
rtmp.pop(r)
if i.getReversible() == True:
t = 'Rever'
else:
t = 'Irrev'
rDict['Type'] = t
NetworkDict[self.getId(i)].update(rDict)
mods = []
if len(i.getListOfModifiers()) > 0:
for m in i.getListOfModifiers():
msbml = m.toSBML().split('\"')[1]
mods.append(msbml)
else:
mods = []
rDict['Modifiers'] = mods
#print "Modifiers", rDict['Modifiers']
if len(hasFast) > 0:
self.__Errors__.update({self._ecount.next() : 'Fast attribute ignored for reactions:\n%s' % hasFast})
if len(Punits) > 0:
self.__Errors__.update({self._ecount.next() : 'Parameter units ignored for (local) parameters:\n%s' % Punits})
if len(delayignore) > 0:
self.__Errors__.update({self._ecount.next() : 'delay fucntion removed in reactions:\n%s' % delayignore})
del hasFast, Punits, delayignore
# ======= Add Other Model components ========
self.getEvents()
self.getRules()
self.notes = ''
if self.model.getNotes() is not None:
self.notes = self.model.getNotesString().replace('\n','\n# ')
self.ModelFile = self.model.getId()
if len(self.ModelFile) == 0:
self.ModelFile = self.model.getName()
InitStrings = []
for s in init_var.keys():
self.__InitDict__.update({s : float(init_var[s])})
setattr(self, s, float(init_var[s]))
for s in init_fixed.keys():
self.__InitDict__.update({s : float(init_fixed[s])})
setattr(self, s, float(init_fixed[s]))
for s in init_par.keys():
self.__InitDict__.update({s : float(init_par[s])})
setattr(self, s, float(init_par[s]))
self.InitParams = init_par.keys()
self.fixed_species = init_fixed.keys()
self.species = init_var.keys()
self.parameters = init_par.keys()
self.reactions = NetworkDict.keys()
self.modifiers = []
for r in NetworkDict.keys():
self.modifiers.append((r, NetworkDict[r]['Modifiers']))
if len(self.__rules__.keys()) > 0:
self._Function_forced = ''
for r in self.__rules__.keys():
self._Function_forced += self.__rules__[r]['name'] + ' = ' +\
self.__rules__[r]['formula'] + '\n'
else:
self._Function_forced = 'pass\n'
self._Function_time = ''
self._Function_user = ''
self._Function_init = ''
self.__nDict__ = NetworkDict
if len(self.__Errors__.keys()) > 0:
print '\n*******************************************************************'
## print 'Errors encountered in SBML translated!'
print 'Issues encountered in SBML translation (model processed anyway)'
print 'SBML source: %s' % self.sbml_file
print '*******************************************************************\n'
ekeys = self.__Errors__.keys()
ekeys.sort()
for e in ekeys:
print self.__Errors__[e],'\n'
print '*******************************************************************\n'
time.sleep(self.__error_sleep_time__)
def getRules(self):
self.__rules__ = {}
for rule in self.model.getListOfRules():
rtype = 'unknown'
if rule.isAssignment():
rtype = 'assignment'
elif rule.isRate():
rtype = 'rate'
elif rule.isAlgebraic():
rtype = 'algebraic'
self.__Errors__.update({self._ecount.next() : 'Algebraic rule (%s) ignored' % rule.getFormula()})
assert rtype in ['assignment', 'rate', 'algebraic'], '\n%s rules currently not supported.' % rtype
csymb = r'<csymbol encoding="text" definitionURL="http://www.sbml.org/sbml/symbols/time">.*<'
hasTimeS = re.search(csymb, self.SBML.writeMathMLToString(rule.getMath()))
tSymb = None
formula = rule.getFormula()
p_names = None
if hasTimeS != None:
tSymb = hasTimeS.group()[hasTimeS.group().find('>'):]
tSymb = tSymb.replace('>','').replace('<','').strip()
print 'csymbol time defined as \"%s\" in rule %s' % (tSymb, self.getId(rule))
InfixParser.setNameStr('', '')
SRs = {tSymb:'_TIME_'}
SRs.update(self.__reserved__)
InfixParser.SymbolReplacements = SRs
InfixParser.parse(formula)
p_names = InfixParser.names
formula = InfixParser.output
pws = InfixParser.piecewises
self.checkParsedInfix()
else:
InfixParser.setNameStr('', '')
InfixParser.SymbolReplacements = self.__reserved__
InfixParser.parse(formula)
p_names = InfixParser.names
formula = InfixParser.output
pws = InfixParser.piecewises
self.checkParsedInfix()
# update piecewise dict ... don't ask!
self.updatePiecewiseDict(InfixParser.piecewises)
self.__rules__.update({rule.getVariable() :
{'name' : rule.getVariable(),
'formula' : formula,
'type' : rtype,
'_names' : p_names
}
})
def removeCompartmentFromKineticLaw(self, kl):
strBuf = StringIO.StringIO()
mathMLin = self.SBML.writeMathMLToString(kl.getMath())
strBuf.write(mathMLin)
strBuf.seek(0)
etree = ElementTree.parse(strBuf)
root = etree.getroot()
node_idx = {}
counter = itertools.count(1)
self._comp_idx = []
def idxNode(node,idx=0):
## print 'node.tag', node.tag
node.attrib.update({'idx':str(idx)})
node_idx.update({idx:node})
if node.text != None and node.text.strip() in self.__compartments__.keys():
node.attrib.update({'compartment':'1'})
self._comp_idx.append(idx)
else:
node.attrib.update({'compartment':'0'})
children = node.getchildren()
for child in range(len(children)):
children[child].attrib.update({'parent':str(idx)})
## print '\tchild.tag', children[child].tag
idxNode(children[child], counter.next())
idxNode(root, idx=0)
if len(self._comp_idx) > 0:
for comp_idx in self._comp_idx:
cParent = int(node_idx[comp_idx].attrib['parent'])
if len(node_idx[cParent].getchildren()) == 3 and\
node_idx[cParent].getchildren()[0].tag == '{http://www.w3.org/1998/Math/MathML}times':
for c in node_idx[cParent].getchildren():
if c.tag != '{http://www.w3.org/1998/Math/MathML}times' and c.text.strip() not in self.__compartments__.keys():
cParentParent = int(node_idx[cParent].attrib['parent'])
for cp in node_idx[cParentParent].getchildren():
if cp.attrib['idx'] == node_idx[cParent].attrib['idx']:
cidx = node_idx[cParentParent]._children.index(cp)
node_idx[cParentParent].remove(node_idx[cParent])
c.attrib.update({'parent' : node_idx[cParentParent].attrib['idx']})
node_idx[cParentParent].insert(cidx, c)
break
elif len(node_idx[cParent].getchildren()) == 2 and\
node_idx[cParent].getchildren()[0].tag == '{http://www.w3.org/1998/Math/MathML}minus':
for c in node_idx[cParent].getchildren():
## print c.tag, c.attrib
if c.tag == '{http://www.w3.org/1998/Math/MathML}minus':
cParentParent = int(node_idx[cParent].attrib['parent'])
for cp in node_idx[cParentParent].getchildren():
## print cp.attrib['idx'], node_idx[cParent].attrib['idx']
if cp.attrib['idx'] == node_idx[cParent].attrib['idx']:
cidx = node_idx[cParentParent]._children.index(cp)
node_idx[cParentParent].remove(node_idx[cParent])
c.attrib.update({'parent' : node_idx[cParentParent].attrib['idx']})
node_idx[cParentParent].insert(cidx, c)
break
elif len(node_idx[cParent].getchildren()) > 3:
for c in node_idx[cParent].getchildren():
if c.text != None and c.text.strip() in self.__compartments__.keys():
node_idx[cParent].remove(node_idx[comp_idx])
break
for n in node_idx:
if node_idx[n].attrib.has_key('idx'):
node_idx[n].attrib.pop('idx')
if node_idx[n].attrib.has_key('compartment'):
node_idx[n].attrib.pop('compartment')
if node_idx[n].attrib.has_key('parent'):
node_idx[n].attrib.pop('parent')
strBuf = StringIO.StringIO()
etree.write(strBuf)
strBuf.seek(0)
mathMLout = strBuf.read()
newAST = self.SBML.readMathMLFromString(mathMLout)
kl.setMath(newAST)
|