Source code for mppi.Utilities.Utils

"""
This module contains some low-level functions.
Some functions are extracted from the Futile Utils of PyBigDFT.
"""

import numpy as np
import os

[docs]def file_to_list(filename,skip='#'): """ Read the filename and append all the lines that do not start with the skip string, to a list. Empty lines are skipped Args: filename (str): name of the file skip (str): first elements of the skipped lines """ lines = [] with open(filename) as f: for l in f: if not l.startswith(skip) and len(l.strip()) > 0: lines.append(l) return lines
[docs]def floats_from_string(line,sep=None): """ Split a string using blank spaces and convert the elements to float. If an element cannot be converted it is skipped. Args: line (:py:class:`string`): string that contains a line of the file sep (:py:class:`string`) : Delimiter at which splits occur. If `None` the string is splitted at whitespaces Return: :py:class:`list` : list with the floats extracted from the line """ line_float = [] for value in line.split(sep=sep): try: line_float.append(float(value)) except ValueError: pass return line_float
[docs]def file_parser(filename,skip='#',sep=None): """ Parse a file. All the lines the start with the skip string are skipped. The lines of the file are converted in floats (elements are separated using the sep parameter). Elements that cannot be converted to float are ignored. Args: filename (:py:class:`string`): name of the file skip (:py:class:`string`): first elements of the skipped lines sep (:py:class:`string`) : Delimiter at which splits occur. If `None` the string is splitted at whitespaces Return: :py:class:`array' : array with the floats extracted from the file sorted in columns. So columns[0] contains the first column of the file and so on """ lines = file_to_list(filename) splitted = [] for line in lines: splitted.append(floats_from_string(line,sep=sep)) columns = np.array(splitted).transpose() return columns
[docs]def convertTonumber(x): """ Check if the input string can be converted to an integer or to a float variable Args: x (:py:class:`string`) : string to be converted """ try : if x.lstrip('-').isnumeric() : return int(x) else : return float(x) except (TypeError, ValueError): return x
[docs]def dict_set(inp,*subfields): """Ensure the provided fields and set the value Provide a entry point to the dictionary. Useful to define a key in a dictionary that may not have the previous keys already defined. Arguments: inp (dict): the top-level dictionary subfields (str,object): keys, ordered by level, that have to be retrieved from topmost level of ``inp``. The last item correspond to the value to be set . Example: >>> inp={} >>> dict_set(inp,'dft','nspin','mpol',2) >>> print (inp) {'dft': {'nspin': {'mpol': 2}}} """ if len(subfields) <= 1: raise ValueError('invalid subfields, the sequence should be longer than one item as the last one is the value to be given') keys=subfields[:-1] tmp,key=push_path(inp,*keys) tmp[key]=subfields[-1]
[docs]def dict_get(inp,*subfields): """Find the value of the provided sequence of keys in the dictionary, if available. Retrieve the value of the dictionary in a sequence of keys if it is available. Otherwise it provides as default value the last item of the sequence ``subfields``. Args: inp (dict): the top-level dictionary. Unchanged on exit. subfields (str,object): keys, ordered by level, that have to be retrieved from topmost level of ``inp``. The last item correspond to the value to be set. Returns: The value provided by the sequence of subfields if available, otherwise the default value given as the last item of the ``subfields`` sequence. """ if len(subfields) <= 1: raise ValueError('invalid subfields, the sequence should be longer than one item as the last one is the value to be given') tmp=inp keys=subfields[:-1] val=subfields[-1] for key in keys: tmp=tmp.get(key) if tmp is None: return val return tmp
[docs]def sort_lists(sort_by,ascending,*lists): """ Sort lists altogether following the lists indicated by the ``sort_by`` index. Args: sort_by (int): the index of the list which has to be taken as reference for sorting ascending (bool): Sort is performed in ascending order if True *lists: sequence of lists to be mutually sorted. They have to be of the same length. Returns: tuple of sorted lists Example: >>> l1=[5,3,4] >>> l2=['c','t','q'] >>> l3=[6,3,7] >>> print (sort_lists(0,True,l1,l2,l3)) >>> print (sort_lists(2,True,l1,l2,l3)) [(3, 4, 5), ('t', 'q', 'c'), (3, 7, 6)] [(3, 5, 4), ('t', 'c', 'q'), (3, 6, 7)] """ import operator return zip(*sorted(zip(*lists), reverse=not ascending, key=operator.itemgetter(sort_by)))
[docs]def dict_merge(dest, src): """ Recursive dict merge. Inspired by :meth:`dict.update`, instead of updating only top-level keys, dict_merge recurses down into dicts nested to an arbitrary depth, updating keys. The ``src`` is merged into ``dest``. From :ref:`angstwad/dict-merge.py` Arguments: dest (dict): dict onto which the merge is executed src (dict): dict merged into dest """ import collections for k, v in src.items(): if (k in dest and isinstance(dest[k], dict) and isinstance(src[k], collections.Mapping)): dict_merge(dest[k], src[k]) else: dest[k] = src[k]
[docs]def ensure_dir(file_path): """ Guarantees the existance on the directory given by the (relative) file_path Args: file_path (str): path of the directory to be created Returns: bool: True if the directory needed to be created, False if it existed already """ directory = file_path created=False if not os.path.exists(directory): os.makedirs(directory) created=True return created