Ejemplo n.º 1
0
    def get_upf_node(self, store=False):
        """
        Creates an UPF node, that can be used in AiiDA workflow.

        :return: :py:class:`aiida.orm.data.upf.UpfData` object
        """
        from aiida.common.utils import md5_file
        from aiida.orm.data.upf import UpfData
        import tempfile

        upfnode = None

        # Prefixing with an ID in order to start file name with the name
        # of the described element.
        with tempfile.NamedTemporaryFile(prefix=self.source['id']) as f:
            f.write(self.contents)
            f.flush()
            upfnode = UpfData(file=f.name, source=self.source)

        # Maintaining backwards-compatibility. Parameter 'store' should
        # be removed in the future, as the new node can be stored later.
        if store:
            upfnode.store()

        return upfnode
Ejemplo n.º 2
0
def import_upf(filename):
    """
    Import upf data object
    """
    from aiida.orm.data.upf import UpfData
    node, _ = UpfData.get_or_create(filename)
    echo.echo_success("Imported: {}".format(node))
Ejemplo n.º 3
0
def validate_pseudo_family(callback_kwargs, ctx, param, value):
    """
    Command line option validator for a pseudo potential family. The value should be a
    string that corresponds to a registered UpfData family, which is an AiiDA Group.

    :param callback_kwargs: an optional dictionary with arguments for internal use in the validator
    :param ctx: internal context of the click.command
    :param param: the click Parameter, i.e. either the Option or Argument to which the validator is hooked up
    :param value: a UpfData pseudo potential family label
    :returns: the pseudo potential family label
    """
    from aiida.common.exceptions import NotExistent
    from aiida.orm.data.upf import UpfData

    try:
        pseudo_family = UpfData.get_upf_group(value)
    except NotExistent as exception:
        raise click.BadParameter(
            "failed to load the pseudo family the label '{}'\n{}".format(
                value, exception))

    return value
Ejemplo n.º 4
0
    def test_cif_structure_roundtrip(self):
        from aiida.tools.dbexporters.tcod import export_cif, export_values
        from aiida.orm import Code
        from aiida.orm import JobCalculation
        from aiida.orm.data.cif import CifData
        from aiida.orm.data.parameter import ParameterData
        from aiida.orm.data.upf import UpfData
        from aiida.orm.data.folder import FolderData
        from aiida.common.folders import SandboxFolder
        from aiida.common.datastructures import calc_states
        import tempfile

        with tempfile.NamedTemporaryFile() as f:
            f.write('''
                data_test
                _cell_length_a    10
                _cell_length_b    10
                _cell_length_c    10
                _cell_angle_alpha 90
                _cell_angle_beta  90
                _cell_angle_gamma 90
                loop_
                _atom_site_label
                _atom_site_fract_x
                _atom_site_fract_y
                _atom_site_fract_z
                C 0 0 0
                O 0.5 0.5 0.5
            ''')
            f.flush()
            a = CifData(file=f.name)

        c = a._get_aiida_structure()
        c.store()
        pd = ParameterData()

        code = Code(local_executable='test.sh')
        with tempfile.NamedTemporaryFile() as f:
            f.write("#/bin/bash\n\necho test run\n")
            f.flush()
            code.add_path(f.name, 'test.sh')

        code.store()

        calc = JobCalculation(computer=self.computer)
        calc.set_resources({'num_machines': 1, 'num_mpiprocs_per_machine': 1})
        calc.add_link_from(code, "code")
        calc.set_environment_variables({
            'PATH': '/dev/null',
            'USER': '******'
        })

        with tempfile.NamedTemporaryFile(prefix="Fe") as f:
            f.write("<UPF version=\"2.0.1\">\nelement=\"Fe\"\n")
            f.flush()
            upf = UpfData(file=f.name)
            upf.store()
            calc.add_link_from(upf, "upf")

        with tempfile.NamedTemporaryFile() as f:
            f.write("data_test")
            f.flush()
            cif = CifData(file=f.name)
            cif.store()
            calc.add_link_from(cif, "cif")

        calc.store()
        calc._set_state(calc_states.SUBMITTING)
        with SandboxFolder() as f:
            calc._store_raw_input_folder(f.abspath)

        fd = FolderData()
        with open(
                fd._get_folder_pathsubfolder.get_abs_path(
                    calc._SCHED_OUTPUT_FILE), 'w') as f:
            f.write("standard output")
            f.flush()

        with open(
                fd._get_folder_pathsubfolder.get_abs_path(
                    calc._SCHED_ERROR_FILE), 'w') as f:
            f.write("standard error")
            f.flush()

        fd.store()
        fd.add_link_from(calc, calc._get_linkname_retrieved(), LinkType.CREATE)

        pd.add_link_from(calc, "calc", LinkType.CREATE)
        pd.store()

        with self.assertRaises(ValueError):
            export_cif(c, parameters=pd)

        c.add_link_from(calc, "calc", LinkType.CREATE)
        export_cif(c, parameters=pd)

        values = export_values(c, parameters=pd)
        values = values['0']

        self.assertEquals(values['_tcod_computation_environment'],
                          ['PATH=/dev/null\nUSER=unknown'])
        self.assertEquals(values['_tcod_computation_command'],
                          ['cd 1; ./_aiidasubmit.sh'])
