Source code for schrodinger.application.matsci.qeschema.qeschema.utils

#
# Copyright (c), 2015-2020, Quantum Espresso Foundation and SISSA (Scuola
# Internazionale Superiore di Studi Avanzati). All rights reserved.
# This file is distributed under the terms of the MIT License. See the
# file 'LICENSE' in the root directory of the present distribution, or
# http://opensource.org/licenses/MIT.
#
# Authors: Davide Brunato
#
import logging
from collections.abc import MutableMapping

logger = logging.getLogger('qeschema')


[docs]def set_logger(loglevel=1, logfile=None): """ Setup a basic logger with an handler and a formatter, using a corresponding numerical range [0..4], where a higher value means a more verbose logging. The loglevel value is mapped to correspondent logging module's value: LOG_CRIT=0 (syslog.h value is 2) ==> logging.CRITICAL LOG_ERR=1 (syslog.h value is 3) ==> logging.ERROR LOG_WARNING=2 (syslog.h value is 4) ==> logging.WARNING LOG_INFO=3 (syslog.h value is 6) ==> logging.INFO LOG_DEBUG=4 (syslog.h value is 7) ==> logging.DEBUG If a logfile name is passed then writes logs to file, instead of send logs to the standard output. :param loglevel: Simplified POSIX's syslog like logging level index :param logfile: Logfile name for non-scripts runs """ global logger # Higher or lesser argument values are also mapped to DEBUG or CRITICAL effective_level = max(logging.DEBUG, logging.CRITICAL - loglevel * 10) logger.setLevel(effective_level) # Add the first new handler if not logger.handlers: if logfile is None: lh = logging.StreamHandler() else: lh = logging.FileHandler(logfile) lh.setLevel(effective_level) if effective_level <= logging.DEBUG: formatter = logging.Formatter( "[%(levelname)s:%(module)s:%(funcName)s: %(lineno)s] %(message)s" ) elif effective_level <= logging.INFO: formatter = logging.Formatter( "[%(levelname)s:%(module)s] %(message)s") else: formatter = logging.Formatter("%(levelname)s: %(message)s") lh.setFormatter(formatter) logger.addHandler(lh) else: for handler in logger.handlers: handler.setLevel(effective_level)
[docs]def etree_iter_path(elem, tag=None, path='.'): """ Iterate an ElementTree structure giving back couples with an element and its path. :param elem: root of the ElementTree :param tag: Optional tag matching argument. :param path: Argument element path """ if tag == "*": tag = None if tag is None or elem.tag == tag: yield elem, path for child in elem: child_path = '%s/%s' % (path, child.tag) for e, p in etree_iter_path(child, tag, path=child_path): yield e, p
[docs]def to_fortran(value): """ Translate a Python value to the equivalent literal representation for Fortran input. Leading and trailing spaces characters are removed from strings. """ if isinstance(value, bool): return '.true.' if value else '.false.' elif isinstance(value, str): return repr(value.strip()) elif isinstance(value, bytes): return repr(value.decode('utf-8').strip()) return str(value)
[docs]class BiunivocalMap(MutableMapping): """ A dictionary that implements a bijective correspondence, namely with constraints of uniqueness both on keys and on values. Both keys and values must be hashable. """
[docs] def __init__(self, *args, **kwargs): self.__map = {} self.__inverse = {} self.update(*args, **kwargs)
def __getitem__(self, key): try: return self.__map[key] except KeyError: if not hasattr(self, '__missing__'): raise return getattr(self, '__missing__')(key) def __setitem__(self, key, item): try: if self.__inverse[item] != key: raise ValueError( "Value '{0}' is already mapped by another key!".format( item)) except KeyError: if key in self.__map: del self.__inverse[self.__map[key]] self.__map[key] = item self.__inverse[item] = key else: del self.__inverse[self.__map[key]] self.__map[key] = item self.__inverse[item] = key def __delitem__(self, key): del self.__inverse[self.__map[key]] del self.__map[key] def __iter__(self): return iter(self.__map)
[docs] def __len__(self): return len(self.__map)
[docs] def __contains__(self, key): return key in self.__map
def __repr__(self): return '%s(%s)' % (self.__class__.__name__, self.__map or '')
[docs] def copy(self): return self.__class__(self.__map.copy())
[docs] def inverse(self): """Returns a copy of the inverse dictionary.""" return self.__inverse.copy()
[docs] def getkey(self, value, default=None): """ If *value* is in dictionary's values, returns the key correspondent to the value, else returns the *default* argument. """ try: return self.__inverse[value] except KeyError: return default