molframe-spatial 0.6.3

Deterministic spatial indices and neighbour search for molframe
Documentation
use super::*;
use molframe_core::io::{InputBuffer, ReadOptions};
use std::fmt::Write;

fn structure(second_contact: bool, coplanar: bool) -> Structure {
    let mut source = String::from(
        "data_pairs\nloop_\n_atom_site.group_PDB\n_atom_site.id\n_atom_site.type_symbol\n_atom_site.label_atom_id\n_atom_site.label_comp_id\n_atom_site.label_asym_id\n_atom_site.label_seq_id\n_atom_site.Cartn_x\n_atom_site.Cartn_y\n_atom_site.Cartn_z\n",
    );
    let atoms = [
        ("C1'", "DA", "A", [-5.0, 0.0, 0.0]),
        ("C2", "DA", "A", [0.0, 0.0, 0.0]),
        ("C4", "DA", "A", [0.0, 1.0, 0.0]),
        ("C6", "DA", "A", [1.0, 0.0, 0.0]),
        ("N6", "DA", "A", [0.0, 0.0, 0.0]),
        ("N1", "DA", "A", [0.0, 2.0, 0.0]),
        ("C1'", "DT", "B", [5.0, 0.0, 0.0]),
        ("C2", "DT", "B", [2.8, 0.0, 0.0]),
        (
            "C4",
            "DT",
            "B",
            if coplanar {
                [2.8, 1.0, 0.0]
            } else {
                [2.8, 0.0, 1.0]
            },
        ),
        ("C6", "DT", "B", [3.8, 0.0, 0.0]),
        ("O4", "DT", "B", [2.8, 0.0, 0.0]),
        (
            "N3",
            "DT",
            "B",
            [if second_contact { 2.8 } else { 20.0 }, 2.0, 0.0],
        ),
    ];
    for (row, (name, residue, chain, [x, y, z])) in atoms.into_iter().enumerate() {
        writeln!(
            source,
            "ATOM {} C {name} {residue} {chain} 1 {x} {y} {z}",
            row + 1
        )
        .expect("source writes");
    }
    molframe_cif::read(
        &InputBuffer::from_bytes(source.into_bytes()),
        &ReadOptions::new(),
    )
    .expect("fixture reads")
    .0
}

#[test]
fn complementary_coplanar_bases_need_two_canonical_edge_contacts() {
    let pairs =
        standard_base_pair_geometry(&structure(true, true), WatsonCrickGeometry::default(), 3.6)
            .expect("geometry resolves");
    assert_eq!(pairs.len(), 1);
    assert_eq!(pairs[0].contact_count, 2);
    assert!((pairs[0].closest_distance - 2.8).abs() < 1e-5);
    for structure in [structure(false, true), structure(true, false)] {
        assert!(
            standard_base_pair_geometry(&structure, WatsonCrickGeometry::default(), 3.6)
                .expect("geometry resolves")
                .is_empty()
        );
    }
}

#[test]
fn invalid_pairing_limits_return_a_spatial_error() {
    assert!(
        standard_base_pair_geometry(
            &structure(true, true),
            WatsonCrickGeometry::default(),
            f32::NAN
        )
        .is_err()
    );
}