rust-sasa-python 0.2.2__tar.gz → 0.2.4__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.2 → rust_sasa_python-0.2.4}/Cargo.lock +1 -1
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/Cargo.toml +1 -1
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/DOCS.md +37 -0
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/PKG-INFO +3 -3
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/README.md +2 -2
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/src/lib.rs +45 -4
- rust_sasa_python-0.2.4/src/simd.rs +33 -0
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/.github/workflows/CI.yml +0 -0
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/.gitignore +0 -0
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/LICENSE.md +0 -0
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/example.cif +0 -0
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/pyproject.toml +0 -0
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/pytest.ini +0 -0
- /rust_sasa_python-0.2.2/rust-sasa-python.pyi → /rust_sasa_python-0.2.4/rust_sasa_python.pyi +0 -0
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/tests/__init__.py +0 -0
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/tests/test_sasa.py +0 -0
- {rust_sasa_python-0.2.2 → rust_sasa_python-0.2.4}/uv.lock +0 -0
|
@@ -119,6 +119,43 @@ sasa_values = sasa.calculate_sasa_internal(atoms, probe_radius=1.4, n_points=100
|
|
|
119
119
|
print(f"SASA values: {sasa_values}")
|
|
120
120
|
```
|
|
121
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
|
+
|
|
122
159
|
## Usage Examples
|
|
123
160
|
|
|
124
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.4
|
|
4
4
|
Classifier: Programming Language :: Rust
|
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
@@ -20,7 +20,7 @@ A high-performance **Python library** for computing SASA (Solvent Accessible Sur
|
|
|
20
20
|
|
|
21
21
|
## Features
|
|
22
22
|
|
|
23
|
-
- 🦀 **
|
|
23
|
+
- 🦀 **Powered by [RustSASA](https://github.com/maxall41/RustSASA)**: Leverages Rust's performance and safety.
|
|
24
24
|
- ⚡️ **Ludicrous Speed**: **46X** faster than Biopython, **7X** faster than Freesasa.
|
|
25
25
|
- 🐍 **Pythonic Interface**: Clean, intuitive API.
|
|
26
26
|
- 🔧 **Configurable**: Customizable probe radius and sampling points.
|
|
@@ -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
|
|
|
@@ -4,7 +4,7 @@ A high-performance **Python library** for computing SASA (Solvent Accessible Sur
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- 🦀 **
|
|
7
|
+
- 🦀 **Powered by [RustSASA](https://github.com/maxall41/RustSASA)**: Leverages Rust's performance and safety.
|
|
8
8
|
- ⚡️ **Ludicrous Speed**: **46X** faster than Biopython, **7X** faster than Freesasa.
|
|
9
9
|
- 🐍 **Pythonic Interface**: Clean, intuitive API.
|
|
10
10
|
- 🔧 **Configurable**: Customizable probe radius and sampling points.
|
|
@@ -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
|
|
|
@@ -3,8 +3,12 @@ use pdbtbx;
|
|
|
3
3
|
use pyo3::exceptions::PyRuntimeError;
|
|
4
4
|
use pyo3::prelude::*;
|
|
5
5
|
use rust_sasa::options::SASAOptions;
|
|
6
|
-
use rust_sasa::{Atom, calculate_sasa_internal as calculate_sasa_internal_internal};
|
|
7
|
-
use rust_sasa::{AtomLevel, ChainLevel, ProteinLevel, ResidueLevel};
|
|
6
|
+
use rust_sasa::{Atom, SASAProcessor, calculate_sasa_internal as calculate_sasa_internal_internal};
|
|
7
|
+
use rust_sasa::{AtomLevel, ChainLevel, ProteinLevel, ResidueLevel};
|
|
8
|
+
use simd::simd_sum; // As in long long
|
|
9
|
+
use std::collections::HashMap;
|
|
10
|
+
|
|
11
|
+
mod simd;
|
|
8
12
|
|
|
9
13
|
#[pyclass]
|
|
10
14
|
#[derive(Clone)]
|
|
@@ -35,7 +39,7 @@ pub struct Residue {
|
|
|
35
39
|
#[pyo3(get)]
|
|
36
40
|
pub residue_name: String,
|
|
37
41
|
#[pyo3(get)]
|
|
38
|
-
pub residue_number:
|
|
42
|
+
pub residue_number: u32,
|
|
39
43
|
#[pyo3(get)]
|
|
40
44
|
pub sasa: f32,
|
|
41
45
|
}
|
|
@@ -195,7 +199,7 @@ impl SASACalculator {
|
|
|
195
199
|
residue_results.push(Residue {
|
|
196
200
|
chain_id: result.chain_id,
|
|
197
201
|
residue_name: result.name,
|
|
198
|
-
residue_number: result.serial_number as
|
|
202
|
+
residue_number: result.serial_number as u32,
|
|
199
203
|
sasa: result.value,
|
|
200
204
|
});
|
|
201
205
|
}
|
|
@@ -316,6 +320,39 @@ pub fn calculate_sasa_internal(
|
|
|
316
320
|
))
|
|
317
321
|
}
|
|
318
322
|
|
|
323
|
+
#[pyfunction]
|
|
324
|
+
fn calculate_sasa_internal_at_residue_level(
|
|
325
|
+
atoms_in: Vec<((f32, f32, f32), f32, usize)>,
|
|
326
|
+
probe_radius: f32,
|
|
327
|
+
n_points: usize,
|
|
328
|
+
) -> PyResult<Vec<Residue>> {
|
|
329
|
+
let atom_sasa = calculate_sasa_internal(atoms_in.clone(), probe_radius, n_points).unwrap();
|
|
330
|
+
|
|
331
|
+
let mut residue_groups: HashMap<usize, Vec<f32>> = HashMap::new();
|
|
332
|
+
|
|
333
|
+
for (i, atom) in atoms_in.iter().enumerate() {
|
|
334
|
+
let parent_id = atom.2;
|
|
335
|
+
residue_groups
|
|
336
|
+
.entry(parent_id)
|
|
337
|
+
.or_insert_with(Vec::new)
|
|
338
|
+
.push(atom_sasa[i]);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
let mut residue_sasa = Vec::new();
|
|
342
|
+
for (parent_id, sasa_values) in residue_groups {
|
|
343
|
+
let local_sum = simd_sum(sasa_values.as_slice());
|
|
344
|
+
|
|
345
|
+
residue_sasa.push(Residue {
|
|
346
|
+
chain_id: "UNK".to_string(),
|
|
347
|
+
residue_name: "UNK".to_string(),
|
|
348
|
+
residue_number: parent_id as u32,
|
|
349
|
+
sasa: local_sum,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
Ok(residue_sasa)
|
|
354
|
+
}
|
|
355
|
+
|
|
319
356
|
#[pymodule]
|
|
320
357
|
fn rust_sasa_python(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
321
358
|
m.add_class::<SASACalculator>()?;
|
|
@@ -329,6 +366,10 @@ fn rust_sasa_python(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
|
329
366
|
m.add_function(wrap_pyfunction!(calculate_atom_sasa, m)?)?;
|
|
330
367
|
m.add_function(wrap_pyfunction!(calculate_chain_sasa, m)?)?;
|
|
331
368
|
m.add_function(wrap_pyfunction!(calculate_sasa_internal, m)?)?;
|
|
369
|
+
m.add_function(wrap_pyfunction!(
|
|
370
|
+
calculate_sasa_internal_at_residue_level,
|
|
371
|
+
m
|
|
372
|
+
)?)?;
|
|
332
373
|
|
|
333
374
|
Ok(())
|
|
334
375
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const LANES: usize = 16;
|
|
2
|
+
#[allow(clippy::needless_range_loop)]
|
|
3
|
+
pub fn simd_sum(values: &[f32]) -> f32 {
|
|
4
|
+
let chunks = values.chunks_exact(LANES);
|
|
5
|
+
let remainder = chunks.remainder();
|
|
6
|
+
|
|
7
|
+
let sum = chunks.fold([0.0f32; LANES], |mut acc, chunk| {
|
|
8
|
+
let chunk: [f32; LANES] = chunk.try_into().unwrap();
|
|
9
|
+
for i in 0..LANES {
|
|
10
|
+
acc[i] += chunk[i];
|
|
11
|
+
}
|
|
12
|
+
acc
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
let remainder: f32 = remainder.iter().copied().sum();
|
|
16
|
+
|
|
17
|
+
let mut reduced = 0.0f32;
|
|
18
|
+
for i in 0..LANES {
|
|
19
|
+
reduced += sum[i];
|
|
20
|
+
}
|
|
21
|
+
reduced + remainder
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
pub(crate) fn serialize_chain_id(s: &str) -> isize {
|
|
25
|
+
let mut result = 0;
|
|
26
|
+
for c in s.chars() {
|
|
27
|
+
if c.is_ascii_alphabetic() {
|
|
28
|
+
let position = c.to_ascii_uppercase() as isize - 64;
|
|
29
|
+
result = result * 10 + position;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
result
|
|
33
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|