Source code for simularium_readdy_models.actin.actin_util

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import numpy as np
import readdy
import random

from ..common import ReaddyUtil
from .actin_generator import ActinGenerator
from .actin_structure import ActinStructure
from .fiber_data import FiberData


parameters = {}


[docs]def set_parameters(p): global parameters parameters = p return p
displacements = {}
[docs]def set_displacements(d): global displacements displacements = d return d
time_index = 0 init_monomer_positions = {} pointed_monomer_positions = []
[docs]class ActinUtil: def __init__(self, parameters, displacements=None): """ Utility functions for ReaDDy branched actin models Parameters need to be accessible in ReaDDy callbacks which can't be instance methods, so parameters are global """ set_parameters(parameters) if displacements is not None: set_displacements(displacements)
[docs] @staticmethod def get_new_vertex(topology): """ Get the vertex tagged "new" """ results = ReaddyUtil.get_vertices_of_type( topology, "new", exact_match=False, error_msg="Failed to find new vertex" ) if len(results) > 1: raise Exception( f"Found more than one new vertex\n" f"{ReaddyUtil.topology_to_string(topology)}" ) return results[0]
[docs] @staticmethod def get_new_arp23(topology): """ get a new arp3 and its unbranched arp2#free neighbor, meaning the arp2/3 dimer has just bound """ for vertex in topology.graph.get_vertices(): pt = topology.particle_type_of_vertex(vertex) if "arp3#new" in pt: for neighbor in vertex: if topology.particle_type_of_vertex(neighbor.get()) == "arp2#free": return neighbor.get(), vertex return None, None
[docs] @staticmethod def get_actin_number(topology, vertex, offset): """ get the type number for an actin plus the given offset in range [-1, 1] (i.e. return 3 for type = "actin#ATP_1" and offset = -1) """ pt = topology.particle_type_of_vertex(vertex) if "actin" not in pt: raise Exception( f"Failed to get actin number: {pt} is not actin\n" f"{ReaddyUtil.topology_to_string(topology)}" ) return ReaddyUtil.calculate_polymer_number(int(pt[-1]), offset)
[docs] @staticmethod def get_all_polymer_actin_types(vertex_type): """ get a list of all numbered versions of a type (e.g. for "actin#ATP" return ["actin#ATP_1", "actin#ATP_2", "actin#ATP_3"]) """ spacer = "_" if "#" not in vertex_type: spacer = "#" return [ f"{vertex_type}{spacer}1", f"{vertex_type}{spacer}2", f"{vertex_type}{spacer}3", ]
[docs] @staticmethod def get_actin_rotation(positions, box_size, periodic_boundary=True): """ get the difference in the actin's current orientation compared to the initial orientation as a rotation matrix positions = [prev actin position, middle actin position, next actin position] """ if periodic_boundary: positions[0] = ReaddyUtil.get_non_periodic_boundary_position( positions[1], positions[0], box_size ) positions[2] = ReaddyUtil.get_non_periodic_boundary_position( positions[1], positions[2], box_size ) current_orientation = ReaddyUtil.get_orientation_from_positions(positions) return np.matmul( current_orientation, np.linalg.inv(ActinStructure.orientation()) )
[docs] @staticmethod def get_actin_axis_position(positions, box_size, periodic_boundary=True): """ get the position on the filament axis closest to an actin positions = [ previous actin position, middle actin position, next actin position ] """ rotation = ActinUtil.get_actin_rotation(positions, box_size, periodic_boundary) if rotation is None: return None vector_to_axis_local = np.squeeze( np.array(np.dot(rotation, ActinStructure.vector_to_axis())) ) return positions[1] + vector_to_axis_local
[docs] @staticmethod def get_position_for_new_vertex(positions, offset_vector): """ get the offset vector in the local space for the actin at positions[1] positions = [ previous actin position, middle actin position, next actin position ] """ rotation = ActinUtil.get_actin_rotation( positions, parameters["box_size"], bool(parameters["periodic_boundary"]) ) if rotation is None: return None vector_to_new_pos = np.squeeze(np.array(np.dot(rotation, offset_vector))) return (positions[1] + vector_to_new_pos).tolist()
[docs] @staticmethod def get_next_actin(topology, v_actin, direction, error_if_not_found=False): """ get the next actin toward the pointed or barbed direction """ n = ActinUtil.get_actin_number(topology, v_actin, direction) end_type = "barbed" if direction > 0 else "pointed" actin_types = [ f"actin#ATP_{n}", f"actin#{n}", f"actin#mid_ATP_{n}", f"actin#mid_{n}", f"actin#{end_type}_ATP_{n}", f"actin#{end_type}_{n}", ] if direction < 0 and n == 1: actin_types += ["actin#branch_1", "actin#branch_ATP_1"] error_msg = f"Couldn't find next actin with number {n}" v_actin_neighbor = ReaddyUtil.get_neighbor_of_types( topology, v_actin, actin_types, [], parameters["verbose"], error_msg if not error_if_not_found else "", error_msg if error_if_not_found else "", ) return v_actin_neighbor
[docs] @staticmethod def get_prev_branch_actin(topology, vertex, last_vertex_id, max_edges): """ recurse up the chain until first branch actin is found or max_edges is reached """ for neighbor in vertex: n_id = topology.particle_id_of_vertex(neighbor) if n_id == last_vertex_id: continue pt = topology.particle_type_of_vertex(neighbor) if "branch_" in pt: return neighbor.get(), max_edges else: if max_edges <= 1: return None, max_edges return ActinUtil.get_prev_branch_actin( topology, neighbor.get(), n_id, max_edges - 1 ) return None, max_edges
[docs] @staticmethod def get_branch_orientation_vertices_and_offset(topology, vertex): """ get orientation vertices [actin, actin_arp2, actin_arp3] for a new actin within 3 actins of a branch, as well as the offset vector """ v_arp2 = ReaddyUtil.get_neighbor_of_types( topology, vertex, ["arp2", "arp2#branched", "arp2#free"], [] ) offset_index = 0 if v_arp2 is None: v_branch, edges = ActinUtil.get_prev_branch_actin(topology, vertex, None, 3) if v_branch is None: raise Exception( "Failed to set position: couldn't find arp2 " f"or first branch actin\n{ReaddyUtil.topology_to_string(topology)}" ) offset_index = 3 - edges v_arp2 = ReaddyUtil.get_neighbor_of_types( topology, v_branch, ["arp2", "arp2#branched", "arp2#free"], [], error_msg="Failed to set position: couldn't find arp2", ) v_arp3 = ReaddyUtil.get_neighbor_of_types( topology, v_arp2, ["arp3", "arp3#ATP", "arp3#new", "arp3#new_ATP"], [], error_msg="Failed to set position: couldn't find arp3", ) actin_types = ( ActinUtil.get_all_polymer_actin_types("actin") + ActinUtil.get_all_polymer_actin_types("actin#ATP") + ActinUtil.get_all_polymer_actin_types("actin#mid") + ActinUtil.get_all_polymer_actin_types("actin#mid_ATP") + ActinUtil.get_all_polymer_actin_types("actin#barbed") + ActinUtil.get_all_polymer_actin_types("actin#barbed_ATP") ) v_actin_arp3 = ReaddyUtil.get_neighbor_of_types( topology, v_arp3, actin_types, [], error_msg="Failed to set position: couldn't find actin_arp3", ) n_pointed = ActinUtil.get_actin_number(topology, v_actin_arp3, -1) actin_types = [f"actin#ATP_{n_pointed}", f"actin#{n_pointed}"] v_actin_arp2 = ReaddyUtil.get_neighbor_of_types( topology, v_actin_arp3, actin_types, [], error_msg="Failed to set position: couldn't find actin_arp2", ) n_pointed = ActinUtil.get_actin_number(topology, v_actin_arp2, -1) actin_types = [ f"actin#ATP_{n_pointed}", f"actin#{n_pointed}", f"actin#pointed_ATP_{n_pointed}", f"actin#pointed_{n_pointed}", ] if n_pointed == 1: actin_types += ["actin#branch_1", "actin#branch_ATP_1"] v_prev = ReaddyUtil.get_neighbor_of_types( topology, v_actin_arp2, actin_types, [v_actin_arp3], error_msg="Failed to set position: couldn't find v_prev", ) return ( [v_prev, v_actin_arp2, v_actin_arp3], ActinStructure.mother1_to_branch_actin_vectors()[offset_index], )
[docs] @staticmethod def set_end_vertex_position(topology, recipe, v_new, barbed): """ set the position of a new pointed or barbed vertex """ vertices = [] offset_vector = ( ActinStructure.mother1_to_mother3_vector() if barbed else ActinStructure.mother1_to_mother_vector() ) at_branch = False vertices.append( ReaddyUtil.get_neighbor_of_type(topology, v_new, "actin", False) ) if vertices[0] is None: ( vertices, offset_vector, ) = ActinUtil.get_branch_orientation_vertices_and_offset(topology, v_new) at_branch = True else: vertices.append( ReaddyUtil.get_neighbor_of_type( topology, vertices[0], "actin", False, [v_new] ) ) if vertices[1] is None: ( vertices, offset_vector, ) = ActinUtil.get_branch_orientation_vertices_and_offset( topology, v_new ) at_branch = True else: vertices.append( ReaddyUtil.get_neighbor_of_type( topology, vertices[1], "actin", False, [vertices[0]] ) ) if vertices[2] is None: ( vertices, offset_vector, ) = ActinUtil.get_branch_orientation_vertices_and_offset( topology, v_new ) at_branch = True positions = [] for v in vertices: positions.append(ReaddyUtil.get_vertex_position(topology, v)) if barbed and not at_branch: positions = positions[::-1] pos = ActinUtil.get_position_for_new_vertex(positions, offset_vector) if pos is None: raise Exception( f"Failed to set position: couldn't calculate position\n" f"{ReaddyUtil.topology_to_string(topology)}" ) recipe.change_particle_position(v_new, pos)
[docs] @staticmethod def set_new_trimer_vertex_position(topology, recipe, v_new, v_pointed, v_barbed): """ set the position of an actin monomer just added to a dimer to create a trimer """ pos_new = ReaddyUtil.get_vertex_position(topology, v_new) pos_pointed = ReaddyUtil.get_vertex_position(topology, v_pointed) pos_barbed = ReaddyUtil.get_vertex_position(topology, v_barbed) v_barbed_to_pointed = pos_pointed - pos_barbed v_barbed_to_new = pos_new - pos_barbed current_angle = ReaddyUtil.get_angle_between_vectors( v_barbed_to_pointed, v_barbed_to_new ) angle = ActinStructure.actin_to_actin_angle() - current_angle axis = np.cross(v_barbed_to_pointed, v_barbed_to_new) pos = pos_barbed + ReaddyUtil.rotate( ActinStructure.actin_to_actin_distance() * ReaddyUtil.normalize(v_barbed_to_new), axis, angle, ) recipe.change_particle_position(v_new, pos)
[docs] @staticmethod def set_arp23_vertex_position( topology, recipe, v_arp2, v_arp3, v_actin_arp2, v_actin_arp3 ): """ set the position of new arp2/3 vertices """ actin_types = ( ActinUtil.get_all_polymer_actin_types("actin") + ActinUtil.get_all_polymer_actin_types("actin#ATP") + ActinUtil.get_all_polymer_actin_types("actin#mid") + ActinUtil.get_all_polymer_actin_types("actin#mid_ATP") + ActinUtil.get_all_polymer_actin_types("actin#pointed") + ActinUtil.get_all_polymer_actin_types("actin#pointed_ATP") + ["actin#branch_1", "actin#branch_ATP_1"] ) v1 = ReaddyUtil.get_neighbor_of_types( topology, v_actin_arp2, actin_types, [v_actin_arp3], error_msg="Failed to set position: couldn't find v1", ) pos1 = ReaddyUtil.get_vertex_position(topology, v1) pos2 = ReaddyUtil.get_vertex_position(topology, v_actin_arp2) pos3 = ReaddyUtil.get_vertex_position(topology, v_actin_arp3) pos_arp2 = ActinUtil.get_position_for_new_vertex( [pos1, pos2, pos3], ActinStructure.mother1_to_arp2_vector() ) if pos_arp2 is None: raise Exception( f"Failed to set position of arp2: couldn't calculate position\n" f"{ReaddyUtil.topology_to_string(topology)}" ) recipe.change_particle_position(v_arp2, pos_arp2) pos_arp3 = ActinUtil.get_position_for_new_vertex( [pos1, pos2, pos3], ActinStructure.mother1_to_arp3_vector() ) if pos_arp3 is None: raise Exception( f"Failed to set position of arp3: couldn't calculate position\n" f"{ReaddyUtil.topology_to_string(topology)}" ) recipe.change_particle_position(v_arp3, pos_arp3)
[docs] @staticmethod def get_random_arp2(topology, with_ATP, with_branch): """ get a random bound arp2 with the given arp3 nucleotide state and with or without a branch attached to the arp2 """ v_arp3s = ReaddyUtil.get_vertices_of_type( topology, "arp3#ATP" if with_ATP else "arp3", True, parameters["verbose"], f"Couldn't find arp3 (ATP={with_ATP})", ) if len(v_arp3s) < 1: return None v_arp2s = [] for v_arp3 in v_arp3s: v_arp2 = ReaddyUtil.get_neighbor_of_types( topology, v_arp3, ["arp2#branched" if with_branch else "arp2"], [] ) if v_arp2 is not None: v_arp2s.append(v_arp2) if len(v_arp2s) < 1: if parameters["verbose"]: print(f"Couldn't find arp2 (branch={with_branch})") return None return random.choice(v_arp2s)
[docs] @staticmethod def check_arp3_attached_to_neighbors( topology, vertex, max_edges, exclude_id=None, last_vertex_id=None ): """ Check if an arp3 is attached to the vertex's neighbors within max_edges """ for neighbor in vertex: n_id = topology.particle_id_of_vertex(neighbor) if n_id == last_vertex_id or n_id == exclude_id: continue pt = topology.particle_type_of_vertex(neighbor) if "arp3" in pt: return True if "actin" not in pt or max_edges <= 1: continue arp3_is_attached_to_neighbors = ActinUtil.check_arp3_attached_to_neighbors( topology, neighbor.get(), max_edges - 1, exclude_id, topology.particle_id_of_vertex(vertex), ) if arp3_is_attached_to_neighbors: return True return False
[docs] @staticmethod def set_actin_mid_flag(topology, recipe, vertex, exclude_id=None): """ if an actin near a reaction is a "mid" actin, add the "mid" flag, otherwise remove it actin is "mid" unless: - it is pointed, barbed, or branch - it is within 2 neighbors from an actin bound to arp3 - it is neighbor of a pointed or branch actin """ pt = topology.particle_type_of_vertex(vertex) if "pointed" in pt or "branch" in pt or "barbed" in pt: return if ( not ActinUtil.check_arp3_attached_to_neighbors( topology, vertex, 3, exclude_id ) and ReaddyUtil.get_neighbor_of_type(topology, vertex, "actin#branch", False) is None and ReaddyUtil.get_neighbor_of_type( topology, vertex, "actin#pointed", False ) is None ): ReaddyUtil.set_flags(topology, recipe, vertex, ["mid"], [""], True) else: ReaddyUtil.set_flags(topology, recipe, vertex, [""], ["mid"], True)
[docs] @staticmethod def get_actins_near_branch(topology, recipe, v_actin_arp2, v_actin_arp3): """ get the 5 mother actins near a branch """ n_pointed = ActinUtil.get_actin_number(topology, v_actin_arp2, -1) pointed_types = [ f"actin#ATP_{n_pointed}", f"actin#{n_pointed}", f"actin#mid_ATP_{n_pointed}", f"actin#mid_{n_pointed}", f"actin#pointed_ATP_{n_pointed}", f"actin#pointed_{n_pointed}", ] if n_pointed == 1: pointed_types += ["actin#branch_1", "actin#branch_ATP_1"] v_actin_pointed = ReaddyUtil.get_neighbor_of_types( topology, v_actin_arp2, pointed_types, [] ) n_barbed = ActinUtil.get_actin_number(topology, v_actin_arp3, 1) barbed_types = [ f"actin#ATP_{n_barbed}", f"actin#{n_barbed}", f"actin#mid_ATP_{n_barbed}", f"actin#mid_{n_barbed}", f"actin#barbed_ATP_{n_barbed}", f"actin#barbed_{n_barbed}", ] v_actin_barbed1 = ReaddyUtil.get_neighbor_of_types( topology, v_actin_arp3, barbed_types, [v_actin_pointed] ) v_actin_barbed2 = None if v_actin_barbed1 is not None: n_barbed = ActinUtil.get_actin_number(topology, v_actin_barbed1, 1) barbed_types = [ f"actin#ATP_{n_barbed}", f"actin#{n_barbed}", f"actin#mid_ATP_{n_barbed}", f"actin#mid_{n_barbed}", f"actin#barbed_ATP_{n_barbed}", f"actin#barbed_{n_barbed}", ] v_actin_barbed2 = ReaddyUtil.get_neighbor_of_types( topology, v_actin_barbed1, barbed_types, [v_actin_arp3] ) return [ v_actin_pointed, v_actin_arp2, v_actin_arp3, v_actin_barbed1, v_actin_barbed2, ]
[docs] @staticmethod def set_actin_mid_flags_at_new_branch(topology, recipe, v_actin_arp2, v_actin_arp3): """ Remove the "mid" flag on all the mother actins near a branch nucleation reaction """ v_branch_actins = ActinUtil.get_actins_near_branch( topology, recipe, v_actin_arp2, v_actin_arp3 ) for v_actin in v_branch_actins: if v_actin is not None: ReaddyUtil.set_flags(topology, recipe, v_actin, [""], ["mid"], True)
[docs] @staticmethod def set_actin_mid_flags_at_removed_branch( topology, recipe, v_actin_arp2, v_actin_arp3, v_arp3 ): """ set the "mid" state on all the actins near a branch dissociation reaction """ v_branch_actins = ActinUtil.get_actins_near_branch( topology, recipe, v_actin_arp2, v_actin_arp3 ) arp3_id = topology.particle_id_of_vertex(v_arp3) for v_actin in v_branch_actins: if v_actin is not None: ActinUtil.set_actin_mid_flag(topology, recipe, v_actin, arp3_id)
[docs] @staticmethod def add_random_linear_fibers(simulation, n_fibers, length=20, use_uuids=True): """ add linear actin fibers of the given length """ positions = ( np.random.uniform(size=(n_fibers, 3)) * parameters["box_size"] - parameters["box_size"] * 0.5 ) print("Adding random fibers at \n" + str(positions)) for fiber in range(n_fibers): direction = ReaddyUtil.get_random_unit_vector() monomers = ActinGenerator.get_monomers( [ FiberData( 0, [ positions[fiber], positions[fiber] + length * direction, ], ), ], use_uuids, ) ActinUtil.add_monomers_from_data(simulation, monomers)
[docs] @staticmethod def add_fibers_from_data(simulation, fibers_data, use_uuids=True): """ add (branched) actin fiber(s) fibers_data : List[FiberData] """ fiber_monomers = ActinGenerator.get_monomers(fibers_data, use_uuids) ActinUtil.add_monomers_from_data(simulation, fiber_monomers)
[docs] @staticmethod def add_monomers_from_data(simulation, monomer_data): """ add actin and other monomers monomer_data : { "topologies": { "[topology ID]" : { "type_name": "[topology type]", "particle_ids": [] }, "particles": { "[particle ID]" : { "type_name": "[particle type]", "position": np.zeros(3), "neighbor_ids": [], }, }, } * IDs are uuid strings or ints """ topologies = [] for topology_id in monomer_data["topologies"]: topology = monomer_data["topologies"][topology_id] types = [] positions = [] for particle_id in topology["particle_ids"]: particle = monomer_data["particles"][particle_id] types.append(particle["type_name"]) positions.append(particle["position"]) top = simulation.add_topology( topology["type_name"], types, np.array(positions) ) added_edges = [] for index, particle_id in enumerate(topology["particle_ids"]): for neighbor_id in monomer_data["particles"][particle_id][ "neighbor_ids" ]: neighbor_index = topology["particle_ids"].index(neighbor_id) if (index, neighbor_index) not in added_edges and ( neighbor_index, index, ) not in added_edges: top.get_graph().add_edge(index, neighbor_index) added_edges.append((index, neighbor_index)) added_edges.append((neighbor_index, index)) topologies.append(top) return topologies
[docs] @staticmethod def add_actin_dimer(position, simulation): """ add an actin dimer fiber """ positions = np.array( [ [0, 0, 0], ActinStructure.actin_to_actin_distance() * ReaddyUtil.get_random_unit_vector(), ] ) types = ["actin#pointed_ATP_1", "actin#barbed_ATP_2"] top = simulation.add_topology("Actin-Dimer", types, position + positions) top.get_graph().add_edge(0, 1)
[docs] @staticmethod def add_actin_dimers(n, simulation): """ add actin dimers """ positions = ( np.random.uniform(size=(n, 3)) * parameters["box_size"] - parameters["box_size"] * 0.5 ) for p in range(len(positions)): ActinUtil.add_actin_dimer(positions[p], simulation)
[docs] @staticmethod def get_box_positions(n_particles, particle_type): """ Get random positions for n particles of the given type either filling the simulation volume box or confined to a sub volume box """ if parameters[f"use_box_{particle_type}"]: center = np.array( [ parameters[f"{particle_type}_box_center_x"], parameters[f"{particle_type}_box_center_y"], parameters[f"{particle_type}_box_center_z"], ] ) size = np.array( [ parameters[f"{particle_type}_box_size_x"], parameters[f"{particle_type}_box_size_y"], parameters[f"{particle_type}_box_size_z"], ] ) result = center + (np.random.uniform(size=(n_particles, 3)) - 0.5) * size else: result = (np.random.uniform(size=(n_particles, 3)) - 0.5) * parameters[ "box_size" ] return result
[docs] @staticmethod def add_actin_monomers(n, simulation): """ add free actin """ positions = ActinUtil.get_box_positions(n, "actin") for p in range(len(positions)): simulation.add_topology( "Actin-Monomer-ATP", ["actin#free_ATP"], np.array([positions[p]]) )
[docs] @staticmethod def add_arp23_dimers(n, simulation): """ add arp2/3 dimers """ positions = ActinUtil.get_box_positions(n, "arp") for p in range(len(positions)): top = simulation.add_topology( "Arp23-Dimer-ATP", ["arp2#free", "arp3#ATP"], np.array( [ positions[p], positions[p] + 4.0 * ReaddyUtil.get_random_unit_vector(), ] ), ) top.get_graph().add_edge(0, 1)
[docs] @staticmethod def add_capping_protein(n, simulation): """ add free capping protein """ positions = ActinUtil.get_box_positions(n, "cap") for p in range(len(positions)): simulation.add_topology("Cap", ["cap"], np.array([positions[p]]))
[docs] @staticmethod def reaction_function_reverse_dimerize(topology): """ reaction function for a dimer falling apart """ recipe = readdy.StructuralReactionRecipe(topology) if parameters["verbose"]: print("Reverse Dimerize") v_barbed = ReaddyUtil.get_first_vertex_of_types( topology, [ "actin#barbed_ATP_1", "actin#barbed_ATP_2", "actin#barbed_ATP_3", "actin#barbed_1", "actin#barbed_2", "actin#barbed_3", ], error_msg="Failed to find barbed end of dimer", ) v_pointed = ReaddyUtil.get_first_neighbor( topology, v_barbed, [], error_msg="Failed to find pointed end of dimer" ) pt_barbed = topology.particle_type_of_vertex(v_barbed) pt_pointed = topology.particle_type_of_vertex(v_pointed) recipe.remove_edge(v_barbed, v_pointed) recipe.change_particle_type( v_barbed, "actin#free" + ("_ATP" if "ATP" in pt_barbed else "") ) recipe.change_particle_type( v_pointed, "actin#free" + ("_ATP" if "ATP" in pt_pointed else "") ) recipe.change_topology_type("Actin-Monomer-ATP") return recipe
[docs] @staticmethod def reaction_function_finish_trimerize(topology): """ reaction function for a trimer forming """ recipe = readdy.StructuralReactionRecipe(topology) if parameters["verbose"]: print("Trimerize") v_new = ActinUtil.get_new_vertex(topology) v_neighbor1 = ReaddyUtil.get_first_neighbor( topology, v_new, [], error_msg="Failed to find first neighbor of new vertex in trimer", ) v_neighbor2 = ReaddyUtil.get_first_neighbor( topology, v_neighbor1, [v_new], error_msg="Failed to find second neighbor of new vertex in trimer", ) ReaddyUtil.set_flags( topology, recipe, v_new, ["barbed", str(ActinUtil.get_actin_number(topology, v_neighbor1, 1))], ["new"], True, ) ActinUtil.set_new_trimer_vertex_position( topology, recipe, v_new, v_neighbor2, v_neighbor1 ) recipe.change_topology_type("Actin-Trimer") return recipe
[docs] @staticmethod def reaction_function_reverse_trimerize(topology): """ reaction function for removing ATP-actin from a trimer """ recipe = readdy.StructuralReactionRecipe(topology) if parameters["verbose"]: print("Reverse Trimerize") v_barbed = ReaddyUtil.get_first_vertex_of_types( topology, [ "actin#barbed_ATP_1", "actin#barbed_ATP_2", "actin#barbed_ATP_3", "actin#barbed_1", "actin#barbed_2", "actin#barbed_3", ], error_msg="Failed to find barbed end in trimer", ) v_neighbor = ReaddyUtil.get_first_neighbor( topology, v_barbed, [], error_msg="Failed to find neighbor of barbed end in trimer", ) recipe.remove_edge(v_barbed, v_neighbor) recipe.change_particle_type(v_barbed, "actin#free_ATP") ReaddyUtil.set_flags(topology, recipe, v_neighbor, ["barbed"], [], True) recipe.change_topology_type("Actin-Polymer#Shrinking") return recipe
[docs] @staticmethod def do_finish_grow(topology, barbed): """ reaction function for the pointed or barbed end growing """ recipe = readdy.StructuralReactionRecipe(topology) end_type = "barbed" if barbed else "pointed" if parameters["verbose"]: print("Grow " + end_type) v_new = ActinUtil.get_new_vertex(topology) v_neighbor = ReaddyUtil.get_first_neighbor( topology, v_new, [], error_msg=f"Failed to find neighbor of new {end_type} end", ) if not barbed: v_neighbor_neighbor = ActinUtil.get_next_actin(topology, v_neighbor, 1) if v_neighbor_neighbor is not None: # previous neighbor of pointed end probably needs "mid" added ActinUtil.set_actin_mid_flag(topology, recipe, v_neighbor_neighbor) ReaddyUtil.set_flags( topology, recipe, v_new, [ end_type, str( ActinUtil.get_actin_number( topology, v_neighbor, 1 if barbed else -1 ) ), ], ["new"], True, ) if not barbed: # neighbor of pointed end should never be "mid" ReaddyUtil.set_flags(topology, recipe, v_neighbor, [""], ["mid"], True) else: # neighbor of barbed end could be "mid" ActinUtil.set_actin_mid_flag(topology, recipe, v_neighbor) ActinUtil.set_end_vertex_position(topology, recipe, v_new, barbed) recipe.change_topology_type("Actin-Polymer") return recipe
[docs] @staticmethod def reaction_function_finish_pointed_grow(topology): """ reaction function for the pointed end growing """ return ActinUtil.do_finish_grow(topology, False)
[docs] @staticmethod def reaction_function_finish_barbed_grow(topology): """ reaction function for the barbed end growing """ return ActinUtil.do_finish_grow(topology, True)
[docs] @staticmethod def reaction_function_finish_arp_bind(topology): """ reaction function to finish a branching reaction (triggered by a spatial reaction) """ recipe = readdy.StructuralReactionRecipe(topology) if parameters["verbose"]: print("Bind Arp2/3") v_arp2, v_arp3 = ActinUtil.get_new_arp23(topology) if v_arp2 is None or v_arp3 is None: raise Exception( f"Failed to find new arp2 and arp3\n" f"{ReaddyUtil.topology_to_string(topology)}" ) v_actin_arp3 = ReaddyUtil.get_first_neighbor( topology, v_arp3, [v_arp2], error_msg="Failed to find new actin_arp3" ) # make sure arp2 binds to the pointed end neighbor of the actin bound to arp3 v_actin_arp2 = ActinUtil.get_next_actin( topology, v_actin_arp3, -1, error_if_not_found=True ) actin_arp2_type = topology.particle_type_of_vertex(v_actin_arp2) if "pointed" in actin_arp2_type or "branch" in actin_arp2_type: raise Exception( "Branch is starting exactly at a pointed end or start of a branch" ) ReaddyUtil.set_flags(topology, recipe, v_arp2, [], ["free"], True) ReaddyUtil.set_flags(topology, recipe, v_arp3, [], ["new"], True) ActinUtil.set_actin_mid_flags_at_new_branch( topology, recipe, v_actin_arp2, v_actin_arp3 ) recipe.add_edge(v_actin_arp2, v_arp2) recipe.change_topology_type("Actin-Polymer") ActinUtil.set_arp23_vertex_position( topology, recipe, v_arp2, v_arp3, v_actin_arp2, v_actin_arp3 ) return recipe
[docs] @staticmethod def reaction_function_finish_start_branch(topology): """ reaction function for adding the first actin to an arp2/3 to start a branch """ recipe = readdy.StructuralReactionRecipe(topology) if parameters["verbose"]: print("Start Branch") v_new = ActinUtil.get_new_vertex(topology) ReaddyUtil.set_flags( topology, recipe, v_new, ["barbed", "1", "branch"], ["new"], True ) recipe.change_topology_type("Actin-Polymer") ActinUtil.set_end_vertex_position(topology, recipe, v_new, True) return recipe
[docs] @staticmethod def do_shrink(topology, barbed, atp): """ remove an (ATP or ADP)-actin from the (barbed or pointed) end """ recipe = readdy.StructuralReactionRecipe(topology) end_state = "Barbed" if barbed else "Pointed" atp_state = "ATP" if atp else "ADP" if parameters["verbose"]: print(f"Shrink {end_state} {atp_state}") end_flag = end_state.lower() atp_flag = "_ATP" if atp else "" end_type = f"actin#{end_flag}{atp_flag}" v_end = ReaddyUtil.get_random_vertex_of_types( topology, ActinUtil.get_all_polymer_actin_types(end_type), parameters["verbose"], "Couldn't find end actin to remove", ) if v_end is None: return recipe v_arp = ReaddyUtil.get_neighbor_of_types( topology, v_end, ["arp3", "arp3#ATP", "arp2", "arp2#branched"], [], parameters["verbose"], "Couldn't remove actin because a branch was attached", ) if v_arp is not None: return recipe v_neighbor = ReaddyUtil.get_neighbor_of_types( topology, v_end, ActinUtil.get_all_polymer_actin_types("actin") + ActinUtil.get_all_polymer_actin_types("actin#ATP") + ActinUtil.get_all_polymer_actin_types("actin#mid") + ActinUtil.get_all_polymer_actin_types("actin#mid_ATP") + ["actin#branch_1", "actin#branch_ATP_1"], [], parameters["verbose"], "Couldn't find plain actin neighbor of actin to remove", ) if v_neighbor is None: return recipe if not barbed: v_arp2 = ReaddyUtil.get_neighbor_of_types( topology, v_neighbor, ["arp2", "arp2#branched"], [], parameters["verbose"], "Couldn't remove actin because a branch " "was attached to its barbed neighbor", ) if v_arp2 is not None: return recipe v_neighbor_neighbor = ActinUtil.get_next_actin(topology, v_neighbor, 1) if v_neighbor_neighbor is not None: ReaddyUtil.set_flags( topology, recipe, v_neighbor_neighbor, [], ["mid"], True, ) recipe.remove_edge(v_end, v_neighbor) recipe.change_particle_type( v_end, "actin#free" if not atp else "actin#free_ATP" ) ReaddyUtil.set_flags( topology, recipe, v_neighbor, ["barbed"] if barbed else ["pointed"], ["mid"], True, ) recipe.change_topology_type("Actin-Polymer#Shrinking") return recipe
[docs] @staticmethod def reaction_function_pointed_shrink_ATP(topology): """ reaction function to remove an ATP-actin from the pointed end """ return ActinUtil.do_shrink(topology, False, True)
[docs] @staticmethod def reaction_function_pointed_shrink_ADP(topology): """ reaction function to remove an ADP-actin from the pointed end """ return ActinUtil.do_shrink(topology, False, False)
[docs] @staticmethod def reaction_function_barbed_shrink_ATP(topology): """ reaction function to remove an ATP-actin from the barbed end """ return ActinUtil.do_shrink(topology, True, True)
[docs] @staticmethod def reaction_function_barbed_shrink_ADP(topology): """ reaction function to remove an ADP-actin from the barbed end """ return ActinUtil.do_shrink(topology, True, False)
[docs] @staticmethod def reaction_function_cleanup_shrink(topology): """ reaction function for finishing a reverse polymerization reaction """ recipe = readdy.StructuralReactionRecipe(topology) if parameters["verbose"]: print("Cleanup Shrink") new_type = "" if len(topology.graph.get_vertices()) < 2: v_cap = ReaddyUtil.get_vertex_of_type(topology, "cap", True) if v_cap is not None: new_type = "Cap" else: v_actin = ReaddyUtil.get_vertex_of_type( topology, "actin", False, error_msg="Failed to find actin to set monomer's ATP state", ) pt_actin = topology.particle_type_of_vertex(v_actin) new_type = "Actin-Monomer" + ("-ATP" if "ATP" in pt_actin else "") elif len(topology.graph.get_vertices()) < 3: v_arp2 = ReaddyUtil.get_vertex_of_type(topology, "arp2#free", True) if v_arp2 is not None: v_arp3 = ReaddyUtil.get_vertex_of_type( topology, "arp3", False, error_msg="Failed to find arp3 to set arp2/3's ATP state", ) pt_arp3 = topology.particle_type_of_vertex(v_arp3) new_type = "Arp23-Dimer" + ("-ATP" if "ATP" in pt_arp3 else "") else: new_type = "Actin-Dimer" elif len(topology.graph.get_vertices()) < 4: new_type = "Actin-Trimer" else: new_type = "Actin-Polymer" if parameters["verbose"]: print(f"cleaned up {new_type}") recipe.change_topology_type(new_type) return recipe
[docs] @staticmethod def reaction_function_hydrolyze_actin(topology): """ reaction function to hydrolyze a filamentous ATP-actin to ADP-actin """ recipe = readdy.StructuralReactionRecipe(topology) if parameters["verbose"]: print("Hydrolyze Actin") v_actin = ReaddyUtil.get_random_vertex_of_types( topology, ActinUtil.get_all_polymer_actin_types("actin#ATP") + ActinUtil.get_all_polymer_actin_types("actin#pointed_ATP") + ActinUtil.get_all_polymer_actin_types("actin#mid_ATP") + ActinUtil.get_all_polymer_actin_types("actin#barbed_ATP") + ["actin#branch_barbed_ATP_1", "actin#branch_ATP_1"], parameters["verbose"], "Couldn't find ATP-actin", ) if v_actin is None: return recipe ReaddyUtil.set_flags(topology, recipe, v_actin, [], ["ATP"], True) return recipe
[docs] @staticmethod def reaction_function_hydrolyze_arp(topology): """ reaction function to hydrolyze a arp2/3 """ recipe = readdy.StructuralReactionRecipe(topology) if parameters["verbose"]: print("Hydrolyze Arp2/3") v_arp3 = ReaddyUtil.get_random_vertex_of_types( topology, ["arp3#ATP"], parameters["verbose"], "Couldn't find ATP-arp3" ) if v_arp3 is None: return recipe ReaddyUtil.set_flags(topology, recipe, v_arp3, [], ["ATP"], True) return recipe
[docs] @staticmethod def reaction_function_nucleotide_exchange_actin(topology): """ reaction function to exchange ATP for ADP in free actin """ recipe = readdy.StructuralReactionRecipe(topology) if parameters["verbose"]: print("Nucleotide Exchange Actin") v_actin = ReaddyUtil.get_vertex_of_type( topology, "actin#free", True, parameters["verbose"], "Couldn't find ADP-actin", ) if v_actin is None: return recipe ReaddyUtil.set_flags(topology, recipe, v_actin, ["ATP"], [], True) return recipe
[docs] @staticmethod def reaction_function_nucleotide_exchange_arp(topology): """ reaction function to exchange ATP for ADP in free Arp2/3 """ recipe = readdy.StructuralReactionRecipe(topology) if parameters["verbose"]: print("Nucleotide Exchange Arp2/3") v_arp3 = ReaddyUtil.get_vertex_of_type( topology, "arp3", True, parameters["verbose"], "Couldn't find ADP-arp3" ) if v_arp3 is None: return recipe ReaddyUtil.set_flags(topology, recipe, v_arp3, ["ATP"], [], True) return recipe
[docs] @staticmethod def do_arp23_unbind(topology, with_ATP): """ dissociate an arp2/3 from a mother filament """ recipe = readdy.StructuralReactionRecipe(topology) state = "ATP" if with_ATP else "ADP" if parameters["verbose"]: print(f"Remove Arp2/3 {state}") v_arp2 = ActinUtil.get_random_arp2(topology, with_ATP, False) if v_arp2 is None: return recipe actin_types = ( ActinUtil.get_all_polymer_actin_types("actin") + ActinUtil.get_all_polymer_actin_types("actin#ATP") + ActinUtil.get_all_polymer_actin_types("actin#pointed") + ActinUtil.get_all_polymer_actin_types("actin#pointed_ATP") + ActinUtil.get_all_polymer_actin_types("actin#mid") + ActinUtil.get_all_polymer_actin_types("actin#mid_ATP") + ActinUtil.get_all_polymer_actin_types("actin#barbed") + ActinUtil.get_all_polymer_actin_types("actin#barbed_ATP") + ["actin#branch_1", "actin#branch_ATP_1"] ) v_actin_arp2 = ReaddyUtil.get_neighbor_of_types( topology, v_arp2, actin_types, [], error_msg="Failed to find actin_arp2" ) v_arp3 = ReaddyUtil.get_neighbor_of_types( topology, v_arp2, ["arp3", "arp3#ATP"], [], error_msg="Failed to find arp3" ) v_actin_arp3 = ReaddyUtil.get_neighbor_of_types( topology, v_arp3, actin_types, [], error_msg="Failed to find actin_arp3" ) recipe.remove_edge(v_arp2, v_actin_arp2) recipe.remove_edge(v_arp3, v_actin_arp3) ActinUtil.set_actin_mid_flags_at_removed_branch( topology, recipe, v_actin_arp2, v_actin_arp3, v_arp3 ) ReaddyUtil.set_flags(topology, recipe, v_arp2, ["free"], []) recipe.change_topology_type("Actin-Polymer#Shrinking") return recipe
[docs] @staticmethod def reaction_function_arp23_unbind_ATP(topology): """ reaction function to dissociate an arp2/3 with ATP from a mother filament """ return ActinUtil.do_arp23_unbind(topology, True)
[docs] @staticmethod def reaction_function_arp23_unbind_ADP(topology): """ reaction function to dissociate an arp2/3 with ADP from a mother filament """ return ActinUtil.do_arp23_unbind(topology, False)
[docs] @staticmethod def do_debranching(topology, with_ATP): """ reaction function to detach a branch filament from arp2/3 """ recipe = readdy.StructuralReactionRecipe(topology) state = "ATP" if with_ATP else "ADP" if parameters["verbose"]: print(f"Debranching {state}") v_arp2 = ActinUtil.get_random_arp2(topology, with_ATP, True) if v_arp2 is None: return recipe actin_types = [ "actin#branch_1", "actin#branch_ATP_1", "actin#branch_barbed_1", "actin#branch_barbed_ATP_1", ] v_actin1 = ReaddyUtil.get_neighbor_of_types( topology, v_arp2, actin_types, [], error_msg="Failed to find first branch actin", ) recipe.remove_edge(v_arp2, v_actin1) ReaddyUtil.set_flags(topology, recipe, v_arp2, [], ["branched"], True) pt_actin1 = topology.particle_type_of_vertex(v_actin1) if "barbed" in pt_actin1: # branch is a monomer state = "_ATP" if "ATP" in pt_actin1 else "" recipe.change_particle_type(v_actin1, f"actin#free{state}") else: # branch is a filament ReaddyUtil.set_flags( topology, recipe, v_actin1, ["pointed"], ["branch"], True ) recipe.change_topology_type("Actin-Polymer#Shrinking") return recipe
[docs] @staticmethod def reaction_function_debranching_ATP(topology): """ reaction function to detach a branch filament from arp2/3 with ATP """ return ActinUtil.do_debranching(topology, True)
[docs] @staticmethod def reaction_function_debranching_ADP(topology): """ reaction function to detach a branch filament from arp2/3 with ADP """ return ActinUtil.do_debranching(topology, False)
[docs] @staticmethod def reaction_function_finish_cap_bind(topology): """ reaction function for adding a capping protein """ recipe = readdy.StructuralReactionRecipe(topology) if parameters["verbose"]: print("Finish Cap Bind") v_new = ActinUtil.get_new_vertex(topology) ReaddyUtil.set_flags(topology, recipe, v_new, ["bound"], ["new"], True) recipe.change_topology_type("Actin-Polymer") return recipe
[docs] @staticmethod def reaction_function_cap_unbind(topology): """ reaction function to detach capping protein from a barbed end """ recipe = readdy.StructuralReactionRecipe(topology) if parameters["verbose"]: print("Remove Cap") v_cap = ReaddyUtil.get_random_vertex_of_types( topology, ["cap#bound"], parameters["verbose"], "Couldn't find cap" ) if v_cap is None: return recipe v_actin = ReaddyUtil.get_neighbor_of_types( topology, v_cap, ActinUtil.get_all_polymer_actin_types("actin") + ActinUtil.get_all_polymer_actin_types("actin#ATP") + ActinUtil.get_all_polymer_actin_types("actin#mid") + ActinUtil.get_all_polymer_actin_types("actin#mid_ATP") + ["actin#branch_1", "actin#branch_ATP_1"], [], error_msg="Failed to find actin bound to cap", ) recipe.remove_edge(v_cap, v_actin) ReaddyUtil.set_flags(topology, recipe, v_cap, [], ["bound"], True) ReaddyUtil.set_flags(topology, recipe, v_actin, ["barbed"], [], True) recipe.change_topology_type("Actin-Polymer#Shrinking") return recipe
[docs] @staticmethod def reaction_function_translate(topology): """ reaction function to translate particles by the displacements """ global time_index recipe = readdy.StructuralReactionRecipe(topology) for vertex_id in displacements: v = ReaddyUtil.get_vertex_with_id( topology, vertex_id, error_msg=f"Couldn't find particle {vertex_id} to displace", ) vertex_pos = ReaddyUtil.get_vertex_position(topology, v) new_pos = displacements[vertex_id]["get_translation"]( time_index, vertex_id, vertex_pos, displacements[vertex_id]["parameters"], ) recipe.change_particle_position(v, new_pos) time_index += 1 return recipe
[docs] @staticmethod def get_all_actin_particle_types(): """ get particle types for actin Actin filaments are polymers and to encode polarity,there are 3 polymer types. These are represented as "actin#N" where N is in [1,3]. At branch points, 2 particles arp2 and arp3 join the pointed end of a branch to the side of its mother filament. Spatially, the types are mapped like so: - end + end actin#pointed_1 actin#3 actin#2 actin#1 actin#barbed_3 \\ // \\ // || \\ // \\ // \\ // \\ // || \\ // \\ // actin#2 actin#1 || actin#3 actin#2 || || || arp3 || // || // arp2#branched \\ \\ actin#branch_1 // // actin#2 \\ \\ actin#barbed_3 + end """ result = [ "actin#free", "actin#free_ATP", "actin#new", "actin#new_ATP", "actin#branch_1", "actin#branch_ATP_1", "actin#branch_barbed_1", "actin#branch_barbed_ATP_1", ] for i in range(1, 4): result += [ f"actin#{i}", f"actin#ATP_{i}", f"actin#mid_{i}", f"actin#mid_ATP_{i}", f"actin#pointed_{i}", f"actin#pointed_ATP_{i}", f"actin#barbed_{i}", f"actin#barbed_ATP_{i}", ] return result
[docs] @staticmethod def get_all_fixed_actin_particle_types(): """ get particle types for actins that don't diffuse """ result = [] for i in range(1, 4): result += [ f"actin#fixed_{i}", f"actin#fixed_ATP_{i}", f"actin#mid_fixed_{i}", f"actin#mid_fixed_ATP_{i}", f"actin#pointed_fixed_{i}", f"actin#pointed_fixed_ATP_{i}", f"actin#fixed_barbed_{i}", f"actin#fixed_barbed_ATP_{i}", ] return result
[docs] @staticmethod def get_all_arp23_particle_types(): """ get particle types for Arp2/3 dimer """ return [ "arp2", "arp2#branched", "arp2#free", "arp3", "arp3#ATP", "arp3#new", "arp3#new_ATP", ]
[docs] @staticmethod def get_all_cap_particle_types(): """ get particle types for capping protein """ return [ "cap", "cap#new", "cap#bound", ]
[docs] @staticmethod def get_all_particle_types(): """ add the given particle_types to the system """ return ( ActinUtil.get_all_actin_particle_types() + ActinUtil.get_all_fixed_actin_particle_types() + ActinUtil.get_all_arp23_particle_types() + ActinUtil.get_all_cap_particle_types() + ["obstacle"] )
[docs] @staticmethod def add_particle_types(particle_types, system, diffCoeff): """ add the given particle_types to the system """ for particle_type in particle_types: system.add_topology_species(particle_type, diffCoeff)
[docs] @staticmethod def add_actin_types(system, diffCoeff): """ add particle and topology types for actin """ system.topologies.add_type("Actin-Monomer-ATP") system.topologies.add_type("Actin-Monomer") system.topologies.add_type("Actin-Dimer") system.topologies.add_type("Actin-Trimer") system.topologies.add_type("Actin-Trimer#Growing") system.topologies.add_type("Actin-Trimer#Shrinking") system.topologies.add_type("Actin-Polymer") system.topologies.add_type("Actin-Polymer#GrowingPointed") system.topologies.add_type("Actin-Polymer#GrowingBarbed") system.topologies.add_type("Actin-Polymer#Shrinking") system.topologies.add_type("Actin-Polymer#Branching") system.topologies.add_type("Actin-Polymer#Branch-Nucleating") system.topologies.add_type("Actin-Polymer#Capping") ActinUtil.add_particle_types( ActinUtil.get_all_actin_particle_types(), system, diffCoeff ) ActinUtil.add_particle_types( ActinUtil.get_all_fixed_actin_particle_types(), system, 0.0 )
[docs] @staticmethod def add_arp23_types(system, diffCoeff): """ add particle and topology types for Arp2/3 dimer """ system.topologies.add_type("Arp23-Dimer-ATP") system.topologies.add_type("Arp23-Dimer") ActinUtil.add_particle_types( ActinUtil.get_all_arp23_particle_types(), system, diffCoeff )
[docs] @staticmethod def add_cap_types(system, diffCoeff): """ add particle and topology types for capping protein """ system.topologies.add_type("Cap") ActinUtil.add_particle_types( ActinUtil.get_all_cap_particle_types(), system, diffCoeff )
[docs] @staticmethod def add_bonds_between_actins(force_constant, system, util): """ add bonds between actins """ bond_length = ActinStructure.actin_to_actin_distance() util.add_polymer_bond_1D( [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", ], 0, [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#barbed_", "actin#barbed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", "actin#fixed_barbed_", "actin#fixed_barbed_ATP_", ], 1, force_constant, bond_length, system, ) util.add_bond( [ "actin#branch_1", "actin#branch_ATP_1", ], [ "actin#2", "actin#ATP_2", "actin#mid_2", "actin#mid_ATP_2", "actin#barbed_2", "actin#barbed_ATP_2", "actin#fixed_2", "actin#fixed_ATP_2", "actin#mid_fixed_2", "actin#mid_fixed_ATP_2", "actin#fixed_barbed_2", "actin#fixed_barbed_ATP_2", ], force_constant, bond_length, system, ) util.add_polymer_bond_1D( # temporary during growth reactions [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#barbed_", "actin#barbed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", "actin#fixed_barbed_", "actin#fixed_barbed_ATP_", ], 0, [ "actin#new", "actin#new_ATP", ], None, force_constant, bond_length, system, ) util.add_bond( # temporary during growth reactions [ "actin#branch_1", "actin#branch_ATP_1", "actin#branch_barbed_1", "actin#branch_barbed_ATP_1", "arp3#ATP", ], [ "actin#new", "actin#new_ATP", ], force_constant, bond_length, system, )
[docs] @staticmethod def add_filament_twist_angles(force_constant, system, util): """ add angles for filament twist and cohesiveness """ angle = ActinStructure.actin_to_actin_angle() util.add_polymer_angle_1D( [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", ], -1, [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", ], 0, [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#barbed_", "actin#barbed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", "actin#fixed_barbed_", "actin#fixed_barbed_ATP_", ], 1, force_constant, angle, system, ) util.add_angle( [ "actin#branch_1", "actin#branch_ATP_1", ], [ "actin#2", "actin#ATP_2", "actin#fixed_2", "actin#fixed_ATP_2", ], [ "actin#3", "actin#ATP_3", "actin#mid_3", "actin#mid_ATP_3", "actin#barbed_3", "actin#barbed_ATP_3", "actin#fixed_3", "actin#fixed_ATP_3", "actin#mid_fixed_3", "actin#mid_fixed_ATP_3", "actin#fixed_barbed_3", "actin#fixed_barbed_ATP_3", ], force_constant, angle, system, )
[docs] @staticmethod def add_filament_twist_dihedrals(force_constant, system, util): """ add dihedrals for filament twist and cohesiveness """ angle = ActinStructure.actin_to_actin_dihedral_angle() util.add_polymer_dihedral_1D( [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", ], -1, [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", ], 0, [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", ], 1, [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#barbed_", "actin#barbed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", "actin#fixed_barbed_", "actin#fixed_barbed_ATP_", ], 2, force_constant, angle, system, ) util.add_dihedral( [ "actin#branch_1", "actin#branch_ATP_1", ], [ "actin#2", "actin#ATP_2", "actin#mid_2", "actin#mid_ATP_2", "actin#fixed_2", "actin#fixed_ATP_2", "actin#mid_fixed_2", "actin#mid_fixed_ATP_2", ], [ "actin#3", "actin#ATP_3", "actin#mid_3", "actin#mid_ATP_3", "actin#fixed_3", "actin#fixed_ATP_3", "actin#mid_fixed_3", "actin#mid_fixed_ATP_3", ], [ "actin#1", "actin#ATP_1", "actin#mid_1", "actin#mid_ATP_1", "actin#barbed_1", "actin#barbed_ATP_1", "actin#fixed_1", "actin#fixed_ATP_1", "actin#mid_fixed_1", "actin#mid_fixed_ATP_1", "actin#fixed_barbed_1", "actin#fixed_barbed_ATP_1", ], force_constant, angle, system, )
[docs] @staticmethod def add_branch_bonds(force_constant, system, util): """ add bonds between arp2, arp3, and actins """ util.add_polymer_bond_1D( # mother filament actin to arp2 bonds [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", ], 0, [ "arp2", "arp2#branched", "arp2#free", ], None, force_constant, ActinStructure.arp2_to_mother_distance(), system, ) util.add_polymer_bond_1D( # mother filament actin to arp3 bonds [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#barbed_", "actin#barbed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", "actin#fixed_barbed_", "actin#fixed_barbed_ATP_", ], 0, [ "arp3", "arp3#ATP", "arp3#new", "arp3#new_ATP", ], None, force_constant, ActinStructure.arp3_to_mother_distance(), system, ) util.add_bond( # arp2 to arp3 bonds [ "arp2", "arp2#branched", "arp2#free", ], [ "arp3", "arp3#ATP", "arp3#new", "arp3#new_ATP", ], force_constant, ActinStructure.arp2_to_arp3_distance(), system, ) util.add_bond( # arp2 to daughter filament actin bonds ["arp2#branched"], [ "actin#branch_1", "actin#branch_ATP_1", "actin#branch_barbed_1", "actin#branch_barbed_ATP_1", "actin#new", "actin#new_ATP", ], force_constant, ActinStructure.arp2_to_daughter_distance(), system, )
[docs] @staticmethod def add_branch_angles(force_constant, system, util): """ add angles for branching """ util.add_angle( ["arp3", "arp3#ATP"], ["arp2#branched"], [ "actin#branch_1", "actin#branch_ATP_1", "actin#branch_barbed_1", "actin#branch_barbed_ATP_1", ], force_constant, ActinStructure.arp3_arp2_daughter1_angle(), system, ) util.add_angle( ["arp2", "arp2#branched"], [ "actin#branch_1", "actin#branch_ATP_1", "actin#branch_barbed_1", "actin#branch_barbed_ATP_1", ], [ "actin#2", "actin#ATP_2", "actin#barbed_2", "actin#barbed_ATP_2", "actin#fixed_2", "actin#fixed_ATP_2", "actin#fixed_barbed_2", "actin#fixed_barbed_ATP_2", ], force_constant, ActinStructure.arp2_daughter1_daughter2_angle(), system, ) util.add_polymer_angle_1D( [ "actin#", "actin#ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", ], 0, [ "actin#", "actin#ATP_", "actin#fixed_", "actin#fixed_ATP_", ], 1, ["arp3", "arp3#ATP"], None, force_constant, ActinStructure.mother1_mother2_arp3_angle(), system, ) util.add_polymer_angle_1D( [ "actin#", "actin#ATP_", "actin#barbed_", "actin#barbed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#fixed_barbed_", "actin#fixed_barbed_ATP_", ], 1, [ "actin#", "actin#ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", ], 0, ["arp3", "arp3#ATP"], None, force_constant, ActinStructure.mother3_mother2_arp3_angle(), system, ) angle = ActinStructure.mother0_mother1_arp2_angle() util.add_polymer_angle_1D( [ "actin#", "actin#ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", ], 0, [ "actin#", "actin#ATP_", "actin#fixed_", "actin#fixed_ATP_", ], 1, ["arp2", "arp2#branched"], None, force_constant, angle, system, ) util.add_angle( ["actin#branch_1", "actin#branch_ATP_1"], ["actin#2", "actin#ATP_2", "actin#fixed_2", "actin#fixed_ATP_2"], ["arp2", "arp2#branched"], force_constant, angle, system, )
[docs] @staticmethod def add_branch_dihedrals(force_constant, system, util): """ add dihedrals for branching """ # mother to arp angle = ActinStructure.mother4_mother3_mother2_arp3_dihedral_angle() util.add_polymer_dihedral_1D( [ "actin#", "actin#ATP_", "actin#barbed_", "actin#barbed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#fixed_barbed_", "actin#fixed_barbed_ATP_", ], 1, ["actin#", "actin#ATP_", "actin#fixed_", "actin#fixed_ATP_"], 0, ["actin#", "actin#ATP_", "actin#fixed_", "actin#fixed_ATP_"], -1, ["arp3", "arp3#ATP"], None, force_constant, angle, system, ) angle = ActinStructure.mother_mother0_mother1_arp2_dihedral_angle() util.add_polymer_dihedral_1D( [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", ], -1, ["actin#", "actin#ATP_", "actin#fixed_", "actin#fixed_ATP_"], 0, ["actin#", "actin#ATP_", "actin#fixed_", "actin#fixed_ATP_"], 1, ["arp2", "arp2#branched"], None, force_constant, angle, system, ) util.add_dihedral( ["actin#branch_1", "actin#branch_ATP_1"], ["actin#2", "actin#ATP_2", "actin#fixed_2", "actin#fixed_ATP_2"], ["actin#3", "actin#ATP_3", "actin#fixed_3", "actin#fixed_ATP_3"], ["arp2", "arp2#branched"], force_constant, angle, system, ) util.add_polymer_dihedral_1D( [ "actin#", "actin#ATP_", "actin#barbed_", "actin#barbed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#fixed_barbed_", "actin#fixed_barbed_ATP_", ], 1, ["actin#", "actin#ATP_", "actin#fixed_", "actin#fixed_ATP_"], 0, ["arp3", "arp3#ATP"], None, ["arp2#branched", "arp2"], None, force_constant, ActinStructure.mother3_mother2_arp3_arp2_dihedral_angle(), system, ) # arp ring angle = ActinStructure.mother1_mother2_arp3_arp2_dihedral_angle() util.add_polymer_dihedral_1D( [ "actin#", "actin#ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", ], 0, ["actin#", "actin#ATP_", "actin#fixed_", "actin#fixed_ATP_"], 1, ["arp3", "arp3#ATP"], None, ["arp2", "arp2#branched"], None, force_constant, angle, system, ) util.add_dihedral( ["actin#branch_1", "actin#branch_ATP_1"], ["actin#2", "actin#ATP_2", "actin#fixed_2", "actin#fixed_ATP_2"], ["arp3", "arp3#ATP"], ["arp2", "arp2#branched"], force_constant, angle, system, ) angle = ActinStructure.arp2_mother1_mother2_arp3_dihedral_angle() util.add_polymer_dihedral_1D( ["arp2", "arp2#branched"], None, [ "actin#", "actin#ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", ], 0, [ "actin#", "actin#ATP_", "actin#barbed_", "actin#barbed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#fixed_barbed_", "actin#fixed_barbed_ATP_", ], 1, ["arp3", "arp3#ATP"], None, force_constant, angle, system, ) util.add_dihedral( ["arp2", "arp2#branched"], ["actin#branch_1", "actin#branch_ATP_1"], [ "actin#2", "actin#ATP_2", "actin#barbed_2", "actin#barbed_ATP_2", "actin#fixed_2", "actin#fixed_ATP_2", "actin#fixed_barbed_2", "actin#fixed_barbed_ATP_2", ], ["arp3", "arp3#ATP"], force_constant, angle, system, ) # arp to daughter util.add_dihedral( ["arp3", "arp3#ATP"], ["arp2#branched"], ["actin#branch_1", "actin#branch_ATP_1"], [ "actin#2", "actin#ATP_2", "actin#barbed_2", "actin#barbed_ATP_2", "actin#fixed_2", "actin#fixed_ATP_2", "actin#fixed_barbed_2", "actin#fixed_barbed_ATP_2", ], force_constant, ActinStructure.arp3_arp2_daughter1_daughter2_dihedral_angle(), system, ) util.add_dihedral( ["arp2#branched"], ["actin#branch_1", "actin#branch_ATP_1"], [ "actin#2", "actin#ATP_2", "actin#barbed_2", "actin#barbed_ATP_2", "actin#fixed_2", "actin#fixed_ATP_2", "actin#fixed_barbed_2", "actin#fixed_barbed_ATP_2", ], [ "actin#3", "actin#ATP_3", "actin#mid_3", "actin#mid_ATP_3", "actin#barbed_3", "actin#barbed_ATP_3", "actin#fixed_3", "actin#fixed_ATP_3", "actin#mid_fixed_3", "actin#mid_fixed_ATP_3", "actin#fixed_barbed_3", "actin#fixed_barbed_ATP_3", ], force_constant, ActinStructure.arp2_daughter1_daughter2_daughter3_dihedral_angle(), system, ) # mother to daughter angle = ActinStructure.mother0_mother1_arp2_daughter1_dihedral_angle() util.add_polymer_dihedral_1D( [ "actin#", "actin#ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", ], -1, ["actin#", "actin#ATP_", "actin#fixed_", "actin#fixed_ATP_"], 0, ["arp2#branched"], None, [ "actin#branch_1", "actin#branch_ATP_1", "actin#branch_barbed_1", "actin#branch_barbed_ATP_1", ], None, force_constant, angle, system, ) util.add_dihedral( ["actin#branch_1", "actin#branch_ATP_1"], ["actin#2", "actin#ATP_2", "actin#fixed_2", "actin#fixed_ATP_2"], ["arp2#branched"], [ "actin#branch_1", "actin#branch_ATP_1", "actin#branch_barbed_1", "actin#branch_barbed_ATP_1", ], force_constant, angle, system, ) util.add_polymer_dihedral_1D( [ "actin#", "actin#ATP_", "actin#barbed_", "actin#barbed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#fixed_barbed_", "actin#fixed_barbed_ATP_", ], 0, ["arp3", "arp3#ATP"], None, ["arp2#branched"], None, [ "actin#branch_1", "actin#branch_ATP_1", "actin#branch_barbed_1", "actin#branch_barbed_ATP_1", ], None, force_constant, ActinStructure.mother2_arp3_arp2_daughter1_dihedral_angle(), system, ) util.add_dihedral( [ "actin#1", "actin#ATP_1", "actin#pointed_1", "actin#pointed_ATP_1", "actin#fixed_1", "actin#fixed_ATP_1", "actin#pointed_fixed_1", "actin#pointed_fixed_ATP_1", "actin#branch_1", "actin#branch_ATP_1", "actin#2", "actin#ATP_2", "actin#pointed_2", "actin#pointed_ATP_2", "actin#fixed_2", "actin#fixed_ATP_2", "actin#pointed_fixed_2", "actin#pointed_fixed_ATP_2", "actin#3", "actin#ATP_3", "actin#pointed_3", "actin#pointed_ATP_3", "actin#fixed_3", "actin#fixed_ATP_3", "actin#pointed_fixed_3", "actin#pointed_fixed_ATP_3", ], ["arp2#branched"], ["actin#branch_1", "actin#branch_ATP_1"], [ "actin#2", "actin#ATP_2", "actin#barbed_2", "actin#barbed_ATP_2", "actin#fixed_2", "actin#fixed_ATP_2", "actin#fixed_barbed_2", "actin#fixed_barbed_ATP_2", ], force_constant, ActinStructure.mother1_arp2_daughter1_daughter2_dihedral_angle(), system, )
[docs] @staticmethod def add_cap_bonds(force_constant, system, util): """ add capping protein to actin bonds """ util.add_polymer_bond_1D( ["actin#", "actin#ATP_", "actin#fixed_", "actin#fixed_ATP_"], 0, ["cap#bound", "cap#new"], None, force_constant, ActinStructure.actin_to_actin_distance() + 1.0, system, )
[docs] @staticmethod def add_cap_angles(force_constant, system, util): """ add angles for capping protein """ angle = ActinStructure.actin_to_actin_angle() util.add_polymer_angle_1D( [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", ], 0, [ "actin#", "actin#ATP_", "actin#mid_", "actin#mid_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#mid_fixed_", "actin#mid_fixed_ATP_", ], 1, ["cap#bound"], None, force_constant, angle, system, ) util.add_angle( ["actin#branch_1", "actin#branch_ATP_1"], ["actin#2", "actin#ATP_2", "actin#fixed_2", "actin#fixed_ATP_2"], ["cap#bound"], force_constant, angle, system, )
[docs] @staticmethod def add_cap_dihedrals(force_constant, system, util): """ add dihedrals for capping protein """ angle = ActinStructure.actin_to_actin_dihedral_angle() util.add_polymer_dihedral_1D( [ "actin#", "actin#ATP_", "actin#pointed_", "actin#pointed_ATP_", "actin#fixed_", "actin#fixed_ATP_", "actin#pointed_fixed_", "actin#pointed_fixed_ATP_", ], -1, ["actin#", "actin#ATP_", "actin#fixed_", "actin#fixed_ATP_"], 0, ["actin#", "actin#ATP_", "actin#fixed_", "actin#fixed_ATP_"], 1, ["cap#bound"], None, force_constant, angle, system, ) util.add_dihedral( ["actin#branch_1", "actin#branch_ATP_1"], ["actin#2", "actin#ATP_2", "actin#fixed_2", "actin#fixed_ATP_2"], ["actin#3", "actin#ATP_3", "actin#fixed_3", "actin#fixed_ATP_3"], ["cap#bound"], force_constant, angle, system, ) util.add_dihedral( ["arp3", "arp3#ATP"], ["arp2#branched"], ["actin#branch_1", "actin#branch_ATP_1"], ["cap#bound"], force_constant, ActinStructure.arp3_arp2_daughter1_daughter2_dihedral_angle(), system, )
[docs] @staticmethod def add_repulsions( actin_radius, arp23_radius, cap_radius, obstacle_radius, force_constant, system, util, ): """ add repulsions """ actin_types = ( ActinUtil.get_all_actin_particle_types() + ActinUtil.get_all_fixed_actin_particle_types() ) arp_types = ActinUtil.get_all_arp23_particle_types() cap_types = ActinUtil.get_all_cap_particle_types() # actin util.add_repulsion( actin_types, actin_types, force_constant, ActinStructure.actin_to_actin_repulsion_distance(), system, ) util.add_repulsion( actin_types, ["obstacle"], force_constant, actin_radius + obstacle_radius, system, ) # arp2/3 util.add_repulsion( arp_types, arp_types, force_constant, 2.0 * arp23_radius, system, ) util.add_repulsion( arp_types, actin_types, force_constant, arp23_radius + actin_radius, system, ) util.add_repulsion( arp_types, ["obstacle"], force_constant, arp23_radius + obstacle_radius, system, ) # capping protein util.add_repulsion( cap_types, cap_types, force_constant, 2.0 * cap_radius, system, ) util.add_repulsion( cap_types, actin_types, force_constant, cap_radius + actin_radius, system, ) util.add_repulsion( cap_types, arp_types, force_constant, cap_radius + arp23_radius, system, ) util.add_repulsion( cap_types, ["obstacle"], force_constant, cap_radius + obstacle_radius, system, )
[docs] @staticmethod def add_box_potential(particle_types, origin, extent, force_constant, system): """ add a box potential to keep the given particle types inside a box centered at origin with extent """ for particle_type in particle_types: system.potentials.add_box( particle_type=particle_type, force_constant=force_constant, origin=origin, extent=extent, )
[docs] @staticmethod def check_add_global_box_potential(system): """ If the boundaries are not periodic, all particles need a box potential to keep them in the box volume """ if bool(parameters["periodic_boundary"]): return # 1.0 margin on each side box_potential_size = np.array(parameters["box_size"] - 2.0) ActinUtil.add_box_potential( particle_types=ActinUtil.get_all_particle_types(), origin=-0.5 * box_potential_size, extent=box_potential_size, force_constant=parameters["force_constant"], system=system, )
[docs] @staticmethod def add_monomer_box_potentials(system): """ Confine free monomers to boxes centered at origin with extent """ particle_types = { "actin": ["actin#free", "actin#free_ATP"], "arp": ["arp2#free"], "cap": ["cap"], } for particle_type in particle_types: if not parameters[f"use_box_{particle_type}"]: continue print(f"Adding box for {particle_type}") center = np.array( [ parameters[f"{particle_type}_box_center_x"], parameters[f"{particle_type}_box_center_y"], parameters[f"{particle_type}_box_center_z"], ] ) size = np.array( [ parameters[f"{particle_type}_box_size_x"], parameters[f"{particle_type}_box_size_y"], parameters[f"{particle_type}_box_size_z"], ] ) ActinUtil.add_box_potential( particle_types[particle_type], center - 0.5 * size, size, parameters["force_constant"], system, )
[docs] @staticmethod def add_dimerize_reaction(system): """ attach two monomers """ system.topologies.add_spatial_reaction( "Dimerize: " "Actin-Monomer-ATP(actin#free_ATP) + Actin-Monomer-ATP(actin#free_ATP) -> " "Actin-Dimer(actin#pointed_ATP_1--actin#barbed_ATP_2)", rate=parameters["dimerize_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], )
[docs] @staticmethod def add_dimerize_reverse_reaction(system): """ detach two monomers """ system.topologies.add_structural_reaction( "Reverse_Dimerize", topology_type="Actin-Dimer", reaction_function=ActinUtil.reaction_function_reverse_dimerize, rate_function=lambda x: parameters["dimerize_reverse_rate"], )
[docs] @staticmethod def add_trimerize_reaction(system): """ attach a monomer to a dimer """ for i in range(1, 4): system.topologies.add_spatial_reaction( f"Trimerize{i}: " f"Actin-Dimer(actin#barbed_ATP_{i}) + " "Actin-Monomer-ATP(actin#free_ATP) -> " f"Actin-Trimer#Growing(actin#ATP_{i}--actin#new_ATP)", rate=parameters["trimerize_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_structural_reaction( "Finish_Trimerize", topology_type="Actin-Trimer#Growing", reaction_function=ActinUtil.reaction_function_finish_trimerize, rate_function=ReaddyUtil.rate_function_infinity, )
[docs] @staticmethod def add_trimerize_reverse_reaction(system): """ detach a monomer from a dimer """ system.topologies.add_structural_reaction( "Reverse_Trimerize", topology_type="Actin-Trimer", reaction_function=ActinUtil.reaction_function_reverse_trimerize, rate_function=lambda x: parameters["trimerize_reverse_rate"], )
[docs] @staticmethod def add_nucleate_reaction(system): """ reversibly attach a monomer to a trimer """ for i in range(1, 4): system.topologies.add_spatial_reaction( f"Barbed_Growth_Nucleate_ATP{i}: " f"Actin-Trimer(actin#barbed_ATP_{i}) + " "Actin-Monomer-ATP(actin#free_ATP) " f"-> Actin-Polymer#GrowingBarbed(actin#ATP_{i}--actin#new_ATP)", rate=parameters["nucleate_ATP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( f"Barbed_Growth_Nucleate_ADP{i}: " f"Actin-Trimer(actin#barbed_ATP_{i}) + Actin-Monomer(actin#free) -> " f"Actin-Polymer#GrowingBarbed(actin#ATP_{i}--actin#new)", rate=parameters["nucleate_ADP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], )
[docs] @staticmethod def add_pointed_growth_reaction(system): """ attach a monomer to the pointed end of a filament """ for i in range(1, 4): system.topologies.add_spatial_reaction( f"Pointed_Growth_ATP1{i}: Actin-Polymer(actin#pointed_{i}) + " "Actin-Monomer-ATP(actin#free_ATP) -> " f"Actin-Polymer#GrowingPointed(actin#{i}--actin#new_ATP)", rate=parameters["pointed_growth_ATP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( f"Pointed_Growth_ATP2{i}: Actin-Polymer(actin#pointed_ATP_{i}) + " "Actin-Monomer-ATP(actin#free_ATP) -> " f"Actin-Polymer#GrowingPointed(actin#ATP_{i}--actin#new_ATP)", rate=parameters["pointed_growth_ATP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( f"Pointed_Growth_ADP1{i}: Actin-Polymer(actin#pointed_{i}) + " "Actin-Monomer(actin#free) -> " f"Actin-Polymer#GrowingPointed(actin#{i}--actin#new)", rate=parameters["pointed_growth_ADP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( f"Pointed_Growth_ADP2{i}: Actin-Polymer(actin#pointed_ATP_{i}) + " "Actin-Monomer(actin#free) -> " f"Actin-Polymer#GrowingPointed(actin#ATP_{i}--actin#new)", rate=parameters["pointed_growth_ADP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_structural_reaction( "Finish_Pointed_Growth", topology_type="Actin-Polymer#GrowingPointed", reaction_function=ActinUtil.reaction_function_finish_pointed_grow, rate_function=ReaddyUtil.rate_function_infinity, )
[docs] @staticmethod def add_pointed_shrink_reaction(system): """ remove a monomer from the pointed end of a filament """ system.topologies.add_structural_reaction( "Pointed_Shrink_ATP", topology_type="Actin-Polymer", reaction_function=ActinUtil.reaction_function_pointed_shrink_ATP, rate_function=lambda x: parameters["pointed_shrink_ATP_rate"], ) system.topologies.add_structural_reaction( "Pointed_Shrink_ADP", topology_type="Actin-Polymer", reaction_function=ActinUtil.reaction_function_pointed_shrink_ADP, rate_function=lambda x: parameters["pointed_shrink_ADP_rate"], ) system.topologies.add_structural_reaction( "Cleanup_Shrink", topology_type="Actin-Polymer#Shrinking", reaction_function=ActinUtil.reaction_function_cleanup_shrink, rate_function=ReaddyUtil.rate_function_infinity, )
[docs] @staticmethod def add_barbed_growth_reaction(system): """ attach a monomer to the barbed end of a filament """ for i in range(1, 4): system.topologies.add_spatial_reaction( f"Barbed_Growth_ATP1{i}: Actin-Polymer(actin#barbed_{i}) + " "Actin-Monomer-ATP(actin#free_ATP) -> " f"Actin-Polymer#GrowingBarbed(actin#{i}--actin#new_ATP)", rate=parameters["barbed_growth_ATP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( f"Barbed_Growth_ATP2{i}: Actin-Polymer(actin#barbed_ATP_{i}) + " "Actin-Monomer-ATP(actin#free_ATP) -> " f"Actin-Polymer#GrowingBarbed(actin#ATP_{i}--actin#new_ATP)", rate=parameters["barbed_growth_ATP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( f"Barbed_Growth_ADP1{i}: Actin-Polymer(actin#barbed_{i}) + " "Actin-Monomer(actin#free) -> " f"Actin-Polymer#GrowingBarbed(actin#{i}--actin#new)", rate=parameters["barbed_growth_ADP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( f"Barbed_Growth_ADP2{i}: Actin-Polymer(actin#barbed_ATP_{i}) + " "Actin-Monomer(actin#free) -> " f"Actin-Polymer#GrowingBarbed(actin#ATP_{i}--actin#new)", rate=parameters["barbed_growth_ADP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( "Branch_Barbed_Growth_ATP1: Actin-Polymer(actin#branch_barbed_1) + " "Actin-Monomer-ATP(actin#free_ATP) -> " "Actin-Polymer#GrowingBarbed(actin#branch_1--actin#new_ATP)", rate=parameters["barbed_growth_ATP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( "Branch_Barbed_Growth_ATP2: Actin-Polymer(actin#branch_barbed_ATP_1) + " "Actin-Monomer-ATP(actin#free_ATP) -> " "Actin-Polymer#GrowingBarbed(actin#branch_ATP_1--actin#new_ATP)", rate=parameters["barbed_growth_ATP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( "Branch_Barbed_Growth_ADP1: Actin-Polymer(actin#branch_barbed_1) + " "Actin-Monomer(actin#free) -> " "Actin-Polymer#GrowingBarbed(actin#branch_1--actin#new)", rate=parameters["barbed_growth_ADP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( "Branch_Barbed_Growth_ADP2: Actin-Polymer(actin#branch_barbed_ATP_1) + " "Actin-Monomer(actin#free) -> " "Actin-Polymer#GrowingBarbed(actin#branch_ATP_1--actin#new)", rate=parameters["barbed_growth_ADP_rate"], radius=2 * parameters["actin_radius"] + parameters["reaction_distance"], ) system.topologies.add_structural_reaction( "Finish_Barbed_growth", topology_type="Actin-Polymer#GrowingBarbed", reaction_function=ActinUtil.reaction_function_finish_barbed_grow, rate_function=ReaddyUtil.rate_function_infinity, )
[docs] @staticmethod def add_barbed_shrink_reaction(system): """ remove a monomer from the barbed end of a filament """ system.topologies.add_structural_reaction( "Barbed_Shrink_ATP", topology_type="Actin-Polymer", reaction_function=ActinUtil.reaction_function_barbed_shrink_ATP, rate_function=lambda x: parameters["barbed_shrink_ATP_rate"], ) system.topologies.add_structural_reaction( "Barbed_Shrink_ADP", topology_type="Actin-Polymer", reaction_function=ActinUtil.reaction_function_barbed_shrink_ADP, rate_function=lambda x: parameters["barbed_shrink_ADP_rate"], )
[docs] @staticmethod def add_hydrolyze_reaction(system): """ hydrolyze ATP """ system.topologies.add_structural_reaction( "Hydrolysis_Actin", topology_type="Actin-Polymer", reaction_function=ActinUtil.reaction_function_hydrolyze_actin, rate_function=lambda x: parameters["hydrolysis_actin_rate"], ) system.topologies.add_structural_reaction( "Hydrolysis_Arp", topology_type="Actin-Polymer", reaction_function=ActinUtil.reaction_function_hydrolyze_arp, rate_function=lambda x: parameters["hydrolysis_arp_rate"], )
[docs] @staticmethod def add_actin_nucleotide_exchange_reaction(system): """ exchange ATP for ADP in free actin monomers """ system.topologies.add_structural_reaction( "Nucleotide_Exchange_Actin", topology_type="Actin-Monomer", reaction_function=ActinUtil.reaction_function_nucleotide_exchange_actin, rate_function=lambda x: parameters["nucleotide_exchange_actin_rate"], )
[docs] @staticmethod def add_arp23_nucleotide_exchange_reaction(system): """ exchange ATP for ADP in free Arp2/3 dimers """ system.topologies.add_structural_reaction( "Nucleotide_Exchange_Arp", topology_type="Arp23-Dimer", reaction_function=ActinUtil.reaction_function_nucleotide_exchange_arp, rate_function=lambda x: parameters["nucleotide_exchange_arp_rate"], )
[docs] @staticmethod def add_arp23_bind_reaction(system): """ add arp2/3 along filament to start a branch """ for i in range(1, 4): system.topologies.add_spatial_reaction( f"Arp_Bind_ATP1{i}: " f"Actin-Polymer(actin#mid_ATP_{i}) + Arp23-Dimer(arp3) -> " f"Actin-Polymer#Branching(actin#ATP_{i}--arp3#new)", rate=parameters["arp_bind_ATP_rate"], radius=parameters["actin_radius"] + parameters["arp23_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( f"Arp_Bind_ATP2{i}: " f"Actin-Polymer(actin#mid_ATP_{i}) + Arp23-Dimer-ATP(arp3#ATP) -> " f"Actin-Polymer#Branching(actin#ATP_{i}--arp3#new_ATP)", rate=parameters["arp_bind_ATP_rate"], radius=parameters["actin_radius"] + parameters["arp23_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( f"Arp_Bind_ADP1{i}: " f"Actin-Polymer(actin#mid_{i}) + Arp23-Dimer(arp3) -> " f"Actin-Polymer#Branching(actin#{i}--arp3#new)", rate=parameters["arp_bind_ADP_rate"], radius=parameters["actin_radius"] + parameters["arp23_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( f"Arp_Bind_ADP2{i}: " f"Actin-Polymer(actin#mid_{i}) + Arp23-Dimer-ATP(arp3#ATP) -> " f"Actin-Polymer#Branching(actin#{i}--arp3#new_ATP)", rate=parameters["arp_bind_ADP_rate"], radius=parameters["actin_radius"] + parameters["arp23_radius"] + parameters["reaction_distance"], ) system.topologies.add_structural_reaction( "Finish_Arp_Bind", topology_type="Actin-Polymer#Branching", reaction_function=ActinUtil.reaction_function_finish_arp_bind, rate_function=ReaddyUtil.rate_function_infinity, )
[docs] @staticmethod def add_arp23_unbind_reaction(system): """ remove an arp2/3 that is not nucleated """ system.topologies.add_structural_reaction( "Arp_Unbind_ATP", topology_type="Actin-Polymer", reaction_function=ActinUtil.reaction_function_arp23_unbind_ATP, rate_function=lambda x: parameters["arp_unbind_ATP_rate"], ) system.topologies.add_structural_reaction( "Arp_Unbind_ADP", topology_type="Actin-Polymer", reaction_function=ActinUtil.reaction_function_arp23_unbind_ADP, rate_function=lambda x: parameters["arp_unbind_ADP_rate"], )
[docs] @staticmethod def add_nucleate_branch_reaction(system): """ add actin to arp2/3 to begin a branch """ system.topologies.add_spatial_reaction( "Barbed_Growth_Branch_ATP: " "Actin-Polymer(arp2) + Actin-Monomer-ATP(actin#free_ATP) -> " "Actin-Polymer#Branch-Nucleating(arp2#branched--actin#new_ATP)", rate=parameters["barbed_growth_branch_ATP_rate"], radius=parameters["actin_radius"] + parameters["arp23_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( "Barbed_Growth_Branch_ADP: " "Actin-Polymer(arp2) + Actin-Monomer(actin#free) -> " "Actin-Polymer#Branch-Nucleating(arp2#branched--actin#new)", rate=parameters["barbed_growth_branch_ADP_rate"], radius=parameters["actin_radius"] + parameters["arp23_radius"] + parameters["reaction_distance"], ) system.topologies.add_structural_reaction( "Nucleate_Branch", topology_type="Actin-Polymer#Branch-Nucleating", reaction_function=ActinUtil.reaction_function_finish_start_branch, rate_function=ReaddyUtil.rate_function_infinity, )
[docs] @staticmethod def add_debranch_reaction(system): """ remove a branch """ system.topologies.add_structural_reaction( "Debranch_ATP", topology_type="Actin-Polymer", reaction_function=ActinUtil.reaction_function_debranching_ATP, rate_function=lambda x: parameters["debranching_ATP_rate"], ) system.topologies.add_structural_reaction( "Debranch_ADP", topology_type="Actin-Polymer", reaction_function=ActinUtil.reaction_function_debranching_ADP, rate_function=lambda x: parameters["debranching_ADP_rate"], )
[docs] @staticmethod def add_cap_bind_reaction(system): """ add capping protein to a barbed end to stop growth """ for i in range(1, 4): system.topologies.add_spatial_reaction( f"Cap_Bind1{i}: Actin-Polymer(actin#barbed_{i}) + Cap(cap) -> " f"Actin-Polymer#Capping(actin#{i}--cap#new)", rate=parameters["cap_bind_rate"], radius=parameters["actin_radius"] + parameters["cap_radius"] + parameters["reaction_distance"], ) system.topologies.add_spatial_reaction( f"Cap_Bind2{i}: Actin-Polymer(actin#barbed_ATP_{i}) + Cap(cap) -> " f"Actin-Polymer#Capping(actin#ATP_{i}--cap#new)", rate=parameters["cap_bind_rate"], radius=parameters["actin_radius"] + parameters["cap_radius"] + parameters["reaction_distance"], ) system.topologies.add_structural_reaction( "Finish_Cap_Bind", topology_type="Actin-Polymer#Capping", reaction_function=ActinUtil.reaction_function_finish_cap_bind, rate_function=ReaddyUtil.rate_function_infinity, )
[docs] @staticmethod def add_cap_unbind_reaction(system): """ remove capping protein """ system.topologies.add_structural_reaction( "Cap_Unbind", topology_type="Actin-Polymer", reaction_function=ActinUtil.reaction_function_cap_unbind, rate_function=lambda x: parameters["cap_unbind_rate"], )
[docs] @staticmethod def add_translate_reaction(system): """ translate particles by the displacements each timestep """ system.topologies.add_structural_reaction( "Translate", topology_type="Actin-Polymer", reaction_function=ActinUtil.reaction_function_translate, rate_function=ReaddyUtil.rate_function_infinity, )
[docs] @staticmethod def get_position_for_tangent_translation( time_index, monomer_id, monomer_pos, displacement_parameters ): return monomer_pos + ( displacement_parameters["total_displacement_nm"] / displacement_parameters["total_steps"] )
[docs] @staticmethod def get_position_for_radial_translation( time_index, monomer_id, monomer_pos, displacement_parameters ): global init_monomer_positions, pointed_monomer_positions if time_index == 0 and monomer_id > 0: init_monomer_positions[monomer_id] = monomer_pos if monomer_id == 0: pointed_monomer_positions.append(monomer_pos) radius = displacement_parameters["radius_nm"] theta_init = displacement_parameters["theta_init_radians"] theta_final = displacement_parameters["theta_final_radians"] d_theta = (theta_final - theta_init) / displacement_parameters["total_steps"] theta_1 = theta_init + time_index * d_theta theta_2 = theta_init + (time_index + 1) * d_theta dx = radius * (np.cos(theta_2) - np.cos(theta_1)) dy = radius * (np.sin(theta_2) - np.sin(theta_1)) d_pos_0 = np.array([dx, dy, 0]) if monomer_id == 0: return monomer_pos + d_pos_0 v_pos_init = init_monomer_positions[monomer_id] - pointed_monomer_positions[0] pos_magnitude = np.linalg.norm(v_pos_init) v_pos_init = ReaddyUtil.normalize(v_pos_init) v_pos_1 = ReaddyUtil.rotate( v=v_pos_init, axis=np.array([0, 0, 1]), angle=time_index * d_theta, ) v_pos_2 = ReaddyUtil.rotate( v=v_pos_init, axis=np.array([0, 0, 1]), angle=(time_index + 1) * d_theta, ) return (monomer_pos - pos_magnitude * v_pos_1) + ( d_pos_0 + pos_magnitude * v_pos_2 )