#![allow(confusable_idents)]
#![allow(mixed_script_confusables)]
pub mod mmcif;
pub mod mol2;
pub mod pdbqt;
pub mod sdf;
pub mod ab1;
pub mod map;
pub mod dat;
pub mod frcmod;
pub mod gromacs;
pub mod md_params;
pub mod orca;
pub mod amber_typedef;
pub mod bond_inference;
pub mod cif_sf;
pub mod dcd;
mod mmcif_aux;
pub mod mol_templates;
pub mod prmtop;
pub mod xtc;
pub mod xyz;
use std::{
fmt,
fmt::{Display, Formatter},
io,
io::ErrorKind,
str::FromStr,
};
pub use ab1::*;
pub use bond_inference::create_bonds;
use lin_alg::f64::Vec3;
pub use map::*;
pub use mmcif::*;
pub use mol2::*;
use na_seq::{AminoAcid, AtomTypeInRes, Element};
pub use pdbqt::Pdbqt;
pub use sdf::*;
pub use xyz::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(usize)]
pub enum LipidStandard {
Ar,
Chl,
Dha,
Lal,
My,
Ol,
Pa,
Pc,
Pe,
Pgr,
Pgs,
Ph,
Ps,
Sa,
Spm,
St,
Pi,
Cardiolipin,
}
impl Display for LipidStandard {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let name = match self {
Self::Ar => "Ar",
Self::Chl => "Chl",
Self::Dha => "Dha",
Self::Lal => "Lal",
Self::My => "My",
Self::Ol => "Ol",
Self::Pa => "Pa",
Self::Pc => "Pc",
Self::Pe => "Pe",
Self::Pgr => "Pgr",
Self::Pgs => "Pgs",
Self::Ph => "Ph", Self::Ps => "Ps",
Self::Sa => "Sa",
Self::Spm => "Spm",
Self::St => "St",
Self::Pi => "Pi", Self::Cardiolipin => "Cardiolipin", };
write!(f, "{name}")
}
}
impl FromStr for LipidStandard {
type Err = io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s.to_uppercase().as_ref() {
"AR" => Self::Ar,
"CHL" => Self::Chl,
"DHA" => Self::Dha,
"LAL" => Self::Lal,
"MY" => Self::My,
"OL" => Self::Ol,
"PA" => Self::Pa,
"PC" => Self::Pc,
"PE" => Self::Pe,
"PGR" => Self::Pgr,
"PGS" => Self::Pgs,
"PH-" => Self::Ph,
"PS" => Self::Ps,
"SA" => Self::Sa,
"SPM" => Self::Spm,
"ST" => Self::St,
"PI" => Self::Pi, "CARDIOLIPIN" | "CL" | "CDL" | "CDL2" => Self::Cardiolipin, _ => {
return Err(io::Error::new(
ErrorKind::InvalidInput,
format!("Unknown lipid standard: '{s}'"),
));
}
})
}
}
#[derive(Clone, Debug, Default)]
pub struct AtomGeneric {
pub serial_number: u32,
pub posit: Vec3,
pub element: Element,
pub type_in_res: Option<AtomTypeInRes>,
pub type_in_res_general: Option<String>,
pub force_field_type: Option<String>,
pub partial_charge: Option<f32>,
pub hetero: bool,
pub occupancy: Option<f32>,
pub alt_conformation_id: Option<String>,
}
impl Display for AtomGeneric {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let ff_type = match &self.force_field_type {
Some(f) => f,
None => "None",
};
let q = match &self.partial_charge {
Some(q_) => format!("{q_:.3}"),
None => "None".to_string(),
};
write!(
f,
"Atom {}: {}, {}. {:?}, ff: {ff_type}, q: {q}",
self.serial_number,
self.element.to_letter(),
self.posit,
self.type_in_res,
)?;
if self.hetero {
write!(f, ", Het")?;
}
Ok(())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BondType {
Single,
Double,
Triple,
Aromatic,
Amide,
Dummy,
Unknown,
NotConnected,
Quadruple,
Delocalized,
PolymericLink,
}
impl Display for BondType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let name = match self {
Self::Single => "Single",
Self::Double => "Double",
Self::Triple => "Triple",
Self::Aromatic => "Aromatic",
Self::Amide => "Amide",
Self::Dummy => "Dummy",
Self::Unknown => "Unknown",
Self::NotConnected => "Not connected",
Self::Quadruple => "Quadruple",
Self::Delocalized => "Delocalized",
Self::PolymericLink => "Polymeric link",
};
write!(f, "{name}")
}
}
impl BondType {
pub fn order(self) -> f32 {
match self {
Self::Aromatic => 1.5,
Self::Double => 2.,
Self::Triple => 3.,
Self::Quadruple => 4.,
_ => 1.,
}
}
pub fn to_visual_str(&self) -> String {
match self {
Self::Single => "-",
Self::Double => "=",
Self::Triple => "≡",
Self::Aromatic => "=–",
Self::Amide => "-am-",
Self::Dummy => "-",
Self::Unknown => "-un-",
Self::NotConnected => "-nc-",
Self::Quadruple => "-#-",
Self::Delocalized => "-delo-",
Self::PolymericLink => "-poly-",
}
.to_string()
}
pub fn to_mol2_str(&self) -> String {
match self {
Self::Single => "1",
Self::Double => "2",
Self::Triple => "3",
Self::Aromatic => "ar",
Self::Amide => "am",
Self::Dummy => "du",
Self::Unknown => "un",
Self::NotConnected => "nc",
Self::Quadruple => "quad",
Self::Delocalized => "delo",
Self::PolymericLink => "poly",
}
.to_string()
}
pub fn to_str_sdf(&self) -> String {
match self {
Self::Single | Self::Double | Self::Triple => *self,
Self::Aromatic => return "4".to_string(),
_ => Self::Single,
}
.to_mol2_str()
}
}
impl FromStr for BondType {
type Err = io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.trim().to_lowercase().as_str() {
"1" | "sing" => Ok(BondType::Single),
"2" | "doub" => Ok(BondType::Double),
"3" | "trip" => Ok(BondType::Triple),
"4" | "ar" | "arom" => Ok(BondType::Aromatic),
"am" => Ok(BondType::Amide),
"du" => Ok(BondType::Dummy),
"un" => Ok(BondType::Unknown),
"nc" => Ok(BondType::NotConnected),
"quad" => Ok(BondType::Quadruple),
"delo" => Ok(BondType::Delocalized),
"poly" => Ok(BondType::PolymericLink),
_ => Err(io::Error::new(
ErrorKind::InvalidData,
format!("Invalid BondType: {s}"),
)),
}
}
}
#[derive(Clone, Debug)]
pub struct BondGeneric {
pub bond_type: BondType,
pub atom_0_sn: u32,
pub atom_1_sn: u32,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ResidueType {
AminoAcid(AminoAcid),
Water,
Other(String),
}
impl Display for ResidueType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let name = match &self {
ResidueType::Other(n) => n.clone(),
ResidueType::Water => "Water".to_string(),
ResidueType::AminoAcid(aa) => aa.to_string(),
};
write!(f, "{name}")
}
}
impl Default for ResidueType {
fn default() -> Self {
Self::Other(String::new())
}
}
impl ResidueType {
pub fn from_str(name: &str) -> Self {
if name.to_uppercase() == "HOH" {
ResidueType::Water
} else {
match AminoAcid::from_str(name) {
Ok(aa) => ResidueType::AminoAcid(aa),
Err(_) => ResidueType::Other(name.to_owned()),
}
}
}
}
#[derive(Debug, Clone)]
pub struct ResidueGeneric {
pub serial_number: u32,
pub res_type: ResidueType,
pub atom_sns: Vec<u32>,
pub end: ResidueEnd,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum ResidueEnd {
Internal,
NTerminus,
CTerminus,
Hetero,
}
#[derive(Debug, Clone)]
pub struct ChainGeneric {
pub id: String,
pub residue_sns: Vec<u32>,
pub atom_sns: Vec<u32>,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SecondaryStructure {
Helix,
Sheet,
Coil,
}
#[derive(Clone, Debug)]
pub struct BackboneSS {
pub start_sn: u32,
pub end_sn: u32,
pub sec_struct: SecondaryStructure,
}
#[derive(Clone, Copy, Debug)]
pub enum FrameSlice {
Time {
start: Option<f64>,
end: Option<f64>,
},
Index {
start: Option<usize>,
end: Option<usize>,
},
}
impl Display for FrameSlice {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let v = match self {
Self::Time { start, end } => {
let fmt_idx = |i: &Option<f64>| match i {
Some(v) => v.to_string(),
None => String::from("|"),
};
if start.is_none() && end.is_none() {
String::from("All")
} else {
format!("{} - {} ps", fmt_idx(start), fmt_idx(end))
}
}
Self::Index { start, end } => {
let fmt_idx = |i: &Option<usize>| match i {
Some(v) => v.to_string(),
None => String::from("|"),
};
if start.is_none() && end.is_none() {
String::from("All")
} else {
format!("Frames {} - {}", fmt_idx(start), fmt_idx(end))
}
}
};
write!(f, "{v}")
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ExperimentalMethod {
XRayDiffraction,
ElectronDiffraction,
NeutronDiffraction,
ElectronMicroscopy,
SolutionNmr,
}
impl ExperimentalMethod {
pub fn to_str_short(&self) -> String {
match self {
Self::XRayDiffraction => "X-ray",
Self::NeutronDiffraction => "ND",
Self::ElectronDiffraction => "ED",
Self::ElectronMicroscopy => "EM",
Self::SolutionNmr => "NMR",
}
.to_owned()
}
}
impl Display for ExperimentalMethod {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let val = match self {
Self::XRayDiffraction => "X-Ray diffraction",
Self::NeutronDiffraction => "Neutron diffraction",
Self::ElectronDiffraction => "Electron diffraction",
Self::ElectronMicroscopy => "Electron microscopy",
Self::SolutionNmr => "Solution NMR",
};
write!(f, "{val}")
}
}
impl FromStr for ExperimentalMethod {
type Err = io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let normalized = s.to_lowercase();
let s = normalized.trim();
let method = match s {
"x-ray diffraction" => ExperimentalMethod::XRayDiffraction,
"neutron diffraction" => ExperimentalMethod::NeutronDiffraction,
"electron diffraction" => ExperimentalMethod::ElectronDiffraction,
"electron microscopy" => ExperimentalMethod::ElectronMicroscopy,
"solution nmr" => ExperimentalMethod::SolutionNmr,
other => {
return Err(io::Error::new(
ErrorKind::InvalidData,
format!("Error parsing experimental method: {other}"),
));
}
};
Ok(method)
}
}
pub(crate) fn el_from_atom_name(name: &str) -> Element {
let upper = name.to_uppercase();
if upper.starts_with("CL") {
return Element::Chlorine;
}
if upper.starts_with("BR") {
return Element::Bromine;
}
let mut res = Element::from_letter(
&name
.chars()
.take_while(|c| c.is_ascii_alphabetic())
.take(1)
.collect::<String>()
.to_uppercase(),
)
.unwrap_or(Element::Carbon);
if name.starts_with('C') && !name.starts_with("Ca") && !name.starts_with("Cu") {
res = Element::Carbon;
}
if name.starts_with('H') && !name.starts_with("Hg") {
res = Element::Hydrogen;
}
if name.starts_with('S') && !name.starts_with("Se") {
res = Element::Sulfur;
}
res
}
#[derive(Clone, Debug)]
pub struct PharmacophoreFeatureGeneric {
pub atom_sns: Vec<u32>,
pub type_: PharmacophoreTypeGeneric,
}
#[derive(Clone, PartialEq, Debug)]
pub enum PharmacophoreTypeGeneric {
Acceptor,
Donor,
Cation,
Rings,
Hydrophobic,
Hydrophilic,
Anion,
Aromatic, Other(String),
}
impl PharmacophoreTypeGeneric {
fn from_pubchem_str(s: &str) -> Option<Self> {
match s.trim().to_ascii_lowercase().as_str() {
"acceptor" => Some(Self::Acceptor),
"donor" => Some(Self::Donor),
"cation" => Some(Self::Cation),
"rings" | "ring" => Some(Self::Rings),
"hydrophobe" | "hydrophobic" => Some(Self::Hydrophobic),
"hydrophilic" => Some(Self::Hydrophilic),
"anion" => Some(Self::Anion),
"aromatic" => Some(Self::Aromatic),
_ => Some(Self::Other(s.to_string())),
}
}
fn to_pubchem_str(&self) -> String {
match self {
Self::Acceptor => "acceptor".to_string(),
Self::Donor => "donor".to_string(),
Self::Cation => "cation".to_string(),
Self::Rings => "rings".to_string(),
Self::Hydrophobic => "hydrophobe".to_string(),
Self::Hydrophilic => "hydrophilic".to_string(),
Self::Anion => "anion".to_string(),
Self::Aromatic => "aromatic".to_string(),
Self::Other(s) => s.clone(),
}
}
}