From d3952545d611b5a37701cc39e948135ed660178e Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Wed, 13 Nov 2024 11:19:52 +0300 Subject: [PATCH] Add files via upload --- CSharp/UCNLPhysics/PHX.cs | 709 ++++++++++++++------------ CSharp/UCNLPhysics/UCNLPhysics.csproj | 5 +- 2 files changed, 393 insertions(+), 321 deletions(-) diff --git a/CSharp/UCNLPhysics/PHX.cs b/CSharp/UCNLPhysics/PHX.cs index 9ab80c9..a541ee0 100644 --- a/CSharp/UCNLPhysics/PHX.cs +++ b/CSharp/UCNLPhysics/PHX.cs @@ -1,319 +1,390 @@ -using System; -using System.Collections.Generic; - -namespace UCNLPhysics -{ - public struct TSProfilePoint - { - public double Z; - public double T; - public double S; - } - - public static class PHX - { - public static readonly double PHX_FWTR_DENSITY_KGM3 = 998.02; // Fresh water density at 20°C - public static readonly double PHX_FWTR_SOUND_SPEED_MPS = 1500.0; // Default speed of sound in water - public static readonly double PHX_FWTR_SOUND_SPEED_MPS_MIN = 1300.0; // Min value for speed of sound - public static readonly double PHX_FWTR_SOUND_SPEED_MPS_MAX = 1600.0; // Max value for speed of sound - public static readonly double PHX_FWTR_SALINITY_PSU = 0.0; // Default water salinity, PSU - public static readonly double PHX_GRAVITY_ACC_MPS2 = 9.80665; // ISO 80000-3:2006 - public static readonly double PHX_ATM_PRESSURE_MBAR = 1013.25; // Average at sea level - - - #region Obsolete - [Obsolete] - public static double PHX_WaterDensity_Calc(double t, double p, double s) - { - return Water_density_calc(t, p, s); - } - - /// - /// The UNESCO equation: Chen and Millero (1977) - /// - /// temperature, Celsius degree - /// pressure, mBar - /// salinity, PSU - /// Speed of sound in m/s - [Obsolete] - public static double PHX_SpeedOfSound_Calc(double t, double p, double s) - { - return Speed_of_sound_UNESCO_calc(t, p, s); - } - - /// - /// calculates gravity at sea level vs latitude - /// WGS84 ellipsoid gravity formula - /// - /// latitude, signed from -90 to 90 - /// Gravity acceleration at sea level, m/s^2 - [Obsolete] - public static double PHX_GravityConstant_Calc(double latitude) - { - return Gravity_constant_wgs84_calc(latitude); - } - - /// - /// Calculates distance from the water surface where pressure is p0 to the point, where pressure is p - /// To take into account compression of the water column the better way to use water density - /// estimated for the point with Pm = (P-P0)/2 - /// - /// pressure, mBar - /// pressure at water surface, mBar - /// water density, kg/m^3 - /// gravity acceleration at sea level, m/s^2 - /// depth (distance from water surface) - [Obsolete] - public static double PHX_DepthByPressure_Calc(double p, double p0, double rho, double g) - { - return Depth_by_pressure_calc(p, p0, rho, g); - } - #endregion - - - // Interpolates a value with given x coordinate by two given points (x1,y1) and (x2,y2) - public static double Linterp(double x1, double y1, double x2, double y2, double x) - { - return y1 + (x - x1) * (y2 - y1) / (x2 - x1); - } - - /// calculates in situ density of water - /// millero et al 1980, deep-sea res.,27a,255-264 - /// jpots ninth report 1978,tenth report 1980 - public static double Water_density_calc(double t, double p, double s) - { - p = p / 1000.0; - double sr = Math.Sqrt(Math.Abs(s)); - double sig = (((4.8314E-4 * s) + - ((-1.6546E-6 * t + 1.0227E-4) * t - 5.72466E-3) * sr + - (((5.3875E-9 * t - 8.2467E-7) * t + 7.6438E-5) * t - 4.0899E-3) * t + 0.824493) * s) + - ((((6.536332E-9 * t - 1.120083E-6) * t + 1.001685E-4) * t - 9.095290E-3) * t + 6.793952E-2) * t - 0.157406; - - double b = ((9.1697E-10 * t + 2.0816E-8) * t - 9.9348E-7) * s + (5.2787E-8 * t - 6.12293E-6) * t + 8.50935E-5; - - double k0 = (((((-5.3009E-4 * t + 1.6483E-2) * t + 7.944E-2) * sr) + - ((-6.1670E-5 * t + 1.09987E-2) * t - 0.603459) * t + 54.6746) * s) + - (((-5.155288E-5 * t + 1.360477E-2) * t - 2.327105) * t + 148.4206) * t + 19652.21; - - double a = (1.91075E-4 * sr + (-1.6078E-6 * t - 1.0981E-5) * t + 2.2838E-3) * s + - ((-5.77905E-7 * t + 1.16092E-4) * t + 1.43713E-3) * t + 3.239908; - - double k = (b * p + a) * p + k0; - - return 1000.0 + (k * sig + 1000.0 * p) / (k - p); - } - - /// The UNESCO equation: Chen and Millero (1977) - public static double Speed_of_sound_UNESCO_calc(double t, double p, double s) - { - p = p / 1000.0; - double sr = Math.Sqrt(Math.Abs(s)); - - double d = 1.727E-3 - 7.9836E-6 * p; - - double b_1 = 7.3637E-5 + 1.7945E-7 * t; - double b_0 = -1.922E-2 - 4.42E-5 * t; - double b = b_0 + b_1 * p; - - double a_3 = (-3.389E-13 * t + 6.649E-12) * t + 1.100E-10; - double a_2 = ((7.988E-12 * t - 1.6002E-10) * t + 9.1041E-9) * t - 3.9064E-7; - double a_1 = (((-2.0122E-10 * t + 1.0507E-8) * t - 6.4885E-8) * t - 1.2580E-5) * t + 9.4742E-5; - double a_0 = (((-3.21E-8 * t + 2.006E-6) * t + 7.164E-5) * t - 1.262E-2) * t + 1.389; - double a = ((a_3 * p + a_2) * p + a_1) * p + a_0; - - double c_3 = (-2.3643E-12 * t + 3.8504E-10) * t - 9.7729E-9; - double c_2 = (((1.0405E-12 * t - 2.5335E-10) * t + 2.5974E-8) * t - 1.7107E-6) * t + 3.1260E-5; - double c_1 = (((-6.1185E-10 * t + 1.3621E-7) * t - 8.1788E-6) * t + 6.8982E-4) * t + 0.153563; - double c_0 = ((((3.1464E-9 * t - 1.47800E-6) * t + 3.3420E-4) * t - 5.80852E-2) * t + 5.03711) * t + 1402.388; - double c = ((c_3 * p + c_2) * p + c_1) * p + c_0; - - return c + (a + b * sr + d * s) * s; - } - - /// Calculates gravity at sea level vs latitude - /// WGS84 ellipsoid gravity formula - public static double Gravity_constant_wgs84_calc(double phi) - { - double phi_sq = Math.Sin(phi * Math.PI / 180.0); - phi_sq *= phi_sq; - return (9.7803253359 * ((1.0 + 0.00193185265241 * phi_sq) / Math.Sqrt(1.0 - 0.00669437999013 * phi_sq))); - } - - /// calculates distance from the water surface where pressure is p0 to the point, where pressure is p - public static double Depth_by_pressure_calc(double p, double p0, double rho, double g) - { - return 100.0 * (p - p0) / (rho * g); - } - - // Calculates pressure of a water column with given height (distance between - // the water surface and the given point) assuming constant water density - // h - depth, m - // p0 - atmospheric pressure, mBar - // rho - water density, kg/m^3 - // g - gravity acceleration, m/s^2 - public static double Pressure_by_depth_calc(double h, double p0, double rho, double g) - { - return h * rho * g / 100.0 + p0; - } - - // Calculates depth (as a distance between the water surface and a point with - // the given pressure) by the specified TS-profile - // pm - pressure measured at the point, mBar - // p0 - atmospheric pressure, mBar - // g - gravity acceleration, m/s^2 - // tsProfile - vertical Temperature-Salinity profile at the given point - // as an array of (f64, f64, f64) - // z - vertical coordinate, m (positive, 0 - water surface) - // t - temperature, °C - // s - salinity, PSU - // Np - number of pressure intervals for integration - public static double Depth_by_pressure_ts_profile(double pm, double p0, double g, int n_p, TSProfilePoint[] ts_profile) - { - if (n_p <= 0) - { - throw new ArgumentOutOfRangeException("Specified number of time intervals Nt should be greater than zero"); - } - - if (ts_profile.Length < 2) - { - throw new ArgumentOutOfRangeException("tsProfile has to contain at least two points"); - } - - double t1 = ts_profile[0].T; - double s1 = ts_profile[0].S; - double rho0 = Water_density_calc(t1, p0, s1); - double p1 = Pressure_by_depth_calc(ts_profile[0].Z, p0, rho0, g); - double pe = Pressure_by_depth_calc(ts_profile[ts_profile.Length - 1].Z, p0, rho0, g); - - if ((pm < p1) || (pm > pe)) - { - throw new ArgumentOutOfRangeException("Specified pressure is beyond the specified TS-profile"); - } - - int p_idx = 1; - double t2 = ts_profile[p_idx].T; - double s2 = ts_profile[p_idx].S; - double p2 = Pressure_by_depth_calc(ts_profile[p_idx].Z, p0, rho0, g); - - double dp = (pm - p0) / n_p; - double h = 0.0, rho, t, p = p0, s; - - while (p < pm) - { - p += dp; - - if (p > p2) - { - - p1 = p2; - t1 = t2; - s1 = s2; - p_idx += 1; - - t2 = ts_profile[p_idx].T; - s2 = ts_profile[p_idx].S; - p2 = Pressure_by_depth_calc(ts_profile[p_idx].Z, p0, rho0, g); - } - - t = Linterp(p1, t1, p2, t2, p); - s = Linterp(p1, s1, p2, s2, p); - - rho = Water_density_calc(t, p, s); - h += 1.0 / rho; - } - - return h * 100.0 * dp / g; - } - - // Calculates the path, which sound traveled in vertical direction - // between the water surface and the deepest point during - // a given time of flight considering given temperature and salinity profile - // tof - time of flight, sec - // Nt - number of time intervals for integration - // tsProfile - vertical Temperature-Salinity profile at the given point - // as an array of TSPoint - // z - vertical coordinate, m (positive, 0 - water surface) - // t - temperature, °C - // s - salinity, PSU - public static double Vertical_sound_path_ts_profile(double tof, double g, int n_t, TSProfilePoint[] ts_profile) - { - - if (ts_profile.Length < 2) - { - throw new ArgumentOutOfRangeException("tsProfile has to contain at least two points"); - } - - if (n_t <= 0) - { - throw new ArgumentOutOfRangeException("Specified number of time intervals Nt should be greater than zero"); - } - - double z1 = ts_profile[0].Z; - double t1 = ts_profile[0].T; - double s1 = ts_profile[0].S; - double rho0 = Water_density_calc(t1, PHX_ATM_PRESSURE_MBAR, s1); - double p1 = Pressure_by_depth_calc(z1, PHX_ATM_PRESSURE_MBAR, rho0, g); - - double v = Speed_of_sound_UNESCO_calc(t1, p1, s1); - - if (v * tof > ts_profile[ts_profile.Length - 1].Z) - { - throw new ArgumentOutOfRangeException("Specified time of flight is beyond the specified TS-profile"); - } - - int p_idx = 1; - double z2 = ts_profile[p_idx].Z; - double t2 = ts_profile[p_idx].T; - double s2 = ts_profile[p_idx].S; - double p2 = Pressure_by_depth_calc(z2, PHX_ATM_PRESSURE_MBAR, rho0, g); - - double dt = tof / n_t; - double h = 0.0; - double t; - double p; - double s; - double tt = 0.0; - - while (tt < tof) - { - - tt += dt; - h = h + dt * v; - - if (h > z2) - { - p1 = p2; - t1 = t2; - s1 = s2; - z1 = z2; - p_idx = p_idx + 1; - - z2 = ts_profile[p_idx].Z; - t2 = ts_profile[p_idx].T; - s2 = ts_profile[p_idx].S; - p2 = Pressure_by_depth_calc(z2, PHX_ATM_PRESSURE_MBAR + p1, rho0, g); - } - - t = Linterp(z1, t1, z2, t2, h); - p = Linterp(z1, p1, z2, p2, h); - s = Linterp(z1, s1, z2, s2, h); - v = Speed_of_sound_UNESCO_calc(t, p, s); - } - - return h; - } - - // Calculated the freezing temperature of seawater (in °C) with specified pressure and salinity. - // According to: - // Algorithms for computation of fundamental properties of seawater. - // Unesco technical papers in marine science vol. 44, 1983, pp. 30 - // https://darchive.mblwhoilibrary.org/bitstream/handle/1912/2470/059832eb.pdf - // p - pressure, mBar - // s - PSU - public static double Water_fpoint_calc(double p, double s) - { - return (-0.0575 + 1.710523E-3 * Math.Sqrt(s) - 2.154996E-4 * s) * s - 7.53E-6 * p; - } - - } -} +using System; +using System.Collections.Generic; + +namespace UCNLPhysics +{ + public struct TSProfilePoint + { + public double Z; + public double T; + public double S; + + public TSProfilePoint(double z, double t, double s) + { + Z = z; + T = t; + S = s; + } + } + + public static class PHX + { + public static readonly double PHX_FWTR_DENSITY_KGM3 = 998.02; // Fresh water density at 20°C + public static readonly double PHX_FWTR_SOUND_SPEED_MPS = 1500.0; // Default speed of sound in water + public static readonly double PHX_FWTR_SOUND_SPEED_MPS_MIN = 1300.0; // Min value for speed of sound + public static readonly double PHX_FWTR_SOUND_SPEED_MPS_MAX = 1600.0; // Max value for speed of sound + public static readonly double PHX_FWTR_SALINITY_PSU = 0.0; // Default water salinity, PSU + public static readonly double PHX_SALINITY_PSU_MIN = 0.0; + public static readonly double PHX_SALINITY_PSU_MAX = 44.0; + public static readonly double PHX_GRAVITY_ACC_MPS2 = 9.80665; // ISO 80000-3:2006 + public static readonly double PHX_GRAVITY_ACC_MPS2_MIN = 9.7639; + public static readonly double PHX_GRAVITY_ACC_MPS2_MAX = 9.8337; + + public static readonly double PHX_ATM_PRESSURE_MBAR = 1013.25; // Average at sea level + + #region Obsolete + [Obsolete] + public static double PHX_WaterDensity_Calc(double t, double p, double s) + { + return Water_density_calc(t, p, s); + } + + /// + /// The UNESCO equation: Chen and Millero (1977) + /// + /// temperature, Celsius degree + /// pressure, mBar + /// salinity, PSU + /// Speed of sound in m/s + [Obsolete] + public static double PHX_SpeedOfSound_Calc(double t, double p, double s) + { + return Speed_of_sound_UNESCO_calc(t, p, s); + } + + /// + /// calculates gravity at sea level vs latitude + /// WGS84 ellipsoid gravity formula + /// + /// latitude, signed from -90 to 90 + /// Gravity acceleration at sea level, m/s^2 + [Obsolete] + public static double PHX_GravityConstant_Calc(double latitude) + { + return Gravity_constant_wgs84_calc(latitude); + } + + /// + /// Calculates distance from the water surface where pressure is p0 to the point, where pressure is p + /// To take into account compression of the water column the better way to use water density + /// estimated for the point with Pm = (P-P0)/2 + /// + /// pressure, mBar + /// pressure at water surface, mBar + /// water density, kg/m^3 + /// gravity acceleration at sea level, m/s^2 + /// depth (distance from water surface) + [Obsolete] + public static double PHX_DepthByPressure_Calc(double p, double p0, double rho, double g) + { + return Depth_by_pressure_calc(p, p0, rho, g); + } + #endregion + + // Interpolates a value with given x coordinate by two given points (x1,y1) and (x2,y2) + public static double Linterp(double x1, double y1, double x2, double y2, double x) + { + return y1 + (x - x1) * (y2 - y1) / (x2 - x1); + } + + /// calculates in situ density of water + /// millero et al 1980, deep-sea res.,27a,255-264 + /// jpots ninth report 1978,tenth report 1980 + public static double Water_density_calc(double t, double p, double s) + { + p = p / 1000.0; + double sr = Math.Sqrt(Math.Abs(s)); + double sig = (((4.8314E-4 * s) + + ((-1.6546E-6 * t + 1.0227E-4) * t - 5.72466E-3) * sr + + (((5.3875E-9 * t - 8.2467E-7) * t + 7.6438E-5) * t - 4.0899E-3) * t + 0.824493) * s) + + ((((6.536332E-9 * t - 1.120083E-6) * t + 1.001685E-4) * t - 9.095290E-3) * t + 6.793952E-2) * t - 0.157406; + + double b = ((9.1697E-10 * t + 2.0816E-8) * t - 9.9348E-7) * s + (5.2787E-8 * t - 6.12293E-6) * t + 8.50935E-5; + + double k0 = (((((-5.3009E-4 * t + 1.6483E-2) * t + 7.944E-2) * sr) + + ((-6.1670E-5 * t + 1.09987E-2) * t - 0.603459) * t + 54.6746) * s) + + (((-5.155288E-5 * t + 1.360477E-2) * t - 2.327105) * t + 148.4206) * t + 19652.21; + + double a = (1.91075E-4 * sr + (-1.6078E-6 * t - 1.0981E-5) * t + 2.2838E-3) * s + + ((-5.77905E-7 * t + 1.16092E-4) * t + 1.43713E-3) * t + 3.239908; + + double k = (b * p + a) * p + k0; + + return 1000.0 + (k * sig + 1000.0 * p) / (k - p); + } + + /// The UNESCO equation: Chen and Millero (1977) + public static double Speed_of_sound_UNESCO_calc(double t, double p, double s) + { + var t2 = t * t; + var t3 = t2 * t; + var t4 = t3 * t; + p = p / 1000.0; + var p2 = p * p; + var p3 = p2 * p; + + var Cw = (1402.388 + 5.03830 * t + -5.81090E-2 * t2 + 3.3432E-4 * t3 + -1.47797E-6 * t4 + 3.1419E-9 * t4 * t) + + (0.153563 + 6.8999E-4 * t + -8.1829E-6 * t2 + 1.3632E-7 * t3 + -6.1260E-10 * t4) * p + + (3.1260E-5 + -1.7111E-6 * t + 2.5986E-8 * t2 + -2.5353E-10 * t3 + 1.0415E-12 * t4) * p2 + + (-9.7729E-9 + 3.8513E-10 * t + -2.3654E-12 * t2) * p3; + + var A = (1.389 + -1.262E-2 * t + 7.166E-5 * t2 + 2.008E-6 * t3 + -3.21E-8 * t4) + + (9.4742E-5 + -1.2583E-5 * t + -6.4928E-8 * t2 + 1.0515E-8 * t3 + -2.0142E-10 * t4) * p + + (-3.9064E-7 + 9.1061E-9 * t + -1.6009E-10 * t2 + 7.994E-12 * t3) * p2 + + (1.100E-10 + 6.651E-12 * t + -3.391E-13 * t2) * p3; + + var B = -1.922E-2 + -4.42E-5 * t + (7.3637E-5 + 1.7950E-7 * t) * p; + + var D = 1.727E-3 + -7.9836E-6 * p; + + return Cw + A * s + B * Math.Sqrt(s * s * s) + D * s * s; + + } + + /// Calculates gravity at sea level vs latitude + /// WGS84 ellipsoid gravity formula + /// phi in degrees + public static double Gravity_constant_wgs84_calc(double phi) + { + double phi_sq = Math.Sin(phi * Math.PI / 180.0); + phi_sq *= phi_sq; + return (9.7803253359 * ((1.0 + 0.00193185265241 * phi_sq) / Math.Sqrt(1.0 - 0.00669437999013 * phi_sq))); + } + + /// calculates distance from the water surface where pressure is p0 to the point, where pressure is p + public static double Depth_by_pressure_calc(double p, double p0, double rho, double g) + { + return 100.0 * (p - p0) / (rho * g); + } + + // Calculates pressure of a water column with given height (distance between + // the water surface and the given point) assuming constant water density + // h - depth, m + // p0 - atmospheric pressure, mBar + // rho - water density, kg/m^3 + // g - gravity acceleration, m/s^2 + public static double Pressure_by_depth_calc(double h, double p0, double rho, double g) + { + return h * rho * g / 100.0 + p0; + } + + // Calculates depth (as a distance between the water surface and a point with + // the given pressure) by the specified TS-profile + // pm - pressure measured at the point, mBar + // p0 - atmospheric pressure, mBar + // g - gravity acceleration, m/s^2 + // tsProfile - vertical Temperature-Salinity profile at the given point + // as an array of (f64, f64, f64) + // z - vertical coordinate, m (positive, 0 - water surface) + // t - temperature, °C + // s - salinity, PSU + // Np - number of pressure intervals for integration + public static double Depth_by_pressure_ts_profile(double pm, double p0, double g, int n_p, TSProfilePoint[] ts_profile) + { + if (n_p <= 0) + { + throw new ArgumentOutOfRangeException("Specified number of time intervals Nt should be greater than zero"); + } + + if (ts_profile.Length < 2) + { + throw new ArgumentOutOfRangeException("tsProfile has to contain at least two points"); + } + + double t1 = ts_profile[0].T; + double s1 = ts_profile[0].S; + double rho0 = Water_density_calc(t1, p0, s1); + double p1 = Pressure_by_depth_calc(ts_profile[0].Z, p0, rho0, g); + double pe = Pressure_by_depth_calc(ts_profile[ts_profile.Length - 1].Z, p0, rho0, g); + + if ((pm < p1) || (pm > pe)) + { + throw new ArgumentOutOfRangeException("Specified pressure is beyond the specified TS-profile"); + } + + int p_idx = 1; + double t2 = ts_profile[p_idx].T; + double s2 = ts_profile[p_idx].S; + double p2 = Pressure_by_depth_calc(ts_profile[p_idx].Z, p0, rho0, g); + + double dp = (pm - p0) / n_p; + double h = 0.0, rho, t, p = p0, s; + + while (p < pm) + { + p += dp; + + if (p > p2) + { + + p1 = p2; + t1 = t2; + s1 = s2; + p_idx += 1; + + t2 = ts_profile[p_idx].T; + s2 = ts_profile[p_idx].S; + p2 = Pressure_by_depth_calc(ts_profile[p_idx].Z, p0, rho0, g); + } + + t = Linterp(p1, t1, p2, t2, p); + s = Linterp(p1, s1, p2, s2, p); + + rho = Water_density_calc(t, p, s); + h += 1.0 / rho; + } + + return h * 100.0 * dp / g; + } + + // Calculates the path, which sound traveled in vertical direction + // between the water surface and the deepest point during + // a given time of flight considering given temperature and salinity profile + // tof - time of flight, sec + // Nt - number of time intervals for integration + // tsProfile - vertical Temperature-Salinity profile at the given point + // as an array of TSPoint + // z - vertical coordinate, m (positive, 0 - water surface) + // t - temperature, °C + // s - salinity, PSU + public static double Vertical_sound_path_ts_profile(double tof, double g, int n_t, TSProfilePoint[] ts_profile) + { + + if (ts_profile.Length < 2) + { + throw new ArgumentOutOfRangeException("tsProfile has to contain at least two points"); + } + + if (n_t <= 0) + { + throw new ArgumentOutOfRangeException("Specified number of time intervals Nt should be greater than zero"); + } + + double z1 = ts_profile[0].Z; + double t1 = ts_profile[0].T; + double s1 = ts_profile[0].S; + double rho0 = Water_density_calc(t1, PHX_ATM_PRESSURE_MBAR, s1); + double p1 = Pressure_by_depth_calc(z1, PHX_ATM_PRESSURE_MBAR, rho0, g); + + double v = Speed_of_sound_UNESCO_calc(t1, p1, s1); + + if (v * tof > ts_profile[ts_profile.Length - 1].Z) + { + throw new ArgumentOutOfRangeException("Specified time of flight is beyond the specified TS-profile"); + } + + int p_idx = 1; + double z2 = ts_profile[p_idx].Z; + double t2 = ts_profile[p_idx].T; + double s2 = ts_profile[p_idx].S; + double p2 = Pressure_by_depth_calc(z2, PHX_ATM_PRESSURE_MBAR, rho0, g); + + double dt = tof / n_t; + double h = 0.0; + double t; + double p; + double s; + double tt = 0.0; + + while (tt < tof) + { + + tt += dt; + h = h + dt * v; + + if (h > z2) + { + p1 = p2; + t1 = t2; + s1 = s2; + z1 = z2; + p_idx = p_idx + 1; + + z2 = ts_profile[p_idx].Z; + t2 = ts_profile[p_idx].T; + s2 = ts_profile[p_idx].S; + p2 = Pressure_by_depth_calc(z2, PHX_ATM_PRESSURE_MBAR + p1, rho0, g); + } + + t = Linterp(z1, t1, z2, t2, h); + p = Linterp(z1, p1, z2, p2, h); + s = Linterp(z1, s1, z2, s2, h); + v = Speed_of_sound_UNESCO_calc(t, p, s); + } + + return h; + } + + // Calculated the freezing temperature of seawater (in °C) with specified pressure and salinity. + // According to: + // Algorithms for computation of fundamental properties of seawater. + // Unesco technical papers in marine science vol. 44, 1983, pp. 30 + // https://darchive.mblwhoilibrary.org/bitstream/handle/1912/2470/059832eb.pdf + // p - pressure, mBar + // s - PSU + public static double Water_fpoint_calc(double p, double s) + { + return (-0.0575 + 1.710523E-3 * Math.Sqrt(s) - 2.154996E-4 * s) * s - 7.53E-6 * p; + } + + // calculation of absorption according to: + // Francois & Garrison, J. Acoust. Soc. Am., Vol. 72, No. 6, December 1982 + // f frequency (kHz) + // T Temperature (degC) + // S Salinity (ppt) + // D Depth (m) + // pH Acidity + public static double Alpha_e_FrancoisGarrison_calc(double f, double t, double s, double h, double pH) + { + // For f = 1..500 kHz: + // -2 < T < 22 °C + // 30 < S < 35 PSU + // 0 < D < 3.5 km + + // For f > 500 kHz: + + // 0 < T < 30 °C + // 0 < S < 40 PSU + // 0 < D < 10 km + + // Total absorption = Boric Acid Contrib. + Magnesium Sulphate Contrib. + Pure Water Contrib. + + // Measured ambient temp + double t_kel = 273.15 + t; + double fsq = f * f; + + // Calculate speed of sound (according to Francois & Garrison, JASA 72 (6) p1886) + double c = 1412 + 3.21 * t + 1.19 * s + 0.0167 * h; + + // Boric acid contribution + double A1 = (8.86 / c) * Math.Pow(10, 0.78 * pH - 5.0); + double P1 = 1; + double f1 = 2.8 * Math.Sqrt(s / 35) * Math.Pow(10, 4.0 - 1245 / t_kel); + double Boric = (A1 * P1 * f1 * fsq) / (fsq + f1 * f1); + + // MgSO4 contribution + double A2 = 21.44 * (s / c) * (1 + 0.025 * t); + double P2 = 1 - 1.37E-4 * h + 6.2E-9 * h * h; + double f2 = (8.17 * Math.Pow(10, 8 - 1990 / t_kel)) / (1 + 0.0018 * (s - 35)); + double MgSO4 = (A2 * P2 * f2 * fsq) / (fsq + f2 * f2); + + // Pure water contribution + double A3; + if (t <= 20) + { + A3 = 4.937E-4 - 2.59E-5 * t + 9.11E-7 * t * t - 1.5E-8 * t * t * t; + } + else + { + A3 = 3.964E-4 - 1.146E-5 * t + 1.45E-7 * t * t - 6.5E-10 * t * t * t; + } + + double P3 = 1 - 3.83E-5 * h + 4.9E-10 * h * h; + double H2O = A3 * P3 * fsq; + + // Total absorption + return Boric + MgSO4 + H2O; + } + + } +} diff --git a/CSharp/UCNLPhysics/UCNLPhysics.csproj b/CSharp/UCNLPhysics/UCNLPhysics.csproj index 6d61c1a..12b98d4 100644 --- a/CSharp/UCNLPhysics/UCNLPhysics.csproj +++ b/CSharp/UCNLPhysics/UCNLPhysics.csproj @@ -1,5 +1,5 @@  - + Debug @@ -9,8 +9,9 @@ Properties UCNLPhysics UCNLPhysics - v4.5 + v4.8 512 + true