Skip to content

Commit

Permalink
Added support for SCALE and ORIGX in mmCIF #64
Browse files Browse the repository at this point in the history
  • Loading branch information
douweschulte committed Jul 20, 2022
1 parent fa86113 commit bdf2b5a
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 15 deletions.
30 changes: 15 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@ As the main goal of this library is to allow access to the atomical data many me

| PDB Feature | PDB | mmCIF | Corresponding in mmCIF |
|---------------|:---:|:-----:|-----------------------------|
| HEADER (ID) | ✔️ | ✔️ | entry.id |
| REMARK | ✔️ | | _pdbx_database_remark.id |
| ATOM | ✔️ | ✔️ | atom_site |
| ANISOU | ✔️ | ✔️ | atom_site |
| SCALE | ✔️ || _database_PDB_matrix.scale |
| ORIGX | ✔️ | | _database_PDB_matrix.origx |
| MATRIX | ✔️ | | ? |
| CRYSTAL | ✔️ | ✔️ | cell + symmetry |
| MODEL | ✔️ | ✔️ | atom_site |
| MASTER | 〰️ | | _pdbx_database_PDB_master |
| SEQRES | 〰️ | | ? |
| DBREF | ✔️ | | pdbx_dbref |
| DBREF1/2 | ✔️ | | pdbx_dbref |
| MODRES | ✔️ | | ? |
| SEQADV | ✔️ | | ? |
| HEADER (ID) | ✔️ | ✔️ | entry.id |
| REMARK | ✔️ | | _pdbx_database_remark.id |
| ATOM | ✔️ | ✔️ | atom_site |
| ANISOU | ✔️ | ✔️ | atom_site |
| SCALE | ✔️ | ✔️ | _atom_sites.Cartn_transf |
| ORIGX | ✔️ | ✔️ | _database_PDB_matrix.origx |
| MATRIX | ✔️ | | ? |
| CRYSTAL | ✔️ | ✔️ | cell + symmetry |
| MODEL | ✔️ | ✔️ | atom_site |
| MASTER | 〰️ | | _pdbx_database_PDB_master |
| SEQRES | 〰️ | | ? |
| DBREF | ✔️ | | pdbx_dbref |
| DBREF1/2 | ✔️ | | pdbx_dbref |
| MODRES | ✔️ | | ? |
| SEQADV | ✔️ | | ? |

| Section | Keywords | Support |
|---|---|---|
Expand Down
74 changes: 74 additions & 0 deletions src/read/mmcif/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::error::*;
use crate::structs::*;
use crate::validate::*;
use crate::StrictnessLevel;
use crate::TransformationMatrix;
use std::fs::File;
use std::io::prelude::*;

Expand Down Expand Up @@ -125,6 +126,20 @@ fn parse_mmcif(
None
}
}
s if s.starts_with("atom_sites.Cartn_transf") => {
if pdb.scale.is_none() {
pdb.scale = Some(TransformationMatrix::identity());
}
#[allow(clippy::unwrap_used)]
parse_matrix(s, get_f64(&single.content, &context),pdb.scale.as_mut().unwrap(), &context)
}
s if s.starts_with("database_PDB_matrix.origx") => {
if pdb.origx.is_none() {
pdb.origx = Some(TransformationMatrix::identity());
}
#[allow(clippy::unwrap_used)]
parse_matrix(s, get_f64(&single.content, &context),pdb.origx.as_mut().unwrap(), &context)
}
_ => None,
}
.map(|e| vec![e])
Expand All @@ -150,6 +165,65 @@ fn parse_mmcif(
}
}

