diff --git a/shared/src/main/scala/squants/energy/Energy.scala b/shared/src/main/scala/squants/energy/Energy.scala index 0e58ced7..0181579e 100644 --- a/shared/src/main/scala/squants/energy/Energy.scala +++ b/shared/src/main/scala/squants/energy/Energy.scala @@ -45,7 +45,7 @@ final class Energy private (val value: Double, val unit: EnergyUnit) def /(that: Temperature): ThermalCapacity = JoulesPerKelvin(this.toJoules / that.toKelvinDegrees) def /(that: ThermalCapacity) = Kelvin(this.toJoules / that.toJoulesPerKelvin) - def /(that: ChemicalAmount) = ??? // return MolarEnergy + def /(that: ChemicalAmount): MolarEnergy = JoulesPerMole(this.toJoules / that.toMoles) def /(that: Angle): Torque = NewtonMeters(toJoules / that.toRadians) def /(that: Area) = ??? // Insolation, Energy Area Density diff --git a/shared/src/main/scala/squants/energy/MolarEnergy.scala b/shared/src/main/scala/squants/energy/MolarEnergy.scala new file mode 100644 index 00000000..ec499c4e --- /dev/null +++ b/shared/src/main/scala/squants/energy/MolarEnergy.scala @@ -0,0 +1,48 @@ +package squants.energy + +import squants.mass.{ChemicalAmount, Moles} +import squants.{AbstractQuantityNumeric, Dimension, PrimaryUnit, Quantity, SiUnit, UnitConverter, UnitOfMeasure} + +/** + * + * @author Nicolas Vinuesa + * @since 1.4 + * + * @param value Double + */ +final class MolarEnergy private (val value: Double, val unit: MolarEnergyUnit) + extends Quantity[MolarEnergy] { + + def dimension = MolarEnergy + + def *(that: ChemicalAmount): Energy = Joules(this.toJoulesPerMole * that.toMoles) + + def toJoulesPerMole = to(JoulesPerMole) +} + +object MolarEnergy extends Dimension[MolarEnergy] { + private[energy] def apply[A](n: A, unit: MolarEnergyUnit)(implicit num: Numeric[A]) = new MolarEnergy(num.toDouble(n), unit) + def apply = parse _ + def name = "MolarEnergy" + def primaryUnit = JoulesPerMole + def siUnit = JoulesPerMole + def units = Set(JoulesPerMole) +} + +trait MolarEnergyUnit extends UnitOfMeasure[MolarEnergy] with UnitConverter { + def apply[A](n: A)(implicit num: Numeric[A]) = MolarEnergy(n, this) +} + +object JoulesPerMole extends MolarEnergyUnit with PrimaryUnit with SiUnit { + val symbol = Joules.symbol + "/" + Moles.symbol +} + +object MolarEnergyConversions { + lazy val joulePerMole = JoulesPerMole(1) + + implicit class MolarEnergyConversions[A](n: A)(implicit num: Numeric[A]) { + def joulesPerMole = JoulesPerMole(n) + } + + implicit object MolarEnergyNumeric extends AbstractQuantityNumeric[MolarEnergy](MolarEnergy.primaryUnit) +} diff --git a/shared/src/main/scala/squants/experimental/unitgroups/ImplicitDimensions.scala b/shared/src/main/scala/squants/experimental/unitgroups/ImplicitDimensions.scala index 73785368..220149c2 100644 --- a/shared/src/main/scala/squants/experimental/unitgroups/ImplicitDimensions.scala +++ b/shared/src/main/scala/squants/experimental/unitgroups/ImplicitDimensions.scala @@ -39,6 +39,7 @@ object ImplicitDimensions { object energy { implicit val implicitEnergy: Dimension[Energy] = Energy implicit val implicitEnergyDensity: Dimension[EnergyDensity] = EnergyDensity + implicit val implicitMolarEnergy: Dimension[MolarEnergy] = MolarEnergy implicit val implicitPower: Dimension[Power] = Power implicit val implicitPowerRamp: Dimension[PowerRamp] = PowerRamp implicit val implicitSpecificEnergy: Dimension[SpecificEnergy] = SpecificEnergy diff --git a/shared/src/test/scala/squants/energy/EnergySpec.scala b/shared/src/test/scala/squants/energy/EnergySpec.scala index 4320b26f..7bd10d5e 100644 --- a/shared/src/test/scala/squants/energy/EnergySpec.scala +++ b/shared/src/test/scala/squants/energy/EnergySpec.scala @@ -8,14 +8,14 @@ package squants.energy -import org.scalatest.{ FlatSpec, Matchers } -import squants.electro.{ Coulombs, Volts } -import squants.mass.Kilograms -import squants.motion.{ MetersPerSecond, NewtonSeconds, Newtons } -import squants.space.{ CubicMeters, Meters } -import squants.thermal.{ JoulesPerKelvin, Kelvin } +import org.scalatest.{FlatSpec, Matchers} +import squants.electro.{Coulombs, Volts} +import squants.mass.{Kilograms, Moles} +import squants.motion.{MetersPerSecond, NewtonSeconds, Newtons} +import squants.space.{CubicMeters, Meters} +import squants.thermal.{JoulesPerKelvin, Kelvin} import squants.time.Hours -import squants.{ MetricSystem, QuantityParseException } +import squants.{MetricSystem, QuantityParseException} /** * @author garyKeorkunian @@ -147,6 +147,10 @@ class EnergySpec extends FlatSpec with Matchers { Joules(10) / Kelvin(2) should be(JoulesPerKelvin(5)) } + it should "return MolarEnergy when divided by ChemicalAmount" in { + Joules(10) / Moles(2) should be(JoulesPerMole(5)) + } + behavior of "KineticEnergyCalculations" it should "calculate Kinetic Energy from Mass and Velocity" in { diff --git a/shared/src/test/scala/squants/energy/MolarEnergySpec.scala b/shared/src/test/scala/squants/energy/MolarEnergySpec.scala new file mode 100644 index 00000000..e3a099d3 --- /dev/null +++ b/shared/src/test/scala/squants/energy/MolarEnergySpec.scala @@ -0,0 +1,60 @@ +package squants.energy + +import org.scalatest.{FlatSpec, Matchers} +import squants.QuantityParseException +import squants.mass.Moles + +/** + * @author Nicolas Vinuesa + * @since 1.4 + * + */ +class MolarEnergySpec extends FlatSpec with Matchers { + + behavior of "MolarEnergy and its Units of Measure" + + it should "create values using UOM factories" in { + JoulesPerMole(1).toJoulesPerMole should be(1) + } + + it should "create values from properly formatted Strings" in { + MolarEnergy("10.22 J/mol").get should be(JoulesPerMole(10.22)) + MolarEnergy("10.22 zz").failed.get should be(QuantityParseException("Unable to parse MolarEnergy", "10.22 zz")) + MolarEnergy("zz J/mol").failed.get should be(QuantityParseException("Unable to parse MolarEnergy", "zz J/mol")) + } + + it should "properly convert to all supported Units of Measure" in { + val x = JoulesPerMole(10) + x.toJoulesPerMole should be(10.0) + } + + it should "return properly formatted strings for all supported Units of Measure" in { + JoulesPerMole(1).toString(JoulesPerMole) should be("1.0 J/mol") + } + + it should "return Energy when multiplied by ChemicalAmount" in { + JoulesPerMole(1) * Moles(1) should be(Joules(1)) + } + + behavior of "MolarEnergyConversions" + + it should "provide aliases for single unit values" in { + import MolarEnergyConversions._ + + joulePerMole should be(JoulesPerMole(1)) + } + + it should "provide implicit conversion from Double" in { + import MolarEnergyConversions._ + + val d = 10.22 + d.joulesPerMole should be(JoulesPerMole(d)) + } + + it should "provide Numeric support" in { + import MolarEnergyConversions.MolarEnergyNumeric + + val rs = List(JoulesPerMole(100), JoulesPerMole(10)) + rs.sum should be(JoulesPerMole(110)) + } +}