Skip to content

Commit 4d5da93

Browse files
authored
Merge pull request #9 from Ladme/0.11
0.11
2 parents 1521afa + c51b30c commit 4d5da93

22 files changed

+1188
-30
lines changed

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "groan_rs"
33
description = "Gromacs Analysis Library for Rust"
4-
version = "0.10.0"
4+
version = "0.11.0"
55
license = "MIT"
66
edition = "2021"
77
authors = ["Ladislav Bartos"]
@@ -28,14 +28,14 @@ regex = "1.11.1"
2828
thiserror = "2.0.12"
2929
serde = { version = "1.0.218", features = ["derive"] }
3030
serde_yaml = "0.9"
31-
fancy-regex = "0.14.0"
32-
nalgebra = "0.33.2"
31+
fancy-regex = "0.16.1"
32+
nalgebra = "0.34.0"
3333
minitpr = "0.2.3"
3434
ndarray = "0.16.1"
3535
hashbrown = "0.15.2"
3636
getset = "0.1.5"
3737
parking_lot = { version = "0.12.3", optional = true }
38-
molly = { version = "0.3.3", optional = true }
38+
molly = { version = "0.4.0", optional = true }
3939
chemfiles = { version = "0.10.41", optional = true }
4040
itertools = "0.14.0"
4141
dyn-clone = "1.0.19"

changelog.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11

22
## Changelog for the `groan_rs` library
33

4+
### Version 0.11.0
5+
6+
#### Groan Selection Language v0.11
7+
- Updated the `@membrane` macro, which should now match a wider variety of lipid molecules.
8+
- GSL queries with empty quoted blocks no longer panic.
9+
10+
#### Bug fixes
11+
- GRO, PDB, and PQR files with NaN positions (or velocities) are no longer parsed and instead raise an error.
12+
13+
***
14+
415
### Version 0.10.0
516

617
#### New XTC Parser

src/errors.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ pub enum ParseGroError {
6969
/// Used when the "box line" in the gro file could be parsed but the simulation box is not supported by Gromacs.
7070
#[error("{} simulation box on line '{}' is not supported (4th, 5th, and 7th element must be zero)", "error:".red().bold(), .0.yellow())]
7171
UnsupportedBox(String),
72+
/// Used when a gro line contains an invalid floating point number (nan, inf...).
73+
#[error("{} could not parse line '{}' because it contains an invalid floating point number", "error:".red().bold(), .0.yellow())]
74+
InvalidFloat(String),
7275
}
7376

7477
/// Errors that can occur when reading and parsing pdb file.
@@ -94,6 +97,9 @@ pub enum ParsePdbError {
9497
/// Used when a "TITLE" line in the pdb file could not be parsed.
9598
#[error("{} could not parse line '{}' as title", "error:".red().bold(), .0.yellow())]
9699
ParseTitleLineErr(String),
100+
/// Used when a pdb line contains an invalid floating point number (nan, inf...).
101+
#[error("{} could not parse line '{}' because it contains an invalid floating point number", "error:".red().bold(), .0.yellow())]
102+
InvalidFloat(String),
97103
}
98104

99105
/// Errors that can occur when reading the connectivity section of a PDB file.
@@ -186,6 +192,9 @@ pub enum ParsePqrError {
186192
/// Used when a "TITLE" line in the pqr file could not be parsed.
187193
#[error("{} could not parse line '{}' as title", "error:".red().bold(), .0.yellow())]
188194
ParseTitleLineErr(String),
195+
/// Used when a pqr line contains an invalid floating point number (nan, inf...).
196+
#[error("{} could not parse line '{}' because it contains an invalid floating point number", "error:".red().bold(), .0.yellow())]
197+
InvalidFloat(String),
189198
}
190199

191200
/// Errors that can occur when writing a pqr file.
@@ -406,6 +415,9 @@ pub enum ReadTrajError {
406415
/// Used when an unknown error occurs.
407416
#[error("{} an unknown error occured when reading a trajectory: '{}'", "error:".red().bold(), .0.yellow())]
408417
UnknownError(String),
418+
/// Used when an error specific to GRO files has been encountered.
419+
#[error("{}", .0)]
420+
GroSpecificError(ParseGroError),
409421
}
410422

