#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
import readdy
import math
import random
import copy
from ..common import ReaddyUtil
parameters = {}
[docs]def set_parameters(p):
global parameters
parameters = p
return p
[docs]class MicrotubulesUtil:
def __init__(self, parameters):
"""
Utility functions for ReaDDy microtubules models
Parameters need to be accessible in ReaDDy callbacks
which can't be instance methods, so parameters are global
"""
set_parameters(parameters)
[docs] @staticmethod
def get_random_tubulin_neighbors(
topology, types_include, types_exclude, GTP_state, polymer_offsets
):
"""
get a random pair of neighbor tubulins of the given types,
GTP state, and polymer offsets
"""
vertices = []
for v in topology.graph.get_vertices():
pt = topology.particle_type_of_vertex(v)
if ReaddyUtil.vertex_satisfies_type(
pt,
types_include[0] + (["GDP"] if GTP_state == "GDP" else []),
types_exclude[0],
):
vertices.append(v)
if GTP_state == "GDP":
types_include[1] += ["GDP"]
neighbors = []
for v in vertices:
n = MicrotubulesUtil.get_neighboring_tubulin(topology, v, polymer_offsets)
if n is not None:
extra_types = []
if (
GTP_state == "GTP"
and "GTP" not in topology.particle_type_of_vertex(v)
):
extra_types = ["GTP"]
nt = topology.particle_type_of_vertex(n)
if ReaddyUtil.vertex_satisfies_type(
nt, types_include[1] + extra_types, types_exclude[1]
):
neighbors.append([v, n])
if len(neighbors) == 0:
return None
return random.choice(neighbors)
[docs] @staticmethod
def get_neighboring_tubulin(topology, vertex, polymer_offsets):
"""
get the next tubulin neighbor in the branch from site named direction
"""
return ReaddyUtil.get_neighbor_of_type(
topology,
vertex,
MicrotubulesUtil.polymer_indices_to_string(
MicrotubulesUtil.increment_polymer_indices(
MicrotubulesUtil.get_polymer_indices(
topology.particle_type_of_vertex(vertex)
),
polymer_offsets,
)
),
False,
)
[docs] @staticmethod
def tubulin_has_sites(topology, tubulin):
"""
does the tubulin have sites attached?
"""
return (
ReaddyUtil.get_neighbor_of_type(topology, tubulin, "site#out", False)
is not None
)
[docs] @staticmethod
def get_tubulin_sites(topology, tubulin):
"""
get the site particles attached to this tubulin vertex
"""
if not MicrotubulesUtil.tubulin_has_sites(topology, tubulin):
return None
return [
ReaddyUtil.get_neighbor_of_type(topology, tubulin, "site#out", False),
ReaddyUtil.get_neighbor_of_type(topology, tubulin, "site#1", False),
ReaddyUtil.get_neighbor_of_type(topology, tubulin, "site#2", False),
ReaddyUtil.get_neighbor_of_type(topology, tubulin, "site#3", False),
ReaddyUtil.get_neighbor_of_type(topology, tubulin, "site#4", False),
]
[docs] @staticmethod
def polymer_indices_to_string(polymer_indices):
"""
get the x and y polymer index for a particle
"""
return f"_{polymer_indices[0]}_{polymer_indices[1]}"
[docs] @staticmethod
def increment_polymer_indices(polymer_indices, polymer_offsets):
"""
increment the x and y polymer index for a particle
"""
polymer_offsets = ReaddyUtil.clamp_polymer_offsets_2D(
polymer_indices[0], polymer_offsets
)
x = ReaddyUtil.calculate_polymer_number(polymer_indices[0], polymer_offsets[0])
y = ReaddyUtil.calculate_polymer_number(polymer_indices[1], polymer_offsets[1])
return [x, y]
[docs] @staticmethod
def get_polymer_indices(particle_type):
"""
get the x and y polymer index for a particle
"""
if "tubulin" not in particle_type:
return []
flag_string = particle_type[particle_type.index("#") + 1 :]
flags = flag_string.split("_")
if len(flags) <= 1:
return []
x = int(flags[-2])
y = int(flags[-1])
return [x, y]
[docs] @staticmethod
def get_polymer_offsets(particle_types):
"""
get the offsets between two particle's polymer indices
"""
polymer_indices = [
MicrotubulesUtil.get_polymer_indices(particle_types[0]),
MicrotubulesUtil.get_polymer_indices(particle_types[1]),
]
offsets = []
for i in range(2):
offset = int(polymer_indices[1][i] - polymer_indices[0][i])
if abs(offset) > 1:
offset = int(round(-offset / abs(offset)))
offsets.append(offset)
return offsets
[docs] @staticmethod
def get_filament_lengths(topology, tubulin_minus, tubulin_plus):
"""
get the lengths of the filaments, cut off the larger one
at one larger than the smaller
"""
next_tub_minus = MicrotubulesUtil.get_neighboring_tubulin(
topology, tubulin_minus, [-1, 0]
)
next_tub_plus = MicrotubulesUtil.get_neighboring_tubulin(
topology, tubulin_plus, [1, 0]
)
if next_tub_minus is None and next_tub_plus is None:
return np.array([1, 1])
elif next_tub_minus is None:
return np.array([1, 2])
elif next_tub_plus is None:
return np.array([2, 1])
else:
return MicrotubulesUtil.get_filament_lengths(
topology, next_tub_minus, next_tub_plus
) + np.array([1, 1])
[docs] @staticmethod
def filament_is_crosslinked(topology, tubulin, direction):
"""
does the fragment starting at the given tubulin
and going the given direction (-1 or 1) along a filament
have any crosslinks to other filaments?
"""
for i in range(2):
neighbor_tub = MicrotubulesUtil.get_neighboring_tubulin(
topology, tubulin, [0, -1 if i == 0 else 1]
)
if neighbor_tub is not None:
return True
next_tub = MicrotubulesUtil.get_neighboring_tubulin(
topology, tubulin, [direction, 0]
)
if next_tub is None:
return False
return MicrotubulesUtil.filament_is_crosslinked(topology, next_tub, direction)
[docs] @staticmethod
def remove_bent_filament_site_bonds(topology, recipe, tubulin_minus, tubulin_plus):
"""
remove bonds between the sites of tubulin1 and tubulin2
"""
v_sites_minus = MicrotubulesUtil.get_tubulin_sites(topology, tubulin_minus)
if v_sites_minus is None:
raise Exception(
"Failed to find sites on bent tubulin ("
+ ReaddyUtil.vertex_to_string(topology, tubulin_minus)
+ ")\n"
+ ReaddyUtil.topology_to_string(topology)
)
v_sites_plus = MicrotubulesUtil.get_tubulin_sites(topology, tubulin_plus)
if v_sites_plus is None:
raise Exception(
"Failed to find sites on bent tubulin ("
+ ReaddyUtil.vertex_to_string(topology, tubulin_plus)
+ ")\n"
+ ReaddyUtil.topology_to_string(topology)
)
for i in range(3):
if v_sites_plus[i] is None or v_sites_minus[i] is None:
continue
removed, message = ReaddyUtil.try_remove_edge(
topology, recipe, v_sites_plus[i], v_sites_minus[i]
)
if not removed:
raise Exception(
message + "\n" + ReaddyUtil.topology_to_string(topology)
)
if v_sites_plus[3] is not None and v_sites_minus[4] is not None:
removed, message = ReaddyUtil.try_remove_edge(
topology, recipe, v_sites_plus[3], v_sites_minus[4]
)
if not removed:
raise Exception(
message + "\n" + ReaddyUtil.topology_to_string(topology)
)
[docs] @staticmethod
def remove_tubulin_sites(topology, recipe, tubulin):
"""
emit a tubulin's site particles
"""
v_sites = MicrotubulesUtil.get_tubulin_sites(topology, tubulin)
if v_sites is None:
return False
for site in range(5):
if v_sites[site] is not None:
recipe.separate_vertex(v_sites[site])
recipe.change_particle_type(v_sites[site], "site#remove")
return True
[docs] @staticmethod
def set_free(topology, recipe, tubulins):
"""
emit each tubulin's site particles and change its type to tubulin#free
"""
for tubulin in tubulins:
if not MicrotubulesUtil.remove_tubulin_sites(topology, recipe, tubulin):
return False
tub_type = "A" if "A" in topology.particle_type_of_vertex(tubulin) else "B"
recipe.change_particle_type(tubulin, f"tubulin{tub_type}#free")
return True
[docs] @staticmethod
def topology_is_microtubule(topology):
"""
does the topology have tubulins with ring bonds?
if so it has multiple protofilaments and is not just an oligomer
"""
for vertex in topology.graph.get_vertices():
pt = topology.particle_type_of_vertex(vertex)
if "tubulin" in pt:
if (
MicrotubulesUtil.get_neighboring_tubulin(topology, vertex, [0, -1])
is not None
):
return True
if (
MicrotubulesUtil.get_neighboring_tubulin(topology, vertex, [0, 1])
is not None
):
return True
return False
[docs] @staticmethod
def get_attaching_sites(topology):
"""
get the ring sites that just attached in a spatial reaction
"""
sites1 = ReaddyUtil.get_vertices_of_type(topology, "site#1", True)
for site1 in sites1:
site2 = ReaddyUtil.get_neighbor_of_type(topology, site1, "site#2", True)
if site2 is not None:
return [site1, site2]
return []
[docs] @staticmethod
def cancel_attach(topology, recipe, sites):
"""
reverse an attach spatial reaction
"""
removed, message = ReaddyUtil.try_remove_edge(
topology, recipe, sites[0], sites[1]
)
if not removed:
raise Exception(message + "\n" + ReaddyUtil.topology_to_string(topology))
recipe.change_topology_type("Microtubule")
[docs] @staticmethod
def tubulins_can_attach(tubulin_types):
"""
check if tubulins can attach laterally
"""
offsets = MicrotubulesUtil.get_polymer_offsets(tubulin_types)
return offsets[0] == 0 and offsets[1] == -1
[docs] @staticmethod
def tubulin_is_crosslinked(topology, tubulin):
"""
is the tubulin connected to a neighbor on each ring side?
"""
return (
MicrotubulesUtil.get_neighboring_tubulin(topology, tubulin, [0, -1])
is not None
and MicrotubulesUtil.get_neighboring_tubulin(topology, tubulin, [0, 1])
is not None
)
[docs] @staticmethod
def check_remove_tubulin_sites(
topology,
recipe,
tubulin,
tubulin_crosslinked=False,
neighbor_tubulin=None,
neighbor_crosslinked=False,
):
"""
check if the tubulin's sites should be removed, if so remove them
"""
if not MicrotubulesUtil.tubulin_has_sites(topology, tubulin):
return False
crosslinked = []
neighbor_tubulins = [
MicrotubulesUtil.get_neighboring_tubulin(topology, tubulin, [-1, 0]),
MicrotubulesUtil.get_neighboring_tubulin(topology, tubulin, [1, 0]),
]
for nt in range(2):
if (
neighbor_tubulin is not None
and neighbor_tubulins[nt] is not None
and ReaddyUtil.vertices_are_equal(
topology, neighbor_tubulins[nt], neighbor_tubulin
)
):
crosslinked.append(neighbor_crosslinked)
else:
if neighbor_tubulins[nt] is not None:
crosslinked.append(
MicrotubulesUtil.tubulin_is_crosslinked(
topology, neighbor_tubulins[nt]
)
)
else:
crosslinked.append(nt == 0)
if False not in crosslinked and (
tubulin_crosslinked
or MicrotubulesUtil.tubulin_is_crosslinked(topology, tubulin)
):
MicrotubulesUtil.remove_tubulin_sites(topology, recipe, tubulin)
return True
return False
[docs] @staticmethod
def tubulin_is_not_crosslinked(topology, tubulin):
"""
is the tubulin missing at least one ring side connection?
"""
return (
MicrotubulesUtil.get_neighboring_tubulin(topology, tubulin, [0, -1]) is None
or MicrotubulesUtil.get_neighboring_tubulin(topology, tubulin, [0, 1])
is None
)
[docs] @staticmethod
def add_tubulin_sites(
topology, recipe, tubulin, site1_type="site#new", site2_type="site#new"
):
"""
add a new particle attached to the tubulin for each site
"""
pos_tub = ReaddyUtil.get_vertex_position(topology, tubulin)
for i in range(5):
recipe.append_particle(
[tubulin],
site1_type if i == 1 else site2_type if i == 2 else "site#new",
pos_tub + np.array([0, 0, 1.5]),
)
[docs] @staticmethod
def check_add_tubulin_sites(
topology, recipe, tubulin, site1_type="site#new", site2_type="site#new"
):
"""
check if the tubulin should have sites added, if so add them
"""
if MicrotubulesUtil.tubulin_has_sites(topology, tubulin):
if not (site1_type == "site#new" and site2_type == "site#new"):
sites = MicrotubulesUtil.get_tubulin_sites(topology, tubulin)
if site1_type != "site#new":
recipe.change_particle_type(sites[1], site1_type)
if site2_type != "site#new":
recipe.change_particle_type(sites[2], site2_type)
return False
MicrotubulesUtil.add_tubulin_sites(
topology, recipe, tubulin, site1_type, site2_type
)
return True
[docs] @staticmethod
def get_new_sites(topology, tubulin):
"""
get new site particles attached to a tubulin
"""
v_new_sites = ReaddyUtil.get_neighbors_of_type(
topology, tubulin, "site#", False
)
return v_new_sites if len(v_new_sites) >= 1 else None
[docs] @staticmethod
def setup_sites(
topology,
recipe,
v_new_sites,
position,
side,
normal,
tangent,
site_state_ring,
site_state_filament,
):
"""
set positions, types, and intra-tubulin edges for new site particles
"""
recipe.change_particle_type(v_new_sites[0], "site#out")
recipe.change_particle_position(v_new_sites[0], position + normal)
recipe.change_particle_type(v_new_sites[1], f"site#1{site_state_ring}")
recipe.change_particle_position(v_new_sites[1], position + side)
recipe.add_edge(v_new_sites[0], v_new_sites[1]) # edge to site#out
recipe.change_particle_type(v_new_sites[2], f"site#2{site_state_ring}")
recipe.change_particle_position(v_new_sites[2], position - side)
recipe.add_edge(v_new_sites[0], v_new_sites[2]) # edge to site#out
recipe.change_particle_type(v_new_sites[3], "site#3")
recipe.change_particle_position(v_new_sites[3], position - tangent)
recipe.add_edge(v_new_sites[0], v_new_sites[3]) # edge to site#out
recipe.add_edge(v_new_sites[1], v_new_sites[3]) # edge to site#1
recipe.add_edge(v_new_sites[2], v_new_sites[3]) # edge to site#2
recipe.change_particle_type(v_new_sites[4], f"site#4{site_state_filament}")
recipe.change_particle_position(v_new_sites[4], position + tangent)
recipe.add_edge(v_new_sites[0], v_new_sites[4]) # edge to site#out
recipe.add_edge(v_new_sites[1], v_new_sites[4]) # edge to site#1
recipe.add_edge(v_new_sites[2], v_new_sites[4]) # edge to site#2
[docs] @staticmethod
def connect_sites_between_tubulins(topology, recipe, v_sites_minus, v_sites_plus):
"""
add inter-tubulin edges between sites
"""
recipe.add_edge(v_sites_plus[0], v_sites_minus[0]) # + site0 -- - site0
recipe.add_edge(v_sites_plus[1], v_sites_minus[1]) # + site1 -- - site1
recipe.add_edge(v_sites_plus[2], v_sites_minus[2]) # + site2 -- - site2
recipe.add_edge(v_sites_plus[3], v_sites_minus[4]) # + site3 -- - site4
[docs] @staticmethod
def get_all_polymer_tubulin_types(particle_type):
"""
gets a list of all polymer numbers
("type1_1", "type1_2", "type1_3", "type2_1", ... "type3_3")
for type particle_type
returns list of types
"""
result = []
for x in range(1, 4):
for y in range(1, 4):
result.append(f"{particle_type}{x}_{y}")
return result
[docs] @staticmethod
def add_polymer_topology_species(particle_type, diffCoeff, system):
"""
adds topology species for all polymer numbers
("type1_1", "type1_2", "type1_3", "type2_1", ... "type3_3")
for type particle_type
with diffusion coefficient diffCoeff [nm^2/s]
"""
types = MicrotubulesUtil.get_all_polymer_tubulin_types(particle_type)
for t in types:
system.add_topology_species(t, diffCoeff)
[docs] @staticmethod
def get_microtubule_positions_and_types(
n_filaments,
n_rings,
n_frayed_rings_plus,
n_frayed_rings_minus,
frayed_angle,
radius,
use_GTP=True,
):
"""
get lists of positions and types for particles in a microtubule
with n_filaments protofilaments
and n_rings rings
and n_frayed_rings_plus rings at + end with outward bend
and n_frayed_rings_minus rings at - end with outward bend
and frayed_angle [radians] rotation of normal per bent tubulin
and radius [nm]
"""
frayed_y_pos = 0.0
for ring in range(n_frayed_rings_minus):
angle = (ring + 0.5) * frayed_angle
quad = math.floor(angle / (np.pi / 2))
acute_angle = angle % (np.pi / 2)
frayed_y_pos += (
(-1 if quad > 1 else 1)
* 4
* (np.sin(acute_angle) if quad % 2 == 0 else np.cos(acute_angle))
)
n_frayed_rings = n_frayed_rings_minus + n_frayed_rings_plus
positions = []
types = []
i = 0
for filament in range(n_filaments):
tube_angle = (
n_filaments - filament
) * 2.0 * np.pi / n_filaments + np.pi / 2.0
tube_normal = ReaddyUtil.normalize(
np.array([math.cos(tube_angle), math.sin(tube_angle), 0.0])
)
tube_tangent = np.array([0.0, 0.0, 1.0])
side = ReaddyUtil.normalize(np.cross(tube_normal, tube_tangent))
if n_frayed_rings > 0:
tangent = ReaddyUtil.rotate(
np.copy(tube_tangent),
side,
(n_frayed_rings_minus + 0.5) * frayed_angle,
)
normal = ReaddyUtil.rotate(
np.copy(tube_normal),
side,
(n_frayed_rings_minus + 0.5) * frayed_angle,
)
else:
tangent = tube_tangent
normal = tube_normal
pos = (radius + frayed_y_pos) * tube_normal + (
12.0 / 13.0 * filament - 2.0 * n_rings
) * tube_tangent
for ring in range(n_rings):
number1 = ring % 3 + 1
number2 = (filament + math.floor(ring / 3)) % 3 + 1
GTP_state = (
"GTP"
if random.random() <= (ring - n_rings / 3.0) / (n_rings / 3.0)
else "GDP"
)
positions.append(copy.copy(pos))
bent = (
ring < n_frayed_rings_minus
or ring > n_rings - 1 - n_frayed_rings_plus
)
edge = n_frayed_rings > 0 and (
ring == n_frayed_rings_minus
or ring == n_rings - 1 - n_frayed_rings_plus
)
tub_type = "A" if ring % 2 == 0 else "B"
bent_type = "bent_" if bent else ""
tub_GTP_state = GTP_state + "_" if use_GTP else ""
types.append(
f"tubulin{tub_type}#{tub_GTP_state}{bent_type}{number1}_{number2}"
)
i += 1
if bent or edge: # needs site scaffolds
types.append("site#out")
i += 1
positions.append(pos + 1.5 * normal)
site_state = f"_{GTP_state}" if not edge else ""
types.append(f"site#1{site_state}")
i += 1
positions.append(pos - 1.5 * side)
types.append(f"site#2{site_state}")
i += 1
positions.append(pos + 1.5 * side)
types.append("site#3")
i += 1
positions.append(pos - 1.5 * tangent)
site_state = f"_{GTP_state}" if ring == n_rings - 1 else ""
types.append(f"site#4{site_state}")
i += 1
positions.append(pos + 1.5 * tangent)
tangent = ReaddyUtil.rotate(
tangent, side, -frayed_angle * (0.5 if edge else 1.0)
)
normal = ReaddyUtil.rotate(
normal, side, -frayed_angle * (0.5 if edge else 1.0)
)
pos += 4.0 * tangent
return positions, types
[docs] @staticmethod
def add_edges(
microtubule, n_filaments, n_rings, n_frayed_rings_plus, n_frayed_rings_minus
):
"""
add edges to a microtubule topology
with n_filaments protofilaments
and n_rings rings
and n_frayed_rings_plus rings at + end with outward bend
and n_frayed_rings_minus rings at - end with outward bend
"""
sites_per_scaffold = 5
n_frayed_rings = n_frayed_rings_minus + n_frayed_rings_plus
particles_per_filament = n_rings + sites_per_scaffold * (
n_frayed_rings + (2 if n_frayed_rings > 0 else 0)
)
total_particles = n_filaments * particles_per_filament
for filament in range(n_filaments):
for ring in range(n_rings):
end = (
"minus"
if n_frayed_rings_minus > 0 and ring <= n_frayed_rings_minus + 1
else "plus"
)
bent = (
ring < n_frayed_rings_minus
or ring > n_rings - 1 - n_frayed_rings_plus
)
edge = n_frayed_rings > 0 and (
ring == n_frayed_rings_minus
or ring == n_rings - 1 - n_frayed_rings_plus
)
i = (
filament * particles_per_filament
+ ring
+ sites_per_scaffold
* (
(ring if end == "minus" else n_frayed_rings_minus + 1)
if n_frayed_rings_minus > 0
else 0
)
+ sites_per_scaffold
* (
ring - ((n_rings - n_frayed_rings_plus) - 1)
if end == "plus" and bent
else 0
)
)
if ring < n_rings - 1: # bond along filament
i_filament = i + 1 + (sites_per_scaffold if bent or edge else 0)
microtubule.get_graph().add_edge(i, i_filament)
if not bent: # bond along ring
# as long as not in + end overhang
if not (
filament == n_filaments - 1
and ring > (n_rings - 1 - n_frayed_rings_plus) - 3
):
i_ring = i + particles_per_filament
if filament == n_filaments - 1:
i_ring += (
8 if end == "minus" and edge else 3
) - total_particles
microtubule.get_graph().add_edge(i, i_ring)
if bent or edge: # bent site bonds
microtubule.get_graph().add_edge(i, i + 1) # tub -- site0
microtubule.get_graph().add_edge(i, i + 2) # tub -- site1
microtubule.get_graph().add_edge(i, i + 3) # tub -- site2
microtubule.get_graph().add_edge(i, i + 4) # tub -- site3
microtubule.get_graph().add_edge(i, i + 5) # tub -- site4
microtubule.get_graph().add_edge(i + 1, i + 2) # site0 -- site1
microtubule.get_graph().add_edge(i + 1, i + 3) # site0 -- site2
microtubule.get_graph().add_edge(i + 1, i + 4) # site0 -- site3
microtubule.get_graph().add_edge(i + 1, i + 5) # site0 -- site4
microtubule.get_graph().add_edge(i + 2, i + 4) # site1 -- site3
microtubule.get_graph().add_edge(i + 2, i + 5) # site1 -- site4
microtubule.get_graph().add_edge(i + 3, i + 4) # site2 -- site3
microtubule.get_graph().add_edge(i + 3, i + 5) # site2 -- site4
# longitudinal bonds on bent rings
if ring > 0 and (bent or (edge and end == "minus")):
# site0 -- prev site0
microtubule.get_graph().add_edge(i + 1, i - 5)
# site1 -- prev site1
microtubule.get_graph().add_edge(i + 2, i - 4)
# site2 -- prev site2
microtubule.get_graph().add_edge(i + 3, i - 3)
# site3 -- prev site4
microtubule.get_graph().add_edge(i + 4, i - 1)
[docs] @staticmethod
def add_microtubule(
n_rings,
n_frayed_rings_minus,
n_frayed_rings_plus,
position_offset,
simulation,
use_GTP=True,
):
"""
add seed microtubule to the simulation
with n_filaments protofilaments
and n_rings rings
and n_frayed_rings_minus rings at - end with outward bend
and n_frayed_rings_plus rings at + end with outward bend
and position_offset
"""
if n_rings - (n_frayed_rings_minus + n_frayed_rings_plus) < 2:
raise Exception(
"Too many frayed rings, " "protofilaments will not form a microtubule"
)
n_filaments = 13
frayed_angle = np.deg2rad(10.0)
max_frayed_rings = math.floor((360.0 + frayed_angle / 2.0) / frayed_angle)
n_frayed_rings_minus = min(max_frayed_rings, n_frayed_rings_minus)
n_frayed_rings_plus = min(max_frayed_rings, n_frayed_rings_plus)
positions, types = MicrotubulesUtil.get_microtubule_positions_and_types(
n_filaments,
n_rings,
n_frayed_rings_plus,
n_frayed_rings_minus,
frayed_angle,
10.86,
use_GTP,
)
microtubule = simulation.add_topology(
"Microtubule", types, positions + position_offset
)
MicrotubulesUtil.add_edges(
microtubule, n_filaments, n_rings, n_frayed_rings_plus, n_frayed_rings_minus
)
[docs] @staticmethod
def add_tubulin_dimers(simulation, n_tubulin, box_size):
"""
add seed tubulin dimers to the simulation
"""
positions = np.random.uniform(size=(n_tubulin, 3)) * box_size - box_size * 0.5
for p in range(len(positions)):
to_B = 4.0 * ReaddyUtil.normalize(
np.array([random.random(), random.random(), random.random()])
)
top = simulation.add_topology(
"Dimer",
["tubulinA#free", "tubulinB#free"],
np.array([positions[p], positions[p] + to_B]),
)
top.get_graph().add_edge(0, 1)
[docs] @staticmethod
def add_tubulin_types(system, diffCoeff):
"""
add tubulin topology and particle types to the system
microtubules are 2D polymers and to encode polarity in each dimension,
there are 3 x 3 = 9 polymer types. These are represented as "type#x_y"
where x and y are both in [1,3]. spatially, the types are mapped like so:
x_(y+1)
/
A ____/____ B
/ / /
- end (x-1)_y__/___x_y__/_____(x+1)_y + end
/ / /
/___/____/
C / D
/
x_(y-1)
"""
system.topologies.add_type("Dimer")
system.add_topology_species("tubulinA#free", diffCoeff)
system.add_topology_species("tubulinB#free", diffCoeff)
system.topologies.add_type("Oligomer")
system.topologies.add_type("Oligomer#Fail-Shrink-GTP")
system.topologies.add_type("Oligomer#Fail-Shrink-GDP")
system.topologies.add_type("Microtubule")
system.topologies.add_type("Microtubule#Growing1-GTP")
system.topologies.add_type("Microtubule#Growing1-GDP")
system.topologies.add_type("Microtubule#Growing2-GTP")
system.topologies.add_type("Microtubule#Growing2-GDP")
system.topologies.add_type("Microtubule#Shrinking")
system.topologies.add_type("Microtubule#Fail-Shrink-GTP")
system.topologies.add_type("Microtubule#Fail-Shrink-GDP")
system.topologies.add_type("Microtubule#Attaching")
system.topologies.add_type("Microtubule#Fail-Attach")
system.topologies.add_type("Microtubule#Detaching-GTP")
system.topologies.add_type("Microtubule#Detaching-GDP")
system.topologies.add_type("Microtubule#Fail-Hydrolyze")
tube_tubulin_types = [
"tubulinA#GTP_",
"tubulinA#GDP_",
"tubulinB#GTP_",
"tubulinB#GDP_",
]
bent_tubulin_types = [
"tubulinA#GTP_bent_",
"tubulinA#GDP_bent_",
"tubulinB#GTP_bent_",
"tubulinB#GDP_bent_",
]
all_tubulin_types = tube_tubulin_types + bent_tubulin_types
for tubulin_type in all_tubulin_types:
MicrotubulesUtil.add_polymer_topology_species(
tubulin_type, diffCoeff, system
)
site_types = [
"site#out",
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#1_detach",
"site#2",
"site#2_GTP",
"site#2_GDP",
"site#2_detach",
"site#3",
"site#4",
"site#4_GTP",
"site#4_GDP",
"site#new",
]
system.add_species("site#remove", 0)
for site_type in site_types:
system.add_topology_species(site_type, diffCoeff)
[docs] @staticmethod
def get_all_tubulin_types():
"""
returns the list of all tubulin types
"""
tube_tubulin_types = [
"tubulinA#GTP_",
"tubulinA#GDP_",
"tubulinB#GTP_",
"tubulinB#GDP_",
]
bent_tubulin_types = [
"tubulinA#GTP_bent_",
"tubulinA#GDP_bent_",
"tubulinB#GTP_bent_",
"tubulinB#GDP_bent_",
]
all_tubulin_types = tube_tubulin_types + bent_tubulin_types
return all_tubulin_types
[docs] @staticmethod
def do_grow1(topology, GTP_state):
"""
start adding a tubulin dimer to the end of a protofilament:
add additional particles
"""
if parameters["verbose"]:
print("Grow 1")
recipe = readdy.StructuralReactionRecipe(topology)
v_newB = ReaddyUtil.get_vertex_of_type(
topology,
"tubulinB#free",
True,
error_msg="Failed to find tubulinB#free vertex",
)
v_newA = ReaddyUtil.get_neighbor_of_type(
topology, v_newB, "tubulinA#free", True
)
if v_newA is None:
raise Exception(
"Failed to find tubulinA#free vertex\n"
+ ReaddyUtil.topology_to_string(topology)
)
MicrotubulesUtil.add_tubulin_sites(topology, recipe, v_newB)
MicrotubulesUtil.add_tubulin_sites(topology, recipe, v_newA)
recipe.change_topology_type(f"Microtubule#Growing2-{GTP_state}")
return recipe
[docs] @staticmethod
def reaction_function_grow1_GTP(topology):
"""
start adding a tubulin dimer to the end of a protofilament:
add additional particles
"""
return MicrotubulesUtil.do_grow1(topology, "GTP")
[docs] @staticmethod
def reaction_function_grow1_GDP(topology):
"""
start adding a tubulin dimer to the end of a protofilament:
add additional particles
"""
return MicrotubulesUtil.do_grow1(topology, "GDP")
[docs] @staticmethod
def do_grow2(topology):
"""
finish adding a tubulin dimer to the end of a protofilament:
set types, positions, and edges
"""
recipe = readdy.StructuralReactionRecipe(topology)
if parameters["verbose"]:
print("Grow 2")
v_newB = ReaddyUtil.get_vertex_of_type(
topology,
"tubulinB#free",
True,
error_msg="Failed to find tubulinB#free vertex",
)
v_newA = ReaddyUtil.get_neighbor_of_type(
topology, v_newB, "tubulinA#free", True
)
if v_newA is None:
raise Exception(
"Failed to find tubulinA#free vertex\n"
+ ReaddyUtil.topology_to_string(topology)
)
v_site4 = ReaddyUtil.get_neighbor_of_type(topology, v_newA, "site#4", True)
if v_site4 is None:
raise Exception(
"Failed to find site#4 vertex\n"
+ ReaddyUtil.topology_to_string(topology)
)
v_endB = ReaddyUtil.get_neighbor_of_type(topology, v_site4, "tubulinB", False)
if v_endB is None:
raise Exception(
"Failed to find neighboring tubulin vertex\n"
+ ReaddyUtil.topology_to_string(topology)
)
v_sites = MicrotubulesUtil.get_tubulin_sites(topology, v_endB)
if v_sites is None:
raise Exception(
"TubulinB at end does not have sites!\n"
+ ReaddyUtil.topology_to_string(topology)
)
v_new_sitesB = ReaddyUtil.get_neighbors_of_type(
topology, v_newB, "site#new", True
)
if len(v_new_sitesB) != 5:
raise Exception(
f"Found {len(v_new_sitesB)} new particles on tubulinB, expected 5\n"
+ ReaddyUtil.topology_to_string(topology)
)
v_new_sitesA = ReaddyUtil.get_neighbors_of_type(
topology, v_newA, "site#new", True
)
if len(v_new_sitesA) != 5:
raise Exception(
f"Found {len(v_new_sitesA)} new particles on tubulinA, expected 5\n"
+ ReaddyUtil.topology_to_string(topology)
)
pos_endB = ReaddyUtil.get_vertex_position(topology, v_endB)
pos_site0 = ReaddyUtil.get_vertex_position(topology, v_sites[0])
pos_site1 = ReaddyUtil.get_vertex_position(topology, v_sites[1])
side = ReaddyUtil.normalize(pos_site1 - pos_endB)
normal = ReaddyUtil.normalize(pos_site0 - pos_endB)
tangent = np.cross(normal, side)
# remove temporary edge (site#4--tubulinA#free)]
removed, message = ReaddyUtil.try_remove_edge(
topology, recipe, v_sites[4], v_newA
)
if not removed:
raise Exception(message + "\n" + ReaddyUtil.topology_to_string(topology))
recipe.add_edge(v_endB, v_newA) # endB -- newA
# new tubulinA
tangent = ReaddyUtil.rotate(np.copy(tangent), side, np.deg2rad(10.0))
normal = ReaddyUtil.rotate(np.copy(normal), side, np.deg2rad(10.0))
pos_newA = pos_endB + 4.0 * tangent
polymer_indicesA = MicrotubulesUtil.increment_polymer_indices(
MicrotubulesUtil.get_polymer_indices(
topology.particle_type_of_vertex(v_endB)
),
[1, 0],
)
recipe.change_particle_type(
v_newA,
"tubulinA#GTP_bent"
+ MicrotubulesUtil.polymer_indices_to_string(polymer_indicesA),
)
recipe.change_particle_position(v_newA, pos_newA)
MicrotubulesUtil.setup_sites(
topology, recipe, v_new_sitesA, pos_newA, side, normal, tangent, "_GTP", ""
)
MicrotubulesUtil.connect_sites_between_tubulins(
topology, recipe, v_sites, v_new_sitesA
)
# new tubulinB
tangent = ReaddyUtil.rotate(np.copy(tangent), side, np.deg2rad(10.0))
normal = ReaddyUtil.rotate(np.copy(normal), side, np.deg2rad(10.0))
pos_newB = pos_newA + 4.0 * tangent
polymer_indicesB = MicrotubulesUtil.increment_polymer_indices(
polymer_indicesA, [1, 0]
)
recipe.change_particle_type(
v_newB,
"tubulinB#GTP_bent"
+ MicrotubulesUtil.polymer_indices_to_string(polymer_indicesB),
)
recipe.change_particle_position(v_newB, pos_newB)
MicrotubulesUtil.setup_sites(
topology,
recipe,
v_new_sitesB,
pos_newB,
side,
normal,
tangent,
"_GTP",
"_GTP",
)
MicrotubulesUtil.connect_sites_between_tubulins(
topology, recipe, v_new_sitesA, v_new_sitesB
)
recipe.change_topology_type("Microtubule")
return recipe
[docs] @staticmethod
def reaction_function_grow2_GTP(topology):
"""
finish adding a tubulin dimer to the end of a protofilament:
set types, positions, and edges
"""
return MicrotubulesUtil.do_grow2(topology)
[docs] @staticmethod
def reaction_function_grow2_GDP(topology):
"""
finish adding a tubulin dimer to the end of a protofilament:
set types, positions, and edges
"""
return MicrotubulesUtil.do_grow2(topology)
[docs] @staticmethod
def do_shrink1(topology, GTP_state):
"""
start removing a tubulin dimer from the end of a protofilament:
remove or detach particles, change particle types
"""
if parameters["verbose"]:
print("Shrink")
recipe = readdy.StructuralReactionRecipe(topology)
tubulins = MicrotubulesUtil.get_random_tubulin_neighbors(
topology, [["B#", "bent"], ["A#", "bent"]], [[], []], GTP_state, [1, 0]
)
if tubulins is None:
recipe.change_topology_type(f"{topology.type}#Fail-Shrink-{GTP_state}")
if parameters["verbose"]:
print(
"Shrink cancelled: Couldn't find "
"2 bent tubulin vertices to separate"
)
return recipe
# are both fragments crosslinked to other filaments?
if MicrotubulesUtil.filament_is_crosslinked(
topology, tubulins[0], -1
) and MicrotubulesUtil.filament_is_crosslinked(topology, tubulins[1], 1):
recipe.change_topology_type(f"{topology.type}#Fail-Shrink-{GTP_state}")
if parameters["verbose"]:
print(
"Shrink cancelled: both fragments (starting at "
+ ReaddyUtil.vertex_to_string(topology, tubulins[0])
+ " and "
+ ReaddyUtil.vertex_to_string(topology, tubulins[1])
+ ") are crosslinked"
)
return recipe
# will either of the cut fragments be a dimer?
is_dimer = []
filament_lengths = MicrotubulesUtil.get_filament_lengths(
topology, tubulins[0], tubulins[1]
)
for t in range(len(tubulins)):
is_dimer.append(filament_lengths[t] < 3)
if not is_dimer[0]:
site4 = ReaddyUtil.get_neighbor_of_type(
topology, tubulins[0], "site#4", False
)
if site4 is None:
raise Exception(
"Shrink cancelled: Couldn't find site4 to set reactive\n"
+ ReaddyUtil.topology_to_string(topology)
)
# if both fragments are bigger than dimers, just disconnect them
if True not in is_dimer:
MicrotubulesUtil.remove_bent_filament_site_bonds(
topology, recipe, tubulins[0], tubulins[1]
)
# detach at least one dimer
else:
tubulins_to_detach = []
for i in range(len(tubulins)):
if not is_dimer[i]:
continue
tubulins_to_detach.append(tubulins[i])
tubulins_to_detach.append(
MicrotubulesUtil.get_neighboring_tubulin(
topology, tubulins[i], [-1 if i == 0 else 1, 0]
)
)
if not MicrotubulesUtil.set_free(topology, recipe, tubulins_to_detach):
raise Exception(
"Failed to find sites for tubulins being released\n"
+ ReaddyUtil.topology_to_string(topology)
)
removed, message = ReaddyUtil.try_remove_edge(
topology, recipe, tubulins[0], tubulins[1]
)
if not removed:
raise Exception(message + "\n" + ReaddyUtil.topology_to_string(topology))
# make the new plus end reactive
if not is_dimer[0]:
recipe.change_particle_type(site4, f"site#4_{GTP_state}")
# remove sites from the new minus end of the second fragment
# if it's not a dimer and it and its plus neighbor
# are both fully attached laterally
if not is_dimer[1]:
MicrotubulesUtil.check_remove_tubulin_sites(topology, recipe, tubulins[1])
recipe.change_topology_type("Microtubule#Shrinking")
return recipe
[docs] @staticmethod
def reaction_function_shrink_GTP(topology):
"""
start removing a tubulin dimer from the end of a protofilament:
remove or detach particles, change particle types
"""
return MicrotubulesUtil.do_shrink1(topology, "GTP")
[docs] @staticmethod
def reaction_function_shrink_GDP(topology):
"""
start removing a tubulin dimer from the end of a protofilament:
remove or detach particles, change particle types
"""
return MicrotubulesUtil.do_shrink1(topology, "GDP")
[docs] @staticmethod
def reaction_function_shrink2(topology):
"""
finish removing a tubulin dimer from the end of a protofilament:
change topology types
"""
recipe = readdy.StructuralReactionRecipe(topology)
if len(topology.graph.get_vertices()) == 2:
recipe.change_topology_type("Dimer")
elif MicrotubulesUtil.topology_is_microtubule(topology):
recipe.change_topology_type("Microtubule")
else:
recipe.change_topology_type("Oligomer")
return recipe
[docs] @staticmethod
def reaction_function_attach(topology):
"""
attach tubulins laterally
"""
if parameters["verbose"]:
print("Attach")
recipe = readdy.StructuralReactionRecipe(topology)
attaching_sites = MicrotubulesUtil.get_attaching_sites(topology)
if len(attaching_sites) == 0:
raise Exception(
"Failed to find attaching vertices\n"
+ ReaddyUtil.topology_to_string(topology)
)
tubulins = []
for site in attaching_sites:
tubulins.append(
ReaddyUtil.get_neighbor_of_type(topology, site, "tubulin", False)
)
if tubulins[len(tubulins) - 1] is None:
raise Exception(
"Attach cancelled: failed to find attaching site's "
f"({ReaddyUtil.vertex_to_string(topology, site)}) tubulin\n"
+ ReaddyUtil.topology_to_string(topology)
)
# make sure sites don't belong to same tubulin
tubulin_ids = [
topology.particle_id_of_vertex(tubulins[0]),
topology.particle_id_of_vertex(tubulins[1]),
]
if tubulin_ids[0] == tubulin_ids[1]:
MicrotubulesUtil.cancel_attach(topology, recipe, attaching_sites)
if parameters["verbose"]:
print(
"Attach cancelled: sites ("
+ ReaddyUtil.vertex_to_string(topology, attaching_sites[0])
+ ", "
+ ReaddyUtil.vertex_to_string(topology, attaching_sites[1])
+ ") were on same tubulin ("
+ ReaddyUtil.vertex_to_string(topology, tubulins[0])
)
return recipe
# make sure sites belong to tubulins that can attach
tubulin_types = [
topology.particle_type_of_vertex(tubulins[0]),
topology.particle_type_of_vertex(tubulins[1]),
]
if not MicrotubulesUtil.tubulins_can_attach(tubulin_types):
MicrotubulesUtil.cancel_attach(topology, recipe, attaching_sites)
if parameters["verbose"]:
print(
"Attach cancelled: tubulins ("
+ ReaddyUtil.vertex_to_string(topology, tubulins[0])
+ ", "
+ ReaddyUtil.vertex_to_string(topology, tubulins[1])
+ ") can't attach"
)
return recipe
for i in range(2):
crosslinked = (
MicrotubulesUtil.get_neighboring_tubulin(
topology, tubulins[i], [0, 1 if i == 0 else -1]
)
is not None
)
if crosslinked:
MicrotubulesUtil.check_remove_tubulin_sites(
topology, recipe, tubulins[i], True
)
else:
ReaddyUtil.set_flags(topology, recipe, tubulins[i], [], ["bent"])
prev_tubulin = MicrotubulesUtil.get_neighboring_tubulin(
topology, tubulins[i], [-1, 0]
)
if prev_tubulin is not None:
MicrotubulesUtil.check_remove_tubulin_sites(
topology, recipe, prev_tubulin, False, tubulins[i], crosslinked
)
next_tubulin = MicrotubulesUtil.get_neighboring_tubulin(
topology, tubulins[i], [1, 0]
)
if next_tubulin is not None:
MicrotubulesUtil.check_remove_tubulin_sites(
topology, recipe, next_tubulin, False, tubulins[i], crosslinked
)
removed, message = ReaddyUtil.try_remove_edge(
topology, recipe, attaching_sites[0], attaching_sites[1]
)
if not removed:
raise Exception(message + "\n" + ReaddyUtil.topology_to_string(topology))
recipe.add_edge(tubulins[0], tubulins[1])
recipe.change_topology_type("Microtubule")
return recipe
[docs] @staticmethod
def reaction_function_detach1(topology):
"""
add new sites in preparation to detach tubulins laterally
"""
if parameters["verbose"]:
print("Detach")
recipe = readdy.StructuralReactionRecipe(topology)
GTP_state = (
"GTP"
if (
random.random()
<= parameters["ring_detach_GTP_rate"]
/ (
parameters["ring_detach_GTP_rate"]
+ parameters["ring_detach_GDP_rate"]
)
)
else "GDP"
)
detaching_tubulins = MicrotubulesUtil.get_random_tubulin_neighbors(
topology,
[["tubulin"], ["tubulin"]],
[["bent"], ["bent"]],
GTP_state,
[0, -1],
)
if detaching_tubulins is None:
if parameters["verbose"]:
print("Detach cancelled: Couldn't find 2 tubulin vertices to detach")
return recipe
for i in range(2):
MicrotubulesUtil.check_add_tubulin_sites(
topology,
recipe,
detaching_tubulins[i],
"site#new" if i == 0 else "site#1_detach",
"site#2_detach" if i == 0 else "site#new",
)
if (
MicrotubulesUtil.get_neighboring_tubulin(
topology, detaching_tubulins[i], [0, 1 if i == 0 else -1]
)
is None
):
ReaddyUtil.set_flags(
topology, recipe, detaching_tubulins[i], ["bent"], []
)
for j in range(2):
neighbor_tubulin = MicrotubulesUtil.get_neighboring_tubulin(
topology, detaching_tubulins[i], [-1 if j == 0 else 1, 0]
)
if neighbor_tubulin is not None:
MicrotubulesUtil.check_add_tubulin_sites(
topology, recipe, neighbor_tubulin
)
recipe.change_topology_type(f"Microtubule#Detaching-{GTP_state}")
return recipe
[docs] @staticmethod
def reaction_function_detach2(topology):
"""
detach tubulins laterally
"""
recipe = readdy.StructuralReactionRecipe(topology)
detaching_sites = [
ReaddyUtil.get_vertex_of_type(
topology,
"site#2_detach",
False,
error_msg="Failed to find detaching sites",
),
ReaddyUtil.get_vertex_of_type(
topology,
"site#1_detach",
False,
error_msg="Failed to find detaching sites",
),
]
detaching_tubulins = [
ReaddyUtil.get_neighbor_of_type(
topology, detaching_sites[0], "tubulin", False
),
ReaddyUtil.get_neighbor_of_type(
topology, detaching_sites[1], "tubulin", False
),
]
if None in detaching_tubulins:
tub0 = (
"None"
if detaching_tubulins[0] is None
else ReaddyUtil.vertex_to_string(detaching_tubulins[0])
)
tub1 = (
"None"
if detaching_tubulins[1] is None
else ReaddyUtil.vertex_to_string(detaching_tubulins[1])
)
raise Exception(
f"Failed to find detaching tubulins ({tub0}, {tub1})\n"
+ ReaddyUtil.topology_to_string(topology)
)
for i in range(2):
tubulins = [
MicrotubulesUtil.get_neighboring_tubulin(
topology, detaching_tubulins[i], [-1, 0]
),
detaching_tubulins[i],
MicrotubulesUtil.get_neighboring_tubulin(
topology, detaching_tubulins[i], [1, 0]
),
]
if tubulins[0] is None and tubulins[2] is None:
raise Exception(
"Tubulin has no neighbors on filament?!\n"
+ ReaddyUtil.topology_to_string(topology)
)
pos_tubulin = ReaddyUtil.get_vertex_position(topology, tubulins[1])
pos_filament = ReaddyUtil.get_vertex_position(
topology, tubulins[0] if tubulins[0] is not None else tubulins[2]
)
pos_ring = ReaddyUtil.get_vertex_position(
topology, detaching_tubulins[1 if i == 0 else 0]
)
frayed_angle = np.deg2rad(10.0)
tangent = (1 if tubulins[0] is not None else -1) * ReaddyUtil.normalize(
pos_tubulin - pos_filament
)
side = (1 if i == 0 else -1) * ReaddyUtil.normalize(pos_ring - pos_tubulin)
normal = -np.cross(np.copy(tangent), np.copy(side))
sites = 3 * [None]
added_sites = 3 * [False]
for j in range(3):
tangent = ReaddyUtil.rotate(
np.copy(tangent), side, frayed_angle * (-1 if j > 0 else 0.5)
)
normal = ReaddyUtil.rotate(
np.copy(normal), side, frayed_angle * (-1 if j > 0 else 0.5)
)
if tubulins[j] is not None:
sites[j] = MicrotubulesUtil.get_tubulin_sites(topology, tubulins[j])
tubulin_state = (
"_GTP"
if "GTP" in topology.particle_type_of_vertex(tubulins[j])
else "_GDP"
)
site_state_ring = (
tubulin_state
if "bent" in topology.particle_type_of_vertex(tubulins[j])
else ""
)
if sites[j] is None:
sites[j] = MicrotubulesUtil.get_new_sites(topology, tubulins[j])
if sites[j] is None:
raise Exception(
ReaddyUtil.vertex_to_string(topology, tubulins[j])
+ f" is missing sites [{i}]\n"
+ ReaddyUtil.topology_to_string(topology)
)
added_sites[j] = True
site_state_filament = (
tubulin_state
if MicrotubulesUtil.get_neighboring_tubulin(
topology, tubulins[j], [1, 0]
)
is None
else ""
)
MicrotubulesUtil.setup_sites(
topology,
recipe,
sites[j],
ReaddyUtil.get_vertex_position(topology, tubulins[j]),
side,
normal,
tangent,
site_state_ring,
site_state_filament,
)
else:
if sites[j][1] is None or sites[j][2] is None:
raise Exception(
"A ring site was None!\n"
+ ReaddyUtil.topology_to_string(topology)
)
recipe.change_particle_type(
sites[j][1], f"site#1{site_state_ring}"
)
recipe.change_particle_type(
sites[j][2], f"site#2{site_state_ring}"
)
if (
j > 0
and (sites[j - 1] is not None and sites[j] is not None)
and (added_sites[j - 1] or added_sites[j])
):
MicrotubulesUtil.connect_sites_between_tubulins(
topology, recipe, sites[j - 1], sites[j]
)
removed, message = ReaddyUtil.try_remove_edge(
topology, recipe, detaching_tubulins[0], detaching_tubulins[1]
)
if not removed:
raise Exception(message + "\n" + ReaddyUtil.topology_to_string(topology))
recipe.change_topology_type("Microtubule")
return recipe
[docs] @staticmethod
def reaction_function_hydrolyze(topology):
"""
hydrolyze GTP to GDP in a random tubulin
"""
if parameters["verbose"]:
print("Hydrolyze")
recipe = readdy.StructuralReactionRecipe(topology)
tubulin = ReaddyUtil.get_random_vertex_of_type(
topology,
"#GTP",
False,
parameters["verbose"],
"Hydrolyze cancelled: Couldn't find GTP-tubulin",
)
if tubulin is None:
return recipe
sites = MicrotubulesUtil.get_tubulin_sites(topology, tubulin)
if sites is not None:
for s in range(1, 4):
if "GTP" in topology.particle_type_of_vertex(sites[s]):
ReaddyUtil.set_flags(topology, recipe, sites[s], ["GDP"], ["GTP"])
ReaddyUtil.set_flags(topology, recipe, tubulin, ["GDP"], ["GTP"])
return recipe
[docs] @staticmethod
def rate_function_shrink_GTP(topology):
"""
rate function for removing a GTP-tubulin dimer from the end of a protofilament
"""
return parameters["protofilament_shrink_GTP_rate"]
[docs] @staticmethod
def rate_function_shrink_GDP(topology):
"""
rate function for removing a GDP-tubulin dimer from the end of a protofilament
"""
return parameters["protofilament_shrink_GDP_rate"]
[docs] @staticmethod
def rate_function_detach_ring(topology):
"""
rate function for detaching protofilaments laterally
at ring sites for GTP-tubulin
"""
return parameters["ring_detach_GTP_rate"] + parameters["ring_detach_GDP_rate"]
[docs] @staticmethod
def rate_function_hydrolyze(topology):
"""
rate function for hydrolyzing GTP to GDP in tubulin Bs
"""
return parameters["hydrolyze_rate"]
[docs] @staticmethod
def add_bonds_between_tubulins(tubulin_types, force_constant, system, util):
"""
add bonds between tubulins
"""
util.add_polymer_bond_2D( # bonds between protofilaments
tubulin_types, [0, 0], tubulin_types, [0, -1], force_constant, 5.2, system
)
util.add_polymer_bond_2D( # bonds between rings
tubulin_types, [0, 0], tubulin_types, [-1, 0], force_constant, 4.0, system
)
util.add_bond( # dimer bond and temporary bond
["tubulinB#free"], ["tubulinA#free"], force_constant, 4.0, system
)
[docs] @staticmethod
def add_tubulin_site_bonds(tubulin_types, site_types, force_constant, system, util):
"""
add bonds between a tubulin and its sites
"""
util.add_polymer_bond_2D(
tubulin_types, [0, 0], site_types, [], force_constant, 1.5, system
)
util.add_bond(
["tubulinA#free", "tubulinB#free"], site_types, force_constant, 1.5, system
)
util.add_bond(
["site#out"],
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#1_detach",
"site#2",
"site#2_GTP",
"site#2_GDP",
"site#2_detach",
],
force_constant,
2.12,
system,
)
util.add_bond(
["site#out"],
["site#3", "site#4", "site#4_GTP", "site#4_GDP"],
force_constant,
2.12,
system,
)
util.add_bond(
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#1_detach",
"site#2",
"site#2_GTP",
"site#2_GDP",
"site#2_detach",
],
["site#3", "site#4", "site#4_GTP", "site#4_GDP"],
force_constant,
2.12,
system,
)
util.add_bond( # temporary (grow reactions)
["tubulinA#free"], ["site#4", "site#4_GTP", "site#4_GDP"], 1.0, 2.5, system
)
util.add_bond( # temporary (attach reactions)
["site#1", "site#1_GTP", "site#1_GDP", "site#1_detach"],
["site#2", "site#2_GTP", "site#2_GDP", "site#2_detach"],
1.0,
2.5,
system,
)
util.add_bond( # temporary (detach reactions)
["site#new"], site_types, 1.0, 4.0, system
)
[docs] @staticmethod
def add_bent_site_bonds(force_constant, system, util):
"""
add bonds between sites on bent tubulins
"""
util.add_bond(["site#out"], ["site#out"], force_constant, 3.73, system)
util.add_bond(
["site#1", "site#1_GTP", "site#1_GDP", "site#1_detach"],
["site#1", "site#1_GTP", "site#1_GDP", "site#1_detach"],
force_constant,
4.0,
system,
)
util.add_bond(
["site#2", "site#2_GTP", "site#2_GDP", "site#2_detach"],
["site#2", "site#2_GTP", "site#2_GDP", "site#2_detach"],
force_constant,
4.0,
system,
)
util.add_bond(
["site#3"],
["site#4", "site#4_GTP", "site#4_GDP"],
force_constant,
1.0,
system,
)
[docs] @staticmethod
def add_angles_between_tubulins(tubulin_type_sets, force_constant, system, util):
"""
add angles between tubulins
"""
util.add_polymer_angle_2D(
tubulin_type_sets[2],
[0, 1],
tubulin_type_sets[2],
[0, 0],
tubulin_type_sets[2],
[-1, 0],
force_constant,
1.75,
system,
)
util.add_polymer_angle_2D(
tubulin_type_sets[2],
[0, 1],
tubulin_type_sets[2],
[0, 0],
tubulin_type_sets[2],
[1, 0],
force_constant,
1.40,
system,
)
util.add_polymer_angle_2D(
tubulin_type_sets[2],
[0, -1],
tubulin_type_sets[2],
[0, 0],
tubulin_type_sets[2],
[-1, 0],
force_constant,
1.40,
system,
)
util.add_polymer_angle_2D(
tubulin_type_sets[2],
[0, -1],
tubulin_type_sets[2],
[0, 0],
tubulin_type_sets[2],
[1, 0],
force_constant,
1.75,
system,
)
util.add_polymer_angle_2D(
tubulin_type_sets[0],
[-1, 0],
tubulin_type_sets[0],
[0, 0],
tubulin_type_sets[0],
[1, 0],
force_constant,
np.pi,
system,
)
util.add_polymer_angle_2D(
tubulin_type_sets[0],
[-1, 0],
tubulin_type_sets[0],
[0, 0],
tubulin_type_sets[1],
[1, 0],
force_constant,
3.05,
system,
)
util.add_polymer_angle_2D(
tubulin_type_sets[0],
[1, 0],
tubulin_type_sets[0],
[0, 0],
tubulin_type_sets[1],
[-1, 0],
force_constant,
3.05,
system,
)
util.add_polymer_angle_2D(
tubulin_type_sets[2],
[-1, 0],
tubulin_type_sets[1],
[0, 0],
tubulin_type_sets[2],
[1, 0],
force_constant,
2.97,
system,
)
util.add_polymer_angle_2D(
tubulin_type_sets[2],
[0, -1],
tubulin_type_sets[2],
[0, 0],
tubulin_type_sets[2],
[0, 1],
force_constant,
2.67,
system,
)
[docs] @staticmethod
def add_tubulin_site_angles(tubulin_types, force_constant, system, util):
"""
add angles between a tubulin and its sites
"""
util.add_polymer_angle_2D(
tubulin_types,
[0, 0],
["site#out"],
[],
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#2",
"site#2_GTP",
"site#2_GDP",
"site#3",
"site#4",
"site#4_GTP",
"site#4_GDP",
],
[],
force_constant,
0.79,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[0, 0],
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#2",
"site#2_GTP",
"site#2_GDP",
"site#3",
"site#4",
"site#4_GTP",
"site#4_GDP",
],
[],
["site#out"],
[],
force_constant,
0.79,
system,
)
util.add_polymer_angle_2D(
["site#out"],
[],
tubulin_types,
[0, 0],
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#2",
"site#2_GTP",
"site#2_GDP",
"site#3",
"site#4",
"site#4_GTP",
"site#4_GDP",
],
[],
force_constant,
np.pi / 2,
system,
)
util.add_angle(
["site#out"],
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#2",
"site#2_GTP",
"site#2_GDP",
],
["site#3", "site#4", "site#4_GTP", "site#4_GDP"],
force_constant,
1.05,
system,
)
util.add_angle(
["site#out"],
["site#3", "site#4", "site#4_GTP", "site#4_GDP"],
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#2",
"site#2_GTP",
"site#2_GDP",
],
force_constant,
1.05,
system,
)
util.add_angle(
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#2",
"site#2_GTP",
"site#2_GDP",
],
["site#out"],
["site#3", "site#4", "site#4_GTP", "site#4_GDP"],
force_constant,
1.05,
system,
)
util.add_polymer_angle_2D(
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#2",
"site#2_GTP",
"site#2_GDP",
],
[],
tubulin_types,
[0, 0],
["site#3", "site#4", "site#4_GTP", "site#4_GDP"],
[],
force_constant,
np.pi / 2,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[0, 0],
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#2",
"site#2_GTP",
"site#2_GDP",
],
[],
["site#3", "site#4", "site#4_GTP", "site#4_GDP"],
[],
force_constant,
0.79,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[0, 0],
["site#3", "site#4", "site#4_GTP", "site#4_GDP"],
[],
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#2",
"site#2_GTP",
"site#2_GDP",
],
[],
force_constant,
0.79,
system,
)
util.add_angle(
["site#1", "site#1_GTP", "site#1_GDP"],
["site#out"],
["site#2", "site#2_GTP", "site#2_GDP"],
force_constant,
np.pi / 2,
system,
)
util.add_angle(
["site#3"],
["site#out"],
["site#4", "site#4_GTP", "site#4_GDP"],
force_constant,
np.pi / 2,
system,
)
util.add_polymer_angle_2D(
["site#1", "site#1_GTP", "site#1_GDP"],
[],
tubulin_types,
[0, 0],
["site#2", "site#2_GTP", "site#2_GDP"],
[],
force_constant,
np.pi,
system,
)
util.add_polymer_angle_2D(
["site#3"],
[],
tubulin_types,
[0, 0],
["site#4", "site#4_GTP", "site#4_GDP"],
[],
force_constant,
np.pi,
system,
)
util.add_angle(
["site#3"],
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#2",
"site#2_GTP",
"site#2_GDP",
],
["site#4", "site#4_GTP", "site#4_GDP"],
force_constant,
np.pi / 2,
system,
)
util.add_angle(
["site#1", "site#1_GTP", "site#1_GDP"],
["site#3", "site#4", "site#4_GTP", "site#4_GDP"],
["site#2", "site#2_GTP", "site#2_GDP"],
force_constant,
np.pi / 2,
system,
)
[docs] @staticmethod
def add_bent_site_angles(tubulin_types, force_constant, system, util):
"""
add angles between sites on bent tubulins
"""
util.add_angle(
["site#1", "site#1_GTP", "site#1_GDP"],
["site#1", "site#1_GTP", "site#1_GDP"],
["site#out"],
force_constant,
1.51,
system,
)
util.add_angle(
["site#2", "site#2_GTP", "site#2_GDP"],
["site#2", "site#2_GTP", "site#2_GDP"],
["site#out"],
force_constant,
1.51,
system,
)
util.add_angle(
["site#1", "site#1_GTP", "site#1_GDP"],
["site#out"],
["site#out"],
force_constant,
1.63,
system,
)
util.add_angle(
["site#2", "site#2_GTP", "site#2_GDP"],
["site#out"],
["site#out"],
force_constant,
1.63,
system,
)
util.add_polymer_angle_2D(
["site#out"],
[],
["site#out"],
[],
tubulin_types,
[0, 0],
force_constant,
1.66,
system,
)
util.add_polymer_angle_2D(
["site#1", "site#1_GTP", "site#1_GDP"],
[],
["site#1", "site#1_GTP", "site#1_GDP"],
[],
tubulin_types,
[0, 0],
force_constant,
np.pi / 2,
system,
)
util.add_polymer_angle_2D(
["site#2", "site#2_GTP", "site#2_GDP"],
[],
["site#2", "site#2_GTP", "site#2_GDP"],
[],
tubulin_types,
[0, 0],
force_constant,
np.pi / 2,
system,
)
util.add_polymer_angle_2D(
["site#4", "site#4_GTP", "site#4_GDP"],
[],
["site#3"],
[],
tubulin_types,
[0, 0],
force_constant,
3.05,
system,
)
util.add_polymer_angle_2D(
["site#3"],
[],
["site#4", "site#4_GTP", "site#4_GDP"],
[],
tubulin_types,
[0, 0],
force_constant,
3.05,
system,
)
util.add_angle(
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#2",
"site#2_GTP",
"site#2_GDP",
],
["site#4", "site#4_GTP", "site#4_GDP"],
["site#3"],
force_constant,
2.35,
system,
)
util.add_angle(
[
"site#1",
"site#1_GTP",
"site#1_GDP",
"site#2",
"site#2_GTP",
"site#2_GDP",
],
["site#3"],
["site#4", "site#4_GTP", "site#4_GDP"],
force_constant,
2.35,
system,
)
util.add_angle(
["site#out"], ["site#out"], ["site#out"], force_constant, 2.97, system
)
util.add_angle(
["site#1", "site#1_GTP", "site#1_GDP"],
["site#1", "site#1_GTP", "site#1_GDP"],
["site#1", "site#1_GTP", "site#1_GDP"],
force_constant,
2.97,
system,
)
util.add_angle(
["site#2", "site#2_GTP", "site#2_GDP"],
["site#2", "site#2_GTP", "site#2_GDP"],
["site#2", "site#2_GTP", "site#2_GDP"],
force_constant,
2.97,
system,
)
[docs] @staticmethod
def add_edge_site_angles(tubulin_types, force_constant, system, util):
"""
add angles between sites at the edge between tube and bent tubulins
"""
util.add_polymer_angle_2D(
tubulin_types,
[0, -1],
tubulin_types,
[0, 0],
["site#out"],
[],
force_constant,
1.81,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[0, -1],
tubulin_types,
[0, 0],
["site#1", "site#1_GTP", "site#1_GDP"],
[],
force_constant,
0.3,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[0, -1],
tubulin_types,
[0, 0],
["site#2", "site#2_GTP", "site#2_GDP"],
[],
force_constant,
2.84,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[0, -1],
tubulin_types,
[0, 0],
["site#3"],
[],
force_constant,
1.4,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[0, -1],
tubulin_types,
[0, 0],
["site#4", "site#4_GTP", "site#4_GDP"],
[],
force_constant,
1.75,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[-1, 0],
tubulin_types,
[0, 0],
["site#out"],
[],
force_constant,
np.pi / 2,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[-1, 0],
tubulin_types,
[0, 0],
["site#1", "site#1_GTP", "site#1_GDP"],
[],
force_constant,
np.pi / 2,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[-1, 0],
tubulin_types,
[0, 0],
["site#2", "site#2_GTP", "site#2_GDP"],
[],
force_constant,
np.pi / 2,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[-1, 0],
tubulin_types,
[0, 0],
["site#3"],
[],
force_constant,
0.0,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[-1, 0],
tubulin_types,
[0, 0],
["site#4", "site#4_GTP", "site#4_GDP"],
[],
force_constant,
np.pi,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[0, 1],
tubulin_types,
[0, 0],
["site#out"],
[],
force_constant,
1.81,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[0, 1],
tubulin_types,
[0, 0],
["site#1", "site#1_GTP", "site#1_GDP"],
[],
force_constant,
2.84,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[0, 1],
tubulin_types,
[0, 0],
["site#2", "site#2_GTP", "site#2_GDP"],
[],
force_constant,
0.3,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[0, 1],
tubulin_types,
[0, 0],
["site#3"],
[],
force_constant,
1.75,
system,
)
util.add_polymer_angle_2D(
tubulin_types,
[0, 1],
tubulin_types,
[0, 0],
["site#4", "site#4_GTP", "site#4_GDP"],
[],
force_constant,
1.4,
system,
)
[docs] @staticmethod
def add_polymer_repulsion(particle_types, force_const, distance, system, util):
"""
adds a pairwise repulsion between all polymer numbers
of types particle_types
with force constant force_const
with equilibrium distance [nm]
"""
types = []
for t in particle_types:
types += MicrotubulesUtil.get_all_polymer_tubulin_types(t)
util.add_repulsion(types, types, force_const, distance, system)
[docs] @staticmethod
def add_growth_reaction(system, rate_GTP, rate_GDP, reaction_distance):
"""
add dimers to the ends of protofilaments
"""
system.topologies.add_spatial_reaction(
"Start_Grow_GTP: Microtubule(site#4_GTP) + Dimer(tubulinA#free) -> "
"Microtubule#Growing1-GTP(site#4--tubulinA#free)",
rate=rate_GTP,
radius=0.5 + reaction_distance,
)
system.topologies.add_spatial_reaction(
"Start_Grow_GDP: Microtubule(site#4_GDP) + Dimer(tubulinA#free) -> "
"Microtubule#Growing1-GDP(site#4--tubulinA#free)",
rate=rate_GDP,
radius=0.5 + reaction_distance,
)
system.topologies.add_structural_reaction(
"Setup_Grow_GTP",
topology_type="Microtubule#Growing1-GTP",
reaction_function=MicrotubulesUtil.reaction_function_grow1_GTP,
rate_function=ReaddyUtil.rate_function_infinity,
)
system.topologies.add_structural_reaction(
"Setup_Grow_GDP",
topology_type="Microtubule#Growing1-GDP",
reaction_function=MicrotubulesUtil.reaction_function_grow1_GDP,
rate_function=ReaddyUtil.rate_function_infinity,
)
system.topologies.add_structural_reaction(
"Grow_GTP",
topology_type="Microtubule#Growing2-GTP",
reaction_function=MicrotubulesUtil.reaction_function_grow2_GTP,
rate_function=ReaddyUtil.rate_function_infinity,
)
system.topologies.add_structural_reaction(
"Grow_GDP",
topology_type="Microtubule#Growing2-GDP",
reaction_function=MicrotubulesUtil.reaction_function_grow2_GDP,
rate_function=ReaddyUtil.rate_function_infinity,
)
[docs] @staticmethod
def add_shrink_reaction(system):
"""
separate dimers and oligomers from the ends
of frayed protofilaments and oligomers
"""
system.topologies.add_structural_reaction(
"Shrink_MT_GTP",
topology_type="Microtubule",
reaction_function=MicrotubulesUtil.reaction_function_shrink_GTP,
rate_function=MicrotubulesUtil.rate_function_shrink_GTP,
)
system.topologies.add_structural_reaction(
"Shrink_MT_GDP",
topology_type="Microtubule",
reaction_function=MicrotubulesUtil.reaction_function_shrink_GDP,
rate_function=MicrotubulesUtil.rate_function_shrink_GDP,
)
system.topologies.add_structural_reaction(
"Shrink_Oligo_GTP",
topology_type="Oligomer",
reaction_function=MicrotubulesUtil.reaction_function_shrink_GTP,
rate_function=MicrotubulesUtil.rate_function_shrink_GTP,
)
system.topologies.add_structural_reaction(
"Shrink_Oligo_GDP",
topology_type="Oligomer",
reaction_function=MicrotubulesUtil.reaction_function_shrink_GDP,
rate_function=MicrotubulesUtil.rate_function_shrink_GDP,
)
system.topologies.add_structural_reaction(
"Finish_Shrink",
topology_type="Microtubule#Shrinking",
reaction_function=MicrotubulesUtil.reaction_function_shrink2,
rate_function=ReaddyUtil.rate_function_infinity,
)
system.topologies.add_structural_reaction(
"Fail_Shrink_MT_GTP",
topology_type="Microtubule#Fail-Shrink-GTP",
reaction_function=ReaddyUtil.reaction_function_reset_state,
rate_function=ReaddyUtil.rate_function_infinity,
)
system.topologies.add_structural_reaction(
"Fail_Shrink_MT_GDP",
topology_type="Microtubule#Fail-Shrink-GDP",
reaction_function=ReaddyUtil.reaction_function_reset_state,
rate_function=ReaddyUtil.rate_function_infinity,
)
system.topologies.add_structural_reaction(
"Fail_Shrink_Oligo_GTP",
topology_type="Oligomer#Fail-Shrink-GTP",
reaction_function=ReaddyUtil.reaction_function_reset_state,
rate_function=ReaddyUtil.rate_function_infinity,
)
system.topologies.add_structural_reaction(
"Fail_Shrink_Oligo_GDP",
topology_type="Oligomer#Fail-Shrink-GDP",
reaction_function=ReaddyUtil.reaction_function_reset_state,
rate_function=ReaddyUtil.rate_function_infinity,
)
[docs] @staticmethod
def add_attach_reaction(system, rate_GTP, rate_GDP, reaction_distance):
"""
attach protofilaments laterally
"""
system.topologies.add_spatial_reaction(
"Start_Attach_GTP1: Microtubule(site#1_GTP) + Microtubule(site#2_GTP) -> "
"Microtubule#Attaching(site#1--site#2) [self=true]",
rate=rate_GTP,
radius=1.0 + reaction_distance,
)
system.topologies.add_spatial_reaction(
"Start_Attach_GTP2: Microtubule(site#1_GTP) + Microtubule(site#2_GDP) -> "
"Microtubule#Attaching(site#1--site#2) [self=true]",
rate=rate_GTP,
radius=1.0 + reaction_distance,
)
system.topologies.add_spatial_reaction(
"Start_Attach_GTP3: Microtubule(site#1_GDP) + Microtubule(site#2_GTP) -> "
"Microtubule#Attaching(site#1--site#2) [self=true]",
rate=rate_GTP,
radius=1.0 + reaction_distance,
)
system.topologies.add_spatial_reaction(
"Start_Attach_GDP: Microtubule(site#1_GDP) + Microtubule(site#2_GDP) -> "
"Microtubule#Attaching(site#1--site#2) [self=true]",
rate=rate_GDP,
radius=1.0 + reaction_distance,
)
system.topologies.add_structural_reaction(
"Setup_Attach",
topology_type="Microtubule#Attaching",
reaction_function=MicrotubulesUtil.reaction_function_attach,
rate_function=ReaddyUtil.rate_function_infinity,
)
[docs] @staticmethod
def add_detach_reaction(system):
"""
detach protofilaments laterally
"""
system.topologies.add_structural_reaction(
"Start_Detach",
topology_type="Microtubule",
reaction_function=MicrotubulesUtil.reaction_function_detach1,
rate_function=MicrotubulesUtil.rate_function_detach_ring,
)
system.topologies.add_structural_reaction(
"Detach_GTP",
topology_type="Microtubule#Detaching-GTP",
reaction_function=MicrotubulesUtil.reaction_function_detach2,
rate_function=ReaddyUtil.rate_function_infinity,
)
system.topologies.add_structural_reaction(
"Detach_GDP",
topology_type="Microtubule#Detaching-GDP",
reaction_function=MicrotubulesUtil.reaction_function_detach2,
rate_function=ReaddyUtil.rate_function_infinity,
)
[docs] @staticmethod
def add_hydrolyze_reaction(system):
"""
hydrolyze GTP-tubulinB to GDP-tubulinB
"""
system.topologies.add_structural_reaction(
"Hydrolyze",
topology_type="Microtubule",
reaction_function=MicrotubulesUtil.reaction_function_hydrolyze,
rate_function=MicrotubulesUtil.rate_function_hydrolyze,
)
system.topologies.add_structural_reaction(
"Fail_Hydrolyze",
topology_type="Microtubule#Fail-Hydrolyze",
reaction_function=ReaddyUtil.reaction_function_reset_state,
rate_function=ReaddyUtil.rate_function_infinity,
)