use crate::physics::basic::{
Coef, Distance, Energy, EnergyType, Force, PhysicalQuantity, ElectricCharge, ElectricPotential,
time_delta_to_secs_f64,
};
use std::any::Any;
use std::ops::{Add, Div, Mul, Neg, Sub};
impl Default for Energy {
fn default() -> Self {
Self::from_joule(0.0)
}
}
impl PhysicalQuantity for Energy {
fn as_any(&self) -> &dyn Any {
self
}
fn is_zero(&self) -> bool {
self.v == 0.0
}
fn default_unit_value(&self) -> f64 {
self.as_joule()
}
fn set_value(&mut self, value: f64) {
self.v = value;
}
fn unit_display_name(&self) -> String {
"Energy (J)".to_string()
}
}
impl Energy {
pub fn from_joule(joule: f64) -> Self {
Self {
default_type: EnergyType::Joule,
v: joule,
}
}
pub fn from_mill_joule(mill_joule: f64) -> Self {
Self {
default_type: EnergyType::MillJoule,
v: mill_joule,
}
}
pub fn from_micro_joule(micro_joule: f64) -> Self {
Self {
default_type: EnergyType::MicroJoule,
v: micro_joule,
}
}
pub fn from_nano_joule(nano_joule: f64) -> Self {
Self {
default_type: EnergyType::NanoJoule,
v: nano_joule,
}
}
pub fn from_kilo_joule(kilo_joule: f64) -> Self {
Self {
default_type: EnergyType::KiloJoule,
v: kilo_joule,
}
}
pub fn from_mega_joule(mega_joule: f64) -> Self {
Self {
default_type: EnergyType::MegaJoule,
v: mega_joule,
}
}
pub fn from_electron_volt(electron_volt: f64) -> Self {
Self {
default_type: EnergyType::ElectronVolt,
v: electron_volt,
}
}
pub fn from_kilo_electron_volt(kilo_electron_volt: f64) -> Self {
Self {
default_type: EnergyType::KiloElectronVolt,
v: kilo_electron_volt,
}
}
pub fn from_mega_electron_volt(mega_electron_volt: f64) -> Self {
Self {
default_type: EnergyType::MegaElectronVolt,
v: mega_electron_volt,
}
}
pub fn as_joule(&self) -> f64 {
match self.default_type {
EnergyType::Joule => self.v,
EnergyType::MillJoule => self.v * 1e-3,
EnergyType::MicroJoule => self.v * 1e-6,
EnergyType::NanoJoule => self.v * 1e-9,
EnergyType::KiloJoule => self.v * 1e3,
EnergyType::MegaJoule => self.v * 1e6,
EnergyType::ElectronVolt => self.v * 1.602176634e-19,
EnergyType::KiloElectronVolt => self.v * 1.602176634e-16,
EnergyType::MegaElectronVolt => self.v * 1.602176634e-13,
}
}
pub fn as_mill_joule(&self) -> f64 {
match self.default_type {
EnergyType::Joule => self.v * 1e3,
EnergyType::MillJoule => self.v,
EnergyType::MicroJoule => self.v * 1e-3,
EnergyType::NanoJoule => self.v * 1e-6,
EnergyType::KiloJoule => self.v * 1e6,
EnergyType::MegaJoule => self.v * 1e9,
EnergyType::ElectronVolt => self.v * 1.602176634e-16,
EnergyType::KiloElectronVolt => self.v * 1.602176634e-13,
EnergyType::MegaElectronVolt => self.v * 1.602176634e-10,
}
}
pub fn as_micro_joule(&self) -> f64 {
match self.default_type {
EnergyType::Joule => self.v * 1e6,
EnergyType::MillJoule => self.v * 1e3,
EnergyType::MicroJoule => self.v,
EnergyType::NanoJoule => self.v * 1e-3,
EnergyType::KiloJoule => self.v * 1e9,
EnergyType::MegaJoule => self.v * 1e12,
EnergyType::ElectronVolt => self.v * 1.602176634e-13,
EnergyType::KiloElectronVolt => self.v * 1.602176634e-10,
EnergyType::MegaElectronVolt => self.v * 1.602176634e-7,
}
}
pub fn as_nano_joule(&self) -> f64 {
match self.default_type {
EnergyType::Joule => self.v * 1e9,
EnergyType::MillJoule => self.v * 1e6,
EnergyType::MicroJoule => self.v * 1e3,
EnergyType::NanoJoule => self.v,
EnergyType::KiloJoule => self.v * 1e12,
EnergyType::MegaJoule => self.v * 1e15,
EnergyType::ElectronVolt => self.v * 1.602176634e-10,
EnergyType::KiloElectronVolt => self.v * 1.602176634e-7,
EnergyType::MegaElectronVolt => self.v * 1.602176634e-4,
}
}
pub fn as_kilo_joule(&self) -> f64 {
match self.default_type {
EnergyType::Joule => self.v * 1e-3,
EnergyType::MillJoule => self.v * 1e-6,
EnergyType::MicroJoule => self.v * 1e-9,
EnergyType::NanoJoule => self.v * 1e-12,
EnergyType::KiloJoule => self.v,
EnergyType::MegaJoule => self.v * 1e3,
EnergyType::ElectronVolt => self.v * 1.602176634e-22,
EnergyType::KiloElectronVolt => self.v * 1.602176634e-19,
EnergyType::MegaElectronVolt => self.v * 1.602176634e-16,
}
}
pub fn as_mega_joule(&self) -> f64 {
match self.default_type {
EnergyType::Joule => self.v * 1e-6,
EnergyType::MillJoule => self.v * 1e-9,
EnergyType::MicroJoule => self.v * 1e-12,
EnergyType::NanoJoule => self.v * 1e-15,
EnergyType::KiloJoule => self.v * 1e-3,
EnergyType::MegaJoule => self.v,
EnergyType::ElectronVolt => self.v * 1.602176634e-25,
EnergyType::KiloElectronVolt => self.v * 1.602176634e-22,
EnergyType::MegaElectronVolt => self.v * 1.602176634e-19,
}
}
pub fn as_electron_volt(&self) -> f64 {
match self.default_type {
EnergyType::Joule => self.v / 1.602176634e-19,
EnergyType::MillJoule => self.v / 1.602176634e-16,
EnergyType::MicroJoule => self.v / 1.602176634e-13,
EnergyType::NanoJoule => self.v / 1.602176634e-10,
EnergyType::KiloJoule => self.v / 1.602176634e-22,
EnergyType::MegaJoule => self.v / 1.602176634e-25,
EnergyType::ElectronVolt => self.v,
EnergyType::KiloElectronVolt => self.v * 1e3,
EnergyType::MegaElectronVolt => self.v * 1e6,
}
}
pub fn as_kilo_electron_volt(&self) -> f64 {
match self.default_type {
EnergyType::Joule => self.v / 1.602176634e-16,
EnergyType::MillJoule => self.v / 1.602176634e-13,
EnergyType::MicroJoule => self.v / 1.602176634e-10,
EnergyType::NanoJoule => self.v / 1.602176634e-7,
EnergyType::KiloJoule => self.v / 1.602176634e-19,
EnergyType::MegaJoule => self.v / 1.602176634e-22,
EnergyType::ElectronVolt => self.v * 1e-3,
EnergyType::KiloElectronVolt => self.v,
EnergyType::MegaElectronVolt => self.v * 1e3,
}
}
pub fn as_mega_electron_volt(&self) -> f64 {
match self.default_type {
EnergyType::Joule => self.v / 1.602176634e-13,
EnergyType::MillJoule => self.v / 1.602176634e-10,
EnergyType::MicroJoule => self.v / 1.602176634e-7,
EnergyType::NanoJoule => self.v / 1.602176634e-4,
EnergyType::KiloJoule => self.v / 1.602176634e-16,
EnergyType::MegaJoule => self.v / 1.602176634e-19,
EnergyType::ElectronVolt => self.v * 1e-6,
EnergyType::KiloElectronVolt => self.v * 1e-3,
EnergyType::MegaElectronVolt => self.v,
}
}
}
impl Add for Energy {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let v = self.as_joule() + rhs.as_joule();
Self::from_joule(v)
}
}
impl<'a, 'b> Add<&'b Energy> for &'a Energy {
type Output = Energy;
fn add(self, rhs: &'b Energy) -> Self::Output { Energy::from_joule(self.as_joule() + rhs.as_joule()) }
}
impl<'a> Add<&'a Energy> for Energy {
type Output = Energy;
fn add(self, rhs: &'a Energy) -> Self::Output { Energy::from_joule(self.as_joule() + rhs.as_joule()) }
}
impl<'a> Add<Energy> for &'a Energy {
type Output = Energy;
fn add(self, rhs: Energy) -> Self::Output { Energy::from_joule(self.as_joule() + rhs.as_joule()) }
}
impl Sub for Energy {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let v = self.as_joule() - rhs.as_joule();
Self::from_joule(v)
}
}
impl<'a, 'b> Sub<&'b Energy> for &'a Energy {
type Output = Energy;
fn sub(self, rhs: &'b Energy) -> Self::Output { Energy::from_joule(self.as_joule() - rhs.as_joule()) }
}
impl<'a> Sub<&'a Energy> for Energy {
type Output = Energy;
fn sub(self, rhs: &'a Energy) -> Self::Output { Energy::from_joule(self.as_joule() - rhs.as_joule()) }
}
impl<'a> Sub<Energy> for &'a Energy {
type Output = Energy;
fn sub(self, rhs: Energy) -> Self::Output { Energy::from_joule(self.as_joule() - rhs.as_joule()) }
}
impl Add<f64> for Energy {
type Output = Self;
fn add(self, rhs: f64) -> Self::Output {
let v = self.v + rhs;
Energy {
v,
default_type: self.default_type,
}
}
}
impl Sub<f64> for Energy {
type Output = Self;
fn sub(self, rhs: f64) -> Self::Output {
let v = self.v - rhs;
Energy {
v,
default_type: self.default_type,
}
}
}
impl Mul<f64> for Energy {
type Output = Self;
fn mul(self, rhs: f64) -> Self::Output {
let v = self.as_joule() * rhs;
Self::from_joule(v)
}
}
impl Div<f64> for Energy {
type Output = Self;
fn div(self, rhs: f64) -> Self::Output {
let v = self.as_joule() / rhs;
Self::from_joule(v)
}
}
impl Mul<Energy> for f64 {
type Output = Energy;
fn mul(self, rhs: Energy) -> Self::Output {
let v = self * rhs.as_joule();
Energy::from_joule(v)
}
}
impl Div<Energy> for f64 {
type Output = Energy;
fn div(self, rhs: Energy) -> Self::Output {
let v = self / rhs.as_joule();
Energy::from_joule(v)
}
}
impl Mul<Coef> for Energy {
type Output = Self;
fn mul(self, rhs: Coef) -> Self::Output {
let v = self.as_joule() * rhs.get_value();
Self::from_joule(v)
}
}
impl Div<Coef> for Energy {
type Output = Self;
fn div(self, rhs: Coef) -> Self::Output {
let v = self.as_joule() / rhs.get_value();
Self::from_joule(v)
}
}
impl Neg for Energy {
type Output = Self;
fn neg(self) -> Self::Output {
let v = -self.as_joule();
Self::from_joule(v)
}
}
impl Div<chrono::TimeDelta> for Energy {
type Output = crate::physics::basic::Power;
fn div(self, rhs: chrono::TimeDelta) -> Self::Output {
let power_value = self.as_joule() / time_delta_to_secs_f64(&rhs);
crate::physics::basic::Power::from_watt(power_value)
}
}
impl<'a> Div<chrono::TimeDelta> for &'a Energy {
type Output = crate::physics::basic::Power;
fn div(self, rhs: chrono::TimeDelta) -> Self::Output { crate::physics::basic::Power::from_watt(self.as_joule() / time_delta_to_secs_f64(&rhs)) }
}
impl<'a> Div<&'a chrono::TimeDelta> for Energy {
type Output = crate::physics::basic::Power;
fn div(self, rhs: &'a chrono::TimeDelta) -> Self::Output { crate::physics::basic::Power::from_watt(self.as_joule() / time_delta_to_secs_f64(rhs)) }
}
impl<'a, 'b> Div<&'b chrono::TimeDelta> for &'a Energy {
type Output = crate::physics::basic::Power;
fn div(self, rhs: &'b chrono::TimeDelta) -> Self::Output { crate::physics::basic::Power::from_watt(self.as_joule() / time_delta_to_secs_f64(rhs)) }
}
impl Div<Distance> for Energy {
type Output = Force;
fn div(self, rhs: Distance) -> Self::Output {
let force_value = self.as_joule() / rhs.as_m();
Force::from_newton(force_value)
}
}
impl<'a, 'b> Div<&'b Distance> for &'a Energy {
type Output = Force;
fn div(self, rhs: &'b Distance) -> Self::Output { Force::from_newton(self.as_joule() / rhs.as_m()) }
}
impl<'a> Div<&'a Distance> for Energy {
type Output = Force;
fn div(self, rhs: &'a Distance) -> Self::Output { Force::from_newton(self.as_joule() / rhs.as_m()) }
}
impl<'a> Div<Distance> for &'a Energy {
type Output = Force;
fn div(self, rhs: Distance) -> Self::Output { Force::from_newton(self.as_joule() / rhs.as_m()) }
}
impl Mul<ElectricPotential> for ElectricCharge {
type Output = Energy;
fn mul(self, rhs: ElectricPotential) -> Self::Output {
Energy::from_joule(self.as_coulomb() * rhs.as_v())
}
}
impl<'a, 'b> Mul<&'b ElectricPotential> for &'a ElectricCharge {
type Output = Energy;
fn mul(self, rhs: &'b ElectricPotential) -> Self::Output { Energy::from_joule(self.as_coulomb() * rhs.as_v()) }
}
impl<'a> Mul<&'a ElectricPotential> for ElectricCharge {
type Output = Energy;
fn mul(self, rhs: &'a ElectricPotential) -> Self::Output { Energy::from_joule(self.as_coulomb() * rhs.as_v()) }
}
impl<'a> Mul<ElectricPotential> for &'a ElectricCharge {
type Output = Energy;
fn mul(self, rhs: ElectricPotential) -> Self::Output { Energy::from_joule(self.as_coulomb() * rhs.as_v()) }
}
impl Mul<ElectricCharge> for ElectricPotential {
type Output = Energy;
fn mul(self, rhs: ElectricCharge) -> Self::Output {
Energy::from_joule(self.as_v() * rhs.as_coulomb())
}
}
impl<'a, 'b> Mul<&'b ElectricCharge> for &'a ElectricPotential {
type Output = Energy;
fn mul(self, rhs: &'b ElectricCharge) -> Self::Output { Energy::from_joule(self.as_v() * rhs.as_coulomb()) }
}
impl<'a> Mul<&'a ElectricCharge> for ElectricPotential {
type Output = Energy;
fn mul(self, rhs: &'a ElectricCharge) -> Self::Output { Energy::from_joule(self.as_v() * rhs.as_coulomb()) }
}
impl<'a> Mul<ElectricCharge> for &'a ElectricPotential {
type Output = Energy;
fn mul(self, rhs: ElectricCharge) -> Self::Output { Energy::from_joule(self.as_v() * rhs.as_coulomb()) }
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::TimeDelta;
use crate::physics::basic::time_delta_from_secs_f64;
use approx::assert_relative_eq;
#[test]
fn test_energy() {
let e1 = Energy::from_joule(1000.0);
assert_eq!(e1.v, 1000.0);
assert_eq!(e1.default_type, EnergyType::Joule);
let e2 = Energy::from_mill_joule(1000.0);
assert_eq!(e2.v, 1000.0);
assert_eq!(e2.default_type, EnergyType::MillJoule);
let e3 = Energy::from_micro_joule(1000.0);
assert_eq!(e3.v, 1000.0);
assert_eq!(e3.default_type, EnergyType::MicroJoule);
let e4 = Energy::from_nano_joule(1000.0);
assert_eq!(e4.v, 1000.0);
assert_eq!(e4.default_type, EnergyType::NanoJoule);
let e5 = Energy::from_kilo_joule(1.0);
assert_eq!(e5.v, 1.0);
assert_eq!(e5.default_type, EnergyType::KiloJoule);
let e6 = Energy::from_mega_joule(1.0);
assert_eq!(e6.v, 1.0);
assert_eq!(e6.default_type, EnergyType::MegaJoule);
let e7 = Energy::from_electron_volt(1.0);
assert_eq!(e7.v, 1.0);
assert_eq!(e7.default_type, EnergyType::ElectronVolt);
let e8 = Energy::from_kilo_electron_volt(1.0);
assert_eq!(e8.v, 1.0);
assert_eq!(e8.default_type, EnergyType::KiloElectronVolt);
let e9 = Energy::from_mega_electron_volt(1.0);
assert_eq!(e9.v, 1.0);
assert_eq!(e9.default_type, EnergyType::MegaElectronVolt);
let e10 = Energy::default();
assert_eq!(e10.v, 0.0);
assert_eq!(e10.default_type, EnergyType::Joule);
}
#[test]
fn test_energy_as() {
let e1 = Energy::from_joule(1.0);
assert_relative_eq!(e1.as_joule(), 1.0);
assert_relative_eq!(e1.as_mill_joule(), 1e3);
assert_relative_eq!(e1.as_micro_joule(), 1e6);
assert_relative_eq!(e1.as_nano_joule(), 1e9);
assert_relative_eq!(e1.as_kilo_joule(), 1e-3);
assert_relative_eq!(e1.as_mega_joule(), 1e-6);
let e2 = Energy::from_mill_joule(1e3);
assert_relative_eq!(e2.as_joule(), 1.0);
assert_relative_eq!(e2.as_mill_joule(), 1e3);
assert_relative_eq!(e2.as_micro_joule(), 1e6);
let e3 = Energy::from_micro_joule(1e6);
assert_relative_eq!(e3.as_joule(), 1.0);
assert_relative_eq!(e3.as_micro_joule(), 1e6);
let e4 = Energy::from_nano_joule(1e9);
assert_relative_eq!(e4.as_joule(), 1.0);
assert_relative_eq!(e4.as_nano_joule(), 1e9);
let e5 = Energy::from_kilo_joule(1e-3);
assert_relative_eq!(e5.as_joule(), 1.0);
assert_relative_eq!(e5.as_kilo_joule(), 1e-3);
let e6 = Energy::from_mega_joule(1e-6);
assert_relative_eq!(e6.as_joule(), 1.0);
assert_relative_eq!(e6.as_mega_joule(), 1e-6);
let e7 = Energy::from_electron_volt(1.0);
assert_relative_eq!(e7.as_joule(), 1.602176634e-19, epsilon = 1e-25);
assert_relative_eq!(e7.as_electron_volt(), 1.0);
let e8 = Energy::from_kilo_electron_volt(1.0);
assert_relative_eq!(e8.as_joule(), 1.602176634e-16, epsilon = 1e-22);
assert_relative_eq!(e8.as_kilo_electron_volt(), 1.0);
let e9 = Energy::from_mega_electron_volt(1.0);
assert_relative_eq!(e9.as_joule(), 1.602176634e-13, epsilon = 1e-19);
assert_relative_eq!(e9.as_mega_electron_volt(), 1.0);
}
#[test]
fn test_energy_add() {
let e1 = Energy::from_joule(1000.0);
let e2 = Energy::from_joule(1000.0);
let e3 = e1 + e2;
assert_relative_eq!(e3.as_joule(), 2000.0);
let e1 = Energy::from_mill_joule(1e6);
let e2 = Energy::from_joule(1000.0);
let e3 = e1 + e2;
assert_relative_eq!(e3.as_joule(), 2000.0);
let e1 = Energy::from_joule(1000.0);
let e2 = e1 + 100.0;
assert_relative_eq!(e2.as_joule(), 1100.0);
let e1 = Energy::from_mill_joule(1000.0);
let e2 = e1 + 100.0;
assert_relative_eq!(e2.as_mill_joule(), 1100.0);
}
#[test]
fn test_energy_sub() {
let e1 = Energy::from_joule(2000.0);
let e2 = Energy::from_joule(1000.0);
let e3 = e1 - e2;
assert_relative_eq!(e3.as_joule(), 1000.0);
let e1 = Energy::from_mill_joule(2e6);
let e2 = Energy::from_joule(1000.0);
let e3 = e1 - e2;
assert_relative_eq!(e3.as_joule(), 1000.0);
let e1 = Energy::from_joule(2000.0);
let e2 = e1 - 100.0;
assert_relative_eq!(e2.as_joule(), 1900.0);
}
#[test]
fn test_energy_mul() {
let e1 = Energy::from_joule(2000.0);
let e2 = e1 * 2.0;
assert_relative_eq!(e2.as_joule(), 4000.0);
let e1 = Energy::from_mill_joule(2000.0);
let e2 = e1 * 2.0;
assert_relative_eq!(e2.as_mill_joule(), 4000.0);
let e1 = Energy::from_joule(1000.0);
let e2 = e1 * Coef::new(2.0);
assert_relative_eq!(e2.as_joule(), 2000.0);
}
#[test]
fn test_energy_div() {
let e1 = Energy::from_joule(2000.0);
let e2 = e1 / 2.0;
assert_relative_eq!(e2.as_joule(), 1000.0);
let e1 = Energy::from_mill_joule(2000.0);
let e2 = e1 / 2.0;
assert_relative_eq!(e2.as_mill_joule(), 1000.0);
let e1 = Energy::from_joule(2000.0);
let e2 = e1 / Coef::new(2.0);
assert_relative_eq!(e2.as_joule(), 1000.0);
}
#[test]
fn test_default_unit_value() {
let e1 = Energy::from_joule(1.0);
assert_relative_eq!(e1.default_unit_value(), 1.0);
let e1 = Energy::from_mill_joule(1.0);
assert_relative_eq!(e1.default_unit_value(), 1e-3);
}
#[test]
fn test_f64_mul_energy() {
let e = Energy::from_joule(2.0);
let result = 3.0 * e;
assert_relative_eq!(result.as_joule(), 6.0);
let e = Energy::from_mill_joule(2.0);
let result = 3.0 * e;
assert_relative_eq!(result.as_mill_joule(), 6.0);
}
#[test]
fn test_f64_div_energy() {
let e = Energy::from_joule(2.0);
let result = 6.0 / e;
assert_relative_eq!(result.as_joule(), 3.0);
let e = Energy::from_mill_joule(2000.0);
let result = 6.0 / e;
assert_relative_eq!(result.as_joule(), 3.0);
}
#[test]
fn test_energy_operations_with_different_types() {
let e1 = Energy::from_joule(1000.0);
let e2 = Energy::from_kilo_joule(1.0);
let e3 = Energy::from_mega_joule(0.001);
let sum = e1 + e2 + e3;
assert_relative_eq!(sum.as_joule(), 3000.0);
let diff = e1 - e2;
assert_relative_eq!(diff.as_joule(), 0.0);
let product = e1 * 2.0;
assert_relative_eq!(product.as_joule(), 2000.0);
let quotient = e1 / 2.0;
assert_relative_eq!(quotient.as_joule(), 500.0);
}
#[test]
fn test_energy_comprehensive_arithmetic_operations() {
let e_joule = Energy::from_joule(10.0);
let result = e_joule + 5.0;
assert_relative_eq!(result.as_joule(), 15.0);
let e_mill = Energy::from_mill_joule(10.0);
let result = e_mill + 5.0;
assert_relative_eq!(result.as_mill_joule(), 15.0);
let e_micro = Energy::from_micro_joule(10.0);
let result = e_micro + 5.0;
assert_relative_eq!(result.as_micro_joule(), 15.0);
let e_nano = Energy::from_nano_joule(10.0);
let result = e_nano + 5.0;
assert_relative_eq!(result.as_nano_joule(), 15.0);
let e_kilo = Energy::from_kilo_joule(10.0);
let result = e_kilo + 5.0;
assert_relative_eq!(result.as_kilo_joule(), 15.0);
let e_mega = Energy::from_mega_joule(10.0);
let result = e_mega + 5.0;
assert_relative_eq!(result.as_mega_joule(), 15.0);
let e_ev = Energy::from_electron_volt(10.0);
let result = e_ev + 5.0;
assert_relative_eq!(result.as_electron_volt(), 15.0);
let e_kev = Energy::from_kilo_electron_volt(10.0);
let result = e_kev + 5.0;
assert_relative_eq!(result.as_kilo_electron_volt(), 15.0);
let e_mev = Energy::from_mega_electron_volt(10.0);
let result = e_mev + 5.0;
assert_relative_eq!(result.as_mega_electron_volt(), 15.0);
let e_joule = Energy::from_joule(20.0);
let result = e_joule - 5.0;
assert_relative_eq!(result.as_joule(), 15.0);
let e_mill = Energy::from_mill_joule(20.0);
let result = e_mill - 5.0;
assert_relative_eq!(result.as_mill_joule(), 15.0);
let e_micro = Energy::from_micro_joule(20.0);
let result = e_micro - 5.0;
assert_relative_eq!(result.as_micro_joule(), 15.0);
let e_nano = Energy::from_nano_joule(20.0);
let result = e_nano - 5.0;
assert_relative_eq!(result.as_nano_joule(), 15.0);
let e_kilo = Energy::from_kilo_joule(20.0);
let result = e_kilo - 5.0;
assert_relative_eq!(result.as_kilo_joule(), 15.0);
let e_mega = Energy::from_mega_joule(20.0);
let result = e_mega - 5.0;
assert_relative_eq!(result.as_mega_joule(), 15.0);
let e_ev = Energy::from_electron_volt(20.0);
let result = e_ev - 5.0;
assert_relative_eq!(result.as_electron_volt(), 15.0);
let e_kev = Energy::from_kilo_electron_volt(20.0);
let result = e_kev - 5.0;
assert_relative_eq!(result.as_kilo_electron_volt(), 15.0);
let e_mev = Energy::from_mega_electron_volt(20.0);
let result = e_mev - 5.0;
assert_relative_eq!(result.as_mega_electron_volt(), 15.0);
}
#[test]
fn test_energy_physical_operations() {
let energy = Energy::from_joule(100.0);
let time = TimeDelta::seconds(5);
let power = energy / time;
assert_relative_eq!(power.as_watt(), 20.0);
let energy = Energy::from_joule(60.0);
let distance = Distance::from_m(3.0);
let force = energy / distance;
assert_relative_eq!(force.as_newton(), 20.0);
let energy_mill = Energy::from_mill_joule(100000.0); let time = TimeDelta::seconds(5);
let power = energy_mill / time;
assert_relative_eq!(power.as_watt(), 20.0);
let energy_kilo = Energy::from_kilo_joule(0.06); let distance = Distance::from_m(3.0);
let force = energy_kilo / distance;
assert_relative_eq!(force.as_newton(), 20.0);
let energy_ev = Energy::from_electron_volt(100.0 / 1.602176634e-19); let time = TimeDelta::seconds(5);
let power = energy_ev / time;
assert_relative_eq!(power.as_watt(), 20.0);
}
#[test]
fn test_energy_electron_volt_conversions() {
let e1 = Energy::from_electron_volt(1.0);
let e2 = Energy::from_kilo_electron_volt(1.0);
let e3 = Energy::from_mega_electron_volt(1.0);
assert_relative_eq!(e1.as_joule(), 1.602176634e-19, epsilon = 1e-25);
assert_relative_eq!(e2.as_joule(), 1.602176634e-16, epsilon = 1e-22);
assert_relative_eq!(e3.as_joule(), 1.602176634e-13, epsilon = 1e-19);
assert_relative_eq!(e1.as_electron_volt(), 1.0);
assert_relative_eq!(e2.as_electron_volt(), 1000.0);
assert_relative_eq!(e3.as_electron_volt(), 1000000.0);
assert_relative_eq!(e1.as_kilo_electron_volt(), 0.001);
assert_relative_eq!(e2.as_kilo_electron_volt(), 1.0);
assert_relative_eq!(e3.as_kilo_electron_volt(), 1000.0);
assert_relative_eq!(e1.as_mega_electron_volt(), 1e-6);
assert_relative_eq!(e2.as_mega_electron_volt(), 0.001);
assert_relative_eq!(e3.as_mega_electron_volt(), 1.0);
}
#[test]
fn test_energy_all_unit_conversions() {
let e = Energy::from_joule(1.0);
assert_relative_eq!(e.as_joule(), 1.0);
assert_relative_eq!(e.as_mill_joule(), 1000.0);
assert_relative_eq!(e.as_micro_joule(), 1000000.0);
assert_relative_eq!(e.as_nano_joule(), 1000000000.0);
assert_relative_eq!(e.as_kilo_joule(), 0.001);
assert_relative_eq!(e.as_mega_joule(), 0.000001);
let e_mill = Energy::from_mill_joule(1000.0);
assert_relative_eq!(e_mill.as_joule(), 1.0);
let e_micro = Energy::from_micro_joule(1000000.0);
assert_relative_eq!(e_micro.as_joule(), 1.0);
let e_nano = Energy::from_nano_joule(1000000000.0);
assert_relative_eq!(e_nano.as_joule(), 1.0);
let e_kilo = Energy::from_kilo_joule(0.001);
assert_relative_eq!(e_kilo.as_joule(), 1.0);
let e_mega = Energy::from_mega_joule(0.000001);
assert_relative_eq!(e_mega.as_joule(), 1.0);
}
#[test]
fn test_energy_comprehensive_as_methods() {
let e_joule = Energy::from_joule(1.0);
assert_relative_eq!(e_joule.as_joule(), 1.0);
assert_relative_eq!(e_joule.as_mill_joule(), 1e3);
assert_relative_eq!(e_joule.as_micro_joule(), 1e6);
assert_relative_eq!(e_joule.as_nano_joule(), 1e9);
assert_relative_eq!(e_joule.as_kilo_joule(), 1e-3);
assert_relative_eq!(e_joule.as_mega_joule(), 1e-6);
assert_relative_eq!(e_joule.as_electron_volt(), 1.0 / 1.602176634e-19);
assert_relative_eq!(e_joule.as_kilo_electron_volt(), 1.0 / 1.602176634e-16);
assert_relative_eq!(e_joule.as_mega_electron_volt(), 1.0 / 1.602176634e-13);
let e_mill = Energy::from_mill_joule(1.0);
assert_relative_eq!(e_mill.as_joule(), 1e-3);
assert_relative_eq!(e_mill.as_mill_joule(), 1.0);
assert_relative_eq!(e_mill.as_micro_joule(), 1e3);
assert_relative_eq!(e_mill.as_nano_joule(), 1e6);
assert_relative_eq!(e_mill.as_kilo_joule(), 1e-6);
assert_relative_eq!(e_mill.as_mega_joule(), 1e-9);
assert_relative_eq!(e_mill.as_electron_volt(), 1e-3 / 1.602176634e-19);
assert_relative_eq!(e_mill.as_kilo_electron_volt(), 1e-3 / 1.602176634e-16);
assert_relative_eq!(e_mill.as_mega_electron_volt(), 1e-3 / 1.602176634e-13);
let e_micro = Energy::from_micro_joule(1.0);
assert_relative_eq!(e_micro.as_joule(), 1e-6);
assert_relative_eq!(e_micro.as_mill_joule(), 1e-3);
assert_relative_eq!(e_micro.as_micro_joule(), 1.0);
assert_relative_eq!(e_micro.as_nano_joule(), 1e3);
assert_relative_eq!(e_micro.as_kilo_joule(), 1e-9);
assert_relative_eq!(e_micro.as_mega_joule(), 1e-12);
assert_relative_eq!(
e_micro.as_electron_volt(),
1e-6 / 1.602176634e-19,
epsilon = 1e-8
);
assert_relative_eq!(
e_micro.as_kilo_electron_volt(),
1e-6 / 1.602176634e-16,
epsilon = 1e-8
);
assert_relative_eq!(
e_micro.as_mega_electron_volt(),
1e-6 / 1.602176634e-13,
epsilon = 1e-8
);
let e_nano = Energy::from_nano_joule(1.0);
assert_relative_eq!(e_nano.as_joule(), 1e-9);
assert_relative_eq!(e_nano.as_mill_joule(), 1e-6);
assert_relative_eq!(e_nano.as_micro_joule(), 1e-3);
assert_relative_eq!(e_nano.as_nano_joule(), 1.0);
assert_relative_eq!(e_nano.as_kilo_joule(), 1e-12);
assert_relative_eq!(e_nano.as_mega_joule(), 1e-15);
assert_relative_eq!(
e_nano.as_electron_volt(),
1e-9 / 1.602176634e-19,
epsilon = 1e-8
);
assert_relative_eq!(
e_nano.as_kilo_electron_volt(),
1e-9 / 1.602176634e-16,
epsilon = 1e-8
);
assert_relative_eq!(
e_nano.as_mega_electron_volt(),
1e-9 / 1.602176634e-13,
epsilon = 1e-8
);
let e_kilo = Energy::from_kilo_joule(1.0);
assert_relative_eq!(e_kilo.as_joule(), 1e3);
assert_relative_eq!(e_kilo.as_mill_joule(), 1e6);
assert_relative_eq!(e_kilo.as_micro_joule(), 1e9);
assert_relative_eq!(e_kilo.as_nano_joule(), 1e12);
assert_relative_eq!(e_kilo.as_kilo_joule(), 1.0);
assert_relative_eq!(e_kilo.as_mega_joule(), 1e-3);
assert_relative_eq!(e_kilo.as_electron_volt(), 1e3 / 1.602176634e-19);
assert_relative_eq!(e_kilo.as_kilo_electron_volt(), 1e3 / 1.602176634e-16);
assert_relative_eq!(e_kilo.as_mega_electron_volt(), 1e3 / 1.602176634e-13);
let e_mega = Energy::from_mega_joule(1.0);
assert_relative_eq!(e_mega.as_joule(), 1e6);
assert_relative_eq!(e_mega.as_mill_joule(), 1e9);
assert_relative_eq!(e_mega.as_micro_joule(), 1e12);
assert_relative_eq!(e_mega.as_nano_joule(), 1e15);
assert_relative_eq!(e_mega.as_kilo_joule(), 1e3);
assert_relative_eq!(e_mega.as_mega_joule(), 1.0);
assert_relative_eq!(e_mega.as_electron_volt(), 1e6 / 1.602176634e-19);
assert_relative_eq!(e_mega.as_kilo_electron_volt(), 1e6 / 1.602176634e-16);
assert_relative_eq!(e_mega.as_mega_electron_volt(), 1e6 / 1.602176634e-13);
let e_ev = Energy::from_electron_volt(1.0);
assert_relative_eq!(e_ev.as_joule(), 1.602176634e-19);
assert_relative_eq!(e_ev.as_mill_joule(), 1.602176634e-16);
assert_relative_eq!(e_ev.as_micro_joule(), 1.602176634e-13);
assert_relative_eq!(e_ev.as_nano_joule(), 1.602176634e-10);
assert_relative_eq!(e_ev.as_kilo_joule(), 1.602176634e-22);
assert_relative_eq!(e_ev.as_mega_joule(), 1.602176634e-25);
assert_relative_eq!(e_ev.as_electron_volt(), 1.0);
assert_relative_eq!(e_ev.as_kilo_electron_volt(), 1e-3);
assert_relative_eq!(e_ev.as_mega_electron_volt(), 1e-6);
let e_kev = Energy::from_kilo_electron_volt(1.0);
assert_relative_eq!(e_kev.as_joule(), 1.602176634e-16);
assert_relative_eq!(e_kev.as_mill_joule(), 1.602176634e-13);
assert_relative_eq!(e_kev.as_micro_joule(), 1.602176634e-10);
assert_relative_eq!(e_kev.as_nano_joule(), 1.602176634e-7);
assert_relative_eq!(e_kev.as_kilo_joule(), 1.602176634e-19);
assert_relative_eq!(e_kev.as_mega_joule(), 1.602176634e-22);
assert_relative_eq!(e_kev.as_electron_volt(), 1e3);
assert_relative_eq!(e_kev.as_kilo_electron_volt(), 1.0);
assert_relative_eq!(e_kev.as_mega_electron_volt(), 1e-3);
let e_mev = Energy::from_mega_electron_volt(1.0);
assert_relative_eq!(e_mev.as_joule(), 1.602176634e-13);
assert_relative_eq!(e_mev.as_mill_joule(), 1.602176634e-10);
assert_relative_eq!(e_mev.as_micro_joule(), 1.602176634e-7);
assert_relative_eq!(e_mev.as_nano_joule(), 1.602176634e-4);
assert_relative_eq!(e_mev.as_kilo_joule(), 1.602176634e-16);
assert_relative_eq!(e_mev.as_mega_joule(), 1.602176634e-19);
assert_relative_eq!(e_mev.as_electron_volt(), 1e6);
assert_relative_eq!(e_mev.as_kilo_electron_volt(), 1e3);
assert_relative_eq!(e_mev.as_mega_electron_volt(), 1.0);
}
#[test]
fn test_energy_edge_cases() {
let zero_energy = Energy::from_joule(0.0);
assert!(zero_energy.is_zero());
let negative_energy = Energy::from_joule(-100.0);
assert!(!negative_energy.is_zero());
assert_relative_eq!(negative_energy.as_joule(), -100.0);
let large_energy = Energy::from_mega_joule(1000.0);
assert_relative_eq!(large_energy.as_joule(), 1e9);
let small_energy = Energy::from_nano_joule(1.0);
assert_relative_eq!(small_energy.as_joule(), 1e-9);
}
#[test]
fn test_energy_physical_quantity_trait() {
let mut e = Energy::from_joule(10.0);
assert_relative_eq!(e.default_unit_value(), 10.0);
e.set_value(20.0);
assert_relative_eq!(e.as_joule(), 20.0);
assert!(!e.is_zero());
e.set_value(0.0);
assert!(e.is_zero());
let any_ref = e.as_any();
assert!(any_ref.is::<Energy>());
}
#[test]
fn test_set_value() {
let mut e = Energy::from_joule(1.0);
e.set_value(2.0);
assert_relative_eq!(e.as_joule(), 2.0);
}
#[test]
fn test_energy_div_duration() {
let energy = Energy::from_joule(100.0); let time = TimeDelta::seconds(5); let power: crate::physics::basic::Power = energy / time;
assert_relative_eq!(power.as_watt(), 20.0);
}
#[test]
fn test_energy_div_timedelta() {
let energy = Energy::from_joule(100.0); let td = time_delta_from_secs_f64(5.0);
let power: crate::physics::basic::Power = energy / td;
assert_relative_eq!(power.as_watt(), 20.0);
let neg_td = time_delta_from_secs_f64(-5.0);
let power_neg: crate::physics::basic::Power = energy / neg_td;
assert_relative_eq!(power_neg.as_watt(), -20.0);
}
#[test]
fn test_energy_div_distance() {
let energy = Energy::from_joule(60.0); let distance = Distance::from_m(3.0); let force: Force = energy / distance;
assert_relative_eq!(force.as_newton(), 20.0);
}
#[test]
fn test_energy_ref_ops() {
let e1 = Energy::from_joule(10.0);
let e2 = Energy::from_kilo_joule(0.005); let s = &e1 + &e2;
assert_relative_eq!(s.as_joule(), 15.0);
let d = &e1 - &e2;
assert_relative_eq!(d.as_joule(), 5.0);
let p = &e1 / &TimeDelta::seconds(2);
assert_relative_eq!(p.as_watt(), 5.0);
let f = &e1 / &Distance::from_m(2.0);
assert_relative_eq!(f.as_newton(), 5.0);
let s2 = e1 + &e2;
assert_relative_eq!(s2.as_joule(), 15.0);
let s3 = &e1 + e2;
assert_relative_eq!(s3.as_joule(), 15.0);
let e2b = Energy::from_kilo_joule(0.005);
let d2 = e1 - &e2b;
assert_relative_eq!(d2.as_joule(), 5.0);
let d3 = &e1 - e2b;
assert_relative_eq!(d3.as_joule(), 5.0);
let dur = TimeDelta::seconds(2);
let p2 = e1 / &dur;
assert_relative_eq!(p2.as_watt(), 5.0);
let p3 = &e1 / dur;
assert_relative_eq!(p3.as_watt(), 5.0);
let td = time_delta_from_secs_f64(2.0);
let p4 = e1 / &td;
assert_relative_eq!(p4.as_watt(), 5.0);
let p5 = &e1 / td;
assert_relative_eq!(p5.as_watt(), 5.0);
let td2 = time_delta_from_secs_f64(2.0);
let p6 = &e1 / &td2;
assert_relative_eq!(p6.as_watt(), 5.0);
let f2 = e1 / &Distance::from_m(2.0);
assert_relative_eq!(f2.as_newton(), 5.0);
let f3 = &e1 / Distance::from_m(2.0);
assert_relative_eq!(f3.as_newton(), 5.0);
}
#[test]
fn test_energy_neg() {
let e1 = Energy::from_joule(5.0);
let neg_e1 = -e1;
assert_relative_eq!(neg_e1.as_joule(), -5.0);
let e2 = Energy::from_kilo_joule(-10.0);
let neg_e2 = -e2;
assert_relative_eq!(neg_e2.as_kilo_joule(), 10.0);
let e3 = Energy::from_joule(0.0);
let neg_e3 = -e3;
assert_relative_eq!(neg_e3.as_joule(), 0.0);
let e4 = Energy::from_mega_joule(1.0);
let neg_e4 = -e4;
assert_relative_eq!(neg_e4.as_joule(), -1_000_000.0);
let e5 = Energy::from_electron_volt(100.0);
let neg_e5 = -e5;
assert_relative_eq!(neg_e5.as_electron_volt(), -100.0);
}
#[test]
fn test_charge_times_potential_is_energy() {
let q = ElectricCharge::from_coulomb(2.0);
let v = ElectricPotential::from_v(3.0);
let e: Energy = q * v;
assert_relative_eq!(e.as_joule(), 6.0);
let q2 = ElectricCharge::from_coulomb(2.0);
let v2 = ElectricPotential::from_v(3.0);
assert_relative_eq!((&q2 * &v2).as_joule(), 6.0);
let q3 = ElectricCharge::from_coulomb(2.0);
let v3 = ElectricPotential::from_v(3.0);
assert_relative_eq!((q3 * &v3).as_joule(), 6.0);
let q4 = ElectricCharge::from_coulomb(2.0);
let v4 = ElectricPotential::from_v(3.0);
assert_relative_eq!((&q4 * v4).as_joule(), 6.0);
let v5 = ElectricPotential::from_v(2.0);
let q5 = ElectricCharge::from_coulomb(3.0);
let e5: Energy = v5 * q5;
assert_relative_eq!(e5.as_joule(), 6.0);
let v6 = ElectricPotential::from_v(2.0);
let q6 = ElectricCharge::from_coulomb(3.0);
assert_relative_eq!((&v6 * &q6).as_joule(), 6.0);
let v7 = ElectricPotential::from_v(2.0);
let q7 = ElectricCharge::from_coulomb(3.0);
assert_relative_eq!((v7 * &q7).as_joule(), 6.0);
let v8 = ElectricPotential::from_v(2.0);
let q8 = ElectricCharge::from_coulomb(3.0);
assert_relative_eq!((&v8 * q8).as_joule(), 6.0);
}
}