Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arc based atom bonds #94

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ include = ["src/**/*", "LICENSE", "README.md"]

[dependencies]
rstar = { version = "^0.9.2", optional = true}
serde = { version = "~1.0", optional = true, features = ["derive"] }
serde = { version = "~1.0", optional = true, features = ["derive", "rc"] }
rayon = {version = "^1", optional = true}
doc-cfg = "0.1"
indexmap = "^1.8"
Expand Down
44 changes: 23 additions & 21 deletions src/read/pdb/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,41 +607,43 @@ fn add_modifications(pdb: &mut PDB, modifications: Vec<(Context, LexItem)>) -> V
/// Adds all bonds to the PDB, has to be done after all Atoms are already in place
#[allow(clippy::unwrap_used)]
fn add_bonds(pdb: &mut PDB, bonds: Vec<(Context, LexItem)>) -> Vec<PDBError> {
let mut errors = Vec::new();
for (context, bond) in bonds {
let errors = Vec::new();
for (_context, bond) in bonds {
match bond {
LexItem::SSBond(atom1, atom2, ..) => {
let find = |atom: (String, isize, Option<String>, String)| {
pdb.chains()
.find(|c| c.id() == atom.3)
.and_then(|c| {
c.residues()
.find(|r| {
r.serial_number() == atom.1
&& r.insertion_code() == atom.2.as_deref()
})
.map(|r| {
r.conformers().find(|c| c.name() == atom.0).map(|c| {
c.atoms().find(|a| a.name() == "SG").map(Atom::counter)
})
})
})
.flatten()
.flatten()
let h = pdb
.find(
Term::ConformerName(atom.0)
& Term::ResidueSerialNumber(atom.1)
& Term::ResidueInsertionCode(atom.2),
)
.next()
.unwrap();
(
h.atom().serial_number().to_owned(),
h.conformer()
.alternative_location()
.map(std::borrow::ToOwned::to_owned),
)
};
let ref1 = find(atom1);
let ref2 = find(atom2);

pdb.add_bond(
(ref1.0, ref1.1.as_deref()),
(ref2.0, ref2.1.as_deref()),
Bond::Disulfide,
);
/*
if let (Some(counter1), Some(counter2)) = (ref1, ref2) {
pdb.add_bond_counters(counter1, counter2, Bond::Disulfide);
} else {
errors.push(PDBError::new(
ErrorLevel::InvalidatingError,
"Could not find a bond partner",
"One of the atoms could not be found while parsing a disulfide bond.",
context,
));
}
} */
}
_ => {
panic!(
Expand Down
34 changes: 22 additions & 12 deletions src/structs/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,15 @@
use crate::reference_tables;
use crate::structs::*;
use crate::transformation::TransformationMatrix;
use std::cell::{Ref, RefCell};
use std::cmp::Ordering;
use std::convert::TryInto;
use std::fmt;
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};

static ATOM_COUNTER: AtomicUsize = AtomicUsize::new(0);

use std::sync::Arc;
/// A struct to represent a single Atom in a protein.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug)]
pub struct Atom {
/// The unique serial number given to this atom
counter: usize,
/// Determines if this atom is a hetero atom (true), a non standard atom, or a normal atom (false)
hetero: bool,
/// The serial number of the Atom, should be unique within its model
Expand All @@ -37,6 +33,8 @@ pub struct Atom {
charge: isize,
/// The anisotropic temperature factors, if applicable
atf: Option<[[f64; 3]; 3]>,
/// Bonds
bonds: Vec<(Arc<RefCell<Atom>>, Bond)>,
}

impl Atom {
Expand Down Expand Up @@ -81,7 +79,6 @@ impl Atom {
None
};
Some(Atom {
counter: ATOM_COUNTER.fetch_add(1, AtomicOrdering::SeqCst),
hetero,
serial_number,
name: atom_name.trim().to_ascii_uppercase(),
Expand All @@ -93,17 +90,13 @@ impl Atom {
element,
charge,
atf: None,
bonds: Vec::new(),
})
} else {
None
}
}

/// Get a unique immutable counter for this atom.
pub(crate) const fn counter(&self) -> usize {
self.counter
}

/// Determine if this atom is an hetero atom (`true`), a non standard atom, or a normal atom (`false`).
pub const fn hetero(&self) -> bool {
self.hetero
Expand Down Expand Up @@ -350,6 +343,23 @@ impl Atom {
self.atf = Some(factors);
}

/// Add a bond to this Atom, do not forget to add the reverse bond as well yourself.
pub fn add_bond(&mut self, atom: Arc<RefCell<Atom>>, bond: Bond) {
self.bonds.push((atom, bond));
//atom.add_bond(self, bond);
}

/// Get the number of bonds on this Atom.
pub fn bond_count(&self) -> usize {
self.bonds.len()
}

/// Get all bonds to this Atom, it returns an `Arc<Atom>` which is a reference counted pointer to the Atom,
/// meaning it cannot ever be freed while the value is still being used somewhere.
pub fn bonds(&self) -> impl DoubleEndedIterator<Item = (Ref<'_, Atom>, Bond)> + '_ {
self.bonds.iter().map(|(a, b)| (a.borrow(), *b))
}

/// Determine whether this atom is likely to be a part of the backbone of a protein.
/// This is based on this Atom only, for a more precise definition use [`hierarchy::ContainsAtomConformer::is_backbone`].
pub fn is_backbone(&self) -> bool {
Expand Down
125 changes: 63 additions & 62 deletions src/structs/chain.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#![allow(dead_code)]
use crate::structs::*;
use crate::transformation::TransformationMatrix;
use doc_cfg::doc_cfg;
#[cfg(feature = "rayon")]
use rayon::prelude::*;
//use doc_cfg::doc_cfg;
//#[cfg(feature = "rayon")]
//use rayon::prelude::*;
use std::cell::{Ref, RefMut};
use std::cmp::Ordering;

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand Down Expand Up @@ -87,21 +88,21 @@ impl<'a> Chain {
}

/// Get the number of Conformers making up this Chain in parallel
#[doc_cfg(feature = "rayon")]
pub fn par_conformer_count(&self) -> usize {
self.par_residues().map(Residue::conformer_count).sum()
}
//#[doc_cfg(feature = "rayon")]
//pub fn par_conformer_count(&self) -> usize {
// self.par_residues().map(Residue::conformer_count).sum()
//}

/// Get the number of Atoms making up this Chain
pub fn atom_count(&self) -> usize {
self.residues().map(Residue::atom_count).sum()
}

/// Get the number of Atoms making up this Chain in parallel
#[doc_cfg(feature = "rayon")]
pub fn par_atom_count(&self) -> usize {
self.par_residues().map(Residue::par_atom_count).sum()
}
//#[doc_cfg(feature = "rayon")]
//pub fn par_atom_count(&self) -> usize {
// self.par_residues().map(Residue::par_atom_count).sum()
//}

/// Get a reference to a specific Residue from list of Residues making up this Chain.
///
Expand Down Expand Up @@ -154,7 +155,7 @@ impl<'a> Chain {
///
/// ## Fails
/// It returns `None` if the index is out of bounds.
pub fn atom(&self, index: usize) -> Option<&Atom> {
pub fn atom(&self, index: usize) -> Option<Ref<'_, Atom>> {
self.atoms().nth(index)
}

Expand All @@ -165,7 +166,7 @@ impl<'a> Chain {
///
/// ## Fails
/// It returns `None` if the index is out of bounds.
pub fn atom_mut(&mut self, index: usize) -> Option<&mut Atom> {
pub fn atom_mut(&mut self, index: usize) -> Option<RefMut<'_, Atom>> {
self.atoms_mut().nth(index)
}

Expand Down Expand Up @@ -289,10 +290,10 @@ impl<'a> Chain {
}

/// Get a parallel iterator of references to Residues making up this Chain.
#[doc_cfg(feature = "rayon")]
pub fn par_residues(&self) -> impl ParallelIterator<Item = &Residue> + '_ {
self.residues.par_iter()
}
//#[doc_cfg(feature = "rayon")]
//pub fn par_residues(&self) -> impl ParallelIterator<Item = &Residue> + '_ {
// self.residues.par_iter()
//}

/// Get an iterator of mutable references to Residues making up this Chain.
/// Double ended so iterating from the end is just as fast as from the start.
Expand All @@ -301,10 +302,10 @@ impl<'a> Chain {
}

/// Get a parallel iterator of mutable references to Residues making up this Chain.
#[doc_cfg(feature = "rayon")]
pub fn par_residues_mut(&mut self) -> impl ParallelIterator<Item = &mut Residue> + '_ {
self.residues.par_iter_mut()
}
//#[doc_cfg(feature = "rayon")]
//pub fn par_residues_mut(&mut self) -> impl ParallelIterator<Item = &mut Residue> + '_ {
//self.residues.par_iter_mut()
//}

/// Get an iterator of references to Conformers making up this Chain.
/// Double ended so iterating from the end is just as fast as from the start.
Expand All @@ -313,10 +314,10 @@ impl<'a> Chain {
}

/// Get a parallel iterator of references to Conformers making up this Chain.
#[doc_cfg(feature = "rayon")]
pub fn par_conformers(&self) -> impl ParallelIterator<Item = &Conformer> + '_ {
self.par_residues().flat_map(Residue::par_conformers)
}
//#[doc_cfg(feature = "rayon")]
//pub fn par_conformers(&self) -> impl ParallelIterator<Item = &Conformer> + '_ {
//self.par_residues().flat_map(Residue::par_conformers)
//}

/// Get an iterator of mutable references to Conformers making up this Chain.
/// Double ended so iterating from the end is just as fast as from the start.
Expand All @@ -325,35 +326,35 @@ impl<'a> Chain {
}

/// Get a parallel iterator of mutable references to Conformers making up this Chain.
#[doc_cfg(feature = "rayon")]
pub fn par_conformers_mut(&mut self) -> impl ParallelIterator<Item = &mut Conformer> + '_ {
self.par_residues_mut()
.flat_map(Residue::par_conformers_mut)
}
//#[doc_cfg(feature = "rayon")]
//pub fn par_conformers_mut(&mut self) -> impl ParallelIterator<Item = &mut Conformer> + '_ {
//self.par_residues_mut()
//.flat_map(Residue::par_conformers_mut)
//}

