Refactor check_tests.py

This commit is contained in:
Richard Berger
2020-08-03 10:37:45 -04:00
parent 86c6efc04c
commit 865e853a41

View File

@ -1,16 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os, re, sys
from __future__ import print_function
from glob import glob from glob import glob
from argparse import ArgumentParser from argparse import ArgumentParser
import os, re, sys
parser = ArgumentParser(prog='check_tests.py', parser = ArgumentParser(prog='check_tests.py',
description="Check force tests for completeness") description="Check force tests for completeness")
parser.add_argument("-v", "--verbose", parser.add_argument("-v", "--verbose",
action='store_const', action='store_true',
const=True, default=False,
help="Enable verbose output") help="Enable verbose output")
parser.add_argument("-t", "--tests", parser.add_argument("-t", "--tests",
@ -20,30 +17,32 @@ parser.add_argument("-s", "--src",
args = parser.parse_args() args = parser.parse_args()
verbose = args.verbose verbose = args.verbose
src = args.src src_dir = args.src
tests = args.tests tests_dir = args.tests
if not src: LAMMPS_DIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..'))
src = os.path.join('.','..','..','src')
if not tests: if not src_dir:
tests = os.path.join(src,'..','unittest','force-styles','tests') src_dir = os.path.join(LAMMPS_DIR , 'src')
if not tests_dir:
tests_dir = os.path.join(LAMMPS_DIR, 'unittest', 'force-styles', 'tests')
try: try:
src = os.path.abspath(os.path.expanduser(src)) src_dir = os.path.abspath(os.path.expanduser(src_dir))
tests = os.path.abspath(os.path.expanduser(tests)) tests_dir = os.path.abspath(os.path.expanduser(tests_dir))
except: except:
parser.print_help() parser.print_help()
sys.exit(1) sys.exit(1)
if not os.path.isdir(src): if not os.path.isdir(src_dir):
sys.exit("LAMMPS source path %s does not exist" % src) sys.exit(f"LAMMPS source path {src_dir} does not exist")
if not os.path.isdir(tests): if not os.path.isdir(tests_dir):
sys.exit("LAMMPS test inputs path %s does not exist" % tests) sys.exit(f"LAMMPS test inputs path {tests_dir} does not exist")
headers = glob(os.path.join(src, '*', '*.h')) headers = glob(os.path.join(src_dir, '*', '*.h'))
headers += glob(os.path.join(src, '*.h')) headers += glob(os.path.join(src_dir, '*.h'))
angle = {} angle = {}
bond = {} bond = {}
@ -54,9 +53,8 @@ fix = {}
improper = {} improper = {}
kspace = {} kspace = {}
pair = {} pair = {}
total = 0
upper = re.compile("[A-Z]+") style_pattern = re.compile("(.+)Style\((.+),(.+)\)")
gpu = re.compile("(.+)/gpu$") gpu = re.compile("(.+)/gpu$")
intel = re.compile("(.+)/intel$") intel = re.compile("(.+)/intel$")
kokkos = re.compile("(.+)/kk$") kokkos = re.compile("(.+)/kk$")
@ -65,130 +63,110 @@ omp = re.compile("(.+)/omp$")
opt = re.compile("(.+)/opt$") opt = re.compile("(.+)/opt$")
removed = re.compile("(.*)Deprecated$") removed = re.compile("(.*)Deprecated$")
def register_style(list,style,info): def register_style(styles, name, info):
if style in list.keys(): if name in styles:
list[style]['gpu'] += info['gpu'] styles[name]['gpu'] += info['gpu']
list[style]['intel'] += info['intel'] styles[name]['intel'] += info['intel']
list[style]['kokkos'] += info['kokkos'] styles[name]['kokkos'] += info['kokkos']
list[style]['omp'] += info['omp'] styles[name]['omp'] += info['omp']
list[style]['opt'] += info['opt'] styles[name]['opt'] += info['opt']
list[style]['removed'] += info['removed'] styles[name]['removed'] += info['removed']
else: else:
list[style] = info styles[name] = info
def add_suffix(list,style): print("Parsing style names from C++ tree in: ", src_dir)
suffix = ""
if list[style]['gpu']:
suffix += 'g'
if list[style]['intel']:
suffix += 'i'
if list[style]['kokkos']:
suffix += 'k'
if list[style]['omp']:
suffix += 'o'
if list[style]['opt']:
suffix += 't'
if suffix:
return style + ' (' + suffix + ')'
else:
return style
print("Parsing style names from C++ tree in: ",src) for header in headers:
if verbose: print("Checking ", header)
with open(header) as f:
for line in f:
matches = style_pattern.findall(line)
for h in headers: for m in matches:
if verbose: print("Checking ", h) # skip over internal styles w/o explicit documentation
fp = open(h) style = m[1]
text = fp.read() if style.isupper():
fp.close() continue
matches = re.findall("(.+)Style\((.+),(.+)\)",text,re.MULTILINE)
for m in matches:
# skip over internal styles w/o explicit documentation # detect, process, and flag suffix styles:
style = m[1] info = { 'kokkos': 0, 'gpu': 0, 'intel': 0, \
total += 1 'omp': 0, 'opt': 0, 'removed': 0 }
if upper.match(style): suffix = kokkos_skip.match(style)
continue if suffix:
continue
suffix = gpu.match(style)
if suffix:
style = suffix.groups()[0]
info['gpu'] = 1
suffix = intel.match(style)
if suffix:
style = suffix.groups()[0]
info['intel'] = 1
suffix = kokkos.match(style)
if suffix:
style = suffix.groups()[0]
info['kokkos'] = 1
suffix = omp.match(style)
if suffix:
style = suffix.groups()[0]
info['omp'] = 1
suffix = opt.match(style)
if suffix:
style = suffix.groups()[0]
info['opt'] = 1
deprecated = removed.match(m[2])
if deprecated:
info['removed'] = 1
# detect, process, and flag suffix styles: # register style and suffix flags
info = { 'kokkos': 0, 'gpu': 0, 'intel': 0, \ if m[0] == 'Angle':
'omp': 0, 'opt': 0, 'removed': 0 } register_style(angle,style,info)
suffix = kokkos_skip.match(style) elif m[0] == 'Bond':
if suffix: register_style(bond,style,info)
continue elif m[0] == 'Dihedral':
suffix = gpu.match(style) register_style(dihedral,style,info)
if suffix: elif m[0] == 'Improper':
style = suffix.groups()[0] register_style(improper,style,info)
info['gpu'] = 1 elif m[0] == 'KSpace':
suffix = intel.match(style) register_style(kspace,style,info)
if suffix: elif m[0] == 'Pair':
style = suffix.groups()[0] register_style(pair,style,info)
info['intel'] = 1
suffix = kokkos.match(style)
if suffix:
style = suffix.groups()[0]
info['kokkos'] = 1
suffix = omp.match(style)
if suffix:
style = suffix.groups()[0]
info['omp'] = 1
suffix = opt.match(style)
if suffix:
style = suffix.groups()[0]
info['opt'] = 1
deprecated = removed.match(m[2])
if deprecated:
info['removed'] = 1
# register style and suffix flags
if m[0] == 'Angle':
register_style(angle,style,info)
elif m[0] == 'Bond':
register_style(bond,style,info)
elif m[0] == 'Dihedral':
register_style(dihedral,style,info)
elif m[0] == 'Improper':
register_style(improper,style,info)
elif m[0] == 'KSpace':
register_style(kspace,style,info)
elif m[0] == 'Pair':
register_style(pair,style,info)
counter = 0
def check_tests(name,list,yaml,search,skip=()): def check_tests(name,styles,yaml,search,skip=()):
num = 0 yaml_files = glob(os.path.join(tests_dir, yaml))
yaml_files = glob(os.path.join(tests, yaml)) tests = set()
styles = [] missing = set()
missing = [] search_pattern = re.compile(search)
for y in yaml_files: for y in yaml_files:
if verbose: print("Checking: ",y) if verbose: print("Checking: ",y)
fp = open(y) with open(y) as f:
text = fp.read() for line in f:
fp.close() matches = search_pattern.findall(line)
matches = re.findall(search,text,re.MULTILINE) for m in matches:
for m in matches: if m[1] == 'hybrid' or m[1] == 'hybrid/overlay':
if m[1] == 'hybrid' or m[1] == 'hybrid/overlay': for s in m[0].split():
for s in m[0].split(): if s in styles:
if s in list.keys(): tests.add(s)
styles.append(s) else:
else: tests.add(m[1])
styles.append(m[1]) for s in styles:
for s in list.keys():
# known undocumented aliases we need to skip # known undocumented aliases we need to skip
if s in skip: continue if s in skip: continue
if not s in styles: if not s in tests:
if not list[s]['removed']: if not styles[s]['removed']:
if verbose: print("No test for %s style %s" % (name,s)) if verbose: print("No test for %s style %s" % (name,s))
num += 1 missing.add(s)
missing.append(s)
total = len(list)
print("\nTests available for %s styles: %d of %d"
% (name,total - num, total))
missing.sort()
print("No tests for: ", missing)
return num
num_missing = len(missing)
total = len(styles)
num_tests = total - num_missing
print(f"\nTests available for {name} styles: {num_tests} of {total}")
print("No tests for: ", list(missing))
return num_missing
counter = 0
counter += check_tests('pair',pair,'*-pair-*.yaml', counter += check_tests('pair',pair,'*-pair-*.yaml',
'.*pair_style:\s*((\S+).*)?',skip=('meam','lj/sf')) '.*pair_style:\s*((\S+).*)?',skip=('meam','lj/sf'))
counter += check_tests('bond',bond,'bond-*.yaml', counter += check_tests('bond',bond,'bond-*.yaml',
@ -203,4 +181,4 @@ counter += check_tests('kspace',kspace,'kspace-*.yaml',
'.*kspace_style\s*((\S+).*)?') '.*kspace_style\s*((\S+).*)?')
total = len(pair)+len(bond)+len(angle)+len(dihedral)+len(improper)+len(kspace) total = len(pair)+len(bond)+len(angle)+len(dihedral)+len(improper)+len(kspace)
print("\nTotal tests missing: %d of %d" % (counter, total)) print(f"\nTotal tests missing: {counter} of {total}")