411423
/// Errors that can occur when writing a trajectory file.

src/io/gro_io/structure.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,10 @@ fn line_as_atom(line: &str) -> Result<Atom, ParseGroError> {
200200
.trim()
201201
.parse::<f32>()
202202
.map_err(|_| ParseGroError::ParseAtomLineErr(line.to_string()))?;
203+
204+
if !item.is_finite() {
205+
return Err(ParseGroError::InvalidFloat(line.to_string()));
206+
}
203207
}
204208

205209
let atom = Atom::new(resid, &resname, atomid, &atomname).with_position(position.into());
@@ -214,6 +218,10 @@ fn line_as_atom(line: &str) -> Result<Atom, ParseGroError> {
214218
.trim()
215219
.parse::<f32>()
216220
.map_err(|_| ParseGroError::ParseAtomLineErr(line.to_string()))?;
221+
222+
if !item.is_finite() {
223+
return Err(ParseGroError::InvalidFloat(line.to_string()));
224+
}
217225
}
218226

219227
Ok(atom.with_velocity(velocity.into()))
@@ -555,6 +563,20 @@ mod tests_read {
555563
panic!("Parsing should have failed, but it succeeded.")
556564
}
557565
}
566+
567+
read_gro_fails!(
568+
read_nan_position,
569+
"test_files/nan_error.gro",
570+
ParseGroError::InvalidFloat,
571+
" 19ALA SC1 39 nan 2.496 5.027 0.0733 -0.2227 -0.2563"
572+
);
573+
574+
read_gro_fails!(
575+
read_nan_velocity,
576+
"test_files/nan_error_velocity.gro",
577+
ParseGroError::InvalidFloat,
578+
" 6VAL BB 12 9.947 2.258 6.831 -0.2096 NaN 0.0665"
579+
);
558580
}
559581

560582
#[cfg(test)]

src/io/gro_io/trajectory.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::{fs::File, io::BufReader};
1212
use regex::Regex;
1313

1414
use crate::auxiliary::{GRO_MAX_COORDINATE, GRO_MIN_COORDINATE};
15-
use crate::errors::WriteTrajError;
15+
use crate::errors::{ParseGroError, WriteTrajError};
1616
use crate::io::check_coordinate_sizes;
1717
use crate::io::traj_write::{PrivateTrajWrite, TrajWrite};
1818
use crate::prelude::{
@@ -97,6 +97,12 @@ fn read_position_velocity(
9797
.trim()
9898
.parse::<f32>()
9999
.map_err(|_| ReadTrajError::FrameNotFound)?;
100+
101+
if !item.is_finite() {
102+
return Err(ReadTrajError::GroSpecificError(
103+
ParseGroError::InvalidFloat(line.to_string()),
104+
));
105+
}
100106
}
101107

102108
let velocity = if line.trim_end().len() >= 68 {
@@ -108,6 +114,12 @@ fn read_position_velocity(
108114
.trim()
109115
.parse::<f32>()
110116
.map_err(|_| ReadTrajError::FrameNotFound)?;
117+
118+
if !item.is_finite() {
119+
return Err(ReadTrajError::GroSpecificError(
120+
ParseGroError::InvalidFloat(line.to_string()),
121+
));
122+
}
111123
}
112124

113125
Some(velocity)
@@ -430,7 +442,7 @@ impl System {
430442
pub fn gro_iter(
431443
&mut self,
432444
filename: impl AsRef<Path>,
433-
) -> Result<TrajReader<GroReader>, ReadTrajError> {
445+
) -> Result<TrajReader<'_, GroReader<'_>>, ReadTrajError> {
434446
Ok(TrajReader::wrap_traj(GroReader::new(self, filename)?))
435447
}
436448
}
@@ -939,6 +951,27 @@ mod tests_read {
939951
None => panic!("Iterator is empty."),
940952
}
941953
}
954+
955+
#[test]
956+
fn gro_iter_nan_position() {
957+
let mut system = System::from_file("test_files/protein.gro").unwrap();
958+
959+
match system
960+
.gro_iter("test_files/nan_trajectory.gro")
961+
.unwrap()
962+
.nth(3)
963+
{
964+
Some(Ok(_)) => panic!("Function should have failed."),
965+
Some(Err(ReadTrajError::GroSpecificError(ParseGroError::InvalidFloat(x)))) => {
966+
assert_eq!(
967+
x,
968+
String::from(" 23ALA SC1 47 6.290 NaN 4.190\n")
969+
)
970+
}
971+
Some(Err(e)) => panic!("Unexpected error type `{}` returned.", e),
972+
None => panic!("Iterator is empty."),
973+
}
974+
}
942975
}
943976