/// Parse the name of this matrix defining line to find out the index it is pointing at and change that value in the given matrix.
fn parse_matrix(
name: &str,
value: Result<Option<f64>, PDBError>,
matrix: &mut TransformationMatrix,
context: &Context,
) -> Option<PDBError> {
let get_index = |n| {
if let Some(c) = name.chars().nth_back(n) {
if let Some(n) = c.to_digit(10) {
Ok((n - 1) as usize)
} else {
Err(PDBError::new(
ErrorLevel::InvalidatingError,
"Matrix item definition incorrect",
"There are no indices into the matrix. For example this is a valid name: `_database_PDB_matrix.origx[1][1]`",
context.clone(),
))
}
} else {
Err(PDBError::new(
ErrorLevel::InvalidatingError,
"Matrix definition too short",
"This matrix definition item name is too short to contain the matrix indices.",
context.clone(),
))
}
};
match value {
Ok(o) => {
if let Some(value) = o {
if name.matches('[').count() == 2 {
// Two sets of braces so a matrix line
let r = match get_index(4) {
Ok(o) => o,
Err(e) => return Some(e),
};
let c = match get_index(1) {
Ok(o) => o,
Err(e) => return Some(e),
};
matrix.matrix_mut()[r][c] = value;
} else {
// One set of braces so a vector line
let r = match get_index(1) {
Ok(o) => o,
Err(e) => return Some(e),
};
matrix.matrix_mut()[r][3] = value;
}
None // Everything went well
} else {
None // Ignore places where there is no value, assume it to be the default identity
}
}
Err(e) => Some(e),
}
}

/// Flatten a Result of a Result with the same error type (#70142 is still unstable)
fn flatten_result<T, E>(value: Result<Result<T, E>, E>) -> Result<T, E> {
match value {
Expand Down
66 changes: 66 additions & 0 deletions src/save/mmcif.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,72 @@ _cell.Z_PDB {}",
);
}

// Scale
if let Some(scale) = &pdb.scale {
let ma = scale.matrix();
write!(
"_atom_sites.entry_id '{}'
_atom_sites.Cartn_transf_matrix[1][1] {}
_atom_sites.Cartn_transf_matrix[1][2] {}
_atom_sites.Cartn_transf_matrix[1][3] {}
_atom_sites.Cartn_transf_matrix[2][1] {}
_atom_sites.Cartn_transf_matrix[2][2] {}
_atom_sites.Cartn_transf_matrix[2][3] {}
_atom_sites.Cartn_transf_matrix[3][1] {}
_atom_sites.Cartn_transf_matrix[3][2] {}
_atom_sites.Cartn_transf_matrix[3][3] {}
_atom_sites.Cartn_transf_vector[1] {}
_atom_sites.Cartn_transf_vector[2] {}
_atom_sites.Cartn_transf_vector[3] {}",
name,
ma[0][0],
ma[0][1],
ma[0][2],
ma[1][0],
ma[1][1],
ma[1][2],
ma[2][0],
ma[2][1],
ma[2][2],
ma[0][3],
ma[1][3],
ma[2][3],
);
}

// OrigX
if let Some(origx) = &pdb.origx {
let ma = origx.matrix();
write!(
"_database_PDB_matrix.entry_id '{}'
_database_PDB_matrix.origx[1][1] {}
_database_PDB_matrix.origx[1][2] {}
_database_PDB_matrix.origx[1][3] {}
_database_PDB_matrix.origx[2][1] {}
_database_PDB_matrix.origx[2][2] {}
_database_PDB_matrix.origx[2][3] {}
_database_PDB_matrix.origx[3][1] {}
_database_PDB_matrix.origx[3][2] {}
_database_PDB_matrix.origx[3][3] {}
_database_PDB_matrix.origx_vector[1] {}
_database_PDB_matrix.origx_vector[2] {}
_database_PDB_matrix.origx_vector[3] {}",
name,
ma[0][0],
ma[0][1],
ma[0][2],
ma[1][0],
ma[1][1],
ma[1][2],
ma[2][0],
ma[2][1],
ma[2][2],
ma[0][3],
ma[1][3],
ma[2][3],
);
}

if let Some(symmetry) = &pdb.symmetry {
write!(
"# Space group definition
Expand Down
5 changes: 5 additions & 0 deletions src/transformation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ impl TransformationMatrix {
self.matrix
}

/// Get the raw matrix (row major order)
pub fn matrix_mut(&mut self) -> &mut [[f64; 4]; 3] {
&mut self.matrix
}

/// Set the raw matrix (row major order), the user needs to make sure the matrix is valid
pub fn set_matrix(&mut self, new_matrix: [[f64; 4]; 3]) {
self.matrix = new_matrix;
Expand Down

0 comments on commit bdf2b5a

Please sign in to comment.