metanorma / atmospheric

International Standard Atmosphere / ICAO Standard Atmosphere (ISA) from ICAO 7488 / ISO 2533
BSD 2-Clause "Simplified" License
1 stars 1 forks source link

Add high-precision mode #35

Open newbthenewbd opened 5 months ago

newbthenewbd commented 5 months ago

Initial idea as to how to do this without sacrificing all readability. The truly constant constants had to go :(

Metanorma PR checklist

newbthenewbd commented 5 months ago

One idea would be to make configuring the number of accurate significant digits an option (possibly straight away as the parameter given to set_precision, with 0 standing for ye olde ruby double floats?), BigDecimal should allow this...

I find it likely though, that long before floating-point precision proves to be the real (ha ha) bottleneck in getting accurate here, the formulae themselves will be... pretty sure the Pi and the square root of 2 are currently the most accurate among them :)

ronaldtse commented 5 months ago

@newbthenewbd you may well be right!

ronaldtse commented 2 months ago

@newbthenewbd How do we test the high-precision mode? Is this mergable now?

newbthenewbd commented 2 months ago

So long as the way it is now (with only two options, :normal and :high) suffices, should be good to merge, yeah, if only it didn't rot since I last looked at it haha :)

Example usage:

require "bigdecimal"
require "atmospheric"

H = BigDecimal("32000.0")

#Atmospheric::Isa.set_precision(:normal) # This is the default
Atmospheric::Isa.set_precision(:high)

h = Atmospheric::Isa.geometric_altitude_from_geopotential(H)
TK = Atmospheric::Isa.temperature_at_layer_from_geopotential(H)
TC = Atmospheric::Isa.temperature_at_layer_celcius(H)
p_mbar = Atmospheric::Isa.pressure_from_geopotential_mbar(H)
p_mmhg = Atmospheric::Isa.pressure_from_geopotential_mmhg(H)
rho = Atmospheric::Isa.density_from_geopotential(H)
g = Atmospheric::Isa.gravity_at_geopotential(H)
p_p_n = Atmospheric::Isa.p_p_n_from_geopotential(H)
rho_rho_n = Atmospheric::Isa.rho_rho_n_from_geopotential(H)
root_rho_rho_n = Atmospheric::Isa.root_rho_rho_n_from_geopotential(H)
a = Atmospheric::Isa.speed_of_sound_from_geopotential(H)
mu = Atmospheric::Isa.dynamic_viscosity_from_geopotential(H)
v = Atmospheric::Isa.kinematic_viscosity_from_geopotential(H)
lambda = Atmospheric::Isa.thermal_conductivity_from_geopotential(H)
H_p = Atmospheric::Isa.pressure_scale_height_from_geopotential(H)
gamma = Atmospheric::Isa.specific_weight_from_geopotential(H)
n = Atmospheric::Isa.air_number_density_from_geopotential(H)
v_bar = Atmospheric::Isa.mean_air_particle_speed_from_geopotential(H)
omega = Atmospheric::Isa.air_particle_collision_frequency_from_geopotential(H)
l = Atmospheric::Isa.mean_free_path_of_air_particles_from_geopotential(H)

puts ["H = " + H.to_s, "h = " + h.to_s, "TK = " + TK.to_s, "TC = " + TC.to_s, "p_mbar = " + p_mbar.to_s, "p_mmhg = " + p_mmhg.to_s, "rho = " + rho.to_s, "g = " + g.to_s, "p_p_n = " + p_p_n.to_s, "rho_rho_n = " + rho_rho_n.to_s, "root_rho_rho_n = " + root_rho_rho_n.to_s, "a = " + a.to_s, "mu = " + mu.to_s, "v = " + v.to_s, "lambda = " + lambda.to_s, "H_p = " + H_p.to_s, "gamma = " + gamma.to_s, "n = " + n.to_s, "v_bar = " + v_bar.to_s, "omega = " + omega.to_s, "l = " + l.to_s]

Making H a BigDecimal should not be necessary, as the variable gets converted on contact with the BigDecimals in the library, so this works too:

require "atmospheric"

H = 32000.0

#Atmospheric::Isa.set_precision(:normal) # This is the default
Atmospheric::Isa.set_precision(:high)

# ...

But using BigDecimals all along, like in the prior example, would better guard against errors accumulating before the library gets to work on it :)