Ejemplo n.º 1
0
def test_get_formula_hill():
    """Make sure 'hill' and 'hill_compact' modes actually sort according to hill notation

    Wikipedia reference for the Hill system:
    https://en.wikipedia.org/wiki/Chemical_formula#Hill_system
    """
    symbol_lists = [(['F', 'H', 'O', 'N', 'Zn', 'C', 'H',
                      'C'], 'C2 H2 F N O Zn'),
                    (['F', 'O', 'N', 'Zn'], 'F N O Zn'),
                    (['F', 'O', 'N', 'C', 'Zn', 'C'], 'C2 F N O Zn'),
                    (['F', 'H', 'O', 'N', 'Zn', 'H'], 'F H2 N O Zn')]
    for symbol_list, expected_result in symbol_lists:
        assert get_formula(symbol_list, mode='hill',
                           separator=' ') == expected_result
        assert get_formula(symbol_list, mode='hill_compact',
                           separator=' ') == expected_result
Ejemplo n.º 2
0
    def _extract_formula(args, akinds, asites):
        """Extract formula from the structure object."""
        from aiida.orm.nodes.data.structure import (get_formula,
                                                    get_symbols_string)

        if args.element is not None:
            all_symbols = [_['symbols'][0] for _ in akinds]
            if not any([s in args.element for s in all_symbols]):
                return None

        if args.element_only is not None:
            all_symbols = [_['symbols'][0] for _ in akinds]
            if not all([s in all_symbols for s in args.element_only]):
                return None

        # We want only the StructureData that have attributes
        if akinds is None or asites is None:
            return None

        symbol_dict = {}
        for k in akinds:
            symbols = k['symbols']
            weights = k['weights']
            symbol_dict[k['name']] = get_symbols_string(symbols, weights)

        try:
            symbol_list = []
            for site in asites:
                symbol_list.append(symbol_dict[site['kind_name']])
            formula = get_formula(symbol_list, mode=args.formulamode)
        # If for some reason there is no kind with the name
        # referenced by the site
        except KeyError:
            formula = '<<UNKNOWN>>'
        return formula
Ejemplo n.º 3
0
    def _extract_formula(struc_pk, args, deser_data):
        """Extract formula."""
        from aiida.orm.nodes.data.structure import (get_formula,
                                                    get_symbols_string)

        if struc_pk is not None:
            # Exclude structures by the elements
            if args.element is not None:
                all_kinds = [
                    k['symbols'] for k in deser_data[struc_pk]['kinds']
                ]
                all_symbols = [
                    item for sublist in all_kinds for item in sublist
                ]
                if not any([s in args.element for s in all_symbols]):
                    return None
            if args.element_only is not None:
                all_kinds = [
                    k['symbols'] for k in deser_data[struc_pk]['kinds']
                ]
                all_symbols = [
                    item for sublist in all_kinds for item in sublist
                ]
                if not all([s in all_symbols for s in args.element_only]):
                    return None

            # build the formula
            symbol_dict = {
                k['name']: get_symbols_string(k['symbols'], k['weights'])
                for k in deser_data[struc_pk]['kinds']
            }
            try:
                symbol_list = [
                    symbol_dict[s['kind_name']]
                    for s in deser_data[struc_pk]['sites']
                ]
                formula = get_formula(symbol_list, mode=args.formulamode)
            # If for some reason there is no kind with the name
            # referenced by the site
            except KeyError:
                formula = '<<UNKNOWN>>'
                # cycle if we imposed the filter on elements
                if args.element is not None or args.element_only is not None:
                    return None
        else:
            formula = '<<UNKNOWN>>'

        return formula
    def get_formula(self, mode="hill", separator=""):
        """Copy of aiida.orm.StructureData:get_formula()"""
        from aiida.orm.nodes.data.structure import get_symbols_string, get_formula

        symbol_list = []
        for site in self._sites:
            for _kind in self._kinds:
                if _kind["name"] == site["kind_name"]:
                    kind = _kind
                    break
            else:
                raise AiidaError(
                    f"kind with name {site['kind_name']} cannot be found amongst the kinds {self._kinds}"
                )
            symbol_list.append(get_symbols_string(kind["symbols"], kind["weights"]))

        return get_formula(symbol_list, mode=mode, separator=separator)
