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.
Files changed (86) hide show
  1. {graphatoms-2.1.0 → graphatoms-2.2.0}/PKG-INFO +1 -1
  2. {graphatoms-2.1.0 → graphatoms-2.2.0}/pyproject.toml +2 -1
  3. {graphatoms-2.1.0 → graphatoms-2.2.0}/pyproject.toml.orig +2 -1
  4. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/arrayapi/typing.py +3 -3
  5. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/__init__.py +10 -7
  6. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/example.yaml +0 -1
  7. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/network/__init__.py +147 -34
  8. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/network/_metadata.py +12 -27
  9. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/network/_recorder.py +84 -7
  10. graphatoms-2.2.0/src/graphatoms/enterpoint/runner/__init__.py +36 -0
  11. graphatoms-2.2.0/src/graphatoms/enterpoint/runner/common/__init__.py +21 -0
  12. graphatoms-2.2.0/src/graphatoms/enterpoint/runner/common/_base.py +343 -0
  13. {graphatoms-2.1.0/src/graphatoms/enterpoint/runner → graphatoms-2.2.0/src/graphatoms/enterpoint/runner/common}/_helper.py +175 -33
  14. graphatoms-2.2.0/src/graphatoms/enterpoint/runner/general/__init__.py +0 -0
  15. graphatoms-2.1.0/src/graphatoms/enterpoint/runner/_base.py → graphatoms-2.2.0/src/graphatoms/enterpoint/runner/general/_expl.py +108 -303
  16. {graphatoms-2.1.0/src/graphatoms/enterpoint/runner → graphatoms-2.2.0/src/graphatoms/enterpoint/runner/general}/otfkmc.py +82 -23
  17. graphatoms-2.2.0/src/graphatoms/enterpoint/runner/general/rxngen.py +152 -0
  18. graphatoms-2.2.0/src/graphatoms/enterpoint/runner/ray/__init__.py +0 -0
  19. graphatoms-2.2.0/src/graphatoms/enterpoint/runner/ray/_expl.py +36 -0
  20. graphatoms-2.2.0/src/graphatoms/enterpoint/runner/ray/otfkmc.py +9 -0
  21. graphatoms-2.2.0/src/graphatoms/enterpoint/runner/ray/rxngen.py +5 -0
  22. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/view.py +23 -6
  23. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/_bond_list.py +1 -2
  24. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/reaction/__init__.py +1 -2
  25. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/reaction/_event.py +141 -80
  26. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/reaction/reaction.py +5 -15
  27. graphatoms-2.2.0/src/graphatoms/reaction/xxsorption.py +209 -0
  28. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/atoms.py +4 -2
  29. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/bonds.py +33 -18
  30. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/database/__init__.py +20 -4
  31. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/database/abc.py +9 -7
  32. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/database/dict.py +8 -1
  33. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/database/dir.py +9 -1
  34. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/database/hdf5.py +9 -1
  35. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/database/sqliteASE.py +9 -1
  36. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/graph.py +9 -22
  37. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/sysCluster.py +1 -0
  38. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/sysGas.py +56 -29
  39. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/adsorption.py +1 -1
  40. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/rdutils.py +1 -1
  41. graphatoms-2.1.0/src/graphatoms/enterpoint/runner/__init__.py +0 -24
  42. graphatoms-2.1.0/src/graphatoms/enterpoint/runner/rxngen.py +0 -9
  43. graphatoms-2.1.0/src/graphatoms/reaction/xxsorption.py +0 -198
  44. {graphatoms-2.1.0 → graphatoms-2.2.0}/README.md +0 -0
  45. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/LICENSE +0 -0
  46. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/__init__.py +0 -0
  47. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/arrayapi/__init__.py +0 -0
  48. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/arrayapi/compat.py +0 -0
  49. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/dataclasses/__init__.py +0 -0
  50. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/dataclasses/_numpydantic.py +0 -0
  51. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/dataclasses/_pydantic2pyarrow.py +0 -0
  52. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/dataclasses/_pydanticMixin.py +0 -0
  53. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/dataclasses/_pydanticModel.py +0 -0
  54. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/dataclasses/graph.py +0 -0
  55. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/__init__.py +0 -0
  56. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/atoms/__init__.py +0 -0
  57. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/atoms/aseread.yaml +0 -0
  58. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/atoms/octahedron.yaml +0 -0
  59. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/bonds/__init__.py +0 -0
  60. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/bonds/raw.yaml +0 -0
  61. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/calculator/__init__.py +0 -0
  62. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/calculator/emt.yaml +0 -0
  63. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/calculator/nequip.yaml +0 -0
  64. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/config/run.yaml +0 -0
  65. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/network/_scheduler.py +0 -0
  66. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/parallel/__init__.py +0 -0
  67. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/parallel/_base.py +0 -0
  68. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/parallel/_dask.py +0 -0
  69. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/parallel/_executorlib.py +0 -0
  70. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/enterpoint/parallel/_ray.py +0 -0
  71. {graphatoms-2.1.0/src/graphatoms/enterpoint/runner → graphatoms-2.2.0/src/graphatoms/enterpoint/runner/common}/_errors.py +0 -0
  72. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/__init__.py +0 -0
  73. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/_distance_pairs.py +0 -0
  74. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/_inner_outer.py +0 -0
  75. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/_neighbor_list.py +0 -0
  76. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/mic.py +0 -0
  77. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/rotation.py +0 -0
  78. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/geometry/sample.py +0 -0
  79. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/__init__.py +0 -0
  80. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/system/system.py +0 -0
  81. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/__init__.py +0 -0
  82. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/asetools.py +0 -0
  83. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/bytestool.py +0 -0
  84. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/logger.py +0 -0
  85. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/parser.py +0 -0
  86. {graphatoms-2.1.0 → graphatoms-2.2.0}/src/graphatoms/utils/subgraph.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphatoms
