Skip to content

Commit

Permalink
Merge pull request #8 from chrisjsewell/develop
Browse files Browse the repository at this point in the history
v0.6.0b3 release
  • Loading branch information
chrisjsewell authored Jun 22, 2019
2 parents 9a79215 + 35a2e4f commit 59c5b25
Show file tree
Hide file tree
Showing 54 changed files with 9,839 additions and 256 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[![Build Status](https://travis-ci.org/chrisjsewell/aiida-crystal17.svg?branch=master)](https://travis-ci.org/chrisjsewell/aiida-crystal17)
[![Coverage Status](https://coveralls.io/repos/github/chrisjsewell/aiida-crystal17/badge.svg?branch=master)](https://coveralls.io/github/chrisjsewell/aiida-crystal17?branch=master)
[![Docs status](https://readthedocs.org/projects/aiida-crystal17/badge)](http://aiida-crystal17.readthedocs.io/)
[![Docs status](https://readthedocs.org/projects/aiida-crystal17/badge)](http://aiida-crystal17.readthedocs.io/)
[![PyPI](https://img.shields.io/pypi/v/aiida-crystal17.svg)](https://pypi.python.org/pypi/aiida-crystal17/)
[![Anaconda-Server Badge](https://anaconda.org/conda-forge/aiida-crystal17/badges/version.svg)](https://anaconda.org/conda-forge/aiida-crystal17)

# aiida-crystal17

AiiDA plugin for running the [CRYSTAL17](http://www.crystal.unito.it/) code.
The code is principally tested against CRYSTAL17,
The code is principally tested against CRYSTAL17,
but the output parsing has also been tested against CRYSTAL14.

**Documentation**: https://readthedocs.org/projects/aiida-crystal17
Expand All @@ -17,8 +17,7 @@ but the output parsing has also been tested against CRYSTAL14.
To install from Conda (recommended)::

```shell
>> conda install -c conda-forge aiida-crystal17
>> conda install -c bioconda chainmap==1.0.2
>> conda install -c conda-forge aiida-crystal17 aiida-core.services
```

To install from pypi::
Expand Down Expand Up @@ -54,7 +53,7 @@ To omit tests which call `runcry17`:
>> pytest -v -m "not process_execution"
```

or alternatively to call the `mock_runcry17` executable,
or alternatively to call the `mock_runcry17` executable,
first set the global environmental variable:

```shell
Expand Down
2 changes: 1 addition & 1 deletion aiida_crystal17/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
AiiDA plugin for running the CRYSTAL17 code
"""

__version__ = "0.5.0b3"
__version__ = "0.6.0b3"
33 changes: 29 additions & 4 deletions aiida_crystal17/calculations/cry_abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,46 @@ def define(cls, spec):
message=('An error was flagged trying to parse the '
'main crystal output file'))

spec.exit_code(
350, 'ERROR_CRYSTAL_INPUT',
message='the input file was could not be read by CRYSTAL')
spec.exit_code(
351, 'ERROR_WAVEFUNCTION_NOT_FOUND',
message='CRYSTAL could not find the required wavefunction file')

# Significant errors but calculation can be used to restart
spec.exit_code(
400, 'ERROR_CRYSTAL_RUN',
message='The main crystal output file flagged an error')
401, 'UNCONVERGED_SCF',
message='SCF convergence did not finalise (usually due to reaching step limit)')
spec.exit_code(
402, 'UNCONVERGED_GEOMETRY',
message='Geometry convergence did not finalise (usually due to reaching step limit)')
spec.exit_code(
410, 'ERROR_SCF_ABNORMAL_END',
message='an error was encountered during an SCF computation')
spec.exit_code(
411, 'BASIS_SET_LINEARLY_DEPENDENT',
message='an error encountered usually during geometry optimisation')
spec.exit_code(
412, 'ERROR_MPI_ABORT',
message='an unknown error was encountered, causing the MPI to abort')
spec.exit_code(
499, 'ERROR_CRYSTAL_RUN',
message='The main crystal output file flagged an unhandled error')

# errors in symmetry node consistency check
spec.exit_code(
410, 'ERROR_SYMMETRY_INCONSISTENCY',
510, 'ERROR_SYMMETRY_INCONSISTENCY',
message=('inconsistency in the input and output symmetry'))
spec.exit_code(
420, 'ERROR_SYMMETRY_NOT_FOUND',
520, 'ERROR_SYMMETRY_NOT_FOUND',
message=('primitive symmops were not found in the output file'))

spec.output(cls.link_output_results,
valid_type=DataFactory('dict'),
required=True,
help='the data extracted from the main output file')
spec.default_output_node = cls.link_output_results
spec.output(cls.link_output_structure,
valid_type=DataFactory('structure'),
required=False,
Expand Down
4 changes: 2 additions & 2 deletions aiida_crystal17/calculations/cry_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
from aiida.plugins import DataFactory

from aiida_crystal17.calculations.cry_abstract import CryAbstractCalculation
from aiida_crystal17.parsers.gui_parse import gui_file_write
from aiida_crystal17.parsers.inputd12_write import (
from aiida_crystal17.parsers.raw.gui_parse import gui_file_write
from aiida_crystal17.parsers.raw.inputd12_write import (
write_input, create_atom_properties)


Expand Down
1 change: 0 additions & 1 deletion aiida_crystal17/calculations/tests/test_cry_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ def test_calcjob_submission(db_test_app):
('mgo_sto3g_opt.crystal.d12', None),
('mgo_sto3g_external.crystal.d12', 'mgo_sto3g_external.crystal.gui')
))
@pytest.mark.timeout(60)
@pytest.mark.process_execution
def test_calcjob_run(db_test_app, inpath_main, inpath_gui):
# type: (AiidaTestApp, str, str) -> None
Expand Down
92 changes: 20 additions & 72 deletions aiida_crystal17/calculations/tests/test_cry_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,34 @@
import os
from textwrap import dedent # noqa: F401

from ase.spacegroup import crystal
import ejplugins
from jsonextended import edict
import pytest
from aiida.engine import run_get_node
from aiida.plugins import CalculationFactory, DataFactory, WorkflowFactory
import aiida_crystal17
from aiida_crystal17.tests import TEST_DIR
from aiida_crystal17.tests.utils import AiidaTestApp # noqa: F401


def test_create_builder(db_test_app):
def test_create_builder(db_test_app, get_structure):
# type: (AiidaTestApp) -> None
"""test preparation of inputs"""
db_test_app.get_or_create_code('crystal17.main')

inparams = {"scf.k_points": (8, 8)}

from aiida.plugins import DataFactory, CalculationFactory
structure_data_cls = DataFactory('structure')
basis_data_cls = DataFactory('crystal17.basisset')

atoms = crystal(
symbols=[12, 8],
basis=[[0, 0, 0], [0.5, 0.5, 0.5]],
spacegroup=225,
cellpar=[4.21, 4.21, 4.21, 90, 90, 90])
instruct = structure_data_cls(ase=atoms)
instruct = get_structure("MgO")
mg_basis, _ = basis_data_cls.get_or_create(
os.path.join(TEST_DIR, "input_files", "sto3g", 'sto3g_Mg.basis'))
o_basis, _ = basis_data_cls.get_or_create(
os.path.join(TEST_DIR, "input_files", "sto3g", 'sto3g_O.basis'))

from aiida_crystal17.workflows.symmetrise_3d_struct import (
Symmetrise3DStructure)
sym_calc = run_get_node(
Symmetrise3DStructure, structure=instruct, symprec=0.01,
WorkflowFactory("crystal17.sym3d"), structure=instruct, symprec=0.01,
compute={"primitive": True}).node
instruct = sym_calc.get_outgoing().get_node_by_label("structure")
symmetry = sym_calc.get_outgoing().get_node_by_label("symmetry")
Expand All @@ -57,12 +49,11 @@ def test_create_builder(db_test_app):
"input_symmetry",
(False, True)
)
def test_calcjob_submit_mgo(db_test_app, input_symmetry):
def test_calcjob_submit_mgo(db_test_app, input_symmetry, get_structure):
# type: (AiidaTestApp, bool) -> None
"""Test submitting a calculation"""
from aiida.plugins import DataFactory

param_data_cls = DataFactory('crystal17.parameters')
structure_data_cls = DataFactory('structure')
basis_data_cls = DataFactory('crystal17.basisset')

code = db_test_app.get_or_create_code('crystal17.main')
Expand All @@ -75,18 +66,10 @@ def test_calcjob_submit_mgo(db_test_app, input_symmetry):
}
})

# MgO
atoms = crystal(
symbols=[12, 8],
basis=[[0, 0, 0], [0.5, 0.5, 0.5]],
spacegroup=225,
cellpar=[4.21, 4.21, 4.21, 90, 90, 90])
instruct = structure_data_cls(ase=atoms)
instruct = get_structure("MgO")

from aiida_crystal17.workflows.symmetrise_3d_struct import (
Symmetrise3DStructure)
sym_calc = run_get_node(
Symmetrise3DStructure, structure=instruct, symprec=0.01,
WorkflowFactory("crystal17.sym3d"), structure=instruct, symprec=0.01,
compute={"primitive": True}).node
instruct = sym_calc.get_outgoing().get_node_by_label("structure")
symmetry = sym_calc.get_outgoing().get_node_by_label("symmetry")
Expand Down Expand Up @@ -164,12 +147,10 @@ def test_calcjob_submit_mgo(db_test_app, input_symmetry):
# assert gui_content == expected_gui


def test_calcjob_submit_nio_afm(db_test_app):
def test_calcjob_submit_nio_afm(db_test_app, get_structure):
# type: (AiidaTestApp) -> None
"""Test submitting a calculation"""
from aiida.engine import run_get_node
from aiida.plugins import DataFactory
structure_data_cls = DataFactory('structure')

kind_data_cls = DataFactory('crystal17.kinds')
basis_data_cls = DataFactory('crystal17.basisset')
upload_basisset_family = basis_data_cls.upload_basisset_family
Expand All @@ -187,23 +168,14 @@ def test_calcjob_submit_nio_afm(db_test_app):
"scf.post_scf": ["PPAN"]
}

# Ni0
atoms = crystal(
symbols=[28, 8],
basis=[[0, 0, 0], [0.5, 0.5, 0.5]],
spacegroup=225,
cellpar=[4.164, 4.164, 4.164, 90, 90, 90])
atoms.set_tags([1, 1, 2, 2, 0, 0, 0, 0])
instruct = structure_data_cls(ase=atoms)
instruct = get_structure("NiO_afm")

kind_data = kind_data_cls(data={
"kind_names": ["Ni1", "Ni2", "O"],
"spin_alpha": [True, False, False], "spin_beta": [False, True, False]})

from aiida_crystal17.workflows.symmetrise_3d_struct import (
Symmetrise3DStructure)
sym_calc = run_get_node(
Symmetrise3DStructure, structure=instruct, symprec=0.01,
WorkflowFactory("crystal17.sym3d"), structure=instruct, symprec=0.01,
compute={"primitive": True}).node
instruct = sym_calc.get_outgoing().get_node_by_label("structure")
symmetry = sym_calc.get_outgoing().get_node_by_label("symmetry")
Expand Down Expand Up @@ -291,13 +263,10 @@ def test_calcjob_submit_nio_afm(db_test_app):
# assert gui_content == expected_gui


@pytest.mark.timeout(60)
def test_run_nio_afm_scf(db_test_app):
def test_run_nio_afm_scf(db_test_app, get_structure):
# type: (AiidaTestApp) -> None
"""Test running a calculation"""
from aiida.engine import run_get_node
from aiida.plugins import DataFactory
structure_data_cls = DataFactory('structure')

kind_data_cls = DataFactory('crystal17.kinds')
basisset_data_cls = DataFactory('crystal17.basisset')
upload_basisset_family = basisset_data_cls.upload_basisset_family
Expand All @@ -315,23 +284,14 @@ def test_run_nio_afm_scf(db_test_app):
"scf.post_scf": ["PPAN"]
}

# Ni0
atoms = crystal(
symbols=[28, 8],
basis=[[0, 0, 0], [0.5, 0.5, 0.5]],
spacegroup=225,
cellpar=[4.164, 4.164, 4.164, 90, 90, 90])
atoms.set_tags([1, 1, 2, 2, 0, 0, 0, 0])
instruct = structure_data_cls(ase=atoms)
instruct = get_structure("NiO_afm")

kind_data = kind_data_cls(data={
"kind_names": ["Ni1", "Ni2", "O"],
"spin_alpha": [True, False, False], "spin_beta": [False, True, False]})

from aiida_crystal17.workflows.symmetrise_3d_struct import (
Symmetrise3DStructure)
sym_calc = run_get_node(
Symmetrise3DStructure, structure=instruct, symprec=0.01,
WorkflowFactory("crystal17.sym3d"), structure=instruct, symprec=0.01,
compute={"primitive": True}).node
instruct = sym_calc.get_outgoing().get_node_by_label("structure")
symmetry = sym_calc.get_outgoing().get_node_by_label("symmetry")
Expand Down Expand Up @@ -395,14 +355,11 @@ def test_run_nio_afm_scf(db_test_app):
assert edict.diff(attributes, expected_results, np_allclose=True) == {}


@pytest.mark.timeout(60)
@pytest.mark.process_execution
def test_run_nio_afm_fullopt(db_test_app):
def test_run_nio_afm_fullopt(db_test_app, get_structure):
# type: (AiidaTestApp) -> None
"""Test running a calculation"""
from aiida.engine import run_get_node
from aiida.plugins import DataFactory
structure_data_cls = DataFactory('structure')

kind_data_cls = DataFactory('crystal17.kinds')
basis_data_cls = DataFactory('crystal17.basisset')
upload_basisset_family = basis_data_cls.upload_basisset_family
Expand All @@ -420,23 +377,14 @@ def test_run_nio_afm_fullopt(db_test_app):
"scf.post_scf": ["PPAN"]
}

# Ni0
atoms = crystal(
symbols=[28, 8],
basis=[[0, 0, 0], [0.5, 0.5, 0.5]],
spacegroup=225,
cellpar=[4.164, 4.164, 4.164, 90, 90, 90])
atoms.set_tags([1, 1, 2, 2, 0, 0, 0, 0])
instruct = structure_data_cls(ase=atoms)
instruct = get_structure("NiO_afm")

kind_data = kind_data_cls(data={
"kind_names": ["Ni1", "Ni2", "O"],
"spin_alpha": [True, False, False], "spin_beta": [False, True, False]})

from aiida_crystal17.workflows.symmetrise_3d_struct import (
Symmetrise3DStructure)
sym_calc = run_get_node(
Symmetrise3DStructure, structure=instruct, symprec=0.01,
WorkflowFactory("crystal17.sym3d"), structure=instruct, symprec=0.01,
compute={"primitive": True}).node
instruct = sym_calc.get_outgoing().get_node_by_label("structure")
symmetry = sym_calc.get_outgoing().get_node_by_label("symmetry")
Expand Down
11 changes: 11 additions & 0 deletions aiida_crystal17/data/symmetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from jsonschema import ValidationError as SchemeError
import numpy as np
import spglib

from aiida.common.utils import classproperty
# from aiida.common.exceptions import ValidationError
Expand Down Expand Up @@ -169,6 +170,16 @@ def num_symops(self):
def hall_number(self):
return self.get_attribute("hall_number", None)

@property
def spacegroup_info(self):
""" Translate Hall number to space group type information.
Returned as an attribute dict
"""
info = spglib.get_spacegroup_type(self.hall_number)
if info is None:
raise ValueError("the hall number could not be converted")
return AttributeDict(info)

def add_path(self, src_abs, dst_path):
from aiida.common.exceptions import ModificationNotAllowed

Expand Down
8 changes: 6 additions & 2 deletions aiida_crystal17/gulp/calculations/gulp_abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def define(cls, spec):
help=('atomic structure used to create the '
'geometry section of .gin file content.'))
spec.input(
'potential', valid_type=DataFactory('dict'),
'potential', valid_type=DataFactory('gulp.potential'),
required=True,
help=('parameters to create the '
'potential section of the .gin file content.'))
Expand Down Expand Up @@ -74,12 +74,16 @@ def define(cls, spec):
# Significant errors but calculation can be used to restart
spec.exit_code(
400, 'ERROR_GULP_RUN',
message='The main gulp output file flagged an error')
message='The main gulp output file flagged an unknown error')
spec.exit_code(
410, 'ERROR_NOT_OPTIMISED',
message='The main gulp output file did not signal that an expected optimisation completed')

spec.output(cls.link_output_results,
valid_type=DataFactory('dict'),
required=True,
help='the data extracted from the main output file')
spec.default_output_node = cls.link_output_results

def prepare_for_submission(self, tempfolder):
"""
Expand Down
Loading

0 comments on commit 59c5b25

Please sign in to comment.