unitsofmeasurement / seshat

Seshat Units of Measurement Implementation
Apache License 2.0
7 stars 3 forks source link

Simplification for new derived units that conflict with existing derived units ? #20

Open vidzilla opened 1 year ago

vidzilla commented 1 year ago

Hello !

Disclaimer before I describe the issue - I haven't looked too deeply into seshat/ units api just yet so I might be mistaken about a few things. Please do correct me if I am.

I'm working on a project that does a lot of mechanical engineering calculations and we've been looking into using seshat for unit implementation. I've noticed that the parent unit api library doesn't have the Torque unit - this is fairly easily implemented as a derived unit, but I'm also looking to see if this can be implemented in the simplification process.... which is where things get tricky.

The base units for Torque are the same as the unit for Energy (Newton.metre in SI) , the only difference being that Torque is derived from a vector cross product between a force and a length, while energy is the dot product of the same.

Ideally we would want to overload the multiply method(s) but it might get very hard to do so as there's no easy way (in my mind at least) to automatically provide context for the multiply methods. We also don't want to manually provide context (e.g. by providing a boolean flag as method argument) since we'll be using Torque a LOT, and it just gets tiresome having to constantly add context to a simple math operation.

Is there a good way to achieve what I'm after ? I have a feeling this won't just be an issue with Torque but could pop up with other derived units as well. I'm more than happy to work on this and provide a PR.

desruisseaux commented 1 year ago

Hello vidzilla, and welcome!

The first step is to allow the library to distinguish between torque and energy. This is the context information mentioned in your comment. A similar issue exists for dimensionless units, where scale, radians and salinity have the same (absence of) dimensions. In JSR-385 model, this is handled by different Quantity subtypes. For example Units.RADIAN has a specific quantity type, Angle, which distinguishes that unit from other dimensionless units.

So the first step is to create a new interface like below:

import javax.measure.Quantity;

/**
 * Capability of a force to produce change in the rotational motion of the body.
 */
public interface Torque extends Quantity<Torque> {
}

Then to create a new unit using that quantity. The code below uses "N_m" as a symbol instead of "N⋅m" because Seshat does not accept the use of "⋅" in an alternate symbol name (for avoiding confusion with arithmetic operators at parsing time).

public static final Unit<Torque> TORQUE = Units.JOULE.asType(Torque.class).alternate("N_m");

Above should work with current Seshat release. However we can do a little bit better by adding the constant directly in Units. Using internal mechanic not in public API allows us to e.g. bypass the restriction on "N⋅m" symbol. I just pushed a feat/torque experimental branch doing that.

Now that we can distinguish between Torque and Joule, the next step would be to determine what are the desired simplifications in arithmetic operations.

vidzilla commented 1 year ago

Brilliant ! Thanks @desruisseaux ! I'll give that experimental branch a try, but for my current purposes, your noted method of creating an alternate unit works really well !