GraphAtoms 2.1.0__tar.gz → 2.2.0__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.1.0 → graphatoms-2.2.0}/PKG-INFO +1 -1
- {graphatoms-2.1.0 → graphatoms-2.2.0}/pyproject.toml +2 -1
- {graphatoms-2.1.0 → graphatoms-2.2.0}/pyproject.toml.orig +2 -1
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/arrayapi/typing.py +3 -3
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/__init__.py +10 -7
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/example.yaml +0 -1
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/network/__init__.py +147 -34
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/network/_metadata.py +12 -27
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/network/_recorder.py +84 -7
- graphatoms-2.2.0/src/graphatoms/enterpoint/runner/__init__.py +36 -0
- graphatoms-2.2.0/src/graphatoms/enterpoint/runner/common/__init__.py +21 -0
- graphatoms-2.2.0/src/graphatoms/enterpoint/runner/common/_base.py +343 -0
- {graphatoms-2.1.0/src/graphatoms/enterpoint/runner → graphatoms-2.2.0/src/graphatoms/enterpoint/runner/common}/_helper.py +175 -33
- graphatoms-2.2.0/src/graphatoms/enterpoint/runner/general/__init__.py +0 -0
- graphatoms-2.1.0/src/graphatoms/enterpoint/runner/_base.py → graphatoms-2.2.0/src/graphatoms/enterpoint/runner/general/_expl.py +108 -303
- {graphatoms-2.1.0/src/graphatoms/enterpoint/runner → graphatoms-2.2.0/src/graphatoms/enterpoint/runner/general}/otfkmc.py +82 -23
- graphatoms-2.2.0/src/graphatoms/enterpoint/runner/general/rxngen.py +152 -0
- graphatoms-2.2.0/src/graphatoms/enterpoint/runner/ray/__init__.py +0 -0
- graphatoms-2.2.0/src/graphatoms/enterpoint/runner/ray/_expl.py +36 -0
- graphatoms-2.2.0/src/graphatoms/enterpoint/runner/ray/otfkmc.py +9 -0
- graphatoms-2.2.0/src/graphatoms/enterpoint/runner/ray/rxngen.py +5 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/view.py +23 -6
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/_bond_list.py +1 -2
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/reaction/__init__.py +1 -2
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/reaction/_event.py +141 -80
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/reaction/reaction.py +5 -15
- graphatoms-2.2.0/src/graphatoms/reaction/xxsorption.py +209 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/atoms.py +4 -2
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/bonds.py +33 -18
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/database/__init__.py +20 -4
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/database/abc.py +9 -7
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/database/dict.py +8 -1
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/database/dir.py +9 -1
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/database/hdf5.py +9 -1
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/database/sqliteASE.py +9 -1
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/graph.py +9 -22
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/sysCluster.py +1 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/sysGas.py +56 -29
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/adsorption.py +1 -1
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/rdutils.py +1 -1
- graphatoms-2.1.0/src/graphatoms/enterpoint/runner/__init__.py +0 -24
- graphatoms-2.1.0/src/graphatoms/enterpoint/runner/rxngen.py +0 -9
- graphatoms-2.1.0/src/graphatoms/reaction/xxsorption.py +0 -198
- {graphatoms-2.1.0 → graphatoms-2.2.0}/README.md +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/LICENSE +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/__init__.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/arrayapi/__init__.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/arrayapi/compat.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/dataclasses/__init__.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/dataclasses/_numpydantic.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/dataclasses/_pydantic2pyarrow.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/dataclasses/_pydanticMixin.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/dataclasses/_pydanticModel.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/dataclasses/graph.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/__init__.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/atoms/__init__.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/atoms/aseread.yaml +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/atoms/octahedron.yaml +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/bonds/__init__.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/bonds/raw.yaml +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/calculator/__init__.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/calculator/emt.yaml +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/calculator/nequip.yaml +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/run.yaml +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/network/_scheduler.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/parallel/__init__.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/parallel/_base.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/parallel/_dask.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/parallel/_executorlib.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/parallel/_ray.py +0 -0
- {graphatoms-2.1.0/src/graphatoms/enterpoint/runner → graphatoms-2.2.0/src/graphatoms/enterpoint/runner/common}/_errors.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/__init__.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/_distance_pairs.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/_inner_outer.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/_neighbor_list.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/mic.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/rotation.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/sample.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/__init__.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/system.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/__init__.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/asetools.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/bytestool.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/logger.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/parser.py +0 -0
- {graphatoms-2.1.0 → graphatoms-2.2.0}/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.
|
|
7
|
+
version = "2.2.0"
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
description = "The Chemical Core Class for Graph Theory Analysis."
|
|
10
10
|
license-files = ["src/LICENSE"]
|
|
@@ -72,6 +72,7 @@ dev = [
|
|
|
72
72
|
"jupyterlab",
|
|
73
73
|
"chemiscope",
|
|
74
74
|
"nglview",
|
|
75
|
+
"grpcio",
|
|
75
76
|
"ray",
|
|
76
77
|
]
|
|
77
78
|
|
|
@@ -12,7 +12,7 @@ graphatoms-network = "graphatoms.enterpoint.view:main"
|
|
|
12
12
|
graphatoms-run = "graphatoms.enterpoint.runner:run"
|
|
13
13
|
[project]
|
|
14
14
|
name = "graphatoms"
|
|
15
|
-
version = "2.
|
|
15
|
+
version = "2.2.0"
|
|
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" }]
|
|
@@ -76,6 +76,7 @@ dev = [
|
|
|
76
76
|
"chemiscope",
|
|
77
77
|
# "playwright>=1.52", # chemiscope [headless]
|
|
78
78
|
"nglview",
|
|
79
|
+
"grpcio",
|
|
79
80
|
"ray",
|
|
80
81
|
]
|
|
81
82
|
|
|
@@ -4243,8 +4243,8 @@ class abs[TArray: Array](Protocol):
|
|
|
4243
4243
|
.. note::
|
|
4244
4244
|
For complex floating-point operands, conforming implementations should take care to avoid undue overflow or underflow during intermediate stages of computation.
|
|
4245
4245
|
|
|
4246
|
-
..
|
|
4247
|
-
|
|
4246
|
+
.. note::
|
|
4247
|
+
Once ``hypot`` is added to the specification, remove the special cases for complex floating-point operands and the note concerning guarding against undue overflow/underflow, and state that special cases must be handled as if implemented as ``hypot(real(x), imag(x))``.
|
|
4248
4248
|
|
|
4249
4249
|
Parameters
|
|
4250
4250
|
----------
|
|
@@ -9679,7 +9679,7 @@ class ArrayNamespace[TArray: Array, TDtype, TDevice](Protocol):
|
|
|
9679
9679
|
sort: sort[TArray,]
|
|
9680
9680
|
"Returns a sorted copy of an input array ``x``.\n\n.. note::\n For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`).\n\nParameters\n----------\nx: array\n input array. Should have a real-valued data type.\naxis: int\n axis along which to sort. If set to ``-1``, the function must sort along the last axis. Default: ``-1``.\ndescending: bool\n sort order. If ``True``, the array must be sorted in descending order (by value). If ``False``, the array must be sorted in ascending order (by value). Default: ``False``.\nstable: bool\n sort stability. If ``True``, the returned array must maintain the relative order of ``x`` values which compare as equal. If ``False``, the returned array may or may not maintain the relative order of ``x`` values which compare as equal (i.e., the relative order of ``x`` values which compare as equal is implementation-dependent). Default: ``True``.\n\nReturns\n-------\nout : array\n a sorted array. The returned array must have the same data type and shape as ``x``."
|
|
9681
9681
|
abs: abs[TArray,]
|
|
9682
|
-
"Calculates the absolute value for each element ``x_i`` of the input array ``x``.\n\nFor real-valued input arrays, the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign.\n\n.. note::\n For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent.\n\n.. note::\n For complex floating-point operands, the complex absolute value is known as the norm, modulus, or magnitude and, for a complex number :math:`z = a + bj` is computed as\n\n .. math::\n \\operatorname{abs}(z) = \\sqrt{a^2 + b^2}\n\n.. note::\n For complex floating-point operands, conforming implementations should take care to avoid undue overflow or underflow during intermediate stages of computation.\n\n..\n
|
|
9682
|
+
"Calculates the absolute value for each element ``x_i`` of the input array ``x``.\n\nFor real-valued input arrays, the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign.\n\n.. note::\n For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent.\n\n.. note::\n For complex floating-point operands, the complex absolute value is known as the norm, modulus, or magnitude and, for a complex number :math:`z = a + bj` is computed as\n\n .. math::\n \\operatorname{abs}(z) = \\sqrt{a^2 + b^2}\n\n.. note::\n For complex floating-point operands, conforming implementations should take care to avoid undue overflow or underflow during intermediate stages of computation.\n\n..\n once ``hypot`` is added to the specification, remove the special cases for complex floating-point operands and the note concerning guarding against undue overflow/underflow, and state that special cases must be handled as if implemented as ``hypot(real(x), imag(x))``.\n\nParameters\n----------\nx: array\n input array. Should have a numeric data type.\n\nReturns\n-------\nout: array\n an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type).\n\nNotes\n-----\n\n**Special Cases**\n\nFor real-valued floating-point operands,\n\n- If ``x_i`` is ``NaN``, the result is ``NaN``.\n- If ``x_i`` is ``-0``, the result is ``+0``.\n- If ``x_i`` is ``-infinity``, the result is ``+infinity``.\n\nFor complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and\n\n- If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``+infinity``.\n- If ``a`` is any value (including ``NaN``) and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``+infinity``.\n- If ``a`` is either ``+0`` or ``-0``, the result is equal to ``abs(b)``.\n- If ``b`` is either ``+0`` or ``-0``, the result is equal to ``abs(a)``.\n- If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN``.\n- If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN``.\n- If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN``.\n\n.. versionchanged:: 2022.12\n Added complex data type support."
|
|
9683
9683
|
acos: acos[TArray,]
|
|
9684
9684
|
"Calculates an implementation-dependent approximation of the principal value of the inverse cosine for each element ``x_i`` of the input array ``x``.\n\nEach element-wise result is expressed in radians.\n\n.. note::\n The principal value of the arc cosine of a complex number :math:`z` is\n\n .. math::\n \\operatorname{acos}(z) = \\frac{1}{2}\\pi + j\\ \\ln(zj + \\sqrt{1-z^2})\n\n For any :math:`z`,\n\n .. math::\n \\operatorname{acos}(z) = \\pi - \\operatorname{acos}(-z)\n\n.. note::\n For complex floating-point operands, ``acos(conj(x))`` must equal ``conj(acos(x))``.\n\n.. note::\n The inverse cosine (or arc cosine) is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\\infty, -1)` and :math:`(1, \\infty)` of the real axis.\n\n Accordingly, for complex arguments, the function returns the inverse cosine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[0, \\pi]` along the real axis.\n\n *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`).\n\nParameters\n----------\nx: array\n input array. Should have a floating-point data type.\n\nReturns\n-------\nout: array\n an array containing the inverse cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`.\n\nNotes\n-----\n\n**Special cases**\n\nFor real-valued floating-point operands,\n\n- If ``x_i`` is ``NaN``, the result is ``NaN``.\n- If ``x_i`` is greater than ``1``, the result is ``NaN``.\n- If ``x_i`` is less than ``-1``, the result is ``NaN``.\n- If ``x_i`` is ``1``, the result is ``+0``.\n\nFor complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and\n\n- If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``π/2 - 0j``.\n- If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``NaN``, the result is ``π/2 + NaN j``.\n- If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``π/2 - infinity j``.\n- If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``.\n- If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``π - infinity j``.\n- If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 - infinity j``.\n- If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``3π/4 - infinity j``.\n- If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``π/4 - infinity j``.\n- If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN ± infinity j`` (sign of the imaginary component is unspecified).\n- If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``.\n- If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``NaN - infinity j``.\n- If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``.\n\n.. versionchanged:: 2022.12\n Added complex data type support."
|
|
9685
9685
|
acosh: acosh[TArray,]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from collections import defaultdict
|
|
2
3
|
from dataclasses import dataclass, field
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
from typing import Any
|
|
@@ -29,6 +30,7 @@ class ExplConfig:
|
|
|
29
30
|
maxtry: int = 1000
|
|
30
31
|
maxconfidence: float = 10
|
|
31
32
|
max_ncore_for_surface: int = 3 # 4, 5, 6
|
|
33
|
+
optimization_for_system: bool = True
|
|
32
34
|
surface_only_explore_single_core: bool = True
|
|
33
35
|
allow_multiple_adsorption: bool = False
|
|
34
36
|
allow_explore_bulk: bool = False
|
|
@@ -45,9 +47,6 @@ class EventConfig:
|
|
|
45
47
|
min_frequency_for_ts: float = 20.0 # cm^-1
|
|
46
48
|
simplified_threshold: float = 7.0 # the simplified threshold for event
|
|
47
49
|
gas_sticking: dict[str, float] = field(default_factory=dict)
|
|
48
|
-
gas_pressure: dict[str, float] = field(default_factory=dict)
|
|
49
|
-
default_pressure: float = 101325
|
|
50
|
-
default_sticking: float = 1.0
|
|
51
50
|
temperature: float = 300
|
|
52
51
|
|
|
53
52
|
|
|
@@ -66,10 +65,17 @@ class Config:
|
|
|
66
65
|
|
|
67
66
|
calculator: CalcConfig = MISSING
|
|
68
67
|
|
|
69
|
-
outputs: str = "
|
|
68
|
+
outputs: str = "."
|
|
70
69
|
max_steps: int = 100000
|
|
71
70
|
max_times: float = 1000.0 # seconds
|
|
72
71
|
run_type: str = "otfkmc" # otfkmc, rxngen
|
|
72
|
+
gas_pressure_cache_box_length: float = 1e4 # in Angstrom
|
|
73
|
+
initial_gas_pressure: dict[str, float] = field(default_factory=dict)
|
|
74
|
+
# the initial gas pressure only effect for `OTFKMC`, and the key of
|
|
75
|
+
# `initial_gas_pressure` must be the same as the key of `gas_sticking`
|
|
76
|
+
# 2. if the key of `initial_gas_pressure` is not in `gas_sticking`, then the initial gas pressure is 0.0 # noqa: E501
|
|
77
|
+
# 1. if the key of `gas_sticking` is not in `initial_gas_pressure`, then the gas sticking is 1.0 # noqa: E501
|
|
78
|
+
|
|
73
79
|
parallel_workers: int = 0 # 0 means use all cores
|
|
74
80
|
parallel: str = "serial" # serial, multiprocessing, ray, dask, executorlib
|
|
75
81
|
loglevel: str = "info" # Literal["debug", "info", "warning", "error"]
|
|
@@ -98,8 +104,6 @@ cs.store(group="calculator", name="calc_nequip", node=NequipConfig)
|
|
|
98
104
|
version_base=None,
|
|
99
105
|
)
|
|
100
106
|
def print_config(cfg: Config) -> None:
|
|
101
|
-
from shutil import rmtree
|
|
102
|
-
|
|
103
107
|
print(OmegaConf.to_yaml(cfg))
|
|
104
108
|
print("""
|
|
105
109
|
hydra:
|
|
@@ -107,4 +111,3 @@ hydra:
|
|
|
107
111
|
dir: ${outputs}
|
|
108
112
|
verbose: ${debug}
|
|
109
113
|
""")
|
|
110
|
-
rmtree(Path(cfg.outputs))
|
|
@@ -1,27 +1,33 @@
|
|
|
1
1
|
import dataclasses as dc
|
|
2
2
|
import pickle
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import Literal
|
|
4
|
+
from typing import Literal, Self
|
|
5
5
|
|
|
6
6
|
from graphatoms.enterpoint.config import EventConfig
|
|
7
|
-
from graphatoms.reaction import
|
|
8
|
-
|
|
7
|
+
from graphatoms.reaction import (
|
|
8
|
+
Adsorption,
|
|
9
|
+
Desorption,
|
|
10
|
+
EventBase,
|
|
11
|
+
EventInfo,
|
|
12
|
+
Reaction,
|
|
13
|
+
)
|
|
14
|
+
from graphatoms.system import Gas, SysGraph
|
|
9
15
|
from graphatoms.system.database import DatabaseABC, get_db
|
|
10
16
|
|
|
11
17
|
from ._metadata import MetaData
|
|
12
18
|
from ._metadata import _MetaDataBasic as MetaDataBasic
|
|
13
|
-
from ._recorder import Recorder
|
|
19
|
+
from ._recorder import Recorder, RecorderInfo
|
|
14
20
|
from ._scheduler import Scheduler
|
|
15
21
|
|
|
16
22
|
__all__ = [
|
|
17
|
-
"RxNet",
|
|
18
23
|
"MetaData",
|
|
19
24
|
"Recorder",
|
|
20
25
|
"Scheduler",
|
|
26
|
+
"ReactionNetwork",
|
|
21
27
|
]
|
|
22
28
|
|
|
23
29
|
|
|
24
|
-
class
|
|
30
|
+
class ReactionNetwork:
|
|
25
31
|
def __init__(
|
|
26
32
|
self,
|
|
27
33
|
path: Path | str,
|
|
@@ -32,6 +38,7 @@ class RxNet:
|
|
|
32
38
|
**kwargs,
|
|
33
39
|
) -> None:
|
|
34
40
|
self.__path = path = Path(path)
|
|
41
|
+
self.__path_exploration_recorder = path / "exploration.csv"
|
|
35
42
|
if config is not None:
|
|
36
43
|
metadata_basic = MetaDataBasic(
|
|
37
44
|
**(
|
|
@@ -56,6 +63,10 @@ class RxNet:
|
|
|
56
63
|
f"The path `{self.__path}` does not exist."
|
|
57
64
|
+ " Please create it or use `restart=False`."
|
|
58
65
|
)
|
|
66
|
+
assert self.__path_exploration_recorder.exists(), (
|
|
67
|
+
f"The path `{self.__path_exploration_recorder}` does not exist."
|
|
68
|
+
+ " Please create it or use `restart=False`."
|
|
69
|
+
)
|
|
59
70
|
self.scheduler = Scheduler.read_npz(path / "scheduler.npz")
|
|
60
71
|
self.recorder = Recorder.read_json(path / "recorder.json")
|
|
61
72
|
self.metadata = MetaData.from_storage(path)
|
|
@@ -73,28 +84,74 @@ class RxNet:
|
|
|
73
84
|
f"The path `{self.__path}` does exist."
|
|
74
85
|
+ " Please delete it or use `restart=True`."
|
|
75
86
|
)
|
|
87
|
+
self.__path.mkdir(parents=True, exist_ok=True)
|
|
88
|
+
self.__path_exploration_recorder.write_text(
|
|
89
|
+
RecorderInfo.get_csv_title() + "\n"
|
|
90
|
+
)
|
|
76
91
|
self.recorder: Recorder = Recorder()
|
|
77
92
|
self.scheduler: Scheduler = Scheduler()
|
|
78
93
|
if metadata_basic is not None:
|
|
79
94
|
self.metadata: MetaData = MetaData(basic=metadata_basic)
|
|
80
95
|
else:
|
|
81
96
|
self.metadata: MetaData = MetaData()
|
|
97
|
+
self.__format = format
|
|
82
98
|
|
|
83
99
|
# initialize the databases
|
|
84
|
-
|
|
100
|
+
(
|
|
101
|
+
self.db_ts,
|
|
102
|
+
self.db_gas,
|
|
103
|
+
self.db_minima,
|
|
104
|
+
self.db_cluster,
|
|
105
|
+
self.db_system,
|
|
106
|
+
) = [
|
|
85
107
|
get_db(
|
|
86
108
|
path=path,
|
|
87
109
|
format=format,
|
|
88
110
|
prefix=prefix,
|
|
89
111
|
append=restart,
|
|
112
|
+
use_positions_uuid=use_positions_uuid,
|
|
90
113
|
)
|
|
91
|
-
for prefix in [
|
|
114
|
+
for prefix, use_positions_uuid in [
|
|
115
|
+
("ts", True),
|
|
116
|
+
("gas", False),
|
|
117
|
+
("minima", True),
|
|
118
|
+
("cluster", False),
|
|
119
|
+
("system", False),
|
|
120
|
+
]
|
|
92
121
|
]
|
|
93
|
-
self.db_ts,
|
|
122
|
+
assert isinstance(self.db_ts, DatabaseABC)
|
|
123
|
+
assert isinstance(self.db_gas, DatabaseABC)
|
|
124
|
+
assert isinstance(self.db_minima, DatabaseABC)
|
|
125
|
+
assert isinstance(self.db_cluster, DatabaseABC)
|
|
126
|
+
assert isinstance(self.db_system, DatabaseABC)
|
|
127
|
+
|
|
128
|
+
@classmethod
|
|
129
|
+
def merge(
|
|
130
|
+
cls,
|
|
131
|
+
*networks: Self,
|
|
132
|
+
new_path: Path | str,
|
|
133
|
+
new_format: str | Literal["dir", "h5", "sqlite"] = "dir",
|
|
134
|
+
**kwargs,
|
|
135
|
+
) -> Self:
|
|
136
|
+
"""Merge the networks."""
|
|
137
|
+
raise NotImplementedError("Merge the networks.")
|
|
138
|
+
cls(
|
|
139
|
+
path=new_path,
|
|
140
|
+
restart=False,
|
|
141
|
+
config=networks[0].metadata.basic,
|
|
142
|
+
format=networks[0].__format,
|
|
143
|
+
)
|
|
94
144
|
|
|
95
145
|
def summary(self) -> str:
|
|
96
146
|
"""Return the summary of the network."""
|
|
97
|
-
|
|
147
|
+
msg = f"ReactionNetwork: {self.__path} (format={self.__format})\n"
|
|
148
|
+
msg += f" #System :{len(self.db_system)}\n"
|
|
149
|
+
msg += f" #Cluster :{len(self.db_cluster)}\n"
|
|
150
|
+
msg += f" #Minima :{len(self.db_minima)}\n"
|
|
151
|
+
msg += f" #Gas :{len(self.db_gas)}\n"
|
|
152
|
+
msg += f" #TS :{len(self.db_ts)}\n"
|
|
153
|
+
msg += f"#Event :{len(self.metadata.table)}\n"
|
|
154
|
+
return msg
|
|
98
155
|
|
|
99
156
|
def persistence(self) -> None:
|
|
100
157
|
"""Persist the data to the database."""
|
|
@@ -102,16 +159,24 @@ class RxNet:
|
|
|
102
159
|
self.scheduler.write_npz(self.__path / "scheduler.npz")
|
|
103
160
|
self.metadata.persistence(self.__path)
|
|
104
161
|
|
|
105
|
-
def
|
|
162
|
+
def read_event(self, key: str) -> tuple[EventInfo, EventBase]:
|
|
163
|
+
"""Read the event from the database."""
|
|
106
164
|
if self.metadata.has(key):
|
|
107
165
|
info = self.metadata.read(key)
|
|
108
166
|
if info.key_g is not None:
|
|
109
|
-
|
|
167
|
+
assert info.key_t is None
|
|
168
|
+
g = Gas.from_ase(self.db_gas[info.key_g])
|
|
169
|
+
r = SysGraph.from_ase(self.db_minima[info.key_r])
|
|
170
|
+
p = SysGraph.from_ase(self.db_minima[info.key_p])
|
|
171
|
+
if r.natoms < p.natoms:
|
|
172
|
+
return info, Adsorption(G=g, R=r, P=p)
|
|
173
|
+
else:
|
|
174
|
+
return info, Desorption(G=g, R=r, P=p)
|
|
110
175
|
else:
|
|
111
176
|
assert info.key_t is not None
|
|
112
|
-
ts =
|
|
113
|
-
r =
|
|
114
|
-
p =
|
|
177
|
+
ts = SysGraph.from_ase(self.db_ts[info.key_t])
|
|
178
|
+
r = SysGraph.from_ase(self.db_minima[info.key_r])
|
|
179
|
+
p = SysGraph.from_ase(self.db_minima[info.key_p])
|
|
115
180
|
return info, Reaction(T=ts, R=r, P=p)
|
|
116
181
|
else:
|
|
117
182
|
raise ValueError(f"Event {key} is not in the database.")
|
|
@@ -119,20 +184,36 @@ class RxNet:
|
|
|
119
184
|
def found(
|
|
120
185
|
self,
|
|
121
186
|
event: EventBase | str,
|
|
187
|
+
for_gas: str | None,
|
|
188
|
+
for_cluster: str,
|
|
122
189
|
*,
|
|
123
|
-
for_cluster: str | None = None,
|
|
124
190
|
for_system: str | None = None,
|
|
125
191
|
persist: bool = True,
|
|
126
192
|
**kwargs,
|
|
127
193
|
) -> Literal["new", "old", "fail"] | str:
|
|
194
|
+
if for_system is None:
|
|
195
|
+
for_system = ""
|
|
196
|
+
if for_gas is None:
|
|
197
|
+
for_gas = ""
|
|
198
|
+
old_new = self.recorder.cluster[for_cluster]
|
|
199
|
+
min_found = self.metadata.table.get_minconut_for(
|
|
200
|
+
cluster_key=for_cluster,
|
|
201
|
+
system_key=for_system,
|
|
202
|
+
gas_key=None,
|
|
203
|
+
)
|
|
204
|
+
else:
|
|
205
|
+
old_new = self.recorder.adsorption[f"{for_cluster}_{for_gas}"]
|
|
206
|
+
min_found = self.metadata.table.get_minconut_for(
|
|
207
|
+
cluster_key=for_cluster,
|
|
208
|
+
system_key=for_system,
|
|
209
|
+
gas_key=for_gas,
|
|
210
|
+
)
|
|
211
|
+
|
|
128
212
|
if isinstance(event, str):
|
|
129
|
-
|
|
213
|
+
old_new.found_fail()
|
|
214
|
+
result = "fail"
|
|
130
215
|
elif isinstance(event, EventBase):
|
|
131
216
|
simplified_threshold = self.metadata.basic.simplified_threshold
|
|
132
|
-
if for_system is None:
|
|
133
|
-
for_system = ""
|
|
134
|
-
if for_cluster is None:
|
|
135
|
-
for_cluster = event.R.get_key_for_metadata()
|
|
136
217
|
if simplified_threshold > 0:
|
|
137
218
|
try:
|
|
138
219
|
event = event.simplify(simplified_threshold)
|
|
@@ -143,18 +224,33 @@ class RxNet:
|
|
|
143
224
|
fname.write_bytes(pickle.dumps(event))
|
|
144
225
|
fname.with_suffix(".err").write_text(msg)
|
|
145
226
|
raise ValueError(msg)
|
|
146
|
-
|
|
227
|
+
if self.write_event(
|
|
147
228
|
event,
|
|
148
229
|
for_cluster,
|
|
149
230
|
for_system,
|
|
150
231
|
persist=persist,
|
|
151
232
|
**kwargs,
|
|
152
|
-
)
|
|
153
|
-
|
|
233
|
+
):
|
|
234
|
+
old_new.found_new()
|
|
235
|
+
result = f"new {event}"
|
|
236
|
+
else:
|
|
237
|
+
old_new.found_old()
|
|
238
|
+
result = f"old {event}"
|
|
154
239
|
else:
|
|
155
240
|
raise ValueError(f"Unknown event type: {type(event)}")
|
|
156
241
|
|
|
157
|
-
|
|
242
|
+
info = RecorderInfo.from_oldnew(
|
|
243
|
+
oldnew=old_new,
|
|
244
|
+
min_found=min_found,
|
|
245
|
+
for_cluster=for_cluster,
|
|
246
|
+
for_system=for_system,
|
|
247
|
+
for_gas=for_gas,
|
|
248
|
+
)
|
|
249
|
+
with self.__path_exploration_recorder.open("a") as f:
|
|
250
|
+
f.write(info.to_csv_line() + "\n")
|
|
251
|
+
return result
|
|
252
|
+
|
|
253
|
+
def write_event(
|
|
158
254
|
self,
|
|
159
255
|
event: EventBase,
|
|
160
256
|
for_cluster: str,
|
|
@@ -164,18 +260,31 @@ class RxNet:
|
|
|
164
260
|
**kwargs,
|
|
165
261
|
) -> bool:
|
|
166
262
|
"""Write the event to the database."""
|
|
263
|
+
if isinstance(event, Desorption):
|
|
264
|
+
event = event.reversed
|
|
265
|
+
assert isinstance(event, Adsorption | Reaction), (
|
|
266
|
+
f"Unknown event type: {type(event)}. Only " #
|
|
267
|
+
"Adsorption and Reaction are supported, " #
|
|
268
|
+
"and the Desorption will be reversed."
|
|
269
|
+
)
|
|
270
|
+
if event.G is not None:
|
|
271
|
+
assert event.R.natoms < event.P.natoms, (
|
|
272
|
+
f"Event {event._string()} is not Adsorption. "
|
|
273
|
+
"The R must have fewer atoms than P."
|
|
274
|
+
)
|
|
275
|
+
|
|
167
276
|
if self.metadata.has(event):
|
|
168
277
|
self.metadata.rxn_count_add_one(event)
|
|
169
278
|
return False
|
|
170
279
|
else:
|
|
171
280
|
self.metadata.write(event, for_cluster, for_system)
|
|
172
281
|
try:
|
|
173
|
-
self.
|
|
174
|
-
self.
|
|
282
|
+
self.write_sysgraph(event.R, "minima")
|
|
283
|
+
self.write_sysgraph(event.P, "minima")
|
|
175
284
|
if event.G is not None:
|
|
176
|
-
self.
|
|
285
|
+
self.write_sysgraph(event.G, "gas")
|
|
177
286
|
if event.T is not None:
|
|
178
|
-
self.
|
|
287
|
+
self.write_sysgraph(event.T, "ts")
|
|
179
288
|
if persist:
|
|
180
289
|
self.persistence()
|
|
181
290
|
return True
|
|
@@ -201,17 +310,21 @@ class RxNet:
|
|
|
201
310
|
self.persistence()
|
|
202
311
|
raise e
|
|
203
312
|
|
|
204
|
-
def
|
|
313
|
+
def write_sysgraph(
|
|
205
314
|
self,
|
|
206
315
|
sysgraph: SysGraph,
|
|
207
|
-
type: Literal["minima", "ts", "gas"] | str,
|
|
316
|
+
type: Literal["minima", "ts", "gas", "cluster", "system"] | str,
|
|
208
317
|
) -> bool:
|
|
209
318
|
"""Return True if the value is new, False otherwise."""
|
|
210
|
-
if type == "minima":
|
|
319
|
+
if type.lower() == "minima":
|
|
211
320
|
return self.db_minima.add(sysgraph, check_positions=True)
|
|
212
|
-
elif type == "ts":
|
|
321
|
+
elif type.lower() == "ts":
|
|
213
322
|
return self.db_ts.add(sysgraph, check_positions=True)
|
|
214
|
-
elif type == "gas":
|
|
323
|
+
elif type.lower() == "gas":
|
|
215
324
|
return self.db_gas.add(sysgraph, check_positions=False)
|
|
325
|
+
elif type.lower() == "system":
|
|
326
|
+
return self.db_system.add(sysgraph, check_positions=False)
|
|
327
|
+
elif type.lower() == "cluster":
|
|
328
|
+
return self.db_cluster.add(sysgraph, check_positions=False)
|
|
216
329
|
else:
|
|
217
330
|
raise ValueError(f"Unknown type: {type}")
|
|
@@ -7,47 +7,25 @@ import pandas as pd
|
|
|
7
7
|
from pydantic import (
|
|
8
8
|
BaseModel,
|
|
9
9
|
NonNegativeFloat,
|
|
10
|
-
computed_field,
|
|
11
10
|
model_validator,
|
|
12
11
|
)
|
|
13
12
|
|
|
14
13
|
from graphatoms.dataclasses import OurBaseModel
|
|
15
14
|
from graphatoms.enterpoint.config import EventConfig
|
|
16
15
|
from graphatoms.reaction import EventBase, EventInfo
|
|
16
|
+
from graphatoms.system.bonds import matchmode2nmatch
|
|
17
17
|
|
|
18
18
|
__all__ = ["MetaData"]
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
class _GasInfo(BaseModel):
|
|
22
|
-
name: str
|
|
23
|
-
sticking: float
|
|
24
|
-
pressure: float
|
|
25
|
-
|
|
26
|
-
|
|
27
21
|
class _MetaDataBasic(OurBaseModel, EventConfig):
|
|
28
22
|
gas_sticking: dict[str, NonNegativeFloat] = {}
|
|
29
|
-
gas_pressure: dict[str, NonNegativeFloat] = {}
|
|
30
23
|
temperature: float = 300
|
|
31
24
|
|
|
32
25
|
@override
|
|
33
26
|
def _string(self) -> str:
|
|
34
27
|
return ", ".join([f"{k}={v}" for k, v in self.model_dump().items()])
|
|
35
28
|
|
|
36
|
-
@computed_field
|
|
37
|
-
@property
|
|
38
|
-
def gas_info_lst(self) -> list[_GasInfo]:
|
|
39
|
-
result: list[_GasInfo] = []
|
|
40
|
-
for name, sticking in self.gas_sticking.items():
|
|
41
|
-
pressure = self.gas_pressure.get(name, self.default_pressure)
|
|
42
|
-
result.append(
|
|
43
|
-
_GasInfo(
|
|
44
|
-
name=name,
|
|
45
|
-
sticking=sticking,
|
|
46
|
-
pressure=pressure,
|
|
47
|
-
)
|
|
48
|
-
)
|
|
49
|
-
return result
|
|
50
|
-
|
|
51
29
|
|
|
52
30
|
class _MetaDataTable(BaseModel):
|
|
53
31
|
key_rxn: list[str] = []
|
|
@@ -110,7 +88,7 @@ class _MetaDataTable(BaseModel):
|
|
|
110
88
|
*,
|
|
111
89
|
cluster_key: str | None = None,
|
|
112
90
|
system_key: str | None = None,
|
|
113
|
-
|
|
91
|
+
gas_key: str | None = None,
|
|
114
92
|
**kwargs,
|
|
115
93
|
) -> int:
|
|
116
94
|
if cluster_key is not None:
|
|
@@ -120,7 +98,7 @@ class _MetaDataTable(BaseModel):
|
|
|
120
98
|
for i, ck in enumerate(self.for_cluster)
|
|
121
99
|
if (
|
|
122
100
|
ck == cluster_key
|
|
123
|
-
and ((
|
|
101
|
+
and ((gas_key is None) or self.key_g[i] is gas_key)
|
|
124
102
|
)
|
|
125
103
|
]
|
|
126
104
|
+ [0]
|
|
@@ -132,7 +110,7 @@ class _MetaDataTable(BaseModel):
|
|
|
132
110
|
for i, sk in enumerate(self.for_system)
|
|
133
111
|
if (
|
|
134
112
|
sk == system_key
|
|
135
|
-
and ((
|
|
113
|
+
and ((gas_key is None) or self.key_g[i] is gas_key)
|
|
136
114
|
)
|
|
137
115
|
]
|
|
138
116
|
+ [0]
|
|
@@ -163,6 +141,9 @@ class MetaData(BaseModel):
|
|
|
163
141
|
def bkl_solver(
|
|
164
142
|
self,
|
|
165
143
|
matching_dct: dict[tuple[str, bool], np.ndarray],
|
|
144
|
+
*args,
|
|
145
|
+
env_pressure: dict[str, float] = {},
|
|
146
|
+
**kwargs,
|
|
166
147
|
) -> tuple[pd.DataFrame, str, bool, float, float]:
|
|
167
148
|
"""Solve the BKL equation to select the reaction.
|
|
168
149
|
|
|
@@ -181,9 +162,13 @@ class MetaData(BaseModel):
|
|
|
181
162
|
names = ["rxn_key", "is_forward", "nmatched", "rate"]
|
|
182
163
|
for (rxn_key, is_forward), single_match_res in matching_dct.items():
|
|
183
164
|
i: int = self.table.key_rxn.index(rxn_key)
|
|
184
|
-
|
|
165
|
+
# Eliminate the overestimation caused by permutation symmetry.
|
|
166
|
+
nmatched = matchmode2nmatch(single_match_res)
|
|
185
167
|
if is_forward:
|
|
186
168
|
rate = self.table.rate_forword[i]
|
|
169
|
+
key_g = self.table.key_g[i]
|
|
170
|
+
if key_g is not None:
|
|
171
|
+
rate *= env_pressure.get(key_g, 0.0)
|
|
187
172
|
else:
|
|
188
173
|
rate = self.table.rate_reversed[i]
|
|
189
174
|
lst.append((rxn_key, is_forward, nmatched, rate))
|