def test_parse_identifiers_url(): # Get correct namespace and ID from standard and outdated URL formats for ns_tuple, urls in ns_mapping.items(): for url in urls: ns, db_id = parse_identifiers_url(url) assert (ns, db_id) == ns_tuple, (url, ns, db_id)
def pysb_to_gromet(pysb_model, model_name, statements=None, fname=None): """Convert PySB model to GroMEt object and save it to a JSON file. Parameters ---------- pysb_model : pysb.Model PySB model object. model_name : str A name of EMMAA model. statements : Optional[list[indra.statements.Statement]] A list of INDRA Statements a PySB model was assembled from. If provided the statement hashes will be propagated into GroMEt metadata. fname : Optional[str] If given, the GroMEt will be dumped into JSON file. Returns ------- g : automates.script.gromet.gromet.Gromet A GroMEt object built from PySB model. """ from gromet import Gromet, gromet_to_json, \ Junction, Wire, UidJunction, UidType, UidWire, Relation, \ UidBox, UidGromet, Literal, Val from gromet_metadata import IndraAgent, IndraAgentReferenceSet, \ ReactionReference, UidMetadatum, MetadatumMethod, Provenance, \ get_current_datetime, ModelInterface from pysb import Parameter, WILD from pysb.bng import generate_equations logger.info('Generating equations ...') generate_equations(pysb_model) logger.info('Creating GroMEt') junctions = [] wires = [] # Get all species values species_values = {} for initial in pysb_model.initials: ix = pysb_model.get_species_index(initial.pattern) if initial.value: species_values[ix] = Literal(uid=None, type=UidType("Integer"), value=Val(initial.value.value), name=None, metadata=None) # Get groundings for monomers groundings_by_monomer = {} # Build up db_refs for each monomer object for ann in pysb_model.annotations: if ann.predicate == 'is': m = ann.subject db_name, db_id = parse_identifiers_url(ann.object) if m in groundings_by_monomer: groundings_by_monomer[m][db_name] = db_id else: groundings_by_monomer[m] = {db_name: db_id} # Store species names to refer later species_nodes = [str(sp) for sp in pysb_model.species] # Add all species junctions for ix, sp in enumerate(pysb_model.species): # Map to a list of agents agents = [] for mp in sp.monomer_patterns: mods = [] if hasattr(mp.monomer, 'site_annotations'): for site, state in mp.site_conditions.items(): if isinstance(state, tuple) and state[1] == WILD: state = state[0] mod, mod_type, res, pos = None, None, None, None for ann in mp.monomer.site_annotations: if ann.subject == (site, state): mod_type = ann.object elif ann.subject == site and \ ann.predicate == 'is_residue': res = ann.object if ann.subject == site and \ ann.predicate == 'is_position': pos = ann.object if mod_type: not_mod, mod = states[mod_type] if state == mod: is_mod = True elif state == not_mod: is_mod = False else: logger.warning('Unknown state %s for %s, ' 'setting as not modified' % (state, mod_type)) is_mod = False mod = ModCondition(mod_type, res, pos, is_mod) if mod: mods.append(mod) if not mods: mods = None ag = Agent(mp.monomer.name, mods=mods, db_refs=groundings_by_monomer.get(mp.monomer)) agents.append(ag) agent_metadata = IndraAgentReferenceSet( uid=UidMetadatum(f'{species_nodes[ix]}_metadata'), provenance=Provenance(method=MetadatumMethod('from_emmaa_model'), timestamp=get_current_datetime()), indra_agent_references=[IndraAgent(ag.to_json()) for ag in agents]) junctions.append( Junction(uid=UidJunction(f'J:{species_nodes[ix]}'), type=UidType('State'), name=species_nodes[ix], value=species_values.get(ix), value_type=UidType('Integer'), metadata=[agent_metadata])) # Add wires for each reaction rate_counts = defaultdict(int) for rxn in pysb_model.reactions: rate_params = [ rate_term for rate_term in rxn['rate'].args if isinstance(rate_term, Parameter) ] assert len(rate_params) == 1 rate = rate_params[0].name rate_counts[rate] += 1 rate_node = f'{rate}:{rate_counts[rate]}' # Get metadata for rate node assert len(rxn['rule']) == 1 assert len(rxn['reverse']) == 1 rule = rxn['rule'][0] reverse = rxn['reverse'][0] if statements: stmt = stmt_from_rule(rule, pysb_model, statements) # Add rate junction for a reaction (uid and name are the same for now) reaction_metadata = ReactionReference( uid=UidMetadatum(f'{rate_node}_metadata'), provenance=Provenance(method=MetadatumMethod('from_emmaa_model'), timestamp=get_current_datetime()), indra_stmt_hash=stmt.get_hash(), reaction_rule=rule, is_reverse=reverse) wire_count = defaultdict(int) junctions.append( Junction(uid=UidJunction(f'J:{rate_node}'), type=UidType('Rate'), name=rate, value=Literal(uid=None, type=UidType("Float"), value=Val(rate_params[0].value), name=None, metadata=None), value_type=UidType('Float'), metadata=[reaction_metadata])) # Add wires from reactant to rate for reactant_ix in rxn['reactants']: reactant = species_nodes[reactant_ix] wire = f'{reactant}_{rate_node}' wire_count[wire] += 1 wires.append( Wire(uid=UidWire(f'W:{wire}:w{wire_count[wire]}'), type=None, value_type=None, name=None, value=None, metadata=None, src=UidJunction(f'J:{reactant}'), tgt=UidJunction(f'J:{rate_node}'))) # Add wires from rate to product for prod_ix in rxn['products']: prod = species_nodes[prod_ix] wire = f'{rate_node}_{prod}' wire_count[wire] += 1 wires.append( Wire(uid=UidWire(f'W:{wire}:w{wire_count[wire]}'), type=None, value_type=None, name=None, value=None, metadata=None, src=UidJunction(f'J:{rate_node}'), tgt=UidJunction(f'J:{prod}'))) # Create relation pnc = Relation( uid=UidBox(model_name), type=UidType("PetriNetClassic"), name=model_name, ports=None, # contents junctions=[j.uid for j in junctions], wires=[w.uid for w in wires], boxes=None, metadata=None) boxes = [pnc] # Create model interface metadata model_interface = \ ModelInterface( uid=UidMetadatum(f'{model_name}_model_interface'), provenance=Provenance(method=MetadatumMethod('from_emmaa_model'), timestamp=get_current_datetime()), variables=[j.uid for j in junctions], parameters=[j.uid for j in junctions if j.type == 'Rate'], initial_conditions=[j.uid for j in junctions if j.type == 'State']) # Create Gromet object g = Gromet(uid=UidGromet(f'{model_name}_pnc'), name=model_name, type=UidType("PetriNetClassic"), root=pnc.uid, types=None, literals=None, junctions=junctions, ports=None, wires=wires, boxes=boxes, variables=None, metadata=[model_interface]) logger.info('Created GroMEt') # Optionally save Gromet to JSON file if fname: gromet_to_json(g, fname) return g