Source code for openmdao.main.datatypes.float

"""
Trait for floating point variables, with optional min, max, and units.
"""

#public symbols
__all__ = ["Float"]


from sys import float_info

# pylint: disable-msg=E0611,F0401
from traits.api import Range
from traits.api import Float as TraitFloat
from openmdao.units import PhysicalQuantity

from openmdao.main.variable import Variable
from openmdao.main.attrwrapper import AttrWrapper, UnitsAttrWrapper

from openmdao.main.uncertain_distributions import UncertainDistribution

[docs]class Float(Variable): """A Variable wrapper for floating point number valid within a specified range of values. """ def __init__(self, default_value=None, iotype=None, desc=None, low=None, high=None, exclude_low=False, exclude_high=False, units=None, **metadata): # Determine defalt_value if unspecified if default_value is None: if low is None and high is None: default_value = 0.0 elif low is None: default_value = high else: default_value = low else: if not isinstance(default_value, float): if isinstance(default_value, int): default_value = float(default_value) else: raise ValueError("Default value should be a float.") # excludes must be saved locally because we override error() self.exclude_low = exclude_low self.exclude_high = exclude_high # Put iotype in the metadata dictionary if iotype is not None: metadata['iotype'] = iotype # Put desc in the metadata dictionary if desc is not None: metadata['desc'] = desc # Put units in the metadata dictionary if units is not None: metadata['units'] = units # The Range trait must be used if High or Low is set if low is None and high is None: self._validator = TraitFloat(default_value, **metadata) else: if low is None: low = -float_info.max else: low = float(low) if high is None: high = float_info.max else: high = float(high) if low > high: raise ValueError("Lower bound is greater than upper bound.") if default_value > high or default_value < low: raise ValueError("Default value is outside of bounds [%s, %s]." % (str(low), str(high))) # Range can be float or int, so we need to force these to be float. default_value = float(default_value) self._validator = Range(low=low, high=high, value=default_value, exclude_low=exclude_low, exclude_high=exclude_high, **metadata) # If there are units, test them by creating a physical quantity if 'units' in metadata: try: pq = PhysicalQuantity(0., metadata['units']) except: raise ValueError("Units of '%s' are invalid" % metadata['units']) # Add low and high to the trait's dictionary so they can be accessed metadata['low'] = low metadata['high'] = high super(Float, self).__init__(default_value=default_value, **metadata)
[docs] def validate(self, obj, name, value): """ Validates that a specified value is valid for this trait. Units are converted as needed. """ # pylint: disable-msg=E1101 # If both source and target have units, we need to process differently if isinstance(value, AttrWrapper): if self.units: valunits = value.metadata.get('units') if valunits and isinstance(valunits, basestring) and \ self.units != valunits: return self._validate_with_metadata(obj, name, value.value, valunits) value = value.value elif isinstance(value, UncertainDistribution): value = value.getvalue() try: return self._validator.validate(obj, name, value) except Exception: self.error(obj, name, value)
[docs] def error(self, obj, name, value): """Returns a descriptive error string.""" # pylint: disable-msg=E1101 if self.low is None and self.high is None: if self.units: info = "a float having units compatible with '%s'" % self.units else: info = "a float" elif self.low is not None and self.high is not None: right = ']' left = '[' if self.exclude_high is True: right = ')' if self.exclude_low is True: left = '(' info = "a float in the range %s%s, %s%s"% \ (left,self.low,self.high,right) elif self.low is not None: info = "a float with a value > %s"% self.low else: # self.high is not None info = "a float with a value < %s"% self.high vtype = type( value ) msg = "Variable '%s' must be %s, but a value of %s %s was specified." % \ (name, info, value, vtype) try: obj.raise_exception(msg, ValueError) except AttributeError: raise ValueError(msg)
[docs] def get_val_wrapper(self, value, index=None): """Return a UnitsAttrWrapper object. Its value attribute will be filled in by the caller. """ if index is not None: raise ValueError("Float does not support indexing") # pylint: disable-msg=E1101 if self.units is None: return value return UnitsAttrWrapper(value, units=self.units)
def _validate_with_metadata(self, obj, name, value, src_units): """Perform validation and unit conversion using metadata from the source trait. """ # pylint: disable-msg=E1101 dst_units = self.units if isinstance(value, UncertainDistribution): value = value.getvalue() # FIXME: The try blocks testing whether the unit is bogus or undefined # are generally redundant because that test is done at creation. HOWEVER # you might have a case where it wasn't tested because it's technically # not a float. NPSS wrapper may be such a case. A test needs to be # constructed to test these lines. # Note: benchmarking showed that this check does speed things up -- KTM if src_units == dst_units: try: return self._validator.validate(obj, name, value) except Exception: self.error(obj, name, value) try: pq = PhysicalQuantity(value, src_units) except NameError: raise NameError("while setting value of %s: undefined unit '%s'" % (src_units, name)) try: pq.convert_to_unit(dst_units) except NameError: raise NameError("undefined unit '%s' for variable '%s'" % (dst_units, name)) except TypeError: msg = "%s: units '%s' are incompatible " % (name, src_units) + \ "with assigning units of '%s'" % (dst_units) raise TypeError(msg) try: return self._validator.validate(obj, name, pq.value) except Exception: self.error(obj, name, pq.value)
[docs] def get_attribute(self, name, value, trait, meta): """Return the attribute dictionary for this variable. This dict is used by the GUI to populate the edit UI. The basic functionality that most variables need is provided here; you can overload this for special cases, like lists and dictionaries, or custom datatypes. name: str Name of variable value: object The value of the variable trait: CTrait The variable's trait meta: dict Dictionary of metadata for this variable """ attr, other = super(Float, self).get_attribute(name, value, trait, meta) # Fix type 'synonym'. if attr['type'] == 'float64': attr['type'] = 'float' attr['value'] = float(value) return attr, other
OpenMDAO Home