Source code for bionetgen.modelapi.model

import copy

from bionetgen.main import BioNetGen
from bionetgen.core.exc import BNGModelError
from tempfile import TemporaryFile
from .bngparser import BNGParser
from .blocks import (
    ActionBlock,
    CompartmentBlock,
    FunctionBlock,
    MoleculeTypeBlock,
    ObservableBlock,
    ParameterBlock,
    RuleBlock,
    SpeciesBlock,
    EnergyPatternBlock,
    PopulationMapBlock,
)


# This allows access to the CLIs config setup
app = BioNetGen()
app.setup()
conf = app.config["bionetgen"]
def_bng_path = conf["bngpath"]

###### CORE OBJECT AND PARSING FRONT-END ######
[docs]class bngmodel: """ Main model object and entry point for model API. The goal of this object is to generate and read the BNGXML of a given BNGL model and give the user a pythonic interface to the resulting model object. Usage: bngmodel(bng_model) bngmodel(bng_model, BNGPATH) Attributes ---------- active_blocks : list[str] a list of the blocks that have been parsed in the model bngparser : BNGParser BNGParser object that's responsible for .bngl file reading and model setup model_name : str name of the model, generally set from the given BNGL file recompile : bool a tag to keep track if any changes have been made to the model via the XML API by the user changes : dict a list of changes the user have made to the model Methods ------- reset_compilation_tags() resets compilation tags of each block to keep track of any changes the user makes to the model via the API add_action(action_type, action_args) adds the action of action_type with arguments given by the optional keyword argument action_args, which is a dictionary where each element is of the form "ArgumentName":ArgumentValue write_model(model_name) write the model in BNGL format to the path given setup_simulator(sim_type) sets up a simulator in bngmodel.simulator where the only current supported type of simulator is libRR for libRoadRunner simulator. """ def __init__(self, bngl_model, BNGPATH=def_bng_path, generate_network=False): self.active_blocks = [] # We want blocks to be printed in the same order every time self.block_order = [ "parameters", "compartments", "molecule_types", "species", "observables", "functions", "energy_patterns", "population_maps", "rules", "actions", ] self.model_name = "" self.model_path = bngl_model self.bngparser = BNGParser(bngl_model, generate_network=generate_network) self.bngparser.parse_model(self) for block in self.block_order: if block not in self.active_blocks: self.add_empty_block(block) # Check to see if there are no active blocks # If not, model is most likely not in BNGL format if not self.active_blocks: print( "WARNING: No active blocks. Please ensure model is in proper BNGL or BNG-XML format" ) @property def recompile(self): recompile = False for block in self.active_blocks: recompile = recompile or getattr(self, block)._recompile return recompile @property def changes(self): changes = {} for block in self.active_blocks: changes[block] = getattr(self, block)._changes return changes def __str__(self): """ write the model to str """ model_str = "" # gotta check for "before model" type actions if hasattr(self, "actions"): ablock = getattr(self, "actions") if len(ablock.before_model) > 0: for baction in ablock.before_model: model_str += str(baction) + "\n" model_str += "begin model\n" for block in self.block_order: # ensure we didn't get new items into a # previously inactive block, if we did # add them to the active blocks if hasattr(self, block): if len(getattr(self, block)) > 0: if getattr(self, block).name not in self.active_blocks: self.active_blocks.append(block) # if we removed items from a block and # it's now empty, we want to remove it # from the active blocks elif len(getattr(self, block)) == 0 and block in self.active_blocks: self.active_blocks.remove(block) # print only the active blocks if block in self.active_blocks: if block != "actions" and len(getattr(self, block)) > 0: model_str += str(getattr(self, block)) model_str += "\nend model\n\n" if "actions" in self.active_blocks: model_str += str(self.actions) return model_str def __repr__(self): return self.model_name def __iter__(self): active_ordered_blocks = [ getattr(self, i) for i in self.block_order if i in self.active_blocks ] return active_ordered_blocks.__iter__()
[docs] def add_block(self, block): bname = block.name.replace(" ", "_") # TODO: fix this exception if bname == "reaction_rules": bname = "rules" block_adder = getattr(self, "add_{}_block".format(bname)) block_adder(block)
[docs] def add_empty_block(self, block_name): bname = block_name.replace(" ", "_") # TODO: fix this exception if bname == "reaction_rules": bname = "rules" block_adder = getattr(self, "add_{}_block".format(bname)) block_adder()
[docs] def add_parameters_block(self, block=None): if block is not None: # TODO: Transition to BNGErrors and logging assert isinstance(block, ParameterBlock) self.parameters = block if "parameters" not in self.active_blocks: self.active_blocks.append("parameters") else: self.parameters = ParameterBlock()
[docs] def add_compartments_block(self, block=None): if block is not None: # TODO: Transition to BNGErrors and logging assert isinstance(block, CompartmentBlock) self.compartments = block if "compartments" not in self.active_blocks: self.active_blocks.append("compartments") else: self.compartments = CompartmentBlock()
[docs] def add_molecule_types_block(self, block=None): if block is not None: # TODO: Transition to BNGErrors and logging assert isinstance(block, MoleculeTypeBlock) self.molecule_types = block if "molecule_types" not in self.active_blocks: self.active_blocks.append("molecule_types") else: self.molecule_types = MoleculeTypeBlock()
[docs] def add_species_block(self, block=None): if block is not None: # TODO: Transition to BNGErrors and logging assert isinstance(block, SpeciesBlock) self.species = block if "species" not in self.active_blocks: self.active_blocks.append("species") else: self.species = SpeciesBlock()
[docs] def add_observables_block(self, block=None): if block is not None: # TODO: Transition to BNGErrors and logging assert isinstance(block, ObservableBlock) self.observables = block if "observables" not in self.active_blocks: self.active_blocks.append("observables") else: self.observables = ObservableBlock()
[docs] def add_functions_block(self, block=None): if block is not None: # TODO: Transition to BNGErrors and logging assert isinstance(block, FunctionBlock) self.functions = block if "functions" not in self.active_blocks: self.active_blocks.append("functions") else: self.functions = FunctionBlock()
[docs] def add_rules_block(self, block=None): if block is not None: # TODO: Transition to BNGErrors and logging assert isinstance(block, RuleBlock) self.rules = block if "rules" not in self.active_blocks: self.active_blocks.append("rules") else: self.rules = RuleBlock()
[docs] def add_energy_patterns_block(self, block=None): if block is not None: # TODO: Transition to BNGErrors and logging assert isinstance(block, EnergyPatternBlock) self.energy_patterns = block if "energy_patterns" not in self.active_blocks: self.active_blocks.append("energy_patterns") else: self.energy_patterns = EnergyPatternBlock()
[docs] def add_population_maps_block(self, block=None): if block is not None: # TODO: Transition to BNGErrors and logging assert isinstance(block, PopulationMapBlock) self.population_maps = block if "population_maps" not in self.active_blocks: self.active_blocks.append("population_maps") else: self.population_maps = PopulationMapBlock()
[docs] def add_actions_block(self, block=None): if block is not None: # TODO: Transition to BNGErrors and logging assert isinstance(block, ActionBlock) self.actions = block if "actions" not in self.active_blocks: self.active_blocks.append("actions") else: self.actions = ActionBlock()
[docs] def reset_compilation_tags(self): for block in self.active_blocks: getattr(self, block).reset_compilation_tags()
[docs] def add_action(self, action_type, action_args=[]): # add actions block and to active list if not hasattr(self, "actions"): self.actions = ActionBlock() if "actions" not in self.active_blocks: self.active_blocks.append("actions") self.actions.add_action(action_type, action_args)
[docs] def write_model(self, file_name): """ write the model to file """ with open(file_name, "w") as f: f.write(str(self))
[docs] def setup_simulator(self, sim_type="libRR"): """ Sets up a simulator attribute that is a generic front-end to all other simulators. At the moment only libroadrunner is supported """ if sim_type == "libRR": # we need to add writeSBML action for now curr_actions = copy.deepcopy(self.actions) self.actions.clear_actions() self.add_action("generate_network", {"overwrite": 1}) self.add_action("writeSBML", {}) # temporary file with TemporaryFile(mode="w+") as tpath: # write the sbml if not ( self.bngparser.bngfile.write_xml( tpath, xml_type="sbml", bngl_str=str(self) ) ): raise BNGModelError( self.model_path, message="SBML couldn't be generated for libRR simulator", ) # TODO: Only clear the writeSBML action # by adding a mechanism to do so self.actions.clear_actions() # get the simulator import bionetgen as bng self.simulator = bng.sim_getter( model_str=tpath.read(), sim_type=sim_type ) # let's deal with observables here selections = ["time"] + [obs for obs in self.observables] self.simulator.simulator.timeCourseSelections = selections self.actions = curr_actions elif sim_type == "cpy": # get the simulator import bionetgen as bng self.simulator = bng.sim_getter(model_file=self, sim_type=sim_type) return self.simulator else: print( 'Sim type {} is not recognized, only libroadrunner \ is supported currently by passing "libRR" to \ sim_type keyword argument'.format( sim_type ) ) return None # for now we return the underlying simulator return self.simulator.simulator
###### CORE OBJECT AND PARSING FRONT-END ######