Source code for ecoli.processes.tf_unbinding

"""
TfUnbinding
Unbind transcription factors from DNA to allow signaling processes before
binding back to DNA.
"""

import numpy as np
import warnings

from vivarium.core.process import Step

from ecoli.processes.registries import topology_registry
from ecoli.library.schema import bulk_name_to_idx, attrs, numpy_schema

# Register default topology for this process, associating it with process name
NAME = "ecoli-tf-unbinding"
TOPOLOGY = {
    "bulk": ("bulk",),
    "promoters": (
        "unique",
        "promoter",
    ),
    "global_time": ("global_time",),
    "timestep": ("timestep",),
    "next_update_time": ("next_update_time", "tf_unbinding"),
}
topology_registry.register(NAME, TOPOLOGY)


[docs] class TfUnbinding(Step): """TfUnbinding""" name = NAME topology = TOPOLOGY defaults = {"time_step": 1, "emit_unique": False} # Constructor def __init__(self, parameters=None): super().__init__(parameters) self.tf_ids = self.parameters["tf_ids"] self.submass_indices = self.parameters["submass_indices"] self.active_tf_masses = self.parameters["active_tf_masses"] # Numpy indices for bulk molecules self.active_tf_idx = None
[docs] def ports_schema(self): return { "bulk": numpy_schema("bulk"), "promoters": numpy_schema("promoters", emit=self.parameters["emit_unique"]), "global_time": {"_default": 0.0}, "timestep": {"_default": self.parameters["time_step"]}, "next_update_time": { "_default": self.parameters["time_step"], "_updater": "set", "_divider": "set", }, }
[docs] def update_condition(self, timestep, states): """ See :py:meth:`~.Requester.update_condition`. """ if states["next_update_time"] <= states["global_time"]: if states["next_update_time"] < states["global_time"]: warnings.warn( f"{self.name} updated at t=" f"{states['global_time']} instead of t=" f"{states['next_update_time']}. Decrease the " "timestep for the global clock process for more " "accurate timekeeping." ) return True return False
[docs] def next_update(self, timestep, states): # At t=0, convert all strings to indices if self.active_tf_idx is None: self.active_tf_idx = bulk_name_to_idx( [tf + "[c]" for tf in self.tf_ids], states["bulk"]["id"] ) # Get attributes of all promoters (bound_TF,) = attrs(states["promoters"], ["bound_TF"]) # If there are no promoters, return immediately if len(bound_TF) == 0: return {} # Calculate number of bound TFs for each TF prior to changes n_bound_TF = bound_TF.sum(axis=0) update = { # Free all DNA-bound TFs into free active TFs "bulk": [(self.active_tf_idx, n_bound_TF)], "promoters": { # Reset bound_TF attribute of promoters "set": {"bound_TF": np.zeros_like(bound_TF)} }, } # Add mass_diffs array to promoter submass mass_diffs = bound_TF @ -self.active_tf_masses for submass, idx in self.submass_indices.items(): update["promoters"]["set"][submass] = ( attrs(states["promoters"], [submass])[0] + mass_diffs[:, idx] ) update["next_update_time"] = states["global_time"] + states["timestep"] return update