Generating configuration files#

A single configuration file in the toml format must be provided to SkellySim in order to run a simulation. This configuration file specifies input parameters as well as object types and positions. While it is possible to write SkellySim configuration files by hand, it’s generally much more reliable and easier to generate the configurations from a python script.

The python portion of SkellySim includes a utility module called skelly_config to help generate these configuration files with some common configurations. It’s advisable to take a look at the examples to get you started on complex configurations, but the basic outline is provided here, as well as a definition of all parameters and some common terms.

Terminology#

  • Physical objects

    • Fiber: Flexible filament. Can be bound at either end to surfaces (Bodies and Peripheries), experience dynamic instability, and have constant motor forces per unit length along its axis.

    • Body: Mobile object (currently only a sphere) that can host fixed fibers or nucleate them via the dynamic instability module. Think: centrosomes, vesicles, and other objects that microtubules are typically associated with. Currently only spherical Bodies are supported.

    • Periphery: Fixed surface that Fibers and Bodies are contained within. Basically a fixed cellular wall. Spheres, Ellipses, and any convex surface of revolution are supported.

  • Boundary Conditions

    • clamped: Boundary condition for Fibers where the relative orientation of the Fiber to its clamping point is preserved. For Peripheries, this means (Velocity, AngularVelocity) = (0, 0) and for Bodies, (Velocity, AngularVelocity) = (VelocityBody, AngularVelocityBody)

    • hinged: Boundary condition for Fibers where the position, but not the orientation, of the Fiber to its hinge point is preserved. For Peripheries, this means (Velocity, Torque) = (0, 0) and is not implemented for Bodies. See Params.periphery_binding_flag

  • Configuration sections

    • params (required): Global system parameters. Things like timestepper parameters, and inter-object interaction specified here

    • dynamic_instability (optional): Parameters related to Fiber dynamic instability

    • fibers (optional): List of Fiber objects

    • bodies (optional): List of Body objects

    • periphery (optional): Single Periphery object

    • point_sources (optional): List of Point objects

  • Base units

    • time: seconds (s)

    • length: micrometers (μm)

    • force: piconewtons (pN)

    • viscosity: Pascal-seconds (Pa·s)

Example generation script#

The following example script creates an initial configuration with a single Body at the origin with a single Fiber attached to its surface. This object pair is contained within a spherical Periphery.

import numpy as np
from skelly_sim.skelly_config import ConfigSpherical, Body, Fiber

np.random.seed(100)

# Create a config object and set the system parameters. System parameters
# are typically things that control interobject interaction and
# timestepping/measurement
config = ConfigSpherical()
config.params.eta = 1.0
config.params.dt_initial = 1E-1
config.params.dt_min = 1E-4
config.params.dt_max = 1E-1
config.params.dt_write = 1E-1
config.params.t_final = 10.0
config.params.gmres_tol = 1E-10
config.params.seed = 130319

# Bodies are stored in a list. Here we put one Body object at the origin
# with 50 available nucleation sites. Since we're only adding one fiber, we
# really one need one nucleation site, so this is overkill.  To give the
# simulation some motion, we place a constant force in the 'y' direction on
# the Body.
config.bodies = [
    Body(n_nucleation_sites=50,
         position=[0.0, 0.0, 0.0],
         shape='sphere',
         radius=0.5,
         n_nodes=400,
         external_force=[0.0, 0.5, 0.0])
]

# Fibers are stored in a list. Since all fiber nodes positions need to be
# initialized (n_nodes * 3 numbers), we don't provide the position here, but
# instead use a helper utility to generate the positions
config.fibers = [
    Fiber(length=3.0,
          bending_rigidity=2.5E-3,
          parent_body=0,
          force_scale=0.0,
          n_nodes=64)
]

# Move our fiber on the surface of the Body and populate the position array.
config.fibers[0].fill_node_positions(x0=np.array([0.0, 0.0, 0.5]),
                                     normal=np.array([0.0, 0.0, 1.0]))

# number of nodes to represent our containing spherical periphery. larger
# peripheries = more nodes.
config.periphery.n_nodes = 1000

# radius of periphery in microns
config.periphery.radius = 4.25

# output our config
config.save('skelly_config.toml')

