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.
Files changed (202) hide show
  1. diffbio/__init__.py +39 -0
  2. diffbio/configs.py +75 -0
  3. diffbio/constants.py +204 -0
  4. diffbio/core/__init__.py +127 -0
  5. diffbio/core/base_operators.py +612 -0
  6. diffbio/core/data_types.py +260 -0
  7. diffbio/core/gnn_components.py +629 -0
  8. diffbio/core/graph_utils.py +149 -0
  9. diffbio/core/neural_components.py +270 -0
  10. diffbio/core/optimal_transport.py +133 -0
  11. diffbio/core/soft_ops/__init__.py +216 -0
  12. diffbio/core/soft_ops/_projections_permutahedron.py +1864 -0
  13. diffbio/core/soft_ops/_projections_simplex.py +240 -0
  14. diffbio/core/soft_ops/_projections_transport.py +508 -0
  15. diffbio/core/soft_ops/_sorting_network.py +204 -0
  16. diffbio/core/soft_ops/_types.py +15 -0
  17. diffbio/core/soft_ops/_utils.py +342 -0
  18. diffbio/core/soft_ops/autograd_safe.py +120 -0
  19. diffbio/core/soft_ops/comparison.py +235 -0
  20. diffbio/core/soft_ops/elementwise.py +309 -0
  21. diffbio/core/soft_ops/logical.py +146 -0
  22. diffbio/core/soft_ops/quantile.py +376 -0
  23. diffbio/core/soft_ops/selection.py +236 -0
  24. diffbio/core/soft_ops/sorting.py +926 -0
  25. diffbio/core/soft_ops/straight_through.py +261 -0
  26. diffbio/core/uncertainty.py +279 -0
  27. diffbio/evaluation/__init__.py +42 -0
  28. diffbio/evaluation/adapters.py +409 -0
  29. diffbio/evaluation/graders.py +223 -0
  30. diffbio/evaluation/problem.py +157 -0
  31. diffbio/evaluation/runner.py +277 -0
  32. diffbio/losses/__init__.py +59 -0
  33. diffbio/losses/alignment_losses.py +222 -0
  34. diffbio/losses/biological_regularization.py +288 -0
  35. diffbio/losses/metric_losses.py +139 -0
  36. diffbio/losses/singlecell_losses.py +387 -0
  37. diffbio/losses/statistical_losses.py +345 -0
  38. diffbio/operators/__init__.py +60 -0
  39. diffbio/operators/_count_vae.py +197 -0
  40. diffbio/operators/_loss_balancing.py +65 -0
  41. diffbio/operators/_masked_gene_transformer.py +118 -0
  42. diffbio/operators/_transformer_validation.py +50 -0
  43. diffbio/operators/alignment/__init__.py +51 -0
  44. diffbio/operators/alignment/profile_hmm.py +350 -0
  45. diffbio/operators/alignment/scoring.py +127 -0
  46. diffbio/operators/alignment/smith_waterman.py +261 -0
  47. diffbio/operators/alignment/soft_msa.py +419 -0
  48. diffbio/operators/assembly/__init__.py +27 -0
  49. diffbio/operators/assembly/gnn_assembly.py +252 -0
  50. diffbio/operators/assembly/metagenomic_binning.py +296 -0
  51. diffbio/operators/crispr/__init__.py +17 -0
  52. diffbio/operators/crispr/guide_scoring.py +269 -0
  53. diffbio/operators/drug_discovery/__init__.py +133 -0
  54. diffbio/operators/drug_discovery/_graph_utils.py +142 -0
  55. diffbio/operators/drug_discovery/admet_predictor.py +285 -0
  56. diffbio/operators/drug_discovery/attentive_fp.py +411 -0
  57. diffbio/operators/drug_discovery/dti.py +261 -0
  58. diffbio/operators/drug_discovery/fingerprint.py +490 -0
  59. diffbio/operators/drug_discovery/maccs_keys.py +267 -0
  60. diffbio/operators/drug_discovery/message_passing.py +200 -0
  61. diffbio/operators/drug_discovery/primitives.py +242 -0
  62. diffbio/operators/drug_discovery/property_predictor.py +163 -0
  63. diffbio/operators/drug_discovery/similarity.py +193 -0
  64. diffbio/operators/epigenomics/__init__.py +35 -0
  65. diffbio/operators/epigenomics/chromatin_state.py +491 -0
  66. diffbio/operators/epigenomics/contextual.py +288 -0
  67. diffbio/operators/epigenomics/fno_peak_calling.py +153 -0
  68. diffbio/operators/epigenomics/peak_calling.py +555 -0
  69. diffbio/operators/foundation_models/__init__.py +119 -0
  70. diffbio/operators/foundation_models/adapters.py +114 -0
  71. diffbio/operators/foundation_models/contracts.py +245 -0
  72. diffbio/operators/foundation_models/embedding_probe.py +83 -0
  73. diffbio/operators/foundation_models/experimental.py +128 -0
  74. diffbio/operators/foundation_models/foundation_model.py +332 -0
  75. diffbio/operators/foundation_models/frozen.py +59 -0
  76. diffbio/operators/foundation_models/precomputed.py +270 -0
  77. diffbio/operators/foundation_models/transformer_encoder.py +564 -0
  78. diffbio/operators/mapping/__init__.py +17 -0
  79. diffbio/operators/mapping/neural_mapper.py +493 -0
  80. diffbio/operators/metabolomics/__init__.py +39 -0
  81. diffbio/operators/metabolomics/spectral_similarity.py +315 -0
  82. diffbio/operators/molecular_dynamics/__init__.py +51 -0
  83. diffbio/operators/molecular_dynamics/force_field.py +265 -0
  84. diffbio/operators/molecular_dynamics/integrator.py +304 -0
  85. diffbio/operators/molecular_dynamics/primitives.py +115 -0
  86. diffbio/operators/multiomics/__init__.py +38 -0
  87. diffbio/operators/multiomics/hic_contact.py +377 -0
  88. diffbio/operators/multiomics/multiomics_vae.py +325 -0
  89. diffbio/operators/multiomics/spatial_deconvolution.py +316 -0
  90. diffbio/operators/multiomics/spatial_gene_detection.py +493 -0
  91. diffbio/operators/normalization/__init__.py +42 -0
  92. diffbio/operators/normalization/embedding.py +222 -0
  93. diffbio/operators/normalization/phate.py +400 -0
  94. diffbio/operators/normalization/umap.py +261 -0
  95. diffbio/operators/normalization/vae_normalizer.py +258 -0
  96. diffbio/operators/population/__init__.py +17 -0
  97. diffbio/operators/population/ancestry_estimation.py +274 -0
  98. diffbio/operators/preprocessing/__init__.py +76 -0
  99. diffbio/operators/preprocessing/adapter_removal.py +311 -0
  100. diffbio/operators/preprocessing/duplicate_filter.py +317 -0
  101. diffbio/operators/preprocessing/error_correction.py +287 -0
  102. diffbio/operators/protein/__init__.py +31 -0
  103. diffbio/operators/protein/secondary_structure.py +509 -0
  104. diffbio/operators/quality_filter.py +128 -0
  105. diffbio/operators/rna_structure/__init__.py +35 -0
  106. diffbio/operators/rna_structure/rna_folding.py +509 -0
  107. diffbio/operators/rnaseq/__init__.py +23 -0
  108. diffbio/operators/rnaseq/motif_discovery.py +251 -0
  109. diffbio/operators/rnaseq/splicing_psi.py +216 -0
  110. diffbio/operators/singlecell/__init__.py +193 -0
  111. diffbio/operators/singlecell/ambient_removal.py +333 -0
  112. diffbio/operators/singlecell/archetypes.py +191 -0
  113. diffbio/operators/singlecell/batch_correction.py +288 -0
  114. diffbio/operators/singlecell/cell_annotation.py +519 -0
  115. diffbio/operators/singlecell/communication.py +704 -0
  116. diffbio/operators/singlecell/differential_distribution.py +243 -0
  117. diffbio/operators/singlecell/doublet_detection.py +657 -0
  118. diffbio/operators/singlecell/downsampling.py +166 -0
  119. diffbio/operators/singlecell/enhanced_batch_correction.py +519 -0
  120. diffbio/operators/singlecell/grn_inference.py +336 -0
  121. diffbio/operators/singlecell/imputation.py +429 -0
  122. diffbio/operators/singlecell/knockdown_filter.py +176 -0
  123. diffbio/operators/singlecell/ot_trajectory.py +277 -0
  124. diffbio/operators/singlecell/simulation.py +444 -0
  125. diffbio/operators/singlecell/sindy_grn.py +247 -0
  126. diffbio/operators/singlecell/soft_clustering.py +211 -0
  127. diffbio/operators/singlecell/spatial_domains.py +677 -0
  128. diffbio/operators/singlecell/switch_de.py +184 -0
  129. diffbio/operators/singlecell/trajectory.py +447 -0
  130. diffbio/operators/singlecell/velocity.py +361 -0
  131. diffbio/operators/statistical/__init__.py +35 -0
  132. diffbio/operators/statistical/em_quantification.py +260 -0
  133. diffbio/operators/statistical/hmm.py +234 -0
  134. diffbio/operators/statistical/nb_glm.py +272 -0
  135. diffbio/operators/variant/__init__.py +64 -0
  136. diffbio/operators/variant/classifier.py +333 -0
  137. diffbio/operators/variant/cnn_classifier.py +255 -0
  138. diffbio/operators/variant/cnv_segmentation.py +678 -0
  139. diffbio/operators/variant/deepvariant_pileup.py +426 -0
  140. diffbio/operators/variant/pileup.py +240 -0
  141. diffbio/operators/variant/quality_recalibration.py +274 -0
  142. diffbio/pipelines/__init__.py +65 -0
  143. diffbio/pipelines/differential_expression.py +279 -0
  144. diffbio/pipelines/enhanced_variant_calling.py +326 -0
  145. diffbio/pipelines/perturbation.py +407 -0
  146. diffbio/pipelines/preprocessing.py +267 -0
  147. diffbio/pipelines/single_cell.py +366 -0
  148. diffbio/pipelines/variant_calling.py +490 -0
  149. diffbio/samplers/__init__.py +9 -0
  150. diffbio/samplers/perturbation_sampler.py +142 -0
  151. diffbio/sequences/__init__.py +34 -0
  152. diffbio/sequences/dna.py +239 -0
  153. diffbio/sources/__init__.py +149 -0
  154. diffbio/sources/_anndata_shared.py +89 -0
  155. diffbio/sources/_batch_iteration.py +37 -0
  156. diffbio/sources/_benchmark_source.py +152 -0
  157. diffbio/sources/_indexed_batch_source.py +38 -0
  158. diffbio/sources/_utils.py +45 -0
  159. diffbio/sources/anndata_interop.py +387 -0
  160. diffbio/sources/anndata_source.py +361 -0
  161. diffbio/sources/archive_ii.py +174 -0
  162. diffbio/sources/balifam.py +207 -0
  163. diffbio/sources/bam.py +265 -0
  164. diffbio/sources/bengrn_ground_truth.py +306 -0
  165. diffbio/sources/contextual_epigenomics.py +242 -0
  166. diffbio/sources/dti.py +359 -0
  167. diffbio/sources/embeddings.py +203 -0
  168. diffbio/sources/encode_peaks.py +223 -0
  169. diffbio/sources/fasta.py +226 -0
  170. diffbio/sources/immune_human.py +172 -0
  171. diffbio/sources/indexed_embeddings.py +128 -0
  172. diffbio/sources/indexed_view.py +191 -0
  173. diffbio/sources/molnet.py +493 -0
  174. diffbio/sources/multiomics.py +279 -0
  175. diffbio/sources/pancreas.py +108 -0
  176. diffbio/sources/perturbation/__init__.py +69 -0
  177. diffbio/sources/perturbation/_types.py +51 -0
  178. diffbio/sources/perturbation/_utils.py +125 -0
  179. diffbio/sources/perturbation/concat_source.py +115 -0
  180. diffbio/sources/perturbation/control_mapping.py +215 -0
  181. diffbio/sources/perturbation/experiment_config.py +261 -0
  182. diffbio/sources/perturbation/h5_metadata_cache.py +218 -0
  183. diffbio/sources/perturbation/output_space.py +52 -0
  184. diffbio/sources/perturbation/perturbation_source.py +513 -0
  185. diffbio/sources/seqfish.py +145 -0
  186. diffbio/sources/sequence_foundation.py +68 -0
  187. diffbio/sources/singlecell_foundation.py +68 -0
  188. diffbio/splitters/__init__.py +63 -0
  189. diffbio/splitters/base.py +251 -0
  190. diffbio/splitters/molecular.py +330 -0
  191. diffbio/splitters/perturbation.py +199 -0
  192. diffbio/splitters/random.py +217 -0
  193. diffbio/splitters/sequence.py +201 -0
  194. diffbio/utils/__init__.py +55 -0
  195. diffbio/utils/dependency_runtime.py +115 -0
  196. diffbio/utils/nn_utils.py +157 -0
  197. diffbio/utils/quality.py +45 -0
  198. diffbio/utils/training.py +585 -0
  199. diffbio-0.1.0.dist-info/METADATA +480 -0
  200. diffbio-0.1.0.dist-info/RECORD +202 -0
  201. diffbio-0.1.0.dist-info/WHEEL +4 -0
  202. 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
+ ]