Metadata-Version: 2.1
Name: siquant
Version: 2.1.0.dev1
Summary: SI units and quantities library
Home-page: https://github.com/keystonetowersystems/siquant
Author: Greg Echelberger
Author-email: greg@keystonetowersystems.com
License: UNKNOWN
Description: # siquant
        
        A library to provide dimensional and quantitative analysis within the SI units system.
        
        # Description
        
        This library provides a reasonably efficient set of tools to easily track units through abitrary calculations. All types
        are designed to be immutable, and as such can be shared relatively freely.
        
        There are two primary data types:
        * SIUnit - provide some scaling factor of a specific dimensionality of the 7 fundamental SI units.
        * ScalarQuantity - support arithmetic of a quantity of units
        
        Some predefined units are provided in modules in the siquant.systems package.
        
        # Getting Started
        
        ```python
        >>>from siquant.systems import si
        >>>force = 100 * si.kilonewtons
        >>>moment_arm = 50 * si.meters
        >>>torque = force * moment_arm
        >>>torque.get()
        5000
        >>>str(torque.units)
        '1000*kg**1*m**2*s**-2'
        >>>torque.get_as(si.newtons * si.meters)
        5000000.0
        >>>torque.get_as(si.newtons)
        Traceback (most recent call last):
          File "<input>", line 1, in <module>
          File "/siquant/siquant/quantities.py", line 19, in get_as
              assert(self._units.compatible(units))
        AssertionError
        >>>torque = torque.normalized()
        >>>torget.get()
        5000000.0
        >>>str(torque.units)
        '1*kg**1*m**2*s**-2'
        ```
        
        # Defining New Units
        
        New unit types can be created:
        * implicitly derived through combination of existing units.
        * explicitly via the Unit.Unit() factory method.
        
        ## Derived Units  
        
        ```python
        from siquant.systems import si
        pounds = si.kilograms * si.SIUnit.Unit(0.445)
        inches = si.millimeters * si.SIUnit.Unit(25.4)
        ksi = si.kilo * pounds / inches ** 2
        ```
        
        ## Explicit Units
        
        ```python
        from siquant.systems import si
        from siquant.units import SIUnit
        wonky_pi_unit = SIUnit.Unit(3.14, m=1)
        circle = 100 * wonky_pi_unit
        diameter = circle.get()
        circumeference = circle.get_as(si.meters)
        ``` 
        
        # Converters: Quantities at the DMZ
        
        The Quantity type provides a class method ``As(units: Unit)`` which returns a converter function which can be used to 
        normalize an argument in specific units, raise an error if their dimensionality does not match, and promote a raw
        value to a quantity with the expected units.
        
        ```python
        distance_t = ScalarQuantity.As(si.millimeters)
        def area(value):
            return distance_t(value) ** 2
            
        >>>str(area(10.0))
        '100.0 1e-6*m**2'
        >>>str(area(10 * si.millimeters))
        '100.0 1e-6*m**2'
        >>>str(area(10 * si.meters))
        '100000000.0 1e-06*m**2'
        >>>str(area(10 * si.kilograms))
        ...
        AssertionError
        ```
        
        ## Integration with attrs
        
        These converters integrate readily with the attrs library to reduce boilerplate while gaining the benefits of unit
        tracking and validation.
        
        ```python
        import attr
        
        from siquant.quantities import ScalarQuantity
        from siquant.systems import si 
        
        @attr.s
        class IsotropicMaterial:
            elastic_modulus = attr.ib(converter=ScalarQuantity.As(si.gigapascals))
            shear_modulus = attr.ib(converter=ScalarQuantity.As(si.gigapascals))
            poissons_ratio = attr.ib(converter=ScalarQuantity.As(si.unity))
        ```
        
        # Supporting Vector Quantities
        
        There are a number of vector libraries available, all with different interfaces. As such, a ```VectorQuantity``` is not 
        provided. However, integration of existing vector libraries should be possible with relative ease.
        
        ## Provide a VectorQuantity interface:
        
        ```python
        import numbers
        from siquant.quantities import Quantity, ScalarQuantity
        
        class VectorQuantity(Quantity):
            
            def cross(self, other):
                if not isinstance(other, VectorQuantity):
                    raise TypeError()
                return VectorQuantity(self.quantity.cross(other.quantity), self.units * other.units)
                
            def dot(self, other):
                if not isinstance(other, VectorQuantity):
                    raise TypeError()
                return ScalarQuantity(self.quantity.dot(other.quantity), self.units * other.units)
                
            def __mul__(self, other):
                if isinstance(other, numbers.Real):
                    return VectorQuantity(self.quantity * other, self.units)
                if isinstance(other, ScalarQuantity):
                    return VectorQuantity(self.quantity * other.quantity, self.units * other.units)
                if isinstance(other, VectorQuantity):
                    return self.dot(other)
                return NotImplemented
                
            def __rmul__(self, other):
                # Real, ScalarQuantity
                ...
                
            # etc ...
            
        force_vector = VectorQuantity(my_vector, si.newtons)
        ```
        
        ## Provide a hook for SIUnit (optional)
        
        The arithmetic methods of ```SIUnit``` only support operands of type ```numbers.Real``` and ```SIUnit```. In all other
        cases NotImplemented is returned. The interpretter will then attempt to delegate that operation to the other operand 
        type.
        
        In order to support the behavior ```Vector * SIUnit -> VectorQuantity``` the special methods ```__mul__``` and 
        ```__rmul__``` should be augmented. The exact implementation will depend heavily upon the library being integrated, 
        in order to make sure that the new child type is always propagated correctly.
        
        ### Composition
        
        ```python
        from siquant.units import SIUnit
        from your.vec.lib import Vector
        
        class VectorWrapper:
            
            @classmethod
            def Make(cls, *args, **kwargs):
                return cls(Vector(*args, **kwargs))
        
            def __init__(self, vector):
                self._vector = vector
        
            def unwrap(self):
                return self._vector
        
            def __mul__(self, other):
                if isinstance(other, SIUnit):
                    return VectorQuantity(self, other)
                return VectorWrapper(self._vector * other)
                
            def __rmul__(self, other):
                if isinstance(other, SIUnit):
                    return VectorQuantity(self, other)
                return VectorWrapper(other * self._vector)
                
            # any other operations to support
        ```
        
        ### Inheritance
        
        ```python
        from siquant.units import SIUnit
        from your.vec.lib import Vector
        
        class QVector(Vector):
            
            def __mul__(self, other):
                if isinstance(other, SIUnit):
                    return VectorQuantity(self, other)
                return super().__mul__(other)
                
            __rmul__ = __imul__ = __mul__
        ```
        ### Including siquant as a dependency
        
        This is probably the simplest, and the least practical. 
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: License :: OSI Approved :: MIT License
Classifier: Topic :: Scientific/Engineering
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Requires-Python: >=2.7
Description-Content-Type: text/markdown
