-
Notifications
You must be signed in to change notification settings - Fork 1
Add voltage and current units #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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> = | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In some cases you want to multiply your measure with some dimensionless value. e.g. when calculating the effectiveness of an consumer equipment on the congested element
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wasnt this functionality already present in measure 1.3? From MeasureKt.class
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, what you are referring to is a multiplication with a Unit --> What this does is a multiplication with a Meaure: |
||
| 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 |
|---|---|---|
|
|
@@ -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> { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P = I V |
||
| 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> { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P = V I |
||
| 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> { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I = P / V |
||
| 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> { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. V = P / I |
||
| 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) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Voltage definition, I don't expect that we will use more then kiloVolts (our distribution grid is max 380kV) |
||
| 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) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Current definition, I don't expect that we will use more then kA, that already seems really high to me. |
||
| companion object { | ||
| val ampere = Current("A") | ||
| val kiloAmpere = Current("kA", 1_000.toBigDecimal()) | ||
| } | ||
| } | ||
|
|
||
| class Power(suffix: String, ratio: BigDecimal = BigDecimal.ONE) : Units(suffix, ratio) { | ||
|
|
@@ -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()) | ||
cflist marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
|
|
||
|
|
@@ -41,4 +85,3 @@ class Time(suffix: String, ratio: BigDecimal = BigDecimal.ONE) : Units(suffix, r | |
| val hours = Time("h", 3_600.toBigDecimal()) | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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" { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved this to a more elaborate test in the new test file: The units have the correct measure |
||
| 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 | ||
|
|
@@ -47,15 +32,6 @@ class MeasureTest : StringSpec({ | |
| sum shouldBe 2000 * joule | ||
| } | ||
|
|
||
| "power times time is energy" { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move to the new test file |
||
| 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 | ||
|
|
@@ -123,14 +99,6 @@ class MeasureTest : StringSpec({ | |
| } | ||
| } | ||
|
|
||
| "energySum returns correct amount of energy when given a list of measures of energy" { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was already covered by another test. |
||
| 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( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| // SPDX-FileCopyrightText: 2021-2022 Alliander N.V. | ||
| // | ||
| // SPDX-License-Identifier: MPL-2.0 | ||
|
|
||
| package com.alliander.open.measure | ||
|
|
||
| import com.alliander.open.measure.Current.Companion.ampere | ||
| import com.alliander.open.measure.Current.Companion.kiloAmpere | ||
| 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.Voltage.Companion.kiloVolt | ||
| import com.alliander.open.measure.Voltage.Companion.volt | ||
| import io.kotest.core.spec.style.StringSpec | ||
| import io.kotest.matchers.should | ||
| import io.kotest.matchers.shouldBe | ||
| import io.kotest.matchers.types.beInstanceOf | ||
|
|
||
| class SpecificUnitsTest : StringSpec({ | ||
| "The units have the correct measure" { | ||
| joule should beInstanceOf<Energy>() | ||
| kiloJoule should beInstanceOf<Energy>() | ||
| megaJoule should beInstanceOf<Energy>() | ||
| kiloWattHour should beInstanceOf<Energy>() | ||
| megaWattHour should beInstanceOf<Energy>() | ||
|
|
||
| watt should beInstanceOf<Power>() | ||
| kiloWatt should beInstanceOf<Power>() | ||
| megaWatt should beInstanceOf<Power>() | ||
|
|
||
| seconds should beInstanceOf<Time>() | ||
| minutes should beInstanceOf<Time>() | ||
| hours should beInstanceOf<Time>() | ||
|
|
||
| volt should beInstanceOf<Voltage>() | ||
| kiloVolt should beInstanceOf<Voltage>() | ||
|
|
||
| ampere should beInstanceOf<Current>() | ||
| kiloAmpere should beInstanceOf<Current>() | ||
| } | ||
|
|
||
| "power times time is energy" { | ||
| val power = 10 * kiloWatt | ||
| val duration = 15 * minutes | ||
|
|
||
| val energy = power * duration | ||
|
|
||
| energy `as` megaJoule shouldBe 9 * megaJoule | ||
| } | ||
|
|
||
| "current times voltage is power" { | ||
| val current = 10 * ampere | ||
| val voltage = 15 * volt | ||
|
|
||
| val power = current * voltage | ||
|
|
||
| power `as` watt shouldBe 150 * watt | ||
| } | ||
|
|
||
| "voltage times current is power" { | ||
| val current = 10 * ampere | ||
| val voltage = 15 * volt | ||
|
|
||
| val power = voltage * current | ||
|
|
||
| power `as` watt shouldBe 150 * watt | ||
| } | ||
|
|
||
| "power divided by voltage is current" { | ||
| val power = 150 * watt | ||
| val voltage = 15 * volt | ||
|
|
||
| val current = power / voltage | ||
|
|
||
| current `as` ampere shouldBe 10 * ampere | ||
| } | ||
|
|
||
| "power divided by current is voltage" { | ||
| val power = 150 * watt | ||
| val current = 10 * ampere | ||
|
|
||
| val voltage = power / current | ||
|
|
||
| voltage `as` volt shouldBe 15 * volt | ||
| } | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The build complained that this plugin could not be found.