# -*- coding: utf-8 -*-
"""
Plug-in to import a KKR calculation. This is based on the PwImmigrantCalculation of the aiida-quantumespresso plugin.
"""
import os
from aiida.orm import DataFactory
from aiida.orm.calculation.job import _input_subfolder
from aiida.common.utils import classproperty
from aiida.common.folders import SandboxFolder
from aiida.common.exceptions import InputValidationError, InvalidOperation
from aiida.common.datastructures import calc_states
from aiida.common.links import LinkType
from aiida_kkr.calculations.kkr import KkrCalculation
from aiida_kkr.tools.kkr_params import kkrparams
from aiida_kkr.tools.common_workfunctions import structure_from_params
#define aiida structures from DataFactory of aiida
RemoteData = DataFactory('remote')
ParameterData = DataFactory('parameter')
StructureData = DataFactory('structure')
__copyright__ = (u"Copyright (c), 2017, Forschungszentrum Jülich GmbH, "
"IAS-1/PGI-1, Germany. All rights reserved.")
__license__ = "MIT license, see LICENSE.txt file"
__version__ = "0.1"
__contributors__ = ("Philipp Rüßmann")
[docs]class KkrImporterCalculation(KkrCalculation):
"""
Importer dummy calculation for a previous KKR run
:param remote_workdir: Absolute path to the directory where the job was run.
The transport of the computer you link ask input to the calculation is
the transport that will be used to retrieve the calculation's files.
Therefore, ``remote_workdir`` should be the absolute path to the job's
directory on that computer.
:type remote_workdir: str
:param input_file_names: The file names of the job's input file.
:type input_file_name: dict with str entries
:param output_file_name: The file names of the job's output file (i.e. the
file containing the stdout of QE).
:type output_file_name: dict with str entries
"""
[docs] def _init_internal_params(self):
"""
Init internal parameters at class load time
"""
# reuse base class function
super(KkrImporterCalculation, self)._init_internal_params()
# calculation plugin version
self._CALCULATION_PLUGIN_VERSION = __version__
# parser
self._default_parser = 'kkr.kkrimporterparser'
@classproperty
def _use_methods(cls):
"""
Add use_structure method for KKRimporter calculations.
"""
use_dict = KkrCalculation._use_methods
use_dict.update({
"structure": {
'valid_types': StructureData,
'additional_parameter': None,
'linkname': 'structure',
'docstring':
("Use a node that specifies the input crystal structure ")
}
})
return use_dict
[docs] def _prepare_for_retrieval(self, open_transport):
"""
Prepare the calculation for retrieval by daemon.
:param open_transport: An open instance of the transport class of the
calculation's computer.
:type open_transport: aiida.transport.plugins.local.LocalTransport or
aiida.transport.plugins.ssh.SshTransport
Here, we
* manually set the files to retrieve
* store the calculation and all it's input nodes
* copy the input file to the calculation's raw_input_folder in the
* store the remote_workdir as a RemoteData output node
"""
# Manually set the files that will be copied to the repository and that
# the parser will extract the results from. This would normally be
# performed in self._prepare_for_submission prior to submission.
self._set_attr('retrieve_list',
[self._DEFAULT_OUTPUT_FILE, self._NONCO_ANGLES_OUT,
self._OUTPUT_0_INIT, self._OUTPUT_000, self._OUTPUT_2,
'output.0','output.1a','output.1b','output.1c','output.2', # try to import old style output
self._OUT_TIMING_000,
self._OUT_POTENTIAL, self._SHAPEFUN]) # make sure to retrieve potential and shapefun as well
self._set_attr('retrieve_singlefile_list', [])
# Make sure the calculation and input links are stored.
self.store_all()
# Store the original input file in the calculation's repository folder.
remote_path = os.path.join(self._get_remote_workdir(),
self._INPUT_FILE_NAME)
raw_input_folder = self.folder.get_subfolder(_input_subfolder,
create=True)
open_transport.get(remote_path, raw_input_folder.abspath)
# Manually add the remote working directory as a RemoteData output
# node.
self._set_state(calc_states.SUBMITTING)
remotedata = RemoteData(computer=self.get_computer(),
remote_path=self._get_remote_workdir())
remotedata.add_link_from(self, label='remote_folder',
link_type=LinkType.CREATE)
remotedata.store()
[docs] def prepare_for_retrieval_and_parsing(self, open_transport):
"""
Tell the daemon that the calculation is computed and ready to be parsed.
:param open_transport: An open instance of the transport class of the
calculation's computer. See the tutorial for more information.
:type open_transport: aiida.transport.plugins.local.LocalTransport
or aiida.transport.plugins.ssh.SshTransport
The next time the daemon updates the status of calculations, it will
see this job is in the 'COMPUTED' state and will retrieve its output
files and parse the results.
If the daemon is not currently running, nothing will happen until it is
started again.
This method also stores the calculation and all input nodes. It also
copies the original input file to the calculation's repository folder.
:raises aiida.common.exceptions.InputValidationError: if
``open_transport`` is a different type of transport
than the computer's.
:raises aiida.common.exceptions.InvalidOperation: if
``open_transport`` is not open.
"""
# Check that the create_input_nodes method has run successfully.
if not self.get_attr('input_nodes_created', False):
raise InvalidOperation(
"You must run the create_input_nodes method before calling "
"prepare_for_retrieval_and_parsing!"
)
# Check that open_transport is the correct transport type.
if type(open_transport) is not self.get_computer().get_transport_class():
raise InputValidationError(
"The transport passed as the `open_transport` parameter is "
"not the same transport type linked to the computer. Please "
"obtain the correct transport class using the "
"`get_transport_class` method of the calculation's computer. "
"See the tutorial for more information."
)
# Check that open_transport is actually open.
if not open_transport._is_open:
raise InvalidOperation(
"The transport passed as the `open_transport` parameter is "
"not open. Please execute the open the transport using it's "
"`open` method, or execute the call to this method within a "
"`with` statement context guard. See the tutorial for more "
"information."
)
# Prepare the calculation for retrieval
self._prepare_for_retrieval(open_transport)
# Manually set the state of the calculation to "COMPUTED", so that it
# will be retrieved and parsed the next time the daemon updates the
# status of calculations.
self._set_state(calc_states.COMPUTED)
[docs] def set_remote_workdir(self, remote_workdir):
"""
Set the job's remote working directory.
:param remote_workdir: Absolute path of the job's remote working
directory.
:type remote_workdir: str
"""
# This is the functionality as self._set_remote_workir, but it bypasses
# the need to have the calculation state set as SUBMITTING.
self._set_attr('remote_workdir', remote_workdir)
[docs] def set_output_file_names(self, output_file_names):
"""
Set the file names of the job's output files (e.g. ``'output.000.txt'`` etc.).
:param output_file_names: The dictionary of file names of file containing the job's
outputs.
:type output_file_names: dict
Keys of output_file_names dict should be one or more of:
* ``'out_file'``
* ``'out_potential_file'``
* ``'out_nonco_angles_file'``
* ``'output_0_file'``
* ``'output_000_file'``
* ``'output_2_file'``
* ``'timing_file'``
:note: In a filename is not given, the default value of aiida_kkr.calculations.kkr are used
"""
if self._OUTPUT_FILE_NAMES is None:
if output_file_names is None: #set default values if nothing is chosen
self._OUT_POTENTIAL = self._POTENTIAL
self._DEFAULT_OUTPUT_FILE = KkrCalculation()._DEFAULT_OUTPUT_FILE
self._NONCO_ANGLES_OUT = KkrCalculation()._NONCO_ANGLES_OUT
self._OUTPUT_0_INIT = KkrCalculation()._OUTPUT_0_INIT
self._OUTPUT_000 = KkrCalculation()._OUTPUT_000
self._OUTPUT_2 = KkrCalculation()._OUTPUT_2
self._OUT_TIMING_000 = KkrCalculation()._OUT_TIMING_000
output_file_names = {'out_potential_file': self._OUT_POTENTIAL,
'out_file': self._DEFAULT_OUTPUT_FILE,
'out_nonco_angles_file': self._NONCO_ANGLES_OUT,
'output_0_file': self._OUTPUT_0_INIT,
'output_000_file': self._OUT_TIMING_000,
'output_2_file': self._OUTPUT_2,
'timing_file': self._OUT_TIMING_000}
else:
self.logger.info('setting output_file_names: {}'.format(output_file_names))
self._set_filenames_out(output_file_names)
# finally set ourput_file_names as class attribute
self._set_attr('output_file_names', output_file_names)
[docs] def _set_filenames_in(self, input_file_names):
"""
helper function to set filenames from input_file_names dict
also check if at least inputcard and potential are given
"""
has_input_files = False
if input_file_names is not None:
has_input_files = True
if input_file_names.get('input_file') is not None:
self._INPUT_FILE_NAME = input_file_names.get('input_file')
else:
self.logger.info('KKRimporter: input_file not given!')
has_input_files = False
if input_file_names.get('potential_file') is not None:
self._POTENTIAL = input_file_names.get('potential_file')
else:
self.logger.info('KKRimporter: potential_file not given!')
has_input_files = False
if input_file_names.get('shapefun_file') is not None:
self._SHAPEFUN = input_file_names.get('shapefun_file')
else:
self._SHAPEFUN = KkrCalculation()._SHAPEFUN
if not has_input_files:
raise InputValidationError(
'The input file_names has not been specified correctly.\n'
'Please specify it using one of the following...\n '
'(a) pass as a keyword argument to create_input_nodes\n'
' [create_input_nodes(input_file_names=your_file_names_dictionary)]\n'
'(b) pass as a keyword argument when instantiating\n '
' [calc = KkrImporterCalculation(input_file_names={"input_file":"inputcard", "potential_file":"potential", ...}]\n'
'(c) use the set_input_file_names method\n'
' [calc.set_input_file_name(your_file_names)]'
)
[docs] def _set_filenames_out(self, output_file_names):
"""
helper function that sets the output file names from the output_file_names dictionary
"""
if output_file_names is not None and output_file_names.get('out_potential_file') is not None:
self._OUT_POTENTIAL = output_file_names.get('out_potential_file')
else:
self._OUT_POTENTIAL = self._POTENTIAL
#raise InputValidationError('test: {}'.format(self._OUT_POTENTIAL))
if output_file_names is not None:
if output_file_names.get('out_file') is not None:
self._DEFAULT_OUTPUT_FILE = output_file_names.get('out_file')
else:
self._DEFAULT_OUTPUT_FILE = KkrCalculation()._DEFAULT_OUTPUT_FILE
if output_file_names.get('out_nonco_angles_file') is not None:
self._NONCO_ANGLES_OUT = output_file_names.get('out_nonco_angles_file')
else:
self._NONCO_ANGLES_OUT = KkrCalculation()._NONCO_ANGLES_OUT
if output_file_names.get('output_0_file') is not None:
self._OUTPUT_0_INIT = output_file_names.get('output_0_file')
else:
self._OUTPUT_0_INIT = KkrCalculation()._OUTPUT_0_INIT
if output_file_names.get('output_000_file') is not None:
self._OUTPUT_000 = output_file_names.get('output_000_file')
else:
self._OUTPUT_000 = KkrCalculation()._OUTPUT_000
if output_file_names.get('output_2_file') is not None:
self._OUTPUT_2 = output_file_names.get('output_2_file')
else:
self._OUTPUT_2 = KkrCalculation()._OUTPUT_2
if output_file_names.get('timing_file') is not None:
self._OUT_TIMING_000 = output_file_names.get('timing_file')
else:
self._OUT_TIMING_000 = KkrCalculation()._OUT_TIMING_000
# These value are set as class attributes in the parent class,
# BasePwInputGenerator, but they will be different for a job that wasn't
# run using aiida, and they will likely vary from job to job. Therefore,
# we override the parent class's attributes using properties, whose
# setter methods store the values as db attributes, and whose getter
# methods retrieve the stored values from the db.
@property
def _INPUT_FILE_NAMES(self):
return self.get_attr('input_file_names', None)
@_INPUT_FILE_NAMES.setter
def _INPUT_FILE_NAMES(self, value):
self._set_attr('input_file_names', value)
@property
def _OUTPUT_FILE_NAMES(self):
return self.get_attr('output_file_names', None)
@_OUTPUT_FILE_NAMES.setter
def _OUTPUT_FILE_NAMES(self, value):
self._set_attr('output_file_names', value)