diffbio 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- diffbio/__init__.py +39 -0
- diffbio/configs.py +75 -0
- diffbio/constants.py +204 -0
- diffbio/core/__init__.py +127 -0
- diffbio/core/base_operators.py +612 -0
- diffbio/core/data_types.py +260 -0
- diffbio/core/gnn_components.py +629 -0
- diffbio/core/graph_utils.py +149 -0
- diffbio/core/neural_components.py +270 -0
- diffbio/core/optimal_transport.py +133 -0
- diffbio/core/soft_ops/__init__.py +216 -0
- diffbio/core/soft_ops/_projections_permutahedron.py +1864 -0
- diffbio/core/soft_ops/_projections_simplex.py +240 -0
- diffbio/core/soft_ops/_projections_transport.py +508 -0
- diffbio/core/soft_ops/_sorting_network.py +204 -0
- diffbio/core/soft_ops/_types.py +15 -0
- diffbio/core/soft_ops/_utils.py +342 -0
- diffbio/core/soft_ops/autograd_safe.py +120 -0
- diffbio/core/soft_ops/comparison.py +235 -0
- diffbio/core/soft_ops/elementwise.py +309 -0
- diffbio/core/soft_ops/logical.py +146 -0
- diffbio/core/soft_ops/quantile.py +376 -0
- diffbio/core/soft_ops/selection.py +236 -0
- diffbio/core/soft_ops/sorting.py +926 -0
- diffbio/core/soft_ops/straight_through.py +261 -0
- diffbio/core/uncertainty.py +279 -0
- diffbio/evaluation/__init__.py +42 -0
- diffbio/evaluation/adapters.py +409 -0
- diffbio/evaluation/graders.py +223 -0
- diffbio/evaluation/problem.py +157 -0
- diffbio/evaluation/runner.py +277 -0
- diffbio/losses/__init__.py +59 -0
- diffbio/losses/alignment_losses.py +222 -0
- diffbio/losses/biological_regularization.py +288 -0
- diffbio/losses/metric_losses.py +139 -0
- diffbio/losses/singlecell_losses.py +387 -0
- diffbio/losses/statistical_losses.py +345 -0
- diffbio/operators/__init__.py +60 -0
- diffbio/operators/_count_vae.py +197 -0
- diffbio/operators/_loss_balancing.py +65 -0
- diffbio/operators/_masked_gene_transformer.py +118 -0
- diffbio/operators/_transformer_validation.py +50 -0
- diffbio/operators/alignment/__init__.py +51 -0
- diffbio/operators/alignment/profile_hmm.py +350 -0
- diffbio/operators/alignment/scoring.py +127 -0
- diffbio/operators/alignment/smith_waterman.py +261 -0
- diffbio/operators/alignment/soft_msa.py +419 -0
- diffbio/operators/assembly/__init__.py +27 -0
- diffbio/operators/assembly/gnn_assembly.py +252 -0
- diffbio/operators/assembly/metagenomic_binning.py +296 -0
- diffbio/operators/crispr/__init__.py +17 -0
- diffbio/operators/crispr/guide_scoring.py +269 -0
- diffbio/operators/drug_discovery/__init__.py +133 -0
- diffbio/operators/drug_discovery/_graph_utils.py +142 -0
- diffbio/operators/drug_discovery/admet_predictor.py +285 -0
- diffbio/operators/drug_discovery/attentive_fp.py +411 -0
- diffbio/operators/drug_discovery/dti.py +261 -0
- diffbio/operators/drug_discovery/fingerprint.py +490 -0
- diffbio/operators/drug_discovery/maccs_keys.py +267 -0
- diffbio/operators/drug_discovery/message_passing.py +200 -0
- diffbio/operators/drug_discovery/primitives.py +242 -0
- diffbio/operators/drug_discovery/property_predictor.py +163 -0
- diffbio/operators/drug_discovery/similarity.py +193 -0
- diffbio/operators/epigenomics/__init__.py +35 -0
- diffbio/operators/epigenomics/chromatin_state.py +491 -0
- diffbio/operators/epigenomics/contextual.py +288 -0
- diffbio/operators/epigenomics/fno_peak_calling.py +153 -0
- diffbio/operators/epigenomics/peak_calling.py +555 -0
- diffbio/operators/foundation_models/__init__.py +119 -0
- diffbio/operators/foundation_models/adapters.py +114 -0
- diffbio/operators/foundation_models/contracts.py +245 -0
- diffbio/operators/foundation_models/embedding_probe.py +83 -0
- diffbio/operators/foundation_models/experimental.py +128 -0
- diffbio/operators/foundation_models/foundation_model.py +332 -0
- diffbio/operators/foundation_models/frozen.py +59 -0
- diffbio/operators/foundation_models/precomputed.py +270 -0
- diffbio/operators/foundation_models/transformer_encoder.py +564 -0
- diffbio/operators/mapping/__init__.py +17 -0
- diffbio/operators/mapping/neural_mapper.py +493 -0
- diffbio/operators/metabolomics/__init__.py +39 -0
- diffbio/operators/metabolomics/spectral_similarity.py +315 -0
- diffbio/operators/molecular_dynamics/__init__.py +51 -0
- diffbio/operators/molecular_dynamics/force_field.py +265 -0
- diffbio/operators/molecular_dynamics/integrator.py +304 -0
- diffbio/operators/molecular_dynamics/primitives.py +115 -0
- diffbio/operators/multiomics/__init__.py +38 -0
- diffbio/operators/multiomics/hic_contact.py +377 -0
- diffbio/operators/multiomics/multiomics_vae.py +325 -0
- diffbio/operators/multiomics/spatial_deconvolution.py +316 -0
- diffbio/operators/multiomics/spatial_gene_detection.py +493 -0
- diffbio/operators/normalization/__init__.py +42 -0
- diffbio/operators/normalization/embedding.py +222 -0
- diffbio/operators/normalization/phate.py +400 -0
- diffbio/operators/normalization/umap.py +261 -0
- diffbio/operators/normalization/vae_normalizer.py +258 -0
- diffbio/operators/population/__init__.py +17 -0
- diffbio/operators/population/ancestry_estimation.py +274 -0
- diffbio/operators/preprocessing/__init__.py +76 -0
- diffbio/operators/preprocessing/adapter_removal.py +311 -0
- diffbio/operators/preprocessing/duplicate_filter.py +317 -0
- diffbio/operators/preprocessing/error_correction.py +287 -0
- diffbio/operators/protein/__init__.py +31 -0
- diffbio/operators/protein/secondary_structure.py +509 -0
- diffbio/operators/quality_filter.py +128 -0
- diffbio/operators/rna_structure/__init__.py +35 -0
- diffbio/operators/rna_structure/rna_folding.py +509 -0
- diffbio/operators/rnaseq/__init__.py +23 -0
- diffbio/operators/rnaseq/motif_discovery.py +251 -0
- diffbio/operators/rnaseq/splicing_psi.py +216 -0
- diffbio/operators/singlecell/__init__.py +193 -0
- diffbio/operators/singlecell/ambient_removal.py +333 -0
- diffbio/operators/singlecell/archetypes.py +191 -0
- diffbio/operators/singlecell/batch_correction.py +288 -0
- diffbio/operators/singlecell/cell_annotation.py +519 -0
- diffbio/operators/singlecell/communication.py +704 -0
- diffbio/operators/singlecell/differential_distribution.py +243 -0
- diffbio/operators/singlecell/doublet_detection.py +657 -0
- diffbio/operators/singlecell/downsampling.py +166 -0
- diffbio/operators/singlecell/enhanced_batch_correction.py +519 -0
- diffbio/operators/singlecell/grn_inference.py +336 -0
- diffbio/operators/singlecell/imputation.py +429 -0
- diffbio/operators/singlecell/knockdown_filter.py +176 -0
- diffbio/operators/singlecell/ot_trajectory.py +277 -0
- diffbio/operators/singlecell/simulation.py +444 -0
- diffbio/operators/singlecell/sindy_grn.py +247 -0
- diffbio/operators/singlecell/soft_clustering.py +211 -0
- diffbio/operators/singlecell/spatial_domains.py +677 -0
- diffbio/operators/singlecell/switch_de.py +184 -0
- diffbio/operators/singlecell/trajectory.py +447 -0
- diffbio/operators/singlecell/velocity.py +361 -0
- diffbio/operators/statistical/__init__.py +35 -0
- diffbio/operators/statistical/em_quantification.py +260 -0
- diffbio/operators/statistical/hmm.py +234 -0
- diffbio/operators/statistical/nb_glm.py +272 -0
- diffbio/operators/variant/__init__.py +64 -0
- diffbio/operators/variant/classifier.py +333 -0
- diffbio/operators/variant/cnn_classifier.py +255 -0
- diffbio/operators/variant/cnv_segmentation.py +678 -0
- diffbio/operators/variant/deepvariant_pileup.py +426 -0
- diffbio/operators/variant/pileup.py +240 -0
- diffbio/operators/variant/quality_recalibration.py +274 -0
- diffbio/pipelines/__init__.py +65 -0
- diffbio/pipelines/differential_expression.py +279 -0
- diffbio/pipelines/enhanced_variant_calling.py +326 -0
- diffbio/pipelines/perturbation.py +407 -0
- diffbio/pipelines/preprocessing.py +267 -0
- diffbio/pipelines/single_cell.py +366 -0
- diffbio/pipelines/variant_calling.py +490 -0
- diffbio/samplers/__init__.py +9 -0
- diffbio/samplers/perturbation_sampler.py +142 -0
- diffbio/sequences/__init__.py +34 -0
- diffbio/sequences/dna.py +239 -0
- diffbio/sources/__init__.py +149 -0
- diffbio/sources/_anndata_shared.py +89 -0
- diffbio/sources/_batch_iteration.py +37 -0
- diffbio/sources/_benchmark_source.py +152 -0
- diffbio/sources/_indexed_batch_source.py +38 -0
- diffbio/sources/_utils.py +45 -0
- diffbio/sources/anndata_interop.py +387 -0
- diffbio/sources/anndata_source.py +361 -0
- diffbio/sources/archive_ii.py +174 -0
- diffbio/sources/balifam.py +207 -0
- diffbio/sources/bam.py +265 -0
- diffbio/sources/bengrn_ground_truth.py +306 -0
- diffbio/sources/contextual_epigenomics.py +242 -0
- diffbio/sources/dti.py +359 -0
- diffbio/sources/embeddings.py +203 -0
- diffbio/sources/encode_peaks.py +223 -0
- diffbio/sources/fasta.py +226 -0
- diffbio/sources/immune_human.py +172 -0
- diffbio/sources/indexed_embeddings.py +128 -0
- diffbio/sources/indexed_view.py +191 -0
- diffbio/sources/molnet.py +493 -0
- diffbio/sources/multiomics.py +279 -0
- diffbio/sources/pancreas.py +108 -0
- diffbio/sources/perturbation/__init__.py +69 -0
- diffbio/sources/perturbation/_types.py +51 -0
- diffbio/sources/perturbation/_utils.py +125 -0
- diffbio/sources/perturbation/concat_source.py +115 -0
- diffbio/sources/perturbation/control_mapping.py +215 -0
- diffbio/sources/perturbation/experiment_config.py +261 -0
- diffbio/sources/perturbation/h5_metadata_cache.py +218 -0
- diffbio/sources/perturbation/output_space.py +52 -0
- diffbio/sources/perturbation/perturbation_source.py +513 -0
- diffbio/sources/seqfish.py +145 -0
- diffbio/sources/sequence_foundation.py +68 -0
- diffbio/sources/singlecell_foundation.py +68 -0
- diffbio/splitters/__init__.py +63 -0
- diffbio/splitters/base.py +251 -0
- diffbio/splitters/molecular.py +330 -0
- diffbio/splitters/perturbation.py +199 -0
- diffbio/splitters/random.py +217 -0
- diffbio/splitters/sequence.py +201 -0
- diffbio/utils/__init__.py +55 -0
- diffbio/utils/dependency_runtime.py +115 -0
- diffbio/utils/nn_utils.py +157 -0
- diffbio/utils/quality.py +45 -0
- diffbio/utils/training.py +585 -0
- diffbio-0.1.0.dist-info/METADATA +480 -0
- diffbio-0.1.0.dist-info/RECORD +202 -0
- diffbio-0.1.0.dist-info/WHEEL +4 -0
- diffbio-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
"""MD integrator operators wrapping JAX-MD.
|
|
2
|
+
|
|
3
|
+
This module provides differentiable MD integration operators that evolve
|
|
4
|
+
particle positions and velocities over time using JAX-MD's simulators.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import jax
|
|
12
|
+
import jax.numpy as jnp
|
|
13
|
+
from datarax.core.config import OperatorConfig
|
|
14
|
+
from datarax.core.operator import OperatorModule
|
|
15
|
+
from flax import nnx
|
|
16
|
+
from jax_md import quantity, simulate
|
|
17
|
+
|
|
18
|
+
from diffbio.operators.molecular_dynamics.primitives import (
|
|
19
|
+
PotentialType,
|
|
20
|
+
create_displacement_fn,
|
|
21
|
+
create_energy_fn,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class MDIntegratorConfig(OperatorConfig):
|
|
29
|
+
# pylint: disable=too-many-instance-attributes
|
|
30
|
+
"""Configuration for MD integrator operator.
|
|
31
|
+
|
|
32
|
+
Attributes:
|
|
33
|
+
integrator_type: Type of integrator ("velocity_verlet", "nvt_langevin").
|
|
34
|
+
dt: Time step for integration.
|
|
35
|
+
n_steps: Number of integration steps.
|
|
36
|
+
box_size: Size of periodic box. None for non-periodic.
|
|
37
|
+
potential_type: Type of potential ("lennard_jones", "morse", "soft_sphere").
|
|
38
|
+
sigma: Sigma parameter for potential (length scale).
|
|
39
|
+
epsilon: Epsilon parameter for potential (energy scale).
|
|
40
|
+
mass: Particle mass (uniform for all particles).
|
|
41
|
+
kT: Thermal energy for Langevin thermostat.
|
|
42
|
+
gamma: Friction coefficient for Langevin dynamics.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
integrator_type: str = "velocity_verlet"
|
|
46
|
+
dt: float = 0.001
|
|
47
|
+
n_steps: int = 100
|
|
48
|
+
box_size: float | None = 10.0
|
|
49
|
+
potential_type: str = "lennard_jones"
|
|
50
|
+
sigma: float = 1.0
|
|
51
|
+
epsilon: float = 1.0
|
|
52
|
+
mass: float = 1.0
|
|
53
|
+
kT: float = 1.0
|
|
54
|
+
gamma: float = 1.0
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass(frozen=True)
|
|
58
|
+
class _MDRuntime:
|
|
59
|
+
"""Precomputed JAX-MD runtime callables."""
|
|
60
|
+
|
|
61
|
+
displacement_fn: Any
|
|
62
|
+
shift_fn: Any
|
|
63
|
+
energy_fn: Any
|
|
64
|
+
force_fn: Any
|
|
65
|
+
step_fn: Any
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class MDIntegratorOperator(OperatorModule):
|
|
69
|
+
"""Differentiable MD integrator operator using JAX-MD.
|
|
70
|
+
|
|
71
|
+
Evolves particle positions and velocities over time using classical
|
|
72
|
+
molecular dynamics integration schemes.
|
|
73
|
+
|
|
74
|
+
Supported integrators:
|
|
75
|
+
- velocity_verlet: Symplectic velocity Verlet (NVE)
|
|
76
|
+
- nvt_langevin: Langevin dynamics for NVT ensemble
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
```python
|
|
80
|
+
config = MDIntegratorConfig(dt=0.001, n_steps=1000, box_size=10.0)
|
|
81
|
+
integrator = MDIntegratorOperator(config, rngs=nnx.Rngs(42))
|
|
82
|
+
data = {"positions": positions, "velocities": velocities}
|
|
83
|
+
result, state, meta = integrator.apply(data, {}, None)
|
|
84
|
+
final_positions = result["positions"]
|
|
85
|
+
trajectory = result["trajectory"]
|
|
86
|
+
```
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
def __init__(
|
|
90
|
+
self,
|
|
91
|
+
config: MDIntegratorConfig,
|
|
92
|
+
*,
|
|
93
|
+
rngs: nnx.Rngs | None = None,
|
|
94
|
+
name: str | None = None,
|
|
95
|
+
):
|
|
96
|
+
"""Initialize MD integrator operator.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
config: Integrator configuration.
|
|
100
|
+
rngs: Flax NNX random number generators.
|
|
101
|
+
name: Optional name for the operator.
|
|
102
|
+
"""
|
|
103
|
+
super().__init__(config, rngs=rngs, name=name)
|
|
104
|
+
# Pre-create displacement, energy, and force functions (efficiency: only created once)
|
|
105
|
+
displacement_fn, shift_fn = create_displacement_fn(config.box_size)
|
|
106
|
+
energy_fn = create_energy_fn(
|
|
107
|
+
displacement_fn,
|
|
108
|
+
potential_type=config.potential_type,
|
|
109
|
+
sigma=config.sigma,
|
|
110
|
+
epsilon=config.epsilon,
|
|
111
|
+
)
|
|
112
|
+
force_fn = quantity.force(energy_fn)
|
|
113
|
+
|
|
114
|
+
# Pre-create step function based on integrator type
|
|
115
|
+
if config.integrator_type == "velocity_verlet":
|
|
116
|
+
_, step_fn = simulate.nve(energy_fn, shift_fn, dt=config.dt)
|
|
117
|
+
elif config.integrator_type == "nvt_langevin":
|
|
118
|
+
_, step_fn = simulate.nvt_langevin(
|
|
119
|
+
energy_fn,
|
|
120
|
+
shift_fn,
|
|
121
|
+
dt=config.dt,
|
|
122
|
+
kT=config.kT,
|
|
123
|
+
gamma=config.gamma,
|
|
124
|
+
)
|
|
125
|
+
else:
|
|
126
|
+
raise ValueError(f"Unknown integrator type: {config.integrator_type}")
|
|
127
|
+
|
|
128
|
+
self._runtime = nnx.static(
|
|
129
|
+
_MDRuntime(
|
|
130
|
+
displacement_fn=displacement_fn,
|
|
131
|
+
shift_fn=shift_fn,
|
|
132
|
+
energy_fn=energy_fn,
|
|
133
|
+
force_fn=force_fn,
|
|
134
|
+
step_fn=step_fn,
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
def apply(
|
|
139
|
+
self,
|
|
140
|
+
data: dict[str, Any],
|
|
141
|
+
state: dict[str, Any],
|
|
142
|
+
metadata: dict[str, Any] | None,
|
|
143
|
+
random_params: Any = None,
|
|
144
|
+
stats: dict[str, Any] | None = None,
|
|
145
|
+
) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any] | None]:
|
|
146
|
+
"""Run MD simulation for specified number of steps.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
data: Input data containing:
|
|
150
|
+
- positions: Initial particle positions (n_particles, dim)
|
|
151
|
+
- velocities: Initial particle velocities (n_particles, dim)
|
|
152
|
+
state: Per-element state (passed through).
|
|
153
|
+
metadata: Optional metadata.
|
|
154
|
+
random_params: Unused random parameters.
|
|
155
|
+
stats: Optional statistics dictionary.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
Tuple of:
|
|
159
|
+
- data with updated positions/velocities and trajectory
|
|
160
|
+
- unchanged state
|
|
161
|
+
- unchanged metadata
|
|
162
|
+
"""
|
|
163
|
+
positions = data["positions"]
|
|
164
|
+
velocities = data["velocities"]
|
|
165
|
+
config = self.config
|
|
166
|
+
runtime = self._runtime
|
|
167
|
+
|
|
168
|
+
# Use pre-created functions from __init__
|
|
169
|
+
# Initialize state with user-provided velocities
|
|
170
|
+
# JAX-MD uses momentum = mass * velocity internally
|
|
171
|
+
initial_force = runtime.force_fn(positions)
|
|
172
|
+
mass = config.mass # JAX-MD works with scalar mass
|
|
173
|
+
momentum = velocities * mass
|
|
174
|
+
|
|
175
|
+
# Create appropriate state based on integrator type
|
|
176
|
+
if config.integrator_type == "velocity_verlet":
|
|
177
|
+
sim_state = simulate.NVEState(
|
|
178
|
+
position=positions, # pyright: ignore[reportCallIssue]
|
|
179
|
+
momentum=momentum, # pyright: ignore[reportCallIssue]
|
|
180
|
+
force=initial_force, # pyright: ignore[reportCallIssue]
|
|
181
|
+
mass=mass, # pyright: ignore[reportCallIssue]
|
|
182
|
+
)
|
|
183
|
+
elif config.integrator_type == "nvt_langevin":
|
|
184
|
+
# Langevin dynamics requires rng for stochastic forces
|
|
185
|
+
rng_key = jax.random.PRNGKey(42) # Deterministic for reproducibility
|
|
186
|
+
sim_state = simulate.NVTLangevinState(
|
|
187
|
+
position=positions, # pyright: ignore[reportCallIssue]
|
|
188
|
+
momentum=momentum, # pyright: ignore[reportCallIssue]
|
|
189
|
+
force=initial_force, # pyright: ignore[reportCallIssue]
|
|
190
|
+
mass=mass, # pyright: ignore[reportCallIssue]
|
|
191
|
+
rng=rng_key, # pyright: ignore[reportCallIssue]
|
|
192
|
+
)
|
|
193
|
+
else:
|
|
194
|
+
raise ValueError(f"Unknown integrator type: {config.integrator_type}")
|
|
195
|
+
|
|
196
|
+
# Run simulation using scan for efficiency
|
|
197
|
+
step_fn = runtime.step_fn # Capture for use in nested function
|
|
198
|
+
|
|
199
|
+
def scan_step(carry, _):
|
|
200
|
+
sim_state = carry
|
|
201
|
+
sim_state = step_fn(sim_state)
|
|
202
|
+
return sim_state, sim_state.position
|
|
203
|
+
|
|
204
|
+
final_state, traj_positions = jax.lax.scan(
|
|
205
|
+
scan_step, sim_state, None, length=config.n_steps
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
# Stack trajectory (including initial position)
|
|
209
|
+
full_trajectory = jnp.concatenate([positions[jnp.newaxis, ...], traj_positions], axis=0)
|
|
210
|
+
|
|
211
|
+
result = {
|
|
212
|
+
**data,
|
|
213
|
+
"positions": final_state.position,
|
|
214
|
+
"velocities": final_state.velocity,
|
|
215
|
+
"trajectory": full_trajectory,
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return result, state, metadata
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def create_integrator(
|
|
222
|
+
integrator_type: str = "velocity_verlet",
|
|
223
|
+
dt: float = 0.001,
|
|
224
|
+
n_steps: int = 100,
|
|
225
|
+
box_size: float | None = 10.0,
|
|
226
|
+
potential_type: str | PotentialType = PotentialType.LENNARD_JONES,
|
|
227
|
+
sigma: float = 1.0,
|
|
228
|
+
epsilon: float = 1.0,
|
|
229
|
+
mass: float = 1.0,
|
|
230
|
+
kT: float = 1.0,
|
|
231
|
+
gamma: float = 1.0,
|
|
232
|
+
seed: int = 42,
|
|
233
|
+
) -> MDIntegratorOperator:
|
|
234
|
+
"""Create an MD integrator operator.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
integrator_type: Type of integrator ("velocity_verlet", "nvt_langevin").
|
|
238
|
+
dt: Time step for integration.
|
|
239
|
+
n_steps: Number of integration steps.
|
|
240
|
+
box_size: Periodic box size. None for non-periodic.
|
|
241
|
+
potential_type: Type of potential ("lennard_jones", "morse", "soft_sphere")
|
|
242
|
+
or PotentialType enum.
|
|
243
|
+
sigma: Sigma parameter for potential (length scale).
|
|
244
|
+
epsilon: Epsilon parameter for potential (energy scale).
|
|
245
|
+
mass: Particle mass.
|
|
246
|
+
kT: Thermal energy for Langevin thermostat.
|
|
247
|
+
gamma: Friction coefficient for Langevin dynamics.
|
|
248
|
+
seed: Random seed for initialization.
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Configured MDIntegratorOperator.
|
|
252
|
+
"""
|
|
253
|
+
# Convert enum to string if needed
|
|
254
|
+
if isinstance(potential_type, PotentialType):
|
|
255
|
+
potential_type = potential_type.value
|
|
256
|
+
|
|
257
|
+
config = MDIntegratorConfig(
|
|
258
|
+
integrator_type=integrator_type,
|
|
259
|
+
dt=dt,
|
|
260
|
+
n_steps=n_steps,
|
|
261
|
+
box_size=box_size,
|
|
262
|
+
potential_type=potential_type,
|
|
263
|
+
sigma=sigma,
|
|
264
|
+
epsilon=epsilon,
|
|
265
|
+
mass=mass,
|
|
266
|
+
kT=kT,
|
|
267
|
+
gamma=gamma,
|
|
268
|
+
)
|
|
269
|
+
return MDIntegratorOperator(config, rngs=nnx.Rngs(seed))
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def create_verlet_integrator(
|
|
273
|
+
dt: float = 0.001,
|
|
274
|
+
n_steps: int = 100,
|
|
275
|
+
box_size: float | None = 10.0,
|
|
276
|
+
sigma: float = 1.0,
|
|
277
|
+
epsilon: float = 1.0,
|
|
278
|
+
seed: int = 42,
|
|
279
|
+
) -> MDIntegratorOperator:
|
|
280
|
+
"""Create a velocity Verlet integrator operator.
|
|
281
|
+
|
|
282
|
+
This is a convenience function for creating an NVE integrator
|
|
283
|
+
with velocity Verlet algorithm.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
dt: Time step for integration.
|
|
287
|
+
n_steps: Number of integration steps.
|
|
288
|
+
box_size: Periodic box size. None for non-periodic.
|
|
289
|
+
sigma: Sigma parameter for potential.
|
|
290
|
+
epsilon: Epsilon parameter for potential.
|
|
291
|
+
seed: Random seed for initialization.
|
|
292
|
+
|
|
293
|
+
Returns:
|
|
294
|
+
Configured MDIntegratorOperator.
|
|
295
|
+
"""
|
|
296
|
+
return create_integrator(
|
|
297
|
+
integrator_type="velocity_verlet",
|
|
298
|
+
dt=dt,
|
|
299
|
+
n_steps=n_steps,
|
|
300
|
+
box_size=box_size,
|
|
301
|
+
sigma=sigma,
|
|
302
|
+
epsilon=epsilon,
|
|
303
|
+
seed=seed,
|
|
304
|
+
)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Shared JAX-MD primitives for molecular dynamics operators.
|
|
2
|
+
|
|
3
|
+
This module provides common functions for creating JAX-MD primitives,
|
|
4
|
+
following the DRY principle by centralizing displacement, energy, and
|
|
5
|
+
force function creation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from enum import StrEnum
|
|
10
|
+
from typing import Callable
|
|
11
|
+
|
|
12
|
+
from jax_md import energy, quantity, space
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PotentialType(StrEnum):
|
|
18
|
+
"""Enumeration of supported potential types."""
|
|
19
|
+
|
|
20
|
+
LENNARD_JONES = "lennard_jones"
|
|
21
|
+
SOFT_SPHERE = "soft_sphere"
|
|
22
|
+
MORSE = "morse"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def create_displacement_fn(
|
|
26
|
+
box_size: float | None = None,
|
|
27
|
+
) -> tuple[Callable, Callable]:
|
|
28
|
+
"""Create displacement and shift functions based on boundary conditions.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
box_size: Size of periodic box. None for non-periodic (free) boundaries.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Tuple of (displacement_fn, shift_fn) where:
|
|
35
|
+
- displacement_fn: computes displacement vector between two points
|
|
36
|
+
- shift_fn: applies displacement to a position respecting boundaries
|
|
37
|
+
"""
|
|
38
|
+
if box_size is not None:
|
|
39
|
+
return space.periodic(box_size) # pyright: ignore[reportArgumentType]
|
|
40
|
+
else:
|
|
41
|
+
return space.free()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def create_energy_fn(
|
|
45
|
+
displacement_fn: Callable,
|
|
46
|
+
potential_type: PotentialType | str = PotentialType.LENNARD_JONES,
|
|
47
|
+
sigma: float = 1.0,
|
|
48
|
+
epsilon: float = 1.0,
|
|
49
|
+
cutoff: float | None = None,
|
|
50
|
+
alpha: float = 5.0,
|
|
51
|
+
) -> Callable:
|
|
52
|
+
"""Create energy function for the specified potential.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
displacement_fn: Displacement function from create_displacement_fn.
|
|
56
|
+
potential_type: Type of potential to use.
|
|
57
|
+
sigma: Length scale parameter (particle diameter).
|
|
58
|
+
epsilon: Energy scale parameter (well depth).
|
|
59
|
+
cutoff: Cutoff distance for interactions. None for no cutoff.
|
|
60
|
+
alpha: Morse potential width parameter (only for morse).
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Energy function that takes positions and returns total energy.
|
|
64
|
+
|
|
65
|
+
Raises:
|
|
66
|
+
ValueError: If potential_type is not recognized.
|
|
67
|
+
"""
|
|
68
|
+
# Convert string to enum if needed
|
|
69
|
+
if isinstance(potential_type, str):
|
|
70
|
+
try:
|
|
71
|
+
potential_type = PotentialType(potential_type)
|
|
72
|
+
except ValueError as err:
|
|
73
|
+
raise ValueError(f"Unknown potential type: {potential_type}") from err
|
|
74
|
+
|
|
75
|
+
if potential_type == PotentialType.LENNARD_JONES:
|
|
76
|
+
kwargs = {
|
|
77
|
+
"displacement_or_metric": displacement_fn,
|
|
78
|
+
"sigma": sigma,
|
|
79
|
+
"epsilon": epsilon,
|
|
80
|
+
}
|
|
81
|
+
if cutoff is not None:
|
|
82
|
+
kwargs["r_cutoff"] = cutoff * sigma
|
|
83
|
+
return energy.lennard_jones_pair(**kwargs) # pyright: ignore[reportArgumentType]
|
|
84
|
+
|
|
85
|
+
elif potential_type == PotentialType.SOFT_SPHERE:
|
|
86
|
+
return energy.soft_sphere_pair(
|
|
87
|
+
displacement_fn, # pyright: ignore[reportArgumentType]
|
|
88
|
+
sigma=sigma, # pyright: ignore[reportArgumentType]
|
|
89
|
+
epsilon=epsilon, # pyright: ignore[reportArgumentType]
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
elif potential_type == PotentialType.MORSE:
|
|
93
|
+
return energy.morse_pair(
|
|
94
|
+
displacement_fn, # pyright: ignore[reportArgumentType]
|
|
95
|
+
sigma=sigma, # pyright: ignore[reportArgumentType]
|
|
96
|
+
epsilon=epsilon, # pyright: ignore[reportArgumentType]
|
|
97
|
+
alpha=alpha, # pyright: ignore[reportArgumentType]
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
else:
|
|
101
|
+
raise ValueError(f"Unknown potential type: {potential_type}")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def create_force_fn(energy_fn: Callable) -> Callable:
|
|
105
|
+
"""Create force function from energy function.
|
|
106
|
+
|
|
107
|
+
Forces are computed as the negative gradient of the energy.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
energy_fn: Energy function that takes positions and returns energy.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
Force function that takes positions and returns forces.
|
|
114
|
+
"""
|
|
115
|
+
return quantity.force(energy_fn)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Multi-omics analysis operators for differentiable integration.
|
|
2
|
+
|
|
3
|
+
This module provides differentiable operators for multi-omics data analysis:
|
|
4
|
+
- DifferentiableMultiOmicsVAE: PoE-based multi-omics VAE integration
|
|
5
|
+
- SpatialDeconvolution: Cell type deconvolution for spatial transcriptomics
|
|
6
|
+
- HiCContactAnalysis: Chromatin contact analysis for Hi-C data
|
|
7
|
+
- DifferentiableSpatialGeneDetector: SpatialDE-style spatial gene detection
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from diffbio.operators.multiomics.hic_contact import (
|
|
11
|
+
HiCContactAnalysis,
|
|
12
|
+
HiCContactAnalysisConfig,
|
|
13
|
+
)
|
|
14
|
+
from diffbio.operators.multiomics.multiomics_vae import (
|
|
15
|
+
DifferentiableMultiOmicsVAE,
|
|
16
|
+
MultiOmicsVAEConfig,
|
|
17
|
+
)
|
|
18
|
+
from diffbio.operators.multiomics.spatial_deconvolution import (
|
|
19
|
+
SpatialDeconvolution,
|
|
20
|
+
SpatialDeconvolutionConfig,
|
|
21
|
+
)
|
|
22
|
+
from diffbio.operators.multiomics.spatial_gene_detection import (
|
|
23
|
+
DifferentiableSpatialGeneDetector,
|
|
24
|
+
SpatialGeneDetectorConfig,
|
|
25
|
+
create_spatial_gene_detector,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"DifferentiableMultiOmicsVAE",
|
|
30
|
+
"MultiOmicsVAEConfig",
|
|
31
|
+
"SpatialDeconvolution",
|
|
32
|
+
"SpatialDeconvolutionConfig",
|
|
33
|
+
"HiCContactAnalysis",
|
|
34
|
+
"HiCContactAnalysisConfig",
|
|
35
|
+
"DifferentiableSpatialGeneDetector",
|
|
36
|
+
"SpatialGeneDetectorConfig",
|
|
37
|
+
"create_spatial_gene_detector",
|
|
38
|
+
]
|