Ejemplo n.º 5
0
    def _extract_formula(akinds, asites, args):
        """
        Extract formula from the structure object.

        :param akinds: list of kinds, e.g. [{'mass': 55.845, 'name': 'Fe', 'symbols': ['Fe'], 'weights': [1.0]},
                                            {'mass': 15.9994, 'name': 'O', 'symbols': ['O'], 'weights': [1.0]}]
        :param asites: list of structure sites e.g. [{'position': [0.0, 0.0, 0.0], 'kind_name': 'Fe'},
                                                        {'position': [2.0, 2.0, 2.0], 'kind_name': 'O'}]
        :param args: a namespace with parsed command line parameters, here only 'element' and 'element_only' are used
        :type args: dict

        :return: a string with formula if the formula is found
        """
        from aiida.orm.nodes.data.structure import (get_formula,
                                                    get_symbols_string)

        if args.element is not None:
            all_symbols = [_['symbols'][0] for _ in akinds]
            if not any([s in args.element for s in all_symbols]):
                return None

        if args.element_only is not None:
            all_symbols = [_['symbols'][0] for _ in akinds]
            if not all([s in all_symbols for s in args.element_only]):
                return None

        # We want only the StructureData that have attributes
        if akinds is None or asites is None:
            return '<<UNKNOWN>>'

        symbol_dict = {}
        for k in akinds:
            symbols = k['symbols']
            weights = k['weights']
            symbol_dict[k['name']] = get_symbols_string(symbols, weights)

        try:
            symbol_list = []
            for site in asites:
                symbol_list.append(symbol_dict[site['kind_name']])
            formula = get_formula(symbol_list, mode=args.formulamode)
        # If for some reason there is no kind with the name
        # referenced by the site
        except KeyError:
            formula = '<<UNKNOWN>>'
        return formula
Ejemplo n.º 6
0
def structure_list(elements, raw, formula_mode, past_days, groups, all_users):
    """List StructureData objects."""
    from aiida.orm.nodes.data.structure import StructureData, get_formula, get_symbols_string
    from tabulate import tabulate

    elements_only = False
    lst = data_list(StructureData, ['Id', 'Label', 'Kinds', 'Sites'], elements,
                    elements_only, formula_mode, past_days, groups, all_users)

    entry_list = []
    for [pid, label, akinds, asites] in lst:
        # If symbols are defined there is a filtering of the structures
        # based on the element
        # When QueryBuilder will support this (attribute)s filtering,
        # it will be pushed in the query.
        if elements is not None:
            all_symbols = [_['symbols'][0] for _ in akinds]
            if not any([s in elements for s in all_symbols]):
                continue

            if elements_only:
                echo.echo_critical('Not implemented elements-only search')

        # We want only the StructureData that have attributes
        if akinds is None or asites is None:
            continue

        symbol_dict = {}
        for k in akinds:
            symbols = k['symbols']
            weights = k['weights']
            symbol_dict[k['name']] = get_symbols_string(symbols, weights)

        try:
            symbol_list = []
            for site in asites:
                symbol_list.append(symbol_dict[site['kind_name']])
            formula = get_formula(symbol_list, mode=formula_mode)
        # If for some reason there is no kind with the name
        # referenced by the site
        except KeyError:
            formula = '<<UNKNOWN>>'
        entry_list.append([str(pid), label, str(formula)])

    counter = 0
    struct_list_data = list()
    if not raw:
        struct_list_data.append(LIST_PROJECT_HEADERS)
    for entry in entry_list:
        for i, value in enumerate(entry):
            if isinstance(value, list):
                entry[i] = ','.join(value)
        for i in range(len(entry), len(LIST_PROJECT_HEADERS)):
            entry.append(None)
        counter += 1
    struct_list_data.extend(entry_list)
    if raw:
        echo.echo(tabulate(struct_list_data, tablefmt='plain'))
    else:
        echo.echo(tabulate(struct_list_data, headers='firstrow'))
        echo.echo('\nTotal results: {}\n'.format(counter))
Ejemplo n.º 7
0
    def get_bands_and_parents_structure(self, args):
        """
        Returns bands and closest parent structure
        """
        from django.db.models import Q
        from aiida.backends.djsite.db import models
        from aiida.common.utils import grouper
        from aiida.orm.nodes.data.structure import (get_formula,
                                                    get_symbols_string)
        from aiida.orm import BandsData
        from aiida import orm

        user = orm.User.objects.get_default()

        query_group_size = 100
        q_object = None
        if args.all_users is False:
            q_object = Q(user__id=user.id)
        else:
            q_object = Q()

        self.query_past_days(q_object, args)
        self.query_group(q_object, args)

        bands_list = models.DbNode.objects.filter(node_type__startswith=BandsData.class_node_type) \
            .filter(q_object).distinct().order_by('ctime')
        bands_list_data = bands_list.values_list('pk', 'label', 'ctime')

        # split data in chunks
        grouped_bands_list_data = grouper(query_group_size,
                                          [(_[0], _[1], _[2])
                                           for _ in bands_list_data])

        entry_list = []
        for this_chunk in grouped_bands_list_data:
            # gather all banddata pks
            pks = [_[0] for _ in this_chunk]

            # get the closest structures (WITHOUT DbPath)
            q_object = Q(node_type='data.structure.StructureData.')
            structure_dict = get_closest_parents(pks, q_object, chunk_size=1)

            struc_pks = [structure_dict[pk] for pk in pks]

            # query for the attributes needed for the structure formula
            res_attr = models.DbNode.objects.filter(
                id__in=struc_pks).values_list('id', 'attributes')
            deser_data = {}
            for rattr in res_attr:
                deser_data[rattr[0]] = rattr[1]

            # prepare the printout
            for ((bid, blabel, bdate), struc_pk) in zip(this_chunk, struc_pks):
                if struc_pk is not None:
                    # Exclude structures by the elements
                    if args.element is not None:
                        all_kinds = [
                            k['symbols'] for k in deser_data[struc_pk]['kinds']
                        ]
                        all_symbols = [
                            item for sublist in all_kinds for item in sublist
                        ]
                        if not any([s in args.element for s in all_symbols]):
                            continue
                    if args.element_only is not None:
                        all_kinds = [
                            k['symbols'] for k in deser_data[struc_pk]['kinds']
                        ]
                        all_symbols = [
                            item for sublist in all_kinds for item in sublist
                        ]
                        if not all(
                            [s in all_symbols for s in args.element_only]):
                            continue

                    # build the formula
                    symbol_dict = {
                        k['name']: get_symbols_string(k['symbols'],
                                                      k['weights'])
                        for k in deser_data[struc_pk]['kinds']
                    }
                    try:
                        symbol_list = [
                            symbol_dict[s['kind_name']]
                            for s in deser_data[struc_pk]['sites']
                        ]
                        formula = get_formula(symbol_list,
                                              mode=args.formulamode)
                    # If for some reason there is no kind with the name
                    # referenced by the site
                    except KeyError:
                        formula = '<<UNKNOWN>>'
                        # cycle if we imposed the filter on elements
                        if args.element is not None or args.element_only is not None:
                            continue
                else:
                    formula = '<<UNKNOWN>>'
                entry_list.append([
                    str(bid),
                    str(formula),
                    bdate.strftime('%d %b %Y'), blabel
                ])

        return entry_list
