CcaS-CcaR Optogenetic with GFP autoactivation Gene Circuit¶
Bi-stable genetic circuit control using optogenetics. Control GFP expression by modulating light input to the CcaS-CcaR two-component system.
Physics¶
Stochastic dynamics using the Gillespie algorithm for exact simulation.
Pure stateless physics for the CcaS-CcaR + GFP with self-activation gene circuit system.
This module contains the ground truth stochastic dynamics for the bi-stable genetic circuit, using the Gillespie algorithm for exact stochastic simulation.
The physics is completely decoupled from any task-specific logic (rewards, terminations, observations). It can be reused by different tasks (control, SysID, etc.).
- System Description:
Light Input (U) → CcaSR (H) → GFP (F) with autoactivation feedback
Five Chemical Reactions: 1. CcaSR activation: ∅ → H (rate: eta * U) 2. CcaSR deactivation: H → ∅ (rate: nu * H) 3. F creation from H: ∅ → F (rate: 0.5 * a * H^nh / (Kh^nh + H^nh)) 4. F self-activation: ∅ → F (rate: 0.5 * a * F^nf / (Kf^nf + F^nf)) 5. F dilution: F → ∅ (rate: nu * F)
- Reference:
Based on the bi-stable genetic circuit model from: “Control of a Bi-Stable Genetic System via Parallelized Reinforcement Learning” CDC 2025, https://gitlab.com/lugagnelab/pqn-control-cdc2025
- class myriad.envs.bio.ccasr_gfp.physics.PhysicsState(time, H, F, next_reaction_time)[source]¶
Bases:
NamedTuplePure physical state of the gene circuit system.
- Variables:
time (jax.jaxlib._jax.Array) – Current simulation time (minutes)
H (jax.jaxlib._jax.Array) – CcaS-CcaR protein concentration (molecules)
F (jax.jaxlib._jax.Array) – GFP reporter protein concentration (molecules)
next_reaction_time (jax.jaxlib._jax.Array) – Scheduled time of next reaction (minutes). Set to inf when no reaction is pending (sample fresh). Preserved across RL step boundaries for physical accuracy.
- time: Array¶
Alias for field number 0
- H: Array¶
Alias for field number 1
- F: Array¶
Alias for field number 2
- next_reaction_time: Array¶
Alias for field number 3
- to_array()[source]¶
Convert to flat array for NN-based agents.
Note: next_reaction_time is excluded as it’s internal bookkeeping.
- Returns:
Array of shape (3,) with [time, H, F]
- Return type:
Array
- classmethod from_array(arr)[source]¶
Create state from flat array.
- Parameters:
arr (Array) – Array of shape (3,) with [time, H, F]
- Returns:
PhysicsState instance (next_reaction_time defaults to inf)
- Return type:
- classmethod create(time, H, F, next_reaction_time=None)[source]¶
Factory method to create PhysicsState with default next_reaction_time.
- Parameters:
time (Array) – Current simulation time
H (Array) – CcaS-CcaR protein concentration
F (Array) – GFP reporter protein concentration
next_reaction_time (Array | None) – Optional pending reaction time (defaults to inf)
- Returns:
PhysicsState instance
- Return type:
- class myriad.envs.bio.ccasr_gfp.physics.PhysicsConfig(timestep_minutes=5.0, max_gillespie_steps=10000)[source]¶
Bases:
objectStatic structural constants for the gene circuit system.
These are compile-time constants passed as static_argnames to jit. They define the experimental platform and circuit architecture — values that never change between cells or experiments.
Kinetic parameters (nu, Kh, nh, Kf, nf) belong in PhysicsParams because they vary between cells and are the targets of system identification.
- __init__(timestep_minutes=5.0, max_gillespie_steps=10000)¶
- replace(**updates)¶
Returns a new object replacing the specified fields with new values.
- class myriad.envs.bio.ccasr_gfp.physics.PhysicsParams(nu=0.01, Kh=90.0, nh=3.6, Kf=30.0, nf=3.6)[source]¶
Bases:
objectDynamic physics parameters — vmappable over parameter space.
These are the kinetic parameters that vary between cells (domain randomization) or are unknown and must be inferred (system identification).
- __init__(nu=0.01, Kh=90.0, nh=3.6, Kf=30.0, nf=3.6)¶
- replace(**updates)¶
Returns a new object replacing the specified fields with new values.
- class myriad.envs.bio.ccasr_gfp.physics.PhysicsParamsPrior(nu_loc=-4.605170185988091, nu_scale=0.0, Kh_loc=4.499809670330265, Kh_scale=0.0, nh_loc=1.2809338454620642, nh_scale=0.0, Kf_loc=3.4011973816621555, Kf_scale=0.0, nf_loc=1.2809338454620642, nf_scale=0.0)[source]¶
Bases:
objectLog-normal prior over kinetic parameters.
Each parameter p is sampled as: p ~ exp(Normal(loc, scale)). With scale=0 the distribution collapses to a point mass at exp(loc), so the default (all scales zero) is fully deterministic and backward compatible.
- __init__(nu_loc=-4.605170185988091, nu_scale=0.0, Kh_loc=4.499809670330265, Kh_scale=0.0, nh_loc=1.2809338454620642, nh_scale=0.0, Kf_loc=3.4011973816621555, Kf_scale=0.0, nf_loc=1.2809338454620642, nf_scale=0.0)¶
- replace(**updates)¶
Returns a new object replacing the specified fields with new values.
- myriad.envs.bio.ccasr_gfp.physics.compute_propensities(state, action, params)[source]¶
Compute reaction propensities (rates) for all five reactions.
- Parameters:
state (PhysicsState) – Current physical state (time, H, F)
action (Array) – Discrete action {0, 1} representing light input U
params (PhysicsParams) – Kinetic parameters (nu, Kh, nh, Kf, nf) — vmappable
- Returns:
Array of 5 propensities for reactions [R1, R2, R3, R4, R5]
- Return type:
Array
- myriad.envs.bio.ccasr_gfp.physics.apply_reaction(state, reaction_idx)[source]¶
Apply a single reaction to update the state.
Uses jax.lax.switch for JAX-compatible control flow.
- Parameters:
state (PhysicsState) – Current physical state
reaction_idx (Array) – Index of reaction to apply (0-4)
- Returns:
Updated physical state after reaction
- Return type:
- myriad.envs.bio.ccasr_gfp.physics.step_physics(key, state, action, params, config, previous_action, interval_start)[source]¶
Pure physics step using a discrete Gillespie algorithm.
Runs Gillespie simulation from current time until the end of the current interval (
interval_start + timestep_minutes). Intervals are at fixed absolute times (0, 5, 10, 15…), matching the physical setup where observations and actions occur at regular intervals.- Parameters:
key (Array) – RNG key for stochastic simulation
state (PhysicsState) – Current physical state (
time,H,F,next_reaction_time)action (Array) – Discrete action
{0, 1}representing light inputparams (PhysicsParams) – Dynamic parameters
config (PhysicsConfig) – Static physics constants
previous_action (Array) – Action from previous timestep. If different from action, the pending reaction time is invalidated (propensities changed).
interval_start (Array) – Start time of current interval (
t * timestep_minutes).
- Returns:
Next physical state after simulating until interval end
- Return type:
Control Task¶
Track a target GFP expression level.
Control task wrapper for CcaS-CcaR + GFP gene circuit.
Standard tracking task: Control GFP expression (F) to match a target trajectory. Reward: Negative absolute error between F and F_target.
Task variants: - Constant target: Fixed GFP level (default: F_target = 25) - Sinewave target: Time-varying sinusoidal trajectory
- class myriad.envs.bio.ccasr_gfp.tasks.control.ControlTaskState(physics, t, U, F_target)[source]¶
Bases:
NamedTupleState for the control task.
- Variables:
physics (myriad.envs.bio.ccasr_gfp.physics.PhysicsState) – The underlying physics state (time, H, F)
t (jax.jaxlib._jax.Array) – Current timestep counter (RL timesteps, not Gillespie time)
U (jax.jaxlib._jax.Array) – Previous action (light input from last timestep, for action-toggle detection)
F_target (jax.jaxlib._jax.Array) – Target trajectory for GFP expression [current, t+1, …, t+n_horizon]
- physics: PhysicsState¶
Alias for field number 0
- t: Array¶
Alias for field number 1
- U: Array¶
Alias for field number 2
- F_target: Array¶
Alias for field number 3
- class myriad.envs.bio.ccasr_gfp.tasks.control.ControlTaskConfig(physics=<factory>, task=<factory>, target_type='constant', n_horizon=1, F_target_constant=25.0, sinewave_period_minutes=600.0, sinewave_amplitude=20.0, sinewave_vshift=30.0)[source]¶
Bases:
BaseCcasrGfpTaskConfigConfiguration for the CcaS-CcaR control task.
- __init__(physics=<factory>, task=<factory>, target_type='constant', n_horizon=1, F_target_constant=25.0, sinewave_period_minutes=600.0, sinewave_amplitude=20.0, sinewave_vshift=30.0)¶
- replace(**updates)¶
Returns a new object replacing the specified fields with new values.
- class myriad.envs.bio.ccasr_gfp.tasks.control.ControlTaskParams(physics=<factory>)[source]¶
Bases:
objectParameters for the control task.
- physics: PhysicsParams¶
- __init__(physics=<factory>)¶
- replace(**updates)¶
Returns a new object replacing the specified fields with new values.
- class myriad.envs.bio.ccasr_gfp.tasks.control.ControlTaskParamsPrior(physics=<factory>)[source]¶
Bases:
objectPrior distribution over control task parameters.
- physics: PhysicsParamsPrior¶
- __init__(physics=<factory>)¶
- replace(**updates)¶
Returns a new object replacing the specified fields with new values.
- myriad.envs.bio.ccasr_gfp.tasks.control.step(key, state, action, params, config)¶
Step the control task forward one timestep.
- Parameters:
key (Array) – RNG key for stochastic physics simulation
state (ControlTaskState) – Current task state
action (Array) – Discrete action {0, 1} for light input
params (ControlTaskParams) – Task parameters
config (ControlTaskConfig) – Task configuration (static)
- Returns:
Next observation next_state: Next task state reward: Reward (negative absolute error) done: Termination flag (1.0 if done, 0.0 otherwise) info: Dict with current protein levels for logging
- Return type:
obs_next
- myriad.envs.bio.ccasr_gfp.tasks.control.reset(key, params, config)¶
Reset the control task to initial state.
Initializes the system at zero protein concentrations and generates initial target.
- Parameters:
key (Array) – RNG key for random initialization
params (ControlTaskParams) – Task parameters
config (ControlTaskConfig) – Task configuration (static)
- Returns:
Initial observation (CcasCcarControlObs with named fields) state: Initial task state
- Return type:
obs
- myriad.envs.bio.ccasr_gfp.tasks.control.get_obs(state, params, config)[source]¶
Extract observation from state.
Returns a structured observation with named fields for semantic access by classical controllers. Neural network agents can call .to_array().
- Parameters:
state (ControlTaskState) – Current task state
params (ControlTaskParams) – Task parameters (unused)
config (ControlTaskConfig) – Task configuration
- Returns:
CcasCcarControlObs with named fields (F_normalized, U_obs, F_target)
- Return type:
- myriad.envs.bio.ccasr_gfp.tasks.control.get_obs_shape(config)[source]¶
Get the shape of the observation space.
Observation: [F, F_target[0:n_horizon+1]] Shape: (1 + n_horizon + 1,)
- Parameters:
config (ControlTaskConfig) – Task configuration
- Returns:
Observation shape tuple
- Return type:
- myriad.envs.bio.ccasr_gfp.tasks.control.get_action_space(config)[source]¶
Get the discrete action space for the environment.
- Parameters:
config (ControlTaskConfig) – Task configuration (unused)
- Returns:
0 (light off) and 1 (light on)
- Return type:
Discrete space with 2 actions
- myriad.envs.bio.ccasr_gfp.tasks.control.make_env(config=None, params=None, params_prior=None, **kwargs)[source]¶
Create a Ccasr-gfp control task environment.
- Parameters:
config (ControlTaskConfig | None) – Custom ControlTaskConfig. If None, uses defaults.
params (ControlTaskParams | None) – Custom ControlTaskParams. If None, creates from kwargs.
params_prior (ControlTaskParamsPrior | None) – Optional prior for domain randomization. If set,
env.sample_params_fnwill sample distinct θ* per parallel env. Can also be triggered via flat kwargs (e.g.nu_scale=0.3).**kwargs – Keyword arguments for creating config/params if not provided.
- Returns:
Environment instance for the control task
- Return type:
Environment[ControlTaskState, ControlTaskConfig, ControlTaskParams, CcasrGfpControlObs]
Example
>>> # Constant target at F=25 >>> env = make_env(F_target_constant=25.0) >>> # Domain randomization >>> env = make_env(nu_scale=0.3, Kh_scale=0.2)
Shared utilities for CcaS-CcaR + GFP gene circuit task wrappers.
- class myriad.envs.bio.ccasr_gfp.tasks.base.CcasrGfpControlObs(F_normalized, F_target)[source]¶
Bases:
NamedTupleCcaS-CcaR control task observation with named fields.
Note: This is a partially observable system. The agent does not directly observe the light input (U) or the CcaSR concentration (H).
- Variables:
F_normalized (jax.jaxlib._jax.Array) – GFP fluorescence normalized by F_obs_normalizer
F_target (jax.jaxlib._jax.Array) – Target trajectory [current, t+1, …, t+n_horizon]
- F_normalized: Array¶
Alias for field number 0
- F_target: Array¶
Alias for field number 1
- to_array()[source]¶
Convert to flat array for NN-based agents.
- Returns:
Array of shape (1 + n_horizon + 1,) with [F, F_target…]
- Return type:
Array
- class myriad.envs.bio.ccasr_gfp.tasks.base.TaskConfig(max_steps=288, F_obs_normalizer=80.0)[source]¶
Bases:
objectBase configuration shared by all CcaS-CcaR tasks.
These define the task-specific episode limits and observation normalization.
- __init__(max_steps=288, F_obs_normalizer=80.0)¶
- replace(**updates)¶
Returns a new object replacing the specified fields with new values.
- class myriad.envs.bio.ccasr_gfp.tasks.base.BaseCcasrGfpTaskConfig(physics=<factory>, task=<factory>)[source]¶
Bases:
objectShared config fields for all CcaS-CcaR task wrappers.
Provides physics config, task config, and the max_steps protocol property in one place so individual task configs don’t repeat them.
- physics: PhysicsConfig¶
- task: TaskConfig¶
- __init__(physics=<factory>, task=<factory>)¶
- replace(**updates)¶
Returns a new object replacing the specified fields with new values.
- myriad.envs.bio.ccasr_gfp.tasks.base.step_physics_interval(key, physics, t, prev_action, action, params, config)[source]¶
Step physics forward one interval and return (next_physics, t + 1).
Centralises the interval_start calculation and step_physics call that every task _step function would otherwise duplicate.
- myriad.envs.bio.ccasr_gfp.tasks.base.check_termination(t, task_config)[source]¶
Common termination check for CcaS-CcaR tasks.
The episode terminates when maximum timesteps is reached.
- Parameters:
t (Array) – Current timestep counter
task_config (TaskConfig) – TaskConfig with max_steps
- Returns:
1.0 if terminated, 0.0 otherwise (as float for JAX compatibility)
- Return type:
done
- myriad.envs.bio.ccasr_gfp.tasks.base.get_action_space()[source]¶
Get the discrete action space for CcaS-CcaR.
- Returns:
0 (red light) and 1 (green light)
- Return type:
Discrete space with 2 actions
- myriad.envs.bio.ccasr_gfp.tasks.base.sample_initial_physics(key)[source]¶
Sample initial physics state.
We start from zero proteins at time 0. This represents the initial state before any light input.
- Parameters:
key (Array) – RNG key for random initialization (unused)
- Returns:
PhysicsState initialized to zero concentrations
- Return type:
- myriad.envs.bio.ccasr_gfp.tasks.base.generate_constant_target(n_horizon, F_target_value)[source]¶
Generate a constant target trajectory.
- myriad.envs.bio.ccasr_gfp.tasks.base.generate_sinewave_target(key, t, n_horizon, timestep_minutes, period_minutes=600.0, amplitude=20.0, vshift=30.0)[source]¶
Generate a sinusoidal target trajectory.
Creates a time-varying target that follows a sine wave pattern. Used for testing tracking performance on dynamic targets.
- Parameters:
key (Array) – RNG key for random phase initialization
t (Array) – Current timestep counter
n_horizon (int) – Number of future timesteps to predict
timestep_minutes (float) – Duration of each RL timestep in minutes
period_minutes (float) – Period of the sine wave in minutes (default: 600 = 10 hours)
amplitude (float) – Amplitude of the sine wave (default: 20)
vshift (float) – Vertical shift / DC offset (default: 30)
- Returns:
Array of shape (n_horizon + 1,) with sinusoidal target values
- Return type:
Array