use super::fields::{
AlignmentPolicy, AltlocPolicy, AssemblyChoice, ContactDefinition, EquivalencePolicy,
HydrogenPolicy, MissingPolicy, ModelChoice, Namespace, PeriodicPolicy, Precision, ProfileId,
RadiiSet, SymmetryPolicy, Tolerance,
};
use super::fingerprint::{Fingerprint, Fnv1a};
use std::fmt;
use std::hash::{Hash, Hasher};
#[derive(Clone, PartialEq, Debug, Default)]
pub struct AnalysisPolicy {
pub assembly: AssemblyChoice,
pub model: ModelChoice,
pub altloc: AltlocPolicy,
pub identifiers: Namespace,
pub missing_atoms: MissingPolicy,
pub hydrogens: HydrogenPolicy,
pub atom_equivalence: EquivalencePolicy,
pub symmetry: SymmetryPolicy,
pub alignment: AlignmentPolicy,
pub precision: Precision,
pub periodic: PeriodicPolicy,
pub vdw_radii: RadiiSet,
pub contact_def: ContactDefinition,
pub float_tolerance: Tolerance,
}
impl AnalysisPolicy {
#[must_use]
pub fn profile(&self) -> Option<ProfileId> {
(*self == Self::default()).then_some(ProfileId::DEFAULT)
}
#[must_use]
pub fn fingerprint(&self) -> Fingerprint {
let mut hasher = Fnv1a::new();
self.assembly.hash(&mut hasher);
self.model.hash(&mut hasher);
self.altloc.hash(&mut hasher);
self.identifiers.hash(&mut hasher);
self.missing_atoms.hash(&mut hasher);
self.hydrogens.hash(&mut hasher);
self.atom_equivalence.hash(&mut hasher);
self.symmetry.hash(&mut hasher);
self.alignment.hash(&mut hasher);
self.precision.hash(&mut hasher);
self.periodic.hash(&mut hasher);
self.vdw_radii.hash(&mut hasher);
match self.contact_def {
ContactDefinition::DistanceCutoff { tolerance } => {
(0u8, tolerance.to_bits()).hash(&mut hasher);
}
ContactDefinition::SurfaceBased { probe } => {
(1u8, probe.to_bits()).hash(&mut hasher);
}
}
(
self.float_tolerance.relative.to_bits(),
self.float_tolerance.absolute.to_bits(),
)
.hash(&mut hasher);
Fingerprint::from_hash(hasher.finish())
}
#[must_use]
pub fn with_identifiers(mut self, namespace: Namespace) -> Self {
self.identifiers = namespace;
self
}
#[must_use]
pub fn with_altloc(mut self, altloc: AltlocPolicy) -> Self {
self.altloc = altloc;
self
}
#[must_use]
pub fn with_model(mut self, model: ModelChoice) -> Self {
self.model = model;
self
}
#[must_use]
pub fn with_assembly(mut self, assembly: AssemblyChoice) -> Self {
self.assembly = assembly;
self
}
#[must_use]
pub fn with_missing_atoms(mut self, missing: MissingPolicy) -> Self {
self.missing_atoms = missing;
self
}
}
impl fmt::Display for AnalysisPolicy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.profile() {
Some(profile) => writeln!(f, "{profile}")?,
None => writeln!(f, "(modified from {})", ProfileId::DEFAULT)?,
}
writeln!(f, " assembly = {:?}", self.assembly)?;
writeln!(f, " model = {:?}", self.model)?;
writeln!(f, " altloc = {:?}", self.altloc)?;
writeln!(f, " identifiers = {:?}", self.identifiers)?;
writeln!(f, " missing_atoms = {:?}", self.missing_atoms)?;
writeln!(f, " hydrogens = {:?}", self.hydrogens)?;
writeln!(f, " atom_equivalence = {:?}", self.atom_equivalence)?;
writeln!(f, " symmetry = {:?}", self.symmetry)?;
writeln!(f, " alignment = {:?}", self.alignment)?;
writeln!(f, " precision = {:?}", self.precision)?;
writeln!(f, " periodic = {:?}", self.periodic)?;
writeln!(f, " vdw_radii = {:?}", self.vdw_radii)?;
writeln!(f, " contact_def = {:?}", self.contact_def)?;
write!(f, " float_tolerance = {:?}", self.float_tolerance)
}
}
#[cfg(test)]
#[path = "profile_tests.rs"]
mod tests;