Ejemplo n.º 5
0
    def create_input_nodes(self, open_transport, input_file_name=None,
                           output_file_name=None, remote_workdir=None):
        """
        Create calculation input nodes based on the job's files.

        :param open_transport: An open instance of the transport class of the
            calculation's computer. See the tutorial for more information.
        :type open_transport: :py:class:`aiida.transport.plugins.local.LocalTransport`
            | :py:class:`aiida.transport.plugins.ssh.SshTransport`

        This method parses the files in the job's remote working directory to
        create the input nodes that would exist if the calculation were
        submitted using AiiDa. These nodes are

            * a ``'parameters'`` ParameterData node, based on the namelists and
              their variable-value pairs;
            * a ``'kpoints'`` KpointsData node, based on the *K_POINTS* card;
            * a ``'structure'`` StructureData node, based on the
              *ATOMIC_POSITIONS* and *CELL_PARAMETERS* cards;
            * one ``'pseudo_X'`` UpfData node for the pseudopotential used for
              the atomic species with name ``X``, as specified in the
              *ATOMIC_SPECIES* card;
            * a ``'settings'`` ParameterData node, if there are any fixed
              coordinates, or if the gamma kpoint is used;

        and can be retrieved as a dictionary using the ``get_inputs_dict()``
        method. *These input links are cached-links; nothing is stored by this
        method (including the calculation node itself).*

        .. note:: QE stores the calculation's pseudopotential files in the
            ``<outdir>/<prefix>.save/`` subfolder of the job's working
            directory, where ``outdir`` and ``prefix`` are QE *CONTROL*
            variables (see
            `pw input file description <http://www.quantum-espresso.org/wp-content/uploads/Doc/INPUT_PW.html>`_).
            This method uses these files to either get--if the a node already
            exists for the pseudo--or create a UpfData node for each
            pseudopotential.


        **Keyword arguments**

        .. note:: These keyword arguments can also be set when instantiating the
            class or using the ``set_`` methods (e.g. ``set_remote_workdir``).
            Offering to set them here simply offers the user an additional
            place to set their values. *Only the values that have not yet been
            set need to be specified.*

        :param input_file_name: The file name of the job's input file.
        :type input_file_name: str

        :param output_file_name: The file name of the job's output file (i.e.
            the file containing the stdout of QE).
        :type output_file_name: str

        :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

        :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.
        :raises aiida.common.exceptions.InputValidationError: if
            ``remote_workdir``, ``input_file_name``, and/or ``output_file_name``
            are not set prior to or during the call of this method.
        :raises aiida.common.exceptions.FeatureNotAvailable: if the input file
            uses anything other than ``ibrav = 0``, which is not currently
            implimented in aiida.
        :raises aiida.common.exceptions.ParsingError: if there are issues
            parsing the input file.
        :raises IOError: if there are issues reading the input file.
        """
        import re
        # Make sure the remote workdir and input + output file names were
        # provided either before or during the call to this method. If they
        # were just provided during this method call, store the values.
        if remote_workdir is not None:
            self.set_remote_workdir(remote_workdir)
        elif self.get_attr('remote_workdir', None) is None:
            raise InputValidationError(
                'The remote working directory has not been specified.\n'
                'Please specify it using one of the following...\n '
                '(a) pass as a keyword argument to create_input_nodes\n'
                '    [create_input_nodes(remote_workdir=your_remote_workdir)]\n'
                '(b) pass as a keyword argument when instantiating\n '
                '    [calc = PwCalculationImport(remote_workdir='
                'your_remote_workdir)]\n'
                '(c) use the set_remote_workdir method\n'
                '    [calc.set_remote_workdir(your_remote_workdir)]'
            )
        if input_file_name is not None:
            self._INPUT_FILE_NAME = input_file_name
        elif self._INPUT_FILE_NAME is None:
            raise InputValidationError(
                'The input file_name has not been specified.\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_name=your_file_name)]\n'
                '(b) pass as a keyword argument when instantiating\n '
                '    [calc = PwCalculationImport(input_file_name='
                'your_file_name)]\n'
                '(c) use the set_input_file_name method\n'
                '    [calc.set_input_file_name(your_file_name)]'
            )
        if output_file_name is not None:
            self._OUTPUT_FILE_NAME = output_file_name
        elif self._OUTPUT_FILE_NAME is None:
            raise InputValidationError(
                'The input file_name has not been specified.\n'
                'Please specify it using one of the following...\n '
                '(a) pass as a keyword argument to create_input_nodes\n'
                '    [create_input_nodes(output_file_name=your_file_name)]\n'
                '(b) pass as a keyword argument when instantiating\n '
                '    [calc = PwCalculationImport(output_file_name='
                'your_file_name)]\n'
                '(c) use the set_output_file_name method\n'
                '    [calc.set_output_file_name(your_file_name)]'
            )

        # 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."
            )

        # Copy the input file and psuedo files to a temp folder for parsing.
        with SandboxFolder() as folder:

            # Copy the input file to the temp folder.
            remote_path = os.path.join(self._get_remote_workdir(),
                                       self._INPUT_FILE_NAME)
            open_transport.get(remote_path, folder.abspath)

            # Parse the input file.
            local_path = os.path.join(folder.abspath, self._INPUT_FILE_NAME)
            with open(local_path) as fin:
                pwinputfile = pwinputparser.PwInputFile(fin)


            # Determine PREFIX, if it hasn't already been set by the user.
            if self._PREFIX is None:
                control_dict = pwinputfile.namelists['CONTROL']
                # If prefix is not set in input file, use the default,
                # 'pwscf'.
                self._PREFIX = control_dict.get('prefix', 'pwscf')

            # Determine _OUTPUT_SUBFOLDER, if it hasn't already been set by
            # the user.
            # TODO: Prompt user before using the environment variable???
            if self._OUTPUT_SUBFOLDER is None:
                # See if it's specified in the CONTROL namelist.
                control_dict = pwinputfile.namelists['CONTROL']
                self._OUTPUT_SUBFOLDER = control_dict.get('outdir', None)
                if self._OUTPUT_SUBFOLDER is None:
                    # See if the $ESPRESSO_TMPDIR is set.
                    envar = open_transport.exec_command_wait(
                        'echo $ESPRESSO_TMPDIR'
                    )[1]
                    if len(envar.strip()) > 0:
                        self._OUTPUT_SUBFOLDER = envar.strip()
                    else:
                        # Use the default dir--the dir job was submitted in.
                        self._OUTPUT_SUBFOLDER = self._get_remote_workdir()

            # Copy the pseudo files to the temp folder.
            for fnm in pwinputfile.atomic_species['pseudo_file_names']:
                remote_path = os.path.join(self._get_remote_workdir(),
                                           self._OUTPUT_SUBFOLDER,
                                           '{}.save/'.format(self._PREFIX),
                                           fnm)
                open_transport.get(remote_path, folder.abspath)

            # Make sure that ibrav = 0, since aiida doesn't support anything
            # else.
            if pwinputfile.namelists['SYSTEM']['ibrav'] != 0:
                raise FeatureNotAvailable(
                    'Found ibrav !=0 while parsing the input file. '
                    'Currently, AiiDa only supports ibrav = 0.'
                )

            # Create ParameterData node based on the namelist and link as input.

            # First, strip the namelist items that aiida doesn't allow or sets
            # later.
            # NOTE: ibrav = 0 is checked above.
            # NOTE: If any of the position or cell units are in alat or crystal
            # units, that will be taken care of by the input parsing tools, and
            # we are safe to fake that they were never there in the first place.
            parameters_dict = deepcopy(pwinputfile.namelists)
            for namelist, blocked_key in self._blocked_keywords:
                keys = parameters_dict[namelist].keys()
                for this_key in parameters_dict[namelist].keys():
                    # take into account that celldm and celldm(*) must be blocked
                    if re.sub("[(0-9)]", "", this_key) == blocked_key:
                        parameters_dict[namelist].pop(this_key, None)

            parameters = ParameterData(dict=parameters_dict)
            self.use_parameters(parameters)

            # Initialize the dictionary for settings parameter data for possible
            # use later for gamma kpoint and fixed coordinates.
            settings_dict = {}

            # Create a KpointsData node based on the K_POINTS card block
            # and link as input.
            kpointsdata = pwinputfile.get_kpointsdata()
            self.use_kpoints(kpointsdata)
            # If only the gamma kpoint is used, add to the settings dictionary.
            if pwinputfile.k_points['type'] == 'gamma':
                settings_dict['gamma_only'] = True

            # Create a StructureData node based on the ATOMIC_POSITIONS,
            # CELL_PARAMETERS, and ATOMIC_SPECIES card blocks, and link as
            # input.
            structuredata = pwinputfile.get_structuredata()
            self.use_structure(structuredata)

            # Get or create a UpfData node for the pseudopotentials used for
            # the calculation.
            names = pwinputfile.atomic_species['names']
            pseudo_file_names = pwinputfile.atomic_species['pseudo_file_names']
            for name, fnm in zip(names, pseudo_file_names):
                local_path = os.path.join(folder.abspath, fnm)
                pseudo, created = UpfData.get_or_create(local_path)
                self.use_pseudo(pseudo, kind=name)

        # If there are any fixed coordinates (i.e. force modification
        # present in the input file, create a ParameterData node for these
        # special settings.
        fixed_coords = pwinputfile.atomic_positions['fixed_coords']
        # NOTE: any() only works for 1-dimensional lists.
        if any((any(fc_xyz) for fc_xyz in fixed_coords)):
            settings_dict['FIXED_COORDS'] = fixed_coords

        # If the settings_dict has been filled in, create a ParameterData
        # node from it and link as input.
        if settings_dict:
            self.use_settings(ParameterData(dict=settings_dict))

        self._set_attr('input_nodes_created', True)