# uncomment the following to plot fibers on your sphere
# config.plot_fibers()

Base configuration types#

All configurations start with a base configuration class. Currently this is done by importing a class that represents a configuration file with a specific type of Periphery (or none!).

Free space configuration#

No bounding volume. No periodic boundary conditions. Just a big open system.

class skelly_sim.skelly_config.Config#

Parent dataclass for a SkellySim config. Use this config if you don’t have a bounding volume

params#

System parameters

Type

Params, default: Params()

bodies#

List of bodies

Type

List[Body], default: []

fibers#

List of fibers

Type

List[Fiber], default: []

point_sources#

List of point sources

Type

List[Point], default: []

plot_fibers()#

Scatter plot fiber beginning and end points. Note axes are not scaled, so results may look ‘squished’ and not exactly uniform.

Returns

position vector and its normalized version

Return type

tuple(matplotlib figure, matplotlib axis)

save(filename: str = 'skelly_config.toml')#

Write config object to file in TOML format

Parameters

filename (str, default: skelly_config.toml) – path of configuration file to output

Spherical container configuration#

Simulations using a SphericalPeriphery outer boundary

class skelly_sim.skelly_config.ConfigSpherical#

dataclass for a SkellySim config with a spherical periphery

params#

System parameters

Type

Params, default: Params()

bodies#

List of bodies

Type

List[Body], default: []

fibers#

List of fibers

Type

List[Fiber], default: []

point_sources#

List of point sources

Type

List[Point], default: []

periphery#

Spherical periphery object

Type

SphericalPeriphery, default: SphericalPeriphery()

Ellipsoidal container configuration#

Simulations using an EllipsoidalPeriphery outer boundary

class skelly_sim.skelly_config.ConfigEllipsoidal#

dataclass for a SkellySim config with an ellipsoidal periphery

params#

System parameters

Type

Params, default: Params()

bodies#

List of bodies

Type

List[Body], default: []

fibers#

List of fibers

Type

List[Fiber], default: []

point_sources#

List of point sources

Type

List[Point], default: []

periphery#

Periphery represented by an ellipsoid

Type

EllipsoidalPeriphery, default: EllipsoidalPeriphery()

Surface of revolution configuration#

Simulations using a SurfaceOfRevolution outer boundary

class skelly_sim.skelly_config.ConfigRevolution#

dataclass for a SkellySim config with a ‘surface of revolution’ periphery

params#

System parameters

Type

Params, default: Params()

bodies#

List of bodies

Type

List[Body], default: []

fibers#

List of fibers

Type

List[Fiber], default: []

point_sources#

List of point sources

Type

List[Point], default: []

periphery#

Periphery represented by a surface of revolution

Type

RevolutionPeriphery, default: RevolutionPeriphery()

System parameters#

Config.params

class skelly_sim.skelly_config.Params#

dataclass representing system/meta parameters for the entire simulation

eta#

Viscosity of fluid

Type

float, default: 1.0, units: Pa·s

dt_initial#

Initial length of timestep

Type

float, default: 0.025, units: s

dt_min#

Minimum timestep before simulation fails when using adaptive timestepping (adaptive_timestep_flag)

Type

float, default: 1E-5, units: s

dt_max#

Maximum timestep size allowable when using adaptive timestepping (adaptive_timestep_flag)

Type

float, default: 0.1, units: s

dt_write#

Amount of simulation time between writes. Due to adaptive timestepping (and floating point issues) the time between writes is only approximately dt_write

Type

float, default: 0.1, units: s

t_final#

Simulation time to quit the simulation

Type

float, default: 100.0, units: s

gmres_tol#

GMRES tolerance, might be tuned later, but recommend at least 1E-8

Type

float, default: 1E-8

fiber_error_tol#

Fiber error tolerance. Not recommended to tamper with. Fiber error is the maximum deviation between 1.0 and a the derivative along the fiber. When using adaptive timestepping, if the error exceeds this value, the timestep is rejected.

Type

float, default: 0.1

periphery_binding_flag#

If set, fiber plus ends near the periphery (closer than 0.75, hardcoded) will use hinged boundary conditions. Intended for use with dynamic instability

Type

bool, default: False

seed#