Ejemplo n.º 8
0
    def get_bands_and_parents_structure(self, args):
        """
        Search for bands and return bands and the closest structure that is a parent of the instance.
        This is the backend independent way, can be overriden for performance reason

        :returns:
            A list of sublists, each latter containing (in order):
                pk as string, formula as string, creation date, bandsdata-label
        """

        import datetime
        from aiida.common import timezone
        from aiida.orm.nodes.data.structure import (get_formula,
                                                    get_symbols_string)
        from aiida import orm

        qb = orm.QueryBuilder()
        if args.all_users is False:
            user = orm.User.objects.get_default()
            qb.append(orm.User, tag='creator', filters={'email': user.email})
        else:
            qb.append(orm.User, tag='creator')

        bdata_filters = {}
        if args.past_days is not None:
            now = timezone.now()
            n_days_ago = now - datetime.timedelta(days=args.past_days)
            bdata_filters.update({'ctime': {'>=': n_days_ago}})

        qb.append(orm.BandsData,
                  tag='bdata',
                  with_user='******',
                  filters=bdata_filters,
                  project=['id', 'label', 'ctime'])

        group_filters = {}

        if args.group_name is not None:
            group_filters.update({'name': {'in': args.group_name}})
        if args.group_pk is not None:
            group_filters.update({'id': {'in': args.group_pk}})
        if group_filters:
            qb.append(orm.Group,
                      tag='group',
                      filters=group_filters,
                      with_node='bdata')

        qb.append(
            orm.StructureData,
            tag='sdata',
            with_descendants='bdata',
            # We don't care about the creator of StructureData
            project=['id', 'attributes.kinds', 'attributes.sites'])

        qb.order_by({orm.StructureData: {'ctime': 'desc'}})

        list_data = qb.distinct()

        entry_list = []
        already_visited_bdata = set()

        for [bid, blabel, bdate, sid, akinds, asites] in list_data.all():

            # We process only one StructureData per BandsData.
            # We want to process the closest StructureData to
            # every BandsData.
            # We hope that the StructureData with the latest
            # creation time is the closest one.
            # This will be updated when the QueryBuilder supports
            # order_by by the distance of two nodes.
            if already_visited_bdata.__contains__(bid):
                continue
            already_visited_bdata.add(bid)

            if args.element is not None:
                all_symbols = [_['symbols'][0] for _ in akinds]
                if not any([s in args.element for s in all_symbols]):
                    continue

            if args.element_only is not None:
                all_symbols = [_['symbols'][0] for _ in akinds]
                if not all([s in all_symbols for s in args.element_only]):
                    continue

            # We want only the StructureData that have attributes
            if akinds is None or asites is None:
                continue

            symbol_dict = {}
            for k in akinds:
                symbols = k['symbols']
                weights = k['weights']
                symbol_dict[k['name']] = get_symbols_string(symbols, weights)

            try:
                symbol_list = []
                for s in asites:
                    symbol_list.append(symbol_dict[s['kind_name']])
                formula = get_formula(symbol_list, mode=args.formulamode)
            # If for some reason there is no kind with the name
            # referenced by the site
            except KeyError:
                formula = '<<UNKNOWN>>'
            entry_list.append(
                [str(bid),
                 str(formula),
                 bdate.strftime('%d %b %Y'), blabel])

        return entry_list