4
\$\begingroup\$

I am new to rust and wanted to get going with a medium-sized project to help learn. I've settled on creating some basic quantum mechanics code which starts with this bare-bones file reader. It takes a pdb file which is just a list of atom coordinates and the connections between them - with some extra information. I've included a basic pdb for testing below, the location string for the file requires changing.

I'm trying to use rust style as much as possible. Any suggestions on code/style improvement, no matter how small, are very welcome, thanks.

methanol.pdb:

COMPND    methanol
HETATM    1   C  UNL     1      -0.372   0.002   0.003  1.00  0.00           C
HETATM    2   O  UNL     1       0.898  -0.575  -0.119  1.00  0.00           O
HETATM    3   H  UNL     1      -0.674  -0.119   1.051  1.00  0.00           H
HETATM    4   H  UNL     1      -0.314   1.066  -0.315  1.00  0.00           H
HETATM    5   H  UNL     1      -1.083  -0.525  -0.643  1.00  0.00           H
HETATM    6   H  UNL     1       1.545   0.150   0.024  1.00  0.00           H
CONECT    1    2    3    4    5
CONECT    2    6
END

file_readers.rs:

use std::fs;

#[derive(Debug)]
struct Atom {
    /// May include atomic charges, masses etc in future
    atomic_symbol: String,
    index: i16,
    coords: (f64, f64, f64),
}

#[derive(Debug)]
struct Bond {
    atom_1_index: i16,
    atom_2_index: i16,
}

pub fn read_pdb() {
    /// Iterates over lines in any pdb file to produce vec of Atom structs
    /// Will be expanded in future to build graph of molecule as well

    let data = fs::read_to_string(
        "/home/b8009890/Documents/rusty_rockets/src/bin/euler_000_099/methanol.pdb")
        .expect("Unable to read file");

    // vec of strings where each element in vec is a line in the file
    let lines: Vec<&str> = data.lines().collect();
    let name: &str = &lines[0][10..];
    let mut molecule = Vec::new();
    let mut bonds = Vec::new();

    // loop over each element in the vec, starting from the 1st (not 0th)
    for line in lines[1..].iter() {
        if &line[..3] == "HET" {
            // atomic_symbol may be 1/2 chars so it's defined over a range not a specific index
            let atom = Atom {
                atomic_symbol: line[13..15].trim().parse::<String>().unwrap(),
                // pdbs count from 1, hence the -1
                index: line[10..13].trim().parse::<i16>().unwrap() - 1,
                // trim removes whitespace when there isn't a minus sign
                coords: (
                    line[32..38].trim().parse::<f64>().unwrap(),
                    line[40..46].trim().parse::<f64>().unwrap(),
                    line[48..54].trim().parse::<f64>().unwrap(),
                )
            };
            molecule.push(atom);
        } else if &line[..3] == "CON" {
            let parent_index = line[10..13].trim().parse::<usize>().unwrap() - 1;

            for atom_index in line[14..].split_whitespace() {
                let child_index = atom_index.parse::<usize>().unwrap() - 1;
                let bond = Bond {
                    atom_1_index: molecule[parent_index].index,
                    atom_2_index: molecule[child_index].index,
                };
                bonds.push(bond);
            }
        } else {
            break
        }
    }

    println!("{:?}\n{:?}\n{:?}\n", molecule, name, bonds);
}

Please be aware the very specific ranges for extracting the coords and such are from the official pdb format guide. Occasionally coords can overlap if using high precision e.g. -0.56789-0.12345 so generally slicing is used instead of splitting over whitespace.

EDIT: After trying to implement a graph structure using petgraph for the molecule, I instead just added a Vec of tuples for my bonds. This seems much easier than a (potentially) cyclic graph; I know they cause issues with the borrowing system. Anyway, the code is updated and now slightly longer than before but not really anymore complex.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.