Line data Source code
1 : //# MSTransformManager.cc: This file contains the implementation of the MSTransformManager class.
2 : //#
3 : //# CASA - Common Astronomy Software Applications (http://casa.nrao.edu/)
4 : //# Copyright (C) Associated Universities, Inc. Washington DC, USA 2011, All rights reserved.
5 : //# Copyright (C) European Southern Observatory, 2011, All rights reserved.
6 : //#
7 : //# This library is free software; you can redistribute it and/or
8 : //# modify it under the terms of the GNU Lesser General Public
9 : //# License as published by the Free software Foundation; either
10 : //# version 2.1 of the License, or (at your option) any later version.
11 : //#
12 : //# This library is distributed in the hope that it will be useful,
13 : //# but WITHOUT ANY WARRANTY, without even the implied warranty of
14 : //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : //# Lesser General Public License for more details.
16 : //#
17 : //# You should have received a copy of the GNU Lesser General Public
18 : //# License along with this library; if not, write to the Free Software
19 : //# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 : //# MA 02111-1307 USA
21 : //# $Id: $
22 :
23 : #include <mstransform/MSTransform/MSTransformManager.h>
24 :
25 : #include <casacore/tables/Tables/TableUtil.h>
26 :
27 : #include <mstransform/TVI/PolAverageTVI.h>
28 : #include <mstransform/TVI/PointingInterpolationTVI.h>
29 : #include <mstransform/TVI/SDAtmosphereCorrectionTVI.h>
30 :
31 : #include <limits>
32 :
33 : using namespace casacore;
34 : namespace casa { //# NAMESPACE CASA - BEGIN
35 :
36 : /////////////////////////////////////////////
37 : ////// MS Transform Framework utilities /////
38 : /////////////////////////////////////////////
39 : namespace MSTransformations
40 : {
41 0 : Double wtToSigma(Double weight)
42 : {
43 0 : return weight > FLT_MIN ? 1.0 / std::sqrt (weight) : -1.0;
44 : }
45 :
46 0 : Double sigmaToWeight(Double sigma)
47 : {
48 0 : return sigma > FLT_MIN ? 1.0 / std::pow (sigma,2) : 0.0;
49 : }
50 :
51 : Unit Hz(String("Hz"));
52 : }
53 :
54 : /////////////////////////////////////////////
55 : /// MSTransformManager implementation ///
56 : /////////////////////////////////////////////
57 :
58 : // -----------------------------------------------------------------------
59 : // Default constructor
60 : // -----------------------------------------------------------------------
61 0 : MSTransformManager::MSTransformManager()
62 : {
63 0 : initialize();
64 0 : return;
65 : }
66 :
67 :
68 : // -----------------------------------------------------------------------
69 : // Configuration constructor
70 : // -----------------------------------------------------------------------
71 0 : MSTransformManager::MSTransformManager(Record configuration)
72 : {
73 0 : initialize();
74 0 : configure(configuration);
75 0 : return;
76 : }
77 :
78 :
79 : // -----------------------------------------------------------------------
80 : // Default destructor
81 : // -----------------------------------------------------------------------
82 0 : MSTransformManager::~MSTransformManager()
83 : {
84 : // Close the output MS in case the application layer does not do it
85 0 : close();
86 :
87 0 : if (channelSelector_p) delete channelSelector_p;
88 0 : if (visibilityIterator_p and !factory_p) delete visibilityIterator_p;
89 0 : if (dataHandler_p) delete dataHandler_p;
90 0 : if (phaseCenterPar_p) delete phaseCenterPar_p;
91 :
92 : // Delete the output Ms if we are in buffer mode
93 : // This has to be done after deleting the outputMS data handler
94 0 : if (userBufferMode_p)
95 : {
96 0 : TableUtil::deleteTable(outMsName_p,true);
97 : }
98 :
99 0 : return;
100 0 : }
101 :
102 : // -----------------------------------------------------------------------
103 : // Method to initialize members to default values
104 : // -----------------------------------------------------------------------
105 0 : void MSTransformManager::initialize()
106 : {
107 : // MS specification parameters
108 0 : inpMsName_p = String("");
109 0 : outMsName_p = String("");
110 0 : datacolumn_p = String("CORRECTED");
111 0 : makeVirtualModelColReal_p = false; // MODEL_DATA should always be made real via the datacol param.
112 0 : makeVirtualCorrectedColReal_p = true; // TODO: CORRECTED_DATA should be made real on request
113 0 : tileShape_p.resize(1,false);
114 : //TileShape of size 1 can have 2 values [0], and [1] ...these are used in to
115 : //determine the tileshape by using MSTileLayout. Otherwise it has to be a
116 : //vector size 3 e.g [4, 15, 351] => a tile shape of 4 stokes, 15 channels 351
117 : //rows.
118 0 : tileShape_p(0) = 0;
119 :
120 : // Data selection parameters
121 0 : arraySelection_p = String("");
122 0 : fieldSelection_p = String("");
123 0 : scanSelection_p = String("");
124 0 : timeSelection_p = String("");
125 0 : spwSelection_p = String("");
126 0 : baselineSelection_p = String("");
127 0 : uvwSelection_p = String("");
128 0 : polarizationSelection_p = String("");
129 0 : scanIntentSelection_p = String("");
130 0 : observationSelection_p = String("");
131 0 : taqlSelection_p = String("");
132 0 : feedSelection_p = String("");
133 :
134 : // Input-Output index maps
135 0 : inputOutputObservationIndexMap_p.clear();
136 0 : inputOutputArrayIndexMap_p.clear();
137 0 : inputOutputScanIndexMap_p.clear();
138 0 : inputOutputScanIntentIndexMap_p.clear();
139 0 : inputOutputFieldIndexMap_p.clear();
140 0 : inputOutputSPWIndexMap_p.clear();
141 0 : inputOutputDDIndexMap_p.clear();
142 0 : inputOutputAntennaIndexMap_p.clear();
143 0 : outputInputSPWIndexMap_p.clear();
144 0 : inputOutputChanIndexMap_p.clear();
145 :
146 : // Frequency transformation parameters
147 0 : smoothCoeff_p.resize(3,false);
148 0 : smoothCoeff_p(0) = 0.25;
149 0 : smoothCoeff_p(1) = 0.5;
150 0 : smoothCoeff_p(2) = 0.25;
151 :
152 : // Frequency specification parameters
153 0 : mode_p = String("channel"); // Options are: channel, frequency, velocity
154 0 : start_p = String("0");
155 0 : width_p = String("1");
156 0 : nChan_p = -1; // -1 means use all the input channels
157 0 : velocityType_p = String("radio"); // When mode is velocity options are: optical, radio
158 :
159 : // Phase shifting parameters
160 : // CAS-12706 To run phase shift via a TVI which has
161 : // support for shifting across large offset/angles
162 0 : dx_p = 0;
163 0 : dy_p = 0;
164 0 : tviphaseshift_p = False;
165 0 : tviphaseshiftConfig_p = Record();
166 :
167 : // Time transformation parameters
168 0 : scalarAverage_p = false;
169 0 : timeAverage_p = false;
170 0 : timeBin_p = 0.0;
171 0 : timespan_p = String("");
172 0 : timeAvgOptions_p = vi::AveragingOptions(vi::AveragingOptions::Nothing);
173 0 : maxuvwdistance_p = 0;
174 : // minbaselines_p = 0;
175 :
176 : // Cal parameters
177 0 : calibrate_p = false;
178 0 : callib_p = "";
179 0 : callibRec_p = Record();
180 :
181 : // UVContSub parameters
182 0 : uvcontsub_p = False;
183 0 : uvcontsubRec_p = Record();
184 :
185 : // Spw averaging
186 0 : spwAverage_p = false;
187 :
188 : // Polarization transformation
189 0 : polAverage_p = false;
190 0 : polAverageConfig_p = Record();
191 :
192 : // Pointings interpolation
193 0 : pointingsInterpolation_p = false;
194 0 : pointingsInterpolationConfig_p = Record();
195 :
196 : // Weight Spectrum parameters
197 0 : usewtspectrum_p = false;
198 0 : spectrumTransformation_p = false;
199 0 : propagateWeights_p = false;
200 0 : flushWeightSpectrum_p = false;
201 :
202 : // MS-related members
203 0 : dataHandler_p = NULL;
204 0 : inputMs_p = NULL;
205 0 : selectedInputMs_p = NULL;
206 0 : outputMs_p = NULL;
207 0 : selectedInputMsCols_p = NULL;
208 0 : outputMsCols_p = NULL;
209 :
210 : // VI/VB related members
211 0 : sortColumns_p = Block<Int>(7);
212 0 : sortColumns_p[0] = MS::OBSERVATION_ID;
213 0 : sortColumns_p[1] = MS::ARRAY_ID;
214 0 : sortColumns_p[2] = MS::SCAN_NUMBER;
215 0 : sortColumns_p[3] = MS::STATE_ID;
216 0 : sortColumns_p[4] = MS::FIELD_ID;
217 0 : sortColumns_p[5] = MS::DATA_DESC_ID;
218 0 : sortColumns_p[6] = MS::TIME;
219 0 : visibilityIterator_p = NULL;
220 0 : channelSelector_p = NULL;
221 :
222 : // Output MS structure related members
223 0 : inputFlagCategoryAvailable_p = false;
224 0 : inputWeightSpectrumAvailable_p = false;
225 0 : weightSpectrumFromSigmaFilled_p = false;
226 0 : correctedToData_p = false;
227 0 : bothDataColumnsAreOutput_p = false;
228 0 : doingData_p = false;
229 0 : doingCorrected_p = false;
230 0 : doingModel_p = false;
231 0 : dataColMap_p.clear();
232 0 : mainColumn_p = MS::CORRECTED_DATA;
233 0 : nRowsToAdd_p = 0;
234 :
235 : // Frequency transformation members
236 0 : chansPerOutputSpw_p = 0;
237 0 : tailOfChansforLastSpw_p = 0;
238 0 : interpolationMethod_p = MSTransformations::linear;
239 0 : baselineMap_p.clear();
240 0 : rowIndex_p.clear();
241 0 : spwChannelMap_p.clear();
242 0 : inputOutputSpwMap_p.clear();
243 0 : inputOutputChanFactorMap_p.clear();
244 0 : freqbinMap_p.clear();
245 0 : numOfInpChanMap_p.clear();
246 0 : numOfSelChanMap_p.clear();
247 0 : numOfOutChanMap_p.clear();
248 0 : numOfCombInputChanMap_p.clear();
249 0 : numOfCombInterChanMap_p.clear();
250 0 : weightFactorMap_p.clear();
251 0 : sigmaFactorMap_p.clear();
252 0 : newWeightFactorMap_p.clear();
253 0 : newSigmaFactorMap_p.clear();
254 :
255 : // Reference frame transformation members
256 0 : fftShiftEnabled_p = false;
257 0 : fftShift_p = 0;
258 :
259 : // Weight Spectrum members
260 0 : inputWeightSpectrumAvailable_p = false;
261 0 : combinationOfSPWsWithDifferentExposure_p = false;
262 :
263 : // Transformations - related function pointers
264 0 : transformCubeOfDataComplex_p = NULL;
265 0 : transformCubeOfDataFloat_p = NULL;
266 0 : fillWeightsPlane_p = NULL;
267 0 : setWeightsPlaneByReference_p = NULL;
268 0 : setWeightStripeByReference_p = NULL;
269 0 : transformStripeOfDataComplex_p = NULL;
270 0 : transformStripeOfDataFloat_p = NULL;
271 0 : averageKernelComplex_p = NULL;
272 0 : averageKernelFloat_p = NULL;
273 0 : smoothKernelComplex_p = NULL;
274 0 : smoothKernelFloat_p = NULL;
275 :
276 : // I/O related function pointers
277 0 : writeOutputPlanesComplex_p = NULL;
278 0 : writeOutputPlanesFloat_p = NULL;
279 0 : writeOutputFlagsPlane_p = NULL;
280 0 : writeOutputFlagsPlaneSlices_p = NULL;
281 0 : writeOutputFlagsPlaneReshapedSlices_p = NULL;
282 :
283 : // Buffer handling members
284 0 : bufferMode_p = false;
285 0 : userBufferMode_p = false;
286 0 : reindex_p = true;
287 0 : factory_p = False;
288 0 : interactive_p = false;
289 0 : spectrumReshape_p = false;
290 0 : cubeTransformation_p = false;
291 0 : dataColumnAvailable_p = false;
292 0 : correctedDataColumnAvailable_p = false;
293 0 : modelDataColumnAvailable_p = false;
294 0 : floatDataColumnAvailable_p = false;
295 0 : flagCube_p = NULL;
296 0 : visCube_p = NULL;
297 0 : visCubeCorrected_p = NULL;
298 0 : visCubeModel_p = NULL;
299 0 : visCubeFloat_p = NULL;
300 0 : weightSpectrum_p = NULL;
301 0 : sigmaSpectrum_p = NULL;
302 0 : weight_p = NULL;
303 0 : sigma_p = NULL;
304 0 : relativeRow_p = 0;
305 :
306 : // single dish specific
307 0 : smoothFourier_p = false;
308 :
309 0 : return;
310 : }
311 :
312 : // -----------------------------------------------------------------------
313 : // Method to parse the configuration parameters
314 : // -----------------------------------------------------------------------
315 0 : void MSTransformManager::configure(Record &configuration)
316 : {
317 0 : parseMsSpecParams(configuration);
318 0 : parseDataSelParams(configuration);
319 0 : parseFreqTransParams(configuration);
320 0 : parseChanAvgParams(configuration);
321 0 : parseRefFrameTransParams(configuration);
322 0 : parseTimeAvgParams(configuration);
323 0 : parseCalParams(configuration);
324 0 : parseUVContSubParams(configuration);
325 0 : setSpwAvg(configuration);
326 0 : parsePolAvgParams(configuration);
327 0 : parsePointingsInterpolationParams(configuration);
328 0 : parsePhaseShiftParams(configuration);
329 0 : parseAtmCorrectionParams(configuration);
330 :
331 0 : return;
332 : }
333 :
334 : // -----------------------------------------------------------------------
335 : // Method to parse input/output MS specification
336 : // -----------------------------------------------------------------------
337 0 : void MSTransformManager::parseMsSpecParams(Record &configuration)
338 : {
339 0 : int exists = -1;
340 :
341 0 : exists = -1;
342 0 : exists = configuration.fieldNumber ("inputms");
343 0 : if (exists >= 0)
344 : {
345 0 : configuration.get (exists, inpMsName_p);
346 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
347 0 : << "Input file name is " << inpMsName_p << LogIO::POST;
348 : }
349 :
350 0 : exists = -1;
351 0 : exists = configuration.fieldNumber ("buffermode");
352 0 : if (exists >= 0)
353 : {
354 0 : configuration.get (exists, userBufferMode_p);
355 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
356 0 : << "Buffer mode is on " << LogIO::POST;
357 :
358 0 : bufferMode_p = userBufferMode_p;
359 : }
360 :
361 : // In buffer mode this is needed for the time average VI/VB which needs to be informed beforehand
362 0 : exists = -1;
363 0 : exists = configuration.fieldNumber ("datacolumn");
364 0 : if (exists >= 0)
365 : {
366 0 : configuration.get (exists, datacolumn_p);
367 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
368 0 : << "Data column is " << datacolumn_p << LogIO::POST;
369 : }
370 :
371 : // In buffer mode outputms is just a random generated filename used as a placeholder for the re-indexed subtables
372 0 : exists = -1;
373 0 : exists = configuration.fieldNumber ("outputms");
374 0 : if (exists >= 0)
375 : {
376 0 : configuration.get (exists, outMsName_p);
377 :
378 : // Inform of filename only in normal mode, as in buffer mode is random generated
379 0 : if (not bufferMode_p)
380 : {
381 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
382 0 : << "Output file name is " << outMsName_p << LogIO::POST;
383 : }
384 : }
385 :
386 0 : exists = -1;
387 0 : exists = configuration.fieldNumber ("reindex");
388 0 : if (exists >= 0)
389 : {
390 0 : configuration.get (exists, reindex_p);
391 :
392 0 : if (reindex_p)
393 : {
394 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
395 0 : << "Re-index is enabled " << LogIO::POST;
396 : }
397 : else
398 : {
399 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
400 0 : << "Re-index is disabled " << LogIO::POST;
401 : }
402 : }
403 :
404 0 : exists = -1;
405 0 : exists = configuration.fieldNumber ("factory");
406 0 : if (exists >= 0)
407 : {
408 0 : configuration.get (exists, factory_p);
409 :
410 0 : if (factory_p)
411 : {
412 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
413 0 : << "Factory mode enabled " << LogIO::POST;
414 : }
415 : }
416 :
417 0 : if (userBufferMode_p)
418 : {
419 0 : interactive_p = true;
420 :
421 0 : exists = -1;
422 0 : exists = configuration.fieldNumber ("interactive");
423 0 : if (exists >= 0)
424 : {
425 0 : configuration.get (exists, interactive_p);
426 :
427 0 : if (interactive_p)
428 : {
429 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
430 0 : << "Interactive mode is enabled - flagging will be applied on input MS " << LogIO::POST;
431 : }
432 : else
433 : {
434 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
435 0 : << "Interactive mode is disabled - flagging will not be applied on input MS " << LogIO::POST;
436 : }
437 : }
438 : }
439 : else
440 : {
441 0 : interactive_p = false;
442 :
443 0 : exists = -1;
444 0 : exists = configuration.fieldNumber ("realmodelcol");
445 0 : if (exists >= 0)
446 : {
447 0 : configuration.get (exists, makeVirtualModelColReal_p);
448 0 : if (makeVirtualModelColReal_p)
449 : {
450 0 : if (datacolumn_p.contains("ALL") or datacolumn_p.contains("MODEL"))
451 : {
452 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
453 : << "MODEL column will be made real in the output MS "
454 0 : << LogIO::POST;
455 : }
456 : else
457 : {
458 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
459 : << "Requested to make virtual MODEL_DATA column real but "
460 : << "MODEL_DATA column not selected in datacolumn parameter "
461 : << "Options that include MODEL_DATA are 'MODEL' and 'ALL'"
462 0 : << LogIO::POST;
463 0 : makeVirtualModelColReal_p = false;
464 : }
465 : }
466 : }
467 :
468 0 : exists = -1;
469 0 : exists = configuration.fieldNumber ("usewtspectrum");
470 0 : if (exists >= 0)
471 : {
472 0 : configuration.get (exists, usewtspectrum_p);
473 0 : if (usewtspectrum_p)
474 : {
475 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
476 0 : << "WEIGHT_SPECTRUM will be written in output MS " << LogIO::POST;
477 : }
478 : }
479 :
480 0 : exists = -1;
481 0 : exists = configuration.fieldNumber ("tileshape");
482 0 : if (exists >= 0)
483 : {
484 0 : if ( configuration.type(exists) == casacore::TpInt )
485 : {
486 : Int mode;
487 0 : configuration.get (exists, mode);
488 0 : tileShape_p = Vector<Int>(1,mode);
489 : }
490 0 : else if ( configuration.type(exists) == casacore::TpArrayInt)
491 : {
492 0 : configuration.get (exists, tileShape_p);
493 : }
494 :
495 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
496 0 : << "Tile shape is " << tileShape_p << LogIO::POST;
497 : }
498 : }
499 :
500 0 : return;
501 : }
502 :
503 : // -----------------------------------------------------------------------
504 : // Method to parse the data selection parameters
505 : // -----------------------------------------------------------------------
506 0 : void MSTransformManager::parseDataSelParams(Record &configuration)
507 : {
508 0 : int exists = -1;
509 :
510 0 : exists = -1;
511 0 : exists = configuration.fieldNumber ("array");
512 0 : if (exists >= 0)
513 : {
514 0 : configuration.get (exists, arraySelection_p);
515 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
516 0 : << "array selection is " << arraySelection_p << LogIO::POST;
517 : }
518 :
519 0 : exists = -1;
520 0 : exists = configuration.fieldNumber ("field");
521 0 : if (exists >= 0)
522 : {
523 0 : configuration.get (exists, fieldSelection_p);
524 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
525 0 : << "field selection is " << fieldSelection_p << LogIO::POST;
526 : }
527 :
528 0 : exists = -1;
529 0 : exists = configuration.fieldNumber ("scan");
530 0 : if (exists >= 0)
531 : {
532 0 : configuration.get (exists, scanSelection_p);
533 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
534 0 : << "scan selection is " << scanSelection_p << LogIO::POST;
535 : }
536 :
537 0 : exists = -1;
538 0 : exists = configuration.fieldNumber ("timerange");
539 0 : if (exists >= 0)
540 : {
541 0 : configuration.get (exists, timeSelection_p);
542 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
543 0 : << "timerange selection is " << timeSelection_p << LogIO::POST;
544 : }
545 :
546 0 : exists = -1;
547 0 : exists = configuration.fieldNumber ("spw");
548 0 : if (exists >= 0)
549 : {
550 0 : configuration.get (exists, spwSelection_p);
551 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
552 0 : << "spw selection is " << spwSelection_p << LogIO::POST;
553 : }
554 :
555 0 : exists = -1;
556 0 : exists = configuration.fieldNumber ("antenna");
557 0 : if (exists >= 0)
558 : {
559 0 : configuration.get (exists, baselineSelection_p);
560 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
561 0 : << "antenna selection is " << baselineSelection_p << LogIO::POST;
562 : }
563 :
564 0 : exists = -1;
565 0 : exists = configuration.fieldNumber ("uvrange");
566 0 : if (exists >= 0)
567 : {
568 0 : configuration.get (exists, uvwSelection_p);
569 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
570 0 : << "uvrange selection is " << uvwSelection_p << LogIO::POST;
571 : }
572 :
573 0 : exists = -1;
574 0 : exists = configuration.fieldNumber ("correlation");
575 0 : if (exists >= 0)
576 : {
577 0 : configuration.get (exists, polarizationSelection_p);
578 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
579 0 : << "correlation selection is " << polarizationSelection_p << LogIO::POST;
580 : }
581 :
582 0 : exists = -1;
583 0 : exists = configuration.fieldNumber ("observation");
584 0 : if (exists >= 0)
585 : {
586 0 : configuration.get (exists, observationSelection_p);
587 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
588 0 : <<"observation selection is " << observationSelection_p << LogIO::POST;
589 : }
590 :
591 0 : exists = -1;
592 0 : exists = configuration.fieldNumber ("intent");
593 0 : if (exists >= 0)
594 : {
595 0 : configuration.get (exists, scanIntentSelection_p);
596 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
597 0 : << "scan intent selection is " << scanIntentSelection_p << LogIO::POST;
598 : }
599 :
600 0 : exists = -1;
601 0 : exists = configuration.fieldNumber ("taql");
602 0 : if (exists >= 0)
603 : {
604 0 : configuration.get (exists, taqlSelection_p);
605 0 : logger_p << LogIO::NORMAL2 << LogOrigin("MSTransformManager", __FUNCTION__)
606 0 : << "TaQL selection is " << taqlSelection_p << LogIO::POST;
607 : }
608 :
609 0 : exists = -1;
610 0 : exists = configuration.fieldNumber ("feed");
611 0 : if (exists >= 0)
612 : {
613 0 : configuration.get (exists, feedSelection_p);
614 0 : logger_p << LogIO::NORMAL2 << LogOrigin("MSTransformManager", __FUNCTION__)
615 0 : << "feed selection is " << feedSelection_p << LogIO::POST;
616 : }
617 :
618 0 : return;
619 : }
620 :
621 : // -----------------------------------------------------------------------
622 : // Method to parse the channel average parameters
623 : // -----------------------------------------------------------------------
624 0 : void MSTransformManager::parseChanAvgParams(Record &configuration)
625 : {
626 0 : int exists = -1;
627 :
628 0 : exists = -1;
629 0 : exists = configuration.fieldNumber ("chanaverage");
630 0 : if (exists >= 0)
631 : {
632 0 : configuration.get (exists, channelAverage_p);
633 0 : if (channelAverage_p)
634 : {
635 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
636 0 : << "Channel average is activated" << LogIO::POST;
637 : }
638 : else
639 : {
640 0 : return;
641 : }
642 : }
643 : else
644 : {
645 0 : return;
646 : }
647 :
648 0 : exists = -1;
649 0 : exists = configuration.fieldNumber ("chanbin");
650 0 : if (exists >= 0)
651 : {
652 0 : if ( configuration.type(exists) == casacore::TpInt )
653 : {
654 : Int freqbin;
655 0 : configuration.get (exists, freqbin);
656 :
657 0 : if (freqbin < 2)
658 : {
659 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
660 0 : << "Channel bin is " << freqbin << " disabling channel average" << LogIO::POST;
661 0 : channelAverage_p = False;
662 : }
663 : else
664 : {
665 0 : freqbin_p = Vector<Int>(1,freqbin);
666 :
667 : }
668 : }
669 0 : else if ( configuration.type(exists) == casacore::TpArrayInt)
670 : {
671 0 : if(combinespws_p)
672 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
673 : << "If SPW combination is active, "
674 0 : "chabin cannot be an array" << LogIO::EXCEPTION;
675 :
676 0 : configuration.get (exists, freqbin_p);
677 : }
678 : else
679 : {
680 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
681 0 : << "Wrong format for chanbin parameter (only Int and arrayInt are supported) " << LogIO::POST;
682 : }
683 :
684 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
685 0 : << "Channel bin is " << freqbin_p << LogIO::POST;
686 : }
687 : else
688 : {
689 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
690 0 : << "Channel average is activated but no chanbin parameter provided " << LogIO::POST;
691 0 : channelAverage_p = false;
692 0 : return;
693 : }
694 :
695 : // jagonzal: This is now determined by usewtspectrum param and the presence of input WeightSpectrum
696 : /*
697 : exists = configuration.fieldNumber ("useweights");
698 : if (exists >= 0)
699 : {
700 : configuration.get (exists, useweights_p);
701 :
702 : useweights_p.downcase();
703 :
704 : if (useweights_p == "flags")
705 : {
706 : weightmode_p = MSTransformations::flags;
707 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
708 : << "Using FLAGS as weights for channel average" << LogIO::POST;
709 : }
710 : else if (useweights_p == "spectrum")
711 : {
712 : weightmode_p = MSTransformations::spectrum;
713 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
714 : << "Using WEIGHT_SPECTRUM as weights for channel average" << LogIO::POST;
715 : }
716 : else
717 : {
718 : weightmode_p = MSTransformations::flags;
719 : useweights_p = String("flags");
720 : }
721 : }
722 : */
723 :
724 0 : return;
725 : }
726 :
727 : // -----------------------------------------------------------------------
728 : // Method to parse the frequency transformation parameters
729 : // -----------------------------------------------------------------------
730 0 : void MSTransformManager::parseFreqTransParams(Record &configuration)
731 : {
732 0 : int exists = -1;
733 :
734 0 : exists = -1;
735 0 : exists = configuration.fieldNumber ("combinespws");
736 0 : if (exists >= 0)
737 : {
738 0 : configuration.get (exists, combinespws_p);
739 :
740 0 : if (combinespws_p)
741 : {
742 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
743 0 : << "Combine Spectral Windows is activated" << LogIO::POST;
744 : }
745 : }
746 :
747 0 : exists = -1;
748 0 : exists = configuration.fieldNumber ("ddistart");
749 0 : if (exists >= 0)
750 : {
751 0 : configuration.get (exists, ddiStart_p);
752 0 : if (ddiStart_p > 0)
753 : {
754 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
755 0 : << "DDI start is " << ddiStart_p << LogIO::POST;
756 : }
757 : else
758 : {
759 0 : ddiStart_p = 0;
760 : }
761 :
762 : }
763 :
764 0 : exists = -1;
765 0 : exists = configuration.fieldNumber ("hanning");
766 0 : if (exists >= 0)
767 : {
768 0 : configuration.get (exists, hanningSmooth_p);
769 :
770 0 : if (hanningSmooth_p)
771 : {
772 0 : smoothBin_p = 3;
773 0 : smoothCoeff_p.resize(3,false);
774 0 : smoothCoeff_p(0) = 0.25;
775 0 : smoothCoeff_p(1) = 0.5;
776 0 : smoothCoeff_p(2) = 0.25;
777 0 : weightmode_p = MSTransformations::plainSmooth;
778 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
779 0 : << "Hanning Smooth is activated" << LogIO::POST;
780 : }
781 : }
782 :
783 0 : exists = -1;
784 0 : exists = configuration.fieldNumber("smoothFourier");
785 0 : if (exists >= 0)
786 : {
787 0 : configuration.get(exists, smoothFourier_p);
788 0 : if (smoothFourier_p) {
789 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
790 0 : << "Fourier smoothing (single dish specific) is activated" << LogIO::POST;
791 : }
792 : }
793 :
794 0 : return;
795 : }
796 :
797 : // -----------------------------------------------------------------------
798 : // Method to parse the reference frame transformation parameters
799 : // -----------------------------------------------------------------------
800 0 : void MSTransformManager::parseRefFrameTransParams(Record &configuration)
801 : {
802 0 : int exists = -1;
803 :
804 0 : exists = -1;
805 0 : exists = configuration.fieldNumber ("regridms");
806 0 : if (exists >= 0)
807 : {
808 0 : configuration.get (exists, regridding_p);
809 :
810 0 : if (regridding_p)
811 : {
812 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
813 0 : << "Regrid MS is activated"<< LogIO::POST;
814 : }
815 : else
816 : {
817 0 : return;
818 : }
819 : }
820 :
821 0 : exists = -1;
822 0 : exists = configuration.fieldNumber ("phasecenter");
823 0 : if (exists >= 0)
824 : {
825 : //If phase center is a simple numeric value then it is taken
826 : // as a FIELD_ID otherwise it is converted to a MDirection
827 0 : if( configuration.type(exists) == TpInt )
828 : {
829 0 : int fieldIdForPhaseCenter = -1;
830 0 : configuration.get (exists, fieldIdForPhaseCenter);
831 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
832 0 : << "Field Id for phase center is " << fieldIdForPhaseCenter << LogIO::POST;
833 0 : if (phaseCenterPar_p) delete phaseCenterPar_p;
834 0 : phaseCenterPar_p = new casac::variant((long)fieldIdForPhaseCenter);
835 : }
836 : else
837 : {
838 0 : String phaseCenter("");
839 0 : configuration.get (exists, phaseCenter);
840 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
841 0 : << "Phase center is " << phaseCenter << LogIO::POST;
842 0 : if (phaseCenterPar_p) delete phaseCenterPar_p;
843 0 : phaseCenterPar_p = new casac::variant(phaseCenter);
844 : }
845 : }
846 :
847 0 : exists = -1;
848 0 : exists = configuration.fieldNumber ("restfreq");
849 0 : if (exists >= 0)
850 : {
851 0 : configuration.get (exists, restFrequency_p);
852 0 : if (!restFrequency_p.empty())
853 : {
854 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
855 0 : << "Rest frequency is " << restFrequency_p << LogIO::POST;
856 : }
857 : }
858 :
859 0 : exists = -1;
860 0 : exists = configuration.fieldNumber ("outframe");
861 0 : if (exists >= 0)
862 : {
863 0 : configuration.get (exists, outputReferenceFramePar_p);
864 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
865 0 : << "Output reference frame is " << outputReferenceFramePar_p << LogIO::POST;
866 : }
867 :
868 0 : exists = -1;
869 0 : exists = configuration.fieldNumber ("interpolation");
870 0 : if (exists >= 0)
871 : {
872 0 : configuration.get (exists, interpolationMethodPar_p);
873 :
874 0 : if (interpolationMethodPar_p.contains("nearest"))
875 : {
876 0 : interpolationMethod_p = MSTransformations::nearestNeighbour;
877 : }
878 0 : else if (interpolationMethodPar_p.contains("linear"))
879 : {
880 0 : interpolationMethod_p = MSTransformations::linear;
881 : }
882 0 : else if (interpolationMethodPar_p.contains("cubic"))
883 : {
884 0 : interpolationMethod_p = MSTransformations::cubic;
885 : }
886 0 : else if (interpolationMethodPar_p.contains("spline"))
887 : {
888 0 : interpolationMethod_p = MSTransformations::spline;
889 : }
890 0 : else if (interpolationMethodPar_p.contains("fftshift"))
891 : {
892 0 : fftShiftEnabled_p = true;
893 0 : interpolationMethod_p = MSTransformations::linear;
894 : }
895 : else
896 : {
897 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
898 0 : << "Interpolation method " << interpolationMethodPar_p << " not available " << LogIO::POST;
899 : }
900 :
901 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
902 0 : << "Interpolation method is " << interpolationMethodPar_p << LogIO::POST;
903 : }
904 : else
905 : {
906 0 : interpolationMethod_p = MSTransformations::linear;
907 : }
908 :
909 0 : exists = -1;
910 0 : exists = configuration.fieldNumber ("nspw");
911 0 : if (exists >= 0)
912 : {
913 0 : configuration.get (exists, nspws_p);
914 :
915 0 : if (nspws_p > 1)
916 : {
917 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
918 0 : << "Number of output SPWs is " << nspws_p << LogIO::POST;
919 0 : combinespws_p = true;
920 : }
921 : else
922 : {
923 0 : nspws_p = 1;
924 : }
925 : }
926 :
927 0 : parseFreqSpecParams(configuration);
928 :
929 0 : exists = configuration.fieldNumber ("preaverage");
930 0 : if (exists >= 0) {
931 0 : configuration.get (exists, enableChanPreAverage_p);
932 :
933 0 : if (combinespws_p) {
934 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
935 0 : << "Enabling channel pre-averaging" << LogIO::POST;
936 : }
937 : }
938 :
939 0 : return;
940 : }
941 :
942 : // -----------------------------------------------------------------------
943 : // Method to parse the frequency selection specification
944 : // -----------------------------------------------------------------------
945 0 : void MSTransformManager::parseFreqSpecParams(Record &configuration)
946 : {
947 0 : int exists = -1;
948 :
949 0 : exists = -1;
950 0 : exists = configuration.fieldNumber ("mode");
951 0 : if (exists >= 0)
952 : {
953 0 : configuration.get (exists, mode_p);
954 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
955 0 : << "Mode is " << mode_p<< LogIO::POST;
956 :
957 0 : if ((mode_p == "frequency") or (mode_p == "velocity"))
958 : {
959 0 : start_p = String("");
960 0 : width_p = String("");
961 : }
962 : }
963 :
964 0 : exists = -1;
965 0 : exists = configuration.fieldNumber ("nchan");
966 0 : if (exists >= 0)
967 : {
968 0 : configuration.get (exists, nChan_p);
969 0 : if (nspws_p > 1)
970 : {
971 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
972 0 : << "Number of output channels per output spw is " << nChan_p << LogIO::POST;
973 0 : nChan_p *= nspws_p;
974 : }
975 : else
976 : {
977 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
978 0 : << "Number of output channels is " << nChan_p<< LogIO::POST;
979 : }
980 : }
981 :
982 0 : exists = -1;
983 0 : exists = configuration.fieldNumber ("start");
984 0 : if (exists >= 0)
985 : {
986 0 : configuration.get (exists, start_p);
987 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
988 0 : << "Start is " << start_p << LogIO::POST;
989 : }
990 :
991 0 : exists = -1;
992 0 : exists = configuration.fieldNumber ("width");
993 0 : if (exists >= 0)
994 : {
995 0 : configuration.get (exists, width_p);
996 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
997 0 : << "Width is " << width_p << LogIO::POST;
998 : }
999 :
1000 0 : exists = -1;
1001 0 : exists = configuration.fieldNumber ("veltype");
1002 0 : if ((exists >= 0) and (mode_p == "velocity"))
1003 : {
1004 0 : configuration.get (exists, velocityType_p);
1005 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1006 0 : << "Velocity type is " << velocityType_p << LogIO::POST;
1007 : }
1008 :
1009 0 : return;
1010 : }
1011 :
1012 : // -----------------------------------------------------------------------
1013 : // Method to parse the phase shifting specification
1014 : // -----------------------------------------------------------------------
1015 : // CAS-12706 To run phase shift via a TVI which has
1016 : // support for shifting across large offset/angles
1017 : // -----------------------------------------------------------------------
1018 0 : void MSTransformManager::parsePhaseShiftParams(Record &configuration)
1019 : {
1020 0 : int exists = -1;
1021 :
1022 0 : exists = -1;
1023 0 : exists = configuration.fieldNumber("tviphaseshift");
1024 0 : if (exists >= 0)
1025 : {
1026 0 : configuration.get (exists, tviphaseshift_p);
1027 :
1028 0 : if (tviphaseshift_p)
1029 : {
1030 : // Extract the callib Record
1031 0 : exists = -1;
1032 0 : exists = configuration.fieldNumber("tviphaseshiftlib");
1033 0 : if (configuration.type(exists) == TpRecord)
1034 : {
1035 0 : tviphaseshiftConfig_p = configuration.subRecord(exists);
1036 : }
1037 :
1038 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager",__FUNCTION__)
1039 : << "Phase shifting via TVI with support for large offset/angle "
1040 0 : << LogIO::POST;
1041 : }
1042 : }
1043 :
1044 0 : return;
1045 : }
1046 :
1047 : // -----------------------------------------------------------------------
1048 : // Method to parse the time average specification
1049 : // -----------------------------------------------------------------------
1050 0 : void MSTransformManager::parseTimeAvgParams(Record &configuration)
1051 : {
1052 0 : int exists = -1;
1053 :
1054 0 : exists = -1;
1055 0 : exists = configuration.fieldNumber ("timeaverage");
1056 0 : if (exists >= 0)
1057 : {
1058 0 : configuration.get (exists, timeAverage_p);
1059 :
1060 0 : if (timeAverage_p)
1061 : {
1062 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1063 0 : << "Time average is activated" << LogIO::POST;
1064 : }
1065 : }
1066 :
1067 0 : exists = -1;
1068 0 : exists = configuration.fieldNumber ("scalaraverage");
1069 0 : if (exists >= 0)
1070 : {
1071 0 : configuration.get (exists, scalarAverage_p);
1072 :
1073 0 : if (scalarAverage_p)
1074 : {
1075 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1076 0 : << "Scalar average is activated" << LogIO::POST;
1077 : }
1078 : }
1079 :
1080 0 : if (timeAverage_p || scalarAverage_p)
1081 : {
1082 0 : exists = -1;
1083 0 : exists = configuration.fieldNumber ("timebin");
1084 0 : if (exists >= 0)
1085 : {
1086 0 : String timebin;
1087 0 : configuration.get (exists, timebin);
1088 0 : timeBin_p=casaQuantity(timebin).get("s").getValue();
1089 :
1090 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1091 0 : << "Time bin is " << timeBin_p << " seconds" << LogIO::POST;
1092 : }
1093 : else
1094 : {
1095 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
1096 0 : << "Time or scalar average is activated but no timebin parameter provided " << LogIO::POST;
1097 0 : timeAverage_p = false;
1098 0 : scalarAverage_p = false;
1099 0 : return;
1100 : }
1101 :
1102 0 : exists = -1;
1103 0 : exists = configuration.fieldNumber ("timespan");
1104 0 : if (exists >= 0)
1105 : {
1106 0 : configuration.get (exists, timespan_p);
1107 :
1108 0 : if (!timespan_p.contains("scan") and !timespan_p.contains("state") and !timespan_p.contains("field"))
1109 : {
1110 0 : timespan_p = String("");
1111 : }
1112 : else
1113 : {
1114 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1115 0 : << "Time span is " << timespan_p << LogIO::POST;
1116 : }
1117 : }
1118 :
1119 : // CAS-4850 (jagonzal): For ALMA each bdf is limited to 30s, so we need to combine across state (i.e. su-scan)
1120 0 : if (timeAverage_p && (timeBin_p > 30.0) and !timespan_p.contains("state"))
1121 : {
1122 0 : MeasurementSet tmpMs(inpMsName_p,Table::Old);
1123 0 : MSObservation observationTable = tmpMs.observation();
1124 0 : MSObservationColumns observationCols(observationTable);
1125 0 : String telescopeName = observationCols.telescopeName()(0);
1126 :
1127 0 : if (telescopeName.contains("ALMA"))
1128 : {
1129 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
1130 : << "Operating with ALMA data, automatically adding state to timespan "<< endl
1131 0 : << "In order to remove sub-scan boundaries which limit time average to 30s "<< LogIO::POST;
1132 0 : timespan_p += String(",state");
1133 : }
1134 : }
1135 :
1136 0 : exists = -1;
1137 0 : exists = configuration.fieldNumber ("maxuvwdistance");
1138 0 : if (exists >= 0)
1139 : {
1140 0 : configuration.get (exists, maxuvwdistance_p);
1141 :
1142 0 : if (maxuvwdistance_p > 0)
1143 : {
1144 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1145 : << "Maximum UV distance for baseline-dependent time average is: "
1146 0 : << maxuvwdistance_p << " meters" << LogIO::POST;
1147 : }
1148 : }
1149 :
1150 : /*
1151 : exists = configuration.fieldNumber ("minbaselines");
1152 : if (exists >= 0)
1153 : {
1154 : configuration.get (exists, minbaselines_p);
1155 :
1156 : if (minbaselines_p > 0)
1157 : {
1158 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1159 : << "Minimum number of baselines for time average: " << minbaselines_p << LogIO::POST;
1160 : }
1161 : }
1162 : */
1163 : }
1164 :
1165 0 : return;
1166 : }
1167 :
1168 : // -----------------------------------------------------------------------
1169 : // Parameter parser for on-the-fly (OTF) calibration
1170 : // -----------------------------------------------------------------------
1171 0 : void MSTransformManager::parseCalParams(Record &configuration)
1172 : {
1173 0 : int exists = configuration.fieldNumber("callib");
1174 0 : if (exists >= 0)
1175 : {
1176 :
1177 0 : if (configuration.type(exists) == TpRecord)
1178 : {
1179 : // Extract the callib Record
1180 0 : callibRec_p = configuration.subRecord(exists);
1181 0 : callib_p="";
1182 :
1183 : // If the Record is non-trivial, calibration is turned on
1184 0 : calibrate_p = callibRec_p.nfields() > 0;
1185 : }
1186 0 : else if (configuration.type(exists) == TpString)
1187 : {
1188 : // Extract the callib String
1189 0 : callib_p = configuration.asString(exists);
1190 0 : callibRec_p = Record();
1191 :
1192 : // If the callib_p String has non-trivial content, calibration in turned on
1193 0 : calibrate_p = callib_p.length() > 0;
1194 :
1195 : }
1196 :
1197 0 : if (calibrate_p)
1198 : {
1199 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager",__FUNCTION__)
1200 0 : << "Calibration is activated" << LogIO::POST;
1201 : }
1202 :
1203 : }
1204 :
1205 0 : return;
1206 : }
1207 :
1208 : // -----------------------------------------------------------------------
1209 : // Parameter parser for continuum subtraction
1210 : // -----------------------------------------------------------------------
1211 0 : void MSTransformManager::parseUVContSubParams(Record &configuration)
1212 : {
1213 0 : int exists = -1;
1214 :
1215 0 : exists = -1;
1216 0 : exists = configuration.fieldNumber("uvcontsub");
1217 0 : if (exists >= 0)
1218 : {
1219 0 : configuration.get (exists, uvcontsub_p);
1220 :
1221 0 : if (uvcontsub_p)
1222 : {
1223 : // Extract the callib Record
1224 0 : exists = -1;
1225 0 : exists = configuration.fieldNumber("uvcontsublib");
1226 0 : if (configuration.type(exists) == TpRecord)
1227 : {
1228 0 : uvcontsubRec_p = configuration.subRecord(exists);
1229 : }
1230 :
1231 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager",
1232 : __FUNCTION__)
1233 : << "Continuum subtraction is activated "
1234 0 : << LogIO::POST;
1235 :
1236 : // not nice going into the subRec, perhaps a writemodel var
1237 : // could be put in the top level record
1238 0 : int writemodel = uvcontsubRec_p.fieldNumber("writemodel");
1239 0 : if (writemodel >= 0) {
1240 0 : bool dowrite = false;
1241 0 : uvcontsubRec_p.get(writemodel, dowrite);
1242 0 : if (dowrite) {
1243 0 : produceModel_p = true;
1244 : }
1245 : }
1246 : }
1247 : }
1248 0 : }
1249 :
1250 : // -----------------------------------------------------------------------
1251 : // Method to set spw averaging
1252 : // -----------------------------------------------------------------------
1253 0 : void MSTransformManager::setSpwAvg(Record &configuration)
1254 : {
1255 0 : int exists = -1;
1256 :
1257 0 : exists = -1;
1258 0 : exists = configuration.fieldNumber ("spwaverage");
1259 0 : if (exists >= 0)
1260 : {
1261 0 : configuration.get (exists, spwAverage_p);
1262 :
1263 0 : if (spwAverage_p)
1264 : {
1265 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1266 0 : << "Spw average is activated" << LogIO::POST;
1267 : }
1268 : }
1269 0 : }
1270 :
1271 : // -----------------------------------------------------------------------
1272 : // Parameter parser for polarization transformation
1273 : // -----------------------------------------------------------------------
1274 0 : void MSTransformManager::parsePolAvgParams(Record &configuration)
1275 : {
1276 0 : String key("polaverage");
1277 0 : bool exists = configuration.isDefined(key);
1278 0 : if (exists) {
1279 0 : polAverage_p = configuration.asBool(key);
1280 : }
1281 :
1282 0 : key = "polaveragemode";
1283 0 : if (polAverage_p) {
1284 0 : if (configuration.isDefined(key)) {
1285 0 : polAverageConfig_p.define("mode", configuration.asString(key));
1286 : } else {
1287 0 : polAverageConfig_p.define("mode", "default");
1288 : }
1289 : }
1290 0 : }
1291 :
1292 0 : void MSTransformManager::parsePointingsInterpolationParams(casacore::Record &configuration){
1293 0 : String key("pointingsinterpolation");
1294 0 : bool exists = configuration.isDefined(key);
1295 0 : if (exists) {
1296 0 : pointingsInterpolation_p = configuration.asBool(key);
1297 : }
1298 0 : }
1299 :
1300 0 : void MSTransformManager::parseAtmCorrectionParams(casacore::Record &configuration) {
1301 0 : String key("atmCor");
1302 0 : if (configuration.isDefined(key)) {
1303 0 : doAtmCor_p = configuration.asBool(key);
1304 0 : atmCorConfig_p = configuration;
1305 : } else {
1306 0 : doAtmCor_p = False;
1307 : }
1308 0 : }
1309 :
1310 : // -----------------------------------------------------------------------
1311 : // Method to open the input MS, select the data and create the
1312 : // structure of the output MS filling the auxiliary tables.
1313 : // -----------------------------------------------------------------------
1314 0 : void MSTransformManager::open()
1315 : {
1316 : // Initialize MSTransformDataHandler to open the MeasurementSet object
1317 0 : if (interactive_p)
1318 : {
1319 : // In buffer mode we may have to modify the flags
1320 0 : dataHandler_p = new MSTransformDataHandler(inpMsName_p,Table::Update);
1321 : }
1322 : else
1323 : {
1324 0 : dataHandler_p = new MSTransformDataHandler(inpMsName_p,Table::Old);
1325 : }
1326 :
1327 :
1328 : // WARNING: Input MS is re-set at the end of a successful MSTransformDataHandler::makeMSBasicStructure,
1329 : // call therefore we have to use the selected MS always
1330 0 : inputMs_p = dataHandler_p->getInputMS();
1331 : // Note: We always get the input number of channels because we don't know if pre-averaging will be necessary
1332 0 : getInputNumberOfChannels();
1333 :
1334 : // Check available data cols to pass this information on to MSTransformDataHandler which creates the MS structure
1335 0 : checkDataColumnsAvailable();
1336 0 : checkDataColumnsToFill();
1337 :
1338 :
1339 : // Check whether the MS has correlator pre-averaging and we are smoothing or averaging
1340 0 : checkCorrelatorPreaveraging();
1341 :
1342 : // Set virtual column operation
1343 0 : dataHandler_p->setVirtualModelCol(makeVirtualModelColReal_p);
1344 0 : dataHandler_p->setVirtualCorrectedCol(makeVirtualCorrectedColReal_p);
1345 :
1346 : // Once the input MS is opened we can get the selection indexes,
1347 : // in this way we also validate the selection parameters
1348 0 : dataHandler_p->setReindex(reindex_p);
1349 0 : initDataSelectionParams();
1350 :
1351 : // Once the selection parameters have been processed, check consistency in
1352 : // number of channels, if needed.
1353 0 : checkSPWChannelsKnownLimitation();
1354 :
1355 : // Determine channel specification for output MS
1356 0 : Vector<Int> chanSpec;
1357 0 : bool spectralRegridding = combinespws_p or regridding_p;
1358 0 : if (channelAverage_p and !spectralRegridding)
1359 : {
1360 0 : chanSpec = freqbin_p;
1361 : }
1362 : else
1363 : {
1364 0 : chanSpec = Vector<Int>(1,1);
1365 : }
1366 :
1367 : // Set-up splitter object
1368 0 : const String dummyExpr = String("");
1369 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__) << "Select data" << LogIO::POST;
1370 0 : dataHandler_p->setmsselect((const String)spwSelection_p,
1371 0 : (const String)fieldSelection_p,
1372 0 : (const String)baselineSelection_p,
1373 0 : (const String)scanSelection_p,
1374 0 : (const String)uvwSelection_p,
1375 0 : (const String)taqlSelection_p,
1376 : chanSpec,
1377 0 : (const String)arraySelection_p,
1378 0 : (const String)polarizationSelection_p,
1379 0 : (const String)scanIntentSelection_p,
1380 0 : (const String)observationSelection_p,
1381 0 : (const String)feedSelection_p);
1382 :
1383 0 : dataHandler_p->selectTime(timeBin_p,timeSelection_p);
1384 :
1385 0 : createOutputMSStructure();
1386 :
1387 : // jagonzal (CAS-5076): Reindex state column when there is scan selection
1388 : // jagonzal (CAS-6351): Removing this fix as only implicit selection-based re-indexing has to be applied
1389 : /*
1390 : map<Int, Int> stateRemapper = dataHandler_p->getStateRemapper();
1391 : std::map<Int, Int>::iterator stateRemapperIter;
1392 : for ( stateRemapperIter = stateRemapper.begin();
1393 : stateRemapperIter != stateRemapper.end();
1394 : stateRemapperIter++)
1395 : {
1396 : inputOutputScanIntentIndexMap_p[stateRemapperIter->first] = stateRemapperIter->second;
1397 :
1398 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1399 : << "State " << stateRemapperIter->first << " mapped to " << stateRemapperIter->second << LogIO::POST;
1400 : }
1401 : */
1402 :
1403 : // jagonzal (CAS-5349): Reindex antenna columns when there is antenna selection
1404 0 : if (!baselineSelection_p.empty() and reindex_p)
1405 : {
1406 0 : Vector<Int> antennaRemapper = dataHandler_p->getAntennaRemapper();
1407 0 : for (uInt oldIndex=0;oldIndex<antennaRemapper.size();oldIndex++)
1408 : {
1409 0 : inputOutputAntennaIndexMap_p[oldIndex] = antennaRemapper[oldIndex];
1410 : }
1411 : }
1412 :
1413 :
1414 0 : selectedInputMs_p = dataHandler_p->getSelectedInputMS();
1415 0 : outputMs_p = dataHandler_p->getOutputMS();
1416 0 : selectedInputMsCols_p = dataHandler_p->getSelectedInputMSColumns();
1417 0 : outputMsCols_p = dataHandler_p->getOutputMSColumns();
1418 :
1419 0 : return;
1420 : }
1421 :
1422 : /**
1423 : * Whether the WEIGHT/SIGMA_SPECTRUM columns should be created in the output MS.
1424 : * This should be honored when creating the output MS structure (in
1425 : * createOutputMSStructure().
1426 : *
1427 : * The logic to say true is: if the WEIGHT/SIGMA_SPECTRUM are present in the input MS or
1428 : * the user has requested the creation of these columns in the output MS anyway via the
1429 : * parameter 'usewtspectrum'
1430 : * This requires that the input configuration be parsed here in MSTransformManager before
1431 : * calling this method, and passed as parameter.
1432 : *
1433 : * @param usewtspectrum value of the usewtspectrum input parameter of mstransform
1434 : *
1435 : * @return whether WEIGHT/SIGMA_SPECTRUM columns should be created in the output MS.
1436 : */
1437 0 : bool MSTransformManager::shouldCreateOutputWtSpectrum(bool usewtspectrum)
1438 : {
1439 0 : if (nullptr == inputMs_p) {
1440 : throw AipsError("When trying to guess if WEIGHT/SIGMA_SPECTRUM should be created "
1441 0 : "in the output MS: the input MS has not been initialized.");
1442 : }
1443 :
1444 0 : auto wtSpec = MSColumns(*inputMs_p).weightSpectrum();
1445 0 : auto inputWeightSpectrumAvailable = !wtSpec.isNull() and wtSpec.isDefined(0);
1446 0 : return inputWeightSpectrumAvailable or usewtspectrum;
1447 : }
1448 :
1449 : /**
1450 : * Helper method for open() to create the structure of the output MS
1451 : * and check errors.
1452 : *
1453 : * @throws AipsError in case of errors creating the output MS
1454 : */
1455 0 : void MSTransformManager::createOutputMSStructure()
1456 : {
1457 : // Create output MS structure
1458 0 : if (not bufferMode_p)
1459 : {
1460 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1461 0 : << "Create output MS structure" << LogIO::POST;
1462 : }
1463 : else
1464 : {
1465 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1466 0 : << "Create transformed MS Subtables to be stored in memory" << LogIO::POST;
1467 : }
1468 :
1469 :
1470 : //jagonzal (CAS-5174)
1471 0 : bool outputMSStructureCreated = false;
1472 : try
1473 : {
1474 0 : Table::TableOption option = Table::New;
1475 0 : if (bufferMode_p) {
1476 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1477 0 : << "Create output MS structure" << LogIO::POST;
1478 0 : option = Table::Scratch;
1479 : }
1480 :
1481 0 : auto createWeightSpectrum = shouldCreateOutputWtSpectrum(usewtspectrum_p);
1482 0 : outputMSStructureCreated = dataHandler_p->makeMSBasicStructure(outMsName_p,
1483 0 : datacolumn_p,
1484 0 : produceModel_p,
1485 : createWeightSpectrum,
1486 0 : tileShape_p,
1487 0 : timespan_p,
1488 : option);
1489 : }
1490 0 : catch (AipsError ex)
1491 : {
1492 0 : outputMSStructureCreated = false;
1493 0 : logger_p << LogIO::DEBUG1
1494 : << "Exception creating output MS structure: " << ex.getMesg() << endl
1495 0 : << LogIO::POST;
1496 :
1497 0 : throw AipsError(ex.getMesg());
1498 : }
1499 :
1500 :
1501 :
1502 0 : if (!outputMSStructureCreated)
1503 : {
1504 0 : throw AipsError("Error creating output MS structure");
1505 : }
1506 0 : }
1507 :
1508 : // -----------------------------------------------------------------------
1509 : // Method to close the output MS
1510 : // -----------------------------------------------------------------------
1511 0 : void MSTransformManager::close()
1512 : {
1513 0 : if (outputMs_p)
1514 : {
1515 : // unlock MS (the MS data handler will flush it when destroying it).
1516 0 : outputMs_p->unlock();
1517 0 : Table::relinquishAutoLocks(true);
1518 :
1519 : // Unset the output MS
1520 0 : outputMs_p = NULL;
1521 : }
1522 :
1523 0 : return;
1524 : }
1525 :
1526 : // -----------------------------------------------------------------------
1527 : // Check configuration and input MS characteristics to determine run parameters
1528 : // -----------------------------------------------------------------------
1529 0 : void MSTransformManager::setup()
1530 : {
1531 : // Check what columns have to filled
1532 : // CAS-5581 (jagonzal): Moving these methods here because we need to know if
1533 : // WEIGHT_SPECTRUM is available to configure the appropriate averaging kernel.
1534 : // - note also that the availability of WEIGHT_SPECTRUM in the input MS needs
1535 : // to be checked even before, as it is needed when doing
1536 : // dataHandler_p->makeMSBasicStructure() in createOutputMSStructure() - CAS-11269
1537 0 : checkFillFlagCategory();
1538 0 : checkFillWeightSpectrum();
1539 :
1540 : // Check if we really need to combine SPWs
1541 0 : if (combinespws_p)
1542 : {
1543 0 : auto nInputSpws = outputMs_p->spectralWindow().nrow();
1544 0 : if (nInputSpws < 2)
1545 : {
1546 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
1547 0 : << "There is only one selected SPW, no need to combine " << LogIO::POST;
1548 0 : combinespws_p = false;
1549 : }
1550 : }
1551 :
1552 : // Regrid SPW subtable
1553 0 : if (combinespws_p)
1554 : {
1555 0 : initRefFrameTransParams();
1556 0 : regridAndCombineSpwSubtable();
1557 0 : reindexDDISubTable();
1558 0 : reindexSourceSubTable();
1559 : //reindexFeedSubTable();
1560 : //reindexSysCalSubTable();
1561 0 : reindexFreqOffsetSubTable();
1562 0 : reindexGenericTimeDependentSubTable("FEED");
1563 0 : reindexGenericTimeDependentSubTable("SYSCAL");
1564 0 : reindexGenericTimeDependentSubTable("CALDEVICE");
1565 0 : reindexGenericTimeDependentSubTable("SYSPOWER");
1566 : }
1567 0 : else if (regridding_p) // regrid as in the regridms option
1568 : {
1569 0 : initRefFrameTransParams();
1570 0 : regridSpwSubTable();
1571 : }
1572 :
1573 : // Subtable manipulation for polarization averaging
1574 0 : if (polAverage_p) {
1575 : // Int nInputPolarizations = outputMs_p->polarization().nrow();
1576 0 : Int averagedPolId = getAveragedPolarizationId();
1577 0 : reindexPolarizationIdInDataDesc(averagedPolId);
1578 : }
1579 :
1580 : //// Determine the frequency transformation methods to use ////
1581 :
1582 :
1583 : // Cube level
1584 0 : if (combinespws_p)
1585 : {
1586 0 : transformCubeOfDataComplex_p = &MSTransformManager::combineCubeOfData;
1587 0 : transformCubeOfDataFloat_p = &MSTransformManager::combineCubeOfData;
1588 0 : spectrumTransformation_p = true;
1589 0 : propagateWeights_p = true;
1590 0 : spectrumReshape_p = true;
1591 0 : cubeTransformation_p = true;
1592 : }
1593 0 : else if (regridding_p)
1594 : {
1595 0 : transformCubeOfDataComplex_p = &MSTransformManager::regridCubeOfData;
1596 0 : transformCubeOfDataFloat_p = &MSTransformManager::regridCubeOfData;
1597 0 : spectrumTransformation_p = true;
1598 0 : propagateWeights_p = true;
1599 0 : spectrumReshape_p = true;
1600 0 : cubeTransformation_p = true;
1601 : }
1602 0 : else if (channelAverage_p)
1603 : {
1604 0 : transformCubeOfDataComplex_p = &MSTransformManager::averageCubeOfData;
1605 0 : transformCubeOfDataFloat_p = &MSTransformManager::averageCubeOfData;
1606 0 : spectrumTransformation_p = true;
1607 0 : propagateWeights_p = true;
1608 0 : spectrumReshape_p = true;
1609 0 : cubeTransformation_p = true;
1610 : }
1611 0 : else if (hanningSmooth_p || smoothFourier_p)
1612 : {
1613 0 : transformCubeOfDataComplex_p = &MSTransformManager::smoothCubeOfData;
1614 0 : transformCubeOfDataFloat_p = &MSTransformManager::smoothCubeOfData;
1615 0 : spectrumTransformation_p = true;
1616 0 : cubeTransformation_p = true;
1617 : }
1618 0 : else if (nspws_p > 1)
1619 : {
1620 0 : transformCubeOfDataComplex_p = &MSTransformManager::separateCubeOfData;
1621 0 : transformCubeOfDataFloat_p = &MSTransformManager::separateCubeOfData;
1622 0 : spectrumReshape_p = true;
1623 0 : cubeTransformation_p = true;
1624 : }
1625 : else
1626 : {
1627 0 : transformCubeOfDataComplex_p = &MSTransformManager::copyCubeOfData;
1628 0 : transformCubeOfDataFloat_p = &MSTransformManager::copyCubeOfData;
1629 : }
1630 :
1631 0 : bool spectralRegridding = combinespws_p or regridding_p;
1632 :
1633 : // Vector level
1634 0 : if (channelAverage_p and !hanningSmooth_p and !spectralRegridding)
1635 : {
1636 0 : transformStripeOfDataComplex_p = &MSTransformManager::average;
1637 0 : transformStripeOfDataFloat_p = &MSTransformManager::average;
1638 : }
1639 0 : else if (!channelAverage_p and hanningSmooth_p and !spectralRegridding)
1640 : {
1641 0 : transformStripeOfDataComplex_p = &MSTransformManager::smooth;
1642 0 : transformStripeOfDataFloat_p = &MSTransformManager::smooth;
1643 : }
1644 0 : else if (!channelAverage_p and !hanningSmooth_p and spectralRegridding)
1645 : {
1646 0 : transformStripeOfDataComplex_p = &MSTransformManager::regrid;
1647 0 : transformStripeOfDataFloat_p = &MSTransformManager::regrid;
1648 : }
1649 0 : else if (channelAverage_p and hanningSmooth_p and !spectralRegridding)
1650 : {
1651 0 : transformStripeOfDataComplex_p = &MSTransformManager::averageSmooth;
1652 0 : transformStripeOfDataFloat_p = &MSTransformManager::averageSmooth;
1653 : }
1654 0 : else if (channelAverage_p and !hanningSmooth_p and spectralRegridding)
1655 : {
1656 0 : transformStripeOfDataComplex_p = &MSTransformManager::averageRegrid;
1657 0 : transformStripeOfDataFloat_p = &MSTransformManager::averageRegrid;
1658 : }
1659 0 : else if (!channelAverage_p and hanningSmooth_p and spectralRegridding)
1660 : {
1661 0 : transformStripeOfDataComplex_p = &MSTransformManager::smoothRegrid;
1662 0 : transformStripeOfDataFloat_p = &MSTransformManager::smoothRegrid;
1663 : }
1664 0 : else if (channelAverage_p and hanningSmooth_p and spectralRegridding)
1665 : {
1666 0 : transformStripeOfDataComplex_p = &MSTransformManager::averageSmoothRegrid;
1667 0 : transformStripeOfDataFloat_p = &MSTransformManager::averageSmoothRegrid;
1668 : }
1669 0 : else if (smoothFourier_p) {
1670 0 : transformStripeOfDataComplex_p = &MSTransformManager::smoothFourierComplex;
1671 0 : transformStripeOfDataFloat_p = &MSTransformManager::smoothFourierFloat;
1672 : }
1673 :
1674 : // If there is not inputWeightSpectrumAvailable_p and no time average then
1675 : // weightSpectrum is constant and has no effect in frequency avg./regridding
1676 0 : if ((not inputWeightSpectrumAvailable_p) and (not timeAverage_p))
1677 : {
1678 0 : propagateWeights_p = false;
1679 0 : weightmode_p = MSTransformations::flagsNonZero;
1680 : }
1681 : else
1682 : {
1683 : // NOTE: It does not hurt to set the averaging kernel even if we are not going to use it
1684 0 : weightmode_p = MSTransformations::flagSpectrumNonZero;
1685 : }
1686 :
1687 : // SPECTRUM columns have to be set when they exists in the input or the user specifies it via usewtspectrum_p
1688 0 : if (inputWeightSpectrumAvailable_p or usewtspectrum_p)
1689 : {
1690 0 : flushWeightSpectrum_p = true;
1691 : }
1692 : else
1693 : {
1694 0 : flushWeightSpectrum_p = false;
1695 : }
1696 :
1697 0 : propagateWeights(propagateWeights_p);
1698 0 : setChannelAverageKernel(weightmode_p);
1699 0 : setSmoothingKernel(smoothmode_p);
1700 :
1701 :
1702 : // Set Regridding kernel
1703 0 : if (fftShiftEnabled_p)
1704 : {
1705 0 : regridCoreComplex_p = &MSTransformManager::interpol1Dfftshift;
1706 0 : regridCoreFloat_p = &MSTransformManager::interpol1Dfftshift;
1707 : }
1708 : else
1709 : {
1710 0 : regridCoreComplex_p = &MSTransformManager::interpol1D;
1711 0 : regridCoreFloat_p = &MSTransformManager::interpol1D;
1712 : }
1713 :
1714 : //// Determine the frequency transformation methods to use ////
1715 :
1716 : // Drop channels with non-uniform width when doing only channel average
1717 0 : if (channelAverage_p and !regridding_p and !combinespws_p )
1718 : {
1719 0 : dropNonUniformWidthChannels();
1720 : }
1721 :
1722 : // Get number of output channels (needed by chan avg and separate SPWs when there is only 1 selected SPW)
1723 0 : if (channelAverage_p or (nspws_p>1 and !combinespws_p))
1724 : {
1725 0 : getOutputNumberOfChannels();
1726 : }
1727 :
1728 : // Determine weight and sigma factors when either auto or user channel average is set
1729 0 : if (channelAverage_p or combinespws_p or regridding_p)
1730 : {
1731 0 : calculateNewWeightAndSigmaFactors();
1732 : }
1733 :
1734 :
1735 0 : if (nspws_p > 1)
1736 : {
1737 0 : uInt totalNumberOfOutputChannels = 0;
1738 0 : if (combinespws_p)
1739 : {
1740 0 : totalNumberOfOutputChannels = inputOutputSpwMap_p[0].second.NUM_CHAN;
1741 : }
1742 : // jagonzal: This is the case when there is only one input SPW and there is no need to combine
1743 : else
1744 : {
1745 0 : uInt spwId = 0;
1746 0 : if (outputInputSPWIndexMap_p.size()>0)
1747 : {
1748 0 : spwId = outputInputSPWIndexMap_p[0];
1749 : }
1750 : else
1751 : {
1752 0 : spwId = 0;
1753 : }
1754 :
1755 0 : totalNumberOfOutputChannels = numOfOutChanMap_p[spwId];
1756 : }
1757 :
1758 :
1759 0 : chansPerOutputSpw_p = totalNumberOfOutputChannels / nspws_p;
1760 0 : if (totalNumberOfOutputChannels % nspws_p)
1761 : {
1762 0 : chansPerOutputSpw_p += 1;
1763 0 : tailOfChansforLastSpw_p = totalNumberOfOutputChannels - chansPerOutputSpw_p*(nspws_p-1);
1764 : }
1765 : else
1766 : {
1767 0 : tailOfChansforLastSpw_p = chansPerOutputSpw_p;
1768 : }
1769 :
1770 0 : if (bufferMode_p)
1771 : {
1772 0 : writeOutputPlanesComplex_p = &MSTransformManager::bufferOutputPlanesInSlices;
1773 0 : writeOutputPlanesFloat_p = &MSTransformManager::bufferOutputPlanesInSlices;
1774 : }
1775 : else
1776 : {
1777 0 : writeOutputPlanesComplex_p = &MSTransformManager::writeOutputPlanesInSlices;
1778 0 : writeOutputPlanesFloat_p = &MSTransformManager::writeOutputPlanesInSlices;
1779 : }
1780 :
1781 0 : separateSpwSubtable();
1782 0 : separateFeedSubtable();
1783 0 : separateSourceSubtable();
1784 0 : separateSyscalSubtable();
1785 0 : separateFreqOffsetSubtable();
1786 0 : separateCalDeviceSubtable();
1787 0 : separateSysPowerSubtable();
1788 :
1789 : // CAS-5404. DDI sub-table has to be re-indexed after separating SPW sub-table
1790 0 : if (not combinespws_p) reindexDDISubTable();
1791 : }
1792 : else
1793 : {
1794 0 : if (bufferMode_p)
1795 : {
1796 0 : writeOutputPlanesComplex_p = &MSTransformManager::bufferOutputPlanes;
1797 0 : writeOutputPlanesFloat_p = &MSTransformManager::bufferOutputPlanes;
1798 : }
1799 : else
1800 : {
1801 0 : writeOutputPlanesComplex_p = &MSTransformManager::writeOutputPlanesInBlock;
1802 0 : writeOutputPlanesFloat_p = &MSTransformManager::writeOutputPlanesInBlock;
1803 : }
1804 : }
1805 :
1806 : // Generate Iterator
1807 0 : setIterationApproach();
1808 0 : generateIterator();
1809 :
1810 0 : return;
1811 : }
1812 :
1813 :
1814 : // -----------------------------------------------------------------------
1815 : //
1816 : // -----------------------------------------------------------------------
1817 0 : IPosition MSTransformManager::getShape()
1818 : {
1819 0 : return getTransformedShape(visibilityIterator_p->getVisBuffer());
1820 : }
1821 :
1822 : // -----------------------------------------------------------------------
1823 : //
1824 : // -----------------------------------------------------------------------
1825 0 : IPosition MSTransformManager::getTransformedShape(vi::VisBuffer2 *visBuffer)
1826 : {
1827 0 : IPosition outputCubeShape(3);
1828 :
1829 : // Correlations
1830 0 : outputCubeShape(0) = visBuffer->nCorrelations();
1831 :
1832 : // Rows
1833 0 : outputCubeShape(2) = nRowsToAdd_p;
1834 :
1835 : // Channels
1836 0 : if (nspws_p > 1)
1837 : {
1838 0 : outputCubeShape(1) = chansPerOutputSpw_p;
1839 : }
1840 0 : else if (combinespws_p)
1841 : {
1842 0 : outputCubeShape(1) = inputOutputSpwMap_p[0].second.NUM_CHAN;
1843 : }
1844 0 : else if (regridding_p)
1845 : {
1846 0 : Int inputSpw = visBuffer->spectralWindows()(0);
1847 0 : outputCubeShape(1) = inputOutputSpwMap_p[inputSpw].second.NUM_CHAN;
1848 : }
1849 0 : else if (channelAverage_p)
1850 : {
1851 0 : Int inputSpw = visBuffer->spectralWindows()(0);
1852 0 : outputCubeShape(1) = numOfOutChanMap_p[inputSpw];
1853 : }
1854 : else
1855 : {
1856 0 : outputCubeShape(1) = visBuffer->nChannels();
1857 : }
1858 :
1859 0 : return outputCubeShape;
1860 : }
1861 :
1862 : // -----------------------------------------------------------------------
1863 : //
1864 : // -----------------------------------------------------------------------
1865 0 : void MSTransformManager::propagateWeights(bool on)
1866 : {
1867 :
1868 0 : if (on)
1869 : {
1870 : // Used by SPW combination
1871 0 : fillWeightsPlane_p = &MSTransformManager::fillWeightsPlane;
1872 0 : normalizeWeightsPlane_p = &MSTransformManager::normalizeWeightsPlane;
1873 :
1874 : // Used by channel average
1875 0 : setWeightsPlaneByReference_p = &MSTransformManager::setWeightsPlaneByReference;
1876 0 : setWeightStripeByReference_p = &MSTransformManager::setWeightStripeByReference;
1877 : }
1878 : else
1879 : {
1880 : // Used by SPW combination
1881 0 : fillWeightsPlane_p = &MSTransformManager::dontfillWeightsPlane;
1882 0 : normalizeWeightsPlane_p = &MSTransformManager::dontNormalizeWeightsPlane;
1883 :
1884 : // Used by channel average
1885 0 : setWeightsPlaneByReference_p = &MSTransformManager::dontsetWeightsPlaneByReference;
1886 0 : setWeightStripeByReference_p = &MSTransformManager::dontSetWeightStripeByReference;
1887 : }
1888 :
1889 0 : return;
1890 : }
1891 :
1892 : // -----------------------------------------------------------------------
1893 : //
1894 : // -----------------------------------------------------------------------
1895 0 : void MSTransformManager::setBufferMode(bool on)
1896 : {
1897 0 : bufferMode_p = on;
1898 :
1899 0 : if (nspws_p > 1)
1900 : {
1901 0 : if (bufferMode_p)
1902 : {
1903 0 : writeOutputPlanesComplex_p = &MSTransformManager::bufferOutputPlanesInSlices;
1904 0 : writeOutputPlanesFloat_p = &MSTransformManager::bufferOutputPlanesInSlices;
1905 : }
1906 : else
1907 : {
1908 0 : writeOutputPlanesComplex_p = &MSTransformManager::writeOutputPlanesInSlices;
1909 0 : writeOutputPlanesFloat_p = &MSTransformManager::writeOutputPlanesInSlices;
1910 : }
1911 : }
1912 : else
1913 : {
1914 0 : if (bufferMode_p)
1915 : {
1916 0 : writeOutputPlanesComplex_p = &MSTransformManager::bufferOutputPlanes;
1917 0 : writeOutputPlanesFloat_p = &MSTransformManager::bufferOutputPlanes;
1918 : }
1919 : else
1920 : {
1921 0 : writeOutputPlanesComplex_p = &MSTransformManager::writeOutputPlanesInBlock;
1922 0 : writeOutputPlanesFloat_p = &MSTransformManager::writeOutputPlanesInBlock;
1923 : }
1924 : }
1925 :
1926 0 : return;
1927 : }
1928 :
1929 : // -----------------------------------------------------------------------
1930 : //
1931 : // -----------------------------------------------------------------------
1932 0 : void MSTransformManager::setChannelAverageKernel(uInt mode)
1933 : {
1934 0 : switch (mode)
1935 : {
1936 0 : case MSTransformations::spectrum:
1937 : {
1938 0 : averageKernelComplex_p = &MSTransformManager::weightAverageKernel;
1939 0 : averageKernelFloat_p = &MSTransformManager::weightAverageKernel;
1940 0 : break;
1941 : }
1942 0 : case MSTransformations::flags:
1943 : {
1944 0 : averageKernelComplex_p = &MSTransformManager::flagAverageKernel;
1945 0 : averageKernelFloat_p = &MSTransformManager::flagAverageKernel;
1946 0 : break;
1947 : }
1948 0 : case MSTransformations::cumSum:
1949 : {
1950 0 : averageKernelComplex_p = &MSTransformManager::cumSumKernel;
1951 0 : averageKernelFloat_p = &MSTransformManager::cumSumKernel;
1952 0 : break;
1953 : }
1954 0 : case MSTransformations::flagSpectrum:
1955 : {
1956 0 : averageKernelComplex_p = &MSTransformManager::flagWeightAverageKernel;
1957 0 : averageKernelFloat_p = &MSTransformManager::flagWeightAverageKernel;
1958 0 : break;
1959 : }
1960 0 : case MSTransformations::flagCumSum:
1961 : {
1962 0 : averageKernelComplex_p = &MSTransformManager::flagCumSumKernel;
1963 0 : averageKernelFloat_p = &MSTransformManager::flagCumSumKernel;
1964 0 : break;
1965 : }
1966 0 : case MSTransformations::flagsNonZero:
1967 : {
1968 0 : averageKernelComplex_p = &MSTransformManager::flagNonZeroAverageKernel;
1969 0 : averageKernelFloat_p = &MSTransformManager::flagNonZeroAverageKernel;
1970 0 : break;
1971 : }
1972 0 : case MSTransformations::flagSpectrumNonZero:
1973 : {
1974 0 : averageKernelComplex_p = &MSTransformManager::flagWeightNonZeroAverageKernel;
1975 0 : averageKernelFloat_p = &MSTransformManager::flagWeightNonZeroAverageKernel;
1976 0 : break;
1977 : }
1978 0 : case MSTransformations::flagCumSumNonZero:
1979 : {
1980 0 : averageKernelComplex_p = &MSTransformManager::flagCumSumNonZeroKernel;
1981 0 : averageKernelFloat_p = &MSTransformManager::flagCumSumNonZeroKernel;
1982 0 : break;
1983 : }
1984 0 : default:
1985 : {
1986 0 : averageKernelComplex_p = &MSTransformManager::simpleAverageKernel;
1987 0 : averageKernelFloat_p = &MSTransformManager::simpleAverageKernel;
1988 0 : break;
1989 : }
1990 : }
1991 :
1992 0 : return;
1993 : }
1994 :
1995 : // -----------------------------------------------------------------------
1996 : //
1997 : // -----------------------------------------------------------------------
1998 0 : void MSTransformManager::setSmoothingKernel(uInt mode)
1999 : {
2000 0 : switch (mode)
2001 : {
2002 0 : case MSTransformations::plainSmooth:
2003 : {
2004 0 : smoothKernelComplex_p = &MSTransformManager::plainSmooth;
2005 0 : smoothKernelFloat_p = &MSTransformManager::plainSmooth;
2006 0 : break;
2007 : }
2008 0 : case MSTransformations::plainSmoothSpectrum:
2009 : {
2010 0 : smoothKernelComplex_p = &MSTransformManager::plainSmoothSpectrum;
2011 0 : smoothKernelFloat_p = &MSTransformManager::plainSmoothSpectrum;
2012 0 : break;
2013 : }
2014 0 : default:
2015 : {
2016 0 : smoothKernelComplex_p = &MSTransformManager::plainSmooth;
2017 0 : smoothKernelFloat_p = &MSTransformManager::plainSmooth;
2018 0 : break;
2019 : }
2020 : }
2021 :
2022 0 : return;
2023 : }
2024 :
2025 : // -----------------------------------------------------------------------
2026 : //
2027 : // -----------------------------------------------------------------------
2028 0 : void MSTransformManager::setSmoothingFourierKernel(uInt mode)
2029 : {
2030 0 : if (smoothFourier_p) {
2031 0 : switch (mode)
2032 : {
2033 0 : case MSTransformations::plainSmooth:
2034 : {
2035 : //logger_p << "Set smoothing kernel to smoothFourier" << LogIO::POST;
2036 0 : transformStripeOfDataComplex_p = &MSTransformManager::smoothFourierComplex;
2037 0 : transformStripeOfDataFloat_p = &MSTransformManager::smoothFourierFloat;
2038 0 : break;
2039 : }
2040 0 : case MSTransformations::plainSmoothSpectrum:
2041 : {
2042 : //logger_p << "Set smoothing kernel to smooth (for weight propagation)" << LogIO::POST;
2043 0 : transformStripeOfDataComplex_p = &MSTransformManager::smooth;
2044 0 : transformStripeOfDataFloat_p = &MSTransformManager::smooth;
2045 0 : break;
2046 : }
2047 0 : default:
2048 : {
2049 0 : transformStripeOfDataComplex_p = &MSTransformManager::smoothFourierComplex;
2050 0 : transformStripeOfDataFloat_p = &MSTransformManager::smoothFourierFloat;
2051 0 : break;
2052 : }
2053 : }
2054 : }
2055 :
2056 0 : return;
2057 : }
2058 :
2059 : // -----------------------------------------------------------------------
2060 : //
2061 : // -----------------------------------------------------------------------
2062 0 : void MSTransformManager::initDataSelectionParams()
2063 : {
2064 0 : MSSelection mssel;
2065 :
2066 0 : if (reindex_p)
2067 : {
2068 0 : if (!observationSelection_p.empty())
2069 : {
2070 0 : mssel.setObservationExpr(observationSelection_p);
2071 0 : Vector<Int> observationList = mssel.getObservationList(inputMs_p);
2072 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2073 0 : << "Selected Observations Ids are " << observationList << LogIO::POST;
2074 :
2075 0 : for (uInt index=0; index < observationList.size(); index++)
2076 : {
2077 0 : inputOutputObservationIndexMap_p[observationList(index)] = index;
2078 : }
2079 : }
2080 :
2081 0 : if (!arraySelection_p.empty())
2082 : {
2083 0 : mssel.setArrayExpr(arraySelection_p);
2084 0 : Vector<Int> arrayList = mssel.getSubArrayList(inputMs_p);
2085 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2086 0 : << "Selected Arrays Ids are " << arrayList << LogIO::POST;
2087 :
2088 0 : for (uInt index=0; index < arrayList.size(); index++)
2089 : {
2090 0 : inputOutputArrayIndexMap_p[arrayList(index)] = index;
2091 : }
2092 : }
2093 :
2094 0 : if (!scanSelection_p.empty())
2095 : {
2096 0 : mssel.setScanExpr(scanSelection_p);
2097 0 : Vector<Int> scanList = mssel.getScanList(inputMs_p);
2098 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2099 0 : << "Selected Scans Ids are " << scanList << LogIO::POST;
2100 :
2101 0 : for (uInt index=0; index < scanList.size(); index++)
2102 : {
2103 0 : inputOutputScanIndexMap_p[scanList(index)] = index;
2104 : }
2105 : }
2106 :
2107 0 : if (!scanIntentSelection_p.empty())
2108 : {
2109 0 : mssel.setStateExpr(scanIntentSelection_p);
2110 0 : Vector<Int> scanIntentList = mssel.getStateObsModeList(inputMs_p);
2111 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2112 0 : << "Selected Scans Intents Ids are " << scanIntentList << LogIO::POST;
2113 :
2114 0 : for (uInt index=0; index < scanIntentList.size(); index++)
2115 : {
2116 0 : inputOutputScanIntentIndexMap_p[scanIntentList(index)] = index;
2117 : }
2118 : }
2119 :
2120 0 : if (!fieldSelection_p.empty())
2121 : {
2122 0 : mssel.setFieldExpr(fieldSelection_p);
2123 0 : Vector<Int> fieldList = mssel.getFieldList(inputMs_p);
2124 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2125 0 : << "Selected Fields Ids are " << fieldList << LogIO::POST;
2126 :
2127 0 : for (uInt index=0; index < fieldList.size(); index++)
2128 : {
2129 0 : inputOutputFieldIndexMap_p[fieldList(index)] = index;
2130 : }
2131 : }
2132 : }
2133 :
2134 :
2135 0 : if (!spwSelection_p.empty())
2136 : {
2137 0 : mssel.setSpwExpr(spwSelection_p);
2138 0 : Matrix<Int> spwchan = mssel.getChanList(inputMs_p);
2139 :
2140 : // Get the DD IDs of this spw selection
2141 0 : Vector<Int> spwddi = mssel.getSPWDDIDList(inputMs_p);
2142 :
2143 : // Take into account the polarization selections
2144 0 : if (!polarizationSelection_p.empty()){
2145 0 : mssel.setPolnExpr(polarizationSelection_p.c_str());
2146 0 : Vector<Int> polddi = mssel.getDDIDList(inputMs_p);
2147 0 : if (polddi.size() > 0){
2148 : // make an intersection
2149 0 : Vector<Int> commonDDI = set_intersection(spwddi, polddi);
2150 0 : uInt nddids = commonDDI.size();
2151 0 : if (nddids > 0){
2152 0 : spwddi.resize(nddids);
2153 0 : for (uInt ii = 0; ii < nddids; ++ii){
2154 0 : spwddi[ii] = commonDDI[ii];
2155 : }
2156 : }
2157 : }
2158 : }
2159 :
2160 0 : uInt nddi = spwddi.size();
2161 : Int ddid;
2162 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2163 0 : << "Selected SPWs Ids are " << spwchan << LogIO::POST;
2164 : // Example of MS with repeated SPW ID in DD table:
2165 : // DD POL SPW
2166 : // 0 0 0 (RR)
2167 : // 1 1 0 (LL)
2168 : // 2 2 1 (RR,LL)
2169 : // 3 3 2 (RR,LL,RL,LR)
2170 : // example of selection: spw=0,1 correlation=RR, so selected DDs are
2171 : // DD POL SPW
2172 : // 0 0 0
2173 : // 2 2 1
2174 :
2175 : // Do the mapping of DD between input and output
2176 0 : if (reindex_p)
2177 : {
2178 0 : for(uInt selection_ii=0;selection_ii<nddi;selection_ii++)
2179 : {
2180 : // Get dd id and set the input-output dd map
2181 : // This will only be used to write the DD ids in the main table
2182 0 : ddid = spwddi[selection_ii];
2183 0 : inputOutputDDIndexMap_p[ddid] = selection_ii + ddiStart_p;
2184 : }
2185 : }
2186 :
2187 0 : IPosition shape = spwchan.shape();
2188 0 : uInt nSelections = shape[0];
2189 : Int spw,channelStart,channelStop,channelStep,channelWidth;
2190 0 : if (channelSelector_p == NULL) channelSelector_p = new vi::FrequencySelectionUsingChannels();
2191 :
2192 : // Do the spw mapping between input and output
2193 0 : uInt outputSpwIndex = 0;
2194 0 : for(uInt selection_i=0;selection_i<nSelections;selection_i++)
2195 : {
2196 : // Get spw id and set the input-output spw map
2197 0 : spw = spwchan(selection_i,0);
2198 :
2199 : // Set the channel selection ()
2200 0 : channelStart = spwchan(selection_i,1);
2201 0 : channelStop = spwchan(selection_i,2);
2202 0 : channelStep = spwchan(selection_i,3);
2203 : // number of channels to select, starting with first selected channel:
2204 0 : channelWidth = 1 + floor(float(channelStop - channelStart) / float(channelStep));
2205 0 : channelSelector_p->add (spw, channelStart, channelWidth, channelStep);
2206 :
2207 0 : if (numOfSelChanMap_p.find(spw) == numOfSelChanMap_p.end())
2208 : {
2209 0 : if (reindex_p)
2210 : {
2211 0 : inputOutputSPWIndexMap_p[spw] = outputSpwIndex + ddiStart_p;
2212 :
2213 0 : outputInputSPWIndexMap_p[outputSpwIndex] = spw;
2214 : }
2215 :
2216 0 : numOfSelChanMap_p[spw] = channelWidth;
2217 :
2218 0 : outputSpwIndex ++;
2219 :
2220 0 : inputOutputChanIndexMap_p[spw].clear(); // Accesing the vector creates it
2221 : }
2222 : else
2223 : {
2224 0 : numOfSelChanMap_p[spw] += channelWidth;
2225 : }
2226 :
2227 0 : for (Int inpChan=channelStart;inpChan<=channelStop;inpChan += channelStep)
2228 : {
2229 0 : inputOutputChanIndexMap_p[spw].push_back(inpChan);
2230 : }
2231 : }
2232 : }
2233 :
2234 : // jagonzal: must fill numOfSelChanMap_p
2235 : else
2236 : {
2237 0 : spwSelection_p = "*";
2238 0 : mssel.setSpwExpr(spwSelection_p);
2239 0 : Matrix<Int> spwchan = mssel.getChanList(inputMs_p);
2240 :
2241 0 : IPosition shape = spwchan.shape();
2242 0 : uInt nSelections = shape[0];
2243 : Int spw,channelStart,channelStop,channelWidth;
2244 0 : for(uInt selection_i=0;selection_i<nSelections;selection_i++)
2245 : {
2246 : // Get spw id and set the input-output spw map
2247 0 : spw = spwchan(selection_i,0);
2248 :
2249 : // Set the channel selection ()
2250 0 : channelStart = spwchan(selection_i,1);
2251 0 : channelStop = spwchan(selection_i,2);
2252 0 : channelWidth = channelStop-channelStart+1;
2253 0 : numOfSelChanMap_p[spw] = channelWidth;
2254 : }
2255 :
2256 : // CAS-8631: Even w/o spw selection MSTransformDataHandler sets spws selection to *
2257 : // in order to obtain the SPW-DDI list. It turns out that sometimes the
2258 : // output DDI sub-table is resorted, for instance in case of non-monotonic
2259 : // DDI-SPW relation, therefore it is necessary to map input-output DDIS
2260 0 : if (reindex_p)
2261 : {
2262 0 : Vector<Int> spwddi = mssel.getSPWDDIDList(inputMs_p);
2263 :
2264 : Int ddid;
2265 0 : uInt nddi = spwddi.size();
2266 0 : for(uInt selection_ii=0;selection_ii<nddi;selection_ii++)
2267 : {
2268 : // Get dd id and set the input-output dd map
2269 : // This will only be used to write the DD ids in the main table
2270 0 : ddid = spwddi[selection_ii];
2271 0 : inputOutputDDIndexMap_p[ddid] = selection_ii + ddiStart_p;
2272 : }
2273 : }
2274 :
2275 0 : spwSelection_p = "";
2276 : }
2277 :
2278 : // If we have channel average we have to populate the freqbin map
2279 0 : if (channelAverage_p)
2280 : {
2281 0 : if (!spwSelection_p.empty())
2282 : {
2283 0 : mssel.setSpwExpr(spwSelection_p);
2284 : }
2285 : else
2286 : {
2287 0 : mssel.setSpwExpr("*");
2288 : }
2289 :
2290 : //Vector<Int> spwList = mssel.getSpwList(inputMs_p);
2291 0 : Matrix<Int> spwchan = mssel.getChanList(inputMs_p);
2292 :
2293 : // jagonzal (CAS-7149): Have to remove duplicates: With multiple pols per SPW
2294 : // each SPWId appears various (see times test_chanavg_spw_with_diff_pol_shape)
2295 0 : vector<Int> noDupSpwList;
2296 0 : for (size_t idx=0;idx < spwchan.nrow(); idx++)
2297 : {
2298 0 : if (find(noDupSpwList.begin(),noDupSpwList.end(),spwchan(idx,0)) == noDupSpwList.end())
2299 : {
2300 0 : noDupSpwList.push_back(spwchan(idx,0));
2301 : }
2302 : }
2303 :
2304 : //spwList.resize(noDupSpwList.size());
2305 : //for (uInt idx=0;idx < noDupSpwList.size(); idx++) spwList(idx) = noDupSpwList[idx];
2306 0 : Vector<Int> spwList(noDupSpwList);
2307 :
2308 0 : if (freqbin_p.size() == 1)
2309 : {
2310 0 : if(combinespws_p)
2311 : {
2312 0 : uInt spwAfterComb = 0;
2313 0 : freqbinMap_p[spwAfterComb] = freqbin_p(spwAfterComb);
2314 : }
2315 : else
2316 : {
2317 : // jagonzal (CAS-8018): Update chanbin, otherwise there is a problem with dropped channels
2318 0 : Int freqbin = freqbin_p(0);
2319 0 : freqbin_p.resize(spwList.size(),True);
2320 0 : freqbin_p = freqbin;
2321 :
2322 0 : for (size_t spw_i=0;spw_i<spwList.size();spw_i++)
2323 : {
2324 0 : freqbinMap_p[spwList(spw_i)] = freqbin_p(spw_i);
2325 :
2326 : // jagonzal (new WEIGHT/SIGMA convention)
2327 : // jagonzal (CAS-7149): Cut chanbin to not exceed n# selected channels
2328 0 : if (freqbin_p(spw_i) > (Int)numOfSelChanMap_p[spwList(spw_i)])
2329 : {
2330 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
2331 0 : << "Number of selected channels " << numOfSelChanMap_p[spwList(spw_i)]
2332 0 : << " for SPW " << spwList(spw_i)
2333 0 : << " is smaller than specified chanbin " << freqbin_p(spw_i) << endl
2334 0 : << "Setting chanbin to " << numOfSelChanMap_p[spwList(spw_i)]
2335 0 : << " for SPW " << spwList(spw_i)
2336 0 : << LogIO::POST;
2337 0 : freqbinMap_p[spwList(spw_i)] = numOfSelChanMap_p[spwList(spw_i)];
2338 0 : newWeightFactorMap_p[spwList(spw_i)] = numOfSelChanMap_p[spwList(spw_i)];
2339 : // jagonzal (CAS-8018): Update chanbin, otherwise there is a problem with dropped channels
2340 0 : freqbin_p(spw_i) = numOfSelChanMap_p[spwList(spw_i)];
2341 : }
2342 : else
2343 : {
2344 0 : newWeightFactorMap_p[spwList(spw_i)] = freqbin_p(spw_i);
2345 : }
2346 : }
2347 : }
2348 : }
2349 : else
2350 : {
2351 0 : if (spwList.size() != freqbin_p.size())
2352 : {
2353 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
2354 : << "Number of frequency bins ( "
2355 : << freqbin_p.size() << " ) different from number of selected spws ( "
2356 0 : << spwList.size() << " )" << LogIO::POST;
2357 : }
2358 : else
2359 : {
2360 0 : for (size_t spw_i=0;spw_i<spwList.size();spw_i++)
2361 : {
2362 0 : freqbinMap_p[spwList(spw_i)] = freqbin_p(spw_i);
2363 : // jagonzal (new WEIGHT/SIGMA convention)
2364 : // jagonzal (CAS-7149): Cut chanbin to not exceed n# selected channels
2365 0 : if (freqbin_p(spw_i) > (Int)numOfSelChanMap_p[spwList(spw_i)])
2366 : {
2367 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
2368 0 : << "Number of selected channels " << numOfSelChanMap_p[spwList(spw_i)]
2369 0 : << " for SPW " << spwList(spw_i)
2370 0 : << " is smaller than specified chanbin " << freqbin_p(spw_i) << endl
2371 0 : << "Setting chanbin to " << numOfSelChanMap_p[spwList(spw_i)]
2372 0 : << " for SPW " << spwList(spw_i)
2373 0 : << LogIO::POST;
2374 0 : freqbinMap_p[spwList(spw_i)] = numOfSelChanMap_p[spwList(spw_i)];
2375 0 : newWeightFactorMap_p[spwList(spw_i)] = numOfSelChanMap_p[spwList(spw_i)];
2376 : // jagonzal (CAS-8018): Update chanbin, otherwise there is a problem with dropped channels
2377 0 : freqbin_p(spw_i) = numOfSelChanMap_p[spwList(spw_i)];
2378 : }
2379 : else
2380 : {
2381 0 : newWeightFactorMap_p[spwList(spw_i)] = freqbin_p(spw_i);
2382 : }
2383 : }
2384 : }
2385 : }
2386 : }
2387 :
2388 0 : if (!polarizationSelection_p.empty())
2389 : {
2390 0 : mssel.setPolnExpr(polarizationSelection_p.c_str());
2391 0 : Vector <Vector <Slice> > correlationSlices;
2392 0 : mssel.getCorrSlices(correlationSlices,inputMs_p);
2393 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2394 0 : << "Selected correlations are " << correlationSlices << LogIO::POST;
2395 :
2396 0 : if (channelSelector_p == NULL) channelSelector_p = new vi::FrequencySelectionUsingChannels();
2397 :
2398 0 : channelSelector_p->addCorrelationSlices(correlationSlices);
2399 :
2400 : // Get the DDs related to the polarization selection
2401 : // when there is no spw selection
2402 0 : if (spwSelection_p.empty() and reindex_p)
2403 : {
2404 0 : std::vector<Int> polddids = mssel.getDDIDList(inputMs_p).tovector();
2405 : // The output from MSSelection might not be sorted
2406 0 : std::sort(polddids.begin(), polddids.end());
2407 :
2408 : // Make the in/out DD mapping
2409 0 : size_t nddids = polddids.size();
2410 : Int dd;
2411 0 : for(size_t ii=0;ii<nddids;ii++)
2412 : {
2413 : // Get dd id and set the input-output dd map
2414 0 : dd = polddids[ii];
2415 0 : inputOutputDDIndexMap_p[dd] = ii + ddiStart_p;
2416 : }
2417 :
2418 : }
2419 :
2420 : }
2421 :
2422 0 : return;
2423 : }
2424 :
2425 : // -----------------------------------------------------------------------
2426 : // Method to initialize the reference frame transformation parameters
2427 : // -----------------------------------------------------------------------
2428 0 : void MSTransformManager::initRefFrameTransParams()
2429 : {
2430 0 : inputReferenceFrame_p = determineInputRefFrame();
2431 :
2432 : // Parse output reference frame
2433 0 : refFrameTransformation_p = true;
2434 0 : radialVelocityCorrection_p = false;
2435 0 : if(outputReferenceFramePar_p.empty()) {
2436 0 : outputReferenceFrame_p = inputReferenceFrame_p;
2437 : }
2438 : // CAS-6778: Support for new ref. frame SOURCE that requires radial velocity correction
2439 0 : else if (outputReferenceFramePar_p == "SOURCE") {
2440 0 : outputReferenceFrame_p = MFrequency::GEO;
2441 0 : radialVelocityCorrection_p = true;
2442 0 : } else if(!MFrequency::getType(outputReferenceFrame_p, outputReferenceFramePar_p)) {
2443 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
2444 0 : << "Problem parsing output reference frame:" << outputReferenceFramePar_p
2445 0 : << LogIO::EXCEPTION;
2446 : }
2447 :
2448 0 : if (outputReferenceFrame_p == inputReferenceFrame_p) {
2449 0 : refFrameTransformation_p = false;
2450 : }
2451 :
2452 : // Determine observatory position from the first row in the observation sub-table of the output (selected) MS
2453 0 : MSObservation observationTable;
2454 0 : if (userBufferMode_p) {
2455 0 : observationTable = selectedInputMs_p->observation();
2456 : } else {
2457 0 : observationTable = outputMs_p->observation();
2458 : }
2459 0 : MSObservationColumns observationCols(observationTable);
2460 0 : String observatoryName = observationCols.telescopeName()(0);
2461 0 : MeasTable::Observatory(observatoryPosition_p,observatoryName);
2462 :
2463 : // jagonzal: This conversion is needed only for cosmetic reasons
2464 : // observatoryPosition_p=MPosition::Convert(observatoryPosition_p, MPosition::ITRF)();
2465 :
2466 : // Determine observation time from the first row in the selected MS
2467 0 : referenceTime_p = selectedInputMsCols_p->timeMeas()(0);
2468 :
2469 : // Access FIELD cols to get phase center and radial velocity
2470 0 : inputMSFieldCols_p = std::make_shared<MSFieldColumns>(selectedInputMs_p->field());
2471 :
2472 0 : phaseCenter_p = determinePhaseCenter();
2473 0 : }
2474 :
2475 : /**
2476 : * Determine input reference frame from the first row in the SPW 8
2477 : * sub-table of the output/selected MS.
2478 : * Helper for the initialization of the reference frame transformations
2479 : *
2480 : * @return Reference frame of output/selected MS.
2481 : */
2482 0 : casacore::MFrequency::Types MSTransformManager::determineInputRefFrame() {
2483 0 : MSSpectralWindow spwTable;
2484 0 : if (userBufferMode_p) {
2485 0 : spwTable = selectedInputMs_p->spectralWindow();
2486 : } else {
2487 0 : spwTable = outputMs_p->spectralWindow();
2488 : }
2489 0 : MSSpWindowColumns spwCols(spwTable);
2490 :
2491 : casacore::MFrequency::Types result;
2492 0 : if (reindex_p) {
2493 0 : result = MFrequency::castType(spwCols.measFreqRef()(0));
2494 : } else {
2495 0 : Int firstSelectedDDI = selectedInputMsCols_p->dataDescId()(0);
2496 0 : MSDataDescription ddiTable = outputMs_p->dataDescription();
2497 0 : MSDataDescColumns ddiCols(ddiTable);
2498 0 : Int firstSelectedSPW = ddiCols.spectralWindowId()(firstSelectedDDI);
2499 0 : result = MFrequency::castType(spwCols.measFreqRef()(firstSelectedSPW));
2500 : }
2501 :
2502 0 : return result;
2503 : }
2504 :
2505 : /**
2506 : * Determine phase center from output/selected MS.
2507 : * Helper for the initialization of the reference frame transformations
2508 : *
2509 : * @return phase center from output/selected MS.
2510 : */
2511 0 : casacore::MDirection MSTransformManager::determinePhaseCenter() {
2512 0 : casacore::MDirection result;
2513 :
2514 : // Determine phase center
2515 0 : if (phaseCenterPar_p->type() == casac::variant::INT) {
2516 0 : Int fieldIdForPhaseCenter = phaseCenterPar_p->toInt();
2517 :
2518 0 : if (fieldIdForPhaseCenter >= (Int)inputMSFieldCols_p->nrow() ||
2519 : fieldIdForPhaseCenter < 0) {
2520 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
2521 : << "Selected FIELD_ID to determine phase center does not exist "
2522 0 : << LogIO::POST;
2523 : } else {
2524 : // CAS-6778: Support for new ref. frame SOURCE that requires radial velocity correction
2525 0 : if (radialVelocityCorrection_p) {
2526 0 : radialVelocity_p = inputMSFieldCols_p->radVelMeas(fieldIdForPhaseCenter,
2527 0 : referenceTime_p.get("s").getValue());
2528 0 : result = inputMSFieldCols_p->phaseDirMeas(fieldIdForPhaseCenter,
2529 0 : referenceTime_p.get("s").getValue());
2530 : } else {
2531 0 : result = inputMSFieldCols_p->phaseDirMeasCol()(fieldIdForPhaseCenter)(IPosition(1,0));
2532 : }
2533 : }
2534 : } else {
2535 0 : String phaseCenter = phaseCenterPar_p->toString(true);
2536 :
2537 : // Determine phase center from the first row in the FIELD sub-table of the output
2538 : // (selected) MS
2539 0 : if (phaseCenter.empty()) {
2540 0 : std::shared_ptr<MSFieldColumns> fieldCols;
2541 0 : if (userBufferMode_p) {
2542 0 : fieldCols = inputMSFieldCols_p;
2543 : } else {
2544 0 : MSField fieldTable = outputMs_p->field();
2545 0 : fieldCols = std::make_shared<MSFieldColumns>(fieldTable);
2546 : }
2547 :
2548 : // CAS-8870: Mstransform with outframe=’SOURCE’ crashes because of ephemeris type
2549 0 : Int firstSelectedField = selectedInputMsCols_p->fieldId()(0);
2550 0 : if (inputOutputFieldIndexMap_p.find(firstSelectedField) !=
2551 0 : inputOutputFieldIndexMap_p.end()) {
2552 0 : firstSelectedField = inputOutputFieldIndexMap_p[firstSelectedField];
2553 : }
2554 :
2555 : // CAS-6778: Support for new ref. frame SOURCE that requires radial velocity correction
2556 0 : if (radialVelocityCorrection_p) {
2557 0 : radialVelocity_p = fieldCols->radVelMeas(firstSelectedField, referenceTime_p.get("s").getValue());
2558 :
2559 0 : if (radialVelocity_p.getRef().getType() != MRadialVelocity::GEO) {
2560 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
2561 : << "Cannot perform radial velocity correction with ephemerides attached "
2562 : << "to first selected field " << firstSelectedField << " of type "
2563 0 : << MRadialVelocity::showType(radialVelocity_p.getRef().getType())
2564 : << ".\nType needs to be GEO."
2565 0 : << LogIO::EXCEPTION;
2566 : }
2567 :
2568 0 : result = fieldCols->phaseDirMeas(firstSelectedField,referenceTime_p.get("s").getValue());
2569 : } else {
2570 0 : result = fieldCols->phaseDirMeasCol()(firstSelectedField)(IPosition(1,0));
2571 : }
2572 : } else {
2573 : // Parse phase center
2574 0 : if(!casaMDirection(phaseCenter, result)) {
2575 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
2576 0 : << "Cannot interpret phase center " << phaseCenter << LogIO::POST;
2577 : }
2578 : }
2579 : }
2580 :
2581 0 : return result;
2582 : }
2583 :
2584 : // -----------------------------------------------------------------------
2585 : // Method to re-grid each SPW separately in the SPW sub-table
2586 : // It also sets the input/output frequency arrays to be used by the interpolations
2587 : // -----------------------------------------------------------------------
2588 0 : void MSTransformManager::regridSpwSubTable()
2589 : {
2590 : // Access Spectral Window sub-table
2591 0 : MSSpectralWindow spwTable = outputMs_p->spectralWindow();
2592 0 : auto nInputSpws = spwTable.nrow();
2593 0 : MSSpWindowColumns spwCols(spwTable);
2594 :
2595 : // Access columns which have to be modified
2596 0 : ArrayColumn<Double> chanFreqCol = spwCols.chanFreq();
2597 0 : ArrayColumn<Double> chanWidthCol = spwCols.chanWidth();
2598 0 : ArrayColumn<Double> effectiveBWCol = spwCols.effectiveBW();
2599 0 : ArrayColumn<Double> resolutionCol = spwCols.resolution();
2600 0 : ScalarColumn<Int> numChanCol = spwCols.numChan();
2601 0 : ScalarColumn<Double> refFrequencyCol = spwCols.refFrequency();
2602 0 : ScalarColumn<Double> totalBandwidthCol = spwCols.totalBandwidth();
2603 0 : ScalarColumn<Int> measFreqRefCol = spwCols.measFreqRef();
2604 :
2605 : Int spwId;
2606 0 : for(rownr_t spw_idx=0; spw_idx<nInputSpws; ++spw_idx) {
2607 0 : if (outputInputSPWIndexMap_p.size() > 0) {
2608 0 : spwId = outputInputSPWIndexMap_p[spw_idx];
2609 : } else {
2610 0 : spwId = spw_idx;
2611 : }
2612 :
2613 : // jagonzal: Skip this SPW in non-reindex mode
2614 0 : if ((!reindex_p) and (numOfSelChanMap_p.find(spwId) == numOfSelChanMap_p.end()))
2615 0 : continue;
2616 :
2617 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2618 0 : << "Regridding SPW with Id " << spwId << LogIO::POST;
2619 :
2620 : // Get input frequencies and widths
2621 0 : Vector<Double> originalChanFreq(chanFreqCol(spw_idx));
2622 0 : Vector<Double> originalChanWidth(chanWidthCol(spw_idx));
2623 :
2624 : // Calculate output SPW
2625 0 : Vector<Double> regriddedCHAN_FREQ;
2626 0 : Vector<Double> regriddedCHAN_WIDTH;
2627 0 : Vector<Double> inputCHAN_FREQ;
2628 0 : Vector<Double> inputCHAN_WIDTH;
2629 0 : regridSpwAux(spwId, MFrequency::castType(spwCols.measFreqRef()(spw_idx)),
2630 : originalChanFreq, originalChanWidth,
2631 : inputCHAN_FREQ, inputCHAN_WIDTH,
2632 0 : regriddedCHAN_FREQ, regriddedCHAN_WIDTH, string("Input"));
2633 0 : spwInfo inputSpw(inputCHAN_FREQ, inputCHAN_WIDTH);
2634 0 : spwInfo outputSpw(regriddedCHAN_FREQ, regriddedCHAN_WIDTH);
2635 :
2636 : // Set the output SPW characteristics in the SPW sub-table
2637 0 : numChanCol.put(spw_idx, outputSpw.NUM_CHAN);
2638 0 : chanFreqCol.put(spw_idx, outputSpw.CHAN_FREQ);
2639 0 : chanWidthCol.put(spw_idx, outputSpw.CHAN_WIDTH);
2640 0 : effectiveBWCol.put(spw_idx, outputSpw.EFFECTIVE_BW);
2641 0 : resolutionCol.put(spw_idx, outputSpw.RESOLUTION);
2642 0 : refFrequencyCol.put(spw_idx, outputSpw.REF_FREQUENCY);
2643 0 : totalBandwidthCol.put(spw_idx, outputSpw.TOTAL_BANDWIDTH);
2644 :
2645 : // CAS-6778: Support for new ref. frame SOURCE that requires radial velocity correction
2646 0 : if(outputReferenceFrame_p==MFrequency::GEO) {
2647 : // i.e. outframe was GEO or SOURCE
2648 0 : measFreqRefCol.put(spw_idx, (Int)MFrequency::REST);
2649 : } else {
2650 0 : measFreqRefCol.put(spw_idx, (Int)outputReferenceFrame_p);
2651 : }
2652 :
2653 : // Add input-output SPW pair to map
2654 0 : inputOutputSpwMap_p[spwId] = std::make_pair(inputSpw,outputSpw);
2655 :
2656 : // Prepare frequency transformation engine for the reference time
2657 0 : if (fftShiftEnabled_p) {
2658 0 : MFrequency::Ref inputFrameRef(inputReferenceFrame_p,
2659 0 : MeasFrame(phaseCenter_p, observatoryPosition_p, referenceTime_p));
2660 0 : MFrequency::Ref outputFrameRef(outputReferenceFrame_p,
2661 0 : MeasFrame(phaseCenter_p, observatoryPosition_p, referenceTime_p));
2662 0 : refTimeFreqTransEngine_p = MFrequency::Convert(MSTransformations::Hz, inputFrameRef, outputFrameRef);
2663 :
2664 0 : for(uInt chan_idx=0; chan_idx < inputOutputSpwMap_p[spwId].first.CHAN_FREQ.size();
2665 : ++chan_idx) {
2666 0 : inputOutputSpwMap_p[spwId].first.CHAN_FREQ_aux[chan_idx] =
2667 0 : refTimeFreqTransEngine_p(inputOutputSpwMap_p[spwId].first.CHAN_FREQ[chan_idx]).
2668 0 : get(MSTransformations::Hz).getValue();
2669 : }
2670 : }
2671 : }
2672 0 : }
2673 :
2674 : // -----------------------------------------------------------------------
2675 : // Method to combine and re-grid the SPW sub-table
2676 : // It also sets the input/output frequency arrays to be used by the interpolations
2677 : // -----------------------------------------------------------------------
2678 0 : void MSTransformManager::regridAndCombineSpwSubtable()
2679 : {
2680 : /// Determine input SPW structure ////////////////////
2681 :
2682 : // Access Spectral Window sub-table
2683 0 : MSSpectralWindow spwTable = outputMs_p->spectralWindow();
2684 0 : auto nInputSpws = spwTable.nrow();
2685 0 : MSSpWindowColumns spwCols(spwTable);
2686 :
2687 : // Access columns which have to be modified
2688 0 : ArrayColumn<Double> chanFreqCol = spwCols.chanFreq();
2689 0 : ArrayColumn<Double> chanWidthCol = spwCols.chanWidth();
2690 0 : ArrayColumn<Double> effectiveBWCol = spwCols.effectiveBW();
2691 0 : ArrayColumn<Double> resolutionCol = spwCols.resolution();
2692 0 : ScalarColumn<Int> numChanCol = spwCols.numChan();
2693 0 : ScalarColumn<Double> refFrequencyCol = spwCols.refFrequency();
2694 0 : ScalarColumn<Double> totalBandwidthCol = spwCols.totalBandwidth();
2695 0 : ScalarColumn<Int> measFreqRefCol = spwCols.measFreqRef();
2696 :
2697 : // Create list of input channels
2698 0 : vector<channelInfo> inputChannels;
2699 0 : for(rownr_t spw_idx=0; spw_idx<nInputSpws; spw_idx++)
2700 : {
2701 : Int spwId;
2702 0 : if (outputInputSPWIndexMap_p.size())
2703 : {
2704 0 : spwId = outputInputSPWIndexMap_p[spw_idx];
2705 : }
2706 : else
2707 : {
2708 0 : spwId = spw_idx;
2709 : }
2710 :
2711 : // jagonzal: Skip this SPW in non-reindex mode
2712 0 : if ((!reindex_p) and (numOfSelChanMap_p.find(spw_idx) == numOfSelChanMap_p.end())) continue;
2713 :
2714 0 : Vector<Double> originalChanFreq(chanFreqCol(spw_idx));
2715 0 : Vector<Double> originalChanWidth(chanWidthCol(spw_idx));
2716 0 : Vector<Double> inputEffectiveBW(effectiveBWCol(spw_idx));
2717 0 : Vector<Double> inputResolution(resolutionCol(spw_idx));
2718 0 : uInt nChannels = originalChanFreq.size();
2719 :
2720 0 : for (uInt chan_idx=0;chan_idx<nChannels;chan_idx++)
2721 : {
2722 0 : channelInfo channelInfo_idx;
2723 0 : channelInfo_idx.SPW_id = spwId;
2724 :
2725 0 : channelInfo_idx.inpChannel = chan_idx;
2726 0 : channelInfo_idx.CHAN_FREQ = originalChanFreq(chan_idx);
2727 0 : channelInfo_idx.CHAN_WIDTH = originalChanWidth(chan_idx);
2728 0 : channelInfo_idx.EFFECTIVE_BW = inputEffectiveBW(chan_idx);
2729 0 : channelInfo_idx.RESOLUTION = inputResolution(chan_idx);
2730 :
2731 0 : inputChannels.push_back(channelInfo_idx);
2732 : }
2733 : }
2734 :
2735 : // Sort input channels
2736 0 : sort (inputChannels.begin(), inputChannels.end());
2737 :
2738 : /// Determine combined SPW structure ///////////////////
2739 :
2740 : // Determine combined SPWs
2741 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2742 0 : << "Calculate combined SPW frequencies" << LogIO::POST;
2743 :
2744 0 : Vector<Double> combinedCHAN_FREQ;
2745 0 : Vector<Double> combinedCHAN_WIDTH;
2746 0 : std::vector<std::vector<Int> > averageWhichChan;
2747 0 : std::vector<std::vector<Int> > averageWhichSPW;
2748 0 : std::vector<std::vector<Double> > averageChanFrac;
2749 0 : MSTransformRegridder::combineSpws(logger_p,outMsName_p,Vector<Int>(1,-1),
2750 : combinedCHAN_FREQ,combinedCHAN_WIDTH,
2751 : averageWhichChan, averageWhichSPW, averageChanFrac, true);
2752 :
2753 : // Create list of combined channels
2754 0 : vector<channelInfo> combinedChannels;
2755 0 : uInt nCombinedChannels = combinedCHAN_FREQ.size();
2756 0 : for (uInt chan_idx=0;chan_idx<nCombinedChannels;chan_idx++)
2757 : {
2758 0 : channelInfo channelInfo_idx;
2759 0 : channelInfo_idx.SPW_id = 0;
2760 0 : channelInfo_idx.inpChannel = chan_idx;
2761 0 : channelInfo_idx.CHAN_FREQ = combinedCHAN_FREQ(chan_idx);
2762 0 : channelInfo_idx.CHAN_WIDTH = combinedCHAN_WIDTH(chan_idx);
2763 0 : channelInfo_idx.EFFECTIVE_BW = combinedCHAN_WIDTH(chan_idx);
2764 0 : channelInfo_idx.RESOLUTION = combinedCHAN_WIDTH(chan_idx);
2765 0 : channelInfo_idx.contribFrac = averageChanFrac.at(chan_idx);
2766 0 : channelInfo_idx.contribSPW_id = averageWhichSPW.at(chan_idx);
2767 0 : channelInfo_idx.contribChannel = averageWhichChan.at(chan_idx);
2768 0 : combinedChannels.push_back(channelInfo_idx);
2769 : }
2770 :
2771 : // create list of input overlapping channels per combined channel
2772 : // note combineSpws has an edge case growing channels for slight overlap on edges,
2773 : // there the overlap is 1 even though combchannel->overlap(inputchannel) is slightly smaller than 1
2774 0 : inputOutputChanFactorMap_p.clear();
2775 :
2776 0 : for (auto combChanIter = combinedChannels.begin(); combChanIter != combinedChannels.end(); combChanIter++)
2777 : {
2778 0 : for (auto k = 0lu; k < combChanIter->contribFrac.size(); k++)
2779 : {
2780 : // combineSpws sorts spw so we need to map back to input selection to get correct input spw
2781 0 : uInt spw_idx = combChanIter->contribSPW_id[k];
2782 0 : if (outputInputSPWIndexMap_p.size())
2783 : {
2784 0 : spw_idx = outputInputSPWIndexMap_p[spw_idx];
2785 : }
2786 :
2787 : // jagonzal: Skip this SPW in non-reindex mode
2788 0 : if ((!reindex_p) and (numOfSelChanMap_p.find(spw_idx) == numOfSelChanMap_p.end())) continue;
2789 :
2790 0 : inputOutputChanFactorMap_p[combChanIter->inpChannel].
2791 0 : push_back(channelContribution(spw_idx, combChanIter->contribChannel[k], combChanIter->inpChannel, combChanIter->contribFrac[k]));
2792 : }
2793 : }
2794 :
2795 : /// Calculate output SPW ///////////////////////////////
2796 0 : Vector<Double> regriddedCHAN_FREQ;
2797 0 : Vector<Double> regriddedCHAN_WIDTH;
2798 0 : Vector<Double> inputCHAN_FREQ;
2799 0 : Vector<Double> inputCHAN_WIDTH;
2800 0 : regridSpwAux(0,inputReferenceFrame_p,combinedCHAN_FREQ,combinedCHAN_WIDTH,inputCHAN_FREQ,inputCHAN_WIDTH,regriddedCHAN_FREQ,regriddedCHAN_WIDTH,string("Combined"));
2801 0 : spwInfo inputSpw(inputCHAN_FREQ,inputCHAN_WIDTH);
2802 0 : spwInfo outputSpw(regriddedCHAN_FREQ,regriddedCHAN_WIDTH);
2803 :
2804 : /// Modify SPW subtable ////////////////////////////////
2805 :
2806 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2807 0 : << "Write output SPW subtable " << LogIO::POST;
2808 :
2809 : // Delete combined SPWs (reverse to preserve row number)
2810 0 : uInt rowsToDelete = nInputSpws-1;
2811 0 : for(Int spw_idx=rowsToDelete; spw_idx>0; spw_idx--)
2812 : {
2813 0 : spwTable.removeRow(spw_idx);
2814 : }
2815 :
2816 : // Set the output SPW characteristics in the SPW sub-table
2817 0 : numChanCol.put(0,outputSpw.NUM_CHAN);
2818 0 : chanFreqCol.put(0, outputSpw.CHAN_FREQ);
2819 0 : chanWidthCol.put(0, outputSpw.CHAN_WIDTH);
2820 0 : effectiveBWCol.put(0, outputSpw.EFFECTIVE_BW);
2821 0 : resolutionCol.put(0, outputSpw.RESOLUTION);
2822 0 : refFrequencyCol.put(0,outputSpw.REF_FREQUENCY);
2823 0 : totalBandwidthCol.put(0,outputSpw.TOTAL_BANDWIDTH);
2824 0 : measFreqRefCol.put(0,outputReferenceFrame_p);
2825 :
2826 : /// Add input-output SPW pair to map ///////////////////
2827 0 : inputOutputSpwMap_p[0] = std::make_pair(inputSpw,outputSpw);
2828 :
2829 : // Prepare frequency transformation engine for the reference time
2830 0 : if (fftShiftEnabled_p)
2831 : {
2832 0 : MFrequency::Ref inputFrameRef(inputReferenceFrame_p,
2833 0 : MeasFrame(phaseCenter_p, observatoryPosition_p, referenceTime_p));
2834 0 : MFrequency::Ref outputFrameRef(outputReferenceFrame_p,
2835 0 : MeasFrame(phaseCenter_p, observatoryPosition_p, referenceTime_p));
2836 0 : refTimeFreqTransEngine_p = MFrequency::Convert(MSTransformations::Hz, inputFrameRef, outputFrameRef);
2837 :
2838 0 : for(uInt chan_idx=0; chan_idx<inputOutputSpwMap_p[0].first.CHAN_FREQ.size(); chan_idx++)
2839 : {
2840 0 : inputOutputSpwMap_p[0].first.CHAN_FREQ_aux[chan_idx] =
2841 0 : refTimeFreqTransEngine_p(inputOutputSpwMap_p[0].first.CHAN_FREQ[chan_idx]).
2842 0 : get(MSTransformations::Hz).getValue();
2843 : }
2844 : }
2845 :
2846 0 : return;
2847 : }
2848 :
2849 :
2850 : // -----------------------------------------------------------------------
2851 : // Auxiliary method common whenever re-gridding is necessary (with or without combining
2852 : // the SPWs). It regrids one SPW.
2853 : // -----------------------------------------------------------------------
2854 0 : void MSTransformManager::regridSpwAux(Int spwId, MFrequency::Types spwInputRefFrame,
2855 : Vector<Double> &originalCHAN_FREQ,
2856 : Vector<Double> &originalCHAN_WIDTH,
2857 : Vector<Double> &inputCHAN_FREQ,
2858 : Vector<Double> &inputCHAN_WIDTH,
2859 : Vector<Double> ®riddedCHAN_FREQ,
2860 : Vector<Double> ®riddedCHAN_WIDTH,
2861 : string msg)
2862 : {
2863 :
2864 : // Print characteristics of input SPW
2865 0 : ostringstream oss;
2866 0 : oss << msg;
2867 0 : oss << " SPW: " << std::setw(5) << originalCHAN_FREQ.size()
2868 : << " channels, first channel = "
2869 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2870 0 : << originalCHAN_FREQ(0) << " Hz"
2871 : << ", last channel = "
2872 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2873 0 : << originalCHAN_FREQ(originalCHAN_FREQ.size() -1) << " Hz"
2874 : << ", first width = "
2875 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2876 0 : << originalCHAN_WIDTH(originalCHAN_WIDTH.size()-1) << " Hz"
2877 : << ", last width = "
2878 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2879 0 : << originalCHAN_WIDTH(originalCHAN_WIDTH.size()-1) << " Hz"
2880 : ;
2881 :
2882 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__) << oss.str() << LogIO::POST;
2883 :
2884 : // Apply channel average if necessary
2885 0 : if (freqbinMap_p.find(spwId) != freqbinMap_p.end()) {
2886 0 : calculateIntermediateFrequencies(spwId,originalCHAN_FREQ,originalCHAN_WIDTH,inputCHAN_FREQ,inputCHAN_WIDTH);
2887 :
2888 0 : oss.str("");
2889 0 : oss.clear();
2890 0 : oss << "Averaged SPW: " << std::setw(5) << inputCHAN_WIDTH.size()
2891 : << " channels, first channel = "
2892 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2893 0 : << inputCHAN_FREQ(0) << " Hz"
2894 : << ", last channel = "
2895 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2896 0 : << inputCHAN_FREQ(inputCHAN_WIDTH.size() -1) << " Hz";
2897 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2898 0 : << oss.str() << LogIO::POST;
2899 : } else {
2900 0 : numOfCombInputChanMap_p[spwId] = originalCHAN_FREQ.size();
2901 0 : numOfCombInterChanMap_p[spwId] = originalCHAN_FREQ.size();
2902 0 : inputCHAN_FREQ = originalCHAN_FREQ;
2903 0 : inputCHAN_WIDTH = originalCHAN_WIDTH;
2904 : }
2905 :
2906 : // Re-grid the output SPW to be uniform and change reference frame
2907 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2908 0 : << "Calculate frequencies in output reference frame " << LogIO::POST;
2909 :
2910 : Double weightScale;
2911 0 : bool ret = MSTransformRegridder::calcChanFreqs(logger_p,
2912 : regriddedCHAN_FREQ, regriddedCHAN_WIDTH,
2913 : weightScale, inputCHAN_FREQ,
2914 0 : inputCHAN_WIDTH, phaseCenter_p,
2915 0 : spwInputRefFrame, referenceTime_p,
2916 0 : observatoryPosition_p, mode_p, nChan_p,
2917 0 : start_p, width_p, restFrequency_p,
2918 0 : outputReferenceFramePar_p,
2919 0 : velocityType_p,
2920 : true, // verbose
2921 0 : radialVelocity_p);
2922 :
2923 0 : if (!ret) {
2924 0 : logger_p << LogIO::SEVERE << "calcChanFreqs failed, check input start and width parameters"
2925 0 : << LogIO::EXCEPTION;
2926 : }
2927 :
2928 0 : ostringstream oss_debug;
2929 0 : oss_debug << "after calcChanFreqs, phaseCenter_p=" << phaseCenter_p << endl
2930 0 : << " inputReferenceFrame_p=" << inputReferenceFrame_p << endl
2931 0 : << " referenceTime_p=" << referenceTime_p << endl
2932 0 : << " observatoryPosition_p=" << observatoryPosition_p << endl
2933 0 : << " mode_p=" << mode_p << endl
2934 0 : << " nChan_p=" << nChan_p << endl
2935 0 : << " start_p=" << start_p << endl
2936 0 : << " width_p=" << width_p << endl
2937 0 : << " restFrequency_p=" << restFrequency_p << endl
2938 0 : << " outputReferenceFrame_p=" << outputReferenceFrame_p << endl
2939 0 : << " velocityType_p=" << velocityType_p << endl
2940 0 : << " radialVelocity_p=" << radialVelocity_p;
2941 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__) <<
2942 0 : oss_debug.str() << LogIO::POST;
2943 :
2944 : // jagonzal (new WEIGHT/SIGMA convention in CASA 4.2.2)
2945 0 : if (newWeightFactorMap_p.find(spwId) == newWeightFactorMap_p.end()) {
2946 0 : newWeightFactorMap_p[spwId] = weightScale;
2947 : } else {
2948 0 : newWeightFactorMap_p[spwId] *= weightScale;
2949 : }
2950 :
2951 0 : checkAndPreaverageChannelsIfNeeded(spwId, inputCHAN_FREQ, inputCHAN_WIDTH,
2952 : originalCHAN_FREQ, originalCHAN_WIDTH,
2953 : regriddedCHAN_FREQ, regriddedCHAN_WIDTH);
2954 :
2955 : // Print characteristics of output SPW
2956 0 : oss.str("");
2957 0 : oss.clear();
2958 0 : oss << "Output SPW: " << std::setw(5) << regriddedCHAN_FREQ.size()
2959 : << " channels, first channel = "
2960 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2961 0 : << regriddedCHAN_FREQ(0) << " Hz"
2962 : << ", last channel = "
2963 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2964 0 : << regriddedCHAN_FREQ(regriddedCHAN_FREQ.size()-1) << " Hz"
2965 : <<", first width = "
2966 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2967 0 : << regriddedCHAN_WIDTH(0) << " Hz"
2968 : << ", last width = "
2969 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2970 0 : << regriddedCHAN_WIDTH(regriddedCHAN_WIDTH.size()-1) << " Hz";
2971 :
2972 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2973 0 : << oss.str() << LogIO::POST;
2974 0 : }
2975 :
2976 : // -----------------------------------------------------------------------
2977 : //
2978 : // -----------------------------------------------------------------------
2979 0 : void MSTransformManager::separateSpwSubtable()
2980 : {
2981 0 : if (Table::isReadable(outputMs_p->spectralWindowTableName()) and !outputMs_p->spectralWindow().isNull())
2982 : {
2983 : // Access Spectral Window sub-table
2984 0 : MSSpectralWindow spwTable = outputMs_p->spectralWindow();
2985 :
2986 0 : if (spwTable.nrow() > 0)
2987 : {
2988 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2989 0 : << " Multiplexing SPECTRAL_WINDOW sub-table to take into account new SPWs " << LogIO::POST;
2990 :
2991 0 : MSSpWindowColumns spwCols(spwTable);
2992 :
2993 : // Access columns which have to be separated
2994 0 : ArrayColumn<Double> chanFreqCol = spwCols.chanFreq();
2995 0 : Vector<Double> chanFreq = chanFreqCol(0);
2996 0 : ArrayColumn<Double> chanWidthCol = spwCols.chanWidth();
2997 0 : Vector<Double> chanWidth = chanWidthCol(0);
2998 0 : ArrayColumn<Double> effectiveBWCol = spwCols.chanWidth();
2999 0 : Vector<Double> effectiveBW = effectiveBWCol(0);
3000 0 : ArrayColumn<Double> resolutionCol = spwCols.resolution();
3001 0 : Vector<Double> resolution = resolutionCol(0);
3002 :
3003 : // Resize columns to be separated
3004 : // jagonzal (jagonzal (CAS-7435)): Last spw must have fewer channels
3005 : /*
3006 : if (tailOfChansforLastSpw_p)
3007 : {
3008 : uInt nInChannels = chanFreq.size();
3009 : uInt nOutChannels = nspws_p*chansPerOutputSpw_p;
3010 : uInt newChannels = nOutChannels-nInChannels;
3011 : Double lastFreq = chanFreq(chanFreq.size()-1);
3012 : Double lastWidth = chanWidth(chanFreq.size()-1);
3013 : Double lastEffectiveBW = effectiveBW(chanFreq.size()-1);
3014 : Double lastResolution = resolution(chanFreq.size()-1);
3015 :
3016 : chanFreq.resize(nOutChannels,true);
3017 : chanWidth.resize(nOutChannels,true);
3018 : effectiveBW.resize(nOutChannels,true);
3019 : resolution.resize(nOutChannels,true);
3020 :
3021 : uInt outIndex;
3022 : for (uInt newChanIdx = 0; newChanIdx<newChannels; newChanIdx++)
3023 : {
3024 : outIndex = nInChannels+newChanIdx;
3025 : chanFreq(outIndex) = lastFreq + (newChanIdx+1)*lastWidth;
3026 : chanWidth(outIndex) = lastWidth;
3027 : effectiveBW(outIndex) = lastEffectiveBW;
3028 : resolution(outIndex) = lastResolution;
3029 : }
3030 : }
3031 : */
3032 :
3033 : // Calculate bandwidth per output spw
3034 0 : Double totalBandwidth = chanWidth(0)*chansPerOutputSpw_p;
3035 :
3036 0 : uInt rowIndex = 0;
3037 0 : for (uInt spw_i=0; spw_i<nspws_p; spw_i++)
3038 : {
3039 : // Columns that can be just copied
3040 0 : if (rowIndex > 0)
3041 : {
3042 : // Add row
3043 0 : spwTable.addRow(1,true);
3044 :
3045 0 : spwCols.measFreqRef().put(rowIndex,spwCols.measFreqRef()(0));
3046 0 : spwCols.flagRow().put(rowIndex,spwCols.flagRow()(0));
3047 0 : spwCols.freqGroup().put(rowIndex,spwCols.freqGroup()(0));
3048 0 : spwCols.freqGroupName().put(rowIndex,spwCols.freqGroupName()(0));
3049 0 : spwCols.ifConvChain().put(rowIndex,spwCols.ifConvChain()(0));
3050 0 : spwCols.name().put(rowIndex,spwCols.name()(0));
3051 0 : spwCols.netSideband().put(rowIndex,spwCols.netSideband()(0));
3052 :
3053 : // Optional columns
3054 0 : if (MSTransformDataHandler::columnOk(spwCols.bbcNo()))
3055 : {
3056 0 : spwCols.bbcNo().put(rowIndex,spwCols.bbcNo()(0));
3057 : }
3058 :
3059 0 : if (MSTransformDataHandler::columnOk(spwCols.assocSpwId()))
3060 : {
3061 0 : spwCols.assocSpwId().put(rowIndex,spwCols.assocSpwId()(0));
3062 : }
3063 :
3064 0 : if (MSTransformDataHandler::columnOk(spwCols.assocNature()))
3065 : {
3066 0 : spwCols.assocNature().put(rowIndex,spwCols.assocNature()(0));
3067 : }
3068 :
3069 0 : if (MSTransformDataHandler::columnOk(spwCols.bbcSideband()))
3070 : {
3071 0 : spwCols.bbcSideband().put(rowIndex,spwCols.bbcSideband()(0));
3072 : }
3073 :
3074 0 : if (MSTransformDataHandler::columnOk(spwCols.dopplerId()))
3075 : {
3076 0 : spwCols.dopplerId().put(rowIndex,spwCols.dopplerId()(0));
3077 : }
3078 :
3079 0 : if (MSTransformDataHandler::columnOk(spwCols.receiverId()))
3080 : {
3081 0 : spwCols.receiverId().put(rowIndex,spwCols.receiverId()(0));
3082 : }
3083 :
3084 0 : if (spwTable.tableDesc().isColumn("SDM_WINDOW_FUNCTION") &&
3085 0 : spwTable.tableDesc().columnDescSet().isDefined("SDM_WINDOW_FUNCTION"))
3086 : {
3087 0 : ScalarColumn<String> swfCol(spwTable, "SDM_WINDOW_FUNCTION");
3088 0 : swfCol.put(rowIndex, swfCol(0));
3089 : }
3090 :
3091 0 : if (spwTable.tableDesc().isColumn("SDM_NUM_BIN") &&
3092 0 : spwTable.tableDesc().columnDescSet().isDefined("SDM_NUM_BIN"))
3093 : {
3094 0 : ScalarColumn<Int> snbCol(spwTable, "SDM_NUM_BIN");
3095 0 : snbCol.put(rowIndex, snbCol(0));
3096 : }
3097 :
3098 0 : if (spwTable.tableDesc().isColumn("SDM_CORR_BIT") &&
3099 0 : spwTable.tableDesc().columnDescSet().isDefined("SDM_CORR_BIT"))
3100 : {
3101 0 : ScalarColumn<String> corrBitCol(spwTable, "SDM_CORR_BIT");
3102 0 : corrBitCol.put(rowIndex, corrBitCol(0));
3103 : }
3104 :
3105 : }
3106 :
3107 0 : if ( (spw_i < nspws_p-1) or (tailOfChansforLastSpw_p == 0) )
3108 : {
3109 0 : Slice range(chansPerOutputSpw_p*spw_i,chansPerOutputSpw_p);
3110 :
3111 : // Array columns that have to be modified
3112 0 : spwCols.chanFreq().put(rowIndex,chanFreq(range));
3113 0 : spwCols.chanWidth().put(rowIndex,chanWidth(range));
3114 0 : spwCols.effectiveBW().put(rowIndex,effectiveBW(range));
3115 0 : spwCols.resolution().put(rowIndex,resolution(range));
3116 :
3117 : // Scalar columns that have to be modified
3118 0 : spwCols.numChan().put(rowIndex,chansPerOutputSpw_p);
3119 0 : spwCols.totalBandwidth().put(rowIndex,totalBandwidth);
3120 0 : spwCols.refFrequency().put(rowIndex,chanFreq(range)(0));
3121 : }
3122 : // jagonzal (jagonzal (CAS-7435)): Last spw must have fewer channels
3123 : else
3124 : {
3125 0 : Slice range(chansPerOutputSpw_p*spw_i,tailOfChansforLastSpw_p);
3126 :
3127 : // Array columns that have to be modified
3128 0 : spwCols.chanFreq().put(rowIndex,chanFreq(range));
3129 0 : spwCols.chanWidth().put(rowIndex,chanWidth(range));
3130 0 : spwCols.effectiveBW().put(rowIndex,effectiveBW(range));
3131 0 : spwCols.resolution().put(rowIndex,resolution(range));
3132 :
3133 : // Scalar columns that have to be modified
3134 0 : spwCols.numChan().put(rowIndex,tailOfChansforLastSpw_p);
3135 0 : spwCols.totalBandwidth().put(rowIndex,chanWidth(0)*tailOfChansforLastSpw_p);
3136 0 : spwCols.refFrequency().put(rowIndex,chanFreq(range)(0));
3137 : }
3138 :
3139 0 : rowIndex += 1;
3140 : }
3141 :
3142 : // Remove first row
3143 : // spwTable.removeRow(0);
3144 : }
3145 : else
3146 : {
3147 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
3148 0 : << "SPECTRAL_WINDOW sub-table found but has no valid content" << LogIO::POST;
3149 : }
3150 : }
3151 : else
3152 : {
3153 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
3154 0 : << "SPECTRAL_WINDOW sub-table not found " << LogIO::POST;
3155 : }
3156 :
3157 0 : return;
3158 : }
3159 :
3160 : // -----------------------------------------------------------------------
3161 : //
3162 : // -----------------------------------------------------------------------
3163 0 : void MSTransformManager::separateFeedSubtable()
3164 : {
3165 0 : if (Table::isReadable(outputMs_p->feedTableName()) and !outputMs_p->feed().isNull())
3166 : {
3167 : // Access Feed sub-table
3168 0 : MSFeed feedtable = outputMs_p->feed();
3169 :
3170 0 : if (feedtable.nrow() > 0)
3171 : {
3172 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
3173 0 : << " Multiplexing FEED sub-table to take into account new SPWs " << LogIO::POST;
3174 :
3175 0 : MSFeedColumns feedCols(feedtable);
3176 :
3177 : // Get original content from columns
3178 0 : Array<Double> position = feedCols.position().getColumn();
3179 0 : Array<Double> beamOffset = feedCols.beamOffset().getColumn();
3180 0 : Array<String> polarizationType = feedCols.polarizationType().getColumn();
3181 0 : Array<Complex> polResponse = feedCols.polResponse().getColumn();
3182 0 : Array<Double> receptorAngle = feedCols.receptorAngle().getColumn();
3183 0 : Array<Int> antennaId = feedCols.antennaId().getColumn();
3184 0 : Array<Int> beamId = feedCols.beamId().getColumn();
3185 0 : Array<Int> feedId = feedCols.feedId().getColumn();
3186 0 : Array<Double> interval = feedCols.interval().getColumn();
3187 0 : Array<Int> numReceptors = feedCols.numReceptors().getColumn();
3188 0 : Array<Int> spectralWindowId = feedCols.spectralWindowId().getColumn();
3189 0 : Array<Double> time = feedCols.time().getColumn();
3190 :
3191 : // Optional columns
3192 0 : Array<Double> focusLength;
3193 0 : if (MSTransformDataHandler::columnOk(feedCols.focusLength()))
3194 : {
3195 0 : focusLength = feedCols.focusLength().getColumn();
3196 : }
3197 :
3198 0 : Array<Int> phasedFeedId;
3199 0 : if (MSTransformDataHandler::columnOk(feedCols.phasedFeedId()))
3200 : {
3201 0 : phasedFeedId = feedCols.phasedFeedId().getColumn();
3202 : }
3203 :
3204 0 : auto nRowsPerSpw = feedCols.spectralWindowId().nrow();
3205 0 : auto rowIndex = nRowsPerSpw;
3206 0 : for (uInt spw_i=1; spw_i<nspws_p; spw_i++)
3207 : {
3208 : // Add rows
3209 0 : feedtable.addRow(nRowsPerSpw);
3210 :
3211 : // Prepare row reference object
3212 0 : RefRows refRow(rowIndex,rowIndex+nRowsPerSpw-1);
3213 :
3214 : // Reindex SPW col
3215 0 : spectralWindowId = spw_i;
3216 0 : feedCols.spectralWindowId().putColumnCells(refRow,spectralWindowId);
3217 :
3218 : // Columns that can be just copied
3219 0 : feedCols.position().putColumnCells(refRow,position);
3220 0 : feedCols.beamOffset().putColumnCells(refRow,beamOffset);
3221 0 : feedCols.polarizationType().putColumnCells(refRow,polarizationType);
3222 0 : feedCols.polResponse().putColumnCells(refRow,polResponse);
3223 0 : feedCols.receptorAngle().putColumnCells(refRow,receptorAngle);
3224 0 : feedCols.antennaId().putColumnCells(refRow,antennaId);
3225 0 : feedCols.beamId().putColumnCells(refRow,beamId);
3226 0 : feedCols.feedId().putColumnCells(refRow,feedId);
3227 0 : feedCols.interval().putColumnCells(refRow,interval);
3228 0 : feedCols.numReceptors().putColumnCells(refRow,numReceptors);
3229 0 : feedCols.time().putColumnCells(refRow,time);
3230 :
3231 : // Optional columns
3232 0 : if (MSTransformDataHandler::columnOk(feedCols.focusLength()))
3233 : {
3234 0 : feedCols.focusLength().putColumnCells(refRow,focusLength);
3235 : }
3236 :
3237 0 : if (MSTransformDataHandler::columnOk(feedCols.phasedFeedId()))
3238 : {
3239 0 : feedCols.phasedFeedId().putColumnCells(refRow,phasedFeedId);
3240 : }
3241 :
3242 : // Increment row offset
3243 0 : rowIndex += nRowsPerSpw;
3244 : }
3245 :
3246 : }
3247 : else
3248 : {
3249 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
3250 0 : << "FEED sub-table found but has no valid content" << LogIO::POST;
3251 : }
3252 : }
3253 : else
3254 : {
3255 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
3256 0 : << "FEED sub-table not found " << LogIO::POST;
3257 : }
3258 :
3259 0 : return;
3260 : }
3261 :
3262 : // -----------------------------------------------------------------------
3263 : //
3264 : // -----------------------------------------------------------------------
3265 0 : void MSTransformManager::separateSourceSubtable()
3266 : {
3267 0 : if (Table::isReadable(outputMs_p->sourceTableName()) and !outputMs_p->source().isNull())
3268 : {
3269 : // Access Source sub-table
3270 0 : MSSource sourcetable = outputMs_p->source();
3271 :
3272 0 : if (sourcetable.nrow() > 0)
3273 : {
3274 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
3275 0 : << " Multiplexing SOURCE sub-table to take into account new SPWs " << LogIO::POST;
3276 :
3277 0 : MSSourceColumns sourceCols(sourcetable);
3278 :
3279 : // Get original content from columns
3280 0 : Array<Double> direction = sourceCols.direction().getColumn();
3281 0 : Array<Double> properMotion = sourceCols.properMotion().getColumn();
3282 0 : Array<Int> calibrationGroup = sourceCols.calibrationGroup().getColumn();
3283 0 : Array<String> code = sourceCols.code().getColumn();
3284 0 : Array<Double> interval = sourceCols.interval().getColumn();
3285 0 : Array<String> name = sourceCols.name().getColumn();
3286 0 : Array<Int> numLines = sourceCols.numLines().getColumn();
3287 0 : Array<Int> sourceId = sourceCols.sourceId().getColumn();
3288 0 : Array<Int> spectralWindowId = sourceCols.spectralWindowId().getColumn();
3289 0 : Array<Double> time = sourceCols.time().getColumn();
3290 :
3291 : // Optional columns
3292 0 : Array<Double> position;
3293 0 : if (MSTransformDataHandler::columnOk(sourceCols.position()))
3294 : {
3295 0 : position = sourceCols.position().getColumn();
3296 : }
3297 :
3298 0 : Array<String> transition;
3299 0 : if (MSTransformDataHandler::columnOk(sourceCols.transition()))
3300 : {
3301 0 : transition = sourceCols.transition().getColumn();
3302 : }
3303 :
3304 0 : Array<Double> restFrequency;
3305 0 : if (MSTransformDataHandler::columnOk(sourceCols.restFrequency()))
3306 : {
3307 0 : restFrequency = sourceCols.restFrequency().getColumn();
3308 : }
3309 :
3310 0 : Array<Double> sysvel;
3311 0 : if (MSTransformDataHandler::columnOk(sourceCols.sysvel()))
3312 : {
3313 0 : sysvel = sourceCols.sysvel().getColumn();
3314 : }
3315 :
3316 0 : Array<Int> pulsarId;
3317 0 : if (MSTransformDataHandler::columnOk(sourceCols.pulsarId()))
3318 : {
3319 0 : pulsarId = sourceCols.pulsarId().getColumn();
3320 : }
3321 :
3322 0 : Array<TableRecord> sourceModel;
3323 0 : if (MSTransformDataHandler::columnOk(sourceCols.sourceModel()))
3324 : {
3325 0 : sourceModel = sourceCols.sourceModel().getColumn();
3326 : }
3327 :
3328 :
3329 0 : auto nRowsPerSpw = sourceCols.spectralWindowId().nrow();
3330 0 : auto rowIndex = nRowsPerSpw;
3331 0 : for (uInt spw_i=1; spw_i<nspws_p; spw_i++)
3332 : {
3333 : // Add rows
3334 0 : sourcetable.addRow(nRowsPerSpw);
3335 :
3336 : // Prepare row reference object
3337 0 : RefRows refRow(rowIndex,rowIndex+nRowsPerSpw-1);
3338 :
3339 : // Re-index SPW col
3340 0 : spectralWindowId = spw_i;
3341 0 : sourceCols.spectralWindowId().putColumnCells(refRow,spectralWindowId);
3342 :
3343 : // Columns that can be just copied
3344 0 : sourceCols.direction().putColumnCells(refRow,direction);
3345 0 : sourceCols.properMotion().putColumnCells(refRow,properMotion);
3346 0 : sourceCols.calibrationGroup().putColumnCells(refRow,calibrationGroup);
3347 0 : sourceCols.code().putColumnCells(refRow,code);
3348 0 : sourceCols.interval().putColumnCells(refRow,interval);
3349 0 : sourceCols.name().putColumnCells(refRow,name);
3350 0 : sourceCols.numLines().putColumnCells(refRow,numLines);
3351 0 : sourceCols.sourceId().putColumnCells(refRow,sourceId);
3352 0 : sourceCols.time().putColumnCells(refRow,time);
3353 :
3354 : // Optional columns
3355 0 : if (MSTransformDataHandler::columnOk(sourceCols.position()))
3356 : {
3357 0 : sourceCols.position().putColumnCells(refRow,position);
3358 : }
3359 :
3360 0 : if (MSTransformDataHandler::columnOk(sourceCols.transition()))
3361 : {
3362 0 : sourceCols.transition().putColumnCells(refRow,transition);
3363 : }
3364 :
3365 0 : if (MSTransformDataHandler::columnOk(sourceCols.restFrequency()))
3366 : {
3367 0 : sourceCols.restFrequency().putColumnCells(refRow,restFrequency);
3368 : }
3369 :
3370 0 : if (MSTransformDataHandler::columnOk(sourceCols.sysvel()))
3371 : {
3372 0 : sourceCols.sysvel().putColumnCells(refRow,sysvel);
3373 : }
3374 :
3375 0 : if (MSTransformDataHandler::columnOk(sourceCols.pulsarId()))
3376 : {
3377 0 : sourceCols.pulsarId().putColumnCells(refRow,pulsarId);
3378 : }
3379 :
3380 0 : if (MSTransformDataHandler::columnOk(sourceCols.sourceModel()))
3381 : {
3382 0 : sourceCols.sourceModel().putColumnCells(refRow,sourceModel);
3383 : }
3384 :
3385 : // Increment row offset
3386 0 : rowIndex += nRowsPerSpw;
3387 : }
3388 :
3389 : }
3390 : else
3391 : {
3392 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
3393 0 : << "SOURCE sub-table found but has no valid content" << LogIO::POST;
3394 : }
3395 : }
3396 : else
3397 : {
3398 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
3399 0 : << "SOURCE sub-table not found " << LogIO::POST;
3400 : }
3401 :
3402 0 : return;
3403 : }
3404 :
3405 : // -----------------------------------------------------------------------
3406 : //
3407 : // -----------------------------------------------------------------------
3408 0 : void MSTransformManager::separateSyscalSubtable()
3409 : {
3410 :
3411 0 : if (Table::isReadable(outputMs_p->sysCalTableName()) and !outputMs_p->sysCal().isNull())
3412 : {
3413 : // Access SysCal sub-table
3414 0 : MSSysCal syscalTable = outputMs_p->sysCal();
3415 :
3416 0 : if (syscalTable.nrow() > 0)
3417 : {
3418 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
3419 0 : << " Multiplexing SYSCAL sub-table to take into account new SPWs " << LogIO::POST;
3420 :
3421 0 : MSSysCalColumns syscalCols(syscalTable);
3422 :
3423 : // Get original content from columns
3424 0 : Array<Int> antennaId = syscalCols.antennaId().getColumn();
3425 0 : Array<Int> feedId = syscalCols.feedId().getColumn();
3426 0 : Array<Double> interval = syscalCols.interval().getColumn();
3427 0 : Array<Int> spectralWindowId = syscalCols.spectralWindowId().getColumn();
3428 0 : Array<Double> time = syscalCols.time().getColumn();
3429 :
3430 : // Optional columns
3431 0 : Array<Float> phaseDiff;
3432 0 : if (MSTransformDataHandler::columnOk(syscalCols.phaseDiff()))
3433 : {
3434 0 : phaseDiff = syscalCols.phaseDiff().getColumn();
3435 : }
3436 :
3437 0 : Array<bool> phaseDiffFlag;
3438 0 : if (MSTransformDataHandler::columnOk(syscalCols.phaseDiffFlag()))
3439 : {
3440 0 : phaseDiffFlag = syscalCols.phaseDiffFlag().getColumn();
3441 : }
3442 :
3443 0 : Array<Float> tant;
3444 0 : if (MSTransformDataHandler::columnOk(syscalCols.tant()))
3445 : {
3446 0 : tant = syscalCols.tant().getColumn();
3447 : }
3448 :
3449 0 : Array<bool> tantFlag;
3450 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantFlag()))
3451 : {
3452 0 : tantFlag = syscalCols.tantFlag().getColumn();
3453 : }
3454 :
3455 0 : Array<Float> tantSpectrum;
3456 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantSpectrum()))
3457 : {
3458 0 : tantSpectrum = syscalCols.tantSpectrum().getColumn();
3459 : }
3460 :
3461 0 : Array<Float> tantTsys;
3462 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantTsys()))
3463 : {
3464 0 : tantTsys = syscalCols.tantTsys().getColumn();
3465 : }
3466 :
3467 0 : Array<bool> tantTsysFlag;
3468 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantTsysFlag()))
3469 : {
3470 0 : tantTsysFlag = syscalCols.tantTsysFlag().getColumn();
3471 : }
3472 :
3473 0 : Array<Float> tantTsysSpectrum;
3474 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantTsysSpectrum()))
3475 : {
3476 0 : tantTsysSpectrum = syscalCols.tantTsysSpectrum().getColumn();
3477 : }
3478 :
3479 0 : Array<Float> tcal;
3480 0 : if (MSTransformDataHandler::columnOk(syscalCols.tcal()))
3481 : {
3482 0 : tcal = syscalCols.tcal().getColumn();
3483 : }
3484 :
3485 0 : Array<bool> tcalFlag;
3486 0 : if (MSTransformDataHandler::columnOk(syscalCols.tcalFlag()))
3487 : {
3488 0 : tcalFlag = syscalCols.tcalFlag().getColumn();
3489 : }
3490 :
3491 0 : Array<Float> tcalSpectrum;
3492 0 : if (MSTransformDataHandler::columnOk(syscalCols.tcalSpectrum()))
3493 : {
3494 0 : tcalSpectrum = syscalCols.tcalSpectrum().getColumn();
3495 : }
3496 :
3497 0 : Array<Float> trx;
3498 0 : if (MSTransformDataHandler::columnOk(syscalCols.trx()))
3499 : {
3500 0 : trx = syscalCols.trx().getColumn();
3501 : }
3502 :
3503 0 : Array<bool> trxFlag;
3504 0 : if (MSTransformDataHandler::columnOk(syscalCols.trxFlag()))
3505 : {
3506 0 : trxFlag = syscalCols.trxFlag().getColumn();
3507 : }
3508 :
3509 0 : Array<Float> trxSpectrum;
3510 0 : if (MSTransformDataHandler::columnOk(syscalCols.trxSpectrum()))
3511 : {
3512 0 : trxSpectrum = syscalCols.trxSpectrum().getColumn();
3513 : }
3514 :
3515 0 : Array<Float> tsky;
3516 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsky()))
3517 : {
3518 0 : tsky = syscalCols.tsky().getColumn();
3519 : }
3520 :
3521 0 : Array<bool> tskyFlag;
3522 0 : if (MSTransformDataHandler::columnOk(syscalCols.tskyFlag()))
3523 : {
3524 0 : tskyFlag = syscalCols.tskyFlag().getColumn();
3525 : }
3526 :
3527 0 : Array<Float> tskySpectrum;
3528 0 : if (MSTransformDataHandler::columnOk(syscalCols.tskySpectrum()))
3529 : {
3530 0 : tskySpectrum = syscalCols.tskySpectrum().getColumn();
3531 : }
3532 :
3533 0 : Array<Float> tsys;
3534 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsys()))
3535 : {
3536 0 : tsys = syscalCols.tsys().getColumn();
3537 : }
3538 :
3539 0 : Array<bool> tsysFlag;
3540 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsysFlag()))
3541 : {
3542 0 : tsysFlag = syscalCols.tsysFlag().getColumn();
3543 : }
3544 :
3545 0 : Array<Float> tsysSpectrum;
3546 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsysSpectrum()))
3547 : {
3548 0 : tsysSpectrum = syscalCols.tsysSpectrum().getColumn();
3549 : }
3550 :
3551 :
3552 0 : auto nRowsPerSpw = syscalCols.spectralWindowId().nrow();
3553 0 : auto rowIndex = nRowsPerSpw;
3554 0 : for (uInt spw_i=1; spw_i<nspws_p; spw_i++)
3555 : {
3556 : // Add rows
3557 0 : syscalTable.addRow(nRowsPerSpw);
3558 :
3559 : // Prepare row reference object
3560 0 : RefRows refRow(rowIndex,rowIndex+nRowsPerSpw-1);
3561 :
3562 : // Re-index SPW col
3563 0 : spectralWindowId = spw_i;
3564 0 : syscalCols.spectralWindowId().putColumnCells(refRow,spectralWindowId);
3565 :
3566 : // Columns that can be just copied
3567 0 : syscalCols.antennaId().putColumnCells(refRow,antennaId);
3568 0 : syscalCols.feedId().putColumnCells(refRow,feedId);
3569 0 : syscalCols.interval().putColumnCells(refRow,interval);
3570 0 : syscalCols.time().putColumnCells(refRow,time);
3571 :
3572 : // Optional columns
3573 0 : if (MSTransformDataHandler::columnOk(syscalCols.phaseDiff()))
3574 : {
3575 0 : syscalCols.phaseDiff().putColumnCells(refRow,phaseDiff);
3576 : }
3577 :
3578 0 : if (MSTransformDataHandler::columnOk(syscalCols.phaseDiffFlag()))
3579 : {
3580 0 : syscalCols.phaseDiffFlag().putColumnCells(refRow,phaseDiffFlag);
3581 : }
3582 :
3583 0 : if (MSTransformDataHandler::columnOk(syscalCols.tant()))
3584 : {
3585 0 : syscalCols.tant().putColumnCells(refRow,tant);
3586 : }
3587 :
3588 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantFlag()))
3589 : {
3590 0 : syscalCols.tantFlag().putColumnCells(refRow,tantFlag);
3591 : }
3592 :
3593 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantSpectrum()))
3594 : {
3595 0 : syscalCols.tantSpectrum().putColumnCells(refRow,tantSpectrum);
3596 : }
3597 :
3598 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantTsys()))
3599 : {
3600 0 : syscalCols.tantTsys().putColumnCells(refRow,tantTsys);
3601 : }
3602 :
3603 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantTsysFlag()))
3604 : {
3605 0 : syscalCols.tantTsysFlag().putColumnCells(refRow,tantTsysFlag);
3606 : }
3607 :
3608 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantTsysSpectrum()))
3609 : {
3610 0 : syscalCols.tantTsysSpectrum().putColumnCells(refRow,tantTsysSpectrum);
3611 : }
3612 :
3613 0 : if (MSTransformDataHandler::columnOk(syscalCols.tcal()))
3614 : {
3615 0 : syscalCols.tcal().putColumnCells(refRow,tcal);
3616 : }
3617 :
3618 0 : if (MSTransformDataHandler::columnOk(syscalCols.tcalFlag()))
3619 : {
3620 0 : syscalCols.tcalFlag().putColumnCells(refRow,tcalFlag);
3621 : }
3622 :
3623 0 : if (MSTransformDataHandler::columnOk(syscalCols.tcalSpectrum()))
3624 : {
3625 0 : syscalCols.tcalSpectrum().putColumnCells(refRow,tcalSpectrum);
3626 : }
3627 :
3628 0 : if (MSTransformDataHandler::columnOk(syscalCols.trx()))
3629 : {
3630 0 : syscalCols.trx().putColumnCells(refRow,trx);
3631 : }
3632 :
3633 0 : if (MSTransformDataHandler::columnOk(syscalCols.trxFlag()))
3634 : {
3635 0 : syscalCols.trxFlag().putColumnCells(refRow,trxFlag);
3636 : }
3637 :
3638 0 : if (MSTransformDataHandler::columnOk(syscalCols.trxSpectrum()))
3639 : {
3640 0 : syscalCols.trxSpectrum().putColumnCells(refRow,trxSpectrum);
3641 : }
3642 :
3643 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsky()))
3644 : {
3645 0 : syscalCols.tsky().putColumnCells(refRow,tsky);
3646 : }
3647 :
3648 0 : if (MSTransformDataHandler::columnOk(syscalCols.tskyFlag()))
3649 : {
3650 0 : syscalCols.tskyFlag().putColumnCells(refRow,tskyFlag);
3651 : }
3652 :
3653 0 : if (MSTransformDataHandler::columnOk(syscalCols.tskySpectrum()))
3654 : {
3655 0 : syscalCols.tskySpectrum().putColumnCells(refRow,tskySpectrum);
3656 : }
3657 :
3658 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsys()))
3659 : {
3660 0 : syscalCols.tsys().putColumnCells(refRow,tsys);
3661 : }
3662 :
3663 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsysFlag()))
3664 : {
3665 0 : syscalCols.tsysFlag().putColumnCells(refRow,tsysFlag);
3666 : }
3667 :
3668 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsysSpectrum()))
3669 : {
3670 0 : syscalCols.tsysSpectrum().putColumnCells(refRow,tsysSpectrum);
3671 : }
3672 :
3673 : // Increment row offset
3674 0 : rowIndex += nRowsPerSpw;
3675 : }
3676 :
3677 : }
3678 : else
3679 : {
3680 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3681 0 : << "SYSCAL sub-table found but has no valid content" << LogIO::POST;
3682 : }
3683 : }
3684 : else
3685 : {
3686 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3687 0 : << "SYSCAL sub-table not found " << LogIO::POST;
3688 : }
3689 :
3690 0 : return;
3691 : }
3692 :
3693 : // -----------------------------------------------------------------------
3694 : //
3695 : // -----------------------------------------------------------------------
3696 0 : void MSTransformManager::separateFreqOffsetSubtable()
3697 : {
3698 :
3699 0 : if (Table::isReadable(outputMs_p->freqOffsetTableName()) and !outputMs_p->freqOffset().isNull())
3700 : {
3701 : // Access SysCal sub-table
3702 0 : MSFreqOffset freqoffsetTable = outputMs_p->freqOffset();
3703 :
3704 0 : if (freqoffsetTable.nrow() > 0)
3705 : {
3706 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
3707 0 : << " Multiplexing FREQ_OFFSET sub-table to take into account new SPWs " << LogIO::POST;
3708 :
3709 0 : MSFreqOffsetColumns freqoffsetCols(freqoffsetTable);
3710 :
3711 : // Get original content from columns
3712 0 : Array<Int> antenna1 = freqoffsetCols.antenna1().getColumn();
3713 0 : Array<Int> antenna2 = freqoffsetCols.antenna2().getColumn();
3714 0 : Array<Int> feedId = freqoffsetCols.feedId().getColumn();
3715 0 : Array<Double> interval = freqoffsetCols.interval().getColumn();
3716 0 : Array<Double> offset = freqoffsetCols.offset().getColumn();
3717 0 : Array<Int> spectralWindowId = freqoffsetCols.spectralWindowId().getColumn();
3718 0 : Array<Double> time = freqoffsetCols.time().getColumn();
3719 :
3720 : // NOTE (jagonzal): FreqOffset does not have optional columns
3721 :
3722 0 : auto nRowsPerSpw = freqoffsetCols.spectralWindowId().nrow();
3723 0 : auto rowIndex = nRowsPerSpw;
3724 0 : for (uInt spw_i=1; spw_i<nspws_p; spw_i++)
3725 : {
3726 : // Add rows
3727 0 : freqoffsetTable.addRow(nRowsPerSpw);
3728 :
3729 : // Prepare row reference object
3730 0 : RefRows refRow(rowIndex,rowIndex+nRowsPerSpw-1);
3731 :
3732 : // Re-index SPW col
3733 0 : spectralWindowId = spw_i;
3734 0 : freqoffsetCols.spectralWindowId().putColumnCells(refRow,spectralWindowId);
3735 :
3736 : // Columns that can be just copied
3737 0 : freqoffsetCols.antenna1().putColumnCells(refRow,antenna1);
3738 0 : freqoffsetCols.antenna2().putColumnCells(refRow,antenna2);
3739 0 : freqoffsetCols.feedId().putColumnCells(refRow,feedId);
3740 0 : freqoffsetCols.interval().putColumnCells(refRow,interval);
3741 0 : freqoffsetCols.offset().putColumnCells(refRow,offset);
3742 0 : freqoffsetCols.time().putColumnCells(refRow,time);
3743 :
3744 : // Increment row offset
3745 0 : rowIndex += nRowsPerSpw;
3746 : }
3747 :
3748 : }
3749 : else
3750 : {
3751 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3752 0 : << "FREQ_OFFSET sub-table found but has no valid content" << LogIO::POST;
3753 : }
3754 : }
3755 : else
3756 : {
3757 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3758 0 : << "FREQ_OFFSET sub-table not found " << LogIO::POST;
3759 : }
3760 :
3761 0 : return;
3762 : }
3763 :
3764 : // -----------------------------------------------------------------------
3765 : //
3766 : // -----------------------------------------------------------------------
3767 0 : void MSTransformManager::separateCalDeviceSubtable()
3768 : {
3769 0 : if (Table::isReadable(outputMs_p->tableName() + "/CALDEVICE"))
3770 : {
3771 0 : Table subtable(outputMs_p->tableName() + "/CALDEVICE", Table::Update);
3772 :
3773 0 : if (subtable.nrow() > 0)
3774 : {
3775 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
3776 0 : << " Multiplexing CALDEVICE sub-table to take into account new SPWs " << LogIO::POST;
3777 :
3778 : // Get RW access to columns
3779 0 : ScalarColumn<Int> antennaIdCol(subtable, "ANTENNA_ID");
3780 0 : ScalarColumn<Int> feedIdCol(subtable, "FEED_ID");
3781 0 : ScalarColumn<Int> spectralWindowIdCol(subtable, "SPECTRAL_WINDOW_ID");
3782 0 : ScalarColumn<Double> timeCol(subtable, "TIME");
3783 0 : ScalarColumn<Double> intervalCol(subtable, "INTERVAL");
3784 0 : ScalarColumn<Int> numCalLoadCol(subtable, "NUM_CAL_LOAD");
3785 0 : ArrayColumn<String> calLoadNamesCol(subtable, "CAL_LOAD_NAMES");
3786 0 : ScalarColumn<Int> numReceptorCol(subtable, "NUM_RECEPTOR");
3787 0 : ArrayColumn<Float> noiseCalCol(subtable, "NOISE_CAL");
3788 0 : ArrayColumn<Float> calEffCol(subtable, "CAL_EFF");
3789 0 : ArrayColumn<Double> temperatureLoadCol(subtable, "TEMPERATURE_LOAD");
3790 :
3791 : // Get original content of columns
3792 0 : Array<Int> antennaId;
3793 0 : if (MSTransformDataHandler::columnOk(antennaIdCol))
3794 0 : antennaId = antennaIdCol.getColumn();
3795 0 : Array<Int> feedId;
3796 0 : if (MSTransformDataHandler::columnOk(feedIdCol))
3797 0 : feedId = feedIdCol.getColumn();
3798 0 : Array<Int> spectralWindowId;
3799 0 : if (MSTransformDataHandler::columnOk(spectralWindowIdCol))
3800 0 : spectralWindowId = spectralWindowIdCol.getColumn();
3801 0 : Array<Double> time;
3802 0 : if (MSTransformDataHandler::columnOk(timeCol))
3803 0 : time = timeCol.getColumn();
3804 0 : Array<Double> interval;
3805 0 : if (MSTransformDataHandler::columnOk(intervalCol))
3806 0 : interval = intervalCol.getColumn();
3807 :
3808 0 : Array<Int> numCalLoad;
3809 0 : if (MSTransformDataHandler::columnOk(numCalLoadCol))
3810 0 : numCalLoad = numCalLoadCol.getColumn();
3811 0 : Array<String> calLoadNames;
3812 0 : if (MSTransformDataHandler::columnOk(calLoadNamesCol))
3813 0 : calLoadNames = calLoadNamesCol.getColumn();
3814 0 : Array<Int> numReceptor;
3815 0 : if (MSTransformDataHandler::columnOk(numReceptorCol))
3816 0 : numReceptor = numReceptorCol.getColumn();
3817 0 : Array<Float> noiseCal;
3818 0 : if (MSTransformDataHandler::columnOk(noiseCalCol))
3819 0 : noiseCal = noiseCalCol.getColumn();
3820 0 : Array<Float> calEff;
3821 0 : if (MSTransformDataHandler::columnOk(calEffCol))
3822 0 : calEff = calEffCol.getColumn();
3823 0 : Array<Double> temperatureLoad;
3824 0 : if (MSTransformDataHandler::columnOk(temperatureLoadCol))
3825 0 : temperatureLoad = temperatureLoadCol.getColumn();
3826 :
3827 :
3828 0 : uInt nRowsPerSpw = spectralWindowId.nelements();
3829 0 : uInt rowIndex = nRowsPerSpw;
3830 0 : for (uInt spw_i=1; spw_i<nspws_p; spw_i++)
3831 : {
3832 : // Add rows
3833 0 : subtable.addRow(nRowsPerSpw);
3834 :
3835 : // Prepare row reference object
3836 0 : RefRows refRow(rowIndex,rowIndex+nRowsPerSpw-1);
3837 :
3838 : // Re-index SPW col
3839 0 : spectralWindowId = spw_i;
3840 0 : spectralWindowIdCol.putColumnCells(refRow,spectralWindowId);
3841 :
3842 : // Columns that can be just copied
3843 0 : if (MSTransformDataHandler::columnOk(antennaIdCol))
3844 0 : antennaIdCol.putColumnCells(refRow,antennaId);
3845 0 : if (MSTransformDataHandler::columnOk(feedIdCol))
3846 0 : feedIdCol.putColumnCells(refRow,feedId);
3847 0 : if (MSTransformDataHandler::columnOk(timeCol))
3848 0 : timeCol.putColumnCells(refRow,time);
3849 0 : if (MSTransformDataHandler::columnOk(intervalCol))
3850 0 : intervalCol.putColumnCells(refRow,interval);
3851 :
3852 0 : if (MSTransformDataHandler::columnOk(numCalLoadCol))
3853 0 : numCalLoadCol.putColumnCells(refRow,numCalLoad);
3854 0 : if (MSTransformDataHandler::columnOk(calLoadNamesCol))
3855 0 : calLoadNamesCol.putColumnCells(refRow,calLoadNames);
3856 0 : if (MSTransformDataHandler::columnOk(numReceptorCol))
3857 0 : numReceptorCol.putColumnCells(refRow,numReceptor);
3858 0 : if (MSTransformDataHandler::columnOk(noiseCalCol))
3859 0 : noiseCalCol.putColumnCells(refRow,noiseCal);
3860 0 : if (MSTransformDataHandler::columnOk(calEffCol))
3861 0 : calEffCol.putColumnCells(refRow,calEff);
3862 0 : if (MSTransformDataHandler::columnOk(temperatureLoadCol))
3863 0 : temperatureLoadCol.putColumnCells(refRow,temperatureLoad);
3864 :
3865 : // Increment row offset
3866 0 : rowIndex += nRowsPerSpw;
3867 : }
3868 :
3869 : }
3870 : else
3871 : {
3872 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3873 0 : << "CALDEVICE sub-table found but has no valid content" << LogIO::POST;
3874 : }
3875 : }
3876 : else
3877 : {
3878 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3879 0 : << "CALDEVICE sub-table not found." << LogIO::POST;
3880 : }
3881 :
3882 0 : return;
3883 : }
3884 :
3885 : // -----------------------------------------------------------------------
3886 : //
3887 : // -----------------------------------------------------------------------
3888 0 : void MSTransformManager::separateSysPowerSubtable()
3889 : {
3890 0 : if (Table::isReadable(outputMs_p->tableName() + "/SYSPOWER"))
3891 : {
3892 0 : Table subtable(outputMs_p->tableName() + "/SYSPOWER", Table::Update);
3893 :
3894 0 : if (subtable.nrow() > 0)
3895 : {
3896 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
3897 0 : << " Multiplexing SYSPOWER sub-table to take into account new SPWs " << LogIO::POST;
3898 :
3899 : // Get RW access to columns
3900 0 : ScalarColumn<Int> antennaIdCol(subtable, "ANTENNA_ID");
3901 0 : ScalarColumn<Int> feedIdCol(subtable, "FEED_ID");
3902 0 : ScalarColumn<Int> spectralWindowIdCol(subtable, "SPECTRAL_WINDOW_ID");
3903 0 : ScalarColumn<Double> timeCol(subtable, "TIME");
3904 0 : ScalarColumn<Double> intervalCol(subtable, "INTERVAL");
3905 0 : ArrayColumn<Float> switchedDiffCol(subtable, "SWITCHED_DIFF");
3906 0 : ArrayColumn<Float> switchedSumCol(subtable, "SWITCHED_SUM");
3907 0 : ArrayColumn<Float> requantizerGainCol(subtable, "REQUANTIZER_GAIN");
3908 :
3909 : // Get original content of columns
3910 0 : Array<Int> antennaId;
3911 0 : if (MSTransformDataHandler::columnOk(antennaIdCol))
3912 0 : antennaId = antennaIdCol.getColumn();
3913 0 : Array<Int> feedId;
3914 0 : if (MSTransformDataHandler::columnOk(feedIdCol))
3915 0 : feedId = feedIdCol.getColumn();
3916 0 : Array<Int> spectralWindowId;
3917 0 : if (MSTransformDataHandler::columnOk(spectralWindowIdCol))
3918 0 : spectralWindowId = spectralWindowIdCol.getColumn();
3919 0 : Array<Double> time;
3920 0 : if (MSTransformDataHandler::columnOk(timeCol))
3921 0 : time = timeCol.getColumn();
3922 0 : Array<Double> interval;
3923 0 : if (MSTransformDataHandler::columnOk(intervalCol))
3924 0 : interval = intervalCol.getColumn();
3925 :
3926 0 : Array<Float> switchedDiff;
3927 0 : if (MSTransformDataHandler::columnOk(switchedDiffCol))
3928 0 : switchedDiff = switchedDiffCol.getColumn();
3929 0 : Array<Float> switchedSum;
3930 0 : if (MSTransformDataHandler::columnOk(switchedSumCol))
3931 0 : switchedSum = switchedSumCol.getColumn();
3932 0 : Array<Float> requantizerGain;
3933 0 : if (MSTransformDataHandler::columnOk(requantizerGainCol))
3934 0 : requantizerGain = requantizerGainCol.getColumn();
3935 :
3936 0 : auto nRowsPerSpw = spectralWindowId.nelements();
3937 0 : auto rowIndex = nRowsPerSpw;
3938 0 : for (uInt spw_i=1; spw_i<nspws_p; spw_i++)
3939 : {
3940 : // Add rows
3941 0 : subtable.addRow(nRowsPerSpw);
3942 :
3943 : // Prepare row reference object
3944 0 : RefRows refRow(rowIndex,rowIndex+nRowsPerSpw-1);
3945 :
3946 : // Re-index SPW col
3947 0 : spectralWindowId = spw_i;
3948 0 : spectralWindowIdCol.putColumnCells(refRow,spectralWindowId);
3949 :
3950 : // Columns that can be just copied
3951 0 : if (MSTransformDataHandler::columnOk(antennaIdCol))
3952 0 : antennaIdCol.putColumnCells(refRow,antennaId);
3953 0 : if (MSTransformDataHandler::columnOk(feedIdCol))
3954 0 : feedIdCol.putColumnCells(refRow,feedId);
3955 0 : if (MSTransformDataHandler::columnOk(timeCol))
3956 0 : timeCol.putColumnCells(refRow,time);
3957 0 : if (MSTransformDataHandler::columnOk(intervalCol))
3958 0 : intervalCol.putColumnCells(refRow,interval);
3959 :
3960 0 : if (MSTransformDataHandler::columnOk(switchedDiffCol))
3961 0 : switchedDiffCol.putColumnCells(refRow,switchedDiff);
3962 0 : if (MSTransformDataHandler::columnOk(switchedSumCol))
3963 0 : switchedSumCol.putColumnCells(refRow,switchedSum);
3964 0 : if (MSTransformDataHandler::columnOk(requantizerGainCol))
3965 0 : requantizerGainCol.putColumnCells(refRow,requantizerGain);
3966 :
3967 : // Increment row offset
3968 0 : rowIndex += nRowsPerSpw;
3969 : }
3970 :
3971 : }
3972 : else
3973 : {
3974 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3975 0 : << "SYSPOWER sub-table found but has no valid content" << LogIO::POST;
3976 : }
3977 : }
3978 : else
3979 : {
3980 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3981 0 : << "SYSPOWER sub-table not found." << LogIO::POST;
3982 : }
3983 :
3984 0 : return;
3985 : }
3986 :
3987 : // -----------------------------------------------------------------------
3988 : // Return polarization id corresponding to polarization averaged data (Stokes I)
3989 : // Append Polarization row if necessary
3990 : // -----------------------------------------------------------------------
3991 0 : Int MSTransformManager::getAveragedPolarizationId() {
3992 0 : logger_p << LogOrigin("MSTransformManager", __func__, WHERE);
3993 0 : MSPolarizationColumns cols(outputMs_p->polarization());
3994 0 : Int polId = -1;
3995 0 : auto nrow = cols.nrow();
3996 0 : for (rownr_t i = 0; i < nrow; ++i) {
3997 0 : auto const numCorr = cols.numCorr()(i);
3998 0 : auto const flagRow = cols.flagRow()(i);
3999 0 : if (numCorr == 1 && flagRow == False) {
4000 0 : Vector<Int> const corrType = cols.corrType()(i);
4001 0 : Int const corrType0 = corrType[0];
4002 0 : if (Stokes::type(corrType0) == Stokes::I) {
4003 0 : logger_p << "Matched " << i << LogIO::POST;
4004 0 : polId = i;
4005 0 : break;
4006 : }
4007 : }
4008 : }
4009 :
4010 0 : if (polId < 0) {
4011 : // add new row to PolarizationTable
4012 0 : outputMs_p->polarization().addRow(1, False);
4013 0 : polId = nrow;
4014 0 : Matrix<Int> corrProduct(2, 1, 0);
4015 0 : cols.corrProduct().put(polId, corrProduct);
4016 0 : Vector<Int> corrType(1, Stokes::I);
4017 0 : cols.corrType().put(polId, corrType);
4018 0 : cols.flagRow().put(polId, False);
4019 0 : cols.numCorr().put(polId, 1);
4020 : }
4021 :
4022 0 : return polId;
4023 : }
4024 :
4025 : // -----------------------------------------------------------------------
4026 : // Re-index POLARIZATION_ID's in DATA_DESCRIPTION table
4027 : // -----------------------------------------------------------------------
4028 0 : void MSTransformManager::reindexPolarizationIdInDataDesc(Int newPolarizationId) {
4029 0 : logger_p << LogOrigin("MSTransformManager", __func__, WHERE);
4030 0 : logger_p << "new polid is " << newPolarizationId << LogIO::POST;
4031 0 : MSDataDescColumns ddcols(outputMs_p->dataDescription());
4032 0 : MSPolarizationColumns pcols(outputMs_p->polarization());
4033 0 : rownr_t nrow = ddcols.nrow();
4034 0 : auto __isValidType = [&](Vector<Int> const &ctype) {
4035 0 : return (anyEQ(ctype, (Int)Stokes::XX) && anyEQ(ctype, (Int)Stokes::YY))
4036 0 : || (anyEQ(ctype, (Int)Stokes::RR) && anyEQ(ctype, (Int)Stokes::LL));
4037 : };
4038 0 : for (rownr_t i = 0; i < nrow; ++i) {
4039 0 : Int const polarizationId = ddcols.polarizationId()(i);
4040 0 : Int nCorr = pcols.numCorr()(polarizationId);
4041 0 : Vector<Int> corrType = pcols.corrType()(polarizationId);
4042 0 : bool flagRow = pcols.flagRow()(polarizationId);
4043 0 : bool needReindex = (polarizationId != newPolarizationId) &&
4044 0 : (nCorr > 1) && (flagRow == False) && __isValidType(corrType);
4045 0 : if (needReindex) {
4046 0 : logger_p << "ddid " << i << " polid " << polarizationId << " needs reindex" << LogIO::POST;
4047 0 : ddcols.polarizationId().put(i, newPolarizationId);
4048 : }
4049 : }
4050 0 : }
4051 :
4052 :
4053 : // -----------------------------------------------------------------------
4054 : //
4055 : // -----------------------------------------------------------------------
4056 0 : void MSTransformManager::checkAndPreaverageChannelsIfNeeded(Int spwId,
4057 : Vector<Double> &inputCHAN_FREQ,
4058 : Vector<Double> &inputCHAN_WIDTH,
4059 :
4060 : const Vector<Double> &originalCHAN_FREQ,
4061 : const Vector<Double> &originalCHAN_WIDTH,
4062 : const Vector<Double> ®riddedCHAN_FREQ,
4063 : const Vector<Double> ®riddedCHAN_WIDTH
4064 : ) {
4065 : // Check if pre-averaging step is necessary
4066 0 : if (freqbinMap_p.find(spwId) == freqbinMap_p.end()) {
4067 : Double weightScaleDummy;
4068 0 : Vector<Double> tmpCHAN_FREQ;
4069 0 : Vector<Double> tmpCHAN_WIDTH;
4070 0 : MSTransformRegridder::calcChanFreqs(logger_p, tmpCHAN_FREQ, tmpCHAN_WIDTH,
4071 : weightScaleDummy, originalCHAN_FREQ,
4072 0 : originalCHAN_WIDTH, phaseCenter_p,
4073 : inputReferenceFrame_p,
4074 0 : referenceTime_p,
4075 0 : observatoryPosition_p,
4076 0 : String("channel"), -1,
4077 0 : String("0"), String("1"),
4078 0 : restFrequency_p,
4079 0 : outputReferenceFramePar_p,
4080 0 : velocityType_p, false // verbose
4081 : );
4082 :
4083 0 : Double avgCombinedWidth = 0;
4084 0 : for (uInt chanIdx = 0; chanIdx < tmpCHAN_WIDTH.size(); ++chanIdx) {
4085 0 : avgCombinedWidth += tmpCHAN_WIDTH(chanIdx);
4086 : }
4087 0 : avgCombinedWidth /= tmpCHAN_WIDTH.size();
4088 :
4089 0 : Double avgRegriddedWidth = 0;
4090 0 : for (uInt chanIdx=0;chanIdx<regriddedCHAN_WIDTH.size();chanIdx++) {
4091 0 : avgRegriddedWidth += regriddedCHAN_WIDTH(chanIdx);
4092 : }
4093 0 : avgRegriddedWidth /= regriddedCHAN_WIDTH.size();
4094 :
4095 0 : Double widthFactor = fabs(avgRegriddedWidth/avgCombinedWidth);
4096 0 : uInt widthFactorInt = (uInt)floor(widthFactor + 0.001);
4097 :
4098 0 : if ((widthFactorInt >= 2) and 2*widthFactorInt <= originalCHAN_WIDTH.size()) {
4099 0 : if (!enableChanPreAverage_p) {
4100 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4101 : << "Ratio between input and output width is >=2: " << avgRegriddedWidth/avgCombinedWidth
4102 : << ", but not doing pre-channel average (it is disabled by "
4103 0 : << "default since CASA release 5.0)." << LogIO::POST;
4104 :
4105 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4106 : << "Regridding to intermediate grid ("
4107 : << originalCHAN_FREQ.size()
4108 : << " channels) for interpolation as in tclean when the "
4109 : << " ratio between the output and input widths is >2."
4110 0 : << LogIO::POST;
4111 :
4112 0 : initGridForRegridTClean(originalCHAN_FREQ, regriddedCHAN_FREQ,
4113 : regriddedCHAN_WIDTH, widthFactor);
4114 :
4115 : } else {
4116 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
4117 : << "mstransform with regridms does not regrid properly for channel widths "
4118 : "> or = 2 x the native channel width, when using channel pre-averaging. Please "
4119 : "use clean or tclean for larger regridding. "
4120 0 : << LogIO::POST;
4121 :
4122 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4123 : << "Ratio between input and output width is " << avgRegriddedWidth/avgCombinedWidth
4124 0 : << ", setting pre-channel average width to " << widthFactorInt << LogIO::POST;
4125 :
4126 0 : doPreAveragingBeforeRegridding(widthFactorInt, spwId,
4127 : originalCHAN_FREQ, originalCHAN_WIDTH,
4128 : inputCHAN_FREQ, inputCHAN_WIDTH);
4129 : }
4130 : }
4131 : }
4132 0 : }
4133 :
4134 : // -----------------------------------------------------------------------
4135 : //
4136 : // -----------------------------------------------------------------------
4137 0 : void MSTransformManager::doPreAveragingBeforeRegridding(uInt widthFactor, Int spwId,
4138 : const Vector<Double> &originalCHAN_FREQ,
4139 : const Vector<Double> &originalCHAN_WIDTH,
4140 : Vector<Double> &inputCHAN_FREQ,
4141 : Vector<Double> &inputCHAN_WIDTH) {
4142 0 : channelAverage_p = true;
4143 0 : freqbinMap_p[spwId] = widthFactor;
4144 0 : newWeightFactorMap_p[spwId] /= widthFactor; // jagonzal: Remove channel width contribution to the scale factor
4145 :
4146 : // Calculate averaged frequencies
4147 0 : calculateIntermediateFrequencies(spwId, originalCHAN_FREQ, originalCHAN_WIDTH,
4148 : inputCHAN_FREQ, inputCHAN_WIDTH);
4149 :
4150 0 : ostringstream oss;
4151 0 : oss << "Averaged SPW: " << std::setw(5) << inputCHAN_WIDTH.size()
4152 : << " channels, first channel = "
4153 0 : << std::setprecision(9) << std::setw(14) << std::scientific
4154 0 : << inputCHAN_FREQ(0) << " Hz"
4155 : << ", last channel = "
4156 0 : << std::setprecision(9) << std::setw(14) << std::scientific
4157 0 : << inputCHAN_FREQ(inputCHAN_WIDTH.size() -1) << " Hz";
4158 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4159 0 : << oss.str() << LogIO::POST;
4160 0 : }
4161 :
4162 : // -----------------------------------------------------------------------
4163 : //
4164 : // -----------------------------------------------------------------------
4165 0 : void MSTransformManager::calculateIntermediateFrequencies( Int spwId,
4166 : const Vector<Double> &inputChanFreq,
4167 : const Vector<Double> &inputChanWidth,
4168 : Vector<Double> &intermediateChanFreq,
4169 : Vector<Double> &intermediateChanWidth)
4170 : {
4171 0 : uInt mumOfInterChan = inputChanFreq.size() / freqbinMap_p[spwId];
4172 0 : uInt lastChannelWidth = inputChanFreq.size() % freqbinMap_p[spwId];
4173 0 : if (lastChannelWidth > 0)
4174 : {
4175 0 : mumOfInterChan += 1;
4176 : }
4177 0 : numOfCombInputChanMap_p[spwId] = inputChanFreq.size();
4178 0 : numOfCombInterChanMap_p[spwId] = mumOfInterChan;
4179 0 : intermediateChanFreq.resize(mumOfInterChan,false);
4180 0 : intermediateChanWidth.resize(mumOfInterChan,false);
4181 0 : simpleAverage(freqbinMap_p[spwId], inputChanFreq, intermediateChanFreq);
4182 0 : simpleAverage(freqbinMap_p[spwId], inputChanWidth, intermediateChanWidth);
4183 :
4184 0 : for (uInt chanIdx=0;chanIdx<mumOfInterChan;chanIdx++)
4185 : {
4186 0 : intermediateChanWidth[chanIdx] *= freqbinMap_p[spwId];
4187 : }
4188 :
4189 0 : if (lastChannelWidth > 0)
4190 : {
4191 0 : intermediateChanWidth[mumOfInterChan-1] /= freqbinMap_p[spwId];
4192 0 : intermediateChanWidth[mumOfInterChan-1] *= lastChannelWidth;
4193 : }
4194 :
4195 0 : return;
4196 : }
4197 :
4198 : /**
4199 : * Create a fake grid and create a map [input channels] => [output channels]
4200 : * from it. This is for the tclean-like interpolation that is applied when
4201 : * the width of the output is > 2 x width of the inputs.
4202 : *
4203 : * Irrespective of channel widths, we want as many channels as in the
4204 : * original input, with their (lower) width, but projected/aligned
4205 : * with the output grid. As the output grid is fixed based on the
4206 : * first row timestamp, this only need to be done once, at init time.
4207 : *
4208 : * After this method is run, the interpolation methods can use
4209 : * regridTCleanChanMap_p to interpolate the tclean way.
4210 : *
4211 : * @param originalCHAN_FREQ initial input channel frequencies
4212 : * @param outCHAN_FREQ final output channel frequencies
4213 : * @param outCHAN_WIDTH final output channel widths
4214 : * @param widthFactor avg(output_widths) / avg(input_widths)
4215 : */
4216 0 : void MSTransformManager::initGridForRegridTClean(const Vector<Double> &originalCHAN_FREQ,
4217 : const Vector<Double> &outCHAN_FREQ,
4218 : const Vector<Double> &outCHAN_WIDTH,
4219 : Double widthFactor)
4220 : {
4221 : // build grid with widths of the input channels but aligned with the output
4222 : // grid
4223 0 : regridTCleanCHAN_FREQ_p.resize(originalCHAN_FREQ.size());
4224 0 : Vector<Double> regridTCleanCHAN_WIDTH_p;
4225 0 : regridTCleanCHAN_WIDTH_p.resize(regridTCleanCHAN_FREQ_p.size());
4226 :
4227 0 : const auto &outputFreqs = outCHAN_FREQ;
4228 0 : bool negativeWidths = outputFreqs[0] > outputFreqs[outputFreqs.size()-1];
4229 :
4230 : // swap first/last if "negative width" (decreasing frequencies)
4231 0 : auto startIdx = negativeWidths ? (outCHAN_FREQ.size() -1) : 0;
4232 0 : regridTCleanCHAN_FREQ_p[0] = outCHAN_FREQ[startIdx] - outCHAN_WIDTH[startIdx]/2.;
4233 0 : regridTCleanCHAN_WIDTH_p[0] = outCHAN_WIDTH[startIdx] / widthFactor;
4234 0 : Double widthFactorIdx = static_cast<Double>(regridTCleanCHAN_FREQ_p.size()) /
4235 0 : outCHAN_FREQ.size();
4236 :
4237 0 : for (size_t idx = 1; idx < regridTCleanCHAN_FREQ_p.size(); ++idx) {
4238 0 : Int outIdx = static_cast<Int>(idx / widthFactorIdx);
4239 0 : regridTCleanCHAN_WIDTH_p[idx] = outCHAN_WIDTH[outIdx] / widthFactorIdx;
4240 0 : regridTCleanCHAN_FREQ_p[idx] = regridTCleanCHAN_FREQ_p[idx-1] +
4241 0 : regridTCleanCHAN_WIDTH_p[idx];
4242 : }
4243 :
4244 :
4245 : // Build map from fake input channels => output channels
4246 0 : regridTCleanChanMap_p.resize(regridTCleanCHAN_FREQ_p.size());
4247 0 : regridTCleanChanMap_p = -1;
4248 0 : const auto &intermFreqs = regridTCleanCHAN_FREQ_p;
4249 0 : const auto &outputWidths = outCHAN_WIDTH;
4250 0 : for (uInt mapIdx = 0; mapIdx < regridTCleanChanMap_p.size(); ++mapIdx) {
4251 0 : for (uInt outIdx = 0; outIdx < outputFreqs.size(); ++outIdx) {
4252 0 : if (intermFreqs[mapIdx] >= outputFreqs[outIdx] - outputWidths[outIdx]/2. and
4253 0 : intermFreqs[mapIdx] < outputFreqs[outIdx] + outputWidths[outIdx]/2.) {
4254 0 : regridTCleanChanMap_p(mapIdx) = outIdx;
4255 0 : break;
4256 : }
4257 : }
4258 : }
4259 0 : regridTClean_p = true;
4260 0 : }
4261 :
4262 : // -----------------------------------------------------------------------
4263 : // Method to set all the elements of a scalar column to a given value
4264 : // -----------------------------------------------------------------------
4265 0 : void MSTransformManager::reindexColumn(ScalarColumn<Int> &inputCol, Int value)
4266 : {
4267 0 : for(rownr_t idx=0; idx<inputCol.nrow(); idx++)
4268 : {
4269 0 : inputCol.put(idx,value);
4270 : }
4271 :
4272 0 : return;
4273 : }
4274 :
4275 : // -----------------------------------------------------------------------
4276 : // Method to re-index Spectral Window column in Source sub-table
4277 : // -----------------------------------------------------------------------
4278 0 : void MSTransformManager::reindexSourceSubTable()
4279 : {
4280 0 : if(Table::isReadable(outputMs_p->sourceTableName()) and !outputMs_p->source().isNull())
4281 : {
4282 :
4283 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4284 0 : << "Re-indexing SOURCE sub-table" << LogIO::POST;
4285 :
4286 :
4287 0 : MSSource sourceSubtable = outputMs_p->source();
4288 0 : MSSourceColumns tableCols(sourceSubtable);
4289 0 : ScalarColumn<Int> spectralWindowId = tableCols.spectralWindowId();
4290 0 : ScalarColumn<Int> sourceId = tableCols.sourceId();
4291 0 : reindexColumn(spectralWindowId,0);
4292 :
4293 : // Remove duplicates
4294 0 : std::vector<rownr_t> duplicateIdx;
4295 0 : std::vector< std::pair<uInt,uInt> > sourceIdSpwIdMap;
4296 :
4297 0 : for (rownr_t idx = 0; idx < spectralWindowId.nrow(); idx++)
4298 : {
4299 0 : std::pair<uInt,uInt> sourceIdSpwId = std::make_pair(spectralWindowId(idx),sourceId(idx));
4300 :
4301 0 : if (std::find(sourceIdSpwIdMap.begin(),sourceIdSpwIdMap.end(),sourceIdSpwId) != sourceIdSpwIdMap.end())
4302 : {
4303 0 : duplicateIdx.push_back(idx);
4304 : }
4305 : else
4306 : {
4307 0 : sourceIdSpwIdMap.push_back(sourceIdSpwId);
4308 : }
4309 : }
4310 :
4311 0 : sourceSubtable.removeRow(Vector<rownr_t>(duplicateIdx.begin(),duplicateIdx.end()));
4312 :
4313 : }
4314 : else
4315 : {
4316 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
4317 0 : << "SOURCE sub-table not found " << LogIO::POST;
4318 : }
4319 :
4320 0 : return;
4321 : }
4322 :
4323 : // -----------------------------------------------------------------------
4324 : // Method to re-index Spectral Window column in DDI sub-table
4325 : // -----------------------------------------------------------------------
4326 0 : void MSTransformManager::reindexDDISubTable()
4327 : {
4328 0 : if(Table::isReadable(outputMs_p->dataDescriptionTableName()) and !outputMs_p->dataDescription().isNull())
4329 : {
4330 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4331 0 : << "Re-indexing DDI sub-table" << LogIO::POST;
4332 :
4333 : // Access DDI sub-table
4334 0 : MSDataDescription ddiTable = outputMs_p->dataDescription();
4335 0 : MSDataDescColumns ddiCols(ddiTable);
4336 :
4337 : // Add a new row for each of the separated SPWs
4338 0 : uInt rowIndex = 0;
4339 0 : for (uInt spw_i=0; spw_i<nspws_p; spw_i++)
4340 : {
4341 0 : if (rowIndex > 0)
4342 : {
4343 : // Add row
4344 0 : ddiTable.addRow(1,true);
4345 :
4346 : // Copy polID and flagRow from the first original SPW
4347 0 : ddiCols.polarizationId().put(rowIndex,ddiCols.polarizationId()(0));
4348 0 : ddiCols.flagRow().put(rowIndex,ddiCols.flagRow()(0));
4349 :
4350 : // Optional columns
4351 0 : if (ddiCols.lagId().isNull()==false and ddiCols.lagId().hasContent()==true)
4352 : {
4353 0 : ddiCols.lagId().put(rowIndex,ddiCols.lagId()(0));
4354 : }
4355 : }
4356 :
4357 : // Set SPW id separately
4358 0 : ddiCols.spectralWindowId().put(rowIndex,ddiStart_p+spw_i);
4359 :
4360 0 : rowIndex += 1;
4361 : }
4362 :
4363 : // Delete the old rows
4364 0 : rownr_t nrowsToDelete = ddiCols.nrow()-nspws_p;
4365 0 : if (nrowsToDelete > 0)
4366 : {
4367 0 : rownr_t rownr = ddiCols.nrow()-1;
4368 0 : Vector<rownr_t> rowsToDelete(nrowsToDelete);
4369 0 : for(rownr_t idx=0; idx<nrowsToDelete; idx++)
4370 : {
4371 0 : rowsToDelete(idx) = rownr;
4372 0 : rownr -= 1;
4373 : }
4374 :
4375 0 : ddiTable.removeRow(rowsToDelete);
4376 : }
4377 :
4378 :
4379 : }
4380 : else
4381 : {
4382 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
4383 0 : << "DATA_DESCRIPTION sub-table not found " << LogIO::POST;
4384 : }
4385 0 : }
4386 :
4387 : // -----------------------------------------------------------------------
4388 : // Method to re-index Spectral Window column in Feed sub-table
4389 : // -----------------------------------------------------------------------
4390 0 : void MSTransformManager::reindexFeedSubTable()
4391 : {
4392 0 : if(Table::isReadable(outputMs_p->feedTableName()) and !outputMs_p->feed().isNull())
4393 : {
4394 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4395 0 : << "Re-indexing FEED sub-table and removing duplicates" << LogIO::POST;
4396 :
4397 0 : MSFeed feedSubtable = outputMs_p->feed();
4398 0 : MSFeedColumns tableCols(feedSubtable);
4399 0 : ScalarColumn<Int> feedId = tableCols.feedId();
4400 0 : ScalarColumn<Int> antennaId = tableCols.antennaId();
4401 0 : ScalarColumn<Int> spectralWindowId = tableCols.spectralWindowId();
4402 0 : ScalarColumn<Double> time = tableCols.time();
4403 :
4404 : // Re-index SPWId to be 0
4405 0 : reindexColumn(spectralWindowId,0);
4406 :
4407 : // Remove duplicates
4408 0 : std::vector<rownr_t> duplicateIdx;
4409 0 : std::map< std::pair<uInt,uInt> , Double > antennaFeedTimeMap;
4410 0 : std::map< std::pair<uInt,uInt> , Double >::iterator antennaFeedTimeIter;
4411 :
4412 0 : for (rownr_t idx = 0; idx < spectralWindowId.nrow(); idx++)
4413 : {
4414 0 : std::pair<uInt,uInt> antennaFeedPair = std::make_pair(antennaId(idx),feedId(idx));
4415 0 : antennaFeedTimeIter = antennaFeedTimeMap.find(antennaFeedPair);
4416 :
4417 0 : if (antennaFeedTimeIter != antennaFeedTimeMap.end())
4418 : {
4419 0 : if (abs(antennaFeedTimeIter->second - time(idx)) < 2*FLT_MIN)
4420 : {
4421 0 : duplicateIdx.push_back(idx);
4422 : }
4423 : else
4424 : {
4425 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4426 : }
4427 : }
4428 : else
4429 : {
4430 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4431 : }
4432 : }
4433 :
4434 :
4435 0 : feedSubtable.removeRow(Vector<rownr_t>(duplicateIdx.begin(),duplicateIdx.end()));
4436 :
4437 : }
4438 : else
4439 : {
4440 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__) <<
4441 0 : "FEED sub-table not found " << LogIO::POST;
4442 : }
4443 :
4444 0 : return;
4445 : }
4446 :
4447 : // -----------------------------------------------------------------------
4448 : // Method to re-index Spectral Window column in SysCal sub-table
4449 : // -----------------------------------------------------------------------
4450 0 : void MSTransformManager::reindexSysCalSubTable()
4451 : {
4452 0 : if(Table::isReadable(outputMs_p->sysCalTableName()) and !outputMs_p->sysCal().isNull())
4453 : {
4454 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4455 0 : << "Re-indexing SYSCAL sub-table and removing duplicates" << LogIO::POST;
4456 :
4457 0 : MSSysCal syscalSubtable = outputMs_p->sysCal();
4458 0 : MSSysCalColumns tableCols(syscalSubtable);
4459 0 : ScalarColumn<Int> feedId = tableCols.feedId();
4460 0 : ScalarColumn<Int> antennaId = tableCols.antennaId();
4461 0 : ScalarColumn<Int> spectralWindowId = tableCols.spectralWindowId();
4462 0 : ScalarColumn<Double> time = tableCols.time();
4463 :
4464 : // Re-index SPWId to be 0
4465 0 : reindexColumn(spectralWindowId,0);
4466 :
4467 : // Remove duplicates
4468 0 : std::vector<rownr_t> duplicateIdx;
4469 0 : std::map< std::pair<uInt,uInt> , Double > antennaFeedTimeMap;
4470 0 : std::map< std::pair<uInt,uInt> , Double >::iterator antennaFeedTimeIter;
4471 :
4472 0 : for (rownr_t idx = 0; idx < spectralWindowId.nrow(); idx++)
4473 : {
4474 0 : std::pair<uInt,uInt> antennaFeedPair = std::make_pair(antennaId(idx),feedId(idx));
4475 0 : antennaFeedTimeIter = antennaFeedTimeMap.find(antennaFeedPair);
4476 :
4477 0 : if (antennaFeedTimeIter != antennaFeedTimeMap.end())
4478 : {
4479 0 : if (abs(antennaFeedTimeIter->second - time(idx)) < 2*FLT_MIN)
4480 : {
4481 0 : duplicateIdx.push_back(idx);
4482 : }
4483 : else
4484 : {
4485 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4486 : }
4487 : }
4488 : else
4489 : {
4490 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4491 : }
4492 : }
4493 :
4494 0 : syscalSubtable.removeRow(Vector<rownr_t>(duplicateIdx.begin(),duplicateIdx.end()));
4495 :
4496 : }
4497 : else
4498 : {
4499 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
4500 0 : << "SYSCAL sub-table not found " << LogIO::POST;
4501 : }
4502 :
4503 0 : return;
4504 : }
4505 :
4506 : // -----------------------------------------------------------------------
4507 : // Method to re-index Spectral Window column in FreqOffset sub-table
4508 : // -----------------------------------------------------------------------
4509 0 : void MSTransformManager::reindexFreqOffsetSubTable()
4510 : {
4511 0 : if(Table::isReadable(outputMs_p->freqOffsetTableName()) and !outputMs_p->freqOffset().isNull())
4512 : {
4513 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4514 0 : << "Re-indexing FREQ_OFFSET sub-table and removing duplicates" << LogIO::POST;
4515 :
4516 0 : MSFreqOffset freqoffsetSubtable = outputMs_p->freqOffset();
4517 0 : MSFreqOffsetColumns tableCols(freqoffsetSubtable);
4518 0 : ScalarColumn<Int> feedId = tableCols.feedId();
4519 0 : ScalarColumn<Int> antenna1 = tableCols.antenna1();
4520 0 : ScalarColumn<Int> antenna2 = tableCols.antenna2();
4521 0 : ScalarColumn<Int> spectralWindowId = tableCols.spectralWindowId();
4522 0 : ScalarColumn<Double> time = tableCols.time();
4523 :
4524 : // Re-index SPWId to be 0
4525 0 : reindexColumn(spectralWindowId,0);
4526 :
4527 : // Remove duplicates
4528 0 : std::vector<rownr_t> duplicateIdx;
4529 0 : std::map< std::pair < std::pair<uInt,uInt> , uInt> , Double > antennaFeedTimeMap;
4530 0 : std::map< std::pair < std::pair<uInt,uInt> , uInt> , Double >::iterator antennaFeedTimeIter;
4531 :
4532 0 : for (rownr_t idx = 0; idx < spectralWindowId.nrow(); idx++)
4533 : {
4534 0 : std::pair < std::pair<uInt,uInt> , uInt> antennaFeedPair = std::make_pair(std::make_pair(antenna1(idx),antenna2(idx)),feedId(idx));
4535 0 : antennaFeedTimeIter = antennaFeedTimeMap.find(antennaFeedPair);
4536 :
4537 0 : if (antennaFeedTimeIter != antennaFeedTimeMap.end())
4538 : {
4539 0 : if (abs(antennaFeedTimeIter->second - time(idx)) < 2*FLT_MIN)
4540 : {
4541 0 : duplicateIdx.push_back(idx);
4542 : }
4543 : else
4544 : {
4545 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4546 : }
4547 : }
4548 : else
4549 : {
4550 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4551 : }
4552 : }
4553 :
4554 0 : freqoffsetSubtable.removeRow(Vector<rownr_t>(duplicateIdx.begin(),duplicateIdx.end()));
4555 :
4556 : }
4557 : else
4558 : {
4559 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
4560 0 : << "FREQ_OFFSET sub-table not found " << LogIO::POST;
4561 : }
4562 :
4563 0 : return;
4564 : }
4565 :
4566 : // -----------------------------------------------------------------------
4567 : // Method to re-index Spectral Window column in a generic sub-table (with feedId, antennaId and time columns)
4568 : // -----------------------------------------------------------------------
4569 0 : void MSTransformManager::reindexGenericTimeDependentSubTable(const String& subtabname)
4570 : {
4571 0 : if (Table::isReadable(outputMs_p->tableName() + "/" + subtabname))
4572 : {
4573 0 : Table subtable(outputMs_p->tableName() + "/" + subtabname, Table::Update);
4574 :
4575 0 : if (subtable.nrow() > 0)
4576 : {
4577 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4578 : << "Re-indexing SPW column of " << subtabname
4579 0 : << " sub-table and removing duplicates " << LogIO::POST;
4580 :
4581 0 : ScalarColumn<Int> feedId(subtable, "FEED_ID");
4582 0 : ScalarColumn<Int> antennaId(subtable, "ANTENNA_ID");
4583 0 : ScalarColumn<Int> spectralWindowId(subtable, "SPECTRAL_WINDOW_ID");
4584 0 : ScalarColumn<Double> time(subtable, "TIME");
4585 :
4586 : // Re-index SPWId to be 0
4587 0 : reindexColumn(spectralWindowId,0);
4588 :
4589 : // Remove duplicates
4590 0 : std::vector<rownr_t> duplicateIdx;
4591 0 : std::map< std::pair<uInt,uInt> , Double > antennaFeedTimeMap;
4592 0 : std::map< std::pair<uInt,uInt> , Double >::iterator antennaFeedTimeIter;
4593 :
4594 0 : for (rownr_t idx = 0; idx < spectralWindowId.nrow(); idx++)
4595 : {
4596 0 : std::pair<uInt,uInt> antennaFeedPair = std::make_pair(antennaId(idx),feedId(idx));
4597 0 : antennaFeedTimeIter = antennaFeedTimeMap.find(antennaFeedPair);
4598 :
4599 0 : if (antennaFeedTimeIter != antennaFeedTimeMap.end())
4600 : {
4601 0 : if (abs(antennaFeedTimeIter->second - time(idx)) < 2*FLT_MIN)
4602 : {
4603 0 : duplicateIdx.push_back(idx);
4604 : }
4605 : else
4606 : {
4607 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4608 : }
4609 : }
4610 : else
4611 : {
4612 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4613 : }
4614 : }
4615 :
4616 0 : subtable.removeRow(Vector<rownr_t>(duplicateIdx.begin(),duplicateIdx.end()));
4617 :
4618 : }
4619 : else
4620 : {
4621 0 : if (subtabname == casacore::String("FEED"))
4622 : {
4623 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
4624 0 : << subtabname << " sub-table found but has no valid content" << LogIO::POST;
4625 : }
4626 : else
4627 : {
4628 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
4629 0 : << subtabname << " sub-table found but has no valid content" << LogIO::POST;
4630 : }
4631 : }
4632 : }
4633 : else
4634 : {
4635 0 : if (subtabname == casacore::String("FEED"))
4636 : {
4637 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
4638 0 : << subtabname << " sub-table not found" << LogIO::POST;
4639 : }
4640 : else
4641 : {
4642 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
4643 0 : << subtabname << " sub-table not found" << LogIO::POST;
4644 : }
4645 : }
4646 :
4647 0 : return;
4648 : }
4649 :
4650 : // -----------------------------------------------------------------------
4651 : //
4652 : // -----------------------------------------------------------------------
4653 0 : void MSTransformManager::getInputNumberOfChannels()
4654 : {
4655 : // Access spectral window sub-table
4656 0 : MSSpectralWindow spwTable = inputMs_p->spectralWindow();
4657 0 : auto nInputSpws = spwTable.nrow();
4658 0 : MSSpWindowColumns spwCols(spwTable);
4659 0 : ScalarColumn<Int> numChanCol = spwCols.numChan();
4660 :
4661 : // Get number of output channels per input spw
4662 0 : for(rownr_t spw_idx=0; spw_idx<nInputSpws; spw_idx++)
4663 : {
4664 0 : numOfInpChanMap_p[spw_idx] = numChanCol(spw_idx);
4665 : }
4666 :
4667 0 : return;
4668 : }
4669 :
4670 : // -----------------------------------------------------------------------
4671 : //
4672 : // -----------------------------------------------------------------------
4673 0 : void MSTransformManager::dropNonUniformWidthChannels()
4674 : {
4675 : // Access spectral window sub-table
4676 0 : MSSpectralWindow spwTable = outputMs_p->spectralWindow();
4677 0 : auto nInputSpws = spwTable.nrow();
4678 0 : MSSpWindowColumns spwCols(spwTable);
4679 0 : ArrayColumn<Double> chanFreqCol = spwCols.chanFreq();
4680 0 : ArrayColumn<Double> chanWidthCol = spwCols.chanWidth();
4681 0 : ArrayColumn<Double> effectiveBWCol = spwCols.effectiveBW();
4682 0 : ArrayColumn<Double> resolutionCol = spwCols.resolution();
4683 0 : ScalarColumn<Int> numChanCol = spwCols.numChan();
4684 0 : ScalarColumn<Double> totalBandwidthCol = spwCols.totalBandwidth();
4685 :
4686 : uInt nChans;
4687 : Int spwId;
4688 0 : for(rownr_t spw_idx=0; spw_idx<nInputSpws; spw_idx++)
4689 : {
4690 0 : nChans = numChanCol(spw_idx);
4691 0 : Vector<Double> widthVector = chanWidthCol(spw_idx);
4692 :
4693 0 : if (outputInputSPWIndexMap_p.size()>0)
4694 : {
4695 0 : spwId = outputInputSPWIndexMap_p[spw_idx];
4696 : }
4697 : else
4698 : {
4699 0 : spwId = spw_idx;
4700 : }
4701 :
4702 : // Skip this SPW in non-reindex mode
4703 0 : if ((!reindex_p) and (numOfSelChanMap_p.find(spwId) == numOfSelChanMap_p.end())) continue;
4704 :
4705 : //logger_p << dataHandler_p->getDroppedChannelsMap() << LogIO::POST;
4706 :
4707 0 : if (dataHandler_p->getDroppedChannelsMap().find(spwId) != dataHandler_p->getDroppedChannelsMap().end())
4708 : {
4709 0 : vector<Int>::iterator iter;
4710 0 : Double droppedWidth = 0;
4711 0 : vector<Int> &droppedChannels = dataHandler_p->getDroppedChannelsMap()[spwId];
4712 0 : for (iter = droppedChannels.begin(); iter != droppedChannels.end(); iter++)
4713 : {
4714 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
4715 : << "Not enough input channels to populate output channel n# "
4716 0 : << *iter << " from SPW " << spwId << "." << endl
4717 : << "The channel will be dropped in order to have an uniform grid."
4718 0 : << LogIO::POST;
4719 :
4720 0 : droppedWidth += widthVector(*iter);
4721 : }
4722 :
4723 : // Calculate final number of channels
4724 0 : uInt nChansFinal = nChans-droppedChannels.size();
4725 :
4726 0 : if (nChansFinal <= 0)
4727 : {
4728 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
4729 : << "Channel selection does not allow to produce any output channel with the requested width "
4730 0 : << LogIO::POST;
4731 :
4732 0 : throw AipsError("Channel selection does not allow to produce any output channel with the requested width ");
4733 : }
4734 :
4735 :
4736 :
4737 0 : numChanCol.put(spw_idx, nChansFinal);
4738 :
4739 : // Total BW has to be reduced to account for the dropped channels
4740 0 : totalBandwidthCol.put(spw_idx, totalBandwidthCol(spw_idx)-droppedWidth);
4741 :
4742 : // Get current vectors
4743 0 : Vector<Double> effectiveBWVector = effectiveBWCol(spw_idx);
4744 0 : Vector<Double> resolutionVector = resolutionCol(spw_idx);
4745 0 : Vector<Double> frequencyVector = chanFreqCol(spw_idx);
4746 :
4747 : // Declare new vectors
4748 0 : Vector<Double> newWidthVector(nChansFinal);
4749 0 : Vector<Double> newEffectiveBWVector(nChansFinal);
4750 0 : Vector<Double> newResolutionVector(nChansFinal);
4751 0 : Vector<Double> newFrequencyVector(nChansFinal);
4752 :
4753 : // Create a new frequency vector
4754 0 : uInt finalIdx = 0;
4755 0 : vector<Int>::iterator matchIdx;
4756 0 : for (uInt idx=0;idx < widthVector.size(); idx++)
4757 : {
4758 0 : matchIdx = find (droppedChannels.begin(), droppedChannels.end(), idx);
4759 0 : if (matchIdx == droppedChannels.end() )
4760 : {
4761 0 : newWidthVector(finalIdx) = widthVector(idx);
4762 0 : newEffectiveBWVector(finalIdx) = effectiveBWVector(idx);
4763 0 : newResolutionVector(finalIdx) = resolutionVector(idx);
4764 0 : newFrequencyVector(finalIdx) = frequencyVector(idx);
4765 0 : finalIdx ++;
4766 : }
4767 : }
4768 :
4769 : // Put new vectors in corresponding columns
4770 0 : chanWidthCol.put(spw_idx, newWidthVector);
4771 0 : effectiveBWCol.put(spw_idx, newEffectiveBWVector);
4772 0 : resolutionCol.put(spw_idx, newResolutionVector);
4773 0 : chanFreqCol.put(spw_idx, newFrequencyVector);
4774 :
4775 : // Update output number of channels
4776 0 : if (regridding_p) inputOutputSpwMap_p[spw_idx].second.resize(nChansFinal);
4777 : }
4778 : }
4779 :
4780 0 : return;
4781 : }
4782 :
4783 :
4784 : // -----------------------------------------------------------------------
4785 : //
4786 : // -----------------------------------------------------------------------
4787 0 : void MSTransformManager::getOutputNumberOfChannels()
4788 : {
4789 0 : if (regridding_p or combinespws_p)
4790 : {
4791 0 : map<uInt,uInt>::iterator iter;
4792 0 : for(iter = numOfSelChanMap_p.begin(); iter != numOfSelChanMap_p.end(); iter++)
4793 : {
4794 0 : if (freqbinMap_p.find(iter->first) == freqbinMap_p.end())
4795 : {
4796 : // When doing only re-gridding, maybe not all SPWs require pre-averaging
4797 0 : if (not combinespws_p)
4798 : {
4799 0 : freqbinMap_p[iter->first] = 1;
4800 : }
4801 : // When combining SPWs all of them get the same freqbin
4802 : else
4803 : {
4804 0 : freqbinMap_p[iter->first] = freqbinMap_p[0];
4805 : }
4806 : }
4807 : }
4808 : }
4809 :
4810 : // Access spectral window sub-table
4811 0 : MSSpectralWindow spwTable = outputMs_p->spectralWindow();
4812 0 : auto nInputSpws = spwTable.nrow();
4813 0 : MSSpWindowColumns spwCols(spwTable);
4814 0 : ScalarColumn<Int> numChanCol = spwCols.numChan();
4815 0 : ArrayColumn<Double> chanFreqCol = spwCols.chanFreq();
4816 :
4817 0 : if (combinespws_p)
4818 : {
4819 0 : map<uInt,uInt>::iterator iter;
4820 0 : for(iter = numOfSelChanMap_p.begin(); iter != numOfSelChanMap_p.end(); iter++)
4821 : {
4822 : // Note: This will truncate the result, but it is ok because we are dropping the last channel
4823 0 : numOfOutChanMap_p[iter->first] = numOfSelChanMap_p[iter->first] / freqbinMap_p[iter->first];
4824 : }
4825 : }
4826 : else
4827 : {
4828 : // Get number of output channels per input spw
4829 : Int spwId;
4830 0 : for(rownr_t spw_idx=0; spw_idx<nInputSpws; spw_idx++)
4831 : {
4832 0 : if (outputInputSPWIndexMap_p.size()>0)
4833 : {
4834 0 : spwId = outputInputSPWIndexMap_p[spw_idx];
4835 : }
4836 : else
4837 : {
4838 0 : spwId = spw_idx;
4839 : }
4840 :
4841 0 : numOfOutChanMap_p[spwId] = numChanCol(spw_idx);
4842 : }
4843 : }
4844 :
4845 0 : return;
4846 : }
4847 :
4848 : // -----------------------------------------------------------------------
4849 : //
4850 : // -----------------------------------------------------------------------
4851 0 : void MSTransformManager::calculateWeightAndSigmaFactors()
4852 : {
4853 0 : map<uInt,uInt>::iterator iter;
4854 0 : for(iter = numOfSelChanMap_p.begin(); iter != numOfSelChanMap_p.end(); iter++)
4855 : {
4856 0 : weightFactorMap_p[iter->first] = (Float)numOfSelChanMap_p[iter->first] /
4857 0 : (Float)numOfInpChanMap_p[iter->first];
4858 0 : sigmaFactorMap_p[iter->first] = 1./sqrt((Float)numOfSelChanMap_p[iter->first] /
4859 0 : (Float)numOfOutChanMap_p[iter->first]);
4860 : }
4861 :
4862 0 : return;
4863 : }
4864 :
4865 : // -----------------------------------------------------------------------
4866 : //
4867 : // -----------------------------------------------------------------------
4868 0 : void MSTransformManager::calculateNewWeightAndSigmaFactors()
4869 : {
4870 :
4871 0 : map<uInt, uInt>::iterator iter;
4872 0 : for (iter = numOfSelChanMap_p.begin(); iter != numOfSelChanMap_p.end(); iter++)
4873 : {
4874 : // Populateremaining SPWs of weight factor map
4875 0 : if (newWeightFactorMap_p.find(iter->first)== newWeightFactorMap_p.end())
4876 : {
4877 : // When doing only re-gridding, maybe not all SPWs require pre-averaging
4878 0 : if (not combinespws_p)
4879 : {
4880 0 : newWeightFactorMap_p[iter->first] = 1;
4881 : }
4882 : // When combining SPWs all of them get the same freqbin
4883 : else
4884 : {
4885 0 : newWeightFactorMap_p[iter->first] = newWeightFactorMap_p[0];
4886 : }
4887 : }
4888 :
4889 : // Populate sigma factor map
4890 0 : newSigmaFactorMap_p[iter->first] = 1 / sqrt(newWeightFactorMap_p[iter->first]);
4891 : }
4892 :
4893 0 : return;
4894 : }
4895 :
4896 : // -----------------------------------------------------------------------
4897 : // Method to check if flag category has to be filled
4898 : // -----------------------------------------------------------------------
4899 0 : void MSTransformManager::checkFillFlagCategory()
4900 : {
4901 0 : inputFlagCategoryAvailable_p = false;
4902 0 : if ( !selectedInputMsCols_p->flagCategory().isNull()
4903 0 : && selectedInputMsCols_p->flagCategory().isDefined(0)
4904 0 : && selectedInputMsCols_p->flagCategory()(0).shape() == 3)
4905 : {
4906 0 : inputFlagCategoryAvailable_p = true;
4907 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4908 0 : << "Optional column FLAG_CATEGORY found in input MS will be written to output MS" << LogIO::POST;
4909 : }
4910 :
4911 0 : return;
4912 : }
4913 :
4914 : // -----------------------------------------------------------------------
4915 : // Method to check if weight spectrum column has to be filled
4916 : // -----------------------------------------------------------------------
4917 0 : void MSTransformManager::checkFillWeightSpectrum()
4918 : {
4919 0 : inputWeightSpectrumAvailable_p = false;
4920 0 : if (!selectedInputMsCols_p->weightSpectrum().isNull() and
4921 0 : selectedInputMsCols_p->weightSpectrum().isDefined(0))
4922 : {
4923 0 : inputWeightSpectrumAvailable_p = true;
4924 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4925 0 : << "Optional column WEIGHT_SPECTRUM found in input MS will be written to output MS" << LogIO::POST;
4926 : }
4927 0 : }
4928 :
4929 : /**
4930 : * Early check for a potential issue that would prevent an MSTransform
4931 : * setup which looks in principle fine from running correctly. Ensures
4932 : * that we catch a current limitation in the underlying iterators /
4933 : * VI/VB2 framework whereby combinespws won't work when the number of
4934 : * channels is different for different SPWs.
4935 : *
4936 : * Requires that numOfInpChanMap_p be populated previously (in
4937 : * getInputNumberOfChannels()).
4938 : *
4939 : * @throws AipsError if combinespws is enabled and the input MS of the
4940 : * current configuration has different number of channels for
4941 : * different SPWs
4942 : */
4943 0 : void MSTransformManager::checkSPWChannelsKnownLimitation()
4944 : {
4945 0 : if (not combinespws_p)
4946 0 : return;
4947 :
4948 0 : auto nSpws = inputMs_p->spectralWindow().nrow();
4949 0 : if (1 >= nSpws or numOfInpChanMap_p.empty() or numOfSelChanMap_p.empty())
4950 0 : return;
4951 :
4952 0 : auto firstNum = numOfSelChanMap_p.begin()->second;
4953 : auto diff = std::find_if(numOfSelChanMap_p.begin(), numOfSelChanMap_p.end(),
4954 0 : [&firstNum](const std::pair<casacore::uInt,casacore::uInt> &other) {
4955 0 : return firstNum != other.second; });
4956 :
4957 :
4958 0 : if (numOfSelChanMap_p.end() != diff) {
4959 0 : auto otherNum = diff->second;
4960 : throw AipsError("Currently the option 'combinespws' is only supported when the number "
4961 : "of channels is the same for all the spw's selected. One of the SPWs "
4962 0 : "selected has " + std::to_string(firstNum) + " channels, but another "
4963 0 : "selected SPW has " + std::to_string(otherNum) + " channels.");
4964 : }
4965 : }
4966 :
4967 : /**
4968 : * Early check to issue a warning if the data was preaveraged
4969 : * by the correlator ans we are performing a further
4970 : * smoothing and average.
4971 : */
4972 0 : void MSTransformManager::checkCorrelatorPreaveraging()
4973 : {
4974 0 : std::string spwPreaveraged;
4975 0 : if (hanningSmooth_p || channelAverage_p)
4976 : {
4977 0 : auto spwTable = inputMs_p->spectralWindow();
4978 0 : MSSpWindowColumns spwColumns(spwTable);
4979 0 : if (spwTable.tableDesc().isColumn("SDM_WINDOW_FUNCTION") &&
4980 0 : spwTable.tableDesc().columnDescSet().isDefined("SDM_WINDOW_FUNCTION") &&
4981 0 : spwTable.tableDesc().isColumn("SDM_NUM_BIN") &&
4982 0 : spwTable.tableDesc().columnDescSet().isDefined("SDM_NUM_BIN"))
4983 : {
4984 0 : auto nrows = spwColumns.nrow();
4985 0 : auto effBWCol = spwColumns.effectiveBW();
4986 0 : auto chanWidthCol = spwColumns.chanWidth();
4987 0 : ScalarColumn<String> windowFunctionCol(spwTable, "SDM_WINDOW_FUNCTION");
4988 0 : ScalarColumn<Int> numBinCol(spwTable, "SDM_NUM_BIN");
4989 0 : for (size_t spwIdx = 0; spwIdx < nrows; spwIdx++)
4990 : {
4991 0 : auto numBin = numBinCol(spwIdx);
4992 0 : auto windowFunction = windowFunctionCol(spwIdx);
4993 0 : if(windowFunction != "UNKNOWN" && numBin != 1)
4994 0 : spwPreaveraged += std::to_string(spwIdx)+" ";
4995 : }
4996 : }
4997 : }
4998 :
4999 0 : if(spwPreaveraged != "")
5000 0 : logger_p << LogIO::WARN<<LogOrigin("MSTransformManager", __func__) <<
5001 : "The data has already been preaveraged by the correlator but "
5002 : "further smoothing or averaging has been requested. "
5003 0 : "Preaveraged SPWs are: "<<spwPreaveraged<<LogIO::POST;
5004 0 : }
5005 :
5006 : // -----------------------------------------------------------------------
5007 : //
5008 : // -----------------------------------------------------------------------
5009 0 : void MSTransformManager::checkDataColumnsAvailable()
5010 : {
5011 0 : dataColumnAvailable_p = false;
5012 0 : correctedDataColumnAvailable_p = false;
5013 0 : modelDataColumnAvailable_p = false;
5014 :
5015 :
5016 0 : floatDataColumnAvailable_p = false;
5017 0 : lagDataColumnAvailable_p = false;
5018 :
5019 :
5020 : // DATA
5021 0 : if (inputMs_p->tableDesc().isColumn(MS::columnName(MS::DATA)))
5022 : {
5023 0 : dataColumnAvailable_p = true;
5024 : }
5025 :
5026 :
5027 : // CORRECTED_DATA already exists in the input MS
5028 0 : if (inputMs_p->tableDesc().isColumn(MS::columnName(MS::CORRECTED_DATA)))
5029 : {
5030 0 : correctedDataColumnAvailable_p = true;
5031 : }
5032 : // CORRECTED_DATA does not exist but there is a calibration parameter set available
5033 0 : else if (calibrate_p and (makeVirtualCorrectedColReal_p or bufferMode_p))
5034 : {
5035 0 : correctedDataColumnAvailable_p = true;
5036 : }
5037 : // There is no calibration parameter set available
5038 : else
5039 : {
5040 : // TODO: Inform that virtual CORRECTED_DATA is not available
5041 :
5042 : // Unset makeVirtualModelColReal_p as virtual CORRECTED col. is not available
5043 0 : makeVirtualCorrectedColReal_p = false;
5044 : }
5045 :
5046 : // FLOAT_DATA
5047 0 : if (inputMs_p->tableDesc().isColumn(MS::columnName(MS::FLOAT_DATA)))
5048 : {
5049 0 : floatDataColumnAvailable_p = true;
5050 : }
5051 :
5052 :
5053 : // MODEL_DATA already exists in the input MS
5054 0 : if (inputMs_p->tableDesc().isColumn(MS::columnName(MS::MODEL_DATA)))
5055 : {
5056 0 : modelDataColumnAvailable_p = true;
5057 : }
5058 : // MODEL_DATA does not exist but there is a model available in the SOURCE sub-table
5059 : // MODEL_DATA should not be made real if the user does not specify it implicitly
5060 0 : else if (inputMs_p->source().isColumn(MSSource::SOURCE_MODEL) and makeVirtualModelColReal_p)
5061 : {
5062 0 : modelDataColumnAvailable_p = true;
5063 : }
5064 : // CAS-7390: Provide default MODEL_DATA in buffer mode
5065 0 : else if (bufferMode_p and not floatDataColumnAvailable_p) // MODEL is not defined for SD data
5066 : {
5067 0 : makeVirtualModelColReal_p = true;
5068 0 : modelDataColumnAvailable_p = true;
5069 : }
5070 : // There is no model available in the SOURCE sub-table
5071 : else
5072 : {
5073 0 : modelDataColumnAvailable_p = false;
5074 :
5075 : // Inform that virtual MODEL_DATA is not available
5076 0 : if (makeVirtualModelColReal_p)
5077 : {
5078 0 : if (bufferMode_p)
5079 : {
5080 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
5081 : << "Requested to make virtual MODEL_DATA column available from MSTransformBuffer but"
5082 : << "SOURCE_MODEL column is not present in SOURCE sub-table"
5083 0 : << LogIO::POST;
5084 : }
5085 : else
5086 : {
5087 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
5088 : << "Requested to make virtual MODEL_DATA column real but "
5089 : << "SOURCE_MODEL column is not present in SOURCE sub-table"
5090 0 : << LogIO::POST;
5091 : }
5092 : }
5093 :
5094 : // Unset makeVirtualModelColReal_p as virtual MODEL col. is not available
5095 0 : makeVirtualModelColReal_p = false;
5096 : }
5097 :
5098 :
5099 : // LAG_DATA
5100 0 : if (inputMs_p->tableDesc().isColumn(MS::columnName(MS::LAG_DATA)))
5101 : {
5102 0 : lagDataColumnAvailable_p = true;
5103 : }
5104 :
5105 0 : return;
5106 : }
5107 :
5108 : // -----------------------------------------------------------------------
5109 : // Method to check which data columns have to be filled
5110 : // -----------------------------------------------------------------------
5111 0 : void MSTransformManager::checkDataColumnsToFill()
5112 : {
5113 0 : dataColMap_p.clear();
5114 0 : bool mainColSet=false;
5115 0 : timeAvgOptions_p = vi::AveragingOptions(vi::AveragingOptions::Nothing);
5116 :
5117 0 : if (datacolumn_p.contains("ALL"))
5118 : {
5119 0 : if (dataColumnAvailable_p)
5120 : {
5121 0 : if (!mainColSet)
5122 : {
5123 0 : mainColumn_p = MS::DATA;
5124 0 : mainColSet = true;
5125 : }
5126 0 : dataColMap_p[MS::DATA] = MS::DATA;
5127 0 : colCheckInfo(MS::columnName(MS::DATA),MS::columnName(dataColMap_p[MS::DATA]));
5128 :
5129 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageObserved;
5130 0 : timeAvgOptions_p |= vi::AveragingOptions::ObservedFlagWeightAvgFromSIGMA;
5131 : }
5132 :
5133 0 : if (correctedDataColumnAvailable_p)
5134 : {
5135 0 : if (!mainColSet)
5136 : {
5137 0 : mainColumn_p = MS::CORRECTED_DATA;
5138 0 : mainColSet = true;
5139 : }
5140 0 : dataColMap_p[MS::CORRECTED_DATA] = MS::CORRECTED_DATA;
5141 0 : colCheckInfo(MS::columnName(MS::CORRECTED_DATA),MS::columnName(dataColMap_p[MS::CORRECTED_DATA]));
5142 :
5143 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageCorrected;
5144 0 : timeAvgOptions_p |= vi::AveragingOptions::CorrectedFlagWeightAvgFromWEIGHT;
5145 : }
5146 0 : if (dataColumnAvailable_p && correctedDataColumnAvailable_p)
5147 0 : bothDataColumnsAreOutput_p = true;
5148 :
5149 :
5150 0 : if (modelDataColumnAvailable_p)
5151 : {
5152 0 : if (!mainColSet)
5153 : {
5154 0 : mainColumn_p = MS::MODEL_DATA;
5155 0 : mainColSet = true;
5156 : }
5157 0 : dataColMap_p[MS::MODEL_DATA] = MS::MODEL_DATA;
5158 0 : colCheckInfo(MS::columnName(MS::MODEL_DATA),MS::columnName(dataColMap_p[MS::MODEL_DATA]));
5159 :
5160 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageModel;
5161 :
5162 0 : if (correctedDataColumnAvailable_p)
5163 : {
5164 0 : timeAvgOptions_p |= vi::AveragingOptions::ModelFlagWeightAvgFromWEIGHT;
5165 : }
5166 0 : else if (dataColumnAvailable_p)
5167 : {
5168 0 : timeAvgOptions_p |= vi::AveragingOptions::ModelFlagWeightAvgFromSIGMA;
5169 : }
5170 : else
5171 : {
5172 0 : timeAvgOptions_p |= vi::AveragingOptions::ModelPlainAvg;
5173 : }
5174 : }
5175 :
5176 0 : if (floatDataColumnAvailable_p)
5177 : {
5178 0 : if (!mainColSet)
5179 : {
5180 0 : mainColumn_p = MS::FLOAT_DATA;
5181 0 : mainColSet = true;
5182 : }
5183 0 : dataColMap_p[MS::FLOAT_DATA] = MS::FLOAT_DATA;
5184 0 : colCheckInfo(MS::columnName(MS::FLOAT_DATA),MS::columnName(dataColMap_p[MS::FLOAT_DATA]));
5185 :
5186 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageFloat;
5187 : }
5188 :
5189 0 : if (lagDataColumnAvailable_p)
5190 : {
5191 0 : if (!mainColSet)
5192 : {
5193 0 : mainColumn_p = MS::LAG_DATA;
5194 0 : mainColSet = true;
5195 : }
5196 0 : dataColMap_p[MS::LAG_DATA] = MS::LAG_DATA;
5197 0 : colCheckInfo(MS::columnName(MS::LAG_DATA),MS::columnName(dataColMap_p[MS::LAG_DATA]));
5198 :
5199 : // TODO: LAG_DATA is not yet supported by TVI
5200 : // timeAvgOptions_p |= vi::AveragingOptions::AverageLagData;
5201 : }
5202 : }
5203 0 : else if (datacolumn_p.contains("DATA,MODEL,CORRECTED"))
5204 : {
5205 0 : if (dataColumnAvailable_p)
5206 : {
5207 0 : if (!mainColSet)
5208 : {
5209 0 : mainColumn_p = MS::DATA;
5210 0 : mainColSet = true;
5211 : }
5212 0 : dataColMap_p[MS::DATA] = MS::DATA;
5213 0 : colCheckInfo(MS::columnName(MS::DATA),MS::columnName(dataColMap_p[MS::DATA]));
5214 :
5215 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageObserved;
5216 0 : timeAvgOptions_p |= vi::AveragingOptions::ObservedFlagWeightAvgFromSIGMA;
5217 : }
5218 :
5219 0 : if (correctedDataColumnAvailable_p)
5220 : {
5221 0 : if (!mainColSet)
5222 : {
5223 0 : mainColumn_p = MS::CORRECTED_DATA;
5224 0 : mainColSet = true;
5225 : }
5226 0 : dataColMap_p[MS::CORRECTED_DATA] = MS::CORRECTED_DATA;
5227 0 : colCheckInfo(MS::columnName(MS::CORRECTED_DATA),MS::columnName(dataColMap_p[MS::CORRECTED_DATA]));
5228 :
5229 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageCorrected;
5230 0 : timeAvgOptions_p |= vi::AveragingOptions::CorrectedFlagWeightAvgFromWEIGHT;
5231 : }
5232 :
5233 0 : if (dataColumnAvailable_p && correctedDataColumnAvailable_p)
5234 0 : bothDataColumnsAreOutput_p = true;
5235 0 : if (modelDataColumnAvailable_p)
5236 : {
5237 0 : if (!mainColSet)
5238 : {
5239 0 : mainColumn_p = MS::MODEL_DATA;
5240 0 : mainColSet = true;
5241 : }
5242 0 : dataColMap_p[MS::MODEL_DATA] = MS::MODEL_DATA;
5243 0 : colCheckInfo(MS::columnName(MS::MODEL_DATA),MS::columnName(dataColMap_p[MS::MODEL_DATA]));
5244 :
5245 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageModel;
5246 :
5247 0 : if (correctedDataColumnAvailable_p)
5248 : {
5249 0 : timeAvgOptions_p |= vi::AveragingOptions::ModelFlagWeightAvgFromWEIGHT;
5250 : }
5251 0 : else if (dataColumnAvailable_p)
5252 : {
5253 0 : timeAvgOptions_p |= vi::AveragingOptions::ModelFlagWeightAvgFromSIGMA;
5254 : }
5255 : else
5256 : {
5257 0 : timeAvgOptions_p |= vi::AveragingOptions::ModelPlainAvg;
5258 : }
5259 : }
5260 : }
5261 0 : else if (datacolumn_p.contains("FLOAT_DATA,DATA"))
5262 : {
5263 :
5264 0 : if (dataColumnAvailable_p)
5265 : {
5266 0 : if (!mainColSet)
5267 : {
5268 0 : mainColumn_p = MS::DATA;
5269 0 : mainColSet = true;
5270 : }
5271 0 : dataColMap_p[MS::DATA] = MS::DATA;
5272 0 : colCheckInfo(MS::columnName(MS::DATA),MS::columnName(dataColMap_p[MS::DATA]));
5273 :
5274 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageObserved;
5275 0 : timeAvgOptions_p |= vi::AveragingOptions::ObservedFlagWeightAvgFromSIGMA;
5276 : }
5277 : else
5278 : {
5279 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5280 0 : "DATA column requested but not available in input MS "<< LogIO::POST;
5281 : }
5282 :
5283 0 : if (floatDataColumnAvailable_p)
5284 : {
5285 0 : if (!mainColSet)
5286 : {
5287 0 : mainColumn_p = MS::FLOAT_DATA;
5288 0 : mainColSet = true;
5289 : }
5290 0 : dataColMap_p[MS::FLOAT_DATA] = MS::FLOAT_DATA;
5291 0 : colCheckInfo(MS::columnName(MS::FLOAT_DATA),MS::columnName(dataColMap_p[MS::FLOAT_DATA]));
5292 :
5293 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageFloat;
5294 : }
5295 : else
5296 : {
5297 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5298 0 : "FLOAT_DATA column requested but not available in input MS "<< LogIO::POST;
5299 : }
5300 : }
5301 0 : else if (datacolumn_p.contains("FLOAT_DATA"))
5302 : {
5303 0 : if (floatDataColumnAvailable_p)
5304 : {
5305 0 : if (!mainColSet)
5306 : {
5307 0 : mainColumn_p = MS::FLOAT_DATA;
5308 0 : mainColSet = true;
5309 : }
5310 0 : dataColMap_p[MS::FLOAT_DATA] = MS::FLOAT_DATA;
5311 0 : colCheckInfo(MS::columnName(MS::FLOAT_DATA),MS::columnName(dataColMap_p[MS::FLOAT_DATA]));
5312 :
5313 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageFloat;
5314 : }
5315 : else
5316 : {
5317 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5318 0 : "FLOAT_DATA column requested but not available in input MS "<< LogIO::POST;
5319 : }
5320 : }
5321 0 : else if (datacolumn_p.contains("LAG_DATA,DATA"))
5322 : {
5323 0 : if (dataColumnAvailable_p)
5324 : {
5325 0 : if (!mainColSet)
5326 : {
5327 0 : mainColumn_p = MS::DATA;
5328 0 : mainColSet = true;
5329 : }
5330 0 : dataColMap_p[MS::DATA] = MS::DATA;
5331 0 : colCheckInfo(MS::columnName(MS::DATA),MS::columnName(dataColMap_p[MS::DATA]));
5332 :
5333 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageObserved;
5334 0 : timeAvgOptions_p |= vi::AveragingOptions::ObservedFlagWeightAvgFromSIGMA;
5335 : }
5336 : else
5337 : {
5338 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5339 0 : "DATA column requested but not available in input MS "<< LogIO::POST;
5340 : }
5341 :
5342 0 : if (lagDataColumnAvailable_p)
5343 : {
5344 0 : if (!mainColSet)
5345 : {
5346 0 : mainColumn_p = MS::LAG_DATA;
5347 0 : mainColSet = true;
5348 : }
5349 0 : dataColMap_p[MS::LAG_DATA] = MS::LAG_DATA;
5350 0 : colCheckInfo(MS::columnName(MS::LAG_DATA),MS::columnName(dataColMap_p[MS::LAG_DATA]));
5351 :
5352 : // TODO: LAG_DATA is not yet supported by TVI
5353 : // timeAvgOptions_p |= vi::AveragingOptions::AverageLagData;
5354 : }
5355 : else
5356 : {
5357 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5358 0 : "LAG_DATA column requested but not available in input MS "<< LogIO::POST;
5359 : }
5360 : }
5361 0 : else if (datacolumn_p.contains("LAG_DATA"))
5362 : {
5363 0 : if (lagDataColumnAvailable_p)
5364 : {
5365 0 : if (!mainColSet)
5366 : {
5367 0 : mainColumn_p = MS::LAG_DATA;
5368 0 : mainColSet = true;
5369 : }
5370 0 : dataColMap_p[MS::LAG_DATA] = MS::LAG_DATA;
5371 0 : colCheckInfo(MS::columnName(MS::LAG_DATA),MS::columnName(dataColMap_p[MS::LAG_DATA]));
5372 :
5373 : // TODO: LAG_DATA is not yet supported by TVI
5374 : // timeAvgOptions_p |= vi::AveragingOptions::AverageLagData;
5375 : }
5376 : else
5377 : {
5378 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5379 0 : "LAG_DATA column requested but not available in input MS "<< LogIO::POST;
5380 : }
5381 : }
5382 0 : else if (datacolumn_p.contains("DATA"))
5383 : {
5384 0 : if (dataColumnAvailable_p)
5385 : {
5386 0 : if (!mainColSet)
5387 : {
5388 0 : mainColumn_p = MS::DATA;
5389 0 : mainColSet = true;
5390 : }
5391 0 : dataColMap_p[MS::DATA] = MS::DATA;
5392 0 : colCheckInfo(MS::columnName(MS::DATA),MS::columnName(dataColMap_p[MS::DATA]));
5393 :
5394 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageObserved;
5395 0 : timeAvgOptions_p |= vi::AveragingOptions::ObservedFlagWeightAvgFromSIGMA;
5396 : }
5397 : else
5398 : {
5399 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5400 0 : "DATA column requested but not available in input MS "<< LogIO::POST;
5401 : }
5402 : }
5403 0 : else if (datacolumn_p.contains("CORRECTED"))
5404 : {
5405 0 : if (correctedDataColumnAvailable_p)
5406 : {
5407 0 : if (!mainColSet)
5408 : {
5409 0 : mainColumn_p = MS::CORRECTED_DATA;
5410 0 : mainColSet = true;
5411 : }
5412 0 : dataColMap_p[MS::CORRECTED_DATA] = MS::DATA;
5413 0 : correctedToData_p = true;
5414 0 : colCheckInfo(MS::columnName(MS::CORRECTED_DATA),MS::columnName(dataColMap_p[MS::CORRECTED_DATA]));
5415 :
5416 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageCorrected;
5417 0 : timeAvgOptions_p |= vi::AveragingOptions::CorrectedFlagWeightAvgFromWEIGHT;
5418 : }
5419 : else
5420 : {
5421 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5422 0 : "CORRECTED_DATA column requested but not available in input MS "<< LogIO::POST;
5423 : }
5424 : }
5425 0 : else if (datacolumn_p.contains("MODEL"))
5426 : {
5427 :
5428 0 : if (modelDataColumnAvailable_p)
5429 : {
5430 0 : if (!mainColSet)
5431 : {
5432 0 : mainColumn_p = MS::MODEL_DATA;
5433 0 : mainColSet = true;
5434 : }
5435 :
5436 0 : dataColMap_p[MS::MODEL_DATA] = MS::DATA;
5437 0 : colCheckInfo(MS::columnName(MS::MODEL_DATA),MS::columnName(dataColMap_p[MS::MODEL_DATA]));
5438 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageModel;
5439 0 : timeAvgOptions_p |= vi::AveragingOptions::ModelPlainAvg;
5440 : }
5441 : else
5442 : {
5443 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5444 0 : "MODEL_DATA column requested but not available in input MS "<< LogIO::POST;
5445 : }
5446 : }
5447 0 : else if (datacolumn_p.contains("NONE") and userBufferMode_p)
5448 : {
5449 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
5450 : << "No datacolumn selected in buffer mode"
5451 0 : << LogIO::POST;
5452 : }
5453 : else
5454 : {
5455 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
5456 0 : << "Requested data column " << datacolumn_p
5457 : << " is not supported, possible choices are ALL,DATA,CORRECTED,MODEL,FLOAT_DATA,LAG_DATA"
5458 0 : << LogIO::POST;
5459 : }
5460 :
5461 0 : if (produceModel_p) {
5462 0 : const auto colname = (MS::DATA == mainColumn_p) ? "DATA" : "CORRECTED_DATA";
5463 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5464 : << "Will produce a MODEL_DATA column in the output MS, "
5465 : << "with the fit calculated for input " << colname
5466 0 : << LogIO::POST;
5467 0 : dataColMap_p[MS::MODEL_DATA] = mainColumn_p;
5468 : }
5469 :
5470 : // Add shortcuts to be used in the context of WeightSpectrum related transformations
5471 0 : dataColMap::iterator iter;
5472 :
5473 : // Check if we are doing DATA
5474 0 : iter = dataColMap_p.find(MS::DATA);
5475 0 : if (iter != dataColMap_p.end()) doingData_p = true;
5476 :
5477 : // Check if we are doing CORRECTED_DATA
5478 0 : iter = dataColMap_p.find(MS::CORRECTED_DATA);
5479 0 : if (iter != dataColMap_p.end()) doingCorrected_p = true;
5480 :
5481 : // Check if we are doing MODEL_DATA
5482 0 : iter = dataColMap_p.find(MS::MODEL_DATA);
5483 0 : if (iter != dataColMap_p.end()) doingModel_p = true;
5484 :
5485 0 : return;
5486 : }
5487 :
5488 :
5489 : // -----------------------------------------------------------------------
5490 : //
5491 : // -----------------------------------------------------------------------
5492 0 : void MSTransformManager::colCheckInfo(const String& inputColName, const String& outputColName)
5493 : {
5494 0 : if (inputMs_p->tableDesc().isColumn(inputColName))
5495 : {
5496 0 : if (not bufferMode_p)
5497 : {
5498 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5499 : << "Adding " << outputColName << " column to output MS from input " << inputColName<< " column"
5500 0 : << LogIO::POST;
5501 : }
5502 : else
5503 : {
5504 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5505 : << inputColName << " column present in input MS will be available from MSTransformBuffer"
5506 0 : << LogIO::POST;
5507 : }
5508 : }
5509 : else
5510 : {
5511 0 : if (not bufferMode_p)
5512 : {
5513 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5514 : << "Adding " << outputColName << " column to output MS from input virtual " << inputColName<< " column"
5515 0 : << LogIO::POST;
5516 : }
5517 : else
5518 : {
5519 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5520 : << "Virtual " << inputColName << " column present in input MS will be available from MSTransformBuffer"
5521 0 : << LogIO::POST;
5522 : }
5523 : }
5524 :
5525 0 : return;
5526 : }
5527 :
5528 :
5529 : // -----------------------------------------------------------------------
5530 : // Method to determine sort columns order
5531 : // -----------------------------------------------------------------------
5532 0 : void MSTransformManager::setIterationApproach()
5533 : {
5534 0 : uInt nSortColumns = 7;
5535 :
5536 0 : if (timespan_p.contains("scan")) nSortColumns -= 1;
5537 0 : if (timespan_p.contains("state")) nSortColumns -= 1;
5538 0 : if (timespan_p.contains("field")) nSortColumns -= 1;
5539 0 : if ((combinespws_p) || (spwAverage_p)) nSortColumns -= 1;
5540 :
5541 0 : sortColumns_p = Block<Int>(nSortColumns);
5542 0 : uInt sortColumnIndex = 0;
5543 :
5544 0 : sortColumns_p[0] = MS::OBSERVATION_ID;
5545 0 : sortColumnIndex += 1;
5546 :
5547 0 : sortColumns_p[1] = MS::ARRAY_ID;
5548 0 : sortColumnIndex += 1;
5549 :
5550 0 : if (!timespan_p.contains("scan"))
5551 : {
5552 0 : sortColumns_p[sortColumnIndex] = MS::SCAN_NUMBER;
5553 0 : sortColumnIndex += 1;
5554 : }
5555 : else
5556 : {
5557 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5558 0 : << "Combining data through scans for time average " << LogIO::POST;
5559 : }
5560 :
5561 0 : if (!timespan_p.contains("state"))
5562 : {
5563 0 : sortColumns_p[sortColumnIndex] = MS::STATE_ID;
5564 0 : sortColumnIndex += 1;
5565 : }
5566 : else
5567 : {
5568 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5569 0 : << "Combining data through state for time average" << LogIO::POST;
5570 : }
5571 :
5572 0 : if (!timespan_p.contains("field"))
5573 : {
5574 0 : sortColumns_p[sortColumnIndex] = MS::FIELD_ID;
5575 0 : sortColumnIndex += 1;
5576 : }
5577 : else
5578 : {
5579 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5580 0 : << "Combining data through field time average" << LogIO::POST;
5581 : }
5582 :
5583 0 : if ((!combinespws_p) && (!spwAverage_p))
5584 : {
5585 0 : sortColumns_p[sortColumnIndex] = MS::DATA_DESC_ID;
5586 0 : sortColumnIndex += 1;
5587 : }
5588 : else
5589 : {
5590 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5591 0 : << "Combining data from selected spectral windows" << LogIO::POST;
5592 : }
5593 :
5594 0 : sortColumns_p[sortColumnIndex] = MS::TIME;
5595 :
5596 0 : return;
5597 : }
5598 :
5599 :
5600 : // -----------------------------------------------------------------------
5601 : // Method to generate the initial iterator
5602 : // -----------------------------------------------------------------------
5603 0 : void MSTransformManager::generateIterator()
5604 : {
5605 0 : bool isWritable = false;
5606 0 : if (interactive_p) isWritable = true;
5607 :
5608 : // Prepare time average parameters (common for all cases)
5609 0 : std::shared_ptr<vi::AveragingParameters> timeavgParams = nullptr;
5610 0 : if (timeAverage_p)
5611 : {
5612 0 : if (maxuvwdistance_p > 0)
5613 : {
5614 0 : timeAvgOptions_p |= vi::AveragingOptions::BaselineDependentAveraging;
5615 : }
5616 :
5617 : timeavgParams = std::make_shared<vi::AveragingParameters>
5618 0 : (timeBin_p, .0, vi::SortColumns(sortColumns_p, false),
5619 0 : timeAvgOptions_p, maxuvwdistance_p, nullptr, isWritable, dx_p, dy_p);
5620 : }
5621 :
5622 : // Calibrating VI
5623 0 : if (uvcontsub_p)
5624 : {
5625 : // First determine number of layers
5626 0 : uInt nTVIs = 1;
5627 0 : if (timeAverage_p) nTVIs++;
5628 0 : if (uvcontsub_p) nTVIs++;
5629 :
5630 : // Init vector of TVI factories and populate it
5631 0 : uInt TVIFactoryIdx = 0;
5632 0 : Vector<vi::ViiLayerFactory*> TVIFactories(nTVIs);
5633 :
5634 : // Data layer
5635 0 : vi::IteratingParameters ipar(timeBin_p,vi::SortColumns(sortColumns_p, false));
5636 0 : vi::VisIterImpl2LayerFactory dataLayerTVIFactory(selectedInputMs_p,ipar,isWritable);
5637 0 : TVIFactories[TVIFactoryIdx]=&dataLayerTVIFactory;
5638 0 : TVIFactoryIdx++;
5639 :
5640 : // Time avg. layer
5641 0 : std::unique_ptr<vi::AveragingVi2LayerFactory> timeAverageTVIFactory;
5642 0 : if (timeAverage_p)
5643 : {
5644 0 : timeAverageTVIFactory.reset(new vi::AveragingVi2LayerFactory(*timeavgParams));
5645 0 : TVIFactories[TVIFactoryIdx]=timeAverageTVIFactory.get();
5646 0 : TVIFactoryIdx++;
5647 : }
5648 :
5649 : // UVContSub layer
5650 0 : std::unique_ptr<vi::UVContSubTVILayerFactory> uvContSubTVIFactory;
5651 0 : if (uvcontsub_p)
5652 : {
5653 : // needed for warning to prevent confusion with old uvcontsub!
5654 0 : uvcontsubRec_p.define("allowed_spws", spwSelection_p);
5655 0 : uvContSubTVIFactory.reset(new vi::UVContSubTVILayerFactory (uvcontsubRec_p));
5656 0 : TVIFactories[TVIFactoryIdx]=uvContSubTVIFactory.get();
5657 0 : TVIFactoryIdx++;
5658 : }
5659 :
5660 0 : visibilityIterator_p = new vi::VisibilityIterator2 (TVIFactories);
5661 :
5662 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5663 0 : << "TVI chain is " << visibilityIterator_p->ViiType() << LogIO::POST;
5664 : }
5665 0 : else if (calibrate_p || scalarAverage_p)
5666 : {
5667 : try
5668 : {
5669 : // Isolate iteration parameters
5670 0 : vi::IteratingParameters iterpar;
5671 0 : if (scalarAverage_p)
5672 0 : iterpar = vi::IteratingParameters(timeBin_p,vi::SortColumns(sortColumns_p, false));
5673 : else
5674 0 : iterpar = vi::IteratingParameters(0,vi::SortColumns(sortColumns_p, false));
5675 :
5676 : // By callib String
5677 0 : if (callib_p.length() > 0)
5678 : {
5679 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager",__FUNCTION__)
5680 : << "OTF calibration activated, using calibration file spec to generate iterator"
5681 0 : << LogIO::POST;
5682 :
5683 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::LayeredVi2Factory(selectedInputMs_p, &iterpar,callib_p, timeavgParams.get()));
5684 : }
5685 : // By callib Record
5686 0 : else if (callibRec_p.nfields() > 0)
5687 : {
5688 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager",__FUNCTION__)
5689 : << "OTF calibration activated, using calibration record spec to generate iterator"
5690 0 : << LogIO::POST;
5691 :
5692 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::LayeredVi2Factory(selectedInputMs_p, &iterpar,callibRec_p, timeavgParams.get()));
5693 : }
5694 : else // scalar
5695 : {
5696 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::LayeredVi2Factory(selectedInputMs_p, &iterpar));
5697 : }
5698 : }
5699 0 : catch (MSSelectionError x)
5700 : {
5701 0 : delete visibilityIterator_p;
5702 :
5703 0 : correctedDataColumnAvailable_p = false;
5704 0 : checkDataColumnsToFill();
5705 :
5706 : // Averaging VI
5707 0 : if (timeAverage_p && !tviphaseshift_p)
5708 : {
5709 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::AveragingVi2Factory(*timeavgParams, selectedInputMs_p));
5710 : }
5711 : // Polarization Averaging VI
5712 0 : else if (polAverage_p) {
5713 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::PolAverageVi2Factory(polAverageConfig_p, selectedInputMs_p,
5714 0 : vi::SortColumns(sortColumns_p, false), timeBin_p, isWritable));
5715 : }
5716 : // Pointings Interpolator VI
5717 0 : else if (pointingsInterpolation_p) {
5718 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::PointingInterpolationVi2Factory(pointingsInterpolationConfig_p, selectedInputMs_p,
5719 0 : vi::SortColumns(sortColumns_p, false), timeBin_p, isWritable));
5720 : }
5721 : // CAS-12706 To run phase shift via a TVI which has
5722 : // support for shifting across large offset/angles
5723 0 : else if (tviphaseshift_p) {
5724 :
5725 : // First determine number of layers
5726 0 : uInt nTVIs = (timeAverage_p ? 3 : 2);
5727 :
5728 : // Init vector of TVI factories and populate it
5729 0 : uInt TVIFactoryIdx = 0;
5730 0 : Vector<vi::ViiLayerFactory*> TVIFactories(nTVIs);
5731 :
5732 : // Data layer
5733 0 : vi::IteratingParameters ipar(timeBin_p,vi::SortColumns(sortColumns_p, false));
5734 0 : vi::VisIterImpl2LayerFactory dataLayerTVIFactory(selectedInputMs_p,ipar,isWritable);
5735 0 : TVIFactories[TVIFactoryIdx++]=&dataLayerTVIFactory;
5736 :
5737 : // Time avg. layer
5738 0 : std::unique_ptr<vi::AveragingVi2LayerFactory> timeAverageTVIFactory;
5739 0 : if (timeAverage_p)
5740 : {
5741 0 : timeAverageTVIFactory.reset(new vi::AveragingVi2LayerFactory(*timeavgParams));
5742 0 : TVIFactories[TVIFactoryIdx++]=timeAverageTVIFactory.get();
5743 : }
5744 :
5745 : // Phaseshift layer
5746 0 : vi::PhaseShiftingTVILayerFactory phaseShiftingTVILayerFactory(tviphaseshiftConfig_p);
5747 0 : TVIFactories[TVIFactoryIdx]=&phaseShiftingTVILayerFactory;
5748 :
5749 0 : visibilityIterator_p = new vi::VisibilityIterator2 (TVIFactories);
5750 : }
5751 : // Plain VI
5752 : else
5753 : {
5754 0 : visibilityIterator_p = new vi::VisibilityIterator2(*selectedInputMs_p,vi::SortColumns(sortColumns_p, false),
5755 0 : isWritable, NULL, timeBin_p);
5756 : }
5757 : }
5758 0 : catch (AipsError x)
5759 : {
5760 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager",__FUNCTION__)
5761 : << "Error initializing calibration VI: " << x.getMesg()
5762 0 : << LogIO::POST;
5763 0 : throw(x);
5764 0 : }
5765 : }
5766 : // Averaging VI
5767 0 : else if (timeAverage_p && !tviphaseshift_p)
5768 : {
5769 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::AveragingVi2Factory(*timeavgParams, selectedInputMs_p));
5770 : }
5771 : // Polarization Averaging VI
5772 0 : else if (polAverage_p) {
5773 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::PolAverageVi2Factory(polAverageConfig_p, selectedInputMs_p,
5774 0 : vi::SortColumns(sortColumns_p, false), timeBin_p, isWritable));
5775 : }
5776 : // VI interpolating pointing directions
5777 0 : else if (pointingsInterpolation_p) {
5778 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::PointingInterpolationVi2Factory(pointingsInterpolationConfig_p, selectedInputMs_p,
5779 0 : vi::SortColumns(sortColumns_p, false), timeBin_p, isWritable));
5780 : }
5781 : // CAS-12706 To run phase shift via a TVI which has
5782 : // support for shifting across large offset/angles
5783 0 : else if (tviphaseshift_p) {
5784 :
5785 : // First determine number of layers
5786 0 : uInt nTVIs = (timeAverage_p ? 3 : 2);
5787 :
5788 : // Init vector of TVI factories and populate it
5789 0 : uInt TVIFactoryIdx = 0;
5790 0 : Vector<vi::ViiLayerFactory*> TVIFactories(nTVIs);
5791 :
5792 : // Data layer
5793 0 : vi::IteratingParameters ipar(timeBin_p,vi::SortColumns(sortColumns_p, false));
5794 0 : vi::VisIterImpl2LayerFactory dataLayerTVIFactory(selectedInputMs_p,ipar,isWritable);
5795 0 : TVIFactories[TVIFactoryIdx++]=&dataLayerTVIFactory;
5796 :
5797 : // Time avg. layer
5798 0 : std::unique_ptr<vi::AveragingVi2LayerFactory> timeAverageTVIFactory;
5799 0 : if (timeAverage_p)
5800 : {
5801 0 : timeAverageTVIFactory.reset(new vi::AveragingVi2LayerFactory(*timeavgParams));
5802 0 : TVIFactories[TVIFactoryIdx++]=timeAverageTVIFactory.get();
5803 : }
5804 :
5805 : // Phaseshift layer
5806 0 : vi::PhaseShiftingTVILayerFactory phaseShiftingTVILayerFactory(tviphaseshiftConfig_p);
5807 0 : TVIFactories[TVIFactoryIdx]=&phaseShiftingTVILayerFactory;
5808 :
5809 0 : visibilityIterator_p = new vi::VisibilityIterator2 (TVIFactories);
5810 : }
5811 : // Offline ATM correction
5812 0 : else if (doAtmCor_p) {
5813 0 : visibilityIterator_p = new vi::VisibilityIterator2(
5814 0 : vi::SDAtmosphereCorrectionVi2Factory(
5815 0 : atmCorConfig_p, selectedInputMs_p, vi::SortColumns(sortColumns_p, false), timeBin_p, isWritable
5816 : )
5817 0 : );
5818 : }
5819 : // Plain VI
5820 : else
5821 : {
5822 0 : visibilityIterator_p = new vi::VisibilityIterator2(*selectedInputMs_p,vi::SortColumns(sortColumns_p, false),
5823 0 : isWritable, NULL, timeBin_p);
5824 : }
5825 :
5826 0 : if (timeAverage_p) visibilityIterator_p->setWeightScaling(vi::WeightScaling::generateUnityWeightScaling());
5827 0 : if (channelSelector_p != NULL) visibilityIterator_p->setFrequencySelection(*channelSelector_p);
5828 :
5829 0 : return;
5830 : }
5831 :
5832 :
5833 : // -----------------------------------------------------------------------
5834 : //
5835 : // -----------------------------------------------------------------------
5836 0 : void MSTransformManager::setupBufferTransformations(vi::VisBuffer2 *vb)
5837 : {
5838 : // Calculate number of rows to add to the output MS depending on the combination parameters
5839 0 : uInt rowsToAdd = 0;
5840 :
5841 0 : if ((combinespws_p) or (nspws_p > 1))
5842 : {
5843 : // Fill baseline map using as key Ant1,Ant2,Scan and State,
5844 : // Which are the elements that can be combined in one chunk
5845 0 : rowIndex_p.clear();
5846 0 : baselineMap_p.clear();
5847 0 : Vector<Int> antenna1 = vb->antenna1();
5848 0 : Vector<Int> antenna2 = vb->antenna2();
5849 0 : Vector<Int> scan = vb->scan();
5850 0 : Vector<Int> state = vb->stateId();
5851 0 : Int relativeTimeInMiliseconds = 0;
5852 0 : for (uInt row=0;row<antenna1.size();row++)
5853 : {
5854 0 : pair<uInt,uInt> baseline = std::make_pair(antenna1(row),antenna2(row));
5855 0 : relativeTimeInMiliseconds = (Int)floor(1E3*(vb->time()(row) - vb->time()(0)));
5856 0 : pair< pair<uInt,uInt>, uInt > baselineTime = std::make_pair(baseline,relativeTimeInMiliseconds);
5857 :
5858 : // Fill row index vector with to the first row for every element in the baseline map
5859 0 : if (baselineMap_p.find(baselineTime) == baselineMap_p.end())
5860 : {
5861 0 : rowIndex_p.push_back(row);
5862 : }
5863 :
5864 0 : baselineMap_p[baselineTime].push_back(row);
5865 :
5866 : }
5867 :
5868 0 : rowsToAdd = baselineMap_p.size();
5869 :
5870 : // Fill row index vector with to the first row for every element in the baseline map
5871 : // jagonzal (CAS-8492): For SPW separation only we don't
5872 : // follow the baselineMap order but the input order
5873 0 : if (combinespws_p)
5874 : {
5875 0 : uInt rowIndex = 0;
5876 0 : rowIndex_p.clear();
5877 0 : for (baselineMap::iterator iter = baselineMap_p.begin(); iter != baselineMap_p.end(); iter++)
5878 : {
5879 0 : rowIndex_p.push_back((iter->second)[0]);
5880 0 : rowIndex ++;
5881 : }
5882 0 : }
5883 : }
5884 : else
5885 : {
5886 0 : rowsToAdd = vb->nRows();
5887 : }
5888 :
5889 : // Initialize reference frame transformation parameters
5890 0 : if (refFrameTransformation_p)
5891 : {
5892 0 : initFrequencyTransGrid(vb);
5893 : }
5894 :
5895 : // Calculate total number for rows to add
5896 0 : nRowsToAdd_p = rowsToAdd*nspws_p;
5897 :
5898 0 : return;
5899 :
5900 : }
5901 :
5902 : // -----------------------------------------------------------------------
5903 : // Fill output MS with data from an input VisBuffer
5904 : // -----------------------------------------------------------------------
5905 0 : void MSTransformManager::fillOutputMs(vi::VisBuffer2 *vb)
5906 : {
5907 0 : setupBufferTransformations(vb);
5908 :
5909 0 : if (not bufferMode_p)
5910 : {
5911 : // Create RowRef object to fill new rows
5912 0 : auto currentRows = outputMs_p->nrow();
5913 0 : RefRows rowRef( currentRows, currentRows + nRowsToAdd_p/nspws_p - 1);
5914 :
5915 : // Add new rows to output MS
5916 0 : outputMs_p->addRow(nRowsToAdd_p,false);
5917 :
5918 : // Fill new rows
5919 0 : weightSpectrumFlatFilled_p = false;
5920 0 : weightSpectrumFromSigmaFilled_p = false;
5921 0 : fillWeightCols(vb,rowRef);
5922 0 : fillDataCols(vb,rowRef);
5923 0 : fillIdCols(vb,rowRef);
5924 : }
5925 :
5926 0 : return;
5927 : }
5928 :
5929 : // -----------------------------------------------------------------------
5930 : // Method to initialize the input frequency grid to change reference frame
5931 : // -----------------------------------------------------------------------
5932 0 : void MSTransformManager::initFrequencyTransGrid(vi::VisBuffer2 *vb)
5933 : {
5934 : // NOTE (jagonzal): According to dpetry the difference between times is negligible but he recommends to use TIME
5935 : // However it does not cross-validate unless we use timeMeas from the MS columns
5936 0 : ScalarMeasColumn<MEpoch> mainTimeMeasCol = selectedInputMsCols_p->timeMeas();
5937 0 : MEpoch currentRowTime = mainTimeMeasCol(vb->rowIds()(0));
5938 :
5939 : // CAS-6778: Support for new ref. frame SOURCE that requires radial velocity correction
5940 0 : MDoppler radVelCorr;
5941 0 : MDirection inputFieldDirection;
5942 0 : bool radVelSignificant = false;
5943 0 : if (radialVelocityCorrection_p && inputMSFieldCols_p->needInterTime(vb->fieldId()(0)))
5944 : {
5945 0 : MRadialVelocity mRV = inputMSFieldCols_p->radVelMeas(vb->fieldId()(0),vb->time()(0));
5946 0 : Quantity mrv = mRV.get("m/s");
5947 0 : Quantity offsetMrv = radialVelocity_p.get("m/s"); // the radvel by which the out SPW def was shifted
5948 0 : radVelCorr = MDoppler(mrv-(Quantity(2.)*offsetMrv));
5949 0 : if (fabs(mrv.getValue()) > 1E-6) radVelSignificant = true;
5950 :
5951 0 : inputFieldDirection = inputMSFieldCols_p->phaseDirMeas(vb->fieldId()(0), vb->time()(0));
5952 : }
5953 : else
5954 : {
5955 0 : inputFieldDirection = vb->phaseCenter();
5956 : }
5957 :
5958 0 : MFrequency::Ref inputFrameRef = MFrequency::Ref(inputReferenceFrame_p,
5959 0 : MeasFrame(inputFieldDirection, observatoryPosition_p, currentRowTime));
5960 :
5961 0 : MFrequency::Ref outputFrameRef;
5962 0 : outputFrameRef = MFrequency::Ref(outputReferenceFrame_p,
5963 0 : MeasFrame(phaseCenter_p, observatoryPosition_p, referenceTime_p));
5964 :
5965 0 : freqTransEngine_p = MFrequency::Convert(MSTransformations::Hz, inputFrameRef, outputFrameRef);
5966 :
5967 0 : Int spwIndex = 0;
5968 0 : if (not combinespws_p)
5969 : {
5970 : // jagonzal : It is not necessary to map spwIndex because we
5971 : // pass the original SPWId down to the interpol1D method
5972 0 : spwIndex = vb->spectralWindows()(0);
5973 : }
5974 :
5975 :
5976 0 : if (fftShiftEnabled_p)
5977 : {
5978 0 : uInt centralChan = inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ.size()/2;
5979 :
5980 0 : Double oldCentralFrequencyBeforeRegridding = inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ[centralChan];
5981 : Double newCentralFrequencyBeforeRegriddingAtCurrentTime =
5982 0 : freqTransEngine_p(oldCentralFrequencyBeforeRegridding).get(MSTransformations::Hz).getValue();
5983 :
5984 : // CAS-6778: Support for new ref. frame SOURCE that requires radial velocity correction
5985 0 : if (radVelSignificant)
5986 : {
5987 0 : Vector<Double> tmp(1,newCentralFrequencyBeforeRegriddingAtCurrentTime);
5988 0 : newCentralFrequencyBeforeRegriddingAtCurrentTime = radVelCorr.shiftFrequency(tmp)(0);
5989 : }
5990 :
5991 0 : Double newCentralFrequencyBeforeRegriddingAtReferenceTime = inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ_aux[centralChan];
5992 0 : Double absoluteShift = newCentralFrequencyBeforeRegriddingAtCurrentTime - newCentralFrequencyBeforeRegriddingAtReferenceTime;
5993 :
5994 0 : Double chanWidth = inputOutputSpwMap_p[spwIndex].second.CHAN_FREQ[1] - inputOutputSpwMap_p[spwIndex].second.CHAN_FREQ[0];
5995 0 : Double bandwidth = inputOutputSpwMap_p[spwIndex].second.CHAN_FREQ[inputOutputSpwMap_p[spwIndex].second.NUM_CHAN-1] - inputOutputSpwMap_p[spwIndex].second.CHAN_FREQ[0];
5996 0 : bandwidth += chanWidth;
5997 :
5998 0 : fftShift_p = - absoluteShift / bandwidth;
5999 :
6000 0 : ostringstream current;
6001 0 : current << setprecision(numeric_limits<double>::max_digits10)
6002 0 : << newCentralFrequencyBeforeRegriddingAtCurrentTime;
6003 0 : ostringstream reference;
6004 0 : reference << setprecision(numeric_limits<double>::max_digits10)
6005 0 : << newCentralFrequencyBeforeRegriddingAtReferenceTime;
6006 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager",__FUNCTION__)
6007 : << "Using fftshift interpolation. The absolute shift is the "
6008 : << "new central frequency at current (input SPW) time - new "
6009 : << "central frequency "
6010 : << "at reference (output SPW) time\nAbsolute shift: "
6011 : << current
6012 : << " - " << reference
6013 : << " = " << absoluteShift << ", bandwidth " << bandwidth
6014 0 : << ", relative shift: " << fftShift_p << LogIO::POST;
6015 :
6016 : }
6017 : else
6018 : {
6019 0 : for(uInt chan_idx=0; chan_idx<inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ.size(); chan_idx++)
6020 : {
6021 0 : inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ_aux[chan_idx] =
6022 0 : freqTransEngine_p(inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ[chan_idx]).get(MSTransformations::Hz).getValue();
6023 : }
6024 :
6025 : /*
6026 : ostringstream oss;
6027 : oss.precision(30);
6028 : oss << " field direction input frame=" << inputFieldDirection << endl;
6029 : oss << " input frame=" << inputFrameRef << endl;
6030 : oss << " field direction output frame=" << phaseCenter_p << endl;
6031 : oss << " output frame=" << outputFrameRef << endl;
6032 : oss << " transformation engine=" << freqTransEngine_p << endl;
6033 : oss << " before transformation=" << inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ[0] << endl;
6034 : oss << " after transformation=" << inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ_aux[0] << endl;
6035 : */
6036 :
6037 :
6038 0 : if (radVelSignificant)
6039 : {
6040 0 : inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ_aux =
6041 0 : radVelCorr.shiftFrequency(inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ_aux);
6042 :
6043 : /*
6044 : oss << " correction engine=" << radVelCorr << endl;
6045 : oss << " after radial velocity correction=" << inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ_aux[0] << endl;
6046 : */
6047 : }
6048 :
6049 : //logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__) << oss.str() << LogIO::POST;
6050 : }
6051 :
6052 0 : return;
6053 : }
6054 :
6055 : // ----------------------------------------------------------------------------------------
6056 : // Fill auxiliary (meta data) columns which don't depend on the SPW (merely consist of Ids)
6057 : // ----------------------------------------------------------------------------------------
6058 0 : void MSTransformManager::fillIdCols(vi::VisBuffer2 *vb,RefRows &rowRef)
6059 : {
6060 : // Declare common auxiliary variables
6061 0 : RefRows absoluteRefRows(rowRef.firstRow(),rowRef.firstRow()+nRowsToAdd_p-1);
6062 0 : Vector<Int> tmpVectorInt(nRowsToAdd_p,0);
6063 0 : Vector<Double> tmpVectorDouble(nRowsToAdd_p,0.0);
6064 0 : Vector<bool> tmpVectorbool(nRowsToAdd_p,false);
6065 :
6066 : // Special case for Data description Id
6067 0 : if (transformDDIVector(vb->dataDescriptionIds(),tmpVectorInt))
6068 : {
6069 0 : outputMsCols_p->dataDescId().putColumnCells(absoluteRefRows,tmpVectorInt);
6070 : }
6071 : else
6072 : {
6073 0 : outputMsCols_p->dataDescId().putColumnCells(absoluteRefRows,vb->dataDescriptionIds());
6074 : }
6075 :
6076 : // Re-indexable Columns
6077 0 : transformAndWriteReindexableVector(vb->observationId(),tmpVectorInt,true,
6078 0 : inputOutputObservationIndexMap_p,
6079 0 : outputMsCols_p->observationId(),absoluteRefRows);
6080 0 : transformAndWriteReindexableVector(vb->arrayId(),tmpVectorInt,true,
6081 0 : inputOutputArrayIndexMap_p,
6082 0 : outputMsCols_p->arrayId(),absoluteRefRows);
6083 0 : transformAndWriteReindexableVector(vb->fieldId(),tmpVectorInt,!timespan_p.contains("field"),
6084 0 : inputOutputFieldIndexMap_p,
6085 0 : outputMsCols_p->fieldId(),absoluteRefRows);
6086 0 : transformAndWriteReindexableVector(vb->stateId(),tmpVectorInt,!timespan_p.contains("state"),
6087 0 : inputOutputScanIntentIndexMap_p,
6088 0 : outputMsCols_p->stateId(),absoluteRefRows);
6089 0 : transformAndWriteReindexableVector(vb->antenna1(),tmpVectorInt,false,
6090 0 : inputOutputAntennaIndexMap_p,
6091 0 : outputMsCols_p->antenna1(),absoluteRefRows);
6092 0 : transformAndWriteReindexableVector(vb->antenna2(),tmpVectorInt,false,
6093 0 : inputOutputAntennaIndexMap_p,
6094 0 : outputMsCols_p->antenna2(),absoluteRefRows);
6095 :
6096 : // Not Re-indexable Columns
6097 0 : transformAndWriteNotReindexableVector(vb->scan(),tmpVectorInt,!timespan_p.contains("scan"),outputMsCols_p->scanNumber(),absoluteRefRows);
6098 0 : transformAndWriteNotReindexableVector(vb->processorId(),tmpVectorInt,false,outputMsCols_p->processorId(),absoluteRefRows);
6099 0 : transformAndWriteNotReindexableVector(vb->feed1(),tmpVectorInt,false,outputMsCols_p->feed1(),absoluteRefRows);
6100 0 : transformAndWriteNotReindexableVector(vb->feed2(),tmpVectorInt,false,outputMsCols_p->feed2(),absoluteRefRows);
6101 0 : transformAndWriteNotReindexableVector(vb->time(),tmpVectorDouble,false,outputMsCols_p->time(),absoluteRefRows);
6102 0 : transformAndWriteNotReindexableVector(vb->timeCentroid(),tmpVectorDouble,false,outputMsCols_p->timeCentroid(),absoluteRefRows);
6103 0 : transformAndWriteNotReindexableVector(vb->timeInterval(),tmpVectorDouble,false,outputMsCols_p->interval(),absoluteRefRows);
6104 :
6105 : // Special case for vectors that have to be averaged
6106 0 : if (combinespws_p)
6107 : {
6108 0 : mapAndAverageVector(vb->flagRow(),tmpVectorbool);
6109 0 : outputMsCols_p->flagRow().putColumnCells(absoluteRefRows, tmpVectorbool);
6110 :
6111 : // jagonzal: We average exposures by default, if they are the same we obtain the same results
6112 0 : mapAndAverageVector(vb->exposure(),tmpVectorDouble);
6113 0 : outputMsCols_p->exposure().putColumnCells(absoluteRefRows, tmpVectorDouble);
6114 : }
6115 : else
6116 : {
6117 0 : transformAndWriteNotReindexableVector(vb->flagRow(),tmpVectorbool,false,outputMsCols_p->flagRow(),absoluteRefRows);
6118 0 : transformAndWriteNotReindexableVector(vb->exposure(),tmpVectorDouble,false,outputMsCols_p->exposure(),absoluteRefRows);
6119 : }
6120 :
6121 0 : if (combinespws_p)
6122 : {
6123 0 : Matrix<Double> tmpUvw(IPosition(2,3,rowRef.nrows()),0.0);
6124 0 : Matrix<Float> tmpMatrixFloat(IPosition(2,vb->nCorrelations(),rowRef.nrows()),0.0);
6125 :
6126 0 : mapMatrix(vb->uvw(),tmpUvw);
6127 0 : writeMatrix(tmpUvw,outputMsCols_p->uvw(),rowRef,nspws_p);
6128 :
6129 : // WEIGHT/SIGMA are defined as the median of WEIGHT_SPECTRUM / SIGMA_SPECTRUM in the case of SPECTRUM transformation
6130 0 : if (not spectrumTransformation_p)
6131 : {
6132 0 : if (newWeightFactorMap_p.size() > 0)
6133 : {
6134 0 : mapAndScaleMatrix(vb->weight(),tmpMatrixFloat,newWeightFactorMap_p,vb->spectralWindows());
6135 0 : writeMatrix(tmpMatrixFloat,outputMsCols_p->weight(),rowRef,nspws_p);
6136 : }
6137 : else
6138 : {
6139 : // jagonzal: According to dpetry we have to copy weights from the first SPW
6140 : // This is justified since the rows to be combined _must_ be from the
6141 : // same baseline and therefore have the same UVW coordinates in the MS (in meters).
6142 : // They could therefore be regarded to also have the same WEIGHT, at least to
6143 : // a good approximation.
6144 0 : mapMatrix(vb->weight(),tmpMatrixFloat);
6145 0 : writeMatrix(tmpMatrixFloat,outputMsCols_p->weight(),rowRef,nspws_p);
6146 : }
6147 :
6148 :
6149 : // Sigma must be redefined to 1/weight when corrected data becomes data
6150 0 : if (correctedToData_p)
6151 : {
6152 0 : arrayTransformInPlace(tmpMatrixFloat, vi::AveragingTvi2::weightToSigma);
6153 0 : outputMsCols_p->sigma().putColumnCells(rowRef, tmpMatrixFloat);
6154 0 : writeMatrix(tmpMatrixFloat,outputMsCols_p->sigma(),rowRef,nspws_p);
6155 : }
6156 : else
6157 : {
6158 0 : if (newSigmaFactorMap_p.size() > 0)
6159 : {
6160 0 : mapAndScaleMatrix(vb->sigma(),tmpMatrixFloat,newSigmaFactorMap_p,vb->spectralWindows());
6161 0 : outputMsCols_p->sigma().putColumnCells(rowRef, tmpMatrixFloat);
6162 0 : writeMatrix(tmpMatrixFloat,outputMsCols_p->sigma(),rowRef,nspws_p);
6163 : }
6164 : else
6165 : {
6166 : // jagonzal: According to dpetry we have to copy weights from the first SPW
6167 : // This is justified since the rows to be combined _must_ be from the
6168 : // same baseline and therefore have the same UVW coordinates in the MS (in meters).
6169 : // They could therefore be regarded to also have the same WEIGHT, at least to
6170 : // a good approximation.
6171 0 : mapMatrix(vb->sigma(),tmpMatrixFloat);
6172 0 : writeMatrix(tmpMatrixFloat,outputMsCols_p->sigma(),rowRef,nspws_p);
6173 : }
6174 : }
6175 : }
6176 :
6177 : }
6178 : else
6179 : {
6180 0 : writeMatrix(vb->uvw(),outputMsCols_p->uvw(),rowRef,nspws_p);
6181 :
6182 : // WEIGHT/SIGMA are defined as the median of WEIGHT_SPECTRUM / SIGMA_SPECTRUM in the case of SPECTRUM transformation
6183 0 : if (not spectrumTransformation_p)
6184 : {
6185 0 : if (correctedToData_p) {
6186 :
6187 : // weight -> weight
6188 0 : Matrix<Float> weights = vb->weight();
6189 0 : if (newWeightFactorMap_p.size() > 0)
6190 : {
6191 0 : if ( (newWeightFactorMap_p.find(vb->spectralWindows()(0)) != newWeightFactorMap_p.end()) and
6192 0 : (newWeightFactorMap_p[vb->spectralWindows()(0)] != 1) )
6193 : {
6194 0 : weights *= newWeightFactorMap_p[vb->spectralWindows()(0)];
6195 : }
6196 : }
6197 0 : writeMatrix(weights,outputMsCols_p->weight(),rowRef,nspws_p);
6198 :
6199 : // weight -> sigma
6200 0 : arrayTransformInPlace(weights, vi::AveragingTvi2::weightToSigma);
6201 0 : writeMatrix(weights,outputMsCols_p->sigma(),rowRef,nspws_p);
6202 :
6203 : }
6204 0 : else if(!bothDataColumnsAreOutput_p)
6205 : {
6206 : // sigma -> sigma
6207 0 : Matrix<Float> sigma = vb->sigma();
6208 0 : if (newSigmaFactorMap_p.size() > 0)
6209 : {
6210 0 : if ( (newSigmaFactorMap_p.find(vb->spectralWindows()(0)) != newSigmaFactorMap_p.end()) and
6211 0 : (newSigmaFactorMap_p[vb->spectralWindows()(0)] != 1) )
6212 : {
6213 0 : sigma *= newSigmaFactorMap_p[vb->spectralWindows()(0)];
6214 : }
6215 : }
6216 0 : writeMatrix(sigma,outputMsCols_p->sigma(),rowRef,nspws_p);
6217 :
6218 : // sigma -> weight
6219 0 : arrayTransformInPlace(sigma, vi::AveragingTvi2::sigmaToWeight);
6220 0 : writeMatrix(sigma, outputMsCols_p->weight(), rowRef, nspws_p);
6221 : }
6222 : // If both DATA and DATA_CORRECTED are input and output then
6223 : // SIGMA(_SPECTRUM) and WEIGHT(_SPECTRUM) should maintain their alignment
6224 : // with DATA and CORRECTED_DATA, respectively and nothing is done. See CAS-11139
6225 : else
6226 : {
6227 : // weight -> weight
6228 0 : Matrix<Float> weights = vb->weight();
6229 0 : if (newWeightFactorMap_p.size() > 0)
6230 : {
6231 0 : if ( (newWeightFactorMap_p.find(vb->spectralWindows()(0)) != newWeightFactorMap_p.end()) and
6232 0 : (newWeightFactorMap_p[vb->spectralWindows()(0)] != 1) )
6233 : {
6234 0 : weights *= newWeightFactorMap_p[vb->spectralWindows()(0)];
6235 : }
6236 : }
6237 0 : writeMatrix(weights,outputMsCols_p->weight(),rowRef,nspws_p);
6238 :
6239 : // sigma -> sigma
6240 0 : Matrix<Float> sigma = vb->sigma();
6241 0 : if (newSigmaFactorMap_p.size() > 0)
6242 : {
6243 0 : if ( (newSigmaFactorMap_p.find(vb->spectralWindows()(0)) != newSigmaFactorMap_p.end()) and
6244 0 : (newSigmaFactorMap_p[vb->spectralWindows()(0)] != 1) )
6245 : {
6246 0 : sigma *= newSigmaFactorMap_p[vb->spectralWindows()(0)];
6247 : }
6248 : }
6249 0 : writeMatrix(sigma,outputMsCols_p->sigma(),rowRef,nspws_p);
6250 : }
6251 : }
6252 : }
6253 :
6254 0 : return;
6255 : }
6256 :
6257 : // ------------------------------------------------------------------------------------
6258 : //
6259 : // ------------------------------------------------------------------------------------
6260 0 : template <class T> void MSTransformManager::transformAndWriteNotReindexableVector( const Vector<T> &inputVector,
6261 : Vector<T> &outputVector,
6262 : bool constant,
6263 : ScalarColumn<T> &outputCol,
6264 : RefRows &rowReference)
6265 : {
6266 0 : bool transformed = transformNotReindexableVector(inputVector,outputVector,constant);
6267 :
6268 0 : if (transformed)
6269 : {
6270 0 : outputCol.putColumnCells(rowReference, outputVector);
6271 : }
6272 : else
6273 : {
6274 0 : outputCol.putColumnCells(rowReference, inputVector);
6275 : }
6276 :
6277 0 : return;
6278 : };
6279 :
6280 : // ------------------------------------------------------------------------------------
6281 : //
6282 : // ------------------------------------------------------------------------------------
6283 0 : template <class T> void MSTransformManager::transformAndWriteReindexableVector( const Vector<T> &inputVector,
6284 : Vector<T> &outputVector,
6285 : bool constant,
6286 : map<uInt,uInt> &inputOutputIndexMap,
6287 : ScalarColumn<T> &outputCol,
6288 : RefRows &rowReference)
6289 : {
6290 0 : bool transformed = transformReindexableVector(inputVector,outputVector,constant,inputOutputIndexMap);
6291 :
6292 0 : if (transformed)
6293 : {
6294 0 : outputCol.putColumnCells(rowReference, outputVector);
6295 : }
6296 : else
6297 : {
6298 0 : outputCol.putColumnCells(rowReference, inputVector);
6299 : }
6300 :
6301 0 : return;
6302 : };
6303 :
6304 : // ------------------------------------------------------------------------------------
6305 : //
6306 : // ------------------------------------------------------------------------------------
6307 0 : bool MSTransformManager::transformDDIVector(const Vector<Int> &inputVector,Vector<Int> &outputVector)
6308 : {
6309 0 : bool transformed = true;
6310 :
6311 0 : if ((combinespws_p) or (nspws_p > 1))
6312 : {
6313 0 : if (nspws_p > 1)
6314 : {
6315 0 : uInt absoluteIndex = 0;
6316 0 : for (uInt index=0; index<rowIndex_p.size();index++)
6317 : {
6318 0 : for (uInt spwIndex=0;spwIndex < nspws_p; spwIndex++)
6319 : {
6320 0 : outputVector(absoluteIndex) = ddiStart_p + spwIndex;
6321 0 : absoluteIndex += 1;
6322 : }
6323 : }
6324 : }
6325 : else
6326 : {
6327 0 : outputVector = ddiStart_p;
6328 0 : }
6329 : }
6330 : else
6331 : {
6332 0 : transformed = transformReindexableVector(inputVector,outputVector,true,inputOutputDDIndexMap_p);
6333 : }
6334 :
6335 0 : return transformed;
6336 : }
6337 :
6338 : // ------------------------------------------------------------------------------------
6339 : //
6340 : // ------------------------------------------------------------------------------------
6341 0 : void MSTransformManager::mapAndAverageVector( const Vector<Double> &inputVector,
6342 : Vector<Double> &outputVector)
6343 : {
6344 0 : Double vec_average = 0;
6345 0 : vector<uInt> baselineRows;
6346 0 : uInt row, counts, absoluteIndex = 0;
6347 0 : for (baselineMap::iterator iter = baselineMap_p.begin(); iter != baselineMap_p.end(); iter++)
6348 : {
6349 : // Get baseline rows vector
6350 0 : baselineRows = iter->second;
6351 :
6352 : // Compute combined value from each SPW
6353 0 : counts = 0;
6354 :
6355 0 : for (auto iter_row = baselineRows.begin();iter_row != baselineRows.end(); iter_row++)
6356 : {
6357 0 : row = *iter_row;
6358 0 : if (counts == 0)
6359 : {
6360 0 : vec_average = inputVector(row);
6361 : }
6362 : else
6363 : {
6364 0 : vec_average += inputVector(row);
6365 : }
6366 :
6367 0 : counts += 1;
6368 : }
6369 :
6370 : // Normalize value
6371 0 : if (counts) vec_average /= counts;
6372 :
6373 : // Set value in output vector
6374 0 : for (uInt spwIndex=0;spwIndex < nspws_p; spwIndex++)
6375 : {
6376 0 : outputVector(absoluteIndex) = vec_average;
6377 0 : absoluteIndex += 1;
6378 : }
6379 : }
6380 :
6381 0 : return;
6382 : }
6383 :
6384 : // ------------------------------------------------------------------------------------
6385 : //
6386 : // ------------------------------------------------------------------------------------
6387 0 : void MSTransformManager::mapAndAverageVector( const Vector<bool> &inputVector,
6388 : Vector<bool> &outputVector)
6389 : {
6390 0 : bool vec_average = false;
6391 0 : vector<uInt> baselineRows;
6392 0 : uInt row, counts, absoluteIndex = 0;
6393 0 : for (baselineMap::iterator iter = baselineMap_p.begin(); iter != baselineMap_p.end(); iter++)
6394 : {
6395 : // Get baseline rows vector
6396 0 : baselineRows = iter->second;
6397 :
6398 : // Compute combined value from each SPW
6399 0 : counts = 0;
6400 :
6401 0 : for (auto iter_row = baselineRows.begin();iter_row != baselineRows.end(); iter_row++)
6402 : {
6403 0 : row = *iter_row;
6404 0 : if (counts == 0)
6405 : {
6406 0 : vec_average = inputVector(row);
6407 : }
6408 : else
6409 : {
6410 0 : vec_average &= inputVector(row);
6411 : }
6412 : }
6413 :
6414 : // Set value in output vector
6415 0 : for (uInt spwIndex=0;spwIndex < nspws_p; spwIndex++)
6416 : {
6417 0 : outputVector(absoluteIndex) = vec_average;
6418 0 : absoluteIndex += 1;
6419 : }
6420 : }
6421 :
6422 0 : return;
6423 : }
6424 :
6425 :
6426 : // -----------------------------------------------------------------------------------
6427 : // Fill the data from an input matrix with shape [nCol,nBaselinesxnSPWs] into an
6428 : // output matrix with shape [nCol,nBaselines] accumulating the averaging from all SPWS
6429 : // -----------------------------------------------------------------------------------
6430 : template <class T> void MSTransformManager::mapAndAverageMatrix( const Matrix<T> &inputMatrix,
6431 : Matrix<T> &outputMatrix,
6432 : bool convolveFlags,
6433 : vi::VisBuffer2 *vb)
6434 : {
6435 : // Get number of columns
6436 : uInt nCols = outputMatrix.shape()(0);
6437 :
6438 : // Access FLAG_ROW in case we need to convolute the average
6439 : Vector<bool> flags;
6440 : if (convolveFlags) flags = vb->flagRow();
6441 :
6442 : // Fill output array with the combined data from each SPW
6443 : uInt row;
6444 : uInt baseline_index = 0;
6445 : Double normalizingFactor = 0;
6446 : Double contributionFactor = 0;
6447 : vector<uInt> baselineRows;
6448 : for (baselineMap::iterator iter = baselineMap_p.begin(); iter != baselineMap_p.end(); iter++)
6449 : {
6450 : // Get baseline rows vector
6451 : baselineRows = iter->second;
6452 :
6453 : // Reset normalizing factor
6454 : normalizingFactor = 0;
6455 :
6456 : // Compute combined value from each SPW
6457 : for (vector<uInt>::iterator iter_row = baselineRows.begin();iter_row != baselineRows.end(); iter_row++)
6458 : {
6459 : row = *iter_row;
6460 : if (convolveFlags)
6461 : {
6462 : contributionFactor = !flags(row);
6463 : }
6464 : else
6465 : {
6466 : contributionFactor = 1;
6467 : }
6468 :
6469 : for (uInt col = 0; col < nCols; col++)
6470 : {
6471 : outputMatrix(col,baseline_index) += contributionFactor*inputMatrix(col,row);
6472 : }
6473 :
6474 : normalizingFactor += contributionFactor;
6475 : }
6476 :
6477 : // Normalize accumulated value
6478 : if (normalizingFactor>0)
6479 : {
6480 : for (uInt col = 0; col < nCols; col++)
6481 : {
6482 : outputMatrix(col,baseline_index) /= normalizingFactor;
6483 : }
6484 : }
6485 :
6486 : baseline_index += 1;
6487 : }
6488 :
6489 : return;
6490 : }
6491 :
6492 : // -----------------------------------------------------------------------
6493 : //
6494 : // -----------------------------------------------------------------------
6495 0 : template <class T> void MSTransformManager::mapAndScaleMatrix( const Matrix<T> &inputMatrix,
6496 : Matrix<T> &outputMatrix,
6497 : map<uInt,T> scaleMap,
6498 : Vector<Int> spws)
6499 : {
6500 : // Reset output Matrix
6501 0 : outputMatrix = 0;
6502 :
6503 : // Get number of columns
6504 0 : uInt nCols = outputMatrix.shape()(0);
6505 :
6506 : // Fill output array with the combined data from each SPW
6507 : Int spw;
6508 : uInt row;
6509 0 : uInt baseline_index = 0;
6510 0 : vector<uInt> baselineRows;
6511 : T contributionFactor;
6512 0 : for (baselineMap::iterator iter = baselineMap_p.begin(); iter != baselineMap_p.end(); iter++)
6513 : {
6514 : // Get baseline rows vector
6515 0 : baselineRows = iter->second;
6516 :
6517 : // Reset normalizing factor
6518 :
6519 : // Get value from first SPW (this is for Weight and Sigma and cvel is doing it so)
6520 0 : row = baselineRows.at(0);
6521 0 : spw = spws(row);
6522 0 : if (scaleMap.find(spw) != scaleMap.end())
6523 : {
6524 0 : contributionFactor = scaleMap[spw];
6525 : }
6526 : else
6527 : {
6528 0 : contributionFactor = 1;
6529 : }
6530 :
6531 0 : for (uInt col = 0; col < nCols; col++)
6532 : {
6533 0 : outputMatrix(col,baseline_index) = contributionFactor*inputMatrix(col,row);
6534 : }
6535 :
6536 0 : baseline_index += 1;
6537 : }
6538 :
6539 0 : return;
6540 : }
6541 :
6542 :
6543 : // ----------------------------------------------------------------------------------------
6544 : // Fill main (data) columns which have to be combined together to produce bigger SPWs
6545 : // ----------------------------------------------------------------------------------------
6546 0 : void MSTransformManager::fillDataCols(vi::VisBuffer2 *vb,RefRows &rowRef)
6547 : {
6548 0 : ArrayColumn<bool> *outputFlagCol=NULL;
6549 0 : for (dataColMap::iterator iter = dataColMap_p.begin();iter != dataColMap_p.end();iter++)
6550 : {
6551 : // Get applicable *_SPECTRUM (copy constructor uses reference semantics)
6552 : // If channel average or combine, otherwise no need to copy
6553 0 : const Cube<Float> &applicableSpectrum = getApplicableSpectrum(vb,iter->first);
6554 :
6555 : // Apply transformations
6556 0 : switch (iter->first)
6557 : {
6558 0 : case MS::DATA:
6559 : {
6560 0 : if (mainColumn_p == MS::DATA)
6561 : {
6562 0 : outputFlagCol = &(outputMsCols_p->flag());
6563 0 : setTileShape(rowRef,outputMsCols_p->flag());
6564 : }
6565 : else
6566 : {
6567 0 : outputFlagCol = NULL;
6568 : }
6569 :
6570 0 : setTileShape(rowRef,outputMsCols_p->data());
6571 0 : transformCubeOfData(vb,rowRef,vb->visCube(),outputMsCols_p->data(), outputFlagCol,applicableSpectrum);
6572 :
6573 0 : break;
6574 : }
6575 0 : case MS::CORRECTED_DATA:
6576 : {
6577 0 : if (mainColumn_p == MS::CORRECTED_DATA)
6578 : {
6579 0 : outputFlagCol = &(outputMsCols_p->flag());
6580 0 : setTileShape(rowRef,outputMsCols_p->flag());
6581 : }
6582 : else
6583 : {
6584 0 : outputFlagCol = NULL;
6585 : }
6586 :
6587 0 : if (iter->second == MS::DATA)
6588 : {
6589 0 : setTileShape(rowRef,outputMsCols_p->data());
6590 0 : transformCubeOfData(vb,rowRef,vb->visCubeCorrected(),outputMsCols_p->data(), outputFlagCol,applicableSpectrum);
6591 : }
6592 : else
6593 : {
6594 0 : setTileShape(rowRef,outputMsCols_p->correctedData());
6595 0 : transformCubeOfData(vb,rowRef,vb->visCubeCorrected(),outputMsCols_p->correctedData(), outputFlagCol,applicableSpectrum);
6596 : }
6597 :
6598 0 : break;
6599 : }
6600 0 : case MS::MODEL_DATA:
6601 : {
6602 0 : if (mainColumn_p == MS::MODEL_DATA)
6603 : {
6604 0 : outputFlagCol = &(outputMsCols_p->flag());
6605 0 : setTileShape(rowRef,outputMsCols_p->flag());
6606 : }
6607 : else
6608 : {
6609 0 : outputFlagCol = NULL;
6610 : }
6611 :
6612 0 : if (produceModel_p)
6613 : {
6614 : // irrespective of wheter iter->second == MS::DATA
6615 : // or iter->second == MS::CORRECTED_DATA
6616 0 : setTileShape(rowRef,outputMsCols_p->modelData());
6617 0 : transformCubeOfData(vb,rowRef,vb->visCubeModel(),outputMsCols_p->modelData(), outputFlagCol,applicableSpectrum);
6618 0 : } else if (iter->second == MS::DATA) {
6619 0 : setTileShape(rowRef,outputMsCols_p->data());
6620 0 : transformCubeOfData(vb,rowRef,vb->visCubeModel(),outputMsCols_p->data(), outputFlagCol,applicableSpectrum);
6621 : }
6622 : else
6623 : {
6624 0 : setTileShape(rowRef,outputMsCols_p->modelData());
6625 0 : transformCubeOfData(vb,rowRef,vb->visCubeModel(),outputMsCols_p->modelData(), outputFlagCol,applicableSpectrum);
6626 : }
6627 0 : break;
6628 : }
6629 0 : case MS::FLOAT_DATA:
6630 : {
6631 0 : if (mainColumn_p == MS::FLOAT_DATA)
6632 : {
6633 0 : outputFlagCol = &(outputMsCols_p->flag());
6634 0 : setTileShape(rowRef,outputMsCols_p->flag());
6635 : }
6636 : else
6637 : {
6638 0 : outputFlagCol = NULL;
6639 : }
6640 :
6641 0 : setTileShape(rowRef,outputMsCols_p->floatData());
6642 0 : transformCubeOfData(vb,rowRef,vb->visCubeFloat(),outputMsCols_p->floatData(), outputFlagCol,applicableSpectrum);
6643 :
6644 0 : break;
6645 : }
6646 0 : case MS::LAG_DATA:
6647 : {
6648 : // jagonzal: TODO
6649 0 : break;
6650 : }
6651 0 : default:
6652 : {
6653 : // jagonzal: TODO
6654 0 : break;
6655 : }
6656 : }
6657 : }
6658 :
6659 : // Special case for flag category
6660 0 : if (inputFlagCategoryAvailable_p)
6661 : {
6662 0 : if (spectrumReshape_p)
6663 : {
6664 0 : IPosition transformedCubeShape = getShape(); //[nC,nF,nR]
6665 0 : IPosition inputFlagCategoryShape = vb->flagCategory().shape(); // [nC,nF,nCategories,nR]
6666 0 : IPosition flagCategoryShape(4, inputFlagCategoryShape(1),
6667 0 : transformedCubeShape(2),
6668 0 : inputFlagCategoryShape(2),
6669 0 : transformedCubeShape(2));
6670 0 : Array<bool> flagCategory(flagCategoryShape,false);
6671 :
6672 0 : outputMsCols_p->flagCategory().putColumnCells(rowRef, flagCategory);
6673 : }
6674 : else
6675 : {
6676 0 : outputMsCols_p->flagCategory().putColumnCells(rowRef, vb->flagCategory());
6677 : }
6678 : }
6679 :
6680 0 : return;
6681 : }
6682 :
6683 : // ----------------------------------------------------------------------------------------
6684 : // Fill weight cols (WEIGHT_SPECTRUM and SIGMA_SPECTRUM) as well as WEIGHT/SIGMA which have to be derived from it using median
6685 : // ----------------------------------------------------------------------------------------
6686 0 : void MSTransformManager::fillWeightCols(vi::VisBuffer2 *vb,RefRows &rowRef)
6687 : {
6688 : // WEIGHT_SPECTRUM and SIGMA_SPECTRUM are only filled if requested or when WEIGHT_SPECTRUM is present in the input MS
6689 : // But WEIGHT/SIGMA have always to be derived from in-memory WEIGHT_SPECTRUM/SIGMA_SPECTRUM
6690 0 : if (flushWeightSpectrum_p or spectrumTransformation_p or userBufferMode_p)
6691 : {
6692 : // Switch aux Weight propagation off
6693 0 : propagateWeights(false);
6694 :
6695 : // Switch average and smooth kernels
6696 0 : setChannelAverageKernel(MSTransformations::flagCumSumNonZero);
6697 0 : setSmoothingKernel(MSTransformations::plainSmoothSpectrum);
6698 0 : setSmoothingFourierKernel(MSTransformations::plainSmoothSpectrum);
6699 :
6700 : // Dummy auxiliary weightSpectrum
6701 0 : const Cube<Float> applicableSpectrum;
6702 :
6703 0 : if (spectrumTransformation_p)
6704 : {
6705 : // For SPW separation:
6706 : // Prepare RowReference for spectrum transformations
6707 : // (all data is flushed at once instead of blocks)
6708 0 : RefRows rowRefSpectrum(rowRef.firstRow(), rowRef.firstRow() + nRowsToAdd_p-1);
6709 :
6710 : // Switch on buffer mode
6711 0 : Cube<Float> transformedSpectrum;
6712 0 : Cube<bool> transformedFlag;
6713 0 : if (not userBufferMode_p)
6714 : {
6715 0 : setBufferMode(true);
6716 0 : dataBuffer_p = MSTransformations::weightSpectrum;
6717 0 : transformedSpectrum.resize(getShape(),false);
6718 0 : weightSpectrum_p = &transformedSpectrum;
6719 0 : transformedFlag.resize(getShape(),false);
6720 0 : flagCube_p = &transformedFlag; // Not used for the output but to extract the average/median
6721 : }
6722 :
6723 :
6724 : // Multiple column operation
6725 0 : if (doingData_p and doingCorrected_p)
6726 : {
6727 : // Transform WEIGHT_SPECTRUM but don't derive SIGMA_SPECTRUM from it
6728 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6729 : getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),
6730 : getOutputWeightColumn(vb,MS::WEIGHT),
6731 0 : MSTransformations::transformWeight,flushWeightSpectrum_p);
6732 :
6733 : // Convert SIGMA_SPECTRUM to WEIGHT format, transform it and derive SIGMA_SPECTRUM from it
6734 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,getWeightSpectrumFromSigmaSpectrum(vb),
6735 : getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),
6736 : getOutputWeightColumn(vb,MS::SIGMA),
6737 0 : MSTransformations::transformWeightIntoSigma,flushWeightSpectrum_p);
6738 : }
6739 : // In case of time average we can use directly WEIGHT_SPECTRUM because
6740 : // AveragingTvi2 derives it from the input SIGMA_SPECTRUM or WEIGHT_SPECTRUM
6741 : // depending on the selected DATA column
6742 0 : else if (timeAverage_p)
6743 : {
6744 : // Transform WEIGHT_SPECTRUM
6745 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6746 : getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),
6747 : getOutputWeightColumn(vb,MS::WEIGHT),
6748 0 : MSTransformations::transformWeight,flushWeightSpectrum_p);
6749 :
6750 : // Derive SIGMA_SPECTRUM from WEIGHT_SPECTRUM
6751 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6752 : getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),
6753 : getOutputWeightColumn(vb,MS::SIGMA),
6754 0 : MSTransformations::weightIntoSigma,flushWeightSpectrum_p);
6755 : }
6756 : // DATA to DATA: Convert SIGMA_SPECTRUM to WEIGHT format, transform it and derive SIGMA_SPECTRUM from it
6757 0 : else if (doingData_p)
6758 : {
6759 : // Transform WEIGHT_SPECTRUM
6760 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,getWeightSpectrumFromSigmaSpectrum(vb),
6761 : getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),
6762 : getOutputWeightColumn(vb,MS::WEIGHT),
6763 0 : MSTransformations::transformWeight,flushWeightSpectrum_p);
6764 :
6765 : // Derive SIGMA_SPECTRUM from WEIGHT_SPECTRUM
6766 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6767 : getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),
6768 : getOutputWeightColumn(vb,MS::SIGMA),
6769 0 : MSTransformations::weightIntoSigma,flushWeightSpectrum_p);
6770 : }
6771 : // CORRECTED to DATA: Transform WEIGHT_SPECTRUM and derive SIGMA_SPECTRUM from it
6772 0 : else if (doingCorrected_p) // CORRECTED to DATA
6773 : {
6774 : // Transform WEIGHT_SPECTRUM
6775 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6776 : getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),
6777 : getOutputWeightColumn(vb,MS::WEIGHT),
6778 0 : MSTransformations::transformWeight,flushWeightSpectrum_p);
6779 :
6780 : // Derive SIGMA_SPECTRUM from WEIGHT_SPECTRUM
6781 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6782 : getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),
6783 : getOutputWeightColumn(vb,MS::SIGMA),
6784 0 : MSTransformations::weightIntoSigma,flushWeightSpectrum_p);
6785 : }
6786 : // MODEL to DATA: Calculate WEIGHT_SPECTRUM using FLAG and derive SIGMA_SPECTRUM from it
6787 0 : else if (doingModel_p)
6788 : {
6789 : // Transform WEIGHT_SPECTRUM
6790 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,getWeightSpectrumFlat(vb),
6791 : getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),
6792 : getOutputWeightColumn(vb,MS::WEIGHT),
6793 0 : MSTransformations::transformWeight,flushWeightSpectrum_p);
6794 :
6795 : // Derive SIGMA_SPECTRUM from WEIGHT_SPECTRUM
6796 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6797 : getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),
6798 : getOutputWeightColumn(vb,MS::SIGMA),
6799 0 : MSTransformations::weightIntoSigma,flushWeightSpectrum_p);
6800 : }
6801 :
6802 : // Switch off buffer mode
6803 0 : if (not userBufferMode_p)
6804 : {
6805 0 : setBufferMode(false);
6806 0 : weightSpectrum_p = NULL;
6807 : }
6808 : }
6809 : // Within AveragingTvi2 SIGMA_SPECTRUM is already re-defined to 1/sqrt(WEIGHT_SPECTRUM) if CORRECTED->DATA
6810 : // or obtained from the input SIGMA_SPECTRUM in the case of DATA->DATA or multiple column operation
6811 0 : else if (timeAverage_p)
6812 : {
6813 : // TransformCubeOfData is either copyCubeOfData or separateCubeOfData
6814 0 : if (userBufferMode_p)
6815 : {
6816 0 : dataBuffer_p = MSTransformations::weightSpectrum;
6817 : }
6818 : else
6819 : {
6820 0 : setTileShape(rowRef,getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM));
6821 : }
6822 0 : transformCubeOfData(vb,rowRef,vb->weightSpectrum(),getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),NULL,applicableSpectrum);
6823 :
6824 0 : if (userBufferMode_p)
6825 : {
6826 0 : dataBuffer_p = MSTransformations::sigmaSpectrum;
6827 : }
6828 : else
6829 : {
6830 0 : setTileShape(rowRef,getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM));
6831 : }
6832 0 : transformCubeOfData(vb,rowRef,vb->sigmaSpectrum(),getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),NULL,applicableSpectrum);
6833 : }
6834 : // When CORRECTED becomes DATA, then SIGMA_SPECTRUM has to be re-defined to 1/sqrt(WEIGHT_SPECTRUM)
6835 0 : else if (correctedToData_p)
6836 : {
6837 : // TransformCubeOfData is either copyCubeOfData or separateCubeOfData
6838 0 : if (userBufferMode_p)
6839 : {
6840 0 : dataBuffer_p = MSTransformations::weightSpectrum;
6841 : }
6842 : else
6843 : {
6844 0 : setTileShape(rowRef,getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM));
6845 : }
6846 0 : transformCubeOfData(vb,rowRef,vb->weightSpectrum(),getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),NULL,applicableSpectrum);
6847 :
6848 0 : if (userBufferMode_p)
6849 : {
6850 0 : dataBuffer_p = MSTransformations::sigmaSpectrum;
6851 : }
6852 : else
6853 : {
6854 0 : setTileShape(rowRef,getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM));
6855 : }
6856 : // VI/VB only allocates and populates sigmaSpectrum on request
6857 : // But its contents are not usable for this case
6858 : // So we should just create a local storage
6859 0 : Cube<Float> sigmaSpectrum;
6860 0 : sigmaSpectrum = vb->weightSpectrum(); // Copy constructor does not use reference semantics, but deep copy
6861 : // Apply transformation
6862 0 : arrayTransformInPlace(sigmaSpectrum, vi::AveragingTvi2::weightToSigma);
6863 : // TransformCubeOfData is either copyCubeOfData or separateCubeOfData
6864 0 : transformCubeOfData(vb,rowRef,sigmaSpectrum,getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),NULL,applicableSpectrum);
6865 : }
6866 : // Pure split operation
6867 : else
6868 : {
6869 : // TransformCubeOfData is either copyCubeOfData or separateCubeOfData
6870 0 : if (userBufferMode_p)
6871 : {
6872 0 : dataBuffer_p = MSTransformations::weightSpectrum;
6873 : }
6874 : else
6875 : {
6876 0 : setTileShape(rowRef,getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM));
6877 : }
6878 0 : transformCubeOfData(vb,rowRef,vb->weightSpectrum(),getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),NULL,applicableSpectrum);
6879 :
6880 0 : if (userBufferMode_p)
6881 : {
6882 0 : dataBuffer_p = MSTransformations::sigmaSpectrum;
6883 : }
6884 : else
6885 : {
6886 0 : setTileShape(rowRef,getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM));
6887 : }
6888 0 : transformCubeOfData(vb,rowRef,vb->sigmaSpectrum(),getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),NULL,applicableSpectrum);
6889 : }
6890 :
6891 : // Switch aux Weight propagation on
6892 0 : propagateWeights(propagateWeights_p);
6893 :
6894 : // Reset average and smooth kernels
6895 0 : setChannelAverageKernel(weightmode_p);
6896 0 : setSmoothingKernel(smoothmode_p);
6897 0 : setSmoothingFourierKernel(MSTransformations::plainSmooth);
6898 : }
6899 :
6900 0 : return;
6901 : }
6902 :
6903 :
6904 : // ----------------------------------------------------------------------------------------
6905 : // Set tile shape
6906 : // ----------------------------------------------------------------------------------------
6907 0 : template <class T> void MSTransformManager::setTileShape( RefRows &rowRef,
6908 : ArrayColumn<T> &outputDataCol)
6909 : {
6910 0 : IPosition outputCubeShape = getShape();
6911 0 : size_t nCorr = outputCubeShape(0);
6912 0 : size_t nChan = outputCubeShape(1);
6913 0 : ssize_t nRows = 1048576 / (sizeof(T)*nCorr*nChan);
6914 0 : IPosition outputPlaneShape(2,nCorr,nChan);
6915 0 : IPosition tileShape(3,nCorr,nChan,nRows);
6916 :
6917 0 : outputDataCol.setShape(rowRef.firstRow(),outputPlaneShape,tileShape);
6918 :
6919 0 : return;
6920 : }
6921 :
6922 : // explicit instatiation for the use from SDMSManager
6923 : template void MSTransformManager::setTileShape<Float>(RefRows &, ArrayColumn<Float> &);
6924 : template void MSTransformManager::setTileShape<bool>(RefRows &, ArrayColumn<bool> &);
6925 : template void MSTransformManager::setTileShape<Complex>(RefRows &, ArrayColumn<Complex> &);
6926 :
6927 : // ----------------------------------------------------------------------------------------
6928 : //
6929 : // ----------------------------------------------------------------------------------------
6930 0 : void MSTransformManager::transformAndWriteSpectrum( vi::VisBuffer2 *vb,
6931 : RefRows &rowRef,
6932 : const Cube<Float> &inputSpectrum,
6933 : ArrayColumn<Float> &outputCubeCol,
6934 : ArrayColumn<Float> &outputMatrixCol,
6935 : MSTransformations::weightTransformation weightTransformation,
6936 : bool /* flushSpectrumCube */)
6937 : {
6938 : // Dummy auxiliary weightSpectrum
6939 0 : const Cube<Float> applicableSpectrum;
6940 :
6941 : // Check if weight scaling has to be applied
6942 0 : Float weightScale = 0, sigmaScale = 0;
6943 0 : if (refFrameTransformation_p)
6944 : {
6945 0 : if ( (newWeightFactorMap_p.find(vb->spectralWindows()(0)) != newWeightFactorMap_p.end()) and
6946 0 : (newWeightFactorMap_p[vb->spectralWindows()(0)] != 1) )
6947 : {
6948 0 : weightScale = newWeightFactorMap_p[vb->spectralWindows()(0)];
6949 : }
6950 :
6951 0 : if ( (newSigmaFactorMap_p.find(vb->spectralWindows()(0)) != newSigmaFactorMap_p.end()) and
6952 0 : (newSigmaFactorMap_p[vb->spectralWindows()(0)] != 1) )
6953 : {
6954 0 : sigmaScale = newSigmaFactorMap_p[vb->spectralWindows()(0)];
6955 : }
6956 : }
6957 :
6958 : // Apply transformations
6959 0 : switch (weightTransformation)
6960 : {
6961 0 : case MSTransformations::transformWeight:
6962 : {
6963 0 : dataBuffer_p = MSTransformations::weightSpectrum;
6964 0 : transformCubeOfData(vb,rowRef,inputSpectrum,outputCubeCol,NULL,applicableSpectrum);
6965 :
6966 0 : if (weightScale > 0) *weightSpectrum_p *= weightScale;
6967 :
6968 0 : break;
6969 : }
6970 0 : case MSTransformations::transformWeightIntoSigma:
6971 : {
6972 0 : if (userBufferMode_p)
6973 : {
6974 0 : dataBuffer_p = MSTransformations::sigmaSpectrum;
6975 0 : transformCubeOfData(vb,rowRef,inputSpectrum,outputCubeCol,NULL,applicableSpectrum);
6976 0 : arrayTransformInPlace (*sigmaSpectrum_p,vi::AveragingTvi2::weightToSigma);
6977 :
6978 0 : if (sigmaScale > 0) *sigmaSpectrum_p *= sigmaScale;
6979 : }
6980 : else
6981 : {
6982 0 : transformCubeOfData(vb,rowRef,inputSpectrum,outputCubeCol,NULL,applicableSpectrum);
6983 0 : arrayTransformInPlace (*weightSpectrum_p,vi::AveragingTvi2::weightToSigma);
6984 :
6985 0 : if (sigmaScale > 0) *weightSpectrum_p *= sigmaScale;
6986 : }
6987 :
6988 0 : break;
6989 : }
6990 0 : case MSTransformations::weightIntoSigma:
6991 : {
6992 0 : if (userBufferMode_p)
6993 : {
6994 : // WeightSpectrum is always transformed before sigmaSpectrum
6995 : // so copy weightSpectrum into sigmaSpectrum
6996 0 : sigmaSpectrum_p->operator =(*weightSpectrum_p);
6997 0 : arrayTransformInPlace (*sigmaSpectrum_p,vi::AveragingTvi2::weightToSigma);
6998 :
6999 : // No need to scale in this case as it already happened before
7000 : }
7001 : else
7002 : {
7003 : // WeightSpectrum is always transformed before sigmaSpectrum
7004 : // so transform directly weightSpectrum into sigmaSpectrum
7005 0 : arrayTransformInPlace (*weightSpectrum_p,vi::AveragingTvi2::weightToSigma);
7006 :
7007 : // No need to scale in this case as it already happened before
7008 : }
7009 0 : break;
7010 : }
7011 : }
7012 :
7013 : // Write resulting cube
7014 0 : if ( (not userBufferMode_p) and flushWeightSpectrum_p)
7015 : {
7016 0 : setTileShape(rowRef,outputCubeCol);
7017 0 : writeCube(*weightSpectrum_p,outputCubeCol,rowRef);
7018 : }
7019 :
7020 : // Extract median matrix (nCorr x nRow)
7021 : // When separating SPWs this procedure computes the mean of each separated SPW
7022 : // Matrix<Float> medians = partialMedians(*weightSpectrum_p,IPosition(1,1),true);
7023 0 : if (userBufferMode_p)
7024 : {
7025 0 : switch (weightTransformation)
7026 : {
7027 0 : case MSTransformations::transformWeight:
7028 : {
7029 0 : weight_p->operator =(vi::AveragingTvi2::average(*weightSpectrum_p,*flagCube_p));
7030 0 : break;
7031 : }
7032 0 : case MSTransformations::transformWeightIntoSigma:
7033 : {
7034 0 : sigma_p->operator =(vi::AveragingTvi2::average(*sigmaSpectrum_p,*flagCube_p));
7035 0 : break;
7036 : }
7037 0 : case MSTransformations::weightIntoSigma:
7038 : {
7039 0 : sigma_p->operator =(vi::AveragingTvi2::average(*sigmaSpectrum_p,*flagCube_p));
7040 0 : break;
7041 : }
7042 : }
7043 : }
7044 : else
7045 : {
7046 0 : Matrix<Float> means = vi::AveragingTvi2::average(*weightSpectrum_p,*flagCube_p);
7047 0 : writeMatrix(means,outputMatrixCol,rowRef,1);
7048 : }
7049 :
7050 0 : return;
7051 : }
7052 :
7053 : // -----------------------------------------------------------------------
7054 : // Get *_SPECTRUM column to use depending on the input col
7055 : // -----------------------------------------------------------------------
7056 0 : const Cube<Float>& MSTransformManager::getApplicableSpectrum(vi::VisBuffer2 *vb, MS::PredefinedColumns datacol)
7057 : {
7058 0 : if (propagateWeights_p)
7059 : {
7060 0 : switch (datacol)
7061 : {
7062 0 : case MS::DATA:
7063 : {
7064 : // NOTE: There is room for optimization here if in the case of
7065 : // A.- Time average and single column operation
7066 : // B.- Single column in the input (George denied this)
7067 : // C.- Time average should not convert SIGMA_SPECTRUM to WEIGHT format if there is chan.avg downstream
7068 : // D.- SIGMA_SPECTRUM should be in WEIGHT format
7069 0 : return getWeightSpectrumFromSigmaSpectrum(vb);
7070 : break;
7071 : }
7072 0 : case MS::CORRECTED_DATA:
7073 : {
7074 0 : return vb->weightSpectrum();
7075 : break;
7076 : }
7077 0 : case MS::MODEL_DATA:
7078 : {
7079 : // Return either WEIGHT_SPECTRUM or SIGMA_SPECTRUM depending on the other accompany col
7080 0 : if (doingCorrected_p)
7081 : {
7082 0 : return vb->weightSpectrum();
7083 : }
7084 0 : else if (doingData_p)
7085 : {
7086 0 : return getWeightSpectrumFromSigmaSpectrum(vb);
7087 : }
7088 : // When doing only MODEL_DATA only FLAG cube is used, and applicable weightSpectrum must be flat unit
7089 : // The same convention is applied in VbAvg::accumulateElementForCubes for time average
7090 : else
7091 : {
7092 0 : return getWeightSpectrumFlat(vb);
7093 : }
7094 :
7095 : break;
7096 : }
7097 0 : default:
7098 : {
7099 0 : return vb->weightSpectrum();
7100 : break;
7101 : }
7102 : }
7103 : }
7104 : else
7105 : {
7106 0 : return weightSpectrumCubeDummy_p;
7107 : }
7108 : }
7109 :
7110 : // -----------------------------------------------------------------------
7111 : // Get output weight column
7112 : // -----------------------------------------------------------------------
7113 0 : ArrayColumn<Float>& MSTransformManager::getOutputWeightColumn(vi::VisBuffer2 *, MS::PredefinedColumns datacol)
7114 : {
7115 0 : if (userBufferMode_p)
7116 : {
7117 0 : return dummyWeightCol_p;
7118 : }
7119 : else
7120 : {
7121 0 : switch (datacol)
7122 : {
7123 0 : case MS::WEIGHT_SPECTRUM:
7124 : {
7125 0 : return outputMsCols_p->weightSpectrum();
7126 : break;
7127 : }
7128 0 : case MS::SIGMA_SPECTRUM:
7129 : {
7130 0 : return outputMsCols_p->sigmaSpectrum();
7131 : break;
7132 : }
7133 0 : case MS::WEIGHT:
7134 : {
7135 0 : return outputMsCols_p->weight();
7136 : break;
7137 : }
7138 0 : case MS::SIGMA:
7139 : {
7140 0 : return outputMsCols_p->sigma();
7141 : break;
7142 : }
7143 0 : default:
7144 : {
7145 0 : return outputMsCols_p->weight();
7146 : break;
7147 : }
7148 : }
7149 : }
7150 : }
7151 :
7152 :
7153 : // -----------------------------------------------------------------------
7154 : // Pupulate weightSpectrum derived from sigmaSpectrum
7155 : // -----------------------------------------------------------------------
7156 0 : const Cube<Float>& MSTransformManager::getWeightSpectrumFromSigmaSpectrum(vi::VisBuffer2 *vb)
7157 : {
7158 0 : if (weightSpectrumFromSigmaFilled_p)
7159 : {
7160 0 : return weightSpectrumCube_p;
7161 : }
7162 : else
7163 : {
7164 0 : weightSpectrumCube_p.resize(vb->getShape(),false);
7165 0 : weightSpectrumCube_p = vb->sigmaSpectrum(); // = Operator makes a copy
7166 0 : arrayTransformInPlace (weightSpectrumCube_p,vi::AveragingTvi2::sigmaToWeight);
7167 0 : weightSpectrumFromSigmaFilled_p = true;
7168 0 : return weightSpectrumCube_p;
7169 : }
7170 : }
7171 :
7172 : // -----------------------------------------------------------------------
7173 : // Populate a synthetic flat unit weightSpectrum to be use for MODEL_DATA
7174 : // -----------------------------------------------------------------------
7175 0 : const Cube<Float>& MSTransformManager::getWeightSpectrumFlat(vi::VisBuffer2 *vb)
7176 : {
7177 0 : if (weightSpectrumFlatFilled_p)
7178 : {
7179 0 : return weightSpectrumCubeFlat_p;
7180 : }
7181 0 : else if (weightSpectrumCubeFlat_p.shape().isEqual(vb->getShape()))
7182 : {
7183 0 : weightSpectrumFlatFilled_p = true;
7184 0 : return weightSpectrumCubeFlat_p;
7185 : }
7186 : else
7187 : {
7188 0 : weightSpectrumCubeFlat_p.resize(vb->getShape(),false);
7189 0 : weightSpectrumCubeFlat_p = 1.0f;
7190 0 : weightSpectrumFlatFilled_p = true;
7191 0 : return weightSpectrumCubeFlat_p;
7192 : }
7193 : }
7194 :
7195 : // -----------------------------------------------------------------------
7196 : // Generic method to write a Matrix from a VisBuffer into a ArrayColumn
7197 : // -----------------------------------------------------------------------
7198 0 : template <class T> void MSTransformManager::writeMatrix( const Matrix<T> &inputMatrix,
7199 : ArrayColumn<T> &outputCol,
7200 : RefRows &rowRef,
7201 : uInt nBlocks)
7202 : {
7203 0 : if (nBlocks == 1)
7204 : {
7205 0 : outputCol.putColumnCells(rowRef, inputMatrix);
7206 : }
7207 : else
7208 : {
7209 : // jagonzal (CAS-8492): Huge bug, each input row must
7210 : // be copied n times not the whole matrix n times
7211 0 : uInt outRowIdx = 0;
7212 0 : size_t nInputRows = inputMatrix.shape()(1);
7213 0 : Matrix<T> outputMatrix(IPosition(2,3,nInputRows*nBlocks));
7214 0 : for (size_t inputRowIdx = 0; inputRowIdx<nInputRows; inputRowIdx++)
7215 : {
7216 0 : for (uInt blockIdx = 0; blockIdx<nBlocks; blockIdx++)
7217 : {
7218 0 : outputMatrix.column(outRowIdx) = inputMatrix.column(inputRowIdx);
7219 0 : outRowIdx += 1;
7220 : }
7221 : }
7222 :
7223 0 : RefRows outRowRef(rowRef.firstRow(),rowRef.firstRow()+nInputRows*nBlocks-1);
7224 0 : outputCol.putColumnCells(outRowRef, outputMatrix);
7225 :
7226 : /*
7227 : uInt offset = 0;
7228 : for (uInt block_i=0;block_i<nBlocks;block_i++)
7229 : {
7230 : uInt startRow_i = rowRef.firstRow()+offset;
7231 : RefRows rowRef_i(startRow_i, startRow_i+inputMatrix.shape()(1)-1);
7232 : outputCol.putColumnCells(rowRef_i, inputMatrix);
7233 : offset += inputMatrix.shape()(1);
7234 : }
7235 : */
7236 : }
7237 0 : return;
7238 : }
7239 :
7240 : // -----------------------------------------------------------------------
7241 : // Generic method to write a Cube from a VisBuffer into a ArrayColumn
7242 : // -----------------------------------------------------------------------
7243 0 : template <class T> void MSTransformManager::writeCube( const Cube<T> &inputCube,
7244 : ArrayColumn<T> &outputCol,
7245 : RefRows &rowRef)
7246 : {
7247 0 : IPosition shape = inputCube.shape();
7248 0 : shape(2) = rowRef.nrows();
7249 : bool deleteIt;
7250 0 : Array<T> outputArray(shape,const_cast<T*>(inputCube.getStorage(deleteIt)),SHARE);
7251 0 : outputCol.putColumnCells(rowRef, outputArray);
7252 :
7253 0 : return;
7254 : }
7255 :
7256 : // explicit instatiation for the use from SDMSManager
7257 : template void MSTransformManager::writeCube<bool>(const Cube<bool> &, ArrayColumn<bool> &, RefRows &);
7258 :
7259 : // -----------------------------------------------------------------------
7260 : //
7261 : // -----------------------------------------------------------------------
7262 0 : void MSTransformManager::transformCubeOfData( vi::VisBuffer2 *vb,
7263 : RefRows &rowRef,
7264 : const Cube<Complex> &inputDataCube,
7265 : ArrayColumn<Complex> &outputDataCol,
7266 : ArrayColumn<bool> *outputFlagCol,
7267 : const Cube<Float> &inputWeightCube)
7268 : {
7269 0 : (*this.*transformCubeOfDataComplex_p)(vb,rowRef,inputDataCube,outputDataCol,outputFlagCol,inputWeightCube);
7270 0 : return;
7271 : }
7272 :
7273 : // -----------------------------------------------------------------------
7274 : //
7275 : // -----------------------------------------------------------------------
7276 0 : void MSTransformManager::transformCubeOfData( vi::VisBuffer2 *vb,
7277 : RefRows &rowRef,
7278 : const Cube<Float> &inputDataCube,
7279 : ArrayColumn<Float> &outputDataCol,
7280 : ArrayColumn<bool> *outputFlagCol,
7281 : const Cube<Float> &inputWeightCube)
7282 : {
7283 0 : (*this.*transformCubeOfDataFloat_p)(vb,rowRef,inputDataCube,outputDataCol,outputFlagCol,inputWeightCube);
7284 0 : return;
7285 : }
7286 :
7287 : // -----------------------------------------------------------------------
7288 : //
7289 : // -----------------------------------------------------------------------
7290 0 : template <class T> void MSTransformManager::copyCubeOfData( vi::VisBuffer2 *vb,
7291 : RefRows &rowRef,
7292 : const Cube<T> &inputDataCube,
7293 : ArrayColumn<T> &outputDataCol,
7294 : ArrayColumn<bool> *outputFlagCol,
7295 : const Cube<Float> & /* inputWeightCube */)
7296 : {
7297 0 : writeCube(inputDataCube,outputDataCol,rowRef);
7298 0 : if (outputFlagCol != NULL)
7299 : {
7300 0 : writeCube(vb->flagCube(),*outputFlagCol,rowRef);
7301 : }
7302 :
7303 0 : return;
7304 : }
7305 :
7306 : // -----------------------------------------------------------------------
7307 : // combine - for combinespws=True
7308 : // -----------------------------------------------------------------------
7309 0 : template <class T> void MSTransformManager::combineCubeOfData( vi::VisBuffer2 *vb,
7310 : RefRows &rowRef,
7311 : const Cube<T> &inputDataCube,
7312 : ArrayColumn<T> &outputDataCol,
7313 : ArrayColumn<bool> *outputFlagCol,
7314 : const Cube<Float> &inputWeightCube)
7315 : {
7316 : // Write flag column too?
7317 0 : if (outputFlagCol != NULL)
7318 : {
7319 0 : writeOutputFlagsPlaneSlices_p = &MSTransformManager::writeOutputFlagsPlaneSlices;
7320 0 : writeOutputFlagsPlaneReshapedSlices_p = &MSTransformManager::writeOutputFlagsPlaneReshapedSlices;
7321 0 : writeOutputFlagsPlane_p = &MSTransformManager::writeOutputFlagsPlane;
7322 : }
7323 : else
7324 : {
7325 0 : writeOutputFlagsPlaneSlices_p = &MSTransformManager::dontWriteOutputFlagsPlaneSlices;
7326 0 : writeOutputFlagsPlaneReshapedSlices_p = &MSTransformManager::dontWriteOutputPlaneReshapedSlices;
7327 0 : writeOutputFlagsPlane_p = &MSTransformManager::dontWriteOutputFlagsPlane;
7328 : }
7329 :
7330 : // Get input flag cube
7331 0 : const Cube<bool> inputFlagCube = vb->flagCube();
7332 :
7333 : // Get input SPWs and exposures
7334 0 : Vector<Int> spws = vb->spectralWindows();
7335 0 : Vector<Double> exposures = vb->exposure();
7336 :
7337 : // Get input cube shape
7338 0 : IPosition inputCubeShape = inputDataCube.shape();
7339 0 : uInt nInputCorrelations = inputCubeShape(0);
7340 :
7341 : // Initialize input planes
7342 0 : IPosition inputPlaneShape(2,nInputCorrelations, numOfCombInputChanMap_p[0]);
7343 0 : Matrix<Double> normalizingFactorPlane(inputPlaneShape);
7344 0 : Matrix<T> inputPlaneData(inputPlaneShape);
7345 0 : Matrix<bool> inputPlaneFlags(inputPlaneShape,false);
7346 0 : Matrix<Float> inputPlaneWeights(inputPlaneShape);
7347 :
7348 : // Initialize output planes
7349 0 : IPosition outputPlaneShape(2,nInputCorrelations, inputOutputSpwMap_p[0].second.NUM_CHAN);
7350 0 : Matrix<T> outputPlaneData(outputPlaneShape);
7351 0 : Matrix<bool> outputPlaneFlags(outputPlaneShape);
7352 :
7353 0 : Int spw = 0;
7354 : Double weight;
7355 : uInt inputChannel;
7356 : bool inputChanelFlag;
7357 : Double normalizingFactor;
7358 0 : uInt row = 0, baseline_index = 0;
7359 0 : vector<uInt> baselineRows;
7360 0 : map<Int, uInt> spwRowMap;
7361 0 : map<Int, uInt>::iterator spwRowMapIter;
7362 0 : map<Int, uInt> spwFractionCountsMap;
7363 0 : bool unityContributors = false;
7364 0 : vector< channelContribution > contributions;
7365 0 : vector< channelContribution >::iterator contributionsIter;
7366 0 : map < Int , map < uInt, bool > > removeContributionsMap;
7367 :
7368 0 : bool combinationOfSPWsWithDifferentExposure = false;
7369 0 : Double exposure = 0;
7370 :
7371 0 : relativeRow_p = 0; // Initialize relative row for buffer mode
7372 0 : for (baselineMap::iterator iter = baselineMap_p.begin(); iter != baselineMap_p.end(); iter++)
7373 : {
7374 : // Initialize input plane
7375 0 : inputPlaneData = 0.0;
7376 :
7377 : // Initialize weights plane
7378 0 : inputPlaneWeights = 0.0;
7379 :
7380 : // Initialize normalizing factor plane
7381 0 : normalizingFactorPlane = 0.0;
7382 :
7383 : // Fill input plane to benefit from contiguous access to the input cube
7384 0 : baselineRows = iter->second;
7385 :
7386 : // Create spw-row map for this baseline and initialize detection of SPWs with different exposure
7387 0 : spwRowMap.clear();
7388 0 : if (combinationOfSPWsWithDifferentExposure_p and (inputWeightCube.shape().isEqual(inputCubeShape)))
7389 : {
7390 0 : combinationOfSPWsWithDifferentExposure = true;
7391 0 : addWeightSpectrumContribution_p = &MSTransformManager::addWeightSpectrumContribution;
7392 0 : for (vector<uInt>::iterator iter_row = baselineRows.begin();iter_row != baselineRows.end(); iter_row++)
7393 : {
7394 0 : row = *iter_row;
7395 0 : spw = spws(row);
7396 0 : spwRowMap[spw]=row;
7397 : }
7398 : }
7399 : else
7400 : {
7401 0 : exposure = exposures(*baselineRows.begin());
7402 0 : combinationOfSPWsWithDifferentExposure = false;
7403 0 : for (vector<uInt>::iterator iter_row = baselineRows.begin();iter_row != baselineRows.end(); iter_row++)
7404 : {
7405 0 : row = *iter_row;
7406 0 : spw = spws(row);
7407 0 : spwRowMap[spw]=row;
7408 :
7409 : // In the case of *_SPECTRUM inputWeightCube is dummy
7410 0 : if ((abs(exposure - exposures(row)) > FLT_EPSILON) and (inputWeightCube.shape().isEqual(inputCubeShape)))
7411 : {
7412 0 : combinationOfSPWsWithDifferentExposure = true;
7413 : }
7414 : }
7415 :
7416 0 : if (combinationOfSPWsWithDifferentExposure)
7417 : {
7418 0 : combinationOfSPWsWithDifferentExposure_p = true;
7419 0 : addWeightSpectrumContribution_p = &MSTransformManager::addWeightSpectrumContribution;
7420 0 : if (inputWeightSpectrumAvailable_p)
7421 : {
7422 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
7423 : << "Detected combination of SPWs with different EXPOSURE "<< endl
7424 : << "Will use WEIGHT_SPECTRUM to combine them "<< endl
7425 0 : << LogIO::POST;
7426 : }
7427 : else
7428 : {
7429 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
7430 : << "Detected combination of SPWs with different EXPOSURE "<< endl
7431 : << "Will use WEIGHT to combine them (WEIGHT_SPECTRUM not available)"<< endl
7432 0 : << LogIO::POST;
7433 : }
7434 : }
7435 : else
7436 : {
7437 0 : addWeightSpectrumContribution_p = &MSTransformManager::dontAddWeightSpectrumContribution;
7438 : }
7439 : }
7440 :
7441 :
7442 0 : for (uInt outputChannel = 0; outputChannel < numOfCombInputChanMap_p[0]; outputChannel++)
7443 : {
7444 0 : contributions = inputOutputChanFactorMap_p[outputChannel];
7445 :
7446 0 : for (uInt pol = 0; pol < inputDataCube.shape()(0); pol++)
7447 : {
7448 0 : spwFractionCountsMap.clear();
7449 0 : unityContributors = false;
7450 :
7451 : // Go through list of contributors for this output channel and polarization and gather flags info
7452 0 : for (contributionsIter = contributions.begin(); contributionsIter != contributions.end(); contributionsIter++)
7453 : {
7454 0 : inputChannel = contributionsIter->inpChannel;
7455 0 : weight = contributionsIter->weight;
7456 :
7457 : // Add WEIGHT_SPECTRUM to the contribution
7458 0 : (*this.*addWeightSpectrumContribution_p)(weight,pol,inputChannel,row,inputWeightCube);
7459 :
7460 : // Find row for this input channel
7461 0 : spw = contributionsIter->inpSpw;
7462 0 : spwRowMapIter = spwRowMap.find(spw);
7463 0 : if (spwRowMapIter != spwRowMap.end())
7464 : {
7465 0 : row = spwRowMap[spw];
7466 :
7467 : // Fill flags info
7468 0 : inputChanelFlag = inputFlagCube(pol,inputChannel,row);
7469 0 : contributionsIter->flag = inputChanelFlag;
7470 :
7471 : // Count input channel if it is not flagged and has non-unity overlapping fraction
7472 0 : if (weight<1.0)
7473 : {
7474 0 : if (!inputChanelFlag) spwFractionCountsMap[spw] += 1;
7475 : }
7476 : // Count if we have valid unity contributors, otherwise we don't discard non-unity contributors
7477 : else
7478 : {
7479 0 : unityContributors = true;
7480 : }
7481 : }
7482 : else
7483 : {
7484 : // Fill flags info
7485 0 : contributionsIter->flag = true;
7486 : }
7487 : }
7488 :
7489 : // Remove contributions from SPWs with odd numbers of contributors with non-unity
7490 : // overlap fraction which could influence the averaging asymmetrically
7491 0 : for (contributionsIter = contributions.begin(); contributionsIter != contributions.end(); contributionsIter++)
7492 : {
7493 0 : inputChannel = contributionsIter->inpChannel;
7494 0 : weight = contributionsIter->weight;
7495 0 : spw = contributionsIter->inpSpw;
7496 :
7497 : // Find row for this input channel
7498 0 : if (!contributionsIter->flag)
7499 : {
7500 : // jagonzal: Caution, accessing the map populates it!!!
7501 0 : row = spwRowMap[spw];
7502 :
7503 0 : if ((spwFractionCountsMap[spw] % 2 == 0) or (weight >= 1.0) or (!unityContributors))
7504 : {
7505 0 : inputPlaneData(pol,outputChannel) += weight*inputDataCube(pol,inputChannel,row);
7506 0 : normalizingFactorPlane(pol,outputChannel) += weight;
7507 0 : (*this.*fillWeightsPlane_p)(pol,inputChannel,outputChannel,row,inputWeightCube,inputPlaneWeights,weight);
7508 : }
7509 : }
7510 : }
7511 : }
7512 : }
7513 :
7514 : // Normalize combined data and determine input plane flags
7515 0 : inputPlaneFlags = false;
7516 0 : for (uInt outputChannel = 0; outputChannel < numOfCombInputChanMap_p[0]; outputChannel++)
7517 : {
7518 0 : for (uInt pol = 0; pol < nInputCorrelations; pol++)
7519 : {
7520 0 : normalizingFactor = normalizingFactorPlane(pol,outputChannel);
7521 0 : if (normalizingFactor >= 0.999999) // we lose a couple significant digits in the subtractions
7522 : {
7523 0 : inputPlaneData(pol,outputChannel) /= normalizingFactorPlane(pol,outputChannel);
7524 :
7525 : // Normalize weights plane
7526 0 : (*this.*normalizeWeightsPlane_p)(pol,outputChannel,inputPlaneWeights,normalizingFactorPlane);
7527 : }
7528 0 : else if (normalizingFactor > 0)
7529 : {
7530 0 : inputPlaneData(pol,outputChannel) /= normalizingFactorPlane(pol,outputChannel);
7531 0 : inputPlaneFlags(pol,outputChannel) = true;
7532 : }
7533 : else
7534 : {
7535 0 : inputPlaneFlags(pol,outputChannel) = true;
7536 : }
7537 : }
7538 : }
7539 :
7540 : // Initialize output flags plane
7541 0 : outputPlaneFlags = false;
7542 :
7543 : // Transform input planes and write them
7544 0 : transformAndWritePlaneOfData( 0,rowRef.firstRow()+baseline_index*nspws_p,
7545 : inputPlaneData,inputPlaneFlags,inputPlaneWeights,
7546 : outputPlaneData,outputPlaneFlags,outputDataCol,outputFlagCol);
7547 :
7548 :
7549 0 : relativeRow_p += nspws_p;
7550 0 : baseline_index += 1;
7551 : }
7552 :
7553 0 : return;
7554 : }
7555 :
7556 : // -----------------------------------------------------------------------
7557 : //
7558 : // -----------------------------------------------------------------------
7559 0 : void MSTransformManager::addWeightSpectrumContribution( Double &weight,
7560 : uInt &pol,
7561 : uInt &inputChannel,
7562 : uInt &row,
7563 : const Cube<Float> &inputWeightsCube)
7564 : {
7565 0 : weight *= inputWeightsCube(pol,inputChannel,row);
7566 :
7567 0 : return;
7568 : }
7569 :
7570 : // -----------------------------------------------------------------------
7571 : //
7572 : // -----------------------------------------------------------------------
7573 0 : void MSTransformManager::dontAddWeightSpectrumContribution( Double &,
7574 : uInt &,
7575 : uInt &,
7576 : uInt &,
7577 : const Cube<Float> &)
7578 : {
7579 0 : return;
7580 : }
7581 :
7582 : // -----------------------------------------------------------------------
7583 : //
7584 : // -----------------------------------------------------------------------
7585 0 : void MSTransformManager::fillWeightsPlane( uInt pol,
7586 : uInt inputChannel,
7587 : uInt outputChannel,
7588 : uInt inputRow,
7589 : const Cube<Float> &inputWeightsCube,
7590 : Matrix<Float> &inputWeightsPlane,
7591 : Double factor)
7592 : {
7593 0 : inputWeightsPlane(pol,outputChannel) += factor*inputWeightsCube(pol,inputChannel,inputRow);
7594 :
7595 0 : return;
7596 : }
7597 :
7598 : // -----------------------------------------------------------------------
7599 : //
7600 : // -----------------------------------------------------------------------
7601 0 : void MSTransformManager::normalizeWeightsPlane( uInt pol,
7602 : uInt outputChannel,
7603 : Matrix<Float> &inputPlaneWeights,
7604 : Matrix<Double> &normalizingFactorPlane)
7605 : {
7606 0 : inputPlaneWeights(pol,outputChannel) /= normalizingFactorPlane(pol,outputChannel);
7607 :
7608 0 : return;
7609 : }
7610 :
7611 : // -----------------------------------------------------------------------
7612 : //
7613 : // -----------------------------------------------------------------------
7614 0 : template <class T> void MSTransformManager::averageCubeOfData( vi::VisBuffer2 *vb,
7615 : RefRows &rowRef,
7616 : const Cube<T> &inputDataCube,
7617 : ArrayColumn<T> &outputDataCol,
7618 : ArrayColumn<bool> *outputFlagCol,
7619 : const Cube<Float> &inputWeightCube)
7620 : {
7621 : // Get input spw and flag and weight cubes
7622 0 : Int inputSpw = vb->spectralWindows()(0);
7623 0 : const Cube<bool> inputFlagsCube = vb->flagCube();
7624 :
7625 : // Define output plane shape
7626 0 : IPosition outputPlaneShape = IPosition(2,inputDataCube.shape()(0), numOfOutChanMap_p[inputSpw]);
7627 :
7628 0 : transformAndWriteCubeOfData( inputSpw, rowRef,
7629 : inputDataCube, inputFlagsCube, inputWeightCube,
7630 : outputPlaneShape, outputDataCol, outputFlagCol);
7631 :
7632 0 : return;
7633 : }
7634 :
7635 : // -----------------------------------------------------------------------
7636 : //
7637 : // -----------------------------------------------------------------------
7638 0 : template <class T> void MSTransformManager::smoothCubeOfData( vi::VisBuffer2 *vb,
7639 : RefRows &rowRef,
7640 : const Cube<T> &inputDataCube,
7641 : ArrayColumn<T> &outputDataCol,
7642 : ArrayColumn<bool> *outputFlagCol,
7643 : const Cube<Float> &inputWeightCube)
7644 : {
7645 : // Get input spw and flag cube
7646 0 : Int inputSpw = vb->spectralWindows()(0);
7647 0 : const Cube<bool> inputFlagsCube = vb->flagCube();
7648 :
7649 : // Define output plane shape
7650 0 : IPosition outputPlaneShape = IPosition(2,inputDataCube.shape()(0), inputDataCube.shape()(1));
7651 :
7652 : // Transform cube
7653 0 : transformAndWriteCubeOfData( inputSpw, rowRef,
7654 : inputDataCube, inputFlagsCube, inputWeightCube,
7655 : outputPlaneShape, outputDataCol, outputFlagCol);
7656 :
7657 0 : return;
7658 : }
7659 :
7660 : // -----------------------------------------------------------------------
7661 : //
7662 : // -----------------------------------------------------------------------
7663 0 : template <class T> void MSTransformManager::regridCubeOfData( vi::VisBuffer2 *vb,
7664 : RefRows &rowRef,
7665 : const Cube<T> &inputDataCube,
7666 : ArrayColumn<T> &outputDataCol,
7667 : ArrayColumn<bool> *outputFlagCol,
7668 : const Cube<Float> &inputWeightCube)
7669 : {
7670 : // Get input spw and flag cube
7671 0 : Int inputSpw = vb->spectralWindows()(0);
7672 0 : const Cube<bool> inputFlagsCube = vb->flagCube();
7673 :
7674 : // Define output plane shape
7675 0 : IPosition outputPlaneShape = IPosition(2,inputDataCube.shape()(0), inputOutputSpwMap_p[inputSpw].second.NUM_CHAN);
7676 :
7677 : // Transform cube
7678 0 : transformAndWriteCubeOfData( inputSpw, rowRef,
7679 : inputDataCube, inputFlagsCube, inputWeightCube,
7680 : outputPlaneShape, outputDataCol, outputFlagCol);
7681 :
7682 0 : return;
7683 : }
7684 :
7685 : // -----------------------------------------------------------------------
7686 : //
7687 : // -----------------------------------------------------------------------
7688 0 : template <class T> void MSTransformManager::transformAndWriteCubeOfData( Int inputSpw,
7689 : RefRows &rowRef,
7690 : const Cube<T> &inputDataCube,
7691 : const Cube<bool> &inputFlagsCube,
7692 : const Cube<Float> &inputWeightsCube,
7693 : IPosition &outputPlaneShape,
7694 : ArrayColumn<T> &outputDataCol,
7695 : ArrayColumn<bool> *outputFlagCol)
7696 : {
7697 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager",__FUNCTION__)
7698 : << "Shape of input data cube: " << inputDataCube.shape()
7699 : << ", output plane shape: " << outputPlaneShape
7700 0 : << LogIO::POST;
7701 :
7702 : // Write flag column too?
7703 0 : if (outputFlagCol != NULL)
7704 : {
7705 0 : writeOutputFlagsPlaneSlices_p = &MSTransformManager::writeOutputFlagsPlaneSlices;
7706 0 : writeOutputFlagsPlaneReshapedSlices_p = &MSTransformManager::writeOutputFlagsPlaneReshapedSlices;
7707 0 : writeOutputFlagsPlane_p = &MSTransformManager::writeOutputFlagsPlane;
7708 : }
7709 : else
7710 : {
7711 0 : writeOutputFlagsPlaneSlices_p = &MSTransformManager::dontWriteOutputFlagsPlaneSlices;
7712 0 : writeOutputFlagsPlaneReshapedSlices_p = &MSTransformManager::dontWriteOutputPlaneReshapedSlices;
7713 0 : writeOutputFlagsPlane_p = &MSTransformManager::dontWriteOutputFlagsPlane;
7714 : }
7715 :
7716 : // Get input number of rows
7717 0 : uInt nInputRows = inputDataCube.shape()(2);
7718 :
7719 : // Initialize input planes
7720 0 : Matrix<T> inputPlaneData;
7721 0 : Matrix<bool> inputPlaneFlags;
7722 0 : Matrix<Float> inputPlaneWeights;
7723 :
7724 : // Initialize output planes
7725 0 : Matrix<T> outputPlaneData(outputPlaneShape);
7726 0 : Matrix<bool> outputPlaneFlags(outputPlaneShape);
7727 :
7728 : // Iterate row by row in order to extract a plane
7729 0 : relativeRow_p = 0; // Initialize relative row for buffer mode
7730 0 : for (uInt rowIndex=0; rowIndex < nInputRows; rowIndex++)
7731 : {
7732 : // Initialize output flags plane
7733 0 : outputPlaneFlags = false;
7734 :
7735 : // Fill input planes by reference
7736 0 : inputPlaneData = inputDataCube.xyPlane(rowIndex);
7737 0 : inputPlaneFlags = inputFlagsCube.xyPlane(rowIndex);
7738 0 : (*this.*setWeightsPlaneByReference_p)(rowIndex,inputWeightsCube,inputPlaneWeights);
7739 :
7740 : // Transform input planes and write them
7741 0 : transformAndWritePlaneOfData( inputSpw,rowRef.firstRow()+rowIndex*nspws_p,
7742 : inputPlaneData,inputPlaneFlags,inputPlaneWeights,
7743 : outputPlaneData,outputPlaneFlags,outputDataCol,outputFlagCol);
7744 :
7745 0 : relativeRow_p += nspws_p;
7746 : }
7747 :
7748 0 : return;
7749 : }
7750 :
7751 : // -----------------------------------------------------------------------
7752 : //
7753 : // -----------------------------------------------------------------------
7754 0 : template <class T> void MSTransformManager::separateCubeOfData( vi::VisBuffer2 *vb,
7755 : RefRows &rowRef,
7756 : const Cube<T> &inputDataCube,
7757 : ArrayColumn<T> &outputDataCol,
7758 : ArrayColumn<bool> *outputFlagCol,
7759 : const Cube<Float> & /* inputWeightCube */)
7760 : {
7761 : // Write flag column too?
7762 0 : if (outputFlagCol != NULL)
7763 : {
7764 0 : writeOutputFlagsPlaneSlices_p = &MSTransformManager::writeOutputFlagsPlaneSlices;
7765 0 : writeOutputFlagsPlaneReshapedSlices_p = &MSTransformManager::writeOutputFlagsPlaneReshapedSlices;
7766 0 : writeOutputFlagsPlane_p = &MSTransformManager::writeOutputFlagsPlane;
7767 : }
7768 : else
7769 : {
7770 0 : writeOutputFlagsPlaneSlices_p = &MSTransformManager::dontWriteOutputFlagsPlaneSlices;
7771 0 : writeOutputFlagsPlaneReshapedSlices_p = &MSTransformManager::dontWriteOutputPlaneReshapedSlices;
7772 0 : writeOutputFlagsPlane_p = &MSTransformManager::dontWriteOutputFlagsPlane;
7773 : }
7774 :
7775 : // Get input flags, spw and number of rows
7776 0 : uInt nInputRows = inputDataCube.shape()(2);
7777 0 : const Cube<bool> inputFlagsCube = vb->flagCube();
7778 :
7779 : // Initialize input planes
7780 0 : Matrix<T> inputPlaneData;
7781 0 : Matrix<bool> inputPlaneFlags;
7782 :
7783 : // Iterate row by row in order to extract a plane
7784 0 : relativeRow_p = 0; // Initialize relative row for buffer mode
7785 0 : for (uInt rowIndex=0; rowIndex < nInputRows; rowIndex++)
7786 : {
7787 : // Fill input planes by reference
7788 0 : inputPlaneData = inputDataCube.xyPlane(rowIndex);
7789 0 : inputPlaneFlags = inputFlagsCube.xyPlane(rowIndex);
7790 :
7791 : // Directly write output plane
7792 0 : writeOutputPlanes( rowRef.firstRow()+rowIndex*nspws_p,
7793 : inputPlaneData,inputPlaneFlags,
7794 : outputDataCol,*outputFlagCol);
7795 :
7796 0 : relativeRow_p += nspws_p;
7797 : }
7798 :
7799 0 : return;
7800 : }
7801 :
7802 : // -----------------------------------------------------------------------
7803 : //
7804 : // -----------------------------------------------------------------------
7805 0 : void MSTransformManager::setWeightsPlaneByReference( uInt inputRow,
7806 : const Cube<Float> &inputWeightsCube,
7807 : Matrix<Float> &inputWeightsPlane)
7808 : {
7809 0 : inputWeightsPlane = inputWeightsCube.xyPlane(inputRow);
7810 0 : }
7811 :
7812 : // -----------------------------------------------------------------------
7813 : //
7814 : // -----------------------------------------------------------------------
7815 0 : template <class T> void MSTransformManager::transformAndWritePlaneOfData( Int inputSpw,
7816 : uInt row,
7817 : Matrix<T> &inputDataPlane,
7818 : Matrix<bool> &inputFlagsPlane,
7819 : Matrix<Float> &inputWeightsPlane,
7820 : Matrix<T> &outputDataPlane,
7821 : Matrix<bool> &outputFlagsPlane,
7822 : ArrayColumn<T> &outputDataCol,
7823 : ArrayColumn<bool> *outputFlagCol)
7824 : {
7825 : // Get input number of correlations
7826 0 : uInt nCorrs = inputDataPlane.shape()(0);
7827 :
7828 : // Get output plane shape
7829 0 : IPosition outputPlaneShape = outputDataPlane.shape();
7830 :
7831 : // Initialize vectors
7832 0 : Vector<T> inputDataStripe;
7833 0 : Vector<bool> inputFlagsStripe;
7834 0 : Vector<Float> inputWeightsStripe;
7835 0 : Vector<T> outputDataStripe;
7836 0 : Vector<bool> outputFlagsStripe;
7837 :
7838 : // Iterate correlation by correlation in order to extract a vector
7839 0 : for (uInt corrIndex=0; corrIndex < nCorrs; corrIndex++)
7840 : {
7841 : // Fill input stripes by reference
7842 0 : inputDataStripe.reference(inputDataPlane.row(corrIndex));
7843 0 : inputFlagsStripe.reference(inputFlagsPlane.row(corrIndex));
7844 0 : (*this.*setWeightStripeByReference_p)(corrIndex,inputWeightsPlane,inputWeightsStripe);
7845 :
7846 : // Fill output stripes by reference
7847 0 : outputDataStripe.reference(outputDataPlane.row(corrIndex));
7848 0 : outputFlagsStripe.reference(outputFlagsPlane.row(corrIndex));
7849 :
7850 0 : transformStripeOfData(inputSpw,inputDataStripe,inputFlagsStripe,
7851 : inputWeightsStripe,outputDataStripe,outputFlagsStripe);
7852 : }
7853 :
7854 : // Write output planes
7855 0 : writeOutputPlanes(row,outputDataPlane,outputFlagsPlane,outputDataCol,*outputFlagCol);
7856 0 : }
7857 :
7858 : // -----------------------------------------------------------------------
7859 : //
7860 : // -----------------------------------------------------------------------
7861 0 : void MSTransformManager::writeOutputPlanes( uInt row,
7862 : Matrix<Complex> &outputDataPlane,
7863 : Matrix<bool> &outputFlagsPlane,
7864 : ArrayColumn<Complex> &outputDataCol,
7865 : ArrayColumn<bool> &outputFlagCol)
7866 : {
7867 0 : (*this.*writeOutputPlanesComplex_p)(row,outputDataPlane,outputFlagsPlane,outputDataCol,outputFlagCol);
7868 0 : }
7869 :
7870 : // -----------------------------------------------------------------------
7871 : //
7872 : // -----------------------------------------------------------------------
7873 0 : void MSTransformManager::writeOutputPlanes( uInt row,
7874 : Matrix<Float> &outputDataPlane,
7875 : Matrix<bool> &outputFlagsPlane,
7876 : ArrayColumn<Float> &outputDataCol,
7877 : ArrayColumn<bool> &outputFlagCol)
7878 : {
7879 0 : (*this.*writeOutputPlanesFloat_p)(row,outputDataPlane,outputFlagsPlane,outputDataCol,outputFlagCol);
7880 0 : }
7881 :
7882 : // -----------------------------------------------------------------------
7883 : //
7884 : // -----------------------------------------------------------------------
7885 0 : void MSTransformManager::setOutputbuffer(Cube<Complex> *& dataBufferPointer,Cube<bool> *& flagBufferPointer)
7886 : {
7887 0 : switch (dataBuffer_p)
7888 : {
7889 0 : case MSTransformations::visCube:
7890 : {
7891 0 : dataBufferPointer=visCube_p;
7892 0 : if (userBufferMode_p)
7893 : {
7894 0 : flagBufferPointer = flagCube_p;
7895 : }
7896 : else
7897 : {
7898 0 : flagBufferPointer = NULL;
7899 : }
7900 0 : break;
7901 : }
7902 0 : case MSTransformations::visCubeCorrected:
7903 : {
7904 0 : dataBufferPointer=visCubeCorrected_p;
7905 0 : if (userBufferMode_p)
7906 : {
7907 0 : flagBufferPointer = flagCube_p;
7908 : }
7909 : else
7910 : {
7911 0 : flagBufferPointer = NULL;
7912 : }
7913 0 : break;
7914 : }
7915 0 : case MSTransformations::visCubeModel:
7916 : {
7917 0 : dataBufferPointer=visCubeModel_p;
7918 0 : if (userBufferMode_p)
7919 : {
7920 0 : flagBufferPointer = flagCube_p;
7921 : }
7922 : else
7923 : {
7924 0 : flagBufferPointer = NULL;
7925 : };
7926 0 : break;
7927 : }
7928 0 : default:
7929 : {
7930 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
7931 : << " Data buffer not specified"
7932 0 : << LogIO::POST;
7933 0 : dataBufferPointer=NULL;
7934 0 : flagBufferPointer=NULL;
7935 0 : break;
7936 : }
7937 : }
7938 :
7939 0 : return;
7940 : }
7941 :
7942 : // -----------------------------------------------------------------------
7943 : //
7944 : // -----------------------------------------------------------------------
7945 0 : void MSTransformManager::setOutputbuffer(Cube<Float> *& dataBufferPointer,Cube<bool> *& flagBufferPointer)
7946 : {
7947 0 : switch (dataBuffer_p)
7948 : {
7949 0 : case MSTransformations::visCubeFloat:
7950 : {
7951 0 : dataBufferPointer=visCubeFloat_p;
7952 0 : if (userBufferMode_p)
7953 : {
7954 0 : flagBufferPointer = flagCube_p;
7955 : }
7956 : else
7957 : {
7958 0 : flagBufferPointer = NULL;
7959 : };
7960 0 : break;
7961 : }
7962 0 : case MSTransformations::weightSpectrum:
7963 : {
7964 0 : dataBufferPointer=weightSpectrum_p;
7965 : // In buffer mode we already have a memory resident flagCube
7966 : // And the vector transformations use vectors from a dynamically initialize matrixes
7967 0 : if (userBufferMode_p)
7968 : {
7969 0 : flagBufferPointer=NULL;
7970 : }
7971 : else
7972 : {
7973 0 : flagBufferPointer = flagCube_p;
7974 : }
7975 0 : break;
7976 : }
7977 0 : case MSTransformations::sigmaSpectrum:
7978 : {
7979 0 : dataBufferPointer=sigmaSpectrum_p;
7980 : // In buffer mode we already have a memory resident flagCube
7981 : // And the vector transformations use vectors from a dynamically initialize matrixes
7982 0 : if (userBufferMode_p)
7983 : {
7984 0 : flagBufferPointer=NULL;
7985 : }
7986 : else
7987 : {
7988 0 : flagBufferPointer = flagCube_p;
7989 : }
7990 0 : break;
7991 : }
7992 0 : default:
7993 : {
7994 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
7995 : << " Data buffer not specified"
7996 0 : << LogIO::POST;
7997 0 : dataBufferPointer=NULL;
7998 0 : flagBufferPointer = NULL;
7999 0 : break;
8000 : }
8001 : }
8002 :
8003 0 : return;
8004 : }
8005 :
8006 : // -----------------------------------------------------------------------
8007 : //
8008 : // -----------------------------------------------------------------------
8009 0 : template <class T> void MSTransformManager::bufferOutputPlanes( uInt ,
8010 : Matrix<T> &outputDataPlane,
8011 : Matrix<bool> &outputFlagsPlane,
8012 : ArrayColumn<T> &,
8013 : ArrayColumn<bool> &)
8014 : {
8015 : // Get buffer pointers
8016 : Cube<T> *dataBufferPointer;
8017 : Cube<bool> *flagBufferPointer;
8018 0 : setOutputbuffer(dataBufferPointer,flagBufferPointer);
8019 :
8020 : // Copy data to buffer
8021 0 : dataBufferPointer->xyPlane(relativeRow_p) = outputDataPlane;
8022 :
8023 : // Copy flags to buffer
8024 0 : if (flagBufferPointer != NULL)
8025 : {
8026 0 : flagBufferPointer->xyPlane(relativeRow_p) = outputFlagsPlane;
8027 : }
8028 :
8029 0 : return;
8030 : }
8031 :
8032 : // -----------------------------------------------------------------------
8033 : //
8034 : // -----------------------------------------------------------------------
8035 0 : template <class T> void MSTransformManager::bufferOutputPlanesInSlices( uInt,
8036 : Matrix<T> &outputDataPlane,
8037 : Matrix<bool> &outputFlagsPlane,
8038 : ArrayColumn<T> & /* outputDataCol */,
8039 : ArrayColumn<bool> & /* outputFlagCol */)
8040 : {
8041 : // Get buffer pointers
8042 : Cube<T> *dataBufferPointer;
8043 : Cube<bool> *flagBufferPointer;
8044 0 : setOutputbuffer(dataBufferPointer,flagBufferPointer);
8045 :
8046 : // Copy data to buffer
8047 0 : IPosition outputPlaneShape = outputDataPlane.shape();
8048 0 : uInt nCorrs = outputPlaneShape(0);
8049 0 : IPosition outputPlaneShape_i(2,nCorrs,chansPerOutputSpw_p);
8050 0 : Slice sliceX(0,nCorrs);
8051 :
8052 : uInt spw_i;
8053 0 : uInt nspws = nspws_p-1;
8054 0 : for (spw_i=0;spw_i<nspws;spw_i++)
8055 : {
8056 0 : uInt outRow = relativeRow_p+spw_i;
8057 0 : Slice sliceY(chansPerOutputSpw_p*spw_i,chansPerOutputSpw_p);
8058 0 : Matrix<T> outputPlane_i = outputDataPlane(sliceX,sliceY);
8059 0 : dataBufferPointer->xyPlane(outRow) = outputPlane_i;
8060 :
8061 0 : if (flagBufferPointer != NULL)
8062 : {
8063 0 : Matrix<bool> outputFlagPlane_i = outputFlagsPlane(sliceX,sliceY);
8064 0 : flagBufferPointer->xyPlane(outRow) = outputFlagPlane_i;
8065 : }
8066 : }
8067 :
8068 0 : uInt outRow = relativeRow_p+spw_i;
8069 0 : Slice sliceY(chansPerOutputSpw_p*spw_i,tailOfChansforLastSpw_p);
8070 0 : Matrix<T> outputPlane_i = outputDataPlane(sliceX,sliceY);
8071 0 : outputPlane_i.resize(outputPlaneShape_i,true); // Resize uses a new storage and copies the old values to it
8072 : // jagonzal (CAS-7435): We have to set the new values to 0
8073 0 : Slice sliceTail(tailOfChansforLastSpw_p,chansPerOutputSpw_p-tailOfChansforLastSpw_p);
8074 0 : outputPlane_i(sliceX,sliceTail) = 0; // Slices use reference semantics.
8075 0 : dataBufferPointer->xyPlane(outRow) = outputPlane_i;
8076 :
8077 0 : if (flagBufferPointer != NULL)
8078 : {
8079 0 : Matrix<bool> outputFlagPlane_i = outputFlagsPlane(sliceX,sliceY);
8080 0 : outputFlagPlane_i.resize(outputPlaneShape_i,true); // Resize uses a new storage and copies the old values to it
8081 : // jagonzal (CAS-7435): We have to set the new values to 0
8082 0 : outputFlagPlane_i(sliceX,sliceTail) = true; // Slices use reference semantics.
8083 0 : flagBufferPointer->xyPlane(outRow) = outputFlagPlane_i;
8084 : }
8085 :
8086 0 : return;
8087 : }
8088 :
8089 : // -----------------------------------------------------------------------
8090 : //
8091 : // -----------------------------------------------------------------------
8092 0 : template <class T> void MSTransformManager::writeOutputPlanesInBlock( uInt row,
8093 : Matrix<T> &outputDataPlane,
8094 : Matrix<bool> &outputFlagsPlane,
8095 : ArrayColumn<T> &outputDataCol,
8096 : ArrayColumn<bool> &outputFlagCol)
8097 : {
8098 0 : IPosition outputPlaneShape = outputDataPlane.shape();
8099 0 : outputDataCol.setShape(row,outputPlaneShape);
8100 0 : outputDataCol.put(row, outputDataPlane);
8101 0 : (*this.*writeOutputFlagsPlane_p)(outputFlagsPlane,outputFlagCol, outputPlaneShape, row);
8102 0 : }
8103 :
8104 :
8105 : // -----------------------------------------------------------------------
8106 : //
8107 : // -----------------------------------------------------------------------
8108 0 : void MSTransformManager::writeOutputFlagsPlane( Matrix<bool> &outputPlane,
8109 : ArrayColumn<bool> &outputCol,
8110 : IPosition &outputPlaneShape,
8111 : uInt &outputRow)
8112 : {
8113 0 : outputCol.setShape(outputRow,outputPlaneShape);
8114 0 : outputCol.put(outputRow, outputPlane);
8115 0 : }
8116 :
8117 : // -----------------------------------------------------------------------
8118 : //
8119 : // -----------------------------------------------------------------------
8120 0 : template <class T> void MSTransformManager::writeOutputPlanesInSlices( uInt row,
8121 : Matrix<T> &outputDataPlane,
8122 : Matrix<bool> &outputFlagsPlane,
8123 : ArrayColumn<T> &outputDataCol,
8124 : ArrayColumn<bool> &outputFlagCol)
8125 : {
8126 0 : IPosition outputPlaneShape = outputDataPlane.shape();
8127 0 : uInt nCorrs = outputPlaneShape(0);
8128 0 : IPosition outputPlaneShape_i(2,nCorrs,chansPerOutputSpw_p);
8129 0 : Slice sliceX(0,nCorrs);
8130 :
8131 : uInt spw_i;
8132 0 : uInt nspws = nspws_p-1;
8133 0 : for (spw_i=0;spw_i<nspws;spw_i++)
8134 : {
8135 0 : uInt outRow = row+spw_i;
8136 0 : Slice sliceY(chansPerOutputSpw_p*spw_i,chansPerOutputSpw_p);
8137 0 : writeOutputPlaneSlices(outputDataPlane,outputDataCol,sliceX,sliceY,outputPlaneShape_i,outRow);
8138 0 : (*this.*writeOutputFlagsPlaneSlices_p)( outputFlagsPlane,outputFlagCol,
8139 : sliceX,sliceY,outputPlaneShape_i,outRow);
8140 : }
8141 :
8142 0 : uInt outRow = row+spw_i;
8143 0 : IPosition outputPlaneShape_tail(2,nCorrs,tailOfChansforLastSpw_p);
8144 0 : Slice sliceY(chansPerOutputSpw_p*spw_i,tailOfChansforLastSpw_p);
8145 0 : writeOutputPlaneReshapedSlices(outputDataPlane,outputDataCol,sliceX,sliceY,outputPlaneShape_tail,outRow);
8146 0 : (*this.*writeOutputFlagsPlaneReshapedSlices_p)( outputFlagsPlane,outputFlagCol,
8147 : sliceX,sliceY,outputPlaneShape_tail,outRow);
8148 0 : }
8149 :
8150 : // -----------------------------------------------------------------------
8151 : //
8152 : // -----------------------------------------------------------------------
8153 0 : void MSTransformManager::writeOutputFlagsPlaneSlices( Matrix<bool> &outputPlane,
8154 : ArrayColumn<bool> &outputCol,
8155 : Slice &sliceX,
8156 : Slice &sliceY,
8157 : IPosition &outputPlaneShape,
8158 : uInt &outputRow)
8159 : {
8160 0 : writeOutputPlaneSlices(outputPlane,outputCol,sliceX,sliceY,outputPlaneShape,outputRow);
8161 0 : }
8162 :
8163 : // -----------------------------------------------------------------------
8164 : //
8165 : // -----------------------------------------------------------------------
8166 0 : void MSTransformManager::writeOutputFlagsPlaneReshapedSlices( Matrix<bool> &outputPlane,
8167 : ArrayColumn<bool> &outputCol,
8168 : Slice &sliceX,
8169 : Slice &sliceY,
8170 : IPosition &outputPlaneShape,
8171 : uInt &outputRow)
8172 : {
8173 0 : writeOutputPlaneReshapedSlices(outputPlane,outputCol,sliceX,sliceY,outputPlaneShape,outputRow);
8174 0 : }
8175 :
8176 : // -----------------------------------------------------------------------
8177 : //
8178 : // -----------------------------------------------------------------------
8179 0 : template <class T> void MSTransformManager::writeOutputPlaneSlices( Matrix<T> &outputPlane,
8180 : ArrayColumn<T> &outputCol,
8181 : Slice &sliceX,
8182 : Slice &sliceY,
8183 : IPosition &outputPlaneShape,
8184 : uInt &outputRow)
8185 : {
8186 0 : Matrix<T> outputPlane_i = outputPlane(sliceX,sliceY);
8187 0 : outputCol.setShape(outputRow,outputPlaneShape);
8188 0 : outputCol.put(outputRow, outputPlane_i);
8189 0 : }
8190 :
8191 : // -----------------------------------------------------------------------
8192 : //
8193 : // -----------------------------------------------------------------------
8194 0 : template <class T> void MSTransformManager::writeOutputPlaneReshapedSlices( Matrix<T> &outputPlane,
8195 : ArrayColumn<T> &outputCol,
8196 : Slice &sliceX,
8197 : Slice &sliceY,
8198 : IPosition &outputPlaneShape,
8199 : uInt &outputRow)
8200 : {
8201 0 : Matrix<T> outputPlane_i = outputPlane(sliceX,sliceY);
8202 0 : outputPlane_i.resize(outputPlaneShape,true);
8203 0 : outputCol.setShape(outputRow,outputPlaneShape);
8204 0 : outputCol.put(outputRow, outputPlane_i);
8205 0 : }
8206 :
8207 : // -----------------------------------------------------------------------
8208 : //
8209 : // -----------------------------------------------------------------------
8210 0 : void MSTransformManager::setWeightStripeByReference( uInt corrIndex,
8211 : Matrix<Float> &inputWeightsPlane,
8212 : Vector<Float> &inputWeightsStripe)
8213 : {
8214 0 : inputWeightsStripe.reference(inputWeightsPlane.row(corrIndex));
8215 0 : }
8216 :
8217 : // -----------------------------------------------------------------------
8218 : //
8219 : // -----------------------------------------------------------------------
8220 0 : void MSTransformManager::transformStripeOfData(Int inputSpw,
8221 : const Vector<Complex> &inputDataStripe,
8222 : const Vector<bool> &inputFlagsStripe,
8223 : const Vector<Float> &inputWeightsStripe,
8224 : Vector<Complex> &outputDataStripe,
8225 : Vector<bool> &outputFlagsStripe)
8226 : {
8227 0 : auto shapeBefore = outputDataStripe.shape();
8228 0 : (*this.*transformStripeOfDataComplex_p)(inputSpw, inputDataStripe, inputFlagsStripe,
8229 : inputWeightsStripe, outputDataStripe,
8230 0 : outputFlagsStripe);
8231 0 : auto shapeAfter = outputDataStripe.shape();
8232 0 : if (shapeAfter != shapeBefore) {
8233 0 : ostringstream msg;
8234 : msg << "Shape of output complex data stripe changed after applying "
8235 0 : << "transformation. Output shape expected before transformation: "
8236 0 : << shapeBefore
8237 0 : << ". Output shape produced by transformation: " << shapeAfter;
8238 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager",__FUNCTION__)
8239 0 : << LogIO::POST;
8240 0 : throw AipsError(msg.str());
8241 : }
8242 0 : }
8243 :
8244 : // -----------------------------------------------------------------------
8245 : //
8246 : // -----------------------------------------------------------------------
8247 0 : void MSTransformManager::transformStripeOfData(Int inputSpw,
8248 : const Vector<Float> &inputDataStripe,
8249 : const Vector<bool> &inputFlagsStripe,
8250 : const Vector<Float> &inputWeightsStripe,
8251 : Vector<Float> &outputDataStripe,
8252 : Vector<bool> &outputFlagsStripe)
8253 : {
8254 0 : (*this.*transformStripeOfDataFloat_p)( inputSpw,inputDataStripe,inputFlagsStripe,inputWeightsStripe,
8255 0 : outputDataStripe,outputFlagsStripe);
8256 0 : }
8257 :
8258 : // -----------------------------------------------------------------------
8259 : //
8260 : // -----------------------------------------------------------------------
8261 0 : template <class T> void MSTransformManager::average(Int inputSpw,
8262 : const Vector<T> &inputDataStripe,
8263 : const Vector<bool> &inputFlagsStripe,
8264 : const Vector<Float> &inputWeightsStripe,
8265 : Vector<T> &outputDataStripe,
8266 : Vector<bool> &outputFlagsStripe)
8267 : {
8268 0 : uInt width = freqbinMap_p[inputSpw];
8269 0 : uInt startChan = 0;
8270 0 : uInt outChanIndex = 0;
8271 0 : uInt tail = inputDataStripe.size() % width;
8272 0 : while (outChanIndex < outputDataStripe.size())
8273 : {
8274 0 : averageKernel( inputDataStripe,inputFlagsStripe,inputWeightsStripe,
8275 : outputDataStripe,outputFlagsStripe,startChan,outChanIndex,width);
8276 0 : startChan += width;
8277 0 : outChanIndex += 1;
8278 : }
8279 :
8280 : // jagonzal: The last channel is dropped when there are not enough input channels
8281 : // to populate it only when there is no regridding afterwards
8282 0 : if (tail and (outChanIndex <= outputDataStripe.size()-1) )
8283 : {
8284 0 : averageKernel( inputDataStripe,inputFlagsStripe,inputWeightsStripe,
8285 : outputDataStripe,outputFlagsStripe,startChan,outChanIndex,tail);
8286 : }
8287 :
8288 0 : return;
8289 : }
8290 :
8291 : // -----------------------------------------------------------------------
8292 : //
8293 : // -----------------------------------------------------------------------
8294 0 : template <class T> void MSTransformManager::simpleAverage(uInt width,
8295 : const Vector<T> &inputData,
8296 : Vector<T> &outputData)
8297 : {
8298 : // Dummy variables
8299 0 : Vector<bool> inputFlags,outputFlags;
8300 0 : Vector<Float> inputWeights;
8301 :
8302 0 : uInt startChan = 0;
8303 0 : uInt outChanIndex = 0;
8304 0 : uInt tail = inputData.size() % width;
8305 0 : uInt limit = inputData.size() - tail;
8306 0 : while (startChan < limit)
8307 : {
8308 0 : simpleAverageKernel(inputData,inputFlags,inputWeights,outputData,outputFlags,startChan,outChanIndex,width);
8309 0 : startChan += width;
8310 0 : outChanIndex += 1;
8311 : }
8312 :
8313 : // jagonzal: The last channel is dropped when there are not enough input channels
8314 : // to populate it only when there is no regridding afterwards
8315 0 : if (tail and (outChanIndex <= outputData.size()-1) )
8316 : {
8317 0 : simpleAverageKernel(inputData,inputFlags,inputWeights,outputData,outputFlags,startChan,outChanIndex,tail);
8318 : }
8319 :
8320 0 : return;
8321 : }
8322 :
8323 : // -----------------------------------------------------------------------
8324 : //
8325 : // -----------------------------------------------------------------------
8326 0 : void MSTransformManager::averageKernel(const Vector<Complex> &inputData,
8327 : const Vector<bool> &inputFlags,
8328 : const Vector<Float> &inputWeights,
8329 : Vector<Complex> &outputData,
8330 : Vector<bool> &outputFlags,
8331 : uInt startInputPos,
8332 : uInt outputPos,
8333 : uInt width)
8334 : {
8335 0 : (*this.*averageKernelComplex_p)( inputData,inputFlags,inputWeights,
8336 0 : outputData,outputFlags,startInputPos,outputPos,width);
8337 0 : return;
8338 : }
8339 :
8340 : // -----------------------------------------------------------------------
8341 : //
8342 : // -----------------------------------------------------------------------
8343 0 : void MSTransformManager::averageKernel(const Vector<Float> &inputData,
8344 : const Vector<bool> &inputFlags,
8345 : const Vector<Float> &inputWeights,
8346 : Vector<Float> &outputData,
8347 : Vector<bool> &outputFlags,
8348 : uInt startInputPos,
8349 : uInt outputPos,
8350 : uInt width)
8351 : {
8352 0 : (*this.*averageKernelFloat_p)( inputData,inputFlags,inputWeights,
8353 0 : outputData,outputFlags,startInputPos,outputPos,width);
8354 0 : return;
8355 : }
8356 :
8357 : // -----------------------------------------------------------------------
8358 : //
8359 : // -----------------------------------------------------------------------
8360 0 : template <class T> void MSTransformManager::simpleAverageKernel(const Vector<T> &inputData,
8361 : const Vector<bool> &,
8362 : const Vector<Float> &,
8363 : Vector<T> &outputData,
8364 : Vector<bool> &,
8365 : uInt startInputPos,
8366 : uInt outputPos,
8367 : uInt width)
8368 : {
8369 0 : uInt pos = startInputPos + 1;
8370 0 : uInt counts = 1;
8371 0 : T avg = inputData(startInputPos);
8372 0 : while (counts < width)
8373 : {
8374 0 : avg += inputData(pos);
8375 0 : counts += 1;
8376 0 : pos += 1;
8377 : }
8378 :
8379 0 : if (counts > 0)
8380 : {
8381 0 : avg /= counts;
8382 : }
8383 :
8384 0 : outputData(outputPos) = avg;
8385 :
8386 0 : return;
8387 : }
8388 :
8389 : // -----------------------------------------------------------------------
8390 : //
8391 : // -----------------------------------------------------------------------
8392 0 : template <class T> void MSTransformManager::flagAverageKernel(const Vector<T> &inputData,
8393 : const Vector<bool> &inputFlags,
8394 : const Vector<Float> &,
8395 : Vector<T> &outputData,
8396 : Vector<bool> &outputFlags,
8397 : uInt startInputPos,
8398 : uInt outputPos,
8399 : uInt width)
8400 : {
8401 0 : uInt samples = 1;
8402 0 : uInt pos = startInputPos + 1;
8403 0 : uInt counts = !inputFlags(startInputPos);
8404 0 : T avg = inputData(startInputPos)*(!inputFlags(startInputPos));
8405 0 : while (samples < width)
8406 : {
8407 0 : avg += inputData(pos)*(!inputFlags(pos));
8408 0 : counts += (!inputFlags(pos));
8409 0 : samples += 1;
8410 0 : pos += 1;
8411 : }
8412 :
8413 0 : if (counts > 0)
8414 : {
8415 0 : avg /= counts;
8416 : }
8417 : else
8418 : {
8419 0 : outputFlags(outputPos) = true;
8420 : }
8421 :
8422 0 : outputData(outputPos) = avg;
8423 :
8424 0 : return;
8425 : }
8426 :
8427 : // -----------------------------------------------------------------------
8428 : //
8429 : // -----------------------------------------------------------------------
8430 0 : template <class T> void MSTransformManager::weightAverageKernel(const Vector<T> &inputData,
8431 : const Vector<bool> &,
8432 : const Vector<Float> &inputWeights,
8433 : Vector<T> &outputData,
8434 : Vector<bool> &outputFlags,
8435 : uInt startInputPos,
8436 : uInt outputPos,
8437 : uInt width)
8438 : {
8439 0 : uInt samples = 1;
8440 0 : uInt pos = startInputPos + 1;
8441 0 : Float counts = inputWeights(startInputPos);
8442 0 : T avg = inputData(startInputPos)*inputWeights(startInputPos);
8443 0 : while (samples < width)
8444 : {
8445 0 : avg += inputData(pos)*inputWeights(pos);
8446 0 : counts += inputWeights(pos);
8447 0 : samples += 1;
8448 0 : pos += 1;
8449 : }
8450 :
8451 0 : if (counts > 0)
8452 : {
8453 0 : avg /= counts;
8454 : }
8455 : else
8456 : {
8457 0 : outputFlags(outputPos) = true;
8458 : }
8459 :
8460 0 : outputData(outputPos) = avg;
8461 :
8462 0 : return;
8463 : }
8464 :
8465 : // -----------------------------------------------------------------------
8466 : //
8467 : // -----------------------------------------------------------------------
8468 0 : template <class T> void MSTransformManager::cumSumKernel(const Vector<T> &inputData,
8469 : const Vector<bool> &,
8470 : const Vector<Float> &,
8471 : Vector<T> &outputData,
8472 : Vector<bool> &,
8473 : uInt startInputPos,
8474 : uInt outputPos,
8475 : uInt width)
8476 : {
8477 0 : uInt pos = startInputPos + 1;
8478 0 : uInt counts = 1;
8479 0 : T avg = inputData(startInputPos);
8480 0 : while (counts < width)
8481 : {
8482 0 : avg += inputData(pos);
8483 0 : counts += 1;
8484 0 : pos += 1;
8485 : }
8486 :
8487 0 : outputData(outputPos) = avg;
8488 :
8489 0 : return;
8490 : }
8491 :
8492 : // -----------------------------------------------------------------------
8493 : //
8494 : // -----------------------------------------------------------------------
8495 0 : template <class T> void MSTransformManager::flagWeightAverageKernel(const Vector<T> &inputData,
8496 : const Vector<bool> &inputFlags,
8497 : const Vector<Float> &inputWeights,
8498 : Vector<T> &outputData,
8499 : Vector<bool> &outputFlags,
8500 : uInt startInputPos,
8501 : uInt outputPos,
8502 : uInt width)
8503 : {
8504 0 : uInt samples = 1;
8505 0 : uInt pos = startInputPos + 1;
8506 0 : Float totalWeight = inputWeights(startInputPos)*(!inputFlags(startInputPos));
8507 0 : Float counts = totalWeight;
8508 0 : T avg = inputData(startInputPos)*totalWeight;
8509 0 : while (samples < width)
8510 : {
8511 0 : totalWeight = inputWeights(pos)*(!inputFlags(pos));
8512 0 : avg += inputData(pos)*totalWeight;
8513 0 : counts += totalWeight;
8514 0 : samples += 1;
8515 0 : pos += 1;
8516 : }
8517 :
8518 0 : if (counts > 0)
8519 : {
8520 0 : avg /= counts;
8521 : }
8522 : else
8523 : {
8524 0 : outputFlags(outputPos) = true;
8525 : }
8526 :
8527 0 : outputData(outputPos) = avg;
8528 :
8529 0 : return;
8530 : }
8531 :
8532 : // -----------------------------------------------------------------------
8533 : //
8534 : // -----------------------------------------------------------------------
8535 0 : template <class T> void MSTransformManager::flagCumSumKernel(const Vector<T> &inputData,
8536 : const Vector<bool> &inputFlags,
8537 : const Vector<Float> &,
8538 : Vector<T> &outputData,
8539 : Vector<bool> &,
8540 : uInt startInputPos,
8541 : uInt outputPos,
8542 : uInt width)
8543 : {
8544 0 : uInt samples = 1;
8545 0 : uInt pos = startInputPos + 1;
8546 0 : T avg = inputData(startInputPos)*(!inputFlags(startInputPos));
8547 0 : while (samples < width)
8548 : {
8549 0 : avg += inputData(pos)*(!inputFlags(pos));
8550 0 : samples += 1;
8551 0 : pos += 1;
8552 : }
8553 :
8554 0 : outputData(outputPos) = avg;
8555 :
8556 0 : return;
8557 : }
8558 :
8559 : // -----------------------------------------------------------------------
8560 : //
8561 : // -----------------------------------------------------------------------
8562 0 : template <class T> void MSTransformManager::flagNonZeroAverageKernel(const Vector<T> &inputData,
8563 : const Vector<bool> &inputFlags,
8564 : const Vector<Float> & /* inputWeights */,
8565 : Vector<T> &outputData,
8566 : Vector<bool> &outputFlags,
8567 : uInt startInputPos,
8568 : uInt outputPos,
8569 : uInt width)
8570 : {
8571 0 : T avg = 0;
8572 0 : uInt samples = 0;
8573 0 : uInt inputPos = 0;
8574 0 : bool accumulatorFlag = inputFlags(startInputPos);
8575 :
8576 0 : for (uInt sample_i=0;sample_i<width;sample_i++)
8577 : {
8578 : // Get input index
8579 0 : inputPos = startInputPos + sample_i;
8580 :
8581 : // true/true or false/false
8582 0 : if (accumulatorFlag == inputFlags(inputPos))
8583 : {
8584 0 : samples += 1;
8585 0 : avg += inputData(inputPos);
8586 : }
8587 : // true/false: Reset accumulation when accumulator switches from flagged to unflag
8588 0 : else if ( (accumulatorFlag == true) and (inputFlags(inputPos) == false) )
8589 : {
8590 0 : accumulatorFlag = false;
8591 0 : samples = 1;
8592 0 : avg = inputData(inputPos);
8593 : }
8594 : }
8595 :
8596 :
8597 : // Apply normalization factor
8598 0 : if (samples > 0)
8599 : {
8600 0 : avg /= samples;
8601 0 : outputData(outputPos) = avg;
8602 : }
8603 : // This should never happen
8604 : else
8605 : {
8606 0 : accumulatorFlag = true;
8607 0 : outputData(outputPos) = 0; // this should be a code error
8608 : }
8609 :
8610 :
8611 : // Set output flag (it is initialized to false)
8612 0 : if (accumulatorFlag)
8613 : {
8614 0 : outputFlags(outputPos) = true;
8615 : }
8616 :
8617 0 : return;
8618 : }
8619 :
8620 :
8621 : // -----------------------------------------------------------------------
8622 : //
8623 : // -----------------------------------------------------------------------
8624 0 : template <class T> void MSTransformManager::flagWeightNonZeroAverageKernel(const Vector<T> &inputData,
8625 : const Vector<bool> &inputFlags,
8626 : const Vector<Float> &inputWeights,
8627 : Vector<T> &outputData,
8628 : Vector<bool> &outputFlags,
8629 : uInt startInputPos,
8630 : uInt outputPos,
8631 : uInt width)
8632 : {
8633 0 : T avg = 0;
8634 0 : T normalization = 0;
8635 0 : uInt inputPos = 0;
8636 0 : bool accumulatorFlag = inputFlags(startInputPos);
8637 :
8638 0 : for (uInt sample_i=0;sample_i<width;sample_i++)
8639 : {
8640 : // Get input index
8641 0 : inputPos = startInputPos + sample_i;
8642 :
8643 : // true/true or false/false
8644 0 : if (accumulatorFlag == inputFlags(inputPos))
8645 : {
8646 0 : normalization += inputWeights(inputPos);
8647 0 : avg += inputData(inputPos)*inputWeights(inputPos);
8648 : }
8649 : // true/false: Reset accumulation when accumulator switches from flagged to unflag
8650 0 : else if ( (accumulatorFlag == true) and (inputFlags(inputPos) == false) )
8651 : {
8652 0 : accumulatorFlag = false;
8653 0 : normalization = inputWeights(inputPos);
8654 0 : avg = inputData(inputPos)*inputWeights(inputPos);
8655 : }
8656 : }
8657 :
8658 :
8659 : // Apply normalization factor
8660 0 : if (normalization > 0)
8661 : {
8662 0 : avg /= normalization;
8663 0 : outputData(outputPos) = avg;
8664 : }
8665 : // If all weights are zero set accumulatorFlag to true
8666 : else
8667 : {
8668 0 : accumulatorFlag = true;
8669 0 : outputData(outputPos) = 0; // If all weights are zero then the avg is 0 too
8670 : }
8671 :
8672 :
8673 : // Set output flag (it is initialized to false)
8674 0 : if (accumulatorFlag)
8675 : {
8676 0 : outputFlags(outputPos) = true;
8677 : }
8678 :
8679 0 : return;
8680 : }
8681 :
8682 : // -----------------------------------------------------------------------
8683 : //
8684 : // -----------------------------------------------------------------------
8685 0 : template <class T> void MSTransformManager::flagCumSumNonZeroKernel(const Vector<T> &inputData,
8686 : const Vector<bool> &inputFlags,
8687 : const Vector<Float> & /* inputWeights */,
8688 : Vector<T> &outputData,
8689 : Vector<bool> &outputFlags,
8690 : uInt startInputPos,
8691 : uInt outputPos,
8692 : uInt width)
8693 : {
8694 0 : T avg = 0;
8695 0 : uInt inputPos = 0;
8696 0 : bool accumulatorFlag = inputFlags(startInputPos);
8697 :
8698 0 : for (uInt sample_i=0;sample_i<width;sample_i++)
8699 : {
8700 : // Get input index
8701 0 : inputPos = startInputPos + sample_i;
8702 :
8703 : // true/true or false/false
8704 0 : if (accumulatorFlag == inputFlags(inputPos))
8705 : {
8706 0 : avg += inputData(inputPos);
8707 : }
8708 : // true/false: Reset accumulation when accumulator switches from flagged to unflag
8709 0 : else if ( (accumulatorFlag == true) and (inputFlags(inputPos) == false) )
8710 : {
8711 0 : accumulatorFlag = false;
8712 0 : avg = inputData(inputPos);
8713 : }
8714 : }
8715 :
8716 0 : outputData(outputPos) = avg;
8717 :
8718 : // Set output flag (it is initialized to false)
8719 0 : if (accumulatorFlag)
8720 : {
8721 0 : outputFlags(outputPos) = true;
8722 : }
8723 :
8724 0 : return;
8725 : }
8726 :
8727 :
8728 : // -----------------------------------------------------------------------
8729 : //
8730 : // -----------------------------------------------------------------------
8731 0 : template <class T> void MSTransformManager::smooth(Int ,
8732 : const Vector<T> &inputDataStripe,
8733 : const Vector<bool> &inputFlagsStripe,
8734 : const Vector<Float> &inputWeightsStripe,
8735 : Vector<T> &outputDataStripe,
8736 : Vector<bool> &outputFlagsStripe)
8737 : {
8738 : // Calculate limits
8739 0 : uInt width = smoothBin_p;
8740 0 : uInt halfWidth = width / 2;
8741 0 : uInt outChanStart = halfWidth;
8742 0 : uInt outChanStop = inputDataStripe.size() - outChanStart;
8743 :
8744 : // Main loop
8745 0 : for (uInt outChan = outChanStart; outChan<outChanStop; outChan++)
8746 : {
8747 0 : smoothKernel( inputDataStripe,inputFlagsStripe,inputWeightsStripe,
8748 : outputDataStripe,outputFlagsStripe,outChan);
8749 : }
8750 :
8751 : // Flag lower edge
8752 0 : for (uInt outChan = 0; outChan<outChanStart; outChan++)
8753 : {
8754 0 : outputFlagsStripe(outChan) = true;
8755 0 : outputDataStripe(outChan) = inputDataStripe(outChan);
8756 : }
8757 :
8758 : // Flag higher edge
8759 0 : for (uInt outChan = outChanStop; outChan<inputDataStripe.size(); outChan++)
8760 : {
8761 0 : outputFlagsStripe(outChan) = true;
8762 0 : outputDataStripe(outChan) = inputDataStripe(outChan);
8763 : }
8764 :
8765 0 : return;
8766 : }
8767 :
8768 : // -----------------------------------------------------------------------
8769 : //
8770 : // -----------------------------------------------------------------------
8771 0 : void MSTransformManager::smoothKernel(const Vector<Complex> &inputData,
8772 : const Vector<bool> &inputFlags,
8773 : const Vector<Float> &inputWeights,
8774 : Vector<Complex> &outputData,
8775 : Vector<bool> &outputFlags,
8776 : uInt outputPos)
8777 : {
8778 0 : (*this.*smoothKernelComplex_p)( inputData,inputFlags,inputWeights,
8779 0 : outputData,outputFlags,outputPos);
8780 0 : return;
8781 : }
8782 :
8783 : // -----------------------------------------------------------------------
8784 : //
8785 : // -----------------------------------------------------------------------
8786 0 : void MSTransformManager::smoothKernel(const Vector<Float> &inputData,
8787 : const Vector<bool> &inputFlags,
8788 : const Vector<Float> &inputWeights,
8789 : Vector<Float> &outputData,
8790 : Vector<bool> &outputFlags,
8791 : uInt outputPos)
8792 : {
8793 0 : (*this.*smoothKernelFloat_p)( inputData,inputFlags,inputWeights,
8794 0 : outputData,outputFlags,outputPos);
8795 0 : return;
8796 : }
8797 :
8798 : // -----------------------------------------------------------------------
8799 : //
8800 : // -----------------------------------------------------------------------
8801 0 : template <class T> void MSTransformManager::plainSmooth(const Vector<T> &inputData,
8802 : const Vector<bool> &inputFlags,
8803 : const Vector<Float> &,
8804 : Vector<T> &outputData,
8805 : Vector<bool> &outputFlags,
8806 : uInt outputPos)
8807 : {
8808 0 : uInt halfWidth = smoothBin_p / 2;
8809 :
8810 : // Initialization
8811 0 : outputFlags(outputPos) = inputFlags(outputPos-halfWidth);
8812 0 : outputData(outputPos) = smoothCoeff_p(0)*inputData(outputPos-halfWidth);
8813 :
8814 : // Main loop
8815 0 : for (uInt i = 1; i<smoothBin_p;i++)
8816 : {
8817 0 : outputData(outputPos) += smoothCoeff_p(i)*inputData(outputPos-halfWidth+i);
8818 :
8819 : // Output sample is flagged if any of the contributors are flagged
8820 0 : if (inputFlags(outputPos-halfWidth+i)) outputFlags(outputPos)=true;
8821 : }
8822 :
8823 0 : return;
8824 : }
8825 :
8826 : // -----------------------------------------------------------------------
8827 : //
8828 : // -----------------------------------------------------------------------
8829 0 : template <class T> void MSTransformManager::plainSmoothSpectrum(const Vector<T> &inputData,
8830 : const Vector<bool> &inputFlags,
8831 : const Vector<Float> &,
8832 : Vector<T> &outputData,
8833 : Vector<bool> &outputFlags,
8834 : uInt outputPos)
8835 : {
8836 0 : uInt halfWidth = smoothBin_p / 2;
8837 :
8838 : // Initialization (mind for zeros as there is a division operation)
8839 0 : if (inputData(outputPos-halfWidth) <= FLT_MIN)
8840 : {
8841 0 : outputData(outputPos) = 0;
8842 0 : outputFlags(outputPos) = true;
8843 : }
8844 : else
8845 : {
8846 0 : outputFlags(outputPos) = inputFlags(outputPos-halfWidth);
8847 0 : outputData(outputPos) = smoothCoeff_p(0)*smoothCoeff_p(0)/inputData(outputPos-halfWidth);
8848 : }
8849 :
8850 : // Main accumulation loop
8851 0 : for (uInt i = 1; i<smoothBin_p;i++)
8852 : {
8853 : // Mind for zeros as there is a division operation
8854 0 : if (inputData(outputPos-halfWidth+i) <= FLT_MIN)
8855 : {
8856 0 : outputFlags(outputPos) = true;
8857 : }
8858 : else
8859 : {
8860 0 : outputData(outputPos) += smoothCoeff_p(i)*smoothCoeff_p(i)/inputData(outputPos-halfWidth+i);
8861 :
8862 : // Output sample is flagged if any of the contributors are flagged
8863 0 : if (inputFlags(outputPos-halfWidth+i)) outputFlags(outputPos)=true;
8864 : }
8865 : }
8866 :
8867 : // Final propaged weight si the inverse of the accumulation
8868 0 : if (outputData(outputPos) > FLT_MIN)
8869 : {
8870 0 : outputData(outputPos) = 1/outputData(outputPos);
8871 : }
8872 :
8873 0 : return;
8874 : }
8875 :
8876 : // -----------------------------------------------------------------------
8877 : //
8878 : // -----------------------------------------------------------------------
8879 0 : template <class T> void MSTransformManager::regrid(Int inputSpw,
8880 : const Vector<T> &inputDataStripe,
8881 : const Vector<bool> &inputFlagsStripe,
8882 : const Vector<Float> &inputWeightsStripe,
8883 : Vector<T> &outputDataStripe,
8884 : Vector<bool> &outputFlagsStripe)
8885 : {
8886 :
8887 0 : regridCore( inputSpw,
8888 : inputDataStripe,
8889 : inputFlagsStripe,
8890 : inputWeightsStripe,
8891 : outputDataStripe,
8892 : outputFlagsStripe);
8893 :
8894 0 : }
8895 :
8896 : // -----------------------------------------------------------------------
8897 : //
8898 : // -----------------------------------------------------------------------
8899 0 : void MSTransformManager::regridCore(Int inputSpw,
8900 : const Vector<Complex> &inputDataStripe,
8901 : const Vector<bool> &inputFlagsStripe,
8902 : const Vector<Float> &inputWeightsStripe,
8903 : Vector<Complex> &outputDataStripe,
8904 : Vector<bool> &outputFlagsStripe)
8905 : {
8906 :
8907 0 : (*this.*regridCoreComplex_p)( inputSpw,
8908 : inputDataStripe,
8909 : inputFlagsStripe,
8910 : inputWeightsStripe,
8911 : outputDataStripe,
8912 0 : outputFlagsStripe);
8913 0 : }
8914 :
8915 : // -----------------------------------------------------------------------
8916 : //
8917 : // -----------------------------------------------------------------------
8918 0 : void MSTransformManager::regridCore(Int inputSpw,
8919 : const Vector<Float> &inputDataStripe,
8920 : const Vector<bool> &inputFlagsStripe,
8921 : const Vector<Float> &inputWeightsStripe,
8922 : Vector<Float> &outputDataStripe,
8923 : Vector<bool> &outputFlagsStripe)
8924 : {
8925 0 : (*this.*regridCoreFloat_p)( inputSpw,
8926 : inputDataStripe,
8927 : inputFlagsStripe,
8928 : inputWeightsStripe,
8929 : outputDataStripe,
8930 0 : outputFlagsStripe);
8931 0 : }
8932 :
8933 : // -----------------------------------------------------------------------
8934 : //
8935 : // -----------------------------------------------------------------------
8936 0 : void MSTransformManager::fftshift(Int ,
8937 : const Vector<Complex> &inputDataStripe,
8938 : const Vector<bool> &inputFlagsStripe,
8939 : const Vector<Float> &,
8940 : Vector<Complex> &outputDataStripe,
8941 : Vector<bool> &outputFlagsStripe)
8942 : {
8943 0 : fFFTServer_p.fftshift(outputDataStripe,
8944 : outputFlagsStripe,
8945 0 : (const Vector<Complex>)inputDataStripe,
8946 0 : (const Vector<bool>)inputFlagsStripe,
8947 0 : (const uInt)0, // In vectors axis 0 is the only dimension
8948 0 : (const Double)fftShift_p,
8949 : false, // A good data point has its flag set to false
8950 : false);
8951 0 : }
8952 :
8953 : // -----------------------------------------------------------------------
8954 : //
8955 : // -----------------------------------------------------------------------
8956 0 : void MSTransformManager::fftshift(Int ,
8957 : const Vector<Float> &inputDataStripe,
8958 : const Vector<bool> &inputFlagsStripe,
8959 : const Vector<Float> &,
8960 : Vector<Float> &outputDataStripe,
8961 : Vector<bool> &outputFlagsStripe)
8962 : {
8963 0 : fFFTServer_p.fftshift(outputDataStripe,
8964 : outputFlagsStripe,
8965 0 : (const Vector<Float>)inputDataStripe,
8966 0 : (const Vector<bool>)inputFlagsStripe,
8967 0 : (const uInt)0, // In vectors axis 0 is the only dimension
8968 0 : (const Double)fftShift_p,
8969 : false); // A good data point has its flag set to false
8970 0 : }
8971 :
8972 : // -----------------------------------------------------------------------
8973 : //
8974 : // -----------------------------------------------------------------------
8975 0 : template <class T> void MSTransformManager::interpol1D(Int inputSpw,
8976 : const Vector<T> &inputDataStripe,
8977 : const Vector<bool> &inputFlagsStripe,
8978 : const Vector<Float> &,
8979 : Vector<T> &outputDataStripe,
8980 : Vector<bool> &outputFlagsStripe)
8981 : {
8982 0 : if (inputDataStripe.size() < 2) {
8983 0 : outputDataStripe = inputDataStripe(0);
8984 0 : outputFlagsStripe = true;
8985 0 : return;
8986 : }
8987 :
8988 0 : if (!regridTClean_p) {
8989 0 : InterpolateArray1D<Double,T>::interpolate(outputDataStripe, // Output data
8990 : outputFlagsStripe, // Output flags
8991 0 : inputOutputSpwMap_p[inputSpw].second.CHAN_FREQ, // Out chan freq
8992 0 : inputOutputSpwMap_p[inputSpw].first.CHAN_FREQ_aux, // In chan freq
8993 : inputDataStripe, // Input data
8994 : inputFlagsStripe, // Input Flags
8995 0 : interpolationMethod_p, // Interpolation method
8996 : false, // A good data point has its flag set to false
8997 : false // If false extrapolated data points are set flagged
8998 : );
8999 : } else {
9000 0 : interpolateByChannelMap(inputSpw,
9001 : inputDataStripe, inputFlagsStripe,
9002 : outputDataStripe, outputFlagsStripe);
9003 : }
9004 : }
9005 :
9006 : /**
9007 : * Introduced to mimic the way tclean regrids when the factor between
9008 : * the output channel width and the input channel width is > 2.
9009 : * Ref. TransformMachines2/FTMachine.cc
9010 : *
9011 : * Uses a map from original input channels => fake output channels,
9012 : * where the fake output channels have the (lower) width of the
9013 : * input channels but are projected/aligned with the output channel
9014 : * grid.
9015 : *
9016 : * @param spw spw index of the input channels, to fetch original
9017 : * input channel freqs
9018 : * @param inputDataStripe input data coming from regridCubeOfData,
9019 : * transformAndWriteCubeOfData, etc. and passed to the
9020 : * regrid/interpolation kernels.
9021 : * @param inputFlagsStripe flags for the inputDataStripe
9022 : * @param outputDataStripe will be interpolated by aggregating
9023 : * input visibilities into wider channels
9024 : * @param outputFlagsStripe flags for outputDataStripe
9025 : */
9026 0 : template <class T> void MSTransformManager::interpolateByChannelMap(Int spw,
9027 : const Vector<T> &inputDataStripe,
9028 : const Vector<bool> &inputFlagsStripe,
9029 : Vector<T> &outputDataStripe,
9030 : Vector<bool> &outputFlagsStripe)
9031 : {
9032 0 : Vector<T> intermDataStripe;
9033 0 : Vector<bool> intermFlagsStripe;
9034 : // Bring frequencies from input grid to fake output grid ( the
9035 : // one with same widths as the original input channels).
9036 0 : InterpolateArray1D<Double,T>::interpolate(intermDataStripe,
9037 : intermFlagsStripe,
9038 0 : regridTCleanCHAN_FREQ_p, // Out channel freqs
9039 0 : inputOutputSpwMap_p[spw].first.CHAN_FREQ_aux, // Input chan freqs
9040 : inputDataStripe,
9041 : inputFlagsStripe,
9042 0 : interpolationMethod_p,
9043 : false, // flags
9044 : false // extrapolated data points are set flagged
9045 : );
9046 :
9047 : // Aggregate fine grain fake output channels into the final
9048 : // output channels
9049 0 : outputDataStripe = 0;
9050 0 : Vector<Double> outWeights;
9051 0 : outWeights.resize(outputDataStripe.size());
9052 0 : outWeights = 0.;
9053 0 : for (uInt mapIdx = 0; mapIdx < regridTCleanChanMap_p.size(); ++mapIdx) {
9054 0 : Int outIdx = regridTCleanChanMap_p[mapIdx];
9055 0 : if (outIdx < 0)
9056 0 : continue;
9057 :
9058 0 : outputDataStripe[outIdx] = (outputDataStripe[outIdx] * outWeights[outIdx] +
9059 0 : intermDataStripe[mapIdx]) /
9060 0 : (1. + outWeights[outIdx]);
9061 0 : outWeights[outIdx] += 1;
9062 0 : outputFlagsStripe[outIdx] |= intermFlagsStripe[mapIdx];
9063 : }
9064 0 : }
9065 :
9066 : // ------------------------------------------------------------------------
9067 : // casacore::fftshift does not interpolate, it needs interpolation+fftshift
9068 : // ------------------------------------------------------------------------
9069 0 : template <class T> void MSTransformManager::interpol1Dfftshift(Int inputSpw,
9070 : const Vector<T> &inputDataStripe,
9071 : const Vector<bool> &inputFlagsStripe,
9072 : const Vector<Float> &inputWeightsStripe,
9073 : Vector<T> &outputDataStripe,
9074 : Vector<bool> &outputFlagsStripe)
9075 : {
9076 0 : Vector<T> regriddedDataStripe(outputDataStripe.shape(),T());
9077 0 : Vector<bool> regriddedFlagsStripe(outputFlagsStripe.shape(),false);
9078 :
9079 : // This linear interpolation provides a uniform grid (pre-condition to apply fftshift)
9080 0 : interpol1D(inputSpw,inputDataStripe,inputFlagsStripe,inputWeightsStripe,regriddedDataStripe,regriddedFlagsStripe);
9081 :
9082 : // fftshift takes care of time
9083 0 : fftshift(inputSpw,regriddedDataStripe,regriddedFlagsStripe,inputWeightsStripe,outputDataStripe,outputFlagsStripe);
9084 0 : }
9085 :
9086 : // -----------------------------------------------------------------------
9087 : //
9088 : // -----------------------------------------------------------------------
9089 0 : template <class T> void MSTransformManager::averageRegrid(Int inputSpw,
9090 : const Vector<T> &inputDataStripe,
9091 : const Vector<bool> &inputFlagsStripe,
9092 : const Vector<Float> &inputWeightsStripe,
9093 : Vector<T> &outputDataStripe,
9094 : Vector<bool> &outputFlagsStripe)
9095 : {
9096 0 : Vector<T> averagedDataStripe(numOfCombInterChanMap_p[inputSpw],T());
9097 0 : Vector<bool> averagedFlagsStripe(numOfCombInterChanMap_p[inputSpw],false);
9098 :
9099 0 : average(inputSpw,inputDataStripe,inputFlagsStripe,inputWeightsStripe, averagedDataStripe,averagedFlagsStripe);
9100 :
9101 0 : regrid(inputSpw,averagedDataStripe,averagedFlagsStripe,inputWeightsStripe,outputDataStripe,outputFlagsStripe);
9102 :
9103 0 : return;
9104 : }
9105 :
9106 : // -----------------------------------------------------------------------
9107 : //
9108 : // -----------------------------------------------------------------------
9109 0 : template <class T> void MSTransformManager::smoothRegrid(Int inputSpw,
9110 : const Vector<T> &inputDataStripe,
9111 : const Vector<bool> &inputFlagsStripe,
9112 : const Vector<Float> &inputWeightsStripe,
9113 : Vector<T> &outputDataStripe,
9114 : Vector<bool> &outputFlagsStripe)
9115 : {
9116 0 : Vector<T> smoothedDataStripe(inputDataStripe.shape(),T());
9117 0 : Vector<bool> smoothedFlagsStripe(inputFlagsStripe.shape(),false);
9118 :
9119 0 : smooth(inputSpw,inputDataStripe,inputFlagsStripe,inputWeightsStripe,smoothedDataStripe,smoothedFlagsStripe);
9120 :
9121 0 : regrid(inputSpw,smoothedDataStripe,smoothedFlagsStripe,inputWeightsStripe,outputDataStripe,outputFlagsStripe);
9122 :
9123 0 : return;
9124 : }
9125 :
9126 : // -----------------------------------------------------------------------
9127 : //
9128 : // -----------------------------------------------------------------------
9129 0 : template <class T> void MSTransformManager::averageSmooth(Int inputSpw,
9130 : const Vector<T> &inputDataStripe,
9131 : const Vector<bool> &inputFlagsStripe,
9132 : const Vector<Float> &inputWeightsStripe,
9133 : Vector<T> &outputDataStripe,
9134 : Vector<bool> &outputFlagsStripe)
9135 : {
9136 0 : Vector<T> averagedDataStripe(outputDataStripe.shape(),T());
9137 0 : Vector<bool> averagedFlagsStripe(outputFlagsStripe.shape(),false);
9138 :
9139 0 : average(inputSpw,inputDataStripe,inputFlagsStripe,inputWeightsStripe, averagedDataStripe,averagedFlagsStripe);
9140 :
9141 0 : smooth(inputSpw,averagedDataStripe,averagedFlagsStripe, inputWeightsStripe, outputDataStripe,outputFlagsStripe);
9142 :
9143 0 : return;
9144 : }
9145 :
9146 : // -----------------------------------------------------------------------
9147 : //
9148 : // -----------------------------------------------------------------------
9149 0 : template <class T> void MSTransformManager::averageSmoothRegrid(Int inputSpw,
9150 : const Vector<T> &inputDataStripe,
9151 : const Vector<bool> &inputFlagsStripe,
9152 : const Vector<Float> &inputWeightsStripe,
9153 : Vector<T> &outputDataStripe,
9154 : Vector<bool> &outputFlagsStripe)
9155 : {
9156 0 : Vector<T> averageSmoothedDataStripe(numOfCombInterChanMap_p[inputSpw],T());
9157 0 : Vector<bool> averageSmoothedFlagsStripe(numOfCombInterChanMap_p[inputSpw],false);
9158 :
9159 0 : averageSmooth( inputSpw,inputDataStripe,inputFlagsStripe,
9160 : inputWeightsStripe,averageSmoothedDataStripe,averageSmoothedFlagsStripe);
9161 :
9162 0 : regrid( inputSpw,averageSmoothedDataStripe,averageSmoothedFlagsStripe,
9163 : inputWeightsStripe,outputDataStripe,outputFlagsStripe);
9164 :
9165 0 : return;
9166 : }
9167 :
9168 : // -----------------------------------------------------------------------
9169 : //
9170 : // -----------------------------------------------------------------------
9171 0 : void MSTransformManager::smoothFourierFloat(Int,
9172 : const Vector<Float> &inputDataStripe,
9173 : const Vector<bool> &inputFlagStripe,
9174 : const Vector<Float> &,
9175 : Vector<Float> &outputDataStripe,
9176 : Vector<bool> &outputFlagStripe)
9177 : {
9178 : // replace flagged channel data with zero
9179 0 : auto mutableInputDataStripe = inputDataStripe;
9180 0 : Int const numChan = mutableInputDataStripe.nelements();
9181 0 : for (Int ichan = 0; ichan < numChan; ++ichan) {
9182 0 : if (inputFlagStripe[ichan]) {
9183 0 : mutableInputDataStripe[ichan] = 0.0f;
9184 : }
9185 : }
9186 :
9187 : // execute convolution
9188 0 : Convolver<Float> *convolver = getConvolver(numChan);
9189 0 : convolver->linearConv(outputDataStripe, mutableInputDataStripe);
9190 :
9191 : // copy input flags
9192 0 : outputFlagStripe = inputFlagStripe;
9193 0 : }
9194 :
9195 : // -----------------------------------------------------------------------
9196 : //
9197 : // -----------------------------------------------------------------------
9198 0 : void MSTransformManager::smoothFourierComplex(Int n,
9199 : const Vector<Complex> &inputDataStripe,
9200 : const Vector<bool> &inputFlagStripe,
9201 : const Vector<Float> &inputWeightStripe,
9202 : Vector<Complex> &outputDataStripe, Vector<bool> &outputFlagStripe)
9203 : {
9204 0 : Vector<Float> inputDataStripeFloat = real(inputDataStripe);
9205 0 : Vector<Float> outputDataStripeFloat(inputDataStripeFloat.nelements());
9206 0 : smoothFourierFloat(n, inputDataStripeFloat, inputFlagStripe,
9207 : inputWeightStripe, outputDataStripeFloat, outputFlagStripe);
9208 0 : convertArray(outputDataStripe, outputDataStripeFloat);
9209 0 : }
9210 :
9211 : // -----------------------------------------------------------------------
9212 : //
9213 : // -----------------------------------------------------------------------
9214 0 : Convolver<Float> *MSTransformManager::getConvolver(Int const numChan) {
9215 0 : if (convolverPool_.find(numChan) == convolverPool_.end()) {
9216 0 : throw AipsError("Failed to get convolver. Smoothing is not properly configured.");
9217 : }
9218 0 : return &convolverPool_[numChan];
9219 : }
9220 :
9221 : } //# NAMESPACE CASA - END
|