Ejemplo n.º 6
0
    def parse_with_retrieved(self, retrieved):
        """
        Parse output data folder, store results in database.

        :param retrieved: a dictionary of retrieved nodes, where
          the key is the link name
        :returns: a tuple with two values ``(bool, node_list)``, 
          where:

          * ``bool``: variable to tell if the parsing succeeded
          * ``node_list``: list of new nodes to be stored in the db
            (as a list of tuples ``(link_name, node)``)
        """
        success = False
        node_list = ()

        #out_folder is the local folder where the retrived file are.
        #so one file to be parsed must be in the retrive_list
        #specified in /calculation/ape.py

        try:
            out_folder = retrieved[self._calc._get_linkname_retrieved()]
        except KeyError:
            ##    #raise IOError("No retrieved folder found")
            self.logger.error("No retrieved folder found")
            return success, node_list

        list_of_files = out_folder.get_folder_list()

        if self._calc._OUTPUT_FILE_NAME not in list_of_files:
            self.logger.error("Output file not found")
            return success, node_list

        with open(out_folder.get_abs_path(self._calc._OUTPUT_FILE_NAME)) as f:
            for line in f:
                if "Wavefunction info:" in line:
                    next(f)
                    s = next(f).split()
                    p = next(f).split()
                    d = next(f).split()
                    f = next(f).split()
        nodespicks = {
            "s node": float(s[2]),
            "s pick": float(s[3]),
            "p node": float(p[2]),
            "p pick": float(p[3]),
            "d node": float(d[2]),
            "d pick": float(d[3]),
            "f node": float(f[2]),
            "f pick": float(f[3])
        }

        if int(self._calc.inp.parameters.get_attr('CoreCorrection')) > 0:
            with open(out_folder.get_abs_path(
                    self._calc._OUTPUT_FILE_NAME)) as f:
                for line in f:
                    if "Core Corrections:" in line:
                        l1 = next(f).split()
                        l2 = next(f).split()

            cocor = {
                "CoreCorrection scheme": l1[1],
                "CoreCorrection rc": float(l2[2])
            }
