def rules_using_parameter(model, parameter): """Return a ComponentSet of rules in the model which make use of the given parameter""" cset = ComponentSet() for rule in model.rules: if rule.rate_forward is parameter or rule.rate_reverse is parameter: cset.add(rule) return cset
def rules_using_parameter(model, parameter): """Return a ComponentSet of rules in the model which make use of the given parameter""" if not isinstance(parameter, pysb.core.Parameter): # Try getting the parameter by name parameter = model.parameters.get(parameter) cset = ComponentSet() for rule in model.rules: if rule.rate_forward is parameter or rule.rate_reverse is parameter: cset.add(rule) return cset
def merge_parameters(model, new_name, parameters): unique_values = {parameter.value for parameter in parameters} if len(unique_values) > 1: raise ValueError("Given parameters have different values: %s" % (', '.join('%s=%g' % (p.name, p.value) for p in parameters))) value = parameters[0].value rules = ComponentSet() for parameter in parameters: rules |= rules_using_parameter(model, parameter) if not rules: raise ValueError("Model has no rules using given parameters: %s" % ', '.join(p.name for p in parameters)) try: new_parameter = model.parameters[new_name] if new_parameter.value != value: raise ValueError("Parameter %s is already present in the model " "with the value %g, which differs from the " "common value of the given parameters, %g" % (new_parameter.name, new_parameter.value, value)) except KeyError: new_parameter = Parameter(new_name, value) model.add_component(new_parameter) for rule in rules: for attr in 'rate_forward', 'rate_reverse': if getattr(rule, attr) in parameters: setattr(rule, attr, new_parameter)
def pore_bind(subunit, sp_site1, sp_site2, sc_site, size, cargo, c_site, klist): """Generate rules to bind a monomer to a circular homomeric pore. The pore structure is defined by the `pore_species` macro -- `subunit` monomers bind to each other from `sp_site1` to `sp_site2` to form a closed ring. The binding reaction takes the form pore + cargo <> pore:cargo. Parameters ---------- subunit : Monomer or MonomerPattern Subunit of which the pore is composed. sp_site1, sp_site2 : string Names of the sites where one copy of `subunit` binds to the next. sc_site : string Name of the site on `subunit` where it binds to the cargo `cargo`. size : integer Number of subunits in the pore at which binding will occur. cargo : Monomer or MonomerPattern Cargo that binds to the pore complex. c_site : string Name of the site on `cargo` where it binds to `subunit`. klist : list of Parameters or numbers List containing forward and reverse rate constants for the binding reaction (in that order). Rate constants should either be both Parameter objects or both numbers. If Parameters are passed, they will be used directly in the generated Rules. If numbers are passed, Parameters will be created with automatically generated names based on <TODO> and these parameters will be included at the end of the returned component list. """ macros._verify_sites(subunit, sc_site) macros._verify_sites(cargo, c_site) def pore_bind_rule_name(rule_expression, size): # Get ReactionPatterns react_p = rule_expression.reactant_pattern prod_p = rule_expression.product_pattern # Build the label components # Pore is always first complex of LHS due to how we build the rules subunit = react_p.complex_patterns[0].monomer_patterns[0].monomer if len(react_p.complex_patterns) == 2: # This is the complexation reaction cargo = react_p.complex_patterns[1].monomer_patterns[0] else: # This is the dissociation reaction cargo = prod_p.complex_patterns[1].monomer_patterns[0] return '%s_%d_%s' % (subunit.name, size, macros._monomer_pattern_label(cargo)) components = ComponentSet() # Set up some aliases that are invariant with pore size subunit_free = subunit({sc_site: None}) cargo_free = cargo({c_site: None}) #for size, klist in zip(range(min_size, max_size + 1), ktable): # More aliases which do depend on pore size pore_free = macros.pore_species(subunit_free, sp_site1, sp_site2, size) # This one is a bit tricky. The pore:cargo complex must only introduce # one additional bond even though there are multiple subunits in the # pore. We create partial patterns for bound pore and cargo, using a # bond number that is high enough not to conflict with the bonds within # the pore ring itself. # Start by copying pore_free, which has all cargo binding sites empty pore_bound = pore_free.copy() # Get the next bond number not yet used in the pore structure itself cargo_bond_num = size + 1 # Assign that bond to the first subunit in the pore pore_bound.monomer_patterns[0].site_conditions[sc_site] = cargo_bond_num # Create a cargo source pattern with that same bond cargo_bound = cargo({c_site: cargo_bond_num}) # Finally we can define the complex trivially; the bond numbers are # already present in the patterns pc_complex = pore_bound % cargo_bound # Create the rules name_func = functools.partial(pore_bind_rule_name, size=size) components |= macros._macro_rule('pore_bind', pore_free + cargo_free | pc_complex, klist[0:2], ['kf', 'kr'], name_func=name_func) return components
def get_im(self, force_update=False): """Get the influence map for the model, generating it if necessary. Parameters ---------- force_update : bool Whether to generate the influence map when the function is called. If False, returns the previously generated influence map if available. Defaults to True. Returns ------- pygraphviz AGraph object containing the influence map. The influence map can be rendered as a pdf using the dot layout program as follows:: influence_map.draw('influence_map.pdf', prog='dot') """ if self._im and not force_update: return self._im if not self.model: raise Exception("Cannot get influence map if there is no model.") def add_obs_for_agent(agent): obj_mps = list(pa.grounded_monomer_patterns(self.model, agent)) if not obj_mps: logger.debug( 'No monomer patterns found in model for agent %s, ' 'skipping' % agent) return obs_list = [] for obj_mp in obj_mps: obs_name = _monomer_pattern_label(obj_mp) + '_obs' # Add the observable obj_obs = Observable(obs_name, obj_mp, _export=False) obs_list.append(obs_name) try: self.model.add_component(obj_obs) except ComponentDuplicateNameError as e: pass return obs_list # Create observables for all statements to check, and add to model # Remove any existing observables in the model self.model.observables = ComponentSet([]) for stmt in self.statements: # Generate observables for Modification statements if isinstance(stmt, Modification): mod_condition_name = modclass_to_modtype[stmt.__class__] if isinstance(stmt, RemoveModification): mod_condition_name = modtype_to_inverse[mod_condition_name] # Add modification to substrate agent modified_sub = _add_modification_to_agent( stmt.sub, mod_condition_name, stmt.residue, stmt.position) obs_list = add_obs_for_agent(modified_sub) # Associate this statement with this observable self.stmt_to_obs[stmt] = obs_list # Generate observables for Activation/Inhibition statements elif isinstance(stmt, RegulateActivity): regulated_obj, polarity = \ _add_activity_to_agent(stmt.obj, stmt.obj_activity, stmt.is_activation) obs_list = add_obs_for_agent(regulated_obj) # Associate this statement with this observable self.stmt_to_obs[stmt] = obs_list elif isinstance(stmt, RegulateAmount): obs_list = add_obs_for_agent(stmt.obj) self.stmt_to_obs[stmt] = obs_list # Add observables for each agent for ag in self.agent_obs: obs_list = add_obs_for_agent(ag) self.agent_to_obs[ag] = obs_list logger.info("Generating influence map") self._im = kappa.influence_map(self.model) #self._im.is_multigraph = lambda: False # Now, for every rule in the model, check if there are any observables # downstream # Alternatively, for every observable in the model, get a list of rules # We'll need the dictionary to check if nodes are observables node_attributes = nx.get_node_attributes(self._im, 'shape') for rule in self.model.rules: obs_list = [] # Get successors of the rule node for neighb in self._im.neighbors(rule.name): # Check if the node is an observable if node_attributes[neighb] != 'ellipse': continue # Get the edge and check the polarity edge_sign = _get_edge_sign(self._im, (rule.name, neighb)) obs_list.append((neighb, edge_sign)) self.rule_obs_dict[rule.name] = obs_list return self._im
def _find_im_paths(self, subj_mp, obj_obs, target_polarity): """Check for a source/target path in the influence map. Parameters ---------- subj_mp : pysb.MonomerPattern MonomerPattern corresponding to the subject of the Statement being checked. obj_obs : pysb.Observable Observable corresponding to the object/target of the Statement being checked. target_polarity : 1 or -1 Whether the influence in the Statement is positive (1) or negative (-1). Returns ------- boolean Whether there is a path from a rule matching the subject MonomerPattern to the object Observable with the appropriate polarity. """ # Reset the observables list self.model.observables = ComponentSet([]) self.model.add_component(obj_obs) # Find rules in the model corresponding to the input logger.info('Finding paths between %s and %s with polarity %s' % (subj_mp, obj_obs, target_polarity)) if subj_mp is None: input_rule_set = None else: input_rules = _match_lhs(subj_mp, self.model.rules) logger.info('Found %s input rules matching %s' % (len(input_rules), str(subj_mp))) # Filter to include only rules where the subj_mp is actually the # subject (i.e., don't pick up upstream rules where the subject # is itself a substrate/object) # FIXME: Note that this will eliminate rules where the subject # being checked is included on the left hand side as # a bound condition rather than as an enzyme. subj_rules = pa.rules_with_annotation(self.model, subj_mp.monomer.name, 'rule_has_subject') logger.info('%d rules with %s as subject' % (len(subj_rules), subj_mp.monomer.name)) input_rule_set = set([r.name for r in input_rules]).intersection( set([r.name for r in subj_rules])) logger.info('Final input rule set contains %d rules' % len(input_rule_set)) # If we have enzyme information but there are no input rules # matching the enzyme, then there is no path if not input_rule_set: return False # Generate the predecessors to our observable and count the paths # TODO: Make it optionally possible to return on the first path? num_paths = 0 for path in _find_sources(self.get_im(), obj_obs.name, input_rule_set, target_polarity): num_paths += 1 #for path in _find_sources_with_paths(self.get_im(), obj_obs.name, # input_rule_set, target_polarity): # num_paths += 1 if num_paths > 0: return True else: return False
def get_im(self, force_update=False): """Get the influence map for the model, generating it if necessary. Parameters ---------- force_update : bool Whether to generate the influence map when the function is called. If False, returns the previously generated influence map if available. Defaults to True. Returns ------- networkx MultiDiGraph object containing the influence map. The influence map can be rendered as a pdf using the dot layout program as follows:: im_agraph = nx.nx_agraph.to_agraph(influence_map) im_agraph.draw('influence_map.pdf', prog='dot') """ if self._im and not force_update: return self._im if not self.model: raise Exception("Cannot get influence map if there is no model.") def add_obs_for_agents(main_agent, ref_agents=None): if ref_agents: all_agents = [main_agent] + ref_agents else: all_agents = [main_agent] ag_to_obj_mps = self.get_all_mps(all_agents, mapping=True) if all([not v for v in ag_to_obj_mps.values()]): logger.debug('No monomer patterns found in model for agents %s' ', skipping' % all_agents) return obs_nodes = NodesContainer(main_agent, ref_agents) main_obs_set = set() ref_obs_set = set() for agent in ag_to_obj_mps: for obj_mp in ag_to_obj_mps[agent]: obs_name = _monomer_pattern_label(obj_mp) + '_obs' self.obs_to_agents[obs_name] = agent # Add the observable obj_obs = Observable(obs_name, obj_mp, _export=False) if agent.matches(main_agent): main_obs_set.add(obs_name) else: ref_obs_set.add(obs_name) try: self.model.add_component(obj_obs) self.model.add_annotation( Annotation(obs_name, agent.name, 'from_indra_agent')) except ComponentDuplicateNameError as e: pass obs_nodes.main_interm = main_obs_set obs_nodes.ref_interm = ref_obs_set return obs_nodes # Create observables for all statements to check, and add to model # Remove any existing observables in the model self.model.observables = ComponentSet([]) for stmt in self.statements: # Generate observables for Modification statements if isinstance(stmt, Modification) or \ isinstance(stmt, SelfModification): # If the statement is a regular Mod, the target is stmt.sub if isinstance(stmt, Modification): sub = stmt.sub # If it's a SelfMod, the target is stmt.enz elif isinstance(stmt, SelfModification): sub = stmt.enz # Add the mod for the agent if sub is None: self.stmt_to_obs[stmt] = NodesContainer(None) else: mod_condition_name = modclass_to_modtype[stmt.__class__] if isinstance(stmt, RemoveModification): mod_condition_name = modtype_to_inverse[ mod_condition_name] # Add modification to substrate agent modified_sub = _add_modification_to_agent( sub, mod_condition_name, stmt.residue, stmt.position) # Get all refinements of substrate agent ref_subs = self.get_refinements(modified_sub) obs_nodes = add_obs_for_agents(modified_sub, ref_subs) # Associate this statement with this observable self.stmt_to_obs[stmt] = obs_nodes # Generate observables for Activation/Inhibition statements elif isinstance(stmt, RegulateActivity): if stmt.obj is None: self.stmt_to_obs[stmt] = NodesContainer(None) else: # Add activity to object agent regulated_obj = _add_activity_to_agent( stmt.obj, stmt.obj_activity, stmt.is_activation) # Get all refinements of object agent ref_objs = self.get_refinements(stmt.obj) obs_nodes = add_obs_for_agents(regulated_obj, ref_objs) # Associate this statement with this observable self.stmt_to_obs[stmt] = obs_nodes elif isinstance(stmt, RegulateAmount): if stmt.obj is None: self.stmt_to_obs[stmt] = NodesContainer(None) else: # Get all refinements of object agent ref_objs = self.get_refinements(stmt.obj) obs_nodes = add_obs_for_agents(stmt.obj, ref_objs) self.stmt_to_obs[stmt] = obs_nodes elif isinstance(stmt, Influence): if stmt.obj is None: self.stmt_to_obs[stmt] = NodesContainer(None) else: # Get all refinements of object agent ref_objs = self.get_refinements(stmt.obj) concepts = [obj.concept for obj in ref_objs] obs_nodes = add_obs_for_agents(stmt.obj.concept, concepts) self.stmt_to_obs[stmt] = obs_nodes # Add observables for each agent for ag in self.agent_obs: obs_nodes = add_obs_for_agents(ag) self.agent_to_obs[ag] = obs_nodes logger.info("Generating influence map") self._im = self.generate_im(self.model) # self._im.is_multigraph = lambda: False # Now, for every rule in the model, check if there are any observables # downstream; alternatively, for every observable in the model, get a # list of rules. # We'll need the dictionary to check if nodes are observables node_attributes = nx.get_node_attributes(self._im, 'node_type') for rule in self.model.rules: obs_list = [] # Get successors of the rule node for neighb in self._im.neighbors(rule.name): # Check if the node is an observable if node_attributes[neighb] != 'variable': continue # Get the edge and check the polarity edge_sign = _get_edge_sign(self._im, (rule.name, neighb)) obs_list.append((neighb, edge_sign)) self.rule_obs_dict[rule.name] = obs_list return self._im