void oskar_sky_evaluate_gaussian_source_parameters(oskar_Sky* sky, int zero_failed_sources, double ra0, double dec0, int* num_failed, int* status) { int i, j, num_sources; int type; /* Check if safe to proceed. */ if (*status) return; /* Return if memory is not on the CPU. */ if (oskar_sky_mem_location(sky) != OSKAR_CPU) { *status = OSKAR_ERR_BAD_LOCATION; return; } /* Get data type and number of sources. */ type = oskar_sky_precision(sky); num_sources = oskar_sky_num_sources(sky); /* Switch on type. */ if (type == OSKAR_DOUBLE) { /* Double precision. */ const double *ra_, *dec_, *maj_, *min_, *pa_; double *I_, *Q_, *U_, *V_, *a_, *b_, *c_; double cos_pa_2, sin_pa_2, sin_2pa, inv_std_min_2, inv_std_maj_2; double ellipse_a, ellipse_b, maj, min, pa, cos_pa, sin_pa, t; double l[ELLIPSE_PTS], m[ELLIPSE_PTS]; double work1[5 * ELLIPSE_PTS], work2[5 * ELLIPSE_PTS]; double lon[ELLIPSE_PTS], lat[ELLIPSE_PTS]; double x[ELLIPSE_PTS], y[ELLIPSE_PTS], z[ELLIPSE_PTS]; ra_ = oskar_mem_double_const(oskar_sky_ra_rad_const(sky), status); dec_ = oskar_mem_double_const(oskar_sky_dec_rad_const(sky), status); maj_ = oskar_mem_double_const(oskar_sky_fwhm_major_rad_const(sky), status); min_ = oskar_mem_double_const(oskar_sky_fwhm_minor_rad_const(sky), status); pa_ = oskar_mem_double_const(oskar_sky_position_angle_rad_const(sky), status); I_ = oskar_mem_double(oskar_sky_I(sky), status); Q_ = oskar_mem_double(oskar_sky_Q(sky), status); U_ = oskar_mem_double(oskar_sky_U(sky), status); V_ = oskar_mem_double(oskar_sky_V(sky), status); a_ = oskar_mem_double(oskar_sky_gaussian_a(sky), status); b_ = oskar_mem_double(oskar_sky_gaussian_b(sky), status); c_ = oskar_mem_double(oskar_sky_gaussian_c(sky), status); for (i = 0; i < num_sources; ++i) { /* Note: could do something different from the projection below * in the case of a line (i.e. maj or min = 0), as in this case * there is no ellipse to project, only two points. * -- This continue could then be a if() .. else() instead. */ if (maj_[i] == 0.0 && min_[i] == 0.0) continue; /* Evaluate shape of ellipse on the l,m plane. */ ellipse_a = maj_[i]/2.0; ellipse_b = min_[i]/2.0; cos_pa = cos(pa_[i]); sin_pa = sin(pa_[i]); for (j = 0; j < ELLIPSE_PTS; ++j) { t = j * 60.0 * M_PI / 180.0; l[j] = ellipse_a*cos(t)*sin_pa + ellipse_b*sin(t)*cos_pa; m[j] = ellipse_a*cos(t)*cos_pa - ellipse_b*sin(t)*sin_pa; } oskar_convert_relative_directions_to_lon_lat_2d_d(ELLIPSE_PTS, l, m, 0.0, 0.0, lon, lat); /* Rotate on the sphere. */ oskar_convert_lon_lat_to_xyz_d(ELLIPSE_PTS, lon, lat, x, y, z); oskar_rotate_sph_d(ELLIPSE_PTS, x, y, z, ra_[i], dec_[i]); oskar_convert_xyz_to_lon_lat_d(ELLIPSE_PTS, x, y, z, lon, lat); oskar_convert_lon_lat_to_relative_directions_2d_d( ELLIPSE_PTS, lon, lat, ra0, dec0, l, m); /* Get new major and minor axes and position angle. */ oskar_fit_ellipse_d(&maj, &min, &pa, ELLIPSE_PTS, l, m, work1, work2, status); /* Check if fitting failed. */ if (*status == OSKAR_ERR_ELLIPSE_FIT_FAILED) { if (zero_failed_sources) { I_[i] = 0.0; Q_[i] = 0.0; U_[i] = 0.0; V_[i] = 0.0; } ++(*num_failed); *status = 0; continue; } else if (*status) break; /* Evaluate ellipse parameters. */ inv_std_maj_2 = 0.5 * (maj * maj) * M_PI_2_2_LN_2; inv_std_min_2 = 0.5 * (min * min) * M_PI_2_2_LN_2; cos_pa_2 = cos(pa) * cos(pa); sin_pa_2 = sin(pa) * sin(pa); sin_2pa = sin(2.0 * pa); a_[i] = cos_pa_2*inv_std_min_2 + sin_pa_2*inv_std_maj_2; b_[i] = -sin_2pa*inv_std_min_2*0.5 + sin_2pa *inv_std_maj_2*0.5; c_[i] = sin_pa_2*inv_std_min_2 + cos_pa_2*inv_std_maj_2; } } else { /* Single precision. */ const float *ra_, *dec_, *maj_, *min_, *pa_; float *I_, *Q_, *U_, *V_, *a_, *b_, *c_; float cos_pa_2, sin_pa_2, sin_2pa, inv_std_min_2, inv_std_maj_2; float ellipse_a, ellipse_b, maj, min, pa, cos_pa, sin_pa, t; float l[ELLIPSE_PTS], m[ELLIPSE_PTS]; float work1[5 * ELLIPSE_PTS], work2[5 * ELLIPSE_PTS]; float lon[ELLIPSE_PTS], lat[ELLIPSE_PTS]; float x[ELLIPSE_PTS], y[ELLIPSE_PTS], z[ELLIPSE_PTS]; ra_ = oskar_mem_float_const(oskar_sky_ra_rad_const(sky), status); dec_ = oskar_mem_float_const(oskar_sky_dec_rad_const(sky), status); maj_ = oskar_mem_float_const(oskar_sky_fwhm_major_rad_const(sky), status); min_ = oskar_mem_float_const(oskar_sky_fwhm_minor_rad_const(sky), status); pa_ = oskar_mem_float_const(oskar_sky_position_angle_rad_const(sky), status); I_ = oskar_mem_float(oskar_sky_I(sky), status); Q_ = oskar_mem_float(oskar_sky_Q(sky), status); U_ = oskar_mem_float(oskar_sky_U(sky), status); V_ = oskar_mem_float(oskar_sky_V(sky), status); a_ = oskar_mem_float(oskar_sky_gaussian_a(sky), status); b_ = oskar_mem_float(oskar_sky_gaussian_b(sky), status); c_ = oskar_mem_float(oskar_sky_gaussian_c(sky), status); for (i = 0; i < num_sources; ++i) { /* Note: could do something different from the projection below * in the case of a line (i.e. maj or min = 0), as in this case * there is no ellipse to project, only two points. * -- This continue could then be a if() .. else() instead. */ if (maj_[i] == 0.0 && min_[i] == 0.0) continue; /* Evaluate shape of ellipse on the l,m plane. */ ellipse_a = maj_[i]/2.0; ellipse_b = min_[i]/2.0; cos_pa = cos(pa_[i]); sin_pa = sin(pa_[i]); for (j = 0; j < ELLIPSE_PTS; ++j) { t = j * 60.0 * M_PI / 180.0; l[j] = ellipse_a*cos(t)*sin_pa + ellipse_b*sin(t)*cos_pa; m[j] = ellipse_a*cos(t)*cos_pa - ellipse_b*sin(t)*sin_pa; } oskar_convert_relative_directions_to_lon_lat_2d_f(ELLIPSE_PTS, l, m, 0.0, 0.0, lon, lat); /* Rotate on the sphere. */ oskar_convert_lon_lat_to_xyz_f(ELLIPSE_PTS, lon, lat, x, y, z); oskar_rotate_sph_f(ELLIPSE_PTS, x, y, z, ra_[i], dec_[i]); oskar_convert_xyz_to_lon_lat_f(ELLIPSE_PTS, x, y, z, lon, lat); oskar_convert_lon_lat_to_relative_directions_2d_f( ELLIPSE_PTS, lon, lat, (float)ra0, (float)dec0, l, m); /* Get new major and minor axes and position angle. */ oskar_fit_ellipse_f(&maj, &min, &pa, ELLIPSE_PTS, l, m, work1, work2, status); /* Check if fitting failed. */ if (*status == OSKAR_ERR_ELLIPSE_FIT_FAILED) { if (zero_failed_sources) { I_[i] = 0.0; Q_[i] = 0.0; U_[i] = 0.0; V_[i] = 0.0; } ++(*num_failed); *status = 0; continue; } else if (*status) break; /* Evaluate ellipse parameters. */ inv_std_maj_2 = 0.5 * (maj * maj) * M_PI_2_2_LN_2; inv_std_min_2 = 0.5 * (min * min) * M_PI_2_2_LN_2; cos_pa_2 = cos(pa) * cos(pa); sin_pa_2 = sin(pa) * sin(pa); sin_2pa = sin(2.0 * pa); a_[i] = cos_pa_2*inv_std_min_2 + sin_pa_2*inv_std_maj_2; b_[i] = -sin_2pa*inv_std_min_2*0.5 + sin_2pa *inv_std_maj_2*0.5; c_[i] = sin_pa_2*inv_std_min_2 + cos_pa_2*inv_std_maj_2; } } }
TEST(fit_ellipse, test1) { int num_points = 7, status = 0; double maj_d = 0.0, min_d = 0.0, pa_d = 0.0; float maj_f = 0.0, min_f = 0.0, pa_f = 0.0; // Test double precision. { std::vector<double> x(num_points), y(num_points); std::vector<double> work1(5 * num_points), work2(5 * num_points); x[0] = -0.1686; x[1] = -0.0921; x[2] = 0.0765; x[3] = 0.1686; x[4] = 0.0921; x[5] = -0.0765; x[6] = -0.1686; y[0] = 0.7282; y[1] = 0.6994; y[2] = 0.6675; y[3] = 0.6643; y[4] = 0.7088; y[5] = 0.7407; y[6] = 0.7282; oskar_fit_ellipse_d(&maj_d, &min_d, &pa_d, num_points, &x[0], &y[0], &work1[0], &work2[0], &status); EXPECT_EQ(0, status) << oskar_get_error_string(status); } // Test single precision. { std::vector<float> x(num_points), y(num_points); std::vector<float> work1(5 * num_points), work2(5 * num_points); x[0] = -0.1686; x[1] = -0.0921; x[2] = 0.0765; x[3] = 0.1686; x[4] = 0.0921; x[5] = -0.0765; x[6] = -0.1686; y[0] = 0.7282; y[1] = 0.6994; y[2] = 0.6675; y[3] = 0.6643; y[4] = 0.7088; y[5] = 0.7407; y[6] = 0.7282; oskar_fit_ellipse_f(&maj_f, &min_f, &pa_f, num_points, &x[0], &y[0], &work1[0], &work2[0], &status); EXPECT_EQ(0, status) << oskar_get_error_string(status); } // Compare results. EXPECT_NEAR(maj_d, 0.3608619735, 1e-9); EXPECT_NEAR(min_d, 0.0494223702, 1e-9); EXPECT_NEAR(pa_d, -1.3865537748, 1e-9); EXPECT_NEAR(maj_d, maj_f, 1e-5); EXPECT_NEAR(min_d, min_f, 1e-5); EXPECT_NEAR(pa_d, pa_f, 1e-5); }