@@ -186,7 +186,14 @@ pub fn to_bio_topology(system: &System) -> Result<bf::Topology, ConversionError>
186186 type ResidueKey = ( String , i32 , Option < char > ) ;
187187 let mut chains: IndexMap < String , IndexMap < ResidueKey , bf:: Residue > > = IndexMap :: new ( ) ;
188188
189- for ( atom, info) in system. atoms . iter ( ) . zip ( metadata. atom_info . iter ( ) ) {
189+ let mut residue_members: IndexMap < ResidueKey , Vec < usize > > = IndexMap :: new ( ) ;
190+
191+ for ( i, ( atom, info) ) in system
192+ . atoms
193+ . iter ( )
194+ . zip ( metadata. atom_info . iter ( ) )
195+ . enumerate ( )
196+ {
190197 let bio_atom = bf:: Atom :: new (
191198 & info. atom_name ,
192199 convert_element_to_bf ( atom. element ) ?,
@@ -196,7 +203,7 @@ pub fn to_bio_topology(system: &System) -> Result<bf::Topology, ConversionError>
196203 let residue_key = ( info. chain_id . clone ( ) , info. residue_id , info. insertion_code ) ;
197204 let residues = chains. entry ( info. chain_id . clone ( ) ) . or_default ( ) ;
198205
199- let residue = match residues. entry ( residue_key) {
206+ let residue = match residues. entry ( residue_key. clone ( ) ) {
200207 Entry :: Occupied ( e) => e. into_mut ( ) ,
201208 Entry :: Vacant ( e) => {
202209 let mut res = bf:: Residue :: new (
@@ -212,6 +219,7 @@ pub fn to_bio_topology(system: &System) -> Result<bf::Topology, ConversionError>
212219 } ;
213220
214221 residue. add_atom ( bio_atom) ;
222+ residue_members. entry ( residue_key) . or_default ( ) . push ( i) ;
215223 }
216224
217225 let mut bio_struct = bf:: Structure :: new ( ) ;
@@ -225,13 +233,18 @@ pub fn to_bio_topology(system: &System) -> Result<bf::Topology, ConversionError>
225233 bio_struct. add_chain ( chain) ;
226234 }
227235
236+ let mut old_to_new = vec ! [ 0usize ; system. atoms. len( ) ] ;
237+ for ( flat, & orig) in residue_members. values ( ) . flatten ( ) . enumerate ( ) {
238+ old_to_new[ orig] = flat;
239+ }
240+
228241 let bio_bonds = system
229242 . bonds
230243 . iter ( )
231244 . map ( |bond| {
232245 Ok ( bf:: Bond :: new (
233- bond. i ,
234- bond. j ,
246+ old_to_new [ bond. i ] ,
247+ old_to_new [ bond. j ] ,
235248 convert_bond_order_to_bf ( bond. order ) ?,
236249 ) )
237250 } )
@@ -572,6 +585,43 @@ mod tests {
572585 assert_eq ! ( roundtrip. bio_metadata. as_ref( ) , Some ( & metadata) ) ;
573586 }
574587
588+ #[ test]
589+ fn to_bio_topology_remaps_bonds_for_non_contiguous_atoms ( ) {
590+ let atoms = vec ! [
591+ Atom :: new( Element :: C , [ 0.0 , 0.0 , 0.0 ] ) ,
592+ Atom :: new( Element :: N , [ 3.0 , 0.0 , 0.0 ] ) ,
593+ Atom :: new( Element :: C , [ 0.0 , 1.5 , 0.0 ] ) ,
594+ ] ;
595+ let metadata = BioMetadata {
596+ atom_info : vec ! [
597+ AtomResidueInfo :: builder( "CA" , "ALA" , 1 , "A" ) . build( ) ,
598+ AtomResidueInfo :: builder( "N" , "ALA" , 2 , "A" ) . build( ) ,
599+ AtomResidueInfo :: builder( "CB" , "ALA" , 1 , "A" ) . build( ) ,
600+ ] ,
601+ target_ph : None ,
602+ } ;
603+ let bonds = vec ! [ Bond :: new( 0 , 2 , BondOrder :: Single ) ] ;
604+ let system = System {
605+ atoms,
606+ bonds,
607+ box_vectors : None ,
608+ bio_metadata : Some ( metadata) ,
609+ } ;
610+
611+ let bio_topo = to_bio_topology ( & system) . expect ( "conversion should succeed" ) ;
612+
613+ let bio_bonds = bio_topo. bonds ( ) ;
614+ assert_eq ! ( bio_bonds. len( ) , 1 ) ;
615+ assert_eq ! (
616+ bio_bonds[ 0 ] . a1_idx, 0 ,
617+ "bond endpoint a should be flat 0 (CA)"
618+ ) ;
619+ assert_eq ! (
620+ bio_bonds[ 0 ] . a2_idx, 1 ,
621+ "bond endpoint b should be flat 1 (CB)"
622+ ) ;
623+ }
624+
575625 #[ test]
576626 fn converts_clean_config_fields ( ) {
577627 let mut remove_res = HashSet :: new ( ) ;
0 commit comments