Skip to content
This repository was archived by the owner on Mar 10, 2026. It is now read-only.

Commit 413d412

Browse files
committed
refactor(core): Optimize pairwise interaction calculation in EnergyGrid
1 parent e87f5be commit 413d412

1 file changed

Lines changed: 28 additions & 28 deletions

File tree

crates/scream-core/src/engine/energy_grid.rs

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use crate::core::forcefield::term::EnergyTerm;
88
use crate::core::models::atom::AtomRole;
99
use crate::core::models::ids::ResidueId;
1010
use crate::core::models::system::MolecularSystem;
11-
use itertools::Itertools;
1211
use std::collections::{HashMap, HashSet};
1312
use tracing::{info, trace};
1413

@@ -105,42 +104,43 @@ impl EnergyGrid {
105104

106105
let scorer = Scorer::new(system, forcefield);
107106

108-
for pair in active_residues.iter().combinations(2) {
109-
let res_a_id = *pair[0];
110-
let res_b_id = *pair[1];
107+
let active_residue_vec: Vec<_> = active_residues.iter().cloned().collect();
108+
for i in 0..active_residue_vec.len() {
109+
for j in (i + 1)..active_residue_vec.len() {
110+
let res_a_id = active_residue_vec[i];
111+
let res_b_id = active_residue_vec[j];
111112

112-
let atoms_a = collect_active_sidechain_atoms(system, &HashSet::from([res_a_id]));
113-
let atoms_b = collect_active_sidechain_atoms(system, &HashSet::from([res_b_id]));
113+
let atoms_a = collect_active_sidechain_atoms(system, &HashSet::from([res_a_id]));
114+
let atoms_b = collect_active_sidechain_atoms(system, &HashSet::from([res_b_id]));
114115

115-
let atoms_a_slice = atoms_a
116-
.get(&res_a_id)
117-
.map_or([].as_slice(), |v| v.as_slice());
118-
let atoms_b_slice = atoms_b
119-
.get(&res_b_id)
120-
.map_or([].as_slice(), |v| v.as_slice());
116+
let atoms_a_slice = atoms_a
117+
.get(&res_a_id)
118+
.map_or([].as_slice(), |v| v.as_slice());
119+
let atoms_b_slice = atoms_b
120+
.get(&res_b_id)
121+
.map_or([].as_slice(), |v| v.as_slice());
121122

122-
if atoms_a_slice.is_empty() || atoms_b_slice.is_empty() {
123-
continue;
124-
}
123+
if atoms_a_slice.is_empty() || atoms_b_slice.is_empty() {
124+
continue;
125+
}
125126

126-
let interaction = scorer.score_interaction(atoms_a_slice, atoms_b_slice)?;
127+
let interaction = scorer.score_interaction(atoms_a_slice, atoms_b_slice)?;
127128

128-
let key = if res_a_id < res_b_id {
129-
(res_a_id, res_b_id)
130-
} else {
131-
(res_b_id, res_a_id)
132-
};
133-
pair_interactions.insert(key, interaction);
129+
let key = (res_a_id, res_b_id);
130+
pair_interactions.insert(key, interaction);
131+
132+
*total_residue_interactions.get_mut(&res_a_id).unwrap() += interaction;
133+
*total_residue_interactions.get_mut(&res_b_id).unwrap() += interaction;
134+
}
135+
}
134136

135-
*total_residue_interactions.get_mut(&res_a_id).unwrap() += interaction;
136-
*total_residue_interactions.get_mut(&res_b_id).unwrap() += interaction;
137+
for term in total_residue_interactions.values_mut() {
138+
*term = *term * 0.5;
137139
}
138140

139-
// The total interaction energy is double-counted in the sum above, so divide by 2
140-
let total_interaction_energy = total_residue_interactions
141+
let total_interaction_energy = pair_interactions
141142
.values()
142-
.fold(EnergyTerm::default(), |acc, term| acc + *term)
143-
* 0.5;
143+
.fold(EnergyTerm::default(), |acc, term| acc + *term);
144144

145145
let mut current_el_energies = HashMap::with_capacity(active_residues.len());
146146
let mut total_el_energy = EnergyTerm::default();

0 commit comments

Comments
 (0)