1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
import os
import os.path as op
import sys
from ase.io import read
from ase.io.formats import filetype, UnknownFileTypeError
from ase.db import connect
from ase.db.core import parse_selection
from ase.db.jsondb import JSONDatabase
from ase.db.row import atoms2dict
class CLICommand:
"""Find files with atoms in them.
Search through files known to ASE applying a query to filter the results.
See https://wiki.fysik.dtu.dk/ase/ase/db/db.html#querying for more
informations on how to construct the query string.
"""
@staticmethod
def add_arguments(parser):
parser.add_argument('folder', help='Folder to look in.')
parser.add_argument(
'query', nargs='?',
help='Examples: More than 2 hydrogens and no silver: "H>2,Ag=0". '
'More than 1000 atoms: "natoms>1000". '
'Slab geometry containing Cu and Ni: "pbc=TTF,Cu,Ni".')
parser.add_argument('-v', '--verbose', action='store_true',
help='More output.')
parser.add_argument('-l', '--long', action='store_true',
help='Show also periodic boundary conditions, '
'chemical formula and filetype.')
parser.add_argument('-i', '--include', help='Include only filenames '
'ending with given strings. Example: '
'"-i .xyz,.traj".')
parser.add_argument('-x', '--exclude', help='Exclude filenames '
'ending with given strings. Example: '
'"-x .cif".')
@staticmethod
def run(args):
main(args)
def main(args):
query = parse_selection(args.query)
include = args.include.split(',') if args.include else []
exclude = args.exclude.split(',') if args.exclude else []
if args.long:
print('pbc {:10} {:15} path'.format('formula', 'filetype'))
for path in allpaths(args.folder, include, exclude):
format, row = check(path, query, args.verbose)
if format:
if args.long:
print('{} {:10} {:15} {}'
.format(''.join(str(p) for p in row.pbc.astype(int)),
row.formula,
format,
path))
else:
print(path)
def allpaths(folder, include, exclude):
"""Generate paths."""
exclude += ['.py', '.pyc']
for dirpath, dirnames, filenames in os.walk(folder):
for name in filenames:
if any(name.endswith(ext) for ext in exclude):
continue
if include:
for ext in include:
if name.endswith(ext):
break
else:
continue
path = op.join(dirpath, name)
yield path
# Skip .git, __pycache__ and friends:
dirnames[:] = (name for name in dirnames if name[0] not in '._')
def check(path, query, verbose):
"""Check a path.
Returns a (filetype, AtomsRow object) tuple.
"""
try:
format = filetype(path, guess=False)
except (OSError, UnknownFileTypeError):
return '', None
if format in ['db', 'json']:
db = connect(path)
else:
try:
atoms = read(path, format=format)
except Exception as x:
if verbose:
print(path + ':', x, file=sys.stderr)
return '', None
db = FakeDB(atoms)
try:
for row in db._select(*query):
return format, row
except Exception as x:
if verbose:
print(path + ':', x, file=sys.stderr)
return '', None
class FakeDB(JSONDatabase):
def __init__(self, atoms):
self.bigdct = {1: atoms2dict(atoms)}
def _read_json(self):
return self.bigdct, [1], 2
|