Line data Source code
1 : //# SolvableVisCal.cc: Implementation of SolvableVisCal classes/Users/nschweig/CASA6/CASR-539/SolvableVisCal.cc
2 : //# Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003
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 : //# $Id: VisCal.cc,v 1.15 2006/02/06 19:23:11 gmoellen Exp $
27 :
28 : #include <synthesis/MeasurementComponents/CalCorruptor.h>
29 : #include <synthesis/MeasurementComponents/SolvableVisCal.h>
30 : #include <synthesis/MeasurementComponents/MSMetaInfoForCal.h>
31 :
32 : #include <msvis/MSVis/VisBuffer.h>
33 :
34 : #include <casacore/casa/Arrays/ArrayMath.h>
35 : #include <casacore/casa/Arrays/MaskArrMath.h>
36 : #include <casacore/casa/Arrays/ArrayIter.h>
37 : #include <casacore/scimath/Mathematics/MatrixMathLA.h>
38 : #include <casacore/scimath/Fitting/LinearFit.h>
39 : #include <casacore/scimath/Functionals/Polynomial.h>
40 : #include <casacore/casa/BasicSL/String.h>
41 : #include <casacore/casa/Utilities/Assert.h>
42 : #include <casacore/casa/Quanta/MVTime.h>
43 : #include <casacore/casa/Exceptions/Error.h>
44 : #include <casacore/casa/OS/Memory.h>
45 : #include <casacore/casa/OS/File.h>
46 : #include <casacore/casa/Utilities/GenSort.h>
47 : #include <casacore/casa/Quanta/Quantum.h>
48 : #include <casacore/casa/Quanta/QuantumHolder.h>
49 : #include <casacore/tables/Tables/TableCopy.h>
50 : #include <casacore/tables/Tables/TableUtil.h>
51 : #include <casacore/ms/MeasurementSets/MSAntennaColumns.h>
52 : #include <casacore/ms/MeasurementSets/MSSpWindowColumns.h>
53 : #include <casacore/ms/MeasurementSets/MSFieldColumns.h>
54 : #include <casacore/ms/MSOper/MSMetaData.h>
55 : #include <synthesis/CalTables/CTMainColumns.h>
56 : #include <synthesis/CalTables/CTColumns.h>
57 : #include <synthesis/CalTables/CTGlobals.h>
58 : #include <synthesis/CalTables/CTIter.h>
59 : #include <synthesis/CalTables/CTInterface.h>
60 : #include <synthesis/MeasurementComponents/SolveDataBuffer.h>
61 : #include <casacore/ms/MSSel/MSSelection.h>
62 : #include <casacore/ms/MSSel/MSSelectionTools.h>
63 : #include <sstream>
64 : #include <iostream>
65 : #include <iomanip>
66 : #include <casacore/casa/Containers/RecordField.h>
67 :
68 : #include <casacore/casa/Logging/LogMessage.h>
69 : #include <casacore/casa/Logging/LogSink.h>
70 : #include <casacore/casa/System/Aipsrc.h>
71 : #include <casacore/casa/System/ProgressMeter.h>
72 :
73 : #include <fstream>
74 :
75 : using namespace casacore;
76 : namespace casa { //# NAMESPACE CASA - BEGIN
77 :
78 :
79 100 : SolNorm::SolNorm(Bool donorm, String type) :
80 100 : donorm_(donorm),
81 100 : normtype_(normTypeFromString(type))
82 : {
83 : // report();
84 100 : }
85 :
86 0 : SolNorm::SolNorm(const SolNorm& other) :
87 0 : donorm_(other.donorm_),
88 0 : normtype_(other.normtype_)
89 0 : {}
90 :
91 0 : void SolNorm::report() {
92 0 : cout << "Forming SolNorm object:" << endl;
93 0 : cout << " donorm=" << boolalpha << donorm_ << endl
94 0 : << " normtype=" << normtypeString() << endl;
95 0 : }
96 :
97 0 : String SolNorm::normTypeAsString(Type type) {
98 0 : switch (type) {
99 0 : case MEAN: {
100 0 : return String("MEAN");
101 : }
102 0 : case MEDIAN: {
103 0 : return String("MEDIAN");
104 : }
105 0 : default: {
106 0 : return String("UNKNOWN");
107 : }
108 : }
109 : return String("UNKNOWN");
110 : }
111 :
112 100 : SolNorm::Type SolNorm::normTypeFromString(String type) {
113 :
114 100 : String uptype=upcase(type);
115 100 : if (uptype.contains("MEAN")) return SolNorm::MEAN;
116 0 : else if (uptype.contains("MED")) return SolNorm::MEDIAN;
117 : else {
118 0 : throw(AipsError("Invalid normalization type specifiec!"));
119 : }
120 : // Shouldn't reach here return SolNorm::UNKNOWN;
121 :
122 100 : }
123 :
124 :
125 :
126 :
127 :
128 : // **********************************************************
129 : // FreqMetaData Implementations
130 : //
131 :
132 68 : FreqMetaData::FreqMetaData() :
133 68 : ok_(False), // ok requires running calcFreqMeta later
134 68 : validspws_(),
135 68 : freq_(Vector< Vector<Double> >()),
136 68 : width_(Vector< Vector<Double> >()),
137 68 : effBW_(Vector< Vector<Double> >()),
138 68 : spwfanin_()
139 68 : {}
140 :
141 :
142 32 : void FreqMetaData::calcFreqMeta(const Vector< Vector<Double> >& msfreq,
143 : const Vector< Vector<Double> >& mswidth,
144 : const Vector<uInt>& selspw,
145 : Bool freqdep,Bool combspw,
146 : const Vector<Int>& spwfanin) {
147 :
148 : // Max number of spws
149 32 : uInt nspw(msfreq.nelements());
150 :
151 : // We will keep track of which spws get set
152 32 : Vector<Bool> validspw(nspw,false);
153 :
154 : // Size up the Vector of spw freq Vectors
155 32 : freq_.resize(nspw);
156 32 : width_.resize(nspw);
157 32 : effBW_.resize(nspw);
158 :
159 : // We will log some pertinent info
160 32 : LogIO log;
161 32 : log << LogOrigin("FreqMetaData","calcFreqMeta") << LogIO::NORMAL << "Derived frequency meta-info for solutions:" << LogIO::POST;
162 :
163 : // Gather MS freq info
164 142 : for (uInt i=0;i<selspw.nelements();++i) {
165 110 : uInt ispw=selspw(i);
166 110 : uInt nchan=msfreq(ispw).nelements();
167 :
168 : // This ensures msfreq/mswidth consistent with selspw
169 : // (each selspw has at least one channel of freq info)
170 110 : if (nchan<1)
171 0 : throw(AipsError("No frequency information for a selected spw!"));
172 :
173 :
174 : // Set nominal per-spw solution frequencies
175 110 : if (!freqdep && nchan>1) {
176 :
177 : // cout << "Not freqdep and multi-chan data..."
178 : // << "Soln freqs will be collapsed to single channel." << endl;
179 :
180 :
181 : // solutions NOT freq dep but more than one MS channel to solve from
182 : // --> Average chan freqs to single fiducial value
183 : // (this is a parameterized solution, like delay or fringefit...)
184 :
185 :
186 : // Manage value scale, to avoid loss of precision
187 110 : Double freq0=msfreq(ispw)(0); // Lop off large freq value
188 110 : Double width1=mswidth(ispw)(0); // Divide widths by typical value (also ensures abs)
189 110 : Vector<Double> f=msfreq(ispw)-freq0; // relative freq
190 110 : Vector<Double> w=mswidth(ispw)/width1; // width-weights
191 :
192 : // output info will be single-channel
193 110 : freq_(ispw).resize(1);
194 110 : width_(ispw).resize(1);
195 :
196 : // calculate
197 110 : freq_(ispw).set(sum( (Array<Double>) f*w)); // weighed rel freq sum
198 110 : width_(ispw).set(sum(w)); // sum of norm'd width weights
199 110 : freq_(ispw)/=width_(ispw); // divide by weight sum
200 :
201 : // Restore offsets to final values
202 110 : freq_(ispw)+=freq0; // add offset back in
203 110 : width_(ispw)*=width1; // mult by width norm
204 :
205 110 : } else {
206 : // Solutions ARE freq-dep, or only one channel,
207 : // so just adopt MS frequencies (NB: possibly already decimated by VI2)
208 : // TBD: could use reference here (only if ~combspw)?
209 : //cout << "Soln is freqdep, or only one channel..."
210 : //<< "Soln freqs are just the VI2 data freqs" << endl;
211 0 : freq_(ispw).assign(msfreq(ispw));
212 0 : width_(ispw).assign(mswidth(ispw));
213 : }
214 :
215 : {
216 : // Report spw freq-metadetails....
217 110 : ostringstream os;
218 110 : os.precision(15);
219 110 : os << " Selected spw=" << ispw << " (nchan=" << freq_(ispw).nelements() << ") has centroid freq = " << mean(freq_(ispw));
220 110 : log << LogIO::NORMAL << os << LogIO::POST;
221 : //log << LogOrigin("FreqMetaData","calcFreqMeta") << LogIO::NORMAL << os << LogIO::POST;
222 110 : }
223 :
224 :
225 : // Assume effective BW is just the width
226 110 : effBW_(ispw).reference(width_(ispw));
227 :
228 : // Remember we set this spw
229 110 : validspw(ispw)=true;
230 :
231 : }
232 :
233 : // Collapse over spws if combining them...
234 32 : if (combspw && spwfanin.nelements()>1) {
235 :
236 : // cout << "Combining spws!" << endl;
237 :
238 : // Remember the fan-in vector
239 5 : spwfanin_.resize();
240 5 : spwfanin_.assign(spwfanin);
241 :
242 :
243 : // Keep track of which spws are aggregate spws
244 : // (none are yet)
245 5 : Vector<Bool> isAggspw(nspw,false);
246 :
247 : // Keep track of fanned-in spws per agg spw
248 5 : Vector< Vector<Int> > fannedin(nspw,Vector<Int>(0));
249 :
250 :
251 5 : Vector<Double> freq0(nspw,0);
252 5 : Vector<Double> width1(nspw,0);
253 :
254 25 : for (uInt ispw=0;ispw<spwfanin.nelements();++ispw) {
255 :
256 : // Step over unmapped spws...
257 20 : if (spwfanin(ispw)<0)
258 0 : continue;
259 :
260 : // The following assumes fan-in is always to lowest spw id in group
261 20 : if (Int(ispw)==spwfanin(ispw)) {
262 :
263 : //cout << "Aggregate spw = " << ispw << endl;
264 :
265 5 : isAggspw(ispw)=true;
266 :
267 : // Just to be sure...
268 5 : validspw(ispw)=true;
269 :
270 : // Add this (agg) spw to fanned in list
271 5 : uInt nfanin=fannedin(ispw).nelements();
272 5 : fannedin(ispw).resize(nfanin+1,true); // copies elements
273 5 : fannedin(ispw)(nfanin)=ispw;
274 :
275 : // This is a spw in which we'll accumulate
276 :
277 : // Offsets for precision
278 5 : freq0(ispw)=freq_(ispw)(0);
279 5 : width1(ispw)=width_(ispw)(0);
280 :
281 5 : freq_(ispw)-=freq0(ispw);
282 5 : width_(ispw)/=width1(ispw);
283 :
284 : // begin to accumulate effBW
285 5 : effBW_(ispw).resize(); // break prior reference to width_
286 5 : effBW_(ispw).assign(width_(ispw)); // copy in this spw's width_
287 :
288 : // weight the freqs with widths
289 5 : freq_(ispw)*=width_(ispw);
290 :
291 : // weight the widths with the widths
292 : // (we will end up with a width-weighted width over spws)
293 5 : width_(ispw)*=width_(ispw);
294 :
295 : }
296 : else {
297 15 : uInt aggspw(spwfanin(ispw));
298 :
299 15 : uInt nfanin=fannedin(aggspw).nelements();
300 15 : fannedin(aggspw).resize(nfanin+1,true); // copies elements
301 15 : fannedin(aggspw)(nfanin)=ispw;
302 :
303 15 : if (ispw<=aggspw)
304 0 : throw(AipsError("Cannot accumulate into spw with a lower spw id."));
305 :
306 :
307 : // cout << "Accumulating spw=" << ispw << " into aggspw="<< aggspw << endl;
308 :
309 : // Trap incompatible spws
310 15 : if (freq_(ispw).nelements()!=freq_(aggspw).nelements())
311 0 : throw(AipsError("Cannont combine spws with differing nchan!"));
312 :
313 : // TBD: recognize/handle sideband and width variation if nchan>1 ?
314 : // (at the moment, there is no SB info in the sign of the width)
315 :
316 : // Offsets for precision (from aggspw!)
317 15 : Vector<Double> f(freq_(ispw)-freq0(aggspw));
318 15 : Vector<Double> w(width_(ispw)/width1(aggspw));
319 :
320 : // accumulate
321 15 : freq_(aggspw)+= ( (Array<Double>) f*w);
322 15 : width_(aggspw)+= ( (Array<Double>) w*w);
323 15 : effBW_(aggspw)+= w;
324 :
325 : // This acculated spw now refers to aggspw:
326 15 : freq_(ispw).reference(freq_(aggspw));
327 15 : width_(ispw).reference(width_(aggspw));
328 15 : effBW_(ispw).reference(effBW_(aggspw));
329 :
330 : // This spw no longer autonomously "valid"
331 : // (aggspw is the relevant valid one)
332 15 : validspw(ispw)=false;
333 :
334 15 : }
335 : }
336 :
337 : // Finish weighted mean calculation
338 25 : for (uInt ispw=0;ispw<spwfanin.nelements();++ispw) {
339 :
340 : // Step over non-agg spws
341 20 : if (!isAggspw(ispw))
342 15 : continue;
343 :
344 : // cout << "Finalizing freq averages for agg spw = " << ispw << endl;
345 :
346 5 : if (freq0(ispw)>0.0 && effBW_(ispw).nelements()>0 && allGT(effBW_(ispw),0.0)) {
347 5 : freq_(ispw)/=effBW_(ispw);
348 5 : width_(ispw)/=effBW_(ispw);
349 :
350 : // put offsets back in
351 5 : freq_(ispw)+=freq0(ispw);
352 5 : width_(ispw)*=width1(ispw);
353 5 : effBW_(ispw)*=width1(ispw);
354 :
355 : {
356 : // Report fanin details....
357 5 : ostringstream os;
358 5 : os.precision(15);
359 5 : os << " Combining spws=" << fannedin(ispw) << " into (aggregate) spw=" << ispw << " (nchan=" << freq_(ispw).nelements() << ") at centroid freq = " << mean(freq_(ispw));
360 5 : log << LogIO::NORMAL << os << LogIO::POST;
361 : //log << LogOrigin("FreqMetaData","calcFreqMeta") << LogIO::NORMAL << os << LogIO::POST;
362 5 : }
363 :
364 : }
365 : else {
366 0 : throw(AipsError("Problem completing combspw freq average."));
367 : }
368 : } // ispw (fanin spws only)
369 : // cout << "Finished combining spws." << endl;
370 :
371 5 : } // combspw?
372 : else {
373 :
374 : // For safety, make spwfanin the identity vector
375 27 : spwfanin_.resize(nspw);
376 27 : indgen(spwfanin_);
377 :
378 : }
379 :
380 : // Fill validspws_ vector
381 32 : Vector<Int> spwlist(nspw);
382 32 : indgen(spwlist);
383 32 : validspws_.assign(spwlist(validspw).getCompressedArray());
384 :
385 : // If we get here, we should be ok!
386 32 : ok_=true;
387 :
388 32 : }
389 :
390 :
391 644 : Bool FreqMetaData::ok() const {
392 644 : if (ok_)
393 644 : return true;
394 : else
395 0 : throw(AipsError("FreqMetaData not initialized!"));
396 : return false;
397 :
398 : }
399 :
400 1 : const Vector<Int>& FreqMetaData::validSpws() const {
401 :
402 1 : if (ok() && validspws_.nelements()>0)
403 1 : return validspws_;
404 : else
405 0 : throw(AipsError("No valid spws in FreqMetaData!"));
406 :
407 : }
408 :
409 :
410 451 : const Vector<Double>& FreqMetaData::freq(Int spw) const {
411 451 : if (ok() && freq_(spw).nelements()>0)
412 451 : return freq_(spw);
413 : else
414 0 : throw(AipsError("Bad spw in FreqMetaData!"));
415 :
416 : }
417 94 : const Vector<Double>& FreqMetaData::width(Int spw) const {
418 94 : if (ok() && width_(spw).nelements()>0)
419 94 : return width_(spw);
420 : else
421 0 : throw(AipsError("Bad spw in FreqMetaData!"));
422 :
423 : }
424 94 : const Vector<Double>& FreqMetaData::effBW(Int spw) const {
425 94 : if (ok() && effBW_(spw).nelements()>0)
426 94 : return effBW_(spw);
427 : else
428 0 : throw(AipsError("Bad spw in FreqMetaData!"));
429 :
430 : }
431 :
432 4 : Int FreqMetaData::fannedInSpw(Int spw) const {
433 :
434 4 : if (ok() && Int(spwfanin_.nelements())>spw && spwfanin_(spw)>-1)
435 4 : return spwfanin_(spw);
436 : else
437 0 : throw(AipsError("Bad spw fan-in in FreqMetaData::faninoutspw."));
438 :
439 : }
440 :
441 :
442 : // **********************************************************
443 : // SolvableVisCal Implementations
444 : //
445 :
446 0 : SolvableVisCal::SolvableVisCal(VisSet& vs) :
447 : VisCal(vs),
448 0 : corruptor_p(NULL),
449 0 : ct_(NULL),
450 0 : ci_(NULL),
451 0 : cpp_(NULL),
452 0 : spwOK_(vs.numberSpw(),false),
453 0 : maxTimePerSolution_p(0),
454 0 : minTimePerSolution_p(10000000),
455 0 : avgTimePerSolution_p(0),
456 0 : timer_p(),
457 0 : freqMetaData_(),
458 0 : calTableName_(""),
459 0 : calTableSelect_(""),
460 0 : append_(false),
461 0 : tInterpType_(""),
462 0 : fInterpType_(""),
463 0 : spwMap_(1,-1),
464 0 : refantmode_("flex"),
465 0 : urefantlist_(1,-1),
466 0 : minblperant_(4),
467 0 : solved_(false),
468 0 : byCallib_(false),
469 0 : apmode_(""),
470 0 : solmode_(""),
471 0 : rmsthresh_(0),
472 0 : usolint_("inf"),
473 0 : solint_("inf"),
474 0 : solTimeInterval_(DBL_MAX),
475 0 : fsolint_("none"),
476 0 : fintervalHz_(-1.0),
477 0 : fintervalCh_(vs.numberSpw(),0.0),
478 0 : chanAveBounds_(vs.numberSpw(),Matrix<Int>()),
479 0 : solnorm_(false,"mean"),
480 0 : minSNR_(0.0f),
481 0 : combine_(""),
482 0 : corrcomb_("none"),
483 0 : focusChan_(0),
484 0 : dataInterval_(0.0),
485 0 : fitWt_(0.0),
486 0 : fit_(0.0),
487 0 : antennaMap_(),
488 0 : refantMap_(),
489 0 : solveCPar_(vs.numberSpw(),NULL), // TBD: move inflation into ctor body
490 0 : solveRPar_(vs.numberSpw(),NULL),
491 0 : solveParOK_(vs.numberSpw(),NULL),
492 0 : solveParErr_(vs.numberSpw(),NULL),
493 0 : solveParSNR_(vs.numberSpw(),NULL),
494 0 : solveAllCPar_(vs.numberSpw(),NULL),
495 0 : solveAllRPar_(vs.numberSpw(),NULL),
496 0 : solveAllParOK_(vs.numberSpw(),NULL),
497 0 : solveAllParErr_(vs.numberSpw(),NULL),
498 0 : solveAllParSNR_(vs.numberSpw(),NULL),
499 0 : srcPolPar_(),
500 0 : chanmask_(NULL),
501 0 : simulated_(false),
502 0 : simint_("integration"),
503 0 : onthefly_(false)
504 : {
505 0 : if (prtlev()>2) cout << "SVC::SVC(vs)" << endl;
506 :
507 0 : caiRC_p = Aipsrc::registerRC("calibrater.activity.interval", "3600.0");
508 0 : cafRC_p = Aipsrc::registerRC("calibrater.activity.fraction", "0.00001");
509 0 : String ca_str = Aipsrc::get(caiRC_p);
510 0 : std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityInterval_p);
511 0 : userPrintActivityInterval_p = abs(userPrintActivityInterval_p);
512 :
513 0 : ca_str = Aipsrc::get(cafRC_p);
514 0 : std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityFraction_p);
515 0 : userPrintActivityFraction_p = abs(userPrintActivityFraction_p);
516 :
517 0 : initSVC();
518 :
519 0 : };
520 :
521 0 : SolvableVisCal::SolvableVisCal(String msname,Int MSnAnt,Int MSnSpw) :
522 : VisCal(msname,MSnAnt,MSnSpw),
523 0 : corruptor_p(NULL),
524 0 : ct_(NULL),
525 0 : ci_(NULL),
526 0 : cpp_(NULL),
527 0 : spwOK_(MSnSpw,false),
528 0 : maxTimePerSolution_p(0),
529 0 : minTimePerSolution_p(10000000),
530 0 : avgTimePerSolution_p(0),
531 0 : timer_p(),
532 0 : calTableName_(""),
533 0 : calTableSelect_(""),
534 0 : append_(false),
535 0 : tInterpType_(""),
536 0 : fInterpType_(""),
537 0 : spwMap_(1,-1),
538 0 : refantmode_("flex"),
539 0 : urefantlist_(1,-1),
540 0 : minblperant_(4),
541 0 : solved_(false),
542 0 : byCallib_(false),
543 0 : apmode_(""),
544 0 : solmode_(""),
545 0 : rmsthresh_(0),
546 0 : usolint_("inf"),
547 0 : solint_("inf"),
548 0 : solTimeInterval_(DBL_MAX),
549 0 : fsolint_("none"),
550 0 : fintervalHz_(-1.0),
551 0 : fintervalCh_(MSnSpw,0.0),
552 0 : chanAveBounds_(MSnSpw,Matrix<Int>()),
553 0 : solnorm_(false,"mean"),
554 0 : minSNR_(0.0f),
555 0 : combine_(""),
556 0 : focusChan_(0),
557 0 : dataInterval_(0.0),
558 0 : fitWt_(0.0),
559 0 : fit_(0.0),
560 0 : solveCPar_(MSnSpw,NULL), // TBD: move inflation into ctor body
561 0 : solveRPar_(MSnSpw,NULL),
562 0 : solveParOK_(MSnSpw,NULL),
563 0 : solveParErr_(MSnSpw,NULL),
564 0 : solveParSNR_(MSnSpw,NULL),
565 0 : solveAllCPar_(MSnSpw,NULL),
566 0 : solveAllRPar_(MSnSpw,NULL),
567 0 : solveAllParOK_(MSnSpw,NULL),
568 0 : solveAllParErr_(MSnSpw,NULL),
569 0 : solveAllParSNR_(MSnSpw,NULL),
570 0 : srcPolPar_(),
571 0 : chanmask_(NULL),
572 0 : simulated_(false),
573 0 : simint_("integration"),
574 0 : onthefly_(false)
575 : {
576 0 : if (prtlev()>2) cout << "SVC::SVC(msname,MSnAnt,MSnSpw)" << endl;
577 :
578 0 : caiRC_p = Aipsrc::registerRC("calibrater.activity.interval", "3600.0");
579 0 : cafRC_p = Aipsrc::registerRC("calibrater.activity.fraction", "0.00001");
580 0 : String ca_str = Aipsrc::get(caiRC_p);
581 0 : std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityInterval_p);
582 0 : userPrintActivityInterval_p = abs(userPrintActivityInterval_p);
583 :
584 0 : ca_str = Aipsrc::get(cafRC_p);
585 0 : std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityFraction_p);
586 0 : userPrintActivityFraction_p = abs(userPrintActivityFraction_p);
587 :
588 0 : initSVC();
589 :
590 0 : };
591 :
592 :
593 :
594 68 : SolvableVisCal::SolvableVisCal(const MSMetaInfoForCal& msmc) :
595 : VisCal(msmc),
596 68 : corruptor_p(NULL),
597 68 : ct_(NULL),
598 68 : ci_(NULL),
599 68 : cpp_(NULL),
600 68 : spwOK_(nSpw(),False),
601 68 : maxTimePerSolution_p(0),
602 68 : minTimePerSolution_p(10000000),
603 68 : avgTimePerSolution_p(0),
604 68 : timer_p(),
605 68 : calTableName_(""),
606 68 : calTableSelect_(""),
607 68 : append_(False),
608 68 : tInterpType_(""),
609 68 : fInterpType_(""),
610 68 : spwMap_(1,-1),
611 68 : refantmode_("flex"),
612 68 : urefantlist_(1,-1),
613 68 : minblperant_(4),
614 68 : solved_(False),
615 68 : byCallib_(False),
616 68 : apmode_(""),
617 68 : solmode_(""),
618 68 : rmsthresh_(0),
619 68 : usolint_("inf"),
620 68 : solint_("inf"),
621 68 : solTimeInterval_(DBL_MAX),
622 68 : fsolint_("none"),
623 68 : fintervalHz_(-1.0),
624 68 : fintervalCh_(nSpw(),0.0),
625 68 : chanAveBounds_(nSpw(),Matrix<Int>()),
626 68 : solnorm_(false,"mean"),
627 68 : minSNR_(0.0f),
628 68 : combine_(""),
629 68 : focusChan_(0),
630 68 : dataInterval_(0.0),
631 68 : fitWt_(0.0),
632 68 : fit_(0.0),
633 68 : solveCPar_(nSpw(),NULL), // TBD: move inflation into ctor body
634 68 : solveRPar_(nSpw(),NULL),
635 68 : solveParOK_(nSpw(),NULL),
636 68 : solveParErr_(nSpw(),NULL),
637 68 : solveParSNR_(nSpw(),NULL),
638 68 : solveAllCPar_(nSpw(),NULL),
639 68 : solveAllRPar_(nSpw(),NULL),
640 68 : solveAllParOK_(nSpw(),NULL),
641 68 : solveAllParErr_(nSpw(),NULL),
642 68 : solveAllParSNR_(nSpw(),NULL),
643 68 : srcPolPar_(),
644 68 : chanmask_(NULL),
645 68 : simulated_(False),
646 68 : simint_("integration"),
647 272 : onthefly_(False)
648 : {
649 68 : if (prtlev()>2) cout << "SVC::SVC(msmc)" << endl;
650 :
651 68 : caiRC_p = Aipsrc::registerRC("calibrater.activity.interval", "3600.0");
652 68 : cafRC_p = Aipsrc::registerRC("calibrater.activity.fraction", "0.00001");
653 68 : String ca_str = Aipsrc::get(caiRC_p);
654 68 : std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityInterval_p);
655 68 : userPrintActivityInterval_p = abs(userPrintActivityInterval_p);
656 :
657 68 : ca_str = Aipsrc::get(cafRC_p);
658 68 : std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityFraction_p);
659 68 : userPrintActivityFraction_p = abs(userPrintActivityFraction_p);
660 :
661 68 : initSVC();
662 :
663 68 : };
664 :
665 :
666 :
667 0 : SolvableVisCal::SolvableVisCal(const Int& nAnt) :
668 : VisCal(nAnt),
669 0 : corruptor_p(NULL),
670 0 : maxTimePerSolution_p(0),
671 0 : minTimePerSolution_p(10000000),
672 0 : avgTimePerSolution_p(0),
673 0 : timer_p(),
674 0 : calTableName_(""),
675 0 : calTableSelect_(""),
676 0 : append_(false),
677 0 : tInterpType_(""),
678 0 : fInterpType_(""),
679 0 : spwMap_(1,-1),
680 0 : refantmode_("flex"),
681 0 : urefantlist_(1,-1),
682 0 : minblperant_(4),
683 0 : solved_(false),
684 0 : apmode_(""),
685 0 : solmode_(""),
686 0 : rmsthresh_(0),
687 0 : usolint_("inf"),
688 0 : solint_("inf"),
689 0 : solTimeInterval_(DBL_MAX),
690 0 : fsolint_("none"),
691 0 : solnorm_(false,"mean"),
692 0 : minSNR_(0.0),
693 0 : combine_(""),
694 0 : focusChan_(0),
695 0 : dataInterval_(0.0),
696 0 : fitWt_(0.0),
697 0 : fit_(0.0),
698 0 : solveCPar_(1,NULL),
699 0 : solveRPar_(1,NULL),
700 0 : solveParOK_(1,NULL),
701 0 : solveParErr_(1,NULL),
702 0 : solveParSNR_(1,NULL),
703 0 : srcPolPar_(),
704 0 : chanmask_(NULL),
705 0 : simulated_(false),
706 0 : simint_("inf"),
707 0 : onthefly_(false)
708 : {
709 0 : if (prtlev()>2) cout << "SVC::SVC(i,j,k)" << endl;
710 :
711 0 : caiRC_p = Aipsrc::registerRC("calibrater.activity.interval", "3600.0");
712 0 : cafRC_p = Aipsrc::registerRC("calibrater.activity.fraction", "0.00001");
713 0 : String ca_str = Aipsrc::get(caiRC_p);
714 0 : std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityInterval_p);
715 0 : userPrintActivityInterval_p = abs(userPrintActivityInterval_p);
716 :
717 0 : ca_str = Aipsrc::get(cafRC_p);
718 0 : std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityFraction_p);
719 0 : userPrintActivityFraction_p = abs(userPrintActivityFraction_p);
720 :
721 0 : initSVC();
722 :
723 0 : }
724 :
725 68 : SolvableVisCal::~SolvableVisCal() {
726 :
727 68 : if (prtlev()>2) cout << "SVC::~SVC()" << endl;
728 :
729 : // TODO RI do we ever have the same corruptor working on multiple VCs? then we need some kind of
730 : // multiuse locking...
731 68 : if (corruptor_p) delete corruptor_p;
732 :
733 68 : deleteSVC();
734 :
735 68 : if (ci_) delete ci_; ci_=NULL;
736 68 : if (cpp_) delete cpp_; cpp_=NULL;
737 68 : if (ct_) delete ct_; ct_=NULL;
738 :
739 68 : }
740 :
741 :
742 : // Generic setapply
743 0 : void SolvableVisCal::setApply() {
744 :
745 0 : if (prtlev()>2) cout << "SVC::setApply()" << endl;
746 :
747 : // Generic settings
748 0 : calTableName()="<none>";
749 0 : calTableSelect()="<none>";
750 0 : tInterpType()="nearest";
751 0 : indgen(spwMap());
752 0 : interval()=DBL_MAX;
753 :
754 : // This is apply context
755 0 : setApplied(true);
756 0 : setSolved(false);
757 :
758 0 : }
759 :
760 :
761 :
762 : // Setapply from a Cal Table, etc.
763 34 : void SolvableVisCal::setApply(const Record& apply) {
764 : // Inputs:
765 : // apply Record& Contains application params
766 : //
767 :
768 34 : if (prtlev()>2)
769 0 : cout << "SVC::setApply(apply)" << endl;
770 :
771 : // Call VisCal version for generic stuff
772 34 : VisCal::setApply(apply);
773 :
774 : // Collect Cal table parameters
775 34 : if (apply.isDefined("table")) {
776 34 : calTableName()=apply.asString("table");
777 : // Verify that CalTable is of correct type
778 34 : verifyCalTable(calTableName());
779 : }
780 :
781 : // Collect interpolation parameters
782 34 : if (apply.isDefined("interp")) {
783 5 : String interp=apply.asString("interp");
784 5 : if (interp.contains(',')) {
785 0 : tInterpType()=String(interp.before(','));
786 0 : fInterpType() = interp.after(',');
787 : }
788 : else
789 5 : tInterpType()=interp;
790 5 : }
791 :
792 : // Protect against non-specific interp
793 34 : if (tInterpType()=="")
794 29 : tInterpType()="linear";
795 34 : if (fInterpType()=="" && this->freqDepPar()) // only if we are freq-dep
796 0 : fInterpType()="linear";
797 :
798 : // Catch use of deprecated 'aipslin' interpolation
799 34 : if (tInterpType().contains("aips") || fInterpType().contains("aips") )
800 0 : throw(AipsError("The (peculiar) 'aipslin' interpolation type was deprecated in CASA v3.4; use 'linear'."));
801 :
802 :
803 : // cout << "SVC::setApply(apply) is not yet supporting CalSelection." << endl;
804 :
805 : /*
806 : if (apply.isDefined("select"))
807 : calTableSelect()=apply.asString("select");
808 :
809 : else {
810 :
811 : calTableSelect()="";
812 : // String spwsel("");
813 : // if (apply.isDefined("spw")) {
814 : // ostringstream os;
815 : // os << Vector<Int>(apply.asArrayInt("spw"));
816 : // spwsel = os.str();
817 : // }
818 : // cout << "spwsel = " << spwsel << endl;
819 :
820 : String fldsel("");
821 : if (apply.isDefined("field")) {
822 : ostringstream os;
823 : os << Vector<Int>(apply.asArrayInt("field"));
824 : if (os.str()!="[]")
825 : fldsel = os.str();
826 : }
827 :
828 : if (fldsel.length()>0) {
829 : ostringstream os;
830 : os << "(FIELD_ID IN " << fldsel << ")";
831 : calTableSelect() = os.str();
832 : }
833 : }
834 : */
835 :
836 34 : String fieldstr;
837 34 : String fieldtype("");
838 34 : if (apply.isDefined("fieldstr")) {
839 5 : fieldstr=apply.asString("fieldstr");
840 : // cout << "SVC::setApply: fieldstr=" << fieldstr << endl;
841 5 : if (fieldstr=="nearest") {
842 0 : fieldtype="nearest";
843 0 : fieldstr="";
844 : }
845 : }
846 : //cout << "SVC::setApply: fieldstr=" << fieldstr << endl;
847 : //cout << "SVC::setApply: fieldtype=" << fieldtype << endl;
848 :
849 34 : if (apply.isDefined("spwmap"))
850 5 : spwMap().assign(apply.asArrayInt("spwmap"));
851 :
852 : // Catch spwmap that is too long
853 34 : if (spwMap().nelements()>uInt(nSpw()))
854 0 : throw(AipsError("Specified spwmap has more elements ("+String::toString(spwMap().nelements())+") than the number of spectral windows in the MS ("+String::toString(nSpw())+")."));
855 :
856 : // TBD: move interval to VisCal version?
857 : // TBD: change to "reach"
858 34 : if (apply.isDefined("t"))
859 5 : interval()=apply.asFloat("t");
860 :
861 : // This is apply context
862 34 : setApplied(true);
863 34 : setSolved(false);
864 :
865 : // TBD: "Arranging to apply...."
866 :
867 : // TBD: Move the following so as to be triggered
868 : // when actual application starts? E.g., SVC::initApply()...
869 :
870 : // Open the caltable
871 34 : loadMemCalTable(calTableName(),fieldstr);
872 :
873 : // Make the interpolation engine
874 34 : MeasurementSet ms(msName());
875 34 : ci_ = new CTPatchedInterp(*ct_,matrixType(),nPar(),tInterpType(),fInterpType(),fieldtype,ms,msmc(),spwMap(),cttifactoryptr());
876 :
877 : // Channel counting info
878 : // (soon will deprecate, I think, because there will be no need
879 : // to do channel registration in the apply)
880 34 : startChanList()=0; // all zero
881 :
882 : // cout << "End of SVC::setApply" << endl;
883 :
884 34 : }
885 :
886 : // Setapply from a Cal Table, etc.
887 2 : void SolvableVisCal::setCallib(const Record& callib,
888 : const MeasurementSet& selms) {
889 :
890 2 : if (prtlev()>2)
891 0 : cout << "SVC::setCallib(callib)" << endl;
892 :
893 :
894 6 : if (typeName().contains("BPOLY") ||
895 4 : typeName().contains("GSPLINE"))
896 0 : throw(AipsError(typeName()+" not yet supported for apply by cal library."));
897 :
898 : // Call VisCal version for generic stuff
899 2 : VisCal::setCallib(callib,selms);
900 :
901 : // signal that we are using a callib
902 2 : byCallib_=true;
903 :
904 : // Collect Cal table parameters
905 2 : if (callib.isDefined("tablename")) {
906 2 : calTableName()=callib.asString("tablename");
907 : // Verify that CalTable is of correct type
908 2 : verifyCalTable(calTableName());
909 : }
910 :
911 : // This is apply context
912 2 : setApplied(true);
913 2 : setSolved(false);
914 :
915 : logSink() << LogIO::NORMAL << ". "
916 2 : << this->applyinfo()
917 2 : << LogIO::POST;
918 :
919 : // Make the interpolation engine
920 2 : cpp_ = new CLPatchPanel(calTableName(),selms,callib,matrixType(),nPar(),cttifactoryptr());
921 : //cpp_->listmappings();
922 :
923 : // Setup ct_ in SVC private data, because some derived classes need this
924 : // NB: Not loaded into memory in the callib context (CLPatchPanel has that)
925 2 : ct_= new NewCalTable(calTableName(),Table::Old,Table::Plain);
926 :
927 2 : }
928 :
929 :
930 : // ===================================================
931 :
932 0 : void SolvableVisCal::createCorruptor(const VisIter& vi,const Record& simpar, const Int nSim) {
933 0 : LogIO os(LogOrigin("SVC", "createCorruptor", WHERE));
934 :
935 0 : if (prtlev()>3) cout << " SVC::createCorruptor:" << endl;
936 :
937 : // this is the generic create and init
938 : // ** specialists should call this after createing their corruptor
939 : // and before initializing
940 :
941 0 : if (!corruptor_p) {
942 0 : corruptor_p = new CalCorruptor(nSim);
943 0 : os << LogIO::WARN << "creating generic CalCorruptor" << LogIO::POST;
944 : }
945 :
946 : // would be nice to reduce the amount of stuff passed down to the corruptor;
947 : // fnChan is used in AtmosCorruptor, currAnt and curr Spw are used generically
948 :
949 0 : corruptor_p->prtlev()=prtlev();
950 0 : corruptor_p->freqDepPar()=freqDepPar();
951 0 : corruptor_p->simpar()=simpar;
952 : // initialize is supposed to be called in a specialization, but
953 : // if we end up only using the generic CalCorruptor and this generic
954 : // createCorruptor, we still want amplitude to be passed on.
955 0 : if (simpar.isDefined("amplitude"))
956 0 : corruptor_p->amp()=simpar.asFloat("amplitude");
957 :
958 0 : if (simpar.isDefined("mode"))
959 0 : corruptor_p->mode()=simpar.asString("mode");
960 :
961 : // corruptor_p->nCorr()=vi.nCorr();
962 : // if (prtlev()>3)
963 : // os << LogIO::POST << "nCorr= " << vi.nCorr() << LogIO::POST;
964 : // what matters is nPar not nCorr - then apply uses coridx
965 0 : corruptor_p->nPar()=nPar();
966 :
967 0 : const MSSpWindowColumns& spwcols = vi.msColumns().spectralWindow();
968 : // if (prtlev()>3) cout << " SpwCols accessed:" << endl;
969 : //if (prtlev()>3) cout << " nSpw()= " << nSpw() << " spwcols= " << nSpw() << endl;
970 : //if (prtlev()>3) cout << " spwcols.nrow()= " << spwcols.nrow() << endl;
971 0 : AlwaysAssert(uInt(nSpw())==spwcols.nrow(),AipsError);
972 : // there's a member variable in Simulator nSpw, should we verify that
973 : // this is the same? probably.
974 :
975 : // things will break if spw mapping, ie not in same order as in vs
976 0 : corruptor_p->nSpw()=nSpw();
977 0 : corruptor_p->nAnt()=nAnt();
978 0 : corruptor_p->currAnt()=0;
979 0 : corruptor_p->currSpw()=0;
980 0 : corruptor_p->fRefFreq().resize(nSpw());
981 0 : corruptor_p->fnChan().resize(nSpw());
982 0 : corruptor_p->fWidth().resize(nSpw());
983 0 : corruptor_p->currChans().resize(nSpw());
984 :
985 0 : for (Int irow=0;irow<nSpw();++irow) {
986 0 : corruptor_p->currChans()[irow]=0;
987 0 : corruptor_p->fRefFreq()[irow]=spwcols.refFrequency()(irow);
988 : // don't need to change fnChan to 1 if not freqDepPar()
989 : // because fnChan is only used in AtmosCorruptor if
990 : // freqDepPar() is set i.e. in initAtm().
991 0 : corruptor_p->fnChan()[irow]=spwcols.numChan()(irow);
992 0 : corruptor_p->fWidth()[irow]=spwcols.totalBandwidth()(irow);
993 : // totalBandwidthQuant ? in other places its assumed to be in Hz
994 : }
995 : // see MSsummary.cc for more info/examples
996 0 : if (prtlev()>3)
997 0 : cout << " SVC::fnChan = "<<corruptor_p->fnChan()<<" reffreq = "<<corruptor_p->fRefFreq()<<" fWidth = "<<corruptor_p->fWidth()<<endl;
998 :
999 0 : if (prtlev()>3) cout << " ~SVC::createCorruptor:" << endl;
1000 :
1001 0 : }
1002 :
1003 :
1004 :
1005 0 : void SolvableVisCal::setSimulate(VisSet& vs, Record& simpar, Vector<Double>& solTimes) {
1006 :
1007 0 : LogIO os(LogOrigin("SVC["+typeName()+"]", "setSimulate()", WHERE));
1008 0 : if (prtlev()>2) cout << " SVC::setSimulate(simpar)" << endl;
1009 :
1010 : // cout << "SVC::setSimulate" << endl;
1011 :
1012 : // Extract calWt
1013 0 : if (simpar.isDefined("calwt"))
1014 0 : calWt()=simpar.asBool("calwt");
1015 :
1016 : // (copied from SolvableVisCal::setSolve)
1017 0 : if (simpar.isDefined("simint"))
1018 0 : simint()=simpar.asString("simint");
1019 :
1020 0 : if (upcase(simint()).contains("INF") || simint()=="") {
1021 0 : simint()="infinite";
1022 0 : interval()=-1.0;
1023 0 : } else if (upcase(simint()).contains("INT")) {
1024 0 : simint()="integration";
1025 0 : interval()=0.0;
1026 : } else {
1027 0 : QuantumHolder qhsimint;
1028 0 : String error;
1029 0 : Quantity qsimint;
1030 0 : qhsimint.fromString(error,simint());
1031 0 : if (error.length()!=0)
1032 0 : throw(AipsError("Unrecognized units for simint."));
1033 0 : qsimint=qhsimint.asQuantumDouble();
1034 :
1035 0 : if (qsimint.isConform("s"))
1036 0 : interval()=qsimint.get("s").getValue();
1037 : else {
1038 0 : if (qsimint.getUnit().length()==0) {
1039 : // when no units specified, assume seconds
1040 : // assume seconds
1041 0 : interval()=qsimint.getValue();
1042 0 : simint()=simint()+"s";
1043 : }
1044 : else
1045 : // unrecognized units:
1046 0 : throw(AipsError("Unrecognized units for simint (e.g., use 'min', not 'm', for minutes)"));
1047 : }
1048 0 : }
1049 :
1050 : // check if want to write a table:
1051 0 : if (simpar.isDefined("caltable")) {
1052 0 : calTableName()=simpar.asString("caltable");
1053 : // RI todo SVC::setSimulate deal with over-writing existing caltables
1054 : // verifyCalTable(calTableName());
1055 0 : append()=false;
1056 : } else {
1057 0 : calTableName()="<none>";
1058 : }
1059 0 : if (calTableName().length()==0)
1060 0 : calTableName()="<none>";
1061 :
1062 : // on the fly (only implemented for ANoise 20100817)
1063 0 : simOnTheFly()=false;
1064 0 : if (simpar.isDefined("onthefly")) {
1065 0 : if (simpar.asBool("onthefly")) {
1066 0 : if (type() != VisCal::ANoise) {
1067 0 : throw(AipsError("Logic Error: onthefly simulation not available for type "+typeName()));
1068 : } else {
1069 0 : simOnTheFly()=true;
1070 0 : os << LogIO::DEBUG1 << " using OTF simulation" << LogIO::POST;
1071 0 : calTableName()="<none>";
1072 : }
1073 : }
1074 : }
1075 :
1076 0 : setSolved(false);
1077 : // this has to be true for some of George's VE stuff
1078 : // but be careful about VC structure and inflation!
1079 0 : setApplied(true);
1080 0 : setSimulated(true);
1081 :
1082 : // without this, CI gets created without a sensible time
1083 : // interpolation, and ends up bombing
1084 0 : tInterpType()="nearest";
1085 :
1086 :
1087 : // ----------------
1088 : // assess size of ms:
1089 :
1090 : // how to combine data in sizeUp e.g. SPW,SCAN
1091 0 : if (simpar.isDefined("combine"))
1092 0 : combine()=simpar.asString("combine");
1093 : else
1094 0 : throw(AipsError("MS combination information not set"));
1095 :
1096 : // GM: organize calibration correction/corruption according to
1097 : // multi-spw consistency; e.g. move time ahead of data_desc_id so that
1098 : // data_desc_id (spw) changes faster than time, even within scans.
1099 :
1100 : // RI todo double-check logic in case of spwmap and multi-spw
1101 :
1102 : // Arrange for iteration over data
1103 0 : Block<Int> columns;
1104 : // include scan iteration
1105 0 : columns.resize(5);
1106 0 : columns[0]=MS::ARRAY_ID;
1107 0 : columns[1]=MS::SCAN_NUMBER;
1108 0 : columns[2]=MS::FIELD_ID;
1109 : // GM's order:
1110 : //columns[3]=MS::DATA_DESC_ID;
1111 : //columns[4]=MS::TIME;
1112 : // RI put spw after time
1113 0 : columns[4]=MS::DATA_DESC_ID;
1114 0 : columns[3]=MS::TIME;
1115 :
1116 :
1117 : // drop chunking time interval down to the simulation interval, else will
1118 : // chunk by entire scans.
1119 0 : Double iterInterval(max(interval(),DBL_MIN));
1120 0 : if (interval() < 0.0) { // means no interval (infinite solint)
1121 0 : iterInterval=0.0;
1122 0 : interval()=DBL_MAX;
1123 : }
1124 0 : vs.resetVisIter(columns,iterInterval);
1125 :
1126 0 : Vector<Int> nChunkPerSol;
1127 0 : Int nSim = 1;
1128 : // independent of simpar details
1129 :
1130 0 : nSim=sizeUpSim(vs,nChunkPerSol,solTimes);
1131 0 : if (prtlev()>1 and prtlev()<=4) cout << " VisCal sized for Simulation with " << nSim << " slots." << endl;
1132 0 : if (prtlev()>4) cout << " solTimes = " << solTimes-solTimes[0] << endl;
1133 :
1134 0 : if (!(simpar.isDefined("startTime"))) {
1135 0 : throw(AipsError("can't add startTime field to Record"));
1136 : // Record seems to have been designed strangely, so this doesn't work:
1137 : // RecordDesc simParDesc = simpar.description();
1138 : // simParDesc.addField("startTime",TpDouble);
1139 : // simpar.restructure(simParDesc);
1140 : }
1141 0 : simpar.define("startTime",min(solTimes));
1142 0 : if (!(simpar.isDefined("stopTime"))) {
1143 0 : throw(AipsError("can't add stopTime field to Record"));
1144 : }
1145 0 : simpar.define("stopTime",max(solTimes));
1146 :
1147 : // assume only one ms attached to the VI. need vi for mscolumns in createCorruptor
1148 : // note - sizeUpSim seems to break the reference to mscolumns inside of VI,
1149 : // so we're better off resetting it here, I think, just to make sure?
1150 0 : VisIter& vi(vs.iter());
1151 : os << LogIO::DEBUG1 << " number of spw in VI (checking validity of mscolumns) = "
1152 0 : << vi.numberSpw() << LogIO::POST;
1153 0 : vi.origin();
1154 : os << LogIO::DEBUG1 << " number of spw in VI (after resetting to origin = "
1155 0 : << vi.numberSpw() << LogIO::POST;
1156 :
1157 : // -------------------
1158 : // create (and initialize) a corruptor in a VC-specific way -
1159 : // specializations need to call the generic SVC::createCorruptor to get
1160 : // spw etc information passed down.
1161 0 : createCorruptor(vi,simpar,nSim);
1162 :
1163 : // set times in the corruptor if createCorruptor didn't:
1164 0 : if (!corruptor_p->times_initialized()) {
1165 0 : corruptor_p->curr_slot()=0;
1166 0 : corruptor_p->slot_times().resize(nSim);
1167 0 : corruptor_p->slot_times()=solTimes;
1168 0 : corruptor_p->startTime()=min(solTimes);
1169 0 : corruptor_p->stopTime()=max(solTimes);
1170 0 : corruptor_p->times_initialized()=true;
1171 : }
1172 :
1173 0 : if (simOnTheFly()) {
1174 :
1175 0 : calTableName()="<none>";
1176 :
1177 : } else {
1178 :
1179 0 : if (prtlev()>5)
1180 0 : cout << " slot_times= "
1181 0 : << corruptor_p->slot_time(1)-corruptor_p->slot_time(0) << " "
1182 0 : << corruptor_p->slot_time(2)-corruptor_p->slot_time(0) << " "
1183 0 : << corruptor_p->slot_time(3)-corruptor_p->slot_time(0) << " "
1184 0 : << corruptor_p->slot_time(4)-corruptor_p->slot_time(0) << " "
1185 0 : << corruptor_p->slot_time(5)-corruptor_p->slot_time(0) << " "
1186 0 : << corruptor_p->slot_time(6)-corruptor_p->slot_time(0) << " "
1187 0 : << corruptor_p->slot_time(7)-corruptor_p->slot_time(0) << " "
1188 0 : << endl;
1189 :
1190 0 : os << LogIO::NORMAL << "Calculating corruption terms for " << siminfo() << LogIO::POST;
1191 : //-------------------
1192 : // actually calculate the calset
1193 : // which was inflated by sizeupSim to the right size
1194 :
1195 0 : Vector<Int> slotidx(nSpw(),-1);
1196 :
1197 0 : vi.originChunks();
1198 :
1199 0 : Vector<Int> a1;
1200 0 : Vector<Int> a2;
1201 0 : Matrix<Bool> flags;
1202 :
1203 0 : ProgressMeter meter(0.,1. , "Simulating "+nameOfType(type())+" ", "", "", "", true, 1);
1204 :
1205 : // check if it's possible to simulate ACs
1206 0 : Bool knownACtype(false);
1207 0 : String mode(corruptor_p->mode());
1208 0 : if (type()==VisCal::ANoise)
1209 0 : knownACtype = true;
1210 0 : else if (type()==VisCal::T && (mode=="tsys-manual" || mode=="tsys-atm"))
1211 0 : knownACtype = true;
1212 :
1213 0 : for (Int isim=0;isim<nSim && vi.moreChunks();++isim) {
1214 :
1215 0 : Int thisSpw=spwMap()(vi.spectralWindow());
1216 0 : currSpw()=thisSpw;
1217 0 : corruptor_p->currSpw()=thisSpw;
1218 0 : slotidx(thisSpw)++;
1219 :
1220 0 : IPosition cparshape=solveCPar().shape();
1221 :
1222 0 : Vector<Double> timevec;
1223 : Double starttime,stoptime;
1224 0 : starttime=vi.time(timevec)[0];
1225 :
1226 : //IPosition blc(3,0, 0,0); // par,chan=focuschan,elem=ant
1227 : //IPosition trc(3,nPar()-1,0,0);
1228 0 : IPosition blc(3,0, 0, 0); // par,chan=focuschan,elem=ant
1229 0 : IPosition trc(3,nPar()-1,nChanPar()-1,0);
1230 0 : IPosition gpos(3,0,0,0);
1231 :
1232 0 : Bool useBase(false);
1233 0 : if (nElem()==nBln()) useBase=true;
1234 :
1235 0 : for (Int ichunk=0;ichunk<nChunkPerSol[isim];++ichunk) {
1236 : // RI todo: SVC:setSim deal with spwmap and spwcomb() here
1237 :
1238 0 : for (vi.origin(); vi.more(); vi++) {
1239 :
1240 0 : if (prtlev()>5) cout << " vi++"<<endl;
1241 0 : vi.antenna1(a1);
1242 0 : vi.antenna2(a2);
1243 0 : vi.flag(flags);
1244 0 : vi.time(timevec);
1245 : // assume that the corruptor slot i.e. time is the same for all rows.
1246 : // (to the accuracy of simint())
1247 :
1248 : // set things for SVC::keep:
1249 : Int tvsize;
1250 0 : timevec.shape(tvsize);
1251 0 : stoptime=timevec[tvsize-1];
1252 0 : refTime() = 0.5*(starttime+stoptime);
1253 0 : interval() = (stoptime-starttime);
1254 0 : currField() = vi.fieldId();
1255 :
1256 : // make sure we have the right slot in the corruptor
1257 : // RI todo can the corruptor slot be the same for all chunks?
1258 : // were setting curr_time() to timevec[0], but I think refTime is more
1259 : // accurate
1260 : // 20100831 make corruptor->setCurrtime() which does slot if ness,
1261 : // and * invalidates any aux matrices like airmass in atmcorr,
1262 : // if ness *
1263 :
1264 0 : if (corruptor_p->curr_time()!=refTime())
1265 0 : corruptor_p->setCurrTime(refTime());
1266 :
1267 0 : solveCPar()=Complex(0.0);
1268 0 : solveParOK()=false;
1269 :
1270 0 : for (Int irow=0;irow<vi.nRow();++irow) {
1271 :
1272 0 : if (nfalse(flags.column(irow))> 0 ) {
1273 :
1274 0 : corruptor_p->currAnt()=a1(irow);
1275 : // only used for baseline-based SVCs
1276 0 : corruptor_p->currAnt2()=a2(irow);
1277 :
1278 : // baseline or antenna-based?
1279 0 : if (useBase) {
1280 0 : gpos(2)=blnidx(a1(irow),a2(irow));
1281 : } else {
1282 0 : gpos(2)=a1(irow);
1283 : }
1284 :
1285 : // RI TODO make some freqDepPar VCs return all ch at once
1286 : //if not freqDepPar, then nChanPar=1
1287 0 : for (Int ich=nChanPar()-1;ich>-1;--ich) {
1288 0 : focusChan()=ich;
1289 0 : corruptor_p->setFocusChan(ich);
1290 0 : gpos(1)=ich;
1291 :
1292 : // gpos is (ipar, ich, iant|ibln)
1293 0 : for (Int ipar=0;ipar<nPar();ipar++) {
1294 0 : gpos(0)=ipar;
1295 0 : if ( a1(irow)==a2(irow) ) {
1296 : // autocorrels should get 1. for multiplicative VC
1297 : // if (type()==VisCal::ANoise or type()==VisCal::A)
1298 0 : if (type()==VisCal::A)
1299 0 : solveCPar()(gpos)=0.0;
1300 0 : else if (knownACtype)
1301 0 : solveCPar()(gpos) = corruptor_p->simPar(vi,type(),ipar);
1302 : else
1303 0 : solveCPar()(gpos)=1.0;
1304 0 : solveParOK()(gpos)=true;
1305 : } else {
1306 : // specialized simPar for each VC - may depend on mode etc
1307 0 : solveCPar()(gpos) = corruptor_p->simPar(vi,type(),ipar);
1308 0 : solveParOK()(gpos)=true;
1309 :
1310 : // if MS doesn't have ACs we need to fill ant2 b/c it'll
1311 : // never get selected in this loop over ant1
1312 : // TODO clean this up
1313 0 : if (not useBase) {
1314 0 : gpos(2)=a2(irow);
1315 0 : if (solveCPar()(gpos)==Complex(0.0)) {
1316 0 : corruptor_p->currAnt()=a2(irow);
1317 0 : solveCPar()(gpos) = corruptor_p->simPar(vi,type(),ipar);
1318 0 : solveParOK()(gpos)=true;
1319 0 : corruptor_p->currAnt()=a1(irow);
1320 : }
1321 0 : gpos(2)=a1(irow);
1322 : }
1323 : }
1324 : }
1325 :
1326 :
1327 : // 20101006
1328 : // if ( a1(irow)==a2(irow) ) {
1329 : // // autocorrels should get 1. for multiplicative VC
1330 : // if (type()==VisCal::ANoise or type()==VisCal::A)
1331 : // solveCPar()(blc,trc)=0.0;
1332 : // else
1333 : // solveCPar()(blc,trc)=1.0;
1334 : // } else {
1335 : // // specialized simPar for each VC - may depend on mode etc
1336 : // for (Int ipar=0;ipar<nPar();ipar++)
1337 : // // RI TODO left-hand operand of comma has no effect:
1338 : // (solveCPar()(blc,trc))[ipar,0,0] = corruptor_p->simPar(vi,type(),ipar);
1339 : // }
1340 :
1341 : } //ich
1342 :
1343 : // if (prtlev()>5) cout << " row "<<irow<< " set; cparshape="<<solveCPar().shape()<<endl;
1344 : // if using gpos and not changing these then they stay set this way
1345 : //blc(1)=0;
1346 : //trc(1)=nChanPar()-1;
1347 : // blc(2)=gpos(2);
1348 : // trc(2)=gpos(2);
1349 : //solveParOK()(blc,trc)=true;
1350 : }// if not flagged
1351 : }// row
1352 :
1353 : // Reference solveCPar, etc. for keepNCT
1354 0 : solveAllCPar().reference(solveCPar());
1355 0 : solveAllParOK().reference(solveParOK());
1356 0 : solveAllParErr().reference(solveParErr());
1357 0 : solveAllParSNR().reference(solveParSNR());
1358 0 : currScan()=-1;
1359 0 : currObs()=0;
1360 :
1361 0 : keepNCT();
1362 :
1363 : }// vi
1364 0 : if (vi.moreChunks()) vi.nextChunk();
1365 : } // chunk loop
1366 :
1367 : // progress indicator
1368 0 : meter.update(Double(isim)/nSim);
1369 :
1370 0 : }// nsim loop
1371 0 : }
1372 :
1373 0 : if (calTableName()!="<none>") {
1374 : // RI todo SVC::setSimulate check if user wants to overwrite calTable
1375 : os << LogIO::NORMAL
1376 0 : << "Writing calTable = "+calTableName()+" ("+typeName()+")"
1377 0 : << endl << LogIO::POST;
1378 : // write the table
1379 0 : append()=false;
1380 0 : storeNCT();
1381 : } else {
1382 : os << LogIO::NORMAL
1383 0 : << "calTable name not set - not writing to disk (note: ";
1384 0 : if (simOnTheFly())
1385 0 : os << "OTF sim - not creating Calset either)";
1386 : else
1387 0 : os << "NOT OTF sim - still creating Calset)";
1388 0 : os << LogIO::POST;
1389 : }
1390 :
1391 :
1392 :
1393 0 : if (not simOnTheFly()) {
1394 :
1395 : // Create the interpolator
1396 0 : if (ci_)
1397 0 : delete ci_;
1398 :
1399 0 : MeasurementSet ms(msName());
1400 0 : ci_=new CTPatchedInterp(*ct_,matrixType(),nPar(),tInterpType(),"linear","",ms,spwMap(),cttifactoryptr());
1401 :
1402 0 : }
1403 :
1404 : // cout << "End of SVC::setSimulate" << endl;
1405 :
1406 :
1407 0 : if (prtlev()>2) cout << " ~SVC::setSimulate(simpar)" << endl;
1408 0 : }
1409 :
1410 :
1411 :
1412 :
1413 :
1414 :
1415 :
1416 0 : String SolvableVisCal::siminfo() {
1417 :
1418 0 : ostringstream o;
1419 0 : o << "simulated " << typeName()
1420 0 : << ": output table=" << calTableName()
1421 0 : << " simint=" << simint()
1422 0 : << " t=" << interval();
1423 0 : return String(o);
1424 0 : }
1425 :
1426 : // ===================================================
1427 :
1428 :
1429 :
1430 :
1431 :
1432 :
1433 14 : String SolvableVisCal::applyinfo() {
1434 :
1435 14 : ostringstream o;
1436 28 : o << typeName()
1437 14 : << ": table=" << calTableName();
1438 :
1439 14 : if (byCallib_)
1440 4 : o << " (by cal library)";
1441 : else {
1442 10 : o << " select=" << calTableSelect()
1443 10 : << " interp=" << tInterpType();
1444 10 : if (this->freqDepPar())
1445 0 : o << "," << fInterpType();
1446 10 : o << " spwmap=" << spwMap();
1447 :
1448 : }
1449 :
1450 14 : o << boolalpha << " calWt=" << calWt();
1451 : // << " t=" << interval();
1452 :
1453 28 : return String(o);
1454 :
1455 14 : }
1456 :
1457 : // NEWCALTABLE ?????
1458 0 : void SolvableVisCal::setSolve() {
1459 :
1460 0 : if (prtlev()>2) cout << "SVC::setSolve()" << endl;
1461 :
1462 0 : interval()=10.0;
1463 0 : urefantlist_.resize(1);
1464 0 : urefantlist_(0)=-1;
1465 0 : apmode()="AP";
1466 0 : calTableName()="<none>";
1467 0 : solnorm_=SolNorm(false,String("mean"));
1468 0 : minSNR()=0.0f;
1469 :
1470 : // This is the solve context
1471 0 : setSolved(true);
1472 0 : setApplied(false);
1473 0 : setSimulated(false);
1474 :
1475 0 : }
1476 :
1477 32 : void SolvableVisCal::setSolve(const Record& solve)
1478 : {
1479 :
1480 32 : if (prtlev()>2) cout << "SVC::setSolve(solve)" << endl;
1481 :
1482 : // Collect parameters
1483 32 : if (solve.isDefined("table"))
1484 32 : calTableName()=solve.asString("table");
1485 :
1486 32 : if (calTableName().length()==0)
1487 0 : throw(AipsError("Please specify a name for the output calibration table!"));
1488 :
1489 : // Internal default solint
1490 32 : solint()="inf";
1491 32 : fsolint()="none";
1492 32 : if (solve.isDefined("solint")) {
1493 32 : usolint_=solve.asString("solint");
1494 32 : if (usolint_.contains(',')) {
1495 : // both time and freq solint specified
1496 0 : solint()=usolint_.before(',');
1497 0 : fsolint()=usolint_.after(',');
1498 : }
1499 : else
1500 : // interpret as only time-dep solint
1501 32 : solint()=usolint_;
1502 : }
1503 :
1504 : // Handle solint format
1505 32 : if (upcase(solint()).contains("INF") || solint()=="") {
1506 30 : solint()="inf";
1507 30 : interval()=-1.0;
1508 : }
1509 2 : else if (upcase(solint()).contains("INT"))
1510 0 : interval()=0.0;
1511 : else {
1512 2 : QuantumHolder qhsolint;
1513 2 : String error;
1514 2 : Quantity qsolint;
1515 2 : qhsolint.fromString(error,solint());
1516 2 : if (error.length()!=0)
1517 0 : throw(AipsError("Unrecognized units for time-dep solint."));
1518 2 : qsolint=qhsolint.asQuantumDouble();
1519 :
1520 2 : if (qsolint.isConform("s"))
1521 0 : interval()=qsolint.get("s").getValue();
1522 : else {
1523 2 : if (qsolint.getUnit().length()==0) {
1524 : // when no units specified, assume seconds
1525 2 : interval()=qsolint.getValue();
1526 2 : solint()=solint()+"s";
1527 : }
1528 : else
1529 : // unrecognized units:
1530 0 : throw(AipsError("Unrecognized units for solint (e.g., use 'min', not 'm', for minutes)"));
1531 : }
1532 2 : }
1533 :
1534 : // Handle fsolint format
1535 32 : if (upcase(fsolint()).contains("NONE") || !freqDepPar()) {
1536 32 : fsolint()="none";
1537 32 : fintervalCh_.set(0.0);
1538 32 : fintervalHz_=-1.0;
1539 : }
1540 : else {
1541 0 : if (freqDepPar()) {
1542 : // Try to parse it
1543 0 : if (upcase(fsolint()).contains("CH")) {
1544 0 : String fsolintstr=upcase(fsolint());
1545 0 : fintervalCh_.set(String::toDouble(upcase(fsolint()).before("CH")));
1546 0 : fintervalHz_=-1.0; // Don't know in Hz, and don't really care
1547 0 : fsolint()=downcase(fsolint());
1548 0 : }
1549 : else {
1550 0 : QuantumHolder qhFsolint;
1551 0 : String error;
1552 0 : qhFsolint.fromString(error,fsolint());
1553 0 : if (error.length()!=0)
1554 0 : throw(AipsError("Unrecognized units for freq-dep solint."));
1555 0 : Quantity qFsolint;
1556 0 : qFsolint=qhFsolint.asQuantumDouble();
1557 :
1558 0 : if (qFsolint.isConform("Hz")) {
1559 0 : fintervalHz_=qFsolint.get("Hz").getValue();
1560 0 : fintervalCh_.set(-1.0);
1561 : // throw(AipsError("Not able to convert freq-dep solint from Hz to channel yet."));
1562 : }
1563 : else {
1564 0 : if (qFsolint.getUnit().length()==0) {
1565 : // when no units specified, assume channel
1566 0 : fintervalCh_.set(qFsolint.getValue());
1567 0 : fsolint()=fsolint()+"ch";
1568 : }
1569 : else
1570 : // unrecognized units:
1571 0 : throw(AipsError("Unrecognized units for freq-dep solint"));
1572 : } // Hz vs. Ch via Quantum
1573 0 : } // parse by Quantum
1574 : } // freqDepPar
1575 : /*
1576 : cout << "Freq-dep solint: " << fsolint()
1577 : << " Ch=" << fintervalCh_
1578 : << " Hz=" << fintervalHz()
1579 : << endl;
1580 : */
1581 : } // user set something
1582 :
1583 32 : if (solve.isDefined("preavg"))
1584 32 : preavg()=solve.asFloat("preavg");
1585 :
1586 32 : if (solve.isDefined("refantmode")) {
1587 32 : refantmode_=solve.asString("refantmode");
1588 : }
1589 32 : if (solve.isDefined("refant")) {
1590 32 : refantlist().resize();
1591 32 : refantlist()=solve.asArrayInt("refant");
1592 : }
1593 32 : if (solve.isDefined("minblperant"))
1594 32 : minblperant()=solve.asInt("minblperant");
1595 :
1596 32 : if (solve.isDefined("apmode"))
1597 32 : apmode()=solve.asString("apmode");
1598 32 : apmode().upcase();
1599 :
1600 32 : if (solve.isDefined("append"))
1601 32 : append()=solve.asBool("append");
1602 :
1603 32 : if (solve.isDefined("solnorm")) {
1604 32 : Bool solnorm=solve.asBool("solnorm");
1605 :
1606 : // normtype="mean" if not specified
1607 32 : String normtype("mean");
1608 32 : if (solve.isDefined("normtype"))
1609 32 : normtype=solve.asString("normtype");
1610 :
1611 : // Set the SolNorm object
1612 32 : solnorm_=SolNorm(solnorm,normtype);
1613 :
1614 32 : }
1615 :
1616 32 : if (solve.isDefined("minsnr"))
1617 32 : minSNR()=solve.asFloat("minsnr");
1618 :
1619 32 : if (solve.isDefined("combine"))
1620 32 : combine()=solve.asString("combine");
1621 : // cout << "SVC::setsolve: minSNR() = " << minSNR() << endl;
1622 :
1623 : // TBD: Warn if table exists (and append=F)!
1624 :
1625 : // If normalizable & preavg<0, use full pre-averaging
1626 : // (or handle this per type, e.g. D)
1627 : // TBD: make a nice log message concerning preavg
1628 32 : if (normalizable() && preavg()<0.0)
1629 0 : preavg()=DBL_MAX;
1630 :
1631 : // This is the solve context
1632 32 : setSolved(true);
1633 32 : setApplied(false);
1634 :
1635 : // state();
1636 :
1637 32 : }
1638 :
1639 64 : String SolvableVisCal::solveinfo() {
1640 :
1641 : // Get the refant name from the MS
1642 64 : String refantNames("none");
1643 64 : if (refant()>-1) {
1644 64 : refantNames="";
1645 64 : Int nra=refantlist().nelements();
1646 128 : for (Int i=0;i<nra;++i) {
1647 64 : refantNames+=msmc().antennaName(refantlist()(i));
1648 64 : if (i<nra-1) refantNames+=",";
1649 : }
1650 : }
1651 :
1652 64 : ostringstream o;
1653 64 : o << boolalpha
1654 64 : << typeName()
1655 64 : << ": table=" << calTableName()
1656 64 : << " append=" << append()
1657 64 : << " solint=" << solint()
1658 128 : << (freqDepPar() ? (","+fsolint()) : "")
1659 : // << " t=" << interval()
1660 : // << " preavg=" << preavg()
1661 64 : << " refantmode=" << "'" << refantmode_ << "'"
1662 64 : << " refant=" << "'" << refantNames << "'" // (id=" << refant() << ")"
1663 64 : << " minsnr=" << minSNR()
1664 64 : << " apmode=" << apmode()
1665 64 : << " solnorm=" << solnorm()
1666 64 : << (solnorm() ? " normtype="+solNorm().normtypeString() : "");
1667 128 : return String(o);
1668 :
1669 64 : }
1670 :
1671 :
1672 0 : void SolvableVisCal::setAccumulate(VisSet& vs,
1673 : const String& table,
1674 : const String& select,
1675 : const Double& t,
1676 : const Int&) {
1677 :
1678 :
1679 0 : LogMessage message(LogOrigin("SolvableVisCal","setAccumulate"));
1680 :
1681 : // meta-info
1682 0 : calTableName()=table;
1683 0 : calTableSelect()=select;
1684 0 : interval()=t;
1685 :
1686 : // Not actually applying or solving
1687 0 : setSolved(false);
1688 0 : setApplied(false);
1689 :
1690 : // If interval<0, this signals an existing input cumulative table
1691 0 : if (interval()<0.0) {
1692 :
1693 : // throw(AipsError("Accum is temporarily disabled."));
1694 :
1695 0 : logSink() << "Loading existing " << typeName()
1696 : << " table: " << table
1697 : << " for accumulation."
1698 0 : << LogIO::POST;
1699 :
1700 :
1701 : // Load the exiting table
1702 0 : loadMemCalTable(calTableName(),"");
1703 :
1704 : // The following should be for trivial types only!
1705 0 : nChanMatList()=nChanParList();
1706 :
1707 :
1708 : }
1709 :
1710 : // else, we are creating a cumulative table from scratch (the VisSet)
1711 : else {
1712 :
1713 0 : logSink() << "Creating " << typeName()
1714 : << " table for accumulation."
1715 0 : << LogIO::POST;
1716 :
1717 : // Creat an empty caltable
1718 0 : createMemCalTable();
1719 :
1720 : // Setup channelization (as if solving)
1721 0 : setSolveChannelization(vs);
1722 0 : nChanMatList()=nChanParList();
1723 :
1724 : // Initialize solvePar shapes
1725 0 : initSolvePar();
1726 :
1727 : // Inflate it by iteratin over the dataset
1728 0 : inflateNCTwithMetaData(vs);
1729 :
1730 : }
1731 :
1732 0 : }
1733 :
1734 :
1735 6 : void SolvableVisCal::setSpecify(const Record& specify) {
1736 :
1737 12 : LogMessage message(LogOrigin("SolvableVisCal","setSpecify"));
1738 :
1739 : // Not actually applying or solving
1740 6 : setSolved(false);
1741 6 : setApplied(false);
1742 :
1743 : // Collect Cal table parameters
1744 6 : Bool tableExists(false);
1745 6 : if (specify.isDefined("caltable")) {
1746 6 : calTableName()=specify.asString("caltable");
1747 :
1748 : // Detect existence of the table
1749 6 : tableExists=Table::isReadable(calTableName());
1750 :
1751 : }
1752 :
1753 6 : if (tableExists) {
1754 :
1755 : // Verify table has correct type
1756 0 : verifyCalTable(calTableName());
1757 :
1758 0 : logSink() << "Loading existing " << typeName()
1759 0 : << " table: " << calTableName()
1760 : << " (to be updated)."
1761 0 : << LogIO::POST;
1762 :
1763 : // Open it
1764 0 : loadMemCalTable(calTableName());
1765 :
1766 : // Fill solveParArrays
1767 :
1768 0 : Block<String> sortcols(1);
1769 0 : sortcols[0]="SPECTRAL_WINDOW_ID";
1770 0 : ROCTIter ctiter(*ct_,sortcols);
1771 0 : while (!ctiter.pastEnd()) {
1772 0 : currSpw()=ctiter.thisSpw();
1773 0 : nChanPar()=ctiter.nchan();
1774 0 : switch(parType()) {
1775 0 : case VisCalEnum::COMPLEX: {
1776 0 : ctiter.cparam(solveAllCPar());
1777 0 : break;
1778 : }
1779 0 : case VisCalEnum::REAL: {
1780 0 : ctiter.fparam(solveAllRPar());
1781 0 : break;
1782 : }
1783 0 : default: {
1784 0 : throw(AipsError("Internal SVC::setSpecify(...) error: Got invalid VisCalEnum"));
1785 : break;
1786 : }
1787 : }
1788 0 : ctiter.paramErr(solveAllParErr());
1789 0 : ctiter.snr(solveAllParSNR());
1790 0 : solveAllParOK().assign(!ctiter.flag());
1791 :
1792 : // Advance iterator
1793 0 : ctiter.next();
1794 : }
1795 :
1796 : // Delete old mem caltable (it will be replaced)
1797 0 : if (ct_) delete ct_;
1798 0 : else throw(AipsError("SVC::setSpecify: unknown error on caltable delete"));
1799 0 : ct_=NULL;
1800 :
1801 0 : } // tableExists
1802 : else {
1803 :
1804 6 : nChanParList()=Vector<Int>(nSpw(),1);
1805 6 : startChanList()=Vector<Int>(nSpw(),0);
1806 :
1807 : // we are creating a table from scratch
1808 6 : logSink() << "Creating " << typeName()
1809 : << " table from specified parameters."
1810 6 : << LogIO::POST;
1811 :
1812 : // Size up the solve arrays
1813 6 : initSolvePar();
1814 :
1815 12 : for (Int ispw=0;ispw<nSpw();++ispw) {
1816 6 : currSpw()=ispw;
1817 6 : refTime()=0.0;
1818 6 : currField()=-1;
1819 6 : currScan()=-1;
1820 6 : currObs()=0;
1821 :
1822 6 : switch(parType()) {
1823 6 : case VisCalEnum::COMPLEX: {
1824 6 : solveAllCPar().set(defaultCPar());
1825 6 : break;
1826 : }
1827 0 : case VisCalEnum::REAL: {
1828 0 : solveAllRPar().set(defaultRPar());
1829 0 : break;
1830 : }
1831 0 : default: {
1832 0 : throw(AipsError("Internal SVC::setAccumulate(...) error: Got invalid VisCalEnum"));
1833 : }
1834 : }
1835 6 : solveAllParOK().set(true);
1836 6 : solveAllParSNR().set(1.0);
1837 6 : solveAllParErr().set(0.0);
1838 :
1839 : } // ispw
1840 : } // !tableExists
1841 :
1842 : // Create the caltable
1843 6 : createMemCalTable();
1844 :
1845 6 : }
1846 :
1847 18 : void SolvableVisCal::specify(const Record& specify) {
1848 :
1849 36 : LogMessage message(LogOrigin("SolvableVisCal","specify"));
1850 :
1851 18 : Vector<Int> spws;
1852 18 : Vector<Int> antennas;
1853 18 : Vector<Int> pols;
1854 18 : Vector<Double> parameters;
1855 :
1856 18 : Int nUserSpw(1);
1857 18 : Int Ntime(1);
1858 18 : Int Nant(0);
1859 18 : Int Npol(1);
1860 :
1861 18 : Bool repspw(false);
1862 :
1863 18 : IPosition ip0(3,0,0,0);
1864 18 : IPosition ip1(3,0,0,0);
1865 :
1866 18 : if (specify.isDefined("caltype")) {
1867 18 : String caltype=specify.asString("caltype");
1868 18 : logSink() << "Generating '" << caltype << "' corrections." << LogIO::POST;
1869 18 : if (upcase(caltype).contains("PH"))
1870 0 : apmode()="P";
1871 : else
1872 18 : apmode()="A";
1873 18 : }
1874 :
1875 : /*
1876 : if (specify.isDefined("time")) {
1877 : // TBD: the time label
1878 : cout << "time = " << specify.asString("time") << endl;
1879 : cout << "refTime() = " << refTime() << endl;
1880 : }
1881 : */
1882 : /**
1883 : if (specify.isDefined("time")) {
1884 : // TBD: the time label
1885 : //cout << "time = " << specify.asString("time") << endl;
1886 : cout << "refTime() = " << refTime() << endl;
1887 : currTime()=specify.asDouble("time");
1888 : }
1889 : **/
1890 :
1891 18 : if (specify.isDefined("spw")) {
1892 : // TBD: the spws (in order) identifying the solutions
1893 18 : spws=specify.asArrayInt("spw");
1894 18 : nUserSpw=spws.nelements();
1895 18 : if (nUserSpw<1) {
1896 : // None specified, so loop over all, repetitively
1897 : // (We ought to optimize this...)
1898 : logSink() <<
1899 : "Specified parameter(s) (per antenna and pol) repeated on all spws."
1900 0 : << LogIO::POST;
1901 0 : repspw=true;
1902 0 : nUserSpw=nSpw();
1903 0 : spws.resize(nUserSpw);
1904 0 : indgen(spws);
1905 : }
1906 : }
1907 :
1908 :
1909 18 : if (specify.isDefined("antenna")) {
1910 : // TBD: the antennas (in order) identifying the solutions
1911 18 : antennas=specify.asArrayInt("antenna");
1912 : // cout << "antenna indices = " << antennas << endl;
1913 18 : Nant=antennas.nelements();
1914 18 : if (Nant<1) {
1915 : // Use specified values for _all_ antennas implicitly
1916 : logSink() <<
1917 : "Specified parameter(s) (per spw and pol) repeated on all antennas."
1918 18 : << LogIO::POST;
1919 18 : Nant=1; // For the antenna loop below
1920 18 : ip0(2)=0;
1921 18 : ip1(2)=nAnt()-1;
1922 : }
1923 : else {
1924 : // Point to first antenna
1925 0 : ip0(2)=antennas(0);
1926 0 : ip1(2)=ip0(2);
1927 : }
1928 : }
1929 18 : if (specify.isDefined("pol")) {
1930 : // TBD: the pols (in order) identifying the solutions
1931 18 : String polstr=specify.asString("pol");
1932 : // cout << "pol = " << polstr << endl;
1933 18 : if (polstr=="R" || polstr=="X")
1934 : // Fill in only first pol
1935 0 : pols=Vector<Int>(1,0);
1936 18 : else if (polstr=="L" || polstr=="Y")
1937 : // Fill in only second pol
1938 0 : pols=Vector<Int>(1,1);
1939 18 : else if (polstr=="R,L" || polstr=="X,Y") {
1940 : // Fill in both pols explicity
1941 0 : pols=Vector<Int>(2,0);
1942 0 : pols(1)=1;
1943 : }
1944 18 : else if (polstr=="L,R" || polstr=="Y,X") {
1945 : // Fill in both pols explicity
1946 0 : pols=Vector<Int>(2,0);
1947 0 : pols(0)=1;
1948 : }
1949 18 : else if (polstr=="")
1950 : // Fill in both pols implicitly
1951 18 : pols=Vector<Int>();
1952 : else
1953 0 : throw(AipsError("Invalid pol specification"));
1954 :
1955 18 : Npol=pols.nelements();
1956 18 : if (Npol<1) {
1957 : // No pol axis specified
1958 : logSink() <<
1959 : "Specified parameter(s) (per spw and antenna) repeated on all polarizations."
1960 18 : << LogIO::POST;
1961 18 : Npol=1;
1962 18 : ip0(0)=0;
1963 18 : ip1(0)=nPar()-1;
1964 : }
1965 : else {
1966 : // Point to the first polarization
1967 0 : ip0(0)=pols(0);
1968 0 : ip1(0)=ip0(0);
1969 : }
1970 18 : }
1971 18 : if (specify.isDefined("parameter")) {
1972 : // TBD: the actual cal values
1973 18 : parameters=specify.asArrayDouble("parameter");
1974 : }
1975 18 : Int nparam=parameters.nelements();
1976 :
1977 : // Test for correct number of specified parameters
1978 : // Either all params are enumerated, or one is specified
1979 : // for all, [TBD:or a polarization pair is specified for all]
1980 : // else throw
1981 18 : if (nparam!=(repspw ? (Ntime*Nant*Npol) : (nUserSpw*Ntime*Nant*Npol)) &&
1982 : nparam!=1 ) // one for all
1983 : // (Npol==2 && nparam%2!=0) ) // poln pair for all
1984 0 : throw(AipsError("Inconsistent number of parameters specified."));
1985 :
1986 :
1987 : // Fill in user-specifed parameters in order
1988 18 : Int ipar(0);
1989 36 : for (Int iUspw=0;iUspw<nUserSpw;++iUspw) {
1990 :
1991 18 : currSpw()=spws(iUspw);
1992 :
1993 : // reset par index if we are repeating for all spws
1994 18 : if (repspw) ipar=0;
1995 :
1996 : // Loop over specified antennas
1997 36 : for (Int iant=0;iant<Nant;++iant) {
1998 18 : if (Nant>1)
1999 0 : ip1(2)=ip0(2)=antennas(iant);
2000 :
2001 : // Loop over specified polarizations
2002 36 : for (Int ipol=0;ipol<Npol;++ipol) {
2003 18 : if (Npol>1)
2004 0 : ip1(0)=ip0(0)=pols(ipol);
2005 :
2006 : // Report details as compactly as possible
2007 18 : if (!repspw || iUspw==0)
2008 : logSink() << "spwId="
2009 36 : << (repspw ? "<all>" : String::toString(currSpw()) )
2010 : << " antId="
2011 36 : << (antennas.nelements()>0 ? String::toString(antennas(iant)) : "<all>")
2012 : << " polId="
2013 36 : << (pols.nelements()>0 ? String::toString(pols(ipol)) : "<all>")
2014 36 : << " parameter= " << parameters(ipar)
2015 : << " (ip0,ip1 = " << ip0 << "," << ip1 << ")"
2016 72 : << LogIO::POST;
2017 :
2018 18 : switch(parType()) {
2019 18 : case VisCalEnum::COMPLEX: {
2020 18 : Array<Complex> sl(solveAllCPar()(ip0,ip1));
2021 : // Multiply ipar-th parameter onto the selecte slice
2022 18 : if (apmode()=="P") {
2023 : // Phases have been specified
2024 0 : Double phase=parameters(ipar)*M_PI/180.0;
2025 0 : sl*=Complex(cos(phase),sin(phase));
2026 : }
2027 : else
2028 : // Assume amplitude
2029 18 : sl*=Complex(parameters(ipar));
2030 18 : break;
2031 18 : }
2032 0 : case VisCalEnum::REAL: {
2033 : // Add ipar-th parameter onto the selected slice
2034 0 : Array<Float> sl(solveAllRPar()(ip0,ip1));
2035 0 : sl+=Float(parameters(ipar));
2036 0 : break;
2037 0 : }
2038 0 : default: {
2039 0 : throw(AipsError("Internal SVC::setAccumulate(...) error: Got invalid VisCalEnum"));
2040 : break;
2041 : }
2042 : }
2043 :
2044 : // increment ipar, but be sure not to run off the end
2045 18 : ++ipar;
2046 18 : ipar = ipar%nparam;
2047 :
2048 :
2049 : } // ipol
2050 : } // iant
2051 :
2052 : } // iUspw
2053 :
2054 :
2055 : // Now write keep _all_ spws
2056 36 : for (Int ispw=0;ispw<nSpw();++ispw) {
2057 : // Keep this result
2058 18 : currSpw()=ispw;
2059 18 : keepNCT();
2060 : }
2061 :
2062 18 : }
2063 :
2064 0 : Int SolvableVisCal::sizeUpSolve(VisSet& vs, Vector<Int>& nChunkPerSol) {
2065 :
2066 : // New version that counts solutions (which may overlap in
2067 : // field and/or ddid) rather than chunks
2068 :
2069 0 : Bool verby(false);
2070 :
2071 : // Set Nominal per-spw channelization
2072 0 : setSolveChannelization(vs);
2073 :
2074 0 : sortVisSet(vs, verby);
2075 :
2076 : // Number of VisIter chunks per spw
2077 0 : Vector<Int> nChunkPerSpw(vs.numberSpw(),0);
2078 :
2079 0 : Vector<Int> nSolPerSpw(vs.numberSpw(),0);
2080 :
2081 : // Number of VisIter chunks per solution
2082 0 : nChunkPerSol.resize(100);
2083 0 : nChunkPerSol=0;
2084 :
2085 0 : VisIter& vi(vs.iter());
2086 :
2087 : /*
2088 : Block< Vector<Int> > g,st,nch,icr,spw;
2089 : vi.getChannelSelection(g,st,nch,icr,spw);
2090 : for (uInt isel=0;isel<spw.nelements();++isel)
2091 : cout << isel << ":" << endl
2092 : << " " << "nGrp =" << g[isel]
2093 : << " " << "start=" << st[isel]
2094 : << " " << "nchan=" << nch[isel]
2095 : << " " << "icrem=" << icr[isel]
2096 : << " " << "spw =" << spw[isel]
2097 : << endl;
2098 : */
2099 :
2100 0 : VisBuffer vb(vi);
2101 0 : vi.originChunks();
2102 0 : vi.origin();
2103 :
2104 0 : Double time0(86400.0*floor(vb.time()(0)/86400.0));
2105 0 : Double time1(0.0),time(0.0);
2106 :
2107 0 : Int thisobs(-1),lastobs(-1);
2108 0 : Int thisscan(-1),lastscan(-1);
2109 0 : Int thisfld(-1),lastfld(-1);
2110 0 : Int thisspw(-1),lastspw(-1);
2111 0 : Int chunk(0);
2112 0 : Int sol(-1);
2113 0 : Double soltime1(-1.0);
2114 0 : for (vi.originChunks(); vi.moreChunks(); vi.nextChunk(),chunk++) {
2115 0 : vi.origin();
2116 0 : time1=vb.time()(0); // first time in this chunk
2117 0 : thisobs=vb.observationId()(0);
2118 0 : thisscan=vb.scan()(0);
2119 0 : thisfld=vb.fieldId();
2120 0 : thisspw=vb.spectralWindow();
2121 :
2122 0 : nChunkPerSpw(thisspw)++;
2123 :
2124 : // New chunk means new sol interval, IF....
2125 0 : if ( (!combfld() && !combspw()) || // not combing fld nor spw, OR
2126 0 : ((time1-soltime1)>interval()) || // (combing fld and/or spw) and solint exceeded, OR
2127 0 : ((time1-soltime1)<0.0) || // a negative time step occurs, OR
2128 0 : (!combobs() && (thisobs!=lastobs)) || // not combing obs, and new obs encountered OR
2129 0 : (!combscan() && (thisscan!=lastscan)) || // not combing scans, and new scan encountered OR
2130 0 : (!combspw() && (thisspw!=lastspw)) || // not combing spws, and new spw encountered OR
2131 0 : (!combfld() && (thisfld!=lastfld)) || // not combing fields, and new field encountered OR
2132 : (sol==-1)) { // this is the first interval
2133 0 : soltime1=time1;
2134 0 : sol++;
2135 :
2136 : // Increment solution count per spw
2137 0 : nSolPerSpw(thisspw)++;
2138 :
2139 0 : if (verby) {
2140 0 : cout << "--------------------------------" << endl;
2141 0 : cout << "sol = " << sol << endl;
2142 : }
2143 : // increase size of nChunkPerSol array, if needed
2144 0 : if (nChunkPerSol.nelements()<uInt(sol+1))
2145 0 : nChunkPerSol.resize(nChunkPerSol.nelements()+100,true);
2146 0 : nChunkPerSol(sol)=0;
2147 : }
2148 :
2149 : // Increment chunk-per-sol count for current solution
2150 0 : nChunkPerSol(sol)++;
2151 :
2152 0 : if (verby) {
2153 0 : cout << " ck=" << chunk << " " << soltime1-time0 << endl;
2154 :
2155 0 : Int iter(0);
2156 0 : for (vi.origin(); vi.more();vi++,iter++) {
2157 0 : time=vb.time()(0);
2158 0 : cout << " " << "vb=" << iter << " ";
2159 0 : cout << "ob=" << vb.observationId()(0) << " ";
2160 0 : cout << "ar=" << vb.arrayId() << " ";
2161 0 : cout << "ob=" << vb.observationId()(0) << " ";
2162 0 : cout << "sc=" << vb.scan()(0) << " ";
2163 0 : if (!combfld()) cout << "fl=" << vb.fieldId() << " ";
2164 0 : if (!combspw()) cout << "sp=" << vb.spectralWindow() << " ";
2165 0 : cout << "t=" << floor(time-time0) << " (" << floor(time-soltime1) << ") ";
2166 0 : if (combfld()) cout << "fl=" << vb.fieldId() << " ";
2167 0 : if (combspw()) cout << "sp=" << vb.spectralWindow() << " ";
2168 0 : cout << endl;
2169 : }
2170 : }
2171 :
2172 0 : lastobs=thisobs;
2173 0 : lastscan=thisscan;
2174 0 : lastfld=thisfld;
2175 0 : lastspw=thisspw;
2176 :
2177 : }
2178 :
2179 0 : if (verby) {
2180 0 : cout << "nSolPerSpw = " << nSolPerSpw << endl;
2181 0 : cout << "nChunkPerSpw = " << nChunkPerSpw << " " << sum(nChunkPerSpw) << endl;
2182 0 : cout << "nchunk = " << chunk << endl;
2183 : }
2184 :
2185 0 : Int nSol(sol+1);
2186 :
2187 0 : nChunkPerSol.resize(nSol,true);
2188 :
2189 0 : spwMap().resize(vs.numberSpw());
2190 0 : indgen(spwMap());
2191 0 : Vector<Int> spwlist=spwMap()(nChunkPerSpw>0).getCompressedArray();
2192 0 : Int spwlab=0;
2193 0 : if (combspw()) {
2194 0 : while (nChunkPerSpw(spwlab)<1) spwlab++;
2195 0 : if (verby) cout << "Obtaining " << nSol << " solutions, labelled as spw=" << spwlab << endl;
2196 0 : spwMap()=-1; // TBD: needed?
2197 0 : spwMap()(nChunkPerSpw>0)=spwlab;
2198 :
2199 0 : if (verby)
2200 0 : cout << "nChanParList = " << nChanParList()(nChunkPerSpw>0).getCompressedArray()
2201 0 : << "==" << nChanParList()(spwlab) << endl;
2202 :
2203 : // Verify that all spws have same number of channels (so they can be combined!)
2204 0 : if (!allEQ(nChanParList()(spwMap()>-1).getCompressedArray(),nChanParList()(spwlab)))
2205 0 : throw(AipsError("Spws with different selected channelizations cannot be combined."));
2206 :
2207 : // nChunkPerSpw = 0;
2208 : // nChunkPerSpw(spwlab)=nSol;
2209 :
2210 0 : nSolPerSpw=0;
2211 0 : nSolPerSpw(spwlab)=nSol;
2212 :
2213 : }
2214 :
2215 0 : if (verby) {
2216 0 : cout << " spwMap() = " << spwMap() << endl;
2217 0 : cout << " spwlist = " << spwlist << endl;
2218 0 : cout << "nSolPerSpw = " << nSolPerSpw << endl;
2219 0 : cout << "nChunkPerSpw = " << nChunkPerSpw << " " << sum(nChunkPerSpw) << endl;
2220 0 : cout << "Total solutions = " << nSol << endl;
2221 0 : cout << "nChunkPerSol = " << nChunkPerSol << endl;
2222 : }
2223 :
2224 0 : if (combobs())
2225 0 : logSink() << "Combining observation Ids." << LogIO::POST;
2226 0 : if (combscan())
2227 0 : logSink() << "Combining scans." << LogIO::POST;
2228 0 : if (combspw())
2229 0 : logSink() << "Combining spws: " << spwlist << " -> " << spwlab << LogIO::POST;
2230 0 : if (combfld())
2231 0 : logSink() << "Combining fields." << LogIO::POST;
2232 :
2233 :
2234 : //if (!isSimulated()) {
2235 0 : logSink() << "For solint = " << solint() << ", found "
2236 : << nSol << " solution intervals."
2237 0 : << LogIO::POST;
2238 : //}
2239 :
2240 : // Size the solvePar arrays
2241 0 : initSolvePar();
2242 :
2243 : // Return the total number of solution intervals
2244 0 : return nSol;
2245 :
2246 0 : }
2247 :
2248 0 : void SolvableVisCal::sortVisSet(VisSet& vs, const Bool verbose)
2249 : {
2250 : // Interpret solution interval for the VisIter
2251 0 : Double iterInterval(max(interval(),DBL_MIN));
2252 0 : if (interval() < 0.0) { // means no interval (infinite solint)
2253 0 : iterInterval=0.0;
2254 0 : interval()=DBL_MAX;
2255 : }
2256 :
2257 0 : if (verbose) {
2258 0 : cout << " interval() = " << interval() ;
2259 0 : cout << boolalpha << " combobs() = " << combobs();
2260 0 : cout << boolalpha << " combscan() = " << combscan();
2261 0 : cout << boolalpha << " combfld() = " << combfld() ;
2262 0 : cout << boolalpha << " combspw() = " << combspw() ;
2263 : }
2264 :
2265 0 : Int nsortcol(4+(combscan()?0:1)+(combobs()?0:1) ); // include room for scan,obs
2266 0 : Block<Int> columns(nsortcol);
2267 0 : Int i(0);
2268 0 : columns[i++]=MS::ARRAY_ID;
2269 0 : if (!combobs()) columns[i++]=MS::OBSERVATION_ID; // force obsid boundaries
2270 0 : if (!combscan()) columns[i++]=MS::SCAN_NUMBER; // force scan boundaries
2271 0 : if (!combfld()) columns[i++]=MS::FIELD_ID; // force field boundaries
2272 0 : if (!combspw()) columns[i++]=MS::DATA_DESC_ID; // force spw boundaries
2273 0 : columns[i++]=MS::TIME;
2274 0 : if (combspw() || combfld()) iterInterval=DBL_MIN; // force per-timestamp chunks
2275 0 : if (combfld()) columns[i++]=MS::FIELD_ID; // effectively ignore field boundaries
2276 0 : if (combspw()) columns[i++]=MS::DATA_DESC_ID; // effectively ignore spw boundaries
2277 :
2278 0 : if (verbose) {
2279 0 : cout << " sort columns: ";
2280 0 : for (Int i=0;i<nsortcol;++i)
2281 0 : cout << columns[i] << " ";
2282 0 : cout << endl;
2283 : }
2284 :
2285 : // this sets the vi to send chunks by iterInterval (e.g. integration time)
2286 : // instead of default which would go until the scan changed
2287 0 : vs.resetVisIter(columns,iterInterval);
2288 0 : }
2289 :
2290 0 : Int SolvableVisCal::sizeUpSim(VisSet& vs, Vector<Int>& nChunkPerSol, Vector<Double>& solTimes) {
2291 :
2292 : // New version that counts solutions (which may overlap in
2293 : // field and/or ddid) rather than chunks
2294 0 : LogIO os(LogOrigin("SVC", "sizeUpSim()", WHERE));
2295 :
2296 0 : if (prtlev()>2) cout << " SVC::sizeUpSim" << endl;
2297 :
2298 0 : sortVisSet(vs, prtlev() > 2);
2299 :
2300 0 : VisIter& vi(vs.iter());
2301 0 : vi.originChunks();
2302 0 : vi.origin();
2303 0 : VisBuffer vb(vi);
2304 :
2305 : // Number of VisIter chunks per spw
2306 0 : Vector<Int> nChunkPerSpw(vs.numberSpw(),0);
2307 :
2308 0 : Int nSol(1);
2309 :
2310 0 : if (simOnTheFly()) {
2311 0 : nChunkPerSol.resize(1);
2312 0 : nChunkPerSol=1;
2313 :
2314 0 : vi.origin();
2315 0 : solTimes.resize(1);
2316 0 : solTimes(0)=vb.time()(0); // first time in this chunk
2317 :
2318 : } else {
2319 :
2320 :
2321 : // Number of VisIter chunks per solution
2322 0 : nChunkPerSol.resize(100);
2323 0 : nChunkPerSol=0;
2324 :
2325 0 : Double time0(86400.0*floor(vb.time()(0)/86400.0));
2326 0 : Double time1(0.0),time(0.0);
2327 :
2328 0 : Int thisscan(-1),lastscan(-1);
2329 0 : Int thisfld(-1),lastfld(-1);
2330 0 : Int thisspw(-1),lastspw(-1);
2331 0 : Int chunk(0);
2332 0 : Int sol(-1);
2333 0 : Double soltime1(-1.0);
2334 0 : for (vi.originChunks(); vi.moreChunks(); vi.nextChunk(),chunk++) {
2335 0 : vi.origin();
2336 0 : time1=vb.time()(0); // first time in this chunk
2337 0 : thisscan=vb.scan()(0);
2338 0 : thisfld=vb.fieldId();
2339 0 : thisspw=vb.spectralWindow();
2340 :
2341 0 : nChunkPerSpw(thisspw)++;
2342 :
2343 : // New chunk means new sol interval, IF....
2344 0 : if ( (!combfld() && !combspw()) || // not combing fld nor spw, OR
2345 0 : ((time1-soltime1)>interval()) || // (combing fld and/or spw) and solint exceeded, OR
2346 0 : ((time1-soltime1)<0.0) || // a negative time step occurs, OR
2347 0 : (!combscan() && (thisscan!=lastscan)) || // not combing scans, and new scan encountered OR
2348 0 : (!combspw() && (thisspw!=lastspw)) || // not combing spws, and new spw encountered OR
2349 0 : (!combfld() && (thisfld!=lastfld)) || // not combing fields, and new field encountered OR
2350 : (sol==-1)) { // this is the first interval
2351 0 : soltime1=time1;
2352 0 : sol++;
2353 0 : if (prtlev()>5) {
2354 0 : cout << "--------------------------------" << endl;
2355 0 : cout << " sol = " << sol << endl;
2356 : }
2357 : // increase size of nChunkPerSol array, if needed
2358 0 : if (nChunkPerSol.nelements()<uInt(sol+1))
2359 0 : nChunkPerSol.resize(nChunkPerSol.nelements()+100,true);
2360 0 : nChunkPerSol(sol)=0;
2361 : // keep the times!
2362 0 : if (solTimes.nelements()<uInt(sol+1))
2363 0 : solTimes.resize(solTimes.nelements()+100,true);
2364 0 : solTimes(sol)=soltime1;
2365 : }
2366 :
2367 : // Increment chunk-per-sol count for current solution
2368 0 : nChunkPerSol(sol)++;
2369 :
2370 0 : if (prtlev()>5) {
2371 0 : cout << " ck=" << chunk << " " << soltime1-time0 << endl;
2372 :
2373 0 : Int iter(0);
2374 0 : for (vi.origin(); vi.more();vi++,iter++) {
2375 0 : time=vb.time()(0);
2376 0 : cout << " " << "vb=" << iter << " ";
2377 0 : cout << "ar=" << vb.arrayId() << " ";
2378 0 : cout << "sc=" << vb.scan()(0) << " ";
2379 0 : if (!combfld()) cout << "fl=" << vb.fieldId() << " ";
2380 0 : if (!combspw()) cout << "sp=" << vb.spectralWindow() << " ";
2381 0 : cout << "t=" << floor(time-time0) << " (" << floor(time-soltime1) << ") ";
2382 0 : if (combfld()) cout << "fl=" << vb.fieldId() << " ";
2383 0 : if (combspw()) cout << "sp=" << vb.spectralWindow() << " ";
2384 0 : cout << endl;
2385 : }
2386 : }
2387 :
2388 0 : lastscan=thisscan;
2389 0 : lastfld=thisfld;
2390 0 : lastspw=thisspw;
2391 :
2392 : }
2393 :
2394 0 : nSol = sol+1;
2395 :
2396 0 : nChunkPerSol.resize(nSol,true);
2397 0 : solTimes.resize(nSol,true);
2398 :
2399 0 : if (prtlev()>5) {
2400 0 : cout << " solTimes = " << solTimes-solTimes[0] << endl;
2401 0 : cout << " nChunkPerSol = " << nChunkPerSol << " " << sum(nChunkPerSol) << endl;
2402 : }
2403 : } // if not inTheFly
2404 :
2405 : // Set Nominal per-spw channelization - this does set chanParList to full
2406 : // # chans
2407 0 : setSolveChannelization(vs);
2408 0 : if (prtlev()>3) cout<<" freqDepPar="<<freqDepPar()<<endl;
2409 0 : if (prtlev()>2) cout<<" nSpw()="<<nSpw()
2410 0 : <<" nPar()="<<nPar()<<" nChanParList="<<nChanParList()
2411 0 : <<" nElem()="<<nElem()<<" nSol="<<nSol
2412 0 : <<" approx size = "<<(nSpw()*(nChanParList().size())*nElem()*nSol*nPar())
2413 0 : <<"x size(complex)"<<endl;
2414 :
2415 0 : if (not simOnTheFly()) {
2416 :
2417 0 : if (ct_)
2418 0 : delete ct_;
2419 :
2420 : // Make a caltable into which simulated solutions will be deposited
2421 : // !freqDepPar controls channelization in SPW subtable (T == single channel)
2422 0 : ct_=new NewCalTable(calTableName()+"_sim_temp",parType(),typeName(),msName(),!freqDepPar());
2423 :
2424 : }
2425 :
2426 :
2427 0 : spwMap().resize(vs.numberSpw());
2428 0 : indgen(spwMap());
2429 0 : Vector<Int> spwlist=spwMap()(nChunkPerSpw>0).getCompressedArray();
2430 0 : Int spwlab=0;
2431 0 : if (combspw()) {
2432 0 : while (nChunkPerSpw(spwlab)<1) spwlab++;
2433 0 : if (prtlev()>2) cout << " obtaining " << nSol << " solutions, labelled as spw=" << spwlab << endl;
2434 0 : spwMap()=-1; // TBD: needed?
2435 0 : spwMap()(nChunkPerSpw>0)=spwlab;
2436 :
2437 0 : if (prtlev()>2)
2438 0 : cout << " nChanParList = " << nChanParList()(nChunkPerSpw>0).getCompressedArray()
2439 0 : << "==" << nChanParList()(spwlab) << endl;
2440 :
2441 : // Verify that all spws have same number of channels (so they can be combined!)
2442 0 : if (!allEQ(nChanParList()(spwMap()>-1).getCompressedArray(),nChanParList()(spwlab)))
2443 0 : throw(AipsError("Spws with different selected channelizations cannot be combined."));
2444 :
2445 0 : nChunkPerSpw = 0;
2446 0 : nChunkPerSpw(spwlab)=nSol;
2447 : }
2448 :
2449 0 : if (prtlev()>2) {
2450 0 : cout << " spwMap() = " << spwMap() ;
2451 0 : cout << " spwlist = " << spwlist ;
2452 0 : cout << " nChunkPerSpw = " << nChunkPerSpw << " " << sum(nChunkPerSpw) << " = " << nSol << endl;
2453 : //cout << "Total solutions = " << nSol << endl;
2454 : }
2455 0 : if (prtlev()>5)
2456 0 : cout << " nChunkPerSim = " << nChunkPerSol << endl;
2457 :
2458 :
2459 0 : if (combscan())
2460 0 : os << "Combining scans." << LogIO::POST;
2461 0 : if (combspw())
2462 0 : os << "Combining spws: " << spwlist << " -> " << spwlab << LogIO::POST;
2463 0 : if (combfld())
2464 0 : os << "Combining fields." << LogIO::POST;
2465 :
2466 0 : os << "For simint = " << simint() << ", found "
2467 : << nSol << " solution intervals."
2468 0 : << LogIO::POST;
2469 :
2470 : // Size the solvePar arrays
2471 : // Jones' insists on having 1 channel, but mullers have lots.
2472 : // initSolvePar();
2473 : // so i have to copy this from initsolvepar and make it all chans
2474 :
2475 0 : for (Int ispw=0;ispw<nSpw();++ispw) {
2476 :
2477 0 : currSpw()=ispw;
2478 :
2479 0 : switch(parType())
2480 : {
2481 0 : case VisCalEnum::COMPLEX:
2482 : {
2483 0 : os << LogIO::DEBUG1 << "spw " << currSpw()
2484 0 : << " nPar=" << nPar() << "nChanPar=" << nChanPar()
2485 0 : << " nElem=" << nElem() << LogIO::POST;
2486 :
2487 0 : solveCPar().resize(nPar(),nChanPar(),nElem());
2488 0 : solveParOK().resize(nPar(),nChanPar(),nElem());
2489 0 : solveParErr().resize(nPar(),nChanPar(),nElem());
2490 0 : solveParSNR().resize(nPar(),nChanPar(),nElem());
2491 :
2492 0 : solveCPar()=Complex(1.0);
2493 0 : solveParOK()=true;
2494 0 : solveParErr()=0.0;
2495 0 : solveParSNR()=0.0;
2496 0 : break;
2497 : }
2498 0 : case VisCalEnum::REAL:
2499 : {
2500 0 : solveRPar().resize(nPar(),nChanPar(),nElem());
2501 0 : solveParOK().resize(nPar(),nChanPar(),nElem());
2502 0 : solveParErr().resize(nPar(),nChanPar(),nElem());
2503 0 : solveParSNR().resize(nPar(),nChanPar(),nElem());
2504 :
2505 0 : solveRPar()=0.0;
2506 0 : solveParOK()=true;
2507 0 : solveParErr()=0.0;
2508 0 : solveParSNR()=0.0;
2509 0 : break;
2510 : }
2511 0 : case VisCalEnum::COMPLEXREAL:
2512 0 : throw(AipsError("Internal error(Calibrater Module): Unsupported parameter type COMPLEXREAL found"));
2513 : break;
2514 : }
2515 : }
2516 :
2517 :
2518 0 : if (not simOnTheFly()) {
2519 : os << LogIO::DEBUG1
2520 : // << "calset shape = " << cs().shape(0)
2521 0 : << " solveCPar shape = " << solveCPar().shape()
2522 0 : << LogIO::POST;
2523 : }
2524 :
2525 0 : if (prtlev()>2) cout << " ~SVC::sizeUpSim" << endl;
2526 :
2527 : // Return the total number of solution intervals
2528 0 : return nSol;
2529 :
2530 0 : }
2531 :
2532 : // VI2-related refactorings------------------
2533 :
2534 225 : void SolvableVisCal::setMeta(Int obs, Int scan, Double time,
2535 : Int spw, const Vector<Double>& freq,
2536 : Int fld) {
2537 :
2538 225 : VisCal::setMeta(obs,scan,time,spw,freq,fld);
2539 :
2540 225 : refTime()=time; // current time for solving is _refTime()_
2541 :
2542 : // refFreq()=???
2543 :
2544 225 : }
2545 :
2546 :
2547 : // Setup solvePar shape for a spw
2548 225 : Int SolvableVisCal::sizeSolveParCurrSpw(Int nVisChan) {
2549 :
2550 : // Sizes the solvePar arrays for the currSpw()
2551 :
2552 225 : if (prtlev()>3) cout << " SVJ::sizeSolveParCurrSpw()" << endl;
2553 :
2554 : // Use nVisChan only for freqDepPar() types
2555 225 : Int nChan = ( freqDepPar() ? nVisChan : 1);
2556 :
2557 : // Keep old way informed (needed?)
2558 225 : nChanPar()=nChan;
2559 :
2560 : // Now, size the arrays:
2561 :
2562 225 : IPosition parsh(3,nPar(),nChan,nElem()); // multi-chan
2563 225 : IPosition parsh1(3,nPar(),1,nElem()); // single-chan
2564 225 : switch (parType()) {
2565 0 : case VisCalEnum::COMPLEX: {
2566 0 : solveAllCPar().resize(parsh);
2567 0 : solveAllCPar()=Complex(1.0);
2568 0 : if (nChan==1)
2569 0 : solveCPar().reference(solveAllCPar());
2570 : else {
2571 0 : solveCPar().resize(parsh1);
2572 0 : solveCPar()=Complex(1.0);
2573 : }
2574 0 : break;
2575 : }
2576 225 : case VisCalEnum::REAL: {
2577 225 : solveAllRPar().resize(parsh);
2578 225 : solveAllRPar()=0.0;
2579 225 : if (nChanPar()==1)
2580 225 : solveRPar().reference(solveAllRPar());
2581 : else {
2582 0 : solveRPar().resize(parsh1);
2583 0 : solveRPar()=0.0;
2584 : }
2585 225 : break;
2586 : }
2587 0 : default:
2588 0 : throw(AipsError("Internal error(Calibrater Module): Unsupported parameter type "
2589 0 : "COMPLEXREAL found in SVC::sizeSolveParCurrSpw"));
2590 : }
2591 :
2592 225 : solveAllParOK().resize(parsh);
2593 225 : solveAllParErr().resize(parsh);
2594 225 : solveAllParSNR().resize(parsh);
2595 225 : solveAllParOK()=True;
2596 225 : solveAllParErr()=0.0;
2597 225 : solveAllParSNR()=0.0;
2598 225 : if (nChan==1) {
2599 225 : solveParOK().reference(solveAllParOK());
2600 225 : solveParErr().reference(solveAllParErr());
2601 225 : solveParSNR().reference(solveAllParSNR());
2602 : }
2603 : else {
2604 : // solving many channels, one at a time
2605 0 : solveParOK().resize(parsh1);
2606 0 : solveParErr().resize(parsh1);
2607 0 : solveParSNR().resize(parsh1);
2608 0 : solveParOK()=True;
2609 0 : solveParErr()=0.0;
2610 0 : solveParSNR()=0.0;
2611 : }
2612 :
2613 : // return the realized nChan
2614 225 : return nChan;
2615 :
2616 225 : }
2617 :
2618 0 : void SolvableVisCal::setDefSolveParCurrSpw(Bool sync) {
2619 :
2620 : // TBD: generalize for type-dep def values, etc.
2621 :
2622 0 : switch (parType()) {
2623 0 : case VisCalEnum::COMPLEX: {
2624 0 : AlwaysAssert(solveCPar().nelements()>0,AipsError);
2625 0 : solveCPar().set(1.0); // def=1+0j
2626 0 : break;
2627 : }
2628 0 : case VisCalEnum::REAL: {
2629 0 : AlwaysAssert(solveRPar().nelements()>0,AipsError);
2630 0 : solveRPar().set(0.0); // def=0
2631 0 : break;
2632 : }
2633 0 : default:
2634 0 : throw(AipsError("Internal error(Calibrater Module): Unsupported parameter type "
2635 0 : "COMPLEXREAL found in SVC::setDefSolveParCurrSpw"));
2636 : }
2637 0 : solveParOK().set(True);
2638 :
2639 0 : if (sync)
2640 0 : syncSolveCal();
2641 :
2642 0 : }
2643 :
2644 : // Parse solint in VI2 context
2645 32 : void SolvableVisCal::reParseSolintForVI2() {
2646 :
2647 : // Internal default solint
2648 32 : solint()="inf";
2649 32 : fsolint()="none";
2650 32 : if (usolint_.contains(',')) {
2651 : // both time and freq solint specified
2652 0 : solint()=usolint_.before(',');
2653 0 : fsolint()=usolint_.after(',');
2654 : }
2655 : else
2656 : // interpret as only time-dep solint
2657 32 : solint()=usolint_;
2658 :
2659 : // solint is always "int" for single dish calibration
2660 32 : if (longTypeName().startsWith("SDGAIN_OTFD")) {
2661 : //return;
2662 0 : solint() = "int";
2663 : }
2664 :
2665 : // Handle solint format
2666 32 : if (upcase(solint()).contains("INF") || solint()=="") {
2667 30 : solint()="inf";
2668 30 : solTimeInterval_=DBL_MAX;
2669 : }
2670 2 : else if (upcase(solint()).contains("INT"))
2671 0 : solTimeInterval_=FLT_MIN; // implausibly small; forces chunk boundaries at integrations
2672 : else {
2673 2 : QuantumHolder qhsolint;
2674 2 : String error;
2675 2 : Quantity qsolint;
2676 2 : qhsolint.fromString(error,solint());
2677 2 : if (error.length()!=0)
2678 0 : throw(AipsError("Unrecognized units for time-dep solint."));
2679 2 : qsolint=qhsolint.asQuantumDouble();
2680 :
2681 2 : if (qsolint.isConform("s"))
2682 0 : solTimeInterval_=qsolint.get("s").getValue();
2683 : else {
2684 2 : if (qsolint.getUnit().length()==0) {
2685 : // when no units specified, assume seconds
2686 2 : solTimeInterval_=qsolint.getValue();
2687 2 : solint()=solint()+"s";
2688 : }
2689 : else
2690 : // unrecognized units:
2691 0 : throw(AipsError("Unrecognized units for solint (e.g., use 'min', not 'm', for minutes)"));
2692 : }
2693 2 : }
2694 :
2695 : // cout << "******* VI2: Review fsolint parsing..." << endl;
2696 :
2697 : // Maybe should just parse it, and then work out logic re freqDepPar, etc.
2698 :
2699 : // Handle fsolint format
2700 : // TBD: compare to logic in Calibrater::genericGatherAndSolve (line ~2298)
2701 32 : if (upcase(fsolint()).contains("NONE") || // unspecified OR
2702 0 : !freqDepMat()) { // cal is entirely unchannelizedb
2703 32 : fsolint()="none";
2704 32 : fintervalCh_.set(-1.0); // signals full averaging (this is different from old way)
2705 32 : fintervalHz_=-1.0; // don't care
2706 : }
2707 : else {
2708 : // something specified OR freqDepMat
2709 : // if pars are freq-dep, specification indicates desired soln resolution
2710 0 : if (freqDepPar()) {
2711 : // Try to parse it
2712 0 : if (upcase(fsolint()).contains("CH")) {
2713 0 : String fsolintstr=upcase(fsolint());
2714 0 : fintervalCh_.set(String::toDouble(upcase(fsolint()).before("CH")));
2715 0 : fintervalHz_=-1.0; // Don't know in Hz, and don't really care
2716 0 : fsolint()=downcase(fsolint());
2717 0 : }
2718 : else {
2719 0 : QuantumHolder qhFsolint;
2720 0 : String error;
2721 0 : qhFsolint.fromString(error,fsolint());
2722 0 : if (error.length()!=0)
2723 0 : throw(AipsError("Unrecognized units for freq-dep solint."));
2724 0 : Quantity qFsolint;
2725 0 : qFsolint=qhFsolint.asQuantumDouble();
2726 :
2727 0 : if (qFsolint.isConform("Hz")) {
2728 0 : fintervalHz_=qFsolint.get("Hz").getValue();
2729 0 : convertHzToCh();
2730 : }
2731 : else {
2732 0 : if (qFsolint.getUnit().length()==0) {
2733 : // when no units specified, assume channel
2734 0 : fintervalCh_.set(qFsolint.getValue());
2735 0 : fsolint()=fsolint()+"ch";
2736 : }
2737 : else
2738 : // unrecognized units:
2739 0 : throw(AipsError("Unrecognized units for freq-dep solint"));
2740 : } // Hz vs. Ch via Quantum
2741 0 : } // parse by Quantum
2742 : } // freqDepPar
2743 : } // user set something
2744 : /*
2745 : cout << "Freq-dep solint: " << fsolint()
2746 : << " Ch=" << fintervalCh_
2747 : << " Hz=" << fintervalHz()
2748 : << endl;
2749 : //*/
2750 :
2751 32 : }
2752 :
2753 :
2754 : // Generate the in-memory caltable (empty)
2755 : // NB: no subtable revisions
2756 31 : void SolvableVisCal::createMemCalTable2() {
2757 :
2758 : // cout << "createMemCalTable" << endl;
2759 :
2760 : // Set up description
2761 31 : String partype = ((parType()==VisCalEnum::COMPLEX) ? "Complex" : "Float");
2762 62 : CTDesc caltabdesc(partype,Path(msName()).baseName(),typeName(),"unknown");
2763 31 : ct_ = new NewCalTable("tempNCT.tab",caltabdesc,Table::Scratch,Table::Memory);
2764 :
2765 31 : if (msmc().msOk())
2766 31 : ct_->setMetaInfo(msName());
2767 : else {
2768 0 : ct_->fillGenericObs(1);
2769 0 : ct_->fillGenericField(msmc().nFld());
2770 0 : ct_->fillGenericAntenna(msmc().nAnt());
2771 0 : Vector<Int> nchan(msmc().nSpw(),1);
2772 0 : ct_->fillGenericSpw(msmc().nSpw(),nchan);
2773 0 : }
2774 :
2775 : // Flag all SPW subtable rows; we'll set them OTF
2776 31 : CTColumns ncc(*ct_);
2777 :
2778 : // Set FLAG_ROW in SPW subtable
2779 31 : Vector<Bool> flr=ncc.spectralWindow().flagRow().getColumn();
2780 31 : flr.set(True);
2781 31 : ncc.spectralWindow().flagRow().putColumn(flr);
2782 :
2783 : // Collapse channel axis info in all rows for unchan'd
2784 : // calibration, so columns are "clean" (uniform shape)
2785 : // NB: some of this info will be revised during data iteration
2786 31 : CTSpWindowColumns& spwcol(ncc.spectralWindow());
2787 31 : if (!freqDepPar()) {
2788 31 : Int nspw=ncc.spectralWindow().nrow();
2789 155 : for (Int ispw=0;ispw<nspw;++ispw) {
2790 124 : Vector<Double> chfr,chwid,chres,cheff;
2791 :
2792 124 : spwcol.chanFreq().get(ispw,chfr);
2793 124 : spwcol.chanWidth().get(ispw,chwid);
2794 124 : spwcol.resolution().get(ispw,chres);
2795 124 : spwcol.effectiveBW().get(ispw,cheff);
2796 :
2797 124 : spwcol.chanFreq().put(ispw,Vector<Double>(1,mean(chfr)));
2798 124 : spwcol.chanWidth().put(ispw,Vector<Double>(1,sum(chwid)));
2799 124 : spwcol.resolution().put(ispw,Vector<Double>(1,sum(chres)));
2800 124 : spwcol.effectiveBW().put(ispw,Vector<Double>(1,sum(cheff)));
2801 124 : }
2802 :
2803 : // One channel per spw
2804 31 : spwcol.numChan().putColumn(Vector<Int>(nspw,1));
2805 : }
2806 :
2807 31 : }
2808 :
2809 0 : void SolvableVisCal::setOrVerifyCTFrequencies(Int spw) {
2810 :
2811 : // cout << "SVC::setOrVerifyCTFrequencies......." << endl;
2812 :
2813 :
2814 : // Assumes currFreq() is set properly (see syncSolveMeta)
2815 :
2816 : // Access SPW subtable columns
2817 0 : CTColumns ctcol(*ct_);
2818 0 : CTSpWindowColumns& spwcol(ctcol.spectralWindow());
2819 :
2820 : // If row is flagged, then it hasn't been set yet...
2821 0 : Bool needToSet(spwcol.flagRow().get(spw));
2822 :
2823 : // How many solution channels?
2824 0 : Int nChan=currFreq().nelements();
2825 :
2826 0 : Vector<Double> currFreqHz;
2827 0 : currFreqHz.assign(currFreq()); // currFreq is in GHz!!
2828 0 : currFreqHz*=1e9; // currFreqHz is in Hz
2829 :
2830 0 : if (needToSet) {
2831 :
2832 : //cout << "Setting freqs in spw=" << spw << endl;
2833 :
2834 : // Existing values (from the _unaveraged_ MS)
2835 0 : Vector<Double> chfr,chwid,chres,cheff;
2836 : Double totbw;
2837 0 : spwcol.chanFreq().get(spw,chfr);
2838 0 : spwcol.chanWidth().get(spw,chwid);
2839 0 : spwcol.resolution().get(spw,chres);
2840 0 : spwcol.effectiveBW().get(spw,cheff);
2841 0 : totbw=spwcol.totalBandwidth().get(spw);
2842 :
2843 : // Setup freq info for caltable accordingly
2844 0 : if (nChan>1) {
2845 : // Incoming data is channelized...
2846 0 : Double df=currFreqHz(1)-currFreqHz(0); // apparent width
2847 0 : totbw=(currFreqHz(nChan-1)-currFreqHz(0))+df; // total span (ignoring gaps!)
2848 0 : if (freqDepPar()) {
2849 : // solution is channelized
2850 :
2851 : // Assumes uniform width
2852 : // TBD: do better job here for quirky non-gridded cases!
2853 0 : chfr.resize(nChan); chfr.assign(currFreqHz);
2854 0 : chwid.resize(nChan); chwid.set(df);
2855 0 : chres.resize(nChan); chres.set(df);
2856 0 : cheff.resize(nChan); cheff.set(df);
2857 : }
2858 : else {
2859 : // Data channelized, but solution is not (e.g., delays)
2860 0 : chfr.resize(1); chfr.set(mean(currFreqHz)); // The ~centroid freq
2861 0 : chwid.resize(1); chwid.set(totbw);
2862 0 : chres.resize(1); chres.set(totbw);
2863 0 : cheff.resize(1); cheff.set(totbw);
2864 : }
2865 : }
2866 : else {
2867 : // Incoming data has only one channel
2868 :
2869 : // Assume full collapse of existing freq axis
2870 : // NB: Using UN-SELECTED MS total bandwidth here!!
2871 : // TBD: this is wrong for partially selected channels....
2872 0 : AlwaysAssert(currFreqHz.nelements()==1,AipsError);
2873 0 : chfr.resize(1); chfr.assign(currFreqHz);
2874 0 : chwid.resize(1); chwid.set(totbw);
2875 0 : chres.resize(1); chres.set(totbw);
2876 0 : cheff.resize(1); cheff.set(totbw);
2877 : }
2878 :
2879 : // Export revised values to the table
2880 0 : spwcol.chanFreq().put(spw,chfr);
2881 0 : spwcol.chanWidth().put(spw,chwid);
2882 0 : spwcol.resolution().put(spw,chres);
2883 0 : spwcol.effectiveBW().put(spw,cheff);
2884 0 : spwcol.numChan().put(spw,(freqDepPar()?nChan:1)); // handles unchan'd par case
2885 0 : spwcol.totalBandwidth().put(spw,totbw);
2886 0 : spwcol.flagRow().put(spw,False);
2887 :
2888 0 : }
2889 : else {
2890 : // Only verify that freqs haven't changed
2891 :
2892 : //cout << "Verifying freqs in spw=" << spw << endl;
2893 :
2894 0 : Vector<Double> currCTFreq;
2895 0 : spwcol.chanFreq().get(spw,currCTFreq);
2896 :
2897 :
2898 0 : if (!freqDepPar()) {
2899 0 : Double currFreqHz1=mean(currFreqHz);
2900 0 : currFreqHz.resize(1);
2901 0 : currFreqHz.set(currFreqHz1);
2902 : }
2903 :
2904 0 : Vector<Float> fcurrCTFreq(currCTFreq.size());
2905 0 : for (size_t i=0; i!=currCTFreq.size(); i++) {
2906 0 : fcurrCTFreq[i] = float(currCTFreq[i]);
2907 : }
2908 0 : Vector<Float> fcurrFreqHz(currFreqHz.size());
2909 0 : for (size_t i=0; i!=currCTFreq.size(); i++) {
2910 0 : fcurrFreqHz[i] = float(currFreqHz[i]);
2911 : }
2912 :
2913 : // cout << "Diff (currFreqHz) = " << (currFreqHz - fcurrFreqHz) << endl;
2914 : // cout << "Diff (currCTFreq) = " << (currCTFreq - fcurrCTFreq) << endl;
2915 : // cout << "currFreqHz = " << currFreqHz << endl;
2916 : // cout << "fcurrFreqHz = " << fcurrFreqHz << endl;
2917 : // cout << "currCTFreq = " << currCTFreq << endl;
2918 : // cout << "fcurrCTFreq = " << fcurrCTFreq << endl;
2919 :
2920 :
2921 : // if (!allEQ(float(currCTFreq),float(currFreqHz))) {
2922 0 : if (!allEQ(fcurrCTFreq,fcurrFreqHz)) {
2923 0 : cout << "For spw=" << spw << ":" << endl;
2924 0 : cout << "Current CalTable nchan= " << currCTFreq.nelements() << endl;
2925 0 : cout << "Current CalTable freq = " << currCTFreq << endl;
2926 0 : cout << "Current Solution nchan= " << (freqDepPar() ? nChan : 1) << endl;
2927 0 : cout << "Current Solution freq = " << currFreqHz << endl;
2928 0 : cout << "Diff = " << currFreqHz-currCTFreq << endl;
2929 :
2930 :
2931 0 : throw(AipsError("Mismatch between Solution frequencies and existing CalTable frequencies for spw="+String::toString(spw)));
2932 : }
2933 0 : }
2934 0 : }
2935 :
2936 225 : void SolvableVisCal::setCTFrequencies(Int spw) {
2937 :
2938 : // cout << "SVC::setCTFrequencies......." << endl;
2939 :
2940 :
2941 : // Discern spw to which to write
2942 225 : Int outspw=spw;
2943 : // If combining spws, freqMetaData_ knows the fan-in
2944 225 : if (combspw())
2945 4 : outspw=freqMetaData_.fannedInSpw(spw);
2946 :
2947 : // Access SPW subtable columns
2948 225 : CTColumns ctcol(*ct_);
2949 225 : CTSpWindowColumns& spwcol(ctcol.spectralWindow());
2950 :
2951 : // If row is flagged, then it hasn't been set yet (in this execution or any prior)
2952 225 : Bool needToSet(spwcol.flagRow().get(outspw));
2953 :
2954 :
2955 : // cout << "needToSet = " << boolalpha << needToSet << endl;
2956 :
2957 :
2958 225 : if (needToSet) {
2959 :
2960 : //cout << "Setting freqs for spw=" << outspw << endl;
2961 :
2962 : // const references to freq info from freqMetaData_
2963 94 : const Vector<Double>& chfr(freqMetaData_.freq(outspw));
2964 94 : const Vector<Double>& chwid(freqMetaData_.width(outspw));
2965 94 : const Vector<Double>& cheff(freqMetaData_.effBW(outspw));
2966 :
2967 : // Derived info
2968 94 : const Vector<Double>& chres(chfr); // resolution same as freq
2969 94 : Int numChan=chfr.nelements();
2970 94 : Double totbw=sum(chfr);
2971 :
2972 : // TBD: add some sanity checks, e.g., numChan==1 if !freqDepPar, etc.
2973 :
2974 : // Set freq info in the table
2975 94 : spwcol.chanFreq().put(outspw,chfr);
2976 94 : spwcol.chanWidth().put(outspw,chwid);
2977 94 : spwcol.resolution().put(outspw,chres);
2978 94 : spwcol.effectiveBW().put(outspw,cheff);
2979 94 : spwcol.numChan().put(outspw,numChan);
2980 94 : spwcol.totalBandwidth().put(outspw,totbw);
2981 94 : spwcol.flagRow().put(outspw,False);
2982 :
2983 :
2984 : }
2985 : else {
2986 :
2987 : // outspw already set (not yet written to disk, unless (possibly) append=True; checked elsewhere)
2988 : // Verify that info matches... this shouldn't be necessary, in general,
2989 : // as discernAndSetSolutionFrequencies sets the rigorously....
2990 : // TBD: test against _apparent_ frequencies in this soluton interval, e.g.,
2991 : // are available spws consistent.... (and merely warn)
2992 :
2993 : //cout << "Verifying freqs for spw=" << outspw << endl;
2994 :
2995 : // Existing freqs in table...
2996 131 : Vector<Double> currCTFreq;
2997 131 : spwcol.chanFreq().get(outspw,currCTFreq);
2998 : Int numChan;
2999 131 : spwcol.numChan().get(outspw,numChan);
3000 :
3001 : // Current solution freqs
3002 131 : const Vector<Double>& chfr(freqMetaData_.freq(outspw));
3003 131 : const Int numChanOut(chfr.nelements());
3004 :
3005 : // If values mismatch, we need to abort
3006 131 : if (numChan!=numChanOut || !allEQ(currCTFreq,chfr)) {
3007 0 : cout << "For spw=" << outspw << ":" << endl;
3008 0 : cout << "Current CalTable nchan= " << numChan << endl;
3009 0 : cout << "Current CalTable freq = " << currCTFreq << endl;
3010 0 : cout << "Current Solution nchan= " << numChan << endl;
3011 0 : cout << "Current Solution freq = " << chfr << endl;
3012 0 : cout << "Diff = " << chfr-currCTFreq << endl;
3013 :
3014 0 : throw(AipsError("Mismatch between Solution frequencies and existing CalTable frequencies for spw="+String::toString(spw)));
3015 : }
3016 :
3017 131 : } // !needToSet
3018 :
3019 225 : }
3020 :
3021 : // Discern detailed frequency meta info for solutions (solve context)
3022 32 : void SolvableVisCal::discernAndSetSolnFrequencies(const vi::VisibilityIterator2& vi, const Vector<uInt>& selspws) {
3023 :
3024 : // cout << endl << "SVC::discernAndSetSolnFrequencies---------------------------" << endl;
3025 :
3026 : // TBD: When aggregating, we should verify that all frames are consistent
3027 32 : Vector<Int> frames(vi.spectralWindowSubtablecols().measFreqRef().getColumn());
3028 : //cout << "vi.spectralWindowSubtablecols().measFreqRef() = " << frames << endl;
3029 :
3030 : // Gather MS freq info
3031 64 : Vector< Vector<Double> > MSfreq(nSpw(),Vector<Double>()), MSwidth(nSpw(),Vector<Double>());
3032 142 : for (uInt i=0;i<selspws.nelements();++i) {
3033 110 : uInt ispw=selspws(i);
3034 :
3035 110 : MSfreq(ispw).assign(vi.getImpl()->getFrequencies(-1.0e0,frames(ispw),ispw,0));
3036 110 : MSwidth(ispw).assign(vi.getImpl()->getChanWidths(-1.0e0,frames(ispw),ispw,0));
3037 :
3038 : // cout << "Spw=" << ispw << ":" << endl
3039 : // << " MSfreq=" << MSfreq(ispw) << endl
3040 : // << " MSwidth=" << MSwidth(ispw) << endl;
3041 : }
3042 :
3043 : // Nominally empty spwFanIn...
3044 32 : Vector<Int> spwFanIn;
3045 :
3046 : // Work out spwFanIn from selecte spws, if we are combining spws...
3047 32 : if (combspw()) {
3048 :
3049 : // We're combining, so set up the "spwmap" for spw fan-in
3050 5 : spwFanIn.resize(nSpw());
3051 5 : spwFanIn.set(-1); // -1 means not included
3052 :
3053 : // Use the MINIMUM spwid from selection for the aggregate
3054 5 : Int aggSpw=min(selspws);
3055 25 : for (uInt iselspw=0;iselspw<selspws.nelements();++iselspw)
3056 20 : spwFanIn(selspws(iselspw))=aggSpw;
3057 :
3058 : }
3059 :
3060 : // Now delegate the freq meta calculation to the FreqMetaData object
3061 32 : freqMetaData_.calcFreqMeta(MSfreq,MSwidth,selspws,freqDepPar(),combspw(),spwFanIn);
3062 :
3063 :
3064 : // If appending, check current/pending freq meta data againt existing info on disk
3065 32 : if (append()) {
3066 1 : const CTSpectralWindow ctspw(calTableName()+"/SPECTRAL_WINDOW");
3067 1 : const CTSpWindowColumns& spwcol(ctspw);
3068 :
3069 : // Which spws are we procssing now?
3070 1 : Vector<Int> validfMDspws(freqMetaData_.validSpws());
3071 :
3072 : // If current spws already in disk table, freq meta must match!
3073 1 : for (uInt i=0;i<validfMDspws.nelements();++i) {
3074 1 : const Int& ispw(validfMDspws(i));
3075 :
3076 : // If disk table already has this spw set (not flagged), we need to check for a match
3077 1 : if (!spwcol.flagRow().get(ispw)) {
3078 :
3079 : // disk table info
3080 1 : const uInt numChan(spwcol.numChan().get(ispw));
3081 1 : const Vector<Double> currCTFreq(spwcol.chanFreq().get(ispw));
3082 :
3083 : // current pending freq info
3084 1 : const Vector<Double>& fMDfreq(freqMetaData_.freq(ispw));
3085 :
3086 : // TBD: check other freq meta info (width, resoln, effBW)?
3087 :
3088 : // Insist nchan and freq(s) match!
3089 1 : if (numChan!=fMDfreq.nelements() || !allEQ(currCTFreq,fMDfreq))
3090 2 : throw(AipsError("Mismatch with frequency meta-data in append to "+
3091 3 : calTableName()+" detected in spw="+String::toString(ispw)+". Check spw selection."));
3092 :
3093 1 : } // !flagged in disk table
3094 :
3095 : } // validfMDspws(i}
3096 :
3097 3 : } // append?
3098 :
3099 :
3100 :
3101 : // TBD: Add more log info, probably inside FreqMetaData...
3102 :
3103 35 : }
3104 :
3105 :
3106 :
3107 : // VI2------------------------^
3108 :
3109 :
3110 :
3111 : // The inflate methods will soon deprecate (gmoellen, 20121212)
3112 : // (the are assumed to exist only by LJJones and EPJones, which
3113 : // are not yet NewCalTable-compliant)
3114 :
3115 : // Inflate the internal CalSet according to VisSet info
3116 0 : void SolvableVisCal::inflate(VisSet& vs, const Bool& /* fillMeta */) {
3117 :
3118 0 : if (prtlev()>3) cout << " SVC::inflate(vs)" << endl;
3119 :
3120 : // This method sets up various shape parameters
3121 : // according to the current VisSet. It is necessary
3122 : // to run this after Calibrater::setdata and before
3123 : // the main part of the solve. (In case the setdata
3124 : // was run after the setsolve.) This method calls
3125 : // a generic version to interpret the data shapes
3126 : // in the proper context-dependent way and size
3127 : // the CalSet.
3128 :
3129 : // TBD: Move this slot counting exercise out to Calibrater?
3130 : // --> Not clear we should do this...
3131 :
3132 : // TBD: How do we generalize this to create bracketing
3133 : // slots at scan start/stop (for accumulation context)?
3134 :
3135 : // Count slots in the VisIter
3136 0 : Vector<Int> nSlot(nSpw(),0);
3137 : {
3138 0 : VisIter& vi(vs.iter());
3139 0 : for (vi.originChunks(); vi.moreChunks(); vi.nextChunk())
3140 0 : nSlot(vi.spectralWindow())++;
3141 0 : vi.originChunks();
3142 :
3143 0 : logSink() << "For interval of "<<interval()<<" seconds, found "
3144 : << sum(nSlot)<<" slots"
3145 0 : << LogIO::POST;
3146 : }
3147 :
3148 : // Call generic version to actually inflate the CalSet
3149 : // (assumes nChanParList()/startChanList() already valid!)
3150 0 : inflate(nChanParList(),startChanList(),nSlot);
3151 :
3152 0 : }
3153 :
3154 :
3155 : // Inflate the internal CalSet generically
3156 0 : void SolvableVisCal::inflate(const Vector<Int>& /*nChan*/,
3157 : const Vector<Int>& /*startChan*/,
3158 : const Vector<Int>& /*nSlot*/) {
3159 :
3160 0 : if (prtlev()>3) cout << " SVC::inflate(,,)" << endl;
3161 :
3162 0 : throw(AipsError("Attempt to use deprecated SVC::inflate method."));
3163 :
3164 : }
3165 :
3166 0 : void SolvableVisCal::setSolveChannelization(VisSet& vs) {
3167 :
3168 : // TBD: include anticipated decimation when partial freq ave supported?
3169 : // (NB: note difference between chan-ave on selection [VisSet] and
3170 : // chan-ave on-the-fly with vb.freqAve())
3171 :
3172 :
3173 0 : Vector<Int> nDatChan(vs.numberChan());
3174 0 : Vector<Int> startDatChan(vs.startChan());
3175 :
3176 : // Figure out channel axis shapes (solve context!):
3177 :
3178 : // If multi-channel pars, this is a frequency-sampled calibration (e.g., B)
3179 0 : if (freqDepPar()) {
3180 : // Overall par shape follows data shape
3181 0 : nChanParList() = nDatChan;
3182 0 : startChanList() = startDatChan;
3183 :
3184 : // Handle partial freq average
3185 0 : if (fsolint()!="none" && (allGT(fintervalCh_,0.0)||fintervalHz_>0.0))
3186 0 : setFracChanAve();
3187 :
3188 : // However, for solving, we will only consider one channel at a time:
3189 0 : nChanMatList() = 1;
3190 :
3191 : }
3192 : else {
3193 : // Pars are not themselves channel-dependent
3194 0 : nChanParList() = 1;
3195 :
3196 : // Check if matrices may still be freq-dep:
3197 0 : if (freqDepMat()) {
3198 : // cal is an explicit f(freq) (e.g., like delay)
3199 0 : nChanMatList() = nDatChan;
3200 0 : startChanList() = startDatChan;
3201 : } else {
3202 : // cal has no freq dep at all
3203 0 : nChanMatList() = Vector<Int>(nSpw(),1);
3204 0 : startChanList() = Vector<Int>(nSpw(),0);
3205 : }
3206 :
3207 : }
3208 :
3209 : // At this point:
3210 : // 1. nChanParList() represents the (per-Spw) overall length of the
3211 : // output parameter channel axis, appropriate for shaping the
3212 : // output NewCalTable. This value is irrelevant during the solve, since
3213 : // we will only solve for one parameter channel at a time (or
3214 : // there is only one channel to solver for).
3215 : // 2. nChanMatList() represents the per-Spw matrix channel axis length to
3216 : // be used during the solve, independent of the parameter channel
3217 : // axis length. In the solve context, nChanMat()>1 when there is
3218 : // more than one channel of data upon which the (single channel)
3219 : // solve parameters depend (e.g., delay, polynomial bandpass, etc.)
3220 :
3221 0 : }
3222 :
3223 :
3224 :
3225 :
3226 0 : void SolvableVisCal::convertHzToCh() {
3227 :
3228 : // cout << "convertHzToCh!" << endl;
3229 :
3230 : // Access the channel widths vis msmc, etc.
3231 0 : vector<QVD> chanwidths=msmc().msmd().getChanWidths();
3232 :
3233 0 : logSink() << LogIO::NORMAL;
3234 0 : logSink() << " Frequency solint parsing:" << LogIO::POST;
3235 0 : for (Int ispw=0;ispw<nSpw();++ispw) {
3236 0 : currSpw()=ispw;
3237 : // Calculate channel increment from Hz
3238 0 : if (fintervalCh()<0.0 && fintervalHz()>0.0) {
3239 : // Assumes constant chan width in each spw!
3240 0 : Double datawidthHz=abs(chanwidths[ispw][0].get("Hz").getValue());
3241 0 : fintervalCh()=floor(fintervalHz()/datawidthHz);
3242 0 : if (fintervalCh()<1.0) fintervalCh()=1.0; // nothing fractional <1.0
3243 :
3244 : logSink() << ". Spw " << ispw << ": "
3245 0 : << " (freq solint: " << fintervalHz() << " Hz) / (data width: " << datawidthHz << " Hz)"
3246 0 : << " = " << fintervalCh() << " data channels per solution channel."
3247 0 : << LogIO::POST;
3248 : }
3249 : } // ispw
3250 :
3251 0 : }
3252 :
3253 :
3254 :
3255 :
3256 0 : void SolvableVisCal::setFracChanAve() {
3257 :
3258 : // TBD: calculate fintervalCh from fintervalHz
3259 0 : MeasurementSet ms(msName());
3260 0 : MSSpWindowColumns spwcol(ms.spectralWindow());
3261 :
3262 : // cout << "setFracChanAve!" << endl;
3263 0 : for (Int ispw=0;ispw<nSpw();++ispw) {
3264 : // cout << "ispw=" << ispw << ":" << endl;
3265 : // cout << " nChanData = " << nChanPar() << endl;
3266 : // cout << " startChan() = " << startChan() << endl;
3267 0 : currSpw()=ispw;
3268 :
3269 : // Calculate channel increment from Hz
3270 0 : if (fintervalCh()<0.0 && fintervalHz()>0.0) {
3271 0 : Double datawidth=abs(spwcol.chanWidth()(ispw)(IPosition(1,0)));
3272 0 : cout << "ispw=" << ispw << " datawidth=" << datawidth << flush;
3273 0 : fintervalCh()=floor(fintervalHz()/datawidth);
3274 0 : if (fintervalCh()<1.0) fintervalCh()=1.0;
3275 0 : cout << " dHz=" << fintervalHz() << " --> " << fintervalCh() << " channels." << endl;
3276 : }
3277 :
3278 0 : Int extrach=nChanPar()%Int(fintervalCh());
3279 0 : Int nChanOut=nChanPar()/Int(fintervalCh()) + (extrach > 0 ? 1 : 0);
3280 :
3281 : // cout << " fintervalCh() = " << fintervalCh() << endl;
3282 : // cout << " extrach = " << extrach << endl;
3283 : // cout << " nChanOut = " << nChanOut << endl;
3284 :
3285 0 : chanAveBounds_(ispw).resize(nChanOut,2);
3286 0 : Matrix<Int> bounds(chanAveBounds_(ispw));
3287 0 : bounds.column(0).set(startChan());
3288 0 : bounds.column(1).set(startChan()+Int(fintervalCh()-1));
3289 0 : for (Int ochan=1;ochan<nChanOut;++ochan) {
3290 0 : Vector<Int> col(bounds.row(ochan));
3291 0 : col+=Int(ochan*fintervalCh());
3292 0 : }
3293 0 : if (extrach>0) bounds(nChanOut-1,1)+=(extrach-Int(fintervalCh()));
3294 :
3295 : // for (int ochan=0;ochan<nChanOut;++ochan)
3296 : // cout << " ochan="<<ochan<< " bounds="
3297 : // << bounds.row(ochan)
3298 : // << " n=" << bounds(ochan,1)-bounds(ochan,0)+1
3299 : // << endl;
3300 :
3301 : // Revise nChanPar()
3302 0 : nChanPar()=nChanOut;
3303 0 : }
3304 0 : currSpw()=0;
3305 : // cout << "nChanParList() = " << nChanParList() << endl;
3306 : // cout << "chanAveBounds_ = " << chanAveBounds_ << endl;
3307 0 : }
3308 :
3309 : // Inflate an empty Caltable w/ meta-data from a VisSet
3310 0 : void SolvableVisCal::inflateNCTwithMetaData(VisSet& vs) {
3311 :
3312 0 : if (prtlev()>3) cout << " SVC::inflateNCTwithMetaData(vs)" << endl;
3313 :
3314 : // NB: Currently, this is only used for the accumulate
3315 : // context; in solve, meta-data is filled on-the-fly
3316 : // (this ensures more accurate timestamps, etc.)
3317 :
3318 : // Fill the Calset with meta info
3319 0 : VisIter& vi(vs.iter());
3320 0 : vi.originChunks();
3321 0 : VisBuffer vb(vi);
3322 0 : Vector<Int> islot(nSpw(),0);
3323 0 : for (vi.originChunks(); vi.moreChunks(); vi.nextChunk()) {
3324 :
3325 0 : vi.origin();
3326 0 : currSpw()=vi.spectralWindow();
3327 0 : currField()=vi.fieldId();
3328 0 : currScan()=vb.scan0();
3329 0 : currObs()=vb.observationId()(0);
3330 :
3331 : // Derive average time info
3332 0 : Double timeStamp(0.0);
3333 0 : Int ntime(0);
3334 0 : for (vi.origin(); vi.more(); vi++,++ntime) timeStamp+=vb.time()(0);
3335 0 : if (ntime>0)
3336 0 : refTime()=timeStamp/Double(ntime);
3337 : else
3338 0 : refTime()=0.0;
3339 :
3340 : // Initialize parameters
3341 0 : switch(parType()) {
3342 0 : case VisCalEnum::COMPLEX: {
3343 0 : solveAllCPar().set(defaultPar());
3344 0 : break;
3345 : }
3346 0 : case VisCalEnum::REAL: {
3347 0 : solveAllCPar().set(defaultPar());
3348 0 : break;
3349 : }
3350 0 : default:
3351 0 : break;
3352 : }
3353 0 : solveAllParOK().set(true);
3354 0 : solveAllParErr().set(Float(0.0));
3355 0 : solveAllParSNR().set(1.0);
3356 :
3357 : /*
3358 : cout << "Spw=" << currSpw()
3359 : << " Fld=" << currField()
3360 : << " Scan=" << currScan()
3361 : << " Time=" << MVTime(refTime()/C::day).string(MVTime::YMD,7)
3362 : << endl;
3363 : */
3364 :
3365 : // Add this interval to the NCT
3366 0 : if (refTime()>0.0)
3367 0 : keepNCT();
3368 :
3369 : }
3370 :
3371 0 : }
3372 :
3373 0 : Bool SolvableVisCal::syncSolveMeta(VisBuffGroupAcc& vbga) {
3374 :
3375 : // Adopt meta data from FIRST CalVisBuffer in the VBGA, for now
3376 0 : currSpw()=spwMap()(vbga(0).spectralWindow());
3377 0 : currField()=vbga(0).fieldId();
3378 :
3379 : // The timestamp really is global, in any case
3380 0 : Double& rTime(vbga.globalTimeStamp());
3381 0 : if (rTime > 0.0) {
3382 0 : refTime()=rTime;
3383 0 : return true;
3384 : }
3385 : else
3386 0 : return false;
3387 :
3388 : }
3389 :
3390 225 : void SolvableVisCal::syncSolveMeta(SDBList& sdbs) { // VI2
3391 :
3392 : // cout << "spwMap() = " << spwMap() << endl;
3393 :
3394 : // Ask the sdbs
3395 225 : Vector<Double> freqs;
3396 225 : if (freqDepPar())
3397 : // nominally channelized
3398 0 : freqs.reference(sdbs.freqs());
3399 : else
3400 : // a single aggregate frequency (as a Vector)
3401 225 : freqs.reference(Vector<Double>(1,sdbs.aggregateCentroidFreq()));
3402 :
3403 225 : setMeta(sdbs.aggregateObsId(),
3404 : sdbs.aggregateScan(),
3405 : //sdbs.aggregateTime(),
3406 : sdbs.aggregateTimeCentroid(),
3407 : sdbs.aggregateSpw(),
3408 : freqs,
3409 : sdbs.aggregateFld());
3410 225 : }
3411 :
3412 :
3413 :
3414 0 : Bool SolvableVisCal::syncSolveMeta(VisBuffer& vb,
3415 : const Int&) {
3416 :
3417 0 : if (prtlev()>2) cout << "SVC::syncSolveMeta(,,)" << endl;
3418 :
3419 : // Returns true, only if sum of weights is positive,
3420 : // i.e., there is data to solve with
3421 :
3422 : // TBD: freq info, etc.
3423 :
3424 0 : currSpw()=spwMap()(vb.spectralWindow());
3425 0 : currField()=vb.fieldId();
3426 0 : currScan()=vb.scan0();
3427 0 : currObs()=vb.observationId()(0);
3428 :
3429 : // Row weights as a Doubles
3430 0 : Vector<Double> dWts;
3431 0 : dWts.resize(vb.weight().shape());
3432 0 : convertArray(dWts,vb.weight());
3433 0 : Vector<Double> times;
3434 0 : times = vb.time();
3435 :
3436 : // The following assumes flagRow is accurate
3437 0 : LogicalArray gRows(!vb.flagRow());
3438 0 : Double sumWts(0.0);
3439 0 : MaskedArray<Double> gTimes(times,gRows);
3440 0 : MaskedArray<Double> gWts(dWts,gRows);
3441 :
3442 0 : if (sum(gRows)>0) {
3443 0 : sumWts=sum(gWts);
3444 : }
3445 :
3446 0 : if (sumWts>0.0) {
3447 0 : gTimes*=gWts;
3448 0 : refTime()=sum(gTimes);
3449 0 : refTime()/=sumWts;
3450 0 : return true;
3451 : }
3452 : else
3453 0 : return false;
3454 :
3455 0 : }
3456 :
3457 0 : void SolvableVisCal::overrideObsScan(Int obs,Int scan) {
3458 0 : currObs()=obs;
3459 0 : currScan()=scan;
3460 0 : }
3461 :
3462 0 : void SolvableVisCal::enforceAPonData(VisBuffer& vb) {
3463 :
3464 : // TBD: migrate this to VisEquation?
3465 :
3466 : // ONLY if something to do
3467 0 : if (apmode()=="A" || apmode()=="P") {
3468 0 : Int nCorr(vb.corrType().nelements());
3469 0 : Float amp(1.0);
3470 0 : Complex cor(1.0);
3471 0 : Bool *flR=vb.flagRow().data();
3472 0 : Bool *fl =vb.flag().data();
3473 0 : Vector<Float> ampCorr(nCorr);
3474 0 : Vector<Int> n(nCorr,0);
3475 0 : for (Int irow=0;irow<vb.nRow();++irow,++flR) {
3476 0 : if (!vb.flagRow()(irow)) {
3477 0 : ampCorr=0.0f;
3478 0 : n=0;
3479 0 : for (Int ich=0;ich<vb.nChannel();++ich,++fl) {
3480 0 : if (!vb.flag()(ich,irow)) {
3481 0 : for (Int icorr=0;icorr<nCorr;icorr++) {
3482 :
3483 0 : amp=abs(vb.visCube()(icorr,ich,irow));
3484 0 : if (amp>0.0f) {
3485 0 : if (apmode()=="P") {
3486 : // we will scale by amp to make data phase-only
3487 0 : cor=Complex(amp,0.0);
3488 : // keep track for weight adjustment
3489 0 : ampCorr(icorr)+=abs(cor); // amp;
3490 0 : n(icorr)++;
3491 : }
3492 0 : else if (apmode()=="A")
3493 : // we will scale by "phase" to make data amp-only
3494 0 : cor=vb.visCube()(icorr,ich,irow)/amp;
3495 :
3496 : // Apply the complex scaling
3497 0 : vb.visCube()(icorr,ich,irow)/=cor;
3498 : }
3499 : } // icorr
3500 : } // !*fl
3501 : } // ich
3502 : // Make appropriate weight adjustment
3503 : // Only for phase-only since only it rescales data
3504 0 : if (apmode()=="P") {
3505 0 : for (Int icorr=0;icorr<nCorr;icorr++)
3506 0 : if (n(icorr)>0)
3507 : // weights adjusted by square of the mean(amp)
3508 0 : vb.weightMat()(icorr,irow)*=square(ampCorr(icorr)/Float(n(icorr)));
3509 : else
3510 : // weights now zero
3511 0 : vb.weightMat()(icorr,irow)=0.0f;
3512 : }
3513 : } // !*flR
3514 : } // irow
3515 :
3516 0 : } // phase- or amp-only
3517 :
3518 : // cout << "amp(vb.visCube())=" << amplitude(vb.visCube().reform(IPosition(1,vb.visCube().nelements()))) << endl;
3519 :
3520 :
3521 0 : }
3522 :
3523 0 : void SolvableVisCal::setUpForPolSolve(VisBuffer& vb) {
3524 :
3525 : // TBD: migrate this to VisEquation?
3526 :
3527 : // NB (2016Nov29, gmoellen): No, should actually move this very specific
3528 : // activity into DJones where it is specifically relevant.
3529 : // VB2 version has done this.
3530 :
3531 : // Divide model and data by (scalar) stokes I (which may be resolved!),
3532 : // and set model cross-hands to (1,0) so we can solve for fractional
3533 : // pol factors.
3534 :
3535 : // Only if solving for Q an U
3536 : // (leave cross-hands alone if just solving for X)
3537 0 : if (solvePol()>1) {
3538 :
3539 0 : Int nCorr(vb.corrType().nelements());
3540 0 : Bool *flR=vb.flagRow().data();
3541 0 : Bool *fl =vb.flag().data();
3542 0 : Vector<Float> ampCorr(nCorr);
3543 0 : Vector<Int> n(nCorr,0);
3544 0 : Complex sI(0.0);
3545 0 : for (Int irow=0;irow<vb.nRow();++irow,++flR) {
3546 0 : if (!vb.flagRow()(irow)) {
3547 0 : ampCorr=0.0f;
3548 0 : n=0;
3549 0 : for (Int ich=0;ich<vb.nChannel();++ich,++fl) {
3550 0 : if (!vb.flag()(ich,irow)) {
3551 :
3552 0 : sI=(vb.modelVisCube()(0,ich,irow)+vb.modelVisCube()(3,ich,irow))/Complex(2.0);
3553 0 : if (abs(sI)>0.0) {
3554 0 : for (Int icorr=0;icorr<nCorr;icorr++) {
3555 0 : vb.visCube()(icorr,ich,irow)/=sI;
3556 0 : ampCorr(icorr)+=abs(sI);
3557 0 : n(icorr)++;
3558 : } // icorr
3559 : }
3560 : else
3561 0 : vb.flag()(ich,irow)=true;
3562 :
3563 : } // !*fl
3564 : } // ich
3565 : // Make appropriate weight adjustment
3566 0 : for (Int icorr=0;icorr<nCorr;icorr++)
3567 0 : if (n(icorr)>0)
3568 : // weights adjusted by square of the mean(amp)
3569 0 : vb.weightMat()(icorr,irow)*=square(ampCorr(icorr)/Float(n(icorr)));
3570 : else
3571 : // weights now zero
3572 0 : vb.weightMat()(icorr,irow)=0.0f;
3573 : } // !*flR
3574 : } // irow
3575 :
3576 : // Model is now all unity (Is this ok for flagged data? Probably.)
3577 0 : vb.modelVisCube()=Complex(1.0);
3578 :
3579 0 : }
3580 :
3581 0 : }
3582 :
3583 0 : Bool SolvableVisCal::verifyConstraints(VisBuffGroupAcc& vbag) {
3584 :
3585 : // TBD: handle multi-channel infocusFlag properly
3586 : // TBD: optimize array access
3587 :
3588 : // Assemble nominal baseline weights distribution
3589 0 : Matrix<Double> blwtsum(nAnt(),nAnt(),0.0);
3590 0 : for (Int ivb=0;ivb<vbag.nBuf();++ivb) {
3591 0 : CalVisBuffer& cvb(vbag(ivb));
3592 :
3593 0 : cvb.setFocusChan(focusChan());
3594 :
3595 0 : for (Int irow=0;irow<cvb.nRow();++irow) {
3596 0 : Int& a1(cvb.antenna1()(irow));
3597 0 : Int& a2(cvb.antenna2()(irow));
3598 0 : if (!cvb.flagRow()(irow) && a1!=a2) {
3599 0 : if (!cvb.infocusFlag()(0,irow)) {
3600 0 : Double wt=Double(sum(cvb.weightMat().column(irow)));
3601 0 : blwtsum(a2,a1)+=wt;
3602 0 : blwtsum(a1,a2)+=wt;
3603 : } // flag
3604 : } // flagRow
3605 : } // irow
3606 : } // ivb
3607 :
3608 : // Recursively apply threshold on baselines per antenna
3609 : // Currently, we insist on at least 3 baselines per antenna
3610 : // (This will eventually be a user-specified parameter: blperant)
3611 0 : Vector<Bool> antOK(nAnt(),true); // nominally OK
3612 0 : Vector<Int> blperant(nAnt(),0);
3613 0 : Int iant=0;
3614 0 : while (iant<nAnt()) {
3615 0 : if (antOK(iant)) { // avoid reconsidering already bad ones
3616 0 : Int nbl=ntrue(blwtsum.column(iant)>0.0);
3617 0 : blperant(iant)=nbl;
3618 0 : if (nbl<minblperant()) {
3619 : // some baselines available, but not enough
3620 : // so eliminate this antenna
3621 0 : antOK(iant)=false;
3622 0 : blwtsum.row(iant)=0.0;
3623 0 : blwtsum.column(iant)=0.0;
3624 0 : blperant(iant)=0;
3625 : // ensure we begin recount at first antenna again
3626 0 : iant=-1;
3627 : }
3628 : }
3629 0 : ++iant;
3630 : }
3631 :
3632 : // cout << " blperant = " << blperant << " (minblperant = " << minblperant() << endl;
3633 : // cout << " antOK = " << antOK << endl;
3634 : // cout << " ntrue(antOK) = " << ntrue(antOK) << endl;
3635 :
3636 : // Apply constraints results to solutions and data
3637 0 : solveParOK()=false; // Solutions nominally bad
3638 0 : for (Int iant=0;iant<nAnt();++iant) {
3639 0 : if (antOK(iant)) {
3640 : // set solution good
3641 0 : solveParOK().xyPlane(iant) = true;
3642 : }
3643 : else {
3644 : // This ant not ok, set soln to zero
3645 0 : if (parType()==VisCalEnum::COMPLEX)
3646 0 : solveCPar().xyPlane(iant)=1.0;
3647 0 : else if (parType()==VisCalEnum::REAL)
3648 0 : solveRPar().xyPlane(iant)=0.0;
3649 :
3650 : // Flag corresponding data
3651 0 : for (Int ivb=0;ivb<vbag.nBuf();++ivb) {
3652 0 : CalVisBuffer& cvb(vbag(ivb));
3653 0 : Vector<Int>& a1(cvb.antenna1());
3654 0 : Vector<Int>& a2(cvb.antenna2());
3655 0 : for (Int irow=0;irow<cvb.nRow();++irow) {
3656 0 : if (a1(irow)==iant || a2(irow)==iant)
3657 0 : cvb.infocusFlag()(0,irow)=true;
3658 : }
3659 : // the following didn't work because row(0) behaved
3660 : // as contiguous and set the wrong flags for multi-chan data!
3661 : // cvb.infocusFlag().row(0)(a1==iant)=true;
3662 : // cvb.infocusFlag().row(0)(a2==iant)=true;
3663 : } // ivb
3664 :
3665 : } // antOK
3666 : } // iant
3667 :
3668 : // We return sum(antOK)>0 here because it is not how many
3669 : // good ants there are, but rather how many good baselines
3670 : // per ant there are. The above counting exercise will
3671 : // reduce sum(antOK) to zero when the baseline counts
3672 : // constraint is violated over enough of the whole array.
3673 : // so as to make the solution impossible. Otherwise
3674 : // there will be at least blperant+1 (>0) good antennas.
3675 :
3676 0 : return (ntrue(antOK)>0);
3677 :
3678 0 : }
3679 :
3680 225 : void SolvableVisCal::clearMap() {
3681 : // Clear or initalize values for the antennaMap_
3682 225 : Vector<Int> initVector(nPar(), 0);
3683 225 : Vector<Int> singleVector(1, 0);
3684 :
3685 2457 : for (Int iant=0; iant<nAnt(); ++iant) {
3686 2232 : antennaMap_[iant]["expected"] = initVector;
3687 2232 : antennaMap_[iant]["data_unflagged"] = initVector;
3688 2232 : antennaMap_[iant]["above_minblperant"] = initVector;
3689 2232 : antennaMap_[iant]["above_minsnr"] = initVector;
3690 2232 : antennaMap_[iant]["used_as_refant"] = singleVector;
3691 : }
3692 :
3693 225 : }
3694 :
3695 31 : void SolvableVisCal::clearRefantMap() {
3696 : // Clear or initialize values for refantMap_
3697 155 : for (Int ispw=0; ispw<nSpw(); ++ispw) {
3698 1388 : for (Int iant=0; iant<nAnt(); ++iant) {
3699 1264 : refantMap_[ispw][iant] = 0;
3700 : }
3701 : }
3702 31 : }
3703 :
3704 225 : void SolvableVisCal::expectedUnflagged(SDBList& sdbs) {
3705 : // Iterate over sdbs and add values to expected and data unflagged
3706 27744 : for (Int isdb=0;isdb<sdbs.nSDB();++isdb) {
3707 27519 : SolveDataBuffer& sdb(sdbs(isdb));
3708 :
3709 27519 : Int nRow(sdb.nRows());
3710 27519 : Int nCorr(sdb.nCorrelations());
3711 563989 : for (Int irow=0;irow<nRow;++irow) {
3712 536470 : const Int& a1(sdb.antenna1()(irow));
3713 536470 : const Int& a2(sdb.antenna2()(irow));
3714 :
3715 536470 : if (a1!=a2) {
3716 4374630 : for (int par=0;par<nPar();par++) {
3717 3888560 : antennaMap_[a1]["expected"][par] = 1;
3718 3888560 : antennaMap_[a2]["expected"][par] = 1;
3719 : }
3720 : }
3721 : // Do cal type-dependent setting of "data_unflagged" counts
3722 :
3723 536470 : switch (this->type()) {
3724 536470 : case VisCal::G:
3725 : case VisCal::K:
3726 : case VisCal::B: { // nPar=2 (gain-like)
3727 : // Set each pol by flags from appropriate parallel-hand corr
3728 536470 : if (nfalse(sdb.flagCube()(0,Slice(),irow))>0) {
3729 504152 : antennaMap_[a1]["data_unflagged"][0] =
3730 1008304 : antennaMap_[a2]["data_unflagged"][0] = 1;
3731 : }
3732 536470 : if (nfalse(sdb.flagCube()(nCorr-1,Slice(),irow))>0) {
3733 502370 : antennaMap_[a1]["data_unflagged"][1] =
3734 1004740 : antennaMap_[a2]["data_unflagged"][1] = 1;
3735 : }
3736 536470 : break;
3737 : }
3738 0 : case VisCal::T: { // nPar=1 (gain-like)
3739 : // Set single pol by flags from all parallel-hand correlations
3740 0 : Int nsl(nCorr>1?2:1), isl(nCorr>2?3:1);
3741 0 : if (nfalse(sdb.flagCube()(Slice(0,nsl,isl),Slice(),irow))>0) {
3742 0 : antennaMap_[a1]["data_unflagged"][0] =
3743 0 : antennaMap_[a2]["data_unflagged"][0] = 1;
3744 : }
3745 0 : break;
3746 : }
3747 0 : default: {
3748 : // Set all pols by flags from all correlations (any unflagged is ok)
3749 0 : if (nfalse(sdb.flagCube()(Slice(),Slice(),irow))>0) {
3750 0 : antennaMap_[a1]["data_unflagged"].set(1);
3751 0 : antennaMap_[a2]["data_unflagged"].set(1);
3752 : }
3753 : }
3754 : }
3755 : }
3756 : }
3757 225 : }
3758 :
3759 0 : Bool SolvableVisCal::verifyConstraints(SDBList& sdbs) { // VI2
3760 :
3761 : // TBD: handle multi-channel infocusFlag properly
3762 : // TBD: optimize array access
3763 :
3764 : // Assemble nominal baseline weights distribution
3765 0 : Matrix<Double> blwtsum(nAnt(),nAnt(),0.0);
3766 0 : for (Int isdb=0;isdb<sdbs.nSDB();++isdb) {
3767 0 : SolveDataBuffer& sdb(sdbs(isdb));
3768 :
3769 0 : sdb.setFocusChan(focusChan());
3770 :
3771 : // TBD: do this per cal parameter, rather than just per ant
3772 :
3773 0 : Int nRow(sdb.nRows());
3774 0 : Int nCorr(sdb.nCorrelations());
3775 :
3776 0 : for (Int irow=0;irow<nRow;++irow) {
3777 0 : const Int& a1(sdb.antenna1()(irow));
3778 0 : const Int& a2(sdb.antenna2()(irow));
3779 0 : if (!sdb.flagRow()(irow) && a1!=a2) {
3780 : // Currently insist _any_ unflagged correlations; need to refine!
3781 0 : if (sum(sdb.infocusFlagCube()(Slice(),Slice(),irow))<nCorr) {
3782 0 : Double wt=Double(sum(sdb.infocusWtSpec()(Slice(),Slice(),irow)));
3783 0 : blwtsum(a2,a1)+=wt;
3784 0 : blwtsum(a1,a2)+=wt;
3785 : } // flag
3786 : } // flagRow
3787 : } // irow
3788 : } // ivb
3789 :
3790 : // Recursively apply threshold on baselines per antenna
3791 0 : Vector<Bool> antOK(nAnt(),True); // nominally OK
3792 0 : Vector<Int> blperant(nAnt(),0);
3793 0 : Vector<Int> initVector(nPar(), 0);
3794 :
3795 0 : Int iant=0;
3796 0 : while (iant<nAnt()) {
3797 0 : if (antOK(iant)) { // avoid reconsidering already bad ones
3798 0 : Int nbl=ntrue(blwtsum.column(iant)>0.0);
3799 0 : blperant(iant)=nbl;
3800 0 : if (nbl<minblperant()) {
3801 : // some baselines available, but not enough
3802 : // so eliminate this antenna
3803 0 : antOK(iant)=False;
3804 0 : blwtsum.row(iant)=0.0;
3805 0 : blwtsum.column(iant)=0.0;
3806 0 : blperant(iant)=0;
3807 : // ensure we begin recount at first antenna again
3808 0 : iant=-1;
3809 : }
3810 : }
3811 0 : ++iant;
3812 : }
3813 :
3814 : // cout << " blperant = " << blperant << " (minblperant = " << minblperant() << endl;
3815 : // cout << " antOK = " << antOK << endl;
3816 : // cout << " ntrue(antOK) = " << ntrue(antOK) << endl;
3817 :
3818 : // Apply constraints results to solutions and data
3819 0 : solveParOK()=False; // Solutions nominally bad
3820 0 : for (Int iant=0;iant<nAnt();++iant) {
3821 0 : if (antOK(iant)) {
3822 : // set solution good
3823 0 : solveParOK().xyPlane(iant) = True;
3824 0 : for (Int ipar=0; ipar<nPar();++ipar) {
3825 0 : antennaMap_[iant]["above_minblperant"][ipar] = 1;
3826 : }
3827 : }
3828 : else {
3829 : // This ant not ok, set soln to zero
3830 0 : if (parType()==VisCalEnum::COMPLEX)
3831 0 : solveCPar().xyPlane(iant)=1.0;
3832 0 : else if (parType()==VisCalEnum::REAL)
3833 0 : solveRPar().xyPlane(iant)=0.0;
3834 :
3835 : // Flag corresponding data
3836 0 : for (Int isdb=0;isdb<sdbs.nSDB();++isdb) {
3837 0 : SolveDataBuffer& sdb(sdbs(isdb));
3838 0 : const Vector<Int>& a1(sdb.antenna1());
3839 0 : const Vector<Int>& a2(sdb.antenna2());
3840 0 : for (Int irow=0;irow<sdb.nRows();++irow) {
3841 0 : if (a1(irow)==iant || a2(irow)==iant)
3842 0 : sdb.infocusFlagCube()(Slice(),Slice(),irow)=True;
3843 : }
3844 : // the following didn't work because row(0) behaved
3845 : // as contiguous and set the wrong flags for multi-chan data!
3846 : // cvb.infocusFlag().row(0)(a1==iant)=True;
3847 : // cvb.infocusFlag().row(0)(a2==iant)=True;
3848 : } // ivb
3849 :
3850 : } // antOK
3851 : } // iant
3852 :
3853 : // We return sum(antOK)>0 here because it is not how many
3854 : // good ants there are, but rather how many good baselines
3855 : // per ant there are. The above counting exercise will
3856 : // reduce sum(antOK) to zero when the baseline counts
3857 : // constraint is violated over enough of the whole array.
3858 : // so as to make the solution impossible. Otherwise
3859 : // there will be at least blperant+1 (>0) good antennas.
3860 :
3861 0 : return (ntrue(antOK)>0);
3862 :
3863 0 : }
3864 :
3865 :
3866 :
3867 : // Verify VisBuffer data sufficient for solving (wts, etc.)
3868 0 : Bool SolvableVisCal::verifyForSolve(VisBuffer& vb) {
3869 :
3870 : // cout << "verifyForSolve..." << endl;
3871 :
3872 0 : Int nAntForSolveFinal(-1);
3873 0 : Int nAntForSolve(0);
3874 :
3875 : // We will count baselines and weights per ant
3876 : // and set solveParOK accordingly
3877 0 : Vector<Int> blperant(nAnt(),0);
3878 0 : Vector<Double> wtperant(nAnt(),0.0);
3879 0 : Vector<Bool> antOK(nAnt(),false);
3880 :
3881 0 : while (nAntForSolve!=nAntForSolveFinal) {
3882 :
3883 0 : nAntForSolveFinal=nAntForSolve;
3884 0 : nAntForSolve=0;
3885 :
3886 :
3887 : // TBD: optimize indexing with pointers in the following
3888 0 : blperant=0;
3889 0 : wtperant=0.0;
3890 :
3891 0 : for (Int irow=0;irow<vb.nRow();++irow) {
3892 0 : Int a1=vb.antenna1()(irow);
3893 0 : Int a2=vb.antenna2()(irow);
3894 0 : if (!vb.flagRow()(irow) && a1!=a2) {
3895 :
3896 0 : if (!vb.flag()(focusChan(),irow)) {
3897 :
3898 0 : blperant(a1)+=1;
3899 0 : blperant(a2)+=1;
3900 :
3901 0 : wtperant(a1)+=Double(sum(vb.weightMat().column(irow)));
3902 0 : wtperant(a2)+=Double(sum(vb.weightMat().column(irow)));
3903 :
3904 : }
3905 : }
3906 : }
3907 :
3908 0 : antOK=false;
3909 0 : for (Int iant=0;iant<nAnt();++iant) {
3910 0 : if (blperant(iant)>3 &&
3911 0 : wtperant(iant)>0.0) {
3912 : // This antenna is good, keep it
3913 0 : nAntForSolve+=1;
3914 0 : antOK(iant)=true;
3915 : }
3916 : else {
3917 : // This antenna under-represented; flag it
3918 0 : vb.flag().row(focusChan())(vb.antenna1()==iant)=true;
3919 0 : vb.flag().row(focusChan())(vb.antenna2()==iant)=true;
3920 : // vb.flagRow()(vb.antenna1()==iant)=true;
3921 : // vb.flagRow()(vb.antenna2()==iant)=true;
3922 : }
3923 : }
3924 :
3925 : // cout << "blperant = " << blperant << endl;
3926 : // cout << "wtperant = " << wtperant << endl;
3927 : // cout << "nAntForSolve = " << nAntForSolve << " " << antOK << endl;
3928 :
3929 : }
3930 :
3931 : // We've converged on the correct good antenna count
3932 0 : nAntForSolveFinal=nAntForSolve;
3933 :
3934 : // Set a priori solution flags
3935 0 : solveParOK() = false;
3936 0 : for (Int iant=0;iant<nAnt();++iant)
3937 0 : if (antOK(iant))
3938 : // This ant ok
3939 0 : solveParOK().xyPlane(iant) = true;
3940 : else
3941 : // This ant not ok, set soln to zero
3942 0 : if (parType()==VisCalEnum::COMPLEX)
3943 0 : solveCPar().xyPlane(iant)=1.0;
3944 0 : else if (parType()==VisCalEnum::REAL)
3945 0 : solveRPar().xyPlane(iant)=0.0;
3946 : // cout << "antOK = " << antOK << endl;
3947 : // cout << "solveParOK() = " << solveParOK() << endl;
3948 : // cout << "amp(solveCPar()) = " << amplitude(solveCPar()) << endl;
3949 :
3950 0 : if (nAntForSolve<4) cout << "Only " << nAntForSolve
3951 0 : << "/" << nAnt()
3952 0 : << " antennas ("
3953 0 : << floor(100*Float(nAntForSolve/nAnt()))
3954 0 : << "%) have sufficient baselines at "
3955 0 : << MVTime(refTime()/C::day).string(MVTime::YMD,7)
3956 0 : << endl;
3957 0 : return (nAntForSolve>3);
3958 :
3959 0 : }
3960 :
3961 0 : void SolvableVisCal::selfGatherAndSolve(VisSet&, VisEquation&) {
3962 :
3963 0 : if (useGenericGatherForSolve())
3964 0 : throw(AipsError("Spurious call to selfGatherAndSolve() with useGenericGatherForSolve()=T."));
3965 : else
3966 0 : throw(AipsError("Attempt to call un-implemented selfGatherAndSolve()"));
3967 :
3968 : }
3969 0 : void SolvableVisCal::selfSolveOne(VisBuffGroupAcc&) {
3970 :
3971 0 : if (useGenericSolveOne())
3972 0 : throw(AipsError("Spurious call to selfSolveOne() with useGenericSolveOne()=T."));
3973 : else
3974 0 : throw(AipsError("Attempt to call un-implemented selfSolveOne()"));
3975 :
3976 : }
3977 :
3978 :
3979 0 : void SolvableVisCal::updatePar(const Vector<Complex> dCalPar,const Vector<Complex> dSrcPar) {
3980 :
3981 0 : AlwaysAssert((solveCPar().nelements()==dCalPar.nelements()),AipsError);
3982 :
3983 0 : Cube<Complex> dparcube(dCalPar.reform(solveCPar().shape()));
3984 :
3985 : // zero flagged increments
3986 0 : dparcube(!solveParOK())=Complex(0.0);
3987 :
3988 : // Add the increment
3989 0 : solveCPar()+=dparcube;
3990 :
3991 : // Update source params
3992 0 : if (solvePol()) {
3993 0 : srcPolPar()+=dSrcPar;
3994 : // cout << "Updated Q,U = " << real(srcPolPar()) << endl;
3995 : }
3996 :
3997 : // The matrices are nominally out-of-sync now
3998 0 : invalidateCalMat();
3999 :
4000 : // Ensure phaseonly-ness, if necessary
4001 : // if (apmode()=='P') {
4002 : // NB: Disable this, for the moment (07May24); testing a fix for
4003 : // a problem Kumar noticed. See VC::makeSolnPhaseOnly(), etc.
4004 : if (false) {
4005 : Float amp(0.0);
4006 : for (Int iant=0;iant<nAnt();++iant) {
4007 : for (Int ipar=0;ipar<nPar();++ipar) {
4008 : if (solveParOK()(ipar,0,iant)) {
4009 : amp=abs(solveCPar()(ipar,0,iant));
4010 : if (amp>0.0)
4011 : solveCPar()(ipar,0,iant)/=amp;
4012 : }
4013 : }
4014 : }
4015 : }
4016 0 : }
4017 :
4018 0 : void SolvableVisCal::updatePar(const Vector<Complex> dPar) { // VI2
4019 :
4020 0 : AlwaysAssert((solveCPar().nelements()==dPar.nelements()),AipsError);
4021 :
4022 0 : Cube<Complex> dparcube(dPar.reform(solveCPar().shape()));
4023 :
4024 : // zero flagged increments
4025 0 : dparcube(!solveParOK())=Complex(0.0);
4026 :
4027 : // Add the increment
4028 0 : solveCPar()+=dparcube;
4029 :
4030 : // The matrices are nominally out-of-sync now
4031 0 : invalidateCalMat();
4032 :
4033 : // Ensure phaseonly-ness, if necessary
4034 : // if (apmode()=='P') {
4035 : // NB: Disable this, for the moment (07May24); testing a fix for
4036 : // a problem Kumar noticed. See VC::makeSolnPhaseOnly(), etc.
4037 : if (False) {
4038 : Float amp(0.0);
4039 : for (Int iant=0;iant<nAnt();++iant) {
4040 : for (Int ipar=0;ipar<nPar();++ipar) {
4041 : if (solveParOK()(ipar,0,iant)) {
4042 : amp=abs(solveCPar()(ipar,0,iant));
4043 : if (amp>0.0)
4044 : solveCPar()(ipar,0,iant)/=amp;
4045 : }
4046 : }
4047 : }
4048 : }
4049 0 : }
4050 :
4051 :
4052 0 : void SolvableVisCal::formSolveSNR() {
4053 :
4054 : // Nominally zero
4055 0 : solveParSNR()=0.0;
4056 :
4057 0 : for (Int iant=0;iant<nAnt();++iant) {
4058 0 : for (Int ipar=0;ipar<nPar();++ipar) {
4059 0 : if (solveParOK()(ipar,0,iant)) {
4060 0 : if (solveParErr()(ipar,0,iant)>0.0f)
4061 0 : solveParSNR()(ipar,0,iant)=abs(solveCPar()(ipar,0,iant))/solveParErr()(ipar,0,iant);
4062 : else
4063 : // if error is zero, SNR is officially infinite; use a (large) special value here
4064 0 : solveParSNR()(ipar,0,iant)=9999999.0;
4065 : } // ok
4066 : } // ipar
4067 : } // iant
4068 :
4069 0 : }
4070 :
4071 0 : void SolvableVisCal::applySNRThreshold() {
4072 :
4073 0 : Int nOk1(ntrue(solveParOK()));
4074 :
4075 0 : std::map<casacore::Int, std::map<casacore::String, casacore::Vector<casacore::Int>>> resultMap;
4076 0 : Vector<Int> initVector(nPar(), 0);
4077 0 : Vector<Int> initVectorSingle(1, 0);
4078 :
4079 0 : for (Int iant=0;iant<nAnt();++iant) {
4080 : //if (refant() == iant) {
4081 : // antennaMap_[iant]["used_as_refant"][0] += 1;
4082 : //}
4083 0 : for (Int ipar=0;ipar<nPar();++ipar) {
4084 : //antennaMap_[iant]["expected"][ipar] += 1;
4085 0 : if (solveParOK()(ipar,0,iant)){
4086 0 : solveParOK()(ipar,0,iant)=(solveParSNR()(ipar,0,iant)>minSNR());
4087 : //antennaMap_[iant]["data_unflagged"][ipar] += 1;
4088 0 : if (solveParOK()(ipar,0,iant)) {antennaMap_[iant]["above_minsnr"][ipar] = 1;};
4089 : }
4090 : }
4091 : }
4092 :
4093 : //cout << pexp << endl;
4094 :
4095 0 : Int nOk2(ntrue(solveParOK()));
4096 0 : Int nFail=nOk1-nOk2;
4097 :
4098 : if (false) {
4099 : // Report some stuff re SNR
4100 : cout << endl
4101 : << "Time = " << MVTime(refTime()/C::day).string(MVTime::YMD,7) << endl;
4102 : cout << "SNR = " << solveParSNR() << endl;
4103 : cout << nOk1 << " " << nOk2 << " " << nFail << endl;
4104 : Float meansnr(0.0f);
4105 : if (ntrue(solveParOK())>0) {
4106 : meansnr=mean(solveParSNR()(solveParOK()));
4107 : cout << "mean solution SNR = " << meansnr
4108 : << " (passing threshold)."
4109 : << endl;
4110 : }
4111 : }
4112 :
4113 0 : if (nFail>0) {
4114 0 : cout << nFail << " of " << nOk1
4115 0 : << " solutions flagged due to SNR < " << minSNR()
4116 0 : << " in spw=" << currSpw();
4117 : // if multi-chan, report channel
4118 0 : if (freqDepPar())
4119 0 : cout << " (chan="<<focusChan()<<")";
4120 :
4121 0 : cout << " at " << MVTime(refTime()/C::day).string(MVTime::YMD,7)
4122 0 : << endl;
4123 : }
4124 :
4125 0 : }
4126 :
4127 : // Return the cal flag record, with tableName included
4128 0 : Record SolvableVisCal::actionRec() {
4129 0 : Record cf;
4130 0 : cf.define("table",calTableName());
4131 0 : cf.merge(VisCal::actionRec());
4132 0 : return cf;
4133 0 : }
4134 :
4135 31 : Record SolvableVisCal::solveActionRec() {
4136 :
4137 : // Return empty record
4138 : // TBD: consider returning various _generic_ info
4139 : // NB: specialization may add particulars via merge
4140 31 : Record r;
4141 31 : return r;
4142 : }
4143 :
4144 :
4145 :
4146 :
4147 :
4148 0 : void SolvableVisCal::smooth(Vector<Int>& fields,
4149 : const String& smtype,
4150 : const Double& smtime,
4151 : const bool ratesmooth) {
4152 :
4153 0 : if (smoothable())
4154 : // Call NewCalTable's global smooth method
4155 0 : casa::smoothCT(*ct_,smtype,smtime,fields,ratesmooth);
4156 : else
4157 0 : throw(AipsError("This type "+this->typeName()+" does not support smoothing!"));
4158 :
4159 0 : }
4160 :
4161 0 : void SolvableVisCal::syncSolveCal() {
4162 :
4163 0 : if (prtlev()>4) cout << " SVC::syncSolveCal()" << endl;
4164 :
4165 : // Ensure parameters are ready
4166 0 : syncSolvePar();
4167 :
4168 0 : if (!PValid())
4169 0 : throw(AipsError("No valid parameters in syncSolveCal"));
4170 :
4171 : // Sync up matrices using current params
4172 0 : syncCalMat(false); // NEVER invert in solve context
4173 0 : syncDiffMat();
4174 :
4175 0 : }
4176 0 : void SolvableVisCal::syncSolvePar() {
4177 :
4178 0 : if (prtlev()>5) cout << " SVC::syncSolvePar()" << endl;
4179 :
4180 : // In solve context, reference solveCPar(), etc.
4181 0 : AlwaysAssert((solveCPar().nelements()>0 || solveRPar().nelements()>0),AipsError);
4182 0 : currCPar().reference(solveCPar());
4183 0 : currRPar().reference(solveRPar());
4184 0 : currParOK().reference(solveParOK());
4185 0 : validateP();
4186 :
4187 0 : }
4188 :
4189 4680 : void SolvableVisCal::calcPar() {
4190 :
4191 4680 : if (simOnTheFly() and isSimulated()) {
4192 0 : if (prtlev()>3) cout << "SVC:calcPar triggered simOTF with isSolved=" << isSolved()
4193 0 : << " isApplied=" << isApplied() << " isSimulated=" << isSimulated() << endl;
4194 0 : syncSolvePar(); // OTF simulation context RI 20100831
4195 : } else {
4196 :
4197 4680 : if (prtlev()>6) cout << " SVC::calcPar()" << endl;
4198 :
4199 : // This method is relevant only to the apply (& simulate) context
4200 :
4201 : // If we have a CLPatchPanel, use it
4202 4680 : if (cpp_)
4203 2400 : this->calcParByCLPP();
4204 : else { // use CTPatchedInterp
4205 :
4206 2280 : Bool newcal(false);
4207 :
4208 : // Interpolate solution (CTPatchedInterp)
4209 2280 : if (freqDepPar()) {
4210 :
4211 : //cout << "currFreq() = " << currFreq().shape() << " " << currFreq() << endl;
4212 :
4213 : // Call w/ freq-dep
4214 0 : if (fInterpType().contains("rel")) {
4215 : // Relative freq
4216 0 : Double freqOff(msmc().centerFreq(currSpw()));
4217 0 : Double SBfactor(1.0);
4218 0 : if (currFreq().nelements()>1 && currFreq()(0)>currFreq()(1))
4219 0 : SBfactor=-1.0f;
4220 : //cout << "freqOff=" << freqOff << " SBfactor=" << SBfactor << " netSB=" << msmc().msmd().getNetSidebands()[currSpw()] << endl;
4221 0 : newcal=ci_->interpolate(currObs(),currScan(),currField(),currSpw(),currTime(),(currFreq()-freqOff)*SBfactor);
4222 : }
4223 : else
4224 : // absolute freq
4225 0 : newcal=ci_->interpolate(currObs(),currScan(),currField(),currSpw(),currTime(),currFreq());
4226 :
4227 : // cout.precision(12);
4228 : // cout << typeName() << " t="<< currTime() << " newcal=" << boolalpha << newcal << endl;
4229 : }
4230 : else {
4231 2280 : if (parType()==VisCalEnum::COMPLEX)
4232 : // Call w/ fiducial freq for phase-delay correction
4233 : // TBD: improve freq spec, e.g., use spw center freq rather than _selected_ center
4234 0 : newcal=ci_->interpolate(currObs(),currScan(),currField(),currSpw(),currTime(),1.0e9*currFreq()(currFreq().nelements()/2));
4235 : else
4236 : // No freq info at all
4237 2280 : newcal=ci_->interpolate(currObs(),currScan(),currField(),currSpw(),currTime());
4238 : }
4239 :
4240 : // TBD: signal failure to find calibration?? (e.g., for a spw?)
4241 :
4242 : // Parameters now (or still) valid (independent of newcal!!)
4243 2280 : validateP();
4244 :
4245 : // If new cal parameters, use them
4246 2280 : if (newcal) {
4247 :
4248 : // cout << "Found new cal!" << endl;
4249 :
4250 : // Reference result
4251 615 : if (parType()==VisCalEnum::COMPLEX)
4252 0 : currCPar().reference(ci_->resultC(currObs(),currScan(),currField(),currSpw()));
4253 615 : else if (parType()==VisCalEnum::REAL)
4254 615 : currRPar().reference(ci_->resultF(currObs(),currScan(),currField(),currSpw()));
4255 : else
4256 0 : throw(AipsError("Bad parType() in SVC::calcPar"));
4257 :
4258 : // Assign _inverse_ of parameter flags
4259 615 : currParOK().reference(!ci_->rflag(currObs(),currScan(),currField(),currSpw()));
4260 :
4261 : // Ensure shapes recorded correctly
4262 : // (New interpolation generates cal samples for all data channels...revisit?
4263 615 : IPosition ip=currCPar().shape();
4264 615 : nChanPar()=ip(1);
4265 615 : startChan()=0;
4266 :
4267 : // In case we need solution timestamp
4268 : // NB: w/ new caltables, we use currTime() here.
4269 615 : refTime() = currTime();
4270 :
4271 : // If new parameters, matrices (generically) are necessarily invalid now
4272 615 : invalidateCalMat();
4273 615 : }
4274 : }
4275 : }
4276 :
4277 4680 : }
4278 :
4279 2400 : void SolvableVisCal::calcParByCLPP() {
4280 :
4281 2400 : Bool newcal(false);
4282 2400 : Cube<Bool> resFlag;
4283 :
4284 : // Interpolate solution
4285 2400 : switch (parType()) {
4286 0 : case VisCalEnum::COMPLEX: {
4287 :
4288 0 : if (freqDepPar()) {
4289 : // Call w/ freq-dep
4290 0 : newcal=cpp_->interpolate(currCPar(),resFlag,currObs(),currScan(),currField(),currIntent(),currSpw(),currTime(),currFreq());
4291 : }
4292 : else {
4293 : // Call w/ fiducial freq for phase-delay correction
4294 0 : Double freq=1.0e9*currFreq()(currFreq().nelements()/2);
4295 0 : newcal=cpp_->interpolate(currCPar(),resFlag,currObs(),currScan(),currField(),currIntent(),currSpw(),currTime(),freq);
4296 : }
4297 0 : break;
4298 : }
4299 2400 : case VisCalEnum::REAL: {
4300 : // Interpolate solution
4301 2400 : if (freqDepPar()) {
4302 : // Call w/ freq-dep
4303 0 : newcal=cpp_->interpolate(currRPar(),resFlag,currObs(),currScan(),currField(),currIntent(),currSpw(),currTime(),currFreq());
4304 : }
4305 : else {
4306 2400 : newcal=cpp_->interpolate(currRPar(),resFlag,currObs(),currScan(),currField(),currIntent(),currSpw(),currTime(),-1.0);
4307 : }
4308 2400 : break;
4309 : }
4310 0 : default:
4311 0 : throw(AipsError("Unhandled parType()")); // users should never see this
4312 : break;
4313 : }
4314 :
4315 : // TBD: signal failure to find calibration?? (e.g., for a spw?)
4316 :
4317 : // Parameters now (or still) valid (independent of newcal!!)
4318 2400 : validateP();
4319 :
4320 2400 : if (newcal) {
4321 :
4322 : // Assign _inverse_ of parameter flags
4323 1208 : currParOK().reference(!resFlag);
4324 :
4325 : // Ensure shapes recorded correctly
4326 : // (New interpolation generates cal samples for all data channels...revisit?
4327 : // IS THIS NEEDED?
4328 1208 : IPosition ip=currCPar().shape();
4329 1208 : nChanPar()=ip(1);
4330 1208 : startChan()=0;
4331 :
4332 : // In case we need solution timestamp
4333 : // NB: w/ new caltables, we use currTime() here.
4334 1208 : refTime() = currTime();
4335 :
4336 : // If new parameters, matrices (generically) are necessarily invalid now
4337 1208 : invalidateCalMat();
4338 1208 : }
4339 :
4340 2400 : }
4341 :
4342 :
4343 : // Report solved-for QU
4344 0 : void SolvableVisCal::reportSolvedQU() {
4345 :
4346 0 : String fldname(msmc().fieldName(currField()));
4347 :
4348 0 : if (solvePol()==2) {
4349 0 : Float Q=real(srcPolPar()(0));
4350 0 : Float U=real(srcPolPar()(1));
4351 0 : Float P=sqrt(Q*Q + U*U);
4352 0 : Float X=atan2(U,Q)/2.0*180.0/M_PI;
4353 :
4354 : logSink() << "Fractional polarization solution for " << fldname
4355 0 : << " (spw = " << currSpw() << "): "
4356 : << ": Q = " << Q
4357 : << ", U = " << U
4358 : << " (P = " << P
4359 : << ", X = " << X << " deg)"
4360 0 : << LogIO::POST;
4361 : }
4362 0 : else if (solvePol()==1) {
4363 : logSink() << "Position angle offset solution for " << fldname
4364 0 : << " (spw = " << currSpw() << ") = "
4365 0 : << real(srcPolPar()(0))*180.0/M_PI/2.0
4366 : << " deg."
4367 0 : << LogIO::POST;
4368 : }
4369 0 : }
4370 :
4371 6 : void SolvableVisCal::createMemCalTable() {
4372 :
4373 : // cout << "createMemCalTable" << endl;
4374 :
4375 : // Set up description
4376 6 : String partype = ((parType()==VisCalEnum::COMPLEX) ? "Complex" : "Float");
4377 :
4378 6 : if (msName()!="<noms>") {
4379 12 : CTDesc caltabdesc(partype,Path(msName()).baseName(),typeName(),"unknown");
4380 6 : ct_ = new NewCalTable("tempNCT.tab",caltabdesc,Table::Scratch,Table::Memory)
4381 : ;
4382 6 : ct_->setMetaInfo(msName());
4383 6 : }
4384 : else {
4385 0 : ct_ = new NewCalTable("tempNCT.tab",partype,typeName(),msmc().ssp(),
4386 0 : false,true);
4387 : }
4388 :
4389 6 : CTColumns ncc(*ct_);
4390 :
4391 : // Revise SPW frequencies
4392 12 : for (Int ispw=0;ispw<nSpw();++ispw) {
4393 :
4394 6 : currSpw()=ispw;
4395 :
4396 : // MS freqs
4397 6 : Vector<Double> chfr,chwid,chres,cheff;
4398 6 : ncc.spectralWindow().chanFreq().get(ispw,chfr);
4399 6 : ncc.spectralWindow().chanWidth().get(ispw,chwid);
4400 6 : ncc.spectralWindow().resolution().get(ispw,chres);
4401 6 : ncc.spectralWindow().effectiveBW().get(ispw,cheff);
4402 :
4403 6 : Int nchan=0;
4404 6 : Vector<Double> calfreq,calwid,calres,caleff;
4405 6 : if (startChan()>-1 && nChanPar()>0) {
4406 :
4407 6 : if (freqDepPar()) {
4408 0 : if (fsolint()!="none") {
4409 0 : IPosition blc(1,0),trc(1,0);
4410 0 : Matrix<Int> bounds(chanAveBounds());
4411 0 : nchan=bounds.nrow();
4412 0 : calfreq.resize(nchan);
4413 0 : calwid.resize(nchan);
4414 0 : calres.resize(nchan);
4415 0 : caleff.resize(nchan);
4416 0 : cout.precision(12);
4417 0 : for (Int ochan=0;ochan<nchan;++ochan) {
4418 0 : blc(0)=bounds(ochan,0);
4419 0 : trc(0)=bounds(ochan,1);
4420 0 : calfreq(ochan)=mean(chfr(blc,trc));
4421 0 : calwid(ochan)=sum(chwid(blc,trc));
4422 0 : calres(ochan)=sum(chres(blc,trc));
4423 0 : caleff(ochan)=sum(cheff(blc,trc));
4424 : }
4425 0 : }
4426 : else {
4427 0 : nchan=nChanPar();
4428 0 : if (nChanPar()<Int(chfr.nelements())) {
4429 0 : calfreq=chfr(Slice(startChan(),nChanPar()));
4430 0 : calwid=chwid(Slice(startChan(),nChanPar()));
4431 0 : calres=chres(Slice(startChan(),nChanPar()));
4432 0 : caleff=cheff(Slice(startChan(),nChanPar()));
4433 : }
4434 : else {
4435 0 : calfreq.reference(chfr);
4436 0 : calwid.reference(chwid);
4437 0 : calres.reference(chres);
4438 0 : caleff.reference(cheff);
4439 : }
4440 : }
4441 : }
4442 : else {
4443 6 : nchan=1;
4444 6 : calfreq.resize(1);
4445 6 : calwid.resize(1);
4446 6 : calres.resize(1);
4447 6 : caleff.resize(1);
4448 : // Use simple mean freq, and aggregate bandwidth
4449 6 : calfreq(0)=mean(chfr);
4450 6 : calwid(0)=sum(chwid);
4451 6 : calres(0)=sum(chres);
4452 6 : caleff(0)=sum(cheff);
4453 : }
4454 : }
4455 : // cout << "nchan=" << nchan << " calfreq.nelements() = " << calfreq.nelements() << " " << calfreq << endl;
4456 6 : if (nchan>0) {
4457 6 : ncc.spectralWindow().chanFreq().setShape(ispw,IPosition(1,nchan));
4458 : // cout << "ncc.spectralWindow().chanFreq().shape(ispw) = " << ncc.spectralWindow().chanFreq().shape(ispw) << endl;
4459 6 : ncc.spectralWindow().chanFreq().put(ispw,calfreq);
4460 6 : ncc.spectralWindow().chanWidth().put(ispw,calwid);
4461 6 : ncc.spectralWindow().resolution().put(ispw,calres); // same as chanWidth, for now
4462 6 : ncc.spectralWindow().effectiveBW().put(ispw,caleff); // same as chanWidth, for now
4463 6 : ncc.spectralWindow().numChan().put(ispw,nchan);
4464 6 : ncc.spectralWindow().totalBandwidth().put(ispw,abs(sum(calwid)));
4465 : }
4466 : else
4467 0 : ncc.spectralWindow().flagRow().put(ispw,true);
4468 6 : }
4469 :
4470 : // When combining in spw, further revise freq info to average over combined spws
4471 : // Only for freqDepPar()=false types, for now (nothing bandpass-like)
4472 : // NB: Currently, this will only handle a single aggregation..., e.g., not CAS-5687
4473 6 : if (combspw() && !freqDepPar()) {
4474 :
4475 : try {
4476 :
4477 0 : Matrix<Double> chanFreq,chanWidth,effectiveBW;
4478 0 : ncc.spectralWindow().chanFreq().getColumn(chanFreq,true);
4479 0 : ncc.spectralWindow().chanWidth().getColumn(chanWidth,true);
4480 0 : ncc.spectralWindow().effectiveBW().getColumn(effectiveBW,true);
4481 :
4482 : // Insist on a single channel! (NO BANDPASS-LIKE TYPES!)
4483 0 : Int nChan=chanFreq.shape()[0];
4484 0 : AlwaysAssert(nChan==1,AipsError);
4485 :
4486 0 : Vector<Bool> spwmask=(spwMap()>-1);
4487 0 : Int outSpw=Vector<Int>(spwMap()(spwmask).getCompressedArray())[0];
4488 :
4489 : // If only one chan, then the chanWidth should span the the whole spw range
4490 : // NB: this is done before the chanFreq are revised, below
4491 : // NB: Disabled for now, since centroid freq +/- wid/2 doesn't actually
4492 : // cover the input spw range, in general....more thought necessary here
4493 : // So keep the single spw width, for now, for which there remains
4494 : // a reasonable argument (the phase correction is ~appropriate over this
4495 : // limited range without further refinement...) (the width isn't used
4496 : // decisively anywhere yet, in any case)
4497 : if (false) {
4498 :
4499 : Vector<Double> f(chanFreq.row(0));
4500 : Vector<Double> chW(chanWidth.row(0));
4501 : Vector<Double> flo=f-chW/2.0;
4502 : Vector<Double> fhi=f+chW/2.0;
4503 :
4504 : if (allGT(fhi,flo))
4505 : // USB (positive result)
4506 : chW(outSpw)=max(fhi(spwmask))-min(flo(spwmask));
4507 : else
4508 : // LSB (negative result)
4509 : chW(outSpw)=min(fhi(spwmask))-max(flo(spwmask));
4510 :
4511 : }
4512 :
4513 : // Assumes single channel!
4514 0 : Vector<Double> f(chanFreq.row(0));
4515 0 : Vector<Double> ebw(effectiveBW.row(0));
4516 0 : Double meanfreq=sum(f(spwmask)*ebw(spwmask));
4517 0 : Double sumebw=sum(ebw(spwmask));
4518 0 : meanfreq/=sumebw;
4519 :
4520 0 : f(outSpw)=meanfreq;
4521 0 : ebw(outSpw)=sumebw;
4522 :
4523 : /*
4524 : cout << "spwmask = " << boolalpha << spwmask << endl;
4525 : cout << "chanFreq(:,outSpw) = " << chanFreq.column(outSpw) << endl;
4526 : cout << "chanWidth(:,outSpw) = " << chanWidth.column(outSpw) << endl;
4527 : cout << "effectiveBW(:,outSpw) = " << effectiveBW.column(outSpw) << endl;
4528 : */
4529 :
4530 :
4531 0 : ncc.spectralWindow().chanFreq().putColumn(chanFreq);
4532 0 : ncc.spectralWindow().chanWidth().putColumn(chanWidth);
4533 0 : ncc.spectralWindow().effectiveBW().putColumn(effectiveBW);
4534 0 : }
4535 0 : catch (...) {
4536 0 : throw(AipsError("Error calculating solution frequencies w/ combine='spw'"));
4537 0 : }
4538 : }
4539 :
4540 6 : }
4541 :
4542 : // File a single-channel solved solution into the multi-channel space for it
4543 0 : void SolvableVisCal::keep1(Int ichan) {
4544 0 : if (parType()==VisCalEnum::COMPLEX)
4545 0 : solveAllCPar()(Slice(),Slice(ichan,1),Slice())=solveCPar();
4546 0 : else if (parType()==VisCalEnum::REAL)
4547 0 : solveAllRPar()(Slice(),Slice(ichan,1),Slice())=solveRPar();
4548 :
4549 0 : solveAllParOK()(Slice(),Slice(ichan,1),Slice())=solveParOK();
4550 0 : solveAllParErr()(Slice(),Slice(ichan,1),Slice())=solveParErr();
4551 0 : solveAllParSNR()(Slice(),Slice(ichan,1),Slice())=solveParSNR();
4552 0 : }
4553 :
4554 0 : Bool SolvableVisCal::spwOK(Int ispw) {
4555 :
4556 0 : if (isSolved())
4557 0 : return spwOK_(ispw);
4558 :
4559 0 : if (isApplied() && ci_)
4560 : // Get it from the interpolator (w/ spwmap)
4561 0 : return spwOK_(ispw)=ci_->spwOK(ispw);
4562 : else {
4563 : // Assume ok (e.g., non-ci_ types like TOpac, GainCurve)
4564 : // TBD: be more careful by specializing this method
4565 0 : return true;
4566 : }
4567 : }
4568 :
4569 : // Is the data in this VB calibrate-able? This replaces the old spwOK and
4570 : // is more specific as regards obs, fld, intent. Used at wide scopes
4571 : // (Calibrater/VisEquation) to control entering expensive loops.
4572 : // "OK for Cal" or "Calibrate-able" here means:
4573 : // a) this SVC can actually calibrate the data within the VB because
4574 : // there are solutions explicitly available to do it (see
4575 : // SVC::calAvailable(vb) below)
4576 : // OR
4577 : // b) that this SVC is agnostic about the data within the VB according
4578 : // to arrangements made by CalLibrary specifictions and
4579 : // embodied within the CLPatchPanel (cpp_). Agnosticism is
4580 : // supported ONLY when using the CalLibrary and CLPatchPanel
4581 4680 : Bool SolvableVisCal::VBOKforCalApply(vi::VisBuffer2& vb) {
4582 :
4583 : // Current spw
4584 : // TBD: Use syncMeta2?
4585 4680 : const Int& ispw(vb.spectralWindows()(0));
4586 :
4587 4680 : if (isSolved())
4588 0 : return spwOK_(ispw);
4589 :
4590 4680 : if (isApplied()) {
4591 :
4592 4680 : if (ci_)
4593 : // Get it from the old-fashioned CTPatchedInterp
4594 2280 : return spwOK_(ispw)=ci_->spwOK(ispw);
4595 :
4596 2400 : else if (cpp_) {
4597 : // Get it from the new CLPatchPanel, which has
4598 : // obs, fld, intent specificity, too!
4599 2400 : const Int& iobs(vb.observationId()(0));
4600 2400 : const Int& iscan(vb.scan()(0));
4601 2400 : const Int& ifld(vb.fieldId()(0));
4602 2400 : const Int& ient(vb.stateId()(0));
4603 2400 : return cpp_->MSIndicesOK(iobs,iscan,ifld,ient,ispw,-1); // all ants
4604 : }
4605 : else
4606 : // Assume ok for non-interpolable types
4607 0 : return true;
4608 : }
4609 :
4610 : // Shouldn't reach here, assume true (could trigger failure elsewhere)
4611 0 : return true;
4612 :
4613 : }
4614 :
4615 : // Is calibration for the specified VB actually available?
4616 : // This returns true when condition "a" described above
4617 : // is true. If the CLPatchPanel is agnostic, this returns
4618 : // false. This is used by VisCal::correct2 control whether
4619 : // calibration update and algebraic apply can/should be done.
4620 : // In the CalLibrary context, this enables agnosticism (when
4621 : // false)
4622 : // The implementation here is almost the same as VBOKforCal,
4623 : // differing only in the call to cpp_->calAvailable.
4624 4680 : Bool SolvableVisCal::calAvailable(vi::VisBuffer2& vb) {
4625 :
4626 : // Current spw
4627 : // TBD: Use syncMeta2?
4628 4680 : const Int& ispw(vb.spectralWindows()(0));
4629 :
4630 4680 : if (isSolved())
4631 0 : return spwOK_(ispw);
4632 :
4633 4680 : if (isApplied()) {
4634 :
4635 4680 : if (ci_)
4636 : // Get it from the old-fashioned CTPatchedInterp
4637 2280 : return spwOK_(ispw)=ci_->spwOK(ispw);
4638 :
4639 2400 : else if (cpp_) {
4640 : // Get it from the new CLPatchPanel, which has
4641 : // obs, fld, intent specificity, too!
4642 2400 : const Int& iobs(vb.observationId()(0));
4643 2400 : const Int& iscan(vb.scan()(0));
4644 2400 : const Int& ifld(vb.fieldId()(0));
4645 2400 : const Int& ient(vb.stateId()(0));
4646 2400 : return cpp_->calAvailable(iobs,iscan,ifld,ient,ispw,-1); // all ants
4647 : }
4648 : else
4649 : // Assume ok for non-interpolable types
4650 0 : return true;
4651 : }
4652 :
4653 : // Shouldn't reach here, assume true (could trigger failure elsewhere)
4654 0 : return true;
4655 :
4656 : }
4657 :
4658 :
4659 :
4660 : // File a solved solution (and meta-data) into the in-memory Caltable
4661 243 : void SolvableVisCal::keepNCT() {
4662 :
4663 : // TBD: set CalTable freq info here
4664 : // if (!spwOK(currSpw()))
4665 : // setSpwFreqInCT(currSpw(),currFreq());
4666 :
4667 243 : if (prtlev()>4)
4668 0 : cout << " SVC::keepNCT" << endl;
4669 :
4670 : // Add some rows to fill
4671 : // nElem() gets it right for both baseline- and antenna-based
4672 243 : ct_->addRow(nElem());
4673 :
4674 243 : CTMainColumns ncmc(*ct_);
4675 :
4676 : // We are adding to the most-recently added rows
4677 243 : RefRows rows(ct_->nrow()-nElem(),ct_->nrow()-1,1);
4678 :
4679 : // Meta-info
4680 243 : ncmc.time().putColumnCells(rows,Vector<Double>(nElem(),refTime()));
4681 243 : ncmc.fieldId().putColumnCells(rows,Vector<Int>(nElem(),currField()));
4682 243 : ncmc.spwId().putColumnCells(rows,Vector<Int>(nElem(),currSpw()));
4683 243 : ncmc.scanNo().putColumnCells(rows,Vector<Int>(nElem(),currScan()));
4684 243 : ncmc.obsId().putColumnCells(rows,Vector<Int>(nElem(),currObs()));
4685 243 : ncmc.interval().putColumnCells(rows,Vector<Double>(nElem(),0.0));
4686 :
4687 : // Params
4688 243 : if (parType()==VisCalEnum::COMPLEX)
4689 : // Fill Complex column
4690 18 : ncmc.cparam().putColumnCells(rows,solveAllCPar());
4691 225 : else if (parType()==VisCalEnum::REAL)
4692 : // Fill Float column
4693 225 : ncmc.fparam().putColumnCells(rows,solveAllRPar());
4694 :
4695 : // Stats
4696 243 : ncmc.paramerr().putColumnCells(rows,solveAllParErr());
4697 243 : ncmc.snr().putColumnCells(rows,solveAllParSNR());
4698 243 : ncmc.flag().putColumnCells(rows,!solveAllParOK());
4699 :
4700 : // This spw now has some solutions in it
4701 243 : spwOK_(currSpw())=true;
4702 :
4703 243 : }
4704 :
4705 0 : void SolvableVisCal::globalPostSolveTinker() {
4706 :
4707 : // Make solutions phase- or amp-only, if required
4708 0 : if (apmode()!="AP") enforceAPonSoln();
4709 :
4710 : // Apply normalization
4711 0 : if (solnorm()) normalize();
4712 :
4713 0 : }
4714 :
4715 : // Divide all solutions by their amplitudes to make them "phase-only"
4716 0 : void SolvableVisCal::enforceAPonSoln() {
4717 :
4718 : // VI2: review initializatin of apmode! (and similar!)
4719 0 : if (apmode()=="") return;
4720 :
4721 : // Only if we have a CalTable, and it is not empty
4722 0 : if (ct_ && ct_->nrow()>0) {
4723 :
4724 : // TBD: trap attempts to enforceAPonSoln a caltable containing FPARAM (non-Complex)?
4725 :
4726 : logSink() << "Enforcing apmode on solutions."
4727 0 : << LogIO::POST;
4728 :
4729 : // In this generic version, one normalization factor per spw
4730 0 : Block<String> col(3);
4731 0 : col[0]="SPECTRAL_WINDOW_ID";
4732 0 : col[1]="TIME";
4733 0 : col[2]="ANTENNA1";
4734 0 : CTIter ctiter(*ct_,col);
4735 :
4736 0 : while (!ctiter.pastEnd()) {
4737 :
4738 0 : Array<Complex> par(ctiter.cparam());
4739 0 : Array<Bool> fl(ctiter.flag());
4740 0 : Array<Float> amps(amplitude(par));
4741 0 : par(amps==0.0f)=Complex(1.0);
4742 0 : par(fl)=Complex(1.0);
4743 0 : amps(amps==0.0f)=1.0f;
4744 0 : amps(fl)=1.0f;
4745 :
4746 0 : Array<Complex> cor(amps.shape());
4747 0 : if (apmode()=='P')
4748 : // we will scale solns by amp to make them phase-only
4749 0 : convertArray(cor,amps);
4750 0 : else if (apmode()=='A') {
4751 : // we will scale solns by "phase" to make them amp-only
4752 0 : cor=par;
4753 0 : cor/=amps;
4754 : }
4755 :
4756 0 : if (ntrue(amplitude(cor)==0.0f)==0)
4757 0 : par/=cor;
4758 : else
4759 0 : throw(AipsError("enforceAPonSoln divide-by-zero error."));
4760 :
4761 : // put result back
4762 0 : ctiter.setcparam(par);
4763 :
4764 : // advance iterator
4765 0 : ctiter.next();
4766 0 : }
4767 :
4768 :
4769 0 : }
4770 : else
4771 0 : throw(AipsError("Solution apmode enforcement not supported."));
4772 :
4773 : }
4774 :
4775 0 : void SolvableVisCal::normalize() {
4776 :
4777 : // Only if we have a CalTable, and it is not empty
4778 0 : if (ct_ && ct_->nrow()>0) {
4779 :
4780 : // TBD: trap attempts to normalize a caltable containing FPARAM (non-Complex)?
4781 :
4782 0 : logSink() << "Normalizing solution amplitudes per spw with " << solNorm().normtypeString()
4783 0 : << LogIO::POST;
4784 :
4785 : // In this generic version, one normalization factor per spw
4786 0 : Block<String> col(1);
4787 0 : col[0]="SPECTRAL_WINDOW_ID";
4788 0 : CTIter ctiter(*ct_,col);
4789 :
4790 0 : while (!ctiter.pastEnd()) {
4791 0 : Cube<Complex> p(ctiter.cparam());
4792 0 : Cube<Bool> fl(ctiter.flag());
4793 0 : if (nfalse(fl)>0) {
4794 0 : Complex normfactor=normSolnArray(p,!fl,false); // don't do phase
4795 0 : logSink() << " Normalization factor (" << solNorm().normtypeString() << ") for spw " << ctiter.thisSpw() << " = " << abs(normfactor)
4796 0 : << LogIO::POST;
4797 :
4798 : // record result...
4799 0 : ctiter.setcparam(p);
4800 : }
4801 0 : ctiter.next();
4802 0 : }
4803 :
4804 0 : }
4805 0 : }
4806 :
4807 60 : void SolvableVisCal::storeNCT() {
4808 :
4809 60 : if (prtlev()>3) cout << " SVC::storeNCT()" << endl;
4810 :
4811 : // Escape from attempt to write to an empty name,
4812 : // because this may delete more than one wants
4813 60 : if (calTableName().empty())
4814 0 : throw(AipsError("Empty string provided for caltable name; this is not allowed."));
4815 :
4816 : // Flag spws that didn't occur (should do for other meta-info!)
4817 60 : ct_->flagAbsentSpws();
4818 :
4819 : // If append=T and the specified table exists...
4820 60 : if (append() && Table::isReadable(calTableName())) {
4821 :
4822 : // Verify the same type
4823 1 : verifyCalTable(calTableName());
4824 :
4825 1 : logSink() << "Appending solutions to table: " << calTableName()
4826 1 : << LogIO::POST;
4827 :
4828 : // Keep the new in-memory caltable locally
4829 1 : NewCalTable *newct=ct_;
4830 1 : ct_=NULL;
4831 :
4832 : // Load the existing table (ct_)
4833 1 : loadMemCalTable(calTableName());
4834 :
4835 : // Verify that both caltables come from the same MS
4836 : try {
4837 1 : String msn0=ct_->keywordSet().asString("MSName");
4838 1 : String msn1=newct->keywordSet().asString("MSName");
4839 1 : AlwaysAssert( msn0==msn1, AipsError);
4840 1 : }
4841 0 : catch ( AipsError err ) {
4842 0 : delete newct; // ct_ will be deleted in dtor
4843 0 : throw(AipsError("Cannot append solutions from different MS."));
4844 0 : }
4845 :
4846 : // Merge spw info (carefully) from newct to ct_
4847 : try {
4848 1 : ct_->mergeSpwMetaInfo(*newct);
4849 : }
4850 0 : catch ( AipsError err ) {
4851 0 : logSink() << err.getMesg() << LogIO::SEVERE;
4852 0 : throw(AipsError("Error attempting append=T"));
4853 0 : }
4854 :
4855 : // copy the new onto the existing...
4856 1 : TableCopy::copyRows(*ct_,*newct,ct_->nrow(),0,newct->nrow());
4857 :
4858 : // Delete the local pointer to the new solutions
4859 : // NB: ct_ will be deleted by dtor (after writeToDisk below)
4860 1 : delete newct;
4861 :
4862 : // At this point, ct_ contains old and new solutions in memory
4863 :
4864 : }
4865 : else
4866 59 : logSink() << "Writing solutions to table: " << calTableName()
4867 59 : << LogIO::POST;
4868 :
4869 : // Write out the table to disk (regardless of what happened above)
4870 : // (this will sort)
4871 60 : ct_->writeToDisk(calTableName());
4872 :
4873 60 : }
4874 :
4875 29 : void SolvableVisCal::storeNCT(const String& table,const Bool& append) {
4876 :
4877 29 : if (prtlev()>3) cout << " SVC::store(table,append)" << endl;
4878 :
4879 : // Override tablename
4880 29 : calTableName()=table;
4881 29 : SolvableVisCal::append()=append;
4882 :
4883 : // Call conventional store
4884 29 : storeNCT();
4885 :
4886 29 : }
4887 :
4888 35 : void SolvableVisCal::loadMemCalTable(String ctname,String field) {
4889 35 : if (field.length()>0) {
4890 : // Open whole table (on disk);
4891 0 : NewCalTable wholect(NewCalTable::createCT(ctname,Table::Old,Table::Memory));
4892 0 : ct_ = new NewCalTable(wholect); // Make sure ct_ contains a real object
4893 :
4894 : // Prepare to select on it
4895 0 : CTInterface cti(wholect);
4896 0 : MSSelection mss;
4897 : // mss.reset(cti,MSSelection::PARSE_LATE,"","",field);
4898 0 : mss.setFieldExpr(field);
4899 0 : TableExprNode ten=mss.toTableExprNode(&cti);
4900 : //cout << "Selected field list: " << mss.getFieldList() << endl;
4901 :
4902 : // Apply selection to table
4903 : try {
4904 0 : getSelectedTable(*ct_,wholect,ten,"");
4905 0 : } catch (AipsError x) {
4906 0 : logSink() << x.getMesg() << LogIO::SEVERE;
4907 0 : throw(AipsError("Error selecting on caltable: "+ctname+"... "));
4908 0 : }
4909 :
4910 0 : }
4911 : else
4912 : // No selection
4913 35 : ct_ = new NewCalTable(NewCalTable::createCT(ctname,Table::Old,Table::Memory));
4914 :
4915 :
4916 :
4917 : // Fill nChanParList from the Caltable
4918 : // (this may be revised by calcPar)
4919 :
4920 : // This should not be needed anymore (and it breaks portability)
4921 : // MSSpWindowColumns spwcol(ct_->spectralWindow());
4922 : // nChanParList().assign(spwcol.numChan().getColumn());
4923 :
4924 35 : }
4925 :
4926 0 : void SolvableVisCal::stateSVC(const Bool& doVC) {
4927 :
4928 : // If requested, report VisCal state
4929 0 : if (doVC) VisCal::state();
4930 :
4931 0 : if (prtlev()>3) cout << "SVC::stateSVC():" << endl;
4932 0 : cout << boolalpha;
4933 :
4934 : // Now SVC-specific stuff:
4935 0 : cout << " isSolved() = " << isSolved() << endl;
4936 0 : cout << " calTableName() = " << calTableName() << endl;
4937 0 : cout << " calTableSelect() = " << calTableSelect() << endl;
4938 0 : cout << " apmode() = " << apmode() << endl;
4939 0 : cout << " phandonly() = " << phandonly() << endl;
4940 0 : cout << " tInterpType() = " << tInterpType() << endl;
4941 0 : cout << " fInterpType() = " << fInterpType() << endl;
4942 0 : cout << " spwMap() = " << spwMap() << endl;
4943 0 : cout << " refantmode() = " << refantmode() << endl;
4944 0 : cout << " refant() = " << refant() << endl;
4945 0 : cout << " refantlist() = " << refantlist() << endl;
4946 0 : cout << " solmode = " << solmode() << endl;
4947 0 : cout << " rmsthresh = " << rmsthresh() << endl;
4948 :
4949 0 : cout << " solveCPar().shape() = " << solveCPar().shape()
4950 0 : << " (" << solveCPar().data() << ")" << endl;
4951 0 : cout << " solveRPar().shape() = " << solveRPar().shape()
4952 0 : << " (" << solveRPar().data() << ")" << endl;
4953 0 : cout << " solveParOK().shape() = " << solveParOK().shape()
4954 0 : << " (" << solveParOK().data() << ") "
4955 0 : << " (ntrue=" << ntrue(solveParOK()) << ")" << endl;
4956 :
4957 0 : cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" << endl;
4958 :
4959 0 : }
4960 :
4961 0 : Complex SolvableVisCal::normSolnArray(Array<Complex>& sol,
4962 : const Array<Bool>& solOK,
4963 : const Bool doPhase) {
4964 :
4965 : // Only do something if 2 or more good solutions
4966 0 : Complex factor(1.0);
4967 0 : if (ntrue(solOK)>1) {
4968 :
4969 :
4970 0 : Array<Float> amp(amplitude(sol));
4971 :
4972 : // If desired, determine phase part of the normalization
4973 0 : if (doPhase) {
4974 : // Prepare to divide by amplitudes indiscriminately
4975 0 : amp(!solOK)=1.0f;
4976 0 : Array<Complex> sol1=sol/amp;
4977 0 : sol1(!solOK)=Complex(0.0);
4978 0 : factor=sum(sol1);
4979 0 : factor/=abs(factor);
4980 0 : }
4981 :
4982 : // Determine amplitude normalization factor
4983 0 : factor*=calcPowerNorm(amp,solOK);
4984 :
4985 : // Apply the normalization factor, if non-zero
4986 0 : if (abs(factor) > 0.0)
4987 0 : sol/=factor;
4988 :
4989 0 : } // ntrue > 0
4990 :
4991 : // Return the net normlization factor
4992 0 : return factor;
4993 :
4994 : }
4995 :
4996 :
4997 :
4998 0 : void SolvableVisCal::currMetaNote() {
4999 :
5000 : cout << " ("
5001 0 : << "time=" << MVTime(refTime()/C::day).string(MVTime::YMD,7)
5002 0 : << " field=" << currField()
5003 0 : << " spw=" << currSpw()
5004 0 : << " chan=" << focusChan()
5005 0 : << ")"
5006 0 : << endl;
5007 :
5008 0 : }
5009 :
5010 68 : void SolvableVisCal::initSVC() {
5011 :
5012 68 : if (prtlev()>2) cout << " SVC::initSVC()" << endl;
5013 :
5014 306 : for (Int ispw=0;ispw<nSpw(); ispw++) {
5015 :
5016 : // TBD: Would like to make this parType()-dependent,
5017 : // but parType() isn't initialized yet...
5018 :
5019 : // if (parType()==VisCalEnum::COMPLEX) {
5020 238 : solveCPar_[ispw] = new Cube<Complex>();
5021 238 : solveAllCPar_[ispw] = new Cube<Complex>();
5022 : // }
5023 : // else if (parType()==VisCalEnum::REAL) {
5024 238 : solveRPar_[ispw] = new Cube<Float>();
5025 238 : solveAllRPar_[ispw] = new Cube<Float>();
5026 : // }
5027 238 : solveParOK_[ispw] = new Cube<Bool>();
5028 238 : solveParErr_[ispw] = new Cube<Float>();
5029 238 : solveParSNR_[ispw] = new Cube<Float>();
5030 238 : solveAllParOK_[ispw] = new Cube<Bool>();
5031 238 : solveAllParErr_[ispw] = new Cube<Float>();
5032 238 : solveAllParSNR_[ispw] = new Cube<Float>();
5033 : }
5034 :
5035 68 : parType_=VisCalEnum::COMPLEX;
5036 :
5037 68 : }
5038 :
5039 68 : void SolvableVisCal::deleteSVC() {
5040 :
5041 68 : if (prtlev()>2) cout << " SVC::deleteSVC()" << endl;
5042 :
5043 306 : for (Int ispw=0; ispw<nSpw(); ispw++) {
5044 238 : if (solveCPar_[ispw]) delete solveCPar_[ispw];
5045 238 : if (solveRPar_[ispw]) delete solveRPar_[ispw];
5046 238 : if (solveParOK_[ispw]) delete solveParOK_[ispw];
5047 238 : if (solveParErr_[ispw]) delete solveParErr_[ispw];
5048 238 : if (solveParSNR_[ispw]) delete solveParSNR_[ispw];
5049 238 : if (solveAllCPar_[ispw]) delete solveAllCPar_[ispw];
5050 238 : if (solveAllRPar_[ispw]) delete solveAllRPar_[ispw];
5051 238 : if (solveAllParOK_[ispw]) delete solveAllParOK_[ispw];
5052 238 : if (solveAllParErr_[ispw]) delete solveAllParErr_[ispw];
5053 238 : if (solveAllParSNR_[ispw]) delete solveAllParSNR_[ispw];
5054 : }
5055 68 : solveCPar_=NULL;
5056 68 : solveRPar_=NULL;
5057 68 : solveParOK_=NULL;
5058 68 : solveParErr_=NULL;
5059 68 : solveParSNR_=NULL;
5060 68 : solveAllCPar_=NULL;
5061 68 : solveAllRPar_=NULL;
5062 68 : solveAllParOK_=NULL;
5063 68 : solveAllParErr_=NULL;
5064 68 : solveAllParSNR_=NULL;
5065 68 : }
5066 :
5067 37 : void SolvableVisCal::verifyCalTable(const String& caltablename) {
5068 :
5069 : // Call external method to get type (will throw if bad table)
5070 37 : String calType=calTableType(caltablename);
5071 :
5072 : // Check if proper Calibration type...
5073 37 : if (calType!=typeName()) {
5074 0 : ostringstream o;
5075 0 : o << "Table " << caltablename
5076 0 : << " has wrong Calibration type: " << calType
5077 0 : << " (expected: " << typeName() << ")";
5078 0 : throw(AipsError(String(o)));
5079 0 : }
5080 37 : }
5081 :
5082 0 : void SolvableVisCal::applyChanMask(VisBuffer& vb) {
5083 :
5084 0 : if (chanmask_) {
5085 :
5086 : // A reference to de-referenced pointer
5087 0 : PtrBlock<Vector<Bool>*>& chmask(*chanmask_);
5088 :
5089 0 : Int spw=vb.spectralWindow();
5090 0 : Int chan0=vb.channel()(0);
5091 0 : Int nchan=vb.nChannel();
5092 0 : if (chmask.nelements()==uInt(nSpw()) &&
5093 0 : chmask[spw] &&
5094 0 : sum((*chmask[spw])(Slice(chan0,nchan))) > 0 ) {
5095 : // There are some channels to mask...
5096 0 : Vector<Bool> fr(vb.flagRow());
5097 0 : Matrix<Bool> f(vb.flag());
5098 0 : Vector<Bool> fc;
5099 0 : Vector<Bool> chm((*(*chanmask_)[spw])(Slice(chan0,nchan)));
5100 0 : for (Int irow=0;irow<vb.nRow();++irow)
5101 0 : if (!fr(irow)) {
5102 0 : fc.reference(f.column(irow));
5103 0 : fc = fc||chm;
5104 :
5105 : // cout << irow << ": ";
5106 : // for (Int j=0;j<nchan;++j) cout << fc(j);
5107 : // cout << endl;
5108 :
5109 : }
5110 0 : }
5111 : }
5112 :
5113 0 : }
5114 : //
5115 : //-----------------------------------------------------------------------
5116 : //
5117 0 : void SolvableVisCal::printActivity(const Int nSlots, const Int slotNo,
5118 : const Int fieldId, const Int spw,
5119 : const Int nSolutions)
5120 : {
5121 : Int nMesg;
5122 :
5123 : // nSlots = rcs().nTime(spw);
5124 :
5125 0 : Double timeTaken = timer_p.all();
5126 0 : if (maxTimePerSolution_p < timeTaken) maxTimePerSolution_p = timeTaken;
5127 0 : if (minTimePerSolution_p > timeTaken) minTimePerSolution_p = timeTaken;
5128 0 : avgTimePerSolution_p += timeTaken;
5129 0 : Double avgT = avgTimePerSolution_p/(nSolutions>0?nSolutions:1);
5130 : //
5131 : // Boost the no. of messages printed if the next message, based on
5132 : // the average time per solution, is going to appear after a time
5133 : // longer than your patience would permit! The limit of
5134 : // patience defaults to 1h.
5135 : //
5136 0 : Float boost = userPrintActivityInterval_p/avgT;
5137 0 : boost = userPrintActivityInterval_p/avgT;
5138 0 : boost = (boost < 1.0)? 1.0 : nSlots*userPrintActivityFraction_p;
5139 0 : nMesg = (Int)boost;
5140 :
5141 0 : Int tmp=abs(nSlots-slotNo); Bool print;
5142 0 : print = false;
5143 0 : if (nMesg <= 0) print=false;
5144 0 : else if ((slotNo == 0) || (slotNo == nSlots-1)) print=true;
5145 0 : else if ((tmp > 0 ) && ((slotNo+1)%nMesg ==0)) print=true;
5146 0 : else print=false;
5147 :
5148 0 : if (print)
5149 : {
5150 0 : Int f = (Int)(100*(slotNo+1)/(nSlots>0?nSlots:1));
5151 : logSink()<< LogIO::NORMAL
5152 : << "Spw=" << spw << " slot=" << slotNo << "/" << nSlots
5153 : << " field=" << fieldId << ". Done " << f << "%"
5154 : << " Time taken per solution (max/min/avg): "
5155 : << maxTimePerSolution_p << "/"
5156 0 : << (minTimePerSolution_p<0?1:minTimePerSolution_p) << "/"
5157 0 : << avgT << " sec" << LogIO::POST;
5158 : }
5159 0 : }
5160 :
5161 : // **********************************************************
5162 : // SolvableVisMueller Implementations
5163 : //
5164 :
5165 :
5166 0 : SolvableVisMueller::SolvableVisMueller(VisSet& vs) :
5167 : VisCal(vs),
5168 : VisMueller(vs),
5169 : SolvableVisCal(vs),
5170 0 : dM_(NULL),
5171 0 : diffMElem_(),
5172 0 : DMValid_(false)
5173 : {
5174 0 : if (prtlev()>2) cout << "SVM::SVM(vs)" << endl;
5175 0 : }
5176 :
5177 0 : SolvableVisMueller::SolvableVisMueller(String msname,Int MSnAnt,Int MSnSpw) :
5178 : VisCal(msname,MSnAnt,MSnSpw),
5179 : VisMueller(msname,MSnAnt,MSnSpw),
5180 : SolvableVisCal(msname,MSnAnt,MSnSpw),
5181 0 : dM_(NULL),
5182 0 : diffMElem_(),
5183 0 : DMValid_(false)
5184 : {
5185 0 : if (prtlev()>2) cout << "SVM::SVM(msname,MSnAnt,MSnSpw)" << endl;
5186 0 : }
5187 :
5188 68 : SolvableVisMueller::SolvableVisMueller(const MSMetaInfoForCal& msmc) :
5189 : VisCal(msmc),
5190 : VisMueller(msmc),
5191 : SolvableVisCal(msmc),
5192 68 : dM_(NULL),
5193 68 : diffMElem_(),
5194 68 : DMValid_(False)
5195 : {
5196 68 : if (prtlev()>2) cout << "SVM::SVM(msmc)" << endl;
5197 68 : }
5198 :
5199 0 : SolvableVisMueller::SolvableVisMueller(const Int& nAnt) :
5200 : VisCal(nAnt),
5201 : VisMueller(nAnt),
5202 : SolvableVisCal(nAnt),
5203 0 : dM_(NULL),
5204 0 : diffMElem_(),
5205 0 : DMValid_(false)
5206 : {
5207 0 : if (prtlev()>2) cout << "SVM::SVM(i,j,k)" << endl;
5208 0 : }
5209 :
5210 68 : SolvableVisMueller::~SolvableVisMueller() {
5211 :
5212 68 : if (prtlev()>2) cout << "SVM::~SVM()" << endl;
5213 :
5214 68 : }
5215 :
5216 : // Setup solvePar shape (Mueller version)
5217 0 : void SolvableVisMueller::initSolvePar() {
5218 :
5219 : // TBD: NCT: attention to solveAllPar
5220 :
5221 0 : if (prtlev()>3) cout << " SVM::initSolvePar()" << endl;
5222 :
5223 0 : for (Int ispw=0;ispw<nSpw();++ispw) {
5224 :
5225 0 : currSpw()=ispw;
5226 :
5227 0 : switch(parType()) {
5228 0 : case VisCalEnum::COMPLEX: {
5229 0 : solveAllCPar().resize(nPar(),nChanPar(),nBln());
5230 0 : solveAllCPar()=Complex(1.0);
5231 0 : solveCPar().reference(solveAllCPar());
5232 0 : break;
5233 : }
5234 0 : case VisCalEnum::REAL: {
5235 0 : solveAllRPar().resize(nPar(),nChanPar(),nBln());
5236 0 : solveAllRPar()=0.0;
5237 0 : solveRPar().reference(solveAllRPar());
5238 0 : break;
5239 : }
5240 0 : case VisCalEnum::COMPLEXREAL: {
5241 0 : throw(AipsError("Internal error(Calibrater Module): Unsupported parameter type "
5242 0 : "COMPLEXREAL found in SolvableVisMueller::initSolvePar()"));
5243 : break;
5244 : }
5245 : }//switch
5246 :
5247 0 : solveAllParOK().resize(nPar(),nChanPar(),nBln());
5248 0 : solveAllParErr().resize(nPar(),nChanPar(),nBln());
5249 0 : solveAllParSNR().resize(nPar(),nChanPar(),nBln());
5250 0 : solveAllParOK()=true;
5251 0 : solveAllParErr()=0.0;
5252 0 : solveAllParSNR()=0.0;
5253 0 : solveParOK().reference(solveAllParOK());
5254 0 : solveParErr().reference(solveAllParErr());
5255 0 : solveParSNR().reference(solveAllParSNR());
5256 : }
5257 0 : currSpw()=0;
5258 0 : }
5259 :
5260 0 : void SolvableVisMueller::syncDiffMat() {
5261 :
5262 0 : if (prtlev()>5) cout << " SVM::syncDiffMat()"
5263 0 : << " (DMValid()=" << DMValid() << ")" << endl;
5264 :
5265 : // Sync the diff'd Mueller matrices
5266 0 : if (!DMValid()) syncDiffMueller();
5267 :
5268 0 : }
5269 :
5270 0 : void SolvableVisMueller::syncDiffMueller() {
5271 :
5272 0 : if (prtlev()>6) cout << " SVM::syncDiffMueller()" << endl;
5273 :
5274 : // TBD: validateDM() for trivialMuellerElem()=true??
5275 : // (cf. where does invalidateDM() occur?)
5276 :
5277 0 : if (trivialDM())
5278 : // Ensure trivial matrices ready
5279 0 : initTrivDM();
5280 : else {
5281 0 : diffMElem().resize(IPosition(4,muellerNPar(muellerType()),nPar(),nChanMat(),nCalMat()));
5282 0 : diffMElem().unique();
5283 0 : invalidateDM();
5284 :
5285 : // Calculate for all blns/chans
5286 0 : calcAllDiffMueller();
5287 :
5288 : }
5289 :
5290 : // Ensure diff'd Mueller matrix renders are OK
5291 0 : createDiffMueller();
5292 :
5293 : // diff'd Mueller matrices now valid
5294 0 : validateDM();
5295 :
5296 0 : }
5297 :
5298 0 : void SolvableVisMueller::calcAllDiffMueller() {
5299 :
5300 0 : if (prtlev()>6) cout << " SVM::calcAllDiffMueller" << endl;
5301 :
5302 : // Should handle OK flags in this method, and only
5303 : // do calc if OK
5304 :
5305 : // Sanity check on parameter channel axis
5306 0 : AlwaysAssert((solveCPar().shape()(1)==1),AipsError);
5307 :
5308 : // Referencing arrays, per baseline
5309 0 : Matrix<Complex> oneDM; // (nElem,nPar)
5310 0 : Vector<Complex> onePar; // (nPar)
5311 :
5312 0 : ArrayIterator<Complex> dMiter(diffMElem(),2);
5313 0 : ArrayIterator<Complex> Piter(solveCPar(),1);
5314 :
5315 0 : for (Int ibln=0; ibln<nCalMat(); ++ibln) {
5316 :
5317 : // Solving parameters are NEVER channel-dependent
5318 : // (even if data & matrices are)
5319 0 : onePar.reference(Piter.array());
5320 :
5321 0 : for (Int ich=0; ich<nChanMat(); ich++) {
5322 :
5323 0 : oneDM.reference(dMiter.array());
5324 :
5325 : // Calculate the DM matrices for each par on this bln/chan
5326 0 : calcOneDiffMueller(oneDM,onePar);
5327 :
5328 : // Advance iterators
5329 0 : dMiter.next();
5330 :
5331 : }
5332 0 : Piter.next();
5333 : }
5334 :
5335 0 : }
5336 :
5337 0 : void SolvableVisMueller::calcOneDiffMueller(Matrix<Complex>&,
5338 : const Vector<Complex>&) {
5339 :
5340 0 : if (prtlev()>10) cout << " SVM::calcOneDiffMueller()" << endl;
5341 :
5342 : // If Mueller matrix is trivial, shouldn't get here
5343 0 : if (trivialMuellerElem())
5344 0 : throw(AipsError("Trivial Mueller Matrix logic error."));
5345 :
5346 : // Otherwise, this method apparently hasn't been specialized, as required
5347 : else
5348 0 : throw(AipsError("Unknown non-trivial dMueller-from-parameter calculation requested."));
5349 :
5350 : }
5351 :
5352 0 : void SolvableVisMueller::createDiffMueller() {
5353 :
5354 0 : if (prtlev()>6) cout << " SVM::createDiffMueller()" << endl;
5355 :
5356 0 : Mueller::MuellerType mtype(muellerType());
5357 :
5358 : // Delete if wrong type
5359 0 : if (dM_ && dM().type() != mtype) delete dM_;
5360 :
5361 : // If needed, construct the correct diff Mueller
5362 0 : if (!dM_) dM_ = casa::createMueller(mtype);
5363 :
5364 0 : }
5365 :
5366 0 : void SolvableVisMueller::initTrivDM() {
5367 :
5368 0 : if (prtlev()>7) cout << " SVM::initTrivDM()" << endl;
5369 :
5370 : // If DM matrice not trivial, shouldn't get here
5371 0 : if (!trivialDM())
5372 0 : throw(AipsError("Trivial Mueller Matrix logic error."));
5373 :
5374 : // Otherwise, this method apparently hasn't been specialized, as required
5375 : else
5376 0 : throw(AipsError("Unknown trivial dM initialization requested."));
5377 :
5378 : }
5379 :
5380 : // File a solved solution (and meta-data) into the in-memory Caltable
5381 0 : void SolvableVisMueller::keepNCT() {
5382 :
5383 : // Call parent to do general stuff
5384 : // This adds nElem() rows
5385 0 : SolvableVisCal::keepNCT();
5386 :
5387 0 : if (prtlev()>4)
5388 0 : cout << " SVM::keepNCT" << endl;
5389 :
5390 : // Form antenna pairs
5391 0 : Vector<Int> a1(nElem()),a2(nElem());
5392 0 : Int k=0;
5393 0 : for (Int i=0;i<nAnt();++i)
5394 0 : for (Int j=i;j<nAnt();++j) {
5395 0 : a1(k)=i;
5396 0 : a2(k)=j;
5397 0 : ++k;
5398 : }
5399 :
5400 : // We are adding to the most-recently added rows
5401 0 : RefRows rows(ct_->nrow()-nElem(),ct_->nrow()-1,1);
5402 :
5403 : // Write to table
5404 0 : CTMainColumns ncmc(*ct_);
5405 0 : ncmc.antenna1().putColumnCells(rows,a1);
5406 0 : ncmc.antenna2().putColumnCells(rows,a2);
5407 :
5408 0 : }
5409 :
5410 :
5411 0 : void SolvableVisMueller::stateSVM(const Bool& doVC) {
5412 :
5413 : // If requested, report VisCal state
5414 0 : if (doVC) VisMueller::state();
5415 :
5416 : // Get parent's state (w/out VC):
5417 0 : SolvableVisCal::stateSVC(false);
5418 :
5419 0 : if (applyByMueller()) {
5420 0 : if (prtlev()>3) cout << "SVM::stateSVM()" << endl;
5421 0 : cout << boolalpha;
5422 :
5423 : // Now SVM-specific stuff:
5424 0 : cout << "DMValid() = " << DMValid() << endl;
5425 0 : cout << "diffMElem().shape() = " << diffMElem().shape()
5426 0 : << " (" << diffMElem().data() << ")" << endl;
5427 :
5428 0 : cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" << endl;
5429 : }
5430 0 : }
5431 :
5432 0 : Float SolvableVisMueller::calcPowerNorm(Array<Float>& amp, const Array<Bool>& ok) {
5433 :
5434 : // SVM version assumes amp already in power units
5435 0 : Array<Float> a2;
5436 0 : a2.assign(amp);
5437 0 : a2(!ok)=0.0; // zero flagged samples
5438 :
5439 0 : Float norm(1.0);
5440 0 : switch (solNorm().normtype()) {
5441 0 : case SolNorm::MEAN: {
5442 0 : Float n=Float(ntrue(ok));
5443 0 : if (n>0.0)
5444 0 : norm=sum(a2)/n;
5445 0 : break;
5446 : }
5447 0 : case SolNorm::MEDIAN: {
5448 0 : MaskedArray<Float> a2masked(a2,ok);
5449 0 : norm=median(a2masked,false,true); // unsorted, do mean when even
5450 0 : break;
5451 0 : }
5452 0 : default:
5453 0 : throw(AipsError("Proper normalization type not specified."));
5454 : break;
5455 : }
5456 0 : return norm;
5457 0 : }
5458 :
5459 :
5460 : // **********************************************************
5461 : // SolvableVisJones Implementations
5462 : //
5463 :
5464 :
5465 0 : SolvableVisJones::SolvableVisJones(VisSet& vs) :
5466 : VisCal(vs), // virtual base
5467 : VisMueller(vs), // virtual base
5468 : SolvableVisMueller(vs), // immediate parent
5469 : VisJones(vs), // immediate parent
5470 0 : dJ1_(NULL), // data...
5471 0 : dJ2_(NULL),
5472 0 : diffJElem_(),
5473 0 : DJValid_(false)
5474 : {
5475 0 : if (prtlev()>2) cout << "SVJ::SVJ(vs)" << endl;
5476 0 : }
5477 :
5478 0 : SolvableVisJones::SolvableVisJones(String msname,Int MSnAnt,Int MSnSpw) :
5479 : VisCal(msname,MSnAnt,MSnSpw), // virtual base
5480 : VisMueller(msname,MSnAnt,MSnSpw), // virtual base
5481 : SolvableVisMueller(msname,MSnAnt,MSnSpw), // immediate parent
5482 : VisJones(msname,MSnAnt,MSnSpw), // immediate parent
5483 0 : dJ1_(NULL), // data...
5484 0 : dJ2_(NULL),
5485 0 : diffJElem_(),
5486 0 : DJValid_(false)
5487 : {
5488 0 : if (prtlev()>2) cout << "SVJ::SVJ(msname,MSnAnt,MSnSpw)" << endl;
5489 0 : }
5490 :
5491 68 : SolvableVisJones::SolvableVisJones(const MSMetaInfoForCal& msmc) :
5492 : VisCal(msmc), // virtual base
5493 : VisMueller(msmc), // virtual base
5494 : SolvableVisMueller(msmc), // immediate parent
5495 : VisJones(msmc), // immediate parent
5496 68 : dJ1_(NULL), // data...
5497 68 : dJ2_(NULL),
5498 68 : diffJElem_(),
5499 68 : DJValid_(False)
5500 : {
5501 68 : if (prtlev()>2) cout << "SVJ::SVJ(msmc)" << endl;
5502 68 : }
5503 :
5504 :
5505 0 : SolvableVisJones::SolvableVisJones(const Int& nAnt) :
5506 : VisCal(nAnt), // virtual base
5507 : VisMueller(nAnt), // virtual base
5508 : SolvableVisMueller(nAnt), // immediate parent
5509 : VisJones(nAnt), // immediate parent
5510 0 : dJ1_(NULL), // data...
5511 0 : dJ2_(NULL),
5512 0 : diffJElem_(),
5513 0 : DJValid_(false)
5514 : {
5515 0 : if (prtlev()>2) cout << "SVJ::SVJ(i,j,k)" << endl;
5516 0 : }
5517 :
5518 68 : SolvableVisJones::~SolvableVisJones() {
5519 :
5520 68 : if (prtlev()>2) cout << "SVJ::~SVJ()" << endl;
5521 68 : if (dJ1_)
5522 0 : delete dJ1_;
5523 68 : if (dJ2_)
5524 0 : delete dJ2_;
5525 68 : }
5526 :
5527 0 : void SolvableVisJones::reReference() {
5528 :
5529 : // TBD: Handle single-poln referencing
5530 : // TBD: Handle missing refant
5531 :
5532 : // Generic version for trivial types
5533 0 : if (trivialJonesElem()) {
5534 :
5535 : // Determine multiplicative complex phase
5536 0 : Matrix<Complex> refgain;
5537 0 : refgain=solveCPar().xyPlane(refant());
5538 :
5539 : // cout << "refgain add: " << refgain.data() << " " << solveCPar().xyPlane(refant()).data() << endl;
5540 :
5541 0 : Float amp(1.0);
5542 0 : Complex* rg=refgain.data();
5543 : // TBD: clean this up: there is only 1 solvePar chan!
5544 : // for (Int ich=0;ich<nChanPar();++ich) {
5545 0 : for (Int ip=0;ip<nPar();++ip,++rg) {
5546 0 : amp=abs(*rg);
5547 0 : if (amp>0.0) {
5548 0 : *rg/=amp;
5549 0 : *rg=conj(*rg);
5550 : }
5551 : else
5552 0 : *rg=Complex(1.0);
5553 : }
5554 : // }
5555 :
5556 : // cout << "amp(refgain) = " << amplitude(refgain) << endl;
5557 :
5558 :
5559 : // Apply complex phase to each ant
5560 0 : Matrix<Complex> antgain;
5561 0 : for (Int ia=0;ia<nAnt();++ia) {
5562 0 : antgain.reference(solveCPar().xyPlane(ia));
5563 0 : antgain*=refgain;
5564 : }
5565 0 : }
5566 : else
5567 0 : throw(AipsError("Attempt to reference non-trivial calibration type."));
5568 :
5569 :
5570 0 : }
5571 :
5572 :
5573 0 : void SolvableVisJones::differentiate(CalVisBuffer& cvb) {
5574 :
5575 0 : if (prtlev()>3) cout << " SVJ::differentiate(CVB)" << endl;
5576 :
5577 : // NB: For freqDepPar()=true, the data and solutions are
5578 : // multi-channel, but nChanMat()=1 because we only
5579 : // consider one channel at a time. In this case,
5580 : // focusChan is the specific channel under consideration.
5581 : // Otherwise, we will use all channels in the vb
5582 : // simultaneously
5583 :
5584 : // Some vb shape info
5585 0 : Int& nRow(cvb.nRow());
5586 0 : Int& nCorr(cvb.nCorr());
5587 :
5588 : // Size (diff)residuals workspace in the CVB
5589 0 : cvb.setFocusChan(focusChan());
5590 0 : cvb.sizeResiduals(nPar(),2); // 2 sets of nPar() derivatives per baseline
5591 :
5592 : // Copy in-focus model to residual workspace
5593 0 : cvb.initResidWithModel();
5594 :
5595 :
5596 : // References to workspaces
5597 0 : Cube<Complex>& Vout(cvb.residuals());
5598 0 : Array<Complex>& dVout(cvb.diffResiduals());
5599 0 : Matrix<Bool>& Vflg(cvb.residFlag());
5600 :
5601 : // "Apply" the current Q,U or X estimates to the crosshand model
5602 0 : if (solvePol()>0) {
5603 0 : Complex pol(1.0);
5604 :
5605 0 : if (solvePol()==2) // pol = Q+iU
5606 0 : pol=Complex(real(srcPolPar()(0)),real(srcPolPar()(1)));
5607 0 : else if (solvePol()==1) // pol = exp(iX)
5608 0 : pol=exp(Complex(0.0,real(srcPolPar()(0))));
5609 :
5610 0 : IPosition blc(3,1,0,0), trc(3,1,nChanMat()-1,nRow-1);
5611 0 : Array<Complex> RL(Vout(blc,trc));
5612 0 : RL*=pol;
5613 0 : blc(0)=trc(0)=2;
5614 0 : Array<Complex> LR(Vout(blc,trc));
5615 0 : LR*=conj(pol);
5616 0 : }
5617 :
5618 : // Visibility vector renderers
5619 0 : VisVector::VisType vt(visType(nCorr));
5620 0 : VisVector cVm(vt); // The model data corrupted by trial solution
5621 0 : VisVector dV1(vt); // The deriv of V wrt pars of 1st ant in bln
5622 0 : VisVector dV2(vt); // The deriv of V wrt pars of 2nd ant in bln
5623 :
5624 : // Temporary non-iterating VisVectors to hold partial applies
5625 0 : VisVector J1V(vt,true);
5626 0 : VisVector VJ2(vt,true);
5627 :
5628 : // Starting synchronization for output visibility data
5629 0 : cVm.sync(Vout(0,0,0));
5630 0 : dV1.sync(dVout(IPosition(5,0,0,0,0,0)));
5631 0 : dV2.sync(dVout(IPosition(5,0,0,0,0,1)));
5632 :
5633 : // Synchronize current calibration pars/matrices
5634 0 : syncSolveCal();
5635 :
5636 : // Nominal synchronization of dJs
5637 0 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,0)));
5638 0 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,0)));
5639 :
5640 : // Inform Jones matrices if data is scalar
5641 0 : Bool scalar(vt==VisVector::One);
5642 0 : J1().setScalarData(scalar);
5643 0 : J2().setScalarData(scalar);
5644 0 : dJ1().setScalarData(scalar);
5645 0 : dJ2().setScalarData(scalar);
5646 :
5647 : // VisBuffer indices
5648 0 : Double* time= cvb.time().data();
5649 0 : Int* a1= cvb.antenna1().data();
5650 0 : Int* a2= cvb.antenna2().data();
5651 0 : Bool* flagR= cvb.flagRow().data();
5652 0 : Bool* flag= Vflg.data(); // via local reference
5653 :
5654 : // TBD: set weights according to flags??
5655 :
5656 : // iterate rows
5657 0 : for (Int irow=0; irow<nRow; irow++,flagR++,a1++,a2++,time++) {
5658 :
5659 : // Avoid ACs
5660 0 : if (*a1==*a2) *flagR=true;
5661 :
5662 0 : if (!*flagR) { // if this row unflagged
5663 :
5664 : // Re-update matrices if time changes
5665 0 : if (timeDepMat() && *time != lastTime()) {
5666 0 : currTime()=*time;
5667 0 : invalidateDiffCalMat();
5668 0 : syncCalMat();
5669 0 : syncDiffMat();
5670 0 : lastTime()=currTime();
5671 : }
5672 :
5673 : // Synchronize Jones renderers for the ants on this baseline
5674 0 : J1().sync(currJElem()(0,0,*a1),currJElemOK()(0,0,*a1));
5675 0 : J2().sync(currJElem()(0,0,*a2),currJElemOK()(0,0,*a2));
5676 :
5677 : // Synchronize differentiated Jones renderers for this baseline
5678 0 : if (trivialDJ()) {
5679 0 : dJ1().origin();
5680 0 : dJ2().origin();
5681 : } else {
5682 0 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,*a1)));
5683 0 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,*a2)));
5684 : }
5685 :
5686 : // Assumes all iterating quantities have nChanMat() channelization
5687 0 : for (Int ich=0; ich<nChanMat();ich++,flag++,
5688 0 : cVm++, J1()++, J2()++) {
5689 :
5690 : // if channel unflagged an cal ok
5691 : // if (!*flag && (*J1Ok && *J2Ok) ) {
5692 0 : if (!*flag) {
5693 :
5694 : // Partial applies for repeated use below
5695 0 : VJ2=cVm;
5696 0 : J2().applyLeft(VJ2,*flag); // VJ2 = Vm*J2, used below
5697 :
5698 0 : J1().applyRight(cVm,*flag);
5699 0 : J1V=cVm; // J1V = J1*Vm, used below
5700 :
5701 : // Finish trial corruption
5702 0 : J2().applyLeft(cVm,*flag); // cVm = (J1*Vm)*J2
5703 :
5704 : }
5705 :
5706 : // Only continue with diff-ing, if we aren't flagged yet
5707 0 : if (!*flag) {
5708 :
5709 : // Differentiation per par
5710 0 : for (Int ip=0;ip<nPar();ip++,
5711 0 : dV1++,dJ1()++,
5712 0 : dV2++,dJ2()++) {
5713 :
5714 0 : dV1=VJ2;
5715 0 : dJ1().applyRight(dV1); // dV1 = dJ1(ip)*(Vm*J2)
5716 :
5717 0 : dV2=J1V;
5718 0 : dJ2().applyLeft(dV2); // dV2 = (J1*Vm)*dJ2(ip)
5719 : }
5720 :
5721 : } // (!*flag)
5722 : else {
5723 : // set trial corruption to zero
5724 0 : cVm.zero();
5725 :
5726 : // Advance all par-dep pointers over flagged channel
5727 0 : dV1.advance(nPar());
5728 0 : dV2.advance(nPar());
5729 0 : dJ1().advance(nPar());
5730 0 : dJ2().advance(nPar());
5731 : }
5732 :
5733 : } // chn
5734 :
5735 : } // !*flagR
5736 : else {
5737 : // Must advance all chan-, par-dep pointers over flagged row
5738 0 : flag+=nChanMat();
5739 0 : cVm.advance(nChanMat());
5740 0 : J1().advance(nChanMat());
5741 0 : J2().advance(nChanMat());
5742 0 : Int chpar(nChanMat()*nPar());
5743 0 : dV1.advance(chpar);
5744 0 : dV2.advance(chpar);
5745 0 : dJ1().advance(chpar);
5746 0 : dJ2().advance(chpar);
5747 : }
5748 : }
5749 :
5750 : // Subtract the obs'd data from the trial-corrupted model
5751 : // to form residuals
5752 0 : cvb.finalizeResiduals();
5753 :
5754 0 : }
5755 :
5756 0 : void SolvableVisJones::differentiate(SolveDataBuffer& sdb) { // VI2
5757 :
5758 0 : if (prtlev()>3) cout << " SVJ::differentiate(SDB)" << endl;
5759 :
5760 : // NB: For freqDepPar()=True, the data and solutions are
5761 : // multi-channel, but nChanMat()=1 because we only
5762 : // consider one channel at a time. In this case,
5763 : // focusChan is the specific channel under consideration.
5764 : // Otherwise, we will use all channels in the vb
5765 : // simultaneously
5766 :
5767 : // Some vb shape info
5768 0 : const Int& nRow(sdb.nRows());
5769 0 : const Int& nCorr(sdb.nCorrelations());
5770 :
5771 : // Size (diff)residuals workspace in the CVB
5772 0 : sdb.setFocusChan(focusChan());
5773 0 : sdb.sizeResiduals(nPar(),2); // 2 sets of nPar() derivatives per baseline
5774 :
5775 : // Copy in-focus model to residual workspace
5776 0 : sdb.initResidWithModel();
5777 :
5778 : // References to workspaces
5779 0 : Cube<Complex>& Vout(sdb.residuals());
5780 0 : Array<Complex>& dVout(sdb.diffResiduals());
5781 :
5782 : // "Apply" the current Q,U or X estimates to the crosshand model
5783 : // NB: This is circular-basis specific!!
5784 :
5785 : /* 2016Nov29 (gmoellen): MOVED TO DJones::guessPar(SDBList)
5786 :
5787 : if (solvePol()>0) {
5788 : Complex pol(1.0);
5789 :
5790 : if (solvePol()==2) // pol = Q+iU
5791 : pol=Complex(real(srcPolPar()(0)),real(srcPolPar()(1)));
5792 : else if (solvePol()==1) // pol = exp(iX)
5793 : pol=exp(Complex(0.0,real(srcPolPar()(0))));
5794 :
5795 : IPosition blc(3,1,0,0), trc(3,1,nChanMat()-1,nRow-1);
5796 : Array<Complex> RL(Vout(blc,trc));
5797 : RL*=pol;
5798 : blc(0)=trc(0)=2;
5799 : Array<Complex> LR(Vout(blc,trc));
5800 : LR*=conj(pol);
5801 : }
5802 : */
5803 :
5804 :
5805 : // Visibility vector renderers
5806 0 : VisVector::VisType vt(visType(nCorr));
5807 0 : VisVector cVm(vt); // The model data corrupted by trial solution
5808 0 : VisVector dV1(vt); // The deriv of V wrt pars of 1st ant in bln
5809 0 : VisVector dV2(vt); // The deriv of V wrt pars of 2nd ant in bln
5810 :
5811 : // Temporary non-iterating VisVectors to hold partial applies
5812 0 : VisVector J1V(vt,True);
5813 0 : VisVector VJ2(vt,True);
5814 :
5815 : // Starting synchronization for output visibility data
5816 0 : cVm.sync(Vout(0,0,0));
5817 0 : dV1.sync(dVout(IPosition(5,0,0,0,0,0)));
5818 0 : dV2.sync(dVout(IPosition(5,0,0,0,0,1)));
5819 :
5820 : // Synchronize current calibration pars/matrices
5821 0 : syncSolveCal();
5822 :
5823 : // Nominal synchronization of dJs
5824 0 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,0)));
5825 0 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,0)));
5826 :
5827 : // Inform Jones matrices if data is scalar
5828 0 : Bool scalar(vt==VisVector::One);
5829 0 : J1().setScalarData(scalar);
5830 0 : J2().setScalarData(scalar);
5831 0 : dJ1().setScalarData(scalar);
5832 0 : dJ2().setScalarData(scalar);
5833 :
5834 : // VisBuffer indices
5835 0 : const Double* time= sdb.time().data();
5836 0 : const Int* a1= sdb.antenna1().data();
5837 0 : const Int* a2= sdb.antenna2().data();
5838 0 : const Bool* flagR= sdb.flagRow().data();
5839 :
5840 : // TBD: set weights according to flags??
5841 :
5842 : // iterate rows
5843 0 : for (Int irow=0; irow<nRow; irow++,flagR++,a1++,a2++,time++) {
5844 :
5845 : // Avoid ACs and flagged rows
5846 0 : if (*a1!=*a2 && !*flagR) {
5847 :
5848 : // Re-update matrices if time changes
5849 : // E.g.?
5850 0 : if (timeDepMat() && *time != lastTime()) {
5851 0 : currTime()=*time;
5852 0 : invalidateDiffCalMat();
5853 0 : syncCalMat();
5854 0 : syncDiffMat();
5855 0 : lastTime()=currTime();
5856 : }
5857 :
5858 : // Synchronize Jones renderers for the ants on this baseline
5859 0 : J1().sync(currJElem()(0,0,*a1),currJElemOK()(0,0,*a1));
5860 0 : J2().sync(currJElem()(0,0,*a2),currJElemOK()(0,0,*a2));
5861 :
5862 : // Synchronize differentiated Jones renderers for this baseline
5863 0 : if (trivialDJ()) {
5864 0 : dJ1().origin();
5865 0 : dJ2().origin();
5866 : } else {
5867 0 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,*a1)));
5868 0 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,*a2)));
5869 : }
5870 :
5871 : // Assumes all iterating quantities have nChanMat() channelization
5872 0 : for (Int ich=0; ich<nChanMat();ich++,
5873 0 : cVm++, J1()++, J2()++) {
5874 :
5875 : // NB: Ignoring vis flag state (OK?)
5876 :
5877 : // Partial applies for repeated use below
5878 0 : VJ2=cVm;
5879 0 : J2().applyLeft(VJ2); // VJ2 = Vm*J2, used below
5880 :
5881 0 : J1().applyRight(cVm);
5882 0 : J1V=cVm; // J1V = J1*Vm, used below
5883 :
5884 : // Finish trial corruption
5885 0 : J2().applyLeft(cVm); // cVm = (J1*Vm)*J2
5886 :
5887 : // Differentiation per par
5888 0 : for (Int ip=0;ip<nPar();ip++,
5889 0 : dV1++,dJ1()++,
5890 0 : dV2++,dJ2()++) {
5891 :
5892 0 : dV1=VJ2;
5893 0 : dJ1().applyRight(dV1); // dV1 = dJ1(ip)*(Vm*J2)
5894 :
5895 0 : dV2=J1V;
5896 0 : dJ2().applyLeft(dV2); // dV2 = (J1*Vm)*dJ2(ip)
5897 : }
5898 :
5899 : } // chn
5900 :
5901 0 : } // !*flagR
5902 : else {
5903 : // Must advance all chan-, par-dep pointers over flagged row
5904 0 : cVm.advance(nChanMat());
5905 0 : J1().advance(nChanMat());
5906 0 : J2().advance(nChanMat());
5907 0 : Int chpar(nChanMat()*nPar());
5908 0 : dV1.advance(chpar);
5909 0 : dV2.advance(chpar);
5910 0 : dJ1().advance(chpar);
5911 0 : dJ2().advance(chpar);
5912 : }
5913 : }
5914 :
5915 : // Subtract the obs'd data from the trial-corrupted model
5916 : // to form residuals
5917 0 : sdb.finalizeResiduals();
5918 :
5919 0 : }
5920 :
5921 :
5922 0 : void SolvableVisJones::differentiate(VisBuffer& vb,
5923 : Cube<Complex>& Vout,
5924 : Array<Complex>& dVout,
5925 : Matrix<Bool>& Vflg) {
5926 :
5927 0 : if (prtlev()>3) cout << " SVJ::differentiate()" << endl;
5928 :
5929 : // NB: For freqDepPar()=true, the data and solutions are
5930 : // multi-channel, but nChanMat()=1 because we only
5931 : // consider one channel at a time. In this case,
5932 : // focusChan is the specific channel under consideration.
5933 : // Otherwise, we will use all channels in the vb
5934 : // simultaneously
5935 :
5936 : // Some vb shape info
5937 0 : Int& nRow(vb.nRow());
5938 0 : Int nCorr(vb.corrType().nelements());
5939 :
5940 : // Size up the output data arrays
5941 : // Vout = [nCorr,nChan,nRow]
5942 : // dVout = [nCorr,nPar,nChan,nRow,2] (1 set of dV for both ants on baseline)
5943 0 : Vout.resize(IPosition(3,nCorr,nChanMat(),nRow));
5944 0 : Vout.unique(); // ensure unique storage
5945 :
5946 0 : dVout.resize(IPosition(5,nCorr,nPar(),nChanMat(),nRow,2));
5947 0 : dVout.unique();
5948 0 : dVout=Complex(0.0);
5949 :
5950 : // Copy the input model data from the VisBuffer to Vout
5951 : // for in-place application (do this according to focusChan)
5952 : // (also flags)
5953 0 : Matrix<Bool> fl;
5954 0 : if (freqDepPar()) {
5955 : // Copy just the focusChan; all work below is single-channel
5956 0 : AlwaysAssert((nChanMat()==1),AipsError); // sanity
5957 0 : AlwaysAssert((focusChan()>-1),AipsError); // sanity
5958 :
5959 0 : Vout = vb.modelVisCube()(IPosition(3,0, focusChan(),0 ),
5960 0 : IPosition(3,nCorr-1,focusChan(),nRow-1));
5961 :
5962 0 : Vflg.resize(IPosition(2,1,nRow)); // proper single channel size
5963 0 : Vflg.unique(); // unique storage
5964 0 : Vflg = vb.flag()(IPosition(2,focusChan(),0 ),
5965 0 : IPosition(2,focusChan(),nRow-1));
5966 : }
5967 : else {
5968 : // Copy all channels in the vb
5969 0 : Vout = vb.modelVisCube();
5970 0 : Vflg.reference(vb.flag()); // Just reference whole flag array
5971 : }
5972 :
5973 : // "Apply" the current Q,U or X estimates to the crosshand model
5974 0 : if (solvePol()>0) {
5975 0 : Complex pol(1.0);
5976 :
5977 0 : if (solvePol()==2) // pol = Q+iU
5978 0 : pol=Complex(real(srcPolPar()(0)),real(srcPolPar()(1)));
5979 0 : else if (solvePol()==1) // pol = exp(iX)
5980 0 : pol=exp(Complex(0.0,real(srcPolPar()(0))));
5981 :
5982 0 : IPosition blc(3,1,0,0), trc(3,1,nChanMat()-1,nRow-1);
5983 0 : Array<Complex> RL(Vout(blc,trc));
5984 0 : RL*=pol;
5985 0 : blc(0)=trc(0)=2;
5986 0 : Array<Complex> LR(Vout(blc,trc));
5987 0 : LR*=conj(pol);
5988 0 : }
5989 :
5990 : // Visibility vector renderers
5991 0 : VisVector::VisType vt(visType(nCorr));
5992 0 : VisVector cVm(vt); // The model data corrupted by trial solution
5993 0 : VisVector dV1(vt); // The deriv of V wrt pars of 1st ant in bln
5994 0 : VisVector dV2(vt); // The deriv of V wrt pars of 2nd ant in bln
5995 :
5996 : // Temporary non-iterating VisVectors to hold partial applies
5997 0 : VisVector J1V(vt,true);
5998 0 : VisVector VJ2(vt,true);
5999 :
6000 : // Starting synchronization for output visibility data
6001 0 : cVm.sync(Vout(0,0,0));
6002 0 : dV1.sync(dVout(IPosition(5,0,0,0,0,0)));
6003 0 : dV2.sync(dVout(IPosition(5,0,0,0,0,1)));
6004 :
6005 : // Synchronize current calibration pars/matrices
6006 0 : syncSolveCal();
6007 :
6008 : // Nominal synchronization of dJs
6009 0 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,0)));
6010 0 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,0)));
6011 :
6012 : // Inform Jones matrices if data is scalar
6013 0 : Bool scalar(vt==VisVector::One);
6014 0 : J1().setScalarData(scalar);
6015 0 : J2().setScalarData(scalar);
6016 0 : dJ1().setScalarData(scalar);
6017 0 : dJ2().setScalarData(scalar);
6018 :
6019 : // VisBuffer indices
6020 0 : Double* time= vb.time().data();
6021 0 : Int* a1= vb.antenna1().data();
6022 0 : Int* a2= vb.antenna2().data();
6023 0 : Bool* flagR= vb.flagRow().data();
6024 0 : Bool* flag= Vflg.data(); // via local reference
6025 :
6026 : // TBD: set weights according to flags??
6027 :
6028 : // iterate rows
6029 0 : for (Int irow=0; irow<nRow; irow++,flagR++,a1++,a2++,time++) {
6030 :
6031 : // Avoid ACs
6032 0 : if (*a1==*a2) *flagR=true;
6033 :
6034 0 : if (!*flagR) { // if this row unflagged
6035 :
6036 : // Re-update matrices if time changes
6037 0 : if (timeDepMat() && *time != lastTime()) {
6038 0 : currTime()=*time;
6039 0 : invalidateDiffCalMat();
6040 0 : syncCalMat();
6041 0 : syncDiffMat();
6042 0 : lastTime()=currTime();
6043 : }
6044 :
6045 : // Synchronize Jones renderers for the ants on this baseline
6046 0 : J1().sync(currJElem()(0,0,*a1),currJElemOK()(0,0,*a1));
6047 0 : J2().sync(currJElem()(0,0,*a2),currJElemOK()(0,0,*a2));
6048 :
6049 : // Synchronize differentiated Jones renderers for this baseline
6050 0 : if (trivialDJ()) {
6051 0 : dJ1().origin();
6052 0 : dJ2().origin();
6053 : } else {
6054 0 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,*a1)));
6055 0 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,*a2)));
6056 : }
6057 :
6058 : // Assumes all iterating quantities have nChanMat() channelization
6059 0 : for (Int ich=0; ich<nChanMat();ich++,flag++,
6060 0 : cVm++, J1()++, J2()++) {
6061 :
6062 : // if channel unflagged an cal ok
6063 : // if (!*flag && (*J1Ok && *J2Ok) ) {
6064 0 : if (!*flag) {
6065 :
6066 : // Partial applies for repeated use below
6067 0 : VJ2=cVm;
6068 0 : J2().applyLeft(VJ2,*flag); // VJ2 = Vm*J2, used below
6069 :
6070 0 : J1().applyRight(cVm,*flag);
6071 0 : J1V=cVm; // J1V = J1*Vm, used below
6072 :
6073 : // Finish trial corruption
6074 0 : J2().applyLeft(cVm,*flag); // cVm = (J1*Vm)*J2
6075 :
6076 : }
6077 :
6078 : // Only continue with diff-ing, if we aren't flagged yet
6079 0 : if (!*flag) {
6080 :
6081 : // Differentiation per par
6082 0 : for (Int ip=0;ip<nPar();ip++,
6083 0 : dV1++,dJ1()++,
6084 0 : dV2++,dJ2()++) {
6085 :
6086 0 : dV1=VJ2;
6087 0 : dJ1().applyRight(dV1); // dV1 = dJ1(ip)*(Vm*J2)
6088 :
6089 0 : dV2=J1V;
6090 0 : dJ2().applyLeft(dV2); // dV2 = (J1*Vm)*dJ2(ip)
6091 : }
6092 :
6093 : } // (!*flag)
6094 : else {
6095 : // set trial corruption to zero
6096 0 : cVm.zero();
6097 :
6098 : // Advance all par-dep pointers over flagged channel
6099 0 : dV1.advance(nPar());
6100 0 : dV2.advance(nPar());
6101 0 : dJ1().advance(nPar());
6102 0 : dJ2().advance(nPar());
6103 : }
6104 :
6105 : } // chn
6106 :
6107 : } // !*flagR
6108 : else {
6109 : // Must advance all chan-, par-dep pointers over flagged row
6110 0 : flag+=nChanMat();
6111 0 : cVm.advance(nChanMat());
6112 0 : J1().advance(nChanMat());
6113 0 : J2().advance(nChanMat());
6114 0 : Int chpar(nChanMat()*nPar());
6115 0 : dV1.advance(chpar);
6116 0 : dV2.advance(chpar);
6117 0 : dJ1().advance(chpar);
6118 0 : dJ2().advance(chpar);
6119 : }
6120 : }
6121 :
6122 0 : }
6123 :
6124 0 : void SolvableVisJones::diffSrc(VisBuffer& vb,
6125 : Array<Complex>& dVout) {
6126 :
6127 0 : if (prtlev()>3) cout << " SVJ::diffSrc()" << endl;
6128 :
6129 : // Some vb shape info
6130 0 : Int& nRow(vb.nRow());
6131 0 : Int nCorr(vb.corrType().nelements());
6132 :
6133 : // Size up the output data arrays
6134 0 : dVout.resize(IPosition(4,nCorr,nChanMat(),nRow,solvePol()));
6135 0 : dVout.unique();
6136 0 : dVout=Complex(0.0);
6137 :
6138 : // For now, we don't actually need gradients w.r.t. the source
6139 0 : return;
6140 :
6141 : IPosition blc(4,0,0,0,0), trc(4,0,nChanMat()-1,nRow-1,0);
6142 :
6143 : if (solvePol()==2) {
6144 : blc(3)=trc(3)=0;
6145 : blc(0)=1;trc(0)=2;
6146 : dVout(blc,trc)=Complex(1.0); // Q part (both RL & LR)
6147 : blc(3)=trc(3)=1;
6148 : blc(0)=trc(0)=1;
6149 : dVout(blc,trc)=Complex(0.0,1.0); // U part (in RL)
6150 : blc(0)=trc(0)=2;
6151 : dVout(blc,trc)=Complex(0.0,-1.0); // U part (in LR)
6152 : }
6153 : else if (solvePol()==1) {
6154 : Complex dX=Complex(0.0,1.0)*exp(Complex(0.0,real(srcPolPar()(0))));
6155 : blc(3)=trc(3)=0;
6156 : blc(0)=trc(0)=1;
6157 : dVout(blc,trc)=dX; // multiplying RL
6158 : blc(0)=trc(0)=2;
6159 : dVout(blc,trc)=conj(dX); // multiplying LR
6160 : }
6161 :
6162 : // Visibility vector renderers
6163 : VisVector::VisType vt(visType(nCorr));
6164 : VisVector dSm1(vt); // The model data corrupted by trial solution
6165 : VisVector dSm2(vt); // The model data corrupted by trial solution
6166 :
6167 : // Starting synchronization for output visibility data
6168 : dSm1.sync(dVout(IPosition(4,0,0,0,0)));
6169 : if (solvePol()>1)
6170 : dSm2.sync(dVout(IPosition(4,0,0,0,1)));
6171 :
6172 : // Synchronize current calibration pars/matrices
6173 : syncSolveCal();
6174 :
6175 : // Nominal synchronization of dJs
6176 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,0)));
6177 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,0)));
6178 :
6179 : // Inform Jones matrices if data is scalar
6180 : Bool scalar(vt==VisVector::One);
6181 : J1().setScalarData(scalar);
6182 : J2().setScalarData(scalar);
6183 : dJ1().setScalarData(scalar);
6184 : dJ2().setScalarData(scalar);
6185 :
6186 : // VisBuffer indices
6187 : Double* time= vb.time().data();
6188 : Int* a1= vb.antenna1().data();
6189 : Int* a2= vb.antenna2().data();
6190 : Bool* flagR= vb.flagRow().data();
6191 : Bool* flag= vb.flag().data();
6192 :
6193 : // TBD: set weights according to flags??
6194 :
6195 : // iterate rows
6196 : for (Int irow=0; irow<nRow; irow++,flagR++,a1++,a2++,time++) {
6197 :
6198 : // Avoid ACs
6199 : if (*a1==*a2) *flagR=true;
6200 :
6201 : if (!*flagR) { // if this row unflagged
6202 :
6203 : // Re-update matrices if time changes
6204 : if (timeDepMat() && *time != lastTime()) {
6205 : currTime()=*time;
6206 : invalidateDiffCalMat();
6207 : syncCalMat();
6208 : syncDiffMat();
6209 : lastTime()=currTime();
6210 : }
6211 :
6212 : // Synchronize Jones renderers for the ants on this baseline
6213 : J1().sync(currJElem()(0,0,*a1),currJElemOK()(0,0,*a1));
6214 : J2().sync(currJElem()(0,0,*a2),currJElemOK()(0,0,*a2));
6215 :
6216 : // Assumes all iterating quantities have nChanMat() channelization
6217 : for (Int ich=0; ich<nChanMat();ich++,flag++,
6218 : dSm1++, dSm2++, J1()++, J2()++) {
6219 :
6220 : // if channel unflagged an cal ok
6221 : if (!*flag) {
6222 :
6223 : J1().applyRight(dSm1);
6224 : J2().applyLeft(dSm1);
6225 : if (solvePol()>1) {
6226 : J1().applyRight(dSm2);
6227 : J2().applyLeft(dSm2);
6228 : }
6229 : }
6230 :
6231 : } // chn
6232 :
6233 : } // !*flagR
6234 : else {
6235 : // Must advance all chan-, par-dep pointers over flagged row
6236 : flag+=nChanMat();
6237 : dSm1.advance(nChanMat());
6238 : dSm2.advance(nChanMat());
6239 : J1().advance(nChanMat());
6240 : J2().advance(nChanMat());
6241 : }
6242 : }
6243 :
6244 : }
6245 :
6246 0 : void SolvableVisJones::accumulate(SolvableVisCal* incr,
6247 : const Vector<Int>& fields) {
6248 :
6249 : // Use SVJ interface for the incremental component
6250 : // (this should always be safe at this point?)
6251 0 : SolvableVisJones* svj = dynamic_cast<SolvableVisJones*>(incr);
6252 :
6253 : // Catch bad SVJ conversion or fundamental type mismatch
6254 0 : if (svj==NULL || svj->type() != this->type())
6255 0 : throw(AipsError("Incremental calibration is not of compatible type."));
6256 :
6257 0 : Int nfield(fields.nelements());
6258 :
6259 0 : Bool fldok(true);
6260 :
6261 : // TBD: Iterate over the ct_
6262 0 : Block<String> cols(2);
6263 0 : cols[0]="SPECTRAL_WINDOW_ID";
6264 0 : cols[1]="TIME";
6265 0 : CTIter ctiter(*ct_,cols);
6266 :
6267 0 : cout << boolalpha;
6268 0 : Int piter(0);
6269 0 : Int prow(0);
6270 0 : while (!ctiter.pastEnd()) {
6271 :
6272 0 : currSpw()=ctiter.thisSpw();
6273 0 : currTime()=ctiter.thisTime();
6274 :
6275 : /*
6276 : cout << "Spw=" << currSpw() << " spwok=" << svj->spwOK(currSpw());
6277 : cout << " Time=" << MVTime(currTime()/C::day).string(MVTime::YMD,7);
6278 : cout << " nrow=" << ctiter.nrow();
6279 : */
6280 :
6281 : // Only update spws which are available in the incr table:
6282 0 : if (svj->spwOK(currSpw())) {
6283 :
6284 0 : currField()=ctiter.thisField();
6285 :
6286 : // Is current field among those we need to update?
6287 0 : fldok = (nfield==0 || anyEQ(fields,currField()));
6288 :
6289 : // cout << " Fld=" << currField() << " fldok=" << fldok;
6290 :
6291 0 : if (fldok) {
6292 :
6293 0 : currFreq()=ctiter.freq();
6294 :
6295 0 : currCPar().assign(ctiter.cparam());
6296 0 : currParOK().assign(!ctiter.flag());
6297 :
6298 0 : syncCalMat(false); // a reference!!
6299 :
6300 : // Sync svj with this
6301 0 : svj->syncCal(*this);
6302 :
6303 0 : AlwaysAssert( (nChanMat()==svj->nChanMat()), AipsError);
6304 :
6305 : // Do the multiplication each ant, chan
6306 0 : for (Int iant=0; iant<nAnt(); iant++) {
6307 0 : for (Int ichan=0; ichan<svj->nChanMat(); ichan++) {
6308 0 : J1()*=(svj->J1());
6309 0 : J1()++;
6310 0 : svj->J1()++;
6311 : } // ichan
6312 : } // iant
6313 :
6314 : //cout << " keep";
6315 :
6316 0 : ctiter.setcparam(currCPar()); // assumes matrices are references
6317 0 : ctiter.setflag(!currParOK());
6318 :
6319 0 : piter+=1;
6320 0 : prow+=ctiter.nrow();
6321 :
6322 : } // fldok
6323 : } // spwOK
6324 :
6325 : // cout << endl;
6326 :
6327 : // Advance iterator
6328 0 : ctiter.next();
6329 :
6330 : } // ispw
6331 :
6332 : // cout << "Processed " << prow << " rows in " << piter << " iterations." << endl;
6333 :
6334 0 : }
6335 :
6336 :
6337 :
6338 : // Setup solvePar shape (Jones version)
6339 24 : void SolvableVisJones::initSolvePar() {
6340 :
6341 24 : if (prtlev()>3) cout << " SVJ::initSolvePar()" << endl;
6342 :
6343 48 : for (Int ispw=0;ispw<nSpw();++ispw) {
6344 :
6345 24 : currSpw()=ispw;
6346 :
6347 24 : switch (parType()) {
6348 24 : case VisCalEnum::COMPLEX: {
6349 24 : solveAllCPar().resize(nPar(),nChanPar(),nAnt());
6350 24 : solveAllCPar()=Complex(1.0);
6351 24 : if (nChanPar()==1)
6352 24 : solveCPar().reference(solveAllCPar());
6353 : else {
6354 0 : solveCPar().resize(nPar(),1,nAnt());
6355 0 : solveCPar()=Complex(1.0);
6356 : }
6357 24 : break;
6358 : }
6359 0 : case VisCalEnum::REAL: {
6360 0 : solveAllRPar().resize(nPar(),nChanPar(),nAnt());
6361 0 : solveAllRPar()=0.0;
6362 0 : if (nChanPar()==1)
6363 0 : solveRPar().reference(solveAllRPar());
6364 : else {
6365 0 : solveRPar().resize(nPar(),1,nAnt());
6366 0 : solveRPar()=0.0;
6367 : }
6368 0 : break;
6369 : }
6370 0 : default:
6371 0 : throw(AipsError("Internal error(Calibrater Module): Unsupported parameter type "
6372 0 : "COMPLEXREAL found in SolvableVisJones::initSolvePar()"));
6373 : }
6374 :
6375 24 : solveAllParOK().resize(nPar(),nChanPar(),nAnt());
6376 24 : solveAllParErr().resize(nPar(),nChanPar(),nAnt());
6377 24 : solveAllParSNR().resize(nPar(),nChanPar(),nAnt());
6378 24 : solveAllParOK()=true;
6379 24 : solveAllParErr()=0.0;
6380 24 : solveAllParSNR()=0.0;
6381 24 : if (nChanPar()==1) {
6382 24 : solveParOK().reference(solveAllParOK());
6383 24 : solveParErr().reference(solveAllParErr());
6384 24 : solveParSNR().reference(solveAllParSNR());
6385 : }
6386 : else {
6387 : // solving many channels, one at a time
6388 0 : solveParOK().resize(nPar(),1,nAnt());
6389 0 : solveParErr().resize(nPar(),1,nAnt());
6390 0 : solveParSNR().resize(nPar(),1,nAnt());
6391 0 : solveParOK()=true;
6392 0 : solveParErr()=0.0;
6393 0 : solveParSNR()=0.0;
6394 : }
6395 : }
6396 24 : currSpw()=0;
6397 :
6398 24 : }
6399 :
6400 0 : void SolvableVisJones::syncDiffMat() {
6401 :
6402 0 : if (prtlev()>5) cout << " SVJ::syncDiffMat()"
6403 0 : << " (DJValid()=" << DJValid() << ")" << endl;
6404 :
6405 : // Sync the diff'd Jones matrices
6406 0 : if (!DJValid()) syncDiffJones();
6407 :
6408 : // Sync up Muellers, if necessary
6409 : // if (applyByMueller())
6410 : // Do nothing for now! --All dJ applied directly in differentiate
6411 : // if (!DMValid()) syncDiffMueller();
6412 :
6413 0 : }
6414 :
6415 0 : void SolvableVisJones::syncDiffJones() {
6416 :
6417 0 : if (prtlev()>6) cout << " SVJ::syncDiffJones()" << endl;
6418 :
6419 : // If differentiated Jones are trivial, we are
6420 : // already referencing the type-dep trivial versions
6421 : // TBD: Review this for D, where trivialJonesElem()=false,
6422 : // but diffJ is "trivial-ish"!!! (Probably need trivDiffJonesElem(),
6423 : // or override this method in D to make it no-op)
6424 :
6425 0 : if (trivialDJ())
6426 : // Ensure trivial matrices ready
6427 0 : initTrivDJ();
6428 : else {
6429 0 : diffJElem().resize(IPosition(4,jonesNPar(jonesType()),nPar(),nChanMat(),nCalMat()));
6430 0 : diffJElem().unique();
6431 0 : invalidateDJ();
6432 :
6433 : // Calculate for all ants/chans
6434 0 : calcAllDiffJones();
6435 :
6436 : }
6437 :
6438 : // Ensure diff'd Jones matrix renders are OK
6439 0 : createDiffJones();
6440 :
6441 : // diff'd Jones matrices now valid
6442 0 : validateDJ();
6443 0 : invalidateDM(); // dMs still invalid, probably forever
6444 :
6445 0 : }
6446 :
6447 0 : void SolvableVisJones::calcAllDiffJones() {
6448 :
6449 0 : if (prtlev()>6) cout << " SVJ::calcAllDiffJones" << endl;
6450 :
6451 : // Should handle OK flags in this method, and only
6452 : // do calc if OK
6453 :
6454 0 : Matrix<Complex> oneDJ; // (nElem,nPar)
6455 0 : Vector<Complex> onePar; // (nPar)
6456 :
6457 0 : ArrayIterator<Complex> dJiter(diffJElem(),2);
6458 0 : ArrayIterator<Complex> Piter(currCPar(),1);
6459 :
6460 0 : for (Int iant=0; iant<nCalMat(); iant++) {
6461 :
6462 : // Solving parameters are NEVER channel-dependent
6463 : // (even if data & matrices are)
6464 0 : onePar.reference(Piter.array());
6465 :
6466 0 : for (Int ich=0; ich<nChanMat(); ich++) {
6467 :
6468 0 : oneDJ.reference(dJiter.array());
6469 :
6470 : // Calculate the DJ matrices w.r.t. each par on this ant/chan
6471 0 : calcOneDiffJones(oneDJ,onePar);
6472 :
6473 : // Advance iterators
6474 0 : dJiter.next();
6475 :
6476 : }
6477 0 : Piter.next();
6478 : }
6479 :
6480 0 : }
6481 :
6482 0 : void SolvableVisJones::calcOneDiffJones(Matrix<Complex>&,
6483 : const Vector<Complex>&) {
6484 :
6485 0 : if (prtlev()>10) cout << " SVJ::calcOneDiffJones()" << endl;
6486 :
6487 : // If Jones matrix is trivial, shouldn't get here
6488 0 : if (trivialJonesElem())
6489 0 : throw(AipsError("Trivial Jones Matrix logic error."));
6490 :
6491 : // Otherwise, this method apparently hasn't been specialized, as required
6492 : else
6493 0 : throw(AipsError("Unknown non-trivial dJones-from-parameter calculation requested."));
6494 :
6495 : }
6496 :
6497 0 : void SolvableVisJones::createDiffJones() {
6498 :
6499 0 : if (prtlev()>6) cout << " SVJ::createDiffJones()" << endl;
6500 :
6501 0 : Jones::JonesType jtype(jonesType());
6502 :
6503 : // Delete if wrong type
6504 0 : if (dJ1_ && dJ1().type() != jtype) delete dJ1_;
6505 0 : if (dJ2_ && dJ2().type() != jtype) delete dJ2_;
6506 :
6507 : // If needed, construct the correct diff Jones
6508 0 : if (!dJ1_) dJ1_ = casa::createJones(jtype);
6509 0 : if (!dJ2_) dJ2_ = casa::createJones(jtype);
6510 :
6511 0 : }
6512 :
6513 0 : void SolvableVisJones::initTrivDJ() {
6514 :
6515 0 : if (prtlev()>7) cout << " SVJ::initTrivDJ()" << endl;
6516 :
6517 : // If DJ matrice not trivial, shouldn't get here
6518 0 : if (!trivialDJ())
6519 0 : throw(AipsError("Trivial Jones Matrix logic error."));
6520 :
6521 : // Otherwise, this method apparently hasn't been specialized, as required
6522 : else
6523 0 : throw(AipsError("Unknown trivial dJ initialization requested."));
6524 :
6525 : }
6526 :
6527 : // File a solved solution (and meta-data) into the in-memory Caltable
6528 243 : void SolvableVisJones::keepNCT() {
6529 :
6530 : // Call parent to do general stuff
6531 243 : SolvableVisCal::keepNCT();
6532 :
6533 243 : if (prtlev()>4)
6534 0 : cout << " SVJ::keepNCT" << endl;
6535 :
6536 : // Antenna id sequence
6537 243 : Vector<Int> a1(nAnt());
6538 243 : indgen(a1);
6539 :
6540 : // We are adding to the most-recently added rows
6541 243 : RefRows rows(ct_->nrow()-nElem(),ct_->nrow()-1,1);
6542 :
6543 : // Write to table
6544 243 : CTMainColumns ncmc(*ct_);
6545 243 : ncmc.antenna1().putColumnCells(rows,a1);
6546 243 : ncmc.antenna2().putColumnCells(rows,Vector<Int>(nAnt(),-1)); // Unknown but nominally unform
6547 :
6548 : // NB: a2 will be set separately, e.g., by applyRefAnt
6549 :
6550 243 : }
6551 :
6552 0 : void SolvableVisJones::stateSVJ(const Bool& doVC) {
6553 :
6554 : // If requested, report VisCal state
6555 0 : if (doVC) VisJones::state();
6556 :
6557 : // Get parent's state (w/out VC):
6558 0 : SolvableVisMueller::stateSVM(false);
6559 :
6560 0 : if (applyByJones()) {
6561 0 : if (prtlev()>3) cout << "SVJ::stateSVJ()" << endl;
6562 0 : cout << boolalpha;
6563 :
6564 : // Now SVJ-specific stuff:
6565 0 : cout << " DJValid() = " << DJValid() << endl;
6566 :
6567 0 : cout << " diffJElem().shape() = " << diffJElem().shape()
6568 0 : << " (" << diffJElem().data() << ")" << endl;
6569 0 : cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" << endl;
6570 : }
6571 0 : }
6572 :
6573 0 : Float SolvableVisJones::calcPowerNorm(Array<Float>& amp, const Array<Bool>& ok) {
6574 :
6575 : // SVJ version asumes amps are voltages, so square them
6576 0 : Array<Float> a2(square(amp));
6577 0 : a2(!ok)=0.0; // zero flagged samples
6578 :
6579 :
6580 0 : Float norm2(1.0);
6581 0 : switch (solNorm().normtype()) {
6582 0 : case SolNorm::MEAN: {
6583 0 : Float n=Float(ntrue(ok));
6584 0 : if (n>0.0)
6585 0 : norm2=sum(a2)/n;
6586 0 : break;
6587 : }
6588 0 : case SolNorm::MEDIAN: {
6589 0 : MaskedArray<Float> a2masked(a2,ok);
6590 0 : norm2=median(a2masked,false,true); // unsorted, do mean when even
6591 0 : break;
6592 0 : }
6593 0 : default:
6594 0 : throw(AipsError("Proper normalization type not specified."));
6595 : break;
6596 : }
6597 :
6598 : // Return sqrt, because Jones are voltages
6599 0 : return sqrt(norm2);
6600 0 : }
6601 :
6602 0 : void SolvableVisJones::globalPostSolveTinker() {
6603 :
6604 : // Re-reference the phase, if requested
6605 0 : if (refantlist()(0)>-1) applyRefAnt();
6606 :
6607 : // Apply more general post-solve stuff
6608 0 : SolvableVisCal::globalPostSolveTinker();
6609 :
6610 0 : }
6611 :
6612 0 : void SolvableVisJones::applyRefAnt() {
6613 :
6614 : // TBD:
6615 : // 1. Synchronize refant changes on par axis
6616 : // 2. Implement minimum mean deviation algorithm
6617 :
6618 0 : if (refantlist()(0)<0)
6619 0 : throw(AipsError("No refant specified."));
6620 :
6621 0 : Int nUserRefant=refantlist().nelements();
6622 :
6623 : // Get the preferred refant names from the MS
6624 0 : String refantName(msmc().antennaName(refantlist()(0)));
6625 0 : if (nUserRefant>1) {
6626 0 : refantName+=" (";
6627 0 : for (Int i=1;i<nUserRefant;++i) {
6628 0 : refantName+=msmc().antennaName(refantlist()(i));
6629 0 : if (i<nUserRefant-1) refantName+=",";
6630 : }
6631 0 : refantName+=")";
6632 : }
6633 :
6634 : logSink() << "Applying refant: " << refantName
6635 0 : << " refantmode = " << refantmode();
6636 0 : if (refantmode()=="flex")
6637 0 : logSink() << " (hold alternate refants' phase constant) when refant flagged";
6638 0 : if (refantmode()=="strict")
6639 0 : logSink() << " (flag all antennas when refant flagged)";
6640 0 : logSink() << LogIO::POST;
6641 :
6642 : // Generate a prioritized refant choice list
6643 : // The first entry in this list is the user's primary refant,
6644 : // the second entry is the refant used on the previous interval,
6645 : // and the rest is a prioritized list of alternate refants,
6646 : // starting with the user's secondary (if provided) refants,
6647 : // followed by the rest of the array, in distance order. This
6648 : // makes the priorities correct all the time, and prevents
6649 : // a semi-stochastic alternation (by preferring the last-used
6650 : // alternate, even if nominally higher-priority refants become
6651 : // available)
6652 :
6653 :
6654 : // Extract antenna positions
6655 0 : Matrix<Double> xyz;
6656 0 : if (msName()!="<noms>") {
6657 0 : MeasurementSet ms(msName());
6658 0 : MSAntennaColumns msant(ms.antenna());
6659 0 : msant.position().getColumn(xyz);
6660 0 : }
6661 : else {
6662 : // TBD RO*
6663 0 : CTColumns ctcol(*ct_);
6664 0 : CTAntennaColumns& antcol(ctcol.antenna());
6665 0 : antcol.position().getColumn(xyz);
6666 0 : }
6667 :
6668 : // Calculate (squared) antenna distances, relative
6669 : // to last preferred antenna
6670 0 : Vector<Double> dist2(xyz.ncolumn(),0.0);
6671 0 : for (Int i=0;i<3;++i) {
6672 0 : Vector<Double> row=xyz.row(i);
6673 0 : row-=row(refantlist()(nUserRefant-1));
6674 0 : dist2+=square(row);
6675 0 : }
6676 : // Move preferred antennas to a large distance
6677 0 : for (Int i=0;i<nUserRefant;++i)
6678 0 : dist2(refantlist()(i))=DBL_MAX;
6679 :
6680 : // Generated sorted index
6681 0 : Vector<uInt> ord;
6682 0 : genSort(ord,dist2);
6683 :
6684 : // Assemble the whole choices list
6685 0 : Int nchoices=nUserRefant+1+ord.nelements();
6686 0 : Vector<Int> refantchoices(nchoices,0);
6687 0 : Vector<Int> r(refantchoices(IPosition(1,nUserRefant+1),IPosition(1,refantchoices.nelements()-1)));
6688 0 : convertArray(r,ord);
6689 :
6690 : // set first two to primary preferred refant
6691 0 : refantchoices(0)=refantchoices(1)=refantlist()(0);
6692 :
6693 : // set user's secondary refants (if any)
6694 0 : if (nUserRefant>1)
6695 0 : refantchoices(IPosition(1,2),IPosition(1,nUserRefant))=
6696 0 : refantlist()(IPosition(1,1),IPosition(1,nUserRefant-1));
6697 :
6698 : //cout << "refantchoices = " << refantchoices << endl;
6699 :
6700 :
6701 0 : if (refantmode()=="strict") {
6702 0 : nchoices=1;
6703 0 : refantchoices.resize(1,True);
6704 : }
6705 :
6706 0 : Vector<Int> nPol(nSpw(),nPar()); // TBD:or 1, if data was single pol
6707 :
6708 0 : if (nPar()==2) {
6709 : // Verify that 2nd poln has unflagged solutions, PER SPW
6710 0 : ROCTMainColumns ctmc(*ct_);
6711 :
6712 0 : Block<String> cols(1);
6713 0 : cols[0]="SPECTRAL_WINDOW_ID";
6714 0 : CTIter ctiter(*ct_,cols);
6715 0 : Cube<Bool> fl;
6716 :
6717 0 : while (!ctiter.pastEnd()) {
6718 :
6719 0 : Int ispw=ctiter.thisSpw();
6720 0 : fl.assign(ctiter.flag());
6721 :
6722 0 : IPosition blc(3,0,0,0), trc(fl.shape());
6723 0 : trc-=1; trc(0)=blc(0)=1;
6724 :
6725 : // cout << "ispw = " << ispw << " nfalse(fl(1,:,:)) = " << nfalse(fl(blc,trc)) << endl;
6726 :
6727 : // If there are no unflagged solutions in 2nd pol,
6728 : // avoid it in refant calculations
6729 0 : if (nfalse(fl(blc,trc))==0)
6730 0 : nPol(ispw)=1;
6731 :
6732 0 : ctiter.next();
6733 0 : }
6734 0 : }
6735 : // cout << "nPol = " << nPol << endl;
6736 :
6737 0 : Bool usedaltrefant(false);
6738 0 : Int currrefant(refantchoices(0)), lastrefant(-1);
6739 :
6740 0 : Block<String> cols(2);
6741 0 : cols[0]="SPECTRAL_WINDOW_ID";
6742 0 : cols[1]="TIME";
6743 0 : CTIter ctiter(*ct_,cols);
6744 :
6745 : // Arrays to hold per-timestamp solutions
6746 0 : Cube<Complex> solA, solB;
6747 0 : Cube<Bool> flA, flB;
6748 0 : Vector<Int> ant1A, ant1B, ant2B;
6749 0 : Matrix<Complex> refPhsr; // the reference phasor [npol,nchan]
6750 0 : Int lastspw(-1);
6751 0 : Bool first(true);
6752 0 : while (!ctiter.pastEnd()) {
6753 0 : Int ispw=ctiter.thisSpw();
6754 0 : if (ispw!=lastspw) first=true; // spw changed, start over
6755 :
6756 : // Read in the current sol, fl, ant1:
6757 0 : solB.assign(ctiter.cparam());
6758 0 : flB.assign(ctiter.flag());
6759 0 : ant1B.assign(ctiter.antenna1());
6760 0 : ant2B.assign(ctiter.antenna2());
6761 :
6762 : // First time thru, 'previous' solution same as 'current'
6763 0 : if (first) {
6764 0 : solA.reference(solB);
6765 0 : flA.reference(flB);
6766 0 : ant1A.reference(ant1B);
6767 : }
6768 0 : IPosition shB(solB.shape());
6769 0 : IPosition shA(solA.shape());
6770 :
6771 : // Find a good refant at this time
6772 : // A good refant is one that is unflagged in all polarizations
6773 : // in the current(B) and previous(A) intervals (so they can be connected)
6774 0 : Int irefA(0),irefB(0); // index on 3rd axis of solution arrays
6775 0 : Int ichoice(0); // index in refantchoicelist
6776 0 : Bool found(false);
6777 0 : IPosition blcA(3,0,0,0),trcA(shA),blcB(3,0,0,0),trcB(shB);
6778 0 : trcA-=1; trcA(0)=trcA(2)=0;
6779 0 : trcB-=1; trcB(0)=trcB(2)=0;
6780 0 : ichoice=0;
6781 0 : while (!found && ichoice<nchoices) {
6782 : // Find index of current refant choice
6783 0 : irefA=irefB=0;
6784 0 : while (ant1A(irefA)!=refantchoices(ichoice) && irefA<shA(2)) ++irefA;
6785 0 : while (ant1B(irefB)!=refantchoices(ichoice) && irefB<shB(2)) ++irefB;
6786 :
6787 0 : if (irefA<shA(2) && irefB<shB(2)) {
6788 :
6789 : // cout << " Trial irefA,irefB: " << irefA << "," << irefB
6790 : // << " Ants=" << ant1A(irefA) << "," << ant1B(irefB) << endl;
6791 :
6792 0 : blcA(2)=trcA(2)=irefA;
6793 0 : blcB(2)=trcB(2)=irefB;
6794 0 : found=true; // maybe
6795 0 : for (Int ipol=0;ipol<nPol(ispw);++ipol) {
6796 0 : blcA(0)=trcA(0)=blcB(0)=trcB(0)=ipol;
6797 0 : found &= (nfalse(flA(blcA,trcA))>0); // previous interval
6798 0 : found &= (nfalse(flB(blcB,trcB))>0); // current interval
6799 : }
6800 : }
6801 : else
6802 : // irefA or irefB out-of-range
6803 0 : found=false; // Just to be sure
6804 :
6805 0 : if (!found) ++ichoice; // try next choice next round
6806 :
6807 : }
6808 :
6809 0 : if (found) {
6810 : // at this point, irefA/irefB point to a good refant
6811 :
6812 : // Keep track
6813 0 : usedaltrefant|=(ichoice>0);
6814 0 : currrefant=refantchoices(ichoice);
6815 0 : refantchoices(1)=currrefant; // 2nd priorty next time
6816 :
6817 : // Mark refant in activity rec
6818 0 : refantMap_[ctiter.thisSpw()][currrefant] += 1;
6819 :
6820 : // cout << " currrefant = " << currrefant << " (" << ichoice << ")" << endl;
6821 :
6822 : // cout << " Final irefA,irefB: " << irefA << "," << irefB
6823 : // << " Ants=" << ant1A(irefA) << "," << ant1B(irefB) << endl;
6824 :
6825 :
6826 : // Only report if using an alternate refant
6827 0 : if (currrefant!=lastrefant && ichoice>0) {
6828 : logSink()
6829 : << "At "
6830 0 : << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7)
6831 : << " ("
6832 : << "Spw=" << ctiter.thisSpw()
6833 : << ", Fld=" << ctiter.thisField()
6834 : << ")"
6835 0 : << ", using refant " << msmc().antennaName(currrefant)
6836 : << " (id=" << currrefant
6837 : << ")" << " (alternate)"
6838 0 : << LogIO::POST;
6839 : }
6840 :
6841 : // Form reference phasor [nPar,nChan]
6842 0 : Matrix<Complex> rA,rB;
6843 0 : Matrix<Float> ampA,ampB;
6844 0 : Matrix<Bool> rflA,rflB;
6845 0 : rB.assign(solB.xyPlane(irefB));
6846 0 : rflB.assign(flB.xyPlane(irefB));
6847 0 : switch (this->type()) {
6848 0 : case VisCal::G:
6849 : case VisCal::B:
6850 : case VisCal::T: {
6851 0 : ampB=amplitude(rB);
6852 0 : rflB(ampB<FLT_EPSILON)=true; // flag...
6853 0 : rB(rflB)=Complex(1.0); // ...and reset zeros
6854 0 : ampB(rflB)=1.0;
6855 0 : rB/=ampB; // rB now normalized ("phase"-only)
6856 0 : break;
6857 : }
6858 0 : case VisCal::D: {
6859 : // Fill 2nd pol with negative conj of 1st pol
6860 0 : rB.row(1)=-conj(rB.row(0));
6861 0 : break;
6862 : }
6863 0 : default:
6864 0 : throw(AipsError("SVC::applyRefAnt attempted for inapplicable type"));
6865 : }
6866 :
6867 0 : if (!first) {
6868 : // Get and condition previous phasor for the current refant
6869 0 : rA.assign(solA.xyPlane(irefA));
6870 0 : rflA.assign(flA.xyPlane(irefA));
6871 0 : switch (this->type()) {
6872 0 : case VisCal::G:
6873 : case VisCal::B:
6874 : case VisCal::T: {
6875 0 : ampA=amplitude(rA);
6876 0 : rflA(ampA<FLT_EPSILON)=true; // flag...
6877 0 : rA(rflA)=Complex(1.0); // ...and reset zeros
6878 0 : ampA(rflA)=1.0;
6879 0 : rA/=ampA; // rA now normalized ("phase"-only)
6880 :
6881 : // Phase difference (as complex) relative to last
6882 0 : rB/=rA;
6883 0 : break;
6884 : }
6885 0 : case VisCal::D: {
6886 : //
6887 0 : rA.row(1)=-conj(rA.row(0));
6888 :
6889 : // Complex difference relative to last
6890 0 : rB-=rA;
6891 0 : break;
6892 : }
6893 0 : default:
6894 0 : throw(AipsError("SVC::applyRefAnt attempted for inapplicable type"));
6895 : }
6896 :
6897 : // Accumulate flags
6898 0 : rflB&=rflA;
6899 : }
6900 :
6901 : // cout << " rB = " << rB << endl;
6902 : // cout << boolalpha << " rflB = " << rflB << endl;
6903 : // TBD: fillChanGaps?
6904 :
6905 : // Now apply reference phasor to all antennas
6906 0 : Matrix<Complex> thissol;
6907 0 : for (Int iant=0;iant<shB(2);++iant) {
6908 0 : thissol.reference(solB.xyPlane(iant));
6909 0 : switch (this->type()) {
6910 0 : case VisCal::G:
6911 : case VisCal::B:
6912 : case VisCal::T: {
6913 : // Complex division == phase subtraction
6914 0 : thissol/=rB;
6915 0 : break;
6916 : }
6917 0 : case VisCal::D: {
6918 : // Complex subtraction
6919 0 : thissol-=rB;
6920 0 : break;
6921 : }
6922 0 : default:
6923 0 : throw(AipsError("SVC::applyRefAnt attempted for inapplicable type"));
6924 : }
6925 : }
6926 :
6927 : // Set refant, so we can put it back
6928 0 : ant2B=currrefant;
6929 :
6930 : // put back referenced solutions
6931 0 : ctiter.setcparam(solB);
6932 0 : ctiter.setantenna2(ant2B);
6933 :
6934 : // Next time thru, solB is previous
6935 0 : solA.reference(solB);
6936 0 : flA.reference(flB);
6937 0 : ant1A.reference(ant1B);
6938 0 : solB.resize(); // (break references)
6939 0 : flB.resize();
6940 0 : ant1B.resize();
6941 :
6942 0 : lastrefant=currrefant;
6943 0 : first=false; // avoid first-pass stuff from now on
6944 :
6945 0 : } // found
6946 : else {
6947 : logSink()
6948 : << "At "
6949 0 : << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7)
6950 : << " ("
6951 : << "Spw=" << ctiter.thisSpw()
6952 : << ", Fld=" << ctiter.thisField()
6953 : << ")"
6954 : << ", refant (id=" << currrefant
6955 : << ") was flagged; flagging all antennas strictly."
6956 0 : << LogIO::POST;
6957 : // Flag all solutions in this interval
6958 0 : flB.set(True);
6959 0 : ctiter.setflag(flB);
6960 : }
6961 :
6962 : // advance to the next interval
6963 0 : lastspw=ispw;
6964 0 : ctiter.next();
6965 0 : }
6966 :
6967 0 : if (usedaltrefant)
6968 : logSink() << LogIO::NORMAL
6969 : << " NB: An alternate refant was used at least once to maintain" << endl
6970 : << " phase continuity where the user's preferred refant drops out." << endl
6971 : << " Alternate refants are held constant in phase (_not_ zeroed)" << endl
6972 : << " during these periods, and the preferred refant may return at" << endl
6973 : << " a non-zero phase. This is generally harmless."
6974 0 : << LogIO::POST;
6975 :
6976 0 : return;
6977 :
6978 0 : }
6979 :
6980 :
6981 29 : void SolvableVisJones::fluxscale(const String& outfile,
6982 : const Vector<Int>& refFieldIn,
6983 : const Vector<Int>& tranFieldIn,
6984 : const Vector<Int>& inRefSpwMap,
6985 : const Vector<String>& fldNames,
6986 : const Float& inGainThres,
6987 : const String& antSel,
6988 : const String& timerangeSel,
6989 : const String& scanSel,
6990 : fluxScaleStruct& oFluxScaleStruct,
6991 : const String& oListFile,
6992 : const Bool& incremental,
6993 : const Int& fitorder,
6994 : const Bool& display) {
6995 :
6996 : //String outCalTabName="_tmp_testfluxscaletab";
6997 29 : String outCalTabName=outfile;
6998 :
6999 : //timerange
7000 : //String timerange("");
7001 : //String scanSel("");
7002 : // turn on incremental caltable mode
7003 : //Bool incremental = true;
7004 : //Bool fitperchan = true;
7005 :
7006 : // threshold for gain (amplitude) to be used in
7007 : // fluxscale determination
7008 : // -1: no threshold
7009 : // plot histogram of gain ratio
7010 29 : Bool report_p=display;
7011 :
7012 29 : if (incremental) {
7013 : logSink() << LogIO::NORMAL
7014 : << "Generating an incremental caltable"
7015 6 : << LogIO::POST;
7016 : }
7017 :
7018 29 : if (!ct_ || ct_->nrow()<1)
7019 0 : throw(AipsError("SVJ:fluxscale: Empty or absent caltable specified"));
7020 :
7021 : // For updating the MS History Table
7022 : // LogSink logSink_p = LogSink(LogMessage::NORMAL, false);
7023 : // logSink_p.clearLocally();
7024 : // LogIO oss(LogOrigin("calibrater", "fluxscale()"), logSink_p);
7025 :
7026 : // PtrBlocks to hold mean gain moduli and related
7027 29 : PtrBlock< Cube<Bool>* > MGOK;
7028 29 : PtrBlock< Cube<Double>* > MG;
7029 29 : PtrBlock< Cube<Double>* > MG2;
7030 29 : PtrBlock< Cube<Double>* > MGWT;
7031 29 : PtrBlock< Cube<Double>* > MGVAR;
7032 29 : PtrBlock< Cube<Int>* > MGN;
7033 29 : PtrBlock< Cube<Int>* > MGNALL;
7034 :
7035 29 : Int nMSFld; fldNames.shape(nMSFld);
7036 :
7037 : // Assemble available field list from the NewCalTable
7038 29 : ROCTMainColumns mcols(*ct_);
7039 29 : Vector<Int> fldList;
7040 29 : mcols.fieldId().getColumn(fldList);
7041 29 : Int nFldList=genSort(fldList,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
7042 29 : fldList.resize(nFldList,true);
7043 :
7044 29 : Int nFld=max(fldList)+1;
7045 :
7046 : //get Antenna names
7047 29 : MSAntennaColumns antcol(ct_->antenna());
7048 29 : Vector<String> antNames(antcol.name().getColumn());
7049 :
7050 29 : Vector<Double> solFreq(nSpw(),-1.0);
7051 29 : Vector<Double> mgreft(nFld,0);
7052 :
7053 :
7054 : try {
7055 :
7056 : // Resize, NULL-initialize PtrBlocks
7057 29 : MGOK.resize(nFld); MGOK=NULL;
7058 29 : MG.resize(nFld); MG=NULL;
7059 29 : MG2.resize(nFld); MG2=NULL;
7060 29 : MGWT.resize(nFld); MGWT=NULL;
7061 29 : MGVAR.resize(nFld); MGVAR=NULL;
7062 29 : MGN.resize(nFld); MGN=NULL;
7063 29 : MGNALL.resize(nFld); MGNALL=NULL;
7064 :
7065 : // sort user-specified fields
7066 29 : Vector<Int> refField; refField = refFieldIn;
7067 : Int nRef,nTran;
7068 29 : nRef=genSort(refField,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
7069 : // temp copy of tranFieldIn
7070 29 : std::vector<Int> tmpTranField;
7071 29 : tranFieldIn.tovector(tmpTranField);
7072 62 : for (Int iRef=0; iRef<nRef; iRef++) {
7073 33 : auto iidx = std::find(tmpTranField.begin(),tmpTranField.end(),refField(iRef));
7074 33 : if (iidx != tmpTranField.end()) {
7075 4 : logSink() << "The reference field, "<<fldNames(*iidx)
7076 : << " , is also listed in the transfer fields. "
7077 : <<" It will be ignored for further scaling process."
7078 2 : << LogIO::POST;
7079 2 : tmpTranField.erase(iidx);
7080 : }
7081 : }
7082 : //Vector<Int> tranField; tranField = tranFieldIn;
7083 29 : Vector<Int> tranField(tmpTranField);
7084 29 : nTran=genSort(tranField,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
7085 :
7086 : // make masks for ref/tran among available fields
7087 29 : Vector<Bool> tranmask(nFldList,true);
7088 29 : Vector<Bool> refmask(nFldList,false);
7089 107 : for (Int iFld=0; iFld<nFldList; iFld++) {
7090 78 : if ( anyEQ(refField,fldList(iFld)) ) {
7091 : // this is a ref field
7092 33 : refmask(iFld)=true;
7093 33 : tranmask(iFld)=false;
7094 : }
7095 : }
7096 :
7097 : // Check availability of all ref fields
7098 29 : if (ntrue(refmask)==0) {
7099 0 : throw(AipsError(" Cannot find specified reference field(s)"));
7100 : }
7101 : // Any fields present other than ref fields?
7102 29 : if (ntrue(tranmask)==0) {
7103 0 : throw(AipsError(" Cannot find solutions for transfer field(s)"));
7104 : }
7105 :
7106 : // make implicit reference field list
7107 29 : MaskedArray<Int> mRefFldList(fldList,LogicalArray(refmask));
7108 29 : Vector<Int> implRefField(mRefFldList.getCompressedArray());
7109 :
7110 : // Check for missing reference fields
7111 29 : if (Int(ntrue(refmask)) < nRef) {
7112 0 : ostringstream x;
7113 0 : for (Int iRef=0; iRef<nRef; iRef++) {
7114 0 : if ( !anyEQ(fldList,refField(iRef)) ) {
7115 0 : if (refField(iRef)>-1 && refField(iRef) < nMSFld) x << fldNames(refField(iRef)) << " ";
7116 0 : else x << "Index="<<refField(iRef)+1<<"=out-of-range ";
7117 : }
7118 : }
7119 0 : String noRefSol=x.str();
7120 : logSink() << LogIO::WARN
7121 : << " The following reference fields have no solutions available: "
7122 : << noRefSol
7123 0 : << LogIO::POST;
7124 0 : refField.reference(implRefField);
7125 0 : }
7126 29 : refField.shape(nRef);
7127 :
7128 : // make implicit tranfer field list
7129 29 : MaskedArray<Int> mTranFldList(fldList,LogicalArray(tranmask));
7130 29 : Vector<Int> implTranField(mTranFldList.getCompressedArray());
7131 29 : Int nImplTran; implTranField.shape(nImplTran);
7132 :
7133 : // cout << "implTranField = " << implTranField << endl;
7134 :
7135 : // Check availability of transfer fields
7136 :
7137 : // If user specified no transfer fields, use implicit
7138 : // transfer field list, ELSE check for missing tran fields
7139 : // among those they specified
7140 29 : if (nTran==0) {
7141 17 : tranField.reference(implTranField);
7142 : logSink() << LogIO::NORMAL
7143 : << " Assuming all non-reference fields are transfer fields."
7144 17 : << LogIO::POST;
7145 : } else {
7146 15 : if ( !(nTran==nImplTran &&
7147 3 : allEQ(tranField,implTranField)) ) {
7148 9 : ostringstream x;
7149 18 : for (Int iTran=0; iTran<nTran; iTran++) {
7150 9 : if ( !anyEQ(implTranField,tranField(iTran)) ) {
7151 0 : if (tranField(iTran)>-1 && tranField(iTran) < nMSFld) x << fldNames(tranField(iTran)) << " ";
7152 0 : else x << "Index="<<tranField(iTran)+1<<"=out-of-range ";
7153 : }
7154 : }
7155 9 : String noTranSol=x.str();
7156 9 : if (x!="") {
7157 : logSink() << LogIO::WARN
7158 : << " The following transfer fields have no solutions available: "
7159 : << noTranSol
7160 0 : << LogIO::POST;
7161 : }
7162 : //tranField.reference(implTranField);
7163 9 : }
7164 : }
7165 29 : tranField.shape(nTran);
7166 :
7167 : // make a combined field list
7168 58 : std::vector<Int> allfields(refField.begin(), refField.end());
7169 29 : allfields.insert(allfields.end(), tranField.begin(), tranField.end());
7170 :
7171 : // Report ref, tran field info
7172 29 : String refNames(fldNames(refField(0)));
7173 33 : for (Int iRef=1; iRef<nRef; iRef++) {
7174 4 : refNames+=" ";
7175 4 : refNames+=fldNames(refField(iRef));
7176 : }
7177 : logSink() << " Found reference field(s): " << refNames
7178 29 : << LogIO::POST;
7179 29 : String tranNames(fldNames(tranField(0)));
7180 35 : for (Int iTran=1; iTran<nTran; iTran++) {
7181 6 : tranNames+=" ";
7182 6 : tranNames+=fldNames(tranField(iTran));
7183 : }
7184 : logSink() << " Found transfer field(s): " << tranNames
7185 29 : << LogIO::POST;
7186 :
7187 : // Handle spw referencing
7188 29 : Vector<Int> refSpwMap;
7189 29 : refSpwMap.resize(nSpw());
7190 29 : indgen(refSpwMap);
7191 :
7192 29 : if (inRefSpwMap(0)>-1) {
7193 5 : if (inRefSpwMap.nelements()==1) {
7194 0 : refSpwMap=inRefSpwMap(0);
7195 0 : logSink() << " All spectral windows will be referenced to spw=" << inRefSpwMap(0)
7196 0 : << LogIO::POST;
7197 : } else {
7198 23 : for (Int i=0; i<Int(inRefSpwMap.nelements()); i++) {
7199 18 : if (inRefSpwMap(i)>-1 && inRefSpwMap(i)!=i) {
7200 9 : refSpwMap(i)=inRefSpwMap(i);
7201 18 : logSink() << " Spw=" << i << " will be referenced to spw=" << inRefSpwMap(i)
7202 9 : << LogIO::POST;
7203 : }
7204 : }
7205 : }
7206 : }
7207 :
7208 : // Field names for log messages
7209 :
7210 : // cout << "Filling mgnorms....";
7211 :
7212 29 : Matrix<Float> medianGains(nFld,nSpw(),0.0); //keeps median (amplitude) gains for each field for each spw
7213 : { // make an inner scope
7214 29 : Block<String> cols(4);
7215 29 : cols[0]="SPECTRAL_WINDOW_ID";
7216 29 : cols[1]="TIME";
7217 29 : cols[2]="FIELD_ID"; // should usually be degenerate with TIME?
7218 29 : cols[3]="ANTENNA1";
7219 : //ROCTIter ctiter(*ct_,cols);
7220 :
7221 : // Loop over solutions and fill the calculation
7222 29 : Cube<Bool> mgok; // For referencing PtrBlocks...
7223 29 : Cube<Double> mg;
7224 29 : Cube<Double> mg2;
7225 29 : Cube<Double> mgwt;
7226 29 : Cube<Int> mgn;
7227 29 : Cube<Int> mgnall;
7228 29 : Int prevFld(-1);
7229 :
7230 29 : Int lastFld(-1);
7231 :
7232 : // determine median gain amplitude for each field
7233 : // use CTinterface to appy selection with MSSelection syntax
7234 29 : NewCalTable selct(*ct_);
7235 29 : CTInterface cti(*ct_);
7236 29 : Vector<Int> selAntList;
7237 29 : Vector<Int> deselAntList;
7238 29 : Vector<Int> allAntList(nElem());
7239 29 : indgen(allAntList);
7240 58 : vector<Int> tmpAllAntList(allAntList.begin(),allAntList.end());
7241 : //
7242 : // Check if antenna specific time/scan selection is needed.
7243 : // If so get selected time col for later use to flag the data.
7244 : // The negation '!' is used as a keyword to trigger such a selection mode.
7245 29 : Bool doPerAntSel(false);
7246 29 : Vector<Double> selTime;
7247 29 : if (antSel!="" ) {
7248 4 : if (antSel.contains(casacore::Regex("^!")) && (timerangeSel!="" || scanSel!="")) {
7249 2 : doPerAntSel = true;
7250 : // if doPerAntSel time/scan sel only applied to deselected ant in antSel
7251 : // so need to construct selected table based on that
7252 2 : MSSelection msssub;
7253 2 : String antsel=antSel;
7254 2 : antsel.ltrim('!');
7255 2 : msssub.setAntennaExpr(antsel);
7256 2 : if (timerangeSel != "") msssub.setTimeExpr(timerangeSel);
7257 2 : if (scanSel != "") msssub.setScanExpr(scanSel);
7258 2 : TableExprNode tensub=msssub.toTableExprNode(&cti);
7259 2 : getSelectedTable(selct,*ct_,tensub,"");
7260 2 : ROCTMainColumns ctmc(selct);
7261 2 : selTime=ctmc.time().getColumn();
7262 2 : deselAntList=ctmc.antenna1().getColumn();
7263 2 : Int ndeselAnt=genSort(deselAntList,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
7264 2 : deselAntList.resize(ndeselAnt,true);
7265 2 : }
7266 : }
7267 :
7268 29 : Bool firstpass(true);
7269 113 : for (Int iFld=0; iFld<nFld; iFld++) {
7270 :
7271 84 : MSSelection mss;
7272 : //String antSel("!ea25");
7273 : //String antSel("0~26");
7274 : //String antSel("");
7275 84 : mss.setFieldExpr(String::toString(iFld));
7276 84 : if (antSel!="") {
7277 11 : if (!doPerAntSel) {
7278 : // applied selections globally
7279 5 : mss.setAntennaExpr(antSel);
7280 5 : if (timerangeSel!="") mss.setTimeExpr(timerangeSel);
7281 5 : if (scanSel!="") mss.setScanExpr(scanSel);
7282 : }
7283 : } else {
7284 73 : selAntList=allAntList;
7285 : }
7286 84 : std::vector<Int> tmpSelAntList;
7287 84 : Vector<Bool> validSels(nSpw(),true);
7288 292 : for (Int iSpw=0; iSpw<nSpw(); iSpw++) {
7289 : //reset MSSelection
7290 208 : mss.clear(MSSelection::SPW_EXPR);
7291 : //mss.setFieldExpr(String::toString(iFld));
7292 208 : mss.setSpwExpr(String::toString(iSpw));
7293 : try {
7294 208 : TableExprNode ten=mss.toTableExprNode(&cti);
7295 230 : getSelectedTable(selct,*ct_,ten,"");
7296 186 : ROCTMainColumns ctmc(selct);
7297 186 : Array<Float> outparams;
7298 186 : Array<Bool> flagcol=ctmc.flag().getColumn();
7299 186 : Vector<Double> timecol=ctmc.time().getColumn();
7300 186 : Vector<Int> antenna1=ctmc.antenna1().getColumn();
7301 : // Do antenna-specific the selections in time
7302 186 : IPosition flshp = flagcol.shape();
7303 186 : if (doPerAntSel && selTime.nelements()!=0) {
7304 398 : for (uInt ifg = 0; ifg < flshp(2); ifg++) {
7305 1176 : for (Int ipar = 0; ipar < nPar(); ipar++) {
7306 784 : if (anyEQ(deselAntList, antenna1(ifg)) && !anyEQ(selTime, timecol(ifg)))
7307 : //outflag(IPosition(3,ipar,0,ifg))=false;
7308 8 : flagcol(IPosition(3,ipar,0,ifg))=true;
7309 : }
7310 : }
7311 : }
7312 : // reverse the flag for a masked array
7313 186 : LogicalArray outflag(!flagcol);
7314 : //cerr<<"ntrue outflag ="<<ntrue(outflag)<<endl;
7315 186 : ctmc.fparamArray(outparams,"AP");
7316 : // get subset (amp only) of the array
7317 186 : IPosition arshp = outparams.shape();
7318 186 : IPosition start(3,0,0,0);
7319 186 : Int pinc = nPar()!=1 ? 2: 1;
7320 186 : Int pshp = arshp(0)!=1 ? Int(arshp(0)/2) : 1;
7321 : //IPosition length(3,Int(arshp(0)/pinc),1,arshp(arshp.nelements()-1));
7322 186 : IPosition length(3,pshp,1,arshp(arshp.nelements()-1));
7323 186 : IPosition stride(3,pinc,1,1);
7324 186 : Slicer slicer(start,length,stride);
7325 186 : Array<Float> subarr=outparams(slicer);
7326 186 : MaskedArray<Float> moutparams(subarr,outflag);
7327 : //Vector<Float> subarr2 = moutparams.getCompressedArray();
7328 : // Get selected antenna list in ant ids.
7329 : // While it is applied to all fields and spws
7330 : // the actual selections happen per spw. So we do it here but only for the first
7331 : // successful selection for the data and use it for the rest of the process.
7332 186 : if (antSel!="" && firstpass) {
7333 4 : Vector<Int> selantlist=ctmc.antenna1().getColumn();
7334 4 : Int nSelAnt=genSort(selantlist,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
7335 4 : selantlist.resize(nSelAnt,true);
7336 4 : selAntList=selantlist;
7337 : //cerr<<"selantlist.nelements()="<<selantlist.nelements()<<endl;
7338 4 : String oMsg( "" );
7339 4 : if ( doPerAntSel ) {
7340 2 : oMsg+="Selected data range for antenna(s): "+String::toString(deselAntList)+",";
7341 2 : if ( timerangeSel!="") oMsg+= " time range:"+timerangeSel;
7342 2 : if ( scanSel!="") oMsg+= " scan(s):"+scanSel;
7343 : }
7344 : else {
7345 2 : oMsg+=" Selected antennas: "+String::toString(selAntList);
7346 : }
7347 4 : logSink() << oMsg << LogIO::POST;
7348 4 : firstpass=false;
7349 4 : }
7350 :
7351 : //medianGains(iFld,iSpw)=median(subarr2);
7352 186 : medianGains(iFld,iSpw)=median(moutparams);
7353 185 : String oMsg( "" );
7354 370 : oMsg+="median(field="+String::toString(iFld)+",spw="+String::toString(iSpw)+")="+\
7355 555 : String::toString(medianGains(iFld,iSpw));
7356 185 : logSink() << LogIO::NORMAL3<< oMsg << LogIO::POST;
7357 245 : } catch (...) {
7358 23 : if (anyEQ(tranField,iFld)) validSels[iSpw]=false;
7359 23 : }
7360 : }
7361 84 : if (!ntrue(validSels))
7362 0 : throw(AipsError("The input selections results in empy data selection for the transfer field="
7363 0 : +String::toString(iFld)));
7364 84 : } //for-iFld
7365 29 : NewCalTable selct2(*ct_);
7366 29 : CTInterface cti2(*ct_);
7367 29 : MSSelection mss2;
7368 29 : String fieldstr;
7369 97 : for (uInt iselfld=0; iselfld<allfields.size();iselfld++) {
7370 68 : fieldstr+=String::toString(allfields[iselfld]);
7371 68 : if (iselfld!=allfields.size()-1) fieldstr+=',';
7372 : }
7373 29 : mss2.setFieldExpr(fieldstr);
7374 29 : if (!doPerAntSel) {
7375 27 : mss2.setAntennaExpr(antSel);
7376 27 : mss2.setTimeExpr(timerangeSel);
7377 27 : mss2.setScanExpr(scanSel);
7378 : }
7379 29 : TableExprNode ten2=mss2.toTableExprNode(&cti2);
7380 29 : getSelectedTable(selct2,*ct_,ten2,"");
7381 :
7382 29 : ROCTIter ctiter(selct2,cols);
7383 13935 : while (!ctiter.pastEnd()) {
7384 13906 : Int iSpw(ctiter.thisSpw());
7385 13906 : Int iFld(ctiter.thisField());
7386 13906 : Int iAnt(ctiter.thisAntenna1());
7387 : //refTime_ = ctiter.thisTime();
7388 13906 : if (iFld > prevFld) {
7389 586 : mgreft = ctiter.thisTime();
7390 : }
7391 13906 : prevFld = iFld;
7392 :
7393 13906 : if (solFreq(iSpw)<0.0) {
7394 78 : Vector<Double> freq;
7395 78 : ctiter.freq(freq);
7396 78 : uInt nFrq=freq.nelements();
7397 78 : solFreq(iSpw)=freq(nFrq/2);
7398 78 : }
7399 :
7400 13906 : if (MGOK[iFld]==NULL) {
7401 : // First time this field, allocate ant/spw matrices
7402 68 : MGOK[iFld] = new Cube<Bool>(nPar(),nElem(),nSpw(),false);
7403 68 : MG[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7404 68 : MG2[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7405 68 : MGWT[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7406 68 : MGVAR[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7407 68 : MGN[iFld] = new Cube<Int>(nPar(),nElem(),nSpw(),0);
7408 : // for reporting numbers of solution used
7409 68 : MGNALL[iFld] = new Cube<Int>(nPar(),nElem(),nSpw(),0);
7410 :
7411 : }
7412 : // References to PBs for syntactical convenience
7413 : // TBD: should need to do this for each iteration (nAnt times redundant!)
7414 13906 : if (iFld!=lastFld) {
7415 1125 : mgok.reference(*(MGOK[iFld]));
7416 1125 : mg.reference(*(MG[iFld]));
7417 1125 : mg2.reference(*(MG2[iFld]));
7418 1125 : mgwt.reference(*(MGWT[iFld]));
7419 1125 : mgn.reference(*(MGN[iFld]));
7420 1125 : mgnall.reference(*(MGNALL[iFld]));
7421 : }
7422 :
7423 : // References to PBs for syntactical convenience
7424 : // TBD: Handle "iFitwt" from NewCalTable?
7425 : // Double wt=cs().iFitwt(iSpw)(iAnt,islot);
7426 13906 : Double wt=1;
7427 :
7428 : // amps, flags [npar] (one channel, one antenna)
7429 : // check for data shape (e.g. duplicated entries)
7430 13906 : Cube<Complex> CParam(ctiter.cparam());
7431 13906 : IPosition testShape=CParam.shape();
7432 13906 : if (testShape[2]!=1) {
7433 0 : if (testShape[2]>1) {
7434 : // possible cause: append=true in gaincal
7435 0 : throw(AipsError("Found multiple gain solutions in a single timestamp for fieldid="+String::toString(iFld)+". Please check the input Caltable."));
7436 : }
7437 : else {
7438 0 : throw(AipsError("Found gain solution array shape, "+String::toString(testShape)+" while expected [2,1,1]. Please check the input Caltable."));
7439 : }
7440 : }
7441 : //Vector<Float> amp(amplitude(ctiter.cparam())[0]);
7442 13906 : Vector<Float> amp(amplitude(CParam));
7443 13906 : Vector<Bool> fl(ctiter.flag());
7444 41718 : for (Int ipar=0; ipar<nPar(); ipar++) {
7445 27812 : if (!fl(ipar)) {
7446 26700 : Double gn=amp(ipar); // converts to Double
7447 : // evaluate input gain to be within the threshold
7448 26700 : Float lowbound= (inGainThres >0 and inGainThres <1.0)? 1.0 - inGainThres : 0.0;
7449 26700 : if (inGainThres==0) lowbound=1.0;
7450 : //if ((anyEQ(selAntList,iAnt) && && (inGainThres < 0 ||
7451 26970 : if (inGainThres < 0 ||
7452 : // (gn >= lowbound*medianGains(iFld,iSpw))) {
7453 : // take both lower and upper bounds
7454 270 : (gn >= lowbound*medianGains(iFld,iSpw) and
7455 265 : gn <= (1.0 + inGainThres) * medianGains(iFld,iSpw))) {
7456 :
7457 26650 : if (doPerAntSel && selTime.nelements() != 0) {
7458 540 : if (anyEQ(deselAntList,iAnt) && !anyEQ(selTime,ctiter.thisTime())) {
7459 6 : logSink()<<LogIO::NORMAL3<<"skipped "<<ctiter.thisTime()<<" for iAnt="<<iAnt<<LogIO::POST;
7460 6 : continue;
7461 : }
7462 : }
7463 : //cerr<<"fld="<<iFld<<" spw="<<iSpw<<" ant="<<iAnt<<" gn="<<gn<<" median="<<medianGains(iFld,iSpw)<<endl;
7464 26644 : mgok(ipar,iAnt,iSpw)=true;
7465 26644 : mg(ipar,iAnt,iSpw) += (wt*gn);
7466 26644 : mg2(ipar,iAnt,iSpw)+= (wt*gn*gn);
7467 26644 : mgn(ipar,iAnt,iSpw)++;
7468 26644 : mgwt(ipar,iAnt,iSpw)+=wt;
7469 : }
7470 : else {
7471 50 : String debugMsg( "" );
7472 100 : debugMsg+="Rejected field="+String::toString(iFld)+" spw="+String::toString(iSpw)+" antenna="+String::toString(iAnt)+
7473 200 : "; gain(amp)="+String::toString(gn)+" is outside the accepted range:"+String::toString(lowbound*medianGains(iFld,iSpw))+
7474 150 : " ~ "+String::toString((1.0 + inGainThres) * medianGains(iFld,iSpw));
7475 50 : logSink() << LogIO::DEBUG1 << debugMsg << LogIO::POST;
7476 50 : }
7477 26694 : mgnall(ipar,iAnt,iSpw)++;
7478 : }
7479 : }
7480 13906 : lastFld=iFld;
7481 13906 : ctiter.next();
7482 13906 : }//end of while
7483 29 : } // end inner scope
7484 :
7485 : //for reporting only
7486 29 : if (inGainThres>=0.0) {
7487 1 : String oMsg( "" );
7488 1 : oMsg+=" Applying gain threshold="+String::toString(inGainThres);
7489 1 : logSink() << oMsg << LogIO::POST;
7490 1 : Bool hasFlaggedData(false);
7491 : //for (Int iFld=0; iFld<nFld; iFld++) {
7492 : Int iFld;
7493 3 : for (int idx=0; idx < (int) allfields.size(); idx++) {
7494 2 : iFld = allfields[idx];
7495 2 : if (MGOK[iFld]!=NULL) {
7496 2 : Cube<Bool> mgok; mgok.reference(*(MGOK[iFld]));
7497 2 : Cube<Int> mgn; mgn.reference(*(MGN[iFld]));
7498 2 : Cube<Int> mgnall; mgnall.reference(*(MGNALL[iFld]));
7499 : //cerr<<"ntrue="<<ntrue(mgok)<< " shape="<<mgok.shape()<<endl;
7500 : //cerr<<"mgn shape="<<mgn.shape()<<endl;
7501 : //cerr<<"mgnall shape="<<mgnall.shape()<<endl;
7502 4 : for (Int iSpw=0; iSpw<nSpw(); iSpw++) {
7503 : //cerr<<"median gain="<<medianGains(iFld,iSpw)<<endl;
7504 58 : for (Int iAnt=0; iAnt<nElem(); iAnt++) {
7505 56 : IPosition start(3,0,iAnt,iSpw);
7506 56 : IPosition length(3,nPar(),1,1);
7507 56 : IPosition stride(3,1,1,1);
7508 56 : Slicer slicer(start,length,stride);
7509 : //if (ntrue(mgok(slicer))) {
7510 56 : if ( sum(mgn(slicer))<sum(mgnall(slicer)) ) {
7511 : //cerr<<"iFld:"<<iFld<<" iAnt:"<<iAnt<<" sum(mgn)="<<sum(mgn(slicer))<<" sum(mgnall(slicer))="<<sum(mgnall(slicer))<<endl;
7512 14 : Float frac=Float (sum(mgn(slicer)))/Float (sum(mgnall(slicer)));
7513 14 : ostringstream fracstream;
7514 14 : fracstream.precision(3);
7515 14 : if (frac<1.0) {
7516 : // report a fraction flagged
7517 14 : fracstream << (1.0-frac)*100.0;
7518 14 : oMsg="";
7519 : //cerr<<"iFld="<<iFld<<" iAnt="<<iAnt<<": "<<frac*100.0<<"% of "<<sum(mgnall(slicer))<<" will be excluded"<<endl;
7520 : //oMsg+=" Field ID="+String::toString(tranField(iFld))+" Antenna ID="+String::toString(iAnt)+": ";
7521 : //oMsg+=" Field ID="+String::toString(allfields[idx])+" Antenna ID="+String::toString(iAnt)+": ";
7522 14 : oMsg+=" "+fldNames(allfields[idx])+"(id="+String::toString(allfields[idx])+") Antenna:"+antNames(iAnt)+"(id="+String::toString(iAnt)+"): ";
7523 14 : oMsg+=fracstream.str()+" % of ";
7524 : //oMsg+=String::toString(sum(mgnall(slicer)) )+" solutions will be used";
7525 14 : oMsg+=String::toString(sum(mgnall(slicer)) )+" solution(s) will be excluded";
7526 14 : logSink() << oMsg << LogIO::POST;
7527 : }
7528 14 : hasFlaggedData=true;
7529 14 : }//ntrue()
7530 56 : } //iAnt
7531 : } //iSpw
7532 2 : }
7533 : }//iFld
7534 1 : if (!hasFlaggedData) {
7535 0 : oMsg=" None of the gains were exceeded the threshold.";
7536 0 : logSink() << oMsg << LogIO::POST;
7537 : }
7538 1 : }//gainthreshold
7539 : /*
7540 :
7541 : // fill per-ant -fld, -spw mean gain moduli
7542 : for (Int iSpw=0; iSpw<nSpw(); iSpw++) {
7543 :
7544 : if (cs().nTime(iSpw) > 0 ) {
7545 :
7546 : for (Int islot=0; islot<cs().nTime(iSpw); islot++) {
7547 : Int iFld=cs().fieldId(iSpw)(islot);
7548 : if (MGOK[iFld]==NULL) {
7549 : // First time this field, allocate ant/spw matrices
7550 : MGOK[iFld] = new Cube<Bool>(nPar(),nElem(),nSpw(),false);
7551 : MG[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7552 : MG2[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7553 : MGWT[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7554 : MGVAR[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7555 : MGN[iFld] = new Cube<Int>(nPar(),nElem(),nSpw(),0);
7556 :
7557 : }
7558 : // References to PBs for syntactical convenience
7559 : Cube<Bool> mgok; mgok.reference(*(MGOK[iFld]));
7560 : Cube<Double> mg; mg.reference(*(MG[iFld]));
7561 : Cube<Double> mg2; mg2.reference(*(MG2[iFld]));
7562 : Cube<Double> mgwt; mgwt.reference(*(MGWT[iFld]));
7563 : Cube<Int> mgn; mgn.reference(*(MGN[iFld]));
7564 :
7565 : for (Int iAnt=0; iAnt<nElem(); iAnt++) {
7566 : if (true) { // || antmask(iAnt)) {
7567 : Double wt=cs().iFitwt(iSpw)(iAnt,islot);
7568 :
7569 : for (Int ipar=0; ipar<nPar(); ipar++) {
7570 : IPosition ip(4,ipar,0,iAnt,islot);
7571 : if (cs().parOK(iSpw)(ip)) {
7572 : Double gn=abs( cs().par(iSpw)(ip) );
7573 : mgok(ipar,iAnt,iSpw)=true;
7574 : mg(ipar,iAnt,iSpw) += (wt*gn);
7575 : mg2(ipar,iAnt,iSpw)+= (wt*gn*gn);
7576 : mgn(ipar,iAnt,iSpw)++;
7577 : mgwt(ipar,iAnt,iSpw)+=wt;
7578 : }
7579 : }
7580 : }
7581 : }
7582 : }
7583 : }
7584 : }
7585 : */
7586 :
7587 : // cout << "done." << endl;
7588 :
7589 : // cout << "Normalizing mgs...";
7590 :
7591 :
7592 : // normalize mg
7593 113 : for (Int iFld=0; iFld<nFld; iFld++) {
7594 :
7595 : // cout << "iFld = " << iFld << " " << MGOK[iFld]->column(0) << endl;
7596 :
7597 : // Have data for this field?
7598 84 : if (MGOK[iFld]!=NULL) {
7599 : // References to PBs for syntactical convenience
7600 68 : Cube<Bool> mgok; mgok.reference(*(MGOK[iFld]));
7601 68 : Cube<Double> mg; mg.reference(*(MG[iFld]));
7602 68 : Cube<Double> mg2; mg2.reference(*(MG2[iFld]));
7603 68 : Cube<Double> mgwt; mgwt.reference(*(MGWT[iFld]));
7604 68 : Cube<Double> mgvar; mgvar.reference(*(MGVAR[iFld]));
7605 68 : Cube<Int> mgn; mgn.reference(*(MGN[iFld]));
7606 :
7607 254 : for (Int iSpw=0; iSpw<nSpw(); iSpw++) {
7608 2624 : for (Int iAnt=0; iAnt<nElem(); iAnt++) {
7609 7314 : for (Int ipar=0;ipar<nPar(); ++ipar) {
7610 4876 : if ( mgok(ipar,iAnt,iSpw) && mgwt(ipar,iAnt,iSpw)>0.0 ) {
7611 4159 : mg(ipar,iAnt,iSpw)/=mgwt(ipar,iAnt,iSpw);
7612 4159 : mg2(ipar,iAnt,iSpw)/=mgwt(ipar,iAnt,iSpw);
7613 : // Per-ant, per-spw variance (non-zero only if sufficient data)
7614 4159 : if (mgn(ipar,iAnt,iSpw) > 2) {
7615 2922 : mgvar(ipar,iAnt,iSpw) = (mg2(ipar,iAnt,iSpw) - pow(mg(ipar,iAnt,iSpw),2.0))/(mgn(ipar,iAnt,iSpw)-1);
7616 : }
7617 : } else {
7618 717 : mg(ipar,iAnt,iSpw)=0.0;
7619 717 : mgwt(ipar,iAnt,iSpw)=0.0;
7620 717 : mgok(ipar,iAnt,iSpw)=false;
7621 : }
7622 : }
7623 : /*
7624 : cout << " iSpw = " << iSpw << " iFld = " << iFld;
7625 : cout << " iAnt = " << iAnt;
7626 : cout << " mg = " << mg(iAnt,iSpw);
7627 : cout << " +/- " << sqrt(1.0/mgwt(iAnt,iSpw));
7628 : cout << " SNR = " << mg(iAnt,iSpw)/sqrt(1.0/mgwt(iAnt,iSpw));
7629 : cout << " " << mgn(iAnt,iSpw);
7630 : cout << endl;
7631 : */
7632 : }
7633 : }
7634 :
7635 68 : } //if-MGOK end
7636 : }
7637 :
7638 :
7639 : // cout << "done." << endl;
7640 : // cout << "nTran = " << nTran << endl;
7641 :
7642 : // cout << "Calculating scale factors...";
7643 :
7644 : // Collapse ref field mg's into a single ref
7645 29 : Cube<Double> mgref;
7646 29 : Cube<Bool> mgrefok;
7647 29 : mgref.reference(*MG[refField(0)]);
7648 29 : mgrefok.reference(*MGOK[refField(0)]);
7649 :
7650 29 : if (nRef>1) {
7651 : //Store no. of fields that is not flagged per pol,ant,and spw
7652 2 : Cube<Double> nokref(nPar(),nElem(),nSpw(),0);
7653 : // Add on additional ref fields
7654 6 : for (Int iref=1;iref<nRef;++iref) {
7655 :
7656 4 : Cube<Bool> mgokR; mgokR.reference(*MGOK[refField(iref)]);
7657 4 : Cube<Double> mgR; mgR.reference(*MG[refField(iref)]);
7658 :
7659 8 : for (Int ispw=0;ispw<nSpw();++ispw) {
7660 112 : for (Int iant=0;iant<nAnt();++iant) {
7661 324 : for (Int ipar=0;ipar<nPar();++ipar) {
7662 216 : if (iref==1) {
7663 108 : if (mgrefok(ipar,iant,ispw)) {
7664 54 : nokref(ipar,iant,ispw)+=1.0;
7665 : }
7666 : else {// the first ref field of this gain is flagged
7667 54 : mgref(ipar,iant,ispw)=0.0;
7668 : }
7669 : }
7670 :
7671 216 : if (mgokR(ipar,iant,ispw)) {
7672 211 : mgref(ipar,iant,ispw)+=mgR(ipar,iant,ispw);
7673 211 : nokref(ipar,iant,ispw)+=1.0;
7674 : }
7675 :
7676 : // at the last ref field...
7677 216 : if(iref==nRef-1 ) {
7678 108 : if (nokref(ipar,iant,ispw)==0.0) {
7679 0 : mgrefok(ipar,iant,ispw)=false;
7680 0 : mgref(ipar,iant,ispw)=0.0;
7681 : }
7682 : else {
7683 : // overwrite to turn to true for the case of mgrefok=false for refField(0)
7684 108 : mgrefok(ipar,iant,ispw)=true;
7685 : }
7686 : }
7687 :
7688 : // Replaced this with above to support flagged ref field case(CAS-4758) - TT
7689 : //if (mgrefok(ipar,iant,ispw) && mgokR(ipar,iant,ispw))
7690 : // mgref(ipar,iant,ispw)+=mgR(ipar,iant,ispw);
7691 : // else {
7692 : // mgrefok(ipar,iant,ispw)=false;
7693 : // mgref(ipar,iant,ispw)=0.0;
7694 : //}
7695 :
7696 : } // ipar
7697 : } // iant
7698 : } // ispw
7699 4 : } // iref
7700 : // Complete the average:
7701 : //mgref/=Double(nRef);
7702 2 : mgref/=nokref; // only count unflagged ones
7703 2 : } // nRef > 1
7704 :
7705 : // Scale factor calculation, per trans fld, per spw
7706 29 : Matrix<Double> fd( nSpw(), nFld, -1.0 );
7707 29 : Matrix<Double> fderr( nSpw(), nFld, -1.0 );
7708 29 : Matrix<Double> fdrms(nSpw(),nFld,-1.0);
7709 29 : Matrix<Int> numSol( nSpw(), nFld, -1 );
7710 : // fd.resize(nSpw(),nFld);
7711 : // fd.set(-1.0);
7712 : // fderr.resize( nSpw(), nFld );
7713 : // fderr.set( -1.0 );
7714 : // numSol.resize( nSpw() );
7715 : // numSol.set( -1 );
7716 :
7717 29 : Matrix<Bool> scaleOK(nSpw(),nFld,false);
7718 29 : Matrix<Double> mgratio(nSpw(),nFld,-1.0);
7719 29 : Matrix<Double> mgrms(nSpw(),nFld,-1.0);
7720 29 : Matrix<Double> mgerr(nSpw(),nFld,-1.0);
7721 :
7722 64 : for (Int iTran=0; iTran<nTran; iTran++) {
7723 :
7724 35 : Int tranidx=tranField(iTran);
7725 35 : if (MGOK[tranidx]!=NULL) {
7726 : // References to PBs for syntactical convenience
7727 35 : Cube<Bool> mgokT; mgokT.reference(*(MGOK[tranidx]));
7728 35 : Cube<Double> mgT; mgT.reference(*(MG[tranidx]));
7729 35 : Cube<Double> mgvarT; mgvarT.reference(*(MGVAR[tranidx]));
7730 35 : Cube<Double> mgwtT; mgwtT.reference(*(MGWT[tranidx]));
7731 35 : if (report_p) {
7732 0 : setupPlotter();
7733 : }
7734 35 : int countvalidspw = 0;
7735 135 : for (Int ispw=0; ispw<nSpw(); ispw++) {
7736 : // Reference spw may be different
7737 100 : Int refSpw(refSpwMap(ispw));
7738 :
7739 : // Only if anything good for this spw
7740 100 : if (ntrue(mgokT.xyPlane(ispw)) > 0) {
7741 :
7742 1323 : for (Int iant=0;iant<nAnt();++iant) {
7743 3684 : for (Int ipar=0;ipar<nPar();++ipar) {
7744 2456 : if (mgokT(ipar,iant,ispw) &&
7745 4600 : mgrefok(ipar,iant,refSpw) &&
7746 2144 : mgref(ipar,iant,refSpw)>0.0 ) {
7747 2144 : mgT(ipar,iant,ispw)/=mgref(ipar,iant,refSpw);
7748 : }
7749 : else {
7750 312 : mgT(ipar,iant,ispw)=0.0;
7751 312 : mgokT(ipar,iant,ispw)=false;
7752 : }
7753 : } // ipar
7754 : } // iant
7755 : } // ntrue>0
7756 :
7757 : // Form the mean gain ratio
7758 100 : Matrix<Double> mgTspw(mgT.xyPlane(ispw));
7759 100 : Matrix<Bool> mgokTspw(mgokT.xyPlane(ispw));
7760 100 : cout.precision(6);
7761 100 : cout.setf(ios::fixed,ios::floatfield);
7762 100 : Int nPA=ntrue(mgokTspw);
7763 100 : if (nPA>0) {
7764 :
7765 : // for plotting
7766 95 : if (report_p) {
7767 : //cerr<<"plotting for each spw..."<<endl;
7768 0 : String hlab = "Fld:"+String::toString(tranidx)+" Spw:"+String::toString(ispw)+
7769 0 : " median="+String::toString(medianGains(tranidx,ispw));
7770 0 : Vector<Double> tempvec;
7771 0 : tempvec=mgTspw(mgokTspw).getCompressedArray();
7772 : // determine nbins by Scott's rule
7773 : Double minv, maxv;
7774 0 : minMax(minv,maxv,tempvec);
7775 0 : Double binw = 3.49*stddev(tempvec)/pow(Double (tempvec.nelements()), 1./3.);
7776 0 : Int inNbins = Int (ceil ((maxv-minv)/binw));
7777 0 : plotHistogram(hlab,countvalidspw,tempvec,inNbins);
7778 0 : countvalidspw++;
7779 0 : }
7780 :
7781 : // cout << "mgTspw = " << mgTspw << endl;
7782 95 : scaleOK(ispw,tranidx)=true;
7783 : //mgratio(ispw,tranidx)=mean(mgTspw(mgokTspw));
7784 95 : mgratio(ispw,tranidx)=median(mgTspw(mgokTspw));
7785 95 : if (nPA==1) { // flux scaling based on a single gain ratio...
7786 0 : mgrms(ispw,tranidx)=0.0;
7787 0 : mgerr(ispw,tranidx)=0.0;
7788 : }
7789 : else {
7790 95 : mgrms(ispw,tranidx)=stddev(mgTspw(mgokTspw));
7791 95 : mgerr(ispw,tranidx)=mgrms(ispw,tranidx)/sqrt(Double(nPA-1));
7792 : }
7793 : // ...and flux density estimate
7794 95 : fd(ispw,tranidx)=mgratio(ispw,tranidx)*mgratio(ispw,tranidx);
7795 95 : fdrms(ispw,tranidx)=2.0*mgrms(ispw,tranidx);
7796 95 : if (nPA==1) {
7797 0 : fderr(ispw,tranidx)=0.0;
7798 : }
7799 : else {
7800 95 : fderr(ispw,tranidx)=fdrms(ispw,tranidx)/sqrt(Double(nPA-1));
7801 : }
7802 95 : numSol(ispw,tranidx) = nPA;
7803 : }
7804 :
7805 : // Compose the fit message for the list file and the log
7806 :
7807 100 : String oMsg( "" );
7808 :
7809 100 : oMsg += " Flux density for ";
7810 100 : oMsg += fldNames(tranidx);
7811 100 : oMsg += " in SpW=";
7812 100 : oMsg += String::toString<Int>( ispw );
7813 100 : if (scaleOK(ispw,tranidx)) {
7814 95 : oMsg += " (freq=";
7815 95 : oMsg += String::toString<Double>(solFreq(ispw));
7816 95 : oMsg += " Hz)";
7817 : }
7818 :
7819 100 : if ( refSpw != ispw ) {
7820 13 : oMsg += " (ref SpW=";
7821 13 : oMsg += String::toString<Int>( refSpw );
7822 13 : oMsg += ")";
7823 : }
7824 :
7825 100 : oMsg += " is: ";
7826 :
7827 100 : if ( scaleOK(ispw,tranidx) ) {
7828 95 : oMsg += String::toString<Double>( fd(ispw,tranidx) );
7829 95 : oMsg += " +/- ";
7830 95 : oMsg += String::toString<Double>( fderr(ispw,tranidx) );
7831 95 : oMsg += " (SNR = ";
7832 95 : oMsg += String::toString<Double>( fd(ispw,tranidx)/fderr(ispw,tranidx) );
7833 95 : oMsg += ", N = ";
7834 95 : oMsg += String::toString<Int>( nPA );
7835 95 : oMsg += ")";
7836 : } else {
7837 5 : oMsg += " INSUFFICIENT DATA ";
7838 : }
7839 :
7840 : // Write the fit message to the output list file if the file name is
7841 : // non-null. In the first iteration (first transfer field and spw),
7842 : // open the list file and truncate any previous version. In subsequent
7843 : // iterations, append the messages.
7844 :
7845 100 : if ( oListFile != "" ) {
7846 28 : ofstream oStream;
7847 28 : if ( iTran == 0 && ispw == 0 ) {
7848 3 : oStream.open( oListFile.chars(), ios::out|ios::trunc );
7849 : } else {
7850 25 : oStream.open( oListFile.chars(), ios::out|ios::app );
7851 : }
7852 28 : oStream << "#" << oMsg << endl << flush;
7853 28 : oStream.close();
7854 28 : }
7855 :
7856 :
7857 : // Write the fit message to the logger
7858 :
7859 100 : logSink() << oMsg << LogIO::POST;
7860 :
7861 : /*
7862 : // Report flux densities to logger
7863 : logSink() << " Flux density for " << fldNames(tranidx)
7864 : << " in SpW=" << ispw;
7865 : if (refSpw!=ispw)
7866 : logSink() << " (ref SpW=" << refSpw << ")";
7867 :
7868 : logSink() << " is: ";
7869 : if (scaleOK(ispw,tranidx)) {
7870 : logSink() << fd(ispw,tranidx)
7871 : << " +/- " << fderr(ispw,tranidx)
7872 : << " (SNR = " << fd(ispw,tranidx)/fderr(ispw,tranidx)
7873 : << ", N= " << nPA << ")";
7874 : }
7875 : else
7876 : logSink() << " INSUFFICIENT DATA ";
7877 :
7878 : logSink() << LogIO::POST;
7879 : */
7880 100 : } // ispw
7881 35 : }
7882 : } // iTran
7883 : // max 3 coefficients
7884 : //Matrix<Double> spidx(nFld,3,0.0);
7885 : //Matrix<Double> spidxerr(nFld,3,0.0);
7886 29 : Matrix<Double> spidx(nFld,fitorder+1,0.0);
7887 29 : Matrix<Double> spidxerr(nFld,fitorder+1,0.0);
7888 29 : Matrix<Double> covar;
7889 29 : Vector<Double> fitFluxD(nFld,0.0);
7890 29 : Vector<Double> fitFluxDErr(nFld,0.0);
7891 29 : Vector<Double> fitRefFreq(nFld,0.0);
7892 : //PtrBlock<Matrix<Double> *> covarList(nFld);
7893 29 : Vector<Matrix<Double> > covarList(nFld);
7894 : //Vector<Double> refFreq(nFld,0.0);
7895 :
7896 64 : for (Int iTran=0; iTran<nTran; iTran++) {
7897 35 : uInt tranidx=tranField(iTran);
7898 35 : Int nValidFlux=ntrue(scaleOK.column(tranidx));
7899 :
7900 35 : String oFitMsg;
7901 35 : logSink()<<LogIO::DEBUG1<<"nValidFLux="<<nValidFlux<<LogIO::POST;
7902 :
7903 : //if (nValidFlux>1) {
7904 35 : if (nValidFlux>0) {
7905 :
7906 : // Make fd and freq lists
7907 35 : Vector<Double> fds;
7908 35 : fds=fd.column(tranidx)(scaleOK.column(tranidx)).getCompressedArray();
7909 35 : Vector<Double> fderrs;
7910 35 : fderrs=fderr.column(tranidx)(scaleOK.column(tranidx)).getCompressedArray();
7911 35 : Vector<Double> freqs;
7912 35 : freqs=solFreq(scaleOK.column(tranidx)).getCompressedArray();
7913 :
7914 : // shift mean(log(freq)) later
7915 : // Reference frequency is first in the list
7916 : //refFreq(tranidx)=freqs[0];
7917 : //freqs/=refFreq(tranidx);
7918 : //
7919 : // calculate spectral index
7920 : // fit the per-spw fluxes to get spectral index
7921 35 : if (nValidFlux==1) {
7922 15 : fitFluxD(tranidx) = fds(0);
7923 15 : fitRefFreq(tranidx) = freqs(0);
7924 : }
7925 : else {
7926 : // single spw so no fitting is performed, just fill flux and frequency
7927 : // to fit result record
7928 20 : LinearFit<Double> fitter;
7929 20 : uInt myfitorder = 0;
7930 20 : if (fitorder < 0) {
7931 : logSink() << LogIO::WARN
7932 : << "fitorder=" << fitorder
7933 : << " not supported. Using fitorder=1"
7934 0 : << LogIO::POST;
7935 0 : myfitorder = 1;
7936 : }
7937 20 : else if (nValidFlux==2 && fitorder>1) {
7938 : // note that myfitorder does not get set in this conditional branch, is that
7939 : // the correct thing not to do? (myfitorder was prevously unitialized at this point).
7940 : logSink() << LogIO::WARN
7941 : << "Not enough number of valid flux density data for the requested fitorder:"<<fitorder
7942 0 : << ". Use fitorder=1." <<LogIO::POST;
7943 : }
7944 : else {
7945 20 : myfitorder = (uInt)fitorder;
7946 :
7947 : //if (fitorder < nValidFlux) {
7948 : // myfitorder = (uInt)fitorder;
7949 : //}
7950 : //else {
7951 : //if (fitorder > nValidFlux) {
7952 : // myfitorder = (uInt)(nValidFlux-1);
7953 : // logSink() << LogIO::WARN
7954 : // << "Not enough number of valid flux density data for the requested fitorder:"<<fitorder
7955 : // <<". Using a lower fitorder="<<myfitorder<<LogIO::POST;
7956 : }
7957 : // set fitting for spectral index, alpha and beta(curvature)
7958 : // with S = S_o*f/f0^(alpha+beta*log(f/fo))
7959 : // fitting y = c + alpha*x + beta*x^2
7960 : // log(S/S0)=alpha*log(f/f0) + beta*log(f/f0)**2
7961 20 : Polynomial< AutoDiff<Double> > bp(myfitorder);
7962 20 : fitter.setFunction(bp);
7963 :
7964 : // shift the zero point to the mean of log(freq)
7965 20 : Double meanLogFreq=mean(log10(freqs));
7966 40 : Vector<Double> log_relsolFreq=log10(freqs)-meanLogFreq;
7967 : //Vector<Double> log_relsolFreq=log10(freqs);
7968 20 : Vector<Double> log_fd=log10(fds);
7969 :
7970 : // The error in the log of fds is fderrs/fds
7971 40 : Vector<Double> soln=fitter.fit(log_relsolFreq, log_fd, fderrs/fds);
7972 20 : Vector<Double> errs=fitter.errors();
7973 20 : Matrix<Double> covar=fitter.compuCovariance();
7974 :
7975 105 : for (uInt i=0; i<soln.nelements(); i++) {
7976 85 : spidx(tranidx,i) = soln(i);
7977 85 : spidxerr(tranidx,i) = errs(i);
7978 : }
7979 20 : fitFluxD(tranidx) = pow(10.0,(soln(0)));
7980 : // correct for the proper propagation of error
7981 20 : fitFluxDErr(tranidx) = (errs(0)>0.0 ? log(10)*pow(10.0,(soln(0)))*errs(0) : 0.0);
7982 20 : fitRefFreq(tranidx) = pow(10.0,meanLogFreq);
7983 : //covarList[tranidx] = &covar;
7984 20 : covarList(tranidx) = covar;
7985 20 : oFitMsg =" Fitted spectrum for ";
7986 20 : oFitMsg += fldNames(tranidx);
7987 20 : oFitMsg += " with fitorder="+String::toString<Int>(myfitorder)+": ";
7988 : // oFitMsg += "Flux density = "+String::toString<Double>(pow(10.0,(soln(0))));
7989 20 : oFitMsg += "Flux density = "+String::toString<Double>(fitFluxD(tranidx));
7990 : // Double ferr=(errs(0)>0.0 ? exp10(errs(0)) : 0.0);
7991 : // Double ferr=(errs(0)>0.0 ? pow(10.0,(errs(0))) : 0.0);
7992 20 : oFitMsg += " +/- "+String::toString<Double>(fitFluxDErr(tranidx));
7993 : // oFitMsg += " (freq="+String::toString<Double>(refFreq(tranidx)/1.0e9)+" GHz)";
7994 : // oFitMsg += " (freq="+String::toString<Double>(pow(10.0,meanLogFreq)/1.0e9)+" GHz)";
7995 20 : oFitMsg += " (freq="+String::toString<Double>(fitRefFreq(tranidx)/1.0e9)+" GHz)";
7996 : //oFitMsg += " soln.nelements="+String::toString<Int>(soln.nelements());
7997 20 : oFitMsg += " spidx:";
7998 85 : for (uInt j=1; j<soln.nelements();j++) {
7999 65 : String coefname=" a_"+String::toString<Int>(j);
8000 65 : if (j==1) coefname += " (spectral index) ";
8001 65 : oFitMsg += coefname+"="+String::toString<Double>(soln(j));
8002 65 : oFitMsg += " +/- "+String::toString<Double>(errs(j));
8003 : //if (nValidFlux > (Int)(j+1)) {
8004 : // oFitMsg += " +/- "+String::toString<Double>(errs(j));
8005 : //}
8006 : //else {
8007 : // oFitMsg += " (degenerate)";
8008 : //}
8009 65 : }
8010 : Int sh1, sh2;
8011 20 : covar.shape(sh1,sh2);
8012 20 : if (sh1 > 1) {
8013 20 : oFitMsg += " covariance matrix for the fit: ";
8014 105 : for (Int i=0;i<sh1; i++) {
8015 1878 : for (Int j=0;j<sh2; j++) {
8016 1793 : oFitMsg += " covar("+String::toString(i)+","+String::toString(j)+")="+String::toString<Double>(covar(i,j));
8017 : }
8018 : }
8019 : }
8020 20 : if ( oListFile != "" ) {
8021 7 : ofstream oStream;
8022 7 : oStream.open( oListFile.chars(), ios::out|ios::app );
8023 7 : oStream << "#" << oFitMsg << endl << flush;
8024 7 : oStream.close();
8025 7 : }
8026 20 : logSink() << oFitMsg << LogIO::POST;
8027 20 : }
8028 35 : }// nValidFlux
8029 : /**
8030 : Int sh1, sh2;
8031 : covar->shape(sh1,sh2);
8032 :
8033 : for (Int i=0;i<sh1; i++) {
8034 : for (Int j=0;j<sh2; j++) {
8035 : logSink() << LogIO::DEBUG1
8036 : <<"covar("<<i<<","<<j<<")="<<*covar(i,j) << LogIO::POST;
8037 : }
8038 : }
8039 : **/
8040 35 : }//iTran
8041 :
8042 : //store determined quantities for returned output
8043 29 : oFluxScaleStruct.fd = fd.copy();
8044 29 : oFluxScaleStruct.fderr = fderr.copy();
8045 29 : oFluxScaleStruct.numSol = numSol.copy();
8046 29 : oFluxScaleStruct.freq = solFreq.copy();
8047 29 : oFluxScaleStruct.spidx = spidx.copy();
8048 29 : oFluxScaleStruct.spidxerr = spidxerr.copy();
8049 29 : oFluxScaleStruct.fitfd = fitFluxD.copy();
8050 29 : oFluxScaleStruct.fitfderr = fitFluxDErr.copy();
8051 29 : oFluxScaleStruct.fitreffreq = fitRefFreq.copy();
8052 : //oFluxScaleStruct.covarmat = covarList;
8053 29 : oFluxScaleStruct.covarmat = covarList.copy();
8054 : // quit if no scale factors found
8055 29 : if (ntrue(scaleOK) == 0) throw(AipsError("No scale factors determined!"));
8056 :
8057 : // cout << "done." << endl;
8058 :
8059 : // cout << "Adjusting gains...";
8060 :
8061 : // Adjust tran field's gains here
8062 :
8063 : //create incremental caltable
8064 29 : if (incremental) {
8065 : //MSSpWindowColumns spwcol(ct_->spectralWindow());
8066 : //Vector<Int> NCHAN=spwcol.numChan().getColumn();
8067 : //nChanPar()=NCHAN(0);
8068 :
8069 6 : delete ct_;
8070 : // setup and fill a record
8071 : // set record description
8072 6 : Vector<Int> spwlist(nSpw());
8073 6 : indgen(spwlist);
8074 :
8075 6 : RecordDesc fsparDesc;
8076 6 : fsparDesc.addField ("caltable", TpString);
8077 6 : fsparDesc.addField ("time", TpDouble);
8078 6 : fsparDesc.addField ("spw", TpArrayInt);
8079 6 : fsparDesc.addField ("antenna", TpArrayInt);
8080 6 : fsparDesc.addField ("pol", TpString);
8081 6 : fsparDesc.addField ("parameter", TpArrayDouble);
8082 6 : fsparDesc.addField ("paramerr", TpArrayDouble);
8083 6 : fsparDesc.addField ("caltype", TpString);
8084 :
8085 : // create record with field values
8086 6 : Record fspar(fsparDesc);
8087 6 : fspar.define("caltable",outCalTabName);
8088 : //fspar.define("time",tc(0));
8089 6 : fspar.define("spw", spwlist);
8090 6 : fspar.define("caltype", "G Cal");
8091 6 : setSpecify(fspar);
8092 : //
8093 : { // generate per chan factor taking account for spectral index
8094 : // for(Int ich=0;ich<nchan;ich++); fl = soln(0) + alpha*chanf(ich) * beta*chanf(ich)*chanf(ich)
8095 : // fact = sqrt(fl) at each ich for each spw and each field
8096 : // and store 1/fact in bcal-like table
8097 : }
8098 :
8099 : // Only do fields that occurred in the input caltable
8100 24 : for (uInt ifld=0;ifld<fldList.nelements();ifld++) {
8101 18 : Int iFld=fldList(ifld);
8102 18 : setCurrField(iFld);
8103 : //
8104 18 : initSolvePar(); // somewhat redundant but needed to reset solveCPar
8105 :
8106 : //currField()=iFld;
8107 : //refTime()=tc(0);
8108 : //currTime()=tc(0);
8109 18 : refTime()=mgreft(iFld);
8110 : // for future time support in specify
8111 18 : fspar.define("time",mgreft(iFld));
8112 :
8113 : // for only looping thru field id (set all spw for each field)
8114 18 : fspar.define("parameter", abs(1./mgratio.column(iFld)));
8115 18 : fspar.define("paramerr", 1./mgerr.column(iFld));
8116 : //
8117 18 : specify(fspar);
8118 : }
8119 : /***
8120 : Block<String> cols(3);
8121 : cols[0]="SPECTRAL_WINDOW_ID";
8122 : cols[1]="TIME";
8123 : cols[2]="FIELD_ID";
8124 : CTIter ctiter(*ct_,cols);
8125 : while (!ctiter.pastEnd()) {
8126 : Int iSpw(ctiter.thisSpw());
8127 : Int iFld(ctiter.thisField());
8128 : cerr<<"iFld last="<<iFld<<endl;
8129 : //Cube<Complex> cpar(ctiter.cparam());
8130 : Cube<Float> fpar(ctiter.fparam());
8131 : //cpar = Complex(Float(mgratio(iSpw,iFld)));
8132 : fpar = Float(mgratio(iSpw,iFld));
8133 : //ctiter.setcparam(cpar);
8134 : ctiter.setfparam(fpar);
8135 : ctiter.next();
8136 : }
8137 : storeNCT(outfile,false);
8138 : ***/
8139 6 : }
8140 : else {
8141 : // older behavior
8142 23 : Block<String> cols(3);
8143 23 : cols[0]="SPECTRAL_WINDOW_ID";
8144 23 : cols[1]="TIME";
8145 23 : cols[2]="FIELD_ID";
8146 23 : CTIter ctiter(*ct_,cols);
8147 :
8148 1364 : while (!ctiter.pastEnd()) {
8149 1341 : Int iSpw(ctiter.thisSpw());
8150 1341 : Int iFld(ctiter.thisField());
8151 :
8152 1341 : if (scaleOK(iSpw,iFld)) {
8153 701 : Cube<Complex> cpar(ctiter.cparam());
8154 701 : cpar/=Complex(Float(mgratio(iSpw,iFld)));
8155 701 : ctiter.setcparam(cpar);
8156 701 : }
8157 1341 : ctiter.next();
8158 : }
8159 23 : } // scope
8160 :
8161 : // cout << "done." << endl;
8162 :
8163 : // cout << "Cleaning up...";
8164 :
8165 : // Clean up PtrBlocks
8166 113 : for (Int iFld=0; iFld<nFld; iFld++) {
8167 84 : if (MGOK[iFld]!=NULL) {
8168 68 : delete MGOK[iFld];
8169 68 : delete MG[iFld];
8170 68 : delete MG2[iFld];
8171 68 : delete MGWT[iFld];
8172 68 : delete MGVAR[iFld];
8173 68 : delete MGN[iFld];
8174 68 : delete MGNALL[iFld];
8175 : }
8176 : }
8177 :
8178 : // cout << "done." << endl;
8179 :
8180 : // Avoid this since problem with <msname>/SELECTED_TABLE (06Feb02 gmoellen)
8181 : /*
8182 : {
8183 :
8184 : MeasurementSet ms(vs_->msName().before("/SELECTED"));
8185 : Table historytab = Table(ms.historyTableName(),
8186 : TableLock(TableLock::UserNoReadLocking),
8187 : Table::Update);
8188 : MSHistoryHandler hist = MSHistoryHandler(ms, "calibrater");
8189 : historytab.lock(true);
8190 : oss.postLocally();
8191 : hist.addMessage(oss);
8192 : historytab.unlock();
8193 : }
8194 : */
8195 29 : }
8196 0 : catch (AipsError x) {
8197 :
8198 : // Clean up PtrBlocks
8199 0 : for (Int iFld=0; iFld<nFld; iFld++) {
8200 0 : if (MGOK[iFld]!=NULL) {
8201 0 : delete MGOK[iFld];
8202 0 : delete MG[iFld];
8203 0 : delete MG2[iFld];
8204 0 : delete MGWT[iFld];
8205 0 : delete MGVAR[iFld];
8206 0 : delete MGN[iFld];
8207 0 : delete MGNALL[iFld];
8208 : }
8209 : }
8210 :
8211 0 : throw(x);
8212 :
8213 0 : }
8214 :
8215 58 : return;
8216 :
8217 29 : }
8218 :
8219 0 : void SolvableVisJones::setupPlotter() {
8220 0 : }
8221 :
8222 0 : void SolvableVisJones::plotHistogram(const String& title,
8223 : const Int index,
8224 : const Vector<Double>& data,
8225 : const Int nbins) {
8226 : // construct histogram in multiple panels
8227 0 : std::string legendloc = "bottom";
8228 0 : std::string zoomloc = "";
8229 0 : if (index==0) {
8230 0 : std::vector<std::string> loc;
8231 0 : loc.push_back("top");
8232 : //plotter_->loaddock( dock_xml_p, "bottom", loc, panels_id_[0].getInt());
8233 0 : }
8234 : else {
8235 :
8236 : // multirow panels
8237 : /***
8238 : if (index<3) {
8239 : //cerr<<"panels_id[index-1].getInt()="<<panels_id_[index-1].getInt()<<endl;
8240 : panels_id_[index] = plotter_->panel( title, "ratio", "N", "",
8241 : std::vector<int>( ), legendloc,zoomloc,panels_id_[index-1].getInt(),false,false);
8242 : }
8243 : else {
8244 : if (index==3) {
8245 : panels_id_[index] = plotter_->panel( title, "ratio", "N", "",
8246 : std::vector<int>( ), legendloc,zoomloc,panels_id_[0].getInt(),true,false);
8247 : }
8248 : else {
8249 : panels_id_[index] = plotter_->panel( title, "ratio", "N", "",
8250 : std::vector<int>( ), legendloc,zoomloc,panels_id_[index-1].getInt(),false,false);
8251 : }
8252 : }
8253 : ***/
8254 : }
8255 : // plot histogram
8256 :
8257 0 : }
8258 :
8259 0 : void SolvableVisJones::listCal(const Vector<Int> ufldids,
8260 : const Vector<Int> uantids,
8261 : const Matrix<Int> uchanids,
8262 : const String& listfile,
8263 : const Int& maxScrRows) {
8264 :
8265 : // cout << "listcal disabled for the moment." << endl;
8266 :
8267 : // return;
8268 :
8269 0 : if (typeName().contains("BPOLY") ||
8270 0 : typeName().contains("GSPLINE"))
8271 0 : throw(AipsError(typeName()+" not yet supported."));
8272 :
8273 0 : char cfill = cout.fill(' '); // Set fill character for terminal output
8274 :
8275 : //Int uSpwID = uchanids(0,0);
8276 : //Int chan = uchanids(0,1);
8277 :
8278 : // The number of spws; that is, the number of rows in matrix uchanids.
8279 : // Actually, this is the number of spw/channel selections made in the
8280 : // spw selection parameter. The rows of uchanids may contain the same
8281 : // spw.
8282 0 : uInt nSpws = uchanids.nrow();
8283 :
8284 : // Prep for listing
8285 0 : Bool endOutput = false; // if true, end output immediately
8286 0 : Bool prompt = true; // if true, issue prompt
8287 0 : Int isol = 0; // total solution counter
8288 0 : Int scrRows=0; // screen row counter, reset after continue prompt
8289 :
8290 : // Redirect cout to listfile
8291 0 : ofstream file;
8292 0 : streambuf* sbuf = cout.rdbuf();
8293 0 : if(listfile!="") { // non-interactive
8294 0 : prompt = false;
8295 : // Guard against trampling existing file
8296 0 : File diskfile(listfile);
8297 0 : if (diskfile.exists()) {
8298 0 : String errmsg = "File: " + listfile +
8299 0 : " already exists; delete it or choose a different name.";
8300 0 : throw(AipsError(errmsg));
8301 0 : }
8302 : else
8303 0 : cout << "Writing output to file: " << listfile << endl;
8304 : logSink() << LogIO::NORMAL2 << "Redirecting output to "
8305 0 : << diskfile.path().originalName().data() << LogIO::POST;
8306 0 : file.open(diskfile.path().originalName().data());
8307 0 : cout.rdbuf(file.rdbuf());
8308 0 : } else {
8309 : logSink() << LogIO::DEBUG1
8310 : << "Not redirecting output: cout remains untouched."
8311 0 : << LogIO::POST;
8312 : }
8313 :
8314 0 : Vector<String> antname;
8315 0 : msmc().antennaNames(antname);
8316 0 : Vector<String> fldname;
8317 0 : msmc().fieldNames(fldname);
8318 :
8319 : // Default header info.
8320 0 : logSink() << LogIO::NORMAL1 << "MS name = " << msName() << LogIO::POST;
8321 :
8322 : logSink() << LogIO::DEBUG1 << "Number of spectral window selections (may not be unique) = "
8323 0 : << nSpws << LogIO::POST;
8324 : logSink() << LogIO::DEBUG1 << "Number of (unique) spws in cal table = "
8325 0 : << ct_->spectralWindow().nrow() << LogIO::POST;
8326 :
8327 :
8328 :
8329 : // Get nchan from the subtable
8330 0 : MSSpWindowColumns spwcol(ct_->spectralWindow());
8331 0 : Vector<Int> NCHAN=spwcol.numChan().getColumn();
8332 :
8333 0 : Int NANT=ct_->antenna().nrow();
8334 :
8335 :
8336 0 : Block<String> cols(1);
8337 0 : cols[0]="SPECTRAL_WINDOW_ID";
8338 0 : ROCTIter ctiter(*ct_,cols);
8339 :
8340 :
8341 0 : while (!ctiter.pastEnd()) {
8342 :
8343 0 : Int spwID=ctiter.thisSpw();
8344 0 : if (anyEQ(uchanids.column(0),spwID)) {
8345 : // spwID among selected spws
8346 0 : uInt iUchanids=0;
8347 0 : while (uchanids(iUchanids,0)!=spwID) ++iUchanids;
8348 0 : Vector<Int> RowUchanids = uchanids.row(iUchanids);
8349 :
8350 0 : if (ctiter.nrow()<1) {
8351 : // shouldn't happen
8352 0 : String errMsg;
8353 : errMsg = "Nothing to list for selected SpwID: "
8354 0 : + errMsg.toString(spwID);
8355 0 : logSink() << LogIO::NORMAL1 << errMsg << LogIO::POST;
8356 0 : } else { // we have something to list
8357 :
8358 : // Handle channel selection here.
8359 0 : const uInt nchan= NCHAN(spwID);
8360 : logSink() << LogIO::DEBUG1 << "For Spw ID " << spwID
8361 : << ": Number of spectral channels in calibration table = "
8362 0 : << nchan << LogIO::POST;
8363 :
8364 : // Extract channel selection info from uchanids
8365 0 : Int stepChan = RowUchanids(3);
8366 0 : if (stepChan == 0) { stepChan = 1; } // one channel at a time (default)
8367 0 : else if (stepChan < 0) {
8368 0 : throw(AipsError("Stepping backwards through channels not supported."));
8369 : }
8370 : // Cal table channels are a subset of the MS channels.
8371 : // MS indices of channels in cal table.
8372 0 : const uInt msCalStartChan = 0;
8373 0 : const uInt msCalStopChan = nchan-1;
8374 : // MS indices of selected channels
8375 0 : uInt msSelStartChan = RowUchanids(1);
8376 0 : uInt msSelStopChan = RowUchanids(2);
8377 : // Cal table indices of selected channels
8378 0 : Int startChan = msSelStartChan - msCalStartChan;
8379 0 : Int stopChan = msSelStopChan - msCalStartChan;
8380 0 : if (startChan > stopChan) {
8381 0 : throw(AipsError("Start channel must be less than or equal to stop channel."));
8382 0 : } else if ((stopChan < 0) || (startChan > (Int)nchan - 1)) {
8383 : // All selected channels out of range
8384 0 : String errMsg = "None of the selected channels are present in cal table.";
8385 : logSink() << LogIO::SEVERE << errMsg
8386 : << endl << "Selected channel range = ["
8387 : << msSelStartChan << "," << msSelStopChan << "]" << endl
8388 : << "Cal table channel range = ["
8389 0 : << msCalStartChan << "," << msCalStopChan << "]" << LogIO::POST;
8390 0 : throw(AipsError(errMsg));
8391 0 : }
8392 0 : if (startChan < 0) {
8393 : logSink() << LogIO::NORMAL1 << "Start channel ( " << msSelStartChan
8394 : << " ) below allowed range." << endl
8395 : << "Increasing start channel to " << msCalStartChan
8396 0 : << LogIO::POST;
8397 0 : startChan = 0;
8398 : }
8399 0 : if (stopChan > (Int)nchan - 1) {
8400 : logSink() << LogIO::NORMAL1 << "Stop channel ( " << msSelStopChan
8401 : << " ) above allowed range." << endl
8402 : << "Decreasing stop channel to " << msCalStopChan
8403 0 : << LogIO::POST;
8404 0 : stopChan = (Int)nchan - 1;
8405 : }
8406 : // Number of channels selected
8407 0 : Int numChans = ((stopChan - startChan) / stepChan) + 1;
8408 0 : if (numChans > Int(nchan)) {
8409 : logSink() << LogIO::NORMAL1
8410 : << "More channels requested than are present in the cal table."
8411 : << endl << "Cal table channels for this spw: "
8412 : << msCalStartChan << " to " << msCalStopChan
8413 0 : << LogIO::POST;
8414 : }
8415 :
8416 : logSink() << LogIO::DEBUG1 << "For spwID " << spwID << endl
8417 : << " startChan = " << startChan << endl
8418 : << " stopChan = " << stopChan << endl
8419 : << " stepChan = " << stepChan << endl
8420 : << " Number of channels to list: numChans = " << numChans
8421 0 : << LogIO::POST;
8422 :
8423 : // Setup the column widths. Check width of each string.
8424 : uInt precAmp, precPhase; // Column precision
8425 : uInt oAmp, oPhase; // Column order
8426 :
8427 0 : wTime_p = 10; // set width of time column
8428 : // set the field column width (looking at the whole cal table)
8429 0 : wField_p = 0;
8430 :
8431 0 : Vector<Int> fldids;
8432 0 : fldids=ctiter.field();
8433 0 : Int nUniqFlds=genSort(fldids,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
8434 0 : fldids.resize(nUniqFlds,true); // shrink the Vector
8435 :
8436 0 : for (Int ifld=0;ifld<nUniqFlds;++ifld) {
8437 0 : String fldstr=(fldname(ifld));
8438 0 : uInt fldstrLength = fldstr.length();
8439 0 : if (wField_p < fldstrLength) { wField_p = fldstrLength; }
8440 0 : }
8441 :
8442 0 : wChan_p = (uInt)max(3,(Int)rint(log10(nchan)+0.5));
8443 0 : wPreAnt_p = wTime_p + 1 + wField_p + 1 + wChan_p; // do not count final pipe ("|")
8444 : logSink() << LogIO::DEBUG1 << "Column widths:" << endl
8445 : << " time = " << wTime_p << endl
8446 : << " field = " << wField_p << endl
8447 0 : << " channel = " << wChan_p << LogIO::POST;
8448 :
8449 : // For multiple channels, I think I will need to write a method that
8450 : // looks through all spws to determine the necessary order for the
8451 : // Amplitude and Phase.
8452 :
8453 0 : if (ct_->isComplex()) {
8454 0 : oAmp = 1;
8455 0 : precAmp = 3;
8456 0 : oPhase = 4;
8457 0 : precPhase = 1;
8458 : }
8459 : else {
8460 : // only "amp" column matters (and may have -ve sign)
8461 0 : oAmp = 4;
8462 0 : precAmp = 5;
8463 0 : oPhase = 0;
8464 0 : precPhase = 0;
8465 : }
8466 :
8467 : // set width of amplitude column
8468 0 : wAmp_p = oAmp + precAmp + 1; // order + precision + decimal point
8469 :
8470 : // set width of phase column
8471 0 : wPhase_p = oPhase + precPhase + 1; // order + precision + decimal point
8472 :
8473 0 : wFlag_p=1;
8474 0 : wPol_p = wAmp_p + 1 + wPhase_p + 1 + wFlag_p + 1;
8475 0 : wAntCol_p = wPol_p*nPar();
8476 : //cerr << "wAntCol_p = " <<wAntCol_p << endl;
8477 :
8478 : logSink() << LogIO::DEBUG1 << "oAmp = " << oAmp
8479 : << ", precAmp = " << precAmp
8480 : << ", wAmp_p = " << wAmp_p << endl
8481 : << "oPhase = " << oPhase
8482 : << ", precPhase = " << precPhase
8483 : << ", wPhase_p = " << wPhase_p
8484 0 : << LogIO::POST;
8485 :
8486 : //uInt numAntCols = 4; // Number of antenna columns
8487 0 : uInt numAntCols = 8/nPar(); // Number of antenna columns
8488 0 : wTotal_p = wPreAnt_p + 1 + wAntCol_p*numAntCols;
8489 :
8490 : //cerr << "wTotal_p = " << wTotal_p << endl;
8491 :
8492 : // Construct the horizontal separator
8493 0 : String hSeparator=replicate('-',wTotal_p);
8494 0 : uInt colPos=0;
8495 0 : colPos+=wPreAnt_p; hSeparator[colPos]='|'; colPos++;
8496 0 : for(uInt iPol=0; iPol<numAntCols*nPar(); iPol++) {
8497 0 : colPos+=wPol_p-1;
8498 0 : hSeparator[colPos]='|';
8499 0 : colPos++;
8500 : }
8501 :
8502 : logSink() << LogIO::DEBUG1
8503 0 : << "Listing CalTable: " << calTableName()
8504 0 : << " (" << typeName() << ") "
8505 0 : << LogIO::POST;
8506 :
8507 0 : String dateTimeStr0=MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7);
8508 0 : String dateStr0=dateTimeStr0.substr(0,10);
8509 :
8510 0 : String headLine = "SpwID = " + String::toString(spwID) + ", "
8511 0 : "Date = " + dateStr0 + ", " +
8512 0 : "CalTable = " + calTableName() + " (" + typeName() + "), " +
8513 0 : "MS name = " + msName();
8514 0 : cout.setf(ios::left,ios::adjustfield);
8515 : // cout << setw(wTotal_p) << headLine << endl
8516 0 : cout << headLine << endl
8517 0 : << replicate('-',wTotal_p) << endl;
8518 0 : scrRows+=2;
8519 :
8520 : // labels for flagged solutions
8521 0 : Vector<String> flagstr(2);
8522 0 : flagstr(0)="F";
8523 0 : flagstr(1)=" ";
8524 :
8525 : // The following is a klugey way to
8526 : // make the times, fields, and gains look like
8527 : // what the CalTable's used to be
8528 :
8529 0 : Int NTIME=ctiter.nrow()/NANT;
8530 0 : Vector<Double> timelist;
8531 0 : timelist=ctiter.time();
8532 0 : Vector<Int> fieldlist;
8533 0 : fieldlist=ctiter.field();
8534 0 : for (Int i=1;i<NTIME;++i) {
8535 0 : timelist(i)=timelist(i*NANT);
8536 0 : fieldlist(i)=fieldlist(i*NANT);
8537 : }
8538 0 : timelist.resize(NTIME,true);
8539 0 : fieldlist.resize(NTIME,true);
8540 :
8541 0 : Array<Float> v1,v2;
8542 0 : Array<Bool> vok;
8543 0 : Int npar=nPar();
8544 0 : if (ct_->isComplex()) {
8545 0 : Cube<Complex> cparam;
8546 0 : ctiter.cparam(cparam);
8547 0 : IPosition sh(cparam.shape());
8548 0 : sh.append(IPosition(1,NTIME));
8549 0 : sh(2)=NANT;
8550 0 : Array<Complex> calGains;
8551 0 : calGains.reference(cparam.reform(sh));
8552 0 : v1.assign(amplitude(calGains));
8553 0 : v2.assign(phase(calGains)*180.0/M_PI);
8554 0 : Cube<Bool> sok;
8555 0 : sok=!ctiter.flag();
8556 0 : Array<Bool> calGainOK;
8557 0 : calGainOK.reference(sok.reform(sh));
8558 0 : vok.reference(calGainOK);
8559 0 : }
8560 : else {
8561 0 : Cube<Float> fparam;
8562 0 : Array<Float> fparam4;
8563 0 : ctiter.fparam(fparam);
8564 0 : IPosition sh(fparam.shape());
8565 0 : Cube<Bool> sok;
8566 0 : Array<Bool> sok4;
8567 0 : sok=!ctiter.flag();
8568 0 : sh.append(IPosition(1,NTIME));
8569 0 : sh(2)=NANT;
8570 0 : fparam4.reference(fparam.reform(sh));
8571 0 : sok4.reference(sok.reform(sh));
8572 :
8573 : // only one val per par
8574 0 : sh.append(IPosition(1,NTIME));
8575 0 : sh(2)=NANT;
8576 0 : v1.reference(fparam4);
8577 0 : v2.resize();
8578 0 : vok.reference(sok4);
8579 0 : }
8580 :
8581 0 : IPosition gidx(4,0,0,0,0); // 4-element IPosition, all zeros
8582 :
8583 : // Setup a Vector of antenna ID's to ease the process of printing
8584 : // multiple antenna columns per row.
8585 : uInt numAnts; // Hold number of antennas to be output.
8586 0 : Vector<Int> pAntids(NANT); // Vector of antenna ID's.
8587 0 : if (uantids.nelements()==0) { // Print all antennas.
8588 0 : numAnts = NANT;
8589 0 : for(uInt i=0; i< numAnts; i++) { // Fill pAntids with all antenna IDs.
8590 0 : pAntids[i] = i;
8591 : }
8592 : } else { // Use the user-specified antenna ID's.
8593 0 : numAnts = uantids.nelements();
8594 0 : pAntids.resize(numAnts);
8595 0 : pAntids = uantids;
8596 : }
8597 :
8598 : // loop over antenna elements
8599 0 : for (uInt iElem=0;iElem<numAnts;iElem+=numAntCols) {
8600 0 : gidx(2)=pAntids(iElem);
8601 :
8602 0 : Bool header=true; // New antenna, require print header
8603 :
8604 : // If antenna element is among selected antennas, print it
8605 0 : if (uantids.nelements()==0 || anyEQ(uantids,pAntids(iElem))) {
8606 :
8607 : // Begin loop over time
8608 0 : for (Int itime=0;itime<NTIME;++itime) {
8609 0 : gidx(3)=itime;
8610 :
8611 0 : Int fldid(fieldlist(itime));
8612 :
8613 : // Get date-time string
8614 0 : String dateTimeStr=MVTime(timelist(itime)/C::day).string(MVTime::YMD,7);
8615 0 : String dateStr=dateTimeStr.substr(0,10);
8616 0 : String timeStr=dateTimeStr.substr(11,10);
8617 : // Get field string
8618 0 : String fldStr="";
8619 0 : if (fldid>-1)
8620 0 : fldStr=(fldname(fldid));
8621 :
8622 0 : String tmp_timestr = timeStr; // tmp_ variables get reset during the loop
8623 0 : String tmp_fldstr = fldStr; //
8624 :
8625 : // If no user-specified fields, or fldid is in user's list
8626 0 : if (ufldids.nelements()==0 || anyEQ(ufldids,fldid) ) {
8627 :
8628 : // Set i/o flags for writing data
8629 0 : cout << setiosflags(ios::fixed) << setiosflags(ios::right);
8630 :
8631 : // Loop over channels
8632 0 : for (uInt iChan=startChan; iChan<=uInt(stopChan); iChan+=stepChan) {
8633 :
8634 : // If beginning new screen, print the header
8635 0 : if (scrRows == 0 || header) {
8636 0 : header=false;
8637 : // Write Antenna line (put spaces over the time, field cols)
8638 0 : for(uInt k=0; k<(wPreAnt_p); k++) { cout<<" "; }
8639 0 : cout << "|";
8640 0 : for(uInt k=0; (k<numAntCols) and (iElem+k<=numAnts-1); k++) {
8641 0 : String tAntName = " Ant = " + String(antname(pAntids(iElem+k)));
8642 0 : cout.setf(ios::left,ios::adjustfield);
8643 0 : cout << setw(wAntCol_p-1) << tAntName << "|";
8644 0 : }
8645 0 : cout << endl; scrRows++;
8646 :
8647 : // Write part of header with no data
8648 0 : scrRows += writeHeader(numAntCols, numAnts, iElem);
8649 : }
8650 :
8651 :
8652 0 : gidx(1)=iChan;
8653 : // Write the Time, Field, and Channel for each row
8654 0 : cout << setw(wTime_p) << timeStr << " "
8655 0 : << setw(wField_p) << fldStr << " "
8656 0 : << setw(wChan_p) << msCalStartChan + iChan << "|";
8657 :
8658 : // Write data for each antenna column
8659 0 : for (uInt kelem=iElem; (kelem<iElem+numAntCols) and (kelem<=numAnts-1);
8660 : kelem++) {
8661 0 : gidx(2)=pAntids(kelem);
8662 : // Loop over polarization
8663 0 : for (Int ipar=0;ipar<npar;++ipar) {
8664 0 : gidx(0)=ipar;
8665 :
8666 : // WRITE THE DATA
8667 : // amplitude
8668 0 : cout << setprecision(precAmp) << setw(wAmp_p) << v1(gidx) << " ";
8669 :
8670 0 : if (v2.nelements()>0)
8671 : // phase
8672 0 : cout<< setprecision(precPhase) << setw(wPhase_p) << v2(gidx) << " ";
8673 : else
8674 0 : cout<< setprecision(precPhase) << setw(wPhase_p) << replicate(" ",wPhase_p) << " ";
8675 : // flag
8676 0 : cout << flagstr(Int(vok(gidx))) << " ";
8677 : } // end ipar loop
8678 :
8679 : } // end kelem loop
8680 :
8681 0 : cout << resetiosflags(ios::right) << endl;
8682 0 : isol=isol+numAntCols; scrRows++;
8683 :
8684 : // If at end of screen prompt user or new header
8685 0 : if (maxScrRows>0 && (scrRows >= maxScrRows-1) ) { // scrRows counts from 0
8686 0 : scrRows = 0; // signal a new page
8687 0 : if (prompt) { // query the user, if we are interactive
8688 0 : string contStr;
8689 0 : cout << "Type Q to quit, A to list all, or RETURN to continue [continue]: ";
8690 0 : getline(cin,contStr);
8691 0 : if ( (contStr.compare(0,1,"q") == 0) or
8692 0 : (contStr.compare(0,1,"Q") == 0) ) { endOutput=true; }
8693 0 : if ( (contStr.compare(0,1,"a") == 0) or
8694 0 : (contStr.compare(0,1,"A") == 0) ) { prompt = false; }
8695 0 : }
8696 : }
8697 : } // end iChan loop
8698 :
8699 : } // end if (field)
8700 :
8701 0 : if (endOutput) {break;} // break out of itime loop
8702 :
8703 0 : } // itime
8704 :
8705 : } // end if (antenna)
8706 :
8707 0 : if (endOutput) {break;} // break out of ielem loop
8708 :
8709 : } // end iElem loop
8710 :
8711 0 : if (endOutput) {break;} // break out of spw loop
8712 :
8713 0 : } // end spw if (verification) block
8714 :
8715 0 : } // end spw loop
8716 :
8717 : // advance iterator (spw)
8718 0 : ctiter.next();
8719 : } // ctiter
8720 :
8721 0 : cout << endl
8722 0 : << "Listed " << isol << " antenna solutions."
8723 0 : << endl << endl;
8724 :
8725 0 : if (listfile!="") cout.rdbuf(sbuf); // restore cout
8726 0 : cout.fill(cfill);
8727 :
8728 0 : }// end function listCal
8729 :
8730 0 : int SolvableVisJones::writeHeader(const uInt numAntCols,
8731 : const uInt numAnts,
8732 : const uInt iElem) {
8733 0 : uInt lineCount=0;
8734 : // Write time and field headings (only once)
8735 : cout << setiosflags(ios::left)
8736 0 : << setw(wTime_p) << "Time" << " "
8737 0 : << setw(wField_p) << "Field" << " "
8738 0 : << setw(wChan_p) << "Chn" << "|";
8739 :
8740 : // Write Amp and Phase headings for each antenna column
8741 0 : Int nh(2);
8742 0 : Vector<String> vh(nh);
8743 0 : vh[0]="Amp ";
8744 0 : vh[1]="Phs ";
8745 0 : if (this->typeName().contains("EVLAGAIN")) {
8746 0 : nh=8;
8747 0 : vh.resize(nh);
8748 0 : vh[0]=vh[4]="Gain";
8749 0 : vh[2]=vh[6]="Tsys";
8750 0 : vh[1]=vh[3]=vh[5]=vh[7]=" ";
8751 : }
8752 0 : else if (this->typeName()=="K Jones") {
8753 0 : vh[0]="Delay ";
8754 0 : vh[1]=" ";
8755 : }
8756 0 : else if (this->typeName().contains("Opac")) {
8757 0 : vh[0]="Opac ";
8758 0 : vh[1]=" ";
8759 : }
8760 0 : else if (this->typeName().contains("KAntPos")) {
8761 0 : nh=6;
8762 0 : vh.resize(nh);
8763 0 : vh[0]="dX m";
8764 0 : vh[2]="dY m";
8765 0 : vh[4]="dZ m";
8766 0 : vh[1]=vh[3]=vh[5]=" ";
8767 : }
8768 0 : else if (this->typeName().contains("EGainCurve")) {
8769 0 : nh=8;
8770 0 : vh.resize(nh);
8771 0 : vh[0]="c[0]";
8772 0 : vh[2]="c[1]";
8773 0 : vh[4]="c[2]";
8774 0 : vh[6]="c[3]";
8775 0 : vh[1]=vh[3]=vh[5]=vh[7]=" ";
8776 : }
8777 0 : else if (this->typeName().contains("TSYS")) {
8778 0 : vh[0]="Tsys";
8779 0 : vh[1]=" ";
8780 : }
8781 :
8782 0 : cout.setf(ios::right, ios::adjustfield);
8783 0 : for(uInt k=0; (k<numAntCols) and (iElem+k<=numAnts-1); k++) {
8784 0 : for (Int ip=0;ip<nPar();++ip) {
8785 0 : if (ip>0) cout << " ";
8786 0 : cout << setw(wAmp_p) << vh[(2*ip)%nh] << " "
8787 0 : << setw(wPhase_p) << vh[(2*ip+1)%nh] << " "
8788 0 : << "F";
8789 : }
8790 0 : cout << "|";
8791 : }
8792 0 : cout << endl; lineCount++;
8793 : // Construct the horizontal separator
8794 0 : String hSeparator=replicate('-',wTotal_p);
8795 0 : uInt colPos=0;
8796 0 : colPos+=wTime_p; hSeparator[colPos]='|'; colPos++;
8797 0 : colPos+=wField_p; hSeparator[colPos]='|'; colPos++;
8798 0 : colPos+=wChan_p; hSeparator[colPos]='|'; colPos++;
8799 0 : for(uInt iPol=0; iPol<numAntCols*nPar(); iPol++) {
8800 0 : colPos+=wPol_p-1;
8801 0 : hSeparator[colPos]='|';
8802 0 : colPos++;
8803 : }
8804 : // Write horizontal separator
8805 0 : cout << hSeparator << endl; lineCount++;
8806 0 : return lineCount;
8807 0 : } // end writeHeader
8808 :
8809 : // Globals
8810 :
8811 : // Return a cal table's type, verifying its existence
8812 44 : String calTableType(const String& tablename) {
8813 :
8814 : // Check existence...
8815 44 : if (!Table::isReadable(tablename)) {
8816 0 : ostringstream o;
8817 0 : o << "Table " << tablename
8818 0 : << " does not exist.";
8819 0 : throw(AipsError(String(o)));
8820 0 : }
8821 :
8822 : // Table exists...
8823 :
8824 44 : TableInfo ti(TableUtil::tableInfo(tablename));
8825 :
8826 : // ...Check if Calibration table....
8827 44 : if (ti.type()!="Calibration") {
8828 0 : ostringstream o;
8829 0 : o << "Table " << tablename
8830 : << " is not a valid Calibration table."
8831 0 : << " (expected type = \"Calibration\"; type found = \""
8832 0 : << ti.type() << "\")";
8833 0 : throw(AipsError(String(o)));
8834 :
8835 0 : }
8836 :
8837 : // If we get here, we have a calibration table,
8838 : // so return its type
8839 88 : return ti.subType();
8840 :
8841 44 : }
8842 :
8843 :
8844 : } //# NAMESPACE CASA - END
|