3
- Version: 2.1.0
3
+ Version: 2.2.0
4
4
  Summary: The Chemical Core Class for Graph Theory Analysis.
5
5
  Keywords: chemistry,graph theory,reaction,event,KMC
6
6
  Author: LiuGaoyong
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "graphatoms"
7
- version = "2.1.0"
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.1.0"
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
- TODO: 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))``.
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 TODO: 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."
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 = "./zzz"
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))
@@ -64,7 +64,6 @@ event:
64
64
  gas_sticking:
65
65
  CO: 0.5
66
66
  CO2: 0.5
67
- gas_pressure: {}
68
67
  temperature: 300.0
69
68
  optimizer:
70
69
  method: "lbfgs"
@@ -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 EventBase, EventInfo, Reaction
8
- from graphatoms.system import Cluster, SysGraph
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 RxNet:
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
- lst: list[DatabaseABC] = [
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 ["ts", "gas", "minima"]
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, self.db_gas, self.db_minima = lst
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
- return "fasdasdgase"
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 read(self, key: str) -> tuple[EventInfo, EventBase]:
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
- raise NotImplementedError("Ads/Des is not supported.")
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 = Cluster.from_ase(self.db_ts[info.key_t])
113
- r = Cluster.from_ase(self.db_minima[info.key_r])
114
- p = Cluster.from_ase(self.db_minima[info.key_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
- return "fail"
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
- is_new = self._write(
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
- return f"{'new' if is_new else 'old'} {event}"
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
- def _write(
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.__write(event.R, "minima")
174
- self.__write(event.P, "minima")
282
+ self.write_sysgraph(event.R, "minima")
283
+ self.write_sysgraph(event.P, "minima")
175
284
  if event.G is not None:
176
- self.__write(event.G, "gas")
285
+ self.write_sysgraph(event.G, "gas")
177
286
  if event.T is not None:
178
- self.__write(event.T, "ts")
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 __write(
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
- exclude_gas: bool = False,
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 ((not exclude_gas) or self.key_g[i] is None)
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 ((not exclude_gas) or self.key_g[i] is None)
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
- nmatched = int(single_match_res.shape[0])
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))