bentopy 0.2.0a10__cp313-cp313-manylinux_2_34_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bentopy-0.2.0a10.data/scripts/bentopy-init +0 -0
- bentopy-0.2.0a10.data/scripts/bentopy-pack +0 -0
- bentopy-0.2.0a10.data/scripts/bentopy-render +0 -0
- bentopy-0.2.0a10.data/scripts/bentopy-solvate +0 -0
- bentopy-0.2.0a10.dist-info/METADATA +358 -0
- bentopy-0.2.0a10.dist-info/RECORD +58 -0
- bentopy-0.2.0a10.dist-info/WHEEL +5 -0
- bentopy-0.2.0a10.dist-info/entry_points.txt +4 -0
- bentopy-0.2.0a10.dist-info/licenses/LICENSE.txt +13 -0
- bentopy-0.2.0a10.dist-info/top_level.txt +8 -0
- check/check.py +128 -0
- core/config/bent/lexer.rs +338 -0
- core/config/bent/parser.rs +1180 -0
- core/config/bent/writer.rs +205 -0
- core/config/bent.rs +149 -0
- core/config/compartment_combinations.rs +300 -0
- core/config/legacy.rs +768 -0
- core/config.rs +362 -0
- core/mod.rs +4 -0
- core/placement.rs +100 -0
- core/utilities.rs +1 -0
- core/version.rs +32 -0
- init/example.bent +74 -0
- init/main.rs +235 -0
- mask/config.py +153 -0
- mask/mask.py +308 -0
- mask/utilities.py +38 -0
- merge/merge.py +175 -0
- pack/args.rs +77 -0
- pack/main.rs +121 -0
- pack/mask.rs +940 -0
- pack/session.rs +176 -0
- pack/state/combinations.rs +31 -0
- pack/state/compartment.rs +44 -0
- pack/state/mask.rs +196 -0
- pack/state/pack.rs +187 -0
- pack/state/segment.rs +72 -0
- pack/state/space.rs +98 -0
- pack/state.rs +440 -0
- pack/structure.rs +185 -0
- pack/voxelize.rs +85 -0
- render/args.rs +109 -0
- render/limits.rs +73 -0
- render/main.rs +12 -0
- render/render.rs +393 -0
- render/structure.rs +264 -0
- solvate/args.rs +324 -0
- solvate/convert.rs +25 -0
- solvate/cookies.rs +185 -0
- solvate/main.rs +177 -0
- solvate/placement.rs +380 -0
- solvate/solvate.rs +244 -0
- solvate/structure.rs +160 -0
- solvate/substitute.rs +113 -0
- solvate/water/martini.rs +409 -0
- solvate/water/models.rs +150 -0
- solvate/water/tip3p.rs +658 -0
- solvate/water.rs +115 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
use std::str::FromStr;
|
|
2
|
+
|
|
3
|
+
use chumsky::{prelude::*, text::Char};
|
|
4
|
+
|
|
5
|
+
use crate::core::config::Point;
|
|
6
|
+
|
|
7
|
+
/// A shorter alias for this otherwise rather unwieldy type.
|
|
8
|
+
type E<'src> = extra::Err<Rich<'src, char>>;
|
|
9
|
+
|
|
10
|
+
// TODO: Move to chumsky::Spanned when that is released.
|
|
11
|
+
pub type Spanned<T> = (T, SimpleSpan);
|
|
12
|
+
|
|
13
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
14
|
+
pub enum Number {
|
|
15
|
+
Float(f64),
|
|
16
|
+
Integer(u64),
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
impl Number {
|
|
20
|
+
pub fn as_float(&self) -> f64 {
|
|
21
|
+
match *self {
|
|
22
|
+
Self::Float(f) => f,
|
|
23
|
+
Self::Integer(i) => i as f64,
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
29
|
+
pub enum Token<'s> {
|
|
30
|
+
// Values
|
|
31
|
+
Ident(&'s str),
|
|
32
|
+
Number(Number),
|
|
33
|
+
Point(Point),
|
|
34
|
+
Concentration(f64),
|
|
35
|
+
String(&'s str),
|
|
36
|
+
Section(&'s str),
|
|
37
|
+
Placeholder(&'s str),
|
|
38
|
+
|
|
39
|
+
// Interpunction
|
|
40
|
+
ParenOpen,
|
|
41
|
+
ParenClose,
|
|
42
|
+
Comma,
|
|
43
|
+
Colon,
|
|
44
|
+
|
|
45
|
+
// Operators
|
|
46
|
+
Not,
|
|
47
|
+
And,
|
|
48
|
+
Or,
|
|
49
|
+
GreaterThan,
|
|
50
|
+
LessThan,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
impl std::fmt::Display for Token<'_> {
|
|
54
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
55
|
+
match self {
|
|
56
|
+
Token::Ident(ident) => write!(f, "word {ident:?}"),
|
|
57
|
+
Token::Number(Number::Float(n)) => write!(f, "float {n}"),
|
|
58
|
+
Token::Number(Number::Integer(n)) => write!(f, "integer {n}"),
|
|
59
|
+
Token::Point([x, y, z]) => write!(f, "point ({x}, {y}, {z})"),
|
|
60
|
+
Token::String(path) => write!(f, "string {path:?}"),
|
|
61
|
+
Token::Concentration(conc) => write!(f, "concentration ({conc}M)"),
|
|
62
|
+
Token::Section(header) => write!(f, "section header {header:?}"),
|
|
63
|
+
Token::Placeholder(name) => write!(f, "placeholder {name:?}"),
|
|
64
|
+
Token::ParenOpen => write!(f, "("),
|
|
65
|
+
Token::ParenClose => write!(f, ")"),
|
|
66
|
+
Token::Comma => write!(f, ","),
|
|
67
|
+
Token::Colon => write!(f, ":"),
|
|
68
|
+
Token::Not => write!(f, "not"),
|
|
69
|
+
Token::And => write!(f, "and"),
|
|
70
|
+
Token::Or => write!(f, "or"),
|
|
71
|
+
Token::GreaterThan => write!(f, ">"),
|
|
72
|
+
Token::LessThan => write!(f, "<"),
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
mod components {
|
|
78
|
+
use super::*;
|
|
79
|
+
|
|
80
|
+
// There could be advantages to placing this in the parser, rather than the lexer. But for now
|
|
81
|
+
// I think this is the best choice.
|
|
82
|
+
/// A three-value point, values separated by commas, optionally delimited by parentheses.
|
|
83
|
+
pub(crate) fn point<'s>() -> impl Parser<'s, &'s str, Point, E<'s>> {
|
|
84
|
+
let number = regex(r"[-+]?(\d*\.\d+|\d+\.?\d*)")
|
|
85
|
+
.map(FromStr::from_str)
|
|
86
|
+
.unwrapped()
|
|
87
|
+
.labelled("number");
|
|
88
|
+
let point = number
|
|
89
|
+
.separated_by(just(',').padded())
|
|
90
|
+
.collect_exactly::<Point>();
|
|
91
|
+
let parens_point = point.clone().padded().delimited_by(just('('), just(')'));
|
|
92
|
+
choice((point, parens_point))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
pub(crate) fn identifier_builder<'s>(
|
|
96
|
+
illegal: &'static [char],
|
|
97
|
+
) -> impl Parser<'s, &'s str, &'s str, E<'s>> {
|
|
98
|
+
any()
|
|
99
|
+
.filter(|c: &char| !c.is_whitespace() && !illegal.contains(c))
|
|
100
|
+
.repeated()
|
|
101
|
+
.at_least(1)
|
|
102
|
+
.to_slice()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
pub(crate) fn string<'s>() -> impl Parser<'s, &'s str, &'s str, E<'s>> {
|
|
106
|
+
any()
|
|
107
|
+
.filter(|c: &char| !c.is_newline() && *c != '"')
|
|
108
|
+
.repeated()
|
|
109
|
+
.at_least(1)
|
|
110
|
+
.to_slice()
|
|
111
|
+
.padded_by(just('"'))
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
pub(crate) fn identifier<'s>() -> impl Parser<'s, &'s str, &'s str, E<'s>> {
|
|
115
|
+
identifier_builder(&['(', ')', '[', ']', ',', ':', '"', '<', '>'])
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
pub(crate) fn comment<'s>() -> impl Parser<'s, &'s str, &'s str, E<'s>> {
|
|
119
|
+
choice((just('#'), just(';')))
|
|
120
|
+
.padded()
|
|
121
|
+
.ignore_then(any().filter(|c: &char| !c.is_newline()).repeated())
|
|
122
|
+
.to_slice()
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
pub fn lexer<'s>() -> impl Parser<'s, &'s str, Vec<Spanned<Token<'s>>>, extra::Err<Rich<'s, char>>>
|
|
127
|
+
{
|
|
128
|
+
let operator = |s: &'static str| just(s).labelled(s);
|
|
129
|
+
let integer = text::int(10)
|
|
130
|
+
.map(FromStr::from_str)
|
|
131
|
+
.unwrapped()
|
|
132
|
+
// This is a bit cursed, but we need to make sure that an int is not followed by an
|
|
133
|
+
// alphabetic character.
|
|
134
|
+
.then_ignore(any().filter(|c: &char| c.is_alphabetic()).not())
|
|
135
|
+
.boxed();
|
|
136
|
+
let float = regex(r"[-+]?(\d*\.\d+)")
|
|
137
|
+
.map(FromStr::from_str)
|
|
138
|
+
.unwrapped()
|
|
139
|
+
.boxed();
|
|
140
|
+
let number = choice((float.map(Number::Float), integer.map(Number::Integer)))
|
|
141
|
+
.map(Token::Number)
|
|
142
|
+
.boxed();
|
|
143
|
+
// This is a bit silly, but if we want concentrations like 1M to work like 1.0M, we need a
|
|
144
|
+
// leniant notion of a float that can also match integers. But just for concentrations.
|
|
145
|
+
let leniant_float = regex(r"[-+]?(\d*\.?\d+)")
|
|
146
|
+
.map(f64::from_str)
|
|
147
|
+
.unwrapped()
|
|
148
|
+
.boxed();
|
|
149
|
+
// TODO: Introduce mM and nM quantities as well.
|
|
150
|
+
let unit = choice((
|
|
151
|
+
just('M').to(1.0),
|
|
152
|
+
just("mM").to(1e-3),
|
|
153
|
+
just("uM").or(just("µM")).to(1e-6),
|
|
154
|
+
just("nM").to(1e-9),
|
|
155
|
+
just("pM").to(1e-12),
|
|
156
|
+
));
|
|
157
|
+
let concentration = leniant_float
|
|
158
|
+
.clone()
|
|
159
|
+
.then(unit)
|
|
160
|
+
.map(|(v, u)| Token::Concentration(v * u))
|
|
161
|
+
.boxed();
|
|
162
|
+
let section = components::identifier()
|
|
163
|
+
.padded()
|
|
164
|
+
.delimited_by(just('['), just(']'))
|
|
165
|
+
.map(Token::Section)
|
|
166
|
+
.boxed();
|
|
167
|
+
let placeholder = components::identifier()
|
|
168
|
+
.padded()
|
|
169
|
+
.delimited_by(just('<'), just('>'))
|
|
170
|
+
.map(Token::Placeholder)
|
|
171
|
+
.boxed();
|
|
172
|
+
let point = components::point().map(Token::Point).boxed();
|
|
173
|
+
|
|
174
|
+
choice((
|
|
175
|
+
// Unparseable
|
|
176
|
+
placeholder,
|
|
177
|
+
// Operators
|
|
178
|
+
operator("not").to(Token::Not),
|
|
179
|
+
operator("and").to(Token::And),
|
|
180
|
+
operator("or").to(Token::Or),
|
|
181
|
+
operator("<").to(Token::LessThan),
|
|
182
|
+
operator(">").to(Token::GreaterThan),
|
|
183
|
+
// Values
|
|
184
|
+
point,
|
|
185
|
+
concentration,
|
|
186
|
+
number,
|
|
187
|
+
section,
|
|
188
|
+
components::string().map(Token::String),
|
|
189
|
+
components::identifier().map(Token::Ident),
|
|
190
|
+
// Separators
|
|
191
|
+
just(',').to(Token::Comma),
|
|
192
|
+
just(':').to(Token::Colon),
|
|
193
|
+
just('(').to(Token::ParenOpen),
|
|
194
|
+
just(')').to(Token::ParenClose),
|
|
195
|
+
))
|
|
196
|
+
.map_with(|t, e| (t, e.span()))
|
|
197
|
+
.padded()
|
|
198
|
+
// Tokens usually follow each other directly, but there may be comments between them.
|
|
199
|
+
.separated_by(choice((
|
|
200
|
+
components::comment()
|
|
201
|
+
.ignored()
|
|
202
|
+
.padded()
|
|
203
|
+
.repeated()
|
|
204
|
+
.at_least(1),
|
|
205
|
+
empty(),
|
|
206
|
+
)))
|
|
207
|
+
.allow_leading()
|
|
208
|
+
.allow_trailing()
|
|
209
|
+
.collect()
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
#[cfg(test)]
|
|
213
|
+
mod test {
|
|
214
|
+
use super::*;
|
|
215
|
+
|
|
216
|
+
fn p<'s, T>(
|
|
217
|
+
p: impl Parser<'s, &'s str, T, E<'s>>,
|
|
218
|
+
s: &'s str,
|
|
219
|
+
) -> Result<T, Vec<Rich<'s, char>>> {
|
|
220
|
+
p.parse(s).into_result()
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
mod point {
|
|
224
|
+
use super::*;
|
|
225
|
+
#[test]
|
|
226
|
+
fn point_floats() {
|
|
227
|
+
assert_eq!(p(components::point(), "1.0, 2.0, 3.0"), Ok([1.0, 2.0, 3.0]));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
#[test]
|
|
231
|
+
fn point_integers() {
|
|
232
|
+
assert_eq!(p(components::point(), "1, 2, 3"), Ok([1.0, 2.0, 3.0]));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
#[test]
|
|
236
|
+
fn point_mixed() {
|
|
237
|
+
assert_eq!(p(components::point(), "1.0, 2, 3"), Ok([1.0, 2.0, 3.0]));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
#[test]
|
|
241
|
+
fn point_whitespace() {
|
|
242
|
+
assert_eq!(p(components::point(), "1.0,2,3"), Ok([1.0, 2.0, 3.0]));
|
|
243
|
+
assert_eq!(p(components::point(), "1.0 ,2 ,3"), Ok([1.0, 2.0, 3.0]));
|
|
244
|
+
assert_eq!(p(components::point(), "1.0 , 2 , 3"), Ok([1.0, 2.0, 3.0]));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
#[test]
|
|
248
|
+
fn point_with_parentheses() {
|
|
249
|
+
assert_eq!(
|
|
250
|
+
p(components::point(), "(1.0, 2.0, 3.0)"),
|
|
251
|
+
Ok([1.0, 2.0, 3.0])
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
#[test]
|
|
256
|
+
fn point_with_parentheses_whitespace() {
|
|
257
|
+
assert_eq!(
|
|
258
|
+
p(components::point(), "( 1.0, 2.0, 3.0 )"),
|
|
259
|
+
Ok([1.0, 2.0, 3.0])
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
#[test]
|
|
264
|
+
fn bad_points() {
|
|
265
|
+
assert!(p(components::point(), "1.0, 2.0").is_err());
|
|
266
|
+
assert!(p(components::point(), "1.0, (2.0").is_err());
|
|
267
|
+
assert!(p(components::point(), "((1.0, 2.0, 3.0))").is_err());
|
|
268
|
+
assert!(p(components::point(), "1.0, .2.0, 3.0").is_err());
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
mod string {
|
|
273
|
+
use super::*;
|
|
274
|
+
#[test]
|
|
275
|
+
fn string() {
|
|
276
|
+
assert_eq!(p(components::string(), r#""abc""#), Ok("abc"));
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
#[test]
|
|
280
|
+
fn bad_string_single_quotes() {
|
|
281
|
+
assert!(p(components::string(), r#"'abc'"#).is_err());
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
#[test]
|
|
285
|
+
fn bad_string_extra_quote() {
|
|
286
|
+
assert!(p(components::string(), r#""ab"c""#).is_err());
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
mod identifier {
|
|
291
|
+
use super::*;
|
|
292
|
+
|
|
293
|
+
#[test]
|
|
294
|
+
fn identifier() {
|
|
295
|
+
assert_eq!(p(components::identifier(), "abc"), Ok("abc"));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
#[test]
|
|
299
|
+
fn lysozyme() {
|
|
300
|
+
assert_eq!(p(components::identifier(), "3lyz"), Ok("3lyz"));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
#[test]
|
|
304
|
+
fn containing_double_quote() {
|
|
305
|
+
assert!(p(components::identifier(), r#""ab"c""#).is_err());
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
mod comment {
|
|
310
|
+
use super::*;
|
|
311
|
+
|
|
312
|
+
#[test]
|
|
313
|
+
fn comment() {
|
|
314
|
+
assert_eq!(p(components::comment(), "# abc"), Ok("# abc"));
|
|
315
|
+
assert_eq!(p(components::comment(), "; abc"), Ok("; abc"));
|
|
316
|
+
assert!(p(components::comment(), "// abc").is_err());
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
#[test]
|
|
320
|
+
fn many() {
|
|
321
|
+
assert_eq!(
|
|
322
|
+
p(components::comment(), "# abc # a # b # c"),
|
|
323
|
+
Ok("# abc # a # b # c")
|
|
324
|
+
);
|
|
325
|
+
assert_eq!(p(components::comment(), "; abc"), Ok("; abc"));
|
|
326
|
+
assert!(p(components::comment(), "// abc").is_err());
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
#[test]
|
|
330
|
+
fn weird_whitespace() {
|
|
331
|
+
assert_eq!(p(components::comment(), "#abc"), Ok("#abc"));
|
|
332
|
+
assert_eq!(
|
|
333
|
+
p(components::comment(), "\t\t # \t abc\t\t"),
|
|
334
|
+
Ok("\t\t # \t abc\t\t")
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|