-
Notifications
You must be signed in to change notification settings - Fork 2
ENH: Add an adaptive displacement list for atoms #209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
8efaace
dec606e
dcc8fb3
389b6b4
ff3bb67
1e064dc
e8f95ce
3fcef8c
b72f95f
5468282
5b77ed4
fd44a3f
3a8425f
f92ad57
b86ef2f
bda0f92
ddcd55a
140bd0d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| from pathlib import Path | ||
| from enum import Enum | ||
| import sys | ||
| import subprocess | ||
| import tempfile | ||
| import logging | ||
| import typing as typ | ||
| from dataclasses import dataclass | ||
|
|
||
| from eon import fileio as eio | ||
| from eon import atoms as eatm | ||
| from eon import config as econf | ||
|
|
||
|
|
||
| class ScriptType(Enum): | ||
| STATE = 0 | ||
| DISP = 1 | ||
|
|
||
| @dataclass | ||
| class ScriptConfig: | ||
| """Configuration for running an external atom list script.""" | ||
|
|
||
| script_path: str | ||
| scratch_path: str | ||
| root_path: str | ||
|
|
||
| def __post_init__(self): | ||
| """ | ||
| Post-initialization processing to validate and resolve paths. | ||
| This method is automatically called by the dataclass constructor. | ||
| """ | ||
| for pth in (self.script_path, self.scratch_path): | ||
| if not pth.is_absolute(): | ||
| pth = self.root_path / pth | ||
|
|
||
| @classmethod | ||
| def from_eon_config(cls, config: econf.ConfigClass, stype: ScriptType) -> typ.Self: | ||
| """ | ||
| Factory method to create a ScriptConfig instance from the main EON config. | ||
| """ | ||
| if stype == ScriptType.STATE: | ||
| script_path = Path(config.displace_atom_kmc_state_script) | ||
| elif stype == ScriptType.DISP: | ||
| script_path = Path(config.displace_atom_kmc_step_script) | ||
|
|
||
| return cls( | ||
| script_path=script_path, | ||
| scratch_path=Path(config.path_scratch), | ||
| root_path=Path(config.path_root), | ||
| ) | ||
|
|
||
|
|
||
| def gen_ids_from_con(sconf: ScriptConfig, reactant: eatm.Atoms, logger: logging.Logger): | ||
| script_path = Path(sconf.script_path) | ||
| if not script_path.is_absolute(): | ||
| script_path = sconf.root_path / sconf.script_path | ||
|
|
||
| if not script_path.is_file(): | ||
| logger.error(f"displace_atom_list_script not found: {script_path}") | ||
| return [] | ||
|
|
||
| # Use a secure temporary file to pass the structure to the script | ||
| # The file is automatically deleted when the 'with' block is exited. | ||
| sconf.scratch_path.mkdir(parents=True, exist_ok=True) | ||
| with tempfile.NamedTemporaryFile( | ||
| mode="w+", delete=True, suffix=".con", dir=sconf.scratch_path | ||
| ) as tmpf: | ||
| # Save the displaced structure to the temporary file | ||
| eio.savecon(tmpf, reactant) | ||
| # Ensure all data is written to disk before the script reads it | ||
| tmpf.flush() | ||
|
|
||
| try: | ||
| # Execute the script, passing the temporary filename as an argument | ||
| proc = subprocess.run( | ||
| [sys.executable, str(script_path), tmpf.name], # Pass filename | ||
| capture_output=True, | ||
| text=True, | ||
| check=True, | ||
| cwd=sconf.root_path, | ||
| ) | ||
| atom_list_str = proc.stdout.strip() | ||
| return atom_list_str | ||
| except subprocess.CalledProcessError as e: | ||
| logger.error(f"Error running displace_atom_list_script '{script_path}':") | ||
| logger.error(f"Stderr: {e.stderr.strip()}") | ||
| sys.exit(1) | ||
| except Exception as e: | ||
| logger.error( | ||
| f"An unexpected error occurred while running the displacement script: {e}" | ||
| ) | ||
| sys.exit(1) |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -17,6 +17,7 @@ | |||||
| #import kdb | ||||||
| from eon import recycling | ||||||
| from eon import eon_kdb as kdb | ||||||
| from eon import _utils as utl | ||||||
|
|
||||||
| from eon.config import config as EON_CONFIG | ||||||
| from eon.config import ConfigClass # Typing | ||||||
|
|
@@ -194,7 +195,7 @@ def make_jobs(self): | |||||
|
|
||||||
| # Merge potential files into invariants | ||||||
| invariants = dict(invariants, **io.load_potfiles(self.config.path_pot)) | ||||||
|
|
||||||
| atom_list_str = str(self.state.info.get("Saddle Search", "displace_atom_list", "")) | ||||||
|
||||||
| atom_list_str = str(self.state.info.get("Saddle Search", "displace_atom_list", "")) | |
| atom_list_str = str(self.get_displacement_atom_list()) |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -123,3 +123,36 @@ def get_num_procs(self): | |||||
| def get_process_table(self): | ||||||
| self.load_process_table() | ||||||
| return self.procs | ||||||
|
|
||||||
| def get_displacement_atom_list(self, config: ConfigClass) -> list[int]: | ||||||
| """ | ||||||
| Gets the list of atoms for displacement. | ||||||
|
|
||||||
| If the list has already been generated and stored in this state's | ||||||
| info file, it is read from there. Otherwise, the displacement | ||||||
| script is run, and the result is saved to the info file for future use. | ||||||
|
|
||||||
| Returns: | ||||||
| A list of integer atom indices for displacement. | ||||||
| """ | ||||||
| # Try to get the list from the state's own info file first. | ||||||
| # We use a try/except block in case the section or option doesn't exist yet. | ||||||
| try: | ||||||
| # The list is stored as a string, so we need to parse it. | ||||||
| atom_list_str = self.info.get("Saddle Search", "displace_atom_list") | ||||||
| return atom_list_str | ||||||
|
||||||
| return atom_list_str | |
| return list(map(int, atom_list_str.split(','))) if atom_list_str else [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These imports (
sys,subprocess,tempfile,Path) look unused in this module. Consider removing them to keep dependencies clean.