From 1e6c54f94f15a48f5ffa39dbc870e0a5197349ad Mon Sep 17 00:00:00 2001 From: "Christopher H. Jordan" Date: Wed, 9 Mar 2022 11:00:19 +0800 Subject: [PATCH] Overhaul "list" flux density estimation. The code is now simpler and allows for negative and positive "measurements" to be included in a list (a linear fit is used rather than a spectral index). Tracing log messages can also be emitted; these have no cost if the log level is not that low. This commit slightly changes expected visibility values in a test. Not entirely sure why... --- srclist/src/types/flux_density/mod.rs | 135 +++++++------- srclist/src/types/flux_density/tests.rs | 188 +++++++++++++++++--- tests/integration/modelling/calibrate.rs | 8 +- tests/integration/modelling/simulate_vis.rs | 160 ++++++++--------- 4 files changed, 307 insertions(+), 184 deletions(-) diff --git a/srclist/src/types/flux_density/mod.rs b/srclist/src/types/flux_density/mod.rs index 94e9c04f..917dd196 100644 --- a/srclist/src/types/flux_density/mod.rs +++ b/srclist/src/types/flux_density/mod.rs @@ -7,12 +7,13 @@ #[cfg(test)] mod tests; +use log::{log_enabled, trace, Level::Trace}; use marlu::Jones; use serde::{Deserialize, Serialize}; use vec1::Vec1; use crate::constants::*; -use mwa_hyperdrive_common::{marlu, vec1, Complex}; +use mwa_hyperdrive_common::{log, marlu, vec1, Complex}; #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] /// At a frequency, four flux densities for each Stokes parameter. @@ -43,8 +44,8 @@ pub struct FluxDensity { impl FluxDensity { /// Given two flux densities, calculate the spectral index that fits them. /// Uses only Stokes I. - pub fn calc_spec_index(&self, fd2: &Self) -> f64 { - (fd2.i.abs() / self.i.abs()).ln() / (fd2.freq / self.freq).ln() + pub(super) fn calc_spec_index(&self, fd2: &Self) -> f64 { + (fd2.i / self.i).ln() / (fd2.freq / self.freq).ln() } /// Convert a `FluxDensity` into a [Jones] matrix representing instrumental @@ -120,6 +121,8 @@ impl FluxDensityType { /// Stokes I component, so any other Stokes parameters may be poorly /// estimated. pub fn estimate_at_freq(&self, freq_hz: f64) -> FluxDensity { + let we_should_trace_log = log_enabled!(Trace); + match self { FluxDensityType::PowerLaw { si, fd } => { let ratio = calc_flux_ratio(freq_hz, fd.freq, *si); @@ -136,8 +139,6 @@ impl FluxDensityType { } FluxDensityType::List { fds } => { - let mut old_freq = -1.0; - // `smaller_flux_density` is a bad name given to the component's flux // density corresponding to a frequency smaller than but nearest to the // specified frequency. @@ -145,69 +146,77 @@ impl FluxDensityType { // If there's only one source component, then we must assume the // spectral index for extrapolation. if fds.len() == 1 { - // trace!("Only one flux density in a component's list; extrapolating with spectral index {}", DEFAULT_SPEC_INDEX); + if we_should_trace_log { + trace!("Only one flux density in a component's list; extrapolating with spectral index {}", DEFAULT_SPEC_INDEX); + } (DEFAULT_SPEC_INDEX, &fds[0]) } - // Otherwise, find the frequencies that bound the given frequency. As we - // assume that the input source components are sorted by frequency, we - // can assume that the comp. with the smallest frequency is at index 0, - // and similarly for the last component. + // Otherwise, find the two closest `FluxDensity`s closest to + // the given frequency. We enforce that the input list of + // `FluxDensity`s is sorted by frequency. else { - let mut smaller_comp_index: usize = 0; - let mut larger_comp_index: usize = fds.len() - 1; - for (i, fd) in fds.iter().enumerate() { - let f = fd.freq; - // Bail if this frequency is smaller than the old - // frequency; we require the list of flux densities - // to be sorted by frequency. - if f < old_freq { + let mut pair: (&FluxDensity, &FluxDensity) = (&fds[0], &fds[1]); + for window in fds.windows(2) { + // Bail if the frequencies are out of order. + if window[1].freq < window[0].freq { panic!("The list of flux densities used for estimation were not sorted"); } - old_freq = f; - // Iterate until we hit a catalogue frequency bigger than the - // desired frequency. + pair = (&window[0], &window[1]); - // If this freq and the specified freq are the same... - if (f - freq_hz).abs() < 1e-3 { - // ... then just return the flux density information from - // this frequency. - return fd.clone(); + // If either element's and the specified freq are the same... + if (window[0].freq - freq_hz).abs() < 1e-3 { + // ... then just return the flux density + // information from this frequency. + return window[0].clone(); } - // If this freq is smaller than the specified freq... - else if f < freq_hz { - // Check if we've iterated to the last catalogue component - - // if so, then we must extrapolate (i.e. the specified - // freq. is bigger than all catalogue frequencies). - if i == fds.len() - 1 { - smaller_comp_index = fds.len() - 2; - } + if (window[1].freq - freq_hz).abs() < 1e-3 { + return window[1].clone(); } - // We only arrive here if f > freq. - else { - // Because the array is sorted, we now know the closest two - // frequencies. The only exception is if this is the first - // catalogue frequency (i.e. the desired freq is smaller - // than all catalogue freqs -> extrapolate). - if i == 0 { - larger_comp_index = 1; - } else { - smaller_comp_index = i - 1; - } + // If the specified freq is smaller than the second + // element... + if freq_hz < window[1].freq { + // ... we're done. break; } } - let mut spec_index = - fds[smaller_comp_index].calc_spec_index(&fds[larger_comp_index]); + // We now have the two relevant flux densities (on + // either side of the target frequency, or the two + // closest to the target frequency). If one is positive + // and one negative, we have to use a linear fit, not a + // spectral index. + let (fd1, fd2) = pair; + if pair.0.i.signum() != pair.1.i.signum() { + let i_rise = fd2.i - fd1.i; + let q_rise = fd2.q - fd1.q; + let u_rise = fd2.u - fd1.u; + let v_rise = fd2.v - fd1.v; + let run = fd2.freq - fd1.freq; + let i_slope = i_rise / run; + let q_slope = q_rise / run; + let u_slope = u_rise / run; + let v_slope = v_rise / run; + return FluxDensity { + freq: freq_hz, + i: fd1.i + i_slope * (freq_hz - fd1.freq), + q: fd1.q + q_slope * (freq_hz - fd1.freq), + u: fd1.u + u_slope * (freq_hz - fd1.freq), + v: fd1.v + v_slope * (freq_hz - fd1.freq), + }; + } + + let mut spec_index = fd1.calc_spec_index(fd2); // Stop stupid spectral indices. if spec_index < SPEC_INDEX_CAP { - // trace!( - // "Component had a spectral index {}; capping at {}", - // spec_index, - // SPEC_INDEX_CAP - // ); + if we_should_trace_log { + trace!( + "Component had a spectral index {}; capping at {}", + spec_index, + SPEC_INDEX_CAP + ); + } spec_index = SPEC_INDEX_CAP; } @@ -215,11 +224,7 @@ impl FluxDensityType { spec_index, // If our last component's frequency is smaller than the specified // freq., then we should use that for flux densities. - if fds[larger_comp_index].freq < freq_hz { - &fds[larger_comp_index] - } else { - &fds[smaller_comp_index] - }, + if fd2.freq < freq_hz { fd2 } else { fd1 }, ) } }; @@ -227,27 +232,17 @@ impl FluxDensityType { // Now scale the flux densities given the calculated // spectral index. let flux_ratio = calc_flux_ratio(freq_hz, smaller_flux_density.freq, spec_index); - let fd = FluxDensity { + FluxDensity { freq: freq_hz, ..*smaller_flux_density - } * flux_ratio; - - // Handle NaNs by setting the flux densities to 0. - if fd.i.is_nan() { - FluxDensity { - freq: fd.freq, - ..Default::default() - } - } else { - fd - } + } * flux_ratio } } } } /// Given a spectral index, determine the flux-density ratio of two frequencies. -pub fn calc_flux_ratio(desired_freq_hz: f64, cat_freq_hz: f64, spec_index: f64) -> f64 { +pub(crate) fn calc_flux_ratio(desired_freq_hz: f64, cat_freq_hz: f64, spec_index: f64) -> f64 { (desired_freq_hz / cat_freq_hz).powf(spec_index) } diff --git a/srclist/src/types/flux_density/tests.rs b/srclist/src/types/flux_density/tests.rs index a2834682..00c80ce0 100644 --- a/srclist/src/types/flux_density/tests.rs +++ b/srclist/src/types/flux_density/tests.rs @@ -31,65 +31,195 @@ fn calc_freq_ratio_2() { } #[test] -#[ignore] -// TODO: Fix! fn estimate_with_negative_fds() { - // MLT011814-4027 from LoBES + // All negative to start with. let fdt = FluxDensityType::List { fds: vec1![ FluxDensity { - freq: 130e6, - i: -0.006830723490566015, + freq: 150e6, + i: -1.0, ..Default::default() }, FluxDensity { - freq: 143e6, - i: -0.027053141966462135, + freq: 175e6, + i: -3.0, ..Default::default() }, FluxDensity { - freq: 151e6, - i: -0.038221485912799835, + freq: 200e6, + i: -2.0, + ..Default::default() + } + ], + }; + assert_abs_diff_eq!( + fdt.estimate_at_freq(140e6), + FluxDensity { + freq: 140e6, + // Using the FDs with 150 and 175 MHz, SI = 0.611. + i: -0.611583722518741, + ..Default::default() + } + ); + assert_abs_diff_eq!( + fdt.estimate_at_freq(150e6), + FluxDensity { + freq: 150e6, + // Exact match. + i: -1.0, + ..Default::default() + } + ); + assert_abs_diff_eq!( + fdt.estimate_at_freq(160e6), + FluxDensity { + freq: 160e6, + // Spec index 7.126. + i: -1.584007188344133, + ..Default::default() + } + ); + assert_abs_diff_eq!( + fdt.estimate_at_freq(190e6), + FluxDensity { + freq: 190e6, + // Spectral index would be -3.036, but it gets capped to -2. + i: -2.545013850415513, + ..Default::default() + } + ); + assert_abs_diff_eq!( + fdt.estimate_at_freq(210e6), + FluxDensity { + freq: 210e6, + // Spectral index would be -3.036, but it gets capped to -2. + i: -1.8140589569160996, + ..Default::default() + } + ); + + // One negative, one positive. + let fdt = FluxDensityType::List { + fds: vec1![ + FluxDensity { + freq: 100e6, + i: -1.0, ..Default::default() }, FluxDensity { - freq: 166e6, - i: 0.08616726100444794, + freq: 200e6, + i: 1.0, ..Default::default() }, + ], + }; + let fds = match &fdt { + FluxDensityType::List { fds } => fds, + _ => unreachable!(), + }; + let desired_freq = 90e6; + let result = fdt.estimate_at_freq(desired_freq); + let expected = FluxDensity { + freq: desired_freq, + // IQUV are increased/decreased with the straight line fit between the + // positive and negative FDs. + i: fds[0].i - 0.2, + q: 0.0, + u: 0.0, + v: 0.0, + }; + assert_abs_diff_eq!(result, expected); + + let desired_freq = 210e6; + let result = fdt.estimate_at_freq(desired_freq); + let expected = FluxDensity { + freq: desired_freq, + i: fds[1].i + 0.2, + q: 0.0, + u: 0.0, + v: 0.0, + }; + assert_abs_diff_eq!(result, expected); + + let desired_freq = 150e6; + let result = fdt.estimate_at_freq(desired_freq); + let expected = FluxDensity { + freq: desired_freq, + i: 0.0, + q: 0.0, + u: 0.0, + v: 0.0, + }; + assert_abs_diff_eq!(result, expected); + + // Two negative, one positive. + let fdt = FluxDensityType::List { + fds: vec1![ FluxDensity { - freq: 174e6, - i: 0.11915085464715958, + freq: 100e6, + i: -1.0, ..Default::default() }, FluxDensity { - freq: 181e6, - i: 0.06860895454883575, + freq: 150e6, + i: -0.5, + ..Default::default() + }, + FluxDensity { + freq: 200e6, + i: 1.0, ..Default::default() }, ], }; - let desired_freq = 136.5e6; + let fds = match &fdt { + FluxDensityType::List { fds } => fds, + _ => unreachable!(), + }; + let desired_freq = 90e6; + let result = fdt.estimate_at_freq(desired_freq); + // A spectral index is used for frequencies < 150e6. + let spec_index = (fds[1].i / fds[0].i).ln() / (fds[1].freq / fds[0].freq).ln(); + let ratio = calc_flux_ratio(desired_freq, fds[0].freq, spec_index); + let expected = FluxDensity { + freq: desired_freq, + ..fds[0] + } * ratio; + assert_abs_diff_eq!(result, expected); + assert_abs_diff_eq!(result.i, -1.1973550404744007); + + let desired_freq = 145e6; let result = fdt.estimate_at_freq(desired_freq); - let si = (0.027053141966462135_f64 / 0.006830723490566015).ln() / (143e6_f64 / 130e6).ln(); - let flux_ratio = calc_flux_ratio(desired_freq, 130e6, si); + let ratio = calc_flux_ratio(desired_freq, fds[0].freq, spec_index); let expected = FluxDensity { freq: desired_freq, - i: -0.004744315639, - ..Default::default() - } * flux_ratio; - assert_abs_diff_eq!(result, expected, epsilon = 1e-10); + ..fds[0] + } * ratio; + assert_abs_diff_eq!(result, expected); + assert_abs_diff_eq!(result.i, -0.5298337000434852); - let desired_freq = 158.5e6; + // The straight line is used again > 150e6. + let desired_freq = 155e6; let result = fdt.estimate_at_freq(desired_freq); - let si = (0.08616726100444794_f64 / 0.038221485912799835).ln() / (166e6_f64 / 151e6).ln(); - let flux_ratio = calc_flux_ratio(desired_freq, 151e6, si); let expected = FluxDensity { freq: desired_freq, - i: -0.013818502583985523, - ..Default::default() - } * flux_ratio; - assert_abs_diff_eq!(result, expected, epsilon = 1e-10); + i: fds[1].i + 1.5 / 50.0 * 5.0, + q: 0.0, + u: 0.0, + v: 0.0, + }; + assert_abs_diff_eq!(result, expected); + + let desired_freq = 210e6; + let result = fdt.estimate_at_freq(desired_freq); + let expected = FluxDensity { + freq: desired_freq, + i: fds[2].i + 1.5 / 50.0 * 10.0, + q: 0.0, + u: 0.0, + v: 0.0, + }; + assert_abs_diff_eq!(result, expected); } #[test] diff --git a/tests/integration/modelling/calibrate.rs b/tests/integration/modelling/calibrate.rs index d9ab7b06..78407297 100644 --- a/tests/integration/modelling/calibrate.rs +++ b/tests/integration/modelling/calibrate.rs @@ -5,13 +5,14 @@ //! Integration tests for sky-model visibilities generated during calibration. use approx::{assert_abs_diff_eq, assert_abs_diff_ne}; +use marlu::Jones; use mwalib::{fitsio_sys, *}; use ndarray::prelude::*; use serial_test::serial; use crate::*; use mwa_hyperdrive::calibrate::solutions::CalibrationSolutions; -use mwa_hyperdrive_common::{mwalib, ndarray}; +use mwa_hyperdrive_common::{marlu, mwalib, ndarray}; #[test] #[serial] @@ -168,10 +169,7 @@ fn test_1090008640_calibrate_model() { let sols = result.unwrap(); assert_abs_diff_eq!( sols.di_jones.mapv(TestJones::from), - Array3::from_elem( - sols.di_jones.dim(), - TestJones::from([1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0]) - ), + Array3::from_elem(sols.di_jones.dim(), TestJones::from(Jones::identity())), epsilon = 1e-15 ); } diff --git a/tests/integration/modelling/simulate_vis.rs b/tests/integration/modelling/simulate_vis.rs index ea56389b..9c09fdda 100644 --- a/tests/integration/modelling/simulate_vis.rs +++ b/tests/integration/modelling/simulate_vis.rs @@ -189,47 +189,47 @@ fn test_1090008640_simulate_vis() { // The values of the visibilities changes slightly depending on the precision. cfg_if::cfg_if! { if #[cfg(feature = "cuda-single")] { - assert_abs_diff_eq!(vis[0], 36.747265); - assert_abs_diff_eq!(vis[1], -37.801533); - assert_abs_diff_eq!(vis[3], 36.47097); - assert_abs_diff_eq!(vis[4], -38.022476); - assert_abs_diff_eq!(vis[6], 0.12832667); - assert_abs_diff_eq!(vis[7], -0.07697471); - assert_abs_diff_eq!(vis[9], 0.13588743); - assert_abs_diff_eq!(vis[10], -0.051935546); - assert_abs_diff_eq!(vis[12], 36.68455); - assert_abs_diff_eq!(vis[13], -37.85039); - assert_abs_diff_eq!(vis[15], 36.418015); - assert_abs_diff_eq!(vis[16], -38.07826); - assert_abs_diff_eq!(vis[18], 0.13196859); - assert_abs_diff_eq!(vis[19], -0.0752564); - assert_abs_diff_eq!(vis[21], 0.13948323); - assert_abs_diff_eq!(vis[22], -0.05024762); - assert_abs_diff_eq!(vis[24], 36.61832); - assert_abs_diff_eq!(vis[25], -37.89711); - assert_abs_diff_eq!(vis[27], 36.361664); - assert_abs_diff_eq!(vis[28], -38.132008); + assert_abs_diff_eq!(vis[0], 36.740784); + assert_abs_diff_eq!(vis[1], -37.80606); + assert_abs_diff_eq!(vis[3], 36.464603); + assert_abs_diff_eq!(vis[4], -38.02713); + assert_abs_diff_eq!(vis[6], 0.12835015); + assert_abs_diff_eq!(vis[7], -0.07698194); + assert_abs_diff_eq!(vis[9], 0.13591044); + assert_abs_diff_eq!(vis[10], -0.051941235); + assert_abs_diff_eq!(vis[12], 36.677784); + assert_abs_diff_eq!(vis[13], -37.855076); + assert_abs_diff_eq!(vis[15], 36.411377); + assert_abs_diff_eq!(vis[16], -38.083076); + assert_abs_diff_eq!(vis[18], 0.13199334); + assert_abs_diff_eq!(vis[19], -0.07526353); + assert_abs_diff_eq!(vis[21], 0.13950741); + assert_abs_diff_eq!(vis[22], -0.050253063); + assert_abs_diff_eq!(vis[24], 36.61131); + assert_abs_diff_eq!(vis[25], -37.901936); + assert_abs_diff_eq!(vis[27], 36.354816); + assert_abs_diff_eq!(vis[28], -38.13698); } else { - assert_abs_diff_eq!(vis[0], 36.747486); - assert_abs_diff_eq!(vis[1], -37.80138); - assert_abs_diff_eq!(vis[3], 36.471222); - assert_abs_diff_eq!(vis[4], -38.022335); - assert_abs_diff_eq!(vis[6], 0.12833099); - assert_abs_diff_eq!(vis[7], -0.07697737); - assert_abs_diff_eq!(vis[9], 0.13589254); - assert_abs_diff_eq!(vis[10], -0.05193789); - assert_abs_diff_eq!(vis[12], 36.68475); - assert_abs_diff_eq!(vis[13], -37.850204); - assert_abs_diff_eq!(vis[15], 36.41824); - assert_abs_diff_eq!(vis[16], -38.078094); - assert_abs_diff_eq!(vis[18], 0.13197264); - assert_abs_diff_eq!(vis[19], -0.07525928); - assert_abs_diff_eq!(vis[21], 0.13948803); - assert_abs_diff_eq!(vis[22], -0.050250113); - assert_abs_diff_eq!(vis[24], 36.618553); - assert_abs_diff_eq!(vis[25], -37.896935); - assert_abs_diff_eq!(vis[27], 36.361942); - assert_abs_diff_eq!(vis[28], -38.13186); + assert_abs_diff_eq!(vis[0], 36.740982); + assert_abs_diff_eq!(vis[1], -37.80591); + assert_abs_diff_eq!(vis[3], 36.464863); + assert_abs_diff_eq!(vis[4], -38.02699); + assert_abs_diff_eq!(vis[6], 0.12835437); + assert_abs_diff_eq!(vis[7], -0.07698456); + assert_abs_diff_eq!(vis[9], 0.13591558); + assert_abs_diff_eq!(vis[10], -0.05194349); + assert_abs_diff_eq!(vis[12], 36.677994); + assert_abs_diff_eq!(vis[13], -37.85488); + assert_abs_diff_eq!(vis[15], 36.411633); + assert_abs_diff_eq!(vis[16], -38.08291); + assert_abs_diff_eq!(vis[18], 0.13199718); + assert_abs_diff_eq!(vis[19], -0.075266466); + assert_abs_diff_eq!(vis[21], 0.1395122); + assert_abs_diff_eq!(vis[22], -0.050255615); + assert_abs_diff_eq!(vis[24], 36.61154); + assert_abs_diff_eq!(vis[25], -37.901764); + assert_abs_diff_eq!(vis[27], 36.355083); + assert_abs_diff_eq!(vis[28], -38.136826); } } // Every third value (a weight) should be 1. @@ -271,47 +271,47 @@ fn test_1090008640_simulate_vis() { cfg_if::cfg_if! { if #[cfg(feature = "cuda-single")] { - assert_abs_diff_eq!(vis[0], 36.806145); - assert_abs_diff_eq!(vis[1], -37.706573); - assert_abs_diff_eq!(vis[3], 36.52608); - assert_abs_diff_eq!(vis[4], -37.917084); - assert_abs_diff_eq!(vis[6], 0.12915021); - assert_abs_diff_eq!(vis[7], -0.07719816); - assert_abs_diff_eq!(vis[9], 0.1368717); - assert_abs_diff_eq!(vis[10], -0.052241363); - assert_abs_diff_eq!(vis[12], 36.741222); - assert_abs_diff_eq!(vis[13], -37.755745); - assert_abs_diff_eq!(vis[15], 36.4707); - assert_abs_diff_eq!(vis[16], -37.973244); - assert_abs_diff_eq!(vis[18], 0.13278112); - assert_abs_diff_eq!(vis[19], -0.07547793); - assert_abs_diff_eq!(vis[21], 0.14045581); - assert_abs_diff_eq!(vis[22], -0.050551586); - assert_abs_diff_eq!(vis[24], 36.67284); - assert_abs_diff_eq!(vis[25], -37.802803); - assert_abs_diff_eq!(vis[27], 36.411987); - assert_abs_diff_eq!(vis[28], -38.02739); + assert_abs_diff_eq!(vis[0], 36.799625); + assert_abs_diff_eq!(vis[1], -37.711067); + assert_abs_diff_eq!(vis[3], 36.51971); + assert_abs_diff_eq!(vis[4], -37.921707); + assert_abs_diff_eq!(vis[6], 0.12917346); + assert_abs_diff_eq!(vis[7], -0.07720526); + assert_abs_diff_eq!(vis[9], 0.1368949); + assert_abs_diff_eq!(vis[10], -0.05224684); + assert_abs_diff_eq!(vis[12], 36.734447); + assert_abs_diff_eq!(vis[13], -37.760387); + assert_abs_diff_eq!(vis[15], 36.464058); + assert_abs_diff_eq!(vis[16], -37.97802); + assert_abs_diff_eq!(vis[18], 0.13280581); + assert_abs_diff_eq!(vis[19], -0.07548501); + assert_abs_diff_eq!(vis[21], 0.14047989); + assert_abs_diff_eq!(vis[22], -0.0505571); + assert_abs_diff_eq!(vis[24], 36.66581); + assert_abs_diff_eq!(vis[25], -37.807594); + assert_abs_diff_eq!(vis[27], 36.405113); + assert_abs_diff_eq!(vis[28], -38.03232); } else { - assert_abs_diff_eq!(vis[0], 36.806194); - assert_abs_diff_eq!(vis[1], -37.706398); - assert_abs_diff_eq!(vis[3], 36.52614); - assert_abs_diff_eq!(vis[4], -37.916924); - assert_abs_diff_eq!(vis[6], 0.12915494); - assert_abs_diff_eq!(vis[7], -0.07720397); - assert_abs_diff_eq!(vis[9], 0.13687298); - assert_abs_diff_eq!(vis[10], -0.052244976); - assert_abs_diff_eq!(vis[12], 36.741276); - assert_abs_diff_eq!(vis[13], -37.75553); - assert_abs_diff_eq!(vis[15], 36.47075); - assert_abs_diff_eq!(vis[16], -37.973045); - assert_abs_diff_eq!(vis[18], 0.1327857); - assert_abs_diff_eq!(vis[19], -0.07548385); - assert_abs_diff_eq!(vis[21], 0.14045675); - assert_abs_diff_eq!(vis[22], -0.05055546); - assert_abs_diff_eq!(vis[24], 36.672867); - assert_abs_diff_eq!(vis[25], -37.802574); - assert_abs_diff_eq!(vis[27], 36.41201); - assert_abs_diff_eq!(vis[28], -38.027172); + assert_abs_diff_eq!(vis[0], 36.799675); + assert_abs_diff_eq!(vis[1], -37.71089); + assert_abs_diff_eq!(vis[3], 36.519768); + assert_abs_diff_eq!(vis[4], -37.921543); + assert_abs_diff_eq!(vis[6], 0.12917838); + assert_abs_diff_eq!(vis[7], -0.07721107); + assert_abs_diff_eq!(vis[9], 0.13689607); + assert_abs_diff_eq!(vis[10], -0.052250482); + assert_abs_diff_eq!(vis[12], 36.7345); + assert_abs_diff_eq!(vis[13], -37.760174); + assert_abs_diff_eq!(vis[15], 36.464123); + assert_abs_diff_eq!(vis[16], -37.97782); + assert_abs_diff_eq!(vis[18], 0.13281031); + assert_abs_diff_eq!(vis[19], -0.07549093); + assert_abs_diff_eq!(vis[21], 0.14048097); + assert_abs_diff_eq!(vis[22], -0.05056086); + assert_abs_diff_eq!(vis[24], 36.66584); + assert_abs_diff_eq!(vis[25], -37.807365); + assert_abs_diff_eq!(vis[27], 36.405136); + assert_abs_diff_eq!(vis[28], -38.032104); } } for (i, vis) in vis.iter().enumerate() {