Migrating from JScience quantities to Unit API 2.0

If you’re developing software that operates a lot with physical quantities you absolutely should use a library that defines types for quantities and supports safe conversions between units of measurements. Our go-to library for this in Java was JScience. The latest version of JScience is 4.3.1, which was released in 2012.

Since then a group of developers has formed that strives towards the standardization of a units API for Java. JScience maintainer Jean-Marie Dautelle is actively involved in this effort. The group operates under the name Units of Measurement alongside with their GitHub presence unitsofmeasurement.

Over the years there have been several JSRs (Java Specification Requests) by the group:

The current state of affairs is JSR-385, which is the basis of this post. The Units of Measurement API 2.0, or Unit API 2.0 for short, was released in July 2019.

JARs

While JScience is distributed as one JAR (~600 KiB), a setup of Unit API involves three JARs (~300 KiB in total):

  • unit-api-2.0.jar
  • indriya-2.0.jar
  • uom-lib-common-2.0.jar

JScience offers a lot more functionality than just quantities and units, but that’s the part we have been using and what we are interested in.

The unit-api JAR only defines interfaces, which is the scope of JSR-385. So you need an implementation to do anything useful with it. The reference implementation is called Indriya, provided by the second JAR. The third JAR, uom-lib-common, is a utility library used by Indriya for common functionality shared with other projects under the Units of Measurement umbrella.

Using quantities

Here’s a simple use of a physical quantity with JScience, in this example Length:

import org.jscience.physics.amount.Amount;

import javax.measure.quantity.Length;

import static javax.measure.unit.SI.*;

// ...

final Amount<Length> d = Amount.valueOf(214, CENTI(METRE));
final double d_metre = d.doubleValue(METRE);

And here’s the equivalent code using Units API 2.0 and Indriya:

import tech.units.indriya.quantity.Quantities;

import javax.measure.Quantity;
import javax.measure.quantity.Length;

import static javax.measure.MetricPrefix.CENTI;
import static tech.units.indriya.unit.Units.METRE;

// ...

final Quantity<Length> d = Quantities.getQuantity(214, CENTI(METRE));
final double d_metre = d.to(METRE).getValue().doubleValue();

Consistency

While JScience also defines aliases with alternative spellings like METER and constants for many prefixed units like CENTIMETER or MILLIMETER, Indriya encourages consistency and only allows METRE, CENTI(METRE), MILLI(METRE).

Quantity names

Most quantities have the same names in both projects, but there are some differences:

  • Amount<Duration> becomes Quantity<Time>
  • Amount<Velocity> becomes Quantity<Speed>

In these cases Unit API uses the correct SI names, i.e. time and speed. Wikipedia explains the difference between speed and velocity.

Arithmetic operations

The method names for the elementary arithmetic operations have changed:

  • plus() becomes add()
  • minus() becomes subtract()
  • times() becomes multiply()

Only the method name for division is the same:

  • divide() is still divide()

However, the runtime exceptions thrown on division by zero are different:

  • JScience: java.lang.ArithmeticException: / by zero
  • Indriya: java.lang.IllegalArgumentException: cannot initalize a rational number with divisor equal to ZERO

Type hints

If you divide or multiply two quantities the Java type system needs a type hint, because it doesn’t know the resulting quantity. Here’s how this looks in JScience versus Unit API:

With JScience:

Amount<Area> a = Amount.valueOf(100, SQUARE_METRE);
Amount<Length> b = Amount.valueOf(10, METRE);
Amount<Length> c = a.divide(b)
                    .to(METRE);

With Unit API:

Quantity<Area> a = Quantities.getQuantity(100, SQUARE_METRE);
Quantity<Length> b = Quantities.getQuantity(10, METRE);
Quantity<Length> c = a.divide(b)
                      .asType(Length.class);

Comparing quantities

If you want to compare quantities via compareTo(), isLessThan(), etc. you need quantities of type ComparableQuantity. The Quantities.getQuantity() factory method returns a ComparableQuantity, which is a sub-interface of Quantity.

Defining custom units

Defining custom units is very similar to JScience. Here’s an example for degree (angle), which is not an SI unit:

public static final Unit<Angle> DEGREE_ANGLE =
    new TransformedUnit<>("°", RADIAN,
        MultiplyConverter.ofPiExponent(1).concatenate(MultiplyConverter.ofRational(1, 180)));

Quantities in C++ and User Defined Literals

Some weeks ago one of my colleagues wrote about the use and implementation of physical quantities in C#. If you are writing an application in the technical or scientific domain chances are high that you should adhere to his advice and use a suitable representation of physical quantities instead of plain primitive values. Good news is that you can easily port/implement quantities to modern C++ or use existing libraries like Boost.Units.

With C++11 you can go one step further adding the so called User-defined literals. This feature allows definition of suffices for integer, floating-point, character and string literals to produce objects of the desired (quantity) type. While there is nothing wrong with using the multiplication operator to produce quantity instances user-defined literals provide just a little bit more syntactic sugar:

