Ejemplo n.º 1
0
    def test_subclassing(self):
        from aiida.orm.data.structure import StructureData
        from aiida.orm.data.parameter import ParameterData
        from aiida.orm import Node, Data
        from aiida.orm.querybuilder import QueryBuilder
        s = StructureData()
        s._set_attr('cat', 'miau')
        s.store()

        d = Data()
        d._set_attr('cat', 'miau')
        d.store()

        p = ParameterData(dict=dict(cat='miau'))
        p.store()

        n = Node()
        n._set_attr('cat', 'miau')
        n.store()

        # Now when asking for a node with attr.cat==miau, I want 4 esults:
        qb = QueryBuilder().append(Node, filters={'attributes.cat': 'miau'})
        self.assertEqual(qb.count(), 4)

        qb = QueryBuilder().append(Data, filters={'attributes.cat': 'miau'})
        self.assertEqual(qb.count(), 3)

        # If I'm asking for the specific lowest subclass, I want one result
        for cls in (StructureData, ParameterData):
            qb = QueryBuilder().append(cls, filters={'attributes.cat': 'miau'})
            self.assertEqual(qb.count(), 1)

        # Now I am not allow the subclassing, which should give 1 result for each
        for cls in (StructureData, ParameterData, Node, Data):
            qb = QueryBuilder().append(cls,
                                       filters={'attributes.cat': 'miau'},
                                       subclassing=False)
            self.assertEqual(qb.count(), 1)
Ejemplo n.º 2
0
    def get_structuredata(self):
        """
        Return a StructureData object based on the data in the input file.
        
        This uses all of the data in the input file to do the necessary unit 
        conversion, ect. and then creates an AiiDA StructureData object.
    
        All of the names corresponding of the Kind objects composing the 
        StructureData object will match those found in the ATOMIC_SPECIES 
        block, so the pseudopotentials can be linked to the calculation using 
        the kind.name for each specific type of atom (in the event that you 
        wish to use different pseudo's for two or more of the same atom).
    
        :return: StructureData object of the structure in the input file
        :rtype: aiida.orm.data.structure.StructureData
        :raises aiida.common.exceptions.ParsingError: if there are issues
            parsing the input.
        """
        from aiida.orm.data.structure import StructureData, Kind, Site

        valid_elements_regex = re.compile(
            """
            (?P<ele>
H  | He |
Li | Be | B  | C  | N  | O  | F  | Ne |
Na | Mg | Al | Si | P  | S  | Cl | Ar |
K  | Ca | Sc | Ti | V  | Cr | Mn | Fe | Co | Ni | Cu | Zn | Ga | Ge | As | Se | Br | Kr |
Rb | Sr | Y  | Zr | Nb | Mo | Tc | Ru | Rh | Pd | Ag | Cd | In | Sn | Sb | Te | I  | Xe |
Cs | Ba | Hf | Ta | W  | Re | Os | Ir | Pt | Au | Hg | Tl | Pb | Bi | Po | At | Rn |
Fr | Ra | Rf | Db | Sg | Bh | Hs | Mt |

La | Ce | Pr | Nd | Pm | Sm | Eu | Gd | Tb | Dy | Ho | Er | Tm | Yb | Lu | # Lanthanides
Ac | Th | Pa | U  | Np | Pu | Am | Cm | Bk | Cf | Es | Fm | Md | No | Lr | # Actinides
        )
        [^a-z]  # Any specification of an element is followed by some number
                # or capital letter or special character.
""", re.X | re.I)

        structure_dict = self.get_structure_from_qeinput()
        # instance and set the cell
        structuredata = StructureData()
        structuredata._set_attr('cell', structure_dict['cell'].tolist())

        #################  KINDS ##########################
        for mass, name, pseudo in zip(
                structure_dict['species']['masses'],
                structure_dict['species']['names'],
                structure_dict['species']['pseudo_file_names']):
            try:
                # IMPORTANT: The symbols is parsed from the Pseudo file name
                # Is this the best way??
                # Should we also try from the associated kind name?
                symbols = valid_elements_regex.search(pseudo).group(
                    'ele').capitalize()
            except Exception as e:
                raise InputValidationError(
                    'I could not read an element name in {}'.format(
                        match.group(0)))
            structuredata.append_kind(
                Kind(
                    name=name,
                    symbols=symbols,
                    mass=mass,
                ))

        [
            structuredata.append_site(Site(
                kind_name=sym,
                position=pos,
            )) for sym, pos in zip(structure_dict['atom_names'],
                                   structure_dict['positions'])
        ]

        return structuredata
