diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da3c451f4..28bfc4963 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ jobs: docs: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v1 @@ -37,7 +37,7 @@ jobs: pre-commit: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 timeout-minutes: 30 steps: @@ -69,7 +69,7 @@ jobs: tests: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 timeout-minutes: 30 strategy: @@ -120,3 +120,9 @@ jobs: touch local_exe/inpgen && chmod +x local_exe/inpgen touch local_exe/fleur && chmod +x local_exe/fleur ./run_all_cov.sh + + - name: Upload report to Codecov + uses: codecov/codecov-action@v1 + with: + file: ./tests/coverage.xml + fail_ci_if_error: False diff --git a/.gitignore b/.gitignore index f2abc28d4..6c5af7cf9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Created by https://www.gitignore.io/api/python,linux,macos - +# +.aiida/ submit_test/ ### Python ### diff --git a/CHANGELOG.md b/CHANGELOG.md index 58e0f27ae..0f44c7d3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## v1.1.3 +### release compatible with AiiDA-core 1.3.0 +- still support of Fleur MaXR4 version with inpgen +- Does not support yet for Fleur MaXR5 and new inpgen +- Set_kpoints was moved from fleurinp to fleurinpmodifier +- Break_symmetry of a structure was refactored +- Implemented feature in fleurinputCalculation to set significant figures +- Implemented feature scf can now use default queues specified in code extras +- First implementation of relax type None, which cases the relax workchain to skip the +relaxation, becoming a usual scf wc, which might make it easier to switch relaxation on +and off in other workchains. +- Fleur parser parses now the total magnetic moment of the cell +- Introduced common constants, for bohr and htr, increased precision +- Command line interface (CLI) `aiida-fleur` with various functionalities exposed +- For devs: Increased test coverage, codecov is now added to CI and linked to badge +removed some older outdated code ## v1.1.2 ### release compatible with AiiDA-core 1.3.0 diff --git a/README.md b/README.md index 76f80fb5e..a445d85c1 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,10 @@ [![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![GitHub release](https://img.shields.io/github/release/JuDFTteam/aiida-fleur.svg)](https://github.com/JuDFTteam/aiida-fleur/releases) [![PyPI version](https://badge.fury.io/py/aiida-fleur.svg)](https://badge.fury.io/py/aiida-fleur) -[![Build develop](https://travis-ci.org/JuDFTteam/aiida-fleur.svg?branch=master)](https://travis-ci.org/JuDFTteam/aiida-fleur) -[![Coveralls github branch](https://github.com/JuDFTteam/aiida-fleur/blob/develop/aiida_fleur/tests/coverage.svg)](https://github.com/JuDFTteam/aiida-fleur/tree/develop) -[![Code quality pylint](https://github.com/JuDFTteam/aiida-fleur/blob/develop/aiida_fleur/tests/pylint.svg)](https://github.com/JuDFTteam/aiida-fleur/tree/develop) +[![PyPI pyversions](https://img.shields.io/pypi/pyversions/aiida-fleur.svg)](https://pypi.python.org/pypi/aiida-fleur) +[![Build status](https://github.com/JuDFTteam/aiida-fleur/workflows/aiida-fleur/badge.svg?branch=develop&event=push)](https://github.com/JuDFTteam/aiida-fleur/actions) [![Documentation Status](https://readthedocs.org/projects/aiida-fleur/badge/?version=develop)](https://aiida-fleur.readthedocs.io/en/develop/?badge=develop) +[![codecov](https://codecov.io/gh/JuDFTteam/aiida-fleur/branch/develop/graph/badge.svg)](https://codecov.io/gh/JuDFTteam/aiida-fleur) This software contains a plugin that enables the usage of the all-electron @@ -14,6 +14,12 @@ DFT [FLEUR code](http://www.flapw.de) with the [AiiDA framework](http://www.aiid Developed at [Forschungszentrum Jülich GmbH](http://www.fz-juelich.de/pgi/pgi-1/DE/Home/home_node.html) +## Compatibility matrix + +| FLEUR Plugin | AiiDA CORE | Python | FLEUR | +|-|-|-|-| +| `v1.0.0 < v2.0.0` | | [![PyPI pyversions](https://img.shields.io/pypi/pyversions/aiida-fleur.svg)](https://pypi.org/project/aiida-fleur.svg) | MaXR1 < MaXR5 (v0.29)| +| `< v0.6.3` | | [![PyPI pyversions](https://img.shields.io/pypi/pyversions/aiida-fleur/0.6.svg)](https://pypi.python.org/pypi/aiida-fleur/0.6.3/) | MaXR1 < MaXR3 (v0.28)| ### Documentation @@ -37,7 +43,7 @@ In Extreme Data Workshop 2018 Proceedings, 2019, vol 40, p 43-48 ### Comments/Disclaimer: -The plug-in and the workflows will only work with a Fleur version using xml files as I/O. +The plug-in and the workflows will only work with a Fleur version using xml files as I/O, i.e >v0.27. ### Contents @@ -94,6 +100,49 @@ read_cif.py | This can be used as stand-alone to create StructureData nodes from Utility and tools, which are independend of AiiDA are moved to the [masci-tools](https://github.com/JuDFTteam/masci-tools) (material science tools) repository, which is a dependency of aiida-fleur. + +### Command line interface (CLI) + +Besides the python API, aiida-fleur comes with a builtin CLI: `aiida-fleur`. +This interface is built using the click library and supports tab-completion. + +To enable tab-completion, add the following to your shell loading script, e.g. the .bashrc or virtual environment activate script: + + eval "$(_AIIDA_FLEUR_COMPLETE=source aiida-fleur)" + +the main subcommands include: + + data: Commands to create and inspect data nodes + fleurinp Commands to handle `FleurinpData` nodes. + parameter Commands to create and inspect `Dict` nodes containing FLAPW parameters + structure Commands to create and inspect `StructureData` nodes. + launch: Commands to launch workflows and calcjobs of aiida-fleur + + banddos Launch a banddos workchain + corehole Launch a corehole workchain + create_magnetic Launch a create_magnetic workchain + dmi Launch a dmi workchain + eos Launch a eos workchain + fleur Launch a base_fleur workchain. + init_cls Launch an init_cls workchain + inpgen Launch an inpgen calcjob on given input If no code is... + mae Launch a mae workchain + relax Launch a base relax workchain # TODO final scf input + scf Launch a scf workchain + ssdisp Launch a ssdisp workchain + + plot: Invoke the plot_fleur command on given nodes + + workflow: Commands to inspect aiida-fleur workchains and prepare inputs + +for example to launch an scf workchain on a given structure execute: + + $ aiida-fleur launch scf -i -f -S + +the command can also process structures in any format `ase` can handle, this includes `Cif`, `xsf` and `poscar` files. In such a case simply parse the path to the file: + + $ aiida-fleur launch scf -i -f -S ./structure/Cu.cif + ## Installation Instructions From the aiida-fleur folder (after downloading the code, recommended) use: @@ -154,7 +203,7 @@ Mainly AiiDA: Easy plotting and other useful routines that do not depend on aiida_core are part of the [masci-tools](https://github.com/JuDFTteam/masci-tools) (material science tools) repository. -For easy ploting we recommend using 'plot_methods' from masci-tools, which are also deployed by the 'plot_fleur()' function. +For easy plotting we recommend using 'plot_methods' from masci-tools, which are also deployed by the 'plot_fleur()' function. ## Further Information diff --git a/aiida_fleur/__init__.py b/aiida_fleur/__init__.py index 521641094..41430d285 100644 --- a/aiida_fleur/__init__.py +++ b/aiida_fleur/__init__.py @@ -12,4 +12,4 @@ ''' AiiDA-FLEUR ''' -__version__ = '1.1.2' +__version__ = '1.1.3' diff --git a/aiida_fleur/calculation/fleur.py b/aiida_fleur/calculation/fleur.py index 1de9a4d76..344407326 100644 --- a/aiida_fleur/calculation/fleur.py +++ b/aiida_fleur/calculation/fleur.py @@ -193,7 +193,7 @@ class FleurCalculation(CalcJob): @classmethod def define(cls, spec): - super(FleurCalculation, cls).define(spec) + super().define(spec) # spec.input('metadata.options.input_filename', valid_type=six.string_types, # default=cls._INPXML_FILE_NAME) diff --git a/aiida_fleur/calculation/fleurinputgen.py b/aiida_fleur/calculation/fleurinputgen.py index 4fbb5758d..6d1a123c2 100644 --- a/aiida_fleur/calculation/fleurinputgen.py +++ b/aiida_fleur/calculation/fleurinputgen.py @@ -28,7 +28,7 @@ from aiida_fleur.data.fleurinp import FleurinpData from aiida_fleur.tools.StructureData_util import abs_to_rel_f, abs_to_rel from aiida_fleur.tools.xml_util import convert_to_fortran_bool, convert_to_fortran_string -from aiida_fleur.common.constants import bohr_a +from aiida_fleur.common.constants import BOHR_A class FleurinputgenCalculation(CalcJob): @@ -37,7 +37,7 @@ class FleurinputgenCalculation(CalcJob): For more information about produced files and the FLEUR-code family, go to http://www.flapw.de/. """ - __version__ = '1.2.1' + __version__ = '1.2.2' # Default input and output files _INPUT_FILE = 'aiida.in' # will be shown with inputcat @@ -51,7 +51,10 @@ class FleurinputgenCalculation(CalcJob): _ERROR_FILE_NAME = 'out.error' _STRUCT_FILE_NAME = 'struct.xsf' - _settings_keys = ['additional_retrieve_list', 'remove_from_retrieve_list', 'cmdline'] + _settings_keys = [ + 'additional_retrieve_list', 'remove_from_retrieve_list', 'cmdline', 'significant_figures_cell', + 'significant_figures_positions' + ] # TODO switch all these to init_internal_params? _OUTPUT_SUBFOLDER = './fleur_inp_out/' _PREFIX = 'aiida' @@ -97,7 +100,7 @@ class FleurinputgenCalculation(CalcJob): @classmethod def define(cls, spec): - super(FleurinputgenCalculation, cls).define(spec) + super().define(spec) spec.input('metadata.options.input_filename', valid_type=six.string_types, default=cls._INPUT_FILE) spec.input('metadata.options.output_filename', valid_type=six.string_types, default=cls._INPXML_FILE_NAME) @@ -136,7 +139,7 @@ def define(cls, spec): 'ERROR_FLEURINPDATA_INPUT_NOT_VALID', message=('During parsing: FleurinpData could not be initialized, see log. ' 'Maybe no Schemafile was found or the Fleurinput is not valid.')) - spec.exit_code(309, 'ERROR_FLEURINPDATE_NOT_VALID', message='During parsing: FleurinpData failed validation.') + spec.exit_code(309, 'ERROR_FLEURINPDATA_NOT_VALID', message='During parsing: FleurinpData failed validation.') def prepare_for_submission(self, folder): """ @@ -170,7 +173,7 @@ def prepare_for_submission(self, folder): # but we have to convert from Angstrom to a.u (bohr radii) scaling_factors = [1.0, 1.0, 1.0] scaling_lat = 1. # /bohr_to_ang = 0.52917720859 - scaling_pos = 1. / bohr_a # Angstrom to atomic + scaling_pos = 1. / BOHR_A # Angstrom to atomic own_lattice = False # not self._use_aiida_structure ########################################## @@ -258,7 +261,8 @@ def prepare_for_submission(self, folder): if self._use_aiida_structure: input_params.pop('lattice', {}) own_lattice = False - + #TODO check if input parameter dict is consistent to given structure. + # if not issue warnings. # TODO allow only usual kpt meshes and use therefore Aiida kpointData # if self._use_kpoints: # try: @@ -301,14 +305,18 @@ def prepare_for_submission(self, folder): scaling_factor_card = '' cell_parameters_card = '' - + # We allow to set the significant figures format, because sometimes + # inpgen has numerical problems which are not there with less precise formatting + sf_c = str(settings_dict.get('significant_figures_cell', 9)) + sf_p = str(settings_dict.get('significant_figure_positions', 10)) if not own_lattice: cell = structure.cell for vector in cell: scaled = [a * scaling_pos for a in vector] # scaling_pos=1./bohr_to_ang - cell_parameters_card += ('{0:18.9f} {1:18.9f} {2:18.9f}' '\n'.format(scaled[0], scaled[1], scaled[2])) - scaling_factor_card += ('{0:18.9f} {1:18.9f} {2:18.9f}' - '\n'.format(scaling_factors[0], scaling_factors[1], scaling_factors[2])) + reg_string = '{0:18.' + sf_c + 'f} {1:18.' + sf_c + 'f} {2:18.' + sf_c + 'f}\n' + cell_parameters_card += (reg_string.format(scaled[0], scaled[1], scaled[2])) + reg_string = '{0:18.' + sf_c + 'f} {1:18.' + sf_c + 'f} {2:18.' + sf_c + 'f}\n' + scaling_factor_card += (reg_string.format(scaling_factors[0], scaling_factors[1], scaling_factors[2])) #### ATOMIC_POSITIONS #### @@ -348,24 +356,27 @@ def prepare_for_submission(self, folder): vector_rel = abs_to_rel_f(pos, cell, structure.pbc) vector_rel[2] = vector_rel[2] * scaling_pos - if site_symbol != kind_name: # This is an important fact, if user renames it becomes a new specie! + if site_symbol != kind_name: # This is an important fact, if user renames it becomes a new atomtype or species! try: + # Kind names can be more then numbers now, this might need to be reworked head = kind_name.rstrip('0123456789') kind_namet = int(kind_name[len(head):]) - if int(kind_name[len(head)]) > 4: - raise InputValidationError('New specie name/label should start with a digit smaller than 4') + #if int(kind_name[len(head)]) > 4: + # raise InputValidationError('New specie name/label should start with a digit smaller than 4') except ValueError: - pass + self.report( + 'Warning: Kind name {} will be ignored by the FleurinputgenCalculation and not set a charge number.' + .format(kind_name)) else: atomic_number_name = '{}.{}'.format(atomic_number, kind_namet) # append a label to the detached atom - atomic_positions_card_listtmp.append(' {0:7} {1:18.10f} {2:18.10f} {3:18.10f} {4}' - '\n'.format(atomic_number_name, vector_rel[0], vector_rel[1], - vector_rel[2], kind_namet)) + reg_string = ' {0:7} {1:18.' + sf_p + 'f} {2:18.' + sf_p + 'f} {3:18.' + sf_p + 'f} {4}\n' + atomic_positions_card_listtmp.append( + reg_string.format(atomic_number_name, vector_rel[0], vector_rel[1], vector_rel[2], kind_namet)) else: - atomic_positions_card_listtmp.append(' {0:7} {1:18.10f} {2:18.10f} {3:18.10f}' - '\n'.format(atomic_number_name, vector_rel[0], vector_rel[1], - vector_rel[2])) + reg_string = ' {0:7} {1:18.' + sf_p + 'f} {2:18.' + sf_p + 'f} {3:18.' + sf_p + 'f}\n' + atomic_positions_card_listtmp.append( + reg_string.format(atomic_number_name, vector_rel[0], vector_rel[1], vector_rel[2])) # TODO check format # we write it later, since we do not know what natoms is before the loop... atomic_positions_card_list.append(' {0:3}\n'.format(natoms)) @@ -557,8 +568,8 @@ def get_input_data_text(key, val, value_only, mapping=None): for elemk, itemval in six.iteritems(val): try: idx = mapping[elemk] - except KeyError: - raise ValueError("Unable to find the key '{}' in the mapping " 'dictionary'.format(elemk)) + except KeyError as exc: + raise ValueError("Unable to find the key '{}' in the mapping " 'dictionary'.format(elemk)) from exc list_of_strings.append((idx, ' {0}({2})={1} '.format(key, conv_to_fortran(itemval), idx))) # changed {0}({2}) = {1}\n".format diff --git a/aiida_fleur/cmdline/__init__.py b/aiida_fleur/cmdline/__init__.py old mode 100644 new mode 100755 index 6e91f601d..05ed9c8e8 --- a/aiida_fleur/cmdline/__init__.py +++ b/aiida_fleur/cmdline/__init__.py @@ -10,5 +10,36 @@ # http://aiida-fleur.readthedocs.io/en/develop/ # ############################################################################### ''' -AiiDA-FLEUR +Module for the command line interface of AiiDA-FLEUR ''' +import click +import click_completion + +from aiida.cmdline.params import options, types +from .launch import cmd_launch +from .data import cmd_data +from .workflows import cmd_workflow +from .visualization import cmd_plot + +# Activate the completion of parameter types provided by the click_completion package +# for bash: eval "$(_AIIDA_FLEUR_COMPLETE=source aiida-fleur)" +click_completion.init() + +# Instead of using entrypoints and directly injecting verdi commands into aiida-core +# we created our own separete CLI because verdi will prob change and become +# less material science specific + + +@click.group('aiida-fleur', 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-fleur` plugin.""" + + +# To avoid circular imports all commands are not yet connected to the root +# but they have to be here because of bash completion + +cmd_root.add_command(cmd_launch) +cmd_root.add_command(cmd_data) +cmd_root.add_command(cmd_workflow) +cmd_root.add_command(cmd_plot) diff --git a/aiida_fleur/cmdline/commands/fleurinpdata.py b/aiida_fleur/cmdline/commands/fleurinpdata.py deleted file mode 100644 index 4ac092fb0..000000000 --- a/aiida_fleur/cmdline/commands/fleurinpdata.py +++ /dev/null @@ -1,76 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################### -# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # -# All rights reserved. # -# This file is part of the AiiDA-FLEUR package. # -# # -# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # -# For further information on the license, see the LICENSE.txt file # -# For further information please visit http://www.flapw.de or # -# http://aiida-fleur.readthedocs.io/en/develop/ # -############################################################################### -""" -Contains verdi commands for fleurinpdata -""" -from __future__ import absolute_import -import click - - -# this will get replaced by data_plug.group -#@data_plug.group('fleur.fleurinp') -@click.group() -def fleurinp(): - pass - - -@fleurinp.command() -def list_fleurinp(): - """ - list all Fleurinp data in the database and displays some information - """ - click.echo('verdi data fleurinp list') - #do a query and list all reuse AiiDA code - - -@fleurinp.command() -def show(): - """ - Shows some basic information about the fleurinp datastructure and dumbs the - inp.xml - """ - click.echo('verdi data fleurinp list') - - -@fleurinp.command() -def open_inp(): - """ - opens the inp.xml in some editor, readonly. - inp.xml - """ - click.echo('verdi data fleurinp list') - - -# this is a maybe -@fleurinp.command() -def get_structure(): - """ - Prints some basic information about the structure data and return a structure uuid/pk - """ - click.echo('verdi data fleurinp list') - - -@fleurinp.command() -def get_kpoints(): - """ - Prints some basic information about the kpoints data and returns a kpoints uuid/pk - """ - click.echo('verdi data fleurinp kpoints') - - -@fleurinp.command() -def get_parameters(): - """ - Prints some basic information about the parameter data and returns a - parameter data uuid/pk - """ - click.echo('verdi data fleurinp parameter') diff --git a/aiida_fleur/cmdline/commands/scf_wc.py b/aiida_fleur/cmdline/data/__init__.py old mode 100644 new mode 100755 similarity index 56% rename from aiida_fleur/cmdline/commands/scf_wc.py rename to aiida_fleur/cmdline/data/__init__.py index e7d76c829..6f44a8666 --- a/aiida_fleur/cmdline/commands/scf_wc.py +++ b/aiida_fleur/cmdline/data/__init__.py @@ -9,40 +9,22 @@ # For further information please visit http://www.flapw.de or # # http://aiida-fleur.readthedocs.io/en/develop/ # ############################################################################### +# pylint: disable=cyclic-import +# ,reimported,unused-import,wrong-import-position """ -contains verdi commands for the scf workchain -in general these should become options of verdi aiida-fleur workchains +Module with CLI commands for various data types. """ - -from __future__ import absolute_import import click -@click.group() -def scf_wc(): - pass - - -@scf_wc.command() -def res_scf(): - """ - Prints the result node to screen - """ - click.echo('verdi aiida-fleur scf res') - +@click.group('data') +def cmd_data(): + """Commands to create and inspect data nodes.""" -@scf_wc.command() -def show_scf(): - """ - plots the results of a - """ - click.echo('verdi aiida-fleur scf show') +#cmd_root.add_command(cmd_data) -@scf_wc.command() -def list_scf(): - """ - similar to the verdi work list command, but this displays also some - specific information about the scfs - """ - click.echo('verdi aiida-fleur scf list') +# Import the sub commands to register them with the CLI +from .structure import cmd_structure +from .parameters import cmd_parameter +from .fleurinp import cmd_fleurinp diff --git a/aiida_fleur/cmdline/data/fleurinp.py b/aiida_fleur/cmdline/data/fleurinp.py new file mode 100755 index 000000000..23ae0648d --- /dev/null +++ b/aiida_fleur/cmdline/data/fleurinp.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +""" +Contains verdi commands for fleurinpdata +""" +from __future__ import absolute_import +import click +from aiida.cmdline.commands.cmd_data.cmd_list import query, list_options +from aiida.cmdline.params import arguments, options, types +from aiida.cmdline.utils import decorators, echo +from aiida.cmdline.params.types import DataParamType +from aiida.plugins import DataFactory +#from aiida_fleur.data.fleurinp import FleurinpData +from . import cmd_data +FleurinpData = DataFactory('fleur.fleurinp') + + +@click.group('fleurinp') +def cmd_fleurinp(): + """Commands to handle `FleurinpData` nodes.""" + + +cmd_data.add_command(cmd_fleurinp) + + +@cmd_fleurinp.command('list') +@list_options # usual aiida list options +@click.option('--uuid/--no-uuid', default=False, show_default=True, help='Display uuid of nodes.') +@click.option('--ctime/--no-ctime', default=False, show_default=True, help='Display ctime of nodes.') +@click.option('--extras/--no-extras', default=True, show_default=True, help='Display extras of nodes.') +@click.option('--strucinfo/--no-strucinfo', + default=False, + show_default=True, + help='Perpare additional information on the crystal structure to show. This slows down the query.') +@decorators.with_dbenv() +def list_fleurinp(raw, past_days, groups, all_users, strucinfo, uuid, ctime, extras): + """ + List stored FleurinpData in the database with additional information + """ + # do a query and list all reuse AiiDA code + from tabulate import tabulate + list_project_headers = ['Id', 'Label', 'Description', 'Files'] # these we always get + # 'UUID', 'Ctime', + columns_dict = { + 'ID': 'id', + 'Id': 'id', + 'UUID': 'uuid', + 'Ctime': 'ctime', + 'Label': 'label', + 'Description': 'description', + 'Files': 'attributes.files', + 'Extras': 'attributes.extras' + } + + if uuid: + list_project_headers.append('UUID') + if ctime: + list_project_headers.append('Ctime') + if extras: + list_project_headers.append('Extras') + + project = [columns_dict[k] for k in list_project_headers] + group_pks = None + if groups is not None: + group_pks = [g.pk for g in groups] + + data_fleurinp = query(FleurinpData, project, past_days, group_pks, all_users) + if strucinfo: # second query + # we get the whole node to get some extra information + project2 = '*' + fleurinps = query(FleurinpData, project2, past_days, group_pks, all_users) + list_project_headers.append('Formula') + counter = 0 + fleurinp_list_data = list() + + # , 'Formula', 'Symmetry' + # It is fastest for list commands to only display content from a query + if not raw: + fleurinp_list_data.append(list_project_headers) + for j, entry in enumerate(data_fleurinp): + #print(entry) + for i, value in enumerate(entry): + if isinstance(value, list): + new_entry = list() + for elm in value: + if elm is None: + new_entry.append('') + else: + new_entry.append(elm) + entry[i] = ','.join(new_entry) + if strucinfo: + structure = fleurinps[j][0].get_structuredata_ncf() + formula = structure.get_formula() + entry.append(formula) + for i in range(len(entry), len(list_project_headers)): + entry.append(None) + counter += 1 + fleurinp_list_data.extend(data_fleurinp) + if raw: + echo.echo(tabulate(fleurinp_list_data, tablefmt='plain')) + else: + echo.echo(tabulate(fleurinp_list_data, headers='firstrow')) + echo.echo('\nTotal results: {}\n'.format(counter)) + + +@cmd_fleurinp.command('cat') +@arguments.NODE('node', type=DataParamType(sub_classes=('aiida.data:fleur.fleurinp',))) +@click.option('-f', + '--filename', + 'filename', + default='inp.xml', + show_default=True, + help='Disply the file content of the given filename.') +def cat_file(node, filename): + """ + Dumb the content of a file contained in given fleurinpdata, per default dump + inp.xml + """ + echo.echo(node.get_content(filename=filename)) + + +''' +@cmd_fleurinp.command('info') +def info(): + """ + Shows some basic information about the fleurinp datastructure and dumbs the + inp.xml + """ + click.echo('Not implemented yet, sorry. Please implement me!') + + +@cmd_fleurinp.command('show') +def cmd_show(): + """ + Shows the content of a certain file + """ + click.echo('Not implemented yet, sorry. Please implement me!') + + +@cmd_fleurinp.command('open') +def open_inp(): + """ + opens the inp.xml in some editor, readonly. + inp.xml this way looking at xml might be more convenient. + """ + click.echo('Not implemented yet, sorry. Please implement me!') + + +# this is a maybe +@cmd_fleurinp.command() +def get_structure(): + """ + Prints some basic information about the structure data and return a structure uuid/pk + """ + click.echo('Not implemented yet, sorry. Please implement me!') + + +@cmd_fleurinp.command() +def get_kpoints(): + """ + Prints some basic information about the kpoints data and returns a kpoints uuid/pk + """ + click.echo('Not implemented yet, sorry. Please implement me!') + + +@cmd_fleurinp.command() +def get_parameters(): + """ + Prints some basic information about the parameter data and returns a + parameter data uuid/pk + """ + click.echo('Not implemented yet, sorry. Please implement me!') +''' diff --git a/aiida_fleur/cmdline/data/parameters.py b/aiida_fleur/cmdline/data/parameters.py new file mode 100644 index 000000000..cffbb0d74 --- /dev/null +++ b/aiida_fleur/cmdline/data/parameters.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +# pylint: disable=cyclic-import +"""Command line utilities to create and inspect `Dict` nodes with FLAPW parameters.""" +import click + +from aiida.cmdline.params import options +from aiida.cmdline.utils import decorators, echo + +from . import cmd_data + + +@cmd_data.group('parameter') +def cmd_parameter(): + """Commands to create and inspect `Dict` nodes containing FLAPW parameters ('calc_parameters').""" + + +@cmd_parameter.command('import') +@click.argument('filename', type=click.Path(exists=True)) +@click.option('--fleurinp/--no-fleurinp', + default=False, + show_default=True, + help='Store also the fleurinp and the extractor calcfunction in the db.') +@click.option('--show/--no-show', default=True, show_default=True, help='Print the contents from the extracted dict.') +@options.DRY_RUN() +@decorators.with_dbenv() +def cmd_param_import(filename, dry_run, fleurinp, show): + """ + Extract FLAPW parameters from a Fleur input file and store as Dict in the db. + + FILENAME is the name/path of the inp.xml file to use. + """ + from aiida_fleur.data.fleurinp import FleurinpData + + if not filename.endswith('.xml'): + echo.echo_critical('Error: Currently, we can only extract information from an inp.xml file.') + fleurinpd = FleurinpData(files=[filename]) + if not fleurinp or dry_run: + parameters = fleurinpd.get_parameterdata_ncf() + else: + parameters = fleurinpd.get_parameterdata(fleurinpd) + + if dry_run: + echo.echo_success('parsed FLAPW parameters') + else: + parameters.store() + echo.echo_success(f'parsed and stored FLAPW parameters<{parameters.pk}> <{parameters.uuid}>') + + if show: + echo.echo_dictionary(parameters.get_dict()) + + +# further ideas: +# query for certain FLAPW parameter nodes. +# Example show me all for Si +# query for options nodes +# command to split and merge parameters nodes together based on elements. diff --git a/aiida_fleur/cmdline/data/structure.py b/aiida_fleur/cmdline/data/structure.py new file mode 100755 index 000000000..bded4de20 --- /dev/null +++ b/aiida_fleur/cmdline/data/structure.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +"""Command line utilities to create and inspect `StructureData` nodes.""" +import click +from aiida.cmdline.params import options +from aiida.cmdline.utils import decorators, echo + +from . import cmd_data + + +@click.group('structure') +def cmd_structure(): + """Commands to create and inspect `StructureData` nodes.""" + + +cmd_data.add_command(cmd_structure) +# import filename +# import -N pk_fleurinp + + +@cmd_structure.command('import') +@click.argument('filename', type=click.Path(exists=True)) +@click.option('--fleurinp/--no-fleurinp', + default=False, + show_default=True, + help='Store also the fleurinp and the extractor calcfunction in the db.') +@options.DRY_RUN() +@decorators.with_dbenv() +def cmd_import(filename, dry_run, fleurinp): + """ + Import a `StructureData` from a Fleur input file. + + FILENAME is the name/path of the inp.xml file to use. + + If you want to import a structure from any file type you can use + 'verdi data structure import -ase ' instead. + """ + from aiida_fleur.data.fleurinp import FleurinpData + + if not filename.endswith('.xml'): + echo.echo_critical('Error: Currently, only StructureData from a inp.xml file can be extracted.') + fleurinpd = FleurinpData(files=[filename]) + if not fleurinp or dry_run: + structure = fleurinpd.get_structuredata_ncf() + else: + structure = fleurinpd.get_structuredata() + formula = structure.get_formula() + + if dry_run: + echo.echo_success(f'parsed structure with formula {formula}') + else: + structure.store() + echo.echo_success( + f'parsed and stored StructureData<{structure.pk}> with formula {formula}, also stored FleurinpData<{fleurinpd.pk}>' + ) diff --git a/aiida_fleur/cmdline/launch/__init__.py b/aiida_fleur/cmdline/launch/__init__.py new file mode 100644 index 000000000..c8e32e054 --- /dev/null +++ b/aiida_fleur/cmdline/launch/__init__.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +''' +Module with CLI commands for calcjob types of aiida-fleur. +''' +import click +from .launch import launch_inpgen +from .launch import launch_fleur +from .launch import launch_scf +from .launch import launch_banddos +from .launch import launch_relax +from .launch import launch_eos +from .launch import launch_corehole +from .launch import launch_init_cls +from .launch import launch_mae +from .launch import launch_create_magnetic +from .launch import launch_dmi +from .launch import launch_ssdisp + + +@click.group('launch') +def cmd_launch(): + """Commands to launch workflows and calcjobs of aiida-fleur.""" + + +# we do it like this and not in short from to avoid cyclic imports +# and get the full bash completion working +cmd_launch.add_command(launch_inpgen) +cmd_launch.add_command(launch_fleur) +cmd_launch.add_command(launch_scf) +cmd_launch.add_command(launch_banddos) +cmd_launch.add_command(launch_relax) +cmd_launch.add_command(launch_eos) +cmd_launch.add_command(launch_corehole) +cmd_launch.add_command(launch_init_cls) +cmd_launch.add_command(launch_mae) +cmd_launch.add_command(launch_create_magnetic) +cmd_launch.add_command(launch_dmi) +cmd_launch.add_command(launch_ssdisp) diff --git a/aiida_fleur/cmdline/launch/launch.py b/aiida_fleur/cmdline/launch/launch.py new file mode 100755 index 000000000..8e0720729 --- /dev/null +++ b/aiida_fleur/cmdline/launch/launch.py @@ -0,0 +1,480 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +''' +Module with CLI commands to launch for calcjob and workflows of aiida-fleur. +''' +# TODO: these launch commands should be put in separate files, if this one becomes to large.. + +import click +from ..util import options +from ..util.utils import launch_process +from ..util import defaults +from aiida_fleur.tools.dict_util import clean_nones +from aiida.orm import Code, load_node, Dict +from aiida.plugins import WorkflowFactory +from aiida.plugins import CalculationFactory + + +@click.command('inpgen') +@options.STRUCTURE_OR_FILE(default=defaults.get_si_bulk_structure, show_default=True) +@options.INPGEN() +@options.CALC_PARAMETERS() +@options.SETTINGS() +@options.DAEMON() +def launch_inpgen(structure, inpgen, calc_parameters, settings, daemon): + """ + Launch an inpgen calcjob on given input + + If no code is given it queries the DB for inpgen codes and uses the one with + the newest creation time. + + Either structure or anysource_structure can be specified. + Default structure is Si bulk. + """ + + process_class = CalculationFactory('fleur.inpgen') + inputs = { + 'code': inpgen, + 'structure': structure, + 'parameters': calc_parameters, + 'settings': settings, + 'metadata': { + 'options': { + 'withmpi': False, + 'max_wallclock_seconds': 6000, + 'resources': { + 'num_machines': 1, + 'num_mpiprocs_per_machine': 1, + } + } + } + } + inputs = clean_nones(inputs) + builder = process_class.get_builder() + builder.update(inputs) + launch_process(builder, daemon) + + +@click.command('fleur') +@options.FLEURINP() +@options.FLEUR() +@options.REMOTE() +@options.SETTINGS() +@options.DAEMON() +@options.MAX_NUM_MACHINES() +@options.MAX_WALLCLOCK_SECONDS() +@options.NUM_MPIPROCS_PER_MACHINE() +@options.OPTION_NODE() +@options.WITH_MPI() +@click.option('--launch_base/--no-launch_base', + is_flag=True, + default=True, + show_default=True, + help=('Run the base_fleur workchain, which also handles errors instead ' + 'of a single fleur calcjob.')) +def launch_fleur(fleurinp, fleur, parent_folder, settings, daemon, max_num_machines, max_wallclock_seconds, + num_mpiprocs_per_machine, option_node, with_mpi, launch_base): + """ + Launch a base_fleur workchain. + If launch_base is False launch a single fleur calcjob instead. + + """ + + process_class = CalculationFactory('fleur.fleur') + workchain_class = WorkflowFactory('fleur.base') + + inputs = { + 'code': fleur, + 'fleurinpdata': fleurinp, + 'parent_folder': parent_folder, + 'settings': settings, + 'metadata': { + 'options': { + 'withmpi': with_mpi, + 'max_wallclock_seconds': max_wallclock_seconds, + 'resources': { + 'num_machines': max_num_machines, + 'num_mpiprocs_per_machine': num_mpiprocs_per_machine, + } + } + } + } + + if not launch_base: + inputs = clean_nones(inputs) + builder = process_class.get_builder() + builder.update(inputs) + else: + if option_node is None: + option_node = Dict( + dict={ + 'withmpi': with_mpi, + 'max_wallclock_seconds': max_wallclock_seconds, + 'resources': { + 'num_machines': max_num_machines, + 'num_mpiprocs_per_machine': num_mpiprocs_per_machine + } + }) + + inputs_base = { + 'code': fleur, + 'fleurinpdata': fleurinp, + 'parent_folder': parent_folder, + 'settings': settings, + 'options': option_node + } + inputs_base = clean_nones(inputs_base) + builder = workchain_class.get_builder() + builder.update(**inputs_base) + + launch_process(builder, daemon) + + +@click.command('scf') +@options.STRUCTURE_OR_FILE(default=defaults.get_si_bulk_structure, show_default=True) +@options.INPGEN() +@options.CALC_PARAMETERS() +@options.SETTINGS() +@options.FLEURINP() +@options.FLEUR() +@options.WF_PARAMETERS() +@options.REMOTE() +@options.DAEMON() +@options.SETTINGS() +@options.OPTION_NODE() +def launch_scf(structure, inpgen, calc_parameters, fleurinp, fleur, wf_parameters, parent_folder, daemon, settings, + option_node): + """ + Launch a scf workchain + """ + workchain_class = WorkflowFactory('fleur.scf') + inputs = { + 'inpgen': inpgen, + 'fleur': fleur, + 'structure': structure, + 'fleurinp': fleurinp, + 'wf_parameters': wf_parameters, + 'calc_parameters': calc_parameters, + 'remote_data': parent_folder, + 'settings': settings, + 'options': option_node + } + + inputs = clean_nones(inputs) + builder = workchain_class.get_builder() + builder.update(inputs) + launch_process(builder, daemon) + + +@click.command('relax') +@options.STRUCTURE_OR_FILE(default=defaults.get_si_bulk_structure, show_default=True) +@options.INPGEN() +@options.CALC_PARAMETERS() +@options.FLEUR() +@options.WF_PARAMETERS() +@options.SCF_PARAMETERS() +@options.DAEMON() +@options.SETTINGS() +@options.OPTION_NODE() +def launch_relax(structure, inpgen, calc_parameters, fleur, wf_parameters, scf_parameters, daemon, settings, + option_node): + """ + Launch a base relax workchain + + # TODO final scf input + """ + workchain_class = WorkflowFactory('fleur.base_relax') + inputs = { + 'scf': { + 'wf_parameters': scf_parameters, + 'structure': structure, + 'calc_parameters': calc_parameters, + 'options': option_node, + 'inpgen': inpgen, + 'fleur': fleur + }, + 'wf_parameters': wf_parameters + } + inputs = clean_nones(inputs) + builder = workchain_class.get_builder() + builder.update(inputs) + launch_process(builder, daemon) + + +@click.command('eos') +@options.STRUCTURE_OR_FILE(default=defaults.get_si_bulk_structure, show_default=True) +@options.INPGEN() +@options.CALC_PARAMETERS() +@options.FLEUR() +@options.WF_PARAMETERS() +@options.SCF_PARAMETERS() +@options.DAEMON() +@options.SETTINGS() +@options.OPTION_NODE() +def launch_eos(structure, inpgen, calc_parameters, fleur, wf_parameters, scf_parameters, daemon, settings, option_node): + """ + Launch a eos workchain + """ + workchain_class = WorkflowFactory('fleur.eos') + inputs = { + 'scf': { + 'wf_parameters': scf_parameters, + 'calc_parameters': calc_parameters, + 'options': option_node, + 'inpgen': inpgen, + 'fleur': fleur + }, + 'wf_parameters': wf_parameters, + 'structure': structure + } + inputs = clean_nones(inputs) + builder = workchain_class.get_builder() + builder.update(inputs) + launch_process(builder, daemon) + + +@click.command('banddos') +@options.FLEURINP() +@options.FLEUR() +@options.WF_PARAMETERS() +@options.REMOTE() +@options.DAEMON() +@options.SETTINGS() +@options.OPTION_NODE() +def launch_banddos(fleurinp, fleur, wf_parameters, parent_folder, daemon, settings, option_node): + """ + Launch a banddos workchain + """ + workchain_class = WorkflowFactory('fleur.banddos') + inputs = { + 'wf_parameters': wf_parameters, + 'fleur': fleur, + 'remote': parent_folder, + 'fleurinp': fleurinp, + 'options': option_node + } + inputs = clean_nones(inputs) + builder = workchain_class.get_builder() + builder.update(inputs) + launch_process(builder, daemon) + + +@click.command('init_cls') +@options.STRUCTURE_OR_FILE(default=defaults.get_si_bulk_structure, show_default=True) +@options.INPGEN() +@options.CALC_PARAMETERS() +@options.FLEURINP() +@options.FLEUR() +@options.WF_PARAMETERS() +@options.DAEMON() +@options.SETTINGS() +@options.OPTION_NODE() +def launch_init_cls(structure, inpgen, calc_parameters, fleurinp, fleur, wf_parameters, daemon, settings, option_node): + """ + Launch an init_cls workchain + """ + workchain_class = WorkflowFactory('fleur.init_cls') + inputs = { + 'calc_parameters': calc_parameters, + 'options': option_node, + 'inpgen': inpgen, + 'fleur': fleur, + 'wf_parameters': wf_parameters, + 'structure': structure + } + inputs = clean_nones(inputs) + builder = workchain_class.get_builder() + builder.update(inputs) + launch_process(builder, daemon) + + +@click.command('corehole') +@options.STRUCTURE_OR_FILE(default=defaults.get_si_bulk_structure, show_default=True) +@options.INPGEN() +@options.CALC_PARAMETERS() +@options.FLEURINP() +@options.FLEUR() +@options.WF_PARAMETERS() +@options.DAEMON() +@options.SETTINGS() +@options.OPTION_NODE() +def launch_corehole(structure, inpgen, calc_parameters, fleurinp, fleur, wf_parameters, daemon, settings, option_node): + """ + Launch a corehole workchain + """ + workchain_class = WorkflowFactory('fleur.corehole') + inputs = { + 'calc_parameters': calc_parameters, + 'options': option_node, + 'inpgen': inpgen, + 'fleur': fleur, + 'wf_parameters': wf_parameters, + 'structure': structure + } + inputs = clean_nones(inputs) + builder = workchain_class.get_builder() + builder.update(inputs) + launch_process(builder, daemon) + + +@click.command('mae') +@options.STRUCTURE_OR_FILE(default=defaults.get_fept_film_structure, show_default=True) +@options.INPGEN() +@options.CALC_PARAMETERS() +@options.FLEURINP() +@options.FLEUR() +@options.WF_PARAMETERS() +@options.SCF_PARAMETERS() +@options.REMOTE() +@options.DAEMON() +@options.SETTINGS() +@options.OPTION_NODE() +def launch_mae(structure, inpgen, calc_parameters, fleurinp, fleur, wf_parameters, scf_parameters, parent_folder, + daemon, settings, option_node): + """ + Launch a mae workchain + """ + workchain_class = WorkflowFactory('fleur.mae') + inputs = { + 'scf': { + 'wf_parameters': scf_parameters, + 'structure': structure, + 'calc_parameters': calc_parameters, + 'settings': settings, + 'inpgen': inpgen, + 'fleur': fleur + }, + 'wf_parameters': wf_parameters, + 'fleurinp': fleurinp, + 'remote': parent_folder, + 'fleur': fleur, + 'options': option_node + } + + inputs = clean_nones(inputs) + builder = workchain_class.get_builder() + builder.update(inputs) + launch_process(builder, daemon) + + +@click.command('create_magnetic') +@options.INPGEN() +@options.CALC_PARAMETERS() +@options.FLEUR() +@options.WF_PARAMETERS(required=True) +@options.EOS_PARAMETERS() +@options.SCF_PARAMETERS() +@options.RELAX_PARAMETERS() +@options.DAEMON() +@options.OPTION_NODE() +def launch_create_magnetic(inpgen, calc_parameters, fleur, wf_parameters, eos_parameters, scf_parameters, + relax_parameters, daemon, option_node): + """ + Launch a create_magnetic workchain + """ + workchain_class = WorkflowFactory('fleur.create_magnetic') + inputs = { + 'eos': { + 'scf': { + 'wf_parameters': scf_parameters, + 'calc_parameters': calc_parameters, + 'options': option_node, + 'inpgen': inpgen, + 'fleur': fleur + }, + 'wf_parameters': eos_parameters + }, + 'relax': { + 'scf': { + 'wf_parameters': scf_parameters, + 'calc_parameters': calc_parameters, + 'options': option_node, + 'inpgen': inpgen, + 'fleur': fleur + }, + 'wf_parameters': relax_parameters, + 'label': 'relaxation', + }, + 'wf_parameters': wf_parameters + } + + inputs = clean_nones(inputs) + builder = workchain_class.get_builder() + builder.update(inputs) + launch_process(builder, daemon) + + +@click.command('ssdisp') +@options.STRUCTURE_OR_FILE(default=defaults.get_fept_film_structure, show_default=True) +@options.INPGEN() +@options.CALC_PARAMETERS() +@options.FLEUR() +@options.WF_PARAMETERS(required=True) +@options.SCF_PARAMETERS() +@options.DAEMON() +@options.OPTION_NODE() +def launch_ssdisp(structure, inpgen, calc_parameters, fleur, wf_parameters, scf_parameters, daemon, option_node): + """ + Launch a ssdisp workchain + """ + workchain_class = WorkflowFactory('fleur.ssdisp') + inputs = { + 'scf': { + 'wf_parameters': scf_parameters, + 'structure': structure, + 'calc_parameters': calc_parameters, + 'options': option_node, + 'inpgen': inpgen, + 'fleur': fleur + }, + 'wf_parameters': wf_parameters, + 'fleur': fleur, + 'options': option_node + } + inputs = clean_nones(inputs) + builder = workchain_class.get_builder() + builder.update(inputs) + launch_process(builder, daemon) + + +@click.command('dmi') +@options.STRUCTURE_OR_FILE(default=defaults.get_fept_film_structure, show_default=True) +@options.INPGEN() +@options.CALC_PARAMETERS() +@options.FLEUR() +@options.WF_PARAMETERS(required=True) +@options.SCF_PARAMETERS() +@options.DAEMON() +@options.OPTION_NODE() +def launch_dmi(structure, inpgen, calc_parameters, fleur, wf_parameters, scf_parameters, daemon, option_node): + """ + Launch a dmi workchain + """ + click.echo('Not implemented yet, sorry. Please implement me!') + workchain_class = WorkflowFactory('fleur.dmi') + inputs = { + 'scf': { + 'wf_parameters': scf_parameters, + 'structure': structure, + 'calc_parameters': calc_parameters, + 'options': option_node, + 'inpgen': inpgen, + 'fleur': fleur + }, + 'wf_parameters': wf_parameters, + 'fleur': fleur, + 'options': option_node + } + inputs = clean_nones(inputs) + builder = workchain_class.get_builder() + builder.update(inputs) + launch_process(builder, daemon) diff --git a/aiida_fleur/cmdline/commands/workchains.py b/aiida_fleur/cmdline/list/__init__.py old mode 100644 new mode 100755 similarity index 51% rename from aiida_fleur/cmdline/commands/workchains.py rename to aiida_fleur/cmdline/list/__init__.py index ca4905af8..318a115bb --- a/aiida_fleur/cmdline/commands/workchains.py +++ b/aiida_fleur/cmdline/list/__init__.py @@ -9,40 +9,12 @@ # For further information please visit http://www.flapw.de or # # http://aiida-fleur.readthedocs.io/en/develop/ # ############################################################################### -""" -contains verdi commands that are useful for fleur workchains -""" +''' +Module with CLI commands for calcjob types of aiida-fleur. +''' +from .. import cmd_root -from __future__ import absolute_import -import click - -@click.group() -def workchains(): - pass - - -@workchains.command() -def res_wc(): - """ - Prints the result node to screen - """ - click.echo('verdi aiida-fleur workchains res pk/uuid/list') - - -@workchains.command() -def show_wc(): - """ - plots the results of a workchain - """ - click.echo('verdi aiida-fleur workchains show pk/uuid/list') - - -@workchains.command() -def list_wc(): - """ - similar to the verdi work list command, but this displays also some - specific information about the fleur workchains, can be filtered for - certain workchains... - """ - click.echo('verdi aiida-fleur workchians list -scf -A -p') +@cmd_root.group('list') +def cmd_calcjob(): + """Command group to list calcjobs and workflows of aiida-fleur.""" diff --git a/aiida_fleur/cmdline/commands/__init__.py b/aiida_fleur/cmdline/util/__init__.py old mode 100644 new mode 100755 similarity index 100% rename from aiida_fleur/cmdline/commands/__init__.py rename to aiida_fleur/cmdline/util/__init__.py diff --git a/aiida_fleur/cmdline/util/defaults.py b/aiida_fleur/cmdline/util/defaults.py new file mode 100644 index 000000000..8982068ed --- /dev/null +++ b/aiida_fleur/cmdline/util/defaults.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- +""" +Here we specify some defaults for cli commands +""" + +# Structures + + +def get_si_bulk_structure(): + """Return a `StructureData` representing bulk silicon. + + The database will first be queried for the existence of a bulk silicon crystal. If this is not the case, one is + created and stored. This function should be used as a default for CLI options that require a `StructureData` node. + This way new users can launch the command without having to construct or import a structure first. This is the + reason that we hardcode a bulk silicon crystal to be returned. More flexibility is not required for this purpose. + + :return: a `StructureData` representing bulk silicon + """ + from ase.spacegroup import crystal + from aiida.orm import QueryBuilder, StructureData + + # Filters that will match any elemental Silicon structure with 2 or less sites in total + filters = { + 'attributes.sites': { + 'of_length': 2 + }, + 'attributes.kinds': { + 'of_length': 1 + }, + 'attributes.kinds.0.symbols.0': 'Si' + } + + builder = QueryBuilder().append(StructureData, filters=filters) + results = builder.first() + + if not results: + alat = 5.43 + ase_structure = crystal( + 'Si', + [(0, 0, 0)], + spacegroup=227, + cellpar=[alat, alat, alat, 90, 90, 90], + primitive_cell=True, + ) + structure = StructureData(ase=ase_structure) + structure.store() + else: + structure = results[0] + + return structure.uuid + + +def get_fept_film_structure(): + """Return a `StructureData` representing FePt film. + + The database will first be queried for the existence of a FePt film. If this is not the case, one is + created and stored. This function should be used as a default for CLI options that require a `StructureData` node. + This way new users can launch the command without having to construct or import a structure first. This is the + reason that we hardcode a FePt film to be returned. More flexibility is not required for this purpose. + + :return: the uuid of `StructureData` representing a FePt film + """ + from aiida.orm import StructureData, QueryBuilder + + bohr_a_0 = 0.52917721092 # A + a = 7.497 * bohr_a_0 + cell = [[0.7071068 * a, 0.0, 0.0], [0.0, 1.0 * a, 0.0], [0.0, 0.0, 0.7071068 * a]] + structure = StructureData(cell=cell) + structure.append_atom(position=(0.0, 0.0, -1.99285 * bohr_a_0), symbols='Fe', name='Fe123') + structure.append_atom(position=(0.5 * 0.7071068 * a, 0.5 * a, 0.0), symbols='Pt') + structure.append_atom(position=(0., 0., 2.65059 * bohr_a_0), symbols='Pt') + structure.pbc = (True, True, False) + + builder = QueryBuilder().append(StructureData, filters={'extras._aiida_hash': structure._get_hash()}) + results = builder.first() + + if not results: + structure.store() + else: + structure = results[0] + + return structure.uuid + + +# Codes +def get_inpgen(): + """Return a `Code` node of the latest added inpgen executable in the database.""" + + return get_last_code('fleur.inpgen') + + +def get_fleur(): + """Return a `Code` node of the latest added inpgen executable in the database.""" + + return get_last_code('fleur.fleur') + + +def get_last_code(entry_point_name): + """Return a `Code` node of the latest code executable of the given entry_point_name in the database. + + The database will be queried for the existence of a inpgen node. + If this is not exists and NotExistent error is raised. + + + :param entry_point_name: string + :return: the uuid of a inpgen `Code` node + :raise: aiida.common.exceptions.NotExistent + """ + from aiida.orm import QueryBuilder, Code + from aiida.common.exceptions import NotExistent + + filters = {'attributes.input_plugin': {'==': entry_point_name}} + + builder = QueryBuilder().append(Code, filters=filters) + builder.order_by({Code: {'ctime': 'asc'}}) + results = builder.first() + + if not results: + raise NotExistent(f'ERROR: Could not find any Code in the database with entry point: {entry_point_name}!') + else: + inpgen = results[0] + + return inpgen.uuid diff --git a/aiida_fleur/cmdline/util/options.py b/aiida_fleur/cmdline/util/options.py new file mode 100755 index 000000000..a498a38cc --- /dev/null +++ b/aiida_fleur/cmdline/util/options.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +""" +Options commonly used throughout the aiida-fleur command line interface. +To standardize at least of the options, they are kept as close as possible to +aiida-core and aiida-quantumespresso +""" +import click +from aiida.cmdline.params import types +from aiida.cmdline.params.options import OverridableOption +from .defaults import get_inpgen, get_fleur, get_si_bulk_structure +from .types import StructureNodeOrFileParamType + +STRUCTURE_OR_FILE = OverridableOption( + '-s', + '--structure', + type=StructureNodeOrFileParamType(), + help='StructureData node, given by pk or uuid or file in any for mat which will be converted.') + +STRUCTURE = OverridableOption('-s', + '--structure', + type=types.DataParamType(sub_classes=('aiida.data:structure',)), + help='StructureData node, given by pk or uuid.') + +FULL_PROVENANCE = OverridableOption('-fp', + '--full-provenance', + is_flag=True, + default=False, + show_default=True, + help=('Store the full or reduced provenance. Example with the "-as" ' + 'also the given file will be stored in the database together with a ' + 'calcfunction extracting the structure.')) + +INPGEN = OverridableOption('-i', + '--inpgen', + type=types.CodeParamType(entry_point='fleur.inpgen'), + default=get_inpgen, + show_default=True, + help='A code node or label for an inpgen executable.') + +FLEUR = OverridableOption('-f', + '--fleur', + type=types.CodeParamType(entry_point='fleur.fleur'), + default=get_fleur, + show_default=True, + help='A code node or label for a fleur executable.') + +FLEURINP = OverridableOption('-inp', + '--fleurinp', + type=types.DataParamType(sub_classes=('aiida.data:fleur.fleurinp',)), + help='FleurinpData node for the fleur calculation.') + +CALC_PARAMETERS = OverridableOption( + '-calc_p', + '--calc-parameters', + type=types.DataParamType(sub_classes=('aiida.data:dict',)), + help='Dict with calculation (FLAPW) parameters to build, which will be given to inpgen.') + +SETTINGS = OverridableOption('-set', + '--settings', + type=types.DataParamType(sub_classes=('aiida.data:dict',)), + help='Settings node for the calcjob.') + +WF_PARAMETERS = OverridableOption('-wf', + '--wf-parameters', + type=types.DataParamType(sub_classes=('aiida.data:dict',)), + help='Dict containing parameters given to the workchain.') + +SCF_PARAMETERS = OverridableOption('-scf', + '--scf-parameters', + type=types.DataParamType(sub_classes=('aiida.data:dict',)), + help='Dict containing parameters given to the sub SCF workchains.') + +EOS_PARAMETERS = OverridableOption('-eos', + '--eos-parameters', + type=types.DataParamType(sub_classes=('aiida.data:dict',)), + help='Dict containing wf parameters given to the sub EOS workchains.') + +RELAX_PARAMETERS = OverridableOption('-relax', + '--relax-parameters', + type=types.DataParamType(sub_classes=('aiida.data:dict',)), + help='Dict containing wf parameters given to the sub relax workchains.') + +OPTION_NODE = OverridableOption('-opt', + '--option-node', + type=types.DataParamType(sub_classes=('aiida.data:dict',)), + help='Dict, an option node for the workchain.') + +MAX_NUM_MACHINES = OverridableOption('-N', + '--max-num-machines', + type=click.INT, + default=1, + show_default=True, + help='The maximum number of machines (nodes) to use for the calculations.') + +MAX_WALLCLOCK_SECONDS = OverridableOption('-W', + '--max-wallclock-seconds', + type=click.INT, + default=1800, + show_default=True, + help='The maximum wallclock time in seconds to set for the calculations.') + +NUM_MPIPROCS_PER_MACHINE = OverridableOption('-M', + '--num-mpiprocs-per-machine', + type=click.INT, + default=12, + show_default=True, + help='Run the simulation with so many num-mpi-procs-per-machine.') + +WITH_MPI = OverridableOption('-I', + '--with-mpi', + is_flag=True, + default=False, + show_default=True, + help='Run the calculations with MPI enabled.') + +REMOTE = OverridableOption('-P', + '--parent-folder', + 'parent_folder', + type=types.DataParamType(sub_classes=('aiida.data:remote',)), + show_default=True, + required=False, + help='The PK of a parent remote folder (for restarts).') + +DAEMON = OverridableOption('-d', + '--daemon', + is_flag=True, + default=False, + show_default=True, + help='Submit the process to the daemon instead of running it locally.') + +CLEAN_WORKDIR = OverridableOption( + '-x', + '--clean-workdir', + is_flag=True, + default=False, + show_default=True, + help='Clean the remote folder of all the launched calculations after completion of the workchain.') + +SHOW = OverridableOption('--show/--no-show', + default=True, + show_default=True, + help='Show the main output of the command.') diff --git a/aiida_fleur/cmdline/util/types.py b/aiida_fleur/cmdline/util/types.py new file mode 100644 index 000000000..a4eeff1f4 --- /dev/null +++ b/aiida_fleur/cmdline/util/types.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +''' +This module contains click option types specific to aiida-fleur +''' +import click +from aiida.cmdline.params import types +from aiida.cmdline.utils import echo +from aiida.common.exceptions import NotExistent +from aiida.plugins import DataFactory +from aiida.cmdline.utils.decorators import with_dbenv + + +class StructureNodeOrFileParamType(click.ParamType): + """ + The ParamType for identifying a structure by node or to extract it from a given file + + Pro: It is convenient + Con: If users only use other formats to launch their workflows it will create many + more structures in the database. + """ + + name = 'StructureFile' + + @with_dbenv() + def convert(self, value, param, ctx): + is_path = False + # Alternative one could check if int or uuid + # aiida allows also for shorten uuids + from aiida.orm import StructureData, QueryBuilder + + try: + structure = types.DataParamType(sub_classes=('aiida.data:structure',)).convert(value, param, ctx) + except (NotExistent, click.exceptions.BadParameter) as er: + echo.echo(f'Tried to load node, could not fine one for {value}. ' + 'I will further check if it is a filepath.') + is_path = True + + if is_path: + # If it is a path to a file try to convert the structure + pathtype = click.Path(exists=True, dir_okay=False, resolve_path=True) + filename = pathtype.convert(value, param, ctx) + try: + import ase.io + except ImportError: + echo.echo_critical('You have not installed the package ase. \nYou can install it with: pip install ase') + + try: + asecell = ase.io.read(filename) + structure = StructureData(ase=asecell) + except ValueError as err: + echo.echo_critical(str(err)) + # do not store structure, since this option is for calculation and workflow + # input, which will store the structure anyway. + + # do not store again if structure is already there. + duplicate = QueryBuilder().append(StructureData, filters={'extras._aiida_hash': structure._get_hash()}).first() # pylint: disable=protected-access + + if duplicate: + return duplicate[0] + return structure diff --git a/aiida_fleur/cmdline/util/utils.py b/aiida_fleur/cmdline/util/utils.py new file mode 100644 index 000000000..4b64fe013 --- /dev/null +++ b/aiida_fleur/cmdline/util/utils.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +""" +Module with utitlies for the CLI. + +The echo_process_results and launch_process routines have been copied from +aiida-common-workflows repository found under cli utils +""" +import click + + +def echo_process_results(node): + """Display a formatted table of the outputs registered for the given process node. + + :param node: the `ProcessNode` of a terminated process. + """ + from aiida.common.links import LinkType + + class_name = node.process_class.__name__ + outputs = node.get_outgoing(link_type=(LinkType.CREATE, LinkType.RETURN)).all() + + if node.is_finished and node.exit_message: + state = '{} [{}] `{}`'.format(node.process_state.value, node.exit_status, node.exit_message) + elif node.is_finished: + state = '{} [{}]'.format(node.process_state.value, node.exit_status) + else: + state = node.process_state.value + + click.echo('{}<{}> terminated with state: {}'.format(class_name, node.pk, state)) + + if not outputs: + click.echo('{}<{}> registered no outputs'.format(class_name, node.pk)) + return + + click.echo('\n{link:25s} {node}'.format(link='Output link', node='Node pk and type')) + click.echo('{s}'.format(s='-' * 60)) + + for triple in sorted(outputs, key=lambda triple: triple.link_label): + click.echo('{:25s} {}<{}> '.format(triple.link_label, triple.node.__class__.__name__, triple.node.pk)) + + +def launch_process(process, daemon, **inputs): + """Launch a process with the given inputs. + + If not sent to the daemon, the results will be displayed after the calculation finishes. + + :param process: the process class or process builder. + :param daemon: boolean, if True will submit to the daemon instead of running in current interpreter. + :param inputs: inputs for the process if the process is not already a fully prepared builder. + """ + from aiida.engine import launch, Process, ProcessBuilder + + if isinstance(process, ProcessBuilder): + process_name = process.process_class.__name__ + elif issubclass(process, Process): + process_name = process.__name__ + else: + raise TypeError('invalid type for process: {}'.format(process)) + + if daemon: + node = launch.submit(process, **inputs) + click.echo('Submitted {}<{}> to the daemon'.format(process_name, node.pk)) + else: + click.echo('Running a {}...'.format(process_name)) + _, node = launch.run_get_node(process, **inputs) + echo_process_results(node) diff --git a/aiida_fleur/cmdline/visualization/__init__.py b/aiida_fleur/cmdline/visualization/__init__.py new file mode 100755 index 000000000..30654e4ca --- /dev/null +++ b/aiida_fleur/cmdline/visualization/__init__.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +""" +Module with CLI commands for various visualizations of data types. +""" +# if in the future there are futher sub commands of plot, the current plot +# command can become plot_fleur +import click +from aiida.cmdline.utils import decorators +from aiida.cmdline.params import arguments + + +@click.command('plot') +@arguments.NODES('nodes') +# help='The pks for the nodes to be parsed to plot_fleur') +# type=click.Path(exists=True)) +@click.option('-f', 'filename', type=click.File('r'), default=None) +@click.option('--save', + type=click.BOOL, + default=False, + show_default=True, + help='Should the result of plot_fleur be saved to a files.') +@click.option('--show/--no-show', default=True, show_default=True, help='Show the output of plot_fleur.') +@click.option('--show_dict/--no-show_dict', default=False, show_default=True, help='Show the output of plot_fleur.') +@click.option('--bokeh', 'backend', flag_value='bokeh') +@click.option('--matplotlib', 'backend', flag_value='matplotlib', default=True) +#@decorators.with_dbenv() +def cmd_plot(nodes, filename, save, show_dict, backend, show): + """ + Invoke the plot_fleur command on given nodes + """ + if backend != 'bokeh': + # Try to set a working GUI backend for matplotlib + # normally we assume to be on ipython which is not good. + # The order is arbitrary. + import matplotlib + gui_env = [ + 'WebAgg', 'GTK3Agg', 'GTK3Cairo', 'MacOSX', 'Qt4Agg', 'Qt4Cairo', 'Qt5Agg', 'Qt5Cairo', 'TkAgg', 'TkCairo', + 'WX', 'WXAgg', 'WXCairo', 'nbAgg', 'agg', 'cairo', 'pdf', 'pgf', 'ps', 'svg' + ] + for gui in gui_env: + try: + print('testing', gui) + matplotlib.use(gui, force=True) + from matplotlib import pyplot as plt + break + except ImportError as ex: + print(ex) + continue + print('Using:', matplotlib.get_backend()) + + from aiida_fleur.tools.plot.fleur import plot_fleur + + nodes = list(nodes) + nodesf = [] + if filename is not None: + nodesf = filename.read().split() + filename.close() + nodes = nodes + nodesf + p = plot_fleur(nodes, save=save, show_dict=show_dict, backend=backend, show=show) diff --git a/aiida_fleur/cmdline/workflows/__init__.py b/aiida_fleur/cmdline/workflows/__init__.py new file mode 100755 index 000000000..e4e92b550 --- /dev/null +++ b/aiida_fleur/cmdline/workflows/__init__.py @@ -0,0 +1,172 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +""" +Module with CLI commands to launch and inspect various aiida-fleur workchains. +""" +import click +from aiida.cmdline.params.types import ProcessParamType +from aiida.cmdline.params import arguments, options +from aiida.cmdline.utils import decorators, echo +from aiida import orm +from aiida_fleur.cmdline.util import options as options_fl + + +@click.group('workflow') +def cmd_workflow(): + """Commands to inspect aiida-fleur workchains.""" + + +# general further commands for fleur workchains + + +@cmd_workflow.command('res') +@arguments.PROCESS('process', type=ProcessParamType() + ) #, type=WorkflowParamType(sub_classes=('aiida.node:process.workflow.workchain',))) +@click.option('--info/--no-info', default=False, help='Print an info header above each node.') +@click.option('-l', '--label', 'label', type=str, help='Print only output dicts with a certain link_label.') +@options_fl.SHOW() +@options.DICT_KEYS() +@options.DICT_FORMAT() +@decorators.with_dbenv() +def workchain_res(process, info, label, show, keys, fmt): + """Print data from Dict nodes returned or created by any fleur process.""" + + returned_dicts_info = [] + returned_dicts = [] + try: + results = process.get_outgoing().all() + except ValueError as exception: + echo.echo_critical(str(exception)) + for result in results: + if isinstance(result.node, orm.Dict): + if label is not None: + if label == result.link_label: + returned_dicts.append(result.node.get_dict()) + returned_dicts_info.append(result) + else: + returned_dicts.append(result.node.get_dict()) + returned_dicts_info.append(result) + + for i, re_dict in enumerate(returned_dicts): + if keys is not None: + try: + result = {k: re_dict[k] for k in keys} + except KeyError as exc: + echo.echo_critical("key '{}' was not found in the results dictionary".format(exc.args[0])) + else: + result = re_dict + if info: + echo.echo('# Info: {} {} dict:'.format(returned_dicts_info[i].link_label, returned_dicts_info[i].node)) + echo.echo_dictionary(result, fmt=fmt) + + +@cmd_workflow.command('inputdict') +@arguments.PROCESS('process', type=ProcessParamType() + ) #, type=WorkflowParamType(sub_classes=('aiida.node:process.workflow.workchain',))) +@click.option('--info/--no-info', default=False, help='Print an info header above each node.') +@click.option('-l', '--label', 'label', type=str, help='Print only output dicts with a certain link_label.') +@options_fl.SHOW() +@options.DICT_KEYS() +@options.DICT_FORMAT() +@decorators.with_dbenv() +def workchain_inputdict(process, info, label, show, keys, fmt): + """Print data from Dict nodes input into any fleur process.""" + from aiida.orm import Dict + + returned_dicts_info = [] + returned_dicts = [] + try: + results = process.get_incoming().all() + except ValueError as exception: + echo.echo_critical(str(exception)) + for result in results: + if isinstance(result.node, orm.Dict): + if label is not None: + if label == result.link_label: + returned_dicts.append(result.node.get_dict()) + returned_dicts_info.append(result) + else: + returned_dicts.append(result.node.get_dict()) + returned_dicts_info.append(result) + + for i, re_dict in enumerate(returned_dicts): + if keys is not None: + try: + result = {k: re_dict[k] for k in keys} + except KeyError as exc: + echo.echo_critical("key '{}' was not found in the results dictionary".format(exc.args[0])) + else: + result = re_dict + if info: + echo.echo('# Info: {} {} dict:'.format(returned_dicts_info[i].link_label, returned_dicts_info[i].node)) + if show: + echo.echo_dictionary(result, fmt=fmt) + + +''' +@cmd_workflow.command('gen_wf_para') +@arguments.ENTRYPOINTSTR('entrypoint', default='fleur.scf') +@options.SHOW() +@options.STORE() +@options.CHECK_EXISTENCE() +@options.KWARGS() +@decorators.with_dbenv() +def gen_wf_para_cmd(entrypoint, show, store, check_existence, kwargs): + """ + Generates a default parameter wf parameter node for given entrypoint. + """ + from aiida_fleur.tools.node_generators import generate_wf_para_node + from aiida.plugins import entry_point + try: + wf = entry_point.load_entry_point('aiida.workflows', prefix) + except ValueError: + echo.echo('here1') + try: + wf = entry_point.load_entry_point('aiida.calculations', prefix) + except ValueError: + echo.echo('here1') + + wf_para = generate_wf_para_node(entrypoint=entrypoint, **kwargs) + if store: + wf_para.store() + echo.echo('Created wf para node') + else: + echo.echo('Created wf para node') + if show: + echo.echo_dictionary(wf.para.get_dict()) + + + +@cmd_workflow.command('inputls') +def inputls_wc(): + """ + Prints verdi node show for all workchain inputs. + """ + click.echo('verdi aiida-fleur scf res') + +@cmd_workflow.command('show') +def show_wc(): + """ + Shows the node ans structure of a workchain. + Similar to verdi node show + """ + click.echo('verdi aiida-fleur scf show') + + +@cmd_workflow.command('list') +def list_wc(): + """ + Similar to the verdi process list command, but this has preset filters and + displays also some specific information about fleur workchains + """ + click.echo('verdi aiida-fleur scf list') +''' diff --git a/aiida_fleur/common/constants.py b/aiida_fleur/common/constants.py index 0a474ee13..26e135419 100644 --- a/aiida_fleur/common/constants.py +++ b/aiida_fleur/common/constants.py @@ -13,6 +13,25 @@ Here we collect physical constants which are used throughout the code that way we ensure consitency ''' +# at some point one should import these from masci-tools, or better scipy or ase to ensure, +# that all judft plugins and tools take the same values, to make roundtrips consistent +# NIST https://physics.nist.gov/cgi-bin/cuu/Value?hrev +HTR_TO_EV = 27.211386245988 #(53) +BOHR_A = 0.5291772108 +#Scipy bohr 5.29177210903e-11 m +#Scipy htr 27.211386245988 eV +# NIST BOHR 0.529177210903 #(80) +#https://physics.nist.gov/cgi-bin/cuu/Value?bohrrada0 -htr_to_ev = 27.21138602 -bohr_a = 0.52917720903 +#Fleur +#htr_eV = 27.21138602 +#bohr=0.5291772108 +#bohrtocm=0.529177e-8 +#pymatgen uses scipy.constants +#ase: Bohr 0.5291772105638411 +#Hartree 27.211386024367243 +#Rydberg 13.605693012183622 +#1/Bohr +#1.8897261258369282 +#aiida-core units: +#bohr_to_ang = 0.52917720859 diff --git a/aiida_fleur/common/defaults.py b/aiida_fleur/common/defaults.py new file mode 100644 index 000000000..fc45bee68 --- /dev/null +++ b/aiida_fleur/common/defaults.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +''' +Here default values are collected. +Meaning is to centralize the defaults throughout the plugin more, to allow in the +end that the user might be able to specify them in a file he provides +''' +default_options = { + 'resources': { + 'num_machines': 1, + 'num_mpiprocs_per_machine': 1 + }, + 'max_wallclock_seconds': 6 * 60 * 60, + 'queue_name': '', + 'custom_scheduler_commands': '', + 'import_sys_environment': False, + 'environment_variables': {} +} diff --git a/aiida_fleur/common/mapping.py b/aiida_fleur/common/mapping.py index cb01e3015..59118a4b6 100644 --- a/aiida_fleur/common/mapping.py +++ b/aiida_fleur/common/mapping.py @@ -57,8 +57,8 @@ def prepare_process_inputs(process, inputs): try: process_spec = process.spec() - except AttributeError: - raise ValueError('process {} does not have a spec') + except AttributeError as exc: + raise ValueError('Process {} does not have a spec') from exc for key, value in six.iteritems(inputs): diff --git a/aiida_fleur/common/node_generators.py b/aiida_fleur/common/node_generators.py new file mode 100644 index 000000000..23e8dc655 --- /dev/null +++ b/aiida_fleur/common/node_generators.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +''' +This contains functions to generate certain node content, mostly dictionaries +with defaults. +These functions are usefull to expose one the commandline and to have defaults in one place +''' +# Todo: some of these can be moved to aiida-jutools +# since for kkr they might be the same +#todo, we allow kwargs for the nodes, maybe they should be validated +from aiida import orm +from aiida.plugins import WorkflowFactory +from aiida.orm import QueryBuilder + + +def generate_wf_option_node(computer=None, check_existence=True, **kwargs): + """Create a option node for a certain workflow or calculation entry point. + + :param wf_entry_point: string the entry point to create the node for, default='fleur.scf' + :param computer: dict {computername, queue} to provide computer dependend defaults + :param kwargs: dict, further key word argument by which the node content will be updated + + :returns: AiiDA Dict node + """ + option_node_dict = generate_wf_option_dict(computer=computer, **kwargs) + option_node = orm.Dict(dict=option_node_dict) + if check_existence: + duplicate = QueryBuilder().append(orm.Dict, filters={'extras._aiida_hash': option_node._get_hash()}).first() # pylint: disable=protected-access + if duplicate: + option_node = duplicate[0] + + return option_node + + +def generate_wf_option_dict(computer=None, protocol_file=None, **kwargs): + """Create a option dict for a certain workflow or calculation entry point. + + :param computer: dict {computername, queue} to provide computer dependend defaults + :param kwargs: dict, further key word argument by which the node content will be updated + :param protocol_file: str, path to json file containing a set of default options + + :returns: python dict + """ + # options usually do not differe between workflows, but depend on system size and machine. + # Also per project, therefore it would be nice to allow to provide a file and with a set of defaults. + # and this function should read them + from aiida_fleur.common.defaults import default_options + + default_wf_dict = default_options.deepcopy() + #todo better rekursive merge? + default_wf_dict.update(kwargs) + + return default_wf_dict + + +def generate_wf_para_dict(wf_entry_point='fleur.scf', **kwargs): + """Create a wf parameter dict for a certain workflow or calculation entry point. + + :param wf_entry_point: string the entry point to create the node for, default='fleur.scf' + :param kwargs: dict, further key word argument by which the node content will be updated + + :returns: python dict + """ + + wf = WorkflowFactory(wf_entry_point) + default_wf_dict = wf._default_wf_para + #todo better rekursive merge? + default_wf_dict.update(kwargs) + + return default_wf_dict + + +def generate_wf_para_node(wf_entry_point='fleur.scf', check_existence=True, **kwargs): + """Create a wf parameter node for a certain workflow or calculation entry point. + + :param wf_entry_point: string the entry point to create the node for, default='fleur.scf' + :param kwargs: dict, further key word argument by which the node content will be updated + + :returns: AiiDA Dict node + """ + wf_para_node_dict = generate_wf_para_dict(wf_entry_point=wf_entry_point, check_existence=check_existence, **kwargs) + wf_para_node = orm.Dict(dict=wf_para_node_dict) + if check_existence: + duplicate = QueryBuilder().append(orm.Dict, filters={'extras._aiida_hash': wf_para_node._get_hash()}).first() # pylint: disable=protected-access + if duplicate: + wf_para_node = duplicate[0] + + return wf_para_node diff --git a/aiida_fleur/common/workchain/base/restart.py b/aiida_fleur/common/workchain/base/restart.py index 9841b7c7f..0114e4ddc 100644 --- a/aiida_fleur/common/workchain/base/restart.py +++ b/aiida_fleur/common/workchain/base/restart.py @@ -56,7 +56,7 @@ class BaseRestartWorkChain(WorkChain): _error_handler_entry_point = None def __init__(self, *args, **kwargs): - super(BaseRestartWorkChain, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self._calculation_class is None or not issubclass(self._calculation_class, (CalcJob, WorkChain)): raise ValueError('no valid CalcJob or WorkChain class defined for `_calculation_class` attribute') @@ -65,7 +65,7 @@ def __init__(self, *args, **kwargs): @override def load_instance_state(self, saved_state, load_context): - super(BaseRestartWorkChain, self).load_instance_state(saved_state, load_context) + super().load_instance_state(saved_state, load_context) self._load_error_handlers() def _load_error_handlers(self): @@ -86,8 +86,7 @@ def _load_error_handlers(self): @classmethod def define(cls, spec): # yapf: disable - # pylint: disable=bad-continuation - super(BaseRestartWorkChain, cls).define(spec) + super().define(spec) spec.input('max_iterations', valid_type=orm.Int, default=lambda: orm.Int(3), help='Maximum number of iterations the work chain will restart the calculation to finish successfully.') spec.input('clean_workdir', valid_type=orm.Bool, default=lambda: orm.Bool(False), @@ -121,8 +120,8 @@ def run_calculation(self): try: unwrapped_inputs = self.ctx.inputs - except AttributeError: - raise AttributeError('no calculation input dictionary was defined in `self.ctx.inputs`') + except AttributeError as exc: + raise AttributeError('no calculation input dictionary was defined in `self.ctx.inputs`') from exc inputs = prepare_process_inputs(self._calculation_class, unwrapped_inputs) calculation = self.submit(self._calculation_class, **inputs) @@ -201,7 +200,7 @@ def results(self): def on_terminated(self): """Clean the working directories of all child calculations if `clean_workdir=True` in the inputs.""" - super(BaseRestartWorkChain, self).on_terminated() + super().on_terminated() if self.inputs.clean_workdir.value is False: self.report('remote folders will not be cleaned') diff --git a/aiida_fleur/data/fleurinp.py b/aiida_fleur/data/fleurinp.py index f92858692..7e4083bd0 100644 --- a/aiida_fleur/data/fleurinp.py +++ b/aiida_fleur/data/fleurinp.py @@ -35,7 +35,7 @@ from aiida_fleur.tools.xml_util import replace_tag from aiida_fleur.fleur_schema.schemafile_index import get_internal_search_paths, get_schema_paths -from aiida_fleur.common.constants import bohr_a as BOHR_A +from aiida_fleur.common.constants import BOHR_A class FleurinpData(Data): @@ -82,7 +82,7 @@ def __init__(self, **kwargs): files.append(filename) break node = kwargs.pop('node', None) - super(FleurinpData, self).__init__(**kwargs) + super().__init__(**kwargs) search_paths = [] ifolders = get_internal_search_paths() @@ -431,8 +431,12 @@ def _set_inp_dict(self): parser = etree.XMLParser(attribute_defaults=True, encoding='utf-8') # dtd_validation=True with self.open(path='inp.xml', mode='r') as inpxmlfile: - tree_x = etree.parse(inpxmlfile, parser) - + try: + tree_x = etree.parse(inpxmlfile, parser) + except etree.XMLSyntaxError as exc: + # prob inp.xml file broken + err_msg = ('The inp.xml file is probably broken, could not parse it to an xml etree.') + raise InputValidationError(err_msg) from exc # relax.xml should be available to be used in xinclude # hence copy relax.xml from the retrieved node into the temp file fo = tempfile.NamedTemporaryFile(mode='w', delete=False) @@ -464,7 +468,8 @@ def _set_inp_dict(self): tree_x = etree.fromstring(inpxmlfile, parser_on_fly) except etree.XMLSyntaxError as msg: message = msg - raise InputValidationError('Input file does not validate against the schema: {}'.format(message)) + raise InputValidationError( + 'Input file does not validate against the schema: {}'.format(message)) from msg raise InputValidationError('Input file is not validated against the schema.' 'Reason is unknown') @@ -491,7 +496,7 @@ def _validate(self): """ #from aiida.common.exceptions import ValidationError - super(FleurinpData, self)._validate() + super()._validate() if 'inp.xml' in self.files: # has_inpxml = True # does nothing so far @@ -943,108 +948,6 @@ def get_parameterdata(fleurinp): return fleurinp.get_parameterdata_ncf() - @cf - def set_kpointsdata(self, fleurinp_orgi, KpointsDataNode): - """ - This calc function writes the all the kpoints from a :class:`~aiida.orm.KpointsData` node - in the ``inp.xml`` file as a kpointslist. It replaces kpoints written in the - ``inp.xml`` file. The output :class:`~aiida_fleur.data.fleurinp.FleurinpData` is stored in - the database. - - Currently it is the users resposibility to provide a full - :class:`~aiida.orm.KpointsData` node with weights. - - :param KpointsDataNode: :class:`~aiida.orm.KpointsData` node to be written into ``inp.xml`` - :returns: modified :class:`~aiida_fleur.data.fleurinp.FleurinpData` node - """ - from aiida.orm import KpointsData - #from aiida.common.exceptions import InputValidationError - - # all hardcoded xpaths used and attributes names: - fleurinp = fleurinp_orgi.copy() - kpointlist_xpath = '/fleurInput/calculationSetup/bzIntegration/kPointList' - #kpoint_tag = 'kPoint' - #kpointlist_attrib_posscale = 'posScale' - #kpointlist_attrib_weightscale = 'weightScale' - #kpointlist_attrib_count = 'count' - #kpoint_attrib_weight = 'weight' - - #### method layout: ##### - # Check if Kpoints node - # get kpoints, weights, inp.xml - - # replace the kpoints tag.(delete old write new) - # kpoint list posScale, wightScale, count - # - # 17.000000 0.000000 0.000000 - - # add new inp.xml to fleurinpdata - - if not isinstance(KpointsDataNode, KpointsData): - raise InputValidationError('The node given is not a valid KpointsData node.') - - if 'inp.xml' in fleurinp.files: - # read in inpxml - if fleurinp._schema_file_path: # Schema there, parse with schema - xmlschema_doc = etree.parse(fleurinp._schema_file_path) - xmlschema = etree.XMLSchema(xmlschema_doc) - parser = etree.XMLParser(schema=xmlschema, - attribute_defaults=True, - remove_blank_text=True, - encoding='utf-8') - with fleurinp.open(path='inp.xml', mode='r') as inpxmlfile: - tree = etree.parse(inpxmlfile, parser) - else: # schema not there, parse without - print('parsing inp.xml without XMLSchema') - parser = etree.XMLParser(attribute_defaults=True, remove_blank_text=True, encoding='utf-8') - with self.open(path='inp.xml', mode='r') as inpxmlfile: - tree = etree.parse(inpxmlfile, parser) - #root = tree.getroot() - else: - raise InputValidationError('No inp.xml file yet specified, to add kpoints to.') - - #cell_k = KpointsDataNode.cell - - # TODO: shall we check if cell is the same as cell from structure? - # or is that to narrow? - - kpoint_list = KpointsDataNode.get_kpoints(also_weights=True, cartesian=False) - nkpts = len(kpoint_list[0]) - totalw = 0 - for weight in kpoint_list[1]: - totalw = totalw + weight - #weightscale = totalw - - new_kpo = etree.Element('kPointList', posScale='1.000', weightScale='1.0', count='{}'.format(nkpts)) - for i, kpos in enumerate(kpoint_list[0]): - new_k = etree.Element('kPoint', weight='{}'.format(kpoint_list[1][i])) - new_k.text = '{} {} {}'.format(kpos[0], kpos[1], kpos[2]) - new_kpo.append(new_k) - - new_tree = replace_tag(tree, kpointlist_xpath, new_kpo) - # use _write_new_fleur_xmlinp_file(fleurinp, inp_file_xmltree, fleur_change_dic): - - # TODO this should be sourced out to other methods. - # somehow directly writing inp.xml does not work, create new one - inpxmlfile = os.path.join(fleurinp._get_folder_pathsubfolder.abspath, 'temp_inp.xml') - - # write new inp.xml, schema evaluation will be done when the file gets added - new_tree.write(inpxmlfile, pretty_print=True) - print(('wrote tree to' + str(inpxmlfile))) - - # delete old inp.xml file, not needed anymore - # TODO maybe do some checks before - fleurinp.del_file('inp.xml') - - # now the new inp.xml file is added and with that the inpxml_dict will - # be overwritten, and the file validated - fleurinp._add_path(str(inpxmlfile), 'inp.xml') - - # remove temporary inp.xml file - os.remove(inpxmlfile) - - return fleurinp - def get_tag(self, xpath): """ Tries to evaluate an xpath expression for ``inp.xml`` file. If it fails it logs it. @@ -1071,10 +974,10 @@ def get_tag(self, xpath): try: return_value = root.xpath(xpath) - except etree.XPathEvalError: + except etree.XPathEvalError as exc: raise InputValidationError('There was a XpathEvalError on the xpath: {} \n Either it does ' 'not exist, or something is wrong with the expression.' - ''.format(xpath)) + ''.format(xpath)) from exc if len(return_value) == 1: return return_value diff --git a/aiida_fleur/data/fleurinpmodifier.py b/aiida_fleur/data/fleurinpmodifier.py index c2fd569e8..d95f4c3af 100644 --- a/aiida_fleur/data/fleurinpmodifier.py +++ b/aiida_fleur/data/fleurinpmodifier.py @@ -23,6 +23,7 @@ from lxml import etree from aiida.plugins import DataFactory +from aiida import orm from aiida.engine.processes.functions import calcfunction as cf from aiida_fleur.data.fleurinp import FleurinpData @@ -40,6 +41,7 @@ def __init__(self, original): self._original = original self._tasks = [] + self._other_nodes = {} @staticmethod def apply_modifications(fleurinp_tree_copy, nmmp_lines_copy, modification_tasks, schema_tree=None): @@ -153,6 +155,10 @@ def set_kpath1(fleurinp_tree_copy, kpath, count, gamma): fleurinp_tree_copy = set_kpath(fleurinp_tree_copy, kpath, count, gamma) return fleurinp_tree_copy + def set_kpointsdata1(fleurinp_tree_copy, kpointsdata_uuid): + fleurinp_tree_copy = set_kpointsdata_f(fleurinp_tree_copy, kpointsdata_uuid) + return fleurinp_tree_copy + def set_nmmpmat1(fleurinp_tree_copy, nmmp_lines_copy, species_name, orbital,\ spin, occStates, denmat, phi, theta): nmmp_lines_copy = set_nmmpmat(fleurinp_tree_copy, nmmp_lines_copy, species_name, orbital,\ @@ -179,8 +185,9 @@ def set_nmmpmat1(fleurinp_tree_copy, nmmp_lines_copy, species_name, orbital,\ 'shift_value_species_label': shift_value_species_label1, 'set_nkpts': set_nkpts1, 'set_kpath': set_kpath1, + 'set_kpointsdata': set_kpointsdata1, 'add_num_to_att': add_num_to_att1, - 'set_nmmpmat': set_nmmpmat1, + 'set_nmmpmat': set_nmmpmat1 } workingtree = fleurinp_tree_copy @@ -192,8 +199,8 @@ def set_nmmpmat1(fleurinp_tree_copy, nmmp_lines_copy, species_name, orbital,\ for task in modification_tasks: try: action = actions[task[0]] - except KeyError: - raise ValueError('Unknown task {}'.format(task[0])) + except KeyError as exc: + raise ValueError('Unknown task {}'.format(task[0])) from exc if task[0] == 'set_nmmpmat': workingnmmp = action(workingtree, workingnmmp, *task[1:]) @@ -203,14 +210,16 @@ def set_nmmpmat1(fleurinp_tree_copy, nmmp_lines_copy, species_name, orbital,\ if schema_tree: try: xmlschema.assertValid(clear_xml(workingtree)) - except etree.DocumentInvalid: - print('changes were not valid: {}'.format(modification_tasks)) - raise + except etree.DocumentInvalid as exc: + msg = 'Changes were not valid: {}'.format(modification_tasks) + print(msg) + raise etree.DocumentInvalid(msg) from exc try: validate_nmmpmat(workingtree, workingnmmp) - except ValueError: - print('changes were not valid (n_mmp_mat file is not compatible): {}'.format(modification_tasks)) - raise + except ValueError as exc: + msg = 'Changes were not valid (n_mmp_mat file is not compatible): {}'.format(modification_tasks) + print(msg) + raise ValueError(msg) from exc return workingtree, workingnmmp @@ -237,8 +246,10 @@ def get_avail_actions(self): 'shift_value': self.shift_value, 'shift_value_species_label': self.shift_value_species_label, 'set_nkpts': self.set_nkpts, + 'set_kpath': self.set_kpath, + 'set_kpointsdata': self.set_kpointsdata, 'add_num_to_att': self.add_num_to_att, - 'set_nmmpmat': self.set_nmmpmat, + 'set_nmmpmat': self.set_nmmpmat } return outside_actions @@ -455,6 +466,21 @@ def set_kpath(self, kpath, count, gamma='F'): """ self._tasks.append(('set_kpath', kpath, count, gamma)) + def set_kpointsdata(self, kpointsdata_uuid): + """ + Appends a :py:func:`~aiida_fleur.data.fleurinpmodifier.set_kpointsdata_f()` to + the list of tasks that will be done on the FleurinpData. + + :param kpointsdata_uuid: an :class:`aiida.orm.KpointsData` or node uuid, since the node is self cannot be be serialized in tasks. + """ + from aiida.orm import KpointsData, load_node + + if isinstance(kpointsdata_uuid, KpointsData): + kpointsdata_uuid = kpointsdata_uuid.uuid + # Be more careful? Needs to be stored, otherwise we cannot load it + self._other_nodes['kpoints'] = load_node(kpointsdata_uuid) + self._tasks.append(('set_kpointsdata', kpointsdata_uuid)) + def add_num_to_att(self, xpathn, attributename, set_val, mode='abs', occ=None): """ Appends a :py:func:`~aiida_fleur.tools.xml_util.add_num_to_att()` to @@ -552,16 +578,20 @@ def freeze(self): :return: stored :class:`~aiida_fleur.data.fleurinp.FleurinpData` with applied changes """ - modifications = DataFactory('dict')(dict={'tasks': self._tasks}) + modifications = orm.Dict(dict={'tasks': self._tasks}) + #print(self._tasks) modifications.description = 'Fleurinpmodifier Tasks and inputs of these.' modifications.label = 'Fleurinpdata modifications' # This runs in a inline calculation to keep provenance - out = modify_fleurinpdata(original=self._original, - modifications=modifications, - metadata={ - 'label': 'fleurinp modifier', - 'description': 'This calcfunction modified an Fleurinpdataobject' - }) + print(self._original) + inputs = dict(original=self._original, + modifications=modifications, + metadata={ + 'label': 'fleurinp modifier', + 'description': 'This calcfunction modified an Fleurinpdataobject' + }, + **self._other_nodes) + out = modify_fleurinpdata(**inputs) return out def undo(self, revert_all=False): @@ -574,20 +604,21 @@ def undo(self, revert_all=False): self._tasks = [] else: if self._tasks: - self._tasks.pop() + task = self._tasks.pop() + #TODO delete nodes from other nodes #del self._tasks[-1] return self._tasks @cf -def modify_fleurinpdata(original, modifications): +def modify_fleurinpdata(original, modifications, **kwargs): """ A CalcFunction that performs the modification of the given FleurinpData and stores the result in a database. :param original: a FleurinpData to be modified :param modifications: a python dictionary of modifications in the form of {'task': ...} - + :param kwargs: dict of other aiida nodes to be linked to the modifications :returns new_fleurinp: a modified FleurinpData that is stored in a database """ @@ -611,9 +642,10 @@ def modify_fleurinpdata(original, modifications): try: xmlschema.assertValid(clear_xml(tree)) - except etree.DocumentInvalid: - print('Input file is not validated against the schema') - raise + except etree.DocumentInvalid as exc: + msg = 'Input file is not validated against the schema' + print(msg) + raise etree.DocumentInvalid(msg) from exc try: with new_fleurinp.open(path='n_mmp_mat', mode='r') as n_mmp_file: @@ -645,3 +677,51 @@ def modify_fleurinpdata(original, modifications): new_fleurinp.description = 'Fleurinpdata with modifications (see inputs of modify_fleurinpdata)' return new_fleurinp + + +def set_kpointsdata_f(fleurinp_tree_copy, kpointsdata_uuid): + """This calc function writes all kpoints from a :class:`~aiida.orm.KpointsData` node + in the ``inp.xml`` file as a kpointslist. It replaces kpoints written in the + ``inp.xml`` file. Currently it is the users responsibility to provide a full + :class:`~aiida.orm.KpointsData` node with weights. + + :param fleurinp_tree_copy: fleurinp_tree_copy + :param kpointsdata_uuid: node identifier or :class:`~aiida.orm.KpointsData` node to be written into ``inp.xml`` + :return: modified xml tree + """ + # TODO: check on weights, + # also fleur allows for several kpoint sets, lists, paths and meshes, + # support this. + from aiida.orm import KpointsData, load_node + from aiida.common.exceptions import InputValidationError + from aiida_fleur.tools.xml_util import replace_tag + + # all hardcoded xpaths used and attributes names: + kpointlist_xpath = '/fleurInput/calculationSetup/bzIntegration/kPointList' + + # replace the kpoints tag.(delete old write new) + # + # 17.000000 0.000000 0.000000 + # add new inp.xml to fleurinpdata + if not isinstance(kpointsdata_uuid, KpointsData): + KpointsDataNode = load_node(kpointsdata_uuid) + else: + KpointsDataNode = kpointsdata_uuid + + if not isinstance(KpointsDataNode, KpointsData): + raise InputValidationError('The node given is not a valid KpointsData node.') + + kpoint_list = KpointsDataNode.get_kpoints(also_weights=True, cartesian=False) + nkpts = len(kpoint_list[0]) + totalw = 0 + for weight in kpoint_list[1]: + totalw = totalw + weight + #weightscale = totalw + # fleur will re weight? renormalize? + new_kpo = etree.Element('kPointList', posScale='1.000', weightScale='1.0', count='{}'.format(nkpts)) + for i, kpos in enumerate(kpoint_list[0]): + new_k = etree.Element('kPoint', weight='{}'.format(kpoint_list[1][i])) + new_k.text = '{} {} {}'.format(kpos[0], kpos[1], kpos[2]) + new_kpo.append(new_k) + new_tree = replace_tag(fleurinp_tree_copy, kpointlist_xpath, new_kpo) + return new_tree diff --git a/aiida_fleur/parsers/fleur.py b/aiida_fleur/parsers/fleur.py index e408558f5..e810febb3 100644 --- a/aiida_fleur/parsers/fleur.py +++ b/aiida_fleur/parsers/fleur.py @@ -22,12 +22,14 @@ import os import re import json +import numpy as np from datetime import date from lxml import etree from aiida.parsers import Parser from aiida.orm import Dict, BandsData from aiida.common.exceptions import NotExistent +from aiida_fleur.common.constants import HTR_TO_EV class FleurParser(Parser): @@ -139,7 +141,8 @@ def parse(self, **kwargs): mpiprocs = self.node.get_attribute('resources').get('num_mpiprocs_per_machine', 1) kb_used = 0.0 - with output_folder.open('out.xml', 'r') as out_file: # lazy out.xml parsing + with output_folder.open(FleurCalculation._OUTXML_FILE_NAME, + 'r') as out_file: # lazy out.xml parsing outlines = out_file.read() try: line_avail = re.findall(r' 0: + new_parameterd[atomlistname] = val + ids.remove(el_id) + symbol_possible_ids[symbol] = ids + kind_found = True + break # we assume the user is smart and provides a para node, + # which incorporates the symmetry breaking already + # but we need to see all atom lists to know if it is there... + if kind_found: + continue + for key in sorted(para): + val = para[key] + if 'atom' in key: + if val.get('element', None) != symbol: + if val.get('z', None) != _atomic_numbers.get(symbol): + continue + el_id = str(val.get('id', '0.0')) + el_id = int(el_id.split('.')[1]) + ids = symbol_possible_ids.get(symbol) + # copy parameter of symbol and add id + # this would be the lowest predefined atom list of an element + val_new = {} + val_new.update(val) + charge = _atomic_numbers.get((val.get('element', None))) + if charge is None: + charge = val.get('z', None) + idp = '{}.{}'.format(charge, ids[0]) + ids.remove(el_id) + idp = float('{0:.2f}'.format(float(idp))) + # dot cannot be stored in AiiDA dict... + val_new.update({u'id': idp}) + atomlistname = 'atom{}'.format(i)#id_a) + # Since there are other atoms list also find the next + # free atom key. + #j = 0 + #while new_parameterd.get(atomlistname, {}): + # j = j + 1 + # atomlistname = 'atom{}'.format(id_a + i) + #symbol_new_kinds_names = new_kinds_names.get(symbol, []) + # print(symbol_new_kinds_names) + #if symbol_new_kinds_names and ((len(symbol_new_kinds_names)) == symbol_count[symbol]): + # species_name = symbol_new_kinds_names[symbol_count[symbol] - 1] + # val_new.update({u'name': species_name}) + new_parameterd[atomlistname] = val_new + break # max one new atom list per kind +''' +''' + # add other non atom keys from original parameterdata + for key, val in para.items(): + if 'atom' not in key: + new_parameterd[key] = val + elif add_atom_base_lists: + if not 'id' in val: + new_parameterd[key] = val para_new = Dict(dict=new_parameterd) else: para_new = None + print(new_parameterd) new_structure.label = structure.label new_structure.description = structure.description + 'more kinds, less sym' return new_structure, para_new +''' def find_equi_atoms(structure): # , sitenumber=0, position=None): @@ -663,9 +978,11 @@ def get_all_miller_indices(structure, highestindex): """ wraps the pymatgen function get_symmetrically_distinct_miller_indices for an AiiDa structure """ + from pymatgen.core.surface import get_symmetrically_distinct_miller_indices return get_symmetrically_distinct_miller_indices(structure.get_pymatgen_structure(), highestindex) +''' def create_all_slabs_buggy(initial_structure, miller_index, min_slab_size_ang, @@ -705,6 +1022,7 @@ def create_all_slabs_buggy(initial_structure, film_struc.pbc = (True, True, False) aiida_strucs[slab.miller_index] = film_struc return aiida_strucs +''' def create_all_slabs(initial_structure, @@ -728,9 +1046,9 @@ def create_all_slabs(initial_structure, indices = get_all_miller_indices(initial_structure, miller_index) for index in indices: slab = create_slap(initial_structure, index, min_slab_size_ang, min_vacuum_size, min_slab_size_ang) - film_struc = StructureData(pymatgen_structure=slab) - film_struc.pbc = (True, True, False) - aiida_strucs[slab.miller_index] = film_struc + #film_struc = StructureData(pymatgen_structure=slab) + #film_struc.pbc = (True, True, False) + aiida_strucs[index] = slab return aiida_strucs @@ -869,7 +1187,7 @@ def create_manual_slab_ase(lattice='fcc', *_, layer_occupancies = get_layers(structure) if replacements is not None: - keys = six.viewkeys(replacements) + keys = list(replacements.keys()) if max((abs(int(x)) for x in keys)) >= len(layer_occupancies): raise ValueError('"replacements" has to contain numbers less than number of layers:' ' {}'.format(len(layer_occupancies))) @@ -894,7 +1212,7 @@ def create_manual_slab_ase(lattice='fcc', *_, layer_occupancies = get_layers(structure) layer_occupancies.insert(0, 0) - for i, at_type in six.iteritems(replacements): + for i, at_type in replacements.items(): if isinstance(i, str): i = int(i) if i < 0: @@ -1271,6 +1589,7 @@ def request_average_bond_length(main_elements, sub_elements, user_api_key): return Dict(dict=bond_data) +''' def estimate_mt_radii(structure, stepsize=0.05): """ # TODO implement @@ -1311,3 +1630,4 @@ def find_common_mt(structures): """ return None +''' diff --git a/aiida_fleur/tools/check_existence.py b/aiida_fleur/tools/check_existence.py deleted file mode 100644 index 9af938de1..000000000 --- a/aiida_fleur/tools/check_existence.py +++ /dev/null @@ -1,252 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -############################################################################### -# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # -# All rights reserved. # -# This file is part of the AiiDA-FLEUR package. # -# # -# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # -# For further information on the license, see the LICENSE.txt file # -# For further information please visit http://www.flapw.de or # -# http://aiida-fleur.readthedocs.io/en/develop/ # -############################################################################### -""" -DO NOT USE, this is crab so far. The development was stoped because this is done -with AiiDA 'caching' now. - -Here are methods to check the existence of something in the database -example if a (successful) SCF with the same inputs exists - -Since cashing is not there for data yet, and below are some basic querries I -leave the code here for now. -""" -from __future__ import absolute_import -from aiida.plugins import DataFactory -from aiida.orm import QueryBuilder -from aiida.engine import CalcJob -from aiida.orm import Node -''' -def check_existence_calc(input_nodes, successful=True): - """ - This methods checks in the database waether a certain type of node with the given - input nodes already exists. If yes it returns the output nodes of that node. - - param: input_nodes : List of input nodes - - returns output nodes - """ - #TODO: some checks and inputnodes could be parsed in different formats - inputnodesuuid = [node.uuid for node in input_nodes] - - qb=QueryBuilder() - qb.append( - JobCalculation, tag='calc', project='*', - filters={'state' : {'==':'FINISHED'}}) - - for idx, uuid in enumerate(inputnodesuuid): - qb.append(Node, input_of='calc', filters={'uuid':uuid}, - tag='input_{}'.format(idx)) - - qb.order_by({JobCalculation:'ctime'}) - res = qb.all() - if res: - return res[-1][0].get_outputs() - else: - return None - -def check_existence_wf(input_nodes, successful=True): - """ - This methods checks in the database waether a certain type of node with the given - input nodes already exists. If yes it returns the output nodes of that node. - - param: input_nodes : List of input nodes - - returns output nodes - """ - #TODO: some checks and inputnodes could be parsed in different formats - inputnodesuuid = [node.uuid for node in input_nodes] - - qb=QueryBuilder() - qb.append( - JobCalculation, tag='calc', project='*', - filters={'state' : {'==':'FINISHED'}}) - - for idx, uuid in enumerate(inputnodesuuid): - qb.append(Node, input_of='calc', filters={'uuid':uuid}, tag='input_{}'.format(idx)) - - qb.order_by({JobCalculation:'ctime'}) - res = qb.all() - if res: - return res[-1][0].get_outputs() - else: - return None - -''' -''' -def intersectlist(l1, l2): - common = [] - for element in l1: - if element in l2: - common.append(element) - return common - -def check_existence_calc(input_nodes, successful=True): - """ - This methods checks in the database waether a certain type of node with the given - input nodes already exists. If yes it returns the output nodes of that node. - - param: input_nodes : List of input nodes - - returns output nodes - """ - inputnodesuuid = [node.uuid for node in input_nodes] - overall_results = [] - - for node in inputnodesuuid: - suc = successful - qb=QueryBuilder() - qb.append(Node, - filters={ - 'uuid' : {'==': node}, - }, - tag='input') - if suc: - qb.append( - JobCalculation, - filters={ - 'state' : {'==':'FINISHED'} - }, - output_of='input') - else: - qb.append( - JobCalculation, - output_of='input', - project=['uuid']) - res = qb.all() - if res: # if there is no node with such an input return - resnodesuuid = [node[0].uuid for node in res] # needed for common list parts - overall_results.append(resnodesuuid) - else: - return None - - intersect = overall_results[0] - if len(overall_results) > 1: - for res in overall_results[1:]: - intersect = intersectlist(intersect, res) - qb1=QueryBuilder() - qb1.append( - JobCalculation, - filters={ - 'uuid' : {'in': intersect} - }) - res = qb1.all() - # we - return res[0][0].outputs() -''' -''' -def check_existence(target_nodetype, input_nodes, successful=False): - """ - This methods checks in the database waether a certain type of node with the given - input nodes already exists. If yes it returns the output nodes of that node. - - param: target_nodetype - param: input_nodes : List of input nodes - - returns output nodes - - Hints; successful is only for calculations types - """ - inputnodesuuid = [node.uuid for node in input_nodes] - qb=QueryBuilder() - qb.append(Node, - filters={ - 'uuid' : {'in': inputnodesuuid}, - }, - tag='input') - if successful: - qb.append( - target_nodetype, - filters={ - 'state' : {'==':'FINISHED'} - }, - output_of='input') - else: - qb.append( - target_nodetype, - output_of='input') - res = qb.all() - print(len(res)) - if res: - return res[0][0].ouputs() - else: - return None - -def check_existence_calc(input_nodes, successful=True): - """ - This methods checks in the database waether a certain type of node with the given - input nodes already exists. If yes it returns the output nodes of that node. - - param: input_nodes : List of input nodes - - returns output nodes - """ - inputnodesuuid = [node.uuid for node in input_nodes] - qb=QueryBuilder() - qb.append(Node, - filters={ - 'uuid' : {'in': inputnodesuuid}, - }, - tag='input') - if successful: - qb.append( - JobCalculation, - filters={ - 'state' : {'==':'FINISHED'} - }, - output_of='input') - else: - qb.append( - JobCalculation, - output_of='input') - - res = qb.all() - print(len(res)) - if res: - return res[0][0].ouputs() - else: - return None - -def check_existence_wf(target_nodetype, input_nodes, successful=True): - """ - This methods checks in the database waether a certain type of node with the given - input nodes already exists. If yes it returns the output nodes of that node. - - param: input_nodes : List of input nodes - - returns output nodes - """ - inputnodesuuid = [node.uuid for node in input_nodes] - qb=QueryBuilder() - qb.append(Node, - filters={ - 'uuid' : {'in': inputnodesuuid}, - }, - tag='input') - if successful: - qb.append( - target_nodetype, - filters={ - 'state' : {'==':'FINISHED'} - }, - output_of='input') - else: - qb.append( - target_nodetype, - output_of='input') - res = qb.all() - print(len(res)) - if res: - return res[0][0].ouputs() - else: - return None -''' diff --git a/aiida_fleur/tools/common_aiida.py b/aiida_fleur/tools/common_aiida.py index 25549bb71..997d76e4d 100644 --- a/aiida_fleur/tools/common_aiida.py +++ b/aiida_fleur/tools/common_aiida.py @@ -192,6 +192,7 @@ def create_group(name, nodes, description=None, add_if_exist=False): """ Creates a group for a given node list. + !!! Now aiida-core has these functionality, use it from there instead!!! So far this is only an AiiDA verdi command. :params name: string name for the group @@ -246,6 +247,8 @@ def create_group(name, nodes, description=None, add_if_exist=False): def get_nodes_from_group(group, return_format='uuid'): """ Returns a list of pk or uuid of a nodes in a given group. Since 1.1.0, this function does + !!! Now aiida-core has these functionality, use it from there instead!!! + not load a group using the label or any other identification. Use Group.objects.get(filter=ID) to pre-load this, available filters are: id, uuid, label, type_string, time, description, user_id. """ diff --git a/aiida_fleur/tools/common_fleur_wf.py b/aiida_fleur/tools/common_fleur_wf.py index 34e5cbf08..05096931a 100644 --- a/aiida_fleur/tools/common_fleur_wf.py +++ b/aiida_fleur/tools/common_fleur_wf.py @@ -139,7 +139,7 @@ def get_inputs_fleur(code, return inputs -def get_inputs_inpgen(structure, inpgencode, options, label='', description='', params=None, **kwargs): +def get_inputs_inpgen(structure, inpgencode, options, label='', description='', settings=None, params=None, **kwargs): ''' Assembles the input dictionary for Fleur Calculation. @@ -167,7 +167,8 @@ def get_inputs_inpgen(structure, inpgencode, options, label='', description='', inputs.code = inpgencode if params: inputs.parameters = params - + if settings: + inputs.settings = settings if description: inputs.metadata.description = description else: @@ -194,69 +195,6 @@ def get_inputs_inpgen(structure, inpgencode, options, label='', description='', return inputs -def get_scheduler_extras(code, resources, extras=None, project='jara0172'): - """ - This is a utility function with the goal to make prepare the right resource - and scheduler extras for a given computer. - Since this is user dependend you might want to create your own. - - return: dict, custom scheduler commands - """ - if extras is None: - extras = {} - nnodes = resources.get('num_machines', 1) - - # TODO memory has to be done better... - mem_per_node = 120000 # max recommend 126000 MB on claix jara-clx nodes - mem_per_process = mem_per_node / 24 - if not extras: - # use defaults # TODO add other things, span, pinnning... openmp - extras = { - 'lsf': ('#BSUB -P {} \n#BSUB -M {} \n' - '#BSUB -a intelmpi'.format(project, mem_per_process)), - 'torque': '', - 'direct': '' - } - - # get the scheduler type from the computer the code is run on. - com = code.computer - # com_name = com.get_name() - scheduler_type = com.get_scheduler_type() - - default_per_machine = com.get_default_mpiprocs_per_machine() - if not default_per_machine: - default_per_machine = 24 # claix, lsf does can not have default mpiprocs... #TODO this better - tot_num_mpiprocs = resources.get('tot_num_mpiprocs', default_per_machine * nnodes) - - if scheduler_type == 'lsf': - new_resources = {'tot_num_mpiprocs': tot_num_mpiprocs} # only this needs to be given - elif scheduler_type == 'torque': - # {'num_machines', 1} # on iff003 currently we do not do multinode mpi, - new_resources = resources - # like this it will get stuck on iff003 - else: - new_resources = resources - scheduler_extras = extras.get(scheduler_type, '') - - return new_resources, scheduler_extras - - -# test -############################### -# codename = 'inpgen@local_mac'#'inpgen_v0.28@iff003'#'inpgen_iff@local_iff' -# codename2 = 'fleur_v0.28@iff003'#'fleur_mpi_v0.28@iff003'# 'fleur_iff_0.28@local_iff'' -# codename2 = 'fleur_max_1.3_dev@iff003' -# codename2 = 'fleur_mpi_max_1.3_dev@iff003' -# codename4 = 'fleur_mpi_v0.28@claix' -############################### -# code = Code.get_from_string(codename) -# code2 = Code.get_from_string(codename2) -# code4 = Code.get_from_string(codename4) -# print(get_scheduler_extras(code, {'num_machines' : 1})) -# print(get_scheduler_extras(code2, {'num_machines' : 2})) -# print(get_scheduler_extras(code4, {'num_machines' : 1})) - - def test_and_get_codenode(codenode, expected_code_type, use_exceptions=False): """ Pass a code node and an expected code (plugin) type. Check that the @@ -280,7 +218,7 @@ def test_and_get_codenode(codenode, expected_code_type, use_exceptions=False): code = codenode if code.get_input_plugin_name() != expected_code_type: raise ValueError - except ValueError: + except ValueError as exc: from aiida.orm.querybuilder import QueryBuilder qb = QueryBuilder() qb.append(Code, filters={'attributes.input_plugin': {'==': expected_code_type}}, project='*') @@ -293,7 +231,7 @@ def test_and_get_codenode(codenode, expected_code_type, use_exceptions=False): msg += '\n'.join('* {}'.format(l) for l in valid_code_labels) if use_exceptions: - raise ValueError(msg) + raise ValueError(msg) from exc else: print(msg) # , file=sys.stderr) sys.exit(1) @@ -302,7 +240,7 @@ def test_and_get_codenode(codenode, expected_code_type, use_exceptions=False): 'Configure at least one first using\n' ' verdi code setup'.format(expected_code_type)) if use_exceptions: - raise ValueError(msg) + raise ValueError(msg) from exc else: print(msg) # , file=sys.stderr) sys.exit(1) @@ -353,6 +291,9 @@ def determine_favorable_reaction(reaction_list, workchain_dict): workchain_dict = {'Be12W' : uuid_wc or output, 'Be2W' : uuid, ...} return dictionary that ranks the reactions after their enthalpy + + TODO: refactor aiida part out of this, leaving an aiida independent part and one + more universal """ from aiida.engine import WorkChain from aiida_fleur.tools.common_fleur_wf_util import get_enhalpy_of_equation @@ -384,7 +325,7 @@ def determine_favorable_reaction(reaction_list, workchain_dict): except (AttributeError, KeyError, ValueError): # TODO: Check this ouputnode = None formenergy = None - print(('WARNING: ouput node of {} not found. I skip'.format(n))) + print(('WARNING: output node of {} not found. I skip'.format(n))) continue formenergy = ouputnode.get('formation_energy') # TODO is this value per atom? @@ -401,28 +342,6 @@ def determine_favorable_reaction(reaction_list, workchain_dict): return energy_sorted_reactions -# test -# reaction_list = ['1*Be12W->1*Be12W', '2*Be12W->1*Be2W+1*Be22W', '11*Be12W->5*W+6*Be22W', '1*Be12W->12*Be+1*W', '1*Be12W->1*Be2W+10*Be'] -# workchain_dict = {'Be12W' : '4f685bc5-b5fb-46d3-aad6-e0f512c3313d', -# 'Be2W' : '045d3071-f442-46b4-8d6b-3c85d72b24d4', -# 'Be22W' : '1e32880a-bdc9-4081-a5da-be04860aa1bc', -# 'W' : 'f8b12b23-0b71-45a1-9040-b51ccf379439', -# 'Be' : 0.0} -# reac_list = determine_favorable_reaction(reaction_list, workchain_dict) -# print reac_list -# {'products': {'Be12W': 1}, 'educts': {'Be12W': 1}} -# 0.0 -# {'products': {'Be2W': 1, 'Be22W': 1}, 'educts': {'Be12W': 2}} -# 0.114321037514 -# {'products': {'Be22W': 6, 'W': 5}, 'educts': {'Be12W': 11}} -# -0.868053153884 -# {'products': {'Be': 12, 'W': 1}, 'educts': {'Be12W': 1}} -# -0.0946046496213 -# {'products': {'Be': 10, 'Be2W': 1}, 'educts': {'Be12W': 1}} -# 0.180159355144 -# [['11*Be12W->5*W+6*Be22W', -0.8680531538839534], ['1*Be12W->12*Be+1*W', -0.0946046496213127], ['1*Be12W->1*Be12W', 0.0], ['2*Be12W->1*Be2W+1*Be22W', 0.11432103751404535], ['1*Be12W->1*Be2W+10*Be', 0.1801593551436103]] - - def performance_extract_calcs(calcs): """ Extracts some runtime and system data from given fleur calculations diff --git a/aiida_fleur/tools/common_fleur_wf_util.py b/aiida_fleur/tools/common_fleur_wf_util.py index 4599728d9..54d9eb23c 100644 --- a/aiida_fleur/tools/common_fleur_wf_util.py +++ b/aiida_fleur/tools/common_fleur_wf_util.py @@ -568,13 +568,3 @@ def check_eos_energies(energylist): print('annormly detected') return abnormality, abnormalityindexlist - - -#total_energy = [ -1, -2, -3 ,-2,-4,-3,-2,-1] -#check_eos_energies(total_energy) -#(True, [3]) -#total_energy = [ -1, -2, -3 ,-2,-2,-3,-2,-1] -#check_eos_energies(total_energy) -#(False, []) -#total_energy = [ -1, -2, -3 ,-4,-5,-3,-2,-1] -#(False, []) diff --git a/aiida_fleur/tools/create_corehole.py b/aiida_fleur/tools/create_corehole.py index b81cc5617..a9a94b347 100644 --- a/aiida_fleur/tools/create_corehole.py +++ b/aiida_fleur/tools/create_corehole.py @@ -13,48 +13,41 @@ Contains helper functions to create core-holes in Fleur input files from AiiDA data nodes. ''' -from __future__ import absolute_import -from __future__ import print_function -from aiida.plugins import DataFactory -import six + # TODO maybe merge these methods into fleurinp or structure util? or create a parameterData utils #355 - - def create_corehole_para(structure, kind, econfig, species_name='corehole', parameterdata=None): """ This methods sets of electron configurations for a kind or position given, make sure to break the symmetry for this position/kind beforehand, otherwise you will create several coreholes. - param: structure: StructureData - param: kind, a string with the kind_name (TODO: alternative the kind object) - param: econfig, string, e.g. econfig = "[Kr] 5s2 4d10 4f13 | 5p6 5d5 6s2" - ! THis is the new econfig therefore + :param structure: StructureData + :param kind: a string with the kind_name (TODO: alternative the kind object) + :param econfig: string, e.g. econfig = "[Kr] 5s2 4d10 4f13 | 5p6 5d5 6s2" to set, i.e. the corehole - returns a Dict node + :return: a Dict node """ - + # TODO: Since fleur MaXR5 there is a default econfig file and the order behavior + # has changed. now to atom lists only change the default if they have an id. from aiida.common.constants import elements as PeriodicTableElements - - _atomic_numbers = {data['symbol']: num for num, data in six.iteritems(PeriodicTableElements)} + from aiida import orm + _atomic_numbers = {data['symbol']: num for num, data in PeriodicTableElements.items()} #from aiida_fleur.tools.merge_parameter import merge_parameter kindo = structure.get_kind(kind) symbol = kindo.symbol head = kindo.name.rstrip('01223456789') - #print(kindo) charge = _atomic_numbers[kindo.symbol] a_id = float('{}.{}'.format(charge, kindo.name[len(head):])) - #print('a_id {}'.format(a_id)) # get kind symbol, get kind name, #&atom element="W" jri=921 lmax=8 rmt=2.52 dx=0.014 lo="5p" econfig="[Kr] 5s2 4d10 4f13 | 5p6 5d4 6s2" / #count = 0 if parameterdata: new_parameterd = parameterdata.get_dict() # dict()otherwise parameterdata is changed - for key, val in six.iteritems(new_parameterd): + for key, val in new_parameterd.items(): if 'atom' in key: if val.get('element', None) == symbol: # remember atomic id is atomic number.some int @@ -74,13 +67,13 @@ def create_corehole_para(structure, kind, econfig, species_name='corehole', para else: new_parameterd = {'atom': {'element': symbol, 'econfig': econfig}} - from aiida.orm import Dict - new_parameter = Dict(dict=new_parameterd) + new_parameter = orm.Dict(dict=new_parameterd) #if parameterdata: # new_parameter = merge_parameter(parameterdata, new_parameter) return new_parameter #structure +''' # Move to fleurinpmod? fleurinp->self # This method is fully implemented yet since it turned out to better go over inpgen def create_corehole_fleurinp(fleurinp, species, stateocc, pos=None, coreconfig='same', valenceconfig='same'): @@ -110,14 +103,14 @@ def create_corehole_fleurinp(fleurinp, species, stateocc, pos=None, coreconfig=' :return: the changes fleurinpData object """ - ''' - - [Kr] (5s1/2) (4d3/2) (4d5/2) (4f5/2) (4f7/2) - (5p1/2) (5p3/2) (6s1/2) (5d3/2) (5d5/2) - - - - ''' + + # + # [Kr] (5s1/2) (4d3/2) (4d5/2) (4f5/2) (4f7/2) + # (5p1/2) (5p3/2) (6s1/2) (5d3/2) (5d5/2) + # + # + # + from aiida_fleur.tools.xml_util import eval_xpath2, get_xml_attribute #from aiida_fleur.data.fleurinpmodifier import FleurinpModifier # or from fleurinp? @@ -191,3 +184,4 @@ def write_change(xmltree, changelist_xpath): xpath = element[0] value = element[1] return xmltree_new +''' diff --git a/aiida_fleur/tools/dict_util.py b/aiida_fleur/tools/dict_util.py index 6fde96cd5..e8e7dcf37 100644 --- a/aiida_fleur/tools/dict_util.py +++ b/aiida_fleur/tools/dict_util.py @@ -81,6 +81,25 @@ def dict_merger(dict1, dict2): return new_dict +def clean_nones(dict_to_clean): + """Recursively remove all keys which values are None from a nested dictionary + return the cleaned dictionary + + :param dict_to_clean: (dict): python dictionary to remove keys with None as value + :return: dict, cleaned dictionary + """ + new_dict = {} + for key, val in dict_to_clean.items(): + if isinstance(val, dict): + new_val = clean_nones(val) + else: + new_val = val + if new_val is not None: # currently we keep empty dicts + new_dict[key] = new_val + + return new_dict + + def recursive_merge(left: typ.Dict[str, typ.Any], right: typ.Dict[str, typ.Any]) -> typ.Dict[str, typ.Any]: """ Recursively merge two dictionaries into a single dictionary. diff --git a/aiida_fleur/tools/merge_parameter.py b/aiida_fleur/tools/merge_parameter.py index 8e6ce1001..6bebdcdd6 100644 --- a/aiida_fleur/tools/merge_parameter.py +++ b/aiida_fleur/tools/merge_parameter.py @@ -13,8 +13,6 @@ This module, contains a method to merge Dict nodes used by the FLEUR inpgen. This might also be of interest for other all-electron codes """ -# TODO this should be made an inline calculation or calcfunction to -# keep the proverance! # Shall we allow for a python dictionary also instead of forcing paramteraData? # but then we can not keep the provenace... @@ -43,6 +41,8 @@ def merge_parameter(Dict1, Dict2, overwrite=True, merge=True): :param merge: bool, default True returns: AiiDA Dict Node + + #TODO be more carefull how to merge ids in atom namelists, i.e species labels """ from aiida.common.exceptions import InputValidationError @@ -65,6 +65,9 @@ def merge_parameter(Dict1, Dict2, overwrite=True, merge=True): dict1 = Dict1.get_dict() dict2 = Dict2.get_dict() + if dict1 == dict2: + return Dict(dict=dict1) + for key in list(dict1.keys()): if 'atom' in key: val = dict1.pop(key) @@ -148,6 +151,8 @@ def merge_parameters_wf(*Dicts, overwrite=Bool(True)): return paremeter_data_new ''' +''' +#TODO this has to moved into cmdline if __name__ == '__main__': import argparse #Dict = DataFactory('dict') @@ -162,3 +167,4 @@ def merge_parameters_wf(*Dicts, overwrite=Bool(True)): required=False) args = parser.parse_args() merge_parameter(Dict1=args.para1, Dict2=args.para1, overwrite=args.overwrite) + ''' diff --git a/aiida_fleur/tools/read_cif_folder.py b/aiida_fleur/tools/read_cif_folder.py index 6401eb8f8..d8104460e 100644 --- a/aiida_fleur/tools/read_cif_folder.py +++ b/aiida_fleur/tools/read_cif_folder.py @@ -49,6 +49,8 @@ def read_cif_folder(path=os.getcwd(), :params: extras: dir/string/arb: extras added to the structures stored in the db """ + # TODO check for duplicates in the database, so that reruning the functions + # won't import anything else in the database cifdata = DataFactory('cif') ############ parameters for the user to set ######## @@ -104,7 +106,7 @@ def read_cif_folder(path=os.getcwd(), # continue #asecell = new_cif[0].get_ase() #structuredatas.append(DataFactory('structure')) - #filenames2.append(filenames[i]) + filenames2.append(filenames[i]) #struc = structuredatas[-1](ase=asecell) #formula = struc.get_formula() if store_db: @@ -119,7 +121,7 @@ def read_cif_folder(path=os.getcwd(), user = struc.user # we are the creator struc.add_comment(comment, user) if extra: - if isinstance(extra, type(dict())): + if isinstance(extra, dict): struc.set_extra_many(extra) else: struc.set_extra('specification', extra) @@ -127,7 +129,7 @@ def read_cif_folder(path=os.getcwd(), structuredatas2.append(struc) else: struc = struc_from_cif(new_cif[0]) - structuredatas.append(struc) + structuredatas2.append(struc) formula = struc.get_formula() if write_log: # This file is a logfile/info file created by 'read_cif_folder' @@ -154,9 +156,7 @@ def read_cif_folder(path=os.getcwd(), @cf def wf_struc_from_cif(cif): - asecell = cif.get_ase() - struc = DataFactory('structure')(ase=asecell) - return struc + return struc_from_cif(cif) def struc_from_cif(cif): @@ -165,6 +165,9 @@ def struc_from_cif(cif): return struc +# TODO add this to command line, or better move to aiida-jutools +# ggf add what Roman has done there. +''' if __name__ == '__main__': import argparse import json @@ -212,3 +215,4 @@ def struc_from_cif(cif): read_cif_folder(path=args.p, recursive=args.r, store=args.s, log=args.l, comments=args.c, extras=args.e) else: read_cif_folder(recursive=args.r, store=args.s, log=args.l, comments=args.c, extras=args.e) +''' diff --git a/aiida_fleur/tools/xml_util.py b/aiida_fleur/tools/xml_util.py index 994302770..1c54d8ed5 100644 --- a/aiida_fleur/tools/xml_util.py +++ b/aiida_fleur/tools/xml_util.py @@ -110,13 +110,15 @@ def convert_htr_to_ev(value, parser_info_out=None): """ Multiplies the value given with the Hartree factor (converts htr to eV) """ + from aiida_fleur.common.constants import HTR_TO_EV + # htr = 27.21138602 if parser_info_out is None: parser_info_out = {'parser_warnings': []} - htr = 27.21138602 + suc = False value_to_save, suc = convert_to_float(value, parser_info_out=parser_info_out) if suc: - return value_to_save * htr + return value_to_save * HTR_TO_EV else: return value @@ -125,13 +127,14 @@ def convert_ev_to_htr(value, parser_info_out=None): """ Divides the value given with the Hartree factor (converts htr to eV) """ + from aiida_fleur.common.constants import HTR_TO_EV + # htr = 27.21138602 if parser_info_out is None: parser_info_out = {'parser_warnings': []} - htr = 27.21138602 suc = False value_to_save, suc = convert_to_float(value, parser_info_out=parser_info_out) if suc: - return value_to_save / htr + return value_to_save / HTR_TO_EV else: return value @@ -413,7 +416,8 @@ def create_tag(xmlnode, xpath, newelement, create=False, place_index=None, tag_o try: newelement = etree.Element(newelement) except ValueError as v: - raise ValueError('{}. If this is a species, are you sure this species exists ' 'in your inp.xml?'.format(v)) + raise ValueError('{}. If this is a species, are you sure this species exists ' + 'in your inp.xml?'.format(v)) from v nodes = eval_xpath3(xmlnode, xpath, create=create) if nodes: for node_1 in nodes: @@ -423,8 +427,8 @@ def create_tag(xmlnode, xpath, newelement, create=False, place_index=None, tag_o # behind what shall I place it try: place_index = tag_order.index(newelement_name) - except: - raise ValueError('Did not find element name in the tag_order list') + except ValueError as exc: + raise ValueError('Did not find element name in the tag_order list') from exc behind_tags = tag_order[:place_index] # check if children are in the same sequence as given in tag_order tags = [] @@ -435,8 +439,9 @@ def create_tag(xmlnode, xpath, newelement, create=False, place_index=None, tag_o for name in tags: try: current = tag_order.index(name) - except ValueError: - raise ValueError('Did not find existing tag name in the tag_order list' ': {}'.format(name)) + except ValueError as exc: + raise ValueError('Did not find existing tag name in the tag_order list' + ': {}'.format(name)) from exc if current > prev: prev = current else: @@ -449,10 +454,10 @@ def create_tag(xmlnode, xpath, newelement, create=False, place_index=None, tag_o tag_index = node_1.index(child) try: node_1.insert(tag_index + 1, element_to_write) - except ValueError as v: + except ValueError as exc: raise ValueError('{}. If this is a species, are' 'you sure this species exists in your inp.xml?' - ''.format(v)) + ''.format(exc)) from exc was_set = True break if was_set: @@ -460,23 +465,23 @@ def create_tag(xmlnode, xpath, newelement, create=False, place_index=None, tag_o if not was_set: # just append try: node_1.insert(0, element_to_write) - except ValueError as v: + except ValueError as exc: raise ValueError('{}. If this is a species, are you' ' sure this species exists in your inp.xml?' - ''.format(v)) + ''.format(exc)) from exc # (or remove all and write them again in right order?) else: try: node_1.insert(place_index, element_to_write) - except ValueError as v: + except ValueError as exc: raise ValueError('{}. If this is a species, are you sure this species ' - 'exists in your inp.xml?'.format(v)) + 'exists in your inp.xml?'.format(exc)) from exc else: try: node_1.append(element_to_write) - except ValueError as v: + except ValueError as exc: raise ValueError('{}. If this is a species, are you sure this species exists' - 'in your inp.xml?'.format(v)) + 'in your inp.xml?'.format(exc)) from exc return xmlnode @@ -551,12 +556,14 @@ def get_inpgen_paranode_from_xml(inpxmlfile): return Dict(dict=para_dict) -def get_inpgen_para_from_xml(inpxmlfile): +def get_inpgen_para_from_xml(inpxmlfile, inpgen_ready=True): """ This routine returns an python dictionary produced from the inp.xml file, which can be used as a calc_parameters node by inpgen. Be aware that inpgen does not take all information that is contained in an inp.xml file + :param inpxmlfile: and xml etree of a inp.xml file + :param inpgen_ready: Bool, return a dict which can be inputed into inpgen while setting atoms :return new_parameters: A Dict, which will lead to the same inp.xml (in case if other defaults, which can not be controlled by input for inpgen, were changed) @@ -583,7 +590,7 @@ def get_inpgen_para_from_xml(inpxmlfile): atom_jri_xpath = 'mtSphere/@gridPoints' atom_lmax_xpath = 'atomicCutoffs/@lmax' atom_lnosph_xpath = 'atomicCutoffs/@lnonsphr' - atom_ncst_xpath = '@coreStates' + #atom_ncst_xpath = '@coreStates' atom_econfig_xpath = 'electronConfig' # converting todo atom_bmu_xpath = '@magMom' atom_lo_xpath = 'lo' # converting todo @@ -651,26 +658,28 @@ def get_inpgen_para_from_xml(inpxmlfile): atom_jri = convert_to_int(eval_xpath(species, atom_jri_xpath), suc_return=False) atom_lmax = convert_to_int(eval_xpath(species, atom_lmax_xpath), suc_return=False) atom_lnosph = convert_to_int(eval_xpath(species, atom_lnosph_xpath), suc_return=False) - atom_ncst = convert_to_int(eval_xpath(species, atom_ncst_xpath), suc_return=False) + #atom_ncst = convert_to_int(eval_xpath(species, atom_ncst_xpath), suc_return=False) atom_econfig = eval_xpath(species, atom_econfig_xpath) atom_bmu = convert_to_float(eval_xpath(species, atom_bmu_xpath), suc_return=False) atom_lo = eval_xpath(species, atom_lo_xpath) atom_element = eval_xpath(species, atom_element_xpath) atom_name_2 = eval_xpath(species, atom_name_xpath) - atom_dict = set_dict_or_not(atom_dict, 'z', atom_z) + if not inpgen_ready: + atom_dict = set_dict_or_not(atom_dict, 'z', atom_z) + #atom_dict = set_dict_or_not(atom_dict, 'name', atom_name_2) + #atom_dict = set_dict_or_not(atom_dict, 'ncst', atom_ncst) (deprecated) atom_dict = set_dict_or_not(atom_dict, 'rmt', atom_rmt) atom_dict = set_dict_or_not(atom_dict, 'dx', atom_dx) atom_dict = set_dict_or_not(atom_dict, 'jri', atom_jri) atom_dict = set_dict_or_not(atom_dict, 'lmax', atom_lmax) atom_dict = set_dict_or_not(atom_dict, 'lnonsph', atom_lnosph) - atom_dict = set_dict_or_not(atom_dict, 'ncst', atom_ncst) + atom_dict = set_dict_or_not(atom_dict, 'econfig', atom_econfig) atom_dict = set_dict_or_not(atom_dict, 'bmu', atom_bmu) if atom_lo is not None: atom_dict = set_dict_or_not(atom_dict, 'lo', convert_fleur_lo(atom_lo)) atom_dict = set_dict_or_not(atom_dict, 'element', '{}'.format(atom_element)) - #atom_dict = set_dict_or_not(atom_dict, 'name', atom_name_2) new_parameters[atoms_name] = atom_dict @@ -1471,11 +1480,11 @@ def eval_xpath3(node, xpath, create=False, place_index=None, tag_order=None): """ try: return_value = node.xpath(xpath) - except etree.XPathEvalError: + except etree.XPathEvalError as exc: message = ('There was a XpathEvalError on the xpath: {} \n Either it does ' 'not exist, or something is wrong with the expression.' ''.format(xpath)) - raise etree.XPathEvalError(message) + raise etree.XPathEvalError(message) from exc if return_value == []: if create: diff --git a/aiida_fleur/workflows/b_corehole.py.legacy b/aiida_fleur/workflows/b_corehole.py.legacy deleted file mode 100644 index 2171cc0b0..000000000 --- a/aiida_fleur/workflows/b_corehole.py.legacy +++ /dev/null @@ -1,276 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -This is the worklfow 'corehole' using the Fleur code, which calculates Binding -energies and corelevel shifts with different methods. -'divide and conquer' -""" -# TODO alow certain kpoint path, or kpoint node, so far auto -from __future__ import absolute_import -from __future__ import print_function -from aiida_fleur.data.fleurinp import FleurinpData -from aiida import load_dbenv, is_dbenv_loaded -import six -if not is_dbenv_loaded(): - load_dbenv() - -import os.path -from aiida.plugins import Code, DataFactory -from aiida.engine import WorkChain -from aiida.engine import submit -from aiida.engine import ToContext -from aiida.engine.process_registry import ProcessRegistry - -from aiida_fleur.calculation.fleur import FleurCalculation -from aiida_fleur.data.fleurinpmodifier import FleurinpModifier -from aiida.engine import while_, if_ -from aiida_fleur.tools.create_corehole import create_corehole - -StructureData = DataFactory('structure') -Dict = DataFactory('dict') -RemoteData = DataFactory('remote') -FleurProcess = FleurCalculation.process() - - -class fleur_corehole_wc(WorkChain): - ''' - Turn key solution for the calculation of core level shift and Binding energies - - - ''' - # wf_Parameters: Dict, - ''' - 'method' : ['initial', 'full_valence ch', 'half_valence_ch', 'ch', ...] - 'Bes' : [W4f, Be1s] - 'CLS' : [W4f, Be1s] - 'atoms' : ['all', 'postions' : []] - 'references' : ['calculate', or - 'scf_para' : {...}, 'default' - 'relax' : True - 'relax_mode': ['Fleur', 'QE Fleur', 'QE'] - 'relax_para' : {...}, 'default' - 'calculate_doses' : False - 'dos_para' : {...}, 'default' - ''' - ''' - # defaults - default wf_Parameters:: - 'method' : 'initial' - 'atoms' : 'all - 'references' : 'calculate' - 'scf_para' : 'default' - 'relax' : True - 'relax_mode': 'QE Fleur' - 'relax_para' : 'default' - 'calculate_doses' : False - 'dos_para' : 'default' - ''' - - _workflowversion = "0.0.1" - - @classmethod - def define(cls, spec): - super(fleur_corehole_wc, cls).define(spec) - spec.input("wf_parameters", valid_type=Dict, required=False, - default=Dict(dict={ - 'method' : 'initial', - 'atoms' : 'all', - 'references' : 'calculate', - 'relax' : False, - 'relax_mode': 'Fleur', - 'relax_para' : 'default', - 'scf_para' : 'default', - })) - spec.input("fleurinp", valid_type=FleurinpData, required=True) - spec.input("fleur", valid_type=Code, required=True) - spec.input("structure", valid_type=StructureData, required=False) - spec.input("calc_parameters", valid_type=Dict, required=False) - spec.outline( - cls.check_input, - if_(cls.relaxation_needed)( - cls.relax), - if_(cls.supercell_needed)( - cls.create_supercell - ), - cls.create_new_fleurinp, - cls.create_coreholes, - cls.run_scfs, - cls.collect_results, - cls.return_results - ) - #spec.dynamic_output() - - - def check_input(self): - ''' - check parameters, what condictions? complete? - check input nodes - ''' - ### input check ### ? or done automaticly, how optional? - # check if fleuinp corresponds to fleur_calc - print(('started bands workflow version {}'.format(self._workflowversion))) - print(("Workchain node identifiers: {}" - "".format(ProcessRegistry().current_calc_node))) - - def relaxation_needed(self): - """ - If the structures should be relaxed, check if their Forces are below a certain - threshold, otherwise throw them in the relaxation wf. - """ - print('In relaxation inital_state_CLS workflow') - if self.ctx.relax: - # TODO check all forces of calculations - forces_fine = True - if forces_fine: - return True - else: - return False - else: - return False - - - def relax(self): - """ - Do structural relaxation for certain structures. - """ - print('In relax inital_state_CLS workflow') - for calc in self.ctx.dos_to_calc: - pass - # TODO run relax workflow - - def create_new_fleurinp(self): - """ - create a new fleurinp from the old with certain parameters - """ - # TODO allow change of kpoint mesh?, tria? - wf_dict = self.inputs.wf_parameters.get_dict() - nkpts = wf_dict.get('nkpts', 500) - # how can the user say he want to use the given kpoint mesh, ZZ nkpts : False/0 - sigma = wf_dict.get('sigma', 0.005) - emin = wf_dict.get('emin', -0.30) - emax = wf_dict.get('emax', 0.80) - - fleurmode = FleurinpModifier(self.inputs.fleurinp) - - #change_dict = {'band': True, 'ndir' : -1, 'minEnergy' : self.inputs.wf_parameters.get_dict().get('minEnergy', -0.30000000), - #'maxEnergy' : self.inputs.wf_parameters.get_dict().get('manEnergy','0.80000000'), - #'sigma' : self.inputs.wf_parameters.get_dict().get('sigma', '0.00500000')} - change_dict = {'band': True, 'ndir' : 0, 'minEnergy' : emin, - 'maxEnergy' : emax, 'sigma' : sigma} #'ndir' : 1, 'pot8' : True - - fleurmode.set_inpchanges(change_dict) - - if nkpts: - fleurmode.set_nkpts(count=nkpts) - #fleurinp_new.replace_tag() - - fleurmode.show(validate=True, display=False) # needed? - fleurinp_new = fleurmode.freeze() - self.ctx.fleurinp1 = fleurinp_new - print(fleurinp_new) - #print(fleurinp_new.folder.get_subfolder('path').get_abs_path('')) - - def get_inputs_fleur(self): - ''' - get the input for a FLEUR calc - ''' - inputs = FleurProcess.get_inputs_template() - - fleurin = self.ctx.fleurinp1 - #print fleurin - remote = self.inputs.remote - inputs.parent_folder = remote - inputs.code = self.inputs.fleur - inputs.fleurinpdata = fleurin - - # TODO nkpoints decide n core - - core = 12 # get from computer nodes per machine - inputs._options.resources = {"num_machines": 1, "num_mpiprocs_per_machine" : core} - inputs._options.max_wallclock_seconds = 30 * 60 - - if self.ctx.serial: - inputs._options.withmpi = False # for now - inputs._options.resources = {"num_machines": 1} - - if self.ctx.queue: - inputs._options.queue_name = self.ctx.queue - print(self.ctx.queue) - # if code local use - #if self.inputs.fleur.is_local(): - # inputs._options.computer = computer - # #else use computer from code. - #else: - # inputs._options.queue_name = 'th1' - - if self.ctx.serial: - inputs._options.withmpi = False # for now - inputs._options.resources = {"num_machines": 1} - - return inputs - - def run_fleur(self): - ''' - run a fleur calculation - ''' - FleurProcess = FleurCalculation.process() - inputs = {} - inputs = self.get_inputs_fleur() - #print inputs - future = submit(FleurProcess, **inputs) - print('run Fleur in band workflow') - - return ToContext(last_calc=future) - - def return_results(self): - ''' - return the results of the calculations - ''' - # TODO more here - print('Band workflow Done') - print(('A bandstructure was calculated for fleurinpdata {} and is found under pk={}, ' - 'calculation {}'.format(self.inputs.fleurinp, self.ctx.last_calc.pk, self.ctx.last_calc))) - - #check if band file exists: if not succesful = False - #TODO be careful with general bands.X - - bandfilename = 'bands.1' # ['bands.1', 'bands.2', ...] - # TODO this should be easier... - last_calc_retrieved = self.ctx.last_calc.get_outputs_dict()['retrieved'].folder.get_subfolder('path') - bandfilepath = self.ctx.last_calc.get_outputs_dict()['retrieved'].folder.get_subfolder('path').get_abs_path(bandfilename) - print(bandfilepath) - #bandfilepath = "path to bandfile" # Array? - if os.path.isfile(bandfilepath): - self.ctx.successful = True - else: - bandfilepath = None - print('!NO bandstructure file was found, something went wrong!') - #TODO corret efermi: - # get efermi from last calculation - efermi1 = self.inputs.remote.get_inputs()[-1].res.fermi_energy - #get efermi from this caclulation - efermi2 = self.ctx.last_calc.res.fermi_energy - diff_efermi = efermi1 - efermi2 - # store difference in output node - # adjust difference in band.gnu - #filename = 'gnutest2' - - outputnode_dict ={} - - outputnode_dict['workflow_name'] = self.__class__.__name__ - outputnode_dict['Warnings'] = self.ctx.warnings - outputnode_dict['successful'] = self.ctx.successful - outputnode_dict['diff_efermi'] = diff_efermi - #outputnode_dict['last_calc_pk'] = self.ctx.last_calc.pk - #outputnode_dict['last_calc_uuid'] = self.ctx.last_calc.uuid - outputnode_dict['bandfile'] = bandfilepath - outputnode_dict['last_calc_uuid'] = self.ctx.last_calc.uuid - outputnode_dict['last_calc_retrieved'] = last_calc_retrieved - #print outputnode_dict - outputnode = Dict(dict=outputnode_dict) - outdict = {} - outdict['output_corehole_wc_para'] = outputnode - #print outdict - for k, v in six.iteritems(outdict): - self.out(k, v) diff --git a/aiida_fleur/workflows/band.py b/aiida_fleur/workflows/band.py deleted file mode 100644 index 98733db44..000000000 --- a/aiida_fleur/workflows/band.py +++ /dev/null @@ -1,346 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################### -# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # -# All rights reserved. # -# This file is part of the AiiDA-FLEUR package. # -# # -# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # -# For further information on the license, see the LICENSE.txt file # -# For further information please visit http://www.flapw.de or # -# http://aiida-fleur.readthedocs.io/en/develop/ # -############################################################################### -""" -This is the worklfow 'band' for the Fleur code, which calculates a -electron bandstructure. -""" -# TODO alow certain kpoint path, or kpoint node, so far auto -# TODO alternative parse a structure and run scf -from __future__ import absolute_import -from __future__ import print_function -import os.path -import copy -import six - -from aiida.plugins import DataFactory -from aiida.orm import Code, StructureData, Dict, RemoteData -from aiida.engine import WorkChain, ToContext, if_ -from aiida.engine import calcfunction as cf -from aiida.common.exceptions import NotExistent -from aiida.common import AttributeDict - -from aiida_fleur.workflows.scf import FleurScfWorkChain -from aiida_fleur.workflows.base_fleur import FleurBaseWorkChain -from aiida_fleur.data.fleurinpmodifier import FleurinpModifier -from aiida_fleur.tools.common_fleur_wf import get_inputs_fleur -from aiida_fleur.tools.common_fleur_wf import test_and_get_codenode, is_code -from aiida_fleur.data.fleurinp import FleurinpData - - -class FleurBandWorkChain(WorkChain): - ''' - This workflow calculated a bandstructure from a Fleur calculation - - :Params: a Fleurcalculation node - :returns: Success, last result node, list with convergence behavior - ''' - # wf_parameters: { 'tria', 'nkpts', 'sigma', 'emin', 'emax'} - # defaults : tria = True, nkpts = 800, sigma=0.005, emin= , emax = - - _workflowversion = '0.3.4' - - _default_options = { - 'resources': { - 'num_machines': 1, - 'num_mpiprocs_per_machine': 1 - }, - 'max_wallclock_seconds': 60 * 60, - 'queue_name': '', - 'custom_scheduler_commands': '', - 'import_sys_environment': False, - 'environment_variables': {} - } - _wf_default = { - 'fleur_runmax': 4, - 'kpath': 'auto', - # 'nkpts' : 800, - 'sigma': 0.005, - 'emin': -0.50, - 'emax': 0.90 - } - - @classmethod - def define(cls, spec): - super(FleurBandWorkChain, cls).define(spec) - # spec.expose_inputs(FleurScfWorkChain, namespace='scf') - spec.input('wf_parameters', valid_type=Dict, required=False) - spec.input('fleur', valid_type=Code, required=True) - spec.input('remote', valid_type=RemoteData, required=False) - spec.input('fleurinp', valid_type=FleurinpData, required=False) - spec.input('options', valid_type=Dict, required=False) - - spec.outline( - cls.start, - if_(cls.scf_needed)( - cls.converge_scf, - cls.create_new_fleurinp, - cls.run_fleur, - ).else_( - cls.create_new_fleurinp, - cls.run_fleur, - ), cls.return_results) - - spec.output('output_band_wc_para', valid_type=Dict) - - spec.exit_code(233, - 'ERROR_INVALID_CODE_PROVIDED', - message='Invalid code node specified, check inpgen and fleur code nodes.') - spec.exit_code(231, 'ERROR_INVALID_INPUT_CONFIG', message='Invalid input configuration.') - - def start(self): - ''' - check parameters, what condictions? complete? - check input nodes - ''' - ### input check ### ? or done automaticly, how optional? - # check if fleuinp corresponds to fleur_calc - self.report('started bands workflow version {}'.format(self._workflowversion)) - #print("Workchain node identifiers: ")#'{}' - #"".format(ProcessRegistry().current_calc_node)) - - self.ctx.fleurinp_band = '' - self.ctx.last_calc = None - self.ctx.successful = False - self.ctx.info = [] - self.ctx.warnings = [] - self.ctx.errors = [] - self.ctx.calcs = [] - - inputs = self.inputs - - wf_default = copy.deepcopy(self._wf_default) - if 'wf_parameters' in inputs: - wf_dict = inputs.wf_parameters.get_dict() - else: - wf_dict = wf_default - - for key, val in six.iteritems(wf_default): - wf_dict[key] = wf_dict.get(key, val) - self.ctx.wf_dict = wf_dict - # if MPI in code name, execute parallel - self.ctx.serial = self.ctx.wf_dict.get('serial', False) - - defaultoptions = self._default_options - if 'options' in inputs: - options = inputs.options.get_dict() - else: - options = defaultoptions - - # extend options given by user using defaults - for key, val in six.iteritems(defaultoptions): - options[key] = options.get(key, val) - self.ctx.options = options - - # set values, or defaults - self.ctx.max_number_runs = self.ctx.wf_dict.get('fleur_runmax', 4) - - # Check if user gave valid fleur executable - # if 'fleur' in inputs.scf: - # try: - # test_and_get_codenode(inputs.scf.fleur, 'fleur.fleur', use_exceptions=True) - # except ValueError: - # error = ("The code you provided for FLEUR does not use the plugin fleur.fleur") - # self.control_end_wc(error) - # return self.exit_codes.ERROR_INVALID_CODE_PROVIDED - - if 'scf' in inputs: - self.ctx.scf_needed = True - if 'remote' in inputs: - error = 'ERROR: you gave SCF input + remote for the FT' - self.control_end_wc(error) - return self.exit_codes.ERROR_INVALID_INPUT_CONFIG - elif 'remote' not in inputs: - error = 'ERROR: you gave neither SCF input nor remote for the FT' - self.control_end_wc(error) - return self.exit_codes.ERROR_INVALID_INPUT_CONFIG - else: - self.ctx.scf_needed = False - - def create_new_fleurinp(self): - """ - create a new fleurinp from the old with certain parameters - """ - # TODO allow change of kpoint mesh?, tria? - wf_dict = self.ctx.wf_dict - # nkpts = wf_dict.get('nkpts', 500) - # how can the user say he want to use the given kpoint mesh, ZZ nkpts : False/0 - sigma = wf_dict.get('sigma', 0.005) - emin = wf_dict.get('emin', -0.30) - emax = wf_dict.get('emax', 0.80) - - fleurmode = FleurinpModifier(self.inputs.fleurinp) - - change_dict = {'band': True, 'ndir': 0, 'minEnergy': emin, 'maxEnergy': emax, 'sigma': sigma} #'ndir' : 1, - - fleurmode.set_inpchanges(change_dict) - - # if nkpts: - # fleurmode.set_nkpts(count=nkpts) - #fleurinp_new.replace_tag() - - fleurmode.show(validate=True, display=False) # needed? - fleurinp_new = fleurmode.freeze() - self.ctx.fleurinp_band = fleurinp_new - - def scf_needed(self): - """ - Returns True if SCF WC is needed. - """ - return self.ctx.scf_needed - - def converge_scf(self): - """ - Converge charge density. - """ - return 0 - - def run_fleur(self): - """ - run a FLEUR calculation - """ - self.report('INFO: run FLEUR') - # inputs = self.get_inputs_scf() - fleurin = self.ctx.fleurinp_band - remote = self.inputs.remote - code = self.inputs.fleur - options = self.ctx.options.copy() - label = 'bansdtructure_calculation' - description = 'Bandstructure is calculated for the given structure' - - inputs = get_inputs_fleur(code, remote, fleurin, options, label, description, serial=self.ctx.serial) - future = self.submit(FleurBaseWorkChain, **inputs) - self.ctx.calcs.append(future) - - return ToContext(last_calc=future) - - def get_inputs_scf(self): - """ - Initialize inputs for scf workflow: - wf_param, options, calculation parameters, codes, structure - """ - input_scf = AttributeDict(self.exposed_inputs(FleurScfWorkChain, namespace='scf')) - input_scf.fleurinp = self.ctx.fleurinp_band - - return input_scf - - def return_results(self): - ''' - return the results of the calculations - ''' - # TODO more here - self.report('Band workflow Done') - self.report('A bandstructure was calculated for fleurinpdata {} and is found under pk={}, ' - 'calculation {}'.format(self.inputs.fleurinp, self.ctx.last_calc.pk, self.ctx.last_calc)) - - from aiida_fleur.tools.common_fleur_wf import find_last_submitted_calcjob - if self.ctx.last_calc: - try: - last_calc_uuid = find_last_submitted_calcjob(self.ctx.last_calc) - except NotExistent: - last_calc_uuid = None - else: - last_calc_uuid = None - - try: # if something failed, we still might be able to retrieve something - last_calc_out = self.ctx.last_calc.outputs.output_parameters - retrieved = self.ctx.last_calc.outputs.retrieved - last_calc_out_dict = last_calc_out.get_dict() - except (NotExistent, AttributeError): - last_calc_out = None - last_calc_out_dict = {} - retrieved = None - - #check if band file exists: if not succesful = False - #TODO be careful with general bands.X - # bandfilename = 'bands.1' # ['bands.1', 'bands.2', ...] - - # last_calc_retrieved = self.ctx.last_calc.get_outputs_dict()['retrieved'].folder.get_subfolder('path').get_abs_path('') - # bandfilepath = self.ctx.last_calc.get_outputs_dict()['retrieved'].folder.get_subfolder('path').get_abs_path(bandfilename) - # print(bandfilepath) - # #bandfilepath = "path to bandfile" # Array? - # if os.path.isfile(bandfilepath): - # self.ctx.successful = True - # else: - # bandfilepath = None - # self.report('!NO bandstructure file was found, something went wrong!') - - # #TODO corret efermi: - # # get efermi from last calculation - scf_results = self.inputs.remote_data.get_incoming().all()[-1].node.res - efermi_scf = scf_results.fermi_energy - bandgap_scf = scf_results.bandgap - # efermi_band = last_calc_out_dict['fermi_energy'] - # bandgap_band = last_calc_out_dict['bandgap'] - - # diff_efermi = efermi_scf - efermi_band - # diff_bandgap = bandgap_scf - bandgap_band - - outputnode_dict = {} - - outputnode_dict['workflow_name'] = self.__class__.__name__ - outputnode_dict['Warnings'] = self.ctx.warnings - outputnode_dict['successful'] = self.ctx.successful - # outputnode_dict['last_calc_uuid'] = last_calc_uuid - # outputnode_dict['last_calc_pk'] = self.ctx.last_calc.pk - # outputnode_dict['remote_dir'] = self.ctx.last_calc.get_remote_workdir() - # outputnode_dict['fermi_energy_band'] = efermi_band - # outputnode_dict['bandgap_band'] = bandgap_band - outputnode_dict['fermi_energy_scf'] = efermi_scf - outputnode_dict['bandgap_scf'] = bandgap_scf - # outputnode_dict['diff_efermi'] = diff_efermi - # outputnode_dict['diff_bandgap'] = diff_bandgap - - # outputnode_dict['diff_efermi'] = diff_efermi - # outputnode_dict['bandfile'] = bandfilepath - - outputnode_t = Dict(dict=outputnode_dict) - if last_calc_out: - outdict = create_band_result_node(outpara=outputnode_t, - last_calc_out=last_calc_out, - last_calc_retrieved=retrieved) - else: - outdict = create_band_result_node(outpara=outputnode_t) - - #TODO parse Bandstructure - for link_name, node in six.iteritems(outdict): - self.out(link_name, node) - - def control_end_wc(self, errormsg): - """ - Controlled way to shutdown the workchain. will initialize the output nodes - The shutdown of the workchain will has to be done afterwards - """ - self.report(errormsg) # because return_results still fails somewhen - self.ctx.errors.append(errormsg) - self.return_results() - - -@cf -def create_band_result_node(**kwargs): - """ - This is a pseudo wf, to create the right graph structure of AiiDA. - This wokfunction will create the output node in the database. - It also connects the output_node to all nodes the information commes from. - So far it is just also parsed in as argument, because so far we are to lazy - to put most of the code overworked from return_results in here. - """ - for key, val in six.iteritems(kwargs): - if key == 'outpara': # should be always there - outpara = val - outdict = {} - outputnode = outpara.clone() - outputnode.label = 'output_band_wc_para' - outputnode.description = ('Contains band calculation results') - - outdict['output_band_wc_para'] = outputnode - - return outdict diff --git a/aiida_fleur/workflows/band2.py.legacy b/aiida_fleur/workflows/band2.py.legacy deleted file mode 100644 index b50d92b51..000000000 --- a/aiida_fleur/workflows/band2.py.legacy +++ /dev/null @@ -1,270 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################### -# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # -# All rights reserved. # -# This file is part of the AiiDA-FLEUR package. # -# # -# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # -# For further information on the license, see the LICENSE.txt file # -# For further information please visit http://www.flapw.de or # -# http://aiida-fleur.readthedocs.io/en/develop/ # -############################################################################### - - -""" -This is the worklfow 'band2' for the Fleur code, which calculates a -electron bandstructure from a given structure data node with seekpath. - -""" -# TODO alow certain kpoint path, or kpoint node, so far auto -# TODO alternative parse a structure and run scf -from __future__ import absolute_import -from __future__ import print_function -import os.path -from aiida.plugins import Code, DataFactory -#from aiida.tools.codespecific.fleur.queue_defaults import queue_defaults -from aiida.engine import WorkChain -from aiida.engine import submit -from aiida.engine import if_ -from aiida.engine import ToContext -from aiida.engine import workfunction as wf -#from aiida.work.process_registry import ProcessRegistry -from aiida_fleur.calculation.fleur import FleurCalculation -from aiida_fleur.data.fleurinpmodifier import FleurinpModifier -from aiida_fleur.tools.common_fleur_wf import get_inputs_fleur -from seekpath.aiidawrappers import get_path, get_explicit_k_path -import six - -StructureData = DataFactory('structure') -Dict = DataFactory('dict') -RemoteData = DataFactory('remote') -KpointsData = DataFactory('array.kpoints') -FleurinpData = DataFactory('fleur.fleurinp') -FleurProcess = FleurCalculation.process() - -''' -We want to run fleur with a certain kpath, which we will get from the seek path method -''' - - -class fleur_band2_wc(WorkChain): - ''' - This workflow calculated a bandstructure from a Fleur calculation - - :Params: a Fleurcalculation node - :returns: - ''' - - _workflowversion = "0.1.0" - - @classmethod - def define(cls, spec): - super(fleur_band2_wc, cls).define(spec) - spec.input("wf_parameters", valid_type=Dict, required=False, - default=Dict(dict={ - 'kpath' : 'auto', - 'nkpts' : 800, - 'sigma' : 0.005, - 'emin' : -0.50, - 'emax' : 0.90})) - - spec.input("fleur", valid_type=Code, required=True) - spec.input("structure", valid_type=StructureData, required=False) - spec.input("calc_parameters", valid_type=Dict, required=False) - spec.input("settings", valid_type=Dict, required=False) - spec.input("inpgen", valid_type=Code, required=False) - spec.outline( - cls.start, - cls.setup_structure, - cls.setup_kpoints, - cls.setup_parameters, - cls.create_new_fleurinp, - cls.run_fleur, - cls.return_results - ) - #spec.dynamic_output() - - - def start(self): - ''' - check parameters, what condictions? complete? - check input nodes - ''' - ### input check ### ? or done automaticly, how optional? - # check if fleuinp corresponds to fleur_calc - print(('started bands workflow version {}'.format(self._workflowversion))) - print("Workchain node identifiers: ")#{}" - #"".format(ProcessRegistry().current_calc_node)) - - self.ctx.fleurinp1 = "" - self.ctx.last_calc = None - self.ctx.successful = False - self.ctx.warnings = [] - - wf_dict = self.inputs.wf_parameters.get_dict() - - # if MPI in code name, execute parallel - self.ctx.serial = wf_dict.get('serial', False) - - # set values, or defaults - self.ctx.max_number_runs = wf_dict.get('fleur_runmax', 4) - self.ctx.resources = wf_dict.get('resources', {"num_machines": 1}) - self.ctx.walltime_sec = wf_dict.get('walltime_sec', 10*30) - self.ctx.queue = wf_dict.get('queue_name', None) - - - - def setup_structure(self): - """ - We use SeeKPath to determine the primitive structure for the given input structure, if it - wasn't yet the case. - """ - seekpath_result = seekpath_structure(self.inputs.structure) - self.ctx.structure_initial_primitive = seekpath_result['primitive_structure'] - - def setup_kpoints(self): - """ - Define the k-point mesh for the relax and scf calculations. Also get the k-point path for - the bands calculation for the initial input structure from SeeKpath - """ - kpoints_mesh = KpointsData() - kpoints_mesh.set_cell_from_structure(self.inputs.structure) - kpoints_mesh.set_kpoints_mesh_from_density( - distance=self.ctx.protocol['kpoints_mesh_density'], - offset=self.ctx.protocol['kpoints_mesh_offset'] - ) - - self.ctx.kpoints_mesh = kpoints_mesh - - - def create_new_fleurinp(self): - """ - create a new fleurinp from the old with certain parameters - """ - # TODO allow change of kpoint mesh?, tria? - wf_dict = self.inputs.wf_parameters.get_dict() - nkpts = wf_dict.get('nkpts', 500) - # how can the user say he want to use the given kpoint mesh, ZZ nkpts : False/0 - sigma = wf_dict.get('sigma', 0.005) - emin = wf_dict.get('emin', -0.30) - emax = wf_dict.get('emax', 0.80) - - fleurmode = FleurinpModifier(self.inputs.fleurinp) - - #change_dict = {'band': True, 'ndir' : -1, 'minEnergy' : self.inputs.wf_parameters.get_dict().get('minEnergy', -0.30000000), - #'maxEnergy' : self.inputs.wf_parameters.get_dict().get('manEnergy','0.80000000'), - #'sigma' : self.inputs.wf_parameters.get_dict().get('sigma', '0.00500000')} - change_dict = {'band': True, 'ndir' : 0, 'minEnergy' : emin, - 'maxEnergy' : emax, 'sigma' : sigma} #'ndir' : 1, 'pot8' : True - - fleurmode.set_inpchanges(change_dict) - - if nkpts: - fleurmode.set_nkpts(count=nkpts) - #fleurinp_new.replace_tag() - - fleurmode.show(validate=True, display=False) # needed? - fleurinp_new = fleurmode.freeze() - self.ctx.fleurinp1 = fleurinp_new - #print(fleurinp_new) - #print(fleurinp_new.folder.get_subfolder('path').get_abs_path('')) - - def run_fleur(self): - """ - run a FLEUR calculation - """ - fleurin = self.ctx.fleurinp1 - remote = self.inputs.remote - code = self.inputs.fleur - - options = {"max_wallclock_seconds": self.ctx.walltime_sec, - "resources": self.ctx.resources, - "queue_name" : self.ctx.queue} - - inputs = get_inputs_fleur(code, remote, fleurin, options, serial=self.ctx.serial) - future = submit(FleurProcess, **inputs) - - return ToContext(last_calc=future) #calcs.append(future), - - - - def return_results(self): - ''' - return the results of the calculations - ''' - # TODO more here - print('Band workflow Done') - print(('A bandstructure was calculated for fleurinpdata {} and is found under pk={}, ' - 'calculation {}'.format(self.inputs.fleurinp, self.ctx.last_calc.pk, self.ctx.last_calc))) - - #check if band file exists: if not succesful = False - #TODO be careful with general bands.X - - bandfilename = 'bands.1' # ['bands.1', 'bands.2', ...] - # TODO this should be easier... - last_calc_retrieved = self.ctx.last_calc.get_outputs_dict()['retrieved'].folder.get_subfolder('path').get_abs_path('') - bandfilepath = self.ctx.last_calc.get_outputs_dict()['retrieved'].folder.get_subfolder('path').get_abs_path(bandfilename) - print(bandfilepath) - #bandfilepath = "path to bandfile" # Array? - if os.path.isfile(bandfilepath): - self.ctx.successful = True - else: - bandfilepath = None - print('!NO bandstructure file was found, something went wrong!') - #TODO corret efermi: - # get efermi from last calculation - efermi1 = self.inputs.remote.get_inputs()[-1].res.fermi_energy - #get efermi from this caclulation - efermi2 = self.ctx.last_calc.res.fermi_energy - diff_efermi = efermi1 - efermi2 - # store difference in output node - # adjust difference in band.gnu - #filename = 'gnutest2' - - outputnode_dict ={} - - outputnode_dict['workflow_name'] = self.__class__.__name__ - outputnode_dict['Warnings'] = self.ctx.warnings - outputnode_dict['successful'] = self.ctx.successful - outputnode_dict['diff_efermi'] = diff_efermi - #outputnode_dict['last_calc_pk'] = self.ctx.last_calc.pk - #outputnode_dict['last_calc_uuid'] = self.ctx.last_calc.uuid - outputnode_dict['bandfile'] = bandfilepath - outputnode_dict['last_calc_uuid'] = self.ctx.last_calc.uuid - outputnode_dict['last_calc_retrieved'] = last_calc_retrieved - #print outputnode_dict - outputnode = Dict(dict=outputnode_dict) - outdict = {} - #TODO parse Bandstructure - #bandstructurenode = '' - #outdict['output_band'] = bandstructurenode - #or if spin =2 - #outdict['output_band1'] = bandstructurenode1 - #outdict['output_band2'] = bandstructurenode1 - outdict['output_band_wf_para'] = outputnode - #print outdict - for k, v in six.iteritems(outdict): - self.out(k, v) - - - - -#TODO import from somewhere? -@wf -def seekpath_structure(structure): - - seekpath_info = get_path(structure) - explicit_path = get_explicit_k_path(structure) - - primitive_structure = seekpath_info.pop('primitive_structure') - conv_structure = seekpath_info.pop('conv_structure') - parameters = Dict(dict=seekpath_info) - - result = { - 'parameters': parameters, - 'conv_structure': conv_structure, - 'primitive_structure': primitive_structure, - 'explicit_kpoints_path': explicit_path['explicit_kpoints'], - } - - return result diff --git a/aiida_fleur/workflows/banddos.py b/aiida_fleur/workflows/banddos.py index 50189f727..2ed2f6349 100644 --- a/aiida_fleur/workflows/banddos.py +++ b/aiida_fleur/workflows/banddos.py @@ -60,7 +60,7 @@ class FleurBandDosWorkChain(WorkChain): 'import_sys_environment': False, 'environment_variables': {} } - _wf_default = { + _default_wf_para = { 'fleur_runmax': 4, 'kpath': 'auto', # 'nkpts' : 800, @@ -71,7 +71,7 @@ class FleurBandDosWorkChain(WorkChain): @classmethod def define(cls, spec): - super(FleurBandDosWorkChain, cls).define(spec) + super().define(spec) # spec.expose_inputs(FleurScfWorkChain, namespace='scf') spec.input('wf_parameters', valid_type=Dict, required=False) spec.input('fleur', valid_type=Code, required=True) @@ -120,7 +120,7 @@ def start(self): inputs = self.inputs - wf_default = copy.deepcopy(self._wf_default) + wf_default = copy.deepcopy(self._default_wf_para) if 'wf_parameters' in inputs: wf_dict = inputs.wf_parameters.get_dict() else: @@ -301,11 +301,16 @@ def return_results(self): efermi_scf = scf_results.fermi_energy bandgap_scf = scf_results.bandgap - efermi_band = last_calc_out_dict['fermi_energy'] - bandgap_band = last_calc_out_dict['bandgap'] + efermi_band = last_calc_out_dict.get('fermi_energy', None) + bandgap_band = last_calc_out_dict.get('bandgap', None) - diff_efermi = efermi_scf - efermi_band - diff_bandgap = bandgap_scf - bandgap_band + diff_efermi = None + if efermi_band is not None: + diff_efermi = efermi_scf - efermi_band + + diff_bandgap = None + if bandgap_band is not None: + diff_bandgap = bandgap_scf - bandgap_band outputnode_dict = {} diff --git a/aiida_fleur/workflows/base_fleur.py b/aiida_fleur/workflows/base_fleur.py index 2c428e556..daadc01df 100644 --- a/aiida_fleur/workflows/base_fleur.py +++ b/aiida_fleur/workflows/base_fleur.py @@ -39,7 +39,7 @@ class FleurBaseWorkChain(BaseRestartWorkChain): @classmethod def define(cls, spec): - super(FleurBaseWorkChain, cls).define(spec) + super().define(spec) spec.input('code', valid_type=orm.Code, help='The FLEUR code.') spec.input('parent_folder', valid_type=orm.RemoteData, @@ -174,8 +174,8 @@ def check_kpts(self): self.ctx.suggest_mpi_omp_ratio, fleurinp, only_even_MPI=self.inputs.only_even_MPI) - except ValueError: - raise Warning('Not optimal computational resources, load less than 60%') + except ValueError as exc: + raise Warning('Not optimal computational resources, load less than 60%') from exc self.report(message) diff --git a/aiida_fleur/workflows/base_relax.py b/aiida_fleur/workflows/base_relax.py index dc18c2fdf..deb41dd5f 100644 --- a/aiida_fleur/workflows/base_relax.py +++ b/aiida_fleur/workflows/base_relax.py @@ -41,7 +41,7 @@ class FleurBaseRelaxWorkChain(BaseRestartWorkChain): @classmethod def define(cls, spec): - super(FleurBaseRelaxWorkChain, cls).define(spec) + super().define(spec) spec.expose_inputs(RelaxProcess) spec.input('description', valid_type=six.string_types, @@ -89,7 +89,11 @@ def pop_non_stacking_inpxml_changes(self): """ pops some inpxml_changes that do not stack, for example shift_value. """ - wf_param = self.ctx.inputs.scf.wf_parameters.get_dict() + if 'wf_parameters' in self.ctx.inputs.scf: + wf_param = self.ctx.inputs.scf.wf_parameters.get_dict() + else: + wf_param = {} + if 'inpxml_changes' not in wf_param: return diff --git a/aiida_fleur/workflows/corehole.py b/aiida_fleur/workflows/corehole.py index b6ee6391f..243cb3bb1 100644 --- a/aiida_fleur/workflows/corehole.py +++ b/aiida_fleur/workflows/corehole.py @@ -99,8 +99,8 @@ class fleur_corehole_wc(WorkChain): # #'references' : 'calculate',# at some point aiida will have fast forwarding # 'relax' : False, # relax the unit cell first? # 'relax_mode': 'Fleur', # what releaxation do you want - # 'relax_para' : 'default', # parameter dict for the relaxation - # 'scf_para' : 'default', # wf parameter dict for the scfs + # 'relax_para' : None, # parameter dict for the relaxation + # 'scf_para' : None, # wf parameter dict for the scfs # 'same_para' : True, # enforce the same atom parameter/cutoffs on the corehole calc and ref # 'resources' : {"num_machines": 1},# resources per job # 'max_wallclock_seconds' : 6*60*60, # walltime per job @@ -126,61 +126,36 @@ class fleur_corehole_wc(WorkChain): #'import_sys_environment': False, #'environment_variables': {} } + _default_wf_para = { + 'method': 'valence', # what method to use, default for valence to highest open shell + 'hole_charge': 1.0, # what is the charge of the corehole? 0<1.0 + 'atoms': + ['all'], # coreholes on what atoms, positions or index for list, or element ['Be', (0.0, 0.5, 0.334), 3] + 'corelevel': ['all'], # coreholes on which corelevels [ 'Be1s', 'W4f', 'Oall'...] + 'supercell_size': [2, 1, 1], # size of the supercell [nx,ny,nz] + 'para_group': None, # use parameter nodes from a parameter group + #'references' : 'calculate',# at some point aiida will have fast forwarding + #'relax' : False, # relax the unit cell first? + #'relax_mode': 'Fleur', # what releaxation do you want + #'relax_para' : None, # parameter dict for the relaxation + 'scf_para': None, # wf parameter dict for the scfs + 'same_para': True, # enforce the same atom parameter/cutoffs on the corehole calc and ref + 'serial': True, # run fleur in serial, or parallel? + #'job_limit' : 100 # enforce the workflow not to spawn more scfs wcs then this number(which is roughly the number of fleur jobs) + 'magnetic': True + } @classmethod def define(cls, spec): - super(fleur_corehole_wc, cls).define(spec) - spec.input( - 'wf_parameters', - valid_type=Dict, - required=False, - #default=Dict( - # dict={ - # 'method': - # 'valence', # what method to use, default for valence to highest open shell - # 'hole_charge': 1.0, # what is the charge of the corehole? 0<1.0 - # 'atoms': [ - # 'all' - # ], # coreholes on what atoms, positions or index for list, or element ['Be', (0.0, 0.5, 0.334), 3] - # 'corelevel': ['all' - # ], # coreholes on which corelevels [ 'Be1s', 'W4f', 'Oall'...] - # 'supercell_size': [2, 1, 1], # size of the supercell [nx,ny,nz] - # 'para_group': None, # use parameter nodes from a parameter group - # #'references' : 'calculate',# at some point aiida will have fast forwarding - # #'relax' : False, # relax the unit cell first? - # #'relax_mode': 'Fleur', # what releaxation do you want - # #'relax_para' : 'default', # parameter dict for the relaxation - # 'scf_para': 'default', # wf parameter dict for the scfs - # 'same_para': - # True, # enforce the same atom parameter/cutoffs on the corehole calc and ref - # 'serial': True, # run fleur in serial, or parallel? - # #'job_limit' : 100 # enforce the workflow not to spawn more scfs wcs then this number(which is roughly the number of fleur jobs) - # 'magnetic': True - # } - #) - ) + super().define(spec) + spec.input('wf_parameters', valid_type=Dict, required=False, default=lambda: Dict(dict=cls._default_wf_para)) spec.input('fleurinp', valid_type=FleurinpData, required=False) spec.input('fleur', valid_type=Code, required=True) spec.input('inpgen', valid_type=Code, required=True) spec.input('structure', valid_type=StructureData, required=False) spec.input('calc_parameters', valid_type=Dict, required=False) - spec.input( - 'options', - valid_type=Dict, - required=False #, - #default=Dict( - # dict={ - # 'resources': { - # "num_machines": 1, "num_mpiprocs_per_machine": 1, - # }, - # 'max_wallclock_seconds': 60 * 60, - # 'queue_name': '', - # 'custom_scheduler_commands': '', - # 'import_sys_environment': False, - # 'environment_variables': {} - # } - #) - ) + spec.input('options', valid_type=Dict, required=False) #, default=lambda: Dict(dict=cls._default_options)) + spec.outline( cls.check_input, # first check if input is consistent if_(cls.relaxation_needed)( # ggf relax the given cell @@ -648,8 +623,8 @@ def create_coreholes(self): #pprint('inpxml_changes {}'.format(corehole['inpxml_changes'])) # create_wf para or write in last line what should be in 'fleur_change' # for scf, which with the changes in the inp.xml needed - para = self.ctx.scf_para.copy() # Otherwise inline edit... What about Provenance? TODO check - if para == 'default': + para = self.ctx.scf_para # Otherwise inline edit... What about Provenance? TODO check + if para is None: wf_parameter = {} else: wf_parameter = para @@ -697,7 +672,7 @@ def run_ref_scf(self): self.report('INFO: In run_ref_scf fleur_corehole_wc') print('INFO: In run_ref_scf fleur_corehole_wc') para = self.ctx.scf_para - if para == 'default': + if para is None: wf_parameter = {} else: wf_parameter = para @@ -841,7 +816,7 @@ def run_scfs(self): self.report('INFO: In run_scfs fleur_corehole_wc') print('INFO: In run_scfs fleur_corehole_wc') para = self.ctx.scf_para - if para == 'default': + if para is None: wf_parameter = {} else: wf_parameter = para @@ -1098,7 +1073,9 @@ def create_corehole_result_node(**kwargs): #*args): # 'inpxml_changes' : fleurinp_change} @cf def prepare_struc_corehole_wf( - base_supercell, wf_para, para + base_supercell, + wf_para, + para=None, ): #, _label='prepare_struc_corehole_wf', _description='WF, used in the corehole_wc, breaks the symmetry and moves the cell, prepares the inpgen parameters for a corehole.'): """ calcfunction which does all/some the structure+calcparameter manipulations together @@ -1106,6 +1083,7 @@ def prepare_struc_corehole_wf( wf_para: Dict node dict: {'site' : sites[8], 'kindname' : 'W1', 'econfig': "[Kr] 5s2 4d10 4f13 | 5p6 5d5 6s2", 'fleurinp_change' : []} """ from aiida_fleur.tools.StructureData_util import move_atoms_incell + #from aiida.orm.data.structure import Site wf_para_dict = wf_para.get_dict() @@ -1120,12 +1098,14 @@ def prepare_struc_corehole_wf( npos = -np.array(pos) # break the symmetry, make corehole atoms its own species. # pos has to be tuple, unpack problem here.. #TODO rather not so nice - new_struc, new_para = break_symmetry(base_supercell, - atoms=[], - site=[], - pos=[(pos[0], pos[1], pos[2])], - new_kinds_names=new_kinds_names, - parameterdata=para) + inputs = dict(structure=base_supercell, + atoms=[], + site=[], + pos=[(pos[0], pos[1], pos[2])], + new_kinds_names=new_kinds_names) + if para is not None: + inputs['parameterdata'] = para + new_struc, new_para = break_symmetry(**inputs) #kinds = new_struc.kinds #for kind in kinds: # if kind.name == broke_kn: @@ -1160,11 +1140,12 @@ def extract_results_corehole(calcs): print(calc.exit_status, calc.exit_message) print(calc.get_outgoing().all()) try: - calc_uuids.append(calc.outputs.output_scf_wc_para.get_dict()['last_calc_uuid']) + calc_uuid = calc.outputs.output_scf_wc_para.get_dict()['last_calc_uuid'] except (KeyError, AttributeError): print('continue') continue - #calc_uuids.append(calc['output_scf_wc_para'].get_dict()['last_calc_uuid']) + if calc_uuid is not None: + calc_uuids.append(calc_uuid) #print(calc_uuids) #all_corelevels = {} diff --git a/aiida_fleur/workflows/corelevel.py.legacy b/aiida_fleur/workflows/corelevel.py.legacy deleted file mode 100644 index 1f3dff4c9..000000000 --- a/aiida_fleur/workflows/corelevel.py.legacy +++ /dev/null @@ -1,258 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################### -# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # -# All rights reserved. # -# This file is part of the AiiDA-FLEUR package. # -# # -# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # -# For further information on the license, see the LICENSE.txt file # -# For further information please visit http://www.flapw.de or # -# http://aiida-fleur.readthedocs.io/en/develop/ # -############################################################################### - - -""" -This is the worklfow 'corelevel' using the Fleur code, which calculates Binding -energies and corelevel shifts with different methods. -'divide and conquer' -""" -# TODO alow certain kpoint path, or kpoint node, so far auto - - -from __future__ import absolute_import -from __future__ import print_function -import os.path -from aiida.plugins import Code, DataFactory -from aiida.engine import WorkChain -from aiida.engine import submit -from aiida.engine import ToContext -from aiida.engine import while_, if_ -#from aiida.work.process_registry import ProcessRegistry - -from aiida_fleur.calculation.fleur import FleurCalculation -from aiida_fleur.data.fleurinpmodifier import FleurinpModifier -from aiida_fleur.tools.create_corehole import create_corehole -import six - -StructureData = DataFactory('structure') -Dict = DataFactory('dict') -RemoteData = DataFactory('remote') -FleurinpData = DataFactory('fleur.fleurinp') -FleurProcess = FleurCalculation.process() - - -class fleur_corelevel_wc(WorkChain): - ''' - Turn key solution for the calculation of core level shift and Binding energies - - - ''' - # wf_Parameters: Dict, - ''' - 'method' : ['initial', 'full_valence ch', 'half_valence_ch', 'ch', ...] - 'Bes' : [W4f, Be1s] - 'CLS' : [W4f, Be1s] - 'atoms' : ['all', 'postions' : []] - 'references' : ['calculate', or - 'scf_para' : {...}, 'default' - 'relax' : True - 'relax_mode': ['Fleur', 'QE Fleur', 'QE'] - 'relax_para' : {...}, 'default' - 'calculate_doses' : False - 'dos_para' : {...}, 'default' - ''' - ''' - # defaults - default wf_Parameters:: - 'method' : 'initial' - 'atoms' : 'all - 'references' : 'calculate' - 'scf_para' : 'default' - 'relax' : True - 'relax_mode': 'QE Fleur' - 'relax_para' : 'default' - 'calculate_doses' : False - 'dos_para' : 'default' - ''' - - _workflowversion = "0.0.1" - - @classmethod - def define(cls, spec): - super(corelevel, cls).define(spec) - spec.input("wf_parameters", valid_type=Dict, required=False, - default=Dict(dict={ - 'method' : 'initial', - 'atoms' : 'all', - 'references' : 'calculate', - 'calculate_doses' : False, - 'relax' : True, - 'relax_mode': 'QE Fleur', - 'relax_para' : 'default', - 'scf_para' : 'default', - 'dos_para' : 'default'})) - spec.input("fleurinp", valid_type=FleurinpData, required=True) - spec.input("fleur", valid_type=Code, required=True) - spec.input("structure", valid_type=StructureData, required=False) - spec.input("calc_parameters", valid_type=Dict, required=False) - spec.outline( - cls.check_input, - if_(cls.initalstate)( - cls.calculate_inital), - cls.create_new_fleurinp, - cls.run_fleur, - cls.run_scfs, - cls.collect_results, - cls.return_results - ) - #spec.dynamic_output() - - - def start(self): - ''' - check parameters, what condictions? complete? - check input nodes - ''' - ### input check ### ? or done automaticly, how optional? - # check if fleuinp corresponds to fleur_calc - print(('started bands workflow version {}'.format(self._workflowversion))) - print("Workchain node identifiers: ")#{}" - #"".format(ProcessRegistry().current_calc_node)) - - - - def create_new_fleurinp(self): - """ - create a new fleurinp from the old with certain parameters - """ - # TODO allow change of kpoint mesh?, tria? - wf_dict = self.inputs.wf_parameters.get_dict() - nkpts = wf_dict.get('nkpts', 500) - # how can the user say he want to use the given kpoint mesh, ZZ nkpts : False/0 - sigma = wf_dict.get('sigma', 0.005) - emin = wf_dict.get('emin', -0.30) - emax = wf_dict.get('emax', 0.80) - - fleurmode = FleurinpModifier(self.inputs.fleurinp) - - #change_dict = {'band': True, 'ndir' : -1, 'minEnergy' : self.inputs.wf_parameters.get_dict().get('minEnergy', -0.30000000), - #'maxEnergy' : self.inputs.wf_parameters.get_dict().get('manEnergy','0.80000000'), - #'sigma' : self.inputs.wf_parameters.get_dict().get('sigma', '0.00500000')} - change_dict = {'band': True, 'ndir' : 0, 'minEnergy' : emin, - 'maxEnergy' : emax, 'sigma' : sigma} #'ndir' : 1, 'pot8' : True - - fleurmode.set_inpchanges(change_dict) - - if nkpts: - fleurmode.set_nkpts(count=nkpts) - #fleurinp_new.replace_tag() - - fleurmode.show(validate=True, display=False) # needed? - fleurinp_new = fleurmode.freeze() - self.ctx.fleurinp1 = fleurinp_new - print(fleurinp_new) - #print(fleurinp_new.folder.get_subfolder('path').get_abs_path('')) - - def get_inputs_fleur(self): - ''' - get the input for a FLEUR calc - ''' - inputs = FleurProcess.get_inputs_template() - - fleurin = self.ctx.fleurinp1 - #print fleurin - remote = self.inputs.remote - inputs.parent_folder = remote - inputs.code = self.inputs.fleur - inputs.fleurinpdata = fleurin - - # TODO nkpoints decide n core - - core = 12 # get from computer nodes per machine - inputs._options.resources = {"num_machines": 1, "num_mpiprocs_per_machine" : core} - inputs._options.max_wallclock_seconds = 30 * 60 - - if self.ctx.serial: - inputs._options.withmpi = False # for now - inputs._options.resources = {"num_machines": 1} - - if self.ctx.queue: - inputs._options.queue_name = self.ctx.queue - print((self.ctx.queue)) - # if code local use - #if self.inputs.fleur.is_local(): - # inputs._options.computer = computer - # #else use computer from code. - #else: - # inputs._options.queue_name = 'th1' - - if self.ctx.serial: - inputs._options.withmpi = False # for now - inputs._options.resources = {"num_machines": 1} - - return inputs - - def run_fleur(self): - ''' - run a fleur calculation - ''' - FleurProcess = FleurCalculation.process() - inputs = {} - inputs = self.get_inputs_fleur() - #print inputs - future = submit(FleurProcess, **inputs) - print('run Fleur in band workflow') - - return ToContext(last_calc=future) - - def return_results(self): - ''' - return the results of the calculations - ''' - # TODO more here - print('Band workflow Done') - print(('A bandstructure was calculated for fleurinpdata {} and is found under pk={}, ' - 'calculation {}'.format(self.inputs.fleurinp, self.ctx.last_calc.pk, self.ctx.last_calc))) - - #check if band file exists: if not succesful = False - #TODO be careful with general bands.X - - bandfilename = 'bands.1' # ['bands.1', 'bands.2', ...] - # TODO this should be easier... - last_calc_retrieved = self.ctx.last_calc.get_outputs_dict()['retrieved'].folder.get_subfolder('path') - bandfilepath = self.ctx.last_calc.get_outputs_dict()['retrieved'].folder.get_subfolder('path').get_abs_path(bandfilename) - print(bandfilepath) - #bandfilepath = "path to bandfile" # Array? - if os.path.isfile(bandfilepath): - self.ctx.successful = True - else: - bandfilepath = None - print('!NO bandstructure file was found, something went wrong!') - #TODO corret efermi: - # get efermi from last calculation - efermi1 = self.inputs.remote.get_inputs()[-1].res.fermi_energy - #get efermi from this caclulation - efermi2 = self.ctx.last_calc.res.fermi_energy - diff_efermi = efermi1 - efermi2 - # store difference in output node - # adjust difference in band.gnu - #filename = 'gnutest2' - - outputnode_dict ={} - - outputnode_dict['workflow_name'] = self.__class__.__name__ - outputnode_dict['Warnings'] = self.ctx.warnings - outputnode_dict['successful'] = self.ctx.successful - outputnode_dict['diff_efermi'] = diff_efermi - #outputnode_dict['last_calc_pk'] = self.ctx.last_calc.pk - #outputnode_dict['last_calc_uuid'] = self.ctx.last_calc.uuid - outputnode_dict['bandfile'] = bandfilepath - outputnode_dict['last_calc_uuid'] = self.ctx.last_calc.uuid - outputnode_dict['last_calc_retrieved'] = last_calc_retrieved - #print outputnode_dict - outputnode = Dict(dict=outputnode_dict) - outdict = {} - outdict['band_out'] = outputnode - #print outdict - for k, v in six.iteritems(outdict): - self.out(k, v) diff --git a/aiida_fleur/workflows/create_magnetic_film.py b/aiida_fleur/workflows/create_magnetic_film.py index 25224d5df..b5fcb54ac 100644 --- a/aiida_fleur/workflows/create_magnetic_film.py +++ b/aiida_fleur/workflows/create_magnetic_film.py @@ -34,7 +34,7 @@ class FleurCreateMagneticWorkChain(WorkChain): """ _workflowversion = '0.1.2' - _wf_default = { + _default_wf_para = { 'lattice': 'fcc', 'miller': [[-1, 1, 0], [0, 0, 1], [1, 1, 0]], 'host_symbol': 'Pt', @@ -53,7 +53,7 @@ class FleurCreateMagneticWorkChain(WorkChain): @classmethod def define(cls, spec): - super(FleurCreateMagneticWorkChain, cls).define(spec) + super().define(spec) spec.expose_inputs(FleurEosWorkChain, namespace_options={ 'required': False, @@ -133,7 +133,7 @@ def start(self): self.ctx.substrate = None # initialize the dictionary using defaults if no wf paramters are given - wf_default = copy.deepcopy(self._wf_default) + wf_default = copy.deepcopy(self._default_wf_para) if 'wf_parameters' in self.inputs: wf_dict = self.inputs.wf_parameters.get_dict() else: diff --git a/aiida_fleur/workflows/delta.py b/aiida_fleur/workflows/delta.py deleted file mode 100644 index 5df0bf867..000000000 --- a/aiida_fleur/workflows/delta.py +++ /dev/null @@ -1,614 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################### -# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # -# All rights reserved. # -# This file is part of the AiiDA-FLEUR package. # -# # -# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # -# For further information on the license, see the LICENSE.txt file # -# For further information please visit http://www.flapw.de or # -# http://aiida-fleur.readthedocs.io/en/develop/ # -############################################################################### -""" -In this module you find the worklfow 'fleur_delta_wc' which is a turnkey solution to calculate a delta for a given code with AiiDA. -""" -#TODO: calculation of delta value from the files -# submit everything if subworkchaining works in Aiida -# parameter node finding is not optimal. - -# TODO several eos starts wich only 20 structures to limit jobs throughput -from __future__ import absolute_import -from __future__ import print_function -import os -import six -from string import digits -#from pprint import pprint - -from aiida.plugins import DataFactory -from aiida.orm import Code, Group -from aiida.orm import RemoteData, StructureData, Dict, SinglefileData -from aiida.engine import WorkChain, ToContext #, while_ -#from aiida.work.process_registry import ProcessRegistry -from aiida.engine import calcfunction as cf -from aiida.engine import submit -from aiida.common.exceptions import NotExistent - -from aiida_fleur.workflows.eos import FleurEosWorkChain -from aiida_fleur.data.fleurinp import FleurinpData - - -class fleur_delta_wc(WorkChain): - """ - This workflow calculates a equation of states and from a given - group of structures in the database using a group of given parameter nodes in the database - """ - - _workflowversion = '0.3.2' - _wf_default = {} - - @classmethod - def define(cls, spec): - super(fleur_delta_wc, cls).define(spec) - spec.input( - 'wf_parameters', - valid_type=Dict, - required=False, - default=Dict( - dict={ - 'struc_group': 'delta', - 'para_group': 'delta', - 'add_extra': { - 'type': 'delta run' - }, - #'group_label' : 'delta_eos', - 'joblimit': 100, - 'part': [1, 2, 3, 4], - 'points': 7, - 'step': 0.02 - })) - spec.input('options', - valid_type=Dict, - required=False, - default=Dict( - dict={ - 'resources': { - 'num_machines': 1 - }, - 'walltime_sec': 60 * 60, - 'queue_name': '', - 'custom_scheduler_commands': '', - 'import_sys_environment': False, - 'environment_variables': {} - })) - spec.input('inpgen', valid_type=Code, required=True) - spec.input('fleur', valid_type=Code, required=True) - spec.outline( - cls.start_up, - #while_(cls.calculations_left_torun)( - cls.run_eos, #), - cls.extract_results_eos, - cls.calculate_delta, - cls.return_results, - ) - #spec.dynamic_output() - - def start_up(self): - """ - init context and some parameters - """ - - #print('started delta workflow version {}'.format(self._workflowversion)) - #print("Workchain node identifiers: {}".format(ProcessRegistry().current_calc_node)) - #identifier = 0#ProcessRegistry().current_calc_node - #self.ctx.own_uuid = identifier.uuid - #self.ctx.own_pk = identifier.pk - - self.report('started delta workflow version {} with identifier: ' #{}' - ''.format(self._workflowversion)) #, identifier)) - - # init - self.ctx.calcs_to_run = [] - # input check - - # check if right codes - wf_dict = self.inputs.wf_parameters.get_dict() - options_dict = self.inputs.get('options', - Dict(dict={ - 'resources': { - 'num_machines': 1 - }, - 'walltime_sec': int(5.5 * 3600) - })) - self.ctx.inputs_eos = { - 'fleur': self.inputs.fleur, - 'inpgen': self.inputs.inpgen, - 'wf_parameters': { - 'points': wf_dict.get('points', 7), - 'step': wf_dict.get('step', 0.02), - 'guess': 1.0 - }, - 'options': options_dict - } - self.ctx.wc_eos_para = Dict(dict=self.ctx.inputs_eos.get('wf_parameters')) - self.ctx.ncalc = 1 # init - self.get_calcs_from_groups() - self.ctx.successful = True - self.ctx.warnings = [] - self.ctx.labels = [] - #self.ctx.calcs_to_run = calcs - self.ctx.ncalcs = len(self.ctx.calcs_to_run) - print((self.ctx.ncalcs)) - print((self.ctx.ncalc)) - estimated_jobs = self.ctx.ncalc * wf_dict.get('points', 5) - joblimit = wf_dict.get('joblimit', 90) - self.ctx.eos_run_steps = 1 - self.ctx.eos_steps_done = 0 - self.ctx.minindex = 0 - self.ctx.maxindex = self.ctx.ncalc - 1 - self.ctx.eos_max_perstep = 10000 # init - - if estimated_jobs >= joblimit: - self.ctx.eos_run_steps = estimated_jobs / joblimit + 1 - self.ctx.eos_max_perstep = joblimit / wf_dict.get('points', 5) - # TODO be carefull if is not a divisor... of joblimit - self.ctx.maxindex = 0 # will be set later self.ctx.eos_max_perstep - - self.report('{} {}'.format(self.ctx.ncalc, self.ctx.eos_max_perstep)) - self.report('Estimated fleur scfs to run {}, running in {} steps.' - ''.format(estimated_jobs, self.ctx.eos_run_steps)) - - def get_calcs_from_groups(self): - """ - Extract the crystal structures and parameter data nodes from the given - groups and create calculation 'pairs' (stru, para). - """ - wf_dict = self.inputs.wf_parameters.get_dict() - #get all delta structure - str_gr = wf_dict.get('struc_group', 'delta') - - try: - group_pk = int(str_gr) - except ValueError: - group_pk = None - group_name = str_gr - - if group_pk is not None: - try: - str_group = Group(label=group_pk) - except NotExistent: - str_group = None - message = ('You have to provide a valid pk for a Group of' - 'structures or a Group name. Wf_para key: "struc_group".' - 'given pk= {} is not a valid group' - '(or is your group name integer?)'.format(group_pk)) - #print(message) - self.report(message) - self.abort_nowait('I abort, because I have no structures to calculate ...') - else: - try: - str_group = Group.get_from_string(group_name) - except NotExistent: - str_group = None - message = ('You have to provide a valid pk for a Group of' - 'structures or a Group name. Wf_para key: "struc_group".' - 'given group name= {} is not a valid group' - '(or is your group name integer?)'.format(group_name)) - #print(message) - self.report(message) - self.abort_nowait('I abort, because I have no structures to calculate ...') - - #get all delta parameters - para_gr = wf_dict.get('para_group', 'delta') - - if not para_gr: - #waring use defauls - message = 'COMMENT: I did recieve "para_group=None" as input. I will use inpgen defaults' - self.report(message) - - try: - group_pk = int(para_gr) - except ValueError: - group_pk = None - group_name = para_gr - - if group_pk is not None: - try: - para_group = Group(label=group_pk) - except NotExistent: - para_group = None - message = ('ERROR: You have to provide a valid pk for a Group of' - 'parameters or a Group name (or use None for inpgen defaults). Wf_para key: "para_group".' - 'given pk= {} is not a valid group' - '(or is your group name integer?)'.format(group_pk)) - #print(message) - self.report(message) - self.abort_nowait('ERROR: I abort, because I have no paremeters to calculate and ' - 'I guess you did not want to use the inpgen default...') - else: - try: - para_group = Group.get_from_string(group_name) - except NotExistent: - para_group = None - message = ('ERROR: You have to provide a valid pk for a Group of' - 'parameters or a Group name (or use None for inpgen defaults). Wf_para key: "struc_group".' - 'given group name= {} is not a valid group' - '(or is your group name integer?)'.format(group_name)) - #print(message) - self.report(message) - self.abort_nowait('ERROR: I abort, because I have no paremeters to calculate and ' - 'I guess you did not want to use the inpgen default...') - - # creating calculation pairs (structure, parameters) - - para_nodesi = para_group.nodes - para_nodes = [] - - for para in para_nodesi: - para_nodes.append(para) - #print para_nodes - n_para = len(para_nodes) - stru_nodes = str_group.nodes - n_stru = len(stru_nodes) - if n_para != n_stru: - message = ('COMMENT: You did not provide the same number of parameter' - 'nodes as structure nodes. Is this wanted? npara={} nstru={}'.format(n_para, n_stru)) - self.report(message) - calcs = [] - for struc in stru_nodes: - para = get_paranode(struc, para_nodes) - #if para: - calcs.append((struc, para)) - #else: - # calcs.append((struc)) - #pprint(calcs[:20]) - self.ctx.calcs_to_run = calcs - self.ctx.ncalc = len(calcs) - - #def calculations_left_torun(self): - # """ - # Checks if there are still some equations of states to run - # """ - # calculations_left = True - # self.ctx.last_step = False - # - # if self.ctx.eos_steps_done == self.ctx.eos_run_steps: - # calculations_left = False - # if (self.ctx.eos_steps_done + 1) == self.ctx.eos_run_steps: - # self.ctx.last_step = True - # - # return calculations_left - - def run_eos(self): - """ - Run the equation of states for all delta structures with their parameters - """ - #if self.ctx.last_step: - # self.ctx.maxindex = None - #else: - # self.ctx.maxindex = self.ctx.maxindex + self.ctx.eos_max_perstep - - #self.report('Submitting eqaution of states part {} out of {}, from {} to {}' - # ''.format(self.ctx.eos_steps_done, self.ctx.eos_run_steps, - # self.ctx.minindex, self.ctx.maxindex)) - - eos_results = {} - inputs = self.get_inputs_eos() - - #print(self.ctx.minindex) - #print(self.ctx.maxindex) - - for struc, para in self.ctx.calcs_to_run: #[:4]self.ctx.minindex:self.ctx.maxindex]:#0:0]:# - #print para - formula = struc.get_formula() - label = '|delta_wc|eos|{}'.format(formula) - description = '|delta| fleur_eos_wc on {}'.format(formula) - if para: - eos_future = submit(FleurEosWorkChain, - wf_parameters=inputs['wc_eos_para'], - structure=struc, - options=inputs['options'], - calc_parameters=para, - inpgen=inputs['inpgen'], - fleur=inputs['fleur'], - label=label, - description=description) - else: # TODO: run eos_wc_simple - eos_future = submit(FleurEosWorkChain, - wf_parameters=inputs['wc_eos_para'], - structure=struc, - options=inputs['options'], - inpgen=inputs['inpgen'], - fleur=inputs['fleur'], - label=label, - description=description) - self.report('launching fleur_eos_wc<{}> on structure {} with parameter {}' - ''.format(eos_future.pid, struc.pk, para.pk)) - label = formula - self.ctx.labels.append(label) - eos_results[label] = eos_future - - #self.ctx.eos_steps_done = self.ctx.eos_steps_done + 1 - #self.ctx.minindex = self.ctx.maxindex - ''' - # with run - eos_results = {} - inputs = self.get_inputs_eos() - - - for struc, para in self.ctx.calcs_to_run[:]: - print para - formula = struc.get_formula() - if para: - #print('here') - eos_future = fleur_eos_wc.run( - wf_parameters=inputs['wc_eos_para'], structure=struc, - calc_parameters=para, inpgen=inputs['inpgen'], fleur=inputs['fleur']) - #fleur_eos_wc.run(# - else: - self.report('INFO: default parameters for structure {}'.format(formula)) - eos_future = fleur_eos_wc.run( - wf_parameters=inputs['wc_eos_para'], structure=struc, - inpgen=inputs['inpgen'], fleur=inputs['fleur']) - #fleur_eos_wc.run(#a - #self.report('launching fleur_eos_wc<{}> on structure {} with parameter {}' - # ''.format(eos_future.pid, struc.pk, para.pk)) - label = formula - self.ctx.labels.append(label) - eos_results[label] = eos_future - - return ToContext(**eos_results) - ''' - return ToContext(**eos_results) - - # To limit the troughput of 100 jobs, we create several run eos steps - def get_inputs_eos(self): - """ - get the inputs for a scf-cycle - """ - inputs = {} - # produce the inputs for a eos worklfow (collect here...) - - inputs['wc_eos_para'] = self.ctx.wc_eos_para - #inputs['calc_parameters'] = self.inputs.calc_parameters - inputs['inpgen'] = self.ctx.inputs_eos.get('inpgen') - inputs['fleur'] = self.ctx.inputs_eos.get('fleur') - inputs['options'] = self.ctx.inputs_eos.get('options') - return inputs - - def extract_results_eos(self): - """ - extract information out of the result nodes of the the eos workchains - ran in the step before - """ - - self.ctx.all_results = {} - self.ctx.all_succ = {} - self.ctx.eos_uuids = {} - outstr = ('''\ - Delta calculation FLEUR {} (AiiDA wc). - - Crystal \t V0 \t \t B0 \t \t BP [A^3/at] \t [GPa] \t \t [--] \n - '''.format(self.ctx.inputs_eos.get('fleur'))) - filename = 'delta_wc_{}.out'.format(self.ctx.own_pk) - outfile = open(filename, 'w') - outfile.write(outstr) - outfile.close() - outstr = '' - for label in self.ctx.labels: - eos_res = self.ctx[label] - #print(calc) - outpara1 = eos_res.get_outputs_dict() - #print outpara1 - try: - outpara = outpara1['output_eos_wc_para'].get_dict() - except KeyError: - self.report('ERROR: Eos wc for element: {} failed. I retrieved {} ' - 'I skip the results retrieval for that element.'.format(label, eos_res)) - continue - eos_succ = outpara.get('successful', False) - if not eos_succ: - #maybe do something else here (exclude point and write a warning or so, or error treatment) - self.ctx.successful = False - - natoms = outpara.get('natoms', None) - gs_vol = outpara.get('volume_gs', None) - bm = outpara.get('bulk_modulus', None) - #bm_u = outpara.get('bulk_modulus_units', 'GPa') - dbm = outpara.get('bulk_deriv', None) - if natoms: - gs_vol_pera = gs_vol / natoms - else: - gs_vol_pera = gs_vol - - element = label.translate(None, digits) # remove all numbers from string - self.ctx.all_results[element] = [gs_vol_pera, bm, dbm] - self.ctx.all_succ[element] = eos_succ - self.ctx.eos_uuids[element] = eos_res.get_inputs()[0].uuid - - outstr = outstr + '{} \t {:.5f} \t {:.5f} \t {:.5f} \n'.format(element, gs_vol_pera, bm, dbm) - #write inside the loop to have at least partially results... - #outfile = open('delta_wc.out', 'a') - #outstr = '{} \t {:.5f} \t {:.5f} \t {:.5f} \n'.format(element, gs_vol_pera, bm, dbm) - #outfile.write(outstr) - #outfile.close() - # produce a single file - # maybe put in try(or write in a certain place where is sure that you have the permissions) - #outfile = open('delta_wc.out', 'w') - outfile = open(filename, 'a') # for testing purposes - outfile.write(outstr) - - outfile.close() - - self.ctx.outfilepath = os.path.abspath(outfile.name) - - def calculate_delta(self): - """ - Execute here the script to calculate a delta factor - """ - pass - - def return_results(self): - """ - return the results of the calculations - """ - - # log some stuff in report - - # a text file should be written and stored as single file data and - #parameter data node in the database - - #produce a single file data with all the numbers - - all_res = self.ctx.all_results - self.report('all_res : {}'.format(all_res)) - #print all_res - bm_dic = {} - bmd_dic = {} - vol_dic = {} - - for elem, val in six.iteritems(all_res): - #print elem - vol_dic[elem] = val[0] - bm_dic[elem] = val[1] - bmd_dic[elem] = val[2] - - outputnode_dict = {} - - outputnode_dict['workflow_name'] = self.__class__.__name__ - outputnode_dict['warnings'] = self.ctx.warnings - outputnode_dict['successful'] = self.ctx.successful - outputnode_dict['eos_uuids'] = self.ctx.eos_uuids - outputnode_dict['eos_success'] = self.ctx.all_succ - outputnode_dict['bulk_modulus'] = bm_dic - outputnode_dict['bulk_modulus_units'] = 'GPa' - outputnode_dict['bulk_modulus_dev'] = bmd_dic - outputnode_dict['volumes'] = vol_dic - outputnode_dict['volumes_units'] = 'A^3/per atom' - outputnode_dict['delta_factor'] = {'Wien2K': '', 'Fleur_026': ''} - - #outputnode = Dict(dict=outputnode_dict) - - if self.ctx.successful: - self.report('INFO: Done, delta worklfow complete') - #print 'Done, delta worklfow complete' - else: - self.report('INFO: Done, but something went wrong.... Properly some ' - 'individual eos workchain failed. Check the log.') - #print('Done, but something went wrong.... Properly some ' - # 'individual eos workchain failed. Check the log.') - - delta_file = SinglefileData.filename = self.ctx.outfilepath - - print(delta_file) - - # output must be aiida Data types. - outnodedict = {} - outnode = Dict(dict=outputnode_dict) - outnodedict['results_node'] = outnode - for label in self.ctx.labels: - eos_res = self.ctx[label] - #print(calc) - outpara1 = eos_res.get_outputs_dict() - #print outpara1 - try: - outpara = outpara1['output_eos_wc_para'] - except KeyError: - #self.report('ERROR: Eos wc for element: {} failed. I retrieved {} ' - # 'I skip the results retrieval for that element.'.format(label, eos_res)) - continue - outnodedict[label] = outpara - - outputnode = create_delta_result_node(**outnodedict) - - outdict = {} - outdict['output_delta_wc_para'] = outputnode.get('output_delta_wc_para') - #outdict['delta_file'] = delta_file - #print outdict - for link_name, node in six.iteritems(outdict): - self.out(link_name, node) - - -''' -if __name__ == "__main__": - import argparse - - parser = argparse.ArgumentParser(description='SCF with FLEUR. workflow to' - ' converge the chargedensity and optional the total energy.') - parser.add_argument('--wf_para', type=Dict, dest='wf_parameters', - help='The pseudopotential family', required=False) - parser.add_argument('--structure', type=StructureData, dest='structure', - help='The crystal structure node', required=False) - parser.add_argument('--calc_para', type=Dict, dest='calc_parameters', - help='Parameters for the FLEUR calculation', required=False) - parser.add_argument('--fleurinp', type=FleurinpData, dest='fleurinp', - help='FleurinpData from which to run the FLEUR calculation', required=False) - parser.add_argument('--remote', type=RemoteData, dest='remote_data', - help=('Remote Data of older FLEUR calculation, ' - 'from which files will be copied (mixing_history ...)'), required=False) - parser.add_argument('--inpgen', type=Code, dest='inpgen', - help='The inpgen code node to use', required=False) - parser.add_argument('--fleur', type=Code, dest='fleur', - help='The FLEUR code node to use', required=True) - - args = parser.parse_args() - res = fleur_scf_wc.run(wf_parameters=args.wf_parameters, - structure=args.structure, - calc_parameters=args.calc_parameters, - fleurinp=args.fleurinp, - remote_data=args.remote_data, - inpgen = args.inpgen, - fleur=args.fleur) -''' - - -@cf -def create_delta_result_node(**kwargs): #*args): - """ - This is a pseudo wf, to create the rigth graph structure of AiiDA. - This wokfunction will create the output node in the database. - It also connects the output_node to all nodes the information commes from. - So far it is just also parsed in as argument, because so far we are to lazy - to put most of the code overworked from return_results in here. - - """ - outdict = {} - outpara = kwargs.get('results_node', {}) - outdict['output_delta_wc_para'] = outpara.clone() - # copy, because we rather produce the same node twice then have a circle in the database for now... - #output_para = args[0] - #return {'output_eos_wc_para'} - return outdict - - -def get_paranode(struc, para_nodes): - """ - find out if a parameter node for a structure is in para_nodes - (currently very creedy, but lists are small (100x100) but maybe reduce database accesses) - """ - - suuid = struc.uuid - formula = struc.get_formula() - element = formula.translate(None, digits) - #print para_nodes - for para in para_nodes: - struc_uuid = para.get_extra('struc_uuid', None) - para_form = para.get_extra('formula', None) - para_ele = para.get_extra('element', None) - if suuid == struc_uuid: - return para - elif formula == para_form: - return para - elif element == para_ele: - return para - elif element == para_form: - return para - else: - pass - #Do something else (test if parameters for a certain element are there) - #.... - # we found no parameter node for the given structure therefore return none - return None - - -def write_delta_file(result_dict): - pass diff --git a/aiida_fleur/workflows/delta_split.py.legacy b/aiida_fleur/workflows/delta_split.py.legacy deleted file mode 100644 index a06c9fe37..000000000 --- a/aiida_fleur/workflows/delta_split.py.legacy +++ /dev/null @@ -1,588 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################### -# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # -# All rights reserved. # -# This file is part of the AiiDA-FLEUR package. # -# # -# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # -# For further information on the license, see the LICENSE.txt file # -# For further information please visit http://www.flapw.de or # -# http://aiida-fleur.readthedocs.io/en/develop/ # -############################################################################### - -""" -In this module you find the worklfow 'fleur_delta_wc' which is a turnkey solution to calculate a delta for a given code with AiiDA. -""" -#TODO: calculation of delta value from the files -# submit everything if subworkchaining works in Aiida -# parameter node finding is not optimal. - -# TODO several eos starts wich only 20 structures to limit jobs throughput -from __future__ import absolute_import -from __future__ import print_function -import os -from string import digits -from pprint import pprint - -from aiida.plugins import Code, DataFactory, Group -from aiida.engine import WorkChain, ToContext, while_ -#from aiida.work.process_registry import ProcessRegistry -from aiida.engine import workfunction as wf -from aiida.engine import submit -from aiida.common.exceptions import NotExistent -from aiida_fleur.workflows.eos import fleur_eos_wc -import six - -#from aiida_fleur.tools.xml_util import eval_xpath2 -#from lxml import etree - - -RemoteData = DataFactory('remote') -StructureData = DataFactory('structure') -Dict = DataFactory('dict') -FleurinpData = DataFactory('fleur.fleurinp') -SingleData = DataFactory('singlefile') - -class fleur_delta_wc(WorkChain): - """ - This workflow calculates a equation of states and from a given - group of structures in the database using a group of given parameter nodes in the database - """ - - _workflowversion = "0.0.1" - _wf_default = {} - - def __init__(self, *args, **kwargs): - super(fleur_delta_wc, self).__init__(*args, **kwargs) - - @classmethod - def define(cls, spec): - super(fleur_delta_wc, cls).define(spec) - spec.input("wf_parameters", valid_type=Dict, required=False, - default=Dict(dict={'struc_group': 'delta', - 'para_group' : 'delta', - 'add_extra' : {'type' : 'delta run'}, - #'group_label' : 'delta_eos', - 'joblimit' : 100, - 'part' : [1,2,3,4], - 'points' : 5, - 'step' : 0.02, - 'queue_name' : '', - 'options' : {'resources' : {"num_machines": 1}, - 'walltime_sec' : int(5.5*3600)}})) - spec.input("inpgen", valid_type=Code, required=True) - spec.input("fleur", valid_type=Code, required=True) - spec.outline( - cls.start_up, - while_(cls.calculations_left_torun)( - cls.run_eos), - cls.extract_results_eos, - cls.calculate_delta, - cls.return_results, - - ) - #spec.dynamic_output() - - def start_up(self): - """ - init context and some parameters - """ - - #print('started delta workflow version {}'.format(self._workflowversion)) - #print("Workchain node identifiers: {}".format(ProcessRegistry().current_calc_node)) - self.report('started delta workflow version {} with idenifier: '#{}' - ''.format(self._workflowversion))#, ProcessRegistry().current_calc_node)) - - # init - self.ctx.calcs_to_run = [] - # input check - - # check if right codes - wf_dict = self.inputs.wf_parameters.get_dict() - self.ctx.inputs_eos = { - 'fleur': self.inputs.fleur, - 'inpgen': self.inputs.inpgen, - 'wf_parameters': - {'points' : wf_dict.get('points', 5), - 'step' : wf_dict.get('step', 0.02), - 'guess' : 1.0, - 'resources' : wf_dict.get('resources', {"num_machines": 1}), - 'walltime_sec': wf_dict.get('walltime_sec', int(5.5*3600)), - 'queue_name' : wf_dict.get('queue_name', ''), - 'serial' : wf_dict.get('serial', False) - }} - self.ctx.wc_eos_para = Dict(dict=self.ctx.inputs_eos.get('wf_parameters')) - self.ctx.ncalc = 1 # init - self.get_calcs_from_groups() - self.ctx.successful = True - self.ctx.warnings = [] - self.ctx.labels = [] - #self.ctx.calcs_to_run = calcs - self.ctx.ncalcs = len(self.ctx.calcs_to_run) - print(self.ctx.ncalcs) - print(self.ctx.ncalc) - estimated_jobs = self.ctx.ncalc*wf_dict.get('points', 5) - joblimit = wf_dict.get('joblimit', 90) - self.ctx.eos_run_steps = 1 - self.ctx.eos_steps_done = 0 - self.ctx.minindex = 0 - self.ctx.maxindex = self.ctx.ncalc -1 - self.ctx.eos_max_perstep = 10000 # init - - if estimated_jobs >= joblimit: - self.ctx.eos_run_steps = estimated_jobs/joblimit + 1 - self.ctx.eos_max_perstep = joblimit/wf_dict.get('points', 5) - # TODO be carefull if is not a divisor... of joblimit - self.ctx.maxindex = 0 # will be set later self.ctx.eos_max_perstep - - self.report('{} {}'.format(self.ctx.ncalc, self.ctx.eos_max_perstep)) - self.report('Estimated fleur scfs to run {}, running in {} steps.' - ''.format(estimated_jobs, self.ctx.eos_run_steps)) - - def get_calcs_from_groups(self): - """ - Extract the crystal structures and parameter data nodes from the given - groups and create calculation 'pairs' (stru, para). - """ - wf_dict = self.inputs.wf_parameters.get_dict() - #get all delta structure - str_gr = wf_dict.get('struc_group', 'delta') - - try: - group_pk = int(str_gr) - except ValueError: - group_pk = None - group_name = str_gr - - if group_pk is not None: - try: - str_group = Group(dbgroup=group_pk) - except NotExistent: - str_group = None - message = ('You have to provide a valid pk for a Group of' - 'structures or a Group name. Wf_para key: "struc_group".' - 'given pk= {} is not a valid group' - '(or is your group name integer?)'.format(group_pk)) - #print(message) - self.report(message) - self.abort_nowait('I abort, because I have no structures to calculate ...') - else: - try: - str_group = Group.get_from_string(group_name) - except NotExistent: - str_group = None - message = ('You have to provide a valid pk for a Group of' - 'structures or a Group name. Wf_para key: "struc_group".' - 'given group name= {} is not a valid group' - '(or is your group name integer?)'.format(group_name)) - #print(message) - self.report(message) - self.abort_nowait('I abort, because I have no structures to calculate ...') - - - #get all delta parameters - para_gr = wf_dict.get('para_group', 'delta') - - if not para_gr: - #waring use defauls - message = 'COMMENT: I did recieve "para_group=None" as input. I will use inpgen defaults' - self.report(message) - - try: - group_pk = int(para_gr ) - except ValueError: - group_pk = None - group_name = para_gr - - if group_pk is not None: - try: - para_group = Group(dbgroup=group_pk) - except NotExistent: - para_group = None - message = ('ERROR: You have to provide a valid pk for a Group of' - 'parameters or a Group name (or use None for inpgen defaults). Wf_para key: "para_group".' - 'given pk= {} is not a valid group' - '(or is your group name integer?)'.format(group_pk)) - #print(message) - self.report(message) - self.abort_nowait('ERROR: I abort, because I have no paremeters to calculate and ' - 'I guess you did not want to use the inpgen default...') - else: - try: - para_group = Group.get_from_string(group_name) - except NotExistent: - para_group = None - message = ('ERROR: You have to provide a valid pk for a Group of' - 'parameters or a Group name (or use None for inpgen defaults). Wf_para key: "struc_group".' - 'given group name= {} is not a valid group' - '(or is your group name integer?)'.format(group_name)) - #print(message) - self.report(message) - self.abort_nowait('ERROR: I abort, because I have no paremeters to calculate and ' - 'I guess you did not want to use the inpgen default...') - - # creating calculation pairs (structure, parameters) - - para_nodesi = para_group.nodes - para_nodes = [] - - for para in para_nodesi: - para_nodes.append(para) - #print para_nodes - n_para = len(para_nodes) - stru_nodes = str_group.nodes - n_stru = len(stru_nodes) - if n_para != n_stru: - message = ('COMMENT: You did not provide the same number of parameter' - 'nodes as structure nodes. Is this wanted? npara={} nstru={}'.format(n_para, n_stru)) - self.report(message) - calcs = [] - for struc in stru_nodes: - para = get_paranode(struc, para_nodes) - #if para: - calcs.append((struc, para)) - #else: - # calcs.append((struc)) - #pprint(calcs[:20]) - self.ctx.calcs_to_run = calcs - self.ctx.ncalc = len(calcs) - return - - def calculations_left_torun(self): - """ - Checks if there are still some equations of states to run - """ - calculations_left = True - self.ctx.last_step = False - - if self.ctx.eos_steps_done == self.ctx.eos_run_steps: - calculations_left = False - if (self.ctx.eos_steps_done + 1) == self.ctx.eos_run_steps: - self.ctx.last_step = True - - return calculations_left - - - - def run_eos(self): - """ - Run the equation of states for all delta structures with their parameters - """ - if self.ctx.last_step: - self.ctx.maxindex = None - else: - self.ctx.maxindex = self.ctx.maxindex + self.ctx.eos_max_perstep - - self.report('Submitting eqaution of states part {} out of {}, from {} to {}' - ''.format(self.ctx.eos_steps_done, self.ctx.eos_run_steps, - self.ctx.minindex, self.ctx.maxindex)) - - eos_results = {} - inputs = self.get_inputs_eos() - - - print((self.ctx.minindex)) - print((self.ctx.maxindex)) - - for struc, para in self.ctx.calcs_to_run[self.ctx.minindex:self.ctx.maxindex]:#0:0]:# - #print para - formula = struc.get_formula() - label = '|delta_wc|eos|{}'.format(formula) - description = '|delta| fleur_eos_wc on {}'.format(formula) - if para: - eos_future = submit(fleur_eos_wc, - wf_parameters=inputs['wc_eos_para'], structure=struc, - calc_parameters=para, inpgen=inputs['inpgen'], fleur=inputs['fleur'], - _label=label, _description=description) - else: # TODO: run eos_wc_simple - eos_future = submit(fleur_eos_wc, - wf_parameters=inputs['wc_eos_para'], structure=struc, - inpgen=inputs['inpgen'], fleur=inputs['fleur'], - _label=label, _description=description) - self.report('launching fleur_eos_wc<{}> on structure {} with parameter {}' - ''.format(eos_future.pid, struc.pk, para.pk)) - label = formula - self.ctx.labels.append(label) - eos_results[label] = eos_future - - self.ctx.eos_steps_done = self.ctx.eos_steps_done + 1 - self.ctx.minindex = self.ctx.maxindex - - - return ToContext(**eos_results) - - ''' - # with run - eos_results = {} - inputs = self.get_inputs_eos() - - - for struc, para in self.ctx.calcs_to_run[:]: - print para - formula = struc.get_formula() - if para: - #print('here') - eos_future = fleur_eos_wc.run( - wf_parameters=inputs['wc_eos_para'], structure=struc, - calc_parameters=para, inpgen=inputs['inpgen'], fleur=inputs['fleur']) - #fleur_eos_wc.run(# - else: - self.report('INFO: default parameters for structure {}'.format(formula)) - eos_future = fleur_eos_wc.run( - wf_parameters=inputs['wc_eos_para'], structure=struc, - inpgen=inputs['inpgen'], fleur=inputs['fleur']) - #fleur_eos_wc.run(#a - #self.report('launching fleur_eos_wc<{}> on structure {} with parameter {}' - # ''.format(eos_future.pid, struc.pk, para.pk)) - label = formula - self.ctx.labels.append(label) - eos_results[label] = eos_future - - return ToContext(**eos_results) - ''' - - # To limit the troughput of 100 jobs, we create several run eos steps - def get_inputs_eos(self): - """ - get the inputs for a scf-cycle - """ - inputs = {} - # produce the inputs for a eos worklfow (collect here...) - - inputs['wc_eos_para'] = self.ctx.wc_eos_para - #inputs['calc_parameters'] = self.inputs.calc_parameters - inputs['inpgen'] = self.ctx.inputs_eos.get('inpgen') - inputs['fleur'] = self.ctx.inputs_eos.get('fleur') - - return inputs - - def extract_results_eos(self): - """ - extract information out of the result nodes of the the eos workchains - ran in the step before - """ - - self.ctx.all_results = {} - self.ctx.all_succ = {} - self.ctx.eos_uuids ={} - outstr = ('''\ - Delta calculation FLEUR {} (AiiDA wc). - - Crystal \t V0 \t \t B0 \t \t BP [A^3/at] \t [GPa] \t \t [--] \n - '''.format(self.ctx.inputs_eos.get('fleur'))) - outfile = open('delta_wc.out', 'w') - outfile.write(outstr) - outfile.close() - outstr = '' - for label in self.ctx.labels: - eos_res = self.ctx[label] - #print(calc) - outpara1 = eos_res.get_outputs_dict() - #print outpara1 - try: - outpara= outpara1['output_eos_wc_para'].get_dict() - except KeyError: - self.report('ERROR: Eos wc for element: {} failed. I retrieved {} ' - 'I skip the results retrieval for that element.'.format(label, eos_res)) - continue - eos_succ = outpara.get('successful', False) - if not eos_succ: - #maybe do something else here (exclude point and write a warning or so, or error treatment) - self.ctx.successful = False - - natoms = outpara.get('natoms', None) - gs_vol = outpara.get('volume_gs', None) - bm = outpara.get('bulk_modulus', None) - #bm_u = outpara.get('bulk_modulus_units', 'GPa') - dbm = outpara.get('bulk_deriv', None) - if natoms: - gs_vol_pera = gs_vol/natoms - else: - gs_vol_pera = gs_vol - - element = label.translate(None, digits) # remove all numbers from string - self.ctx.all_results[element] = [gs_vol_pera, bm, dbm] - self.ctx.all_succ[element] = eos_succ - self.ctx.eos_uuids[element] = eos_res.get_inputs()[0].uuid - - outstr = outstr + '{} \t {:.5f} \t {:.5f} \t {:.5f} \n'.format(element, gs_vol_pera, bm, dbm) - #write inside the loop to have at least partially results... - #outfile = open('delta_wc.out', 'a') - #outstr = '{} \t {:.5f} \t {:.5f} \t {:.5f} \n'.format(element, gs_vol_pera, bm, dbm) - #outfile.write(outstr) - #outfile.close() - # produce a single file - # maybe put in try(or write in a certain place where is sure that you have the permissions) - #outfile = open('delta_wc.out', 'w') - outfile = open('delta_wc.out', 'a') # for testing purposes - outfile.write(outstr) - - outfile.close() - - self.ctx.outfilepath = os.path.abspath(outfile.name) - - - def calculate_delta(self): - """ - Execute here the script to calculate a delta factor - """ - pass - - def return_results(self): - """ - return the results of the calculations - """ - - # log some stuff in report - - # a text file should be written and stored as single file data and - #parameter data node in the database - - #produce a single file data with all the numbers - - all_res = self.ctx.all_results - bm_dic = {} - bmd_dic = {} - vol_dic = {} - - for elem,val in all_res: - vol_dic[elem] = val[0] - bm_dic[elem] = val[1] - bmd_dic[elem] = val[2] - - outputnode_dict ={} - - - outputnode_dict['workflow_name'] = self.__class__.__name__ - outputnode_dict['warnings'] = self.ctx.warnings - outputnode_dict['successful'] = self.ctx.successful - outputnode_dict['eos_uuids'] = self.ctx.eos_uuids - outputnode_dict['eos_success'] = self.ctx.all_succ - outputnode_dict['bulk_modulus'] = bm_dic - outputnode_dict['bulk_modulus_units'] = 'GPa' - outputnode_dict['bulk_modulus_dev'] = bmd_dic - outputnode_dict['volumes'] = vol_dic - outputnode_dict['volumes_units'] = 'A^3/per atom' - outputnode_dict['delta_factor'] = {'Wien2K' : '', 'Fleur_026' : ''} - - #outputnode = Dict(dict=outputnode_dict) - - if self.ctx.successful: - self.report('INFO: Done, delta worklfow complete') - #print 'Done, delta worklfow complete' - else: - self.report('INFO: Done, but something went wrong.... Properly some ' - 'individual eos workchain failed. Check the log.') - #print('Done, but something went wrong.... Properly some ' - # 'individual eos workchain failed. Check the log.') - - delta_file = SingleData.filename = self.ctx.outfilepath - - print(delta_file) - - # output must be aiida Data types. - outnodedict = {} - outnode = Dict(dict=outputnode_dict) - outnodedict['results_node'] = outnode - for label in self.ctx.labels: - eos_res = self.ctx[label] - #print(calc) - outpara1 = eos_res.get_outputs_dict() - #print outpara1 - try: - outpara = outpara1['output_eos_wc_para'] - except KeyError: - #self.report('ERROR: Eos wc for element: {} failed. I retrieved {} ' - # 'I skip the results retrieval for that element.'.format(label, eos_res)) - continue - outnodedict[label] = outpara - - outputnode = create_delta_result_node(**outnodedict) - - outdict = {} - outdict['output_delta_wc_para'] = outputnode.get('output_delta_wc_para') - #outdict['delta_file'] = delta_file - #print outdict - for link_name, node in six.iteritems(outdict): - self.out(link_name, node) -''' -if __name__ == "__main__": - import argparse - - parser = argparse.ArgumentParser(description='SCF with FLEUR. workflow to' - ' converge the chargedensity and optional the total energy.') - parser.add_argument('--wf_para', type=Dict, dest='wf_parameters', - help='The pseudopotential family', required=False) - parser.add_argument('--structure', type=StructureData, dest='structure', - help='The crystal structure node', required=False) - parser.add_argument('--calc_para', type=Dict, dest='calc_parameters', - help='Parameters for the FLEUR calculation', required=False) - parser.add_argument('--fleurinp', type=FleurinpData, dest='fleurinp', - help='FleurinpData from which to run the FLEUR calculation', required=False) - parser.add_argument('--remote', type=RemoteData, dest='remote_data', - help=('Remote Data of older FLEUR calculation, ' - 'from which files will be copied (mixing_history ...)'), required=False) - parser.add_argument('--inpgen', type=Code, dest='inpgen', - help='The inpgen code node to use', required=False) - parser.add_argument('--fleur', type=Code, dest='fleur', - help='The FLEUR code node to use', required=True) - - args = parser.parse_args() - res = fleur_scf_wc.run(wf_parameters=args.wf_parameters, - structure=args.structure, - calc_parameters=args.calc_parameters, - fleurinp=args.fleurinp, - remote_data=args.remote_data, - inpgen = args.inpgen, - fleur=args.fleur) -''' -@wf -def create_delta_result_node(**kwargs):#*args): - """ - This is a pseudo wf, to create the rigth graph structure of AiiDA. - This wokfunction will create the output node in the database. - It also connects the output_node to all nodes the information commes from. - So far it is just also parsed in as argument, because so far we are to lazy - to put most of the code overworked from return_results in here. - - """ - outdict = {} - outpara = kwargs.get('results_node', {}) - outdict['output_delta_wc_para'] = outpara.copy() - # copy, because we rather produce the same node twice then have a circle in the database for now... - #output_para = args[0] - #return {'output_eos_wc_para'} - return outdict - - -def get_paranode(struc, para_nodes): - """ - find out if a parameter node for a structure is in para_nodes - (currently very creedy, but lists are small (100x100) but maybe reduce database accesses) - """ - - suuid = struc.uuid - formula = struc.get_formula() - element = formula.translate(None, digits) - #print para_nodes - for para in para_nodes: - struc_uuid = para.get_extra('struc_uuid', None) - para_form = para.get_extra('formula', None) - para_ele = para.get_extra('element', None) - if suuid == struc_uuid: - return para - elif formula == para_form: - return para - elif element == para_ele: - return para - elif element == para_form: - return para - else: - pass - #Do something else (test if parameters for a certain element are there) - #.... - # we found no parameter node for the given structure therefore return none - return None - -def write_delta_file(result_dict): - pass diff --git a/aiida_fleur/workflows/dmi.py b/aiida_fleur/workflows/dmi.py index 4dc7d1448..9a98361a1 100644 --- a/aiida_fleur/workflows/dmi.py +++ b/aiida_fleur/workflows/dmi.py @@ -35,7 +35,7 @@ from aiida_fleur.workflows.scf import FleurScfWorkChain from aiida_fleur.data.fleurinpmodifier import FleurinpModifier from aiida_fleur.workflows.base_fleur import FleurBaseWorkChain - +from aiida_fleur.common.constants import HTR_TO_EV from aiida_fleur.data.fleurinp import FleurinpData @@ -58,7 +58,7 @@ class FleurDMIWorkChain(WorkChain): 'environment_variables': {} } - _wf_default = { + _default_wf_para = { 'serial': False, 'only_even_MPI': False, 'beta': { @@ -75,7 +75,7 @@ class FleurDMIWorkChain(WorkChain): @classmethod def define(cls, spec): - super(FleurDMIWorkChain, cls).define(spec) + super().define(spec) spec.expose_inputs(FleurScfWorkChain, namespace='scf') spec.input('wf_parameters', valid_type=Dict, required=False) spec.input('fleur', valid_type=Code, required=True) @@ -124,7 +124,7 @@ def start(self): self.ctx.q_vectors = [] # initialize the dictionary using defaults if no wf paramters are given - wf_default = copy.deepcopy(self._wf_default) + wf_default = copy.deepcopy(self._default_wf_para) if 'wf_parameters' in self.inputs: wf_dict = self.inputs.wf_parameters.get_dict() else: @@ -493,7 +493,6 @@ def get_results(self): """ Generates results of the workchain. """ - htr_to_ev = 27.21138602 t_energydict = [] mae_thetas = [] mae_phis = [] @@ -531,7 +530,7 @@ def get_results(self): if e_u == 'Htr' or 'htr': for labels, energies in t_energydict.items(): - t_energydict[labels] = energies * htr_to_ev + t_energydict[labels] = energies * HTR_TO_EV except AttributeError: message = ('Did not manage to read evSum or energy units after FT calculation.') self.control_end_wc(message) diff --git a/aiida_fleur/workflows/dos.py b/aiida_fleur/workflows/dos.py index 88508c749..ce6ee4229 100644 --- a/aiida_fleur/workflows/dos.py +++ b/aiida_fleur/workflows/dos.py @@ -58,11 +58,11 @@ class fleur_dos_wc(WorkChain): @classmethod def define(cls, spec): - super(fleur_dos_wc, cls).define(spec) - spec.input('wf_parameters', valid_type=Dict, required=False, default=Dict(dict=cls._default_wf_para)) + super().define(spec) + spec.input('wf_parameters', valid_type=Dict, required=False, default=lambda: Dict(dict=cls._default_wf_para)) spec.input('calc_parameters', valid_type=Dict, required=False) spec.input('settings', valid_type=Dict, required=False) - spec.input('options', valid_type=Dict, required=False, default=Dict(dict=cls._default_options)) + spec.input('options', valid_type=Dict, required=False, default=lambda: Dict(dict=cls._default_options)) spec.input('fleurinp', valid_type=FleurinpData, required=False) # TODO ggf run convergence first spec.input('remote_data', valid_type=RemoteData, required=False) diff --git a/aiida_fleur/workflows/eos.py b/aiida_fleur/workflows/eos.py index fa97dbfe0..0a47eba02 100644 --- a/aiida_fleur/workflows/eos.py +++ b/aiida_fleur/workflows/eos.py @@ -32,6 +32,7 @@ from aiida_fleur.tools.StructureData_util import rescale, rescale_nowf, is_structure from aiida_fleur.workflows.scf import FleurScfWorkChain from aiida_fleur.tools.common_fleur_wf_util import check_eos_energies +from aiida_fleur.common.constants import HTR_TO_EV class FleurEosWorkChain(WorkChain): @@ -54,11 +55,12 @@ class FleurEosWorkChain(WorkChain): _workflowversion = '0.4.0' - _wf_default = {'points': 9, 'step': 0.002, 'guess': 1.00} + _default_wf_para = {'points': 9, 'step': 0.002, 'guess': 1.00} + _default_options = FleurScfWorkChain._default_options @classmethod def define(cls, spec): - super(FleurEosWorkChain, cls).define(spec) + super().define(spec) spec.expose_inputs(FleurScfWorkChain, namespace='scf', exclude=( 'structure', 'remote_data', @@ -100,7 +102,7 @@ def start(self): # TODO get all successful from convergence, if all True this # initialize the dictionary using defaults if no wf paramters are given - wf_default = self._wf_default + wf_default = self._default_wf_para if 'wf_parameters' in self.inputs: wf_dict = self.inputs.wf_parameters.get_dict() else: @@ -190,7 +192,6 @@ def return_results(self): vol_peratom_success = [] outnodedict = {} natoms = len(self.inputs.structure.sites) - htr_to_ev = 27.21138602 e_u = 'eV' dis_u = 'me/bohr^3' for label in self.ctx.labels: @@ -220,7 +221,7 @@ def return_results(self): t_e = outpara.get('total_energy', float('nan')) e_u = outpara.get('total_energy_units', 'eV') if e_u == 'Htr' or 'htr': - t_e = t_e * htr_to_ev + t_e = t_e * HTR_TO_EV dis = outpara.get('distance_charge', float('nan')) dis_u = outpara.get('distance_charge_units', 'me/bohr^3') t_energylist.append(t_e) diff --git a/aiida_fleur/workflows/initial_cls.py b/aiida_fleur/workflows/initial_cls.py index 6a69161a9..b6c373da5 100644 --- a/aiida_fleur/workflows/initial_cls.py +++ b/aiida_fleur/workflows/initial_cls.py @@ -107,8 +107,8 @@ class fleur_initial_cls_wc(WorkChain): @classmethod def define(cls, spec): - super(fleur_initial_cls_wc, cls).define(spec) - spec.input('wf_parameters', valid_type=Dict, required=False, default=Dict(dict=cls._default_wf_para)) + super().define(spec) + spec.input('wf_parameters', valid_type=Dict, required=False, default=lambda: Dict(dict=cls._default_wf_para)) spec.input('fleurinp', valid_type=FleurinpData, required=False) spec.input('fleur', valid_type=Code, required=True) spec.input('inpgen', valid_type=Code, required=False) @@ -163,6 +163,7 @@ def check_input(self): self.ctx.bandgaps = {} self.ctx.atomtypes = {} # set values, or defaults for Wf_para + # 'wf_parameters' always there wf_dict = self.inputs.wf_parameters.get_dict() default = self._default_wf_para @@ -174,7 +175,7 @@ def check_input(self): self.ctx.relax_para = wf_dict.get('relax_para', default.get('dos_para')) defaultoptions = self._default_options - if self.inputs.options: + if 'options' in self.inputs: options = self.inputs.options.get_dict() else: options = defaultoptions @@ -774,34 +775,47 @@ def return_results(self): if self.ctx.errors: self.ctx.warnings.append(self.ctx.errors) + material = list(efermi.keys()) + if material: + material = material[0] + fermi_energy = list(efermi.values()) + if fermi_energy: + fermi_energy = fermi_energy[0] + total_energy = list(tE.values()) + if total_energy: + total_energy = total_energy[0] + bandgap = list(gap.values()) + if bandgap: + bandgap = bandgap[0] + outputnode_dict = {} outputnode_dict['workflow_name'] = self.__class__.__name__ outputnode_dict['workflow_version'] = self._workflowversion outputnode_dict['warnings'] = self.ctx.warnings outputnode_dict['successful'] = self.ctx.successful - outputnode_dict['material'] = list(efermi.keys())[0] + outputnode_dict['material'] = material outputnode_dict['corelevel_energies'] = cl outputnode_dict['corelevel_energies_units'] = 'htr' #'eV' outputnode_dict['reference_corelevel_energies'] = ref_cl outputnode_dict['reference_corelevel_energies_units'] = 'htr' #'eV' outputnode_dict['reference_fermi_energy'] = list(ref_efermi.values()) outputnode_dict['reference_fermi_energy_des'] = list(ref_efermi.keys()) - outputnode_dict['fermi_energy'] = list(efermi.values())[0] + outputnode_dict['fermi_energy'] = efermi outputnode_dict['fermi_energy_units'] = 'htr' outputnode_dict['corelevelshifts'] = cls outputnode_dict['corelevelshifts_units'] = 'htr' outputnode_dict['binding_energy_convention'] = 'negativ' #outputnode_dict['coresetup'] = []#cls #outputnode_dict['reference_coresetup'] = []#cls - outputnode_dict['bandgap'] = list(gap.values())[0] + outputnode_dict['bandgap'] = bandgap outputnode_dict['bandgap_units'] = 'htr' outputnode_dict['reference_bandgaps'] = list(ref_gap.values()) outputnode_dict['reference_bandgaps_des'] = list(ref_gap.keys()) outputnode_dict['atomtypes'] = at outputnode_dict['formation_energy'] = formE outputnode_dict['formation_energy_units'] = 'eV/atom' - outputnode_dict['total_energy'] = list(tE.values())[0] + outputnode_dict['total_energy'] = total_energy outputnode_dict['total_energy_units'] = 'eV' outputnode_dict['total_energy_ref'] = list(tE_ref.values()) outputnode_dict['total_energy_ref_des'] = list(tE_ref.keys()) @@ -926,12 +940,14 @@ def extract_results(calcs): for calc in calcs: #print(calc) try: - calc_uuids.append(calc.get_outgoing().get_node_by_label('output_scf_wc_para').get_dict()['last_calc_uuid']) + calc_uuid = calc.get_outgoing().get_node_by_label('output_scf_wc_para').get_dict()['last_calc_uuid'] except (NotExistent, MultipleObjectsError, ValueError, TypeError, KeyError): #TODO which error logmsg = ('ERROR: No output_scf_wc_para node found or no "last_calc_uuid" ' 'key in it for calculation: {}'.format(calc)) log.append(logmsg) continue + if calc_uuid is not None: + calc_uuids.append(calc_uuid) #calc_uuids.append(calc['output_scf_wc_para'].get_dict()['last_calc_uuid']) all_corelevels = {} diff --git a/aiida_fleur/workflows/mae.py b/aiida_fleur/workflows/mae.py index e73c96f65..befb8ba6f 100644 --- a/aiida_fleur/workflows/mae.py +++ b/aiida_fleur/workflows/mae.py @@ -33,6 +33,7 @@ from aiida_fleur.workflows.base_fleur import FleurBaseWorkChain from aiida_fleur.data.fleurinpmodifier import FleurinpModifier from aiida_fleur.data.fleurinp import FleurinpData +from aiida_fleur.common.constants import HTR_TO_EV class FleurMaeWorkChain(WorkChain): @@ -54,7 +55,7 @@ class FleurMaeWorkChain(WorkChain): 'environment_variables': {} } - _wf_default = { + _default_wf_para = { 'sqa_ref': [0.7, 0.7], 'use_soc_ref': False, 'sqas_theta': [0.0, 1.57079, 1.57079], @@ -67,7 +68,7 @@ class FleurMaeWorkChain(WorkChain): @classmethod def define(cls, spec): - super(FleurMaeWorkChain, cls).define(spec) + super().define(spec) spec.expose_inputs(FleurScfWorkChain, namespace='scf') spec.input('wf_parameters', valid_type=Dict, required=False) spec.input('fleur', valid_type=Code, required=True) @@ -115,7 +116,7 @@ def start(self): self.ctx.fleuroutuuid = None # initialize the dictionary using defaults if no wf paramters are given - wf_default = copy.deepcopy(self._wf_default) + wf_default = copy.deepcopy(self._default_wf_para) if 'wf_parameters' in self.inputs: wf_dict = self.inputs.wf_parameters.get_dict() else: @@ -449,7 +450,6 @@ def get_results(self): t_energydict = [] mae_thetas = [] mae_phis = [] - htr_to_ev = 27.21138602 fleur_output_uuid = None try: @@ -476,7 +476,7 @@ def get_results(self): minenergy = min(t_energydict) if e_u == 'Htr' or 'htr': - t_energydict = [htr_to_ev * (x - minenergy) for x in t_energydict] + t_energydict = [HTR_TO_EV * (x - minenergy) for x in t_energydict] else: t_energydict = [(x - minenergy) for x in t_energydict] diff --git a/aiida_fleur/workflows/mae_conv.py b/aiida_fleur/workflows/mae_conv.py index 6304b952d..220a6bb75 100644 --- a/aiida_fleur/workflows/mae_conv.py +++ b/aiida_fleur/workflows/mae_conv.py @@ -24,6 +24,7 @@ from aiida.common import AttributeDict from aiida_fleur.workflows.scf import FleurScfWorkChain +from aiida_fleur.common.constants import HTR_TO_EV class FleurMaeConvWorkChain(WorkChain): @@ -33,11 +34,22 @@ class FleurMaeConvWorkChain(WorkChain): _workflowversion = '0.2.0' - _wf_default = {'sqas': {'label': [0.0, 0.0]}, 'soc_off': []} + _default_wf_para = {'sqas': {'label': [0.0, 0.0]}, 'soc_off': []} + _default_options = { + 'resources': { + 'num_machines': 1, + 'num_mpiprocs_per_machine': 1 + }, + 'max_wallclock_seconds': 6 * 60 * 60, + 'queue_name': '', + 'custom_scheduler_commands': '', + 'import_sys_environment': False, + 'environment_variables': {} + } @classmethod def define(cls, spec): - super(FleurMaeConvWorkChain, cls).define(spec) + super().define(spec) spec.expose_inputs(FleurScfWorkChain, namespace='scf') spec.input('wf_parameters', valid_type=Dict, required=False) @@ -67,7 +79,7 @@ def start(self): self.ctx.mae_phis = [] # initialize the dictionary using defaults if no wf paramters are given - wf_default = copy.deepcopy(self._wf_default) + wf_default = copy.deepcopy(self._default_wf_para) if 'wf_parameters' in self.inputs: wf_dict = self.inputs.wf_parameters.get_dict() else: @@ -146,7 +158,6 @@ def get_results(self): t_energydict = {} original_t_energydict = {} outnodedict = {} - htr_to_ev = 27.21138602 for label in six.iterkeys(self.ctx.wf_dict['sqas']): calc = self.ctx[label] @@ -172,7 +183,7 @@ def get_results(self): continue e_u = outpara.get('total_energy_units', 'Htr') if e_u == 'Htr' or 'htr': - t_e = t_e * htr_to_ev + t_e = t_e * HTR_TO_EV t_energydict[label] = t_e if t_energydict: diff --git a/aiida_fleur/workflows/optimize_para.py b/aiida_fleur/workflows/optimize_para.py index 901bd7b42..c6c5a2032 100644 --- a/aiida_fleur/workflows/optimize_para.py +++ b/aiida_fleur/workflows/optimize_para.py @@ -50,17 +50,19 @@ class fleur_optimize_parameters_wc(WorkChain): _workflowversion = '0.1.0' + _default_wf_para = {} + def __init__(self, *args, **kwargs): - super(fleur_optimize_parameters_wc, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) @classmethod def define(cls, spec): - super(fleur_optimize_parameters_wc, cls).define(spec) + super().define(spec) spec.input( 'wf_parameters', valid_type=Dict, required=False, - default=Dict( + default=lambda: Dict( dict={ 'resources': { 'num_machines': 1 diff --git a/aiida_fleur/workflows/relax.py b/aiida_fleur/workflows/relax.py index ea81d67ec..1cdd36bb6 100644 --- a/aiida_fleur/workflows/relax.py +++ b/aiida_fleur/workflows/relax.py @@ -27,7 +27,7 @@ from aiida_fleur.workflows.scf import FleurScfWorkChain from aiida_fleur.calculation.fleur import FleurCalculation as FleurCalc -from aiida_fleur.common.constants import bohr_a +from aiida_fleur.common.constants import BOHR_A from aiida_fleur.tools.StructureData_util import break_symmetry_wf @@ -36,21 +36,25 @@ class FleurRelaxWorkChain(WorkChain): This workflow performs structure optimization. """ - _workflowversion = '0.2.2' + _workflowversion = '0.3.0' - _wf_default = { + _default_wf_para = { 'relax_iter': 5, # Stop if not converged after so many relaxation steps 'film_distance_relaxation': False, # Do not relax the z coordinates 'force_criterion': 0.001, # Converge the force until lower this value in atomic units 'run_final_scf': False, # Run a final scf on the final relaxed structure 'break_symmetry': False, # Break the symmetry for the relaxation each atom own type 'change_mixing_criterion': 0.025, # After the force is smaller switch mixing scheme - 'atoms_off': [] # Species to be switched off, '49' is reserved + 'atoms_off': [], # Species to be switched off, '49' is reserved + 'relaxation_type': 'atoms' # others include None and maybe in the future volume + # None would run an scf only } + _default_options = FleurScfWorkChain._default_options + @classmethod def define(cls, spec): - super(FleurRelaxWorkChain, cls).define(spec) + super().define(spec) spec.expose_inputs(FleurScfWorkChain, namespace='scf') spec.expose_inputs(FleurScfWorkChain, namespace='final_scf', @@ -62,13 +66,11 @@ def define(cls, spec): spec.outline( cls.start, - cls.converge_scf, - cls.check_failure, - while_(cls.condition)( + if_(cls.should_relax)(cls.converge_scf, cls.check_failure, while_(cls.condition)( cls.generate_new_fleurinp, cls.converge_scf, cls.check_failure, - ), + )), cls.get_results_relax, if_(cls.should_run_final_scf)(cls.run_final_scf, cls.get_results_final_scf), cls.return_results, @@ -111,9 +113,10 @@ def start(self): self.ctx.switch_bfgs = False # Bool if BFGS should be switched on self.ctx.scf_res = None # Last scf results self.ctx.final_structure = None # The optimized structure + self.ctx.total_magnetic_moment = None # initialize the dictionary using defaults if no wf paramters are given - wf_default = copy.deepcopy(self._wf_default) + wf_default = copy.deepcopy(self._default_wf_para) if 'wf_parameters' in self.inputs: wf_dict = self.inputs.wf_parameters.get_dict() else: @@ -166,6 +169,19 @@ def start(self): self.report('Error: Wrong input: inpgen missing for final scf.') return self.exit_codes.ERROR_INPGEN_MISSING + def should_relax(self): + """ + Should we run a relaxation or only a final scf + This allows to call the workchain to run an scf only and makes + logic of other higher workflows a lot easier + """ + relaxtype = self.ctx.wf_dict.get('relaxation_type', 'atoms') + if relaxtype is None: + self.ctx.reached_relax = True + return False + else: + return True + def converge_scf(self): """ Submits :class:`aiida_fleur.workflows.scf.FleurScfWorkChain`. @@ -433,6 +449,24 @@ def get_results_relax(self): Creates a new structure data node which is an optimized structure. """ + + if self.ctx.wf_dict.get('relaxation_type', 'atoms') is None: + input_scf = AttributeDict(self.exposed_inputs(FleurScfWorkChain, namespace='scf')) + if 'structure' in input_scf: + structure = input_scf.structure + elif 'fleurinp' in input_scf: + structure = input_scf.fleurinp.get_structuredata_ncf() + else: + pass + self.ctx.final_structure = structure + self.ctx.total_energy_last = None #total_energy + self.ctx.total_energy_units = None #total_energy_units + self.ctx.final_cell = structure.cell + self.ctx.final_atom_positions = None #atom_positions + self.ctx.atomtype_info = None + + return + try: relax_out = self.ctx.scf_res.outputs.last_fleur_calc_output except NotExistent: @@ -446,6 +480,7 @@ def get_results_relax(self): film = relax_out['film'] total_energy = relax_out['energy'] total_energy_units = relax_out['energy_units'] + atomtype_info = relax_out['relax_atomtype_info'] except KeyError: return self.exit_codes.ERROR_NO_RELAX_OUTPUT @@ -453,6 +488,7 @@ def get_results_relax(self): self.ctx.total_energy_units = total_energy_units self.ctx.final_cell = cell self.ctx.final_atom_positions = atom_positions + self.ctx.atomtype_info = atomtype_info if film == 'True': self.ctx.pbc = (True, True, False) @@ -460,17 +496,24 @@ def get_results_relax(self): self.ctx.pbc = (True, True, True) # we build the structure here, that way we can run an scf afterwards + # construct it in a way which preserves the species information from the initial input structure if self.ctx.final_cell: - np_cell = np.array(self.ctx.final_cell) * bohr_a + np_cell = np.array(self.ctx.final_cell) * BOHR_A structure = StructureData(cell=np_cell.tolist()) - - for atom in self.ctx.final_atom_positions: - np_pos = np.array(atom[1:]) + #self.report('############ {}'.format(atomtype_info)) + for i, atom in enumerate(self.ctx.final_atom_positions): + species_name = atomtype_info[i][0] + element = atomtype_info[i][1] + np_pos = np.array(atom) pos_abs = np_pos @ np_cell if self.ctx.pbc == (True, True, True): - structure.append_atom(position=(pos_abs[0], pos_abs[1], pos_abs[2]), symbols=atom[0]) + structure.append_atom(position=(pos_abs[0], pos_abs[1], pos_abs[2]), + symbols=element, + name=species_name) else: # assume z-direction is orthogonal to xy - structure.append_atom(position=(pos_abs[0], pos_abs[1], atom[3] * bohr_a), symbols=atom[0]) + structure.append_atom(position=(pos_abs[0], pos_abs[1], atom[3] * BOHR_A), + symbols=element, + name=species_name) structure.pbc = self.ctx.pbc self.ctx.final_structure = structure @@ -496,6 +539,17 @@ def get_results_final_scf(self): self.ctx.total_energy_last = total_energy self.ctx.total_energy_units = total_energy_units + if self.ctx.wf_dict.get('relaxation_type', 'atoms') is None: + # we need this for run through + self.ctx.scf_res = self.ctx.scf_final_res + + #if jspin ==2 + try: + total_mag = scf_out_d['total_magnetic_moment_cell'] + self.ctx.total_magnetic_moment = total_mag + except KeyError: + self.report('ERROR: Could not parse total magnetic moment cell of final scf run') + def return_results(self): """ This function stores results of the workchain into the output nodes. @@ -514,7 +568,9 @@ def return_results(self): 'force_iter_done': self.ctx.loop_count, # uuids in the output are bad for caching should be avoided, # instead better return the node. - 'last_scf_wc_uuid': self.ctx.scf_res.uuid + 'last_scf_wc_uuid': self.ctx.scf_res.uuid, + 'total_magnetic_moment_cell': self.ctx.total_magnetic_moment, + 'total_magnetic_moment_cell_units': 'muBohr' } outnode = Dict(dict=out) diff --git a/aiida_fleur/workflows/scf.py b/aiida_fleur/workflows/scf.py index 70e0d4d2c..f48eebd09 100644 --- a/aiida_fleur/workflows/scf.py +++ b/aiida_fleur/workflows/scf.py @@ -60,8 +60,8 @@ class FleurScfWorkChain(WorkChain): like Success, last result node, list with convergence behavior """ - _workflowversion = '0.4.2' - _wf_default = { + _workflowversion = '0.4.3' + _default_wf_para = { 'fleur_runmax': 4, 'density_converged': 0.00002, 'energy_converged': 0.002, @@ -97,7 +97,7 @@ class FleurScfWorkChain(WorkChain): @classmethod def define(cls, spec): - super(FleurScfWorkChain, cls).define(spec) + super().define(spec) spec.input('fleur', valid_type=Code, required=True) spec.input('inpgen', valid_type=Code, required=False) spec.input('wf_parameters', valid_type=Dict, required=False) @@ -107,7 +107,7 @@ def define(cls, spec): spec.input('remote_data', valid_type=RemoteData, required=False) spec.input('options', valid_type=Dict, required=False) spec.input('settings', valid_type=Dict, required=False) - + spec.input('settings_inpgen', valid_type=Dict, required=False) spec.outline(cls.start, cls.validate_input, if_(cls.fleurinpgen_needed)(cls.run_fleurinpgen), cls.run_fleur, cls.inspect_fleur, cls.get_res, while_(cls.condition)(cls.run_fleur, cls.inspect_fleur, cls.get_res), cls.return_results) @@ -144,7 +144,7 @@ def start(self): self.ctx.abort = False self.ctx.reached_conv = True - wf_default = self._wf_default + wf_default = self._default_wf_para if 'wf_parameters' in self.inputs: wf_dict = self.inputs.wf_parameters.get_dict() else: @@ -155,12 +155,33 @@ def start(self): self.ctx.wf_dict = wf_dict self.ctx.serial = self.ctx.wf_dict.get('serial', False) + fleur = self.inputs.fleur + fleur_extras = fleur.extras + inpgen_extras = None + if 'inpgen' in self.inputs: + inpgen = self.inputs.inpgen + inpgen_extras = inpgen.extras + + defaultoptions = self._default_options.copy() + user_options = {} + if 'options' in self.inputs: + user_options = self.inputs.options.get_dict() + + # extend options by code defaults given in code extras + # Maybe do full recursive merge + if 'queue_defaults' in fleur_extras: + qd = fleur_extras['queue_defaults'] + queue = user_options.get('queue', 'default') + defaults_queue = qd.get(queue, {}) + for key, val in defaultoptions.items(): + defaultoptions[key] = defaults_queue.get(key, val) - defaultoptions = self._default_options if 'options' in self.inputs: - options = self.inputs.options.get_dict() + options = user_options else: options = defaultoptions + # we use the same options for both codes, inpgen resources get overridden + # and queue does not matter in case of direct scheduler # extend options given by user using defaults for key, val in six.iteritems(defaultoptions): @@ -201,7 +222,7 @@ def validate_input(self): """ extra_keys = [] for key in self.ctx.wf_dict.keys(): - if key not in self._wf_default.keys(): + if key not in self._default_wf_para.keys(): extra_keys.append(key) if extra_keys: error = 'ERROR: input wf_parameters for SCF contains extra keys: {}'.format(extra_keys) @@ -304,6 +325,11 @@ def run_fleurinpgen(self): else: params = None + if 'settings_inpgen' in self.inputs: + settings = self.inputs.settings_inpgen + else: + settings = None + # If given kpt_dist has prio over given calc_parameters kpt_dist = self.ctx.wf_dict.get('kpoints_distance', None) if kpt_dist is not None: @@ -330,7 +356,13 @@ def run_fleurinpgen(self): 'queue_name': self.ctx.options.get('queue_name', '') } - inputs_build = get_inputs_inpgen(structure, inpgencode, options, label, description, params=params) + inputs_build = get_inputs_inpgen(structure, + inpgencode, + options, + label, + description, + settings=settings, + params=params) # Launch inpgen self.report('INFO: run inpgen') diff --git a/aiida_fleur/workflows/ssdisp.py b/aiida_fleur/workflows/ssdisp.py index a5ec7fd46..9decd146e 100644 --- a/aiida_fleur/workflows/ssdisp.py +++ b/aiida_fleur/workflows/ssdisp.py @@ -33,7 +33,7 @@ from aiida_fleur.workflows.scf import FleurScfWorkChain from aiida_fleur.data.fleurinpmodifier import FleurinpModifier from aiida_fleur.workflows.base_fleur import FleurBaseWorkChain - +from aiida_fleur.common.constants import HTR_TO_EV from aiida_fleur.data.fleurinp import FleurinpData @@ -56,7 +56,7 @@ class FleurSSDispWorkChain(WorkChain): 'environment_variables': {} } - _wf_default = { + _default_wf_para = { 'beta': { 'all': 1.57079 }, @@ -70,7 +70,7 @@ class FleurSSDispWorkChain(WorkChain): @classmethod def define(cls, spec): - super(FleurSSDispWorkChain, cls).define(spec) + super().define(spec) spec.expose_inputs(FleurScfWorkChain, namespace='scf') spec.input('wf_parameters', valid_type=Dict, required=False) spec.input('fleur', valid_type=Code, required=True) @@ -113,7 +113,7 @@ def start(self): self.ctx.energy_dict = [] # initialize the dictionary using defaults if no wf paramters are given - wf_default = copy.deepcopy(self._wf_default) + wf_default = copy.deepcopy(self._default_wf_para) if 'wf_parameters' in self.inputs: wf_dict = self.inputs.wf_parameters.get_dict() else: @@ -454,7 +454,6 @@ def get_results(self): Generates results of the workchain. """ t_energydict = [] - htr_to_ev = 27.21138602 try: calculation = self.ctx.f_t if not calculation.is_finished_ok: @@ -476,7 +475,7 @@ def get_results(self): minenergy = min(t_energydict) if e_u == 'Htr' or 'htr': - t_energydict = [htr_to_ev * (x - minenergy) for x in t_energydict] + t_energydict = [HTR_TO_EV * (x - minenergy) for x in t_energydict] else: t_energydict = [(x - minenergy) for x in t_energydict] diff --git a/aiida_fleur/workflows/ssdisp_conv.py b/aiida_fleur/workflows/ssdisp_conv.py index 7efab8441..889ea388f 100644 --- a/aiida_fleur/workflows/ssdisp_conv.py +++ b/aiida_fleur/workflows/ssdisp_conv.py @@ -33,7 +33,7 @@ class FleurSSDispConvWorkChain(WorkChain): _workflowversion = '0.2.0' - _wf_default = { + _default_wf_para = { 'beta': { 'all': 1.57079 }, @@ -46,7 +46,7 @@ class FleurSSDispConvWorkChain(WorkChain): @classmethod def define(cls, spec): - super(FleurSSDispConvWorkChain, cls).define(spec) + super().define(spec) spec.expose_inputs(FleurScfWorkChain, namespace='scf') spec.input('wf_parameters', valid_type=Dict, required=False) @@ -76,7 +76,7 @@ def start(self): self.ctx.energy_dict = [] # initialize the dictionary using defaults if no wf paramters are given - wf_default = copy.deepcopy(self._wf_default) + wf_default = copy.deepcopy(self._default_wf_para) if 'wf_parameters' in self.inputs: wf_dict = self.inputs.wf_parameters.get_dict() else: diff --git a/docs/source/module_guide/code.rst b/docs/source/module_guide/code.rst index 0d2c27519..cc1d9e841 100644 --- a/docs/source/module_guide/code.rst +++ b/docs/source/module_guide/code.rst @@ -59,10 +59,10 @@ SCF: Fleur-Scf WorkChain .. automodule:: aiida_fleur.workflows.scf :members: -Band: Bandstructure WorkChain ------------------------------- +BandDos: Bandstructure WorkChain +-------------------------------- -.. automodule:: aiida_fleur.workflows.band +.. automodule:: aiida_fleur.workflows.banddos :members: DOS: Density of states WorkChain @@ -95,12 +95,6 @@ corehole: Performance of coreholes calculations .. automodule:: aiida_fleur.workflows.corehole :members: -delta: Calculates a Delta Factor --------------------------------- - -.. automodule:: aiida_fleur.workflows.delta - :members: - MAE: Force-theorem calculation of magnetic anisotropy energies ---------------------------------------------------------------- diff --git a/docs/source/user_guide/data/fleurinp_data.rst b/docs/source/user_guide/data/fleurinp_data.rst index ac5a8fdaf..5a17e4271 100644 --- a/docs/source/user_guide/data/fleurinp_data.rst +++ b/docs/source/user_guide/data/fleurinp_data.rst @@ -111,11 +111,10 @@ User Methods * :py:func:`~aiida_fleur.data.fleurinp.FleurinpData.get_parameterdata()` - A CalcFunction that extracts a :py:class:`~aiida.orm.Dict` node containing FLAPW parameters. This node can be used as an input for inpgen. - * :py:func:`~aiida_fleur.data.fleurinp.FleurinpData.set_kpointsdata()` - - A CalcFunction that writes kpoints - of a :py:class:`~aiida.orm.KpointsData` node in the - inp.xml file returns a new - :py:class:`~aiida_fleur.data.fleurinp.FleurinpData` instance. It replaces old kpoints. + * :py:func:`~aiida_fleur.data.fleurinpmodifier.set_kpointsdata_f()` - + A Function of fleurmodifier used to writes kpoints + of a :py:class:`~aiida.orm.KpointsData` node to the + inp.xml file. It replaces old kpoints. .. _setting_labels: diff --git a/docs/source/user_guide/workflows/dos_band_wc.rst b/docs/source/user_guide/workflows/dos_band_wc.rst index 290d85573..9aee76c80 100644 --- a/docs/source/user_guide/workflows/dos_band_wc.rst +++ b/docs/source/user_guide/workflows/dos_band_wc.rst @@ -9,8 +9,8 @@ Fleur dos/band workflows These are two seperate workflows which are pretty similar so we treat them here together -* **Class**: :py:class:`~aiida_fleur.workflows.dos.fleur_dos_wc` and :py:class:`~aiida_fleur.workflows.band.FleurBandWorkChain` -* **String to pass to the** :py:func:`~aiida.plugins.WorkflowFactory`: ``fleur.dos``, ``fleur.band`` +* **Class**: :py:class:`~aiida_fleur.workflows.dos.fleur_dos_wc` and :py:class:`~aiida_fleur.workflows.banddos.FleurBandDosWorkChain` +* **String to pass to the** :py:func:`~aiida.plugins.WorkflowFactory`: ``fleur.dos``, ``fleur.banddos`` * **Workflow type**: Workflow (lv 1) * **Aim**: Calculate a density of states. Calculate a Band structure. * **Compuational demand**: 1 ``Fleur Job calculation`` @@ -28,9 +28,9 @@ Import Example: #or WorkflowFactory('fleur.dos') - from aiida_fleur.workflows.band import FleurBandWorkChain + from aiida_fleur.workflows.banddos import FleurBandDosWorkChain #or - WorkflowFactory('fleur.band') + WorkflowFactory('fleur.banddos') Description/Purpose ^^^^^^^^^^^^^^^^^^^ @@ -38,11 +38,11 @@ Description/Purpose Calculates an Density of states (DOS) ontop of a given Fleur calculation (converged or not). - Band: + BandDos: Calculates an electronic band structure ontop of a given Fleur calculation (converged or not). - In the future we plan to add the posibility to converge a calculation before, and choose the kpaths automatic. + In the future we plan to add the possibility to converge a calculation before, and choose the kpaths automatic. This version should be able start simply from a crystal structure. Each of these workflows prepares/chances the Fleur input and manages one Fleur calculation. diff --git a/docs/source/user_guide/workflows/wc_index.rst b/docs/source/user_guide/workflows/wc_index.rst index df1da81f6..54f136214 100644 --- a/docs/source/user_guide/workflows/wc_index.rst +++ b/docs/source/user_guide/workflows/wc_index.rst @@ -10,7 +10,7 @@ Inputs '''''' There is always a ``wf_parameters``: -:py:class:`~aiida.orm.Dict` node for controlling the workflow behaviour. +:py:class:`~aiida.orm.Dict` node for controlling the workflow behavior. It contains all the parameters related to physical aspects of the workchain and its content vary between different workchains. diff --git a/setup.json b/setup.json index 85750bc6a..166e27385 100644 --- a/setup.json +++ b/setup.json @@ -1,5 +1,5 @@ { - "version": "1.1.2", + "version": "1.1.3", "name": "aiida-fleur", "url": "https://github.com/JuDFTteam/aiida-fleur", "license": "MIT License, see LICENSE.txt file.", @@ -30,9 +30,9 @@ "aiida-core>=1.3.0,<2.0.0", "lxml >= 3.6.4", "pytest-cov >= 2.5.0", - "numpy>=1.16.4,<1.18.0", + "numpy>=1.16.4,<1.20.0", "sympy", - "masci-tools==0.3.12-dev4", + "masci-tools>=0.3.12-dev4", "future", "ase", "pymatgen", @@ -50,14 +50,15 @@ ], "pre-commit": [ "pre-commit>=2.6.0", - "yapf==0.30.0", - "pylint==2.5.2" + "yapf~=0.30", + "pylint>=2.5" ], "testing" : [ "pytest>=2.9", "pytest-timeout", "pytest-cov>= 2.5.0", - "pgtest" + "pgtest", + "pytest-regressions>=1.0" ] }, "entry_points": { @@ -76,7 +77,6 @@ "aiida.workflows": [ "fleur.scf = aiida_fleur.workflows.scf:FleurScfWorkChain", "fleur.dos = aiida_fleur.workflows.dos:fleur_dos_wc", - "fleur.band = aiida_fleur.workflows.band:FleurBandWorkChain", "fleur.banddos = aiida_fleur.workflows.banddos:FleurBandDosWorkChain", "fleur.eos = aiida_fleur.workflows.eos:FleurEosWorkChain", "fleur.init_cls = aiida_fleur.workflows.initial_cls:fleur_initial_cls_wc", @@ -90,6 +90,9 @@ "fleur.create_magnetic = aiida_fleur.workflows.create_magnetic_film:FleurCreateMagneticWorkChain", "fleur.base_relax = aiida_fleur.workflows.base_relax:FleurBaseRelaxWorkChain", "fleur.base = aiida_fleur.workflows.base_fleur:FleurBaseWorkChain" + ], + "console_scripts": [ + "aiida-fleur = aiida_fleur.cmdline:cmd_root" ] } } diff --git a/setup.py b/setup.py index 73ebd7f5a..d02ae26aa 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from __future__ import absolute_import from setuptools import setup, find_packages import json @@ -10,4 +9,12 @@ # such that it can be discovered automatically with open('setup.json', 'r') as info: kwargs = json.load(info) - setup(packages=find_packages(exclude='aiida'), **kwargs) + setup( + packages=find_packages(exclude=['tests*']), + # this doesn't work when placed in setup.json (something to do with str type) + package_data={ + '': ['*'], + }, + long_description=open('README.md').read(), + long_description_content_type='text/markdown', + **kwargs) diff --git a/tests/.aiida/config.json b/tests/.aiida/config.json deleted file mode 100644 index d74fb51db..000000000 --- a/tests/.aiida/config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "CONFIG_VERSION": { - "CURRENT": 3, - "OLDEST_COMPATIBLE": 3 - }, - "profiles": {} -} diff --git a/tests/.coveragerc b/tests/.coveragerc deleted file mode 100644 index eb3500f32..000000000 --- a/tests/.coveragerc +++ /dev/null @@ -1,6 +0,0 @@ -[run] -source = aiida_fleur -omit = *test* - -[html] -directory = coverage/html diff --git a/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/JUDFT_WARN_ONLY b/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/JUDFT_WARN_ONLY new file mode 100644 index 000000000..65c71eb10 --- /dev/null +++ b/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/JUDFT_WARN_ONLY @@ -0,0 +1 @@ +/n diff --git a/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/_scheduler-stderr.txt b/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/_scheduler-stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/_scheduler-stdout.txt b/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/_scheduler-stdout.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/inp.xml b/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/inp.xml new file mode 100644 index 000000000..4d34c362a --- /dev/null +++ b/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/inp.xml @@ -0,0 +1,368 @@ + + + + Si, alpha silicon, bulk, delta project + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + 0.437500 0.437500 0.437500 + 0.312500 0.437500 0.437500 + 0.187500 0.437500 0.437500 + 0.062500 0.437500 0.437500 + 0.062500 0.500000 0.500000 + 0.187500 0.562500 0.562500 + 0.312500 0.562500 0.562500 + 0.437500 0.437500 0.562500 + 0.312500 0.312500 0.437500 + 0.187500 0.312500 0.437500 + 0.125000 0.375000 0.437500 + 0.125000 0.437500 0.500000 + 0.187500 0.500000 0.625000 + 0.312500 0.437500 0.687500 + 0.312500 0.437500 0.562500 + 0.250000 0.250000 0.437500 + 0.250000 0.375000 0.437500 + 0.250000 0.437500 0.500000 + 0.250000 0.437500 0.625000 + 0.250000 0.500000 0.687500 + 0.187500 0.437500 0.562500 + 0.375000 0.375000 0.437500 + 0.375000 0.437500 0.500000 + 0.375000 0.437500 0.625000 + 0.250000 0.562500 0.625000 + 0.125000 0.500000 0.562500 + 0.437500 0.500000 0.500000 + 0.375000 0.500000 0.562500 + 0.250000 0.500000 0.562500 + 0.375000 0.375000 0.562500 + 0.250000 0.375000 0.562500 + 0.312500 0.312500 0.562500 + 0.312500 0.312500 0.312500 + 0.187500 0.312500 0.312500 + 0.062500 0.312500 0.312500 + 0.062500 0.375000 0.375000 + 0.187500 0.500000 0.500000 + 0.375000 0.375000 0.687500 + 0.187500 0.187500 0.312500 + 0.125000 0.250000 0.312500 + 0.125000 0.312500 0.375000 + 0.187500 0.375000 0.500000 + 0.312500 0.500000 0.625000 + 0.250000 0.250000 0.312500 + 0.250000 0.312500 0.375000 + 0.250000 0.312500 0.500000 + 0.312500 0.375000 0.625000 + 0.312500 0.375000 0.375000 + 0.312500 0.375000 0.500000 + 0.312500 0.500000 0.500000 + 0.187500 0.187500 0.187500 + 0.062500 0.187500 0.187500 + 0.062500 0.250000 0.250000 + 0.187500 0.375000 0.375000 + 0.125000 0.125000 0.187500 + 0.125000 0.187500 0.250000 + 0.187500 0.250000 0.375000 + 0.187500 0.250000 0.250000 + 0.062500 0.062500 0.062500 + 0.062500 0.125000 0.125000 + + + + + + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 1 1 1 .5000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 1 1 1 .5000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + -1 -1 -1 .5000000000 + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + -1 -1 -1 .5000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 0 1 .0000000000 + 1 0 0 .0000000000 + -1 -1 -1 .5000000000 + + + 0 0 1 .0000000000 + 0 1 0 .0000000000 + -1 -1 -1 .5000000000 + + + 1 1 1 .5000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 1 1 .5000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 1 1 1 .5000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 0 0 1 .0000000000 + -1 -1 -1 .5000000000 + + + 0 1 0 .0000000000 + 0 0 1 .0000000000 + -1 -1 -1 .5000000000 + + + 0 -1 0 .0000000000 + 1 1 1 .5000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + + + 0 1 0 .0000000000 + -1 -1 -1 .5000000000 + 1 0 0 .0000000000 + + + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + + + 1 0 0 .0000000000 + -1 -1 -1 .5000000000 + 0 1 0 .0000000000 + + + 1 1 1 .5000000000 + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + + + 0 0 1 .0000000000 + -1 -1 -1 .5000000000 + 1 0 0 .0000000000 + + + 1 1 1 .5000000000 + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + + + 0 0 1 .0000000000 + -1 -1 -1 .5000000000 + 0 1 0 .0000000000 + + + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + + + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + + + -1 -1 -1 .5000000000 + 0 1 0 .0000000000 + 1 0 0 .0000000000 + + + -1 -1 -1 .5000000000 + 1 0 0 .0000000000 + 0 1 0 .0000000000 + + + 0 0 1 .0000000000 + 0 1 0 .0000000000 + 1 0 0 .0000000000 + + + 1 1 1 .5000000000 + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + + + 1 1 1 .5000000000 + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + + + 0 0 1 .0000000000 + 1 0 0 .0000000000 + 0 1 0 .0000000000 + + + 0 0 -1 .0000000000 + 1 1 1 .5000000000 + -1 0 0 .0000000000 + + + 0 0 -1 .0000000000 + 1 1 1 .5000000000 + 0 -1 0 .0000000000 + + + -1 -1 -1 .5000000000 + 0 0 1 .0000000000 + 1 0 0 .0000000000 + + + -1 -1 -1 .5000000000 + 0 0 1 .0000000000 + 0 1 0 .0000000000 + + + -1 0 0 .0000000000 + 1 1 1 .5000000000 + 0 -1 0 .0000000000 + + + 0 1 0 .0000000000 + 0 0 1 .0000000000 + 1 0 0 .0000000000 + + + 0 -1 0 .0000000000 + 1 1 1 .5000000000 + -1 0 0 .0000000000 + + + 1 0 0 .0000000000 + 0 0 1 .0000000000 + 0 1 0 .0000000000 + + + 1 0 0 .0000000000 + -1 -1 -1 .5000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + -1 -1 -1 .5000000000 + 0 0 1 .0000000000 + + + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + 1 1 1 .5000000000 + + + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + 1 1 1 .5000000000 + + + -1 -1 -1 .5000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + -1 -1 -1 .5000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + 1 1 1 .5000000000 + + + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + 1 1 1 .5000000000 + + + + + .000000000000000 5.167355275200000 5.167355275200000 + 5.167355275200000 .000000000000000 5.167355275200000 + 5.167355275200000 5.167355275200000 .000000000000000 + + + + + + + + + + + + + + + 1.000/8.000 1.000/8.000 1.000/8.000 + -1.000/8.000 -1.000/8.000 -1.000/8.000 + + + + + + + + + + + + + + + + + diff --git a/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/out.error b/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/out.error new file mode 100644 index 000000000..16cc26986 --- /dev/null +++ b/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/out.error @@ -0,0 +1 @@ +_aiidasubmit.sh: line 7: ./local_exe/fleur: No such file or directory diff --git a/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/shell.out b/tests/calculation/data_dir/mock-fleur-88edcca7024f2f2c75ac80044aa80644/shell.out new file mode 100644 index 000000000..e69de29bb diff --git a/tests/calculation/test_inpgen.py b/tests/calculation/test_inpgen.py index 8946ba7aa..e7a27fc40 100644 --- a/tests/calculation/test_inpgen.py +++ b/tests/calculation/test_inpgen.py @@ -54,9 +54,9 @@ def test_fleurinpgen_default_calcinfo(aiida_profile, fixture_sandbox, generate_c input_written = handle.read() aiida_in_text = """A Fleur input generator calculation with aiida\n&input cartesian=F / - 0.000000000 5.130606447 5.130606447 - 5.130606447 0.000000000 5.130606447 - 5.130606447 5.130606447 0.000000000 + 0.000000000 5.130606429 5.130606429 + 5.130606429 0.000000000 5.130606429 + 5.130606429 5.130606429 0.000000000 1.0000000000 1.000000000 1.000000000 1.000000000 @@ -117,9 +117,9 @@ def test_fleurinpgen_with_parameters(aiida_profile, fixture_sandbox, generate_ca input_written = handle.read() aiida_in_text = """A Fleur input generator calculation with aiida\n&input cartesian=F / - 0.000000000 5.130606447 5.130606447 - 5.130606447 0.000000000 5.130606447 - 5.130606447 5.130606447 0.000000000 + 0.000000000 5.130606429 5.130606429 + 5.130606429 0.000000000 5.130606429 + 5.130606429 5.130606429 0.000000000 1.0000000000 1.000000000 1.000000000 1.000000000 diff --git a/tests/cmdline/__init__.py b/tests/cmdline/__init__.py index 713971d59..e69de29bb 100644 --- a/tests/cmdline/__init__.py +++ b/tests/cmdline/__init__.py @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -''' -AiiDA-FLEUR -''' - -__copyright__ = u'Copyright (c), 2015-2017, Forschungszentrum Juelich GmbH, Germany. All rights reserved.' -__license__ = 'MIT license, see LICENSE.txt file.' -__contributors__ = 'Jens Broeder' -__paper__ = '' -__paper_short__ = '' diff --git a/tests/cmdline/conftest.py b/tests/cmdline/conftest.py new file mode 100644 index 000000000..dbf830f8a --- /dev/null +++ b/tests/cmdline/conftest.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +# pylint: disable=redefined-outer-name +"""Fixtures for the command line interface. +Most of these fixtures are taken from the aiida-quantum espresso package since they +are needed to mock commands running aiida process +""" +import pytest + + +def mock_launch_process(*_, **__): + """Mock the :meth:`~aiida_fleur.cmdline.util.utils.launch_process` to be a no-op.""" + return + + +@pytest.fixture +def import_with_migrate(temp_dir): + """Import an aiida export file and migrate it + + We want to be able to run the test with several aiida versions, + therefore imports have to be migrate, but we also do not want to use verdi + """ + # This function has some deep aiida imports which might change in the future + _DEFAULT_IMPORT_KWARGS = {'group': None} + + def _import_with_migrate(filename, tempdir=temp_dir, import_kwargs=None, try_migration=True): + from click import echo + from aiida.tools.importexport import import_data + from aiida.tools.importexport import EXPORT_VERSION, IncompatibleArchiveVersionError + # these are only availbale after aiida >= 1.5.0, maybe rely on verdi import instead + from aiida.tools.importexport import detect_archive_type + from aiida.tools.importexport.archive.migrators import get_migrator + from aiida.tools.importexport.common.config import ExportFileFormat + if import_kwargs is None: + import_kwargs = _DEFAULT_IMPORT_KWARGS + archive_path = filename + + try: + import_data(archive_path, **import_kwargs) + except IncompatibleArchiveVersionError as exception: + #raise ValueError + if try_migration: + echo(f'incompatible version detected for {archive_path}, trying migration') + migrator = get_migrator(detect_archive_type(archive_path))(archive_path) + archive_path = migrator.migrate(EXPORT_VERSION, None, out_compression='none', work_dir=tempdir) + import_data(archive_path, **import_kwargs) + + return _import_with_migrate + + +@pytest.fixture +def struct_file_type(): + """Return instance of ``StructureNodeOrFileParamType``.""" + from aiida_fleur.cmdline.util.types import StructureNodeOrFileParamType + return StructureNodeOrFileParamType() + + +@pytest.fixture +def run_cli_command(): + """Run a `click` command with the given options. + + The call will raise if the command triggered an exception or the exit code returned is non-zero. + """ + + def _run_cli_command(command, options=None, raises=None): + """Run the command and check the result. + + :param command: the command to invoke + :param options: the list of command line options to pass to the command invocation + :param raises: optionally an exception class that is expected to be raised + """ + import traceback + from click.testing import CliRunner + + runner = CliRunner() + result = runner.invoke(command, options or []) + + if raises is not None: + assert result.exception is not None, result.output + assert result.exit_code != 0 + else: + assert result.exception is None, ''.join(traceback.format_exception(*result.exc_info)) + assert result.exit_code == 0, result.output + + result.output_lines = [line.strip() for line in result.output.split('\n') if line.strip()] + + return result + + return _run_cli_command + + +@pytest.fixture +def run_cli_process_launch_command(run_cli_command, monkeypatch): + """Run a process launch command with the given options. + + The call will raise if the command triggered an exception or the exit code returned is non-zero. + + :param command: the command to invoke + :param options: the list of command line options to pass to the command invocation + :param raises: optionally an exception class that is expected to be raised + """ + + def _inner(command, options=None, raises=None): + """Run the command and check the result.""" + from aiida_fleur.cmdline.util import utils + monkeypatch.setattr(utils, 'launch_process', mock_launch_process) + return run_cli_command(command, options, raises) + + return _inner diff --git a/tests/cmdline/data/__init__.py b/tests/cmdline/data/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cmdline/data/test_fleurinp.py b/tests/cmdline/data/test_fleurinp.py new file mode 100644 index 000000000..cefa74d9a --- /dev/null +++ b/tests/cmdline/data/test_fleurinp.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +''' +Module to test all CLI data fleurinp commands. +''' +import os +from aiida.orm import Dict +file_path1 = '../../files/inpxml/FePt/inp.xml' +file_path2 = '../../files/inpxml/Si/inp.xml' + +inpxmlfilefolder = os.path.dirname(os.path.abspath(__file__)) +FEPT_INPXML_FILE = os.path.abspath(os.path.join(inpxmlfilefolder, file_path1)) +SI_INPXML_FILE = os.path.abspath(os.path.join(inpxmlfilefolder, file_path2)) + + +def test_cmd_fleurinp_list(run_cli_command, create_fleurinp): + """Test invoking the data fleurinp list command.""" + from aiida_fleur.cmdline.data.fleurinp import list_fleurinp + + fleurinp = create_fleurinp(FEPT_INPXML_FILE) + fleurinp.store() + options = ['--uuid', '--ctime', '--strucinfo'] + results = run_cli_command(list_fleurinp, options=options) + print(results.output_lines) + assert fleurinp.uuid in results.output + + fleurinp2 = create_fleurinp(SI_INPXML_FILE) + fleurinp2.store() + options = ['--uuid', '--ctime', '--strucinfo', '--raw'] + results = run_cli_command(list_fleurinp, options=options) + assert fleurinp.uuid in results.output + assert fleurinp2.uuid in results.output + + +def test_cmd_fleurinp_cat(run_cli_command, create_fleurinp): + """Test invoking the data fleurinp cat command.""" + from aiida_fleur.cmdline.data.fleurinp import cat_file + + fleurinp = create_fleurinp(FEPT_INPXML_FILE) + fleurinp.store() + options = [fleurinp.uuid] + result = run_cli_command(cat_file, options=options) + # printed contents will also put in line breaks \n which makes comparisson hard. diff --git a/tests/cmdline/data/test_parameters.py b/tests/cmdline/data/test_parameters.py new file mode 100644 index 000000000..aac6ae6b7 --- /dev/null +++ b/tests/cmdline/data/test_parameters.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +''' +Module to test all CLI data parameter commands. +''' +import os +from aiida.orm import Dict +file_path1 = '../../files/inpxml/Si/inp.xml' + +inpxmlfilefolder = os.path.dirname(os.path.abspath(__file__)) +SI_INPXML_FILE = os.path.abspath(os.path.join(inpxmlfilefolder, file_path1)) + + +def test_cmd_param_import(run_cli_command): + """Test invoking the import parameter command in all variants.""" + from shutil import copyfile + from aiida_fleur.cmdline.data.parameters import cmd_param_import + + options = [SI_INPXML_FILE, '--fleurinp'] + run_cli_command(cmd_param_import, options=options) + + options = [SI_INPXML_FILE, '--fleurinp', '--dry-run'] + run_cli_command(cmd_param_import, options=options) + + options = [SI_INPXML_FILE, '--show', '--dry-run'] + run_cli_command(cmd_param_import, options=options) + + dest_path = SI_INPXML_FILE.strip('.xml') + copyfile(SI_INPXML_FILE, dest_path) + options = [dest_path, '--fleurinp', '--dry-run'] + result = run_cli_command(cmd_param_import, options=options, raises=True) + os.remove(dest_path) + assert 'Critical: Error: Currently, we can only extract information from an inp.xml file.' in result.output_lines diff --git a/tests/cmdline/data/test_structure.py b/tests/cmdline/data/test_structure.py new file mode 100644 index 000000000..251998077 --- /dev/null +++ b/tests/cmdline/data/test_structure.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +''' +Module to test all CLI data structure commands. +''' +import os +from aiida.orm import Dict +file_path1 = '../../files/inpxml/FePt/inp.xml' + +inpxmlfilefolder = os.path.dirname(os.path.abspath(__file__)) +FEPT_INPXML_FILE = os.path.abspath(os.path.join(inpxmlfilefolder, file_path1)) + + +def test_import_structure(run_cli_command): + """Test invoking the import structure command in all variants.""" + from shutil import copyfile + from aiida_fleur.cmdline.data.structure import cmd_import + + options = [FEPT_INPXML_FILE, '--fleurinp'] + run_cli_command(cmd_import, options=options) + + options = [FEPT_INPXML_FILE, '--fleurinp', '--dry-run'] + run_cli_command(cmd_import, options=options) + + dest_path = FEPT_INPXML_FILE.strip('.xml') + copyfile(FEPT_INPXML_FILE, dest_path) + options = [dest_path, '--fleurinp', '--dry-run'] + result = run_cli_command(cmd_import, options=options, raises=True) + os.remove(dest_path) + assert 'Critical: Error: Currently, only StructureData from a inp.xml file can be '\ + 'extracted.' in result.output_lines diff --git a/tests/cmdline/launch/__init__.py b/tests/cmdline/launch/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cmdline/launch/test_launch.py b/tests/cmdline/launch/test_launch.py new file mode 100644 index 000000000..583d70f55 --- /dev/null +++ b/tests/cmdline/launch/test_launch.py @@ -0,0 +1,237 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +''' +Module to test all CLI commands to launch for calcjob and workflows of aiida-fleur. + +Comment: while 'launch process' is mocked to do nothing these tests are still quite slow +but execute large parts of the workchain code base. +''' +import os +from aiida.orm import Dict +file_path1 = '../../files/inpxml/FePt/inp.xml' + +inpxmlfilefolder = os.path.dirname(os.path.abspath(__file__)) +FEPT_INPXML_FILE = os.path.abspath(os.path.join(inpxmlfilefolder, file_path1)) + + +def test_launch_inpgen_base(run_cli_process_launch_command, fixture_code): + """Test invoking the inpgen launch command with only required inputs.""" + from aiida_fleur.cmdline.launch import launch_inpgen + + code = fixture_code('fleur.inpgen').store() + options = ['--inpgen', code.uuid] + run_cli_process_launch_command(launch_inpgen, options=options) + + options = ['--inpgen', code.uuid, '--daemon'] + run_cli_process_launch_command(launch_inpgen, options=options) + + +def test_launch_fleur_base(run_cli_process_launch_command, fixture_code, create_fleurinp): + """Test invoking the fleur launch command with only required inputs.""" + from aiida_fleur.cmdline.launch import launch_fleur + + code = fixture_code('fleur.fleur').store() + fleurinp = create_fleurinp(FEPT_INPXML_FILE).store() + + #Calcjob + options = ['--fleur', code.uuid, '-inp', fleurinp.uuid, '--no-launch_base'] + run_cli_process_launch_command(launch_fleur, options=options) + + #Base_fleur + options = ['--fleur', code.uuid, '-inp', fleurinp.uuid] + run_cli_process_launch_command(launch_fleur, options=options) + + +def test_launch_scf_base(run_cli_process_launch_command, fixture_code, create_fleurinp): + """Test invoking the scf workchain launch command with only required inputs.""" + from aiida_fleur.cmdline.launch import launch_scf + + #Path 1 + inpgen = fixture_code('fleur.inpgen').store() + fleur = fixture_code('fleur.fleur').store() + options = ['--inpgen', inpgen.uuid, '--fleur', fleur.uuid] + run_cli_process_launch_command(launch_scf, options=options) + + #Path2 + fleurinp = create_fleurinp(FEPT_INPXML_FILE).store() + options = ['--fleur', fleur.uuid, '-inp', fleurinp.uuid] + run_cli_process_launch_command(launch_scf, options=options) + + +def test_launch_eos_base(run_cli_process_launch_command, fixture_code): + """Test invoking the eos workchain launch command with only required inputs.""" + from aiida_fleur.cmdline.launch import launch_eos + + inpgen = fixture_code('fleur.inpgen').store() + fleur = fixture_code('fleur.fleur').store() + options = ['--inpgen', inpgen.uuid, '--fleur', fleur.uuid] + run_cli_process_launch_command(launch_eos, options=options) + + +def test_launch_relax_base(run_cli_process_launch_command, fixture_code): + """Test invoking the relax workchain launch command with only required inputs.""" + from aiida_fleur.cmdline.launch import launch_relax + + inpgen = fixture_code('fleur.inpgen').store() + fleur = fixture_code('fleur.fleur').store() + options = ['--inpgen', inpgen.uuid, '--fleur', fleur.uuid] + run_cli_process_launch_command(launch_relax, options=options) + + +def test_launch_corehole_base(run_cli_process_launch_command, fixture_code): + """Test invoking the corehole workchain launch command with only required inputs.""" + from aiida_fleur.cmdline.launch import launch_corehole + + inpgen = fixture_code('fleur.inpgen').store() + fleur = fixture_code('fleur.fleur').store() + options = ['--inpgen', inpgen.uuid, '--fleur', fleur.uuid] + run_cli_process_launch_command(launch_corehole, options=options) + + +def test_launch_init_cls_base(run_cli_process_launch_command, fixture_code): + """Test invoking the initial_cls workchain launch command with only required inputs.""" + from aiida_fleur.cmdline.launch import launch_init_cls + + inpgen = fixture_code('fleur.inpgen').store() + fleur = fixture_code('fleur.fleur').store() + options = ['--inpgen', inpgen.uuid, '--fleur', fleur.uuid] + run_cli_process_launch_command(launch_init_cls, options=options) + + +def test_launch_banddos_base(run_cli_process_launch_command, fixture_code, generate_remote_data, create_fleurinp): + """Test invoking the banddow workchain launch command with only required inputs.""" + from aiida_fleur.cmdline.launch import launch_banddos + + inpgen = fixture_code('fleur.inpgen').store() + fleur = fixture_code('fleur.fleur').store() + path = os.path.abspath(os.path.join(inpxmlfilefolder, '../../files/outxml/tmp')) + remote = generate_remote_data(fleur.computer, path).store() + fleurinp = create_fleurinp(FEPT_INPXML_FILE).store() + + options = ['--fleur', fleur.uuid, '-P', remote.uuid, '-inp', fleurinp.uuid] + run_cli_process_launch_command(launch_banddos, options=options) + + +def test_launch_mae_base(run_cli_process_launch_command, fixture_code): + """Test invoking the mae workchain launch command with only required inputs.""" + from aiida_fleur.cmdline.launch import launch_mae + + inpgen = fixture_code('fleur.inpgen').store() + fleur = fixture_code('fleur.fleur').store() + + wf_para = { + 'lattice': 'fcc', + 'miller': [[-1, 1, 0], [0, 0, 1], [1, 1, 0]], + 'host_symbol': 'Pt', + 'latticeconstant': 4.0, + 'size': (1, 1, 5), + 'replacements': { + 0: 'Fe', + -1: 'Fe' + }, + 'decimals': 10, + 'pop_last_layers': 1, + 'total_number_layers': 8, + 'num_relaxed_layers': 3 + } + + wf_para = Dict(dict=wf_para).store() + options = ['--inpgen', inpgen.uuid, '--fleur', fleur.uuid, '-wf', wf_para.uuid] + run_cli_process_launch_command(launch_mae, options=options) + + +def test_launch_create_magnetic_base(run_cli_process_launch_command, fixture_code): + """Test invoking the mae workchain launch command with only required inputs.""" + from aiida_fleur.cmdline.launch import launch_create_magnetic + + inpgen = fixture_code('fleur.inpgen').store() + fleur = fixture_code('fleur.fleur').store() + + wf_para = { + 'sqa_ref': [0.7, 0.7], + 'use_soc_ref': False, + 'sqas_theta': [0.0, 1.57079, 1.57079], + 'sqas_phi': [0.0, 0.0, 1.57079], + 'serial': False, + 'soc_off': [], + 'inpxml_changes': [], + } + + wf_para = Dict(dict=wf_para).store() + + options = ['--inpgen', inpgen.uuid, '--fleur', fleur.uuid, '-wf', wf_para.uuid] + run_cli_process_launch_command(launch_create_magnetic, options=options) + + +def test_launch_dmi_base(run_cli_process_launch_command, fixture_code): + """Test invoking the mae workchain launch command with only required inputs.""" + from aiida_fleur.cmdline.launch import launch_dmi + + inpgen = fixture_code('fleur.inpgen').store() + fleur = fixture_code('fleur.fleur').store() + + wf_para = { + 'serial': False, + 'beta': { + '123': 1.57079 + }, + 'sqas_theta': [0.0, 1.57079, 1.57079], + 'sqas_phi': [0.0, 0.0, 1.57079], + 'soc_off': [], + # 'prop_dir': [0.125, 0.15, 0.24], + 'q_vectors': [[0.0, 0.0, 0.0], [0.1, 0.1, 0.0]], + 'ref_qss': [0.0, 0.0, 0.0], + 'inpxml_changes': [] + } + + wf_para = Dict(dict=wf_para).store() + options = ['--inpgen', inpgen.uuid, '--fleur', fleur.uuid, '-wf', wf_para.uuid] + run_cli_process_launch_command(launch_dmi, options=options) + + +def test_launch_ssdisp_base(run_cli_process_launch_command, fixture_code): + """Test invoking the mae workchain launch command with only required inputs.""" + from aiida_fleur.cmdline.launch import launch_ssdisp + + inpgen = fixture_code('fleur.inpgen').store() + fleur = fixture_code('fleur.fleur').store() + + wf_para = { + 'lattice': 'fcc', + 'miller': [[-1, 1, 0], [0, 0, 1], [1, 1, 0]], + 'host_symbol': 'Pt', + 'latticeconstant': 4.0, + 'size': (1, 1, 5), + 'replacements': { + 0: 'Fe', + -1: 'Fe' + }, + 'decimals': 10, + 'pop_last_layers': 1, + 'total_number_layers': 8, + 'num_relaxed_layers': 3 + } + + wf_para = { + 'beta': { + 'all': 1.57079 + }, + 'prop_dir': [0.125, 0.125, 0.0], + 'q_vectors': [[0.0, 0.0, 0.0], [0.125, 0.125, 0.0], [0.250, 0.250, 0.0], [0.375, 0.375, 0.0], + [0.500, 0.500, 0.0]], + 'ref_qss': [0.0, 0.0, 0.0], + 'inpxml_changes': [] + } + + wf_para = Dict(dict=wf_para).store() + options = ['--inpgen', inpgen.uuid, '--fleur', fleur.uuid, '-wf', wf_para.uuid] + run_cli_process_launch_command(launch_ssdisp, options=options) diff --git a/tests/cmdline/test_base_all_commands.py b/tests/cmdline/test_base_all_commands.py new file mode 100644 index 000000000..a3911bf0f --- /dev/null +++ b/tests/cmdline/test_base_all_commands.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +"""Tests if all available CLI commands can print help.""" +from click import Context, Group +from aiida_fleur.cmdline import cmd_root + + +def test_base_all_commands(): + """Test that all commands in ``cmd_root`` are reachable and can print the help message. + + This doesn't guarantee that the command works but at least that it can be successfully called and there are no + import errors or other basic problems. + """ + + def recursively_print_help(ctx): + assert isinstance(ctx.get_help(), str) + + if isinstance(ctx.command, Group): + for subcommand in ctx.command.commands.values(): + ctx.command = subcommand + recursively_print_help(ctx) + + ctx = Context(cmd_root) + recursively_print_help(ctx) diff --git a/tests/cmdline/test_types.py b/tests/cmdline/test_types.py new file mode 100644 index 000000000..407766326 --- /dev/null +++ b/tests/cmdline/test_types.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +''' +Module to test all CLI types of the package. +''' +import pytest +import os +import click +from aiida.orm import StructureData + +file_path1 = '../files/cif/AlB.cif' + +inpxmlfilefolder = os.path.dirname(os.path.abspath(__file__)) +CIF_FILE = os.path.abspath(os.path.join(inpxmlfilefolder, file_path1)) + + +class TestStructureNodeOrFileParamType: + """Test the ``StructureNodeOrFileParamType``""" + + def test_not_existent_structure(self, struct_file_type): + """Test failure if identifier given but NotExistent""" + with pytest.raises(click.BadParameter): + struct_file_type.convert('7000', None, None) + + def test_path_give(self, struct_file_type): + """Test if it can take a cif file""" + result = struct_file_type.convert(CIF_FILE, None, None) + assert isinstance(result, StructureData) + + def test_parse_duplicate(self, struct_file_type): + """Test if duplicates are not stored again""" + result = struct_file_type.convert(CIF_FILE, None, None) + structure = result.store() + + result = struct_file_type.convert(CIF_FILE, None, None) + assert result.uuid == structure.uuid diff --git a/tests/cmdline/visualization/__init__.py b/tests/cmdline/visualization/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cmdline/visualization/test_plot.py b/tests/cmdline/visualization/test_plot.py new file mode 100644 index 000000000..36477dd8f --- /dev/null +++ b/tests/cmdline/visualization/test_plot.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +''' +Module to test the plot cmd from the commandline +''' + +import os +import pytest +import aiida +from packaging import version + +file_path = '../../files/exports/fleur_scf_fleurinp_Si.tar.gz' +thisfilefolder = os.path.dirname(os.path.abspath(__file__)) +EXPORTFILE_FILE = os.path.abspath(os.path.join(thisfilefolder, file_path)) + + +@pytest.mark.skipif(version.parse(aiida.__version__) < version.parse('1.5.0'), + reason='archive import and migration works only with aiida-core > 1.5.0') +def test_cmd_plot(run_cli_command, temp_dir, import_with_migrate): + """Test invoking the plot command in all variants. + + If this test hangs, --no-show is not working + """ + from aiida_fleur.cmdline.visualization import cmd_plot + + # import an an aiida export, this does not migrate + import_with_migrate(EXPORTFILE_FILE) + process_uuid = '7f9f4cfb-4170-48ea-801d-4269f88792e0' + + options = [process_uuid, '--no-show'] + result = run_cli_command(cmd_plot, options=options) + + # provide a file with ids + tempfile_name = os.path.join(temp_dir, 'test_uuids.txt') + with open(tempfile_name, 'w') as file1: + file1.write('7f9f4cfb-4170-48ea-801d-4269f88792e0\n7f9f4cfb-4170-48ea-801d-4269f88792e0') + options = [process_uuid, '--no-show', '-f', tempfile_name] + result = run_cli_command(cmd_plot, options=options) + os.remove(tempfile_name) diff --git a/tests/cmdline/workflows/__init__.py b/tests/cmdline/workflows/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cmdline/workflows/test_worklow_cmd.py b/tests/cmdline/workflows/test_worklow_cmd.py new file mode 100644 index 000000000..f8909b7aa --- /dev/null +++ b/tests/cmdline/workflows/test_worklow_cmd.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +''' +Module to test all CLI workflow commands. +''' + +import os +import pytest +import aiida +from packaging import version + +file_path = '../../files/exports/fleur_scf_fleurinp_Si.tar.gz' +thisfilefolder = os.path.dirname(os.path.abspath(__file__)) +EXPORTFILE_FILE = os.path.abspath(os.path.join(thisfilefolder, file_path)) + + +@pytest.mark.skipif(version.parse(aiida.__version__) < version.parse('1.5.0'), + reason='archive import and migration works only with aiida-core > 1.5.0') +def test_workchain_res(run_cli_command, import_with_migrate): + """Test invoking the workchain res command in all variants.""" + from aiida_fleur.cmdline.workflows import workchain_res + + EXPECTED1 = '"total_energy": -580.0719889044,' + EXPECTED2 = '"energy_core_electrons": -316.8117066016,' + # import an an aiida export, this does not migrate + #import_data(EXPORTFILE_FILE, group=None) + import_with_migrate(EXPORTFILE_FILE) + process_uuid = '7f9f4cfb-4170-48ea-801d-4269f88792e0' + + options = [process_uuid] + result = run_cli_command(workchain_res, options=options) + assert EXPECTED1 in result.output_lines + assert EXPECTED2 in result.output_lines + + # only one node + options = [process_uuid, '-l', 'output_scf_wc_para', '--info', '--keys', 'total_energy', 'total_wall_time'] + result = run_cli_command(workchain_res, options=options) + assert EXPECTED1 in result.output_lines + assert EXPECTED2 not in result.output_lines + assert 'Info:' in result.output_lines[0] + + options = [process_uuid, '--keys', 'nothere'] + run_cli_command(workchain_res, options=options, raises=KeyError) + + +@pytest.mark.skipif(version.parse(aiida.__version__) < version.parse('1.5.0'), + reason='archive import and migration works only with aiida-core > 1.5.0') +def test_workchain_inputdict(run_cli_command, import_with_migrate): + """Test invoking the workchain inputdict command in all variants.""" + from aiida_fleur.cmdline.workflows import workchain_inputdict + + # import an an aiida export, this does not migrate + #import_data(EXPORTFILE_FILE, group=None) + import_with_migrate(EXPORTFILE_FILE) + EXPECTED = '"max_wallclock_seconds": 300,' + EXPECTED2 = '"num_machines": 1,' + process_uuid = '7f9f4cfb-4170-48ea-801d-4269f88792e0' + + options = [process_uuid] + result = run_cli_command(workchain_inputdict, options=options) + assert EXPECTED in result.output_lines + assert EXPECTED2 in result.output_lines + + options = [process_uuid, '--info', '-l', 'options', '--keys', 'max_wallclock_seconds', 'withmpi'] + result = run_cli_command(workchain_inputdict, options=options) + assert EXPECTED in result.output_lines + assert EXPECTED2 not in result.output_lines + assert 'Info:' in result.output_lines[0] + + options = [process_uuid, '--keys', 'nothere'] + run_cli_command(workchain_inputdict, options=options, raises=KeyError) diff --git a/tests/common/__initi__.py b/tests/common/__initi__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/common/test_node_generators.py b/tests/common/test_node_generators.py new file mode 100644 index 000000000..cd09fd2cd --- /dev/null +++ b/tests/common/test_node_generators.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +''' +Module to test all common node_generators + + +import pytest +from aiida_fleur.common.node_generators import generate_option_dict, generate_option_node +from aiida_fleur.common.node_generators import generate_wf_para_dict, generate_wf_para_node + +ALL_ENTRYPOINTS_CALCS = ['fleur.fleur', 'fleur.inpgen'] +ALL_ENTRYPOINTS_WC = ['fleur.base', 'fleur.scf', 'fleur.relax', 'fleur.base_relax', 'fleur.eos', + 'fleur.corehole', 'fleur.init_cls', 'fleur.banddos', 'fleur.mae', 'fleur.dmi', 'fleur.ssdisp', + 'fleur.create_magnetic'] + +def test_generate_option_dict_defaults_wc(entrypoint): + """Tests if the generate_option_dict function can get all the default options from the workchains + + i.e this also tests if all fleur workchains have defined some _default_option + """ + default_dict = generate_option_dict(wf_entry_point=entrypoint) + assert isinstance(default_dict, dict) + +def test_generate_option_node_interface(): + """ + + """ + pass + +@pytest.mark.parametrize('entrypoint', ALL_ENTRYPOINTS_WC) +def test_generate_wf_para_dict_defaults_wc(entrypoint): + """Tests if the generate_option_dict function can get all the default options from the workchains + + i.e this also tests if all fleur workchains have defined some _default_option + """ + default_dict = generate_wf_para_dict(wf_entry_point=entrypoint) + assert isinstance(default_dict, dict) +''' diff --git a/tests/conftest.py b/tests/conftest.py index 08c6c6bfa..74ec02f82 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,7 +8,6 @@ import os import collections import pytest -import six import sys from aiida.orm import Node, Code, Dict, RemoteData, CalcJobNode @@ -50,6 +49,7 @@ def fixture_code(fixture_localhost): """Return a `Code` instance configured to run calculations of given entry point on localhost `Computer`.""" def _fixture_code(entry_point_name): + return Code(input_plugin_name=entry_point_name, remote_computer_exec=[fixture_localhost, '/bin/ls']) return _fixture_code @@ -83,20 +83,26 @@ def _generate_calc_job(folder, entry_point_name, inputs=None): @pytest.fixture -def generate_calc_job_node(): +def generate_calc_job_node(fixture_localhost): """Fixture to generate a mock `CalcJobNode` for testing parsers.""" def flatten_inputs(inputs, prefix=''): """Flatten inputs recursively like :meth:`aiida.engine.processes.process::Process._flatten_inputs`.""" flat_inputs = [] - for key, value in six.iteritems(inputs): + for key, value in inputs.items(): if isinstance(value, collections.Mapping): flat_inputs.extend(flatten_inputs(value, prefix=prefix + key + '__')) else: flat_inputs.append((prefix + key, value)) return flat_inputs - def _generate_calc_job_node(entry_point_name, computer, test_name=None, inputs=None, attributes=None): + def _generate_calc_job_node(entry_point_name, + computer=None, + test_name=None, + inputs=None, + attributes=None, + store=False, + retrieve_list=None): """Fixture to generate a mock `CalcJobNode` for testing parsers. :param entry_point_name: entry point name of the calculation class @@ -110,6 +116,9 @@ def _generate_calc_job_node(entry_point_name, computer, test_name=None, inputs=N from aiida.common import LinkType from aiida.plugins.entry_point import format_entry_point_string + if computer is None: + computer = fixture_localhost + entry_point = format_entry_point_string('aiida.calculations', entry_point_name) node = orm.CalcJobNode(computer=computer, process_type=entry_point) @@ -120,6 +129,8 @@ def _generate_calc_job_node(entry_point_name, computer, test_name=None, inputs=N node.set_option('withmpi', True) node.set_option('max_wallclock_seconds', 1800) + if retrieve_list is not None: + node.set_attribute('retrieve_list', retrieve_list) if attributes: node.set_attribute_many(attributes) @@ -128,12 +139,12 @@ def _generate_calc_job_node(entry_point_name, computer, test_name=None, inputs=N input_node.store() node.add_incoming(input_node, link_type=LinkType.INPUT_CALC, link_label=link_label) - # node.store() + if store: # needed if test_name is not None + node.store() if test_name is not None: basepath = os.path.dirname(os.path.abspath(__file__)) - filepath = os.path.join(basepath, 'parsers', 'fixtures', entry_point_name[len('quantumespresso.'):], - test_name) + filepath = os.path.join(basepath, 'parsers', 'fixtures', entry_point_name[len('fleur.'):], test_name) retrieved = orm.FolderData() retrieved.put_object_from_tree(filepath) @@ -205,7 +216,7 @@ def generate_remote_data(): """Return a `RemoteData` node.""" def _generate_remote_data(computer, remote_path, entry_point_name=None): - """Return a `KpointsData` with a mesh of npoints in each direction.""" + """Return a `RemoteData` node pointing to given path.""" from aiida.common.links import LinkType from aiida.plugins.entry_point import format_entry_point_string @@ -261,7 +272,7 @@ def generate_work_chain_node(): def flatten_inputs(inputs, prefix=''): """Flatten inputs recursively like :meth:`aiida.engine.processes.process::Process._flatten_inputs`.""" flat_inputs = [] - for key, value in six.iteritems(inputs): + for key, value in inputs.items(): if isinstance(value, collections.Mapping): flat_inputs.extend(flatten_inputs(value, prefix=prefix + key + '__')) else: @@ -320,14 +331,13 @@ def generate_film_structure(): def _generate_film_structure(): """Return a `StructureData` representing bulk silicon.""" from aiida.orm import StructureData - - bohr_a_0 = 0.52917721092 # A - a = 7.497 * bohr_a_0 + from aiida_fleur.common.constants import BOHR_A + a = 7.497 * BOHR_A cell = [[0.7071068 * a, 0.0, 0.0], [0.0, 1.0 * a, 0.0], [0.0, 0.0, 0.7071068 * a]] structure = StructureData(cell=cell) - structure.append_atom(position=(0., 0., -1.99285 * bohr_a_0), symbols='Fe') + structure.append_atom(position=(0., 0., -1.99285 * BOHR_A), symbols='Fe') structure.append_atom(position=(0.5 * 0.7071068 * a, 0.5 * a, 0.0), symbols='Pt') - structure.append_atom(position=(0., 0., 2.65059 * bohr_a_0), symbols='Pt') + structure.append_atom(position=(0., 0., 2.65059 * BOHR_A), symbols='Pt') structure.pbc = (True, True, False) return structure diff --git a/tests/coverage.svg b/tests/coverage.svg deleted file mode 100644 index f86374a02..000000000 --- a/tests/coverage.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - coverage - coverage - 43% - 43% - - diff --git a/tests/data/test_fleurinp.py b/tests/data/test_fleurinp.py index d7b6b9f1b..0f6ec26bb 100644 --- a/tests/data/test_fleurinp.py +++ b/tests/data/test_fleurinp.py @@ -117,10 +117,10 @@ def test_fleurinp_structuredata_extraction(create_fleurinp, inpxmlfilepath): assert isinstance(struc, StructureData) else: pass - # What todo here, may test inpxml are with latnam definded, - # which does not work here. - # But if something else fails also None return. T - # Therefore this test might let two much through + # # What todo here, may test inpxml are with latnam definded, + # # which does not work here. + # # But if something else fails also None return. T + # # Therefore this test might let two much through # Input Modification tests @@ -145,8 +145,9 @@ def test_fleurinp_single_value_modification(create_fleurinp, inpxmlfilepath): @pytest.mark.parametrize('inpxmlfilepath', inpxmlfilelist) -def test_fleurinp_first_species_modification(create_fleurinp, inpxmlfilepath): - """ - Decrease the rmt of the first species by 10%, check if rmt was set - """ - return +def test_get_tag(create_fleurinp, inpxmlfilepath): + + fleurinp_tmp = create_fleurinp(inpxmlfilepath) + tag = fleurinp_tmp.get_tag('/fleurInput/atomSpecies/species') + + assert tag != [] diff --git a/tests/data/test_fleurinpmodifier.py b/tests/data/test_fleurinpmodifier.py index 07c294bab..270884d7b 100644 --- a/tests/data/test_fleurinpmodifier.py +++ b/tests/data/test_fleurinpmodifier.py @@ -14,6 +14,7 @@ from __future__ import absolute_import import os import pytest +from aiida_fleur.data.fleurinpmodifier import FleurinpModifier # Collect the input files file_path1 = '../files/inpxml/FePt/inp.xml' @@ -23,7 +24,7 @@ def test_fleurinp_modifier1(create_fleurinp): - from aiida_fleur.data.fleurinpmodifier import FleurinpModifier + """Tests if fleurinp_modifier with various modifations on species""" fleurinp_tmp = create_fleurinp(inpxmlfilefolder) fm = FleurinpModifier(fleurinp_tmp) @@ -43,15 +44,25 @@ def test_fleurinp_modifier1(create_fleurinp): fm.show(validate=True) fm.freeze() + fm = FleurinpModifier(fleurinp_tmp) + fm.set_inpchanges({'dos': True, 'Kmax': 3.9}) + fm.undo(revert_all=True) + changes = fm.changes() + assert changes == [] + def test_fleurinp_modifier2(create_fleurinp, inpxml_etree): - from aiida_fleur.data.fleurinpmodifier import FleurinpModifier + """Tests if fleurinp_modifier with various other modifations methods, + the detailed tests for method functionality is tested elsewhere.""" from aiida_fleur.tools.xml_util import eval_xpath fleurinp_tmp = create_fleurinp(inpxmlfilefolder) etree = inpxml_etree(inpxmlfilefolder) fm = FleurinpModifier(fleurinp_tmp) + actions = fm.get_avail_actions() + assert isinstance(actions, dict) + new_tag = eval_xpath(etree, '/fleurInput/calculationSetup/scfLoop') fm.delete_tag('/fleurInput/calculationSetup/scfLoop') fm.replace_tag('/fleurInput/calculationSetup/cutoffs', new_tag) @@ -66,6 +77,11 @@ def test_fleurinp_modifier2(create_fleurinp, inpxml_etree): fm.set_species_label(' 222', {'mtSphere': {'radius': 3.333}}) fm.set_atomgr_att_label(attributedict={'force': [('relaxXYZ', 'FFF')]}, atom_label=' 222') fm.set_atomgr_att(attributedict={'force': [('relaxXYZ', 'TFF')]}, species='Fe-1') + + fm.set_nkpts(500, gamma='T') + fm.set_kpath({'gamma': (0, 0, 0), 'L': (0.1, 0.1, 0.1)}, 300) + fm.add_num_to_att('/fleurInput/calculationSetup/soc', 'theta', 4) + #fm.set_species1 fm.show() @@ -76,12 +92,60 @@ def test_fleurinp_modifier2(create_fleurinp, inpxml_etree): inpxmlfilefolder2 = os.path.abspath(os.path.join(inpxmlfilefolder2, file_path2)) -def test_fleurinp_modifier3(create_fleurinp): - from aiida_fleur.data.fleurinpmodifier import FleurinpModifier +def test_fleurinp_modifier_set_nmmpmat(create_fleurinp): + """Tests if set_nmmpmat works on fleurinp modifier works, with right interface""" fleurinp_tmp = create_fleurinp(inpxmlfilefolder2) fm = FleurinpModifier(fleurinp_tmp) fm.set_nmmpmat('Ga-1', orbital=2, spin=1, occStates=[1, 2, 3, 4, 5]) fm.set_nmmpmat('As-2', orbital=1, spin=1, denmat=[[1, -2, 3], [4, -5, 6], [7, -8, 9]]) + + # Does not validate + # Found invalid diagonal element for species Ga-1, spin 1 and l=2 + with pytest.raises(ValueError): + fm.show(validate=True, display=False) new_fleurinp = fm.freeze() assert 'n_mmp_mat' in new_fleurinp.files + + +def test_fleurinp_modifier_set_kpointsdata(create_fleurinp): + """Test if setting a kpoints list to a fleurinp data node works""" + from aiida.orm import KpointsData + + fleurinp_tmp = create_fleurinp(inpxmlfilefolder) + fleurinp_tmp.store() # needed? + struc = fleurinp_tmp.get_structuredata_ncf() + + kps = KpointsData() + kps.set_cell(struc.cell) + kps.pbc = struc.pbc + kpoints_pos = [[0.0, 0.0, 0.0], [0.0, 0.5, 0.0], [0.5, 0.0, 0.0], [0.5, 0.0, 0.5], [0.5, 0.5, 0.5], [1.0, 1.0, 1.0]] + kpoints_weight = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + # Fleur renormalizes + kps.set_kpoints(kpoints_pos, cartesian=False, weights=kpoints_weight) + + kps.store() # needed, because node has to be loaded... + #print(fleurinp_tmp) + fm = FleurinpModifier(fleurinp_tmp) + fm.set_kpointsdata(kps) + + fm.show(validate=True, display=False) + fm.freeze() + + # check if kpoint node is input into modification + # uuid of node show also work + fm = FleurinpModifier(fleurinp_tmp) + fm.set_kpointsdata(kps.uuid) + fm.freeze() + + +def test_fleurinpmodifier_error_messages(create_fleurinp): + """Test error interface of fleurinpmodifier""" + fleurinp_tmp = create_fleurinp(inpxmlfilefolder) + + fm = FleurinpModifier(fleurinp_tmp) + fm._tasks.append(('not_existent', 1, 2, 3)) # task does not exists. + with pytest.raises(ValueError): + fm.freeze() + + fm = FleurinpModifier(fleurinp_tmp) diff --git a/tests/files/exports/base_export_regression_tests.tar.gz b/tests/files/exports/base_export_regression_tests.tar.gz new file mode 100644 index 000000000..93e26be53 Binary files /dev/null and b/tests/files/exports/base_export_regression_tests.tar.gz differ diff --git a/tests/files/exports/fleur_scf_fleurinp_Si.tar.gz b/tests/files/exports/fleur_scf_fleurinp_Si.tar.gz new file mode 100644 index 000000000..a2dd39448 Binary files /dev/null and b/tests/files/exports/fleur_scf_fleurinp_Si.tar.gz differ diff --git a/tests/files/outxml/all_test/Fe_relax_out.xml b/tests/files/outxml/all_test/Fe_relax_out.xml new file mode 100644 index 000000000..14207dadb --- /dev/null +++ b/tests/files/outxml/all_test/Fe_relax_out.xml @@ -0,0 +1,474 @@ + + + + + + GEN + + + + + + + + + + + A Fleur input generator calculation with aiida + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + 0.416667 0.416667 0.416667 + 0.416667 0.416667 0.250000 + 0.416667 0.416667 0.083333 + 0.416667 0.250000 0.250000 + 0.416667 0.250000 0.083333 + 0.416667 0.083333 0.083333 + 0.250000 0.250000 0.250000 + 0.250000 0.250000 0.083333 + 0.250000 0.083333 0.083333 + 0.083333 0.083333 0.083333 + + + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 -1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + + + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + + + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + + + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + 1 0 0 .0000000000 + + + 0 1 0 .0000000000 + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + + + 0 1 0 .0000000000 + 0 0 -1 .0000000000 + 1 0 0 .0000000000 + + + 1 0 0 .0000000000 + 0 0 -1 .0000000000 + 0 1 0 .0000000000 + + + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + 0 1 0 .0000000000 + + + 0 0 -1 .0000000000 + 0 1 0 .0000000000 + -1 0 0 .0000000000 + + + 0 0 -1 .0000000000 + 0 1 0 .0000000000 + 1 0 0 .0000000000 + + + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + + + 0 0 -1 .0000000000 + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + + + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + + + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + 1 0 0 .0000000000 + + + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + 0 1 0 .0000000000 + + + 0 0 -1 .0000000000 + 1 0 0 .0000000000 + 0 1 0 .0000000000 + + + 0 0 1 .0000000000 + 0 1 0 .0000000000 + -1 0 0 .0000000000 + + + 0 0 1 .0000000000 + 0 1 0 .0000000000 + 1 0 0 .0000000000 + + + 0 0 1 .0000000000 + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + + + 0 0 1 .0000000000 + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + + + 0 0 1 .0000000000 + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + + + 0 0 1 .0000000000 + 0 -1 0 .0000000000 + 1 0 0 .0000000000 + + + 0 0 1 .0000000000 + -1 0 0 .0000000000 + 0 1 0 .0000000000 + + + 0 0 1 .0000000000 + 1 0 0 .0000000000 + 0 1 0 .0000000000 + + + 1 0 0 .0000000000 + 0 0 1 .0000000000 + 0 -1 0 .0000000000 + + + -1 0 0 .0000000000 + 0 0 1 .0000000000 + 0 -1 0 .0000000000 + + + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + -1 0 0 .0000000000 + + + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + 1 0 0 .0000000000 + + + 0 1 0 .0000000000 + 0 0 1 .0000000000 + -1 0 0 .0000000000 + + + 0 1 0 .0000000000 + 0 0 1 .0000000000 + 1 0 0 .0000000000 + + + 1 0 0 .0000000000 + 0 0 1 .0000000000 + 0 1 0 .0000000000 + + + -1 0 0 .0000000000 + 0 0 1 .0000000000 + 0 1 0 .0000000000 + + + + + 5.354555983000000 .000000000000000 .000000000000000 + .000000000000000 5.354555983000000 .000000000000000 + .000000000000000 .000000000000000 5.354555983000000 + + + + + + + + + + + + + + + + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + 1.000/2.000 1.000/2.000 1.000/2.000 + + + + + + + + + + + + + + + + + + + + + + + + + + 0.416667 0.416667 0.416667 + 0.416667 0.416667 0.250000 + 0.416667 0.416667 0.083333 + 0.416667 0.250000 0.250000 + 0.416667 0.250000 0.083333 + 0.416667 0.083333 0.083333 + 0.250000 0.250000 0.250000 + 0.250000 0.250000 0.083333 + 0.250000 0.083333 0.083333 + 0.083333 0.083333 0.083333 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/files/relaxxml/Fe_relax.xml b/tests/files/relaxxml/Fe_relax.xml new file mode 100644 index 000000000..5ef8a9cc3 --- /dev/null +++ b/tests/files/relaxxml/Fe_relax.xml @@ -0,0 +1,13 @@ + + + + 0.0000000000 -0.0000000000 -0.0000000000 + 0.0000000000 0.0000000000 -0.0000000000 + + + + 0.0000000000 0.0000000000 0.0000000000 0.0000000000 -0.0000000000 -0.0000000000 + 2.6772779915 2.6772779915 2.6772779915 0.0000000000 0.0000000000 -0.0000000000 + + + diff --git a/tests/old_todo/data/fleurinpmodifier/btest_fleurinpmodifier_py.back b/tests/old_todo/data/fleurinpmodifier/btest_fleurinpmodifier_py.back deleted file mode 100644 index b06a01104..000000000 --- a/tests/old_todo/data/fleurinpmodifier/btest_fleurinpmodifier_py.back +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -This test tries to create a fleurinpdata and to modefy it -""" -from __future__ import absolute_import -from __future__ import print_function -from aiida.orm import ParameterData -import time -import os -from lxml import etree -from pprint import pprint -from aiida_fleur.data.fleurinpmodifier import FleurinpModifier -from aiida.plugins import DataFactory -from aiida_fleur.data.fleurinp import FleurinpData -from aiida import load_dbenv, is_dbenv_loaded -if not is_dbenv_loaded(): - load_dbenv() - -start_time = time.time() - -# schemanameQq - -path = os.getcwd() # path.realpath(__file__) -print(path) -filepath = path + '/inp.xml' -# '/Users/broeder/aiida/scratch/broeder/aiida_run2/ff/4c/c14d-8a1b-40b3-af95-400e23002bcb/inp.xml' - -new_fleurinpData = FleurinpData(files=[filepath]) -# print(new_fleurinpData.get_file_abs_path('inp.xml')) -# new_fleurinpData.store() - -#new_fleurinpData= load_node(6) - -fleurmode = FleurinpModifier(new_fleurinpData) - -#fleurmode.set_switch({'dos': True}) - -fleurmode.set_inpchanges({}) -fleurmode.set_inpchanges({'dos': True}) -tria = True -nkpts = 800 - -change_dict = {'dos': True, 'ndir': -1, 'minEnergy': -0.8, 'maxEnergy': 0.8, 'sigma': 0.005} - -fleurmode.set_inpchanges(change_dict) -if tria: - change_dict = {'mode': 'tria'} - fleurmode.set_inpchanges(change_dict) -if nkpts: - fleurmode.set_nkpts(count=nkpts) -''' -fleurmode.set_species('W-1', {'radius' : 3.5}) -fleurmode.change_atom('forces', True, position=(0.0, 0.0, 0.0)) -fleurmode.set_xpath('/fleurinput/@dos', True) -''' -''' -name = 'Na-1' -xpathn = '/fleurInput/atomSpecies/species[@name = "{}"]/mtSphere'.format(name)# 'radius': -attributename = 'radius' -attribv = 0.0000 -fleurmode.xml_set_all_attribv(xpathn, attributename, attribv) - -xpathn = '/fleurInput/atomSpecies/species/mtSphere' -xpathn = '/fleurInput' -#attribv = [0.0000, '1.2', 3.4] -#fleurmode.xml_set_all_attribv(xpathn, attributename, attribv) - - -#fleurmode.xml_set_attribv_occ(xmltree, xpathn, attributename, attribv, occ=[0]) -#fleurmode.xml_set_first_attribv(xmltree, xpathn, attributename, attribv) -xpathn = '/fleurInput/atomSpecies/species[@name = "{}"]/mtSphere/@radius'.format(name)# 'radius': - -attribv = 1.1111 -#set_xpath(xmltree, xpathn, attribv)# does not work - - -xpathn = '/fleurInput/atomGroups/atomGroup/relPos' -text = '1.20000 PI/3 5.1-MYCrazyCostant' -#fleurmode.xml_set_all_text(xpathn, text) - - -fleurmode.set_species('Na-1', { 'mtSphere' : {'radius' : 3.5}}) -fleurmode.set_species('W-2', {'atomicCutoffs' : {'lmax' : 9, 'lnonsphr': 7}, 'energyParameters': {'d' : 6}, 'mtSphere' : {'radius' : 2.6, 'gridPoints' : 925, 'logIncrement' : .01800000}}) -print 'here1' -# -fleurmode.set_species('W-2', {'electronConfig' : {'coreConfig' : '[Xe] (4f5/2) (4f7/2)', 'valenceConfig' : '(6s1/2) (5d3/2) (5d5/2) (6p1/2) (6p3/2)'}}, create=True)#, 'stateOccupation' : [{'state' : "(6p3/2)", 'spinUp' : "1.00000000", 'spinDown' : "1.00000000"}, {'state' : "(6p1/2)", 'spinUp' : "1.00000000", 'spinDown' : "1.00000000"}]}}, create=True) - - -xpathn = '/fleurInput/atomSpecies/species[@name = "{}"]'.format(name)# 'radius': -xpathn2 = '/fleurInput/atomSpecies/species[@name = "{}"]/electronConfig3/e/d/g/f/yeah'.format(name) - -new_e = etree.Element('lo') -new_e.set('type', "SCLO") - -#fleurmode.create_tag(xpathn, new_e, True) -#fleurmode.create_tag(xpathn,'electronConfig2', True) - -#eval_xpath3(root, xpathn2, create=True) -#fleurmode.set_species('W-2', {'lo': {'type':"SCLO", 'l' : 1, 'n' : 5, 'eDeriv' : 1}}, True) - -#fleurmode.set_species('W-2', {'lo': [{'type':"SCLO", 'l' : 1, 'n' : 5, 'eDeriv' : 2}]}, True) -#fleurmode.set_species('W-2', {'lo': [{'type':"SCLO", 'l' : 1, 'n' : 5, 'eDeriv' : 3}, {'type':"SCLO", 'l' : 1, 'n' : 5, 'eDeriv' : 4}, {'type':"SCLO", 'l' : 1, 'n' : 5, 'eDeriv' : 5}, {'type':"SCLO", 'l' : 1, 'n' : 5, 'eDeriv' : 6}]}, True) -''' - -# fleurmode.changes() -fleurmode.show(validate=True) # , display=False) - -print(fleurmode._original) -print(fleurmode._tasks) -out = '' # fleurmode.freeze() - -print('out: {}'.format(out)) -print('in: {}'.format(new_fleurinpData)) diff --git a/tests/old_todo/util/36.dot b/tests/old_todo/util/36.dot deleted file mode 100644 index 8126966e4..000000000 --- a/tests/old_todo/util/36.dot +++ /dev/null @@ -1,4 +0,0 @@ -digraph G { - N36 [shape=ellipse,label="StructureData (36) -Cr",color="lightblue",style="filled"]; -} diff --git a/tests/old_todo/util/btest_create_corehole_py.back b/tests/old_todo/util/btest_create_corehole_py.back deleted file mode 100644 index bfec885fa..000000000 --- a/tests/old_todo/util/btest_create_corehole_py.back +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from __future__ import absolute_import -from __future__ import print_function -__copyright__ = (u'Copyright (c), 2016, Forschungszentrum Jülich GmbH, ' 'IAS-1/PGI-1, Germany. All rights reserved.') -__license__ = 'MIT license, see LICENSE.txt file' -__version__ = '0.27' -__contributors__ = 'Jens Broeder' - -from aiida import load_dbenv, is_dbenv_loaded -if not is_dbenv_loaded(): - load_dbenv() -import sys, os -from aiida.orm.querybuilder import QueryBuilder - -from aiida_fleur_ad.util.create_corehole import create_corehole, create_corehole_fleurinp, write_change -from aiida_fleur.data.fleurinp import FleurinpData -from aiida.plugins import Code, CalculationFactory, DataFactory -from aiida.orm import load_node -from pprint import pprint -from aiida_fleur.tools.StructureData_util import break_symmetry as bs - -from aiida.orm import StructureData -''' -ids = [13586, 13934, 12748]#, 12927] - -for id in ids: - s = load_node(id) - new_s = bs(s, atoms=['Be'], site=[0, 1], pos=[(0.0, 0.0, -1.83792744752922), (0.0, 0.0, 0.918963723764612)]) - #new_s.store() -''' -#s = load_node(355) - -ids = [] #13924]#, 13925]#, 13926, 13927, 13928, 13929, 13930, 13931, 13932, 13933, 13934, 13935] -#ids = [479, 480, 481, 482, 537]# O12W4, O12W4, O6W2, O6W2, O36W3Y18 - -kind = 'W1' -econfig = '[Kr] 5s2 4d10 4f13 | 5p6 5d5 6s2' -para1 = Dict( - dict={ - 'title': 'A test calculation of Tungsten', - 'input': { - 'film': False, - 'cartesian': True, - }, - 'atom': { - 'element': 'W', - 'jri': 833, - 'rmt': 2.3, - 'dx': 0.015, - 'lmax': 8, - 'lo': '5p', - 'econfig': '[Kr] 5s2 4d10 4f14| 5p6 5d4 6s2', - }, - 'soc': { - 'theta': 0.0, - 'phi': 0.0 - }, - 'comp': { - 'kmax': 3.5, - 'gmax': 2.9, - }, - 'kpt': { - 'nkpt': 200, - } - }) -#para1.store() -#pprint(para1.get_dict()) - -for id in ids: - s = load_node(id) - new_s, para = bs(s, atoms=[], site=[0, 1], pos=[(0.0, 0.0, 0, 0)], parameterData=para1) - #print new_s.sites - #pprint(para.get_dict()) - res = create_corehole(new_s, kind, econfig, para) - #print res - #pprint(para.get_dict()) - #pprint(res.get_dict()) - -# test create_corehole_fleurinp -#fleurinp = load_node(14039) # W film - -inpxmlfile1 = '../inp_xml_files/W/inp.xml' -inpxmlfile = os.path.abspath(inpxmlfile1) -fleurinp = FleurinpData(files=[inpxmlfile]) -species = 'W-1' -stateocc = {'(5d3/2)': (2.5, 0.0), '(4f7/2)': (3.5, 4.0)} -pos = [] -coreconfig = 'same' -valenceconfig = 'same' -#pprint(fleurinp.inp_dict) - -new_inp = create_corehole_fleurinp(fleurinp, species, stateocc) -print(new_inp) - -etree = '' -change = [(1, 2)] -res = write_change(etree, change) -#res.write('.outtree') -print(res) diff --git a/tests/old_todo/util/btest_read_cif_folder.py b/tests/old_todo/util/btest_read_cif_folder.py deleted file mode 100644 index de9c75e59..000000000 --- a/tests/old_todo/util/btest_read_cif_folder.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -'''Implement a test for this interface''' -from __future__ import absolute_import -from aiida import load_dbenv, is_dbenv_loaded -if not is_dbenv_loaded(): - load_dbenv() -from aiida_fleur.tools.read_cif_folder import read_cif_folder - -read_cif_folder(log=True, - store=True, - recursive=True, - extras={ - 'type': 'bulk', - 'project': 'Fusion', - 'specification': 'aiida_work', - 'comment': 'Materials for Fusion' - }) diff --git a/tests/parsers/fixtures/fleur/complex_errorout/out.error b/tests/parsers/fixtures/fleur/complex_errorout/out.error new file mode 100644 index 000000000..cc8ea98a2 --- /dev/null +++ b/tests/parsers/fixtures/fleur/complex_errorout/out.error @@ -0,0 +1,18 @@ +/O warning : failed to load external entity "relax.xml" +**************juDFT-Error***************** +Error message:Allocation of memmory failed for mat datatype +Hint:You probably run out of memory +***************************************** + Last kown location: + Last timer:Setup of H&S matrices + Timerstack: + Timer:eigen + Timer:gen. of hamil. and diag. (total) + Timer:Iteration + Timer:Total Run + ***************************************** +Rank:0 used 2.093GB/ 3412936 kB + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 873 100 101 100 772 257 1966 --:--:-- --:--:-- --:--:-- 1969 +juDFT-STOPPED diff --git a/tests/parsers/fixtures/fleur/complex_errorout/out.xml b/tests/parsers/fixtures/fleur/complex_errorout/out.xml new file mode 100644 index 000000000..4542bb57d --- /dev/null +++ b/tests/parsers/fixtures/fleur/complex_errorout/out.xml @@ -0,0 +1,140 @@ + + + + + + GEN + + + + + + + + + + + A Fleur input generator calculation with aiida + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + 0.000000 0.000000 0.000000 + + + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + + + + + 28.345891875000000 .000000000000000 .000000000000000 + .000000000000000 28.345891875000000 .000000000000000 + .000000000000000 .000000000000000 28.345891875000000 + + + + + + + + + + + + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + -1.000/15.000 .0000000000 -.0266666667 + + + + + 1.000/30.000 .0577350267 -.0266666667 + 1.000/30.000 -.0577350267 -.0266666667 + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.000000 0.000000 0.000000 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/parsers/fixtures/fleur/complex_errorout/shell.out b/tests/parsers/fixtures/fleur/complex_errorout/shell.out new file mode 100644 index 000000000..3d16af8e6 --- /dev/null +++ b/tests/parsers/fixtures/fleur/complex_errorout/shell.out @@ -0,0 +1,8 @@ +iffcluster0105: Using InfiniBand for MPI communication. + Welcome to FLEUR (www.flapw.de) + MaX-Release 4.0 (www.max-centre.eu) + stars are always ordered + -------------------------------------------------------- + Number of OMP-threads: 12 + -------------------------------------------------------- + Usage data send using curl: usage.json diff --git a/tests/parsers/fixtures/fleur/complex_errorout/usage.json b/tests/parsers/fixtures/fleur/complex_errorout/usage.json new file mode 100644 index 000000000..688d6fe67 --- /dev/null +++ b/tests/parsers/fixtures/fleur/complex_errorout/usage.json @@ -0,0 +1,31 @@ +{ + "url":"www.flapw.de/collect.pl", + "calculation-id":"F6674BD6CD51AA09", + "data": { + "githash":"9cddd6d3ed47288c8d096c3f755728090cc6dc36", + "XC-treatment":2, + "MPI-PE":1, + "OMP":12, + "A-Types":3, + "Atoms":4, + "Real":false, + "Spins":1, + "Noco":false, + "SOC":false, + "SpinSpiral":false, + "PlaneWaves":47937, + "LOs":0, + "nkpt":1, + "gpu_per_node":0, + "Runtime":39.00, + "Error":"Allocation of memmory failed for mat datatype", + "cpu_model":"44", + "cpu_modelname":"Intel(R) Xeon(R) CPU X5670 @ 2.93GHz", + "VmPeak":3412936, + "VmSize":2194828, + "VmData":1614740, + "VmStk":350524, + "VmExe":12428, + "VmSwap":0 + } +} diff --git a/tests/parsers/fixtures/fleur/default/JUDFT_WARN_ONLY b/tests/parsers/fixtures/fleur/default/JUDFT_WARN_ONLY new file mode 100644 index 000000000..65c71eb10 --- /dev/null +++ b/tests/parsers/fixtures/fleur/default/JUDFT_WARN_ONLY @@ -0,0 +1 @@ +/n diff --git a/tests/parsers/fixtures/fleur/default/_scheduler-stderr.txt b/tests/parsers/fixtures/fleur/default/_scheduler-stderr.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/parsers/fixtures/fleur/default/_scheduler-stdout.txt b/tests/parsers/fixtures/fleur/default/_scheduler-stdout.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/parsers/fixtures/fleur/default/cdn1 b/tests/parsers/fixtures/fleur/default/cdn1 new file mode 100644 index 000000000..2a3a43854 Binary files /dev/null and b/tests/parsers/fixtures/fleur/default/cdn1 differ diff --git a/tests/parsers/fixtures/fleur/default/inp.xml b/tests/parsers/fixtures/fleur/default/inp.xml new file mode 100644 index 000000000..4d34c362a --- /dev/null +++ b/tests/parsers/fixtures/fleur/default/inp.xml @@ -0,0 +1,368 @@ + + + + Si, alpha silicon, bulk, delta project + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + 0.437500 0.437500 0.437500 + 0.312500 0.437500 0.437500 + 0.187500 0.437500 0.437500 + 0.062500 0.437500 0.437500 + 0.062500 0.500000 0.500000 + 0.187500 0.562500 0.562500 + 0.312500 0.562500 0.562500 + 0.437500 0.437500 0.562500 + 0.312500 0.312500 0.437500 + 0.187500 0.312500 0.437500 + 0.125000 0.375000 0.437500 + 0.125000 0.437500 0.500000 + 0.187500 0.500000 0.625000 + 0.312500 0.437500 0.687500 + 0.312500 0.437500 0.562500 + 0.250000 0.250000 0.437500 + 0.250000 0.375000 0.437500 + 0.250000 0.437500 0.500000 + 0.250000 0.437500 0.625000 + 0.250000 0.500000 0.687500 + 0.187500 0.437500 0.562500 + 0.375000 0.375000 0.437500 + 0.375000 0.437500 0.500000 + 0.375000 0.437500 0.625000 + 0.250000 0.562500 0.625000 + 0.125000 0.500000 0.562500 + 0.437500 0.500000 0.500000 + 0.375000 0.500000 0.562500 + 0.250000 0.500000 0.562500 + 0.375000 0.375000 0.562500 + 0.250000 0.375000 0.562500 + 0.312500 0.312500 0.562500 + 0.312500 0.312500 0.312500 + 0.187500 0.312500 0.312500 + 0.062500 0.312500 0.312500 + 0.062500 0.375000 0.375000 + 0.187500 0.500000 0.500000 + 0.375000 0.375000 0.687500 + 0.187500 0.187500 0.312500 + 0.125000 0.250000 0.312500 + 0.125000 0.312500 0.375000 + 0.187500 0.375000 0.500000 + 0.312500 0.500000 0.625000 + 0.250000 0.250000 0.312500 + 0.250000 0.312500 0.375000 + 0.250000 0.312500 0.500000 + 0.312500 0.375000 0.625000 + 0.312500 0.375000 0.375000 + 0.312500 0.375000 0.500000 + 0.312500 0.500000 0.500000 + 0.187500 0.187500 0.187500 + 0.062500 0.187500 0.187500 + 0.062500 0.250000 0.250000 + 0.187500 0.375000 0.375000 + 0.125000 0.125000 0.187500 + 0.125000 0.187500 0.250000 + 0.187500 0.250000 0.375000 + 0.187500 0.250000 0.250000 + 0.062500 0.062500 0.062500 + 0.062500 0.125000 0.125000 + + + + + + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 1 1 1 .5000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 1 1 1 .5000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + -1 -1 -1 .5000000000 + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + -1 -1 -1 .5000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 0 1 .0000000000 + 1 0 0 .0000000000 + -1 -1 -1 .5000000000 + + + 0 0 1 .0000000000 + 0 1 0 .0000000000 + -1 -1 -1 .5000000000 + + + 1 1 1 .5000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 1 1 .5000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 1 1 1 .5000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 0 0 1 .0000000000 + -1 -1 -1 .5000000000 + + + 0 1 0 .0000000000 + 0 0 1 .0000000000 + -1 -1 -1 .5000000000 + + + 0 -1 0 .0000000000 + 1 1 1 .5000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + + + 0 1 0 .0000000000 + -1 -1 -1 .5000000000 + 1 0 0 .0000000000 + + + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + + + 1 0 0 .0000000000 + -1 -1 -1 .5000000000 + 0 1 0 .0000000000 + + + 1 1 1 .5000000000 + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + + + 0 0 1 .0000000000 + -1 -1 -1 .5000000000 + 1 0 0 .0000000000 + + + 1 1 1 .5000000000 + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + + + 0 0 1 .0000000000 + -1 -1 -1 .5000000000 + 0 1 0 .0000000000 + + + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + + + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + + + -1 -1 -1 .5000000000 + 0 1 0 .0000000000 + 1 0 0 .0000000000 + + + -1 -1 -1 .5000000000 + 1 0 0 .0000000000 + 0 1 0 .0000000000 + + + 0 0 1 .0000000000 + 0 1 0 .0000000000 + 1 0 0 .0000000000 + + + 1 1 1 .5000000000 + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + + + 1 1 1 .5000000000 + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + + + 0 0 1 .0000000000 + 1 0 0 .0000000000 + 0 1 0 .0000000000 + + + 0 0 -1 .0000000000 + 1 1 1 .5000000000 + -1 0 0 .0000000000 + + + 0 0 -1 .0000000000 + 1 1 1 .5000000000 + 0 -1 0 .0000000000 + + + -1 -1 -1 .5000000000 + 0 0 1 .0000000000 + 1 0 0 .0000000000 + + + -1 -1 -1 .5000000000 + 0 0 1 .0000000000 + 0 1 0 .0000000000 + + + -1 0 0 .0000000000 + 1 1 1 .5000000000 + 0 -1 0 .0000000000 + + + 0 1 0 .0000000000 + 0 0 1 .0000000000 + 1 0 0 .0000000000 + + + 0 -1 0 .0000000000 + 1 1 1 .5000000000 + -1 0 0 .0000000000 + + + 1 0 0 .0000000000 + 0 0 1 .0000000000 + 0 1 0 .0000000000 + + + 1 0 0 .0000000000 + -1 -1 -1 .5000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + -1 -1 -1 .5000000000 + 0 0 1 .0000000000 + + + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + 1 1 1 .5000000000 + + + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + 1 1 1 .5000000000 + + + -1 -1 -1 .5000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + -1 -1 -1 .5000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + 1 1 1 .5000000000 + + + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + 1 1 1 .5000000000 + + + + + .000000000000000 5.167355275200000 5.167355275200000 + 5.167355275200000 .000000000000000 5.167355275200000 + 5.167355275200000 5.167355275200000 .000000000000000 + + + + + + + + + + + + + + + 1.000/8.000 1.000/8.000 1.000/8.000 + -1.000/8.000 -1.000/8.000 -1.000/8.000 + + + + + + + + + + + + + + + + + diff --git a/tests/parsers/fixtures/fleur/default/juDFT_times.json b/tests/parsers/fixtures/fleur/default/juDFT_times.json new file mode 100644 index 000000000..c3ad98c14 --- /dev/null +++ b/tests/parsers/fixtures/fleur/default/juDFT_times.json @@ -0,0 +1,434 @@ +{ + "timername" : "Total Run", + "totaltime" : 4.00000, + "subtimers": [ + { + "timername" : "Initialization", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 1, + "subtimers": [ + { + "timername" : "r_inpXML", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 1 + }, + { + "timername" : "postprocessInput", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 1, + "subtimers": [ + { + "timername" : "strgn", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 1, + "subtimers": [ + { + "timername" : "writeStars", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 1 + } + ] + }, + { + "timername" : "stepf", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 1 + } + ] + } + ] + }, + { + "timername" : "generation of start-density", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 1, + "subtimers": [ + { + "timername" : "qpw_to_nmt", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 1 + }, + { + "timername" : "cdntot", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 1, + "subtimers": [ + { + "timername" : "MT", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 1 + } + ] + } + ] + }, + { + "timername" : "Qfix", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 1 + }, + { + "timername" : "Open file/memory for IO of eig", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 1 + }, + { + "timername" : "Iteration", + "totaltime" : 4.00000, + "mintime" : 0.0000E+00, + "maxtime" : 1.00000, + "ncalls" : 11, + "subtimers": [ + { + "timername" : "generation of potential", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11, + "subtimers": [ + { + "timername" : "psqpw", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11 + }, + { + "timername" : "interstitial", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11 + }, + { + "timername" : "MT-spheres", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11 + }, + { + "timername" : "den-pot integrals", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11 + }, + { + "timername" : "Vxc in interstitial", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11 + }, + { + "timername" : "Vxc in MT", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11 + } + ] + }, + { + "timername" : "gen. of hamil. and diag. (tota", + "totaltime" : 3.00000, + "mintime" : 0.0000E+00, + "maxtime" : 1.00000, + "ncalls" : 11, + "subtimers": [ + { + "timername" : "eigen", + "totaltime" : 3.00000, + "mintime" : 0.0000E+00, + "maxtime" : 1.00000, + "ncalls" : 11, + "subtimers": [ + { + "timername" : "Updating energy parameters", + "totaltime" : 1.00000, + "mintime" : 0.0000E+00, + "maxtime" : 1.00000, + "ncalls" : 11 + }, + { + "timername" : "tlmplm", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11 + }, + { + "timername" : "Setup of H&S matrices", + "totaltime" : 2.00000, + "mintime" : 0.0000E+00, + "maxtime" : 1.00000, + "ncalls" : 660, + "subtimers": [ + { + "timername" : "Interstitial part", + "totaltime" : 1.00000, + "mintime" : 0.0000E+00, + "maxtime" : 1.00000, + "ncalls" : 660 + }, + { + "timername" : "MT part", + "totaltime" : 1.00000, + "mintime" : 0.0000E+00, + "maxtime" : 1.00000, + "ncalls" : 660, + "subtimers": [ + { + "timername" : "fjgj coefficients", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660 + }, + { + "timername" : "spherical setup", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660 + }, + { + "timername" : "non-spherical setup", + "totaltime" : 1.00000, + "mintime" : 0.0000E+00, + "maxtime" : 1.00000, + "ncalls" : 660 + }, + { + "timername" : "LO setup", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660 + } + ] + }, + { + "timername" : "Matrix redistribution", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660 + } + ] + }, + { + "timername" : "Diagonalization", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660 + }, + { + "timername" : "EV output", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660, + "subtimers": [ + { + "timername" : "IO (write)", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660 + } + ] + } + ] + } + ] + }, + { + "timername" : "determination of fermi energy", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11, + "subtimers": [ + { + "timername" : "IO (read)", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660 + }, + { + "timername" : "IO (write)", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660 + } + ] + }, + { + "timername" : "generation of new charge densi", + "totaltime" : 1.00000, + "mintime" : 0.0000E+00, + "maxtime" : 1.00000, + "ncalls" : 11, + "subtimers": [ + { + "timername" : "cdnval", + "totaltime" : 1.00000, + "mintime" : 0.0000E+00, + "maxtime" : 1.00000, + "ncalls" : 11, + "subtimers": [ + { + "timername" : "IO (read)", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660 + }, + { + "timername" : "pwden", + "totaltime" : 1.00000, + "mintime" : 0.0000E+00, + "maxtime" : 1.00000, + "ncalls" : 660 + }, + { + "timername" : "abcof", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660 + }, + { + "timername" : "cdnval: rhomt", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660 + }, + { + "timername" : "cdnval: rhonmt", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660 + }, + { + "timername" : "cdnval: rho(n)mtlo", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 660 + }, + { + "timername" : "cdnmt", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11 + } + ] + }, + { + "timername" : "cdntot", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 22, + "subtimers": [ + { + "timername" : "MT", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 22 + } + ] + }, + { + "timername" : "cdngen: cdncore", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11, + "subtimers": [ + { + "timername" : "qpw_to_nmt", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11 + } + ] + } + ] + }, + { + "timername" : "determination of total energy", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11 + }, + { + "timername" : "Charge Density Mixing", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11, + "subtimers": [ + { + "timername" : "Reading of distances", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11 + }, + { + "timername" : "Mixing", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11 + }, + { + "timername" : "Postprocessing", + "totaltime" : 0.0000E+00, + "mintime" : 0.0000E+00, + "maxtime" : 0.0000E+00, + "ncalls" : 11 + } + ] + } + ] + } + ] +} diff --git a/tests/parsers/fixtures/fleur/default/out.error b/tests/parsers/fixtures/fleur/default/out.error new file mode 100644 index 000000000..af9803b54 --- /dev/null +++ b/tests/parsers/fixtures/fleur/default/out.error @@ -0,0 +1,12 @@ +I/O warning : failed to load external entity "relax.xml" + + ***************************************** + Run finished successfully + Stop message: + all done + ***************************************** +Rank:0 used 0.676GB/ 712964 kB + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed + 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 780 100 40 100 740 181 3352 --:--:-- --:--:-- --:--:-- 3363 +OK diff --git a/tests/parsers/fixtures/fleur/default/out.xml b/tests/parsers/fixtures/fleur/default/out.xml new file mode 100644 index 000000000..0fe9c6b19 --- /dev/null +++ b/tests/parsers/fixtures/fleur/default/out.xml @@ -0,0 +1,1013 @@ + + + + + + GEN + + + + + + + + + + Si, alpha silicon, bulk, delta project + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + 0.437500 0.437500 0.437500 + 0.312500 0.437500 0.437500 + 0.187500 0.437500 0.437500 + 0.062500 0.437500 0.437500 + 0.062500 0.500000 0.500000 + 0.187500 0.562500 0.562500 + 0.312500 0.562500 0.562500 + 0.437500 0.437500 0.562500 + 0.312500 0.312500 0.437500 + 0.187500 0.312500 0.437500 + 0.125000 0.375000 0.437500 + 0.125000 0.437500 0.500000 + 0.187500 0.500000 0.625000 + 0.312500 0.437500 0.687500 + 0.312500 0.437500 0.562500 + 0.250000 0.250000 0.437500 + 0.250000 0.375000 0.437500 + 0.250000 0.437500 0.500000 + 0.250000 0.437500 0.625000 + 0.250000 0.500000 0.687500 + 0.187500 0.437500 0.562500 + 0.375000 0.375000 0.437500 + 0.375000 0.437500 0.500000 + 0.375000 0.437500 0.625000 + 0.250000 0.562500 0.625000 + 0.125000 0.500000 0.562500 + 0.437500 0.500000 0.500000 + 0.375000 0.500000 0.562500 + 0.250000 0.500000 0.562500 + 0.375000 0.375000 0.562500 + 0.250000 0.375000 0.562500 + 0.312500 0.312500 0.562500 + 0.312500 0.312500 0.312500 + 0.187500 0.312500 0.312500 + 0.062500 0.312500 0.312500 + 0.062500 0.375000 0.375000 + 0.187500 0.500000 0.500000 + 0.375000 0.375000 0.687500 + 0.187500 0.187500 0.312500 + 0.125000 0.250000 0.312500 + 0.125000 0.312500 0.375000 + 0.187500 0.375000 0.500000 + 0.312500 0.500000 0.625000 + 0.250000 0.250000 0.312500 + 0.250000 0.312500 0.375000 + 0.250000 0.312500 0.500000 + 0.312500 0.375000 0.625000 + 0.312500 0.375000 0.375000 + 0.312500 0.375000 0.500000 + 0.312500 0.500000 0.500000 + 0.187500 0.187500 0.187500 + 0.062500 0.187500 0.187500 + 0.062500 0.250000 0.250000 + 0.187500 0.375000 0.375000 + 0.125000 0.125000 0.187500 + 0.125000 0.187500 0.250000 + 0.187500 0.250000 0.375000 + 0.187500 0.250000 0.250000 + 0.062500 0.062500 0.062500 + 0.062500 0.125000 0.125000 + + + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 1 1 1 .5000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 1 1 1 .5000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + -1 -1 -1 .5000000000 + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + -1 -1 -1 .5000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 0 1 .0000000000 + 1 0 0 .0000000000 + -1 -1 -1 .5000000000 + + + 0 0 1 .0000000000 + 0 1 0 .0000000000 + -1 -1 -1 .5000000000 + + + 1 1 1 .5000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 1 1 .5000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 1 1 1 .5000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 0 0 1 .0000000000 + -1 -1 -1 .5000000000 + + + 0 1 0 .0000000000 + 0 0 1 .0000000000 + -1 -1 -1 .5000000000 + + + 0 -1 0 .0000000000 + 1 1 1 .5000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + + + 0 1 0 .0000000000 + -1 -1 -1 .5000000000 + 1 0 0 .0000000000 + + + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + + + 1 0 0 .0000000000 + -1 -1 -1 .5000000000 + 0 1 0 .0000000000 + + + 1 1 1 .5000000000 + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + + + 0 0 1 .0000000000 + -1 -1 -1 .5000000000 + 1 0 0 .0000000000 + + + 1 1 1 .5000000000 + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + + + 0 0 1 .0000000000 + -1 -1 -1 .5000000000 + 0 1 0 .0000000000 + + + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + + + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + + + -1 -1 -1 .5000000000 + 0 1 0 .0000000000 + 1 0 0 .0000000000 + + + -1 -1 -1 .5000000000 + 1 0 0 .0000000000 + 0 1 0 .0000000000 + + + 0 0 1 .0000000000 + 0 1 0 .0000000000 + 1 0 0 .0000000000 + + + 1 1 1 .5000000000 + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + + + 1 1 1 .5000000000 + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + + + 0 0 1 .0000000000 + 1 0 0 .0000000000 + 0 1 0 .0000000000 + + + 0 0 -1 .0000000000 + 1 1 1 .5000000000 + -1 0 0 .0000000000 + + + 0 0 -1 .0000000000 + 1 1 1 .5000000000 + 0 -1 0 .0000000000 + + + -1 -1 -1 .5000000000 + 0 0 1 .0000000000 + 1 0 0 .0000000000 + + + -1 -1 -1 .5000000000 + 0 0 1 .0000000000 + 0 1 0 .0000000000 + + + -1 0 0 .0000000000 + 1 1 1 .5000000000 + 0 -1 0 .0000000000 + + + 0 1 0 .0000000000 + 0 0 1 .0000000000 + 1 0 0 .0000000000 + + + 0 -1 0 .0000000000 + 1 1 1 .5000000000 + -1 0 0 .0000000000 + + + 1 0 0 .0000000000 + 0 0 1 .0000000000 + 0 1 0 .0000000000 + + + 1 0 0 .0000000000 + -1 -1 -1 .5000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + -1 -1 -1 .5000000000 + 0 0 1 .0000000000 + + + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + 1 1 1 .5000000000 + + + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + 1 1 1 .5000000000 + + + -1 -1 -1 .5000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + -1 -1 -1 .5000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + 1 1 1 .5000000000 + + + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + 1 1 1 .5000000000 + + + + + .000000000000000 5.167355275200000 5.167355275200000 + 5.167355275200000 .000000000000000 5.167355275200000 + 5.167355275200000 5.167355275200000 .000000000000000 + + + + + + + + + + + + + + + 1.000/8.000 1.000/8.000 1.000/8.000 + -1.000/8.000 -1.000/8.000 -1.000/8.000 + + + + + + + + + + + + + + + + + + + + + + + + + 0.437500 0.437500 0.437500 + 0.312500 0.437500 0.437500 + 0.187500 0.437500 0.437500 + 0.062500 0.437500 0.437500 + 0.062500 0.500000 0.500000 + 0.187500 0.562500 0.562500 + 0.312500 0.562500 0.562500 + 0.437500 0.437500 0.562500 + 0.312500 0.312500 0.437500 + 0.187500 0.312500 0.437500 + 0.125000 0.375000 0.437500 + 0.125000 0.437500 0.500000 + 0.187500 0.500000 0.625000 + 0.312500 0.437500 0.687500 + 0.312500 0.437500 0.562500 + 0.250000 0.250000 0.437500 + 0.250000 0.375000 0.437500 + 0.250000 0.437500 0.500000 + 0.250000 0.437500 0.625000 + 0.250000 0.500000 0.687500 + 0.187500 0.437500 0.562500 + 0.375000 0.375000 0.437500 + 0.375000 0.437500 0.500000 + 0.375000 0.437500 0.625000 + 0.250000 0.562500 0.625000 + 0.125000 0.500000 0.562500 + 0.437500 0.500000 0.500000 + 0.375000 0.500000 0.562500 + 0.250000 0.500000 0.562500 + 0.375000 0.375000 0.562500 + 0.250000 0.375000 0.562500 + 0.312500 0.312500 0.562500 + 0.312500 0.312500 0.312500 + 0.187500 0.312500 0.312500 + 0.062500 0.312500 0.312500 + 0.062500 0.375000 0.375000 + 0.187500 0.500000 0.500000 + 0.375000 0.375000 0.687500 + 0.187500 0.187500 0.312500 + 0.125000 0.250000 0.312500 + 0.125000 0.312500 0.375000 + 0.187500 0.375000 0.500000 + 0.312500 0.500000 0.625000 + 0.250000 0.250000 0.312500 + 0.250000 0.312500 0.375000 + 0.250000 0.312500 0.500000 + 0.312500 0.375000 0.625000 + 0.312500 0.375000 0.375000 + 0.312500 0.375000 0.500000 + 0.312500 0.500000 0.500000 + 0.187500 0.187500 0.187500 + 0.062500 0.187500 0.187500 + 0.062500 0.250000 0.250000 + 0.187500 0.375000 0.375000 + 0.125000 0.125000 0.187500 + 0.125000 0.187500 0.250000 + 0.187500 0.250000 0.375000 + 0.187500 0.250000 0.250000 + 0.062500 0.062500 0.062500 + 0.062500 0.125000 0.125000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/parsers/fixtures/fleur/default/shell.out b/tests/parsers/fixtures/fleur/default/shell.out new file mode 100644 index 000000000..39ea32f54 --- /dev/null +++ b/tests/parsers/fixtures/fleur/default/shell.out @@ -0,0 +1,58 @@ + Welcome to FLEUR (www.flapw.de) + MaX-Release 4.0 (www.max-centre.eu) + stars are always ordered + -------------------------------------------------------- + Number of OMP-threads: 6 + -------------------------------------------------------- + Iteration: 1 Distance: 8.14211820818857 + Test for time of next iteration: + Time provided (min): 10 + Time used (min): 1 + Time per iter (min): 1 + Iteration: 2 Distance: 7.69204733499305 + Test for time of next iteration: + Time provided (min): 10 + Time used (min): 1 + Time per iter (min): 1 + Iteration: 3 Distance: 0.856944507774482 + Test for time of next iteration: + Time provided (min): 10 + Time used (min): 1 + Time per iter (min): 1 + Iteration: 4 Distance: 0.501438298333166 + Test for time of next iteration: + Time provided (min): 10 + Time used (min): 1 + Time per iter (min): 1 + Iteration: 5 Distance: 0.205605182835176 + Test for time of next iteration: + Time provided (min): 10 + Time used (min): 1 + Time per iter (min): 1 + Iteration: 6 Distance: 1.852288794887397E-002 + Test for time of next iteration: + Time provided (min): 10 + Time used (min): 1 + Time per iter (min): 1 + Iteration: 7 Distance: 1.291466956872122E-002 + Test for time of next iteration: + Time provided (min): 10 + Time used (min): 1 + Time per iter (min): 1 + Iteration: 8 Distance: 1.303177341130901E-003 + Test for time of next iteration: + Time provided (min): 10 + Time used (min): 1 + Time per iter (min): 1 + Iteration: 9 Distance: 1.207653876674686E-003 + Test for time of next iteration: + Time provided (min): 10 + Time used (min): 1 + Time per iter (min): 1 + Iteration: 10 Distance: 1.741120625902552E-004 + Test for time of next iteration: + Time provided (min): 10 + Time used (min): 1 + Time per iter (min): 1 + Iteration: 11 Distance: 3.295348349644261E-005 + Usage data send using curl: usage.json diff --git a/tests/parsers/fixtures/fleur/mt_overlap_errorout/out.error b/tests/parsers/fixtures/fleur/mt_overlap_errorout/out.error new file mode 100644 index 000000000..e11603cde --- /dev/null +++ b/tests/parsers/fixtures/fleur/mt_overlap_errorout/out.error @@ -0,0 +1,16 @@ +**************juDFT-Error***************** +Error message:Overlapping MT-spheres during relaxation: +2 1 olap: 6.8200E-03 +Treat as an error: writing rescaled displacements to relax.xml is not implemented +***************************************** + Last kown location: + Last timer:postprocessInput + Timerstack: + Timer:Initialization + Timer:Total Run + ***************************************** +Rank:0 used 0.171GB/ 178892 kB + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 697 100 101 100 596 295 1745 --:--:-- --:--:-- --:--:-- 1747 +juDFT-STOPPED diff --git a/tests/parsers/fixtures/fleur/mt_overlap_errorout/out.xml b/tests/parsers/fixtures/fleur/mt_overlap_errorout/out.xml new file mode 100644 index 000000000..4f4396841 --- /dev/null +++ b/tests/parsers/fixtures/fleur/mt_overlap_errorout/out.xml @@ -0,0 +1,19 @@ + + + + + + GEN + + + + + + + + + + + diff --git a/tests/parsers/fixtures/fleur/mt_overlap_errorout/relax.xml b/tests/parsers/fixtures/fleur/mt_overlap_errorout/relax.xml new file mode 100644 index 000000000..99be634d9 --- /dev/null +++ b/tests/parsers/fixtures/fleur/mt_overlap_errorout/relax.xml @@ -0,0 +1,14 @@ + + + + 0.0000000000 0.0000000000 0.0246059526 + + + + 0.0000000000 0.0000000000 -0.7558904500 0.0000000000 0.0000000000 0.0283825580 + + + 0.0000000000 0.0000000000 -0.7416991710 0.0000000000 0.0000000000 0.0208293472 + + + diff --git a/tests/parsers/fixtures/fleur/mt_overlap_errorout/shell.out b/tests/parsers/fixtures/fleur/mt_overlap_errorout/shell.out new file mode 100644 index 000000000..20176599a --- /dev/null +++ b/tests/parsers/fixtures/fleur/mt_overlap_errorout/shell.out @@ -0,0 +1,6 @@ +iffcluster0111: Using InfiniBand for MPI communication. + Welcome to FLEUR (www.flapw.de) + MaX-Release 4.0 (www.max-centre.eu) + Attention: Overlapping MT-spheres. Reduced displacement by 10% + 2 1 6.819998745005051E-003 + Usage data send using curl: usage.json diff --git a/tests/parsers/fixtures/fleur/relax/inp.xml b/tests/parsers/fixtures/fleur/relax/inp.xml new file mode 100644 index 000000000..0c4cd2a6f --- /dev/null +++ b/tests/parsers/fixtures/fleur/relax/inp.xml @@ -0,0 +1,151 @@ + + + A Fleur input generator calculation with aiida + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + 0.000000 0.000000 0.000000 + + + + + + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 -1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + + + 28.345891875000000 .000000000000000 .000000000000000 + .000000000000000 28.345891875000000 .000000000000000 + .000000000000000 .000000000000000 28.345891875000000 + + + + + + + + + + + + + + + + .0000000000 .0000000000 -.7558904500 + .0000000000 .0000000000 .7558904500 + + + + + + + + + + + + + + + + + + + diff --git a/tests/parsers/fixtures/fleur/relax/out.error b/tests/parsers/fixtures/fleur/relax/out.error new file mode 100644 index 000000000..8fd25387b --- /dev/null +++ b/tests/parsers/fixtures/fleur/relax/out.error @@ -0,0 +1,10 @@ + ***************************************** + Run finished successfully + Stop message: + Structural relaxation: new displacements generated + ***************************************** +Rank:0 used 2.394GB/ 4967856 kB + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 807 100 74 100 733 191 1897 --:--:-- --:--:-- --:--:-- 1894 +OK diff --git a/tests/parsers/fixtures/fleur/relax/out.xml b/tests/parsers/fixtures/fleur/relax/out.xml new file mode 100644 index 000000000..82e5d56bb --- /dev/null +++ b/tests/parsers/fixtures/fleur/relax/out.xml @@ -0,0 +1,2317 @@ + + + + + + GEN + + + + + + + + + + + A Fleur input generator calculation with aiida + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + 0.000000 0.000000 0.000000 + + + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 -1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + + + 28.345891875000000 .000000000000000 .000000000000000 + .000000000000000 28.345891875000000 .000000000000000 + .000000000000000 .000000000000000 4.630000000000000 + + + + + + + + + + + + + + + + .0000000000 .0000000000 -.7416991710 + .0000000000 .0000000000 .7416991710 + + + + + + + + + + + + + + + + + + + + + + + + + 0.000000 0.000000 0.000000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/parsers/fixtures/fleur/relax/relax.xml b/tests/parsers/fixtures/fleur/relax/relax.xml new file mode 100644 index 000000000..99be634d9 --- /dev/null +++ b/tests/parsers/fixtures/fleur/relax/relax.xml @@ -0,0 +1,14 @@ + + + + 0.0000000000 0.0000000000 0.0246059526 + + + + 0.0000000000 0.0000000000 -0.7558904500 0.0000000000 0.0000000000 0.0283825580 + + + 0.0000000000 0.0000000000 -0.7416991710 0.0000000000 0.0000000000 0.0208293472 + + + diff --git a/tests/parsers/fixtures/fleur/relax/shell.out b/tests/parsers/fixtures/fleur/relax/shell.out new file mode 100644 index 000000000..333823046 --- /dev/null +++ b/tests/parsers/fixtures/fleur/relax/shell.out @@ -0,0 +1,214 @@ +iffcluster0107: Using InfiniBand for MPI communication. + Welcome to FLEUR (www.flapw.de) + MaX-Release 4.0 (www.max-centre.eu) + nop = 16 + -------------------------------------------------------- + Number of OMP-threads: 12 + -------------------------------------------------------- + Iteration: 1 Distance: 0.163237983230284 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 4 + Time per iter (min): 4 + Iteration: 2 Distance: 0.152278301128890 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 8 + Time per iter (min): 4 + Iteration: 3 Distance: 1.280699031885719E-002 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 11 + Time per iter (min): 4 + Iteration: 4 Distance: 1.544701303213275E-002 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 15 + Time per iter (min): 4 + Iteration: 5 Distance: 4.020987856830026E-003 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 19 + Time per iter (min): 4 + Iteration: 6 Distance: 1.945253362703284E-004 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 23 + Time per iter (min): 4 + Iteration: 7 Distance: 2.468709825867029E-004 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 26 + Time per iter (min): 4 + Iteration: 8 Distance: 1.028491110414090E-004 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 30 + Time per iter (min): 4 + Iteration: 9 Distance: 9.929615259078387E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 34 + Time per iter (min): 4 + Iteration: 10 Distance: 3.876139978531418E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 38 + Time per iter (min): 4 + Iteration: 11 Distance: 5.192625893104915E-006 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 41 + Time per iter (min): 4 + Iteration: 12 Distance: 9.189232451067283E-006 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 45 + Time per iter (min): 4 + Iteration: 13 Distance: 2.783739128832825E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 49 + Time per iter (min): 4 + Iteration: 14 Distance: 4.212128520807909E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 53 + Time per iter (min): 4 + Iteration: 15 Distance: 7.731771252447340E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 57 + Time per iter (min): 4 + Iteration: 16 Distance: 7.768845617471034E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 61 + Time per iter (min): 4 + Iteration: 17 Distance: 7.341253721698628E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 65 + Time per iter (min): 4 + Iteration: 18 Distance: 3.526433224843018E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 69 + Time per iter (min): 4 + Iteration: 19 Distance: 6.266528245181366E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 73 + Time per iter (min): 4 + Iteration: 20 Distance: 7.731238834573022E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 77 + Time per iter (min): 4 + Iteration: 21 Distance: 3.388841940099947E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 81 + Time per iter (min): 4 + Iteration: 22 Distance: 3.230813132151605E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 85 + Time per iter (min): 4 + Iteration: 23 Distance: 3.288678618197010E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 89 + Time per iter (min): 4 + Iteration: 24 Distance: 2.973785652738386E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 94 + Time per iter (min): 4 + Iteration: 25 Distance: 2.924083584706251E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 98 + Time per iter (min): 4 + Iteration: 26 Distance: 2.913527221808891E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 102 + Time per iter (min): 4 + Iteration: 27 Distance: 2.999922005973378E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 106 + Time per iter (min): 4 + Iteration: 28 Distance: 3.008806094258066E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 110 + Time per iter (min): 4 + Iteration: 29 Distance: 3.504814074016484E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 115 + Time per iter (min): 4 + Iteration: 30 Distance: 3.338360515741878E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 119 + Time per iter (min): 4 + Iteration: 31 Distance: 3.842254803335153E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 123 + Time per iter (min): 4 + Iteration: 32 Distance: 4.627627754515800E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 128 + Time per iter (min): 4 + Iteration: 33 Distance: 4.311438958929168E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 132 + Time per iter (min): 4 + Iteration: 34 Distance: 4.488399890836128E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 137 + Time per iter (min): 5 + Iteration: 35 Distance: 4.932233829957257E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 141 + Time per iter (min): 5 + Iteration: 36 Distance: 3.389671397825875E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 146 + Time per iter (min): 5 + Iteration: 37 Distance: 1.990699684397925E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 150 + Time per iter (min): 5 + Iteration: 38 Distance: 2.212929999310191E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 155 + Time per iter (min): 5 + Iteration: 39 Distance: 2.515473192069385E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 159 + Time per iter (min): 5 + Iteration: 40 Distance: 1.265346941883755E-005 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 164 + Time per iter (min): 5 + Iteration: 41 Distance: 1.531689360592881E-006 + Test for time of next iteration: + Time provided (min): 360 + Time used (min): 168 + Time per iter (min): 5 + Reset of history + Usage data send using curl: usage.json diff --git a/tests/parsers/fixtures/inpgen/broken_inpxml/inp.xml b/tests/parsers/fixtures/inpgen/broken_inpxml/inp.xml new file mode 100644 index 000000000..a1dfec490 --- /dev/null +++ b/tests/parsers/fixtures/inpgen/broken_inpxml/inp.xml @@ -0,0 +1,111 @@ + + + + A Fleur input generator calculation with aiida + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + -0.000000 0.333333 0.333333 + -0.333333 0.333333 0.333333 + -0.000000 0.000000 0.333333 + 0.000000 0.000000 0.000000 + + + + + + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + -1 1 0 .0000000000 + -1 0 1 .0000000000 + + + 1 -1 0 .0000000000 + 0 -1 0 .0000000000 + 0 -1 1 .0000000000 + + + 0 -1 0 .0000000000 + 1 -1 0 .0000000000 + 0 -1 1 .0000000000 + + + -1 1 0 .0000000000 + -1 0 0 .0000000000 + -1 0 1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 -1 .0000000000 + 0 1 -1 .0000000000 + 0 0 -1 .0000000000 + + + 0 0 -1 .0000000000 + 0 1 -1 .0000000000 + 1 0 -1 .0000000000 + + + 0 1 -1 .0000000000 + 1 0 -1 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 -1 .0000000000 + 0 0 -1 .0000000000 + 1 0 -1 .0000000000 + + + 1 0 -1 .0000000000 + 0 0 -1 .0000000000 + 0 1 -1 .0000000000 + + + 0 0 -1 .0000000000 + 1 0 -1 .0000000000 + 0 1 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 1 -1 0 .0000000000 + 1 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 -1 0 .0000000000 + diff --git a/tests/parsers/fixtures/inpgen/broken_inpxml/out b/tests/parsers/fixtures/inpgen/broken_inpxml/out new file mode 100644 index 000000000..fca99897b --- /dev/null +++ b/tests/parsers/fixtures/inpgen/broken_inpxml/out @@ -0,0 +1,687 @@ +line: 1>A Fleur input generator calculation with aiida +line: 2>&input cartesian=F / +line: 3>-3.0138120600 3.0138120600 3.0138120600 +line: 4>3.0138120600 -3.0138120600 3.0138120600 +line: 5>3.0138120600 3.0138120600 -3.0138120600 +line: 6>1.0000000000 +line: 7>1.0000000000 1.0000000000 1.0000000000 +line: 8> +line: 9>1 +line: 10>74 0.0000000000 0.0000000000 0.0000000000 +line: 11>&atom +line: 12>econfig="[Kr] 4d10 4f14 | 5s2 5p6 6s2 5d4" element="W" jri=981 lm + + A Fleur input generator calculation with aiida + + film= F cartesian= F + checkinp= F symor= F + +a1 = -3.01381 3.01381 3.01381 +a2 = 3.01381 -3.01381 3.01381 +a3 = 3.01381 3.01381 -3.01381 + +dvac= -3.01381 aa = 1.00000 +scale = 1.00000 1.00000 1.00000 + +natin= 1 Z = 74 + positions: + 0.00000 0.00000 0.00000 + + generators: 0 (excluding identity) + + + Lattice information: + -------------------- + + overall lattice constant a0 = 1.000000 bohr + + real-space primitive lattice vectors in units of a_{x,y,z} + a_1: -3.013812 3.013812 3.013812 + a_2: 3.013812 -3.013812 3.013812 + a_3: 3.013812 3.013812 -3.013812 + + lattice constants a_x, a_y, a_z = 1.000000 1.000000 1.000000 + volume of unit cell (a.u.^3) = 109.498581 + +dbg: lattice matrices + 109.498580847925 +dbg: as : + -3.013812 3.013812 3.013812 + 3.013812 -3.013812 3.013812 + 3.013812 3.013812 -3.013812 +dbg: bs : + 0.000000 0.165903 0.165903 + 0.165903 0.000000 0.165903 + 0.165903 0.165903 0.000000 +dbg: amat : + -3.013812 3.013812 3.013812 + 3.013812 -3.013812 3.013812 + 3.013812 3.013812 -3.013812 +dbg: bmat : + 0.000000 0.521199 0.521199 + 0.521199 0.000000 0.521199 + 0.521199 0.521199 0.000000 +dbg: amatinv : + 0.000000 0.165903 0.165903 + 0.165903 0.000000 0.165903 + 0.165903 0.165903 0.000000 +dbg: aamat : + 27.249189 -9.083063 -9.083063 + -9.083063 27.249189 -9.083063 + -9.083063 -9.083063 27.249189 +dbg: bbmat : + 0.543297 0.271649 0.271649 + 0.271649 0.543297 0.271649 + 0.271649 0.271649 0.543297 + +dbg: lattice vectors : +vector 1 : -3.01381 3.01381 3.01381 length : 5.22008 +vector 2 : 3.01381 -3.01381 3.01381 length : 5.22008 +vector 3 : 3.01381 3.01381 -3.01381 length : 5.22008 +angle between vectors (1,2) =109.47122 +angle between vectors (1,3) =109.47122 +angle between vectors (2,3) =109.47122 + +dbg: reciprocal lattice vectors : +vector 1 : 0.00000 0.52120 0.52120 length : 0.73709 +vector 2 : 0.52120 0.00000 0.52120 length : 0.73709 +vector 3 : 0.52120 0.52120 0.00000 length : 0.73709 +angle between vectors (1,2) = 60.00000 +angle between vectors (1,3) = 60.00000 +angle between vectors (2,3) = 60.00000 + + + Point group of the Bravais lattice has 48 operations + + DBG: symor,zorth,oldfleur : T F F + DBG: optype : 1 -2 -2 3 3 -2 -2 3 2 -4 3 -4 -1 2 2 -3 -3 2 2 -2 -3 4 4 -3 -3 4 2 -3 -2 4 3 -2 -4 2 -4 3 3 -4 -4 3 -2 2 4 -3 -3 2 4 -2 + DBG: invsym,invs,zrfs,invs2 : T T F F + DBG: (before reorder) invsop,zrfsop,invs2op : 13 7 46 + + Space group information: + ------------------------ + 48 operations + space group is symmorphic + has inversion symmetry + + + Operations: (in International notation) + --------------------------------------- + lattice coordinates (scaled) Cartesian coordinates + + operation 1: 1 (inverse = 1) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + _ + operation 2: 2 (inverse = 2) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + _ + operation 3: 2 (inverse = 3) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + + operation 4: 3 (inverse = 5) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + + operation 5: 3 (inverse = 4) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + _ + operation 6: 2 (inverse = 6) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + _ + operation 7: 2 (inverse = 7) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + + operation 8: 3 (inverse = 31) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + + operation 9: 2 (inverse = 9) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + _ + operation 10: 4 (inverse = 33) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + + operation 11: 3 (inverse = 37) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + _ + operation 12: 4 (inverse = 39) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + _ + operation 13: 1 (inverse = 13) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + + operation 14: 2 (inverse = 14) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + + operation 15: 2 (inverse = 15) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + _ + operation 16: 3 (inverse = 17) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + _ + operation 17: 3 (inverse = 16) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + + operation 18: 2 (inverse = 18) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + + operation 19: 2 (inverse = 19) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + _ + operation 20: 2 (inverse = 20) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + _ + operation 21: 3 (inverse = 25) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + + operation 22: 4 (inverse = 43) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + + operation 23: 4 (inverse = 26) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + _ + operation 24: 3 (inverse = 44) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + _ + operation 25: 3 (inverse = 21) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + + operation 26: 4 (inverse = 23) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + + operation 27: 2 (inverse = 27) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + _ + operation 28: 3 (inverse = 45) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + _ + operation 29: 2 (inverse = 29) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + + operation 30: 4 (inverse = 47) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + + operation 31: 3 (inverse = 8) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + _ + operation 32: 2 (inverse = 32) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + _ + operation 33: 4 (inverse = 10) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + + operation 34: 2 (inverse = 34) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + _ + operation 35: 4 (inverse = 38) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + + operation 36: 3 (inverse = 40) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + + operation 37: 3 (inverse = 11) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + _ + operation 38: 4 (inverse = 35) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + _ + operation 39: 4 (inverse = 12) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + + operation 40: 3 (inverse = 36) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + _ + operation 41: 2 (inverse = 41) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + + operation 42: 2 (inverse = 42) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + + operation 43: 4 (inverse = 22) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + _ + operation 44: 3 (inverse = 24) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + _ + operation 45: 3 (inverse = 28) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + + operation 46: 2 (inverse = 46) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + + operation 47: 4 (inverse = 30) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + _ + operation 48: 2 (inverse = 48) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + + Multiplcation table: {R_j|t_j}{R_i|t_i} + operation j= 1 : 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 + operation j= 2 : 2 1 5 6 3 4 31 32 33 34 35 36 + 14 13 17 18 15 16 20 19 23 24 21 22 + 43 44 45 46 47 48 7 8 9 10 11 12 + 39 40 37 38 42 41 25 26 27 28 29 30 + operation j= 3 : 3 4 1 2 6 5 37 38 39 40 41 42 + 18 17 16 15 14 13 44 43 47 48 45 46 + 26 25 29 30 27 28 33 34 31 32 36 35 + 7 8 9 10 11 12 20 19 23 24 21 22 + operation j= 4 : 4 3 6 5 1 2 33 34 31 32 36 35 + 17 18 14 13 16 15 43 44 45 46 47 48 + 20 19 23 24 21 22 37 38 39 40 41 42 + 9 10 7 8 12 11 26 25 29 30 27 28 + operation j= 5 : 5 6 2 1 4 3 39 40 37 38 42 41 + 16 15 18 17 13 14 26 25 29 30 27 28 + 44 43 47 48 45 46 9 10 7 8 12 11 + 31 32 33 34 35 36 19 20 21 22 23 24 + operation j= 6 : 6 5 4 3 2 1 9 10 7 8 12 11 + 15 16 13 14 18 17 25 26 27 28 29 30 + 19 20 21 22 23 24 39 40 37 38 42 41 + 33 34 31 32 36 35 44 43 47 48 45 46 + operation j= 7 : 7 8 11 12 10 9 1 2 6 5 3 4 + 46 45 48 47 43 44 24 23 22 21 20 19 + 30 29 28 27 26 25 32 31 36 35 34 33 + 41 42 40 39 37 38 17 18 14 13 16 15 + operation j= 8 : 8 7 10 9 11 12 32 31 36 35 34 33 + 45 46 43 44 48 47 23 24 20 19 22 21 + 17 18 14 13 16 15 1 2 6 5 3 4 + 40 39 41 42 38 37 30 29 28 27 26 25 + operation j= 9 : 9 10 12 11 8 7 6 5 1 2 4 3 + 48 47 46 45 44 43 30 29 28 27 26 25 + 24 23 22 21 20 19 40 39 41 42 38 37 + 36 35 32 31 33 34 18 17 16 15 14 13 + operation j=10 : 10 9 8 7 12 11 40 39 41 42 38 37 + 47 48 44 43 46 45 29 30 26 25 28 27 + 18 17 16 15 14 13 6 5 1 2 4 3 + 32 31 36 35 34 33 24 23 22 21 20 19 + operation j=11 : 11 12 7 8 9 10 41 42 40 39 37 38 + 44 43 47 48 45 46 18 17 16 15 14 13 + 29 30 26 25 28 27 36 35 32 31 33 34 + 1 2 6 5 3 4 23 24 20 19 22 21 + operation j=12 : 12 11 9 10 7 8 36 35 32 31 33 34 + 43 44 45 46 47 48 17 18 14 13 16 15 + 23 24 20 19 22 21 41 42 40 39 37 38 + 6 5 1 2 4 3 29 30 26 25 28 27 + operation j=13 : 13 14 18 17 16 15 46 45 48 47 44 43 + 1 2 6 5 4 3 41 42 40 39 38 37 + 36 35 32 31 34 33 28 27 30 29 26 25 + 24 23 22 21 19 20 12 11 8 7 10 9 + operation j=14 : 14 13 16 15 18 17 28 27 30 29 26 25 + 2 1 4 3 6 5 42 41 38 37 40 39 + 12 11 8 7 10 9 46 45 48 47 44 43 + 22 21 24 23 20 19 36 35 32 31 34 33 + operation j=15 : 15 16 17 18 14 13 48 47 46 45 43 44 + 6 5 1 2 3 4 36 35 32 31 34 33 + 41 42 40 39 38 37 22 21 24 23 20 19 + 30 29 28 27 25 26 11 12 10 9 8 7 + operation j=16 : 16 15 14 13 17 18 22 21 24 23 20 19 + 5 6 3 4 1 2 35 36 34 33 32 31 + 11 12 10 9 8 7 48 47 46 45 43 44 + 28 27 30 29 26 25 41 42 40 39 38 37 + operation j=17 : 17 18 15 16 13 14 30 29 28 27 25 26 + 4 3 2 1 5 6 12 11 8 7 10 9 + 42 41 38 37 40 39 24 23 22 21 19 20 + 48 47 46 45 43 44 35 36 34 33 32 31 + operation j=18 : 18 17 13 14 15 16 24 23 22 21 19 20 + 3 4 5 6 2 1 11 12 10 9 8 7 + 35 36 34 33 32 31 30 29 28 27 25 26 + 46 45 48 47 44 43 42 41 38 37 40 39 + operation j=19 : 19 20 24 23 22 21 44 43 47 48 46 45 + 41 42 40 39 38 37 1 2 6 5 4 3 + 32 31 36 35 33 34 26 25 29 30 28 27 + 18 17 16 15 13 14 8 7 12 11 9 10 + operation j=20 : 20 19 22 21 24 23 26 25 29 30 28 27 + 42 41 38 37 40 39 2 1 4 3 6 5 + 8 7 12 11 9 10 44 43 47 48 46 45 + 16 15 18 17 14 13 32 31 36 35 33 34 + operation j=21 : 21 22 23 24 20 19 47 48 44 43 45 46 + 40 39 41 42 37 38 32 31 36 35 33 34 + 1 2 6 5 4 3 16 15 18 17 14 13 + 29 30 26 25 27 28 7 8 9 10 12 11 + operation j=22 : 22 21 20 19 23 24 16 15 18 17 14 13 + 39 40 37 38 41 42 31 32 33 34 36 35 + 7 8 9 10 12 11 47 48 44 43 45 46 + 26 25 29 30 28 27 1 2 6 5 4 3 + operation j=23 : 23 24 21 22 19 20 29 30 26 25 27 28 + 38 37 42 41 39 40 8 7 12 11 9 10 + 2 1 4 3 6 5 18 17 16 15 13 14 + 47 48 44 43 45 46 31 32 33 34 36 35 + operation j=24 : 24 23 19 20 21 22 18 17 16 15 13 14 + 37 38 39 40 42 41 7 8 9 10 12 11 + 31 32 33 34 36 35 29 30 26 25 27 28 + 44 43 47 48 46 45 2 1 4 3 6 5 + operation j=25 : 25 26 30 29 28 27 43 44 45 46 48 47 + 36 35 32 31 34 33 6 5 1 2 3 4 + 40 39 41 42 37 38 20 19 23 24 22 21 + 17 18 14 13 15 16 10 9 11 12 7 8 + operation j=26 : 26 25 28 27 30 29 20 19 23 24 22 21 + 35 36 34 33 32 31 5 6 3 4 1 2 + 10 9 11 12 7 8 43 44 45 46 48 47 + 14 13 17 18 16 15 40 39 41 42 37 38 + operation j=27 : 27 28 29 30 26 25 45 46 43 44 47 48 + 32 31 36 35 33 34 40 39 41 42 37 38 + 6 5 1 2 3 4 14 13 17 18 16 15 + 23 24 20 19 21 22 9 10 7 8 11 12 + operation j=28 : 28 27 26 25 29 30 14 13 17 18 16 15 + 31 32 33 34 36 35 39 40 37 38 41 42 + 9 10 7 8 11 12 45 46 43 44 47 48 + 20 19 23 24 22 21 6 5 1 2 3 4 + operation j=29 : 29 30 27 28 25 26 23 24 20 19 21 22 + 34 33 35 36 31 32 10 9 11 12 7 8 + 5 6 3 4 1 2 17 18 14 13 15 16 + 45 46 43 44 47 48 39 40 37 38 41 42 + operation j=30 : 30 29 25 26 27 28 17 18 14 13 15 16 + 33 34 31 32 35 36 9 10 7 8 11 12 + 39 40 37 38 41 42 23 24 20 19 21 22 + 43 44 45 46 48 47 5 6 3 4 1 2 + operation j=31 : 31 32 35 36 34 33 2 1 4 3 5 6 + 28 27 30 29 25 26 22 21 24 23 19 20 + 48 47 46 45 44 43 8 7 12 11 10 9 + 42 41 38 37 39 40 15 16 13 14 18 17 + operation j=32 : 32 31 34 33 35 36 8 7 12 11 10 9 + 27 28 25 26 30 29 21 22 19 20 24 23 + 15 16 13 14 18 17 2 1 4 3 5 6 + 38 37 42 41 40 39 48 47 46 45 44 43 + operation j=33 : 33 34 36 35 32 31 4 3 2 1 6 5 + 30 29 28 27 26 25 48 47 46 45 44 43 + 22 21 24 23 19 20 38 37 42 41 40 39 + 12 11 8 7 9 10 16 15 18 17 13 14 + operation j=34 : 34 33 32 31 36 35 38 37 42 41 40 39 + 29 30 26 25 28 27 47 48 44 43 46 45 + 16 15 18 17 13 14 4 3 2 1 6 5 + 8 7 12 11 10 9 22 21 24 23 19 20 + operation j=35 : 35 36 31 32 33 34 42 41 38 37 39 40 + 26 25 29 30 27 28 16 15 18 17 13 14 + 47 48 44 43 46 45 12 11 8 7 9 10 + 2 1 4 3 5 6 21 22 19 20 24 23 + operation j=36 : 36 35 33 34 31 32 12 11 8 7 9 10 + 25 26 27 28 29 30 15 16 13 14 18 17 + 21 22 19 20 24 23 42 41 38 37 39 40 + 4 3 2 1 6 5 47 48 44 43 46 45 + operation j=37 : 37 38 41 42 40 39 3 4 5 6 1 2 + 24 23 22 21 20 19 46 45 48 47 43 44 + 28 27 30 29 25 26 34 33 35 36 32 31 + 11 12 10 9 7 8 14 13 17 18 15 16 + operation j=38 : 38 37 40 39 41 42 34 33 35 36 32 31 + 23 24 20 19 22 21 45 46 43 44 48 47 + 14 13 17 18 15 16 3 4 5 6 1 2 + 10 9 11 12 8 7 28 27 30 29 25 26 + operation j=39 : 39 40 42 41 38 37 5 6 3 4 2 1 + 22 21 24 23 19 20 28 27 30 29 25 26 + 46 45 48 47 43 44 10 9 11 12 8 7 + 35 36 34 33 31 32 13 14 15 16 17 18 + operation j=40 : 40 39 38 37 42 41 10 9 11 12 8 7 + 21 22 19 20 24 23 27 28 25 26 30 29 + 13 14 15 16 17 18 5 6 3 4 2 1 + 34 33 35 36 32 31 46 45 48 47 43 44 + operation j=41 : 41 42 37 38 39 40 11 12 10 9 7 8 + 19 20 21 22 23 24 13 14 15 16 17 18 + 27 28 25 26 30 29 35 36 34 33 31 32 + 3 4 5 6 1 2 45 46 43 44 48 47 + operation j=42 : 42 41 39 40 37 38 35 36 34 33 31 32 + 20 19 23 24 21 22 14 13 17 18 15 16 + 45 46 43 44 48 47 11 12 10 9 7 8 + 5 6 3 4 2 1 27 28 25 26 30 29 + operation j=43 : 43 44 48 47 46 45 25 26 27 28 30 29 + 12 11 8 7 10 9 4 3 2 1 5 6 + 38 37 42 41 39 40 19 20 21 22 24 23 + 15 16 13 14 17 18 34 33 35 36 31 32 + operation j=44 : 44 43 46 45 48 47 19 20 21 22 24 23 + 11 12 10 9 8 7 3 4 5 6 2 1 + 34 33 35 36 31 32 25 26 27 28 30 29 + 13 14 15 16 18 17 38 37 42 41 39 40 + operation j=45 : 45 46 47 48 44 43 27 28 25 26 29 30 + 8 7 12 11 9 10 38 37 42 41 39 40 + 4 3 2 1 5 6 13 14 15 16 18 17 + 21 22 19 20 23 24 33 34 31 32 35 36 + operation j=46 : 46 45 44 43 47 48 13 14 15 16 18 17 + 7 8 9 10 12 11 37 38 39 40 42 41 + 33 34 31 32 35 36 27 28 25 26 29 30 + 19 20 21 22 24 23 4 3 2 1 5 6 + operation j=47 : 47 48 45 46 43 44 21 22 19 20 23 24 + 10 9 11 12 7 8 34 33 35 36 31 32 + 3 4 5 6 2 1 15 16 13 14 17 18 + 27 28 25 26 29 30 37 38 39 40 42 41 + operation j=48 : 48 47 43 44 45 46 15 16 13 14 17 18 + 9 10 7 8 11 12 33 34 31 32 35 36 + 37 38 39 40 42 41 21 22 19 20 23 24 + 25 26 27 28 30 29 3 4 5 6 2 1 + + + Space group can be generated using 5 generators: 13 4 9 34 2 + + generators (in lattice coordinates): + +&gen 5 + + -1 0 0 0.00000 + 0 -1 0 0.00000 + 0 0 -1 0.00000 + + 0 -1 0 0.00000 + 1 -1 0 0.00000 + 0 -1 1 0.00000 + + 0 1 -1 0.00000 + 1 0 -1 0.00000 + 0 0 -1 0.00000 + + 0 -1 1 0.00000 + 0 -1 0 0.00000 + 1 -1 0 0.00000 + + -1 0 0 0.00000 + -1 1 0 0.00000 + -1 0 1 0.00000 + +/ ! end generators + + + + Atomic positions: + ----------------- + atom types = 1 + total = 1 + + lattice coordinates (scaled) Cartesian coordinates atom + + atom type 1: atomic identification number = 74.0 representative = 1 + 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1 + +atoms% 1 atoms 1 + Z( 1)= 74 atoms 1 + 0.000000 0.000000 0.000000 1 + ---------------------------------------------------- + Suggested values for input: + + Atom Z lmax jri rmt dx + W 74 10 841 2.544787 0.015844 +k_max = 3.92960 +G_max =11.78881 + + =============================================== + === modifying atomic input for &(all)atom === + =============================================== + +for atom 1 ( W) changed rmt to 2.100000 +for atom 1 ( W) changed jri to 981 +for atom 1 ( W) changed lmax to 12 +for atom 1 ( W) changed lnonsph to 6 +for atom 1 ( W) set econfig to [Kr] 4d10 4f14 | 5s2 5p6 6s2 5d4 + corestates = 16 with 60.0 electrons + valence st.= 5 with 14.0 electrons +nlod = 2 llod = 1 : 5s5p + nlo( 1) = 2 llo = 0 1 + lonqn = 5 5 +line: 13>&comp +line: 14>gmax=15.0 gmaxxc=12.5 kmax=5.0 / + ---------- + core : 1 -1 2.0 + core : 2 -1 2.0 + core : 2 1 2.0 + core : 2 -2 4.0 + core : 3 -1 2.0 + core : 3 1 2.0 + core : 3 -2 4.0 + core : 3 2 4.0 + core : 3 -3 6.0 + core : 4 -1 2.0 + core : 4 1 2.0 + core : 4 -2 4.0 + core : 4 2 4.0 + core : 4 -3 6.0 + core : 4 3 6.0 + core : 4 -4 8.0 + valence : 5 -1 2.0 5s + valence : 5 1 2.0 5p + valence : 5 -2 4.0 5p + valence : 6 -1 2.0 6s + valence : 5 2 2.0 5d + valence : 5 -3 2.0 5d + ---------- +Valence Electrons = 14 + ---------------------------------------------------- + Suggested values for input: + + Atom Z lmax jri rmt dx + W 74 10 841 2.544787 0.015844 +k_max = 3.92960 +G_max =11.78881 +line: 15>&kpt +line: 16>div1=3 div2=3 div3=3 tkb=0.0005 / + 5.22007561238382 5.22007561238382 5.22007561238382 + -0.333333333333333 -0.333333333333333 -0.333333333333333 + body centered cubic + values accepted unchanged + 3 3 3 nmop(i),i=1,3 + orientation of boundary faces + 1 -1 -0.5740361 ifac,iside,orient for xvec + 2 -1 -0.0454288 ifac,iside,orient for xvec + 3 -1 -0.0256305 ifac,iside,orient for xvec + 4 -1 -0.0469244 ifac,iside,orient for xvec +Bravais lattice vectors + -3.013812 3.013812 3.013812 + 3.013812 -3.013812 3.013812 + 3.013812 3.013812 -3.013812 +reciprocal lattice vectors + 0.000000 1.042398 1.042398 + 1.042398 0.000000 1.042398 + 1.042398 1.042398 0.000000 + 3 3 3 Monkhorst-Pack-parameters + 0 nreg; k-points in irreducible wedge of BZ + Monkhorst-Pack-fractions + 0 nbound; no k-points on boundary of BZ + 1 idim + -0.3333333 + 0.0000000 + 0.3333333 + 2 idim + -0.3333333 + 0.0000000 + 0.3333333 + 3 idim + -0.3333333 + 0.0000000 + 0.3333333 + +k-point count: 4 + +k-point mesh: 3 3 3 +k-point density: 2.035038 2.035038 2.035038 + diff --git a/tests/parsers/fixtures/inpgen/broken_inpxml/out.error b/tests/parsers/fixtures/inpgen/broken_inpxml/out.error new file mode 100644 index 000000000..e69de29bb diff --git a/tests/parsers/fixtures/inpgen/default/inp.xml b/tests/parsers/fixtures/inpgen/default/inp.xml new file mode 100644 index 000000000..2bf34f24c --- /dev/null +++ b/tests/parsers/fixtures/inpgen/default/inp.xml @@ -0,0 +1,319 @@ + + + + A Fleur input generator calculation with aiida + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + -0.000000 0.333333 0.333333 + -0.333333 0.333333 0.333333 + -0.000000 0.000000 0.333333 + 0.000000 0.000000 0.000000 + + + + + + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + -1 1 0 .0000000000 + -1 0 1 .0000000000 + + + 1 -1 0 .0000000000 + 0 -1 0 .0000000000 + 0 -1 1 .0000000000 + + + 0 -1 0 .0000000000 + 1 -1 0 .0000000000 + 0 -1 1 .0000000000 + + + -1 1 0 .0000000000 + -1 0 0 .0000000000 + -1 0 1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 -1 .0000000000 + 0 1 -1 .0000000000 + 0 0 -1 .0000000000 + + + 0 0 -1 .0000000000 + 0 1 -1 .0000000000 + 1 0 -1 .0000000000 + + + 0 1 -1 .0000000000 + 1 0 -1 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 -1 .0000000000 + 0 0 -1 .0000000000 + 1 0 -1 .0000000000 + + + 1 0 -1 .0000000000 + 0 0 -1 .0000000000 + 0 1 -1 .0000000000 + + + 0 0 -1 .0000000000 + 1 0 -1 .0000000000 + 0 1 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 1 -1 0 .0000000000 + 1 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 -1 0 .0000000000 + 1 0 0 .0000000000 + 1 0 -1 .0000000000 + + + 0 1 0 .0000000000 + -1 1 0 .0000000000 + 0 1 -1 .0000000000 + + + -1 1 0 .0000000000 + 0 1 0 .0000000000 + 0 1 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + + + 1 0 0 .0000000000 + 1 0 -1 .0000000000 + 1 -1 0 .0000000000 + + + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + + + 1 -1 0 .0000000000 + 1 0 -1 .0000000000 + 1 0 0 .0000000000 + + + 0 1 0 .0000000000 + 0 1 -1 .0000000000 + -1 1 0 .0000000000 + + + -1 1 0 .0000000000 + 0 1 -1 .0000000000 + 0 1 0 .0000000000 + + + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + + + 1 0 -1 .0000000000 + 1 0 0 .0000000000 + 1 -1 0 .0000000000 + + + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + + + 1 0 -1 .0000000000 + 1 -1 0 .0000000000 + 1 0 0 .0000000000 + + + 0 1 -1 .0000000000 + 0 1 0 .0000000000 + -1 1 0 .0000000000 + + + 0 1 -1 .0000000000 + -1 1 0 .0000000000 + 0 1 0 .0000000000 + + + -1 0 1 .0000000000 + -1 1 0 .0000000000 + -1 0 0 .0000000000 + + + 0 0 1 .0000000000 + 0 1 0 .0000000000 + 1 0 0 .0000000000 + + + 0 -1 1 .0000000000 + 1 -1 0 .0000000000 + 0 -1 0 .0000000000 + + + 0 -1 1 .0000000000 + 0 -1 0 .0000000000 + 1 -1 0 .0000000000 + + + -1 0 1 .0000000000 + -1 0 0 .0000000000 + -1 1 0 .0000000000 + + + 0 0 1 .0000000000 + 1 0 0 .0000000000 + 0 1 0 .0000000000 + + + 1 -1 0 .0000000000 + 0 -1 1 .0000000000 + 0 -1 0 .0000000000 + + + 0 -1 0 .0000000000 + 0 -1 1 .0000000000 + 1 -1 0 .0000000000 + + + -1 1 0 .0000000000 + -1 0 1 .0000000000 + -1 0 0 .0000000000 + + + 0 1 0 .0000000000 + 0 0 1 .0000000000 + 1 0 0 .0000000000 + + + 1 0 0 .0000000000 + 0 0 1 .0000000000 + 0 1 0 .0000000000 + + + -1 0 0 .0000000000 + -1 0 1 .0000000000 + -1 1 0 .0000000000 + + + 0 0 1 .0000000000 + -1 0 1 .0000000000 + 0 -1 1 .0000000000 + + + -1 0 1 .0000000000 + 0 0 1 .0000000000 + 0 -1 1 .0000000000 + + + 0 0 1 .0000000000 + 0 -1 1 .0000000000 + -1 0 1 .0000000000 + + + -1 0 1 .0000000000 + 0 -1 1 .0000000000 + 0 0 1 .0000000000 + + + 0 -1 1 .0000000000 + 0 0 1 .0000000000 + -1 0 1 .0000000000 + + + 0 -1 1 .0000000000 + -1 0 1 .0000000000 + 0 0 1 .0000000000 + + + + + -3.013812060000000 3.013812060000000 3.013812060000000 + 3.013812060000000 -3.013812060000000 3.013812060000000 + 3.013812060000000 3.013812060000000 -3.013812060000000 + + + + + + + + + + + + [Kr] (4d3/2) (4d5/2) (4f5/2) (4f7/2) + (5s1/2) (5p1/2) (5p3/2) (6s1/2) (5d3/2) (5d5/2) + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + + + + + + + + + + + diff --git a/tests/parsers/fixtures/inpgen/default/out b/tests/parsers/fixtures/inpgen/default/out new file mode 100644 index 000000000..fca99897b --- /dev/null +++ b/tests/parsers/fixtures/inpgen/default/out @@ -0,0 +1,687 @@ +line: 1>A Fleur input generator calculation with aiida +line: 2>&input cartesian=F / +line: 3>-3.0138120600 3.0138120600 3.0138120600 +line: 4>3.0138120600 -3.0138120600 3.0138120600 +line: 5>3.0138120600 3.0138120600 -3.0138120600 +line: 6>1.0000000000 +line: 7>1.0000000000 1.0000000000 1.0000000000 +line: 8> +line: 9>1 +line: 10>74 0.0000000000 0.0000000000 0.0000000000 +line: 11>&atom +line: 12>econfig="[Kr] 4d10 4f14 | 5s2 5p6 6s2 5d4" element="W" jri=981 lm + + A Fleur input generator calculation with aiida + + film= F cartesian= F + checkinp= F symor= F + +a1 = -3.01381 3.01381 3.01381 +a2 = 3.01381 -3.01381 3.01381 +a3 = 3.01381 3.01381 -3.01381 + +dvac= -3.01381 aa = 1.00000 +scale = 1.00000 1.00000 1.00000 + +natin= 1 Z = 74 + positions: + 0.00000 0.00000 0.00000 + + generators: 0 (excluding identity) + + + Lattice information: + -------------------- + + overall lattice constant a0 = 1.000000 bohr + + real-space primitive lattice vectors in units of a_{x,y,z} + a_1: -3.013812 3.013812 3.013812 + a_2: 3.013812 -3.013812 3.013812 + a_3: 3.013812 3.013812 -3.013812 + + lattice constants a_x, a_y, a_z = 1.000000 1.000000 1.000000 + volume of unit cell (a.u.^3) = 109.498581 + +dbg: lattice matrices + 109.498580847925 +dbg: as : + -3.013812 3.013812 3.013812 + 3.013812 -3.013812 3.013812 + 3.013812 3.013812 -3.013812 +dbg: bs : + 0.000000 0.165903 0.165903 + 0.165903 0.000000 0.165903 + 0.165903 0.165903 0.000000 +dbg: amat : + -3.013812 3.013812 3.013812 + 3.013812 -3.013812 3.013812 + 3.013812 3.013812 -3.013812 +dbg: bmat : + 0.000000 0.521199 0.521199 + 0.521199 0.000000 0.521199 + 0.521199 0.521199 0.000000 +dbg: amatinv : + 0.000000 0.165903 0.165903 + 0.165903 0.000000 0.165903 + 0.165903 0.165903 0.000000 +dbg: aamat : + 27.249189 -9.083063 -9.083063 + -9.083063 27.249189 -9.083063 + -9.083063 -9.083063 27.249189 +dbg: bbmat : + 0.543297 0.271649 0.271649 + 0.271649 0.543297 0.271649 + 0.271649 0.271649 0.543297 + +dbg: lattice vectors : +vector 1 : -3.01381 3.01381 3.01381 length : 5.22008 +vector 2 : 3.01381 -3.01381 3.01381 length : 5.22008 +vector 3 : 3.01381 3.01381 -3.01381 length : 5.22008 +angle between vectors (1,2) =109.47122 +angle between vectors (1,3) =109.47122 +angle between vectors (2,3) =109.47122 + +dbg: reciprocal lattice vectors : +vector 1 : 0.00000 0.52120 0.52120 length : 0.73709 +vector 2 : 0.52120 0.00000 0.52120 length : 0.73709 +vector 3 : 0.52120 0.52120 0.00000 length : 0.73709 +angle between vectors (1,2) = 60.00000 +angle between vectors (1,3) = 60.00000 +angle between vectors (2,3) = 60.00000 + + + Point group of the Bravais lattice has 48 operations + + DBG: symor,zorth,oldfleur : T F F + DBG: optype : 1 -2 -2 3 3 -2 -2 3 2 -4 3 -4 -1 2 2 -3 -3 2 2 -2 -3 4 4 -3 -3 4 2 -3 -2 4 3 -2 -4 2 -4 3 3 -4 -4 3 -2 2 4 -3 -3 2 4 -2 + DBG: invsym,invs,zrfs,invs2 : T T F F + DBG: (before reorder) invsop,zrfsop,invs2op : 13 7 46 + + Space group information: + ------------------------ + 48 operations + space group is symmorphic + has inversion symmetry + + + Operations: (in International notation) + --------------------------------------- + lattice coordinates (scaled) Cartesian coordinates + + operation 1: 1 (inverse = 1) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + _ + operation 2: 2 (inverse = 2) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + _ + operation 3: 2 (inverse = 3) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + + operation 4: 3 (inverse = 5) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + + operation 5: 3 (inverse = 4) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + _ + operation 6: 2 (inverse = 6) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + _ + operation 7: 2 (inverse = 7) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + + operation 8: 3 (inverse = 31) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + + operation 9: 2 (inverse = 9) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + _ + operation 10: 4 (inverse = 33) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + + operation 11: 3 (inverse = 37) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + _ + operation 12: 4 (inverse = 39) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + _ + operation 13: 1 (inverse = 13) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + + operation 14: 2 (inverse = 14) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + + operation 15: 2 (inverse = 15) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + _ + operation 16: 3 (inverse = 17) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + _ + operation 17: 3 (inverse = 16) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + + operation 18: 2 (inverse = 18) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + + operation 19: 2 (inverse = 19) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + _ + operation 20: 2 (inverse = 20) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + _ + operation 21: 3 (inverse = 25) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + + operation 22: 4 (inverse = 43) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + + operation 23: 4 (inverse = 26) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + _ + operation 24: 3 (inverse = 44) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + _ + operation 25: 3 (inverse = 21) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + + operation 26: 4 (inverse = 23) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + + operation 27: 2 (inverse = 27) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + _ + operation 28: 3 (inverse = 45) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + _ + operation 29: 2 (inverse = 29) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + + operation 30: 4 (inverse = 47) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + + operation 31: 3 (inverse = 8) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + _ + operation 32: 2 (inverse = 32) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + _ + operation 33: 4 (inverse = 10) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + + operation 34: 2 (inverse = 34) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + _ + operation 35: 4 (inverse = 38) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + + operation 36: 3 (inverse = 40) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + + operation 37: 3 (inverse = 11) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + _ + operation 38: 4 (inverse = 35) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + _ + operation 39: 4 (inverse = 12) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + + operation 40: 3 (inverse = 36) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + _ + operation 41: 2 (inverse = 41) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + + operation 42: 2 (inverse = 42) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + + operation 43: 4 (inverse = 22) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + _ + operation 44: 3 (inverse = 24) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + _ + operation 45: 3 (inverse = 28) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + + operation 46: 2 (inverse = 46) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + + operation 47: 4 (inverse = 30) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + _ + operation 48: 2 (inverse = 48) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + + Multiplcation table: {R_j|t_j}{R_i|t_i} + operation j= 1 : 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 + operation j= 2 : 2 1 5 6 3 4 31 32 33 34 35 36 + 14 13 17 18 15 16 20 19 23 24 21 22 + 43 44 45 46 47 48 7 8 9 10 11 12 + 39 40 37 38 42 41 25 26 27 28 29 30 + operation j= 3 : 3 4 1 2 6 5 37 38 39 40 41 42 + 18 17 16 15 14 13 44 43 47 48 45 46 + 26 25 29 30 27 28 33 34 31 32 36 35 + 7 8 9 10 11 12 20 19 23 24 21 22 + operation j= 4 : 4 3 6 5 1 2 33 34 31 32 36 35 + 17 18 14 13 16 15 43 44 45 46 47 48 + 20 19 23 24 21 22 37 38 39 40 41 42 + 9 10 7 8 12 11 26 25 29 30 27 28 + operation j= 5 : 5 6 2 1 4 3 39 40 37 38 42 41 + 16 15 18 17 13 14 26 25 29 30 27 28 + 44 43 47 48 45 46 9 10 7 8 12 11 + 31 32 33 34 35 36 19 20 21 22 23 24 + operation j= 6 : 6 5 4 3 2 1 9 10 7 8 12 11 + 15 16 13 14 18 17 25 26 27 28 29 30 + 19 20 21 22 23 24 39 40 37 38 42 41 + 33 34 31 32 36 35 44 43 47 48 45 46 + operation j= 7 : 7 8 11 12 10 9 1 2 6 5 3 4 + 46 45 48 47 43 44 24 23 22 21 20 19 + 30 29 28 27 26 25 32 31 36 35 34 33 + 41 42 40 39 37 38 17 18 14 13 16 15 + operation j= 8 : 8 7 10 9 11 12 32 31 36 35 34 33 + 45 46 43 44 48 47 23 24 20 19 22 21 + 17 18 14 13 16 15 1 2 6 5 3 4 + 40 39 41 42 38 37 30 29 28 27 26 25 + operation j= 9 : 9 10 12 11 8 7 6 5 1 2 4 3 + 48 47 46 45 44 43 30 29 28 27 26 25 + 24 23 22 21 20 19 40 39 41 42 38 37 + 36 35 32 31 33 34 18 17 16 15 14 13 + operation j=10 : 10 9 8 7 12 11 40 39 41 42 38 37 + 47 48 44 43 46 45 29 30 26 25 28 27 + 18 17 16 15 14 13 6 5 1 2 4 3 + 32 31 36 35 34 33 24 23 22 21 20 19 + operation j=11 : 11 12 7 8 9 10 41 42 40 39 37 38 + 44 43 47 48 45 46 18 17 16 15 14 13 + 29 30 26 25 28 27 36 35 32 31 33 34 + 1 2 6 5 3 4 23 24 20 19 22 21 + operation j=12 : 12 11 9 10 7 8 36 35 32 31 33 34 + 43 44 45 46 47 48 17 18 14 13 16 15 + 23 24 20 19 22 21 41 42 40 39 37 38 + 6 5 1 2 4 3 29 30 26 25 28 27 + operation j=13 : 13 14 18 17 16 15 46 45 48 47 44 43 + 1 2 6 5 4 3 41 42 40 39 38 37 + 36 35 32 31 34 33 28 27 30 29 26 25 + 24 23 22 21 19 20 12 11 8 7 10 9 + operation j=14 : 14 13 16 15 18 17 28 27 30 29 26 25 + 2 1 4 3 6 5 42 41 38 37 40 39 + 12 11 8 7 10 9 46 45 48 47 44 43 + 22 21 24 23 20 19 36 35 32 31 34 33 + operation j=15 : 15 16 17 18 14 13 48 47 46 45 43 44 + 6 5 1 2 3 4 36 35 32 31 34 33 + 41 42 40 39 38 37 22 21 24 23 20 19 + 30 29 28 27 25 26 11 12 10 9 8 7 + operation j=16 : 16 15 14 13 17 18 22 21 24 23 20 19 + 5 6 3 4 1 2 35 36 34 33 32 31 + 11 12 10 9 8 7 48 47 46 45 43 44 + 28 27 30 29 26 25 41 42 40 39 38 37 + operation j=17 : 17 18 15 16 13 14 30 29 28 27 25 26 + 4 3 2 1 5 6 12 11 8 7 10 9 + 42 41 38 37 40 39 24 23 22 21 19 20 + 48 47 46 45 43 44 35 36 34 33 32 31 + operation j=18 : 18 17 13 14 15 16 24 23 22 21 19 20 + 3 4 5 6 2 1 11 12 10 9 8 7 + 35 36 34 33 32 31 30 29 28 27 25 26 + 46 45 48 47 44 43 42 41 38 37 40 39 + operation j=19 : 19 20 24 23 22 21 44 43 47 48 46 45 + 41 42 40 39 38 37 1 2 6 5 4 3 + 32 31 36 35 33 34 26 25 29 30 28 27 + 18 17 16 15 13 14 8 7 12 11 9 10 + operation j=20 : 20 19 22 21 24 23 26 25 29 30 28 27 + 42 41 38 37 40 39 2 1 4 3 6 5 + 8 7 12 11 9 10 44 43 47 48 46 45 + 16 15 18 17 14 13 32 31 36 35 33 34 + operation j=21 : 21 22 23 24 20 19 47 48 44 43 45 46 + 40 39 41 42 37 38 32 31 36 35 33 34 + 1 2 6 5 4 3 16 15 18 17 14 13 + 29 30 26 25 27 28 7 8 9 10 12 11 + operation j=22 : 22 21 20 19 23 24 16 15 18 17 14 13 + 39 40 37 38 41 42 31 32 33 34 36 35 + 7 8 9 10 12 11 47 48 44 43 45 46 + 26 25 29 30 28 27 1 2 6 5 4 3 + operation j=23 : 23 24 21 22 19 20 29 30 26 25 27 28 + 38 37 42 41 39 40 8 7 12 11 9 10 + 2 1 4 3 6 5 18 17 16 15 13 14 + 47 48 44 43 45 46 31 32 33 34 36 35 + operation j=24 : 24 23 19 20 21 22 18 17 16 15 13 14 + 37 38 39 40 42 41 7 8 9 10 12 11 + 31 32 33 34 36 35 29 30 26 25 27 28 + 44 43 47 48 46 45 2 1 4 3 6 5 + operation j=25 : 25 26 30 29 28 27 43 44 45 46 48 47 + 36 35 32 31 34 33 6 5 1 2 3 4 + 40 39 41 42 37 38 20 19 23 24 22 21 + 17 18 14 13 15 16 10 9 11 12 7 8 + operation j=26 : 26 25 28 27 30 29 20 19 23 24 22 21 + 35 36 34 33 32 31 5 6 3 4 1 2 + 10 9 11 12 7 8 43 44 45 46 48 47 + 14 13 17 18 16 15 40 39 41 42 37 38 + operation j=27 : 27 28 29 30 26 25 45 46 43 44 47 48 + 32 31 36 35 33 34 40 39 41 42 37 38 + 6 5 1 2 3 4 14 13 17 18 16 15 + 23 24 20 19 21 22 9 10 7 8 11 12 + operation j=28 : 28 27 26 25 29 30 14 13 17 18 16 15 + 31 32 33 34 36 35 39 40 37 38 41 42 + 9 10 7 8 11 12 45 46 43 44 47 48 + 20 19 23 24 22 21 6 5 1 2 3 4 + operation j=29 : 29 30 27 28 25 26 23 24 20 19 21 22 + 34 33 35 36 31 32 10 9 11 12 7 8 + 5 6 3 4 1 2 17 18 14 13 15 16 + 45 46 43 44 47 48 39 40 37 38 41 42 + operation j=30 : 30 29 25 26 27 28 17 18 14 13 15 16 + 33 34 31 32 35 36 9 10 7 8 11 12 + 39 40 37 38 41 42 23 24 20 19 21 22 + 43 44 45 46 48 47 5 6 3 4 1 2 + operation j=31 : 31 32 35 36 34 33 2 1 4 3 5 6 + 28 27 30 29 25 26 22 21 24 23 19 20 + 48 47 46 45 44 43 8 7 12 11 10 9 + 42 41 38 37 39 40 15 16 13 14 18 17 + operation j=32 : 32 31 34 33 35 36 8 7 12 11 10 9 + 27 28 25 26 30 29 21 22 19 20 24 23 + 15 16 13 14 18 17 2 1 4 3 5 6 + 38 37 42 41 40 39 48 47 46 45 44 43 + operation j=33 : 33 34 36 35 32 31 4 3 2 1 6 5 + 30 29 28 27 26 25 48 47 46 45 44 43 + 22 21 24 23 19 20 38 37 42 41 40 39 + 12 11 8 7 9 10 16 15 18 17 13 14 + operation j=34 : 34 33 32 31 36 35 38 37 42 41 40 39 + 29 30 26 25 28 27 47 48 44 43 46 45 + 16 15 18 17 13 14 4 3 2 1 6 5 + 8 7 12 11 10 9 22 21 24 23 19 20 + operation j=35 : 35 36 31 32 33 34 42 41 38 37 39 40 + 26 25 29 30 27 28 16 15 18 17 13 14 + 47 48 44 43 46 45 12 11 8 7 9 10 + 2 1 4 3 5 6 21 22 19 20 24 23 + operation j=36 : 36 35 33 34 31 32 12 11 8 7 9 10 + 25 26 27 28 29 30 15 16 13 14 18 17 + 21 22 19 20 24 23 42 41 38 37 39 40 + 4 3 2 1 6 5 47 48 44 43 46 45 + operation j=37 : 37 38 41 42 40 39 3 4 5 6 1 2 + 24 23 22 21 20 19 46 45 48 47 43 44 + 28 27 30 29 25 26 34 33 35 36 32 31 + 11 12 10 9 7 8 14 13 17 18 15 16 + operation j=38 : 38 37 40 39 41 42 34 33 35 36 32 31 + 23 24 20 19 22 21 45 46 43 44 48 47 + 14 13 17 18 15 16 3 4 5 6 1 2 + 10 9 11 12 8 7 28 27 30 29 25 26 + operation j=39 : 39 40 42 41 38 37 5 6 3 4 2 1 + 22 21 24 23 19 20 28 27 30 29 25 26 + 46 45 48 47 43 44 10 9 11 12 8 7 + 35 36 34 33 31 32 13 14 15 16 17 18 + operation j=40 : 40 39 38 37 42 41 10 9 11 12 8 7 + 21 22 19 20 24 23 27 28 25 26 30 29 + 13 14 15 16 17 18 5 6 3 4 2 1 + 34 33 35 36 32 31 46 45 48 47 43 44 + operation j=41 : 41 42 37 38 39 40 11 12 10 9 7 8 + 19 20 21 22 23 24 13 14 15 16 17 18 + 27 28 25 26 30 29 35 36 34 33 31 32 + 3 4 5 6 1 2 45 46 43 44 48 47 + operation j=42 : 42 41 39 40 37 38 35 36 34 33 31 32 + 20 19 23 24 21 22 14 13 17 18 15 16 + 45 46 43 44 48 47 11 12 10 9 7 8 + 5 6 3 4 2 1 27 28 25 26 30 29 + operation j=43 : 43 44 48 47 46 45 25 26 27 28 30 29 + 12 11 8 7 10 9 4 3 2 1 5 6 + 38 37 42 41 39 40 19 20 21 22 24 23 + 15 16 13 14 17 18 34 33 35 36 31 32 + operation j=44 : 44 43 46 45 48 47 19 20 21 22 24 23 + 11 12 10 9 8 7 3 4 5 6 2 1 + 34 33 35 36 31 32 25 26 27 28 30 29 + 13 14 15 16 18 17 38 37 42 41 39 40 + operation j=45 : 45 46 47 48 44 43 27 28 25 26 29 30 + 8 7 12 11 9 10 38 37 42 41 39 40 + 4 3 2 1 5 6 13 14 15 16 18 17 + 21 22 19 20 23 24 33 34 31 32 35 36 + operation j=46 : 46 45 44 43 47 48 13 14 15 16 18 17 + 7 8 9 10 12 11 37 38 39 40 42 41 + 33 34 31 32 35 36 27 28 25 26 29 30 + 19 20 21 22 24 23 4 3 2 1 5 6 + operation j=47 : 47 48 45 46 43 44 21 22 19 20 23 24 + 10 9 11 12 7 8 34 33 35 36 31 32 + 3 4 5 6 2 1 15 16 13 14 17 18 + 27 28 25 26 29 30 37 38 39 40 42 41 + operation j=48 : 48 47 43 44 45 46 15 16 13 14 17 18 + 9 10 7 8 11 12 33 34 31 32 35 36 + 37 38 39 40 42 41 21 22 19 20 23 24 + 25 26 27 28 30 29 3 4 5 6 2 1 + + + Space group can be generated using 5 generators: 13 4 9 34 2 + + generators (in lattice coordinates): + +&gen 5 + + -1 0 0 0.00000 + 0 -1 0 0.00000 + 0 0 -1 0.00000 + + 0 -1 0 0.00000 + 1 -1 0 0.00000 + 0 -1 1 0.00000 + + 0 1 -1 0.00000 + 1 0 -1 0.00000 + 0 0 -1 0.00000 + + 0 -1 1 0.00000 + 0 -1 0 0.00000 + 1 -1 0 0.00000 + + -1 0 0 0.00000 + -1 1 0 0.00000 + -1 0 1 0.00000 + +/ ! end generators + + + + Atomic positions: + ----------------- + atom types = 1 + total = 1 + + lattice coordinates (scaled) Cartesian coordinates atom + + atom type 1: atomic identification number = 74.0 representative = 1 + 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1 + +atoms% 1 atoms 1 + Z( 1)= 74 atoms 1 + 0.000000 0.000000 0.000000 1 + ---------------------------------------------------- + Suggested values for input: + + Atom Z lmax jri rmt dx + W 74 10 841 2.544787 0.015844 +k_max = 3.92960 +G_max =11.78881 + + =============================================== + === modifying atomic input for &(all)atom === + =============================================== + +for atom 1 ( W) changed rmt to 2.100000 +for atom 1 ( W) changed jri to 981 +for atom 1 ( W) changed lmax to 12 +for atom 1 ( W) changed lnonsph to 6 +for atom 1 ( W) set econfig to [Kr] 4d10 4f14 | 5s2 5p6 6s2 5d4 + corestates = 16 with 60.0 electrons + valence st.= 5 with 14.0 electrons +nlod = 2 llod = 1 : 5s5p + nlo( 1) = 2 llo = 0 1 + lonqn = 5 5 +line: 13>&comp +line: 14>gmax=15.0 gmaxxc=12.5 kmax=5.0 / + ---------- + core : 1 -1 2.0 + core : 2 -1 2.0 + core : 2 1 2.0 + core : 2 -2 4.0 + core : 3 -1 2.0 + core : 3 1 2.0 + core : 3 -2 4.0 + core : 3 2 4.0 + core : 3 -3 6.0 + core : 4 -1 2.0 + core : 4 1 2.0 + core : 4 -2 4.0 + core : 4 2 4.0 + core : 4 -3 6.0 + core : 4 3 6.0 + core : 4 -4 8.0 + valence : 5 -1 2.0 5s + valence : 5 1 2.0 5p + valence : 5 -2 4.0 5p + valence : 6 -1 2.0 6s + valence : 5 2 2.0 5d + valence : 5 -3 2.0 5d + ---------- +Valence Electrons = 14 + ---------------------------------------------------- + Suggested values for input: + + Atom Z lmax jri rmt dx + W 74 10 841 2.544787 0.015844 +k_max = 3.92960 +G_max =11.78881 +line: 15>&kpt +line: 16>div1=3 div2=3 div3=3 tkb=0.0005 / + 5.22007561238382 5.22007561238382 5.22007561238382 + -0.333333333333333 -0.333333333333333 -0.333333333333333 + body centered cubic + values accepted unchanged + 3 3 3 nmop(i),i=1,3 + orientation of boundary faces + 1 -1 -0.5740361 ifac,iside,orient for xvec + 2 -1 -0.0454288 ifac,iside,orient for xvec + 3 -1 -0.0256305 ifac,iside,orient for xvec + 4 -1 -0.0469244 ifac,iside,orient for xvec +Bravais lattice vectors + -3.013812 3.013812 3.013812 + 3.013812 -3.013812 3.013812 + 3.013812 3.013812 -3.013812 +reciprocal lattice vectors + 0.000000 1.042398 1.042398 + 1.042398 0.000000 1.042398 + 1.042398 1.042398 0.000000 + 3 3 3 Monkhorst-Pack-parameters + 0 nreg; k-points in irreducible wedge of BZ + Monkhorst-Pack-fractions + 0 nbound; no k-points on boundary of BZ + 1 idim + -0.3333333 + 0.0000000 + 0.3333333 + 2 idim + -0.3333333 + 0.0000000 + 0.3333333 + 3 idim + -0.3333333 + 0.0000000 + 0.3333333 + +k-point count: 4 + +k-point mesh: 3 3 3 +k-point density: 2.035038 2.035038 2.035038 + diff --git a/tests/parsers/fixtures/inpgen/default/out.error b/tests/parsers/fixtures/inpgen/default/out.error new file mode 100644 index 000000000..e69de29bb diff --git a/tests/parsers/fixtures/inpgen/no_inpxml/out b/tests/parsers/fixtures/inpgen/no_inpxml/out new file mode 100644 index 000000000..fca99897b --- /dev/null +++ b/tests/parsers/fixtures/inpgen/no_inpxml/out @@ -0,0 +1,687 @@ +line: 1>A Fleur input generator calculation with aiida +line: 2>&input cartesian=F / +line: 3>-3.0138120600 3.0138120600 3.0138120600 +line: 4>3.0138120600 -3.0138120600 3.0138120600 +line: 5>3.0138120600 3.0138120600 -3.0138120600 +line: 6>1.0000000000 +line: 7>1.0000000000 1.0000000000 1.0000000000 +line: 8> +line: 9>1 +line: 10>74 0.0000000000 0.0000000000 0.0000000000 +line: 11>&atom +line: 12>econfig="[Kr] 4d10 4f14 | 5s2 5p6 6s2 5d4" element="W" jri=981 lm + + A Fleur input generator calculation with aiida + + film= F cartesian= F + checkinp= F symor= F + +a1 = -3.01381 3.01381 3.01381 +a2 = 3.01381 -3.01381 3.01381 +a3 = 3.01381 3.01381 -3.01381 + +dvac= -3.01381 aa = 1.00000 +scale = 1.00000 1.00000 1.00000 + +natin= 1 Z = 74 + positions: + 0.00000 0.00000 0.00000 + + generators: 0 (excluding identity) + + + Lattice information: + -------------------- + + overall lattice constant a0 = 1.000000 bohr + + real-space primitive lattice vectors in units of a_{x,y,z} + a_1: -3.013812 3.013812 3.013812 + a_2: 3.013812 -3.013812 3.013812 + a_3: 3.013812 3.013812 -3.013812 + + lattice constants a_x, a_y, a_z = 1.000000 1.000000 1.000000 + volume of unit cell (a.u.^3) = 109.498581 + +dbg: lattice matrices + 109.498580847925 +dbg: as : + -3.013812 3.013812 3.013812 + 3.013812 -3.013812 3.013812 + 3.013812 3.013812 -3.013812 +dbg: bs : + 0.000000 0.165903 0.165903 + 0.165903 0.000000 0.165903 + 0.165903 0.165903 0.000000 +dbg: amat : + -3.013812 3.013812 3.013812 + 3.013812 -3.013812 3.013812 + 3.013812 3.013812 -3.013812 +dbg: bmat : + 0.000000 0.521199 0.521199 + 0.521199 0.000000 0.521199 + 0.521199 0.521199 0.000000 +dbg: amatinv : + 0.000000 0.165903 0.165903 + 0.165903 0.000000 0.165903 + 0.165903 0.165903 0.000000 +dbg: aamat : + 27.249189 -9.083063 -9.083063 + -9.083063 27.249189 -9.083063 + -9.083063 -9.083063 27.249189 +dbg: bbmat : + 0.543297 0.271649 0.271649 + 0.271649 0.543297 0.271649 + 0.271649 0.271649 0.543297 + +dbg: lattice vectors : +vector 1 : -3.01381 3.01381 3.01381 length : 5.22008 +vector 2 : 3.01381 -3.01381 3.01381 length : 5.22008 +vector 3 : 3.01381 3.01381 -3.01381 length : 5.22008 +angle between vectors (1,2) =109.47122 +angle between vectors (1,3) =109.47122 +angle between vectors (2,3) =109.47122 + +dbg: reciprocal lattice vectors : +vector 1 : 0.00000 0.52120 0.52120 length : 0.73709 +vector 2 : 0.52120 0.00000 0.52120 length : 0.73709 +vector 3 : 0.52120 0.52120 0.00000 length : 0.73709 +angle between vectors (1,2) = 60.00000 +angle between vectors (1,3) = 60.00000 +angle between vectors (2,3) = 60.00000 + + + Point group of the Bravais lattice has 48 operations + + DBG: symor,zorth,oldfleur : T F F + DBG: optype : 1 -2 -2 3 3 -2 -2 3 2 -4 3 -4 -1 2 2 -3 -3 2 2 -2 -3 4 4 -3 -3 4 2 -3 -2 4 3 -2 -4 2 -4 3 3 -4 -4 3 -2 2 4 -3 -3 2 4 -2 + DBG: invsym,invs,zrfs,invs2 : T T F F + DBG: (before reorder) invsop,zrfsop,invs2op : 13 7 46 + + Space group information: + ------------------------ + 48 operations + space group is symmorphic + has inversion symmetry + + + Operations: (in International notation) + --------------------------------------- + lattice coordinates (scaled) Cartesian coordinates + + operation 1: 1 (inverse = 1) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + _ + operation 2: 2 (inverse = 2) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + _ + operation 3: 2 (inverse = 3) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + + operation 4: 3 (inverse = 5) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + + operation 5: 3 (inverse = 4) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + _ + operation 6: 2 (inverse = 6) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + _ + operation 7: 2 (inverse = 7) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + + operation 8: 3 (inverse = 31) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + + operation 9: 2 (inverse = 9) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + _ + operation 10: 4 (inverse = 33) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + + operation 11: 3 (inverse = 37) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + _ + operation 12: 4 (inverse = 39) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + _ + operation 13: 1 (inverse = 13) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + + operation 14: 2 (inverse = 14) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + + operation 15: 2 (inverse = 15) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + _ + operation 16: 3 (inverse = 17) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + _ + operation 17: 3 (inverse = 16) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + + operation 18: 2 (inverse = 18) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + + operation 19: 2 (inverse = 19) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + _ + operation 20: 2 (inverse = 20) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + _ + operation 21: 3 (inverse = 25) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + + operation 22: 4 (inverse = 43) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + + operation 23: 4 (inverse = 26) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + _ + operation 24: 3 (inverse = 44) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + _ + operation 25: 3 (inverse = 21) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + + operation 26: 4 (inverse = 23) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + + operation 27: 2 (inverse = 27) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + _ + operation 28: 3 (inverse = 45) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + _ + operation 29: 2 (inverse = 29) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + + operation 30: 4 (inverse = 47) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + + operation 31: 3 (inverse = 8) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + _ + operation 32: 2 (inverse = 32) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + _ + operation 33: 4 (inverse = 10) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + + operation 34: 2 (inverse = 34) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + _ + operation 35: 4 (inverse = 38) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + + operation 36: 3 (inverse = 40) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + + operation 37: 3 (inverse = 11) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + _ + operation 38: 4 (inverse = 35) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + _ + operation 39: 4 (inverse = 12) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + + operation 40: 3 (inverse = 36) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + _ + operation 41: 2 (inverse = 41) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + + operation 42: 2 (inverse = 42) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + + operation 43: 4 (inverse = 22) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + _ + operation 44: 3 (inverse = 24) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + _ + operation 45: 3 (inverse = 28) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + + operation 46: 2 (inverse = 46) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + + operation 47: 4 (inverse = 30) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + _ + operation 48: 2 (inverse = 48) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + + Multiplcation table: {R_j|t_j}{R_i|t_i} + operation j= 1 : 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 + operation j= 2 : 2 1 5 6 3 4 31 32 33 34 35 36 + 14 13 17 18 15 16 20 19 23 24 21 22 + 43 44 45 46 47 48 7 8 9 10 11 12 + 39 40 37 38 42 41 25 26 27 28 29 30 + operation j= 3 : 3 4 1 2 6 5 37 38 39 40 41 42 + 18 17 16 15 14 13 44 43 47 48 45 46 + 26 25 29 30 27 28 33 34 31 32 36 35 + 7 8 9 10 11 12 20 19 23 24 21 22 + operation j= 4 : 4 3 6 5 1 2 33 34 31 32 36 35 + 17 18 14 13 16 15 43 44 45 46 47 48 + 20 19 23 24 21 22 37 38 39 40 41 42 + 9 10 7 8 12 11 26 25 29 30 27 28 + operation j= 5 : 5 6 2 1 4 3 39 40 37 38 42 41 + 16 15 18 17 13 14 26 25 29 30 27 28 + 44 43 47 48 45 46 9 10 7 8 12 11 + 31 32 33 34 35 36 19 20 21 22 23 24 + operation j= 6 : 6 5 4 3 2 1 9 10 7 8 12 11 + 15 16 13 14 18 17 25 26 27 28 29 30 + 19 20 21 22 23 24 39 40 37 38 42 41 + 33 34 31 32 36 35 44 43 47 48 45 46 + operation j= 7 : 7 8 11 12 10 9 1 2 6 5 3 4 + 46 45 48 47 43 44 24 23 22 21 20 19 + 30 29 28 27 26 25 32 31 36 35 34 33 + 41 42 40 39 37 38 17 18 14 13 16 15 + operation j= 8 : 8 7 10 9 11 12 32 31 36 35 34 33 + 45 46 43 44 48 47 23 24 20 19 22 21 + 17 18 14 13 16 15 1 2 6 5 3 4 + 40 39 41 42 38 37 30 29 28 27 26 25 + operation j= 9 : 9 10 12 11 8 7 6 5 1 2 4 3 + 48 47 46 45 44 43 30 29 28 27 26 25 + 24 23 22 21 20 19 40 39 41 42 38 37 + 36 35 32 31 33 34 18 17 16 15 14 13 + operation j=10 : 10 9 8 7 12 11 40 39 41 42 38 37 + 47 48 44 43 46 45 29 30 26 25 28 27 + 18 17 16 15 14 13 6 5 1 2 4 3 + 32 31 36 35 34 33 24 23 22 21 20 19 + operation j=11 : 11 12 7 8 9 10 41 42 40 39 37 38 + 44 43 47 48 45 46 18 17 16 15 14 13 + 29 30 26 25 28 27 36 35 32 31 33 34 + 1 2 6 5 3 4 23 24 20 19 22 21 + operation j=12 : 12 11 9 10 7 8 36 35 32 31 33 34 + 43 44 45 46 47 48 17 18 14 13 16 15 + 23 24 20 19 22 21 41 42 40 39 37 38 + 6 5 1 2 4 3 29 30 26 25 28 27 + operation j=13 : 13 14 18 17 16 15 46 45 48 47 44 43 + 1 2 6 5 4 3 41 42 40 39 38 37 + 36 35 32 31 34 33 28 27 30 29 26 25 + 24 23 22 21 19 20 12 11 8 7 10 9 + operation j=14 : 14 13 16 15 18 17 28 27 30 29 26 25 + 2 1 4 3 6 5 42 41 38 37 40 39 + 12 11 8 7 10 9 46 45 48 47 44 43 + 22 21 24 23 20 19 36 35 32 31 34 33 + operation j=15 : 15 16 17 18 14 13 48 47 46 45 43 44 + 6 5 1 2 3 4 36 35 32 31 34 33 + 41 42 40 39 38 37 22 21 24 23 20 19 + 30 29 28 27 25 26 11 12 10 9 8 7 + operation j=16 : 16 15 14 13 17 18 22 21 24 23 20 19 + 5 6 3 4 1 2 35 36 34 33 32 31 + 11 12 10 9 8 7 48 47 46 45 43 44 + 28 27 30 29 26 25 41 42 40 39 38 37 + operation j=17 : 17 18 15 16 13 14 30 29 28 27 25 26 + 4 3 2 1 5 6 12 11 8 7 10 9 + 42 41 38 37 40 39 24 23 22 21 19 20 + 48 47 46 45 43 44 35 36 34 33 32 31 + operation j=18 : 18 17 13 14 15 16 24 23 22 21 19 20 + 3 4 5 6 2 1 11 12 10 9 8 7 + 35 36 34 33 32 31 30 29 28 27 25 26 + 46 45 48 47 44 43 42 41 38 37 40 39 + operation j=19 : 19 20 24 23 22 21 44 43 47 48 46 45 + 41 42 40 39 38 37 1 2 6 5 4 3 + 32 31 36 35 33 34 26 25 29 30 28 27 + 18 17 16 15 13 14 8 7 12 11 9 10 + operation j=20 : 20 19 22 21 24 23 26 25 29 30 28 27 + 42 41 38 37 40 39 2 1 4 3 6 5 + 8 7 12 11 9 10 44 43 47 48 46 45 + 16 15 18 17 14 13 32 31 36 35 33 34 + operation j=21 : 21 22 23 24 20 19 47 48 44 43 45 46 + 40 39 41 42 37 38 32 31 36 35 33 34 + 1 2 6 5 4 3 16 15 18 17 14 13 + 29 30 26 25 27 28 7 8 9 10 12 11 + operation j=22 : 22 21 20 19 23 24 16 15 18 17 14 13 + 39 40 37 38 41 42 31 32 33 34 36 35 + 7 8 9 10 12 11 47 48 44 43 45 46 + 26 25 29 30 28 27 1 2 6 5 4 3 + operation j=23 : 23 24 21 22 19 20 29 30 26 25 27 28 + 38 37 42 41 39 40 8 7 12 11 9 10 + 2 1 4 3 6 5 18 17 16 15 13 14 + 47 48 44 43 45 46 31 32 33 34 36 35 + operation j=24 : 24 23 19 20 21 22 18 17 16 15 13 14 + 37 38 39 40 42 41 7 8 9 10 12 11 + 31 32 33 34 36 35 29 30 26 25 27 28 + 44 43 47 48 46 45 2 1 4 3 6 5 + operation j=25 : 25 26 30 29 28 27 43 44 45 46 48 47 + 36 35 32 31 34 33 6 5 1 2 3 4 + 40 39 41 42 37 38 20 19 23 24 22 21 + 17 18 14 13 15 16 10 9 11 12 7 8 + operation j=26 : 26 25 28 27 30 29 20 19 23 24 22 21 + 35 36 34 33 32 31 5 6 3 4 1 2 + 10 9 11 12 7 8 43 44 45 46 48 47 + 14 13 17 18 16 15 40 39 41 42 37 38 + operation j=27 : 27 28 29 30 26 25 45 46 43 44 47 48 + 32 31 36 35 33 34 40 39 41 42 37 38 + 6 5 1 2 3 4 14 13 17 18 16 15 + 23 24 20 19 21 22 9 10 7 8 11 12 + operation j=28 : 28 27 26 25 29 30 14 13 17 18 16 15 + 31 32 33 34 36 35 39 40 37 38 41 42 + 9 10 7 8 11 12 45 46 43 44 47 48 + 20 19 23 24 22 21 6 5 1 2 3 4 + operation j=29 : 29 30 27 28 25 26 23 24 20 19 21 22 + 34 33 35 36 31 32 10 9 11 12 7 8 + 5 6 3 4 1 2 17 18 14 13 15 16 + 45 46 43 44 47 48 39 40 37 38 41 42 + operation j=30 : 30 29 25 26 27 28 17 18 14 13 15 16 + 33 34 31 32 35 36 9 10 7 8 11 12 + 39 40 37 38 41 42 23 24 20 19 21 22 + 43 44 45 46 48 47 5 6 3 4 1 2 + operation j=31 : 31 32 35 36 34 33 2 1 4 3 5 6 + 28 27 30 29 25 26 22 21 24 23 19 20 + 48 47 46 45 44 43 8 7 12 11 10 9 + 42 41 38 37 39 40 15 16 13 14 18 17 + operation j=32 : 32 31 34 33 35 36 8 7 12 11 10 9 + 27 28 25 26 30 29 21 22 19 20 24 23 + 15 16 13 14 18 17 2 1 4 3 5 6 + 38 37 42 41 40 39 48 47 46 45 44 43 + operation j=33 : 33 34 36 35 32 31 4 3 2 1 6 5 + 30 29 28 27 26 25 48 47 46 45 44 43 + 22 21 24 23 19 20 38 37 42 41 40 39 + 12 11 8 7 9 10 16 15 18 17 13 14 + operation j=34 : 34 33 32 31 36 35 38 37 42 41 40 39 + 29 30 26 25 28 27 47 48 44 43 46 45 + 16 15 18 17 13 14 4 3 2 1 6 5 + 8 7 12 11 10 9 22 21 24 23 19 20 + operation j=35 : 35 36 31 32 33 34 42 41 38 37 39 40 + 26 25 29 30 27 28 16 15 18 17 13 14 + 47 48 44 43 46 45 12 11 8 7 9 10 + 2 1 4 3 5 6 21 22 19 20 24 23 + operation j=36 : 36 35 33 34 31 32 12 11 8 7 9 10 + 25 26 27 28 29 30 15 16 13 14 18 17 + 21 22 19 20 24 23 42 41 38 37 39 40 + 4 3 2 1 6 5 47 48 44 43 46 45 + operation j=37 : 37 38 41 42 40 39 3 4 5 6 1 2 + 24 23 22 21 20 19 46 45 48 47 43 44 + 28 27 30 29 25 26 34 33 35 36 32 31 + 11 12 10 9 7 8 14 13 17 18 15 16 + operation j=38 : 38 37 40 39 41 42 34 33 35 36 32 31 + 23 24 20 19 22 21 45 46 43 44 48 47 + 14 13 17 18 15 16 3 4 5 6 1 2 + 10 9 11 12 8 7 28 27 30 29 25 26 + operation j=39 : 39 40 42 41 38 37 5 6 3 4 2 1 + 22 21 24 23 19 20 28 27 30 29 25 26 + 46 45 48 47 43 44 10 9 11 12 8 7 + 35 36 34 33 31 32 13 14 15 16 17 18 + operation j=40 : 40 39 38 37 42 41 10 9 11 12 8 7 + 21 22 19 20 24 23 27 28 25 26 30 29 + 13 14 15 16 17 18 5 6 3 4 2 1 + 34 33 35 36 32 31 46 45 48 47 43 44 + operation j=41 : 41 42 37 38 39 40 11 12 10 9 7 8 + 19 20 21 22 23 24 13 14 15 16 17 18 + 27 28 25 26 30 29 35 36 34 33 31 32 + 3 4 5 6 1 2 45 46 43 44 48 47 + operation j=42 : 42 41 39 40 37 38 35 36 34 33 31 32 + 20 19 23 24 21 22 14 13 17 18 15 16 + 45 46 43 44 48 47 11 12 10 9 7 8 + 5 6 3 4 2 1 27 28 25 26 30 29 + operation j=43 : 43 44 48 47 46 45 25 26 27 28 30 29 + 12 11 8 7 10 9 4 3 2 1 5 6 + 38 37 42 41 39 40 19 20 21 22 24 23 + 15 16 13 14 17 18 34 33 35 36 31 32 + operation j=44 : 44 43 46 45 48 47 19 20 21 22 24 23 + 11 12 10 9 8 7 3 4 5 6 2 1 + 34 33 35 36 31 32 25 26 27 28 30 29 + 13 14 15 16 18 17 38 37 42 41 39 40 + operation j=45 : 45 46 47 48 44 43 27 28 25 26 29 30 + 8 7 12 11 9 10 38 37 42 41 39 40 + 4 3 2 1 5 6 13 14 15 16 18 17 + 21 22 19 20 23 24 33 34 31 32 35 36 + operation j=46 : 46 45 44 43 47 48 13 14 15 16 18 17 + 7 8 9 10 12 11 37 38 39 40 42 41 + 33 34 31 32 35 36 27 28 25 26 29 30 + 19 20 21 22 24 23 4 3 2 1 5 6 + operation j=47 : 47 48 45 46 43 44 21 22 19 20 23 24 + 10 9 11 12 7 8 34 33 35 36 31 32 + 3 4 5 6 2 1 15 16 13 14 17 18 + 27 28 25 26 29 30 37 38 39 40 42 41 + operation j=48 : 48 47 43 44 45 46 15 16 13 14 17 18 + 9 10 7 8 11 12 33 34 31 32 35 36 + 37 38 39 40 42 41 21 22 19 20 23 24 + 25 26 27 28 30 29 3 4 5 6 2 1 + + + Space group can be generated using 5 generators: 13 4 9 34 2 + + generators (in lattice coordinates): + +&gen 5 + + -1 0 0 0.00000 + 0 -1 0 0.00000 + 0 0 -1 0.00000 + + 0 -1 0 0.00000 + 1 -1 0 0.00000 + 0 -1 1 0.00000 + + 0 1 -1 0.00000 + 1 0 -1 0.00000 + 0 0 -1 0.00000 + + 0 -1 1 0.00000 + 0 -1 0 0.00000 + 1 -1 0 0.00000 + + -1 0 0 0.00000 + -1 1 0 0.00000 + -1 0 1 0.00000 + +/ ! end generators + + + + Atomic positions: + ----------------- + atom types = 1 + total = 1 + + lattice coordinates (scaled) Cartesian coordinates atom + + atom type 1: atomic identification number = 74.0 representative = 1 + 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1 + +atoms% 1 atoms 1 + Z( 1)= 74 atoms 1 + 0.000000 0.000000 0.000000 1 + ---------------------------------------------------- + Suggested values for input: + + Atom Z lmax jri rmt dx + W 74 10 841 2.544787 0.015844 +k_max = 3.92960 +G_max =11.78881 + + =============================================== + === modifying atomic input for &(all)atom === + =============================================== + +for atom 1 ( W) changed rmt to 2.100000 +for atom 1 ( W) changed jri to 981 +for atom 1 ( W) changed lmax to 12 +for atom 1 ( W) changed lnonsph to 6 +for atom 1 ( W) set econfig to [Kr] 4d10 4f14 | 5s2 5p6 6s2 5d4 + corestates = 16 with 60.0 electrons + valence st.= 5 with 14.0 electrons +nlod = 2 llod = 1 : 5s5p + nlo( 1) = 2 llo = 0 1 + lonqn = 5 5 +line: 13>&comp +line: 14>gmax=15.0 gmaxxc=12.5 kmax=5.0 / + ---------- + core : 1 -1 2.0 + core : 2 -1 2.0 + core : 2 1 2.0 + core : 2 -2 4.0 + core : 3 -1 2.0 + core : 3 1 2.0 + core : 3 -2 4.0 + core : 3 2 4.0 + core : 3 -3 6.0 + core : 4 -1 2.0 + core : 4 1 2.0 + core : 4 -2 4.0 + core : 4 2 4.0 + core : 4 -3 6.0 + core : 4 3 6.0 + core : 4 -4 8.0 + valence : 5 -1 2.0 5s + valence : 5 1 2.0 5p + valence : 5 -2 4.0 5p + valence : 6 -1 2.0 6s + valence : 5 2 2.0 5d + valence : 5 -3 2.0 5d + ---------- +Valence Electrons = 14 + ---------------------------------------------------- + Suggested values for input: + + Atom Z lmax jri rmt dx + W 74 10 841 2.544787 0.015844 +k_max = 3.92960 +G_max =11.78881 +line: 15>&kpt +line: 16>div1=3 div2=3 div3=3 tkb=0.0005 / + 5.22007561238382 5.22007561238382 5.22007561238382 + -0.333333333333333 -0.333333333333333 -0.333333333333333 + body centered cubic + values accepted unchanged + 3 3 3 nmop(i),i=1,3 + orientation of boundary faces + 1 -1 -0.5740361 ifac,iside,orient for xvec + 2 -1 -0.0454288 ifac,iside,orient for xvec + 3 -1 -0.0256305 ifac,iside,orient for xvec + 4 -1 -0.0469244 ifac,iside,orient for xvec +Bravais lattice vectors + -3.013812 3.013812 3.013812 + 3.013812 -3.013812 3.013812 + 3.013812 3.013812 -3.013812 +reciprocal lattice vectors + 0.000000 1.042398 1.042398 + 1.042398 0.000000 1.042398 + 1.042398 1.042398 0.000000 + 3 3 3 Monkhorst-Pack-parameters + 0 nreg; k-points in irreducible wedge of BZ + Monkhorst-Pack-fractions + 0 nbound; no k-points on boundary of BZ + 1 idim + -0.3333333 + 0.0000000 + 0.3333333 + 2 idim + -0.3333333 + 0.0000000 + 0.3333333 + 3 idim + -0.3333333 + 0.0000000 + 0.3333333 + +k-point count: 4 + +k-point mesh: 3 3 3 +k-point density: 2.035038 2.035038 2.035038 + diff --git a/tests/parsers/fixtures/inpgen/no_inpxml/out.error b/tests/parsers/fixtures/inpgen/no_inpxml/out.error new file mode 100644 index 000000000..79c4a880f --- /dev/null +++ b/tests/parsers/fixtures/inpgen/no_inpxml/out.error @@ -0,0 +1,2 @@ +ERROR +Check_rmt diff --git a/tests/parsers/fixtures/inpgen/no_otherfiles/inp.xml b/tests/parsers/fixtures/inpgen/no_otherfiles/inp.xml new file mode 100644 index 000000000..2bf34f24c --- /dev/null +++ b/tests/parsers/fixtures/inpgen/no_otherfiles/inp.xml @@ -0,0 +1,319 @@ + + + + A Fleur input generator calculation with aiida + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + -0.000000 0.333333 0.333333 + -0.333333 0.333333 0.333333 + -0.000000 0.000000 0.333333 + 0.000000 0.000000 0.000000 + + + + + + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + -1 1 0 .0000000000 + -1 0 1 .0000000000 + + + 1 -1 0 .0000000000 + 0 -1 0 .0000000000 + 0 -1 1 .0000000000 + + + 0 -1 0 .0000000000 + 1 -1 0 .0000000000 + 0 -1 1 .0000000000 + + + -1 1 0 .0000000000 + -1 0 0 .0000000000 + -1 0 1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 -1 .0000000000 + 0 1 -1 .0000000000 + 0 0 -1 .0000000000 + + + 0 0 -1 .0000000000 + 0 1 -1 .0000000000 + 1 0 -1 .0000000000 + + + 0 1 -1 .0000000000 + 1 0 -1 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 -1 .0000000000 + 0 0 -1 .0000000000 + 1 0 -1 .0000000000 + + + 1 0 -1 .0000000000 + 0 0 -1 .0000000000 + 0 1 -1 .0000000000 + + + 0 0 -1 .0000000000 + 1 0 -1 .0000000000 + 0 1 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 1 -1 0 .0000000000 + 1 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 -1 0 .0000000000 + 1 0 0 .0000000000 + 1 0 -1 .0000000000 + + + 0 1 0 .0000000000 + -1 1 0 .0000000000 + 0 1 -1 .0000000000 + + + -1 1 0 .0000000000 + 0 1 0 .0000000000 + 0 1 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + + + 1 0 0 .0000000000 + 1 0 -1 .0000000000 + 1 -1 0 .0000000000 + + + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + + + 1 -1 0 .0000000000 + 1 0 -1 .0000000000 + 1 0 0 .0000000000 + + + 0 1 0 .0000000000 + 0 1 -1 .0000000000 + -1 1 0 .0000000000 + + + -1 1 0 .0000000000 + 0 1 -1 .0000000000 + 0 1 0 .0000000000 + + + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + + + 1 0 -1 .0000000000 + 1 0 0 .0000000000 + 1 -1 0 .0000000000 + + + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + + + 1 0 -1 .0000000000 + 1 -1 0 .0000000000 + 1 0 0 .0000000000 + + + 0 1 -1 .0000000000 + 0 1 0 .0000000000 + -1 1 0 .0000000000 + + + 0 1 -1 .0000000000 + -1 1 0 .0000000000 + 0 1 0 .0000000000 + + + -1 0 1 .0000000000 + -1 1 0 .0000000000 + -1 0 0 .0000000000 + + + 0 0 1 .0000000000 + 0 1 0 .0000000000 + 1 0 0 .0000000000 + + + 0 -1 1 .0000000000 + 1 -1 0 .0000000000 + 0 -1 0 .0000000000 + + + 0 -1 1 .0000000000 + 0 -1 0 .0000000000 + 1 -1 0 .0000000000 + + + -1 0 1 .0000000000 + -1 0 0 .0000000000 + -1 1 0 .0000000000 + + + 0 0 1 .0000000000 + 1 0 0 .0000000000 + 0 1 0 .0000000000 + + + 1 -1 0 .0000000000 + 0 -1 1 .0000000000 + 0 -1 0 .0000000000 + + + 0 -1 0 .0000000000 + 0 -1 1 .0000000000 + 1 -1 0 .0000000000 + + + -1 1 0 .0000000000 + -1 0 1 .0000000000 + -1 0 0 .0000000000 + + + 0 1 0 .0000000000 + 0 0 1 .0000000000 + 1 0 0 .0000000000 + + + 1 0 0 .0000000000 + 0 0 1 .0000000000 + 0 1 0 .0000000000 + + + -1 0 0 .0000000000 + -1 0 1 .0000000000 + -1 1 0 .0000000000 + + + 0 0 1 .0000000000 + -1 0 1 .0000000000 + 0 -1 1 .0000000000 + + + -1 0 1 .0000000000 + 0 0 1 .0000000000 + 0 -1 1 .0000000000 + + + 0 0 1 .0000000000 + 0 -1 1 .0000000000 + -1 0 1 .0000000000 + + + -1 0 1 .0000000000 + 0 -1 1 .0000000000 + 0 0 1 .0000000000 + + + 0 -1 1 .0000000000 + 0 0 1 .0000000000 + -1 0 1 .0000000000 + + + 0 -1 1 .0000000000 + -1 0 1 .0000000000 + 0 0 1 .0000000000 + + + + + -3.013812060000000 3.013812060000000 3.013812060000000 + 3.013812060000000 -3.013812060000000 3.013812060000000 + 3.013812060000000 3.013812060000000 -3.013812060000000 + + + + + + + + + + + + [Kr] (4d3/2) (4d5/2) (4f5/2) (4f7/2) + (5s1/2) (5p1/2) (5p3/2) (6s1/2) (5d3/2) (5d5/2) + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + + + + + + + + + + + diff --git a/tests/parsers/fixtures/inpgen/no_otherfiles/out.error b/tests/parsers/fixtures/inpgen/no_otherfiles/out.error new file mode 100644 index 000000000..e69de29bb diff --git a/tests/parsers/fixtures/inpgen/novalid_inpxml/inp.xml b/tests/parsers/fixtures/inpgen/novalid_inpxml/inp.xml new file mode 100644 index 000000000..a203a82dd --- /dev/null +++ b/tests/parsers/fixtures/inpgen/novalid_inpxml/inp.xml @@ -0,0 +1,319 @@ + + + + A Fleur input generator calculation with aiida + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + -0.000000 0.333333 0.333333 + -0.333333 0.333333 0.333333 + -0.000000 0.000000 0.333333 + 0.000000 0.000000 0.000000 + + + + + + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + -1 0 0 .0000000000 + -1 1 0 .0000000000 + -1 0 1 .0000000000 + + + 1 -1 0 .0000000000 + 0 -1 0 .0000000000 + 0 -1 1 .0000000000 + + + 0 -1 0 .0000000000 + 1 -1 0 .0000000000 + 0 -1 1 .0000000000 + + + -1 1 0 .0000000000 + -1 0 0 .0000000000 + -1 0 1 .0000000000 + + + 0 1 0 .0000000000 + 1 0 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 -1 .0000000000 + 0 1 -1 .0000000000 + 0 0 -1 .0000000000 + + + 0 0 -1 .0000000000 + 0 1 -1 .0000000000 + 1 0 -1 .0000000000 + + + 0 1 -1 .0000000000 + 1 0 -1 .0000000000 + 0 0 -1 .0000000000 + + + 0 1 -1 .0000000000 + 0 0 -1 .0000000000 + 1 0 -1 .0000000000 + + + 1 0 -1 .0000000000 + 0 0 -1 .0000000000 + 0 1 -1 .0000000000 + + + 0 0 -1 .0000000000 + 1 0 -1 .0000000000 + 0 1 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 0 0 .0000000000 + 1 -1 0 .0000000000 + 1 0 -1 .0000000000 + + + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + + + 1 -1 0 .0000000000 + 1 0 0 .0000000000 + 1 0 -1 .0000000000 + + + 0 1 0 .0000000000 + -1 1 0 .0000000000 + 0 1 -1 .0000000000 + + + -1 1 0 .0000000000 + 0 1 0 .0000000000 + 0 1 -1 .0000000000 + + + -1 0 0 .0000000000 + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + + + 1 0 0 .0000000000 + 1 0 -1 .0000000000 + 1 -1 0 .0000000000 + + + 0 -1 0 .0000000000 + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + + + 1 -1 0 .0000000000 + 1 0 -1 .0000000000 + 1 0 0 .0000000000 + + + 0 1 0 .0000000000 + 0 1 -1 .0000000000 + -1 1 0 .0000000000 + + + -1 1 0 .0000000000 + 0 1 -1 .0000000000 + 0 1 0 .0000000000 + + + 0 0 -1 .0000000000 + -1 0 0 .0000000000 + 0 -1 0 .0000000000 + + + 1 0 -1 .0000000000 + 1 0 0 .0000000000 + 1 -1 0 .0000000000 + + + 0 0 -1 .0000000000 + 0 -1 0 .0000000000 + -1 0 0 .0000000000 + + + 1 0 -1 .0000000000 + 1 -1 0 .0000000000 + 1 0 0 .0000000000 + + + 0 1 -1 .0000000000 + 0 1 0 .0000000000 + -1 1 0 .0000000000 + + + 0 1 -1 .0000000000 + -1 1 0 .0000000000 + 0 1 0 .0000000000 + + + -1 0 1 .0000000000 + -1 1 0 .0000000000 + -1 0 0 .0000000000 + + + 0 0 1 .0000000000 + 0 1 0 .0000000000 + 1 0 0 .0000000000 + + + 0 -1 1 .0000000000 + 1 -1 0 .0000000000 + 0 -1 0 .0000000000 + + + 0 -1 1 .0000000000 + 0 -1 0 .0000000000 + 1 -1 0 .0000000000 + + + -1 0 1 .0000000000 + -1 0 0 .0000000000 + -1 1 0 .0000000000 + + + 0 0 1 .0000000000 + 1 0 0 .0000000000 + 0 1 0 .0000000000 + + + 1 -1 0 .0000000000 + 0 -1 1 .0000000000 + 0 -1 0 .0000000000 + + + 0 -1 0 .0000000000 + 0 -1 1 .0000000000 + 1 -1 0 .0000000000 + + + -1 1 0 .0000000000 + -1 0 1 .0000000000 + -1 0 0 .0000000000 + + + 0 1 0 .0000000000 + 0 0 1 .0000000000 + 1 0 0 .0000000000 + + + 1 0 0 .0000000000 + 0 0 1 .0000000000 + 0 1 0 .0000000000 + + + -1 0 0 .0000000000 + -1 0 1 .0000000000 + -1 1 0 .0000000000 + + + 0 0 1 .0000000000 + -1 0 1 .0000000000 + 0 -1 1 .0000000000 + + + -1 0 1 .0000000000 + 0 0 1 .0000000000 + 0 -1 1 .0000000000 + + + 0 0 1 .0000000000 + 0 -1 1 .0000000000 + -1 0 1 .0000000000 + + + -1 0 1 .0000000000 + 0 -1 1 .0000000000 + 0 0 1 .0000000000 + + + 0 -1 1 .0000000000 + 0 0 1 .0000000000 + -1 0 1 .0000000000 + + + 0 -1 1 .0000000000 + -1 0 1 .0000000000 + 0 0 1 .0000000000 + + + + + -3.013812060000000 3.013812060000000 3.013812060000000 + 3.013812060000000 -3.013812060000000 3.013812060000000 + 3.013812060000000 3.013812060000000 -3.013812060000000 + + + + + + + + + + + + [Kr] (4d3/2) (4d5/2) (4f5/2) (4f7/2) + (5s1/2) (5p1/2) (5p3/2) (6s1/2) (5d3/2) (5d5/2) + + + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + + + + + + + + + + + diff --git a/tests/parsers/fixtures/inpgen/novalid_inpxml/out b/tests/parsers/fixtures/inpgen/novalid_inpxml/out new file mode 100644 index 000000000..fca99897b --- /dev/null +++ b/tests/parsers/fixtures/inpgen/novalid_inpxml/out @@ -0,0 +1,687 @@ +line: 1>A Fleur input generator calculation with aiida +line: 2>&input cartesian=F / +line: 3>-3.0138120600 3.0138120600 3.0138120600 +line: 4>3.0138120600 -3.0138120600 3.0138120600 +line: 5>3.0138120600 3.0138120600 -3.0138120600 +line: 6>1.0000000000 +line: 7>1.0000000000 1.0000000000 1.0000000000 +line: 8> +line: 9>1 +line: 10>74 0.0000000000 0.0000000000 0.0000000000 +line: 11>&atom +line: 12>econfig="[Kr] 4d10 4f14 | 5s2 5p6 6s2 5d4" element="W" jri=981 lm + + A Fleur input generator calculation with aiida + + film= F cartesian= F + checkinp= F symor= F + +a1 = -3.01381 3.01381 3.01381 +a2 = 3.01381 -3.01381 3.01381 +a3 = 3.01381 3.01381 -3.01381 + +dvac= -3.01381 aa = 1.00000 +scale = 1.00000 1.00000 1.00000 + +natin= 1 Z = 74 + positions: + 0.00000 0.00000 0.00000 + + generators: 0 (excluding identity) + + + Lattice information: + -------------------- + + overall lattice constant a0 = 1.000000 bohr + + real-space primitive lattice vectors in units of a_{x,y,z} + a_1: -3.013812 3.013812 3.013812 + a_2: 3.013812 -3.013812 3.013812 + a_3: 3.013812 3.013812 -3.013812 + + lattice constants a_x, a_y, a_z = 1.000000 1.000000 1.000000 + volume of unit cell (a.u.^3) = 109.498581 + +dbg: lattice matrices + 109.498580847925 +dbg: as : + -3.013812 3.013812 3.013812 + 3.013812 -3.013812 3.013812 + 3.013812 3.013812 -3.013812 +dbg: bs : + 0.000000 0.165903 0.165903 + 0.165903 0.000000 0.165903 + 0.165903 0.165903 0.000000 +dbg: amat : + -3.013812 3.013812 3.013812 + 3.013812 -3.013812 3.013812 + 3.013812 3.013812 -3.013812 +dbg: bmat : + 0.000000 0.521199 0.521199 + 0.521199 0.000000 0.521199 + 0.521199 0.521199 0.000000 +dbg: amatinv : + 0.000000 0.165903 0.165903 + 0.165903 0.000000 0.165903 + 0.165903 0.165903 0.000000 +dbg: aamat : + 27.249189 -9.083063 -9.083063 + -9.083063 27.249189 -9.083063 + -9.083063 -9.083063 27.249189 +dbg: bbmat : + 0.543297 0.271649 0.271649 + 0.271649 0.543297 0.271649 + 0.271649 0.271649 0.543297 + +dbg: lattice vectors : +vector 1 : -3.01381 3.01381 3.01381 length : 5.22008 +vector 2 : 3.01381 -3.01381 3.01381 length : 5.22008 +vector 3 : 3.01381 3.01381 -3.01381 length : 5.22008 +angle between vectors (1,2) =109.47122 +angle between vectors (1,3) =109.47122 +angle between vectors (2,3) =109.47122 + +dbg: reciprocal lattice vectors : +vector 1 : 0.00000 0.52120 0.52120 length : 0.73709 +vector 2 : 0.52120 0.00000 0.52120 length : 0.73709 +vector 3 : 0.52120 0.52120 0.00000 length : 0.73709 +angle between vectors (1,2) = 60.00000 +angle between vectors (1,3) = 60.00000 +angle between vectors (2,3) = 60.00000 + + + Point group of the Bravais lattice has 48 operations + + DBG: symor,zorth,oldfleur : T F F + DBG: optype : 1 -2 -2 3 3 -2 -2 3 2 -4 3 -4 -1 2 2 -3 -3 2 2 -2 -3 4 4 -3 -3 4 2 -3 -2 4 3 -2 -4 2 -4 3 3 -4 -4 3 -2 2 4 -3 -3 2 4 -2 + DBG: invsym,invs,zrfs,invs2 : T T F F + DBG: (before reorder) invsop,zrfsop,invs2op : 13 7 46 + + Space group information: + ------------------------ + 48 operations + space group is symmorphic + has inversion symmetry + + + Operations: (in International notation) + --------------------------------------- + lattice coordinates (scaled) Cartesian coordinates + + operation 1: 1 (inverse = 1) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + _ + operation 2: 2 (inverse = 2) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + _ + operation 3: 2 (inverse = 3) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + + operation 4: 3 (inverse = 5) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + + operation 5: 3 (inverse = 4) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + _ + operation 6: 2 (inverse = 6) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + _ + operation 7: 2 (inverse = 7) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + + operation 8: 3 (inverse = 31) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + + operation 9: 2 (inverse = 9) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + _ + operation 10: 4 (inverse = 33) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + + operation 11: 3 (inverse = 37) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + _ + operation 12: 4 (inverse = 39) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + _ + operation 13: 1 (inverse = 13) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + + operation 14: 2 (inverse = 14) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + + operation 15: 2 (inverse = 15) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + _ + operation 16: 3 (inverse = 17) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + _ + operation 17: 3 (inverse = 16) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + + operation 18: 2 (inverse = 18) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + + operation 19: 2 (inverse = 19) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + _ + operation 20: 2 (inverse = 20) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + _ + operation 21: 3 (inverse = 25) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 -1 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + + operation 22: 4 (inverse = 43) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 -1 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + + operation 23: 4 (inverse = 26) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + _ + operation 24: 3 (inverse = 44) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + _ + operation 25: 3 (inverse = 21) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + + operation 26: 4 (inverse = 23) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + + operation 27: 2 (inverse = 27) + ( 0 0 -1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + _ + operation 28: 3 (inverse = 45) + ( 1 0 -1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + _ + operation 29: 2 (inverse = 29) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + + operation 30: 4 (inverse = 47) + ( 0 1 -1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + + operation 31: 3 (inverse = 8) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + _ + operation 32: 2 (inverse = 32) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + _ + operation 33: 4 (inverse = 10) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + + operation 34: 2 (inverse = 34) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + _ + operation 35: 4 (inverse = 38) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + + operation 36: 3 (inverse = 40) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + + operation 37: 3 (inverse = 11) + ( 1 -1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + _ + operation 38: 4 (inverse = 35) + ( 0 -1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( -1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 1 -1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + _ + operation 39: 4 (inverse = 12) + ( -1 1 0 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 -1.00000 -0.00000 ) ( 0.000 ) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + + operation 40: 3 (inverse = 36) + ( 0 1 0 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 0.00000 1.00000 ) ( 0.000 ) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + _ + operation 41: 2 (inverse = 41) + ( 1 0 0 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 -0.00000 1.00000 ) ( 0.000 ) + ( 0 1 0 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + + operation 42: 2 (inverse = 42) + ( -1 0 0 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 -1.00000 0.00000 ) ( 0.000 ) + ( -1 1 0 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + + operation 43: 4 (inverse = 22) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + _ + operation 44: 3 (inverse = 24) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 -0.00000 0.00000 ) ( 0.000 ) + _ + operation 45: 3 (inverse = 28) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 0.00000 -1.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 -0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + + operation 46: 2 (inverse = 46) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 1.00000 -0.00000 ) ( 0.000 ) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 0.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + + operation 47: 4 (inverse = 30) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( 0.00000 -0.00000 -1.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( -0.00000 1.00000 0.00000 ) ( 0.000 ) + _ + operation 48: 2 (inverse = 48) + ( 0 -1 1 ) ( 0.000 ) ( 1.00000 0.00000 -0.00000 ) ( 0.000 ) + ( -1 0 1 ) ( 0.000 ) ( 0.00000 1.00000 0.00000 ) ( 0.000 ) + ( 0 0 1 ) ( 0.000 ) ( -0.00000 -0.00000 -1.00000 ) ( 0.000 ) + + Multiplcation table: {R_j|t_j}{R_i|t_i} + operation j= 1 : 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 + operation j= 2 : 2 1 5 6 3 4 31 32 33 34 35 36 + 14 13 17 18 15 16 20 19 23 24 21 22 + 43 44 45 46 47 48 7 8 9 10 11 12 + 39 40 37 38 42 41 25 26 27 28 29 30 + operation j= 3 : 3 4 1 2 6 5 37 38 39 40 41 42 + 18 17 16 15 14 13 44 43 47 48 45 46 + 26 25 29 30 27 28 33 34 31 32 36 35 + 7 8 9 10 11 12 20 19 23 24 21 22 + operation j= 4 : 4 3 6 5 1 2 33 34 31 32 36 35 + 17 18 14 13 16 15 43 44 45 46 47 48 + 20 19 23 24 21 22 37 38 39 40 41 42 + 9 10 7 8 12 11 26 25 29 30 27 28 + operation j= 5 : 5 6 2 1 4 3 39 40 37 38 42 41 + 16 15 18 17 13 14 26 25 29 30 27 28 + 44 43 47 48 45 46 9 10 7 8 12 11 + 31 32 33 34 35 36 19 20 21 22 23 24 + operation j= 6 : 6 5 4 3 2 1 9 10 7 8 12 11 + 15 16 13 14 18 17 25 26 27 28 29 30 + 19 20 21 22 23 24 39 40 37 38 42 41 + 33 34 31 32 36 35 44 43 47 48 45 46 + operation j= 7 : 7 8 11 12 10 9 1 2 6 5 3 4 + 46 45 48 47 43 44 24 23 22 21 20 19 + 30 29 28 27 26 25 32 31 36 35 34 33 + 41 42 40 39 37 38 17 18 14 13 16 15 + operation j= 8 : 8 7 10 9 11 12 32 31 36 35 34 33 + 45 46 43 44 48 47 23 24 20 19 22 21 + 17 18 14 13 16 15 1 2 6 5 3 4 + 40 39 41 42 38 37 30 29 28 27 26 25 + operation j= 9 : 9 10 12 11 8 7 6 5 1 2 4 3 + 48 47 46 45 44 43 30 29 28 27 26 25 + 24 23 22 21 20 19 40 39 41 42 38 37 + 36 35 32 31 33 34 18 17 16 15 14 13 + operation j=10 : 10 9 8 7 12 11 40 39 41 42 38 37 + 47 48 44 43 46 45 29 30 26 25 28 27 + 18 17 16 15 14 13 6 5 1 2 4 3 + 32 31 36 35 34 33 24 23 22 21 20 19 + operation j=11 : 11 12 7 8 9 10 41 42 40 39 37 38 + 44 43 47 48 45 46 18 17 16 15 14 13 + 29 30 26 25 28 27 36 35 32 31 33 34 + 1 2 6 5 3 4 23 24 20 19 22 21 + operation j=12 : 12 11 9 10 7 8 36 35 32 31 33 34 + 43 44 45 46 47 48 17 18 14 13 16 15 + 23 24 20 19 22 21 41 42 40 39 37 38 + 6 5 1 2 4 3 29 30 26 25 28 27 + operation j=13 : 13 14 18 17 16 15 46 45 48 47 44 43 + 1 2 6 5 4 3 41 42 40 39 38 37 + 36 35 32 31 34 33 28 27 30 29 26 25 + 24 23 22 21 19 20 12 11 8 7 10 9 + operation j=14 : 14 13 16 15 18 17 28 27 30 29 26 25 + 2 1 4 3 6 5 42 41 38 37 40 39 + 12 11 8 7 10 9 46 45 48 47 44 43 + 22 21 24 23 20 19 36 35 32 31 34 33 + operation j=15 : 15 16 17 18 14 13 48 47 46 45 43 44 + 6 5 1 2 3 4 36 35 32 31 34 33 + 41 42 40 39 38 37 22 21 24 23 20 19 + 30 29 28 27 25 26 11 12 10 9 8 7 + operation j=16 : 16 15 14 13 17 18 22 21 24 23 20 19 + 5 6 3 4 1 2 35 36 34 33 32 31 + 11 12 10 9 8 7 48 47 46 45 43 44 + 28 27 30 29 26 25 41 42 40 39 38 37 + operation j=17 : 17 18 15 16 13 14 30 29 28 27 25 26 + 4 3 2 1 5 6 12 11 8 7 10 9 + 42 41 38 37 40 39 24 23 22 21 19 20 + 48 47 46 45 43 44 35 36 34 33 32 31 + operation j=18 : 18 17 13 14 15 16 24 23 22 21 19 20 + 3 4 5 6 2 1 11 12 10 9 8 7 + 35 36 34 33 32 31 30 29 28 27 25 26 + 46 45 48 47 44 43 42 41 38 37 40 39 + operation j=19 : 19 20 24 23 22 21 44 43 47 48 46 45 + 41 42 40 39 38 37 1 2 6 5 4 3 + 32 31 36 35 33 34 26 25 29 30 28 27 + 18 17 16 15 13 14 8 7 12 11 9 10 + operation j=20 : 20 19 22 21 24 23 26 25 29 30 28 27 + 42 41 38 37 40 39 2 1 4 3 6 5 + 8 7 12 11 9 10 44 43 47 48 46 45 + 16 15 18 17 14 13 32 31 36 35 33 34 + operation j=21 : 21 22 23 24 20 19 47 48 44 43 45 46 + 40 39 41 42 37 38 32 31 36 35 33 34 + 1 2 6 5 4 3 16 15 18 17 14 13 + 29 30 26 25 27 28 7 8 9 10 12 11 + operation j=22 : 22 21 20 19 23 24 16 15 18 17 14 13 + 39 40 37 38 41 42 31 32 33 34 36 35 + 7 8 9 10 12 11 47 48 44 43 45 46 + 26 25 29 30 28 27 1 2 6 5 4 3 + operation j=23 : 23 24 21 22 19 20 29 30 26 25 27 28 + 38 37 42 41 39 40 8 7 12 11 9 10 + 2 1 4 3 6 5 18 17 16 15 13 14 + 47 48 44 43 45 46 31 32 33 34 36 35 + operation j=24 : 24 23 19 20 21 22 18 17 16 15 13 14 + 37 38 39 40 42 41 7 8 9 10 12 11 + 31 32 33 34 36 35 29 30 26 25 27 28 + 44 43 47 48 46 45 2 1 4 3 6 5 + operation j=25 : 25 26 30 29 28 27 43 44 45 46 48 47 + 36 35 32 31 34 33 6 5 1 2 3 4 + 40 39 41 42 37 38 20 19 23 24 22 21 + 17 18 14 13 15 16 10 9 11 12 7 8 + operation j=26 : 26 25 28 27 30 29 20 19 23 24 22 21 + 35 36 34 33 32 31 5 6 3 4 1 2 + 10 9 11 12 7 8 43 44 45 46 48 47 + 14 13 17 18 16 15 40 39 41 42 37 38 + operation j=27 : 27 28 29 30 26 25 45 46 43 44 47 48 + 32 31 36 35 33 34 40 39 41 42 37 38 + 6 5 1 2 3 4 14 13 17 18 16 15 + 23 24 20 19 21 22 9 10 7 8 11 12 + operation j=28 : 28 27 26 25 29 30 14 13 17 18 16 15 + 31 32 33 34 36 35 39 40 37 38 41 42 + 9 10 7 8 11 12 45 46 43 44 47 48 + 20 19 23 24 22 21 6 5 1 2 3 4 + operation j=29 : 29 30 27 28 25 26 23 24 20 19 21 22 + 34 33 35 36 31 32 10 9 11 12 7 8 + 5 6 3 4 1 2 17 18 14 13 15 16 + 45 46 43 44 47 48 39 40 37 38 41 42 + operation j=30 : 30 29 25 26 27 28 17 18 14 13 15 16 + 33 34 31 32 35 36 9 10 7 8 11 12 + 39 40 37 38 41 42 23 24 20 19 21 22 + 43 44 45 46 48 47 5 6 3 4 1 2 + operation j=31 : 31 32 35 36 34 33 2 1 4 3 5 6 + 28 27 30 29 25 26 22 21 24 23 19 20 + 48 47 46 45 44 43 8 7 12 11 10 9 + 42 41 38 37 39 40 15 16 13 14 18 17 + operation j=32 : 32 31 34 33 35 36 8 7 12 11 10 9 + 27 28 25 26 30 29 21 22 19 20 24 23 + 15 16 13 14 18 17 2 1 4 3 5 6 + 38 37 42 41 40 39 48 47 46 45 44 43 + operation j=33 : 33 34 36 35 32 31 4 3 2 1 6 5 + 30 29 28 27 26 25 48 47 46 45 44 43 + 22 21 24 23 19 20 38 37 42 41 40 39 + 12 11 8 7 9 10 16 15 18 17 13 14 + operation j=34 : 34 33 32 31 36 35 38 37 42 41 40 39 + 29 30 26 25 28 27 47 48 44 43 46 45 + 16 15 18 17 13 14 4 3 2 1 6 5 + 8 7 12 11 10 9 22 21 24 23 19 20 + operation j=35 : 35 36 31 32 33 34 42 41 38 37 39 40 + 26 25 29 30 27 28 16 15 18 17 13 14 + 47 48 44 43 46 45 12 11 8 7 9 10 + 2 1 4 3 5 6 21 22 19 20 24 23 + operation j=36 : 36 35 33 34 31 32 12 11 8 7 9 10 + 25 26 27 28 29 30 15 16 13 14 18 17 + 21 22 19 20 24 23 42 41 38 37 39 40 + 4 3 2 1 6 5 47 48 44 43 46 45 + operation j=37 : 37 38 41 42 40 39 3 4 5 6 1 2 + 24 23 22 21 20 19 46 45 48 47 43 44 + 28 27 30 29 25 26 34 33 35 36 32 31 + 11 12 10 9 7 8 14 13 17 18 15 16 + operation j=38 : 38 37 40 39 41 42 34 33 35 36 32 31 + 23 24 20 19 22 21 45 46 43 44 48 47 + 14 13 17 18 15 16 3 4 5 6 1 2 + 10 9 11 12 8 7 28 27 30 29 25 26 + operation j=39 : 39 40 42 41 38 37 5 6 3 4 2 1 + 22 21 24 23 19 20 28 27 30 29 25 26 + 46 45 48 47 43 44 10 9 11 12 8 7 + 35 36 34 33 31 32 13 14 15 16 17 18 + operation j=40 : 40 39 38 37 42 41 10 9 11 12 8 7 + 21 22 19 20 24 23 27 28 25 26 30 29 + 13 14 15 16 17 18 5 6 3 4 2 1 + 34 33 35 36 32 31 46 45 48 47 43 44 + operation j=41 : 41 42 37 38 39 40 11 12 10 9 7 8 + 19 20 21 22 23 24 13 14 15 16 17 18 + 27 28 25 26 30 29 35 36 34 33 31 32 + 3 4 5 6 1 2 45 46 43 44 48 47 + operation j=42 : 42 41 39 40 37 38 35 36 34 33 31 32 + 20 19 23 24 21 22 14 13 17 18 15 16 + 45 46 43 44 48 47 11 12 10 9 7 8 + 5 6 3 4 2 1 27 28 25 26 30 29 + operation j=43 : 43 44 48 47 46 45 25 26 27 28 30 29 + 12 11 8 7 10 9 4 3 2 1 5 6 + 38 37 42 41 39 40 19 20 21 22 24 23 + 15 16 13 14 17 18 34 33 35 36 31 32 + operation j=44 : 44 43 46 45 48 47 19 20 21 22 24 23 + 11 12 10 9 8 7 3 4 5 6 2 1 + 34 33 35 36 31 32 25 26 27 28 30 29 + 13 14 15 16 18 17 38 37 42 41 39 40 + operation j=45 : 45 46 47 48 44 43 27 28 25 26 29 30 + 8 7 12 11 9 10 38 37 42 41 39 40 + 4 3 2 1 5 6 13 14 15 16 18 17 + 21 22 19 20 23 24 33 34 31 32 35 36 + operation j=46 : 46 45 44 43 47 48 13 14 15 16 18 17 + 7 8 9 10 12 11 37 38 39 40 42 41 + 33 34 31 32 35 36 27 28 25 26 29 30 + 19 20 21 22 24 23 4 3 2 1 5 6 + operation j=47 : 47 48 45 46 43 44 21 22 19 20 23 24 + 10 9 11 12 7 8 34 33 35 36 31 32 + 3 4 5 6 2 1 15 16 13 14 17 18 + 27 28 25 26 29 30 37 38 39 40 42 41 + operation j=48 : 48 47 43 44 45 46 15 16 13 14 17 18 + 9 10 7 8 11 12 33 34 31 32 35 36 + 37 38 39 40 42 41 21 22 19 20 23 24 + 25 26 27 28 30 29 3 4 5 6 2 1 + + + Space group can be generated using 5 generators: 13 4 9 34 2 + + generators (in lattice coordinates): + +&gen 5 + + -1 0 0 0.00000 + 0 -1 0 0.00000 + 0 0 -1 0.00000 + + 0 -1 0 0.00000 + 1 -1 0 0.00000 + 0 -1 1 0.00000 + + 0 1 -1 0.00000 + 1 0 -1 0.00000 + 0 0 -1 0.00000 + + 0 -1 1 0.00000 + 0 -1 0 0.00000 + 1 -1 0 0.00000 + + -1 0 0 0.00000 + -1 1 0 0.00000 + -1 0 1 0.00000 + +/ ! end generators + + + + Atomic positions: + ----------------- + atom types = 1 + total = 1 + + lattice coordinates (scaled) Cartesian coordinates atom + + atom type 1: atomic identification number = 74.0 representative = 1 + 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1 + +atoms% 1 atoms 1 + Z( 1)= 74 atoms 1 + 0.000000 0.000000 0.000000 1 + ---------------------------------------------------- + Suggested values for input: + + Atom Z lmax jri rmt dx + W 74 10 841 2.544787 0.015844 +k_max = 3.92960 +G_max =11.78881 + + =============================================== + === modifying atomic input for &(all)atom === + =============================================== + +for atom 1 ( W) changed rmt to 2.100000 +for atom 1 ( W) changed jri to 981 +for atom 1 ( W) changed lmax to 12 +for atom 1 ( W) changed lnonsph to 6 +for atom 1 ( W) set econfig to [Kr] 4d10 4f14 | 5s2 5p6 6s2 5d4 + corestates = 16 with 60.0 electrons + valence st.= 5 with 14.0 electrons +nlod = 2 llod = 1 : 5s5p + nlo( 1) = 2 llo = 0 1 + lonqn = 5 5 +line: 13>&comp +line: 14>gmax=15.0 gmaxxc=12.5 kmax=5.0 / + ---------- + core : 1 -1 2.0 + core : 2 -1 2.0 + core : 2 1 2.0 + core : 2 -2 4.0 + core : 3 -1 2.0 + core : 3 1 2.0 + core : 3 -2 4.0 + core : 3 2 4.0 + core : 3 -3 6.0 + core : 4 -1 2.0 + core : 4 1 2.0 + core : 4 -2 4.0 + core : 4 2 4.0 + core : 4 -3 6.0 + core : 4 3 6.0 + core : 4 -4 8.0 + valence : 5 -1 2.0 5s + valence : 5 1 2.0 5p + valence : 5 -2 4.0 5p + valence : 6 -1 2.0 6s + valence : 5 2 2.0 5d + valence : 5 -3 2.0 5d + ---------- +Valence Electrons = 14 + ---------------------------------------------------- + Suggested values for input: + + Atom Z lmax jri rmt dx + W 74 10 841 2.544787 0.015844 +k_max = 3.92960 +G_max =11.78881 +line: 15>&kpt +line: 16>div1=3 div2=3 div3=3 tkb=0.0005 / + 5.22007561238382 5.22007561238382 5.22007561238382 + -0.333333333333333 -0.333333333333333 -0.333333333333333 + body centered cubic + values accepted unchanged + 3 3 3 nmop(i),i=1,3 + orientation of boundary faces + 1 -1 -0.5740361 ifac,iside,orient for xvec + 2 -1 -0.0454288 ifac,iside,orient for xvec + 3 -1 -0.0256305 ifac,iside,orient for xvec + 4 -1 -0.0469244 ifac,iside,orient for xvec +Bravais lattice vectors + -3.013812 3.013812 3.013812 + 3.013812 -3.013812 3.013812 + 3.013812 3.013812 -3.013812 +reciprocal lattice vectors + 0.000000 1.042398 1.042398 + 1.042398 0.000000 1.042398 + 1.042398 1.042398 0.000000 + 3 3 3 Monkhorst-Pack-parameters + 0 nreg; k-points in irreducible wedge of BZ + Monkhorst-Pack-fractions + 0 nbound; no k-points on boundary of BZ + 1 idim + -0.3333333 + 0.0000000 + 0.3333333 + 2 idim + -0.3333333 + 0.0000000 + 0.3333333 + 3 idim + -0.3333333 + 0.0000000 + 0.3333333 + +k-point count: 4 + +k-point mesh: 3 3 3 +k-point density: 2.035038 2.035038 2.035038 + diff --git a/tests/parsers/fixtures/inpgen/novalid_inpxml/out.error b/tests/parsers/fixtures/inpgen/novalid_inpxml/out.error new file mode 100644 index 000000000..e69de29bb diff --git a/tests/parsers/test_fleur_parser.py b/tests/parsers/test_fleur_parser.py index b7737651e..e6cbe1a1b 100644 --- a/tests/parsers/test_fleur_parser.py +++ b/tests/parsers/test_fleur_parser.py @@ -1,10 +1,19 @@ # -*- coding: utf-8 -*- -''' Contains tests for routines used by the fleur parser. ''' +''' Contains tests for the fleur parser and its routines. ''' from __future__ import absolute_import import os import pytest import math +from aiida.common import AttributeDict +from aiida import orm +import aiida_fleur +#TODO use pytest-regression for full dict tests, easier to update if parser changes. + +aiida_path = os.path.dirname(aiida_fleur.__file__) +TEST_INP_XML_PATH = os.path.join(aiida_path, '../tests/files/inpxml/Si/inp.xml') +# for relaxation path +TEST_INP_XML_PATH1 = os.path.join(aiida_path, '../tests/parsers/fixtures/fleur/relax/inp.xml') # parse_xmlout_file @@ -28,7 +37,7 @@ def test_parse_xmlout_file(): 'creator_target_architecture': 'GEN', 'creator_target_structure': ' ', 'density_convergence_units': 'me/bohr^3', - 'energy': -23635.691764717936, + 'energy': -23635.691961010132, 'energy_core_electrons': -496.172547773, 'energy_hartree': -868.5956587197, 'energy_hartree_units': 'Htr', @@ -67,7 +76,7 @@ def test_parse_xmlout_file(): } } - expected_parser_info_out = {'parser_info': 'AiiDA Fleur Parser v0.3.0', 'parser_warnings': [], 'unparsed': []} + expected_parser_info_out = {'parser_info': 'AiiDA Fleur Parser v0.3.2', 'parser_warnings': [], 'unparsed': []} simple_out.pop('outputfile_path', None) # otherwise test will fail on different installations # also this should go away any way... @@ -93,7 +102,7 @@ def test_parse_xmlout_file_broken_xmlout_file(): 'last_iteration_parsed': 15, 'parser_info': - 'AiiDA Fleur Parser v0.3.0', + 'AiiDA Fleur Parser v0.3.2', 'parser_warnings': [ 'The out.xml file is broken I try to repair it.', 'Endtime was unparsed, inp.xml prob not complete, do not believe the walltime!' @@ -123,7 +132,7 @@ def test_parse_xmlout_file_broken_first_xmlout_file(): 'last_iteration_parsed': 1, 'parser_info': - 'AiiDA Fleur Parser v0.3.0', + 'AiiDA Fleur Parser v0.3.2', 'parser_warnings': [ 'The out.xml file is broken I try to repair it.', 'Can not get attributename: "units" from node "[]", because node is not an element of etree.', @@ -212,7 +221,7 @@ def test_parse_xmlout_file_fortran_garbage_in_xmlout_file(): expected_parser_info_out = { 'parser_info': - 'AiiDA Fleur Parser v0.3.0', + 'AiiDA Fleur Parser v0.3.2', 'parser_warnings': [ 'Could not convert: "**" to float, ValueError', 'Could not convert: " !#@)!(U$*(Y" to float, ValueError' @@ -252,7 +261,7 @@ def test_parse_xmlout_file_empty_file(): expected_parser_info_out = { 'parser_info': - 'AiiDA Fleur Parser v0.3.0', + 'AiiDA Fleur Parser v0.3.2', 'parser_warnings': [ 'The out.xml file is broken I try to repair it.', 'Skipping the parsing of the xml file. Repairing was not possible.' @@ -288,6 +297,18 @@ def test_fleurparse_all_xmlout_file(xmloutfile): assert successful +def test_fleurparse_relax_file(): + """Test if parsing of a given relax.xml file is successfull""" + from aiida_fleur.parsers.fleur import parse_relax_file + from aiida.orm import Dict + + filename = os.path.abspath('./files/relaxxml/Fe_relax.xml') + with open(filename, 'r') as relaxfile: + result = parse_relax_file(relaxfile) + assert isinstance(result, Dict) + assert result.get_dict() != {} + + # parse_dos_file, test for different dos files with spin and without @pytest.mark.skip(reason='Test is not implemented') def test_parse_dos_file(): @@ -317,3 +338,199 @@ def test_parse_bands_file(): # test if the right aiida datastructures are produced for different output # also check if errors are working... # if an empty and broken file works, broken before and after first iteration + + +def test_fleur_parser_default_full(fixture_localhost, generate_parser, generate_calc_job_node, create_fleurinp, + data_regression): + """ + Default inpgen parser test of a successful inpgen calculation. + Checks via data regression if attributes of outputparamters are the same + """ + + name = 'default' + entry_point_calc_job = 'fleur.fleur' + entry_point_parser = 'fleur.fleurparser' + + inputs = AttributeDict({'fleurinp': create_fleurinp(TEST_INP_XML_PATH), 'metadata': {}}) + + #change retrieve list to save space + retrieve_list = [ + 'out.xml', 'inp.xml', 'shell.out', 'out.error', 'cdn1', '_scheduler-stdout.txt', '_scheduler-stderr.txt' + ] + node = generate_calc_job_node(entry_point_calc_job, + fixture_localhost, + name, + inputs, + store=True, + retrieve_list=retrieve_list) + parser = generate_parser(entry_point_parser) + results, calcfunction = parser.parse_from_node(node, store_provenance=False) + + assert calcfunction.is_finished, calcfunction.exception + assert calcfunction.is_finished_ok, calcfunction.exit_message + assert not orm.Log.objects.get_logs_for(node), [log.message for log in orm.Log.objects.get_logs_for(node)] + assert 'output_parameters' in results + assert 'output_params_complex' not in results + assert 'relax_parameters' not in results + assert 'error_params' not in results + + data_regression.check({ + 'output_parameters': clean_outdict_for_reg_dump(results['output_parameters'].get_dict()), + }) + + +''' +def test_fleur_parser_band_dos(fixture_localhost, generate_parser, generate_calc_job_node, create_fleurinp, data_regression): + """ + Default inpgen parser test of a successful inpgen calculation. + Checks via data regression if attributes of fleurinp are the same + """ + + name = 'band_dos' + entry_point_calc_job = 'fleur.fleur' + entry_point_parser = 'fleur.fleurparser' + + inputs = AttributeDict({'fleurinp': create_fleurinp(TEST_INP_XML_PATH), + 'metadata' : {}}) + + #change retrieve list to save space + retrieve_list = ['out.xml', 'inp.xml', 'shell.out', 'out.error','cdn1','_scheduler-stdout.txt','_scheduler-stderr.txt'] + node = generate_calc_job_node(entry_point_calc_job, fixture_localhost, name, inputs, store=True, retrieve_list=retrieve_list) + parser = generate_parser(entry_point_parser) + results, calcfunction = parser.parse_from_node(node, store_provenance=False) + + assert calcfunction.is_finished, calcfunction.exception + assert calcfunction.is_finished_ok, calcfunction.exit_message + assert not orm.Log.objects.get_logs_for(node), [log.message for log in orm.Log.objects.get_logs_for(node)] + assert 'output_parameters' in results + assert 'output_params_complex' not in results + assert 'relax_parameters' not in results + assert 'error_params' not in results + + data_regression.check({ + 'output_parameters': results['output_parameters'].attributes, + }) +''' + + +def test_fleur_parser_relax(fixture_localhost, generate_parser, generate_calc_job_node, create_fleurinp, + data_regression): + """ + Default inpgen parser test of a successful inpgen calculation. + Checks via data regression if attributes of fleurinp are the same + """ + + name = 'relax' + entry_point_calc_job = 'fleur.fleur' + entry_point_parser = 'fleur.fleurparser' + + inputs = AttributeDict({'fleurinp': create_fleurinp(TEST_INP_XML_PATH1), 'metadata': {}}) + + #change retrieve list to save space + retrieve_list = ['out.xml', 'out.error', 'relax.xml'] + node = generate_calc_job_node(entry_point_calc_job, + fixture_localhost, + name, + inputs, + store=True, + retrieve_list=retrieve_list) + parser = generate_parser(entry_point_parser) + results, calcfunction = parser.parse_from_node(node, store_provenance=False) + + assert calcfunction.is_finished, calcfunction.exception + assert calcfunction.is_finished_ok, calcfunction.exit_message + assert not orm.Log.objects.get_logs_for(node), [log.message for log in orm.Log.objects.get_logs_for(node)] + assert 'output_parameters' in results + assert 'output_params_complex' not in results + assert 'relax_parameters' in results + assert 'error_params' not in results + + data_regression.check({ + 'output_parameters': clean_outdict_for_reg_dump(results['output_parameters'].get_dict()), + 'relax_parameters': results['relax_parameters'].get_dict() + }) + + +def test_fleur_parser_MT_overlap_erroroutput(fixture_localhost, generate_parser, generate_calc_job_node, + create_fleurinp, data_regression): + """ + Default inpgen parser test of a failed fleur calculation. + """ + + name = 'mt_overlap_errorout' + entry_point_calc_job = 'fleur.fleur' + entry_point_parser = 'fleur.fleurparser' + + inputs = AttributeDict({'fleurinp': create_fleurinp(TEST_INP_XML_PATH1), 'metadata': {}}) + + #change retrieve list to save space + retrieve_list = ['out.xml', 'out.error', 'relax.xml'] + node = generate_calc_job_node(entry_point_calc_job, + fixture_localhost, + name, + inputs, + store=True, + retrieve_list=retrieve_list) + parser = generate_parser(entry_point_parser) + results, calcfunction = parser.parse_from_node(node, store_provenance=False) + + assert calcfunction.is_finished, calcfunction.exception + assert calcfunction.is_failed, calcfunction.exit_status + assert calcfunction.exit_status == node.process_class.exit_codes.ERROR_MT_RADII_RELAX.status + assert 'output_parameters' not in results + assert 'output_params_complex' not in results + assert 'relax_parameters' not in results + assert 'error_params' in results + data_regression.check({'error_params': results['error_params'].get_dict()}) + + +def test_fleur_parser_complex_erroroutput(fixture_localhost, generate_parser, generate_calc_job_node, create_fleurinp, + data_regression): + """ + Default inpgen parser test of a successful inpgen calculation. + Checks via data regression if attributes of fleurinp are the same + """ + + name = 'complex_errorout' + entry_point_calc_job = 'fleur.fleur' + entry_point_parser = 'fleur.fleurparser' + + inputs = AttributeDict({'fleurinp': create_fleurinp(TEST_INP_XML_PATH), 'metadata': {}}) + + #change retrieve list to save space + retrieve_list = ['out.xml', 'out.error', 'usage.json'] + node = generate_calc_job_node(entry_point_calc_job, + fixture_localhost, + name, + inputs, + store=True, + retrieve_list=retrieve_list) + parser = generate_parser(entry_point_parser) + results, calcfunction = parser.parse_from_node(node, store_provenance=False) + + assert calcfunction.is_finished, calcfunction.exception + assert calcfunction.is_failed, calcfunction.exit_status + assert calcfunction.exit_status == node.process_class.exit_codes.ERROR_FLEUR_CALC_FAILED.status + + assert 'output_parameters' not in results + assert 'output_params_complex' not in results + assert 'relax_parameters' not in results + assert 'error_params' not in results + + +def clean_outdict_for_reg_dump(outdict): + """ + Apparently the regression dumper has problems with + ' ', '0.33', 'fleur 31', dates + we remove these keys. + """ + outdict.pop('creator_target_structure', None) + outdict.pop('creator_name', None) + outdict.pop('creator_target_architecture', None) + outdict.pop('title', None) + outdict.pop('output_file_version', None) + outdict.pop('start_date', None) + outdict.pop('end_date', None) + outdict.pop('relax_atomtype_info', None) + + return outdict diff --git a/tests/parsers/test_fleur_parser/test_fleur_parser_MT_overlap_erroroutput.yml b/tests/parsers/test_fleur_parser/test_fleur_parser_MT_overlap_erroroutput.yml new file mode 100644 index 000000000..52ca0bdcf --- /dev/null +++ b/tests/parsers/test_fleur_parser/test_fleur_parser_MT_overlap_erroroutput.yml @@ -0,0 +1,8 @@ +error_params: + description: This output node contains informationabout FLEUR error + error_name: MT_OVERLAP_RELAX + iteration_number: 3 + overlaping_value: '6.8200E-03' + overlapped_indices: + - '2' + - '1' diff --git a/tests/parsers/test_fleur_parser/test_fleur_parser_default_full.yml b/tests/parsers/test_fleur_parser/test_fleur_parser_default_full.yml new file mode 100644 index 000000000..d68282aba --- /dev/null +++ b/tests/parsers/test_fleur_parser/test_fleur_parser_default_full.yml @@ -0,0 +1,35 @@ +output_parameters: + bandgap: 0.85561712 + bandgap_units: eV + charge_den_xc_den_integral: -41.74447706 + charge_density: 3.29535e-05 + density_convergence_units: me/bohr^3 + energy: -15784.562940686706 + energy_core_electrons: -316.8117176949 + energy_hartree: -580.0719889092 + energy_hartree_units: Htr + energy_units: eV + energy_valence_electrons: 0.1710194344 + fermi_energy: 0.2022322894 + fermi_energy_units: Htr + force_largest: -0.0 + kmax: 3.5 + number_of_atom_types: 1 + number_of_atoms: 2 + number_of_iterations: 11 + number_of_iterations_total: 11 + number_of_kpoints: 60 + number_of_species: 1 + number_of_spin_components: 1 + number_of_symmetries: 48 + parser_info: AiiDA Fleur Parser v0.3.2 + parser_warnings: [] + sum_of_eigenvalues: -316.6406982605 + unparsed: [] + walltime: 4 + walltime_units: seconds + warnings: + debug: {} + error: {} + info: {} + warning: {} diff --git a/tests/parsers/test_fleur_parser/test_fleur_parser_relax.yml b/tests/parsers/test_fleur_parser/test_fleur_parser_relax.yml new file mode 100644 index 000000000..5cc7e75c9 --- /dev/null +++ b/tests/parsers/test_fleur_parser/test_fleur_parser_relax.yml @@ -0,0 +1,82 @@ +output_parameters: + abspos_x_type1: 0.0 + abspos_y_type1: 0.0 + abspos_z_type1: -0.741699 + bandgap: 10.6740023301 + bandgap_units: eV + charge_den_xc_den_integral: -0.6753699578 + density_convergence_units: null + energy: -31.649357888579065 + energy_core_electrons: 0.0 + energy_hartree: -1.1630924497 + energy_hartree_units: Htr + energy_units: eV + energy_valence_electrons: -0.747242106 + fermi_energy: -0.373621053 + fermi_energy_units: Htr + film: 'True' + force_largest: 0.02082935 + force_units: Htr/bohr + force_x_type1: 0.0 + force_y_type1: 0.0 + force_z_type1: 0.02082935 + kmax: 5.0 + number_of_atom_types: 1 + number_of_atoms: 2 + number_of_iterations: 42 + number_of_iterations_total: 142 + number_of_kpoints: 1 + number_of_species: 1 + number_of_spin_components: 1 + number_of_symmetries: 16 + parser_info: AiiDA Fleur Parser v0.3.2 + parser_warnings: + - 'Can not get attributename: "units" from node "[]", because node is not an element + of etree.' + relax_atom_positions: + - - 0.0 + - 0.0 + - -0.741699171 + - - 0.0 + - 0.0 + - 0.741699171 + relax_brav_vectors: + - - 28.345891875 + - 0.0 + - 0.0 + - - 0.0 + - 28.345891875 + - 0.0 + - - 0.0 + - 0.0 + - 4.63 + sum_of_eigenvalues: -0.747242106 + unparsed: [] + walltime: 10290 + walltime_units: seconds + warnings: + debug: {} + error: {} + info: {} + warning: {} +relax_parameters: + displacements: + - - 0.0 + - 0.0 + - 0.0246059526 + energies: + - -1.1623986264 + - -1.1630924497 + posforces: + - - - 0.0 + - 0.0 + - -0.75589045 + - 0.0 + - 0.0 + - 0.028382558 + - - - 0.0 + - 0.0 + - -0.741699171 + - 0.0 + - 0.0 + - 0.0208293472 diff --git a/tests/parsers/test_inpgen_parser.py b/tests/parsers/test_inpgen_parser.py index 5c682871c..d70ab37ff 100644 --- a/tests/parsers/test_inpgen_parser.py +++ b/tests/parsers/test_inpgen_parser.py @@ -1,5 +1,117 @@ # -*- coding: utf-8 -*- -# test all routines used by inpgen parser +''' Contains tests for the inpgen parser and its routines. ''' # TODO: implement all # test the full parser itself. + +from aiida.common import AttributeDict +from aiida import orm + + +def test_inpgen_parser_default(fixture_localhost, generate_parser, generate_calc_job_node, generate_structure, + data_regression): + """ + Default inpgen parser test of a successful inpgen calculation. + Checks via data regression if attributes of fleurinp are the same + """ + + name = 'default' + entry_point_calc_job = 'fleur.inpgen' + entry_point_parser = 'fleur.fleurinpgenparser' + + inputs = AttributeDict({'structure': generate_structure(), 'metadata': {}}) + node = generate_calc_job_node(entry_point_calc_job, fixture_localhost, name, inputs, store=True) + parser = generate_parser(entry_point_parser) + results, calcfunction = parser.parse_from_node(node, store_provenance=False) + + assert calcfunction.is_finished, calcfunction.exception + assert calcfunction.is_finished_ok, calcfunction.exit_message + assert not orm.Log.objects.get_logs_for(node), [log.message for log in orm.Log.objects.get_logs_for(node)] + assert 'fleurinpData' in results + + data_regression.check({ + 'fleurinpData': results['fleurinpData'].inp_dict, + }) + + +def test_inpgen_parser_no_inpxml(fixture_localhost, generate_parser, generate_calc_job_node, generate_structure): + """ + Default inpgen parser test of a failed inpgen calculation, inp.xml file missing. + """ + + name = 'no_inpxml' + entry_point_calc_job = 'fleur.inpgen' + entry_point_parser = 'fleur.fleurinpgenparser' + + inputs = AttributeDict({'structure': generate_structure(), 'metadata': {}}) + node = generate_calc_job_node(entry_point_calc_job, fixture_localhost, name, inputs, store=True) + parser = generate_parser(entry_point_parser) + results, calcfunction = parser.parse_from_node(node, store_provenance=False) + + assert calcfunction.is_finished, calcfunction.exception + assert calcfunction.is_failed, calcfunction.exit_status + assert calcfunction.exit_status == node.process_class.exit_codes.ERROR_NO_INPXML.status + assert 'fleurinpData' not in results + + +def test_inpgen_parser_no_other_files(fixture_localhost, generate_parser, generate_calc_job_node, generate_structure): + """ + Default inpgen parser test of a failed inpgen calculation, where files are missing. + """ + + name = 'no_otherfiles' + entry_point_calc_job = 'fleur.inpgen' + entry_point_parser = 'fleur.fleurinpgenparser' + + inputs = AttributeDict({'structure': generate_structure(), 'metadata': {}}) + node = generate_calc_job_node(entry_point_calc_job, fixture_localhost, name, inputs, store=True) + parser = generate_parser(entry_point_parser) + results, calcfunction = parser.parse_from_node(node, store_provenance=False) + + assert calcfunction.is_finished, calcfunction.exception + assert calcfunction.is_failed, calcfunction.exit_status + assert calcfunction.exit_status == node.process_class.exit_codes.ERROR_MISSING_RETRIEVED_FILES.status + assert 'fleurinpData' not in results + + +def test_inpgen_parser_broken_inpxml(fixture_localhost, generate_parser, generate_calc_job_node, generate_structure): + """ + Default inpgen parser test of a failed inpgen calculation with broken xml. + """ + + name = 'broken_inpxml' + entry_point_calc_job = 'fleur.inpgen' + entry_point_parser = 'fleur.fleurinpgenparser' + + inputs = AttributeDict({'structure': generate_structure(), 'metadata': {}}) + node = generate_calc_job_node(entry_point_calc_job, fixture_localhost, name, inputs, store=True) + parser = generate_parser(entry_point_parser) + results, calcfunction = parser.parse_from_node(node, store_provenance=False) + + assert calcfunction.is_finished, calcfunction.exception + assert calcfunction.is_failed, calcfunction.exit_status + assert calcfunction.exit_status == node.process_class.exit_codes.ERROR_FLEURINPDATA_INPUT_NOT_VALID.status + assert 'fleurinpData' not in results + + +def test_inpgen_parser_nonvalid_inpxml(fixture_localhost, generate_parser, generate_calc_job_node, generate_structure): + """ + Default inpgen parser test of a failed inpgen calculation with non valid inpmxl. + """ + + name = 'novalid_inpxml' + entry_point_calc_job = 'fleur.inpgen' + entry_point_parser = 'fleur.fleurinpgenparser' + + inputs = AttributeDict({'structure': generate_structure(), 'metadata': {}}) + node = generate_calc_job_node(entry_point_calc_job, fixture_localhost, name, inputs, store=True) + parser = generate_parser(entry_point_parser) + results, calcfunction = parser.parse_from_node(node, store_provenance=False) + + assert calcfunction.is_finished, calcfunction.exception + assert calcfunction.is_failed, calcfunction.exit_status + assert calcfunction.exit_status == node.process_class.exit_codes.ERROR_FLEURINPDATA_INPUT_NOT_VALID.status + assert 'fleurinpData' not in results + + +# TODO test multi files, enpara, kpts, relax.xml nnmpmat ... diff --git a/tests/parsers/test_inpgen_parser/test_inpgen_parser_default.yml b/tests/parsers/test_inpgen_parser/test_inpgen_parser_default.yml new file mode 100644 index 000000000..45b4bbfde --- /dev/null +++ b/tests/parsers/test_inpgen_parser/test_inpgen_parser_default.yml @@ -0,0 +1,338 @@ +fleurinpData: + atomGroups: + atomGroup: + - force: + calculate: true + relaxXYZ: TTT + nocoParams: + alpha: 0.0 + b_cons_x: '.00000000' + b_cons_y: '.00000000' + beta: '.00000000' + l_relax: F + relPos: + - .0000000000 .0000000000 .0000000000 + species: W-1 + atomSpecies: + species: + - atomicCutoffs: + lmax: 12 + lnonsphr: 6 + atomicNumber: 74 + coreStates: 16 + electronConfig: + coreConfig: '[Kr] (4d3/2) (4d5/2) (4f5/2) (4f7/2)' + stateOccupation: + - spinDown: '.00000000' + spinUp: '2.00000000' + state: (5d3/2) + - spinDown: '.00000000' + spinUp: '2.00000000' + state: (5d5/2) + valenceConfig: (5s1/2) (5p1/2) (5p3/2) (6s1/2) (5d3/2) (5d5/2) + element: W + energyParameters: + d: 5 + f: 5 + p: 6 + s: 6 + flipSpin: true + lo: + - eDeriv: 0 + l: 0 + n: 5 + type: SCLO + - eDeriv: 0 + l: 1 + n: 5 + type: SCLO + magMom: 0.0 + mtSphere: + gridPoints: 981 + logIncrement: 0.016 + radius: 2.1 + name: W-1 + prodBasis: + lcutm: '4' + lcutwf: '11' + select: 4 0 4 2 + calculationSetup: + bzIntegration: + altKPointSet: + kPointCount: + count: 240 + gamma: false + purpose: bands + fermiSmearingEnergy: 0.0005 + kPointList: + count: 4 + kPoint: + - -0.000000 0.333333 0.333333 + - -0.333333 0.333333 0.333333 + - -0.000000 0.000000 0.333333 + - 0.000000 0.000000 0.000000 + posScale: '1.00000000' + weightScale: '1.00000000' + mode: hist + valenceElectrons: 14.0 + coreElectrons: + coretail_lmax: '0' + ctail: true + frcor: false + kcrel: 0 + cutoffs: + Gmax: 15.0 + GmaxXC: 12.5 + Kmax: 5.0 + numbands: 0 + energyParameterLimits: + ellow: -1.8 + elup: 1.0 + expertModes: + gw: 0 + secvar: false + geometryOptimization: + epsdisp: 1.0e-05 + epsforce: 1.0e-05 + forcealpha: 1.0 + forcemix: BFGS + l_f: false + ldaU: + - l_linMix: false + mixParam: 0.05 + spinf: 1.0 + magnetism: + jspins: 1 + l_noco: false + lflip: false + swsp: false + nocoParams: + l_constr: F + l_mperp: F + l_ss: false + mix_b: '.00000000' + qss: .0000000000 .0000000000 .0000000000 + prodBasis: + bands: '0' + ewaldlambda: '3' + gcutm: '3.40000000' + lexp: '16' + tolerance: '.00010000' + scfLoop: + alpha: 0.05 + imix: Anderson + itmax: 15 + maxIterBroyd: 99 + minDistance: 1.0e-05 + precondParam: '0.0' + spinf: 2.0 + soc: + l_soc: false + phi: 0.0 + spav: false + theta: 0.0 + cell: + bulkLattice: + bravaisMatrix: + row-1: -3.013812060000000 3.013812060000000 3.013812060000000 + row-2: 3.013812060000000 -3.013812060000000 3.013812060000000 + row-3: 3.013812060000000 3.013812060000000 -3.013812060000000 + latnam: any + scale: 1.0 + symmetryOperations: + symOp: + - row-1: 1 0 0 .0000000000 + row-2: 0 1 0 .0000000000 + row-3: 0 0 1 .0000000000 + - row-1: -1 0 0 .0000000000 + row-2: -1 1 0 .0000000000 + row-3: -1 0 1 .0000000000 + - row-1: 1 -1 0 .0000000000 + row-2: 0 -1 0 .0000000000 + row-3: 0 -1 1 .0000000000 + - row-1: 0 -1 0 .0000000000 + row-2: 1 -1 0 .0000000000 + row-3: 0 -1 1 .0000000000 + - row-1: -1 1 0 .0000000000 + row-2: -1 0 0 .0000000000 + row-3: -1 0 1 .0000000000 + - row-1: 0 1 0 .0000000000 + row-2: 1 0 0 .0000000000 + row-3: 0 0 1 .0000000000 + - row-1: 1 0 -1 .0000000000 + row-2: 0 1 -1 .0000000000 + row-3: 0 0 -1 .0000000000 + - row-1: 0 0 -1 .0000000000 + row-2: 0 1 -1 .0000000000 + row-3: 1 0 -1 .0000000000 + - row-1: 0 1 -1 .0000000000 + row-2: 1 0 -1 .0000000000 + row-3: 0 0 -1 .0000000000 + - row-1: 0 1 -1 .0000000000 + row-2: 0 0 -1 .0000000000 + row-3: 1 0 -1 .0000000000 + - row-1: 1 0 -1 .0000000000 + row-2: 0 0 -1 .0000000000 + row-3: 0 1 -1 .0000000000 + - row-1: 0 0 -1 .0000000000 + row-2: 1 0 -1 .0000000000 + row-3: 0 1 -1 .0000000000 + - row-1: -1 0 0 .0000000000 + row-2: 0 -1 0 .0000000000 + row-3: 0 0 -1 .0000000000 + - row-1: 1 0 0 .0000000000 + row-2: 1 -1 0 .0000000000 + row-3: 1 0 -1 .0000000000 + - row-1: 0 -1 0 .0000000000 + row-2: -1 0 0 .0000000000 + row-3: 0 0 -1 .0000000000 + - row-1: 1 -1 0 .0000000000 + row-2: 1 0 0 .0000000000 + row-3: 1 0 -1 .0000000000 + - row-1: 0 1 0 .0000000000 + row-2: -1 1 0 .0000000000 + row-3: 0 1 -1 .0000000000 + - row-1: -1 1 0 .0000000000 + row-2: 0 1 0 .0000000000 + row-3: 0 1 -1 .0000000000 + - row-1: -1 0 0 .0000000000 + row-2: 0 0 -1 .0000000000 + row-3: 0 -1 0 .0000000000 + - row-1: 1 0 0 .0000000000 + row-2: 1 0 -1 .0000000000 + row-3: 1 -1 0 .0000000000 + - row-1: 0 -1 0 .0000000000 + row-2: 0 0 -1 .0000000000 + row-3: -1 0 0 .0000000000 + - row-1: 1 -1 0 .0000000000 + row-2: 1 0 -1 .0000000000 + row-3: 1 0 0 .0000000000 + - row-1: 0 1 0 .0000000000 + row-2: 0 1 -1 .0000000000 + row-3: -1 1 0 .0000000000 + - row-1: -1 1 0 .0000000000 + row-2: 0 1 -1 .0000000000 + row-3: 0 1 0 .0000000000 + - row-1: 0 0 -1 .0000000000 + row-2: -1 0 0 .0000000000 + row-3: 0 -1 0 .0000000000 + - row-1: 1 0 -1 .0000000000 + row-2: 1 0 0 .0000000000 + row-3: 1 -1 0 .0000000000 + - row-1: 0 0 -1 .0000000000 + row-2: 0 -1 0 .0000000000 + row-3: -1 0 0 .0000000000 + - row-1: 1 0 -1 .0000000000 + row-2: 1 -1 0 .0000000000 + row-3: 1 0 0 .0000000000 + - row-1: 0 1 -1 .0000000000 + row-2: 0 1 0 .0000000000 + row-3: -1 1 0 .0000000000 + - row-1: 0 1 -1 .0000000000 + row-2: -1 1 0 .0000000000 + row-3: 0 1 0 .0000000000 + - row-1: -1 0 1 .0000000000 + row-2: -1 1 0 .0000000000 + row-3: -1 0 0 .0000000000 + - row-1: 0 0 1 .0000000000 + row-2: 0 1 0 .0000000000 + row-3: 1 0 0 .0000000000 + - row-1: 0 -1 1 .0000000000 + row-2: 1 -1 0 .0000000000 + row-3: 0 -1 0 .0000000000 + - row-1: 0 -1 1 .0000000000 + row-2: 0 -1 0 .0000000000 + row-3: 1 -1 0 .0000000000 + - row-1: -1 0 1 .0000000000 + row-2: -1 0 0 .0000000000 + row-3: -1 1 0 .0000000000 + - row-1: 0 0 1 .0000000000 + row-2: 1 0 0 .0000000000 + row-3: 0 1 0 .0000000000 + - row-1: 1 -1 0 .0000000000 + row-2: 0 -1 1 .0000000000 + row-3: 0 -1 0 .0000000000 + - row-1: 0 -1 0 .0000000000 + row-2: 0 -1 1 .0000000000 + row-3: 1 -1 0 .0000000000 + - row-1: -1 1 0 .0000000000 + row-2: -1 0 1 .0000000000 + row-3: -1 0 0 .0000000000 + - row-1: 0 1 0 .0000000000 + row-2: 0 0 1 .0000000000 + row-3: 1 0 0 .0000000000 + - row-1: 1 0 0 .0000000000 + row-2: 0 0 1 .0000000000 + row-3: 0 1 0 .0000000000 + - row-1: -1 0 0 .0000000000 + row-2: -1 0 1 .0000000000 + row-3: -1 1 0 .0000000000 + - row-1: 0 0 1 .0000000000 + row-2: -1 0 1 .0000000000 + row-3: 0 -1 1 .0000000000 + - row-1: -1 0 1 .0000000000 + row-2: 0 0 1 .0000000000 + row-3: 0 -1 1 .0000000000 + - row-1: 0 0 1 .0000000000 + row-2: 0 -1 1 .0000000000 + row-3: -1 0 1 .0000000000 + - row-1: -1 0 1 .0000000000 + row-2: 0 -1 1 .0000000000 + row-3: 0 0 1 .0000000000 + - row-1: 0 -1 1 .0000000000 + row-2: 0 0 1 .0000000000 + row-3: -1 0 1 .0000000000 + - row-1: 0 -1 1 .0000000000 + row-2: -1 0 1 .0000000000 + row-3: 0 0 1 .0000000000 + comment: A Fleur input generator calculation with aiida + fleurInputVersion: '0.31' + output: + band: false + chargeDensitySlicing: + maxEigenval: 0.0 + minEigenval: 0.0 + nnne: 0 + numkpt: 0 + pallst: false + checks: + cdinf: false + vchk: false + densityOfStates: + maxEnergy: 0.5 + minEnergy: -0.5 + ndir: 0 + sigma: 0.015 + dos: false + magneticCircularDichroism: + energyLo: '-10.00000000' + energyUp: '.00000000' + mcd: F + plotting: + iplot: 0 + plplot: false + score: false + slice: false + specialOutput: + bmt: false + eonly: false + unfoldingBand: + supercellX: '1' + supercellY: '1' + supercellZ: '1' + unfoldBand: F + vacdos: false + vacuumDOS: + integ: false + layers: 0 + locx1: 0.0 + locx2: 0.0 + locy1: 0.0 + locy2: 0.0 + nstars: 0 + nstm: 0 + star: false + tworkf: 0.0 + xcFunctional: + name: pbe + relativisticCorrections: false diff --git a/tests/pylint.svg b/tests/pylint.svg deleted file mode 100644 index 61836ac08..000000000 --- a/tests/pylint.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - pylint - pylint - 6.91 - 7.49 - - diff --git a/tests/run_all_cov.sh b/tests/run_all_cov.sh index 59dcd37f3..9f40c5792 100755 --- a/tests/run_all_cov.sh +++ b/tests/run_all_cov.sh @@ -3,7 +3,7 @@ export AIIDA_PATH='.'; mkdir -p '.aiida'; #pytest -sv #pytest -v -pytest --cov-report=term-missing:skip-covered --cov=aiida_fleur +pytest --cov-report=xml --cov=aiida_fleur #pytest --cov-report=html --cov=aiida_fleur #pytest --cov-report=html --cov=aiida_fleur -vv -rXxs -x diff --git a/tests/run_all_cov_show.sh b/tests/run_all_cov_show.sh new file mode 100755 index 000000000..59dcd37f3 --- /dev/null +++ b/tests/run_all_cov_show.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh +export AIIDA_PATH='.'; +mkdir -p '.aiida'; +#pytest -sv +#pytest -v +pytest --cov-report=term-missing:skip-covered --cov=aiida_fleur +#pytest --cov-report=html --cov=aiida_fleur +#pytest --cov-report=html --cov=aiida_fleur -vv -rXxs -x + +# to create badge (requires coverage-badge) +#coverage-badge -o coverage.svg + +# pylint (for shield create, by hand, or write script to write total into svg) +# pylint ../../aiida_fleur/ > outlint diff --git a/tests/test_entrypoints.py b/tests/test_entrypoints.py index 763a7ec30..00ceae9c3 100644 --- a/tests/test_entrypoints.py +++ b/tests/test_entrypoints.py @@ -75,13 +75,6 @@ def test_fleur_dos_wc_entry_point(self): workflow = WorkflowFactory('fleur.dos') assert workflow == fleur_dos_wc - def test_fleur_band_wc_entry_point(self): - from aiida.plugins import WorkflowFactory - from aiida_fleur.workflows.band import FleurBandWorkChain - - workflow = WorkflowFactory('fleur.band') - assert workflow == FleurBandWorkChain - def test_fleur_banddos_wc_entry_point(self): from aiida.plugins import WorkflowFactory from aiida_fleur.workflows.banddos import FleurBandDosWorkChain diff --git a/tests/test_workflows_builder_init.py b/tests/test_workflows_builder_init.py index 5e1cc7e46..15252f411 100644 --- a/tests/test_workflows_builder_init.py +++ b/tests/test_workflows_builder_init.py @@ -55,22 +55,6 @@ def test_fleur_dos_wc_init(self): builder = fleur_dos_wc.get_builder() - def test_fleur_band_wc_init(self): - """ - Test the interface of the band workchain - """ - from aiida_fleur.workflows.band import FleurBandWorkChain - - builder = FleurBandWorkChain.get_builder() - - # def test_fleur_band2_wc_init(self): - # """ - # Test the interface of the band2 workchain - # """ - # from aiida_fleur.workflows.band2 import fleur_band2_wc - # - # builder = fleur_band2_wc.get_builder() - def test_fleur_corehole_wc_init(self): """ Test the interface of the corehole workchain @@ -87,14 +71,6 @@ def test_fleur_initial_cls_wc_init(self): builder = fleur_initial_cls_wc.get_builder() - def test_fleur_delta_wc_init(self): - """ - Test the interface of the delta workchain - """ - from aiida_fleur.workflows.delta import fleur_delta_wc - - builder = fleur_delta_wc.get_builder() - def test_fleur_relax_wc_init(self): """ Test the interface of the relax workchain diff --git a/tests/tools/test_StructureData_util.py b/tests/tools/test_StructureData_util.py index 0542e510c..a6ceaadeb 100644 --- a/tests/tools/test_StructureData_util.py +++ b/tests/tools/test_StructureData_util.py @@ -16,6 +16,7 @@ def test_is_structure(generate_structure): + """Test if is structure can differentiate between structures, identifiers and else""" from aiida_fleur.tools.StructureData_util import is_structure from aiida.orm import Dict @@ -34,6 +35,7 @@ def test_is_structure(generate_structure): def test_is_primitive(generate_structure): + """Test if is_primitive test can distinguish between a primitive and non primitive structure""" from aiida_fleur.tools.StructureData_util import is_primitive structure = generate_structure() structure.store() @@ -51,23 +53,41 @@ def test_is_primitive(generate_structure): def test_rescale_nowf(generate_structure): + """Test to rescale some structure """ from aiida_fleur.tools.StructureData_util import rescale_nowf + from aiida_fleur.tools.StructureData_util import rescale + from aiida.orm import Dict, Float + structure = generate_structure() old_cell = np.array(structure.cell) rescaled = rescale_nowf(structure, 1.05) + rescaled2 = rescale(structure, Float(1.05)) rescaled_cell = np.array(rescaled.cell) + rescaled_cell2 = np.array(rescaled2.cell) assert (rescaled_cell == 1.05**(1 / 3.) * old_cell).all() + #assert (np.round(rescaled_cell2, 13) == 1.05**(1 / 3.) * old_cell).all() + # This does not work, seems to check if it is the same object, not if values are the same + # The precision between these functions is strangely different + assert list(np.round(rescaled_cell[0], 13)) == list(rescaled_cell2[0]) + assert list(np.round(rescaled_cell[1], 13)) == list(rescaled_cell2[1]) + assert list(np.round(rescaled_cell[2], 13)) == list(rescaled_cell2[2]) positions_old = [x.position for x in structure.sites] positions_rescaled = [x.position for x in rescaled.sites] for position in positions_old: assert tuple(pos * 1.05**(1 / 3.) for pos in position) in positions_rescaled + no_struc = Dict(dict={}) + no_rescaled = rescale_nowf(no_struc, 1.05) + assert no_rescaled is None + def test_supercell(generate_structure): + """Test to create a super cell""" from aiida_fleur.tools.StructureData_util import supercell + from aiida_fleur.tools.StructureData_util import supercell_ncf from aiida.orm import Int from itertools import product @@ -89,6 +109,10 @@ def test_supercell(generate_structure): z * np.array(structure.cell[2])) assert test_pos in positions_rescaled + no_struc = Int(1) + no_supercell = supercell_ncf(no_struc, 2, 3, 4) + assert no_supercell is None + def test_abs_to_rel(generate_structure): from aiida_fleur.tools.StructureData_util import abs_to_rel @@ -113,6 +137,7 @@ def test_abs_to_rel_f(generate_film_structure): def test_rel_to_abs(generate_structure): + """Test if rel_to_abs for bulk function scales coordinates right""" from aiida_fleur.tools.StructureData_util import rel_to_abs structure = generate_structure() @@ -124,6 +149,7 @@ def test_rel_to_abs(generate_structure): def test_rel_to_abs_f(generate_film_structure): + """Test if rel_to_abs film function scales coordinates right""" from aiida_fleur.tools.StructureData_util import rel_to_abs_f structure = generate_film_structure() @@ -134,11 +160,10 @@ def test_rel_to_abs_f(generate_film_structure): assert not rel_to_abs_f([1], cell) -def test_break_symmetry_wf(generate_film_structure): - """ - Check if it does not crash and able to destroy all symmetries - """ +def test_break_symmetry_wf_film_structure_only(generate_film_structure): + """Check if it does not crash and able to destroy all symmetries""" from aiida_fleur.tools.StructureData_util import break_symmetry_wf, supercell_ncf + from aiida_fleur.tools.StructureData_util import break_symmetry from aiida.orm import Dict structure = generate_film_structure() @@ -150,12 +175,542 @@ def test_break_symmetry_wf(generate_film_structure): ) structure_broken = out['new_structure'] kind_names = [x.kind_name for x in structure_broken.sites] + kind_names_should = ['Fe1', 'Fe2', 'Fe3', 'Fe4', 'Pt1', 'Pt2', 'Pt3', 'Pt4', 'Pt5', 'Pt6', 'Pt7', 'Pt8'] + for kind_name in kind_names_should: + assert kind_name in kind_names + assert len(set(kind_names)) == len(kind_names_should) + + struc_b_fe, para_new_fe = break_symmetry(structure, atoms=['Fe']) + kind_names = [x.kind_name for x in struc_b_fe.sites] + kind_names_should = ['Fe1', 'Fe2', 'Fe3', 'Fe4', 'Pt'] + for kind_name in kind_names_should: + assert kind_name in kind_names + assert len(set(kind_names)) == len(kind_names_should) - for kind_name in ['Fe1', 'Fe1', 'Fe1', 'Fe1', 'Pt1', 'Pt2', 'Pt3', 'Pt4', 'Pt5', 'Pt6', 'Pt7', 'Pt8']: + struc_b_pt, para_new_pt = break_symmetry(structure, atoms=['Pt']) + kind_names = [x.kind_name for x in struc_b_pt.sites] + kind_names_should = ['Fe', 'Pt1', 'Pt2', 'Pt3', 'Pt4', 'Pt5', 'Pt6', 'Pt7', 'Pt8'] + for kind_name in kind_names_should: assert kind_name in kind_names + assert len(set(kind_names)) == len(kind_names_should) + + struc_b_site, para_new_site = break_symmetry(structure, atoms=[], site=[0, 1]) + kind_names = [x.kind_name for x in struc_b_site.sites] + kind_names_should = ['Fe', 'Fe1', 'Fe2', 'Pt'] + for kind_name in kind_names_should: + assert kind_name in kind_names + assert len(set(kind_names)) == len(kind_names_should) + + pos = [structure.sites[0].position, structure.sites[1].position] + + struc_b_pos, para_new_pos = break_symmetry(structure, atoms=[], pos=pos) + kind_names = [x.kind_name for x in struc_b_pos.sites] + kind_names_should = ['Fe', 'Fe1', 'Fe2', 'Pt'] + for kind_name in kind_names_should: + assert kind_name in kind_names + assert len(set(kind_names)) == len(kind_names_should) + + +def test_break_symmetry_corhole(generate_structure): + """Test if what the corehole workflow does works""" + from aiida_fleur.tools.StructureData_util import break_symmetry + from aiida import orm + + structure = generate_structure() + sites = structure.sites + pos = sites[0].position + kind_name = sites[0].kind_name + para = orm.Dict(dict={ + 'atom': { + 'element': 'Si', + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, + 'comp': { + 'kmax': 5.0, + } + }) + new_kinds_names = {'Si': [kind_name + '_corehole1']} + inputs = dict(structure=structure, + atoms=[], + site=[], + pos=[(pos[0], pos[1], pos[2])], + new_kinds_names=new_kinds_names) + if para is not None: + inputs['parameterdata'] = para + new_struc, new_para = break_symmetry(**inputs) + + #print(new_para.get_dict()) + kind_names = ['Si_corehole1', 'Si'] + for i, site in enumerate(new_struc.sites): + assert site.kind_name == kind_names[i] + + # Test if the kind name was set to the atom lists + should = { + 'atom1': { + 'element': 'Si', + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, + 'comp': { + 'kmax': 5.0 + }, + 'atom2': { + 'element': 'Si', + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6, + 'id': '14.1', + 'name': 'Si_corehole1' + } + } + assert new_para.get_dict() == should + + +def test_break_symmetry_film_parameters_only_simple(generate_film_structure): + """Test if these break symmetry operation adjusted the parameter data right. + This basicly tests + from aiida_fleur.tools.StructureData_util import adjust_calc_para_to_structure + for a separate test we would have to generate these structures again + """ + from aiida_fleur.tools.StructureData_util import break_symmetry + from aiida.orm import Dict + + structure = generate_film_structure() + para = Dict( + dict={ + 'atom': { + 'element': 'Fe', + 'z': 26, + 'rmt': 2.1, + 'bmu': -1 + }, + 'atom1': { + 'element': 'Pt', + 'rmt': 2.2, + 'bmu': 1 + }, + 'comp': { + 'kmax': 5.0, + } + }) + + structure_broken, para_out = break_symmetry(structure, parameterdata=para) + should1 = { + 'atom1': { + 'element': 'Fe', + 'z': 26, + 'rmt': 2.1, + 'bmu': -1 + }, + 'atom2': { + 'element': 'Pt', + 'rmt': 2.2, + 'bmu': 1 + }, + 'comp': { + 'kmax': 5.0 + }, + 'atom3': { + 'element': 'Fe', + 'z': 26, + 'rmt': 2.1, + 'bmu': -1, + 'id': '26.1' + }, + 'atom4': { + 'element': 'Pt', + 'rmt': 2.2, + 'bmu': 1, + 'id': '78.1' + }, + 'atom5': { + 'element': 'Pt', + 'rmt': 2.2, + 'bmu': 1, + 'id': '78.2' + } + } + assert para_out.get_dict() == should1 + + # breaking again should not change something + structure_broken, para_out = break_symmetry(structure_broken, parameterdata=para_out) + assert para_out.get_dict() == should1 + + should2 = { + 'comp': { + 'kmax': 5.0 + }, + 'atom1': { + 'element': 'Fe', + 'z': 26, + 'rmt': 2.1, + 'bmu': -1, + 'id': '26.1' + }, + 'atom2': { + 'element': 'Pt', + 'rmt': 2.2, + 'bmu': 1, + 'id': '78.1' + }, + 'atom3': { + 'element': 'Pt', + 'rmt': 2.2, + 'bmu': 1, + 'id': '78.2' + } + } + structure_broken, para_out = break_symmetry(structure_broken, parameterdata=para_out, add_atom_base_lists=False) + print(para_out.get_dict()) + assert para_out.get_dict() == should2 + + struc_b_fe, para_new_fe = break_symmetry(structure, atoms=['Fe'], parameterdata=para) + + should3 = { + 'atom1': { + 'element': 'Fe', + 'z': 26, + 'rmt': 2.1, + 'bmu': -1 + }, + 'atom2': { + 'element': 'Pt', + 'rmt': 2.2, + 'bmu': 1 + }, + 'comp': { + 'kmax': 5.0 + }, + 'atom3': { + 'element': 'Fe', + 'z': 26, + 'rmt': 2.1, + 'bmu': -1, + 'id': '26.1' + } + } + assert para_new_fe.get_dict() == should3 + + +def test_break_symmetry_film_parameters_only_complex(generate_film_structure): + """Test if these break symmetry operation adjusted the complex parameter data right. + This basicly tests + from aiida_fleur.tools.StructureData_util import adjust_calc_para_to_structure + for a separate test we would have to generate these structures again + """ + from aiida_fleur.tools.StructureData_util import break_symmetry + from aiida.orm import Dict + + structure = generate_film_structure() + para = Dict( + dict={ + 'atom': { + 'element': 'Fe', + 'id': 26.1, + 'rmt': 2.1, + 'bmu': -1 + }, + 'atom1': { + 'element': 'Pt', + 'id': 78.1, + 'rmt': 2.2, + 'bmu': 1 + }, + 'comp': { + 'kmax': 5.0, + } + }) + + structure_broken, para_out = break_symmetry(structure, parameterdata=para) + struc_b_fe, para_new_fe = break_symmetry(structure, atoms=['Fe'], parameterdata=para) + + should1 = { + 'atom1': { + 'element': 'Fe', + 'id': '26.1', + 'rmt': 2.1, + 'bmu': -1 + }, + 'atom2': { + 'element': 'Pt', + 'id': '78.1', + 'rmt': 2.2, + 'bmu': 1 + }, + 'atom3': { + 'element': 'Pt', + 'id': '78.2', + 'rmt': 2.2, + 'bmu': 1 + }, + 'comp': { + 'kmax': 5.0, + } + } + + assert para_out.get_dict() == should1 + + should2 = {'atom1': {'bmu': -1, 'element': 'Fe', 'id': '26.1', 'rmt': 2.1}, 'comp': {'kmax': 5.0}} + assert para_new_fe.get_dict() == should2 + # Deletes the other Ids because Pt had an id + + +''' + + + # old should dict + should_out_dict = { + 'atom': { + 'id': 26, + 'rmt': 2.1, + 'bmu': -1 + }, + 'atom1': { + 'id': 78.1, + 'rmt': 2.1, + 'bmu': -1 + }, + 'atom2': { + 'id': 78.2, + 'rmt': 2.2, + 'bmu': 1 + } + } + + should_out_dict = {'atom1': {'z': 26, 'rmt': 2.1, 'bmu': -1}, + 'atom2': {'z': 26, 'rmt': 2.1, 'bmu': -1, 'id': '26.1'}, + 'atom3': {'z': 26, 'rmt': 2.1, 'bmu': -1, 'id': '26.2'}, + 'atom4': {'z': 26, 'rmt': 2.1, 'bmu': -1, 'id': '26.3'}, + 'atom5': {'z': 26, 'rmt': 2.1, 'bmu': -1, 'id': '26.4'}} + parameter_data = Dict( + dict={ + 'atom': { + 'z': 26, + 'rmt': 2.1, + 'bmu': -1 + }, + 'atom1': { + 'id': 78.1, + 'rmt': 2.1, + 'bmu': -1 + }, + 'atom2': { + 'id': 78.2, + 'rmt': 2.2, + 'bmu': 1 + } + }) + out, parameterdata_new = break_symmetry(structure, parameterdata=parameter_data) + out_dict = parameterdata_new.get_dict() + print(out_dict) + assert out_dict == should_out_dict +''' +''' +def test_break_symmetry_bulk(generate_structure): + """Check if it does not crash and able to destroy all symmetries""" + from aiida_fleur.tools.StructureData_util import break_symmetry, supercell_ncf + from aiida.orm import Dict + + structure = generate_structure() + + # Test if break symmetry adjusts parameters right with simple parameters + + parameter_data = Dict( + dict={ + 'atom': { + 'element': 'Si', + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, + 'comp': { + 'kmax': 5.0, + }}) + structure_broken, parameters1 = break_symmetry(structure, parameterdata=parameter_data) + + print('para1', parameters1.get_dict()) + should_para1 = { + 'atom0': { + 'element': 'Si', + 'id': 14.1, + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, + 'atom1': { + 'element': 'Si', + 'id': 14.2, + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, + 'comp': { + 'kmax': 5.0, + }} + assert parameters1.get_dict() == should_para1 + # Now test if it also adjusts for complex parameters right + parameter_data2 = Dict(dict={ + 'atom1': { + 'element': 'Si', + 'id': 14.1, + 'rmt': 2.2, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, + 'atom2': { + 'element': 'Si', + 'z' : 14, + 'id': 14.2, + 'rmt': 2.1, + 'jri': 981, + 'lmax': 11, + 'lnonsph': 6 + }, + 'atom': { + 'element': 'Si', + 'rmt': 2.0, + 'jri': 981, + 'lmax': 10, + 'lnonsph': 6 + }, + 'comp': { + 'kmax': 5.0, + } + }) + structure = supercell_ncf(structure, 2, 1, 1) + # Test if break symmetry adjusts the parameter data right. + structure_broken, parameters2 = break_symmetry(structure, parameterdata=parameter_data2) + kind_names = [x.kind_name for x in structure_broken.sites] + for kind_name in ['Si1', 'Si2', 'Si3', 'Si4']: + assert kind_name in kind_names + print('para2', parameters2.get_dict()) + para2_should = { + 'atom1': { + 'element': 'Si', + 'id': 14.1, + 'rmt': 2.2, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, + 'atom2': { + 'element': 'Si', + 'z' : 14, + 'id': 14.2, + 'rmt': 2.1, + 'jri': 981, + 'lmax': 11, + 'lnonsph': 6 + }, + 'atom0': { + 'element': 'Si', + 'id': 14.3, + 'rmt': 2.0, + 'jri': 981, + 'lmax': 10, + 'lnonsph': 6 + }, + 'atom3': { + 'element': 'Si', + 'id': 14.4, + 'rmt': 2.0, + 'jri': 981, + 'lmax': 10, + 'lnonsph': 6 + }, + 'comp': { + 'kmax': 5.0, + } + } + + assert para2_should == parameters2.get_dict() + #TODO test break_symmetry with several different elements in parameter and structure +''' + + +def test_adjust_calc_para_to_structure(generate_structure): + """Test intergace of check_structure_para_consistent""" + from aiida_fleur.tools.StructureData_util import adjust_calc_para_to_structure + from aiida_fleur.tools.StructureData_util import break_symmetry + from aiida import orm + + structure = generate_structure() + + parameter_data = orm.Dict(dict={ + 'atom1': { + 'element': 'Si', + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, + 'comp': { + 'kmax': 5.0, + } + }) + new_para = adjust_calc_para_to_structure(parameter_data, structure) + # The parameter data should not be changed + assert new_para.get_dict() == parameter_data.get_dict() + + structure_broken, parameters1 = break_symmetry(structure, parameterdata=parameter_data) + new_para = adjust_calc_para_to_structure(parameter_data, structure_broken) + # The parameter data should be changed and should be the same. + assert new_para.get_dict() == parameters1.get_dict() + + +def test_check_structure_para_consistent(generate_structure): + """Test intergace of check_structure_para_consistent""" + from aiida_fleur.tools.StructureData_util import check_structure_para_consistent + from aiida_fleur.tools.StructureData_util import break_symmetry + from aiida import orm + + structure = generate_structure() + + parameter_data = orm.Dict(dict={ + 'atom': { + 'element': 'Si', + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, + 'comp': { + 'kmax': 5.0, + } + }) + assert check_structure_para_consistent(parameter_data, structure) + + structure_broken, parameters1 = break_symmetry(structure, parameterdata=parameter_data) + assert check_structure_para_consistent(parameters1, structure_broken) + assert check_structure_para_consistent(parameter_data, structure_broken) + + wrong_parameter_data = orm.Dict(dict={ + 'atom': { + 'element': 'P', + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, + 'comp': { + 'kmax': 5.0, + } + }) + assert not check_structure_para_consistent(wrong_parameter_data, structure) def test_find_equi_atoms(generate_film_structure): + """Test if find_equi_atoms functions returns equidistant atoms""" from aiida_fleur.tools.StructureData_util import find_equi_atoms, supercell_ncf from numpy import array @@ -174,6 +729,7 @@ def test_find_equi_atoms(generate_film_structure): def test_get_spacegroup(generate_film_structure): + """Test if get_spacegroup function returns the right spacegroup""" from aiida_fleur.tools.StructureData_util import get_spacegroup structure = generate_film_structure() @@ -181,6 +737,7 @@ def test_get_spacegroup(generate_film_structure): def test_move_atoms_incell_wf(generate_structure): + """Test if move atoms incell functions moves atoms correctly""" from aiida_fleur.tools.StructureData_util import move_atoms_incell_wf from aiida.orm import Dict @@ -198,6 +755,7 @@ def test_move_atoms_incell_wf(generate_structure): def test_find_primitive_cell_wf(generate_structure): from aiida_fleur.tools.StructureData_util import find_primitive_cell_wf, supercell_ncf + from aiida_fleur.tools.StructureData_util import find_primitive_cells structure_primitive = generate_structure() structure = supercell_ncf(structure_primitive, 2, 2, 22) @@ -207,6 +765,10 @@ def test_find_primitive_cell_wf(generate_structure): assert all(x in structure_primitive.cell for x in result.cell) + resultlist = find_primitive_cells([structure.uuid, structure.uuid]) + for struc in resultlist: + assert all(x in structure_primitive.cell for x in result.cell) + def test_center_film_wf(generate_film_structure, generate_structure): from aiida_fleur.tools.StructureData_util import center_film_wf, move_atoms_incell, center_film @@ -217,9 +779,9 @@ def test_center_film_wf(generate_film_structure, generate_structure): structure_film = move_atoms_incell(structure_film, [0.0, 0.0, 1.1242]) centered_film = center_film_wf(structure_film) - assert [x.position for x in centered_film.sites] == [(0.0, 0.0, -1.2286013142), - (1.4026317387, 1.9836207751, -0.1740305093), - (0.0, 0.0, 1.2286013141)] + assert [x.position for x in centered_film.sites] == [(0.0, 0.0, -1.2286013139), + (1.4026317384, 1.9836207747, -0.1740305094), + (0.0, 0.0, 1.2286013138)] with pytest.raises(TypeError): center_film(structure_bulk) @@ -227,20 +789,19 @@ def test_center_film_wf(generate_film_structure, generate_structure): def test_get_layers(generate_film_structure): from aiida_fleur.tools.StructureData_util import get_layers - + from aiida_fleur.common.constants import BOHR_A structure = generate_film_structure() - assert get_layers(structure) == ([[([0.0, 0.0, -1.054570804781922], 'Fe')], - [([1.4026317387182539, 1.9836207751336201, 0.0], 'Pt')], - [([0.0, 0.0, 1.4026318234924429], 'Pt')]], [-1.0545708048, 0.0, - 1.4026318235], [1, 1, 1]) + assert get_layers(structure) == ([[([0.0, 0.0, -1.05457080454278], 'Fe')], + [([1.402631738400183, 1.9836207746838, 0.0], 'Pt')], + [([0.0, 0.0, 1.402631823174372], 'Pt')]], [-1.0545708045, 0.0, + 1.4026318232], [1, 1, 1]) - bohr_a_0 = 0.52917721092 - structure.append_atom(position=(1.0, 0., -1.99285 * bohr_a_0), symbols='Fe') - assert get_layers(structure) == ([[([0.0, 0.0, -1.054570804781922], 'Fe'), ([1.0, 0.0, -1.054570804781922], 'Fe')], - [([1.4026317387182539, 1.9836207751336201, 0.0], 'Pt')], - [([0.0, 0.0, 1.4026318234924429], 'Pt')]], [-1.0545708048, 0.0, - 1.4026318235], [2, 1, 1]) + structure.append_atom(position=(1.0, 0., -1.99285 * BOHR_A), symbols='Fe') + assert get_layers(structure) == ([[([0.0, 0.0, -1.05457080454278], 'Fe'), ([1.0, 0.0, -1.05457080454278], 'Fe')], + [([1.402631738400183, 1.9836207746838, 0.0], 'Pt')], + [([0.0, 0.0, 1.402631823174372], 'Pt')]], [-1.0545708045, 0.0, + 1.4026318232], [2, 1, 1]) create_slab_inputs = [{ @@ -346,6 +907,8 @@ def test_magnetic_slab_from_relaxed(generate_film_structure): def test_request_average_bond_length(generate_film_structure): + """Test interface of request average bond length from mp, requires mp_api_key""" + # Todo mock the mp query, since result could change overtime, also that the CI can run this import os from aiida_fleur.tools.StructureData_util import request_average_bond_length @@ -368,6 +931,8 @@ def test_request_average_bond_length(generate_film_structure): def test_adjust_film_relaxation(generate_film_structure): + """Test interface of adjust film relaxation, requires mp_api_key""" + # Todo mock the mp query, since result could change overtime, also that the CI can run this import os from aiida_fleur.tools.StructureData_util import adjust_film_relaxation @@ -398,3 +963,35 @@ def test_adjust_film_relaxation(generate_film_structure): assert result.sites[0].position[2] == -1.1709859694 assert result.sites[1].position[2] == 0.2602185234 assert result.sites[2].position[2] == 1.1709859694 + + +def test_create_slap(generate_structure): + """Test if create_slap""" + from aiida_fleur.tools.StructureData_util import create_slap + + structure = generate_structure() + film_struc = create_slap(structure, [1, 1, 1], 2) + cell_should = [[3.839589821842953, 0.0, 2.351070692679364e-16], + [1.9197949109214756, 3.3251823258281643, 2.351070692679364e-16], [0.0, 0.0, 9.405035885099004]] + sites_should = [(3.839589821842953, 2.216788217218776, 3.135011961699669), (0.0, 0.0, 0.0), + (1.9197949109214758, 1.1083941086093878, 6.270023923399337)] + # since this depends on pymatgen we round here the last digits. + assert (np.round(film_struc.cell, 8) == np.round(cell_should, 8)).all() + assert (np.round(film_struc.sites[0].position, 8) == np.round(sites_should[0], 8)).all() + assert (np.round(film_struc.sites[1].position, 8) == np.round(sites_should[1], 8)).all() + assert (np.round(film_struc.sites[2].position, 8) == np.round(sites_should[2], 8)).all() + + +def test_create_all_slabs(generate_structure): + """Test if create_all_slabs""" + from aiida_fleur.tools.StructureData_util import create_all_slabs + from aiida.orm import StructureData + + structure = generate_structure() + film_strucs = create_all_slabs(structure, 2, 5) + + assert len(film_strucs.keys()) == 9 + assert list(film_strucs.keys()) == [(1, 1, 1), (2, 2, 1), (1, 1, 0), (2, 2, -1), (2, 1, 1), (2, 1, -1), (2, 1, -2), + (2, 0, -1), (2, -1, -1)] + for key, film_struc in film_strucs.items(): + assert isinstance(film_struc, StructureData) diff --git a/tests/tools/test_StructureData_util/test_break_symmetry_bulk.yml b/tests/tools/test_StructureData_util/test_break_symmetry_bulk.yml new file mode 100644 index 000000000..345341d53 --- /dev/null +++ b/tests/tools/test_StructureData_util/test_break_symmetry_bulk.yml @@ -0,0 +1,33 @@ +parameters1: + atom: + element: Si + jri: 981 + lmax: 12 + lnonsph: 6 + rmt: 2.1 + comp: + kmax: 5.0 +parameters2: + atom: + element: Si + jri: 981 + lmax: 10 + lnonsph: 6 + rmt: 2.0 + atom1: + element: Si + id: 16.1 + jri: 981 + lmax: 12 + lnonsph: 6 + rmt: 2.2 + atom2: + element: Si + id: 16.2 + jri: 981 + lmax: 11 + lnonsph: 6 + rmt: 2.1 + z: 16 + comp: + kmax: 5.0 diff --git a/tests/tools/test_common_aiida.py b/tests/tools/test_common_aiida.py index b23fa745f..12cf29423 100644 --- a/tests/tools/test_common_aiida.py +++ b/tests/tools/test_common_aiida.py @@ -8,8 +8,8 @@ import pytest -def test_create_group(capsys): - 'Test group creation' +def test_create_group(capsys, clear_database): + """Test group creation""" from aiida_fleur.tools.common_aiida import create_group from aiida.orm import Group, Dict @@ -18,26 +18,29 @@ def test_create_group(capsys): group = create_group(name='test_group', nodes=[para.pk, 'not-existent-uuid'], description='test_description') captured = capsys.readouterr() + if '=4' in captured.out: + pk = 4 # when running all tests the import group counter is not reset... + else: + pk = 1 - assert captured.out == ('Group created with PK=1 and name test_group\n' + assert captured.out == (f'Group created with PK={pk} and name test_group\n' 'Skipping not-existent-uuid, it does not exist in the DB\n' - 'added nodes: [{}] to group test_group 1\n'.format(para.pk)) - + f'added nodes: [{para.pk}] to group test_group {pk}\n') para2 = para.clone() para2.store() group = create_group(name='test_group', nodes=[para2], add_if_exist=False) captured = capsys.readouterr() - assert captured.out == ('Group with name test_group and pk 1 already exists.\n' - 'Nodes were not added to the existing group test_group\n') + assert captured.out == ('Group with name test_group and pk {} already exists.\n' + 'Nodes were not added to the existing group test_group\n'.format(pk)) group = create_group(name='test_group', nodes=[para2], add_if_exist=True) captured = capsys.readouterr() - assert captured.out == ('Group with name test_group and pk 1 already exists.\n' + assert captured.out == (f'Group with name test_group and pk {pk} already exists.\n' 'Adding nodes to the existing group test_group\n' - 'added nodes: [{}] to group test_group 1\n'.format(para2.pk)) + f'added nodes: [{para2.pk}] to group test_group {pk}\n') assert isinstance(group, Group) diff --git a/tests/tools/test_common_fleur_wf.py b/tests/tools/test_common_fleur_wf.py index c8ca0e499..92646476a 100644 --- a/tests/tools/test_common_fleur_wf.py +++ b/tests/tools/test_common_fleur_wf.py @@ -17,6 +17,7 @@ # is_code def test_is_code_interface(fixture_code): + """Test if is_code interface can take all inputs types without failure""" from aiida_fleur.tools.common_fleur_wf import is_code assert is_code('random_string') is None @@ -160,15 +161,15 @@ def test_get_inputs_inpgen(fixture_code, generate_structure): assert get_inputs_inpgen(**inputs) == returns -@pytest.mark.skip(reason='Test is not implemented') -def test_get_scheduler_extras(): - from aiida_fleur.tools.common_fleur_wf import get_scheduler_extras - - # test_and_get_codenode - - def test_test_and_get_codenode_inpgen(fixture_code): + """Tests for test_and_get_code_node function + + test interface for cases: + if code exists and is right, + if code is wrong, + if code does not exists + """ from aiida_fleur.tools.common_fleur_wf import test_and_get_codenode from aiida.orm import Code from aiida.common.exceptions import NotExistent @@ -198,6 +199,7 @@ def test_test_and_get_codenode_inpgen(fixture_code): def test_get_kpoints_mesh_from_kdensity(generate_structure): + """Test genration of a kpoints mesh node from a given density""" from aiida_fleur.tools.common_fleur_wf import get_kpoints_mesh_from_kdensity from aiida.orm import KpointsData @@ -206,10 +208,36 @@ def test_get_kpoints_mesh_from_kdensity(generate_structure): assert isinstance(b, KpointsData) -@pytest.mark.skip(reason='Test is not implemented') def test_determine_favorable_reaction(): + """Test favorable reaction function + + which returns a list which ranks which reaction is energetically the most favorable. + We only test the way if the formation energies are provided + not when they have to be taken from the node + """ from aiida_fleur.tools.common_fleur_wf import determine_favorable_reaction + reaction_list = [ + '1*Be12W->1*Be12W', '2*Be12W->1*Be2W+1*Be22W', '11*Be12W->5*W+6*Be22W', '1*Be12W->12*Be+1*W', + '1*Be12W->1*Be2W+10*Be' + ] + workchain_dict = { + 'Be12W': -0.21, #'4f685bc5-b5fb-46d3-aad6-e0f512c3313d', + 'Be2W': -0.3, #'045d3071-f442-46b4-8d6b-3c85d72b24d4', + 'Be22W': -0.1, #'1e32880a-bdc9-4081-a5da-be04860aa1bc', + 'W': 0.0, #'f8b12b23-0b71-45a1-9040-b51ccf379439', + 'Be': 0.0 + } + best_order = [['11*Be12W->5*W+6*Be22W', -1.71], ['1*Be12W->12*Be+1*W', -0.21], + ['2*Be12W->1*Be2W+1*Be22W', -0.019999999999999962], ['1*Be12W->1*Be12W', 0.0], + ['1*Be12W->1*Be2W+10*Be', 0.09]] + + reac_list = determine_favorable_reaction(reaction_list, workchain_dict) + + assert len(reac_list) == len(reaction_list) + for i, reaction in enumerate(reac_list): + assert reaction == best_order[i] + # @pytest.mark.skip(reason="There seems to be now way to add outputs to CalcJobNode") diff --git a/tests/tools/test_common_fleur_wf_util.py b/tests/tools/test_common_fleur_wf_util.py index 797f9630a..e375dff32 100644 --- a/tests/tools/test_common_fleur_wf_util.py +++ b/tests/tools/test_common_fleur_wf_util.py @@ -27,6 +27,12 @@ def test_get_natoms_element_Be2W(): assert get_natoms_element('Be2W') == {'Be': 2, 'W': 1} +def test_convert_frac_formula_BeW(): + from aiida_fleur.tools.common_fleur_wf_util import convert_frac_formula + + assert convert_frac_formula('Be0.5W0.5') == 'BeW' + + def test_ucell_to_atompr(): from aiida_fleur.tools.common_fleur_wf_util import ucell_to_atompr @@ -60,12 +66,6 @@ def test_get_atomprocent_Be24W2(): assert get_atomprocent('Be24W2') == {'Be': 24. / 26., 'W': 2. / 26.} -#@pytest.mark.skip(reason='The function is not implemented') -#def test_get_weight_procent(): -# from aiida_fleur.tools.common_fleur_wf_util import get_weight_procent -# pass - - def test_determine_formation_energy(): from aiida_fleur.tools.common_fleur_wf_util import determine_formation_energy @@ -77,9 +77,15 @@ def test_determine_formation_energy(): assert form_en_dict == form_en_dict_exp -@pytest.mark.skip(reason='Test is not implemented') def test_determine_convex_hull(): from aiida_fleur.tools.common_fleur_wf_util import determine_convex_hull + from pyhull.convex_hull import ConvexHull + + formation_en_grid = [[0.5, -1.0], [0.5, -0.5]] + + hull = determine_convex_hull(formation_en_grid) + + assert isinstance(hull, ConvexHull) def test_inpgen_dict_set_mesh(generate_kpoints_mesh): @@ -125,10 +131,20 @@ def test_convert_eq_to_dict(): assert convert_eq_to_dict('1*Be12Ti->10*Be+1*Be2Ti+5*Be') == res_dict -@pytest.mark.skip(reason='Test is not implemented') def test_get_enhalpy_of_equation(): from aiida_fleur.tools.common_fleur_wf_util import get_enhalpy_of_equation + reaction_list = [ + '1*Be12W->1*Be12W', '2*Be12W->1*Be2W+1*Be22W', '11*Be12W->5*W+6*Be22W', '1*Be12W->12*Be+1*W', + '1*Be12W->1*Be2W+10*Be' + ] + formenergydict = {'Be12W': -0.21, 'Be2W': -0.3, 'Be22W': -0.1, 'W': 0.0, 'Be': 0.0} + results = [0.0, -0.019999999999999962, -1.71, -0.21, 0.09] + + for i, reaction in enumerate(reaction_list): + result = get_enhalpy_of_equation(reaction, formenergydict) + assert result == results[i] + @pytest.mark.parametrize('test_input,expected', [('C7H16+O2 -> CO2+H2O', '1*C7H16+11*O2 ->7* CO2+8*H2O'), ('Be12W->Be2W+W+Be', None), ('Be12WO->Be2WO+W+Be+O2', None), @@ -138,6 +154,20 @@ def test_balance_equation(test_input, expected): assert balance_equation(test_input) == expected -@pytest.mark.skip(reason='Test is not implemented') def test_check_eos_energies(): from aiida_fleur.tools.common_fleur_wf_util import check_eos_energies + + energylist = [-1, -2, -3, -2, -4, -3, -2, -1] + abnormality, abnormalityindexlist = check_eos_energies(energylist) + assert abnormality + assert abnormalityindexlist == [3] + + energylist = [-1, -2, -3, -2, -2, -3, -2, -1] + abnormality, abnormalityindexlist = check_eos_energies(energylist) + assert not abnormality + assert abnormalityindexlist == [] + + energylist = [-1, -2, -3, -4, -5, -3, -2, -1] + abnormality, abnormalityindexlist = check_eos_energies(energylist) + assert not abnormality + assert abnormalityindexlist == [] diff --git a/tests/tools/test_create_corehole.py b/tests/tools/test_create_corehole.py index f33128211..d1f27c04c 100644 --- a/tests/tools/test_create_corehole.py +++ b/tests/tools/test_create_corehole.py @@ -1,3 +1,134 @@ # -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +'''Contains tests for create_corehole functions.''' +import pytest +from aiida import orm + # create_corehole_para # test interface of corehole para, that the parameter dict that comes out is right +PARAMETERS2 = { + 'atom1': { + 'element': 'Si', + 'id': 14.1, + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, #'econfig': '[He] 2s2 2p6 | 3s2 3p2', 'lo': ''}, + 'atom2': { + 'element': 'Si', + 'z': 14, + 'id': 14.2, + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, + 'comp': { + 'kmax': 5.0, + } +} + + +def test_create_corehole_para(generate_structure, data_regression): + """Test if the create corehole para function has thr right interface and returns + the correct things + """ + from aiida_fleur.tools.create_corehole import create_corehole_para + from aiida_fleur.tools.StructureData_util import break_symmetry + + dict2 = orm.Dict(dict=PARAMETERS2) + struc = generate_structure() #Si + struc2, para_new = break_symmetry(struc, parameterdata=dict2) + parameters1 = create_corehole_para(struc2, kind='Si1', econfig='[He] 2s1 2p6 | 3s2 3p3', parameterdata=para_new) + assert isinstance(parameters1, orm.Dict) + + # with no parameterdata to modify + parameters2 = create_corehole_para(struc2, kind='Si1', econfig='[He] 2s1 2p6 | 3s2 3p3') + assert isinstance(parameters2, orm.Dict) + + data_regression.check({ + 'parameters1': parameters1.get_dict(), + 'parameters2': parameters2.get_dict(), + }) + + +''' +# from old, test idea for create_corehole_fleurinp +ids = [] #13924]#, 13925]#, 13926, 13927, 13928, 13929, 13930, 13931, 13932, 13933, 13934, 13935] +#ids = [479, 480, 481, 482, 537]# O12W4, O12W4, O6W2, O6W2, O36W3Y18 + +kind = 'W1' +econfig = '[Kr] 5s2 4d10 4f13 | 5p6 5d5 6s2' +para1 = Dict( + dict={ + 'title': 'A test calculation of Tungsten', + 'input': { + 'film': False, + 'cartesian': True, + }, + 'atom': { + 'element': 'W', + 'jri': 833, + 'rmt': 2.3, + 'dx': 0.015, + 'lmax': 8, + 'lo': '5p', + 'econfig': '[Kr] 5s2 4d10 4f14| 5p6 5d4 6s2', + }, + 'soc': { + 'theta': 0.0, + 'phi': 0.0 + }, + 'comp': { + 'kmax': 3.5, + 'gmax': 2.9, + }, + 'kpt': { + 'nkpt': 200, + } + }) +#para1.store() +#pprint(para1.get_dict()) + +for id in ids: + s = load_node(id) + new_s, para = bs(s, atoms=[], site=[0, 1], pos=[(0.0, 0.0, 0, 0)], parameterData=para1) + #print new_s.sites + #pprint(para.get_dict()) + res = create_corehole(new_s, kind, econfig, para) + #print res + #pprint(para.get_dict()) + #pprint(res.get_dict()) + +# test create_corehole_fleurinp +#fleurinp = load_node(14039) # W film + +inpxmlfile1 = '../inp_xml_files/W/inp.xml' +inpxmlfile = os.path.abspath(inpxmlfile1) +fleurinp = FleurinpData(files=[inpxmlfile]) +species = 'W-1' +stateocc = {'(5d3/2)': (2.5, 0.0), '(4f7/2)': (3.5, 4.0)} +pos = [] +coreconfig = 'same' +valenceconfig = 'same' +#pprint(fleurinp.inp_dict) + +new_inp = create_corehole_fleurinp(fleurinp, species, stateocc) +print(new_inp) + +etree = '' +change = [(1, 2)] +res = write_change(etree, change) +#res.write('.outtree') +print(res) +''' diff --git a/tests/tools/test_create_corehole/test_create_corehole_para.yml b/tests/tools/test_create_corehole/test_create_corehole_para.yml new file mode 100644 index 000000000..44a4aa10a --- /dev/null +++ b/tests/tools/test_create_corehole/test_create_corehole_para.yml @@ -0,0 +1,40 @@ +parameters1: + atom1: + econfig: '[He] 2s1 2p6 | 3s2 3p3' + element: Si + id: '14.1' + jri: 981 + lmax: 12 + lnonsph: 6 + rmt: 2.1 + atom2: + element: Si + id: '14.1' + jri: 981 + lmax: 12 + lnonsph: 6 + rmt: 2.1 + z: 14 + atom3: + element: Si + id: '14.2' + jri: 981 + lmax: 12 + lnonsph: 6 + rmt: 2.1 + atom4: + element: Si + id: '14.2' + jri: 981 + lmax: 12 + lnonsph: 6 + rmt: 2.1 + z: 14 + comp: + kmax: 5.0 +parameters2: + atom: + econfig: '[He] 2s1 2p6 | 3s2 3p3' + element: Si + id: 14.1 + name: corehole diff --git a/tests/tools/test_dict_util.py b/tests/tools/test_dict_util.py index ceebbb6e1..d848a6fd2 100644 --- a/tests/tools/test_dict_util.py +++ b/tests/tools/test_dict_util.py @@ -88,3 +88,13 @@ def test_extract_elementpara_interface_W(): para_dict = {'a': 1, 'atom': {'element': 'H', 'rmt': 1}, 'atom1': {'element': 'W', 'rmt': 4}} assert extract_elementpara(para_dict, 'W') == {'a': 1, 'atom1': {'element': 'W', 'rmt': 4}} + + +def test_clean_nones(): + from aiida_fleur.tools.dict_util import clean_nones + + test_dict = {1: None, 2: 3, 4: {1: None}} + expected = {2: 3, 4: {}} + out_dict = clean_nones(test_dict) + + assert out_dict == expected diff --git a/tests/tools/test_graph_fleur.py b/tests/tools/test_graph_fleur.py deleted file mode 100644 index fc202c169..000000000 --- a/tests/tools/test_graph_fleur.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -''' Contains test the fleur specific graph gernation routine. ''' -from __future__ import absolute_import -import pytest - -# These tests need dot/graphviz... which is not autoinstalled in the python env... so far -# Therefore I uncomment these tests for know, because they will fail on travis. -# TODO find a way (aiidas problem) to set up a clean environment -''' -# test draw_graph -@pytest.mark.usefixtures("aiida_env") -def test_draw_graph_if_produces_file(): - """ - does the individual fleur_draw_graph routine produce a file? - """ - import os - from aiida_fleur.tools.graph_fleur import draw_graph - from aiida.orm import Node - - # TODO store a real graph and test if it is represented right... - node = Node() - outfile_expected = 'None.dot' - exit_expected = 0 - exit_status, output_file_name = draw_graph(node) - os.remove(output_file_name) - - assert exit_status == exit_expected - assert output_file_name == outfile_expected - -''' diff --git a/tests/tools/test_io_routines.py b/tests/tools/test_io_routines.py index a32527cd8..2cc7cef7c 100644 --- a/tests/tools/test_io_routines.py +++ b/tests/tools/test_io_routines.py @@ -60,6 +60,8 @@ def test_compress_fleuroutxml(): testfilepath = abspath('./files/outxml/BeTi_out.xml') dest_path = testfilepath.replace('.xml', '_test.xml') + testfilepath_broken = abspath('./files/outxml/special/broken_first_BeTi_out.xml') + dest_path2 = testfilepath_broken.replace('.xml', '_test.xml') niter_file = 19 xpath_iter = '/fleurOutput/scfLoop/iteration' xpath_eig = '/fleurOutput/scfLoop/iteration/eigenvalues' @@ -94,5 +96,9 @@ def get_npath(filepath, xpath): assert niter3 == niter_file # check if no iteration deleted + # test if broken file will not generate an error + compress_fleuroutxml(testfilepath_broken, dest_file_path=dest_path2, iterations_to_keep=25) + # cleanup remove(dest_path) + remove(dest_path2) diff --git a/tests/tools/test_merge_parameter.py b/tests/tools/test_merge_parameter.py new file mode 100644 index 000000000..9fb0e5c7f --- /dev/null +++ b/tests/tools/test_merge_parameter.py @@ -0,0 +1,257 @@ +# -*- coding: utf-8 -*- +############################################################################### +# Copyright (c), Forschungszentrum Jülich GmbH, IAS-1/PGI-1, Germany. # +# All rights reserved. # +# This file is part of the AiiDA-FLEUR package. # +# # +# The code is hosted on GitHub at https://github.com/JuDFTteam/aiida-fleur # +# For further information on the license, see the LICENSE.txt file # +# For further information please visit http://www.flapw.de or # +# http://aiida-fleur.readthedocs.io/en/develop/ # +############################################################################### +'''Contains tests merge_parameters.''' +import pytest +from aiida import orm + +PARAMETERS1 = { + 'atom': { + 'element': 'Si', + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, #'econfig': '[He] 2s2 2p6 | 3s2 3p2', 'lo': ''}, + 'comp': { + 'kmax': 5.0, + }, + 'kpt': { + 'div1': 17, + 'tkb': 0.0005 + } +} +PARAMETERS2 = { + 'atom1': { + 'element': 'Si', + 'id': 16.1, + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, #'econfig': '[He] 2s2 2p6 | 3s2 3p2', 'lo': ''}, + 'atom2': { + 'element': 'Si', + 'z': 16, + 'id': 16.4, + 'rmt': 2.1, + 'jri': 981, + 'lmax': 12, + 'lnonsph': 6 + }, + 'comp': { + 'kmax': 5.0, + } +} +PARAMETERS3 = PARAMETERS1.copy() +PARAMETERS3['atom']['element'] = 'Fe' + + +def test_merge_parameter(): + """Test if merge_parameter merges atom keys in dicts right + """ + from aiida_fleur.tools.merge_parameter import merge_parameter + from aiida.common.exceptions import InputValidationError + + dict1 = orm.Dict(dict=PARAMETERS1).store() + dict2 = orm.Dict(dict=PARAMETERS2).store() + dict3 = orm.Dict(dict=PARAMETERS3).store() + # otherwise we we can still change the dicts and therefore the PARAMETERS + + result = merge_parameter(dict2, dict2) + assert isinstance(result, orm.Dict) + assert result.get_dict() == PARAMETERS2 + + res_exp = { + 'kpt': { + 'tkb': 0.0005, + 'div1': 17 + }, + 'comp': { + 'kmax': 5.0 + }, + 'atom0': { + 'jri': 981, + 'rmt': 2.1, + 'lmax': 12, + 'element': 'Fe', + 'lnonsph': 6 + }, + 'atom1': { + 'id': 16.1, + 'jri': 981, + 'rmt': 2.1, + 'lmax': 12, + 'element': 'Si', + 'lnonsph': 6 + }, + 'atom2': { + 'z': 16, + 'id': 16.4, + 'jri': 981, + 'rmt': 2.1, + 'lmax': 12, + 'element': 'Si', + 'lnonsph': 6 + } + } + + result1 = merge_parameter(dict1, dict2) + assert isinstance(result1, orm.Dict) + assert result1.get_dict() == res_exp + + res_exp = { + 'kpt': { + 'tkb': 0.0005, + 'div1': 17 + }, + 'atom': { + 'jri': 981, + 'rmt': 2.1, + 'lmax': 12, + 'element': 'Fe', + 'lnonsph': 6 + }, + 'comp': { + 'kmax': 5.0 + } + } + result2 = merge_parameter(dict1, dict3) + assert isinstance(result2, orm.Dict) + assert result2.get_dict() == res_exp + + # wrong input + with pytest.raises(InputValidationError): + merge_parameter(dict2, 'string') + with pytest.raises(InputValidationError): + merge_parameter(123123, dict2) + + +def test_merge_parameters(): + """Test if merge_parameters works for a given set + """ + from aiida_fleur.tools.merge_parameter import merge_parameters + + dict1 = orm.Dict(dict=PARAMETERS1).store() + dict2 = orm.Dict(dict=PARAMETERS2).store() + dict3 = orm.Dict(dict=PARAMETERS3).store() + + # overwrite seems broken... + res_exp = { + 'kpt': { + 'tkb': 0.0005, + 'div1': 17 + }, + 'comp': { + 'kmax': 5.0 + }, + 'atom0': { + 'jri': 981, + 'rmt': 2.1, + 'lmax': 12, + 'element': 'Fe', + 'lnonsph': 6 + }, + 'atom1': { + 'jri': 981, + 'rmt': 2.1, + 'lmax': 12, + 'element': 'Fe', + 'lnonsph': 6 + } + } + result1 = merge_parameters([dict1, dict1], overwrite=False) + assert isinstance(result1, orm.Dict) + assert result1.get_dict() == res_exp + + res_exp = { + 'kpt': { + 'tkb': 0.0005, + 'div1': 17 + }, + 'comp': { + 'kmax': 5.0 + }, + 'atom0': { + 'jri': 981, + 'rmt': 2.1, + 'lmax': 12, + 'element': 'Fe', + 'lnonsph': 6 + }, + 'atom1': { + 'jri': 981, + 'rmt': 2.1, + 'lmax': 12, + 'element': 'Fe', + 'lnonsph': 6 + } + } + result2 = merge_parameters([dict1, dict1], overwrite=True) + assert isinstance(result2, orm.Dict) + assert result2.get_dict() == res_exp + + res_exp = { + 'kpt': { + 'tkb': 0.0005, + 'div1': 17 + }, + 'comp': { + 'kmax': 5.0 + }, + 'atom0': { + 'jri': 981, + 'rmt': 2.1, + 'lmax': 12, + 'element': 'Fe', + 'lnonsph': 6 + }, + 'atom1': { + 'id': 16.1, + 'jri': 981, + 'rmt': 2.1, + 'lmax': 12, + 'element': 'Si', + 'lnonsph': 6 + }, + 'atom2': { + 'z': 16, + 'id': 16.4, + 'jri': 981, + 'rmt': 2.1, + 'lmax': 12, + 'element': 'Si', + 'lnonsph': 6 + }, + 'atom3': { + 'jri': 981, + 'rmt': 2.1, + 'lmax': 12, + 'element': 'Fe', + 'lnonsph': 6 + } + } + result3 = merge_parameters([dict1, dict2, dict3]) + assert isinstance(result3, orm.Dict) + assert result3.get_dict() == res_exp + + +def test_merge_parameter_cf(): + """Test calcfunction of merge_parameter + """ + from aiida_fleur.tools.merge_parameter import merge_parameter_cf + + dict1 = orm.Dict(dict=PARAMETERS1) + + result = merge_parameter_cf(dict1, dict1) + assert isinstance(result, orm.Dict) + assert result.get_dict() == PARAMETERS1 + assert result.is_stored diff --git a/tests/tools/test_read_cif_folder.py b/tests/tools/test_read_cif_folder.py index 2c06b2bf2..d1143851f 100644 --- a/tests/tools/test_read_cif_folder.py +++ b/tests/tools/test_read_cif_folder.py @@ -1,13 +1,11 @@ # -*- coding: utf-8 -*- '''Contains tests for read and with work cif file routines.''' -from __future__ import absolute_import -from __future__ import print_function import pytest # read-cif_folder -@pytest.mark.skip(reason='Test not implemented') +#@pytest.mark.skip(reason='Test not implemented') def test_read_cif_folder_interface(temp_dir): """ this test set reads in the cif files in the ../files/cif/ directory and subdirs @@ -17,32 +15,46 @@ def test_read_cif_folder_interface(temp_dir): import os from aiida_fleur.tools.read_cif_folder import read_cif_folder import aiida_fleur + from aiida import orm path = os.path.dirname(aiida_fleur.__file__) - cif_folderpath = os.path.join(path, 'tests/files/cif/') + cif_folderpath = os.path.join(path, '../tests/files/cif/') out_filename = os.path.join(temp_dir, 'out.txt') - + add_extra = {'test': 1} #read_in - structure_data, filenames = read_cif_folder(path=os.getcwd(), + structure_data, filenames = read_cif_folder(path=cif_folderpath, recursive=True, store=True, log=True, comments='Test_comment', - extras={'test': 1}, + extras=add_extra, logfile_name=out_filename) - structure_data, filenames = read_cif_folder(path=cif_folderpath, - recursive=False, - store=False, - log=False, - comments='', - extras='') #test number of structurs written #test number of cif files written #test if extras are set right #test prov #test + for structure in structure_data: + assert isinstance(structure, orm.StructureData) + assert structure.is_stored + assert structure.extras['test'] == 1 + + assert len(structure_data) == len(filenames) #read_in again - # test if cif files are not rewritten. - assert False + structure_data, filenames = read_cif_folder(path=cif_folderpath, + recursive=False, + store=False, + log=True, + comments='', + extras='myproject', + logfile_name=out_filename) + for structure in structure_data: + assert isinstance(structure, orm.StructureData) + assert not structure.is_stored + assert 'test' not in structure.extras + #assert structure.extras['specification'] == 'myproject' + assert 'specification' not in structure.extras + # extras get only written if structures are stored + assert len(structure_data) == len(filenames) diff --git a/tests/workflows_regression_manually.py b/tests/workflows_regression_manually.py new file mode 100644 index 000000000..b8b73cc3c --- /dev/null +++ b/tests/workflows_regression_manually.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- + +# this should be executed at least once before a release +# It runs all launch commands form the aiida-fleur cmdline once +# with defaults for a given inpgen or fleur code or it use + +#aiida-fleur launch inpgen +#aiida-fleur launch fleur +#aiida-fleur launch scf +#aiida-fleur launch eos +#aiida-fleur launch banddos +#aiida-fleur launch relax +#aiida-fleur launch corehole +#aiida-fleur launch init_cls diff --git a/tests/workflows_regression_manually.sh b/tests/workflows_regression_manually.sh new file mode 100644 index 000000000..2e010b3d3 --- /dev/null +++ b/tests/workflows_regression_manually.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Todo: parse as argument the fleur and inpgen code you want to use, optional options, if non default for the used machine, +# +# This test set should be executed at least once before a release +# It runs all launch commands form the aiida-fleur cmdline once +# with defaults for a given inpgen or fleur code or it use +# the materials and all other parameter are definded in the submission tests... + +FLEUR=713 #iff pc +INPGEN='497d15d9-9e53-434a-9b32-b85256fe3a69' #712 # iff pc +STRUCTURE=1604 +SUBMIT=true +FLEURINP=1916 # Tungesten +OPTIONS=49361 # claix +REMOTE=1921 # W on claix + +# import a some nodes needed for the regression tests +verdi import ./files/exports/base_export_regression_tests.tar.gz + +# Run or submit all workflows via CLI + +aiida-fleur launch inpgen --inpgen $INPGEN +aiida-fleur launch fleur --fleur $FLEUR -P $REMOTE +aiida-fleur launch scf --inpgen $INPGEN --fleur $FLEUR +aiida-fleur launch eos --inpgen $INPGEN --fleur $FLEUR +#aiida-fleur launch banddos +aiida-fleur launch relax --inpgen $INPGEN --fleur $FLEUR +#aiida-fleur launch corehole +#aiida-fleur launch init_cls