angularsen / UnitsNet

Makes life working with units of measurement just a little bit better.
https://www.nuget.org/packages/UnitsNet/
MIT No Attribution
2.67k stars 382 forks source link

Complex Units #592

Closed SGStino closed 5 years ago

SGStino commented 5 years ago

I'm searching for something that can handle slightly more complex units like representing avogadro's number [J/(mol K)] etc.

This would mean that these compound units aren't strongly typed anymore so i'm not sure if this is the goal of this library?

tmilnthorp commented 5 years ago

Take a look at my PR, #593. I am not sure if this is enough, but it's hopefully a start!

SGStino commented 5 years ago

Hey, certainly a usefull addition, but wasn't entirely what i meant. Shouldn't have used a fixed constant as an example.

I mean something like combining some units in a formula resulting in a more complex intermediate.

MolarEnergy.FromJoulesPerMole(1) / Temperature.FromKelvins(1) would result in the same unit as Avogadro's number, but doesn't look like its feasible at the moment.

Or another one: [J/(kg K)] pecificEnergy.FromKilowattHoursPerKilogram(1) / Temperature.FromKelvins(1)

So writing formulas would usually boil back to taking the SI unit from the quantity object, running the formula, and trying to create a new unit quantity from the result.

Storing intermediates would be in the old way without typing, strongly or not.

Take for example a classic: Q = m.c. ΔT Q would be representable as EnergyUnit m as MassUnit ΔT as TemperatureDeltaUnit but specifying c would have to be in the SI unit, as it can't be represented (yet)? While there are many different options here: some specify it as [kJ/(kg K)], some as [Kcal/(kg °C)], certain people would even use [btu/(lb°F)] ..

SGStino commented 5 years ago

I've investigated how math.js solves this for example, and it seems upon first glance that they have baseunits: Mass, Length, Volume, Temperature, ...

And compounds like speed are basically an array with the base/primitive unit and the power.

For speed this would be [(unit: LengthUnit.Meters, power:1), (unit: TimeUnit.Seconds, power:-1)]

Comparing if it's the same unit would ofc be only possible at runtime, but would come down to a check of the units and the powers.

I wonder if this could be an approach for v5 perhaps? (or it's already in and I just completly overlooked it?) EDIT: I wonder if Units.NET could take the ValueTuple approach:

ICompoundUnit<U1,U2>
ICompoundUnit<U1,U2,U3>
ICompoundUnit<U1,U2,U3,U4>
….
ICompoundUnit<U1,U2,U3,U4,U6,U7,U8, URest>

Although i'm not sure how URest should work with the following, I guess once you get that far it should become just IDynamicUnit or something, and no more compile-time checking from there on.

for example: IMassFlowUnit : ICompoundUnit<IMassUnit,IInverseUnit<ITimeUnit>>

This could really simplify the library and adding extra units could be done through inheritance? Operators overloads on interfaces could become possible in c#8 or higher so we can specify the arithmic purely on the interfaces. https://github.com/dotnet/csharplang/issues/192 https://github.com/dotnet/csharplang/issues/515

With the added language features it could come down to copying the dynamic approach of math.js to a more static language as c# 9 or 10.

I'm not sure how many operator overloads that would generate though, since ICompoundUnit<IMassUnit, IInvertedUnit<IMassUnit>> should just revert to IUnitless?

There are certainly tons of things I haven't thought about, this is just an idea I had and thought to share :smiley:

angularsen commented 5 years ago

Cool stuff, but also heavy to digest late in the evening :-)

We do have BaseDimensions on all our quantities, so we can possibly do something similar to Math.js, but without the static typing as you observed.

I think maybe we can get some static typing out of it though, please look at my comment here. We seem to be onto the same idea: https://github.com/angularsen/UnitsNet/issues/515#issuecomment-450319160

angularsen commented 5 years ago

Closing this in favor of #515, just to keep discussion in a single place.