#		link_name = self.get_linkname_outparams()
#		nodes_list = [(link_name, s)]

        else:
            cocor = {"CoreCorrection scheme": "no correction"}
#		link_name = self.get_linkname_outparams()
#		nodes_list = [(link_name, s)]

        parsed_dict = dict(nodespicks.items() + cocor.items())
        parr = ParameterData(dict=parsed_dict)
        link_name = self.get_linkname_outparams()
        nodes_list = [(link_name, parr)]

        from aiida_ape.data.elements import ELEMENTS
        nuclcharge = self._calc.inp.parameters.get_attr('NuclearCharge')
        Sy = ELEMENTS[int(nuclcharge)].symbol

        if "{}.ascii".format(Sy) not in list_of_files:
            self.logger.error("Siesta pseudo not found")
            return success, node_list

        if "{}.UPF".format(Sy) not in list_of_files:
            self.logger.error("UPF pseudo not found")
            return success, node_list

        from aiida_ape.data.psf import PsfData
        pseascii = PsfData()
        pseascii.set_file(out_folder.get_abs_path("{}.ascii".format(Sy)))
        nodes_list.append((self.get_linkname_pseascii(), pseascii))

        from aiida.orm.data.upf import UpfData
        pseupf = UpfData()
        pseupf.set_file(out_folder.get_abs_path("{}.UPF".format(Sy)))
        nodes_list.append((self.get_linkname_pseupf(), pseupf))

        success = True
        return success, nodes_list  #out_nodes