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.
Files changed (58) hide show
  1. bentopy-0.2.0a10.data/scripts/bentopy-init +0 -0
  2. bentopy-0.2.0a10.data/scripts/bentopy-pack +0 -0
  3. bentopy-0.2.0a10.data/scripts/bentopy-render +0 -0
  4. bentopy-0.2.0a10.data/scripts/bentopy-solvate +0 -0
  5. bentopy-0.2.0a10.dist-info/METADATA +358 -0
  6. bentopy-0.2.0a10.dist-info/RECORD +58 -0
  7. bentopy-0.2.0a10.dist-info/WHEEL +5 -0
  8. bentopy-0.2.0a10.dist-info/entry_points.txt +4 -0
  9. bentopy-0.2.0a10.dist-info/licenses/LICENSE.txt +13 -0
  10. bentopy-0.2.0a10.dist-info/top_level.txt +8 -0
  11. check/check.py +128 -0
  12. core/config/bent/lexer.rs +338 -0
  13. core/config/bent/parser.rs +1180 -0
  14. core/config/bent/writer.rs +205 -0
  15. core/config/bent.rs +149 -0
  16. core/config/compartment_combinations.rs +300 -0
  17. core/config/legacy.rs +768 -0
  18. core/config.rs +362 -0
  19. core/mod.rs +4 -0
  20. core/placement.rs +100 -0
  21. core/utilities.rs +1 -0
  22. core/version.rs +32 -0
  23. init/example.bent +74 -0
  24. init/main.rs +235 -0
  25. mask/config.py +153 -0
  26. mask/mask.py +308 -0
  27. mask/utilities.py +38 -0
  28. merge/merge.py +175 -0
  29. pack/args.rs +77 -0
  30. pack/main.rs +121 -0
  31. pack/mask.rs +940 -0
  32. pack/session.rs +176 -0
  33. pack/state/combinations.rs +31 -0
  34. pack/state/compartment.rs +44 -0
  35. pack/state/mask.rs +196 -0
  36. pack/state/pack.rs +187 -0
  37. pack/state/segment.rs +72 -0
  38. pack/state/space.rs +98 -0
  39. pack/state.rs +440 -0
  40. pack/structure.rs +185 -0
  41. pack/voxelize.rs +85 -0
  42. render/args.rs +109 -0
  43. render/limits.rs +73 -0
  44. render/main.rs +12 -0
  45. render/render.rs +393 -0
  46. render/structure.rs +264 -0
  47. solvate/args.rs +324 -0
  48. solvate/convert.rs +25 -0
  49. solvate/cookies.rs +185 -0
  50. solvate/main.rs +177 -0
  51. solvate/placement.rs +380 -0
  52. solvate/solvate.rs +244 -0
  53. solvate/structure.rs +160 -0
  54. solvate/substitute.rs +113 -0
  55. solvate/water/martini.rs +409 -0
  56. solvate/water/models.rs +150 -0
  57. solvate/water/tip3p.rs +658 -0
  58. 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
+ }