944977
#[cfg(test)]

src/io/pdb_io.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,10 @@ fn line_as_atom(line: &str) -> Result<Atom, ParsePdbError> {
388388
.map(|x| x / 10.0)
389389
.map_err(|_| ParsePdbError::ParseAtomLineErr(line.to_string()))?;
390390

391+
if !pos.is_finite() {
392+
return Err(ParsePdbError::InvalidFloat(line.to_string()));
393+
}
394+
391395
curr += 8;
392396
}
393397

@@ -1092,6 +1096,13 @@ mod tests_read {
10921096
"ATOM 30 SC1 ARG A 14 32.540 35.200 34.040 1.00 0.00 "
10931097
);
10941098

1099+
read_pdb_fails!(
1100+
read_nan_position,
1101+
"test_files/nan_error.pdb",
1102+
ParsePdbError::InvalidFloat,
1103+
"ATOM 4 SC2 LYS 2 98.640 26.920 NaN 1.00 0.00 "
1104+
);
1105+
10951106
macro_rules! read_bonds_fails {
10961107
($name:ident, $file_struct:expr, $file_bonds:expr, $variant:path, $expected:expr) => {
10971108
#[test]

src/io/pqr_io.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@ fn line_as_atom(line: &str) -> Result<Atom, ParsePqrError> {
258258
let y = parse_float(line, split[7 - convert])? / 10.0;
259259
let z = parse_float(line, split[8 - convert])? / 10.0;
260260

261+
if !x.is_finite() || !y.is_finite() || !z.is_finite() {
262+
return Err(ParsePqrError::InvalidFloat(line.to_string()));
263+
}
264+
261265
let charge = parse_float(line, split[9 - convert])?;
262266
let vdw = parse_float(line, split[10 - convert])? / 10.0;
263267

@@ -552,6 +556,13 @@ mod tests_read {
552556
ParsePqrError::ParseBoxLineErr,
553557
"CRYST1 60.861 60.861.3 60.861 90.00 90.00 90.00 P 1 1"
554558
);
559+
560+
read_pqr_fails!(
561+
read_nan_position,
562+
"test_files/nan_error.pqr",
563+
ParsePqrError::InvalidFloat,
564+
"ATOM 32 BB VAL C 15 35.650 33.730 NaN 0.0000 0.0000"
565+
);
555566
}
556567

557568
#[cfg(test)]

src/io/trr_io.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ impl System {
374374
pub fn trr_iter(
375375
&mut self,
376376
filename: impl AsRef<Path>,
377-
) -> Result<TrajReader<TrrReader>, ReadTrajError> {
377+
) -> Result<TrajReader<'_, TrrReader<'_>>, ReadTrajError> {
378378
Ok(TrajReader::wrap_traj(TrrReader::new(self, filename)?))
379379
}
380380

src/io/xtc_io/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ impl System {
172172
pub fn xtc_iter(
173173
&mut self,
174174
filename: impl AsRef<Path>,
175-
) -> Result<TrajReader<XtcReader>, ReadTrajError> {
175+
) -> Result<TrajReader<'_, XtcReader<'_>>, ReadTrajError> {
176176
Ok(TrajReader::wrap_traj(XtcReader::new(self, filename)?))
177177
}
178178

src/io/xtc_io/molly_xtc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ impl System {
635635
&mut self,
636636
filename: impl AsRef<Path>,
637637
group: &str,
638-
) -> Result<TrajReader<GroupXtcReader>, ReadTrajError> {
638+
) -> Result<TrajReader<'_, GroupXtcReader<'_>>, ReadTrajError> {
639639
Ok(TrajReader::wrap_traj(GroupXtcReader::new(
640640
self, filename, group,
641641
)?))

0 commit comments

Comments
 (0)