mod search;
use std::collections::BTreeSet;
use crate::{Error, Structure};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RingStep {
pub atom: usize,
pub image: [i32; 3],
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Ring {
pub atoms: Vec<usize>,
pub path: Vec<RingStep>,
}
impl Ring {
#[must_use]
pub fn size(&self) -> usize {
self.path.len()
}
}
pub fn rings(structure: &Structure, max_size: usize) -> Result<Vec<Ring>, Error> {
if max_size < 3 {
return Err(Error::InvalidInput(
"ring size limit must be at least 3".to_owned(),
));
}
search::find(structure, max_size)
}
pub fn ring_paths(structure: &Structure, max_size: usize) -> Result<Vec<Vec<RingStep>>, Error> {
Ok(rings(structure, max_size)?
.into_iter()
.map(|ring| ring.path)
.collect())
}
pub fn ring_counts(structure: &Structure, max_size: usize) -> Result<Vec<(usize, usize)>, Error> {
let mut counts: Vec<(usize, usize)> = Vec::new();
for ring in rings(structure, max_size)? {
if let Some(entry) = counts.iter_mut().find(|(size, _)| *size == ring.size()) {
entry.1 += 1;
} else {
counts.push((ring.size(), 1));
}
}
Ok(counts)
}
pub fn ring_membership(structure: &Structure, max_size: usize) -> Result<Vec<usize>, Error> {
let p1 = structure.p1()?;
let mut membership = vec![0usize; p1.atoms.len()];
for ring in rings(structure, max_size)? {
for atom in ring.atoms {
if let Some(slot) = membership.get_mut(atom) {
*slot += 1;
}
}
}
Ok(membership)
}
pub fn is_aromatic(structure: &Structure, ring: &Ring) -> Result<bool, Error> {
if !matches!(ring.size(), 5 | 6) {
return Ok(false);
}
let p1 = structure.p1()?;
Ok(ring.atoms.iter().all(|index| {
p1.atoms
.get(*index)
.is_some_and(|atom| matches!(atom.element.as_str(), "C" | "N" | "O"))
}))
}
pub(crate) fn translated_home(path: &[RingStep]) -> BTreeSet<RingStep> {
let Some(minimum) = path.iter().min() else {
return BTreeSet::new();
};
path.iter()
.map(|step| RingStep {
atom: step.atom,
image: [
step.image[0] - minimum.image[0],
step.image[1] - minimum.image[1],
step.image[2] - minimum.image[2],
],
})
.collect()
}