/// Get an iterator of references to Atoms making up this Chain.
/// Double ended so iterating from the end is just as fast as from the start.
pub fn atoms(&self) -> impl DoubleEndedIterator<Item = &Atom> + '_ {
pub fn atoms(&self) -> impl DoubleEndedIterator<Item = Ref<'_, Atom>> + '_ {
self.residues().flat_map(Residue::atoms)
}

/// Get a parallel iterator of references to Atoms making up this Chain.
#[doc_cfg(feature = "rayon")]
pub fn par_atoms(&self) -> impl ParallelIterator<Item = &Atom> + '_ {
self.par_residues().flat_map(Residue::par_atoms)
}
//#[doc_cfg(feature = "rayon")]
//pub fn par_atoms(&self) -> impl ParallelIterator<Item = &Atom> + '_ {
// self.par_residues().flat_map(Residue::par_atoms)
//}

/// Get an iterator of mutable references to Atoms making up this Chain.
/// Double ended so iterating from the end is just as fast as from the start.
pub fn atoms_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Atom> + '_ {
pub fn atoms_mut(&mut self) -> impl DoubleEndedIterator<Item = RefMut<'_, Atom>> + '_ {
self.residues_mut().flat_map(Residue::atoms_mut)
}

/// Get a parallel iterator of mutablereferences to Atoms making up this Chain.
#[doc_cfg(feature = "rayon")]
pub fn par_atoms_mut(&mut self) -> impl ParallelIterator<Item = &mut Atom> + '_ {
self.par_residues_mut().flat_map(Residue::par_atoms_mut)
}
//#[doc_cfg(feature = "rayon")]
//pub fn par_atoms_mut(&mut self) -> impl ParallelIterator<Item = &mut Atom> + '_ {
// self.par_residues_mut().flat_map(Residue::par_atoms_mut)
//}