Random number seed at simulation runtime (doesn’t affect numpy seed during configuration generation)

Type

int, default: 130319

dynamic_instability#

Dynamic instability parameters

Type

DynamicInstability, default: DynamicInstability()

periphery_interaction_flag#

Experimental repulsion between periphery and Fibers

Type

bool, default: False

adaptive_timestep_flag#

If set, use adaptive timestepping, which attempts to control simulation error by reducing the timestep when the solution has convergence issues

Type

bool, default: True

pair_evaluator#

Type of evaluator to use for kernels (stokeslet, stokes double layer, etc) Valid values: “CPU”, “FMM”

Type

str, default: "FMM"

Dynamic instability#

Config.params.dynamic_instability

class skelly_sim.skelly_config.DynamicInstability#

dataclass for dynamic instability parameters

n_nodes#

Number of nodes for newly nucleated fibers (see nucleation_rate). 0 disables dynamic instability

Type

int, default: 0

v_growth#

Growth velocity in microns/second. Growth happens at the “plus” ends

Type

float, default: 0.0, units: μm·s⁻¹

f_catastrophe#

Catastrophe frequency (probability per unit time of switching from growth to deletion) in 1/second

Type

float, default: 0.0, units: s⁻¹

v_grow_collision_scale#

When a fiber hits a boundary, scale its velocity (v_growth) by this factor

Type

float, default: 0.5

f_catastrophe_collision_scale#

When a fiber hits a boundary, scale its catastrophe frequency (f_catastrophe) by this

Type

float, default: 2.0

nucleation_rate#

Fiber nucleation rate in units of MT nucleations / second

Type

float, default: 0.0, units: s⁻¹

radius#

New fiber radius in microns

Type

float, default: 0.025, units: μm

min_length#

New fiber initial length in microns

Type

float, default: 0.5, units: μm

bending_rigidity#

New fiber bending rigidity

Type

float, default: 2.5E-3, units: pN·μm²

min_separation#

Minimum distance between Fiber minus ends in microns when nucleating (closer than this will be rejected)

Type

float, default: 0.1, units: μm

Fibers#

Config.fibers (must be a list of Fiber objects!)

class skelly_sim.skelly_config.Fiber#

dataclass representing a single fiber

n_nodes#

Number of nodes to represent fiber. Highly deformed or very long fibers will require more nodes to be accurately represented

Type

int, default: 32

parent_body#

Index of Body the Fiber is bound to. A value of -1 indicates a free fiber. Fibers attached to Bodies obey the clamped boundary condition, which preserves the relative angle of attachment to the body.

Type

int, default: -1

force_scale#

Tangential force per unit length to act along filament. A positive value pushes toward the plus end, while a negative value pushes toward the minus end

Type

float, default: 0.0, units: pN·μm⁻¹

bending_rigidity#

Bending rigidity of this filament

Type

float default: 2.5E-3, units: pN·μm²

radius#

Radius of fiber (for purposes of SBT, currently no physical dimension)

Type

float, default: 0.0125, units: μm

length#

Constraint length of this filament

Type

float, default: 1.0, units: μm

minus_clamped#

Fix minus end of filament with “clamped” boundary condition, preserving orientation and position (Velocity = 0, AngularVelocity = 0). If attached to a body (parent_body >= 0), then this parameter is implied True and ignored.

Type

bool, default: False

x#

List of node positions in [x0,y0,z0,x1,y1,z1…] order. Extreme care must be taken when setting this since the length constraint can generate massive tensions with poor input. See examples.

Type

List[float], default: [], units: μm

Bodies#

Config.bodies (must be a list of Fiber objects!)

class skelly_sim.skelly_config.Body#

dataclass for a single body and its parameters

n_nucleation_sites#

Number of available Fiber sites on the body. Don’t add more fibers than this to body

Type

int, default: 0

position#

Lab frame coordinate of the body center [x,y,z]

Type

List[float], default: [0.0, 0.0, 0.0], units: μm

orientation#

Orientation quaternion of the body. Not worth changing

Type

List[float], default: [0.0, 0.0, 0.0, 1.0]

shape#

Shape of the body. Sphere is currently only supported option

Type

str, default: 'sphere'

radius#

