4
1
mirror of https://github.com/pfloos/quack synced 2024-12-22 20:35:36 +01:00
quack/tests/lunch_bench.py

300 lines
8.9 KiB
Python
Raw Normal View History

2024-08-29 20:48:16 +02:00
2024-08-29 23:18:44 +02:00
import time
import threading
2024-08-29 20:48:16 +02:00
import sys
import os
import shutil
from pathlib import Path
import subprocess
import platform
from datetime import datetime
import argparse
from molecule import get_molecules_from_db
from molecule import generate_xyz
2024-08-29 23:18:44 +02:00
from utils import print_col, stdout_col
2024-08-29 20:48:16 +02:00
current_date = datetime.now()
quack_root = os.getenv('QUACK_ROOT')
# User Name
2024-11-15 18:55:39 +01:00
# Fallback to 'default_user' if USER is not set
user_name = os.getenv('USER', 'default_user')
2024-08-29 20:48:16 +02:00
# Operating System
os_name = platform.system()
os_release = platform.release()
os_version = platform.version()
# CPU Information
machine = platform.machine()
processor = platform.processor()
# System Architecture
architecture = platform.architecture()[0]
# Python Version
python_version_full = platform.python_version_tuple()
PYTHON_VERSION = "{}.{}".format(python_version_full[0], python_version_full[1])
print(f"The current date and time is {current_date.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"User Name: {user_name}")
print(f"Operating System: {os_name} {os_release} ({os_version})")
print(f"CPU: {processor} ({machine})")
print(f"System Architecture: {architecture}")
print(f"QUACK_ROOT: {quack_root}")
print(f"Python version: {python_version_full}\n\n")
parser = argparse.ArgumentParser(description="Benchmark Data Sets")
parser.add_argument(
'-s', '--set_type',
choices=['light', 'medium', 'heavy'],
default='light',
help="Specify the type of data set: light (default), medium, or heavy."
)
2024-11-15 17:22:07 +01:00
thresh_default = 1e-7
2024-08-30 00:10:19 +02:00
parser.add_argument(
'-t', '--thresh',
type=float,
2024-11-15 17:22:07 +01:00
default=thresh_default,
help='Threshold for acceptable difference, default = {}'.format(thresh_default)
2024-08-30 00:10:19 +02:00
)
2024-08-29 20:48:16 +02:00
args = parser.parse_args()
2024-08-30 00:10:19 +02:00
THRESH = args.thresh
2024-08-29 20:48:16 +02:00
if args.set_type == 'light':
bench = 'FeatherBench'
bench_title = "\n\nSelected Light Benchmark: {}\n\n".format(bench)
elif args.set_type == 'medium':
bench = 'BalanceBench'
bench_title = "\n\nSelected Medium Benchmark: {}\n\n".format(bench)
elif args.set_type == 'heavy':
bench = 'TitanBench'
bench_title = "\n\nSelected Heavy Benchmark: {}\n\n".format(bench)
else:
bench_title = "\n\nSelected Light Benchmark: {}\n\n".format(bench)
print(bench_title.center(150, '-'))
print("\n\n")
# ---
class Quack_Job:
2024-11-15 17:22:07 +01:00
def __init__(self, mol, multip, basis, geom, methd, workdir):
2024-08-29 20:48:16 +02:00
self.mol = mol
self.multip = multip
self.basis = basis
self.geom = geom
self.methd = methd
2024-11-15 17:22:07 +01:00
self.workdir = workdir
2024-08-29 20:48:16 +02:00
def prep_inp(self):
# geometry
2024-11-15 17:22:07 +01:00
if not os.path.exists("{}/mol".format(self.workdir)):
os.makedirs("{}/mol".format(self.workdir))
generate_xyz(self.geom, filename="{}/mol/{}.xyz".format(self.workdir, self.mol))
2024-08-29 20:48:16 +02:00
# input files
for inp in ["methods", "options"]:
inp_file = "{}.{}".format(inp, self.methd.upper())
if os.path.exists("inp/{}".format(inp_file)):
2024-08-30 20:38:00 +02:00
shutil.copy("{}/tests/inp/{}".format(quack_root, inp_file),
2024-11-15 17:22:07 +01:00
"{}/input/{}".format(self.workdir, inp))
2024-08-29 20:48:16 +02:00
else:
print_col("File 'inp/{}' does not exist.".format(inp_file), "red")
sys.exit(1)
2024-11-15 19:52:24 +01:00
def run_ci(self):
try:
os.chdir('..')
command = [
'python{}'.format(PYTHON_VERSION), 'PyDuck.py',
'--working_dir', '{}'.format(self.workdir),
'-x', '{}'.format(self.mol),
'-b', '{}'.format(self.basis),
'-m', '{}'.format(self.multip)
]
file_out = "{}/{}/{}_{}_{}.out".format(self.workdir, self.methd, self.mol, self.multip, self.basis)
with open(file_out, 'w') as fobj:
result = subprocess.run(command, stdout=fobj, stderr=subprocess.PIPE, text=True)
if result.stderr:
print("Error output:", result.stderr)
os.chdir('tests')
except Exception as e:
print_col(f"An error occurred: {str(e)}", "red")
2024-11-15 17:22:07 +01:00
def run(self):
2024-08-29 23:18:44 +02:00
def display_spinner():
spinner = ['|', '/', '-', '\\']
idx = 0
while not done_event.is_set():
2024-08-30 00:10:19 +02:00
stdout_col(f'\r Testing {self.methd} ({self.basis}) {spinner[idx]}', "cyan")
2024-08-29 23:18:44 +02:00
sys.stdout.flush()
idx = (idx + 1) % len(spinner)
2024-08-30 00:10:19 +02:00
time.sleep(0.05)
2024-08-31 13:30:34 +02:00
stdout_col(f'\r Testing {self.methd} ({self.basis}) \n\n', "cyan")
2024-08-29 23:18:44 +02:00
done_event = threading.Event()
spinner_thread = threading.Thread(target=display_spinner)
spinner_thread.start()
try:
os.chdir('..')
#print_col(f" Starting QuAck..", "magenta")
#print_col(f" $ cd ..", "magenta")
command = [
'python{}'.format(PYTHON_VERSION), 'PyDuck.py',
2024-11-15 17:22:07 +01:00
'--working_dir', '{}'.format(self.workdir),
2024-08-29 23:18:44 +02:00
'-x', '{}'.format(self.mol),
'-b', '{}'.format(self.basis),
'-m', '{}'.format(self.multip)
]
#print_col(f" $ {' '.join(command)}", "magenta")
2024-11-15 17:22:07 +01:00
file_out = "{}/{}/{}_{}_{}.out".format(self.workdir, self.methd, self.mol, self.multip, self.basis)
2024-08-29 23:18:44 +02:00
with open(file_out, 'w') as fobj:
result = subprocess.run(command, stdout=fobj, stderr=subprocess.PIPE, text=True)
if result.stderr:
print("Error output:", result.stderr)
os.chdir('tests')
#print_col(f" $ cd tests", "magenta")
except Exception as e:
print_col(f"An error occurred: {str(e)}", "red")
finally:
done_event.set()
spinner_thread.join()
2024-08-30 00:10:19 +02:00
2024-11-15 17:22:07 +01:00
def check_data(self, data_ref, test_failed_):
filepath = '{}/test/Rtest.dat'.format(self.workdir)
2024-08-30 00:10:19 +02:00
data_new = {}
try:
# read data_new
with open(filepath, 'r') as f:
lines = f.readlines()
for i in range(0, len(lines) - 1, 2):
key = lines[i].strip()
value = lines[i + 1].strip()
data_new[key] = float(value) # Convert value to float
# Compare with data_ref
for key in data_ref:
if key not in data_new:
print_col(f" 😐 {key} missing ⚠️ ", "yellow")
2024-11-15 17:22:07 +01:00
test_failed_ = True
2024-08-30 00:10:19 +02:00
else:
diff = abs(data_new[key] - data_ref[key]) / (1e-15 + abs(data_ref[key]))
if(diff <= THRESH):
2024-08-31 13:30:34 +02:00
print_col(f" 🙂 {key}", "green")
2024-08-30 00:10:19 +02:00
else:
2024-08-30 20:15:39 +02:00
print_col(f" ☹️ {key}: ❌ {data_ref[key]}{data_new[key]}", "red")
2024-11-15 17:22:07 +01:00
test_failed_ = True
2024-08-30 00:10:19 +02:00
except FileNotFoundError:
print_col(f"Error: The file '{filepath}' does not exist.", "red")
2024-08-30 20:38:00 +02:00
sys.exit(1)
2024-08-30 00:10:19 +02:00
except Exception as e:
print_col(f"An error occurred: {str(e)}", "red")
2024-08-30 20:38:00 +02:00
sys.exit(1)
2024-08-29 23:18:44 +02:00
2024-08-30 00:10:19 +02:00
2024-08-29 20:48:16 +02:00
# ---
def main():
work_path = Path('{}/tests/work'.format(quack_root))
if not work_path.exists():
work_path.mkdir(parents=True, exist_ok=True)
print(f"Directory '{work_path}' created.\n")
2024-11-15 19:13:05 +01:00
# for I/O
2024-11-15 17:22:07 +01:00
if not os.path.exists("{}/test".format(work_path)):
os.makedirs("{}/test".format(work_path))
2024-11-15 19:13:05 +01:00
if not os.path.exists("{}/input".format(work_path)):
os.makedirs("{}/input".format(work_path))
2024-11-15 17:22:07 +01:00
2024-11-15 19:52:24 +01:00
is_ci = os.getenv('CI')
2024-11-15 17:22:07 +01:00
test_failed = False
2024-08-29 20:48:16 +02:00
for mol in molecules:
mol_name = mol.name
mol_mult = mol.multiplicity
mol_geom = mol.geometry
mol_data = mol.properties
print_col(" Molecule: {} (2S+1 = {})".format(mol_name, mol_mult), "blue")
for mol_prop_name, mol_prop_data in mol_data.items():
methd = mol_prop_name[len('properties_'):]
if(len(mol_prop_data) == 0):
continue
for basis_name, basis_data in mol_prop_data.items():
if(len(basis_data) == 0):
continue
work_methd = Path('{}/{}'.format(work_path, methd))
if not work_methd.exists():
work_methd.mkdir(parents=True, exist_ok=True)
2024-11-15 17:22:07 +01:00
New_Quack_Job = Quack_Job(mol_name, mol_mult, basis_name, mol_geom, methd, work_path)
2024-08-29 20:48:16 +02:00
New_Quack_Job.prep_inp()
2024-11-15 19:52:24 +01:00
if is_ci:
New_Quack_Job.run_ci()
else:
New_Quack_Job.run()
2024-11-15 17:22:07 +01:00
test_failed_ = False
New_Quack_Job.check_data(basis_data, test_failed_)
if (test_failed_):
test_failed = True
2024-08-29 20:48:16 +02:00
print()
print()
print()
2024-11-15 17:22:07 +01:00
if test_failed:
sys.exit(1)
sys.exit(0)
2024-08-29 20:48:16 +02:00
db_name = '{}.db'.format(bench)
molecules = get_molecules_from_db(db_name)
main()