1 /*
2  * Copyright (c) 2014-2021, The OSKAR Developers.
3  * See the LICENSE file at the top-level directory of this distribution.
4  */
5 
6 #include "correlate/define_correlate_utils.h"
7 #include "correlate/oskar_cross_correlate_scalar_omp.h"
8 #include "math/define_multiply.h"
9 #include "math/oskar_kahan_sum.h"
10 #include "utility/oskar_kernel_macros.h"
11 #include "utility/oskar_vector_types.h"
12 #include <stdio.h>
13 
14 template<typename T1, typename T2>
15 struct is_same
16 {
17     enum { value = false }; // is_same represents a bool.
18     typedef is_same<T1,T2> type; // to qualify as a metafunction.
19 };
20 
21 template<typename T>
22 struct is_same<T,T>
23 {
24     enum { value = true };
25     typedef is_same<T,T> type;
26 };
27 
28 template
29 <
30 // Compile-time parameters.
31 bool BANDWIDTH_SMEARING, bool TIME_SMEARING, bool GAUSSIAN,
32 typename REAL, typename REAL2
33 >
oskar_xcorr_scalar_omp(const int num_sources,const int num_stations,const int offset_out,const REAL2 * const RESTRICT jones,const REAL * const RESTRICT source_I,const REAL * const RESTRICT source_l,const REAL * const RESTRICT source_m,const REAL * const RESTRICT source_n,const REAL * const RESTRICT source_a,const REAL * const RESTRICT source_b,const REAL * const RESTRICT source_c,const REAL * const RESTRICT station_u,const REAL * const RESTRICT station_v,const REAL * const RESTRICT station_w,const REAL * const RESTRICT station_x,const REAL * const RESTRICT station_y,const REAL uv_min_lambda,const REAL uv_max_lambda,const REAL inv_wavelength,const REAL frac_bandwidth,const REAL time_int_sec,const REAL gha0_rad,const REAL dec0_rad,REAL2 * RESTRICT vis)34 void oskar_xcorr_scalar_omp(
35         const int                   num_sources,
36         const int                   num_stations,
37         const int                   offset_out,
38         const REAL2* const RESTRICT jones,
39         const REAL*  const RESTRICT source_I,
40         const REAL*  const RESTRICT source_l,
41         const REAL*  const RESTRICT source_m,
42         const REAL*  const RESTRICT source_n,
43         const REAL*  const RESTRICT source_a,
44         const REAL*  const RESTRICT source_b,
45         const REAL*  const RESTRICT source_c,
46         const REAL*  const RESTRICT station_u,
47         const REAL*  const RESTRICT station_v,
48         const REAL*  const RESTRICT station_w,
49         const REAL*  const RESTRICT station_x,
50         const REAL*  const RESTRICT station_y,
51         const REAL                  uv_min_lambda,
52         const REAL                  uv_max_lambda,
53         const REAL                  inv_wavelength,
54         const REAL                  frac_bandwidth,
55         const REAL                  time_int_sec,
56         const REAL                  gha0_rad,
57         const REAL                  dec0_rad,
58         REAL2*             RESTRICT vis)
59 {
60     // Loop over stations.
61 #pragma omp parallel for schedule(dynamic, 1)
62     for (int SQ = 0; SQ < num_stations; ++SQ)
63     {
64         // Pointer to source vector for station q.
65         const REAL2* const station_q = &jones[SQ * num_sources];
66 
67         // Loop over baselines for this station.
68         for (int SP = SQ + 1; SP < num_stations; ++SP)
69         {
70             REAL uv_len, uu, vv, ww, uu2, vv2, uuvv, du, dv, dw;
71             REAL2 t1, t2, sum, guard;
72             sum.x = sum.y = (REAL) 0;
73             if (is_same<REAL, float>::value)
74             {
75                 guard.x = guard.y = (REAL) 0;
76             }
77 
78             // Pointer to source vector for station p.
79             const REAL2* const station_p = &jones[SP * num_sources];
80 
81             // Get common baseline values.
82             OSKAR_BASELINE_TERMS(REAL, station_u[SP], station_u[SQ],
83                     station_v[SP], station_v[SQ], station_w[SP], station_w[SQ],
84                     uu, vv, ww, uu2, vv2, uuvv, uv_len);
85 
86             // Apply the baseline length filter.
87             if (uv_len < uv_min_lambda || uv_len > uv_max_lambda) continue;
88 
89             // Compute the deltas for time-average smearing.
90             if (TIME_SMEARING)
91                 OSKAR_BASELINE_DELTAS(REAL, station_x[SP], station_x[SQ],
92                         station_y[SP], station_y[SQ], du, dv, dw);
93 
94             // Loop over sources.
95             for (int i = 0; i < num_sources; ++i)
96             {
97                 REAL smearing;
98                 if (GAUSSIAN)
99                 {
100                     const REAL t = source_a[i] * uu2 + source_b[i] * uuvv +
101                             source_c[i] * vv2;
102                     smearing = exp((REAL) -t);
103                 }
104                 else
105                 {
106                     smearing = (REAL) 1;
107                 }
108                 smearing *= source_I[i];
109                 if (BANDWIDTH_SMEARING || TIME_SMEARING)
110                 {
111                     const REAL l = source_l[i];
112                     const REAL m = source_m[i];
113                     const REAL n = source_n[i] - (REAL) 1;
114                     if (BANDWIDTH_SMEARING)
115                     {
116                         const REAL t = uu * l + vv * m + ww * n;
117                         smearing *= OSKAR_SINC(REAL, t);
118                     }
119                     if (TIME_SMEARING)
120                     {
121                         const REAL t = du * l + dv * m + dw * n;
122                         smearing *= OSKAR_SINC(REAL, t);
123                     }
124                 }
125 
126                 // Multiply Jones scalars.
127                 t1 = station_p[i];
128                 t2 = station_q[i];
129                 OSKAR_MUL_COMPLEX_CONJUGATE_IN_PLACE(REAL2, t1, t2)
130 
131                 // Multiply result by smearing term and accumulate.
132                 if (is_same<REAL, float>::value)
133                 {
134                     OSKAR_KAHAN_SUM_MULTIPLY_COMPLEX(
135                             REAL, sum, t1, smearing, guard)
136                 }
137                 else
138                 {
139                     sum.x += t1.x * smearing;
140                     sum.y += t1.y * smearing;
141                 }
142             }
143 
144             // Add result to the baseline visibility.
145             int i = OSKAR_BASELINE_INDEX(num_stations, SP, SQ) + offset_out;
146             vis[i].x += sum.x;
147             vis[i].y += sum.y;
148         }
149     }
150 }
151 
152 #define XCORR_KERNEL(BS, TS, GAUSSIAN, REAL, REAL2)                         \
153         oskar_xcorr_scalar_omp<BS, TS, GAUSSIAN, REAL, REAL2>               \
154         (num_sources, num_stations, offset_out, d_jones, d_I, d_l, d_m, d_n,\
155                 d_a, d_b, d_c, d_station_u, d_station_v, d_station_w,       \
156                 d_station_x, d_station_y, uv_min_lambda, uv_max_lambda,     \
157                 inv_wavelength, frac_bandwidth, time_int_sec,               \
158                 gha0_rad, dec0_rad, d_vis);
159 
160 #define XCORR_SELECT(GAUSSIAN, REAL, REAL2)                                 \
161         if (frac_bandwidth == (REAL)0 && time_int_sec == (REAL)0)           \
162             XCORR_KERNEL(false, false, GAUSSIAN, REAL, REAL2)               \
163         else if (frac_bandwidth != (REAL)0 && time_int_sec == (REAL)0)      \
164             XCORR_KERNEL(true, false, GAUSSIAN, REAL, REAL2)                \
165         else if (frac_bandwidth == (REAL)0 && time_int_sec != (REAL)0)      \
166             XCORR_KERNEL(false, true, GAUSSIAN, REAL, REAL2)                \
167         else if (frac_bandwidth != (REAL)0 && time_int_sec != (REAL)0)      \
168             XCORR_KERNEL(true, true, GAUSSIAN, REAL, REAL2)
169 
oskar_cross_correlate_scalar_point_omp_f(int num_sources,int num_stations,int offset_out,const float2 * d_jones,const float * d_I,const float * d_l,const float * d_m,const float * d_n,const float * d_station_u,const float * d_station_v,const float * d_station_w,const float * d_station_x,const float * d_station_y,float uv_min_lambda,float uv_max_lambda,float inv_wavelength,float frac_bandwidth,const float time_int_sec,const float gha0_rad,const float dec0_rad,float2 * d_vis)170 void oskar_cross_correlate_scalar_point_omp_f(
171         int num_sources, int num_stations, int offset_out,
172         const float2* d_jones, const float* d_I, const float* d_l,
173         const float* d_m, const float* d_n,
174         const float* d_station_u, const float* d_station_v,
175         const float* d_station_w, const float* d_station_x,
176         const float* d_station_y, float uv_min_lambda, float uv_max_lambda,
177         float inv_wavelength, float frac_bandwidth, const float time_int_sec,
178         const float gha0_rad, const float dec0_rad, float2* d_vis)
179 {
180     const float *d_a = 0, *d_b = 0, *d_c = 0;
181     XCORR_SELECT(false, float, float2)
182 }
183 
oskar_cross_correlate_scalar_point_omp_d(int num_sources,int num_stations,int offset_out,const double2 * d_jones,const double * d_I,const double * d_l,const double * d_m,const double * d_n,const double * d_station_u,const double * d_station_v,const double * d_station_w,const double * d_station_x,const double * d_station_y,double uv_min_lambda,double uv_max_lambda,double inv_wavelength,double frac_bandwidth,const double time_int_sec,const double gha0_rad,const double dec0_rad,double2 * d_vis)184 void oskar_cross_correlate_scalar_point_omp_d(
185         int num_sources, int num_stations, int offset_out,
186         const double2* d_jones, const double* d_I, const double* d_l,
187         const double* d_m, const double* d_n,
188         const double* d_station_u, const double* d_station_v,
189         const double* d_station_w, const double* d_station_x,
190         const double* d_station_y, double uv_min_lambda, double uv_max_lambda,
191         double inv_wavelength, double frac_bandwidth, const double time_int_sec,
192         const double gha0_rad, const double dec0_rad, double2* d_vis)
193 {
194     const double *d_a = 0, *d_b = 0, *d_c = 0;
195     XCORR_SELECT(false, double, double2)
196 }
197 
oskar_cross_correlate_scalar_gaussian_omp_f(int num_sources,int num_stations,int offset_out,const float2 * d_jones,const float * d_I,const float * d_l,const float * d_m,const float * d_n,const float * d_a,const float * d_b,const float * d_c,const float * d_station_u,const float * d_station_v,const float * d_station_w,const float * d_station_x,const float * d_station_y,float uv_min_lambda,float uv_max_lambda,float inv_wavelength,float frac_bandwidth,float time_int_sec,float gha0_rad,float dec0_rad,float2 * d_vis)198 void oskar_cross_correlate_scalar_gaussian_omp_f(
199         int num_sources, int num_stations, int offset_out,
200         const float2* d_jones, const float* d_I, const float* d_l,
201         const float* d_m, const float* d_n,
202         const float* d_a, const float* d_b,
203         const float* d_c, const float* d_station_u,
204         const float* d_station_v, const float* d_station_w,
205         const float* d_station_x, const float* d_station_y,
206         float uv_min_lambda, float uv_max_lambda, float inv_wavelength,
207         float frac_bandwidth, float time_int_sec, float gha0_rad,
208         float dec0_rad, float2* d_vis)
209 {
210     XCORR_SELECT(true, float, float2)
211 }
212 
oskar_cross_correlate_scalar_gaussian_omp_d(int num_sources,int num_stations,int offset_out,const double2 * d_jones,const double * d_I,const double * d_l,const double * d_m,const double * d_n,const double * d_a,const double * d_b,const double * d_c,const double * d_station_u,const double * d_station_v,const double * d_station_w,const double * d_station_x,const double * d_station_y,double uv_min_lambda,double uv_max_lambda,double inv_wavelength,double frac_bandwidth,double time_int_sec,double gha0_rad,double dec0_rad,double2 * d_vis)213 void oskar_cross_correlate_scalar_gaussian_omp_d(
214         int num_sources, int num_stations, int offset_out,
215         const double2* d_jones, const double* d_I, const double* d_l,
216         const double* d_m, const double* d_n,
217         const double* d_a, const double* d_b,
218         const double* d_c, const double* d_station_u,
219         const double* d_station_v, const double* d_station_w,
220         const double* d_station_x, const double* d_station_y,
221         double uv_min_lambda, double uv_max_lambda, double inv_wavelength,
222         double frac_bandwidth, double time_int_sec, double gha0_rad,
223         double dec0_rad, double2* d_vis)
224 {
225     XCORR_SELECT(true, double, double2)
226 }
227