@@ -18,6 +18,17 @@ pub struct Bead {
1818 pub position : Vector3 < f64 > ,
1919}
2020
21+ #[ derive( Debug , Clone ) ]
22+ pub struct Pair {
23+ pub chain_i : String ,
24+ pub res_i : isize ,
25+ pub atom_i : String ,
26+ pub chain_j : String ,
27+ pub res_j : isize ,
28+ pub atom_j : String ,
29+ pub distance : f64 ,
30+ }
31+
2132/// Performs a neighbor search for residues within a specified radius of target residues.
2233///
2334/// This function uses a K-d tree to efficiently find residues that are within a given radius
@@ -623,6 +634,88 @@ pub fn process_pdb(input_pdb: &str) -> BufReader<Cursor<Vec<u8>>> {
623634 pdb_handler:: pad_lines ( temp_path)
624635}
625636
637+ /// Finds the closest residue pairs between different protein chains within a specified distance cutoff.
638+ ///
639+ /// This function analyzes inter-chain interactions by identifying the closest atom pairs between residues
640+ /// from different chains, using the alpha carbon (CA) atoms for distance calculation.
641+ ///
642+ /// # Arguments
643+ ///
644+ /// * pdb - A reference to a parsed PDB structure.
645+ /// * cutoff - A floating-point value specifying the maximum distance (in Angstroms) for considering residue pairs.
646+ ///
647+ /// # Returns
648+ ///
649+ /// A Vec<Pair> containing the closest residue pairs within the specified cutoff, sorted by distance.
650+ ///
651+ /// # Functionality
652+ ///
653+ /// 1. Iterates through all unique chain pairs in the PDB structure.
654+ /// 2. For each chain pair, finds the closest atoms between residues.
655+ /// 3. Selects pairs where the inter-residue distance is less than the specified cutoff.
656+ /// 4. Uses alpha carbon (CA) atoms for distance calculation and pair representation.
657+ /// 5. Sorts the resulting pairs by their inter-alpha carbon distance.
658+ ///
659+ /// # Notes
660+ ///
661+ /// - Only inter-chain interactions are considered.
662+ /// - The distance is calculated based on the closest atom pairs between residues.
663+ /// - The resulting pairs are sorted from shortest to longest distance.
664+ pub fn get_closest_residue_pairs ( pdb : & pdbtbx:: PDB , cutoff : f64 ) -> Vec < Pair > {
665+ let mut closest_pairs = Vec :: new ( ) ;
666+
667+ let chains: Vec < _ > = pdb. chains ( ) . collect ( ) ;
668+
669+ for i in 0 ..chains. len ( ) {
670+ for j in ( i + 1 ) ..chains. len ( ) {
671+ let chain_i = & chains[ i] ;
672+ let chain_j = & chains[ j] ;
673+
674+ for res_i in chain_i. residues ( ) {
675+ let mut min_distance = f64:: MAX ;
676+ let mut closest_pair = None ;
677+
678+ for res_j in chain_j. residues ( ) {
679+ let mut atom_dist = f64:: MAX ;
680+ for atom_i in res_i. atoms ( ) {
681+ for atom_j in res_j. atoms ( ) {
682+ let distance = atom_i. distance ( atom_j) ;
683+ if distance < atom_dist {
684+ atom_dist = distance;
685+ }
686+ }
687+ }
688+ if atom_dist < min_distance {
689+ min_distance = atom_dist;
690+ closest_pair = Some ( ( res_j, res_i) ) ;
691+ }
692+ }
693+
694+ if min_distance < cutoff {
695+ if let Some ( ( res_j, res_i) ) = closest_pair {
696+ let ca_i = res_i. atoms ( ) . find ( |atom| atom. name ( ) == "CA" ) . unwrap ( ) ;
697+ let ca_j = res_j. atoms ( ) . find ( |atom| atom. name ( ) == "CA" ) . unwrap ( ) ;
698+ let ca_ca_dist = ca_i. distance ( ca_j) ;
699+ closest_pairs. push ( Pair {
700+ chain_i : chain_i. id ( ) . to_string ( ) ,
701+ res_i : res_i. serial_number ( ) ,
702+ atom_i : ca_i. name ( ) . to_string ( ) ,
703+ chain_j : chain_j. id ( ) . to_string ( ) ,
704+ res_j : res_j. serial_number ( ) ,
705+ atom_j : ca_j. name ( ) . to_string ( ) ,
706+ distance : ca_ca_dist,
707+ } ) ;
708+ }
709+ }
710+ }
711+ }
712+ }
713+
714+ closest_pairs. sort_by ( |a, b| a. distance . partial_cmp ( & b. distance ) . unwrap ( ) ) ;
715+
716+ closest_pairs
717+ }
718+
626719#[ cfg( test) ]
627720mod tests {
628721
@@ -686,4 +779,27 @@ mod tests {
686779 . filter( |line| line. starts_with( "ATOM" ) )
687780 . all( |line| line. len( ) == 80 ) ) ;
688781 }
782+ #[ test]
783+ fn test_get_closest_residue_pairs ( ) {
784+ let pdb = load_pdb ( "tests/data/two_res.pdb" ) . unwrap ( ) ;
785+ let observed_pairs = get_closest_residue_pairs ( & pdb, 5.0 ) ;
786+ let expected_pairs = vec ! [ Pair {
787+ chain_i: "A" . to_string( ) ,
788+ chain_j: "B" . to_string( ) ,
789+ atom_i: "CA" . to_string( ) ,
790+ atom_j: "CA" . to_string( ) ,
791+ res_i: 2 ,
792+ res_j: 10 ,
793+ distance: 9.1 ,
794+ } ] ;
795+ assert_eq ! ( observed_pairs. len( ) , expected_pairs. len( ) ) ;
796+ let pair = & observed_pairs[ 0 ] ;
797+ assert_eq ! ( pair. chain_i, expected_pairs[ 0 ] . chain_i) ;
798+ assert_eq ! ( pair. chain_j, expected_pairs[ 0 ] . chain_j) ;
799+ assert_eq ! ( pair. atom_i, expected_pairs[ 0 ] . atom_i) ;
800+ assert_eq ! ( pair. atom_j, expected_pairs[ 0 ] . atom_j) ;
801+ assert_eq ! ( pair. res_i, expected_pairs[ 0 ] . res_i) ;
802+ assert_eq ! ( pair. res_j, expected_pairs[ 0 ] . res_j) ;
803+ assert ! ( ( pair. distance - 9.1 ) . abs( ) < 0.1 ) ;
804+ }
689805}
0 commit comments