diff --git a/examples/consistency_others.nbt b/examples/consistency_others.nbt index 70d16f34e..13c11b10b 100644 --- a/examples/consistency_others.nbt +++ b/examples/consistency_others.nbt @@ -64,7 +64,8 @@ assert_eq(1 calorie, 4.184 J) assert_eq(1 BTU, 1055.05585262 J) assert_eq(1 lbf, 4.448222 N) assert_eq(1 ozf, (4.448222 / 16.0) N, 1e-5 N) -assert_eq(60 RPM, 1 Hz) +assert_eq(60 RPM, 1 rev / s) +assert_eq(60 RPM, 360° / s) assert_eq(1 fortnight, 2 week) assert_eq(1 mmHg, 133.322387415 Pa, 1e-5 Pa) assert_eq(1 PSI, 6.894757 kPa) diff --git a/examples/dimensionful_angles.nbt b/examples/dimensionful_angles.nbt new file mode 100644 index 000000000..a71c0ec4c --- /dev/null +++ b/examples/dimensionful_angles.nbt @@ -0,0 +1,34 @@ +# This file uses the dimensionful_angles prelude + +print("h = {planck_constant}") +print("ℏ = {ℏ}") +print("ȟ = {ȟ}") + +# harmonic oscillation +let ω = 2π rad / s +let t = 0.4 s +let amplitude = Sin(ω·t) +print("Amplitude: {amplitude}") + +# Tangential velocity +let r = 20 cm +let v: Velocity = r ω / θC # This is one of the "text book formulas" that needs adaptation +print("Linear velocity: {v}") + +# Rotational motion +assert_eq(60 rpm, 360° / s) + +# Arc length +fn arc_length(radius: Length, θ: Angle) -> Length = radius × θ / θC +print(arc_length(1 m, 45°)) + +# Rotational energy +let mass = 1 kg +let radius = 1 m +let I: MomentOfInertia = mass × radius^2 / θC^2 +let ω_rot: AngularFrequency = 180° / 5 s +let E_rot: Energy = 1/2 * I * ω_rot^2 +print("E_rot = {E_rot -> J}") + +# Cyclotron frequency +let ω_cyc: AngularFrequency = electron_charge/electron_mass × 50 µT × θC diff --git a/examples/projectile_motion.nbt b/examples/projectile_motion.nbt index 2646356eb..93aca0062 100644 --- a/examples/projectile_motion.nbt +++ b/examples/projectile_motion.nbt @@ -1,8 +1,8 @@ # https://en.wikipedia.org/wiki/Projectile_motion -fn max_height(v: Velocity, θ: Angle) -> Length = v² · sin(θ)^2 / (2 · g0) -fn max_distance(v: Velocity, θ: Angle) -> Length = v² · sin(2 θ) / g0 -fn time_of_flight(v: Velocity, θ: Angle) -> Time = 2 v · sin(θ) / g0 +fn max_height(v: Velocity, θ: Angle) -> Length = v² · Sin(θ)^2 / (2 · g0) +fn max_distance(v: Velocity, θ: Angle) -> Length = v² · Sin(2 θ) / g0 +fn time_of_flight(v: Velocity, θ: Angle) -> Time = 2 v · Sin(θ) / g0 assert_eq(max_height(10 m/s, 45 deg), 2.55 m, 1 cm) assert_eq(max_distance(10 m/s, 45 deg), 10.20 m, 1 cm) diff --git a/examples/readme-demo.nbt b/examples/readme-demo.nbt index 613d49462..de85bff7d 100644 --- a/examples/readme-demo.nbt +++ b/examples/readme-demo.nbt @@ -2,6 +2,6 @@ use units::currencies 8 km / (1 h + 25 min) 140 € -> GBP -atan2(30 cm, 1 m) -> deg -let ω = 2π c / 660 nm +ATan2(30 cm, 1 m) -> deg +let ω = 2π θC c / 660 nm print("Energy of red photon: {ℏ ω -> eV}") diff --git a/examples/unicode.nbt b/examples/unicode.nbt index 78487a9f7..48eb98f5c 100644 --- a/examples/unicode.nbt +++ b/examples/unicode.nbt @@ -3,7 +3,7 @@ let ν = c / λ assert_eq(ν, 499.7 GHz, 0.1 GHz) -let ω = 2 π ν +let ω = 2 π θC ν let E = ℏ ω assert_eq(E, 2 meV, 0.1 meV) diff --git a/numbat-wasm/deploy.sh b/numbat-wasm/deploy.sh index 1ece5d479..cb43f5ace 100644 --- a/numbat-wasm/deploy.sh +++ b/numbat-wasm/deploy.sh @@ -4,11 +4,6 @@ set -euo pipefail current_branch=$(git rev-parse --abbrev-ref HEAD) -if [[ "$current_branch" != "master" ]]; then - echo "You are currently on the '$current_branch' branch, not 'master'." - exit 1 -fi - bash build.sh -rsync --archive --stats --progress --human-readable -r www/ shark.fish:numbat.dev/ +rsync --archive --stats --progress --human-readable -r www/ shark.fish:numbat.dev/angles/ diff --git a/numbat/modules/core/dimensions.nbt b/numbat/modules/core/dimensions.nbt index e06a16388..7d2f1e67e 100644 --- a/numbat/modules/core/dimensions.nbt +++ b/numbat/modules/core/dimensions.nbt @@ -1,6 +1,6 @@ ### Physical dimensions -dimension Angle = 1 # SI: plane angle +dimension Angle # SI: plane angle dimension SolidAngle = Angle^2 dimension Length @@ -14,6 +14,8 @@ dimension Velocity = Length / Time dimension Acceleration = Length / Time^2 dimension Jerk = Length / Time^3 dimension FlowRate = Volume / Time +dimension AngularFrequency = Angle / Time +dimension AngularAcceleration = Angle / Time^2 dimension Mass dimension Momentum = Mass × Velocity @@ -24,7 +26,7 @@ dimension Pressure = Force / Area = Energy / Volume # also: stress dimension Action = Energy × Time dimension MassDensity = Mass / Length^3 dimension MomentOfInertia = Mass × Length^2 / Angle^2 -dimension AngularMomentum = MomentOfInertia × Angle / Time = Mass × Length^2 / Time / Angle +dimension AngularMomentum = MomentOfInertia × AngularFrequency = Mass × Length^2 / Time / Angle dimension Torque = Length × Force / Angle # also: moment of force dimension EnergyDensity = Energy / Volume dimension MassFlow = Mass / Time @@ -45,7 +47,7 @@ dimension ElectricChargeDensity = ElectricCharge / Volume dimension CurrentDensity = Current / Area dimension ElectricDipoleMoment = ElectricCharge × Length dimension ElectricQuadrupoleMoment = ElectricCharge × Length^2 -dimension MagneticDipoleMoment = Current × Area = Torque / MagneticFluxDensity +dimension MagneticDipoleMoment = Current × Area = Torque / MagneticFluxDensity * Angle dimension ElectricFieldStrength = Voltage / Length dimension ElectricDisplacementFieldStrength = ElectricCharge / Area dimension ElectricPermittivity = Time^4 × Current^2 / Mass / Length^3 × Angle = ElectricDisplacementFieldStrength / ElectricFieldStrength × Angle diff --git a/numbat/modules/physics/constants.nbt b/numbat/modules/physics/constants.nbt index 53550c1e7..4db542330 100644 --- a/numbat/modules/physics/constants.nbt +++ b/numbat/modules/physics/constants.nbt @@ -24,7 +24,9 @@ let planck_constant: Action = 6.626_070_15e-34 J / Hz @name("Reduced Planck constant") @url("https://en.wikipedia.org/wiki/Planck_constant#Reduced_Planck_constant_%E2%84%8F") @aliases(h_bar) -let ℏ: AngularMomentum = planck_constant / 2π +let ℏ: AngularMomentum = planck_constant / 2π θC +let h_bar = ℏ +let ȟ: Action = planck_constant / 2π @name("Electron mass") @url("https://en.wikipedia.org/wiki/Electron_mass") @@ -38,22 +40,22 @@ let elementary_charge: ElectricCharge = 1.602_176_634e-19 C @name("Vacuum permeability / magnetic constant") @url("https://en.wikipedia.org/wiki/Vacuum_permeability") @aliases(µ0,μ0,mu0) -let magnetic_constant: MagneticPermeability = 1.256_637_062_12e-6 N / A² +let magnetic_constant: MagneticPermeability = 1.256_637_062_12e-6 N / A² / rad @name("Vacuum electric permittivity / electric constant") @url("https://en.wikipedia.org/wiki/Vacuum_permittivity") @aliases(ε0,eps0) -let electric_constant: ElectricPermittivity = 1 / (µ0 c²) -> F/m +let electric_constant: ElectricPermittivity = 1 / (µ0 c²) -> F/m × rad -@name("Bohr magneton") -@aliases(µ_B,μ_B) -@url("https://en.wikipedia.org/wiki/Bohr_magneton") -let bohr_magneton: Energy / MagneticFluxDensity = electron_charge ℏ / 2 electron_mass -> J/T +#@name("Bohr magneton") +#@aliases(µ_B,μ_B) +#@url("https://en.wikipedia.org/wiki/Bohr_magneton") +#let bohr_magneton: Energy / MagneticFluxDensity = electron_charge ℏ / 2 electron_mass -> J/T -@name("Fine structure constant") -@url("https://en.wikipedia.org/wiki/Fine-structure_constant") -@aliases(α, alpha) -let fine_structure_constant: Scalar = electron_charge^2 / (2 eps0 ℎ c) +#@name("Fine structure constant") +#@url("https://en.wikipedia.org/wiki/Fine-structure_constant") +#@aliases(α, alpha) +#let fine_structure_constant: Scalar = electron_charge^2 / (2 eps0 ȟ c) @name("Proton mass") @url("https://en.wikipedia.org/wiki/Proton") @@ -85,15 +87,15 @@ let gas_constant: Energy / (AmountOfSubstance × Temperature) = k_B × N_A @name("Bohr radius") @url("https://en.wikipedia.org/wiki/Bohr_radius") @aliases(a0) -let bohr_radius: Length = 4 pi ε0 ℏ^2 / (electron_charge^2 electron_mass) +let bohr_radius: Length / Angle = 4 pi ε0 ℏ^2 / (electron_charge^2 electron_mass) -> m/rad -@name("Rydberg constant") -@url("https://en.wikipedia.org/wiki/Rydberg_constant") -let rydberg_constant: Wavenumber = (electron_mass electron_charge^4) / (8 ε0^2 ℎ^3 c) +#@name("Rydberg constant") +#@url("https://en.wikipedia.org/wiki/Rydberg_constant") +#let rydberg_constant: Wavenumber = (electron_mass electron_charge^4) / (8 ε0^2 ℎ^3 c) -@name("Rydberg unit of energy") -@url("https://en.wikipedia.org/wiki/Rydberg_constant") -unit Ry: Energy = ℎ c × rydberg_constant +#@name("Rydberg unit of energy") +#@url("https://en.wikipedia.org/wiki/Rydberg_constant") +#unit Ry: Energy = ℎ c × rydberg_constant @name("Atomic Mass constant") @url("https://en.wikipedia.org/wiki/Atomic_mass_constant") diff --git a/numbat/modules/prelude.nbt b/numbat/modules/prelude.nbt index 9d71be032..91532d6d1 100644 --- a/numbat/modules/prelude.nbt +++ b/numbat/modules/prelude.nbt @@ -1,3 +1,26 @@ +# The following prelude is based on a proposal to treat angles +# as dimensionful quantities [1]. +# +# +# Literature +# ---------- +# +# Pro: +# - [1] Angles in the SI: a detailed proposal for solving the problem, https://arxiv.org/abs/2108.05704 +# - [2] Angles are inherently neither length ratios nor dimensionless, https://arxiv.org/abs/1909.08389 +# - [3] Brownstein K R, Angles—let’s treat them squarely, Am. J. Phys. 65 605–14 (1997). +# - [4] Dimensionless units in the SI, https://arxiv.org/abs/1409.2794 +# +# Contra: +# - [4] Dimensional angles and universal constants, https://doi.org/10.1119/1.18964 +# - [5] M. Grötschel, H. Hanche-Olsen, H. Holden, Comment on ‘Angles are inherently neither length ratios nor dimensionless’. +# (and companion paper https://arxiv.org/abs/2011.05779v4) +# - [6] Comment on 'Angles in the SI: a detailed proposal for solving the problem', B P Leonard, https://iopscience.iop.org/article/10.1088/1681-7575/ac5433/meta +# (and reply to comment: https://iopscience.iop.org/article/10.1088/1681-7575/ac5434) +# +# Review: +# - [7] Implications of adopting plane angle as a base quantity in the SI, https://arxiv.org/pdf/1604.02373.pdf + use core::scalar use core::quantities use core::dimensions @@ -36,3 +59,11 @@ use chemistry::elements use datetime::functions use datetime::human + +fn Sin(θ: Angle) -> Scalar = sin(θ / θC) +fn Cos(θ: Angle) -> Scalar = cos(θ / θC) +fn Tan(θ: Angle) -> Scalar = tan(θ / θC) +fn ASin(x: Scalar) -> Angle = asin(x) × θC +fn ACos(x: Scalar) -> Angle = acos(x) × θC +fn ATan(x: Scalar) -> Angle = atan(x) × θC +fn ATan2(y: Q, x: Q) -> Angle = atan2(y, x) × θC diff --git a/numbat/modules/units/hartree.nbt b/numbat/modules/units/hartree.nbt index 04dff2ab1..cd2a64e5d 100644 --- a/numbat/modules/units/hartree.nbt +++ b/numbat/modules/units/hartree.nbt @@ -7,4 +7,4 @@ unit hartree: Energy = ℏ^2 / (electron_mass a0^2) @name("Bohr") @url("https://en.wikipedia.org/wiki/Hartree_atomic_units") -unit bohr: Length = a0 +unit bohr: Length = a0 × θC diff --git a/numbat/modules/units/misc.nbt b/numbat/modules/units/misc.nbt index 34cca9c92..19722021c 100644 --- a/numbat/modules/units/misc.nbt +++ b/numbat/modules/units/misc.nbt @@ -58,7 +58,7 @@ unit revolution: Angle = 360° @name("Revolutions per minute") @url("https://en.wikipedia.org/wiki/Revolutions_per_minute") @aliases(RPM: short) -unit rpm: Frequency = 1 / minute +unit rpm: AngularFrequency = revolutions per minute @name("Millimeter of mercury") @url("https://en.wikipedia.org/wiki/Millimeter_of_mercury") diff --git a/numbat/modules/units/planck.nbt b/numbat/modules/units/planck.nbt index 2ca9b9f40..614904871 100644 --- a/numbat/modules/units/planck.nbt +++ b/numbat/modules/units/planck.nbt @@ -4,20 +4,20 @@ use physics::constants @name("Planck length") @url("https://en.wikipedia.org/wiki/Planck_length") -unit planck_length: Length = sqrt(ℏ G / c^3) -> m +unit planck_length: Length = sqrt(ȟ G / c^3) -> m @name("Planck mass") @url("https://en.wikipedia.org/wiki/Planck_mass") -unit planck_mass: Mass = sqrt(ℏ c / G) -> kg +unit planck_mass: Mass = sqrt(ȟ c / G) -> kg @name("Planck time") @url("https://en.wikipedia.org/wiki/Planck_time") -unit planck_time: Time = sqrt(ℏ G / c^5) -> s +unit planck_time: Time = sqrt(ȟ G / c^5) -> s @name("Planck temperature") @url("https://en.wikipedia.org/wiki/Planck_temperature") -unit planck_temperature: Temperature = sqrt(ℏ c^5 / (G k_B^2)) -> K +unit planck_temperature: Temperature = sqrt(ȟ c^5 / (G k_B^2)) -> K @name("Planck energy") @url("https://en.wikipedia.org/wiki/Planck_energy") -unit planck_energy: Energy = sqrt(ℏ c^5 / G) -> J +unit planck_energy: Energy = sqrt(ȟ c^5 / G) -> J diff --git a/numbat/modules/units/si.nbt b/numbat/modules/units/si.nbt index 45335db33..628a00e1a 100644 --- a/numbat/modules/units/si.nbt +++ b/numbat/modules/units/si.nbt @@ -51,7 +51,11 @@ unit candela: LuminousIntensity @url("https://en.wikipedia.org/wiki/Radian") @metric_prefixes @aliases(radians, rad: short) -unit radian: Angle = meter / meter +unit radian: Angle + +# The "Cotes angle" +let theta_C = 1 rad +let θC = theta_C @name("Steradian") @url("https://en.wikipedia.org/wiki/Steradian") diff --git a/numbat/modules/units/stoney.nbt b/numbat/modules/units/stoney.nbt index 9da12c4f0..5ffad276c 100644 --- a/numbat/modules/units/stoney.nbt +++ b/numbat/modules/units/stoney.nbt @@ -1,13 +1,13 @@ use physics::constants -@name("Stoney length") -@url("https://en.wikipedia.org/wiki/Stoney_units") -unit stoney_length: Length = sqrt(G × electron_charge^2 / 4 π ε0 c^4) +#@name("Stoney length") +#@url("https://en.wikipedia.org/wiki/Stoney_units") +#unit stoney_length: Length = sqrt(G × electron_charge^2 / 4 π ε0 c^4) -@name("Stoney mass") -@url("https://en.wikipedia.org/wiki/Stoney_units") -unit stoney_mass: Mass = sqrt(electron_charge^2 / 4 π ε0 G) +#@name("Stoney mass") +#@url("https://en.wikipedia.org/wiki/Stoney_units") +#unit stoney_mass: Mass = sqrt(electron_charge^2 / 4 π ε0 G) -@name("Stoney time") -@url("https://en.wikipedia.org/wiki/Stoney_units") -unit stoney_time: Time = sqrt(G × electron_charge^2 / 4 π ε0 c^6) +#@name("Stoney time") +#@url("https://en.wikipedia.org/wiki/Stoney_units") +#unit stoney_time: Time = sqrt(G × electron_charge^2 / 4 π ε0 c^6) diff --git a/numbat/tests/interpreter.rs b/numbat/tests/interpreter.rs index 775578529..11d3797ee 100644 --- a/numbat/tests/interpreter.rs +++ b/numbat/tests/interpreter.rs @@ -258,8 +258,8 @@ fn test_algebra() { #[test] fn test_math() { - expect_output("sin(90°)", "1"); - expect_output("sin(30°)", "0.5"); + expect_output("Sin(90°)", "1"); + expect_output("Sin(30°)", "0.5"); expect_output("sin(pi/2)", "1"); expect_output("atan2(10, 0) / (pi / 2)", "1"); @@ -283,7 +283,7 @@ fn test_incompatible_dimension_errors() { get_error_message("kg m / s^2 + kg m^2"), @r###" left hand side: Length × Mass × Time⁻² [= Force] - right hand side: Length² × Mass [= MomentOfInertia] + right hand side: Length² × Mass "### ); @@ -420,14 +420,14 @@ fn test_misc_examples() { expect_output("2min + 30s -> sec", "150 s"); expect_output("4/3 * pi * (6000km)³", "9.04779e+11 km³"); expect_output("40kg * 9.8m/s^2 * 150cm", "588 kg·m²/s²"); - expect_output("sin(30°)", "0.5"); + expect_output("Sin(30°)", "0.5"); expect_output("60mph -> m/s", "26.8224 m/s"); expect_output("240km/day -> km/h", "10 km/h"); expect_output("1mrad -> °", "0.0572958°"); expect_output("52weeks -> days", "364 day"); expect_output("5in + 2ft -> cm", "73.66 cm"); - expect_output("atan(30cm / 2m) -> deg", "8.53077°"); + expect_output("ATan(30cm / 2m) -> deg", "8.53077°"); expect_output("6Mbit/s * 1.5h -> GB", "4.05 GB"); expect_output("6Mbit/s * 1.5h -> GiB", "3.77186 GiB"); @@ -439,7 +439,7 @@ fn test_misc_examples() { #[test] fn test_bohr_radius_regression() { // Make sure that the unit is 'm', and not 'F·J²/(C²·kg·m·Hz²)', like we had before - expect_output("bohr_radius", "5.29177e-11 m"); + expect_output("bohr_radius", "5.29177e-11 m/rad"); } #[test]