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: aips2-request@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 0 : AuxParamBundle(SDBList& sdbs_, size_t refant, const std::map< Int, std::set<Int> >& activeAntennas_, Vector<Bool> paramActive) :
107 : sdbs(sdbs_),
108 : nCalls(0),
109 : refant(refant),
110 0 : nCorrelations(sdbs.nCorrelations() > 1 ? 2 : 1),
111 0 : corrStep(sdbs.nCorrelations() > 2 ? 3 : 1),
112 : activeAntennas(activeAntennas_),
113 : parameterFlags(),
114 : parameterMap(),
115 0 : activeCorr(-1)
116 : // corrStep(3)
117 : {
118 0 : Int last_index = sdbs.nSDB() - 1 ;
119 0 : t0 = sdbs(0).time()(0);
120 0 : Double tlast = sdbs(last_index).time()(0);
121 0 : reftime = 0.5*(t0 + tlast);
122 :
123 0 : parameterFlags = paramActive.tovector();
124 0 : Int j = 0; // The CASA parameter index (0=peculiar phase, 1=delay, 2=rate, 3=dispersive)
125 0 : Int i = 0; // the Least Squares parameter vector index, depending on what's being solved for
126 0 : for (auto p=parameterFlags.begin(); p!=parameterFlags.end(); p++) {
127 0 : if (*p) {
128 0 : parameterMap.insert(std::pair<Int, Int>(j, i));
129 0 : i++;
130 : }
131 0 : j++;
132 : }
133 0 : if (i==0) {
134 0 : throw(AipsError("No parameters specified!"));
135 : }
136 0 : nParams = i; // There's always at least one parameter!
137 : // cerr << "AuxParamBundle reftime " << reftime << " t0 " << t0 <<" dt " << tlast - t0 << endl;
138 0 : }
139 :
140 0 : Int nParameters() {
141 0 : return nParams;
142 : }
143 0 : Double get_t0() {
144 0 : return t0;
145 : }
146 : Double
147 : get_ref_time() {
148 : return reftime;
149 : }
150 : size_t
151 0 : get_num_corrs() {
152 : //return sdbs.nCorrelations() > 1 ? 2 : 1;
153 0 : return nCorrelations;
154 : }
155 : size_t
156 0 : get_num_antennas() {
157 0 : if (activeCorr < 0) {
158 0 : throw(AipsError("Correlation out of range."));
159 : }
160 0 : std::set< Int > ants = activeAntennas.find(activeCorr)->second;
161 0 : return (size_t) ants.size();
162 : }
163 : size_t
164 0 : get_max_antenna_index() {
165 0 : if (activeCorr < 0) {
166 0 : throw(AipsError("Correlation out of range."));
167 : }
168 0 : 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 nTotalRows = 0;
174 : for (Int i = 0; i != sdbs.nSDB(); i++) {
175 : nTotalRows += sdbs(i).nRows();
176 : }
177 : return nTotalRows * sdbs.nChannels();
178 : }
179 : Int
180 0 : get_actual_num_data_points() {
181 0 : Int nTotalRows = 0;
182 0 : for (Int i = 0; i != sdbs.nSDB(); i++) {
183 0 : SolveDataBuffer& s (sdbs(i));
184 0 : for (Int irow=0; irow!=s.nRows(); irow++) {
185 0 : if (s.flagRow()(irow)) continue;
186 0 : nTotalRows++;
187 : }
188 : }
189 0 : return nTotalRows * sdbs.nChannels();
190 : }
191 : size_t
192 0 : get_data_corr_index(size_t icorr) {
193 0 : if (icorr > nCorrelations) {
194 0 : throw(AipsError("Correlation out of range."));
195 : }
196 0 : size_t dcorr = icorr * corrStep;
197 0 : return dcorr;
198 : }
199 : bool
200 0 : isActive(size_t iant) {
201 0 : std::set<Int> ants = activeAntennas.find(activeCorr)->second;
202 0 : if (iant == refant) return true;
203 0 : else return (ants.find(iant) != ants.end());
204 : }
205 : Int
206 0 : get_param_corr_param_index(size_t iant0, size_t ipar) {
207 0 : if (iant0 == refant) return -1;
208 0 : int iant1 = antennaIndexMap[iant0];
209 0 : if (iant1 > antennaIndexMap[refant]) {
210 0 : iant1 -= 1;
211 : }
212 : int ipar1;
213 0 : auto p = parameterMap.find(ipar);
214 0 : if (p==parameterMap.end()) {
215 0 : ipar1 = -1;
216 : }
217 : else {
218 0 : ipar1 = (iant1 * nParameters()) + p->second;
219 : }
220 0 : return ipar1;
221 : }
222 : size_t
223 0 : get_active_corr() {
224 0 : return activeCorr;
225 : }
226 : void
227 0 : set_active_corr(size_t icorr) {
228 0 : activeCorr = icorr;
229 0 : antennaIndexMap.clear();
230 0 : Int i = 0;
231 0 : std::set<Int>::iterator it;
232 0 : std::set<Int> ants = activeAntennas.find(activeCorr)->second;
233 0 : for (it = ants.begin(); it != ants.end(); it++) {
234 0 : antennaIndexMap[*it] = i++;
235 : }
236 0 : }
237 : };
238 :
239 :
240 :
241 : void
242 0 : print_baselines(std::set<std::pair< Int, Int > > baselines) {
243 0 : cerr << "Baselines encountered ";
244 0 : std::set<std::pair< Int, Int > >::iterator it;
245 0 : for (it=baselines.begin(); it != baselines.end(); ++it) {
246 0 : cerr << "(" << it->first << ", " << it->second << ") ";
247 : }
248 0 : cerr << endl;
249 0 : }
250 :
251 :
252 : int
253 0 : expb_f(const gsl_vector *param, void *d, gsl_vector *f)
254 : {
255 0 : AuxParamBundle *bundle = (AuxParamBundle *)d;
256 0 : SDBList& sdbs = bundle->sdbs;
257 0 : Double refTime = bundle->get_t0();
258 :
259 0 : gsl_vector_set_zero(f);
260 : // Vector<Double> freqs = sdbs.freqs();
261 :
262 0 : const Double reffreq0=sdbs(0).freqs()(0); // First freq in first SDB
263 :
264 0 : size_t count = 0; // This is the master index.
265 :
266 0 : Double sumwt = 0.0;
267 0 : Double xi_squared = 0.0;
268 :
269 0 : for (Int ibuf=0; ibuf < sdbs.nSDB(); ibuf++) {
270 0 : SolveDataBuffer& s (sdbs(ibuf));
271 0 : if (!s.Ok()) continue;
272 :
273 0 : const Vector<Double> freqs(s.freqs()); // This ibuf's freqs
274 0 : Float fmin_ = min(freqs);
275 0 : Float fmax = max(freqs);
276 :
277 0 : const Cube<Complex>& v(s.visCubeCorrected());
278 0 : const Cube<Bool>& fl(s.flagCube());
279 0 : const Cube<Float>& weights(s.weightSpectrum());
280 :
281 0 : for (Int irow=0; irow!=s.nRows(); irow++) {
282 0 : if (s.flagRow()(irow)) continue;
283 :
284 0 : Int ant1(s.antenna1()(irow));
285 0 : Int ant2(s.antenna2()(irow));
286 0 : if (!bundle->isActive(ant1) || !bundle->isActive(ant2))
287 0 : continue;
288 0 : if (ant1==ant2) continue;
289 :
290 : // VisBuffer.h seems to suggest that a vb.visCube may have shape
291 : // (nCorr(), nChannel(), nRow())
292 0 : size_t icorr0 = bundle->get_active_corr();
293 0 : size_t dcorr = bundle->get_data_corr_index(icorr0);
294 : // We also need to get the right parameters for this,
295 : // polarization (icorr is an encoding of the
296 : // polarization of the correlation products).
297 :
298 : Double phi0, tau, r, disp;
299 : {
300 : Int i;
301 : Double phi0_1, tau1, r1, disp1;
302 : Double phi0_2, tau2, r2, disp2;
303 :
304 0 : phi0_1 = ((i = bundle->get_param_corr_param_index(ant1, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
305 0 : tau1 = ((i = bundle->get_param_corr_param_index(ant1, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
306 0 : r1 = ((i = bundle->get_param_corr_param_index(ant1, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
307 0 : disp1 = ((i = bundle->get_param_corr_param_index(ant1, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
308 :
309 0 : phi0_2 = ((i = bundle->get_param_corr_param_index(ant2, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
310 0 : tau2 = ((i = bundle->get_param_corr_param_index(ant2, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
311 0 : r2 = ((i = bundle->get_param_corr_param_index(ant2, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
312 0 : disp2 = ((i = bundle->get_param_corr_param_index(ant2, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
313 :
314 0 : phi0 = phi0_2 - phi0_1;
315 0 : tau = tau2 - tau1;
316 0 : r = r2-r1;
317 0 : disp = disp2-disp1;
318 : }
319 :
320 0 : for (size_t ichan = 0; ichan != v.ncolumn(); ichan++) {
321 0 : if (fl(dcorr, ichan, irow)) continue;
322 :
323 0 : Float freq = freqs(ichan);
324 0 : Float k_disp = KDISPSCALE*C::_2pi*(1.0/freq + (freq-fmin_-fmax)/(fmin_*fmax));
325 :
326 0 : Complex vis = v(dcorr, ichan, irow);
327 0 : Double w0 = weights(dcorr, ichan, irow);
328 : // FIXME: what should we use to scale the weights?
329 : // Double weightScale = norm(vis);
330 : // Double weightScale = abs(vis);
331 : // Double weightScale = 1;
332 : // Double weightScale = 1/sqrt(w0); // Actually AIPS 0, not AIPS 1!
333 : // Double weightScale = pow(w0, -0.75); // AIPS 2
334 : // Double weightScale = 1/w0; // AIPS 3
335 : // Double weightScale = norm(vis); // Casa 1, I guess
336 0 : Double w = sqrt(w0);
337 0 : sumwt += w*w;
338 0 : if (fabs(w) < FLT_EPSILON) continue;
339 : // We have to turn the delay back into seconds from nanoseconds.
340 : // Freq difference is in Hz, which comes out typically as 1e6 bands
341 : //Double wDf = C::_2pi*(freqs(ichan) - freqs(0))*1e-9;
342 0 : Double wDf = C::_2pi*(freqs(ichan) - reffreq0)*1e-9;
343 : //
344 0 : Double t1 = s.time()(0);
345 : // FIXME: Remind me why we *do* scale wDf with 1e-9
346 : // but do *not* do that with ref_freq?
347 : // I have a theory which is mine:
348 : // this is because tau is in nanoseconds.
349 : //Double ref_freq = freqs(0);
350 : //Double wDt = C::_2pi*(t1 - refTime) * ref_freq;
351 0 : Double wDt = C::_2pi*(t1 - refTime) * reffreq0;
352 :
353 0 : Double mtheta = -(phi0 + tau*wDf + r*wDt + disp*k_disp);
354 0 : Double vtheta = arg(vis);
355 :
356 0 : Double c_r = w*(cos(mtheta) - cos(vtheta));
357 0 : Double c_i = w*(sin(mtheta) - sin(vtheta));
358 0 : gsl_vector_set(f, count, c_r);
359 0 : gsl_vector_set(f, count+1, c_i);
360 :
361 0 : count += 2;
362 0 : xi_squared += c_r*c_r + c_i*c_i;
363 : }
364 : }
365 : }
366 : // cerr << "Residual xi-squared = " << xi_squared << endl;
367 0 : return GSL_SUCCESS;
368 : }
369 :
370 :
371 : int
372 0 : expb_df(CBLAS_TRANSPOSE_t TransJ, const gsl_vector* param, const gsl_vector *u, void *bundle_, gsl_vector *v, gsl_matrix *JTJ)
373 : {
374 :
375 : // param is the current vector for which we're finding the jacobian.
376 : // if TransJ is true, evaluate J^T u and store in v.
377 : // Also store J^T . J in lower half of JTJ.
378 0 : std::set <std::pair < Int, Int> > baselines;
379 0 : AuxParamBundle *bundle = (AuxParamBundle *)bundle_;
380 :
381 0 : SDBList& sdbs = bundle->sdbs;
382 0 : const Double reffreq0=sdbs(0).freqs()(0); // First freq in first SDB
383 :
384 0 : size_t count = 0; // This is the master index.
385 :
386 0 : gsl_vector_set_zero(v);
387 0 : gsl_matrix_set_zero(JTJ);
388 :
389 0 : Double refTime = bundle->get_t0();
390 :
391 0 : for (Int ibuf=0; ibuf < sdbs.nSDB(); ibuf++) {
392 0 : SolveDataBuffer& s (sdbs(ibuf));
393 0 : if (!s.Ok()) continue;
394 :
395 0 : const Vector<Double>& freqs(s.freqs()); // This ibuf's freqs
396 0 : Float fmin_ = min(freqs);
397 0 : Float fmax = max(freqs);
398 0 : const Cube<Complex>& vis(s.visCubeCorrected());
399 0 : const Cube<Bool>& fl(s.flagCube());
400 0 : const Cube<Float>& weights(s.weightSpectrum());
401 :
402 0 : Double t1 = s.time()(0);
403 0 : for (Int irow=0; irow!=s.nRows(); irow++) {
404 0 : if (s.flagRow()(irow)) continue;
405 :
406 0 : Int ant1(s.antenna1()(irow));
407 0 : Int ant2(s.antenna2()(irow));
408 :
409 0 : if (ant1==ant2) continue;
410 0 : if (!bundle->isActive(ant1) || !bundle->isActive(ant2)) {
411 0 : continue;
412 : }
413 :
414 : // VisBuffer.h seems to suggest that a vb.visCube may have shape
415 : // (nCorr(), nChannel(), nRow())
416 :
417 0 : size_t icorr0 = bundle->get_active_corr();
418 0 : size_t dcorr = bundle->get_data_corr_index(icorr0);
419 : // We also need to get the right parameters for this
420 : // polarization (icorr is an encoding of the
421 : // polarization of the correlation products).
422 :
423 : Double phi0, tau, r, disp;
424 : {
425 : Int i;
426 : Double phi0_1, tau1, r1, disp1;
427 : Double phi0_2, tau2, r2, disp2;
428 :
429 0 : phi0_1 = ((i = bundle->get_param_corr_param_index(ant1, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
430 0 : tau1 = ((i = bundle->get_param_corr_param_index(ant1, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
431 0 : r1 = ((i = bundle->get_param_corr_param_index(ant1, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
432 0 : disp1 = ((i = bundle->get_param_corr_param_index(ant1, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
433 :
434 0 : phi0_2 = ((i = bundle->get_param_corr_param_index(ant2, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
435 0 : tau2 = ((i = bundle->get_param_corr_param_index(ant2, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
436 0 : r2 = ((i = bundle->get_param_corr_param_index(ant2, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
437 0 : disp2 = ((i = bundle->get_param_corr_param_index(ant2, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
438 :
439 0 : phi0 = phi0_2 - phi0_1;
440 0 : tau = tau2 - tau1;
441 0 : r = r2-r1;
442 0 : disp = disp2-disp1;
443 : }
444 :
445 :
446 : //Double ref_freq = freqs(0);
447 : //Double wDt = C::_2pi*(t1 - refTime) * ref_freq;
448 0 : Double wDt = C::_2pi*(t1 - refTime) * reffreq0;
449 0 : bool found_data = false;
450 :
451 0 : for (size_t ichan = 0; ichan != vis.ncolumn(); ichan++) {
452 0 : if (fl(dcorr, ichan, irow)) continue;
453 0 : Double w0 = weights(dcorr, ichan, irow);
454 0 : Double w = sqrt(w0);
455 0 : if (fabs(w) < FLT_EPSILON) continue;
456 0 : found_data = true;
457 :
458 0 : Float freq = freqs(ichan);
459 0 : Float k_disp = KDISPSCALE*C::_2pi*(1.0/freq + (freq-fmin_-fmax)/(fmin_*fmax));
460 :
461 : // Add a 1e-9 factor because tau parameter is in nanoseconds.
462 : //Double wDf = C::_2pi*(freqs(ichan) - freqs(0))*1e-9;
463 0 : Double wDf = C::_2pi*(freqs(ichan) - reffreq0)*1e-9;
464 : //
465 0 : Double mtheta = -(phi0 + tau*wDf + r*wDt + disp*k_disp);
466 0 : Double ws = sin(mtheta);
467 0 : Double wc = cos(mtheta);
468 :
469 0 : Double p0 = 1.0;
470 0 : Double p1 = wDf;
471 0 : Double p2 = wDt;
472 0 : Double p3 = k_disp;
473 :
474 0 : Vector<Double> dterm2(4);
475 0 : dterm2(0) = -p0;
476 0 : dterm2(1) = -p1;
477 0 : dterm2(2) = -p2;
478 0 : dterm2(3) = -p3;
479 :
480 0 : Vector<Double> dterm1(4);
481 0 : dterm1(0) = p0;
482 0 : dterm1(1) = p1;
483 0 : dterm1(2) = p2;
484 0 : dterm1(3) = p3;
485 :
486 : /*
487 : What we want to express is just:
488 : J[count + 0, iparam2 + 0] = w*-ws*-1.0;
489 : J[count + 1, iparam2 + 0] = w*+wc*-1.0;
490 : J[count + 0, iparam2 + 1] = w*-ws*-wDf;
491 : J[count + 1, iparam2 + 1] = w*+wc*-wDf;
492 : J[count + 0, iparam2 + 2] = w*-ws*-wDt;
493 : J[count + 1, iparam2 + 2] = w*+wc*-wDt;
494 :
495 : But in the GSL multilarge framework we have to
496 : be ready to calculate either J*u for a given u
497 : or J^T*u, depending on the flag TransJ, and we also have to fill in the
498 :
499 : v[iparam + ...] = J[count + ..., iparam + ...] * u[iparam + ...]
500 :
501 : or
502 :
503 : v[iparam + ...] = J^T[iparam + ..., count + ...] * u[count + ...]
504 :
505 : <https://www.gnu.org/software/gsl/doc/html/nls.html#c.gsl_multifit_nlinear_default_parameters>
506 :
507 : "Additionally, the normal equations matrix J^T J should be stored in the lower half of JTJ."
508 :
509 : So we should also use
510 : JTJ[iparam + ..., iparam + ...] += J^T[iparam + ..., count + ...] J[count + ..., iparam + ...]
511 :
512 : */
513 0 : if (TransJ==CblasNoTrans) {
514 0 : for (Int di=0; di<4; di++) {
515 : Int i;
516 0 : if ((i = bundle->get_param_corr_param_index(ant2, di))>=0) {
517 0 : (*gsl_vector_ptr(v, count + 0)) += (w*-ws*dterm2(di)) * gsl_vector_get(u, i);
518 0 : (*gsl_vector_ptr(v, count + 1)) += (w*+wc*dterm2(di)) * gsl_vector_get(u, i);
519 : }
520 0 : if ((i = bundle->get_param_corr_param_index(ant1, di))>=0) {
521 0 : (*gsl_vector_ptr(v, count + 0)) += gsl_vector_get(u, i) * (w*-ws*dterm1(di));
522 0 : (*gsl_vector_ptr(v, count + 1)) += gsl_vector_get(u, i) * (w*+wc*dterm1(di));
523 : }
524 : }
525 : } else {
526 0 : for (Int di=0; di<4; di++) {
527 : Int i;
528 0 : if ((i = bundle->get_param_corr_param_index(ant2, di))>=0) {
529 0 : (*gsl_vector_ptr(v, i)) += (w*-ws*dterm2(di)) * gsl_vector_get(u, count + 0);
530 0 : (*gsl_vector_ptr(v, i)) += (w*+wc*dterm2(di)) * gsl_vector_get(u, count + 1);
531 : }
532 0 : if ((i = bundle->get_param_corr_param_index(ant1, di))>=0) {
533 0 : (*gsl_vector_ptr(v, i)) += gsl_vector_get(u, count + 0) * (w*-ws*dterm1(di));
534 0 : (*gsl_vector_ptr(v, i)) += gsl_vector_get(u, count + 1) * (w*+wc*dterm1(di));
535 : }
536 : }
537 : }
538 0 : if (JTJ) {
539 : Int i, j;
540 0 : Double wterm = (-ws) * (-ws) + (+wc) * (+wc);
541 0 : if (fabs(1-wterm) > 1e-15)
542 0 : throw AipsError("Insufficiently at one");
543 0 : for (Int di=0; di<4; di++) {
544 0 : for (Int dj=0; dj<=di; dj++) {
545 0 : if (((i = bundle->get_param_corr_param_index(ant2, di))>=0) &&
546 0 : ((j = bundle->get_param_corr_param_index(ant2, dj))>=0)) {
547 0 : (*gsl_matrix_ptr(JTJ, i, j)) += w0*dterm2(di)*dterm2(dj);
548 : }
549 0 : if (((i = bundle->get_param_corr_param_index(ant1, di))>=0) &&
550 0 : ((j = bundle->get_param_corr_param_index(ant1, dj))>=0)) {
551 0 : (*gsl_matrix_ptr(JTJ, i, j)) += w0*dterm1(di)*dterm1(dj);
552 : }
553 : }
554 : }
555 : // iant1 != iant2, so we don't have to worry about collisions
556 0 : for (Int di=0; di<4; di++) {
557 0 : for (Int dj=0; dj<4; dj++) {
558 : Int i0, j0;
559 0 : if (((i0 = bundle->get_param_corr_param_index(ant1, di))>=0) &&
560 0 : ((j0 = bundle->get_param_corr_param_index(ant2, dj))>=0)) {
561 0 : Int i1 = max(i0, j0);
562 0 : Int j1 = min(i0, j0);
563 0 : (*gsl_matrix_ptr(JTJ, i1, j1)) += w0*dterm2(di)*dterm1(dj);
564 : }
565 : }
566 : }
567 0 : count += 2;
568 : } // if JTJ
569 : } // loop over channels
570 0 : if (found_data) {
571 0 : std::pair<Int, Int> antpair = std::make_pair(ant1, ant2);
572 0 : bool newBaseline = (baselines.find(antpair) == baselines.end());
573 0 : if (newBaseline) {
574 0 : baselines.insert(antpair);
575 : // cerr << "paramFlagging for antenna "<< ant1 << ": ";
576 : // for (size_t di=0; di<4; di++) {
577 : // cerr << (bundle->get_param_corr_param_index(ant1, di)>=0) << " ";
578 : // }
579 : // cerr << endl;
580 : // cerr << "indices for antenna "<< ant1 << ": ";
581 : // if (bundle->get_param_corr_param_index(ant1, 0) >= 0) {
582 : // for (size_t di=0; di<4; di++) {
583 : // cerr << bundle->get_param_corr_param_index(ant1, di) << " ";
584 : // }
585 : // cerr << endl;
586 : // }
587 : // cerr << "phi0 " << phi0 << " tau " << tau << " r " << r << endl;
588 : }
589 : }
590 : }
591 : }
592 : if (DEVDEBUG && 0) {
593 : print_baselines(baselines);
594 : cerr << "count " << count << endl;
595 : cerr << "v = ";
596 : for (size_t i=0; i!=v->size; i++) {
597 : cerr << gsl_vector_get(v, i) << " ";
598 : }
599 : cerr << endl;
600 : // if (JTJ) {
601 : // cerr <<"JTJ " << std::scientific << endl;
602 : // for (size_t i=0; i!=JTJ->size1; i++) {
603 : // for (size_t j=0; j!=JTJ->size2; j++) {
604 : // cerr << gsl_matrix_get(JTJ, i, j) << " ";
605 : // }
606 : // cerr << endl;
607 : // }
608 : // cerr << endl;
609 : // }
610 : }
611 0 : return GSL_SUCCESS;
612 : }
613 :
614 :
615 :
616 : int
617 0 : expb_hess(gsl_vector *param, AuxParamBundle *bundle, gsl_matrix *hess, Double xi_squared, gsl_vector *snr_vector, LogIO& logSink)
618 : {
619 : // We calculate the diagonal for the hessian as used by AIPS for
620 : // the signal to noise. The AIPS formulation, by Fred Schwab, is a
621 : // hand-rolled routine that solves a different problem to ours: by
622 : // using a triangular matrix for the Jacobian (requiring antenna i<
623 : // antenna j) the J^T * J term vanishes throughout and the Hessian
624 : // of the Xi^2 functional *only* includes the second-order
625 : // derivative terms, which are usually neglected.
626 : //
627 : // This is very clever, but it also means different covariance and
628 : // information matrices, and therefore a different SNR. Here we
629 : // use a generic least squares solver but we cheat slightly and use
630 : // the AIPS form for the Hessian and SNR calculations.
631 : //
632 : // FIXME: Is there any compelling reason to use gsl_vectors for
633 : // this, given that we're not really hooked in to the gsl
634 : // least squares framework by the time we do this?
635 :
636 0 : SDBList& sdbs = bundle->sdbs;
637 0 : Double refTime = bundle->get_t0();
638 :
639 : // Dimensions of (num_antennas); is the same dimension as
640 : // param vector here.
641 0 : gsl_matrix_set_zero(hess);
642 :
643 0 : const Double reffreq0=sdbs(0).freqs()(0); // First freq in first SDB
644 :
645 0 : size_t nobs = 0;
646 0 : Double sumwt = 0;
647 0 : size_t numpar = param->size;
648 :
649 0 : for (Int ibuf=0; ibuf < sdbs.nSDB(); ibuf++)
650 : {
651 0 : SolveDataBuffer& s (sdbs(ibuf));
652 0 : if (!s.Ok()) continue;
653 :
654 0 : const Vector<Double> freqs(s.freqs()); // This ibuf's freqs
655 0 : Float fmin_ = min(freqs);
656 0 : Float fmax = max(freqs);
657 :
658 0 : const Cube<Complex>& v(s.visCubeCorrected());
659 0 : const Cube<Bool>& fl(s.flagCube());
660 0 : const Cube<Float>& weights(s.weightSpectrum());
661 :
662 :
663 0 : for (Int irow=0; irow!=s.nRows(); irow++) {
664 0 : if (s.flagRow()(irow)) continue;
665 :
666 0 : Int ant1(s.antenna1()(irow));
667 0 : Int ant2(s.antenna2()(irow));
668 0 : if (!bundle->isActive(ant1) || !bundle->isActive(ant2))
669 0 : continue;
670 0 : if (ant1==ant2) continue;
671 :
672 : // VisBuffer.h seems to suggest that a vb.visCube may have shape
673 : // (nCorr(), nChannel(), nRow())
674 0 : size_t icorr0 = bundle->get_active_corr();
675 0 : size_t dcorr = bundle->get_data_corr_index(icorr0);
676 : // We also need to get the right parameters for this,
677 : // polarization (icorr is an encoding of the
678 : // polarization of the correlation products).
679 :
680 : Double phi0, tau, r, disp;
681 : {
682 : Int i;
683 : Double phi0_1, tau1, r1, disp1;
684 : Double phi0_2, tau2, r2, disp2;
685 :
686 0 : phi0_1 = ((i = bundle->get_param_corr_param_index(ant1, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
687 0 : tau1 = ((i = bundle->get_param_corr_param_index(ant1, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
688 0 : r1 = ((i = bundle->get_param_corr_param_index(ant1, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
689 0 : disp1 = ((i = bundle->get_param_corr_param_index(ant1, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
690 :
691 :
692 0 : phi0_2 = ((i = bundle->get_param_corr_param_index(ant2, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
693 0 : tau2 = ((i = bundle->get_param_corr_param_index(ant2, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
694 0 : r2 = ((i = bundle->get_param_corr_param_index(ant2, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
695 0 : disp2 = ((i = bundle->get_param_corr_param_index(ant2, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
696 :
697 0 : phi0 = phi0_2 - phi0_1;
698 0 : tau = tau2 - tau1;
699 0 : r = r2-r1;
700 0 : disp = disp2-disp1;
701 : }
702 :
703 0 : for (size_t ichan = 0; ichan != v.ncolumn(); ichan++) {
704 0 : if (fl(dcorr, ichan, irow)) continue;
705 0 : Complex vis = v(dcorr, ichan, irow);
706 : // Fixme: this isn't a square root.
707 0 : Double w0 = weights(dcorr, ichan, irow);
708 0 : sumwt += w0;
709 0 : Double w = w0;
710 0 : nobs++;
711 0 : if (fabs(w) < FLT_EPSILON) continue;
712 :
713 : // We have to turn the delay back into seconds from nanoseconds.
714 : // Freq difference is in Hz, which comes out typically as 1e6 bands
715 : //Double wDf = C::_2pi*(freqs(ichan) - freqs(0))*1e-9;
716 0 : Double wDf = C::_2pi*(freqs(ichan) - reffreq0)*1e-9;
717 : //
718 0 : Double t1 = s.time()(0);
719 :
720 : //Double ref_freq = freqs(0);
721 : //Double wDt = C::_2pi*(t1 - refTime) * ref_freq;
722 0 : Double wDt = C::_2pi*(t1 - refTime) * reffreq0;
723 :
724 0 : Float freq = freqs(ichan);
725 0 : Float k_disp = KDISPSCALE*C::_2pi*(1.0/freq + (freq-fmin_-fmax)/(fmin_*fmax));
726 :
727 0 : Double mtheta = -(phi0 + tau*wDf + r*wDt + disp*k_disp);
728 0 : Double vtheta = arg(vis);
729 :
730 : // Hold on a minute though!
731 0 : Double cx = w*cos(vtheta - mtheta);
732 :
733 0 : Matrix<Double> dterm(4,4);
734 0 : dterm(0, 0) = cx;
735 0 : dterm(0, 1) = wDf*cx;
736 0 : dterm(0, 2) = wDt*cx;
737 0 : dterm(0, 3) = k_disp*dterm(0, 1);
738 0 : dterm(1, 1) = wDf*dterm(0, 1);
739 0 : dterm(1, 2) = wDt*dterm(0, 1);
740 0 : dterm(1, 3) = wDf*dterm(0, 3);
741 0 : dterm(2, 2) = wDt*dterm(1, 2);
742 0 : dterm(2, 3) = wDt*dterm(1, 3);
743 0 : dterm(3, 3) = k_disp*dterm(2, 3);
744 :
745 : // Symmetry terms:
746 0 : dterm(1, 0) = dterm(0, 1);
747 0 : dterm(2, 0) = dterm(0, 2);
748 0 : dterm(3, 0) = dterm(0, 3);
749 0 : dterm(2, 1) = dterm(1, 2);
750 0 : dterm(3, 1) = dterm(1, 3);
751 0 : dterm(3, 2) = dterm(2, 3);
752 :
753 :
754 :
755 0 : for (Int di=0; di<4; di++) {
756 0 : for (Int dj=0; dj<4; dj++) {
757 : Int i, j;
758 0 : if (((i = bundle->get_param_corr_param_index(ant1, di))>=0) &&
759 0 : ((j = bundle->get_param_corr_param_index(ant1, dj))>=0)) {
760 0 : *gsl_matrix_ptr(hess, i, j) += dterm(di, dj);
761 : }
762 : // Exactly the same logic, but with antenna2
763 0 : if (((i = bundle->get_param_corr_param_index(ant2, di))>=0) &&
764 0 : ((j = bundle->get_param_corr_param_index(ant2, dj))>=0)) {
765 0 : *gsl_matrix_ptr(hess, i, j) += dterm(di, dj);
766 : }
767 : }
768 : }
769 : // FIXME: Not just diagonal terms any more!
770 : // Note that some of these are not in the lower
771 : // triangular part, even though they are copied
772 : // faithfully from AIPS which thinks it is filling
773 : // a triangular matrix and handles symmetry
774 : // later. Unless I've missed something (again).
775 0 : for (Int di=0; di<4; di++) {
776 0 : for (Int dj=0; dj<4; dj++) {
777 : Int i, j;
778 0 : if (((i = bundle->get_param_corr_param_index(ant1, di))>=0) &&
779 0 : ((j = bundle->get_param_corr_param_index(ant2, dj))>=0)) {
780 0 : *gsl_matrix_ptr(hess, i, j) -= dterm(di, dj);
781 0 : *gsl_matrix_ptr(hess, j, i) -= dterm(dj, di);
782 : } // if
783 : } // dj
784 : } // di
785 : } // ichan
786 : } // irow
787 : } // ibuff
788 : // s is more tricky: it is the xi^2 term from exp_f
789 :
790 0 : xi_squared = max(xi_squared, 1e-25);
791 :
792 : if (DEVDEBUG && 0) {
793 : cerr << "The matrix is" << endl;
794 : cerr << setprecision(3) << scientific;
795 : for (size_t i = 0; i != hess->size1; i++) {
796 : for (size_t j = 0; j < hess->size2; j++) {
797 : cerr << gsl_matrix_get(hess,i,j) << " ";
798 : }
799 : cerr << endl;
800 : }
801 : cerr << endl;
802 : // str.unsetf(cerr:floatfield);
803 : cerr << std::defaultfloat;
804 : }
805 : //
806 0 : size_t hsize = hess->size1;
807 : int signum;
808 0 : gsl_permutation *perm = gsl_permutation_alloc (hsize);
809 0 : gsl_matrix *lu = gsl_matrix_alloc(hsize, hsize);
810 0 : gsl_matrix *inv_hess = gsl_matrix_alloc(hsize, hsize);
811 :
812 0 : gsl_linalg_LU_decomp(hess, perm, &signum);
813 0 : Double det = gsl_linalg_LU_det(hess, signum);
814 0 : if ((fabs(det) < GSL_DBL_EPSILON) || std::isnan(det)) {
815 0 : logSink << "Hessian matrix singular (determinant=" << det << "); setting signal-to-noise ratio to zero." << LogIO::POST;
816 : // Singular matrix; fill snrs with zero.
817 0 : for (size_t i=0; i < hess->size1; i+=bundle->nParameters()) {
818 0 : Double snr = 0;
819 0 : gsl_vector_set(snr_vector, i, snr);
820 : }
821 : }
822 : else {
823 0 : gsl_linalg_LU_invert(hess, perm, inv_hess);
824 :
825 0 : Double sigma2 = xi_squared / (nobs - numpar) * nobs / sumwt;
826 : // cerr << "xi_squared " << xi_squared << " Nobs " << nobs << " sumwt " << sumwt << " sigma2 " << sigma2 << endl;
827 0 : for (size_t i=0; i < hess->size1; i+=bundle->nParameters()) {
828 0 : Double h = gsl_matrix_get(inv_hess, i, i);
829 0 : Double snr0 = sqrt(sigma2*h*0.5);
830 0 : snr0 = min(snr0, 9999.999);
831 0 : Double snr = (snr0 > 1e-20) ? 1.0/snr0 : snr0;
832 0 : gsl_vector_set(snr_vector, i, snr);
833 : }
834 : }
835 0 : gsl_matrix_free(lu);
836 0 : gsl_matrix_free(inv_hess);
837 0 : gsl_permutation_free(perm);
838 : // SNR[i], according to aips, is 1/sqrt(sigma2*hess(i1,i1)*0.5);
839 : // Note that in AIPS i1 ranges over 1..NANT
840 : // We use 1 as a success code.
841 0 : return 1;
842 : }
843 :
844 :
845 : Int
846 0 : findRefAntWithData(SDBList& sdbs, Vector<Int>& refAntList, Int prtlev) {
847 0 : std::set<Int> activeAntennas;
848 0 : for (Int ibuf=0; ibuf != sdbs.nSDB(); ibuf++) {
849 0 : SolveDataBuffer& s(sdbs(ibuf));
850 0 : if (!s.Ok())
851 0 : continue;
852 0 : Cube<Bool> fl = s.flagCube();
853 0 : for (Int irow=0; irow!=s.nRows(); irow++) {
854 0 : if (s.flagRow()(irow))
855 0 : continue;
856 0 : Int a1(s.antenna1()(irow));
857 0 : Int a2(s.antenna2()(irow));
858 : // Not using irow
859 0 : Matrix<Bool> flr = fl.xyPlane(irow);
860 0 : if (!allTrue(flr)) {
861 0 : activeAntennas.insert(a1);
862 0 : activeAntennas.insert(a2);
863 : }
864 : }
865 : }
866 0 : if (prtlev > 2) {
867 0 : cout << "[FringeJones.cc::findRefAntWithData] refantlist " << refAntList << endl;
868 0 : cout << "[FringeJones.cc::findRefAntWithData] activeAntennas: ";
869 0 : std::copy(
870 : activeAntennas.begin(),
871 : activeAntennas.end(),
872 0 : std::ostream_iterator<Int>(std::cout, " ")
873 : );
874 0 : cout << endl;
875 : }
876 0 : Int refAnt = -1;
877 0 : for (Vector<Int>::ConstIteratorSTL a = refAntList.begin(); a != refAntList.end(); a++) {
878 0 : if (activeAntennas.find(*a) != activeAntennas.end()) {
879 0 : if (prtlev > 2)
880 0 : cout << "[FringeJones.cc::findRefAntWithData] We are choosing refant " << *a << endl;
881 0 : refAnt = *a;
882 0 : break;
883 : } else {
884 0 : if (prtlev > 2)
885 0 : cout << "[FringeJones.cc::findRefAntWithData] No data for refant " << *a << endl;
886 : }
887 : }
888 0 : return refAnt;
889 : }
890 :
891 :
892 : // Stolen from SolveDataBuffer
893 : void
894 0 : aggregateTimeCentroid(SDBList& sdbs, Int refAnt, std::map<Int, Double>& aggregateTime) {
895 : // Weighted average of SDBs' timeCentroids
896 0 : std::map<Int, Double> aggregateWeight;
897 0 : for (Int i=0; i < sdbs.nSDB(); ++i) {
898 0 : SolveDataBuffer& s = sdbs(i);
899 0 : Vector<Double> wtvD;
900 : // Sum over correlations and channels to get a vector of weights for each row
901 0 : Vector<Float> wtv(partialSums(s.weightSpectrum(), IPosition(2, 0, 1)));
902 0 : wtvD.resize(wtv.nelements());
903 0 : convertArray(wtvD, wtv);
904 0 : for (Int j=0; j<s.nRows(); j++) {
905 0 : Int a1 = s.antenna1()(j);
906 0 : Int a2 = s.antenna2()(j);
907 : Int ant;
908 0 : if (a1 == refAnt) { ant = a2; }
909 0 : else if (a2 == refAnt) { ant = a1; }
910 0 : else continue;
911 0 : Double w = wtv(j);
912 0 : aggregateTime[ant] += w*s.timeCentroid()(j);
913 0 : aggregateWeight[ant] += w;
914 : }
915 : }
916 0 : for (auto it=aggregateTime.begin(); it!=aggregateTime.end(); ++it) {
917 0 : Int a = it->first;
918 0 : it->second /= aggregateWeight[a];
919 : }
920 :
921 0 : }
922 :
923 :
924 : void
925 0 : print_gsl_vector(gsl_vector *v)
926 : {
927 0 : const size_t n = v->size;
928 0 : for (size_t i=0; i!=n; i++) {
929 0 : cerr << gsl_vector_get(v, i) << " ";
930 0 : if (i>0 && (i % 4)==3) cerr << endl;
931 : }
932 0 : cerr << endl;
933 0 : }
934 :
935 : void
936 0 : print_max_gsl3(gsl_vector *v)
937 : {
938 0 : double phi_max = 0.0;
939 0 : double del_max = 0.0;
940 0 : double rat_max = 0.0;
941 :
942 0 : const size_t n = v->size;
943 0 : for (size_t i=0; i!=n/3; i++) {
944 0 : if (fabs(gsl_vector_get(v, 3*i+0)) > fabs(phi_max)) phi_max = gsl_vector_get(v, 3*i+0);
945 0 : if (fabs(gsl_vector_get(v, 3*i+1)) > fabs(del_max)) del_max = gsl_vector_get(v, 3*i+1);
946 0 : if (fabs(gsl_vector_get(v, 3*i+2)) > fabs(rat_max)) rat_max = gsl_vector_get(v, 3*i+2);
947 : }
948 0 : cerr << "phi_max " << phi_max << " del_max " << del_max << " rat_max " << rat_max << endl;
949 0 : }
950 :
951 :
952 :
953 : /*
954 : gsl-2.4/multilarge_nlinear/fdf.c defines gsl_multilarge_nlinear_driver,
955 : which I have butchered for my purposes here into
956 : not_gsl_multilarge_nlinear_driver(). We still iterate the nonlinear
957 : least squares solver until completion, but we adopt a convergence
958 : criterion copied from AIPS.
959 :
960 : Inputs: maxiter - maximum iterations to allow
961 : w - workspace
962 :
963 : Additionally I've removed the info parameter, and I may yet regret it.
964 :
965 : Originally:
966 : info - (output) info flag on why iteration terminated
967 : 1 = stopped due to small step size ||dx|
968 : 2 = stopped due to small gradient
969 : 3 = stopped due to small change in f
970 : GSL_ETOLX = ||dx|| has converged to within machine
971 : precision (and xtol is too small)
972 : GSL_ETOLG = ||g||_inf is smaller than machine
973 : precision (gtol is too small)
974 : GSL_ETOLF = change in ||f|| is smaller than machine
975 : precision (ftol is too small)
976 :
977 : Return:
978 : GSL_SUCCESS if converged
979 : GSL_MAXITER if maxiter exceeded without converging
980 : GSL_ENOPROG if no accepted step found on first iteration
981 : */
982 :
983 : int
984 0 : least_squares_inner_driver (const size_t maxiter,
985 : gsl_multilarge_nlinear_workspace * w,
986 : AuxParamBundle *bundle)
987 : {
988 : int status;
989 0 : size_t iter = 0;
990 : /* call user callback function prior to any iterations
991 : * with initial system state */
992 : Double s;
993 0 : Double last_s = 1.0e30;
994 0 : Bool converged = false;
995 0 : do {
996 0 : status = gsl_multilarge_nlinear_iterate (w);
997 : /*
998 : * If the solver reports no progress on the first iteration,
999 : * then it didn't find a single step to reduce the
1000 : * cost function and more iterations won't help so return.
1001 : *
1002 : * If we get a no progress flag on subsequent iterations,
1003 : * it means we did find a good step in a previous iteration,
1004 : * so continue iterating since the solver has now reset
1005 : * mu to its initial value.
1006 : */
1007 0 : if (status == GSL_ENOPROG && iter == 0) {
1008 0 : return GSL_EMAXITER;
1009 : }
1010 :
1011 0 : Double fnorm = gsl_blas_dnrm2(w->f);
1012 0 : s = 0.5 * fnorm * fnorm;
1013 : if (DEVDEBUG) {
1014 : cerr << "Iter: " << iter << " ";
1015 : cerr << "Parameters: " << endl;
1016 : print_gsl_vector(w->x);
1017 : print_max_gsl3(w->dx);
1018 : cerr << "1 - s/last_s=" << 1 - s/last_s << endl;
1019 : }
1020 0 : ++iter;
1021 0 : if ((1 - s/last_s < 5e-6) && (iter > 1)) converged = true;
1022 0 : last_s = s;
1023 : /* old test for convergence:
1024 : status = not_gsl_multilarge_nlinear_test(xtol, gtol, ftol, info, w); */
1025 0 : } while (!converged && iter < maxiter);
1026 : /*
1027 : * the following error codes mean that the solution has converged
1028 : * to within machine precision, so record the error code in info
1029 : * and return success
1030 : */
1031 0 : if (status == GSL_ETOLF || status == GSL_ETOLX || status == GSL_ETOLG)
1032 : {
1033 0 : status = GSL_SUCCESS;
1034 : }
1035 : /* check if max iterations reached */
1036 0 : if (iter >= maxiter && status != GSL_SUCCESS)
1037 0 : status = GSL_EMAXITER; return status;
1038 : } /* gsl_multilarge_nlinear_driver() */
1039 :
1040 :
1041 :
1042 :
1043 : void
1044 0 : least_squares_driver(SDBList& sdbs, Matrix<Float>& casa_param, Matrix<Bool>& casa_flags, Matrix<Float>& casa_snr, Int refant,
1045 : const std::map< Int, std::set<Int> >& activeAntennas, Int maxits, Vector<Bool> paramActive, LogIO& logSink) {
1046 : // The variable casa_param is the Casa calibration framework's RParam matrix; we transcribe our results into it only at the end.
1047 : // n below is number of variables,
1048 : // p is number of parameters
1049 :
1050 : // We could pass in an AuxParamBundle instead I guess?
1051 0 : AuxParamBundle bundle(sdbs, refant, activeAntennas, paramActive);
1052 0 : for (size_t icor=0; icor != bundle.get_num_corrs(); icor++) {
1053 0 : bundle.set_active_corr(icor);
1054 0 : if (bundle.get_num_antennas() == 0) {
1055 0 : logSink << "No antennas for correlation " << icor << "; not running least-squares solver." << LogIO::POST;
1056 0 : continue;
1057 : }
1058 0 : if (bundle.get_num_antennas() == 1) {
1059 0 : logSink << "No baselines for correlation " << icor << "; not running least-squares solver." << LogIO::POST;
1060 0 : continue;
1061 : }
1062 : // Four parameters for every antenna, with dispersion
1063 0 : size_t p = bundle.nParameters() * (bundle.get_num_antennas() - 1);
1064 : // We need to store complex visibilities in a real matrix so we
1065 : // just store real and imaginary components separately.
1066 0 : size_t n = 2 * bundle.get_actual_num_data_points();
1067 :
1068 : if (DEVDEBUG) {
1069 : cerr << "bundle.nParameters() " << bundle.nParameters()
1070 : << " bundle.get_num_antennas() " <<bundle.get_num_antennas() << endl;
1071 : cerr << "p " << p << " n " << n << endl;
1072 : }
1073 : // Parameters for the least-squares solver.
1074 : // param_tol sets roughly the number of decimal places accuracy you want in the answer;
1075 : // I feel that 3 is probably plenty for fringe fitting.
1076 : // param_tol is not used
1077 : //const double param_tol = 1.0e-3;
1078 : // gtol is not used
1079 : // const double gtol = pow(GSL_DBL_EPSILON, 1.0/3.0);
1080 : // ftol is not used
1081 : // const double ftol = 1.0e-20;
1082 0 : const size_t max_iter = maxits ;
1083 :
1084 0 : const gsl_multilarge_nlinear_type *T = gsl_multilarge_nlinear_trust;
1085 0 : gsl_multilarge_nlinear_parameters params = gsl_multilarge_nlinear_default_parameters();
1086 : // the Moré scaling is the best equipped to handle very different scales;
1087 : //it should be the best choice to accommodate dispersive terms of O(f)
1088 0 : params.scale = gsl_multilarge_nlinear_scale_more;
1089 0 : params.trs = gsl_multilarge_nlinear_trs_lm;
1090 0 : params.solver = gsl_multilarge_nlinear_solver_cholesky;
1091 0 : gsl_multilarge_nlinear_workspace *w = gsl_multilarge_nlinear_alloc(T, ¶ms, n, p);
1092 : gsl_multilarge_nlinear_fdf f;
1093 :
1094 0 : f.f = &expb_f;
1095 : /* Can't set to NULL for finite-difference Jacobian in multilarge case. */
1096 0 : f.df = &expb_df;
1097 0 : f.n = n; /* number of data points */
1098 0 : f.p = p; /* number of parameters */
1099 0 : f.params = &bundle;
1100 :
1101 :
1102 : // Our original param is a matrix of (3*nCorr, nElem).
1103 : // We have to transcribe it to a vector.
1104 :
1105 0 : gsl_vector *gp = gsl_vector_alloc(p);
1106 0 : gsl_vector_set_zero(gp);
1107 :
1108 : // We transcribe Casa parameters into gsl vector format, as required by the solver.
1109 0 : for (size_t iant=0; iant != bundle.get_max_antenna_index()+1; iant++) {
1110 0 : if (!bundle.isActive(iant)) {
1111 0 : continue;
1112 : }
1113 0 : for (int di=0; di<4; di++) {
1114 0 : Int param_ind = bundle.get_param_corr_param_index(iant, di);
1115 0 : if (param_ind < 0) continue;
1116 0 : gsl_vector_set(gp, param_ind, casa_param(4*icor + di, iant));
1117 : }
1118 : }
1119 0 : gsl_vector *gp_orig = gsl_vector_alloc(p);
1120 : // Keep a copy of original parameters
1121 0 : gsl_vector_memcpy (gp_orig, gp);
1122 : // initialise workspace
1123 0 : gsl_multilarge_nlinear_init(gp, &f, w);
1124 :
1125 : // compute initial residual norm */
1126 0 : gsl_vector *res_f = gsl_multilarge_nlinear_residual(w);
1127 :
1128 : int info;
1129 0 : int status = least_squares_inner_driver(max_iter, w, &bundle);
1130 0 : double chi1 = gsl_blas_dnrm2(res_f);
1131 :
1132 0 : gsl_vector_sub(gp_orig, w->x);
1133 0 : gsl_vector *res = gsl_multilarge_nlinear_position(w);
1134 :
1135 : // We transcribe values back from gsl_vector to the param matrix
1136 :
1137 0 : gsl_matrix *hess = gsl_matrix_alloc(p,p);
1138 0 : gsl_vector *snr_vector = gsl_vector_alloc(p);
1139 0 : gsl_matrix_set_zero(hess);
1140 0 : gsl_vector_set_zero(snr_vector);
1141 0 : expb_hess(gp, &bundle, hess, chi1*chi1, snr_vector, logSink);
1142 :
1143 : // Transcribe parameters back into CASA arrays
1144 0 : for (size_t iant=0; iant != bundle.get_max_antenna_index()+1; iant++) {
1145 0 : if (!bundle.isActive(iant)) continue;
1146 0 : Int iparam = bundle.get_param_corr_param_index(iant, 0);
1147 0 : if (iparam<0) {
1148 0 : continue;
1149 : }
1150 : if (DEVDEBUG) {
1151 : logSink << "iparam " << iparam << endl;
1152 : logSink << "Old values for ant " << iant << " correlation " << icor
1153 : << " delay " << casa_param(4*icor + 1, iant) << " ns "
1154 : << " rate " << casa_param(4*icor + 2, iant)
1155 : << " angle " << casa_param(4*icor + 0, iant)
1156 : << endl;
1157 : logSink << "New values for ant " << iant << " correlation " << icor << ":";
1158 : int i;
1159 : if ((i=bundle.get_param_corr_param_index(iant, 0))>=0) {
1160 : logSink << " Angle " << gsl_vector_get(res, i);
1161 : }
1162 : if ((i=bundle.get_param_corr_param_index(iant, 1))>=0) {
1163 : logSink << " delay " << gsl_vector_get(res, i) << " ns ";
1164 : }
1165 : if ((i=bundle.get_param_corr_param_index(iant, 2))>=0) {
1166 : logSink << " rate " << gsl_vector_get(res, i);
1167 : }
1168 : logSink << "." << LogIO::POST;
1169 : }
1170 0 : if (status==GSL_SUCCESS || status==GSL_EMAXITER) {
1171 : // Current policy is to assume that exceeding max
1172 : // number of iterations is not a deal-breaker, leave it
1173 : // to SNR calculation to decide if the results are
1174 : // useful.
1175 0 : for (size_t di=0; di<4; di++) {
1176 0 : int i=bundle.get_param_corr_param_index(iant, di);
1177 0 : int i0 = bundle.get_param_corr_param_index(iant, 0);
1178 0 : if (i>=0) {
1179 0 : casa_param(4*icor + di, iant) = gsl_vector_get(res, i);
1180 0 : casa_snr(4*icor + di, iant) = gsl_vector_get(snr_vector, i0);
1181 : } else {
1182 0 : casa_param(4*icor + di, iant) = 0.0;
1183 0 : casa_snr(4*icor + di, iant) = 0.0;
1184 : }
1185 0 : }
1186 : } else { // gsl solver failed; flag data
1187 0 : logSink << "Least-squares solver failed to converge; flagging" << endl;
1188 0 : for (size_t di=0; di<4; di++) {
1189 0 : casa_flags(4*icor + di, iant) = false;
1190 : }
1191 : }
1192 : }
1193 :
1194 : logSink << "Least squares complete for correlation " << icor
1195 0 : << " after " << gsl_multilarge_nlinear_niter(w) << " iterations." << LogIO::POST;
1196 :
1197 : // << "reason for stopping: " << ((info == 1) ? "small step size" : "small gradient") << endl
1198 : // << "initial |f(x)| = " << chi0 << endl
1199 : // << "final |f(x)| = " << chi1 << endl
1200 : // << "final step taken = " << diffsize
1201 :
1202 : if (DEVDEBUG) {
1203 : cerr << "casa_param " << casa_param << endl;
1204 :
1205 : switch (info) {
1206 : case 1:
1207 : logSink << "Small step size." << endl;
1208 : break;
1209 : case 2:
1210 : logSink << "Flatness." << endl;
1211 : }
1212 : logSink << LogIO::POST;
1213 : }
1214 0 : gsl_vector_free(gp);
1215 0 : gsl_vector_free(gp_orig);
1216 0 : gsl_vector_free(snr_vector);
1217 0 : gsl_matrix_free(hess);
1218 0 : gsl_multilarge_nlinear_free(w);
1219 : }
1220 0 : }
1221 :
1222 :
1223 :
1224 :
1225 : // **********************************************************
1226 : // CTRateAwareTimeInterp1 Implementations
1227 : //
1228 :
1229 0 : CTRateAwareTimeInterp1::CTRateAwareTimeInterp1(NewCalTable& ct,
1230 : const casacore::String& timetype,
1231 : casacore::Array<Float>& result,
1232 0 : casacore::Array<Bool>& rflag) :
1233 0 : CTTimeInterp1(ct,timetype,result,rflag)
1234 0 : {}
1235 :
1236 : // Destructor (nothing to do locally)
1237 0 : CTRateAwareTimeInterp1::~CTRateAwareTimeInterp1() {}
1238 :
1239 0 : Bool CTRateAwareTimeInterp1::interpolate(Double newtime) {
1240 : // Call generic first
1241 0 : if (CTTimeInterp1::interpolate(newtime)) {
1242 : // Only if generic yields new calibration
1243 : // NB: lastWasExact_=exact in generic
1244 0 : applyPhaseRate(timeType().contains("nearest") || lastWasExact_);
1245 0 : return true;
1246 : }
1247 : else
1248 : // No change
1249 0 : return false;
1250 :
1251 : }
1252 :
1253 : // Do the phase rate math
1254 0 : void CTRateAwareTimeInterp1::applyPhaseRate(Bool single)
1255 : {
1256 :
1257 0 : Int ispw=mcols_p->spwId()(0); // should only be one (sliced ct_)!
1258 0 : MSSpectralWindow msSpw(ct_.spectralWindow());
1259 0 : MSSpWindowColumns msCol(msSpw);
1260 : //Vector<Double> refFreqs;
1261 : //msCol.refFrequency().getColumn(refFreqs,True);
1262 :
1263 0 : Vector<Double> freqs;
1264 0 : msCol.chanFreq().get(ispw,freqs,True); // should only be 1
1265 0 : Double centroidFreq=freqs(0);
1266 :
1267 : // cout << "time = " << (currTime_ - timeRef_) << endl;
1268 :
1269 0 : if (single) {
1270 0 : for (Int ipol=0;ipol<2;ipol++) {
1271 0 : Double dtime=(currTime_-timeRef_)-timelist_(currIdx_);
1272 0 : Double phase=result_(IPosition(2,ipol*4,0));
1273 0 : Double rate=result_(IPosition(2,ipol*4+2,0));
1274 0 : phase+=2.0*C::pi*rate*centroidFreq*dtime;
1275 0 : result_(IPosition(2,ipol*4,0))=phase;
1276 : }
1277 : } else {
1278 0 : Vector<uInt> rows(2); indgen(rows); rows+=uInt(currIdx_);
1279 0 : Cube<Float> r(mcols_p->fparamArray("",rows));
1280 :
1281 0 : Vector<Double> dtime(2);
1282 0 : dtime(0)=(currTime_-timeRef_)-timelist_(currIdx_);
1283 0 : dtime(1)=(currTime_-timeRef_)-timelist_(currIdx_+1);
1284 0 : Double wt=dtime(1) / (dtime(1)-dtime(0));
1285 :
1286 :
1287 0 : for (Int ipol=0;ipol<2;ipol++) {
1288 0 : Vector<Double> phase(2), rate(2);
1289 0 : phase(0)=r.xyPlane(0)(IPosition(2,ipol*4,0));
1290 0 : phase(1)=r.xyPlane(1)(IPosition(2,ipol*4,0));
1291 0 : rate(0)=r.xyPlane(0)(IPosition(2,ipol*4+2,0));
1292 0 : rate(1)=r.xyPlane(1)(IPosition(2,ipol*4+2,0));
1293 :
1294 0 : phase(0)+=2.0*C::pi*rate(0)*centroidFreq*dtime(0);
1295 0 : phase(1)+=2.0*C::pi*rate(1)*centroidFreq*dtime(1);
1296 :
1297 0 : Vector<Complex> ph(2);
1298 0 : ph(0)=Complex(cos(phase(0)),sin(phase(0)));
1299 0 : ph(1)=Complex(cos(phase(1)),sin(phase(1)));
1300 0 : ph(0)=Float(wt)*ph(0) + Float(1.0-wt)*ph(1);
1301 0 : result_(IPosition(2,ipol*4,0))=arg(ph(0));
1302 : }
1303 : }
1304 0 : }
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 0 : FringeJones::FringeJones(const MSMetaInfoForCal& msmc) :
1329 : VisCal(msmc), // virtual base
1330 : VisMueller(msmc), // virtual base
1331 0 : GJones(msmc) // immediate parent
1332 : {
1333 0 : if (prtlev()>2) cout << "FringeJones::FringeJones(msmc)" << endl;
1334 0 : }
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 0 : FringeJones::~FringeJones() {
1345 0 : if (prtlev()>2) cout << "FringeJones::~FringeJones()" << endl;
1346 0 : }
1347 :
1348 0 : void FringeJones::setApply(const Record& apply) {
1349 : // Call parent to do conventional things
1350 0 : GJones::setApply(apply);
1351 :
1352 0 : if (calWt())
1353 0 : logSink() << " (" << this->typeName() << ": Enforcing calWt()=false for phase/delay-like terms)" << LogIO::POST;
1354 :
1355 : // Enforce calWt() = false for delays
1356 0 : 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 0 : MSSpectralWindow msSpw(ct_->spectralWindow());
1379 0 : MSSpWindowColumns msCol(msSpw);
1380 0 : Vector<Double> tmpfreqs;
1381 0 : Vector<Double> chanfreq;
1382 0 : tmpfreqs.resize(msSpw.nrow());
1383 0 : for (rownr_t ispw=0;ispw<msSpw.nrow();++ispw) {
1384 0 : if (ispw < msSpw.nrow()) {
1385 0 : msCol.chanFreq().get(ispw,chanfreq,true); // reshape, if nec.
1386 0 : Int nch=chanfreq.nelements();
1387 0 : tmpfreqs(ispw)=chanfreq(nch/2);
1388 : }
1389 : }
1390 :
1391 0 : KrefFreqs_.resize(nSpw()); KrefFreqs_.set(0.0);
1392 0 : for (rownr_t ispw=0;ispw<(rownr_t)nSpw();++ispw) {
1393 0 : if (ispw < tmpfreqs.nelements())
1394 0 : KrefFreqs_(ispw)=tmpfreqs(ispw);
1395 : }
1396 :
1397 : /// Re-assign KrefFreq_ according spwmap (if any)
1398 0 : if (spwMap().nelements()>0) {
1399 0 : for (uInt ispw=0;ispw<spwMap().nelements();++ispw)
1400 0 : if (spwMap()(ispw)>-1 && ispw < tmpfreqs.nelements())
1401 0 : KrefFreqs_(ispw)=tmpfreqs(spwMap()(ispw));
1402 : }
1403 :
1404 0 : KrefFreqs_/=1.0e9; // in GHz
1405 0 : }
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 0 : void FringeJones::setCallib(const Record& callib,
1424 : const MeasurementSet& selms) {
1425 :
1426 : // Call parent to do conventional things
1427 0 : 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 0 : 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 0 : KrefFreqs_.resize(nSpw());
1454 0 : for (Int ispw=0;ispw<nSpw();++ispw) {
1455 0 : const Vector<Double>& f(cpp_->freqIn(ispw));
1456 0 : Int nf=f.nelements();
1457 0 : KrefFreqs_[ispw]=f[nf/2]; // center (usually this will be same as [0])
1458 : }
1459 0 : KrefFreqs_/=1.0e9; // In GHz
1460 :
1461 : // Re-assign KrefFreq_ according spwmap (if any)
1462 0 : if (spwMap().nelements()>0) {
1463 0 : Vector<Double> tmpfreqs;
1464 0 : tmpfreqs.assign(KrefFreqs_);
1465 0 : for (uInt ispw=0;ispw<spwMap().nelements();++ispw)
1466 0 : if (spwMap()(ispw)>-1)
1467 0 : KrefFreqs_(ispw)=tmpfreqs(spwMap()(ispw));
1468 : }
1469 :
1470 0 : }
1471 :
1472 0 : void FringeJones::setSolve(const Record& solve) {
1473 :
1474 : // Call parent to do conventional things
1475 0 : GJones::setSolve(solve);
1476 0 : 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 0 : refant() = -1;
1481 0 : 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 0 : if (solve.isDefined("zerorates")) {
1488 0 : zeroRates() = solve.asBool("zerorates");
1489 : }
1490 0 : if (solve.isDefined("globalsolve")) {
1491 0 : globalSolve() = solve.asBool("globalsolve");
1492 : }
1493 0 : if (solve.isDefined("delaywindow")) {
1494 0 : Array<Double> dw = solve.asArrayDouble("delaywindow");
1495 0 : delayWindow() = dw;
1496 : } else {
1497 0 : cerr << "No delay window!" << endl;
1498 : }
1499 0 : if (solve.isDefined("ratewindow")) {
1500 0 : rateWindow() = solve.asArrayDouble("ratewindow");
1501 : } else {
1502 0 : cerr << "No rate window!" << endl;
1503 : }
1504 0 : if (solve.isDefined("niter")) {
1505 0 : maxits() = solve.asInt("niter");
1506 : }
1507 0 : if (solve.isDefined("paramactive")) {
1508 0 : paramActive() = solve.asArrayBool("paramactive");
1509 : }
1510 0 : if (solve.isDefined("concatspws")) {
1511 0 : concatSPWs() = solve.asBool("concatspws");
1512 : }
1513 0 : if (solve.isDefined("corrcomb")) {
1514 : //cerr << "FringeJones::setsolve() Corrcomb is set! To:"
1515 : // << solve.asString("corrcomb")
1516 : // << endl;
1517 0 : corrcomb() = solve.asString("corrcomb");
1518 : }
1519 0 : }
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 0 : void FringeJones::calcAllJones() {
1529 :
1530 0 : 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 0 : Vector<Complex> oneJones;
1536 0 : Vector<Bool> oneJOK;
1537 0 : Vector<Float> onePar;
1538 0 : Vector<Bool> onePOK;
1539 :
1540 0 : ArrayIterator<Complex> Jiter(currJElem(),1);
1541 0 : ArrayIterator<Bool> JOKiter(currJElemOK(),1);
1542 0 : ArrayIterator<Float> Piter(currRPar(),1);
1543 0 : ArrayIterator<Bool> POKiter(currParOK(),1);
1544 :
1545 : Double phase;
1546 :
1547 0 : for (Int iant=0; iant<nAnt(); iant++) {
1548 0 : onePar.reference(Piter.array());
1549 0 : onePOK.reference(POKiter.array());
1550 :
1551 0 : Float fmin_ = min(currFreq());
1552 0 : Float fmax = max(currFreq());
1553 0 : for (Int ich=0; ich<nChanMat(); ich++) {
1554 :
1555 0 : oneJones.reference(Jiter.array());
1556 0 : oneJOK.reference(JOKiter.array());
1557 :
1558 0 : for (Int ipar=0;ipar<nPar();ipar+=4) {
1559 0 : if (onePOK(ipar)) {
1560 0 : Float freq = currFreq()(ich);
1561 0 : Float k_disp = 1e-9*KDISPSCALE*C::_2pi*(1.0/freq + (freq-fmin_-fmax)/(fmin_*fmax));
1562 :
1563 0 : phase=onePar(ipar);
1564 0 : phase+=2.0*C::pi*onePar(ipar+1)*
1565 0 : (currFreq()(ich)-KrefFreqs_(currSpw()));
1566 0 : phase+=2.0*C::pi*onePar(ipar+2)*KrefFreqs_(currSpw())*1e9*
1567 0 : (currTime() - refTime());
1568 0 : 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 0 : phase+=dph_d;
1574 0 : oneJones(ipar/4)=Complex(cos(phase),sin(phase));
1575 0 : oneJOK(ipar/4)=True;
1576 : } else {
1577 0 : oneJOK(ipar/4)=False;
1578 : }
1579 : }
1580 : // Advance iterators
1581 0 : Jiter.next();
1582 0 : JOKiter.next();
1583 : }
1584 : // Step to next antenns's pars
1585 0 : Piter.next();
1586 0 : POKiter.next();
1587 : }
1588 0 : }
1589 :
1590 :
1591 : void
1592 0 : FringeJones::calculateSNR(Int nCorr, DelayRateFFT& drf) {
1593 0 : Matrix<Float> sRP(solveRPar().nonDegenerate(1));
1594 0 : Matrix<Bool> sPok(solveParOK().nonDegenerate(1));
1595 0 : Matrix<Float> sSNR(solveParSNR().nonDegenerate(1));
1596 :
1597 0 : for (size_t icor=0; icor != (size_t) nCorr; icor++) {
1598 0 : const set<Int>& activeAntennas = drf.getActiveAntennasCorrelation(icor);
1599 0 : for (Int iant=0; iant != nAnt(); iant++) {
1600 0 : if (iant == refant()) {
1601 0 : Double maxsnr = 999.0;
1602 0 : sSNR(4*icor + 0, iant) = maxsnr;
1603 0 : sSNR(4*icor + 1, iant) = maxsnr;
1604 0 : sSNR(4*icor + 2, iant) = maxsnr;
1605 0 : sSNR(4*icor + 3, iant) = maxsnr;
1606 : }
1607 0 : else if (activeAntennas.find(iant) != activeAntennas.end()) {
1608 0 : Double delay = sRP(4*icor + 1, iant);
1609 0 : Double rate = sRP(4*icor + 2, iant);
1610 : // Note that DelayRateFFT::snr is also used to calculate SNRs for the least square values!
1611 0 : Float snrval = drf.snr(icor, iant, delay, rate);
1612 0 : sSNR(4*icor + 0, iant) = snrval;
1613 0 : sSNR(4*icor + 1, iant) = snrval;
1614 0 : sSNR(4*icor + 2, iant) = snrval;
1615 0 : sSNR(4*icor + 3, iant) = snrval;
1616 : } else {
1617 0 : sPok(4*icor + 0, iant) = false;
1618 0 : sPok(4*icor + 1, iant) = false;
1619 0 : sPok(4*icor + 2, iant) = false;
1620 0 : sPok(4*icor + 3, iant) = false;
1621 : }
1622 : }
1623 : }
1624 0 : }
1625 :
1626 :
1627 :
1628 :
1629 : void
1630 0 : FringeJones::selfSolveOne(SDBList& sdbs) {
1631 0 : solveRPar()=0.0;
1632 0 : solveParOK()=false;
1633 0 : solveParErr()=1.0; // Does nothing?
1634 : // Maybe we put refFreq, refTime stuff in here?
1635 0 : 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 0 : Int spw = currSpw();
1647 0 : Double reffreq = freqMetaData_.freq(spw)(0);
1648 0 : Double t0 = sdbs(0).time()(0);
1649 0 : Double dt0 = refTime() - t0;
1650 : //Double df0 = ref_freq - sdbs.freqs()(0);
1651 : //Double df0 = 0;
1652 0 : Double df0 = reffreq - sdbs(0).freqs()(0); // global center to global edge
1653 :
1654 0 : logSink() << "Solving for fringes for spw=" << currSpw() << " at t="
1655 0 : << MVTime(refTime()/C::day).string(MVTime::YMD,7) << LogIO::POST;
1656 :
1657 0 : std::map<Int, Double> aggregateTime;
1658 : // Set the refant to the first choice that has data!
1659 0 : refant() = findRefAntWithData(sdbs, refantlist(), prtlev());
1660 0 : 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 0 : logSink() << "Using reference antenna " << refant() << LogIO::POST;
1669 : }
1670 0 : 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 0 : 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 0 : drfp->FFT();
1690 0 : drfp->searchPeak();
1691 0 : Matrix<Float> sRP(solveRPar().nonDegenerate(1));
1692 0 : Matrix<Bool> sPok(solveParOK().nonDegenerate(1));
1693 0 : Matrix<Float> sSNR(solveParSNR().nonDegenerate(1));
1694 0 : logSink() << "sPok " << sPok.shape() << LogIO::POST;
1695 :
1696 : // Map from MS antenna number to index
1697 : // transcribe fft results to sRP
1698 0 : Int ncol = drfp->param().ncolumn();
1699 0 : 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 0 : for (Int i=0; i!=ncol; i++) { // i==iant
1706 0 : for (Int j=0; j!=nrow; j++) { // j is parameter number
1707 0 : Int oj = (j>=3) ? j+1 : j;
1708 0 : sRP(IPosition(2, oj, i)) = drfp->param()(IPosition(2, j, i));
1709 0 : 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 0 : sPok(IPosition(2, 3, i)) = true;
1713 0 : if (nrow > 3)
1714 0 : sPok(IPosition(2, 7, i)) = true;
1715 : }
1716 0 : size_t nCorrOrig(sdbs(0).nCorrelations());
1717 0 : size_t nCorr = (nCorrOrig> 1 ? 2 : 1); // number of p-hands
1718 0 : calculateSNR(nCorr, *drfp);
1719 0 : set<Int> belowThreshold;
1720 0 : Float threshold = minSNR();
1721 :
1722 0 : for (size_t icor=0; icor != nCorr; icor++) {
1723 0 : const set<Int>& activeAntennas = drfp->getActiveAntennasCorrelation(icor);
1724 0 : for (Int iant=0; iant != nAnt(); iant++) {
1725 0 : if (iant != refant() && (activeAntennas.find(iant) != activeAntennas.end())) {
1726 0 : Float s = sSNR(4*icor + 0, iant);
1727 : // Start the log message; finished below
1728 0 : logSink() << "Antenna " << iant << " correlation " << icor << " has (FFT) SNR of " << s;
1729 0 : if (s < threshold) {
1730 0 : belowThreshold.insert(iant);
1731 0 : 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 0 : sPok(4*icor + 0, iant) = false;
1735 0 : sPok(4*icor + 1, iant) = false;
1736 0 : sPok(4*icor + 2, iant) = false;
1737 0 : sPok(4*icor + 3, iant) = false;
1738 : }
1739 : // Finish the log message
1740 0 : 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 0 : drfp->removeAntennasCorrelation(icor, belowThreshold);
1746 : if (DEVDEBUG) {
1747 : drfp->printActive();
1748 : }
1749 : }
1750 0 : if (globalSolve()) {
1751 0 : 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 0 : least_squares_driver(sdbs, sRP, sPok, sSNR, refant(), drfp->getActiveAntennas(), maxits(),
1757 0 : 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 0 : for (Int iant=0; iant != nAnt(); iant++) {
1772 0 : for (size_t icor=0; icor != nCorr; icor++) {
1773 0 : const set<Int>& activeAntennas = drfp->getActiveAntennasCorrelation(icor);
1774 0 : if (activeAntennas.find(iant) == activeAntennas.end()) {
1775 0 : continue;
1776 : }
1777 0 : Double phi0 = sRP(4*icor + 0, iant);
1778 0 : Double delay = sRP(4*icor + 1, iant);
1779 0 : Double rate = sRP(4*icor + 2, iant);
1780 0 : Double k_disp = sRP(4*icor + 3, iant);
1781 0 : 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 0 : Double delta1 = df0*delay/1e9;
1786 0 : Double delta2 = reffreq*dt0*rate;
1787 0 : Double delta3 = C::_2pi*(delta1+delta2);
1788 : Double dt;
1789 0 : auto p = aggregateTime.find(iant);
1790 0 : if (zeroRates() && p != aggregateTime.end()) {
1791 0 : dt = p->second - t0;
1792 : } else {
1793 0 : 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 0 : 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 0 : if (zeroRates()) {
1807 0 : logSink() << "Zeroing delay rates in calibration table." << LogIO::POST;
1808 :
1809 0 : for (size_t icor=0; icor != nCorr; icor++) {
1810 0 : for (Int iant=0; iant != nAnt(); iant++) {
1811 0 : sRP(4*icor + 2, iant) = 0.0;
1812 : }
1813 : }
1814 : }
1815 : // Copy the results to the second polarisation for combined pols
1816 0 : if (corrcomb()=="all") {
1817 0 : logSink() << "Correlations combined: Copying results to other correlation" << LogIO::POST;
1818 0 : for (Int iant=0; iant != nAnt(); iant++) {
1819 0 : for (Int i=0; i !=4; i++) {
1820 0 : sRP(4+i, iant) = sRP(i, iant);
1821 0 : sPok(4+i, iant) = sPok(i, iant);
1822 0 : sSNR(4+i, iant) = sSNR(i, iant);
1823 : }
1824 : }
1825 : }
1826 : if (DEVDEBUG) {
1827 : std::cerr << "sPok " << sPok << endl;
1828 : }
1829 0 : delete drfp;
1830 0 : }
1831 :
1832 : void
1833 0 : FringeJones::solveOneVB(const VisBuffer&) {
1834 0 : throw(AipsError("VisBuffer interface not supported!"));
1835 : }
1836 :
1837 :
1838 0 : void FringeJones::globalPostSolveTinker() {
1839 :
1840 : // Re-reference the phase, if requested
1841 0 : if (refantlist()(0)>-1) applyRefAnt();
1842 0 : }
1843 :
1844 0 : void FringeJones::applyRefAnt() {
1845 :
1846 : // TBD:
1847 : // 1. Synchronize refant changes on par axis
1848 : // 2. Implement minimum mean deviation algorithm
1849 :
1850 0 : if (refantlist()(0)<0)
1851 0 : throw(AipsError("No refant specified."));
1852 :
1853 0 : Int nUserRefant=refantlist().nelements();
1854 :
1855 : // Get the preferred refant names from the MS
1856 0 : String refantName(msmc().antennaName(refantlist()(0)));
1857 0 : if (nUserRefant>1) {
1858 0 : refantName+=" (";
1859 0 : for (Int i=1;i<nUserRefant;++i) {
1860 0 : refantName+=msmc().antennaName(refantlist()(i));
1861 0 : if (i<nUserRefant-1) refantName+=",";
1862 : }
1863 0 : refantName+=")";
1864 : }
1865 :
1866 : logSink() << "Applying refant: " << refantName
1867 0 : << " refantmode = " << refantmode();
1868 0 : if (refantmode()=="flex")
1869 0 : logSink() << " (hold alternate refants' phase constant) when refant flagged";
1870 0 : if (refantmode()=="strict")
1871 0 : logSink() << " (flag all antennas when refant flagged)";
1872 0 : logSink() << LogIO::POST;
1873 :
1874 : // Generate a prioritized refant choice list
1875 : // The first entry in this list is the user's primary refant,
1876 : // the second entry is the refant used on the previous interval,
1877 : // and the rest is a prioritized list of alternate refants,
1878 : // starting with the user's secondary (if provided) refants,
1879 : // followed by the rest of the array, in distance order. This
1880 : // makes the priorities correct all the time, and prevents
1881 : // a semi-stochastic alternation (by preferring the last-used
1882 : // alternate, even if nominally higher-priority refants become
1883 : // available)
1884 :
1885 :
1886 : // Extract antenna positions
1887 0 : Matrix<Double> xyz;
1888 0 : if (msName()!="<noms>") {
1889 0 : MeasurementSet ms(msName());
1890 0 : MSAntennaColumns msant(ms.antenna());
1891 0 : msant.position().getColumn(xyz);
1892 : }
1893 : else {
1894 : // TBD RO*
1895 0 : CTColumns ctcol(*ct_);
1896 0 : CTAntennaColumns& antcol(ctcol.antenna());
1897 0 : antcol.position().getColumn(xyz);
1898 : }
1899 :
1900 : // Calculate (squared) antenna distances, relative
1901 : // to last preferred antenna
1902 0 : Vector<Double> dist2(xyz.ncolumn(),0.0);
1903 0 : for (Int i=0;i<3;++i) {
1904 0 : Vector<Double> row=xyz.row(i);
1905 0 : row-=row(refantlist()(nUserRefant-1));
1906 0 : dist2+=square(row);
1907 : }
1908 : // Move preferred antennas to a large distance
1909 0 : for (Int i=0;i<nUserRefant;++i)
1910 0 : dist2(refantlist()(i))=DBL_MAX;
1911 :
1912 : // Generated sorted index
1913 0 : Vector<uInt> ord;
1914 0 : genSort(ord,dist2);
1915 :
1916 : // Assemble the whole choices list
1917 0 : Int nchoices=nUserRefant+1+ord.nelements();
1918 0 : Vector<Int> refantchoices(nchoices,0);
1919 0 : Vector<Int> r(refantchoices(IPosition(1,nUserRefant+1),IPosition(1,refantchoices.nelements()-1)));
1920 0 : convertArray(r,ord);
1921 :
1922 : // set first two to primary preferred refant
1923 0 : refantchoices(0)=refantchoices(1)=refantlist()(0);
1924 :
1925 : // set user's secondary refants (if any)
1926 0 : if (nUserRefant>1)
1927 0 : refantchoices(IPosition(1,2),IPosition(1,nUserRefant))=
1928 0 : refantlist()(IPosition(1,1),IPosition(1,nUserRefant-1));
1929 :
1930 : //cout << "refantchoices = " << refantchoices << endl;
1931 :
1932 :
1933 0 : if (refantmode()=="strict") {
1934 0 : nchoices=1;
1935 0 : refantchoices.resize(1,True);
1936 : }
1937 :
1938 0 : Vector<Int> nPol(nSpw(),2); // TBD:or 1, if data was single pol
1939 :
1940 0 : if (nPar()==8) {
1941 : // Verify that 2nd poln has unflagged solutions, PER SPW
1942 0 : ROCTMainColumns ctmc(*ct_);
1943 :
1944 0 : Block<String> cols(1);
1945 0 : cols[0]="SPECTRAL_WINDOW_ID";
1946 0 : CTIter ctiter(*ct_,cols);
1947 0 : Cube<Bool> fl;
1948 :
1949 0 : while (!ctiter.pastEnd()) {
1950 :
1951 0 : Int ispw=ctiter.thisSpw();
1952 0 : fl.assign(ctiter.flag());
1953 :
1954 0 : IPosition blc(3,0,0,0), trc(fl.shape());
1955 0 : trc-=1; blc(0)=nPar()/2;
1956 :
1957 : // cout << "ispw = " << ispw << " nfalse(fl(1,:,:)) = " << nfalse(fl(blc,trc)) << endl;
1958 :
1959 : // If there are no unflagged solutions in 2nd pol,
1960 : // avoid it in refant calculations
1961 0 : if (nfalse(fl(blc,trc))==0)
1962 0 : nPol(ispw)=1;
1963 :
1964 0 : ctiter.next();
1965 : }
1966 : }
1967 : // cout << "nPol = " << nPol << endl;
1968 :
1969 0 : Bool usedaltrefant(false);
1970 0 : Int currrefant(refantchoices(0)), lastrefant(-1);
1971 :
1972 0 : Block<String> cols(2);
1973 0 : cols[0]="SPECTRAL_WINDOW_ID";
1974 0 : cols[1]="TIME";
1975 0 : CTIter ctiter(*ct_,cols);
1976 :
1977 : // Arrays to hold per-timestamp solutions
1978 0 : Cube<Float> solA, solB;
1979 0 : Cube<Bool> flA, flB;
1980 0 : Vector<Int> ant1A, ant1B, ant2B;
1981 0 : Matrix<Complex> refPhsr; // the reference phasor [npol,nchan]
1982 0 : Int lastspw(-1);
1983 0 : Bool first(true);
1984 0 : while (!ctiter.pastEnd()) {
1985 0 : Int ispw=ctiter.thisSpw();
1986 0 : if (ispw!=lastspw) first=true; // spw changed, start over
1987 :
1988 : // Read in the current sol, fl, ant1:
1989 0 : solB.assign(ctiter.fparam());
1990 0 : flB.assign(ctiter.flag());
1991 0 : ant1B.assign(ctiter.antenna1());
1992 0 : ant2B.assign(ctiter.antenna2());
1993 :
1994 : // First time thru, 'previous' solution same as 'current'
1995 0 : if (first) {
1996 0 : solA.reference(solB);
1997 0 : flA.reference(flB);
1998 0 : ant1A.reference(ant1B);
1999 : }
2000 0 : IPosition shB(solB.shape());
2001 0 : IPosition shA(solA.shape());
2002 :
2003 : // Find a good refant at this time
2004 : // A good refant is one that is unflagged in all polarizations
2005 : // in the current(B) and previous(A) intervals (so they can be connected)
2006 0 : Int irefA(0),irefB(0); // index on 3rd axis of solution arrays
2007 0 : Int ichoice(0); // index in refantchoicelist
2008 0 : Bool found(false);
2009 0 : IPosition blcA(3,0,0,0),trcA(shA),blcB(3,0,0,0),trcB(shB);
2010 0 : trcA-=1; trcA(0)=trcA(2)=0;
2011 0 : trcB-=1; trcB(0)=trcB(2)=0;
2012 0 : ichoice=0;
2013 0 : while (!found && ichoice<nchoices) {
2014 : // Find index of current refant choice
2015 0 : irefA=irefB=0;
2016 0 : while (ant1A(irefA)!=refantchoices(ichoice) && irefA<shA(2)) ++irefA;
2017 0 : while (ant1B(irefB)!=refantchoices(ichoice) && irefB<shB(2)) ++irefB;
2018 :
2019 0 : if (irefA<shA(2) && irefB<shB(2)) {
2020 :
2021 : // cout << " Trial irefA,irefB: " << irefA << "," << irefB
2022 : // << " Ants=" << ant1A(irefA) << "," << ant1B(irefB) << endl;
2023 :
2024 0 : blcA(2)=trcA(2)=irefA;
2025 0 : blcB(2)=trcB(2)=irefB;
2026 0 : found=true; // maybe
2027 0 : for (Int ipol=0;ipol<nPol(ispw);++ipol) {
2028 0 : blcA(0)=blcB(0)=ipol*nPar()/2;
2029 0 : trcA(0)=trcB(0)=(ipol+1)*nPar()/2-1;
2030 0 : found &= (nfalse(flA(blcA,trcA))>0); // previous interval
2031 0 : found &= (nfalse(flB(blcB,trcB))>0); // current interval
2032 : }
2033 : }
2034 : else
2035 : // irefA or irefB out-of-range
2036 0 : found=false; // Just to be sure
2037 :
2038 0 : if (!found) ++ichoice; // try next choice next round
2039 :
2040 : }
2041 :
2042 0 : if (found) {
2043 : // at this point, irefA/irefB point to a good refant
2044 :
2045 : // Keep track
2046 0 : usedaltrefant|=(ichoice>0);
2047 0 : currrefant=refantchoices(ichoice);
2048 0 : refantchoices(1)=currrefant; // 2nd priorty next time
2049 :
2050 : // cout << " currrefant = " << currrefant << " (" << ichoice << ")" << endl;
2051 :
2052 : // cout << " Final irefA,irefB: " << irefA << "," << irefB
2053 : // << " Ants=" << ant1A(irefA) << "," << ant1B(irefB) << endl;
2054 :
2055 :
2056 : // Only report if using an alternate refant
2057 0 : if (currrefant!=lastrefant && ichoice>0) {
2058 : logSink()
2059 : << "At "
2060 0 : << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7)
2061 : << " ("
2062 : << "Spw=" << ctiter.thisSpw()
2063 : << ", Fld=" << ctiter.thisField()
2064 : << ")"
2065 0 : << ", using refant " << msmc().antennaName(currrefant)
2066 : << " (id=" << currrefant
2067 : << ")" << " (alternate)"
2068 0 : << LogIO::POST;
2069 : }
2070 :
2071 : // Form reference phasor [nPar,nChan]
2072 0 : Matrix<Float> rA,rB;
2073 0 : Matrix<Bool> rflA,rflB;
2074 0 : rB.assign(solB.xyPlane(irefB));
2075 0 : rflB.assign(flB.xyPlane(irefB));
2076 :
2077 0 : if (!first) {
2078 : // Get and condition previous phasor for the current refant
2079 0 : rA.assign(solA.xyPlane(irefA));
2080 0 : rflA.assign(flA.xyPlane(irefA));
2081 0 : rB-=rA;
2082 :
2083 : // Accumulate flags
2084 0 : rflB&=rflA;
2085 : }
2086 :
2087 : // cout << " rB = " << rB << endl;
2088 : // cout << boolalpha << " rflB = " << rflB << endl;
2089 : // TBD: fillChanGaps?
2090 :
2091 : // Now apply reference phasor to all antennas
2092 0 : Matrix<Float> thissol;
2093 0 : for (Int iant=0;iant<shB(2);++iant) {
2094 0 : thissol.reference(solB.xyPlane(iant));
2095 0 : thissol-=rB;
2096 : }
2097 :
2098 : // Set refant, so we can put it back
2099 0 : ant2B=currrefant;
2100 :
2101 : // put back referenced solutions
2102 0 : ctiter.setfparam(solB);
2103 0 : ctiter.setantenna2(ant2B);
2104 :
2105 : // Next time thru, solB is previous
2106 0 : solA.reference(solB);
2107 0 : flA.reference(flB);
2108 0 : ant1A.reference(ant1B);
2109 0 : solB.resize(); // (break references)
2110 0 : flB.resize();
2111 0 : ant1B.resize();
2112 :
2113 0 : lastrefant=currrefant;
2114 0 : first=false; // avoid first-pass stuff from now on
2115 :
2116 : } // found
2117 : else {
2118 : logSink()
2119 : << "At "
2120 0 : << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7)
2121 : << " ("
2122 : << "Spw=" << ctiter.thisSpw()
2123 : << ", Fld=" << ctiter.thisField()
2124 : << ")"
2125 : << ", refant (id=" << currrefant
2126 : << ") was flagged; flagging all antennas strictly."
2127 0 : << LogIO::POST;
2128 : // Flag all solutions in this interval
2129 0 : flB.set(True);
2130 0 : ctiter.setflag(flB);
2131 0 : if (ichoice == nchoices){
2132 : logSink() << LogIO::WARN
2133 : << "From time: "
2134 0 : << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7)
2135 : << "in Spw: "
2136 : << ctiter.thisSpw()
2137 : << " refant list exhausted, flagging all solutions"
2138 0 : << LogIO::POST;
2139 : }
2140 : }
2141 :
2142 : // advance to the next interval
2143 0 : lastspw=ispw;
2144 0 : ctiter.next();
2145 : }
2146 :
2147 0 : if (usedaltrefant)
2148 : logSink() << LogIO::NORMAL
2149 : << " NB: An alternate refant was used at least once to maintain" << endl
2150 : << " phase continuity where the user's preferred refant drops out." << endl
2151 : << " Alternate refants are held constant in phase (_not_ zeroed)" << endl
2152 : << " during these periods, and the preferred refant may return at" << endl
2153 : << " a non-zero phase. This is generally harmless."
2154 0 : << LogIO::POST;
2155 :
2156 0 : return;
2157 :
2158 : }
2159 :
2160 : } //# NAMESPACE CASA - END
2161 :
2162 :
2163 : /*
2164 : Example of use in at Python level:
2165 :
2166 : fringefit(vis="n14c2.ms", caltable="fail.fj", field="",spw="1",intent="",
2167 : selectdata=True, timerange="", antenna="", scan="5", observation="",
2168 : msselect="", solint="inf", refant="EF", minsnr=3.0, append=False,
2169 : gaintable=['n14c2.gcal'], parang=False)
2170 : */
2171 :
|