-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Units in models and parsers #84
Comments
Unfortunately, as a general statement, Python doesn't have a good solution for units. Though, for our specific use case we may be able to find something that works. [1] https://traitlets.readthedocs.io/en/stable/api.html#callbacks-when-trait-attributes-change |
@tarekelgindy and I had a discussion on this subject this morning. The following is a possible solution we came up with: Change the models and add a For example, in X = Float(help="x coordinate of the wire", default=0, unit="m", unit_type="distance") In the readers, the attribute setting should be changed to: #The input gives a x coordinate of 10 feet. The user doesn't have to worry about conversion
api_wire.set("X", 10, "ft") The What are your thoughts on this @kdheepak? Do you think we could implement something like that? |
It might work well. Why do we need |
I'll also need to prototype this or see a prototype and experiment to see if it works as intended. |
We might need unit type to avoid stuffs like: api_wire.set("X",10,"kva") #KVA is not a valid unit for length There might be other ways to do that though... |
I'm trying to see what I can do with that but I have troubles getting the attributes' kwargs in the This is what I get when I print
I tried, with no success, modifying the Float class to store this information: class Float(T.Float, DiTToTraitType):
def __init__(self,**kwargs):
if "unit" in kwargs:
self.unit=kwargs["unit"]
super.__init__(self) Since I've never really worked with traitlets before, I'm not sure how to do this. Any idea? |
I'm able to do something like this: import traitlets as T
class Float(T.Float, T.TraitType):
def __init__(self, **kwargs):
if "unit" in kwargs:
self.unit=kwargs.pop("unit")
super().__init__(**kwargs)
class Test(T.HasTraits):
x = Float(unit="m")
t = Test(x=1)
print(t.x)
print(Test.x.unit) but I still need to think about this more before we commit to doing it this way. Specifically, the |
Thanks for having a look @kdheepak , I'll try again then. |
Here's a prototype of something that could work in DiTTo. import traitlets as T
import pint
UNIT_REGISTRY = pint.UnitRegistry()
class DiTToHasTraits(T.HasTraits):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._units_registry = UNIT_REGISTRY
self._units = {}
for name in self.trait_names():
trait = getattr(self.__class__, name)
self._units[name] = trait.metadata["units"]
class Line(DiTToHasTraits):
x = T.Float().tag(units="meter")
y = T.Float().tag(units="meter")
def compute_impedance_matrix(self, a, b, a_units=None, b_units=None):
if a_units is None:
a_units = self._units["x"] # Or some other default value
if b_units is None:
b_units = self._units["y"] # Or some other default value
unitized_a = ( x * getattr(self._units_registry, a_units) ).to(self._units_registry.meter) # convert to unit that will be used internally, in this case meter.
unitized_b = ( y * getattr(self._units_registry, b_units) ).to(self._units_registry.meter) # convert to unit that will be used internally, in this case meter.
print(unitized_a, unitized_b)
l = Line(x=1, y=1)
l.compute_impedance_matrix(x=1, y=1, y_units="centimeter") This prints out the following:
|
Steps to start integrating units:
To think
|
A few unit related problems I noticed:
Ex:
Ex:
These are already introducing some bugs in the conversions and it will probably get worse as we add more parsers...
Having a more robust framework to handle units (like Pint maybe??) would be a nice addition in my opinion. Thoughts?
The text was updated successfully, but these errors were encountered: