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: aips2-request@nrao.edu.
21 : //# Postal address: AIPS++ Project Office
22 : //# National Radio Astronomy Observatory
23 : //# 520 Edgemont Road
24 : //# Charlottesville, VA 22903-2475 USA
25 : //#
26 : //# $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 0 : SolNorm::SolNorm(Bool donorm, String type) :
80 : donorm_(donorm),
81 0 : normtype_(normTypeFromString(type))
82 : {
83 : // report();
84 0 : }
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 0 : SolNorm::Type SolNorm::normTypeFromString(String type) {
113 :
114 0 : String uptype=upcase(type);
115 0 : 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 : }
123 :
124 :
125 :
126 :
127 :
128 : // **********************************************************
129 : // FreqMetaData Implementations
130 : //
131 :
132 0 : FreqMetaData::FreqMetaData() :
133 : ok_(False), // ok requires running calcFreqMeta later
134 : validspws_(),
135 : freq_(Vector< Vector<Double> >()),
136 : width_(Vector< Vector<Double> >()),
137 : effBW_(Vector< Vector<Double> >()),
138 0 : spwfanin_()
139 0 : {}
140 :
141 :
142 0 : 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 0 : uInt nspw(msfreq.nelements());
150 :
151 : // We will keep track of which spws get set
152 0 : Vector<Bool> validspw(nspw,false);
153 :
154 : // Size up the Vector of spw freq Vectors
155 0 : freq_.resize(nspw);
156 0 : width_.resize(nspw);
157 0 : effBW_.resize(nspw);
158 :
159 : // We will log some pertinent info
160 0 : LogIO log;
161 0 : log << LogOrigin("FreqMetaData","calcFreqMeta") << LogIO::NORMAL << "Derived frequency meta-info for solutions:" << LogIO::POST;
162 :
163 : // Gather MS freq info
164 0 : for (uInt i=0;i<selspw.nelements();++i) {
165 0 : uInt ispw=selspw(i);
166 0 : 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 0 : if (nchan<1)
171 0 : throw(AipsError("No frequency information for a selected spw!"));
172 :
173 :
174 : // Set nominal per-spw solution frequencies
175 0 : 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 0 : Double freq0=msfreq(ispw)(0); // Lop off large freq value
188 0 : Double width1=mswidth(ispw)(0); // Divide widths by typical value (also ensures abs)
189 0 : Vector<Double> f=msfreq(ispw)-freq0; // relative freq
190 0 : Vector<Double> w=mswidth(ispw)/width1; // width-weights
191 :
192 : // output info will be single-channel
193 0 : freq_(ispw).resize(1);
194 0 : width_(ispw).resize(1);
195 :
196 : // calculate
197 0 : freq_(ispw).set(sum( (Array<Double>) f*w)); // weighed rel freq sum
198 0 : width_(ispw).set(sum(w)); // sum of norm'd width weights
199 0 : freq_(ispw)/=width_(ispw); // divide by weight sum
200 :
201 : // Restore offsets to final values
202 0 : freq_(ispw)+=freq0; // add offset back in
203 0 : width_(ispw)*=width1; // mult by width norm
204 :
205 : } 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 0 : ostringstream os;
218 0 : os.precision(15);
219 0 : os << " Selected spw=" << ispw << " (nchan=" << freq_(ispw).nelements() << ") has centroid freq = " << mean(freq_(ispw));
220 0 : log << LogIO::NORMAL << os << LogIO::POST;
221 : //log << LogOrigin("FreqMetaData","calcFreqMeta") << LogIO::NORMAL << os << LogIO::POST;
222 : }
223 :
224 :
225 : // Assume effective BW is just the width
226 0 : effBW_(ispw).reference(width_(ispw));
227 :
228 : // Remember we set this spw
229 0 : validspw(ispw)=true;
230 :
231 : }
232 :
233 : // Collapse over spws if combining them...
234 0 : if (combspw && spwfanin.nelements()>1) {
235 :
236 : // cout << "Combining spws!" << endl;
237 :
238 : // Remember the fan-in vector
239 0 : spwfanin_.resize();
240 0 : spwfanin_.assign(spwfanin);
241 :
242 :
243 : // Keep track of which spws are aggregate spws
244 : // (none are yet)
245 0 : Vector<Bool> isAggspw(nspw,false);
246 :
247 : // Keep track of fanned-in spws per agg spw
248 0 : Vector< Vector<Int> > fannedin(nspw,Vector<Int>(0));
249 :
250 :
251 0 : Vector<Double> freq0(nspw,0);
252 0 : Vector<Double> width1(nspw,0);
253 :
254 0 : for (uInt ispw=0;ispw<spwfanin.nelements();++ispw) {
255 :
256 : // Step over unmapped spws...
257 0 : if (spwfanin(ispw)<0)
258 0 : continue;
259 :
260 : // The following assumes fan-in is always to lowest spw id in group
261 0 : if (Int(ispw)==spwfanin(ispw)) {
262 :
263 : //cout << "Aggregate spw = " << ispw << endl;
264 :
265 0 : isAggspw(ispw)=true;
266 :
267 : // Just to be sure...
268 0 : validspw(ispw)=true;
269 :
270 : // Add this (agg) spw to fanned in list
271 0 : uInt nfanin=fannedin(ispw).nelements();
272 0 : fannedin(ispw).resize(nfanin+1,true); // copies elements
273 0 : fannedin(ispw)(nfanin)=ispw;
274 :
275 : // This is a spw in which we'll accumulate
276 :
277 : // Offsets for precision
278 0 : freq0(ispw)=freq_(ispw)(0);
279 0 : width1(ispw)=width_(ispw)(0);
280 :
281 0 : freq_(ispw)-=freq0(ispw);
282 0 : width_(ispw)/=width1(ispw);
283 :
284 : // begin to accumulate effBW
285 0 : effBW_(ispw).resize(); // break prior reference to width_
286 0 : effBW_(ispw).assign(width_(ispw)); // copy in this spw's width_
287 :
288 : // weight the freqs with widths
289 0 : 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 0 : width_(ispw)*=width_(ispw);
294 :
295 : }
296 : else {
297 0 : uInt aggspw(spwfanin(ispw));
298 :
299 0 : uInt nfanin=fannedin(aggspw).nelements();
300 0 : fannedin(aggspw).resize(nfanin+1,true); // copies elements
301 0 : fannedin(aggspw)(nfanin)=ispw;
302 :
303 0 : 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 0 : 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 0 : Vector<Double> f(freq_(ispw)-freq0(aggspw));
318 0 : Vector<Double> w(width_(ispw)/width1(aggspw));
319 :
320 : // accumulate
321 0 : freq_(aggspw)+= ( (Array<Double>) f*w);
322 0 : width_(aggspw)+= ( (Array<Double>) w*w);
323 0 : effBW_(aggspw)+= w;
324 :
325 : // This acculated spw now refers to aggspw:
326 0 : freq_(ispw).reference(freq_(aggspw));
327 0 : width_(ispw).reference(width_(aggspw));
328 0 : effBW_(ispw).reference(effBW_(aggspw));
329 :
330 : // This spw no longer autonomously "valid"
331 : // (aggspw is the relevant valid one)
332 0 : validspw(ispw)=false;
333 :
334 : }
335 : }
336 :
337 : // Finish weighted mean calculation
338 0 : for (uInt ispw=0;ispw<spwfanin.nelements();++ispw) {
339 :
340 : // Step over non-agg spws
341 0 : if (!isAggspw(ispw))
342 0 : continue;
343 :
344 : // cout << "Finalizing freq averages for agg spw = " << ispw << endl;
345 :
346 0 : if (freq0(ispw)>0.0 && effBW_(ispw).nelements()>0 && allGT(effBW_(ispw),0.0)) {
347 0 : freq_(ispw)/=effBW_(ispw);
348 0 : width_(ispw)/=effBW_(ispw);
349 :
350 : // put offsets back in
351 0 : freq_(ispw)+=freq0(ispw);
352 0 : width_(ispw)*=width1(ispw);
353 0 : effBW_(ispw)*=width1(ispw);
354 :
355 : {
356 : // Report fanin details....
357 0 : ostringstream os;
358 0 : os.precision(15);
359 0 : os << " Combining spws=" << fannedin(ispw) << " into (aggregate) spw=" << ispw << " (nchan=" << freq_(ispw).nelements() << ") at centroid freq = " << mean(freq_(ispw));
360 0 : log << LogIO::NORMAL << os << LogIO::POST;
361 : //log << LogOrigin("FreqMetaData","calcFreqMeta") << LogIO::NORMAL << os << LogIO::POST;
362 : }
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 : } // combspw?
372 : else {
373 :
374 : // For safety, make spwfanin the identity vector
375 0 : spwfanin_.resize(nspw);
376 0 : indgen(spwfanin_);
377 :
378 : }
379 :
380 : // Fill validspws_ vector
381 0 : Vector<Int> spwlist(nspw);
382 0 : indgen(spwlist);
383 0 : validspws_.assign(spwlist(validspw).getCompressedArray());
384 :
385 : // If we get here, we should be ok!
386 0 : ok_=true;
387 :
388 0 : }
389 :
390 :
391 0 : Bool FreqMetaData::ok() const {
392 0 : if (ok_)
393 0 : return true;
394 : else
395 0 : throw(AipsError("FreqMetaData not initialized!"));
396 : return false;
397 :
398 : }
399 :
400 0 : const Vector<Int>& FreqMetaData::validSpws() const {
401 :
402 0 : if (ok() && validspws_.nelements()>0)
403 0 : return validspws_;
404 : else
405 0 : throw(AipsError("No valid spws in FreqMetaData!"));
406 :
407 : }
408 :
409 :
410 0 : const Vector<Double>& FreqMetaData::freq(Int spw) const {
411 0 : if (ok() && freq_(spw).nelements()>0)
412 0 : return freq_(spw);
413 : else
414 0 : throw(AipsError("Bad spw in FreqMetaData!"));
415 :
416 : }
417 0 : const Vector<Double>& FreqMetaData::width(Int spw) const {
418 0 : if (ok() && width_(spw).nelements()>0)
419 0 : return width_(spw);
420 : else
421 0 : throw(AipsError("Bad spw in FreqMetaData!"));
422 :
423 : }
424 0 : const Vector<Double>& FreqMetaData::effBW(Int spw) const {
425 0 : if (ok() && effBW_(spw).nelements()>0)
426 0 : return effBW_(spw);
427 : else
428 0 : throw(AipsError("Bad spw in FreqMetaData!"));
429 :
430 : }
431 :
432 0 : Int FreqMetaData::fannedInSpw(Int spw) const {
433 :
434 0 : if (ok() && Int(spwfanin_.nelements())>spw && spwfanin_(spw)>-1)
435 0 : 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 : corruptor_p(NULL),
449 : ct_(NULL),
450 : ci_(NULL),
451 : cpp_(NULL),
452 0 : spwOK_(vs.numberSpw(),false),
453 : maxTimePerSolution_p(0),
454 : minTimePerSolution_p(10000000),
455 : avgTimePerSolution_p(0),
456 : timer_p(),
457 : freqMetaData_(),
458 : calTableName_(""),
459 : calTableSelect_(""),
460 : append_(false),
461 : tInterpType_(""),
462 : fInterpType_(""),
463 : spwMap_(1,-1),
464 : refantmode_("flex"),
465 : urefantlist_(1,-1),
466 : minblperant_(4),
467 : solved_(false),
468 : byCallib_(false),
469 : apmode_(""),
470 : solmode_(""),
471 : rmsthresh_(0),
472 : usolint_("inf"),
473 : solint_("inf"),
474 : solTimeInterval_(DBL_MAX),
475 : fsolint_("none"),
476 : fintervalHz_(-1.0),
477 0 : fintervalCh_(vs.numberSpw(),0.0),
478 0 : chanAveBounds_(vs.numberSpw(),Matrix<Int>()),
479 : solnorm_(false,"mean"),
480 : minSNR_(0.0f),
481 : combine_(""),
482 : corrcomb_("none"),
483 : focusChan_(0),
484 : dataInterval_(0.0),
485 : fitWt_(0.0),
486 : fit_(0.0),
487 : antennaMap_(),
488 : 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 : srcPolPar_(),
500 : chanmask_(NULL),
501 : simulated_(false),
502 : 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 : corruptor_p(NULL),
524 : ct_(NULL),
525 : ci_(NULL),
526 : cpp_(NULL),
527 : spwOK_(MSnSpw,false),
528 : maxTimePerSolution_p(0),
529 : minTimePerSolution_p(10000000),
530 : avgTimePerSolution_p(0),
531 : timer_p(),
532 : calTableName_(""),
533 : calTableSelect_(""),
534 : append_(false),
535 : tInterpType_(""),
536 : fInterpType_(""),
537 : spwMap_(1,-1),
538 : refantmode_("flex"),
539 : urefantlist_(1,-1),
540 : minblperant_(4),
541 : solved_(false),
542 : byCallib_(false),
543 : apmode_(""),
544 : solmode_(""),
545 : rmsthresh_(0),
546 : usolint_("inf"),
547 : solint_("inf"),
548 : solTimeInterval_(DBL_MAX),
549 : fsolint_("none"),
550 : fintervalHz_(-1.0),
551 : fintervalCh_(MSnSpw,0.0),
552 0 : chanAveBounds_(MSnSpw,Matrix<Int>()),
553 : solnorm_(false,"mean"),
554 : minSNR_(0.0f),
555 : combine_(""),
556 : focusChan_(0),
557 : dataInterval_(0.0),
558 : fitWt_(0.0),
559 : fit_(0.0),
560 : solveCPar_(MSnSpw,NULL), // TBD: move inflation into ctor body
561 : solveRPar_(MSnSpw,NULL),
562 : solveParOK_(MSnSpw,NULL),
563 : solveParErr_(MSnSpw,NULL),
564 : solveParSNR_(MSnSpw,NULL),
565 : solveAllCPar_(MSnSpw,NULL),
566 : solveAllRPar_(MSnSpw,NULL),
567 : solveAllParOK_(MSnSpw,NULL),
568 : solveAllParErr_(MSnSpw,NULL),
569 : solveAllParSNR_(MSnSpw,NULL),
570 : srcPolPar_(),
571 : chanmask_(NULL),
572 : simulated_(false),
573 : 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 0 : SolvableVisCal::SolvableVisCal(const MSMetaInfoForCal& msmc) :
595 : VisCal(msmc),
596 : corruptor_p(NULL),
597 : ct_(NULL),
598 : ci_(NULL),
599 : cpp_(NULL),
600 0 : spwOK_(nSpw(),False),
601 : maxTimePerSolution_p(0),
602 : minTimePerSolution_p(10000000),
603 : avgTimePerSolution_p(0),
604 : timer_p(),
605 : calTableName_(""),
606 : calTableSelect_(""),
607 : append_(False),
608 : tInterpType_(""),
609 : fInterpType_(""),
610 : spwMap_(1,-1),
611 : refantmode_("flex"),
612 : urefantlist_(1,-1),
613 : minblperant_(4),
614 : solved_(False),
615 : byCallib_(False),
616 : apmode_(""),
617 : solmode_(""),
618 : rmsthresh_(0),
619 : usolint_("inf"),
620 : solint_("inf"),
621 : solTimeInterval_(DBL_MAX),
622 : fsolint_("none"),
623 : fintervalHz_(-1.0),
624 0 : fintervalCh_(nSpw(),0.0),
625 0 : chanAveBounds_(nSpw(),Matrix<Int>()),
626 : solnorm_(false,"mean"),
627 : minSNR_(0.0f),
628 : combine_(""),
629 : focusChan_(0),
630 : dataInterval_(0.0),
631 : fitWt_(0.0),
632 : fit_(0.0),
633 0 : solveCPar_(nSpw(),NULL), // TBD: move inflation into ctor body
634 0 : solveRPar_(nSpw(),NULL),
635 0 : solveParOK_(nSpw(),NULL),
636 0 : solveParErr_(nSpw(),NULL),
637 0 : solveParSNR_(nSpw(),NULL),
638 0 : solveAllCPar_(nSpw(),NULL),
639 0 : solveAllRPar_(nSpw(),NULL),
640 0 : solveAllParOK_(nSpw(),NULL),
641 0 : solveAllParErr_(nSpw(),NULL),
642 0 : solveAllParSNR_(nSpw(),NULL),
643 : srcPolPar_(),
644 : chanmask_(NULL),
645 : simulated_(False),
646 : simint_("integration"),
647 0 : onthefly_(False)
648 : {
649 0 : if (prtlev()>2) cout << "SVC::SVC(msmc)" << endl;
650 :
651 0 : caiRC_p = Aipsrc::registerRC("calibrater.activity.interval", "3600.0");
652 0 : cafRC_p = Aipsrc::registerRC("calibrater.activity.fraction", "0.00001");
653 0 : String ca_str = Aipsrc::get(caiRC_p);
654 0 : std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityInterval_p);
655 0 : userPrintActivityInterval_p = abs(userPrintActivityInterval_p);
656 :
657 0 : ca_str = Aipsrc::get(cafRC_p);
658 0 : std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityFraction_p);
659 0 : userPrintActivityFraction_p = abs(userPrintActivityFraction_p);
660 :
661 0 : initSVC();
662 :
663 0 : };
664 :
665 :
666 :
667 0 : SolvableVisCal::SolvableVisCal(const Int& nAnt) :
668 : VisCal(nAnt),
669 : corruptor_p(NULL),
670 : maxTimePerSolution_p(0),
671 : minTimePerSolution_p(10000000),
672 : avgTimePerSolution_p(0),
673 : timer_p(),
674 : calTableName_(""),
675 : calTableSelect_(""),
676 : append_(false),
677 : tInterpType_(""),
678 : fInterpType_(""),
679 : spwMap_(1,-1),
680 : refantmode_("flex"),
681 : urefantlist_(1,-1),
682 : minblperant_(4),
683 : solved_(false),
684 : apmode_(""),
685 : solmode_(""),
686 : rmsthresh_(0),
687 : usolint_("inf"),
688 : solint_("inf"),
689 : solTimeInterval_(DBL_MAX),
690 : fsolint_("none"),
691 : solnorm_(false,"mean"),
692 : minSNR_(0.0),
693 : combine_(""),
694 : focusChan_(0),
695 : dataInterval_(0.0),
696 : fitWt_(0.0),
697 : fit_(0.0),
698 : solveCPar_(1,NULL),
699 : solveRPar_(1,NULL),
700 : solveParOK_(1,NULL),
701 : solveParErr_(1,NULL),
702 : solveParSNR_(1,NULL),
703 : srcPolPar_(),
704 : chanmask_(NULL),
705 : simulated_(false),
706 : 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 0 : SolvableVisCal::~SolvableVisCal() {
726 :
727 0 : 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 0 : if (corruptor_p) delete corruptor_p;
732 :
733 0 : deleteSVC();
734 :
735 0 : if (ci_) delete ci_; ci_=NULL;
736 0 : if (cpp_) delete cpp_; cpp_=NULL;
737 0 : if (ct_) delete ct_; ct_=NULL;
738 :
739 0 : }
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 0 : void SolvableVisCal::setApply(const Record& apply) {
764 : // Inputs:
765 : // apply Record& Contains application params
766 : //
767 :
768 0 : if (prtlev()>2)
769 0 : cout << "SVC::setApply(apply)" << endl;
770 :
771 : // Call VisCal version for generic stuff
772 0 : VisCal::setApply(apply);
773 :
774 : // Collect Cal table parameters
775 0 : if (apply.isDefined("table")) {
776 0 : calTableName()=apply.asString("table");
777 : // Verify that CalTable is of correct type
778 0 : verifyCalTable(calTableName());
779 : }
780 :
781 : // Collect interpolation parameters
782 0 : if (apply.isDefined("interp")) {
783 0 : String interp=apply.asString("interp");
784 0 : if (interp.contains(',')) {
785 0 : tInterpType()=String(interp.before(','));
786 0 : fInterpType() = interp.after(',');
787 : }
788 : else
789 0 : tInterpType()=interp;
790 : }
791 :
792 : // Protect against non-specific interp
793 0 : if (tInterpType()=="")
794 0 : tInterpType()="linear";
795 0 : if (fInterpType()=="" && this->freqDepPar()) // only if we are freq-dep
796 0 : fInterpType()="linear";
797 :
798 : // Catch use of deprecated 'aipslin' interpolation
799 0 : 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 0 : String fieldstr;
837 0 : String fieldtype("");
838 0 : if (apply.isDefined("fieldstr")) {
839 0 : fieldstr=apply.asString("fieldstr");
840 : // cout << "SVC::setApply: fieldstr=" << fieldstr << endl;
841 0 : 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 0 : if (apply.isDefined("spwmap"))
850 0 : spwMap().assign(apply.asArrayInt("spwmap"));
851 :
852 : // Catch spwmap that is too long
853 0 : 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 0 : if (apply.isDefined("t"))
859 0 : interval()=apply.asFloat("t");
860 :
861 : // This is apply context
862 0 : setApplied(true);
863 0 : 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 0 : loadMemCalTable(calTableName(),fieldstr);
872 :
873 : // Make the interpolation engine
874 0 : MeasurementSet ms(msName());
875 0 : 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 0 : startChanList()=0; // all zero
881 :
882 : // cout << "End of SVC::setApply" << endl;
883 :
884 0 : }
885 :
886 : // Setapply from a Cal Table, etc.
887 0 : void SolvableVisCal::setCallib(const Record& callib,
888 : const MeasurementSet& selms) {
889 :
890 0 : if (prtlev()>2)
891 0 : cout << "SVC::setCallib(callib)" << endl;
892 :
893 :
894 0 : if (typeName().contains("BPOLY") ||
895 0 : 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 0 : VisCal::setCallib(callib,selms);
900 :
901 : // signal that we are using a callib
902 0 : byCallib_=true;
903 :
904 : // Collect Cal table parameters
905 0 : if (callib.isDefined("tablename")) {
906 0 : calTableName()=callib.asString("tablename");
907 : // Verify that CalTable is of correct type
908 0 : verifyCalTable(calTableName());
909 : }
910 :
911 : // This is apply context
912 0 : setApplied(true);
913 0 : setSolved(false);
914 :
915 : logSink() << LogIO::NORMAL << ". "
916 0 : << this->applyinfo()
917 0 : << LogIO::POST;
918 :
919 : // Make the interpolation engine
920 0 : 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 0 : ct_= new NewCalTable(calTableName(),Table::Old,Table::Plain);
926 :
927 0 : }
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 : }
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 : }// nsim loop
1371 : }
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 : }
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 : }
1425 :
1426 : // ===================================================
1427 :
1428 :
1429 :
1430 :
1431 :
1432 :
1433 0 : String SolvableVisCal::applyinfo() {
1434 :
1435 0 : ostringstream o;
1436 0 : o << typeName()
1437 0 : << ": table=" << calTableName();
1438 :
1439 0 : if (byCallib_)
1440 0 : o << " (by cal library)";
1441 : else {
1442 0 : o << " select=" << calTableSelect()
1443 0 : << " interp=" << tInterpType();
1444 0 : if (this->freqDepPar())
1445 0 : o << "," << fInterpType();
1446 0 : o << " spwmap=" << spwMap();
1447 :
1448 : }
1449 :
1450 0 : o << boolalpha << " calWt=" << calWt();
1451 : // << " t=" << interval();
1452 :
1453 0 : return String(o);
1454 :
1455 : }
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 0 : void SolvableVisCal::setSolve(const Record& solve)
1478 : {
1479 :
1480 0 : if (prtlev()>2) cout << "SVC::setSolve(solve)" << endl;
1481 :
1482 : // Collect parameters
1483 0 : if (solve.isDefined("table"))
1484 0 : calTableName()=solve.asString("table");
1485 :
1486 0 : if (calTableName().length()==0)
1487 0 : throw(AipsError("Please specify a name for the output calibration table!"));
1488 :
1489 : // Internal default solint
1490 0 : solint()="inf";
1491 0 : fsolint()="none";
1492 0 : if (solve.isDefined("solint")) {
1493 0 : usolint_=solve.asString("solint");
1494 0 : 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 0 : solint()=usolint_;
1502 : }
1503 :
1504 : // Handle solint format
1505 0 : if (upcase(solint()).contains("INF") || solint()=="") {
1506 0 : solint()="inf";
1507 0 : interval()=-1.0;
1508 : }
1509 0 : else if (upcase(solint()).contains("INT"))
1510 0 : interval()=0.0;
1511 : else {
1512 0 : QuantumHolder qhsolint;
1513 0 : String error;
1514 0 : Quantity qsolint;
1515 0 : qhsolint.fromString(error,solint());
1516 0 : if (error.length()!=0)
1517 0 : throw(AipsError("Unrecognized units for time-dep solint."));
1518 0 : qsolint=qhsolint.asQuantumDouble();
1519 :
1520 0 : if (qsolint.isConform("s"))
1521 0 : interval()=qsolint.get("s").getValue();
1522 : else {
1523 0 : if (qsolint.getUnit().length()==0) {
1524 : // when no units specified, assume seconds
1525 0 : interval()=qsolint.getValue();
1526 0 : 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 : }
1533 :
1534 : // Handle fsolint format
1535 0 : if (upcase(fsolint()).contains("NONE") || !freqDepPar()) {
1536 0 : fsolint()="none";
1537 0 : fintervalCh_.set(0.0);
1538 0 : 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 : }
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 : } // 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 0 : if (solve.isDefined("preavg"))
1584 0 : preavg()=solve.asFloat("preavg");
1585 :
1586 0 : if (solve.isDefined("refantmode")) {
1587 0 : refantmode_=solve.asString("refantmode");
1588 : }
1589 0 : if (solve.isDefined("refant")) {
1590 0 : refantlist().resize();
1591 0 : refantlist()=solve.asArrayInt("refant");
1592 : }
1593 0 : if (solve.isDefined("minblperant"))
1594 0 : minblperant()=solve.asInt("minblperant");
1595 :
1596 0 : if (solve.isDefined("apmode"))
1597 0 : apmode()=solve.asString("apmode");
1598 0 : apmode().upcase();
1599 :
1600 0 : if (solve.isDefined("append"))
1601 0 : append()=solve.asBool("append");
1602 :
1603 0 : if (solve.isDefined("solnorm")) {
1604 0 : Bool solnorm=solve.asBool("solnorm");
1605 :
1606 : // normtype="mean" if not specified
1607 0 : String normtype("mean");
1608 0 : if (solve.isDefined("normtype"))
1609 0 : normtype=solve.asString("normtype");
1610 :
1611 : // Set the SolNorm object
1612 0 : solnorm_=SolNorm(solnorm,normtype);
1613 :
1614 : }
1615 :
1616 0 : if (solve.isDefined("minsnr"))
1617 0 : minSNR()=solve.asFloat("minsnr");
1618 :
1619 0 : if (solve.isDefined("combine"))
1620 0 : 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 0 : if (normalizable() && preavg()<0.0)
1629 0 : preavg()=DBL_MAX;
1630 :
1631 : // This is the solve context
1632 0 : setSolved(true);
1633 0 : setApplied(false);
1634 :
1635 : // state();
1636 :
1637 0 : }
1638 :
1639 0 : String SolvableVisCal::solveinfo() {
1640 :
1641 : // Get the refant name from the MS
1642 0 : String refantNames("none");
1643 0 : if (refant()>-1) {
1644 0 : refantNames="";
1645 0 : Int nra=refantlist().nelements();
1646 0 : for (Int i=0;i<nra;++i) {
1647 0 : refantNames+=msmc().antennaName(refantlist()(i));
1648 0 : if (i<nra-1) refantNames+=",";
1649 : }
1650 : }
1651 :
1652 0 : ostringstream o;
1653 0 : o << boolalpha
1654 0 : << typeName()
1655 0 : << ": table=" << calTableName()
1656 0 : << " append=" << append()
1657 0 : << " solint=" << solint()
1658 0 : << (freqDepPar() ? (","+fsolint()) : "")
1659 : // << " t=" << interval()
1660 : // << " preavg=" << preavg()
1661 0 : << " refantmode=" << "'" << refantmode_ << "'"
1662 0 : << " refant=" << "'" << refantNames << "'" // (id=" << refant() << ")"
1663 0 : << " minsnr=" << minSNR()
1664 0 : << " apmode=" << apmode()
1665 0 : << " solnorm=" << solnorm()
1666 0 : << (solnorm() ? " normtype="+solNorm().normtypeString() : "");
1667 0 : return String(o);
1668 :
1669 : }
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 0 : void SolvableVisCal::setSpecify(const Record& specify) {
1736 :
1737 0 : LogMessage message(LogOrigin("SolvableVisCal","setSpecify"));
1738 :
1739 : // Not actually applying or solving
1740 0 : setSolved(false);
1741 0 : setApplied(false);
1742 :
1743 : // Collect Cal table parameters
1744 0 : Bool tableExists(false);
1745 0 : if (specify.isDefined("caltable")) {
1746 0 : calTableName()=specify.asString("caltable");
1747 :
1748 : // Detect existence of the table
1749 0 : tableExists=Table::isReadable(calTableName());
1750 :
1751 : }
1752 :
1753 0 : 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 : } // tableExists
1802 : else {
1803 :
1804 0 : nChanParList()=Vector<Int>(nSpw(),1);
1805 0 : startChanList()=Vector<Int>(nSpw(),0);
1806 :
1807 : // we are creating a table from scratch
1808 0 : logSink() << "Creating " << typeName()
1809 : << " table from specified parameters."
1810 0 : << LogIO::POST;
1811 :
1812 : // Size up the solve arrays
1813 0 : initSolvePar();
1814 :
1815 0 : for (Int ispw=0;ispw<nSpw();++ispw) {
1816 0 : currSpw()=ispw;
1817 0 : refTime()=0.0;
1818 0 : currField()=-1;
1819 0 : currScan()=-1;
1820 0 : currObs()=0;
1821 :
1822 0 : switch(parType()) {
1823 0 : case VisCalEnum::COMPLEX: {
1824 0 : solveAllCPar().set(defaultCPar());
1825 0 : 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 0 : solveAllParOK().set(true);
1836 0 : solveAllParSNR().set(1.0);
1837 0 : solveAllParErr().set(0.0);
1838 :
1839 : } // ispw
1840 : } // !tableExists
1841 :
1842 : // Create the caltable
1843 0 : createMemCalTable();
1844 :
1845 0 : }
1846 :
1847 0 : void SolvableVisCal::specify(const Record& specify) {
1848 :
1849 0 : LogMessage message(LogOrigin("SolvableVisCal","specify"));
1850 :
1851 0 : Vector<Int> spws;
1852 0 : Vector<Int> antennas;
1853 0 : Vector<Int> pols;
1854 0 : Vector<Double> parameters;
1855 :
1856 0 : Int nUserSpw(1);
1857 0 : Int Ntime(1);
1858 0 : Int Nant(0);
1859 0 : Int Npol(1);
1860 :
1861 0 : Bool repspw(false);
1862 :
1863 0 : IPosition ip0(3,0,0,0);
1864 0 : IPosition ip1(3,0,0,0);
1865 :
1866 0 : if (specify.isDefined("caltype")) {
1867 0 : String caltype=specify.asString("caltype");
1868 0 : logSink() << "Generating '" << caltype << "' corrections." << LogIO::POST;
1869 0 : if (upcase(caltype).contains("PH"))
1870 0 : apmode()="P";
1871 : else
1872 0 : apmode()="A";
1873 : }
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 0 : if (specify.isDefined("spw")) {
1892 : // TBD: the spws (in order) identifying the solutions
1893 0 : spws=specify.asArrayInt("spw");
1894 0 : nUserSpw=spws.nelements();
1895 0 : 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 0 : if (specify.isDefined("antenna")) {
1910 : // TBD: the antennas (in order) identifying the solutions
1911 0 : antennas=specify.asArrayInt("antenna");
1912 : // cout << "antenna indices = " << antennas << endl;
1913 0 : Nant=antennas.nelements();
1914 0 : 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 0 : << LogIO::POST;
1919 0 : Nant=1; // For the antenna loop below
1920 0 : ip0(2)=0;
1921 0 : 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 0 : if (specify.isDefined("pol")) {
1930 : // TBD: the pols (in order) identifying the solutions
1931 0 : String polstr=specify.asString("pol");
1932 : // cout << "pol = " << polstr << endl;
1933 0 : if (polstr=="R" || polstr=="X")
1934 : // Fill in only first pol
1935 0 : pols=Vector<Int>(1,0);
1936 0 : else if (polstr=="L" || polstr=="Y")
1937 : // Fill in only second pol
1938 0 : pols=Vector<Int>(1,1);
1939 0 : 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 0 : 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 0 : else if (polstr=="")
1950 : // Fill in both pols implicitly
1951 0 : pols=Vector<Int>();
1952 : else
1953 0 : throw(AipsError("Invalid pol specification"));
1954 :
1955 0 : Npol=pols.nelements();
1956 0 : if (Npol<1) {
1957 : // No pol axis specified
1958 : logSink() <<
1959 : "Specified parameter(s) (per spw and antenna) repeated on all polarizations."
1960 0 : << LogIO::POST;
1961 0 : Npol=1;
1962 0 : ip0(0)=0;
1963 0 : 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 : }
1971 0 : if (specify.isDefined("parameter")) {
1972 : // TBD: the actual cal values
1973 0 : parameters=specify.asArrayDouble("parameter");
1974 : }
1975 0 : 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 0 : 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 0 : Int ipar(0);
1989 0 : for (Int iUspw=0;iUspw<nUserSpw;++iUspw) {
1990 :
1991 0 : currSpw()=spws(iUspw);
1992 :
1993 : // reset par index if we are repeating for all spws
1994 0 : if (repspw) ipar=0;
1995 :
1996 : // Loop over specified antennas
1997 0 : for (Int iant=0;iant<Nant;++iant) {
1998 0 : if (Nant>1)
1999 0 : ip1(2)=ip0(2)=antennas(iant);
2000 :
2001 : // Loop over specified polarizations
2002 0 : for (Int ipol=0;ipol<Npol;++ipol) {
2003 0 : if (Npol>1)
2004 0 : ip1(0)=ip0(0)=pols(ipol);
2005 :
2006 : // Report details as compactly as possible
2007 0 : if (!repspw || iUspw==0)
2008 : logSink() << "spwId="
2009 0 : << (repspw ? "<all>" : String::toString(currSpw()) )
2010 : << " antId="
2011 0 : << (antennas.nelements()>0 ? String::toString(antennas(iant)) : "<all>")
2012 : << " polId="
2013 0 : << (pols.nelements()>0 ? String::toString(pols(ipol)) : "<all>")
2014 0 : << " parameter= " << parameters(ipar)
2015 : << " (ip0,ip1 = " << ip0 << "," << ip1 << ")"
2016 0 : << LogIO::POST;
2017 :
2018 0 : switch(parType()) {
2019 0 : case VisCalEnum::COMPLEX: {
2020 0 : Array<Complex> sl(solveAllCPar()(ip0,ip1));
2021 : // Multiply ipar-th parameter onto the selecte slice
2022 0 : if (apmode()=="P") {
2023 : // Phases have been specified
2024 0 : Double phase=parameters(ipar)*C::pi/180.0;
2025 0 : sl*=Complex(cos(phase),sin(phase));
2026 : }
2027 : else
2028 : // Assume amplitude
2029 0 : sl*=Complex(parameters(ipar));
2030 0 : break;
2031 : }
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 : }
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 0 : ++ipar;
2046 0 : ipar = ipar%nparam;
2047 :
2048 :
2049 : } // ipol
2050 : } // iant
2051 :
2052 : } // iUspw
2053 :
2054 :
2055 : // Now write keep _all_ spws
2056 0 : for (Int ispw=0;ispw<nSpw();++ispw) {
2057 : // Keep this result
2058 0 : currSpw()=ispw;
2059 0 : keepNCT();
2060 : }
2061 :
2062 0 : }
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 : }
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 : }
2531 :
2532 : // VI2-related refactorings------------------
2533 :
2534 0 : void SolvableVisCal::setMeta(Int obs, Int scan, Double time,
2535 : Int spw, const Vector<Double>& freq,
2536 : Int fld) {
2537 :
2538 0 : VisCal::setMeta(obs,scan,time,spw,freq,fld);
2539 :
2540 0 : refTime()=time; // current time for solving is _refTime()_
2541 :
2542 : // refFreq()=???
2543 :
2544 0 : }
2545 :
2546 :
2547 : // Setup solvePar shape for a spw
2548 0 : Int SolvableVisCal::sizeSolveParCurrSpw(Int nVisChan) {
2549 :
2550 : // Sizes the solvePar arrays for the currSpw()
2551 :
2552 0 : if (prtlev()>3) cout << " SVJ::sizeSolveParCurrSpw()" << endl;
2553 :
2554 : // Use nVisChan only for freqDepPar() types
2555 0 : Int nChan = ( freqDepPar() ? nVisChan : 1);
2556 :
2557 : // Keep old way informed (needed?)
2558 0 : nChanPar()=nChan;
2559 :
2560 : // Now, size the arrays:
2561 :
2562 0 : IPosition parsh(3,nPar(),nChan,nElem()); // multi-chan
2563 0 : IPosition parsh1(3,nPar(),1,nElem()); // single-chan
2564 0 : 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 0 : case VisCalEnum::REAL: {
2577 0 : solveAllRPar().resize(parsh);
2578 0 : solveAllRPar()=0.0;
2579 0 : if (nChanPar()==1)
2580 0 : solveRPar().reference(solveAllRPar());
2581 : else {
2582 0 : solveRPar().resize(parsh1);
2583 0 : solveRPar()=0.0;
2584 : }
2585 0 : break;
2586 : }
2587 0 : default:
2588 : throw(AipsError("Internal error(Calibrater Module): Unsupported parameter type "
2589 0 : "COMPLEXREAL found in SVC::sizeSolveParCurrSpw"));
2590 : }
2591 :
2592 0 : solveAllParOK().resize(parsh);
2593 0 : solveAllParErr().resize(parsh);
2594 0 : solveAllParSNR().resize(parsh);
2595 0 : solveAllParOK()=True;
2596 0 : solveAllParErr()=0.0;
2597 0 : solveAllParSNR()=0.0;
2598 0 : if (nChan==1) {
2599 0 : solveParOK().reference(solveAllParOK());
2600 0 : solveParErr().reference(solveAllParErr());
2601 0 : 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 0 : return nChan;
2615 :
2616 : }
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 : 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 0 : void SolvableVisCal::reParseSolintForVI2() {
2646 :
2647 : // Internal default solint
2648 0 : solint()="inf";
2649 0 : fsolint()="none";
2650 0 : 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 0 : solint()=usolint_;
2658 :
2659 : // solint is always "int" for single dish calibration
2660 0 : if (longTypeName().startsWith("SDGAIN_OTFD")) {
2661 : //return;
2662 0 : solint() = "int";
2663 : }
2664 :
2665 : // Handle solint format
2666 0 : if (upcase(solint()).contains("INF") || solint()=="") {
2667 0 : solint()="inf";
2668 0 : solTimeInterval_=DBL_MAX;
2669 : }
2670 0 : else if (upcase(solint()).contains("INT"))
2671 0 : solTimeInterval_=FLT_MIN; // implausibly small; forces chunk boundaries at integrations
2672 : else {
2673 0 : QuantumHolder qhsolint;
2674 0 : String error;
2675 0 : Quantity qsolint;
2676 0 : qhsolint.fromString(error,solint());
2677 0 : if (error.length()!=0)
2678 0 : throw(AipsError("Unrecognized units for time-dep solint."));
2679 0 : qsolint=qhsolint.asQuantumDouble();
2680 :
2681 0 : if (qsolint.isConform("s"))
2682 0 : solTimeInterval_=qsolint.get("s").getValue();
2683 : else {
2684 0 : if (qsolint.getUnit().length()==0) {
2685 : // when no units specified, assume seconds
2686 0 : solTimeInterval_=qsolint.getValue();
2687 0 : 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 : }
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 0 : if (upcase(fsolint()).contains("NONE") || // unspecified OR
2702 0 : !freqDepMat()) { // cal is entirely unchannelizedb
2703 0 : fsolint()="none";
2704 0 : fintervalCh_.set(-1.0); // signals full averaging (this is different from old way)
2705 0 : 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 : }
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 : } // 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 0 : }
2752 :
2753 :
2754 : // Generate the in-memory caltable (empty)
2755 : // NB: no subtable revisions
2756 0 : void SolvableVisCal::createMemCalTable2() {
2757 :
2758 : // cout << "createMemCalTable" << endl;
2759 :
2760 : // Set up description
2761 0 : String partype = ((parType()==VisCalEnum::COMPLEX) ? "Complex" : "Float");
2762 0 : CTDesc caltabdesc(partype,Path(msName()).baseName(),typeName(),"unknown");
2763 0 : ct_ = new NewCalTable("tempNCT.tab",caltabdesc,Table::Scratch,Table::Memory);
2764 :
2765 0 : if (msmc().msOk())
2766 0 : 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 : }
2774 :
2775 : // Flag all SPW subtable rows; we'll set them OTF
2776 0 : CTColumns ncc(*ct_);
2777 :
2778 : // Set FLAG_ROW in SPW subtable
2779 0 : Vector<Bool> flr=ncc.spectralWindow().flagRow().getColumn();
2780 0 : flr.set(True);
2781 0 : 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 0 : CTSpWindowColumns& spwcol(ncc.spectralWindow());
2787 0 : if (!freqDepPar()) {
2788 0 : Int nspw=ncc.spectralWindow().nrow();
2789 0 : for (Int ispw=0;ispw<nspw;++ispw) {
2790 0 : Vector<Double> chfr,chwid,chres,cheff;
2791 :
2792 0 : spwcol.chanFreq().get(ispw,chfr);
2793 0 : spwcol.chanWidth().get(ispw,chwid);
2794 0 : spwcol.resolution().get(ispw,chres);
2795 0 : spwcol.effectiveBW().get(ispw,cheff);
2796 :
2797 0 : spwcol.chanFreq().put(ispw,Vector<Double>(1,mean(chfr)));
2798 0 : spwcol.chanWidth().put(ispw,Vector<Double>(1,sum(chwid)));
2799 0 : spwcol.resolution().put(ispw,Vector<Double>(1,sum(chres)));
2800 0 : spwcol.effectiveBW().put(ispw,Vector<Double>(1,sum(cheff)));
2801 : }
2802 :
2803 : // One channel per spw
2804 0 : spwcol.numChan().putColumn(Vector<Int>(nspw,1));
2805 : }
2806 :
2807 0 : }
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 : }
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 : }
2934 0 : }
2935 :
2936 0 : void SolvableVisCal::setCTFrequencies(Int spw) {
2937 :
2938 : // cout << "SVC::setCTFrequencies......." << endl;
2939 :
2940 :
2941 : // Discern spw to which to write
2942 0 : Int outspw=spw;
2943 : // If combining spws, freqMetaData_ knows the fan-in
2944 0 : if (combspw())
2945 0 : outspw=freqMetaData_.fannedInSpw(spw);
2946 :
2947 : // Access SPW subtable columns
2948 0 : CTColumns ctcol(*ct_);
2949 0 : CTSpWindowColumns& spwcol(ctcol.spectralWindow());
2950 :
2951 : // If row is flagged, then it hasn't been set yet (in this execution or any prior)
2952 0 : Bool needToSet(spwcol.flagRow().get(outspw));
2953 :
2954 :
2955 : // cout << "needToSet = " << boolalpha << needToSet << endl;
2956 :
2957 :
2958 0 : if (needToSet) {
2959 :
2960 : //cout << "Setting freqs for spw=" << outspw << endl;
2961 :
2962 : // const references to freq info from freqMetaData_
2963 0 : const Vector<Double>& chfr(freqMetaData_.freq(outspw));
2964 0 : const Vector<Double>& chwid(freqMetaData_.width(outspw));
2965 0 : const Vector<Double>& cheff(freqMetaData_.effBW(outspw));
2966 :
2967 : // Derived info
2968 0 : const Vector<Double>& chres(chfr); // resolution same as freq
2969 0 : Int numChan=chfr.nelements();
2970 0 : 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 0 : spwcol.chanFreq().put(outspw,chfr);
2976 0 : spwcol.chanWidth().put(outspw,chwid);
2977 0 : spwcol.resolution().put(outspw,chres);
2978 0 : spwcol.effectiveBW().put(outspw,cheff);
2979 0 : spwcol.numChan().put(outspw,numChan);
2980 0 : spwcol.totalBandwidth().put(outspw,totbw);
2981 0 : 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 0 : Vector<Double> currCTFreq;
2997 0 : spwcol.chanFreq().get(outspw,currCTFreq);
2998 : Int numChan;
2999 0 : spwcol.numChan().get(outspw,numChan);
3000 :
3001 : // Current solution freqs
3002 0 : const Vector<Double>& chfr(freqMetaData_.freq(outspw));
3003 0 : const Int numChanOut(chfr.nelements());
3004 :
3005 : // If values mismatch, we need to abort
3006 0 : 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 : } // !needToSet
3018 :
3019 0 : }
3020 :
3021 : // Discern detailed frequency meta info for solutions (solve context)
3022 0 : 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 0 : Vector<Int> frames(vi.spectralWindowSubtablecols().measFreqRef().getColumn());
3028 : //cout << "vi.spectralWindowSubtablecols().measFreqRef() = " << frames << endl;
3029 :
3030 : // Gather MS freq info
3031 0 : Vector< Vector<Double> > MSfreq(nSpw(),Vector<Double>()), MSwidth(nSpw(),Vector<Double>());
3032 0 : for (uInt i=0;i<selspws.nelements();++i) {
3033 0 : uInt ispw=selspws(i);
3034 :
3035 0 : MSfreq(ispw).assign(vi.getImpl()->getFrequencies(-1.0e0,frames(ispw),ispw,0));
3036 0 : 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 0 : Vector<Int> spwFanIn;
3045 :
3046 : // Work out spwFanIn from selecte spws, if we are combining spws...
3047 0 : if (combspw()) {
3048 :
3049 : // We're combining, so set up the "spwmap" for spw fan-in
3050 0 : spwFanIn.resize(nSpw());
3051 0 : spwFanIn.set(-1); // -1 means not included
3052 :
3053 : // Use the MINIMUM spwid from selection for the aggregate
3054 0 : Int aggSpw=min(selspws);
3055 0 : for (uInt iselspw=0;iselspw<selspws.nelements();++iselspw)
3056 0 : spwFanIn(selspws(iselspw))=aggSpw;
3057 :
3058 : }
3059 :
3060 : // Now delegate the freq meta calculation to the FreqMetaData object
3061 0 : 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 0 : if (append()) {
3066 0 : const CTSpectralWindow ctspw(calTableName()+"/SPECTRAL_WINDOW");
3067 0 : const CTSpWindowColumns& spwcol(ctspw);
3068 :
3069 : // Which spws are we procssing now?
3070 0 : Vector<Int> validfMDspws(freqMetaData_.validSpws());
3071 :
3072 : // If current spws already in disk table, freq meta must match!
3073 0 : for (uInt i=0;i<validfMDspws.nelements();++i) {
3074 0 : 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 0 : if (!spwcol.flagRow().get(ispw)) {
3078 :
3079 : // disk table info
3080 0 : const uInt numChan(spwcol.numChan().get(ispw));
3081 0 : const Vector<Double> currCTFreq(spwcol.chanFreq().get(ispw));
3082 :
3083 : // current pending freq info
3084 0 : 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 0 : if (numChan!=fMDfreq.nelements() || !allEQ(currCTFreq,fMDfreq))
3090 0 : throw(AipsError("Mismatch with frequency meta-data in append to "+
3091 0 : calTableName()+" detected in spw="+String::toString(ispw)+". Check spw selection."));
3092 :
3093 : } // !flagged in disk table
3094 :
3095 : } // validfMDspws(i}
3096 :
3097 : } // append?
3098 :
3099 :
3100 :
3101 : // TBD: Add more log info, probably inside FreqMetaData...
3102 :
3103 0 : }
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 : }
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 : }
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 0 : void SolvableVisCal::syncSolveMeta(SDBList& sdbs) { // VI2
3391 :
3392 : // cout << "spwMap() = " << spwMap() << endl;
3393 :
3394 : // Ask the sdbs
3395 0 : Vector<Double> freqs;
3396 0 : if (freqDepPar())
3397 : // nominally channelized
3398 0 : freqs.reference(sdbs.freqs());
3399 : else
3400 : // a single aggregate frequency (as a Vector)
3401 0 : freqs.reference(Vector<Double>(1,sdbs.aggregateCentroidFreq()));
3402 :
3403 0 : setMeta(sdbs.aggregateObsId(),
3404 : sdbs.aggregateScan(),
3405 : //sdbs.aggregateTime(),
3406 : sdbs.aggregateTimeCentroid(),
3407 : sdbs.aggregateSpw(),
3408 : freqs,
3409 0 : sdbs.aggregateFld());
3410 0 : }
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 : }
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 : } // 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 : }
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 : }
3679 :
3680 0 : void SolvableVisCal::clearMap() {
3681 : // Clear or initalize values for the antennaMap_
3682 0 : Vector<Int> initVector(nPar(), 0);
3683 0 : Vector<Int> singleVector(1, 0);
3684 :
3685 0 : for (Int iant=0; iant<nAnt(); ++iant) {
3686 0 : antennaMap_[iant]["expected"] = initVector;
3687 0 : antennaMap_[iant]["data_unflagged"] = initVector;
3688 0 : antennaMap_[iant]["above_minblperant"] = initVector;
3689 0 : antennaMap_[iant]["above_minsnr"] = initVector;
3690 0 : antennaMap_[iant]["used_as_refant"] = singleVector;
3691 : }
3692 :
3693 0 : }
3694 :
3695 0 : void SolvableVisCal::clearRefantMap() {
3696 : // Clear or initialize values for refantMap_
3697 0 : for (Int ispw=0; ispw<nSpw(); ++ispw) {
3698 0 : for (Int iant=0; iant<nAnt(); ++iant) {
3699 0 : refantMap_[ispw][iant] = 0;
3700 : }
3701 : }
3702 0 : }
3703 :
3704 0 : void SolvableVisCal::expectedUnflagged(SDBList& sdbs) {
3705 : // Iterate over sdbs and add values to expected and data unflagged
3706 0 : for (Int isdb=0;isdb<sdbs.nSDB();++isdb) {
3707 0 : SolveDataBuffer& sdb(sdbs(isdb));
3708 :
3709 0 : Int nRow(sdb.nRows());
3710 0 : Int nCorr(sdb.nCorrelations());
3711 0 : for (Int irow=0;irow<nRow;++irow) {
3712 0 : const Int& a1(sdb.antenna1()(irow));
3713 0 : const Int& a2(sdb.antenna2()(irow));
3714 :
3715 0 : if (a1!=a2) {
3716 0 : for (int par=0;par<nPar();par++) {
3717 0 : antennaMap_[a1]["expected"][par] = 1;
3718 0 : antennaMap_[a2]["expected"][par] = 1;
3719 : }
3720 : }
3721 : // Do cal type-dependent setting of "data_unflagged" counts
3722 :
3723 0 : switch (this->type()) {
3724 0 : 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 0 : if (nfalse(sdb.flagCube()(0,Slice(),irow))>0) {
3729 0 : antennaMap_[a1]["data_unflagged"][0] =
3730 0 : antennaMap_[a2]["data_unflagged"][0] = 1;
3731 : }
3732 0 : if (nfalse(sdb.flagCube()(nCorr-1,Slice(),irow))>0) {
3733 0 : antennaMap_[a1]["data_unflagged"][1] =
3734 0 : antennaMap_[a2]["data_unflagged"][1] = 1;
3735 : }
3736 0 : 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 0 : }
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 : }
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 : }
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 : }
4134 :
4135 0 : Record SolvableVisCal::solveActionRec() {
4136 :
4137 : // Return empty record
4138 : // TBD: consider returning various _generic_ info
4139 : // NB: specialization may add particulars via merge
4140 0 : Record r;
4141 0 : 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 :
4152 0 : if (smoothable())
4153 : // Call NewCalTable's global smooth method
4154 0 : casa::smoothCT(*ct_,smtype,smtime,fields);
4155 : else
4156 0 : throw(AipsError("This type "+this->typeName()+" does not support smoothing!"));
4157 :
4158 0 : }
4159 :
4160 0 : void SolvableVisCal::syncSolveCal() {
4161 :
4162 0 : if (prtlev()>4) cout << " SVC::syncSolveCal()" << endl;
4163 :
4164 : // Ensure parameters are ready
4165 0 : syncSolvePar();
4166 :
4167 0 : if (!PValid())
4168 0 : throw(AipsError("No valid parameters in syncSolveCal"));
4169 :
4170 : // Sync up matrices using current params
4171 0 : syncCalMat(false); // NEVER invert in solve context
4172 0 : syncDiffMat();
4173 :
4174 0 : }
4175 0 : void SolvableVisCal::syncSolvePar() {
4176 :
4177 0 : if (prtlev()>5) cout << " SVC::syncSolvePar()" << endl;
4178 :
4179 : // In solve context, reference solveCPar(), etc.
4180 0 : AlwaysAssert((solveCPar().nelements()>0 || solveRPar().nelements()>0),AipsError);
4181 0 : currCPar().reference(solveCPar());
4182 0 : currRPar().reference(solveRPar());
4183 0 : currParOK().reference(solveParOK());
4184 0 : validateP();
4185 :
4186 0 : }
4187 :
4188 0 : void SolvableVisCal::calcPar() {
4189 :
4190 0 : if (simOnTheFly() and isSimulated()) {
4191 0 : if (prtlev()>3) cout << "SVC:calcPar triggered simOTF with isSolved=" << isSolved()
4192 0 : << " isApplied=" << isApplied() << " isSimulated=" << isSimulated() << endl;
4193 0 : syncSolvePar(); // OTF simulation context RI 20100831
4194 : } else {
4195 :
4196 0 : if (prtlev()>6) cout << " SVC::calcPar()" << endl;
4197 :
4198 : // This method is relevant only to the apply (& simulate) context
4199 :
4200 : // If we have a CLPatchPanel, use it
4201 0 : if (cpp_)
4202 0 : this->calcParByCLPP();
4203 : else { // use CTPatchedInterp
4204 :
4205 0 : Bool newcal(false);
4206 :
4207 : // Interpolate solution (CTPatchedInterp)
4208 0 : if (freqDepPar()) {
4209 :
4210 : //cout << "currFreq() = " << currFreq().shape() << " " << currFreq() << endl;
4211 :
4212 : // Call w/ freq-dep
4213 0 : if (fInterpType().contains("rel")) {
4214 : // Relative freq
4215 0 : Double freqOff(msmc().centerFreq(currSpw()));
4216 0 : Double SBfactor(1.0);
4217 0 : if (currFreq().nelements()>1 && currFreq()(0)>currFreq()(1))
4218 0 : SBfactor=-1.0f;
4219 : //cout << "freqOff=" << freqOff << " SBfactor=" << SBfactor << " netSB=" << msmc().msmd().getNetSidebands()[currSpw()] << endl;
4220 0 : newcal=ci_->interpolate(currObs(),currScan(),currField(),currSpw(),currTime(),(currFreq()-freqOff)*SBfactor);
4221 : }
4222 : else
4223 : // absolute freq
4224 0 : newcal=ci_->interpolate(currObs(),currScan(),currField(),currSpw(),currTime(),currFreq());
4225 :
4226 : // cout.precision(12);
4227 : // cout << typeName() << " t="<< currTime() << " newcal=" << boolalpha << newcal << endl;
4228 : }
4229 : else {
4230 0 : if (parType()==VisCalEnum::COMPLEX)
4231 : // Call w/ fiducial freq for phase-delay correction
4232 : // TBD: improve freq spec, e.g., use spw center freq rather than _selected_ center
4233 0 : newcal=ci_->interpolate(currObs(),currScan(),currField(),currSpw(),currTime(),1.0e9*currFreq()(currFreq().nelements()/2));
4234 : else
4235 : // No freq info at all
4236 0 : newcal=ci_->interpolate(currObs(),currScan(),currField(),currSpw(),currTime());
4237 : }
4238 :
4239 : // TBD: signal failure to find calibration?? (e.g., for a spw?)
4240 :
4241 : // Parameters now (or still) valid (independent of newcal!!)
4242 0 : validateP();
4243 :
4244 : // If new cal parameters, use them
4245 0 : if (newcal) {
4246 :
4247 : // cout << "Found new cal!" << endl;
4248 :
4249 : // Reference result
4250 0 : if (parType()==VisCalEnum::COMPLEX)
4251 0 : currCPar().reference(ci_->resultC(currObs(),currScan(),currField(),currSpw()));
4252 0 : else if (parType()==VisCalEnum::REAL)
4253 0 : currRPar().reference(ci_->resultF(currObs(),currScan(),currField(),currSpw()));
4254 : else
4255 0 : throw(AipsError("Bad parType() in SVC::calcPar"));
4256 :
4257 : // Assign _inverse_ of parameter flags
4258 0 : currParOK().reference(!ci_->rflag(currObs(),currScan(),currField(),currSpw()));
4259 :
4260 : // Ensure shapes recorded correctly
4261 : // (New interpolation generates cal samples for all data channels...revisit?
4262 0 : IPosition ip=currCPar().shape();
4263 0 : nChanPar()=ip(1);
4264 0 : startChan()=0;
4265 :
4266 : // In case we need solution timestamp
4267 : // NB: w/ new caltables, we use currTime() here.
4268 0 : refTime() = currTime();
4269 :
4270 : // If new parameters, matrices (generically) are necessarily invalid now
4271 0 : invalidateCalMat();
4272 : }
4273 : }
4274 : }
4275 :
4276 0 : }
4277 :
4278 0 : void SolvableVisCal::calcParByCLPP() {
4279 :
4280 0 : Bool newcal(false);
4281 0 : Cube<Bool> resFlag;
4282 :
4283 : // Interpolate solution
4284 0 : switch (parType()) {
4285 0 : case VisCalEnum::COMPLEX: {
4286 :
4287 0 : if (freqDepPar()) {
4288 : // Call w/ freq-dep
4289 0 : newcal=cpp_->interpolate(currCPar(),resFlag,currObs(),currScan(),currField(),currIntent(),currSpw(),currTime(),currFreq());
4290 : }
4291 : else {
4292 : // Call w/ fiducial freq for phase-delay correction
4293 0 : Double freq=1.0e9*currFreq()(currFreq().nelements()/2);
4294 0 : newcal=cpp_->interpolate(currCPar(),resFlag,currObs(),currScan(),currField(),currIntent(),currSpw(),currTime(),freq);
4295 : }
4296 0 : break;
4297 : }
4298 0 : case VisCalEnum::REAL: {
4299 : // Interpolate solution
4300 0 : if (freqDepPar()) {
4301 : // Call w/ freq-dep
4302 0 : newcal=cpp_->interpolate(currRPar(),resFlag,currObs(),currScan(),currField(),currIntent(),currSpw(),currTime(),currFreq());
4303 : }
4304 : else {
4305 0 : newcal=cpp_->interpolate(currRPar(),resFlag,currObs(),currScan(),currField(),currIntent(),currSpw(),currTime(),-1.0);
4306 : }
4307 0 : break;
4308 : }
4309 0 : default:
4310 0 : throw(AipsError("Unhandled parType()")); // users should never see this
4311 : break;
4312 : }
4313 :
4314 : // TBD: signal failure to find calibration?? (e.g., for a spw?)
4315 :
4316 : // Parameters now (or still) valid (independent of newcal!!)
4317 0 : validateP();
4318 :
4319 0 : if (newcal) {
4320 :
4321 : // Assign _inverse_ of parameter flags
4322 0 : currParOK().reference(!resFlag);
4323 :
4324 : // Ensure shapes recorded correctly
4325 : // (New interpolation generates cal samples for all data channels...revisit?
4326 : // IS THIS NEEDED?
4327 0 : IPosition ip=currCPar().shape();
4328 0 : nChanPar()=ip(1);
4329 0 : startChan()=0;
4330 :
4331 : // In case we need solution timestamp
4332 : // NB: w/ new caltables, we use currTime() here.
4333 0 : refTime() = currTime();
4334 :
4335 : // If new parameters, matrices (generically) are necessarily invalid now
4336 0 : invalidateCalMat();
4337 : }
4338 :
4339 0 : }
4340 :
4341 :
4342 : // Report solved-for QU
4343 0 : void SolvableVisCal::reportSolvedQU() {
4344 :
4345 0 : String fldname(msmc().fieldName(currField()));
4346 :
4347 0 : if (solvePol()==2) {
4348 0 : Float Q=real(srcPolPar()(0));
4349 0 : Float U=real(srcPolPar()(1));
4350 0 : Float P=sqrt(Q*Q + U*U);
4351 0 : Float X=atan2(U,Q)/2.0*180.0/C::pi;
4352 :
4353 : logSink() << "Fractional polarization solution for " << fldname
4354 0 : << " (spw = " << currSpw() << "): "
4355 : << ": Q = " << Q
4356 : << ", U = " << U
4357 : << " (P = " << P
4358 : << ", X = " << X << " deg)"
4359 0 : << LogIO::POST;
4360 : }
4361 0 : else if (solvePol()==1) {
4362 : logSink() << "Position angle offset solution for " << fldname
4363 0 : << " (spw = " << currSpw() << ") = "
4364 0 : << real(srcPolPar()(0))*180.0/C::pi/2.0
4365 : << " deg."
4366 0 : << LogIO::POST;
4367 : }
4368 0 : }
4369 :
4370 0 : void SolvableVisCal::createMemCalTable() {
4371 :
4372 : // cout << "createMemCalTable" << endl;
4373 :
4374 : // Set up description
4375 0 : String partype = ((parType()==VisCalEnum::COMPLEX) ? "Complex" : "Float");
4376 :
4377 0 : if (msName()!="<noms>") {
4378 0 : CTDesc caltabdesc(partype,Path(msName()).baseName(),typeName(),"unknown");
4379 0 : ct_ = new NewCalTable("tempNCT.tab",caltabdesc,Table::Scratch,Table::Memory)
4380 : ;
4381 0 : ct_->setMetaInfo(msName());
4382 : }
4383 : else {
4384 0 : ct_ = new NewCalTable("tempNCT.tab",partype,typeName(),msmc().ssp(),
4385 0 : false,true);
4386 : }
4387 :
4388 0 : CTColumns ncc(*ct_);
4389 :
4390 : // Revise SPW frequencies
4391 0 : for (Int ispw=0;ispw<nSpw();++ispw) {
4392 :
4393 0 : currSpw()=ispw;
4394 :
4395 : // MS freqs
4396 0 : Vector<Double> chfr,chwid,chres,cheff;
4397 0 : ncc.spectralWindow().chanFreq().get(ispw,chfr);
4398 0 : ncc.spectralWindow().chanWidth().get(ispw,chwid);
4399 0 : ncc.spectralWindow().resolution().get(ispw,chres);
4400 0 : ncc.spectralWindow().effectiveBW().get(ispw,cheff);
4401 :
4402 0 : Int nchan=0;
4403 0 : Vector<Double> calfreq,calwid,calres,caleff;
4404 0 : if (startChan()>-1 && nChanPar()>0) {
4405 :
4406 0 : if (freqDepPar()) {
4407 0 : if (fsolint()!="none") {
4408 0 : IPosition blc(1,0),trc(1,0);
4409 0 : Matrix<Int> bounds(chanAveBounds());
4410 0 : nchan=bounds.nrow();
4411 0 : calfreq.resize(nchan);
4412 0 : calwid.resize(nchan);
4413 0 : calres.resize(nchan);
4414 0 : caleff.resize(nchan);
4415 0 : cout.precision(12);
4416 0 : for (Int ochan=0;ochan<nchan;++ochan) {
4417 0 : blc(0)=bounds(ochan,0);
4418 0 : trc(0)=bounds(ochan,1);
4419 0 : calfreq(ochan)=mean(chfr(blc,trc));
4420 0 : calwid(ochan)=sum(chwid(blc,trc));
4421 0 : calres(ochan)=sum(chres(blc,trc));
4422 0 : caleff(ochan)=sum(cheff(blc,trc));
4423 : }
4424 : }
4425 : else {
4426 0 : nchan=nChanPar();
4427 0 : if (nChanPar()<Int(chfr.nelements())) {
4428 0 : calfreq=chfr(Slice(startChan(),nChanPar()));
4429 0 : calwid=chwid(Slice(startChan(),nChanPar()));
4430 0 : calres=chres(Slice(startChan(),nChanPar()));
4431 0 : caleff=cheff(Slice(startChan(),nChanPar()));
4432 : }
4433 : else {
4434 0 : calfreq.reference(chfr);
4435 0 : calwid.reference(chwid);
4436 0 : calres.reference(chres);
4437 0 : caleff.reference(cheff);
4438 : }
4439 : }
4440 : }
4441 : else {
4442 0 : nchan=1;
4443 0 : calfreq.resize(1);
4444 0 : calwid.resize(1);
4445 0 : calres.resize(1);
4446 0 : caleff.resize(1);
4447 : // Use simple mean freq, and aggregate bandwidth
4448 0 : calfreq(0)=mean(chfr);
4449 0 : calwid(0)=sum(chwid);
4450 0 : calres(0)=sum(chres);
4451 0 : caleff(0)=sum(cheff);
4452 : }
4453 : }
4454 : // cout << "nchan=" << nchan << " calfreq.nelements() = " << calfreq.nelements() << " " << calfreq << endl;
4455 0 : if (nchan>0) {
4456 0 : ncc.spectralWindow().chanFreq().setShape(ispw,IPosition(1,nchan));
4457 : // cout << "ncc.spectralWindow().chanFreq().shape(ispw) = " << ncc.spectralWindow().chanFreq().shape(ispw) << endl;
4458 0 : ncc.spectralWindow().chanFreq().put(ispw,calfreq);
4459 0 : ncc.spectralWindow().chanWidth().put(ispw,calwid);
4460 0 : ncc.spectralWindow().resolution().put(ispw,calres); // same as chanWidth, for now
4461 0 : ncc.spectralWindow().effectiveBW().put(ispw,caleff); // same as chanWidth, for now
4462 0 : ncc.spectralWindow().numChan().put(ispw,nchan);
4463 0 : ncc.spectralWindow().totalBandwidth().put(ispw,abs(sum(calwid)));
4464 : }
4465 : else
4466 0 : ncc.spectralWindow().flagRow().put(ispw,true);
4467 : }
4468 :
4469 : // When combining in spw, further revise freq info to average over combined spws
4470 : // Only for freqDepPar()=false types, for now (nothing bandpass-like)
4471 : // NB: Currently, this will only handle a single aggregation..., e.g., not CAS-5687
4472 0 : if (combspw() && !freqDepPar()) {
4473 :
4474 : try {
4475 :
4476 0 : Matrix<Double> chanFreq,chanWidth,effectiveBW;
4477 0 : ncc.spectralWindow().chanFreq().getColumn(chanFreq,true);
4478 0 : ncc.spectralWindow().chanWidth().getColumn(chanWidth,true);
4479 0 : ncc.spectralWindow().effectiveBW().getColumn(effectiveBW,true);
4480 :
4481 : // Insist on a single channel! (NO BANDPASS-LIKE TYPES!)
4482 0 : Int nChan=chanFreq.shape()[0];
4483 0 : AlwaysAssert(nChan==1,AipsError);
4484 :
4485 0 : Vector<Bool> spwmask=(spwMap()>-1);
4486 0 : Int outSpw=Vector<Int>(spwMap()(spwmask).getCompressedArray())[0];
4487 :
4488 : // If only one chan, then the chanWidth should span the the whole spw range
4489 : // NB: this is done before the chanFreq are revised, below
4490 : // NB: Disabled for now, since centroid freq +/- wid/2 doesn't actually
4491 : // cover the input spw range, in general....more thought necessary here
4492 : // So keep the single spw width, for now, for which there remains
4493 : // a reasonable argument (the phase correction is ~appropriate over this
4494 : // limited range without further refinement...) (the width isn't used
4495 : // decisively anywhere yet, in any case)
4496 : if (false) {
4497 :
4498 : Vector<Double> f(chanFreq.row(0));
4499 : Vector<Double> chW(chanWidth.row(0));
4500 : Vector<Double> flo=f-chW/2.0;
4501 : Vector<Double> fhi=f+chW/2.0;
4502 :
4503 : if (allGT(fhi,flo))
4504 : // USB (positive result)
4505 : chW(outSpw)=max(fhi(spwmask))-min(flo(spwmask));
4506 : else
4507 : // LSB (negative result)
4508 : chW(outSpw)=min(fhi(spwmask))-max(flo(spwmask));
4509 :
4510 : }
4511 :
4512 : // Assumes single channel!
4513 0 : Vector<Double> f(chanFreq.row(0));
4514 0 : Vector<Double> ebw(effectiveBW.row(0));
4515 0 : Double meanfreq=sum(f(spwmask)*ebw(spwmask));
4516 0 : Double sumebw=sum(ebw(spwmask));
4517 0 : meanfreq/=sumebw;
4518 :
4519 0 : f(outSpw)=meanfreq;
4520 0 : ebw(outSpw)=sumebw;
4521 :
4522 : /*
4523 : cout << "spwmask = " << boolalpha << spwmask << endl;
4524 : cout << "chanFreq(:,outSpw) = " << chanFreq.column(outSpw) << endl;
4525 : cout << "chanWidth(:,outSpw) = " << chanWidth.column(outSpw) << endl;
4526 : cout << "effectiveBW(:,outSpw) = " << effectiveBW.column(outSpw) << endl;
4527 : */
4528 :
4529 :
4530 0 : ncc.spectralWindow().chanFreq().putColumn(chanFreq);
4531 0 : ncc.spectralWindow().chanWidth().putColumn(chanWidth);
4532 0 : ncc.spectralWindow().effectiveBW().putColumn(effectiveBW);
4533 : }
4534 0 : catch (...) {
4535 0 : throw(AipsError("Error calculating solution frequencies w/ combine='spw'"));
4536 : }
4537 : }
4538 :
4539 0 : }
4540 :
4541 : // File a single-channel solved solution into the multi-channel space for it
4542 0 : void SolvableVisCal::keep1(Int ichan) {
4543 0 : if (parType()==VisCalEnum::COMPLEX)
4544 0 : solveAllCPar()(Slice(),Slice(ichan,1),Slice())=solveCPar();
4545 0 : else if (parType()==VisCalEnum::REAL)
4546 0 : solveAllRPar()(Slice(),Slice(ichan,1),Slice())=solveRPar();
4547 :
4548 0 : solveAllParOK()(Slice(),Slice(ichan,1),Slice())=solveParOK();
4549 0 : solveAllParErr()(Slice(),Slice(ichan,1),Slice())=solveParErr();
4550 0 : solveAllParSNR()(Slice(),Slice(ichan,1),Slice())=solveParSNR();
4551 0 : }
4552 :
4553 0 : Bool SolvableVisCal::spwOK(Int ispw) {
4554 :
4555 0 : if (isSolved())
4556 0 : return spwOK_(ispw);
4557 :
4558 0 : if (isApplied() && ci_)
4559 : // Get it from the interpolator (w/ spwmap)
4560 0 : return spwOK_(ispw)=ci_->spwOK(ispw);
4561 : else {
4562 : // Assume ok (e.g., non-ci_ types like TOpac, GainCurve)
4563 : // TBD: be more careful by specializing this method
4564 0 : return true;
4565 : }
4566 : }
4567 :
4568 : // Is the data in this VB calibrate-able? This replaces the old spwOK and
4569 : // is more specific as regards obs, fld, intent. Used at wide scopes
4570 : // (Calibrater/VisEquation) to control entering expensive loops.
4571 : // "OK for Cal" or "Calibrate-able" here means:
4572 : // a) this SVC can actually calibrate the data within the VB because
4573 : // there are solutions explicitly available to do it (see
4574 : // SVC::calAvailable(vb) below)
4575 : // OR
4576 : // b) that this SVC is agnostic about the data within the VB according
4577 : // to arrangements made by CalLibrary specifictions and
4578 : // embodied within the CLPatchPanel (cpp_). Agnosticism is
4579 : // supported ONLY when using the CalLibrary and CLPatchPanel
4580 0 : Bool SolvableVisCal::VBOKforCalApply(vi::VisBuffer2& vb) {
4581 :
4582 : // Current spw
4583 : // TBD: Use syncMeta2?
4584 0 : const Int& ispw(vb.spectralWindows()(0));
4585 :
4586 0 : if (isSolved())
4587 0 : return spwOK_(ispw);
4588 :
4589 0 : if (isApplied()) {
4590 :
4591 0 : if (ci_)
4592 : // Get it from the old-fashioned CTPatchedInterp
4593 0 : return spwOK_(ispw)=ci_->spwOK(ispw);
4594 :
4595 0 : else if (cpp_) {
4596 : // Get it from the new CLPatchPanel, which has
4597 : // obs, fld, intent specificity, too!
4598 0 : const Int& iobs(vb.observationId()(0));
4599 0 : const Int& iscan(vb.scan()(0));
4600 0 : const Int& ifld(vb.fieldId()(0));
4601 0 : const Int& ient(vb.stateId()(0));
4602 0 : return cpp_->MSIndicesOK(iobs,iscan,ifld,ient,ispw,-1); // all ants
4603 : }
4604 : else
4605 : // Assume ok for non-interpolable types
4606 0 : return true;
4607 : }
4608 :
4609 : // Shouldn't reach here, assume true (could trigger failure elsewhere)
4610 0 : return true;
4611 :
4612 : }
4613 :
4614 : // Is calibration for the specified VB actually available?
4615 : // This returns true when condition "a" described above
4616 : // is true. If the CLPatchPanel is agnostic, this returns
4617 : // false. This is used by VisCal::correct2 control whether
4618 : // calibration update and algebraic apply can/should be done.
4619 : // In the CalLibrary context, this enables agnosticism (when
4620 : // false)
4621 : // The implementation here is almost the same as VBOKforCal,
4622 : // differing only in the call to cpp_->calAvailable.
4623 0 : Bool SolvableVisCal::calAvailable(vi::VisBuffer2& vb) {
4624 :
4625 : // Current spw
4626 : // TBD: Use syncMeta2?
4627 0 : const Int& ispw(vb.spectralWindows()(0));
4628 :
4629 0 : if (isSolved())
4630 0 : return spwOK_(ispw);
4631 :
4632 0 : if (isApplied()) {
4633 :
4634 0 : if (ci_)
4635 : // Get it from the old-fashioned CTPatchedInterp
4636 0 : return spwOK_(ispw)=ci_->spwOK(ispw);
4637 :
4638 0 : else if (cpp_) {
4639 : // Get it from the new CLPatchPanel, which has
4640 : // obs, fld, intent specificity, too!
4641 0 : const Int& iobs(vb.observationId()(0));
4642 0 : const Int& iscan(vb.scan()(0));
4643 0 : const Int& ifld(vb.fieldId()(0));
4644 0 : const Int& ient(vb.stateId()(0));
4645 0 : return cpp_->calAvailable(iobs,iscan,ifld,ient,ispw,-1); // all ants
4646 : }
4647 : else
4648 : // Assume ok for non-interpolable types
4649 0 : return true;
4650 : }
4651 :
4652 : // Shouldn't reach here, assume true (could trigger failure elsewhere)
4653 0 : return true;
4654 :
4655 : }
4656 :
4657 :
4658 :
4659 : // File a solved solution (and meta-data) into the in-memory Caltable
4660 0 : void SolvableVisCal::keepNCT() {
4661 :
4662 : // TBD: set CalTable freq info here
4663 : // if (!spwOK(currSpw()))
4664 : // setSpwFreqInCT(currSpw(),currFreq());
4665 :
4666 0 : if (prtlev()>4)
4667 0 : cout << " SVC::keepNCT" << endl;
4668 :
4669 : // Add some rows to fill
4670 : // nElem() gets it right for both baseline- and antenna-based
4671 0 : ct_->addRow(nElem());
4672 :
4673 0 : CTMainColumns ncmc(*ct_);
4674 :
4675 : // We are adding to the most-recently added rows
4676 0 : RefRows rows(ct_->nrow()-nElem(),ct_->nrow()-1,1);
4677 :
4678 : // Meta-info
4679 0 : ncmc.time().putColumnCells(rows,Vector<Double>(nElem(),refTime()));
4680 0 : ncmc.fieldId().putColumnCells(rows,Vector<Int>(nElem(),currField()));
4681 0 : ncmc.spwId().putColumnCells(rows,Vector<Int>(nElem(),currSpw()));
4682 0 : ncmc.scanNo().putColumnCells(rows,Vector<Int>(nElem(),currScan()));
4683 0 : ncmc.obsId().putColumnCells(rows,Vector<Int>(nElem(),currObs()));
4684 0 : ncmc.interval().putColumnCells(rows,Vector<Double>(nElem(),0.0));
4685 :
4686 : // Params
4687 0 : if (parType()==VisCalEnum::COMPLEX)
4688 : // Fill Complex column
4689 0 : ncmc.cparam().putColumnCells(rows,solveAllCPar());
4690 0 : else if (parType()==VisCalEnum::REAL)
4691 : // Fill Float column
4692 0 : ncmc.fparam().putColumnCells(rows,solveAllRPar());
4693 :
4694 : // Stats
4695 0 : ncmc.paramerr().putColumnCells(rows,solveAllParErr());
4696 0 : ncmc.snr().putColumnCells(rows,solveAllParSNR());
4697 0 : ncmc.flag().putColumnCells(rows,!solveAllParOK());
4698 :
4699 : // This spw now has some solutions in it
4700 0 : spwOK_(currSpw())=true;
4701 :
4702 0 : }
4703 :
4704 0 : void SolvableVisCal::globalPostSolveTinker() {
4705 :
4706 : // Make solutions phase- or amp-only, if required
4707 0 : if (apmode()!="AP") enforceAPonSoln();
4708 :
4709 : // Apply normalization
4710 0 : if (solnorm()) normalize();
4711 :
4712 0 : }
4713 :
4714 : // Divide all solutions by their amplitudes to make them "phase-only"
4715 0 : void SolvableVisCal::enforceAPonSoln() {
4716 :
4717 : // VI2: review initializatin of apmode! (and similar!)
4718 0 : if (apmode()=="") return;
4719 :
4720 : // Only if we have a CalTable, and it is not empty
4721 0 : if (ct_ && ct_->nrow()>0) {
4722 :
4723 : // TBD: trap attempts to enforceAPonSoln a caltable containing FPARAM (non-Complex)?
4724 :
4725 : logSink() << "Enforcing apmode on solutions."
4726 0 : << LogIO::POST;
4727 :
4728 : // In this generic version, one normalization factor per spw
4729 0 : Block<String> col(3);
4730 0 : col[0]="SPECTRAL_WINDOW_ID";
4731 0 : col[1]="TIME";
4732 0 : col[2]="ANTENNA1";
4733 0 : CTIter ctiter(*ct_,col);
4734 :
4735 0 : while (!ctiter.pastEnd()) {
4736 :
4737 0 : Array<Complex> par(ctiter.cparam());
4738 0 : Array<Bool> fl(ctiter.flag());
4739 0 : Array<Float> amps(amplitude(par));
4740 0 : par(amps==0.0f)=Complex(1.0);
4741 0 : par(fl)=Complex(1.0);
4742 0 : amps(amps==0.0f)=1.0f;
4743 0 : amps(fl)=1.0f;
4744 :
4745 0 : Array<Complex> cor(amps.shape());
4746 0 : if (apmode()=='P')
4747 : // we will scale solns by amp to make them phase-only
4748 0 : convertArray(cor,amps);
4749 0 : else if (apmode()=='A') {
4750 : // we will scale solns by "phase" to make them amp-only
4751 0 : cor=par;
4752 0 : cor/=amps;
4753 : }
4754 :
4755 0 : if (ntrue(amplitude(cor)==0.0f)==0)
4756 0 : par/=cor;
4757 : else
4758 0 : throw(AipsError("enforceAPonSoln divide-by-zero error."));
4759 :
4760 : // put result back
4761 0 : ctiter.setcparam(par);
4762 :
4763 : // advance iterator
4764 0 : ctiter.next();
4765 : }
4766 :
4767 :
4768 : }
4769 : else
4770 0 : throw(AipsError("Solution apmode enforcement not supported."));
4771 :
4772 : }
4773 :
4774 0 : void SolvableVisCal::normalize() {
4775 :
4776 : // Only if we have a CalTable, and it is not empty
4777 0 : if (ct_ && ct_->nrow()>0) {
4778 :
4779 : // TBD: trap attempts to normalize a caltable containing FPARAM (non-Complex)?
4780 :
4781 0 : logSink() << "Normalizing solution amplitudes per spw with " << solNorm().normtypeString()
4782 0 : << LogIO::POST;
4783 :
4784 : // In this generic version, one normalization factor per spw
4785 0 : Block<String> col(1);
4786 0 : col[0]="SPECTRAL_WINDOW_ID";
4787 0 : CTIter ctiter(*ct_,col);
4788 :
4789 0 : while (!ctiter.pastEnd()) {
4790 0 : Cube<Complex> p(ctiter.cparam());
4791 0 : Cube<Bool> fl(ctiter.flag());
4792 0 : if (nfalse(fl)>0) {
4793 0 : Complex normfactor=normSolnArray(p,!fl,false); // don't do phase
4794 0 : logSink() << " Normalization factor (" << solNorm().normtypeString() << ") for spw " << ctiter.thisSpw() << " = " << abs(normfactor)
4795 0 : << LogIO::POST;
4796 :
4797 : // record result...
4798 0 : ctiter.setcparam(p);
4799 : }
4800 0 : ctiter.next();
4801 : }
4802 :
4803 : }
4804 0 : }
4805 :
4806 0 : void SolvableVisCal::storeNCT() {
4807 :
4808 0 : if (prtlev()>3) cout << " SVC::storeNCT()" << endl;
4809 :
4810 : // Escape from attempt to write to an empty name,
4811 : // because this may delete more than one wants
4812 0 : if (calTableName().empty())
4813 0 : throw(AipsError("Empty string provided for caltable name; this is not allowed."));
4814 :
4815 : // Flag spws that didn't occur (should do for other meta-info!)
4816 0 : ct_->flagAbsentSpws();
4817 :
4818 : // If append=T and the specified table exists...
4819 0 : if (append() && Table::isReadable(calTableName())) {
4820 :
4821 : // Verify the same type
4822 0 : verifyCalTable(calTableName());
4823 :
4824 0 : logSink() << "Appending solutions to table: " << calTableName()
4825 0 : << LogIO::POST;
4826 :
4827 : // Keep the new in-memory caltable locally
4828 0 : NewCalTable *newct=ct_;
4829 0 : ct_=NULL;
4830 :
4831 : // Load the existing table (ct_)
4832 0 : loadMemCalTable(calTableName());
4833 :
4834 : // Verify that both caltables come from the same MS
4835 : try {
4836 0 : String msn0=ct_->keywordSet().asString("MSName");
4837 0 : String msn1=newct->keywordSet().asString("MSName");
4838 0 : AlwaysAssert( msn0==msn1, AipsError);
4839 : }
4840 0 : catch ( AipsError err ) {
4841 0 : delete newct; // ct_ will be deleted in dtor
4842 0 : throw(AipsError("Cannot append solutions from different MS."));
4843 : }
4844 :
4845 : // Merge spw info (carefully) from newct to ct_
4846 : try {
4847 0 : ct_->mergeSpwMetaInfo(*newct);
4848 : }
4849 0 : catch ( AipsError err ) {
4850 0 : logSink() << err.getMesg() << LogIO::SEVERE;
4851 0 : throw(AipsError("Error attempting append=T"));
4852 : }
4853 :
4854 : // copy the new onto the existing...
4855 0 : TableCopy::copyRows(*ct_,*newct,ct_->nrow(),0,newct->nrow());
4856 :
4857 : // Delete the local pointer to the new solutions
4858 : // NB: ct_ will be deleted by dtor (after writeToDisk below)
4859 0 : delete newct;
4860 :
4861 : // At this point, ct_ contains old and new solutions in memory
4862 :
4863 : }
4864 : else
4865 0 : logSink() << "Writing solutions to table: " << calTableName()
4866 0 : << LogIO::POST;
4867 :
4868 : // Write out the table to disk (regardless of what happened above)
4869 : // (this will sort)
4870 0 : ct_->writeToDisk(calTableName());
4871 :
4872 0 : }
4873 :
4874 0 : void SolvableVisCal::storeNCT(const String& table,const Bool& append) {
4875 :
4876 0 : if (prtlev()>3) cout << " SVC::store(table,append)" << endl;
4877 :
4878 : // Override tablename
4879 0 : calTableName()=table;
4880 0 : SolvableVisCal::append()=append;
4881 :
4882 : // Call conventional store
4883 0 : storeNCT();
4884 :
4885 0 : }
4886 :
4887 0 : void SolvableVisCal::loadMemCalTable(String ctname,String field) {
4888 0 : if (field.length()>0) {
4889 : // Open whole table (on disk);
4890 0 : NewCalTable wholect(NewCalTable::createCT(ctname,Table::Old,Table::Memory));
4891 0 : ct_ = new NewCalTable(wholect); // Make sure ct_ contains a real object
4892 :
4893 : // Prepare to select on it
4894 0 : CTInterface cti(wholect);
4895 0 : MSSelection mss;
4896 : // mss.reset(cti,MSSelection::PARSE_LATE,"","",field);
4897 0 : mss.setFieldExpr(field);
4898 0 : TableExprNode ten=mss.toTableExprNode(&cti);
4899 : //cout << "Selected field list: " << mss.getFieldList() << endl;
4900 :
4901 : // Apply selection to table
4902 : try {
4903 0 : getSelectedTable(*ct_,wholect,ten,"");
4904 0 : } catch (AipsError x) {
4905 0 : logSink() << x.getMesg() << LogIO::SEVERE;
4906 0 : throw(AipsError("Error selecting on caltable: "+ctname+"... "));
4907 : }
4908 :
4909 : }
4910 : else
4911 : // No selection
4912 0 : ct_ = new NewCalTable(NewCalTable::createCT(ctname,Table::Old,Table::Memory));
4913 :
4914 :
4915 :
4916 : // Fill nChanParList from the Caltable
4917 : // (this may be revised by calcPar)
4918 :
4919 : // This should not be needed anymore (and it breaks portability)
4920 : // MSSpWindowColumns spwcol(ct_->spectralWindow());
4921 : // nChanParList().assign(spwcol.numChan().getColumn());
4922 :
4923 0 : }
4924 :
4925 0 : void SolvableVisCal::stateSVC(const Bool& doVC) {
4926 :
4927 : // If requested, report VisCal state
4928 0 : if (doVC) VisCal::state();
4929 :
4930 0 : if (prtlev()>3) cout << "SVC::stateSVC():" << endl;
4931 0 : cout << boolalpha;
4932 :
4933 : // Now SVC-specific stuff:
4934 0 : cout << " isSolved() = " << isSolved() << endl;
4935 0 : cout << " calTableName() = " << calTableName() << endl;
4936 0 : cout << " calTableSelect() = " << calTableSelect() << endl;
4937 0 : cout << " apmode() = " << apmode() << endl;
4938 0 : cout << " phandonly() = " << phandonly() << endl;
4939 0 : cout << " tInterpType() = " << tInterpType() << endl;
4940 0 : cout << " fInterpType() = " << fInterpType() << endl;
4941 0 : cout << " spwMap() = " << spwMap() << endl;
4942 0 : cout << " refantmode() = " << refantmode() << endl;
4943 0 : cout << " refant() = " << refant() << endl;
4944 0 : cout << " refantlist() = " << refantlist() << endl;
4945 0 : cout << " solmode = " << solmode() << endl;
4946 0 : cout << " rmsthresh = " << rmsthresh() << endl;
4947 :
4948 0 : cout << " solveCPar().shape() = " << solveCPar().shape()
4949 0 : << " (" << solveCPar().data() << ")" << endl;
4950 0 : cout << " solveRPar().shape() = " << solveRPar().shape()
4951 0 : << " (" << solveRPar().data() << ")" << endl;
4952 0 : cout << " solveParOK().shape() = " << solveParOK().shape()
4953 0 : << " (" << solveParOK().data() << ") "
4954 0 : << " (ntrue=" << ntrue(solveParOK()) << ")" << endl;
4955 :
4956 0 : cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" << endl;
4957 :
4958 0 : }
4959 :
4960 0 : Complex SolvableVisCal::normSolnArray(Array<Complex>& sol,
4961 : const Array<Bool>& solOK,
4962 : const Bool doPhase) {
4963 :
4964 : // Only do something if 2 or more good solutions
4965 0 : Complex factor(1.0);
4966 0 : if (ntrue(solOK)>1) {
4967 :
4968 :
4969 0 : Array<Float> amp(amplitude(sol));
4970 :
4971 : // If desired, determine phase part of the normalization
4972 0 : if (doPhase) {
4973 : // Prepare to divide by amplitudes indiscriminately
4974 0 : amp(!solOK)=1.0f;
4975 0 : Array<Complex> sol1=sol/amp;
4976 0 : sol1(!solOK)=Complex(0.0);
4977 0 : factor=sum(sol1);
4978 0 : factor/=abs(factor);
4979 : }
4980 :
4981 : // Determine amplitude normalization factor
4982 0 : factor*=calcPowerNorm(amp,solOK);
4983 :
4984 : // Apply the normalization factor, if non-zero
4985 0 : if (abs(factor) > 0.0)
4986 0 : sol/=factor;
4987 :
4988 : } // ntrue > 0
4989 :
4990 : // Return the net normlization factor
4991 0 : return factor;
4992 :
4993 : }
4994 :
4995 :
4996 :
4997 0 : void SolvableVisCal::currMetaNote() {
4998 :
4999 : cout << " ("
5000 0 : << "time=" << MVTime(refTime()/C::day).string(MVTime::YMD,7)
5001 0 : << " field=" << currField()
5002 0 : << " spw=" << currSpw()
5003 0 : << " chan=" << focusChan()
5004 0 : << ")"
5005 0 : << endl;
5006 :
5007 0 : }
5008 :
5009 0 : void SolvableVisCal::initSVC() {
5010 :
5011 0 : if (prtlev()>2) cout << " SVC::initSVC()" << endl;
5012 :
5013 0 : for (Int ispw=0;ispw<nSpw(); ispw++) {
5014 :
5015 : // TBD: Would like to make this parType()-dependent,
5016 : // but parType() isn't initialized yet...
5017 :
5018 : // if (parType()==VisCalEnum::COMPLEX) {
5019 0 : solveCPar_[ispw] = new Cube<Complex>();
5020 0 : solveAllCPar_[ispw] = new Cube<Complex>();
5021 : // }
5022 : // else if (parType()==VisCalEnum::REAL) {
5023 0 : solveRPar_[ispw] = new Cube<Float>();
5024 0 : solveAllRPar_[ispw] = new Cube<Float>();
5025 : // }
5026 0 : solveParOK_[ispw] = new Cube<Bool>();
5027 0 : solveParErr_[ispw] = new Cube<Float>();
5028 0 : solveParSNR_[ispw] = new Cube<Float>();
5029 0 : solveAllParOK_[ispw] = new Cube<Bool>();
5030 0 : solveAllParErr_[ispw] = new Cube<Float>();
5031 0 : solveAllParSNR_[ispw] = new Cube<Float>();
5032 : }
5033 :
5034 0 : parType_=VisCalEnum::COMPLEX;
5035 :
5036 0 : }
5037 :
5038 0 : void SolvableVisCal::deleteSVC() {
5039 :
5040 0 : if (prtlev()>2) cout << " SVC::deleteSVC()" << endl;
5041 :
5042 0 : for (Int ispw=0; ispw<nSpw(); ispw++) {
5043 0 : if (solveCPar_[ispw]) delete solveCPar_[ispw];
5044 0 : if (solveRPar_[ispw]) delete solveRPar_[ispw];
5045 0 : if (solveParOK_[ispw]) delete solveParOK_[ispw];
5046 0 : if (solveParErr_[ispw]) delete solveParErr_[ispw];
5047 0 : if (solveParSNR_[ispw]) delete solveParSNR_[ispw];
5048 0 : if (solveAllCPar_[ispw]) delete solveAllCPar_[ispw];
5049 0 : if (solveAllRPar_[ispw]) delete solveAllRPar_[ispw];
5050 0 : if (solveAllParOK_[ispw]) delete solveAllParOK_[ispw];
5051 0 : if (solveAllParErr_[ispw]) delete solveAllParErr_[ispw];
5052 0 : if (solveAllParSNR_[ispw]) delete solveAllParSNR_[ispw];
5053 : }
5054 0 : solveCPar_=NULL;
5055 0 : solveRPar_=NULL;
5056 0 : solveParOK_=NULL;
5057 0 : solveParErr_=NULL;
5058 0 : solveParSNR_=NULL;
5059 0 : solveAllCPar_=NULL;
5060 0 : solveAllRPar_=NULL;
5061 0 : solveAllParOK_=NULL;
5062 0 : solveAllParErr_=NULL;
5063 0 : solveAllParSNR_=NULL;
5064 0 : }
5065 :
5066 0 : void SolvableVisCal::verifyCalTable(const String& caltablename) {
5067 :
5068 : // Call external method to get type (will throw if bad table)
5069 0 : String calType=calTableType(caltablename);
5070 :
5071 : // Check if proper Calibration type...
5072 0 : if (calType!=typeName()) {
5073 0 : ostringstream o;
5074 0 : o << "Table " << caltablename
5075 0 : << " has wrong Calibration type: " << calType
5076 0 : << " (expected: " << typeName() << ")";
5077 0 : throw(AipsError(String(o)));
5078 : }
5079 0 : }
5080 :
5081 0 : void SolvableVisCal::applyChanMask(VisBuffer& vb) {
5082 :
5083 0 : if (chanmask_) {
5084 :
5085 : // A reference to de-referenced pointer
5086 0 : PtrBlock<Vector<Bool>*>& chmask(*chanmask_);
5087 :
5088 0 : Int spw=vb.spectralWindow();
5089 0 : Int chan0=vb.channel()(0);
5090 0 : Int nchan=vb.nChannel();
5091 0 : if (chmask.nelements()==uInt(nSpw()) &&
5092 0 : chmask[spw] &&
5093 0 : sum((*chmask[spw])(Slice(chan0,nchan))) > 0 ) {
5094 : // There are some channels to mask...
5095 0 : Vector<Bool> fr(vb.flagRow());
5096 0 : Matrix<Bool> f(vb.flag());
5097 0 : Vector<Bool> fc;
5098 0 : Vector<Bool> chm((*(*chanmask_)[spw])(Slice(chan0,nchan)));
5099 0 : for (Int irow=0;irow<vb.nRow();++irow)
5100 0 : if (!fr(irow)) {
5101 0 : fc.reference(f.column(irow));
5102 0 : fc = fc||chm;
5103 :
5104 : // cout << irow << ": ";
5105 : // for (Int j=0;j<nchan;++j) cout << fc(j);
5106 : // cout << endl;
5107 :
5108 : }
5109 : }
5110 : }
5111 :
5112 0 : }
5113 : //
5114 : //-----------------------------------------------------------------------
5115 : //
5116 0 : void SolvableVisCal::printActivity(const Int nSlots, const Int slotNo,
5117 : const Int fieldId, const Int spw,
5118 : const Int nSolutions)
5119 : {
5120 : Int nMesg;
5121 :
5122 : // nSlots = rcs().nTime(spw);
5123 :
5124 0 : Double timeTaken = timer_p.all();
5125 0 : if (maxTimePerSolution_p < timeTaken) maxTimePerSolution_p = timeTaken;
5126 0 : if (minTimePerSolution_p > timeTaken) minTimePerSolution_p = timeTaken;
5127 0 : avgTimePerSolution_p += timeTaken;
5128 0 : Double avgT = avgTimePerSolution_p/(nSolutions>0?nSolutions:1);
5129 : //
5130 : // Boost the no. of messages printed if the next message, based on
5131 : // the average time per solution, is going to appear after a time
5132 : // longer than your patience would permit! The limit of
5133 : // patience defaults to 1h.
5134 : //
5135 0 : Float boost = userPrintActivityInterval_p/avgT;
5136 0 : boost = userPrintActivityInterval_p/avgT;
5137 0 : boost = (boost < 1.0)? 1.0 : nSlots*userPrintActivityFraction_p;
5138 0 : nMesg = (Int)boost;
5139 :
5140 0 : Int tmp=abs(nSlots-slotNo); Bool print;
5141 0 : print = false;
5142 0 : if (nMesg <= 0) print=false;
5143 0 : else if ((slotNo == 0) || (slotNo == nSlots-1)) print=true;
5144 0 : else if ((tmp > 0 ) && ((slotNo+1)%nMesg ==0)) print=true;
5145 0 : else print=false;
5146 :
5147 0 : if (print)
5148 : {
5149 0 : Int f = (Int)(100*(slotNo+1)/(nSlots>0?nSlots:1));
5150 : logSink()<< LogIO::NORMAL
5151 : << "Spw=" << spw << " slot=" << slotNo << "/" << nSlots
5152 : << " field=" << fieldId << ". Done " << f << "%"
5153 : << " Time taken per solution (max/min/avg): "
5154 : << maxTimePerSolution_p << "/"
5155 0 : << (minTimePerSolution_p<0?1:minTimePerSolution_p) << "/"
5156 0 : << avgT << " sec" << LogIO::POST;
5157 : }
5158 0 : }
5159 :
5160 : // **********************************************************
5161 : // SolvableVisMueller Implementations
5162 : //
5163 :
5164 :
5165 0 : SolvableVisMueller::SolvableVisMueller(VisSet& vs) :
5166 : VisCal(vs),
5167 : VisMueller(vs),
5168 : SolvableVisCal(vs),
5169 : dM_(NULL),
5170 : diffMElem_(),
5171 0 : DMValid_(false)
5172 : {
5173 0 : if (prtlev()>2) cout << "SVM::SVM(vs)" << endl;
5174 0 : }
5175 :
5176 0 : SolvableVisMueller::SolvableVisMueller(String msname,Int MSnAnt,Int MSnSpw) :
5177 : VisCal(msname,MSnAnt,MSnSpw),
5178 : VisMueller(msname,MSnAnt,MSnSpw),
5179 : SolvableVisCal(msname,MSnAnt,MSnSpw),
5180 : dM_(NULL),
5181 : diffMElem_(),
5182 0 : DMValid_(false)
5183 : {
5184 0 : if (prtlev()>2) cout << "SVM::SVM(msname,MSnAnt,MSnSpw)" << endl;
5185 0 : }
5186 :
5187 0 : SolvableVisMueller::SolvableVisMueller(const MSMetaInfoForCal& msmc) :
5188 : VisCal(msmc),
5189 : VisMueller(msmc),
5190 : SolvableVisCal(msmc),
5191 : dM_(NULL),
5192 : diffMElem_(),
5193 0 : DMValid_(False)
5194 : {
5195 0 : if (prtlev()>2) cout << "SVM::SVM(msmc)" << endl;
5196 0 : }
5197 :
5198 0 : SolvableVisMueller::SolvableVisMueller(const Int& nAnt) :
5199 : VisCal(nAnt),
5200 : VisMueller(nAnt),
5201 : SolvableVisCal(nAnt),
5202 : dM_(NULL),
5203 : diffMElem_(),
5204 0 : DMValid_(false)
5205 : {
5206 0 : if (prtlev()>2) cout << "SVM::SVM(i,j,k)" << endl;
5207 0 : }
5208 :
5209 0 : SolvableVisMueller::~SolvableVisMueller() {
5210 :
5211 0 : if (prtlev()>2) cout << "SVM::~SVM()" << endl;
5212 :
5213 0 : }
5214 :
5215 : // Setup solvePar shape (Mueller version)
5216 0 : void SolvableVisMueller::initSolvePar() {
5217 :
5218 : // TBD: NCT: attention to solveAllPar
5219 :
5220 0 : if (prtlev()>3) cout << " SVM::initSolvePar()" << endl;
5221 :
5222 0 : for (Int ispw=0;ispw<nSpw();++ispw) {
5223 :
5224 0 : currSpw()=ispw;
5225 :
5226 0 : switch(parType()) {
5227 0 : case VisCalEnum::COMPLEX: {
5228 0 : solveAllCPar().resize(nPar(),nChanPar(),nBln());
5229 0 : solveAllCPar()=Complex(1.0);
5230 0 : solveCPar().reference(solveAllCPar());
5231 0 : break;
5232 : }
5233 0 : case VisCalEnum::REAL: {
5234 0 : solveAllRPar().resize(nPar(),nChanPar(),nBln());
5235 0 : solveAllRPar()=0.0;
5236 0 : solveRPar().reference(solveAllRPar());
5237 0 : break;
5238 : }
5239 0 : case VisCalEnum::COMPLEXREAL: {
5240 : throw(AipsError("Internal error(Calibrater Module): Unsupported parameter type "
5241 0 : "COMPLEXREAL found in SolvableVisMueller::initSolvePar()"));
5242 : break;
5243 : }
5244 : }//switch
5245 :
5246 0 : solveAllParOK().resize(nPar(),nChanPar(),nBln());
5247 0 : solveAllParErr().resize(nPar(),nChanPar(),nBln());
5248 0 : solveAllParSNR().resize(nPar(),nChanPar(),nBln());
5249 0 : solveAllParOK()=true;
5250 0 : solveAllParErr()=0.0;
5251 0 : solveAllParSNR()=0.0;
5252 0 : solveParOK().reference(solveAllParOK());
5253 0 : solveParErr().reference(solveAllParErr());
5254 0 : solveParSNR().reference(solveAllParSNR());
5255 : }
5256 0 : currSpw()=0;
5257 0 : }
5258 :
5259 0 : void SolvableVisMueller::syncDiffMat() {
5260 :
5261 0 : if (prtlev()>5) cout << " SVM::syncDiffMat()"
5262 0 : << " (DMValid()=" << DMValid() << ")" << endl;
5263 :
5264 : // Sync the diff'd Mueller matrices
5265 0 : if (!DMValid()) syncDiffMueller();
5266 :
5267 0 : }
5268 :
5269 0 : void SolvableVisMueller::syncDiffMueller() {
5270 :
5271 0 : if (prtlev()>6) cout << " SVM::syncDiffMueller()" << endl;
5272 :
5273 : // TBD: validateDM() for trivialMuellerElem()=true??
5274 : // (cf. where does invalidateDM() occur?)
5275 :
5276 0 : if (trivialDM())
5277 : // Ensure trivial matrices ready
5278 0 : initTrivDM();
5279 : else {
5280 0 : diffMElem().resize(IPosition(4,muellerNPar(muellerType()),nPar(),nChanMat(),nCalMat()));
5281 0 : diffMElem().unique();
5282 0 : invalidateDM();
5283 :
5284 : // Calculate for all blns/chans
5285 0 : calcAllDiffMueller();
5286 :
5287 : }
5288 :
5289 : // Ensure diff'd Mueller matrix renders are OK
5290 0 : createDiffMueller();
5291 :
5292 : // diff'd Mueller matrices now valid
5293 0 : validateDM();
5294 :
5295 0 : }
5296 :
5297 0 : void SolvableVisMueller::calcAllDiffMueller() {
5298 :
5299 0 : if (prtlev()>6) cout << " SVM::calcAllDiffMueller" << endl;
5300 :
5301 : // Should handle OK flags in this method, and only
5302 : // do calc if OK
5303 :
5304 : // Sanity check on parameter channel axis
5305 0 : AlwaysAssert((solveCPar().shape()(1)==1),AipsError);
5306 :
5307 : // Referencing arrays, per baseline
5308 0 : Matrix<Complex> oneDM; // (nElem,nPar)
5309 0 : Vector<Complex> onePar; // (nPar)
5310 :
5311 0 : ArrayIterator<Complex> dMiter(diffMElem(),2);
5312 0 : ArrayIterator<Complex> Piter(solveCPar(),1);
5313 :
5314 0 : for (Int ibln=0; ibln<nCalMat(); ++ibln) {
5315 :
5316 : // Solving parameters are NEVER channel-dependent
5317 : // (even if data & matrices are)
5318 0 : onePar.reference(Piter.array());
5319 :
5320 0 : for (Int ich=0; ich<nChanMat(); ich++) {
5321 :
5322 0 : oneDM.reference(dMiter.array());
5323 :
5324 : // Calculate the DM matrices for each par on this bln/chan
5325 0 : calcOneDiffMueller(oneDM,onePar);
5326 :
5327 : // Advance iterators
5328 0 : dMiter.next();
5329 :
5330 : }
5331 0 : Piter.next();
5332 : }
5333 :
5334 0 : }
5335 :
5336 0 : void SolvableVisMueller::calcOneDiffMueller(Matrix<Complex>&,
5337 : const Vector<Complex>&) {
5338 :
5339 0 : if (prtlev()>10) cout << " SVM::calcOneDiffMueller()" << endl;
5340 :
5341 : // If Mueller matrix is trivial, shouldn't get here
5342 0 : if (trivialMuellerElem())
5343 0 : throw(AipsError("Trivial Mueller Matrix logic error."));
5344 :
5345 : // Otherwise, this method apparently hasn't been specialized, as required
5346 : else
5347 0 : throw(AipsError("Unknown non-trivial dMueller-from-parameter calculation requested."));
5348 :
5349 : }
5350 :
5351 0 : void SolvableVisMueller::createDiffMueller() {
5352 :
5353 0 : if (prtlev()>6) cout << " SVM::createDiffMueller()" << endl;
5354 :
5355 0 : Mueller::MuellerType mtype(muellerType());
5356 :
5357 : // Delete if wrong type
5358 0 : if (dM_ && dM().type() != mtype) delete dM_;
5359 :
5360 : // If needed, construct the correct diff Mueller
5361 0 : if (!dM_) dM_ = casa::createMueller(mtype);
5362 :
5363 0 : }
5364 :
5365 0 : void SolvableVisMueller::initTrivDM() {
5366 :
5367 0 : if (prtlev()>7) cout << " SVM::initTrivDM()" << endl;
5368 :
5369 : // If DM matrice not trivial, shouldn't get here
5370 0 : if (!trivialDM())
5371 0 : throw(AipsError("Trivial Mueller Matrix logic error."));
5372 :
5373 : // Otherwise, this method apparently hasn't been specialized, as required
5374 : else
5375 0 : throw(AipsError("Unknown trivial dM initialization requested."));
5376 :
5377 : }
5378 :
5379 : // File a solved solution (and meta-data) into the in-memory Caltable
5380 0 : void SolvableVisMueller::keepNCT() {
5381 :
5382 : // Call parent to do general stuff
5383 : // This adds nElem() rows
5384 0 : SolvableVisCal::keepNCT();
5385 :
5386 0 : if (prtlev()>4)
5387 0 : cout << " SVM::keepNCT" << endl;
5388 :
5389 : // Form antenna pairs
5390 0 : Vector<Int> a1(nElem()),a2(nElem());
5391 0 : Int k=0;
5392 0 : for (Int i=0;i<nAnt();++i)
5393 0 : for (Int j=i;j<nAnt();++j) {
5394 0 : a1(k)=i;
5395 0 : a2(k)=j;
5396 0 : ++k;
5397 : }
5398 :
5399 : // We are adding to the most-recently added rows
5400 0 : RefRows rows(ct_->nrow()-nElem(),ct_->nrow()-1,1);
5401 :
5402 : // Write to table
5403 0 : CTMainColumns ncmc(*ct_);
5404 0 : ncmc.antenna1().putColumnCells(rows,a1);
5405 0 : ncmc.antenna2().putColumnCells(rows,a2);
5406 :
5407 0 : }
5408 :
5409 :
5410 0 : void SolvableVisMueller::stateSVM(const Bool& doVC) {
5411 :
5412 : // If requested, report VisCal state
5413 0 : if (doVC) VisMueller::state();
5414 :
5415 : // Get parent's state (w/out VC):
5416 0 : SolvableVisCal::stateSVC(false);
5417 :
5418 0 : if (applyByMueller()) {
5419 0 : if (prtlev()>3) cout << "SVM::stateSVM()" << endl;
5420 0 : cout << boolalpha;
5421 :
5422 : // Now SVM-specific stuff:
5423 0 : cout << "DMValid() = " << DMValid() << endl;
5424 0 : cout << "diffMElem().shape() = " << diffMElem().shape()
5425 0 : << " (" << diffMElem().data() << ")" << endl;
5426 :
5427 0 : cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" << endl;
5428 : }
5429 0 : }
5430 :
5431 0 : Float SolvableVisMueller::calcPowerNorm(Array<Float>& amp, const Array<Bool>& ok) {
5432 :
5433 : // SVM version assumes amp already in power units
5434 0 : Array<Float> a2;
5435 0 : a2.assign(amp);
5436 0 : a2(!ok)=0.0; // zero flagged samples
5437 :
5438 0 : Float norm(1.0);
5439 0 : switch (solNorm().normtype()) {
5440 0 : case SolNorm::MEAN: {
5441 0 : Float n=Float(ntrue(ok));
5442 0 : if (n>0.0)
5443 0 : norm=sum(a2)/n;
5444 0 : break;
5445 : }
5446 0 : case SolNorm::MEDIAN: {
5447 0 : MaskedArray<Float> a2masked(a2,ok);
5448 0 : norm=median(a2masked,false,true); // unsorted, do mean when even
5449 0 : break;
5450 : }
5451 0 : default:
5452 0 : throw(AipsError("Proper normalization type not specified."));
5453 : break;
5454 : }
5455 0 : return norm;
5456 : }
5457 :
5458 :
5459 : // **********************************************************
5460 : // SolvableVisJones Implementations
5461 : //
5462 :
5463 :
5464 0 : SolvableVisJones::SolvableVisJones(VisSet& vs) :
5465 : VisCal(vs), // virtual base
5466 : VisMueller(vs), // virtual base
5467 : SolvableVisMueller(vs), // immediate parent
5468 : VisJones(vs), // immediate parent
5469 : dJ1_(NULL), // data...
5470 : dJ2_(NULL),
5471 : diffJElem_(),
5472 0 : DJValid_(false)
5473 : {
5474 0 : if (prtlev()>2) cout << "SVJ::SVJ(vs)" << endl;
5475 0 : }
5476 :
5477 0 : SolvableVisJones::SolvableVisJones(String msname,Int MSnAnt,Int MSnSpw) :
5478 : VisCal(msname,MSnAnt,MSnSpw), // virtual base
5479 : VisMueller(msname,MSnAnt,MSnSpw), // virtual base
5480 : SolvableVisMueller(msname,MSnAnt,MSnSpw), // immediate parent
5481 : VisJones(msname,MSnAnt,MSnSpw), // immediate parent
5482 : dJ1_(NULL), // data...
5483 : dJ2_(NULL),
5484 : diffJElem_(),
5485 0 : DJValid_(false)
5486 : {
5487 0 : if (prtlev()>2) cout << "SVJ::SVJ(msname,MSnAnt,MSnSpw)" << endl;
5488 0 : }
5489 :
5490 0 : SolvableVisJones::SolvableVisJones(const MSMetaInfoForCal& msmc) :
5491 : VisCal(msmc), // virtual base
5492 : VisMueller(msmc), // virtual base
5493 : SolvableVisMueller(msmc), // immediate parent
5494 : VisJones(msmc), // immediate parent
5495 : dJ1_(NULL), // data...
5496 : dJ2_(NULL),
5497 : diffJElem_(),
5498 0 : DJValid_(False)
5499 : {
5500 0 : if (prtlev()>2) cout << "SVJ::SVJ(msmc)" << endl;
5501 0 : }
5502 :
5503 :
5504 0 : SolvableVisJones::SolvableVisJones(const Int& nAnt) :
5505 : VisCal(nAnt), // virtual base
5506 : VisMueller(nAnt), // virtual base
5507 : SolvableVisMueller(nAnt), // immediate parent
5508 : VisJones(nAnt), // immediate parent
5509 : dJ1_(NULL), // data...
5510 : dJ2_(NULL),
5511 : diffJElem_(),
5512 0 : DJValid_(false)
5513 : {
5514 0 : if (prtlev()>2) cout << "SVJ::SVJ(i,j,k)" << endl;
5515 0 : }
5516 :
5517 0 : SolvableVisJones::~SolvableVisJones() {
5518 :
5519 0 : if (prtlev()>2) cout << "SVJ::~SVJ()" << endl;
5520 0 : if (dJ1_)
5521 0 : delete dJ1_;
5522 0 : if (dJ2_)
5523 0 : delete dJ2_;
5524 0 : }
5525 :
5526 0 : void SolvableVisJones::reReference() {
5527 :
5528 : // TBD: Handle single-poln referencing
5529 : // TBD: Handle missing refant
5530 :
5531 : // Generic version for trivial types
5532 0 : if (trivialJonesElem()) {
5533 :
5534 : // Determine multiplicative complex phase
5535 0 : Matrix<Complex> refgain;
5536 0 : refgain=solveCPar().xyPlane(refant());
5537 :
5538 : // cout << "refgain add: " << refgain.data() << " " << solveCPar().xyPlane(refant()).data() << endl;
5539 :
5540 0 : Float amp(1.0);
5541 0 : Complex* rg=refgain.data();
5542 : // TBD: clean this up: there is only 1 solvePar chan!
5543 : // for (Int ich=0;ich<nChanPar();++ich) {
5544 0 : for (Int ip=0;ip<nPar();++ip,++rg) {
5545 0 : amp=abs(*rg);
5546 0 : if (amp>0.0) {
5547 0 : *rg/=amp;
5548 0 : *rg=conj(*rg);
5549 : }
5550 : else
5551 0 : *rg=Complex(1.0);
5552 : }
5553 : // }
5554 :
5555 : // cout << "amp(refgain) = " << amplitude(refgain) << endl;
5556 :
5557 :
5558 : // Apply complex phase to each ant
5559 0 : Matrix<Complex> antgain;
5560 0 : for (Int ia=0;ia<nAnt();++ia) {
5561 0 : antgain.reference(solveCPar().xyPlane(ia));
5562 0 : antgain*=refgain;
5563 : }
5564 : }
5565 : else
5566 0 : throw(AipsError("Attempt to reference non-trivial calibration type."));
5567 :
5568 :
5569 0 : }
5570 :
5571 :
5572 0 : void SolvableVisJones::differentiate(CalVisBuffer& cvb) {
5573 :
5574 0 : if (prtlev()>3) cout << " SVJ::differentiate(CVB)" << endl;
5575 :
5576 : // NB: For freqDepPar()=true, the data and solutions are
5577 : // multi-channel, but nChanMat()=1 because we only
5578 : // consider one channel at a time. In this case,
5579 : // focusChan is the specific channel under consideration.
5580 : // Otherwise, we will use all channels in the vb
5581 : // simultaneously
5582 :
5583 : // Some vb shape info
5584 0 : Int& nRow(cvb.nRow());
5585 0 : Int& nCorr(cvb.nCorr());
5586 :
5587 : // Size (diff)residuals workspace in the CVB
5588 0 : cvb.setFocusChan(focusChan());
5589 0 : cvb.sizeResiduals(nPar(),2); // 2 sets of nPar() derivatives per baseline
5590 :
5591 : // Copy in-focus model to residual workspace
5592 0 : cvb.initResidWithModel();
5593 :
5594 :
5595 : // References to workspaces
5596 0 : Cube<Complex>& Vout(cvb.residuals());
5597 0 : Array<Complex>& dVout(cvb.diffResiduals());
5598 0 : Matrix<Bool>& Vflg(cvb.residFlag());
5599 :
5600 : // "Apply" the current Q,U or X estimates to the crosshand model
5601 0 : if (solvePol()>0) {
5602 0 : Complex pol(1.0);
5603 :
5604 0 : if (solvePol()==2) // pol = Q+iU
5605 0 : pol=Complex(real(srcPolPar()(0)),real(srcPolPar()(1)));
5606 0 : else if (solvePol()==1) // pol = exp(iX)
5607 0 : pol=exp(Complex(0.0,real(srcPolPar()(0))));
5608 :
5609 0 : IPosition blc(3,1,0,0), trc(3,1,nChanMat()-1,nRow-1);
5610 0 : Array<Complex> RL(Vout(blc,trc));
5611 0 : RL*=pol;
5612 0 : blc(0)=trc(0)=2;
5613 0 : Array<Complex> LR(Vout(blc,trc));
5614 0 : LR*=conj(pol);
5615 : }
5616 :
5617 : // Visibility vector renderers
5618 0 : VisVector::VisType vt(visType(nCorr));
5619 0 : VisVector cVm(vt); // The model data corrupted by trial solution
5620 0 : VisVector dV1(vt); // The deriv of V wrt pars of 1st ant in bln
5621 0 : VisVector dV2(vt); // The deriv of V wrt pars of 2nd ant in bln
5622 :
5623 : // Temporary non-iterating VisVectors to hold partial applies
5624 0 : VisVector J1V(vt,true);
5625 0 : VisVector VJ2(vt,true);
5626 :
5627 : // Starting synchronization for output visibility data
5628 0 : cVm.sync(Vout(0,0,0));
5629 0 : dV1.sync(dVout(IPosition(5,0,0,0,0,0)));
5630 0 : dV2.sync(dVout(IPosition(5,0,0,0,0,1)));
5631 :
5632 : // Synchronize current calibration pars/matrices
5633 0 : syncSolveCal();
5634 :
5635 : // Nominal synchronization of dJs
5636 0 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,0)));
5637 0 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,0)));
5638 :
5639 : // Inform Jones matrices if data is scalar
5640 0 : Bool scalar(vt==VisVector::One);
5641 0 : J1().setScalarData(scalar);
5642 0 : J2().setScalarData(scalar);
5643 0 : dJ1().setScalarData(scalar);
5644 0 : dJ2().setScalarData(scalar);
5645 :
5646 : // VisBuffer indices
5647 0 : Double* time= cvb.time().data();
5648 0 : Int* a1= cvb.antenna1().data();
5649 0 : Int* a2= cvb.antenna2().data();
5650 0 : Bool* flagR= cvb.flagRow().data();
5651 0 : Bool* flag= Vflg.data(); // via local reference
5652 :
5653 : // TBD: set weights according to flags??
5654 :
5655 : // iterate rows
5656 0 : for (Int irow=0; irow<nRow; irow++,flagR++,a1++,a2++,time++) {
5657 :
5658 : // Avoid ACs
5659 0 : if (*a1==*a2) *flagR=true;
5660 :
5661 0 : if (!*flagR) { // if this row unflagged
5662 :
5663 : // Re-update matrices if time changes
5664 0 : if (timeDepMat() && *time != lastTime()) {
5665 0 : currTime()=*time;
5666 0 : invalidateDiffCalMat();
5667 0 : syncCalMat();
5668 0 : syncDiffMat();
5669 0 : lastTime()=currTime();
5670 : }
5671 :
5672 : // Synchronize Jones renderers for the ants on this baseline
5673 0 : J1().sync(currJElem()(0,0,*a1),currJElemOK()(0,0,*a1));
5674 0 : J2().sync(currJElem()(0,0,*a2),currJElemOK()(0,0,*a2));
5675 :
5676 : // Synchronize differentiated Jones renderers for this baseline
5677 0 : if (trivialDJ()) {
5678 0 : dJ1().origin();
5679 0 : dJ2().origin();
5680 : } else {
5681 0 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,*a1)));
5682 0 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,*a2)));
5683 : }
5684 :
5685 : // Assumes all iterating quantities have nChanMat() channelization
5686 0 : for (Int ich=0; ich<nChanMat();ich++,flag++,
5687 0 : cVm++, J1()++, J2()++) {
5688 :
5689 : // if channel unflagged an cal ok
5690 : // if (!*flag && (*J1Ok && *J2Ok) ) {
5691 0 : if (!*flag) {
5692 :
5693 : // Partial applies for repeated use below
5694 0 : VJ2=cVm;
5695 0 : J2().applyLeft(VJ2,*flag); // VJ2 = Vm*J2, used below
5696 :
5697 0 : J1().applyRight(cVm,*flag);
5698 0 : J1V=cVm; // J1V = J1*Vm, used below
5699 :
5700 : // Finish trial corruption
5701 0 : J2().applyLeft(cVm,*flag); // cVm = (J1*Vm)*J2
5702 :
5703 : }
5704 :
5705 : // Only continue with diff-ing, if we aren't flagged yet
5706 0 : if (!*flag) {
5707 :
5708 : // Differentiation per par
5709 0 : for (Int ip=0;ip<nPar();ip++,
5710 0 : dV1++,dJ1()++,
5711 0 : dV2++,dJ2()++) {
5712 :
5713 0 : dV1=VJ2;
5714 0 : dJ1().applyRight(dV1); // dV1 = dJ1(ip)*(Vm*J2)
5715 :
5716 0 : dV2=J1V;
5717 0 : dJ2().applyLeft(dV2); // dV2 = (J1*Vm)*dJ2(ip)
5718 : }
5719 :
5720 : } // (!*flag)
5721 : else {
5722 : // set trial corruption to zero
5723 0 : cVm.zero();
5724 :
5725 : // Advance all par-dep pointers over flagged channel
5726 0 : dV1.advance(nPar());
5727 0 : dV2.advance(nPar());
5728 0 : dJ1().advance(nPar());
5729 0 : dJ2().advance(nPar());
5730 : }
5731 :
5732 : } // chn
5733 :
5734 : } // !*flagR
5735 : else {
5736 : // Must advance all chan-, par-dep pointers over flagged row
5737 0 : flag+=nChanMat();
5738 0 : cVm.advance(nChanMat());
5739 0 : J1().advance(nChanMat());
5740 0 : J2().advance(nChanMat());
5741 0 : Int chpar(nChanMat()*nPar());
5742 0 : dV1.advance(chpar);
5743 0 : dV2.advance(chpar);
5744 0 : dJ1().advance(chpar);
5745 0 : dJ2().advance(chpar);
5746 : }
5747 : }
5748 :
5749 : // Subtract the obs'd data from the trial-corrupted model
5750 : // to form residuals
5751 0 : cvb.finalizeResiduals();
5752 :
5753 0 : }
5754 :
5755 0 : void SolvableVisJones::differentiate(SolveDataBuffer& sdb) { // VI2
5756 :
5757 0 : if (prtlev()>3) cout << " SVJ::differentiate(SDB)" << endl;
5758 :
5759 : // NB: For freqDepPar()=True, the data and solutions are
5760 : // multi-channel, but nChanMat()=1 because we only
5761 : // consider one channel at a time. In this case,
5762 : // focusChan is the specific channel under consideration.
5763 : // Otherwise, we will use all channels in the vb
5764 : // simultaneously
5765 :
5766 : // Some vb shape info
5767 0 : const Int& nRow(sdb.nRows());
5768 0 : const Int& nCorr(sdb.nCorrelations());
5769 :
5770 : // Size (diff)residuals workspace in the CVB
5771 0 : sdb.setFocusChan(focusChan());
5772 0 : sdb.sizeResiduals(nPar(),2); // 2 sets of nPar() derivatives per baseline
5773 :
5774 : // Copy in-focus model to residual workspace
5775 0 : sdb.initResidWithModel();
5776 :
5777 : // References to workspaces
5778 0 : Cube<Complex>& Vout(sdb.residuals());
5779 0 : Array<Complex>& dVout(sdb.diffResiduals());
5780 :
5781 : // "Apply" the current Q,U or X estimates to the crosshand model
5782 : // NB: This is circular-basis specific!!
5783 :
5784 : /* 2016Nov29 (gmoellen): MOVED TO DJones::guessPar(SDBList)
5785 :
5786 : if (solvePol()>0) {
5787 : Complex pol(1.0);
5788 :
5789 : if (solvePol()==2) // pol = Q+iU
5790 : pol=Complex(real(srcPolPar()(0)),real(srcPolPar()(1)));
5791 : else if (solvePol()==1) // pol = exp(iX)
5792 : pol=exp(Complex(0.0,real(srcPolPar()(0))));
5793 :
5794 : IPosition blc(3,1,0,0), trc(3,1,nChanMat()-1,nRow-1);
5795 : Array<Complex> RL(Vout(blc,trc));
5796 : RL*=pol;
5797 : blc(0)=trc(0)=2;
5798 : Array<Complex> LR(Vout(blc,trc));
5799 : LR*=conj(pol);
5800 : }
5801 : */
5802 :
5803 :
5804 : // Visibility vector renderers
5805 0 : VisVector::VisType vt(visType(nCorr));
5806 0 : VisVector cVm(vt); // The model data corrupted by trial solution
5807 0 : VisVector dV1(vt); // The deriv of V wrt pars of 1st ant in bln
5808 0 : VisVector dV2(vt); // The deriv of V wrt pars of 2nd ant in bln
5809 :
5810 : // Temporary non-iterating VisVectors to hold partial applies
5811 0 : VisVector J1V(vt,True);
5812 0 : VisVector VJ2(vt,True);
5813 :
5814 : // Starting synchronization for output visibility data
5815 0 : cVm.sync(Vout(0,0,0));
5816 0 : dV1.sync(dVout(IPosition(5,0,0,0,0,0)));
5817 0 : dV2.sync(dVout(IPosition(5,0,0,0,0,1)));
5818 :
5819 : // Synchronize current calibration pars/matrices
5820 0 : syncSolveCal();
5821 :
5822 : // Nominal synchronization of dJs
5823 0 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,0)));
5824 0 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,0)));
5825 :
5826 : // Inform Jones matrices if data is scalar
5827 0 : Bool scalar(vt==VisVector::One);
5828 0 : J1().setScalarData(scalar);
5829 0 : J2().setScalarData(scalar);
5830 0 : dJ1().setScalarData(scalar);
5831 0 : dJ2().setScalarData(scalar);
5832 :
5833 : // VisBuffer indices
5834 0 : const Double* time= sdb.time().data();
5835 0 : const Int* a1= sdb.antenna1().data();
5836 0 : const Int* a2= sdb.antenna2().data();
5837 0 : const Bool* flagR= sdb.flagRow().data();
5838 :
5839 : // TBD: set weights according to flags??
5840 :
5841 : // iterate rows
5842 0 : for (Int irow=0; irow<nRow; irow++,flagR++,a1++,a2++,time++) {
5843 :
5844 : // Avoid ACs and flagged rows
5845 0 : if (*a1!=*a2 && !*flagR) {
5846 :
5847 : // Re-update matrices if time changes
5848 : // E.g.?
5849 0 : if (timeDepMat() && *time != lastTime()) {
5850 0 : currTime()=*time;
5851 0 : invalidateDiffCalMat();
5852 0 : syncCalMat();
5853 0 : syncDiffMat();
5854 0 : lastTime()=currTime();
5855 : }
5856 :
5857 : // Synchronize Jones renderers for the ants on this baseline
5858 0 : J1().sync(currJElem()(0,0,*a1),currJElemOK()(0,0,*a1));
5859 0 : J2().sync(currJElem()(0,0,*a2),currJElemOK()(0,0,*a2));
5860 :
5861 : // Synchronize differentiated Jones renderers for this baseline
5862 0 : if (trivialDJ()) {
5863 0 : dJ1().origin();
5864 0 : dJ2().origin();
5865 : } else {
5866 0 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,*a1)));
5867 0 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,*a2)));
5868 : }
5869 :
5870 : // Assumes all iterating quantities have nChanMat() channelization
5871 0 : for (Int ich=0; ich<nChanMat();ich++,
5872 0 : cVm++, J1()++, J2()++) {
5873 :
5874 : // NB: Ignoring vis flag state (OK?)
5875 :
5876 : // Partial applies for repeated use below
5877 0 : VJ2=cVm;
5878 0 : J2().applyLeft(VJ2); // VJ2 = Vm*J2, used below
5879 :
5880 0 : J1().applyRight(cVm);
5881 0 : J1V=cVm; // J1V = J1*Vm, used below
5882 :
5883 : // Finish trial corruption
5884 0 : J2().applyLeft(cVm); // cVm = (J1*Vm)*J2
5885 :
5886 : // Differentiation per par
5887 0 : for (Int ip=0;ip<nPar();ip++,
5888 0 : dV1++,dJ1()++,
5889 0 : dV2++,dJ2()++) {
5890 :
5891 0 : dV1=VJ2;
5892 0 : dJ1().applyRight(dV1); // dV1 = dJ1(ip)*(Vm*J2)
5893 :
5894 0 : dV2=J1V;
5895 0 : dJ2().applyLeft(dV2); // dV2 = (J1*Vm)*dJ2(ip)
5896 : }
5897 :
5898 0 : } // chn
5899 :
5900 : } // !*flagR
5901 : else {
5902 : // Must advance all chan-, par-dep pointers over flagged row
5903 0 : cVm.advance(nChanMat());
5904 0 : J1().advance(nChanMat());
5905 0 : J2().advance(nChanMat());
5906 0 : Int chpar(nChanMat()*nPar());
5907 0 : dV1.advance(chpar);
5908 0 : dV2.advance(chpar);
5909 0 : dJ1().advance(chpar);
5910 0 : dJ2().advance(chpar);
5911 : }
5912 : }
5913 :
5914 : // Subtract the obs'd data from the trial-corrupted model
5915 : // to form residuals
5916 0 : sdb.finalizeResiduals();
5917 :
5918 0 : }
5919 :
5920 :
5921 0 : void SolvableVisJones::differentiate(VisBuffer& vb,
5922 : Cube<Complex>& Vout,
5923 : Array<Complex>& dVout,
5924 : Matrix<Bool>& Vflg) {
5925 :
5926 0 : if (prtlev()>3) cout << " SVJ::differentiate()" << endl;
5927 :
5928 : // NB: For freqDepPar()=true, the data and solutions are
5929 : // multi-channel, but nChanMat()=1 because we only
5930 : // consider one channel at a time. In this case,
5931 : // focusChan is the specific channel under consideration.
5932 : // Otherwise, we will use all channels in the vb
5933 : // simultaneously
5934 :
5935 : // Some vb shape info
5936 0 : Int& nRow(vb.nRow());
5937 0 : Int nCorr(vb.corrType().nelements());
5938 :
5939 : // Size up the output data arrays
5940 : // Vout = [nCorr,nChan,nRow]
5941 : // dVout = [nCorr,nPar,nChan,nRow,2] (1 set of dV for both ants on baseline)
5942 0 : Vout.resize(IPosition(3,nCorr,nChanMat(),nRow));
5943 0 : Vout.unique(); // ensure unique storage
5944 :
5945 0 : dVout.resize(IPosition(5,nCorr,nPar(),nChanMat(),nRow,2));
5946 0 : dVout.unique();
5947 0 : dVout=Complex(0.0);
5948 :
5949 : // Copy the input model data from the VisBuffer to Vout
5950 : // for in-place application (do this according to focusChan)
5951 : // (also flags)
5952 0 : Matrix<Bool> fl;
5953 0 : if (freqDepPar()) {
5954 : // Copy just the focusChan; all work below is single-channel
5955 0 : AlwaysAssert((nChanMat()==1),AipsError); // sanity
5956 0 : AlwaysAssert((focusChan()>-1),AipsError); // sanity
5957 :
5958 0 : Vout = vb.modelVisCube()(IPosition(3,0, focusChan(),0 ),
5959 0 : IPosition(3,nCorr-1,focusChan(),nRow-1));
5960 :
5961 0 : Vflg.resize(IPosition(2,1,nRow)); // proper single channel size
5962 0 : Vflg.unique(); // unique storage
5963 0 : Vflg = vb.flag()(IPosition(2,focusChan(),0 ),
5964 0 : IPosition(2,focusChan(),nRow-1));
5965 : }
5966 : else {
5967 : // Copy all channels in the vb
5968 0 : Vout = vb.modelVisCube();
5969 0 : Vflg.reference(vb.flag()); // Just reference whole flag array
5970 : }
5971 :
5972 : // "Apply" the current Q,U or X estimates to the crosshand model
5973 0 : if (solvePol()>0) {
5974 0 : Complex pol(1.0);
5975 :
5976 0 : if (solvePol()==2) // pol = Q+iU
5977 0 : pol=Complex(real(srcPolPar()(0)),real(srcPolPar()(1)));
5978 0 : else if (solvePol()==1) // pol = exp(iX)
5979 0 : pol=exp(Complex(0.0,real(srcPolPar()(0))));
5980 :
5981 0 : IPosition blc(3,1,0,0), trc(3,1,nChanMat()-1,nRow-1);
5982 0 : Array<Complex> RL(Vout(blc,trc));
5983 0 : RL*=pol;
5984 0 : blc(0)=trc(0)=2;
5985 0 : Array<Complex> LR(Vout(blc,trc));
5986 0 : LR*=conj(pol);
5987 : }
5988 :
5989 : // Visibility vector renderers
5990 0 : VisVector::VisType vt(visType(nCorr));
5991 0 : VisVector cVm(vt); // The model data corrupted by trial solution
5992 0 : VisVector dV1(vt); // The deriv of V wrt pars of 1st ant in bln
5993 0 : VisVector dV2(vt); // The deriv of V wrt pars of 2nd ant in bln
5994 :
5995 : // Temporary non-iterating VisVectors to hold partial applies
5996 0 : VisVector J1V(vt,true);
5997 0 : VisVector VJ2(vt,true);
5998 :
5999 : // Starting synchronization for output visibility data
6000 0 : cVm.sync(Vout(0,0,0));
6001 0 : dV1.sync(dVout(IPosition(5,0,0,0,0,0)));
6002 0 : dV2.sync(dVout(IPosition(5,0,0,0,0,1)));
6003 :
6004 : // Synchronize current calibration pars/matrices
6005 0 : syncSolveCal();
6006 :
6007 : // Nominal synchronization of dJs
6008 0 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,0)));
6009 0 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,0)));
6010 :
6011 : // Inform Jones matrices if data is scalar
6012 0 : Bool scalar(vt==VisVector::One);
6013 0 : J1().setScalarData(scalar);
6014 0 : J2().setScalarData(scalar);
6015 0 : dJ1().setScalarData(scalar);
6016 0 : dJ2().setScalarData(scalar);
6017 :
6018 : // VisBuffer indices
6019 0 : Double* time= vb.time().data();
6020 0 : Int* a1= vb.antenna1().data();
6021 0 : Int* a2= vb.antenna2().data();
6022 0 : Bool* flagR= vb.flagRow().data();
6023 0 : Bool* flag= Vflg.data(); // via local reference
6024 :
6025 : // TBD: set weights according to flags??
6026 :
6027 : // iterate rows
6028 0 : for (Int irow=0; irow<nRow; irow++,flagR++,a1++,a2++,time++) {
6029 :
6030 : // Avoid ACs
6031 0 : if (*a1==*a2) *flagR=true;
6032 :
6033 0 : if (!*flagR) { // if this row unflagged
6034 :
6035 : // Re-update matrices if time changes
6036 0 : if (timeDepMat() && *time != lastTime()) {
6037 0 : currTime()=*time;
6038 0 : invalidateDiffCalMat();
6039 0 : syncCalMat();
6040 0 : syncDiffMat();
6041 0 : lastTime()=currTime();
6042 : }
6043 :
6044 : // Synchronize Jones renderers for the ants on this baseline
6045 0 : J1().sync(currJElem()(0,0,*a1),currJElemOK()(0,0,*a1));
6046 0 : J2().sync(currJElem()(0,0,*a2),currJElemOK()(0,0,*a2));
6047 :
6048 : // Synchronize differentiated Jones renderers for this baseline
6049 0 : if (trivialDJ()) {
6050 0 : dJ1().origin();
6051 0 : dJ2().origin();
6052 : } else {
6053 0 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,*a1)));
6054 0 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,*a2)));
6055 : }
6056 :
6057 : // Assumes all iterating quantities have nChanMat() channelization
6058 0 : for (Int ich=0; ich<nChanMat();ich++,flag++,
6059 0 : cVm++, J1()++, J2()++) {
6060 :
6061 : // if channel unflagged an cal ok
6062 : // if (!*flag && (*J1Ok && *J2Ok) ) {
6063 0 : if (!*flag) {
6064 :
6065 : // Partial applies for repeated use below
6066 0 : VJ2=cVm;
6067 0 : J2().applyLeft(VJ2,*flag); // VJ2 = Vm*J2, used below
6068 :
6069 0 : J1().applyRight(cVm,*flag);
6070 0 : J1V=cVm; // J1V = J1*Vm, used below
6071 :
6072 : // Finish trial corruption
6073 0 : J2().applyLeft(cVm,*flag); // cVm = (J1*Vm)*J2
6074 :
6075 : }
6076 :
6077 : // Only continue with diff-ing, if we aren't flagged yet
6078 0 : if (!*flag) {
6079 :
6080 : // Differentiation per par
6081 0 : for (Int ip=0;ip<nPar();ip++,
6082 0 : dV1++,dJ1()++,
6083 0 : dV2++,dJ2()++) {
6084 :
6085 0 : dV1=VJ2;
6086 0 : dJ1().applyRight(dV1); // dV1 = dJ1(ip)*(Vm*J2)
6087 :
6088 0 : dV2=J1V;
6089 0 : dJ2().applyLeft(dV2); // dV2 = (J1*Vm)*dJ2(ip)
6090 : }
6091 :
6092 : } // (!*flag)
6093 : else {
6094 : // set trial corruption to zero
6095 0 : cVm.zero();
6096 :
6097 : // Advance all par-dep pointers over flagged channel
6098 0 : dV1.advance(nPar());
6099 0 : dV2.advance(nPar());
6100 0 : dJ1().advance(nPar());
6101 0 : dJ2().advance(nPar());
6102 : }
6103 :
6104 : } // chn
6105 :
6106 : } // !*flagR
6107 : else {
6108 : // Must advance all chan-, par-dep pointers over flagged row
6109 0 : flag+=nChanMat();
6110 0 : cVm.advance(nChanMat());
6111 0 : J1().advance(nChanMat());
6112 0 : J2().advance(nChanMat());
6113 0 : Int chpar(nChanMat()*nPar());
6114 0 : dV1.advance(chpar);
6115 0 : dV2.advance(chpar);
6116 0 : dJ1().advance(chpar);
6117 0 : dJ2().advance(chpar);
6118 : }
6119 : }
6120 :
6121 0 : }
6122 :
6123 0 : void SolvableVisJones::diffSrc(VisBuffer& vb,
6124 : Array<Complex>& dVout) {
6125 :
6126 0 : if (prtlev()>3) cout << " SVJ::diffSrc()" << endl;
6127 :
6128 : // Some vb shape info
6129 0 : Int& nRow(vb.nRow());
6130 0 : Int nCorr(vb.corrType().nelements());
6131 :
6132 : // Size up the output data arrays
6133 0 : dVout.resize(IPosition(4,nCorr,nChanMat(),nRow,solvePol()));
6134 0 : dVout.unique();
6135 0 : dVout=Complex(0.0);
6136 :
6137 : // For now, we don't actually need gradients w.r.t. the source
6138 0 : return;
6139 :
6140 : IPosition blc(4,0,0,0,0), trc(4,0,nChanMat()-1,nRow-1,0);
6141 :
6142 : if (solvePol()==2) {
6143 : blc(3)=trc(3)=0;
6144 : blc(0)=1;trc(0)=2;
6145 : dVout(blc,trc)=Complex(1.0); // Q part (both RL & LR)
6146 : blc(3)=trc(3)=1;
6147 : blc(0)=trc(0)=1;
6148 : dVout(blc,trc)=Complex(0.0,1.0); // U part (in RL)
6149 : blc(0)=trc(0)=2;
6150 : dVout(blc,trc)=Complex(0.0,-1.0); // U part (in LR)
6151 : }
6152 : else if (solvePol()==1) {
6153 : Complex dX=Complex(0.0,1.0)*exp(Complex(0.0,real(srcPolPar()(0))));
6154 : blc(3)=trc(3)=0;
6155 : blc(0)=trc(0)=1;
6156 : dVout(blc,trc)=dX; // multiplying RL
6157 : blc(0)=trc(0)=2;
6158 : dVout(blc,trc)=conj(dX); // multiplying LR
6159 : }
6160 :
6161 : // Visibility vector renderers
6162 : VisVector::VisType vt(visType(nCorr));
6163 : VisVector dSm1(vt); // The model data corrupted by trial solution
6164 : VisVector dSm2(vt); // The model data corrupted by trial solution
6165 :
6166 : // Starting synchronization for output visibility data
6167 : dSm1.sync(dVout(IPosition(4,0,0,0,0)));
6168 : if (solvePol()>1)
6169 : dSm2.sync(dVout(IPosition(4,0,0,0,1)));
6170 :
6171 : // Synchronize current calibration pars/matrices
6172 : syncSolveCal();
6173 :
6174 : // Nominal synchronization of dJs
6175 : dJ1().sync(diffJElem()(IPosition(4,0,0,0,0)));
6176 : dJ2().sync(diffJElem()(IPosition(4,0,0,0,0)));
6177 :
6178 : // Inform Jones matrices if data is scalar
6179 : Bool scalar(vt==VisVector::One);
6180 : J1().setScalarData(scalar);
6181 : J2().setScalarData(scalar);
6182 : dJ1().setScalarData(scalar);
6183 : dJ2().setScalarData(scalar);
6184 :
6185 : // VisBuffer indices
6186 : Double* time= vb.time().data();
6187 : Int* a1= vb.antenna1().data();
6188 : Int* a2= vb.antenna2().data();
6189 : Bool* flagR= vb.flagRow().data();
6190 : Bool* flag= vb.flag().data();
6191 :
6192 : // TBD: set weights according to flags??
6193 :
6194 : // iterate rows
6195 : for (Int irow=0; irow<nRow; irow++,flagR++,a1++,a2++,time++) {
6196 :
6197 : // Avoid ACs
6198 : if (*a1==*a2) *flagR=true;
6199 :
6200 : if (!*flagR) { // if this row unflagged
6201 :
6202 : // Re-update matrices if time changes
6203 : if (timeDepMat() && *time != lastTime()) {
6204 : currTime()=*time;
6205 : invalidateDiffCalMat();
6206 : syncCalMat();
6207 : syncDiffMat();
6208 : lastTime()=currTime();
6209 : }
6210 :
6211 : // Synchronize Jones renderers for the ants on this baseline
6212 : J1().sync(currJElem()(0,0,*a1),currJElemOK()(0,0,*a1));
6213 : J2().sync(currJElem()(0,0,*a2),currJElemOK()(0,0,*a2));
6214 :
6215 : // Assumes all iterating quantities have nChanMat() channelization
6216 : for (Int ich=0; ich<nChanMat();ich++,flag++,
6217 : dSm1++, dSm2++, J1()++, J2()++) {
6218 :
6219 : // if channel unflagged an cal ok
6220 : if (!*flag) {
6221 :
6222 : J1().applyRight(dSm1);
6223 : J2().applyLeft(dSm1);
6224 : if (solvePol()>1) {
6225 : J1().applyRight(dSm2);
6226 : J2().applyLeft(dSm2);
6227 : }
6228 : }
6229 :
6230 : } // chn
6231 :
6232 : } // !*flagR
6233 : else {
6234 : // Must advance all chan-, par-dep pointers over flagged row
6235 : flag+=nChanMat();
6236 : dSm1.advance(nChanMat());
6237 : dSm2.advance(nChanMat());
6238 : J1().advance(nChanMat());
6239 : J2().advance(nChanMat());
6240 : }
6241 : }
6242 :
6243 : }
6244 :
6245 0 : void SolvableVisJones::accumulate(SolvableVisCal* incr,
6246 : const Vector<Int>& fields) {
6247 :
6248 : // Use SVJ interface for the incremental component
6249 : // (this should always be safe at this point?)
6250 0 : SolvableVisJones* svj = dynamic_cast<SolvableVisJones*>(incr);
6251 :
6252 : // Catch bad SVJ conversion or fundamental type mismatch
6253 0 : if (svj==NULL || svj->type() != this->type())
6254 0 : throw(AipsError("Incremental calibration is not of compatible type."));
6255 :
6256 0 : Int nfield(fields.nelements());
6257 :
6258 0 : Bool fldok(true);
6259 :
6260 : // TBD: Iterate over the ct_
6261 0 : Block<String> cols(2);
6262 0 : cols[0]="SPECTRAL_WINDOW_ID";
6263 0 : cols[1]="TIME";
6264 0 : CTIter ctiter(*ct_,cols);
6265 :
6266 0 : cout << boolalpha;
6267 0 : Int piter(0);
6268 0 : Int prow(0);
6269 0 : while (!ctiter.pastEnd()) {
6270 :
6271 0 : currSpw()=ctiter.thisSpw();
6272 0 : currTime()=ctiter.thisTime();
6273 :
6274 : /*
6275 : cout << "Spw=" << currSpw() << " spwok=" << svj->spwOK(currSpw());
6276 : cout << " Time=" << MVTime(currTime()/C::day).string(MVTime::YMD,7);
6277 : cout << " nrow=" << ctiter.nrow();
6278 : */
6279 :
6280 : // Only update spws which are available in the incr table:
6281 0 : if (svj->spwOK(currSpw())) {
6282 :
6283 0 : currField()=ctiter.thisField();
6284 :
6285 : // Is current field among those we need to update?
6286 0 : fldok = (nfield==0 || anyEQ(fields,currField()));
6287 :
6288 : // cout << " Fld=" << currField() << " fldok=" << fldok;
6289 :
6290 0 : if (fldok) {
6291 :
6292 0 : currFreq()=ctiter.freq();
6293 :
6294 0 : currCPar().assign(ctiter.cparam());
6295 0 : currParOK().assign(!ctiter.flag());
6296 :
6297 0 : syncCalMat(false); // a reference!!
6298 :
6299 : // Sync svj with this
6300 0 : svj->syncCal(*this);
6301 :
6302 0 : AlwaysAssert( (nChanMat()==svj->nChanMat()), AipsError);
6303 :
6304 : // Do the multiplication each ant, chan
6305 0 : for (Int iant=0; iant<nAnt(); iant++) {
6306 0 : for (Int ichan=0; ichan<svj->nChanMat(); ichan++) {
6307 0 : J1()*=(svj->J1());
6308 0 : J1()++;
6309 0 : svj->J1()++;
6310 : } // ichan
6311 : } // iant
6312 :
6313 : //cout << " keep";
6314 :
6315 0 : ctiter.setcparam(currCPar()); // assumes matrices are references
6316 0 : ctiter.setflag(!currParOK());
6317 :
6318 0 : piter+=1;
6319 0 : prow+=ctiter.nrow();
6320 :
6321 : } // fldok
6322 : } // spwOK
6323 :
6324 : // cout << endl;
6325 :
6326 : // Advance iterator
6327 0 : ctiter.next();
6328 :
6329 : } // ispw
6330 :
6331 : // cout << "Processed " << prow << " rows in " << piter << " iterations." << endl;
6332 :
6333 0 : }
6334 :
6335 :
6336 :
6337 : // Setup solvePar shape (Jones version)
6338 0 : void SolvableVisJones::initSolvePar() {
6339 :
6340 0 : if (prtlev()>3) cout << " SVJ::initSolvePar()" << endl;
6341 :
6342 0 : for (Int ispw=0;ispw<nSpw();++ispw) {
6343 :
6344 0 : currSpw()=ispw;
6345 :
6346 0 : switch (parType()) {
6347 0 : case VisCalEnum::COMPLEX: {
6348 0 : solveAllCPar().resize(nPar(),nChanPar(),nAnt());
6349 0 : solveAllCPar()=Complex(1.0);
6350 0 : if (nChanPar()==1)
6351 0 : solveCPar().reference(solveAllCPar());
6352 : else {
6353 0 : solveCPar().resize(nPar(),1,nAnt());
6354 0 : solveCPar()=Complex(1.0);
6355 : }
6356 0 : break;
6357 : }
6358 0 : case VisCalEnum::REAL: {
6359 0 : solveAllRPar().resize(nPar(),nChanPar(),nAnt());
6360 0 : solveAllRPar()=0.0;
6361 0 : if (nChanPar()==1)
6362 0 : solveRPar().reference(solveAllRPar());
6363 : else {
6364 0 : solveRPar().resize(nPar(),1,nAnt());
6365 0 : solveRPar()=0.0;
6366 : }
6367 0 : break;
6368 : }
6369 0 : default:
6370 : throw(AipsError("Internal error(Calibrater Module): Unsupported parameter type "
6371 0 : "COMPLEXREAL found in SolvableVisJones::initSolvePar()"));
6372 : }
6373 :
6374 0 : solveAllParOK().resize(nPar(),nChanPar(),nAnt());
6375 0 : solveAllParErr().resize(nPar(),nChanPar(),nAnt());
6376 0 : solveAllParSNR().resize(nPar(),nChanPar(),nAnt());
6377 0 : solveAllParOK()=true;
6378 0 : solveAllParErr()=0.0;
6379 0 : solveAllParSNR()=0.0;
6380 0 : if (nChanPar()==1) {
6381 0 : solveParOK().reference(solveAllParOK());
6382 0 : solveParErr().reference(solveAllParErr());
6383 0 : solveParSNR().reference(solveAllParSNR());
6384 : }
6385 : else {
6386 : // solving many channels, one at a time
6387 0 : solveParOK().resize(nPar(),1,nAnt());
6388 0 : solveParErr().resize(nPar(),1,nAnt());
6389 0 : solveParSNR().resize(nPar(),1,nAnt());
6390 0 : solveParOK()=true;
6391 0 : solveParErr()=0.0;
6392 0 : solveParSNR()=0.0;
6393 : }
6394 : }
6395 0 : currSpw()=0;
6396 :
6397 0 : }
6398 :
6399 0 : void SolvableVisJones::syncDiffMat() {
6400 :
6401 0 : if (prtlev()>5) cout << " SVJ::syncDiffMat()"
6402 0 : << " (DJValid()=" << DJValid() << ")" << endl;
6403 :
6404 : // Sync the diff'd Jones matrices
6405 0 : if (!DJValid()) syncDiffJones();
6406 :
6407 : // Sync up Muellers, if necessary
6408 : // if (applyByMueller())
6409 : // Do nothing for now! --All dJ applied directly in differentiate
6410 : // if (!DMValid()) syncDiffMueller();
6411 :
6412 0 : }
6413 :
6414 0 : void SolvableVisJones::syncDiffJones() {
6415 :
6416 0 : if (prtlev()>6) cout << " SVJ::syncDiffJones()" << endl;
6417 :
6418 : // If differentiated Jones are trivial, we are
6419 : // already referencing the type-dep trivial versions
6420 : // TBD: Review this for D, where trivialJonesElem()=false,
6421 : // but diffJ is "trivial-ish"!!! (Probably need trivDiffJonesElem(),
6422 : // or override this method in D to make it no-op)
6423 :
6424 0 : if (trivialDJ())
6425 : // Ensure trivial matrices ready
6426 0 : initTrivDJ();
6427 : else {
6428 0 : diffJElem().resize(IPosition(4,jonesNPar(jonesType()),nPar(),nChanMat(),nCalMat()));
6429 0 : diffJElem().unique();
6430 0 : invalidateDJ();
6431 :
6432 : // Calculate for all ants/chans
6433 0 : calcAllDiffJones();
6434 :
6435 : }
6436 :
6437 : // Ensure diff'd Jones matrix renders are OK
6438 0 : createDiffJones();
6439 :
6440 : // diff'd Jones matrices now valid
6441 0 : validateDJ();
6442 0 : invalidateDM(); // dMs still invalid, probably forever
6443 :
6444 0 : }
6445 :
6446 0 : void SolvableVisJones::calcAllDiffJones() {
6447 :
6448 0 : if (prtlev()>6) cout << " SVJ::calcAllDiffJones" << endl;
6449 :
6450 : // Should handle OK flags in this method, and only
6451 : // do calc if OK
6452 :
6453 0 : Matrix<Complex> oneDJ; // (nElem,nPar)
6454 0 : Vector<Complex> onePar; // (nPar)
6455 :
6456 0 : ArrayIterator<Complex> dJiter(diffJElem(),2);
6457 0 : ArrayIterator<Complex> Piter(currCPar(),1);
6458 :
6459 0 : for (Int iant=0; iant<nCalMat(); iant++) {
6460 :
6461 : // Solving parameters are NEVER channel-dependent
6462 : // (even if data & matrices are)
6463 0 : onePar.reference(Piter.array());
6464 :
6465 0 : for (Int ich=0; ich<nChanMat(); ich++) {
6466 :
6467 0 : oneDJ.reference(dJiter.array());
6468 :
6469 : // Calculate the DJ matrices w.r.t. each par on this ant/chan
6470 0 : calcOneDiffJones(oneDJ,onePar);
6471 :
6472 : // Advance iterators
6473 0 : dJiter.next();
6474 :
6475 : }
6476 0 : Piter.next();
6477 : }
6478 :
6479 0 : }
6480 :
6481 0 : void SolvableVisJones::calcOneDiffJones(Matrix<Complex>&,
6482 : const Vector<Complex>&) {
6483 :
6484 0 : if (prtlev()>10) cout << " SVJ::calcOneDiffJones()" << endl;
6485 :
6486 : // If Jones matrix is trivial, shouldn't get here
6487 0 : if (trivialJonesElem())
6488 0 : throw(AipsError("Trivial Jones Matrix logic error."));
6489 :
6490 : // Otherwise, this method apparently hasn't been specialized, as required
6491 : else
6492 0 : throw(AipsError("Unknown non-trivial dJones-from-parameter calculation requested."));
6493 :
6494 : }
6495 :
6496 0 : void SolvableVisJones::createDiffJones() {
6497 :
6498 0 : if (prtlev()>6) cout << " SVJ::createDiffJones()" << endl;
6499 :
6500 0 : Jones::JonesType jtype(jonesType());
6501 :
6502 : // Delete if wrong type
6503 0 : if (dJ1_ && dJ1().type() != jtype) delete dJ1_;
6504 0 : if (dJ2_ && dJ2().type() != jtype) delete dJ2_;
6505 :
6506 : // If needed, construct the correct diff Jones
6507 0 : if (!dJ1_) dJ1_ = casa::createJones(jtype);
6508 0 : if (!dJ2_) dJ2_ = casa::createJones(jtype);
6509 :
6510 0 : }
6511 :
6512 0 : void SolvableVisJones::initTrivDJ() {
6513 :
6514 0 : if (prtlev()>7) cout << " SVJ::initTrivDJ()" << endl;
6515 :
6516 : // If DJ matrice not trivial, shouldn't get here
6517 0 : if (!trivialDJ())
6518 0 : throw(AipsError("Trivial Jones Matrix logic error."));
6519 :
6520 : // Otherwise, this method apparently hasn't been specialized, as required
6521 : else
6522 0 : throw(AipsError("Unknown trivial dJ initialization requested."));
6523 :
6524 : }
6525 :
6526 : // File a solved solution (and meta-data) into the in-memory Caltable
6527 0 : void SolvableVisJones::keepNCT() {
6528 :
6529 : // Call parent to do general stuff
6530 0 : SolvableVisCal::keepNCT();
6531 :
6532 0 : if (prtlev()>4)
6533 0 : cout << " SVJ::keepNCT" << endl;
6534 :
6535 : // Antenna id sequence
6536 0 : Vector<Int> a1(nAnt());
6537 0 : indgen(a1);
6538 :
6539 : // We are adding to the most-recently added rows
6540 0 : RefRows rows(ct_->nrow()-nElem(),ct_->nrow()-1,1);
6541 :
6542 : // Write to table
6543 0 : CTMainColumns ncmc(*ct_);
6544 0 : ncmc.antenna1().putColumnCells(rows,a1);
6545 0 : ncmc.antenna2().putColumnCells(rows,Vector<Int>(nAnt(),-1)); // Unknown but nominally unform
6546 :
6547 : // NB: a2 will be set separately, e.g., by applyRefAnt
6548 :
6549 0 : }
6550 :
6551 0 : void SolvableVisJones::stateSVJ(const Bool& doVC) {
6552 :
6553 : // If requested, report VisCal state
6554 0 : if (doVC) VisJones::state();
6555 :
6556 : // Get parent's state (w/out VC):
6557 0 : SolvableVisMueller::stateSVM(false);
6558 :
6559 0 : if (applyByJones()) {
6560 0 : if (prtlev()>3) cout << "SVJ::stateSVJ()" << endl;
6561 0 : cout << boolalpha;
6562 :
6563 : // Now SVJ-specific stuff:
6564 0 : cout << " DJValid() = " << DJValid() << endl;
6565 :
6566 0 : cout << " diffJElem().shape() = " << diffJElem().shape()
6567 0 : << " (" << diffJElem().data() << ")" << endl;
6568 0 : cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" << endl;
6569 : }
6570 0 : }
6571 :
6572 0 : Float SolvableVisJones::calcPowerNorm(Array<Float>& amp, const Array<Bool>& ok) {
6573 :
6574 : // SVJ version asumes amps are voltages, so square them
6575 0 : Array<Float> a2(square(amp));
6576 0 : a2(!ok)=0.0; // zero flagged samples
6577 :
6578 :
6579 0 : Float norm2(1.0);
6580 0 : switch (solNorm().normtype()) {
6581 0 : case SolNorm::MEAN: {
6582 0 : Float n=Float(ntrue(ok));
6583 0 : if (n>0.0)
6584 0 : norm2=sum(a2)/n;
6585 0 : break;
6586 : }
6587 0 : case SolNorm::MEDIAN: {
6588 0 : MaskedArray<Float> a2masked(a2,ok);
6589 0 : norm2=median(a2masked,false,true); // unsorted, do mean when even
6590 0 : break;
6591 : }
6592 0 : default:
6593 0 : throw(AipsError("Proper normalization type not specified."));
6594 : break;
6595 : }
6596 :
6597 : // Return sqrt, because Jones are voltages
6598 0 : return sqrt(norm2);
6599 : }
6600 :
6601 0 : void SolvableVisJones::globalPostSolveTinker() {
6602 :
6603 : // Re-reference the phase, if requested
6604 0 : if (refantlist()(0)>-1) applyRefAnt();
6605 :
6606 : // Apply more general post-solve stuff
6607 0 : SolvableVisCal::globalPostSolveTinker();
6608 :
6609 0 : }
6610 :
6611 0 : void SolvableVisJones::applyRefAnt() {
6612 :
6613 : // TBD:
6614 : // 1. Synchronize refant changes on par axis
6615 : // 2. Implement minimum mean deviation algorithm
6616 :
6617 0 : if (refantlist()(0)<0)
6618 0 : throw(AipsError("No refant specified."));
6619 :
6620 0 : Int nUserRefant=refantlist().nelements();
6621 :
6622 : // Get the preferred refant names from the MS
6623 0 : String refantName(msmc().antennaName(refantlist()(0)));
6624 0 : if (nUserRefant>1) {
6625 0 : refantName+=" (";
6626 0 : for (Int i=1;i<nUserRefant;++i) {
6627 0 : refantName+=msmc().antennaName(refantlist()(i));
6628 0 : if (i<nUserRefant-1) refantName+=",";
6629 : }
6630 0 : refantName+=")";
6631 : }
6632 :
6633 : logSink() << "Applying refant: " << refantName
6634 0 : << " refantmode = " << refantmode();
6635 0 : if (refantmode()=="flex")
6636 0 : logSink() << " (hold alternate refants' phase constant) when refant flagged";
6637 0 : if (refantmode()=="strict")
6638 0 : logSink() << " (flag all antennas when refant flagged)";
6639 0 : logSink() << LogIO::POST;
6640 :
6641 : // Generate a prioritized refant choice list
6642 : // The first entry in this list is the user's primary refant,
6643 : // the second entry is the refant used on the previous interval,
6644 : // and the rest is a prioritized list of alternate refants,
6645 : // starting with the user's secondary (if provided) refants,
6646 : // followed by the rest of the array, in distance order. This
6647 : // makes the priorities correct all the time, and prevents
6648 : // a semi-stochastic alternation (by preferring the last-used
6649 : // alternate, even if nominally higher-priority refants become
6650 : // available)
6651 :
6652 :
6653 : // Extract antenna positions
6654 0 : Matrix<Double> xyz;
6655 0 : if (msName()!="<noms>") {
6656 0 : MeasurementSet ms(msName());
6657 0 : MSAntennaColumns msant(ms.antenna());
6658 0 : msant.position().getColumn(xyz);
6659 : }
6660 : else {
6661 : // TBD RO*
6662 0 : CTColumns ctcol(*ct_);
6663 0 : CTAntennaColumns& antcol(ctcol.antenna());
6664 0 : antcol.position().getColumn(xyz);
6665 : }
6666 :
6667 : // Calculate (squared) antenna distances, relative
6668 : // to last preferred antenna
6669 0 : Vector<Double> dist2(xyz.ncolumn(),0.0);
6670 0 : for (Int i=0;i<3;++i) {
6671 0 : Vector<Double> row=xyz.row(i);
6672 0 : row-=row(refantlist()(nUserRefant-1));
6673 0 : dist2+=square(row);
6674 : }
6675 : // Move preferred antennas to a large distance
6676 0 : for (Int i=0;i<nUserRefant;++i)
6677 0 : dist2(refantlist()(i))=DBL_MAX;
6678 :
6679 : // Generated sorted index
6680 0 : Vector<uInt> ord;
6681 0 : genSort(ord,dist2);
6682 :
6683 : // Assemble the whole choices list
6684 0 : Int nchoices=nUserRefant+1+ord.nelements();
6685 0 : Vector<Int> refantchoices(nchoices,0);
6686 0 : Vector<Int> r(refantchoices(IPosition(1,nUserRefant+1),IPosition(1,refantchoices.nelements()-1)));
6687 0 : convertArray(r,ord);
6688 :
6689 : // set first two to primary preferred refant
6690 0 : refantchoices(0)=refantchoices(1)=refantlist()(0);
6691 :
6692 : // set user's secondary refants (if any)
6693 0 : if (nUserRefant>1)
6694 0 : refantchoices(IPosition(1,2),IPosition(1,nUserRefant))=
6695 0 : refantlist()(IPosition(1,1),IPosition(1,nUserRefant-1));
6696 :
6697 : //cout << "refantchoices = " << refantchoices << endl;
6698 :
6699 :
6700 0 : if (refantmode()=="strict") {
6701 0 : nchoices=1;
6702 0 : refantchoices.resize(1,True);
6703 : }
6704 :
6705 0 : Vector<Int> nPol(nSpw(),nPar()); // TBD:or 1, if data was single pol
6706 :
6707 0 : if (nPar()==2) {
6708 : // Verify that 2nd poln has unflagged solutions, PER SPW
6709 0 : ROCTMainColumns ctmc(*ct_);
6710 :
6711 0 : Block<String> cols(1);
6712 0 : cols[0]="SPECTRAL_WINDOW_ID";
6713 0 : CTIter ctiter(*ct_,cols);
6714 0 : Cube<Bool> fl;
6715 :
6716 0 : while (!ctiter.pastEnd()) {
6717 :
6718 0 : Int ispw=ctiter.thisSpw();
6719 0 : fl.assign(ctiter.flag());
6720 :
6721 0 : IPosition blc(3,0,0,0), trc(fl.shape());
6722 0 : trc-=1; trc(0)=blc(0)=1;
6723 :
6724 : // cout << "ispw = " << ispw << " nfalse(fl(1,:,:)) = " << nfalse(fl(blc,trc)) << endl;
6725 :
6726 : // If there are no unflagged solutions in 2nd pol,
6727 : // avoid it in refant calculations
6728 0 : if (nfalse(fl(blc,trc))==0)
6729 0 : nPol(ispw)=1;
6730 :
6731 0 : ctiter.next();
6732 : }
6733 : }
6734 : // cout << "nPol = " << nPol << endl;
6735 :
6736 0 : Bool usedaltrefant(false);
6737 0 : Int currrefant(refantchoices(0)), lastrefant(-1);
6738 :
6739 0 : Block<String> cols(2);
6740 0 : cols[0]="SPECTRAL_WINDOW_ID";
6741 0 : cols[1]="TIME";
6742 0 : CTIter ctiter(*ct_,cols);
6743 :
6744 : // Arrays to hold per-timestamp solutions
6745 0 : Cube<Complex> solA, solB;
6746 0 : Cube<Bool> flA, flB;
6747 0 : Vector<Int> ant1A, ant1B, ant2B;
6748 0 : Matrix<Complex> refPhsr; // the reference phasor [npol,nchan]
6749 0 : Int lastspw(-1);
6750 0 : Bool first(true);
6751 0 : while (!ctiter.pastEnd()) {
6752 0 : Int ispw=ctiter.thisSpw();
6753 0 : if (ispw!=lastspw) first=true; // spw changed, start over
6754 :
6755 : // Read in the current sol, fl, ant1:
6756 0 : solB.assign(ctiter.cparam());
6757 0 : flB.assign(ctiter.flag());
6758 0 : ant1B.assign(ctiter.antenna1());
6759 0 : ant2B.assign(ctiter.antenna2());
6760 :
6761 : // First time thru, 'previous' solution same as 'current'
6762 0 : if (first) {
6763 0 : solA.reference(solB);
6764 0 : flA.reference(flB);
6765 0 : ant1A.reference(ant1B);
6766 : }
6767 0 : IPosition shB(solB.shape());
6768 0 : IPosition shA(solA.shape());
6769 :
6770 : // Find a good refant at this time
6771 : // A good refant is one that is unflagged in all polarizations
6772 : // in the current(B) and previous(A) intervals (so they can be connected)
6773 0 : Int irefA(0),irefB(0); // index on 3rd axis of solution arrays
6774 0 : Int ichoice(0); // index in refantchoicelist
6775 0 : Bool found(false);
6776 0 : IPosition blcA(3,0,0,0),trcA(shA),blcB(3,0,0,0),trcB(shB);
6777 0 : trcA-=1; trcA(0)=trcA(2)=0;
6778 0 : trcB-=1; trcB(0)=trcB(2)=0;
6779 0 : ichoice=0;
6780 0 : while (!found && ichoice<nchoices) {
6781 : // Find index of current refant choice
6782 0 : irefA=irefB=0;
6783 0 : while (ant1A(irefA)!=refantchoices(ichoice) && irefA<shA(2)) ++irefA;
6784 0 : while (ant1B(irefB)!=refantchoices(ichoice) && irefB<shB(2)) ++irefB;
6785 :
6786 0 : if (irefA<shA(2) && irefB<shB(2)) {
6787 :
6788 : // cout << " Trial irefA,irefB: " << irefA << "," << irefB
6789 : // << " Ants=" << ant1A(irefA) << "," << ant1B(irefB) << endl;
6790 :
6791 0 : blcA(2)=trcA(2)=irefA;
6792 0 : blcB(2)=trcB(2)=irefB;
6793 0 : found=true; // maybe
6794 0 : for (Int ipol=0;ipol<nPol(ispw);++ipol) {
6795 0 : blcA(0)=trcA(0)=blcB(0)=trcB(0)=ipol;
6796 0 : found &= (nfalse(flA(blcA,trcA))>0); // previous interval
6797 0 : found &= (nfalse(flB(blcB,trcB))>0); // current interval
6798 : }
6799 : }
6800 : else
6801 : // irefA or irefB out-of-range
6802 0 : found=false; // Just to be sure
6803 :
6804 0 : if (!found) ++ichoice; // try next choice next round
6805 :
6806 : }
6807 :
6808 0 : if (found) {
6809 : // at this point, irefA/irefB point to a good refant
6810 :
6811 : // Keep track
6812 0 : usedaltrefant|=(ichoice>0);
6813 0 : currrefant=refantchoices(ichoice);
6814 0 : refantchoices(1)=currrefant; // 2nd priorty next time
6815 :
6816 : // Mark refant in activity rec
6817 0 : refantMap_[ctiter.thisSpw()][currrefant] += 1;
6818 :
6819 : // cout << " currrefant = " << currrefant << " (" << ichoice << ")" << endl;
6820 :
6821 : // cout << " Final irefA,irefB: " << irefA << "," << irefB
6822 : // << " Ants=" << ant1A(irefA) << "," << ant1B(irefB) << endl;
6823 :
6824 :
6825 : // Only report if using an alternate refant
6826 0 : if (currrefant!=lastrefant && ichoice>0) {
6827 : logSink()
6828 : << "At "
6829 0 : << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7)
6830 : << " ("
6831 : << "Spw=" << ctiter.thisSpw()
6832 : << ", Fld=" << ctiter.thisField()
6833 : << ")"
6834 0 : << ", using refant " << msmc().antennaName(currrefant)
6835 : << " (id=" << currrefant
6836 : << ")" << " (alternate)"
6837 0 : << LogIO::POST;
6838 : }
6839 :
6840 : // Form reference phasor [nPar,nChan]
6841 0 : Matrix<Complex> rA,rB;
6842 0 : Matrix<Float> ampA,ampB;
6843 0 : Matrix<Bool> rflA,rflB;
6844 0 : rB.assign(solB.xyPlane(irefB));
6845 0 : rflB.assign(flB.xyPlane(irefB));
6846 0 : switch (this->type()) {
6847 0 : case VisCal::G:
6848 : case VisCal::B:
6849 : case VisCal::T: {
6850 0 : ampB=amplitude(rB);
6851 0 : rflB(ampB<FLT_EPSILON)=true; // flag...
6852 0 : rB(rflB)=Complex(1.0); // ...and reset zeros
6853 0 : ampB(rflB)=1.0;
6854 0 : rB/=ampB; // rB now normalized ("phase"-only)
6855 0 : break;
6856 : }
6857 0 : case VisCal::D: {
6858 : // Fill 2nd pol with negative conj of 1st pol
6859 0 : rB.row(1)=-conj(rB.row(0));
6860 0 : break;
6861 : }
6862 0 : default:
6863 0 : throw(AipsError("SVC::applyRefAnt attempted for inapplicable type"));
6864 : }
6865 :
6866 0 : if (!first) {
6867 : // Get and condition previous phasor for the current refant
6868 0 : rA.assign(solA.xyPlane(irefA));
6869 0 : rflA.assign(flA.xyPlane(irefA));
6870 0 : switch (this->type()) {
6871 0 : case VisCal::G:
6872 : case VisCal::B:
6873 : case VisCal::T: {
6874 0 : ampA=amplitude(rA);
6875 0 : rflA(ampA<FLT_EPSILON)=true; // flag...
6876 0 : rA(rflA)=Complex(1.0); // ...and reset zeros
6877 0 : ampA(rflA)=1.0;
6878 0 : rA/=ampA; // rA now normalized ("phase"-only)
6879 :
6880 : // Phase difference (as complex) relative to last
6881 0 : rB/=rA;
6882 0 : break;
6883 : }
6884 0 : case VisCal::D: {
6885 : //
6886 0 : rA.row(1)=-conj(rA.row(0));
6887 :
6888 : // Complex difference relative to last
6889 0 : rB-=rA;
6890 0 : break;
6891 : }
6892 0 : default:
6893 0 : throw(AipsError("SVC::applyRefAnt attempted for inapplicable type"));
6894 : }
6895 :
6896 : // Accumulate flags
6897 0 : rflB&=rflA;
6898 : }
6899 :
6900 : // cout << " rB = " << rB << endl;
6901 : // cout << boolalpha << " rflB = " << rflB << endl;
6902 : // TBD: fillChanGaps?
6903 :
6904 : // Now apply reference phasor to all antennas
6905 0 : Matrix<Complex> thissol;
6906 0 : for (Int iant=0;iant<shB(2);++iant) {
6907 0 : thissol.reference(solB.xyPlane(iant));
6908 0 : switch (this->type()) {
6909 0 : case VisCal::G:
6910 : case VisCal::B:
6911 : case VisCal::T: {
6912 : // Complex division == phase subtraction
6913 0 : thissol/=rB;
6914 0 : break;
6915 : }
6916 0 : case VisCal::D: {
6917 : // Complex subtraction
6918 0 : thissol-=rB;
6919 0 : break;
6920 : }
6921 0 : default:
6922 0 : throw(AipsError("SVC::applyRefAnt attempted for inapplicable type"));
6923 : }
6924 : }
6925 :
6926 : // Set refant, so we can put it back
6927 0 : ant2B=currrefant;
6928 :
6929 : // put back referenced solutions
6930 0 : ctiter.setcparam(solB);
6931 0 : ctiter.setantenna2(ant2B);
6932 :
6933 : // Next time thru, solB is previous
6934 0 : solA.reference(solB);
6935 0 : flA.reference(flB);
6936 0 : ant1A.reference(ant1B);
6937 0 : solB.resize(); // (break references)
6938 0 : flB.resize();
6939 0 : ant1B.resize();
6940 :
6941 0 : lastrefant=currrefant;
6942 0 : first=false; // avoid first-pass stuff from now on
6943 :
6944 : } // found
6945 : else {
6946 : logSink()
6947 : << "At "
6948 0 : << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7)
6949 : << " ("
6950 : << "Spw=" << ctiter.thisSpw()
6951 : << ", Fld=" << ctiter.thisField()
6952 : << ")"
6953 : << ", refant (id=" << currrefant
6954 : << ") was flagged; flagging all antennas strictly."
6955 0 : << LogIO::POST;
6956 : // Flag all solutions in this interval
6957 0 : flB.set(True);
6958 0 : ctiter.setflag(flB);
6959 : }
6960 :
6961 : // advance to the next interval
6962 0 : lastspw=ispw;
6963 0 : ctiter.next();
6964 : }
6965 :
6966 0 : if (usedaltrefant)
6967 : logSink() << LogIO::NORMAL
6968 : << " NB: An alternate refant was used at least once to maintain" << endl
6969 : << " phase continuity where the user's preferred refant drops out." << endl
6970 : << " Alternate refants are held constant in phase (_not_ zeroed)" << endl
6971 : << " during these periods, and the preferred refant may return at" << endl
6972 : << " a non-zero phase. This is generally harmless."
6973 0 : << LogIO::POST;
6974 :
6975 0 : return;
6976 :
6977 : }
6978 :
6979 :
6980 0 : void SolvableVisJones::fluxscale(const String& outfile,
6981 : const Vector<Int>& refFieldIn,
6982 : const Vector<Int>& tranFieldIn,
6983 : const Vector<Int>& inRefSpwMap,
6984 : const Vector<String>& fldNames,
6985 : const Float& inGainThres,
6986 : const String& antSel,
6987 : const String& timerangeSel,
6988 : const String& scanSel,
6989 : fluxScaleStruct& oFluxScaleStruct,
6990 : const String& oListFile,
6991 : const Bool& incremental,
6992 : const Int& fitorder,
6993 : const Bool& display) {
6994 :
6995 : //String outCalTabName="_tmp_testfluxscaletab";
6996 0 : String outCalTabName=outfile;
6997 :
6998 : //timerange
6999 : //String timerange("");
7000 : //String scanSel("");
7001 : // turn on incremental caltable mode
7002 : //Bool incremental = true;
7003 : //Bool fitperchan = true;
7004 :
7005 : // threshold for gain (amplitude) to be used in
7006 : // fluxscale determination
7007 : // -1: no threshold
7008 : // plot histogram of gain ratio
7009 0 : Bool report_p=display;
7010 :
7011 0 : if (incremental) {
7012 : logSink() << LogIO::NORMAL
7013 : << "Generating an incremental caltable"
7014 0 : << LogIO::POST;
7015 : }
7016 :
7017 0 : if (!ct_ || ct_->nrow()<1)
7018 0 : throw(AipsError("SVJ:fluxscale: Empty or absent caltable specified"));
7019 :
7020 : // For updating the MS History Table
7021 : // LogSink logSink_p = LogSink(LogMessage::NORMAL, false);
7022 : // logSink_p.clearLocally();
7023 : // LogIO oss(LogOrigin("calibrater", "fluxscale()"), logSink_p);
7024 :
7025 : // PtrBlocks to hold mean gain moduli and related
7026 0 : PtrBlock< Cube<Bool>* > MGOK;
7027 0 : PtrBlock< Cube<Double>* > MG;
7028 0 : PtrBlock< Cube<Double>* > MG2;
7029 0 : PtrBlock< Cube<Double>* > MGWT;
7030 0 : PtrBlock< Cube<Double>* > MGVAR;
7031 0 : PtrBlock< Cube<Int>* > MGN;
7032 0 : PtrBlock< Cube<Int>* > MGNALL;
7033 :
7034 0 : Int nMSFld; fldNames.shape(nMSFld);
7035 :
7036 : // Assemble available field list from the NewCalTable
7037 0 : ROCTMainColumns mcols(*ct_);
7038 0 : Vector<Int> fldList;
7039 0 : mcols.fieldId().getColumn(fldList);
7040 0 : Int nFldList=genSort(fldList,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
7041 0 : fldList.resize(nFldList,true);
7042 :
7043 0 : Int nFld=max(fldList)+1;
7044 :
7045 : //get Antenna names
7046 0 : MSAntennaColumns antcol(ct_->antenna());
7047 0 : Vector<String> antNames(antcol.name().getColumn());
7048 :
7049 0 : Vector<Double> solFreq(nSpw(),-1.0);
7050 0 : Vector<Double> mgreft(nFld,0);
7051 :
7052 :
7053 : try {
7054 :
7055 : // Resize, NULL-initialize PtrBlocks
7056 0 : MGOK.resize(nFld); MGOK=NULL;
7057 0 : MG.resize(nFld); MG=NULL;
7058 0 : MG2.resize(nFld); MG2=NULL;
7059 0 : MGWT.resize(nFld); MGWT=NULL;
7060 0 : MGVAR.resize(nFld); MGVAR=NULL;
7061 0 : MGN.resize(nFld); MGN=NULL;
7062 0 : MGNALL.resize(nFld); MGNALL=NULL;
7063 :
7064 : // sort user-specified fields
7065 0 : Vector<Int> refField; refField = refFieldIn;
7066 : Int nRef,nTran;
7067 0 : nRef=genSort(refField,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
7068 : // temp copy of tranFieldIn
7069 0 : std::vector<Int> tmpTranField;
7070 0 : tranFieldIn.tovector(tmpTranField);
7071 0 : for (Int iRef=0; iRef<nRef; iRef++) {
7072 0 : auto iidx = std::find(tmpTranField.begin(),tmpTranField.end(),refField(iRef));
7073 0 : if (iidx != tmpTranField.end()) {
7074 0 : logSink() << "The reference field, "<<fldNames(*iidx)
7075 : << " , is also listed in the transfer fields. "
7076 : <<" It will be ignored for further scaling process."
7077 0 : << LogIO::POST;
7078 0 : tmpTranField.erase(iidx);
7079 : }
7080 : }
7081 : //Vector<Int> tranField; tranField = tranFieldIn;
7082 0 : Vector<Int> tranField(tmpTranField);
7083 0 : nTran=genSort(tranField,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
7084 :
7085 : // make masks for ref/tran among available fields
7086 0 : Vector<Bool> tranmask(nFldList,true);
7087 0 : Vector<Bool> refmask(nFldList,false);
7088 0 : for (Int iFld=0; iFld<nFldList; iFld++) {
7089 0 : if ( anyEQ(refField,fldList(iFld)) ) {
7090 : // this is a ref field
7091 0 : refmask(iFld)=true;
7092 0 : tranmask(iFld)=false;
7093 : }
7094 : }
7095 :
7096 : // Check availability of all ref fields
7097 0 : if (ntrue(refmask)==0) {
7098 0 : throw(AipsError(" Cannot find specified reference field(s)"));
7099 : }
7100 : // Any fields present other than ref fields?
7101 0 : if (ntrue(tranmask)==0) {
7102 0 : throw(AipsError(" Cannot find solutions for transfer field(s)"));
7103 : }
7104 :
7105 : // make implicit reference field list
7106 0 : MaskedArray<Int> mRefFldList(fldList,LogicalArray(refmask));
7107 0 : Vector<Int> implRefField(mRefFldList.getCompressedArray());
7108 :
7109 : // Check for missing reference fields
7110 0 : if (Int(ntrue(refmask)) < nRef) {
7111 0 : ostringstream x;
7112 0 : for (Int iRef=0; iRef<nRef; iRef++) {
7113 0 : if ( !anyEQ(fldList,refField(iRef)) ) {
7114 0 : if (refField(iRef)>-1 && refField(iRef) < nMSFld) x << fldNames(refField(iRef)) << " ";
7115 0 : else x << "Index="<<refField(iRef)+1<<"=out-of-range ";
7116 : }
7117 : }
7118 0 : String noRefSol=x.str();
7119 : logSink() << LogIO::WARN
7120 : << " The following reference fields have no solutions available: "
7121 : << noRefSol
7122 0 : << LogIO::POST;
7123 0 : refField.reference(implRefField);
7124 : }
7125 0 : refField.shape(nRef);
7126 :
7127 : // make implicit tranfer field list
7128 0 : MaskedArray<Int> mTranFldList(fldList,LogicalArray(tranmask));
7129 0 : Vector<Int> implTranField(mTranFldList.getCompressedArray());
7130 0 : Int nImplTran; implTranField.shape(nImplTran);
7131 :
7132 : // cout << "implTranField = " << implTranField << endl;
7133 :
7134 : // Check availability of transfer fields
7135 :
7136 : // If user specified no transfer fields, use implicit
7137 : // transfer field list, ELSE check for missing tran fields
7138 : // among those they specified
7139 0 : if (nTran==0) {
7140 0 : tranField.reference(implTranField);
7141 : logSink() << LogIO::NORMAL
7142 : << " Assuming all non-reference fields are transfer fields."
7143 0 : << LogIO::POST;
7144 : } else {
7145 0 : if ( !(nTran==nImplTran &&
7146 0 : allEQ(tranField,implTranField)) ) {
7147 0 : ostringstream x;
7148 0 : for (Int iTran=0; iTran<nTran; iTran++) {
7149 0 : if ( !anyEQ(implTranField,tranField(iTran)) ) {
7150 0 : if (tranField(iTran)>-1 && tranField(iTran) < nMSFld) x << fldNames(tranField(iTran)) << " ";
7151 0 : else x << "Index="<<tranField(iTran)+1<<"=out-of-range ";
7152 : }
7153 : }
7154 0 : String noTranSol=x.str();
7155 0 : if (x!="") {
7156 : logSink() << LogIO::WARN
7157 : << " The following transfer fields have no solutions available: "
7158 : << noTranSol
7159 0 : << LogIO::POST;
7160 : }
7161 : //tranField.reference(implTranField);
7162 : }
7163 : }
7164 0 : tranField.shape(nTran);
7165 :
7166 : // make a combined field list
7167 0 : std::vector<Int> allfields(refField.begin(), refField.end());
7168 0 : allfields.insert(allfields.end(), tranField.begin(), tranField.end());
7169 :
7170 : // Report ref, tran field info
7171 0 : String refNames(fldNames(refField(0)));
7172 0 : for (Int iRef=1; iRef<nRef; iRef++) {
7173 0 : refNames+=" ";
7174 0 : refNames+=fldNames(refField(iRef));
7175 : }
7176 : logSink() << " Found reference field(s): " << refNames
7177 0 : << LogIO::POST;
7178 0 : String tranNames(fldNames(tranField(0)));
7179 0 : for (Int iTran=1; iTran<nTran; iTran++) {
7180 0 : tranNames+=" ";
7181 0 : tranNames+=fldNames(tranField(iTran));
7182 : }
7183 : logSink() << " Found transfer field(s): " << tranNames
7184 0 : << LogIO::POST;
7185 :
7186 : // Handle spw referencing
7187 0 : Vector<Int> refSpwMap;
7188 0 : refSpwMap.resize(nSpw());
7189 0 : indgen(refSpwMap);
7190 :
7191 0 : if (inRefSpwMap(0)>-1) {
7192 0 : if (inRefSpwMap.nelements()==1) {
7193 0 : refSpwMap=inRefSpwMap(0);
7194 0 : logSink() << " All spectral windows will be referenced to spw=" << inRefSpwMap(0)
7195 0 : << LogIO::POST;
7196 : } else {
7197 0 : for (Int i=0; i<Int(inRefSpwMap.nelements()); i++) {
7198 0 : if (inRefSpwMap(i)>-1 && inRefSpwMap(i)!=i) {
7199 0 : refSpwMap(i)=inRefSpwMap(i);
7200 0 : logSink() << " Spw=" << i << " will be referenced to spw=" << inRefSpwMap(i)
7201 0 : << LogIO::POST;
7202 : }
7203 : }
7204 : }
7205 : }
7206 :
7207 : // Field names for log messages
7208 :
7209 : // cout << "Filling mgnorms....";
7210 :
7211 0 : Matrix<Float> medianGains(nFld,nSpw(),0.0); //keeps median (amplitude) gains for each field for each spw
7212 : { // make an inner scope
7213 0 : Block<String> cols(4);
7214 0 : cols[0]="SPECTRAL_WINDOW_ID";
7215 0 : cols[1]="TIME";
7216 0 : cols[2]="FIELD_ID"; // should usually be degenerate with TIME?
7217 0 : cols[3]="ANTENNA1";
7218 : //ROCTIter ctiter(*ct_,cols);
7219 :
7220 : // Loop over solutions and fill the calculation
7221 0 : Cube<Bool> mgok; // For referencing PtrBlocks...
7222 0 : Cube<Double> mg;
7223 0 : Cube<Double> mg2;
7224 0 : Cube<Double> mgwt;
7225 0 : Cube<Int> mgn;
7226 0 : Cube<Int> mgnall;
7227 0 : Int prevFld(-1);
7228 :
7229 0 : Int lastFld(-1);
7230 :
7231 : // determine median gain amplitude for each field
7232 : // use CTinterface to appy selection with MSSelection syntax
7233 0 : NewCalTable selct(*ct_);
7234 0 : CTInterface cti(*ct_);
7235 0 : Vector<Int> selAntList;
7236 0 : Vector<Int> deselAntList;
7237 0 : Vector<Int> allAntList(nElem());
7238 0 : indgen(allAntList);
7239 0 : vector<Int> tmpAllAntList(allAntList.begin(),allAntList.end());
7240 : //
7241 : // Check if antenna specific time/scan selection is needed.
7242 : // If so get selected time col for later use to flag the data.
7243 : // The negation '!' is used as a keyword to trigger such a selection mode.
7244 0 : Bool doPerAntSel(false);
7245 0 : Vector<Double> selTime;
7246 0 : if (antSel!="" ) {
7247 0 : if (antSel.contains(casacore::Regex("^!")) && (timerangeSel!="" || scanSel!="")) {
7248 0 : doPerAntSel = true;
7249 : // if doPerAntSel time/scan sel only applied to deselected ant in antSel
7250 : // so need to construct selected table based on that
7251 0 : MSSelection msssub;
7252 0 : String antsel=antSel;
7253 0 : antsel.ltrim('!');
7254 0 : msssub.setAntennaExpr(antsel);
7255 0 : if (timerangeSel != "") msssub.setTimeExpr(timerangeSel);
7256 0 : if (scanSel != "") msssub.setScanExpr(scanSel);
7257 0 : TableExprNode tensub=msssub.toTableExprNode(&cti);
7258 0 : getSelectedTable(selct,*ct_,tensub,"");
7259 0 : ROCTMainColumns ctmc(selct);
7260 0 : selTime=ctmc.time().getColumn();
7261 0 : deselAntList=ctmc.antenna1().getColumn();
7262 0 : Int ndeselAnt=genSort(deselAntList,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
7263 0 : deselAntList.resize(ndeselAnt,true);
7264 : }
7265 : }
7266 :
7267 0 : Bool firstpass(true);
7268 0 : for (Int iFld=0; iFld<nFld; iFld++) {
7269 :
7270 0 : MSSelection mss;
7271 : //String antSel("!ea25");
7272 : //String antSel("0~26");
7273 : //String antSel("");
7274 0 : mss.setFieldExpr(String::toString(iFld));
7275 0 : if (antSel!="") {
7276 0 : if (!doPerAntSel) {
7277 : // applied selections globally
7278 0 : mss.setAntennaExpr(antSel);
7279 0 : if (timerangeSel!="") mss.setTimeExpr(timerangeSel);
7280 0 : if (scanSel!="") mss.setScanExpr(scanSel);
7281 : }
7282 : } else {
7283 0 : selAntList=allAntList;
7284 : }
7285 0 : std::vector<Int> tmpSelAntList;
7286 0 : Vector<Bool> validSels(nSpw(),true);
7287 0 : for (Int iSpw=0; iSpw<nSpw(); iSpw++) {
7288 : //reset MSSelection
7289 0 : mss.clear(MSSelection::SPW_EXPR);
7290 : //mss.setFieldExpr(String::toString(iFld));
7291 0 : mss.setSpwExpr(String::toString(iSpw));
7292 : try {
7293 0 : TableExprNode ten=mss.toTableExprNode(&cti);
7294 0 : getSelectedTable(selct,*ct_,ten,"");
7295 0 : ROCTMainColumns ctmc(selct);
7296 0 : Array<Float> outparams;
7297 0 : Array<Bool> flagcol=ctmc.flag().getColumn();
7298 0 : Vector<Double> timecol=ctmc.time().getColumn();
7299 0 : Vector<Int> antenna1=ctmc.antenna1().getColumn();
7300 : // Do antenna-specific the selections in time
7301 0 : IPosition flshp = flagcol.shape();
7302 0 : if (doPerAntSel && selTime.nelements()!=0) {
7303 0 : for (uInt ifg = 0; ifg < flshp(2); ifg++) {
7304 0 : for (Int ipar = 0; ipar < nPar(); ipar++) {
7305 0 : if (anyEQ(deselAntList, antenna1(ifg)) && !anyEQ(selTime, timecol(ifg)))
7306 : //outflag(IPosition(3,ipar,0,ifg))=false;
7307 0 : flagcol(IPosition(3,ipar,0,ifg))=true;
7308 : }
7309 : }
7310 : }
7311 : // reverse the flag for a masked array
7312 0 : LogicalArray outflag(!flagcol);
7313 : //cerr<<"ntrue outflag ="<<ntrue(outflag)<<endl;
7314 0 : ctmc.fparamArray(outparams,"AP");
7315 : // get subset (amp only) of the array
7316 0 : IPosition arshp = outparams.shape();
7317 0 : IPosition start(3,0,0,0);
7318 0 : Int pinc = nPar()!=1 ? 2: 1;
7319 0 : Int pshp = arshp(0)!=1 ? Int(arshp(0)/2) : 1;
7320 : //IPosition length(3,Int(arshp(0)/pinc),1,arshp(arshp.nelements()-1));
7321 0 : IPosition length(3,pshp,1,arshp(arshp.nelements()-1));
7322 0 : IPosition stride(3,pinc,1,1);
7323 0 : Slicer slicer(start,length,stride);
7324 0 : Array<Float> subarr=outparams(slicer);
7325 0 : MaskedArray<Float> moutparams(subarr,outflag);
7326 : //Vector<Float> subarr2 = moutparams.getCompressedArray();
7327 : // Get selected antenna list in ant ids.
7328 : // While it is applied to all fields and spws
7329 : // the actual selections happen per spw. So we do it here but only for the first
7330 : // successful selection for the data and use it for the rest of the process.
7331 0 : if (antSel!="" && firstpass) {
7332 0 : Vector<Int> selantlist=ctmc.antenna1().getColumn();
7333 0 : Int nSelAnt=genSort(selantlist,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
7334 0 : selantlist.resize(nSelAnt,true);
7335 0 : selAntList=selantlist;
7336 : //cerr<<"selantlist.nelements()="<<selantlist.nelements()<<endl;
7337 0 : String oMsg( "" );
7338 0 : if ( doPerAntSel ) {
7339 0 : oMsg+="Selected data range for antenna(s): "+String::toString(deselAntList)+",";
7340 0 : if ( timerangeSel!="") oMsg+= " time range:"+timerangeSel;
7341 0 : if ( scanSel!="") oMsg+= " scan(s):"+scanSel;
7342 : }
7343 : else {
7344 0 : oMsg+=" Selected antennas: "+String::toString(selAntList);
7345 : }
7346 0 : logSink() << oMsg << LogIO::POST;
7347 0 : firstpass=false;
7348 : }
7349 :
7350 : //medianGains(iFld,iSpw)=median(subarr2);
7351 0 : medianGains(iFld,iSpw)=median(moutparams);
7352 0 : String oMsg( "" );
7353 0 : oMsg+="median(field="+String::toString(iFld)+",spw="+String::toString(iSpw)+")="+\
7354 0 : String::toString(medianGains(iFld,iSpw));
7355 0 : logSink() << LogIO::NORMAL3<< oMsg << LogIO::POST;
7356 0 : } catch (...) {
7357 0 : if (anyEQ(tranField,iFld)) validSels[iSpw]=false;
7358 : }
7359 : }
7360 0 : if (!ntrue(validSels))
7361 : throw(AipsError("The input selections results in empy data selection for the transfer field="
7362 0 : +String::toString(iFld)));
7363 : } //for-iFld
7364 0 : NewCalTable selct2(*ct_);
7365 0 : CTInterface cti2(*ct_);
7366 0 : MSSelection mss2;
7367 0 : String fieldstr;
7368 0 : for (uInt iselfld=0; iselfld<allfields.size();iselfld++) {
7369 0 : fieldstr+=String::toString(allfields[iselfld]);
7370 0 : if (iselfld!=allfields.size()-1) fieldstr+=',';
7371 : }
7372 0 : mss2.setFieldExpr(fieldstr);
7373 0 : if (!doPerAntSel) {
7374 0 : mss2.setAntennaExpr(antSel);
7375 0 : mss2.setTimeExpr(timerangeSel);
7376 0 : mss2.setScanExpr(scanSel);
7377 : }
7378 0 : TableExprNode ten2=mss2.toTableExprNode(&cti2);
7379 0 : getSelectedTable(selct2,*ct_,ten2,"");
7380 :
7381 0 : ROCTIter ctiter(selct2,cols);
7382 0 : while (!ctiter.pastEnd()) {
7383 0 : Int iSpw(ctiter.thisSpw());
7384 0 : Int iFld(ctiter.thisField());
7385 0 : Int iAnt(ctiter.thisAntenna1());
7386 : //refTime_ = ctiter.thisTime();
7387 0 : if (iFld > prevFld) {
7388 0 : mgreft = ctiter.thisTime();
7389 : }
7390 0 : prevFld = iFld;
7391 :
7392 0 : if (solFreq(iSpw)<0.0) {
7393 0 : Vector<Double> freq;
7394 0 : ctiter.freq(freq);
7395 0 : uInt nFrq=freq.nelements();
7396 0 : solFreq(iSpw)=freq(nFrq/2);
7397 : }
7398 :
7399 0 : if (MGOK[iFld]==NULL) {
7400 : // First time this field, allocate ant/spw matrices
7401 0 : MGOK[iFld] = new Cube<Bool>(nPar(),nElem(),nSpw(),false);
7402 0 : MG[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7403 0 : MG2[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7404 0 : MGWT[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7405 0 : MGVAR[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7406 0 : MGN[iFld] = new Cube<Int>(nPar(),nElem(),nSpw(),0);
7407 : // for reporting numbers of solution used
7408 0 : MGNALL[iFld] = new Cube<Int>(nPar(),nElem(),nSpw(),0);
7409 :
7410 : }
7411 : // References to PBs for syntactical convenience
7412 : // TBD: should need to do this for each iteration (nAnt times redundant!)
7413 0 : if (iFld!=lastFld) {
7414 0 : mgok.reference(*(MGOK[iFld]));
7415 0 : mg.reference(*(MG[iFld]));
7416 0 : mg2.reference(*(MG2[iFld]));
7417 0 : mgwt.reference(*(MGWT[iFld]));
7418 0 : mgn.reference(*(MGN[iFld]));
7419 0 : mgnall.reference(*(MGNALL[iFld]));
7420 : }
7421 :
7422 : // References to PBs for syntactical convenience
7423 : // TBD: Handle "iFitwt" from NewCalTable?
7424 : // Double wt=cs().iFitwt(iSpw)(iAnt,islot);
7425 0 : Double wt=1;
7426 :
7427 : // amps, flags [npar] (one channel, one antenna)
7428 : // check for data shape (e.g. duplicated entries)
7429 0 : Cube<Complex> CParam(ctiter.cparam());
7430 0 : IPosition testShape=CParam.shape();
7431 0 : if (testShape[2]!=1) {
7432 0 : if (testShape[2]>1) {
7433 : // possible cause: append=true in gaincal
7434 0 : throw(AipsError("Found multiple gain solutions in a single timestamp for fieldid="+String::toString(iFld)+". Please check the input Caltable."));
7435 : }
7436 : else {
7437 0 : throw(AipsError("Found gain solution array shape, "+String::toString(testShape)+" while expected [2,1,1]. Please check the input Caltable."));
7438 : }
7439 : }
7440 : //Vector<Float> amp(amplitude(ctiter.cparam())[0]);
7441 0 : Vector<Float> amp(amplitude(CParam));
7442 0 : Vector<Bool> fl(ctiter.flag());
7443 0 : for (Int ipar=0; ipar<nPar(); ipar++) {
7444 0 : if (!fl(ipar)) {
7445 0 : Double gn=amp(ipar); // converts to Double
7446 : // evaluate input gain to be within the threshold
7447 0 : Float lowbound= (inGainThres >0 and inGainThres <1.0)? 1.0 - inGainThres : 0.0;
7448 0 : if (inGainThres==0) lowbound=1.0;
7449 : //if ((anyEQ(selAntList,iAnt) && && (inGainThres < 0 ||
7450 0 : if (inGainThres < 0 ||
7451 : // (gn >= lowbound*medianGains(iFld,iSpw))) {
7452 : // take both lower and upper bounds
7453 0 : (gn >= lowbound*medianGains(iFld,iSpw) and
7454 0 : gn <= (1.0 + inGainThres) * medianGains(iFld,iSpw))) {
7455 :
7456 0 : if (doPerAntSel && selTime.nelements() != 0) {
7457 0 : if (anyEQ(deselAntList,iAnt) && !anyEQ(selTime,ctiter.thisTime())) {
7458 0 : logSink()<<LogIO::NORMAL3<<"skipped "<<ctiter.thisTime()<<" for iAnt="<<iAnt<<LogIO::POST;
7459 0 : continue;
7460 : }
7461 : }
7462 : //cerr<<"fld="<<iFld<<" spw="<<iSpw<<" ant="<<iAnt<<" gn="<<gn<<" median="<<medianGains(iFld,iSpw)<<endl;
7463 0 : mgok(ipar,iAnt,iSpw)=true;
7464 0 : mg(ipar,iAnt,iSpw) += (wt*gn);
7465 0 : mg2(ipar,iAnt,iSpw)+= (wt*gn*gn);
7466 0 : mgn(ipar,iAnt,iSpw)++;
7467 0 : mgwt(ipar,iAnt,iSpw)+=wt;
7468 : }
7469 : else {
7470 0 : String debugMsg( "" );
7471 0 : debugMsg+="Rejected field="+String::toString(iFld)+" spw="+String::toString(iSpw)+" antenna="+String::toString(iAnt)+
7472 0 : "; gain(amp)="+String::toString(gn)+" is outside the accepted range:"+String::toString(lowbound*medianGains(iFld,iSpw))+
7473 0 : " ~ "+String::toString((1.0 + inGainThres) * medianGains(iFld,iSpw));
7474 0 : logSink() << LogIO::DEBUG1 << debugMsg << LogIO::POST;
7475 : }
7476 0 : mgnall(ipar,iAnt,iSpw)++;
7477 : }
7478 : }
7479 0 : lastFld=iFld;
7480 0 : ctiter.next();
7481 : }//end of while
7482 : } // end inner scope
7483 :
7484 : //for reporting only
7485 0 : if (inGainThres>=0.0) {
7486 0 : String oMsg( "" );
7487 0 : oMsg+=" Applying gain threshold="+String::toString(inGainThres);
7488 0 : logSink() << oMsg << LogIO::POST;
7489 0 : Bool hasFlaggedData(false);
7490 : //for (Int iFld=0; iFld<nFld; iFld++) {
7491 : Int iFld;
7492 0 : for (int idx=0; idx < (int) allfields.size(); idx++) {
7493 0 : iFld = allfields[idx];
7494 0 : if (MGOK[iFld]!=NULL) {
7495 0 : Cube<Bool> mgok; mgok.reference(*(MGOK[iFld]));
7496 0 : Cube<Int> mgn; mgn.reference(*(MGN[iFld]));
7497 0 : Cube<Int> mgnall; mgnall.reference(*(MGNALL[iFld]));
7498 : //cerr<<"ntrue="<<ntrue(mgok)<< " shape="<<mgok.shape()<<endl;
7499 : //cerr<<"mgn shape="<<mgn.shape()<<endl;
7500 : //cerr<<"mgnall shape="<<mgnall.shape()<<endl;
7501 0 : for (Int iSpw=0; iSpw<nSpw(); iSpw++) {
7502 : //cerr<<"median gain="<<medianGains(iFld,iSpw)<<endl;
7503 0 : for (Int iAnt=0; iAnt<nElem(); iAnt++) {
7504 0 : IPosition start(3,0,iAnt,iSpw);
7505 0 : IPosition length(3,nPar(),1,1);
7506 0 : IPosition stride(3,1,1,1);
7507 0 : Slicer slicer(start,length,stride);
7508 : //if (ntrue(mgok(slicer))) {
7509 0 : if ( sum(mgn(slicer))<sum(mgnall(slicer)) ) {
7510 : //cerr<<"iFld:"<<iFld<<" iAnt:"<<iAnt<<" sum(mgn)="<<sum(mgn(slicer))<<" sum(mgnall(slicer))="<<sum(mgnall(slicer))<<endl;
7511 0 : Float frac=Float (sum(mgn(slicer)))/Float (sum(mgnall(slicer)));
7512 0 : ostringstream fracstream;
7513 0 : fracstream.precision(3);
7514 0 : if (frac<1.0) {
7515 : // report a fraction flagged
7516 0 : fracstream << (1.0-frac)*100.0;
7517 0 : oMsg="";
7518 : //cerr<<"iFld="<<iFld<<" iAnt="<<iAnt<<": "<<frac*100.0<<"% of "<<sum(mgnall(slicer))<<" will be excluded"<<endl;
7519 : //oMsg+=" Field ID="+String::toString(tranField(iFld))+" Antenna ID="+String::toString(iAnt)+": ";
7520 : //oMsg+=" Field ID="+String::toString(allfields[idx])+" Antenna ID="+String::toString(iAnt)+": ";
7521 0 : oMsg+=" "+fldNames(allfields[idx])+"(id="+String::toString(allfields[idx])+") Antenna:"+antNames(iAnt)+"(id="+String::toString(iAnt)+"): ";
7522 0 : oMsg+=fracstream.str()+" % of ";
7523 : //oMsg+=String::toString(sum(mgnall(slicer)) )+" solutions will be used";
7524 0 : oMsg+=String::toString(sum(mgnall(slicer)) )+" solution(s) will be excluded";
7525 0 : logSink() << oMsg << LogIO::POST;
7526 : }
7527 0 : hasFlaggedData=true;
7528 : }//ntrue()
7529 : } //iAnt
7530 : } //iSpw
7531 : }
7532 : }//iFld
7533 0 : if (!hasFlaggedData) {
7534 0 : oMsg=" None of the gains were exceeded the threshold.";
7535 0 : logSink() << oMsg << LogIO::POST;
7536 : }
7537 : }//gainthreshold
7538 : /*
7539 :
7540 : // fill per-ant -fld, -spw mean gain moduli
7541 : for (Int iSpw=0; iSpw<nSpw(); iSpw++) {
7542 :
7543 : if (cs().nTime(iSpw) > 0 ) {
7544 :
7545 : for (Int islot=0; islot<cs().nTime(iSpw); islot++) {
7546 : Int iFld=cs().fieldId(iSpw)(islot);
7547 : if (MGOK[iFld]==NULL) {
7548 : // First time this field, allocate ant/spw matrices
7549 : MGOK[iFld] = new Cube<Bool>(nPar(),nElem(),nSpw(),false);
7550 : MG[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7551 : MG2[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7552 : MGWT[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7553 : MGVAR[iFld] = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
7554 : MGN[iFld] = new Cube<Int>(nPar(),nElem(),nSpw(),0);
7555 :
7556 : }
7557 : // References to PBs for syntactical convenience
7558 : Cube<Bool> mgok; mgok.reference(*(MGOK[iFld]));
7559 : Cube<Double> mg; mg.reference(*(MG[iFld]));
7560 : Cube<Double> mg2; mg2.reference(*(MG2[iFld]));
7561 : Cube<Double> mgwt; mgwt.reference(*(MGWT[iFld]));
7562 : Cube<Int> mgn; mgn.reference(*(MGN[iFld]));
7563 :
7564 : for (Int iAnt=0; iAnt<nElem(); iAnt++) {
7565 : if (true) { // || antmask(iAnt)) {
7566 : Double wt=cs().iFitwt(iSpw)(iAnt,islot);
7567 :
7568 : for (Int ipar=0; ipar<nPar(); ipar++) {
7569 : IPosition ip(4,ipar,0,iAnt,islot);
7570 : if (cs().parOK(iSpw)(ip)) {
7571 : Double gn=abs( cs().par(iSpw)(ip) );
7572 : mgok(ipar,iAnt,iSpw)=true;
7573 : mg(ipar,iAnt,iSpw) += (wt*gn);
7574 : mg2(ipar,iAnt,iSpw)+= (wt*gn*gn);
7575 : mgn(ipar,iAnt,iSpw)++;
7576 : mgwt(ipar,iAnt,iSpw)+=wt;
7577 : }
7578 : }
7579 : }
7580 : }
7581 : }
7582 : }
7583 : }
7584 : */
7585 :
7586 : // cout << "done." << endl;
7587 :
7588 : // cout << "Normalizing mgs...";
7589 :
7590 :
7591 : // normalize mg
7592 0 : for (Int iFld=0; iFld<nFld; iFld++) {
7593 :
7594 : // cout << "iFld = " << iFld << " " << MGOK[iFld]->column(0) << endl;
7595 :
7596 : // Have data for this field?
7597 0 : if (MGOK[iFld]!=NULL) {
7598 : // References to PBs for syntactical convenience
7599 0 : Cube<Bool> mgok; mgok.reference(*(MGOK[iFld]));
7600 0 : Cube<Double> mg; mg.reference(*(MG[iFld]));
7601 0 : Cube<Double> mg2; mg2.reference(*(MG2[iFld]));
7602 0 : Cube<Double> mgwt; mgwt.reference(*(MGWT[iFld]));
7603 0 : Cube<Double> mgvar; mgvar.reference(*(MGVAR[iFld]));
7604 0 : Cube<Int> mgn; mgn.reference(*(MGN[iFld]));
7605 :
7606 0 : for (Int iSpw=0; iSpw<nSpw(); iSpw++) {
7607 0 : for (Int iAnt=0; iAnt<nElem(); iAnt++) {
7608 0 : for (Int ipar=0;ipar<nPar(); ++ipar) {
7609 0 : if ( mgok(ipar,iAnt,iSpw) && mgwt(ipar,iAnt,iSpw)>0.0 ) {
7610 0 : mg(ipar,iAnt,iSpw)/=mgwt(ipar,iAnt,iSpw);
7611 0 : mg2(ipar,iAnt,iSpw)/=mgwt(ipar,iAnt,iSpw);
7612 : // Per-ant, per-spw variance (non-zero only if sufficient data)
7613 0 : if (mgn(ipar,iAnt,iSpw) > 2) {
7614 0 : mgvar(ipar,iAnt,iSpw) = (mg2(ipar,iAnt,iSpw) - pow(mg(ipar,iAnt,iSpw),2.0))/(mgn(ipar,iAnt,iSpw)-1);
7615 : }
7616 : } else {
7617 0 : mg(ipar,iAnt,iSpw)=0.0;
7618 0 : mgwt(ipar,iAnt,iSpw)=0.0;
7619 0 : mgok(ipar,iAnt,iSpw)=false;
7620 : }
7621 : }
7622 : /*
7623 : cout << " iSpw = " << iSpw << " iFld = " << iFld;
7624 : cout << " iAnt = " << iAnt;
7625 : cout << " mg = " << mg(iAnt,iSpw);
7626 : cout << " +/- " << sqrt(1.0/mgwt(iAnt,iSpw));
7627 : cout << " SNR = " << mg(iAnt,iSpw)/sqrt(1.0/mgwt(iAnt,iSpw));
7628 : cout << " " << mgn(iAnt,iSpw);
7629 : cout << endl;
7630 : */
7631 : }
7632 : }
7633 :
7634 : } //if-MGOK end
7635 : }
7636 :
7637 :
7638 : // cout << "done." << endl;
7639 : // cout << "nTran = " << nTran << endl;
7640 :
7641 : // cout << "Calculating scale factors...";
7642 :
7643 : // Collapse ref field mg's into a single ref
7644 0 : Cube<Double> mgref;
7645 0 : Cube<Bool> mgrefok;
7646 0 : mgref.reference(*MG[refField(0)]);
7647 0 : mgrefok.reference(*MGOK[refField(0)]);
7648 :
7649 0 : if (nRef>1) {
7650 : //Store no. of fields that is not flagged per pol,ant,and spw
7651 0 : Cube<Double> nokref(nPar(),nElem(),nSpw(),0);
7652 : // Add on additional ref fields
7653 0 : for (Int iref=1;iref<nRef;++iref) {
7654 :
7655 0 : Cube<Bool> mgokR; mgokR.reference(*MGOK[refField(iref)]);
7656 0 : Cube<Double> mgR; mgR.reference(*MG[refField(iref)]);
7657 :
7658 0 : for (Int ispw=0;ispw<nSpw();++ispw) {
7659 0 : for (Int iant=0;iant<nAnt();++iant) {
7660 0 : for (Int ipar=0;ipar<nPar();++ipar) {
7661 0 : if (iref==1) {
7662 0 : if (mgrefok(ipar,iant,ispw)) {
7663 0 : nokref(ipar,iant,ispw)+=1.0;
7664 : }
7665 : else {// the first ref field of this gain is flagged
7666 0 : mgref(ipar,iant,ispw)=0.0;
7667 : }
7668 : }
7669 :
7670 0 : if (mgokR(ipar,iant,ispw)) {
7671 0 : mgref(ipar,iant,ispw)+=mgR(ipar,iant,ispw);
7672 0 : nokref(ipar,iant,ispw)+=1.0;
7673 : }
7674 :
7675 : // at the last ref field...
7676 0 : if(iref==nRef-1 ) {
7677 0 : if (nokref(ipar,iant,ispw)==0.0) {
7678 0 : mgrefok(ipar,iant,ispw)=false;
7679 0 : mgref(ipar,iant,ispw)=0.0;
7680 : }
7681 : else {
7682 : // overwrite to turn to true for the case of mgrefok=false for refField(0)
7683 0 : mgrefok(ipar,iant,ispw)=true;
7684 : }
7685 : }
7686 :
7687 : // Replaced this with above to support flagged ref field case(CAS-4758) - TT
7688 : //if (mgrefok(ipar,iant,ispw) && mgokR(ipar,iant,ispw))
7689 : // mgref(ipar,iant,ispw)+=mgR(ipar,iant,ispw);
7690 : // else {
7691 : // mgrefok(ipar,iant,ispw)=false;
7692 : // mgref(ipar,iant,ispw)=0.0;
7693 : //}
7694 :
7695 : } // ipar
7696 : } // iant
7697 : } // ispw
7698 : } // iref
7699 : // Complete the average:
7700 : //mgref/=Double(nRef);
7701 0 : mgref/=nokref; // only count unflagged ones
7702 : } // nRef > 1
7703 :
7704 : // Scale factor calculation, per trans fld, per spw
7705 0 : Matrix<Double> fd( nSpw(), nFld, -1.0 );
7706 0 : Matrix<Double> fderr( nSpw(), nFld, -1.0 );
7707 0 : Matrix<Double> fdrms(nSpw(),nFld,-1.0);
7708 0 : Matrix<Int> numSol( nSpw(), nFld, -1 );
7709 : // fd.resize(nSpw(),nFld);
7710 : // fd.set(-1.0);
7711 : // fderr.resize( nSpw(), nFld );
7712 : // fderr.set( -1.0 );
7713 : // numSol.resize( nSpw() );
7714 : // numSol.set( -1 );
7715 :
7716 0 : Matrix<Bool> scaleOK(nSpw(),nFld,false);
7717 0 : Matrix<Double> mgratio(nSpw(),nFld,-1.0);
7718 0 : Matrix<Double> mgrms(nSpw(),nFld,-1.0);
7719 0 : Matrix<Double> mgerr(nSpw(),nFld,-1.0);
7720 :
7721 0 : for (Int iTran=0; iTran<nTran; iTran++) {
7722 :
7723 0 : Int tranidx=tranField(iTran);
7724 0 : if (MGOK[tranidx]!=NULL) {
7725 : // References to PBs for syntactical convenience
7726 0 : Cube<Bool> mgokT; mgokT.reference(*(MGOK[tranidx]));
7727 0 : Cube<Double> mgT; mgT.reference(*(MG[tranidx]));
7728 0 : Cube<Double> mgvarT; mgvarT.reference(*(MGVAR[tranidx]));
7729 0 : Cube<Double> mgwtT; mgwtT.reference(*(MGWT[tranidx]));
7730 0 : if (report_p) {
7731 0 : setupPlotter();
7732 : }
7733 0 : int countvalidspw = 0;
7734 0 : for (Int ispw=0; ispw<nSpw(); ispw++) {
7735 : // Reference spw may be different
7736 0 : Int refSpw(refSpwMap(ispw));
7737 :
7738 : // Only if anything good for this spw
7739 0 : if (ntrue(mgokT.xyPlane(ispw)) > 0) {
7740 :
7741 0 : for (Int iant=0;iant<nAnt();++iant) {
7742 0 : for (Int ipar=0;ipar<nPar();++ipar) {
7743 0 : if (mgokT(ipar,iant,ispw) &&
7744 0 : mgrefok(ipar,iant,refSpw) &&
7745 0 : mgref(ipar,iant,refSpw)>0.0 ) {
7746 0 : mgT(ipar,iant,ispw)/=mgref(ipar,iant,refSpw);
7747 : }
7748 : else {
7749 0 : mgT(ipar,iant,ispw)=0.0;
7750 0 : mgokT(ipar,iant,ispw)=false;
7751 : }
7752 : } // ipar
7753 : } // iant
7754 : } // ntrue>0
7755 :
7756 : // Form the mean gain ratio
7757 0 : Matrix<Double> mgTspw(mgT.xyPlane(ispw));
7758 0 : Matrix<Bool> mgokTspw(mgokT.xyPlane(ispw));
7759 0 : cout.precision(6);
7760 0 : cout.setf(ios::fixed,ios::floatfield);
7761 0 : Int nPA=ntrue(mgokTspw);
7762 0 : if (nPA>0) {
7763 :
7764 : // for plotting
7765 0 : if (report_p) {
7766 : //cerr<<"plotting for each spw..."<<endl;
7767 0 : String hlab = "Fld:"+String::toString(tranidx)+" Spw:"+String::toString(ispw)+
7768 0 : " median="+String::toString(medianGains(tranidx,ispw));
7769 0 : Vector<Double> tempvec;
7770 0 : tempvec=mgTspw(mgokTspw).getCompressedArray();
7771 : // determine nbins by Scott's rule
7772 : Double minv, maxv;
7773 0 : minMax(minv,maxv,tempvec);
7774 0 : Double binw = 3.49*stddev(tempvec)/pow(Double (tempvec.nelements()), 1./3.);
7775 0 : Int inNbins = Int (ceil ((maxv-minv)/binw));
7776 0 : plotHistogram(hlab,countvalidspw,tempvec,inNbins);
7777 0 : countvalidspw++;
7778 : }
7779 :
7780 : // cout << "mgTspw = " << mgTspw << endl;
7781 0 : scaleOK(ispw,tranidx)=true;
7782 : //mgratio(ispw,tranidx)=mean(mgTspw(mgokTspw));
7783 0 : mgratio(ispw,tranidx)=median(mgTspw(mgokTspw));
7784 0 : if (nPA==1) { // flux scaling based on a single gain ratio...
7785 0 : mgrms(ispw,tranidx)=0.0;
7786 0 : mgerr(ispw,tranidx)=0.0;
7787 : }
7788 : else {
7789 0 : mgrms(ispw,tranidx)=stddev(mgTspw(mgokTspw));
7790 0 : mgerr(ispw,tranidx)=mgrms(ispw,tranidx)/sqrt(Double(nPA-1));
7791 : }
7792 : // ...and flux density estimate
7793 0 : fd(ispw,tranidx)=mgratio(ispw,tranidx)*mgratio(ispw,tranidx);
7794 0 : fdrms(ispw,tranidx)=2.0*mgrms(ispw,tranidx);
7795 0 : if (nPA==1) {
7796 0 : fderr(ispw,tranidx)=0.0;
7797 : }
7798 : else {
7799 0 : fderr(ispw,tranidx)=fdrms(ispw,tranidx)/sqrt(Double(nPA-1));
7800 : }
7801 0 : numSol(ispw,tranidx) = nPA;
7802 : }
7803 :
7804 : // Compose the fit message for the list file and the log
7805 :
7806 0 : String oMsg( "" );
7807 :
7808 0 : oMsg += " Flux density for ";
7809 0 : oMsg += fldNames(tranidx);
7810 0 : oMsg += " in SpW=";
7811 0 : oMsg += String::toString<Int>( ispw );
7812 0 : if (scaleOK(ispw,tranidx)) {
7813 0 : oMsg += " (freq=";
7814 0 : oMsg += String::toString<Double>(solFreq(ispw));
7815 0 : oMsg += " Hz)";
7816 : }
7817 :
7818 0 : if ( refSpw != ispw ) {
7819 0 : oMsg += " (ref SpW=";
7820 0 : oMsg += String::toString<Int>( refSpw );
7821 0 : oMsg += ")";
7822 : }
7823 :
7824 0 : oMsg += " is: ";
7825 :
7826 0 : if ( scaleOK(ispw,tranidx) ) {
7827 0 : oMsg += String::toString<Double>( fd(ispw,tranidx) );
7828 0 : oMsg += " +/- ";
7829 0 : oMsg += String::toString<Double>( fderr(ispw,tranidx) );
7830 0 : oMsg += " (SNR = ";
7831 0 : oMsg += String::toString<Double>( fd(ispw,tranidx)/fderr(ispw,tranidx) );
7832 0 : oMsg += ", N = ";
7833 0 : oMsg += String::toString<Int>( nPA );
7834 0 : oMsg += ")";
7835 : } else {
7836 0 : oMsg += " INSUFFICIENT DATA ";
7837 : }
7838 :
7839 : // Write the fit message to the output list file if the file name is
7840 : // non-null. In the first iteration (first transfer field and spw),
7841 : // open the list file and truncate any previous version. In subsequent
7842 : // iterations, append the messages.
7843 :
7844 0 : if ( oListFile != "" ) {
7845 0 : ofstream oStream;
7846 0 : if ( iTran == 0 && ispw == 0 ) {
7847 0 : oStream.open( oListFile.chars(), ios::out|ios::trunc );
7848 : } else {
7849 0 : oStream.open( oListFile.chars(), ios::out|ios::app );
7850 : }
7851 0 : oStream << "#" << oMsg << endl << flush;
7852 0 : oStream.close();
7853 : }
7854 :
7855 :
7856 : // Write the fit message to the logger
7857 :
7858 0 : logSink() << oMsg << LogIO::POST;
7859 :
7860 : /*
7861 : // Report flux densities to logger
7862 : logSink() << " Flux density for " << fldNames(tranidx)
7863 : << " in SpW=" << ispw;
7864 : if (refSpw!=ispw)
7865 : logSink() << " (ref SpW=" << refSpw << ")";
7866 :
7867 : logSink() << " is: ";
7868 : if (scaleOK(ispw,tranidx)) {
7869 : logSink() << fd(ispw,tranidx)
7870 : << " +/- " << fderr(ispw,tranidx)
7871 : << " (SNR = " << fd(ispw,tranidx)/fderr(ispw,tranidx)
7872 : << ", N= " << nPA << ")";
7873 : }
7874 : else
7875 : logSink() << " INSUFFICIENT DATA ";
7876 :
7877 : logSink() << LogIO::POST;
7878 : */
7879 : } // ispw
7880 : }
7881 : } // iTran
7882 : // max 3 coefficients
7883 : //Matrix<Double> spidx(nFld,3,0.0);
7884 : //Matrix<Double> spidxerr(nFld,3,0.0);
7885 0 : Matrix<Double> spidx(nFld,fitorder+1,0.0);
7886 0 : Matrix<Double> spidxerr(nFld,fitorder+1,0.0);
7887 0 : Matrix<Double> covar;
7888 0 : Vector<Double> fitFluxD(nFld,0.0);
7889 0 : Vector<Double> fitFluxDErr(nFld,0.0);
7890 0 : Vector<Double> fitRefFreq(nFld,0.0);
7891 : //PtrBlock<Matrix<Double> *> covarList(nFld);
7892 0 : Vector<Matrix<Double> > covarList(nFld);
7893 : //Vector<Double> refFreq(nFld,0.0);
7894 :
7895 0 : for (Int iTran=0; iTran<nTran; iTran++) {
7896 0 : uInt tranidx=tranField(iTran);
7897 0 : Int nValidFlux=ntrue(scaleOK.column(tranidx));
7898 :
7899 0 : String oFitMsg;
7900 0 : logSink()<<LogIO::DEBUG1<<"nValidFLux="<<nValidFlux<<LogIO::POST;
7901 :
7902 : //if (nValidFlux>1) {
7903 0 : if (nValidFlux>0) {
7904 :
7905 : // Make fd and freq lists
7906 0 : Vector<Double> fds;
7907 0 : fds=fd.column(tranidx)(scaleOK.column(tranidx)).getCompressedArray();
7908 0 : Vector<Double> fderrs;
7909 0 : fderrs=fderr.column(tranidx)(scaleOK.column(tranidx)).getCompressedArray();
7910 0 : Vector<Double> freqs;
7911 0 : freqs=solFreq(scaleOK.column(tranidx)).getCompressedArray();
7912 :
7913 : // shift mean(log(freq)) later
7914 : // Reference frequency is first in the list
7915 : //refFreq(tranidx)=freqs[0];
7916 : //freqs/=refFreq(tranidx);
7917 : //
7918 : // calculate spectral index
7919 : // fit the per-spw fluxes to get spectral index
7920 0 : if (nValidFlux==1) {
7921 0 : fitFluxD(tranidx) = fds(0);
7922 0 : fitRefFreq(tranidx) = freqs(0);
7923 : }
7924 : else {
7925 : // single spw so no fitting is performed, just fill flux and frequency
7926 : // to fit result record
7927 0 : LinearFit<Double> fitter;
7928 0 : uInt myfitorder = 0;
7929 0 : if (fitorder < 0) {
7930 : logSink() << LogIO::WARN
7931 : << "fitorder=" << fitorder
7932 : << " not supported. Using fitorder=1"
7933 0 : << LogIO::POST;
7934 0 : myfitorder = 1;
7935 : }
7936 0 : else if (nValidFlux==2 && fitorder>1) {
7937 : // note that myfitorder does not get set in this conditional branch, is that
7938 : // the correct thing not to do? (myfitorder was prevously unitialized at this point).
7939 : logSink() << LogIO::WARN
7940 : << "Not enough number of valid flux density data for the requested fitorder:"<<fitorder
7941 0 : << ". Use fitorder=1." <<LogIO::POST;
7942 : }
7943 : else {
7944 0 : myfitorder = (uInt)fitorder;
7945 :
7946 : //if (fitorder < nValidFlux) {
7947 : // myfitorder = (uInt)fitorder;
7948 : //}
7949 : //else {
7950 : //if (fitorder > nValidFlux) {
7951 : // myfitorder = (uInt)(nValidFlux-1);
7952 : // logSink() << LogIO::WARN
7953 : // << "Not enough number of valid flux density data for the requested fitorder:"<<fitorder
7954 : // <<". Using a lower fitorder="<<myfitorder<<LogIO::POST;
7955 : }
7956 : // set fitting for spectral index, alpha and beta(curvature)
7957 : // with S = S_o*f/f0^(alpha+beta*log(f/fo))
7958 : // fitting y = c + alpha*x + beta*x^2
7959 : // log(S/S0)=alpha*log(f/f0) + beta*log(f/f0)**2
7960 0 : Polynomial< AutoDiff<Double> > bp(myfitorder);
7961 0 : fitter.setFunction(bp);
7962 :
7963 : // shift the zero point to the mean of log(freq)
7964 0 : Double meanLogFreq=mean(log10(freqs));
7965 0 : Vector<Double> log_relsolFreq=log10(freqs)-meanLogFreq;
7966 : //Vector<Double> log_relsolFreq=log10(freqs);
7967 0 : Vector<Double> log_fd=log10(fds);
7968 :
7969 : // The error in the log of fds is fderrs/fds
7970 0 : Vector<Double> soln=fitter.fit(log_relsolFreq, log_fd, fderrs/fds);
7971 0 : Vector<Double> errs=fitter.errors();
7972 0 : Matrix<Double> covar=fitter.compuCovariance();
7973 :
7974 0 : for (uInt i=0; i<soln.nelements(); i++) {
7975 0 : spidx(tranidx,i) = soln(i);
7976 0 : spidxerr(tranidx,i) = errs(i);
7977 : }
7978 0 : fitFluxD(tranidx) = pow(10.0,(soln(0)));
7979 : // correct for the proper propagation of error
7980 0 : fitFluxDErr(tranidx) = (errs(0)>0.0 ? log(10)*pow(10.0,(soln(0)))*errs(0) : 0.0);
7981 0 : fitRefFreq(tranidx) = pow(10.0,meanLogFreq);
7982 : //covarList[tranidx] = &covar;
7983 0 : covarList(tranidx) = covar;
7984 0 : oFitMsg =" Fitted spectrum for ";
7985 0 : oFitMsg += fldNames(tranidx);
7986 0 : oFitMsg += " with fitorder="+String::toString<Int>(myfitorder)+": ";
7987 : // oFitMsg += "Flux density = "+String::toString<Double>(pow(10.0,(soln(0))));
7988 0 : oFitMsg += "Flux density = "+String::toString<Double>(fitFluxD(tranidx));
7989 : // Double ferr=(errs(0)>0.0 ? exp10(errs(0)) : 0.0);
7990 : // Double ferr=(errs(0)>0.0 ? pow(10.0,(errs(0))) : 0.0);
7991 0 : oFitMsg += " +/- "+String::toString<Double>(fitFluxDErr(tranidx));
7992 : // oFitMsg += " (freq="+String::toString<Double>(refFreq(tranidx)/1.0e9)+" GHz)";
7993 : // oFitMsg += " (freq="+String::toString<Double>(pow(10.0,meanLogFreq)/1.0e9)+" GHz)";
7994 0 : oFitMsg += " (freq="+String::toString<Double>(fitRefFreq(tranidx)/1.0e9)+" GHz)";
7995 : //oFitMsg += " soln.nelements="+String::toString<Int>(soln.nelements());
7996 0 : oFitMsg += " spidx:";
7997 0 : for (uInt j=1; j<soln.nelements();j++) {
7998 0 : String coefname=" a_"+String::toString<Int>(j);
7999 0 : if (j==1) coefname += " (spectral index) ";
8000 0 : oFitMsg += coefname+"="+String::toString<Double>(soln(j));
8001 0 : oFitMsg += " +/- "+String::toString<Double>(errs(j));
8002 : //if (nValidFlux > (Int)(j+1)) {
8003 : // oFitMsg += " +/- "+String::toString<Double>(errs(j));
8004 : //}
8005 : //else {
8006 : // oFitMsg += " (degenerate)";
8007 : //}
8008 : }
8009 : Int sh1, sh2;
8010 0 : covar.shape(sh1,sh2);
8011 0 : if (sh1 > 1) {
8012 0 : oFitMsg += " covariance matrix for the fit: ";
8013 0 : for (Int i=0;i<sh1; i++) {
8014 0 : for (Int j=0;j<sh2; j++) {
8015 0 : oFitMsg += " covar("+String::toString(i)+","+String::toString(j)+")="+String::toString<Double>(covar(i,j));
8016 : }
8017 : }
8018 : }
8019 0 : if ( oListFile != "" ) {
8020 0 : ofstream oStream;
8021 0 : oStream.open( oListFile.chars(), ios::out|ios::app );
8022 0 : oStream << "#" << oFitMsg << endl << flush;
8023 0 : oStream.close();
8024 : }
8025 0 : logSink() << oFitMsg << LogIO::POST;
8026 : }
8027 : }// nValidFlux
8028 : /**
8029 : Int sh1, sh2;
8030 : covar->shape(sh1,sh2);
8031 :
8032 : for (Int i=0;i<sh1; i++) {
8033 : for (Int j=0;j<sh2; j++) {
8034 : logSink() << LogIO::DEBUG1
8035 : <<"covar("<<i<<","<<j<<")="<<*covar(i,j) << LogIO::POST;
8036 : }
8037 : }
8038 : **/
8039 : }//iTran
8040 :
8041 : //store determined quantities for returned output
8042 0 : oFluxScaleStruct.fd = fd.copy();
8043 0 : oFluxScaleStruct.fderr = fderr.copy();
8044 0 : oFluxScaleStruct.numSol = numSol.copy();
8045 0 : oFluxScaleStruct.freq = solFreq.copy();
8046 0 : oFluxScaleStruct.spidx = spidx.copy();
8047 0 : oFluxScaleStruct.spidxerr = spidxerr.copy();
8048 0 : oFluxScaleStruct.fitfd = fitFluxD.copy();
8049 0 : oFluxScaleStruct.fitfderr = fitFluxDErr.copy();
8050 0 : oFluxScaleStruct.fitreffreq = fitRefFreq.copy();
8051 : //oFluxScaleStruct.covarmat = covarList;
8052 0 : oFluxScaleStruct.covarmat = covarList.copy();
8053 : // quit if no scale factors found
8054 0 : if (ntrue(scaleOK) == 0) throw(AipsError("No scale factors determined!"));
8055 :
8056 : // cout << "done." << endl;
8057 :
8058 : // cout << "Adjusting gains...";
8059 :
8060 : // Adjust tran field's gains here
8061 :
8062 : //create incremental caltable
8063 0 : if (incremental) {
8064 : //MSSpWindowColumns spwcol(ct_->spectralWindow());
8065 : //Vector<Int> NCHAN=spwcol.numChan().getColumn();
8066 : //nChanPar()=NCHAN(0);
8067 :
8068 0 : delete ct_;
8069 : // setup and fill a record
8070 : // set record description
8071 0 : Vector<Int> spwlist(nSpw());
8072 0 : indgen(spwlist);
8073 :
8074 0 : RecordDesc fsparDesc;
8075 0 : fsparDesc.addField ("caltable", TpString);
8076 0 : fsparDesc.addField ("time", TpDouble);
8077 0 : fsparDesc.addField ("spw", TpArrayInt);
8078 0 : fsparDesc.addField ("antenna", TpArrayInt);
8079 0 : fsparDesc.addField ("pol", TpString);
8080 0 : fsparDesc.addField ("parameter", TpArrayDouble);
8081 0 : fsparDesc.addField ("paramerr", TpArrayDouble);
8082 0 : fsparDesc.addField ("caltype", TpString);
8083 :
8084 : // create record with field values
8085 0 : Record fspar(fsparDesc);
8086 0 : fspar.define("caltable",outCalTabName);
8087 : //fspar.define("time",tc(0));
8088 0 : fspar.define("spw", spwlist);
8089 0 : fspar.define("caltype", "G Cal");
8090 0 : setSpecify(fspar);
8091 : //
8092 : { // generate per chan factor taking account for spectral index
8093 : // for(Int ich=0;ich<nchan;ich++); fl = soln(0) + alpha*chanf(ich) * beta*chanf(ich)*chanf(ich)
8094 : // fact = sqrt(fl) at each ich for each spw and each field
8095 : // and store 1/fact in bcal-like table
8096 : }
8097 :
8098 : // Only do fields that occurred in the input caltable
8099 0 : for (uInt ifld=0;ifld<fldList.nelements();ifld++) {
8100 0 : Int iFld=fldList(ifld);
8101 0 : setCurrField(iFld);
8102 : //
8103 0 : initSolvePar(); // somewhat redundant but needed to reset solveCPar
8104 :
8105 : //currField()=iFld;
8106 : //refTime()=tc(0);
8107 : //currTime()=tc(0);
8108 0 : refTime()=mgreft(iFld);
8109 : // for future time support in specify
8110 0 : fspar.define("time",mgreft(iFld));
8111 :
8112 : // for only looping thru field id (set all spw for each field)
8113 0 : fspar.define("parameter", abs(1./mgratio.column(iFld)));
8114 0 : fspar.define("paramerr", 1./mgerr.column(iFld));
8115 : //
8116 0 : specify(fspar);
8117 : }
8118 : /***
8119 : Block<String> cols(3);
8120 : cols[0]="SPECTRAL_WINDOW_ID";
8121 : cols[1]="TIME";
8122 : cols[2]="FIELD_ID";
8123 : CTIter ctiter(*ct_,cols);
8124 : while (!ctiter.pastEnd()) {
8125 : Int iSpw(ctiter.thisSpw());
8126 : Int iFld(ctiter.thisField());
8127 : cerr<<"iFld last="<<iFld<<endl;
8128 : //Cube<Complex> cpar(ctiter.cparam());
8129 : Cube<Float> fpar(ctiter.fparam());
8130 : //cpar = Complex(Float(mgratio(iSpw,iFld)));
8131 : fpar = Float(mgratio(iSpw,iFld));
8132 : //ctiter.setcparam(cpar);
8133 : ctiter.setfparam(fpar);
8134 : ctiter.next();
8135 : }
8136 : storeNCT(outfile,false);
8137 : ***/
8138 : }
8139 : else {
8140 : // older behavior
8141 0 : Block<String> cols(3);
8142 0 : cols[0]="SPECTRAL_WINDOW_ID";
8143 0 : cols[1]="TIME";
8144 0 : cols[2]="FIELD_ID";
8145 0 : CTIter ctiter(*ct_,cols);
8146 :
8147 0 : while (!ctiter.pastEnd()) {
8148 0 : Int iSpw(ctiter.thisSpw());
8149 0 : Int iFld(ctiter.thisField());
8150 :
8151 0 : if (scaleOK(iSpw,iFld)) {
8152 0 : Cube<Complex> cpar(ctiter.cparam());
8153 0 : cpar/=Complex(Float(mgratio(iSpw,iFld)));
8154 0 : ctiter.setcparam(cpar);
8155 : }
8156 0 : ctiter.next();
8157 : }
8158 : } // scope
8159 :
8160 : // cout << "done." << endl;
8161 :
8162 : // cout << "Cleaning up...";
8163 :
8164 : // Clean up PtrBlocks
8165 0 : for (Int iFld=0; iFld<nFld; iFld++) {
8166 0 : if (MGOK[iFld]!=NULL) {
8167 0 : delete MGOK[iFld];
8168 0 : delete MG[iFld];
8169 0 : delete MG2[iFld];
8170 0 : delete MGWT[iFld];
8171 0 : delete MGVAR[iFld];
8172 0 : delete MGN[iFld];
8173 0 : delete MGNALL[iFld];
8174 : }
8175 : }
8176 :
8177 : // cout << "done." << endl;
8178 :
8179 : // Avoid this since problem with <msname>/SELECTED_TABLE (06Feb02 gmoellen)
8180 : /*
8181 : {
8182 :
8183 : MeasurementSet ms(vs_->msName().before("/SELECTED"));
8184 : Table historytab = Table(ms.historyTableName(),
8185 : TableLock(TableLock::UserNoReadLocking),
8186 : Table::Update);
8187 : MSHistoryHandler hist = MSHistoryHandler(ms, "calibrater");
8188 : historytab.lock(true);
8189 : oss.postLocally();
8190 : hist.addMessage(oss);
8191 : historytab.unlock();
8192 : }
8193 : */
8194 : }
8195 0 : catch (AipsError x) {
8196 :
8197 : // Clean up PtrBlocks
8198 0 : for (Int iFld=0; iFld<nFld; iFld++) {
8199 0 : if (MGOK[iFld]!=NULL) {
8200 0 : delete MGOK[iFld];
8201 0 : delete MG[iFld];
8202 0 : delete MG2[iFld];
8203 0 : delete MGWT[iFld];
8204 0 : delete MGVAR[iFld];
8205 0 : delete MGN[iFld];
8206 0 : delete MGNALL[iFld];
8207 : }
8208 : }
8209 :
8210 0 : throw(x);
8211 :
8212 : }
8213 :
8214 0 : return;
8215 :
8216 : }
8217 :
8218 0 : void SolvableVisJones::setupPlotter() {
8219 0 : }
8220 :
8221 0 : void SolvableVisJones::plotHistogram(const String& title,
8222 : const Int index,
8223 : const Vector<Double>& data,
8224 : const Int nbins) {
8225 : // construct histogram in multiple panels
8226 0 : std::string legendloc = "bottom";
8227 0 : std::string zoomloc = "";
8228 0 : if (index==0) {
8229 0 : std::vector<std::string> loc;
8230 0 : loc.push_back("top");
8231 : //plotter_->loaddock( dock_xml_p, "bottom", loc, panels_id_[0].getInt());
8232 : }
8233 : else {
8234 :
8235 : // multirow panels
8236 : /***
8237 : if (index<3) {
8238 : //cerr<<"panels_id[index-1].getInt()="<<panels_id_[index-1].getInt()<<endl;
8239 : panels_id_[index] = plotter_->panel( title, "ratio", "N", "",
8240 : std::vector<int>( ), legendloc,zoomloc,panels_id_[index-1].getInt(),false,false);
8241 : }
8242 : else {
8243 : if (index==3) {
8244 : panels_id_[index] = plotter_->panel( title, "ratio", "N", "",
8245 : std::vector<int>( ), legendloc,zoomloc,panels_id_[0].getInt(),true,false);
8246 : }
8247 : else {
8248 : panels_id_[index] = plotter_->panel( title, "ratio", "N", "",
8249 : std::vector<int>( ), legendloc,zoomloc,panels_id_[index-1].getInt(),false,false);
8250 : }
8251 : }
8252 : ***/
8253 : }
8254 : // plot histogram
8255 :
8256 0 : }
8257 :
8258 0 : void SolvableVisJones::listCal(const Vector<Int> ufldids,
8259 : const Vector<Int> uantids,
8260 : const Matrix<Int> uchanids,
8261 : const String& listfile,
8262 : const Int& maxScrRows) {
8263 :
8264 : // cout << "listcal disabled for the moment." << endl;
8265 :
8266 : // return;
8267 :
8268 0 : if (typeName().contains("BPOLY") ||
8269 0 : typeName().contains("GSPLINE"))
8270 0 : throw(AipsError(typeName()+" not yet supported."));
8271 :
8272 0 : char cfill = cout.fill(' '); // Set fill character for terminal output
8273 :
8274 : //Int uSpwID = uchanids(0,0);
8275 : //Int chan = uchanids(0,1);
8276 :
8277 : // The number of spws; that is, the number of rows in matrix uchanids.
8278 : // Actually, this is the number of spw/channel selections made in the
8279 : // spw selection parameter. The rows of uchanids may contain the same
8280 : // spw.
8281 0 : uInt nSpws = uchanids.nrow();
8282 :
8283 : // Prep for listing
8284 0 : Bool endOutput = false; // if true, end output immediately
8285 0 : Bool prompt = true; // if true, issue prompt
8286 0 : Int isol = 0; // total solution counter
8287 0 : Int scrRows=0; // screen row counter, reset after continue prompt
8288 :
8289 : // Redirect cout to listfile
8290 0 : ofstream file;
8291 0 : streambuf* sbuf = cout.rdbuf();
8292 0 : if(listfile!="") { // non-interactive
8293 0 : prompt = false;
8294 : // Guard against trampling existing file
8295 0 : File diskfile(listfile);
8296 0 : if (diskfile.exists()) {
8297 0 : String errmsg = "File: " + listfile +
8298 0 : " already exists; delete it or choose a different name.";
8299 0 : throw(AipsError(errmsg));
8300 : }
8301 : else
8302 0 : cout << "Writing output to file: " << listfile << endl;
8303 : logSink() << LogIO::NORMAL2 << "Redirecting output to "
8304 0 : << diskfile.path().originalName().data() << LogIO::POST;
8305 0 : file.open(diskfile.path().originalName().data());
8306 0 : cout.rdbuf(file.rdbuf());
8307 : } else {
8308 : logSink() << LogIO::DEBUG1
8309 : << "Not redirecting output: cout remains untouched."
8310 0 : << LogIO::POST;
8311 : }
8312 :
8313 0 : Vector<String> antname;
8314 0 : msmc().antennaNames(antname);
8315 0 : Vector<String> fldname;
8316 0 : msmc().fieldNames(fldname);
8317 :
8318 : // Default header info.
8319 0 : logSink() << LogIO::NORMAL1 << "MS name = " << msName() << LogIO::POST;
8320 :
8321 : logSink() << LogIO::DEBUG1 << "Number of spectral window selections (may not be unique) = "
8322 0 : << nSpws << LogIO::POST;
8323 : logSink() << LogIO::DEBUG1 << "Number of (unique) spws in cal table = "
8324 0 : << ct_->spectralWindow().nrow() << LogIO::POST;
8325 :
8326 :
8327 :
8328 : // Get nchan from the subtable
8329 0 : MSSpWindowColumns spwcol(ct_->spectralWindow());
8330 0 : Vector<Int> NCHAN=spwcol.numChan().getColumn();
8331 :
8332 0 : Int NANT=ct_->antenna().nrow();
8333 :
8334 :
8335 0 : Block<String> cols(1);
8336 0 : cols[0]="SPECTRAL_WINDOW_ID";
8337 0 : ROCTIter ctiter(*ct_,cols);
8338 :
8339 :
8340 0 : while (!ctiter.pastEnd()) {
8341 :
8342 0 : Int spwID=ctiter.thisSpw();
8343 0 : if (anyEQ(uchanids.column(0),spwID)) {
8344 : // spwID among selected spws
8345 0 : uInt iUchanids=0;
8346 0 : while (uchanids(iUchanids,0)!=spwID) ++iUchanids;
8347 0 : Vector<Int> RowUchanids = uchanids.row(iUchanids);
8348 :
8349 0 : if (ctiter.nrow()<1) {
8350 : // shouldn't happen
8351 0 : String errMsg;
8352 : errMsg = "Nothing to list for selected SpwID: "
8353 0 : + errMsg.toString(spwID);
8354 0 : logSink() << LogIO::NORMAL1 << errMsg << LogIO::POST;
8355 : } else { // we have something to list
8356 :
8357 : // Handle channel selection here.
8358 0 : const uInt nchan= NCHAN(spwID);
8359 : logSink() << LogIO::DEBUG1 << "For Spw ID " << spwID
8360 : << ": Number of spectral channels in calibration table = "
8361 0 : << nchan << LogIO::POST;
8362 :
8363 : // Extract channel selection info from uchanids
8364 0 : Int stepChan = RowUchanids(3);
8365 0 : if (stepChan == 0) { stepChan = 1; } // one channel at a time (default)
8366 0 : else if (stepChan < 0) {
8367 0 : throw(AipsError("Stepping backwards through channels not supported."));
8368 : }
8369 : // Cal table channels are a subset of the MS channels.
8370 : // MS indices of channels in cal table.
8371 0 : const uInt msCalStartChan = 0;
8372 0 : const uInt msCalStopChan = nchan-1;
8373 : // MS indices of selected channels
8374 0 : uInt msSelStartChan = RowUchanids(1);
8375 0 : uInt msSelStopChan = RowUchanids(2);
8376 : // Cal table indices of selected channels
8377 0 : Int startChan = msSelStartChan - msCalStartChan;
8378 0 : Int stopChan = msSelStopChan - msCalStartChan;
8379 0 : if (startChan > stopChan) {
8380 0 : throw(AipsError("Start channel must be less than or equal to stop channel."));
8381 0 : } else if ((stopChan < 0) || (startChan > (Int)nchan - 1)) {
8382 : // All selected channels out of range
8383 0 : String errMsg = "None of the selected channels are present in cal table.";
8384 : logSink() << LogIO::SEVERE << errMsg
8385 : << endl << "Selected channel range = ["
8386 : << msSelStartChan << "," << msSelStopChan << "]" << endl
8387 : << "Cal table channel range = ["
8388 0 : << msCalStartChan << "," << msCalStopChan << "]" << LogIO::POST;
8389 0 : throw(AipsError(errMsg));
8390 : }
8391 0 : if (startChan < 0) {
8392 : logSink() << LogIO::NORMAL1 << "Start channel ( " << msSelStartChan
8393 : << " ) below allowed range." << endl
8394 : << "Increasing start channel to " << msCalStartChan
8395 0 : << LogIO::POST;
8396 0 : startChan = 0;
8397 : }
8398 0 : if (stopChan > (Int)nchan - 1) {
8399 : logSink() << LogIO::NORMAL1 << "Stop channel ( " << msSelStopChan
8400 : << " ) above allowed range." << endl
8401 : << "Decreasing stop channel to " << msCalStopChan
8402 0 : << LogIO::POST;
8403 0 : stopChan = (Int)nchan - 1;
8404 : }
8405 : // Number of channels selected
8406 0 : Int numChans = ((stopChan - startChan) / stepChan) + 1;
8407 0 : if (numChans > Int(nchan)) {
8408 : logSink() << LogIO::NORMAL1
8409 : << "More channels requested than are present in the cal table."
8410 : << endl << "Cal table channels for this spw: "
8411 : << msCalStartChan << " to " << msCalStopChan
8412 0 : << LogIO::POST;
8413 : }
8414 :
8415 : logSink() << LogIO::DEBUG1 << "For spwID " << spwID << endl
8416 : << " startChan = " << startChan << endl
8417 : << " stopChan = " << stopChan << endl
8418 : << " stepChan = " << stepChan << endl
8419 : << " Number of channels to list: numChans = " << numChans
8420 0 : << LogIO::POST;
8421 :
8422 : // Setup the column widths. Check width of each string.
8423 : uInt precAmp, precPhase; // Column precision
8424 : uInt oAmp, oPhase; // Column order
8425 :
8426 0 : wTime_p = 10; // set width of time column
8427 : // set the field column width (looking at the whole cal table)
8428 0 : wField_p = 0;
8429 :
8430 0 : Vector<Int> fldids;
8431 0 : fldids=ctiter.field();
8432 0 : Int nUniqFlds=genSort(fldids,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
8433 0 : fldids.resize(nUniqFlds,true); // shrink the Vector
8434 :
8435 0 : for (Int ifld=0;ifld<nUniqFlds;++ifld) {
8436 0 : String fldstr=(fldname(ifld));
8437 0 : uInt fldstrLength = fldstr.length();
8438 0 : if (wField_p < fldstrLength) { wField_p = fldstrLength; }
8439 : }
8440 :
8441 0 : wChan_p = (uInt)max(3,(Int)rint(log10(nchan)+0.5));
8442 0 : wPreAnt_p = wTime_p + 1 + wField_p + 1 + wChan_p; // do not count final pipe ("|")
8443 : logSink() << LogIO::DEBUG1 << "Column widths:" << endl
8444 : << " time = " << wTime_p << endl
8445 : << " field = " << wField_p << endl
8446 0 : << " channel = " << wChan_p << LogIO::POST;
8447 :
8448 : // For multiple channels, I think I will need to write a method that
8449 : // looks through all spws to determine the necessary order for the
8450 : // Amplitude and Phase.
8451 :
8452 0 : if (ct_->isComplex()) {
8453 0 : oAmp = 1;
8454 0 : precAmp = 3;
8455 0 : oPhase = 4;
8456 0 : precPhase = 1;
8457 : }
8458 : else {
8459 : // only "amp" column matters (and may have -ve sign)
8460 0 : oAmp = 4;
8461 0 : precAmp = 5;
8462 0 : oPhase = 0;
8463 0 : precPhase = 0;
8464 : }
8465 :
8466 : // set width of amplitude column
8467 0 : wAmp_p = oAmp + precAmp + 1; // order + precision + decimal point
8468 :
8469 : // set width of phase column
8470 0 : wPhase_p = oPhase + precPhase + 1; // order + precision + decimal point
8471 :
8472 0 : wFlag_p=1;
8473 0 : wPol_p = wAmp_p + 1 + wPhase_p + 1 + wFlag_p + 1;
8474 0 : wAntCol_p = wPol_p*nPar();
8475 : //cerr << "wAntCol_p = " <<wAntCol_p << endl;
8476 :
8477 : logSink() << LogIO::DEBUG1 << "oAmp = " << oAmp
8478 : << ", precAmp = " << precAmp
8479 : << ", wAmp_p = " << wAmp_p << endl
8480 : << "oPhase = " << oPhase
8481 : << ", precPhase = " << precPhase
8482 : << ", wPhase_p = " << wPhase_p
8483 0 : << LogIO::POST;
8484 :
8485 : //uInt numAntCols = 4; // Number of antenna columns
8486 0 : uInt numAntCols = 8/nPar(); // Number of antenna columns
8487 0 : wTotal_p = wPreAnt_p + 1 + wAntCol_p*numAntCols;
8488 :
8489 : //cerr << "wTotal_p = " << wTotal_p << endl;
8490 :
8491 : // Construct the horizontal separator
8492 0 : String hSeparator=replicate('-',wTotal_p);
8493 0 : uInt colPos=0;
8494 0 : colPos+=wPreAnt_p; hSeparator[colPos]='|'; colPos++;
8495 0 : for(uInt iPol=0; iPol<numAntCols*nPar(); iPol++) {
8496 0 : colPos+=wPol_p-1;
8497 0 : hSeparator[colPos]='|';
8498 0 : colPos++;
8499 : }
8500 :
8501 : logSink() << LogIO::DEBUG1
8502 0 : << "Listing CalTable: " << calTableName()
8503 0 : << " (" << typeName() << ") "
8504 0 : << LogIO::POST;
8505 :
8506 0 : String dateTimeStr0=MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7);
8507 0 : String dateStr0=dateTimeStr0.substr(0,10);
8508 :
8509 0 : String headLine = "SpwID = " + String::toString(spwID) + ", "
8510 0 : "Date = " + dateStr0 + ", " +
8511 0 : "CalTable = " + calTableName() + " (" + typeName() + "), " +
8512 0 : "MS name = " + msName();
8513 0 : cout.setf(ios::left,ios::adjustfield);
8514 : // cout << setw(wTotal_p) << headLine << endl
8515 0 : cout << headLine << endl
8516 0 : << replicate('-',wTotal_p) << endl;
8517 0 : scrRows+=2;
8518 :
8519 : // labels for flagged solutions
8520 0 : Vector<String> flagstr(2);
8521 0 : flagstr(0)="F";
8522 0 : flagstr(1)=" ";
8523 :
8524 : // The following is a klugey way to
8525 : // make the times, fields, and gains look like
8526 : // what the CalTable's used to be
8527 :
8528 0 : Int NTIME=ctiter.nrow()/NANT;
8529 0 : Vector<Double> timelist;
8530 0 : timelist=ctiter.time();
8531 0 : Vector<Int> fieldlist;
8532 0 : fieldlist=ctiter.field();
8533 0 : for (Int i=1;i<NTIME;++i) {
8534 0 : timelist(i)=timelist(i*NANT);
8535 0 : fieldlist(i)=fieldlist(i*NANT);
8536 : }
8537 0 : timelist.resize(NTIME,true);
8538 0 : fieldlist.resize(NTIME,true);
8539 :
8540 0 : Array<Float> v1,v2;
8541 0 : Array<Bool> vok;
8542 0 : Int npar=nPar();
8543 0 : if (ct_->isComplex()) {
8544 0 : Cube<Complex> cparam;
8545 0 : ctiter.cparam(cparam);
8546 0 : IPosition sh(cparam.shape());
8547 0 : sh.append(IPosition(1,NTIME));
8548 0 : sh(2)=NANT;
8549 0 : Array<Complex> calGains;
8550 0 : calGains.reference(cparam.reform(sh));
8551 0 : v1.assign(amplitude(calGains));
8552 0 : v2.assign(phase(calGains)*180.0/C::pi);
8553 0 : Cube<Bool> sok;
8554 0 : sok=!ctiter.flag();
8555 0 : Array<Bool> calGainOK;
8556 0 : calGainOK.reference(sok.reform(sh));
8557 0 : vok.reference(calGainOK);
8558 : }
8559 : else {
8560 0 : Cube<Float> fparam;
8561 0 : Array<Float> fparam4;
8562 0 : ctiter.fparam(fparam);
8563 0 : IPosition sh(fparam.shape());
8564 0 : Cube<Bool> sok;
8565 0 : Array<Bool> sok4;
8566 0 : sok=!ctiter.flag();
8567 0 : sh.append(IPosition(1,NTIME));
8568 0 : sh(2)=NANT;
8569 0 : fparam4.reference(fparam.reform(sh));
8570 0 : sok4.reference(sok.reform(sh));
8571 :
8572 : // only one val per par
8573 0 : sh.append(IPosition(1,NTIME));
8574 0 : sh(2)=NANT;
8575 0 : v1.reference(fparam4);
8576 0 : v2.resize();
8577 0 : vok.reference(sok4);
8578 : }
8579 :
8580 0 : IPosition gidx(4,0,0,0,0); // 4-element IPosition, all zeros
8581 :
8582 : // Setup a Vector of antenna ID's to ease the process of printing
8583 : // multiple antenna columns per row.
8584 : uInt numAnts; // Hold number of antennas to be output.
8585 0 : Vector<Int> pAntids(NANT); // Vector of antenna ID's.
8586 0 : if (uantids.nelements()==0) { // Print all antennas.
8587 0 : numAnts = NANT;
8588 0 : for(uInt i=0; i< numAnts; i++) { // Fill pAntids with all antenna IDs.
8589 0 : pAntids[i] = i;
8590 : }
8591 : } else { // Use the user-specified antenna ID's.
8592 0 : numAnts = uantids.nelements();
8593 0 : pAntids.resize(numAnts);
8594 0 : pAntids = uantids;
8595 : }
8596 :
8597 : // loop over antenna elements
8598 0 : for (uInt iElem=0;iElem<numAnts;iElem+=numAntCols) {
8599 0 : gidx(2)=pAntids(iElem);
8600 :
8601 0 : Bool header=true; // New antenna, require print header
8602 :
8603 : // If antenna element is among selected antennas, print it
8604 0 : if (uantids.nelements()==0 || anyEQ(uantids,pAntids(iElem))) {
8605 :
8606 : // Begin loop over time
8607 0 : for (Int itime=0;itime<NTIME;++itime) {
8608 0 : gidx(3)=itime;
8609 :
8610 0 : Int fldid(fieldlist(itime));
8611 :
8612 : // Get date-time string
8613 0 : String dateTimeStr=MVTime(timelist(itime)/C::day).string(MVTime::YMD,7);
8614 0 : String dateStr=dateTimeStr.substr(0,10);
8615 0 : String timeStr=dateTimeStr.substr(11,10);
8616 : // Get field string
8617 0 : String fldStr="";
8618 0 : if (fldid>-1)
8619 0 : fldStr=(fldname(fldid));
8620 :
8621 0 : String tmp_timestr = timeStr; // tmp_ variables get reset during the loop
8622 0 : String tmp_fldstr = fldStr; //
8623 :
8624 : // If no user-specified fields, or fldid is in user's list
8625 0 : if (ufldids.nelements()==0 || anyEQ(ufldids,fldid) ) {
8626 :
8627 : // Set i/o flags for writing data
8628 0 : cout << setiosflags(ios::fixed) << setiosflags(ios::right);
8629 :
8630 : // Loop over channels
8631 0 : for (uInt iChan=startChan; iChan<=uInt(stopChan); iChan+=stepChan) {
8632 :
8633 : // If beginning new screen, print the header
8634 0 : if (scrRows == 0 || header) {
8635 0 : header=false;
8636 : // Write Antenna line (put spaces over the time, field cols)
8637 0 : for(uInt k=0; k<(wPreAnt_p); k++) { cout<<" "; }
8638 0 : cout << "|";
8639 0 : for(uInt k=0; (k<numAntCols) and (iElem+k<=numAnts-1); k++) {
8640 0 : String tAntName = " Ant = " + String(antname(pAntids(iElem+k)));
8641 0 : cout.setf(ios::left,ios::adjustfield);
8642 0 : cout << setw(wAntCol_p-1) << tAntName << "|";
8643 : }
8644 0 : cout << endl; scrRows++;
8645 :
8646 : // Write part of header with no data
8647 0 : scrRows += writeHeader(numAntCols, numAnts, iElem);
8648 : }
8649 :
8650 :
8651 0 : gidx(1)=iChan;
8652 : // Write the Time, Field, and Channel for each row
8653 0 : cout << setw(wTime_p) << timeStr << " "
8654 0 : << setw(wField_p) << fldStr << " "
8655 0 : << setw(wChan_p) << msCalStartChan + iChan << "|";
8656 :
8657 : // Write data for each antenna column
8658 0 : for (uInt kelem=iElem; (kelem<iElem+numAntCols) and (kelem<=numAnts-1);
8659 : kelem++) {
8660 0 : gidx(2)=pAntids(kelem);
8661 : // Loop over polarization
8662 0 : for (Int ipar=0;ipar<npar;++ipar) {
8663 0 : gidx(0)=ipar;
8664 :
8665 : // WRITE THE DATA
8666 : // amplitude
8667 0 : cout << setprecision(precAmp) << setw(wAmp_p) << v1(gidx) << " ";
8668 :
8669 0 : if (v2.nelements()>0)
8670 : // phase
8671 0 : cout<< setprecision(precPhase) << setw(wPhase_p) << v2(gidx) << " ";
8672 : else
8673 0 : cout<< setprecision(precPhase) << setw(wPhase_p) << replicate(" ",wPhase_p) << " ";
8674 : // flag
8675 0 : cout << flagstr(Int(vok(gidx))) << " ";
8676 : } // end ipar loop
8677 :
8678 : } // end kelem loop
8679 :
8680 0 : cout << resetiosflags(ios::right) << endl;
8681 0 : isol=isol+numAntCols; scrRows++;
8682 :
8683 : // If at end of screen prompt user or new header
8684 0 : if (maxScrRows>0 && (scrRows >= maxScrRows-1) ) { // scrRows counts from 0
8685 0 : scrRows = 0; // signal a new page
8686 0 : if (prompt) { // query the user, if we are interactive
8687 0 : string contStr;
8688 0 : cout << "Type Q to quit, A to list all, or RETURN to continue [continue]: ";
8689 0 : getline(cin,contStr);
8690 0 : if ( (contStr.compare(0,1,"q") == 0) or
8691 0 : (contStr.compare(0,1,"Q") == 0) ) { endOutput=true; }
8692 0 : if ( (contStr.compare(0,1,"a") == 0) or
8693 0 : (contStr.compare(0,1,"A") == 0) ) { prompt = false; }
8694 : }
8695 : }
8696 : } // end iChan loop
8697 :
8698 : } // end if (field)
8699 :
8700 0 : if (endOutput) {break;} // break out of itime loop
8701 :
8702 : } // itime
8703 :
8704 : } // end if (antenna)
8705 :
8706 0 : if (endOutput) {break;} // break out of ielem loop
8707 :
8708 : } // end iElem loop
8709 :
8710 0 : if (endOutput) {break;} // break out of spw loop
8711 :
8712 : } // end spw if (verification) block
8713 :
8714 : } // end spw loop
8715 :
8716 : // advance iterator (spw)
8717 0 : ctiter.next();
8718 : } // ctiter
8719 :
8720 0 : cout << endl
8721 0 : << "Listed " << isol << " antenna solutions."
8722 0 : << endl << endl;
8723 :
8724 0 : if (listfile!="") cout.rdbuf(sbuf); // restore cout
8725 0 : cout.fill(cfill);
8726 :
8727 0 : }// end function listCal
8728 :
8729 0 : int SolvableVisJones::writeHeader(const uInt numAntCols,
8730 : const uInt numAnts,
8731 : const uInt iElem) {
8732 0 : uInt lineCount=0;
8733 : // Write time and field headings (only once)
8734 : cout << setiosflags(ios::left)
8735 0 : << setw(wTime_p) << "Time" << " "
8736 0 : << setw(wField_p) << "Field" << " "
8737 0 : << setw(wChan_p) << "Chn" << "|";
8738 :
8739 : // Write Amp and Phase headings for each antenna column
8740 0 : Int nh(2);
8741 0 : Vector<String> vh(nh);
8742 0 : vh[0]="Amp ";
8743 0 : vh[1]="Phs ";
8744 0 : if (this->typeName().contains("EVLAGAIN")) {
8745 0 : nh=8;
8746 0 : vh.resize(nh);
8747 0 : vh[0]=vh[4]="Gain";
8748 0 : vh[2]=vh[6]="Tsys";
8749 0 : vh[1]=vh[3]=vh[5]=vh[7]=" ";
8750 : }
8751 0 : else if (this->typeName()=="K Jones") {
8752 0 : vh[0]="Delay ";
8753 0 : vh[1]=" ";
8754 : }
8755 0 : else if (this->typeName().contains("Opac")) {
8756 0 : vh[0]="Opac ";
8757 0 : vh[1]=" ";
8758 : }
8759 0 : else if (this->typeName().contains("KAntPos")) {
8760 0 : nh=6;
8761 0 : vh.resize(nh);
8762 0 : vh[0]="dX m";
8763 0 : vh[2]="dY m";
8764 0 : vh[4]="dZ m";
8765 0 : vh[1]=vh[3]=vh[5]=" ";
8766 : }
8767 0 : else if (this->typeName().contains("EGainCurve")) {
8768 0 : nh=8;
8769 0 : vh.resize(nh);
8770 0 : vh[0]="c[0]";
8771 0 : vh[2]="c[1]";
8772 0 : vh[4]="c[2]";
8773 0 : vh[6]="c[3]";
8774 0 : vh[1]=vh[3]=vh[5]=vh[7]=" ";
8775 : }
8776 0 : else if (this->typeName().contains("TSYS")) {
8777 0 : vh[0]="Tsys";
8778 0 : vh[1]=" ";
8779 : }
8780 :
8781 0 : cout.setf(ios::right, ios::adjustfield);
8782 0 : for(uInt k=0; (k<numAntCols) and (iElem+k<=numAnts-1); k++) {
8783 0 : for (Int ip=0;ip<nPar();++ip) {
8784 0 : if (ip>0) cout << " ";
8785 0 : cout << setw(wAmp_p) << vh[(2*ip)%nh] << " "
8786 0 : << setw(wPhase_p) << vh[(2*ip+1)%nh] << " "
8787 0 : << "F";
8788 : }
8789 0 : cout << "|";
8790 : }
8791 0 : cout << endl; lineCount++;
8792 : // Construct the horizontal separator
8793 0 : String hSeparator=replicate('-',wTotal_p);
8794 0 : uInt colPos=0;
8795 0 : colPos+=wTime_p; hSeparator[colPos]='|'; colPos++;
8796 0 : colPos+=wField_p; hSeparator[colPos]='|'; colPos++;
8797 0 : colPos+=wChan_p; hSeparator[colPos]='|'; colPos++;
8798 0 : for(uInt iPol=0; iPol<numAntCols*nPar(); iPol++) {
8799 0 : colPos+=wPol_p-1;
8800 0 : hSeparator[colPos]='|';
8801 0 : colPos++;
8802 : }
8803 : // Write horizontal separator
8804 0 : cout << hSeparator << endl; lineCount++;
8805 0 : return lineCount;
8806 : } // end writeHeader
8807 :
8808 : // Globals
8809 :
8810 : // Return a cal table's type, verifying its existence
8811 0 : String calTableType(const String& tablename) {
8812 :
8813 : // Check existence...
8814 0 : if (!Table::isReadable(tablename)) {
8815 0 : ostringstream o;
8816 0 : o << "Table " << tablename
8817 0 : << " does not exist.";
8818 0 : throw(AipsError(String(o)));
8819 : }
8820 :
8821 : // Table exists...
8822 :
8823 0 : TableInfo ti(TableUtil::tableInfo(tablename));
8824 :
8825 : // ...Check if Calibration table....
8826 0 : if (ti.type()!="Calibration") {
8827 0 : ostringstream o;
8828 0 : o << "Table " << tablename
8829 : << " is not a valid Calibration table."
8830 0 : << " (expected type = \"Calibration\"; type found = \""
8831 0 : << ti.type() << "\")";
8832 0 : throw(AipsError(String(o)));
8833 :
8834 : }
8835 :
8836 : // If we get here, we have a calibration table,
8837 : // so return its type
8838 0 : return ti.subType();
8839 :
8840 : }
8841 :
8842 :
8843 : } //# NAMESPACE CASA - END
|