GraphAtoms 2.3.0__tar.gz → 2.3.2__tar.gz
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.
- {graphatoms-2.3.0 → graphatoms-2.3.2}/PKG-INFO +1 -1
- {graphatoms-2.3.0 → graphatoms-2.3.2}/pyproject.toml +2 -2
- {graphatoms-2.3.0 → graphatoms-2.3.2}/pyproject.toml.orig +2 -2
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/dataclasses/_pydanticMixin.py +38 -20
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/network/__init__.py +2 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/network/_clsnetwork.py +231 -84
- graphatoms-2.3.2/src/graphatoms/enterpoint/network/_commands.py +139 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/network/_metadata.py +52 -2
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/network/_recorder.py +17 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/network/_scheduler.py +13 -2
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/parallel/_ray.py +23 -4
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/common/_base.py +6 -3
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/common/_helper.py +7 -5
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/general/otfkmc.py +5 -1
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/v2/general/_expl.py +11 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/v2/ray/_expl.py +8 -9
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/v2/ray/_helper.py +4 -4
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/geometry/sample.py +7 -1
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/reaction/_event.py +56 -18
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/system/bonds.py +9 -5
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/system/database/abc.py +9 -5
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/system/sysCluster.py +44 -6
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/utils/adsorption.py +6 -2
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/utils/bytestool.py +52 -1
- graphatoms-2.3.0/src/graphatoms/enterpoint/view.py +0 -118
- {graphatoms-2.3.0 → graphatoms-2.3.2}/README.md +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/LICENSE +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/arrayapi/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/arrayapi/compat.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/arrayapi/typing.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/dataclasses/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/dataclasses/_numpydantic.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/dataclasses/_pydantic2pyarrow.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/dataclasses/_pydanticModel.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/dataclasses/graph.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/config/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/config/atoms/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/config/atoms/aseread.yaml +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/config/atoms/octahedron.yaml +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/config/bonds/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/config/bonds/raw.yaml +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/config/calculator/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/config/calculator/emt.yaml +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/config/calculator/nequip.yaml +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/config/example.yaml +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/config/run.yaml +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/parallel/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/parallel/_base.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/parallel/_dask.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/parallel/_executorlib.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/common/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/common/_errors.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/general/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/general/_expl.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/general/rxngen.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/v2/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/v2/_helperv2.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/v2/general/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/v2/general/otfkmc.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/v2/general/rxngen.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/v2/ray/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/v2/ray/otfkmc.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/enterpoint/runner/v2/ray/rxngen.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/geometry/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/geometry/_bond_list.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/geometry/_distance_pairs.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/geometry/_inner_outer.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/geometry/_neighbor_list.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/geometry/mic.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/geometry/rotation.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/reaction/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/reaction/reaction.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/reaction/xxsorption.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/system/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/system/atoms.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/system/database/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/system/database/dict.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/system/database/dir.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/system/database/hdf5.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/system/database/sqliteASE.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/system/graph.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/system/sysGas.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/system/system.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/utils/__init__.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/utils/aseqhull.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/utils/asetools.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/utils/logger.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/utils/parser.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/utils/rdutils.py +0 -0
- {graphatoms-2.3.0 → graphatoms-2.3.2}/src/graphatoms/utils/subgraph.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "graphatoms"
|
|
7
|
-
version = "2.3.
|
|
7
|
+
version = "2.3.2"
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
description = "The Chemical Core Class for Graph Theory Analysis."
|
|
10
10
|
license-files = ["src/LICENSE"]
|
|
@@ -56,7 +56,7 @@ Issues = "https://github.com/LiuGaoyong/GraphAtoms/issues/"
|
|
|
56
56
|
|
|
57
57
|
[project.scripts]
|
|
58
58
|
graphatoms-config = "graphatoms.enterpoint.config:print_config"
|
|
59
|
-
graphatoms-network = "graphatoms.enterpoint.
|
|
59
|
+
graphatoms-network = "graphatoms.enterpoint.network:main"
|
|
60
60
|
graphatoms-run = "graphatoms.enterpoint.runner:run"
|
|
61
61
|
|
|
62
62
|
[[project.authors]]
|
|
@@ -8,11 +8,11 @@ Repository = "https://github.com/LiuGaoyong/GraphAtoms"
|
|
|
8
8
|
Issues = "https://github.com/LiuGaoyong/GraphAtoms/issues/"
|
|
9
9
|
[project.scripts]
|
|
10
10
|
graphatoms-config = "graphatoms.enterpoint.config:print_config"
|
|
11
|
-
graphatoms-network = "graphatoms.enterpoint.
|
|
11
|
+
graphatoms-network = "graphatoms.enterpoint.network:main"
|
|
12
12
|
graphatoms-run = "graphatoms.enterpoint.runner:run"
|
|
13
13
|
[project]
|
|
14
14
|
name = "graphatoms"
|
|
15
|
-
version = "2.3.
|
|
15
|
+
version = "2.3.2"
|
|
16
16
|
readme = "README.md"
|
|
17
17
|
description = "The Chemical Core Class for Graph Theory Analysis."
|
|
18
18
|
authors = [{ name = "LiuGaoyong", email = "liugaoyong_88@163.com" }]
|
|
@@ -229,7 +229,11 @@ class __Json(PydanticConvertFactoryMixin):
|
|
|
229
229
|
indent=indent,
|
|
230
230
|
)
|
|
231
231
|
)
|
|
232
|
-
|
|
232
|
+
bytesutils.atomic_write_text(
|
|
233
|
+
target=filename,
|
|
234
|
+
text=self.to_str(**kwargs),
|
|
235
|
+
encoding="utf-8",
|
|
236
|
+
)
|
|
233
237
|
return filename
|
|
234
238
|
|
|
235
239
|
@classmethod
|
|
@@ -260,13 +264,15 @@ class __Toml(PydanticConvertFactoryMixin):
|
|
|
260
264
|
numpy_ndarray_compatible=True,
|
|
261
265
|
)
|
|
262
266
|
)
|
|
263
|
-
|
|
264
|
-
|
|
267
|
+
bytesutils.atomic_write_text(
|
|
268
|
+
target=filename,
|
|
269
|
+
text=toml_w.dumps(
|
|
265
270
|
self.to_dict(**kwargs),
|
|
266
|
-
f,
|
|
267
271
|
indent=indent,
|
|
268
272
|
multiline_strings=True,
|
|
269
|
-
)
|
|
273
|
+
),
|
|
274
|
+
encoding="utf-8",
|
|
275
|
+
)
|
|
270
276
|
return filename
|
|
271
277
|
|
|
272
278
|
@classmethod
|
|
@@ -301,16 +307,17 @@ class __Yaml(PydanticConvertFactoryMixin):
|
|
|
301
307
|
numpy_ndarray_compatible=True,
|
|
302
308
|
)
|
|
303
309
|
)
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
310
|
+
bytesutils.atomic_write_text(
|
|
311
|
+
target=filename,
|
|
312
|
+
text=OmegaConf.to_yaml(
|
|
313
|
+
self.to_dict(**kwargs),
|
|
314
|
+
# f,
|
|
315
|
+
# encoding="utf-8",
|
|
316
|
+
# # default_flow_style=False,
|
|
317
|
+
# indent=4,
|
|
318
|
+
),
|
|
319
|
+
encoding="utf-8",
|
|
320
|
+
)
|
|
314
321
|
return filename
|
|
315
322
|
|
|
316
323
|
@classmethod
|
|
@@ -345,10 +352,14 @@ class __Npz(PydanticConvertFactoryMixin):
|
|
|
345
352
|
numpy_ndarray_compatible=True,
|
|
346
353
|
)
|
|
347
354
|
)
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
355
|
+
func = np.savez_compressed if compress else np.savez
|
|
356
|
+
bytesutils.atomic_write(
|
|
357
|
+
target=filename,
|
|
358
|
+
writer=lambda p: func(
|
|
359
|
+
p,
|
|
360
|
+
allow_pickle=False,
|
|
361
|
+
**self.to_dict(**kwargs),
|
|
362
|
+
),
|
|
352
363
|
)
|
|
353
364
|
return filename
|
|
354
365
|
|
|
@@ -411,7 +422,14 @@ class __Pickle(PydanticConvertFactoryMixin):
|
|
|
411
422
|
numpy_ndarray_compatible=True,
|
|
412
423
|
)
|
|
413
424
|
)
|
|
414
|
-
|
|
425
|
+
bytesutils.atomic_write(
|
|
426
|
+
target=filename,
|
|
427
|
+
writer=lambda p: dump(
|
|
428
|
+
value=self.to_dict(**kwargs),
|
|
429
|
+
filename=p,
|
|
430
|
+
compress=compress, # type: ignore
|
|
431
|
+
),
|
|
432
|
+
)
|
|
415
433
|
return filename
|
|
416
434
|
|
|
417
435
|
@classmethod
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from ._clsnetwork import ReactionNetwork
|
|
2
|
+
from ._commands import main
|
|
2
3
|
from ._metadata import MetaData
|
|
3
4
|
from ._recorder import Recorder
|
|
4
5
|
from ._scheduler import Scheduler
|
|
@@ -8,4 +9,5 @@ __all__ = [
|
|
|
8
9
|
"Recorder",
|
|
9
10
|
"Scheduler",
|
|
10
11
|
"ReactionNetwork",
|
|
12
|
+
"main",
|
|
11
13
|
]
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import pickle
|
|
2
2
|
import time
|
|
3
|
+
from collections.abc import Iterator, Mapping
|
|
3
4
|
from pathlib import Path
|
|
4
|
-
from typing import Literal, Self
|
|
5
|
+
from typing import Literal, Self, override
|
|
5
6
|
|
|
6
7
|
import numpy as np
|
|
7
8
|
from ase import Atoms
|
|
8
9
|
|
|
9
10
|
from graphatoms.enterpoint.config import Config, EventConfig
|
|
11
|
+
from graphatoms.enterpoint.network._metadata import MetaData
|
|
12
|
+
from graphatoms.enterpoint.network._metadata import (
|
|
13
|
+
_MetaDataBasic as MetaDataBasic,
|
|
14
|
+
)
|
|
15
|
+
from graphatoms.enterpoint.network._recorder import (
|
|
16
|
+
OldNewRecorder4Confidence,
|
|
17
|
+
Recorder,
|
|
18
|
+
RecorderInfo,
|
|
19
|
+
)
|
|
20
|
+
from graphatoms.enterpoint.network._scheduler import Scheduler
|
|
10
21
|
from graphatoms.reaction import (
|
|
11
22
|
Adsorption,
|
|
12
23
|
Desorption,
|
|
@@ -16,11 +27,7 @@ from graphatoms.reaction import (
|
|
|
16
27
|
)
|
|
17
28
|
from graphatoms.system import Cluster, Gas, SysGraph, System
|
|
18
29
|
from graphatoms.system.database import DatabaseABC, get_db
|
|
19
|
-
|
|
20
|
-
from ._metadata import MetaData
|
|
21
|
-
from ._metadata import _MetaDataBasic as MetaDataBasic
|
|
22
|
-
from ._recorder import OldNewRecorder4Confidence, Recorder, RecorderInfo
|
|
23
|
-
from ._scheduler import Scheduler
|
|
30
|
+
from graphatoms.utils.bytestool import atomic_write, atomic_write_text
|
|
24
31
|
|
|
25
32
|
__all__ = [
|
|
26
33
|
"MetaData",
|
|
@@ -31,7 +38,7 @@ __all__ = [
|
|
|
31
38
|
NETWORK_PATH_PREFIX = "event"
|
|
32
39
|
|
|
33
40
|
|
|
34
|
-
class ReactionNetwork:
|
|
41
|
+
class ReactionNetwork(Mapping[str, tuple[EventInfo, EventBase]]):
|
|
35
42
|
DB_USE_POSITION_UUID_DICT: dict[str, bool] = {
|
|
36
43
|
"ts": True,
|
|
37
44
|
"minima": True,
|
|
@@ -57,8 +64,8 @@ class ReactionNetwork:
|
|
|
57
64
|
assert format in (
|
|
58
65
|
"sqlite",
|
|
59
66
|
"directory",
|
|
60
|
-
"dir",
|
|
61
67
|
"folder",
|
|
68
|
+
"dir",
|
|
62
69
|
"h5",
|
|
63
70
|
"hdf5",
|
|
64
71
|
), f"The format of `{format}` is not supported for restart."
|
|
@@ -82,8 +89,9 @@ class ReactionNetwork:
|
|
|
82
89
|
+ " Please delete it or use `restart=True`."
|
|
83
90
|
)
|
|
84
91
|
self.__path.mkdir(parents=True, exist_ok=True)
|
|
85
|
-
|
|
86
|
-
|
|
92
|
+
atomic_write_text(
|
|
93
|
+
self.__path_exploration_recorder,
|
|
94
|
+
RecorderInfo.get_csv_title() + "\n",
|
|
87
95
|
)
|
|
88
96
|
self.__recorder = Recorder()
|
|
89
97
|
self.__scheduler = Scheduler()
|
|
@@ -118,6 +126,171 @@ class ReactionNetwork:
|
|
|
118
126
|
assert isinstance(self.__db_cluster, DatabaseABC)
|
|
119
127
|
assert isinstance(self.__db_system, DatabaseABC)
|
|
120
128
|
|
|
129
|
+
@classmethod
|
|
130
|
+
def from_config(
|
|
131
|
+
cls,
|
|
132
|
+
config: Config,
|
|
133
|
+
*args,
|
|
134
|
+
restart: bool | None = None,
|
|
135
|
+
remote_retry_times: float = 2.0,
|
|
136
|
+
remote_mode: bool = False,
|
|
137
|
+
**kwargs,
|
|
138
|
+
) -> Self: # type: ignore
|
|
139
|
+
"""Create a network from a config file."""
|
|
140
|
+
if remote_mode is True:
|
|
141
|
+
# When remote_mode is True, some files may not exist or in write.
|
|
142
|
+
# We need to try to create the network again.
|
|
143
|
+
err = None
|
|
144
|
+
for _ in range(10):
|
|
145
|
+
try:
|
|
146
|
+
return cls(
|
|
147
|
+
path=Path(config.outputs) / NETWORK_PATH_PREFIX,
|
|
148
|
+
restart=restart
|
|
149
|
+
if restart is not None
|
|
150
|
+
else config.restart,
|
|
151
|
+
format=config.event.db_format,
|
|
152
|
+
remote_mode=remote_mode,
|
|
153
|
+
config=config.event,
|
|
154
|
+
**kwargs,
|
|
155
|
+
)
|
|
156
|
+
break
|
|
157
|
+
except Exception as e:
|
|
158
|
+
time.sleep(abs(remote_retry_times))
|
|
159
|
+
err = e
|
|
160
|
+
if err is not None:
|
|
161
|
+
raise RuntimeError(
|
|
162
|
+
f"Failed to create the network in remote mode. {err}"
|
|
163
|
+
)
|
|
164
|
+
else:
|
|
165
|
+
return cls(
|
|
166
|
+
path=Path(config.outputs) / NETWORK_PATH_PREFIX,
|
|
167
|
+
restart=restart if restart is not None else config.restart,
|
|
168
|
+
format=config.event.db_format,
|
|
169
|
+
remote_mode=remote_mode,
|
|
170
|
+
config=config.event,
|
|
171
|
+
**kwargs,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
@classmethod
|
|
175
|
+
def merge(
|
|
176
|
+
cls,
|
|
177
|
+
*networks: Self,
|
|
178
|
+
new_path: Path | str,
|
|
179
|
+
new_format: str | Literal["dir", "h5", "sqlite"] = "dir",
|
|
180
|
+
**kwargs,
|
|
181
|
+
) -> Self:
|
|
182
|
+
"""Merge the networks.
|
|
183
|
+
|
|
184
|
+
Note: the recorder will be set empty.
|
|
185
|
+
"""
|
|
186
|
+
if len(networks) <= 1:
|
|
187
|
+
raise ValueError("At least two network is required.")
|
|
188
|
+
result = cls(
|
|
189
|
+
path=Path(new_path),
|
|
190
|
+
restart=False,
|
|
191
|
+
config=networks[0].metadata.basic,
|
|
192
|
+
format=new_format,
|
|
193
|
+
)
|
|
194
|
+
result.metadata.basic.db_format = new_format
|
|
195
|
+
for network in networks[1:]:
|
|
196
|
+
try:
|
|
197
|
+
network.metadata.basic.check_consistency(
|
|
198
|
+
result.metadata.basic,
|
|
199
|
+
exclude_keys={"db_format", "gas_sticking"},
|
|
200
|
+
)
|
|
201
|
+
for k, v in network.metadata.basic.gas_sticking.items():
|
|
202
|
+
if k not in result.metadata.basic.gas_sticking:
|
|
203
|
+
result.metadata.basic.gas_sticking[k] = v
|
|
204
|
+
else:
|
|
205
|
+
v0 = result.metadata.basic.gas_sticking[k]
|
|
206
|
+
assert v0 == v, (
|
|
207
|
+
f"Failed to merge the networks because the "
|
|
208
|
+
f"gas sticking of {k} is not the same as "
|
|
209
|
+
f"input. self={v0}, input={v}"
|
|
210
|
+
)
|
|
211
|
+
result.metadata.basic.gas_sticking[k] = v
|
|
212
|
+
except Exception as e:
|
|
213
|
+
raise ValueError(
|
|
214
|
+
f"Failed to merge the networks because "
|
|
215
|
+
f"of check consistency failed: {e}"
|
|
216
|
+
)
|
|
217
|
+
for k, use_pos_uuid in cls.DB_USE_POSITION_UUID_DICT.items():
|
|
218
|
+
db_res: DatabaseABC = getattr(result, f"db_{k}")
|
|
219
|
+
db: DatabaseABC = getattr(network, f"db_{k}")
|
|
220
|
+
for _, v in db.items():
|
|
221
|
+
graph = SysGraph.from_ase(v)
|
|
222
|
+
graph_key = graph.get_key_for_metadata(use_pos_uuid)
|
|
223
|
+
if graph_key not in db_res:
|
|
224
|
+
db_res._save(graph_key, graph)
|
|
225
|
+
for i, rxn in enumerate(network.metadata.table.key_rxn):
|
|
226
|
+
if rxn not in result.metadata.table.key_rxn:
|
|
227
|
+
key_r = network.metadata.table.key_r[i]
|
|
228
|
+
key_p = network.metadata.table.key_p[i]
|
|
229
|
+
key_g = network.metadata.table.key_g[i]
|
|
230
|
+
key_ts = network.metadata.table.key_t[i]
|
|
231
|
+
if key_r not in result.db_minima:
|
|
232
|
+
print(
|
|
233
|
+
f"Find invalid key: {rxn}\n"
|
|
234
|
+
f" Missing key of reactant: {key_r}\n",
|
|
235
|
+
flush=True,
|
|
236
|
+
)
|
|
237
|
+
continue
|
|
238
|
+
elif key_g is not None and key_g not in result.db_gas:
|
|
239
|
+
print(
|
|
240
|
+
f"Find invalid key: {rxn}\n"
|
|
241
|
+
f" Missing key of gas: {key_g}\n",
|
|
242
|
+
flush=True,
|
|
243
|
+
)
|
|
244
|
+
continue
|
|
245
|
+
elif key_ts is not None and key_ts not in result.db_ts:
|
|
246
|
+
print(
|
|
247
|
+
f"Find invalid key: {rxn}\n"
|
|
248
|
+
f" Missing key of transition state: {key_ts}\n",
|
|
249
|
+
flush=True,
|
|
250
|
+
)
|
|
251
|
+
continue
|
|
252
|
+
elif key_p is not None and key_p not in result.db_minima:
|
|
253
|
+
print(
|
|
254
|
+
f"Find invalid key: {rxn}\n"
|
|
255
|
+
f" Missing key of product: {key_p}\n",
|
|
256
|
+
flush=True,
|
|
257
|
+
)
|
|
258
|
+
continue
|
|
259
|
+
result.metadata.table.merge( # Output duplicate info
|
|
260
|
+
network.metadata.table, idxs=[i]
|
|
261
|
+
)
|
|
262
|
+
n = len(result.metadata.table.key_rxn)
|
|
263
|
+
print(f"Merge networks({n} events) done.", flush=True)
|
|
264
|
+
result.scheduler.clear()
|
|
265
|
+
result.recorder.clear()
|
|
266
|
+
result.persistence()
|
|
267
|
+
return result
|
|
268
|
+
|
|
269
|
+
@classmethod
|
|
270
|
+
def reformat_message(cls, msg: str) -> str:
|
|
271
|
+
return msg
|
|
272
|
+
__LOGURU_FORMAT_LENGTH: int = 37
|
|
273
|
+
__LOGURU_TOTAL_LENGTH: int = 120
|
|
274
|
+
len_msg = __LOGURU_TOTAL_LENGTH - __LOGURU_FORMAT_LENGTH
|
|
275
|
+
lst = wrap_line(msg, width_min=len_msg, width_max=len_msg + 20)
|
|
276
|
+
return ("\n" + " " * __LOGURU_FORMAT_LENGTH).join(lst)
|
|
277
|
+
|
|
278
|
+
@override
|
|
279
|
+
def __len__(self) -> int:
|
|
280
|
+
return len(self.metadata.table.key_rxn)
|
|
281
|
+
|
|
282
|
+
@override
|
|
283
|
+
def __contains__(self, key: str) -> bool: # type: ignore
|
|
284
|
+
return key in self.metadata.table.key_rxn
|
|
285
|
+
|
|
286
|
+
@override
|
|
287
|
+
def __getitem__(self, key: str) -> tuple[EventInfo, EventBase]:
|
|
288
|
+
return self.read_event(key)
|
|
289
|
+
|
|
290
|
+
@override
|
|
291
|
+
def __iter__(self) -> Iterator[str]:
|
|
292
|
+
yield from self.metadata.table.key_rxn
|
|
293
|
+
|
|
121
294
|
@property
|
|
122
295
|
def path(self) -> Path:
|
|
123
296
|
return self.__path
|
|
@@ -186,76 +359,6 @@ class ReactionNetwork:
|
|
|
186
359
|
)
|
|
187
360
|
return self.__db_ts
|
|
188
361
|
|
|
189
|
-
@classmethod
|
|
190
|
-
def from_config(
|
|
191
|
-
cls,
|
|
192
|
-
config: Config,
|
|
193
|
-
*args,
|
|
194
|
-
restart: bool | None = None,
|
|
195
|
-
remote_mode: bool = False,
|
|
196
|
-
**kwargs,
|
|
197
|
-
) -> Self: # type: ignore
|
|
198
|
-
"""Create a network from a config file."""
|
|
199
|
-
if remote_mode is True:
|
|
200
|
-
# When remote_mode is True, some files may not exist or in write.
|
|
201
|
-
# We need to try to create the network again.
|
|
202
|
-
err = None
|
|
203
|
-
for _ in range(10):
|
|
204
|
-
try:
|
|
205
|
-
return cls(
|
|
206
|
-
path=Path(config.outputs) / NETWORK_PATH_PREFIX,
|
|
207
|
-
restart=restart
|
|
208
|
-
if restart is not None
|
|
209
|
-
else config.restart,
|
|
210
|
-
format=config.event.db_format,
|
|
211
|
-
remote_mode=remote_mode,
|
|
212
|
-
config=config.event,
|
|
213
|
-
**kwargs,
|
|
214
|
-
)
|
|
215
|
-
break
|
|
216
|
-
except Exception as e:
|
|
217
|
-
time.sleep(0.5)
|
|
218
|
-
err = e
|
|
219
|
-
if err is not None:
|
|
220
|
-
raise RuntimeError(
|
|
221
|
-
f"Failed to create the network in remote mode. {err}"
|
|
222
|
-
)
|
|
223
|
-
else:
|
|
224
|
-
return cls(
|
|
225
|
-
path=Path(config.outputs) / NETWORK_PATH_PREFIX,
|
|
226
|
-
restart=restart if restart is not None else config.restart,
|
|
227
|
-
format=config.event.db_format,
|
|
228
|
-
remote_mode=remote_mode,
|
|
229
|
-
config=config.event,
|
|
230
|
-
**kwargs,
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
@classmethod
|
|
234
|
-
def merge(
|
|
235
|
-
cls,
|
|
236
|
-
*networks: Self,
|
|
237
|
-
new_path: Path | str,
|
|
238
|
-
new_format: str | Literal["dir", "h5", "sqlite"] = "dir",
|
|
239
|
-
**kwargs,
|
|
240
|
-
) -> Self:
|
|
241
|
-
"""Merge the networks."""
|
|
242
|
-
raise NotImplementedError("Merge the networks.")
|
|
243
|
-
cls(
|
|
244
|
-
path=new_path,
|
|
245
|
-
restart=False,
|
|
246
|
-
config=networks[0].metadata.basic,
|
|
247
|
-
format=networks[0].__format,
|
|
248
|
-
)
|
|
249
|
-
|
|
250
|
-
@classmethod
|
|
251
|
-
def reformat_message(cls, msg: str) -> str:
|
|
252
|
-
return msg
|
|
253
|
-
__LOGURU_FORMAT_LENGTH: int = 37
|
|
254
|
-
__LOGURU_TOTAL_LENGTH: int = 120
|
|
255
|
-
len_msg = __LOGURU_TOTAL_LENGTH - __LOGURU_FORMAT_LENGTH
|
|
256
|
-
lst = wrap_line(msg, width_min=len_msg, width_max=len_msg + 20)
|
|
257
|
-
return ("\n" + " " * __LOGURU_FORMAT_LENGTH).join(lst)
|
|
258
|
-
|
|
259
362
|
def exploration_can_be_finished(
|
|
260
363
|
self,
|
|
261
364
|
confidence: float,
|
|
@@ -311,7 +414,8 @@ class ReactionNetwork:
|
|
|
311
414
|
msg += f" #Minima :{len(self.__db_minima)}\n"
|
|
312
415
|
msg += f" #Gas :{len(self.__db_gas)}\n"
|
|
313
416
|
msg += f" #TS :{len(self.__db_ts)}\n"
|
|
314
|
-
msg += f"#Event
|
|
417
|
+
msg += f"#Event :{len(self.__metadata.table)}\n"
|
|
418
|
+
msg += f"Configuration :{self.__metadata.basic.to_str(indent=4)}\n"
|
|
315
419
|
return msg
|
|
316
420
|
|
|
317
421
|
def persistence(self) -> None:
|
|
@@ -397,6 +501,7 @@ class ReactionNetwork:
|
|
|
397
501
|
*,
|
|
398
502
|
for_system: str | None = None,
|
|
399
503
|
persist: bool = True,
|
|
504
|
+
env_hop: int = 1, # TODO: make this into whole configuration
|
|
400
505
|
**kwargs,
|
|
401
506
|
) -> Literal["new", "old", "fail"] | str:
|
|
402
507
|
"""Record the event as found.
|
|
@@ -425,13 +530,25 @@ class ReactionNetwork:
|
|
|
425
530
|
simplified_threshold = self.__metadata.basic.simplified_threshold
|
|
426
531
|
if simplified_threshold > 0:
|
|
427
532
|
try:
|
|
428
|
-
event = event.simplify(
|
|
533
|
+
event = event.simplify(
|
|
534
|
+
env_radius=simplified_threshold,
|
|
535
|
+
env_hop=env_hop,
|
|
536
|
+
)
|
|
429
537
|
except Exception as e:
|
|
430
538
|
msg = f"Event {event._string()} failed "
|
|
431
539
|
msg += f"to simplify. because of {e}"
|
|
432
540
|
fname = self.__path / "event-simplify-fail.pkl"
|
|
433
|
-
fname.
|
|
434
|
-
|
|
541
|
+
atomic_write_text(fname.with_suffix(".err"), msg)
|
|
542
|
+
atomic_write(
|
|
543
|
+
fname,
|
|
544
|
+
writer=lambda p: p.write_bytes(pickle.dumps(event)),
|
|
545
|
+
)
|
|
546
|
+
event.R.write_npz(fname.with_suffix(".R.npz"))
|
|
547
|
+
event.P.write_npz(fname.with_suffix(".P.npz"))
|
|
548
|
+
if event.G is not None:
|
|
549
|
+
event.G.write_npz(fname.with_suffix(".G.npz"))
|
|
550
|
+
if event.T is not None:
|
|
551
|
+
event.T.write_npz(fname.with_suffix(".T.npz"))
|
|
435
552
|
raise ValueError(msg)
|
|
436
553
|
if self.write_event(
|
|
437
554
|
event,
|
|
@@ -659,3 +776,33 @@ def wrap_line(
|
|
|
659
776
|
lines.pop()
|
|
660
777
|
|
|
661
778
|
return lines
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
if __name__ == "__main__":
|
|
782
|
+
import json
|
|
783
|
+
import shutil
|
|
784
|
+
from pathlib import Path
|
|
785
|
+
|
|
786
|
+
this_dir = Path(__file__).parent
|
|
787
|
+
root_path = this_dir.parent.parent.parent.parent
|
|
788
|
+
print(root_path)
|
|
789
|
+
|
|
790
|
+
new_path = root_path / "zzzz-merged" / "event"
|
|
791
|
+
shutil.rmtree(new_path.parent, ignore_errors=True)
|
|
792
|
+
|
|
793
|
+
network_lst: list[ReactionNetwork] = []
|
|
794
|
+
for zzzz_path in root_path.glob("zzzz-*"):
|
|
795
|
+
if "merge" not in zzzz_path.name:
|
|
796
|
+
p = zzzz_path / "event"
|
|
797
|
+
(p / "recorder.json").unlink(missing_ok=True)
|
|
798
|
+
atomic_write_text(
|
|
799
|
+
p / "recorder.json",
|
|
800
|
+
json.dumps({}, indent=4),
|
|
801
|
+
)
|
|
802
|
+
network_lst.append(
|
|
803
|
+
ReactionNetwork(
|
|
804
|
+
zzzz_path / "event",
|
|
805
|
+
restart=True,
|
|
806
|
+
)
|
|
807
|
+
)
|
|
808
|
+
new_network = ReactionNetwork.merge(*network_lst, new_path=new_path)
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import pathlib
|
|
2
|
+
from typing import Annotated
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import typer
|
|
6
|
+
from ase import Atoms
|
|
7
|
+
from ase.visualize import view as _ase_view
|
|
8
|
+
|
|
9
|
+
from graphatoms.enterpoint.network import ReactionNetwork as Net
|
|
10
|
+
from graphatoms.system import SysGraph
|
|
11
|
+
|
|
12
|
+
__p_help__ = "Path to the network directory."
|
|
13
|
+
Path = Annotated[str, typer.Option("--path", "-p", help=__p_help__)]
|
|
14
|
+
pd.set_option("display.max_colwidth", None) # don't truncate cell contents
|
|
15
|
+
pd.set_option("display.max_columns", None) # show all columns
|
|
16
|
+
pd.set_option("display.max_rows", None) # show all rows
|
|
17
|
+
pd.set_option("display.width", None) # don't wrap lines
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# --------------
|
|
21
|
+
# Main command
|
|
22
|
+
# --------------
|
|
23
|
+
main = typer.Typer(no_args_is_help=True)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@main.command()
|
|
27
|
+
def summary(path: Path = ".") -> None:
|
|
28
|
+
assert pathlib.Path(path).exists()
|
|
29
|
+
net = Net(path, restart=True, format="dir")
|
|
30
|
+
print(net.summary())
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@main.command(no_args_is_help=True)
|
|
34
|
+
def merge(
|
|
35
|
+
args: Annotated[
|
|
36
|
+
list[str],
|
|
37
|
+
typer.Argument(
|
|
38
|
+
help=f"{Net.__name__} directories to merge (one or more)"
|
|
39
|
+
),
|
|
40
|
+
],
|
|
41
|
+
path: Path = "./event",
|
|
42
|
+
db_format: Annotated[
|
|
43
|
+
str,
|
|
44
|
+
typer.Option(
|
|
45
|
+
"--db-format",
|
|
46
|
+
"-f",
|
|
47
|
+
help="Database format in the network.",
|
|
48
|
+
),
|
|
49
|
+
] = "dir",
|
|
50
|
+
) -> None:
|
|
51
|
+
assert db_format == "dir", "Only `dir` format is supported now."
|
|
52
|
+
lst = [Net(p, restart=True, format=db_format) for p in args]
|
|
53
|
+
Net.merge(*lst, new_path=path)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# ----------------
|
|
57
|
+
# Table subcommand
|
|
58
|
+
# ----------------
|
|
59
|
+
show = typer.Typer(no_args_is_help=True)
|
|
60
|
+
main.add_typer(show, name="show")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@show.command(name="reaction")
|
|
64
|
+
def show_reaction(arg: str, path: Path = ".") -> tuple[int, Net]:
|
|
65
|
+
net = Net(path, restart=True, format="dir")
|
|
66
|
+
df = net.metadata.table.dataframe
|
|
67
|
+
try:
|
|
68
|
+
i = int(arg)
|
|
69
|
+
except ValueError:
|
|
70
|
+
i = net.metadata.table.key_rxn.index(arg)
|
|
71
|
+
print(df.iloc[i])
|
|
72
|
+
return i, net
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@show.command()
|
|
76
|
+
def table(path: Path = ".") -> None:
|
|
77
|
+
assert pathlib.Path(path).exists()
|
|
78
|
+
net = Net(path, restart=True, format="dir")
|
|
79
|
+
df = net.metadata.table.dataframe
|
|
80
|
+
col = [0, 5, 6, 7, 8, 11, 12]
|
|
81
|
+
print(df[df.columns[col]])
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# ----------------
|
|
85
|
+
# View subcommand
|
|
86
|
+
# ----------------
|
|
87
|
+
view = typer.Typer(no_args_is_help=True)
|
|
88
|
+
|
|
89
|
+
main.add_typer(view, name="view")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@view.command(name="reaction")
|
|
93
|
+
def view_reaction(
|
|
94
|
+
name: str,
|
|
95
|
+
path: Path = ".",
|
|
96
|
+
forward: bool = True,
|
|
97
|
+
) -> None:
|
|
98
|
+
idx, net = show_reaction(name, path)
|
|
99
|
+
key_rxn = net.metadata.table.key_rxn[idx]
|
|
100
|
+
_, rxn = net.read_event(key_rxn)
|
|
101
|
+
if not forward:
|
|
102
|
+
rxn = rxn.reversed
|
|
103
|
+
return rxn.view()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@view.command(name="structure")
|
|
107
|
+
def view_structure(
|
|
108
|
+
name_or_path: str,
|
|
109
|
+
path: Path = ".",
|
|
110
|
+
) -> None:
|
|
111
|
+
try:
|
|
112
|
+
fname = pathlib.Path(name_or_path)
|
|
113
|
+
if fname.name.count("*") == 0:
|
|
114
|
+
assert fname.exists() and fname.is_file()
|
|
115
|
+
return _ase_view(SysGraph.read_npz(fname).to_ase())
|
|
116
|
+
else:
|
|
117
|
+
return _ase_view(
|
|
118
|
+
[
|
|
119
|
+
SysGraph.read_npz(i).to_ase()
|
|
120
|
+
for i in fname.parent.glob(fname.name)
|
|
121
|
+
]
|
|
122
|
+
)
|
|
123
|
+
except ValueError:
|
|
124
|
+
name = name_or_path
|
|
125
|
+
|
|
126
|
+
assert pathlib.Path(path).exists()
|
|
127
|
+
net = Net(path, restart=True, format="dir")
|
|
128
|
+
atoms: Atoms | None = None
|
|
129
|
+
for type in ("gas", "ts", "minima", "cluster", "system"):
|
|
130
|
+
if net.contain_sysgraph(name, type=type):
|
|
131
|
+
atoms = net.read_atoms(name, type=type)
|
|
132
|
+
break
|
|
133
|
+
if atoms is None:
|
|
134
|
+
raise ValueError(f"structure {name} is not in the database.")
|
|
135
|
+
return _ase_view(atoms)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
if __name__ == "__main__":
|
|
139
|
+
main()
|