rust-sasa-python 0.2.1__tar.gz → 0.2.3__tar.gz
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.
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/.github/workflows/CI.yml +1 -1
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/Cargo.lock +2 -1
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/Cargo.toml +2 -1
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/DOCS.md +72 -0
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/PKG-INFO +2 -2
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/README.md +1 -1
- rust_sasa_python-0.2.1/rust-sasa-python.pyi → rust_sasa_python-0.2.3/rust_sasa_python.pyi +17 -0
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/src/lib.rs +67 -3
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/uv.lock +1 -1
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/.gitignore +0 -0
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/LICENSE.md +0 -0
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/example.cif +0 -0
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/pyproject.toml +0 -0
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/pytest.ini +0 -0
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/tests/__init__.py +0 -0
- {rust_sasa_python-0.2.1 → rust_sasa_python-0.2.3}/tests/test_sasa.py +0 -0
|
@@ -138,7 +138,7 @@ jobs:
|
|
|
138
138
|
name: Release
|
|
139
139
|
runs-on: ubuntu-latest
|
|
140
140
|
needs: [linux, windows, macos, sdist, test]
|
|
141
|
-
if: github.
|
|
141
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
142
142
|
steps:
|
|
143
143
|
- uses: actions/download-artifact@v4
|
|
144
144
|
- name: Publish to PyPI
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "rust-sasa-python"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.3"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
|
|
6
6
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
@@ -12,3 +12,4 @@ crate-type = ["cdylib"]
|
|
|
12
12
|
pdbtbx = "0.12.0"
|
|
13
13
|
pyo3 = "0.25.1"
|
|
14
14
|
rust-sasa = "0.3.2"
|
|
15
|
+
nalgebra = "0.33.2"
|
|
@@ -84,6 +84,78 @@ atom_results = sasa.calculate_atom_sasa("protein.pdb")
|
|
|
84
84
|
chain_results = sasa.calculate_chain_sasa("protein.pdb")
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
### Low-level Functions
|
|
88
|
+
|
|
89
|
+
For advanced use cases where you need to calculate SASA for custom atom sets:
|
|
90
|
+
|
|
91
|
+
**`calculate_sasa_internal(atoms_in: list[tuple[tuple[float, float, float], float, int]], probe_radius: float, n_points: int) -> list[float]`**
|
|
92
|
+
|
|
93
|
+
Calculate SASA for a set of atoms directly without PDB file parsing.
|
|
94
|
+
|
|
95
|
+
**Parameters:**
|
|
96
|
+
- `atoms_in`: List of tuples, each containing:
|
|
97
|
+
- Atom coordinates as `(x, y, z)` tuple of floats
|
|
98
|
+
- Atom radius as float
|
|
99
|
+
- Atom index as int
|
|
100
|
+
- `probe_radius`: Probe sphere radius in Ångströms
|
|
101
|
+
- `n_points`: Number of points for surface sampling
|
|
102
|
+
|
|
103
|
+
**Returns:**
|
|
104
|
+
- List of SASA values (floats) corresponding to each input atom
|
|
105
|
+
|
|
106
|
+
**Example:**
|
|
107
|
+
```python
|
|
108
|
+
import rust_sasa_python as sasa
|
|
109
|
+
|
|
110
|
+
# Define atoms: [(coordinates, radius, index), ...]
|
|
111
|
+
atoms = [
|
|
112
|
+
((0.0, 0.0, 0.0), 1.7, 0), # Carbon atom
|
|
113
|
+
((2.0, 0.0, 0.0), 1.2, 1), # Hydrogen atom
|
|
114
|
+
((0.0, 2.0, 0.0), 1.55, 2), # Nitrogen atom
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
# Calculate SASA
|
|
118
|
+
sasa_values = sasa.calculate_sasa_internal(atoms, probe_radius=1.4, n_points=100)
|
|
119
|
+
print(f"SASA values: {sasa_values}")
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**`calculate_sasa_internal_at_residue_level(atoms_in: list[tuple[tuple[float, float, float], float, int]], probe_radius: float, n_points: int) -> list[ResidueResult]`**
|
|
123
|
+
|
|
124
|
+
Calculate SASA at the residue level for a set of atoms directly without PDB file parsing. This function groups atoms by residue ID and calculates the average SASA per atom within each residue.
|
|
125
|
+
|
|
126
|
+
**Parameters:**
|
|
127
|
+
- `atoms_in`: List of tuples, each containing:
|
|
128
|
+
- Atom coordinates as `(x, y, z)` tuple of floats
|
|
129
|
+
- Atom radius as float
|
|
130
|
+
- Residue ID as int (used to group atoms into residues)
|
|
131
|
+
- `probe_radius`: Probe sphere radius in Ångströms
|
|
132
|
+
- `n_points`: Number of points for surface sampling
|
|
133
|
+
|
|
134
|
+
**Returns:**
|
|
135
|
+
- List of `ResidueResult` objects with:
|
|
136
|
+
- `chain_id`: Always "UNK" (unknown)
|
|
137
|
+
- `residue_name`: Always "UNK" (unknown)
|
|
138
|
+
- `residue_number`: The residue ID from input
|
|
139
|
+
- `sasa`: Average SASA per atom in the residue
|
|
140
|
+
|
|
141
|
+
**Example:**
|
|
142
|
+
```python
|
|
143
|
+
import rust_sasa_python as sasa
|
|
144
|
+
|
|
145
|
+
# Define atoms with residue grouping
|
|
146
|
+
# Residue 1: two atoms, Residue 2: one atom
|
|
147
|
+
atoms = [
|
|
148
|
+
((0.0, 0.0, 0.0), 1.7, 1), # Carbon in residue 1
|
|
149
|
+
((1.5, 0.0, 0.0), 1.2, 1), # Hydrogen in residue 1
|
|
150
|
+
((0.0, 3.0, 0.0), 1.55, 2), # Nitrogen in residue 2
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
# Calculate residue-level SASA
|
|
154
|
+
residues = sasa.calculate_sasa_internal_at_residue_level(atoms, probe_radius=1.4, n_points=100)
|
|
155
|
+
for residue in residues:
|
|
156
|
+
print(f"Residue {residue.residue_number}: {residue.sasa:.2f} Ų (avg per atom)")
|
|
157
|
+
```
|
|
158
|
+
|
|
87
159
|
## Usage Examples
|
|
88
160
|
|
|
89
161
|
### Basic Usage
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rust-sasa-python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
@@ -51,7 +51,7 @@ print(f"Polar SASA: {result.polar:.2f}")
|
|
|
51
51
|
print(f"Non-polar SASA: {result.non_polar:.2f}")
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
See [DOCS](DOCS.md) for more information and API reference.
|
|
54
|
+
See [DOCS](https://github.com/maxall41/rust-sasa-python/blob/main/DOCS.md) for more information and API reference.
|
|
55
55
|
|
|
56
56
|
## Contributing
|
|
57
57
|
|
|
@@ -35,7 +35,7 @@ print(f"Polar SASA: {result.polar:.2f}")
|
|
|
35
35
|
print(f"Non-polar SASA: {result.non_polar:.2f}")
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
See [DOCS](DOCS.md) for more information and API reference.
|
|
38
|
+
See [DOCS](https://github.com/maxall41/rust-sasa-python/blob/main/DOCS.md) for more information and API reference.
|
|
39
39
|
|
|
40
40
|
## Contributing
|
|
41
41
|
|
|
@@ -132,3 +132,20 @@ def calculate_chain_sasa(pdb_path: str) -> List[Chain]:
|
|
|
132
132
|
List[Chain]: List of chain-level SASA results
|
|
133
133
|
|
|
134
134
|
"""
|
|
135
|
+
|
|
136
|
+
def calculate_sasa_internal(
|
|
137
|
+
atoms_in: list[tuple[tuple[float, float, float], float, int]],
|
|
138
|
+
probe_radius: float,
|
|
139
|
+
n_points: int,
|
|
140
|
+
) -> list[float]:
|
|
141
|
+
"""Calculate SASA for a set of atoms.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
atoms_in: List of atom coordinates, radii, and indices
|
|
145
|
+
probe_radius: Probe radius
|
|
146
|
+
n_points: Number of points on the sphere
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
List[float]: List of SASA values
|
|
150
|
+
|
|
151
|
+
"""
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
use nalgebra::Point3;
|
|
1
2
|
use pdbtbx;
|
|
2
3
|
use pyo3::exceptions::PyRuntimeError;
|
|
3
4
|
use pyo3::prelude::*;
|
|
4
5
|
use rust_sasa::options::SASAOptions;
|
|
5
|
-
use rust_sasa::{
|
|
6
|
+
use rust_sasa::{Atom, SASAProcessor, calculate_sasa_internal as calculate_sasa_internal_internal};
|
|
7
|
+
use rust_sasa::{AtomLevel, ChainLevel, ProteinLevel, ResidueLevel}; // As in long long
|
|
8
|
+
use std::collections::HashMap;
|
|
6
9
|
|
|
7
10
|
#[pyclass]
|
|
8
11
|
#[derive(Clone)]
|
|
@@ -33,7 +36,7 @@ pub struct Residue {
|
|
|
33
36
|
#[pyo3(get)]
|
|
34
37
|
pub residue_name: String,
|
|
35
38
|
#[pyo3(get)]
|
|
36
|
-
pub residue_number:
|
|
39
|
+
pub residue_number: u32,
|
|
37
40
|
#[pyo3(get)]
|
|
38
41
|
pub sasa: f32,
|
|
39
42
|
}
|
|
@@ -193,7 +196,7 @@ impl SASACalculator {
|
|
|
193
196
|
residue_results.push(Residue {
|
|
194
197
|
chain_id: result.chain_id,
|
|
195
198
|
residue_name: result.name,
|
|
196
|
-
residue_number: result.serial_number as
|
|
199
|
+
residue_number: result.serial_number as u32,
|
|
197
200
|
sasa: result.value,
|
|
198
201
|
});
|
|
199
202
|
}
|
|
@@ -291,6 +294,62 @@ pub fn calculate_chain_sasa(pdb_path: String) -> PyResult<Vec<Chain>> {
|
|
|
291
294
|
SASACalculator::new(pdb_path).calculate_chain()
|
|
292
295
|
}
|
|
293
296
|
|
|
297
|
+
#[pyfunction]
|
|
298
|
+
pub fn calculate_sasa_internal(
|
|
299
|
+
atoms_in: Vec<((f32, f32, f32), f32, usize)>,
|
|
300
|
+
probe_radius: f32,
|
|
301
|
+
n_points: usize,
|
|
302
|
+
) -> PyResult<Vec<f32>> {
|
|
303
|
+
let atoms: Vec<Atom> = atoms_in
|
|
304
|
+
.into_iter()
|
|
305
|
+
.map(|(pos, radius, index)| Atom {
|
|
306
|
+
position: Point3::new(pos.0, pos.1, pos.2),
|
|
307
|
+
id: index,
|
|
308
|
+
parent_id: None,
|
|
309
|
+
radius,
|
|
310
|
+
})
|
|
311
|
+
.collect();
|
|
312
|
+
Ok(calculate_sasa_internal_internal(
|
|
313
|
+
atoms.as_slice(),
|
|
314
|
+
probe_radius,
|
|
315
|
+
n_points,
|
|
316
|
+
true,
|
|
317
|
+
))
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
#[pyfunction]
|
|
321
|
+
fn calculate_sasa_internal_at_residue_level(
|
|
322
|
+
atoms_in: Vec<((f32, f32, f32), f32, usize)>,
|
|
323
|
+
probe_radius: f32,
|
|
324
|
+
n_points: usize,
|
|
325
|
+
) -> PyResult<Vec<Residue>> {
|
|
326
|
+
let atom_sasa = calculate_sasa_internal(atoms_in.clone(), probe_radius, n_points).unwrap();
|
|
327
|
+
|
|
328
|
+
let mut residue_groups: HashMap<usize, Vec<f32>> = HashMap::new();
|
|
329
|
+
|
|
330
|
+
for (i, atom) in atoms_in.iter().enumerate() {
|
|
331
|
+
let parent_id = atom.2;
|
|
332
|
+
residue_groups
|
|
333
|
+
.entry(parent_id)
|
|
334
|
+
.or_insert_with(Vec::new)
|
|
335
|
+
.push(atom_sasa[i]);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
let mut residue_sasa = Vec::new();
|
|
339
|
+
for (parent_id, sasa_values) in residue_groups {
|
|
340
|
+
let local_sum = sasa_values.iter().sum::<f32>();
|
|
341
|
+
|
|
342
|
+
residue_sasa.push(Residue {
|
|
343
|
+
chain_id: "UNK".to_string(),
|
|
344
|
+
residue_name: "UNK".to_string(),
|
|
345
|
+
residue_number: parent_id as u32,
|
|
346
|
+
sasa: local_sum / sasa_values.len() as f32,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
Ok(residue_sasa)
|
|
351
|
+
}
|
|
352
|
+
|
|
294
353
|
#[pymodule]
|
|
295
354
|
fn rust_sasa_python(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
296
355
|
m.add_class::<SASACalculator>()?;
|
|
@@ -303,6 +362,11 @@ fn rust_sasa_python(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
|
303
362
|
m.add_function(wrap_pyfunction!(calculate_residue_sasa, m)?)?;
|
|
304
363
|
m.add_function(wrap_pyfunction!(calculate_atom_sasa, m)?)?;
|
|
305
364
|
m.add_function(wrap_pyfunction!(calculate_chain_sasa, m)?)?;
|
|
365
|
+
m.add_function(wrap_pyfunction!(calculate_sasa_internal, m)?)?;
|
|
366
|
+
m.add_function(wrap_pyfunction!(
|
|
367
|
+
calculate_sasa_internal_at_residue_level,
|
|
368
|
+
m
|
|
369
|
+
)?)?;
|
|
306
370
|
|
|
307
371
|
Ok(())
|
|
308
372
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|