Ejemplo n.º 3
0
def get_structuredata_from_qeinput(filepath=None,
                                   text=None,
                                   namelists=None,
                                   atomic_species=None,
                                   atomic_positions=None,
                                   cell_parameters=None):
    """
    Function that receives either
    :param filepath: the filepath storing **or**
    :param text: the string of a standard QE-input file.
    An instance of :func:`StructureData` is initialized with kinds, positions and cell
    as defined in the input file.
    This function can deal with ibrav being set different from 0 and the cell being defined
    with celldm(n) or A,B,C, cosAB etc.
    """
    from aiida.orm.data.structure import StructureData, Kind, Site
    #~ from aiida.common.utils import get_fortfloat

    valid_elements_regex = re.compile(
        """
        (?P<ele>
H  | He |
Li | Be | B  | C  | N  | O  | F  | Ne |
Na | Mg | Al | Si | P  | S  | Cl | Ar |
K  | Ca | Sc | Ti | V  | Cr | Mn | Fe | Co | Ni | Cu | Zn | Ga | Ge | As | Se | Br | Kr |
Rb | Sr | Y  | Zr | Nb | Mo | Tc | Ru | Rh | Pd | Ag | Cd | In | Sn | Sb | Te | I  | Xe |
Cs | Ba | Hf | Ta | W  | Re | Os | Ir | Pt | Au | Hg | Tl | Pb | Bi | Po | At | Rn |
Fr | Ra | Rf | Db | Sg | Bh | Hs | Mt |

La | Ce | Pr | Nd | Pm | Sm | Eu | Gd | Tb | Dy | Ho | Er | Tm | Yb | Lu | # Lanthanides
Ac | Th | Pa | U  | Np | Pu | Am | Cm | Bk | Cf | Es | Fm | Md | No | Lr | # Actinides
        )
        [^a-z]  # Any specification of an element is followed by some number
                # or capital letter or special character.
    """, re.X | re.I)
    # I need either a valid filepath or the text of the qeinput file:
    if filepath:
        with open(filepath) as f:
            txt = f.read()
    elif text:
        txt = text
    else:
        raise InputValidationError(
            'Provide either a filepath or text to be parsed')

    if namelists is None:
        namelists = parse_namelists(text)
    if atomic_species is None:
        atomic_species = parse_atomic_species(txt)
    if cell_parameters is None:
        cell_parameters = parse_cell_parameters(txt)
    if atomic_positions is None:
        atomic_positions = parse_atomic_positions(txt)

    # First, I'm trying to figure out whether alat was specified:
    system_dict = namelists['SYSTEM']

    if 'a' in system_dict and 'celldm(1)' in system_dict:
        # The user should define exclusively in celldm or ABC-system
        raise InputValidationError('Both a and celldm(1) specified')
    elif 'a' in system_dict:
        alat = system_dict['a']
        using_celldm = False
    elif 'celldm(1)' in system_dict:
        alat = bohr_to_ang * system_dict['celldm(1)']
        using_celldm = True
    else:
        alat = None
        using_celldm = None

    cell = get_cell_from_parameters(cell_parameters, system_dict, alat,
                                    using_celldm)

    # instance and set the cell
    structuredata = StructureData()
    structuredata._set_attr('cell', cell.tolist())

    #################  KINDS ##########################

    for mass, name, pseudo in zip(atomic_species['masses'],
                                  atomic_species['names'],
                                  atomic_species['pseudo_file_names']):
        try:
            symbols = valid_elements_regex.search(pseudo).group(
                'ele').capitalize()
        except Exception as e:
            raise InputValidationError(
                'I could not read an element name in {}'.format(
                    match.group(0)))
        structuredata.append_kind(Kind(
            name=name,
            symbols=symbols,
            mass=mass,
        ))

    ################## POSITIONS #######################
    positions_units = atomic_positions['units']
    positions = np.array(atomic_positions['positions'])

    if positions_units is None:
        raise InputValidationError(
            "There is no unit for positions\n"
            "This is deprecated behavior for QE.\n"
            "In addition the default values by CP and PW differ (bohr and alat)"
        )
    elif positions_units == 'angstrom':
        pass
    elif positions_units == 'bohr':
        positions = bohr_to_ang * positions
    elif positions_units == 'crystal':
        positions = np.dot(positions, cell)
    elif positions_units == 'alat':
        positions = np.linalg.norm(cell[0]) * positions
    elif positions_units == 'crystal_sg':
        raise NotImplementedError('crystal_sg is not implemented')
    else:
        valid_positions_units = ('alat', 'bohr', 'angstrom', 'crystal',
                                 'crystal_sg')
        raise InputValidationError('\nFound atom unit {}, which is not\n'
                                   'among the valid units: {}'.format(
                                       positions_units,
                                       ', '.join(valid_positions_units)))
    ######### DEFINE SITES ######################

    positions = positions.tolist()
    [
        structuredata.append_site(Site(
            kind_name=sym,
            position=pos,
        )) for sym, pos in zip(atomic_positions['names'], positions)
    ]
    return structuredata