Skip to main content

cyanea_struct/
lib.rs

1//! Protein and nucleic acid 3D structures for the Cyanea bioinformatics ecosystem.
2//!
3//! - **PDB parsing** — Read macromolecular structure files with [`pdb::parse_pdb`]
4//! - **mmCIF parsing** — Read PDBx/mmCIF files with [`mmcif::parse_mmcif`]
5//! - **Coordinate geometry** — Distance, angle, dihedral, RMSD in [`geometry`]
6//! - **Secondary structure** — Simplified and full DSSP assignment in [`secondary`]
7//! - **Superposition** — Kabsch structural alignment in [`superposition`]
8//! - **Contact maps** — Residue-residue contact analysis in [`contact`]
9//! - **Ramachandran** — Backbone dihedral validation in [`ramachandran`]
10//! - **B-factor analysis** — Flexibility scoring in [`analysis`]
11//!
12//! # Quick start
13//!
14//! ```
15//! use cyanea_struct::pdb::parse_pdb;
16//! use cyanea_struct::types::Structure;
17//! use cyanea_core::Summarizable;
18//!
19//! let pdb_text = "\
20//! HEADER                                                        1TST
21//! ATOM      1  N   ALA A   1       1.000   2.000   3.000  1.00  0.00           N
22//! ATOM      2  CA  ALA A   1       2.000   2.000   3.000  1.00  0.00           C
23//! ATOM      3  C   ALA A   1       3.000   2.000   3.000  1.00  0.00           C
24//! ATOM      4  O   ALA A   1       3.000   3.000   3.000  1.00  0.00           O
25//! TER
26//! END
27//! ";
28//!
29//! let structure = parse_pdb(pdb_text).unwrap();
30//! assert_eq!(structure.chain_count(), 1);
31//! assert!(structure.summary().contains("1TST"));
32//! ```
33
34#![no_std]
35
36extern crate alloc;
37
38#[cfg(feature = "std")]
39extern crate std;
40
41pub mod analysis;
42pub mod contact;
43pub mod geometry;
44mod linalg;
45pub mod mmcif;
46pub mod pdb;
47pub mod ramachandran;
48pub mod secondary;
49pub mod superposition;
50pub mod types;
51
52pub use analysis::{chain_bfactors, flexibility_score, residue_bfactors, BFactorStats};
53pub use contact::{compute_contact_map, compute_contact_map_allatom, ContactMap};
54pub use geometry::{angle, angle_points, center_of_mass, dihedral, dihedral_points, distance};
55pub use mmcif::parse_mmcif;
56pub use pdb::parse_pdb;
57pub use ramachandran::{ramachandran_report, validate_ramachandran, RamachandranRegion};
58pub use secondary::{
59    assign_secondary_structure, backbone_dihedrals, dssp, DsspAssignment, DsspState,
60    SecondaryStructure, SecondaryStructureAssignment,
61};
62pub use superposition::{kabsch, kabsch_points, SuperpositionResult};
63pub use types::{Atom, Chain, Point3D, Residue, Structure};
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68    use cyanea_core::Summarizable;
69
70    #[test]
71    fn integration_parse_and_analyze() {
72        let pdb_text = "\
73HEADER                                                        1INT\n\
74ATOM      1  N   ALA A   1       0.000   0.000   0.000  1.00  0.00           N\n\
75ATOM      2  CA  ALA A   1       1.458   0.000   0.000  1.00  0.00           C\n\
76ATOM      3  C   ALA A   1       2.009   1.420   0.000  1.00  0.00           C\n\
77ATOM      4  O   ALA A   1       1.246   2.390   0.000  1.00  0.00           O\n\
78ATOM      5  N   GLY A   2       3.325   1.506   0.000  1.00  0.00           N\n\
79ATOM      6  CA  GLY A   2       3.988   2.802   0.000  1.00  0.00           C\n\
80ATOM      7  C   GLY A   2       5.504   2.714   0.000  1.00  0.00           C\n\
81ATOM      8  O   GLY A   2       6.092   1.635   0.000  1.00  0.00           O\n\
82ATOM      9  N   VAL A   3       6.120   3.898   0.000  1.00  0.00           N\n\
83ATOM     10  CA  VAL A   3       7.574   3.984   0.000  1.00  0.00           C\n\
84ATOM     11  C   VAL A   3       8.173   2.578   0.000  1.00  0.00           C\n\
85ATOM     12  O   VAL A   3       9.398   2.445   0.000  1.00  0.00           O\n\
86TER\n\
87END\n";
88
89        let s = parse_pdb(pdb_text).unwrap();
90        assert_eq!(s.id, "1INT");
91        assert_eq!(s.chain_count(), 1);
92        assert_eq!(s.residue_count(), 3);
93        assert!(s.summary().contains("3 residue"));
94
95        // Contact map
96        let chain = s.get_chain('A').unwrap();
97        let cm = compute_contact_map(chain).unwrap();
98        assert_eq!(cm.size, 3);
99        assert!(cm.get(0, 0).abs() < 1e-10); // diagonal
100
101        // SS assignment
102        let ss = assign_secondary_structure(chain).unwrap();
103        assert_eq!(ss.assignments.len(), 3);
104    }
105}