1 '''
2 Datamodel used for the merging
3 '''
4
5
6 import libsbml
7 import sys
8
9 import libSBAnnotation.config
10 import annotate
11 import merge_logic
12 import sbo
13 import xmlobject
14
15
17
20
22 return self.errorMessage
23
25 return self.errorMessage
26
29 self.errorMessage = 'Error in Merge_BioQuantity: %s'% message
30
32 '''
33 The MergeBase provides basic values that are needed to handle libsbml elements
34 - the libsbml element itself
35 - the model representation (L{OriginModel}) belonging to the element
36 - the element type e.g. reaction
37 - a string representation of the element (element name or id)
38 '''
39 - def __init__(self,libsbml_element,merge_model):
40 self.libsbml_element = libsbml_element
41 if not merge_model: self.libsbml_model = None
42 else: self.libsbml_model = merge_model.libsbml_model
43 self.type = libsbml_element.getElementName()
44 self.repr = libsbml_element.getName() or libsbml_element.getId()
45 self.merge_model = merge_model
46
65
66
68 - def __init__(self,libsbml_element,merge_model):
69 MergeBase.__init__(self,libsbml_element,merge_model)
70
71 self.searchUnit= lambda x: self.merge_model.global_unit_defs[x]
73 raise NotImplementedError
81 raise NotImplementedError
83 if self.type != 'reaction':
84 self.unit=unitdef
86 raise NotImplementedError
88 self.location=location
89
91
93
94 if self.libsbml_element.getHasOnlySubstanceUnits():
95 return 'Amount'
96 else:
97 return 'Concentration'
98
100 if type=='Concentration':
101 self.libsbml_element.setHasOnlySubstanceUnits(False)
102 if type =='Amount':
103 self.libsbml_element.setHasOnlySubstanceUnits(True)
104
106 if self.getQuantityType == 'Concentration':
107 substance=self.merge_model.global_unit_defs['substance']
108 su=self.libsbml_element.getSubstanceUnits()
109 if su:
110 substance = self.searchUnit(su)
111 volume = self.location.getUnit(True)
112 vo=self.libsbml_element.getSpatialSizeUnits()
113 if vo:
114 volume = self.searchUnit(vo)
115
116 return UnitDef(unit_defs=(substance,volume))
117 else:
118 units=self.libsbml_element.getUnits()
119 if units:
120 return self.searchUnit(units)
121 else:
122 return self.merge_model.global_unit_defs['substance']
123
125 return self.merge_model.id2merge_element[self.libsbml_element.getCompartment()]
126
127
129 - def __init__(self,libsbml_element,merge_model):
130 SubBioquantity.__init__(self,libsbml_element,merge_model)
131 self.entity_types=['Reactant','Modifier','Product']
132
133
135 '''
136 @rtype entities: {'Reactant':[],'Modifier':[],'Product':[]}
137 '''
138 ret={'Reactant':[],'Modifier':[],'Product':[]}
139
140 for part in self.entity_types:
141 for i in range(getattr(self.libsbml_element,'getNum%ss'%part)()):
142 ret[part].append(self.merge_model.id2merge_element[getattr(self.libsbml_element,'get%s'%part)(i).getSpecies()])
143
144
145
146
147
148 return ret
149
150
152 '''
153 @type entities: {'Reactant':[],'Modifier':[],'Product':[]}
154 '''
155 for type in self.entity_types:
156 list_of = getattr(self.libsbml_element,'getListOf'+type+'s')()
157 list_of.clear()
158 for me in entities[type]:
159 species_reference=getattr(self.libsbml_element,'create'+type)()
160 if me.getTuple():
161 species_reference.setSpecies(me.getTuple().getMergedElement().getId())
162 else:
163 species_reference.setSpecies(me.getId())
164
165
167 time=self.merge_model.global_unit_defs['time']
168 return UnitDef(unit_defs=(self.merge_model.global_unit_defs['substance'],time))
169
170
172 res=[]
173
174
175
176 for type in self.entity_types:
177 tmp_res=set()
178 if getattr(self.libsbml_element,'getNum'+type+'s')()>0:
179 for n in range(getattr(self.libsbml_element,'getNum'+type+'s')()):
180 tmp_res.add(self.merge_model.id2merge_element[getattr(self.libsbml_element,'get'+type)(n).getSpecies()].getLocation())
181 res.append(list(tmp_res))
182 return res
183
184
186
187 - def __init__(self,libsbml_element,merge_model):
190
191
193 dim2type=dict(zip(range(1,4),self.qtypes))
194 try:
195 return dim2type[self.libsbml_element.getSpatialDimensions()]
196 except KeyError:
197 return ''
198
200 type2dim=dict(zip(self.qtypes,range(1,4)))
201 try:
202 self.libsbml_element.setSpatialDimensions(type2dim[type])
203 except KeyError:
204 raise MergeError('Unknown Quantity Type')
205
207 units=self.libsbml_element.getUnits()
208 if not units:
209 dim2type=dict(zip(range(1,4),self.qtypes))
210 spacialDimension=self.libsbml_element.getSpatialDimensions()
211 return self.merge_model.global_unit_defs[dim2type[spacialDimension]]
212 else:
213 return self.searchUnit(units)
214
216 if self.libsbml_element.isSetOutside():
217 if self.libsbml_element.getOutside():
218 return self.merge_model.id2merge_element[self.libsbml_element.getOutside()]
219 else:
220 raise MergeBioQuantityLocationError('requeue location since it is linking to a yet unknown location')
221
223
225 unit=self.libsbml_element.getUnits()
226 if not unit:
227
228 return None
229 else:
230 return self.searchUnit(unit)
231
233 - def __init__(self,libsbml_element,merge_model):
237 raise NotImplementedError
239 raise NotImplementedError
241 if self.type in ['species','parameter','compartment']:
242 return self.libsbml_element.getConstant()
243 else:
244 raise NotImplementedError
246 if self.type in ['species','parameter','compartment']:
247 if isinstance(val,str):
248 if val=='True': val=True
249 elif val=='False': val=False
250 else: raise MergeError(' setConstant failed because % was inserted'%val)
251 if not isinstance(val, bool):val=bool(val)
252 self.libsbml_element.setConstant(val)
253 self.constant=val
254 else:
255 raise NotImplementedError
256
258 raise NotImplementedError
260 raise NotImplementedError
262 raise NotImplementedError
264 raise NotImplementedError
266 raise NotImplementedError
268 raise NotImplementedError
270 raise NotImplementedError
272 raise NotImplementedError
274 '''
275 overwritten by reaction subclass
276 '''
277 if self.statement: return self.statement
278 math_obj=None
279 if self.merge_model.id2rule.has_key(self.libsbml_element.getId()):
280
281
282 math_obj = self.merge_model.id2rule[self.libsbml_element.getId()]
283
284
285 if math_obj:
286 self._attatchFunctionDefinition(math_obj)
287 return math_obj
288
290 self.statement = math_obj
292 if self.merge_model.id2assignment.has_key(self.libsbml_element.getId()):
293 ia=self.merge_model.id2assignment[self.libsbml_element.getId()]
294 self._attatchFunctionDefinition(ia)
295 return ia
296
298 self.initialAssignment=math_obj
299
301 for en in merge_logic.BioRelations().getMathElementNames(math_obj.getMath()):
302 if self.merge_model.id2function_definition.has_key(en):
303 try:
304 math_obj.functionDefinitions.append(self.merge_model.id2function_definition[en].clone())
305 except AttributeError,e:
306 math_obj.functionDefinitions=[self.merge_model.id2function_definition[en].clone()]
307
309
312
314 if not isinstance(val,float):val=float(val)
315 return self.libsbml_element.setCharge(val)
316 self.charge=val
317
319 if self.libsbml_element.isSetInitialConcentration():
320 return ('Concentration',self.libsbml_element.getInitialConcentration())
321 if self.libsbml_element.isSetInitialAmount():
322 return ('Amount',self.libsbml_element.getInitialAmount())
323
325 if not isinstance(val,tuple):
326 raise OriginModelStatementError('ModelStatement quantity for a species must be a tuple (type,value)')
327 type=val[0]
328 value=val[1]
329 if not isinstance(value, float):value=float(value)
330 if type=='Concentration':
331 self.libsbml_element.setInitialConcentration(value)
332 elif type=='Amount':
333 self.libsbml_element.setInitialAmount(value)
334 else:
335 nononothisisnotright
336 self.quantity=val
337
338
340
342 return self.libsbml_element.getFast()
343
345 if not isinstance(val, bool):val=bool(val)
346 self.libsbml_element.setFast(val)
347 self.fast=val
348
349
352
354 if not isinstance(val, bool):val=bool(val)
355 self.libsbml_element.setReversible(val)
356 self.reversible=val
357
358
360 math_obj = self.libsbml_element.getKineticLaw()
361
362 if math_obj:
363 self._attatchFunctionDefinition(math_obj)
364 return math_obj
365
367
368 self.statement = math_obj
369 self.libsbml_element.setKineticLaw(math_obj)
370
371
373
375 if self.libsbml_element.isSetSize():
376 return self.libsbml_element.getSize()
377
379 if not isinstance(val, float):val=float(val)
380 self.libsbml_element.setSize(val)
381
382
383
385
387 if self.libsbml_element.isSetValue():
388 return ('Value',self.libsbml_element.getValue())
389
391 if not isinstance(val, float):val=float(val)
392 return self.libsbml_element.setSize(val[1])
393
394
396 '''
397 abstraction of a biological entity for merging
398
399 wrap class that consists of three sublcass of the base type
400 - SubBioentity
401 - SubBioquantity
402 - SubModelstatement
403 '''
404 - def __init__(self,libsbml_element,merge_model):
405
406
407 MergeBase.__init__(self,libsbml_element,merge_model)
408
409
410
411
412 self.name = libsbml_element.getName()
413 self.id = libsbml_element.getId()
414 self.newid = self.id
415
416 self.mid=self.id
417
418
419
420 self._merge_tuple_candidates=set()
421 self.tuple=None
422
423
424 self.sig_tuple_changed=None
425
426
427
428 self._bioentity = SubBioentity(self.libsbml_element)
429 self._bioquantity = globals()['SubBioquantity%s'%self.type.title()](self.libsbml_element,merge_model)
430 self._modelstatement = globals()['SubModelstatement%s'%self.type.title()](self.libsbml_element,merge_model)
431
432 self._allattributes = dict([(x,self._bioentity) for x in dir(self._bioentity) if not '_' == x[0]]+\
433 [(x,self._bioquantity) for x in dir(self._bioquantity) if not '_' in x]+\
434 [(x,self._modelstatement) for x in dir(self._modelstatement) if not '_' in x])
435
436
437
439 '''
440 realize wrap pattern!
441 make methods of the sub objects
442 - SubBioquantity
443 - SubBioentity
444 - SubModelstatement
445 directly accessible
446 '''
447 if n in self._allattributes:
448 return getattr(self._allattributes[n], n)
449 else:
450 raise AttributeError, n
451
454
457
459 '''
460 set an external function that should be executed when the tuple this element belongs to is changed
461 @type tuple_changed_fkt: function pointer
462 '''
463
464 self.sig_tuple_changed=tuple_changed_fkt
465
467 '''
468 add and element to the list of similar elements
469 @type element: OriginElement
470 '''
471 neighbous=[]
472 if self.tuple and not force:neighbous=self.tuple.getElements()
473 if self.merge_model!=element.merge_model and not (element in neighbous):
474 self._merge_tuple_candidates.add(element)
475
477 '''
478 update the list of similar elements
479 @type elements: [OriginElement]
480 '''
481 for e in elements:
482 self.addTupleCandidate(e)
483
485 '''
486 returns a list of similar elements, elements that have matching MIRIAM annotations
487 @rtype: [OriginElement]
488 '''
489 return list(self._merge_tuple_candidates)
491 '''
492 returns the L{MergeTuple} the element instance belongs to, if it does not belong to an element None is returnend
493 @rtype: MergeTuple or None
494 '''
495 return self.tuple
497 '''
498 set the L{MergeTuple} the element belongs to
499 if an external function of a view is set, call the function so the view can be updated
500 @type tuple: MergeTuple
501 '''
502
503
504 old_tuple=self.tuple
505 self.tuple=tuple
506 if self.sig_tuple_changed and self.tuple!=old_tuple:
507
508
509 merge_logic.BioRelations().elements_update_queue=merge_logic.BioRelations().elements_update_queue.union(self.getDependingElements())
510
511
512 self.sig_tuple_changed(self)
513
515 '''
516 set the "new" id, this identifier is globally unique in the merged model
517 @type id: str
518 '''
519 self.newid=id
522
523
524
525
526
527
528
529
531 '''
532 abstraction of a model for merging
533 a model contains biological entities that can be merged
534 '''
536 '''
537 '''
538
539 self.libsbml_model = libsbml_model
540 self.mid = mid
541 self.repr = self.libsbml_model.getName() or self.libsbml_model.getId()
542
543 self.global_unit_defs={}
544 self._getUnits()
545
546
547 self.id2rule = self._getRules()
548
549
550 self.id2assignment={}
551 for asm in list(self.libsbml_model.getListOfInitialAssignments()):
552 self.id2assignment[asm.getId()]=asm
553
554 self.id2function_definition={}
555 for fd in list(self.libsbml_model.getListOfFunctionDefinitions()):
556 self.id2function_definition[fd.getId()]=fd
557 self._buildElements()
558
560
561
562
563 self._merge_elements=[]
564
565 compartment_queue=list(self.libsbml_model.getListOfCompartments())
566 while compartment_queue:
567 element = compartment_queue.pop(0)
568 try:
569 self._merge_elements.append(OriginElement(element,self))
570 except MergeBioQuantityLocationError:
571 compartment_queue.append(element)
572
573 for listname in ("Species", "Parameters", "Reactions"):
574 for element in getattr(self.libsbml_model, 'getListOf' + listname)():
575 self._merge_elements.append(OriginElement(element,self))
576
577 self.id2merge_element=dict([(x.id, x) for x in self._merge_elements])
578
579
580
581 self._type2merge_elements={'species':[],'parameter':[],'reaction':[],'compartment':[]}
582 for me in self._merge_elements:
583 self._type2merge_elements[me.type].append(me)
584
585
586 self.element_depends_on = {}
587 self.elements_depending_on = {}
588
589 for e in self.getElements():
590 self.element_depends_on[e] = self._dependingElements(e)
591 for de in self.element_depends_on[e]:
592 if de in self.elements_depending_on: self.elements_depending_on[de].add(e)
593 else: self.elements_depending_on[de]=set([e])
594 for e in [x for x in self.getElements() if not x in self.elements_depending_on.keys()]:
595 self.elements_depending_on[e]=set([])
596
598 return self._merge_elements
599
601 type2compare_types = {
602 'species':['species','parameter'],
603 'parameter':['parameter','species','compartment'],
604 'reaction':['reaction'],
605 'compartment':['compartment','parameter'],
606 }
607 res=[]
608 for t in type2compare_types[type]:
609 res+=self._type2merge_elements[t]
610 return res
611
613 out={}
614 for rule in list(self.libsbml_model.getListOfRules()):
615 if isinstance(rule, libsbml.AssignmentRule) or isinstance(rule, libsbml.RateRule):
616 out[rule.getVariable()]=rule
617 elif isinstance(rule, libsbml.AlgebraicRule):
618 raise MergeError('AlgebraicRules are currently not supported.')
619 return out
620
622 '''
623 build a list of units defined in the model
624 complete list with standard units
625 this funtion takes no input and creates no output but fills self.global_unit_defs
626 '''
627
628
629 for ud in list(self.libsbml_model.getListOfUnitDefinitions()):
630 self.global_unit_defs[ud.getId()]=UnitDef(ud)
631
632
633 x = xmlobject.XMLFile(path=libSBAnnotation.config.Config().getpath('resources','libsbml_resources'))
634 for unit in x.root.DefaultUnitDefinitions[0].unit:
635 if not self.global_unit_defs.has_key(unit.id):
636 self.global_unit_defs[unit.id]=UnitDef(default_unit_def_name=unit.id)
637 for unit in x.root.knownUnits[0].kinds.split():
638 if not self.global_unit_defs.has_key(unit):
639 self.global_unit_defs[unit]=UnitDef(default_unit_def_name=unit)
640
665
666
668 '''
669 get a list of elements depending on the inserted element
670 @rtype: set(L{OriginElement})
671 '''
672 return [self.id2merge_element[ret] for ret in self.elements_depending_on[element] if isinstance(ret,str)]+[ret for ret in self.elements_depending_on[element] if not isinstance(ret,str)]
673
675 '''
676 get e list of elements the inserted element depends on
677 @rtype: set(L{OriginElement})
678 '''
679 return [self.id2merge_element[ret] for ret in self.element_depends_on[element] if isinstance(ret,str)]+[ret for ret in self.element_depends_on[element] if not isinstance(ret,str)]
680
681
683 - def __init__(self,libsbml_model,origin_models):
684 OriginModel.__init__(self,libsbml_model,'M')
685 self.id2merge_element={}
686 self.global_unit_defs={}
687 self.id2rule={}
688 for m in origin_models:
689
690
691 self.id2merge_element.update(m.id2merge_element)
692 self.global_unit_defs.update(m.global_unit_defs)
693 self.id2rule.update(m.id2rule)
694
700 self.id2merge_element[element.getId()]=element
702 self.id2merge_element.pop(element.getId())
703
704
705
706
707
708
710 '''
711 unit definition
712 can contain multiple L{Unit}s
713 '''
714 - def __init__(self,libsbml_unit_definition=None,default_unit_def_name='',unit_defs=[]):
715 '''
716 either a libsbml.UnitDefinition is inserted or the name of a default unit,
717 the default units are looked up in the libsbmlresource
718
719 @type libsbml_unit_definition: L{libsbml.UnitDefinition}
720 @type default_unit_def_name: str
721 @type unit_items= [Unit]
722 '''
723 self.id=''
724 self.unit_items=[]
725 self.unit_defs=()
726 self.type=''
727 self.libsbml_ud=None
728
729 if libsbml_unit_definition:
730 self.type='libsbml'
731 self.libsbml_ud=libsbml_unit_definition
732 self.id=libsbml_unit_definition.getId()
733 for unit_item in list(libsbml_unit_definition.getListOfUnits()):
734 self.unit_items.append(Unit(libsbml.UnitKind_toString(unit_item.getKind()),unit_item.getScale() or 0.0 ,unit_item.getMultiplier() or 1.0,unit_item.getExponent()))
735 elif default_unit_def_name:
736 self.type='default'
737 x = xmlobject.XMLFile(path=libSBAnnotation.config.Config().getpath('resources','libsbml_resources'))
738 for xml_unit in x.root.DefaultUnitDefinitions[0].unit:
739 if xml_unit.id==default_unit_def_name:
740 try:
741 exponent=xml_unit.exponent
742 except:
743 exponent=1.0
744 self.unit_items.append(Unit(kind=xml_unit.kind,exponent=exponent))
745 break
746 else:
747 self.unit_items.append(Unit(default_unit_def_name))
748 elif unit_defs:
749 self.type='composed'
750 self.unit_defs=unit_defs
751 else:
752 raise MergeError('UnitDef was not properly initialized')
753
755 '''
756 return a html string representation of the unit definition
757 '''
758 seperator='*'
759 res=''
760
761 if self.unit_defs and self.unit_items:
762 return self.unit_defs[0].toHTML() + '*' + self.unit_defs[1].unit_items[0].toHTML(-1.0)
763 else:
764 for unit in self.unit_items:
765 res+=unit.toHTML()+seperator
766 return res[:-1]
767
770
772 '''
773 return a string representation of the unit
774 '''
775 res=''
776 seperator=' * '
777 if self.unit_defs:
778 return self.unit_defs[0].toStr()+' * '+self.unit_defs[1].unit_items[0].toStr(-1.0)
779 else:
780 for unit in self.unit_items:
781 res +='%s%s'%(unit.toStr(),seperator)
782 return res[:-3]
783
784
786 - def __init__(self,kind,scale=0.0,multiplier=1.0,exponent=1.0):
787 known_units=xmlobject.XMLFile(path=libSBAnnotation.config.Config().getpath('resources','libsbml_resources')).root.knownUnits[0].kinds.split()
788 if kind in known_units:
789 self.kind=kind
790 else:
791 raise MergeError('Unknown unit kind \'%s\' '%kind)
792 self.scale=float(scale)
793 self.multiplier=float(multiplier)
794 self.exponent=exponent
795 - def toStr(self,exponent_mulitiplier=1.0):
796 return 'Kind: %s | Scale: %s | Mulitiplier: %s | Exponent %s'%(self.kind,self.scale,self.multiplier,self.exponent*exponent_mulitiplier)
797 - def toHTML(self,exponent_mulitiplier=1.0):
798 res=''
799 if self.multiplier!=1.0:
800 res+='%s*'%self.multiplier
801 res+=self.kind
802 if self.scale!=0.0:
803 res+='*10<sup>%s</sup>'%self.scale
804 if self.exponent!=1.0 or exponent_mulitiplier!=1:
805 res='(%s)<sup>%s</sup>'%(res,self.exponent*exponent_mulitiplier)
806 return res
807