ase2sprkkr-gui 0.2.0b1__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 (348) hide show
  1. ase2sprkkr_gui-0.2.0b1/PKG-INFO +41 -0
  2. ase2sprkkr_gui-0.2.0b1/README.md +25 -0
  3. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/__init__.py +1 -0
  4. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/ase/__init__.py +0 -0
  5. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/ase/element_assignment.py +424 -0
  6. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/ase/utils.py +42 -0
  7. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/assets/icons/COPYING-ICONS +209 -0
  8. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/assets/icons/README.md +19 -0
  9. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/assets/icons/bulk_crystal.png +0 -0
  10. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/assets/icons/database.svg +1 -0
  11. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/assets/icons/labplot-xy-interpolation-curve.svg +17 -0
  12. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/assets/icons/run-build-clean.svg +14 -0
  13. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/assets/icons/settings-cog.svg +4 -0
  14. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/assets/icons/sprkkr-orbital.svg +150 -0
  15. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/assets/icons/structure_interface.png +0 -0
  16. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/assets/icons/surface_2d.svg +1 -0
  17. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/assets/icons/system-run.svg +14 -0
  18. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/assets/structures/ITXC_structure.dat +446 -0
  19. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/assets/structures/README.md +10 -0
  20. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/cli/__init__.py +1 -0
  21. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/cli/gui.py +15 -0
  22. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/__init__.py +1 -0
  23. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/__init__.py +1 -0
  24. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/atomic_io.py +77 -0
  25. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/attached_run_execution.py +48 -0
  26. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/config.py +11 -0
  27. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/console_interrupt.py +74 -0
  28. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/execution_cancellation.py +103 -0
  29. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/execution_profiles.py +173 -0
  30. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/historical_state.py +114 -0
  31. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/imported_project_results.py +85 -0
  32. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/operation_results.py +38 -0
  33. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/persistent_jobs.py +875 -0
  34. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/potential_version.py +7 -0
  35. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/recent_files.py +181 -0
  36. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/result_action_policy.py +165 -0
  37. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/result_artifacts.py +69 -0
  38. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/result_cache.py +101 -0
  39. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/result_contract.py +16 -0
  40. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/result_files.py +7 -0
  41. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/result_loading.py +185 -0
  42. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/result_presentation.py +326 -0
  43. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/result_store.py +805 -0
  44. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/run_file_deletion.py +331 -0
  45. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/settings.py +67 -0
  46. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/shell_history.py +146 -0
  47. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/sprkkr_execution.py +157 -0
  48. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/structure_snapshot.py +102 -0
  49. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/viewers.py +50 -0
  50. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/window_geometry.py +352 -0
  51. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/workspace.py +222 -0
  52. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/application/workspace_controller.py +967 -0
  53. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/controllers/__init__.py +1 -0
  54. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/controllers/persistent_jobs.py +771 -0
  55. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/__init__.py +1 -0
  56. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/_tree_base.py +102 -0
  57. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/assign_results.py +135 -0
  58. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/attached_run.py +83 -0
  59. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/calculation_history.py +34 -0
  60. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/delete_run_record.py +442 -0
  61. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/expert_input.py +176 -0
  62. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/guided_input.py +431 -0
  63. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/input_file.py +143 -0
  64. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/main_window.py +515 -0
  65. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/object_view.py +198 -0
  66. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/profiles.py +486 -0
  67. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/project_browser.py +675 -0
  68. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/project_edit.py +59 -0
  69. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/run_calculation.py +307 -0
  70. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/run_conflict.py +247 -0
  71. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/run_monitor.py +260 -0
  72. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/settings.py +109 -0
  73. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/structures/__init__.py +1 -0
  74. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/structures/build_2d.py +342 -0
  75. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/structures/database.py +191 -0
  76. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/structures/element_assignment.py +342 -0
  77. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/structures/element_selector.py +345 -0
  78. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/structures/empty_spheres.py +157 -0
  79. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/structures/online_database.py +878 -0
  80. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/structures/shell.py +177 -0
  81. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/structures/source.py +255 -0
  82. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/structures/spacegroup_selector.py +838 -0
  83. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/structures/transforms.py +417 -0
  84. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/dialogs/workflow_window.py +389 -0
  85. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/flows/__init__.py +1 -0
  86. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/flows/calculation.py +412 -0
  87. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/flows/files.py +464 -0
  88. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/flows/input_editing.py +106 -0
  89. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/flows/input_parameters.py +101 -0
  90. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/flows/structure_candidates.py +146 -0
  91. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/flows/structures.py +373 -0
  92. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/flows/visualization.py +107 -0
  93. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/__init__.py +1 -0
  94. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/bindings.py +46 -0
  95. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/bsf.py +58 -0
  96. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/dataset.py +75 -0
  97. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/defaults.py +12 -0
  98. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/energy.py +67 -0
  99. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/expert_fields.py +87 -0
  100. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/field_binding.py +595 -0
  101. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/keyword_choices.py +46 -0
  102. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/session.py +465 -0
  103. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/single_site_contour.py +47 -0
  104. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/specs/__init__.py +1 -0
  105. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/specs/arpes.py +75 -0
  106. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/specs/bsf.py +132 -0
  107. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/specs/dos.py +29 -0
  108. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/specs/jxc.py +31 -0
  109. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/specs/scf.py +124 -0
  110. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/specs/schema.py +177 -0
  111. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/specs/shared.py +289 -0
  112. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/specs/xas.py +39 -0
  113. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/tasks.py +161 -0
  114. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/tooltips.py +60 -0
  115. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/input_parameters/validation.py +43 -0
  116. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/misc/__init__.py +1 -0
  117. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/misc/colors.py +32 -0
  118. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/misc/dialog_flow.py +52 -0
  119. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/misc/icons.py +17 -0
  120. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/misc/modal_task.py +131 -0
  121. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/misc/resources.py +8 -0
  122. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/misc/structure_wait.py +22 -0
  123. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/misc/tables.py +13 -0
  124. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/plots/__init__.py +1 -0
  125. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/plots/lattice.py +344 -0
  126. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/presentation.py +18 -0
  127. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/presenters/__init__.py +1 -0
  128. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/presenters/result_actions.py +103 -0
  129. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/recent_presentation.py +128 -0
  130. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/style.py +195 -0
  131. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/viewers/__init__.py +1 -0
  132. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/viewers/ase_gui.py +123 -0
  133. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/__init__.py +1 -0
  134. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/action_card.py +110 -0
  135. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/browser_panel.py +42 -0
  136. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/calculation_setup.py +184 -0
  137. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/double_edit.py +19 -0
  138. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/execution_profiles.py +406 -0
  139. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/expert_side_panel.py +54 -0
  140. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/__init__.py +1 -0
  141. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/bsf.py +488 -0
  142. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/commit.py +83 -0
  143. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/common.py +96 -0
  144. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/dataset.py +84 -0
  145. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/energy.py +110 -0
  146. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/expert_tree.py +378 -0
  147. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/expert_tree_renderer.py +860 -0
  148. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/expert_tree_runtime.py +225 -0
  149. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/expert_tree_structure.py +212 -0
  150. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/form.py +502 -0
  151. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/kpath.py +61 -0
  152. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/modal_editor.py +83 -0
  153. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/parameter.py +153 -0
  154. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/registry.py +92 -0
  155. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/relativistic_scaling.py +188 -0
  156. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/scalar.py +427 -0
  157. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/input_parameters/value_editor.py +61 -0
  158. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/nullable_spinbox.py +90 -0
  159. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/numeric_table.py +69 -0
  160. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/optimade_filters.py +264 -0
  161. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/persistent_jobs.py +785 -0
  162. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/recent_launcher.py +93 -0
  163. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/result_actions.py +456 -0
  164. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/settings/__init__.py +5 -0
  165. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/settings/general.py +113 -0
  166. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/settings/run_configurations.py +189 -0
  167. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/structure_overview.py +444 -0
  168. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/structures/__init__.py +1 -0
  169. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/structures/element_assignment.py +406 -0
  170. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/structures/structure_pane.py +161 -0
  171. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/structures/wyckoff_position.py +154 -0
  172. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/units.py +43 -0
  173. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/widgets/workflow_actions.py +158 -0
  174. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/workflow/__init__.py +1 -0
  175. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/workflow/model.py +188 -0
  176. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/workflow/planner.py +345 -0
  177. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/workflow/scf_status.py +66 -0
  178. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/gui/workspace_semantics.py +14 -0
  179. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/main.py +435 -0
  180. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/online_databases/__init__.py +39 -0
  181. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/online_databases/models.py +198 -0
  182. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/online_databases/optimade.py +1138 -0
  183. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/online_databases/provider.py +60 -0
  184. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/physics/__init__.py +0 -0
  185. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/physics/composition.py +161 -0
  186. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/physics/lattice.py +76 -0
  187. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/physics/pyxtal_utils.py +117 -0
  188. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui/physics/structure_database.py +198 -0
  189. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui.egg-info/PKG-INFO +41 -0
  190. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui.egg-info/SOURCES.txt +346 -0
  191. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui.egg-info/dependency_links.txt +1 -0
  192. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui.egg-info/entry_points.txt +5 -0
  193. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui.egg-info/requires.txt +9 -0
  194. ase2sprkkr_gui-0.2.0b1/ase2sprkkr_gui.egg-info/top_level.txt +1 -0
  195. ase2sprkkr_gui-0.2.0b1/pyproject.toml +45 -0
  196. ase2sprkkr_gui-0.2.0b1/setup.cfg +4 -0
  197. ase2sprkkr_gui-0.2.0b1/tests/test_active_project.py +180 -0
  198. ase2sprkkr_gui-0.2.0b1/tests/test_application_icon.py +59 -0
  199. ase2sprkkr_gui-0.2.0b1/tests/test_ase_gui_readiness.py +112 -0
  200. ase2sprkkr_gui-0.2.0b1/tests/test_atomic_io.py +51 -0
  201. ase2sprkkr_gui-0.2.0b1/tests/test_attached_run_execution.py +107 -0
  202. ase2sprkkr_gui-0.2.0b1/tests/test_backend_persistence_contract.py +180 -0
  203. ase2sprkkr_gui-0.2.0b1/tests/test_backend_public_imports.py +33 -0
  204. ase2sprkkr_gui-0.2.0b1/tests/test_bsf_calculation_setup.py +381 -0
  205. ase2sprkkr_gui-0.2.0b1/tests/test_build2d_recent_files_di.py +144 -0
  206. ase2sprkkr_gui-0.2.0b1/tests/test_calculation_concurrency.py +390 -0
  207. ase2sprkkr_gui-0.2.0b1/tests/test_calculation_dialog_geometry.py +36 -0
  208. ase2sprkkr_gui-0.2.0b1/tests/test_calculation_history.py +320 -0
  209. ase2sprkkr_gui-0.2.0b1/tests/test_calculation_profile_flow.py +462 -0
  210. ase2sprkkr_gui-0.2.0b1/tests/test_calculation_structure_cleanliness.py +137 -0
  211. ase2sprkkr_gui-0.2.0b1/tests/test_calculation_worker_isolation.py +71 -0
  212. ase2sprkkr_gui-0.2.0b1/tests/test_clearing_inputs.py +162 -0
  213. ase2sprkkr_gui-0.2.0b1/tests/test_cli_plugin.py +58 -0
  214. ase2sprkkr_gui-0.2.0b1/tests/test_console_interrupt.py +138 -0
  215. ase2sprkkr_gui-0.2.0b1/tests/test_continue_output.py +130 -0
  216. ase2sprkkr_gui-0.2.0b1/tests/test_current_potential_state_reuse.py +209 -0
  217. ase2sprkkr_gui-0.2.0b1/tests/test_dataset_naming.py +145 -0
  218. ase2sprkkr_gui-0.2.0b1/tests/test_dialog_flow.py +54 -0
  219. ase2sprkkr_gui-0.2.0b1/tests/test_editor_commit_boundaries.py +77 -0
  220. ase2sprkkr_gui-0.2.0b1/tests/test_element_assignment_dialog.py +81 -0
  221. ase2sprkkr_gui-0.2.0b1/tests/test_element_assignment_state.py +186 -0
  222. ase2sprkkr_gui-0.2.0b1/tests/test_empty_spheres_dialog.py +43 -0
  223. ase2sprkkr_gui-0.2.0b1/tests/test_empty_spheres_workflow.py +225 -0
  224. ase2sprkkr_gui-0.2.0b1/tests/test_energy_editor.py +199 -0
  225. ase2sprkkr_gui-0.2.0b1/tests/test_exception_boundaries.py +306 -0
  226. ase2sprkkr_gui-0.2.0b1/tests/test_execution_dialog_projects.py +769 -0
  227. ase2sprkkr_gui-0.2.0b1/tests/test_execution_profile_application.py +175 -0
  228. ase2sprkkr_gui-0.2.0b1/tests/test_execution_profile_architecture.py +26 -0
  229. ase2sprkkr_gui-0.2.0b1/tests/test_execution_profiles.py +85 -0
  230. ase2sprkkr_gui-0.2.0b1/tests/test_expert_changed_state_errors.py +48 -0
  231. ase2sprkkr_gui-0.2.0b1/tests/test_expert_field_specs.py +38 -0
  232. ase2sprkkr_gui-0.2.0b1/tests/test_expert_shared_editors.py +535 -0
  233. ase2sprkkr_gui-0.2.0b1/tests/test_expert_tree_deferred_updates.py +33 -0
  234. ase2sprkkr_gui-0.2.0b1/tests/test_expert_tree_rendering.py +350 -0
  235. ase2sprkkr_gui-0.2.0b1/tests/test_expert_tree_runtime.py +129 -0
  236. ase2sprkkr_gui-0.2.0b1/tests/test_expert_tree_runtime_lifecycle.py +45 -0
  237. ase2sprkkr_gui-0.2.0b1/tests/test_expert_tree_structure.py +134 -0
  238. ase2sprkkr_gui-0.2.0b1/tests/test_field_binding.py +440 -0
  239. ase2sprkkr_gui-0.2.0b1/tests/test_file_flows.py +154 -0
  240. ase2sprkkr_gui-0.2.0b1/tests/test_file_version.py +50 -0
  241. ase2sprkkr_gui-0.2.0b1/tests/test_finalization_failed_actions.py +91 -0
  242. ase2sprkkr_gui-0.2.0b1/tests/test_generation_model.py +314 -0
  243. ase2sprkkr_gui-0.2.0b1/tests/test_gui_architecture.py +399 -0
  244. ase2sprkkr_gui-0.2.0b1/tests/test_gui_composition.py +97 -0
  245. ase2sprkkr_gui-0.2.0b1/tests/test_gui_data_integrity.py +441 -0
  246. ase2sprkkr_gui-0.2.0b1/tests/test_guided_explicit_commit.py +50 -0
  247. ase2sprkkr_gui-0.2.0b1/tests/test_guided_form_spec_validation.py +52 -0
  248. ase2sprkkr_gui-0.2.0b1/tests/test_guided_history_lifetime.py +22 -0
  249. ase2sprkkr_gui-0.2.0b1/tests/test_guided_parameter_tooltips.py +72 -0
  250. ase2sprkkr_gui-0.2.0b1/tests/test_guided_presentation_rules.py +76 -0
  251. ase2sprkkr_gui-0.2.0b1/tests/test_guided_task_availability.py +179 -0
  252. ase2sprkkr_gui-0.2.0b1/tests/test_guided_validation_navigation.py +76 -0
  253. ase2sprkkr_gui-0.2.0b1/tests/test_imported_results_projects.py +146 -0
  254. ase2sprkkr_gui-0.2.0b1/tests/test_input_file_editor.py +147 -0
  255. ase2sprkkr_gui-0.2.0b1/tests/test_input_file_explicit_commit.py +95 -0
  256. ase2sprkkr_gui-0.2.0b1/tests/test_input_parameter_flows.py +112 -0
  257. ase2sprkkr_gui-0.2.0b1/tests/test_input_parameters_session.py +630 -0
  258. ase2sprkkr_gui-0.2.0b1/tests/test_input_parameters_session_comparison.py +25 -0
  259. ase2sprkkr_gui-0.2.0b1/tests/test_input_parameters_session_dormant.py +63 -0
  260. ase2sprkkr_gui-0.2.0b1/tests/test_input_parameters_session_read_contract.py +17 -0
  261. ase2sprkkr_gui-0.2.0b1/tests/test_input_parameters_session_unification.py +225 -0
  262. ase2sprkkr_gui-0.2.0b1/tests/test_keyword_choices.py +297 -0
  263. ase2sprkkr_gui-0.2.0b1/tests/test_kkrunner_wip2_contract.py +60 -0
  264. ase2sprkkr_gui-0.2.0b1/tests/test_kpath_qt_integration.py +140 -0
  265. ase2sprkkr_gui-0.2.0b1/tests/test_kpath_table.py +169 -0
  266. ase2sprkkr_gui-0.2.0b1/tests/test_lattice_transforms.py +71 -0
  267. ase2sprkkr_gui-0.2.0b1/tests/test_main_window_view_decomposition.py +225 -0
  268. ase2sprkkr_gui-0.2.0b1/tests/test_modal_task.py +33 -0
  269. ase2sprkkr_gui-0.2.0b1/tests/test_mpi_warning_submit.py +57 -0
  270. ase2sprkkr_gui-0.2.0b1/tests/test_online_database_live.py +187 -0
  271. ase2sprkkr_gui-0.2.0b1/tests/test_online_database_provider.py +448 -0
  272. ase2sprkkr_gui-0.2.0b1/tests/test_online_structure_dialog.py +286 -0
  273. ase2sprkkr_gui-0.2.0b1/tests/test_operation_capabilities.py +201 -0
  274. ase2sprkkr_gui-0.2.0b1/tests/test_operation_result_identity.py +39 -0
  275. ase2sprkkr_gui-0.2.0b1/tests/test_package_identity.py +26 -0
  276. ase2sprkkr_gui-0.2.0b1/tests/test_persistent_finalization_recovery.py +72 -0
  277. ase2sprkkr_gui-0.2.0b1/tests/test_persistent_history_entry.py +161 -0
  278. ase2sprkkr_gui-0.2.0b1/tests/test_persistent_jobs.py +290 -0
  279. ase2sprkkr_gui-0.2.0b1/tests/test_persistent_jobs_architecture.py +71 -0
  280. ase2sprkkr_gui-0.2.0b1/tests/test_persistent_jobs_controller.py +943 -0
  281. ase2sprkkr_gui-0.2.0b1/tests/test_persistent_result_application.py +72 -0
  282. ase2sprkkr_gui-0.2.0b1/tests/test_persistent_result_files.py +111 -0
  283. ase2sprkkr_gui-0.2.0b1/tests/test_persistent_result_preload.py +176 -0
  284. ase2sprkkr_gui-0.2.0b1/tests/test_persistent_result_reference.py +64 -0
  285. ase2sprkkr_gui-0.2.0b1/tests/test_persistent_submitting_recovery.py +86 -0
  286. ase2sprkkr_gui-0.2.0b1/tests/test_potential_authority.py +327 -0
  287. ase2sprkkr_gui-0.2.0b1/tests/test_presentation.py +104 -0
  288. ase2sprkkr_gui-0.2.0b1/tests/test_profile_editor_ui.py +388 -0
  289. ase2sprkkr_gui-0.2.0b1/tests/test_project_browser.py +768 -0
  290. ase2sprkkr_gui-0.2.0b1/tests/test_project_execution_workflow.py +69 -0
  291. ase2sprkkr_gui-0.2.0b1/tests/test_projected_editor_bindings.py +66 -0
  292. ase2sprkkr_gui-0.2.0b1/tests/test_python39_compat.py +74 -0
  293. ase2sprkkr_gui-0.2.0b1/tests/test_recent_files.py +132 -0
  294. ase2sprkkr_gui-0.2.0b1/tests/test_recent_menu_policy.py +129 -0
  295. ase2sprkkr_gui-0.2.0b1/tests/test_recompute_task_routing.py +176 -0
  296. ase2sprkkr_gui-0.2.0b1/tests/test_restart_scf_execution.py +103 -0
  297. ase2sprkkr_gui-0.2.0b1/tests/test_result_actions_history.py +125 -0
  298. ase2sprkkr_gui-0.2.0b1/tests/test_result_actions_widget.py +275 -0
  299. ase2sprkkr_gui-0.2.0b1/tests/test_result_cache.py +44 -0
  300. ase2sprkkr_gui-0.2.0b1/tests/test_result_file_provenance.py +168 -0
  301. ase2sprkkr_gui-0.2.0b1/tests/test_result_lineage_fast_forward.py +49 -0
  302. ase2sprkkr_gui-0.2.0b1/tests/test_result_loading.py +224 -0
  303. ase2sprkkr_gui-0.2.0b1/tests/test_result_potential_projection.py +228 -0
  304. ase2sprkkr_gui-0.2.0b1/tests/test_result_refresh_ownership.py +48 -0
  305. ase2sprkkr_gui-0.2.0b1/tests/test_result_selection_intent.py +59 -0
  306. ase2sprkkr_gui-0.2.0b1/tests/test_result_state_capability.py +118 -0
  307. ase2sprkkr_gui-0.2.0b1/tests/test_result_store_history.py +298 -0
  308. ase2sprkkr_gui-0.2.0b1/tests/test_result_store_invariants.py +318 -0
  309. ase2sprkkr_gui-0.2.0b1/tests/test_result_store_lightweight_provenance.py +94 -0
  310. ase2sprkkr_gui-0.2.0b1/tests/test_run_cancellation.py +61 -0
  311. ase2sprkkr_gui-0.2.0b1/tests/test_run_conflict_dialog.py +361 -0
  312. ase2sprkkr_gui-0.2.0b1/tests/test_run_file_deletion.py +557 -0
  313. ase2sprkkr_gui-0.2.0b1/tests/test_run_identification.py +178 -0
  314. ase2sprkkr_gui-0.2.0b1/tests/test_run_monitor.py +166 -0
  315. ase2sprkkr_gui-0.2.0b1/tests/test_runtime_public_api.py +19 -0
  316. ase2sprkkr_gui-0.2.0b1/tests/test_scalar_validation_boundary.py +35 -0
  317. ase2sprkkr_gui-0.2.0b1/tests/test_scaling_editor.py +95 -0
  318. ase2sprkkr_gui-0.2.0b1/tests/test_settings.py +247 -0
  319. ase2sprkkr_gui-0.2.0b1/tests/test_shared_use_cases.py +259 -0
  320. ase2sprkkr_gui-0.2.0b1/tests/test_sprkkr_execution.py +289 -0
  321. ase2sprkkr_gui-0.2.0b1/tests/test_structure_candidates.py +208 -0
  322. ase2sprkkr_gui-0.2.0b1/tests/test_structure_composition.py +133 -0
  323. ase2sprkkr_gui-0.2.0b1/tests/test_structure_continuation.py +284 -0
  324. ase2sprkkr_gui-0.2.0b1/tests/test_structure_database.py +75 -0
  325. ase2sprkkr_gui-0.2.0b1/tests/test_structure_database_dialog.py +119 -0
  326. ase2sprkkr_gui-0.2.0b1/tests/test_structure_pane.py +36 -0
  327. ase2sprkkr_gui-0.2.0b1/tests/test_structure_shell.py +271 -0
  328. ase2sprkkr_gui-0.2.0b1/tests/test_structure_shell_history.py +205 -0
  329. ase2sprkkr_gui-0.2.0b1/tests/test_structure_type_icons.py +49 -0
  330. ase2sprkkr_gui-0.2.0b1/tests/test_task_capabilities.py +164 -0
  331. ase2sprkkr_gui-0.2.0b1/tests/test_thread_boundaries.py +43 -0
  332. ase2sprkkr_gui-0.2.0b1/tests/test_transactional_structure_edit.py +33 -0
  333. ase2sprkkr_gui-0.2.0b1/tests/test_use_result_state_invariants.py +131 -0
  334. ase2sprkkr_gui-0.2.0b1/tests/test_values_equal.py +12 -0
  335. ase2sprkkr_gui-0.2.0b1/tests/test_viewer_handling.py +220 -0
  336. ase2sprkkr_gui-0.2.0b1/tests/test_visualization_flow.py +116 -0
  337. ase2sprkkr_gui-0.2.0b1/tests/test_window_geometry.py +119 -0
  338. ase2sprkkr_gui-0.2.0b1/tests/test_workflow_actions_widget.py +240 -0
  339. ase2sprkkr_gui-0.2.0b1/tests/test_workflow_formula.py +40 -0
  340. ase2sprkkr_gui-0.2.0b1/tests/test_workflow_planner.py +357 -0
  341. ase2sprkkr_gui-0.2.0b1/tests/test_workflow_recent_integration.py +39 -0
  342. ase2sprkkr_gui-0.2.0b1/tests/test_workflow_scf_status.py +37 -0
  343. ase2sprkkr_gui-0.2.0b1/tests/test_workflow_task_identity.py +29 -0
  344. ase2sprkkr_gui-0.2.0b1/tests/test_workflow_window.py +393 -0
  345. ase2sprkkr_gui-0.2.0b1/tests/test_workspace_controller_clear_structure.py +27 -0
  346. ase2sprkkr_gui-0.2.0b1/tests/test_workspace_controller_reads.py +27 -0
  347. ase2sprkkr_gui-0.2.0b1/tests/test_workspace_restarted.py +153 -0
  348. ase2sprkkr_gui-0.2.0b1/tests/test_workspace_state.py +104 -0
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.4
2
+ Name: ase2sprkkr-gui
3
+ Version: 0.2.0b1
4
+ Summary: PyQt6 GUI for building/editing ASE structures and running SPR-KKR via ase2sprkkr.
5
+ Requires-Python: >=3.9
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: kkrunner<0.3,>=0.2.0b2
8
+ Requires-Dist: PyQt6
9
+ Requires-Dist: qonsole<4,>=3.3
10
+ Requires-Dist: matplotlib
11
+ Requires-Dist: numpy
12
+ Requires-Dist: ase
13
+ Requires-Dist: platformdirs
14
+ Requires-Dist: pyxtal
15
+ Requires-Dist: ase2sprkkr<5,>=4.0.0b3
16
+
17
+ # ASE2SPRKKR GUI
18
+
19
+ A PyQt6 desktop interface for creating and editing ASE structures, configuring
20
+ SPR-KKR calculations, and exploring calculation results through ASE2SPRKKR.
21
+
22
+ ## Install
23
+
24
+ Install this beta alongside the matching released ASE2SPRKKR and KKRunner packages:
25
+
26
+ ```bash
27
+ python -m pip install --pre ase2sprkkr-gui
28
+ ```
29
+
30
+ ## Run
31
+
32
+ ```bash
33
+ ase2sprkkr-gui
34
+ ```
35
+
36
+ The GUI requires the ASE2SPRKKR Python backend. Running actual SPR-KKR
37
+ calculations also requires a separately installed SPR-KKR executable.
38
+
39
+ ## Development
40
+
41
+ Source: https://github.com/ase2sprkkr/ase2sprkkr-gui
@@ -0,0 +1,25 @@
1
+ # ASE2SPRKKR GUI
2
+
3
+ A PyQt6 desktop interface for creating and editing ASE structures, configuring
4
+ SPR-KKR calculations, and exploring calculation results through ASE2SPRKKR.
5
+
6
+ ## Install
7
+
8
+ Install this beta alongside the matching released ASE2SPRKKR and KKRunner packages:
9
+
10
+ ```bash
11
+ python -m pip install --pre ase2sprkkr-gui
12
+ ```
13
+
14
+ ## Run
15
+
16
+ ```bash
17
+ ase2sprkkr-gui
18
+ ```
19
+
20
+ The GUI requires the ASE2SPRKKR Python backend. Running actual SPR-KKR
21
+ calculations also requires a separately installed SPR-KKR executable.
22
+
23
+ ## Development
24
+
25
+ Source: https://github.com/ase2sprkkr/ase2sprkkr-gui
@@ -0,0 +1 @@
1
+ """Ase2sprkkr graphical interface for ASE and SPR-KKR workflows."""
File without changes
@@ -0,0 +1,424 @@
1
+ """Qt-independent working model for assigning elements to structure sites."""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass
5
+ import re
6
+ from typing import Any, Iterable
7
+
8
+ import numpy as np
9
+ from ase import Atoms
10
+ from ase.data import chemical_symbols
11
+ from ase2sprkkr import SPRKKRAtoms
12
+ from ase2sprkkr.sprkkr.atomic_types import AtomicType
13
+ from ase2sprkkr.sprkkr.sites import Site, SiteType
14
+
15
+ from ase2sprkkr_gui.ase.utils import labels_for_partitions, partition_by_kinds
16
+
17
+
18
+ _VALID_SYMBOLS = {
19
+ symbol for symbol in chemical_symbols if isinstance(symbol, str)
20
+ } | {"Vc"}
21
+ _OCCUPANCY_TOLERANCE = 1e-6
22
+
23
+
24
+ @dataclass
25
+ class OccupancyEntry:
26
+ """One editable component of a site's chemical occupation."""
27
+
28
+ symbol: str = ""
29
+ value: float = 1.0
30
+
31
+
32
+ @dataclass
33
+ class AssignmentSite:
34
+ """One independently editable group of equivalent fractional positions."""
35
+
36
+ label: str
37
+ positions: np.ndarray
38
+ origins: list[int | None]
39
+ occupancies: list[OccupancyEntry]
40
+
41
+ @property
42
+ def can_split(self) -> bool:
43
+ return len(self.positions) > 1
44
+
45
+
46
+ class ElementAssignmentDraft:
47
+ """Transactional edit buffer for the element-assignment dialog.
48
+
49
+ This deliberately is not another general material or structure model.
50
+ ``Atoms``/``SPRKKRAtoms`` remain the authoritative accepted structures,
51
+ while this sidecar can represent dialog-only provenance, labels, grouping,
52
+ and temporarily incomplete occupancy without polluting or invalidating the
53
+ source object. :meth:`apply` materializes a valid structure only on OK.
54
+
55
+ ``origins`` records which input atom, if any, supplied every position. It
56
+ replaces the former ambiguous combination of payload ``index`` and
57
+ ``origin`` fields and remains aligned with ``positions`` after edits.
58
+ """
59
+
60
+ def __init__(self, atoms: Atoms):
61
+ self._source_atoms = atoms
62
+ self._cell = np.asarray(atoms.cell, dtype=float).copy()
63
+ self.sites = self._sites_from_atoms(atoms)
64
+ self._original_partition = tuple(
65
+ tuple(site.origins) for site in self.sites
66
+ )
67
+
68
+ @property
69
+ def cell(self) -> np.ndarray:
70
+ """Return a copy of the currently edited lattice vectors."""
71
+ return self._cell.copy()
72
+
73
+ def set_cell_component(self, row: int, column: int, value: float) -> None:
74
+ self._cell[row, column] = float(value)
75
+
76
+ def split_site(self, site: AssignmentSite) -> tuple[AssignmentSite, ...]:
77
+ """Replace a multi-position site by uniquely labelled single sites."""
78
+ site_index = self._site_index(site)
79
+ if not site.can_split:
80
+ return (site,)
81
+
82
+ used_labels = {candidate.label for candidate in self.sites}
83
+ replacements: list[AssignmentSite] = []
84
+ for position_index, position in enumerate(site.positions):
85
+ template = f"{site.label}.{position_index + 1}"
86
+ label = self._unique_label(template, used_labels)
87
+ used_labels.add(label)
88
+ replacements.append(
89
+ AssignmentSite(
90
+ label=label,
91
+ positions=np.asarray(position, dtype=float).reshape(1, 3),
92
+ origins=[site.origins[position_index]],
93
+ occupancies=self._copy_occupancies(site.occupancies),
94
+ )
95
+ )
96
+ self.sites[site_index:site_index + 1] = replacements
97
+ return tuple(replacements)
98
+
99
+ def add_position(self, site: AssignmentSite) -> int:
100
+ """Append a position, duplicating the last coordinates when present."""
101
+ self._site_index(site)
102
+ if len(site.positions):
103
+ position = site.positions[-1].copy()
104
+ site.positions = np.vstack((site.positions, position))
105
+ else:
106
+ site.positions = np.zeros((1, 3), dtype=float)
107
+ site.origins.append(None)
108
+ return len(site.positions) - 1
109
+
110
+ def remove_position(self, site: AssignmentSite, index: int) -> bool:
111
+ """Remove a position while preserving the invariant of one per site."""
112
+ self._site_index(site)
113
+ if len(site.positions) <= 1:
114
+ return False
115
+ index = max(0, min(int(index), len(site.positions) - 1))
116
+ site.positions = np.delete(site.positions, index, axis=0)
117
+ del site.origins[index]
118
+ return True
119
+
120
+ def set_position_component(
121
+ self,
122
+ site: AssignmentSite,
123
+ position: int,
124
+ component: int,
125
+ value: float,
126
+ ) -> None:
127
+ self._site_index(site)
128
+ site.positions[position, component] = float(value)
129
+
130
+ def add_occupancy(
131
+ self,
132
+ site: AssignmentSite,
133
+ symbol: str = "",
134
+ value: float = 1.0,
135
+ ) -> OccupancyEntry:
136
+ self._site_index(site)
137
+ entry = OccupancyEntry(symbol, float(value))
138
+ site.occupancies.append(entry)
139
+ return entry
140
+
141
+ def remove_occupancy(
142
+ self, site: AssignmentSite, entry: OccupancyEntry
143
+ ) -> bool:
144
+ self._site_index(site)
145
+ if len(site.occupancies) <= 1:
146
+ return False
147
+ site.occupancies.remove(entry)
148
+ return True
149
+
150
+ def set_occupancy_symbol(
151
+ self, site: AssignmentSite, entry: OccupancyEntry, symbol: str
152
+ ) -> None:
153
+ self._occupancy_index(site, entry)
154
+ entry.symbol = symbol.strip()
155
+
156
+ def set_occupancy_value(
157
+ self, site: AssignmentSite, entry: OccupancyEntry, value: float
158
+ ) -> None:
159
+ self._occupancy_index(site, entry)
160
+ entry.value = float(value)
161
+
162
+ def normalize_occupancy(self, site: AssignmentSite) -> None:
163
+ self._site_index(site)
164
+ total = self.occupancy_total(site)
165
+ if total == 0.0:
166
+ return
167
+ for entry in site.occupancies:
168
+ entry.value /= total
169
+
170
+ @staticmethod
171
+ def occupancy_total(site: AssignmentSite) -> float:
172
+ return sum(entry.value for entry in site.occupancies)
173
+
174
+ @classmethod
175
+ def occupancy_is_overfull(cls, site: AssignmentSite) -> bool:
176
+ return cls.occupancy_total(site) > 1.0 + _OCCUPANCY_TOLERANCE
177
+
178
+ @staticmethod
179
+ def symbol_is_valid(symbol: str) -> bool:
180
+ return symbol in _VALID_SYMBOLS
181
+
182
+ def validation_errors(self, site: AssignmentSite) -> tuple[str, ...]:
183
+ """Return all domain validation errors for one site."""
184
+ self._site_index(site)
185
+ errors: list[str] = []
186
+ if site.positions.ndim != 2 or site.positions.shape[1:] != (3,):
187
+ errors.append(f"Invalid positions for site {site.label}")
188
+ elif not len(site.positions):
189
+ errors.append(f"Site {site.label} requires a position")
190
+ if len(site.origins) != len(site.positions):
191
+ errors.append(f"Position origins are inconsistent for site {site.label}")
192
+ nonempty = [entry for entry in site.occupancies if entry.symbol]
193
+ invalid = [
194
+ entry.symbol
195
+ for entry in nonempty
196
+ if not self.symbol_is_valid(entry.symbol)
197
+ ]
198
+ if invalid:
199
+ errors.append(
200
+ f"Invalid element for site {site.label}: {', '.join(invalid)}"
201
+ )
202
+ if not nonempty:
203
+ errors.append(f"Site {site.label} requires an element")
204
+ if any(
205
+ entry.value < 0.0 or entry.value > 1.0
206
+ for entry in site.occupancies
207
+ ):
208
+ errors.append(
209
+ f"Occupation component is outside 0..1 for site {site.label}"
210
+ )
211
+ total = self.occupancy_total(site)
212
+ if total <= 0.0:
213
+ errors.append(f"Occupation must be positive for site {site.label}")
214
+ elif self.occupancy_is_overfull(site):
215
+ errors.append(f"Occupation too large for site {site.label}")
216
+ return tuple(errors)
217
+
218
+ def is_site_valid(self, site: AssignmentSite) -> bool:
219
+ return not self.validation_errors(site)
220
+
221
+ def is_valid(self) -> bool:
222
+ return bool(self.sites) and all(
223
+ self.is_site_valid(site) for site in self.sites
224
+ )
225
+
226
+ def apply(self, atoms: Atoms | None = None) -> Atoms:
227
+ """Validate and materialize the draft into a detached structure."""
228
+ if not self.is_valid():
229
+ raise ValueError("Element assignment is not valid")
230
+
231
+ source = self._source_atoms
232
+ if atoms is None or atoms is source:
233
+ atoms = source.copy()
234
+ changed = self._partition_changed()
235
+
236
+ if changed:
237
+ materialization_source = atoms
238
+ rebuilt: Atoms | None = None
239
+ for site in self.sites:
240
+ if all(origin is not None for origin in site.origins):
241
+ indices = [int(origin) for origin in site.origins]
242
+ part = materialization_source[indices]
243
+ else:
244
+ part = self._rebuilt_site(materialization_source, site)
245
+ rebuilt = part if rebuilt is None else rebuilt + part
246
+ atoms = rebuilt if rebuilt is not None else Atoms(cell=self._cell)
247
+
248
+ positions: list[np.ndarray] = []
249
+ kinds: list[int] = []
250
+ symbols: list[str] = []
251
+ labels: list[str] = []
252
+ occupancy: dict[str, dict[Any, float]] = {}
253
+ for kind, site in enumerate(self.sites):
254
+ count = len(site.positions)
255
+ positions.append(site.positions @ self._cell)
256
+ kinds.extend([kind] * count)
257
+ site_occupancy = self._occupancy_mapping(site.occupancies)
258
+ occupancy[str(kind)] = site_occupancy
259
+ symbol = next(iter(site_occupancy), "X")
260
+ symbols.extend([getattr(symbol, "symbol", symbol)] * count)
261
+ labels.extend(
262
+ f"{site.label}.{position + 1}"
263
+ for position in range(count)
264
+ )
265
+
266
+ atoms.cell = self._cell
267
+ atoms.symbols = symbols
268
+ atoms.set_array("spacegroup_kinds", np.asarray(kinds, dtype=int))
269
+ atoms.set_array("labels", np.asarray(labels, dtype=object))
270
+ atoms.positions = np.vstack(positions)
271
+ atoms.info["occupancy"] = occupancy
272
+ if isinstance(source, SPRKKRAtoms):
273
+ if not isinstance(atoms, SPRKKRAtoms):
274
+ atoms = SPRKKRAtoms.promote_ase_atoms(
275
+ atoms, symmetry=False, update_info=False
276
+ )
277
+ self._apply_sprkkr_sites(atoms)
278
+ return atoms
279
+
280
+ def _apply_sprkkr_sites(self, atoms: SPRKKRAtoms) -> None:
281
+ """Materialize site groups while retaining origin SiteType data."""
282
+ source_sites = self._source_atoms.sites
283
+ result_sites: list[Site] = []
284
+ for draft_site in self.sites:
285
+ occupation = self._occupancy_mapping(draft_site.occupancies)
286
+ origin = next(
287
+ (item for item in draft_site.origins if item is not None),
288
+ None,
289
+ )
290
+ if origin is None:
291
+ site_type = SiteType(atoms, occupation)
292
+ else:
293
+ site_type = source_sites[origin].site_type.copy(atoms=atoms)
294
+ site_type.occupation.set(
295
+ self._occupation_with_preserved_types(
296
+ site_type, occupation
297
+ )
298
+ )
299
+ result_sites.extend(
300
+ Site(site_type) for _position in draft_site.positions
301
+ )
302
+ atoms.set_sites(
303
+ np.asarray(result_sites, dtype=object),
304
+ spacegroup_info=False,
305
+ update=True,
306
+ )
307
+
308
+ @staticmethod
309
+ def _occupation_with_preserved_types(
310
+ site_type: SiteType,
311
+ occupation: dict[Any, float],
312
+ ) -> dict[Any, float]:
313
+ """Reuse matching AtomicTypes so their SPR-KKR data survive editing."""
314
+ available: dict[str, list[AtomicType]] = {}
315
+ for atomic_type in site_type.occupation:
316
+ available.setdefault(atomic_type.symbol, []).append(atomic_type)
317
+ result: dict[Any, float] = {}
318
+ for key, value in occupation.items():
319
+ symbol = getattr(key, "symbol", str(key))
320
+ candidates = available.get(symbol, [])
321
+ preserved = candidates.pop(0) if candidates else key
322
+ result[preserved] = value
323
+ return result
324
+
325
+ def _rebuilt_site(self, source: Atoms, site: AssignmentSite) -> Atoms:
326
+ """Rebuild an edited site while retaining data of sourced atoms."""
327
+ result: Atoms | None = None
328
+ for position, origin in zip(site.positions, site.origins):
329
+ if origin is None:
330
+ atom = Atoms(
331
+ positions=[position], cell=self._cell, pbc=True
332
+ )
333
+ else:
334
+ atom = source[[origin]]
335
+ result = atom if result is None else result + atom
336
+ return result if result is not None else Atoms(cell=self._cell)
337
+
338
+ def _partition_changed(self) -> bool:
339
+ current = tuple(tuple(site.origins) for site in self.sites)
340
+ return current != self._original_partition or any(
341
+ origin is None for site in self.sites for origin in site.origins
342
+ )
343
+
344
+ def _site_index(self, site: AssignmentSite) -> int:
345
+ for index, candidate in enumerate(self.sites):
346
+ if candidate is site:
347
+ return index
348
+ raise ValueError("Site is not part of this assignment")
349
+
350
+ def _occupancy_index(
351
+ self, site: AssignmentSite, entry: OccupancyEntry
352
+ ) -> int:
353
+ self._site_index(site)
354
+ for index, candidate in enumerate(site.occupancies):
355
+ if candidate is entry:
356
+ return index
357
+ raise ValueError("Occupancy is not part of this site")
358
+
359
+ @staticmethod
360
+ def _unique_label(template: str, used: set[str]) -> str:
361
+ if template not in used:
362
+ return template
363
+ suffix = 1
364
+ while f"{template}.{suffix}" in used:
365
+ suffix += 1
366
+ return f"{template}.{suffix}"
367
+
368
+ @staticmethod
369
+ def _copy_occupancies(
370
+ entries: Iterable[OccupancyEntry],
371
+ ) -> list[OccupancyEntry]:
372
+ return [OccupancyEntry(entry.symbol, entry.value) for entry in entries]
373
+
374
+ @staticmethod
375
+ def _occupancy_mapping(
376
+ entries: Iterable[OccupancyEntry],
377
+ ) -> dict[Any, float]:
378
+ result: dict[Any, float] = {}
379
+ for entry in entries:
380
+ if not entry.symbol:
381
+ continue
382
+ key: Any = entry.symbol
383
+ if key in result:
384
+ key = AtomicType.from_symbol(entry.symbol)
385
+ result[key] = entry.value
386
+ return result
387
+
388
+ @classmethod
389
+ def _sites_from_atoms(cls, atoms: Atoms) -> list[AssignmentSite]:
390
+ partitions = partition_by_kinds(atoms)
391
+ kinds = (
392
+ atoms.get_array("spacegroup_kinds")
393
+ if "spacegroup_kinds" in atoms.arrays
394
+ else None
395
+ )
396
+ stored_occupancy = atoms.info.get("occupancy", {})
397
+ labels = labels_for_partitions(atoms, partitions=partitions)
398
+ positions = atoms.get_scaled_positions()
399
+ sites: list[AssignmentSite] = []
400
+ for number, partition in enumerate(partitions):
401
+ indices = [int(index) for index in partition]
402
+ first = indices[0]
403
+ occupancy = None
404
+ if stored_occupancy and kinds is not None:
405
+ occupancy = stored_occupancy.get(str(kinds[first]))
406
+ if occupancy is None:
407
+ symbol = atoms[first].symbol
408
+ occupancy = {} if symbol == "X" else {symbol: 1.0}
409
+ entries = [
410
+ OccupancyEntry(
411
+ re.sub(r"_\d+$", "", getattr(symbol, "symbol", str(symbol))),
412
+ float(value),
413
+ )
414
+ for symbol, value in occupancy.items()
415
+ ] or [OccupancyEntry()]
416
+ sites.append(
417
+ AssignmentSite(
418
+ label=str(labels[number]),
419
+ positions=np.asarray(positions[partition], dtype=float).copy(),
420
+ origins=indices,
421
+ occupancies=entries,
422
+ )
423
+ )
424
+ return sites
@@ -0,0 +1,42 @@
1
+ import numpy as np
2
+ import re
3
+
4
+ def labels_for_partitions(atoms, partitions=None, sep='_'):
5
+ """Generate unique labels for atom kinds, appending suffixes as needed."""
6
+ try:
7
+ arr = atoms.get_array('labels')
8
+ except KeyError:
9
+ arr = atoms.symbols
10
+ partitions = partition_by_kinds(atoms) if partitions is None else partitions
11
+ firsts = [ i[0] for i in partitions ]
12
+ arr = arr[firsts]
13
+
14
+ used = set()
15
+ result = []
16
+
17
+ for label in arr:
18
+ label = re.sub(r"\.\d+$", "", label)
19
+ if label not in used:
20
+ result.append(label)
21
+ used.add(label)
22
+ else:
23
+ i = 1
24
+ while f"{label}{sep}{i}" in used:
25
+ i += 1
26
+ new_label = f"{label}{sep}{i}"
27
+ result.append(new_label)
28
+ used.add(new_label)
29
+ return result
30
+
31
+ def partition_by_kinds(atoms):
32
+ """Partition atoms by their spacegroup kinds.
33
+
34
+ Returns a dict mapping kind index to list of atom indices.
35
+ """
36
+ if not 'spacegroup_kinds' in atoms.arrays:
37
+ return np.arange(len(atoms)).reshape(-1,1)
38
+
39
+ kinds = atoms.get_array('spacegroup_kinds')
40
+ kind_idxs = np.argsort(kinds)
41
+ sorted_kinds = kinds[kind_idxs]
42
+ return np.split(kind_idxs, np.where(np.diff(sorted_kinds))[0] + 1)