예제 #1
0
class LightVector(LightTensor):

    ##################
    # Initialization #
    ##################

    def __new__(cls, iterable):
        return np.array(iterable).view(cls)

    ##################
    # Static Methods #
    ##################

    @staticmethod
    def l_sub(a, b):
        return LightVector(a.view(np.ndarray) - b.view(np.ndarray))

    @staticmethod
    def l_add(a, b):
        return LightVector(a.view(np.ndarray) + b.view(np.ndarray))

    ###########
    # Methods #
    ###########

    #-----------------------------#
    # Methods that return scalars #
    #-----------------------------#

    def magnitude(self):
        """ The magnitude of the vector.
        """
        return math.sqrt(self.dot(self))
        # Aliases

    norm = function_alias('norm', magnitude)

    def size(self):
        """ The number of entries in the vector
        """
        return self.shape[0]

    #---------------------------------------#
    # "Light" versions of methods in Vector #
    #---------------------------------------#

    def normalize(self):
        """ Performs an in-place normalization of `self`.

        :Examples:


        >>> Vector(2.0, 0.0, 0.0).normalize()
        Vector([ 1.,  0.,  0.])
        >>> Vector(0.5, 0.5, 0.5).normalize()
        Vector([ 0.57735027,  0.57735027,  0.57735027])
        >>> v = Vector(-0.5, 0.5, -0.5).normalize()
        >>> v
        Vector([-0.57735027,  0.57735027, -0.57735027])
        >>> v.magnitude()
        1.0

        """
        if self.is_zero():
            raise ZeroDivisionError(
                "can't normalize a zero vector.  (A zero vector, "
                "in this case, is one with a magnitude less than {0}.  "
                "The vector you tried to normalize has a magnitude of "
                "{1}".format(self.zero_cutoff, self.magnitude()))
        norm = self.magnitude()
        for i in xrange(self.size()):
            self[i] /= norm
        return self

    def l_normalized(self):
        """ Same as `l_normalize()`, but does not modify self
        """
        ret_val = copy(self)
        ret_val.normalize()
        return ret_val.view(LightVector)

    normalized = function_alias('normalized', l_normalized)

    def l_cross(self, other):
        """ Returns cross product of self with other.  Wrapper to `numpy.cross`
        """
        return l_cross(self, other)

    #----------------------------------------------------------------------#
    # Boolean-returning methods for determing aspects of the vector `self` #
    #----------------------------------------------------------------------#

    def is_cartesian(self):
        """ Returns True if the vector is Cartesian
        (i.e. if the vector is two or three dimensional).
        """
        return self.size() == 2 or self.size() == 3

    def is_zero_vector(self, cutoff=None):
        """
        Alias for Tensor.is_zero()
        """
        return self.is_zero(cutoff)
예제 #2
0
    'AngularUnit',
    'ElectricChargeUnit',
    'MassUnit',
    'TimeUnit'
]

#############
# Utilities #
#############

def isunit(unit):
    if isinstance(unit, Unit) or isinstance(unit, CompositeUnit):
        return True
    else:
        return False
is_unit = function_alias('is_unit', isunit)

def plural(unit): # pragma: no cover
    if not isunit(unit):
        raise TypeError
    return unit.__plural__

def convert_units(val, from_unit, to_unit):
    if not isunit(from_unit):
        raise UnknownUnitError(from_unit)
    if not isunit(to_unit):
        raise UnknownUnitError(to_unit)
    if from_unit == to_unit:
        return val
    return val * from_unit.to(to_unit)
convert = function_alias('convert', convert_units)
예제 #3
0
from grendel.util.units.unit import isunit
from grendel.util.metaclasses import Immutable


__all__ = ["hasunits", "has_units", "strip_units", "stripunits", "ValueWithUnits", "Unitized"]

#####################
# Utility functions #
#####################


def has_units(obj):
    return hasattr(obj, "units") and obj.units is not None


hasunits = function_alias("hasunits", has_units)