Radius of the body. This is the attachment radius for nucleation sites, the hydrodynamic radius is a bit smaller

Type

float, default: 1.0, units: μm

n_nodes#

Number of nodes to represent surface. WARNING: MAKE NEW PRECOMPUTE DATA WHEN CHANGING or you will regret it.

Type

int, default: 600

precompute_file#

Where precompute data is stored (quadrature data, mostly). Can be different on different bodies, though should be the same if the bodies are the same radius and have the same numbers of nodes.

Type

str, default: 'body_precompute.npz'

external_force#

Lab frame external force applied to body - useful for testing things like stokes flow

Type

List[float], default: [0.0, 0.0, 0.0], units: pN

Periphery#

Config.periphery

Spherical periphery#

Config.periphery

class skelly_sim.skelly_config.SphericalPeriphery#

dataclass representing a spherical periphery

n_nodes#

Number of nodes to represent Periphery object. larger peripheries = more nodes. Memory scales as n_nodes^2, so don’t exceed ~10000

Type

int, default: 6000

shape#

Shape of the periphery. Don’t modify it!

Type

str, default: 'sphere'

radius#

Radius of our sphere in microns

Type

float, default: 6.0, units: μm

Ellipsoidal periphery#

Config.periphery

class skelly_sim.skelly_config.EllipsoidalPeriphery#

dataclass representing an ellipsoidal periphery. (x/a)^2 + (y/b)^2 + (z/c)^2 = 1

n_nodes#

Number of nodes to represent Periphery object. larger peripheries = more nodes. Memory scales as n_nodes^2, so don’t exceed ~10000

Type

int, default: 6000

shape#

Shape of the periphery. Don’t modify it!

Type

str, default: 'ellipsoid'

a#

Length of axis ‘a’

Type

float, default: 7.8, units: μm

b#

Length of axis ‘b’

Type

float, default: 4.16, units: μm

c#

Length of axis ‘c’

Type

float, default: 4.16, units: μm

Periphery of revolution#

Config.periphery

class skelly_sim.skelly_config.RevolutionPeriphery#

dataclass representing a surface of revolution. The user provides an envelope function ‘h(x)’ (see skelly_sim.shape_gallery.Envelope) which is rotated around the ‘x’ axis to generate a periphery. Note that the ‘skelly_precompute’ utility will actually update your output toml file with the correct number of nodes. This complicated machinery is so that later on ‘skelly_sim’ can directly look for collisions using the input height function

# Example usage:
# Target number of nodes -- actual number likely larger
config.periphery.envelope.n_nodes_target = 6000

# lower/upper bound are required options. ideally your function should go to zero at the upper/lower bounds
config.periphery.envelope.lower_bound = -3.75
config.periphery.envelope.upper_bound = 3.75

# required option. this is the function you're revolving around the 'x' axis. 'x' needs to be
# the independent variable. Currently the function has to be a one-liner
# Unit lengths should be in μm
config.periphery.envelope.height = "0.5 * T * ((1 + 2*x/length)**p1) * ((1 - 2*x/length)**p2) * length"
config.periphery.envelope.T = 0.72
config.periphery.envelope.p1 = 0.4
config.periphery.envelope.p2 = 0.2
config.periphery.envelope.length = 7.5
n_nodes#

Number of nodes to represent Periphery object. This will be set later by the envelope during the precompute stage, so don’t bother changing from default

Type

int, default: 0

shape#

Shape of the periphery. Don’t modify it!

Type

str, default: surface_of_revolution

envelope#

See example above

Type

Namespace, default: argparse.Namespace()

Point Sources#

Config.point_sources (must be a list of Point objects!)

class skelly_sim.skelly_config.Point#

dataclass for a point force/torque source

position#

Position of the point source (x,y,z)

Type

List[float], default: [0.0, 0.0, 0.0], units: μm

force#

Constant force to emit from point source

Type

List[float], default: [0.0, 0.0, 0.0], units: pN

torque#

Constant torque to emit from point source

Type

List[float], default: [0.0, 0.0, 0.0], units: pN·μm

time_to_live#

Simulation time after which the point source deactivates and does nothing. A value of 0.0 means to live forever.

Type

float, default: 0.0, units: s