synth-dynamics 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.
@@ -0,0 +1,6 @@
1
+ from .system import System
2
+ from .forcefield import ANMForceField
3
+ from .integrator import LangevinIntegrator
4
+ from .simulation import Simulation
5
+
6
+ __all__ = ["System", "ANMForceField", "LangevinIntegrator", "Simulation"]
@@ -0,0 +1,57 @@
1
+ import numpy as np
2
+ from scipy.spatial.distance import pdist, squareform
3
+
4
+ class ANMForceField:
5
+ def __init__(self, equilibrium_coords, cutoff=15.0, spring_constant=1.0):
6
+ """
7
+ Anisotropic Network Model Force Field.
8
+
9
+ Args:
10
+ equilibrium_coords: (N, 3) array of C-alpha equilibrium positions.
11
+ cutoff: Distance cutoff for interactions in Angstroms.
12
+ spring_constant: Uniform spring constant k.
13
+ """
14
+ self.x0 = equilibrium_coords
15
+ self.cutoff = cutoff
16
+ self.k = spring_constant
17
+ self.n_atoms = len(equilibrium_coords)
18
+
19
+ # Precompute equilibrium distances and adjacency matrix
20
+ dist_matrix = squareform(pdist(self.x0))
21
+ self.adj = (dist_matrix < cutoff) & (dist_matrix > 0)
22
+ self.r0 = dist_matrix
23
+
24
+ def compute_forces(self, current_coords):
25
+ """
26
+ Computes the harmonic forces on each atom.
27
+
28
+ Args:
29
+ current_coords: (N, 3) array of current positions.
30
+ Returns:
31
+ forces: (N, 3) array of forces.
32
+ """
33
+ # Calculate current distances and difference vectors
34
+ # diff[i, j] = r_i - r_j
35
+ diff = current_coords[:, np.newaxis, :] - current_coords[np.newaxis, :, :]
36
+ dist = np.linalg.norm(diff, axis=2)
37
+
38
+ # Avoid division by zero
39
+ dist_inv = np.zeros_like(dist)
40
+ mask = dist > 0
41
+ dist_inv[mask] = 1.0 / dist[mask]
42
+
43
+ # Force magnitude matrix: F_ij = -k * (r_ij - r0_ij)
44
+ # We only care about pairs in the adjacency matrix
45
+ force_mag = -self.k * (dist - self.r0)
46
+
47
+ # Full force vector matrix: F_vec_ij = F_ij * (diff_ij / dist_ij)
48
+ # Shape: (N, N, 3)
49
+ force_vecs = (force_mag * dist_inv)[:, :, np.newaxis] * diff
50
+
51
+ # Zero out inactive interactions
52
+ force_vecs[~self.adj] = 0.0
53
+
54
+ # Total force on atom i is sum over j
55
+ forces = np.sum(force_vecs, axis=1)
56
+
57
+ return forces
@@ -0,0 +1,39 @@
1
+ import numpy as np
2
+
3
+ class LangevinIntegrator:
4
+ def __init__(self, dt=0.1, temperature=300.0, friction=1.0):
5
+ """
6
+ Overdamped Langevin (Brownian) Integrator.
7
+
8
+ Args:
9
+ dt: Time step.
10
+ temperature: Temperature in Kelvin.
11
+ friction: Friction coefficient (gamma).
12
+ """
13
+ self.dt = dt
14
+ self.T = temperature
15
+ self.gamma = friction
16
+ self.kb = 0.0019872041 # Boltzmann constant in kcal/(mol*K)
17
+
18
+ def step(self, positions, forces):
19
+ """
20
+ Performs a single integration step.
21
+
22
+ x(t+dt) = x(t) + (dt/gamma) * F + sqrt(2 * kb * T * dt / gamma) * R
23
+
24
+ Args:
25
+ positions: (N, 3) array of current positions.
26
+ forces: (N, 3) array of current forces.
27
+ Returns:
28
+ new_positions: (N, 3) array of updated positions.
29
+ """
30
+ n_atoms = positions.shape[0]
31
+
32
+ # Deterministic term
33
+ drift = (self.dt / self.gamma) * forces
34
+
35
+ # Stochastic term
36
+ sigma = np.sqrt(2.0 * self.kb * self.T * self.dt / self.gamma)
37
+ random_force = sigma * np.random.normal(size=(n_atoms, 3))
38
+
39
+ return positions + drift + random_force
@@ -0,0 +1,40 @@
1
+ import MDAnalysis as mda
2
+ from .system import System
3
+ from .forcefield import ANMForceField
4
+ from .integrator import LangevinIntegrator
5
+
6
+ class Simulation:
7
+ def __init__(self, system, forcefield, integrator):
8
+ """
9
+ Orchestrates the Langevin dynamics simulation.
10
+
11
+ Args:
12
+ system: System instance.
13
+ forcefield: ForceField instance.
14
+ integrator: Integrator instance.
15
+ """
16
+ self.system = system
17
+ self.ff = forcefield
18
+ self.integrator = integrator
19
+
20
+ def run(self, n_steps, output_path, stride=10):
21
+ """
22
+ Runs the simulation and saves the trajectory.
23
+
24
+ Args:
25
+ n_steps: Total number of integration steps.
26
+ output_path: Path to save the trajectory (e.g., .dcd or .pdb).
27
+ stride: Frequency of saving frames.
28
+ """
29
+ writer = mda.Writer(output_path, self.system.n_atoms)
30
+
31
+ for i in range(n_steps):
32
+ forces = self.ff.compute_forces(self.system.positions)
33
+ new_positions = self.integrator.step(self.system.positions, forces)
34
+ self.system.positions = new_positions
35
+
36
+ if i % stride == 0:
37
+ writer.write(self.system.ca_atoms)
38
+
39
+ writer.close()
40
+ print(f"Simulation complete. Trajectory saved to {output_path}")
@@ -0,0 +1,28 @@
1
+ import MDAnalysis as mda
2
+ import numpy as np
3
+
4
+ class System:
5
+ def __init__(self, pdb_path: str):
6
+ """
7
+ Initializes the system by loading a PDB file and extracting C-alpha atoms.
8
+
9
+ Args:
10
+ pdb_path: Path to the input PDB file.
11
+ """
12
+ self.universe = mda.Universe(pdb_path)
13
+ self.ca_atoms = self.universe.select_atoms("name CA")
14
+
15
+ if len(self.ca_atoms) == 0:
16
+ raise ValueError(f"No C-alpha atoms found in {pdb_path}")
17
+
18
+ # Store equilibrium coordinates (reference state)
19
+ self.equilibrium_coords = self.ca_atoms.positions.copy()
20
+ self.n_atoms = len(self.ca_atoms)
21
+
22
+ @property
23
+ def positions(self):
24
+ return self.ca_atoms.positions
25
+
26
+ @positions.setter
27
+ def positions(self, new_positions):
28
+ self.ca_atoms.positions = new_positions
@@ -0,0 +1,100 @@
1
+ Metadata-Version: 2.4
2
+ Name: synth-dynamics
3
+ Version: 0.1.0
4
+ Summary: Time-Resolved Ensemble Generator using Coarse-Grained ENM Langevin Dynamics
5
+ Author: George Elkins
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/georgeelkins/synth-dynamics
8
+ Project-URL: Repository, https://github.com/georgeelkins/synth-dynamics
9
+ Project-URL: Documentation, https://synth-dynamics.readthedocs.io/
10
+ Project-URL: Bug Tracker, https://github.com/georgeelkins/synth-dynamics/issues
11
+ Keywords: molecular-dynamics,protein-dynamics,ANM,Langevin,ensemble-generation
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
15
+ Classifier: Topic :: Scientific/Engineering :: Physics
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Operating System :: OS Independent
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: numpy
25
+ Requires-Dist: MDAnalysis
26
+ Requires-Dist: scipy
27
+ Provides-Extra: docs
28
+ Requires-Dist: sphinx; extra == "docs"
29
+ Requires-Dist: sphinx_rtd_theme; extra == "docs"
30
+ Dynamic: license-file
31
+
32
+ # synth-dynamics: Time-Resolved Ensemble Generator
33
+
34
+ `synth-dynamics` is a fast, lightweight molecular dynamics engine designed to generate meaningful conformational ensembles of proteins. Unlike full-atom simulations (like GROMACS or Amber), `synth-dynamics` uses a **Coarse-Grained Anisotropic Network Model (ANM)** and **Langevin dynamics** to capture the essential global motions of proteins with minimal computational overhead.
35
+
36
+ This tool is designed to bridge the gap between static structures and time-averaged experimental observables, such as NMR relaxation parameters, SAXS Kratky plots, or FRET efficiency distributions.
37
+
38
+ ## Key Features
39
+
40
+ - **Coarse-Grained Simulation**: Models proteins using C-alpha atoms and harmonic "spring" networks.
41
+ - **Fast Langevin Engine**: Propagates coordinates using a stable, overdamped Langevin integrator.
42
+ - **Experimental Integration**: Perfect for generating the structural ensembles needed for `synth-nmr` or `synth-saxs`.
43
+ - **Easy to Use**: Simple API for loading PDBs, configuring forcefields, and running simulations.
44
+ - **Extensively Tested**: 100% test coverage ensuring reliability and correctness.
45
+
46
+ ## Installation
47
+
48
+ `synth-dynamics` requires Python 3.10+ and the following dependencies:
49
+
50
+ ```bash
51
+ pip install numpy MDAnalysis scipy
52
+ ```
53
+
54
+ To install the documentation theme:
55
+ ```bash
56
+ pip install sphinx_rtd_theme
57
+ ```
58
+
59
+ ## Quick Start
60
+
61
+ Running a simulation is straightforward:
62
+
63
+ ```python
64
+ from synth_dynamics import System, ANMForceField, LangevinIntegrator, Simulation
65
+
66
+ # 1. Load the system (automatically filters for C-alpha atoms)
67
+ system = System("protein.pdb")
68
+
69
+ # 2. Define the Anisotropic Network Model forcefield
70
+ # Cutoff (15A) and spring constant determine the flexibility
71
+ ff = ANMForceField(system.equilibrium_coords, cutoff=15.0, spring_constant=1.0)
72
+
73
+ # 3. Initialize the Langevin integrator (dt in fs, T in Kelvin)
74
+ integrator = LangevinIntegrator(dt=0.1, temperature=300.0, friction=1.0)
75
+
76
+ # 4. Run and save the trajectory
77
+ sim = Simulation(system, ff, integrator)
78
+ sim.run(n_steps=1000, output_path="trajectory.dcd", stride=10)
79
+ ```
80
+
81
+ ## Documentation
82
+
83
+ Full API documentation and usage guides are available in the `docs/` directory. You can build the HTML documentation locally:
84
+
85
+ ```bash
86
+ cd docs
87
+ sphinx-build -b html . _build/html
88
+ ```
89
+
90
+ ## Testing
91
+
92
+ To run the test suite and verify coverage:
93
+
94
+ ```bash
95
+ PYTHONPATH=. pytest --cov=synth_dynamics tests/
96
+ ```
97
+
98
+ ## License
99
+
100
+ This project is licensed under the MIT License - see the LICENSE file for details (if applicable).
@@ -0,0 +1,10 @@
1
+ synth_dynamics/__init__.py,sha256=o_OJWCEU3hUTQY0y9NhT_UikVJZEv8HWAEJj5DrPAcI,218
2
+ synth_dynamics/forcefield.py,sha256=ZXJ9soNd52pYUnO4oLxR-CKESNHcdgtlzm2iQFrYLXE,2044
3
+ synth_dynamics/integrator.py,sha256=TiVLtxgAARtLEUKoTJnb5DS7DOJWpf74acS0qRe1etU,1251
4
+ synth_dynamics/simulation.py,sha256=h0x6QT4s5DrsL0Zhbx0yZwH84GI62XNhc0gN3AVSLys,1383
5
+ synth_dynamics/system.py,sha256=xwzOwXf7_wFUSE27A5_Ndd58bMSaPW3H7EqyEHcgGJE,878
6
+ synth_dynamics-0.1.0.dist-info/licenses/LICENSE,sha256=vhOY8MmX_KvSe6pbSfjbPEoceqNPv_Hoaz6BXrKS6rI,1070
7
+ synth_dynamics-0.1.0.dist-info/METADATA,sha256=h1H5Wmyqf1TrmndGlCCOzHHDsDoQufYUu_jObELE1FE,3817
8
+ synth_dynamics-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
9
+ synth_dynamics-0.1.0.dist-info/top_level.txt,sha256=Hg-LJU210eYBuiyW4HYA3g82mAgNmZYcUBksa4Gii3I,15
10
+ synth_dynamics-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 George Elkins
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ synth_dynamics