#!/usr/bin/env python3
import shutil
import os
import sys
import importlib.util
from pathlib import Path
# Colors for output
GREEN = '\033[92m'
RED = '\033[91m'
YELLOW = '\033[93m'
RESET = '\033[0m'
[docs]
def log_pass(msg) -> None:
"""Print a success message in green."""
print(f"[{GREEN}PASS{RESET}] {msg}")
[docs]
def log_fail(msg) -> None:
"""Print a failure message in red."""
print(f"[{RED}FAIL{RESET}] {msg}")
[docs]
def log_warn(msg) -> None:
"""Print a warning message in yellow."""
print(f"[{YELLOW}WARN{RESET}] {msg}")
[docs]
def check_python_dependencies() -> bool:
"""
Verify that all required Python libraries are installed and importable.
Returns:
bool: True if all critical dependencies are found.
"""
print(f"\n{'-'*20} 1. Checking Python Dependencies {'-'*20}")
required = ['numpy', 'scipy', 'matplotlib', 'ase', 'numba', 'sklearn']
all_pass = True
for lib in required:
if importlib.util.find_spec(lib) is not None:
log_pass(f"Library found: {lib}")
else:
log_fail(f"Library MISSING: {lib}")
all_pass = False
# Check EnAn package itself
if importlib.util.find_spec("ensemble_analyzer") is not None:
log_pass("Ensemble Analyzer package is installed and importable.")
else:
log_fail("Ensemble Analyzer package NOT found. Did you run 'pip install .'?")
all_pass = False
return all_pass
[docs]
def check_orca() -> bool:
"""
Verify ORCA installation and environment configuration.
Checks:
1. 'orca' executable in PATH.
2. 'ORCAVERSION' environment variable.
Returns:
bool: True if ORCA is correctly configured.
"""
print(f"\n{'-'*20} 2. Checking ORCA Configuration {'-'*20}")
# Check 1: Executable in PATH
orca_path = shutil.which("orca")
if orca_path:
log_pass(f"ORCA executable found at: {orca_path}")
else:
log_fail("ORCA executable NOT found in PATH.")
return False
# Check 2: Environment Variable
version_env = os.environ.get("ORCAVERSION")
if version_env:
log_pass(f"ORCAVERSION environment variable is set to: {version_env}")
else:
log_fail("ORCAVERSION environment variable is MISSING.")
print(f" {YELLOW}Hint: export ORCAVERSION='x.y.z' in your shell config.{RESET}")
return False
return True
[docs]
def check_gaussian() -> None:
"""
Check for Gaussian availability (Optional).
Looks for 'g16' or 'g09' in PATH.
"""
print(f"\n{'-'*20} 3. Checking Gaussian Configuration {'-'*20}")
g16_path = shutil.which("g16")
g09_path = shutil.which("g09")
if g16_path:
log_pass(f"Gaussian 16 found at: {g16_path}")
elif g09_path:
log_pass(f"Gaussian 09 found at: {g09_path}")
else:
log_warn("Gaussian executable (g16/g09) NOT found. (Optional if using ORCA)")
[docs]
def check_ml_potentials() -> None:
"""
Check optional ML potential dependencies (TBLite, AIMNet).
"""
print(f"\n{'-'*20} 4. Checking ML Potentials {'-'*20}")
# TBLite
if importlib.util.find_spec("tblite") is not None:
log_pass("TBLite library found.")
else:
log_warn("TBLite NOT installed. Install: pip install \"ensemble-analyzer[tblite]\"")
# AIMNet
try:
import aimnet
log_pass("aimnet found.")
except ImportError:
log_warn("aimnet NOT installed. Install: pip install \"ensemble-analyzer[aimnet]\"")
[docs]
def check_models_dir() -> None:
"""Check ENAN_MODELS_DIR environment variable."""
models_dir = os.environ.get("ENAN_MODELS_DIR")
if models_dir:
p = Path(models_dir)
if p.is_dir():
log_pass(f"ENAN_MODELS_DIR = {models_dir}")
else:
log_warn(f"ENAN_MODELS_DIR = {models_dir} (directory does not exist yet)")
else:
log_warn("ENAN_MODELS_DIR not set. ML models default to ~/.ensemble_analyzer/models/")
[docs]
def main() -> None:
"""Run the complete installation check suite."""
print(f"Running Ensemble Analyzer Installation Check...\n")
deps_ok = check_python_dependencies()
orca_ok = check_orca()
check_gaussian()
check_ml_potentials()
check_models_dir()
print(f"\n{'-'*50}")
if deps_ok and orca_ok:
print(f"{GREEN}SUCCESS: Installation looks correct! You are ready to run EnAn.{RESET}")
sys.exit(0)
else:
print(f"{RED}FAILURE: Critical issues found. Please fix the errors above.{RESET}")
sys.exit(1)
if __name__ == "__main__":
main()