scgo 0.1.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 (240) hide show
  1. scgo-0.1.0/LICENSE +21 -0
  2. scgo-0.1.0/PKG-INFO +509 -0
  3. scgo-0.1.0/README.md +461 -0
  4. scgo-0.1.0/benchmark/benchmark_Pt.py +101 -0
  5. scgo-0.1.0/benchmark/benchmark_Pt_surface_graphite.py +122 -0
  6. scgo-0.1.0/benchmark/benchmark_common.py +673 -0
  7. scgo-0.1.0/docs/source/conf.py +109 -0
  8. scgo-0.1.0/examples/example_pt5_2oh_graphite.py +85 -0
  9. scgo-0.1.0/examples/example_pt5_gas.py +57 -0
  10. scgo-0.1.0/examples/example_pt5_graphite.py +69 -0
  11. scgo-0.1.0/examples/example_pt5_oh_gas.py +75 -0
  12. scgo-0.1.0/pyproject.toml +112 -0
  13. scgo-0.1.0/scgo/__init__.py +168 -0
  14. scgo-0.1.0/scgo/algorithms/__init__.py +26 -0
  15. scgo-0.1.0/scgo/algorithms/basinhopping_go.py +693 -0
  16. scgo-0.1.0/scgo/algorithms/ga_common.py +1455 -0
  17. scgo-0.1.0/scgo/algorithms/geneticalgorithm_go_torchsim.py +1553 -0
  18. scgo-0.1.0/scgo/algorithms/simple_go.py +138 -0
  19. scgo-0.1.0/scgo/ase_ga_patches/__init__.py +7 -0
  20. scgo-0.1.0/scgo/ase_ga_patches/_vector_utils.py +23 -0
  21. scgo-0.1.0/scgo/ase_ga_patches/cutandsplicepairing.py +726 -0
  22. scgo-0.1.0/scgo/ase_ga_patches/population.py +592 -0
  23. scgo-0.1.0/scgo/ase_ga_patches/standardmutations.py +1800 -0
  24. scgo-0.1.0/scgo/calculators/__init__.py +66 -0
  25. scgo-0.1.0/scgo/calculators/ase_batch_relaxer.py +50 -0
  26. scgo-0.1.0/scgo/calculators/mace_helpers.py +167 -0
  27. scgo-0.1.0/scgo/calculators/orca_helpers.py +128 -0
  28. scgo-0.1.0/scgo/calculators/torchsim_helpers.py +738 -0
  29. scgo-0.1.0/scgo/calculators/uma_helpers.py +77 -0
  30. scgo-0.1.0/scgo/calculators/vasp_helpers.py +111 -0
  31. scgo-0.1.0/scgo/cluster_adsorbate/__init__.py +49 -0
  32. scgo-0.1.0/scgo/cluster_adsorbate/combine.py +38 -0
  33. scgo-0.1.0/scgo/cluster_adsorbate/config.py +48 -0
  34. scgo-0.1.0/scgo/cluster_adsorbate/constraints.py +78 -0
  35. scgo-0.1.0/scgo/cluster_adsorbate/feasibility.py +129 -0
  36. scgo-0.1.0/scgo/cluster_adsorbate/geometry.py +124 -0
  37. scgo-0.1.0/scgo/cluster_adsorbate/hierarchical.py +215 -0
  38. scgo-0.1.0/scgo/cluster_adsorbate/placement.py +410 -0
  39. scgo-0.1.0/scgo/cluster_adsorbate/relax.py +222 -0
  40. scgo-0.1.0/scgo/cluster_adsorbate/reposition.py +139 -0
  41. scgo-0.1.0/scgo/cluster_adsorbate/rigid.py +105 -0
  42. scgo-0.1.0/scgo/cluster_adsorbate/validation.py +118 -0
  43. scgo-0.1.0/scgo/constants.py +30 -0
  44. scgo-0.1.0/scgo/database/__init__.py +175 -0
  45. scgo-0.1.0/scgo/database/cache.py +259 -0
  46. scgo-0.1.0/scgo/database/connection.py +180 -0
  47. scgo-0.1.0/scgo/database/constants.py +10 -0
  48. scgo-0.1.0/scgo/database/discovery.py +383 -0
  49. scgo-0.1.0/scgo/database/exceptions.py +9 -0
  50. scgo-0.1.0/scgo/database/health.py +165 -0
  51. scgo-0.1.0/scgo/database/helpers.py +948 -0
  52. scgo-0.1.0/scgo/database/manager.py +211 -0
  53. scgo-0.1.0/scgo/database/metadata.py +347 -0
  54. scgo-0.1.0/scgo/database/registry.py +254 -0
  55. scgo-0.1.0/scgo/database/schema.py +176 -0
  56. scgo-0.1.0/scgo/database/streaming.py +229 -0
  57. scgo-0.1.0/scgo/database/sync.py +208 -0
  58. scgo-0.1.0/scgo/database/transactions.py +51 -0
  59. scgo-0.1.0/scgo/exceptions.py +64 -0
  60. scgo-0.1.0/scgo/initialization/__init__.py +71 -0
  61. scgo-0.1.0/scgo/initialization/atomic_radii.py +193 -0
  62. scgo-0.1.0/scgo/initialization/candidate_discovery.py +285 -0
  63. scgo-0.1.0/scgo/initialization/geometry_helpers.py +1804 -0
  64. scgo-0.1.0/scgo/initialization/initialization_config.py +205 -0
  65. scgo-0.1.0/scgo/initialization/initializers.py +1395 -0
  66. scgo-0.1.0/scgo/initialization/random_spherical.py +1091 -0
  67. scgo-0.1.0/scgo/initialization/seed_combiners.py +238 -0
  68. scgo-0.1.0/scgo/initialization/steric_scoring.py +51 -0
  69. scgo-0.1.0/scgo/initialization/strategy_allocation.py +224 -0
  70. scgo-0.1.0/scgo/initialization/templates.py +1847 -0
  71. scgo-0.1.0/scgo/minima_search/__init__.py +10 -0
  72. scgo-0.1.0/scgo/minima_search/core.py +962 -0
  73. scgo-0.1.0/scgo/param_presets.py +569 -0
  74. scgo-0.1.0/scgo/runner_api.py +1511 -0
  75. scgo-0.1.0/scgo/surface/__init__.py +63 -0
  76. scgo-0.1.0/scgo/surface/composition.py +12 -0
  77. scgo-0.1.0/scgo/surface/config.py +161 -0
  78. scgo-0.1.0/scgo/surface/constraints.py +184 -0
  79. scgo-0.1.0/scgo/surface/deposition.py +618 -0
  80. scgo-0.1.0/scgo/surface/fragment_templates.py +39 -0
  81. scgo-0.1.0/scgo/surface/objectives.py +21 -0
  82. scgo-0.1.0/scgo/surface/pbc.py +53 -0
  83. scgo-0.1.0/scgo/surface/presets.py +108 -0
  84. scgo-0.1.0/scgo/surface/validation.py +434 -0
  85. scgo-0.1.0/scgo/system_types.py +658 -0
  86. scgo-0.1.0/scgo/ts_search/__init__.py +31 -0
  87. scgo-0.1.0/scgo/ts_search/parallel_neb.py +412 -0
  88. scgo-0.1.0/scgo/ts_search/transition_state.py +1479 -0
  89. scgo-0.1.0/scgo/ts_search/transition_state_io.py +571 -0
  90. scgo-0.1.0/scgo/ts_search/transition_state_run.py +936 -0
  91. scgo-0.1.0/scgo/ts_search/ts_network.py +708 -0
  92. scgo-0.1.0/scgo/ts_search/ts_statistics.py +42 -0
  93. scgo-0.1.0/scgo/utils/__init__.py +53 -0
  94. scgo-0.1.0/scgo/utils/atoms_helpers.py +21 -0
  95. scgo-0.1.0/scgo/utils/comparators.py +255 -0
  96. scgo-0.1.0/scgo/utils/diversity_scorer.py +188 -0
  97. scgo-0.1.0/scgo/utils/fitness_strategies.py +106 -0
  98. scgo-0.1.0/scgo/utils/helpers.py +806 -0
  99. scgo-0.1.0/scgo/utils/logging.py +121 -0
  100. scgo-0.1.0/scgo/utils/mlip_extras.py +42 -0
  101. scgo-0.1.0/scgo/utils/mutation_weights.py +377 -0
  102. scgo-0.1.0/scgo/utils/optimizer_utils.py +42 -0
  103. scgo-0.1.0/scgo/utils/parallel_workers.py +25 -0
  104. scgo-0.1.0/scgo/utils/rng_helpers.py +78 -0
  105. scgo-0.1.0/scgo/utils/run_helpers.py +530 -0
  106. scgo-0.1.0/scgo/utils/run_tracking.py +196 -0
  107. scgo-0.1.0/scgo/utils/runtime_warnings.py +22 -0
  108. scgo-0.1.0/scgo/utils/timing_report.py +82 -0
  109. scgo-0.1.0/scgo/utils/torchsim_policy.py +91 -0
  110. scgo-0.1.0/scgo/utils/ts_provenance.py +48 -0
  111. scgo-0.1.0/scgo/utils/ts_runner_kwargs.py +133 -0
  112. scgo-0.1.0/scgo/utils/validation.py +175 -0
  113. scgo-0.1.0/scgo.egg-info/PKG-INFO +509 -0
  114. scgo-0.1.0/scgo.egg-info/SOURCES.txt +238 -0
  115. scgo-0.1.0/scgo.egg-info/dependency_links.txt +1 -0
  116. scgo-0.1.0/scgo.egg-info/requires.txt +25 -0
  117. scgo-0.1.0/scgo.egg-info/top_level.txt +6 -0
  118. scgo-0.1.0/setup.cfg +4 -0
  119. scgo-0.1.0/tests/__init__.py +0 -0
  120. scgo-0.1.0/tests/algorithms/__init__.py +0 -0
  121. scgo-0.1.0/tests/algorithms/test_adsorbate_ga_acceptance.py +210 -0
  122. scgo-0.1.0/tests/algorithms/test_adsorbate_operator_weights.py +111 -0
  123. scgo-0.1.0/tests/algorithms/test_algorithms_ga_common.py +50 -0
  124. scgo-0.1.0/tests/algorithms/test_core_adsorbate_ga_tags.py +151 -0
  125. scgo-0.1.0/tests/algorithms/test_edge_cases.py +300 -0
  126. scgo-0.1.0/tests/algorithms/test_ga_operator_acceptance.py +554 -0
  127. scgo-0.1.0/tests/algorithms/test_geneticalgorithm_generational.py +379 -0
  128. scgo-0.1.0/tests/algorithms/test_geneticalgorithm_logging.py +59 -0
  129. scgo-0.1.0/tests/algorithms/test_reproducibility.py +1014 -0
  130. scgo-0.1.0/tests/algorithms/test_validation.py +915 -0
  131. scgo-0.1.0/tests/ase_ga_patches/__init__.py +0 -0
  132. scgo-0.1.0/tests/ase_ga_patches/test_ase_ga_patches.py +476 -0
  133. scgo-0.1.0/tests/ase_ga_patches/test_ga_mutations.py +201 -0
  134. scgo-0.1.0/tests/ase_ga_patches/test_ga_pairing.py +160 -0
  135. scgo-0.1.0/tests/ase_ga_patches/test_population_selection.py +73 -0
  136. scgo-0.1.0/tests/ase_ga_patches/test_retry_reduction.py +560 -0
  137. scgo-0.1.0/tests/ase_ga_patches/test_surface_coherence.py +418 -0
  138. scgo-0.1.0/tests/benchmarks/__init__.py +0 -0
  139. scgo-0.1.0/tests/benchmarks/test_benchmarks.py +103 -0
  140. scgo-0.1.0/tests/calculators/__init__.py +0 -0
  141. scgo-0.1.0/tests/calculators/test_calculators.py +240 -0
  142. scgo-0.1.0/tests/calculators/test_torchsim_fixatoms_mapping.py +45 -0
  143. scgo-0.1.0/tests/calculators/test_torchsim_helpers.py +393 -0
  144. scgo-0.1.0/tests/calculators/test_uma_helpers.py +66 -0
  145. scgo-0.1.0/tests/cluster_adsorbate/test_fragment_reposition.py +83 -0
  146. scgo-0.1.0/tests/cluster_adsorbate/test_frozen_adsorbate_geometry.py +109 -0
  147. scgo-0.1.0/tests/cluster_adsorbate/test_general_adsorbate.py +172 -0
  148. scgo-0.1.0/tests/cluster_adsorbate/test_multi_fragment_placement.py +83 -0
  149. scgo-0.1.0/tests/cluster_adsorbate/test_multi_fragment_site_metadata.py +44 -0
  150. scgo-0.1.0/tests/cluster_adsorbate/test_oh_on_pt_cluster.py +137 -0
  151. scgo-0.1.0/tests/cluster_adsorbate/test_placement_heuristics.py +70 -0
  152. scgo-0.1.0/tests/cluster_adsorbate/test_site_diversity.py +81 -0
  153. scgo-0.1.0/tests/conftest.py +253 -0
  154. scgo-0.1.0/tests/constants.py +41 -0
  155. scgo-0.1.0/tests/database/__init__.py +0 -0
  156. scgo-0.1.0/tests/database/test_database_core.py +1316 -0
  157. scgo-0.1.0/tests/database/test_database_metadata_adapter.py +93 -0
  158. scgo-0.1.0/tests/database/test_initialization_cache.py +105 -0
  159. scgo-0.1.0/tests/database/test_mark_final_minima.py +125 -0
  160. scgo-0.1.0/tests/database/test_mark_final_minima_dbpaths.py +60 -0
  161. scgo-0.1.0/tests/database/test_parallel_worker_ase_compat.py +45 -0
  162. scgo-0.1.0/tests/database/test_persist_provenance.py +34 -0
  163. scgo-0.1.0/tests/database/test_registry.py +231 -0
  164. scgo-0.1.0/tests/database/test_require_json1.py +29 -0
  165. scgo-0.1.0/tests/database/test_schema_utils.py +86 -0
  166. scgo-0.1.0/tests/initialization/__init__.py +0 -0
  167. scgo-0.1.0/tests/initialization/test_atomic_radii.py +59 -0
  168. scgo-0.1.0/tests/initialization/test_atomic_radii_blmin.py +23 -0
  169. scgo-0.1.0/tests/initialization/test_batch_initialization.py +513 -0
  170. scgo-0.1.0/tests/initialization/test_composition_matching.py +103 -0
  171. scgo-0.1.0/tests/initialization/test_connectivity.py +328 -0
  172. scgo-0.1.0/tests/initialization/test_geometry_helpers.py +709 -0
  173. scgo-0.1.0/tests/initialization/test_init_canonical_mtime.py +68 -0
  174. scgo-0.1.0/tests/initialization/test_init_common.py +1559 -0
  175. scgo-0.1.0/tests/initialization/test_init_logging.py +27 -0
  176. scgo-0.1.0/tests/initialization/test_init_random_spherical.py +249 -0
  177. scgo-0.1.0/tests/initialization/test_init_seed_growth.py +630 -0
  178. scgo-0.1.0/tests/initialization/test_init_smart.py +470 -0
  179. scgo-0.1.0/tests/initialization/test_init_template.py +333 -0
  180. scgo-0.1.0/tests/initialization/test_initialization_modes.py +312 -0
  181. scgo-0.1.0/tests/initialization/test_mixed_compositions.py +136 -0
  182. scgo-0.1.0/tests/initialization/test_parameter_sensitivity.py +335 -0
  183. scgo-0.1.0/tests/initialization/test_path_prefilter.py +27 -0
  184. scgo-0.1.0/tests/initialization/test_seed_combiners.py +395 -0
  185. scgo-0.1.0/tests/initialization/test_template_discovery_logs.py +41 -0
  186. scgo-0.1.0/tests/initialization/test_template_facet_vertex.py +193 -0
  187. scgo-0.1.0/tests/initialization/test_templates.py +753 -0
  188. scgo-0.1.0/tests/integration/__init__.py +0 -0
  189. scgo-0.1.0/tests/integration/test_integration.py +759 -0
  190. scgo-0.1.0/tests/integration/test_main_final_tagging.py +177 -0
  191. scgo-0.1.0/tests/integration/test_run_api.py +1009 -0
  192. scgo-0.1.0/tests/integration/test_run_go_surface.py +65 -0
  193. scgo-0.1.0/tests/integration/test_runners_emulation.py +70 -0
  194. scgo-0.1.0/tests/minima_search/__init__.py +0 -0
  195. scgo-0.1.0/tests/minima_search/test_minima_search.py +875 -0
  196. scgo-0.1.0/tests/minima_search/test_output.py +485 -0
  197. scgo-0.1.0/tests/minima_search/test_run_tracking.py +511 -0
  198. scgo-0.1.0/tests/param_presets/__init__.py +0 -0
  199. scgo-0.1.0/tests/param_presets/test_param_presets.py +367 -0
  200. scgo-0.1.0/tests/param_presets/test_param_presets_and_run_helpers.py +501 -0
  201. scgo-0.1.0/tests/surface/__init__.py +1 -0
  202. scgo-0.1.0/tests/surface/test_hierarchical_deposition.py +189 -0
  203. scgo-0.1.0/tests/surface/test_mobile_symbol_validation.py +107 -0
  204. scgo-0.1.0/tests/surface/test_slab_ga_metadata.py +42 -0
  205. scgo-0.1.0/tests/surface/test_slab_ordering_contract.py +125 -0
  206. scgo-0.1.0/tests/surface/test_slab_pbc.py +49 -0
  207. scgo-0.1.0/tests/surface/test_supported_cluster_binding.py +355 -0
  208. scgo-0.1.0/tests/surface/test_surface_constraints.py +197 -0
  209. scgo-0.1.0/tests/surface/test_surface_deposition.py +324 -0
  210. scgo-0.1.0/tests/surface/test_surface_ga_smoke.py +51 -0
  211. scgo-0.1.0/tests/surface/test_surface_ga_torchsim.py +156 -0
  212. scgo-0.1.0/tests/test_optimization_algorithm_select.py +19 -0
  213. scgo-0.1.0/tests/test_optional_extras_smoke.py +17 -0
  214. scgo-0.1.0/tests/test_runner_surface.py +85 -0
  215. scgo-0.1.0/tests/test_utils.py +780 -0
  216. scgo-0.1.0/tests/ts_search/__init__.py +0 -0
  217. scgo-0.1.0/tests/ts_search/test_neb_blockwise_alignment.py +94 -0
  218. scgo-0.1.0/tests/ts_search/test_parallel_neb.py +292 -0
  219. scgo-0.1.0/tests/ts_search/test_surface_neb_alignment.py +500 -0
  220. scgo-0.1.0/tests/ts_search/test_ts_final_minima_integration.py +212 -0
  221. scgo-0.1.0/tests/ts_search/test_ts_integration.py +1001 -0
  222. scgo-0.1.0/tests/ts_search/test_ts_integration_cu4_mace.py +564 -0
  223. scgo-0.1.0/tests/ts_search/test_ts_interpolation_mic.py +212 -0
  224. scgo-0.1.0/tests/ts_search/test_ts_network.py +395 -0
  225. scgo-0.1.0/tests/ts_search/test_ts_postprocessing.py +964 -0
  226. scgo-0.1.0/tests/ts_search/test_ts_robustness.py +306 -0
  227. scgo-0.1.0/tests/ts_search/test_ts_search.py +1027 -0
  228. scgo-0.1.0/tests/ts_search/test_ts_search_forces_failures.py +69 -0
  229. scgo-0.1.0/tests/utils/__init__.py +0 -0
  230. scgo-0.1.0/tests/utils/test_atoms_helpers.py +115 -0
  231. scgo-0.1.0/tests/utils/test_diversity_scorer.py +168 -0
  232. scgo-0.1.0/tests/utils/test_fitness_strategies.py +237 -0
  233. scgo-0.1.0/tests/utils/test_helpers.py +492 -0
  234. scgo-0.1.0/tests/utils/test_is_true_minimum.py +335 -0
  235. scgo-0.1.0/tests/utils/test_logging_trace_method.py +24 -0
  236. scgo-0.1.0/tests/utils/test_mutation_weights.py +233 -0
  237. scgo-0.1.0/tests/utils/test_optimizer_utils.py +90 -0
  238. scgo-0.1.0/tests/utils/test_rng_helpers.py +208 -0
  239. scgo-0.1.0/tests/utils/test_torchsim_policy.py +117 -0
  240. scgo-0.1.0/tests/utils/test_verbosity.py +247 -0