// Your quantity classes...
class Angle;

// operators for user-defined literals
constexpr Angle operator "" _deg(long double deg)
{
    return deg * degrees;
}

constexpr Angle operator "" _deg(unsigned long long int deg)
{
    return deg * degrees;
}

constexpr Angle operator "" _rad(long double rad)
{
    return (rad * 180 / M_PI) * degrees;
}

// add more if needed

This allows you to write code like:

Angle rightAngle = 90_deg;
Angle halfCircle = 3.141_rad;
Angle fullCircle = 4 * 90_deg;

In many cases this looks a tad simpler and cleaner than using the multiplication operator in conjunction with a unit especially in more complex formulas. There are a few things about quantities and user-defined literals in C++ I find noteworthy:

  • These literals are only supported for the built-in literal types. If exact calculation and better than floating-point precision is needed, raw literals (instead of the explained cooked) and decimal libraries have to be used. For raw literals you have to parse the characters of the literal yourself.
  • User-defined literals need to be prefixed with _ to avoid namespace clashes with current and future standard library literals. There are for example some nice literals for durations in the <chrono>-date and time standard library.
  • If you implement your literal operators as constexpr they will be evaluated at compile time meaning slightly increased compile times and zero runtime overhead.

For some more in-depth discussion of user-defined literals have a look at the blog series from Andrzej Krzemieński.

 

Physical Quantities in C#

Scientific applications usually perform lots of calculations with physical quantities. If you do not represent them properly in your code you run the risk of mixing them up. For example, it’s easy to add a value in meters to a value in kilometers if you simply work with variables of primitive types like double or decimal. It can help to encode the unit in the variable name, e.g. massInKilogram, but it’s much better to let the type system handle it.

So here’s some C# code which models a generic physical quantity and its unit:

public abstract class Quantity<T> where T : Quantity<T>, new()
{
    private decimal value;

    public decimal In(Unit<T> unit)
    {
        return value / unit.Factor;
    }

    public string ToStringIn(Unit<T> unit)
    {
        return string.Format("{0} {1}", In(unit), unit.Text);
    }

    public class Unit<Q> where Q : Quantity<Q>, new()
    {
        public decimal Factor { get; private set; }
        public string Text { get; private set; }

        public Unit(string representation, decimal factor)
        {
            Text = representation;
            Factor = factor;
        }

        public static Q operator *(decimal value, Unit<Q> unit)
        {
            var quantity = new Q();
            quantity.value = value * unit.Factor;
            return quantity;
        }
    }
}

With this base class we can easily implement some quantities:

class Duration : Quantity<Duration>
{
    public static readonly Unit<Duration> Millisecond = new Unit<Duration>("ms", 1e-3M);
    public static readonly Unit<Duration> Second = new Unit<Duration>("s", 1M);
    public static readonly Unit<Duration> Minute = new Unit<Duration>("min", 60M);
}

class Mass : Quantity<Mass>
{
    public static readonly Unit<Mass> Milligram = new Unit<Mass>("mg", 1e-3M);
    public static readonly Unit<Mass> Gram = new Unit<Mass>("g", 1M);
    public static readonly Unit<Mass> Kilogram = new Unit<Mass>("kg", 1e+3M);
}

And this is how they are used:

var t = 30 * Duration.Second;
Console.WriteLine(t.ToStringIn(Duration.Minute));
Console.WriteLine(t.ToStringIn(Duration.Second));
Console.WriteLine(t.ToStringIn(Duration.Millisecond));

var m = 10 * Mass.Gram;
Console.WriteLine(m.ToStringIn(Mass.Milligram));
Console.WriteLine(m.ToStringIn(Mass.Gram));
Console.WriteLine(m.ToStringIn(Mass.Kilogram));

The Unit class uses operator overloading to overload the multiplication operator. Instead of calling a constructor directly we use multiplication with a unit to create new instances of a quantity.

The type system prevents nonsense like this:

// does not compile
(10 * Mass.Gram).In(Duration.Minute);

You will probably want to overload more operators of the quantity classes depending on your use case. You can also overload operators to produce instances of new quantities:

Velocity v = (3.5 * Length.Kilometer) / (10 * Duration.Minute);

class Velocity : Quantity
{
    public static readonly Unit MeterPerSecond = new Unit("m/s", 1M);
}

class Length : Quantity
{
    public static readonly Unit Meter = new Unit("m", 1M);
    public static readonly Unit Kilometer = new Unit("m", 1e+3M);

    public static Velocity operator /(Length s, Duration t)
    {
        return (s.In(Length.Meter) / t.In(Duration.Second)) * Velocity.MeterPerSecond;
    }
}

If you do not want to hand craft your quantities you might want to check out existing libraries for working with quantities like QuantityTypes.