Skip to content

Commit 361b9cd

Browse files
authored
Add files via upload
Implementation of the ORCA 6.1.0 interface using ASE. Option: -os orca Please specify the absolute path to the ORCA executable in software_path.conf using the format orca::<path>. For Linux, provide the path to the binary (e.g., /absolute/path/to/orca), and for Windows, provide the path to the executable file (e.g., C:\absolute\path\to\orca.exe).
1 parent bfcf788 commit 361b9cd

1 file changed

Lines changed: 37 additions & 13 deletions

File tree

  • multioptpy/Calculator/ase_tools

multioptpy/Calculator/ase_tools/orca.py

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
from ase.calculators.orca import ORCA, OrcaProfile
66
from ase.data import atomic_numbers
77

8+
"""
9+
Please specify the absolute path to the ORCA executable in software_path.conf using the format orca::<path>. For Linux, provide the path to the binary (e.g., /absolute/path/to/orca), and for Windows, provide the path to the executable file (e.g., C:\absolute\path\to\orca.exe).
10+
"""
11+
12+
813
class ASE_ORCA:
914
TARGET_ORCA_VERSION = '6.1.0'
1015

@@ -28,22 +33,41 @@ def __init__(self, **kwargs):
2833
self.heavy_atom_basis = kwargs.get('heavy_atom_basis', 'def2-SVP')
2934

3035
def _resolve_orca_exe(self, provided_path):
36+
"""
37+
Resolve the absolute path to the ORCA executable.
38+
Handles directories, stripping whitespace from config files, and WSL/Windows paths.
39+
"""
3140
if not provided_path:
3241
return None
33-
clean_path = os.path.normpath(provided_path)
42+
43+
# CRITICAL FIX: Strip whitespace/newlines that might come from config parsing
44+
clean_path = provided_path.strip()
45+
# Expand ~ to home directory if present
46+
clean_path = os.path.expanduser(clean_path)
47+
clean_path = os.path.normpath(clean_path)
48+
49+
candidates = []
50+
# If the path is a directory, look for the executable inside it
3451
if os.path.isdir(clean_path):
35-
candidate = os.path.join(clean_path, 'orca.exe') if os.name == 'nt' else os.path.join(clean_path, 'orca')
52+
candidates.append(os.path.join(clean_path, 'orca'))
53+
candidates.append(os.path.join(clean_path, 'orca.exe'))
3654
else:
37-
candidate = clean_path
38-
39-
if os.path.exists(candidate) and os.path.isfile(candidate):
40-
return os.path.abspath(candidate)
41-
42-
resolved = shutil.which(candidate)
43-
if resolved and os.path.exists(resolved):
44-
return os.path.abspath(resolved)
45-
46-
raise FileNotFoundError(f"Cannot locate ORCA executable at: {candidate}")
55+
# If it's a file path (or doesn't exist yet), use it as is
56+
candidates.append(clean_path)
57+
58+
for candidate in candidates:
59+
# Check if file exists
60+
if os.path.exists(candidate) and os.path.isfile(candidate):
61+
return os.path.abspath(candidate)
62+
63+
# Check system PATH
64+
resolved = shutil.which(candidate)
65+
if resolved and os.path.exists(resolved):
66+
return os.path.abspath(resolved)
67+
68+
# Use repr() in error message to reveal hidden characters like \n
69+
candidate_reprs = [repr(c) for c in candidates]
70+
raise FileNotFoundError(f"Cannot locate ORCA executable. Checked: {', '.join(candidate_reprs)}")
4771

4872
def _is_pople_basis(self, basis_name):
4973
if not basis_name: return False
@@ -101,7 +125,7 @@ def _setup_calculator(self, task_keyword):
101125
label_path = os.path.join(cwd, 'orca').replace('\\', '/')
102126
self.input_file = label_path + '.inp'
103127

104-
print(f"DEBUG: ASE Label Path (Forced): {label_path}")
128+
print(f"DEBUG: ASE Label Path : {label_path}")
105129

106130
simple_input = f"{self.functional} {self.basis_set} {task_keyword}"
107131

0 commit comments

Comments
 (0)