Skip to content

Commit

Permalink
initial commit of the aiida-cp2k cli
Browse files Browse the repository at this point in the history
  • Loading branch information
dev-zero committed Apr 24, 2020
1 parent 452350b commit c8dcc5d
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 0 deletions.
21 changes: 21 additions & 0 deletions aiida_cp2k/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-

# pylint: disable=wrong-import-position,wildcard-import
"""Base command line interface module to wire up subcommands and loading the profile."""

import click
import click_completion

from aiida.cmdline.params import options, types

# Activate the completion of parameter types provided by the click_completion package
click_completion.init()


@click.group('aiida-cp2k', context_settings={'help_option_names': ['-h', '--help']})
@options.PROFILE(type=types.ProfileParamType(load_profile=True))
def cmd_root(profile): # pylint: disable=unused-argument
"""CLI for the `aiida-cp2k` plugin."""


from .data import cmd_structure
15 changes: 15 additions & 0 deletions aiida_cp2k/cli/data/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-

# pylint: disable=cyclic-import,unused-import,wrong-import-position
"""Module with CLI commands for various data types."""

from .. import cmd_root


@cmd_root.group('data')
def cmd_data():
"""Commands to create and inspect data nodes."""


# Import the sub commands to register them with the CLI
from .structure import cmd_structure
93 changes: 93 additions & 0 deletions aiida_cp2k/cli/data/structure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
"""Command line utilities to create and inspect `StructureData` nodes from CP2K input files."""

from fractions import Fraction

import click
import numpy as np

from aiida.cmdline.params import options
from aiida.cmdline.utils import decorators, echo

from . import cmd_data


@cmd_data.group('structure')
def cmd_structure():
"""Commands to create and inspect `StructureData` nodes from CP2K input."""


@cmd_structure.command('import')
@click.argument('filename', type=click.File('r'))
@options.DRY_RUN()
@decorators.with_dbenv()
def cmd_import(filename, dry_run):
"""Import a `StructureData` from a CP2K input file."""

# pylint: disable=import-outside-toplevel,invalid-name,too-many-locals,too-many-statements,too-many-branches

from cp2k_input_tools.parser import CP2KInputParser
from aiida.orm.nodes.data.structure import StructureData, Kind, Site, symop_fract_from_ortho
from ase.geometry.cell import cell_to_cellpar, cellpar_to_cell

parser = CP2KInputParser()
tree = parser.parse(filename)

for force_eval in tree['+force_eval']:
try:
cell = force_eval['+subsys']['+cell']
kinds = force_eval['+subsys']['+kind']
coord = force_eval['+subsys']['+coord']
break # for now grab the first &COORD found
except KeyError:
continue
else:
echo.echo_error('no STRUCTURE, CELL, or KIND found in the given input file')

structure = StructureData()

# CP2K can get its cell information in two ways:
# - A, B, C: cell vectors
# - ABC: scaling of cell vectors, ALPHA_BETA_GAMMA: angles between the cell vectors (optional)

if 'a' in cell:
unit_cell = np.array([cell['a'], cell['b'], cell['c']]) # unit vectors given
cellpar = cell_to_cellpar(unit_cell)
elif 'abc' in cell:
cellpar = cell['abc'] + cell.get('alpha_beta_gamma', [90., 90., 90.])
unit_cell = cellpar_to_cell(cellpar)
else:
echo.echo_error('incomplete &CELL section')

structure.set_attribute('cell', unit_cell)

if coord.get('scaled', False):
tmat = symop_fract_from_ortho(cellpar)
else:
tmat = np.eye(3)

for kind in kinds:
name = kind['_']
element = kind.get('element', name) # TODO: support getting the element from e.g. 'Fe1'
structure.append_kind(Kind(name=name, symbols=element))

if coord.get('units', 'angstrom').lower() != 'angstrom':
echo.echo_error('unit conversion for coordinations is not (yet) supported')

for coordline in coord['*']:
# coordinates are a series of strings according to the CP2K schema
fields = coordline.split()

name = fields[0]
# positions can be fractions AND they may be scaled
position = tmat @ np.array([float(Fraction(f)) for f in fields[1:4]])

structure.append_site(Site(kind_name=name, position=position))

formula = structure.get_formula()

if dry_run:
echo.echo_success('parsed structure with formula {}'.format(formula))
else:
structure.store()
echo.echo_success('parsed and stored StructureData<{}> with formula {}'.format(structure.pk, formula))
8 changes: 8 additions & 0 deletions setup.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,17 @@
],
"aiida.workflows": [
"cp2k.base = aiida_cp2k.workchains:Cp2kBaseWorkChain"
],
"console_scripts": [
"aiida-cp2k = aiida_cp2k.cli:cmd_root"
]
},
"extras_require": {
"cli": [
"click",
"click-completion",
"cp2k-input-tools"
],
"test": [
"pgtest==1.2.0",
"pytest>=4.4,<5.0.0",
Expand Down

0 comments on commit c8dcc5d

Please sign in to comment.