Files
lammps/doc/utils/check-styles.py
tomswinburne e8fb7c7ece big update
2020-08-24 16:54:16 +02:00

249 lines
9.0 KiB
Python
Executable File

#!/usr/bin/env python3
import os, re, sys
from glob import glob
from argparse import ArgumentParser
parser = ArgumentParser(prog='check-styles.py',
description="Check style table completeness")
parser.add_argument("-v", "--verbose",
action='store_true',
help="Enable verbose output")
parser.add_argument("-d", "--doc",
help="Path to LAMMPS documentation sources")
parser.add_argument("-s", "--src",
help="Path to LAMMPS sources")
args = parser.parse_args()
verbose = args.verbose
src_dir = args.src
doc_dir = args.doc
LAMMPS_DIR = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..'))
if not src_dir:
src_dir = os.path.join(LAMMPS_DIR , 'src')
if not doc_dir:
doc_dir = os.path.join(LAMMPS_DIR, 'doc', 'src')
if not src_dir or not doc_dir:
parser.print_help()
sys.exit(1)
if not os.path.isdir(src_dir):
sys.exit(f"LAMMPS source path {src_dir} does not exist")
if not os.path.isdir(doc_dir):
sys.exit(f"LAMMPS documentation source path {doc_dir} does not exist")
headers = glob(os.path.join(src_dir, '*', '*.h'))
headers += glob(os.path.join(src_dir, '*.h'))
angle = {}
atom = {}
body = {}
bond = {}
command = {}
compute = {}
dihedral = {}
dump = {}
fix = {}
improper = {}
integrate = {}
kspace = {}
minimize = {}
pair = {}
reader = {}
region = {}
total = 0
style_pattern = re.compile(r"(.+)Style\((.+),(.+)\)")
upper = re.compile("[A-Z]+")
gpu = re.compile("(.+)/gpu$")
intel = re.compile("(.+)/intel$")
kokkos = re.compile("(.+)/kk$")
kokkos_skip = re.compile("(.+)/kk/(host|device)$")
omp = re.compile("(.+)/omp$")
opt = re.compile("(.+)/opt$")
removed = re.compile("(.*)Deprecated$")
def register_style(styles, name, info):
if name in styles:
for key, value in info.items():
styles[name][key] += value
else:
styles[name] = info
def add_suffix(styles, name):
suffix = ""
if styles[name]['gpu']:
suffix += 'g'
if styles[name]['intel']:
suffix += 'i'
if styles[name]['kokkos']:
suffix += 'k'
if styles[name]['omp']:
suffix += 'o'
if styles[name]['opt']:
suffix += 't'
if suffix:
return f"{name} ({suffix})"
else:
return name
def check_style(filename, dirname, pattern, styles, name, suffix=False, skip=set()):
with open(os.path.join(dirname, filename)) as f:
text = f.read()
matches = re.findall(pattern, text, re.MULTILINE)
counter = 0
for c in styles:
# known undocumented aliases we need to skip
if c in skip: continue
s = c
if suffix: s = add_suffix(styles, c)
if not s in matches:
if not styles[c]['removed']:
print(f"{name} style entry {s} is missing or incomplete in {filename}")
counter += 1
return counter
for header in headers:
if verbose: print("Checking ", header)
with open(header) as f:
for line in f:
matches = style_pattern.findall(line)
for m in matches:
# skip over internal styles w/o explicit documentation
style = m[1]
total += 1
if upper.match(style):
continue
# detect, process, and flag suffix styles:
info = { 'kokkos': 0, 'gpu': 0, 'intel': 0, \
'omp': 0, 'opt': 0, 'removed': 0 }
suffix = kokkos_skip.match(style)
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
# register style and suffix flags
if m[0] == 'Angle':
register_style(angle,style,info)
elif m[0] == 'Atom':
register_style(atom,style,info)
elif m[0] == 'Body':
register_style(body,style,info)
elif m[0] == 'Bond':
register_style(bond,style,info)
elif m[0] == 'Command':
register_style(command,style,info)
elif m[0] == 'Compute':
register_style(compute,style,info)
elif m[0] == 'Dihedral':
register_style(dihedral,style,info)
elif m[0] == 'Dump':
register_style(dump,style,info)
elif m[0] == 'Fix':
register_style(fix,style,info)
elif m[0] == 'Improper':
register_style(improper,style,info)
elif m[0] == 'Integrate':
register_style(integrate,style,info)
elif m[0] == 'KSpace':
register_style(kspace,style,info)
elif m[0] == 'Minimize':
register_style(minimize,style,info)
elif m[0] == 'Pair':
register_style(pair,style,info)
elif m[0] == 'Reader':
register_style(reader,style,info)
elif m[0] == 'Region':
register_style(region,style,info)
else:
print("Skipping over: ",m)
print("""Parsed style names w/o suffixes from C++ tree in %s:
Angle styles: %3d Atom styles: %3d
Body styles: %3d Bond styles: %3d
Command styles: %3d Compute styles: %3d
Dihedral styles: %3d Dump styles: %3d
Fix styles: %3d Improper styles: %3d
Integrate styles: %3d Kspace styles: %3d
Minimize styles: %3d Pair styles: %3d
Reader styles: %3d Region styles: %3d
----------------------------------------------------
Total number of styles (including suffixes): %d""" \
% (src_dir, len(angle), len(atom), len(body), len(bond), \
len(command), len(compute), len(dihedral), len(dump), \
len(fix), len(improper), len(integrate), len(kspace), \
len(minimize), len(pair), len(reader), len(region), total))
counter = 0
counter += check_style('Commands_all.rst', doc_dir, ":doc:`(.+) <.+>`",
command,'Command',suffix=False)
counter += check_style('Commands_compute.rst', doc_dir, ":doc:`(.+) <compute.+>`",
compute,'Compute',suffix=True)
counter += check_style('compute.rst', doc_dir, ":doc:`(.+) <compute.+>` -",
compute,'Compute',suffix=False)
counter += check_style('Commands_fix.rst', doc_dir, ":doc:`(.+) <fix.+>`",
fix,'Fix',skip=('python', 'NEIGH_HISTORY/omp'),suffix=True)
counter += check_style('fix.rst', doc_dir, ":doc:`(.+) <fix.+>` -",
fix,'Fix',skip=('python', 'NEIGH_HISTORY/omp'),suffix=False)
counter += check_style('Commands_pair.rst', doc_dir, ":doc:`(.+) <pair.+>`",
pair,'Pair',skip=('meam','lj/sf'),suffix=True)
counter += check_style('pair_style.rst', doc_dir, ":doc:`(.+) <pair.+>` -",
pair,'Pair',skip=('meam','lj/sf'),suffix=False)
counter += check_style('Commands_bond.rst', doc_dir, ":doc:`(.+) <bond.+>`",
bond,'Bond',suffix=True)
counter += check_style('bond_style.rst', doc_dir, ":doc:`(.+) <bond.+>` -",
bond,'Bond',suffix=False)
counter += check_style('Commands_bond.rst', doc_dir, ":doc:`(.+) <angle.+>`",
angle,'Angle',suffix=True)
counter += check_style('angle_style.rst', doc_dir, ":doc:`(.+) <angle.+>` -",
angle,'Angle',suffix=False)
counter += check_style('Commands_bond.rst', doc_dir, ":doc:`(.+) <dihedral.+>`",
dihedral,'Dihedral',suffix=True)
counter += check_style('dihedral_style.rst', doc_dir, ":doc:`(.+) <dihedral.+>` -",
dihedral,'Dihedral',suffix=False)
counter += check_style('Commands_bond.rst', doc_dir, ":doc:`(.+) <improper.+>`",
improper,'Improper',suffix=True)
counter += check_style('improper_style.rst', doc_dir, ":doc:`(.+) <improper.+>` -",
improper,'Improper',suffix=False)
counter += check_style('Commands_kspace.rst', doc_dir, ":doc:`(.+) <kspace_style>`",
kspace,'KSpace',suffix=True)
if counter:
print("Found %d issue(s) with style lists" % counter)