Line data Source code
1 : //# FringeJones.cc: Implementation of FringeJones
2 : //# Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003,2011
3 : //# Associated Universities, Inc. Washington DC, USA.
4 : //#
5 : //# This library is free software; you can redistribute it and/or modify it
6 : //# under the terms of the GNU Library General Public License as published by
7 : //# the Free Software Foundation; either version 2 of the License, or (at your
8 : //# option) any later version.
9 : //#
10 : //# This library is distributed in the hope that it will be useful, but WITHOUT
11 : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 : //# License for more details.
14 : //#
15 : //# You should have received a copy of the GNU Library General Public License
16 : //# along with this library; if not, write to the Free Software Foundation,
17 : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 : //#
19 : //# Correspondence concerning AIPS++ should be addressed as follows:
20 : //# Internet email: casa-feedback@nrao.edu.
21 : //# Postal address: AIPS++ Project Office
22 : //# National Radio Astronomy Observatory
23 : //# 520 Edgemont Road
24 : //# Charlottesville, VA 22903-2475 USA
25 : //#
26 :
27 : #include <synthesis/MeasurementComponents/FringeJones.h>
28 : #include <msvis/MSVis/VisBuffer.h>
29 : #include <msvis/MSVis/VisBuffAccumulator.h>
30 : #include <casacore/ms/MeasurementSets/MSColumns.h>
31 : #include <synthesis/CalTables/CTIter.h>
32 : #include <synthesis/MeasurementEquations/VisEquation.h> // *
33 : #include <synthesis/MeasurementComponents/SolveDataBuffer.h>
34 : #include <synthesis/MeasurementComponents/MSMetaInfoForCal.h>
35 : #include <casacore/lattices/Lattices/ArrayLattice.h>
36 : #include <casacore/lattices/LatticeMath/LatticeFFT.h>
37 : #include <casacore/scimath/Mathematics/FFTServer.h>
38 :
39 : #include <casacore/casa/Arrays/ArrayMath.h>
40 : #include <casacore/casa/Arrays/MatrixMath.h>
41 : #include <casacore/casa/Arrays/ArrayLogical.h>
42 : #include <casacore/casa/BasicSL/String.h>
43 : #include <casacore/casa/Utilities/Assert.h>
44 : #include <casacore/casa/Exceptions/Error.h>
45 : #include <casacore/casa/System/Aipsrc.h>
46 :
47 : #include <sstream>
48 :
49 : #include <casacore/measures/Measures/MCBaseline.h>
50 : #include <casacore/measures/Measures/MDirection.h>
51 : #include <casacore/measures/Measures/MEpoch.h>
52 : #include <casacore/measures/Measures/MeasTable.h>
53 :
54 : #include <casacore/casa/Logging/LogMessage.h>
55 : #include <casacore/casa/Logging/LogSink.h>
56 :
57 : #include <casacore/casa/Arrays/MaskedArray.h>
58 : #include <casacore/casa/Arrays/MaskArrMath.h>
59 :
60 : #include <gsl/gsl_rng.h>
61 : #include <gsl/gsl_randist.h>
62 : #include <gsl/gsl_vector.h>
63 : #include <gsl/gsl_blas.h>
64 : #include <gsl/gsl_spblas.h>
65 : #include <gsl/gsl_multilarge_nlinear.h>
66 : #include <gsl/gsl_multimin.h>
67 : #include <gsl/gsl_linalg.h>
68 : #include <iomanip> // needed for setprecision
69 :
70 : // DEVDEBUG gates the development debugging information to standard
71 : // error; it should be set to 0 for production.
72 : #define DEVDEBUG false
73 : #define KDISPSCALE 1e6
74 :
75 : using namespace casa::vi;
76 : using namespace casacore;
77 :
78 : namespace casa { //# NAMESPACE CASA - BEGIN
79 :
80 : // Start of GSL compliant solver
81 :
82 : class AuxParamBundle {
83 : public:
84 : SDBList &sdbs;
85 : size_t nCalls;
86 : private:
87 : // We make sure there are no copy or default constructors to
88 : // preserve the integrity of our reference member.
89 : AuxParamBundle();
90 : AuxParamBundle(AuxParamBundle const&);
91 : AuxParamBundle const& operator=(AuxParamBundle const&);
92 :
93 : size_t refant;
94 : size_t nCorrelations;
95 : size_t corrStep;
96 : Double t0;
97 : Double reftime;
98 : std::map< Int, std::set< Int > > activeAntennas;
99 : std::map< Int, Int > antennaIndexMap;
100 : // Can't I just have a vector, which maps indices to values anyway?
101 : std::vector<bool> parameterFlags;
102 : Int nParams;
103 : std::map< Int, Int > parameterMap;
104 : Int activeCorr;
105 : public:
106 225 : AuxParamBundle(SDBList& sdbs_, size_t refant, const std::map< Int, std::set<Int> >& activeAntennas_, Vector<Bool> paramActive) :
107 225 : sdbs(sdbs_),
108 225 : nCalls(0),
109 225 : refant(refant),
110 225 : nCorrelations(sdbs.nCorrelations() > 1 ? 2 : 1),
111 225 : corrStep(sdbs.nCorrelations() > 2 ? 3 : 1),
112 225 : activeAntennas(activeAntennas_),
113 225 : parameterFlags(),
114 225 : parameterMap(),
115 225 : activeCorr(-1)
116 : // corrStep(3)
117 : {
118 225 : Int last_index = sdbs.nSDB() - 1 ;
119 225 : t0 = sdbs(0).time()(0);
120 225 : Double tlast = sdbs(last_index).time()(0);
121 225 : reftime = 0.5*(t0 + tlast);
122 :
123 225 : parameterFlags = paramActive.tovector();
124 225 : Int j = 0; // The CASA parameter index (0=peculiar phase, 1=delay, 2=rate, 3=dispersive)
125 225 : Int i = 0; // the Least Squares parameter vector index, depending on what's being solved for
126 1125 : for (auto p=parameterFlags.begin(); p!=parameterFlags.end(); p++) {
127 900 : if (*p) {
128 671 : parameterMap.insert(std::pair<Int, Int>(j, i));
129 671 : i++;
130 : }
131 900 : j++;
132 : }
133 225 : if (i==0) {
134 0 : throw(AipsError("No parameters specified!"));
135 : }
136 225 : nParams = i; // There's always at least one parameter!
137 : // cerr << "AuxParamBundle reftime " << reftime << " t0 " << t0 <<" dt " << tlast - t0 << endl;
138 225 : }
139 :
140 7862003326 : Int nParameters() {
141 7862003326 : return nParams;
142 : }
143 6572 : Double get_t0() {
144 6572 : return t0;
145 : }
146 : Double
147 : get_ref_time() {
148 : return reftime;
149 : }
150 : size_t
151 587 : get_num_corrs() {
152 : //return sdbs.nCorrelations() > 1 ? 2 : 1;
153 587 : return nCorrelations;
154 : }
155 : size_t
156 1086 : get_num_antennas() {
157 1086 : if (activeCorr < 0) {
158 0 : throw(AipsError("Correlation out of range."));
159 : }
160 1086 : std::set< Int > ants = activeAntennas.find(activeCorr)->second;
161 2172 : return (size_t) ants.size();
162 1086 : }
163 : size_t
164 5740 : get_max_antenna_index() {
165 5740 : if (activeCorr < 0) {
166 0 : throw(AipsError("Correlation out of range."));
167 : }
168 5740 : return *(activeAntennas.find(activeCorr)->second.rbegin());
169 : }
170 : // Sometimes there is Int, sometimes size_t; the following ones are casacore::Int.
171 : Int
172 : get_num_data_points() {
173 : Int nTotalChans = 0;
174 : Int nTotalRows = 0;
175 : for (Int i = 0; i != sdbs.nSDB(); i++) {
176 : SolveDataBuffer& s (sdbs(i));
177 : nTotalChans += s.nRows()*s.nChannels();
178 : }
179 : return nTotalChans;
180 : }
181 : Int
182 362 : get_actual_num_data_points() {
183 362 : Int nTotalRows = 0;
184 362 : Int nTotalChans = 0;
185 43358 : for (Int i = 0; i != sdbs.nSDB(); i++) {
186 42996 : SolveDataBuffer& s (sdbs(i));
187 854846 : for (Int irow=0; irow!=s.nRows(); irow++) {
188 811850 : if (s.flagRow()(irow)) continue;
189 809876 : nTotalChans += s.nChannels();
190 : }
191 : }
192 362 : return nTotalChans;
193 : }
194 : size_t
195 18042308 : get_data_corr_index(size_t icorr) {
196 18042308 : if (icorr > nCorrelations) {
197 0 : throw(AipsError("Correlation out of range."));
198 : }
199 18042308 : size_t dcorr = icorr * corrStep;
200 18042308 : return dcorr;
201 : }
202 : bool
203 37961824 : isActive(size_t iant) {
204 37961824 : std::set<Int> ants = activeAntennas.find(activeCorr)->second;
205 37961824 : if (iant == refant) return true;
206 33317408 : else return (ants.find(iant) != ants.end());
207 37961824 : }
208 : Int
209 11916533911 : get_param_corr_param_index(size_t iant0, size_t ipar) {
210 11916533911 : if (iant0 == refant) return -1;
211 10487183449 : int iant1 = antennaIndexMap[iant0];
212 10487183449 : if (iant1 > antennaIndexMap[refant]) {
213 10487183449 : iant1 -= 1;
214 : }
215 : int ipar1;
216 10487183449 : auto p = parameterMap.find(ipar);
217 10487183449 : if (p==parameterMap.end()) {
218 2625182386 : ipar1 = -1;
219 : }
220 : else {
221 7862001063 : ipar1 = (iant1 * nParameters()) + p->second;
222 : }
223 10487183449 : return ipar1;
224 : }
225 : size_t
226 18042308 : get_active_corr() {
227 18042308 : return activeCorr;
228 : }
229 : void
230 362 : set_active_corr(size_t icorr) {
231 362 : activeCorr = icorr;
232 362 : antennaIndexMap.clear();
233 362 : Int i = 0;
234 362 : std::set<Int>::iterator it;
235 362 : std::set<Int> ants = activeAntennas.find(activeCorr)->second;
236 2625 : for (it = ants.begin(); it != ants.end(); it++) {
237 2263 : antennaIndexMap[*it] = i++;
238 : }
239 362 : }
240 : };
241 :
242 :
243 :
244 : void
245 0 : print_baselines(std::set<std::pair< Int, Int > > baselines) {
246 0 : cerr << "Baselines encountered ";
247 0 : std::set<std::pair< Int, Int > >::iterator it;
248 0 : for (it=baselines.begin(); it != baselines.end(); ++it) {
249 0 : cerr << "(" << it->first << ", " << it->second << ") ";
250 : }
251 0 : cerr << endl;
252 0 : }
253 :
254 :
255 : int
256 3105 : expb_f(const gsl_vector *param, void *d, gsl_vector *f)
257 : {
258 3105 : AuxParamBundle *bundle = (AuxParamBundle *)d;
259 3105 : SDBList& sdbs = bundle->sdbs;
260 3105 : Double refTime = bundle->get_t0();
261 :
262 3105 : gsl_vector_set_zero(f);
263 : // Vector<Double> freqs = sdbs.freqs();
264 :
265 3105 : const Double reffreq0=sdbs(0).freqs()(0); // First freq in first SDB
266 :
267 3105 : size_t count = 0; // This is the master index.
268 :
269 3105 : Double sumwt = 0.0;
270 3105 : Double xi_squared = 0.0;
271 :
272 358095 : for (Int ibuf=0; ibuf < sdbs.nSDB(); ibuf++) {
273 354990 : SolveDataBuffer& s (sdbs(ibuf));
274 354990 : if (!s.Ok()) continue;
275 :
276 354709 : const Vector<Double> freqs(s.freqs()); // This ibuf's freqs
277 354709 : Float fmin_ = min(freqs);
278 354709 : Float fmax = max(freqs);
279 :
280 354709 : const Cube<Complex>& v(s.visCubeCorrected());
281 354709 : const Cube<Bool>& fl(s.flagCube());
282 354709 : const Cube<Float>& weights(s.weightSpectrum());
283 :
284 9725805 : for (Int irow=0; irow!=s.nRows(); irow++) {
285 9371096 : if (s.flagRow()(irow)) continue;
286 :
287 9363793 : Int ant1(s.antenna1()(irow));
288 9363793 : Int ant2(s.antenna2()(irow));
289 9363793 : if (!bundle->isActive(ant1) || !bundle->isActive(ant2))
290 223832 : continue;
291 9139961 : if (ant1==ant2) continue;
292 :
293 : // VisBuffer.h seems to suggest that a vb.visCube may have shape
294 : // (nCorr(), nChannel(), nRow())
295 8661055 : size_t icorr0 = bundle->get_active_corr();
296 8661055 : size_t dcorr = bundle->get_data_corr_index(icorr0);
297 : // We also need to get the right parameters for this,
298 : // polarization (icorr is an encoding of the
299 : // polarization of the correlation products).
300 :
301 : Double phi0, tau, r, disp;
302 : {
303 : Int i;
304 : Double phi0_1, tau1, r1, disp1;
305 : Double phi0_2, tau2, r2, disp2;
306 :
307 8661055 : phi0_1 = ((i = bundle->get_param_corr_param_index(ant1, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
308 8661055 : tau1 = ((i = bundle->get_param_corr_param_index(ant1, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
309 8661055 : r1 = ((i = bundle->get_param_corr_param_index(ant1, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
310 8661055 : disp1 = ((i = bundle->get_param_corr_param_index(ant1, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
311 :
312 8661055 : phi0_2 = ((i = bundle->get_param_corr_param_index(ant2, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
313 8661055 : tau2 = ((i = bundle->get_param_corr_param_index(ant2, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
314 8661055 : r2 = ((i = bundle->get_param_corr_param_index(ant2, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
315 8661055 : disp2 = ((i = bundle->get_param_corr_param_index(ant2, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
316 :
317 8661055 : phi0 = phi0_2 - phi0_1;
318 8661055 : tau = tau2 - tau1;
319 8661055 : r = r2-r1;
320 8661055 : disp = disp2-disp1;
321 : }
322 :
323 180949719 : for (size_t ichan = 0; ichan != v.ncolumn(); ichan++) {
324 172288664 : if (fl(dcorr, ichan, irow)) continue;
325 :
326 171721550 : Float freq = freqs(ichan);
327 171721550 : Float k_disp = KDISPSCALE*(2.0*M_PI)*(1.0/freq + (freq-fmin_-fmax)/(fmin_*fmax));
328 :
329 171721550 : Complex vis = v(dcorr, ichan, irow);
330 171721550 : Double w0 = weights(dcorr, ichan, irow);
331 : // FIXME: what should we use to scale the weights?
332 : // Double weightScale = norm(vis);
333 : // Double weightScale = abs(vis);
334 : // Double weightScale = 1;
335 : // Double weightScale = 1/sqrt(w0); // Actually AIPS 0, not AIPS 1!
336 : // Double weightScale = pow(w0, -0.75); // AIPS 2
337 : // Double weightScale = 1/w0; // AIPS 3
338 : // Double weightScale = norm(vis); // Casa 1, I guess
339 171721550 : Double w = sqrt(w0);
340 171721550 : sumwt += w*w;
341 171721550 : if (fabs(w) < FLT_EPSILON) continue;
342 : // We have to turn the delay back into seconds from nanoseconds.
343 : // Freq difference is in Hz, which comes out typically as 1e6 bands
344 : //Double wDf = (2.0*M_PI)*(freqs(ichan) - freqs(0))*1e-9;
345 171721550 : Double wDf = (2.0*M_PI)*(freqs(ichan) - reffreq0)*1e-9;
346 : //
347 171721550 : Double t1 = s.time()(0);
348 : // FIXME: Remind me why we *do* scale wDf with 1e-9
349 : // but do *not* do that with ref_freq?
350 : // I have a theory which is mine:
351 : // this is because tau is in nanoseconds.
352 : //Double ref_freq = freqs(0);
353 : //Double wDt = (2.0*M_PI)*(t1 - refTime) * ref_freq;
354 171721550 : Double wDt = (2.0*M_PI)*(t1 - refTime) * reffreq0;
355 :
356 171721550 : Double mtheta = -(phi0 + tau*wDf + r*wDt + disp*k_disp);
357 171721550 : Double vtheta = arg(vis);
358 :
359 171721550 : Double c_r = w*(cos(mtheta) - cos(vtheta));
360 171721550 : Double c_i = w*(sin(mtheta) - sin(vtheta));
361 171721550 : gsl_vector_set(f, count, c_r);
362 171721550 : gsl_vector_set(f, count+1, c_i);
363 :
364 171721550 : count += 2;
365 171721550 : xi_squared += c_r*c_r + c_i*c_i;
366 : }
367 : }
368 354709 : }
369 : // cerr << "Residual xi-squared = " << xi_squared << endl;
370 3105 : return GSL_SUCCESS;
371 : }
372 :
373 :
374 : int
375 3105 : expb_df(CBLAS_TRANSPOSE_t TransJ, const gsl_vector* param, const gsl_vector *u, void *bundle_, gsl_vector *v, gsl_matrix *JTJ)
376 : {
377 :
378 : // param is the current vector for which we're finding the jacobian.
379 : // if TransJ is true, evaluate J^T u and store in v.
380 : // Also store J^T . J in lower half of JTJ.
381 3105 : std::set <std::pair < Int, Int> > baselines;
382 3105 : AuxParamBundle *bundle = (AuxParamBundle *)bundle_;
383 :
384 3105 : SDBList& sdbs = bundle->sdbs;
385 3105 : const Double reffreq0=sdbs(0).freqs()(0); // First freq in first SDB
386 :
387 3105 : size_t count = 0; // This is the master index.
388 :
389 3105 : gsl_vector_set_zero(v);
390 3105 : gsl_matrix_set_zero(JTJ);
391 :
392 3105 : Double refTime = bundle->get_t0();
393 :
394 358095 : for (Int ibuf=0; ibuf < sdbs.nSDB(); ibuf++) {
395 354990 : SolveDataBuffer& s (sdbs(ibuf));
396 354990 : if (!s.Ok()) continue;
397 :
398 354709 : const Vector<Double>& freqs(s.freqs()); // This ibuf's freqs
399 354709 : Float fmin_ = min(freqs);
400 354709 : Float fmax = max(freqs);
401 354709 : const Cube<Complex>& vis(s.visCubeCorrected());
402 354709 : const Cube<Bool>& fl(s.flagCube());
403 354709 : const Cube<Float>& weights(s.weightSpectrum());
404 :
405 354709 : Double t1 = s.time()(0);
406 9725805 : for (Int irow=0; irow!=s.nRows(); irow++) {
407 10073834 : if (s.flagRow()(irow)) continue;
408 :
409 9363793 : Int ant1(s.antenna1()(irow));
410 9363793 : Int ant2(s.antenna2()(irow));
411 :
412 9363793 : if (ant1==ant2) continue;
413 8882023 : if (!bundle->isActive(ant1) || !bundle->isActive(ant2)) {
414 220968 : continue;
415 : }
416 :
417 : // VisBuffer.h seems to suggest that a vb.visCube may have shape
418 : // (nCorr(), nChannel(), nRow())
419 :
420 8661055 : size_t icorr0 = bundle->get_active_corr();
421 8661055 : size_t dcorr = bundle->get_data_corr_index(icorr0);
422 : // We also need to get the right parameters for this
423 : // polarization (icorr is an encoding of the
424 : // polarization of the correlation products).
425 :
426 : Double phi0, tau, r, disp;
427 : {
428 : Int i;
429 : Double phi0_1, tau1, r1, disp1;
430 : Double phi0_2, tau2, r2, disp2;
431 :
432 8661055 : phi0_1 = ((i = bundle->get_param_corr_param_index(ant1, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
433 8661055 : tau1 = ((i = bundle->get_param_corr_param_index(ant1, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
434 8661055 : r1 = ((i = bundle->get_param_corr_param_index(ant1, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
435 8661055 : disp1 = ((i = bundle->get_param_corr_param_index(ant1, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
436 :
437 8661055 : phi0_2 = ((i = bundle->get_param_corr_param_index(ant2, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
438 8661055 : tau2 = ((i = bundle->get_param_corr_param_index(ant2, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
439 8661055 : r2 = ((i = bundle->get_param_corr_param_index(ant2, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
440 8661055 : disp2 = ((i = bundle->get_param_corr_param_index(ant2, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
441 :
442 8661055 : phi0 = phi0_2 - phi0_1;
443 8661055 : tau = tau2 - tau1;
444 8661055 : r = r2-r1;
445 8661055 : disp = disp2-disp1;
446 : }
447 :
448 :
449 : //Double ref_freq = freqs(0);
450 : //Double wDt = (2.0*M_PI)*(t1 - refTime) * ref_freq;
451 8661055 : Double wDt = (2.0*M_PI)*(t1 - refTime) * reffreq0;
452 8661055 : bool found_data = false;
453 :
454 180949719 : for (size_t ichan = 0; ichan != vis.ncolumn(); ichan++) {
455 172288664 : if (fl(dcorr, ichan, irow)) continue;
456 171721550 : Double w0 = weights(dcorr, ichan, irow);
457 171721550 : Double w = sqrt(w0);
458 171721550 : if (fabs(w) < FLT_EPSILON) continue;
459 171721550 : found_data = true;
460 :
461 171721550 : Float freq = freqs(ichan);
462 171721550 : Float k_disp = KDISPSCALE*(2.0*M_PI)*(1.0/freq + (freq-fmin_-fmax)/(fmin_*fmax));
463 :
464 : // Add a 1e-9 factor because tau parameter is in nanoseconds.
465 : //Double wDf = (2.0*M_PI)*(freqs(ichan) - freqs(0))*1e-9;
466 171721550 : Double wDf = (2.0*M_PI)*(freqs(ichan) - reffreq0)*1e-9;
467 : //
468 171721550 : Double mtheta = -(phi0 + tau*wDf + r*wDt + disp*k_disp);
469 171721550 : Double ws = sin(mtheta);
470 171721550 : Double wc = cos(mtheta);
471 :
472 171721550 : Double p0 = 1.0;
473 171721550 : Double p1 = wDf;
474 171721550 : Double p2 = wDt;
475 171721550 : Double p3 = k_disp;
476 :
477 171721550 : Vector<Double> dterm2(4);
478 171721550 : dterm2(0) = -p0;
479 171721550 : dterm2(1) = -p1;
480 171721550 : dterm2(2) = -p2;
481 171721550 : dterm2(3) = -p3;
482 :
483 171721550 : Vector<Double> dterm1(4);
484 171721550 : dterm1(0) = p0;
485 171721550 : dterm1(1) = p1;
486 171721550 : dterm1(2) = p2;
487 171721550 : dterm1(3) = p3;
488 :
489 : /*
490 : What we want to express is just:
491 : J[count + 0, iparam2 + 0] = w*-ws*-1.0;
492 : J[count + 1, iparam2 + 0] = w*+wc*-1.0;
493 : J[count + 0, iparam2 + 1] = w*-ws*-wDf;
494 : J[count + 1, iparam2 + 1] = w*+wc*-wDf;
495 : J[count + 0, iparam2 + 2] = w*-ws*-wDt;
496 : J[count + 1, iparam2 + 2] = w*+wc*-wDt;
497 :
498 : But in the GSL multilarge framework we have to
499 : be ready to calculate either J*u for a given u
500 : or J^T*u, depending on the flag TransJ, and we also have to fill in the
501 :
502 : v[iparam + ...] = J[count + ..., iparam + ...] * u[iparam + ...]
503 :
504 : or
505 :
506 : v[iparam + ...] = J^T[iparam + ..., count + ...] * u[count + ...]
507 :
508 : <https://www.gnu.org/software/gsl/doc/html/nls.html#c.gsl_multifit_nlinear_default_parameters>
509 :
510 : "Additionally, the normal equations matrix J^T J should be stored in the lower half of JTJ."
511 :
512 : So we should also use
513 : JTJ[iparam + ..., iparam + ...] += J^T[iparam + ..., count + ...] J[count + ..., iparam + ...]
514 :
515 : */
516 171721550 : if (TransJ==CblasNoTrans) {
517 0 : for (Int di=0; di<4; di++) {
518 : Int i;
519 0 : if ((i = bundle->get_param_corr_param_index(ant2, di))>=0) {
520 0 : (*gsl_vector_ptr(v, count + 0)) += (w*-ws*dterm2(di)) * gsl_vector_get(u, i);
521 0 : (*gsl_vector_ptr(v, count + 1)) += (w*+wc*dterm2(di)) * gsl_vector_get(u, i);
522 : }
523 0 : if ((i = bundle->get_param_corr_param_index(ant1, di))>=0) {
524 0 : (*gsl_vector_ptr(v, count + 0)) += gsl_vector_get(u, i) * (w*-ws*dterm1(di));
525 0 : (*gsl_vector_ptr(v, count + 1)) += gsl_vector_get(u, i) * (w*+wc*dterm1(di));
526 : }
527 : }
528 : } else {
529 858607750 : for (Int di=0; di<4; di++) {
530 : Int i;
531 686886200 : if ((i = bundle->get_param_corr_param_index(ant2, di))>=0) {
532 514357436 : (*gsl_vector_ptr(v, i)) += (w*-ws*dterm2(di)) * gsl_vector_get(u, count + 0);
533 514357436 : (*gsl_vector_ptr(v, i)) += (w*+wc*dterm2(di)) * gsl_vector_get(u, count + 1);
534 : }
535 686886200 : if ((i = bundle->get_param_corr_param_index(ant1, di))>=0) {
536 385205432 : (*gsl_vector_ptr(v, i)) += gsl_vector_get(u, count + 0) * (w*-ws*dterm1(di));
537 385205432 : (*gsl_vector_ptr(v, i)) += gsl_vector_get(u, count + 1) * (w*+wc*dterm1(di));
538 : }
539 : }
540 : }
541 171721550 : if (JTJ) {
542 : Int i, j;
543 171721550 : Double wterm = (-ws) * (-ws) + (+wc) * (+wc);
544 171721550 : if (fabs(1-wterm) > 1e-15)
545 0 : throw AipsError("Insufficiently at one");
546 858607750 : for (Int di=0; di<4; di++) {
547 2404101700 : for (Int dj=0; dj<=di; dj++) {
548 2748972808 : if (((i = bundle->get_param_corr_param_index(ant2, di))>=0) &&
549 1031757308 : ((j = bundle->get_param_corr_param_index(ant2, dj))>=0)) {
550 1029231260 : (*gsl_matrix_ptr(JTJ, i, j)) += w0*dterm2(di)*dterm2(dj);
551 : }
552 2488667300 : if (((i = bundle->get_param_corr_param_index(ant1, di))>=0) &&
553 771451800 : ((j = bundle->get_param_corr_param_index(ant1, dj))>=0)) {
554 770609784 : (*gsl_matrix_ptr(JTJ, i, j)) += w0*dterm1(di)*dterm1(dj);
555 : }
556 : }
557 : }
558 : // iant1 != iant2, so we don't have to worry about collisions
559 858607750 : for (Int di=0; di<4; di++) {
560 3434431000 : for (Int dj=0; dj<4; dj++) {
561 : Int i0, j0;
562 4288366528 : if (((i0 = bundle->get_param_corr_param_index(ant1, di))>=0) &&
563 1540821728 : ((j0 = bundle->get_param_corr_param_index(ant2, dj))>=0)) {
564 1156014136 : Int i1 = max(i0, j0);
565 1156014136 : Int j1 = min(i0, j0);
566 1156014136 : (*gsl_matrix_ptr(JTJ, i1, j1)) += w0*dterm2(di)*dterm1(dj);
567 : }
568 : }
569 : }
570 171721550 : count += 2;
571 : } // if JTJ
572 171721550 : } // loop over channels
573 8661055 : if (found_data) {
574 8661055 : std::pair<Int, Int> antpair = std::make_pair(ant1, ant2);
575 8661055 : bool newBaseline = (baselines.find(antpair) == baselines.end());
576 8661055 : if (newBaseline) {
577 87542 : baselines.insert(antpair);
578 : // cerr << "paramFlagging for antenna "<< ant1 << ": ";
579 : // for (size_t di=0; di<4; di++) {
580 : // cerr << (bundle->get_param_corr_param_index(ant1, di)>=0) << " ";
581 : // }
582 : // cerr << endl;
583 : // cerr << "indices for antenna "<< ant1 << ": ";
584 : // if (bundle->get_param_corr_param_index(ant1, 0) >= 0) {
585 : // for (size_t di=0; di<4; di++) {
586 : // cerr << bundle->get_param_corr_param_index(ant1, di) << " ";
587 : // }
588 : // cerr << endl;
589 : // }
590 : // cerr << "phi0 " << phi0 << " tau " << tau << " r " << r << endl;
591 : }
592 : }
593 : }
594 : }
595 : if (DEVDEBUG && 0) {
596 : print_baselines(baselines);
597 : cerr << "count " << count << endl;
598 : cerr << "v = ";
599 : for (size_t i=0; i!=v->size; i++) {
600 : cerr << gsl_vector_get(v, i) << " ";
601 : }
602 : cerr << endl;
603 : // if (JTJ) {
604 : // cerr <<"JTJ " << std::scientific << endl;
605 : // for (size_t i=0; i!=JTJ->size1; i++) {
606 : // for (size_t j=0; j!=JTJ->size2; j++) {
607 : // cerr << gsl_matrix_get(JTJ, i, j) << " ";
608 : // }
609 : // cerr << endl;
610 : // }
611 : // cerr << endl;
612 : // }
613 : }
614 3105 : return GSL_SUCCESS;
615 3105 : }
616 :
617 :
618 :
619 : int
620 362 : expb_hess(gsl_vector *param, AuxParamBundle *bundle, gsl_matrix *hess, Double xi_squared, gsl_vector *snr_vector, LogIO& logSink)
621 : {
622 : // We calculate the diagonal for the hessian as used by AIPS for
623 : // the signal to noise. The AIPS formulation, by Fred Schwab, is a
624 : // hand-rolled routine that solves a different problem to ours: by
625 : // using a triangular matrix for the Jacobian (requiring antenna i<
626 : // antenna j) the J^T * J term vanishes throughout and the Hessian
627 : // of the Xi^2 functional *only* includes the second-order
628 : // derivative terms, which are usually neglected.
629 : //
630 : // This is very clever, but it also means different covariance and
631 : // information matrices, and therefore a different SNR. Here we
632 : // use a generic least squares solver but we cheat slightly and use
633 : // the AIPS form for the Hessian and SNR calculations.
634 : //
635 : // FIXME: Is there any compelling reason to use gsl_vectors for
636 : // this, given that we're not really hooked in to the gsl
637 : // least squares framework by the time we do this?
638 :
639 362 : SDBList& sdbs = bundle->sdbs;
640 362 : Double refTime = bundle->get_t0();
641 :
642 : // Dimensions of (num_antennas); is the same dimension as
643 : // param vector here.
644 362 : gsl_matrix_set_zero(hess);
645 :
646 362 : const Double reffreq0=sdbs(0).freqs()(0); // First freq in first SDB
647 :
648 362 : size_t nobs = 0;
649 362 : Double sumwt = 0;
650 362 : size_t numpar = param->size;
651 :
652 43358 : for (Int ibuf=0; ibuf < sdbs.nSDB(); ibuf++)
653 : {
654 42996 : SolveDataBuffer& s (sdbs(ibuf));
655 42996 : if (!s.Ok()) continue;
656 :
657 42936 : const Vector<Double> freqs(s.freqs()); // This ibuf's freqs
658 42936 : Float fmin_ = min(freqs);
659 42936 : Float fmax = max(freqs);
660 :
661 42936 : const Cube<Complex>& v(s.visCubeCorrected());
662 42936 : const Cube<Bool>& fl(s.flagCube());
663 42936 : const Cube<Float>& weights(s.weightSpectrum());
664 :
665 :
666 854426 : for (Int irow=0; irow!=s.nRows(); irow++) {
667 811490 : if (s.flagRow()(irow)) continue;
668 :
669 809816 : Int ant1(s.antenna1()(irow));
670 809816 : Int ant2(s.antenna2()(irow));
671 809816 : if (!bundle->isActive(ant1) || !bundle->isActive(ant2))
672 11408 : continue;
673 798408 : if (ant1==ant2) continue;
674 :
675 : // VisBuffer.h seems to suggest that a vb.visCube may have shape
676 : // (nCorr(), nChannel(), nRow())
677 720198 : size_t icorr0 = bundle->get_active_corr();
678 720198 : size_t dcorr = bundle->get_data_corr_index(icorr0);
679 : // We also need to get the right parameters for this,
680 : // polarization (icorr is an encoding of the
681 : // polarization of the correlation products).
682 :
683 : Double phi0, tau, r, disp;
684 : {
685 : Int i;
686 : Double phi0_1, tau1, r1, disp1;
687 : Double phi0_2, tau2, r2, disp2;
688 :
689 720198 : phi0_1 = ((i = bundle->get_param_corr_param_index(ant1, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
690 720198 : tau1 = ((i = bundle->get_param_corr_param_index(ant1, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
691 720198 : r1 = ((i = bundle->get_param_corr_param_index(ant1, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
692 720198 : disp1 = ((i = bundle->get_param_corr_param_index(ant1, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
693 :
694 :
695 720198 : phi0_2 = ((i = bundle->get_param_corr_param_index(ant2, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
696 720198 : tau2 = ((i = bundle->get_param_corr_param_index(ant2, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
697 720198 : r2 = ((i = bundle->get_param_corr_param_index(ant2, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
698 720198 : disp2 = ((i = bundle->get_param_corr_param_index(ant2, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
699 :
700 720198 : phi0 = phi0_2 - phi0_1;
701 720198 : tau = tau2 - tau1;
702 720198 : r = r2-r1;
703 720198 : disp = disp2-disp1;
704 : }
705 :
706 12199726 : for (size_t ichan = 0; ichan != v.ncolumn(); ichan++) {
707 11479528 : if (fl(dcorr, ichan, irow)) continue;
708 11428500 : Complex vis = v(dcorr, ichan, irow);
709 : // Fixme: this isn't a square root.
710 11428500 : Double w0 = weights(dcorr, ichan, irow);
711 11428500 : sumwt += w0;
712 11428500 : Double w = w0;
713 11428500 : nobs++;
714 11428500 : if (fabs(w) < FLT_EPSILON) continue;
715 :
716 : // We have to turn the delay back into seconds from nanoseconds.
717 : // Freq difference is in Hz, which comes out typically as 1e6 bands
718 : //Double wDf = (2.0*M_PI)*(freqs(ichan) - freqs(0))*1e-9;
719 11428500 : Double wDf = (2.0*M_PI)*(freqs(ichan) - reffreq0)*1e-9;
720 : //
721 11428500 : Double t1 = s.time()(0);
722 :
723 : //Double ref_freq = freqs(0);
724 : //Double wDt = (2.0*M_PI)*(t1 - refTime) * ref_freq;
725 11428500 : Double wDt = (2.0*M_PI)*(t1 - refTime) * reffreq0;
726 :
727 11428500 : Float freq = freqs(ichan);
728 11428500 : Float k_disp = KDISPSCALE*(2.0*M_PI)*(1.0/freq + (freq-fmin_-fmax)/(fmin_*fmax));
729 :
730 11428500 : Double mtheta = -(phi0 + tau*wDf + r*wDt + disp*k_disp);
731 11428500 : Double vtheta = arg(vis);
732 :
733 : // Hold on a minute though!
734 11428500 : Double cx = w*cos(vtheta - mtheta);
735 :
736 11428500 : Matrix<Double> dterm(4,4);
737 11428500 : dterm(0, 0) = cx;
738 11428500 : dterm(0, 1) = wDf*cx;
739 11428500 : dterm(0, 2) = wDt*cx;
740 11428500 : dterm(0, 3) = k_disp*dterm(0, 1);
741 11428500 : dterm(1, 1) = wDf*dterm(0, 1);
742 11428500 : dterm(1, 2) = wDt*dterm(0, 1);
743 11428500 : dterm(1, 3) = wDf*dterm(0, 3);
744 11428500 : dterm(2, 2) = wDt*dterm(1, 2);
745 11428500 : dterm(2, 3) = wDt*dterm(1, 3);
746 11428500 : dterm(3, 3) = k_disp*dterm(2, 3);
747 :
748 : // Symmetry terms:
749 11428500 : dterm(1, 0) = dterm(0, 1);
750 11428500 : dterm(2, 0) = dterm(0, 2);
751 11428500 : dterm(3, 0) = dterm(0, 3);
752 11428500 : dterm(2, 1) = dterm(1, 2);
753 11428500 : dterm(3, 1) = dterm(1, 3);
754 11428500 : dterm(3, 2) = dterm(2, 3);
755 :
756 :
757 :
758 57142500 : for (Int di=0; di<4; di++) {
759 228570000 : for (Int dj=0; dj<4; dj++) {
760 : Int i, j;
761 276510944 : if (((i = bundle->get_param_corr_param_index(ant1, di))>=0) &&
762 93654944 : ((j = bundle->get_param_corr_param_index(ant1, dj))>=0)) {
763 70316600 : *gsl_matrix_ptr(hess, i, j) += dterm(di, dj);
764 : }
765 : // Exactly the same logic, but with antenna2
766 319368000 : if (((i = bundle->get_param_corr_param_index(ant2, di))>=0) &&
767 136512000 : ((j = bundle->get_param_corr_param_index(ant2, dj))>=0)) {
768 102578832 : *gsl_matrix_ptr(hess, i, j) += dterm(di, dj);
769 : }
770 : }
771 : }
772 : // FIXME: Not just diagonal terms any more!
773 : // Note that some of these are not in the lower
774 : // triangular part, even though they are copied
775 : // faithfully from AIPS which thinks it is filling
776 : // a triangular matrix and handles symmetry
777 : // later. Unless I've missed something (again).
778 57142500 : for (Int di=0; di<4; di++) {
779 228570000 : for (Int dj=0; dj<4; dj++) {
780 : Int i, j;
781 276510944 : if (((i = bundle->get_param_corr_param_index(ant1, di))>=0) &&
782 93654944 : ((j = bundle->get_param_corr_param_index(ant2, dj))>=0)) {
783 70316600 : *gsl_matrix_ptr(hess, i, j) -= dterm(di, dj);
784 70316600 : *gsl_matrix_ptr(hess, j, i) -= dterm(dj, di);
785 : } // if
786 : } // dj
787 : } // di
788 11428500 : } // ichan
789 : } // irow
790 42936 : } // ibuff
791 : // s is more tricky: it is the xi^2 term from exp_f
792 :
793 362 : xi_squared = max(xi_squared, 1e-25);
794 :
795 : if (DEVDEBUG && 0) {
796 : cerr << "The matrix is" << endl;
797 : cerr << setprecision(3) << scientific;
798 : for (size_t i = 0; i != hess->size1; i++) {
799 : for (size_t j = 0; j < hess->size2; j++) {
800 : cerr << gsl_matrix_get(hess,i,j) << " ";
801 : }
802 : cerr << endl;
803 : }
804 : cerr << endl;
805 : // str.unsetf(cerr:floatfield);
806 : cerr << std::defaultfloat;
807 : }
808 : //
809 362 : size_t hsize = hess->size1;
810 : int signum;
811 362 : gsl_permutation *perm = gsl_permutation_alloc (hsize);
812 362 : gsl_matrix *lu = gsl_matrix_alloc(hsize, hsize);
813 362 : gsl_matrix *inv_hess = gsl_matrix_alloc(hsize, hsize);
814 :
815 362 : gsl_linalg_LU_decomp(hess, perm, &signum);
816 362 : Double det = gsl_linalg_LU_det(hess, signum);
817 362 : if ((fabs(det) < GSL_DBL_EPSILON) || std::isnan(det)) {
818 0 : logSink << "Hessian matrix singular (determinant=" << det << "); setting signal-to-noise ratio to zero." << LogIO::POST;
819 : // Singular matrix; fill snrs with zero.
820 0 : for (size_t i=0; i < hess->size1; i+=bundle->nParameters()) {
821 0 : Double snr = 0;
822 0 : gsl_vector_set(snr_vector, i, snr);
823 : }
824 : }
825 : else {
826 362 : gsl_linalg_LU_invert(hess, perm, inv_hess);
827 :
828 362 : Double sigma2 = xi_squared / (nobs - numpar) * nobs / sumwt;
829 : // cerr << "xi_squared " << xi_squared << " Nobs " << nobs << " sumwt " << sumwt << " sigma2 " << sigma2 << endl;
830 2263 : for (size_t i=0; i < hess->size1; i+=bundle->nParameters()) {
831 1901 : Double h = gsl_matrix_get(inv_hess, i, i);
832 1901 : Double snr0 = sqrt(sigma2*h*0.5);
833 1901 : snr0 = min(snr0, 9999.999);
834 1901 : Double snr = (snr0 > 1e-20) ? 1.0/snr0 : snr0;
835 1901 : gsl_vector_set(snr_vector, i, snr);
836 : }
837 : }
838 362 : gsl_matrix_free(lu);
839 362 : gsl_matrix_free(inv_hess);
840 362 : gsl_permutation_free(perm);
841 : // SNR[i], according to aips, is 1/sqrt(sigma2*hess(i1,i1)*0.5);
842 : // Note that in AIPS i1 ranges over 1..NANT
843 : // We use 1 as a success code.
844 362 : return 1;
845 : }
846 :
847 :
848 : Int
849 225 : findRefAntWithData(SDBList& sdbs, Vector<Int>& refAntList, Int prtlev) {
850 225 : std::set<Int> activeAntennas;
851 27744 : for (Int ibuf=0; ibuf != sdbs.nSDB(); ibuf++) {
852 27519 : SolveDataBuffer& s(sdbs(ibuf));
853 27519 : if (!s.Ok())
854 30 : continue;
855 27489 : Cube<Bool> fl = s.flagCube();
856 563779 : for (Int irow=0; irow!=s.nRows(); irow++) {
857 536290 : if (s.flagRow()(irow))
858 1653 : continue;
859 534637 : Int a1(s.antenna1()(irow));
860 534637 : Int a2(s.antenna2()(irow));
861 : // Not using irow
862 534637 : Matrix<Bool> flr = fl.xyPlane(irow);
863 534637 : if (!allTrue(flr)) {
864 504152 : activeAntennas.insert(a1);
865 504152 : activeAntennas.insert(a2);
866 : }
867 534637 : }
868 27489 : }
869 225 : if (prtlev > 2) {
870 0 : cout << "[FringeJones.cc::findRefAntWithData] refantlist " << refAntList << endl;
871 0 : cout << "[FringeJones.cc::findRefAntWithData] activeAntennas: ";
872 0 : std::copy(
873 : activeAntennas.begin(),
874 : activeAntennas.end(),
875 0 : std::ostream_iterator<Int>(std::cout, " ")
876 : );
877 0 : cout << endl;
878 : }
879 225 : Int refAnt = -1;
880 450 : for (Vector<Int>::ConstIteratorSTL a = refAntList.begin(); a != refAntList.end(); a++) {
881 225 : if (activeAntennas.find(*a) != activeAntennas.end()) {
882 225 : if (prtlev > 2)
883 0 : cout << "[FringeJones.cc::findRefAntWithData] We are choosing refant " << *a << endl;
884 225 : refAnt = *a;
885 225 : break;
886 : } else {
887 0 : if (prtlev > 2)
888 0 : cout << "[FringeJones.cc::findRefAntWithData] No data for refant " << *a << endl;
889 : }
890 225 : }
891 225 : return refAnt;
892 225 : }
893 :
894 :
895 : // Stolen from SolveDataBuffer
896 : void
897 225 : aggregateTimeCentroid(SDBList& sdbs, Int refAnt, std::map<Int, Double>& aggregateTime) {
898 : // Weighted average of SDBs' timeCentroids
899 225 : std::map<Int, Double> aggregateWeight;
900 27744 : for (Int i=0; i < sdbs.nSDB(); ++i) {
901 27519 : SolveDataBuffer& s = sdbs(i);
902 27519 : Vector<Double> wtvD;
903 : // Sum over correlations and channels to get a vector of weights for each row
904 55038 : Vector<Float> wtv(partialSums(s.weightSpectrum(), IPosition(2, 0, 1)));
905 27519 : wtvD.resize(wtv.nelements());
906 27519 : convertArray(wtvD, wtv);
907 563989 : for (Int j=0; j<s.nRows(); j++) {
908 536470 : Int a1 = s.antenna1()(j);
909 536470 : Int a2 = s.antenna2()(j);
910 : Int ant;
911 536470 : if (a1 == refAnt) { ant = a2; }
912 393973 : else if (a2 == refAnt) { ant = a1; }
913 393253 : else continue;
914 143217 : Double w = wtv(j);
915 143217 : aggregateTime[ant] += w*s.timeCentroid()(j);
916 143217 : aggregateWeight[ant] += w;
917 : }
918 27519 : }
919 1548 : for (auto it=aggregateTime.begin(); it!=aggregateTime.end(); ++it) {
920 1323 : Int a = it->first;
921 1323 : it->second /= aggregateWeight[a];
922 : }
923 :
924 225 : }
925 :
926 :
927 : void
928 0 : print_gsl_vector(gsl_vector *v)
929 : {
930 0 : const size_t n = v->size;
931 0 : for (size_t i=0; i!=n; i++) {
932 0 : cerr << gsl_vector_get(v, i) << " ";
933 0 : if (i>0 && (i % 4)==3) cerr << endl;
934 : }
935 0 : cerr << endl;
936 0 : }
937 :
938 : void
939 0 : print_max_gsl3(gsl_vector *v)
940 : {
941 0 : double phi_max = 0.0;
942 0 : double del_max = 0.0;
943 0 : double rat_max = 0.0;
944 :
945 0 : const size_t n = v->size;
946 0 : for (size_t i=0; i!=n/3; i++) {
947 0 : if (fabs(gsl_vector_get(v, 3*i+0)) > fabs(phi_max)) phi_max = gsl_vector_get(v, 3*i+0);
948 0 : if (fabs(gsl_vector_get(v, 3*i+1)) > fabs(del_max)) del_max = gsl_vector_get(v, 3*i+1);
949 0 : if (fabs(gsl_vector_get(v, 3*i+2)) > fabs(rat_max)) rat_max = gsl_vector_get(v, 3*i+2);
950 : }
951 0 : cerr << "phi_max " << phi_max << " del_max " << del_max << " rat_max " << rat_max << endl;
952 0 : }
953 :
954 :
955 :
956 : /*
957 : gsl-2.4/multilarge_nlinear/fdf.c defines gsl_multilarge_nlinear_driver,
958 : which I have butchered for my purposes here into
959 : not_gsl_multilarge_nlinear_driver(). We still iterate the nonlinear
960 : least squares solver until completion, but we adopt a convergence
961 : criterion copied from AIPS.
962 :
963 : Inputs: maxiter - maximum iterations to allow
964 : w - workspace
965 :
966 : Additionally I've removed the info parameter, and I may yet regret it.
967 :
968 : Originally:
969 : info - (output) info flag on why iteration terminated
970 : 1 = stopped due to small step size ||dx|
971 : 2 = stopped due to small gradient
972 : 3 = stopped due to small change in f
973 : GSL_ETOLX = ||dx|| has converged to within machine
974 : precision (and xtol is too small)
975 : GSL_ETOLG = ||g||_inf is smaller than machine
976 : precision (gtol is too small)
977 : GSL_ETOLF = change in ||f|| is smaller than machine
978 : precision (ftol is too small)
979 :
980 : Return:
981 : GSL_SUCCESS if converged
982 : GSL_MAXITER if maxiter exceeded without converging
983 : GSL_ENOPROG if no accepted step found on first iteration
984 : */
985 :
986 : int
987 362 : least_squares_inner_driver (const size_t maxiter,
988 : gsl_multilarge_nlinear_workspace * w,
989 : AuxParamBundle *bundle)
990 : {
991 : int status;
992 362 : size_t iter = 0;
993 : /* call user callback function prior to any iterations
994 : * with initial system state */
995 : Double s;
996 362 : Double last_s = 1.0e30;
997 362 : Bool converged = false;
998 : do {
999 2743 : status = gsl_multilarge_nlinear_iterate (w);
1000 : /*
1001 : * If the solver reports no progress on the first iteration,
1002 : * then it didn't find a single step to reduce the
1003 : * cost function and more iterations won't help so return.
1004 : *
1005 : * If we get a no progress flag on subsequent iterations,
1006 : * it means we did find a good step in a previous iteration,
1007 : * so continue iterating since the solver has now reset
1008 : * mu to its initial value.
1009 : */
1010 2743 : if (status == GSL_ENOPROG && iter == 0) {
1011 0 : return GSL_EMAXITER;
1012 : }
1013 :
1014 2743 : Double fnorm = gsl_blas_dnrm2(w->f);
1015 2743 : s = 0.5 * fnorm * fnorm;
1016 : if (DEVDEBUG) {
1017 : cerr << "Iter: " << iter << " ";
1018 : cerr << "Parameters: " << endl;
1019 : print_gsl_vector(w->x);
1020 : print_max_gsl3(w->dx);
1021 : cerr << "1 - s/last_s=" << 1 - s/last_s << endl;
1022 : }
1023 2743 : ++iter;
1024 2743 : if ((1 - s/last_s < 5e-6) && (iter > 1)) converged = true;
1025 2743 : last_s = s;
1026 : /* old test for convergence:
1027 : status = not_gsl_multilarge_nlinear_test(xtol, gtol, ftol, info, w); */
1028 2743 : } while (!converged && iter < maxiter);
1029 : /*
1030 : * the following error codes mean that the solution has converged
1031 : * to within machine precision, so record the error code in info
1032 : * and return success
1033 : */
1034 362 : if (status == GSL_ETOLF || status == GSL_ETOLX || status == GSL_ETOLG)
1035 : {
1036 0 : status = GSL_SUCCESS;
1037 : }
1038 : /* check if max iterations reached */
1039 362 : if (iter >= maxiter && status != GSL_SUCCESS)
1040 362 : status = GSL_EMAXITER; return status;
1041 : } /* gsl_multilarge_nlinear_driver() */
1042 :
1043 :
1044 :
1045 :
1046 : void
1047 225 : least_squares_driver(SDBList& sdbs, Matrix<Float>& casa_param, Matrix<Bool>& casa_flags, Matrix<Float>& casa_snr, Int refant,
1048 : const std::map< Int, std::set<Int> >& activeAntennas, Int maxits, Vector<Bool> paramActive, LogIO& logSink) {
1049 : // The variable casa_param is the Casa calibration framework's RParam matrix; we transcribe our results into it only at the end.
1050 : // n below is number of variables,
1051 : // p is number of parameters
1052 :
1053 : // We could pass in an AuxParamBundle instead I guess?
1054 225 : AuxParamBundle bundle(sdbs, refant, activeAntennas, paramActive);
1055 587 : for (size_t icor=0; icor != bundle.get_num_corrs(); icor++) {
1056 362 : bundle.set_active_corr(icor);
1057 362 : if (bundle.get_num_antennas() == 0) {
1058 0 : logSink << "No antennas for correlation " << icor << "; not running least-squares solver." << LogIO::POST;
1059 0 : continue;
1060 : }
1061 362 : if (bundle.get_num_antennas() == 1) {
1062 0 : logSink << "No baselines for correlation " << icor << "; not running least-squares solver." << LogIO::POST;
1063 0 : continue;
1064 : }
1065 : // Four parameters for every antenna, with dispersion
1066 362 : size_t p = bundle.nParameters() * (bundle.get_num_antennas() - 1);
1067 : // We need to store complex visibilities in a real matrix so we
1068 : // just store real and imaginary components separately.
1069 362 : size_t n = 2 * bundle.get_actual_num_data_points();
1070 :
1071 : if (DEVDEBUG) {
1072 : cerr << "bundle.nParameters() " << bundle.nParameters()
1073 : << " bundle.get_num_antennas() " <<bundle.get_num_antennas() << endl;
1074 : cerr << "p " << p << " n " << n << endl;
1075 : }
1076 : // Parameters for the least-squares solver.
1077 : // param_tol sets roughly the number of decimal places accuracy you want in the answer;
1078 : // I feel that 3 is probably plenty for fringe fitting.
1079 : // param_tol is not used
1080 : //const double param_tol = 1.0e-3;
1081 : // gtol is not used
1082 : // const double gtol = pow(GSL_DBL_EPSILON, 1.0/3.0);
1083 : // ftol is not used
1084 : // const double ftol = 1.0e-20;
1085 362 : const size_t max_iter = maxits ;
1086 :
1087 362 : const gsl_multilarge_nlinear_type *T = gsl_multilarge_nlinear_trust;
1088 362 : gsl_multilarge_nlinear_parameters params = gsl_multilarge_nlinear_default_parameters();
1089 : // the Moré scaling is the best equipped to handle very different scales;
1090 : //it should be the best choice to accommodate dispersive terms of O(f)
1091 362 : params.scale = gsl_multilarge_nlinear_scale_more;
1092 362 : params.trs = gsl_multilarge_nlinear_trs_lm;
1093 362 : params.solver = gsl_multilarge_nlinear_solver_cholesky;
1094 362 : gsl_multilarge_nlinear_workspace *w = gsl_multilarge_nlinear_alloc(T, ¶ms, n, p);
1095 : gsl_multilarge_nlinear_fdf f;
1096 :
1097 362 : f.f = &expb_f;
1098 : /* Can't set to NULL for finite-difference Jacobian in multilarge case. */
1099 362 : f.df = &expb_df;
1100 362 : f.n = n; /* number of data points */
1101 362 : f.p = p; /* number of parameters */
1102 362 : f.params = &bundle;
1103 :
1104 :
1105 : // Our original param is a matrix of (3*nCorr, nElem).
1106 : // We have to transcribe it to a vector.
1107 :
1108 362 : gsl_vector *gp = gsl_vector_alloc(p);
1109 362 : gsl_vector_set_zero(gp);
1110 :
1111 : // We transcribe Casa parameters into gsl vector format, as required by the solver.
1112 2870 : for (size_t iant=0; iant != bundle.get_max_antenna_index()+1; iant++) {
1113 2508 : if (!bundle.isActive(iant)) {
1114 245 : continue;
1115 : }
1116 11315 : for (int di=0; di<4; di++) {
1117 9052 : Int param_ind = bundle.get_param_corr_param_index(iant, di);
1118 9052 : if (param_ind < 0) continue;
1119 5719 : gsl_vector_set(gp, param_ind, casa_param(4*icor + di, iant));
1120 : }
1121 : }
1122 362 : gsl_vector *gp_orig = gsl_vector_alloc(p);
1123 : // Keep a copy of original parameters
1124 362 : gsl_vector_memcpy (gp_orig, gp);
1125 : // initialise workspace
1126 362 : gsl_multilarge_nlinear_init(gp, &f, w);
1127 :
1128 : // compute initial residual norm */
1129 362 : gsl_vector *res_f = gsl_multilarge_nlinear_residual(w);
1130 :
1131 : int info;
1132 362 : int status = least_squares_inner_driver(max_iter, w, &bundle);
1133 362 : double chi1 = gsl_blas_dnrm2(res_f);
1134 :
1135 362 : gsl_vector_sub(gp_orig, w->x);
1136 362 : gsl_vector *res = gsl_multilarge_nlinear_position(w);
1137 :
1138 : // We transcribe values back from gsl_vector to the param matrix
1139 :
1140 362 : gsl_matrix *hess = gsl_matrix_alloc(p,p);
1141 362 : gsl_vector *snr_vector = gsl_vector_alloc(p);
1142 362 : gsl_matrix_set_zero(hess);
1143 362 : gsl_vector_set_zero(snr_vector);
1144 362 : expb_hess(gp, &bundle, hess, chi1*chi1, snr_vector, logSink);
1145 :
1146 : // Transcribe parameters back into CASA arrays
1147 2870 : for (size_t iant=0; iant != bundle.get_max_antenna_index()+1; iant++) {
1148 2508 : if (!bundle.isActive(iant)) continue;
1149 2263 : Int iparam = bundle.get_param_corr_param_index(iant, 0);
1150 2263 : if (iparam<0) {
1151 362 : continue;
1152 : }
1153 : if (DEVDEBUG) {
1154 : logSink << "iparam " << iparam << endl;
1155 : logSink << "Old values for ant " << iant << " correlation " << icor
1156 : << " delay " << casa_param(4*icor + 1, iant) << " ns "
1157 : << " rate " << casa_param(4*icor + 2, iant)
1158 : << " angle " << casa_param(4*icor + 0, iant)
1159 : << endl;
1160 : logSink << "New values for ant " << iant << " correlation " << icor << ":";
1161 : int i;
1162 : if ((i=bundle.get_param_corr_param_index(iant, 0))>=0) {
1163 : logSink << " Angle " << gsl_vector_get(res, i);
1164 : }
1165 : if ((i=bundle.get_param_corr_param_index(iant, 1))>=0) {
1166 : logSink << " delay " << gsl_vector_get(res, i) << " ns ";
1167 : }
1168 : if ((i=bundle.get_param_corr_param_index(iant, 2))>=0) {
1169 : logSink << " rate " << gsl_vector_get(res, i);
1170 : }
1171 : logSink << "." << LogIO::POST;
1172 : }
1173 1901 : if (status==GSL_SUCCESS || status==GSL_EMAXITER) {
1174 : // Current policy is to assume that exceeding max
1175 : // number of iterations is not a deal-breaker, leave it
1176 : // to SNR calculation to decide if the results are
1177 : // useful.
1178 9505 : for (size_t di=0; di<4; di++) {
1179 7604 : int i=bundle.get_param_corr_param_index(iant, di);
1180 7604 : int i0 = bundle.get_param_corr_param_index(iant, 0);
1181 7604 : if (i>=0) {
1182 5719 : casa_param(4*icor + di, iant) = gsl_vector_get(res, i);
1183 5719 : casa_snr(4*icor + di, iant) = gsl_vector_get(snr_vector, i0);
1184 : } else {
1185 1885 : casa_param(4*icor + di, iant) = 0.0;
1186 1885 : casa_snr(4*icor + di, iant) = 0.0;
1187 : }
1188 : }
1189 1901 : } else { // gsl solver failed; flag data
1190 0 : logSink << "Least-squares solver failed to converge; flagging" << endl;
1191 0 : for (size_t di=0; di<4; di++) {
1192 0 : casa_flags(4*icor + di, iant) = false;
1193 : }
1194 : }
1195 : }
1196 :
1197 : logSink << "Least squares complete for correlation " << icor
1198 362 : << " after " << gsl_multilarge_nlinear_niter(w) << " iterations." << LogIO::POST;
1199 :
1200 : // << "reason for stopping: " << ((info == 1) ? "small step size" : "small gradient") << endl
1201 : // << "initial |f(x)| = " << chi0 << endl
1202 : // << "final |f(x)| = " << chi1 << endl
1203 : // << "final step taken = " << diffsize
1204 :
1205 : if (DEVDEBUG) {
1206 : cerr << "casa_param " << casa_param << endl;
1207 :
1208 : switch (info) {
1209 : case 1:
1210 : logSink << "Small step size." << endl;
1211 : break;
1212 : case 2:
1213 : logSink << "Flatness." << endl;
1214 : }
1215 : logSink << LogIO::POST;
1216 : }
1217 362 : gsl_vector_free(gp);
1218 362 : gsl_vector_free(gp_orig);
1219 362 : gsl_vector_free(snr_vector);
1220 362 : gsl_matrix_free(hess);
1221 362 : gsl_multilarge_nlinear_free(w);
1222 : }
1223 225 : }
1224 :
1225 : // **********************************************************
1226 : // CTRateAwareTimeInterp1 Implementations
1227 : //
1228 :
1229 276 : CTRateAwareTimeInterp1::CTRateAwareTimeInterp1(NewCalTable& ct,
1230 : const casacore::String& timetype,
1231 : casacore::Array<Float>& result,
1232 276 : casacore::Array<Bool>& rflag) :
1233 276 : CTTimeInterp1(ct,timetype,result,rflag)
1234 276 : {}
1235 :
1236 : // Destructor (nothing to do locally)
1237 552 : CTRateAwareTimeInterp1::~CTRateAwareTimeInterp1() {}
1238 :
1239 48600 : Bool CTRateAwareTimeInterp1::interpolate(Double newtime) {
1240 : // Call generic first
1241 48600 : if (CTTimeInterp1::interpolate(newtime)) {
1242 : // Only if generic yields new calibration
1243 : // NB: lastWasExact_=exact in generic
1244 20029 : applyPhaseRate(timeType().contains("nearest") || lastWasExact_);
1245 20029 : return true;
1246 : }
1247 : else
1248 : // No change
1249 28571 : return false;
1250 :
1251 : }
1252 :
1253 : // Do the phase rate math
1254 20029 : void CTRateAwareTimeInterp1::applyPhaseRate(Bool single)
1255 : {
1256 :
1257 20029 : Int ispw=mcols_p->spwId()(0); // should only be one (sliced ct_)!
1258 20029 : MSSpectralWindow msSpw(ct_.spectralWindow());
1259 20029 : MSSpWindowColumns msCol(msSpw);
1260 : //Vector<Double> refFreqs;
1261 : //msCol.refFrequency().getColumn(refFreqs,True);
1262 :
1263 20029 : Vector<Double> freqs;
1264 20029 : msCol.chanFreq().get(ispw,freqs,True); // should only be 1
1265 20029 : Double centroidFreq=freqs(0);
1266 :
1267 : // cout << "time = " << (currTime_ - timeRef_) << endl;
1268 :
1269 20029 : if (single) {
1270 1083 : for (Int ipol=0;ipol<2;ipol++) {
1271 722 : Double dtime=(currTime_-timeRef_)-timelist_(currIdx_);
1272 722 : Double phase=result_(IPosition(2,ipol*4,0));
1273 722 : Double rate=result_(IPosition(2,ipol*4+2,0));
1274 722 : phase+=2.0*M_PI*rate*centroidFreq*dtime;
1275 722 : result_(IPosition(2,ipol*4,0))=phase;
1276 : }
1277 : } else {
1278 19668 : Vector<uInt> rows(2); indgen(rows); rows+=uInt(currIdx_);
1279 39336 : Cube<Float> r(mcols_p->fparamArray("",rows));
1280 :
1281 19668 : Vector<Double> dtime(2);
1282 19668 : dtime(0)=(currTime_-timeRef_)-timelist_(currIdx_);
1283 19668 : dtime(1)=(currTime_-timeRef_)-timelist_(currIdx_+1);
1284 19668 : Double wt=dtime(1) / (dtime(1)-dtime(0));
1285 :
1286 :
1287 59004 : for (Int ipol=0;ipol<2;ipol++) {
1288 39336 : Vector<Double> phase(2), rate(2);
1289 39336 : phase(0)=r.xyPlane(0)(IPosition(2,ipol*4,0));
1290 39336 : phase(1)=r.xyPlane(1)(IPosition(2,ipol*4,0));
1291 39336 : rate(0)=r.xyPlane(0)(IPosition(2,ipol*4+2,0));
1292 39336 : rate(1)=r.xyPlane(1)(IPosition(2,ipol*4+2,0));
1293 :
1294 39336 : phase(0)+=2.0*M_PI*rate(0)*centroidFreq*dtime(0);
1295 39336 : phase(1)+=2.0*M_PI*rate(1)*centroidFreq*dtime(1);
1296 :
1297 39336 : Vector<Complex> ph(2);
1298 39336 : ph(0)=Complex(cos(phase(0)),sin(phase(0)));
1299 39336 : ph(1)=Complex(cos(phase(1)),sin(phase(1)));
1300 39336 : ph(0)=Float(wt)*ph(0) + Float(1.0-wt)*ph(1);
1301 39336 : result_(IPosition(2,ipol*4,0))=arg(ph(0));
1302 39336 : }
1303 19668 : }
1304 20029 : }
1305 :
1306 :
1307 :
1308 :
1309 : // **********************************************************
1310 : // FringeJones Implementations
1311 : //
1312 0 : FringeJones::FringeJones(VisSet& vs) :
1313 : VisCal(vs), // virtual base
1314 : VisMueller(vs), // virtual base
1315 0 : GJones(vs) // immediate parent
1316 : {
1317 0 : if (prtlev()>2) cout << "FringeJones::FringeJones(vs)" << endl;
1318 0 : }
1319 :
1320 0 : FringeJones::FringeJones(String msname,Int MSnAnt,Int MSnSpw) :
1321 : VisCal(msname,MSnAnt,MSnSpw), // virtual base
1322 : VisMueller(msname,MSnAnt,MSnSpw), // virtual base
1323 0 : GJones(msname,MSnAnt,MSnSpw) // immediate parent
1324 : {
1325 0 : if (prtlev()>2) cout << "FringeJones::FringeJones(msname,MSnAnt,MSnSpw)" << endl;
1326 0 : }
1327 :
1328 39 : FringeJones::FringeJones(const MSMetaInfoForCal& msmc) :
1329 : VisCal(msmc), // virtual base
1330 : VisMueller(msmc), // virtual base
1331 39 : GJones(msmc) // immediate parent
1332 : {
1333 39 : if (prtlev()>2) cout << "FringeJones::FringeJones(msmc)" << endl;
1334 39 : }
1335 :
1336 0 : FringeJones::FringeJones(Int nAnt) :
1337 : VisCal(nAnt),
1338 : VisMueller(nAnt),
1339 0 : GJones(nAnt)
1340 : {
1341 0 : if (prtlev()>2) cout << "FringeJones::FringeJones(nAnt)" << endl;
1342 0 : }
1343 :
1344 78 : FringeJones::~FringeJones() {
1345 39 : if (prtlev()>2) cout << "FringeJones::~FringeJones()" << endl;
1346 78 : }
1347 :
1348 5 : void FringeJones::setApply(const Record& apply) {
1349 : // Call parent to do conventional things
1350 5 : GJones::setApply(apply);
1351 :
1352 5 : if (calWt())
1353 5 : logSink() << " (" << this->typeName() << ": Enforcing calWt()=false for phase/delay-like terms)" << LogIO::POST;
1354 :
1355 : // Enforce calWt() = false for delays
1356 5 : calWt()=false;
1357 :
1358 : /*
1359 : // Extract per-spw ref Freq for phase(delay) calculation
1360 : // from the CalTable
1361 : // TBD: revise as per refFreq decisions
1362 : MSSpectralWindow msSpw(ct_->spectralWindow());
1363 : MSSpWindowColumns msCol(msSpw);
1364 : msCol.refFrequency().getColumn(KrefFreqs_,true);
1365 : KrefFreqs_/=1.0e9; // in GHz
1366 :
1367 : /// Re-assign KrefFreq_ according spwmap (if any)
1368 : if (spwMap().nelements()>0) {
1369 : Vector<Double> tmpfreqs;
1370 : tmpfreqs.assign(KrefFreqs_);
1371 : for (uInt ispw=0;ispw<spwMap().nelements();++ispw)
1372 : if (spwMap()(ispw)>-1)
1373 : KrefFreqs_(ispw)=tmpfreqs(spwMap()(ispw));
1374 : }
1375 : */
1376 :
1377 : // Use the "physical" (centroid) frequency, per spw
1378 5 : MSSpectralWindow msSpw(ct_->spectralWindow());
1379 5 : MSSpWindowColumns msCol(msSpw);
1380 5 : Vector<Double> tmpfreqs;
1381 5 : Vector<Double> chanfreq;
1382 5 : tmpfreqs.resize(msSpw.nrow());
1383 25 : for (rownr_t ispw=0;ispw<msSpw.nrow();++ispw) {
1384 20 : if (ispw < msSpw.nrow()) {
1385 20 : msCol.chanFreq().get(ispw,chanfreq,true); // reshape, if nec.
1386 20 : Int nch=chanfreq.nelements();
1387 20 : tmpfreqs(ispw)=chanfreq(nch/2);
1388 : }
1389 : }
1390 :
1391 5 : KrefFreqs_.resize(nSpw()); KrefFreqs_.set(0.0);
1392 25 : for (rownr_t ispw=0;ispw<(rownr_t)nSpw();++ispw) {
1393 20 : if (ispw < tmpfreqs.nelements())
1394 20 : KrefFreqs_(ispw)=tmpfreqs(ispw);
1395 : }
1396 :
1397 : /// Re-assign KrefFreq_ according spwmap (if any)
1398 5 : if (spwMap().nelements()>0) {
1399 10 : for (uInt ispw=0;ispw<spwMap().nelements();++ispw)
1400 5 : if (spwMap()(ispw)>-1 && ispw < tmpfreqs.nelements())
1401 0 : KrefFreqs_(ispw)=tmpfreqs(spwMap()(ispw));
1402 : }
1403 :
1404 5 : KrefFreqs_/=1.0e9; // in GHz
1405 5 : }
1406 :
1407 0 : void FringeJones::setApply() {
1408 : // This was omitted in copying KJones. It shouldn't have been.
1409 :
1410 : // Call parent to do conventional things
1411 0 : GJones::setApply();
1412 :
1413 : // Enforce calWt() = false for delays
1414 0 : calWt()=false;
1415 :
1416 : // Set the ref freqs to something usable
1417 0 : KrefFreqs_.resize(nSpw());
1418 0 : KrefFreqs_.set(5.0);
1419 :
1420 0 : }
1421 :
1422 :
1423 2 : void FringeJones::setCallib(const Record& callib,
1424 : const MeasurementSet& selms) {
1425 :
1426 : // Call parent to do conventional things
1427 2 : SolvableVisCal::setCallib(callib,selms);
1428 :
1429 : /*
1430 : if (calWt())
1431 : logSink() << " (" << this->typeName() << ": Enforcing calWt()=false for phase/delay-like terms)" << LogIO::POST;
1432 : */
1433 : // Enforce calWt() = false for delays
1434 2 : calWt()=false;
1435 :
1436 : /*
1437 : // Extract per-spw ref Freq for phase(delay) calculation
1438 : // from the CalTable
1439 : KrefFreqs_.assign(cpp_->refFreqIn());
1440 : KrefFreqs_/=1.0e9; // in GHz
1441 :
1442 : // Re-assign KrefFreq_ according spwmap (if any)
1443 : if (spwMap().nelements()>0) {
1444 : Vector<Double> tmpfreqs;
1445 : tmpfreqs.assign(KrefFreqs_);
1446 : for (uInt ispw=0;ispw<spwMap().nelements();++ispw)
1447 : if (spwMap()(ispw)>-1)
1448 : KrefFreqs_(ispw)=tmpfreqs(spwMap()(ispw));
1449 : }
1450 : */
1451 :
1452 : // Use the "physical" (centroid) frequency, per spw
1453 2 : KrefFreqs_.resize(nSpw());
1454 10 : for (Int ispw=0;ispw<nSpw();++ispw) {
1455 8 : const Vector<Double>& f(cpp_->freqIn(ispw));
1456 8 : Int nf=f.nelements();
1457 8 : KrefFreqs_[ispw]=f[nf/2]; // center (usually this will be same as [0])
1458 : }
1459 2 : KrefFreqs_/=1.0e9; // In GHz
1460 :
1461 : // Re-assign KrefFreq_ according spwmap (if any)
1462 2 : if (spwMap().nelements()>0) {
1463 2 : Vector<Double> tmpfreqs;
1464 2 : tmpfreqs.assign(KrefFreqs_);
1465 4 : for (uInt ispw=0;ispw<spwMap().nelements();++ispw)
1466 2 : if (spwMap()(ispw)>-1)
1467 0 : KrefFreqs_(ispw)=tmpfreqs(spwMap()(ispw));
1468 2 : }
1469 :
1470 2 : }
1471 :
1472 32 : void FringeJones::setSolve(const Record& solve) {
1473 :
1474 : // Call parent to do conventional things
1475 32 : GJones::setSolve(solve);
1476 32 : preavg() = -DBL_MAX;
1477 :
1478 : // refant isn't properly set until selfSolveOne. We set it to a
1479 : // known value here so that it can be checked in debugging code.
1480 32 : refant() = -1;
1481 32 : if (prtlev() > 2) {
1482 0 : cout << "Before GJones::setSolve" << endl
1483 0 : << "FringeJones::setSolve()" <<endl
1484 0 : << "FringeJones::refant() = "<< refant() <<endl
1485 0 : << "FringeJones::refantlist() = "<< refantlist() <<endl;
1486 : }
1487 32 : if (solve.isDefined("zerorates")) {
1488 32 : zeroRates() = solve.asBool("zerorates");
1489 : }
1490 32 : if (solve.isDefined("globalsolve")) {
1491 32 : globalSolve() = solve.asBool("globalsolve");
1492 : }
1493 32 : if (solve.isDefined("delaywindow")) {
1494 32 : Array<Double> dw = solve.asArrayDouble("delaywindow");
1495 32 : delayWindow() = dw;
1496 32 : } else {
1497 0 : cerr << "No delay window!" << endl;
1498 : }
1499 32 : if (solve.isDefined("ratewindow")) {
1500 32 : rateWindow() = solve.asArrayDouble("ratewindow");
1501 : } else {
1502 0 : cerr << "No rate window!" << endl;
1503 : }
1504 32 : if (solve.isDefined("niter")) {
1505 32 : maxits() = solve.asInt("niter");
1506 : }
1507 32 : if (solve.isDefined("paramactive")) {
1508 32 : paramActive() = solve.asArrayBool("paramactive");
1509 : }
1510 32 : if (solve.isDefined("concatspws")) {
1511 32 : concatSPWs() = solve.asBool("concatspws");
1512 : }
1513 32 : if (solve.isDefined("corrcomb")) {
1514 : //cerr << "FringeJones::setsolve() Corrcomb is set! To:"
1515 : // << solve.asString("corrcomb")
1516 : // << endl;
1517 32 : corrcomb() = solve.asString("corrcomb");
1518 : }
1519 32 : }
1520 :
1521 : // Note: this was previously omitted
1522 0 : void FringeJones::specify(const Record& specify) {
1523 :
1524 0 : return SolvableVisCal::specify(specify);
1525 :
1526 : }
1527 :
1528 4680 : void FringeJones::calcAllJones() {
1529 :
1530 4680 : if (prtlev()>6) cout << " FringeJones::calcAllJones()" << endl;
1531 :
1532 : // Should handle OK flags in this method, and only
1533 : // do Jones calc if OK
1534 :
1535 4680 : Vector<Complex> oneJones;
1536 4680 : Vector<Bool> oneJOK;
1537 4680 : Vector<Float> onePar;
1538 4680 : Vector<Bool> onePOK;
1539 :
1540 4680 : ArrayIterator<Complex> Jiter(currJElem(),1);
1541 4680 : ArrayIterator<Bool> JOKiter(currJElemOK(),1);
1542 4680 : ArrayIterator<Float> Piter(currRPar(),1);
1543 4680 : ArrayIterator<Bool> POKiter(currParOK(),1);
1544 :
1545 : Double phase;
1546 :
1547 53280 : for (Int iant=0; iant<nAnt(); iant++) {
1548 48600 : onePar.reference(Piter.array());
1549 48600 : onePOK.reference(POKiter.array());
1550 :
1551 48600 : Float fmin_ = min(currFreq());
1552 48600 : Float fmax = max(currFreq());
1553 1638360 : for (Int ich=0; ich<nChanMat(); ich++) {
1554 :
1555 1589760 : oneJones.reference(Jiter.array());
1556 1589760 : oneJOK.reference(JOKiter.array());
1557 :
1558 4769280 : for (Int ipar=0;ipar<nPar();ipar+=4) {
1559 3179520 : if (onePOK(ipar)) {
1560 967680 : Float freq = currFreq()(ich);
1561 967680 : Float k_disp = 1e-9*KDISPSCALE*(2.0*M_PI)*(1.0/freq + (freq-fmin_-fmax)/(fmin_*fmax));
1562 :
1563 967680 : phase=onePar(ipar);
1564 967680 : phase+=2.0*M_PI*onePar(ipar+1)*
1565 967680 : (currFreq()(ich)-KrefFreqs_(currSpw()));
1566 967680 : phase+=2.0*M_PI*onePar(ipar+2)*KrefFreqs_(currSpw())*1e9*
1567 967680 : (currTime() - refTime());
1568 967680 : Float dph_d = onePar(ipar+3) * k_disp;
1569 : if (DEVDEBUG && 0) {
1570 : cerr << "fmin_ " << fmin_ << " fmax " << fmax << " k_disp " << k_disp
1571 : << " param " << onePar(ipar+3) << " dph_d " << dph_d << endl;
1572 : }
1573 967680 : phase+=dph_d;
1574 967680 : oneJones(ipar/4)=Complex(cos(phase),sin(phase));
1575 967680 : oneJOK(ipar/4)=True;
1576 : } else {
1577 2211840 : oneJOK(ipar/4)=False;
1578 : }
1579 : }
1580 : // Advance iterators
1581 1589760 : Jiter.next();
1582 1589760 : JOKiter.next();
1583 : }
1584 : // Step to next antenns's pars
1585 48600 : Piter.next();
1586 48600 : POKiter.next();
1587 : }
1588 4680 : }
1589 :
1590 :
1591 : void
1592 225 : FringeJones::calculateSNR(Int nCorr, DelayRateFFT& drf) {
1593 225 : Matrix<Float> sRP(solveRPar().nonDegenerate(1));
1594 225 : Matrix<Bool> sPok(solveParOK().nonDegenerate(1));
1595 225 : Matrix<Float> sSNR(solveParSNR().nonDegenerate(1));
1596 :
1597 587 : for (size_t icor=0; icor != (size_t) nCorr; icor++) {
1598 362 : const set<Int>& activeAntennas = drf.getActiveAntennasCorrelation(icor);
1599 3906 : for (Int iant=0; iant != nAnt(); iant++) {
1600 3544 : if (iant == refant()) {
1601 362 : Double maxsnr = 999.0;
1602 362 : sSNR(4*icor + 0, iant) = maxsnr;
1603 362 : sSNR(4*icor + 1, iant) = maxsnr;
1604 362 : sSNR(4*icor + 2, iant) = maxsnr;
1605 362 : sSNR(4*icor + 3, iant) = maxsnr;
1606 : }
1607 3182 : else if (activeAntennas.find(iant) != activeAntennas.end()) {
1608 1906 : Double delay = sRP(4*icor + 1, iant);
1609 1906 : Double rate = sRP(4*icor + 2, iant);
1610 : // Note that DelayRateFFT::snr is also used to calculate SNRs for the least square values!
1611 1906 : Float snrval = drf.snr(icor, iant, delay, rate);
1612 1906 : sSNR(4*icor + 0, iant) = snrval;
1613 1906 : sSNR(4*icor + 1, iant) = snrval;
1614 1906 : sSNR(4*icor + 2, iant) = snrval;
1615 1906 : sSNR(4*icor + 3, iant) = snrval;
1616 : } else {
1617 1276 : sPok(4*icor + 0, iant) = false;
1618 1276 : sPok(4*icor + 1, iant) = false;
1619 1276 : sPok(4*icor + 2, iant) = false;
1620 1276 : sPok(4*icor + 3, iant) = false;
1621 : }
1622 : }
1623 : }
1624 225 : }
1625 :
1626 :
1627 :
1628 :
1629 : void
1630 225 : FringeJones::selfSolveOne(SDBList& sdbs) {
1631 225 : solveRPar()=0.0;
1632 225 : solveParOK()=false;
1633 225 : solveParErr()=1.0; // Does nothing?
1634 : // Maybe we put refFreq, refTime stuff in here?
1635 225 : Vector<Double> myRefFreqs;
1636 : // Cannot assume we have a calibration table (ct_) in this method.
1637 : // MSSpectralWindow msSpw(ct_->spectralWindow());
1638 : /// MSSpWindowColumns spwCol(msSpw);
1639 : // spwCol.refFrequency().getColumn(myRefFreqs, true);
1640 : //Double ref_freq = myRefFreqs(currSpw());
1641 : //Double ref_freq = sdbs.freqs()(0);
1642 : if (DEVDEBUG) {
1643 : cerr << "Solving for fringes for spw=" << currSpw() << endl
1644 : << "Valid spws are " << freqMetaData_.validSpws() << endl;
1645 : }
1646 225 : Int spw = currSpw();
1647 225 : Double reffreq = freqMetaData_.freq(spw)(0);
1648 225 : Double t0 = sdbs(0).time()(0);
1649 225 : Double dt0 = refTime() - t0;
1650 : //Double df0 = ref_freq - sdbs.freqs()(0);
1651 : //Double df0 = 0;
1652 225 : Double df0 = reffreq - sdbs(0).freqs()(0); // global center to global edge
1653 :
1654 225 : logSink() << "Solving for fringes for spw=" << currSpw() << " at t="
1655 225 : << MVTime(refTime()/C::day).string(MVTime::YMD,7) << LogIO::POST;
1656 :
1657 225 : std::map<Int, Double> aggregateTime;
1658 : // Set the refant to the first choice that has data!
1659 225 : refant() = findRefAntWithData(sdbs, refantlist(), prtlev());
1660 225 : if (refant()<0) {
1661 0 : logSink() << "Antennas " << refantlist() << LogIO::POST;
1662 : logSink() << "dt0 " << dt0
1663 : << " nSDB() " << sdbs.nSDB()
1664 0 : << LogIO::POST;
1665 0 : throw(AipsError("No valid reference antenna supplied."));
1666 : }
1667 : else {
1668 225 : logSink() << "Using reference antenna " << refant() << LogIO::POST;
1669 : }
1670 225 : aggregateTimeCentroid(sdbs, refant(), aggregateTime);
1671 :
1672 : if (DEVDEBUG) {
1673 : std::cerr << "Weighted time centroids" << endl;
1674 : for (auto it=aggregateTime.begin(); it!=aggregateTime.end(); ++it)
1675 : std::cerr << it->first << " => " << it->second - t0 << std::endl;
1676 : }
1677 :
1678 : // We arrange that we can use either the DelayRateFFT based on concatenation
1679 : // or the new one that combines spectral windows after the FFT
1680 : if (DEVDEBUG) {
1681 : std::cerr << "Making a DelayRateFFT" << endl;
1682 : }
1683 225 : DelayRateFFT *drfp = DelayRateFFT::makeAChild(concatSPWs(), sdbs, refant(), delayWindow(), rateWindow());
1684 : // DelayRateFFT *drfp = new DelayRateFFTConcat(sdbs, refant(), delayWindow(), rateWindow());
1685 : // DelayRateFFT *drfp = new DelayRateFFTConcat(sdbs, refant(), delayWindow(), rateWindow());
1686 : if (DEVDEBUG) {
1687 : cerr << "Made a DelayRateFFT of some kind!" << endl;
1688 : }
1689 225 : drfp->FFT();
1690 225 : drfp->searchPeak();
1691 225 : Matrix<Float> sRP(solveRPar().nonDegenerate(1));
1692 225 : Matrix<Bool> sPok(solveParOK().nonDegenerate(1));
1693 225 : Matrix<Float> sSNR(solveParSNR().nonDegenerate(1));
1694 225 : logSink() << "sPok " << sPok.shape() << LogIO::POST;
1695 :
1696 : // Map from MS antenna number to index
1697 : // transcribe fft results to sRP
1698 225 : Int ncol = drfp->param().ncolumn();
1699 225 : Int nrow = drfp->param().nrow();
1700 : if (DEVDEBUG) {
1701 : std::cerr << "nrow " << nrow << ", ncol " << ncol << endl;
1702 : std::cerr << "drfp->flag() " << drfp->flag() << endl;
1703 : }
1704 :
1705 1799 : for (Int i=0; i!=ncol; i++) { // i==iant
1706 9098 : for (Int j=0; j!=nrow; j++) { // j is parameter number
1707 7524 : Int oj = (j>=3) ? j+1 : j;
1708 7524 : sRP(IPosition(2, oj, i)) = drfp->param()(IPosition(2, j, i));
1709 7524 : sPok(IPosition(2, oj, i)) = !(drfp->flag()(IPosition(2, j, i)));
1710 : }
1711 : // Our estimate for dispersion is zero, unconditionally, and we stand by it.
1712 1574 : sPok(IPosition(2, 3, i)) = true;
1713 1574 : if (nrow > 3)
1714 934 : sPok(IPosition(2, 7, i)) = true;
1715 : }
1716 225 : size_t nCorrOrig(sdbs(0).nCorrelations());
1717 225 : size_t nCorr = (nCorrOrig> 1 ? 2 : 1); // number of p-hands
1718 225 : calculateSNR(nCorr, *drfp);
1719 225 : set<Int> belowThreshold;
1720 225 : Float threshold = minSNR();
1721 :
1722 587 : for (size_t icor=0; icor != nCorr; icor++) {
1723 362 : const set<Int>& activeAntennas = drfp->getActiveAntennasCorrelation(icor);
1724 3906 : for (Int iant=0; iant != nAnt(); iant++) {
1725 3544 : if (iant != refant() && (activeAntennas.find(iant) != activeAntennas.end())) {
1726 1906 : Float s = sSNR(4*icor + 0, iant);
1727 : // Start the log message; finished below
1728 1906 : logSink() << "Antenna " << iant << " correlation " << icor << " has (FFT) SNR of " << s;
1729 1906 : if (s < threshold) {
1730 5 : belowThreshold.insert(iant);
1731 5 : logSink() << " below threshold (" << threshold << ")";
1732 : // Don't assume these will be flagged later; do it right away.
1733 : // (The least squares routine will eventually become optional.)
1734 5 : sPok(4*icor + 0, iant) = false;
1735 5 : sPok(4*icor + 1, iant) = false;
1736 5 : sPok(4*icor + 2, iant) = false;
1737 5 : sPok(4*icor + 3, iant) = false;
1738 : }
1739 : // Finish the log message
1740 1906 : logSink() << "." << LogIO::POST;
1741 : }
1742 : }
1743 : // We currently remove the antennas below SNR threshold from
1744 : // the object used to handle the FFT fringe search.
1745 362 : drfp->removeAntennasCorrelation(icor, belowThreshold);
1746 : if (DEVDEBUG) {
1747 : drfp->printActive();
1748 : }
1749 : }
1750 225 : if (globalSolve()) {
1751 225 : logSink() << "Starting least squares optimization." << LogIO::POST;
1752 : // Note that least_squares_driver is *not* a method of
1753 : // FringeJones so we pass everything in, including the logSink
1754 : // reference. Note also that sRP is passed by reference and
1755 : // altered in place.
1756 450 : least_squares_driver(sdbs, sRP, sPok, sSNR, refant(), drfp->getActiveAntennas(), maxits(),
1757 225 : paramActive(), logSink());
1758 : }
1759 : else {
1760 0 : logSink() << "Skipping least squares optimisation." << LogIO::POST;
1761 : }
1762 :
1763 : if (DEVDEBUG) {
1764 : cerr << "Ref time " << MVTime(refTime()/C::day).string(MVTime::YMD,7) << endl;
1765 : cerr << "df0 " << df0 << " dt0 " << dt0 << " reffreq*dt0 " << reffreq*dt0 << endl;
1766 : cerr << "reffreq " << reffreq << endl;
1767 : cerr << "df0 " << df0 << " dt0 " << dt0 << " reffreq*dt0 " << reffreq*dt0 << endl;
1768 : cerr << "sRP " << sRP << endl;
1769 : }
1770 :
1771 2457 : for (Int iant=0; iant != nAnt(); iant++) {
1772 5776 : for (size_t icor=0; icor != nCorr; icor++) {
1773 3544 : const set<Int>& activeAntennas = drfp->getActiveAntennasCorrelation(icor);
1774 3544 : if (activeAntennas.find(iant) == activeAntennas.end()) {
1775 1281 : continue;
1776 : }
1777 2263 : Double phi0 = sRP(4*icor + 0, iant);
1778 2263 : Double delay = sRP(4*icor + 1, iant);
1779 2263 : Double rate = sRP(4*icor + 2, iant);
1780 2263 : Double k_disp = sRP(4*icor + 3, iant);
1781 2263 : aggregateTime.find(iant);
1782 : // We assume the reference frequency for fringe fitting
1783 : // (which is NOT the one stored in the SPECTRAL_WINDOW
1784 : // table) is the left-hand edge of the frequency grid.
1785 2263 : Double delta1 = df0*delay/1e9;
1786 2263 : Double delta2 = reffreq*dt0*rate;
1787 2263 : Double delta3 = (2.0*M_PI)*(delta1+delta2);
1788 : Double dt;
1789 2263 : auto p = aggregateTime.find(iant);
1790 2263 : if (zeroRates() && p != aggregateTime.end()) {
1791 72 : dt = p->second - t0;
1792 : } else {
1793 2191 : dt = refTime() - t0;
1794 : }
1795 : if (DEVDEBUG) {
1796 : cerr << "Antenna " << iant << ": phi0 " << phi0 << " delay " << delay << " rate " << rate << " dt " << dt << endl
1797 : << "k_disp " << k_disp << endl
1798 : << "reffreq "<< reffreq << " Adding corrections for frequency (" << 360*delta1 << ")"
1799 : << " and time (" << 360*delta2 << ") degrees." << endl;
1800 : }
1801 2263 : sRP(4*icor + 0, iant) += delta3;
1802 : }
1803 : }
1804 :
1805 : // We can zero the rates here (if needed) whether we did least squares or not.
1806 225 : if (zeroRates()) {
1807 12 : logSink() << "Zeroing delay rates in calibration table." << LogIO::POST;
1808 :
1809 36 : for (size_t icor=0; icor != nCorr; icor++) {
1810 224 : for (Int iant=0; iant != nAnt(); iant++) {
1811 200 : sRP(4*icor + 2, iant) = 0.0;
1812 : }
1813 : }
1814 : }
1815 : // Copy the results to the second polarisation for combined pols
1816 405 : if (corrcomb().contains("stokes") ||
1817 180 : corrcomb().contains("parallel")) {
1818 48 : logSink() << "Correlations combined: Copying results to other correlation" << LogIO::POST;
1819 528 : for (Int iant=0; iant != nAnt(); iant++) {
1820 2400 : for (Int i=0; i !=4; i++) {
1821 1920 : sRP(4+i, iant) = sRP(i, iant);
1822 1920 : sPok(4+i, iant) = sPok(i, iant);
1823 1920 : sSNR(4+i, iant) = sSNR(i, iant);
1824 : }
1825 : }
1826 : }
1827 : if (DEVDEBUG) {
1828 : std::cerr << "sPok " << sPok << endl;
1829 : }
1830 225 : delete drfp;
1831 225 : }
1832 :
1833 : void
1834 0 : FringeJones::solveOneVB(const VisBuffer&) {
1835 0 : throw(AipsError("VisBuffer interface not supported!"));
1836 : }
1837 :
1838 :
1839 31 : void FringeJones::globalPostSolveTinker() {
1840 :
1841 : // Re-reference the phase, if requested
1842 31 : if (refantlist()(0)>-1) applyRefAnt();
1843 31 : }
1844 :
1845 31 : void FringeJones::applyRefAnt() {
1846 :
1847 : // TBD:
1848 : // 1. Synchronize refant changes on par axis
1849 : // 2. Implement minimum mean deviation algorithm
1850 :
1851 31 : if (refantlist()(0)<0)
1852 0 : throw(AipsError("No refant specified."));
1853 :
1854 31 : Int nUserRefant=refantlist().nelements();
1855 :
1856 : // Get the preferred refant names from the MS
1857 31 : String refantName(msmc().antennaName(refantlist()(0)));
1858 31 : if (nUserRefant>1) {
1859 0 : refantName+=" (";
1860 0 : for (Int i=1;i<nUserRefant;++i) {
1861 0 : refantName+=msmc().antennaName(refantlist()(i));
1862 0 : if (i<nUserRefant-1) refantName+=",";
1863 : }
1864 0 : refantName+=")";
1865 : }
1866 :
1867 : logSink() << "Applying refant: " << refantName
1868 31 : << " refantmode = " << refantmode();
1869 31 : if (refantmode()=="flex")
1870 31 : logSink() << " (hold alternate refants' phase constant) when refant flagged";
1871 31 : if (refantmode()=="strict")
1872 0 : logSink() << " (flag all antennas when refant flagged)";
1873 31 : logSink() << LogIO::POST;
1874 :
1875 : // Generate a prioritized refant choice list
1876 : // The first entry in this list is the user's primary refant,
1877 : // the second entry is the refant used on the previous interval,
1878 : // and the rest is a prioritized list of alternate refants,
1879 : // starting with the user's secondary (if provided) refants,
1880 : // followed by the rest of the array, in distance order. This
1881 : // makes the priorities correct all the time, and prevents
1882 : // a semi-stochastic alternation (by preferring the last-used
1883 : // alternate, even if nominally higher-priority refants become
1884 : // available)
1885 :
1886 :
1887 : // Extract antenna positions
1888 31 : Matrix<Double> xyz;
1889 31 : if (msName()!="<noms>") {
1890 31 : MeasurementSet ms(msName());
1891 31 : MSAntennaColumns msant(ms.antenna());
1892 31 : msant.position().getColumn(xyz);
1893 31 : }
1894 : else {
1895 : // TBD RO*
1896 0 : CTColumns ctcol(*ct_);
1897 0 : CTAntennaColumns& antcol(ctcol.antenna());
1898 0 : antcol.position().getColumn(xyz);
1899 0 : }
1900 :
1901 : // Calculate (squared) antenna distances, relative
1902 : // to last preferred antenna
1903 31 : Vector<Double> dist2(xyz.ncolumn(),0.0);
1904 124 : for (Int i=0;i<3;++i) {
1905 93 : Vector<Double> row=xyz.row(i);
1906 93 : row-=row(refantlist()(nUserRefant-1));
1907 93 : dist2+=square(row);
1908 93 : }
1909 : // Move preferred antennas to a large distance
1910 62 : for (Int i=0;i<nUserRefant;++i)
1911 31 : dist2(refantlist()(i))=DBL_MAX;
1912 :
1913 : // Generated sorted index
1914 31 : Vector<uInt> ord;
1915 31 : genSort(ord,dist2);
1916 :
1917 : // Assemble the whole choices list
1918 31 : Int nchoices=nUserRefant+1+ord.nelements();
1919 31 : Vector<Int> refantchoices(nchoices,0);
1920 62 : Vector<Int> r(refantchoices(IPosition(1,nUserRefant+1),IPosition(1,refantchoices.nelements()-1)));
1921 31 : convertArray(r,ord);
1922 :
1923 : // set first two to primary preferred refant
1924 31 : refantchoices(0)=refantchoices(1)=refantlist()(0);
1925 :
1926 : // set user's secondary refants (if any)
1927 31 : if (nUserRefant>1)
1928 0 : refantchoices(IPosition(1,2),IPosition(1,nUserRefant))=
1929 0 : refantlist()(IPosition(1,1),IPosition(1,nUserRefant-1));
1930 :
1931 : //cout << "refantchoices = " << refantchoices << endl;
1932 :
1933 :
1934 31 : if (refantmode()=="strict") {
1935 0 : nchoices=1;
1936 0 : refantchoices.resize(1,True);
1937 : }
1938 :
1939 31 : Vector<Int> nPol(nSpw(),2); // TBD:or 1, if data was single pol
1940 :
1941 31 : if (nPar()==8) {
1942 : // Verify that 2nd poln has unflagged solutions, PER SPW
1943 31 : ROCTMainColumns ctmc(*ct_);
1944 :
1945 31 : Block<String> cols(1);
1946 31 : cols[0]="SPECTRAL_WINDOW_ID";
1947 31 : CTIter ctiter(*ct_,cols);
1948 31 : Cube<Bool> fl;
1949 :
1950 125 : while (!ctiter.pastEnd()) {
1951 :
1952 94 : Int ispw=ctiter.thisSpw();
1953 94 : fl.assign(ctiter.flag());
1954 :
1955 94 : IPosition blc(3,0,0,0), trc(fl.shape());
1956 94 : trc-=1; blc(0)=nPar()/2;
1957 :
1958 : // cout << "ispw = " << ispw << " nfalse(fl(1,:,:)) = " << nfalse(fl(blc,trc)) << endl;
1959 :
1960 : // If there are no unflagged solutions in 2nd pol,
1961 : // avoid it in refant calculations
1962 94 : if (nfalse(fl(blc,trc))==0)
1963 40 : nPol(ispw)=1;
1964 :
1965 94 : ctiter.next();
1966 94 : }
1967 31 : }
1968 : // cout << "nPol = " << nPol << endl;
1969 :
1970 31 : Bool usedaltrefant(false);
1971 31 : Int currrefant(refantchoices(0)), lastrefant(-1);
1972 :
1973 31 : Block<String> cols(2);
1974 31 : cols[0]="SPECTRAL_WINDOW_ID";
1975 31 : cols[1]="TIME";
1976 31 : CTIter ctiter(*ct_,cols);
1977 :
1978 : // Arrays to hold per-timestamp solutions
1979 31 : Cube<Float> solA, solB;
1980 31 : Cube<Bool> flA, flB;
1981 31 : Vector<Int> ant1A, ant1B, ant2B;
1982 31 : Matrix<Complex> refPhsr; // the reference phasor [npol,nchan]
1983 31 : Int lastspw(-1);
1984 31 : Bool first(true);
1985 256 : while (!ctiter.pastEnd()) {
1986 225 : Int ispw=ctiter.thisSpw();
1987 225 : if (ispw!=lastspw) first=true; // spw changed, start over
1988 :
1989 : // Read in the current sol, fl, ant1:
1990 225 : solB.assign(ctiter.fparam());
1991 225 : flB.assign(ctiter.flag());
1992 225 : ant1B.assign(ctiter.antenna1());
1993 225 : ant2B.assign(ctiter.antenna2());
1994 :
1995 : // First time thru, 'previous' solution same as 'current'
1996 225 : if (first) {
1997 94 : solA.reference(solB);
1998 94 : flA.reference(flB);
1999 94 : ant1A.reference(ant1B);
2000 : }
2001 225 : IPosition shB(solB.shape());
2002 225 : IPosition shA(solA.shape());
2003 :
2004 : // Find a good refant at this time
2005 : // A good refant is one that is unflagged in all polarizations
2006 : // in the current(B) and previous(A) intervals (so they can be connected)
2007 225 : Int irefA(0),irefB(0); // index on 3rd axis of solution arrays
2008 225 : Int ichoice(0); // index in refantchoicelist
2009 225 : Bool found(false);
2010 225 : IPosition blcA(3,0,0,0),trcA(shA),blcB(3,0,0,0),trcB(shB);
2011 225 : trcA-=1; trcA(0)=trcA(2)=0;
2012 225 : trcB-=1; trcB(0)=trcB(2)=0;
2013 225 : ichoice=0;
2014 450 : while (!found && ichoice<nchoices) {
2015 : // Find index of current refant choice
2016 225 : irefA=irefB=0;
2017 229 : while (ant1A(irefA)!=refantchoices(ichoice) && irefA<shA(2)) ++irefA;
2018 229 : while (ant1B(irefB)!=refantchoices(ichoice) && irefB<shB(2)) ++irefB;
2019 :
2020 225 : if (irefA<shA(2) && irefB<shB(2)) {
2021 :
2022 : // cout << " Trial irefA,irefB: " << irefA << "," << irefB
2023 : // << " Ants=" << ant1A(irefA) << "," << ant1B(irefB) << endl;
2024 :
2025 225 : blcA(2)=trcA(2)=irefA;
2026 225 : blcB(2)=trcB(2)=irefB;
2027 225 : found=true; // maybe
2028 635 : for (Int ipol=0;ipol<nPol(ispw);++ipol) {
2029 410 : blcA(0)=blcB(0)=ipol*nPar()/2;
2030 410 : trcA(0)=trcB(0)=(ipol+1)*nPar()/2-1;
2031 410 : found &= (nfalse(flA(blcA,trcA))>0); // previous interval
2032 410 : found &= (nfalse(flB(blcB,trcB))>0); // current interval
2033 : }
2034 : }
2035 : else
2036 : // irefA or irefB out-of-range
2037 0 : found=false; // Just to be sure
2038 :
2039 225 : if (!found) ++ichoice; // try next choice next round
2040 :
2041 : }
2042 :
2043 225 : if (found) {
2044 : // at this point, irefA/irefB point to a good refant
2045 :
2046 : // Keep track
2047 225 : usedaltrefant|=(ichoice>0);
2048 225 : currrefant=refantchoices(ichoice);
2049 225 : refantchoices(1)=currrefant; // 2nd priorty next time
2050 :
2051 : // cout << " currrefant = " << currrefant << " (" << ichoice << ")" << endl;
2052 :
2053 : // cout << " Final irefA,irefB: " << irefA << "," << irefB
2054 : // << " Ants=" << ant1A(irefA) << "," << ant1B(irefB) << endl;
2055 :
2056 :
2057 : // Only report if using an alternate refant
2058 225 : if (currrefant!=lastrefant && ichoice>0) {
2059 : logSink()
2060 : << "At "
2061 0 : << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7)
2062 : << " ("
2063 : << "Spw=" << ctiter.thisSpw()
2064 : << ", Fld=" << ctiter.thisField()
2065 : << ")"
2066 0 : << ", using refant " << msmc().antennaName(currrefant)
2067 : << " (id=" << currrefant
2068 : << ")" << " (alternate)"
2069 0 : << LogIO::POST;
2070 : }
2071 :
2072 : // Form reference phasor [nPar,nChan]
2073 225 : Matrix<Float> rA,rB;
2074 225 : Matrix<Bool> rflA,rflB;
2075 225 : rB.assign(solB.xyPlane(irefB));
2076 225 : rflB.assign(flB.xyPlane(irefB));
2077 :
2078 225 : if (!first) {
2079 : // Get and condition previous phasor for the current refant
2080 131 : rA.assign(solA.xyPlane(irefA));
2081 131 : rflA.assign(flA.xyPlane(irefA));
2082 131 : rB-=rA;
2083 :
2084 : // Accumulate flags
2085 131 : rflB&=rflA;
2086 : }
2087 :
2088 : // cout << " rB = " << rB << endl;
2089 : // cout << boolalpha << " rflB = " << rflB << endl;
2090 : // TBD: fillChanGaps?
2091 :
2092 : // Now apply reference phasor to all antennas
2093 225 : Matrix<Float> thissol;
2094 2457 : for (Int iant=0;iant<shB(2);++iant) {
2095 2232 : thissol.reference(solB.xyPlane(iant));
2096 2232 : thissol-=rB;
2097 : }
2098 :
2099 : // Set refant, so we can put it back
2100 225 : ant2B=currrefant;
2101 :
2102 : // put back referenced solutions
2103 225 : ctiter.setfparam(solB);
2104 225 : ctiter.setantenna2(ant2B);
2105 :
2106 : // Next time thru, solB is previous
2107 225 : solA.reference(solB);
2108 225 : flA.reference(flB);
2109 225 : ant1A.reference(ant1B);
2110 225 : solB.resize(); // (break references)
2111 225 : flB.resize();
2112 225 : ant1B.resize();
2113 :
2114 225 : lastrefant=currrefant;
2115 225 : first=false; // avoid first-pass stuff from now on
2116 :
2117 225 : } // found
2118 : else {
2119 : logSink()
2120 : << "At "
2121 0 : << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7)
2122 : << " ("
2123 : << "Spw=" << ctiter.thisSpw()
2124 : << ", Fld=" << ctiter.thisField()
2125 : << ")"
2126 : << ", refant (id=" << currrefant
2127 : << ") was flagged; flagging all antennas strictly."
2128 0 : << LogIO::POST;
2129 : // Flag all solutions in this interval
2130 0 : flB.set(True);
2131 0 : ctiter.setflag(flB);
2132 0 : if (ichoice == nchoices){
2133 : logSink() << LogIO::WARN
2134 : << "From time: "
2135 0 : << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7)
2136 : << "in Spw: "
2137 : << ctiter.thisSpw()
2138 : << " refant list exhausted, flagging all solutions"
2139 0 : << LogIO::POST;
2140 : }
2141 : }
2142 :
2143 : // advance to the next interval
2144 225 : lastspw=ispw;
2145 225 : ctiter.next();
2146 225 : }
2147 :
2148 31 : if (usedaltrefant)
2149 : logSink() << LogIO::NORMAL
2150 : << " NB: An alternate refant was used at least once to maintain" << endl
2151 : << " phase continuity where the user's preferred refant drops out." << endl
2152 : << " Alternate refants are held constant in phase (_not_ zeroed)" << endl
2153 : << " during these periods, and the preferred refant may return at" << endl
2154 : << " a non-zero phase. This is generally harmless."
2155 0 : << LogIO::POST;
2156 :
2157 62 : return;
2158 :
2159 31 : }
2160 :
2161 : // CT Smooth for fringefit table
2162 : // Some duplication from CTglobals Smooth
2163 :
2164 0 : void FringeJones::smooth(Vector<Int>& fields,
2165 : const String& smtype,
2166 : const Double& smtime,
2167 : const bool ratesmooth) {
2168 0 : NewCalTable ct = *ct_;
2169 :
2170 : // half-width
2171 0 : Double thw(smtime/2.0);
2172 :
2173 : // Workspace
2174 0 : Vector<Double> times;
2175 0 : Vector<Float> p,newp,pRate, newRate;
2176 0 : Vector<Float> d;
2177 0 : Vector<Bool> pOK, newpOK;
2178 : // Unwrapped
2179 0 : vector<vector<float>> temp;
2180 :
2181 0 : Cube<Float> fpar;
2182 0 : Cube<Bool> fparok,newfparok;
2183 :
2184 0 : Vector<Bool> mask;
2185 :
2186 : // Set up spw col for ref freq
2187 0 : MSSpectralWindow msSpw(ct.spectralWindow());
2188 0 : MSSpWindowColumns msCol(msSpw);
2189 :
2190 0 : IPosition blc(3,0,0,0), fblc(3,0,0,0);
2191 0 : IPosition trc(3,0,0,0), ftrc(3,0,0,0);
2192 0 : IPosition vec(1,0);
2193 :
2194 0 : Block<String> cols(4);
2195 0 : cols[0]="SPECTRAL_WINDOW_ID";
2196 0 : cols[1]="FIELD_ID";
2197 0 : cols[2]="ANTENNA1";
2198 0 : cols[3]="ANTENNA2";
2199 0 : CTIter ctiter(ct,cols);
2200 0 : int counter = 0;
2201 :
2202 0 : while (!ctiter.pastEnd()) {
2203 :
2204 : //MSSpectralWindow msSpw(ct.spectralWindow());
2205 : //MSSpWindowColumns msCol(msSpw);
2206 :
2207 0 : Int nSlot=ctiter.nrow();
2208 0 : Int ifld=ctiter.thisField();
2209 0 : Int ispw=ctiter.thisSpw();
2210 :
2211 : // Only if more than one slot in this spw _AND_
2212 : // field is among those requested (if any)
2213 0 : if (nSlot>1 &&
2214 0 : (fields.nelements()<1 || anyEQ(fields,ifld))) {
2215 0 : vec(0)=nSlot;
2216 0 : trc(2)=ftrc(2)=nSlot-1;
2217 :
2218 0 : times.assign(ctiter.time());
2219 :
2220 0 : fpar.assign(ctiter.fparam());
2221 0 : fparok.assign(!ctiter.flag());
2222 0 : newfparok.assign(fparok);
2223 0 : IPosition fsh(fpar.shape());
2224 :
2225 0 : blc(1)=trc(1)=fblc(1)=ftrc(1)=0;
2226 :
2227 : // get chan Freqs
2228 0 : Vector<Double> freqs;
2229 0 : msCol.chanFreq().get(ispw,freqs,True);
2230 0 : Double refFreq = freqs(0);
2231 :
2232 : // For each param (pol)
2233 0 : counter = 0;
2234 0 : temp.clear();
2235 0 : vector<vector<float>> unwrap(2);
2236 : //int polId = 0;
2237 0 : bool polReset = false;
2238 :
2239 : // Smoothing beforehand for rates
2240 :
2241 :
2242 :
2243 : // Need a seperate iter to construct unwrapped phase estimates
2244 : // Iterate over polId rather than ipar
2245 0 : for (Int polId=0; polId<2;++polId) {
2246 0 : temp.clear();
2247 0 : counter = 0;
2248 :
2249 0 : blc(0)=trc(0)=polId * 4;
2250 0 : fblc(0)=ftrc(0)=(polId * 4) + 2;
2251 :
2252 : // Reference slices of par twice. Once for pol and again for delay rates
2253 0 : p.reference(fpar(blc,trc).reform(vec));
2254 0 : newp.assign(p);
2255 0 : pRate.reference(fpar(fblc,ftrc).reform(vec));
2256 0 : newRate.assign(pRate);
2257 0 : pOK.reference(fparok(fblc,ftrc).reform(vec));
2258 0 : newpOK.reference(newfparok(fblc,ftrc).reform(vec));
2259 :
2260 0 : Vector<Bool> mask;
2261 0 : int cycles = 0;
2262 :
2263 0 : for (Int i=0;i<nSlot;++i) {
2264 : // holder for phase, delay, and time
2265 0 : vector<float> holder {0.0, 0.0, 0.0};
2266 : // mask for rate smoothing
2267 : // Make mask
2268 0 : mask = pOK;
2269 0 : mask = (mask && ( (times > (times(i)-thw)) &&
2270 0 : (times <= (times(i)+thw)) ) );
2271 :
2272 :
2273 : // Save the phase rate and time to use for the estimates
2274 :
2275 0 : holder[0] = newp(i);
2276 0 : holder[1] = pRate(i);
2277 0 : holder[2] = times(i);
2278 :
2279 : // Smooth the rates
2280 0 : if (ntrue(mask)>0) {
2281 0 : if (smtype=="mean") {
2282 0 : pRate(i) = mean(newRate(mask));
2283 : }
2284 0 : else if (smtype=="median") {
2285 0 : pRate(i) = median(newRate(mask), false);
2286 : }
2287 : }
2288 :
2289 : // array of phases delays and times to be used in the cycle estimations
2290 0 : temp.push_back(holder);
2291 :
2292 : // Estimate the number of Phase cycles
2293 0 : if (counter == 0) {
2294 : // If we are at 0 we cant interpolate backwards. Just instert as starting value
2295 0 : unwrap[polId].push_back(temp[counter][0]);
2296 : }
2297 : else {
2298 : // Get the time difference between two points
2299 0 : float timeStep = temp[counter][2] - temp[counter-1][2];
2300 : // Get Forwards and backwards predictions (in cycles)
2301 0 : float predictFWDiff = ((temp[counter-1][0]/(2*M_PI)) + (temp[counter-1][1] * refFreq * timeStep * 2) * int(ratesmooth)) - (temp[counter][0]/(2*M_PI));
2302 0 : float predictBWDiff = ((temp[counter][0]/(2*M_PI)) - (temp[counter][1] * refFreq * timeStep * 2) * int(ratesmooth)) - (temp[counter-1][0]/(2*M_PI));
2303 : // Take the average prediction of cycles
2304 0 : float cycleDiff = ((predictFWDiff-predictBWDiff)/2);
2305 : // Adjust total cycle estimate
2306 0 : if (cycleDiff > 0.5) {
2307 0 : cycles += (int)(floor(cycleDiff + 0.5));
2308 : }
2309 0 : if (cycleDiff < 0.5) {
2310 0 : cycles -= (int)(floor(abs(cycleDiff) + 0.5));
2311 : }
2312 :
2313 : // Add unwrapped phase values to array
2314 0 : unwrap[polId].push_back(temp[counter][0] + 2 * M_PI * cycles);
2315 : }
2316 :
2317 : // increment counter
2318 0 : counter++;
2319 0 : }
2320 0 : }
2321 :
2322 : // Convert unwrap to casa Vector so we can use the same mean and masking functions
2323 0 : Vector<Float> unwrapPhasesPol1(unwrap[0]);
2324 0 : Vector<Float> unwrapPhasesPol2(unwrap[1]);
2325 :
2326 : // Regular ipar interation
2327 0 : for (Int ipar=0;ipar<fsh(0);++ipar) {
2328 0 : blc(0)=trc(0)=ipar;
2329 0 : fblc(0)=ftrc(0)=ipar;
2330 :
2331 : // Reference slices of par/parOK
2332 0 : p.reference(fpar(blc,trc).reform(vec));
2333 0 : newp.assign(p);
2334 0 : pOK.reference(fparok(fblc,ftrc).reform(vec));
2335 0 : newpOK.reference(newfparok(fblc,ftrc).reform(vec));
2336 :
2337 0 : Vector<Bool> mask;
2338 :
2339 : //cout << "IPAR: " << ipar << "\n"
2340 : //<< "VAL: " << newp << "\n" << endl;
2341 :
2342 0 : for (Int i=0;i<nSlot;++i) {
2343 : // Make mask
2344 0 : mask = pOK;
2345 0 : mask = (mask && ( (times > (times(i)-thw)) &&
2346 0 : (times <= (times(i)+thw)) ) );
2347 :
2348 0 : if (ntrue(mask)>0) {
2349 0 : if (smtype=="mean") {
2350 :
2351 : // If phases use our unwrapped vector
2352 0 : if (ipar==0) {newp(i)=mean(unwrapPhasesPol1(mask));};
2353 0 : if (ipar==4) {newp(i)=mean(unwrapPhasesPol2(mask));};
2354 :
2355 0 : if (ipar == 0 || ipar == 4){
2356 0 : while (newp(i) < -M_PI) {
2357 0 : newp(i) += 2*M_PI;
2358 : }
2359 0 : while (newp(i) > M_PI) {
2360 0 : newp(i) -= 2*M_PI;
2361 : }
2362 : }
2363 : else{
2364 0 : newp(i)=mean(p(mask));
2365 : }
2366 :
2367 : }
2368 0 : else if (smtype=="median") {
2369 0 : if (ipar==0) {newp(i)=median(unwrapPhasesPol1(mask),false);};
2370 0 : if (ipar==4) {newp(i)=median(unwrapPhasesPol2(mask),false);};
2371 :
2372 : if (ipar == 0 || 4) {
2373 0 : while (newp(i) < -M_PI) {
2374 0 : newp(i) += 2*M_PI;
2375 : }
2376 0 : while (newp(i) > M_PI) {
2377 0 : newp(i) -= 2*M_PI;
2378 : }
2379 : }
2380 : else {
2381 : newp(i)= median(p(mask),false);
2382 : }
2383 : }
2384 0 : newpOK(i)=true;
2385 : }
2386 : else
2387 0 : newpOK(i)=false;
2388 :
2389 : } // i
2390 :
2391 : // keep new ok info
2392 0 : p=newp;
2393 0 : } // ipar
2394 :
2395 : // Put info back
2396 0 : ctiter.setfparam(fpar);
2397 :
2398 0 : ctiter.setflag(!newfparok);
2399 :
2400 0 : } // nSlot>1
2401 :
2402 0 : ctiter.next();
2403 : } // ispw
2404 0 : }
2405 :
2406 :
2407 :
2408 : } //# NAMESPACE CASA - END
2409 :
2410 :
2411 : /*
2412 : Example of use in at Python level:
2413 :
2414 : fringefit(vis="n14c2.ms", caltable="fail.fj", field="",spw="1",intent="",
2415 : selectdata=True, timerange="", antenna="", scan="5", observation="",
2416 : msselect="", solint="inf", refant="EF", minsnr=3.0, append=False,
2417 : gaintable=['n14c2.gcal'], parang=False)
2418 : */
2419 :
|