# TODO Document this
# TODO optional kwarg to strip units after converting to default units (which is non-trivial for composite units)
@typechecked(convert_to=(None, isunit), assume_units=(None, isunit))
def strip_units(obj, convert_to=None, assume_units=None):
    """ Strips the units off of a unitized object
    (or, if the object is not `Unitized`, just return it).  If `convert_to` is given,
    convert to these units if `obj` is `Unitized`.  If `assume_units` is given, `obj` is
    assumed to have the units given by this argument if (and only if) it is not an
    instance of `Unitized`.
    """
    if assume_units and not convert_to:
        raise TypeError(
            "call of strip_units with 'assume_units'"
            " argument must also have a 'convert_to' argument"
예제 #4
0
        return ', '.join(fxn(i) for i in l[:-1]) + (',' if oxford_comma else
                                                    '') + ' and ' + fxn(l[-1])


def orjoin(iterable, fxn=str, oxford_comma=True):
    l = list(iterable)
    length = len(l)
    if length == 0:
        return '<empty list>'
    elif length == 1:
        return fxn(l[0])
    elif length == 2:
        return fxn(l[0]) + ' or ' + fxn(l[1])
    else:
        return ', '.join(fxn(i) for i in l[:-1]) + (',' if oxford_comma else
                                                    '') + ' or ' + fxn(l[-1])


#####################
# Dependent Imports #
#####################

from grendel.util.exceptions import raises_error

###########
# Aliases #
###########

indent = function_alias('indent', indented)
shortstr = function_alias('shortstr', short_str)
예제 #5
0
from grendel.util.metaclasses import Immutable


__all__ = [
    'hasunits', 'has_units',
    'strip_units', 'stripunits',
    'ValueWithUnits', 'Unitized'
]

#####################
# Utility functions #
#####################

def has_units(obj):
    return hasattr(obj, 'units') and obj.units is not None
hasunits = function_alias('hasunits', has_units)

# TODO Document this
# TODO optional kwarg to strip units after converting to default units (which is non-trivial for composite units)
@typechecked(
    convert_to=(None, isunit),
    assume_units=(None, isunit))
def strip_units(obj, convert_to=None, assume_units=None):
    """ Strips the units off of a unitized object
    (or, if the object is not `Unitized`, just return it).  If `convert_to` is given,
    convert to these units if `obj` is `Unitized`.  If `assume_units` is given, `obj` is
    assumed to have the units given by this argument if (and only if) it is not an
    instance of `Unitized`.
    """
    if assume_units and not convert_to:
        raise TypeError("call of strip_units with 'assume_units'"
예제 #6
0
class overloaded(MethodLike):
    """ Overload a function the Pythonic (at least, Python 2) way.

    Types can be specified using the `overloaded` instance decorator method `overload_with` (which is aliased as
    `overload`, `submethod`, and `subfunction`).

    :Examples:

    >>> @overloaded
    ... def test():
    ...     raise TypeError
    ...
    >>> @test.overload_with(int, int)
    ... def test(a, b=5):
    ...     return a+b
    ...
    >>> @test.overload_with(str)
    ... def test(string, *args, **kwargs):
    ...     return string + (' ' if len(args) else '') + ', '.join(list(args) + kwargs.keys())
    ...
    >>> @test.overload_with(list, func=callable)
    ... def test(lst, func, *args):
    ...     for item in lst:
    ...         if func(item, *args):
    ...             return item
    ...
    >>> test(1, 3)
    4
    >>> test(17)
    22
    >>> test("Hello")
    'Hello'
    >>> test("Hello", "World")
    'Hello World'
    >>> test("Hello", "Earth", "Mars", "Jupiter")
    'Hello Earth, Mars, Jupiter'
    >>> test([1, 2, 3], lambda x: x**2 % 2 == 0)
    2
    >>> test([1, 2, 3], lambda x, y: x**2 % y == 0, 1)
    1
    >>> test(3.14159, 3.234)
    Traceback (most recent call last):
        ...
    TypeError: invalid function signature test(float, float).
      Available signatures are:
        test(a: int, b: int=5)
            Not valid signature because: argument 'a' is not of the correct type
        test(string: str, *args, **kwargs)
            Not valid signature because: argument 'string' is not of the correct type
        test(lst: list, func: <something for which callable(func) returns True>, *args)
            Not valid signature because: argument 'lst' is not of the correct type
    >>> # giving multiple values for a keyword argument means there is no match.  For instance:
    >>> test('Hello', 'World', string='this is wrong')
    Traceback (most recent call last):
        ...
    TypeError: invalid function signature test(str, str, string=str).
      Available signatures are:
        test(a: int, b: int=5)
            Not valid signature because: argument 'a' is not of the correct type
        test(string: str, *args, **kwargs)
            Not valid signature because: got multiple values for keyword argument 'string'
        test(lst: list, func: <something for which callable(func) returns True>, *args)
            Not valid signature because: argument 'lst' is not of the correct type
    >>> # Methods in classes
    >>> class Foo(object):
    ...     @overloaded
    ...     def bar(self, *args, **kwargs): pass
    ...
    ...     @bar.overload_with(a=int, b=int)
    ...     def bar(self, a, b):
    ...         if not hasattr(self, 'total'):
    ...             self.total = 0
    ...         self.total += a + b
    ...         return a + b
    ...
    >>> foo = Foo()
    >>> foo.bar(1,2)
    3
    >>> foo.bar(4,5)
    9
    >>> foo.total
    12
    >>> Foo.bar(foo, 7, 8)
    15
    >>> foo.total
    27

    """

    ######################
    # Private Attributes #
    ######################

    _orig_func = None
    _versions = None

    ##################
    # Initialization #
    ##################

    def __init__(self, f):
        self._orig_func = f
        self.__name__ = f.__name__
        self.__doc__ = f.__doc__
        self.__dict__.update(f.__dict__)
        self._versions = []

    ###################
    # Special Methods #
    ###################

    def __get__(self, instance, owner):
        # Mimic the behavior of the built-in function type
        return types.MethodType(self, instance, owner)

    def __call__(self, *args, **kwargs):
        fail_reasons = []
        for typespec in self._versions:
            fargs, fkwargs_or_fail_reason = typespec.get_arg_list(
                *args, **kwargs)
            if fargs is not None:
                return typespec.func(*fargs, **fkwargs_or_fail_reason)
            else:
                fail_reasons.append(fkwargs_or_fail_reason
                                    or '<unknown reason for failed match>')
        # Should we fall back on the original function's code here?  If so, we should catch and reraise any type errors
        raise TypeError(
            "invalid function signature {0}.\n  Available signatures are:\n{1}"
            .format(
                argtypespec.get_call_signature(self.__name__, *args, **kwargs),
                indented('\n'.join(
                    line + "\n" +
                    indented("Not valid signature because: " + reason)
                    for line, reason in zip(
                        self._build_allowed_string().splitlines(),
                        fail_reasons)))))

    ###########
    # Methods #
    ###########

    def getargspec(self):
        """ Pass-through to original function to conform with the `FunctionLike` protocol
        """
        return inspect.getargspec(self._orig_func)

    def overload_with(self, *typespecs_or_func, **kwargs):
        """ Add a overloaded version of the decorated function to the available options for a given overloaded function.
        Types can be specified several ways.  The simplest is to give the types as plain old arguments to
        the `overload_with` decorator.  The order of the arguments given corresponds to the order of the arguments in
        the function definition.  For example:

            >>> @overloaded
            ... def foo():
            ...     pass
            ...
            >>> @foo.overload_with(int, str)
            ... def foo(num, word):
            ...     return word * num
            ...
            >>> foo(3, 'hello')
            'hellohellohello'
            >>> foo('hello', 3)  # doctest: +ELLIPSIS
            Traceback (most recent call last):
                ...
            TypeError: invalid function signature ...

        If fewer types are specified than arguments, it is assumed that each of the remaining arguments can be any type.
        (specifying `None` for the type has the same effect).  Keyword arguments may also be given to `overload_with`,
        where the keyword must correspond to the argument name in the function definition.  Here is an example of this
        specification technique (which may be mixed with the previous technique), using the overloaded function `foo`
        from above:

            >>> @foo.overload_with(int, int, c=int, string=str)
            ... def foo(a, b, string, c=1):
            ...     return string*a*b*c
            ...
            >>> foo(2, 3, 'a')
            'aaaaaa'

        Finally, types may be specified by way of Python 3 function annotations (this is the prefered technique
        if the code is only to be used in Python 3) by using the `overload_with` decorator without arguments.

        The type of a given argument need not be an instance of `type`.  It can also be any callable that can
        be called with one argument, `None`, an `IterableOf` instance, a string, or a tuple of `type`
        any of these.  The way these work is as follows:

        * If the type is a callable that does not return `False` (or anything with a truth value
          of False) when called with the argument value, the argument is considered to be of the correct type.

        * If one of the types in a sequence is `None` and the argument is `None`, the argument is considered
          to have the correct type. [#f2]_

        * If the type is an instance if `IterableOf` (or one of its subtypes), the argument is considered to be
          the correct type if and only if all of the items in the container are considered the correct type when
          the criteria described here are applied with the `types` attribute of the `IterableOf` instance

        * If the type is a string, the string is evaluated in the context of the overloaded function's globals, and
          the return value of this evaluation is used as the type (which may, in turn, be any of the options described
          here except for a string).  This is particularly useful when the function to be overloaded is a
          method that takes as an argument an instance of that method's parent class.  Since the parent class
          will not be defined at the time of the function definition, using the parent class's name as an identifier
          will not work.

        * Finally, if a `tuple` (or any other `Iterable`) of type specifications is given, the argument is considered
          to have the correct type if any of the type specifications in the list lead to the correct type.

        For example:

            >>> def str_reversed(var):
            ...     return ''.join(reversed(var)) if isinstance(var, str) else NotImplemented
            ...
            >>> @foo.overload_with(
            ...     bar=lambda x: x == str_reversed(x),
            ...     n=(int, lambda x: isinstance(x, float) and round(x) == x)
            ... )
            ... def foo(bar, n):
            ...     return bar * int(n) + ' is a palendrome!'
            ...
            >>> @foo.overload_with(baz=str)
            ... def foo(baz, n=3):
            ...     return baz * int(n) + ' is not a palendrome.'
            ...
            >>> foo('racecar', 2.0)
            'racecarracecar is a palendrome!'
            >>> foo('asdf')
            'asdfasdfasdf is not a palendrome.'

        The above example also illustrates the order of precidence for overloaded functions:  if a call is
        allowed to multiple versions of the function, the first to be defined is used.  (Notice that the first
        call in the above example matches both overloaded versions of `foo` defined in the example).

        ..warning ::
            To allow for the use Python 3 function annotations, specifying a single argument to `overload_with` that
            is a callable will assume that the Python 3 type specification method is being used, as described above.
            This could cause problems if what is actually intended is that there be only one type-constrained
            argument which returns `True` for an arbitrary callable.  To get around this, simply specify the type
            callable for the single argument using the keyword form or as a single item tuple.  If the callable
            you want to use for this specification is a builtin such as `callable` or `int`, this shouldn't be
            an issue.

        .. rubric:: Footnotes

        .. [#f2] Note that if the type is `None` and it is not in a sequence, or a length one tuple `(None,)` is
                 given, this is considered a match for all types.  This is mostly to allow arguments to be left out
                 of the specification (in particular, the first argument of most methods, `self`)

        """
        # TODO check to make sure type specifications are valid
        if sys.version_info > (3, 0) \
                and len(kwargs) == 0 \
                and len(typespecs_or_func) == 1 \
                and inspect.isfunction(typespecs_or_func[0]) \
                and not inspect.isbuiltin(typespecs_or_func[0]):
            func = typespecs_or_func[0]
            if hasattr(func, 'func_annotations'):
                # Python 3 version with func_annotations:
                argspec = inspect.getargspec(func)
                # for now, ignore varargs and keywords annotations
                annotations = func.func_annotations
                typespec_dict = {}
                for arg in argspec:
                    typespec_dict[arg] = func.func_annotations[arg]
                self._versions.append(argtypespec(func, typespec_dict))
                return self
            else:
                raise TypeError(
                    "when not using Python 3 function annotations, "
                    "{}.overload_with must\nbe called with "
                    "type specifications as arguments".format(self.__name__))
        else:

            def _get_func_decorator(f):
                argspec = inspect.getargspec(f)
                typespec_dict = {}
                # remember zip always truncates at the length of the shortest iterator
                for spec, argname in zip(typespecs_or_func, argspec.args):
                    typespec_dict[argname] = spec
                for argname, spec in kwargs.items():
                    if argname in typespec_dict:
                        raise TypeError(
                            "multiple type specifications given for "
                            "argument {} to overloaded function {}()".format(
                                argname, self.__name__))
                    if argname not in argspec.args:
                        raise TypeError(
                            "type specifiation for unknown argument {} given to overloaded "
                            "function {}()".format(argname, self.__name__))
                    typespec_dict[argname] = spec
                # fill in None for anything missing, indicating any type will do
                for argname in argspec.args:
                    if argname not in typespec_dict:
                        typespec_dict[argname] = None
                self._versions.append(argtypespec(f, typespec_dict))
                return self

            return _get_func_decorator

    submethod = function_alias('submethod', overload_with)
    subfunction = function_alias('subfuntion', overload_with)
    overload = function_alias('overload', overload_with)

    ###################
    # Private Methods #
    ###################

    def _build_allowed_string(self):
        return '\n'.join(typespec.signature for typespec in self._versions)
예제 #7
0
     Derivative properties can be automatically or manually transformed to other representations.
    """
    if not issubclass(prop, MolecularProperty):
        raise TypeError
    if raises_error(int, order):
        raise TypeError
    name = '_{1}Derivative{0}'.format(order, prop.__name__)
    if name in DerivativeProperty.known_subclasses:
        ret_val = PartiallyConstructed(DerivativeProperty.known_subclasses[name])
    else:
        ret = type(name, (DerivativeProperty,), {})
        DerivativeProperty.known_subclasses[name] = ret
        ret_val = PartiallyConstructed(ret)
    ret_val.with_attributes(order=order, representation=representation)
    return ret_val

PropertyDerivative = function_alias('PropertyDerivative', MolecularPropertyDerivative)

Gradient = EnergyGradient = Forces = PropertyDerivative(Energy, order=1)
Hessian = EnergyHessian = PropertyDerivative(Energy, order=2)

#####################
# Dependent Imports #
#####################

from grendel.differentiation.derivative_tensor import RepresentationDependentTensor
from grendel.representations.internal_representation import InternalRepresentation
from grendel.representations.representation import Representation

예제 #8
0
__all__ = [
    'hasunits', 'has_units', 'strip_units', 'stripunits', 'ValueWithUnits',
    'Unitized'
]

#####################
# Utility functions #
#####################


def has_units(obj):
    return hasattr(obj, 'units') and obj.units is not None


hasunits = function_alias('hasunits', has_units)


# TODO Document this
# TODO optional kwarg to strip units after converting to default units (which is non-trivial for composite units)
@typechecked(convert_to=(None, isunit), assume_units=(None, isunit))
def strip_units(obj, convert_to=None, assume_units=None):
    """ Strips the units off of a unitized object
    (or, if the object is not `Unitized`, just return it).  If `convert_to` is given,
    convert to these units if `obj` is `Unitized`.  If `assume_units` is given, `obj` is
    assumed to have the units given by this argument if (and only if) it is not an
    instance of `Unitized`.
    """
    if assume_units and not convert_to:
        raise TypeError(
            "call of strip_units with 'assume_units'"
예제 #9
0
class Representation(Freezable):
    """
    Superclass of all the representations types.

    :Attributes:

        molecule : `Molecule`
            The `Molecule` object represented by `self`.
        coords : list of `Coordinate`
            The coordinates that make up the representation

    """

    __metaclass__ = ABCMeta

    ##############
    # Attributes #
    ##############

    molecule = FreezableAttribute(name="molecule",
                                  doc="""
        The `Molecule` object represented by `self`.
        """)

    coords = FreezableListAttribute(name="coords",
                                    doc="""
        The coordinates that make up the representation
        """)

    units = ReadOnlyAttribute(name='units',
                              doc="""
        The units to use for the coordinates created, or if the created coordinates vary in units, a `dict` of
        `UnitGenre`, `Unit` pairs.  Must be passed into constructor; defaults to `genre.default`, where `genre` is
        the `UnitGenre` subclass of the applicable units.
        """)

    ###################
    # Special Methods #
    ###################

    def __getitem__(self, item):
        return self.coords[item]

    def __len__(self):
        return len(self.coords)

    def __iter__(self):
        for coord in self.coords:
            yield coord

    ##############
    # Properties #
    ##############

    @property
    def values(self):
        vals = [c.value for c in self.coords]
        return Vector(vals)

    value = values

    ####################
    # Abstract Methods #
    ####################

    @abstractmethod
    def add_coordinate_copy(self, coordinate):
        return NotImplemented

    @abstractmethod
    def copy_with_molecule(self, molecule):
        """ Make a copy of `self` that is the same in every way except for the `molecule` attribute.
        New Coordinate objects are created using the `Coordinate.copy_for_representation()` method for
        each element of `self.coords`.
        This is an abstract method that *must* be implemented by all Representation subclasses.
        """
        return NotImplemented

    @abstractmethod
    def displaced_by(self, disp, tol=None, maxiter=None):
        """ Apply the `Displacement` instance `disp` to the molecule and current representation,
        generating a new molecule and a new representation (which start as a `deepcopy` and the return value of
        `Representation.copy_with_molecule`, respectively) with the displacement applied.
        This is an abstract method that *must* be implemented by all Representation subclasses.
        """
        return NotImplemented

    ###########
    # Methods #
    ###########

    def values_for_molecule(self, mol):
        return Vector([c.value_for_molecule(mol) for c in self.coords])

    value_for_molecule = function_alias('value_for_molecule',
                                        values_for_molecule)

    def values_for_matrix(self, mat):
        return Vector([c.value_for_molecule_matrix(mat) for c in self.coords])

    value_for_matrix = function_alias('value_for_matrix', values_for_matrix)
예제 #10
0
class ComputationResultGetter(ResultGetter):
    """
    """

    ####################
    # Class Attributes #
    ####################

    known_result_getters = {}
    directory_series = {}

    ##############
    # Attributes #
    ##############

    computations = None
    computation_kwargs = None
    use_directory_series = None

    ##################
    # Initialization #
    ##################

    def __new__(cls, use_directory_series=False, **kwargs):
        """
        """
        # First set ourselves up and parse our own kwargs...

        # Now remove the molecule property, if it's present, so the kwargs are usable for lots of stuff...
        kwargs.pop('molecule', None)
        # Check to see if an identical ComputationResultGetter exists
        try:
            key = frozenset((k, v) for k, v in kwargs.iteritems())
        except TypeError:
            key = frozenset((id(k), id(v)) for k, v in kwargs.iteritems())
        if key in ComputationResultGetter.known_result_getters:
            ret_val = ComputationResultGetter.known_result_getters[key]
        else:
            ret_val = object.__new__(cls)
        ret_val.use_directory_series = use_directory_series
        if use_directory_series:
            raise NotImplementedError
        # Then pass the remaining kwargs to computations when they are generated...
        ret_val.computation_kwargs = copy(kwargs)
        ComputationResultGetter.known_result_getters[key] = ret_val
        ret_val.computations = []
        return ret_val

    ###########
    # Methods #
    ###########

    def can_get_property_for_molecule(self, molecule, property, details=None):
        try:
            comp = self._get_comp(molecule, property, details, True)
            if comp.runner is not None:
                comp.runner.validate()
            if comp.input_generator is not None:
                comp.input_generator.validate()
            if comp.output_parser is not None:
                comp.output_parser.validate()
        except ComputationUnavailableError:
            return False
        return True

    can_get_property = function_alias('can_get_property',
                                      can_get_property_for_molecule)

    def has_property_for_molecule(self,
                                  molecule,
                                  property,
                                  details=None,
                                  verbose=False):
        comp = self._get_comp(molecule, property, details, False)
        if comp is None:
            return False
        return comp.has_property(property, details)

    has_property = function_alias('has_property',
                                  can_get_property_for_molecule)

    def get_computation_for_property(self, molecule, property, details=None):
        comp = self._get_comp(molecule, property, details, True)
        # Try to generate any errors that would cause can_get_property_for_molecule to fail...
        if comp.runner is not None:
            comp.runner.validate()
        if comp.input_generator is not None:
            comp.input_generator.validate()
        if comp.output_parser is not None:
            comp.output_parser.validate()
        # Return it, whether or not it has been run.
        return comp

    def get_property_for_molecule(self, molecule, property, details=None):
        comp = self.get_computation_for_property(molecule, property, details)
        # See if we already have the property...
        result = comp.get_property(property, details)
        if result is not None:
            return result
        else:
            # Now run the calculation
            comp.run()
            return comp.get_property(property, details)

    def add_computation(self, comp):
        self.computations.append(comp)

    ###################
    # Private Methods #
    ###################

    def _get_comp(self, molecule, property, details, generate):
        for comp in self.computations:
            # TODO offer both "is" and "==" (as well as "is_same_molecule") options
            if comp.molecule is molecule:
                for prop in comp.properties:
                    if MolecularProperty.is_same_property(prop, property):
                        if details is None or details.is_subset_of(
                                prop.details):
                            return comp
        # well, we couldn't find one.  Should we make one?
        if generate:
            if 'property' in self.computation_kwargs:
                prop = self.computation_kwargs['property']
                if not MolecularProperty.is_same_property(prop, property):
                    raise ComputationUnavailableError(
                        "property mismatch.  Can't generate computation"
                        " of property '{}'".format(
                            MolecularProperty.property_type_of(
                                property).__name__))
                # This will append the computation to the self.computations list automatically
                comp = Computation(molecule=molecule,
                                   result_getter=self,
                                   **self.computation_kwargs)
            else:
                # This will append the computation to the self.computations list automatically
                comp = Computation(molecule=molecule,
                                   property=property,
                                   result_getter=self,
                                   **self.computation_kwargs)
            return comp
        else:
            return None
예제 #11
0
        top='-',
        left='|',
        right='|',
        bottom='-',
        top_left='+',
        top_right=None,
        bottom_left=None,
        bottom_right=None
):
    if top_right is None: top_right = top_left
    if bottom_left is None: bottom_left = top_left
    if bottom_right is None: bottom_right = top_right
    rv = top_left + (top*(width-2)) + top_right + "\n"
    rv += left + "{{0:^{0}}}".format(width-2).format(text) + right + "\n"
    rv += bottom_left + (bottom*(width-2)) + bottom_right
    return rv

#####################
# Dependent Imports #
#####################

from grendel.util.exceptions import raises_error

###########
# Aliases #
###########

indent = function_alias('indent', indented)
shortstr = function_alias('shortstr', short_str)