automol 0.0.1__py3-none-any.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.
automol/__init__.py ADDED
@@ -0,0 +1,8 @@
1
+ """automol."""
2
+
3
+ __version__ = "0.0.1"
4
+
5
+ from . import geom, types
6
+ from .geom import Geometry
7
+
8
+ __all__ = ["geom", "types", "Geometry"]
@@ -0,0 +1,5 @@
1
+ """Element data."""
2
+
3
+ from .core import Element, from_key, mass, mass_number, number, symbol
4
+
5
+ __all__ = ["Element", "from_key", "mass", "mass_number", "number", "symbol"]
@@ -0,0 +1,140 @@
1
+ """Core element interface."""
2
+
3
+ import json
4
+ from dataclasses import dataclass
5
+ from pathlib import Path
6
+
7
+
8
+ @dataclass(frozen=True, slots=True)
9
+ class Element:
10
+ """
11
+ Chemical element.
12
+
13
+ Attributes
14
+ ----------
15
+ Z :
16
+ Atomic number.
17
+ A :
18
+ Mass number.
19
+ symbol :
20
+ Chemical symbol.
21
+ mass :
22
+ Atomic mass.
23
+ """
24
+
25
+ Z: int
26
+ A: int
27
+ symbol: str
28
+ mass: float
29
+
30
+
31
+ ELEMENT_BY_NUMBER: dict[int, Element] = {}
32
+ ELEMENT_BY_SYMBOL: dict[str, Element] = {}
33
+
34
+
35
+ def _load_elements() -> None:
36
+ data_path = Path(__file__).with_name("elements-data.json")
37
+
38
+ with data_path.open() as f:
39
+ elements_data: list[dict[str, object]] = json.load(f)
40
+
41
+ for element_data in elements_data:
42
+ element = Element(**element_data)
43
+
44
+ ELEMENT_BY_NUMBER[element.Z] = element
45
+ ELEMENT_BY_SYMBOL[element.symbol.casefold()] = element
46
+
47
+
48
+ _load_elements()
49
+
50
+
51
+ def from_key(key: int | str) -> Element:
52
+ """
53
+ Retrieve element by atomic number or symbol.
54
+
55
+ Parameters
56
+ ----------
57
+ key :
58
+ Atomic number (int) or symbol (str).
59
+
60
+ Returns
61
+ -------
62
+ Requested element.
63
+
64
+ Raises
65
+ ------
66
+ TypeError
67
+ If key is not int or str.
68
+ """
69
+ if isinstance(key, int):
70
+ return ELEMENT_BY_NUMBER[key]
71
+
72
+ if isinstance(key, str):
73
+ return ELEMENT_BY_SYMBOL[key.casefold()]
74
+
75
+ msg = f"Element key must be int or str, got {type(key).__name__}"
76
+ raise TypeError(msg)
77
+
78
+
79
+ def number(key: int | str) -> int:
80
+ """
81
+ Retrieve atomic number of element by atomic number or symbol.
82
+
83
+ Parameters
84
+ ----------
85
+ key :
86
+ Atomic number (int) or symbol (str).
87
+
88
+ Returns
89
+ -------
90
+ Atomic number.
91
+ """
92
+ return from_key(key).Z
93
+
94
+
95
+ def mass_number(key: int | str) -> int:
96
+ """
97
+ Retrieve mass number of element by atomic number or symbol.
98
+
99
+ Parameters
100
+ ----------
101
+ key :
102
+ Atomic number (int) or symbol (str).
103
+
104
+ Returns
105
+ -------
106
+ Mass number.
107
+ """
108
+ return from_key(key).A
109
+
110
+
111
+ def symbol(key: int | str) -> str:
112
+ """
113
+ Retrieve atomic symbol of element by atomic number or symbol.
114
+
115
+ Parameters
116
+ ----------
117
+ key :
118
+ Atomic number (int) or symbol (str).
119
+
120
+ Returns
121
+ -------
122
+ Atomic symbol.
123
+ """
124
+ return from_key(key).symbol
125
+
126
+
127
+ def mass(key: int | str) -> float:
128
+ """
129
+ Retrieve atomic mass of element by atomic number or symbol.
130
+
131
+ Parameters
132
+ ----------
133
+ key :
134
+ Atomic number (int) or symbol (str).
135
+
136
+ Returns
137
+ -------
138
+ Atomic mass.
139
+ """
140
+ return from_key(key).mass
@@ -0,0 +1,710 @@
1
+ [
2
+ {
3
+ "Z": 1,
4
+ "A": 1,
5
+ "symbol": "H",
6
+ "mass": 1.007825031898
7
+ },
8
+ {
9
+ "Z": 2,
10
+ "A": 4,
11
+ "symbol": "He",
12
+ "mass": 4.00260325413
13
+ },
14
+ {
15
+ "Z": 3,
16
+ "A": 7,
17
+ "symbol": "Li",
18
+ "mass": 7.01600343426
19
+ },
20
+ {
21
+ "Z": 4,
22
+ "A": 9,
23
+ "symbol": "Be",
24
+ "mass": 9.012183062
25
+ },
26
+ {
27
+ "Z": 5,
28
+ "A": 11,
29
+ "symbol": "B",
30
+ "mass": 11.009305166
31
+ },
32
+ {
33
+ "Z": 6,
34
+ "A": 12,
35
+ "symbol": "C",
36
+ "mass": 12.0
37
+ },
38
+ {
39
+ "Z": 7,
40
+ "A": 14,
41
+ "symbol": "N",
42
+ "mass": 14.00307400425
43
+ },
44
+ {
45
+ "Z": 8,
46
+ "A": 16,
47
+ "symbol": "O",
48
+ "mass": 15.99491461926
49
+ },
50
+ {
51
+ "Z": 9,
52
+ "A": 19,
53
+ "symbol": "F",
54
+ "mass": 18.99840316207
55
+ },
56
+ {
57
+ "Z": 10,
58
+ "A": 20,
59
+ "symbol": "Ne",
60
+ "mass": 19.99244017525
61
+ },
62
+ {
63
+ "Z": 11,
64
+ "A": 23,
65
+ "symbol": "Na",
66
+ "mass": 22.98976928195
67
+ },
68
+ {
69
+ "Z": 12,
70
+ "A": 24,
71
+ "symbol": "Mg",
72
+ "mass": 23.985041689
73
+ },
74
+ {
75
+ "Z": 13,
76
+ "A": 27,
77
+ "symbol": "Al",
78
+ "mass": 26.981538408
79
+ },
80
+ {
81
+ "Z": 14,
82
+ "A": 28,
83
+ "symbol": "Si",
84
+ "mass": 27.97692653442
85
+ },
86
+ {
87
+ "Z": 15,
88
+ "A": 31,
89
+ "symbol": "P",
90
+ "mass": 30.97376199768
91
+ },
92
+ {
93
+ "Z": 16,
94
+ "A": 32,
95
+ "symbol": "S",
96
+ "mass": 31.97207117354
97
+ },
98
+ {
99
+ "Z": 17,
100
+ "A": 35,
101
+ "symbol": "Cl",
102
+ "mass": 34.968852694
103
+ },
104
+ {
105
+ "Z": 18,
106
+ "A": 40,
107
+ "symbol": "Ar",
108
+ "mass": 39.96238312204
109
+ },
110
+ {
111
+ "Z": 19,
112
+ "A": 39,
113
+ "symbol": "K",
114
+ "mass": 38.96370648482
115
+ },
116
+ {
117
+ "Z": 20,
118
+ "A": 40,
119
+ "symbol": "Ca",
120
+ "mass": 39.96259085
121
+ },
122
+ {
123
+ "Z": 21,
124
+ "A": 45,
125
+ "symbol": "Sc",
126
+ "mass": 44.955907051
127
+ },
128
+ {
129
+ "Z": 22,
130
+ "A": 48,
131
+ "symbol": "Ti",
132
+ "mass": 47.947940677
133
+ },
134
+ {
135
+ "Z": 23,
136
+ "A": 51,
137
+ "symbol": "V",
138
+ "mass": 50.943957664
139
+ },
140
+ {
141
+ "Z": 24,
142
+ "A": 52,
143
+ "symbol": "Cr",
144
+ "mass": 51.940504714
145
+ },
146
+ {
147
+ "Z": 25,
148
+ "A": 55,
149
+ "symbol": "Mn",
150
+ "mass": 54.93804304
151
+ },
152
+ {
153
+ "Z": 26,
154
+ "A": 56,
155
+ "symbol": "Fe",
156
+ "mass": 55.934935537
157
+ },
158
+ {
159
+ "Z": 27,
160
+ "A": 59,
161
+ "symbol": "Co",
162
+ "mass": 58.933193524
163
+ },
164
+ {
165
+ "Z": 28,
166
+ "A": 58,
167
+ "symbol": "Ni",
168
+ "mass": 57.93534165
169
+ },
170
+ {
171
+ "Z": 29,
172
+ "A": 63,
173
+ "symbol": "Cu",
174
+ "mass": 62.929597119
175
+ },
176
+ {
177
+ "Z": 30,
178
+ "A": 64,
179
+ "symbol": "Zn",
180
+ "mass": 63.929141776
181
+ },
182
+ {
183
+ "Z": 31,
184
+ "A": 69,
185
+ "symbol": "Ga",
186
+ "mass": 68.925573528
187
+ },
188
+ {
189
+ "Z": 32,
190
+ "A": 74,
191
+ "symbol": "Ge",
192
+ "mass": 73.92117776
193
+ },
194
+ {
195
+ "Z": 33,
196
+ "A": 75,
197
+ "symbol": "As",
198
+ "mass": 74.921594562
199
+ },
200
+ {
201
+ "Z": 34,
202
+ "A": 80,
203
+ "symbol": "Se",
204
+ "mass": 79.916521761
205
+ },
206
+ {
207
+ "Z": 35,
208
+ "A": 79,
209
+ "symbol": "Br",
210
+ "mass": 78.918337574
211
+ },
212
+ {
213
+ "Z": 36,
214
+ "A": 84,
215
+ "symbol": "Kr",
216
+ "mass": 83.91149772708
217
+ },
218
+ {
219
+ "Z": 37,
220
+ "A": 85,
221
+ "symbol": "Rb",
222
+ "mass": 84.91178973604
223
+ },
224
+ {
225
+ "Z": 38,
226
+ "A": 88,
227
+ "symbol": "Sr",
228
+ "mass": 87.905612253
229
+ },
230
+ {
231
+ "Z": 39,
232
+ "A": 89,
233
+ "symbol": "Y",
234
+ "mass": 88.905838156
235
+ },
236
+ {
237
+ "Z": 40,
238
+ "A": 90,
239
+ "symbol": "Zr",
240
+ "mass": 89.904698755
241
+ },
242
+ {
243
+ "Z": 41,
244
+ "A": 93,
245
+ "symbol": "Nb",
246
+ "mass": 92.90637317
247
+ },
248
+ {
249
+ "Z": 42,
250
+ "A": 98,
251
+ "symbol": "Mo",
252
+ "mass": 97.905403609
253
+ },
254
+ {
255
+ "Z": 43,
256
+ "A": 83,
257
+ "symbol": "Tc",
258
+ "mass": 82.966377
259
+ },
260
+ {
261
+ "Z": 44,
262
+ "A": 102,
263
+ "symbol": "Ru",
264
+ "mass": 101.904340312
265
+ },
266
+ {
267
+ "Z": 45,
268
+ "A": 103,
269
+ "symbol": "Rh",
270
+ "mass": 102.905494081
271
+ },
272
+ {
273
+ "Z": 46,
274
+ "A": 106,
275
+ "symbol": "Pd",
276
+ "mass": 105.903480287
277
+ },
278
+ {
279
+ "Z": 47,
280
+ "A": 107,
281
+ "symbol": "Ag",
282
+ "mass": 106.905091509
283
+ },
284
+ {
285
+ "Z": 48,
286
+ "A": 114,
287
+ "symbol": "Cd",
288
+ "mass": 113.903364998
289
+ },
290
+ {
291
+ "Z": 49,
292
+ "A": 115,
293
+ "symbol": "In",
294
+ "mass": 114.903878772
295
+ },
296
+ {
297
+ "Z": 50,
298
+ "A": 120,
299
+ "symbol": "Sn",
300
+ "mass": 119.902202557
301
+ },
302
+ {
303
+ "Z": 51,
304
+ "A": 121,
305
+ "symbol": "Sb",
306
+ "mass": 120.903811353
307
+ },
308
+ {
309
+ "Z": 52,
310
+ "A": 130,
311
+ "symbol": "Te",
312
+ "mass": 129.906222745
313
+ },
314
+ {
315
+ "Z": 53,
316
+ "A": 127,
317
+ "symbol": "I",
318
+ "mass": 126.904472592
319
+ },
320
+ {
321
+ "Z": 54,
322
+ "A": 132,
323
+ "symbol": "Xe",
324
+ "mass": 131.90415508346
325
+ },
326
+ {
327
+ "Z": 55,
328
+ "A": 133,
329
+ "symbol": "Cs",
330
+ "mass": 132.905451958
331
+ },
332
+ {
333
+ "Z": 56,
334
+ "A": 138,
335
+ "symbol": "Ba",
336
+ "mass": 137.905247059
337
+ },
338
+ {
339
+ "Z": 57,
340
+ "A": 139,
341
+ "symbol": "La",
342
+ "mass": 138.906362927
343
+ },
344
+ {
345
+ "Z": 58,
346
+ "A": 140,
347
+ "symbol": "Ce",
348
+ "mass": 139.905448433
349
+ },
350
+ {
351
+ "Z": 59,
352
+ "A": 141,
353
+ "symbol": "Pr",
354
+ "mass": 140.907659604
355
+ },
356
+ {
357
+ "Z": 60,
358
+ "A": 142,
359
+ "symbol": "Nd",
360
+ "mass": 141.907728824
361
+ },
362
+ {
363
+ "Z": 61,
364
+ "A": 126,
365
+ "symbol": "Pm",
366
+ "mass": 125.957327
367
+ },
368
+ {
369
+ "Z": 62,
370
+ "A": 152,
371
+ "symbol": "Sm",
372
+ "mass": 151.919738646
373
+ },
374
+ {
375
+ "Z": 63,
376
+ "A": 153,
377
+ "symbol": "Eu",
378
+ "mass": 152.921236789
379
+ },
380
+ {
381
+ "Z": 64,
382
+ "A": 158,
383
+ "symbol": "Gd",
384
+ "mass": 157.9241112
385
+ },
386
+ {
387
+ "Z": 65,
388
+ "A": 159,
389
+ "symbol": "Tb",
390
+ "mass": 158.925353707
391
+ },
392
+ {
393
+ "Z": 66,
394
+ "A": 164,
395
+ "symbol": "Dy",
396
+ "mass": 163.929180819
397
+ },
398
+ {
399
+ "Z": 67,
400
+ "A": 165,
401
+ "symbol": "Ho",
402
+ "mass": 164.930329116
403
+ },
404
+ {
405
+ "Z": 68,
406
+ "A": 166,
407
+ "symbol": "Er",
408
+ "mass": 165.930301067
409
+ },
410
+ {
411
+ "Z": 69,
412
+ "A": 169,
413
+ "symbol": "Tm",
414
+ "mass": 168.934218956
415
+ },
416
+ {
417
+ "Z": 70,
418
+ "A": 174,
419
+ "symbol": "Yb",
420
+ "mass": 173.938867545
421
+ },
422
+ {
423
+ "Z": 71,
424
+ "A": 175,
425
+ "symbol": "Lu",
426
+ "mass": 174.940777211
427
+ },
428
+ {
429
+ "Z": 72,
430
+ "A": 180,
431
+ "symbol": "Hf",
432
+ "mass": 179.946559537
433
+ },
434
+ {
435
+ "Z": 73,
436
+ "A": 181,
437
+ "symbol": "Ta",
438
+ "mass": 180.947998528
439
+ },
440
+ {
441
+ "Z": 74,
442
+ "A": 184,
443
+ "symbol": "W",
444
+ "mass": 183.95093318
445
+ },
446
+ {
447
+ "Z": 75,
448
+ "A": 187,
449
+ "symbol": "Re",
450
+ "mass": 186.955752217
451
+ },
452
+ {
453
+ "Z": 76,
454
+ "A": 192,
455
+ "symbol": "Os",
456
+ "mass": 191.961478765
457
+ },
458
+ {
459
+ "Z": 77,
460
+ "A": 193,
461
+ "symbol": "Ir",
462
+ "mass": 192.962923753
463
+ },
464
+ {
465
+ "Z": 78,
466
+ "A": 195,
467
+ "symbol": "Pt",
468
+ "mass": 194.964794325
469
+ },
470
+ {
471
+ "Z": 79,
472
+ "A": 197,
473
+ "symbol": "Au",
474
+ "mass": 196.966570103
475
+ },
476
+ {
477
+ "Z": 80,
478
+ "A": 202,
479
+ "symbol": "Hg",
480
+ "mass": 201.970643604
481
+ },
482
+ {
483
+ "Z": 81,
484
+ "A": 205,
485
+ "symbol": "Tl",
486
+ "mass": 204.974427318
487
+ },
488
+ {
489
+ "Z": 82,
490
+ "A": 208,
491
+ "symbol": "Pb",
492
+ "mass": 207.976652005
493
+ },
494
+ {
495
+ "Z": 83,
496
+ "A": 209,
497
+ "symbol": "Bi",
498
+ "mass": 208.980398599
499
+ },
500
+ {
501
+ "Z": 84,
502
+ "A": 186,
503
+ "symbol": "Po",
504
+ "mass": 186.004403174
505
+ },
506
+ {
507
+ "Z": 85,
508
+ "A": 191,
509
+ "symbol": "At",
510
+ "mass": 191.004148081
511
+ },
512
+ {
513
+ "Z": 86,
514
+ "A": 193,
515
+ "symbol": "Rn",
516
+ "mass": 193.009707973
517
+ },
518
+ {
519
+ "Z": 87,
520
+ "A": 197,
521
+ "symbol": "Fr",
522
+ "mass": 197.011008086
523
+ },
524
+ {
525
+ "Z": 88,
526
+ "A": 201,
527
+ "symbol": "Ra",
528
+ "mass": 201.012814699
529
+ },
530
+ {
531
+ "Z": 89,
532
+ "A": 205,
533
+ "symbol": "Ac",
534
+ "mass": 205.015144152
535
+ },
536
+ {
537
+ "Z": 90,
538
+ "A": 232,
539
+ "symbol": "Th",
540
+ "mass": 232.038053606
541
+ },
542
+ {
543
+ "Z": 91,
544
+ "A": 231,
545
+ "symbol": "Pa",
546
+ "mass": 231.0358825
547
+ },
548
+ {
549
+ "Z": 92,
550
+ "A": 238,
551
+ "symbol": "U",
552
+ "mass": 238.050786936
553
+ },
554
+ {
555
+ "Z": 93,
556
+ "A": 219,
557
+ "symbol": "Np",
558
+ "mass": 219.031601865
559
+ },
560
+ {
561
+ "Z": 94,
562
+ "A": 221,
563
+ "symbol": "Pu",
564
+ "mass": 221.038572
565
+ },
566
+ {
567
+ "Z": 95,
568
+ "A": 223,
569
+ "symbol": "Am",
570
+ "mass": 223.04584
571
+ },
572
+ {
573
+ "Z": 96,
574
+ "A": 231,
575
+ "symbol": "Cm",
576
+ "mass": 231.050746
577
+ },
578
+ {
579
+ "Z": 97,
580
+ "A": 233,
581
+ "symbol": "Bk",
582
+ "mass": 233.056652
583
+ },
584
+ {
585
+ "Z": 98,
586
+ "A": 237,
587
+ "symbol": "Cf",
588
+ "mass": 237.062199272
589
+ },
590
+ {
591
+ "Z": 99,
592
+ "A": 239,
593
+ "symbol": "Es",
594
+ "mass": 239.06831
595
+ },
596
+ {
597
+ "Z": 100,
598
+ "A": 241,
599
+ "symbol": "Fm",
600
+ "mass": 241.074311
601
+ },
602
+ {
603
+ "Z": 101,
604
+ "A": 244,
605
+ "symbol": "Md",
606
+ "mass": 244.081157
607
+ },
608
+ {
609
+ "Z": 102,
610
+ "A": 248,
611
+ "symbol": "No",
612
+ "mass": 248.086623
613
+ },
614
+ {
615
+ "Z": 103,
616
+ "A": 251,
617
+ "symbol": "Lr",
618
+ "mass": 251.094289
619
+ },
620
+ {
621
+ "Z": 104,
622
+ "A": 253,
623
+ "symbol": "Rf",
624
+ "mass": 253.100528
625
+ },
626
+ {
627
+ "Z": 105,
628
+ "A": 255,
629
+ "symbol": "Db",
630
+ "mass": 255.106919
631
+ },
632
+ {
633
+ "Z": 106,
634
+ "A": 258,
635
+ "symbol": "Sg",
636
+ "mass": 258.11304
637
+ },
638
+ {
639
+ "Z": 107,
640
+ "A": 260,
641
+ "symbol": "Bh",
642
+ "mass": 260.121443
643
+ },
644
+ {
645
+ "Z": 108,
646
+ "A": 263,
647
+ "symbol": "Hs",
648
+ "mass": 263.128479
649
+ },
650
+ {
651
+ "Z": 109,
652
+ "A": 265,
653
+ "symbol": "Mt",
654
+ "mass": 265.135937
655
+ },
656
+ {
657
+ "Z": 110,
658
+ "A": 267,
659
+ "symbol": "Ds",
660
+ "mass": 267.143726
661
+ },
662
+ {
663
+ "Z": 111,
664
+ "A": 272,
665
+ "symbol": "Rg",
666
+ "mass": 272.153273
667
+ },
668
+ {
669
+ "Z": 112,
670
+ "A": 276,
671
+ "symbol": "Cn",
672
+ "mass": 276.161418
673
+ },
674
+ {
675
+ "Z": 113,
676
+ "A": 278,
677
+ "symbol": "Nh",
678
+ "mass": 278.170725
679
+ },
680
+ {
681
+ "Z": 114,
682
+ "A": 284,
683
+ "symbol": "Fl",
684
+ "mass": 284.181192
685
+ },
686
+ {
687
+ "Z": 115,
688
+ "A": 287,
689
+ "symbol": "Mc",
690
+ "mass": 287.19082
691
+ },
692
+ {
693
+ "Z": 116,
694
+ "A": 289,
695
+ "symbol": "Lv",
696
+ "mass": 289.198023
697
+ },
698
+ {
699
+ "Z": 117,
700
+ "A": 291,
701
+ "symbol": "Ts",
702
+ "mass": 291.205748
703
+ },
704
+ {
705
+ "Z": 118,
706
+ "A": 293,
707
+ "symbol": "Og",
708
+ "mass": 293.213423
709
+ }
710
+ ]
automol/geom.py ADDED
@@ -0,0 +1,80 @@
1
+ """Molecular geometries."""
2
+
3
+ import numpy as np
4
+ from pydantic import BaseModel, ConfigDict
5
+
6
+ from . import element, rd
7
+ from .types import CoordinatesField, FloatArray
8
+
9
+
10
+ class Geometry(BaseModel):
11
+ """
12
+ Molecular geometry.
13
+
14
+ Parameters
15
+ ----------
16
+ symbols : list[str]
17
+ Atomic symbols in order (e.g., ``["H", "O", "H"]``).
18
+ The length of ``symbols`` must match the number of atoms.
19
+
20
+ coordinates : CoordinatesField
21
+ Cartesian coordinates of the atoms.
22
+ Shape is ``(len(symbols), 3)`` and the ordering corresponds to ``symbols``.
23
+ Units are assumed to be **angstroms** unless otherwise specified.
24
+
25
+ charge : int, optional
26
+ Total molecular charge.
27
+ Default is ``0``.
28
+
29
+ spin : int, optional
30
+ Total spin multiplicity or spin quantum number (depending on convention).
31
+ Default is ``0``.
32
+ """
33
+
34
+ symbols: list[str]
35
+ coordinates: CoordinatesField
36
+ charge: int = 0
37
+ spin: int = 0
38
+
39
+ model_config = ConfigDict(arbitrary_types_allowed=True)
40
+
41
+
42
+ def from_rdkit_molecule(mol: rd.Mol) -> Geometry:
43
+ """
44
+ Generate geometry from RDKit molecule.
45
+
46
+ Parameters
47
+ ----------
48
+ mol
49
+ RDKit molecule.
50
+
51
+ Returns
52
+ -------
53
+ Geometry.
54
+ """
55
+ if not rd.mol.has_coordinates(mol):
56
+ mol = rd.mol.add_coordinates(mol)
57
+
58
+ return Geometry(
59
+ symbols=rd.mol.symbols(mol),
60
+ coordinates=rd.mol.coordinates(mol),
61
+ charge=rd.mol.charge(mol),
62
+ spin=rd.mol.spin(mol),
63
+ )
64
+
65
+
66
+ def center_of_mass(geo: Geometry) -> FloatArray:
67
+ """
68
+ Calculate geometry center of mass.
69
+
70
+ Parameters
71
+ ----------
72
+ Geometry.
73
+
74
+ Returns
75
+ -------
76
+ Center of mass coordinates.
77
+ """
78
+ masses = list(map(element.mass, geo.symbols))
79
+ coords = geo.coordinates
80
+ return np.sum(np.reshape(masses, (-1, 1)) * coords, axis=0) / np.sum(masses)
automol/rd/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ """RDKit interface."""
2
+
3
+ from . import mol
4
+ from .mol import Mol
5
+
6
+ __all__ = ["mol", "Mol"]
automol/rd/mol.py ADDED
@@ -0,0 +1,153 @@
1
+ """RDKit molecule."""
2
+
3
+ import numpy as np
4
+ from rdkit import Chem
5
+ from rdkit.Chem import Descriptors, Mol
6
+ from rdkit.Chem.rdDistGeom import EmbedMolecule
7
+
8
+ from ..types import FloatArray
9
+
10
+
11
+ # Generators
12
+ def from_smiles(smi: str, *, with_coords: bool = False) -> Mol:
13
+ """
14
+ Get RDKit molecule from SMILES string.
15
+
16
+ Parameters
17
+ ----------
18
+ smi
19
+ SMILES string.
20
+
21
+ with_coords, optional
22
+ If `True`, generate 3D coordinates for the molecule.
23
+ If `False` (default), return a molecule without coordinates.
24
+
25
+ Returns
26
+ -------
27
+ RDKit molecule.
28
+ """
29
+ mol = Chem.MolFromSmiles(smi)
30
+ mol = Chem.AddHs(mol)
31
+ if with_coords:
32
+ add_coordinates(mol, in_place=True)
33
+ return mol
34
+
35
+
36
+ # Properties
37
+ def symbols(mol: Mol) -> list[str]:
38
+ """
39
+ Get atomic symbols.
40
+
41
+ Parameters
42
+ ----------
43
+ mol
44
+ RDKit molecule object.
45
+
46
+ Returns
47
+ -------
48
+ List of atomic symbols.
49
+ """
50
+ return [a.GetSymbol() for a in mol.GetAtoms()]
51
+
52
+
53
+ def coordinates(mol: Mol) -> FloatArray:
54
+ """
55
+ Get atom coordinates.
56
+
57
+ Parameters
58
+ ----------
59
+ mol
60
+ RDKit molecule object.
61
+
62
+ Returns
63
+ -------
64
+ Atomic coordinates as (N, 3) numpy array.
65
+
66
+ Raises
67
+ ------
68
+ ValueError
69
+ If the molecule has no coordinates.
70
+ """
71
+ if not has_coordinates(mol):
72
+ msg = "Molecule has no coordinates. Did you forget to add them?"
73
+ raise ValueError(msg)
74
+
75
+ natms = mol.GetNumAtoms()
76
+ conf = mol.GetConformer()
77
+ coords = [conf.GetAtomPosition(i) for i in range(natms)]
78
+ return np.array(coords, dtype=np.float64)
79
+
80
+
81
+ def charge(mol: Mol) -> int:
82
+ """
83
+ Get molecular charge.
84
+
85
+ Parameters
86
+ ----------
87
+ mol
88
+ RDKit molecule object.
89
+
90
+ Returns
91
+ -------
92
+ Molecular charge as an integer.
93
+ """
94
+ return Chem.GetFormalCharge(mol)
95
+
96
+
97
+ def spin(mol: Mol) -> int:
98
+ """
99
+ Get molecular spin (number of unpaired electrons).
100
+
101
+ Parameters
102
+ ----------
103
+ mol
104
+ RDKit molecule object.
105
+
106
+ Returns
107
+ -------
108
+ Number of unpaired electrons as an integer.
109
+ """
110
+ return Descriptors.NumRadicalElectrons(mol)
111
+
112
+
113
+ # Boolean properties
114
+ def has_coordinates(mol: Mol) -> bool:
115
+ """
116
+ Check if coordinates have been added.
117
+
118
+ Parameters
119
+ ----------
120
+ mol
121
+ RDKit molecule object.
122
+
123
+ Returns
124
+ -------
125
+ `True` if the molecule has coordinates, False otherwise.
126
+ """
127
+ return bool(mol.GetNumConformers())
128
+
129
+
130
+ # Transformations
131
+ def add_coordinates(mol: Mol, *, in_place: bool = False) -> Mol:
132
+ """
133
+ Add coordinates, if missing.
134
+
135
+ Parameters
136
+ ----------
137
+ mol
138
+ RDKit molecule object.
139
+ in_place, optional
140
+ If `True`, modify the molecule in place.
141
+ If `False` (default), return a new molecule.
142
+
143
+ Returns
144
+ -------
145
+ RDKit molecule object with coordinates.
146
+ (Unmodified if it already had coordinates.)
147
+ """
148
+ if has_coordinates(mol):
149
+ return mol
150
+
151
+ mol = mol if in_place else Mol(mol)
152
+ EmbedMolecule(mol)
153
+ return mol
automol/smiles.py ADDED
@@ -0,0 +1,20 @@
1
+ """SMILES strings."""
2
+
3
+ from . import geom, rd
4
+ from .geom import Geometry
5
+
6
+
7
+ def geometry(smi: str) -> Geometry:
8
+ """Get the geometry corresponding to a SMILES string.
9
+
10
+ Parameters
11
+ ----------
12
+ smi : str
13
+ Input SMILES string.
14
+
15
+ Returns
16
+ -------
17
+ Corresponding geometry.
18
+ """
19
+ mol = rd.mol.from_smiles(smi, with_coords=True)
20
+ return geom.from_rdkit_molecule(mol)
@@ -0,0 +1,6 @@
1
+ """Types."""
2
+
3
+ from .core import FloatArray
4
+ from .pydantic import CoordinatesField, FloatArrayField
5
+
6
+ __all__ = ["FloatArray", "CoordinatesField", "FloatArrayField"]
automol/types/core.py ADDED
@@ -0,0 +1,6 @@
1
+ """Core types."""
2
+
3
+ import numpy as np
4
+ from numpy import typing as npt
5
+
6
+ FloatArray = npt.NDArray[np.float64]
@@ -0,0 +1,44 @@
1
+ """Pydantic types."""
2
+
3
+ from typing import Annotated
4
+
5
+ import numpy as np
6
+ from numpy import typing as npt
7
+ from pydantic import BeforeValidator, PlainSerializer
8
+ from pydantic.functional_validators import SkipValidation
9
+
10
+ from .core import FloatArray
11
+
12
+
13
+ # Float array field
14
+ def _float_array_validator(obj: object) -> FloatArray:
15
+ return np.asarray(obj, dtype=np.float64)
16
+
17
+
18
+ def _float_array_serializer(arr: FloatArray) -> list:
19
+ return arr.tolist()
20
+
21
+
22
+ FloatArrayField = Annotated[
23
+ SkipValidation[npt.ArrayLike],
24
+ BeforeValidator(_float_array_validator),
25
+ PlainSerializer(_float_array_serializer, return_type=list),
26
+ ]
27
+
28
+
29
+ # Coordinates field
30
+ def _coordinates_validator(obj: object) -> FloatArray:
31
+ arr = _float_array_validator(obj)
32
+
33
+ if arr.ndim != 2 or arr.shape[-1] != 3: # noqa: PLR2004
34
+ msg = f"Expected array of shape (N, 3) but got {arr.shape}."
35
+ raise ValueError(msg)
36
+
37
+ return arr
38
+
39
+
40
+ CoordinatesField = Annotated[
41
+ SkipValidation[npt.ArrayLike],
42
+ BeforeValidator(_coordinates_validator),
43
+ PlainSerializer(_float_array_serializer, return_type=list),
44
+ ]
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 2.3
2
+ Name: automol
3
+ Version: 0.0.1
4
+ Author: Andreas V. Copan
5
+ Author-email: Andreas V. Copan <avcopan@uga.edu>
6
+ Requires-Dist: networkx>=3.3
7
+ Requires-Dist: numpy>=2.0
8
+ Requires-Dist: pint>=0.24
9
+ Requires-Dist: py3dmol>=2.5
10
+ Requires-Dist: pydantic>=2.5
11
+ Requires-Dist: rdkit>=2025
12
+ Requires-Dist: scipy>=1.13
13
+ Requires-Python: >=3.12
@@ -0,0 +1,14 @@
1
+ automol/__init__.py,sha256=In_4anX1rsW-5oJXvju-ZEVIuhwxKmJiIRVIsPDi7TM,133
2
+ automol/element/__init__.py,sha256=x_pWapmeoIcZmKry2aG3lKMLqgK4GuvA6hk4PvW6FOk,170
3
+ automol/element/core.py,sha256=-CeMz4wkqiDPSrBrkey7T8KAiJ7yU_p_LQzuFT42pag,2583
4
+ automol/element/elements-data.json,sha256=fvsHTGw3oITVPTJS_h2okSkEwXtlxzl7e95G1_fTZEc,9513
5
+ automol/geom.py,sha256=OPaqs7_36vsGHOaMOeXiGnak43HMmUgXznuOO93Xzi0,1883
6
+ automol/rd/__init__.py,sha256=YEnOcgA6v7uM190ohOw94EM6kbb_rRNj3nMLjmO_SHU,89
7
+ automol/rd/mol.py,sha256=X7vfoDeA296aFuAsiht6OAHTaJY5jgIQ4tDeFO1Vfz8,3056
8
+ automol/smiles.py,sha256=0tQR0vlo5Fh6DnAsRcpllv_Gw5SXSIgzS895qf1TQVg,401
9
+ automol/types/__init__.py,sha256=4UkuBihABYldtK9HCnooo0amPlV_-95hiqcvpY5XMTs,164
10
+ automol/types/core.py,sha256=r5WUxPwOGDh-_lkb-lqZ-LWMNgHOeldulpd4TOnTyQ4,108
11
+ automol/types/pydantic.py,sha256=Cwt2gsxlw6GU77f5a7LxeXxROtR2tHlZ5tZT8KYQZLM,1095
12
+ automol-0.0.1.dist-info/WHEEL,sha256=XV0cjMrO7zXhVAIyyc8aFf1VjZ33Fen4IiJk5zFlC3g,80
13
+ automol-0.0.1.dist-info/METADATA,sha256=oIAQNV-TJbgt7Jz0d4VYQQ4WlYyQtXCraUdKdvGvCkQ,341
14
+ automol-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.9.26
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any