mirror of
https://github.com/pfloos/quack
synced 2024-12-31 08:36:05 +01:00
workflow for testing
This commit is contained in:
parent
1cccc81c0d
commit
8bf9c44027
25
.github/workflows/compilation.yml
vendored
25
.github/workflows/compilation.yml
vendored
@ -11,27 +11,30 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
configuration:
|
build:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
name: Dependencies
|
name: Dependencies
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: install dependencies
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt install gfortran gcc liblapack-dev libblas-dev wget python3 make m4 pkg-config
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y gfortran gcc liblapack-dev libblas-dev wget python3 make m4 pkg-config
|
||||||
|
|
||||||
compilation:
|
|
||||||
name: Compilation
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Configuration
|
- name: Configuration
|
||||||
run: |
|
run: |
|
||||||
./configure -i ninja || :
|
./configure -i ninja || :
|
||||||
|
|
||||||
- name: Compilation
|
- name: Compilation
|
||||||
run: |
|
run: |
|
||||||
bash -c "source quack.rc ; cd src ; exec make"
|
bash -c "source quack.rc ; cd src ; make"
|
||||||
|
|
||||||
|
|
||||||
|
- name: Upload compiled binary
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: fortran-binary
|
||||||
|
path: ./bin/QuAcK
|
||||||
|
|
||||||
|
37
.github/workflows/testing.yml
vendored
Normal file
37
.github/workflows/testing.yml
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
name: QuAcK Testing
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: ["QuAcK Compilation"]
|
||||||
|
types:
|
||||||
|
- completed
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Download compiled binary from previous workflow
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: fortran-binary
|
||||||
|
path: ./bin/QuAcK
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
|
||||||
|
- name: Install Python dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install pyscf
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: |
|
||||||
|
bash -c "source quack.rc ; cd tests ; python lunch_bench.py -s light -t 1e-1"
|
||||||
|
|
@ -212,7 +212,7 @@ program QuAcK
|
|||||||
|
|
||||||
dotest = doRtest .or. doUtest .or. doGtest
|
dotest = doRtest .or. doUtest .or. doGtest
|
||||||
|
|
||||||
if(dotest) call init_test(doRtest,doUtest,doGtest)
|
if(dotest) call init_test(working_dir,doRtest,doUtest,doGtest)
|
||||||
|
|
||||||
!-------------------------!
|
!-------------------------!
|
||||||
! Restricted QuAcK branch !
|
! Restricted QuAcK branch !
|
||||||
|
@ -1,21 +1,41 @@
|
|||||||
subroutine init_test(doRtest,doUtest,doGtest)
|
subroutine init_test(working_dir,doRtest,doUtest,doGtest)
|
||||||
|
|
||||||
implicit none
|
implicit none
|
||||||
|
|
||||||
! Input variables
|
! Input variables
|
||||||
|
|
||||||
|
character(len=256),intent(in) :: working_dir
|
||||||
logical,intent(in) :: doRtest
|
logical,intent(in) :: doRtest
|
||||||
logical,intent(in) :: doUtest
|
logical,intent(in) :: doUtest
|
||||||
logical,intent(in) :: doGtest
|
logical,intent(in) :: doGtest
|
||||||
|
|
||||||
! Local variables
|
! Local variables
|
||||||
|
|
||||||
|
integer :: status
|
||||||
|
character(len=256) :: file_path
|
||||||
|
|
||||||
! Output variables
|
! Output variables
|
||||||
|
|
||||||
if(doRtest) open(unit=1231597, file='test/Rtest.dat')
|
if(doRtest) then
|
||||||
|
file_path = trim(working_dir) // '/test/Rtest.dat'
|
||||||
|
open(unit=1231597, file=file_path, iostat=status)
|
||||||
|
if(status /= 0) then
|
||||||
|
print *, "Error opening file: ", file_path
|
||||||
|
stop
|
||||||
|
else
|
||||||
|
print *, "opening file successed"
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
if(doUtest) open(unit=1232584, file='test/Utest.dat')
|
if(doUtest) then
|
||||||
|
file_path = trim(working_dir) // '/test/Utest.dat'
|
||||||
|
open(unit=1232584, file=file_path)
|
||||||
|
endif
|
||||||
|
|
||||||
if(doGtest) open(unit=1234181, file='test/Gtest.dat')
|
if(doGtest) then
|
||||||
|
file_path = trim(working_dir) // '/test/Gtest.dat'
|
||||||
|
open(unit=1234181, file=file_path)
|
||||||
|
endif
|
||||||
|
|
||||||
end subroutine
|
end subroutine
|
||||||
|
|
||||||
|
@ -57,11 +57,13 @@ parser.add_argument(
|
|||||||
default='light',
|
default='light',
|
||||||
help="Specify the type of data set: light (default), medium, or heavy."
|
help="Specify the type of data set: light (default), medium, or heavy."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
thresh_default = 1e-7
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-t', '--thresh',
|
'-t', '--thresh',
|
||||||
type=float,
|
type=float,
|
||||||
default=1e-7,
|
default=thresh_default,
|
||||||
help='Threshold for acceptable difference (default: 1e-8)'
|
help='Threshold for acceptable difference, default = {}'.format(thresh_default)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -91,29 +93,32 @@ print("\n\n")
|
|||||||
|
|
||||||
class Quack_Job:
|
class Quack_Job:
|
||||||
|
|
||||||
def __init__(self, mol, multip, basis, geom, methd):
|
def __init__(self, mol, multip, basis, geom, methd, workdir):
|
||||||
self.mol = mol
|
self.mol = mol
|
||||||
self.multip = multip
|
self.multip = multip
|
||||||
self.basis = basis
|
self.basis = basis
|
||||||
self.geom = geom
|
self.geom = geom
|
||||||
self.methd = methd
|
self.methd = methd
|
||||||
|
self.workdir = workdir
|
||||||
|
|
||||||
def prep_inp(self):
|
def prep_inp(self):
|
||||||
|
|
||||||
# geometry
|
# geometry
|
||||||
generate_xyz(self.geom, filename="{}/mol/{}.xyz".format(quack_root, self.mol))
|
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))
|
||||||
|
|
||||||
# input files
|
# input files
|
||||||
for inp in ["methods", "options"]:
|
for inp in ["methods", "options"]:
|
||||||
inp_file = "{}.{}".format(inp, self.methd.upper())
|
inp_file = "{}.{}".format(inp, self.methd.upper())
|
||||||
if os.path.exists("inp/{}".format(inp_file)):
|
if os.path.exists("inp/{}".format(inp_file)):
|
||||||
shutil.copy("{}/tests/inp/{}".format(quack_root, inp_file),
|
shutil.copy("{}/tests/inp/{}".format(quack_root, inp_file),
|
||||||
"{}/input/{}".format(quack_root, inp))
|
"{}/input/{}".format(self.workdir, inp))
|
||||||
else:
|
else:
|
||||||
print_col("File 'inp/{}' does not exist.".format(inp_file), "red")
|
print_col("File 'inp/{}' does not exist.".format(inp_file), "red")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def run(self, work_path):
|
def run(self):
|
||||||
|
|
||||||
def display_spinner():
|
def display_spinner():
|
||||||
spinner = ['|', '/', '-', '\\']
|
spinner = ['|', '/', '-', '\\']
|
||||||
@ -137,13 +142,14 @@ class Quack_Job:
|
|||||||
|
|
||||||
command = [
|
command = [
|
||||||
'python{}'.format(PYTHON_VERSION), 'PyDuck.py',
|
'python{}'.format(PYTHON_VERSION), 'PyDuck.py',
|
||||||
|
'--working_dir', '{}'.format(self.workdir),
|
||||||
'-x', '{}'.format(self.mol),
|
'-x', '{}'.format(self.mol),
|
||||||
'-b', '{}'.format(self.basis),
|
'-b', '{}'.format(self.basis),
|
||||||
'-m', '{}'.format(self.multip)
|
'-m', '{}'.format(self.multip)
|
||||||
]
|
]
|
||||||
#print_col(f" $ {' '.join(command)}", "magenta")
|
#print_col(f" $ {' '.join(command)}", "magenta")
|
||||||
|
|
||||||
file_out = "{}/{}/{}_{}_{}.out".format(work_path, self.methd, self.mol, self.multip, self.basis)
|
file_out = "{}/{}/{}_{}_{}.out".format(self.workdir, self.methd, self.mol, self.multip, self.basis)
|
||||||
with open(file_out, 'w') as fobj:
|
with open(file_out, 'w') as fobj:
|
||||||
result = subprocess.run(command, stdout=fobj, stderr=subprocess.PIPE, text=True)
|
result = subprocess.run(command, stdout=fobj, stderr=subprocess.PIPE, text=True)
|
||||||
if result.stderr:
|
if result.stderr:
|
||||||
@ -161,8 +167,8 @@ class Quack_Job:
|
|||||||
done_event.set()
|
done_event.set()
|
||||||
spinner_thread.join()
|
spinner_thread.join()
|
||||||
|
|
||||||
def check_data(self, data_ref):
|
def check_data(self, data_ref, test_failed_):
|
||||||
filepath = '../test/Rtest.dat'
|
filepath = '{}/test/Rtest.dat'.format(self.workdir)
|
||||||
data_new = {}
|
data_new = {}
|
||||||
try:
|
try:
|
||||||
# read data_new
|
# read data_new
|
||||||
@ -177,12 +183,14 @@ class Quack_Job:
|
|||||||
for key in data_ref:
|
for key in data_ref:
|
||||||
if key not in data_new:
|
if key not in data_new:
|
||||||
print_col(f" 😐 {key} missing ⚠️ ", "yellow")
|
print_col(f" 😐 {key} missing ⚠️ ", "yellow")
|
||||||
|
test_failed_ = True
|
||||||
else:
|
else:
|
||||||
diff = abs(data_new[key] - data_ref[key]) / (1e-15 + abs(data_ref[key]))
|
diff = abs(data_new[key] - data_ref[key]) / (1e-15 + abs(data_ref[key]))
|
||||||
if(diff <= THRESH):
|
if(diff <= THRESH):
|
||||||
print_col(f" 🙂 {key}", "green")
|
print_col(f" 🙂 {key}", "green")
|
||||||
else:
|
else:
|
||||||
print_col(f" ☹️ {key}: ❌ {data_ref[key]} ≠ {data_new[key]}", "red")
|
print_col(f" ☹️ {key}: ❌ {data_ref[key]} ≠ {data_new[key]}", "red")
|
||||||
|
test_failed_ = True
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print_col(f"Error: The file '{filepath}' does not exist.", "red")
|
print_col(f"Error: The file '{filepath}' does not exist.", "red")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -201,6 +209,11 @@ def main():
|
|||||||
work_path.mkdir(parents=True, exist_ok=True)
|
work_path.mkdir(parents=True, exist_ok=True)
|
||||||
print(f"Directory '{work_path}' created.\n")
|
print(f"Directory '{work_path}' created.\n")
|
||||||
|
|
||||||
|
# to save QuAcK output
|
||||||
|
if not os.path.exists("{}/test".format(work_path)):
|
||||||
|
os.makedirs("{}/test".format(work_path))
|
||||||
|
|
||||||
|
test_failed = False
|
||||||
for mol in molecules:
|
for mol in molecules:
|
||||||
|
|
||||||
mol_name = mol.name
|
mol_name = mol.name
|
||||||
@ -226,16 +239,23 @@ def main():
|
|||||||
if not work_methd.exists():
|
if not work_methd.exists():
|
||||||
work_methd.mkdir(parents=True, exist_ok=True)
|
work_methd.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
New_Quack_Job = Quack_Job(mol_name, mol_mult, basis_name, mol_geom, methd)
|
New_Quack_Job = Quack_Job(mol_name, mol_mult, basis_name, mol_geom, methd, work_path)
|
||||||
New_Quack_Job.prep_inp()
|
New_Quack_Job.prep_inp()
|
||||||
New_Quack_Job.run(work_path)
|
New_Quack_Job.run()
|
||||||
New_Quack_Job.check_data(basis_data)
|
|
||||||
|
test_failed_ = False
|
||||||
|
New_Quack_Job.check_data(basis_data, test_failed_)
|
||||||
|
if (test_failed_):
|
||||||
|
test_failed = True
|
||||||
|
|
||||||
print()
|
print()
|
||||||
print()
|
print()
|
||||||
print()
|
print()
|
||||||
|
|
||||||
quit()
|
if test_failed:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
db_name = '{}.db'.format(bench)
|
db_name = '{}.db'.format(bench)
|
||||||
|
2
tests/work/.gitignore
vendored
Normal file
2
tests/work/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
*
|
Loading…
Reference in New Issue
Block a user