Skip to content

Commit

Permalink
Add voltage and current units
Browse files Browse the repository at this point in the history
Signed-off-by: Geert Mulders <[email protected]>
  • Loading branch information
gmulders committed Oct 22, 2024
1 parent 2734c78 commit c4e13b6
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 40 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,4 @@ Please read [SUPPORT](SUPPORT.md) for how to connect and get into contact with t
[github:create-from-template]: https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/creating-a-repository-from-a-template
[kotlin]: https://kotlinlang.org/
[gradle]: https://gradle.org/

2 changes: 1 addition & 1 deletion measure/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ plugins {
`java-library`

// Apply dokka plugin to allow extraction of ducumentation from KDoc comments
id("org.jetbrains.dokka") version "1.4.20"
id("org.jetbrains.dokka") version "1.9.20"

// Make sure we can publish to maven
`maven-publish`
Expand Down
12 changes: 10 additions & 2 deletions measure/src/main/kotlin/com/alliander/open/measure/Measure.kt
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,16 @@ data class Measure<U : Units>(val amount: BigDecimal, val units: U) : Comparable
val absoluteFactor = (factor `in` base).abs()
return dividend.roundToMultiple(absoluteFactor, roundingMode) * base
}

}

private fun BigDecimal.roundToMultiple(factor: BigDecimal, roundingMode: RoundingMode): BigDecimal =
this.divide(factor, 0, roundingMode) * factor
this.divide(factor, 0, roundingMode) * factor

operator fun <U : Units> BigDecimal.times(m: Measure<U>): Measure<U> =
Measure(amount = m.amount.times(this), units = m.units)

operator fun <U : Units> Int.times(m: Measure<U>): Measure<U> =
BigDecimal.valueOf(this.toLong()) * m

operator fun <U : Units> Long.times(m: Measure<U>): Measure<U> =
BigDecimal.valueOf(this) * m
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,60 @@

package com.alliander.open.measure

import com.alliander.open.measure.Current.Companion.ampere
import com.alliander.open.measure.Energy.Companion.joule
import com.alliander.open.measure.Power.Companion.watt
import com.alliander.open.measure.Time.Companion.seconds
import com.alliander.open.measure.Voltage.Companion.volt
import java.math.BigDecimal

@JvmName("powerTimesTime")
operator fun Measure<Power>.times(duration: Measure<Time>): Measure<Energy> {
val p = this `as` watt
val dt = duration `as` seconds
val p = this `in` watt
val dt = duration `in` seconds
return Measure(p * dt, joule)
}

@JvmName("currentTimesVoltage")
operator fun Measure<Current>.times(voltage: Measure<Voltage>): Measure<Power> {
val i = this `in` ampere
val v = voltage `in` volt
return Measure(i * v, watt)
}

@JvmName("voltageTimesCurrent")
operator fun Measure<Voltage>.times(current: Measure<Current>): Measure<Power> {
val v = this `in` volt
val i = current `in` ampere
return Measure(i * v, watt)
}

@JvmName("powerDivVoltage")
operator fun Measure<Power>.div(voltage: Measure<Voltage>): Measure<Current> {
val p = this `in` watt
val v = voltage `in` volt
return Measure(p / v, ampere)
}

@JvmName("powerDivCurrent")
operator fun Measure<Power>.div(current: Measure<Current>): Measure<Voltage> {
val p = this `in` watt
val i = current `in` ampere
return Measure(p / i, volt)
}

class Voltage(suffix: String, ratio: BigDecimal = BigDecimal.ONE) : Units(suffix, ratio) {
companion object {
val volt = Voltage("V")
val kiloVolt = Voltage("kV", 1_000.toBigDecimal())
}
}

return Measure(p.amount * dt.amount, joule)
class Current(suffix: String, ratio: BigDecimal = BigDecimal.ONE) : Units(suffix, ratio) {
companion object {
val ampere = Current("A")
val kiloAmpere = Current("kA", 1_000.toBigDecimal())
}
}

class Power(suffix: String, ratio: BigDecimal = BigDecimal.ONE) : Units(suffix, ratio) {
Expand All @@ -30,7 +74,7 @@ class Energy(suffix: String, ratio: BigDecimal = BigDecimal.ONE) : Units(suffix,
val kiloJoule = Energy("kJ", 1_000.toBigDecimal())
val megaJoule = Energy("MJ", 1_000_000.toBigDecimal())
val kiloWattHour = Energy("kWh", 3_600_000.toBigDecimal())
val megaWattHour = Energy("mWh", 3_600_000_000.toBigDecimal())
val megaWattHour = Energy("MWh", 3_600_000_000.toBigDecimal())
}
}

Expand All @@ -41,4 +85,3 @@ class Time(suffix: String, ratio: BigDecimal = BigDecimal.ONE) : Units(suffix, r
val hours = Time("h", 3_600.toBigDecimal())
}
}

32 changes: 0 additions & 32 deletions measure/src/test/kotlin/com/alliander/open/measure/MeasureTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,21 @@ import com.alliander.open.measure.Energy.Companion.joule
import com.alliander.open.measure.Energy.Companion.kiloJoule
import com.alliander.open.measure.Energy.Companion.kiloWattHour
import com.alliander.open.measure.Energy.Companion.megaJoule
import com.alliander.open.measure.Energy.Companion.megaWattHour
import com.alliander.open.measure.Power.Companion.kiloWatt
import com.alliander.open.measure.Power.Companion.megaWatt
import com.alliander.open.measure.Power.Companion.watt
import com.alliander.open.measure.Time.Companion.hours
import com.alliander.open.measure.Time.Companion.minutes
import com.alliander.open.measure.Time.Companion.seconds
import com.alliander.open.measure.extension.sum
import io.kotest.core.spec.style.StringSpec
import io.kotest.data.headers
import io.kotest.data.row
import io.kotest.data.table
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.property.checkAll
import java.math.BigDecimal
import java.math.RoundingMode.UP

class MeasureTest : StringSpec({
"Joule, Watt and seconds are different units" {
joule shouldNotBe watt
joule shouldNotBe seconds

watt shouldNotBe joule
watt shouldNotBe seconds

seconds shouldNotBe joule
seconds shouldNotBe watt
}

"joules and kiloJoules can be added" {
val left = 1000 * joule
val right = 1 * kiloJoule
Expand All @@ -47,15 +32,6 @@ class MeasureTest : StringSpec({
sum shouldBe 2000 * joule
}

"power times time is energy" {
val power = 10 * kiloWatt
val duration = 15 * minutes

val energy = power * duration

energy `as` megaJoule shouldBe 9 * megaJoule
}

"joules can be added" {
checkAll { leftQuantity: Int, rightQuantity: Int ->
val left = leftQuantity * joule
Expand Down Expand Up @@ -123,14 +99,6 @@ class MeasureTest : StringSpec({
}
}

"energySum returns correct amount of energy when given a list of measures of energy" {
val list = listOf(100 * joule, 1 * megaWattHour, 1 * megaJoule)
val result = list.sum()

val expectedResult = 3601000100 * joule
result shouldBe expectedResult
}

"roundUpToNextMultiple processes different units correctly" {
io.kotest.data.forAll(
table(
Expand Down

0 comments on commit c4e13b6

Please sign in to comment.