/// Get an iterator of references to a struct containing all atoms with their hierarchy making up this Chain.
pub fn atoms_with_hierarchy(
Expand Down Expand Up @@ -424,7 +425,7 @@ impl<'a> Chain {
/// Remove all Atoms matching the given predicate. As this is done in place this is the fastest way to remove Atoms from this Chain.
pub fn remove_atoms_by<F>(&mut self, predicate: F)
where
F: Fn(&Atom) -> bool,
F: Fn(Ref<'_, Atom>) -> bool,
{
for residue in self.residues_mut() {
residue.remove_atoms_by(&predicate);
Expand Down Expand Up @@ -481,17 +482,17 @@ impl<'a> Chain {
///
/// ## Arguments
/// * `id` - the id construct of the Residue to remove (see Residue.id())
#[doc_cfg(feature = "rayon")]
pub fn par_remove_residue_by_id(&mut self, id: (isize, Option<&str>)) -> bool {
let index = self.residues.par_iter().position_first(|a| a.id() == id);

if let Some(i) = index {
self.remove_residue(i);
true
} else {
false
}
}
//#[doc_cfg(feature = "rayon")]
//pub fn par_remove_residue_by_id(&mut self, id: (isize, Option<&str>)) -> bool {
// let index = self.residues.par_iter().position_first(|a| a.id() == id);
//
// if let Some(i) = index {
// self.remove_residue(i);
// true
// } else {
// false
// }
//}

/// Remove all empty Residues from this Chain, and all empty Conformers from the Residues.
pub fn remove_empty(&mut self) {
Expand All @@ -508,11 +509,11 @@ impl<'a> Chain {

/// Apply a transformation to the position of all atoms making up this Chain, the new position is immediately set.
/// Done in parallel.
#[doc_cfg(feature = "rayon")]
pub fn par_apply_transformation(&mut self, transformation: &TransformationMatrix) {
self.par_atoms_mut()
.for_each(|atom| atom.apply_transformation(transformation));
}
//#[doc_cfg(feature = "rayon")]
//pub fn par_apply_transformation(&mut self, transformation: &TransformationMatrix) {
// self.par_atoms_mut()
// .for_each(|atom| atom.apply_transformation(transformation));
//}

/// Join this Chain with another Chain, this moves all atoms from the other Chain
/// to this Chain. All other (meta) data of this Chain will stay the same.
Expand All @@ -525,11 +526,11 @@ impl<'a> Chain {
self.residues.sort();
}

/// Sort the residues of this chain in parallel
#[doc_cfg(feature = "rayon")]
pub fn par_sort(&mut self) {
self.residues.par_sort();
}
// Sort the residues of this chain in parallel
//#[doc_cfg(feature = "rayon")]
//pub fn par_sort(&mut self) {
// self.residues.par_sort();
//}
}

use std::fmt;
Expand Down
Loading