Source code for tyssue.behaviors.sheet.delamination_events

"""
Mesoderm invagination event module
=======================


"""

import logging
import random

import numpy as np

from ...topology.base_topology import collapse_edge
from ...topology.sheet_topology import split_vert
from ...utils.decorators import face_lookup
from .actions import ab_pull, increase
from .basic_events import contraction

default_constriction_spec = {
    "face_id": -1,
    "face": -1,
    "contract_rate": 2,
    "critical_area": 1e-2,
    "radial_tension": 1.0,
    "contract_neighbors": True,
    "critical_area_neighbors": 10,
    "contract_span": 2,
    "basal_contract_rate": 1.001,
    "current_traction": 0,
    "max_traction": 30,
    "contraction_column": "contractility",
}

log = logging.getLogger(__name__)


[docs]@face_lookup def constriction(sheet, manager, **kwargs): """Constriction process This function corresponds to the process called "apical constriction" in the manuscript The cell undergoing delamination first contracts its apical area until it reaches a critical area. A probability dependent to the apical area allow an apico-basal traction of the cell. The cell can pull during max_traction time step, not necessarily consecutively. Parameters ---------- sheet : a :class:`tyssue.sheet` object manager : a :class:`tyssue.events.EventManager` object face_id : int the Id of the face undergoing delamination. contract_rate : float, default 2 rate of increase of the face contractility. critical_area : float, default 1e-2 face's area under which the cell starts loosing sides. radial_tension : float, default 1. tension applied on the face vertices along the apical-basal axis. contract_neighbors : bool, default `False` if True, the face contraction triggers contraction of the neighbor faces. contract_span : int, default 2 rank of neighbors contracting if contract_neighbor is True. Contraction rate for the neighbors is equal to `contract_rate` devided by the rank. """ constriction_spec = default_constriction_spec constriction_spec.update(**kwargs) # initialiser une variable face # aller chercher la valeur dans le dictionnaire à chaque fois ? face = constriction_spec["face"] contract_rate = constriction_spec["contract_rate"] current_traction = constriction_spec["current_traction"] if sheet.face_df.loc[face, "is_mesoderm"]: face_area = sheet.face_df.loc[face, "area"] if face_area > constriction_spec["critical_area"]: increase( sheet, "face", face, contract_rate, constriction_spec["contraction_column"], True, ) # if sheet.face_df.loc[face, 'prefered_area'] > 6: # sheet.face_df.loc[face, 'prefered_area'] -= 0.5 # increase_linear_tension(sheet, face, contract_rate) if (constriction_spec["contract_neighbors"]) & ( face_area < constriction_spec["critical_area_neighbors"] ): neighbors = sheet.get_neighborhood( face, constriction_spec["contract_span"] ).dropna() neighbors["id"] = sheet.face_df.loc[neighbors.face, "id"].values # remove cell which are not mesoderm ectodermal_cell = sheet.face_df.loc[neighbors.face][ ~sheet.face_df.loc[neighbors.face, "is_mesoderm"] ].id.values neighbors = neighbors.drop( neighbors[neighbors.id.isin(ectodermal_cell)].index ) manager.extend( [ ( contraction, _neighbor_contractile_increase(neighbor, constriction_spec), ) # TODO: check this for _, neighbor in neighbors.iterrows() ] ) proba_tension = np.exp(-face_area / constriction_spec["critical_area"]) aleatory_number = random.uniform(0, 1) if current_traction < constriction_spec["max_traction"]: if aleatory_number < proba_tension: current_traction = current_traction + 1 ab_pull(sheet, face, constriction_spec["radial_tension"], True) constriction_spec.update({"current_traction": current_traction}) manager.append(constriction, **constriction_spec)
[docs]def exchange_neighbour(sheet, manager, **kwargs): """ Executes neighbour exchanges for a face: 1. if face_df[face, 'try_collapse_edge'] is True: collapse that face's shortest edge into a vert 2. if face_df[face, 'try_expand_vert'] is True: expand that face's highest-order vert into an edge If either or both was successful: 1. Stores index of the new vert in face_df[face, 'edge_collapsed'] 2. Stores index of the new edge in face_df[face, 'vert_expanded'] Parameters ---------- sheet : a :class:`tyssue.sheet` object manager : a :class:`tyssue.events.EventManager` object **kwargs : parameters for the event, indices: face_id: id of the face being checked for exchange events critical_area: optional, default 1e-2, events are only executed if face area larger than this minimum_edges: optional, default 3 edge will not be collapsed if face with fewer sides would result maximum_edges: optional, default 10 vert will not be expanded if face with more sides would result """ exchange_spec = { "face_id": -1, "critical_area": 1e-2, "minimum_edges": 3, "maximum_edges": 10, } exchange_spec.update(**kwargs) verbose = exchange_spec.get("verbose", False) face_o = exchange_spec["face_id"] if len(sheet.face_df[sheet.face_df["face_o"] == face_o]) != 1: if sheet.face_df[sheet.face_df["face_o"] == face_o].empty: log.debug(f"No face with original ID {face_o} exists.") else: log.debug(f"More than one face with original ID {face_o} exists.") return face = sheet.face_df[sheet.face_df["face_o"] == face_o].index[0] do_collapse = sheet.face_df.loc[face, "try_collapse_edge"] do_expand = sheet.face_df.loc[face, "try_expand_vert"] if do_collapse or do_expand: log.debug( f"neighbour exchange triggered for face {face}, " f"originally {face_o}: collapse? {do_collapse} " f"expand? {do_expand} ", end="\r", ) if do_collapse and sheet.face_df.loc[face].area > exchange_spec["critical_area"]: # attempt to collapse the face's shortest edge e_collapsilling = sheet.edge_df[sheet.edge_df["face"] == face][ "length" ].idxmin() # check first: does this face and the one opposite that edge have > 3 sides? log.debug( f"checking conditions for edge {e_collapsilling}, " f"face: {face}, originally {face_o} ", end="\r", ) if sheet.face_df.loc[face].num_sides > exchange_spec["minimum_edges"]: opposite_face = sheet.edge_df.loc[ sheet.edge_df.loc[e_collapsilling].opposite ].face if ( sheet.face_df.loc[opposite_face].num_sides > exchange_spec["minimum_edges"] ): if verbose: print( f"collapsing edge {e_collapsilling} (face {face}) ", end="\r" ) remain_vert = collapse_edge( sheet, e_collapsilling, reindex=True, allow_two_sided=True ) sheet.face_df.at[face, "edge_collapsed"] = sheet.vert_df.loc[ remain_vert, "srce_o" ] sheet.face_df.at[opposite_face, "edge_collapsed"] = sheet.vert_df.loc[ remain_vert, "srce_o" ] elif verbose: print( f"could not collapse edge {e_collapsilling} " f"(face {face}) ", end="\r", ) if do_expand and sheet.face_df.loc[face].area > exchange_spec["critical_area"]: # attempt to expand the face's highest-order vertex # this works as if the cell pulled itself away from the rosette, # creating a new edge between it and the rosette verts = sheet.edge_df[sheet.edge_df["face"] == face]["srce"] v_expandilling = sheet.edge_df.srce.value_counts().loc[verts].idxmax() # now check if the rearrangement meets the criteria for this vertex # - is the vertex actually a rosette (more than tricellular)? # - does this create a face with too many sides? # nesting two if-clauses avoids calculating the # second condition if the first fails if len(sheet.edge_df[sheet.edge_df["srce"] == v_expandilling]) > 3: neighbors_v_expandilling = sheet.get_neighbors(face).intersection( sheet.edge_df[sheet.edge_df["trgt"] == v_expandilling]["face"].values ) if all( len(sheet.edge_df.query(f"face == {nf}")) < exchange_spec["maximum_edges"] for nf in neighbors_v_expandilling ): if verbose: print(f"splitting vert {v_expandilling} (face {face}) ", end="\r") new_edges = split_vert( sheet, v_expandilling, face=face, multiplier=1.5, reindex=True, recenter=True, ) # the fact that the vert was expanded needs to be stored # for the two cells that are affected, i.e. the ones # bordering the new edge for e in new_edges: sheet.face_df.at[ sheet.edge_df.loc[e]["face"], "vert_expanded" ] = sheet.edge_df.loc[e, "edge_o"] manager.append(exchange_neighbour, **exchange_spec)
def _neighbor_contractile_increase(neighbor, constriction_spec): contract = constriction_spec["contract_rate"] basal_contract = constriction_spec["basal_contract_rate"] increase = ( -(contract - basal_contract) / constriction_spec["contract_span"] ) * neighbor["order"] + contract specs = { "face_id": neighbor["id"], "contractile_increase": increase, "critical_area": constriction_spec["critical_area"], "max_contractility": 50, "contraction_column": constriction_spec["contraction_column"], "multiple": True, "unique": False, } return specs