scgo-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 R. Laplaza
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
scgo-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,509 @@
1
+ Metadata-Version: 2.4
2
+ Name: scgo
3
+ Version: 0.1.0
4
+ Summary: A modern Python package for global optimization of atomic clusters using ASE with Basin Hopping and Genetic Algorithms. Features clean code, comprehensive testing, and support for multiple energy calculators.
5
+ Author-email: "R. Laplaza" <ruben.laplaza@iiq.csic.es>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/rlaplaza-lab/scgo
8
+ Project-URL: Documentation, https://scgo.readthedocs.io/
9
+ Project-URL: Repository, https://github.com/rlaplaza-lab/scgo
10
+ Project-URL: Issues, https://github.com/rlaplaza-lab/scgo/issues
11
+ Keywords: computational-chemistry,structure-optimization,atomic-clusters,basin-hopping,genetic-algorithm,ase,mace,uma,fairchem
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
20
+ Classifier: Topic :: Scientific/Engineering :: Physics
21
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
22
+ Requires-Python: >=3.12
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: ase>=3.22.0
26
+ Requires-Dist: ase-ga>=0.1.0
27
+ Requires-Dist: numpy>=2.2
28
+ Requires-Dist: scipy<3,>=1.14
29
+ Requires-Dist: tqdm>=4.60.0
30
+ Provides-Extra: mace
31
+ Requires-Dist: e3nn==0.4.4; extra == "mace"
32
+ Requires-Dist: mace-torch==0.3.16; extra == "mace"
33
+ Requires-Dist: nvalchemi-toolkit-ops==0.3.1; extra == "mace"
34
+ Requires-Dist: nvidia-nccl-cu12>=2.28; extra == "mace"
35
+ Requires-Dist: torch<2.13,>=2.12.0; extra == "mace"
36
+ Requires-Dist: torch-sim-atomistic[mace]==0.6.0; extra == "mace"
37
+ Provides-Extra: uma
38
+ Requires-Dist: fairchem-core>=2.19.0; extra == "uma"
39
+ Requires-Dist: torch-sim-atomistic[fairchem]==0.6.0; extra == "uma"
40
+ Provides-Extra: dev
41
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
42
+ Requires-Dist: pytest-xdist>=3.0.0; extra == "dev"
43
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
44
+ Requires-Dist: psutil>=7.0.0; extra == "dev"
45
+ Requires-Dist: ruff>=0.6.0; extra == "dev"
46
+ Requires-Dist: pre-commit>=3.0.0; extra == "dev"
47
+ Dynamic: license-file
48
+
49
+ # SCGO: Simple Cluster Global Optimization
50
+
51
+ [![Python](https://img.shields.io/badge/python-3.12%2B-blue.svg)](https://www.python.org/downloads/) [![PyPI](https://img.shields.io/pypi/v/scgo.svg)](https://pypi.org/project/scgo/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
52
+
53
+ ![SCGO Logo](docs/source/_static/scgo_logo.svg)
54
+
55
+ A compact toolkit for global optimization of atomic clusters using ASE. SCGO provides a focused API for Basin Hopping (BH) and Genetic Algorithm (GA) workflows with practical defaults.
56
+
57
+ **Documentation**: Comprehensive API documentation is available in the `docs/` directory. For online documentation, see [ReadTheDocs](https://scgo.readthedocs.io/).
58
+
59
+ ## Install
60
+
61
+ SCGO has a small core dependency set plus two mutually exclusive MLIP extras:
62
+
63
+ - `[mace]` for MACE + TorchSim + `nvalchemi-toolkit-ops`
64
+ - `[uma]` for `fairchem-core` UMA checkpoints
65
+
66
+ Install only one of `[mace]` or `[uma]` per environment.
67
+
68
+ **From PyPI (recommended):**
69
+
70
+ ```bash
71
+ pip install "scgo[mace]" # or: pip install "scgo[uma]"
72
+ ```
73
+
74
+ For development or editable installs from source, clone the repository and use `pip install -e ".[mace]"` (see [installation docs](https://scgo.readthedocs.io/en/latest/installation.html)).
75
+
76
+ Conda (full dev stack from source):
77
+
78
+ ```bash
79
+ git clone https://github.com/rlaplaza-lab/scgo.git
80
+ cd scgo
81
+ conda env create -f environment.yml
82
+ conda activate scgo
83
+ ```
84
+
85
+ `environment.yml` installs the package editable with **`[mace,dev]`** (MACE/TorchSim + test/lint tooling).
86
+
87
+ The conda env uses `torch-sim-atomistic[mace]` with `nvalchemi-toolkit-ops` for TorchSim neighbor lists. Do not install `vesin` or `vesin-torch`—they conflict with the TorchSim stack we use.
88
+
89
+ Note: SCGO requires SQLite with the JSON1 extension (for `json_extract` and related functions). If you installed using conda, ensure `sqlite` from `conda-forge` is available in your environment (e.g., `conda install -c conda-forge sqlite`). If you use pip-only installs, consider installing `pysqlite3-binary` (e.g., `pip install pysqlite3-binary`) so that the Python `sqlite3` module exposes JSON1. This repository's CI enforces JSON1 availability.
90
+
91
+ Sella is not required by the core SCGO package and has been removed from the default pip constraints to avoid heavy native builds during dependency resolution. If you need Sella for advanced optimization features, install it manually (it builds C extensions and may require a C toolchain and Cython).
92
+
93
+ Editable install from source (alternative):
94
+
95
+ ```bash
96
+ git clone https://github.com/rlaplaza-lab/scgo.git
97
+ cd scgo
98
+ pip install -e ".[mace]" # or: pip install -e ".[uma]"
99
+ ```
100
+
101
+ For pip installs, the same TorchSim stack applies: ensure `nvalchemi-toolkit-ops` is available; uninstall `vesin` and `vesin-torch` if you see TorchSim-related errors.
102
+
103
+ Dependency note: SCGO now allows `scipy>=1.14,<3` so the UMA/fairchem extra can resolve cleanly with `torch-sim-atomistic[fairchem]` (which constrains SciPy to `<1.17` in current releases).
104
+
105
+ For development with tests and linting (after a **runtime-only** `pip install -e .`):
106
+
107
+ ```bash
108
+ pip install -e ".[mace,dev]" # or UMA: pip install -e ".[uma,dev]"
109
+ pre-commit install
110
+ ```
111
+
112
+ ### Running on HPC (Slurm, shared filesystem)
113
+
114
+ - **SQLite**: SCGO keeps WAL mode off by default (fewer `-wal`/`-shm` issues on Lustre/GPFS/NFS). Prefer writing active `*.db` files under job-local scratch (`$SLURM_TMPDIR` or site-specific scratch) when you can, then copying results back to project storage.
115
+ - **Parallel jobs**: SCGO creates unique `run_<timestamp>_<microseconds>` folders, so jobs sharing a parent output directory usually write different DB files. Lock contention is still possible if jobs touch the same `*.db` (for example, reused explicit `run_id`/path) or if shared filesystems serialize lock files; for high parallelism, prefer one output directory per job.
116
+ - **Registry**: Discovery may write `.scgo_db_registry.json` and `.scgo_db_registry.lock` (with `flock` on Linux) for fast DB listing. When your run lives under a directory whose name ends in `_searches`, the index is kept at that parent only (not beside every `trial_*` folder). If your filesystem does not honor `flock`, use separate output directories per job or avoid parallel registry updates.
117
+ - **Logging**: Batch-friendly defaults suppress noisy third-party loggers. For local debugging, set `SCGO_LOCAL_DEV=1` or call `configure_logging(..., hpc_mode=False)`.
118
+
119
+ ---
120
+
121
+ ## Documentation
122
+
123
+ Comprehensive documentation is available in the `docs/` directory:
124
+
125
+ - **Installation**: `docs/source/installation.rst` - Setup instructions for conda and pip
126
+ - **Quick Start**: `docs/source/quickstart.rst` - Basic usage examples and workflows
127
+ - **API Reference**:
128
+ - `docs/source/api/runner_api.rst` - High-level API entry points
129
+ - `docs/source/api/surface.rst` - Slab configuration and deposition
130
+ - `docs/source/api/cluster_adsorbate.rst` - Adsorbate placement and GA repositioning
131
+ - `docs/source/api/param_presets.rst` - Parameter presets
132
+ - `docs/source/api/system_types.rst` - System type definitions
133
+
134
+ To build the documentation locally:
135
+
136
+ ```bash
137
+ pip install -e .
138
+ pip install -r docs/source/requirements.txt
139
+ cd docs && make html
140
+ ```
141
+
142
+ The built documentation will be available in `docs/build/html/index.html`.
143
+
144
+ ---
145
+
146
+ ## Quick start
147
+
148
+ ```python
149
+ from scgo import run_go
150
+ from scgo.param_presets import get_testing_params
151
+ results = run_go(
152
+ ["Pt"] * 4,
153
+ params=get_testing_params(),
154
+ seed=42,
155
+ system_type="gas_cluster",
156
+ )
157
+ ```
158
+
159
+ - `results` is a list of `(energy, Atoms)` for unique minima (sorted by energy by default).
160
+ - Sequential multi-composition GO uses `run_go_campaign([...], system_type=...)` from [`scgo.runner_api`](scgo/runner_api.py) (also re-exported from `scgo`).
161
+
162
+ ### Explicit system types
163
+
164
+ SCGO supports exactly four explicit `system_type` values:
165
+
166
+ - `gas_cluster`: gas-phase cluster (no slab, no extra adsorbate constraints)
167
+ - `surface_cluster`: cluster supported on a slab (`surface_config` required)
168
+ - `gas_cluster_adsorbate`: gas-phase cluster that includes adsorbate-like species (no slab)
169
+ - `surface_cluster_adsorbate`: supported cluster + adsorbate species (`surface_config` required)
170
+
171
+ `system_type` must be passed to each `run_*` API call. Top-level `system_type` is rejected inside preset dicts (`go_params` / `ts_params`); use the run function argument instead. For surface workflows, `surface_config` may appear in presets (e.g. `get_torchsim_ga_params`, `get_ts_search_params`) and on the `run_*` call—values must agree when both are set.
172
+ For adsorbate system types (`gas_cluster_adsorbate`, `surface_cluster_adsorbate`),
173
+ high-level runners require core-only `composition` and `adsorbates` (one ASE `Atoms`
174
+ fragment or a list of fragments). SCGO flattens adsorbate symbols in provided fragment
175
+ order and constructs the full mobile composition as
176
+ `core_composition + flattened_adsorbate_symbols` (mobile region after any slab).
177
+ Hierarchical initialization is the only supported adsorbate layout.
178
+
179
+ ---
180
+
181
+ ## What to expect on disk (output)
182
+
183
+ When you run a search for composition `Pt4`, SCGO writes into `Pt4_searches/` with the following structure:
184
+
185
+ ### Global optimization (`{formula}_searches/`)
186
+
187
+ - `Pt4_searches/run_<YYYYMMDD_HHMMSS_ffffff>/trial_<N>/`
188
+ - `bh_go.db` or `ga_go.db` (ASE database with candidates and relaxed structures)
189
+ - `population.log` (GA runs)
190
+ - `Pt4_searches/results_summary.json` — campaign-level snapshot after the latest run. Top-level keys include:
191
+ - **Provenance** (same convention as other SCGO JSON sidecars): `schema_version` (currently **3**), `scgo_version`, `created_at` (UTC ISO8601), `python_version`
192
+ - **Run summary**: `composition` (formula string, e.g. `"Pt4"`), `total_unique_minima`, `minima_by_run` (map of `run_id` → count), `current_run_id`, `params` (JSON-safe snapshot aligned with `run_*/metadata.json`), `run_metadata_relpath` (e.g. `run_<id>/metadata.json`)
193
+ - `Pt4_searches/final_unique_minima/` — final XYZ files, named like `Pt4_minimum_01_run_YYYYMMDD_HHMMSS_ffffff_trial_1.xyz`
194
+ - `Pt4_searches/run_<...>/metadata.json` — per-run record: provenance header above plus `run_id`, `timestamp`, `composition` (symbol list), `formula`, `params`, and related run fields
195
+ - `Pt4_searches/validation/` — optional; created when `validate_with_hessian=True` to run vibrational checks
196
+ - `Pt4_searches/.scgo_db_registry.json` and `.scgo_db_registry.lock` — optional DB index and lock (see *Running on HPC* above)
197
+
198
+ Notes:
199
+ - If `clean=False`, SCGO will merge previous runs by scanning `run_*` directories and `trial_*/` DB files.
200
+ - `.db` files are ignored by the project `.gitignore`.
201
+
202
+ ### Transition state search (`ts_results_{formula}/`)
203
+
204
+ `run_ts_search` (from `scgo`, wrapping [`scgo.runner_api`](scgo/runner_api.py)) reads minima from `{formula}_searches/` (or the `output_dir` you pass) and writes **under the same tree** into a dedicated folder:
205
+
206
+ - `{formula}_searches/ts_results_{formula}/`
207
+ - **Per pair** `pair_id` (e.g. `0_1`): `ts_{pair_id}.xyz`, `reactant_{pair_id}.xyz`, `product_{pair_id}.xyz` (when geometries exist), and `neb_{pair_id}_metadata.json`
208
+ - **`ts_search_summary_{formula}.json`** — full run: provenance header, NEB settings (`calculator_name`, `neb_fmax`, `neb_steps_resolved`, `neb_backend` `torchsim` or `ase`, `use_parallel_neb`, climb/interpolation flags, image count, spring constant, etc.), `composition`, `formula`, `num_total_pairs`, `num_successful`, `num_converged`, `results` (list of per-pair records), and `statistics` (`total_ts_found`, `converged_ts`, `successful_ts`, `min_barrier` / `max_barrier` / `avg_barrier` over successes)
209
+ - **`ts_network_metadata_{formula}.json`** — graph-oriented view: `ts_connections[]` (each edge: `pair_id`, `minima_indices`, energies, `barrier_height`, optional `barrier_forward` / `barrier_reverse`, `neb_converged`, `n_images`, optional `minima_provenance`), `num_minima`, `statistics`, optional `minima_base_dir`
210
+ - **`final_unique_ts/`** — after deduplication: `final_unique_ts_summary_{formula}.json` (provenance + `unique_ts[]` with `connected_edges`, `connected_minima`, `filename`, energies, etc.) and one `.xyz` per deduplicated TS (names may include `pair_…` when a single edge maps to that file)
211
+
212
+ **Per-pair entries** in `ts_search_summary_*.json` (and overlapping fields in `neb_*_metadata.json`) typically include: `pair_id`, `status` (`success` / `failed`), `neb_converged`, `n_images`, `spring_constant`, `reactant_energy`, `product_energy`, `ts_energy`, `barrier_height`, `error`, and on success `ts_image_index`. When traceability is available, `minima_indices` and **`minima_provenance`** appear: each endpoint lists `run_id`, `trial_id`, `source_db`, `source_db_relpath`, `systems_row_id`, `confid`, `gaid`, `unique_id`, `final_id`, `energy` (see `scgo/ts_search/transition_state_io.py`).
213
+
214
+ **`neb_{pair_id}_metadata.json`** merges the provenance header with pair fields above plus, when present: `final_fmax`, `steps_taken`, `force_calls`, and NEB-parameter echoes (`use_torchsim`, `neb_backend`, `interpolation_method`, `climb`, `align_endpoints`, `perturb_sigma`, `neb_interpolation_mic`, `neb_surface_cell_remap`, `neb_surface_lattice_rotation`, `neb_surface_max_lattice_shift`, `fmax`, `neb_steps`, etc.).
215
+
216
+ ---
217
+
218
+ ## Key options (short)
219
+
220
+ - **Global optimization (`params` for `run_go` / `run_go_campaign`)** is merged with `get_default_params()` via `initialize_params`: any preset that omits keys inherits defaults. Common entry points: `get_default_params()`, `get_minimal_ga_params()`, `get_testing_params()`, `get_high_energy_params()`, `get_diversity_params()`, `get_default_uma_params()` (fairchem UMA), and `get_torchsim_ga_params(system_type=..., surface_config=..., seed=..., model_name=...)` (MACE + TorchSim GA benchmark stack; requires `scgo[mace]`).
221
+ - **Transition-state search (`ts_params` for `run_ts_search` / `run_go_ts`)** is **not** merged with GO defaults. Build a flat dict with `get_ts_search_params(...)` (e.g. `calculator="UMA"` for UMA) and pass it explicitly alongside `go_params` when using `run_go_ts` / `run_go_ts_campaign`.
222
+
223
+ **NEB endpoint alignment (on by default):** Presets set `neb_align_endpoints=True` for all system types. Before ASE path interpolation (`idpp` or `linear`), SCGO reorders product atoms to match the reactant, then rigidly aligns endpoints so interior images start from a sensible band:
224
+
225
+ - **Gas clusters** — 3D Kabsch on the mobile region (or whole structure when no slab prefix).
226
+ - **Slab / periodic systems** — lattice-compatible PBC alignment (`neb_interpolation_mic=True` on surface types): MIC-aware atom matching, collective mobile lattice-image selection, per-atom MIC snapping, optional integer in-plane lattice shifts (`neb_surface_cell_remap`, search span `neb_surface_max_lattice_shift` default `1`), and global in-plane rotation evaluated jointly with each shift (`neb_surface_lattice_rotation`). Slab/`FixAtoms` anchors stay registered; mobile atoms are not rotated independently of the lattice frame (avoids energy-inequivalent distortions).
227
+
228
+ Path interpolation always uses the **aligned** reactant and product copies as band endpoints; only interior images are filled by `NEB.interpolate`. Disable with `ts_params["neb_align_endpoints"] = False` only when you intentionally want raw GO minima as endpoints.
229
+
230
+ **Surface GO final XYZ alignment:** For `surface_cluster` and `surface_cluster_adsorbate`, before writing `final_unique_minima/*.xyz`, SCGO PBC-aligns each minimum to the lowest-energy trial using the same slab protocol as NEB (`neb_surface_cell_remap`, `neb_surface_lattice_rotation`, `neb_surface_max_lattice_shift` from optimizer kwargs, gated by `SystemPolicy`). This keeps stored frames comparable across trials; TS/NEB endpoint alignment is unchanged.
231
+
232
+ **Initialization clash factor:** Default `min_distance_factor` is **0.4** (was 0.5) in `scgo.initialization.initialization_config.MIN_DISTANCE_FACTOR_DEFAULT`; override per run if you need stricter placement.
233
+
234
+ Preset-vs-runtime split in `runner_api`:
235
+
236
+ - Put scientific/tuning knobs in preset dicts (`go_params`/`ts_params`): calculator choice, optimizer settings, NEB settings, pairing thresholds, adsorbate placement (`cluster_adsorbate_config`), connectivity (`connectivity_factor`), etc.
237
+ - Keep run-control knobs on the `run_*` call itself: `verbosity`, `output_dir`, `output_root`, `output_stem`, `seed`, `log_summary`, `write_timing_json`, `profile_ga`.
238
+ - Keep system-definition inputs on the `run_*` call itself: `system_type`, core-only `composition`, and `adsorbates` when applicable.
239
+ - For surface system types, pass `surface_config` on the `run_*` call and in preset builders (`get_torchsim_ga_params`, `get_ts_search_params`); SCGO validates coherence across GO/TS presets and run arguments.
240
+
241
+ Inspect -> edit -> run pattern:
242
+
243
+ ```python
244
+ from scgo import run_go_ts
245
+ from scgo.param_presets import get_default_params, get_ts_search_params
246
+
247
+ go_params = get_default_params()
248
+ ts_params = get_ts_search_params(system_type="gas_cluster")
249
+
250
+ print(go_params["optimizer_params"]["ga"]["niter"])
251
+ go_params["optimizer_params"]["ga"]["niter"] = 8
252
+ ts_params["max_pairs"] = 12
253
+
254
+ summary = run_go_ts(
255
+ "Pt5",
256
+ go_params=go_params,
257
+ ts_params=ts_params,
258
+ system_type="gas_cluster",
259
+ seed=7,
260
+ verbosity=1,
261
+ )
262
+ ```
263
+
264
+ After writing final XYZ files, SCGO can optionally tag the corresponding database records with metadata ("final_unique_minimum": true, "final_rank", and "final_written") so downstream tools can find final minima without re-scanning databases. This is enabled by default; disable with `params['tag_final_minima'] = False`.
265
+
266
+ - `fitness_strategy`: `low_energy` (default), `high_energy`, or `diversity`. The `diversity` strategy requires a `diversity_reference_db` glob (e.g., `"Pt*_searches/**/*.db"`).
267
+ - `validate_with_hessian` (bool): run force + Hessian checks (uses ASE vibrational analysis).
268
+ - GA backend: MLIPs use TorchSim batched GA; classical calculators use ASE GA.
269
+ - Database/perf knobs:
270
+ - `db_enable_expression_indexes` (GA/BH, default `False`): enable extra SQLite JSON expression indexes for frequent metadata predicates/sorts.
271
+ - `ga_adaptive_retry_enabled` (default `True`): adapt offspring attempt budget to recent acceptance rate instead of fixed `10*n_offspring`.
272
+ - `ga_retry_floor_multiplier` / `ga_retry_ceiling_multiplier` (defaults `4` / `15`): lower/upper bounds for adaptive retry budget.
273
+ - `ga_fast_prefilter_enabled` (default `True`): cheap severe-clash prefilter before full system-type validation.
274
+ - `write_timing_json=True` includes per-run retry failure counters (`retry_failures`) and per-generation acceptance/failure breakdown in detailed mode.
275
+
276
+ ---
277
+
278
+ ## Surface workflows (supported clusters)
279
+
280
+ SCGO can run **genetic-algorithm** global optimization for a small **adsorbate cluster** on a periodic **slab**. The GA explores the adsorbate degrees of freedom (`composition`); the slab supplies the cell and controls which substrate atoms move during **local** relaxations via [`SurfaceSystemConfig`](scgo/surface/config.py) (`FixAtoms` under the hood, including on the TorchSim GA path).
281
+
282
+ ### How to run
283
+
284
+ Build (or load) any ASE `Atoms` slab and pass it through the generic surface helper:
285
+
286
+ ```python
287
+ from ase.build import fcc111
288
+ from scgo.surface import make_surface_config
289
+
290
+ slab = fcc111("Pt", size=(3, 3, 3), vacuum=10.0)
291
+ surface_config = make_surface_config(slab)
292
+ ```
293
+
294
+ For the **graphite preset** used in example runners, use [`scgo.surface.make_graphite_surface_config`](scgo/surface/presets.py) (or `from scgo import make_graphite_surface_config`) instead of building a slab by hand.
295
+
296
+ Then build GO/TS presets and pass the same `surface_config` to the runner:
297
+
298
+ ```python
299
+ from scgo.param_presets import get_torchsim_ga_params, get_ts_search_params
300
+ from scgo import run_go_ts
301
+
302
+ go_params = get_torchsim_ga_params(
303
+ system_type="surface_cluster",
304
+ surface_config=surface_config,
305
+ seed=42,
306
+ )
307
+ ts_params = get_ts_search_params(
308
+ system_type="surface_cluster",
309
+ surface_config=surface_config,
310
+ seed=42,
311
+ )
312
+ ```
313
+
314
+ For the bundled graphite preset, `make_graphite_surface_config(slab_layers=3)` controls slab thickness (see `examples/example_pt5_graphite.py`).
315
+
316
+ - **Direct API** (any adsorbate size): `from scgo import ga_go, SurfaceSystemConfig` and pass `surface_config=...`.
317
+ - **`run_go`**: pass `surface_config=...` directly to `run_go(...)`; it is copied into each **present** `optimizer_params` entry among `simple` / `bh` / `ga` so the active algorithm sees the slab. Automatic algorithm choice follows mobile atom count (see **Algorithm selection** under Global optimization).
318
+ - For slab workflows, choose `system_type="surface_cluster"` (supported cluster only) or `system_type="surface_cluster_adsorbate"` (supported cluster with explicit adsorbate-mode policies). Use `scgo.surface.make_surface_config` for a custom ASE slab; use `scgo.surface.make_graphite_surface_config` for the bundled graphite template.
319
+
320
+ Adsorbate inputs and initial structures: For both `gas_cluster_adsorbate` and `surface_cluster_adsorbate`, use core-only `composition` plus `adsorbates` as the primary API (`Atoms` for one fragment, or `list[Atoms]` for multiple fragments). SCGO derives a strict mobile partition in order (`core_symbols == composition`, then flattened adsorbate symbols); slab atoms are not part of `composition`. SCGO uses hierarchical initialization only: build the core, place rigid fragment(s) on convex-hull adsorption sites (vertex/edge/facet), then (for surface) deposit the combined cluster on the slab. Placement ranks candidate poses by steric deficit (covalent-radius `blmin`) and progressively relaxes height/clash thresholds on retry. Optional fragment placement and validation tuning lives in `go_params` (`cluster_adsorbate_config=ClusterAdsorbateConfig(...)`, or set `connectivity_factor` alone for the common case). Use `scgo.surface.describe_surface_config` to log effective slab and height settings. GA and basin-hopping attach `n_core_atoms` and per-role symbol JSON in metadata for round-trip checks (including fragment-length metadata for multi-fragment adsorbates). When adsorbate metadata is present, [`validate_structure_for_system_type`](scgo/system_types.py) also asserts that the mobile region's chemical symbols match `core_symbols + adsorbate_symbols` in order (in addition to geometry checks). Input `adsorbates` fragments are validated to be connected geometries. `adsorbate_definition['adsorbate_fragment_lengths']` is optional for manual definitions: when set, integrity is enforced per fragment; when omitted, integrity falls back to the full adsorbate block as one connected subgraph. Set `freeze_adsorbate_internal_geometry=True` in GO params for strict template rigidity (Kabsch restore after mutations); the default (`False`) still preserves intra-fragment bonds via tag-rigid GA operators.
321
+
322
+ ### Adsorbate GA behavior (`*_adsorbate`)
323
+
324
+ For adsorbate system types, the GA uses ASE tags to partition the mobile region: **core** (tag `0`) vs **adsorbate fragments** (tags `1..N`).
325
+
326
+ | Mechanism | Behavior |
327
+ |-----------|----------|
328
+ | Crossover | Cut-and-splice on the **core only**; adsorbate fragments stay on parent 0. |
329
+ | Rattle / overlap relief | Tag-rigid: each fragment moves as a unit (intra-fragment geometry preserved). |
330
+ | Rotational / mirror / flattening / breathing | Core-targeted variants (`*_core`); adsorbate distortions omitted or scoped to adsorbate tags when freeze is off. |
331
+ | `fragment_reposition` | Re-place one adsorbate fragment on fresh hull sites (same placement engine as init). |
332
+ | `in_plane_slide` | Surface-only; core and adsorbate variants (`in_plane_slide_core`, `in_plane_slide_ads`). |
333
+ | Validation | `enforce_adsorbate_subgraph_integrity=True` (default) rejects dissociated fragments post-operator and post-relax. |
334
+
335
+ Clash tables (`blmin`) and placement use gap-filled covalent radii via [`build_blmin`](scgo/initialization/atomic_radii.py) (`BLMIN_RATIO_DEFAULT=0.7`). Structure validation uses `connectivity_factor` (default `1.4`) — typically stricter than operator sterics, so borderline disconnections are caught at validation rather than during mutation.
336
+
337
+ ### Slab motion during local relaxation
338
+
339
+ | Mode | Settings |
340
+ |------|----------|
341
+ | Entire slab frozen | `fix_all_slab_atoms=True` (default) |
342
+ | Relax only the top **N** slab layers (along `surface_normal_axis`) | `fix_all_slab_atoms=False`, `n_relax_top_slab_layers=N` |
343
+ | Same intent, using bottom layer count | `fix_all_slab_atoms=False`, `n_fix_bottom_slab_layers=L - N` where `L` is the number of distinct slab layers along that axis |
344
+ | Slab fully free to relax | `fix_all_slab_atoms=False` and leave `n_relax_top_slab_layers` and `n_fix_bottom_slab_layers` unset (`None`) |
345
+
346
+ Do not set `n_relax_top_slab_layers` together with `n_fix_bottom_slab_layers`, or together with `fix_all_slab_atoms=True`. For typical `ase.build.fcc111` slabs with vacuum along **z**, use `surface_normal_axis=2` (the default).
347
+
348
+ Run metadata records a JSON-safe summary of these flags (no embedded `Atoms`) under the sanitized `surface_config` key.
349
+
350
+ ### Surface mobile connectivity (validation)
351
+
352
+ For `surface_cluster` and `surface_cluster_adsorbate`, GO/GA/BH and TS validate that the mobile region is slab-bound. Defaults in `get_default_params()` and `get_ts_search_params()`:
353
+
354
+ | Flag | Default | Effect when `True` |
355
+ |------|---------|-------------------|
356
+ | `allow_cluster_fragmentation` | `False` | Multiple disconnected core/mixed mobile subgroups allowed (each must touch the slab). |
357
+ | `allow_adsorbate_surface_detachment` | `False` | Adsorbate-only mobile subgroups on the slab without cluster contact (requires exactly one core/mixed subgroup when fragmentation is off). |
358
+ | `enforce_adsorbate_subgraph_integrity` | `True` | Keep adsorbate subgraphs connected (non-dissociative). With `adsorbate_fragment_lengths`, this is per fragment; otherwise it applies to the whole adsorbate block. External bonds to core/other fragments are still allowed. |
359
+
360
+ **Typical modes:** both `False` (strict single connected mobile cluster); fragmentation only (`True`, `False`); both `True` (any mobile split, each subgroup slab-connected). For `surface_cluster_adsorbate`, core vs adsorbate subgroups are classified using `adsorbate_definition['core_symbols']`.
361
+
362
+ **Breaking rename:** `allow_dissociative_adsorption` was removed. Migration:
363
+
364
+ | Old | New |
365
+ |-----|-----|
366
+ | `False` | `allow_cluster_fragmentation=False`, `allow_adsorbate_surface_detachment=False` |
367
+ | `True` | both flags `True` |
368
+ | (no old equivalent) | fragmentation only or detachment only — use the partial combos above |
369
+
370
+ **TS pair selection:** When `surface_config` is set, structural similarity and pair filtering use `n_slab=len(slab)` so displacements in frozen slab atoms alone do not create spurious distinct-minima pairs.
371
+
372
+ ---
373
+
374
+ ## Testing
375
+
376
+ ```bash
377
+ # Fast default
378
+ pytest tests/ -m "not slow"
379
+
380
+ # Integration-only
381
+ pytest tests/ -m integration
382
+
383
+ # Slow-only
384
+ pytest tests/ -m slow
385
+ ```
386
+
387
+ Fast EMT "benchmark" smoke tests (initialization and dimers) live under [`tests/benchmarks/`](tests/benchmarks/); long MLIP regression sweeps live under the top-level [`benchmark/`](benchmark/) package (see [`benchmark/README.md`](benchmark/README.md)).
388
+
389
+ For long GA/TorchSim tests, run in foreground with live output (`-s`) and an explicit timeout to avoid "looks stalled" sessions:
390
+
391
+ ```bash
392
+ timeout 5400 pytest tests/ -m "not slow" -vv -s
393
+ ```
394
+
395
+ ---
396
+
397
+ ## High-Level API
398
+
399
+ Canonical workflow entry points are defined in [`scgo/runner_api.py`](scgo/runner_api.py) and imported from the `scgo` package. Composition arguments may be a **formula string** (`"Pt3Au"`), a **symbol list**, or **`ase.Atoms`** (only symbols are used for GO).
400
+
401
+ ### Global optimization
402
+
403
+ #### `run_go(composition, params=None, seed=None, ...)`
404
+
405
+ Single composition; returns a list of `(energy, Atoms)` unique minima.
406
+
407
+ ```python
408
+ from scgo import run_go
409
+ from scgo.param_presets import get_default_params
410
+
411
+ results = run_go(
412
+ ["Pt", "Pt", "Pt", "Pt"],
413
+ params=get_default_params(),
414
+ seed=42,
415
+ verbosity=1,
416
+ clean=False,
417
+ output_dir=None,
418
+ system_type="gas_cluster",
419
+ )
420
+ ```
421
+
422
+ **Algorithm selection** (mobile atom count): 1–2 → simple (plain `gas_cluster` only); 3 → basin hopping; 4+ → genetic algorithm. Adsorbate system types skip `simple` (two-atom mobile regions use GA). For basin hopping and surface adsorbate runs, `scgo` builds hierarchical initial structures from `adsorbate_fragment_template` and reads `adsorbate_definition` / `cluster_adsorbate_config` from `go_params`; init-only keys (fragment template, placement glob, etc.) are not forwarded to the algorithm entry point.
423
+
424
+ #### `run_go_campaign(compositions, ..., system_type=...)`
425
+
426
+ Run GO for each composition **sequentially**; returns `dict[formula, list[(energy, Atoms)]]`.
427
+
428
+ For element or binary size scans, build composition lists with helpers from `scgo.runner_api`, then pass them to `run_go_campaign`:
429
+
430
+ ```python
431
+ from scgo import run_go_campaign
432
+ from scgo.param_presets import get_testing_params
433
+ from scgo.runner_api import build_one_element_compositions, build_two_element_compositions
434
+
435
+ params = get_testing_params()
436
+ pt_scan = build_one_element_compositions("Pt", min_atoms=2, max_atoms=6)
437
+ au_pt_scan = build_two_element_compositions("Au", "Pt", min_atoms=2, max_atoms=4)
438
+ results = run_go_campaign(pt_scan, params=params, seed=42, system_type="gas_cluster")
439
+ ```
440
+
441
+ ### Transition state search
442
+
443
+ `run_ts_search` and `run_ts_campaign` take a **flat `ts_params` dict** from [`get_ts_search_params`](scgo/param_presets.py) (or edit a copy). TorchSim use is resolved from the calculator; pass `system_type` on the `run_*` call.
444
+
445
+ Per-system NEB defaults from `get_ts_search_params` include:
446
+
447
+ | Key | Gas types | Surface types |
448
+ |-----|-----------|---------------|
449
+ | `neb_align_endpoints` | `True` | `True` |
450
+ | `neb_interpolation_mic` | `False` | `True` (forced by policy) |
451
+ | `neb_surface_cell_remap` | `False` | `True` |
452
+ | `neb_surface_lattice_rotation` | `False` | `True` |
453
+ | `neb_surface_max_lattice_shift` | `1` | `1` |
454
+
455
+ For `*_adsorbate` runs, pass `adsorbates=` to `run_go_ts` so TS can use blockwise slab / core / adsorbate endpoint matching when alignment is enabled.
456
+
457
+ ```python
458
+ from scgo import run_ts_search
459
+ from scgo.param_presets import get_ts_search_params
460
+
461
+ ts_params = get_ts_search_params(system_type="gas_cluster", seed=42)
462
+ ts_results = run_ts_search(
463
+ ["Pt", "Pt", "Pt"],
464
+ output_dir="Pt3_searches",
465
+ ts_params=ts_params,
466
+ seed=42,
467
+ system_type="gas_cluster",
468
+ )
469
+ ```
470
+
471
+ `run_ts_campaign` forwards the same `ts_params` to each composition.
472
+
473
+ ### GO then TS
474
+
475
+ `run_go_ts` / `run_go_ts_campaign` use **`go_params=`** (merged like other GO runs) and **`ts_params=`** (same flat shape as above; **not** deep-merged with `get_default_params()`). For `*_adsorbate` system types, pass core-only `composition` and `adsorbates` on the `run_*` call (same as `run_go`); SCGO builds the full mobile composition internally. For surface workflows, pass `surface_config` on the `run_*` call and in preset builders (`get_torchsim_ga_params`, `get_ts_search_params`); values must agree when both are set. For MACE + TorchSim GA, start from [`get_torchsim_ga_params`](scgo/param_presets.py) with `system_type=...` and `seed` (optional `surface_config=` / `model_name=`), set `go_params["calculator"] = "MACE"` and `optimizer_params["ga"]` as needed; pair with `get_ts_search_params(...)` and set `ts_params["max_pairs"]`, etc. For UMA NEB defaults, use `get_ts_search_params(calculator="UMA", ...)`. See `examples/example_pt5_gas.py` for a minimal end-to-end example. Default output if `output_dir` is omitted is under `scgo_runs/<stem>_<mace|uma>/` (set `output_root` / `output_stem` to change).
476
+
477
+ Benchmarks comparing MACE vs UMA on the same GA structure can use [`get_uma_ga_benchmark_params`](scgo/param_presets.py) (re-exported from `scgo`). See `benchmark/` for long-running MLIP regression sweeps.
478
+
479
+ ### Advanced / internals
480
+
481
+ - `from scgo.runner_api import _run_go_trials`, `_run_go_campaign_compositions`, `build_one_element_compositions`, `build_two_element_compositions`, …
482
+ - `from scgo.surface import make_surface_config` for arbitrary ASE slabs (preset graphite: `make_graphite_surface_config`)
483
+ - `from scgo.cluster_adsorbate import ClusterAdsorbateConfig, place_fragment_on_cluster` — adsorbate placement; see `docs/source/api/cluster_adsorbate.rst`
484
+ - `from scgo.initialization.atomic_radii import build_blmin` — covalent-radius clash tables for GA and placement
485
+ - Low-level `scgo(...)` / `run_trials(...)`: pass `system_type` in `global_optimizer_kwargs` (required for `scgo`; `run_trials` defaults missing values to `"gas_cluster"`)
486
+ - `from scgo.ts_search.transition_state_run import run_transition_state_search` for a flat keyword API without the `ts_params` dict.
487
+
488
+ ---
489
+
490
+ ## Notes
491
+
492
+ - TorchSim is an optional tool that provides GPU-accelerated batched optimization when available; SCGO works with EMT (CPU) out of the box for quick tests.
493
+ - For reproducible results, pass `seed=` to the workflow functions above.
494
+ - Optional scripts in [`examples/`](examples/) are minimal, no-CLI examples that call [`run_go_ts`](scgo/runner_api.py). Each is tuned for MACE + TorchSim (edit calculator in the script if needed):
495
+
496
+ | Script | `system_type` | Notes |
497
+ |--------|----------------|-------|
498
+ | [`examples/example_pt5_gas.py`](examples/example_pt5_gas.py) | `gas_cluster` | Gas-phase `Pt5` only |
499
+ | [`examples/example_pt5_graphite.py`](examples/example_pt5_graphite.py) | `surface_cluster` | `Pt5` on preset graphite |
500
+ | [`examples/example_pt5_oh_gas.py`](examples/example_pt5_oh_gas.py) | `gas_cluster_adsorbate` | core-only `Pt5` + one OH; tag-aware GA, optional `freeze_adsorbate_internal_geometry` |
501
+ | [`examples/example_pt5_2oh_graphite.py`](examples/example_pt5_2oh_graphite.py) | `surface_cluster_adsorbate` | core-only `Pt5` + two OH on graphite; hull-site placement + `fragment_reposition` |
502
+
503
+ For multi-size MLIP sweeps, see [`benchmark/`](benchmark/) (e.g. [`benchmark/benchmark_Pt.py`](benchmark/benchmark_Pt.py), [`benchmark/benchmark_Pt_surface_graphite.py`](benchmark/benchmark_Pt_surface_graphite.py)), not `tests/benchmarks/`.
504
+
505
+ See `tests/` for concrete usage patterns and acceptance tests for adsorbate GA operators.
506
+
507
+ ---
508
+
509
+ MIT License — see `LICENSE`.