This Scientific Library for Kaluga contains methods for converting values to and from different scientific units.
Installing
This library is available on Maven Central. You can import Kaluga Scientific as follows:
repositories {
// ...
mavenCentral()
}
// ...
dependencies {
// ...
implementation("com.splendo.kaluga:scientific:$kalugaVersion")
}
Add scientific-converters module to support converting between units.
Usage
Check out the full documentation
Scientific Unit
This library contains a ScientificUnit sealed class that describes units according to a PhysicalQuantity and MeasurementSystem. Units can convert Number or Decimal values to a value of another unit with the same PhysicalQuantity:
val meterInFoot = Meter.convert(10, Foot)
There are 59 PhysicalQuantities supported by this library. Each has a equally named sealed class that contains units that measure the given quantity. Depending on the quantity, this may be further split into sealed classes that contain only units used in a MeasurementSystem (e.g. Metric, USCustomary).
See PhysicalQuantity.kt for a list of all supported quantities. This library supports all seven base quantities as well as a large set of derived quantities.
Not all units are named. Some can be derived from using other units using either the x or per operator, depending on whether the unit is derived by multiplying or dividing other units (and has no named alternatives):
val speed = Meter per Second
val momentum = Kilogram x speed
If a unit is not related to a Defined PhysicalQuantity it will become a Custom Scientific Unit.
Serialization
If a Unit has a PhysicalQuantity.Defined it will be automatically serializable. However, when Custom Scientific units are to be serialized, the scientificSerializationModule should be added to your Serialization modules.
Scientific Value
The ScientificValue interface can be used to mark a Number as a value of a ScientificUnit. A DefaultScientificValue can be easily created using its invoke operator: 10(Meter). Alternatively, create a custom ScientificValue implementation and pass a construction function in the invoke method.
value class HeartRateValue(override val value: Double) : ScientificValue<PhysicalQuantity.Frequency, BeatsPerMinute> {
constructor(value: Decimal, unit: ScientificUnit<PhysicalQuantity.Frequency>) : this(unit.convert(value, BeatsPerMinute).toDouble())
override val unit: BeatsPerMinute
get() = BeatsPerMinute
}
val defaultBPM = 10(BeatsPerMinute) // Returns DefaultScientificValue<PhysiscalQuantity.Frequency, BeatsPerMinute>
val heartRate = 60(BeatsPerMinute. ::HeartRateValue) // Returns a HeartRateValue
Convert a ScientificValue to another value of the same PhysicalQuantity using convert
val foot = 5(Meter).convert(Foot)
val convertedHeartRateValue = 60(Hertz).convert(BeatsPerMinute, ::HeartRateValue)
Calculations
ScientificValue objects can be modified with numbers or other ScientificValue objects. All values have a plus, minus, times, and div function. By default this results in a new DefaultScientificUnit but this behaviour can be overloaded using custom parameters.
Scientific Array
The ScientificArray allows to mark a list of Numbers as values of a ScientificUnit. A DefaultScientificArray can be easily created using listOf(1, 2, 3)(Meter). Alternatively, create a custom ScientificArray implementation and pass a construction function in the invoke method. Since ScientificArray expects all values to be of the same number type, convenience interfaces are created: DoubleScientificArray, IntScientificArray, FloatScientificArray, LongScientificArray, ShortScientificArray, and ByteScientificArray.
value class HeartRateArray(override val values: DoubleArray) : DoubleScientificArray<PhysicalQuantity.Frequency, BeatsPerMinute> {
constructor(values: List<Decimal>, unit: ScientificUnit<PhysicalQuantity.Frequency>) : this(values.map { unit.convert(it, BeatsPerMinute) }.toDoubleArray())
override val unit: BeatsPerMinute
get() = BeatsPerMinute
}
val defaultBPMArray = listOf(50, 60, 80)(BeatsPerMinute)
val heartRateArray = listOf(40, 60, 80)(BeatsPerMinute, ::HeartRateArray)
A list of ScientificValue of the same PhysicalQuantity can also be merged using the toScientificArray() method.
val defaultBPMArray = listOf(50(BeatsPerMinute), 60(BeatsPerMinute), 80(BeatsPerMinute)).toScientificArray(BeatsPerMinute)
val heartRateArray = listOf(40(BeatsPerMinute), 60(BeatsPerMinute), 80(BeatsPerMinute)).toScientificArray(BeatsPerMinute, ::HeartRateArray)
Map, Combine, Concat, and Split
ScientificArray can be modied using some methods:
-
maptakes all values, converts them to aScientificUnitand transforms these using a transformation method, returning a ScientificArray of all resulting units.val interval = listOf(1, 1.5, 0.9)(Second) val defaultBPMArray = interval.map { convert(Minute).frequency() } val heartRateArray = interval.map(::HeartRateArray) { convert(Minute).frequency() } -
combinetakes two ScientificArrays of equal size and combines each value into a new ScientificArrayval combinedDefaultBPMArray = defaultBPMArray.combine(listOf(10, 40, 50)(Second)) { times(it.frequency()) } val combinedHeartRateArray = heartRateArray.combine(listOf(10, 40, 50)(Second), ::HeartRateArray) { times(it.frequency()) } -
concatcreates a new ScientificArray out of two ScientificArray of the samePhysiscalQuantity.val defaultBPMArray = listOf(50, 60, 80)(BeatsPerMinute) + listOf(4, 5, 6)(Hertz) val heartRateArray = listOf(40, 60, 80)(BeatsPerMinute, ::HeartRateArray).concat(listOf(4, 5, 6)(Hertz), BeatsPerMinute, ::HeartRateArray) -
splitsplits a ScientificArray intoScientificUnitfor each value.val listOfDefaultBPM = bpmArray.split() val listOfHeartRate = heartRateArray.split(::HeartRateValue)