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 35 : MSTransformManager::MSTransformManager()
62 : {
63 35 : initialize();
64 35 : return;
65 0 : }
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 0 : }
77 :
78 :
79 : // -----------------------------------------------------------------------
80 : // Default destructor
81 : // -----------------------------------------------------------------------
82 70 : MSTransformManager::~MSTransformManager()
83 : {
84 : // Close the output MS in case the application layer does not do it
85 35 : close();
86 :
87 35 : if (channelSelector_p) delete channelSelector_p;
88 35 : if (visibilityIterator_p and !factory_p) delete visibilityIterator_p;
89 35 : if (dataHandler_p) delete dataHandler_p;
90 35 : 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 35 : if (userBufferMode_p)
95 : {
96 0 : TableUtil::deleteTable(outMsName_p,true);
97 : }
98 :
99 35 : return;
100 70 : }
101 :
102 : // -----------------------------------------------------------------------
103 : // Method to initialize members to default values
104 : // -----------------------------------------------------------------------
105 35 : void MSTransformManager::initialize()
106 : {
107 : // MS specification parameters
108 35 : inpMsName_p = String("");
109 35 : outMsName_p = String("");
110 35 : datacolumn_p = String("CORRECTED");
111 35 : makeVirtualModelColReal_p = false; // MODEL_DATA should always be made real via the datacol param.
112 35 : makeVirtualCorrectedColReal_p = true; // TODO: CORRECTED_DATA should be made real on request
113 35 : 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 35 : tileShape_p(0) = 0;
119 :
120 : // Data selection parameters
121 35 : arraySelection_p = String("");
122 35 : fieldSelection_p = String("");
123 35 : scanSelection_p = String("");
124 35 : timeSelection_p = String("");
125 35 : spwSelection_p = String("");
126 35 : baselineSelection_p = String("");
127 35 : uvwSelection_p = String("");
128 35 : polarizationSelection_p = String("");
129 35 : scanIntentSelection_p = String("");
130 35 : observationSelection_p = String("");
131 35 : taqlSelection_p = String("");
132 35 : feedSelection_p = String("");
133 :
134 : // Input-Output index maps
135 35 : inputOutputObservationIndexMap_p.clear();
136 35 : inputOutputArrayIndexMap_p.clear();
137 35 : inputOutputScanIndexMap_p.clear();
138 35 : inputOutputScanIntentIndexMap_p.clear();
139 35 : inputOutputFieldIndexMap_p.clear();
140 35 : inputOutputSPWIndexMap_p.clear();
141 35 : inputOutputDDIndexMap_p.clear();
142 35 : inputOutputAntennaIndexMap_p.clear();
143 35 : outputInputSPWIndexMap_p.clear();
144 35 : inputOutputChanIndexMap_p.clear();
145 :
146 : // Frequency transformation parameters
147 35 : smoothCoeff_p.resize(3,false);
148 35 : smoothCoeff_p(0) = 0.25;
149 35 : smoothCoeff_p(1) = 0.5;
150 35 : smoothCoeff_p(2) = 0.25;
151 :
152 : // Frequency specification parameters
153 35 : mode_p = String("channel"); // Options are: channel, frequency, velocity
154 35 : start_p = String("0");
155 35 : width_p = String("1");
156 35 : nChan_p = -1; // -1 means use all the input channels
157 35 : 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 35 : dx_p = 0;
163 35 : dy_p = 0;
164 35 : tviphaseshift_p = False;
165 35 : tviphaseshiftConfig_p = Record();
166 :
167 : // Time transformation parameters
168 35 : scalarAverage_p = false;
169 35 : timeAverage_p = false;
170 35 : timeBin_p = 0.0;
171 35 : timespan_p = String("");
172 35 : timeAvgOptions_p = vi::AveragingOptions(vi::AveragingOptions::Nothing);
173 35 : maxuvwdistance_p = 0;
174 : // minbaselines_p = 0;
175 :
176 : // Cal parameters
177 35 : calibrate_p = false;
178 35 : callib_p = "";
179 35 : callibRec_p = Record();
180 :
181 : // UVContSub parameters
182 35 : uvcontsub_p = False;
183 35 : uvcontsubRec_p = Record();
184 :
185 : // Spw averaging
186 35 : spwAverage_p = false;
187 :
188 : // Polarization transformation
189 35 : polAverage_p = false;
190 35 : polAverageConfig_p = Record();
191 :
192 : // Pointings interpolation
193 35 : pointingsInterpolation_p = false;
194 35 : pointingsInterpolationConfig_p = Record();
195 :
196 : // Weight Spectrum parameters
197 35 : usewtspectrum_p = false;
198 35 : spectrumTransformation_p = false;
199 35 : propagateWeights_p = false;
200 35 : flushWeightSpectrum_p = false;
201 :
202 : // MS-related members
203 35 : dataHandler_p = NULL;
204 35 : inputMs_p = NULL;
205 35 : selectedInputMs_p = NULL;
206 35 : outputMs_p = NULL;
207 35 : selectedInputMsCols_p = NULL;
208 35 : outputMsCols_p = NULL;
209 :
210 : // VI/VB related members
211 35 : sortColumns_p = Block<Int>(7);
212 35 : sortColumns_p[0] = MS::OBSERVATION_ID;
213 35 : sortColumns_p[1] = MS::ARRAY_ID;
214 35 : sortColumns_p[2] = MS::SCAN_NUMBER;
215 35 : sortColumns_p[3] = MS::STATE_ID;
216 35 : sortColumns_p[4] = MS::FIELD_ID;
217 35 : sortColumns_p[5] = MS::DATA_DESC_ID;
218 35 : sortColumns_p[6] = MS::TIME;
219 35 : visibilityIterator_p = NULL;
220 35 : channelSelector_p = NULL;
221 :
222 : // Output MS structure related members
223 35 : inputFlagCategoryAvailable_p = false;
224 35 : inputWeightSpectrumAvailable_p = false;
225 35 : weightSpectrumFromSigmaFilled_p = false;
226 35 : correctedToData_p = false;
227 35 : bothDataColumnsAreOutput_p = false;
228 35 : doingData_p = false;
229 35 : doingCorrected_p = false;
230 35 : doingModel_p = false;
231 35 : dataColMap_p.clear();
232 35 : mainColumn_p = MS::CORRECTED_DATA;
233 35 : nRowsToAdd_p = 0;
234 :
235 : // Frequency transformation members
236 35 : chansPerOutputSpw_p = 0;
237 35 : tailOfChansforLastSpw_p = 0;
238 35 : interpolationMethod_p = MSTransformations::linear;
239 35 : baselineMap_p.clear();
240 35 : rowIndex_p.clear();
241 35 : spwChannelMap_p.clear();
242 35 : inputOutputSpwMap_p.clear();
243 35 : inputOutputChanFactorMap_p.clear();
244 35 : freqbinMap_p.clear();
245 35 : numOfInpChanMap_p.clear();
246 35 : numOfSelChanMap_p.clear();
247 35 : numOfOutChanMap_p.clear();
248 35 : numOfCombInputChanMap_p.clear();
249 35 : numOfCombInterChanMap_p.clear();
250 35 : weightFactorMap_p.clear();
251 35 : sigmaFactorMap_p.clear();
252 35 : newWeightFactorMap_p.clear();
253 35 : newSigmaFactorMap_p.clear();
254 :
255 : // Reference frame transformation members
256 35 : fftShiftEnabled_p = false;
257 35 : fftShift_p = 0;
258 :
259 : // Weight Spectrum members
260 35 : inputWeightSpectrumAvailable_p = false;
261 35 : combinationOfSPWsWithDifferentExposure_p = false;
262 :
263 : // Transformations - related function pointers
264 35 : transformCubeOfDataComplex_p = NULL;
265 35 : transformCubeOfDataFloat_p = NULL;
266 35 : fillWeightsPlane_p = NULL;
267 35 : setWeightsPlaneByReference_p = NULL;
268 35 : setWeightStripeByReference_p = NULL;
269 35 : transformStripeOfDataComplex_p = NULL;
270 35 : transformStripeOfDataFloat_p = NULL;
271 35 : averageKernelComplex_p = NULL;
272 35 : averageKernelFloat_p = NULL;
273 35 : smoothKernelComplex_p = NULL;
274 35 : smoothKernelFloat_p = NULL;
275 :
276 : // I/O related function pointers
277 35 : writeOutputPlanesComplex_p = NULL;
278 35 : writeOutputPlanesFloat_p = NULL;
279 35 : writeOutputFlagsPlane_p = NULL;
280 35 : writeOutputFlagsPlaneSlices_p = NULL;
281 35 : writeOutputFlagsPlaneReshapedSlices_p = NULL;
282 :
283 : // Buffer handling members
284 35 : bufferMode_p = false;
285 35 : userBufferMode_p = false;
286 35 : reindex_p = true;
287 35 : factory_p = False;
288 35 : interactive_p = false;
289 35 : spectrumReshape_p = false;
290 35 : cubeTransformation_p = false;
291 35 : dataColumnAvailable_p = false;
292 35 : correctedDataColumnAvailable_p = false;
293 35 : modelDataColumnAvailable_p = false;
294 35 : floatDataColumnAvailable_p = false;
295 35 : flagCube_p = NULL;
296 35 : visCube_p = NULL;
297 35 : visCubeCorrected_p = NULL;
298 35 : visCubeModel_p = NULL;
299 35 : visCubeFloat_p = NULL;
300 35 : weightSpectrum_p = NULL;
301 35 : sigmaSpectrum_p = NULL;
302 35 : weight_p = NULL;
303 35 : sigma_p = NULL;
304 35 : relativeRow_p = 0;
305 :
306 : // single dish specific
307 35 : smoothFourier_p = false;
308 :
309 35 : return;
310 : }
311 :
312 : // -----------------------------------------------------------------------
313 : // Method to parse the configuration parameters
314 : // -----------------------------------------------------------------------
315 35 : void MSTransformManager::configure(Record &configuration)
316 : {
317 35 : parseMsSpecParams(configuration);
318 35 : parseDataSelParams(configuration);
319 35 : parseFreqTransParams(configuration);
320 35 : parseChanAvgParams(configuration);
321 35 : parseRefFrameTransParams(configuration);
322 35 : parseTimeAvgParams(configuration);
323 35 : parseCalParams(configuration);
324 35 : parseUVContSubParams(configuration);
325 35 : setSpwAvg(configuration);
326 35 : parsePolAvgParams(configuration);
327 35 : parsePointingsInterpolationParams(configuration);
328 35 : parsePhaseShiftParams(configuration);
329 35 : parseAtmCorrectionParams(configuration);
330 :
331 35 : return;
332 : }
333 :
334 : // -----------------------------------------------------------------------
335 : // Method to parse input/output MS specification
336 : // -----------------------------------------------------------------------
337 35 : void MSTransformManager::parseMsSpecParams(Record &configuration)
338 : {
339 35 : int exists = -1;
340 :
341 35 : exists = -1;
342 35 : exists = configuration.fieldNumber ("inputms");
343 35 : if (exists >= 0)
344 : {
345 35 : configuration.get (exists, inpMsName_p);
346 70 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
347 70 : << "Input file name is " << inpMsName_p << LogIO::POST;
348 : }
349 :
350 35 : exists = -1;
351 35 : exists = configuration.fieldNumber ("buffermode");
352 35 : 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 35 : exists = -1;
363 35 : exists = configuration.fieldNumber ("datacolumn");
364 35 : if (exists >= 0)
365 : {
366 35 : configuration.get (exists, datacolumn_p);
367 70 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
368 70 : << "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 35 : exists = -1;
373 35 : exists = configuration.fieldNumber ("outputms");
374 35 : if (exists >= 0)
375 : {
376 35 : configuration.get (exists, outMsName_p);
377 :
378 : // Inform of filename only in normal mode, as in buffer mode is random generated
379 35 : if (not bufferMode_p)
380 : {
381 70 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
382 70 : << "Output file name is " << outMsName_p << LogIO::POST;
383 : }
384 : }
385 :
386 35 : exists = -1;
387 35 : exists = configuration.fieldNumber ("reindex");
388 35 : if (exists >= 0)
389 : {
390 31 : configuration.get (exists, reindex_p);
391 :
392 31 : if (reindex_p)
393 : {
394 62 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
395 62 : << "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 35 : exists = -1;
405 35 : exists = configuration.fieldNumber ("factory");
406 35 : 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 35 : 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 35 : interactive_p = false;
442 :
443 35 : exists = -1;
444 35 : exists = configuration.fieldNumber ("realmodelcol");
445 35 : if (exists >= 0)
446 : {
447 3 : configuration.get (exists, makeVirtualModelColReal_p);
448 3 : 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 35 : exists = -1;
469 35 : exists = configuration.fieldNumber ("usewtspectrum");
470 35 : if (exists >= 0)
471 : {
472 31 : configuration.get (exists, usewtspectrum_p);
473 31 : if (usewtspectrum_p)
474 : {
475 2 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
476 2 : << "WEIGHT_SPECTRUM will be written in output MS " << LogIO::POST;
477 : }
478 : }
479 :
480 35 : exists = -1;
481 35 : exists = configuration.fieldNumber ("tileshape");
482 35 : if (exists >= 0)
483 : {
484 31 : 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 31 : else if ( configuration.type(exists) == casacore::TpArrayInt)
491 : {
492 31 : configuration.get (exists, tileShape_p);
493 : }
494 :
495 62 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
496 62 : << "Tile shape is " << tileShape_p << LogIO::POST;
497 : }
498 : }
499 :
500 35 : return;
501 : }
502 :
503 : // -----------------------------------------------------------------------
504 : // Method to parse the data selection parameters
505 : // -----------------------------------------------------------------------
506 35 : void MSTransformManager::parseDataSelParams(Record &configuration)
507 : {
508 35 : int exists = -1;
509 :
510 35 : exists = -1;
511 35 : exists = configuration.fieldNumber ("array");
512 35 : 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 35 : exists = -1;
520 35 : exists = configuration.fieldNumber ("field");
521 35 : 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 35 : exists = -1;
529 35 : exists = configuration.fieldNumber ("scan");
530 35 : if (exists >= 0)
531 : {
532 1 : configuration.get (exists, scanSelection_p);
533 2 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
534 2 : << "scan selection is " << scanSelection_p << LogIO::POST;
535 : }
536 :
537 35 : exists = -1;
538 35 : exists = configuration.fieldNumber ("timerange");
539 35 : if (exists >= 0)
540 : {
541 1 : configuration.get (exists, timeSelection_p);
542 2 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
543 2 : << "timerange selection is " << timeSelection_p << LogIO::POST;
544 : }
545 :
546 35 : exists = -1;
547 35 : exists = configuration.fieldNumber ("spw");
548 35 : if (exists >= 0)
549 : {
550 3 : configuration.get (exists, spwSelection_p);
551 6 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
552 6 : << "spw selection is " << spwSelection_p << LogIO::POST;
553 : }
554 :
555 35 : exists = -1;
556 35 : exists = configuration.fieldNumber ("antenna");
557 35 : if (exists >= 0)
558 : {
559 1 : configuration.get (exists, baselineSelection_p);
560 2 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
561 2 : << "antenna selection is " << baselineSelection_p << LogIO::POST;
562 : }
563 :
564 35 : exists = -1;
565 35 : exists = configuration.fieldNumber ("uvrange");
566 35 : 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 35 : exists = -1;
574 35 : exists = configuration.fieldNumber ("correlation");
575 35 : 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 35 : exists = -1;
583 35 : exists = configuration.fieldNumber ("observation");
584 35 : 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 35 : exists = -1;
592 35 : exists = configuration.fieldNumber ("intent");
593 35 : 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 35 : exists = -1;
601 35 : exists = configuration.fieldNumber ("taql");
602 35 : 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 35 : exists = -1;
610 35 : exists = configuration.fieldNumber ("feed");
611 35 : 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 35 : return;
619 : }
620 :
621 : // -----------------------------------------------------------------------
622 : // Method to parse the channel average parameters
623 : // -----------------------------------------------------------------------
624 35 : void MSTransformManager::parseChanAvgParams(Record &configuration)
625 : {
626 35 : int exists = -1;
627 :
628 35 : exists = -1;
629 35 : exists = configuration.fieldNumber ("chanaverage");
630 35 : if (exists >= 0)
631 : {
632 17 : configuration.get (exists, channelAverage_p);
633 17 : if (channelAverage_p)
634 : {
635 34 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
636 34 : << "Channel average is activated" << LogIO::POST;
637 : }
638 : else
639 : {
640 0 : return;
641 : }
642 : }
643 : else
644 : {
645 18 : return;
646 : }
647 :
648 17 : exists = -1;
649 17 : exists = configuration.fieldNumber ("chanbin");
650 17 : if (exists >= 0)
651 : {
652 17 : if ( configuration.type(exists) == casacore::TpInt )
653 : {
654 : Int freqbin;
655 17 : configuration.get (exists, freqbin);
656 :
657 17 : 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 17 : 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 34 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
685 34 : << "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 17 : return;
725 : }
726 :
727 : // -----------------------------------------------------------------------
728 : // Method to parse the frequency transformation parameters
729 : // -----------------------------------------------------------------------
730 35 : void MSTransformManager::parseFreqTransParams(Record &configuration)
731 : {
732 35 : int exists = -1;
733 :
734 35 : exists = -1;
735 35 : exists = configuration.fieldNumber ("combinespws");
736 35 : 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 35 : exists = -1;
748 35 : exists = configuration.fieldNumber ("ddistart");
749 35 : if (exists >= 0)
750 : {
751 31 : configuration.get (exists, ddiStart_p);
752 31 : 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 31 : ddiStart_p = 0;
760 : }
761 :
762 : }
763 :
764 35 : exists = -1;
765 35 : exists = configuration.fieldNumber ("hanning");
766 35 : 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 0 : exists = -1;
781 0 : exists = configuration.fieldNumber ("smooth_spw");
782 0 : if (exists >= 0)
783 : {
784 0 : Array<int> smooth_spw;
785 0 : configuration.get (exists, smooth_spw);
786 0 : smooth_spw_p = smooth_spw.tovector();
787 0 : }
788 : }
789 : }
790 :
791 35 : exists = -1;
792 35 : exists = configuration.fieldNumber("smoothFourier");
793 35 : if (exists >= 0)
794 : {
795 0 : configuration.get(exists, smoothFourier_p);
796 0 : if (smoothFourier_p) {
797 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
798 0 : << "Fourier smoothing (single dish specific) is activated" << LogIO::POST;
799 : }
800 : }
801 :
802 35 : return;
803 : }
804 :
805 : // -----------------------------------------------------------------------
806 : // Method to parse the reference frame transformation parameters
807 : // -----------------------------------------------------------------------
808 35 : void MSTransformManager::parseRefFrameTransParams(Record &configuration)
809 : {
810 35 : int exists = -1;
811 :
812 35 : exists = -1;
813 35 : exists = configuration.fieldNumber ("regridms");
814 35 : if (exists >= 0)
815 : {
816 0 : configuration.get (exists, regridding_p);
817 :
818 0 : if (regridding_p)
819 : {
820 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
821 0 : << "Regrid MS is activated"<< LogIO::POST;
822 : }
823 : else
824 : {
825 0 : return;
826 : }
827 : }
828 :
829 35 : exists = -1;
830 35 : exists = configuration.fieldNumber ("phasecenter");
831 35 : if (exists >= 0)
832 : {
833 : //If phase center is a simple numeric value then it is taken
834 : // as a FIELD_ID otherwise it is converted to a MDirection
835 0 : if( configuration.type(exists) == TpInt )
836 : {
837 0 : int fieldIdForPhaseCenter = -1;
838 0 : configuration.get (exists, fieldIdForPhaseCenter);
839 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
840 0 : << "Field Id for phase center is " << fieldIdForPhaseCenter << LogIO::POST;
841 0 : if (phaseCenterPar_p) delete phaseCenterPar_p;
842 0 : phaseCenterPar_p = new casac::variant((long)fieldIdForPhaseCenter);
843 : }
844 : else
845 : {
846 0 : String phaseCenter("");
847 0 : configuration.get (exists, phaseCenter);
848 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
849 0 : << "Phase center is " << phaseCenter << LogIO::POST;
850 0 : if (phaseCenterPar_p) delete phaseCenterPar_p;
851 0 : phaseCenterPar_p = new casac::variant(phaseCenter);
852 0 : }
853 : }
854 :
855 35 : exists = -1;
856 35 : exists = configuration.fieldNumber ("restfreq");
857 35 : if (exists >= 0)
858 : {
859 0 : configuration.get (exists, restFrequency_p);
860 0 : if (!restFrequency_p.empty())
861 : {
862 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
863 0 : << "Rest frequency is " << restFrequency_p << LogIO::POST;
864 : }
865 : }
866 :
867 35 : exists = -1;
868 35 : exists = configuration.fieldNumber ("outframe");
869 35 : if (exists >= 0)
870 : {
871 0 : configuration.get (exists, outputReferenceFramePar_p);
872 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
873 0 : << "Output reference frame is " << outputReferenceFramePar_p << LogIO::POST;
874 : }
875 :
876 35 : exists = -1;
877 35 : exists = configuration.fieldNumber ("interpolation");
878 35 : if (exists >= 0)
879 : {
880 0 : configuration.get (exists, interpolationMethodPar_p);
881 :
882 0 : if (interpolationMethodPar_p.contains("nearest"))
883 : {
884 0 : interpolationMethod_p = MSTransformations::nearestNeighbour;
885 : }
886 0 : else if (interpolationMethodPar_p.contains("linear"))
887 : {
888 0 : interpolationMethod_p = MSTransformations::linear;
889 : }
890 0 : else if (interpolationMethodPar_p.contains("cubic"))
891 : {
892 0 : interpolationMethod_p = MSTransformations::cubic;
893 : }
894 0 : else if (interpolationMethodPar_p.contains("spline"))
895 : {
896 0 : interpolationMethod_p = MSTransformations::spline;
897 : }
898 0 : else if (interpolationMethodPar_p.contains("fftshift"))
899 : {
900 0 : fftShiftEnabled_p = true;
901 0 : interpolationMethod_p = MSTransformations::linear;
902 : }
903 : else
904 : {
905 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
906 0 : << "Interpolation method " << interpolationMethodPar_p << " not available " << LogIO::POST;
907 : }
908 :
909 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
910 0 : << "Interpolation method is " << interpolationMethodPar_p << LogIO::POST;
911 : }
912 : else
913 : {
914 35 : interpolationMethod_p = MSTransformations::linear;
915 : }
916 :
917 35 : exists = -1;
918 35 : exists = configuration.fieldNumber ("nspw");
919 35 : if (exists >= 0)
920 : {
921 0 : configuration.get (exists, nspws_p);
922 :
923 0 : if (nspws_p > 1)
924 : {
925 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
926 0 : << "Number of output SPWs is " << nspws_p << LogIO::POST;
927 0 : combinespws_p = true;
928 : }
929 : else
930 : {
931 0 : nspws_p = 1;
932 : }
933 : }
934 :
935 35 : parseFreqSpecParams(configuration);
936 :
937 35 : exists = configuration.fieldNumber ("preaverage");
938 35 : if (exists >= 0) {
939 0 : configuration.get (exists, enableChanPreAverage_p);
940 :
941 0 : if (combinespws_p) {
942 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
943 0 : << "Enabling channel pre-averaging" << LogIO::POST;
944 : }
945 : }
946 :
947 35 : return;
948 : }
949 :
950 : // -----------------------------------------------------------------------
951 : // Method to parse the frequency selection specification
952 : // -----------------------------------------------------------------------
953 35 : void MSTransformManager::parseFreqSpecParams(Record &configuration)
954 : {
955 35 : int exists = -1;
956 :
957 35 : exists = -1;
958 35 : exists = configuration.fieldNumber ("mode");
959 35 : if (exists >= 0)
960 : {
961 0 : configuration.get (exists, mode_p);
962 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
963 0 : << "Mode is " << mode_p<< LogIO::POST;
964 :
965 0 : if ((mode_p == "frequency") or (mode_p == "velocity"))
966 : {
967 0 : start_p = String("");
968 0 : width_p = String("");
969 : }
970 : }
971 :
972 35 : exists = -1;
973 35 : exists = configuration.fieldNumber ("nchan");
974 35 : if (exists >= 0)
975 : {
976 0 : configuration.get (exists, nChan_p);
977 0 : if (nspws_p > 1)
978 : {
979 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
980 0 : << "Number of output channels per output spw is " << nChan_p << LogIO::POST;
981 0 : nChan_p *= nspws_p;
982 : }
983 : else
984 : {
985 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
986 0 : << "Number of output channels is " << nChan_p<< LogIO::POST;
987 : }
988 : }
989 :
990 35 : exists = -1;
991 35 : exists = configuration.fieldNumber ("start");
992 35 : if (exists >= 0)
993 : {
994 0 : configuration.get (exists, start_p);
995 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
996 0 : << "Start is " << start_p << LogIO::POST;
997 : }
998 :
999 35 : exists = -1;
1000 35 : exists = configuration.fieldNumber ("width");
1001 35 : if (exists >= 0)
1002 : {
1003 0 : configuration.get (exists, width_p);
1004 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1005 0 : << "Width is " << width_p << LogIO::POST;
1006 : }
1007 :
1008 35 : exists = -1;
1009 35 : exists = configuration.fieldNumber ("veltype");
1010 35 : if ((exists >= 0) and (mode_p == "velocity"))
1011 : {
1012 0 : configuration.get (exists, velocityType_p);
1013 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1014 0 : << "Velocity type is " << velocityType_p << LogIO::POST;
1015 : }
1016 :
1017 35 : return;
1018 : }
1019 :
1020 : // -----------------------------------------------------------------------
1021 : // Method to parse the phase shifting specification
1022 : // -----------------------------------------------------------------------
1023 : // CAS-12706 To run phase shift via a TVI which has
1024 : // support for shifting across large offset/angles
1025 : // -----------------------------------------------------------------------
1026 35 : void MSTransformManager::parsePhaseShiftParams(Record &configuration)
1027 : {
1028 35 : int exists = -1;
1029 :
1030 35 : exists = -1;
1031 35 : exists = configuration.fieldNumber("tviphaseshift");
1032 35 : if (exists >= 0)
1033 : {
1034 0 : configuration.get (exists, tviphaseshift_p);
1035 :
1036 0 : if (tviphaseshift_p)
1037 : {
1038 : // Extract the callib Record
1039 0 : exists = -1;
1040 0 : exists = configuration.fieldNumber("tviphaseshiftlib");
1041 0 : if (configuration.type(exists) == TpRecord)
1042 : {
1043 0 : tviphaseshiftConfig_p = configuration.subRecord(exists);
1044 : }
1045 :
1046 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager",__FUNCTION__)
1047 : << "Phase shifting via TVI with support for large offset/angle "
1048 0 : << LogIO::POST;
1049 : }
1050 : }
1051 :
1052 35 : return;
1053 : }
1054 :
1055 : // -----------------------------------------------------------------------
1056 : // Method to parse the time average specification
1057 : // -----------------------------------------------------------------------
1058 35 : void MSTransformManager::parseTimeAvgParams(Record &configuration)
1059 : {
1060 35 : int exists = -1;
1061 :
1062 35 : exists = -1;
1063 35 : exists = configuration.fieldNumber ("timeaverage");
1064 35 : if (exists >= 0)
1065 : {
1066 19 : configuration.get (exists, timeAverage_p);
1067 :
1068 19 : if (timeAverage_p)
1069 : {
1070 38 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1071 38 : << "Time average is activated" << LogIO::POST;
1072 : }
1073 : }
1074 :
1075 35 : exists = -1;
1076 35 : exists = configuration.fieldNumber ("scalaraverage");
1077 35 : if (exists >= 0)
1078 : {
1079 0 : configuration.get (exists, scalarAverage_p);
1080 :
1081 0 : if (scalarAverage_p)
1082 : {
1083 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1084 0 : << "Scalar average is activated" << LogIO::POST;
1085 : }
1086 : }
1087 :
1088 35 : if (timeAverage_p || scalarAverage_p)
1089 : {
1090 19 : exists = -1;
1091 19 : exists = configuration.fieldNumber ("timebin");
1092 19 : if (exists >= 0)
1093 : {
1094 19 : String timebin;
1095 19 : configuration.get (exists, timebin);
1096 19 : timeBin_p=casaQuantity(timebin).get("s").getValue();
1097 :
1098 38 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1099 38 : << "Time bin is " << timeBin_p << " seconds" << LogIO::POST;
1100 19 : }
1101 : else
1102 : {
1103 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
1104 0 : << "Time or scalar average is activated but no timebin parameter provided " << LogIO::POST;
1105 0 : timeAverage_p = false;
1106 0 : scalarAverage_p = false;
1107 0 : return;
1108 : }
1109 :
1110 19 : exists = -1;
1111 19 : exists = configuration.fieldNumber ("timespan");
1112 19 : if (exists >= 0)
1113 : {
1114 19 : configuration.get (exists, timespan_p);
1115 :
1116 19 : if (!timespan_p.contains("scan") and !timespan_p.contains("state") and !timespan_p.contains("field"))
1117 : {
1118 19 : timespan_p = String("");
1119 : }
1120 : else
1121 : {
1122 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1123 0 : << "Time span is " << timespan_p << LogIO::POST;
1124 : }
1125 : }
1126 :
1127 : // CAS-4850 (jagonzal): For ALMA each bdf is limited to 30s, so we need to combine across state (i.e. su-scan)
1128 19 : if (timeAverage_p && (timeBin_p > 30.0) and !timespan_p.contains("state"))
1129 : {
1130 0 : MeasurementSet tmpMs(inpMsName_p,Table::Old);
1131 0 : MSObservation observationTable = tmpMs.observation();
1132 0 : MSObservationColumns observationCols(observationTable);
1133 0 : String telescopeName = observationCols.telescopeName()(0);
1134 :
1135 0 : if (telescopeName.contains("ALMA"))
1136 : {
1137 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
1138 : << "Operating with ALMA data, automatically adding state to timespan "<< endl
1139 0 : << "In order to remove sub-scan boundaries which limit time average to 30s "<< LogIO::POST;
1140 0 : timespan_p += String(",state");
1141 : }
1142 0 : }
1143 :
1144 19 : exists = -1;
1145 19 : exists = configuration.fieldNumber ("maxuvwdistance");
1146 19 : if (exists >= 0)
1147 : {
1148 19 : configuration.get (exists, maxuvwdistance_p);
1149 :
1150 19 : if (maxuvwdistance_p > 0)
1151 : {
1152 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1153 : << "Maximum UV distance for baseline-dependent time average is: "
1154 0 : << maxuvwdistance_p << " meters" << LogIO::POST;
1155 : }
1156 : }
1157 :
1158 : /*
1159 : exists = configuration.fieldNumber ("minbaselines");
1160 : if (exists >= 0)
1161 : {
1162 : configuration.get (exists, minbaselines_p);
1163 :
1164 : if (minbaselines_p > 0)
1165 : {
1166 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1167 : << "Minimum number of baselines for time average: " << minbaselines_p << LogIO::POST;
1168 : }
1169 : }
1170 : */
1171 : }
1172 :
1173 35 : return;
1174 : }
1175 :
1176 : // -----------------------------------------------------------------------
1177 : // Parameter parser for on-the-fly (OTF) calibration
1178 : // -----------------------------------------------------------------------
1179 35 : void MSTransformManager::parseCalParams(Record &configuration)
1180 : {
1181 35 : int exists = configuration.fieldNumber("callib");
1182 35 : if (exists >= 0)
1183 : {
1184 :
1185 0 : if (configuration.type(exists) == TpRecord)
1186 : {
1187 : // Extract the callib Record
1188 0 : callibRec_p = configuration.subRecord(exists);
1189 0 : callib_p="";
1190 :
1191 : // If the Record is non-trivial, calibration is turned on
1192 0 : calibrate_p = callibRec_p.nfields() > 0;
1193 : }
1194 0 : else if (configuration.type(exists) == TpString)
1195 : {
1196 : // Extract the callib String
1197 0 : callib_p = configuration.asString(exists);
1198 0 : callibRec_p = Record();
1199 :
1200 : // If the callib_p String has non-trivial content, calibration in turned on
1201 0 : calibrate_p = callib_p.length() > 0;
1202 :
1203 : }
1204 :
1205 0 : if (calibrate_p)
1206 : {
1207 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager",__FUNCTION__)
1208 0 : << "Calibration is activated" << LogIO::POST;
1209 : }
1210 :
1211 : }
1212 :
1213 35 : return;
1214 : }
1215 :
1216 : // -----------------------------------------------------------------------
1217 : // Parameter parser for continuum subtraction
1218 : // -----------------------------------------------------------------------
1219 35 : void MSTransformManager::parseUVContSubParams(Record &configuration)
1220 : {
1221 35 : int exists = -1;
1222 :
1223 35 : exists = -1;
1224 35 : exists = configuration.fieldNumber("uvcontsub");
1225 35 : if (exists >= 0)
1226 : {
1227 0 : configuration.get (exists, uvcontsub_p);
1228 :
1229 0 : if (uvcontsub_p)
1230 : {
1231 : // Extract the callib Record
1232 0 : exists = -1;
1233 0 : exists = configuration.fieldNumber("uvcontsublib");
1234 0 : if (configuration.type(exists) == TpRecord)
1235 : {
1236 0 : uvcontsubRec_p = configuration.subRecord(exists);
1237 : }
1238 :
1239 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager",
1240 : __FUNCTION__)
1241 : << "Continuum subtraction is activated "
1242 0 : << LogIO::POST;
1243 :
1244 : // not nice going into the subRec, perhaps a writemodel var
1245 : // could be put in the top level record
1246 0 : int writemodel = uvcontsubRec_p.fieldNumber("writemodel");
1247 0 : if (writemodel >= 0) {
1248 0 : bool dowrite = false;
1249 0 : uvcontsubRec_p.get(writemodel, dowrite);
1250 0 : if (dowrite) {
1251 0 : produceModel_p = true;
1252 : }
1253 : }
1254 : }
1255 : }
1256 35 : }
1257 :
1258 : // -----------------------------------------------------------------------
1259 : // Method to set spw averaging
1260 : // -----------------------------------------------------------------------
1261 35 : void MSTransformManager::setSpwAvg(Record &configuration)
1262 : {
1263 35 : int exists = -1;
1264 :
1265 35 : exists = -1;
1266 35 : exists = configuration.fieldNumber ("spwaverage");
1267 35 : if (exists >= 0)
1268 : {
1269 0 : configuration.get (exists, spwAverage_p);
1270 :
1271 0 : if (spwAverage_p)
1272 : {
1273 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1274 0 : << "Spw average is activated" << LogIO::POST;
1275 : }
1276 : }
1277 35 : }
1278 :
1279 : // -----------------------------------------------------------------------
1280 : // Parameter parser for polarization transformation
1281 : // -----------------------------------------------------------------------
1282 35 : void MSTransformManager::parsePolAvgParams(Record &configuration)
1283 : {
1284 35 : String key("polaverage");
1285 35 : bool exists = configuration.isDefined(key);
1286 35 : if (exists) {
1287 0 : polAverage_p = configuration.asBool(key);
1288 : }
1289 :
1290 35 : key = "polaveragemode";
1291 35 : if (polAverage_p) {
1292 0 : if (configuration.isDefined(key)) {
1293 0 : polAverageConfig_p.define("mode", configuration.asString(key));
1294 : } else {
1295 0 : polAverageConfig_p.define("mode", "default");
1296 : }
1297 : }
1298 35 : }
1299 :
1300 35 : void MSTransformManager::parsePointingsInterpolationParams(casacore::Record &configuration){
1301 35 : String key("pointingsinterpolation");
1302 35 : bool exists = configuration.isDefined(key);
1303 35 : if (exists) {
1304 0 : pointingsInterpolation_p = configuration.asBool(key);
1305 : }
1306 35 : }
1307 :
1308 35 : void MSTransformManager::parseAtmCorrectionParams(casacore::Record &configuration) {
1309 35 : String key("atmCor");
1310 35 : if (configuration.isDefined(key)) {
1311 0 : doAtmCor_p = configuration.asBool(key);
1312 0 : atmCorConfig_p = configuration;
1313 : } else {
1314 35 : doAtmCor_p = False;
1315 : }
1316 35 : }
1317 :
1318 : // -----------------------------------------------------------------------
1319 : // Method to open the input MS, select the data and create the
1320 : // structure of the output MS filling the auxiliary tables.
1321 : // -----------------------------------------------------------------------
1322 35 : void MSTransformManager::open()
1323 : {
1324 : // Initialize MSTransformDataHandler to open the MeasurementSet object
1325 35 : if (interactive_p)
1326 : {
1327 : // In buffer mode we may have to modify the flags
1328 0 : dataHandler_p = new MSTransformDataHandler(inpMsName_p,Table::Update);
1329 : }
1330 : else
1331 : {
1332 35 : dataHandler_p = new MSTransformDataHandler(inpMsName_p,Table::Old);
1333 : }
1334 :
1335 :
1336 : // WARNING: Input MS is re-set at the end of a successful MSTransformDataHandler::makeMSBasicStructure,
1337 : // call therefore we have to use the selected MS always
1338 35 : inputMs_p = dataHandler_p->getInputMS();
1339 : // Note: We always get the input number of channels because we don't know if pre-averaging will be necessary
1340 35 : getInputNumberOfChannels();
1341 :
1342 : // Check available data cols to pass this information on to MSTransformDataHandler which creates the MS structure
1343 35 : checkDataColumnsAvailable();
1344 35 : checkDataColumnsToFill();
1345 :
1346 :
1347 : // Check whether the MS has correlator pre-averaging and we are smoothing or averaging
1348 35 : checkCorrelatorPreaveraging();
1349 :
1350 : // Set virtual column operation
1351 35 : dataHandler_p->setVirtualModelCol(makeVirtualModelColReal_p);
1352 35 : dataHandler_p->setVirtualCorrectedCol(makeVirtualCorrectedColReal_p);
1353 :
1354 : // Once the input MS is opened we can get the selection indexes,
1355 : // in this way we also validate the selection parameters
1356 35 : dataHandler_p->setReindex(reindex_p);
1357 35 : initDataSelectionParams();
1358 :
1359 : // Once the selection parameters have been processed, check consistency in
1360 : // number of channels, if needed.
1361 35 : checkSPWChannelsKnownLimitation();
1362 :
1363 : // Determine channel specification for output MS
1364 35 : Vector<Int> chanSpec;
1365 35 : bool spectralRegridding = combinespws_p or regridding_p;
1366 35 : if (channelAverage_p and !spectralRegridding)
1367 : {
1368 17 : chanSpec = freqbin_p;
1369 : }
1370 : else
1371 : {
1372 18 : chanSpec = Vector<Int>(1,1);
1373 : }
1374 :
1375 : // Set-up splitter object
1376 35 : const String dummyExpr = String("");
1377 35 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__) << "Select data" << LogIO::POST;
1378 35 : dataHandler_p->setmsselect((const String)spwSelection_p,
1379 70 : (const String)fieldSelection_p,
1380 70 : (const String)baselineSelection_p,
1381 70 : (const String)scanSelection_p,
1382 70 : (const String)uvwSelection_p,
1383 70 : (const String)taqlSelection_p,
1384 : chanSpec,
1385 70 : (const String)arraySelection_p,
1386 70 : (const String)polarizationSelection_p,
1387 70 : (const String)scanIntentSelection_p,
1388 70 : (const String)observationSelection_p,
1389 70 : (const String)feedSelection_p);
1390 :
1391 35 : dataHandler_p->selectTime(timeBin_p,timeSelection_p);
1392 :
1393 35 : createOutputMSStructure();
1394 :
1395 : // jagonzal (CAS-5076): Reindex state column when there is scan selection
1396 : // jagonzal (CAS-6351): Removing this fix as only implicit selection-based re-indexing has to be applied
1397 : /*
1398 : map<Int, Int> stateRemapper = dataHandler_p->getStateRemapper();
1399 : std::map<Int, Int>::iterator stateRemapperIter;
1400 : for ( stateRemapperIter = stateRemapper.begin();
1401 : stateRemapperIter != stateRemapper.end();
1402 : stateRemapperIter++)
1403 : {
1404 : inputOutputScanIntentIndexMap_p[stateRemapperIter->first] = stateRemapperIter->second;
1405 :
1406 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1407 : << "State " << stateRemapperIter->first << " mapped to " << stateRemapperIter->second << LogIO::POST;
1408 : }
1409 : */
1410 :
1411 : // jagonzal (CAS-5349): Reindex antenna columns when there is antenna selection
1412 35 : if (!baselineSelection_p.empty() and reindex_p)
1413 : {
1414 1 : Vector<Int> antennaRemapper = dataHandler_p->getAntennaRemapper();
1415 4 : for (uInt oldIndex=0;oldIndex<antennaRemapper.size();oldIndex++)
1416 : {
1417 3 : inputOutputAntennaIndexMap_p[oldIndex] = antennaRemapper[oldIndex];
1418 : }
1419 1 : }
1420 :
1421 :
1422 35 : selectedInputMs_p = dataHandler_p->getSelectedInputMS();
1423 35 : outputMs_p = dataHandler_p->getOutputMS();
1424 35 : selectedInputMsCols_p = dataHandler_p->getSelectedInputMSColumns();
1425 35 : outputMsCols_p = dataHandler_p->getOutputMSColumns();
1426 :
1427 70 : return;
1428 35 : }
1429 :
1430 : /**
1431 : * Whether the WEIGHT/SIGMA_SPECTRUM columns should be created in the output MS.
1432 : * This should be honored when creating the output MS structure (in
1433 : * createOutputMSStructure().
1434 : *
1435 : * The logic to say true is: if the WEIGHT/SIGMA_SPECTRUM are present in the input MS or
1436 : * the user has requested the creation of these columns in the output MS anyway via the
1437 : * parameter 'usewtspectrum'
1438 : * This requires that the input configuration be parsed here in MSTransformManager before
1439 : * calling this method, and passed as parameter.
1440 : *
1441 : * @param usewtspectrum value of the usewtspectrum input parameter of mstransform
1442 : *
1443 : * @return whether WEIGHT/SIGMA_SPECTRUM columns should be created in the output MS.
1444 : */
1445 35 : bool MSTransformManager::shouldCreateOutputWtSpectrum(bool usewtspectrum)
1446 : {
1447 35 : if (nullptr == inputMs_p) {
1448 0 : throw AipsError("When trying to guess if WEIGHT/SIGMA_SPECTRUM should be created "
1449 0 : "in the output MS: the input MS has not been initialized.");
1450 : }
1451 :
1452 35 : auto wtSpec = MSColumns(*inputMs_p).weightSpectrum();
1453 35 : auto inputWeightSpectrumAvailable = !wtSpec.isNull() and wtSpec.isDefined(0);
1454 70 : return inputWeightSpectrumAvailable or usewtspectrum;
1455 35 : }
1456 :
1457 : /**
1458 : * Helper method for open() to create the structure of the output MS
1459 : * and check errors.
1460 : *
1461 : * @throws AipsError in case of errors creating the output MS
1462 : */
1463 35 : void MSTransformManager::createOutputMSStructure()
1464 : {
1465 : // Create output MS structure
1466 35 : if (not bufferMode_p)
1467 : {
1468 70 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1469 70 : << "Create output MS structure" << LogIO::POST;
1470 : }
1471 : else
1472 : {
1473 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1474 0 : << "Create transformed MS Subtables to be stored in memory" << LogIO::POST;
1475 : }
1476 :
1477 :
1478 : //jagonzal (CAS-5174)
1479 35 : bool outputMSStructureCreated = false;
1480 : try
1481 : {
1482 35 : Table::TableOption option = Table::New;
1483 35 : if (bufferMode_p) {
1484 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
1485 0 : << "Create output MS structure" << LogIO::POST;
1486 0 : option = Table::Scratch;
1487 : }
1488 :
1489 35 : auto createWeightSpectrum = shouldCreateOutputWtSpectrum(usewtspectrum_p);
1490 70 : outputMSStructureCreated = dataHandler_p->makeMSBasicStructure(outMsName_p,
1491 35 : datacolumn_p,
1492 35 : produceModel_p,
1493 : createWeightSpectrum,
1494 35 : tileShape_p,
1495 35 : timespan_p,
1496 : option);
1497 : }
1498 0 : catch (const AipsError &ex)
1499 : {
1500 0 : outputMSStructureCreated = false;
1501 0 : logger_p << LogIO::DEBUG1
1502 : << "Exception creating output MS structure: " << ex.getMesg() << endl
1503 0 : << LogIO::POST;
1504 :
1505 0 : throw AipsError(ex.getMesg());
1506 0 : }
1507 :
1508 :
1509 :
1510 35 : if (!outputMSStructureCreated)
1511 : {
1512 0 : throw AipsError("Error creating output MS structure");
1513 : }
1514 35 : }
1515 :
1516 : // -----------------------------------------------------------------------
1517 : // Method to close the output MS
1518 : // -----------------------------------------------------------------------
1519 70 : void MSTransformManager::close()
1520 : {
1521 70 : if (outputMs_p)
1522 : {
1523 : // unlock MS (the MS data handler will flush it when destroying it).
1524 35 : outputMs_p->unlock();
1525 35 : Table::relinquishAutoLocks(true);
1526 :
1527 : // Unset the output MS
1528 35 : outputMs_p = NULL;
1529 : }
1530 :
1531 70 : return;
1532 : }
1533 :
1534 : // -----------------------------------------------------------------------
1535 : // Check configuration and input MS characteristics to determine run parameters
1536 : // -----------------------------------------------------------------------
1537 35 : void MSTransformManager::setup()
1538 : {
1539 : // Check what columns have to filled
1540 : // CAS-5581 (jagonzal): Moving these methods here because we need to know if
1541 : // WEIGHT_SPECTRUM is available to configure the appropriate averaging kernel.
1542 : // - note also that the availability of WEIGHT_SPECTRUM in the input MS needs
1543 : // to be checked even before, as it is needed when doing
1544 : // dataHandler_p->makeMSBasicStructure() in createOutputMSStructure() - CAS-11269
1545 35 : checkFillFlagCategory();
1546 35 : checkFillWeightSpectrum();
1547 :
1548 : // Check if we really need to combine SPWs
1549 35 : if (combinespws_p)
1550 : {
1551 0 : auto nInputSpws = outputMs_p->spectralWindow().nrow();
1552 0 : if (nInputSpws < 2)
1553 : {
1554 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
1555 0 : << "There is only one selected SPW, no need to combine " << LogIO::POST;
1556 0 : combinespws_p = false;
1557 : }
1558 : }
1559 :
1560 : // Regrid SPW subtable
1561 35 : if (combinespws_p)
1562 : {
1563 0 : initRefFrameTransParams();
1564 0 : regridAndCombineSpwSubtable();
1565 0 : reindexDDISubTable();
1566 0 : reindexSourceSubTable();
1567 : //reindexFeedSubTable();
1568 : //reindexSysCalSubTable();
1569 0 : reindexFreqOffsetSubTable();
1570 0 : reindexGenericTimeDependentSubTable("FEED");
1571 0 : reindexGenericTimeDependentSubTable("SYSCAL");
1572 0 : reindexGenericTimeDependentSubTable("CALDEVICE");
1573 0 : reindexGenericTimeDependentSubTable("SYSPOWER");
1574 : }
1575 35 : else if (regridding_p) // regrid as in the regridms option
1576 : {
1577 0 : initRefFrameTransParams();
1578 0 : regridSpwSubTable();
1579 : }
1580 :
1581 : // Subtable manipulation for polarization averaging
1582 35 : if (polAverage_p) {
1583 : // Int nInputPolarizations = outputMs_p->polarization().nrow();
1584 0 : Int averagedPolId = getAveragedPolarizationId();
1585 0 : reindexPolarizationIdInDataDesc(averagedPolId);
1586 : }
1587 :
1588 : //// Determine the frequency transformation methods to use ////
1589 :
1590 :
1591 : // Cube level
1592 35 : if (combinespws_p)
1593 : {
1594 0 : transformCubeOfDataComplex_p = &MSTransformManager::combineCubeOfData;
1595 0 : transformCubeOfDataFloat_p = &MSTransformManager::combineCubeOfData;
1596 0 : spectrumTransformation_p = true;
1597 0 : propagateWeights_p = true;
1598 0 : spectrumReshape_p = true;
1599 0 : cubeTransformation_p = true;
1600 : }
1601 35 : else if (regridding_p)
1602 : {
1603 0 : transformCubeOfDataComplex_p = &MSTransformManager::regridCubeOfData;
1604 0 : transformCubeOfDataFloat_p = &MSTransformManager::regridCubeOfData;
1605 0 : spectrumTransformation_p = true;
1606 0 : propagateWeights_p = true;
1607 0 : spectrumReshape_p = true;
1608 0 : cubeTransformation_p = true;
1609 : }
1610 35 : else if (channelAverage_p)
1611 : {
1612 17 : transformCubeOfDataComplex_p = &MSTransformManager::averageCubeOfData;
1613 17 : transformCubeOfDataFloat_p = &MSTransformManager::averageCubeOfData;
1614 17 : spectrumTransformation_p = true;
1615 17 : propagateWeights_p = true;
1616 17 : spectrumReshape_p = true;
1617 17 : cubeTransformation_p = true;
1618 : }
1619 18 : else if (hanningSmooth_p || smoothFourier_p)
1620 : {
1621 0 : transformCubeOfDataComplex_p = &MSTransformManager::smoothCubeOfData;
1622 0 : transformCubeOfDataFloat_p = &MSTransformManager::smoothCubeOfData;
1623 0 : spectrumTransformation_p = true;
1624 0 : cubeTransformation_p = true;
1625 : }
1626 18 : else if (nspws_p > 1)
1627 : {
1628 0 : transformCubeOfDataComplex_p = &MSTransformManager::separateCubeOfData;
1629 0 : transformCubeOfDataFloat_p = &MSTransformManager::separateCubeOfData;
1630 0 : spectrumReshape_p = true;
1631 0 : cubeTransformation_p = true;
1632 : }
1633 : else
1634 : {
1635 18 : transformCubeOfDataComplex_p = &MSTransformManager::copyCubeOfData;
1636 18 : transformCubeOfDataFloat_p = &MSTransformManager::copyCubeOfData;
1637 : }
1638 :
1639 35 : bool spectralRegridding = combinespws_p or regridding_p;
1640 :
1641 : // Vector level
1642 35 : if (channelAverage_p and !hanningSmooth_p and !spectralRegridding)
1643 : {
1644 17 : transformStripeOfDataComplex_p = &MSTransformManager::average;
1645 17 : transformStripeOfDataFloat_p = &MSTransformManager::average;
1646 : }
1647 18 : else if (!channelAverage_p and hanningSmooth_p and !spectralRegridding)
1648 : {
1649 0 : transformStripeOfDataComplex_p = &MSTransformManager::smooth;
1650 0 : transformStripeOfDataFloat_p = &MSTransformManager::smooth;
1651 : }
1652 18 : else if (!channelAverage_p and !hanningSmooth_p and spectralRegridding)
1653 : {
1654 0 : transformStripeOfDataComplex_p = &MSTransformManager::regrid;
1655 0 : transformStripeOfDataFloat_p = &MSTransformManager::regrid;
1656 : }
1657 18 : else if (channelAverage_p and hanningSmooth_p and !spectralRegridding)
1658 : {
1659 0 : transformStripeOfDataComplex_p = &MSTransformManager::averageSmooth;
1660 0 : transformStripeOfDataFloat_p = &MSTransformManager::averageSmooth;
1661 : }
1662 18 : else if (channelAverage_p and !hanningSmooth_p and spectralRegridding)
1663 : {
1664 0 : transformStripeOfDataComplex_p = &MSTransformManager::averageRegrid;
1665 0 : transformStripeOfDataFloat_p = &MSTransformManager::averageRegrid;
1666 : }
1667 18 : else if (!channelAverage_p and hanningSmooth_p and spectralRegridding)
1668 : {
1669 0 : transformStripeOfDataComplex_p = &MSTransformManager::smoothRegrid;
1670 0 : transformStripeOfDataFloat_p = &MSTransformManager::smoothRegrid;
1671 : }
1672 18 : else if (channelAverage_p and hanningSmooth_p and spectralRegridding)
1673 : {
1674 0 : transformStripeOfDataComplex_p = &MSTransformManager::averageSmoothRegrid;
1675 0 : transformStripeOfDataFloat_p = &MSTransformManager::averageSmoothRegrid;
1676 : }
1677 18 : else if (smoothFourier_p) {
1678 0 : transformStripeOfDataComplex_p = &MSTransformManager::smoothFourierComplex;
1679 0 : transformStripeOfDataFloat_p = &MSTransformManager::smoothFourierFloat;
1680 : }
1681 :
1682 : // If there is not inputWeightSpectrumAvailable_p and no time average then
1683 : // weightSpectrum is constant and has no effect in frequency avg./regridding
1684 35 : if ((not inputWeightSpectrumAvailable_p) and (not timeAverage_p))
1685 : {
1686 16 : propagateWeights_p = false;
1687 16 : weightmode_p = MSTransformations::flagsNonZero;
1688 : }
1689 : else
1690 : {
1691 : // NOTE: It does not hurt to set the averaging kernel even if we are not going to use it
1692 19 : weightmode_p = MSTransformations::flagSpectrumNonZero;
1693 : }
1694 :
1695 : // SPECTRUM columns have to be set when they exists in the input or the user specifies it via usewtspectrum_p
1696 35 : if (inputWeightSpectrumAvailable_p or usewtspectrum_p)
1697 : {
1698 1 : flushWeightSpectrum_p = true;
1699 : }
1700 : else
1701 : {
1702 34 : flushWeightSpectrum_p = false;
1703 : }
1704 :
1705 35 : propagateWeights(propagateWeights_p);
1706 35 : setChannelAverageKernel(weightmode_p);
1707 35 : setSmoothingKernel(smoothmode_p);
1708 :
1709 :
1710 : // Set Regridding kernel
1711 35 : if (fftShiftEnabled_p)
1712 : {
1713 0 : regridCoreComplex_p = &MSTransformManager::interpol1Dfftshift;
1714 0 : regridCoreFloat_p = &MSTransformManager::interpol1Dfftshift;
1715 : }
1716 : else
1717 : {
1718 35 : regridCoreComplex_p = &MSTransformManager::interpol1D;
1719 35 : regridCoreFloat_p = &MSTransformManager::interpol1D;
1720 : }
1721 :
1722 : //// Determine the frequency transformation methods to use ////
1723 :
1724 : // Drop channels with non-uniform width when doing only channel average
1725 35 : if (channelAverage_p and !regridding_p and !combinespws_p )
1726 : {
1727 17 : dropNonUniformWidthChannels();
1728 : }
1729 :
1730 : // Get number of output channels (needed by chan avg and separate SPWs when there is only 1 selected SPW)
1731 35 : if (channelAverage_p or (nspws_p>1 and !combinespws_p))
1732 : {
1733 17 : getOutputNumberOfChannels();
1734 : }
1735 :
1736 : // Determine weight and sigma factors when either auto or user channel average is set
1737 35 : if (channelAverage_p or combinespws_p or regridding_p)
1738 : {
1739 17 : calculateNewWeightAndSigmaFactors();
1740 : }
1741 :
1742 :
1743 35 : if (nspws_p > 1)
1744 : {
1745 0 : uInt totalNumberOfOutputChannels = 0;
1746 0 : if (combinespws_p)
1747 : {
1748 0 : totalNumberOfOutputChannels = inputOutputSpwMap_p[0].second.NUM_CHAN;
1749 : }
1750 : // jagonzal: This is the case when there is only one input SPW and there is no need to combine
1751 : else
1752 : {
1753 0 : uInt spwId = 0;
1754 0 : if (outputInputSPWIndexMap_p.size()>0)
1755 : {
1756 0 : spwId = outputInputSPWIndexMap_p[0];
1757 : }
1758 : else
1759 : {
1760 0 : spwId = 0;
1761 : }
1762 :
1763 0 : totalNumberOfOutputChannels = numOfOutChanMap_p[spwId];
1764 : }
1765 :
1766 :
1767 0 : chansPerOutputSpw_p = totalNumberOfOutputChannels / nspws_p;
1768 0 : if (totalNumberOfOutputChannels % nspws_p)
1769 : {
1770 0 : chansPerOutputSpw_p += 1;
1771 0 : tailOfChansforLastSpw_p = totalNumberOfOutputChannels - chansPerOutputSpw_p*(nspws_p-1);
1772 : }
1773 : else
1774 : {
1775 0 : tailOfChansforLastSpw_p = chansPerOutputSpw_p;
1776 : }
1777 :
1778 0 : if (bufferMode_p)
1779 : {
1780 0 : writeOutputPlanesComplex_p = &MSTransformManager::bufferOutputPlanesInSlices;
1781 0 : writeOutputPlanesFloat_p = &MSTransformManager::bufferOutputPlanesInSlices;
1782 : }
1783 : else
1784 : {
1785 0 : writeOutputPlanesComplex_p = &MSTransformManager::writeOutputPlanesInSlices;
1786 0 : writeOutputPlanesFloat_p = &MSTransformManager::writeOutputPlanesInSlices;
1787 : }
1788 :
1789 0 : separateSpwSubtable();
1790 0 : separateFeedSubtable();
1791 0 : separateSourceSubtable();
1792 0 : separateSyscalSubtable();
1793 0 : separateFreqOffsetSubtable();
1794 0 : separateCalDeviceSubtable();
1795 0 : separateSysPowerSubtable();
1796 :
1797 : // CAS-5404. DDI sub-table has to be re-indexed after separating SPW sub-table
1798 0 : if (not combinespws_p) reindexDDISubTable();
1799 : }
1800 : else
1801 : {
1802 35 : if (bufferMode_p)
1803 : {
1804 0 : writeOutputPlanesComplex_p = &MSTransformManager::bufferOutputPlanes;
1805 0 : writeOutputPlanesFloat_p = &MSTransformManager::bufferOutputPlanes;
1806 : }
1807 : else
1808 : {
1809 35 : writeOutputPlanesComplex_p = &MSTransformManager::writeOutputPlanesInBlock;
1810 35 : writeOutputPlanesFloat_p = &MSTransformManager::writeOutputPlanesInBlock;
1811 : }
1812 : }
1813 :
1814 : // Generate Iterator
1815 35 : setIterationApproach();
1816 35 : generateIterator();
1817 :
1818 35 : return;
1819 : }
1820 :
1821 :
1822 : // -----------------------------------------------------------------------
1823 : //
1824 : // -----------------------------------------------------------------------
1825 5942 : IPosition MSTransformManager::getShape()
1826 : {
1827 5942 : return getTransformedShape(visibilityIterator_p->getVisBuffer());
1828 : }
1829 :
1830 : // -----------------------------------------------------------------------
1831 : //
1832 : // -----------------------------------------------------------------------
1833 5942 : IPosition MSTransformManager::getTransformedShape(vi::VisBuffer2 *visBuffer)
1834 : {
1835 5942 : IPosition outputCubeShape(3);
1836 :
1837 : // Correlations
1838 5942 : outputCubeShape(0) = visBuffer->nCorrelations();
1839 :
1840 : // Rows
1841 5942 : outputCubeShape(2) = nRowsToAdd_p;
1842 :
1843 : // Channels
1844 5942 : if (nspws_p > 1)
1845 : {
1846 0 : outputCubeShape(1) = chansPerOutputSpw_p;
1847 : }
1848 5942 : else if (combinespws_p)
1849 : {
1850 0 : outputCubeShape(1) = inputOutputSpwMap_p[0].second.NUM_CHAN;
1851 : }
1852 5942 : else if (regridding_p)
1853 : {
1854 0 : Int inputSpw = visBuffer->spectralWindows()(0);
1855 0 : outputCubeShape(1) = inputOutputSpwMap_p[inputSpw].second.NUM_CHAN;
1856 : }
1857 5942 : else if (channelAverage_p)
1858 : {
1859 3430 : Int inputSpw = visBuffer->spectralWindows()(0);
1860 3430 : outputCubeShape(1) = numOfOutChanMap_p[inputSpw];
1861 : }
1862 : else
1863 : {
1864 2512 : outputCubeShape(1) = visBuffer->nChannels();
1865 : }
1866 :
1867 5942 : return outputCubeShape;
1868 0 : }
1869 :
1870 : // -----------------------------------------------------------------------
1871 : //
1872 : // -----------------------------------------------------------------------
1873 1217 : void MSTransformManager::propagateWeights(bool on)
1874 : {
1875 :
1876 1217 : if (on)
1877 : {
1878 : // Used by SPW combination
1879 18 : fillWeightsPlane_p = &MSTransformManager::fillWeightsPlane;
1880 18 : normalizeWeightsPlane_p = &MSTransformManager::normalizeWeightsPlane;
1881 :
1882 : // Used by channel average
1883 18 : setWeightsPlaneByReference_p = &MSTransformManager::setWeightsPlaneByReference;
1884 18 : setWeightStripeByReference_p = &MSTransformManager::setWeightStripeByReference;
1885 : }
1886 : else
1887 : {
1888 : // Used by SPW combination
1889 1199 : fillWeightsPlane_p = &MSTransformManager::dontfillWeightsPlane;
1890 1199 : normalizeWeightsPlane_p = &MSTransformManager::dontNormalizeWeightsPlane;
1891 :
1892 : // Used by channel average
1893 1199 : setWeightsPlaneByReference_p = &MSTransformManager::dontsetWeightsPlaneByReference;
1894 1199 : setWeightStripeByReference_p = &MSTransformManager::dontSetWeightStripeByReference;
1895 : }
1896 :
1897 1217 : return;
1898 : }
1899 :
1900 : // -----------------------------------------------------------------------
1901 : //
1902 : // -----------------------------------------------------------------------
1903 1178 : void MSTransformManager::setBufferMode(bool on)
1904 : {
1905 1178 : bufferMode_p = on;
1906 :
1907 1178 : if (nspws_p > 1)
1908 : {
1909 0 : if (bufferMode_p)
1910 : {
1911 0 : writeOutputPlanesComplex_p = &MSTransformManager::bufferOutputPlanesInSlices;
1912 0 : writeOutputPlanesFloat_p = &MSTransformManager::bufferOutputPlanesInSlices;
1913 : }
1914 : else
1915 : {
1916 0 : writeOutputPlanesComplex_p = &MSTransformManager::writeOutputPlanesInSlices;
1917 0 : writeOutputPlanesFloat_p = &MSTransformManager::writeOutputPlanesInSlices;
1918 : }
1919 : }
1920 : else
1921 : {
1922 1178 : if (bufferMode_p)
1923 : {
1924 589 : writeOutputPlanesComplex_p = &MSTransformManager::bufferOutputPlanes;
1925 589 : writeOutputPlanesFloat_p = &MSTransformManager::bufferOutputPlanes;
1926 : }
1927 : else
1928 : {
1929 589 : writeOutputPlanesComplex_p = &MSTransformManager::writeOutputPlanesInBlock;
1930 589 : writeOutputPlanesFloat_p = &MSTransformManager::writeOutputPlanesInBlock;
1931 : }
1932 : }
1933 :
1934 1178 : return;
1935 : }
1936 :
1937 : // -----------------------------------------------------------------------
1938 : //
1939 : // -----------------------------------------------------------------------
1940 1217 : void MSTransformManager::setChannelAverageKernel(uInt mode)
1941 : {
1942 1217 : switch (mode)
1943 : {
1944 0 : case MSTransformations::spectrum:
1945 : {
1946 0 : averageKernelComplex_p = &MSTransformManager::weightAverageKernel;
1947 0 : averageKernelFloat_p = &MSTransformManager::weightAverageKernel;
1948 0 : break;
1949 : }
1950 0 : case MSTransformations::flags:
1951 : {
1952 0 : averageKernelComplex_p = &MSTransformManager::flagAverageKernel;
1953 0 : averageKernelFloat_p = &MSTransformManager::flagAverageKernel;
1954 0 : break;
1955 : }
1956 0 : case MSTransformations::cumSum:
1957 : {
1958 0 : averageKernelComplex_p = &MSTransformManager::cumSumKernel;
1959 0 : averageKernelFloat_p = &MSTransformManager::cumSumKernel;
1960 0 : break;
1961 : }
1962 0 : case MSTransformations::flagSpectrum:
1963 : {
1964 0 : averageKernelComplex_p = &MSTransformManager::flagWeightAverageKernel;
1965 0 : averageKernelFloat_p = &MSTransformManager::flagWeightAverageKernel;
1966 0 : break;
1967 : }
1968 0 : case MSTransformations::flagCumSum:
1969 : {
1970 0 : averageKernelComplex_p = &MSTransformManager::flagCumSumKernel;
1971 0 : averageKernelFloat_p = &MSTransformManager::flagCumSumKernel;
1972 0 : break;
1973 : }
1974 595 : case MSTransformations::flagsNonZero:
1975 : {
1976 595 : averageKernelComplex_p = &MSTransformManager::flagNonZeroAverageKernel;
1977 595 : averageKernelFloat_p = &MSTransformManager::flagNonZeroAverageKernel;
1978 595 : break;
1979 : }
1980 31 : case MSTransformations::flagSpectrumNonZero:
1981 : {
1982 31 : averageKernelComplex_p = &MSTransformManager::flagWeightNonZeroAverageKernel;
1983 31 : averageKernelFloat_p = &MSTransformManager::flagWeightNonZeroAverageKernel;
1984 31 : break;
1985 : }
1986 591 : case MSTransformations::flagCumSumNonZero:
1987 : {
1988 591 : averageKernelComplex_p = &MSTransformManager::flagCumSumNonZeroKernel;
1989 591 : averageKernelFloat_p = &MSTransformManager::flagCumSumNonZeroKernel;
1990 591 : break;
1991 : }
1992 0 : default:
1993 : {
1994 0 : averageKernelComplex_p = &MSTransformManager::simpleAverageKernel;
1995 0 : averageKernelFloat_p = &MSTransformManager::simpleAverageKernel;
1996 0 : break;
1997 : }
1998 : }
1999 :
2000 1217 : return;
2001 : }
2002 :
2003 : // -----------------------------------------------------------------------
2004 : //
2005 : // -----------------------------------------------------------------------
2006 1217 : void MSTransformManager::setSmoothingKernel(uInt mode)
2007 : {
2008 1217 : switch (mode)
2009 : {
2010 626 : case MSTransformations::plainSmooth:
2011 : {
2012 626 : smoothKernelComplex_p = &MSTransformManager::plainSmooth;
2013 626 : smoothKernelFloat_p = &MSTransformManager::plainSmooth;
2014 626 : break;
2015 : }
2016 591 : case MSTransformations::plainSmoothSpectrum:
2017 : {
2018 591 : smoothKernelComplex_p = &MSTransformManager::plainSmoothSpectrum;
2019 591 : smoothKernelFloat_p = &MSTransformManager::plainSmoothSpectrum;
2020 591 : break;
2021 : }
2022 0 : default:
2023 : {
2024 0 : smoothKernelComplex_p = &MSTransformManager::plainSmooth;
2025 0 : smoothKernelFloat_p = &MSTransformManager::plainSmooth;
2026 0 : break;
2027 : }
2028 : }
2029 :
2030 1217 : return;
2031 : }
2032 :
2033 : // -----------------------------------------------------------------------
2034 : //
2035 : // -----------------------------------------------------------------------
2036 1182 : void MSTransformManager::setSmoothingFourierKernel(uInt mode)
2037 : {
2038 1182 : if (smoothFourier_p) {
2039 0 : switch (mode)
2040 : {
2041 0 : case MSTransformations::plainSmooth:
2042 : {
2043 : //logger_p << "Set smoothing kernel to smoothFourier" << LogIO::POST;
2044 0 : transformStripeOfDataComplex_p = &MSTransformManager::smoothFourierComplex;
2045 0 : transformStripeOfDataFloat_p = &MSTransformManager::smoothFourierFloat;
2046 0 : break;
2047 : }
2048 0 : case MSTransformations::plainSmoothSpectrum:
2049 : {
2050 : //logger_p << "Set smoothing kernel to smooth (for weight propagation)" << LogIO::POST;
2051 0 : transformStripeOfDataComplex_p = &MSTransformManager::smooth;
2052 0 : transformStripeOfDataFloat_p = &MSTransformManager::smooth;
2053 0 : break;
2054 : }
2055 0 : default:
2056 : {
2057 0 : transformStripeOfDataComplex_p = &MSTransformManager::smoothFourierComplex;
2058 0 : transformStripeOfDataFloat_p = &MSTransformManager::smoothFourierFloat;
2059 0 : break;
2060 : }
2061 : }
2062 : }
2063 :
2064 1182 : return;
2065 : }
2066 :
2067 : // -----------------------------------------------------------------------
2068 : //
2069 : // -----------------------------------------------------------------------
2070 35 : void MSTransformManager::initDataSelectionParams()
2071 : {
2072 35 : MSSelection mssel;
2073 :
2074 35 : if (reindex_p)
2075 : {
2076 35 : if (!observationSelection_p.empty())
2077 : {
2078 0 : mssel.setObservationExpr(observationSelection_p);
2079 0 : Vector<Int> observationList = mssel.getObservationList(inputMs_p);
2080 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2081 0 : << "Selected Observations Ids are " << observationList << LogIO::POST;
2082 :
2083 0 : for (uInt index=0; index < observationList.size(); index++)
2084 : {
2085 0 : inputOutputObservationIndexMap_p[observationList(index)] = index;
2086 : }
2087 0 : }
2088 :
2089 35 : if (!arraySelection_p.empty())
2090 : {
2091 0 : mssel.setArrayExpr(arraySelection_p);
2092 0 : Vector<Int> arrayList = mssel.getSubArrayList(inputMs_p);
2093 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2094 0 : << "Selected Arrays Ids are " << arrayList << LogIO::POST;
2095 :
2096 0 : for (uInt index=0; index < arrayList.size(); index++)
2097 : {
2098 0 : inputOutputArrayIndexMap_p[arrayList(index)] = index;
2099 : }
2100 0 : }
2101 :
2102 35 : if (!scanSelection_p.empty())
2103 : {
2104 1 : mssel.setScanExpr(scanSelection_p);
2105 1 : Vector<Int> scanList = mssel.getScanList(inputMs_p);
2106 2 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2107 2 : << "Selected Scans Ids are " << scanList << LogIO::POST;
2108 :
2109 2 : for (uInt index=0; index < scanList.size(); index++)
2110 : {
2111 1 : inputOutputScanIndexMap_p[scanList(index)] = index;
2112 : }
2113 1 : }
2114 :
2115 35 : if (!scanIntentSelection_p.empty())
2116 : {
2117 0 : mssel.setStateExpr(scanIntentSelection_p);
2118 0 : Vector<Int> scanIntentList = mssel.getStateObsModeList(inputMs_p);
2119 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2120 0 : << "Selected Scans Intents Ids are " << scanIntentList << LogIO::POST;
2121 :
2122 0 : for (uInt index=0; index < scanIntentList.size(); index++)
2123 : {
2124 0 : inputOutputScanIntentIndexMap_p[scanIntentList(index)] = index;
2125 : }
2126 0 : }
2127 :
2128 35 : if (!fieldSelection_p.empty())
2129 : {
2130 0 : mssel.setFieldExpr(fieldSelection_p);
2131 0 : Vector<Int> fieldList = mssel.getFieldList(inputMs_p);
2132 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2133 0 : << "Selected Fields Ids are " << fieldList << LogIO::POST;
2134 :
2135 0 : for (uInt index=0; index < fieldList.size(); index++)
2136 : {
2137 0 : inputOutputFieldIndexMap_p[fieldList(index)] = index;
2138 : }
2139 0 : }
2140 : }
2141 :
2142 :
2143 35 : if (!spwSelection_p.empty())
2144 : {
2145 3 : mssel.setSpwExpr(spwSelection_p);
2146 3 : Matrix<Int> spwchan = mssel.getChanList(inputMs_p);
2147 :
2148 : // Get the DD IDs of this spw selection
2149 3 : Vector<Int> spwddi = mssel.getSPWDDIDList(inputMs_p);
2150 :
2151 : // Take into account the polarization selections
2152 3 : if (!polarizationSelection_p.empty()){
2153 0 : mssel.setPolnExpr(polarizationSelection_p.c_str());
2154 0 : Vector<Int> polddi = mssel.getDDIDList(inputMs_p);
2155 0 : if (polddi.size() > 0){
2156 : // make an intersection
2157 0 : Vector<Int> commonDDI = set_intersection(spwddi, polddi);
2158 0 : uInt nddids = commonDDI.size();
2159 0 : if (nddids > 0){
2160 0 : spwddi.resize(nddids);
2161 0 : for (uInt ii = 0; ii < nddids; ++ii){
2162 0 : spwddi[ii] = commonDDI[ii];
2163 : }
2164 : }
2165 0 : }
2166 0 : }
2167 :
2168 3 : uInt nddi = spwddi.size();
2169 : Int ddid;
2170 6 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2171 6 : << "Selected SPWs Ids are " << spwchan << LogIO::POST;
2172 : // Example of MS with repeated SPW ID in DD table:
2173 : // DD POL SPW
2174 : // 0 0 0 (RR)
2175 : // 1 1 0 (LL)
2176 : // 2 2 1 (RR,LL)
2177 : // 3 3 2 (RR,LL,RL,LR)
2178 : // example of selection: spw=0,1 correlation=RR, so selected DDs are
2179 : // DD POL SPW
2180 : // 0 0 0
2181 : // 2 2 1
2182 :
2183 : // Do the mapping of DD between input and output
2184 3 : if (reindex_p)
2185 : {
2186 10 : for(uInt selection_ii=0;selection_ii<nddi;selection_ii++)
2187 : {
2188 : // Get dd id and set the input-output dd map
2189 : // This will only be used to write the DD ids in the main table
2190 7 : ddid = spwddi[selection_ii];
2191 7 : inputOutputDDIndexMap_p[ddid] = selection_ii + ddiStart_p;
2192 : }
2193 : }
2194 :
2195 3 : IPosition shape = spwchan.shape();
2196 3 : uInt nSelections = shape[0];
2197 : Int spw,channelStart,channelStop,channelStep,channelWidth;
2198 3 : if (channelSelector_p == NULL) channelSelector_p = new vi::FrequencySelectionUsingChannels();
2199 :
2200 : // Do the spw mapping between input and output
2201 3 : uInt outputSpwIndex = 0;
2202 10 : for(uInt selection_i=0;selection_i<nSelections;selection_i++)
2203 : {
2204 : // Get spw id and set the input-output spw map
2205 7 : spw = spwchan(selection_i,0);
2206 :
2207 : // Set the channel selection ()
2208 7 : channelStart = spwchan(selection_i,1);
2209 7 : channelStop = spwchan(selection_i,2);
2210 7 : channelStep = spwchan(selection_i,3);
2211 : // number of channels to select, starting with first selected channel:
2212 7 : channelWidth = 1 + floor(float(channelStop - channelStart) / float(channelStep));
2213 7 : channelSelector_p->add (spw, channelStart, channelWidth, channelStep);
2214 :
2215 7 : if (numOfSelChanMap_p.find(spw) == numOfSelChanMap_p.end())
2216 : {
2217 7 : if (reindex_p)
2218 : {
2219 7 : inputOutputSPWIndexMap_p[spw] = outputSpwIndex + ddiStart_p;
2220 :
2221 7 : outputInputSPWIndexMap_p[outputSpwIndex] = spw;
2222 : }
2223 :
2224 7 : numOfSelChanMap_p[spw] = channelWidth;
2225 :
2226 7 : outputSpwIndex ++;
2227 :
2228 7 : inputOutputChanIndexMap_p[spw].clear(); // Accesing the vector creates it
2229 : }
2230 : else
2231 : {
2232 0 : numOfSelChanMap_p[spw] += channelWidth;
2233 : }
2234 :
2235 455 : for (Int inpChan=channelStart;inpChan<=channelStop;inpChan += channelStep)
2236 : {
2237 448 : inputOutputChanIndexMap_p[spw].push_back(inpChan);
2238 : }
2239 : }
2240 3 : }
2241 :
2242 : // jagonzal: must fill numOfSelChanMap_p
2243 : else
2244 : {
2245 32 : spwSelection_p = "*";
2246 32 : mssel.setSpwExpr(spwSelection_p);
2247 32 : Matrix<Int> spwchan = mssel.getChanList(inputMs_p);
2248 :
2249 32 : IPosition shape = spwchan.shape();
2250 32 : uInt nSelections = shape[0];
2251 : Int spw,channelStart,channelStop,channelWidth;
2252 65 : for(uInt selection_i=0;selection_i<nSelections;selection_i++)
2253 : {
2254 : // Get spw id and set the input-output spw map
2255 33 : spw = spwchan(selection_i,0);
2256 :
2257 : // Set the channel selection ()
2258 33 : channelStart = spwchan(selection_i,1);
2259 33 : channelStop = spwchan(selection_i,2);
2260 33 : channelWidth = channelStop-channelStart+1;
2261 33 : numOfSelChanMap_p[spw] = channelWidth;
2262 : }
2263 :
2264 : // CAS-8631: Even w/o spw selection MSTransformDataHandler sets spws selection to *
2265 : // in order to obtain the SPW-DDI list. It turns out that sometimes the
2266 : // output DDI sub-table is resorted, for instance in case of non-monotonic
2267 : // DDI-SPW relation, therefore it is necessary to map input-output DDIS
2268 32 : if (reindex_p)
2269 : {
2270 32 : Vector<Int> spwddi = mssel.getSPWDDIDList(inputMs_p);
2271 :
2272 : Int ddid;
2273 32 : uInt nddi = spwddi.size();
2274 65 : for(uInt selection_ii=0;selection_ii<nddi;selection_ii++)
2275 : {
2276 : // Get dd id and set the input-output dd map
2277 : // This will only be used to write the DD ids in the main table
2278 33 : ddid = spwddi[selection_ii];
2279 33 : inputOutputDDIndexMap_p[ddid] = selection_ii + ddiStart_p;
2280 : }
2281 32 : }
2282 :
2283 32 : spwSelection_p = "";
2284 32 : }
2285 :
2286 : // If we have channel average we have to populate the freqbin map
2287 35 : if (channelAverage_p)
2288 : {
2289 17 : if (!spwSelection_p.empty())
2290 : {
2291 1 : mssel.setSpwExpr(spwSelection_p);
2292 : }
2293 : else
2294 : {
2295 16 : mssel.setSpwExpr("*");
2296 : }
2297 :
2298 : //Vector<Int> spwList = mssel.getSpwList(inputMs_p);
2299 17 : Matrix<Int> spwchan = mssel.getChanList(inputMs_p);
2300 :
2301 : // jagonzal (CAS-7149): Have to remove duplicates: With multiple pols per SPW
2302 : // each SPWId appears various (see times test_chanavg_spw_with_diff_pol_shape)
2303 17 : vector<Int> noDupSpwList;
2304 36 : for (size_t idx=0;idx < spwchan.nrow(); idx++)
2305 : {
2306 19 : if (find(noDupSpwList.begin(),noDupSpwList.end(),spwchan(idx,0)) == noDupSpwList.end())
2307 : {
2308 19 : noDupSpwList.push_back(spwchan(idx,0));
2309 : }
2310 : }
2311 :
2312 : //spwList.resize(noDupSpwList.size());
2313 : //for (uInt idx=0;idx < noDupSpwList.size(); idx++) spwList(idx) = noDupSpwList[idx];
2314 17 : Vector<Int> spwList(noDupSpwList);
2315 :
2316 17 : if (freqbin_p.size() == 1)
2317 : {
2318 17 : if(combinespws_p)
2319 : {
2320 0 : uInt spwAfterComb = 0;
2321 0 : freqbinMap_p[spwAfterComb] = freqbin_p(spwAfterComb);
2322 : }
2323 : else
2324 : {
2325 : // jagonzal (CAS-8018): Update chanbin, otherwise there is a problem with dropped channels
2326 17 : Int freqbin = freqbin_p(0);
2327 17 : freqbin_p.resize(spwList.size(),True);
2328 17 : freqbin_p = freqbin;
2329 :
2330 36 : for (size_t spw_i=0;spw_i<spwList.size();spw_i++)
2331 : {
2332 19 : freqbinMap_p[spwList(spw_i)] = freqbin_p(spw_i);
2333 :
2334 : // jagonzal (new WEIGHT/SIGMA convention)
2335 : // jagonzal (CAS-7149): Cut chanbin to not exceed n# selected channels
2336 19 : if (freqbin_p(spw_i) > (Int)numOfSelChanMap_p[spwList(spw_i)])
2337 : {
2338 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
2339 0 : << "Number of selected channels " << numOfSelChanMap_p[spwList(spw_i)]
2340 0 : << " for SPW " << spwList(spw_i)
2341 0 : << " is smaller than specified chanbin " << freqbin_p(spw_i) << endl
2342 0 : << "Setting chanbin to " << numOfSelChanMap_p[spwList(spw_i)]
2343 0 : << " for SPW " << spwList(spw_i)
2344 0 : << LogIO::POST;
2345 0 : freqbinMap_p[spwList(spw_i)] = numOfSelChanMap_p[spwList(spw_i)];
2346 0 : newWeightFactorMap_p[spwList(spw_i)] = numOfSelChanMap_p[spwList(spw_i)];
2347 : // jagonzal (CAS-8018): Update chanbin, otherwise there is a problem with dropped channels
2348 0 : freqbin_p(spw_i) = numOfSelChanMap_p[spwList(spw_i)];
2349 : }
2350 : else
2351 : {
2352 19 : newWeightFactorMap_p[spwList(spw_i)] = freqbin_p(spw_i);
2353 : }
2354 : }
2355 : }
2356 : }
2357 : else
2358 : {
2359 0 : if (spwList.size() != freqbin_p.size())
2360 : {
2361 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
2362 : << "Number of frequency bins ( "
2363 : << freqbin_p.size() << " ) different from number of selected spws ( "
2364 0 : << spwList.size() << " )" << LogIO::POST;
2365 : }
2366 : else
2367 : {
2368 0 : for (size_t spw_i=0;spw_i<spwList.size();spw_i++)
2369 : {
2370 0 : freqbinMap_p[spwList(spw_i)] = freqbin_p(spw_i);
2371 : // jagonzal (new WEIGHT/SIGMA convention)
2372 : // jagonzal (CAS-7149): Cut chanbin to not exceed n# selected channels
2373 0 : if (freqbin_p(spw_i) > (Int)numOfSelChanMap_p[spwList(spw_i)])
2374 : {
2375 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
2376 0 : << "Number of selected channels " << numOfSelChanMap_p[spwList(spw_i)]
2377 0 : << " for SPW " << spwList(spw_i)
2378 0 : << " is smaller than specified chanbin " << freqbin_p(spw_i) << endl
2379 0 : << "Setting chanbin to " << numOfSelChanMap_p[spwList(spw_i)]
2380 0 : << " for SPW " << spwList(spw_i)
2381 0 : << LogIO::POST;
2382 0 : freqbinMap_p[spwList(spw_i)] = numOfSelChanMap_p[spwList(spw_i)];
2383 0 : newWeightFactorMap_p[spwList(spw_i)] = numOfSelChanMap_p[spwList(spw_i)];
2384 : // jagonzal (CAS-8018): Update chanbin, otherwise there is a problem with dropped channels
2385 0 : freqbin_p(spw_i) = numOfSelChanMap_p[spwList(spw_i)];
2386 : }
2387 : else
2388 : {
2389 0 : newWeightFactorMap_p[spwList(spw_i)] = freqbin_p(spw_i);
2390 : }
2391 : }
2392 : }
2393 : }
2394 17 : }
2395 :
2396 35 : if (!polarizationSelection_p.empty())
2397 : {
2398 0 : mssel.setPolnExpr(polarizationSelection_p.c_str());
2399 0 : Vector <Vector <Slice> > correlationSlices;
2400 0 : mssel.getCorrSlices(correlationSlices,inputMs_p);
2401 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2402 0 : << "Selected correlations are " << correlationSlices << LogIO::POST;
2403 :
2404 0 : if (channelSelector_p == NULL) channelSelector_p = new vi::FrequencySelectionUsingChannels();
2405 :
2406 0 : channelSelector_p->addCorrelationSlices(correlationSlices);
2407 :
2408 : // Get the DDs related to the polarization selection
2409 : // when there is no spw selection
2410 0 : if (spwSelection_p.empty() and reindex_p)
2411 : {
2412 0 : std::vector<Int> polddids = mssel.getDDIDList(inputMs_p).tovector();
2413 : // The output from MSSelection might not be sorted
2414 0 : std::sort(polddids.begin(), polddids.end());
2415 :
2416 : // Make the in/out DD mapping
2417 0 : size_t nddids = polddids.size();
2418 : Int dd;
2419 0 : for(size_t ii=0;ii<nddids;ii++)
2420 : {
2421 : // Get dd id and set the input-output dd map
2422 0 : dd = polddids[ii];
2423 0 : inputOutputDDIndexMap_p[dd] = ii + ddiStart_p;
2424 : }
2425 :
2426 0 : }
2427 :
2428 0 : }
2429 :
2430 70 : return;
2431 35 : }
2432 :
2433 : // -----------------------------------------------------------------------
2434 : // Method to initialize the reference frame transformation parameters
2435 : // -----------------------------------------------------------------------
2436 0 : void MSTransformManager::initRefFrameTransParams()
2437 : {
2438 0 : inputReferenceFrame_p = determineInputRefFrame();
2439 :
2440 : // Parse output reference frame
2441 0 : refFrameTransformation_p = true;
2442 0 : radialVelocityCorrection_p = false;
2443 0 : if(outputReferenceFramePar_p.empty()) {
2444 0 : outputReferenceFrame_p = inputReferenceFrame_p;
2445 : }
2446 : // CAS-6778: Support for new ref. frame SOURCE that requires radial velocity correction
2447 0 : else if (outputReferenceFramePar_p == "SOURCE") {
2448 0 : outputReferenceFrame_p = MFrequency::GEO;
2449 0 : radialVelocityCorrection_p = true;
2450 0 : } else if(!MFrequency::getType(outputReferenceFrame_p, outputReferenceFramePar_p)) {
2451 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
2452 0 : << "Problem parsing output reference frame:" << outputReferenceFramePar_p
2453 0 : << LogIO::EXCEPTION;
2454 : }
2455 :
2456 0 : if (outputReferenceFrame_p == inputReferenceFrame_p) {
2457 0 : refFrameTransformation_p = false;
2458 : }
2459 :
2460 : // Determine observatory position from the first row in the observation sub-table of the output (selected) MS
2461 0 : MSObservation observationTable;
2462 0 : if (userBufferMode_p) {
2463 0 : observationTable = selectedInputMs_p->observation();
2464 : } else {
2465 0 : observationTable = outputMs_p->observation();
2466 : }
2467 0 : MSObservationColumns observationCols(observationTable);
2468 0 : String observatoryName = observationCols.telescopeName()(0);
2469 0 : MeasTable::Observatory(observatoryPosition_p,observatoryName);
2470 :
2471 : // jagonzal: This conversion is needed only for cosmetic reasons
2472 : // observatoryPosition_p=MPosition::Convert(observatoryPosition_p, MPosition::ITRF)();
2473 :
2474 : // Determine observation time from the first row in the selected MS
2475 0 : referenceTime_p = selectedInputMsCols_p->timeMeas()(0);
2476 :
2477 : // Access FIELD cols to get phase center and radial velocity
2478 0 : inputMSFieldCols_p = std::make_shared<MSFieldColumns>(selectedInputMs_p->field());
2479 :
2480 0 : phaseCenter_p = determinePhaseCenter();
2481 0 : }
2482 :
2483 : /**
2484 : * Determine input reference frame from the first row in the SPW 8
2485 : * sub-table of the output/selected MS.
2486 : * Helper for the initialization of the reference frame transformations
2487 : *
2488 : * @return Reference frame of output/selected MS.
2489 : */
2490 0 : casacore::MFrequency::Types MSTransformManager::determineInputRefFrame() {
2491 0 : MSSpectralWindow spwTable;
2492 0 : if (userBufferMode_p) {
2493 0 : spwTable = selectedInputMs_p->spectralWindow();
2494 : } else {
2495 0 : spwTable = outputMs_p->spectralWindow();
2496 : }
2497 0 : MSSpWindowColumns spwCols(spwTable);
2498 :
2499 : casacore::MFrequency::Types result;
2500 0 : if (reindex_p) {
2501 0 : result = MFrequency::castType(spwCols.measFreqRef()(0));
2502 : } else {
2503 0 : Int firstSelectedDDI = selectedInputMsCols_p->dataDescId()(0);
2504 0 : MSDataDescription ddiTable = outputMs_p->dataDescription();
2505 0 : MSDataDescColumns ddiCols(ddiTable);
2506 0 : Int firstSelectedSPW = ddiCols.spectralWindowId()(firstSelectedDDI);
2507 0 : result = MFrequency::castType(spwCols.measFreqRef()(firstSelectedSPW));
2508 0 : }
2509 :
2510 0 : return result;
2511 0 : }
2512 :
2513 : /**
2514 : * Determine phase center from output/selected MS.
2515 : * Helper for the initialization of the reference frame transformations
2516 : *
2517 : * @return phase center from output/selected MS.
2518 : */
2519 0 : casacore::MDirection MSTransformManager::determinePhaseCenter() {
2520 0 : casacore::MDirection result;
2521 :
2522 : // Determine phase center
2523 0 : if (phaseCenterPar_p->type() == casac::variant::INT) {
2524 0 : Int fieldIdForPhaseCenter = phaseCenterPar_p->toInt();
2525 :
2526 0 : if (fieldIdForPhaseCenter >= (Int)inputMSFieldCols_p->nrow() ||
2527 : fieldIdForPhaseCenter < 0) {
2528 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
2529 : << "Selected FIELD_ID to determine phase center does not exist "
2530 0 : << LogIO::POST;
2531 : } else {
2532 : // CAS-6778: Support for new ref. frame SOURCE that requires radial velocity correction
2533 0 : if (radialVelocityCorrection_p) {
2534 0 : radialVelocity_p = inputMSFieldCols_p->radVelMeas(fieldIdForPhaseCenter,
2535 0 : referenceTime_p.get("s").getValue());
2536 0 : result = inputMSFieldCols_p->phaseDirMeas(fieldIdForPhaseCenter,
2537 0 : referenceTime_p.get("s").getValue());
2538 : } else {
2539 0 : result = inputMSFieldCols_p->phaseDirMeasCol()(fieldIdForPhaseCenter)(IPosition(1,0));
2540 : }
2541 : }
2542 : } else {
2543 0 : String phaseCenter = phaseCenterPar_p->toString(true);
2544 :
2545 : // Determine phase center from the first row in the FIELD sub-table of the output
2546 : // (selected) MS
2547 0 : if (phaseCenter.empty()) {
2548 0 : std::shared_ptr<MSFieldColumns> fieldCols;
2549 0 : if (userBufferMode_p) {
2550 0 : fieldCols = inputMSFieldCols_p;
2551 : } else {
2552 0 : MSField fieldTable = outputMs_p->field();
2553 0 : fieldCols = std::make_shared<MSFieldColumns>(fieldTable);
2554 0 : }
2555 :
2556 : // CAS-8870: Mstransform with outframe=’SOURCE’ crashes because of ephemeris type
2557 0 : Int firstSelectedField = selectedInputMsCols_p->fieldId()(0);
2558 0 : if (inputOutputFieldIndexMap_p.find(firstSelectedField) !=
2559 0 : inputOutputFieldIndexMap_p.end()) {
2560 0 : firstSelectedField = inputOutputFieldIndexMap_p[firstSelectedField];
2561 : }
2562 :
2563 : // CAS-6778: Support for new ref. frame SOURCE that requires radial velocity correction
2564 0 : if (radialVelocityCorrection_p) {
2565 0 : radialVelocity_p = fieldCols->radVelMeas(firstSelectedField, referenceTime_p.get("s").getValue());
2566 :
2567 0 : if (radialVelocity_p.getRef().getType() != MRadialVelocity::GEO) {
2568 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
2569 : << "Cannot perform radial velocity correction with ephemerides attached "
2570 : << "to first selected field " << firstSelectedField << " of type "
2571 0 : << MRadialVelocity::showType(radialVelocity_p.getRef().getType())
2572 : << ".\nType needs to be GEO."
2573 0 : << LogIO::EXCEPTION;
2574 : }
2575 :
2576 0 : result = fieldCols->phaseDirMeas(firstSelectedField,referenceTime_p.get("s").getValue());
2577 : } else {
2578 0 : result = fieldCols->phaseDirMeasCol()(firstSelectedField)(IPosition(1,0));
2579 : }
2580 0 : } else {
2581 : // Parse phase center
2582 0 : if(!casaMDirection(phaseCenter, result)) {
2583 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
2584 0 : << "Cannot interpret phase center " << phaseCenter << LogIO::POST;
2585 : }
2586 : }
2587 0 : }
2588 :
2589 0 : return result;
2590 0 : }
2591 :
2592 : // -----------------------------------------------------------------------
2593 : // Method to re-grid each SPW separately in the SPW sub-table
2594 : // It also sets the input/output frequency arrays to be used by the interpolations
2595 : // -----------------------------------------------------------------------
2596 0 : void MSTransformManager::regridSpwSubTable()
2597 : {
2598 : // Access Spectral Window sub-table
2599 0 : MSSpectralWindow spwTable = outputMs_p->spectralWindow();
2600 0 : auto nInputSpws = spwTable.nrow();
2601 0 : MSSpWindowColumns spwCols(spwTable);
2602 :
2603 : // Access columns which have to be modified
2604 0 : ArrayColumn<Double> chanFreqCol = spwCols.chanFreq();
2605 0 : ArrayColumn<Double> chanWidthCol = spwCols.chanWidth();
2606 0 : ArrayColumn<Double> effectiveBWCol = spwCols.effectiveBW();
2607 0 : ArrayColumn<Double> resolutionCol = spwCols.resolution();
2608 0 : ScalarColumn<Int> numChanCol = spwCols.numChan();
2609 0 : ScalarColumn<Double> refFrequencyCol = spwCols.refFrequency();
2610 0 : ScalarColumn<Double> totalBandwidthCol = spwCols.totalBandwidth();
2611 0 : ScalarColumn<Int> measFreqRefCol = spwCols.measFreqRef();
2612 :
2613 : Int spwId;
2614 0 : for(rownr_t spw_idx=0; spw_idx<nInputSpws; ++spw_idx) {
2615 0 : if (outputInputSPWIndexMap_p.size() > 0) {
2616 0 : spwId = outputInputSPWIndexMap_p[spw_idx];
2617 : } else {
2618 0 : spwId = spw_idx;
2619 : }
2620 :
2621 : // jagonzal: Skip this SPW in non-reindex mode
2622 0 : if ((!reindex_p) and (numOfSelChanMap_p.find(spwId) == numOfSelChanMap_p.end()))
2623 0 : continue;
2624 :
2625 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2626 0 : << "Regridding SPW with Id " << spwId << LogIO::POST;
2627 :
2628 : // Get input frequencies and widths
2629 0 : Vector<Double> originalChanFreq(chanFreqCol(spw_idx));
2630 0 : Vector<Double> originalChanWidth(chanWidthCol(spw_idx));
2631 :
2632 : // Calculate output SPW
2633 0 : Vector<Double> regriddedCHAN_FREQ;
2634 0 : Vector<Double> regriddedCHAN_WIDTH;
2635 0 : Vector<Double> inputCHAN_FREQ;
2636 0 : Vector<Double> inputCHAN_WIDTH;
2637 0 : regridSpwAux(spwId, MFrequency::castType(spwCols.measFreqRef()(spw_idx)),
2638 : originalChanFreq, originalChanWidth,
2639 : inputCHAN_FREQ, inputCHAN_WIDTH,
2640 0 : regriddedCHAN_FREQ, regriddedCHAN_WIDTH, string("Input"));
2641 0 : spwInfo inputSpw(inputCHAN_FREQ, inputCHAN_WIDTH);
2642 0 : spwInfo outputSpw(regriddedCHAN_FREQ, regriddedCHAN_WIDTH);
2643 :
2644 : // Set the output SPW characteristics in the SPW sub-table
2645 0 : numChanCol.put(spw_idx, outputSpw.NUM_CHAN);
2646 0 : chanFreqCol.put(spw_idx, outputSpw.CHAN_FREQ);
2647 0 : chanWidthCol.put(spw_idx, outputSpw.CHAN_WIDTH);
2648 0 : effectiveBWCol.put(spw_idx, outputSpw.EFFECTIVE_BW);
2649 0 : resolutionCol.put(spw_idx, outputSpw.RESOLUTION);
2650 0 : refFrequencyCol.put(spw_idx, outputSpw.REF_FREQUENCY);
2651 0 : totalBandwidthCol.put(spw_idx, outputSpw.TOTAL_BANDWIDTH);
2652 :
2653 : // CAS-6778: Support for new ref. frame SOURCE that requires radial velocity correction
2654 0 : if(outputReferenceFrame_p==MFrequency::GEO) {
2655 : // i.e. outframe was GEO or SOURCE
2656 0 : measFreqRefCol.put(spw_idx, (Int)MFrequency::REST);
2657 : } else {
2658 0 : measFreqRefCol.put(spw_idx, (Int)outputReferenceFrame_p);
2659 : }
2660 :
2661 : // Add input-output SPW pair to map
2662 0 : inputOutputSpwMap_p[spwId] = std::make_pair(inputSpw,outputSpw);
2663 :
2664 : // Prepare frequency transformation engine for the reference time
2665 0 : if (fftShiftEnabled_p) {
2666 0 : MFrequency::Ref inputFrameRef(inputReferenceFrame_p,
2667 0 : MeasFrame(phaseCenter_p, observatoryPosition_p, referenceTime_p));
2668 0 : MFrequency::Ref outputFrameRef(outputReferenceFrame_p,
2669 0 : MeasFrame(phaseCenter_p, observatoryPosition_p, referenceTime_p));
2670 0 : refTimeFreqTransEngine_p = MFrequency::Convert(MSTransformations::Hz, inputFrameRef, outputFrameRef);
2671 :
2672 0 : for(uInt chan_idx=0; chan_idx < inputOutputSpwMap_p[spwId].first.CHAN_FREQ.size();
2673 : ++chan_idx) {
2674 0 : inputOutputSpwMap_p[spwId].first.CHAN_FREQ_aux[chan_idx] =
2675 0 : refTimeFreqTransEngine_p(inputOutputSpwMap_p[spwId].first.CHAN_FREQ[chan_idx]).
2676 0 : get(MSTransformations::Hz).getValue();
2677 : }
2678 0 : }
2679 0 : }
2680 0 : }
2681 :
2682 : // -----------------------------------------------------------------------
2683 : // Method to combine and re-grid the SPW sub-table
2684 : // It also sets the input/output frequency arrays to be used by the interpolations
2685 : // -----------------------------------------------------------------------
2686 0 : void MSTransformManager::regridAndCombineSpwSubtable()
2687 : {
2688 : /// Determine input SPW structure ////////////////////
2689 :
2690 : // Access Spectral Window sub-table
2691 0 : MSSpectralWindow spwTable = outputMs_p->spectralWindow();
2692 0 : auto nInputSpws = spwTable.nrow();
2693 0 : MSSpWindowColumns spwCols(spwTable);
2694 :
2695 : // Access columns which have to be modified
2696 0 : ArrayColumn<Double> chanFreqCol = spwCols.chanFreq();
2697 0 : ArrayColumn<Double> chanWidthCol = spwCols.chanWidth();
2698 0 : ArrayColumn<Double> effectiveBWCol = spwCols.effectiveBW();
2699 0 : ArrayColumn<Double> resolutionCol = spwCols.resolution();
2700 0 : ScalarColumn<Int> numChanCol = spwCols.numChan();
2701 0 : ScalarColumn<Double> refFrequencyCol = spwCols.refFrequency();
2702 0 : ScalarColumn<Double> totalBandwidthCol = spwCols.totalBandwidth();
2703 0 : ScalarColumn<Int> measFreqRefCol = spwCols.measFreqRef();
2704 :
2705 : // Create list of input channels
2706 0 : vector<channelInfo> inputChannels;
2707 0 : for(rownr_t spw_idx=0; spw_idx<nInputSpws; spw_idx++)
2708 : {
2709 : Int spwId;
2710 0 : if (outputInputSPWIndexMap_p.size())
2711 : {
2712 0 : spwId = outputInputSPWIndexMap_p[spw_idx];
2713 : }
2714 : else
2715 : {
2716 0 : spwId = spw_idx;
2717 : }
2718 :
2719 : // jagonzal: Skip this SPW in non-reindex mode
2720 0 : if ((!reindex_p) and (numOfSelChanMap_p.find(spw_idx) == numOfSelChanMap_p.end())) continue;
2721 :
2722 0 : Vector<Double> originalChanFreq(chanFreqCol(spw_idx));
2723 0 : Vector<Double> originalChanWidth(chanWidthCol(spw_idx));
2724 0 : Vector<Double> inputEffectiveBW(effectiveBWCol(spw_idx));
2725 0 : Vector<Double> inputResolution(resolutionCol(spw_idx));
2726 0 : uInt nChannels = originalChanFreq.size();
2727 :
2728 0 : for (uInt chan_idx=0;chan_idx<nChannels;chan_idx++)
2729 : {
2730 0 : channelInfo channelInfo_idx;
2731 0 : channelInfo_idx.SPW_id = spwId;
2732 :
2733 0 : channelInfo_idx.inpChannel = chan_idx;
2734 0 : channelInfo_idx.CHAN_FREQ = originalChanFreq(chan_idx);
2735 0 : channelInfo_idx.CHAN_WIDTH = originalChanWidth(chan_idx);
2736 0 : channelInfo_idx.EFFECTIVE_BW = inputEffectiveBW(chan_idx);
2737 0 : channelInfo_idx.RESOLUTION = inputResolution(chan_idx);
2738 :
2739 0 : inputChannels.push_back(channelInfo_idx);
2740 0 : }
2741 0 : }
2742 :
2743 : // Sort input channels
2744 0 : sort (inputChannels.begin(), inputChannels.end());
2745 :
2746 : /// Determine combined SPW structure ///////////////////
2747 :
2748 : // Determine combined SPWs
2749 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2750 0 : << "Calculate combined SPW frequencies" << LogIO::POST;
2751 :
2752 0 : Vector<Double> combinedCHAN_FREQ;
2753 0 : Vector<Double> combinedCHAN_WIDTH;
2754 0 : std::vector<std::vector<Int> > averageWhichChan;
2755 0 : std::vector<std::vector<Int> > averageWhichSPW;
2756 0 : std::vector<std::vector<Double> > averageChanFrac;
2757 0 : MSTransformRegridder::combineSpws(logger_p,outMsName_p,Vector<Int>(1,-1),
2758 : combinedCHAN_FREQ,combinedCHAN_WIDTH,
2759 : averageWhichChan, averageWhichSPW, averageChanFrac, true);
2760 :
2761 : // Create list of combined channels
2762 0 : vector<channelInfo> combinedChannels;
2763 0 : uInt nCombinedChannels = combinedCHAN_FREQ.size();
2764 0 : for (uInt chan_idx=0;chan_idx<nCombinedChannels;chan_idx++)
2765 : {
2766 0 : channelInfo channelInfo_idx;
2767 0 : channelInfo_idx.SPW_id = 0;
2768 0 : channelInfo_idx.inpChannel = chan_idx;
2769 0 : channelInfo_idx.CHAN_FREQ = combinedCHAN_FREQ(chan_idx);
2770 0 : channelInfo_idx.CHAN_WIDTH = combinedCHAN_WIDTH(chan_idx);
2771 0 : channelInfo_idx.EFFECTIVE_BW = combinedCHAN_WIDTH(chan_idx);
2772 0 : channelInfo_idx.RESOLUTION = combinedCHAN_WIDTH(chan_idx);
2773 0 : channelInfo_idx.contribFrac = averageChanFrac.at(chan_idx);
2774 0 : channelInfo_idx.contribSPW_id = averageWhichSPW.at(chan_idx);
2775 0 : channelInfo_idx.contribChannel = averageWhichChan.at(chan_idx);
2776 0 : combinedChannels.push_back(channelInfo_idx);
2777 0 : }
2778 :
2779 : // create list of input overlapping channels per combined channel
2780 : // note combineSpws has an edge case growing channels for slight overlap on edges,
2781 : // there the overlap is 1 even though combchannel->overlap(inputchannel) is slightly smaller than 1
2782 0 : inputOutputChanFactorMap_p.clear();
2783 :
2784 0 : for (auto combChanIter = combinedChannels.begin(); combChanIter != combinedChannels.end(); combChanIter++)
2785 : {
2786 0 : for (auto k = 0lu; k < combChanIter->contribFrac.size(); k++)
2787 : {
2788 : // combineSpws sorts spw so we need to map back to input selection to get correct input spw
2789 0 : uInt spw_idx = combChanIter->contribSPW_id[k];
2790 0 : if (outputInputSPWIndexMap_p.size())
2791 : {
2792 0 : spw_idx = outputInputSPWIndexMap_p[spw_idx];
2793 : }
2794 :
2795 : // jagonzal: Skip this SPW in non-reindex mode
2796 0 : if ((!reindex_p) and (numOfSelChanMap_p.find(spw_idx) == numOfSelChanMap_p.end())) continue;
2797 :
2798 0 : inputOutputChanFactorMap_p[combChanIter->inpChannel].
2799 0 : push_back(channelContribution(spw_idx, combChanIter->contribChannel[k], combChanIter->inpChannel, combChanIter->contribFrac[k]));
2800 : }
2801 : }
2802 :
2803 : /// Calculate output SPW ///////////////////////////////
2804 0 : Vector<Double> regriddedCHAN_FREQ;
2805 0 : Vector<Double> regriddedCHAN_WIDTH;
2806 0 : Vector<Double> inputCHAN_FREQ;
2807 0 : Vector<Double> inputCHAN_WIDTH;
2808 0 : regridSpwAux(0,inputReferenceFrame_p,combinedCHAN_FREQ,combinedCHAN_WIDTH,inputCHAN_FREQ,inputCHAN_WIDTH,regriddedCHAN_FREQ,regriddedCHAN_WIDTH,string("Combined"));
2809 0 : spwInfo inputSpw(inputCHAN_FREQ,inputCHAN_WIDTH);
2810 0 : spwInfo outputSpw(regriddedCHAN_FREQ,regriddedCHAN_WIDTH);
2811 :
2812 : /// Modify SPW subtable ////////////////////////////////
2813 :
2814 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2815 0 : << "Write output SPW subtable " << LogIO::POST;
2816 :
2817 : // Delete combined SPWs (reverse to preserve row number)
2818 0 : uInt rowsToDelete = nInputSpws-1;
2819 0 : for(Int spw_idx=rowsToDelete; spw_idx>0; spw_idx--)
2820 : {
2821 0 : spwTable.removeRow(spw_idx);
2822 : }
2823 :
2824 : // Set the output SPW characteristics in the SPW sub-table
2825 0 : numChanCol.put(0,outputSpw.NUM_CHAN);
2826 0 : chanFreqCol.put(0, outputSpw.CHAN_FREQ);
2827 0 : chanWidthCol.put(0, outputSpw.CHAN_WIDTH);
2828 0 : effectiveBWCol.put(0, outputSpw.EFFECTIVE_BW);
2829 0 : resolutionCol.put(0, outputSpw.RESOLUTION);
2830 0 : refFrequencyCol.put(0,outputSpw.REF_FREQUENCY);
2831 0 : totalBandwidthCol.put(0,outputSpw.TOTAL_BANDWIDTH);
2832 0 : measFreqRefCol.put(0,outputReferenceFrame_p);
2833 :
2834 : /// Add input-output SPW pair to map ///////////////////
2835 0 : inputOutputSpwMap_p[0] = std::make_pair(inputSpw,outputSpw);
2836 :
2837 : // Prepare frequency transformation engine for the reference time
2838 0 : if (fftShiftEnabled_p)
2839 : {
2840 0 : MFrequency::Ref inputFrameRef(inputReferenceFrame_p,
2841 0 : MeasFrame(phaseCenter_p, observatoryPosition_p, referenceTime_p));
2842 0 : MFrequency::Ref outputFrameRef(outputReferenceFrame_p,
2843 0 : MeasFrame(phaseCenter_p, observatoryPosition_p, referenceTime_p));
2844 0 : refTimeFreqTransEngine_p = MFrequency::Convert(MSTransformations::Hz, inputFrameRef, outputFrameRef);
2845 :
2846 0 : for(uInt chan_idx=0; chan_idx<inputOutputSpwMap_p[0].first.CHAN_FREQ.size(); chan_idx++)
2847 : {
2848 0 : inputOutputSpwMap_p[0].first.CHAN_FREQ_aux[chan_idx] =
2849 0 : refTimeFreqTransEngine_p(inputOutputSpwMap_p[0].first.CHAN_FREQ[chan_idx]).
2850 0 : get(MSTransformations::Hz).getValue();
2851 : }
2852 0 : }
2853 :
2854 0 : return;
2855 0 : }
2856 :
2857 :
2858 : // -----------------------------------------------------------------------
2859 : // Auxiliary method common whenever re-gridding is necessary (with or without combining
2860 : // the SPWs). It regrids one SPW.
2861 : // -----------------------------------------------------------------------
2862 0 : void MSTransformManager::regridSpwAux(Int spwId, MFrequency::Types spwInputRefFrame,
2863 : Vector<Double> &originalCHAN_FREQ,
2864 : Vector<Double> &originalCHAN_WIDTH,
2865 : Vector<Double> &inputCHAN_FREQ,
2866 : Vector<Double> &inputCHAN_WIDTH,
2867 : Vector<Double> ®riddedCHAN_FREQ,
2868 : Vector<Double> ®riddedCHAN_WIDTH,
2869 : string msg)
2870 : {
2871 :
2872 : // Print characteristics of input SPW
2873 0 : ostringstream oss;
2874 0 : oss << msg;
2875 0 : oss << " SPW: " << std::setw(5) << originalCHAN_FREQ.size()
2876 : << " channels, first channel = "
2877 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2878 0 : << originalCHAN_FREQ(0) << " Hz"
2879 : << ", last channel = "
2880 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2881 0 : << originalCHAN_FREQ(originalCHAN_FREQ.size() -1) << " Hz"
2882 : << ", first width = "
2883 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2884 0 : << originalCHAN_WIDTH(originalCHAN_WIDTH.size()-1) << " Hz"
2885 : << ", last width = "
2886 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2887 0 : << originalCHAN_WIDTH(originalCHAN_WIDTH.size()-1) << " Hz"
2888 : ;
2889 :
2890 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__) << oss.str() << LogIO::POST;
2891 :
2892 : // Apply channel average if necessary
2893 0 : if (freqbinMap_p.find(spwId) != freqbinMap_p.end()) {
2894 0 : calculateIntermediateFrequencies(spwId,originalCHAN_FREQ,originalCHAN_WIDTH,inputCHAN_FREQ,inputCHAN_WIDTH);
2895 :
2896 0 : oss.str("");
2897 0 : oss.clear();
2898 0 : oss << "Averaged SPW: " << std::setw(5) << inputCHAN_WIDTH.size()
2899 : << " channels, first channel = "
2900 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2901 0 : << inputCHAN_FREQ(0) << " Hz"
2902 : << ", last channel = "
2903 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2904 0 : << inputCHAN_FREQ(inputCHAN_WIDTH.size() -1) << " Hz";
2905 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2906 0 : << oss.str() << LogIO::POST;
2907 : } else {
2908 0 : numOfCombInputChanMap_p[spwId] = originalCHAN_FREQ.size();
2909 0 : numOfCombInterChanMap_p[spwId] = originalCHAN_FREQ.size();
2910 0 : inputCHAN_FREQ = originalCHAN_FREQ;
2911 0 : inputCHAN_WIDTH = originalCHAN_WIDTH;
2912 : }
2913 :
2914 : // Re-grid the output SPW to be uniform and change reference frame
2915 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2916 0 : << "Calculate frequencies in output reference frame " << LogIO::POST;
2917 :
2918 : Double weightScale;
2919 0 : bool ret = MSTransformRegridder::calcChanFreqs(logger_p,
2920 : regriddedCHAN_FREQ, regriddedCHAN_WIDTH,
2921 : weightScale, inputCHAN_FREQ,
2922 0 : inputCHAN_WIDTH, phaseCenter_p,
2923 0 : spwInputRefFrame, referenceTime_p,
2924 0 : observatoryPosition_p, mode_p, nChan_p,
2925 0 : start_p, width_p, restFrequency_p,
2926 0 : outputReferenceFramePar_p,
2927 0 : velocityType_p,
2928 : true, // verbose
2929 0 : radialVelocity_p);
2930 :
2931 0 : if (!ret) {
2932 0 : logger_p << LogIO::SEVERE << "calcChanFreqs failed, check input start and width parameters"
2933 0 : << LogIO::EXCEPTION;
2934 : }
2935 :
2936 0 : ostringstream oss_debug;
2937 0 : oss_debug << "after calcChanFreqs, phaseCenter_p=" << phaseCenter_p << endl
2938 0 : << " inputReferenceFrame_p=" << inputReferenceFrame_p << endl
2939 0 : << " referenceTime_p=" << referenceTime_p << endl
2940 0 : << " observatoryPosition_p=" << observatoryPosition_p << endl
2941 0 : << " mode_p=" << mode_p << endl
2942 0 : << " nChan_p=" << nChan_p << endl
2943 0 : << " start_p=" << start_p << endl
2944 0 : << " width_p=" << width_p << endl
2945 0 : << " restFrequency_p=" << restFrequency_p << endl
2946 0 : << " outputReferenceFrame_p=" << outputReferenceFrame_p << endl
2947 0 : << " velocityType_p=" << velocityType_p << endl
2948 0 : << " radialVelocity_p=" << radialVelocity_p;
2949 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__) <<
2950 0 : oss_debug.str() << LogIO::POST;
2951 :
2952 : // jagonzal (new WEIGHT/SIGMA convention in CASA 4.2.2)
2953 0 : if (newWeightFactorMap_p.find(spwId) == newWeightFactorMap_p.end()) {
2954 0 : newWeightFactorMap_p[spwId] = weightScale;
2955 : } else {
2956 0 : newWeightFactorMap_p[spwId] *= weightScale;
2957 : }
2958 :
2959 0 : checkAndPreaverageChannelsIfNeeded(spwId, inputCHAN_FREQ, inputCHAN_WIDTH,
2960 : originalCHAN_FREQ, originalCHAN_WIDTH,
2961 : regriddedCHAN_FREQ, regriddedCHAN_WIDTH);
2962 :
2963 : // Print characteristics of output SPW
2964 0 : oss.str("");
2965 0 : oss.clear();
2966 0 : oss << "Output SPW: " << std::setw(5) << regriddedCHAN_FREQ.size()
2967 : << " channels, first channel = "
2968 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2969 0 : << regriddedCHAN_FREQ(0) << " Hz"
2970 : << ", last channel = "
2971 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2972 0 : << regriddedCHAN_FREQ(regriddedCHAN_FREQ.size()-1) << " Hz"
2973 : <<", first width = "
2974 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2975 0 : << regriddedCHAN_WIDTH(0) << " Hz"
2976 : << ", last width = "
2977 0 : << std::setprecision(9) << std::setw(14) << std::scientific
2978 0 : << regriddedCHAN_WIDTH(regriddedCHAN_WIDTH.size()-1) << " Hz";
2979 :
2980 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2981 0 : << oss.str() << LogIO::POST;
2982 0 : }
2983 :
2984 : // -----------------------------------------------------------------------
2985 : //
2986 : // -----------------------------------------------------------------------
2987 0 : void MSTransformManager::separateSpwSubtable()
2988 : {
2989 0 : if (Table::isReadable(outputMs_p->spectralWindowTableName()) and !outputMs_p->spectralWindow().isNull())
2990 : {
2991 : // Access Spectral Window sub-table
2992 0 : MSSpectralWindow spwTable = outputMs_p->spectralWindow();
2993 :
2994 0 : if (spwTable.nrow() > 0)
2995 : {
2996 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
2997 0 : << " Multiplexing SPECTRAL_WINDOW sub-table to take into account new SPWs " << LogIO::POST;
2998 :
2999 0 : MSSpWindowColumns spwCols(spwTable);
3000 :
3001 : // Access columns which have to be separated
3002 0 : ArrayColumn<Double> chanFreqCol = spwCols.chanFreq();
3003 0 : Vector<Double> chanFreq = chanFreqCol(0);
3004 0 : ArrayColumn<Double> chanWidthCol = spwCols.chanWidth();
3005 0 : Vector<Double> chanWidth = chanWidthCol(0);
3006 0 : ArrayColumn<Double> effectiveBWCol = spwCols.chanWidth();
3007 0 : Vector<Double> effectiveBW = effectiveBWCol(0);
3008 0 : ArrayColumn<Double> resolutionCol = spwCols.resolution();
3009 0 : Vector<Double> resolution = resolutionCol(0);
3010 :
3011 : // Resize columns to be separated
3012 : // jagonzal (jagonzal (CAS-7435)): Last spw must have fewer channels
3013 : /*
3014 : if (tailOfChansforLastSpw_p)
3015 : {
3016 : uInt nInChannels = chanFreq.size();
3017 : uInt nOutChannels = nspws_p*chansPerOutputSpw_p;
3018 : uInt newChannels = nOutChannels-nInChannels;
3019 : Double lastFreq = chanFreq(chanFreq.size()-1);
3020 : Double lastWidth = chanWidth(chanFreq.size()-1);
3021 : Double lastEffectiveBW = effectiveBW(chanFreq.size()-1);
3022 : Double lastResolution = resolution(chanFreq.size()-1);
3023 :
3024 : chanFreq.resize(nOutChannels,true);
3025 : chanWidth.resize(nOutChannels,true);
3026 : effectiveBW.resize(nOutChannels,true);
3027 : resolution.resize(nOutChannels,true);
3028 :
3029 : uInt outIndex;
3030 : for (uInt newChanIdx = 0; newChanIdx<newChannels; newChanIdx++)
3031 : {
3032 : outIndex = nInChannels+newChanIdx;
3033 : chanFreq(outIndex) = lastFreq + (newChanIdx+1)*lastWidth;
3034 : chanWidth(outIndex) = lastWidth;
3035 : effectiveBW(outIndex) = lastEffectiveBW;
3036 : resolution(outIndex) = lastResolution;
3037 : }
3038 : }
3039 : */
3040 :
3041 : // Calculate bandwidth per output spw
3042 0 : Double totalBandwidth = chanWidth(0)*chansPerOutputSpw_p;
3043 :
3044 0 : uInt rowIndex = 0;
3045 0 : for (uInt spw_i=0; spw_i<nspws_p; spw_i++)
3046 : {
3047 : // Columns that can be just copied
3048 0 : if (rowIndex > 0)
3049 : {
3050 : // Add row
3051 0 : spwTable.addRow(1,true);
3052 :
3053 0 : spwCols.measFreqRef().put(rowIndex,spwCols.measFreqRef()(0));
3054 0 : spwCols.flagRow().put(rowIndex,spwCols.flagRow()(0));
3055 0 : spwCols.freqGroup().put(rowIndex,spwCols.freqGroup()(0));
3056 0 : spwCols.freqGroupName().put(rowIndex,spwCols.freqGroupName()(0));
3057 0 : spwCols.ifConvChain().put(rowIndex,spwCols.ifConvChain()(0));
3058 0 : spwCols.name().put(rowIndex,spwCols.name()(0));
3059 0 : spwCols.netSideband().put(rowIndex,spwCols.netSideband()(0));
3060 :
3061 : // Optional columns
3062 0 : if (MSTransformDataHandler::columnOk(spwCols.bbcNo()))
3063 : {
3064 0 : spwCols.bbcNo().put(rowIndex,spwCols.bbcNo()(0));
3065 : }
3066 :
3067 0 : if (MSTransformDataHandler::columnOk(spwCols.assocSpwId()))
3068 : {
3069 0 : spwCols.assocSpwId().put(rowIndex,spwCols.assocSpwId()(0));
3070 : }
3071 :
3072 0 : if (MSTransformDataHandler::columnOk(spwCols.assocNature()))
3073 : {
3074 0 : spwCols.assocNature().put(rowIndex,spwCols.assocNature()(0));
3075 : }
3076 :
3077 0 : if (MSTransformDataHandler::columnOk(spwCols.bbcSideband()))
3078 : {
3079 0 : spwCols.bbcSideband().put(rowIndex,spwCols.bbcSideband()(0));
3080 : }
3081 :
3082 0 : if (MSTransformDataHandler::columnOk(spwCols.dopplerId()))
3083 : {
3084 0 : spwCols.dopplerId().put(rowIndex,spwCols.dopplerId()(0));
3085 : }
3086 :
3087 0 : if (MSTransformDataHandler::columnOk(spwCols.receiverId()))
3088 : {
3089 0 : spwCols.receiverId().put(rowIndex,spwCols.receiverId()(0));
3090 : }
3091 :
3092 0 : if (spwTable.tableDesc().isColumn("SDM_WINDOW_FUNCTION") &&
3093 0 : spwTable.tableDesc().columnDescSet().isDefined("SDM_WINDOW_FUNCTION"))
3094 : {
3095 0 : ScalarColumn<String> swfCol(spwTable, "SDM_WINDOW_FUNCTION");
3096 0 : swfCol.put(rowIndex, swfCol(0));
3097 0 : }
3098 :
3099 0 : if (spwTable.tableDesc().isColumn("SDM_NUM_BIN") &&
3100 0 : spwTable.tableDesc().columnDescSet().isDefined("SDM_NUM_BIN"))
3101 : {
3102 0 : ScalarColumn<Int> snbCol(spwTable, "SDM_NUM_BIN");
3103 0 : snbCol.put(rowIndex, snbCol(0));
3104 0 : }
3105 :
3106 0 : if (spwTable.tableDesc().isColumn("SDM_CORR_BIT") &&
3107 0 : spwTable.tableDesc().columnDescSet().isDefined("SDM_CORR_BIT"))
3108 : {
3109 0 : ScalarColumn<String> corrBitCol(spwTable, "SDM_CORR_BIT");
3110 0 : corrBitCol.put(rowIndex, corrBitCol(0));
3111 0 : }
3112 :
3113 : }
3114 :
3115 0 : if ( (spw_i < nspws_p-1) or (tailOfChansforLastSpw_p == 0) )
3116 : {
3117 0 : Slice range(chansPerOutputSpw_p*spw_i,chansPerOutputSpw_p);
3118 :
3119 : // Array columns that have to be modified
3120 0 : spwCols.chanFreq().put(rowIndex,chanFreq(range));
3121 0 : spwCols.chanWidth().put(rowIndex,chanWidth(range));
3122 0 : spwCols.effectiveBW().put(rowIndex,effectiveBW(range));
3123 0 : spwCols.resolution().put(rowIndex,resolution(range));
3124 :
3125 : // Scalar columns that have to be modified
3126 0 : spwCols.numChan().put(rowIndex,chansPerOutputSpw_p);
3127 0 : spwCols.totalBandwidth().put(rowIndex,totalBandwidth);
3128 0 : spwCols.refFrequency().put(rowIndex,chanFreq(range)(0));
3129 0 : }
3130 : // jagonzal (jagonzal (CAS-7435)): Last spw must have fewer channels
3131 : else
3132 : {
3133 0 : Slice range(chansPerOutputSpw_p*spw_i,tailOfChansforLastSpw_p);
3134 :
3135 : // Array columns that have to be modified
3136 0 : spwCols.chanFreq().put(rowIndex,chanFreq(range));
3137 0 : spwCols.chanWidth().put(rowIndex,chanWidth(range));
3138 0 : spwCols.effectiveBW().put(rowIndex,effectiveBW(range));
3139 0 : spwCols.resolution().put(rowIndex,resolution(range));
3140 :
3141 : // Scalar columns that have to be modified
3142 0 : spwCols.numChan().put(rowIndex,tailOfChansforLastSpw_p);
3143 0 : spwCols.totalBandwidth().put(rowIndex,chanWidth(0)*tailOfChansforLastSpw_p);
3144 0 : spwCols.refFrequency().put(rowIndex,chanFreq(range)(0));
3145 : }
3146 :
3147 0 : rowIndex += 1;
3148 : }
3149 :
3150 : // Remove first row
3151 : // spwTable.removeRow(0);
3152 0 : }
3153 : else
3154 : {
3155 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
3156 0 : << "SPECTRAL_WINDOW sub-table found but has no valid content" << LogIO::POST;
3157 : }
3158 0 : }
3159 : else
3160 : {
3161 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
3162 0 : << "SPECTRAL_WINDOW sub-table not found " << LogIO::POST;
3163 : }
3164 :
3165 0 : return;
3166 : }
3167 :
3168 : // -----------------------------------------------------------------------
3169 : //
3170 : // -----------------------------------------------------------------------
3171 0 : void MSTransformManager::separateFeedSubtable()
3172 : {
3173 0 : if (Table::isReadable(outputMs_p->feedTableName()) and !outputMs_p->feed().isNull())
3174 : {
3175 : // Access Feed sub-table
3176 0 : MSFeed feedtable = outputMs_p->feed();
3177 :
3178 0 : if (feedtable.nrow() > 0)
3179 : {
3180 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
3181 0 : << " Multiplexing FEED sub-table to take into account new SPWs " << LogIO::POST;
3182 :
3183 0 : MSFeedColumns feedCols(feedtable);
3184 :
3185 : // Get original content from columns
3186 0 : Array<Double> position = feedCols.position().getColumn();
3187 0 : Array<Double> beamOffset = feedCols.beamOffset().getColumn();
3188 0 : Array<String> polarizationType = feedCols.polarizationType().getColumn();
3189 0 : Array<Complex> polResponse = feedCols.polResponse().getColumn();
3190 0 : Array<Double> receptorAngle = feedCols.receptorAngle().getColumn();
3191 0 : Array<Int> antennaId = feedCols.antennaId().getColumn();
3192 0 : Array<Int> beamId = feedCols.beamId().getColumn();
3193 0 : Array<Int> feedId = feedCols.feedId().getColumn();
3194 0 : Array<Double> interval = feedCols.interval().getColumn();
3195 0 : Array<Int> numReceptors = feedCols.numReceptors().getColumn();
3196 0 : Array<Int> spectralWindowId = feedCols.spectralWindowId().getColumn();
3197 0 : Array<Double> time = feedCols.time().getColumn();
3198 :
3199 : // Optional columns
3200 0 : Array<Double> focusLength;
3201 0 : if (MSTransformDataHandler::columnOk(feedCols.focusLength()))
3202 : {
3203 0 : focusLength = feedCols.focusLength().getColumn();
3204 : }
3205 :
3206 0 : Array<Int> phasedFeedId;
3207 0 : if (MSTransformDataHandler::columnOk(feedCols.phasedFeedId()))
3208 : {
3209 0 : phasedFeedId = feedCols.phasedFeedId().getColumn();
3210 : }
3211 :
3212 0 : auto nRowsPerSpw = feedCols.spectralWindowId().nrow();
3213 0 : auto rowIndex = nRowsPerSpw;
3214 0 : for (uInt spw_i=1; spw_i<nspws_p; spw_i++)
3215 : {
3216 : // Add rows
3217 0 : feedtable.addRow(nRowsPerSpw);
3218 :
3219 : // Prepare row reference object
3220 0 : RefRows refRow(rowIndex,rowIndex+nRowsPerSpw-1);
3221 :
3222 : // Reindex SPW col
3223 0 : spectralWindowId = spw_i;
3224 0 : feedCols.spectralWindowId().putColumnCells(refRow,spectralWindowId);
3225 :
3226 : // Columns that can be just copied
3227 0 : feedCols.position().putColumnCells(refRow,position);
3228 0 : feedCols.beamOffset().putColumnCells(refRow,beamOffset);
3229 0 : feedCols.polarizationType().putColumnCells(refRow,polarizationType);
3230 0 : feedCols.polResponse().putColumnCells(refRow,polResponse);
3231 0 : feedCols.receptorAngle().putColumnCells(refRow,receptorAngle);
3232 0 : feedCols.antennaId().putColumnCells(refRow,antennaId);
3233 0 : feedCols.beamId().putColumnCells(refRow,beamId);
3234 0 : feedCols.feedId().putColumnCells(refRow,feedId);
3235 0 : feedCols.interval().putColumnCells(refRow,interval);
3236 0 : feedCols.numReceptors().putColumnCells(refRow,numReceptors);
3237 0 : feedCols.time().putColumnCells(refRow,time);
3238 :
3239 : // Optional columns
3240 0 : if (MSTransformDataHandler::columnOk(feedCols.focusLength()))
3241 : {
3242 0 : feedCols.focusLength().putColumnCells(refRow,focusLength);
3243 : }
3244 :
3245 0 : if (MSTransformDataHandler::columnOk(feedCols.phasedFeedId()))
3246 : {
3247 0 : feedCols.phasedFeedId().putColumnCells(refRow,phasedFeedId);
3248 : }
3249 :
3250 : // Increment row offset
3251 0 : rowIndex += nRowsPerSpw;
3252 0 : }
3253 :
3254 0 : }
3255 : else
3256 : {
3257 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
3258 0 : << "FEED sub-table found but has no valid content" << LogIO::POST;
3259 : }
3260 0 : }
3261 : else
3262 : {
3263 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
3264 0 : << "FEED sub-table not found " << LogIO::POST;
3265 : }
3266 :
3267 0 : return;
3268 : }
3269 :
3270 : // -----------------------------------------------------------------------
3271 : //
3272 : // -----------------------------------------------------------------------
3273 0 : void MSTransformManager::separateSourceSubtable()
3274 : {
3275 0 : if (Table::isReadable(outputMs_p->sourceTableName()) and !outputMs_p->source().isNull())
3276 : {
3277 : // Access Source sub-table
3278 0 : MSSource sourcetable = outputMs_p->source();
3279 :
3280 0 : if (sourcetable.nrow() > 0)
3281 : {
3282 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
3283 0 : << " Multiplexing SOURCE sub-table to take into account new SPWs " << LogIO::POST;
3284 :
3285 0 : MSSourceColumns sourceCols(sourcetable);
3286 :
3287 : // Get original content from columns
3288 0 : Array<Double> direction = sourceCols.direction().getColumn();
3289 0 : Array<Double> properMotion = sourceCols.properMotion().getColumn();
3290 0 : Array<Int> calibrationGroup = sourceCols.calibrationGroup().getColumn();
3291 0 : Array<String> code = sourceCols.code().getColumn();
3292 0 : Array<Double> interval = sourceCols.interval().getColumn();
3293 0 : Array<String> name = sourceCols.name().getColumn();
3294 0 : Array<Int> numLines = sourceCols.numLines().getColumn();
3295 0 : Array<Int> sourceId = sourceCols.sourceId().getColumn();
3296 0 : Array<Int> spectralWindowId = sourceCols.spectralWindowId().getColumn();
3297 0 : Array<Double> time = sourceCols.time().getColumn();
3298 :
3299 : // Optional columns
3300 0 : Array<Double> position;
3301 0 : if (MSTransformDataHandler::columnOk(sourceCols.position()))
3302 : {
3303 0 : position = sourceCols.position().getColumn();
3304 : }
3305 :
3306 0 : Array<String> transition;
3307 0 : if (MSTransformDataHandler::columnOk(sourceCols.transition()))
3308 : {
3309 0 : transition = sourceCols.transition().getColumn();
3310 : }
3311 :
3312 0 : Array<Double> restFrequency;
3313 0 : if (MSTransformDataHandler::columnOk(sourceCols.restFrequency()))
3314 : {
3315 0 : restFrequency = sourceCols.restFrequency().getColumn();
3316 : }
3317 :
3318 0 : Array<Double> sysvel;
3319 0 : if (MSTransformDataHandler::columnOk(sourceCols.sysvel()))
3320 : {
3321 0 : sysvel = sourceCols.sysvel().getColumn();
3322 : }
3323 :
3324 0 : Array<Int> pulsarId;
3325 0 : if (MSTransformDataHandler::columnOk(sourceCols.pulsarId()))
3326 : {
3327 0 : pulsarId = sourceCols.pulsarId().getColumn();
3328 : }
3329 :
3330 0 : Array<TableRecord> sourceModel;
3331 0 : if (MSTransformDataHandler::columnOk(sourceCols.sourceModel()))
3332 : {
3333 0 : sourceModel = sourceCols.sourceModel().getColumn();
3334 : }
3335 :
3336 :
3337 0 : auto nRowsPerSpw = sourceCols.spectralWindowId().nrow();
3338 0 : auto rowIndex = nRowsPerSpw;
3339 0 : for (uInt spw_i=1; spw_i<nspws_p; spw_i++)
3340 : {
3341 : // Add rows
3342 0 : sourcetable.addRow(nRowsPerSpw);
3343 :
3344 : // Prepare row reference object
3345 0 : RefRows refRow(rowIndex,rowIndex+nRowsPerSpw-1);
3346 :
3347 : // Re-index SPW col
3348 0 : spectralWindowId = spw_i;
3349 0 : sourceCols.spectralWindowId().putColumnCells(refRow,spectralWindowId);
3350 :
3351 : // Columns that can be just copied
3352 0 : sourceCols.direction().putColumnCells(refRow,direction);
3353 0 : sourceCols.properMotion().putColumnCells(refRow,properMotion);
3354 0 : sourceCols.calibrationGroup().putColumnCells(refRow,calibrationGroup);
3355 0 : sourceCols.code().putColumnCells(refRow,code);
3356 0 : sourceCols.interval().putColumnCells(refRow,interval);
3357 0 : sourceCols.name().putColumnCells(refRow,name);
3358 0 : sourceCols.numLines().putColumnCells(refRow,numLines);
3359 0 : sourceCols.sourceId().putColumnCells(refRow,sourceId);
3360 0 : sourceCols.time().putColumnCells(refRow,time);
3361 :
3362 : // Optional columns
3363 0 : if (MSTransformDataHandler::columnOk(sourceCols.position()))
3364 : {
3365 0 : sourceCols.position().putColumnCells(refRow,position);
3366 : }
3367 :
3368 0 : if (MSTransformDataHandler::columnOk(sourceCols.transition()))
3369 : {
3370 0 : sourceCols.transition().putColumnCells(refRow,transition);
3371 : }
3372 :
3373 0 : if (MSTransformDataHandler::columnOk(sourceCols.restFrequency()))
3374 : {
3375 0 : sourceCols.restFrequency().putColumnCells(refRow,restFrequency);
3376 : }
3377 :
3378 0 : if (MSTransformDataHandler::columnOk(sourceCols.sysvel()))
3379 : {
3380 0 : sourceCols.sysvel().putColumnCells(refRow,sysvel);
3381 : }
3382 :
3383 0 : if (MSTransformDataHandler::columnOk(sourceCols.pulsarId()))
3384 : {
3385 0 : sourceCols.pulsarId().putColumnCells(refRow,pulsarId);
3386 : }
3387 :
3388 0 : if (MSTransformDataHandler::columnOk(sourceCols.sourceModel()))
3389 : {
3390 0 : sourceCols.sourceModel().putColumnCells(refRow,sourceModel);
3391 : }
3392 :
3393 : // Increment row offset
3394 0 : rowIndex += nRowsPerSpw;
3395 0 : }
3396 :
3397 0 : }
3398 : else
3399 : {
3400 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
3401 0 : << "SOURCE sub-table found but has no valid content" << LogIO::POST;
3402 : }
3403 0 : }
3404 : else
3405 : {
3406 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
3407 0 : << "SOURCE sub-table not found " << LogIO::POST;
3408 : }
3409 :
3410 0 : return;
3411 : }
3412 :
3413 : // -----------------------------------------------------------------------
3414 : //
3415 : // -----------------------------------------------------------------------
3416 0 : void MSTransformManager::separateSyscalSubtable()
3417 : {
3418 :
3419 0 : if (Table::isReadable(outputMs_p->sysCalTableName()) and !outputMs_p->sysCal().isNull())
3420 : {
3421 : // Access SysCal sub-table
3422 0 : MSSysCal syscalTable = outputMs_p->sysCal();
3423 :
3424 0 : if (syscalTable.nrow() > 0)
3425 : {
3426 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
3427 0 : << " Multiplexing SYSCAL sub-table to take into account new SPWs " << LogIO::POST;
3428 :
3429 0 : MSSysCalColumns syscalCols(syscalTable);
3430 :
3431 : // Get original content from columns
3432 0 : Array<Int> antennaId = syscalCols.antennaId().getColumn();
3433 0 : Array<Int> feedId = syscalCols.feedId().getColumn();
3434 0 : Array<Double> interval = syscalCols.interval().getColumn();
3435 0 : Array<Int> spectralWindowId = syscalCols.spectralWindowId().getColumn();
3436 0 : Array<Double> time = syscalCols.time().getColumn();
3437 :
3438 : // Optional columns
3439 0 : Array<Float> phaseDiff;
3440 0 : if (MSTransformDataHandler::columnOk(syscalCols.phaseDiff()))
3441 : {
3442 0 : phaseDiff = syscalCols.phaseDiff().getColumn();
3443 : }
3444 :
3445 0 : Array<bool> phaseDiffFlag;
3446 0 : if (MSTransformDataHandler::columnOk(syscalCols.phaseDiffFlag()))
3447 : {
3448 0 : phaseDiffFlag = syscalCols.phaseDiffFlag().getColumn();
3449 : }
3450 :
3451 0 : Array<Float> tant;
3452 0 : if (MSTransformDataHandler::columnOk(syscalCols.tant()))
3453 : {
3454 0 : tant = syscalCols.tant().getColumn();
3455 : }
3456 :
3457 0 : Array<bool> tantFlag;
3458 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantFlag()))
3459 : {
3460 0 : tantFlag = syscalCols.tantFlag().getColumn();
3461 : }
3462 :
3463 0 : Array<Float> tantSpectrum;
3464 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantSpectrum()))
3465 : {
3466 0 : tantSpectrum = syscalCols.tantSpectrum().getColumn();
3467 : }
3468 :
3469 0 : Array<Float> tantTsys;
3470 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantTsys()))
3471 : {
3472 0 : tantTsys = syscalCols.tantTsys().getColumn();
3473 : }
3474 :
3475 0 : Array<bool> tantTsysFlag;
3476 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantTsysFlag()))
3477 : {
3478 0 : tantTsysFlag = syscalCols.tantTsysFlag().getColumn();
3479 : }
3480 :
3481 0 : Array<Float> tantTsysSpectrum;
3482 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantTsysSpectrum()))
3483 : {
3484 0 : tantTsysSpectrum = syscalCols.tantTsysSpectrum().getColumn();
3485 : }
3486 :
3487 0 : Array<Float> tcal;
3488 0 : if (MSTransformDataHandler::columnOk(syscalCols.tcal()))
3489 : {
3490 0 : tcal = syscalCols.tcal().getColumn();
3491 : }
3492 :
3493 0 : Array<bool> tcalFlag;
3494 0 : if (MSTransformDataHandler::columnOk(syscalCols.tcalFlag()))
3495 : {
3496 0 : tcalFlag = syscalCols.tcalFlag().getColumn();
3497 : }
3498 :
3499 0 : Array<Float> tcalSpectrum;
3500 0 : if (MSTransformDataHandler::columnOk(syscalCols.tcalSpectrum()))
3501 : {
3502 0 : tcalSpectrum = syscalCols.tcalSpectrum().getColumn();
3503 : }
3504 :
3505 0 : Array<Float> trx;
3506 0 : if (MSTransformDataHandler::columnOk(syscalCols.trx()))
3507 : {
3508 0 : trx = syscalCols.trx().getColumn();
3509 : }
3510 :
3511 0 : Array<bool> trxFlag;
3512 0 : if (MSTransformDataHandler::columnOk(syscalCols.trxFlag()))
3513 : {
3514 0 : trxFlag = syscalCols.trxFlag().getColumn();
3515 : }
3516 :
3517 0 : Array<Float> trxSpectrum;
3518 0 : if (MSTransformDataHandler::columnOk(syscalCols.trxSpectrum()))
3519 : {
3520 0 : trxSpectrum = syscalCols.trxSpectrum().getColumn();
3521 : }
3522 :
3523 0 : Array<Float> tsky;
3524 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsky()))
3525 : {
3526 0 : tsky = syscalCols.tsky().getColumn();
3527 : }
3528 :
3529 0 : Array<bool> tskyFlag;
3530 0 : if (MSTransformDataHandler::columnOk(syscalCols.tskyFlag()))
3531 : {
3532 0 : tskyFlag = syscalCols.tskyFlag().getColumn();
3533 : }
3534 :
3535 0 : Array<Float> tskySpectrum;
3536 0 : if (MSTransformDataHandler::columnOk(syscalCols.tskySpectrum()))
3537 : {
3538 0 : tskySpectrum = syscalCols.tskySpectrum().getColumn();
3539 : }
3540 :
3541 0 : Array<Float> tsys;
3542 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsys()))
3543 : {
3544 0 : tsys = syscalCols.tsys().getColumn();
3545 : }
3546 :
3547 0 : Array<bool> tsysFlag;
3548 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsysFlag()))
3549 : {
3550 0 : tsysFlag = syscalCols.tsysFlag().getColumn();
3551 : }
3552 :
3553 0 : Array<Float> tsysSpectrum;
3554 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsysSpectrum()))
3555 : {
3556 0 : tsysSpectrum = syscalCols.tsysSpectrum().getColumn();
3557 : }
3558 :
3559 :
3560 0 : auto nRowsPerSpw = syscalCols.spectralWindowId().nrow();
3561 0 : auto rowIndex = nRowsPerSpw;
3562 0 : for (uInt spw_i=1; spw_i<nspws_p; spw_i++)
3563 : {
3564 : // Add rows
3565 0 : syscalTable.addRow(nRowsPerSpw);
3566 :
3567 : // Prepare row reference object
3568 0 : RefRows refRow(rowIndex,rowIndex+nRowsPerSpw-1);
3569 :
3570 : // Re-index SPW col
3571 0 : spectralWindowId = spw_i;
3572 0 : syscalCols.spectralWindowId().putColumnCells(refRow,spectralWindowId);
3573 :
3574 : // Columns that can be just copied
3575 0 : syscalCols.antennaId().putColumnCells(refRow,antennaId);
3576 0 : syscalCols.feedId().putColumnCells(refRow,feedId);
3577 0 : syscalCols.interval().putColumnCells(refRow,interval);
3578 0 : syscalCols.time().putColumnCells(refRow,time);
3579 :
3580 : // Optional columns
3581 0 : if (MSTransformDataHandler::columnOk(syscalCols.phaseDiff()))
3582 : {
3583 0 : syscalCols.phaseDiff().putColumnCells(refRow,phaseDiff);
3584 : }
3585 :
3586 0 : if (MSTransformDataHandler::columnOk(syscalCols.phaseDiffFlag()))
3587 : {
3588 0 : syscalCols.phaseDiffFlag().putColumnCells(refRow,phaseDiffFlag);
3589 : }
3590 :
3591 0 : if (MSTransformDataHandler::columnOk(syscalCols.tant()))
3592 : {
3593 0 : syscalCols.tant().putColumnCells(refRow,tant);
3594 : }
3595 :
3596 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantFlag()))
3597 : {
3598 0 : syscalCols.tantFlag().putColumnCells(refRow,tantFlag);
3599 : }
3600 :
3601 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantSpectrum()))
3602 : {
3603 0 : syscalCols.tantSpectrum().putColumnCells(refRow,tantSpectrum);
3604 : }
3605 :
3606 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantTsys()))
3607 : {
3608 0 : syscalCols.tantTsys().putColumnCells(refRow,tantTsys);
3609 : }
3610 :
3611 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantTsysFlag()))
3612 : {
3613 0 : syscalCols.tantTsysFlag().putColumnCells(refRow,tantTsysFlag);
3614 : }
3615 :
3616 0 : if (MSTransformDataHandler::columnOk(syscalCols.tantTsysSpectrum()))
3617 : {
3618 0 : syscalCols.tantTsysSpectrum().putColumnCells(refRow,tantTsysSpectrum);
3619 : }
3620 :
3621 0 : if (MSTransformDataHandler::columnOk(syscalCols.tcal()))
3622 : {
3623 0 : syscalCols.tcal().putColumnCells(refRow,tcal);
3624 : }
3625 :
3626 0 : if (MSTransformDataHandler::columnOk(syscalCols.tcalFlag()))
3627 : {
3628 0 : syscalCols.tcalFlag().putColumnCells(refRow,tcalFlag);
3629 : }
3630 :
3631 0 : if (MSTransformDataHandler::columnOk(syscalCols.tcalSpectrum()))
3632 : {
3633 0 : syscalCols.tcalSpectrum().putColumnCells(refRow,tcalSpectrum);
3634 : }
3635 :
3636 0 : if (MSTransformDataHandler::columnOk(syscalCols.trx()))
3637 : {
3638 0 : syscalCols.trx().putColumnCells(refRow,trx);
3639 : }
3640 :
3641 0 : if (MSTransformDataHandler::columnOk(syscalCols.trxFlag()))
3642 : {
3643 0 : syscalCols.trxFlag().putColumnCells(refRow,trxFlag);
3644 : }
3645 :
3646 0 : if (MSTransformDataHandler::columnOk(syscalCols.trxSpectrum()))
3647 : {
3648 0 : syscalCols.trxSpectrum().putColumnCells(refRow,trxSpectrum);
3649 : }
3650 :
3651 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsky()))
3652 : {
3653 0 : syscalCols.tsky().putColumnCells(refRow,tsky);
3654 : }
3655 :
3656 0 : if (MSTransformDataHandler::columnOk(syscalCols.tskyFlag()))
3657 : {
3658 0 : syscalCols.tskyFlag().putColumnCells(refRow,tskyFlag);
3659 : }
3660 :
3661 0 : if (MSTransformDataHandler::columnOk(syscalCols.tskySpectrum()))
3662 : {
3663 0 : syscalCols.tskySpectrum().putColumnCells(refRow,tskySpectrum);
3664 : }
3665 :
3666 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsys()))
3667 : {
3668 0 : syscalCols.tsys().putColumnCells(refRow,tsys);
3669 : }
3670 :
3671 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsysFlag()))
3672 : {
3673 0 : syscalCols.tsysFlag().putColumnCells(refRow,tsysFlag);
3674 : }
3675 :
3676 0 : if (MSTransformDataHandler::columnOk(syscalCols.tsysSpectrum()))
3677 : {
3678 0 : syscalCols.tsysSpectrum().putColumnCells(refRow,tsysSpectrum);
3679 : }
3680 :
3681 : // Increment row offset
3682 0 : rowIndex += nRowsPerSpw;
3683 0 : }
3684 :
3685 0 : }
3686 : else
3687 : {
3688 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3689 0 : << "SYSCAL sub-table found but has no valid content" << LogIO::POST;
3690 : }
3691 0 : }
3692 : else
3693 : {
3694 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3695 0 : << "SYSCAL sub-table not found " << LogIO::POST;
3696 : }
3697 :
3698 0 : return;
3699 : }
3700 :
3701 : // -----------------------------------------------------------------------
3702 : //
3703 : // -----------------------------------------------------------------------
3704 0 : void MSTransformManager::separateFreqOffsetSubtable()
3705 : {
3706 :
3707 0 : if (Table::isReadable(outputMs_p->freqOffsetTableName()) and !outputMs_p->freqOffset().isNull())
3708 : {
3709 : // Access SysCal sub-table
3710 0 : MSFreqOffset freqoffsetTable = outputMs_p->freqOffset();
3711 :
3712 0 : if (freqoffsetTable.nrow() > 0)
3713 : {
3714 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
3715 0 : << " Multiplexing FREQ_OFFSET sub-table to take into account new SPWs " << LogIO::POST;
3716 :
3717 0 : MSFreqOffsetColumns freqoffsetCols(freqoffsetTable);
3718 :
3719 : // Get original content from columns
3720 0 : Array<Int> antenna1 = freqoffsetCols.antenna1().getColumn();
3721 0 : Array<Int> antenna2 = freqoffsetCols.antenna2().getColumn();
3722 0 : Array<Int> feedId = freqoffsetCols.feedId().getColumn();
3723 0 : Array<Double> interval = freqoffsetCols.interval().getColumn();
3724 0 : Array<Double> offset = freqoffsetCols.offset().getColumn();
3725 0 : Array<Int> spectralWindowId = freqoffsetCols.spectralWindowId().getColumn();
3726 0 : Array<Double> time = freqoffsetCols.time().getColumn();
3727 :
3728 : // NOTE (jagonzal): FreqOffset does not have optional columns
3729 :
3730 0 : auto nRowsPerSpw = freqoffsetCols.spectralWindowId().nrow();
3731 0 : auto rowIndex = nRowsPerSpw;
3732 0 : for (uInt spw_i=1; spw_i<nspws_p; spw_i++)
3733 : {
3734 : // Add rows
3735 0 : freqoffsetTable.addRow(nRowsPerSpw);
3736 :
3737 : // Prepare row reference object
3738 0 : RefRows refRow(rowIndex,rowIndex+nRowsPerSpw-1);
3739 :
3740 : // Re-index SPW col
3741 0 : spectralWindowId = spw_i;
3742 0 : freqoffsetCols.spectralWindowId().putColumnCells(refRow,spectralWindowId);
3743 :
3744 : // Columns that can be just copied
3745 0 : freqoffsetCols.antenna1().putColumnCells(refRow,antenna1);
3746 0 : freqoffsetCols.antenna2().putColumnCells(refRow,antenna2);
3747 0 : freqoffsetCols.feedId().putColumnCells(refRow,feedId);
3748 0 : freqoffsetCols.interval().putColumnCells(refRow,interval);
3749 0 : freqoffsetCols.offset().putColumnCells(refRow,offset);
3750 0 : freqoffsetCols.time().putColumnCells(refRow,time);
3751 :
3752 : // Increment row offset
3753 0 : rowIndex += nRowsPerSpw;
3754 0 : }
3755 :
3756 0 : }
3757 : else
3758 : {
3759 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3760 0 : << "FREQ_OFFSET sub-table found but has no valid content" << LogIO::POST;
3761 : }
3762 0 : }
3763 : else
3764 : {
3765 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3766 0 : << "FREQ_OFFSET sub-table not found " << LogIO::POST;
3767 : }
3768 :
3769 0 : return;
3770 : }
3771 :
3772 : // -----------------------------------------------------------------------
3773 : //
3774 : // -----------------------------------------------------------------------
3775 0 : void MSTransformManager::separateCalDeviceSubtable()
3776 : {
3777 0 : if (Table::isReadable(outputMs_p->tableName() + "/CALDEVICE"))
3778 : {
3779 0 : Table subtable(outputMs_p->tableName() + "/CALDEVICE", Table::Update);
3780 :
3781 0 : if (subtable.nrow() > 0)
3782 : {
3783 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
3784 0 : << " Multiplexing CALDEVICE sub-table to take into account new SPWs " << LogIO::POST;
3785 :
3786 : // Get RW access to columns
3787 0 : ScalarColumn<Int> antennaIdCol(subtable, "ANTENNA_ID");
3788 0 : ScalarColumn<Int> feedIdCol(subtable, "FEED_ID");
3789 0 : ScalarColumn<Int> spectralWindowIdCol(subtable, "SPECTRAL_WINDOW_ID");
3790 0 : ScalarColumn<Double> timeCol(subtable, "TIME");
3791 0 : ScalarColumn<Double> intervalCol(subtable, "INTERVAL");
3792 0 : ScalarColumn<Int> numCalLoadCol(subtable, "NUM_CAL_LOAD");
3793 0 : ArrayColumn<String> calLoadNamesCol(subtable, "CAL_LOAD_NAMES");
3794 0 : ScalarColumn<Int> numReceptorCol(subtable, "NUM_RECEPTOR");
3795 0 : ArrayColumn<Float> noiseCalCol(subtable, "NOISE_CAL");
3796 0 : ArrayColumn<Float> calEffCol(subtable, "CAL_EFF");
3797 0 : ArrayColumn<Double> temperatureLoadCol(subtable, "TEMPERATURE_LOAD");
3798 :
3799 : // Get original content of columns
3800 0 : Array<Int> antennaId;
3801 0 : if (MSTransformDataHandler::columnOk(antennaIdCol))
3802 0 : antennaId = antennaIdCol.getColumn();
3803 0 : Array<Int> feedId;
3804 0 : if (MSTransformDataHandler::columnOk(feedIdCol))
3805 0 : feedId = feedIdCol.getColumn();
3806 0 : Array<Int> spectralWindowId;
3807 0 : if (MSTransformDataHandler::columnOk(spectralWindowIdCol))
3808 0 : spectralWindowId = spectralWindowIdCol.getColumn();
3809 0 : Array<Double> time;
3810 0 : if (MSTransformDataHandler::columnOk(timeCol))
3811 0 : time = timeCol.getColumn();
3812 0 : Array<Double> interval;
3813 0 : if (MSTransformDataHandler::columnOk(intervalCol))
3814 0 : interval = intervalCol.getColumn();
3815 :
3816 0 : Array<Int> numCalLoad;
3817 0 : if (MSTransformDataHandler::columnOk(numCalLoadCol))
3818 0 : numCalLoad = numCalLoadCol.getColumn();
3819 0 : Array<String> calLoadNames;
3820 0 : if (MSTransformDataHandler::columnOk(calLoadNamesCol))
3821 0 : calLoadNames = calLoadNamesCol.getColumn();
3822 0 : Array<Int> numReceptor;
3823 0 : if (MSTransformDataHandler::columnOk(numReceptorCol))
3824 0 : numReceptor = numReceptorCol.getColumn();
3825 0 : Array<Float> noiseCal;
3826 0 : if (MSTransformDataHandler::columnOk(noiseCalCol))
3827 0 : noiseCal = noiseCalCol.getColumn();
3828 0 : Array<Float> calEff;
3829 0 : if (MSTransformDataHandler::columnOk(calEffCol))
3830 0 : calEff = calEffCol.getColumn();
3831 0 : Array<Double> temperatureLoad;
3832 0 : if (MSTransformDataHandler::columnOk(temperatureLoadCol))
3833 0 : temperatureLoad = temperatureLoadCol.getColumn();
3834 :
3835 :
3836 0 : uInt nRowsPerSpw = spectralWindowId.nelements();
3837 0 : uInt rowIndex = nRowsPerSpw;
3838 0 : for (uInt spw_i=1; spw_i<nspws_p; spw_i++)
3839 : {
3840 : // Add rows
3841 0 : subtable.addRow(nRowsPerSpw);
3842 :
3843 : // Prepare row reference object
3844 0 : RefRows refRow(rowIndex,rowIndex+nRowsPerSpw-1);
3845 :
3846 : // Re-index SPW col
3847 0 : spectralWindowId = spw_i;
3848 0 : spectralWindowIdCol.putColumnCells(refRow,spectralWindowId);
3849 :
3850 : // Columns that can be just copied
3851 0 : if (MSTransformDataHandler::columnOk(antennaIdCol))
3852 0 : antennaIdCol.putColumnCells(refRow,antennaId);
3853 0 : if (MSTransformDataHandler::columnOk(feedIdCol))
3854 0 : feedIdCol.putColumnCells(refRow,feedId);
3855 0 : if (MSTransformDataHandler::columnOk(timeCol))
3856 0 : timeCol.putColumnCells(refRow,time);
3857 0 : if (MSTransformDataHandler::columnOk(intervalCol))
3858 0 : intervalCol.putColumnCells(refRow,interval);
3859 :
3860 0 : if (MSTransformDataHandler::columnOk(numCalLoadCol))
3861 0 : numCalLoadCol.putColumnCells(refRow,numCalLoad);
3862 0 : if (MSTransformDataHandler::columnOk(calLoadNamesCol))
3863 0 : calLoadNamesCol.putColumnCells(refRow,calLoadNames);
3864 0 : if (MSTransformDataHandler::columnOk(numReceptorCol))
3865 0 : numReceptorCol.putColumnCells(refRow,numReceptor);
3866 0 : if (MSTransformDataHandler::columnOk(noiseCalCol))
3867 0 : noiseCalCol.putColumnCells(refRow,noiseCal);
3868 0 : if (MSTransformDataHandler::columnOk(calEffCol))
3869 0 : calEffCol.putColumnCells(refRow,calEff);
3870 0 : if (MSTransformDataHandler::columnOk(temperatureLoadCol))
3871 0 : temperatureLoadCol.putColumnCells(refRow,temperatureLoad);
3872 :
3873 : // Increment row offset
3874 0 : rowIndex += nRowsPerSpw;
3875 0 : }
3876 :
3877 0 : }
3878 : else
3879 : {
3880 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3881 0 : << "CALDEVICE sub-table found but has no valid content" << LogIO::POST;
3882 : }
3883 0 : }
3884 : else
3885 : {
3886 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3887 0 : << "CALDEVICE sub-table not found." << LogIO::POST;
3888 : }
3889 :
3890 0 : return;
3891 : }
3892 :
3893 : // -----------------------------------------------------------------------
3894 : //
3895 : // -----------------------------------------------------------------------
3896 0 : void MSTransformManager::separateSysPowerSubtable()
3897 : {
3898 0 : if (Table::isReadable(outputMs_p->tableName() + "/SYSPOWER"))
3899 : {
3900 0 : Table subtable(outputMs_p->tableName() + "/SYSPOWER", Table::Update);
3901 :
3902 0 : if (subtable.nrow() > 0)
3903 : {
3904 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
3905 0 : << " Multiplexing SYSPOWER sub-table to take into account new SPWs " << LogIO::POST;
3906 :
3907 : // Get RW access to columns
3908 0 : ScalarColumn<Int> antennaIdCol(subtable, "ANTENNA_ID");
3909 0 : ScalarColumn<Int> feedIdCol(subtable, "FEED_ID");
3910 0 : ScalarColumn<Int> spectralWindowIdCol(subtable, "SPECTRAL_WINDOW_ID");
3911 0 : ScalarColumn<Double> timeCol(subtable, "TIME");
3912 0 : ScalarColumn<Double> intervalCol(subtable, "INTERVAL");
3913 0 : ArrayColumn<Float> switchedDiffCol(subtable, "SWITCHED_DIFF");
3914 0 : ArrayColumn<Float> switchedSumCol(subtable, "SWITCHED_SUM");
3915 0 : ArrayColumn<Float> requantizerGainCol(subtable, "REQUANTIZER_GAIN");
3916 :
3917 : // Get original content of columns
3918 0 : Array<Int> antennaId;
3919 0 : if (MSTransformDataHandler::columnOk(antennaIdCol))
3920 0 : antennaId = antennaIdCol.getColumn();
3921 0 : Array<Int> feedId;
3922 0 : if (MSTransformDataHandler::columnOk(feedIdCol))
3923 0 : feedId = feedIdCol.getColumn();
3924 0 : Array<Int> spectralWindowId;
3925 0 : if (MSTransformDataHandler::columnOk(spectralWindowIdCol))
3926 0 : spectralWindowId = spectralWindowIdCol.getColumn();
3927 0 : Array<Double> time;
3928 0 : if (MSTransformDataHandler::columnOk(timeCol))
3929 0 : time = timeCol.getColumn();
3930 0 : Array<Double> interval;
3931 0 : if (MSTransformDataHandler::columnOk(intervalCol))
3932 0 : interval = intervalCol.getColumn();
3933 :
3934 0 : Array<Float> switchedDiff;
3935 0 : if (MSTransformDataHandler::columnOk(switchedDiffCol))
3936 0 : switchedDiff = switchedDiffCol.getColumn();
3937 0 : Array<Float> switchedSum;
3938 0 : if (MSTransformDataHandler::columnOk(switchedSumCol))
3939 0 : switchedSum = switchedSumCol.getColumn();
3940 0 : Array<Float> requantizerGain;
3941 0 : if (MSTransformDataHandler::columnOk(requantizerGainCol))
3942 0 : requantizerGain = requantizerGainCol.getColumn();
3943 :
3944 0 : auto nRowsPerSpw = spectralWindowId.nelements();
3945 0 : auto rowIndex = nRowsPerSpw;
3946 0 : for (uInt spw_i=1; spw_i<nspws_p; spw_i++)
3947 : {
3948 : // Add rows
3949 0 : subtable.addRow(nRowsPerSpw);
3950 :
3951 : // Prepare row reference object
3952 0 : RefRows refRow(rowIndex,rowIndex+nRowsPerSpw-1);
3953 :
3954 : // Re-index SPW col
3955 0 : spectralWindowId = spw_i;
3956 0 : spectralWindowIdCol.putColumnCells(refRow,spectralWindowId);
3957 :
3958 : // Columns that can be just copied
3959 0 : if (MSTransformDataHandler::columnOk(antennaIdCol))
3960 0 : antennaIdCol.putColumnCells(refRow,antennaId);
3961 0 : if (MSTransformDataHandler::columnOk(feedIdCol))
3962 0 : feedIdCol.putColumnCells(refRow,feedId);
3963 0 : if (MSTransformDataHandler::columnOk(timeCol))
3964 0 : timeCol.putColumnCells(refRow,time);
3965 0 : if (MSTransformDataHandler::columnOk(intervalCol))
3966 0 : intervalCol.putColumnCells(refRow,interval);
3967 :
3968 0 : if (MSTransformDataHandler::columnOk(switchedDiffCol))
3969 0 : switchedDiffCol.putColumnCells(refRow,switchedDiff);
3970 0 : if (MSTransformDataHandler::columnOk(switchedSumCol))
3971 0 : switchedSumCol.putColumnCells(refRow,switchedSum);
3972 0 : if (MSTransformDataHandler::columnOk(requantizerGainCol))
3973 0 : requantizerGainCol.putColumnCells(refRow,requantizerGain);
3974 :
3975 : // Increment row offset
3976 0 : rowIndex += nRowsPerSpw;
3977 0 : }
3978 :
3979 0 : }
3980 : else
3981 : {
3982 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3983 0 : << "SYSPOWER sub-table found but has no valid content" << LogIO::POST;
3984 : }
3985 0 : }
3986 : else
3987 : {
3988 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
3989 0 : << "SYSPOWER sub-table not found." << LogIO::POST;
3990 : }
3991 :
3992 0 : return;
3993 : }
3994 :
3995 : // -----------------------------------------------------------------------
3996 : // Return polarization id corresponding to polarization averaged data (Stokes I)
3997 : // Append Polarization row if necessary
3998 : // -----------------------------------------------------------------------
3999 0 : Int MSTransformManager::getAveragedPolarizationId() {
4000 0 : logger_p << LogOrigin("MSTransformManager", __func__, WHERE);
4001 0 : MSPolarizationColumns cols(outputMs_p->polarization());
4002 0 : Int polId = -1;
4003 0 : auto nrow = cols.nrow();
4004 0 : for (rownr_t i = 0; i < nrow; ++i) {
4005 0 : auto const numCorr = cols.numCorr()(i);
4006 0 : auto const flagRow = cols.flagRow()(i);
4007 0 : if (numCorr == 1 && flagRow == False) {
4008 0 : Vector<Int> const corrType = cols.corrType()(i);
4009 0 : Int const corrType0 = corrType[0];
4010 0 : if (Stokes::type(corrType0) == Stokes::I) {
4011 0 : logger_p << "Matched " << i << LogIO::POST;
4012 0 : polId = i;
4013 0 : break;
4014 : }
4015 0 : }
4016 : }
4017 :
4018 0 : if (polId < 0) {
4019 : // add new row to PolarizationTable
4020 0 : outputMs_p->polarization().addRow(1, False);
4021 0 : polId = nrow;
4022 0 : Matrix<Int> corrProduct(2, 1, 0);
4023 0 : cols.corrProduct().put(polId, corrProduct);
4024 0 : Vector<Int> corrType(1, Stokes::I);
4025 0 : cols.corrType().put(polId, corrType);
4026 0 : cols.flagRow().put(polId, False);
4027 0 : cols.numCorr().put(polId, 1);
4028 0 : }
4029 :
4030 0 : return polId;
4031 0 : }
4032 :
4033 : // -----------------------------------------------------------------------
4034 : // Re-index POLARIZATION_ID's in DATA_DESCRIPTION table
4035 : // -----------------------------------------------------------------------
4036 0 : void MSTransformManager::reindexPolarizationIdInDataDesc(Int newPolarizationId) {
4037 0 : logger_p << LogOrigin("MSTransformManager", __func__, WHERE);
4038 0 : logger_p << "new polid is " << newPolarizationId << LogIO::POST;
4039 0 : MSDataDescColumns ddcols(outputMs_p->dataDescription());
4040 0 : MSPolarizationColumns pcols(outputMs_p->polarization());
4041 0 : rownr_t nrow = ddcols.nrow();
4042 0 : auto __isValidType = [&](Vector<Int> const &ctype) {
4043 0 : return (anyEQ(ctype, (Int)Stokes::XX) && anyEQ(ctype, (Int)Stokes::YY))
4044 0 : || (anyEQ(ctype, (Int)Stokes::RR) && anyEQ(ctype, (Int)Stokes::LL));
4045 : };
4046 0 : for (rownr_t i = 0; i < nrow; ++i) {
4047 0 : Int const polarizationId = ddcols.polarizationId()(i);
4048 0 : Int nCorr = pcols.numCorr()(polarizationId);
4049 0 : Vector<Int> corrType = pcols.corrType()(polarizationId);
4050 0 : bool flagRow = pcols.flagRow()(polarizationId);
4051 0 : bool needReindex = (polarizationId != newPolarizationId) &&
4052 0 : (nCorr > 1) && (flagRow == False) && __isValidType(corrType);
4053 0 : if (needReindex) {
4054 0 : logger_p << "ddid " << i << " polid " << polarizationId << " needs reindex" << LogIO::POST;
4055 0 : ddcols.polarizationId().put(i, newPolarizationId);
4056 : }
4057 0 : }
4058 0 : }
4059 :
4060 :
4061 : // -----------------------------------------------------------------------
4062 : //
4063 : // -----------------------------------------------------------------------
4064 0 : void MSTransformManager::checkAndPreaverageChannelsIfNeeded(Int spwId,
4065 : Vector<Double> &inputCHAN_FREQ,
4066 : Vector<Double> &inputCHAN_WIDTH,
4067 :
4068 : const Vector<Double> &originalCHAN_FREQ,
4069 : const Vector<Double> &originalCHAN_WIDTH,
4070 : const Vector<Double> ®riddedCHAN_FREQ,
4071 : const Vector<Double> ®riddedCHAN_WIDTH
4072 : ) {
4073 : // Check if pre-averaging step is necessary
4074 0 : if (freqbinMap_p.find(spwId) == freqbinMap_p.end()) {
4075 : Double weightScaleDummy;
4076 0 : Vector<Double> tmpCHAN_FREQ;
4077 0 : Vector<Double> tmpCHAN_WIDTH;
4078 0 : MSTransformRegridder::calcChanFreqs(logger_p, tmpCHAN_FREQ, tmpCHAN_WIDTH,
4079 : weightScaleDummy, originalCHAN_FREQ,
4080 0 : originalCHAN_WIDTH, phaseCenter_p,
4081 : inputReferenceFrame_p,
4082 0 : referenceTime_p,
4083 0 : observatoryPosition_p,
4084 0 : String("channel"), -1,
4085 0 : String("0"), String("1"),
4086 0 : restFrequency_p,
4087 0 : outputReferenceFramePar_p,
4088 0 : velocityType_p, false // verbose
4089 : );
4090 :
4091 0 : Double avgCombinedWidth = 0;
4092 0 : for (uInt chanIdx = 0; chanIdx < tmpCHAN_WIDTH.size(); ++chanIdx) {
4093 0 : avgCombinedWidth += tmpCHAN_WIDTH(chanIdx);
4094 : }
4095 0 : avgCombinedWidth /= tmpCHAN_WIDTH.size();
4096 :
4097 0 : Double avgRegriddedWidth = 0;
4098 0 : for (uInt chanIdx=0;chanIdx<regriddedCHAN_WIDTH.size();chanIdx++) {
4099 0 : avgRegriddedWidth += regriddedCHAN_WIDTH(chanIdx);
4100 : }
4101 0 : avgRegriddedWidth /= regriddedCHAN_WIDTH.size();
4102 :
4103 0 : Double widthFactor = fabs(avgRegriddedWidth/avgCombinedWidth);
4104 0 : uInt widthFactorInt = (uInt)floor(widthFactor + 0.001);
4105 :
4106 0 : if ((widthFactorInt >= 2) and 2*widthFactorInt <= originalCHAN_WIDTH.size()) {
4107 0 : if (!enableChanPreAverage_p) {
4108 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4109 : << "Ratio between input and output width is >=2: " << avgRegriddedWidth/avgCombinedWidth
4110 : << ", but not doing pre-channel average (it is disabled by "
4111 0 : << "default since CASA release 5.0)." << LogIO::POST;
4112 :
4113 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4114 : << "Regridding to intermediate grid ("
4115 : << originalCHAN_FREQ.size()
4116 : << " channels) for interpolation as in tclean when the "
4117 : << " ratio between the output and input widths is >2."
4118 0 : << LogIO::POST;
4119 :
4120 0 : initGridForRegridTClean(originalCHAN_FREQ, regriddedCHAN_FREQ,
4121 : regriddedCHAN_WIDTH, widthFactor);
4122 :
4123 : } else {
4124 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
4125 : << "mstransform with regridms does not regrid properly for channel widths "
4126 : "> or = 2 x the native channel width, when using channel pre-averaging. Please "
4127 : "use clean or tclean for larger regridding. "
4128 0 : << LogIO::POST;
4129 :
4130 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4131 : << "Ratio between input and output width is " << avgRegriddedWidth/avgCombinedWidth
4132 0 : << ", setting pre-channel average width to " << widthFactorInt << LogIO::POST;
4133 :
4134 0 : doPreAveragingBeforeRegridding(widthFactorInt, spwId,
4135 : originalCHAN_FREQ, originalCHAN_WIDTH,
4136 : inputCHAN_FREQ, inputCHAN_WIDTH);
4137 : }
4138 : }
4139 0 : }
4140 0 : }
4141 :
4142 : // -----------------------------------------------------------------------
4143 : //
4144 : // -----------------------------------------------------------------------
4145 0 : void MSTransformManager::doPreAveragingBeforeRegridding(uInt widthFactor, Int spwId,
4146 : const Vector<Double> &originalCHAN_FREQ,
4147 : const Vector<Double> &originalCHAN_WIDTH,
4148 : Vector<Double> &inputCHAN_FREQ,
4149 : Vector<Double> &inputCHAN_WIDTH) {
4150 0 : channelAverage_p = true;
4151 0 : freqbinMap_p[spwId] = widthFactor;
4152 0 : newWeightFactorMap_p[spwId] /= widthFactor; // jagonzal: Remove channel width contribution to the scale factor
4153 :
4154 : // Calculate averaged frequencies
4155 0 : calculateIntermediateFrequencies(spwId, originalCHAN_FREQ, originalCHAN_WIDTH,
4156 : inputCHAN_FREQ, inputCHAN_WIDTH);
4157 :
4158 0 : ostringstream oss;
4159 0 : oss << "Averaged SPW: " << std::setw(5) << inputCHAN_WIDTH.size()
4160 : << " channels, first channel = "
4161 0 : << std::setprecision(9) << std::setw(14) << std::scientific
4162 0 : << inputCHAN_FREQ(0) << " Hz"
4163 : << ", last channel = "
4164 0 : << std::setprecision(9) << std::setw(14) << std::scientific
4165 0 : << inputCHAN_FREQ(inputCHAN_WIDTH.size() -1) << " Hz";
4166 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4167 0 : << oss.str() << LogIO::POST;
4168 0 : }
4169 :
4170 : // -----------------------------------------------------------------------
4171 : //
4172 : // -----------------------------------------------------------------------
4173 0 : void MSTransformManager::calculateIntermediateFrequencies( Int spwId,
4174 : const Vector<Double> &inputChanFreq,
4175 : const Vector<Double> &inputChanWidth,
4176 : Vector<Double> &intermediateChanFreq,
4177 : Vector<Double> &intermediateChanWidth)
4178 : {
4179 0 : uInt mumOfInterChan = inputChanFreq.size() / freqbinMap_p[spwId];
4180 0 : uInt lastChannelWidth = inputChanFreq.size() % freqbinMap_p[spwId];
4181 0 : if (lastChannelWidth > 0)
4182 : {
4183 0 : mumOfInterChan += 1;
4184 : }
4185 0 : numOfCombInputChanMap_p[spwId] = inputChanFreq.size();
4186 0 : numOfCombInterChanMap_p[spwId] = mumOfInterChan;
4187 0 : intermediateChanFreq.resize(mumOfInterChan,false);
4188 0 : intermediateChanWidth.resize(mumOfInterChan,false);
4189 0 : simpleAverage(freqbinMap_p[spwId], inputChanFreq, intermediateChanFreq);
4190 0 : simpleAverage(freqbinMap_p[spwId], inputChanWidth, intermediateChanWidth);
4191 :
4192 0 : for (uInt chanIdx=0;chanIdx<mumOfInterChan;chanIdx++)
4193 : {
4194 0 : intermediateChanWidth[chanIdx] *= freqbinMap_p[spwId];
4195 : }
4196 :
4197 0 : if (lastChannelWidth > 0)
4198 : {
4199 0 : intermediateChanWidth[mumOfInterChan-1] /= freqbinMap_p[spwId];
4200 0 : intermediateChanWidth[mumOfInterChan-1] *= lastChannelWidth;
4201 : }
4202 :
4203 0 : return;
4204 : }
4205 :
4206 : /**
4207 : * Create a fake grid and create a map [input channels] => [output channels]
4208 : * from it. This is for the tclean-like interpolation that is applied when
4209 : * the width of the output is > 2 x width of the inputs.
4210 : *
4211 : * Irrespective of channel widths, we want as many channels as in the
4212 : * original input, with their (lower) width, but projected/aligned
4213 : * with the output grid. As the output grid is fixed based on the
4214 : * first row timestamp, this only need to be done once, at init time.
4215 : *
4216 : * After this method is run, the interpolation methods can use
4217 : * regridTCleanChanMap_p to interpolate the tclean way.
4218 : *
4219 : * @param originalCHAN_FREQ initial input channel frequencies
4220 : * @param outCHAN_FREQ final output channel frequencies
4221 : * @param outCHAN_WIDTH final output channel widths
4222 : * @param widthFactor avg(output_widths) / avg(input_widths)
4223 : */
4224 0 : void MSTransformManager::initGridForRegridTClean(const Vector<Double> &originalCHAN_FREQ,
4225 : const Vector<Double> &outCHAN_FREQ,
4226 : const Vector<Double> &outCHAN_WIDTH,
4227 : Double widthFactor)
4228 : {
4229 : // build grid with widths of the input channels but aligned with the output
4230 : // grid
4231 0 : regridTCleanCHAN_FREQ_p.resize(originalCHAN_FREQ.size());
4232 0 : Vector<Double> regridTCleanCHAN_WIDTH_p;
4233 0 : regridTCleanCHAN_WIDTH_p.resize(regridTCleanCHAN_FREQ_p.size());
4234 :
4235 0 : const auto &outputFreqs = outCHAN_FREQ;
4236 0 : bool negativeWidths = outputFreqs[0] > outputFreqs[outputFreqs.size()-1];
4237 :
4238 : // swap first/last if "negative width" (decreasing frequencies)
4239 0 : auto startIdx = negativeWidths ? (outCHAN_FREQ.size() -1) : 0;
4240 0 : regridTCleanCHAN_FREQ_p[0] = outCHAN_FREQ[startIdx] - outCHAN_WIDTH[startIdx]/2.;
4241 0 : regridTCleanCHAN_WIDTH_p[0] = outCHAN_WIDTH[startIdx] / widthFactor;
4242 0 : Double widthFactorIdx = static_cast<Double>(regridTCleanCHAN_FREQ_p.size()) /
4243 0 : outCHAN_FREQ.size();
4244 :
4245 0 : for (size_t idx = 1; idx < regridTCleanCHAN_FREQ_p.size(); ++idx) {
4246 0 : Int outIdx = static_cast<Int>(idx / widthFactorIdx);
4247 0 : regridTCleanCHAN_WIDTH_p[idx] = outCHAN_WIDTH[outIdx] / widthFactorIdx;
4248 0 : regridTCleanCHAN_FREQ_p[idx] = regridTCleanCHAN_FREQ_p[idx-1] +
4249 0 : regridTCleanCHAN_WIDTH_p[idx];
4250 : }
4251 :
4252 :
4253 : // Build map from fake input channels => output channels
4254 0 : regridTCleanChanMap_p.resize(regridTCleanCHAN_FREQ_p.size());
4255 0 : regridTCleanChanMap_p = -1;
4256 0 : const auto &intermFreqs = regridTCleanCHAN_FREQ_p;
4257 0 : const auto &outputWidths = outCHAN_WIDTH;
4258 0 : for (uInt mapIdx = 0; mapIdx < regridTCleanChanMap_p.size(); ++mapIdx) {
4259 0 : for (uInt outIdx = 0; outIdx < outputFreqs.size(); ++outIdx) {
4260 0 : if (intermFreqs[mapIdx] >= outputFreqs[outIdx] - outputWidths[outIdx]/2. and
4261 0 : intermFreqs[mapIdx] < outputFreqs[outIdx] + outputWidths[outIdx]/2.) {
4262 0 : regridTCleanChanMap_p(mapIdx) = outIdx;
4263 0 : break;
4264 : }
4265 : }
4266 : }
4267 0 : regridTClean_p = true;
4268 0 : }
4269 :
4270 : // -----------------------------------------------------------------------
4271 : // Method to set all the elements of a scalar column to a given value
4272 : // -----------------------------------------------------------------------
4273 0 : void MSTransformManager::reindexColumn(ScalarColumn<Int> &inputCol, Int value)
4274 : {
4275 0 : for(rownr_t idx=0; idx<inputCol.nrow(); idx++)
4276 : {
4277 0 : inputCol.put(idx,value);
4278 : }
4279 :
4280 0 : return;
4281 : }
4282 :
4283 : // -----------------------------------------------------------------------
4284 : // Method to re-index Spectral Window column in Source sub-table
4285 : // -----------------------------------------------------------------------
4286 0 : void MSTransformManager::reindexSourceSubTable()
4287 : {
4288 0 : if(Table::isReadable(outputMs_p->sourceTableName()) and !outputMs_p->source().isNull())
4289 : {
4290 :
4291 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4292 0 : << "Re-indexing SOURCE sub-table" << LogIO::POST;
4293 :
4294 :
4295 0 : MSSource sourceSubtable = outputMs_p->source();
4296 0 : MSSourceColumns tableCols(sourceSubtable);
4297 0 : ScalarColumn<Int> spectralWindowId = tableCols.spectralWindowId();
4298 0 : ScalarColumn<Int> sourceId = tableCols.sourceId();
4299 0 : reindexColumn(spectralWindowId,0);
4300 :
4301 : // Remove duplicates
4302 0 : std::vector<rownr_t> duplicateIdx;
4303 0 : std::vector< std::pair<uInt,uInt> > sourceIdSpwIdMap;
4304 :
4305 0 : for (rownr_t idx = 0; idx < spectralWindowId.nrow(); idx++)
4306 : {
4307 0 : std::pair<uInt,uInt> sourceIdSpwId = std::make_pair(spectralWindowId(idx),sourceId(idx));
4308 :
4309 0 : if (std::find(sourceIdSpwIdMap.begin(),sourceIdSpwIdMap.end(),sourceIdSpwId) != sourceIdSpwIdMap.end())
4310 : {
4311 0 : duplicateIdx.push_back(idx);
4312 : }
4313 : else
4314 : {
4315 0 : sourceIdSpwIdMap.push_back(sourceIdSpwId);
4316 : }
4317 : }
4318 :
4319 0 : sourceSubtable.removeRow(Vector<rownr_t>(duplicateIdx.begin(),duplicateIdx.end()));
4320 :
4321 0 : }
4322 : else
4323 : {
4324 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
4325 0 : << "SOURCE sub-table not found " << LogIO::POST;
4326 : }
4327 :
4328 0 : return;
4329 : }
4330 :
4331 : // -----------------------------------------------------------------------
4332 : // Method to re-index Spectral Window column in DDI sub-table
4333 : // -----------------------------------------------------------------------
4334 0 : void MSTransformManager::reindexDDISubTable()
4335 : {
4336 0 : if(Table::isReadable(outputMs_p->dataDescriptionTableName()) and !outputMs_p->dataDescription().isNull())
4337 : {
4338 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4339 0 : << "Re-indexing DDI sub-table" << LogIO::POST;
4340 :
4341 : // Access DDI sub-table
4342 0 : MSDataDescription ddiTable = outputMs_p->dataDescription();
4343 0 : MSDataDescColumns ddiCols(ddiTable);
4344 :
4345 : // Add a new row for each of the separated SPWs
4346 0 : uInt rowIndex = 0;
4347 0 : for (uInt spw_i=0; spw_i<nspws_p; spw_i++)
4348 : {
4349 0 : if (rowIndex > 0)
4350 : {
4351 : // Add row
4352 0 : ddiTable.addRow(1,true);
4353 :
4354 : // Copy polID and flagRow from the first original SPW
4355 0 : ddiCols.polarizationId().put(rowIndex,ddiCols.polarizationId()(0));
4356 0 : ddiCols.flagRow().put(rowIndex,ddiCols.flagRow()(0));
4357 :
4358 : // Optional columns
4359 0 : if (ddiCols.lagId().isNull()==false and ddiCols.lagId().hasContent()==true)
4360 : {
4361 0 : ddiCols.lagId().put(rowIndex,ddiCols.lagId()(0));
4362 : }
4363 : }
4364 :
4365 : // Set SPW id separately
4366 0 : ddiCols.spectralWindowId().put(rowIndex,ddiStart_p+spw_i);
4367 :
4368 0 : rowIndex += 1;
4369 : }
4370 :
4371 : // Delete the old rows
4372 0 : rownr_t nrowsToDelete = ddiCols.nrow()-nspws_p;
4373 0 : if (nrowsToDelete > 0)
4374 : {
4375 0 : rownr_t rownr = ddiCols.nrow()-1;
4376 0 : Vector<rownr_t> rowsToDelete(nrowsToDelete);
4377 0 : for(rownr_t idx=0; idx<nrowsToDelete; idx++)
4378 : {
4379 0 : rowsToDelete(idx) = rownr;
4380 0 : rownr -= 1;
4381 : }
4382 :
4383 0 : ddiTable.removeRow(rowsToDelete);
4384 0 : }
4385 :
4386 :
4387 0 : }
4388 : else
4389 : {
4390 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
4391 0 : << "DATA_DESCRIPTION sub-table not found " << LogIO::POST;
4392 : }
4393 0 : }
4394 :
4395 : // -----------------------------------------------------------------------
4396 : // Method to re-index Spectral Window column in Feed sub-table
4397 : // -----------------------------------------------------------------------
4398 0 : void MSTransformManager::reindexFeedSubTable()
4399 : {
4400 0 : if(Table::isReadable(outputMs_p->feedTableName()) and !outputMs_p->feed().isNull())
4401 : {
4402 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4403 0 : << "Re-indexing FEED sub-table and removing duplicates" << LogIO::POST;
4404 :
4405 0 : MSFeed feedSubtable = outputMs_p->feed();
4406 0 : MSFeedColumns tableCols(feedSubtable);
4407 0 : ScalarColumn<Int> feedId = tableCols.feedId();
4408 0 : ScalarColumn<Int> antennaId = tableCols.antennaId();
4409 0 : ScalarColumn<Int> spectralWindowId = tableCols.spectralWindowId();
4410 0 : ScalarColumn<Double> time = tableCols.time();
4411 :
4412 : // Re-index SPWId to be 0
4413 0 : reindexColumn(spectralWindowId,0);
4414 :
4415 : // Remove duplicates
4416 0 : std::vector<rownr_t> duplicateIdx;
4417 0 : std::map< std::pair<uInt,uInt> , Double > antennaFeedTimeMap;
4418 0 : std::map< std::pair<uInt,uInt> , Double >::iterator antennaFeedTimeIter;
4419 :
4420 0 : for (rownr_t idx = 0; idx < spectralWindowId.nrow(); idx++)
4421 : {
4422 0 : std::pair<uInt,uInt> antennaFeedPair = std::make_pair(antennaId(idx),feedId(idx));
4423 0 : antennaFeedTimeIter = antennaFeedTimeMap.find(antennaFeedPair);
4424 :
4425 0 : if (antennaFeedTimeIter != antennaFeedTimeMap.end())
4426 : {
4427 0 : if (abs(antennaFeedTimeIter->second - time(idx)) < 2*FLT_MIN)
4428 : {
4429 0 : duplicateIdx.push_back(idx);
4430 : }
4431 : else
4432 : {
4433 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4434 : }
4435 : }
4436 : else
4437 : {
4438 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4439 : }
4440 : }
4441 :
4442 :
4443 0 : feedSubtable.removeRow(Vector<rownr_t>(duplicateIdx.begin(),duplicateIdx.end()));
4444 :
4445 0 : }
4446 : else
4447 : {
4448 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__) <<
4449 0 : "FEED sub-table not found " << LogIO::POST;
4450 : }
4451 :
4452 0 : return;
4453 : }
4454 :
4455 : // -----------------------------------------------------------------------
4456 : // Method to re-index Spectral Window column in SysCal sub-table
4457 : // -----------------------------------------------------------------------
4458 0 : void MSTransformManager::reindexSysCalSubTable()
4459 : {
4460 0 : if(Table::isReadable(outputMs_p->sysCalTableName()) and !outputMs_p->sysCal().isNull())
4461 : {
4462 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4463 0 : << "Re-indexing SYSCAL sub-table and removing duplicates" << LogIO::POST;
4464 :
4465 0 : MSSysCal syscalSubtable = outputMs_p->sysCal();
4466 0 : MSSysCalColumns tableCols(syscalSubtable);
4467 0 : ScalarColumn<Int> feedId = tableCols.feedId();
4468 0 : ScalarColumn<Int> antennaId = tableCols.antennaId();
4469 0 : ScalarColumn<Int> spectralWindowId = tableCols.spectralWindowId();
4470 0 : ScalarColumn<Double> time = tableCols.time();
4471 :
4472 : // Re-index SPWId to be 0
4473 0 : reindexColumn(spectralWindowId,0);
4474 :
4475 : // Remove duplicates
4476 0 : std::vector<rownr_t> duplicateIdx;
4477 0 : std::map< std::pair<uInt,uInt> , Double > antennaFeedTimeMap;
4478 0 : std::map< std::pair<uInt,uInt> , Double >::iterator antennaFeedTimeIter;
4479 :
4480 0 : for (rownr_t idx = 0; idx < spectralWindowId.nrow(); idx++)
4481 : {
4482 0 : std::pair<uInt,uInt> antennaFeedPair = std::make_pair(antennaId(idx),feedId(idx));
4483 0 : antennaFeedTimeIter = antennaFeedTimeMap.find(antennaFeedPair);
4484 :
4485 0 : if (antennaFeedTimeIter != antennaFeedTimeMap.end())
4486 : {
4487 0 : if (abs(antennaFeedTimeIter->second - time(idx)) < 2*FLT_MIN)
4488 : {
4489 0 : duplicateIdx.push_back(idx);
4490 : }
4491 : else
4492 : {
4493 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4494 : }
4495 : }
4496 : else
4497 : {
4498 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4499 : }
4500 : }
4501 :
4502 0 : syscalSubtable.removeRow(Vector<rownr_t>(duplicateIdx.begin(),duplicateIdx.end()));
4503 :
4504 0 : }
4505 : else
4506 : {
4507 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
4508 0 : << "SYSCAL sub-table not found " << LogIO::POST;
4509 : }
4510 :
4511 0 : return;
4512 : }
4513 :
4514 : // -----------------------------------------------------------------------
4515 : // Method to re-index Spectral Window column in FreqOffset sub-table
4516 : // -----------------------------------------------------------------------
4517 0 : void MSTransformManager::reindexFreqOffsetSubTable()
4518 : {
4519 0 : if(Table::isReadable(outputMs_p->freqOffsetTableName()) and !outputMs_p->freqOffset().isNull())
4520 : {
4521 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4522 0 : << "Re-indexing FREQ_OFFSET sub-table and removing duplicates" << LogIO::POST;
4523 :
4524 0 : MSFreqOffset freqoffsetSubtable = outputMs_p->freqOffset();
4525 0 : MSFreqOffsetColumns tableCols(freqoffsetSubtable);
4526 0 : ScalarColumn<Int> feedId = tableCols.feedId();
4527 0 : ScalarColumn<Int> antenna1 = tableCols.antenna1();
4528 0 : ScalarColumn<Int> antenna2 = tableCols.antenna2();
4529 0 : ScalarColumn<Int> spectralWindowId = tableCols.spectralWindowId();
4530 0 : ScalarColumn<Double> time = tableCols.time();
4531 :
4532 : // Re-index SPWId to be 0
4533 0 : reindexColumn(spectralWindowId,0);
4534 :
4535 : // Remove duplicates
4536 0 : std::vector<rownr_t> duplicateIdx;
4537 0 : std::map< std::pair < std::pair<uInt,uInt> , uInt> , Double > antennaFeedTimeMap;
4538 0 : std::map< std::pair < std::pair<uInt,uInt> , uInt> , Double >::iterator antennaFeedTimeIter;
4539 :
4540 0 : for (rownr_t idx = 0; idx < spectralWindowId.nrow(); idx++)
4541 : {
4542 0 : std::pair < std::pair<uInt,uInt> , uInt> antennaFeedPair = std::make_pair(std::make_pair(antenna1(idx),antenna2(idx)),feedId(idx));
4543 0 : antennaFeedTimeIter = antennaFeedTimeMap.find(antennaFeedPair);
4544 :
4545 0 : if (antennaFeedTimeIter != antennaFeedTimeMap.end())
4546 : {
4547 0 : if (abs(antennaFeedTimeIter->second - time(idx)) < 2*FLT_MIN)
4548 : {
4549 0 : duplicateIdx.push_back(idx);
4550 : }
4551 : else
4552 : {
4553 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4554 : }
4555 : }
4556 : else
4557 : {
4558 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4559 : }
4560 : }
4561 :
4562 0 : freqoffsetSubtable.removeRow(Vector<rownr_t>(duplicateIdx.begin(),duplicateIdx.end()));
4563 :
4564 0 : }
4565 : else
4566 : {
4567 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
4568 0 : << "FREQ_OFFSET sub-table not found " << LogIO::POST;
4569 : }
4570 :
4571 0 : return;
4572 : }
4573 :
4574 : // -----------------------------------------------------------------------
4575 : // Method to re-index Spectral Window column in a generic sub-table (with feedId, antennaId and time columns)
4576 : // -----------------------------------------------------------------------
4577 0 : void MSTransformManager::reindexGenericTimeDependentSubTable(const String& subtabname)
4578 : {
4579 0 : if (Table::isReadable(outputMs_p->tableName() + "/" + subtabname))
4580 : {
4581 0 : Table subtable(outputMs_p->tableName() + "/" + subtabname, Table::Update);
4582 :
4583 0 : if (subtable.nrow() > 0)
4584 : {
4585 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4586 : << "Re-indexing SPW column of " << subtabname
4587 0 : << " sub-table and removing duplicates " << LogIO::POST;
4588 :
4589 0 : ScalarColumn<Int> feedId(subtable, "FEED_ID");
4590 0 : ScalarColumn<Int> antennaId(subtable, "ANTENNA_ID");
4591 0 : ScalarColumn<Int> spectralWindowId(subtable, "SPECTRAL_WINDOW_ID");
4592 0 : ScalarColumn<Double> time(subtable, "TIME");
4593 :
4594 : // Re-index SPWId to be 0
4595 0 : reindexColumn(spectralWindowId,0);
4596 :
4597 : // Remove duplicates
4598 0 : std::vector<rownr_t> duplicateIdx;
4599 0 : std::map< std::pair<uInt,uInt> , Double > antennaFeedTimeMap;
4600 0 : std::map< std::pair<uInt,uInt> , Double >::iterator antennaFeedTimeIter;
4601 :
4602 0 : for (rownr_t idx = 0; idx < spectralWindowId.nrow(); idx++)
4603 : {
4604 0 : std::pair<uInt,uInt> antennaFeedPair = std::make_pair(antennaId(idx),feedId(idx));
4605 0 : antennaFeedTimeIter = antennaFeedTimeMap.find(antennaFeedPair);
4606 :
4607 0 : if (antennaFeedTimeIter != antennaFeedTimeMap.end())
4608 : {
4609 0 : if (abs(antennaFeedTimeIter->second - time(idx)) < 2*FLT_MIN)
4610 : {
4611 0 : duplicateIdx.push_back(idx);
4612 : }
4613 : else
4614 : {
4615 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4616 : }
4617 : }
4618 : else
4619 : {
4620 0 : antennaFeedTimeMap[antennaFeedPair] = time(idx);
4621 : }
4622 : }
4623 :
4624 0 : subtable.removeRow(Vector<rownr_t>(duplicateIdx.begin(),duplicateIdx.end()));
4625 :
4626 0 : }
4627 : else
4628 : {
4629 0 : if (subtabname == casacore::String("FEED"))
4630 : {
4631 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
4632 0 : << subtabname << " sub-table found but has no valid content" << LogIO::POST;
4633 : }
4634 : else
4635 : {
4636 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
4637 0 : << subtabname << " sub-table found but has no valid content" << LogIO::POST;
4638 : }
4639 : }
4640 0 : }
4641 : else
4642 : {
4643 0 : if (subtabname == casacore::String("FEED"))
4644 : {
4645 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
4646 0 : << subtabname << " sub-table not found" << LogIO::POST;
4647 : }
4648 : else
4649 : {
4650 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager", __FUNCTION__)
4651 0 : << subtabname << " sub-table not found" << LogIO::POST;
4652 : }
4653 : }
4654 :
4655 0 : return;
4656 : }
4657 :
4658 : // -----------------------------------------------------------------------
4659 : //
4660 : // -----------------------------------------------------------------------
4661 35 : void MSTransformManager::getInputNumberOfChannels()
4662 : {
4663 : // Access spectral window sub-table
4664 35 : MSSpectralWindow spwTable = inputMs_p->spectralWindow();
4665 35 : auto nInputSpws = spwTable.nrow();
4666 35 : MSSpWindowColumns spwCols(spwTable);
4667 35 : ScalarColumn<Int> numChanCol = spwCols.numChan();
4668 :
4669 : // Get number of output channels per input spw
4670 116 : for(rownr_t spw_idx=0; spw_idx<nInputSpws; spw_idx++)
4671 : {
4672 81 : numOfInpChanMap_p[spw_idx] = numChanCol(spw_idx);
4673 : }
4674 :
4675 70 : return;
4676 35 : }
4677 :
4678 : // -----------------------------------------------------------------------
4679 : //
4680 : // -----------------------------------------------------------------------
4681 17 : void MSTransformManager::dropNonUniformWidthChannels()
4682 : {
4683 : // Access spectral window sub-table
4684 17 : MSSpectralWindow spwTable = outputMs_p->spectralWindow();
4685 17 : auto nInputSpws = spwTable.nrow();
4686 17 : MSSpWindowColumns spwCols(spwTable);
4687 17 : ArrayColumn<Double> chanFreqCol = spwCols.chanFreq();
4688 17 : ArrayColumn<Double> chanWidthCol = spwCols.chanWidth();
4689 17 : ArrayColumn<Double> effectiveBWCol = spwCols.effectiveBW();
4690 17 : ArrayColumn<Double> resolutionCol = spwCols.resolution();
4691 17 : ScalarColumn<Int> numChanCol = spwCols.numChan();
4692 17 : ScalarColumn<Double> totalBandwidthCol = spwCols.totalBandwidth();
4693 :
4694 : uInt nChans;
4695 : Int spwId;
4696 36 : for(rownr_t spw_idx=0; spw_idx<nInputSpws; spw_idx++)
4697 : {
4698 19 : nChans = numChanCol(spw_idx);
4699 19 : Vector<Double> widthVector = chanWidthCol(spw_idx);
4700 :
4701 19 : if (outputInputSPWIndexMap_p.size()>0)
4702 : {
4703 3 : spwId = outputInputSPWIndexMap_p[spw_idx];
4704 : }
4705 : else
4706 : {
4707 16 : spwId = spw_idx;
4708 : }
4709 :
4710 : // Skip this SPW in non-reindex mode
4711 19 : if ((!reindex_p) and (numOfSelChanMap_p.find(spwId) == numOfSelChanMap_p.end())) continue;
4712 :
4713 : //logger_p << dataHandler_p->getDroppedChannelsMap() << LogIO::POST;
4714 :
4715 19 : if (dataHandler_p->getDroppedChannelsMap().find(spwId) != dataHandler_p->getDroppedChannelsMap().end())
4716 : {
4717 0 : vector<Int>::iterator iter;
4718 0 : Double droppedWidth = 0;
4719 0 : vector<Int> &droppedChannels = dataHandler_p->getDroppedChannelsMap()[spwId];
4720 0 : for (iter = droppedChannels.begin(); iter != droppedChannels.end(); iter++)
4721 : {
4722 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
4723 : << "Not enough input channels to populate output channel n# "
4724 0 : << *iter << " from SPW " << spwId << "." << endl
4725 : << "The channel will be dropped in order to have an uniform grid."
4726 0 : << LogIO::POST;
4727 :
4728 0 : droppedWidth += widthVector(*iter);
4729 : }
4730 :
4731 : // Calculate final number of channels
4732 0 : uInt nChansFinal = nChans-droppedChannels.size();
4733 :
4734 0 : if (nChansFinal <= 0)
4735 : {
4736 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
4737 : << "Channel selection does not allow to produce any output channel with the requested width "
4738 0 : << LogIO::POST;
4739 :
4740 0 : throw AipsError("Channel selection does not allow to produce any output channel with the requested width ");
4741 : }
4742 :
4743 :
4744 :
4745 0 : numChanCol.put(spw_idx, nChansFinal);
4746 :
4747 : // Total BW has to be reduced to account for the dropped channels
4748 0 : totalBandwidthCol.put(spw_idx, totalBandwidthCol(spw_idx)-droppedWidth);
4749 :
4750 : // Get current vectors
4751 0 : Vector<Double> effectiveBWVector = effectiveBWCol(spw_idx);
4752 0 : Vector<Double> resolutionVector = resolutionCol(spw_idx);
4753 0 : Vector<Double> frequencyVector = chanFreqCol(spw_idx);
4754 :
4755 : // Declare new vectors
4756 0 : Vector<Double> newWidthVector(nChansFinal);
4757 0 : Vector<Double> newEffectiveBWVector(nChansFinal);
4758 0 : Vector<Double> newResolutionVector(nChansFinal);
4759 0 : Vector<Double> newFrequencyVector(nChansFinal);
4760 :
4761 : // Create a new frequency vector
4762 0 : uInt finalIdx = 0;
4763 0 : vector<Int>::iterator matchIdx;
4764 0 : for (uInt idx=0;idx < widthVector.size(); idx++)
4765 : {
4766 0 : matchIdx = find (droppedChannels.begin(), droppedChannels.end(), idx);
4767 0 : if (matchIdx == droppedChannels.end() )
4768 : {
4769 0 : newWidthVector(finalIdx) = widthVector(idx);
4770 0 : newEffectiveBWVector(finalIdx) = effectiveBWVector(idx);
4771 0 : newResolutionVector(finalIdx) = resolutionVector(idx);
4772 0 : newFrequencyVector(finalIdx) = frequencyVector(idx);
4773 0 : finalIdx ++;
4774 : }
4775 : }
4776 :
4777 : // Put new vectors in corresponding columns
4778 0 : chanWidthCol.put(spw_idx, newWidthVector);
4779 0 : effectiveBWCol.put(spw_idx, newEffectiveBWVector);
4780 0 : resolutionCol.put(spw_idx, newResolutionVector);
4781 0 : chanFreqCol.put(spw_idx, newFrequencyVector);
4782 :
4783 : // Update output number of channels
4784 0 : if (regridding_p) inputOutputSpwMap_p[spw_idx].second.resize(nChansFinal);
4785 0 : }
4786 19 : }
4787 :
4788 34 : return;
4789 17 : }
4790 :
4791 :
4792 : // -----------------------------------------------------------------------
4793 : //
4794 : // -----------------------------------------------------------------------
4795 17 : void MSTransformManager::getOutputNumberOfChannels()
4796 : {
4797 17 : if (regridding_p or combinespws_p)
4798 : {
4799 0 : map<uInt,uInt>::iterator iter;
4800 0 : for(iter = numOfSelChanMap_p.begin(); iter != numOfSelChanMap_p.end(); iter++)
4801 : {
4802 0 : if (freqbinMap_p.find(iter->first) == freqbinMap_p.end())
4803 : {
4804 : // When doing only re-gridding, maybe not all SPWs require pre-averaging
4805 0 : if (not combinespws_p)
4806 : {
4807 0 : freqbinMap_p[iter->first] = 1;
4808 : }
4809 : // When combining SPWs all of them get the same freqbin
4810 : else
4811 : {
4812 0 : freqbinMap_p[iter->first] = freqbinMap_p[0];
4813 : }
4814 : }
4815 : }
4816 : }
4817 :
4818 : // Access spectral window sub-table
4819 17 : MSSpectralWindow spwTable = outputMs_p->spectralWindow();
4820 17 : auto nInputSpws = spwTable.nrow();
4821 17 : MSSpWindowColumns spwCols(spwTable);
4822 17 : ScalarColumn<Int> numChanCol = spwCols.numChan();
4823 17 : ArrayColumn<Double> chanFreqCol = spwCols.chanFreq();
4824 :
4825 17 : if (combinespws_p)
4826 : {
4827 0 : map<uInt,uInt>::iterator iter;
4828 0 : for(iter = numOfSelChanMap_p.begin(); iter != numOfSelChanMap_p.end(); iter++)
4829 : {
4830 : // Note: This will truncate the result, but it is ok because we are dropping the last channel
4831 0 : numOfOutChanMap_p[iter->first] = numOfSelChanMap_p[iter->first] / freqbinMap_p[iter->first];
4832 : }
4833 : }
4834 : else
4835 : {
4836 : // Get number of output channels per input spw
4837 : Int spwId;
4838 36 : for(rownr_t spw_idx=0; spw_idx<nInputSpws; spw_idx++)
4839 : {
4840 19 : if (outputInputSPWIndexMap_p.size()>0)
4841 : {
4842 3 : spwId = outputInputSPWIndexMap_p[spw_idx];
4843 : }
4844 : else
4845 : {
4846 16 : spwId = spw_idx;
4847 : }
4848 :
4849 19 : numOfOutChanMap_p[spwId] = numChanCol(spw_idx);
4850 : }
4851 : }
4852 :
4853 34 : return;
4854 17 : }
4855 :
4856 : // -----------------------------------------------------------------------
4857 : //
4858 : // -----------------------------------------------------------------------
4859 0 : void MSTransformManager::calculateWeightAndSigmaFactors()
4860 : {
4861 0 : map<uInt,uInt>::iterator iter;
4862 0 : for(iter = numOfSelChanMap_p.begin(); iter != numOfSelChanMap_p.end(); iter++)
4863 : {
4864 0 : weightFactorMap_p[iter->first] = (Float)numOfSelChanMap_p[iter->first] /
4865 0 : (Float)numOfInpChanMap_p[iter->first];
4866 0 : sigmaFactorMap_p[iter->first] = 1./sqrt((Float)numOfSelChanMap_p[iter->first] /
4867 0 : (Float)numOfOutChanMap_p[iter->first]);
4868 : }
4869 :
4870 0 : return;
4871 : }
4872 :
4873 : // -----------------------------------------------------------------------
4874 : //
4875 : // -----------------------------------------------------------------------
4876 17 : void MSTransformManager::calculateNewWeightAndSigmaFactors()
4877 : {
4878 :
4879 17 : map<uInt, uInt>::iterator iter;
4880 36 : for (iter = numOfSelChanMap_p.begin(); iter != numOfSelChanMap_p.end(); iter++)
4881 : {
4882 : // Populateremaining SPWs of weight factor map
4883 19 : if (newWeightFactorMap_p.find(iter->first)== newWeightFactorMap_p.end())
4884 : {
4885 : // When doing only re-gridding, maybe not all SPWs require pre-averaging
4886 0 : if (not combinespws_p)
4887 : {
4888 0 : newWeightFactorMap_p[iter->first] = 1;
4889 : }
4890 : // When combining SPWs all of them get the same freqbin
4891 : else
4892 : {
4893 0 : newWeightFactorMap_p[iter->first] = newWeightFactorMap_p[0];
4894 : }
4895 : }
4896 :
4897 : // Populate sigma factor map
4898 19 : newSigmaFactorMap_p[iter->first] = 1 / sqrt(newWeightFactorMap_p[iter->first]);
4899 : }
4900 :
4901 34 : return;
4902 : }
4903 :
4904 : // -----------------------------------------------------------------------
4905 : // Method to check if flag category has to be filled
4906 : // -----------------------------------------------------------------------
4907 35 : void MSTransformManager::checkFillFlagCategory()
4908 : {
4909 35 : inputFlagCategoryAvailable_p = false;
4910 35 : if ( !selectedInputMsCols_p->flagCategory().isNull()
4911 35 : && selectedInputMsCols_p->flagCategory().isDefined(0)
4912 105 : && selectedInputMsCols_p->flagCategory()(0).shape() == 3)
4913 : {
4914 0 : inputFlagCategoryAvailable_p = true;
4915 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4916 0 : << "Optional column FLAG_CATEGORY found in input MS will be written to output MS" << LogIO::POST;
4917 : }
4918 :
4919 35 : return;
4920 : }
4921 :
4922 : // -----------------------------------------------------------------------
4923 : // Method to check if weight spectrum column has to be filled
4924 : // -----------------------------------------------------------------------
4925 35 : void MSTransformManager::checkFillWeightSpectrum()
4926 : {
4927 35 : inputWeightSpectrumAvailable_p = false;
4928 38 : if (!selectedInputMsCols_p->weightSpectrum().isNull() and
4929 3 : selectedInputMsCols_p->weightSpectrum().isDefined(0))
4930 : {
4931 0 : inputWeightSpectrumAvailable_p = true;
4932 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
4933 0 : << "Optional column WEIGHT_SPECTRUM found in input MS will be written to output MS" << LogIO::POST;
4934 : }
4935 35 : }
4936 :
4937 : /**
4938 : * Early check for a potential issue that would prevent an MSTransform
4939 : * setup which looks in principle fine from running correctly. Ensures
4940 : * that we catch a current limitation in the underlying iterators /
4941 : * VI/VB2 framework whereby combinespws won't work when the number of
4942 : * channels is different for different SPWs.
4943 : *
4944 : * Requires that numOfInpChanMap_p be populated previously (in
4945 : * getInputNumberOfChannels()).
4946 : *
4947 : * @throws AipsError if combinespws is enabled and the input MS of the
4948 : * current configuration has different number of channels for
4949 : * different SPWs
4950 : */
4951 35 : void MSTransformManager::checkSPWChannelsKnownLimitation()
4952 : {
4953 35 : if (not combinespws_p)
4954 35 : return;
4955 :
4956 0 : auto nSpws = inputMs_p->spectralWindow().nrow();
4957 0 : if (1 >= nSpws or numOfInpChanMap_p.empty() or numOfSelChanMap_p.empty())
4958 0 : return;
4959 :
4960 0 : auto firstNum = numOfSelChanMap_p.begin()->second;
4961 0 : auto diff = std::find_if(numOfSelChanMap_p.begin(), numOfSelChanMap_p.end(),
4962 0 : [&firstNum](const std::pair<casacore::uInt,casacore::uInt> &other) {
4963 0 : return firstNum != other.second; });
4964 :
4965 :
4966 0 : if (numOfSelChanMap_p.end() != diff) {
4967 0 : auto otherNum = diff->second;
4968 0 : throw AipsError("Currently the option 'combinespws' is only supported when the number "
4969 : "of channels is the same for all the spw's selected. One of the SPWs "
4970 0 : "selected has " + std::to_string(firstNum) + " channels, but another "
4971 0 : "selected SPW has " + std::to_string(otherNum) + " channels.");
4972 : }
4973 : }
4974 :
4975 : /**
4976 : * Early check to issue a warning if the data was preaveraged
4977 : * by the correlator ans we are performing a further
4978 : * smoothing and average.
4979 : */
4980 35 : void MSTransformManager::checkCorrelatorPreaveraging()
4981 : {
4982 35 : std::string spwPreaveraged;
4983 35 : if (hanningSmooth_p || channelAverage_p)
4984 : {
4985 17 : auto spwTable = inputMs_p->spectralWindow();
4986 17 : MSSpWindowColumns spwColumns(spwTable);
4987 34 : if (spwTable.tableDesc().isColumn("SDM_WINDOW_FUNCTION") &&
4988 17 : spwTable.tableDesc().columnDescSet().isDefined("SDM_WINDOW_FUNCTION") &&
4989 51 : spwTable.tableDesc().isColumn("SDM_NUM_BIN") &&
4990 17 : spwTable.tableDesc().columnDescSet().isDefined("SDM_NUM_BIN"))
4991 : {
4992 0 : auto nrows = spwColumns.nrow();
4993 0 : auto effBWCol = spwColumns.effectiveBW();
4994 0 : auto chanWidthCol = spwColumns.chanWidth();
4995 0 : ScalarColumn<String> windowFunctionCol(spwTable, "SDM_WINDOW_FUNCTION");
4996 0 : ScalarColumn<Int> numBinCol(spwTable, "SDM_NUM_BIN");
4997 0 : for (size_t spwIdx = 0; spwIdx < nrows; spwIdx++)
4998 : {
4999 0 : auto numBin = numBinCol(spwIdx);
5000 0 : auto windowFunction = windowFunctionCol(spwIdx);
5001 0 : if(windowFunction != "UNKNOWN" && numBin != 1)
5002 0 : spwPreaveraged += std::to_string(spwIdx)+" ";
5003 0 : }
5004 0 : }
5005 17 : }
5006 :
5007 35 : if(spwPreaveraged != "")
5008 0 : logger_p << LogIO::WARN<<LogOrigin("MSTransformManager", __func__) <<
5009 : "The data has already been preaveraged by the correlator but "
5010 : "further smoothing or averaging has been requested. "
5011 0 : "Preaveraged SPWs are: "<<spwPreaveraged<<LogIO::POST;
5012 35 : }
5013 :
5014 : // -----------------------------------------------------------------------
5015 : //
5016 : // -----------------------------------------------------------------------
5017 35 : void MSTransformManager::checkDataColumnsAvailable()
5018 : {
5019 35 : dataColumnAvailable_p = false;
5020 35 : correctedDataColumnAvailable_p = false;
5021 35 : modelDataColumnAvailable_p = false;
5022 :
5023 :
5024 35 : floatDataColumnAvailable_p = false;
5025 35 : lagDataColumnAvailable_p = false;
5026 :
5027 :
5028 : // DATA
5029 35 : if (inputMs_p->tableDesc().isColumn(MS::columnName(MS::DATA)))
5030 : {
5031 35 : dataColumnAvailable_p = true;
5032 : }
5033 :
5034 :
5035 : // CORRECTED_DATA already exists in the input MS
5036 35 : if (inputMs_p->tableDesc().isColumn(MS::columnName(MS::CORRECTED_DATA)))
5037 : {
5038 6 : correctedDataColumnAvailable_p = true;
5039 : }
5040 : // CORRECTED_DATA does not exist but there is a calibration parameter set available
5041 29 : else if (calibrate_p and (makeVirtualCorrectedColReal_p or bufferMode_p))
5042 : {
5043 0 : correctedDataColumnAvailable_p = true;
5044 : }
5045 : // There is no calibration parameter set available
5046 : else
5047 : {
5048 : // TODO: Inform that virtual CORRECTED_DATA is not available
5049 :
5050 : // Unset makeVirtualModelColReal_p as virtual CORRECTED col. is not available
5051 29 : makeVirtualCorrectedColReal_p = false;
5052 : }
5053 :
5054 : // FLOAT_DATA
5055 35 : if (inputMs_p->tableDesc().isColumn(MS::columnName(MS::FLOAT_DATA)))
5056 : {
5057 0 : floatDataColumnAvailable_p = true;
5058 : }
5059 :
5060 :
5061 : // MODEL_DATA already exists in the input MS
5062 35 : if (inputMs_p->tableDesc().isColumn(MS::columnName(MS::MODEL_DATA)))
5063 : {
5064 6 : modelDataColumnAvailable_p = true;
5065 : }
5066 : // MODEL_DATA does not exist but there is a model available in the SOURCE sub-table
5067 : // MODEL_DATA should not be made real if the user does not specify it implicitly
5068 29 : else if (inputMs_p->source().isColumn(MSSource::SOURCE_MODEL) and makeVirtualModelColReal_p)
5069 : {
5070 0 : modelDataColumnAvailable_p = true;
5071 : }
5072 : // CAS-7390: Provide default MODEL_DATA in buffer mode
5073 29 : else if (bufferMode_p and not floatDataColumnAvailable_p) // MODEL is not defined for SD data
5074 : {
5075 0 : makeVirtualModelColReal_p = true;
5076 0 : modelDataColumnAvailable_p = true;
5077 : }
5078 : // There is no model available in the SOURCE sub-table
5079 : else
5080 : {
5081 29 : modelDataColumnAvailable_p = false;
5082 :
5083 : // Inform that virtual MODEL_DATA is not available
5084 29 : if (makeVirtualModelColReal_p)
5085 : {
5086 0 : if (bufferMode_p)
5087 : {
5088 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
5089 : << "Requested to make virtual MODEL_DATA column available from MSTransformBuffer but"
5090 : << "SOURCE_MODEL column is not present in SOURCE sub-table"
5091 0 : << LogIO::POST;
5092 : }
5093 : else
5094 : {
5095 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
5096 : << "Requested to make virtual MODEL_DATA column real but "
5097 : << "SOURCE_MODEL column is not present in SOURCE sub-table"
5098 0 : << LogIO::POST;
5099 : }
5100 : }
5101 :
5102 : // Unset makeVirtualModelColReal_p as virtual MODEL col. is not available
5103 29 : makeVirtualModelColReal_p = false;
5104 : }
5105 :
5106 :
5107 : // LAG_DATA
5108 35 : if (inputMs_p->tableDesc().isColumn(MS::columnName(MS::LAG_DATA)))
5109 : {
5110 0 : lagDataColumnAvailable_p = true;
5111 : }
5112 :
5113 35 : return;
5114 : }
5115 :
5116 : // -----------------------------------------------------------------------
5117 : // Method to check which data columns have to be filled
5118 : // -----------------------------------------------------------------------
5119 35 : void MSTransformManager::checkDataColumnsToFill()
5120 : {
5121 35 : dataColMap_p.clear();
5122 35 : bool mainColSet=false;
5123 35 : timeAvgOptions_p = vi::AveragingOptions(vi::AveragingOptions::Nothing);
5124 :
5125 35 : if (datacolumn_p.contains("ALL"))
5126 : {
5127 1 : if (dataColumnAvailable_p)
5128 : {
5129 1 : if (!mainColSet)
5130 : {
5131 1 : mainColumn_p = MS::DATA;
5132 1 : mainColSet = true;
5133 : }
5134 1 : dataColMap_p[MS::DATA] = MS::DATA;
5135 1 : colCheckInfo(MS::columnName(MS::DATA),MS::columnName(dataColMap_p[MS::DATA]));
5136 :
5137 1 : timeAvgOptions_p |= vi::AveragingOptions::AverageObserved;
5138 1 : timeAvgOptions_p |= vi::AveragingOptions::ObservedFlagWeightAvgFromSIGMA;
5139 : }
5140 :
5141 1 : if (correctedDataColumnAvailable_p)
5142 : {
5143 0 : if (!mainColSet)
5144 : {
5145 0 : mainColumn_p = MS::CORRECTED_DATA;
5146 0 : mainColSet = true;
5147 : }
5148 0 : dataColMap_p[MS::CORRECTED_DATA] = MS::CORRECTED_DATA;
5149 0 : colCheckInfo(MS::columnName(MS::CORRECTED_DATA),MS::columnName(dataColMap_p[MS::CORRECTED_DATA]));
5150 :
5151 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageCorrected;
5152 0 : timeAvgOptions_p |= vi::AveragingOptions::CorrectedFlagWeightAvgFromWEIGHT;
5153 : }
5154 1 : if (dataColumnAvailable_p && correctedDataColumnAvailable_p)
5155 0 : bothDataColumnsAreOutput_p = true;
5156 :
5157 :
5158 1 : if (modelDataColumnAvailable_p)
5159 : {
5160 0 : if (!mainColSet)
5161 : {
5162 0 : mainColumn_p = MS::MODEL_DATA;
5163 0 : mainColSet = true;
5164 : }
5165 0 : dataColMap_p[MS::MODEL_DATA] = MS::MODEL_DATA;
5166 0 : colCheckInfo(MS::columnName(MS::MODEL_DATA),MS::columnName(dataColMap_p[MS::MODEL_DATA]));
5167 :
5168 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageModel;
5169 :
5170 0 : if (correctedDataColumnAvailable_p)
5171 : {
5172 0 : timeAvgOptions_p |= vi::AveragingOptions::ModelFlagWeightAvgFromWEIGHT;
5173 : }
5174 0 : else if (dataColumnAvailable_p)
5175 : {
5176 0 : timeAvgOptions_p |= vi::AveragingOptions::ModelFlagWeightAvgFromSIGMA;
5177 : }
5178 : else
5179 : {
5180 0 : timeAvgOptions_p |= vi::AveragingOptions::ModelPlainAvg;
5181 : }
5182 : }
5183 :
5184 1 : if (floatDataColumnAvailable_p)
5185 : {
5186 0 : if (!mainColSet)
5187 : {
5188 0 : mainColumn_p = MS::FLOAT_DATA;
5189 0 : mainColSet = true;
5190 : }
5191 0 : dataColMap_p[MS::FLOAT_DATA] = MS::FLOAT_DATA;
5192 0 : colCheckInfo(MS::columnName(MS::FLOAT_DATA),MS::columnName(dataColMap_p[MS::FLOAT_DATA]));
5193 :
5194 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageFloat;
5195 : }
5196 :
5197 1 : if (lagDataColumnAvailable_p)
5198 : {
5199 0 : if (!mainColSet)
5200 : {
5201 0 : mainColumn_p = MS::LAG_DATA;
5202 0 : mainColSet = true;
5203 : }
5204 0 : dataColMap_p[MS::LAG_DATA] = MS::LAG_DATA;
5205 0 : colCheckInfo(MS::columnName(MS::LAG_DATA),MS::columnName(dataColMap_p[MS::LAG_DATA]));
5206 :
5207 : // TODO: LAG_DATA is not yet supported by TVI
5208 : // timeAvgOptions_p |= vi::AveragingOptions::AverageLagData;
5209 : }
5210 : }
5211 34 : else if (datacolumn_p.contains("DATA,MODEL,CORRECTED"))
5212 : {
5213 2 : if (dataColumnAvailable_p)
5214 : {
5215 2 : if (!mainColSet)
5216 : {
5217 2 : mainColumn_p = MS::DATA;
5218 2 : mainColSet = true;
5219 : }
5220 2 : dataColMap_p[MS::DATA] = MS::DATA;
5221 2 : colCheckInfo(MS::columnName(MS::DATA),MS::columnName(dataColMap_p[MS::DATA]));
5222 :
5223 2 : timeAvgOptions_p |= vi::AveragingOptions::AverageObserved;
5224 2 : timeAvgOptions_p |= vi::AveragingOptions::ObservedFlagWeightAvgFromSIGMA;
5225 : }
5226 :
5227 2 : if (correctedDataColumnAvailable_p)
5228 : {
5229 2 : if (!mainColSet)
5230 : {
5231 0 : mainColumn_p = MS::CORRECTED_DATA;
5232 0 : mainColSet = true;
5233 : }
5234 2 : dataColMap_p[MS::CORRECTED_DATA] = MS::CORRECTED_DATA;
5235 2 : colCheckInfo(MS::columnName(MS::CORRECTED_DATA),MS::columnName(dataColMap_p[MS::CORRECTED_DATA]));
5236 :
5237 2 : timeAvgOptions_p |= vi::AveragingOptions::AverageCorrected;
5238 2 : timeAvgOptions_p |= vi::AveragingOptions::CorrectedFlagWeightAvgFromWEIGHT;
5239 : }
5240 :
5241 2 : if (dataColumnAvailable_p && correctedDataColumnAvailable_p)
5242 2 : bothDataColumnsAreOutput_p = true;
5243 2 : if (modelDataColumnAvailable_p)
5244 : {
5245 2 : if (!mainColSet)
5246 : {
5247 0 : mainColumn_p = MS::MODEL_DATA;
5248 0 : mainColSet = true;
5249 : }
5250 2 : dataColMap_p[MS::MODEL_DATA] = MS::MODEL_DATA;
5251 2 : colCheckInfo(MS::columnName(MS::MODEL_DATA),MS::columnName(dataColMap_p[MS::MODEL_DATA]));
5252 :
5253 2 : timeAvgOptions_p |= vi::AveragingOptions::AverageModel;
5254 :
5255 2 : if (correctedDataColumnAvailable_p)
5256 : {
5257 2 : timeAvgOptions_p |= vi::AveragingOptions::ModelFlagWeightAvgFromWEIGHT;
5258 : }
5259 0 : else if (dataColumnAvailable_p)
5260 : {
5261 0 : timeAvgOptions_p |= vi::AveragingOptions::ModelFlagWeightAvgFromSIGMA;
5262 : }
5263 : else
5264 : {
5265 0 : timeAvgOptions_p |= vi::AveragingOptions::ModelPlainAvg;
5266 : }
5267 : }
5268 : }
5269 32 : else if (datacolumn_p.contains("FLOAT_DATA,DATA"))
5270 : {
5271 :
5272 0 : if (dataColumnAvailable_p)
5273 : {
5274 0 : if (!mainColSet)
5275 : {
5276 0 : mainColumn_p = MS::DATA;
5277 0 : mainColSet = true;
5278 : }
5279 0 : dataColMap_p[MS::DATA] = MS::DATA;
5280 0 : colCheckInfo(MS::columnName(MS::DATA),MS::columnName(dataColMap_p[MS::DATA]));
5281 :
5282 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageObserved;
5283 0 : timeAvgOptions_p |= vi::AveragingOptions::ObservedFlagWeightAvgFromSIGMA;
5284 : }
5285 : else
5286 : {
5287 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5288 0 : "DATA column requested but not available in input MS "<< LogIO::POST;
5289 : }
5290 :
5291 0 : if (floatDataColumnAvailable_p)
5292 : {
5293 0 : if (!mainColSet)
5294 : {
5295 0 : mainColumn_p = MS::FLOAT_DATA;
5296 0 : mainColSet = true;
5297 : }
5298 0 : dataColMap_p[MS::FLOAT_DATA] = MS::FLOAT_DATA;
5299 0 : colCheckInfo(MS::columnName(MS::FLOAT_DATA),MS::columnName(dataColMap_p[MS::FLOAT_DATA]));
5300 :
5301 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageFloat;
5302 : }
5303 : else
5304 : {
5305 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5306 0 : "FLOAT_DATA column requested but not available in input MS "<< LogIO::POST;
5307 : }
5308 : }
5309 32 : else if (datacolumn_p.contains("FLOAT_DATA"))
5310 : {
5311 0 : if (floatDataColumnAvailable_p)
5312 : {
5313 0 : if (!mainColSet)
5314 : {
5315 0 : mainColumn_p = MS::FLOAT_DATA;
5316 0 : mainColSet = true;
5317 : }
5318 0 : dataColMap_p[MS::FLOAT_DATA] = MS::FLOAT_DATA;
5319 0 : colCheckInfo(MS::columnName(MS::FLOAT_DATA),MS::columnName(dataColMap_p[MS::FLOAT_DATA]));
5320 :
5321 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageFloat;
5322 : }
5323 : else
5324 : {
5325 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5326 0 : "FLOAT_DATA column requested but not available in input MS "<< LogIO::POST;
5327 : }
5328 : }
5329 32 : else if (datacolumn_p.contains("LAG_DATA,DATA"))
5330 : {
5331 0 : if (dataColumnAvailable_p)
5332 : {
5333 0 : if (!mainColSet)
5334 : {
5335 0 : mainColumn_p = MS::DATA;
5336 0 : mainColSet = true;
5337 : }
5338 0 : dataColMap_p[MS::DATA] = MS::DATA;
5339 0 : colCheckInfo(MS::columnName(MS::DATA),MS::columnName(dataColMap_p[MS::DATA]));
5340 :
5341 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageObserved;
5342 0 : timeAvgOptions_p |= vi::AveragingOptions::ObservedFlagWeightAvgFromSIGMA;
5343 : }
5344 : else
5345 : {
5346 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5347 0 : "DATA column requested but not available in input MS "<< LogIO::POST;
5348 : }
5349 :
5350 0 : if (lagDataColumnAvailable_p)
5351 : {
5352 0 : if (!mainColSet)
5353 : {
5354 0 : mainColumn_p = MS::LAG_DATA;
5355 0 : mainColSet = true;
5356 : }
5357 0 : dataColMap_p[MS::LAG_DATA] = MS::LAG_DATA;
5358 0 : colCheckInfo(MS::columnName(MS::LAG_DATA),MS::columnName(dataColMap_p[MS::LAG_DATA]));
5359 :
5360 : // TODO: LAG_DATA is not yet supported by TVI
5361 : // timeAvgOptions_p |= vi::AveragingOptions::AverageLagData;
5362 : }
5363 : else
5364 : {
5365 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5366 0 : "LAG_DATA column requested but not available in input MS "<< LogIO::POST;
5367 : }
5368 : }
5369 32 : else if (datacolumn_p.contains("LAG_DATA"))
5370 : {
5371 0 : if (lagDataColumnAvailable_p)
5372 : {
5373 0 : if (!mainColSet)
5374 : {
5375 0 : mainColumn_p = MS::LAG_DATA;
5376 0 : mainColSet = true;
5377 : }
5378 0 : dataColMap_p[MS::LAG_DATA] = MS::LAG_DATA;
5379 0 : colCheckInfo(MS::columnName(MS::LAG_DATA),MS::columnName(dataColMap_p[MS::LAG_DATA]));
5380 :
5381 : // TODO: LAG_DATA is not yet supported by TVI
5382 : // timeAvgOptions_p |= vi::AveragingOptions::AverageLagData;
5383 : }
5384 : else
5385 : {
5386 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5387 0 : "LAG_DATA column requested but not available in input MS "<< LogIO::POST;
5388 : }
5389 : }
5390 32 : else if (datacolumn_p.contains("DATA"))
5391 : {
5392 29 : if (dataColumnAvailable_p)
5393 : {
5394 29 : if (!mainColSet)
5395 : {
5396 29 : mainColumn_p = MS::DATA;
5397 29 : mainColSet = true;
5398 : }
5399 29 : dataColMap_p[MS::DATA] = MS::DATA;
5400 29 : colCheckInfo(MS::columnName(MS::DATA),MS::columnName(dataColMap_p[MS::DATA]));
5401 :
5402 29 : timeAvgOptions_p |= vi::AveragingOptions::AverageObserved;
5403 29 : timeAvgOptions_p |= vi::AveragingOptions::ObservedFlagWeightAvgFromSIGMA;
5404 : }
5405 : else
5406 : {
5407 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5408 0 : "DATA column requested but not available in input MS "<< LogIO::POST;
5409 : }
5410 : }
5411 3 : else if (datacolumn_p.contains("CORRECTED"))
5412 : {
5413 3 : if (correctedDataColumnAvailable_p)
5414 : {
5415 3 : if (!mainColSet)
5416 : {
5417 3 : mainColumn_p = MS::CORRECTED_DATA;
5418 3 : mainColSet = true;
5419 : }
5420 3 : dataColMap_p[MS::CORRECTED_DATA] = MS::DATA;
5421 3 : correctedToData_p = true;
5422 3 : colCheckInfo(MS::columnName(MS::CORRECTED_DATA),MS::columnName(dataColMap_p[MS::CORRECTED_DATA]));
5423 :
5424 3 : timeAvgOptions_p |= vi::AveragingOptions::AverageCorrected;
5425 3 : timeAvgOptions_p |= vi::AveragingOptions::CorrectedFlagWeightAvgFromWEIGHT;
5426 : }
5427 : else
5428 : {
5429 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5430 0 : "CORRECTED_DATA column requested but not available in input MS "<< LogIO::POST;
5431 : }
5432 : }
5433 0 : else if (datacolumn_p.contains("MODEL"))
5434 : {
5435 :
5436 0 : if (modelDataColumnAvailable_p)
5437 : {
5438 0 : if (!mainColSet)
5439 : {
5440 0 : mainColumn_p = MS::MODEL_DATA;
5441 0 : mainColSet = true;
5442 : }
5443 :
5444 0 : dataColMap_p[MS::MODEL_DATA] = MS::DATA;
5445 0 : colCheckInfo(MS::columnName(MS::MODEL_DATA),MS::columnName(dataColMap_p[MS::MODEL_DATA]));
5446 0 : timeAvgOptions_p |= vi::AveragingOptions::AverageModel;
5447 0 : timeAvgOptions_p |= vi::AveragingOptions::ModelPlainAvg;
5448 : }
5449 : else
5450 : {
5451 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__) <<
5452 0 : "MODEL_DATA column requested but not available in input MS "<< LogIO::POST;
5453 : }
5454 : }
5455 0 : else if (datacolumn_p.contains("NONE") and userBufferMode_p)
5456 : {
5457 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
5458 : << "No datacolumn selected in buffer mode"
5459 0 : << LogIO::POST;
5460 : }
5461 : else
5462 : {
5463 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
5464 0 : << "Requested data column " << datacolumn_p
5465 : << " is not supported, possible choices are ALL,DATA,CORRECTED,MODEL,FLOAT_DATA,LAG_DATA"
5466 0 : << LogIO::POST;
5467 : }
5468 :
5469 35 : if (produceModel_p) {
5470 0 : const auto colname = (MS::DATA == mainColumn_p) ? "DATA" : "CORRECTED_DATA";
5471 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5472 : << "Will produce a MODEL_DATA column in the output MS, "
5473 : << "with the fit calculated for input " << colname
5474 0 : << LogIO::POST;
5475 0 : dataColMap_p[MS::MODEL_DATA] = mainColumn_p;
5476 : }
5477 :
5478 : // Add shortcuts to be used in the context of WeightSpectrum related transformations
5479 35 : dataColMap::iterator iter;
5480 :
5481 : // Check if we are doing DATA
5482 35 : iter = dataColMap_p.find(MS::DATA);
5483 35 : if (iter != dataColMap_p.end()) doingData_p = true;
5484 :
5485 : // Check if we are doing CORRECTED_DATA
5486 35 : iter = dataColMap_p.find(MS::CORRECTED_DATA);
5487 35 : if (iter != dataColMap_p.end()) doingCorrected_p = true;
5488 :
5489 : // Check if we are doing MODEL_DATA
5490 35 : iter = dataColMap_p.find(MS::MODEL_DATA);
5491 35 : if (iter != dataColMap_p.end()) doingModel_p = true;
5492 :
5493 70 : return;
5494 : }
5495 :
5496 :
5497 : // -----------------------------------------------------------------------
5498 : //
5499 : // -----------------------------------------------------------------------
5500 39 : void MSTransformManager::colCheckInfo(const String& inputColName, const String& outputColName)
5501 : {
5502 39 : if (inputMs_p->tableDesc().isColumn(inputColName))
5503 : {
5504 39 : if (not bufferMode_p)
5505 : {
5506 78 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5507 : << "Adding " << outputColName << " column to output MS from input " << inputColName<< " column"
5508 78 : << LogIO::POST;
5509 : }
5510 : else
5511 : {
5512 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5513 : << inputColName << " column present in input MS will be available from MSTransformBuffer"
5514 0 : << LogIO::POST;
5515 : }
5516 : }
5517 : else
5518 : {
5519 0 : if (not bufferMode_p)
5520 : {
5521 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5522 : << "Adding " << outputColName << " column to output MS from input virtual " << inputColName<< " column"
5523 0 : << LogIO::POST;
5524 : }
5525 : else
5526 : {
5527 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5528 : << "Virtual " << inputColName << " column present in input MS will be available from MSTransformBuffer"
5529 0 : << LogIO::POST;
5530 : }
5531 : }
5532 :
5533 39 : return;
5534 : }
5535 :
5536 :
5537 : // -----------------------------------------------------------------------
5538 : // Method to determine sort columns order
5539 : // -----------------------------------------------------------------------
5540 35 : void MSTransformManager::setIterationApproach()
5541 : {
5542 35 : uInt nSortColumns = 7;
5543 :
5544 35 : if (timespan_p.contains("scan")) nSortColumns -= 1;
5545 35 : if (timespan_p.contains("state")) nSortColumns -= 1;
5546 35 : if (timespan_p.contains("field")) nSortColumns -= 1;
5547 35 : if ((combinespws_p) || (spwAverage_p)) nSortColumns -= 1;
5548 :
5549 35 : sortColumns_p = Block<Int>(nSortColumns);
5550 35 : uInt sortColumnIndex = 0;
5551 :
5552 35 : sortColumns_p[0] = MS::OBSERVATION_ID;
5553 35 : sortColumnIndex += 1;
5554 :
5555 35 : sortColumns_p[1] = MS::ARRAY_ID;
5556 35 : sortColumnIndex += 1;
5557 :
5558 35 : if (!timespan_p.contains("scan"))
5559 : {
5560 35 : sortColumns_p[sortColumnIndex] = MS::SCAN_NUMBER;
5561 35 : sortColumnIndex += 1;
5562 : }
5563 : else
5564 : {
5565 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5566 0 : << "Combining data through scans for time average " << LogIO::POST;
5567 : }
5568 :
5569 35 : if (!timespan_p.contains("state"))
5570 : {
5571 35 : sortColumns_p[sortColumnIndex] = MS::STATE_ID;
5572 35 : sortColumnIndex += 1;
5573 : }
5574 : else
5575 : {
5576 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5577 0 : << "Combining data through state for time average" << LogIO::POST;
5578 : }
5579 :
5580 35 : if (!timespan_p.contains("field"))
5581 : {
5582 35 : sortColumns_p[sortColumnIndex] = MS::FIELD_ID;
5583 35 : sortColumnIndex += 1;
5584 : }
5585 : else
5586 : {
5587 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5588 0 : << "Combining data through field time average" << LogIO::POST;
5589 : }
5590 :
5591 35 : if ((!combinespws_p) && (!spwAverage_p))
5592 : {
5593 35 : sortColumns_p[sortColumnIndex] = MS::DATA_DESC_ID;
5594 35 : sortColumnIndex += 1;
5595 : }
5596 : else
5597 : {
5598 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5599 0 : << "Combining data from selected spectral windows" << LogIO::POST;
5600 : }
5601 :
5602 35 : sortColumns_p[sortColumnIndex] = MS::TIME;
5603 :
5604 35 : return;
5605 : }
5606 :
5607 :
5608 : // -----------------------------------------------------------------------
5609 : // Method to generate the initial iterator
5610 : // -----------------------------------------------------------------------
5611 35 : void MSTransformManager::generateIterator()
5612 : {
5613 35 : bool isWritable = false;
5614 35 : if (interactive_p) isWritable = true;
5615 :
5616 : // Prepare time average parameters (common for all cases)
5617 35 : std::shared_ptr<vi::AveragingParameters> timeavgParams = nullptr;
5618 35 : if (timeAverage_p)
5619 : {
5620 19 : if (maxuvwdistance_p > 0)
5621 : {
5622 0 : timeAvgOptions_p |= vi::AveragingOptions::BaselineDependentAveraging;
5623 : }
5624 :
5625 : timeavgParams = std::make_shared<vi::AveragingParameters>
5626 38 : (timeBin_p, .0, vi::SortColumns(sortColumns_p, false),
5627 57 : timeAvgOptions_p, maxuvwdistance_p, nullptr, isWritable, dx_p, dy_p);
5628 : }
5629 :
5630 : // Calibrating VI
5631 35 : if (uvcontsub_p)
5632 : {
5633 : // First determine number of layers
5634 0 : uInt nTVIs = 1;
5635 0 : if (timeAverage_p) nTVIs++;
5636 0 : if (uvcontsub_p) nTVIs++;
5637 :
5638 : // Init vector of TVI factories and populate it
5639 0 : uInt TVIFactoryIdx = 0;
5640 0 : Vector<vi::ViiLayerFactory*> TVIFactories(nTVIs);
5641 :
5642 : // Data layer
5643 0 : vi::IteratingParameters ipar(timeBin_p,vi::SortColumns(sortColumns_p, false));
5644 0 : vi::VisIterImpl2LayerFactory dataLayerTVIFactory(selectedInputMs_p,ipar,isWritable);
5645 0 : TVIFactories[TVIFactoryIdx]=&dataLayerTVIFactory;
5646 0 : TVIFactoryIdx++;
5647 :
5648 : // Time avg. layer
5649 0 : std::unique_ptr<vi::AveragingVi2LayerFactory> timeAverageTVIFactory;
5650 0 : if (timeAverage_p)
5651 : {
5652 0 : timeAverageTVIFactory.reset(new vi::AveragingVi2LayerFactory(*timeavgParams));
5653 0 : TVIFactories[TVIFactoryIdx]=timeAverageTVIFactory.get();
5654 0 : TVIFactoryIdx++;
5655 : }
5656 :
5657 : // UVContSub layer
5658 0 : std::unique_ptr<vi::UVContSubTVILayerFactory> uvContSubTVIFactory;
5659 0 : if (uvcontsub_p)
5660 : {
5661 : // needed for warning to prevent confusion with old uvcontsub!
5662 0 : uvcontsubRec_p.define("allowed_spws", spwSelection_p);
5663 0 : uvContSubTVIFactory.reset(new vi::UVContSubTVILayerFactory (uvcontsubRec_p));
5664 0 : TVIFactories[TVIFactoryIdx]=uvContSubTVIFactory.get();
5665 0 : TVIFactoryIdx++;
5666 : }
5667 :
5668 0 : visibilityIterator_p = new vi::VisibilityIterator2 (TVIFactories);
5669 :
5670 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__)
5671 0 : << "TVI chain is " << visibilityIterator_p->ViiType() << LogIO::POST;
5672 0 : }
5673 35 : else if (calibrate_p || scalarAverage_p)
5674 : {
5675 : try
5676 : {
5677 : // Isolate iteration parameters
5678 0 : vi::IteratingParameters iterpar;
5679 0 : if (scalarAverage_p)
5680 0 : iterpar = vi::IteratingParameters(timeBin_p,vi::SortColumns(sortColumns_p, false));
5681 : else
5682 0 : iterpar = vi::IteratingParameters(0,vi::SortColumns(sortColumns_p, false));
5683 :
5684 : // By callib String
5685 0 : if (callib_p.length() > 0)
5686 : {
5687 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager",__FUNCTION__)
5688 : << "OTF calibration activated, using calibration file spec to generate iterator"
5689 0 : << LogIO::POST;
5690 :
5691 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::LayeredVi2Factory(selectedInputMs_p, &iterpar,callib_p, timeavgParams.get()));
5692 : }
5693 : // By callib Record
5694 0 : else if (callibRec_p.nfields() > 0)
5695 : {
5696 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager",__FUNCTION__)
5697 : << "OTF calibration activated, using calibration record spec to generate iterator"
5698 0 : << LogIO::POST;
5699 :
5700 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::LayeredVi2Factory(selectedInputMs_p, &iterpar,callibRec_p, timeavgParams.get()));
5701 : }
5702 : else // scalar
5703 : {
5704 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::LayeredVi2Factory(selectedInputMs_p, &iterpar));
5705 : }
5706 0 : }
5707 0 : catch (const MSSelectionError &x)
5708 : {
5709 0 : delete visibilityIterator_p;
5710 :
5711 0 : correctedDataColumnAvailable_p = false;
5712 0 : checkDataColumnsToFill();
5713 :
5714 : // Averaging VI
5715 0 : if (timeAverage_p && !tviphaseshift_p)
5716 : {
5717 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::AveragingVi2Factory(*timeavgParams, selectedInputMs_p));
5718 : }
5719 : // Polarization Averaging VI
5720 0 : else if (polAverage_p) {
5721 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::PolAverageVi2Factory(polAverageConfig_p, selectedInputMs_p,
5722 0 : vi::SortColumns(sortColumns_p, false), timeBin_p, isWritable));
5723 : }
5724 : // Pointings Interpolator VI
5725 0 : else if (pointingsInterpolation_p) {
5726 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::PointingInterpolationVi2Factory(pointingsInterpolationConfig_p, selectedInputMs_p,
5727 0 : vi::SortColumns(sortColumns_p, false), timeBin_p, isWritable));
5728 : }
5729 : // CAS-12706 To run phase shift via a TVI which has
5730 : // support for shifting across large offset/angles
5731 0 : else if (tviphaseshift_p) {
5732 :
5733 : // First determine number of layers
5734 0 : uInt nTVIs = (timeAverage_p ? 3 : 2);
5735 :
5736 : // Init vector of TVI factories and populate it
5737 0 : uInt TVIFactoryIdx = 0;
5738 0 : Vector<vi::ViiLayerFactory*> TVIFactories(nTVIs);
5739 :
5740 : // Data layer
5741 0 : vi::IteratingParameters ipar(timeBin_p,vi::SortColumns(sortColumns_p, false));
5742 0 : vi::VisIterImpl2LayerFactory dataLayerTVIFactory(selectedInputMs_p,ipar,isWritable);
5743 0 : TVIFactories[TVIFactoryIdx++]=&dataLayerTVIFactory;
5744 :
5745 : // Time avg. layer
5746 0 : std::unique_ptr<vi::AveragingVi2LayerFactory> timeAverageTVIFactory;
5747 0 : if (timeAverage_p)
5748 : {
5749 0 : timeAverageTVIFactory.reset(new vi::AveragingVi2LayerFactory(*timeavgParams));
5750 0 : TVIFactories[TVIFactoryIdx++]=timeAverageTVIFactory.get();
5751 : }
5752 :
5753 : // Phaseshift layer
5754 0 : vi::PhaseShiftingTVILayerFactory phaseShiftingTVILayerFactory(tviphaseshiftConfig_p);
5755 0 : TVIFactories[TVIFactoryIdx]=&phaseShiftingTVILayerFactory;
5756 :
5757 0 : visibilityIterator_p = new vi::VisibilityIterator2 (TVIFactories);
5758 0 : }
5759 : // Plain VI
5760 : else
5761 : {
5762 0 : visibilityIterator_p = new vi::VisibilityIterator2(*selectedInputMs_p,vi::SortColumns(sortColumns_p, false),
5763 0 : isWritable, NULL, timeBin_p);
5764 : }
5765 0 : }
5766 0 : catch (const AipsError &x)
5767 : {
5768 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager",__FUNCTION__)
5769 : << "Error initializing calibration VI: " << x.getMesg()
5770 0 : << LogIO::POST;
5771 0 : throw(x);
5772 0 : }
5773 0 : }
5774 : // Averaging VI
5775 35 : else if (timeAverage_p && !tviphaseshift_p)
5776 : {
5777 19 : visibilityIterator_p = new vi::VisibilityIterator2(vi::AveragingVi2Factory(*timeavgParams, selectedInputMs_p));
5778 : }
5779 : // Polarization Averaging VI
5780 16 : else if (polAverage_p) {
5781 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::PolAverageVi2Factory(polAverageConfig_p, selectedInputMs_p,
5782 0 : vi::SortColumns(sortColumns_p, false), timeBin_p, isWritable));
5783 : }
5784 : // VI interpolating pointing directions
5785 16 : else if (pointingsInterpolation_p) {
5786 0 : visibilityIterator_p = new vi::VisibilityIterator2(vi::PointingInterpolationVi2Factory(pointingsInterpolationConfig_p, selectedInputMs_p,
5787 0 : vi::SortColumns(sortColumns_p, false), timeBin_p, isWritable));
5788 : }
5789 : // CAS-12706 To run phase shift via a TVI which has
5790 : // support for shifting across large offset/angles
5791 16 : else if (tviphaseshift_p) {
5792 :
5793 : // First determine number of layers
5794 0 : uInt nTVIs = (timeAverage_p ? 3 : 2);
5795 :
5796 : // Init vector of TVI factories and populate it
5797 0 : uInt TVIFactoryIdx = 0;
5798 0 : Vector<vi::ViiLayerFactory*> TVIFactories(nTVIs);
5799 :
5800 : // Data layer
5801 0 : vi::IteratingParameters ipar(timeBin_p,vi::SortColumns(sortColumns_p, false));
5802 0 : vi::VisIterImpl2LayerFactory dataLayerTVIFactory(selectedInputMs_p,ipar,isWritable);
5803 0 : TVIFactories[TVIFactoryIdx++]=&dataLayerTVIFactory;
5804 :
5805 : // Time avg. layer
5806 0 : std::unique_ptr<vi::AveragingVi2LayerFactory> timeAverageTVIFactory;
5807 0 : if (timeAverage_p)
5808 : {
5809 0 : timeAverageTVIFactory.reset(new vi::AveragingVi2LayerFactory(*timeavgParams));
5810 0 : TVIFactories[TVIFactoryIdx++]=timeAverageTVIFactory.get();
5811 : }
5812 :
5813 : // Phaseshift layer
5814 0 : vi::PhaseShiftingTVILayerFactory phaseShiftingTVILayerFactory(tviphaseshiftConfig_p);
5815 0 : TVIFactories[TVIFactoryIdx]=&phaseShiftingTVILayerFactory;
5816 :
5817 0 : visibilityIterator_p = new vi::VisibilityIterator2 (TVIFactories);
5818 0 : }
5819 : // Offline ATM correction
5820 16 : else if (doAtmCor_p) {
5821 0 : visibilityIterator_p = new vi::VisibilityIterator2(
5822 0 : vi::SDAtmosphereCorrectionVi2Factory(
5823 0 : atmCorConfig_p, selectedInputMs_p, vi::SortColumns(sortColumns_p, false), timeBin_p, isWritable
5824 : )
5825 0 : );
5826 : }
5827 : // Plain VI
5828 : else
5829 : {
5830 32 : visibilityIterator_p = new vi::VisibilityIterator2(*selectedInputMs_p,vi::SortColumns(sortColumns_p, false),
5831 16 : isWritable, NULL, timeBin_p);
5832 : }
5833 :
5834 35 : if (timeAverage_p) visibilityIterator_p->setWeightScaling(vi::WeightScaling::generateUnityWeightScaling());
5835 35 : if (channelSelector_p != NULL) visibilityIterator_p->setFrequencySelection(*channelSelector_p);
5836 :
5837 70 : return;
5838 35 : }
5839 :
5840 :
5841 : // -----------------------------------------------------------------------
5842 : //
5843 : // -----------------------------------------------------------------------
5844 1771 : void MSTransformManager::setupBufferTransformations(vi::VisBuffer2 *vb)
5845 : {
5846 : // Calculate number of rows to add to the output MS depending on the combination parameters
5847 1771 : uInt rowsToAdd = 0;
5848 :
5849 1771 : if ((combinespws_p) or (nspws_p > 1))
5850 : {
5851 : // Fill baseline map using as key Ant1,Ant2,Scan and State,
5852 : // Which are the elements that can be combined in one chunk
5853 0 : rowIndex_p.clear();
5854 0 : baselineMap_p.clear();
5855 0 : Vector<Int> antenna1 = vb->antenna1();
5856 0 : Vector<Int> antenna2 = vb->antenna2();
5857 0 : Vector<Int> scan = vb->scan();
5858 0 : Vector<Int> state = vb->stateId();
5859 0 : Int relativeTimeInMiliseconds = 0;
5860 0 : for (uInt row=0;row<antenna1.size();row++)
5861 : {
5862 0 : pair<uInt,uInt> baseline = std::make_pair(antenna1(row),antenna2(row));
5863 0 : relativeTimeInMiliseconds = (Int)floor(1E3*(vb->time()(row) - vb->time()(0)));
5864 0 : pair< pair<uInt,uInt>, uInt > baselineTime = std::make_pair(baseline,relativeTimeInMiliseconds);
5865 :
5866 : // Fill row index vector with to the first row for every element in the baseline map
5867 0 : if (baselineMap_p.find(baselineTime) == baselineMap_p.end())
5868 : {
5869 0 : rowIndex_p.push_back(row);
5870 : }
5871 :
5872 0 : baselineMap_p[baselineTime].push_back(row);
5873 :
5874 : }
5875 :
5876 0 : rowsToAdd = baselineMap_p.size();
5877 :
5878 : // Fill row index vector with to the first row for every element in the baseline map
5879 : // jagonzal (CAS-8492): For SPW separation only we don't
5880 : // follow the baselineMap order but the input order
5881 0 : if (combinespws_p)
5882 : {
5883 0 : uInt rowIndex = 0;
5884 0 : rowIndex_p.clear();
5885 0 : for (baselineMap::iterator iter = baselineMap_p.begin(); iter != baselineMap_p.end(); iter++)
5886 : {
5887 0 : rowIndex_p.push_back((iter->second)[0]);
5888 0 : rowIndex ++;
5889 : }
5890 : }
5891 0 : }
5892 : else
5893 : {
5894 1771 : rowsToAdd = vb->nRows();
5895 : }
5896 :
5897 : // Initialize reference frame transformation parameters
5898 1771 : if (refFrameTransformation_p)
5899 : {
5900 0 : initFrequencyTransGrid(vb);
5901 : }
5902 :
5903 : // Calculate total number for rows to add
5904 1771 : nRowsToAdd_p = rowsToAdd*nspws_p;
5905 :
5906 1771 : return;
5907 :
5908 : }
5909 :
5910 : // -----------------------------------------------------------------------
5911 : // Fill output MS with data from an input VisBuffer
5912 : // -----------------------------------------------------------------------
5913 1771 : void MSTransformManager::fillOutputMs(vi::VisBuffer2 *vb)
5914 : {
5915 1771 : setupBufferTransformations(vb);
5916 :
5917 1771 : if (not bufferMode_p)
5918 : {
5919 : // Create RowRef object to fill new rows
5920 1771 : auto currentRows = outputMs_p->nrow();
5921 1771 : RefRows rowRef( currentRows, currentRows + nRowsToAdd_p/nspws_p - 1);
5922 :
5923 : // Add new rows to output MS
5924 1771 : outputMs_p->addRow(nRowsToAdd_p,false);
5925 :
5926 : // Fill new rows
5927 1771 : weightSpectrumFlatFilled_p = false;
5928 1771 : weightSpectrumFromSigmaFilled_p = false;
5929 1771 : fillWeightCols(vb,rowRef);
5930 1771 : fillDataCols(vb,rowRef);
5931 1771 : fillIdCols(vb,rowRef);
5932 1771 : }
5933 :
5934 1771 : return;
5935 : }
5936 :
5937 : // -----------------------------------------------------------------------
5938 : // Method to initialize the input frequency grid to change reference frame
5939 : // -----------------------------------------------------------------------
5940 0 : void MSTransformManager::initFrequencyTransGrid(vi::VisBuffer2 *vb)
5941 : {
5942 : // NOTE (jagonzal): According to dpetry the difference between times is negligible but he recommends to use TIME
5943 : // However it does not cross-validate unless we use timeMeas from the MS columns
5944 0 : ScalarMeasColumn<MEpoch> mainTimeMeasCol = selectedInputMsCols_p->timeMeas();
5945 0 : MEpoch currentRowTime = mainTimeMeasCol(vb->rowIds()(0));
5946 :
5947 : // CAS-6778: Support for new ref. frame SOURCE that requires radial velocity correction
5948 0 : MDoppler radVelCorr;
5949 0 : MDirection inputFieldDirection;
5950 0 : bool radVelSignificant = false;
5951 0 : if (radialVelocityCorrection_p && inputMSFieldCols_p->needInterTime(vb->fieldId()(0)))
5952 : {
5953 0 : MRadialVelocity mRV = inputMSFieldCols_p->radVelMeas(vb->fieldId()(0),vb->time()(0));
5954 0 : Quantity mrv = mRV.get("m/s");
5955 0 : Quantity offsetMrv = radialVelocity_p.get("m/s"); // the radvel by which the out SPW def was shifted
5956 0 : radVelCorr = MDoppler(mrv-(Quantity(2.)*offsetMrv));
5957 0 : if (fabs(mrv.getValue()) > 1E-6) radVelSignificant = true;
5958 :
5959 0 : inputFieldDirection = inputMSFieldCols_p->phaseDirMeas(vb->fieldId()(0), vb->time()(0));
5960 0 : }
5961 : else
5962 : {
5963 0 : inputFieldDirection = vb->phaseCenter();
5964 : }
5965 :
5966 0 : MFrequency::Ref inputFrameRef = MFrequency::Ref(inputReferenceFrame_p,
5967 0 : MeasFrame(inputFieldDirection, observatoryPosition_p, currentRowTime));
5968 :
5969 0 : MFrequency::Ref outputFrameRef;
5970 0 : outputFrameRef = MFrequency::Ref(outputReferenceFrame_p,
5971 0 : MeasFrame(phaseCenter_p, observatoryPosition_p, referenceTime_p));
5972 :
5973 0 : freqTransEngine_p = MFrequency::Convert(MSTransformations::Hz, inputFrameRef, outputFrameRef);
5974 :
5975 0 : Int spwIndex = 0;
5976 0 : if (not combinespws_p)
5977 : {
5978 : // jagonzal : It is not necessary to map spwIndex because we
5979 : // pass the original SPWId down to the interpol1D method
5980 0 : spwIndex = vb->spectralWindows()(0);
5981 : }
5982 :
5983 :
5984 0 : if (fftShiftEnabled_p)
5985 : {
5986 0 : uInt centralChan = inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ.size()/2;
5987 :
5988 0 : Double oldCentralFrequencyBeforeRegridding = inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ[centralChan];
5989 : Double newCentralFrequencyBeforeRegriddingAtCurrentTime =
5990 0 : freqTransEngine_p(oldCentralFrequencyBeforeRegridding).get(MSTransformations::Hz).getValue();
5991 :
5992 : // CAS-6778: Support for new ref. frame SOURCE that requires radial velocity correction
5993 0 : if (radVelSignificant)
5994 : {
5995 0 : Vector<Double> tmp(1,newCentralFrequencyBeforeRegriddingAtCurrentTime);
5996 0 : newCentralFrequencyBeforeRegriddingAtCurrentTime = radVelCorr.shiftFrequency(tmp)(0);
5997 0 : }
5998 :
5999 0 : Double newCentralFrequencyBeforeRegriddingAtReferenceTime = inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ_aux[centralChan];
6000 0 : Double absoluteShift = newCentralFrequencyBeforeRegriddingAtCurrentTime - newCentralFrequencyBeforeRegriddingAtReferenceTime;
6001 :
6002 0 : Double chanWidth = inputOutputSpwMap_p[spwIndex].second.CHAN_FREQ[1] - inputOutputSpwMap_p[spwIndex].second.CHAN_FREQ[0];
6003 0 : Double bandwidth = inputOutputSpwMap_p[spwIndex].second.CHAN_FREQ[inputOutputSpwMap_p[spwIndex].second.NUM_CHAN-1] - inputOutputSpwMap_p[spwIndex].second.CHAN_FREQ[0];
6004 0 : bandwidth += chanWidth;
6005 :
6006 0 : fftShift_p = - absoluteShift / bandwidth;
6007 :
6008 0 : ostringstream current;
6009 0 : current << setprecision(numeric_limits<double>::max_digits10)
6010 0 : << newCentralFrequencyBeforeRegriddingAtCurrentTime;
6011 0 : ostringstream reference;
6012 0 : reference << setprecision(numeric_limits<double>::max_digits10)
6013 0 : << newCentralFrequencyBeforeRegriddingAtReferenceTime;
6014 0 : logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager",__FUNCTION__)
6015 : << "Using fftshift interpolation. The absolute shift is the "
6016 : << "new central frequency at current (input SPW) time - new "
6017 : << "central frequency "
6018 : << "at reference (output SPW) time\nAbsolute shift: "
6019 : << current
6020 : << " - " << reference
6021 : << " = " << absoluteShift << ", bandwidth " << bandwidth
6022 0 : << ", relative shift: " << fftShift_p << LogIO::POST;
6023 :
6024 0 : }
6025 : else
6026 : {
6027 0 : for(uInt chan_idx=0; chan_idx<inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ.size(); chan_idx++)
6028 : {
6029 0 : inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ_aux[chan_idx] =
6030 0 : freqTransEngine_p(inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ[chan_idx]).get(MSTransformations::Hz).getValue();
6031 : }
6032 :
6033 : /*
6034 : ostringstream oss;
6035 : oss.precision(30);
6036 : oss << " field direction input frame=" << inputFieldDirection << endl;
6037 : oss << " input frame=" << inputFrameRef << endl;
6038 : oss << " field direction output frame=" << phaseCenter_p << endl;
6039 : oss << " output frame=" << outputFrameRef << endl;
6040 : oss << " transformation engine=" << freqTransEngine_p << endl;
6041 : oss << " before transformation=" << inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ[0] << endl;
6042 : oss << " after transformation=" << inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ_aux[0] << endl;
6043 : */
6044 :
6045 :
6046 0 : if (radVelSignificant)
6047 : {
6048 0 : inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ_aux =
6049 0 : radVelCorr.shiftFrequency(inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ_aux);
6050 :
6051 : /*
6052 : oss << " correction engine=" << radVelCorr << endl;
6053 : oss << " after radial velocity correction=" << inputOutputSpwMap_p[spwIndex].first.CHAN_FREQ_aux[0] << endl;
6054 : */
6055 : }
6056 :
6057 : //logger_p << LogIO::NORMAL << LogOrigin("MSTransformManager", __FUNCTION__) << oss.str() << LogIO::POST;
6058 : }
6059 :
6060 0 : return;
6061 0 : }
6062 :
6063 : // ----------------------------------------------------------------------------------------
6064 : // Fill auxiliary (meta data) columns which don't depend on the SPW (merely consist of Ids)
6065 : // ----------------------------------------------------------------------------------------
6066 1771 : void MSTransformManager::fillIdCols(vi::VisBuffer2 *vb,RefRows &rowRef)
6067 : {
6068 : // Declare common auxiliary variables
6069 1771 : RefRows absoluteRefRows(rowRef.firstRow(),rowRef.firstRow()+nRowsToAdd_p-1);
6070 1771 : Vector<Int> tmpVectorInt(nRowsToAdd_p,0);
6071 1771 : Vector<Double> tmpVectorDouble(nRowsToAdd_p,0.0);
6072 1771 : Vector<bool> tmpVectorbool(nRowsToAdd_p,false);
6073 :
6074 : // Special case for Data description Id
6075 1771 : if (transformDDIVector(vb->dataDescriptionIds(),tmpVectorInt))
6076 : {
6077 1771 : outputMsCols_p->dataDescId().putColumnCells(absoluteRefRows,tmpVectorInt);
6078 : }
6079 : else
6080 : {
6081 0 : outputMsCols_p->dataDescId().putColumnCells(absoluteRefRows,vb->dataDescriptionIds());
6082 : }
6083 :
6084 : // Re-indexable Columns
6085 1771 : transformAndWriteReindexableVector(vb->observationId(),tmpVectorInt,true,
6086 1771 : inputOutputObservationIndexMap_p,
6087 1771 : outputMsCols_p->observationId(),absoluteRefRows);
6088 1771 : transformAndWriteReindexableVector(vb->arrayId(),tmpVectorInt,true,
6089 1771 : inputOutputArrayIndexMap_p,
6090 1771 : outputMsCols_p->arrayId(),absoluteRefRows);
6091 1771 : transformAndWriteReindexableVector(vb->fieldId(),tmpVectorInt,!timespan_p.contains("field"),
6092 1771 : inputOutputFieldIndexMap_p,
6093 1771 : outputMsCols_p->fieldId(),absoluteRefRows);
6094 1771 : transformAndWriteReindexableVector(vb->stateId(),tmpVectorInt,!timespan_p.contains("state"),
6095 1771 : inputOutputScanIntentIndexMap_p,
6096 1771 : outputMsCols_p->stateId(),absoluteRefRows);
6097 1771 : transformAndWriteReindexableVector(vb->antenna1(),tmpVectorInt,false,
6098 1771 : inputOutputAntennaIndexMap_p,
6099 1771 : outputMsCols_p->antenna1(),absoluteRefRows);
6100 1771 : transformAndWriteReindexableVector(vb->antenna2(),tmpVectorInt,false,
6101 1771 : inputOutputAntennaIndexMap_p,
6102 1771 : outputMsCols_p->antenna2(),absoluteRefRows);
6103 :
6104 : // Not Re-indexable Columns
6105 1771 : transformAndWriteNotReindexableVector(vb->scan(),tmpVectorInt,!timespan_p.contains("scan"),outputMsCols_p->scanNumber(),absoluteRefRows);
6106 1771 : transformAndWriteNotReindexableVector(vb->processorId(),tmpVectorInt,false,outputMsCols_p->processorId(),absoluteRefRows);
6107 1771 : transformAndWriteNotReindexableVector(vb->feed1(),tmpVectorInt,false,outputMsCols_p->feed1(),absoluteRefRows);
6108 1771 : transformAndWriteNotReindexableVector(vb->feed2(),tmpVectorInt,false,outputMsCols_p->feed2(),absoluteRefRows);
6109 1771 : transformAndWriteNotReindexableVector(vb->time(),tmpVectorDouble,false,outputMsCols_p->time(),absoluteRefRows);
6110 1771 : transformAndWriteNotReindexableVector(vb->timeCentroid(),tmpVectorDouble,false,outputMsCols_p->timeCentroid(),absoluteRefRows);
6111 1771 : transformAndWriteNotReindexableVector(vb->timeInterval(),tmpVectorDouble,false,outputMsCols_p->interval(),absoluteRefRows);
6112 :
6113 : // Special case for vectors that have to be averaged
6114 1771 : if (combinespws_p)
6115 : {
6116 0 : mapAndAverageVector(vb->flagRow(),tmpVectorbool);
6117 0 : outputMsCols_p->flagRow().putColumnCells(absoluteRefRows, tmpVectorbool);
6118 :
6119 : // jagonzal: We average exposures by default, if they are the same we obtain the same results
6120 0 : mapAndAverageVector(vb->exposure(),tmpVectorDouble);
6121 0 : outputMsCols_p->exposure().putColumnCells(absoluteRefRows, tmpVectorDouble);
6122 : }
6123 : else
6124 : {
6125 1771 : transformAndWriteNotReindexableVector(vb->flagRow(),tmpVectorbool,false,outputMsCols_p->flagRow(),absoluteRefRows);
6126 1771 : transformAndWriteNotReindexableVector(vb->exposure(),tmpVectorDouble,false,outputMsCols_p->exposure(),absoluteRefRows);
6127 : }
6128 :
6129 1771 : if (combinespws_p)
6130 : {
6131 0 : Matrix<Double> tmpUvw(IPosition(2,3,rowRef.nrows()),0.0);
6132 0 : Matrix<Float> tmpMatrixFloat(IPosition(2,vb->nCorrelations(),rowRef.nrows()),0.0);
6133 :
6134 0 : mapMatrix(vb->uvw(),tmpUvw);
6135 0 : writeMatrix(tmpUvw,outputMsCols_p->uvw(),rowRef,nspws_p);
6136 :
6137 : // WEIGHT/SIGMA are defined as the median of WEIGHT_SPECTRUM / SIGMA_SPECTRUM in the case of SPECTRUM transformation
6138 0 : if (not spectrumTransformation_p)
6139 : {
6140 0 : if (newWeightFactorMap_p.size() > 0)
6141 : {
6142 0 : mapAndScaleMatrix(vb->weight(),tmpMatrixFloat,newWeightFactorMap_p,vb->spectralWindows());
6143 0 : writeMatrix(tmpMatrixFloat,outputMsCols_p->weight(),rowRef,nspws_p);
6144 : }
6145 : else
6146 : {
6147 : // jagonzal: According to dpetry we have to copy weights from the first SPW
6148 : // This is justified since the rows to be combined _must_ be from the
6149 : // same baseline and therefore have the same UVW coordinates in the MS (in meters).
6150 : // They could therefore be regarded to also have the same WEIGHT, at least to
6151 : // a good approximation.
6152 0 : mapMatrix(vb->weight(),tmpMatrixFloat);
6153 0 : writeMatrix(tmpMatrixFloat,outputMsCols_p->weight(),rowRef,nspws_p);
6154 : }
6155 :
6156 :
6157 : // Sigma must be redefined to 1/weight when corrected data becomes data
6158 0 : if (correctedToData_p)
6159 : {
6160 0 : arrayTransformInPlace(tmpMatrixFloat, vi::AveragingTvi2::weightToSigma);
6161 0 : outputMsCols_p->sigma().putColumnCells(rowRef, tmpMatrixFloat);
6162 0 : writeMatrix(tmpMatrixFloat,outputMsCols_p->sigma(),rowRef,nspws_p);
6163 : }
6164 : else
6165 : {
6166 0 : if (newSigmaFactorMap_p.size() > 0)
6167 : {
6168 0 : mapAndScaleMatrix(vb->sigma(),tmpMatrixFloat,newSigmaFactorMap_p,vb->spectralWindows());
6169 0 : outputMsCols_p->sigma().putColumnCells(rowRef, tmpMatrixFloat);
6170 0 : writeMatrix(tmpMatrixFloat,outputMsCols_p->sigma(),rowRef,nspws_p);
6171 : }
6172 : else
6173 : {
6174 : // jagonzal: According to dpetry we have to copy weights from the first SPW
6175 : // This is justified since the rows to be combined _must_ be from the
6176 : // same baseline and therefore have the same UVW coordinates in the MS (in meters).
6177 : // They could therefore be regarded to also have the same WEIGHT, at least to
6178 : // a good approximation.
6179 0 : mapMatrix(vb->sigma(),tmpMatrixFloat);
6180 0 : writeMatrix(tmpMatrixFloat,outputMsCols_p->sigma(),rowRef,nspws_p);
6181 : }
6182 : }
6183 : }
6184 :
6185 0 : }
6186 : else
6187 : {
6188 1771 : writeMatrix(vb->uvw(),outputMsCols_p->uvw(),rowRef,nspws_p);
6189 :
6190 : // WEIGHT/SIGMA are defined as the median of WEIGHT_SPECTRUM / SIGMA_SPECTRUM in the case of SPECTRUM transformation
6191 1771 : if (not spectrumTransformation_p)
6192 : {
6193 1182 : if (correctedToData_p) {
6194 :
6195 : // weight -> weight
6196 1080 : Matrix<Float> weights = vb->weight();
6197 1080 : if (newWeightFactorMap_p.size() > 0)
6198 : {
6199 0 : if ( (newWeightFactorMap_p.find(vb->spectralWindows()(0)) != newWeightFactorMap_p.end()) and
6200 0 : (newWeightFactorMap_p[vb->spectralWindows()(0)] != 1) )
6201 : {
6202 0 : weights *= newWeightFactorMap_p[vb->spectralWindows()(0)];
6203 : }
6204 : }
6205 1080 : writeMatrix(weights,outputMsCols_p->weight(),rowRef,nspws_p);
6206 :
6207 : // weight -> sigma
6208 1080 : arrayTransformInPlace(weights, vi::AveragingTvi2::weightToSigma);
6209 1080 : writeMatrix(weights,outputMsCols_p->sigma(),rowRef,nspws_p);
6210 :
6211 1080 : }
6212 102 : else if(!bothDataColumnsAreOutput_p)
6213 : {
6214 : // sigma -> sigma
6215 30 : Matrix<Float> sigma = vb->sigma();
6216 30 : if (newSigmaFactorMap_p.size() > 0)
6217 : {
6218 0 : if ( (newSigmaFactorMap_p.find(vb->spectralWindows()(0)) != newSigmaFactorMap_p.end()) and
6219 0 : (newSigmaFactorMap_p[vb->spectralWindows()(0)] != 1) )
6220 : {
6221 0 : sigma *= newSigmaFactorMap_p[vb->spectralWindows()(0)];
6222 : }
6223 : }
6224 30 : writeMatrix(sigma,outputMsCols_p->sigma(),rowRef,nspws_p);
6225 :
6226 : // sigma -> weight
6227 30 : arrayTransformInPlace(sigma, vi::AveragingTvi2::sigmaToWeight);
6228 30 : writeMatrix(sigma, outputMsCols_p->weight(), rowRef, nspws_p);
6229 30 : }
6230 : // If both DATA and DATA_CORRECTED are input and output then
6231 : // SIGMA(_SPECTRUM) and WEIGHT(_SPECTRUM) should maintain their alignment
6232 : // with DATA and CORRECTED_DATA, respectively and nothing is done. See CAS-11139
6233 : else
6234 : {
6235 : // weight -> weight
6236 72 : Matrix<Float> weights = vb->weight();
6237 72 : if (newWeightFactorMap_p.size() > 0)
6238 : {
6239 0 : if ( (newWeightFactorMap_p.find(vb->spectralWindows()(0)) != newWeightFactorMap_p.end()) and
6240 0 : (newWeightFactorMap_p[vb->spectralWindows()(0)] != 1) )
6241 : {
6242 0 : weights *= newWeightFactorMap_p[vb->spectralWindows()(0)];
6243 : }
6244 : }
6245 72 : writeMatrix(weights,outputMsCols_p->weight(),rowRef,nspws_p);
6246 :
6247 : // sigma -> sigma
6248 72 : Matrix<Float> sigma = vb->sigma();
6249 72 : if (newSigmaFactorMap_p.size() > 0)
6250 : {
6251 0 : if ( (newSigmaFactorMap_p.find(vb->spectralWindows()(0)) != newSigmaFactorMap_p.end()) and
6252 0 : (newSigmaFactorMap_p[vb->spectralWindows()(0)] != 1) )
6253 : {
6254 0 : sigma *= newSigmaFactorMap_p[vb->spectralWindows()(0)];
6255 : }
6256 : }
6257 72 : writeMatrix(sigma,outputMsCols_p->sigma(),rowRef,nspws_p);
6258 72 : }
6259 : }
6260 : }
6261 :
6262 3542 : return;
6263 1771 : }
6264 :
6265 : // ------------------------------------------------------------------------------------
6266 : //
6267 : // ------------------------------------------------------------------------------------
6268 15939 : template <class T> void MSTransformManager::transformAndWriteNotReindexableVector( const Vector<T> &inputVector,
6269 : Vector<T> &outputVector,
6270 : bool constant,
6271 : ScalarColumn<T> &outputCol,
6272 : RefRows &rowReference)
6273 : {
6274 15939 : bool transformed = transformNotReindexableVector(inputVector,outputVector,constant);
6275 :
6276 15939 : if (transformed)
6277 : {
6278 0 : outputCol.putColumnCells(rowReference, outputVector);
6279 : }
6280 : else
6281 : {
6282 15939 : outputCol.putColumnCells(rowReference, inputVector);
6283 : }
6284 :
6285 15939 : return;
6286 : };
6287 :
6288 : // ------------------------------------------------------------------------------------
6289 : //
6290 : // ------------------------------------------------------------------------------------
6291 10626 : template <class T> void MSTransformManager::transformAndWriteReindexableVector( const Vector<T> &inputVector,
6292 : Vector<T> &outputVector,
6293 : bool constant,
6294 : map<uInt,uInt> &inputOutputIndexMap,
6295 : ScalarColumn<T> &outputCol,
6296 : RefRows &rowReference)
6297 : {
6298 10626 : bool transformed = transformReindexableVector(inputVector,outputVector,constant,inputOutputIndexMap);
6299 :
6300 10626 : if (transformed)
6301 : {
6302 8 : outputCol.putColumnCells(rowReference, outputVector);
6303 : }
6304 : else
6305 : {
6306 10618 : outputCol.putColumnCells(rowReference, inputVector);
6307 : }
6308 :
6309 10626 : return;
6310 : };
6311 :
6312 : // ------------------------------------------------------------------------------------
6313 : //
6314 : // ------------------------------------------------------------------------------------
6315 1771 : bool MSTransformManager::transformDDIVector(const Vector<Int> &inputVector,Vector<Int> &outputVector)
6316 : {
6317 1771 : bool transformed = true;
6318 :
6319 1771 : if ((combinespws_p) or (nspws_p > 1))
6320 : {
6321 0 : if (nspws_p > 1)
6322 : {
6323 0 : uInt absoluteIndex = 0;
6324 0 : for (uInt index=0; index<rowIndex_p.size();index++)
6325 : {
6326 0 : for (uInt spwIndex=0;spwIndex < nspws_p; spwIndex++)
6327 : {
6328 0 : outputVector(absoluteIndex) = ddiStart_p + spwIndex;
6329 0 : absoluteIndex += 1;
6330 : }
6331 : }
6332 : }
6333 : else
6334 : {
6335 0 : outputVector = ddiStart_p;
6336 : }
6337 0 : }
6338 : else
6339 : {
6340 1771 : transformed = transformReindexableVector(inputVector,outputVector,true,inputOutputDDIndexMap_p);
6341 : }
6342 :
6343 1771 : return transformed;
6344 : }
6345 :
6346 : // ------------------------------------------------------------------------------------
6347 : //
6348 : // ------------------------------------------------------------------------------------
6349 0 : void MSTransformManager::mapAndAverageVector( const Vector<Double> &inputVector,
6350 : Vector<Double> &outputVector)
6351 : {
6352 0 : Double vec_average = 0;
6353 0 : vector<uInt> baselineRows;
6354 0 : uInt row, counts, absoluteIndex = 0;
6355 0 : for (baselineMap::iterator iter = baselineMap_p.begin(); iter != baselineMap_p.end(); iter++)
6356 : {
6357 : // Get baseline rows vector
6358 0 : baselineRows = iter->second;
6359 :
6360 : // Compute combined value from each SPW
6361 0 : counts = 0;
6362 :
6363 0 : for (auto iter_row = baselineRows.begin();iter_row != baselineRows.end(); iter_row++)
6364 : {
6365 0 : row = *iter_row;
6366 0 : if (counts == 0)
6367 : {
6368 0 : vec_average = inputVector(row);
6369 : }
6370 : else
6371 : {
6372 0 : vec_average += inputVector(row);
6373 : }
6374 :
6375 0 : counts += 1;
6376 : }
6377 :
6378 : // Normalize value
6379 0 : if (counts) vec_average /= counts;
6380 :
6381 : // Set value in output vector
6382 0 : for (uInt spwIndex=0;spwIndex < nspws_p; spwIndex++)
6383 : {
6384 0 : outputVector(absoluteIndex) = vec_average;
6385 0 : absoluteIndex += 1;
6386 : }
6387 : }
6388 :
6389 0 : return;
6390 0 : }
6391 :
6392 : // ------------------------------------------------------------------------------------
6393 : //
6394 : // ------------------------------------------------------------------------------------
6395 0 : void MSTransformManager::mapAndAverageVector( const Vector<bool> &inputVector,
6396 : Vector<bool> &outputVector)
6397 : {
6398 0 : bool vec_average = false;
6399 0 : vector<uInt> baselineRows;
6400 0 : uInt row, counts, absoluteIndex = 0;
6401 0 : for (baselineMap::iterator iter = baselineMap_p.begin(); iter != baselineMap_p.end(); iter++)
6402 : {
6403 : // Get baseline rows vector
6404 0 : baselineRows = iter->second;
6405 :
6406 : // Compute combined value from each SPW
6407 0 : counts = 0;
6408 :
6409 0 : for (auto iter_row = baselineRows.begin();iter_row != baselineRows.end(); iter_row++)
6410 : {
6411 0 : row = *iter_row;
6412 0 : if (counts == 0)
6413 : {
6414 0 : vec_average = inputVector(row);
6415 : }
6416 : else
6417 : {
6418 0 : vec_average &= inputVector(row);
6419 : }
6420 : }
6421 :
6422 : // Set value in output vector
6423 0 : for (uInt spwIndex=0;spwIndex < nspws_p; spwIndex++)
6424 : {
6425 0 : outputVector(absoluteIndex) = vec_average;
6426 0 : absoluteIndex += 1;
6427 : }
6428 : }
6429 :
6430 0 : return;
6431 0 : }
6432 :
6433 :
6434 : // -----------------------------------------------------------------------------------
6435 : // Fill the data from an input matrix with shape [nCol,nBaselinesxnSPWs] into an
6436 : // output matrix with shape [nCol,nBaselines] accumulating the averaging from all SPWS
6437 : // -----------------------------------------------------------------------------------
6438 : template <class T> void MSTransformManager::mapAndAverageMatrix( const Matrix<T> &inputMatrix,
6439 : Matrix<T> &outputMatrix,
6440 : bool convolveFlags,
6441 : vi::VisBuffer2 *vb)
6442 : {
6443 : // Get number of columns
6444 : uInt nCols = outputMatrix.shape()(0);
6445 :
6446 : // Access FLAG_ROW in case we need to convolute the average
6447 : Vector<bool> flags;
6448 : if (convolveFlags) flags = vb->flagRow();
6449 :
6450 : // Fill output array with the combined data from each SPW
6451 : uInt row;
6452 : uInt baseline_index = 0;
6453 : Double normalizingFactor = 0;
6454 : Double contributionFactor = 0;
6455 : vector<uInt> baselineRows;
6456 : for (baselineMap::iterator iter = baselineMap_p.begin(); iter != baselineMap_p.end(); iter++)
6457 : {
6458 : // Get baseline rows vector
6459 : baselineRows = iter->second;
6460 :
6461 : // Reset normalizing factor
6462 : normalizingFactor = 0;
6463 :
6464 : // Compute combined value from each SPW
6465 : for (vector<uInt>::iterator iter_row = baselineRows.begin();iter_row != baselineRows.end(); iter_row++)
6466 : {
6467 : row = *iter_row;
6468 : if (convolveFlags)
6469 : {
6470 : contributionFactor = !flags(row);
6471 : }
6472 : else
6473 : {
6474 : contributionFactor = 1;
6475 : }
6476 :
6477 : for (uInt col = 0; col < nCols; col++)
6478 : {
6479 : outputMatrix(col,baseline_index) += contributionFactor*inputMatrix(col,row);
6480 : }
6481 :
6482 : normalizingFactor += contributionFactor;
6483 : }
6484 :
6485 : // Normalize accumulated value
6486 : if (normalizingFactor>0)
6487 : {
6488 : for (uInt col = 0; col < nCols; col++)
6489 : {
6490 : outputMatrix(col,baseline_index) /= normalizingFactor;
6491 : }
6492 : }
6493 :
6494 : baseline_index += 1;
6495 : }
6496 :
6497 : return;
6498 : }
6499 :
6500 : // -----------------------------------------------------------------------
6501 : //
6502 : // -----------------------------------------------------------------------
6503 0 : template <class T> void MSTransformManager::mapAndScaleMatrix( const Matrix<T> &inputMatrix,
6504 : Matrix<T> &outputMatrix,
6505 : map<uInt,T> scaleMap,
6506 : Vector<Int> spws)
6507 : {
6508 : // Reset output Matrix
6509 0 : outputMatrix = 0;
6510 :
6511 : // Get number of columns
6512 0 : uInt nCols = outputMatrix.shape()(0);
6513 :
6514 : // Fill output array with the combined data from each SPW
6515 : Int spw;
6516 : uInt row;
6517 0 : uInt baseline_index = 0;
6518 0 : vector<uInt> baselineRows;
6519 : T contributionFactor;
6520 0 : for (baselineMap::iterator iter = baselineMap_p.begin(); iter != baselineMap_p.end(); iter++)
6521 : {
6522 : // Get baseline rows vector
6523 0 : baselineRows = iter->second;
6524 :
6525 : // Reset normalizing factor
6526 :
6527 : // Get value from first SPW (this is for Weight and Sigma and cvel is doing it so)
6528 0 : row = baselineRows.at(0);
6529 0 : spw = spws(row);
6530 0 : if (scaleMap.find(spw) != scaleMap.end())
6531 : {
6532 0 : contributionFactor = scaleMap[spw];
6533 : }
6534 : else
6535 : {
6536 0 : contributionFactor = 1;
6537 : }
6538 :
6539 0 : for (uInt col = 0; col < nCols; col++)
6540 : {
6541 0 : outputMatrix(col,baseline_index) = contributionFactor*inputMatrix(col,row);
6542 : }
6543 :
6544 0 : baseline_index += 1;
6545 : }
6546 :
6547 0 : return;
6548 0 : }
6549 :
6550 :
6551 : // ----------------------------------------------------------------------------------------
6552 : // Fill main (data) columns which have to be combined together to produce bigger SPWs
6553 : // ----------------------------------------------------------------------------------------
6554 1771 : void MSTransformManager::fillDataCols(vi::VisBuffer2 *vb,RefRows &rowRef)
6555 : {
6556 1771 : ArrayColumn<bool> *outputFlagCol=NULL;
6557 4760 : for (dataColMap::iterator iter = dataColMap_p.begin();iter != dataColMap_p.end();iter++)
6558 : {
6559 : // Get applicable *_SPECTRUM (copy constructor uses reference semantics)
6560 : // If channel average or combine, otherwise no need to copy
6561 2989 : const Cube<Float> &applicableSpectrum = getApplicableSpectrum(vb,iter->first);
6562 :
6563 : // Apply transformations
6564 2989 : switch (iter->first)
6565 : {
6566 691 : case MS::DATA:
6567 : {
6568 691 : if (mainColumn_p == MS::DATA)
6569 : {
6570 691 : outputFlagCol = &(outputMsCols_p->flag());
6571 691 : setTileShape(rowRef,outputMsCols_p->flag());
6572 : }
6573 : else
6574 : {
6575 0 : outputFlagCol = NULL;
6576 : }
6577 :
6578 691 : setTileShape(rowRef,outputMsCols_p->data());
6579 691 : transformCubeOfData(vb,rowRef,vb->visCube(),outputMsCols_p->data(), outputFlagCol,applicableSpectrum);
6580 :
6581 691 : break;
6582 : }
6583 1689 : case MS::CORRECTED_DATA:
6584 : {
6585 1689 : if (mainColumn_p == MS::CORRECTED_DATA)
6586 : {
6587 1080 : outputFlagCol = &(outputMsCols_p->flag());
6588 1080 : setTileShape(rowRef,outputMsCols_p->flag());
6589 : }
6590 : else
6591 : {
6592 609 : outputFlagCol = NULL;
6593 : }
6594 :
6595 1689 : if (iter->second == MS::DATA)
6596 : {
6597 1080 : setTileShape(rowRef,outputMsCols_p->data());
6598 1080 : transformCubeOfData(vb,rowRef,vb->visCubeCorrected(),outputMsCols_p->data(), outputFlagCol,applicableSpectrum);
6599 : }
6600 : else
6601 : {
6602 609 : setTileShape(rowRef,outputMsCols_p->correctedData());
6603 609 : transformCubeOfData(vb,rowRef,vb->visCubeCorrected(),outputMsCols_p->correctedData(), outputFlagCol,applicableSpectrum);
6604 : }
6605 :
6606 1689 : break;
6607 : }
6608 609 : case MS::MODEL_DATA:
6609 : {
6610 609 : if (mainColumn_p == MS::MODEL_DATA)
6611 : {
6612 0 : outputFlagCol = &(outputMsCols_p->flag());
6613 0 : setTileShape(rowRef,outputMsCols_p->flag());
6614 : }
6615 : else
6616 : {
6617 609 : outputFlagCol = NULL;
6618 : }
6619 :
6620 609 : if (produceModel_p)
6621 : {
6622 : // irrespective of wheter iter->second == MS::DATA
6623 : // or iter->second == MS::CORRECTED_DATA
6624 0 : setTileShape(rowRef,outputMsCols_p->modelData());
6625 0 : transformCubeOfData(vb,rowRef,vb->visCubeModel(),outputMsCols_p->modelData(), outputFlagCol,applicableSpectrum);
6626 609 : } else if (iter->second == MS::DATA) {
6627 0 : setTileShape(rowRef,outputMsCols_p->data());
6628 0 : transformCubeOfData(vb,rowRef,vb->visCubeModel(),outputMsCols_p->data(), outputFlagCol,applicableSpectrum);
6629 : }
6630 : else
6631 : {
6632 609 : setTileShape(rowRef,outputMsCols_p->modelData());
6633 609 : transformCubeOfData(vb,rowRef,vb->visCubeModel(),outputMsCols_p->modelData(), outputFlagCol,applicableSpectrum);
6634 : }
6635 609 : break;
6636 : }
6637 0 : case MS::FLOAT_DATA:
6638 : {
6639 0 : if (mainColumn_p == MS::FLOAT_DATA)
6640 : {
6641 0 : outputFlagCol = &(outputMsCols_p->flag());
6642 0 : setTileShape(rowRef,outputMsCols_p->flag());
6643 : }
6644 : else
6645 : {
6646 0 : outputFlagCol = NULL;
6647 : }
6648 :
6649 0 : setTileShape(rowRef,outputMsCols_p->floatData());
6650 0 : transformCubeOfData(vb,rowRef,vb->visCubeFloat(),outputMsCols_p->floatData(), outputFlagCol,applicableSpectrum);
6651 :
6652 0 : break;
6653 : }
6654 0 : case MS::LAG_DATA:
6655 : {
6656 : // jagonzal: TODO
6657 0 : break;
6658 : }
6659 0 : default:
6660 : {
6661 : // jagonzal: TODO
6662 0 : break;
6663 : }
6664 : }
6665 : }
6666 :
6667 : // Special case for flag category
6668 1771 : if (inputFlagCategoryAvailable_p)
6669 : {
6670 0 : if (spectrumReshape_p)
6671 : {
6672 0 : IPosition transformedCubeShape = getShape(); //[nC,nF,nR]
6673 0 : IPosition inputFlagCategoryShape = vb->flagCategory().shape(); // [nC,nF,nCategories,nR]
6674 0 : IPosition flagCategoryShape(4, inputFlagCategoryShape(1),
6675 0 : transformedCubeShape(2),
6676 0 : inputFlagCategoryShape(2),
6677 0 : transformedCubeShape(2));
6678 0 : Array<bool> flagCategory(flagCategoryShape,false);
6679 :
6680 0 : outputMsCols_p->flagCategory().putColumnCells(rowRef, flagCategory);
6681 0 : }
6682 : else
6683 : {
6684 0 : outputMsCols_p->flagCategory().putColumnCells(rowRef, vb->flagCategory());
6685 : }
6686 : }
6687 :
6688 1771 : return;
6689 : }
6690 :
6691 : // ----------------------------------------------------------------------------------------
6692 : // Fill weight cols (WEIGHT_SPECTRUM and SIGMA_SPECTRUM) as well as WEIGHT/SIGMA which have to be derived from it using median
6693 : // ----------------------------------------------------------------------------------------
6694 1771 : void MSTransformManager::fillWeightCols(vi::VisBuffer2 *vb,RefRows &rowRef)
6695 : {
6696 : // WEIGHT_SPECTRUM and SIGMA_SPECTRUM are only filled if requested or when WEIGHT_SPECTRUM is present in the input MS
6697 : // But WEIGHT/SIGMA have always to be derived from in-memory WEIGHT_SPECTRUM/SIGMA_SPECTRUM
6698 1771 : if (flushWeightSpectrum_p or spectrumTransformation_p or userBufferMode_p)
6699 : {
6700 : // Switch aux Weight propagation off
6701 591 : propagateWeights(false);
6702 :
6703 : // Switch average and smooth kernels
6704 591 : setChannelAverageKernel(MSTransformations::flagCumSumNonZero);
6705 591 : setSmoothingKernel(MSTransformations::plainSmoothSpectrum);
6706 591 : setSmoothingFourierKernel(MSTransformations::plainSmoothSpectrum);
6707 :
6708 : // Dummy auxiliary weightSpectrum
6709 591 : const Cube<Float> applicableSpectrum;
6710 :
6711 591 : if (spectrumTransformation_p)
6712 : {
6713 : // For SPW separation:
6714 : // Prepare RowReference for spectrum transformations
6715 : // (all data is flushed at once instead of blocks)
6716 589 : RefRows rowRefSpectrum(rowRef.firstRow(), rowRef.firstRow() + nRowsToAdd_p-1);
6717 :
6718 : // Switch on buffer mode
6719 589 : Cube<Float> transformedSpectrum;
6720 589 : Cube<bool> transformedFlag;
6721 589 : if (not userBufferMode_p)
6722 : {
6723 589 : setBufferMode(true);
6724 589 : dataBuffer_p = MSTransformations::weightSpectrum;
6725 589 : transformedSpectrum.resize(getShape(),false);
6726 589 : weightSpectrum_p = &transformedSpectrum;
6727 589 : transformedFlag.resize(getShape(),false);
6728 589 : flagCube_p = &transformedFlag; // Not used for the output but to extract the average/median
6729 : }
6730 :
6731 :
6732 : // Multiple column operation
6733 589 : if (doingData_p and doingCorrected_p)
6734 : {
6735 : // Transform WEIGHT_SPECTRUM but don't derive SIGMA_SPECTRUM from it
6736 537 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6737 : getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),
6738 : getOutputWeightColumn(vb,MS::WEIGHT),
6739 537 : MSTransformations::transformWeight,flushWeightSpectrum_p);
6740 :
6741 : // Convert SIGMA_SPECTRUM to WEIGHT format, transform it and derive SIGMA_SPECTRUM from it
6742 537 : transformAndWriteSpectrum( vb,rowRefSpectrum,getWeightSpectrumFromSigmaSpectrum(vb),
6743 : getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),
6744 : getOutputWeightColumn(vb,MS::SIGMA),
6745 537 : MSTransformations::transformWeightIntoSigma,flushWeightSpectrum_p);
6746 : }
6747 : // In case of time average we can use directly WEIGHT_SPECTRUM because
6748 : // AveragingTvi2 derives it from the input SIGMA_SPECTRUM or WEIGHT_SPECTRUM
6749 : // depending on the selected DATA column
6750 52 : else if (timeAverage_p)
6751 : {
6752 : // Transform WEIGHT_SPECTRUM
6753 12 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6754 : getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),
6755 : getOutputWeightColumn(vb,MS::WEIGHT),
6756 12 : MSTransformations::transformWeight,flushWeightSpectrum_p);
6757 :
6758 : // Derive SIGMA_SPECTRUM from WEIGHT_SPECTRUM
6759 12 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6760 : getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),
6761 : getOutputWeightColumn(vb,MS::SIGMA),
6762 12 : MSTransformations::weightIntoSigma,flushWeightSpectrum_p);
6763 : }
6764 : // DATA to DATA: Convert SIGMA_SPECTRUM to WEIGHT format, transform it and derive SIGMA_SPECTRUM from it
6765 40 : else if (doingData_p)
6766 : {
6767 : // Transform WEIGHT_SPECTRUM
6768 40 : transformAndWriteSpectrum( vb,rowRefSpectrum,getWeightSpectrumFromSigmaSpectrum(vb),
6769 : getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),
6770 : getOutputWeightColumn(vb,MS::WEIGHT),
6771 40 : MSTransformations::transformWeight,flushWeightSpectrum_p);
6772 :
6773 : // Derive SIGMA_SPECTRUM from WEIGHT_SPECTRUM
6774 40 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6775 : getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),
6776 : getOutputWeightColumn(vb,MS::SIGMA),
6777 40 : MSTransformations::weightIntoSigma,flushWeightSpectrum_p);
6778 : }
6779 : // CORRECTED to DATA: Transform WEIGHT_SPECTRUM and derive SIGMA_SPECTRUM from it
6780 0 : else if (doingCorrected_p) // CORRECTED to DATA
6781 : {
6782 : // Transform WEIGHT_SPECTRUM
6783 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6784 : getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),
6785 : getOutputWeightColumn(vb,MS::WEIGHT),
6786 0 : MSTransformations::transformWeight,flushWeightSpectrum_p);
6787 :
6788 : // Derive SIGMA_SPECTRUM from WEIGHT_SPECTRUM
6789 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6790 : getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),
6791 : getOutputWeightColumn(vb,MS::SIGMA),
6792 0 : MSTransformations::weightIntoSigma,flushWeightSpectrum_p);
6793 : }
6794 : // MODEL to DATA: Calculate WEIGHT_SPECTRUM using FLAG and derive SIGMA_SPECTRUM from it
6795 0 : else if (doingModel_p)
6796 : {
6797 : // Transform WEIGHT_SPECTRUM
6798 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,getWeightSpectrumFlat(vb),
6799 : getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),
6800 : getOutputWeightColumn(vb,MS::WEIGHT),
6801 0 : MSTransformations::transformWeight,flushWeightSpectrum_p);
6802 :
6803 : // Derive SIGMA_SPECTRUM from WEIGHT_SPECTRUM
6804 0 : transformAndWriteSpectrum( vb,rowRefSpectrum,vb->weightSpectrum(),
6805 : getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),
6806 : getOutputWeightColumn(vb,MS::SIGMA),
6807 0 : MSTransformations::weightIntoSigma,flushWeightSpectrum_p);
6808 : }
6809 :
6810 : // Switch off buffer mode
6811 589 : if (not userBufferMode_p)
6812 : {
6813 589 : setBufferMode(false);
6814 589 : weightSpectrum_p = NULL;
6815 : }
6816 589 : }
6817 : // Within AveragingTvi2 SIGMA_SPECTRUM is already re-defined to 1/sqrt(WEIGHT_SPECTRUM) if CORRECTED->DATA
6818 : // or obtained from the input SIGMA_SPECTRUM in the case of DATA->DATA or multiple column operation
6819 2 : else if (timeAverage_p)
6820 : {
6821 : // TransformCubeOfData is either copyCubeOfData or separateCubeOfData
6822 0 : if (userBufferMode_p)
6823 : {
6824 0 : dataBuffer_p = MSTransformations::weightSpectrum;
6825 : }
6826 : else
6827 : {
6828 0 : setTileShape(rowRef,getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM));
6829 : }
6830 0 : transformCubeOfData(vb,rowRef,vb->weightSpectrum(),getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),NULL,applicableSpectrum);
6831 :
6832 0 : if (userBufferMode_p)
6833 : {
6834 0 : dataBuffer_p = MSTransformations::sigmaSpectrum;
6835 : }
6836 : else
6837 : {
6838 0 : setTileShape(rowRef,getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM));
6839 : }
6840 0 : transformCubeOfData(vb,rowRef,vb->sigmaSpectrum(),getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),NULL,applicableSpectrum);
6841 : }
6842 : // When CORRECTED becomes DATA, then SIGMA_SPECTRUM has to be re-defined to 1/sqrt(WEIGHT_SPECTRUM)
6843 2 : else if (correctedToData_p)
6844 : {
6845 : // TransformCubeOfData is either copyCubeOfData or separateCubeOfData
6846 0 : if (userBufferMode_p)
6847 : {
6848 0 : dataBuffer_p = MSTransformations::weightSpectrum;
6849 : }
6850 : else
6851 : {
6852 0 : setTileShape(rowRef,getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM));
6853 : }
6854 0 : transformCubeOfData(vb,rowRef,vb->weightSpectrum(),getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),NULL,applicableSpectrum);
6855 :
6856 0 : if (userBufferMode_p)
6857 : {
6858 0 : dataBuffer_p = MSTransformations::sigmaSpectrum;
6859 : }
6860 : else
6861 : {
6862 0 : setTileShape(rowRef,getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM));
6863 : }
6864 : // VI/VB only allocates and populates sigmaSpectrum on request
6865 : // But its contents are not usable for this case
6866 : // So we should just create a local storage
6867 0 : Cube<Float> sigmaSpectrum;
6868 0 : sigmaSpectrum = vb->weightSpectrum(); // Copy constructor does not use reference semantics, but deep copy
6869 : // Apply transformation
6870 0 : arrayTransformInPlace(sigmaSpectrum, vi::AveragingTvi2::weightToSigma);
6871 : // TransformCubeOfData is either copyCubeOfData or separateCubeOfData
6872 0 : transformCubeOfData(vb,rowRef,sigmaSpectrum,getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),NULL,applicableSpectrum);
6873 0 : }
6874 : // Pure split operation
6875 : else
6876 : {
6877 : // TransformCubeOfData is either copyCubeOfData or separateCubeOfData
6878 2 : if (userBufferMode_p)
6879 : {
6880 0 : dataBuffer_p = MSTransformations::weightSpectrum;
6881 : }
6882 : else
6883 : {
6884 2 : setTileShape(rowRef,getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM));
6885 : }
6886 2 : transformCubeOfData(vb,rowRef,vb->weightSpectrum(),getOutputWeightColumn(vb,MS::WEIGHT_SPECTRUM),NULL,applicableSpectrum);
6887 :
6888 2 : if (userBufferMode_p)
6889 : {
6890 0 : dataBuffer_p = MSTransformations::sigmaSpectrum;
6891 : }
6892 : else
6893 : {
6894 2 : setTileShape(rowRef,getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM));
6895 : }
6896 2 : transformCubeOfData(vb,rowRef,vb->sigmaSpectrum(),getOutputWeightColumn(vb,MS::SIGMA_SPECTRUM),NULL,applicableSpectrum);
6897 : }
6898 :
6899 : // Switch aux Weight propagation on
6900 591 : propagateWeights(propagateWeights_p);
6901 :
6902 : // Reset average and smooth kernels
6903 591 : setChannelAverageKernel(weightmode_p);
6904 591 : setSmoothingKernel(smoothmode_p);
6905 591 : setSmoothingFourierKernel(MSTransformations::plainSmooth);
6906 591 : }
6907 :
6908 1771 : return;
6909 : }
6910 :
6911 :
6912 : // ----------------------------------------------------------------------------------------
6913 : // Set tile shape
6914 : // ----------------------------------------------------------------------------------------
6915 4764 : template <class T> void MSTransformManager::setTileShape( RefRows &rowRef,
6916 : ArrayColumn<T> &outputDataCol)
6917 : {
6918 4764 : IPosition outputCubeShape = getShape();
6919 4764 : size_t nCorr = outputCubeShape(0);
6920 4764 : size_t nChan = outputCubeShape(1);
6921 4764 : ssize_t nRows = 1048576 / (sizeof(T)*nCorr*nChan);
6922 4764 : IPosition outputPlaneShape(2,nCorr,nChan);
6923 4764 : IPosition tileShape(3,nCorr,nChan,nRows);
6924 :
6925 4764 : outputDataCol.setShape(rowRef.firstRow(),outputPlaneShape,tileShape);
6926 :
6927 9528 : return;
6928 4764 : }
6929 :
6930 : // explicit instatiation for the use from SDMSManager
6931 : template void MSTransformManager::setTileShape<Float>(RefRows &, ArrayColumn<Float> &);
6932 : template void MSTransformManager::setTileShape<bool>(RefRows &, ArrayColumn<bool> &);
6933 : template void MSTransformManager::setTileShape<Complex>(RefRows &, ArrayColumn<Complex> &);
6934 :
6935 : // ----------------------------------------------------------------------------------------
6936 : //
6937 : // ----------------------------------------------------------------------------------------
6938 1178 : void MSTransformManager::transformAndWriteSpectrum( vi::VisBuffer2 *vb,
6939 : RefRows &rowRef,
6940 : const Cube<Float> &inputSpectrum,
6941 : ArrayColumn<Float> &outputCubeCol,
6942 : ArrayColumn<Float> &outputMatrixCol,
6943 : MSTransformations::weightTransformation weightTransformation,
6944 : bool /* flushSpectrumCube */)
6945 : {
6946 : // Dummy auxiliary weightSpectrum
6947 1178 : const Cube<Float> applicableSpectrum;
6948 :
6949 : // Check if weight scaling has to be applied
6950 1178 : Float weightScale = 0, sigmaScale = 0;
6951 1178 : if (refFrameTransformation_p)
6952 : {
6953 0 : if ( (newWeightFactorMap_p.find(vb->spectralWindows()(0)) != newWeightFactorMap_p.end()) and
6954 0 : (newWeightFactorMap_p[vb->spectralWindows()(0)] != 1) )
6955 : {
6956 0 : weightScale = newWeightFactorMap_p[vb->spectralWindows()(0)];
6957 : }
6958 :
6959 0 : if ( (newSigmaFactorMap_p.find(vb->spectralWindows()(0)) != newSigmaFactorMap_p.end()) and
6960 0 : (newSigmaFactorMap_p[vb->spectralWindows()(0)] != 1) )
6961 : {
6962 0 : sigmaScale = newSigmaFactorMap_p[vb->spectralWindows()(0)];
6963 : }
6964 : }
6965 :
6966 : // Apply transformations
6967 1178 : switch (weightTransformation)
6968 : {
6969 589 : case MSTransformations::transformWeight:
6970 : {
6971 589 : dataBuffer_p = MSTransformations::weightSpectrum;
6972 589 : transformCubeOfData(vb,rowRef,inputSpectrum,outputCubeCol,NULL,applicableSpectrum);
6973 :
6974 589 : if (weightScale > 0) *weightSpectrum_p *= weightScale;
6975 :
6976 589 : break;
6977 : }
6978 537 : case MSTransformations::transformWeightIntoSigma:
6979 : {
6980 537 : if (userBufferMode_p)
6981 : {
6982 0 : dataBuffer_p = MSTransformations::sigmaSpectrum;
6983 0 : transformCubeOfData(vb,rowRef,inputSpectrum,outputCubeCol,NULL,applicableSpectrum);
6984 0 : arrayTransformInPlace (*sigmaSpectrum_p,vi::AveragingTvi2::weightToSigma);
6985 :
6986 0 : if (sigmaScale > 0) *sigmaSpectrum_p *= sigmaScale;
6987 : }
6988 : else
6989 : {
6990 537 : transformCubeOfData(vb,rowRef,inputSpectrum,outputCubeCol,NULL,applicableSpectrum);
6991 537 : arrayTransformInPlace (*weightSpectrum_p,vi::AveragingTvi2::weightToSigma);
6992 :
6993 537 : if (sigmaScale > 0) *weightSpectrum_p *= sigmaScale;
6994 : }
6995 :
6996 537 : break;
6997 : }
6998 52 : case MSTransformations::weightIntoSigma:
6999 : {
7000 52 : if (userBufferMode_p)
7001 : {
7002 : // WeightSpectrum is always transformed before sigmaSpectrum
7003 : // so copy weightSpectrum into sigmaSpectrum
7004 0 : sigmaSpectrum_p->operator =(*weightSpectrum_p);
7005 0 : arrayTransformInPlace (*sigmaSpectrum_p,vi::AveragingTvi2::weightToSigma);
7006 :
7007 : // No need to scale in this case as it already happened before
7008 : }
7009 : else
7010 : {
7011 : // WeightSpectrum is always transformed before sigmaSpectrum
7012 : // so transform directly weightSpectrum into sigmaSpectrum
7013 52 : arrayTransformInPlace (*weightSpectrum_p,vi::AveragingTvi2::weightToSigma);
7014 :
7015 : // No need to scale in this case as it already happened before
7016 : }
7017 52 : break;
7018 : }
7019 : }
7020 :
7021 : // Write resulting cube
7022 1178 : if ( (not userBufferMode_p) and flushWeightSpectrum_p)
7023 : {
7024 0 : setTileShape(rowRef,outputCubeCol);
7025 0 : writeCube(*weightSpectrum_p,outputCubeCol,rowRef);
7026 : }
7027 :
7028 : // Extract median matrix (nCorr x nRow)
7029 : // When separating SPWs this procedure computes the mean of each separated SPW
7030 : // Matrix<Float> medians = partialMedians(*weightSpectrum_p,IPosition(1,1),true);
7031 1178 : if (userBufferMode_p)
7032 : {
7033 0 : switch (weightTransformation)
7034 : {
7035 0 : case MSTransformations::transformWeight:
7036 : {
7037 0 : weight_p->operator =(vi::AveragingTvi2::average(*weightSpectrum_p,*flagCube_p));
7038 0 : break;
7039 : }
7040 0 : case MSTransformations::transformWeightIntoSigma:
7041 : {
7042 0 : sigma_p->operator =(vi::AveragingTvi2::average(*sigmaSpectrum_p,*flagCube_p));
7043 0 : break;
7044 : }
7045 0 : case MSTransformations::weightIntoSigma:
7046 : {
7047 0 : sigma_p->operator =(vi::AveragingTvi2::average(*sigmaSpectrum_p,*flagCube_p));
7048 0 : break;
7049 : }
7050 : }
7051 : }
7052 : else
7053 : {
7054 1178 : Matrix<Float> means = vi::AveragingTvi2::average(*weightSpectrum_p,*flagCube_p);
7055 1178 : writeMatrix(means,outputMatrixCol,rowRef,1);
7056 1178 : }
7057 :
7058 2356 : return;
7059 1178 : }
7060 :
7061 : // -----------------------------------------------------------------------
7062 : // Get *_SPECTRUM column to use depending on the input col
7063 : // -----------------------------------------------------------------------
7064 2989 : const Cube<Float>& MSTransformManager::getApplicableSpectrum(vi::VisBuffer2 *vb, MS::PredefinedColumns datacol)
7065 : {
7066 2989 : if (propagateWeights_p)
7067 : {
7068 12 : switch (datacol)
7069 : {
7070 12 : case MS::DATA:
7071 : {
7072 : // NOTE: There is room for optimization here if in the case of
7073 : // A.- Time average and single column operation
7074 : // B.- Single column in the input (George denied this)
7075 : // C.- Time average should not convert SIGMA_SPECTRUM to WEIGHT format if there is chan.avg downstream
7076 : // D.- SIGMA_SPECTRUM should be in WEIGHT format
7077 12 : return getWeightSpectrumFromSigmaSpectrum(vb);
7078 : break;
7079 : }
7080 0 : case MS::CORRECTED_DATA:
7081 : {
7082 0 : return vb->weightSpectrum();
7083 : break;
7084 : }
7085 0 : case MS::MODEL_DATA:
7086 : {
7087 : // Return either WEIGHT_SPECTRUM or SIGMA_SPECTRUM depending on the other accompany col
7088 0 : if (doingCorrected_p)
7089 : {
7090 0 : return vb->weightSpectrum();
7091 : }
7092 0 : else if (doingData_p)
7093 : {
7094 0 : return getWeightSpectrumFromSigmaSpectrum(vb);
7095 : }
7096 : // When doing only MODEL_DATA only FLAG cube is used, and applicable weightSpectrum must be flat unit
7097 : // The same convention is applied in VbAvg::accumulateElementForCubes for time average
7098 : else
7099 : {
7100 0 : return getWeightSpectrumFlat(vb);
7101 : }
7102 :
7103 : break;
7104 : }
7105 0 : default:
7106 : {
7107 0 : return vb->weightSpectrum();
7108 : break;
7109 : }
7110 : }
7111 : }
7112 : else
7113 : {
7114 2977 : return weightSpectrumCubeDummy_p;
7115 : }
7116 : }
7117 :
7118 : // -----------------------------------------------------------------------
7119 : // Get output weight column
7120 : // -----------------------------------------------------------------------
7121 2364 : ArrayColumn<Float>& MSTransformManager::getOutputWeightColumn(vi::VisBuffer2 *, MS::PredefinedColumns datacol)
7122 : {
7123 2364 : if (userBufferMode_p)
7124 : {
7125 0 : return dummyWeightCol_p;
7126 : }
7127 : else
7128 : {
7129 2364 : switch (datacol)
7130 : {
7131 593 : case MS::WEIGHT_SPECTRUM:
7132 : {
7133 593 : return outputMsCols_p->weightSpectrum();
7134 : break;
7135 : }
7136 593 : case MS::SIGMA_SPECTRUM:
7137 : {
7138 593 : return outputMsCols_p->sigmaSpectrum();
7139 : break;
7140 : }
7141 589 : case MS::WEIGHT:
7142 : {
7143 589 : return outputMsCols_p->weight();
7144 : break;
7145 : }
7146 589 : case MS::SIGMA:
7147 : {
7148 589 : return outputMsCols_p->sigma();
7149 : break;
7150 : }
7151 0 : default:
7152 : {
7153 0 : return outputMsCols_p->weight();
7154 : break;
7155 : }
7156 : }
7157 : }
7158 : }
7159 :
7160 :
7161 : // -----------------------------------------------------------------------
7162 : // Pupulate weightSpectrum derived from sigmaSpectrum
7163 : // -----------------------------------------------------------------------
7164 589 : const Cube<Float>& MSTransformManager::getWeightSpectrumFromSigmaSpectrum(vi::VisBuffer2 *vb)
7165 : {
7166 589 : if (weightSpectrumFromSigmaFilled_p)
7167 : {
7168 0 : return weightSpectrumCube_p;
7169 : }
7170 : else
7171 : {
7172 589 : weightSpectrumCube_p.resize(vb->getShape(),false);
7173 589 : weightSpectrumCube_p = vb->sigmaSpectrum(); // = Operator makes a copy
7174 589 : arrayTransformInPlace (weightSpectrumCube_p,vi::AveragingTvi2::sigmaToWeight);
7175 589 : weightSpectrumFromSigmaFilled_p = true;
7176 589 : return weightSpectrumCube_p;
7177 : }
7178 : }
7179 :
7180 : // -----------------------------------------------------------------------
7181 : // Populate a synthetic flat unit weightSpectrum to be use for MODEL_DATA
7182 : // -----------------------------------------------------------------------
7183 0 : const Cube<Float>& MSTransformManager::getWeightSpectrumFlat(vi::VisBuffer2 *vb)
7184 : {
7185 0 : if (weightSpectrumFlatFilled_p)
7186 : {
7187 0 : return weightSpectrumCubeFlat_p;
7188 : }
7189 0 : else if (weightSpectrumCubeFlat_p.shape().isEqual(vb->getShape()))
7190 : {
7191 0 : weightSpectrumFlatFilled_p = true;
7192 0 : return weightSpectrumCubeFlat_p;
7193 : }
7194 : else
7195 : {
7196 0 : weightSpectrumCubeFlat_p.resize(vb->getShape(),false);
7197 0 : weightSpectrumCubeFlat_p = 1.0f;
7198 0 : weightSpectrumFlatFilled_p = true;
7199 0 : return weightSpectrumCubeFlat_p;
7200 : }
7201 : }
7202 :
7203 : // -----------------------------------------------------------------------
7204 : // Generic method to write a Matrix from a VisBuffer into a ArrayColumn
7205 : // -----------------------------------------------------------------------
7206 5313 : template <class T> void MSTransformManager::writeMatrix( const Matrix<T> &inputMatrix,
7207 : ArrayColumn<T> &outputCol,
7208 : RefRows &rowRef,
7209 : uInt nBlocks)
7210 : {
7211 5313 : if (nBlocks == 1)
7212 : {
7213 5313 : outputCol.putColumnCells(rowRef, inputMatrix);
7214 : }
7215 : else
7216 : {
7217 : // jagonzal (CAS-8492): Huge bug, each input row must
7218 : // be copied n times not the whole matrix n times
7219 0 : uInt outRowIdx = 0;
7220 0 : size_t nInputRows = inputMatrix.shape()(1);
7221 0 : Matrix<T> outputMatrix(IPosition(2,3,nInputRows*nBlocks));
7222 0 : for (size_t inputRowIdx = 0; inputRowIdx<nInputRows; inputRowIdx++)
7223 : {
7224 0 : for (uInt blockIdx = 0; blockIdx<nBlocks; blockIdx++)
7225 : {
7226 0 : outputMatrix.column(outRowIdx) = inputMatrix.column(inputRowIdx);
7227 0 : outRowIdx += 1;
7228 : }
7229 : }
7230 :
7231 0 : RefRows outRowRef(rowRef.firstRow(),rowRef.firstRow()+nInputRows*nBlocks-1);
7232 0 : outputCol.putColumnCells(outRowRef, outputMatrix);
7233 :
7234 : /*
7235 : uInt offset = 0;
7236 : for (uInt block_i=0;block_i<nBlocks;block_i++)
7237 : {
7238 : uInt startRow_i = rowRef.firstRow()+offset;
7239 : RefRows rowRef_i(startRow_i, startRow_i+inputMatrix.shape()(1)-1);
7240 : outputCol.putColumnCells(rowRef_i, inputMatrix);
7241 : offset += inputMatrix.shape()(1);
7242 : }
7243 : */
7244 0 : }
7245 5313 : return;
7246 : }
7247 :
7248 : // -----------------------------------------------------------------------
7249 : // Generic method to write a Cube from a VisBuffer into a ArrayColumn
7250 : // -----------------------------------------------------------------------
7251 2512 : template <class T> void MSTransformManager::writeCube( const Cube<T> &inputCube,
7252 : ArrayColumn<T> &outputCol,
7253 : RefRows &rowRef)
7254 : {
7255 2512 : IPosition shape = inputCube.shape();
7256 2512 : shape(2) = rowRef.nrows();
7257 : bool deleteIt;
7258 2512 : Array<T> outputArray(shape,const_cast<T*>(inputCube.getStorage(deleteIt)),SHARE);
7259 2512 : outputCol.putColumnCells(rowRef, outputArray);
7260 :
7261 5024 : return;
7262 2512 : }
7263 :
7264 : // explicit instatiation for the use from SDMSManager
7265 : template void MSTransformManager::writeCube<bool>(const Cube<bool> &, ArrayColumn<bool> &, RefRows &);
7266 :
7267 : // -----------------------------------------------------------------------
7268 : //
7269 : // -----------------------------------------------------------------------
7270 2989 : void MSTransformManager::transformCubeOfData( vi::VisBuffer2 *vb,
7271 : RefRows &rowRef,
7272 : const Cube<Complex> &inputDataCube,
7273 : ArrayColumn<Complex> &outputDataCol,
7274 : ArrayColumn<bool> *outputFlagCol,
7275 : const Cube<Float> &inputWeightCube)
7276 : {
7277 2989 : (*this.*transformCubeOfDataComplex_p)(vb,rowRef,inputDataCube,outputDataCol,outputFlagCol,inputWeightCube);
7278 2989 : return;
7279 : }
7280 :
7281 : // -----------------------------------------------------------------------
7282 : //
7283 : // -----------------------------------------------------------------------
7284 1130 : void MSTransformManager::transformCubeOfData( vi::VisBuffer2 *vb,
7285 : RefRows &rowRef,
7286 : const Cube<Float> &inputDataCube,
7287 : ArrayColumn<Float> &outputDataCol,
7288 : ArrayColumn<bool> *outputFlagCol,
7289 : const Cube<Float> &inputWeightCube)
7290 : {
7291 1130 : (*this.*transformCubeOfDataFloat_p)(vb,rowRef,inputDataCube,outputDataCol,outputFlagCol,inputWeightCube);
7292 1130 : return;
7293 : }
7294 :
7295 : // -----------------------------------------------------------------------
7296 : //
7297 : // -----------------------------------------------------------------------
7298 1330 : template <class T> void MSTransformManager::copyCubeOfData( vi::VisBuffer2 *vb,
7299 : RefRows &rowRef,
7300 : const Cube<T> &inputDataCube,
7301 : ArrayColumn<T> &outputDataCol,
7302 : ArrayColumn<bool> *outputFlagCol,
7303 : const Cube<Float> & /* inputWeightCube */)
7304 : {
7305 1330 : writeCube(inputDataCube,outputDataCol,rowRef);
7306 1330 : if (outputFlagCol != NULL)
7307 : {
7308 1182 : writeCube(vb->flagCube(),*outputFlagCol,rowRef);
7309 : }
7310 :
7311 1330 : return;
7312 : }
7313 :
7314 : // -----------------------------------------------------------------------
7315 : // combine - for combinespws=True
7316 : // -----------------------------------------------------------------------
7317 0 : template <class T> void MSTransformManager::combineCubeOfData( vi::VisBuffer2 *vb,
7318 : RefRows &rowRef,
7319 : const Cube<T> &inputDataCube,
7320 : ArrayColumn<T> &outputDataCol,
7321 : ArrayColumn<bool> *outputFlagCol,
7322 : const Cube<Float> &inputWeightCube)
7323 : {
7324 : // Write flag column too?
7325 0 : if (outputFlagCol != NULL)
7326 : {
7327 0 : writeOutputFlagsPlaneSlices_p = &MSTransformManager::writeOutputFlagsPlaneSlices;
7328 0 : writeOutputFlagsPlaneReshapedSlices_p = &MSTransformManager::writeOutputFlagsPlaneReshapedSlices;
7329 0 : writeOutputFlagsPlane_p = &MSTransformManager::writeOutputFlagsPlane;
7330 : }
7331 : else
7332 : {
7333 0 : writeOutputFlagsPlaneSlices_p = &MSTransformManager::dontWriteOutputFlagsPlaneSlices;
7334 0 : writeOutputFlagsPlaneReshapedSlices_p = &MSTransformManager::dontWriteOutputPlaneReshapedSlices;
7335 0 : writeOutputFlagsPlane_p = &MSTransformManager::dontWriteOutputFlagsPlane;
7336 : }
7337 :
7338 : // Get input flag cube
7339 0 : const Cube<bool> inputFlagCube = vb->flagCube();
7340 :
7341 : // Get input SPWs and exposures
7342 0 : Vector<Int> spws = vb->spectralWindows();
7343 0 : Vector<Double> exposures = vb->exposure();
7344 :
7345 : // Get input cube shape
7346 0 : IPosition inputCubeShape = inputDataCube.shape();
7347 0 : uInt nInputCorrelations = inputCubeShape(0);
7348 :
7349 : // Initialize input planes
7350 0 : IPosition inputPlaneShape(2,nInputCorrelations, numOfCombInputChanMap_p[0]);
7351 0 : Matrix<Double> normalizingFactorPlane(inputPlaneShape);
7352 0 : Matrix<T> inputPlaneData(inputPlaneShape);
7353 0 : Matrix<bool> inputPlaneFlags(inputPlaneShape,false);
7354 0 : Matrix<Float> inputPlaneWeights(inputPlaneShape);
7355 :
7356 : // Initialize output planes
7357 0 : IPosition outputPlaneShape(2,nInputCorrelations, inputOutputSpwMap_p[0].second.NUM_CHAN);
7358 0 : Matrix<T> outputPlaneData(outputPlaneShape);
7359 0 : Matrix<bool> outputPlaneFlags(outputPlaneShape);
7360 :
7361 0 : Int spw = 0;
7362 : Double weight;
7363 : uInt inputChannel;
7364 : bool inputChanelFlag;
7365 : Double normalizingFactor;
7366 0 : uInt row = 0, baseline_index = 0;
7367 0 : vector<uInt> baselineRows;
7368 0 : map<Int, uInt> spwRowMap;
7369 0 : map<Int, uInt>::iterator spwRowMapIter;
7370 0 : map<Int, uInt> spwFractionCountsMap;
7371 0 : bool unityContributors = false;
7372 0 : vector< channelContribution > contributions;
7373 0 : vector< channelContribution >::iterator contributionsIter;
7374 0 : map < Int , map < uInt, bool > > removeContributionsMap;
7375 :
7376 0 : bool combinationOfSPWsWithDifferentExposure = false;
7377 0 : Double exposure = 0;
7378 :
7379 0 : relativeRow_p = 0; // Initialize relative row for buffer mode
7380 0 : for (baselineMap::iterator iter = baselineMap_p.begin(); iter != baselineMap_p.end(); iter++)
7381 : {
7382 : // Initialize input plane
7383 0 : inputPlaneData = 0.0;
7384 :
7385 : // Initialize weights plane
7386 0 : inputPlaneWeights = 0.0;
7387 :
7388 : // Initialize normalizing factor plane
7389 0 : normalizingFactorPlane = 0.0;
7390 :
7391 : // Fill input plane to benefit from contiguous access to the input cube
7392 0 : baselineRows = iter->second;
7393 :
7394 : // Create spw-row map for this baseline and initialize detection of SPWs with different exposure
7395 0 : spwRowMap.clear();
7396 0 : if (combinationOfSPWsWithDifferentExposure_p and (inputWeightCube.shape().isEqual(inputCubeShape)))
7397 : {
7398 0 : combinationOfSPWsWithDifferentExposure = true;
7399 0 : addWeightSpectrumContribution_p = &MSTransformManager::addWeightSpectrumContribution;
7400 0 : for (vector<uInt>::iterator iter_row = baselineRows.begin();iter_row != baselineRows.end(); iter_row++)
7401 : {
7402 0 : row = *iter_row;
7403 0 : spw = spws(row);
7404 0 : spwRowMap[spw]=row;
7405 : }
7406 : }
7407 : else
7408 : {
7409 0 : exposure = exposures(*baselineRows.begin());
7410 0 : combinationOfSPWsWithDifferentExposure = false;
7411 0 : for (vector<uInt>::iterator iter_row = baselineRows.begin();iter_row != baselineRows.end(); iter_row++)
7412 : {
7413 0 : row = *iter_row;
7414 0 : spw = spws(row);
7415 0 : spwRowMap[spw]=row;
7416 :
7417 : // In the case of *_SPECTRUM inputWeightCube is dummy
7418 0 : if ((abs(exposure - exposures(row)) > FLT_EPSILON) and (inputWeightCube.shape().isEqual(inputCubeShape)))
7419 : {
7420 0 : combinationOfSPWsWithDifferentExposure = true;
7421 : }
7422 : }
7423 :
7424 0 : if (combinationOfSPWsWithDifferentExposure)
7425 : {
7426 0 : combinationOfSPWsWithDifferentExposure_p = true;
7427 0 : addWeightSpectrumContribution_p = &MSTransformManager::addWeightSpectrumContribution;
7428 0 : if (inputWeightSpectrumAvailable_p)
7429 : {
7430 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
7431 : << "Detected combination of SPWs with different EXPOSURE "<< endl
7432 : << "Will use WEIGHT_SPECTRUM to combine them "<< endl
7433 0 : << LogIO::POST;
7434 : }
7435 : else
7436 : {
7437 0 : logger_p << LogIO::WARN << LogOrigin("MSTransformManager", __FUNCTION__)
7438 : << "Detected combination of SPWs with different EXPOSURE "<< endl
7439 : << "Will use WEIGHT to combine them (WEIGHT_SPECTRUM not available)"<< endl
7440 0 : << LogIO::POST;
7441 : }
7442 : }
7443 : else
7444 : {
7445 0 : addWeightSpectrumContribution_p = &MSTransformManager::dontAddWeightSpectrumContribution;
7446 : }
7447 : }
7448 :
7449 :
7450 0 : for (uInt outputChannel = 0; outputChannel < numOfCombInputChanMap_p[0]; outputChannel++)
7451 : {
7452 0 : contributions = inputOutputChanFactorMap_p[outputChannel];
7453 :
7454 0 : for (uInt pol = 0; pol < inputDataCube.shape()(0); pol++)
7455 : {
7456 0 : spwFractionCountsMap.clear();
7457 0 : unityContributors = false;
7458 :
7459 : // Go through list of contributors for this output channel and polarization and gather flags info
7460 0 : for (contributionsIter = contributions.begin(); contributionsIter != contributions.end(); contributionsIter++)
7461 : {
7462 0 : inputChannel = contributionsIter->inpChannel;
7463 0 : weight = contributionsIter->weight;
7464 :
7465 : // Add WEIGHT_SPECTRUM to the contribution
7466 0 : (*this.*addWeightSpectrumContribution_p)(weight,pol,inputChannel,row,inputWeightCube);
7467 :
7468 : // Find row for this input channel
7469 0 : spw = contributionsIter->inpSpw;
7470 0 : spwRowMapIter = spwRowMap.find(spw);
7471 0 : if (spwRowMapIter != spwRowMap.end())
7472 : {
7473 0 : row = spwRowMap[spw];
7474 :
7475 : // Fill flags info
7476 0 : inputChanelFlag = inputFlagCube(pol,inputChannel,row);
7477 0 : contributionsIter->flag = inputChanelFlag;
7478 :
7479 : // Count input channel if it is not flagged and has non-unity overlapping fraction
7480 0 : if (weight<1.0)
7481 : {
7482 0 : if (!inputChanelFlag) spwFractionCountsMap[spw] += 1;
7483 : }
7484 : // Count if we have valid unity contributors, otherwise we don't discard non-unity contributors
7485 : else
7486 : {
7487 0 : unityContributors = true;
7488 : }
7489 : }
7490 : else
7491 : {
7492 : // Fill flags info
7493 0 : contributionsIter->flag = true;
7494 : }
7495 : }
7496 :
7497 : // Remove contributions from SPWs with odd numbers of contributors with non-unity
7498 : // overlap fraction which could influence the averaging asymmetrically
7499 0 : for (contributionsIter = contributions.begin(); contributionsIter != contributions.end(); contributionsIter++)
7500 : {
7501 0 : inputChannel = contributionsIter->inpChannel;
7502 0 : weight = contributionsIter->weight;
7503 0 : spw = contributionsIter->inpSpw;
7504 :
7505 : // Find row for this input channel
7506 0 : if (!contributionsIter->flag)
7507 : {
7508 : // jagonzal: Caution, accessing the map populates it!!!
7509 0 : row = spwRowMap[spw];
7510 :
7511 0 : if ((spwFractionCountsMap[spw] % 2 == 0) or (weight >= 1.0) or (!unityContributors))
7512 : {
7513 0 : inputPlaneData(pol,outputChannel) += weight*inputDataCube(pol,inputChannel,row);
7514 0 : normalizingFactorPlane(pol,outputChannel) += weight;
7515 0 : (*this.*fillWeightsPlane_p)(pol,inputChannel,outputChannel,row,inputWeightCube,inputPlaneWeights,weight);
7516 : }
7517 : }
7518 : }
7519 : }
7520 : }
7521 :
7522 : // Normalize combined data and determine input plane flags
7523 0 : inputPlaneFlags = false;
7524 0 : for (uInt outputChannel = 0; outputChannel < numOfCombInputChanMap_p[0]; outputChannel++)
7525 : {
7526 0 : for (uInt pol = 0; pol < nInputCorrelations; pol++)
7527 : {
7528 0 : normalizingFactor = normalizingFactorPlane(pol,outputChannel);
7529 0 : if (normalizingFactor >= 0.999999) // we lose a couple significant digits in the subtractions
7530 : {
7531 0 : inputPlaneData(pol,outputChannel) /= normalizingFactorPlane(pol,outputChannel);
7532 :
7533 : // Normalize weights plane
7534 0 : (*this.*normalizeWeightsPlane_p)(pol,outputChannel,inputPlaneWeights,normalizingFactorPlane);
7535 : }
7536 0 : else if (normalizingFactor > 0)
7537 : {
7538 0 : inputPlaneData(pol,outputChannel) /= normalizingFactorPlane(pol,outputChannel);
7539 0 : inputPlaneFlags(pol,outputChannel) = true;
7540 : }
7541 : else
7542 : {
7543 0 : inputPlaneFlags(pol,outputChannel) = true;
7544 : }
7545 : }
7546 : }
7547 :
7548 : // Initialize output flags plane
7549 0 : outputPlaneFlags = false;
7550 :
7551 : // Transform input planes and write them
7552 0 : transformAndWritePlaneOfData( 0,rowRef.firstRow()+baseline_index*nspws_p,
7553 : inputPlaneData,inputPlaneFlags,inputPlaneWeights,
7554 : outputPlaneData,outputPlaneFlags,outputDataCol,outputFlagCol);
7555 :
7556 :
7557 0 : relativeRow_p += nspws_p;
7558 0 : baseline_index += 1;
7559 : }
7560 :
7561 0 : return;
7562 0 : }
7563 :
7564 : // -----------------------------------------------------------------------
7565 : //
7566 : // -----------------------------------------------------------------------
7567 0 : void MSTransformManager::addWeightSpectrumContribution( Double &weight,
7568 : uInt &pol,
7569 : uInt &inputChannel,
7570 : uInt &row,
7571 : const Cube<Float> &inputWeightsCube)
7572 : {
7573 0 : weight *= inputWeightsCube(pol,inputChannel,row);
7574 :
7575 0 : return;
7576 : }
7577 :
7578 : // -----------------------------------------------------------------------
7579 : //
7580 : // -----------------------------------------------------------------------
7581 0 : void MSTransformManager::dontAddWeightSpectrumContribution( Double &,
7582 : uInt &,
7583 : uInt &,
7584 : uInt &,
7585 : const Cube<Float> &)
7586 : {
7587 0 : return;
7588 : }
7589 :
7590 : // -----------------------------------------------------------------------
7591 : //
7592 : // -----------------------------------------------------------------------
7593 0 : void MSTransformManager::fillWeightsPlane( uInt pol,
7594 : uInt inputChannel,
7595 : uInt outputChannel,
7596 : uInt inputRow,
7597 : const Cube<Float> &inputWeightsCube,
7598 : Matrix<Float> &inputWeightsPlane,
7599 : Double factor)
7600 : {
7601 0 : inputWeightsPlane(pol,outputChannel) += factor*inputWeightsCube(pol,inputChannel,inputRow);
7602 :
7603 0 : return;
7604 : }
7605 :
7606 : // -----------------------------------------------------------------------
7607 : //
7608 : // -----------------------------------------------------------------------
7609 0 : void MSTransformManager::normalizeWeightsPlane( uInt pol,
7610 : uInt outputChannel,
7611 : Matrix<Float> &inputPlaneWeights,
7612 : Matrix<Double> &normalizingFactorPlane)
7613 : {
7614 0 : inputPlaneWeights(pol,outputChannel) /= normalizingFactorPlane(pol,outputChannel);
7615 :
7616 0 : return;
7617 : }
7618 :
7619 : // -----------------------------------------------------------------------
7620 : //
7621 : // -----------------------------------------------------------------------
7622 2789 : template <class T> void MSTransformManager::averageCubeOfData( vi::VisBuffer2 *vb,
7623 : RefRows &rowRef,
7624 : const Cube<T> &inputDataCube,
7625 : ArrayColumn<T> &outputDataCol,
7626 : ArrayColumn<bool> *outputFlagCol,
7627 : const Cube<Float> &inputWeightCube)
7628 : {
7629 : // Get input spw and flag and weight cubes
7630 2789 : Int inputSpw = vb->spectralWindows()(0);
7631 2789 : const Cube<bool> inputFlagsCube = vb->flagCube();
7632 :
7633 : // Define output plane shape
7634 2789 : IPosition outputPlaneShape = IPosition(2,inputDataCube.shape()(0), numOfOutChanMap_p[inputSpw]);
7635 :
7636 2789 : transformAndWriteCubeOfData( inputSpw, rowRef,
7637 : inputDataCube, inputFlagsCube, inputWeightCube,
7638 : outputPlaneShape, outputDataCol, outputFlagCol);
7639 :
7640 5578 : return;
7641 2789 : }
7642 :
7643 : // -----------------------------------------------------------------------
7644 : //
7645 : // -----------------------------------------------------------------------
7646 0 : template <class T> void MSTransformManager::smoothCubeOfData( vi::VisBuffer2 *vb,
7647 : RefRows &rowRef,
7648 : const Cube<T> &inputDataCube,
7649 : ArrayColumn<T> &outputDataCol,
7650 : ArrayColumn<bool> *outputFlagCol,
7651 : const Cube<Float> &inputWeightCube)
7652 : {
7653 : // Get input spw and flag cube
7654 0 : Int inputSpw = vb->spectralWindows()(0);
7655 0 : const Cube<bool> inputFlagsCube = vb->flagCube();
7656 :
7657 : // Define output plane shape
7658 0 : IPosition outputPlaneShape = IPosition(2,inputDataCube.shape()(0), inputDataCube.shape()(1));
7659 :
7660 : // Transform cube
7661 0 : transformAndWriteCubeOfData( inputSpw, rowRef,
7662 : inputDataCube, inputFlagsCube, inputWeightCube,
7663 : outputPlaneShape, outputDataCol, outputFlagCol);
7664 :
7665 0 : return;
7666 0 : }
7667 :
7668 : // -----------------------------------------------------------------------
7669 : //
7670 : // -----------------------------------------------------------------------
7671 0 : template <class T> void MSTransformManager::regridCubeOfData( vi::VisBuffer2 *vb,
7672 : RefRows &rowRef,
7673 : const Cube<T> &inputDataCube,
7674 : ArrayColumn<T> &outputDataCol,
7675 : ArrayColumn<bool> *outputFlagCol,
7676 : const Cube<Float> &inputWeightCube)
7677 : {
7678 : // Get input spw and flag cube
7679 0 : Int inputSpw = vb->spectralWindows()(0);
7680 0 : const Cube<bool> inputFlagsCube = vb->flagCube();
7681 :
7682 : // Define output plane shape
7683 0 : IPosition outputPlaneShape = IPosition(2,inputDataCube.shape()(0), inputOutputSpwMap_p[inputSpw].second.NUM_CHAN);
7684 :
7685 : // Transform cube
7686 0 : transformAndWriteCubeOfData( inputSpw, rowRef,
7687 : inputDataCube, inputFlagsCube, inputWeightCube,
7688 : outputPlaneShape, outputDataCol, outputFlagCol);
7689 :
7690 0 : return;
7691 0 : }
7692 :
7693 : // -----------------------------------------------------------------------
7694 : //
7695 : // -----------------------------------------------------------------------
7696 2789 : template <class T> void MSTransformManager::transformAndWriteCubeOfData( Int inputSpw,
7697 : RefRows &rowRef,
7698 : const Cube<T> &inputDataCube,
7699 : const Cube<bool> &inputFlagsCube,
7700 : const Cube<Float> &inputWeightsCube,
7701 : IPosition &outputPlaneShape,
7702 : ArrayColumn<T> &outputDataCol,
7703 : ArrayColumn<bool> *outputFlagCol)
7704 : {
7705 5578 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager",__FUNCTION__)
7706 : << "Shape of input data cube: " << inputDataCube.shape()
7707 : << ", output plane shape: " << outputPlaneShape
7708 5578 : << LogIO::POST;
7709 :
7710 : // Write flag column too?
7711 2789 : if (outputFlagCol != NULL)
7712 : {
7713 589 : writeOutputFlagsPlaneSlices_p = &MSTransformManager::writeOutputFlagsPlaneSlices;
7714 589 : writeOutputFlagsPlaneReshapedSlices_p = &MSTransformManager::writeOutputFlagsPlaneReshapedSlices;
7715 589 : writeOutputFlagsPlane_p = &MSTransformManager::writeOutputFlagsPlane;
7716 : }
7717 : else
7718 : {
7719 2200 : writeOutputFlagsPlaneSlices_p = &MSTransformManager::dontWriteOutputFlagsPlaneSlices;
7720 2200 : writeOutputFlagsPlaneReshapedSlices_p = &MSTransformManager::dontWriteOutputPlaneReshapedSlices;
7721 2200 : writeOutputFlagsPlane_p = &MSTransformManager::dontWriteOutputFlagsPlane;
7722 : }
7723 :
7724 : // Get input number of rows
7725 2789 : uInt nInputRows = inputDataCube.shape()(2);
7726 :
7727 : // Initialize input planes
7728 2789 : Matrix<T> inputPlaneData;
7729 2789 : Matrix<bool> inputPlaneFlags;
7730 2789 : Matrix<Float> inputPlaneWeights;
7731 :
7732 : // Initialize output planes
7733 2789 : Matrix<T> outputPlaneData(outputPlaneShape);
7734 2789 : Matrix<bool> outputPlaneFlags(outputPlaneShape);
7735 :
7736 : // Iterate row by row in order to extract a plane
7737 2789 : relativeRow_p = 0; // Initialize relative row for buffer mode
7738 19003 : for (uInt rowIndex=0; rowIndex < nInputRows; rowIndex++)
7739 : {
7740 : // Initialize output flags plane
7741 16214 : outputPlaneFlags = false;
7742 :
7743 : // Fill input planes by reference
7744 16214 : inputPlaneData = inputDataCube.xyPlane(rowIndex);
7745 16214 : inputPlaneFlags = inputFlagsCube.xyPlane(rowIndex);
7746 16214 : (*this.*setWeightsPlaneByReference_p)(rowIndex,inputWeightsCube,inputPlaneWeights);
7747 :
7748 : // Transform input planes and write them
7749 16214 : transformAndWritePlaneOfData( inputSpw,rowRef.firstRow()+rowIndex*nspws_p,
7750 : inputPlaneData,inputPlaneFlags,inputPlaneWeights,
7751 : outputPlaneData,outputPlaneFlags,outputDataCol,outputFlagCol);
7752 :
7753 16214 : relativeRow_p += nspws_p;
7754 : }
7755 :
7756 5578 : return;
7757 2789 : }
7758 :
7759 : // -----------------------------------------------------------------------
7760 : //
7761 : // -----------------------------------------------------------------------
7762 0 : template <class T> void MSTransformManager::separateCubeOfData( vi::VisBuffer2 *vb,
7763 : RefRows &rowRef,
7764 : const Cube<T> &inputDataCube,
7765 : ArrayColumn<T> &outputDataCol,
7766 : ArrayColumn<bool> *outputFlagCol,
7767 : const Cube<Float> & /* inputWeightCube */)
7768 : {
7769 : // Write flag column too?
7770 0 : if (outputFlagCol != NULL)
7771 : {
7772 0 : writeOutputFlagsPlaneSlices_p = &MSTransformManager::writeOutputFlagsPlaneSlices;
7773 0 : writeOutputFlagsPlaneReshapedSlices_p = &MSTransformManager::writeOutputFlagsPlaneReshapedSlices;
7774 0 : writeOutputFlagsPlane_p = &MSTransformManager::writeOutputFlagsPlane;
7775 : }
7776 : else
7777 : {
7778 0 : writeOutputFlagsPlaneSlices_p = &MSTransformManager::dontWriteOutputFlagsPlaneSlices;
7779 0 : writeOutputFlagsPlaneReshapedSlices_p = &MSTransformManager::dontWriteOutputPlaneReshapedSlices;
7780 0 : writeOutputFlagsPlane_p = &MSTransformManager::dontWriteOutputFlagsPlane;
7781 : }
7782 :
7783 : // Get input flags, spw and number of rows
7784 0 : uInt nInputRows = inputDataCube.shape()(2);
7785 0 : const Cube<bool> inputFlagsCube = vb->flagCube();
7786 :
7787 : // Initialize input planes
7788 0 : Matrix<T> inputPlaneData;
7789 0 : Matrix<bool> inputPlaneFlags;
7790 :
7791 : // Iterate row by row in order to extract a plane
7792 0 : relativeRow_p = 0; // Initialize relative row for buffer mode
7793 0 : for (uInt rowIndex=0; rowIndex < nInputRows; rowIndex++)
7794 : {
7795 : // Fill input planes by reference
7796 0 : inputPlaneData = inputDataCube.xyPlane(rowIndex);
7797 0 : inputPlaneFlags = inputFlagsCube.xyPlane(rowIndex);
7798 :
7799 : // Directly write output plane
7800 0 : writeOutputPlanes( rowRef.firstRow()+rowIndex*nspws_p,
7801 : inputPlaneData,inputPlaneFlags,
7802 : outputDataCol,*outputFlagCol);
7803 :
7804 0 : relativeRow_p += nspws_p;
7805 : }
7806 :
7807 0 : return;
7808 0 : }
7809 :
7810 : // -----------------------------------------------------------------------
7811 : //
7812 : // -----------------------------------------------------------------------
7813 12 : void MSTransformManager::setWeightsPlaneByReference( uInt inputRow,
7814 : const Cube<Float> &inputWeightsCube,
7815 : Matrix<Float> &inputWeightsPlane)
7816 : {
7817 12 : inputWeightsPlane = inputWeightsCube.xyPlane(inputRow);
7818 12 : }
7819 :
7820 : // -----------------------------------------------------------------------
7821 : //
7822 : // -----------------------------------------------------------------------
7823 16214 : template <class T> void MSTransformManager::transformAndWritePlaneOfData( Int inputSpw,
7824 : uInt row,
7825 : Matrix<T> &inputDataPlane,
7826 : Matrix<bool> &inputFlagsPlane,
7827 : Matrix<Float> &inputWeightsPlane,
7828 : Matrix<T> &outputDataPlane,
7829 : Matrix<bool> &outputFlagsPlane,
7830 : ArrayColumn<T> &outputDataCol,
7831 : ArrayColumn<bool> *outputFlagCol)
7832 : {
7833 : // Get input number of correlations
7834 16214 : uInt nCorrs = inputDataPlane.shape()(0);
7835 :
7836 : // Get output plane shape
7837 16214 : IPosition outputPlaneShape = outputDataPlane.shape();
7838 :
7839 : // Initialize vectors
7840 16214 : Vector<T> inputDataStripe;
7841 16214 : Vector<bool> inputFlagsStripe;
7842 16214 : Vector<Float> inputWeightsStripe;
7843 16214 : Vector<T> outputDataStripe;
7844 16214 : Vector<bool> outputFlagsStripe;
7845 :
7846 : // Iterate correlation by correlation in order to extract a vector
7847 81070 : for (uInt corrIndex=0; corrIndex < nCorrs; corrIndex++)
7848 : {
7849 : // Fill input stripes by reference
7850 64856 : inputDataStripe.reference(inputDataPlane.row(corrIndex));
7851 64856 : inputFlagsStripe.reference(inputFlagsPlane.row(corrIndex));
7852 64856 : (*this.*setWeightStripeByReference_p)(corrIndex,inputWeightsPlane,inputWeightsStripe);
7853 :
7854 : // Fill output stripes by reference
7855 64856 : outputDataStripe.reference(outputDataPlane.row(corrIndex));
7856 64856 : outputFlagsStripe.reference(outputFlagsPlane.row(corrIndex));
7857 :
7858 64856 : transformStripeOfData(inputSpw,inputDataStripe,inputFlagsStripe,
7859 : inputWeightsStripe,outputDataStripe,outputFlagsStripe);
7860 : }
7861 :
7862 : // Write output planes
7863 16214 : writeOutputPlanes(row,outputDataPlane,outputFlagsPlane,outputDataCol,*outputFlagCol);
7864 16214 : }
7865 :
7866 : // -----------------------------------------------------------------------
7867 : //
7868 : // -----------------------------------------------------------------------
7869 9718 : void MSTransformManager::writeOutputPlanes( uInt row,
7870 : Matrix<Complex> &outputDataPlane,
7871 : Matrix<bool> &outputFlagsPlane,
7872 : ArrayColumn<Complex> &outputDataCol,
7873 : ArrayColumn<bool> &outputFlagCol)
7874 : {
7875 9718 : (*this.*writeOutputPlanesComplex_p)(row,outputDataPlane,outputFlagsPlane,outputDataCol,outputFlagCol);
7876 9718 : }
7877 :
7878 : // -----------------------------------------------------------------------
7879 : //
7880 : // -----------------------------------------------------------------------
7881 6496 : void MSTransformManager::writeOutputPlanes( uInt row,
7882 : Matrix<Float> &outputDataPlane,
7883 : Matrix<bool> &outputFlagsPlane,
7884 : ArrayColumn<Float> &outputDataCol,
7885 : ArrayColumn<bool> &outputFlagCol)
7886 : {
7887 6496 : (*this.*writeOutputPlanesFloat_p)(row,outputDataPlane,outputFlagsPlane,outputDataCol,outputFlagCol);
7888 6496 : }
7889 :
7890 : // -----------------------------------------------------------------------
7891 : //
7892 : // -----------------------------------------------------------------------
7893 0 : void MSTransformManager::setOutputbuffer(Cube<Complex> *& dataBufferPointer,Cube<bool> *& flagBufferPointer)
7894 : {
7895 0 : switch (dataBuffer_p)
7896 : {
7897 0 : case MSTransformations::visCube:
7898 : {
7899 0 : dataBufferPointer=visCube_p;
7900 0 : if (userBufferMode_p)
7901 : {
7902 0 : flagBufferPointer = flagCube_p;
7903 : }
7904 : else
7905 : {
7906 0 : flagBufferPointer = NULL;
7907 : }
7908 0 : break;
7909 : }
7910 0 : case MSTransformations::visCubeCorrected:
7911 : {
7912 0 : dataBufferPointer=visCubeCorrected_p;
7913 0 : if (userBufferMode_p)
7914 : {
7915 0 : flagBufferPointer = flagCube_p;
7916 : }
7917 : else
7918 : {
7919 0 : flagBufferPointer = NULL;
7920 : }
7921 0 : break;
7922 : }
7923 0 : case MSTransformations::visCubeModel:
7924 : {
7925 0 : dataBufferPointer=visCubeModel_p;
7926 0 : if (userBufferMode_p)
7927 : {
7928 0 : flagBufferPointer = flagCube_p;
7929 : }
7930 : else
7931 : {
7932 0 : flagBufferPointer = NULL;
7933 : };
7934 0 : break;
7935 : }
7936 0 : default:
7937 : {
7938 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
7939 : << " Data buffer not specified"
7940 0 : << LogIO::POST;
7941 0 : dataBufferPointer=NULL;
7942 0 : flagBufferPointer=NULL;
7943 0 : break;
7944 : }
7945 : }
7946 :
7947 0 : return;
7948 : }
7949 :
7950 : // -----------------------------------------------------------------------
7951 : //
7952 : // -----------------------------------------------------------------------
7953 6496 : void MSTransformManager::setOutputbuffer(Cube<Float> *& dataBufferPointer,Cube<bool> *& flagBufferPointer)
7954 : {
7955 6496 : switch (dataBuffer_p)
7956 : {
7957 0 : case MSTransformations::visCubeFloat:
7958 : {
7959 0 : dataBufferPointer=visCubeFloat_p;
7960 0 : if (userBufferMode_p)
7961 : {
7962 0 : flagBufferPointer = flagCube_p;
7963 : }
7964 : else
7965 : {
7966 0 : flagBufferPointer = NULL;
7967 : };
7968 0 : break;
7969 : }
7970 6496 : case MSTransformations::weightSpectrum:
7971 : {
7972 6496 : dataBufferPointer=weightSpectrum_p;
7973 : // In buffer mode we already have a memory resident flagCube
7974 : // And the vector transformations use vectors from a dynamically initialize matrixes
7975 6496 : if (userBufferMode_p)
7976 : {
7977 0 : flagBufferPointer=NULL;
7978 : }
7979 : else
7980 : {
7981 6496 : flagBufferPointer = flagCube_p;
7982 : }
7983 6496 : break;
7984 : }
7985 0 : case MSTransformations::sigmaSpectrum:
7986 : {
7987 0 : dataBufferPointer=sigmaSpectrum_p;
7988 : // In buffer mode we already have a memory resident flagCube
7989 : // And the vector transformations use vectors from a dynamically initialize matrixes
7990 0 : if (userBufferMode_p)
7991 : {
7992 0 : flagBufferPointer=NULL;
7993 : }
7994 : else
7995 : {
7996 0 : flagBufferPointer = flagCube_p;
7997 : }
7998 0 : break;
7999 : }
8000 0 : default:
8001 : {
8002 0 : logger_p << LogIO::SEVERE << LogOrigin("MSTransformManager", __FUNCTION__)
8003 : << " Data buffer not specified"
8004 0 : << LogIO::POST;
8005 0 : dataBufferPointer=NULL;
8006 0 : flagBufferPointer = NULL;
8007 0 : break;
8008 : }
8009 : }
8010 :
8011 6496 : return;
8012 : }
8013 :
8014 : // -----------------------------------------------------------------------
8015 : //
8016 : // -----------------------------------------------------------------------
8017 6496 : template <class T> void MSTransformManager::bufferOutputPlanes( uInt ,
8018 : Matrix<T> &outputDataPlane,
8019 : Matrix<bool> &outputFlagsPlane,
8020 : ArrayColumn<T> &,
8021 : ArrayColumn<bool> &)
8022 : {
8023 : // Get buffer pointers
8024 : Cube<T> *dataBufferPointer;
8025 : Cube<bool> *flagBufferPointer;
8026 6496 : setOutputbuffer(dataBufferPointer,flagBufferPointer);
8027 :
8028 : // Copy data to buffer
8029 6496 : dataBufferPointer->xyPlane(relativeRow_p) = outputDataPlane;
8030 :
8031 : // Copy flags to buffer
8032 6496 : if (flagBufferPointer != NULL)
8033 : {
8034 6496 : flagBufferPointer->xyPlane(relativeRow_p) = outputFlagsPlane;
8035 : }
8036 :
8037 12992 : return;
8038 : }
8039 :
8040 : // -----------------------------------------------------------------------
8041 : //
8042 : // -----------------------------------------------------------------------
8043 0 : template <class T> void MSTransformManager::bufferOutputPlanesInSlices( uInt,
8044 : Matrix<T> &outputDataPlane,
8045 : Matrix<bool> &outputFlagsPlane,
8046 : ArrayColumn<T> & /* outputDataCol */,
8047 : ArrayColumn<bool> & /* outputFlagCol */)
8048 : {
8049 : // Get buffer pointers
8050 : Cube<T> *dataBufferPointer;
8051 : Cube<bool> *flagBufferPointer;
8052 0 : setOutputbuffer(dataBufferPointer,flagBufferPointer);
8053 :
8054 : // Copy data to buffer
8055 0 : IPosition outputPlaneShape = outputDataPlane.shape();
8056 0 : uInt nCorrs = outputPlaneShape(0);
8057 0 : IPosition outputPlaneShape_i(2,nCorrs,chansPerOutputSpw_p);
8058 0 : Slice sliceX(0,nCorrs);
8059 :
8060 : uInt spw_i;
8061 0 : uInt nspws = nspws_p-1;
8062 0 : for (spw_i=0;spw_i<nspws;spw_i++)
8063 : {
8064 0 : uInt outRow = relativeRow_p+spw_i;
8065 0 : Slice sliceY(chansPerOutputSpw_p*spw_i,chansPerOutputSpw_p);
8066 0 : Matrix<T> outputPlane_i = outputDataPlane(sliceX,sliceY);
8067 0 : dataBufferPointer->xyPlane(outRow) = outputPlane_i;
8068 :
8069 0 : if (flagBufferPointer != NULL)
8070 : {
8071 0 : Matrix<bool> outputFlagPlane_i = outputFlagsPlane(sliceX,sliceY);
8072 0 : flagBufferPointer->xyPlane(outRow) = outputFlagPlane_i;
8073 0 : }
8074 : }
8075 :
8076 0 : uInt outRow = relativeRow_p+spw_i;
8077 0 : Slice sliceY(chansPerOutputSpw_p*spw_i,tailOfChansforLastSpw_p);
8078 0 : Matrix<T> outputPlane_i = outputDataPlane(sliceX,sliceY);
8079 0 : outputPlane_i.resize(outputPlaneShape_i,true); // Resize uses a new storage and copies the old values to it
8080 : // jagonzal (CAS-7435): We have to set the new values to 0
8081 0 : Slice sliceTail(tailOfChansforLastSpw_p,chansPerOutputSpw_p-tailOfChansforLastSpw_p);
8082 0 : outputPlane_i(sliceX,sliceTail) = 0; // Slices use reference semantics.
8083 0 : dataBufferPointer->xyPlane(outRow) = outputPlane_i;
8084 :
8085 0 : if (flagBufferPointer != NULL)
8086 : {
8087 0 : Matrix<bool> outputFlagPlane_i = outputFlagsPlane(sliceX,sliceY);
8088 0 : outputFlagPlane_i.resize(outputPlaneShape_i,true); // Resize uses a new storage and copies the old values to it
8089 : // jagonzal (CAS-7435): We have to set the new values to 0
8090 0 : outputFlagPlane_i(sliceX,sliceTail) = true; // Slices use reference semantics.
8091 0 : flagBufferPointer->xyPlane(outRow) = outputFlagPlane_i;
8092 0 : }
8093 :
8094 0 : return;
8095 0 : }
8096 :
8097 : // -----------------------------------------------------------------------
8098 : //
8099 : // -----------------------------------------------------------------------
8100 9718 : template <class T> void MSTransformManager::writeOutputPlanesInBlock( uInt row,
8101 : Matrix<T> &outputDataPlane,
8102 : Matrix<bool> &outputFlagsPlane,
8103 : ArrayColumn<T> &outputDataCol,
8104 : ArrayColumn<bool> &outputFlagCol)
8105 : {
8106 9718 : IPosition outputPlaneShape = outputDataPlane.shape();
8107 9718 : outputDataCol.setShape(row,outputPlaneShape);
8108 9718 : outputDataCol.put(row, outputDataPlane);
8109 9718 : (*this.*writeOutputFlagsPlane_p)(outputFlagsPlane,outputFlagCol, outputPlaneShape, row);
8110 9718 : }
8111 :
8112 :
8113 : // -----------------------------------------------------------------------
8114 : //
8115 : // -----------------------------------------------------------------------
8116 3274 : void MSTransformManager::writeOutputFlagsPlane( Matrix<bool> &outputPlane,
8117 : ArrayColumn<bool> &outputCol,
8118 : IPosition &outputPlaneShape,
8119 : uInt &outputRow)
8120 : {
8121 3274 : outputCol.setShape(outputRow,outputPlaneShape);
8122 3274 : outputCol.put(outputRow, outputPlane);
8123 3274 : }
8124 :
8125 : // -----------------------------------------------------------------------
8126 : //
8127 : // -----------------------------------------------------------------------
8128 0 : template <class T> void MSTransformManager::writeOutputPlanesInSlices( uInt row,
8129 : Matrix<T> &outputDataPlane,
8130 : Matrix<bool> &outputFlagsPlane,
8131 : ArrayColumn<T> &outputDataCol,
8132 : ArrayColumn<bool> &outputFlagCol)
8133 : {
8134 0 : IPosition outputPlaneShape = outputDataPlane.shape();
8135 0 : uInt nCorrs = outputPlaneShape(0);
8136 0 : IPosition outputPlaneShape_i(2,nCorrs,chansPerOutputSpw_p);
8137 0 : Slice sliceX(0,nCorrs);
8138 :
8139 : uInt spw_i;
8140 0 : uInt nspws = nspws_p-1;
8141 0 : for (spw_i=0;spw_i<nspws;spw_i++)
8142 : {
8143 0 : uInt outRow = row+spw_i;
8144 0 : Slice sliceY(chansPerOutputSpw_p*spw_i,chansPerOutputSpw_p);
8145 0 : writeOutputPlaneSlices(outputDataPlane,outputDataCol,sliceX,sliceY,outputPlaneShape_i,outRow);
8146 0 : (*this.*writeOutputFlagsPlaneSlices_p)( outputFlagsPlane,outputFlagCol,
8147 : sliceX,sliceY,outputPlaneShape_i,outRow);
8148 : }
8149 :
8150 0 : uInt outRow = row+spw_i;
8151 0 : IPosition outputPlaneShape_tail(2,nCorrs,tailOfChansforLastSpw_p);
8152 0 : Slice sliceY(chansPerOutputSpw_p*spw_i,tailOfChansforLastSpw_p);
8153 0 : writeOutputPlaneReshapedSlices(outputDataPlane,outputDataCol,sliceX,sliceY,outputPlaneShape_tail,outRow);
8154 0 : (*this.*writeOutputFlagsPlaneReshapedSlices_p)( outputFlagsPlane,outputFlagCol,
8155 : sliceX,sliceY,outputPlaneShape_tail,outRow);
8156 0 : }
8157 :
8158 : // -----------------------------------------------------------------------
8159 : //
8160 : // -----------------------------------------------------------------------
8161 0 : void MSTransformManager::writeOutputFlagsPlaneSlices( Matrix<bool> &outputPlane,
8162 : ArrayColumn<bool> &outputCol,
8163 : Slice &sliceX,
8164 : Slice &sliceY,
8165 : IPosition &outputPlaneShape,
8166 : uInt &outputRow)
8167 : {
8168 0 : writeOutputPlaneSlices(outputPlane,outputCol,sliceX,sliceY,outputPlaneShape,outputRow);
8169 0 : }
8170 :
8171 : // -----------------------------------------------------------------------
8172 : //
8173 : // -----------------------------------------------------------------------
8174 0 : void MSTransformManager::writeOutputFlagsPlaneReshapedSlices( Matrix<bool> &outputPlane,
8175 : ArrayColumn<bool> &outputCol,
8176 : Slice &sliceX,
8177 : Slice &sliceY,
8178 : IPosition &outputPlaneShape,
8179 : uInt &outputRow)
8180 : {
8181 0 : writeOutputPlaneReshapedSlices(outputPlane,outputCol,sliceX,sliceY,outputPlaneShape,outputRow);
8182 0 : }
8183 :
8184 : // -----------------------------------------------------------------------
8185 : //
8186 : // -----------------------------------------------------------------------
8187 0 : template <class T> void MSTransformManager::writeOutputPlaneSlices( Matrix<T> &outputPlane,
8188 : ArrayColumn<T> &outputCol,
8189 : Slice &sliceX,
8190 : Slice &sliceY,
8191 : IPosition &outputPlaneShape,
8192 : uInt &outputRow)
8193 : {
8194 0 : Matrix<T> outputPlane_i = outputPlane(sliceX,sliceY);
8195 0 : outputCol.setShape(outputRow,outputPlaneShape);
8196 0 : outputCol.put(outputRow, outputPlane_i);
8197 0 : }
8198 :
8199 : // -----------------------------------------------------------------------
8200 : //
8201 : // -----------------------------------------------------------------------
8202 0 : template <class T> void MSTransformManager::writeOutputPlaneReshapedSlices( Matrix<T> &outputPlane,
8203 : ArrayColumn<T> &outputCol,
8204 : Slice &sliceX,
8205 : Slice &sliceY,
8206 : IPosition &outputPlaneShape,
8207 : uInt &outputRow)
8208 : {
8209 0 : Matrix<T> outputPlane_i = outputPlane(sliceX,sliceY);
8210 0 : outputPlane_i.resize(outputPlaneShape,true);
8211 0 : outputCol.setShape(outputRow,outputPlaneShape);
8212 0 : outputCol.put(outputRow, outputPlane_i);
8213 0 : }
8214 :
8215 : // -----------------------------------------------------------------------
8216 : //
8217 : // -----------------------------------------------------------------------
8218 48 : void MSTransformManager::setWeightStripeByReference( uInt corrIndex,
8219 : Matrix<Float> &inputWeightsPlane,
8220 : Vector<Float> &inputWeightsStripe)
8221 : {
8222 48 : inputWeightsStripe.reference(inputWeightsPlane.row(corrIndex));
8223 48 : }
8224 :
8225 : // -----------------------------------------------------------------------
8226 : //
8227 : // -----------------------------------------------------------------------
8228 38872 : void MSTransformManager::transformStripeOfData(Int inputSpw,
8229 : const Vector<Complex> &inputDataStripe,
8230 : const Vector<bool> &inputFlagsStripe,
8231 : const Vector<Float> &inputWeightsStripe,
8232 : Vector<Complex> &outputDataStripe,
8233 : Vector<bool> &outputFlagsStripe)
8234 : {
8235 38872 : if(!smooth_spw_p.empty())
8236 : {
8237 : // Skip this SPW if it is not found in the list of SPWs to smooth
8238 0 : if( std::find(smooth_spw_p.begin(), smooth_spw_p.end(), inputSpw) == smooth_spw_p.end())
8239 : {
8240 0 : outputDataStripe = inputDataStripe;
8241 0 : outputFlagsStripe = inputFlagsStripe;
8242 0 : return;
8243 : }
8244 : }
8245 :
8246 38872 : auto shapeBefore = outputDataStripe.shape();
8247 38872 : (*this.*transformStripeOfDataComplex_p)(inputSpw, inputDataStripe, inputFlagsStripe,
8248 : inputWeightsStripe, outputDataStripe,
8249 : outputFlagsStripe);
8250 38872 : auto shapeAfter = outputDataStripe.shape();
8251 38872 : if (shapeAfter != shapeBefore) {
8252 0 : ostringstream msg;
8253 : msg << "Shape of output complex data stripe changed after applying "
8254 0 : << "transformation. Output shape expected before transformation: "
8255 0 : << shapeBefore
8256 0 : << ". Output shape produced by transformation: " << shapeAfter;
8257 0 : logger_p << LogIO::DEBUG1 << LogOrigin("MSTransformManager",__FUNCTION__)
8258 0 : << LogIO::POST;
8259 0 : throw AipsError(msg.str());
8260 0 : }
8261 38872 : }
8262 :
8263 : // -----------------------------------------------------------------------
8264 : //
8265 : // -----------------------------------------------------------------------
8266 25984 : void MSTransformManager::transformStripeOfData(Int inputSpw,
8267 : const Vector<Float> &inputDataStripe,
8268 : const Vector<bool> &inputFlagsStripe,
8269 : const Vector<Float> &inputWeightsStripe,
8270 : Vector<Float> &outputDataStripe,
8271 : Vector<bool> &outputFlagsStripe)
8272 : {
8273 25984 : (*this.*transformStripeOfDataFloat_p)( inputSpw,inputDataStripe,inputFlagsStripe,inputWeightsStripe,
8274 : outputDataStripe,outputFlagsStripe);
8275 25984 : }
8276 :
8277 : // -----------------------------------------------------------------------
8278 : //
8279 : // -----------------------------------------------------------------------
8280 64856 : template <class T> void MSTransformManager::average(Int inputSpw,
8281 : const Vector<T> &inputDataStripe,
8282 : const Vector<bool> &inputFlagsStripe,
8283 : const Vector<Float> &inputWeightsStripe,
8284 : Vector<T> &outputDataStripe,
8285 : Vector<bool> &outputFlagsStripe)
8286 : {
8287 64856 : uInt width = freqbinMap_p[inputSpw];
8288 64856 : uInt startChan = 0;
8289 64856 : uInt outChanIndex = 0;
8290 64856 : uInt tail = inputDataStripe.size() % width;
8291 204488 : while (outChanIndex < outputDataStripe.size())
8292 : {
8293 139632 : averageKernel( inputDataStripe,inputFlagsStripe,inputWeightsStripe,
8294 : outputDataStripe,outputFlagsStripe,startChan,outChanIndex,width);
8295 139632 : startChan += width;
8296 139632 : outChanIndex += 1;
8297 : }
8298 :
8299 : // jagonzal: The last channel is dropped when there are not enough input channels
8300 : // to populate it only when there is no regridding afterwards
8301 64856 : if (tail and (outChanIndex <= outputDataStripe.size()-1) )
8302 : {
8303 0 : averageKernel( inputDataStripe,inputFlagsStripe,inputWeightsStripe,
8304 : outputDataStripe,outputFlagsStripe,startChan,outChanIndex,tail);
8305 : }
8306 :
8307 64856 : return;
8308 : }
8309 :
8310 : // -----------------------------------------------------------------------
8311 : //
8312 : // -----------------------------------------------------------------------
8313 0 : template <class T> void MSTransformManager::simpleAverage(uInt width,
8314 : const Vector<T> &inputData,
8315 : Vector<T> &outputData)
8316 : {
8317 : // Dummy variables
8318 0 : Vector<bool> inputFlags,outputFlags;
8319 0 : Vector<Float> inputWeights;
8320 :
8321 0 : uInt startChan = 0;
8322 0 : uInt outChanIndex = 0;
8323 0 : uInt tail = inputData.size() % width;
8324 0 : uInt limit = inputData.size() - tail;
8325 0 : while (startChan < limit)
8326 : {
8327 0 : simpleAverageKernel(inputData,inputFlags,inputWeights,outputData,outputFlags,startChan,outChanIndex,width);
8328 0 : startChan += width;
8329 0 : outChanIndex += 1;
8330 : }
8331 :
8332 : // jagonzal: The last channel is dropped when there are not enough input channels
8333 : // to populate it only when there is no regridding afterwards
8334 0 : if (tail and (outChanIndex <= outputData.size()-1) )
8335 : {
8336 0 : simpleAverageKernel(inputData,inputFlags,inputWeights,outputData,outputFlags,startChan,outChanIndex,tail);
8337 : }
8338 :
8339 0 : return;
8340 0 : }
8341 :
8342 : // -----------------------------------------------------------------------
8343 : //
8344 : // -----------------------------------------------------------------------
8345 82704 : void MSTransformManager::averageKernel(const Vector<Complex> &inputData,
8346 : const Vector<bool> &inputFlags,
8347 : const Vector<Float> &inputWeights,
8348 : Vector<Complex> &outputData,
8349 : Vector<bool> &outputFlags,
8350 : uInt startInputPos,
8351 : uInt outputPos,
8352 : uInt width)
8353 : {
8354 82704 : (*this.*averageKernelComplex_p)( inputData,inputFlags,inputWeights,
8355 : outputData,outputFlags,startInputPos,outputPos,width);
8356 82704 : return;
8357 : }
8358 :
8359 : // -----------------------------------------------------------------------
8360 : //
8361 : // -----------------------------------------------------------------------
8362 56928 : void MSTransformManager::averageKernel(const Vector<Float> &inputData,
8363 : const Vector<bool> &inputFlags,
8364 : const Vector<Float> &inputWeights,
8365 : Vector<Float> &outputData,
8366 : Vector<bool> &outputFlags,
8367 : uInt startInputPos,
8368 : uInt outputPos,
8369 : uInt width)
8370 : {
8371 56928 : (*this.*averageKernelFloat_p)( inputData,inputFlags,inputWeights,
8372 : outputData,outputFlags,startInputPos,outputPos,width);
8373 56928 : return;
8374 : }
8375 :
8376 : // -----------------------------------------------------------------------
8377 : //
8378 : // -----------------------------------------------------------------------
8379 0 : template <class T> void MSTransformManager::simpleAverageKernel(const Vector<T> &inputData,
8380 : const Vector<bool> &,
8381 : const Vector<Float> &,
8382 : Vector<T> &outputData,
8383 : Vector<bool> &,
8384 : uInt startInputPos,
8385 : uInt outputPos,
8386 : uInt width)
8387 : {
8388 0 : uInt pos = startInputPos + 1;
8389 0 : uInt counts = 1;
8390 0 : T avg = inputData(startInputPos);
8391 0 : while (counts < width)
8392 : {
8393 0 : avg += inputData(pos);
8394 0 : counts += 1;
8395 0 : pos += 1;
8396 : }
8397 :
8398 0 : if (counts > 0)
8399 : {
8400 0 : avg /= counts;
8401 : }
8402 :
8403 0 : outputData(outputPos) = avg;
8404 :
8405 0 : return;
8406 : }
8407 :
8408 : // -----------------------------------------------------------------------
8409 : //
8410 : // -----------------------------------------------------------------------
8411 0 : template <class T> void MSTransformManager::flagAverageKernel(const Vector<T> &inputData,
8412 : const Vector<bool> &inputFlags,
8413 : const Vector<Float> &,
8414 : Vector<T> &outputData,
8415 : Vector<bool> &outputFlags,
8416 : uInt startInputPos,
8417 : uInt outputPos,
8418 : uInt width)
8419 : {
8420 0 : uInt samples = 1;
8421 0 : uInt pos = startInputPos + 1;
8422 0 : uInt counts = !inputFlags(startInputPos);
8423 0 : T avg = inputData(startInputPos)*(!inputFlags(startInputPos));
8424 0 : while (samples < width)
8425 : {
8426 0 : avg += inputData(pos)*(!inputFlags(pos));
8427 0 : counts += (!inputFlags(pos));
8428 0 : samples += 1;
8429 0 : pos += 1;
8430 : }
8431 :
8432 0 : if (counts > 0)
8433 : {
8434 0 : avg /= counts;
8435 : }
8436 : else
8437 : {
8438 0 : outputFlags(outputPos) = true;
8439 : }
8440 :
8441 0 : outputData(outputPos) = avg;
8442 :
8443 0 : return;
8444 : }
8445 :
8446 : // -----------------------------------------------------------------------
8447 : //
8448 : // -----------------------------------------------------------------------
8449 0 : template <class T> void MSTransformManager::weightAverageKernel(const Vector<T> &inputData,
8450 : const Vector<bool> &,
8451 : const Vector<Float> &inputWeights,
8452 : Vector<T> &outputData,
8453 : Vector<bool> &outputFlags,
8454 : uInt startInputPos,
8455 : uInt outputPos,
8456 : uInt width)
8457 : {
8458 0 : uInt samples = 1;
8459 0 : uInt pos = startInputPos + 1;
8460 0 : Float counts = inputWeights(startInputPos);
8461 0 : T avg = inputData(startInputPos)*inputWeights(startInputPos);
8462 0 : while (samples < width)
8463 : {
8464 0 : avg += inputData(pos)*inputWeights(pos);
8465 0 : counts += inputWeights(pos);
8466 0 : samples += 1;
8467 0 : pos += 1;
8468 : }
8469 :
8470 0 : if (counts > 0)
8471 : {
8472 0 : avg /= counts;
8473 : }
8474 : else
8475 : {
8476 0 : outputFlags(outputPos) = true;
8477 : }
8478 :
8479 0 : outputData(outputPos) = avg;
8480 :
8481 0 : return;
8482 : }
8483 :
8484 : // -----------------------------------------------------------------------
8485 : //
8486 : // -----------------------------------------------------------------------
8487 0 : template <class T> void MSTransformManager::cumSumKernel(const Vector<T> &inputData,
8488 : const Vector<bool> &,
8489 : const Vector<Float> &,
8490 : Vector<T> &outputData,
8491 : Vector<bool> &,
8492 : uInt startInputPos,
8493 : uInt outputPos,
8494 : uInt width)
8495 : {
8496 0 : uInt pos = startInputPos + 1;
8497 0 : uInt counts = 1;
8498 0 : T avg = inputData(startInputPos);
8499 0 : while (counts < width)
8500 : {
8501 0 : avg += inputData(pos);
8502 0 : counts += 1;
8503 0 : pos += 1;
8504 : }
8505 :
8506 0 : outputData(outputPos) = avg;
8507 :
8508 0 : return;
8509 : }
8510 :
8511 : // -----------------------------------------------------------------------
8512 : //
8513 : // -----------------------------------------------------------------------
8514 0 : template <class T> void MSTransformManager::flagWeightAverageKernel(const Vector<T> &inputData,
8515 : const Vector<bool> &inputFlags,
8516 : const Vector<Float> &inputWeights,
8517 : Vector<T> &outputData,
8518 : Vector<bool> &outputFlags,
8519 : uInt startInputPos,
8520 : uInt outputPos,
8521 : uInt width)
8522 : {
8523 0 : uInt samples = 1;
8524 0 : uInt pos = startInputPos + 1;
8525 0 : Float totalWeight = inputWeights(startInputPos)*(!inputFlags(startInputPos));
8526 0 : Float counts = totalWeight;
8527 0 : T avg = inputData(startInputPos)*totalWeight;
8528 0 : while (samples < width)
8529 : {
8530 0 : totalWeight = inputWeights(pos)*(!inputFlags(pos));
8531 0 : avg += inputData(pos)*totalWeight;
8532 0 : counts += totalWeight;
8533 0 : samples += 1;
8534 0 : pos += 1;
8535 : }
8536 :
8537 0 : if (counts > 0)
8538 : {
8539 0 : avg /= counts;
8540 : }
8541 : else
8542 : {
8543 0 : outputFlags(outputPos) = true;
8544 : }
8545 :
8546 0 : outputData(outputPos) = avg;
8547 :
8548 0 : return;
8549 : }
8550 :
8551 : // -----------------------------------------------------------------------
8552 : //
8553 : // -----------------------------------------------------------------------
8554 0 : template <class T> void MSTransformManager::flagCumSumKernel(const Vector<T> &inputData,
8555 : const Vector<bool> &inputFlags,
8556 : const Vector<Float> &,
8557 : Vector<T> &outputData,
8558 : Vector<bool> &,
8559 : uInt startInputPos,
8560 : uInt outputPos,
8561 : uInt width)
8562 : {
8563 0 : uInt samples = 1;
8564 0 : uInt pos = startInputPos + 1;
8565 0 : T avg = inputData(startInputPos)*(!inputFlags(startInputPos));
8566 0 : while (samples < width)
8567 : {
8568 0 : avg += inputData(pos)*(!inputFlags(pos));
8569 0 : samples += 1;
8570 0 : pos += 1;
8571 : }
8572 :
8573 0 : outputData(outputPos) = avg;
8574 :
8575 0 : return;
8576 : }
8577 :
8578 : // -----------------------------------------------------------------------
8579 : //
8580 : // -----------------------------------------------------------------------
8581 81168 : template <class T> void MSTransformManager::flagNonZeroAverageKernel(const Vector<T> &inputData,
8582 : const Vector<bool> &inputFlags,
8583 : const Vector<Float> & /* inputWeights */,
8584 : Vector<T> &outputData,
8585 : Vector<bool> &outputFlags,
8586 : uInt startInputPos,
8587 : uInt outputPos,
8588 : uInt width)
8589 : {
8590 81168 : T avg = 0;
8591 81168 : uInt samples = 0;
8592 81168 : uInt inputPos = 0;
8593 81168 : bool accumulatorFlag = inputFlags(startInputPos);
8594 :
8595 2565904 : for (uInt sample_i=0;sample_i<width;sample_i++)
8596 : {
8597 : // Get input index
8598 2484736 : inputPos = startInputPos + sample_i;
8599 :
8600 : // true/true or false/false
8601 2484736 : if (accumulatorFlag == inputFlags(inputPos))
8602 : {
8603 2484736 : samples += 1;
8604 2484736 : avg += inputData(inputPos);
8605 : }
8606 : // true/false: Reset accumulation when accumulator switches from flagged to unflag
8607 0 : else if ( (accumulatorFlag == true) and (inputFlags(inputPos) == false) )
8608 : {
8609 0 : accumulatorFlag = false;
8610 0 : samples = 1;
8611 0 : avg = inputData(inputPos);
8612 : }
8613 : }
8614 :
8615 :
8616 : // Apply normalization factor
8617 81168 : if (samples > 0)
8618 : {
8619 81168 : avg /= samples;
8620 81168 : outputData(outputPos) = avg;
8621 : }
8622 : // This should never happen
8623 : else
8624 : {
8625 0 : accumulatorFlag = true;
8626 0 : outputData(outputPos) = 0; // this should be a code error
8627 : }
8628 :
8629 :
8630 : // Set output flag (it is initialized to false)
8631 81168 : if (accumulatorFlag)
8632 : {
8633 193 : outputFlags(outputPos) = true;
8634 : }
8635 :
8636 162336 : return;
8637 : }
8638 :
8639 :
8640 : // -----------------------------------------------------------------------
8641 : //
8642 : // -----------------------------------------------------------------------
8643 1536 : template <class T> void MSTransformManager::flagWeightNonZeroAverageKernel(const Vector<T> &inputData,
8644 : const Vector<bool> &inputFlags,
8645 : const Vector<Float> &inputWeights,
8646 : Vector<T> &outputData,
8647 : Vector<bool> &outputFlags,
8648 : uInt startInputPos,
8649 : uInt outputPos,
8650 : uInt width)
8651 : {
8652 1536 : T avg = 0;
8653 1536 : T normalization = 0;
8654 1536 : uInt inputPos = 0;
8655 1536 : bool accumulatorFlag = inputFlags(startInputPos);
8656 :
8657 4608 : for (uInt sample_i=0;sample_i<width;sample_i++)
8658 : {
8659 : // Get input index
8660 3072 : inputPos = startInputPos + sample_i;
8661 :
8662 : // true/true or false/false
8663 3072 : if (accumulatorFlag == inputFlags(inputPos))
8664 : {
8665 3072 : normalization += inputWeights(inputPos);
8666 3072 : avg += inputData(inputPos)*inputWeights(inputPos);
8667 : }
8668 : // true/false: Reset accumulation when accumulator switches from flagged to unflag
8669 0 : else if ( (accumulatorFlag == true) and (inputFlags(inputPos) == false) )
8670 : {
8671 0 : accumulatorFlag = false;
8672 0 : normalization = inputWeights(inputPos);
8673 0 : avg = inputData(inputPos)*inputWeights(inputPos);
8674 : }
8675 : }
8676 :
8677 :
8678 : // Apply normalization factor
8679 1536 : if (normalization > 0)
8680 : {
8681 1536 : avg /= normalization;
8682 1536 : outputData(outputPos) = avg;
8683 : }
8684 : // If all weights are zero set accumulatorFlag to true
8685 : else
8686 : {
8687 0 : accumulatorFlag = true;
8688 0 : outputData(outputPos) = 0; // If all weights are zero then the avg is 0 too
8689 : }
8690 :
8691 :
8692 : // Set output flag (it is initialized to false)
8693 1536 : if (accumulatorFlag)
8694 : {
8695 52 : outputFlags(outputPos) = true;
8696 : }
8697 :
8698 3072 : return;
8699 : }
8700 :
8701 : // -----------------------------------------------------------------------
8702 : //
8703 : // -----------------------------------------------------------------------
8704 56928 : template <class T> void MSTransformManager::flagCumSumNonZeroKernel(const Vector<T> &inputData,
8705 : const Vector<bool> &inputFlags,
8706 : const Vector<Float> & /* inputWeights */,
8707 : Vector<T> &outputData,
8708 : Vector<bool> &outputFlags,
8709 : uInt startInputPos,
8710 : uInt outputPos,
8711 : uInt width)
8712 : {
8713 56928 : T avg = 0;
8714 56928 : uInt inputPos = 0;
8715 56928 : bool accumulatorFlag = inputFlags(startInputPos);
8716 :
8717 1719904 : for (uInt sample_i=0;sample_i<width;sample_i++)
8718 : {
8719 : // Get input index
8720 1662976 : inputPos = startInputPos + sample_i;
8721 :
8722 : // true/true or false/false
8723 1662976 : if (accumulatorFlag == inputFlags(inputPos))
8724 : {
8725 1662976 : avg += inputData(inputPos);
8726 : }
8727 : // true/false: Reset accumulation when accumulator switches from flagged to unflag
8728 0 : else if ( (accumulatorFlag == true) and (inputFlags(inputPos) == false) )
8729 : {
8730 0 : accumulatorFlag = false;
8731 0 : avg = inputData(inputPos);
8732 : }
8733 : }
8734 :
8735 56928 : outputData(outputPos) = avg;
8736 :
8737 : // Set output flag (it is initialized to false)
8738 56928 : if (accumulatorFlag)
8739 : {
8740 245 : outputFlags(outputPos) = true;
8741 : }
8742 :
8743 56928 : return;
8744 : }
8745 :
8746 :
8747 : // -----------------------------------------------------------------------
8748 : //
8749 : // -----------------------------------------------------------------------
8750 0 : template <class T> void MSTransformManager::smooth(Int ,
8751 : const Vector<T> &inputDataStripe,
8752 : const Vector<bool> &inputFlagsStripe,
8753 : const Vector<Float> &inputWeightsStripe,
8754 : Vector<T> &outputDataStripe,
8755 : Vector<bool> &outputFlagsStripe)
8756 : {
8757 : // Calculate limits
8758 0 : uInt width = smoothBin_p;
8759 0 : uInt halfWidth = width / 2;
8760 0 : uInt outChanStart = halfWidth;
8761 0 : uInt outChanStop = inputDataStripe.size() - outChanStart;
8762 :
8763 : // Main loop
8764 0 : for (uInt outChan = outChanStart; outChan<outChanStop; outChan++)
8765 : {
8766 0 : smoothKernel( inputDataStripe,inputFlagsStripe,inputWeightsStripe,
8767 : outputDataStripe,outputFlagsStripe,outChan);
8768 : }
8769 :
8770 : // Flag lower edge
8771 0 : for (uInt outChan = 0; outChan<outChanStart; outChan++)
8772 : {
8773 0 : outputFlagsStripe(outChan) = true;
8774 0 : outputDataStripe(outChan) = inputDataStripe(outChan);
8775 : }
8776 :
8777 : // Flag higher edge
8778 0 : for (uInt outChan = outChanStop; outChan<inputDataStripe.size(); outChan++)
8779 : {
8780 0 : outputFlagsStripe(outChan) = true;
8781 0 : outputDataStripe(outChan) = inputDataStripe(outChan);
8782 : }
8783 :
8784 0 : return;
8785 : }
8786 :
8787 : // -----------------------------------------------------------------------
8788 : //
8789 : // -----------------------------------------------------------------------
8790 0 : void MSTransformManager::smoothKernel(const Vector<Complex> &inputData,
8791 : const Vector<bool> &inputFlags,
8792 : const Vector<Float> &inputWeights,
8793 : Vector<Complex> &outputData,
8794 : Vector<bool> &outputFlags,
8795 : uInt outputPos)
8796 : {
8797 0 : (*this.*smoothKernelComplex_p)( inputData,inputFlags,inputWeights,
8798 : outputData,outputFlags,outputPos);
8799 0 : return;
8800 : }
8801 :
8802 : // -----------------------------------------------------------------------
8803 : //
8804 : // -----------------------------------------------------------------------
8805 0 : void MSTransformManager::smoothKernel(const Vector<Float> &inputData,
8806 : const Vector<bool> &inputFlags,
8807 : const Vector<Float> &inputWeights,
8808 : Vector<Float> &outputData,
8809 : Vector<bool> &outputFlags,
8810 : uInt outputPos)
8811 : {
8812 0 : (*this.*smoothKernelFloat_p)( inputData,inputFlags,inputWeights,
8813 : outputData,outputFlags,outputPos);
8814 0 : return;
8815 : }
8816 :
8817 : // -----------------------------------------------------------------------
8818 : //
8819 : // -----------------------------------------------------------------------
8820 0 : template <class T> void MSTransformManager::plainSmooth(const Vector<T> &inputData,
8821 : const Vector<bool> &inputFlags,
8822 : const Vector<Float> &,
8823 : Vector<T> &outputData,
8824 : Vector<bool> &outputFlags,
8825 : uInt outputPos)
8826 : {
8827 0 : uInt halfWidth = smoothBin_p / 2;
8828 :
8829 : // Initialization
8830 0 : outputFlags(outputPos) = inputFlags(outputPos-halfWidth);
8831 0 : outputData(outputPos) = smoothCoeff_p(0)*inputData(outputPos-halfWidth);
8832 :
8833 : // Main loop
8834 0 : for (uInt i = 1; i<smoothBin_p;i++)
8835 : {
8836 0 : outputData(outputPos) += smoothCoeff_p(i)*inputData(outputPos-halfWidth+i);
8837 :
8838 : // Output sample is flagged if any of the contributors are flagged
8839 0 : if (inputFlags(outputPos-halfWidth+i)) outputFlags(outputPos)=true;
8840 : }
8841 :
8842 0 : return;
8843 : }
8844 :
8845 : // -----------------------------------------------------------------------
8846 : //
8847 : // -----------------------------------------------------------------------
8848 0 : template <class T> void MSTransformManager::plainSmoothSpectrum(const Vector<T> &inputData,
8849 : const Vector<bool> &inputFlags,
8850 : const Vector<Float> &,
8851 : Vector<T> &outputData,
8852 : Vector<bool> &outputFlags,
8853 : uInt outputPos)
8854 : {
8855 0 : uInt halfWidth = smoothBin_p / 2;
8856 :
8857 : // Initialization (mind for zeros as there is a division operation)
8858 0 : if (inputData(outputPos-halfWidth) <= FLT_MIN)
8859 : {
8860 0 : outputData(outputPos) = 0;
8861 0 : outputFlags(outputPos) = true;
8862 : }
8863 : else
8864 : {
8865 0 : outputFlags(outputPos) = inputFlags(outputPos-halfWidth);
8866 0 : outputData(outputPos) = smoothCoeff_p(0)*smoothCoeff_p(0)/inputData(outputPos-halfWidth);
8867 : }
8868 :
8869 : // Main accumulation loop
8870 0 : for (uInt i = 1; i<smoothBin_p;i++)
8871 : {
8872 : // Mind for zeros as there is a division operation
8873 0 : if (inputData(outputPos-halfWidth+i) <= FLT_MIN)
8874 : {
8875 0 : outputFlags(outputPos) = true;
8876 : }
8877 : else
8878 : {
8879 0 : outputData(outputPos) += smoothCoeff_p(i)*smoothCoeff_p(i)/inputData(outputPos-halfWidth+i);
8880 :
8881 : // Output sample is flagged if any of the contributors are flagged
8882 0 : if (inputFlags(outputPos-halfWidth+i)) outputFlags(outputPos)=true;
8883 : }
8884 : }
8885 :
8886 : // Final propaged weight si the inverse of the accumulation
8887 0 : if (outputData(outputPos) > FLT_MIN)
8888 : {
8889 0 : outputData(outputPos) = 1/outputData(outputPos);
8890 : }
8891 :
8892 0 : return;
8893 : }
8894 :
8895 : // -----------------------------------------------------------------------
8896 : //
8897 : // -----------------------------------------------------------------------
8898 0 : template <class T> void MSTransformManager::regrid(Int inputSpw,
8899 : const Vector<T> &inputDataStripe,
8900 : const Vector<bool> &inputFlagsStripe,
8901 : const Vector<Float> &inputWeightsStripe,
8902 : Vector<T> &outputDataStripe,
8903 : Vector<bool> &outputFlagsStripe)
8904 : {
8905 :
8906 0 : regridCore( inputSpw,
8907 : inputDataStripe,
8908 : inputFlagsStripe,
8909 : inputWeightsStripe,
8910 : outputDataStripe,
8911 : outputFlagsStripe);
8912 :
8913 0 : }
8914 :
8915 : // -----------------------------------------------------------------------
8916 : //
8917 : // -----------------------------------------------------------------------
8918 0 : void MSTransformManager::regridCore(Int inputSpw,
8919 : const Vector<Complex> &inputDataStripe,
8920 : const Vector<bool> &inputFlagsStripe,
8921 : const Vector<Float> &inputWeightsStripe,
8922 : Vector<Complex> &outputDataStripe,
8923 : Vector<bool> &outputFlagsStripe)
8924 : {
8925 :
8926 0 : (*this.*regridCoreComplex_p)( inputSpw,
8927 : inputDataStripe,
8928 : inputFlagsStripe,
8929 : inputWeightsStripe,
8930 : outputDataStripe,
8931 : outputFlagsStripe);
8932 0 : }
8933 :
8934 : // -----------------------------------------------------------------------
8935 : //
8936 : // -----------------------------------------------------------------------
8937 0 : void MSTransformManager::regridCore(Int inputSpw,
8938 : const Vector<Float> &inputDataStripe,
8939 : const Vector<bool> &inputFlagsStripe,
8940 : const Vector<Float> &inputWeightsStripe,
8941 : Vector<Float> &outputDataStripe,
8942 : Vector<bool> &outputFlagsStripe)
8943 : {
8944 0 : (*this.*regridCoreFloat_p)( inputSpw,
8945 : inputDataStripe,
8946 : inputFlagsStripe,
8947 : inputWeightsStripe,
8948 : outputDataStripe,
8949 : outputFlagsStripe);
8950 0 : }
8951 :
8952 : // -----------------------------------------------------------------------
8953 : //
8954 : // -----------------------------------------------------------------------
8955 0 : void MSTransformManager::fftshift(Int ,
8956 : const Vector<Complex> &inputDataStripe,
8957 : const Vector<bool> &inputFlagsStripe,
8958 : const Vector<Float> &,
8959 : Vector<Complex> &outputDataStripe,
8960 : Vector<bool> &outputFlagsStripe)
8961 : {
8962 0 : fFFTServer_p.fftshift(outputDataStripe,
8963 : outputFlagsStripe,
8964 0 : (const Vector<Complex>)inputDataStripe,
8965 0 : (const Vector<bool>)inputFlagsStripe,
8966 0 : (const uInt)0, // In vectors axis 0 is the only dimension
8967 0 : (const Double)fftShift_p,
8968 : false, // A good data point has its flag set to false
8969 : false);
8970 0 : }
8971 :
8972 : // -----------------------------------------------------------------------
8973 : //
8974 : // -----------------------------------------------------------------------
8975 0 : void MSTransformManager::fftshift(Int ,
8976 : const Vector<Float> &inputDataStripe,
8977 : const Vector<bool> &inputFlagsStripe,
8978 : const Vector<Float> &,
8979 : Vector<Float> &outputDataStripe,
8980 : Vector<bool> &outputFlagsStripe)
8981 : {
8982 0 : fFFTServer_p.fftshift(outputDataStripe,
8983 : outputFlagsStripe,
8984 0 : (const Vector<Float>)inputDataStripe,
8985 0 : (const Vector<bool>)inputFlagsStripe,
8986 0 : (const uInt)0, // In vectors axis 0 is the only dimension
8987 0 : (const Double)fftShift_p,
8988 : false); // A good data point has its flag set to false
8989 0 : }
8990 :
8991 : // -----------------------------------------------------------------------
8992 : //
8993 : // -----------------------------------------------------------------------
8994 0 : template <class T> void MSTransformManager::interpol1D(Int inputSpw,
8995 : const Vector<T> &inputDataStripe,
8996 : const Vector<bool> &inputFlagsStripe,
8997 : const Vector<Float> &,
8998 : Vector<T> &outputDataStripe,
8999 : Vector<bool> &outputFlagsStripe)
9000 : {
9001 0 : if (inputDataStripe.size() < 2) {
9002 0 : outputDataStripe = inputDataStripe(0);
9003 0 : outputFlagsStripe = true;
9004 0 : return;
9005 : }
9006 :
9007 0 : if (!regridTClean_p) {
9008 0 : InterpolateArray1D<Double,T>::interpolate(outputDataStripe, // Output data
9009 : outputFlagsStripe, // Output flags
9010 0 : inputOutputSpwMap_p[inputSpw].second.CHAN_FREQ, // Out chan freq
9011 0 : inputOutputSpwMap_p[inputSpw].first.CHAN_FREQ_aux, // In chan freq
9012 : inputDataStripe, // Input data
9013 : inputFlagsStripe, // Input Flags
9014 0 : interpolationMethod_p, // Interpolation method
9015 : false, // A good data point has its flag set to false
9016 : false // If false extrapolated data points are set flagged
9017 : );
9018 : } else {
9019 0 : interpolateByChannelMap(inputSpw,
9020 : inputDataStripe, inputFlagsStripe,
9021 : outputDataStripe, outputFlagsStripe);
9022 : }
9023 : }
9024 :
9025 : /**
9026 : * Introduced to mimic the way tclean regrids when the factor between
9027 : * the output channel width and the input channel width is > 2.
9028 : * Ref. TransformMachines2/FTMachine.cc
9029 : *
9030 : * Uses a map from original input channels => fake output channels,
9031 : * where the fake output channels have the (lower) width of the
9032 : * input channels but are projected/aligned with the output channel
9033 : * grid.
9034 : *
9035 : * @param spw spw index of the input channels, to fetch original
9036 : * input channel freqs
9037 : * @param inputDataStripe input data coming from regridCubeOfData,
9038 : * transformAndWriteCubeOfData, etc. and passed to the
9039 : * regrid/interpolation kernels.
9040 : * @param inputFlagsStripe flags for the inputDataStripe
9041 : * @param outputDataStripe will be interpolated by aggregating
9042 : * input visibilities into wider channels
9043 : * @param outputFlagsStripe flags for outputDataStripe
9044 : */
9045 0 : template <class T> void MSTransformManager::interpolateByChannelMap(Int spw,
9046 : const Vector<T> &inputDataStripe,
9047 : const Vector<bool> &inputFlagsStripe,
9048 : Vector<T> &outputDataStripe,
9049 : Vector<bool> &outputFlagsStripe)
9050 : {
9051 0 : Vector<T> intermDataStripe;
9052 0 : Vector<bool> intermFlagsStripe;
9053 : // Bring frequencies from input grid to fake output grid ( the
9054 : // one with same widths as the original input channels).
9055 0 : InterpolateArray1D<Double,T>::interpolate(intermDataStripe,
9056 : intermFlagsStripe,
9057 0 : regridTCleanCHAN_FREQ_p, // Out channel freqs
9058 0 : inputOutputSpwMap_p[spw].first.CHAN_FREQ_aux, // Input chan freqs
9059 : inputDataStripe,
9060 : inputFlagsStripe,
9061 0 : interpolationMethod_p,
9062 : false, // flags
9063 : false // extrapolated data points are set flagged
9064 : );
9065 :
9066 : // Aggregate fine grain fake output channels into the final
9067 : // output channels
9068 0 : outputDataStripe = 0;
9069 0 : Vector<Double> outWeights;
9070 0 : outWeights.resize(outputDataStripe.size());
9071 0 : outWeights = 0.;
9072 0 : for (uInt mapIdx = 0; mapIdx < regridTCleanChanMap_p.size(); ++mapIdx) {
9073 0 : Int outIdx = regridTCleanChanMap_p[mapIdx];
9074 0 : if (outIdx < 0)
9075 0 : continue;
9076 :
9077 0 : outputDataStripe[outIdx] = (outputDataStripe[outIdx] * outWeights[outIdx] +
9078 0 : intermDataStripe[mapIdx]) /
9079 0 : (1. + outWeights[outIdx]);
9080 0 : outWeights[outIdx] += 1;
9081 0 : outputFlagsStripe[outIdx] |= intermFlagsStripe[mapIdx];
9082 : }
9083 0 : }
9084 :
9085 : // ------------------------------------------------------------------------
9086 : // casacore::fftshift does not interpolate, it needs interpolation+fftshift
9087 : // ------------------------------------------------------------------------
9088 0 : template <class T> void MSTransformManager::interpol1Dfftshift(Int inputSpw,
9089 : const Vector<T> &inputDataStripe,
9090 : const Vector<bool> &inputFlagsStripe,
9091 : const Vector<Float> &inputWeightsStripe,
9092 : Vector<T> &outputDataStripe,
9093 : Vector<bool> &outputFlagsStripe)
9094 : {
9095 0 : Vector<T> regriddedDataStripe(outputDataStripe.shape(),T());
9096 0 : Vector<bool> regriddedFlagsStripe(outputFlagsStripe.shape(),false);
9097 :
9098 : // This linear interpolation provides a uniform grid (pre-condition to apply fftshift)
9099 0 : interpol1D(inputSpw,inputDataStripe,inputFlagsStripe,inputWeightsStripe,regriddedDataStripe,regriddedFlagsStripe);
9100 :
9101 : // fftshift takes care of time
9102 0 : fftshift(inputSpw,regriddedDataStripe,regriddedFlagsStripe,inputWeightsStripe,outputDataStripe,outputFlagsStripe);
9103 0 : }
9104 :
9105 : // -----------------------------------------------------------------------
9106 : //
9107 : // -----------------------------------------------------------------------
9108 0 : template <class T> void MSTransformManager::averageRegrid(Int inputSpw,
9109 : const Vector<T> &inputDataStripe,
9110 : const Vector<bool> &inputFlagsStripe,
9111 : const Vector<Float> &inputWeightsStripe,
9112 : Vector<T> &outputDataStripe,
9113 : Vector<bool> &outputFlagsStripe)
9114 : {
9115 0 : Vector<T> averagedDataStripe(numOfCombInterChanMap_p[inputSpw],T());
9116 0 : Vector<bool> averagedFlagsStripe(numOfCombInterChanMap_p[inputSpw],false);
9117 :
9118 0 : average(inputSpw,inputDataStripe,inputFlagsStripe,inputWeightsStripe, averagedDataStripe,averagedFlagsStripe);
9119 :
9120 0 : regrid(inputSpw,averagedDataStripe,averagedFlagsStripe,inputWeightsStripe,outputDataStripe,outputFlagsStripe);
9121 :
9122 0 : return;
9123 0 : }
9124 :
9125 : // -----------------------------------------------------------------------
9126 : //
9127 : // -----------------------------------------------------------------------
9128 0 : template <class T> void MSTransformManager::smoothRegrid(Int inputSpw,
9129 : const Vector<T> &inputDataStripe,
9130 : const Vector<bool> &inputFlagsStripe,
9131 : const Vector<Float> &inputWeightsStripe,
9132 : Vector<T> &outputDataStripe,
9133 : Vector<bool> &outputFlagsStripe)
9134 : {
9135 0 : Vector<T> smoothedDataStripe(inputDataStripe.shape(),T());
9136 0 : Vector<bool> smoothedFlagsStripe(inputFlagsStripe.shape(),false);
9137 :
9138 0 : smooth(inputSpw,inputDataStripe,inputFlagsStripe,inputWeightsStripe,smoothedDataStripe,smoothedFlagsStripe);
9139 :
9140 0 : regrid(inputSpw,smoothedDataStripe,smoothedFlagsStripe,inputWeightsStripe,outputDataStripe,outputFlagsStripe);
9141 :
9142 0 : return;
9143 0 : }
9144 :
9145 : // -----------------------------------------------------------------------
9146 : //
9147 : // -----------------------------------------------------------------------
9148 0 : template <class T> void MSTransformManager::averageSmooth(Int inputSpw,
9149 : const Vector<T> &inputDataStripe,
9150 : const Vector<bool> &inputFlagsStripe,
9151 : const Vector<Float> &inputWeightsStripe,
9152 : Vector<T> &outputDataStripe,
9153 : Vector<bool> &outputFlagsStripe)
9154 : {
9155 0 : Vector<T> averagedDataStripe(outputDataStripe.shape(),T());
9156 0 : Vector<bool> averagedFlagsStripe(outputFlagsStripe.shape(),false);
9157 :
9158 0 : average(inputSpw,inputDataStripe,inputFlagsStripe,inputWeightsStripe, averagedDataStripe,averagedFlagsStripe);
9159 :
9160 0 : smooth(inputSpw,averagedDataStripe,averagedFlagsStripe, inputWeightsStripe, outputDataStripe,outputFlagsStripe);
9161 :
9162 0 : return;
9163 0 : }
9164 :
9165 : // -----------------------------------------------------------------------
9166 : //
9167 : // -----------------------------------------------------------------------
9168 0 : template <class T> void MSTransformManager::averageSmoothRegrid(Int inputSpw,
9169 : const Vector<T> &inputDataStripe,
9170 : const Vector<bool> &inputFlagsStripe,
9171 : const Vector<Float> &inputWeightsStripe,
9172 : Vector<T> &outputDataStripe,
9173 : Vector<bool> &outputFlagsStripe)
9174 : {
9175 0 : Vector<T> averageSmoothedDataStripe(numOfCombInterChanMap_p[inputSpw],T());
9176 0 : Vector<bool> averageSmoothedFlagsStripe(numOfCombInterChanMap_p[inputSpw],false);
9177 :
9178 0 : averageSmooth( inputSpw,inputDataStripe,inputFlagsStripe,
9179 : inputWeightsStripe,averageSmoothedDataStripe,averageSmoothedFlagsStripe);
9180 :
9181 0 : regrid( inputSpw,averageSmoothedDataStripe,averageSmoothedFlagsStripe,
9182 : inputWeightsStripe,outputDataStripe,outputFlagsStripe);
9183 :
9184 0 : return;
9185 0 : }
9186 :
9187 : // -----------------------------------------------------------------------
9188 : //
9189 : // -----------------------------------------------------------------------
9190 0 : void MSTransformManager::smoothFourierFloat(Int,
9191 : const Vector<Float> &inputDataStripe,
9192 : const Vector<bool> &inputFlagStripe,
9193 : const Vector<Float> &,
9194 : Vector<Float> &outputDataStripe,
9195 : Vector<bool> &outputFlagStripe)
9196 : {
9197 : // replace flagged channel data with zero
9198 0 : auto mutableInputDataStripe = inputDataStripe;
9199 0 : Int const numChan = mutableInputDataStripe.nelements();
9200 0 : for (Int ichan = 0; ichan < numChan; ++ichan) {
9201 0 : if (inputFlagStripe[ichan]) {
9202 0 : mutableInputDataStripe[ichan] = 0.0f;
9203 : }
9204 : }
9205 :
9206 : // execute convolution
9207 0 : Convolver<Float> *convolver = getConvolver(numChan);
9208 0 : convolver->linearConv(outputDataStripe, mutableInputDataStripe);
9209 :
9210 : // copy input flags
9211 0 : outputFlagStripe = inputFlagStripe;
9212 0 : }
9213 :
9214 : // -----------------------------------------------------------------------
9215 : //
9216 : // -----------------------------------------------------------------------
9217 0 : void MSTransformManager::smoothFourierComplex(Int n,
9218 : const Vector<Complex> &inputDataStripe,
9219 : const Vector<bool> &inputFlagStripe,
9220 : const Vector<Float> &inputWeightStripe,
9221 : Vector<Complex> &outputDataStripe, Vector<bool> &outputFlagStripe)
9222 : {
9223 0 : Vector<Float> inputDataStripeFloat = real(inputDataStripe);
9224 0 : Vector<Float> outputDataStripeFloat(inputDataStripeFloat.nelements());
9225 0 : smoothFourierFloat(n, inputDataStripeFloat, inputFlagStripe,
9226 : inputWeightStripe, outputDataStripeFloat, outputFlagStripe);
9227 0 : convertArray(outputDataStripe, outputDataStripeFloat);
9228 0 : }
9229 :
9230 : // -----------------------------------------------------------------------
9231 : //
9232 : // -----------------------------------------------------------------------
9233 0 : Convolver<Float> *MSTransformManager::getConvolver(Int const numChan) {
9234 0 : if (convolverPool_.find(numChan) == convolverPool_.end()) {
9235 0 : throw AipsError("Failed to get convolver. Smoothing is not properly configured.");
9236 : }
9237 0 : return &convolverPool_[numChan];
9238 : }
9239 :
9240 : } //# NAMESPACE CASA - END
|