Line data Source code
1 : //# SubMS.cc
2 : //# Copyright (C) 1996-2007
3 : //# Associated Universities, Inc. Washington DC, USA.
4 : //#
5 : //# This library is free software; you can redistribute it and/or modify
6 : //# it under the terms of the GNU General Public License as published by
7 : //# the Free Software Foundation; either version 2 of the License, or
8 : //# (at your option) any later version.
9 : //#
10 : //# This library is distributed in the hope that it will be useful,
11 : //# but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : //# GNU General Public License for more details.
14 : //#
15 : //# You should have received a copy of the GNU General Public License
16 : //# along with this library; if not, write to the Free Software
17 : //# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 : //#
19 : //# Correspondence concerning AIPS++ should be addressed as follows:
20 : //# Internet email: casa-feedback@nrao.edu.
21 : //# Postal address: AIPS++ Project Office
22 : //# National Radio Astronomy Observatory
23 : //# 520 Edgemont Road
24 : //# Charlottesville, VA 22903-2475 USA
25 : //#
26 : //# $Id: $
27 :
28 : // To make Timer reports in the inner loop of the simple copy,
29 : // uncomment the following line:
30 : //#define COPYTIMER
31 :
32 : #include <msvis/MSVis/SubMS.h>
33 : #include <asdmstman/AsdmStMan.h>
34 : #include <casacore/ms/MSSel/MSSelection.h>
35 : //#include <ms/MSSel/MSTimeGram.h>
36 : //#include <tables/TaQL/ExprNode.h>
37 : #include <casacore/tables/Tables/RefRows.h>
38 : #include <casacore/ms/MeasurementSets/MSColumns.h>
39 : #include <casacore/coordinates/Coordinates/CoordinateUtil.h>
40 : #include <casacore/casa/Arrays/Matrix.h>
41 : #include <casacore/casa/Arrays/Cube.h>
42 : #include <casacore/casa/Arrays/ArrayMath.h>
43 : #include <casacore/casa/Arrays/ArrayOpsDiffShapes.h>
44 : #include <casacore/casa/Arrays/ArrayLogical.h>
45 : #include <casacore/casa/Arrays/ArrayUtil.h>
46 : #include <casacore/casa/Arrays/IPosition.h>
47 : #include <casacore/casa/Arrays/Slice.h>
48 : #include <casacore/casa/BasicSL/Complex.h>
49 : #include <casacore/casa/Logging/LogIO.h>
50 : #include <casacore/casa/OS/File.h>
51 : #include <casacore/casa/OS/Directory.h>
52 : #include <casacore/casa/OS/HostInfo.h>
53 : #include <casacore/casa/OS/Memory.h> // Can be commented out along with
54 : // // Memory:: calls.
55 :
56 : //#ifdef COPYTIMER
57 : #include <casacore/casa/OS/Timer.h>
58 : //#endif
59 :
60 : #include <casacore/casa/Containers/Record.h>
61 : #include <casacore/casa/BasicSL/String.h>
62 : #include <casacore/casa/Utilities/Assert.h>
63 : #include <casacore/casa/Utilities/GenSort.h>
64 : #include <casacore/casa/System/AppInfo.h>
65 : #include <casacore/casa/System/ProgressMeter.h>
66 : #include <casacore/casa/Quanta/QuantumHolder.h>
67 : #include <msvis/MSVis/GroupProcessor.h>
68 : //#include <msvis/MSVis/VisSet.h>
69 : #include <msvis/MSVis/VisBuffer.h>
70 : #include <msvis/MSVis/VisBufferComponents.h>
71 : #include <msvis/MSVis/VBGContinuumSubtractor.h>
72 : #include <msvis/MSVis/VBRemapper.h>
73 : #include <msvis/MSVis/VisChunkAverager.h>
74 : #include <msvis/MSVis/VisIterator.h>
75 : //#include <msvis/MSVis/VisibilityIterator.h>
76 : #include <casacore/tables/DataMan/IncrementalStMan.h>
77 : #include <casacore/tables/Tables/ScalarColumn.h>
78 : #include <casacore/tables/Tables/ScaColDesc.h>
79 : #include <casacore/tables/Tables/SetupNewTab.h>
80 : #include <casacore/tables/DataMan/StandardStMan.h>
81 : #include <casacore/tables/Tables/Table.h>
82 : #include <casacore/tables/Tables/PlainTable.h>
83 : #include <casacore/tables/Tables/TableDesc.h>
84 : #include <casacore/tables/Tables/TableInfo.h>
85 : #include <casacore/tables/Tables/TableLock.h>
86 : #include <casacore/tables/Tables/TableRecord.h>
87 : #include <casacore/tables/Tables/TableCopy.h>
88 : #include <casacore/tables/Tables/TableRow.h>
89 : #include <casacore/tables/DataMan/TiledColumnStMan.h>
90 : #include <casacore/tables/DataMan/TiledShapeStMan.h>
91 : #include <casacore/tables/DataMan/TiledDataStMan.h>
92 : #include <casacore/tables/DataMan/TiledStManAccessor.h>
93 : #include <casacore/ms/MeasurementSets/MSTileLayout.h>
94 : #include <casacore/scimath/Mathematics/InterpolateArray1D.h>
95 : #include <casacore/scimath/Mathematics/FFTServer.h>
96 : #include <sstream>
97 : #include <iomanip>
98 : #include <functional>
99 : #include <map>
100 : #include <set>
101 : #include <casacore/measures/Measures/MeasTable.h>
102 : #include <casacore/scimath/Mathematics/Smooth.h>
103 : #include <casacore/casa/Quanta/MVTime.h>
104 :
105 :
106 : using namespace casacore;
107 :
108 :
109 : namespace casa {
110 :
111 : typedef ROVisibilityIterator ROVisIter;
112 : typedef VisibilityIterator VisIter;
113 :
114 : namespace subms {
115 :
116 :
117 : // Weight <-> Sigma routines
118 : // A value in zero in either will be interpretted as
119 : // practically zero weight (~inf noise), w/out generating
120 : // inf or NaN
121 4925 : Double wtToSigma(Double wt)
122 : {
123 : // sig = 1/sqrt(wt)
124 4925 : return wt > 0.0 ? 1.0 / sqrt(wt) : FLT_MAX;
125 : }
126 2987511 : Double sigToWeight(Double sig)
127 : {
128 : // wt = 1/square(sig)
129 2987511 : return sig > 0.0 ? 1.0 / square(sig) : FLT_EPSILON;
130 : }
131 :
132 : } // end namespace subms
133 :
134 : //#warning "Debugging kluge here"
135 : //inline Complex operator*(const Complex& val, Double f) { return val*Float(f); }
136 : //
137 :
138 54 : SubMS::SubMS(String& theMS, Table::TableOption option) :
139 54 : ms_p(MeasurementSet(theMS, option)),
140 54 : mssel_p(ms_p),
141 54 : msc_p(NULL),
142 54 : mscIn_p(NULL),
143 54 : keepShape_p(true),
144 : // sameShape_p(true),
145 54 : antennaSel_p(false),
146 54 : timeBin_p(-1.0),
147 54 : scanString_p(""),
148 54 : intentString_p(""),
149 54 : obsString_p(""),
150 54 : uvrangeString_p(""),
151 54 : taqlString_p(""),
152 54 : timeRange_p(""),
153 54 : arrayExpr_p(""),
154 54 : combine_p(""),
155 54 : fitorder_p(-1),
156 54 : fitspw_p("*"),
157 54 : fitoutspw_p("*"),
158 54 : fillMainTable_p(True),
159 54 : tvi_debug(False),
160 162 : want_cont_p(False)
161 : {
162 54 : }
163 :
164 196 : SubMS::SubMS(MeasurementSet& ms) :
165 196 : ms_p(ms),
166 196 : mssel_p(ms_p),
167 196 : msc_p(NULL),
168 196 : mscIn_p(NULL),
169 196 : keepShape_p(true),
170 : //sameShape_p(true),
171 196 : antennaSel_p(false),
172 196 : timeBin_p(-1.0),
173 196 : scanString_p(""),
174 196 : intentString_p(""),
175 196 : obsString_p(""),
176 196 : uvrangeString_p(""),
177 196 : taqlString_p(""),
178 196 : timeRange_p(""),
179 196 : arrayExpr_p(""),
180 196 : combine_p(""),
181 196 : fitorder_p(-1),
182 196 : fitspw_p("*"),
183 196 : fitoutspw_p("*"),
184 196 : fillMainTable_p(true),
185 196 : tvi_debug(False),
186 588 : want_cont_p(False)
187 : {
188 196 : }
189 :
190 348 : SubMS::~SubMS()
191 : {
192 250 : delete msc_p;
193 250 : msc_p = nullptr;
194 :
195 250 : delete mscIn_p;
196 250 : mscIn_p = nullptr;
197 :
198 250 : msOut_p=MeasurementSet();
199 :
200 : // parseColumnNames unavoidably has a static String and Vector<MS::PredefinedColumns>.
201 : // Collapse them down to free most of that memory.
202 250 : parseColumnNames("None");
203 :
204 348 : }
205 :
206 44 : std::set<Int> SubMS::findBadSpws(MeasurementSet& ms, Vector<Int> spwv)
207 : {
208 44 : ScalarColumn<Int> spws_in_dd(ms.dataDescription(),
209 44 : MSDataDescription::columnName(MSDataDescription::SPECTRAL_WINDOW_ID));
210 44 : std::set<Int> uniqSpwsInDD;
211 44 : uInt nspwsInDD = spws_in_dd.nrow();
212 443 : for(uInt ddrow = 0; ddrow < nspwsInDD; ++ddrow)
213 399 : uniqSpwsInDD.insert(spws_in_dd(ddrow));
214 44 : std::set<Int>::iterator ddend = uniqSpwsInDD.end();
215 44 : std::set<Int> badSelSpwSlots;
216 171 : for(uInt k = 0; k < spwv.nelements(); ++k){
217 127 : if(uniqSpwsInDD.find(spwv[k]) == ddend){
218 0 : badSelSpwSlots.insert(k);
219 : }
220 : }
221 88 : return badSelSpwSlots;
222 44 : }
223 :
224 : // This is the version used by split.
225 44 : Bool SubMS::selectSpw(const String& spwstr, const Vector<Int>& steps)
226 : {
227 88 : LogIO os(LogOrigin("SubMS", "selectSpw()"));
228 :
229 44 : MSSelection mssel;
230 44 : String myspwstr(spwstr == "" ? "*" : spwstr);
231 :
232 44 : mssel.setSpwExpr(myspwstr);
233 :
234 44 : widths_p = steps.copy();
235 44 : if(widths_p.nelements() < 1){
236 0 : widths_p.resize(1);
237 0 : widths_p[0] = 1;
238 : }
239 : else{
240 88 : for(uInt k = 0; k < widths_p.nelements(); ++k){
241 44 : if(widths_p[k] == 0){
242 : os << LogIO::WARN
243 : << "0 cannot be used for channel width...using 1 instead."
244 0 : << LogIO::POST;
245 0 : widths_p[k] = 1;
246 : }
247 : }
248 : }
249 :
250 : // Each row should have spw, start, stop, step
251 : // A single width is a default, but multiple widths should be used
252 : // literally.
253 44 : Matrix<Int> chansel = mssel.getChanList(&ms_p, 1);
254 :
255 44 : if(chansel.nrow() > 0) { // Use myspwstr if it selected anything...
256 44 : spw_p = chansel.column(0);
257 44 : chanStart_p = chansel.column(1);
258 44 : chanEnd_p = chansel.column(2);
259 44 : chanStep_p = chansel.column(3);
260 :
261 44 : uInt nspw = chanEnd_p.nelements();
262 44 : nchan_p.resize(nspw);
263 :
264 : // A single width is a default, but multiple widths should be used
265 : // literally.
266 44 : if(widths_p.nelements() > 1 && widths_p.nelements() != spw_p.nelements()){
267 : os << LogIO::SEVERE
268 : << "Mismatch between the # of widths specified by width and the # of spws."
269 0 : << LogIO::POST;
270 0 : return false;
271 : }
272 :
273 : // Copy the default width to all spws.
274 44 : if(widths_p.nelements() < nspw){
275 25 : widths_p.resize(nspw, true);
276 108 : for(uInt k = 1; k < nspw; ++k)
277 83 : widths_p[k] = widths_p[0];
278 : }
279 :
280 171 : for(uInt k = 0; k < nspw; ++k){
281 127 : if(chanStep_p[k] == 0) // CAS-2224, triggered by spw='0:2'
282 0 : chanStep_p[k] = 1; // (as opposed to '0:2~2').
283 :
284 : // if((nchan_p[k] - chanStart_p[k] + 1) % (chanStep_p[k] * widths_p[k]) != 0)
285 : // os << LogIO::WARN
286 : // << "The number of selected channels, " << nchan_p[k]
287 : // << ", for spw " << spw_p[k] << " is not a multiple of the increment, "
288 : // << chanStep_p[k] * widths_p[k] << ".\n"
289 : // << "The reported width and frequency of the final channel may be"
290 : // << "\noff by a fraction of a channel width.\n"
291 : // << "(This is being worked on.)"
292 : // << LogIO::POST;
293 :
294 127 : nchan_p[k] = 1 + (chanEnd_p[k] -
295 127 : chanStart_p[k]) / (chanStep_p[k] * widths_p[k]);
296 127 : if(nchan_p[k] < 1)
297 0 : nchan_p[k] = 1;
298 : }
299 : }
300 : else{ // select everything and rely on widths.
301 0 : MSSpWindowColumns mySpwTab(ms_p.spectralWindow());
302 0 : uInt nspw = mySpwTab.nrow();
303 :
304 0 : nchan_p = mySpwTab.numChan().getColumn();
305 :
306 0 : spw_p.resize(nspw);
307 0 : indgen(spw_p);
308 :
309 0 : chanStart_p.resize(nspw);
310 0 : chanStep_p.resize(nspw);
311 0 : for(uInt k = 0; k < nspw; ++k){
312 0 : chanStart_p[k] = 0;
313 0 : chanEnd_p[k] = nchan_p[k] - 1;
314 0 : chanStep_p[k] = 1;
315 : }
316 :
317 0 : if(widths_p.nelements() != spw_p.nelements()){
318 0 : if(widths_p.nelements() == 1){
319 0 : widths_p.resize(spw_p.nelements(), true);
320 0 : for(uInt k = 1; k < spw_p.nelements(); ++k)
321 0 : widths_p[k] = widths_p[0];
322 : }
323 : else{
324 : os << LogIO::SEVERE
325 : << "Mismatch between the # of widths specified by width and the # of spws."
326 0 : << LogIO::POST;
327 0 : return false;
328 : }
329 : }
330 :
331 0 : for(uInt k = 0; k < nspw; ++k){
332 : // if((nchan_p[k] + 1) % (chanStep_p[k] * widths_p[k]) != 0)
333 : // os << LogIO::WARN
334 : // << "The number of selected channels, " << nchan_p[k]
335 : // << ", for spw " << spw_p[k] << " is not a multiple of the increment, "
336 : // << chanStep_p[k] * widths_p[k] << ".\n"
337 : // << "The reported width and frequency of the final channel may be"
338 : // << "\noff by a fraction of a channel width.\n"
339 : // << "(This is being worked on.)"
340 : // << LogIO::POST;
341 :
342 0 : nchan_p[k] = 1 + (nchan_p[k] - 1) / widths_p[k];
343 : }
344 0 : }
345 :
346 : // Check for and filter out selected spws that aren't included in
347 : // DATA_DESCRIPTION. (See CAS-1673 for an example.)
348 44 : std::set<Int> badSelSpwSlots(SubMS::findBadSpws(ms_p, spw_p));
349 44 : uInt nbadSelSpwSlots = badSelSpwSlots.size();
350 44 : if(nbadSelSpwSlots > 0){
351 0 : os << LogIO::WARN << "Selected input spw(s)\n";
352 0 : for(std::set<Int>::iterator bbit = badSelSpwSlots.begin();
353 0 : bbit != badSelSpwSlots.end(); ++bbit)
354 0 : os << spw_p[*bbit] << " ";
355 : os << "\nwere not found in DATA_DESCRIPTION and are being excluded."
356 0 : << LogIO::POST;
357 :
358 0 : uInt nSelSpw = spw_p.nelements();
359 0 : uInt ngoodSelSpwSlots = nSelSpw - nbadSelSpwSlots;
360 0 : Vector<Int> spwc(ngoodSelSpwSlots);
361 0 : Vector<Int> chanStartc(ngoodSelSpwSlots);
362 0 : Vector<Int> chanEndc(ngoodSelSpwSlots);
363 0 : Vector<Int> nchanc(ngoodSelSpwSlots);
364 0 : Vector<Int> chanStepc(ngoodSelSpwSlots);
365 0 : std::set<Int>::iterator bsend = badSelSpwSlots.end();
366 :
367 0 : uInt j = 0;
368 0 : for(uInt k = 0; k < nSelSpw; ++k){
369 0 : if(badSelSpwSlots.find(k) == bsend){
370 0 : spwc[j] = spw_p[k];
371 0 : chanStartc[j] = chanStart_p[k];
372 0 : chanEndc[j] = chanEnd_p[k];
373 0 : nchanc[j] = nchan_p[k];
374 0 : chanStepc[j] = chanStep_p[k];
375 0 : ++j;
376 : }
377 : }
378 0 : spw_p.resize(ngoodSelSpwSlots);
379 0 : spw_p = spwc;
380 0 : chanStart_p.resize(ngoodSelSpwSlots);
381 0 : chanStart_p = chanStartc;
382 0 : chanEnd_p.resize(ngoodSelSpwSlots);
383 0 : chanEnd_p = chanEndc;
384 0 : nchan_p.resize(ngoodSelSpwSlots);
385 0 : nchan_p = nchanc;
386 0 : chanStep_p.resize(ngoodSelSpwSlots);
387 0 : chanStep_p = chanStepc;
388 0 : }
389 :
390 44 : mssel.getChanSlices(chanSlices_p, &ms_p, 1);
391 44 : return true;
392 44 : }
393 :
394 : // This older version is used elsewhere.
395 0 : void SubMS::selectSpw(Vector<Int> spw, Vector<Int> nchan, Vector<Int> start,
396 : Vector<Int> step)
397 : {
398 0 : spw_p.resize();
399 0 : spw_p = spw;
400 :
401 : //check for default
402 0 : if(spw_p.nelements() == 1 && spw_p[0] < 0){
403 0 : spw_p.resize(ms_p.spectralWindow().nrow());
404 0 : indgen(spw_p);
405 :
406 : //no may be we have to redo the chan selection
407 :
408 0 : if (nchan.nelements() != spw_p.nelements()){
409 0 : nchan.resize(spw_p.nelements(), true);
410 0 : for(uInt k = 1; k < spw_p.nelements(); ++k){
411 0 : nchan[k] = nchan[0];
412 : }
413 : }
414 0 : if (start.nelements() != spw_p.nelements()){
415 0 : start.resize(spw_p.nelements(), true);
416 0 : for(uInt k = 1; k < spw_p.nelements(); ++k){
417 0 : start[k] = start[0];
418 : }
419 : }
420 0 : if (step.nelements() != spw_p.nelements()){
421 0 : step.resize(spw_p.nelements(), true);
422 0 : for(uInt k = 1; k < spw_p.nelements(); ++k){
423 0 : step[k] = step[0];
424 : }
425 : }
426 : }
427 :
428 0 : nchan_p.resize();
429 0 : nchan_p = nchan;
430 0 : chanStart_p.resize();
431 0 : chanStart_p = start;
432 0 : chanEnd_p.resize(spw_p.nelements());
433 0 : for(uInt k =0; k < spw_p.nelements(); ++k)
434 0 : chanEnd_p[k] = nchan[k] - 1;
435 0 : chanStep_p.resize();
436 0 : chanStep_p = step;
437 : // check for defaults
438 0 : if(nchan_p[0]<=0 || (nchan_p.nelements() != spw_p.nelements())){
439 0 : nchan_p.resize(spw_p.nelements());
440 0 : MSSpWindowColumns mySpwTab(ms_p.spectralWindow());
441 0 : for (uInt k =0; k < spw_p.nelements(); ++k){
442 0 : if(nchan[0]<=0)
443 0 : nchan_p[k]=mySpwTab.numChan()(spw_p[k]);
444 : else
445 0 : nchan_p[k]=nchan[0];
446 0 : chanEnd_p[k] = nchan_p[k] - 1;
447 : }
448 0 : chanStart_p.resize(spw_p.nelements());
449 0 : chanStep_p.resize(spw_p.nelements());
450 0 : if(chanStart_p.nelements() == start.nelements()){
451 0 : chanStart_p=start;
452 : }
453 : else{
454 0 : chanStart_p.set(start[0]);
455 : }
456 0 : if(chanStep_p.nelements() == step.nelements()){
457 0 : chanStep_p=step;
458 : }
459 : else{
460 0 : chanStep_p.set(step[0]);
461 : }
462 0 : }
463 0 : }
464 :
465 : // selectSpw must be called first because this uses spwRelabel_p!
466 44 : Bool SubMS::selectCorrelations(const String& corrstr)
467 : {
468 88 : LogIO os(LogOrigin("SubMS", "selectCorrelations()"));
469 44 : MSSelection mssel;
470 44 : const Bool areSelecting = corrstr != "" && corrstr != "*";
471 :
472 44 : if(areSelecting)
473 0 : mssel.setPolnExpr(corrstr);
474 44 : corrString_p = corrstr;
475 44 : mssel.getCorrSlices(corrSlices_p, &ms_p);
476 88 : return getCorrMaps(mssel, ms_p, inPolOutCorrToInCorrMap_p, areSelecting);
477 44 : }
478 :
479 44 : Bool SubMS::getCorrMaps(MSSelection& mssel, const MeasurementSet& ms,
480 : Vector<Vector<Int> >& outToIn, const Bool areSelecting)
481 : {
482 44 : Bool cando = true;
483 :
484 44 : uInt npol = ms.polarization().nrow(); // The total number of polids
485 :
486 : // Nominally empty selection for all polids
487 44 : outToIn.resize(npol);
488 44 : outToIn.set(Vector<Int>());
489 :
490 44 : if(areSelecting){
491 : // Get the corr indices as an ordered map
492 0 : std::map<Int, Vector<Vector<Int> > > corrmap(mssel.getCorrMap(&ms));
493 :
494 : // Iterate over the ordered map to fill the vector maps
495 0 : for( auto mi = corrmap.begin( ); mi != corrmap.end( ); ++mi ) {
496 0 : Int pol = mi->first;
497 0 : outToIn[pol] = mi->second[0];
498 : }
499 0 : }
500 : else{ // Make outToIn an identity map.
501 44 : ScalarColumn<Int> numCorr(ms.polarization(),
502 44 : MSPolarization::columnName(MSPolarization::NUM_CORR));
503 :
504 89 : for(uInt polid = 0; polid < npol; ++polid){
505 45 : uInt ncorr = numCorr(polid);
506 :
507 45 : outToIn[polid].resize(ncorr);
508 134 : for(uInt cid = 0; cid < ncorr; ++cid)
509 89 : outToIn[polid][cid] = cid;
510 : }
511 44 : }
512 44 : return cando;
513 : }
514 :
515 : // This is the one used by split.
516 44 : Bool SubMS::setmsselect(const String& spw, const String& field,
517 : const String& baseline, const String& scan,
518 : const String& uvrange, const String& taql,
519 : const Vector<Int>& step, const String& subarray,
520 : const String& correlation, const String& intent,
521 : const String& obs)
522 : {
523 88 : LogIO os(LogOrigin("SubMS", "setmsselect()"));
524 : Bool ok;
525 :
526 44 : String myspwstr(spw == "" ? "*" : spw);
527 88 : Record selrec = ms_p.msseltoindex(myspwstr, field);
528 :
529 44 : ok = selectSource(selrec.asArrayInt("field"));
530 :
531 : // All of the requested selection functions will be tried, even if an
532 : // earlier one has indicated its failure. This allows all of the selection
533 : // strings to be tested, yielding more complete feedback for the user
534 : // (fewer retries). This is a matter of taste, though. If the selections
535 : // turn out to be slow, this function should return on the first false.
536 :
537 44 : if(!selectSpw(myspwstr, step)){
538 0 : os << LogIO::SEVERE << "No channels selected." << LogIO::POST;
539 0 : ok = false;
540 : }
541 :
542 44 : if(baseline != ""){
543 0 : Vector<Int> antid(0);
544 0 : Vector<String> antstr(1,baseline);
545 0 : selectAntenna(antid, antstr);
546 0 : }
547 44 : scanString_p = scan;
548 44 : intentString_p = intent;
549 44 : obsString_p = obs;
550 44 : uvrangeString_p = uvrange;
551 44 : taqlString_p = taql;
552 :
553 44 : if(subarray != "")
554 0 : selectArray(subarray);
555 :
556 44 : if(!selectCorrelations(correlation)){
557 0 : os << LogIO::SEVERE << "No correlations selected." << LogIO::POST;
558 0 : ok = false;
559 : }
560 :
561 44 : return ok;
562 44 : }
563 :
564 : // This is the older version, used elsewhere.
565 0 : void SubMS::setmsselect(const String& spw, const String& field,
566 : const String& baseline, const String& scan,
567 : const String& obs, const String& uvrange,
568 : const String& taql, const Vector<Int>& nchan,
569 : const Vector<Int>& start, const Vector<Int>& step,
570 : const String& subarray, const String& intent)
571 : {
572 0 : Vector<Int> inchan(1, -1);
573 0 : Vector<Int> istart(1, 0);
574 0 : Vector<Int> istep(1, 1);
575 0 : Record selrec = ms_p.msseltoindex(spw, field);
576 0 : Vector<Int> spwids = selrec.asArrayInt("spw");
577 :
578 0 : selectSource(selrec.asArrayInt("field"));
579 0 : if(spwids.nelements() < 1)
580 0 : spwids=Vector<Int>(1, -1);
581 :
582 : //use nchan if defined else use caret-column syntax of msselection
583 0 : if((nchan.nelements()>0) && nchan[0] > 0){
584 0 : inchan.resize(); inchan=nchan;
585 0 : if((step.nelements() >0 ) && (step.nelements() != nchan.nelements()) && (nchan.nelements() >1)){
586 0 : istep[0]=step[0];
587 : }
588 0 : if(step.nelements() != nchan.nelements()){
589 0 : istep.resize(nchan.nelements(), true);
590 0 : istep.set(istep[0]);
591 : }
592 : else{
593 0 : istep.resize(); istep=step;
594 : }
595 0 : if((start.nelements() >0 ) && (start.nelements() != nchan.nelements()) && (nchan.nelements() >1)){
596 0 : istart[0]=start[0];
597 : }
598 0 : if(start.nelements() != nchan.nelements()){
599 0 : istart.resize(nchan.nelements(), true);
600 0 : istart.set(istart[0]);
601 : }
602 : else{
603 0 : istart.resize(); istart=start;
604 : }
605 : }
606 : else{
607 0 : Matrix<Int> chansel=selrec.asArrayInt("channel");
608 0 : if(chansel.nelements() != 0){
609 0 : inchan.resize(chansel.nrow());
610 0 : istep.resize(chansel.nrow());
611 0 : istart.resize(chansel.nrow());
612 : // if the vector step is used ..for averaging ..let's use it
613 0 : Bool stepused=false;
614 0 : if( (step.nelements() >= 1) && (max(step) > 1))
615 0 : stepused=true;
616 0 : for (uInt k =0 ; k < chansel.nrow(); ++k){
617 0 : if(stepused){
618 0 : if(step.nelements() == 1)
619 0 : istep[k] = step[0];
620 0 : else if(step.nelements() == istep.nelements())
621 0 : istep[k] = step[k];
622 : else //confused at this stage
623 0 : istep[k] = 1;
624 : }
625 : else{
626 0 : istep[k] = chansel.row(k)(3);
627 0 : if(istep[k] < 1)
628 0 : istep[k] = 1;
629 : }
630 0 : istart[k] = chansel.row(k)(1);
631 0 : inchan[k] = (chansel.row(k)(2) - istart[k] + 1) / istep[k];
632 0 : if(inchan[k] < 1)
633 0 : inchan[k] = 1;
634 : }
635 : }
636 0 : }
637 0 : selectSpw(spwids, inchan, istart, istep);
638 :
639 0 : if(baseline != ""){
640 0 : Vector<Int> antid(0);
641 0 : Vector<String> antstr(1,baseline);
642 0 : selectAntenna(antid, antstr);
643 0 : }
644 0 : scanString_p = scan;
645 0 : obsString_p = obs;
646 0 : uvrangeString_p = uvrange;
647 0 : taqlString_p = taql;
648 0 : intentString_p = intent;
649 :
650 0 : if(subarray != "")
651 0 : selectArray(subarray);
652 0 : }
653 :
654 :
655 44 : Bool SubMS::selectSource(const Vector<Int>& fieldid)
656 : {
657 88 : LogIO os(LogOrigin("SubMS", "selectSource()"));
658 44 : Bool cando = true;
659 :
660 44 : if(fieldid.nelements() < 1){
661 12 : fieldid_p = Vector<Int>(1, -1);
662 : }
663 32 : else if(fieldid.nelements() > ms_p.field().nrow()){
664 : os << LogIO::SEVERE
665 : << "More fields were requested than are in the input MS.\n"
666 0 : << LogIO::POST;
667 0 : cando = false;
668 : }
669 32 : else if(max(fieldid) >= static_cast<Int>(ms_p.field().nrow())){
670 : // Arriving here is very unlikely since if fieldid came from MSSelection
671 : // bad fields were presumably already quietly dropped.
672 : os << LogIO::SEVERE
673 : << "At least 1 field was requested that is not in the input MS.\n"
674 0 : << LogIO::POST;
675 0 : cando = false;
676 : }
677 : else{
678 32 : fieldid_p = fieldid;
679 : }
680 :
681 44 : if(fieldid_p.nelements() == 1 && fieldid_p[0] < 0){
682 12 : fieldid_p.resize(ms_p.field().nrow());
683 12 : indgen(fieldid_p);
684 : }
685 44 : return cando;
686 44 : }
687 :
688 0 : Bool SubMS::pickAntennas(Vector<Int>& selected_antennaids,
689 : Vector<String>& selected_antenna_strs,
690 : const Vector<Int>& antennaids,
691 : const Vector<String>& antennaSel)
692 : {
693 0 : Bool didSelect = true;
694 0 : if((antennaids.nelements() == 1) && (antennaids[0] == -1)){
695 0 : if(antennaSel[0] == "")
696 0 : didSelect = false;
697 : else
698 0 : selected_antennaids.resize();
699 : }
700 : else
701 0 : selected_antennaids = antennaids;
702 0 : selected_antenna_strs = antennaSel;
703 0 : return didSelect;
704 : }
705 :
706 44 : void SubMS::selectTime(Double timeBin, String timerng)
707 : {
708 44 : timeBin_p = timeBin;
709 44 : timeRange_p = timerng;
710 44 : }
711 :
712 44 : Bool SubMS::makeSubMS(String& msname, String& colname,
713 : const Vector<Int>& tileShape, const String& combine)
714 : {
715 88 : LogIO os(LogOrigin("SubMS", "makeSubMS()"));
716 :
717 : /*
718 : try{
719 : */
720 :
721 44 : if((spw_p.nelements()>0) && (max(spw_p) >= Int(ms_p.spectralWindow().nrow()))){
722 : os << LogIO::SEVERE
723 : << "SpectralWindow selection contains elements that do not exist in "
724 : << "this MS"
725 0 : << LogIO::POST;
726 0 : ms_p=MeasurementSet();
727 0 : return false;
728 : }
729 :
730 : // Watch out! This throws an AipsError if ms_p doesn't have the
731 : // requested columns.
732 44 : const Vector<MS::PredefinedColumns> colNamesTok = parseColumnNames(colname, ms_p);
733 :
734 44 : if(!makeSelection()){
735 : //os << LogIO::WARN
736 : // << "Failed on selection: the combination of spw, field, antenna, correlation, "
737 : // << "and timerange may be invalid."
738 : // << LogIO::POST;
739 0 : ms_p=MeasurementSet();
740 0 : return false;
741 : }
742 44 : mscIn_p=new MSColumns(mssel_p);
743 : // Note again the parseColumnNames() a few lines back that stops setupMS()
744 : // from being called if the MS doesn't have the requested columns.
745 44 : MeasurementSet* outpointer=0;
746 :
747 44 : if(tileShape.nelements() == 3){
748 0 : outpointer = setupMS(msname, nchan_p[0], ncorr_p[0],
749 : colNamesTok, tileShape);
750 : }
751 :
752 : // the following calls MSTileLayout... disabled for now because it
753 : // forces tiles to be the full spw bandwidth in width (gmoellen, 2010/11/07)
754 :
755 44 : else if((tileShape.nelements()==1) && (tileShape[0]==0 || tileShape[0]==1)){
756 44 : outpointer = setupMS(msname, nchan_p[0], ncorr_p[0],
757 88 : mscIn_p->observation().telescopeName()(0),
758 44 : colNamesTok, tileShape[0]);
759 : }
760 : /*
761 : else{
762 : // Derive tile shape based on input dataset's tiles, borrowed
763 : // from VisSet's scr col tile shape derivation
764 : // (this may need some tweaking for averaging cases)
765 : TableDesc td = mssel_p.actualTableDesc();
766 :
767 : // If a non-DATA column, i.e. CORRECTED_DATA, is being written to DATA,
768 : // datacolname must be set to DATA because the tile management in
769 : // setupMS() will look for "TiledDATA", not "TiledCorrectedData".
770 : String datacolname = MS::columnName(MS::DATA);
771 : // But if DATA is not present in the input MS, using it would cause a
772 : // segfault.
773 : if(!td.isColumn(datacolname))
774 : // This is could be any other kind of *DATA column, including
775 : // FLOAT_DATA or LAG_DATA, but it is guaranteed to be something.
776 : datacolname = MS::columnName(colNamesTok[0]);
777 :
778 : const ColumnDesc& cdesc = td[datacolname];
779 :
780 : String dataManType = cdesc.dataManagerType();
781 : String dataManGroup = cdesc.dataManagerGroup();
782 :
783 : Bool tiled = (dataManType.contains("Tiled"));
784 :
785 : if (tiled) {
786 : ROTiledStManAccessor tsm(mssel_p, dataManGroup);
787 : uInt nHyper = tsm.nhypercubes();
788 :
789 : // Test clause
790 : if(1){
791 : os << LogIO::DEBUG1
792 : << datacolname << "'s max cache size: "
793 : << tsm.maximumCacheSize() << " bytes.\n"
794 : << "\tnhypercubes: " << nHyper << ".\n"
795 : << "\ttshp of row 0: " << tsm.tileShape(0)
796 : << "\n\thypercube shape of row 0: " << tsm.hypercubeShape(0)
797 : << LogIO::POST;
798 : }
799 :
800 :
801 : // Find smallest tile shape
802 : Int highestProduct=-INT_MAX;
803 : Int highestId=0;
804 : for (uInt id=0; id < nHyper; id++) {
805 : IPosition tshp(tsm.getTileShape(id));
806 : Int product = tshp.product();
807 :
808 : os << LogIO::DEBUG2
809 : << "\thypercube " << id << ":\n"
810 : << "\t\ttshp: " << tshp << "\n"
811 : << "\t\thypercube shape: " << tsm.getHypercubeShape(id)
812 : << ".\n\t\tcache size: " << tsm.getCacheSize(id)
813 : << " buckets.\n\t\tBucket size: " << tsm.getBucketSize(id)
814 : << " bytes."
815 : << LogIO::POST;
816 :
817 : if (product > 0 && (product > highestProduct)) {
818 : highestProduct = product;
819 : highestId = id;
820 : }
821 : }
822 : Vector<Int> dataTileShape = tsm.getTileShape(highestId).asVector();
823 :
824 : outpointer = setupMS(msname, nchan_p[0], ncorr_p[0],
825 : colNamesTok, dataTileShape);
826 :
827 : }
828 : */
829 : else{
830 : //Sweep all other cases of bad tileshape to a default one.
831 : // (this probably never happens)
832 0 : outpointer = setupMS(msname, nchan_p[0], ncorr_p[0],
833 0 : mscIn_p->observation().telescopeName()(0),
834 : colNamesTok, 0);
835 :
836 : }
837 :
838 44 : combine_p = combine;
839 :
840 44 : msOut_p= *outpointer;
841 :
842 44 : if(!fillAllTables(colNamesTok)){
843 0 : delete outpointer;
844 0 : os << LogIO::WARN << msname << " left unfinished." << LogIO::POST;
845 0 : ms_p=MeasurementSet();
846 0 : return false;
847 : }
848 :
849 : // msOut_p.relinquishAutoLocks (true);
850 : // msOut_p.unlock();
851 : //Detaching the selected part
852 44 : ms_p=MeasurementSet();
853 :
854 44 : delete outpointer;
855 44 : return true;
856 :
857 : /*
858 : }
859 : catch(AipsError x){
860 : ms_p=MeasurementSet();
861 : throw(x);
862 : }
863 : catch(...){
864 : ms_p=MeasurementSet();
865 : throw(AipsError("Unknown exception caught"));
866 : }
867 : */
868 :
869 44 : }
870 :
871 0 : MeasurementSet* SubMS::makeScratchSubMS(const String& colname,
872 : const Bool forceInMemory)
873 : {
874 0 : return makeScratchSubMS(parseColumnNames(colname, ms_p), forceInMemory);
875 : }
876 :
877 0 : MeasurementSet* SubMS::makeScratchSubMS(const Vector<MS::PredefinedColumns>& whichDataCols,
878 : const Bool forceInMemory)
879 : {
880 0 : LogIO os(LogOrigin("SubMS", "makeScratchSubMS()"));
881 :
882 0 : if(max(fieldid_p) >= Int(ms_p.field().nrow())){
883 : os << LogIO::SEVERE
884 : << "Field selection contains elements that do not exist in "
885 : << "this MS"
886 0 : << LogIO::POST;
887 0 : ms_p=MeasurementSet();
888 0 : return 0;
889 : }
890 0 : if(max(spw_p) >= Int(ms_p.spectralWindow().nrow())){
891 : os << LogIO::SEVERE
892 : << "SpectralWindow selection contains elements that do not exist in "
893 : << "this MS"
894 0 : << LogIO::POST;
895 0 : ms_p=MeasurementSet();
896 0 : return 0;
897 : }
898 :
899 0 : if(!makeSelection()){
900 : os << LogIO::SEVERE
901 : << "Failed on selection: combination of spw and/or field and/or time "
902 : << "chosen may be invalid."
903 0 : << LogIO::POST;
904 0 : ms_p=MeasurementSet();
905 0 : return 0;
906 : }
907 0 : mscIn_p=new MSColumns(mssel_p);
908 0 : Double sizeInMB= 1.5 * n_bytes() / (1024.0 * 1024.0);
909 0 : String msname=AppInfo::workFileName(uInt(sizeInMB), "TempSubMS");
910 :
911 0 : MeasurementSet* outpointer=setupMS(msname, nchan_p[0], ncorr_p[0],
912 0 : mscIn_p->observation().telescopeName()(0),
913 : whichDataCols);
914 :
915 0 : outpointer->markForDelete();
916 : //Hmmmmmm....memory......
917 0 : if(sizeInMB < (Double)(HostInfo::memoryTotal(true))/(2048.0)
918 0 : || forceInMemory){
919 0 : MeasurementSet* a = outpointer;
920 0 : outpointer= new MeasurementSet(a->copyToMemoryTable("TmpMemoryMS"));
921 0 : outpointer->initRefs();
922 0 : delete a;
923 : }
924 :
925 0 : msOut_p = *outpointer;
926 :
927 0 : if(!fillAllTables(whichDataCols)){
928 0 : delete outpointer;
929 0 : outpointer = 0;
930 0 : ms_p = MeasurementSet();
931 0 : return 0;
932 : }
933 : //Detaching the selected part
934 0 : ms_p=MeasurementSet();
935 0 : return outpointer;
936 0 : }
937 :
938 :
939 44 : Bool SubMS::fillAllTables(const Vector<MS::PredefinedColumns>& datacols)
940 : {
941 :
942 88 : LogIO os(LogOrigin("SubMS", "fillAllTables()"));
943 44 : Bool success = true;
944 :
945 : // Copy the subtables before doing anything with the main table. Otherwise
946 : // MSColumns won't work.
947 :
948 : // fill or update
949 44 : Timer timer;
950 :
951 44 : timer.mark();
952 44 : success &= copyPointing();
953 : os << LogIO::DEBUG1
954 : << "copyPointing took " << timer.real() << "s."
955 44 : << LogIO::POST;
956 :
957 : // Optional columns should be set up before msc_p.
958 44 : addOptionalColumns(mssel_p.spectralWindow(), msOut_p.spectralWindow(), true);
959 :
960 : // Force the Measures frames for all the time type columns to have the same
961 : // reference as the TIME column of the main table.
962 : // Disable the empty table check (with false) because some of the subtables
963 : // (like POINTING) might already have been written.
964 : // However, empty tables are still empty after setting up the reference codes
965 : // here.
966 44 : msc_p = new MSColumns(msOut_p);
967 44 : msc_p->setEpochRef(MEpoch::castType(mscIn_p->timeMeas().getMeasRef().getType()),
968 : false);
969 :
970 : // UVW is the only other Measures column in the main table.
971 44 : msc_p->uvwMeas().setDescRefCode(Muvw::castType(mscIn_p->uvwMeas().getMeasRef().getType()));
972 :
973 44 : if(!mscIn_p->flagCategory().isNull() && mscIn_p->flagCategory().isDefined(0))
974 0 : msc_p->setFlagCategories(mscIn_p->flagCategories());
975 :
976 44 : timer.mark();
977 44 : if(!fillDDTables())
978 0 : return false;
979 : os << LogIO::DEBUG1
980 : << "fillDDTables took " << timer.real() << "s."
981 44 : << LogIO::POST;
982 :
983 : // SourceIDs need to be remapped around here. It could not be done in
984 : // selectSource() because mssel_p was not setup yet.
985 44 : timer.mark();
986 44 : relabelSources();
987 : os << LogIO::DEBUG1
988 : << "relabelSources took " << timer.real() << "s."
989 44 : << LogIO::POST;
990 :
991 44 : success &= fillFieldTable();
992 44 : success &= copySource();
993 :
994 44 : success &= copyAntenna();
995 44 : if(!copyFeed()) // Feed table writing has to be after antenna
996 0 : return false;
997 :
998 44 : success &= copyFlag_Cmd();
999 44 : success &= copyHistory();
1000 44 : success &= copyObservation();
1001 44 : success &= copyProcessor();
1002 44 : success &= copyState();
1003 :
1004 44 : timer.mark();
1005 44 : success &= copySyscal();
1006 : os << LogIO::DEBUG1
1007 : << "copySyscal took " << timer.real() << "s."
1008 44 : << LogIO::POST;
1009 :
1010 44 : timer.mark();
1011 44 : success &= copyWeather();
1012 : os << LogIO::DEBUG1
1013 : << "copyWeather took " << timer.real() << "s."
1014 44 : << LogIO::POST;
1015 :
1016 44 : timer.mark();
1017 44 : success &= filterOptSubtable("CALDEVICE");
1018 : os << LogIO::DEBUG1
1019 : << "CALDEVICE took " << timer.real() << "s."
1020 44 : << LogIO::POST;
1021 :
1022 44 : timer.mark();
1023 44 : success &= filterOptSubtable("SYSPOWER");
1024 : os << LogIO::DEBUG1
1025 : << "SYSPOWER took " << timer.real() << "s."
1026 44 : << LogIO::POST;
1027 :
1028 : // Run this after running the other copy*()s. Maybe there should be an
1029 : // option to *not* run it.
1030 44 : success &= copyGenericSubtables();
1031 :
1032 : //sameShape_p = areDataShapesConstant();
1033 :
1034 : // jagonzal: Allow main table to be left empty, so that it can be filled by another layer.
1035 44 : if (fillMainTable_p)
1036 : {
1037 44 : if(fitorder_p < 0 && timeBin_p <= 0.0)
1038 44 : success &= writeAllMainRows(datacols);
1039 : else
1040 0 : success &= writeSomeMainRows(datacols);
1041 44 : return success;
1042 : }
1043 : else
1044 : {
1045 0 : return success;
1046 : }
1047 44 : }
1048 :
1049 :
1050 44 : Bool SubMS::makeSelection(){
1051 :
1052 88 : LogIO os(LogOrigin("SubMS", "makeSelection()"));
1053 :
1054 : //VisSet/MSIter will check if the SORTED exists
1055 : //and resort if necessary
1056 : {
1057 : // Matrix<Int> noselection;
1058 : // VisSet vs(ms_p, noselection);
1059 44 : Block<Int> sort;
1060 44 : ROVisibilityIterator(ms_p, sort);
1061 44 : }
1062 :
1063 : const MeasurementSet *elms;
1064 44 : elms=&ms_p;
1065 44 : MeasurementSet sorted;
1066 44 : if (ms_p.keywordSet().isDefined("SORTED_TABLE")) {
1067 14 : sorted=ms_p.keywordSet().asTable("SORTED_TABLE");
1068 : //If ms is not writable and sort is a subselection...use original ms
1069 14 : if( ms_p.nrow() == sorted.nrow())
1070 14 : elms=&sorted;
1071 : }
1072 :
1073 44 : MSSelection thisSelection;
1074 44 : if(fieldid_p.nelements() > 0)
1075 44 : thisSelection.setFieldExpr(MSSelection::indexExprStr(fieldid_p));
1076 44 : if(spw_p.nelements() > 0)
1077 44 : thisSelection.setSpwExpr(MSSelection::indexExprStr(spw_p));
1078 44 : if(antennaSel_p){
1079 0 : if(antennaId_p.nelements() > 0){
1080 0 : thisSelection.setAntennaExpr(MSSelection::indexExprStr( antennaId_p ));
1081 : }
1082 0 : if(antennaSelStr_p[0] != "")
1083 0 : thisSelection.setAntennaExpr(MSSelection::nameExprStr( antennaSelStr_p));
1084 : }
1085 44 : if(timeRange_p != "")
1086 0 : thisSelection.setTimeExpr(timeRange_p);
1087 :
1088 44 : thisSelection.setUvDistExpr(uvrangeString_p);
1089 44 : thisSelection.setScanExpr(scanString_p);
1090 44 : thisSelection.setStateExpr(intentString_p);
1091 44 : thisSelection.setObservationExpr(obsString_p);
1092 44 : if(arrayExpr_p != "")
1093 0 : thisSelection.setArrayExpr(arrayExpr_p);
1094 44 : if(corrString_p != "")
1095 0 : thisSelection.setPolnExpr(corrString_p);
1096 44 : thisSelection.setTaQLExpr(taqlString_p);
1097 :
1098 44 : TableExprNode exprNode=thisSelection.toTableExprNode(elms);
1099 44 : selTimeRanges_p = thisSelection.getTimeList();
1100 44 : selObsId_p = thisSelection.getObservationList();
1101 :
1102 : {
1103 44 : const MSDataDescription ddtable = elms->dataDescription();
1104 : ScalarColumn<Int> polId(ddtable,
1105 44 : MSDataDescription::columnName(MSDataDescription::POLARIZATION_ID));
1106 44 : const MSPolarization poltable = elms->polarization();
1107 : ArrayColumn<Int> pols(poltable,
1108 44 : MSPolarization::columnName(MSPolarization::CORR_TYPE));
1109 :
1110 : ScalarColumn<Int> spwId(ddtable,
1111 44 : MSDataDescription::columnName(MSDataDescription::SPECTRAL_WINDOW_ID));
1112 :
1113 44 : uInt nddids = polId.nrow();
1114 44 : uInt nSpws = spw_p.nelements();
1115 :
1116 : // # of distinct channel ranges or pol setups (!#pols) per spw.
1117 44 : Vector<uInt> nuses_per_spw;
1118 :
1119 44 : Int highestSpw = max(spw_p);
1120 44 : if(highestSpw < 0)
1121 0 : highestSpw = 0;
1122 44 : spw2ddid_p.resize(highestSpw + 1);
1123 44 : nuses_per_spw.resize(highestSpw + 1);
1124 44 : spw2ddid_p.set(0); // This is a row #, so must be >= 0.
1125 44 : nuses_per_spw.set(0);
1126 44 : Bool ddidprob = false;
1127 443 : for(uInt j = 0; j < nddids; ++j){
1128 399 : Int spw = spwId(j);
1129 2497 : for(uInt k = 0; k < nSpws; ++k){
1130 2098 : if(spw == spw_p[k]){
1131 127 : ++nuses_per_spw[spw];
1132 127 : if(nuses_per_spw[spw_p[k]] == 2){
1133 0 : ddidprob = true;
1134 : os << LogIO::SEVERE
1135 0 : << "Input spw " << spw_p[k] << " was selected for > 1 "
1136 0 : << "channel ranges or polarization setups." << LogIO::POST;
1137 : }
1138 127 : spw2ddid_p[spw] = j;
1139 : }
1140 : }
1141 : }
1142 :
1143 44 : if(ddidprob){
1144 : os << LogIO::SEVERE
1145 : << "split does not yet support more than 1 channel range (';' in spw)"
1146 : << "\nor polarization setup per spectral window."
1147 0 : << LogIO::POST;
1148 0 : return false;
1149 : }
1150 :
1151 44 : Vector<Int> ddids;
1152 44 : ddids.resize(nSpws);
1153 :
1154 44 : inNumCorr_p.resize(nSpws);
1155 44 : ncorr_p.resize(nSpws);
1156 171 : for(uInt k = 0; k < nSpws; ++k){
1157 127 : Int ddid = spw2ddid_p[spw_p[k]];
1158 :
1159 127 : inNumCorr_p[k] = pols(polId(ddid)).nelements();
1160 127 : ncorr_p[k] = inPolOutCorrToInCorrMap_p[polId(ddid)].nelements();
1161 127 : if(ncorr_p[k] == 0){
1162 : os << LogIO::SEVERE
1163 : << "None of the selected correlations are in spectral window "
1164 0 : << spw_p[k]
1165 0 : << LogIO::POST;
1166 0 : return false;
1167 : }
1168 : }
1169 44 : }
1170 :
1171 : // Now remake the selected ms
1172 44 : if(!(exprNode.isNull())){
1173 44 : mssel_p = MeasurementSet((*elms)(exprNode));
1174 : }
1175 : else{
1176 : // Null take all the ms ...setdata() blank means that
1177 0 : mssel_p = MeasurementSet((*elms));
1178 : }
1179 : //mssel_p.rename(ms_p.tableName()+"/SELECTED_TABLE", Table::Scratch);
1180 44 : if(mssel_p.nrow() == 0)
1181 0 : return false;
1182 :
1183 : // Setup antNewIndex_p now that mssel_p is ready.
1184 44 : if(antennaSel_p){
1185 : // Watch out! getAntenna*List() and getBaselineList() return negative
1186 : // numbers for negated antennas!
1187 : //Vector<Int> selAnt1s(thisSelection.getAntenna1List());
1188 : //Vector<Int> selAnt2s(thisSelection.getAntenna2List());
1189 0 : ScalarColumn<Int> ant1c(mssel_p, MS::columnName(MS::ANTENNA1));
1190 0 : ScalarColumn<Int> ant2c(mssel_p, MS::columnName(MS::ANTENNA2));
1191 0 : Vector<Int> selAnts(ant1c.getColumn());
1192 0 : uInt nAnts = selAnts.nelements();
1193 :
1194 0 : selAnts.resize(2 * nAnts, true);
1195 0 : selAnts(Slice(nAnts, nAnts)) = ant2c.getColumn();
1196 0 : nAnts = GenSort<Int>::sort(selAnts, Sort::Ascending, Sort::NoDuplicates);
1197 0 : selAnts.resize(nAnts, true);
1198 0 : Int maxAnt = max(selAnts);
1199 :
1200 0 : if(maxAnt < 0){
1201 : os << LogIO::SEVERE
1202 : << "The maximum selected antenna number, " << maxAnt
1203 : << ", seems to be < 0."
1204 0 : << LogIO::POST;
1205 0 : return false;
1206 : }
1207 0 : antNewIndex_p.resize(maxAnt + 1);
1208 0 : antNewIndex_p.set(-1); //So if you see -1 in the main, feed, or pointing
1209 : //tables, fix it
1210 0 : Bool trivial = true;
1211 0 : for(uInt k = 0; k < nAnts; ++k){
1212 0 : trivial &= (selAnts[k] == static_cast<Int>(k)); // trivial = selAnts == indgen(nAnts)
1213 0 : antNewIndex_p[selAnts[k]] = k;
1214 : } // It is possible to exclude baselines
1215 0 : antennaSel_p = !trivial; // without excluding any antennas.
1216 0 : } // This still gets tripped up by VLA:OUT.
1217 : else{ // Make a default antNewIndex_p.
1218 44 : antNewIndex_p.resize(mssel_p.antenna().nrow());
1219 44 : indgen(antNewIndex_p);
1220 : }
1221 :
1222 44 : if(mssel_p.nrow() < ms_p.nrow()){
1223 : os << LogIO::NORMAL
1224 : << mssel_p.nrow() << " out of " << ms_p.nrow() << " rows are going to be"
1225 : << " considered due to the selection criteria."
1226 34 : << LogIO::POST;
1227 : }
1228 44 : return true;
1229 44 : }
1230 :
1231 122 : MeasurementSet* SubMS::setupMS(const String& MSFileName, const Int nchan,
1232 : const Int nCorr, const String& telescop,
1233 : const Vector<MS::PredefinedColumns>& colNames,
1234 : const Int obstype,
1235 : const Bool compress,
1236 : const asdmStManUseAlternatives asdmStManUse)
1237 : {
1238 : //Choose an appropriate tileshape
1239 122 : IPosition dataShape(2, nCorr, nchan);
1240 122 : IPosition tileShape = MSTileLayout::tileShape(dataShape, obstype, telescop);
1241 244 : return setupMS(MSFileName, nchan, nCorr, colNames, tileShape.asVector(),
1242 244 : compress, asdmStManUse);
1243 : //return setupMS(MSFileName, nchan, nCorr, colNames, tileShape.asVector());
1244 122 : }
1245 122 : MeasurementSet* SubMS::setupMS(const String& MSFileName, const Int nchan,
1246 : const Int nCorr,
1247 : const Vector<MS::PredefinedColumns>& colNamesTok,
1248 : const Vector<Int>& tshape, const Bool compress,
1249 : const asdmStManUseAlternatives asdmStManUse)
1250 : {
1251 122 : if(tshape.nelements() != 3)
1252 0 : throw(AipsError("TileShape has to have 3 elements ") );
1253 :
1254 : // This is more to shush a compiler warning than to warn users.
1255 244 : LogIO os(LogOrigin("SubMS", "setupMS()"));
1256 122 : if(tshape[0] != nCorr)
1257 : os << LogIO::DEBUG1
1258 0 : << "Warning: using " << tshape[0] << " from the tileshape instead of "
1259 : << nCorr << " for the number of correlations."
1260 0 : << LogIO::POST;
1261 122 : if(tshape[1] != nchan)
1262 : os << LogIO::DEBUG1
1263 92 : << "Warning: using " << tshape[1] << " from the tileshape instead of "
1264 : << nchan << " for the number of channels."
1265 46 : << LogIO::POST;
1266 :
1267 : // Choose an appropriate tileshape
1268 : //IPosition dataShape(2,nCorr,nchan);
1269 : //IPosition tileShape = MSTileLayout::tileShape(dataShape,obsType, telescop);
1270 : //////////////////
1271 :
1272 122 : IPosition tileShape(tshape);
1273 :
1274 : // Make the MS table
1275 122 : TableDesc td = MS::requiredTableDesc();
1276 122 : Vector<String> tiledDataNames;
1277 :
1278 : // Even though we know the data is going to be the same shape throughout I'll
1279 : // still create a column that has a variable shape as this will permit MS's
1280 : // with other shapes to be appended.
1281 122 : uInt ncols = colNamesTok.nelements();
1282 122 : const Bool mustWriteOnlyToData = mustConvertToData(ncols, colNamesTok);
1283 122 : Bool hasFloatData = False;
1284 :
1285 122 : if (mustWriteOnlyToData)
1286 : {
1287 95 : MS::addColumnToDesc(td, MS::DATA, 2);
1288 95 : if(asdmStManUse==DONT){
1289 68 : if (compress) MS::addColumnCompression(td,MS::DATA,true);
1290 136 : String hcolName=String("Tiled")+String("DATA");
1291 68 : td.defineHypercolumn(hcolName, 3,
1292 136 : stringToVector("DATA"));
1293 68 : tiledDataNames.resize(1);
1294 68 : tiledDataNames[0] = hcolName;
1295 68 : }
1296 : }
1297 : else{
1298 27 : tiledDataNames.resize(ncols);
1299 75 : for(uInt i = 0; i < ncols; ++i){
1300 : // only add data-like columns here
1301 : // Unfortunately MS::PredefinedColumns aren't ordered so that I can just check if
1302 : // colNamesTok[i] is in the "data range".
1303 48 : if(colNamesTok[i] == MS::DATA ||
1304 37 : colNamesTok[i] == MS::MODEL_DATA ||
1305 27 : colNamesTok[i] == MS::CORRECTED_DATA ||
1306 85 : colNamesTok[i] == MS::FLOAT_DATA ||
1307 0 : colNamesTok[i] == MS::LAG_DATA) {
1308 48 : MS::addColumnToDesc(td, colNamesTok[i], 2);
1309 : // compress them unless they are DATA or FLOAT_DATA and the AsdmStMan is in use
1310 52 : if(asdmStManUse==DONT ||
1311 4 : (colNamesTok[i] != MS::DATA && colNamesTok[i] != MS::FLOAT_DATA)){
1312 44 : if (compress) MS::addColumnCompression(td,colNamesTok[i],true);
1313 : }
1314 48 : if (colNamesTok[i] == MS::FLOAT_DATA) {
1315 : // make a note that FLOAT_DATA is being used, for later.
1316 16 : hasFloatData = True;
1317 : }
1318 : }
1319 : else {
1320 0 : throw(AipsError(MS::columnName(colNamesTok[i]) +
1321 0 : " is not a recognized data column "));
1322 : }
1323 : // Add tiled versions for these columns except for DATA and FLOAT_DATA when AsdmStMan is in use.
1324 52 : if(asdmStManUse==DONT ||
1325 4 : (colNamesTok[i] != MS::DATA && colNamesTok[i] != MS::FLOAT_DATA)){
1326 44 : String hcolName = String("Tiled") + MS::columnName(colNamesTok[i]);
1327 44 : td.defineHypercolumn(hcolName, 3,
1328 88 : stringToVector(MS::columnName(colNamesTok[i])));
1329 44 : tiledDataNames[i] = hcolName;
1330 44 : }
1331 : }
1332 : }
1333 :
1334 : //other cols for compression
1335 122 : if (compress && asdmStManUse!=USE_FOR_DATA_WEIGHT_SIGMA_FLAG) {
1336 0 : MS::addColumnCompression(td, MS::WEIGHT, true);
1337 0 : MS::addColumnCompression(td, MS::SIGMA, true);
1338 : }
1339 :
1340 : // add this optional column because random group fits has a
1341 : // weight per visibility
1342 122 : MS::addColumnToDesc(td, MS::WEIGHT_SPECTRUM, 2);
1343 :
1344 : // if(asdmStManUse==DONT){
1345 : // td.defineHypercolumn("TiledDATA",3,
1346 : // stringToVector(MS::columnName(MS::DATA)));
1347 : // }
1348 122 : td.defineHypercolumn("TiledFlagCategory",4,
1349 244 : stringToVector(MS::columnName(MS::FLAG_CATEGORY)));
1350 122 : td.defineHypercolumn("TiledWgtSpectrum",3,
1351 244 : stringToVector(MS::columnName(MS::WEIGHT_SPECTRUM)));
1352 122 : td.defineHypercolumn("TiledUVW",2,
1353 244 : stringToVector(MS::columnName(MS::UVW)));
1354 122 : if(asdmStManUse!=USE_FOR_DATA_WEIGHT_SIGMA_FLAG){
1355 122 : td.defineHypercolumn("TiledFlag",3,
1356 244 : stringToVector(MS::columnName(MS::FLAG)));
1357 122 : td.defineHypercolumn("TiledWgt",2,
1358 244 : stringToVector(MS::columnName(MS::WEIGHT)));
1359 122 : td.defineHypercolumn("TiledSigma", 2,
1360 244 : stringToVector(MS::columnName(MS::SIGMA)));
1361 : }
1362 :
1363 122 : SetupNewTable newtab(MSFileName, td, Table::New);
1364 :
1365 122 : uInt cache_val=32768;
1366 : // Set the default Storage Manager to be the Incr one
1367 122 : IncrementalStMan incrStMan ("ISMData",cache_val);
1368 122 : newtab.bindAll(incrStMan, true);
1369 : //Override the binding for specific columns
1370 :
1371 122 : IncrementalStMan incrStMan0("Array_ID",cache_val);
1372 122 : newtab.bindColumn(MS::columnName(MS::ARRAY_ID), incrStMan0);
1373 122 : IncrementalStMan incrStMan1("EXPOSURE",cache_val);
1374 122 : newtab.bindColumn(MS::columnName(MS::EXPOSURE), incrStMan1);
1375 122 : IncrementalStMan incrStMan2("FEED1",cache_val);
1376 122 : newtab.bindColumn(MS::columnName(MS::FEED1), incrStMan2);
1377 122 : IncrementalStMan incrStMan3("FEED2",cache_val);
1378 122 : newtab.bindColumn(MS::columnName(MS::FEED2), incrStMan3);
1379 122 : IncrementalStMan incrStMan4("FIELD_ID",cache_val);
1380 122 : newtab.bindColumn(MS::columnName(MS::FIELD_ID), incrStMan4);
1381 :
1382 : // jagonzal (CAS-6746): Don't use IncrementalStMan with RW cols ///////////////////////////////////////////////////
1383 : //IncrementalStMan incrStMan5("FLAG_ROW",cache_val/4);
1384 : //newtab.bindColumn(MS::columnName(MS::FLAG_ROW), incrStMan5);
1385 122 : StandardStMan aipsStManFlagRow("FLAG_ROW", cache_val/4);
1386 122 : newtab.bindColumn(MS::columnName(MS::FLAG_ROW), aipsStManFlagRow);
1387 : ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1388 :
1389 122 : IncrementalStMan incrStMan6("INTERVAL",cache_val);
1390 122 : newtab.bindColumn(MS::columnName(MS::INTERVAL), incrStMan6);
1391 122 : IncrementalStMan incrStMan7("OBSERVATION_ID",cache_val);
1392 122 : newtab.bindColumn(MS::columnName(MS::OBSERVATION_ID), incrStMan7);
1393 122 : IncrementalStMan incrStMan8("PROCESSOR_ID",cache_val);
1394 122 : newtab.bindColumn(MS::columnName(MS::PROCESSOR_ID), incrStMan8);
1395 122 : IncrementalStMan incrStMan9("SCAN_NUMBER",cache_val);
1396 122 : newtab.bindColumn(MS::columnName(MS::SCAN_NUMBER), incrStMan9);
1397 122 : IncrementalStMan incrStMan10("STATE_ID",cache_val);
1398 122 : newtab.bindColumn(MS::columnName(MS::STATE_ID), incrStMan10);
1399 122 : IncrementalStMan incrStMan11("TIME",cache_val);
1400 122 : newtab.bindColumn(MS::columnName(MS::TIME), incrStMan11);
1401 122 : IncrementalStMan incrStMan12("TIME_CENTROID",cache_val);
1402 122 : newtab.bindColumn(MS::columnName(MS::TIME_CENTROID), incrStMan12);
1403 :
1404 : // Bind ANTENNA1, ANTENNA2 and DATA_DESC_ID to the standardStMan
1405 : // as they may change sufficiently frequently to make the
1406 : // incremental storage manager inefficient for these columns.
1407 :
1408 :
1409 122 : StandardStMan aipsStMan0("ANTENNA1", cache_val);
1410 122 : newtab.bindColumn(MS::columnName(MS::ANTENNA1), aipsStMan0);
1411 122 : StandardStMan aipsStMan1("ANTENNA2", cache_val);
1412 122 : newtab.bindColumn(MS::columnName(MS::ANTENNA2), aipsStMan1);
1413 122 : StandardStMan aipsStMan2("DATA_DESC_ID", cache_val);
1414 122 : newtab.bindColumn(MS::columnName(MS::DATA_DESC_ID), aipsStMan2);
1415 :
1416 :
1417 : // itsLog << LogOrigin("MSFitsInput", "setupMeasurementSet");
1418 : //itsLog << LogIO::NORMAL << "Using tile shape "<<tileShape <<" for "<<
1419 : // array_p<<" with obstype="<< obsType<<LogIO::POST;
1420 :
1421 : // TiledShapeStMan tiledStMan1("TiledData",tileShape);
1422 122 : TiledShapeStMan tiledStMan1f("TiledFlag",tileShape);
1423 : TiledShapeStMan tiledStMan1fc("TiledFlagCategory",
1424 122 : IPosition(4,tileShape(0),tileShape(1),1,
1425 366 : tileShape(2)));
1426 122 : TiledShapeStMan tiledStMan2("TiledWgtSpectrum",tileShape);
1427 244 : TiledColumnStMan tiledStMan3("TiledUVW",IPosition(2, 3, (tileShape(0) * tileShape(1) * tileShape(2)) / 3));
1428 : TiledShapeStMan tiledStMan4("TiledWgt",
1429 244 : IPosition(2,tileShape(0), tileShape(1) * tileShape(2)));
1430 : TiledShapeStMan tiledStMan5("TiledSigma",
1431 244 : IPosition(2,tileShape(0), tileShape(1) * tileShape(2)));
1432 :
1433 : // Bind the DATA or FLOAT_DATA, FLAG & WEIGHT_SPECTRUM columns to the tiled stman or asdmStMan
1434 :
1435 122 : AsdmStMan sm;
1436 :
1437 122 : if (mustWriteOnlyToData){
1438 95 : if(asdmStManUse==DONT){
1439 68 : TiledShapeStMan tiledStMan1Data("TiledDATA",tileShape);
1440 :
1441 68 : newtab.bindColumn(MS::columnName(MS::DATA), tiledStMan1Data);
1442 68 : }
1443 : else{
1444 27 : if (hasFloatData) {
1445 0 : newtab.bindColumn(MS::columnName(MS::FLOAT_DATA), sm);
1446 : } else{
1447 27 : newtab.bindColumn(MS::columnName(MS::DATA), sm);
1448 : }
1449 : }
1450 : }
1451 : else{
1452 75 : for(uInt i = 0; i < ncols; ++i){
1453 48 : TiledShapeStMan tiledStMan1Data(tiledDataNames[i], tileShape);
1454 :
1455 48 : newtab.bindColumn(MS::columnName(colNamesTok[i]), tiledStMan1Data);
1456 48 : }
1457 27 : if(asdmStManUse!=DONT){
1458 4 : if (hasFloatData) {
1459 4 : newtab.bindColumn(MS::columnName(MS::FLOAT_DATA), sm);
1460 : } else {
1461 0 : newtab.bindColumn(MS::columnName(MS::DATA), sm);
1462 : }
1463 : }
1464 : }
1465 122 : newtab.bindColumn(MS::columnName(MS::FLAG_CATEGORY),tiledStMan1fc);
1466 122 : newtab.bindColumn(MS::columnName(MS::WEIGHT_SPECTRUM),tiledStMan2);
1467 :
1468 122 : newtab.bindColumn(MS::columnName(MS::UVW),tiledStMan3);
1469 122 : if(asdmStManUse==USE_FOR_DATA_WEIGHT_SIGMA_FLAG){
1470 0 : newtab.bindColumn(MS::columnName(MS::FLAG),sm);
1471 0 : newtab.bindColumn(MS::columnName(MS::WEIGHT),sm);
1472 0 : newtab.bindColumn(MS::columnName(MS::SIGMA),sm);
1473 : }
1474 : else{
1475 122 : newtab.bindColumn(MS::columnName(MS::FLAG),tiledStMan1f);
1476 122 : newtab.bindColumn(MS::columnName(MS::WEIGHT),tiledStMan4);
1477 122 : newtab.bindColumn(MS::columnName(MS::SIGMA),tiledStMan5);
1478 : }
1479 :
1480 :
1481 : // avoid lock overheads by locking the table permanently
1482 122 : TableLock lock(TableLock::AutoLocking);
1483 122 : MeasurementSet *ms = new MeasurementSet (newtab,lock);
1484 :
1485 : // Set up the subtables for the UVFITS MS
1486 : // we make new tables with 0 rows
1487 122 : Table::TableOption option=Table::New;
1488 122 : createSubtables(*ms, option);
1489 :
1490 : { // Set the TableInfo
1491 122 : TableInfo& info(ms->tableInfo());
1492 122 : info.setType(TableInfo::type(TableInfo::MEASUREMENTSET));
1493 122 : info.setSubType(String("UVFITS"));
1494 : info.readmeAddLine
1495 122 : ("This is a measurement set Table holding astronomical observations");
1496 : }
1497 122 : return ms;
1498 122 : }
1499 :
1500 :
1501 44 : Bool SubMS::fillDDTables()
1502 : {
1503 88 : LogIO os(LogOrigin("SubMS", "fillDDTables()"));
1504 :
1505 44 : MSSpWindowColumns inSpWCols(mssel_p.spectralWindow());
1506 44 : MSSpWindowColumns& msSpW(msc_p->spectralWindow());
1507 : // Detect which optional columns of SPECTRAL_WINDOW are present.
1508 : // inSpWCols and msSpW should agree because addOptionalColumns() was done
1509 : // for SPECTRAL_WINDOW in fillAllTables() before making msc_p or calling
1510 : // fillDDTables.
1511 44 : Bool haveSpwAN = inSpWCols.assocNature().hasContent();
1512 44 : Bool haveSpwASI = inSpWCols.assocSpwId().hasContent();
1513 44 : Bool haveSpwBN = inSpWCols.bbcNo().hasContent();
1514 44 : Bool haveSpwBS = inSpWCols.bbcSideband().hasContent();
1515 44 : Bool haveSpwDI = inSpWCols.dopplerId().hasContent();
1516 :
1517 44 : MSDataDescColumns& msDD(msc_p->dataDescription());
1518 44 : MSPolarizationColumns& msPol(msc_p->polarization());
1519 :
1520 : //DD table
1521 44 : const MSDataDescription ddtable = mssel_p.dataDescription();
1522 : ScalarColumn<Int> polId(ddtable,
1523 44 : MSDataDescription::columnName(MSDataDescription::POLARIZATION_ID));
1524 :
1525 : //Fill in matching spw to datadesc in old ms
1526 : {
1527 44 : MSDataDescColumns msOldDD(ddtable);
1528 44 : oldDDSpwMatch_p=msOldDD.spectralWindowId().getColumn();
1529 44 : }
1530 :
1531 : //POLARIZATION table
1532 44 : const MSPolarization poltable= mssel_p.polarization();
1533 : ScalarColumn<Int> numCorr (poltable,
1534 44 : MSPolarization::columnName(MSPolarization::NUM_CORR));
1535 : ArrayColumn<Int> corrType(poltable,
1536 44 : MSPolarization::columnName(MSPolarization::CORR_TYPE));
1537 44 : ArrayColumn<Int> corrProd(poltable, MSPolarization::columnName(MSPolarization::CORR_PRODUCT));
1538 44 : ScalarColumn<Bool> polFlagRow(poltable, MSPolarization::columnName(MSPolarization::FLAG_ROW));
1539 :
1540 44 : spwRelabel_p.resize(mscIn_p->spectralWindow().nrow());
1541 44 : spwRelabel_p.set(-1);
1542 :
1543 44 : inNumChan_p.resize(spw_p.nelements());
1544 :
1545 44 : polID_p = polId.getColumn();
1546 : Bool dum;
1547 44 : Sort sort( polID_p.getStorage(dum),sizeof(Int) );
1548 44 : sort.sortKey((uInt)0,TpInt);
1549 44 : Vector<uInt> index,uniq;
1550 44 : sort.sort(index,polID_p.nelements());
1551 44 : uInt nPol = sort.unique(uniq,index);
1552 44 : Vector<Int> selectedPolId(nPol); // Map from output polID to input polID.
1553 89 : for(uInt k = 0; k < nPol; ++k)
1554 45 : selectedPolId[k] = polID_p[index[uniq[k]]];
1555 :
1556 : // Make map from input to output spws.
1557 44 : Sort sortSpws(spw_p.getStorage(dum), sizeof(Int));
1558 44 : sortSpws.sortKey((uInt)0, TpInt);
1559 44 : Vector<uInt> spwsortindex, spwuniqinds;
1560 44 : sortSpws.sort(spwsortindex, spw_p.nelements());
1561 44 : uInt nuniqSpws = sortSpws.unique(spwuniqinds, spwsortindex);
1562 44 : spw_uniq_p.resize(nuniqSpws);
1563 171 : for(uInt k = 0; k < nuniqSpws; ++k){
1564 127 : spw_uniq_p[k] = spw_p[spwuniqinds[k]];
1565 127 : spwRelabel_p[spw_uniq_p[k]] = k;
1566 : }
1567 44 : if(nuniqSpws < spw_p.nelements()){
1568 : os << LogIO::WARN
1569 : << "Multiple channel ranges within an spw may not work. SOME DATA MAY BE OMITTED!"
1570 : << "\nConsider splitting them individually and optionally combining the output MSes with concat."
1571 : << "\nEven then, expect problems if exporting to uvfits."
1572 0 : << LogIO::POST;
1573 : }
1574 :
1575 44 : Vector<Int> newPolId(nuniqSpws);
1576 171 : for(uInt k = 0; k < nuniqSpws; ++k){
1577 127 : Bool found = false;
1578 :
1579 127 : for(uInt j = 0; j < nPol; ++j){
1580 127 : if(selectedPolId[j] == polID_p[spw2ddid_p[spw_uniq_p[k]]]){
1581 127 : newPolId[k] = j;
1582 127 : found = true;
1583 127 : break;
1584 : }
1585 : }
1586 127 : if(!found){
1587 : os << LogIO::SEVERE
1588 : << "No polarization ID found for output polarization setup " << k
1589 0 : << LogIO::POST;
1590 0 : return false;
1591 : }
1592 : }
1593 44 : corrSlice_p.resize(nPol);
1594 89 : for(uInt outpid = 0; outpid < nPol; ++outpid){
1595 45 : uInt inpid = selectedPolId[outpid];
1596 45 : uInt ncorr = inPolOutCorrToInCorrMap_p[inpid].nelements();
1597 45 : const Vector<Int> inCT(corrType(inpid));
1598 :
1599 : // ncorr will be 0 if none of the selected spws have this pid.
1600 45 : if(ncorr > 0 && ncorr < inCT.nelements()){
1601 0 : keepShape_p = false;
1602 :
1603 : // Check whether the requested correlations can be accessed by slicing.
1604 : // That means there must be a constant stride. The most likely (only?)
1605 : // way to violate that is to ask for 3 out of 4 correlations.
1606 0 : if(ncorr > 2){
1607 : os << LogIO::SEVERE
1608 : << "Sorry, the requested correlation selection is not unsupported.\n"
1609 : << "Try selecting fewer or all of the correlations."
1610 0 : << LogIO::POST;
1611 0 : return false;
1612 : }
1613 :
1614 0 : corrSlice_p[outpid] = Slice(inPolOutCorrToInCorrMap_p[inpid][0],
1615 : ncorr,
1616 0 : ncorr > 1 ? inPolOutCorrToInCorrMap_p[inpid][1] -
1617 0 : inPolOutCorrToInCorrMap_p[inpid][0] :
1618 : 1);
1619 : }
1620 : else
1621 45 : corrSlice_p[outpid] = Slice(0, ncorr);
1622 :
1623 45 : msOut_p.polarization().addRow();
1624 45 : msPol.numCorr().put(outpid, ncorr);
1625 45 : msPol.flagRow().put(outpid, polFlagRow(inpid));
1626 :
1627 45 : Vector<Int> outCT;
1628 45 : const Matrix<Int> inCP(corrProd(inpid));
1629 45 : Matrix<Int> outCP;
1630 45 : outCT.resize(ncorr);
1631 45 : outCP.resize(2, ncorr);
1632 134 : for(uInt k = 0; k < ncorr; ++k){
1633 89 : Int inCorrInd = inPolOutCorrToInCorrMap_p[inpid][k];
1634 :
1635 89 : outCT[k] = inCT[inCorrInd];
1636 267 : for(uInt feedind = 0; feedind < 2; ++feedind)
1637 178 : outCP(feedind, k) = inCP(feedind, inCorrInd);
1638 : }
1639 45 : msPol.corrType().put(outpid, outCT);
1640 45 : msPol.corrProduct().put(outpid, outCP);
1641 45 : }
1642 :
1643 171 : for(uInt k = 0; k < spw_p.nelements(); ++k)
1644 127 : inNumChan_p[k] = inSpWCols.numChan()(spw_p[k]);
1645 :
1646 44 : Vector<Vector<Int> > spwinds_of_uniq_spws(nuniqSpws);
1647 :
1648 44 : totnchan_p.resize(nuniqSpws);
1649 171 : for(uInt k = 0; k < nuniqSpws; ++k){
1650 127 : Int maxchan = 0;
1651 127 : uInt j = 0;
1652 :
1653 127 : msOut_p.spectralWindow().addRow();
1654 127 : msOut_p.dataDescription().addRow();
1655 :
1656 127 : totnchan_p[k] = 0;
1657 127 : spwinds_of_uniq_spws[k].resize();
1658 1382 : for(uInt spwind = 0; spwind < spw_p.nelements(); ++spwind){
1659 1255 : if(spw_p[spwind] == spw_uniq_p[k]){
1660 127 : Int highchan = nchan_p[spwind] * chanStep_p[spwind]
1661 127 : + chanStart_p[spwind];
1662 :
1663 127 : if(highchan > maxchan)
1664 127 : maxchan = highchan;
1665 :
1666 127 : totnchan_p[k] += nchan_p[spwind];
1667 :
1668 : // The true is necessary to avoid scrambling previously assigned
1669 : // values.
1670 127 : spwinds_of_uniq_spws[k].resize(j + 1, true);
1671 :
1672 : // Warning! spwinds_of_uniq_spws[k][j] will compile without warning,
1673 : // but dump core at runtime.
1674 127 : (spwinds_of_uniq_spws[k])[j] = spwind;
1675 127 : ++j;
1676 : }
1677 : }
1678 127 : if(maxchan > inSpWCols.numChan()(spw_uniq_p[k])){
1679 : os << LogIO::SEVERE
1680 : << " Channel settings wrong; exceeding number of channels in spw "
1681 0 : << spw_uniq_p[k] << LogIO::POST;
1682 0 : return false;
1683 : }
1684 : }
1685 :
1686 : // min_k is an index for getting an spw index via spw_uniq_p[min_k].
1687 : // k is an index for getting an spw index via spw_p[k].
1688 171 : for(uInt min_k = 0; min_k < nuniqSpws; ++min_k){
1689 127 : uInt k = spwinds_of_uniq_spws[min_k][0];
1690 :
1691 254 : if(spwinds_of_uniq_spws[min_k].nelements() > 1 ||
1692 127 : nchan_p[k] != inSpWCols.numChan()(spw_p[k])){
1693 6 : Vector<Double> effBWIn = inSpWCols.effectiveBW()(spw_uniq_p[min_k]);
1694 6 : Int nOutChan = totnchan_p[min_k];
1695 6 : Vector<Double> chanFreqOut(nOutChan);
1696 6 : Vector<Double> chanFreqIn = inSpWCols.chanFreq()(spw_uniq_p[min_k]);
1697 6 : Vector<Double> chanWidthOut(nOutChan);
1698 6 : Vector<Double> chanWidthIn = inSpWCols.chanWidth()(spw_uniq_p[min_k]);
1699 6 : Vector<Double> spwResolOut(nOutChan);
1700 6 : Vector<Double> spwResolIn = inSpWCols.resolution()(spw_uniq_p[min_k]);
1701 6 : Vector<Double> effBWOut(nOutChan);
1702 6 : Int outChan = 0;
1703 :
1704 6 : keepShape_p = false;
1705 :
1706 : // The sign of CHAN_WIDTH defaults to +. Its determination assumes
1707 : // that chanFreqIn is monotonic, but not that the sign of the
1708 : // chanWidthIn is correct.
1709 6 : Bool neginc = chanFreqIn[chanFreqIn.nelements() - 1] < chanFreqIn[0];
1710 :
1711 6 : effBWOut.set(0.0);
1712 6 : Double totalBW = 0.0;
1713 12 : for(uInt rangeNum = 0;
1714 12 : rangeNum < spwinds_of_uniq_spws[min_k].nelements(); ++rangeNum){
1715 6 : k = spwinds_of_uniq_spws[min_k][rangeNum];
1716 :
1717 6 : Int span = chanStep_p[k] * widths_p[k];
1718 :
1719 30 : for(Int j = 0; j < nchan_p[k]; ++j){
1720 24 : Int inpChan = chanStart_p[k] + j * span;
1721 :
1722 24 : if(span > 1){
1723 0 : Int lastChan = inpChan + span - 1;
1724 :
1725 0 : if(lastChan > chanEnd_p[k]){
1726 : // The averaging width is not a factor of the number of
1727 : // selected input channels, so the last output bin receives
1728 : // fewer input channels than the other bins.
1729 0 : lastChan = chanEnd_p[k];
1730 :
1731 0 : Int nchan = lastChan - inpChan + 1;
1732 : os << LogIO::NORMAL
1733 0 : << "The last output channel of spw " << spw_p[k]
1734 0 : << " has only " << nchan << " input channel";
1735 0 : if(nchan > 1)
1736 0 : os << "s.";
1737 : //else
1738 : // os << ".\nRemember that MS selection ranges (unlike Python), *include* the last number.";
1739 0 : os << LogIO::POST;
1740 : //os << LogIO::WARN
1741 : // << "You will not be able to export an MS where the width varies by channel to UVFITS!"
1742 : // << LogIO::POST;
1743 : }
1744 :
1745 0 : chanFreqOut[outChan] = (chanFreqIn[inpChan] +
1746 0 : chanFreqIn[lastChan]) / 2;
1747 :
1748 0 : Double sep = chanFreqIn[lastChan] - chanFreqIn[inpChan];
1749 :
1750 0 : if(neginc)
1751 0 : sep = -sep;
1752 :
1753 : // The internal abs is necessary because the sign of chanWidthIn
1754 : // may be wrong.
1755 0 : chanWidthOut[outChan] = sep + 0.5 * abs(chanWidthIn[inpChan] +
1756 0 : chanWidthIn[lastChan]);
1757 0 : if(neginc)
1758 0 : chanWidthOut[outChan] = -chanWidthOut[outChan];
1759 :
1760 0 : spwResolOut[outChan] = 0.5 * (spwResolIn[inpChan] +
1761 0 : spwResolIn[lastChan])
1762 0 : + sep;
1763 :
1764 0 : for(Int avgChan = inpChan; avgChan <= lastChan;
1765 0 : avgChan += chanStep_p[k])
1766 0 : effBWOut[outChan] += effBWIn[avgChan];
1767 : }
1768 : else{
1769 24 : chanFreqOut[outChan] = chanFreqIn[inpChan];
1770 24 : spwResolOut[outChan] = spwResolIn[inpChan];
1771 24 : chanWidthOut[outChan] = chanWidthIn[inpChan];
1772 24 : effBWOut[outChan] = effBWIn[inpChan];
1773 : }
1774 24 : totalBW += effBWOut[outChan];
1775 24 : ++outChan;
1776 : }
1777 : }
1778 6 : --outChan;
1779 :
1780 6 : msSpW.chanFreq().put(min_k, chanFreqOut);
1781 6 : msSpW.refFrequency().put(min_k, min(chanFreqOut[0],chanFreqOut[chanFreqOut.size()-1]));
1782 6 : msSpW.resolution().put(min_k, spwResolOut);
1783 6 : msSpW.numChan().put(min_k, nOutChan);
1784 6 : msSpW.chanWidth().put(min_k, chanWidthOut);
1785 6 : msSpW.effectiveBW().put(min_k, spwResolOut);
1786 6 : msSpW.totalBandwidth().put(min_k, totalBW);
1787 6 : }
1788 : else{
1789 121 : msSpW.chanFreq().put(min_k, inSpWCols.chanFreq()(spw_p[k]));
1790 121 : msSpW.refFrequency().put(min_k, inSpWCols.refFrequency()(spw_p[k]));
1791 121 : msSpW.resolution().put(min_k, inSpWCols.resolution()(spw_p[k]));
1792 121 : msSpW.numChan().put(min_k, inSpWCols.numChan()(spw_p[k]));
1793 121 : msSpW.chanWidth().put(min_k, inSpWCols.chanWidth()(spw_p[k]));
1794 121 : msSpW.effectiveBW().put(min_k, inSpWCols.effectiveBW()(spw_p[k]));
1795 121 : msSpW.totalBandwidth().put(min_k, inSpWCols.totalBandwidth()(spw_p[k]));
1796 : }
1797 :
1798 127 : msSpW.flagRow().put(min_k, inSpWCols.flagRow()(spw_p[k]));
1799 127 : msSpW.freqGroup().put(min_k, inSpWCols.freqGroup()(spw_p[k]));
1800 127 : msSpW.freqGroupName().put(min_k, inSpWCols.freqGroupName()(spw_p[k]));
1801 127 : msSpW.ifConvChain().put(min_k, inSpWCols.ifConvChain()(spw_p[k]));
1802 127 : msSpW.measFreqRef().put(min_k, inSpWCols.measFreqRef()(spw_p[k]));
1803 127 : msSpW.name().put(min_k, inSpWCols.name()(spw_p[k]));
1804 127 : msSpW.netSideband().put(min_k, inSpWCols.netSideband()(spw_p[k]));
1805 127 : if(haveSpwAN)
1806 5 : msSpW.assocNature().put(min_k, inSpWCols.assocNature()(spw_p[k]));
1807 127 : if(haveSpwASI)
1808 5 : msSpW.assocSpwId().put(min_k, inSpWCols.assocSpwId()(spw_p[k]));
1809 127 : if(haveSpwBN)
1810 5 : msSpW.bbcNo().put(min_k, inSpWCols.bbcNo()(spw_p[k]));
1811 127 : if(haveSpwBS)
1812 0 : msSpW.bbcSideband().put(min_k, inSpWCols.bbcSideband()(spw_p[k]));
1813 127 : if(haveSpwDI)
1814 2 : msSpW.dopplerId().put(min_k, inSpWCols.dopplerId()(spw_p[k]));
1815 :
1816 127 : msDD.flagRow().put(min_k, false);
1817 127 : msDD.polarizationId().put(min_k, newPolId[min_k]);
1818 127 : msDD.spectralWindowId().put(min_k, min_k);
1819 : }
1820 44 : return true;
1821 44 : }
1822 :
1823 44 : Bool SubMS::fillFieldTable()
1824 : {
1825 88 : LogIO os(LogOrigin("SubMS", "fillFieldTable()"));
1826 :
1827 : //MSField fieldtable= mssel_p.field();
1828 : // optionalCols[0] = "EPHEMERIS_ID";
1829 44 : uInt nAddedCols = addOptionalColumns(mssel_p.field(), msOut_p.field(),
1830 : true);
1831 :
1832 44 : MSFieldColumns msField(msOut_p.field());
1833 :
1834 44 : const MSFieldColumns& fieldIn = mscIn_p->field();
1835 44 : ScalarColumn<String> code(fieldIn.code());
1836 44 : ArrayColumn<Double> delayDir(fieldIn.delayDir());
1837 44 : ScalarColumn<Bool> flagRow(fieldIn.flagRow());
1838 44 : ScalarColumn<String> name(fieldIn.name());
1839 44 : ScalarColumn<Int> numPoly(fieldIn.numPoly());
1840 44 : ArrayColumn<Double> phaseDir(fieldIn.phaseDir());
1841 44 : ArrayColumn<Double> refDir(fieldIn.referenceDir());
1842 44 : ScalarColumn<Int> sourceId(fieldIn.sourceId());
1843 44 : ScalarColumn<Double> time(fieldIn.time());
1844 :
1845 44 : String refstr;
1846 44 : String nameVarRefColDelayDir, nameVarRefColPhaseDir, nameVarRefColRefDir;
1847 :
1848 : // Need to correctly define the direction measures.
1849 : // DelayDir
1850 44 : if(delayDir.keywordSet().asRecord("MEASINFO").isDefined("Ref")){
1851 42 : delayDir.keywordSet().asRecord("MEASINFO").get("Ref", refstr);
1852 : // MDirection::getType(dir1, refstr);
1853 42 : msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").define("Ref",refstr);
1854 : }
1855 44 : if(delayDir.keywordSet().asRecord("MEASINFO").isDefined("VarRefCol")){ // it's a variable ref. column
1856 2 : delayDir.keywordSet().asRecord("MEASINFO").get("VarRefCol", refstr);
1857 2 : msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").define("VarRefCol",refstr);
1858 2 : nameVarRefColDelayDir = refstr;
1859 2 : Vector<String> refTypeV;
1860 2 : delayDir.keywordSet().asRecord("MEASINFO").get("TabRefTypes", refTypeV);
1861 2 : msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefTypes",refTypeV);
1862 2 : Vector<uInt> refCodeV;
1863 2 : delayDir.keywordSet().asRecord("MEASINFO").get("TabRefCodes", refCodeV);
1864 2 : msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefCodes",refCodeV);
1865 2 : Int refid=msField.delayDir().keywordSet().asRecord("MEASINFO").fieldNumber("Ref");
1866 2 : if(refid>=0){ // erase the redundant Ref keyword
1867 2 : msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").removeField(RecordFieldId(refid));
1868 : }
1869 2 : }
1870 : // PhaseDir
1871 44 : if(phaseDir.keywordSet().asRecord("MEASINFO").isDefined("Ref")){
1872 42 : phaseDir.keywordSet().asRecord("MEASINFO").get("Ref", refstr);
1873 42 : msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").define("Ref", refstr);
1874 : }
1875 44 : if(phaseDir.keywordSet().asRecord("MEASINFO").isDefined("VarRefCol")){ // it's a variable ref. column
1876 2 : phaseDir.keywordSet().asRecord("MEASINFO").get("VarRefCol", refstr);
1877 2 : msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").define("VarRefCol",refstr);
1878 2 : nameVarRefColPhaseDir = refstr;
1879 2 : Vector<String> refTypeV;
1880 2 : phaseDir.keywordSet().asRecord("MEASINFO").get("TabRefTypes", refTypeV);
1881 2 : msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefTypes",refTypeV);
1882 2 : Vector<uInt> refCodeV;
1883 2 : phaseDir.keywordSet().asRecord("MEASINFO").get("TabRefCodes", refCodeV);
1884 2 : msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefCodes",refCodeV);
1885 2 : Int refid=msField.phaseDir().keywordSet().asRecord("MEASINFO").fieldNumber("Ref");
1886 2 : if(refid>=0){
1887 2 : msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").removeField(RecordFieldId(refid));
1888 : }
1889 2 : }
1890 : // ReferenceDir
1891 44 : if(refDir.keywordSet().asRecord("MEASINFO").isDefined("Ref")){
1892 42 : refDir.keywordSet().asRecord("MEASINFO").get("Ref", refstr);
1893 42 : msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").define("Ref",refstr);
1894 : }
1895 44 : if(refDir.keywordSet().asRecord("MEASINFO").isDefined("VarRefCol")){ // it's a variable ref. column
1896 2 : refDir.keywordSet().asRecord("MEASINFO").get("VarRefCol", refstr);
1897 2 : msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").define("VarRefCol",refstr);
1898 2 : nameVarRefColRefDir = refstr;
1899 2 : Vector<String> refTypeV;
1900 2 : refDir.keywordSet().asRecord("MEASINFO").get("TabRefTypes", refTypeV);
1901 2 : msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefTypes",refTypeV);
1902 2 : Vector<uInt> refCodeV;
1903 2 : refDir.keywordSet().asRecord("MEASINFO").get("TabRefCodes", refCodeV);
1904 2 : msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefCodes",refCodeV);
1905 2 : Int refid=msField.referenceDir().keywordSet().asRecord("MEASINFO").fieldNumber("Ref");
1906 2 : if(refid>=0){
1907 2 : msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").removeField(RecordFieldId(refid));
1908 : }
1909 2 : }
1910 :
1911 : // ...and the time measure...
1912 44 : time.keywordSet().asRecord("MEASINFO").get("Ref", refstr);
1913 44 : msField.time().rwKeywordSet().asrwRecord("MEASINFO").define("Ref", refstr);
1914 :
1915 : // fieldRelabel_p size: nrow of a input MS, -1 for unselected field ids
1916 44 : fieldRelabel_p.resize(mscIn_p->field().nrow());
1917 44 : fieldRelabel_p.set(-1);
1918 :
1919 : os << LogIO::DEBUG1
1920 : << fieldid_p.nelements() << " fields selected out of "
1921 44 : << mscIn_p->field().nrow()
1922 44 : << LogIO::POST;
1923 :
1924 : try{
1925 44 : msOut_p.field().addRow(fieldid_p.nelements());
1926 153 : for(uInt k = 0; k < fieldid_p.nelements(); ++k){
1927 109 : fieldRelabel_p[fieldid_p[k]] = k;
1928 :
1929 109 : msField.code().put(k, code(fieldid_p[k]));
1930 109 : msField.delayDir().put(k, delayDir(fieldid_p[k]));
1931 109 : msField.flagRow().put(k, flagRow(fieldid_p[k]));
1932 109 : msField.name().put(k, name(fieldid_p[k]));
1933 109 : msField.numPoly().put(k, numPoly(fieldid_p[k]));
1934 109 : msField.phaseDir().put(k, phaseDir(fieldid_p[k]));
1935 109 : msField.referenceDir().put(k, refDir(fieldid_p[k]));
1936 109 : msField.time().put(k, time(fieldid_p[k]));
1937 :
1938 109 : Int inSrcID = sourceId(fieldid_p[k]);
1939 109 : if(inSrcID < 0)
1940 9 : msField.sourceId().put(k, -1);
1941 : else
1942 100 : msField.sourceId().put(k, sourceRelabel_p[inSrcID]);
1943 : }
1944 :
1945 44 : if(nAddedCols > 0){
1946 :
1947 2 : ScalarColumn<Int> eID(fieldIn.ephemerisId());
1948 2 : if(eID.hasContent()){
1949 1 : String destPathName = Path(msOut_p.field().tableName()).absoluteName();
1950 9 : for(uInt k = 0; k < fieldid_p.nelements(); ++k){
1951 :
1952 8 : Int theEphId = eID(fieldid_p[k]);
1953 :
1954 8 : if(theEphId>-1){ // there is an ephemeris attached to this field
1955 0 : Path ephPath = Path(fieldIn.ephemPath(fieldid_p[k]));
1956 0 : if(ephPath.length()>0){ // copy the ephemeris table over to the output FIELD table
1957 0 : Directory origEphemDir(ephPath);
1958 0 : origEphemDir.copy(destPathName+"/"+ephPath.baseName());
1959 0 : os << LogIO::NORMAL << "Transferring ephemeris " << ephPath.baseName()
1960 0 : << " for output field " << name(fieldid_p[k]) << LogIO::POST;
1961 0 : }
1962 0 : }
1963 8 : msField.ephemerisId().put(k, theEphId);
1964 : }
1965 1 : }
1966 :
1967 2 : if(!nameVarRefColDelayDir.empty()){ // need to copy the reference column
1968 2 : ScalarColumn<Int> dM(mssel_p.field(), nameVarRefColDelayDir);
1969 2 : ScalarColumn<Int> cdMDirRef(msOut_p.field(), nameVarRefColDelayDir);
1970 11 : for(uInt k = 0; k < fieldid_p.nelements(); ++k){
1971 9 : cdMDirRef.put(k, dM(fieldid_p[k]));
1972 : }
1973 2 : }
1974 2 : if(!nameVarRefColPhaseDir.empty()){ // need to copy the reference column
1975 2 : ScalarColumn<Int> dM(mssel_p.field(), nameVarRefColPhaseDir);
1976 2 : ScalarColumn<Int> cdMDirRef(msOut_p.field(), nameVarRefColPhaseDir);
1977 11 : for(uInt k = 0; k < fieldid_p.nelements(); ++k){
1978 9 : cdMDirRef.put(k, dM(fieldid_p[k]));
1979 : }
1980 2 : }
1981 2 : if(!nameVarRefColRefDir.empty()){ // need to copy the reference column
1982 2 : ScalarColumn<Int> dM(mssel_p.field(), nameVarRefColRefDir);
1983 2 : ScalarColumn<Int> cdMDirRef(msOut_p.field(), nameVarRefColRefDir);
1984 11 : for(uInt k = 0; k < fieldid_p.nelements(); ++k){
1985 9 : cdMDirRef.put(k, dM(fieldid_p[k]));
1986 : }
1987 2 : }
1988 2 : }
1989 :
1990 : }
1991 0 : catch(AipsError x){
1992 : os << LogIO::EXCEPTION
1993 : << "Error " << x.getMesg() << " setting up the output FIELD table."
1994 0 : << LogIO::POST;
1995 0 : }
1996 0 : catch(...){
1997 0 : throw(AipsError("Unknown exception caught and released in fillFieldTable()"));
1998 0 : }
1999 :
2000 44 : return true;
2001 44 : }
2002 :
2003 : // Sets up sourceRelabel_p for mapping input SourceIDs (if any) to output
2004 : // ones. Must be called after fieldid_p is set and before calling
2005 : // fillFieldTable() or copySource().
2006 44 : void SubMS::relabelSources()
2007 : {
2008 88 : LogIO os(LogOrigin("SubMS", "relabelSources()"));
2009 :
2010 : //Source is an optional table, so it may not exist
2011 44 : if(Table::isReadable(mssel_p.sourceTableName())){
2012 : // Note that mscIn_p->field().sourceId() has ALL of the sourceIDs in
2013 : // the input MS, not just the selected ones.
2014 44 : const Vector<Int>& inSrcIDs = mscIn_p->field().sourceId().getColumn();
2015 :
2016 44 : Int highestInpSrc = max(inSrcIDs);
2017 :
2018 44 : if(highestInpSrc < 0) // Ensure space for -1.
2019 8 : highestInpSrc = 0;
2020 44 : sourceRelabel_p.resize(highestInpSrc + 1);
2021 44 : sourceRelabel_p.set(-1); // Default to "any".
2022 :
2023 : // Enable sourceIDs that are actually referred to by selected fields, and
2024 : // remap them using j.
2025 44 : uInt j = 0;
2026 153 : for(uInt k = 0; k < fieldid_p.nelements(); ++k){
2027 109 : Int fldInSrcID = inSrcIDs[fieldid_p[k]];
2028 :
2029 109 : if(fldInSrcID > -1){
2030 100 : if(sourceRelabel_p[fldInSrcID] == -1){ // Multiple fields can use the same
2031 100 : sourceRelabel_p[fldInSrcID] = j; // source in a mosaic.
2032 100 : ++j;
2033 : }
2034 : }
2035 : }
2036 44 : }
2037 : else{
2038 : os << LogIO::NORMAL
2039 : << "The input MS does not have the optional SOURCE table.\n"
2040 : << "-1 will be used as a generic source ID."
2041 0 : << LogIO::POST;
2042 0 : sourceRelabel_p.resize(1);
2043 0 : sourceRelabel_p.set(-1); // Default to "any".
2044 : }
2045 44 : }
2046 :
2047 : // This method is currently not called in SubMS. It should really be called
2048 : // in setupMS, but that has been made into a static method and it cannot be
2049 : // called there. The ms argument is unused, but it is there to preserve the
2050 : // signature, and is commented to prevent a compiler warning.
2051 : //
2052 0 : void SubMS::verifyColumns(const MeasurementSet&, // ms,
2053 : const Vector<MS::PredefinedColumns>& colNames)
2054 : {
2055 0 : LogIO os(LogOrigin("SubMS", "verifyColumns()"));
2056 0 : for(uInt i=0;i<colNames.nelements();i++)
2057 0 : if (!ms_p.tableDesc().isColumn(MS::columnName(colNames[i])))
2058 : {
2059 0 : ostringstream ostr;
2060 0 : ostr << "Desired column (" << MS::columnName(colNames[i])
2061 0 : << ") not found in the input MS (" << ms_p.tableName() << ").";
2062 0 : throw(AipsError(ostr.str()));
2063 0 : }
2064 0 : }
2065 :
2066 54 : Int SubMS::regridSpw(String& regridMessage,
2067 : const String& outframe,
2068 : const String& regridQuant,
2069 : const Double regridVeloRestfrq,
2070 : const String& regridInterpMeth,
2071 : const Double regridCenter,
2072 : const Double regridBandwidth,
2073 : const Double regridChanWidth,
2074 : const Bool doHanningSmooth,
2075 : const Int phaseCenterFieldId,
2076 : MDirection phaseCenter,
2077 : const Bool centerIsStart,
2078 : const Bool startIsEnd,
2079 : const Int nchan,
2080 : const Int width,
2081 : const Int start
2082 : ){
2083 :
2084 108 : LogIO os(LogOrigin("SubMS", "regridSpw()"));
2085 :
2086 54 : Int rval = -1; // return values: -1 = MS not modified, 1 = MS modified and OK,
2087 : // 0 = MS modified but not OK
2088 :
2089 : // get the original table description of the MS
2090 54 : TableDesc origMSTD(ms_p.actualTableDesc());
2091 88 : if(!origMSTD.isColumn("CORRECTED_DATA") && !origMSTD.isColumn("DATA")
2092 88 : && !origMSTD.isColumn("FLOAT_DATA") && !origMSTD.isColumn("MODEL_DATA")){
2093 0 : os << LogIO::WARN << "MS has no DATA columns. Nothing to regrid." << LogIO::POST;
2094 : }
2095 :
2096 : // Set up a little database to keep track of which pairs (FieldId, SPWId) have already
2097 : // been dealt with and what parameters were used
2098 :
2099 54 : vector<Int> oldSpwId;
2100 54 : vector<Int> oldFieldId;
2101 54 : vector<Int> newDataDescId;
2102 54 : vector<Bool> regrid;
2103 54 : vector<Bool> transform;
2104 54 : vector<MDirection> theFieldDirV;
2105 54 : vector<MPosition> mObsPosV;
2106 54 : vector<MFrequency::Types> fromFrameTypeV; // original ref frame of the SPW
2107 54 : vector<MFrequency::Ref> outFrameV; // new ref frame
2108 54 : vector<MRadialVelocity> outRadVelV; // radial velocity correction applied to the new ref frame
2109 54 : vector<Double> weightScaleV; // the scaling factor for the WEIGHTs
2110 54 : vector< Vector<Double> > xold; // the frequencies of the original SPW in the old ref frame
2111 54 : vector< Vector<Double> > xout; // the frequencies of the new SPW in the new ref frame
2112 54 : vector< Vector<Double> > xin; // the frequencies of the old SPW in the new ref frame
2113 54 : vector< Int > method; // interpolation method cast to Int
2114 :
2115 :
2116 54 : Bool msModified = false;
2117 :
2118 54 : String oframe = outframe;
2119 54 : oframe.upcase();
2120 54 : Bool doRadVelCorr = (oframe=="SOURCE");
2121 :
2122 : // Loop 1: Verify the input parameters, no modification of the MS
2123 54 : if(!setRegridParameters(oldSpwId,
2124 : oldFieldId,
2125 : newDataDescId,
2126 : regrid,
2127 : transform,
2128 : theFieldDirV,
2129 : mObsPosV,
2130 : fromFrameTypeV,
2131 : outFrameV,
2132 : outRadVelV,
2133 : weightScaleV,
2134 : xold,
2135 : xout,
2136 : xin,
2137 : method,
2138 : msModified,
2139 : outframe,
2140 : regridQuant,
2141 : regridVeloRestfrq,
2142 : regridInterpMeth,
2143 : regridCenter,
2144 : regridBandwidth,
2145 : regridChanWidth,
2146 : phaseCenterFieldId,
2147 : phaseCenter,
2148 : false, // <-----
2149 : os,
2150 : regridMessage,
2151 : centerIsStart,
2152 : startIsEnd,
2153 : nchan,
2154 : width,
2155 : start
2156 : )){ // an error occured
2157 1 : return -1;
2158 : }
2159 :
2160 53 : if(oframe=="SOURCE" || oframe=="GEO"){
2161 : os << LogIO::NORMAL
2162 : << "Note: with outframe==GEO or outframe==SOURCE, the resulting spectral windows with be labeled as having reference frame REST.\n"
2163 : << " All integrations will be Doppler-tracked to correspond to the GEO frame at the beginning of the observation\n"
2164 : << " (with radial velocity corrections in the case of outframe==SOURCE).\n"
2165 : << " No subsequent regridding to other reference frames will be possible."
2166 3 : << LogIO::POST;
2167 : }
2168 :
2169 53 : vector<Double> sigmaScaleV(weightScaleV.size());
2170 106 : for(uInt i=0; i<weightScaleV.size(); i++){
2171 53 : if(weightScaleV[i]<=0.){
2172 0 : os << LogIO::WARN << "Internal error: Encountered non-positive weight scaling factor " << weightScaleV[i] <<endl
2173 0 : << "Aborting." << LogIO::POST;
2174 0 : return -1;
2175 : }
2176 53 : else if(doHanningSmooth){
2177 3 : weightScaleV[i] *= 1.32;
2178 : }
2179 53 : sigmaScaleV[i] = 1./sqrt(weightScaleV[i]);
2180 : }
2181 :
2182 : // Loop 2: Write modified DD, SPW, and SOURCE tables
2183 :
2184 53 : if(!setRegridParameters(oldSpwId,
2185 : oldFieldId,
2186 : newDataDescId,
2187 : regrid,
2188 : transform,
2189 : theFieldDirV,
2190 : mObsPosV,
2191 : fromFrameTypeV,
2192 : outFrameV,
2193 : outRadVelV,
2194 : weightScaleV,
2195 : xold,
2196 : xout,
2197 : xin,
2198 : method,
2199 : msModified,
2200 : outframe,
2201 : regridQuant,
2202 : regridVeloRestfrq,
2203 : regridInterpMeth,
2204 : regridCenter,
2205 : regridBandwidth,
2206 : regridChanWidth,
2207 : phaseCenterFieldId,
2208 : phaseCenter,
2209 : true, // <-----
2210 : os,
2211 : regridMessage,
2212 : centerIsStart,
2213 : startIsEnd,
2214 : nchan,
2215 : width,
2216 : start
2217 : )){ // an error occured
2218 0 : if(msModified){
2219 0 : return 0;
2220 : }
2221 : else{
2222 0 : return -1;
2223 : }
2224 : }
2225 :
2226 53 : if(!msModified){ // nothing to be done in terms of regridding
2227 8 : if(doHanningSmooth){ // but we still need to Hanning smooth
2228 1 : os << LogIO::NORMAL << "Hanning smoothing not applied in regridding step since no regridding was necessary." << LogIO::POST;
2229 : }
2230 8 : return -1;
2231 : }
2232 :
2233 : // now we need to modify the main table ...
2234 :
2235 45 : Bool needRegridding = false;
2236 90 : for(uInt i=0; i<regrid.size(); i++){
2237 45 : if(regrid[i]){
2238 45 : needRegridding = true;
2239 : }
2240 : }
2241 :
2242 45 : if(needRegridding){
2243 :
2244 45 : os << LogIO::NORMAL << "Main table data array columns will be rewritten." << LogIO::POST;
2245 :
2246 : // create the "partner" columns, i.e. rename the old array columns to old...
2247 : // and create new empty columns with the original names to hold the regridded values
2248 :
2249 45 : MSMainColumns mCols(ms_p);
2250 45 : Int nCorr = mCols.data().shape(0)(0); // the first dimension of DATA
2251 45 : IPosition dataShape(2, nCorr, xout[0].size());
2252 45 : Int obstype = 0; // default
2253 45 : MSObservationColumns obsCols(ms_p.observation());
2254 45 : String telescop = obsCols.telescopeName()(mCols.observationId()(0));
2255 45 : IPosition tileShape = MSTileLayout::tileShape(dataShape, obstype, telescop);
2256 :
2257 45 : createPartnerColumn(origMSTD, "CORRECTED_DATA", "oldCORRECTED_DATA", 3, tileShape);
2258 45 : createPartnerColumn(origMSTD, "DATA", "oldDATA", 3, tileShape);
2259 45 : createPartnerColumn(origMSTD, "FLOAT_DATA", "oldFLOAT_DATA", 3, tileShape);
2260 45 : createPartnerColumn(origMSTD, "LAG_DATA", "oldLAG_DATA", 3, tileShape);
2261 45 : createPartnerColumn(origMSTD, "MODEL_DATA", "oldMODEL_DATA", 3, tileShape);
2262 45 : createPartnerColumn(origMSTD, "SIGMA_SPECTRUM", "oldSIGMA_SPECTRUM", 3, tileShape);
2263 45 : createPartnerColumn(origMSTD, "WEIGHT_SPECTRUM", "oldWEIGHT_SPECTRUM", 3, tileShape);
2264 45 : createPartnerColumn(origMSTD, "FLAG", "oldFLAG", 3, tileShape);
2265 :
2266 45 : createPartnerColumn(origMSTD, "FLAG_CATEGORY", "oldFLAG_CATEGORY", 4,
2267 90 : IPosition(4,tileShape(0),tileShape(1),1, tileShape(2)));
2268 45 : }
2269 :
2270 45 : MSMainColumns mainCols(ms_p);
2271 :
2272 : // columns which depend on the number of frequency channels and may need to be regridded:
2273 : // DATA, FLOAT_DATA, CORRECTED_DATA, MODEL_DATA, LAG_DATA, SIGMA_SPECTRUM,
2274 : // WEIGHT_SPECTRUM, FLAG, and FLAG_CATEGORY
2275 45 : ArrayColumn<Complex> CORRECTED_DATACol = mainCols.correctedData();
2276 45 : ArrayColumn<Complex>* oldCORRECTED_DATAColP = 0;
2277 45 : ArrayColumn<Complex> DATACol = mainCols.data();
2278 45 : ArrayColumn<Complex>* oldDATAColP = 0;
2279 45 : ArrayColumn<Float> FLOAT_DATACol = mainCols.floatData();
2280 45 : ArrayColumn<Float>* oldFLOAT_DATAColP = 0;
2281 45 : ArrayColumn<Complex> LAG_DATACol = mainCols.lagData();
2282 45 : ArrayColumn<Complex>* oldLAG_DATAColP = 0;
2283 45 : ArrayColumn<Complex> MODEL_DATACol = mainCols.modelData();
2284 45 : ArrayColumn<Complex>* oldMODEL_DATAColP = 0;
2285 45 : ArrayColumn<Float> SIGMA_SPECTRUMCol = mainCols.sigmaSpectrum();
2286 45 : ArrayColumn<Float>* oldSIGMA_SPECTRUMColP = 0;
2287 45 : ArrayColumn<Float> WEIGHT_SPECTRUMCol = mainCols.weightSpectrum();
2288 45 : ArrayColumn<Float>* oldWEIGHT_SPECTRUMColP = 0;
2289 45 : ArrayColumn<Bool> FLAGCol = mainCols.flag();
2290 45 : ArrayColumn<Bool>* oldFLAGColP = 0;
2291 45 : ArrayColumn<Bool> FLAG_CATEGORYCol = mainCols.flagCategory();
2292 45 : ArrayColumn<Bool>* oldFLAG_CATEGORYColP = 0;
2293 :
2294 : // WEIGHT and SIGMA will possibly need to be modified (these are also arrays but only for corr. product)
2295 45 : ArrayColumn<Float> SIGMACol = mainCols.sigma();
2296 45 : ArrayColumn<Float> WEIGHTCol = mainCols.weight();
2297 :
2298 45 : if(needRegridding){
2299 :
2300 45 : if(doHanningSmooth){
2301 2 : os << LogIO::NORMAL << "The following columns will be Hanning-smoothed before regridding: " << LogIO::POST;
2302 2 : if(!DATACol.isNull()){
2303 2 : os << LogIO::NORMAL << " DATA ";
2304 : }
2305 2 : if(!CORRECTED_DATACol.isNull()){
2306 2 : os << LogIO::NORMAL << " CORRECTED_DATA " << LogIO::POST;
2307 : }
2308 2 : if(!LAG_DATACol.isNull()){
2309 0 : os << LogIO::NORMAL << " LAG_DATA ";
2310 : }
2311 2 : if(!FLOAT_DATACol.isNull()){
2312 0 : os << LogIO::NORMAL << " FLOAT_DATA ";
2313 : }
2314 2 : os << LogIO::POST;
2315 : }
2316 :
2317 : // (create column objects for all "partners" of the array columns to be modified)
2318 45 : if(!CORRECTED_DATACol.isNull()){
2319 18 : oldCORRECTED_DATAColP = new ArrayColumn<Complex>(ms_p, "oldCORRECTED_DATA");
2320 : }
2321 45 : if(!DATACol.isNull()){
2322 45 : oldDATAColP = new ArrayColumn<Complex>(ms_p, "oldDATA");
2323 : }
2324 45 : if(!FLOAT_DATACol.isNull()){
2325 0 : oldFLOAT_DATAColP = new ArrayColumn<Float>(ms_p, "oldFLOAT_DATA");
2326 : }
2327 45 : if(!LAG_DATACol.isNull()){
2328 0 : oldLAG_DATAColP = new ArrayColumn<Complex>(ms_p, "oldLAG_DATA");
2329 : }
2330 45 : if(!MODEL_DATACol.isNull()){
2331 17 : oldMODEL_DATAColP = new ArrayColumn<Complex>(ms_p, "oldMODEL_DATA");
2332 : }
2333 45 : if(!SIGMA_SPECTRUMCol.isNull()){
2334 2 : oldSIGMA_SPECTRUMColP = new ArrayColumn<Float>(ms_p, "oldSIGMA_SPECTRUM");
2335 : }
2336 45 : if(!WEIGHT_SPECTRUMCol.isNull()){
2337 45 : oldWEIGHT_SPECTRUMColP = new ArrayColumn<Float>(ms_p, "oldWEIGHT_SPECTRUM");
2338 : }
2339 45 : if(!FLAGCol.isNull()){
2340 45 : oldFLAGColP = new ArrayColumn<Bool>(ms_p, "oldFLAG");
2341 : }
2342 45 : if(!FLAG_CATEGORYCol.isNull()){
2343 45 : oldFLAG_CATEGORYColP = new ArrayColumn<Bool>(ms_p, "oldFLAG_CATEGORY");
2344 : }
2345 : } // end if needRegridding
2346 :
2347 : // administrational columns needed from the main table
2348 45 : ScalarColumn<Int> fieldIdCol = mainCols.fieldId();
2349 45 : ScalarColumn<Int> DDIdCol = mainCols.dataDescId();
2350 45 : ScalarMeasColumn<MEpoch> mainTimeMeasCol = mainCols.timeMeas();
2351 :
2352 : // columns needed from subtables
2353 45 : MSDataDescription ddtable=ms_p.dataDescription();
2354 45 : MSDataDescColumns DDCols(ddtable);
2355 45 : ScalarColumn<Int> SPWIdCol = DDCols.spectralWindowId();
2356 45 : MSFieldColumns fldCols(ms_p.field());
2357 :
2358 : // Loop 3: Apply to MAIN table rows
2359 :
2360 : // cout << "Modifying main table ..." << endl;
2361 :
2362 45 : uInt nMainTabRows = ms_p.nrow();
2363 :
2364 : // create time-sorted index for main table access
2365 45 : Vector<uInt> sortedI(nMainTabRows);
2366 :
2367 45 : Vector<Double> mainTimesV = mainCols.time().getColumn();
2368 45 : GenSortIndirect<Double>::sort(sortedI,mainTimesV);
2369 :
2370 : // prepare progress meter
2371 45 : Float progress = 0.2;
2372 45 : Float progressStep = 0.2;
2373 45 : if(ms_p.nrow()>100000){
2374 0 : progress = 0.1;
2375 0 : progressStep = 0.1;
2376 : }
2377 :
2378 : // prepare some regridding prerequisites
2379 45 : FFTServer<Float, Complex> fFFTServer; // for fftshift, if needed
2380 :
2381 : // start loop over main table
2382 427358 : for(uInt mainTabRowI=0; mainTabRowI<nMainTabRows; mainTabRowI++){
2383 :
2384 427313 : uInt mainTabRow = sortedI(mainTabRowI); // i.e. mainTabRow is sorted in time
2385 :
2386 : //if(mainTabRow!=mainTabRowI){
2387 : // cout << "processing row " << mainTabRow << ", index " << mainTabRowI << endl;
2388 : //}
2389 :
2390 : // For each MAIN table row, the FIELD_ID cell and the DATA_DESC_ID cell are read
2391 427313 : Int theFieldId = fieldIdCol(mainTabRow);
2392 427313 : Int theDataDescId = DDIdCol(mainTabRow);
2393 : // and the SPW_ID extracted from the corresponding row in the DATA_DESCRIPTION table.
2394 427313 : Int theSPWId = SPWIdCol(theDataDescId);
2395 :
2396 427313 : MEpoch theObsTime = mainTimeMeasCol(mainTabRow);
2397 :
2398 : // The pair (theFieldId, theSPWId) is looked up in the "done table".
2399 427313 : Int iDone = -1;
2400 427313 : for (uInt i=0; i<oldSpwId.size(); i++){
2401 427313 : if(oldSpwId[i]==theSPWId && (oldFieldId[i]==theFieldId || phaseCenterFieldId>=-1)){
2402 : // if common phase center is given, treat all fields the same
2403 427313 : iDone = i;
2404 427313 : break;
2405 : }
2406 : }
2407 427313 : if(iDone<0){ // should not occur
2408 : os << LogIO::SEVERE << "Internal error: Did not find regrid parameters for field =="
2409 0 : << theFieldId << " spw ==" << theSPWId << LogIO::POST;
2410 0 : return 0;
2411 : }
2412 :
2413 :
2414 427313 : if (DDIdCol(mainTabRow)!=newDataDescId[iDone]){
2415 : // If the data description actually changed, then DATA_DESC_ID
2416 : // of this main table row is set to the new value given in the "done" table
2417 0 : DDIdCol.put(mainTabRow, newDataDescId[iDone]);
2418 :
2419 : }
2420 :
2421 : //Furthermore, if regrid[iDone] is true, the visibilities and all
2422 : // channel-number-dependent arrays need to be regridded.
2423 427313 : if(regrid[iDone]){
2424 :
2425 427313 : Bool doExtrapolate = false;
2426 :
2427 : // regrid the complex columns
2428 427313 : Array<Complex> yout;
2429 427313 : Array<Bool> youtFlags;
2430 427313 : Bool youtFlagsWritten(false);
2431 427313 : Array<Complex> yin;
2432 427313 : Array<Bool> yinFlags((*oldFLAGColP)(mainTabRow));
2433 427313 : Array<Bool> yinFlagsUnsmoothed;
2434 427313 : Array<Complex> yinIntermediate;
2435 427313 : Array<Bool> yinFlagsIntermediate;
2436 427313 : if(doHanningSmooth){
2437 660 : yinFlagsUnsmoothed.assign(yinFlags);
2438 : }
2439 :
2440 427313 : Vector<Double> xindd(xold[iDone].size());
2441 427313 : Double theShift = 0.;
2442 :
2443 427313 : if(transform[iDone]){
2444 :
2445 : // create frequency machine for this time stamp
2446 115999 : MDirection fldDir = fldCols.phaseDirMeas(theFieldId, mainTimesV(mainTabRow));
2447 :
2448 :
2449 115999 : MFrequency::Ref fromFrame = MFrequency::Ref(fromFrameTypeV[iDone], MeasFrame(fldDir, mObsPosV[iDone], theObsTime));
2450 115999 : Unit unit(String("Hz"));
2451 115999 : MFrequency::Convert freqTrans2(unit, fromFrame, outFrameV[iDone]);
2452 :
2453 115999 : MDoppler radVelCorr; // no correction
2454 115999 : Bool radVelSignificant = false;
2455 :
2456 : // prepare correction for radial velocity if requested and possible
2457 115999 : if(doRadVelCorr && fldCols.needInterTime(theFieldId)){
2458 58741 : MRadialVelocity mRV = fldCols.radVelMeas(theFieldId, mainTimesV(mainTabRow));
2459 58741 : MRadialVelocity::Ref mRVR = mRV.getRef();
2460 58741 : if(mRVR.getType() == MRadialVelocity::GEO){
2461 58741 : Quantity mrv = mRV.get("m/s");
2462 58741 : Quantity offsetMrv = outRadVelV[iDone].get("m/s"); // the radvel by which the out SPW def was shifted
2463 58741 : radVelCorr = MDoppler(mrv-(2.*offsetMrv));
2464 58741 : if(fabs(mrv.getValue())>1E-6){
2465 58741 : radVelSignificant = true;
2466 : }
2467 58741 : }
2468 : else{
2469 : os << LogIO::SEVERE << "Cannot perform radial velocity correction with ephemerides of type "
2470 0 : << MRadialVelocity::showType(mRVR.getType()) << ".\nType needs to be GEO." << LogIO::POST;
2471 0 : return 0;
2472 : }
2473 58741 : }
2474 :
2475 : // prepare fftshift if necessary
2476 115999 : if(method[iDone]==(Int)useFFTShift || method[iDone]==(Int)useLinIntThenFFTShift){
2477 990 : uInt centerChan = xold[iDone].size()/2;
2478 990 : Vector<Double> newFreq(1);
2479 990 : newFreq[0] = freqTrans2(xold[iDone][centerChan]).get(unit).getValue();
2480 990 : if(radVelSignificant){
2481 0 : newFreq = radVelCorr.shiftFrequency(newFreq);
2482 : }
2483 :
2484 990 : theShift = newFreq[0] - xin[iDone][centerChan];
2485 :
2486 : //cout << "the shift " << theShift << endl;
2487 254430 : for(uInt i=0; i<xin[iDone].size(); i++){ // cannot use assign due to different data type
2488 253440 : xindd[i] = xin[iDone][i];
2489 : }
2490 990 : }
2491 : else{
2492 : // transform from this timestamp to the one of the output SPW
2493 3062663 : for(uInt i=0; i<xindd.size(); i++){
2494 2947654 : xindd[i] = freqTrans2(xold[iDone][i]).get(unit).getValue();
2495 : }
2496 115009 : if(radVelSignificant){
2497 58741 : xindd = radVelCorr.shiftFrequency(xindd);
2498 : }
2499 : // if(mainTabRow==0){ // debug output
2500 : // Int i = 25;
2501 : // cout << "i " << i << " xin " << setprecision(9) << xin[iDone][i] << " xindd " << setprecision(9) << xindd[i]
2502 : // << " xout " << setprecision(9) << xout[iDone][i] << endl;
2503 : // cout << "i " << i << " vradxin " << setprecision(9) << vrad(xin[iDone][i], regridVeloRestfrq)
2504 : // << " vradxindd " << setprecision(9) << vrad(xindd[i], regridVeloRestfrq)
2505 : // << " xout " << setprecision(9) << vrad(xout[iDone][i], regridVeloRestfrq) << endl;
2506 : // }
2507 : }
2508 115999 : }
2509 : else{ // no additional transformation of input grid
2510 20144406 : for(uInt i=0; i<xin[iDone].size(); i++){ // cannot use assign due to different data type
2511 19833092 : xindd[i] = xin[iDone][i];
2512 : }
2513 : }
2514 :
2515 :
2516 427313 : Double relShift = 0.;
2517 427313 : InterpolateArray1D<Double,Complex>::InterpolationMethod methodC = InterpolateArray1D<Double,Complex>::linear; // the default
2518 427313 : InterpolateArray1D<Double,Float>::InterpolationMethod methodF = InterpolateArray1D<Double,Float>::linear;
2519 :
2520 427643 : if(fabs(theShift)>0. &&
2521 330 : (method[iDone]==(Int)useFFTShift || method[iDone]==(Int)useLinIntThenFFTShift)
2522 : ){
2523 330 : Int endChan = xout[iDone].size()-1;
2524 330 : if(endChan<=0){
2525 0 : os << LogIO::SEVERE << "Internal error: Cannot regrid a single-channel SPW using FFTshift" << LogIO::POST;
2526 0 : return 0;
2527 : }
2528 330 : Double chanWidth = xout[iDone][1] - xout[iDone][0];
2529 330 : relShift = -theShift/(xout[iDone][endChan] - xout[iDone][0] + chanWidth);
2530 : //cout << "the relshift " << relShift << endl;
2531 : }
2532 : else{
2533 426983 : methodC = (InterpolateArray1D<Double,Complex>::InterpolationMethod) method[iDone];
2534 426983 : methodF = (InterpolateArray1D<Double,Float>::InterpolationMethod) method[iDone];
2535 : }
2536 :
2537 427313 : if(!CORRECTED_DATACol.isNull()){
2538 7843 : yin.assign((*oldCORRECTED_DATAColP)(mainTabRow));
2539 :
2540 : // hanning smooth if requested
2541 7843 : if(doHanningSmooth){
2542 :
2543 : // copy yin to yinUnsmoothed
2544 660 : Array<Complex> yinUnsmoothed;
2545 660 : yinUnsmoothed.assign(yin);
2546 :
2547 660 : Smooth<Complex>::hanning(yin, // the output
2548 : yinFlags, // the output flags
2549 : yinUnsmoothed, // the input
2550 : yinFlagsUnsmoothed, // the input flags
2551 : false); // for flagging: good is not true
2552 660 : }
2553 :
2554 7843 : if(method[iDone]==(Int)useLinIntThenFFTShift){
2555 : // first interpolate to equidistant grid at initial timestamp
2556 990 : InterpolateArray1D<Double,Complex>::interpolate(yinIntermediate, // the new visibilities
2557 : yinFlagsIntermediate, // the new flags
2558 990 : xout[iDone], // the new channel centers (for the output SPW timestamp)
2559 : xindd, // the old channel centers
2560 : yin, // the old visibilities
2561 : yinFlags,// the old flags
2562 : InterpolateArray1D<Double,Complex>::linear, // the interpol method
2563 : false, // for flagging: good is not true
2564 : doExtrapolate // do not extrapolate
2565 : );
2566 : // shift from this timestamp to the output SPW timestamp
2567 990 : fFFTServer.fftshift(yout, youtFlags, yinIntermediate, yinFlagsIntermediate,
2568 990 : 1, // axis 1 of the array is the polarisation axis
2569 : relShift,
2570 : false, // for flagging: good is not true
2571 : false);
2572 :
2573 : }
2574 6853 : else if(method[iDone]==(Int)useFFTShift){
2575 : // shift from this timestamp to the output SPW timestamp
2576 0 : fFFTServer.fftshift(yout, youtFlags, yin, yinFlags,
2577 0 : 1, // axis 1 of the array is the polarisation axis
2578 : relShift,
2579 : false, // for flagging: good is not true
2580 : false);
2581 : }
2582 : else{
2583 6853 : InterpolateArray1D<Double,Complex>::interpolate(yout, // the new visibilities
2584 : youtFlags, // the new flags
2585 6853 : xout[iDone], // the new channel centers
2586 : xindd, // the old channel centers
2587 : yin, // the old visibilities
2588 : yinFlags,// the old flags
2589 : methodC, // the interpol method
2590 : false, // for flagging: good is not true
2591 : doExtrapolate // do not extrapolate
2592 : );
2593 : }
2594 :
2595 7843 : CORRECTED_DATACol.put(mainTabRow, yout);
2596 7843 : if(!youtFlagsWritten){
2597 7843 : FLAGCol.put(mainTabRow, youtFlags);
2598 7843 : youtFlagsWritten = true;
2599 : }
2600 : }
2601 427313 : if(!DATACol.isNull()){
2602 427313 : yin.assign((*oldDATAColP)(mainTabRow));
2603 427313 : if(doHanningSmooth){
2604 660 : Array<Complex> yinUnsmoothed;
2605 660 : yinUnsmoothed.assign(yin);
2606 :
2607 660 : Smooth<Complex>::hanning(yin, yinFlags, yinUnsmoothed, yinFlagsUnsmoothed, false);
2608 660 : }
2609 :
2610 427313 : if(method[iDone]==(Int)useLinIntThenFFTShift){
2611 28710 : InterpolateArray1D<Double,Complex>::interpolate(yinIntermediate, yinFlagsIntermediate, xout[iDone],
2612 : xindd, yin, yinFlags,
2613 : InterpolateArray1D<Double,Complex>::linear,
2614 : false, doExtrapolate);
2615 28710 : fFFTServer.fftshift(yout, youtFlags, yinIntermediate, yinFlagsIntermediate,
2616 28710 : 1, relShift, false, false);
2617 :
2618 : }
2619 398603 : else if(method[iDone]==(Int)useFFTShift){
2620 0 : fFFTServer.fftshift(yout, youtFlags, yin, yinFlags,
2621 0 : 1, relShift, false, false);
2622 : }
2623 : else{
2624 398603 : InterpolateArray1D<Double,Complex>::interpolate(yout, youtFlags, xout[iDone],
2625 : xindd, yin, yinFlags,
2626 : methodC, false, doExtrapolate);
2627 : }
2628 :
2629 427313 : DATACol.put(mainTabRow, yout);
2630 427313 : if(!youtFlagsWritten){
2631 419470 : FLAGCol.put(mainTabRow, youtFlags);
2632 419470 : youtFlagsWritten = true;
2633 : }
2634 : }
2635 427313 : if(!LAG_DATACol.isNull()){
2636 0 : yin.assign((*oldLAG_DATAColP)(mainTabRow));
2637 0 : if(doHanningSmooth){
2638 0 : Array<Complex> yinUnsmoothed;
2639 0 : yinUnsmoothed.assign(yin);
2640 :
2641 0 : Smooth<Complex>::hanning(yin, yinFlags, yinUnsmoothed, yinFlagsUnsmoothed, false);
2642 0 : }
2643 0 : if(method[iDone]==(Int)useLinIntThenFFTShift){
2644 0 : InterpolateArray1D<Double,Complex>::interpolate(yinIntermediate, yinFlagsIntermediate, xout[iDone],
2645 : xindd, yin, yinFlags,
2646 : InterpolateArray1D<Double,Complex>::linear,
2647 : false, doExtrapolate);
2648 0 : fFFTServer.fftshift(yout, youtFlags, yinIntermediate, yinFlagsIntermediate,
2649 0 : 1, relShift, false, false);
2650 :
2651 : }
2652 0 : else if(method[iDone]==(Int)useFFTShift){
2653 0 : fFFTServer.fftshift(yout, youtFlags, yin, yinFlags,
2654 0 : 1, relShift, false, false);
2655 : }
2656 : else{
2657 0 : InterpolateArray1D<Double,Complex>::interpolate(yout, youtFlags, xout[iDone],
2658 : xindd, yin, yinFlags,
2659 : methodC, false, doExtrapolate);
2660 : }
2661 :
2662 0 : LAG_DATACol.put(mainTabRow, yout);
2663 : }
2664 427313 : if(!MODEL_DATACol.isNull()){
2665 7842 : yin.assign((*oldMODEL_DATAColP)(mainTabRow));
2666 :
2667 7842 : if(method[iDone]==(Int)useLinIntThenFFTShift){
2668 990 : InterpolateArray1D<Double,Complex>::interpolate(yinIntermediate, yinFlagsIntermediate, xout[iDone],
2669 : xindd, yin, yinFlags,
2670 : InterpolateArray1D<Double,Complex>::linear,
2671 : false, doExtrapolate);
2672 990 : fFFTServer.fftshift(yout, youtFlags, yinIntermediate, yinFlagsIntermediate,
2673 990 : 1, relShift, false, false);
2674 :
2675 : }
2676 6852 : else if(method[iDone]==(Int)useFFTShift){
2677 0 : fFFTServer.fftshift(yout, youtFlags, yin, yinFlags,
2678 0 : 1, relShift, false, false);
2679 : }
2680 : else{
2681 6852 : InterpolateArray1D<Double,Complex>::interpolate(yout, youtFlags, xout[iDone],
2682 : xindd, yin, yinFlags,
2683 : methodC, false, doExtrapolate);
2684 : }
2685 :
2686 7842 : MODEL_DATACol.put(mainTabRow, yout);
2687 7842 : if(!youtFlagsWritten){
2688 0 : FLAGCol.put(mainTabRow, youtFlags);
2689 0 : youtFlagsWritten = true;
2690 : }
2691 : }
2692 :
2693 : // regrid the Float columns
2694 427313 : Array<Float> yinf;
2695 427313 : Array<Float> youtf;
2696 427313 : Array<Float> fYinIntermediate;
2697 427313 : if(!FLOAT_DATACol.isNull()){
2698 0 : yinf.assign((*oldFLOAT_DATAColP)(mainTabRow));
2699 0 : if(doHanningSmooth){
2700 0 : Array<Float> yinfUnsmoothed;
2701 0 : yinfUnsmoothed.assign(yinf);
2702 :
2703 0 : Smooth<Float>::hanning(yinf, yinFlags, yinfUnsmoothed, yinFlagsUnsmoothed, false);
2704 0 : }
2705 :
2706 0 : if(method[iDone]==(Int)useLinIntThenFFTShift){
2707 0 : InterpolateArray1D<Double,Float>::interpolate(fYinIntermediate, yinFlagsIntermediate, xout[iDone],
2708 : xindd, yinf, yinFlags,
2709 : InterpolateArray1D<Double,Float>::linear,
2710 : false, doExtrapolate);
2711 0 : fFFTServer.fftshift(youtf, youtFlags, fYinIntermediate, yinFlagsIntermediate,
2712 0 : 1, relShift, false);
2713 :
2714 : }
2715 0 : else if(method[iDone]==(Int)useFFTShift){
2716 0 : fFFTServer.fftshift(youtf, youtFlags, yinf, yinFlags,
2717 0 : 1, relShift, false);
2718 : }
2719 : else{
2720 0 : InterpolateArray1D<Double, Float>::interpolate(youtf, youtFlags, xout[iDone], xindd,
2721 : yinf, yinFlags, methodF, false, doExtrapolate);
2722 : }
2723 :
2724 0 : FLOAT_DATACol.put(mainTabRow, youtf);
2725 0 : if(!youtFlagsWritten){
2726 0 : FLAGCol.put(mainTabRow, youtFlags);
2727 0 : youtFlagsWritten = true;
2728 : }
2729 : }
2730 :
2731 427313 : if(!SIGMA_SPECTRUMCol.isNull()){
2732 58740 : yinf.assign((*oldSIGMA_SPECTRUMColP)(mainTabRow));
2733 58740 : InterpolateArray1D<Double, Float>::interpolate(youtf, youtFlags, xout[iDone], xindd,
2734 : yinf, yinFlags, methodF, false, doExtrapolate);
2735 58740 : SIGMA_SPECTRUMCol.put(mainTabRow, youtf * sigmaScaleV[iDone]); // an approximation
2736 : }
2737 427313 : if(!WEIGHT_SPECTRUMCol.isNull() && oldWEIGHT_SPECTRUMColP->isDefined(mainTabRow)){ // required column, but can be empty
2738 405278 : yinf.assign((*oldWEIGHT_SPECTRUMColP)(mainTabRow));
2739 405278 : InterpolateArray1D<Double, Float>::interpolate(youtf, youtFlags, xout[iDone],
2740 : xindd, yinf, yinFlags,
2741 : methodF, false, doExtrapolate);
2742 405278 : WEIGHT_SPECTRUMCol.put(mainTabRow, youtf * weightScaleV[iDone]); // an approximation
2743 : }
2744 :
2745 :
2746 427313 : SIGMACol.put(mainTabRow, SIGMACol(mainTabRow)*sigmaScaleV[iDone]);
2747 427313 : WEIGHTCol.put(mainTabRow, WEIGHTCol(mainTabRow)*weightScaleV[iDone]);
2748 :
2749 :
2750 : // deal with FLAG_CATEGORY
2751 : // note: FLAG_CATEGORY is a required column, but it can be undefined (empty)
2752 :
2753 427313 : if(FLAG_CATEGORYCol.isDefined(mainTabRow)){
2754 0 : Array<Bool> flagCat((*oldFLAG_CATEGORYColP)(mainTabRow));
2755 0 : IPosition flagCatShape = (*oldFLAG_CATEGORYColP).shape(mainTabRow);
2756 0 : Int nCorrelations = flagCatShape(0); // get the dimension of the first axis
2757 0 : Int nChannels = flagCatShape(1); // get the dimension of the second axis
2758 0 : Int nCat = flagCatShape(2); // the dimension of the third axis ==
2759 : // number of categories
2760 0 : Int nOutChannels = xout[iDone].size();
2761 :
2762 0 : Vector<Float> dummyYin(nChannels);
2763 0 : Vector<Float> dummyYout(nOutChannels);
2764 0 : Array<Bool> flagCatOut(IPosition(3, nCorrelations, nOutChannels, nCat));
2765 :
2766 0 : for(Int i=0; i<nCat; i++){
2767 0 : IPosition start(0,0,i), length (nCorrelations,nChannels,i), stride (1,1,0);
2768 0 : Slicer slicer (start, length, stride, Slicer::endIsLast);
2769 0 : yinFlags.assign(flagCat(slicer));
2770 0 : InterpolateArray1D<Double, Float>::interpolate(dummyYout, youtFlags,
2771 0 : xout[iDone], xindd,
2772 : dummyYin, yinFlags,
2773 : methodF, false, false);
2774 : // write the slice to the array flagCatOut
2775 0 : for(Int j=0; j<nCorrelations; j++){
2776 0 : for(Int k=0; k<nOutChannels; k++){
2777 0 : flagCatOut(IPosition(3, j, k, i)) = youtFlags(IPosition(2,j,k));
2778 : }
2779 : }
2780 0 : }
2781 :
2782 0 : FLAG_CATEGORYCol.put(mainTabRow, flagCatOut);
2783 :
2784 0 : }
2785 :
2786 427313 : msModified = true;
2787 :
2788 427313 : } // end if regridding necessary
2789 :
2790 427313 : if(mainTabRow>nMainTabRows*progress){
2791 172 : cout << "regridSpw progress: " << progress*100 << "% processed ... " << endl;
2792 172 : progress += progressStep;
2793 : }
2794 :
2795 427313 : } // end loop over main table rows
2796 45 : cout << "regridSpw progress: 100% processed." << endl;
2797 :
2798 45 : if(msModified){
2799 45 : if(needRegridding){
2800 :
2801 : // remove the "partner" columns
2802 45 : if(!CORRECTED_DATACol.isNull()){
2803 18 : ms_p.removeColumn("oldCORRECTED_DATA");
2804 : }
2805 45 : if(!DATACol.isNull()){
2806 45 : ms_p.removeColumn("oldDATA");
2807 : }
2808 45 : if(!FLOAT_DATACol.isNull()){
2809 0 : ms_p.removeColumn("oldFLOAT_DATA");
2810 : }
2811 45 : if(!LAG_DATACol.isNull()){
2812 0 : ms_p.removeColumn("oldLAG_DATA");
2813 : }
2814 45 : if(!MODEL_DATACol.isNull()){
2815 17 : ms_p.removeColumn("oldMODEL_DATA");
2816 : }
2817 45 : if(!SIGMA_SPECTRUMCol.isNull()){
2818 2 : ms_p.removeColumn("oldSIGMA_SPECTRUM");
2819 : }
2820 45 : if(!WEIGHT_SPECTRUMCol.isNull()){
2821 45 : ms_p.removeColumn("oldWEIGHT_SPECTRUM");
2822 : }
2823 45 : if(!FLAGCol.isNull()){
2824 45 : ms_p.removeColumn("oldFLAG");
2825 : }
2826 45 : if(!FLAG_CATEGORYCol.isNull()){
2827 45 : ms_p.removeColumn("oldFLAG_CATEGORY");
2828 : }
2829 : }
2830 :
2831 45 : rval = 1; // successful modification
2832 : }
2833 45 : return rval;
2834 :
2835 54 : }
2836 :
2837 :
2838 405 : Bool SubMS::createPartnerColumn(TableDesc& modMSTD,
2839 : const String& oldName,
2840 : const String& newName,
2841 : const Int& hypercolumnDim,
2842 : const IPosition& tileShape
2843 : ){
2844 405 : Bool rval = false;
2845 405 : if(modMSTD.isColumn(oldName)){
2846 : // get the old column desc
2847 217 : ColumnDesc myColDesc(modMSTD.columnDesc(oldName));
2848 : // move the column away
2849 217 : ms_p.renameColumn(newName, oldName);
2850 : // rename the hypercolumn
2851 217 : String hcName(myColDesc.dataManagerGroup());
2852 217 : String oldHcName = hcName;
2853 217 : String newHcName = hcName + "B";
2854 217 : if(!oldHcName.empty() && ms_p.actualTableDesc().isHypercolumn(oldHcName)){
2855 203 : ms_p.renameHypercolumn(newHcName, oldHcName);
2856 : }
2857 : // rename the datamanager
2858 217 : DataManager* myDM = ms_p.findDataManager(oldHcName);
2859 217 : ((TiledStMan*) myDM)->setDataManagerName(newHcName);
2860 : // create new hypercolumn and a new column with new data manager
2861 217 : TiledShapeStMan* tiledStMan = new TiledShapeStMan(oldHcName, tileShape);
2862 217 : ms_p.addColumn(myColDesc, *tiledStMan);
2863 217 : modMSTD.defineHypercolumn(oldHcName, hypercolumnDim, stringToVector(oldName));
2864 :
2865 217 : rval = true;
2866 217 : }
2867 405 : return rval;
2868 : }
2869 :
2870 :
2871 1356 : Bool SubMS::regridChanBounds(Vector<Double>& newChanLoBound,
2872 : Vector<Double>& newChanHiBound,
2873 : const Double regridCenterC,
2874 : const Double regridBandwidth,
2875 : const Double regridChanWidthC,
2876 : const Double regridVeloRestfrq,
2877 : const String regridQuant,
2878 : const Vector<Double>& transNewXinC,
2879 : const Vector<Double>& transCHAN_WIDTHC,
2880 : String& message,
2881 : const Bool centerIsStartC,
2882 : const Bool startIsEndC,
2883 : const Int nchanC,
2884 : const Int width,
2885 : const Int startC
2886 : ){
2887 1356 : ostringstream oss;
2888 :
2889 : // cout << "regridCenterC " << regridCenterC << " regridBandwidth " << regridBandwidth
2890 : // << " regridChanWidthC " << regridChanWidthC << endl;
2891 : // cout << " nchanC " << nchanC << " width " << width << " startC " << startC << endl;
2892 : // cout << " regridQuant " << regridQuant << " centerIsStartC " << centerIsStartC << " startIsEndC " << startIsEndC << endl;
2893 :
2894 :
2895 1356 : Vector<Double> transNewXin(transNewXinC);
2896 1356 : Vector<Double> transCHAN_WIDTH(transCHAN_WIDTHC);
2897 1356 : Bool centerIsStart = centerIsStartC;
2898 1356 : Bool startIsEnd = startIsEndC;
2899 1356 : Double regridChanWidth = regridChanWidthC;
2900 1356 : Double regridCenter = regridCenterC;
2901 1356 : Int nchan = nchanC;
2902 1356 : Int start = startC;
2903 :
2904 1356 : Int oldNUM_CHAN = transNewXin.size();
2905 :
2906 :
2907 : // detect spectral windows defined with descending frequency
2908 1356 : Bool isDescending=false;
2909 397234 : for(uInt i=1; i<transNewXin.size(); i++){
2910 395878 : if(transNewXin(i)<transNewXin(i-1)){
2911 18404 : isDescending = true;
2912 : }
2913 377474 : else if(isDescending){ // i.e. descending was detected but now we encounter ascending
2914 0 : oss << "Channel frequencies are neither in ascending nor in descending order. Cannot process.";
2915 0 : message = oss.str();
2916 0 : return false;
2917 : }
2918 : }
2919 :
2920 1356 : if(isDescending){ // need to reverse the order for processing and later reverse the result
2921 : //cout << "SPW has descending order ..." << endl;
2922 28 : uInt n = transNewXin.size();
2923 28 : Vector<Double> tempF, tempW;
2924 28 : tempF.assign(transNewXin);
2925 28 : tempW.assign(transCHAN_WIDTH);
2926 18460 : for(uInt i=0; i<n; i++){
2927 18432 : transNewXin(i) = tempF(n-1-i);
2928 18432 : transCHAN_WIDTH(i) = tempW(n-1-i);
2929 : //cout << "i f w " << i << " " << transNewXin(i) << " " << transCHAN_WIDTH(i) << endl;
2930 : }
2931 : // also need to adjust the start values
2932 28 : if(startC>=0){
2933 25 : start = n-1-startC;
2934 25 : if(centerIsStartC){
2935 25 : startIsEnd = !startIsEnd;
2936 : }
2937 : }
2938 : //}
2939 28 : }
2940 :
2941 : // verify regridCenter, regridBandwidth, and regridChanWidth
2942 : // Note: these are in the units corresponding to regridQuant!
2943 :
2944 1356 : if(regridQuant=="chan"){ ////////////////////////
2945 : // channel numbers ...
2946 3 : Int regridCenterChan = -1;
2947 3 : Int regridBandwidthChan = -1;
2948 3 : Int regridChanWidthChan = -1;
2949 :
2950 3 : if(regridCenter<-1E30){ // not set
2951 : // find channel center closest to center of bandwidth
2952 0 : lDouble BWCenterF = (transNewXin[0]+transNewXin[oldNUM_CHAN-1])/2.;
2953 0 : for(Int i=0; i<oldNUM_CHAN; i++){
2954 0 : if(transNewXin[i] >= BWCenterF){
2955 0 : regridCenterChan = i;
2956 0 : break;
2957 : }
2958 : }
2959 0 : centerIsStart = false;
2960 : }
2961 3 : else if(0. <= regridCenter && regridCenter < Double(oldNUM_CHAN)){ // valid input
2962 3 : regridCenterChan = (Int) floor(regridCenter);
2963 : }
2964 : else { // invalid
2965 0 : if(centerIsStart){
2966 0 : oss << "SPW start ";
2967 : }
2968 : else{
2969 0 : oss << "SPW center ";
2970 : }
2971 0 : oss << regridCenter << " outside valid range which is "
2972 0 : << 0 << " - " << oldNUM_CHAN-1 <<".";
2973 0 : message = oss.str();
2974 0 : return false;
2975 : }
2976 :
2977 3 : if(regridBandwidth<=0.|| nchan>0){ // not set or nchan set
2978 3 : if(nchan>0){
2979 0 : regridBandwidthChan = nchan;
2980 : }
2981 : else{
2982 3 : regridBandwidthChan = oldNUM_CHAN;
2983 : }
2984 : }
2985 : else{
2986 0 : regridBandwidthChan = (Int) floor(regridBandwidth);
2987 : }
2988 :
2989 3 : if(centerIsStart){
2990 3 : if(startIsEnd){
2991 0 : regridCenterChan = regridCenterChan - regridBandwidthChan/2;
2992 : }
2993 : else{
2994 3 : regridCenterChan = regridCenterChan + regridBandwidthChan/2;
2995 : }
2996 3 : centerIsStart = false;
2997 : }
2998 :
2999 3 : if(regridCenterChan-regridBandwidthChan/2 < 0) { // center too close to lower edge
3000 0 : regridBandwidthChan = 2 * regridCenterChan + 1;
3001 0 : oss << " *** Requested output SPW width too large." << endl;
3002 : }
3003 3 : if( oldNUM_CHAN < regridCenterChan+regridBandwidthChan/2){ // center too close to upper edge
3004 0 : regridBandwidthChan = 2*(oldNUM_CHAN - regridCenterChan);
3005 0 : oss << " *** Requested output SPW width too large." << endl;
3006 : }
3007 :
3008 3 : if(regridChanWidth < 1.){
3009 0 : regridChanWidthChan = 1;
3010 : }
3011 3 : else if(regridChanWidth > Double(regridBandwidthChan)){
3012 0 : regridChanWidthChan = regridBandwidthChan; // i.e. SPW = a single channel
3013 0 : oss << " *** Requested output channel width too large. Adjusted to maximum possible value." << endl;
3014 : }
3015 : else { // valid input
3016 3 : regridChanWidthChan = (Int) floor(regridChanWidth);
3017 3 : if(nchan>0){
3018 0 : regridBandwidthChan = nchan * regridChanWidthChan;
3019 : }
3020 : }
3021 :
3022 3 : if(regridBandwidthChan != floor(regridBandwidth)){
3023 3 : oss << " *** Output SPW width set to " << regridBandwidthChan << " original channels" << endl;
3024 3 : oss << " in an attempt to keep center of output SPW close to center of requested SPW." << endl;
3025 : }
3026 :
3027 : // calculate newChanLoBound and newChanHiBound from regridCenterChan, regridBandwidthChan, and regridChanWidthChan
3028 3 : Int bwLowerEndChan = regridCenterChan - regridBandwidthChan/2;
3029 3 : Int bwUpperEndChan = bwLowerEndChan + regridBandwidthChan - 1;
3030 3 : Int numNewChanDown = 0;
3031 3 : Int numNewChanUp = 0;
3032 :
3033 3 : if(regridChanWidthChan == regridBandwidthChan){ // only one new channel
3034 0 : newChanLoBound.resize(1);
3035 0 : newChanHiBound.resize(1);
3036 0 : newChanLoBound[0] = transNewXin[bwLowerEndChan]-transCHAN_WIDTH[bwLowerEndChan]/2.;
3037 0 : newChanHiBound[0] = transNewXin[bwUpperEndChan]+transCHAN_WIDTH[bwUpperEndChan]/2.;
3038 0 : numNewChanUp = 1;
3039 : }
3040 : else { // have more than one new channel
3041 : // Need to accomodate the possibility that the original channels are
3042 : // not contiguous!
3043 :
3044 : // the numbers of the Channels from which the lower bounds will be taken for the new channels
3045 3 : vector<Int> loNCBup;
3046 : // starting from the central channel going up
3047 3 : vector<Int> hiNCBup; // the numbers of the Channels from which the high
3048 : // bounds will be taken for the new channels
3049 : // starting from the central channel going up
3050 3 : vector<Int> loNCBdown; // the numbers of the Channels from which the
3051 : // lower bounds will be taken for the new
3052 : // channels
3053 : // starting from the central channel going down
3054 3 : vector<Int> hiNCBdown; // the numbers of the Channels from which the
3055 : // high bounds will be taken for the new
3056 : // channels
3057 : // starting from the central channel going down
3058 : // Want to keep the center of the center channel at the center of
3059 : // the new center channel if the bandwidth is an odd multiple of the
3060 : // new channel width
3061 : // otherwise the center channel is the lower edge of the new center channel
3062 : Int startChan;
3063 3 : lDouble tnumChan = regridBandwidthChan/regridChanWidthChan;
3064 3 : if((Int)tnumChan % 2 != 0 ){
3065 : // odd multiple
3066 3 : startChan = regridCenterChan-regridChanWidthChan/2;
3067 : }
3068 : else{
3069 0 : startChan = regridCenterChan;
3070 : }
3071 3642 : for(Int i=startChan; i<=bwUpperEndChan; i+=regridChanWidthChan){ // upper half
3072 3639 : loNCBup.push_back(i);
3073 3639 : if(i+regridChanWidthChan-1<=bwUpperEndChan){
3074 : // can go one more normal step up
3075 3639 : hiNCBup.push_back(i+regridChanWidthChan-1);
3076 : }
3077 : else{
3078 : // create narrower channels at the edges if necessary
3079 0 : oss << " *** Last channel at upper edge of new SPW made only " << bwUpperEndChan-i+1
3080 0 : << " original channels wide to fit given total bandwidth." << endl;
3081 0 : hiNCBup.push_back(bwUpperEndChan);
3082 : }
3083 : }
3084 :
3085 : // lower half
3086 3639 : for(Int i=startChan - 1; i>=bwLowerEndChan; i-=regridChanWidthChan){
3087 3636 : hiNCBdown.push_back(i);
3088 3636 : if(i-regridChanWidthChan+1>=bwLowerEndChan){
3089 : // can go one more normal step down
3090 3636 : loNCBdown.push_back(i-regridChanWidthChan+1);
3091 : }
3092 : else{
3093 : // create narrower channels at the edges if necessary
3094 0 : oss << " *** First channel at lower edge of new SPW made only " << i-bwLowerEndChan+1
3095 0 : << " original channels wide to fit given total bandwidth." << endl;
3096 0 : loNCBdown.push_back(bwLowerEndChan);
3097 : }
3098 : }
3099 :
3100 : // the number of channels below the central one
3101 3 : numNewChanDown = loNCBdown.size();
3102 :
3103 : // the number of channels above and including the central one
3104 3 : numNewChanUp = loNCBup.size();
3105 :
3106 3 : newChanLoBound.resize(numNewChanDown+numNewChanUp);
3107 3 : newChanHiBound.resize(numNewChanDown+numNewChanUp);
3108 3639 : for(Int i=0; i<numNewChanDown; i++){
3109 3636 : Int k = numNewChanDown-i-1; // need to assign in reverse
3110 3636 : newChanLoBound[i] = transNewXin[loNCBdown[k]] -
3111 3636 : transCHAN_WIDTH[loNCBdown[k]]/2.;
3112 7272 : newChanHiBound[i] = transNewXin[hiNCBdown[k]] +
3113 3636 : transCHAN_WIDTH[hiNCBdown[k]]/2.;
3114 : }
3115 3642 : for(Int i=0; i<numNewChanUp; i++){
3116 3639 : newChanLoBound[i+numNewChanDown] = transNewXin[loNCBup[i]] -
3117 3639 : transCHAN_WIDTH[loNCBup[i]]/2.;
3118 7278 : newChanHiBound[i+numNewChanDown] = transNewXin[hiNCBup[i]] +
3119 3639 : transCHAN_WIDTH[hiNCBup[i]]/2.;
3120 : }
3121 3 : } // end if
3122 :
3123 3 : oss << " New channels defined based on original channels" << endl
3124 3 : << " Central channel contains original channel " << regridCenterChan << endl
3125 3 : << " Channel width = " << regridChanWidthChan
3126 3 : << " original channels" << endl
3127 3 : << " Total width of SPW = " << regridBandwidthChan << " original channels == "
3128 3 : << numNewChanDown + numNewChanUp << " new channels" << endl;
3129 :
3130 3 : uInt nc = newChanLoBound.size();
3131 3 : oss << " Total width of SPW (in output frame) = " << newChanHiBound[nc-1] - newChanLoBound[0]
3132 3 : << " Hz" << endl;
3133 3 : oss << " Lower edge = " << newChanLoBound[0] << " Hz,"
3134 3 : << " upper edge = " << newChanHiBound[nc-1] << " Hz" << endl;
3135 :
3136 3 : if(isDescending){
3137 0 : Vector<Double> tempL, tempU;
3138 0 : tempL.assign(newChanLoBound);
3139 0 : tempU.assign(newChanHiBound);
3140 0 : for(uInt i=0; i<nc; i++){
3141 0 : newChanLoBound(i) = tempL(nc-1-i);
3142 0 : newChanHiBound(i) = tempU(nc-1-i);
3143 : }
3144 0 : }
3145 :
3146 3 : message = oss.str();
3147 :
3148 3 : return true;
3149 : }
3150 : else { // we operate on real numbers /////////////////
3151 : // first transform them to frequencies
3152 1353 : lDouble regridCenterF = -1.; // initialize as "not set"
3153 1353 : lDouble regridBandwidthF = -1.;
3154 1353 : lDouble regridChanWidthF = -1.;
3155 :
3156 1353 : if(regridQuant=="vrad"){ ///////////////
3157 : // radio velocity ...
3158 : // need restfrq
3159 66 : if(regridVeloRestfrq<-1E30){ // means "not set"
3160 0 : oss << "Parameter \"restfreq\" needs to be set if regrid_quantity==vrad. Cannot proceed with regridSpw ...";
3161 0 : message = oss.str();
3162 0 : return false;
3163 : }
3164 66 : else if(regridVeloRestfrq < 0. || regridVeloRestfrq > 1E30){
3165 0 : oss << "Parameter \"restfreq\" value " << regridVeloRestfrq << " is invalid.";
3166 0 : message = oss.str();
3167 0 : return false;
3168 : }
3169 : lDouble regridCenterVel;
3170 66 : if(regridCenter>-C::c){
3171 : // (we deal with invalid values later)
3172 54 : if(centerIsStart){
3173 : Double tcWidth;
3174 54 : if(regridChanWidth > 0.){
3175 54 : tcWidth = regridChanWidth;
3176 : }
3177 : else{
3178 0 : tcWidth = vrad(transNewXin[0]-transCHAN_WIDTH[0]/2.,regridVeloRestfrq)
3179 0 : - vrad(transNewXin[0]+transCHAN_WIDTH[0]/2.,regridVeloRestfrq);
3180 : }
3181 54 : if(startIsEnd){ // start is the center of the last channel (in freq)
3182 51 : regridCenter -= tcWidth/2.;
3183 : }
3184 : else{ // start is the center of the first channel (in freq)
3185 3 : regridCenter += tcWidth/2.;
3186 : }
3187 : }
3188 :
3189 54 : regridCenterF = freq_from_vrad(regridCenter,regridVeloRestfrq);
3190 :
3191 54 : regridCenterVel = regridCenter;
3192 : }
3193 : else{ // center was not specified
3194 12 : regridCenterF = (transNewXin[0]+transNewXin[oldNUM_CHAN-1])/2.;
3195 12 : regridCenterVel = vrad(regridCenterF,regridVeloRestfrq);
3196 12 : centerIsStart = false;
3197 : }
3198 66 : if(nchan>0){
3199 60 : if(regridChanWidth > 0.){
3200 54 : lDouble chanUpperEdgeF = freq_from_vrad(regridCenterVel - regridChanWidth/2.,
3201 : regridVeloRestfrq);
3202 54 : regridChanWidthF = 2.* (chanUpperEdgeF - regridCenterF);
3203 : }
3204 : else{ // take channel width from first channel
3205 6 : regridChanWidthF = transCHAN_WIDTH[0];
3206 : }
3207 60 : regridBandwidthF = nchan*regridChanWidthF;
3208 : // can convert start to center
3209 60 : if(centerIsStart){
3210 54 : if(startIsEnd){
3211 51 : regridCenterF = regridCenterF - regridBandwidthF/2.;
3212 : }
3213 : else{
3214 3 : regridCenterF = regridCenterF + regridBandwidthF/2.;
3215 : }
3216 54 : centerIsStart = false;
3217 : }
3218 : }
3219 6 : else if(regridBandwidth > 0.){
3220 : // can convert start to center
3221 0 : if(centerIsStart){
3222 0 : if(startIsEnd){
3223 0 : regridCenterVel = regridCenter + regridBandwidth/2.;
3224 : }
3225 : else{
3226 0 : regridCenterVel = regridCenter - regridBandwidth/2.;
3227 : }
3228 0 : regridCenterF = freq_from_vrad(regridCenterVel,regridVeloRestfrq);
3229 0 : centerIsStart = false;
3230 : }
3231 0 : lDouble bwUpperEndF = freq_from_vrad(regridCenterVel - regridBandwidth/2.,
3232 : regridVeloRestfrq);
3233 0 : regridBandwidthF = 2.* (bwUpperEndF - regridCenterF);
3234 : }
3235 66 : if(regridChanWidth > 0. && regridChanWidthF<0.){
3236 3 : lDouble chanUpperEdgeF = freq_from_vrad(regridCenterVel - regridChanWidth/2.,
3237 : regridVeloRestfrq);
3238 3 : regridChanWidthF = 2.* (chanUpperEdgeF - freq_from_vrad(regridCenterVel, regridVeloRestfrq));
3239 : }
3240 : }
3241 1287 : else if(regridQuant=="vopt"){ ///////////
3242 : // optical velocity ...
3243 : // need restfrq
3244 13 : if(regridVeloRestfrq < -1E30){ // means "not set"
3245 0 : oss << "Parameter \"restfreq\" needs to be set if regrid_quantity==vopt. Cannot proceed with regridSpw ...";
3246 0 : message = oss.str();
3247 0 : return false;
3248 : }
3249 13 : else if(regridVeloRestfrq <= 0. || regridVeloRestfrq > 1E30){
3250 0 : oss << "Parameter \"restfreq\" value " << regridVeloRestfrq
3251 0 : << " is invalid.";
3252 0 : message = oss.str();
3253 0 : return false;
3254 : }
3255 : lDouble regridCenterVel;
3256 13 : if(regridCenter > -C::c){
3257 12 : if(centerIsStart){
3258 : Double tcWidth;
3259 12 : if(regridChanWidth > 0.){
3260 12 : tcWidth = regridChanWidth;
3261 : }
3262 : else{
3263 0 : tcWidth = vopt(transNewXin[0]-transCHAN_WIDTH[0]/2.,regridVeloRestfrq)
3264 0 : - vopt(transNewXin[0]+transCHAN_WIDTH[0]/2.,regridVeloRestfrq);
3265 : }
3266 12 : if(startIsEnd){ // start is the center of the last channel (in freq)
3267 9 : regridCenter -= tcWidth/2.;
3268 : }
3269 : else{ // start is the center of the first channel (in freq)
3270 3 : regridCenter += tcWidth/2.;
3271 : }
3272 : }
3273 : // (we deal with invalid values later)
3274 12 : regridCenterF = freq_from_vopt(regridCenter,regridVeloRestfrq);
3275 12 : regridCenterVel = regridCenter;
3276 : }
3277 : else{ // center was not specified
3278 1 : regridCenterF = (transNewXin[0]-transCHAN_WIDTH[0]+transNewXin[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1])/2.;
3279 1 : regridCenterVel = vopt(regridCenterF,regridVeloRestfrq);
3280 1 : centerIsStart = false;
3281 : }
3282 13 : if(nchan>0){
3283 : lDouble cw;
3284 12 : lDouble divbytwo = 0.5;
3285 12 : if(centerIsStart){
3286 12 : divbytwo = 1.;
3287 : }
3288 12 : if(regridChanWidth > 0.){
3289 12 : cw = regridChanWidth;
3290 : }
3291 : else{ // determine channel width from first channel
3292 0 : lDouble upEdge = vopt(transNewXin[0]-transCHAN_WIDTH[0],regridVeloRestfrq);
3293 0 : lDouble loEdge = vopt(transNewXin[0]+transCHAN_WIDTH[0],regridVeloRestfrq);
3294 0 : cw = abs(upEdge-loEdge);
3295 : }
3296 12 : lDouble bwUpperEndF = 0.;
3297 12 : if(centerIsStart && !startIsEnd){ // start is end in velocity
3298 3 : bwUpperEndF = freq_from_vopt(regridCenterVel - (lDouble)nchan*cw*divbytwo,
3299 : regridVeloRestfrq);
3300 : }
3301 : else{
3302 9 : bwUpperEndF = freq_from_vopt(regridCenterVel + (lDouble)nchan*cw*divbytwo,
3303 : regridVeloRestfrq);
3304 : }
3305 12 : regridBandwidthF = abs(bwUpperEndF-regridCenterF)/divbytwo;
3306 : // can convert start to center
3307 12 : if(centerIsStart){
3308 12 : if(startIsEnd){
3309 9 : regridCenterVel = regridCenterVel + (lDouble)nchan*cw/2.;
3310 : }
3311 : else{
3312 3 : regridCenterVel = regridCenterVel - (lDouble)nchan*cw/2.;
3313 : }
3314 12 : regridCenterF = freq_from_vopt(regridCenterVel,regridVeloRestfrq);
3315 12 : centerIsStart = false;
3316 : }
3317 12 : nchan=0; // indicate that nchan should not be used in the following
3318 : }
3319 1 : else if(regridBandwidth > 0.){
3320 : // can convert start to center
3321 0 : if(centerIsStart){
3322 0 : if(startIsEnd){
3323 0 : regridCenterVel = regridCenter + regridBandwidth/2.;
3324 : }
3325 : else{
3326 0 : regridCenterVel = regridCenter - regridBandwidth/2.;
3327 : }
3328 0 : regridCenterF = freq_from_vopt(regridCenterVel,regridVeloRestfrq);
3329 0 : centerIsStart = false;
3330 : }
3331 0 : lDouble bwUpperEndF = freq_from_vopt(regridCenterVel - regridBandwidth/2.,
3332 : regridVeloRestfrq);
3333 0 : regridBandwidthF = 2.* (bwUpperEndF- regridCenterF);
3334 : }
3335 13 : if(regridChanWidth > 0. && regridChanWidthF<0.){
3336 12 : lDouble chanUpperEdgeF = freq_from_vopt(regridCenterVel - regridChanWidth/2.,
3337 : regridVeloRestfrq);
3338 12 : regridChanWidthF = 2.* (chanUpperEdgeF - freq_from_vopt(regridCenterVel,regridVeloRestfrq));
3339 : }
3340 : }
3341 1274 : else if(regridQuant=="freq"){ ////////////////////////
3342 1274 : if(width>0){ // width parameter overrides regridChanWidth
3343 1194 : regridChanWidth = width*transCHAN_WIDTH[0];
3344 : }
3345 1274 : if(start>=0){
3346 1206 : Int firstChan = start;
3347 1206 : if(start >= (Int)transNewXin.size()){
3348 0 : oss << " *** Parameter start exceeds total number of channels which is "
3349 0 : << transNewXin.size() << ". Set to 0." << endl;
3350 0 : firstChan = 0;
3351 0 : startIsEnd = false;
3352 : }
3353 1206 : if(startIsEnd){
3354 28 : regridCenter = transNewXin[firstChan]+transCHAN_WIDTH[firstChan]/2.;
3355 : }
3356 : else{
3357 1178 : regridCenter = transNewXin[firstChan]-transCHAN_WIDTH[firstChan]/2.;
3358 : }
3359 1206 : centerIsStart = true;
3360 : }
3361 : else{
3362 68 : if(centerIsStart){ // start is the center of the first channel
3363 : Double tcWidth;
3364 68 : if(regridChanWidth > 0.){
3365 61 : tcWidth = regridChanWidth;
3366 : }
3367 : else{
3368 7 : tcWidth = transCHAN_WIDTH[0];
3369 : }
3370 68 : if(startIsEnd){
3371 6 : regridCenter += tcWidth/2.;
3372 : }
3373 : else{
3374 62 : regridCenter -= tcWidth/2.;
3375 : }
3376 : }
3377 : }
3378 1274 : regridCenterF = regridCenter;
3379 1274 : regridBandwidthF = regridBandwidth;
3380 1274 : regridChanWidthF = regridChanWidth;
3381 : }
3382 0 : else if(regridQuant=="wave"){ ///////////////////////
3383 : // wavelength ...
3384 : lDouble regridCenterWav;
3385 0 : if(regridCenter > 0.){
3386 0 : if(centerIsStart){
3387 : Double tcWidth;
3388 0 : if(regridChanWidth > 0.){
3389 0 : tcWidth = regridChanWidth;
3390 : }
3391 : else{
3392 0 : tcWidth = lambda(transNewXin[0]-transCHAN_WIDTH[0]/2.)
3393 0 : - lambda(transNewXin[0]+transCHAN_WIDTH[0]/2.);
3394 : }
3395 0 : if(startIsEnd){ // start is the center of the last channel (in freq)
3396 0 : regridCenter -= tcWidth/2.;
3397 : }
3398 : else{ // start is the center of the first channel (in freq)
3399 0 : regridCenter += tcWidth/2.;
3400 : }
3401 : }
3402 0 : regridCenterF = freq_from_lambda(regridCenter);
3403 0 : regridCenterWav = regridCenter;
3404 : }
3405 : else{ // center was not specified
3406 0 : regridCenterF = (transNewXin[0] + transNewXin[oldNUM_CHAN-1])/2.;
3407 0 : regridCenterWav = lambda(regridCenterF);
3408 0 : centerIsStart = false;
3409 : }
3410 0 : if(nchan>0){
3411 : lDouble cw;
3412 0 : lDouble divbytwo = 0.5;
3413 0 : if(centerIsStart){
3414 0 : divbytwo = 1.;
3415 : }
3416 0 : if(regridChanWidth > 0.){
3417 0 : cw = regridChanWidth;
3418 : }
3419 : else{ // determine channel width from first channel
3420 0 : lDouble upEdge = lambda(transNewXin[0]-transCHAN_WIDTH[0]);
3421 0 : lDouble loEdge = lambda(transNewXin[0]+transCHAN_WIDTH[0]);
3422 0 : cw = abs(upEdge-loEdge);
3423 : }
3424 0 : lDouble bwUpperEndF = 0.;
3425 0 : if(centerIsStart && !startIsEnd){
3426 0 : bwUpperEndF = freq_from_lambda(regridCenterWav - (lDouble)nchan*cw*divbytwo);
3427 : }
3428 : else{
3429 0 : bwUpperEndF = freq_from_lambda(regridCenterWav + (lDouble)nchan*cw*divbytwo);
3430 : }
3431 0 : regridBandwidthF = (bwUpperEndF-regridCenterF)/divbytwo;
3432 : // can convert start to center
3433 0 : if(centerIsStart){
3434 0 : if(startIsEnd){
3435 0 : regridCenterWav = regridCenterWav + (lDouble)nchan*cw/2.;
3436 : }
3437 : else{
3438 0 : regridCenterWav = regridCenterWav - (lDouble)nchan*cw/2.;
3439 : }
3440 0 : regridCenterF = freq_from_lambda(regridCenterWav);
3441 0 : centerIsStart = false;
3442 : }
3443 0 : nchan=0; // indicate that nchan should not be used in the following
3444 : }
3445 0 : else if(regridBandwidth > 0. && regridBandwidth/2. < regridCenterWav){
3446 : // can convert start to center
3447 0 : if(centerIsStart){
3448 0 : if(startIsEnd){
3449 0 : regridCenterWav = regridCenter + regridBandwidth/2.;
3450 : }
3451 : else{
3452 0 : regridCenterWav = regridCenter - regridBandwidth/2.;
3453 : }
3454 0 : regridCenterF = freq_from_lambda(regridCenterWav);
3455 0 : centerIsStart = false;
3456 : }
3457 0 : lDouble bwUpperEndF = lambda(regridCenterWav - regridBandwidth/2.);
3458 0 : regridBandwidthF = 2.* (bwUpperEndF - regridCenterF);
3459 : }
3460 0 : if(regridChanWidth>0. && regridChanWidth/2.< regridCenterWav){
3461 0 : lDouble chanUpperEdgeF = lambda(regridCenterWav - regridChanWidth/2.);
3462 0 : regridChanWidthF = 2.* (chanUpperEdgeF - regridCenterF);
3463 : }
3464 : }
3465 : else{
3466 0 : oss << "Invalid value " << regridQuant << " for parameter \"mode\".";
3467 0 : message = oss.str();
3468 0 : return false;
3469 : }
3470 : // (transformation of regrid parameters to frequencies completed)
3471 :
3472 : // then determine the actually possible parameters
3473 : lDouble theRegridCenterF;
3474 : lDouble theRegridBWF;
3475 : lDouble theCentralChanWidthF;
3476 :
3477 : // for vrad and vopt also need to keep this adjusted value
3478 1353 : lDouble theChanWidthX = -1.;
3479 :
3480 1353 : if(regridCenterF < 0.){ // means "not set"
3481 : // keep regrid center as it is in the data
3482 7 : theRegridCenterF = (transNewXin[0] - transCHAN_WIDTH[0]/2.
3483 7 : + transNewXin[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1]/2.)/2.;
3484 7 : centerIsStart = false;
3485 : }
3486 : else { // regridCenterF was set
3487 : // keep center in limits
3488 1346 : theRegridCenterF = regridCenterF;
3489 1346 : if( (theRegridCenterF - (transNewXin[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1]/2.)) > 1. ){ // 1 Hz tolerance
3490 0 : oss << "*** Requested center of SPW " << theRegridCenterF << " Hz is too large by "
3491 0 : << theRegridCenterF - transNewXin[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1]/2. << " Hz\n";
3492 0 : theRegridCenterF = transNewXin[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1]/2.;
3493 0 : oss << "*** Reset to maximum possible value " << theRegridCenterF << " Hz";
3494 : }
3495 1346 : else if( theRegridCenterF < (transNewXin[0]-transCHAN_WIDTH[0]/2.) ){
3496 15 : Double diff = (transNewXin[0]-transCHAN_WIDTH[0]/2.) - theRegridCenterF;
3497 : // cope with numerical accuracy problems
3498 15 : if(diff>1.){
3499 6 : oss << "*** Requested center of SPW " << theRegridCenterF << " Hz is smaller than minimum possible value";
3500 6 : oss << " by " << diff << " Hz";
3501 : }
3502 15 : theRegridCenterF = transNewXin[0]-transCHAN_WIDTH[0]/2.;
3503 15 : if(diff>1.){
3504 6 : oss << "\n*** Reset to minimum possible value " << theRegridCenterF << " Hz";
3505 : }
3506 : }
3507 : }
3508 1353 : if(regridBandwidthF<=0.|| nchan!=0){ // "not set" or use nchan instead
3509 : // keep bandwidth as is
3510 1341 : theRegridBWF = transNewXin[oldNUM_CHAN-1] - transNewXin[0]
3511 1341 : + transCHAN_WIDTH[0]/2. + transCHAN_WIDTH[oldNUM_CHAN-1]/2.;
3512 1341 : if(nchan!=0){ // use nchan parameter if available
3513 1341 : if(nchan<0){
3514 437 : if(regridQuant=="freq" || regridQuant=="vrad"){ // i.e. equidistant in freq
3515 : // define via width of first channel to avoid numerical problems
3516 436 : if(regridChanWidthF <= 0.){ // channel width not set
3517 4 : theRegridBWF = transCHAN_WIDTH[0]*floor((theRegridBWF+transCHAN_WIDTH[0]*0.01)/transCHAN_WIDTH[0]);
3518 : }
3519 : else{
3520 432 : theRegridBWF = regridChanWidthF*floor((theRegridBWF+regridChanWidthF*0.01)/regridChanWidthF);
3521 : }
3522 : }
3523 : }
3524 904 : else if(regridChanWidthF <= 0.){ // channel width not set
3525 18 : theRegridBWF = transCHAN_WIDTH[0]*nchan;
3526 : }
3527 : else{
3528 886 : theRegridBWF = regridChanWidthF*nchan;
3529 : }
3530 :
3531 1341 : if(regridCenterF <= 0.|| regridCenter <-C::c ){ // center was not set by user but calculated
3532 : // need to update
3533 20 : theRegridCenterF = transNewXin[0] - transCHAN_WIDTH[0]/2. + theRegridBWF/2.;
3534 20 : centerIsStart = false;
3535 : }
3536 1321 : else if(nchan<0){ // center but not nchan was set by user
3537 : // verify that the bandwidth is correct
3538 429 : if(centerIsStart){
3539 429 : if(startIsEnd){
3540 25 : theRegridBWF = theRegridCenterF - transNewXin[0] + transCHAN_WIDTH[0]/2.;
3541 : }
3542 : else{ // start is start
3543 404 : theRegridBWF = transNewXin[oldNUM_CHAN-1] + transCHAN_WIDTH[oldNUM_CHAN-1]/2. - theRegridCenterF;
3544 : }
3545 429 : if(regridQuant=="freq" || regridQuant=="vrad"){ // i.e. equidistant in freq
3546 : // define via width of first channel to avoid numerical problems
3547 429 : if(regridChanWidthF <= 0.){ // channel width not set
3548 0 : theRegridBWF = transCHAN_WIDTH[0]*floor((theRegridBWF+transCHAN_WIDTH[0]*0.01)/transCHAN_WIDTH[0]);
3549 : }
3550 : else{
3551 429 : theRegridBWF = regridChanWidthF*floor((theRegridBWF+regridChanWidthF*0.01)/regridChanWidthF);
3552 : }
3553 : }
3554 : }
3555 : else{ // center is center
3556 0 : theRegridBWF = 2. * min((Double)(theRegridCenterF - transNewXin[0] - transCHAN_WIDTH[0]),
3557 0 : (Double)(transNewXin[oldNUM_CHAN-1] + transCHAN_WIDTH[oldNUM_CHAN-1]
3558 0 : - theRegridCenterF));
3559 : }
3560 : }
3561 : }
3562 : // now can convert start to center
3563 1341 : if(centerIsStart){
3564 1267 : if(startIsEnd){
3565 34 : theRegridCenterF = theRegridCenterF - theRegridBWF/2.;
3566 : }
3567 : else{
3568 1233 : theRegridCenterF = theRegridCenterF + theRegridBWF/2.;
3569 : }
3570 1267 : centerIsStart = false;
3571 : }
3572 : }
3573 : else { // regridBandwidthF was set
3574 : // determine actually possible bandwidth:
3575 : // width will be truncated to the maximum width possible symmetrically
3576 : // around the value given by "regrid_center"
3577 12 : theRegridBWF = regridBandwidthF;
3578 : // now can convert start to center
3579 12 : if(centerIsStart){
3580 0 : if(startIsEnd){
3581 0 : theRegridCenterF = theRegridCenterF - theRegridBWF/2.;
3582 : }
3583 : else{
3584 0 : theRegridCenterF = theRegridCenterF + theRegridBWF/2.;
3585 : }
3586 0 : centerIsStart = false;
3587 : }
3588 : {
3589 12 : Double rangeTol = 1.; // Hz
3590 12 : if((regridQuant=="vopt" || regridQuant=="wave")){ // i.e. if the center is the center w.r.t. wavelength
3591 12 : rangeTol = transCHAN_WIDTH[0];
3592 : }
3593 12 : if((theRegridCenterF + theRegridBWF / 2.) - (transNewXin[oldNUM_CHAN-1] + transCHAN_WIDTH[oldNUM_CHAN-1]/2.) > rangeTol ){
3594 0 : oss << " *** Input spectral window exceeds upper end of original window. Adjusting to max. possible value." << endl;
3595 0 : theRegridBWF = min((Double)fabs(transNewXin[oldNUM_CHAN-1] + transCHAN_WIDTH[oldNUM_CHAN-1]/2. - theRegridCenterF),
3596 0 : (Double)fabs(theRegridCenterF - transNewXin[0] + transCHAN_WIDTH[0]/2.)) * 2.;
3597 0 : if(theRegridBWF<transCHAN_WIDTH[0]){
3598 0 : theRegridCenterF = (transNewXin[0]+transCHAN_WIDTH[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1]/2.-transCHAN_WIDTH[0]/2.)/2.;
3599 0 : theRegridBWF = transCHAN_WIDTH[oldNUM_CHAN-1]-transNewXin[0]
3600 0 : +transCHAN_WIDTH[oldNUM_CHAN-1]/2. + transCHAN_WIDTH[0]/2.;
3601 : }
3602 : }
3603 12 : if((theRegridCenterF - theRegridBWF/2.) - (transNewXin[0] - transCHAN_WIDTH[0]/2.) < -rangeTol ){
3604 0 : oss << " *** Input spectral window exceeds lower end of original window. Adjusting to max. possible value." << endl;
3605 0 : theRegridBWF = min((Double)fabs(transNewXin[oldNUM_CHAN-1] + transCHAN_WIDTH[oldNUM_CHAN-1]/2. - theRegridCenterF),
3606 0 : (Double)fabs(theRegridCenterF - transNewXin[0] + transCHAN_WIDTH[0]/2.)) * 2.;
3607 0 : if(theRegridBWF<transCHAN_WIDTH[0]){
3608 0 : theRegridCenterF = (transNewXin[0]+transCHAN_WIDTH[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1]/2.-transCHAN_WIDTH[0]/2.)/2.;
3609 0 : theRegridBWF = transCHAN_WIDTH[oldNUM_CHAN-1]-transNewXin[0]
3610 0 : +transCHAN_WIDTH[oldNUM_CHAN-1]/2. + transCHAN_WIDTH[0]/2.;
3611 : }
3612 : }
3613 : }
3614 : }
3615 1353 : if(regridChanWidthF <= 0.){ // "not set"
3616 23 : if(nchan!=0 || centerIsStartC){ // use first channel
3617 23 : theCentralChanWidthF = transCHAN_WIDTH[0];
3618 : }
3619 : else{
3620 : // keep channel width similar to the old one
3621 0 : theCentralChanWidthF = transCHAN_WIDTH[oldNUM_CHAN/2]; // use channel width from
3622 : // near central channel
3623 : }
3624 : }
3625 : else { // regridChanWidthF was set
3626 : // keep in limits
3627 1330 : theCentralChanWidthF = regridChanWidthF;
3628 1330 : if(theCentralChanWidthF>theRegridBWF){ // too large => make a single channel
3629 0 : theCentralChanWidthF = theRegridBWF;
3630 0 : oss << " *** Requested new channel width exceeds defined SPW width." << endl
3631 0 : << " Creating a single channel with the defined SPW width." << endl;
3632 : }
3633 1330 : else if(theCentralChanWidthF<transCHAN_WIDTH[0]){ // check if too small
3634 : // determine smallest channel width
3635 10 : lDouble smallestChanWidth = 1E30;
3636 10 : Int ii = 0;
3637 1610 : for(Int i=0; i<oldNUM_CHAN; i++){
3638 1600 : if(transCHAN_WIDTH[i] < smallestChanWidth){
3639 10 : smallestChanWidth = transCHAN_WIDTH[i];
3640 10 : ii = i;
3641 : }
3642 : }
3643 10 : if(theCentralChanWidthF < smallestChanWidth - 1.){ // 1 Hz tolerance to cope with numerical accuracy problems
3644 1 : oss << " *** Requested new channel width is smaller than smallest original channel width" << endl;
3645 1 : oss << " which is " << smallestChanWidth << " Hz" << endl;
3646 1 : if(regridQuant == "vrad"){
3647 0 : oss << " or " << (vrad(transNewXin[ii],regridVeloRestfrq)
3648 0 : - vrad(transNewXin[ii]+transCHAN_WIDTH[ii]/2.,regridVeloRestfrq)) * 2. << " m/s";
3649 : }
3650 1 : if(regridQuant == "vopt"){
3651 0 : oss << " or " << (vopt(transNewXin[ii],regridVeloRestfrq)
3652 0 : - vopt(transNewXin[ii]+transCHAN_WIDTH[ii]/2.,regridVeloRestfrq)) * 2. << " m/s";
3653 : }
3654 1 : message = oss.str();
3655 1 : return false;
3656 : }
3657 : else { // input channel width was OK, memorize
3658 9 : theChanWidthX = regridChanWidth;
3659 : }
3660 : }
3661 : }
3662 :
3663 1352 : oss << " Channels equidistant in " << regridQuant << endl
3664 1352 : << " Central frequency (in output frame) = " << theRegridCenterF
3665 1352 : << " Hz";
3666 1352 : if(regridQuant == "vrad"){
3667 66 : oss << " == " << vrad(theRegridCenterF, regridVeloRestfrq) << " m/s radio velocity";
3668 : }
3669 1286 : else if(regridQuant == "vopt"){
3670 13 : oss << " == " << vopt(theRegridCenterF, regridVeloRestfrq) << " m/s optical velocity";
3671 : }
3672 1273 : else if(regridQuant == "wave"){
3673 0 : oss << " == " << lambda(theRegridCenterF) << " m wavelength";
3674 : }
3675 1352 : oss << endl;
3676 :
3677 1352 : if(isDescending){
3678 28 : oss << " Channel central frequency is decreasing with increasing channel number." << endl;
3679 : }
3680 :
3681 1352 : oss << " Width of central channel (in output frame) = "
3682 1352 : << theCentralChanWidthF << " Hz";
3683 1352 : if(regridQuant == "vrad"){
3684 66 : oss << " == " << vrad(theRegridCenterF - theCentralChanWidthF, regridVeloRestfrq)
3685 66 : - vrad(theRegridCenterF, regridVeloRestfrq) << " m/s radio velocity";
3686 : }
3687 1286 : else if(regridQuant == "vopt"){
3688 13 : oss << " == " << vopt(theRegridCenterF - theCentralChanWidthF, regridVeloRestfrq)
3689 13 : - vopt(theRegridCenterF, regridVeloRestfrq) << " m/s optical velocity";
3690 : }
3691 1273 : else if(regridQuant == "wave"){
3692 0 : oss << " == " << lambda(theRegridCenterF - theCentralChanWidthF) - lambda(theRegridCenterF) << " m wavelength";
3693 : }
3694 1352 : oss << endl;
3695 :
3696 : // now calculate newChanLoBound, and newChanHiBound from
3697 : // theRegridCenterF, theRegridBWF, theCentralChanWidthF
3698 1352 : vector<lDouble> loFBup; // the lower bounds for the new channels
3699 : // starting from the central channel going up
3700 1352 : vector<lDouble> hiFBup; // the lower bounds for the new channels
3701 : // starting from the central channel going up
3702 1352 : vector<lDouble> loFBdown; // the lower bounds for the new channels
3703 : // starting from the central channel going down
3704 1352 : vector<lDouble> hiFBdown; // the lower bounds for the new channels
3705 : // starting from the central channel going down
3706 :
3707 1352 : lDouble edgeTolerance = theCentralChanWidthF*0.01; // needed to avoid numerical accuracy problems
3708 :
3709 1352 : if(regridQuant=="vrad"){
3710 : // regridding in radio velocity ...
3711 :
3712 : // create freq boundaries equidistant and contiguous in radio velocity
3713 66 : lDouble upperEndF = theRegridCenterF + theRegridBWF/2.;
3714 66 : lDouble lowerEndF = theRegridCenterF - theRegridBWF/2.;
3715 66 : lDouble upperEndV = vrad(upperEndF,regridVeloRestfrq);
3716 66 : lDouble lowerEndV = vrad(lowerEndF,regridVeloRestfrq);
3717 : lDouble velLo;
3718 : lDouble velHi;
3719 :
3720 :
3721 : // Want to keep the center of the center channel at the center of
3722 : // the new center channel if the bandwidth is an odd multiple of the
3723 : // new channel width,
3724 : // otherwise the center channel is the lower edge of the new center channel
3725 66 : lDouble tnumChan = floor((theRegridBWF+edgeTolerance)/theCentralChanWidthF);
3726 66 : if((Int)tnumChan % 2 != 0 ){
3727 : // odd multiple
3728 25 : loFBup.push_back(theRegridCenterF-theCentralChanWidthF/2.);
3729 25 : hiFBup.push_back(theRegridCenterF+theCentralChanWidthF/2.);
3730 25 : loFBdown.push_back(theRegridCenterF-theCentralChanWidthF/2.);
3731 25 : hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF/2.);
3732 : }
3733 : else{
3734 41 : loFBup.push_back(theRegridCenterF);
3735 41 : hiFBup.push_back(theRegridCenterF+theCentralChanWidthF);
3736 41 : loFBdown.push_back(theRegridCenterF);
3737 41 : hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF);
3738 : }
3739 :
3740 66 : if(theChanWidthX<0){ // cannot use original channel width in velocity units
3741 : // need to calculate back from central channel width in Hz
3742 114 : theChanWidthX = vrad(loFBup[0],
3743 57 : regridVeloRestfrq) - vrad(hiFBup[0],
3744 : regridVeloRestfrq);
3745 : }
3746 : // calc velocity corresponding to the upper end (in freq) of the last
3747 : // added channel which is the lower end of the next channel
3748 66 : velLo = vrad(hiFBup[0],regridVeloRestfrq);
3749 : // calc velocity corresponding to the upper end (in freq) of the next channel
3750 66 : velHi = velLo - theChanWidthX; // vrad goes down as freq goes up!
3751 5351 : while(upperEndV - theChanWidthX/10. < velHi){ // (preventing accuracy problems)
3752 : // calc frequency of the upper end (in freq) of the next channel
3753 5285 : lDouble freqHi = freq_from_vrad(velHi,regridVeloRestfrq);
3754 5285 : if(freqHi<=upperEndF+edgeTolerance){ // end of bandwidth not yet reached
3755 5285 : loFBup.push_back(hiFBup.back());
3756 5285 : hiFBup.push_back(freqHi);
3757 : }
3758 0 : else if(freqHi<upperEndF+edgeTolerance){
3759 0 : loFBup.push_back(hiFBup.back());
3760 0 : hiFBup.push_back(upperEndF);
3761 0 : break;
3762 : }
3763 : else{
3764 0 : break;
3765 : }
3766 : // calc velocity corresponding to the upper end (in freq) of the added channel
3767 5285 : velLo = vrad(hiFBup.back(),regridVeloRestfrq);
3768 : // calc velocity corresponding to the upper end (in freq) of the next channel
3769 5285 : velHi = velLo - theChanWidthX; // vrad goes down as freq goes up
3770 : }
3771 :
3772 : // calc velocity corresponding to the lower end (in freq) of the last
3773 : // added channel which is the upper end of the next channel
3774 66 : velHi = vrad(loFBdown[0],regridVeloRestfrq);
3775 : // calc velocity corresponding to the lower end (in freq) of the next channel
3776 66 : velLo = velHi + theChanWidthX; // vrad goes up as freq goes down!
3777 5392 : while(velLo < lowerEndV + theChanWidthX/10.){ // (preventing accuracy problems)
3778 : // calc frequency of the lower end (in freq) of the next channel
3779 5326 : lDouble freqLo = freq_from_vrad(velLo,regridVeloRestfrq);
3780 5326 : if(freqLo>=lowerEndF-edgeTolerance){ // end of bandwidth not yet reached
3781 5326 : hiFBdown.push_back(loFBdown.back());
3782 5326 : loFBdown.push_back(freqLo);
3783 : }
3784 0 : else if(freqLo>lowerEndF-edgeTolerance){
3785 0 : hiFBdown.push_back(loFBdown.back());
3786 0 : loFBdown.push_back(lowerEndF);
3787 0 : break;
3788 : }
3789 : else {
3790 0 : break;
3791 : }
3792 : // calc velocity corresponding to the upper end of the next channel
3793 5326 : velHi = vrad(loFBdown.back(),regridVeloRestfrq);
3794 : // calc velocity corresponding to the lower end (in freq) of the next channel
3795 5326 : velLo = velHi + theChanWidthX; // vrad goes up as freq goes down
3796 : }
3797 : }
3798 1286 : else if(regridQuant=="vopt"){
3799 : // regridding in optical velocity ...
3800 :
3801 : // create freq boundaries equidistant and contiguous in optical velocity
3802 13 : lDouble upperEndF = theRegridCenterF + theRegridBWF/2.;
3803 13 : lDouble lowerEndF = theRegridCenterF - theRegridBWF/2.;
3804 13 : lDouble upperEndV = vopt(upperEndF,regridVeloRestfrq);
3805 13 : lDouble lowerEndV = vopt(lowerEndF,regridVeloRestfrq);
3806 : lDouble velLo;
3807 : lDouble velHi;
3808 :
3809 : // Want to keep the center of the center channel at the center of
3810 : // the new center channel if the bandwidth is an odd multiple of the
3811 : // new channel width,
3812 : // otherwise the center channel is the lower edge of the new center
3813 : // channel
3814 :
3815 : // enlarged edge tolerance since channels non-equidistant in freq
3816 13 : lDouble tnumChan = floor((theRegridBWF+edgeTolerance)/theCentralChanWidthF);
3817 13 : if((Int)tnumChan % 2 != 0 ){
3818 : // odd multiple
3819 9 : loFBup.push_back(theRegridCenterF-theCentralChanWidthF/2.);
3820 9 : hiFBup.push_back(theRegridCenterF+theCentralChanWidthF/2.);
3821 9 : loFBdown.push_back(theRegridCenterF-theCentralChanWidthF/2.);
3822 9 : hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF/2.);
3823 : }
3824 : else{
3825 4 : loFBup.push_back(theRegridCenterF);
3826 4 : hiFBup.push_back(theRegridCenterF+theCentralChanWidthF);
3827 4 : loFBdown.push_back(theRegridCenterF);
3828 4 : hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF);
3829 : }
3830 :
3831 13 : if(theChanWidthX<0){ // cannot use original channel width in velocity units
3832 : // need to calculate back from central channel width in Hz
3833 26 : theChanWidthX = vopt(loFBup[0],
3834 13 : regridVeloRestfrq) - vopt(hiFBup[0],regridVeloRestfrq);
3835 : }
3836 : // calc velocity corresponding to the upper end (in freq) of the last
3837 : // added channel which is the lower end of the next channel
3838 13 : velLo = vopt(hiFBup[0],regridVeloRestfrq);
3839 : // calc velocity corresponding to the upper end (in freq) of the next channel
3840 13 : velHi = velLo - theChanWidthX; // vopt goes down as freq goes up!
3841 166 : while(upperEndV - velHi < theChanWidthX/10.){ // (preventing accuracy problems)
3842 : // calc frequency of the upper end (in freq) of the next channel
3843 154 : lDouble freqHi = freq_from_vopt(velHi,regridVeloRestfrq);
3844 154 : if(freqHi<=upperEndF+edgeTolerance){ // end of bandwidth not yet reached
3845 153 : loFBup.push_back(hiFBup.back());
3846 153 : hiFBup.push_back(freqHi);
3847 : }
3848 1 : else if(freqHi<upperEndF+edgeTolerance){
3849 0 : loFBup.push_back(hiFBup.back());
3850 0 : hiFBup.push_back(upperEndF);
3851 1 : break;
3852 : }
3853 : else{
3854 1 : break;
3855 : }
3856 : // calc velocity corresponding to the upper end (in freq) of the added channel
3857 153 : velLo = vopt(hiFBup.back(),regridVeloRestfrq);
3858 : // calc velocity corresponding to the upper end (in freq) of the next channel
3859 153 : velHi = velLo - theChanWidthX; // vopt goes down as freq goes up
3860 : }
3861 :
3862 : // calc velocity corresponding to the lower end (in freq) of the last
3863 : // added channel which is the upper end of the next channel
3864 13 : velHi = vopt(loFBdown[0],regridVeloRestfrq);
3865 : // calc velocity corresponding to the lower end (in freq) of the next channel
3866 13 : velLo = velHi + theChanWidthX; // vopt goes up as freq goes down!
3867 171 : while(velLo - lowerEndV < theChanWidthX/10.){ // (preventing accuracy problems)
3868 : // calc frequency of the lower end (in freq) of the next channel
3869 158 : lDouble freqLo = freq_from_vopt(velLo,regridVeloRestfrq);
3870 158 : if(freqLo>=lowerEndF-edgeTolerance){ // end of bandwidth not yet reached
3871 158 : hiFBdown.push_back(loFBdown.back());
3872 158 : loFBdown.push_back(freqLo);
3873 : }
3874 0 : else if(freqLo>lowerEndF-edgeTolerance){
3875 0 : hiFBdown.push_back(loFBdown.back());
3876 0 : loFBdown.push_back(lowerEndF);
3877 0 : break;
3878 : }
3879 : else {
3880 0 : break;
3881 : }
3882 : // calc velocity corresponding to the upper end of the next channel
3883 158 : velHi = vopt(loFBdown.back(),regridVeloRestfrq);
3884 : // calc velocity corresponding to the lower end (in freq) of the next channel
3885 158 : velLo = velHi + theChanWidthX; // vopt goes up as freq goes down
3886 : }
3887 : }
3888 1273 : else if(regridQuant=="freq"){
3889 : // regridding in frequency ...
3890 :
3891 : // create freq boundaries equidistant and contiguous in frequency
3892 1273 : lDouble upperEndF = theRegridCenterF + theRegridBWF/2.;
3893 1273 : lDouble lowerEndF = theRegridCenterF - theRegridBWF/2.;
3894 :
3895 : // Want to keep the center of the center channel at the center of
3896 : // the new center channel if the bandwidth is an odd multiple of the
3897 : // new channel width,
3898 : // otherwise the center channel is the lower edge of the new center channel
3899 1273 : lDouble tnumChan = floor((theRegridBWF+edgeTolerance)/theCentralChanWidthF);
3900 :
3901 : //cout << "theRegridBWF " << theRegridBWF << " upperEndF " << upperEndF << " lowerEndF " << lowerEndF << " tnumChan " << tnumChan << endl;
3902 :
3903 1273 : if((Int) tnumChan % 2 != 0){
3904 : // odd multiple
3905 587 : loFBup.push_back(theRegridCenterF-theCentralChanWidthF/2.);
3906 587 : hiFBup.push_back(theRegridCenterF+theCentralChanWidthF/2.);
3907 587 : loFBdown.push_back(theRegridCenterF-theCentralChanWidthF/2.);
3908 587 : hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF/2.);
3909 : }
3910 : else{
3911 686 : loFBup.push_back(theRegridCenterF);
3912 686 : hiFBup.push_back(theRegridCenterF+theCentralChanWidthF);
3913 686 : loFBdown.push_back(theRegridCenterF);
3914 686 : hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF);
3915 : }
3916 :
3917 66050 : while(hiFBup.back()< upperEndF+edgeTolerance){
3918 : // calc frequency of the upper end of the next channel
3919 66050 : lDouble freqHi = hiFBup.back() + theCentralChanWidthF;
3920 66050 : if(freqHi<=upperEndF+edgeTolerance){ // end of bandwidth not yet reached
3921 64777 : loFBup.push_back(hiFBup.back());
3922 64777 : hiFBup.push_back(freqHi);
3923 : }
3924 : else{
3925 1273 : break;
3926 : }
3927 : }
3928 :
3929 66736 : while(loFBdown.back() > lowerEndF-edgeTolerance){
3930 : // calc frequency of the lower end of the next channel
3931 66736 : lDouble freqLo = loFBdown.back() - theCentralChanWidthF;
3932 66736 : if(freqLo>=lowerEndF-edgeTolerance){ // end of bandwidth not yet reached
3933 65463 : hiFBdown.push_back(loFBdown.back());
3934 65463 : loFBdown.push_back(freqLo);
3935 : }
3936 : else {
3937 1273 : break;
3938 : }
3939 : }
3940 : }
3941 0 : else if(regridQuant=="wave"){
3942 : // regridding in wavelength ...
3943 :
3944 : // create freq boundaries equidistant and contiguous in wavelength
3945 0 : lDouble upperEndF = theRegridCenterF + theRegridBWF/2.;
3946 0 : lDouble lowerEndF = theRegridCenterF - theRegridBWF/2.;
3947 0 : lDouble upperEndL = lambda(upperEndF);
3948 0 : lDouble lowerEndL = lambda(lowerEndF);
3949 : lDouble lambdaLo;
3950 : lDouble lambdaHi;
3951 :
3952 : // Want to keep the center of the center channel at the center of
3953 : // the new center channel if the bandwidth is an odd multiple of the
3954 : // new channel width,
3955 : // otherwise the center channel is the lower edge of the new center
3956 : // channel
3957 0 : lDouble tnumChan = floor((theRegridBWF+edgeTolerance)/theCentralChanWidthF);
3958 0 : if((Int)tnumChan % 2 != 0){
3959 : // odd multiple
3960 0 : loFBup.push_back(theRegridCenterF-theCentralChanWidthF/2.);
3961 0 : hiFBup.push_back(theRegridCenterF+theCentralChanWidthF/2.);
3962 0 : loFBdown.push_back(theRegridCenterF-theCentralChanWidthF/2.);
3963 0 : hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF/2.);
3964 : }
3965 : else{
3966 0 : loFBup.push_back(theRegridCenterF);
3967 0 : hiFBup.push_back(theRegridCenterF+theCentralChanWidthF);
3968 0 : loFBdown.push_back(theRegridCenterF);
3969 0 : hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF);
3970 : }
3971 :
3972 0 : if(theChanWidthX<0){ // cannot use original channel width in wavelength units
3973 : // need to calculate back from central channel width in Hz
3974 0 : theChanWidthX = lambda(loFBup[0]) - lambda(hiFBup[0]);
3975 : }
3976 : // calc wavelength corresponding to the upper end (in freq) of the last
3977 : // added channel which is the lower end of the next channel
3978 0 : lambdaLo = lambda(hiFBup[0]);
3979 : // calc wavelength corresponding to the upper end (in freq) of the next channel
3980 0 : lambdaHi = lambdaLo - theChanWidthX; // lambda goes down as freq goes up!
3981 0 : while(upperEndL - lambdaHi < theChanWidthX/10.){ // (preventing accuracy problems)
3982 : // calc frequency of the upper end (in freq) of the next channel
3983 0 : lDouble freqHi = freq_from_lambda(lambdaHi);
3984 0 : if(freqHi<=upperEndF+edgeTolerance){ // end of bandwidth not yet reached
3985 0 : loFBup.push_back(hiFBup.back());
3986 0 : hiFBup.push_back(freqHi);
3987 : }
3988 0 : else if(freqHi<upperEndF+edgeTolerance){
3989 0 : loFBup.push_back(hiFBup.back());
3990 0 : hiFBup.push_back(upperEndF);
3991 0 : break;
3992 : }
3993 : else{
3994 0 : break;
3995 : }
3996 : // calc wavelength corresponding to the upper end (in freq) of the
3997 : // added channel
3998 0 : lambdaLo = lambda(hiFBup.back());
3999 : // calc wavelength corresponding to the upper end (in freq) of the next channel
4000 0 : lambdaHi = lambdaLo - theChanWidthX; // lambda goes down as freq goes up
4001 : }
4002 :
4003 : // calc wavelength corresponding to the lower end (in freq) of the last
4004 : // added channel which is the upper end of the next channel
4005 0 : lambdaHi = lambda(loFBdown[0]);
4006 : // calc wavelength corresponding to the lower end (in freq) of the next channel
4007 0 : lambdaLo = lambdaHi + theChanWidthX; // lambda goes up as freq goes down!
4008 0 : while(lambdaLo - lowerEndL < theChanWidthX/10.){ // (preventing accuracy problems)
4009 : // calc frequency of the lower end (in freq) of the next channel
4010 0 : lDouble freqLo = freq_from_lambda(lambdaLo);
4011 0 : if(freqLo>=lowerEndF-edgeTolerance){ // end of bandwidth not yet reached
4012 0 : hiFBdown.push_back(loFBdown.back());
4013 0 : loFBdown.push_back(freqLo);
4014 : }
4015 0 : else if(freqLo>lowerEndF-edgeTolerance){
4016 0 : hiFBdown.push_back(loFBdown.back());
4017 0 : loFBdown.push_back(lowerEndF);
4018 0 : break;
4019 : }
4020 : else {
4021 0 : break;
4022 : }
4023 : // calc wavelength corresponding to the upper end of the next channel
4024 0 : lambdaHi = lambda(loFBdown.back());
4025 : // calc wavelength corresponding to the lower end (in freq) of the next channel
4026 0 : lambdaLo = lambdaHi + theChanWidthX; // wavelength goes up as freq goes down
4027 : }
4028 :
4029 : }
4030 : else{ // should not get here
4031 0 : oss << "Invalid value " << regridQuant << " for parameter \"mode\".";
4032 0 : message = oss.str();
4033 0 : return false;
4034 : }
4035 :
4036 1352 : Int numNewChanDown = loFBdown.size();
4037 1352 : Int numNewChanUp = loFBup.size();
4038 :
4039 : // central channel contained in both vectors
4040 1352 : newChanLoBound.resize(numNewChanDown+numNewChanUp - 1);
4041 :
4042 1352 : newChanHiBound.resize(numNewChanDown+numNewChanUp - 1);
4043 73651 : for(Int i=0; i<numNewChanDown; i++){
4044 72299 : Int k = numNewChanDown-i-1; // need to assign in reverse
4045 72299 : newChanLoBound[i] = loFBdown[k];
4046 72299 : newChanHiBound[i] = hiFBdown[k];
4047 : }
4048 71567 : for(Int i=1; i<numNewChanUp; i++){ // start at 1 to omit the central channel here
4049 70215 : newChanLoBound[i+numNewChanDown-1] = loFBup[i];
4050 70215 : newChanHiBound[i+numNewChanDown-1] = hiFBup[i];
4051 : }
4052 :
4053 1352 : uInt nc = newChanLoBound.size();
4054 1352 : oss << " Number of channels = " << nc << endl;
4055 1352 : oss << " Total width of SPW (in output frame) = " << newChanHiBound[nc-1] - newChanLoBound[0]
4056 1352 : << " Hz" << endl;
4057 1352 : oss << " Lower edge = " << newChanLoBound[0] << " Hz,"
4058 1352 : << " upper edge = " << newChanHiBound[nc-1] << " Hz" << endl;
4059 :
4060 1352 : if(isDescending){ // original SPW was in reverse order; need to restore that
4061 28 : Vector<Double> tempL, tempU;
4062 28 : tempL.assign(newChanLoBound);
4063 28 : tempU.assign(newChanHiBound);
4064 18430 : for(uInt i=0; i<nc; i++){
4065 18402 : newChanLoBound(i) = tempL(nc-1-i);
4066 18402 : newChanHiBound(i) = tempU(nc-1-i);
4067 : }
4068 28 : }
4069 :
4070 1352 : message = oss.str();
4071 :
4072 1352 : return true;
4073 :
4074 1352 : } // end if (regridQuant== ...
4075 :
4076 1356 : }
4077 :
4078 1304 : Bool SubMS::convertGridPars(LogIO& os,
4079 : const String& mode,
4080 : const int nchan,
4081 : const String& start,
4082 : const String& width,
4083 : const String& interp,
4084 : const String& restfreq,
4085 : const String& outframe,
4086 : const String& veltype,
4087 : String& t_mode,
4088 : String& t_outframe,
4089 : String& t_regridQuantity,
4090 : Double& t_restfreq,
4091 : String& t_regridInterpMeth,
4092 : Double& t_cstart,
4093 : Double& t_bandwidth,
4094 : Double& t_cwidth,
4095 : Bool& t_centerIsStart,
4096 : Bool& t_startIsEnd,
4097 : Int& t_nchan,
4098 : Int& t_width,
4099 : Int& t_start
4100 : ){
4101 1304 : Bool rstat(false);
4102 :
4103 : try {
4104 :
4105 1304 : os << LogOrigin("SubMS", "convertGridPars");
4106 :
4107 1304 : casacore::QuantumHolder qh;
4108 1304 : String error;
4109 :
4110 1304 : t_mode = mode;
4111 1304 : t_restfreq = 0.;
4112 1304 : if(!restfreq.empty() && !(restfreq=="[]")){
4113 1014 : if(qh.fromString(error, restfreq)){
4114 1014 : t_restfreq = qh.asQuantity().getValue("Hz");
4115 : }
4116 : else{
4117 0 : os << LogIO::SEVERE << "restfreq: " << error << LogIO::POST;
4118 0 : return false;
4119 : }
4120 : }
4121 :
4122 : // Determine grid
4123 1304 : t_cstart = -9e99; // default value indicating that the original start of the SPW should be used
4124 1304 : t_bandwidth = -1.; // default value indicating that the original width of the SPW should be used
4125 1304 : t_cwidth = -1.; // default value indicating that the original channel width of the SPW should be used
4126 1304 : t_nchan = -1;
4127 1304 : t_width = 0;
4128 1304 : t_start = -1;
4129 1304 : t_startIsEnd = false; // false means that start specifies the lower end in frequency (default)
4130 : // true means that start specifies the upper end in frequency
4131 :
4132 1304 : if(!start.empty() && !(start=="[]")){ // start was set
4133 1289 : if(t_mode == "channel"){
4134 1180 : t_start = atoi(start.c_str());
4135 : }
4136 1289 : if(t_mode == "channel_b"){
4137 2 : t_cstart = Double(atoi(start.c_str()));
4138 : }
4139 1287 : else if(t_mode == "frequency"){
4140 50 : if(qh.fromString(error, start)){
4141 50 : t_cstart = qh.asQuantity().getValue("Hz");
4142 : }
4143 : else{
4144 0 : os << LogIO::SEVERE << "start: " << error << LogIO::POST;
4145 0 : return false;
4146 : }
4147 : }
4148 1237 : else if(t_mode == "velocity"){
4149 57 : if(qh.fromString(error, start)){
4150 57 : t_cstart = qh.asQuantity().getValue("m/s");
4151 : }
4152 : else{
4153 0 : os << LogIO::SEVERE << "start: " << error << LogIO::POST;
4154 0 : return false;
4155 : }
4156 : }
4157 : }
4158 1304 : if(!width.empty() && !(width=="[]")){ // channel width was set
4159 1291 : if(t_mode == "channel"){
4160 1180 : Int w = atoi(width.c_str());
4161 1180 : t_width = abs(w);
4162 1180 : if(w<0){
4163 2 : t_startIsEnd = true;
4164 : }
4165 : }
4166 111 : else if(t_mode == "channel_b"){
4167 2 : Double w = atoi(width.c_str());
4168 2 : t_cwidth = abs(w);
4169 2 : if(w<0){
4170 0 : t_startIsEnd = true;
4171 : }
4172 : }
4173 109 : else if(t_mode == "frequency"){
4174 50 : if(qh.fromString(error, width)){
4175 50 : Double w = qh.asQuantity().getValue("Hz");
4176 50 : t_cwidth = abs(w);
4177 50 : if(w<0){
4178 4 : t_startIsEnd = true;
4179 : }
4180 : }
4181 : else{
4182 0 : os << LogIO::SEVERE << "width: " << error << LogIO::POST;
4183 0 : return false;
4184 : }
4185 : }
4186 59 : else if(t_mode == "velocity"){
4187 59 : if(qh.fromString(error, width)){
4188 59 : Double w = qh.asQuantity().getValue("m/s");
4189 59 : t_cwidth = abs(w);
4190 59 : if(w>=0){
4191 55 : t_startIsEnd = true;
4192 : }
4193 : }
4194 : else{
4195 0 : os << LogIO::SEVERE << "width: " << error << LogIO::POST;
4196 0 : return false;
4197 : }
4198 : }
4199 : }
4200 : else{ // width was not set
4201 : // for the velocity mode the default t_startIsEnd is true if the sign of width is not known
4202 13 : if(t_mode == "velocity"){
4203 8 : t_startIsEnd = true;
4204 : }
4205 : }
4206 :
4207 1304 : if(nchan > 0){ // number of output channels was set
4208 880 : if(t_mode == "channel_b"){
4209 0 : if(t_cwidth>0){
4210 0 : t_bandwidth = Double(nchan*t_cwidth);
4211 : }
4212 : else{
4213 0 : t_bandwidth = Double(nchan);
4214 : }
4215 : }
4216 : else{
4217 880 : t_nchan = nchan;
4218 : }
4219 : }
4220 :
4221 1304 : if(t_mode == "channel"){
4222 1180 : t_regridQuantity = "freq";
4223 : }
4224 124 : else if(t_mode == "channel_b"){
4225 2 : t_regridQuantity = "chan";
4226 : }
4227 122 : else if(t_mode == "frequency"){
4228 55 : t_regridQuantity = "freq";
4229 : }
4230 67 : else if(t_mode == "velocity"){
4231 67 : if(t_restfreq == 0.){
4232 0 : os << LogIO::SEVERE << "Need to set restfreq in velocity mode." << LogIO::POST;
4233 0 : return false;
4234 : }
4235 67 : t_regridQuantity = "vrad";
4236 67 : if(veltype == "optical"){
4237 10 : t_regridQuantity = "vopt";
4238 : }
4239 57 : else if(veltype != "radio"){
4240 : os << LogIO::WARN << "Invalid velocity type "<< veltype
4241 2 : << ", setting type to \"radio\"" << LogIO::POST;
4242 : }
4243 : }
4244 : else{
4245 0 : os << LogIO::WARN << "Invalid mode " << t_mode << LogIO::POST;
4246 0 : return false;
4247 : }
4248 :
4249 1304 : t_outframe=outframe;
4250 1304 : t_regridInterpMeth=interp;
4251 1304 : t_centerIsStart = true;
4252 :
4253 : // end prepare regridding parameters
4254 :
4255 1304 : rstat = true;
4256 :
4257 1304 : } catch (AipsError x) {
4258 0 : os << LogIO::SEVERE << "Exception Reported: " << x.getMesg() << LogIO::POST;
4259 0 : rstat = false;
4260 0 : }
4261 1304 : return rstat;
4262 : }
4263 :
4264 :
4265 1250 : Bool SubMS::calcChanFreqs(LogIO& os,
4266 : Vector<Double>& newCHAN_FREQ,
4267 : Vector<Double>& newCHAN_WIDTH,
4268 : const Vector<Double>& oldCHAN_FREQ,
4269 : const Vector<Double>& oldCHAN_WIDTH,
4270 : const MDirection phaseCenter,
4271 : const MFrequency::Types theOldRefFrame,
4272 : const MEpoch theObsTime,
4273 : const MPosition mObsPos,
4274 : const String& mode,
4275 : const int nchan,
4276 : const String& start,
4277 : const String& width,
4278 : const String& restfreq,
4279 : const String& outframe,
4280 : const String& veltype,
4281 : const Bool verbose,
4282 : const MRadialVelocity mRV // only used for outframe=="SOURCE"
4283 : ){
4284 :
4285 : Double weightScale;
4286 2500 : return calcChanFreqs(os,
4287 : newCHAN_FREQ,
4288 : newCHAN_WIDTH,
4289 : weightScale,
4290 : oldCHAN_FREQ,
4291 : oldCHAN_WIDTH,
4292 : phaseCenter,
4293 : theOldRefFrame,
4294 : theObsTime,
4295 : mObsPos,
4296 : mode,
4297 : nchan,
4298 : start,
4299 : width,
4300 : restfreq,
4301 : outframe,
4302 : veltype,
4303 : verbose,
4304 : mRV // only used for outframe=="SOURCE"
4305 2500 : );
4306 : }
4307 :
4308 :
4309 1250 : Bool SubMS::calcChanFreqs(LogIO& os,
4310 : Vector<Double>& newCHAN_FREQ,
4311 : Vector<Double>& newCHAN_WIDTH,
4312 : Double& weightScale,
4313 : const Vector<Double>& oldCHAN_FREQ,
4314 : const Vector<Double>& oldCHAN_WIDTH,
4315 : const MDirection phaseCenter,
4316 : const MFrequency::Types theOldRefFrame,
4317 : const MEpoch theObsTime,
4318 : const MPosition mObsPos,
4319 : const String& mode,
4320 : const int nchan,
4321 : const String& start,
4322 : const String& width,
4323 : const String& restfreq,
4324 : const String& outframe,
4325 : const String& veltype,
4326 : const Bool verbose,
4327 : const MRadialVelocity mRV // only used for outframe=="SOURCE"
4328 : ){
4329 :
4330 1250 : Vector<Double> newChanLoBound;
4331 1250 : Vector<Double> newChanHiBound;
4332 1250 : String t_phasec;
4333 :
4334 1250 : String t_mode;
4335 1250 : String t_outframe;
4336 1250 : String t_regridQuantity;
4337 : Double t_restfreq;
4338 1250 : String t_regridInterpMeth;
4339 : Double t_cstart;
4340 : Double t_bandwidth;
4341 : Double t_cwidth;
4342 : Bool t_centerIsStart;
4343 : Bool t_startIsEnd;
4344 : Int t_nchan;
4345 : Int t_width;
4346 : Int t_start;
4347 :
4348 1250 : if(!convertGridPars(os,
4349 : mode,
4350 : nchan,
4351 : start,
4352 : width,
4353 : "linear", // a dummy value in this context
4354 : restfreq,
4355 : outframe,
4356 : veltype,
4357 : ////// output ////
4358 : t_mode,
4359 : t_outframe,
4360 : t_regridQuantity,
4361 : t_restfreq,
4362 : t_regridInterpMeth,
4363 : t_cstart,
4364 : t_bandwidth,
4365 : t_cwidth,
4366 : t_centerIsStart,
4367 : t_startIsEnd,
4368 : t_nchan,
4369 : t_width,
4370 : t_start
4371 : )
4372 : ){
4373 : // an error occured
4374 0 : return false;
4375 : }
4376 :
4377 : // reference frame transformation
4378 1250 : Bool needTransform = true;
4379 1250 : Bool doRadVelCorr = false;
4380 : MFrequency::Types theFrame;
4381 1250 : String oframe = outframe;
4382 1250 : oframe.upcase();
4383 1250 : if(outframe==""){ // no ref frame given
4384 : // keep the reference frame as is
4385 901 : theFrame = theOldRefFrame;
4386 901 : needTransform = false;
4387 : }
4388 349 : else if(oframe=="SOURCE"){ // GEO trafo + radial velocity correction
4389 8 : theFrame = MFrequency::GEO;
4390 8 : doRadVelCorr = true;
4391 : }
4392 341 : else if(!MFrequency::getType(theFrame, outframe)){
4393 : os << LogIO::SEVERE
4394 : << "Parameter \"outframe\" value " << outframe << " is invalid."
4395 0 : << LogIO::POST;
4396 0 : return false;
4397 : }
4398 341 : else if (theFrame == theOldRefFrame){
4399 110 : needTransform = false;
4400 : }
4401 :
4402 1250 : uInt oldNUM_CHAN = oldCHAN_FREQ.size();
4403 1250 : if(oldNUM_CHAN == 0){
4404 0 : newCHAN_FREQ.resize(0);
4405 0 : newCHAN_WIDTH.resize(0);
4406 0 : return true;
4407 : }
4408 :
4409 1250 : if(oldNUM_CHAN != oldCHAN_WIDTH.size()){
4410 : os << LogIO::SEVERE
4411 : << "Internal error: inconsistent dimensions of input channel freq and width arrays."
4412 0 : << LogIO::POST;
4413 0 : return false;
4414 : }
4415 :
4416 1250 : Vector<Double> absOldCHAN_WIDTH;
4417 1250 : absOldCHAN_WIDTH.assign(oldCHAN_WIDTH);
4418 : {
4419 1250 : Bool negativeWidths = false;
4420 332770 : for(uInt i=0; i<oldCHAN_WIDTH.size(); i++){
4421 331520 : if(oldCHAN_WIDTH(i) < 0.){
4422 10773 : negativeWidths = true;
4423 10773 : absOldCHAN_WIDTH(i) = -oldCHAN_WIDTH(i);
4424 : }
4425 : }
4426 1250 : if(negativeWidths && verbose){
4427 : os << LogIO::NORMAL
4428 : << " *** Encountered negative channel widths in input spectral window."
4429 3 : << LogIO::POST;
4430 : }
4431 : }
4432 :
4433 1250 : Vector<Double> transNewXin;
4434 1250 : Vector<Double> transCHAN_WIDTH(oldNUM_CHAN);
4435 :
4436 1250 : if(needTransform){
4437 239 : transNewXin.resize(oldNUM_CHAN);
4438 : // set up conversion
4439 239 : Unit unit(String("Hz"));
4440 239 : MFrequency::Ref fromFrame = MFrequency::Ref(theOldRefFrame, MeasFrame(phaseCenter, mObsPos, theObsTime));
4441 239 : MFrequency::Ref toFrame = MFrequency::Ref(theFrame, MeasFrame(phaseCenter, mObsPos, theObsTime));
4442 239 : MFrequency::Convert freqTrans(unit, fromFrame, toFrame);
4443 :
4444 239 : MDoppler radVelCorr; // no correction
4445 239 : Bool radVelSignificant = false; // is the radial velocity large enough to warrant a shift?
4446 : // prepare correction for radial velocity if requested and possible
4447 239 : if(doRadVelCorr){
4448 8 : Quantity mrv = mRV.get("m/s"); // (const)
4449 8 : radVelCorr = MDoppler(-mrv); // NOTE: opposite sign to achieve correction!
4450 8 : Double mRVVal = mrv.getValue();
4451 8 : if(fabs(mRVVal)>1E-6){
4452 8 : radVelSignificant = true;
4453 8 : if(verbose){
4454 : os << LogIO::NORMAL
4455 : << "Note: The given additional radial velocity of " << mRVVal << " m/s will be taken into account."
4456 0 : << LogIO::POST;
4457 : }
4458 : }
4459 0 : else if(verbose){
4460 : os << LogIO::NORMAL
4461 : << "Note: The given additional radial velocity is less than 1E-6 m/s and will not be taken into account."
4462 0 : << LogIO::POST;
4463 : }
4464 8 : }
4465 :
4466 30465 : for(uInt i=0; i<oldNUM_CHAN; i++){
4467 30226 : transNewXin[i] = freqTrans(oldCHAN_FREQ[i]).get(unit).getValue();
4468 30226 : transCHAN_WIDTH[i] = freqTrans(oldCHAN_FREQ[i] +
4469 60452 : absOldCHAN_WIDTH[i]/2.).get(unit).getValue()
4470 30226 : - freqTrans(oldCHAN_FREQ[i] -
4471 30226 : absOldCHAN_WIDTH[i]/2.).get(unit).getValue(); // eliminate possible offsets
4472 : }
4473 :
4474 239 : if(radVelSignificant){ // correct in addition for radial velocity
4475 8 : transNewXin = radVelCorr.shiftFrequency(transNewXin);
4476 8 : transCHAN_WIDTH = radVelCorr.shiftFrequency(transCHAN_WIDTH); //shiftFrequency is a scaling, so chan widths scale as well
4477 : }
4478 :
4479 239 : }
4480 : else {
4481 : // just copy
4482 1011 : transNewXin.assign(oldCHAN_FREQ);
4483 1011 : transCHAN_WIDTH.assign(absOldCHAN_WIDTH);
4484 : }
4485 :
4486 : // calculate new grid
4487 :
4488 1250 : String message;
4489 :
4490 1250 : if(!regridChanBounds(newChanLoBound,
4491 : newChanHiBound,
4492 : t_cstart,
4493 : t_bandwidth,
4494 : t_cwidth,
4495 : t_restfreq,
4496 : t_regridQuantity,
4497 : transNewXin,
4498 : transCHAN_WIDTH,
4499 : message,
4500 : t_centerIsStart,
4501 : t_startIsEnd,
4502 : t_nchan,
4503 : t_width,
4504 : t_start
4505 : )
4506 : ){ // there was an error
4507 1 : os << LogIO::WARN << message << LogIO::POST;
4508 1 : return false;
4509 : }
4510 :
4511 1249 : if(verbose){
4512 124 : os << LogIO::NORMAL << message << LogIO::POST;
4513 : }
4514 :
4515 : // we have a useful set of channel boundaries
4516 1249 : uInt newNUM_CHAN = newChanLoBound.size();
4517 :
4518 : // complete the calculation of the new channel centers and widths
4519 : // from newNUM_CHAN, newChanLoBound, and newChanHiBound
4520 1249 : newCHAN_FREQ.resize(newNUM_CHAN);
4521 1249 : newCHAN_WIDTH.resize(newNUM_CHAN);
4522 115528 : for(uInt i=0; i<newNUM_CHAN; i++){
4523 114279 : newCHAN_FREQ[i] = (newChanLoBound[i]+newChanHiBound[i])/2.;
4524 114279 : newCHAN_WIDTH[i] = newChanHiBound[i]-newChanLoBound[i];
4525 : //cout << "new lo hi freq width " << newChanLoBound[i] << " " << newChanHiBound[i] << " " << newCHAN_FREQ[i] << " " << newCHAN_WIDTH[i] << endl;
4526 : }
4527 :
4528 1249 : weightScale = newCHAN_WIDTH[0]/transCHAN_WIDTH[0];
4529 :
4530 1249 : return true;
4531 :
4532 1250 : }
4533 :
4534 :
4535 107 : Bool SubMS::setRegridParameters(vector<Int>& oldSpwId,
4536 : vector<Int>& oldFieldId,
4537 : vector<Int>& newDataDescId,
4538 : vector<Bool>& regrid,
4539 : vector<Bool>& transform,
4540 : vector<MDirection>& theFieldDirV,
4541 : vector<MPosition>& mObsPosV,
4542 : vector<MFrequency::Types>& fromFrameTypeV,
4543 : vector<MFrequency::Ref>& outFrameV,
4544 : vector<MRadialVelocity>& outRadVelV,
4545 : vector< Double >& weightScaleV,
4546 : vector< Vector<Double> >& xold,
4547 : vector< Vector<Double> >& xout,
4548 : vector< Vector<Double> >& xin,
4549 : vector<Int>& method,
4550 : Bool& msModified,
4551 : const String& outframe,
4552 : const String& regridQuant,
4553 : const Double regridVeloRestfrq,
4554 : const String& regridInterpMeth,
4555 : const Double regridCenter,
4556 : const Double regridBandwidth,
4557 : const Double regridChanWidth,
4558 : const Int regridPhaseCenterFieldId,
4559 : const MDirection regridPhaseCenter,
4560 : const Bool writeTables,
4561 : LogIO& os,
4562 : String& regridMessage,
4563 : const Bool centerIsStart,
4564 : const Bool startIsEnd,
4565 : const Int nchan,
4566 : const Int width,
4567 : const Int start
4568 : )
4569 : {
4570 107 : Bool rval = true;
4571 :
4572 : // reset the "done" table.
4573 107 : newDataDescId.resize(0);
4574 107 : oldSpwId.resize(0);
4575 107 : oldFieldId.resize(0);
4576 107 : xold.resize(0);
4577 107 : xin.resize(0);
4578 107 : xout.resize(0);
4579 107 : theFieldDirV.resize(0);
4580 107 : mObsPosV.resize(0);
4581 107 : fromFrameTypeV.resize(0);
4582 107 : outFrameV.resize(0);
4583 107 : outRadVelV.resize(0);
4584 107 : weightScaleV.resize(0);
4585 107 : MFrequency::Ref outFrame;
4586 214 : MRadialVelocity outRadVel(Quantity(0, "m/s"), MRadialVelocity::GEO);
4587 107 : method.resize(0);
4588 107 : regrid.resize(0);
4589 107 : transform.resize(0);
4590 :
4591 : // Determine the highest data_desc_id from the DATA_DESCRIPTION table
4592 107 : MSDataDescription ddtable = ms_p.dataDescription();
4593 107 : Int origNumDataDescs = ddtable.nrow();
4594 107 : Int nextDataDescId = origNumDataDescs - 1;
4595 107 : Int numNewDataDesc = 0;
4596 :
4597 : // Determine the highest spw_id in the SPW table
4598 107 : MSSpectralWindow spwtable = ms_p.spectralWindow();
4599 107 : Int origNumSPWs = spwtable.nrow();
4600 107 : Int nextSPWId = origNumSPWs - 1;
4601 107 : Int numNewSPWIds = 0;
4602 :
4603 : // Determine the highest row number in the SOURCE table
4604 107 : Int origNumSourceRows = 0;
4605 107 : Int nextSourceRow = -1;
4606 107 : Int numNewSourceRows = 0;
4607 107 : vector<Int> newSourceIds;
4608 107 : vector<Int> newSourceSPWIds;
4609 107 : MSSource* p_sourcetable = NULL;
4610 107 : MSSourceColumns* p_sourceCol = NULL;
4611 107 : if(Table::isReadable(ms_p.sourceTableName())){
4612 107 : p_sourcetable = &(ms_p.source());
4613 107 : p_sourceCol = new MSSourceColumns(*p_sourcetable);
4614 107 : origNumSourceRows = p_sourcetable->nrow();
4615 107 : nextSourceRow = origNumSourceRows - 1;
4616 : }
4617 0 : else if(!writeTables) { // there is no source table
4618 0 : os << LogIO::NORMAL << "Note: MS does not contain a SOURCE table ..." << LogIO::POST;
4619 0 : nextSourceRow = -1;
4620 : }
4621 :
4622 107 : MSMainColumns mainCols(ms_p);
4623 107 : ScalarColumn<Int> fieldIdCol = mainCols.fieldId();
4624 107 : ScalarColumn<Int> DDIdCol = mainCols.dataDescId();
4625 107 : ScalarMeasColumn<MEpoch> mainTimeMeasCol = mainCols.timeMeas();
4626 : // other administrational tables
4627 :
4628 107 : MSDataDescColumns DDCols(ddtable);
4629 107 : ScalarColumn<Int> SPWIdCol = DDCols.spectralWindowId();
4630 :
4631 107 : MSSpWindowColumns SPWCols(spwtable);
4632 107 : ScalarColumn<Int> numChanCol = SPWCols.numChan();
4633 107 : ArrayColumn<Double> chanFreqCol = SPWCols.chanFreq();
4634 107 : ArrayMeasColumn<MFrequency> chanFreqMeasCol = SPWCols.chanFreqMeas();
4635 107 : ScalarColumn<Int> measFreqRefCol = SPWCols.measFreqRef();
4636 107 : ArrayColumn<Double> chanWidthCol = SPWCols.chanWidth();
4637 107 : ArrayColumn<Double> effectiveBWCol = SPWCols.effectiveBW();
4638 107 : ScalarColumn<Double> refFrequencyCol = SPWCols.refFrequency();
4639 107 : ScalarMeasColumn<MFrequency> refFrequencyMeasCol = SPWCols.refFrequencyMeas();
4640 107 : ArrayColumn<Double> resolutionCol = SPWCols.resolution();
4641 107 : ScalarColumn<Double> totalBandwidthCol = SPWCols.totalBandwidth();
4642 :
4643 107 : MSField fieldtable = ms_p.field();
4644 107 : MSFieldColumns FIELDCols(fieldtable);
4645 : //ArrayMeasColumn<MDirection> referenceDirMeasCol = FIELDCols.referenceDirMeasCol();
4646 : //ScalarMeasColumn<MEpoch>& timeMeasCol = FIELDCols.timeMeas();
4647 107 : ScalarColumn<Int> FIELDsourceIdCol = FIELDCols.sourceId();
4648 :
4649 : // calculate mean antenna position for TOPO transformation
4650 107 : MSAntenna anttable = ms_p.antenna();
4651 107 : MSAntennaColumns ANTCols(anttable);
4652 107 : ROScalarMeasColumn<MPosition> ANTPositionMeasCol = ANTCols.positionMeas();
4653 107 : ScalarColumn<Bool> ANTflagRowCol = ANTCols.flagRow();
4654 107 : Int nAnt = 0;
4655 107 : Vector<Double> pos(3); pos=0;
4656 1605 : for (uInt i=0; i<anttable.nrow(); i++) {
4657 1498 : if(!ANTflagRowCol(i)){
4658 1496 : pos+=ANTPositionMeasCol(i).getValue().get();
4659 1496 : nAnt++;
4660 : }
4661 : }
4662 107 : if(nAnt>0){
4663 107 : pos /= Double(nAnt);
4664 : }
4665 : else {
4666 : os << LogIO::WARN << "No unflagged antennas in this MS. Cannot proceed with regridSpw ..."
4667 0 : << LogIO::POST;
4668 0 : return rval;
4669 : }
4670 :
4671 107 : MPosition mObsPos = ANTPositionMeasCol(0); // transfer reference frame
4672 107 : mObsPos.set(MVPosition(pos)); // set coordinates
4673 :
4674 : // but use a tabulated version if available (as in clean)
4675 : {
4676 107 : MPosition Xpos;
4677 107 : String Xobservatory;
4678 107 : MSObservationColumns XObsCols(ms_p.observation());
4679 107 : if (ms_p.observation().nrow() > 0) {
4680 107 : Xobservatory = XObsCols.telescopeName()(mainCols.observationId()(0));
4681 : }
4682 214 : if (Xobservatory.length() == 0 ||
4683 107 : !MeasTable::Observatory(Xpos,Xobservatory)) {
4684 : // unknown observatory, use the above calculated centroid position
4685 0 : if(!writeTables){
4686 : os << LogIO::WARN << "Unknown observatory: \"" << Xobservatory
4687 0 : << "\". Determining observatory position from antenna 0." << LogIO::POST;
4688 : }
4689 0 : Xpos=MPosition::Convert(ANTPositionMeasCol(0), MPosition::ITRF)();
4690 : }
4691 : else{
4692 107 : if(!writeTables){
4693 : os << LogIO::NORMAL << "Using tabulated observatory position for " << Xobservatory << ":"
4694 54 : << LogIO::POST;
4695 54 : Xpos=MPosition::Convert(Xpos, MPosition::ITRF)();
4696 : }
4697 : }
4698 107 : mObsPos = Xpos;
4699 107 : if(!writeTables){
4700 54 : ostringstream oss;
4701 54 : oss << " " << mObsPos << " (ITRF)";
4702 54 : os << LogIO::NORMAL << oss.str() << LogIO::POST;
4703 54 : }
4704 107 : }
4705 :
4706 : // create time-sorted index for main table access
4707 107 : uInt nMainTabRows = ms_p.nrow();
4708 107 : Vector<uInt> sortedI(nMainTabRows);
4709 : {
4710 107 : Vector<Double> mainTimesV = mainCols.time().getColumn();
4711 107 : GenSortIndirect<Double>::sort(sortedI,mainTimesV);
4712 107 : }
4713 :
4714 1291361 : for(uInt mainTabRowI=0; mainTabRowI<nMainTabRows; mainTabRowI++){
4715 :
4716 1291255 : uInt mainTabRow = sortedI(mainTabRowI); // i.e. mainTabRow is sorted in Time
4717 :
4718 : // For each MAIN table row, the FIELD_ID cell and the DATA_DESC_ID cell are read
4719 1291255 : Int theFieldId = fieldIdCol(mainTabRow);
4720 1291255 : Int theDataDescId = DDIdCol(mainTabRow);
4721 : // and the SPW_ID extracted from the corresponding row in the
4722 : // DATA_DESCRIPTION table.
4723 1291255 : Int theSPWId = -2;
4724 1291255 : if (theDataDescId < origNumDataDescs){
4725 1291255 : theSPWId = SPWIdCol(theDataDescId);
4726 : }
4727 : else {
4728 : os << LogIO::SEVERE
4729 : << "Incoherent MS: Found at main table row " << mainTabRow
4730 : << " reference to non-existing DATA_DESCRIPTION table entry "
4731 : << theDataDescId
4732 0 : << LogIO::POST;
4733 0 : rval = false;
4734 1 : return rval;
4735 : }
4736 :
4737 : // variables saying what has to be done for this row
4738 1291255 : Bool needTransform = false;
4739 1291255 : Bool doRegrid = false;
4740 1291255 : Int equivalentSpwFieldPair = -1;
4741 :
4742 1291255 : String message;
4743 :
4744 : // The pair (theFieldId, theSPWId) is looked up in the "done table".
4745 1291255 : Int iDone = -1;
4746 1291255 : for (uInt i=0; i<oldSpwId.size(); i++){
4747 1291148 : if(oldSpwId[i]==theSPWId && (oldFieldId[i]==theFieldId || regridPhaseCenterFieldId>=-1)){
4748 : // if common phase center is given, treat all fields the same
4749 1291148 : iDone = i;
4750 1291148 : break;
4751 : }
4752 : }
4753 :
4754 1291255 : if(iDone<0){ // this (theFieldId, theSPWId) pair was not yet encountered
4755 :
4756 : // Determine information for new row in "done" table
4757 : // The information necessary for the transformation is extracted:
4758 : // 1) center frequency of each channel (taken from the CHAN_FREQ cell
4759 : // corresponding to theSPWId in the SPW table)
4760 107 : Vector<Double> newXin;
4761 107 : newXin.assign(chanFreqCol(theSPWId));
4762 : // -> store in xin (further below)
4763 : // 2) reference frame for these frequencies (taken from the
4764 : // MEAS_FREQ_REF cell corresponding to theSPWId in the SPW table)
4765 107 : MFrequency::Types theOldRefFrame = MFrequency::castType(measFreqRefCol(theSPWId));
4766 : // -> store in oldRefFrame[numNewDataDesc] (further below)
4767 : // 3) in case either the original or the destination reference frame
4768 : // is TOPO or GEO, we need the observation time
4769 : // (taken from the time of the first integration for this (theFieldId, theSPWId) pair)
4770 : // -> store in obsTime[numNewDataDesc] (further below)
4771 107 : MEpoch theObsTime = mainTimeMeasCol(mainTabRow);
4772 : //// (taken uniformly for the whole MS from the first row of the MS
4773 : //// which is also the earliest row because it is time-sorted)
4774 : //MEpoch theObsTime = mainTimeMeasCol(0);
4775 :
4776 : // Determine if a reference frame transformation is necessary
4777 : // Bool getType (MFrequency::Types &tp, const String &in)
4778 107 : needTransform = true;
4779 107 : Bool doRadVelCorr = false;
4780 : MFrequency::Types theFrame;
4781 107 : String oframe = outframe;
4782 107 : oframe.upcase();
4783 107 : if(outframe==""){ // no ref frame given
4784 : // keep the reference frame as is
4785 70 : theFrame = theOldRefFrame;
4786 70 : needTransform = false;
4787 : }
4788 37 : else if(oframe=="SOURCE"){ // GEO trafo + radial velocity correction
4789 6 : theFrame = MFrequency::GEO;
4790 6 : doRadVelCorr = true;
4791 : }
4792 31 : else if(!MFrequency::getType(theFrame, outframe)){
4793 : os << LogIO::SEVERE
4794 : << "Parameter \"outframe\" value " << outframe << " is invalid."
4795 0 : << LogIO::POST;
4796 0 : return false;
4797 : }
4798 31 : else if (theFrame == theOldRefFrame){
4799 2 : needTransform = false;
4800 : }
4801 :
4802 107 : Double weightScale = 1.;
4803 :
4804 : // 4) direction of the field, i.e. the phase center
4805 107 : MDirection theFieldDir;
4806 107 : uInt theFieldIdToUse = theFieldId;
4807 107 : if(regridPhaseCenterFieldId<-1){ // take it from the PHASE_DIR cell
4808 : // corresponding to theFieldId in the FIELD table)
4809 0 : theFieldDir = FIELDCols.phaseDirMeas(theFieldId, mainCols.time()(mainTabRow));
4810 :
4811 0 : if(FIELDCols.needInterTime(theFieldId)){
4812 0 : String ephPath = FIELDCols.ephemPath(theFieldId);
4813 0 : os << LogIO::NORMAL << "Note: Field with id " << theFieldId;
4814 0 : if(ephPath.size()>0){
4815 0 : os << ", uses ephemeris " << ephPath << LogIO::POST;
4816 : }
4817 : else{
4818 0 : os << ", has a time-dependent position described by a polynomial." << LogIO::POST;
4819 : }
4820 0 : }
4821 :
4822 : }
4823 107 : else if(regridPhaseCenterFieldId==-1){ // use the given direction
4824 14 : theFieldDir = regridPhaseCenter;
4825 14 : doRadVelCorr = false;
4826 : }
4827 93 : else if((uInt)regridPhaseCenterFieldId < fieldtable.nrow()){ // use this valid field ID
4828 93 : theFieldDir = FIELDCols.phaseDirMeas(regridPhaseCenterFieldId, mainCols.time()(mainTabRow));
4829 93 : theFieldIdToUse = regridPhaseCenterFieldId;
4830 93 : if(FIELDCols.needInterTime(regridPhaseCenterFieldId)){
4831 6 : String ephPath = FIELDCols.ephemPath(regridPhaseCenterFieldId);
4832 6 : os << LogIO::NORMAL << "Note: Field to be used as phase center, id " << regridPhaseCenterFieldId;
4833 6 : if(ephPath.size()>0){
4834 6 : os << ", uses ephemeris " << ephPath << LogIO::POST;
4835 : }
4836 : else{
4837 0 : os << ", has a time-dependent position described by a polynomial." << LogIO::POST;
4838 : }
4839 6 : }
4840 :
4841 : }
4842 : else{
4843 : os << LogIO::SEVERE << "Field to be used as phase center, id "
4844 : << regridPhaseCenterFieldId
4845 0 : << ", does not exist." << LogIO::POST;
4846 0 : return false;
4847 : }
4848 :
4849 : // cout << "theFieldId = " << theFieldId << ", theObsTime = " << theObsTime
4850 : // << ", theFieldDir = " << theFieldDir.getAngle() << endl;
4851 :
4852 : // -> store in fieldDir[numNewDataDesc] (further below)
4853 : // 5) in case either the original or the destination reference frame
4854 : // (but not both) are TOPO, we need the observatory position
4855 : // (from the mean antenna position calculated above)
4856 : // -> store in obsPos[numNewDataDesc] (further below)
4857 :
4858 : // Perform the pure frequency transformation (no regridding yet)
4859 107 : Vector<Double> transNewXin;
4860 : // also take care of the other parameters of the spectral window
4861 107 : Int oldNUM_CHAN = numChanCol(theSPWId);
4862 107 : Vector<Double> oldCHAN_WIDTH = chanWidthCol(theSPWId);
4863 : {
4864 107 : Bool negativeWidths = false;
4865 65885 : for(uInt i=0; i<oldCHAN_WIDTH.nelements(); i++){
4866 65778 : if(oldCHAN_WIDTH(i) < 0.){
4867 7680 : negativeWidths = true;
4868 7680 : oldCHAN_WIDTH(i) = -oldCHAN_WIDTH(i);
4869 : }
4870 : }
4871 107 : if(negativeWidths){
4872 : os << LogIO::NORMAL
4873 : << " *** Encountered negative channel widths in SPECTRAL_WINDOW table."
4874 2 : << LogIO::POST;
4875 : }
4876 : }
4877 107 : MFrequency oldREF_FREQUENCY = refFrequencyMeasCol(theSPWId);
4878 107 : Double oldTOTAL_BANDWIDTH = totalBandwidthCol(theSPWId);
4879 107 : Vector<Double> oldEFFECTIVE_BW = effectiveBWCol(theSPWId);
4880 107 : Vector<Double> oldRESOLUTION = resolutionCol(theSPWId);
4881 :
4882 : // storage for values with pure freq trafo applied
4883 107 : Vector<Double> transCHAN_WIDTH(oldNUM_CHAN);
4884 107 : MFrequency transREF_FREQUENCY;
4885 : Double transTOTAL_BANDWIDTH;
4886 107 : Vector<Double> transRESOLUTION(oldNUM_CHAN);;
4887 :
4888 107 : if(needTransform){
4889 :
4890 35 : transNewXin.resize(oldNUM_CHAN);
4891 : // set up conversion
4892 35 : Unit unit(String("Hz"));
4893 35 : MFrequency::Ref fromFrame = MFrequency::Ref(theOldRefFrame, MeasFrame(theFieldDir, mObsPos, theObsTime));
4894 35 : MFrequency::Ref toFrame = MFrequency::Ref(theFrame, MeasFrame(theFieldDir, mObsPos, theObsTime));
4895 35 : MFrequency::Convert freqTrans(unit, fromFrame, toFrame);
4896 :
4897 35 : MDoppler radVelCorr; // no correction
4898 35 : Bool radVelSignificant = false; // is the radial velocity large enough to warrant a shift?
4899 : // prepare correction for radial velocity if requested and possible
4900 35 : if(doRadVelCorr && FIELDCols.needInterTime(theFieldIdToUse)){
4901 6 : MRadialVelocity mRV = FIELDCols.radVelMeas(theFieldIdToUse, mainCols.time()(mainTabRow));
4902 6 : Quantity mrv = mRV.get("m/s");
4903 6 : radVelCorr = MDoppler(-mrv); // NOTE: opposite sign to achieve correction
4904 6 : if(fabs(mrv.getValue())>1E-6){
4905 6 : radVelSignificant = true;
4906 6 : outRadVel = mRV;
4907 : os << LogIO::NORMAL
4908 12 : << "Note: The geocentric radial velocity information (ca. " << mrv.getValue()
4909 : << "m/s) from the ephemeris for field " << theFieldIdToUse << " will be taken into account."
4910 6 : << LogIO::POST;
4911 : }
4912 : else{
4913 0 : outRadVel = MRadialVelocity(Quantity(0, "m/s"), MRadialVelocity::GEO);
4914 : os << LogIO::NORMAL
4915 : << "Note: The geocentric radial velocity from the ephemeris for field " << theFieldIdToUse
4916 : << " is less than 1E-6 m/s and will not be taken into account."
4917 0 : << LogIO::POST;
4918 :
4919 : }
4920 6 : }
4921 :
4922 : // also create the reference for storage in the "Done" table
4923 35 : outFrame = MFrequency::Ref(theFrame, MeasFrame(theFieldDir, mObsPos, theObsTime));
4924 :
4925 :
4926 28755 : for(Int i=0; i<oldNUM_CHAN; i++){
4927 28720 : transNewXin[i] = freqTrans(newXin[i]).get(unit).getValue();
4928 28720 : transCHAN_WIDTH[i] = freqTrans(newXin[i] +
4929 28720 : oldCHAN_WIDTH[i]/2.).get(unit).getValue()
4930 28720 : - freqTrans(newXin[i] -
4931 28720 : oldCHAN_WIDTH[i]/2.).get(unit).getValue(); // eliminate possible offsets
4932 28720 : transRESOLUTION[i] = freqTrans(newXin[i] +
4933 57440 : oldRESOLUTION[i]/2.).get(unit).getValue()
4934 28720 : - freqTrans(newXin[i]
4935 28720 : - oldRESOLUTION[i] / 2.0).get(unit).getValue(); // eliminate possible offsets
4936 : }
4937 35 : transREF_FREQUENCY = freqTrans(oldREF_FREQUENCY);
4938 35 : transTOTAL_BANDWIDTH = fabs(transNewXin[oldNUM_CHAN-1] - transNewXin[0]) +
4939 35 : fabs(transCHAN_WIDTH[oldNUM_CHAN-1])/2. + fabs(transCHAN_WIDTH[0])/2.;
4940 :
4941 35 : if(radVelSignificant){ // correct in addition for radial velocity
4942 6 : transNewXin = radVelCorr.shiftFrequency(transNewXin);
4943 6 : transCHAN_WIDTH = radVelCorr.shiftFrequency(transCHAN_WIDTH); //shiftFrequency is a scaling, so chan widths scale as well
4944 6 : transRESOLUTION = radVelCorr.shiftFrequency(transRESOLUTION);
4945 6 : Vector<Double> tmpV(1);
4946 6 : tmpV(0) = transREF_FREQUENCY.get("Hz").getValue();
4947 6 : transREF_FREQUENCY.set( MVFrequency( radVelCorr.shiftFrequency(tmpV)(0) ) );
4948 6 : tmpV(0) = transTOTAL_BANDWIDTH;
4949 6 : transTOTAL_BANDWIDTH = radVelCorr.shiftFrequency(tmpV)(0);
4950 6 : }
4951 :
4952 35 : }
4953 : else {
4954 : // just copy
4955 72 : transNewXin.assign(newXin);
4956 72 : transCHAN_WIDTH.assign(oldCHAN_WIDTH);
4957 72 : transRESOLUTION.assign(oldRESOLUTION);
4958 72 : transREF_FREQUENCY = oldREF_FREQUENCY;
4959 72 : transTOTAL_BANDWIDTH = oldTOTAL_BANDWIDTH;
4960 : }
4961 :
4962 : // (reference frame transformation completed)
4963 :
4964 :
4965 : // storage for values with complete freq trafo + regridding applied
4966 : // (set to default values for the case of no regridding)
4967 107 : Vector<Double> newXout;
4968 107 : newXout.assign(transNewXin);
4969 107 : Int newNUM_CHAN = oldNUM_CHAN;
4970 107 : Vector<Double> newCHAN_WIDTH;
4971 107 : newCHAN_WIDTH.assign(transCHAN_WIDTH);
4972 107 : MFrequency newREF_FREQUENCY = transREF_FREQUENCY;
4973 107 : Vector<Double> newRESOLUTION;
4974 107 : newRESOLUTION.assign(transRESOLUTION);
4975 107 : Double newTOTAL_BANDWIDTH = transTOTAL_BANDWIDTH;
4976 107 : Vector<Double> newEFFECTIVE_BW;
4977 107 : newEFFECTIVE_BW.assign(oldEFFECTIVE_BW);
4978 : Int theMethod;
4979 :
4980 : // check if theSPWId was already handled
4981 107 : Int iDone2 = -1;
4982 107 : for (uInt i=0; i<oldSpwId.size(); i++){
4983 0 : if(oldSpwId[i]==theSPWId){
4984 0 : iDone2 = i;
4985 0 : break;
4986 : }
4987 : }
4988 107 : equivalentSpwFieldPair = iDone2;
4989 :
4990 107 : if(equivalentSpwFieldPair>=0 && !needTransform){
4991 : // a transformation was not needed,
4992 : // i.e. the operation on this SPW is independent of the FIELD
4993 : // and (since equivalentSpwFieldPair>=0) this SPW was already processed
4994 : // so we can reuse a previous SpwFieldPair
4995 :
4996 : // get the parameters from the "done table"
4997 0 : theSPWId = oldSpwId[equivalentSpwFieldPair];
4998 : // don't get the field id!
4999 0 : theDataDescId = newDataDescId[equivalentSpwFieldPair] + origNumDataDescs;
5000 0 : transNewXin.assign(xin[equivalentSpwFieldPair]);
5001 0 : newXout.assign(xout[equivalentSpwFieldPair]);
5002 0 : theMethod = method[equivalentSpwFieldPair];
5003 0 : doRegrid = regrid[equivalentSpwFieldPair];
5004 :
5005 : }
5006 : else {
5007 : // Determine if regridding is necessary and set the parameters (at
5008 : // the same time, determine if the transformation is non-linear. If
5009 : // so set trafoNonlin (further below).)
5010 :
5011 107 : String methodName;
5012 :
5013 172 : if(regridQuant=="" ||
5014 65 : (regridCenter<-1E30 && regridBandwidth <= 0. && regridChanWidth <= 1.
5015 63 : && regridQuant=="chan")
5016 : ){
5017 : // No regridding will take place.
5018 : // Set the interpol methods to some dummy value
5019 0 : theMethod = (Int) InterpolateArray1D<Double,Complex>::linear;
5020 0 : methodName = "linear";
5021 0 : message = " output frame = " + MFrequency::showType(theFrame) + " (pure transformation of the channel definition)";
5022 : // cout << regridQuant << " " << regridCenter << " " << regridBandwidth << " " << regridChanWidth << endl;
5023 : }
5024 : else { // a regrid quantity was chosen
5025 : // determine interpolation method (this is common for all possible
5026 : // values of regridQuant)
5027 107 : String meth=regridInterpMeth;
5028 107 : meth.downcase();
5029 107 : if(meth.contains("nearest")){
5030 0 : theMethod = (Int) InterpolateArray1D<Double,Complex>::nearestNeighbour;
5031 0 : methodName = "nearestNeighbour";
5032 : }
5033 107 : else if(meth.contains("splin")){
5034 0 : theMethod = (Int) InterpolateArray1D<Double,Complex>::spline;
5035 0 : methodName = "spline";
5036 : }
5037 107 : else if(meth.contains("cub")){
5038 0 : theMethod = (Int) InterpolateArray1D<Double,Complex>::cubic;
5039 0 : methodName = "cubic spline";
5040 : }
5041 107 : else if(meth.contains("fft")){
5042 : // check if input grid is equidistant in frequency
5043 11 : Bool isEquidistant = true;
5044 11 : Double sep = fabs(transCHAN_WIDTH(0));
5045 1088 : for(uInt i=1; i<transCHAN_WIDTH.size(); i++){
5046 1083 : if((fabs(transCHAN_WIDTH(i)-transCHAN_WIDTH(i-1))>0.1)
5047 1083 : || fabs(fabs(transNewXin(i)-transNewXin(i-1))-sep)>0.1 ){
5048 6 : isEquidistant = false;
5049 6 : break;
5050 : }
5051 1077 : sep = fabs(transNewXin(i)-transNewXin(i-1));
5052 : }
5053 :
5054 11 : if(isEquidistant){
5055 5 : theMethod = (Int) useFFTShift;
5056 5 : methodName = "fftshift";
5057 : }
5058 : else{
5059 6 : theMethod = (Int) useLinIntThenFFTShift;
5060 6 : methodName = "fftshift (preceeded by a linear transform to make grid equidistant)";
5061 : }
5062 : // for this method to work, the output grid needs to be equidistant in frequency
5063 12 : if(!(regridQuant=="freq" || regridQuant=="vrad"
5064 1 : || (regridQuant=="chan" && isEquidistant) // (chan equidistance depends on input grid)
5065 : )){
5066 : os << LogIO::SEVERE
5067 : << "Parameter \"interpolation\" value \"" << meth << "\" requires an output grid equidistant in frequency."
5068 : << endl << "Cannot proceed."
5069 1 : << LogIO::POST;
5070 1 : return false;
5071 : }
5072 : }
5073 : else {
5074 96 : if(!meth.contains("linear") && meth!=""){
5075 : os << LogIO::WARN
5076 : << "Parameter \"interpolation\" value \"" << meth << "\" is invalid."
5077 0 : << LogIO::POST;
5078 0 : return false;
5079 : }
5080 96 : theMethod = (Int) InterpolateArray1D<Double,Complex>::linear;
5081 96 : methodName = "linear";
5082 : }
5083 :
5084 106 : Vector<Double> newChanLoBound;
5085 106 : Vector<Double> newChanHiBound;
5086 :
5087 106 : if(!regridChanBounds(newChanLoBound,
5088 : newChanHiBound,
5089 : regridCenter,
5090 : regridBandwidth,
5091 : regridChanWidth,
5092 : regridVeloRestfrq,
5093 : regridQuant,
5094 : transNewXin,
5095 : transCHAN_WIDTH,
5096 : message,
5097 : centerIsStart,
5098 : startIsEnd,
5099 : nchan,
5100 : width,
5101 : start
5102 : )
5103 : ){ // there was an error
5104 0 : os << LogIO::SEVERE << message << LogIO::POST;
5105 0 : throw(AipsError("Regridding failed."));
5106 : //return false;
5107 : }
5108 :
5109 : // we have a useful set of channel boundaries
5110 106 : newNUM_CHAN = newChanLoBound.size();
5111 :
5112 106 : if(theMethod==(Int) useFFTShift
5113 4 : && newNUM_CHAN != oldNUM_CHAN){ // need to precede by lin. interpol. after all
5114 4 : theMethod = (Int) useLinIntThenFFTShift;
5115 : }
5116 :
5117 106 : message = "input frame = " + MFrequency::showType(theOldRefFrame)
5118 318 : + ", output frame = " + MFrequency::showType(theFrame)
5119 106 : + "\n" + message + " Interpolation Method = " + methodName;
5120 :
5121 : // complete the calculation of the new spectral window parameters
5122 : // from newNUM_CHAN, newChanLoBound, and newChanHiBound
5123 106 : newXout.resize(newNUM_CHAN);
5124 106 : newCHAN_WIDTH.resize(newNUM_CHAN);
5125 106 : newRESOLUTION.resize(newNUM_CHAN);
5126 106 : newEFFECTIVE_BW.resize(newNUM_CHAN);
5127 35616 : for(Int i=0; i<newNUM_CHAN; i++){
5128 35510 : newXout[i] = (newChanLoBound[i]+newChanHiBound[i])/2.;
5129 35510 : newCHAN_WIDTH[i] = newChanHiBound[i]-newChanLoBound[i];
5130 35510 : newRESOLUTION[i] = newCHAN_WIDTH[i]; // to be revisited
5131 35510 : newEFFECTIVE_BW[i] = newCHAN_WIDTH[i]; // to be revisited
5132 : }
5133 : // set the reference frequency to the central frequency of the first channel,
5134 : // keeping the already changed frame
5135 106 : MVFrequency mvf(newXout[0]);
5136 106 : newREF_FREQUENCY.set(mvf);
5137 :
5138 : // trivial definition of the bandwidth (taking into account possibility of descending freqs)
5139 106 : newTOTAL_BANDWIDTH = max(newChanHiBound[newNUM_CHAN-1], newChanHiBound[0])
5140 106 : -min(newChanLoBound[0],newChanLoBound[newNUM_CHAN-1]);
5141 :
5142 : // // effective bandwidth needs to be interpolated in quadrature
5143 : // Vector<Double> newEffBWSquared(newNUM_CHAN);
5144 : // Vector<Double> oldEffBWSquared(oldEFFECTIVE_BW);
5145 : // for(Int i=0; i<oldNUM_CHAN; i++){
5146 : // oldEffBWSquared[i] *= oldEffBWSquared[i];
5147 : // }
5148 : // InterpolateArray1D<Double, Double>::interpolate(newEffBWSquared, newXout,
5149 : // transNewXin,
5150 : // oldEffBWSquared,
5151 : // InterpolateArray1D<Double,Double>::linear);
5152 : // for(uInt i=0; i<newNUM_CHAN; i++){
5153 : // newEFFECTIVE_BW[i] = sqrt(newEffBWSquared[i]);
5154 : // }
5155 :
5156 106 : if(!allEQ(newXout, transNewXin)){ // grids are different
5157 90 : doRegrid = true;
5158 : }
5159 :
5160 107 : } // end if (regridQuant=="" ...
5161 :
5162 106 : if(writeTables && (needTransform || doRegrid)){
5163 : // new SPW amd DD table rows may need to be created
5164 :
5165 : // Create new row in the SPW table (with ID nextSPWId) by copying
5166 : // all information from row theSPWId
5167 45 : if(!spwtable.canAddRow()){
5168 : os << LogIO::WARN
5169 : << "Unable to add new row to SPECTRAL_WINDOW table. Cannot proceed with regridSpw ..."
5170 0 : << LogIO::POST;
5171 0 : return false;
5172 : }
5173 :
5174 45 : numNewSPWIds++;
5175 45 : nextSPWId++;
5176 :
5177 : // prepare parameter string for later entry into MS history and report to logger
5178 : {
5179 45 : ostringstream param;
5180 45 : param << "Regridded spectral window "
5181 45 : << nextSPWId - origNumSPWs << " will be created for field "
5182 45 : << theFieldId << " with parameters " << endl
5183 45 : << message << endl;
5184 45 : regridMessage += param.str(); // append
5185 45 : os << LogIO::NORMAL << param.str() << LogIO::POST;
5186 45 : }
5187 :
5188 45 : spwtable.addRow();
5189 45 : TableRow SPWRow(spwtable);
5190 45 : TableRecord spwRecord = SPWRow.get(theSPWId);
5191 : // TODO Warn if the original channels are not contiguous or overlap!
5192 45 : SPWRow.putMatchingFields(nextSPWId, spwRecord);
5193 :
5194 : // and replacing the following columns with updated information:
5195 : // Store xout as new value of CHAN_FREQ.
5196 45 : chanFreqCol.put(nextSPWId, newXout);
5197 45 : numChanCol.put(nextSPWId, newNUM_CHAN);
5198 45 : chanWidthCol.put(nextSPWId, newCHAN_WIDTH);
5199 45 : refFrequencyCol.put(nextSPWId, newREF_FREQUENCY.getValue());
5200 45 : if(theFrame==MFrequency::GEO){ // i.e. outframe was GEO or SOURCE
5201 3 : measFreqRefCol.put(nextSPWId, (Int)MFrequency::REST);
5202 : }
5203 : else{
5204 42 : measFreqRefCol.put(nextSPWId, (Int)theFrame);
5205 : }
5206 :
5207 45 : totalBandwidthCol.put(nextSPWId, newTOTAL_BANDWIDTH);
5208 45 : effectiveBWCol.put(nextSPWId, newEFFECTIVE_BW);
5209 45 : resolutionCol.put(nextSPWId, newRESOLUTION);
5210 :
5211 45 : msModified = true;
5212 : // Create a new row in the DATA_DESCRIPTION table and enter
5213 : // nextSPWId in the SPW_ID column, copy the polarization id and
5214 : // the flag_row content from the old DATA_DESCRIPTION row.
5215 45 : if(!ddtable.canAddRow()){
5216 : os << LogIO::WARN
5217 : << "Unable to add new row to DATA_DESCRIPTION table. Cannot proceed with regridSpw ..."
5218 0 : << LogIO::POST;
5219 0 : return false;
5220 : }
5221 45 : numNewDataDesc++;
5222 45 : nextDataDescId++;
5223 45 : ddtable.addRow();
5224 45 : TableRow DDRow(ddtable);
5225 45 : TableRecord DDRecord = DDRow.get(theDataDescId);
5226 45 : DDRow.putMatchingFields(nextDataDescId, DDRecord);
5227 :
5228 : // anticipate the deletion of the original SPW table rows
5229 45 : SPWIdCol.put(nextDataDescId, nextSPWId - origNumSPWs);
5230 :
5231 : // writing the value of nextDataDescId into the DATA_DESC_ID cell
5232 : // of the present MAIN table row. will be done in the main regridSpw
5233 : // method
5234 45 : theDataDescId = nextDataDescId;
5235 :
5236 45 : } // end if(writeTables && (needTransform || doRegrid)
5237 :
5238 107 : } // end if there is a reusable SPW row
5239 :
5240 106 : if(writeTables && (needTransform || doRegrid)){
5241 : // a new SOURCE table row has to be created
5242 :
5243 : // Add a row to the SOURCE table by copying the contents from the row
5244 : // identified by the SOURCE_ID cell in the row theFieldId from the
5245 : // FIELD table. Set the value of the cell SPECTRAL_WINDOW_ID in this
5246 : // new row to the value nextSPWId.
5247 45 : if(nextSourceRow>=0){ // there is a source table
5248 38 : if(!p_sourcetable->canAddRow()){
5249 : os << LogIO::WARN
5250 : << "Unable to add new row to SOURCE table. Cannot proceed with regridSpw ..."
5251 0 : << LogIO::POST;
5252 0 : return false;
5253 : }
5254 38 : numNewSourceRows++;
5255 38 : nextSourceRow++;
5256 : // find the row in the SOURCE table which has
5257 : // SOURCE_ID==theSOURCEId and SPW_ID==theSPWId
5258 38 : Int theSOURCEId = FIELDsourceIdCol(theFieldId);
5259 38 : ScalarColumn<Int> SOURCEsourceIdCol = p_sourceCol->sourceId();
5260 38 : ScalarColumn<Int> SOURCESPWIdCol = p_sourceCol->spectralWindowId();
5261 38 : Int foundRow = -1;
5262 68 : for(int i=0; i<nextSourceRow; i++){
5263 68 : if(SOURCEsourceIdCol(i) == theSOURCEId && (SOURCESPWIdCol(i)==theSPWId || SOURCESPWIdCol(i)==-1)){
5264 38 : foundRow = i;
5265 38 : break;
5266 : }
5267 : }
5268 38 : if(foundRow<0){
5269 : os << LogIO::SEVERE << "Incoherent MS: Did not find SOURCE table entry with SOURCE_ID == "
5270 : << theSOURCEId << " and SPECTRAL_WINDOW_ID == " << theSPWId << endl
5271 : <<" even though the FIELD and the DATA_DESCRIPTION table entries for main table row "
5272 : << mainTabRow << " refer to it."
5273 0 : << LogIO::POST;
5274 0 : return false;
5275 : }
5276 : else { // found matching row
5277 38 : p_sourcetable->addRow();
5278 38 : TableRow SOURCERow(*p_sourcetable);
5279 38 : TableRecord SOURCERecord = SOURCERow.get(foundRow);
5280 38 : SOURCERow.putMatchingFields(nextSourceRow, SOURCERecord);
5281 :
5282 : // anticipate the deletion of the original SPW rows
5283 38 : SOURCESPWIdCol.put(nextSourceRow, nextSPWId - origNumSPWs);
5284 38 : newSourceIds.push_back(theSOURCEId);
5285 38 : newSourceSPWIds.push_back(nextSPWId - origNumSPWs);
5286 38 : }
5287 :
5288 38 : } // end if there is a source table
5289 : }
5290 :
5291 106 : weightScale = newCHAN_WIDTH[0]/transCHAN_WIDTH[0]; // = deltaNuNew/deltaNuOld (both in outframe)
5292 :
5293 : //Put a new row into the "done" table.
5294 : // (do all the push_backs in one place)
5295 106 : oldSpwId.push_back(theSPWId);
5296 106 : oldFieldId.push_back(theFieldId);
5297 :
5298 : // anticipate the deletion of the original DD rows
5299 106 : newDataDescId.push_back(theDataDescId - origNumDataDescs);
5300 :
5301 106 : weightScaleV.push_back(weightScale);
5302 106 : xold.push_back(newXin);
5303 106 : xin.push_back(transNewXin);
5304 106 : xout.push_back(newXout);
5305 106 : method.push_back(theMethod);
5306 106 : regrid.push_back(doRegrid);
5307 106 : transform.push_back(needTransform);
5308 106 : theFieldDirV.push_back(theFieldDir);
5309 106 : mObsPosV.push_back(mObsPos);
5310 106 : fromFrameTypeV.push_back(theOldRefFrame);
5311 106 : outFrameV.push_back(outFrame);
5312 106 : outRadVelV.push_back(outRadVel);
5313 :
5314 123 : } // end if(!alreadyDone)
5315 : // reference frame transformation and regridding of channel definition completed
5316 : ////////////////////
5317 :
5318 1291255 : } // end loop over main table
5319 :
5320 106 : if(writeTables && msModified){
5321 : // delete the original rows in DD, SPW, and SOURCE if necessary
5322 45 : if(numNewDataDesc>0){
5323 90 : for(Int i=0; i<origNumDataDescs; i++){
5324 45 : ddtable.removeRow(0);
5325 : }
5326 : }
5327 45 : if(numNewSPWIds>0){
5328 90 : for(Int i=0; i<origNumSPWs; i++){
5329 45 : spwtable.removeRow(0);
5330 : }
5331 : }
5332 45 : if(numNewSourceRows>0){
5333 38 : ScalarColumn<Int> sourceIdCol = p_sourceCol->sourceId();
5334 38 : ScalarColumn<Int> spwIdCol = p_sourceCol->spectralWindowId();
5335 : // delete duplicate rows among the original Source rows
5336 38 : vector<Bool> tBRemRows(origNumSourceRows, false);
5337 1236 : for(Int i=0; i<origNumSourceRows-1; i++){
5338 1198 : if(tBRemRows[i]){
5339 1037 : continue;
5340 : }
5341 161 : Int tSId = sourceIdCol(i);
5342 161 : Int tSpwId = spwIdCol(i);
5343 6700 : for(Int j=i+1; j<origNumSourceRows; j++){
5344 6539 : if(sourceIdCol(j)==tSId && spwIdCol(j)==tSpwId){
5345 1055 : tBRemRows[j]=true;
5346 : }
5347 : }
5348 : }
5349 1236 : for(Int i=origNumSourceRows-1; i>0; i--){
5350 1198 : if(tBRemRows[i]){
5351 1055 : p_sourcetable->removeRow(i);
5352 1055 : origNumSourceRows--;
5353 : }
5354 : }
5355 :
5356 : // delete those original Source rows with Source/SPW ID pairs also present among the new ones
5357 38 : uInt sIndex=0;
5358 219 : for(Int i=0; i<origNumSourceRows; i++){
5359 181 : Bool sFound=false;
5360 325 : for(uInt j=0; j<newSourceIds.size(); j++){
5361 181 : if(sourceIdCol(sIndex)==newSourceIds[j] && spwIdCol(sIndex)==newSourceSPWIds[j]){
5362 37 : sFound=true;
5363 37 : break;
5364 : }
5365 : }
5366 181 : if(sFound){
5367 37 : p_sourcetable->removeRow(sIndex);
5368 : }
5369 : else{
5370 144 : sIndex++;
5371 : }
5372 : }
5373 38 : }
5374 :
5375 : // prepare parameter string for later entry into MS history
5376 45 : ostringstream param;
5377 45 : param << "Added " << numNewDataDesc
5378 45 : << " new rows to the DATA_DESCRIPTION table and deleted "
5379 45 : << origNumDataDescs << " old ones." << endl
5380 45 : << "Added " << numNewSPWIds
5381 45 : << " rows to the SPECTRAL_WINDOW table and deleted " << origNumSPWs
5382 45 : << " old ones." << endl
5383 45 : << "Added " << numNewSourceRows
5384 45 : << " rows to the SOURCE table and deleted " << origNumSourceRows
5385 45 : << " old ones.";
5386 45 : regridMessage += param.str() + "\n"; // append
5387 :
5388 45 : os << LogIO::NORMAL << param.str() << LogIO::POST;
5389 45 : }
5390 :
5391 106 : delete p_sourceCol;
5392 :
5393 106 : return rval;
5394 107 : }
5395 :
5396 :
5397 206 : Bool SubMS::combineSpws(const Vector<Int>& spwids,
5398 : const Bool noModify,
5399 : Vector<Double>& newCHAN_FREQ,
5400 : Vector<Double>& newCHAN_WIDTH,
5401 : Bool verbose){
5402 :
5403 :
5404 : using casacore::operator*;
5405 :
5406 412 : LogIO os(LogOrigin("SubMS", "combineSpws()"));
5407 :
5408 : // Analyse spwids
5409 :
5410 206 : if(spwids.nelements()==0){
5411 0 : os << LogIO::WARN << "No SPWs selected for combination ..." << LogIO::POST;
5412 0 : return true;
5413 : }
5414 :
5415 206 : String tempNewName = ms_p.tableName()+".spwCombined"; // temporary name for the MS to store the result
5416 :
5417 : { // begin scope for MS related objects
5418 :
5419 : // find all existing spws,
5420 206 : MSSpectralWindow spwtable = ms_p.spectralWindow();
5421 206 : Int origNumSPWs = spwtable.nrow();
5422 206 : Int newSPWId = origNumSPWs;
5423 :
5424 206 : vector<Int> spwsToCombine;
5425 206 : Vector<Bool> includeIt(origNumSPWs, false);
5426 :
5427 : // jagonzal: This covers for the case when we want to combine all the input SPWs
5428 206 : if(spwids(0) == -1)
5429 : {
5430 336 : for(Int i=0; i<origNumSPWs; i++)
5431 : {
5432 282 : spwsToCombine.push_back(i);
5433 282 : includeIt(i) = true;
5434 : }
5435 : }
5436 : // jagonzal: Nominal case when we want to combine a sub-set of the input SPWs
5437 : else
5438 : {
5439 760 : for(uInt i=0; i<spwids.nelements(); i++)
5440 : {
5441 608 : if(spwids(i)<origNumSPWs && spwids(i)>=0)
5442 : {
5443 608 : spwsToCombine.push_back(spwids(i));
5444 608 : includeIt(spwids(i)) = true;
5445 : }
5446 : else
5447 : {
5448 0 : os << LogIO::SEVERE << "Invalid SPW ID selected for combination " << spwids(i)
5449 0 : << "valid range is 0 - " << origNumSPWs-1 << ")" << LogIO::POST;
5450 0 : return false;
5451 : }
5452 : }
5453 : }
5454 : // jagonzal: Marginal case when there is no actual SPW combination
5455 206 : if(spwsToCombine.size()<=1)
5456 : {
5457 24 : if(verbose)
5458 : {
5459 24 : os << LogIO::NORMAL << "Less than two SPWs selected. No combination necessary." << LogIO::POST;
5460 : }
5461 24 : return true;
5462 : }
5463 :
5464 : // sort the spwids
5465 182 : std::sort(spwsToCombine.begin(), spwsToCombine.end());
5466 :
5467 182 : uInt nSpwsToCombine = spwsToCombine.size();
5468 :
5469 : // prepare access to the SPW table
5470 182 : MSSpWindowColumns SPWColrs(spwtable);
5471 182 : ScalarColumn<Int> numChanColr = SPWColrs.numChan();
5472 182 : ArrayColumn<Double> chanFreqColr = SPWColrs.chanFreq();
5473 182 : ArrayColumn<Double> chanWidthColr = SPWColrs.chanWidth();
5474 : // ArrayMeasColumn<MFrequency> chanFreqMeasColr = SPWColrs.chanFreqMeas();
5475 182 : ScalarColumn<Int> measFreqRefColr = SPWColrs.measFreqRef();
5476 182 : ArrayColumn<Double> effectiveBWColr = SPWColrs.effectiveBW();
5477 182 : ScalarColumn<Double> refFrequencyColr = SPWColrs.refFrequency();
5478 : // ScalarMeasColumn<MFrequency> refFrequencyMeasColr = SPWColrs.refFrequencyMeas();
5479 182 : ArrayColumn<Double> resolutionColr = SPWColrs.resolution();
5480 182 : ScalarColumn<Double> totalBandwidthColr = SPWColrs.totalBandwidth();
5481 :
5482 : // create a list of the spw ids sorted by first (lowest) channel frequency
5483 182 : vector<Int> spwsSorted(nSpwsToCombine);
5484 182 : Vector<Bool> isDescending(origNumSPWs, false);
5485 182 : Bool negChanWidthWarned = false;
5486 : {
5487 182 : Double* firstFreq = new Double[nSpwsToCombine];
5488 182 : uInt count = 0;
5489 1259 : for(uInt i=0; (Int)i<origNumSPWs; i++){
5490 1077 : if(includeIt(i)){
5491 857 : Vector<Double> CHAN_FREQ(chanFreqColr(i));
5492 : // if frequencies are ascending, take the first channel, otherwise the last
5493 857 : uInt nCh = CHAN_FREQ.nelements();
5494 857 : if(CHAN_FREQ(0)<=CHAN_FREQ(nCh-1)){
5495 809 : firstFreq[count] = CHAN_FREQ(0);
5496 : }
5497 : else{
5498 48 : firstFreq[count] = CHAN_FREQ(nCh-1);
5499 48 : isDescending(i) = true;
5500 : }
5501 857 : count++;
5502 857 : }
5503 : }
5504 182 : Sort sort;
5505 182 : sort.sortKey (firstFreq, TpDouble); // define sort key
5506 182 : Vector<uInt> inx(nSpwsToCombine);
5507 182 : sort.sort(inx, nSpwsToCombine);
5508 1048 : for (uInt i=0; i<nSpwsToCombine; i++) {
5509 866 : spwsSorted[i] = spwsToCombine[inx(i)];
5510 : }
5511 182 : delete[] firstFreq;
5512 182 : }
5513 :
5514 182 : Int id0 = spwsSorted[0];
5515 :
5516 182 : uInt newNUM_CHAN = numChanColr(id0);
5517 182 : newCHAN_FREQ.assign(chanFreqColr(id0));
5518 182 : newCHAN_WIDTH.assign(chanWidthColr(id0));
5519 182 : Bool newIsDescending = isDescending(id0);
5520 : {
5521 182 : Bool negativeWidths = false;
5522 6222 : for(uInt i=0; i<newNUM_CHAN; i++){
5523 6040 : if(newCHAN_WIDTH(i) < 0.){
5524 256 : negativeWidths = true;
5525 256 : newCHAN_WIDTH(i) = -newCHAN_WIDTH(i);
5526 : }
5527 : }
5528 182 : if(negativeWidths && verbose){
5529 : os << LogIO::NORMAL
5530 : << " *** Encountered negative channel widths in SPECTRAL_WINDOW table."
5531 1 : << LogIO::POST;
5532 1 : negChanWidthWarned = true;
5533 : }
5534 : }
5535 :
5536 182 : if(newIsDescending){ // need to reverse the order for processing
5537 2 : Vector<Double> tempF, tempW;
5538 2 : tempF.assign(newCHAN_FREQ);
5539 2 : tempW.assign(newCHAN_WIDTH);
5540 258 : for(uInt i=0; i<newNUM_CHAN; i++){
5541 256 : newCHAN_FREQ(i) = tempF(newNUM_CHAN-1-i);
5542 256 : newCHAN_WIDTH(i) = tempW(newNUM_CHAN-1-i);
5543 : }
5544 2 : }
5545 :
5546 182 : Vector<Double> newEFFECTIVE_BW(effectiveBWColr(id0));
5547 182 : Double newREF_FREQUENCY(refFrequencyColr(id0));
5548 : //MFrequency newREF_FREQUENCY = refFrequencyMeasColr(id0);
5549 182 : Int newMEAS_FREQ_REF = measFreqRefColr(id0);
5550 182 : Vector<Double> newRESOLUTION(resolutionColr(id0));
5551 182 : Double newTOTAL_BANDWIDTH = totalBandwidthColr(id0);
5552 :
5553 182 : vector<Int> averageN; // for each new channel store the number of old channels to average over
5554 182 : vector<vector<Int> > averageWhichSPW; // for each new channel store the
5555 : // (old) SPWs to average over
5556 182 : vector<vector<Int> > averageWhichChan; // for each new channel store the
5557 : // channel numbers to av. over
5558 182 : vector<vector<Double> > averageChanFrac; // for each new channel store the
5559 : // channel fraction for each old channel
5560 :
5561 : // initialise the averaging vectors
5562 6222 : for(uInt i=0; i<newNUM_CHAN; i++){
5563 6040 : averageN.push_back(1);
5564 6040 : vector<Int> tv; // just a temporary auxiliary vector
5565 6040 : tv.push_back(id0);
5566 6040 : averageWhichSPW.push_back(tv);
5567 6040 : if(newIsDescending){
5568 256 : tv[0] = newNUM_CHAN-1-i;
5569 : }
5570 : else{
5571 5784 : tv[0] = i;
5572 : }
5573 6040 : averageWhichChan.push_back(tv);
5574 6040 : vector<Double> tvd; // another one
5575 6040 : tvd.push_back(1.);
5576 6040 : averageChanFrac.push_back(tvd);
5577 6040 : }
5578 :
5579 182 : if(verbose){
5580 49 : os << LogIO::NORMAL << "Input SPWs sorted by first (lowest) channel frequency:" << LogIO::POST;
5581 :
5582 49 : ostringstream oss; // needed for iomanip functions
5583 49 : oss << " SPW " << std::setw(3) << id0 << ": " << std::setw(5) << newNUM_CHAN
5584 49 : << " channels, first channel = " << std::setprecision(9) << std::setw(14) << std::scientific << newCHAN_FREQ(0) << " Hz";
5585 49 : if(newNUM_CHAN>1){
5586 39 : oss << ", last channel = " << std::setprecision(9) << std::setw(14) << std::scientific << newCHAN_FREQ(newNUM_CHAN-1) << " Hz";
5587 : }
5588 49 : os << LogIO::NORMAL << oss.str() << LogIO::POST;
5589 49 : }
5590 :
5591 : // loop over remaining given spws
5592 866 : for(uInt i=1; i<nSpwsToCombine; i++){
5593 684 : Int idi = spwsSorted[i];
5594 :
5595 684 : uInt newNUM_CHANi = numChanColr(idi);
5596 684 : Vector<Double> newCHAN_FREQi(chanFreqColr(idi));
5597 684 : Vector<Double> newCHAN_WIDTHi(chanWidthColr(idi));
5598 684 : Bool newIsDescendingI = isDescending(idi);
5599 : {
5600 684 : Bool negativeWidths = false;
5601 61068 : for(uInt ii=0; ii<newNUM_CHANi; ii++){
5602 60384 : if(newCHAN_WIDTHi(ii) < 0.){
5603 5888 : negativeWidths = true;
5604 5888 : newCHAN_WIDTHi(ii) = -newCHAN_WIDTHi(ii);
5605 : }
5606 : }
5607 684 : if(negativeWidths && !negChanWidthWarned && verbose){
5608 : os << LogIO::NORMAL
5609 : << " *** Encountered negative channel widths in SPECTRAL_WINDOW table."
5610 0 : << LogIO::POST;
5611 0 : negChanWidthWarned = true;
5612 : }
5613 : }
5614 684 : if(newIsDescendingI){ // need to reverse the order for processing
5615 46 : Vector<Double> tempF, tempW;
5616 46 : tempF.assign(newCHAN_FREQi);
5617 46 : tempW.assign(newCHAN_WIDTHi);
5618 5934 : for(uInt ii=0; ii<newNUM_CHANi; ii++){
5619 5888 : newCHAN_FREQi(ii) = tempF(newNUM_CHANi-1-ii);
5620 5888 : newCHAN_WIDTHi(ii) = tempW(newNUM_CHANi-1-ii);
5621 : }
5622 46 : }
5623 :
5624 684 : Vector<Double> newEFFECTIVE_BWi(effectiveBWColr(idi));
5625 : //Double newREF_FREQUENCYi(refFrequencyColr(idi));
5626 : //MFrequency newREF_FREQUENCYi = refFrequencyMeasColr(idi);
5627 684 : Int newMEAS_FREQ_REFi = measFreqRefColr(idi);
5628 684 : Vector<Double> newRESOLUTIONi(resolutionColr(idi));
5629 : //Double newTOTAL_BANDWIDTHi = totalBandwidthColr(idi);
5630 :
5631 684 : if(verbose){
5632 265 : ostringstream oss; // needed for iomanip functions
5633 265 : oss << " SPW " << std::setw(3) << idi << ": " << std::setw(5) << newNUM_CHANi
5634 265 : << " channels, first channel = " << std::setprecision(9) << std::setw(14) << std::scientific << newCHAN_FREQi(0) << " Hz";
5635 265 : if(newNUM_CHANi>1){
5636 255 : oss << ", last channel = " << std::setprecision(9) << std::setw(14) << std::scientific << newCHAN_FREQi(newNUM_CHANi-1) << " Hz";
5637 : }
5638 265 : os << LogIO::NORMAL << oss.str() << LogIO::POST;
5639 265 : }
5640 :
5641 684 : vector<Double> mergedChanFreq;
5642 684 : vector<Double> mergedChanWidth;
5643 684 : vector<Double> mergedEffBW;
5644 684 : vector<Double> mergedRes;
5645 684 : vector<Int> mergedAverageN;
5646 684 : vector<vector<Int> > mergedAverageWhichSPW;
5647 684 : vector<vector<Int> > mergedAverageWhichChan;
5648 684 : vector<vector<Double> > mergedAverageChanFrac;
5649 :
5650 : // check for compatibility
5651 684 : if(newMEAS_FREQ_REFi != newMEAS_FREQ_REF){
5652 : os << LogIO::WARN
5653 : << "SPW " << idi << " cannot be combined with SPW " << id0 << ". Non-matching ref. frame."
5654 0 : << LogIO::POST;
5655 0 : return false;
5656 : }
5657 :
5658 : // append or prepend spw to new spw
5659 : // overlap at all?
5660 684 : if(newCHAN_FREQ(newNUM_CHAN-1) + newCHAN_WIDTH(newNUM_CHAN-1)/2.
5661 684 : < newCHAN_FREQi(0) - newCHAN_WIDTHi(0)/2.) {
5662 : // no overlap, and need to append
5663 1563 : for(uInt j=0; j<newNUM_CHAN; j++){
5664 1548 : mergedChanFreq.push_back(newCHAN_FREQ(j));
5665 1548 : mergedChanWidth.push_back(newCHAN_WIDTH(j));
5666 1548 : mergedEffBW.push_back(newEFFECTIVE_BW(j));
5667 1548 : mergedRes.push_back(newRESOLUTION(j));
5668 1548 : mergedAverageN.push_back(averageN[j]);
5669 1548 : mergedAverageWhichSPW.push_back(averageWhichSPW[j]);
5670 1548 : mergedAverageWhichChan.push_back(averageWhichChan[j]);
5671 1548 : mergedAverageChanFrac.push_back(averageChanFrac[j]);
5672 : }
5673 15 : vector<Int> tv;
5674 15 : tv.push_back(idi); // origin is spw idi
5675 15 : vector<Int> tv2;
5676 15 : tv2.push_back(0);
5677 15 : vector<Double> tvd;
5678 15 : tvd.push_back(1.); // fraction is 1.
5679 1563 : for(uInt j=0; j<newNUM_CHANi; j++){
5680 1548 : mergedChanFreq.push_back(newCHAN_FREQi(j));
5681 1548 : mergedChanWidth.push_back(newCHAN_WIDTHi(j));
5682 1548 : mergedEffBW.push_back(newEFFECTIVE_BWi(j));
5683 1548 : mergedRes.push_back(newRESOLUTIONi(j));
5684 1548 : mergedAverageN.push_back(1); // so far only one channel
5685 1548 : mergedAverageWhichSPW.push_back(tv);
5686 1548 : if(newIsDescendingI){
5687 0 : tv2[0] = newNUM_CHANi-1-j;
5688 : }
5689 : else{
5690 1548 : tv2[0] = j;
5691 : }
5692 1548 : mergedAverageWhichChan.push_back(tv2); // channel number is j
5693 1548 : mergedAverageChanFrac.push_back(tvd);
5694 : }
5695 15 : }
5696 669 : else if( newCHAN_FREQ(0) - newCHAN_WIDTH(0)/2.
5697 669 : > newCHAN_FREQi(newNUM_CHANi-1) + newCHAN_WIDTHi(newNUM_CHANi-1)/2.){
5698 : // no overlap, need to prepend
5699 0 : vector<Int> tv;
5700 0 : tv.push_back(idi); // origin is spw idi
5701 0 : vector<Int> tv2;
5702 0 : tv2.push_back(0);
5703 0 : vector<Double> tvd;
5704 0 : tvd.push_back(1.); // fraction is 1.
5705 0 : for(uInt j=0; j<newNUM_CHANi; j++){
5706 0 : mergedChanFreq.push_back(newCHAN_FREQi(j));
5707 0 : mergedChanWidth.push_back(newCHAN_WIDTHi(j));
5708 0 : mergedEffBW.push_back(newEFFECTIVE_BWi(j));
5709 0 : mergedRes.push_back(newRESOLUTIONi(j));
5710 0 : mergedAverageN.push_back(1); // so far only one channel
5711 0 : mergedAverageWhichSPW.push_back(tv);
5712 0 : if(newIsDescendingI){
5713 0 : tv2[0] = newNUM_CHANi-1-j;
5714 : }
5715 : else{
5716 0 : tv2[0] = j;
5717 : }
5718 0 : mergedAverageWhichChan.push_back(tv2); // channel number is j
5719 0 : mergedAverageChanFrac.push_back(tvd);
5720 : }
5721 0 : for(uInt j=0; j<newNUM_CHAN; j++){
5722 0 : mergedChanFreq.push_back(newCHAN_FREQ(j));
5723 0 : mergedChanWidth.push_back(newCHAN_WIDTH(j));
5724 0 : mergedEffBW.push_back(newEFFECTIVE_BW(j));
5725 0 : mergedRes.push_back(newRESOLUTION(j));
5726 0 : mergedAverageN.push_back(averageN[j]);
5727 0 : mergedAverageWhichSPW.push_back(averageWhichSPW[j]);
5728 0 : mergedAverageWhichChan.push_back(averageWhichChan[j]);
5729 0 : mergedAverageChanFrac.push_back(averageChanFrac[j]);
5730 : }
5731 0 : }
5732 : else{ // there is overlap
5733 669 : Int id0StartChan = 0;
5734 669 : if(newCHAN_FREQi(0) - newCHAN_WIDTHi(0)/2. <
5735 669 : newCHAN_FREQ(newNUM_CHAN-1) - newCHAN_WIDTH(newNUM_CHAN-1)/2.){
5736 : // spw idi starts before spw id0
5737 :
5738 : // some utilities for the averaging info
5739 646 : vector<Int> tv; // temporary vector
5740 646 : tv.push_back(idi); // origin is spw idi
5741 646 : vector<Int> tv2;
5742 646 : tv2.push_back(0);
5743 646 : vector<Double> tvd;
5744 646 : tvd.push_back(1.); // fraction is 1.
5745 :
5746 : // find the first overlapping channel and prepend non-overlapping channels
5747 646 : Double ubound0 = newCHAN_FREQ(0) + newCHAN_WIDTH(0)/2.;
5748 646 : Double lbound0 = newCHAN_FREQ(0) - newCHAN_WIDTH(0)/2.;
5749 646 : Double uboundk = 0.;
5750 646 : Double lboundk = 0.;
5751 : uInt k;
5752 646 : for(k=0; k<newNUM_CHANi; k++){
5753 646 : uboundk = newCHAN_FREQi(k) + newCHAN_WIDTHi(k)/2.;
5754 646 : lboundk = newCHAN_FREQi(k) - newCHAN_WIDTHi(k)/2.;
5755 646 : if(lbound0 < uboundk){
5756 646 : break;
5757 : }
5758 0 : mergedChanFreq.push_back(newCHAN_FREQi(k));
5759 0 : mergedChanWidth.push_back(newCHAN_WIDTHi(k));
5760 0 : mergedEffBW.push_back(newEFFECTIVE_BWi(k));
5761 0 : mergedRes.push_back(newRESOLUTIONi(k));
5762 0 : mergedAverageN.push_back(1); // so far only one channel
5763 0 : mergedAverageWhichSPW.push_back(tv);
5764 0 : if(newIsDescendingI){
5765 0 : tv2[0] = newNUM_CHANi-1-k;
5766 : }
5767 : else{
5768 0 : tv2[0] = k;
5769 : }
5770 0 : mergedAverageWhichChan.push_back(tv2); // channel number is k
5771 0 : mergedAverageChanFrac.push_back(tvd);
5772 : }
5773 : // k's the one
5774 646 : if(lbound0 < uboundk && lboundk < lbound0){ // actual overlap, need to merge channel k with channel 0
5775 0 : Double newWidth = ubound0 - lboundk;
5776 0 : Double newCenter = lboundk + newWidth/2.;
5777 0 : mergedChanFreq.push_back(newCenter);
5778 0 : mergedChanWidth.push_back(newWidth);
5779 0 : mergedEffBW.push_back(newWidth);
5780 0 : mergedRes.push_back(newWidth);
5781 0 : mergedAverageN.push_back(averageN[0]+1); // one more channel contributes
5782 : // channel k is from spw idi
5783 0 : if(newIsDescendingI){
5784 0 : tv2[0] = newNUM_CHANi-1-k;
5785 : }
5786 : else{
5787 0 : tv2[0] = k;
5788 : }
5789 0 : for(int j=0; j<averageN[0]; j++){
5790 0 : tv.push_back(averageWhichSPW[0][j]); // additional contributors
5791 0 : tv2.push_back(averageWhichChan[0][j]); // channel 0 from spw id0
5792 0 : tvd.push_back(averageChanFrac[0][j]);
5793 : }
5794 0 : mergedAverageWhichSPW.push_back(tv);
5795 0 : mergedAverageWhichChan.push_back(tv2);
5796 0 : mergedAverageChanFrac.push_back(tvd);
5797 0 : id0StartChan = 1;
5798 : }
5799 646 : }
5800 : // now move along SPW id0 and merge until end of id0 is reached, then just copy
5801 539600 : for(uInt j=id0StartChan; j<newNUM_CHAN; j++){
5802 538931 : mergedChanFreq.push_back(newCHAN_FREQ(j));
5803 538931 : mergedChanWidth.push_back(newCHAN_WIDTH(j));
5804 538931 : mergedEffBW.push_back(newEFFECTIVE_BW(j));
5805 538931 : mergedRes.push_back(newRESOLUTION(j));
5806 69322717 : for(uInt k=0; k<newNUM_CHANi; k++){
5807 68783786 : Double overlap_frac = 0.;
5808 : // does channel j in spw id0 overlap with channel k in spw idi?
5809 68783786 : Double uboundj = newCHAN_FREQ(j) + newCHAN_WIDTH(j)/2.;
5810 68783786 : Double uboundk = newCHAN_FREQi(k) + newCHAN_WIDTHi(k)/2.;
5811 68783786 : Double lboundj = newCHAN_FREQ(j) - newCHAN_WIDTH(j)/2.;
5812 68783786 : Double lboundk = newCHAN_FREQi(k) - newCHAN_WIDTHi(k)/2.;
5813 : // determine fraction
5814 68783786 : if(lboundj <= lboundk && uboundk <= uboundj){ // chan k is completely covered by chan j
5815 2050 : overlap_frac = 1.;
5816 : //cout << "j " << j << " k " << k << " case 1" << endl;
5817 : //cout << "overlap " << overlap_frac << endl;
5818 : }
5819 68781736 : else if(lboundk <= lboundj && uboundj <= uboundk){ // chan j is completely covered by chan k
5820 0 : overlap_frac = newCHAN_WIDTH(j)/newCHAN_WIDTHi(k);
5821 : //cout << "j " << j << " k " << k << " case 2" << endl;
5822 : //cout << "overlap " << overlap_frac << endl;
5823 : }
5824 68781736 : else if(lboundj < lboundk && lboundk < uboundj && uboundj < uboundk){ // lower end of k is overlapping with j
5825 12841 : overlap_frac = (uboundj - lboundk)/newCHAN_WIDTHi(k);
5826 : //cout << "j " << j << " k " << k << " case 3" << endl;
5827 : //cout << "overlap " << overlap_frac << endl;
5828 : }
5829 68768895 : else if(lboundk < lboundj && lboundj < uboundk && lboundj < uboundk){ // upper end of k is overlapping with j
5830 12400 : overlap_frac = (uboundk - lboundj)/newCHAN_WIDTHi(k);
5831 : //cout << "j " << j << " k " << k << " case 4" << endl;
5832 : //cout << "overlap " << overlap_frac << endl;
5833 : }
5834 68783786 : if(overlap_frac > 0.){ // update averaging info
5835 27291 : averageN[j] += 1;
5836 27291 : averageWhichSPW[j].push_back(idi);
5837 27291 : if(newIsDescendingI){
5838 2538 : averageWhichChan[j].push_back(newNUM_CHANi-1-k);
5839 : }
5840 : else{
5841 24753 : averageWhichChan[j].push_back(k);
5842 : }
5843 27291 : averageChanFrac[j].push_back(overlap_frac);
5844 : }
5845 : } // end loop over spw idi
5846 : // append this channel with updated averaging info
5847 538931 : mergedAverageN.push_back(averageN[j]);
5848 538931 : mergedAverageWhichSPW.push_back(averageWhichSPW[j]);
5849 538931 : mergedAverageWhichChan.push_back(averageWhichChan[j]);
5850 538931 : mergedAverageChanFrac.push_back(averageChanFrac[j]);
5851 : } // end loop over spw id0
5852 669 : if(newCHAN_FREQ(newNUM_CHAN-1) + newCHAN_WIDTH(newNUM_CHAN-1)/2.
5853 669 : < newCHAN_FREQi(newNUM_CHANi-1) + newCHAN_WIDTHi(newNUM_CHANi-1)/2.){// spw idi still continues!
5854 : // find the last overlapping channel
5855 464 : Int j = newNUM_CHAN-1;
5856 464 : Double uboundj = newCHAN_FREQ(j) + newCHAN_WIDTH(j)/2.;
5857 464 : Double lboundj = newCHAN_FREQ(j) - newCHAN_WIDTH(j)/2.;
5858 464 : Double uboundk = 0;
5859 464 : Double lboundk = 0;
5860 : Int k;
5861 44386 : for(k=newNUM_CHANi-1; k>=0; k--){
5862 44386 : uboundk = newCHAN_FREQi(k) + newCHAN_WIDTHi(k)/2.;
5863 44386 : lboundk = newCHAN_FREQi(k) - newCHAN_WIDTHi(k)/2.;
5864 44386 : if(lboundk <= uboundj){
5865 464 : break;
5866 : }
5867 : }
5868 : // k's the one
5869 464 : if(lboundk < uboundj && uboundj < uboundk ){ // actual overlap
5870 441 : Double overlap_frac = (uboundj - lboundk)/newCHAN_WIDTHi(k);
5871 441 : if(overlap_frac>0.01){ // merge channel k completely with channel j
5872 439 : Double newWidth = uboundk - lboundj;
5873 439 : Double newCenter = (lboundj+uboundk)/2.;
5874 439 : mergedChanFreq[j] = newCenter;
5875 439 : mergedChanWidth[j] = newWidth;
5876 439 : mergedEffBW[j] = newWidth;
5877 439 : mergedRes[j] = newWidth;
5878 439 : mergedAverageChanFrac[j][mergedAverageN[j]-1] = 1.;
5879 : }
5880 : else{ // create separate, (slightly) more narrow channel
5881 2 : Double newWidth = uboundk - uboundj;
5882 2 : Double newCenter = (uboundj+uboundk)/2.;
5883 2 : vector<Int> tv;
5884 2 : tv.push_back(idi); // origin is spw idi
5885 2 : vector<Int> tv2;
5886 2 : tv2.push_back(0);
5887 2 : vector<Double> tvd;
5888 2 : tvd.push_back(1.); // fraction is 1.
5889 2 : mergedChanFreq.push_back(newCenter);
5890 2 : mergedChanWidth.push_back(newWidth);
5891 2 : mergedEffBW.push_back(newWidth);
5892 2 : mergedRes.push_back(newWidth);
5893 2 : mergedAverageN.push_back(1); // so far only one channel
5894 2 : mergedAverageWhichSPW.push_back(tv);
5895 2 : if(newIsDescendingI){
5896 0 : tv2[0] = newNUM_CHANi-1-k;
5897 : }
5898 : else{
5899 2 : tv2[0] = k;
5900 : }
5901 2 : mergedAverageWhichChan.push_back(tv2); // channel number is k
5902 2 : mergedAverageChanFrac.push_back(tvd);
5903 2 : }
5904 441 : k++; // start appending remaining channels after k
5905 : }
5906 : // append the remaining channels
5907 464 : vector<Int> tv;
5908 464 : tv.push_back(idi); // origin is spw idi
5909 464 : vector<Int> tv2;
5910 464 : tv2.push_back(0);
5911 464 : vector<Double> tvd;
5912 464 : tvd.push_back(1.); // fraction is 1.
5913 44409 : for(uInt m=k; m<newNUM_CHANi; m++){
5914 43945 : mergedChanFreq.push_back(newCHAN_FREQi(m));
5915 43945 : mergedChanWidth.push_back(newCHAN_WIDTHi(m));
5916 43945 : mergedEffBW.push_back(newEFFECTIVE_BWi(m));
5917 43945 : mergedRes.push_back(newRESOLUTIONi(m));
5918 43945 : mergedAverageN.push_back(1); // so far only one channel
5919 43945 : mergedAverageWhichSPW.push_back(tv);
5920 43945 : if(newIsDescendingI){
5921 4596 : tv2[0] = newNUM_CHANi-1-m;
5922 : }
5923 : else{
5924 39349 : tv2[0] = m;
5925 : }
5926 43945 : mergedAverageWhichChan.push_back(tv2); // channel number is m
5927 43945 : mergedAverageChanFrac.push_back(tvd);
5928 : }
5929 464 : } // end if spw idi still continues
5930 : } // end if there is overlap
5931 :
5932 :
5933 684 : newNUM_CHAN = mergedChanFreq.size();
5934 684 : newCHAN_FREQ.assign(Vector<Double>(mergedChanFreq));
5935 684 : newCHAN_WIDTH.assign(Vector<Double>(mergedChanWidth));
5936 684 : newEFFECTIVE_BW.assign(Vector<Double>(mergedEffBW));
5937 684 : newREF_FREQUENCY = newCHAN_FREQ(0);
5938 684 : newTOTAL_BANDWIDTH = fabs(newCHAN_FREQ(newNUM_CHAN-1) - newCHAN_FREQ(0))
5939 684 : + fabs(newCHAN_WIDTH(newNUM_CHAN-1)/2.) + fabs(newCHAN_WIDTH(0)/2.);
5940 684 : newRESOLUTION.assign(Vector<Double>(mergedRes));
5941 684 : averageN = mergedAverageN;
5942 684 : averageWhichSPW = mergedAverageWhichSPW;
5943 684 : averageWhichChan = mergedAverageWhichChan;
5944 684 : averageChanFrac = mergedAverageChanFrac;
5945 :
5946 684 : } // end loop over SPWs
5947 :
5948 : // print channel fractions for debugging
5949 : // vector< vector<bool> > wasprinted;
5950 : // for(uInt i=0; i<newNUM_CHAN; i++){
5951 : // vector<bool> tboolv;
5952 : // cout << "i freq width " << i << " " << newCHAN_FREQ(i) << " " << newCHAN_WIDTH(i) << endl;
5953 : // for(Int j=0; j<averageN[i]; j++){
5954 : // cout << " i, j " << i << ", " << j << " averageWhichChan[i][j] " << averageWhichChan[i][j]
5955 : // << " averageWhichSPW[i][j] " << averageWhichSPW[i][j] << endl;
5956 : // cout << " averageChanFrac[i][j] " << averageChanFrac[i][j] << endl;
5957 : // tboolv.push_back(false);
5958 : // }
5959 : // wasprinted.push_back(tboolv);
5960 : // }
5961 :
5962 :
5963 182 : if(noModify){ // newCHAN_FREQ and newCHAN_WIDTH have been determined now
5964 152 : return true;
5965 : }
5966 :
5967 : // now need write access
5968 30 : MSSpWindowColumns SPWCols(spwtable);
5969 30 : ScalarColumn<Int> numChanCol = SPWCols.numChan();
5970 30 : ArrayColumn<Double> chanFreqCol = SPWCols.chanFreq();
5971 30 : ArrayColumn<Double> chanWidthCol = SPWCols.chanWidth();
5972 : // ArrayMeasColumn<MFrequency> chanFreqMeasCol = SPWCols.chanFreqMeas();
5973 30 : ScalarColumn<Int> measFreqRefCol = SPWCols.measFreqRef();
5974 30 : ArrayColumn<Double> effectiveBWCol = SPWCols.effectiveBW();
5975 30 : ScalarColumn<Double> refFrequencyCol = SPWCols.refFrequency();
5976 : // ScalarMeasColumn<MFrequency> refFrequencyMeasCol = SPWCols.refFrequencyMeas();
5977 30 : ArrayColumn<Double> resolutionCol = SPWCols.resolution();
5978 30 : ScalarColumn<Double> totalBandwidthCol = SPWCols.totalBandwidth();
5979 :
5980 30 : if(verbose){
5981 : os << LogIO::NORMAL << "Combined SPW will have " << newNUM_CHAN
5982 30 : << " channels. May change in later regridding." << LogIO::POST;
5983 : }
5984 :
5985 : // Create new row in the SPW table (with ID nextSPWId) by copying
5986 : // all information from row theSPWId
5987 30 : if(!spwtable.canAddRow()){
5988 : os << LogIO::WARN
5989 : << "Unable to add new row to SPECTRAL_WINDOW table. Cannot proceed with spwCombine ..."
5990 0 : << LogIO::POST;
5991 0 : return false;
5992 : }
5993 :
5994 30 : TableRow SPWRow(spwtable);
5995 30 : TableRecord spwRecord = SPWRow.get(id0);
5996 :
5997 : // write new spw to spw table (ID = newSpwId)
5998 30 : spwtable.addRow();
5999 30 : SPWRow.putMatchingFields(newSPWId, spwRecord);
6000 :
6001 30 : chanFreqCol.put(newSPWId, newCHAN_FREQ);
6002 30 : numChanCol.put(newSPWId, newNUM_CHAN);
6003 30 : chanWidthCol.put(newSPWId, newCHAN_WIDTH);
6004 30 : refFrequencyCol.put(newSPWId, newREF_FREQUENCY);
6005 30 : totalBandwidthCol.put(newSPWId, newTOTAL_BANDWIDTH);
6006 30 : effectiveBWCol.put(newSPWId, newEFFECTIVE_BW);
6007 30 : resolutionCol.put(newSPWId, newRESOLUTION);
6008 :
6009 : // delete unwanted spws and memorize the new ID of the new merged one.
6010 : // (remember the IDs were sorted above)
6011 288 : for(int i=nSpwsToCombine-1; i>=0; i--){ // remove highest row numbers first
6012 258 : spwtable.removeRow(spwsToCombine[i]);
6013 : }
6014 30 : newSPWId -= nSpwsToCombine;
6015 :
6016 : // other tables to correct: MAIN, FREQ_OFFSET, SYSCAL, FEED, DATA_DESCRIPTION, SOURCE
6017 :
6018 : // 1) SOURCE (an optional table)
6019 30 : uInt numSourceRows = 0;
6020 30 : MSSource* p_sourcetable = NULL;
6021 30 : MSSourceColumns* p_sourceCol = NULL;
6022 30 : if(Table::isReadable(ms_p.sourceTableName())){
6023 30 : p_sourcetable = &(ms_p.source());
6024 30 : p_sourceCol = new MSSourceColumns(*p_sourcetable);
6025 30 : numSourceRows = p_sourcetable->nrow();
6026 30 : ScalarColumn<Int> SOURCESPWIdCol = p_sourceCol->spectralWindowId();
6027 : // loop over source table rows
6028 1317 : for(uInt i=0; i<numSourceRows; i++){
6029 30261 : for(uInt j=0; j<nSpwsToCombine; j++){
6030 : // if spw id affected, replace by newSpwId
6031 28974 : if(SOURCESPWIdCol(i) == spwsToCombine[j]){ // source row i is affected
6032 1286 : SOURCESPWIdCol.put(i, newSPWId);
6033 : }
6034 : } // end for j
6035 : }// end for i
6036 30 : }
6037 0 : else if(verbose){ // there is no source table
6038 0 : os << LogIO::NORMAL << "Note: MS contains no SOURCE table ..." << LogIO::POST;
6039 : }
6040 :
6041 : // 2) DATA_DESCRIPTION
6042 30 : MSDataDescription ddtable = ms_p.dataDescription();
6043 30 : uInt numDataDescs = ddtable.nrow();
6044 30 : MSDataDescColumns DDCols(ddtable);
6045 30 : ScalarColumn<Int> SPWIdCol = DDCols.spectralWindowId();
6046 30 : ScalarColumn<Int> PolIdCol = DDCols.polarizationId();
6047 30 : vector<uInt> affDDIds;
6048 30 : vector<Bool> DDRowsToDelete(numDataDescs, false);
6049 30 : std::map<Int, Int> tempDDIndex; // store relation between old and new DD Ids
6050 30 : std::map<Int, Int> DDtoSPWIndex; // store relation between old DD Ids and old SPW Ids
6051 : // (only for affected SPW IDs)
6052 : // loop over DD table rows
6053 288 : for(uInt i=0; i<numDataDescs; i++){
6054 : // if spw id affected, replace by newSpwId
6055 5526 : for(uInt j=0; j<nSpwsToCombine; j++){
6056 : // if spw id affected, replace by newSpwId
6057 5268 : if(SPWIdCol(i) == spwsToCombine[j]){ // DD row i is affected
6058 : // correct the SPW Id in the DD table
6059 258 : SPWIdCol.put(i, newSPWId);
6060 : // memorize affected DD IDs in affDDIds
6061 258 : affDDIds.push_back(i);
6062 : // store relation between old DD Id and old SPW ID for later use in the modification of the MAIN table
6063 258 : DDtoSPWIndex.insert(std::pair<Int, Int>(i, spwsToCombine[j])); // note: this relation can be many-to-one
6064 : }
6065 : }
6066 : }
6067 : // Find redundant DD IDs
6068 : // loop over DD table rows
6069 288 : for(uInt i=0; i<numDataDescs; i++){
6070 258 : Bool affected = false;
6071 5268 : for(uInt j=0; j<affDDIds.size(); j++){
6072 5040 : if(i == affDDIds[j] && !DDRowsToDelete[i]){
6073 30 : affected = true;
6074 30 : break;
6075 : }
6076 : }
6077 258 : if(!affected){
6078 228 : continue;
6079 : }
6080 : else { // i is an affected row
6081 30 : Int PolIDi = PolIdCol(i);
6082 30 : Int SpwIDi = SPWIdCol(i);
6083 : // loop over following DD table rows
6084 258 : for(uInt j=i+1; j<numDataDescs; j++){
6085 : // if row i and row j redundant?
6086 228 : if(PolIDi == PolIdCol(j) && SpwIDi == SPWIdCol(j)){
6087 : // mark for deletion
6088 228 : DDRowsToDelete[j] = true;
6089 : // fill map for DDrenumbering
6090 228 : tempDDIndex.insert(std::pair<Int, Int>(j, i));
6091 : }
6092 : }
6093 : } // end if affected
6094 : }
6095 : // delete redundant DD rows
6096 30 : Int removed = 0;
6097 288 : for(uInt i=0; i<numDataDescs; i++){
6098 258 : if(DDRowsToDelete[i]){
6099 228 : ddtable.removeRow(i-removed);
6100 228 : removed++;
6101 : }
6102 : else{ // this row is not deleted but changes its number by <removed> due to removal of others
6103 30 : tempDDIndex.insert(std::pair<Int, Int>(i, i-removed));
6104 : }
6105 : }
6106 :
6107 : // 3) FEED
6108 30 : MSFeed feedtable = ms_p.feed();
6109 30 : uInt numFeedRows = feedtable.nrow();
6110 30 : MSFeedColumns feedCols(feedtable);
6111 30 : ScalarColumn<Int> feedSPWIdCol = feedCols.spectralWindowId();
6112 :
6113 : // loop over FEED table rows
6114 511 : for(uInt i=0; i<numFeedRows; i++){
6115 : // if spw id affected, replace by newSpwId
6116 2851 : for(uint j=0; j<nSpwsToCombine; j++){
6117 : // if spw id affected, replace by newSpwId
6118 2370 : if(feedSPWIdCol(i) == spwsToCombine[j]){ // feed row i is affected
6119 78 : feedSPWIdCol.put(i, newSPWId);
6120 : }
6121 : }
6122 : }
6123 :
6124 : // TODO: (possibly, not clear if necessary) remove redundant FEED rows and propagate
6125 :
6126 : // 4) SYSCAL
6127 :
6128 : // note: syscal is optional
6129 :
6130 30 : if(!ms_p.sysCal().isNull()){
6131 3 : MSSysCal sysCaltable = ms_p.sysCal();
6132 3 : uInt numSysCalRows = sysCaltable.nrow();
6133 3 : MSSysCalColumns sysCalCols(sysCaltable);
6134 3 : ScalarColumn<Int> sysCalSPWIdCol = sysCalCols.spectralWindowId();
6135 :
6136 : // loop over SYSCAL table rows
6137 3 : for(uInt i=0; i<numSysCalRows; i++){
6138 : // if spw id affected, replace by newSpwId
6139 0 : for(uInt j=0; j<nSpwsToCombine; j++){
6140 : // if spw id affected, replace by newSpwId
6141 0 : if(sysCalSPWIdCol(i) == spwsToCombine[j]){ // SysCal row i is affected
6142 0 : sysCalSPWIdCol.put(i, newSPWId);
6143 : }
6144 : }
6145 : }
6146 3 : }
6147 :
6148 : // 5) FREQ_OFFSET
6149 :
6150 : // note: freq_offset is optional
6151 :
6152 30 : if(!ms_p.freqOffset().isNull()){
6153 0 : MSFreqOffset freqOffsettable = ms_p.freqOffset();
6154 0 : uInt numFreqOffsetRows = freqOffsettable.nrow();
6155 0 : MSFreqOffsetColumns freqOffsetCols(freqOffsettable);
6156 0 : ScalarColumn<Int> freqOffsetSPWIdCol = freqOffsetCols.spectralWindowId();
6157 :
6158 : // loop over FREQ_OFFSET table rows
6159 0 : for(uInt i=0; i<numFreqOffsetRows; i++){
6160 : // if spw id affected, replace by newSpwId
6161 0 : for(uInt j=0; j<nSpwsToCombine; j++){
6162 : // if spw id affected, replace by newSpwId
6163 0 : if(freqOffsetSPWIdCol(i) == spwsToCombine[j]){ // FreqOffset row i is affected
6164 0 : freqOffsetSPWIdCol.put(i, newSPWId);
6165 : }
6166 : }
6167 : }
6168 0 : }
6169 :
6170 : // 6) MAIN
6171 :
6172 : Table newMain(TableCopy::makeEmptyTable( tempNewName,
6173 60 : Record(),
6174 30 : (Table) ms_p,
6175 : Table::New,
6176 : Table::AipsrcEndian,
6177 : true, // replaceTSM
6178 : true // noRows
6179 : )
6180 60 : );
6181 :
6182 30 : TableCopy::copySubTables(newMain, ms_p, false);
6183 :
6184 30 : MSMainColumns mainCols((MeasurementSet&)newMain);
6185 30 : MSMainColumns oldMainCols(ms_p);
6186 :
6187 30 : uInt nMainTabRows = ms_p.nrow();
6188 :
6189 : // columns which depend on the number of frequency channels and may need to be combined:
6190 : // DATA, FLOAT_DATA, CORRECTED_DATA, MODEL_DATA, LAG_DATA, SIGMA_SPECTRUM,
6191 : // WEIGHT_SPECTRUM, FLAG, and FLAG_CATEGORY
6192 30 : ArrayColumn<Complex> CORRECTED_DATACol = mainCols.correctedData();
6193 30 : ArrayColumn<Complex> oldCORRECTED_DATACol = oldMainCols.correctedData();
6194 30 : ArrayColumn<Complex> DATACol = mainCols.data();
6195 30 : ArrayColumn<Complex> oldDATACol = oldMainCols.data();
6196 30 : ArrayColumn<Float> FLOAT_DATACol = mainCols.floatData();
6197 30 : ArrayColumn<Float> oldFLOAT_DATACol = oldMainCols.floatData();
6198 30 : ArrayColumn<Complex> LAG_DATACol = mainCols.lagData();
6199 30 : ArrayColumn<Complex> oldLAG_DATACol = oldMainCols.lagData();
6200 30 : ArrayColumn<Complex> MODEL_DATACol = mainCols.modelData();
6201 30 : ArrayColumn<Complex> oldMODEL_DATACol = oldMainCols.modelData();
6202 30 : ArrayColumn<Float> SIGMA_SPECTRUMCol = mainCols.sigmaSpectrum();
6203 30 : ArrayColumn<Float> oldSIGMA_SPECTRUMCol = oldMainCols.sigmaSpectrum();
6204 30 : ArrayColumn<Float> WEIGHT_SPECTRUMCol = mainCols.weightSpectrum();
6205 30 : ArrayColumn<Float> oldWEIGHT_SPECTRUMCol = oldMainCols.weightSpectrum();
6206 30 : ArrayColumn<Bool> FLAGCol = mainCols.flag();
6207 30 : ArrayColumn<Bool> oldFLAGCol = oldMainCols.flag();
6208 30 : ArrayColumn<Bool> FLAG_CATEGORYCol = mainCols.flagCategory();
6209 30 : ArrayColumn<Bool> oldFLAG_CATEGORYCol = oldMainCols.flagCategory();
6210 :
6211 : // columns which may be different for otherwise matching main table rows
6212 : // and need to be combined
6213 30 : ScalarColumn<Bool> flagRowCol = oldMainCols.flagRow();
6214 :
6215 : // administrational columns needed from the main table
6216 30 : ArrayColumn<Float> SIGMACol = oldMainCols.sigma();
6217 30 : ScalarColumn<Int> fieldCol = oldMainCols.fieldId();
6218 30 : ScalarColumn<Int> DDIdCol = oldMainCols.dataDescId();
6219 30 : ScalarColumn<Int> antenna1Col = oldMainCols.antenna1();
6220 30 : ScalarColumn<Int> antenna2Col = oldMainCols.antenna2();
6221 30 : ScalarColumn<Double> timeCol = oldMainCols.time();
6222 30 : ScalarColumn<Double> intervalCol = oldMainCols.interval();
6223 30 : ScalarColumn<Double> exposureCol = oldMainCols.exposure();
6224 30 : ScalarMeasColumn<MEpoch> mainTimeMeasCol = oldMainCols.timeMeas();
6225 :
6226 : // arrays for composing the combined columns
6227 : // model them on the first affected row of the main table
6228 :
6229 30 : Matrix<Complex> newCorrectedData;
6230 30 : Matrix<Complex> newData;
6231 30 : Matrix<Float> newFloatData;
6232 30 : Matrix<Complex> newLagData;
6233 30 : Matrix<Complex> newModelData;
6234 30 : Matrix<Float> newSigmaSpectrum;
6235 30 : Matrix<Float> newWeightSpectrum;
6236 30 : Matrix<Bool> newFlag;
6237 30 : Array<Bool> newFlagCategory; // has three dimensions
6238 : Bool newFlagRow;
6239 :
6240 : // create time-sorted index for main table access
6241 30 : Vector<uInt> sortedI(nMainTabRows);
6242 : {
6243 30 : Vector<Double> mainTimesV = oldMainCols.time().getColumn();
6244 30 : GenSortIndirect<Double>::sort(sortedI,mainTimesV);
6245 30 : }
6246 :
6247 : // find the first row affected by the spw combination
6248 30 : Int firstAffRow = 0;
6249 30 : for(uInt mRow=0; mRow<nMainTabRows; mRow++){
6250 30 : uInt sortedMRow = sortedI(mRow);
6251 30 : if(DDtoSPWIndex.find(DDIdCol(sortedMRow)) != DDtoSPWIndex.end( )){
6252 30 : firstAffRow = sortedMRow;
6253 30 : break;
6254 : }
6255 : }
6256 :
6257 : // get the number of correlations from the
6258 : // dimension of the first axis of the sigma column
6259 30 : uInt nCorrelations = SIGMACol(firstAffRow).shape()(0);
6260 :
6261 30 : IPosition newShape = IPosition(2, nCorrelations, newNUM_CHAN);
6262 :
6263 30 : Bool CORRECTED_DATAColIsOK = !CORRECTED_DATACol.isNull();
6264 30 : Bool DATAColIsOK = !DATACol.isNull();
6265 30 : Bool FLOAT_DATAColIsOK = !FLOAT_DATACol.isNull();
6266 30 : Bool LAG_DATAColIsOK = !LAG_DATACol.isNull();
6267 30 : Bool MODEL_DATAColIsOK = !MODEL_DATACol.isNull();
6268 30 : Bool SIGMA_SPECTRUMColIsOK = !SIGMA_SPECTRUMCol.isNull();
6269 30 : Bool WEIGHT_SPECTRUMColIsOK = !WEIGHT_SPECTRUMCol.isNull(); // rechecked further below
6270 30 : Bool FLAGColIsOK = !FLAGCol.isNull();
6271 30 : Bool FLAG_CATEGORYColIsOK = false; // to be set to the correct value further below
6272 :
6273 : // initialize arrays to store combined column data
6274 30 : if(CORRECTED_DATAColIsOK){
6275 17 : newCorrectedData.resize(newShape);
6276 : }
6277 30 : if(DATAColIsOK){
6278 30 : newData.resize(newShape);
6279 : }
6280 30 : if(FLOAT_DATAColIsOK){
6281 0 : newFloatData.resize(newShape);
6282 : }
6283 30 : if(LAG_DATAColIsOK){
6284 0 : newLagData.resize(newShape);
6285 : }
6286 30 : if(MODEL_DATAColIsOK){
6287 17 : newModelData.resize(newShape);
6288 : }
6289 30 : if(SIGMA_SPECTRUMColIsOK){
6290 2 : newSigmaSpectrum.resize(newShape);
6291 : }
6292 30 : if(WEIGHT_SPECTRUMColIsOK){
6293 30 : if(oldWEIGHT_SPECTRUMCol.isDefined(firstAffRow)){ // required column but may be empty
6294 25 : newWeightSpectrum.resize(newShape);
6295 : }
6296 : else{
6297 5 : WEIGHT_SPECTRUMColIsOK = false;
6298 : }
6299 : }
6300 30 : if(FLAGColIsOK){ // required but one never knows (there may be bugs elsewhere)
6301 30 : newFlag.resize(newShape);
6302 : }
6303 30 : IPosition flagCatShape;
6304 30 : uInt nCat = 0;
6305 30 : if(!FLAG_CATEGORYCol.isNull()){
6306 30 : if(oldFLAG_CATEGORYCol.isDefined(firstAffRow)){ // required column but may be empty
6307 0 : FLAG_CATEGORYColIsOK = true;
6308 0 : flagCatShape = oldFLAG_CATEGORYCol.shape(firstAffRow);
6309 0 : nCat = flagCatShape(2); // the dimension of the third axis ==
6310 : // number of categories
6311 0 : newFlagCategory.resize(IPosition(3, nCorrelations, newNUM_CHAN, nCat));
6312 : }
6313 : }
6314 :
6315 : /////////////////////////////////////////
6316 :
6317 : // Loop over main table rows
6318 30 : uInt mainTabRowI = 0;
6319 30 : uInt mainTabRow = sortedI(mainTabRowI);
6320 30 : uInt newMainTabRow = 0;
6321 30 : uInt nIncompleteCoverage = 0; // number of rows with incomplete SPW coverage
6322 :
6323 30 : Int prevNewMainTabRow = -1; // needed to reduce redundant warning output
6324 30 : vector<Int> prevFailedAvChans;
6325 30 : vector<Int> prevFailedAvCorrs;
6326 :
6327 : // prepare progress meter
6328 30 : Float progress = 0.2;
6329 30 : Float progressStep = 0.2;
6330 30 : if(nMainTabRows>100000){
6331 2 : progress = 0.1;
6332 2 : progressStep = 0.1;
6333 : }
6334 :
6335 1846910 : while(mainTabRowI<nMainTabRows &&
6336 923440 : (mainTabRow = sortedI(mainTabRowI)) < nMainTabRows
6337 : ){
6338 :
6339 : // should row be combined with others, i.e. has SPW changed?
6340 : // no -> just renumber DD ID (because of shrunk DD ID table)
6341 :
6342 : // yes-> find rows from the spws tobe combined with same timestamp, antennas and field
6343 : // merge these rows
6344 : // write merged row over first one, correcting DD ID at the same time
6345 : // set TIME to 0 in other merged rows
6346 : // reduce nMainTabRows accordingly
6347 :
6348 : // continue
6349 : //
6350 : // when finished, delete all rows with TIME = 0
6351 :
6352 923440 : Double theTime = timeCol(mainTabRow);
6353 :
6354 : // row was already combined with a previous row?
6355 923440 : if(theTime == 0){
6356 : // cout << "skipping row with zero time " << mainTabRow << endl;
6357 486918 : mainTabRowI++;
6358 486918 : continue;
6359 : }
6360 :
6361 436522 : Int theDataDescId = DDIdCol(mainTabRow);
6362 :
6363 : // row affected by the spw combination? (uses the old DD numbering)
6364 436522 : if(DDtoSPWIndex.find(theDataDescId) != DDtoSPWIndex.end( )){
6365 : // find matching affected rows with same time stamp, antennas and field
6366 436522 : Int theAntenna1 = antenna1Col(mainTabRow);
6367 436522 : Int theAntenna2 = antenna2Col(mainTabRow);
6368 436522 : Int theField = fieldCol(mainTabRow);
6369 436522 : Double theInterval = intervalCol(mainTabRow);
6370 436522 : Double toleratedTimeDiff = theInterval/10.;
6371 436522 : Double theExposure = exposureCol(mainTabRow);
6372 436522 : vector<Int> matchingRows;
6373 436522 : matchingRows.push_back(mainTabRow);
6374 436522 : vector<Int> matchingRowSPWIds;
6375 436522 : matchingRowSPWIds.push_back(DDtoSPWIndex.at(theDataDescId));
6376 436522 : std::map<Int, Int> SPWtoRowIndex;
6377 436522 : SPWtoRowIndex.insert(std::pair<Int, Int>(matchingRowSPWIds[0], mainTabRow));
6378 :
6379 : // cout << "theRow = " << mainTabRow << ", time = " << theTime << " DDID " << theDataDescId << endl;
6380 :
6381 436522 : uInt nextRowI = mainTabRowI+1;
6382 : uInt nextRow;
6383 : // cout << "nextRow = " << nextRow << ", time diff = " << timeCol(nextRow) - theTime << " DDID " << DDIdCol(nextRow) << endl;
6384 436522 : while(nextRowI<nMainTabRows &&
6385 12786634 : (nextRow = sortedI(nextRowI))<nMainTabRows && // assignment!
6386 38339687 : (timeCol(nextRow) - theTime)< toleratedTimeDiff &&
6387 12766249 : matchingRows.size() < nSpwsToCombine // there should be one matching row per SPW
6388 : ){
6389 :
6390 12350282 : if( DDtoSPWIndex.find(DDIdCol(nextRow)) == DDtoSPWIndex.end( ) ||
6391 12350282 : antenna1Col(nextRow) != theAntenna1 ||
6392 25187482 : antenna2Col(nextRow) != theAntenna2 ||
6393 486918 : fieldCol(nextRow) != theField ){ // not a matching row
6394 11863364 : nextRowI++;
6395 11863364 : continue;
6396 : }
6397 : // check that the intervals are the same
6398 486918 : if(fabs(intervalCol(nextRow)-theInterval) > 1E-5){
6399 0 : os << LogIO::WARN << "Error: for time " << MVTime(theTime/C::day).string(MVTime::DMY,7) << ", baseline (" << theAntenna1 << ", "
6400 : << theAntenna2 << "), field "<< theField << ", DataDescID " << DDIdCol(mainTabRow)
6401 : << " found matching row with DataDescID " << DDIdCol(nextRow) << endl
6402 : << " but the two rows have different intervals: " << theInterval
6403 : << " vs. " << intervalCol(nextRow)
6404 0 : << LogIO::POST;
6405 0 : if(!flagRowCol(nextRow)){
6406 0 : os << LogIO::SEVERE << "You need to flag row " << nextRow << " to proceed." << LogIO::POST;
6407 0 : return false;
6408 : }
6409 : else{
6410 0 : os << LogIO::WARN << "Fortunately, row " << nextRow << " is flagged so this problem will be ignored." << LogIO::POST;
6411 : }
6412 : }
6413 : // check that the exposures are the same
6414 486918 : if(fabs(exposureCol(nextRow)-theExposure) > 1E-5){
6415 0 : os << LogIO::WARN << "Error: for time " << MVTime(theTime/C::day).string(MVTime::DMY,7) << ", baseline (" << theAntenna1 << ", "
6416 : << theAntenna2 << "), field "<< theField << ", DataDescID " << DDIdCol(mainTabRow)
6417 : << " found matching row with DataDescID " << DDIdCol(nextRow) << endl
6418 : << " but the two rows have different exposures: " << theExposure
6419 : << " vs. " << exposureCol(nextRow)
6420 0 : << LogIO::POST;
6421 0 : if(!flagRowCol(nextRow)){
6422 0 : os << LogIO::SEVERE << "You need to flag row " << nextRow << " to proceed." << LogIO::POST;
6423 0 : return false;
6424 : }
6425 : else{
6426 0 : os << LogIO::WARN << "Fortunately row " << nextRow << " is flagged so this problem will be ignored." << LogIO::POST;
6427 : }
6428 : }
6429 : // found a matching row
6430 486918 : Int theSPWId = DDtoSPWIndex.at(DDIdCol(nextRow));
6431 486918 : if(SPWtoRowIndex.find(theSPWId) != SPWtoRowIndex.end( )){ // there should be a one-to-one relation: SPW <-> matching row
6432 0 : os << LogIO::WARN << "Error: for time " << MVTime(theTime/C::day).string(MVTime::DMY,7) << ", baseline (" << theAntenna1 << ","
6433 : << theAntenna2 << "), field "<< theField << " found more than one row for SPW "
6434 0 : << theSPWId << LogIO::POST;
6435 0 : if(!flagRowCol(nextRow)){
6436 0 : os << LogIO::SEVERE << "You need to flag row " << nextRow << " to proceed." << LogIO::POST;
6437 0 : return false;
6438 : }
6439 : else{
6440 0 : os << LogIO::WARN << "Fortunately, row " << nextRow << " is flagged so this problem will be ignored." << LogIO::POST;
6441 : }
6442 : }
6443 : else{ // this SPW not yet covered, memorize SPWId, row number, and relation
6444 486918 : matchingRowSPWIds.push_back(theSPWId);
6445 486918 : matchingRows.push_back(nextRow);
6446 486918 : SPWtoRowIndex.insert(std::pair<Int, Int>(theSPWId, nextRow));
6447 : // cout << "matching nextRow = " << nextRow << ", time = " << timeCol(nextRow) << " DDID " << DDIdCol(nextRow) << endl;
6448 : }
6449 486918 : nextRowI++;
6450 : } // end while nextRowI ...
6451 :
6452 : // now we have a set of matching rows
6453 436522 : uInt nMatchingRows = matchingRows.size();
6454 :
6455 436522 : if(nMatchingRows < nSpwsToCombine){
6456 16924 : if(nIncompleteCoverage==0){
6457 : os << LogIO::WARN << "Incomplete coverage of combined SPW starting at timestamp "
6458 4 : << MVTime(timeCol(mainTabRow)/C::day).string(MVTime::DMY,7)
6459 : << ", baseline ( " << theAntenna1 << ", " << theAntenna2 << " )" << endl
6460 4 : << "In this and further affected rows, the data arrays will be padded with zeros and corresponding channels flagged." << LogIO::POST;
6461 : }
6462 16924 : nIncompleteCoverage++;
6463 : }
6464 :
6465 : // reset arrays and prepare input data matrices
6466 :
6467 436522 : if(CORRECTED_DATAColIsOK){
6468 7842 : newCorrectedData.set(0);
6469 : }
6470 436522 : if(DATAColIsOK){
6471 436522 : newData.set(0);
6472 : }
6473 436522 : if(FLOAT_DATAColIsOK){
6474 0 : newFloatData.set(0);
6475 : }
6476 436522 : if(LAG_DATAColIsOK){
6477 0 : newLagData.set(0);
6478 : }
6479 436522 : if(MODEL_DATAColIsOK){
6480 7842 : newModelData.set(0);
6481 : }
6482 436522 : if(SIGMA_SPECTRUMColIsOK){
6483 58740 : newSigmaSpectrum.set(0);
6484 : }
6485 436522 : if(WEIGHT_SPECTRUMColIsOK){
6486 414489 : newWeightSpectrum.set(0);
6487 : }
6488 436522 : if(FLAGColIsOK){
6489 436522 : newFlag.set(0);
6490 : }
6491 436522 : if(FLAG_CATEGORYColIsOK){
6492 0 : newFlagCategory.set(0);
6493 : }
6494 :
6495 436522 : vector<Matrix<Complex> > newCorrectedDataI(nSpwsToCombine);
6496 436522 : vector<Matrix<Complex> > newDataI(nSpwsToCombine);
6497 436522 : vector<Matrix<Float> > newFloatDataI(nSpwsToCombine);
6498 436522 : vector<Matrix<Complex> > newLagDataI(nSpwsToCombine);
6499 436522 : vector<Matrix<Complex> > newModelDataI(nSpwsToCombine);
6500 436522 : vector<Matrix<Float> > newSigmaSpectrumI(nSpwsToCombine);
6501 436522 : vector<Matrix<Float> > newWeightSpectrumI(nSpwsToCombine);
6502 436522 : vector<Matrix<Bool> > newFlagI(nSpwsToCombine);
6503 436522 : vector<Array<Bool> > newFlagCategoryI(nSpwsToCombine); // has three dimensions
6504 436522 : vector<Bool> newFlagRowI(nSpwsToCombine);
6505 :
6506 1376886 : for(uInt i=0; i<nSpwsToCombine; i++){
6507 940364 : Int theRowSPWId = spwsToCombine[i];
6508 940364 : if(SPWtoRowIndex.find(theRowSPWId) != SPWtoRowIndex.end( )){ // there actually is a matching row for this SPW
6509 923440 : Int theRow = SPWtoRowIndex[theRowSPWId];
6510 923440 : if(CORRECTED_DATAColIsOK){
6511 73764 : newCorrectedDataI[theRowSPWId].reference(oldCORRECTED_DATACol(theRow));
6512 : }
6513 923440 : if(DATAColIsOK){
6514 923440 : newDataI[theRowSPWId].reference(oldDATACol(theRow));
6515 : }
6516 923440 : if(FLOAT_DATAColIsOK){
6517 0 : newFloatDataI[theRowSPWId].reference(oldFLOAT_DATACol(theRow));
6518 : }
6519 923440 : if(LAG_DATAColIsOK){
6520 0 : newLagDataI[theRowSPWId].reference(oldLAG_DATACol(theRow));
6521 : }
6522 923440 : if(MODEL_DATAColIsOK){
6523 73764 : newModelDataI[theRowSPWId].reference(oldMODEL_DATACol(theRow));
6524 : }
6525 923440 : if(SIGMA_SPECTRUMColIsOK){
6526 117480 : newSigmaSpectrumI[theRowSPWId].reference(oldSIGMA_SPECTRUMCol(theRow));
6527 : }
6528 923440 : if(WEIGHT_SPECTRUMColIsOK){
6529 896298 : newWeightSpectrumI[theRowSPWId].reference(oldWEIGHT_SPECTRUMCol(theRow));
6530 : }
6531 923440 : if(FLAGColIsOK){
6532 923440 : newFlagI[theRowSPWId].reference(oldFLAGCol(theRow));
6533 : }
6534 923440 : if(FLAG_CATEGORYColIsOK){
6535 0 : newFlagCategoryI[theRowSPWId].reference(oldFLAG_CATEGORYCol(theRow));
6536 : }
6537 923440 : newFlagRowI[theRowSPWId] = flagRowCol(theRow);
6538 : } // end if
6539 : } // end for i
6540 :
6541 : // merge data columns from all rows found using the averaging info from above
6542 : // averageN[], averageWhichSPW[], averageWhichChan[], averageChanFrac[]
6543 :
6544 436522 : Bool failedAv = false;
6545 436522 : vector<Int> failedAvChans;
6546 436522 : vector<Int> failedAvCorrs;
6547 :
6548 : // loop over new channels
6549 13804860 : for(uInt i=0; i<newNUM_CHAN; i++){
6550 : // initialise special treatment for Bool columns
6551 13368338 : if(FLAGColIsOK){
6552 33866562 : for(uInt k=0; k<nCorrelations; k++){
6553 20498224 : newFlag(k,i) = true; // overwritten with false below if there is a SPW where this channel is not flagged for this correlator
6554 : }
6555 : }
6556 13368338 : if(FLAG_CATEGORYColIsOK){
6557 0 : for(uInt k=0; k<nCorrelations; k++){
6558 0 : for(uInt m=0; m<nCat; m++){
6559 0 : newFlagCategory(IPosition(3,k,i,m)) = false;
6560 : }
6561 : }
6562 : }
6563 :
6564 13368338 : Bool haveCoverage = false;
6565 13368338 : Vector<Double> modNorm(nCorrelations, 0.); // normalization for the averaging of the contributions from the SPWs
6566 26736676 : vector<vector<Double> > modAverageChanFrac(averageN[i], vector<Double>(nCorrelations, 0.));
6567 33866562 : for(uInt k=0; k<nCorrelations; k++){
6568 20498224 : Vector<Int> spwCount(nSpwsToCombine, 0);
6569 62076578 : for(Int j=0; j<averageN[i]; j++){
6570 41578354 : if(SPWtoRowIndex.find(averageWhichSPW[i][j]) != SPWtoRowIndex.end( )){
6571 28667844 : if(!newFlagI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] )){
6572 25392748 : haveCoverage = true;
6573 25392748 : if(FLAGColIsOK){
6574 25392748 : newFlag(k,i) = false; // there is valid data for this channel and correlation => don't flag in output
6575 : }
6576 25392748 : modAverageChanFrac[j][k] = averageChanFrac[i][j];
6577 25392748 : modNorm(k) += averageChanFrac[i][j];
6578 25392748 : if(modAverageChanFrac[j][k]!=1.){
6579 10968660 : ++spwCount(averageWhichSPW[i][j]); // count the contributions with non-unity overlap fraction for each spw
6580 : }
6581 : }
6582 : }
6583 : }
6584 20498224 : if(modNorm(k)>0.){ // there are contributions
6585 58688123 : for(Int j=0; j<averageN[i]; j++){
6586 : // Second iteration: eliminate contributions from spws with odd numbers of contribs with non-unity overlap fraction
6587 : // which could influence the averaging asymmetrically
6588 39612642 : if(SPWtoRowIndex.find(averageWhichSPW[i][j]) != SPWtoRowIndex.end( )
6589 26837953 : && spwCount(averageWhichSPW[i][j])<averageN[i] // there are also channels with full overlap
6590 26837953 : && spwCount(averageWhichSPW[i][j])%2!=0 // the number of channels with non-unity overlap is odd
6591 66450595 : && modAverageChanFrac[j][k]!=1.){ // this contributor j has non-unity overlap
6592 : //cout << "spw count " << averageWhichSPW[i][j] << " " << spwCount(averageWhichSPW[i][j]) << endl;
6593 : //cout << "not using i j k spw frac " << i << " " << j << " " << k << " "
6594 : // << averageWhichSPW[i][j] << " " << modAverageChanFrac[j][k] << endl;
6595 222193 : modNorm(k) -= modAverageChanFrac[j][k];
6596 222193 : modAverageChanFrac[j][k] = 0.;
6597 222193 : if(modNorm(k)<=0.){ // should only occur in rare cases
6598 16935 : if(FLAGColIsOK && !newFlag(k,i)){
6599 16935 : failedAv = true;
6600 16935 : newFlag(k,i) = true;
6601 16935 : if(prevNewMainTabRow<0){
6602 14 : prevNewMainTabRow = newMainTabRow;
6603 : }
6604 16935 : failedAvChans.push_back(i);
6605 16935 : failedAvCorrs.push_back(k);
6606 : }
6607 16935 : modNorm(k) += averageChanFrac[i][j];
6608 16935 : modAverageChanFrac[j][k] = averageChanFrac[i][j];
6609 16935 : break;
6610 : }
6611 : }
6612 : }
6613 : }
6614 20498224 : } // end loop over correlations
6615 :
6616 13368338 : if(haveCoverage){ // there is unflagged data for this channel
6617 : // loop over SPWs
6618 36021074 : for(Int j=0; j<averageN[i]; j++){
6619 : // new channel value i
6620 : // = SUM{j=0 to averageN[i]}( channelValue(SPW = averageWhichSPW[i][j], CHANNEL = averageWhichChan[i][j]) * averageChanFrac[i][j])
6621 23973034 : if(SPWtoRowIndex.find(averageWhichSPW[i][j]) != SPWtoRowIndex.end( )){
6622 :
6623 17585645 : Double weight = 0.;
6624 :
6625 : // loop over first dimension (number of correlations)
6626 44433190 : for(uInt k=0; k<nCorrelations; k++){
6627 26847545 : if(!newFlagI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] )
6628 26847545 : && modNorm(k)>0.){ // this channel is not flagged for the given SPW and correlator and there are contributions
6629 :
6630 : // renormalize for the case of missing SPW coverage
6631 25392748 : weight = modAverageChanFrac[j][k] / modNorm(k);
6632 :
6633 25392748 : if(CORRECTED_DATAColIsOK){
6634 7351892 : newCorrectedData(k,i) += newCorrectedDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;
6635 : }
6636 25392748 : if(DATAColIsOK){
6637 25392748 : newData(k,i) += newDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;
6638 : // if (!wasprinted[i][j]){
6639 : // cout << "row " << SPWtoRowIndex(averageWhichSPW[i][j]) << "averageWhichSPW[i][j] "
6640 : // << averageWhichSPW[i][j] << " averageWhichChan[i][j] " << averageWhichChan[i][j]
6641 : // << " i, j, k " << i << ", " << j << ", " << k << " modAverageChanFrac[j][k] " << modAverageChanFrac[j][k]
6642 : // << " modNorm(k) " << modNorm(k) << " newDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) "
6643 : // << newDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] )
6644 : // << " newData(k,i) " << newData(k,i)
6645 : // << " weight " << weight << endl;
6646 : // wasprinted[i][j] = true;
6647 : // }
6648 : }
6649 25392748 : if(FLOAT_DATAColIsOK){
6650 0 : newFloatData(k,i) += newFloatDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;
6651 : }
6652 25392748 : if(LAG_DATAColIsOK){
6653 0 : newLagData(k,i) += newLagDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;
6654 : }
6655 25392748 : if(MODEL_DATAColIsOK){
6656 7351892 : newModelData(k,i) += newModelDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;
6657 : }
6658 25392748 : if(SIGMA_SPECTRUMColIsOK){
6659 469920 : newSigmaSpectrum(k,i) += newSigmaSpectrumI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;
6660 : }
6661 25392748 : if(WEIGHT_SPECTRUMColIsOK){
6662 11893360 : newWeightSpectrum(k,i) += newWeightSpectrumI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;
6663 : }
6664 :
6665 : } // end if flagged
6666 : } // end for k = 0
6667 :
6668 : // special treatment for flag cat
6669 17585645 : if(FLAG_CATEGORYColIsOK){
6670 0 : for(uInt k=0; k<nCorrelations; k++){ // logical OR of all input spws
6671 0 : for(uInt m=0; m<nCat; m++){
6672 0 : newFlagCategory(IPosition(3,k,i,m)) =
6673 0 : newFlagCategory(IPosition(3,k,i,m)) || newFlagCategoryI[ averageWhichSPW[i][j] ](IPosition(3,k,averageWhichChan[i][j],m));
6674 : }
6675 : }
6676 : }
6677 :
6678 : } // end if there is a row for this SPW
6679 : } // end for j=0, loop over SPWs
6680 : } // if there is coverage for this channel
6681 13368338 : } // end for i=0, loop over new channels
6682 :
6683 : // give warnings about channels with averaging problems
6684 436522 : if(prevNewMainTabRow>=0){ // may need to issue warnings
6685 16974 : if(!failedAv
6686 8473 : || mainTabRowI==nMainTabRows-1
6687 16960 : || (prevFailedAvChans.size()>0 && !((failedAvChans==prevFailedAvChans) && (failedAvCorrs==prevFailedAvCorrs)))
6688 : ){
6689 14 : uInt lastRow = newMainTabRow-1;
6690 14 : if(mainTabRowI==nMainTabRows-1){
6691 0 : lastRow = newMainTabRow;
6692 : }
6693 : os << LogIO::WARN << "Averaging failed for the following channel/correllation pairs from output row "
6694 14 : << prevNewMainTabRow << " up to " << lastRow << ". Corresponding visibilities will be flagged: " << endl;
6695 31 : for(uInt iii=0; iii<prevFailedAvChans.size(); iii++){
6696 17 : os << "(" << prevFailedAvChans[iii] << ", " << prevFailedAvCorrs[iii] << ") ";
6697 : }
6698 14 : os << LogIO::POST;
6699 14 : prevNewMainTabRow = -1;
6700 : }
6701 8487 : prevFailedAvChans = failedAvChans;
6702 8487 : prevFailedAvCorrs = failedAvCorrs;
6703 : }
6704 :
6705 : // calculate FLAG_ROW as logical OR of all input rows
6706 436522 : newFlagRow = newFlagRowI[0];
6707 923440 : for(uInt i=1; i<nMatchingRows; i++){
6708 486918 : newFlagRow = newFlagRow || newFlagRowI[i];
6709 : }
6710 :
6711 : // write data into the new main table
6712 436522 : newMain.addRow(1,false);
6713 :
6714 : // cout << "writing new row " << newMainTabRow << endl;
6715 :
6716 436522 : if(CORRECTED_DATAColIsOK){
6717 7842 : CORRECTED_DATACol.put(newMainTabRow, newCorrectedData);
6718 : }
6719 436522 : if(DATAColIsOK){
6720 : // cout << "old " << oldDATACol(mainTabRow).shape() << endl;
6721 : // cout << "new " << newData.shape() << endl;
6722 436522 : DATACol.put(newMainTabRow, newData);
6723 : }
6724 436522 : if(FLOAT_DATAColIsOK){
6725 0 : FLOAT_DATACol.put(newMainTabRow, newFloatData);
6726 : }
6727 436522 : if(LAG_DATAColIsOK){
6728 0 : LAG_DATACol.put(newMainTabRow, newLagData);
6729 : }
6730 436522 : if(MODEL_DATAColIsOK){
6731 7842 : MODEL_DATACol.put(newMainTabRow, newModelData);
6732 : }
6733 436522 : if(SIGMA_SPECTRUMColIsOK){
6734 58740 : SIGMA_SPECTRUMCol.put(newMainTabRow, newSigmaSpectrum);
6735 : }
6736 436522 : if(WEIGHT_SPECTRUMColIsOK){
6737 414489 : WEIGHT_SPECTRUMCol.put(newMainTabRow, newWeightSpectrum);
6738 : }
6739 436522 : if(FLAGColIsOK){
6740 436522 : FLAGCol.put(newMainTabRow, newFlag);
6741 : }
6742 436522 : if(FLAG_CATEGORYColIsOK){
6743 0 : FLAG_CATEGORYCol.put(newMainTabRow, newFlagCategory);
6744 : }
6745 :
6746 436522 : mainCols.flagRow().put(newMainTabRow, newFlagRow);
6747 :
6748 436522 : if(tempDDIndex.find(theDataDescId) != tempDDIndex.end( )){
6749 : // do DD ID renumbering (due to shrunk DD table and spw combination )
6750 436522 : mainCols.dataDescId().put(newMainTabRow, tempDDIndex.at(theDataDescId));
6751 : }
6752 : else{
6753 0 : mainCols.dataDescId().put(newMainTabRow, DDIdCol(mainTabRow));
6754 : }
6755 : // copy the rest of the row contents from mainTabRow
6756 436522 : mainCols.sigma().put(newMainTabRow, SIGMACol(mainTabRow));
6757 436522 : mainCols.weight().put(newMainTabRow, oldMainCols.weight()(mainTabRow));
6758 :
6759 436522 : mainCols.fieldId().put(newMainTabRow, fieldCol(mainTabRow));
6760 436522 : mainCols.antenna1().put(newMainTabRow, antenna1Col(mainTabRow));
6761 436522 : mainCols.antenna2().put(newMainTabRow, antenna2Col(mainTabRow));
6762 436522 : mainCols.time().put(newMainTabRow, timeCol(mainTabRow));
6763 436522 : mainCols.exposure().put(newMainTabRow, exposureCol(mainTabRow));
6764 436522 : mainCols.interval().put(newMainTabRow, intervalCol(mainTabRow));
6765 :
6766 436522 : mainCols.uvw().put(newMainTabRow, oldMainCols.uvw()(mainTabRow));
6767 436522 : mainCols.arrayId().put(newMainTabRow, oldMainCols.arrayId()(mainTabRow));
6768 436522 : mainCols.feed1().put(newMainTabRow, oldMainCols.feed1()(mainTabRow));
6769 436522 : mainCols.feed2().put(newMainTabRow, oldMainCols.feed2()(mainTabRow));
6770 436522 : mainCols.observationId().put(newMainTabRow, oldMainCols.observationId()(mainTabRow));
6771 436522 : mainCols.processorId().put(newMainTabRow, oldMainCols.processorId()(mainTabRow));
6772 436522 : mainCols.scanNumber().put(newMainTabRow, oldMainCols.scanNumber()(mainTabRow));
6773 436522 : mainCols.stateId().put(newMainTabRow, oldMainCols.stateId()(mainTabRow));
6774 436522 : mainCols.timeCentroid().put(newMainTabRow, oldMainCols.timeCentroid()(mainTabRow));
6775 :
6776 : // cout << "Wrote new row " << newMainTabRow << endl;
6777 436522 : newMainTabRow++;
6778 : // mark other found rows to be ignored, i.e. set their time to zero
6779 923440 : for(uInt i=1; i<nMatchingRows; i++){ // don't mark the first
6780 : // cout << "setting time to zero in row " << matchingRows[i] << endl;
6781 486918 : timeCol.put(matchingRows[i], 0);
6782 : }
6783 :
6784 436522 : } // end if row is affected
6785 :
6786 436522 : mainTabRowI++;
6787 436522 : if(mainTabRowI>nMainTabRows*progress){
6788 130 : cout << "combineSpws progress: " << progress*100 << "% processed ... " << endl;
6789 130 : progress += progressStep;
6790 : }
6791 :
6792 : } // end loop over main table rows
6793 30 : cout << "combineSpws progress: 100% processed." << endl;
6794 : ////////////////////////////////////////////
6795 :
6796 30 : if(verbose){
6797 : os << LogIO::NORMAL << "Processed " << mainTabRowI << " original rows, wrote "
6798 30 : << newMainTabRow << " new ones." << LogIO::POST;
6799 :
6800 30 : if(nIncompleteCoverage>0){
6801 : os << LogIO::WARN << "Incomplete coverage of combined SPW in " << nIncompleteCoverage
6802 2 : << " of " << newMainTabRow << " output rows." << LogIO::POST;
6803 : }
6804 : }
6805 :
6806 3142 : } // end scope for MS related objects
6807 :
6808 30 : String oldName(ms_p.tableName());
6809 :
6810 : // detach old MS
6811 30 : ms_p = MeasurementSet();
6812 30 : mssel_p = MeasurementSet();
6813 :
6814 : // rename the result MS overwriting the old MS
6815 : {
6816 30 : Table tab(tempNewName, Table::Update);
6817 30 : tab.rename(oldName, Table::New);
6818 30 : }
6819 :
6820 : // attach new MS
6821 30 : ms_p = MeasurementSet(oldName, Table::Update);
6822 30 : mssel_p = ms_p;
6823 :
6824 30 : if(verbose){
6825 30 : os << LogIO::NORMAL << "Spectral window combination complete." << LogIO::POST;
6826 : }
6827 :
6828 30 : return true;
6829 :
6830 206 : }
6831 :
6832 250 : const Vector<MS::PredefinedColumns>& SubMS::parseColumnNames(String col)
6833 : {
6834 : // Memoize both for efficiency and so that the info message at the bottom
6835 : // isn't unnecessarily repeated.
6836 250 : static String my_colNameStr = "";
6837 250 : static Vector<MS::PredefinedColumns> my_colNameVect;
6838 :
6839 250 : col.upcase();
6840 250 : if(col == my_colNameStr && col != ""){
6841 249 : return my_colNameVect;
6842 : }
6843 1 : else if(col == "None"){
6844 0 : my_colNameStr = "";
6845 0 : my_colNameVect.resize(0);
6846 0 : return my_colNameVect;
6847 : }
6848 :
6849 2 : LogIO os(LogOrigin("SubMS", "parseColumnNames()"));
6850 :
6851 : uInt nNames;
6852 :
6853 1 : if(col.contains("ALL")){
6854 0 : nNames = 3;
6855 0 : my_colNameVect.resize(nNames);
6856 0 : my_colNameVect[0] = MS::DATA;
6857 0 : my_colNameVect[1] = MS::MODEL_DATA;
6858 0 : my_colNameVect[2] = MS::CORRECTED_DATA;
6859 : }
6860 : else{
6861 1 : nNames = dataColStrToEnums(col, my_colNameVect);
6862 : }
6863 :
6864 : // Whether or not the MS has the columns is checked by verifyColumns().
6865 : // Unfortunately it cannot be done here because this is a static method.
6866 :
6867 1 : if(col != "NONE"){ // "NONE" is used by ~SubMS().
6868 : os << LogIO::NORMAL
6869 0 : << "Using "; // Don't say "Splitting"; this is used elsewhere.
6870 0 : for(uInt i = 0; i < nNames; ++i)
6871 0 : os << MS::columnName(my_colNameVect[i]) << " ";
6872 0 : os << " column" << (my_colNameVect.nelements() > 1 ? "s." : ".")
6873 0 : << LogIO::POST;
6874 : }
6875 :
6876 1 : my_colNameStr = col;
6877 1 : return my_colNameVect;
6878 1 : }
6879 :
6880 : // This version uses the MeasurementSet to check what columns are present,
6881 : // i.e. it makes col=="all" smarter, and it is not necessary to call
6882 : // verifyColumns() after calling this. Unlike the other version, it knows
6883 : // about FLOAT_DATA and LAG_DATA. It throws an exception if a
6884 : // _specifically_ requested column is absent.
6885 76 : const Vector<MS::PredefinedColumns>& SubMS::parseColumnNames(String col,
6886 : const MeasurementSet& msref)
6887 : {
6888 : // Memorize both for efficiency and so that the info message at the bottom
6889 : // isn't unnecessarily repeated.
6890 76 : static String my_colNameStr = "";
6891 76 : static Vector<MS::PredefinedColumns> my_colNameVect;
6892 :
6893 76 : Vector<MS::PredefinedColumns> wanted; // Data columns to pick up if present.
6894 :
6895 76 : col.upcase();
6896 : // This version of parseColumnNames does not reuse results of previous calls
6897 : // but always checks the given columns because it cannot be certain that msref
6898 : // refers to the same MS with every call.
6899 :
6900 76 : if(col == "None"){
6901 0 : my_colNameStr = "";
6902 0 : my_colNameVect.resize(0);
6903 0 : return my_colNameVect;
6904 : }
6905 :
6906 152 : LogIO os(LogOrigin("SubMS", "parseColumnNames()"));
6907 :
6908 : // Are we choosy?
6909 76 : const Bool doAny = col.contains("ALL") || col.contains("ANY");
6910 :
6911 : uInt nPoss;
6912 76 : if(doAny){
6913 40 : nPoss = 5;
6914 40 : wanted.resize(nPoss);
6915 40 : wanted[0] = MS::DATA;
6916 40 : wanted[1] = MS::MODEL_DATA;
6917 40 : wanted[2] = MS::CORRECTED_DATA;
6918 40 : wanted[3] = MS::FLOAT_DATA;
6919 40 : wanted[4] = MS::LAG_DATA;
6920 : }
6921 : else{ // split name string into individual names
6922 36 : nPoss = dataColStrToEnums(col, wanted);
6923 : }
6924 :
6925 76 : uInt nFound = 0;
6926 76 : my_colNameVect.resize(0);
6927 313 : for(uInt i = 0; i < nPoss; ++i){
6928 237 : if(msref.tableDesc().isColumn(MS::columnName(wanted[i]))){
6929 122 : ++nFound;
6930 122 : my_colNameVect.resize(nFound, true);
6931 122 : my_colNameVect[nFound - 1] = wanted[i];
6932 : }
6933 115 : else if(!doAny){
6934 0 : ostringstream ostr;
6935 0 : ostr << "Desired column (" << MS::columnName(wanted[i])
6936 0 : << ") not found in the input MS (" << msref.tableName() << ").";
6937 0 : throw(AipsError(ostr.str()));
6938 0 : }
6939 : }
6940 76 : if(nFound == 0)
6941 0 : throw(AipsError("Did not find and select any data columns."));
6942 :
6943 : os << LogIO::NORMAL
6944 76 : << "Using "; // Don't say "Splitting"; this is used elsewhere.
6945 198 : for(uInt i = 0; i < nFound; ++i)
6946 122 : os << MS::columnName(my_colNameVect[i]) << " ";
6947 76 : os << "column" << (nFound > 1 ? "s." : ".") << LogIO::POST;
6948 :
6949 76 : my_colNameStr = col;
6950 76 : return my_colNameVect;
6951 76 : }
6952 :
6953 37 : uInt SubMS::dataColStrToEnums(const String& col, Vector<MS::PredefinedColumns>& colvec)
6954 : {
6955 74 : LogIO os(LogOrigin("SubMS", "dataColStrToEnums()"));
6956 37 : String tmpNames(col);
6957 37 : Vector<String> tokens;
6958 37 : tmpNames.upcase();
6959 :
6960 : // split name string into individual names
6961 : char * pch;
6962 37 : Int i = 0;
6963 37 : pch = strtok((char*)tmpNames.c_str(), " ,");
6964 75 : while (pch != NULL){
6965 38 : tokens.resize(i + 1, true);
6966 38 : tokens[i] = String(pch);
6967 38 : ++i;
6968 38 : pch = strtok(NULL, " ,");
6969 : }
6970 :
6971 37 : uInt nNames = tokens.nelements();
6972 :
6973 37 : uInt nFound = 0;
6974 75 : for(uInt i = 0; i < nNames; ++i){
6975 38 : colvec.resize(nFound + 1, true);
6976 38 : colvec[nFound] = MS::UNDEFINED_COLUMN;
6977 :
6978 76 : if (tokens[i] == "OBSERVED" ||
6979 76 : tokens[i] == "DATA" ||
6980 13 : tokens[i] == MS::columnName(MS::DATA)){
6981 25 : colvec[nFound++] = MS::DATA;
6982 : }
6983 26 : else if(tokens[i] == "FLOAT" ||
6984 26 : tokens[i] == "FLOAT_DATA" ||
6985 13 : tokens[i] == MS::columnName(MS::FLOAT_DATA)){
6986 0 : colvec[nFound++] = MS::FLOAT_DATA;
6987 : }
6988 26 : else if(tokens[i] == "LAG" ||
6989 26 : tokens[i] == "LAG_DATA" ||
6990 13 : tokens[i] == MS::columnName(MS::LAG_DATA)){
6991 0 : colvec[nFound++] = MS::LAG_DATA;
6992 : }
6993 26 : else if(tokens[i] == "MODEL" ||
6994 26 : tokens[i] == "MODEL_DATA" ||
6995 9 : tokens[i] == MS::columnName(MS::MODEL_DATA)){
6996 4 : colvec[nFound++] = MS::MODEL_DATA;
6997 : }
6998 10 : else if(tokens[i] == "CORRECTED" ||
6999 10 : tokens[i] == "CORRECTED_DATA" ||
7000 1 : tokens[i] == MS::columnName(MS::CORRECTED_DATA)){
7001 8 : colvec[nFound++] = MS::CORRECTED_DATA;
7002 : }
7003 1 : else if(tmpNames != "NONE"){ // "NONE" is used by ~SubMS().
7004 0 : os << LogIO::SEVERE;
7005 0 : if(nFound == 0){
7006 0 : colvec[0] = MS::DATA;
7007 0 : os << "Unrecognized data column " << tokens[i] << "...trying DATA.";
7008 : }
7009 : else
7010 0 : os << "Skipping unrecognized data column " << tokens[i];
7011 0 : os << LogIO::POST;
7012 : }
7013 : }
7014 37 : return nFound;
7015 37 : }
7016 :
7017 :
7018 44 : Bool SubMS::fillAccessoryMainCols(){
7019 88 : LogIO os(LogOrigin("SubMS", "fillAccessoryMainCols()"));
7020 44 : uInt nrows = mssel_p.nrow();
7021 :
7022 44 : msOut_p.addRow(nrows, true);
7023 :
7024 : //#ifdef COPYTIMER
7025 44 : Timer timer;
7026 44 : timer.mark();
7027 : //#endif
7028 44 : if(!antennaSel_p){
7029 44 : msc_p->antenna1().putColumn(mscIn_p->antenna1().getColumn());
7030 44 : msc_p->antenna2().putColumn(mscIn_p->antenna2().getColumn());
7031 : os << LogIO::DEBUG1
7032 : << "Straight copying ANTENNA* took " << timer.real() << "s."
7033 44 : << LogIO::POST;
7034 : }
7035 : else{
7036 0 : Vector<Int> ant1(mscIn_p->antenna1().getColumn());
7037 0 : Vector<Int> ant2(mscIn_p->antenna2().getColumn());
7038 :
7039 0 : for(uInt k = 0; k < nrows; ++k){
7040 0 : ant1[k] = antNewIndex_p[ant1[k]];
7041 0 : ant2[k] = antNewIndex_p[ant2[k]];
7042 : }
7043 0 : msc_p->antenna1().putColumn(ant1);
7044 0 : msc_p->antenna2().putColumn(ant2);
7045 : os << LogIO::DEBUG1
7046 : << "Selectively copying ANTENNA* took " << timer.real() << "s."
7047 0 : << LogIO::POST;
7048 0 : }
7049 :
7050 44 : timer.mark();
7051 44 : msc_p->feed1().putColumn(mscIn_p->feed1().getColumn());
7052 44 : msc_p->feed2().putColumn(mscIn_p->feed2().getColumn());
7053 : os << LogIO::DEBUG1
7054 : << "Copying FEED* took " << timer.real() << "s."
7055 44 : << LogIO::POST;
7056 :
7057 44 : timer.mark();
7058 44 : msc_p->exposure().putColumn(mscIn_p->exposure().getColumn());
7059 : os << LogIO::DEBUG1
7060 : << "Copying EXPOSURE took " << timer.real() << "s."
7061 44 : << LogIO::POST;
7062 :
7063 44 : timer.mark();
7064 44 : msc_p->flagRow().putColumn(mscIn_p->flagRow().getColumn());
7065 : os << LogIO::DEBUG1
7066 : << "Copying flagRow took " << timer.real() << "s."
7067 44 : << LogIO::POST;
7068 :
7069 44 : timer.mark();
7070 44 : msc_p->interval().putColumn(mscIn_p->interval().getColumn());
7071 : os << LogIO::DEBUG1
7072 : << "Copying INTERVAL took " << timer.real() << "s."
7073 44 : << LogIO::POST;
7074 :
7075 44 : timer.mark();
7076 44 : msc_p->scanNumber().putColumn(mscIn_p->scanNumber().getColumn());
7077 : os << LogIO::DEBUG1
7078 : << "Copying scanNumber took " << timer.real() << "s."
7079 44 : << LogIO::POST;
7080 :
7081 44 : timer.mark();
7082 44 : msc_p->time().putColumn(mscIn_p->time().getColumn());
7083 : os << LogIO::DEBUG1
7084 : << "Copying TIME took " << timer.real() << "s."
7085 44 : << LogIO::POST;
7086 :
7087 44 : timer.mark();
7088 44 : msc_p->timeCentroid().putColumn(mscIn_p->timeCentroid().getColumn());
7089 : os << LogIO::DEBUG1
7090 : << "Copying timeCentroid took " << timer.real() << "s."
7091 44 : << LogIO::POST;
7092 :
7093 : // ScalarMeasColumn doesn't have a putColumn() for some reason.
7094 : //msc_p->uvwMeas().putColumn(mscIn_p->uvwMeas());
7095 44 : timer.mark();
7096 : //msc_p->uvw().putColumn(mscIn_p->uvw()); // 98s for 4.7e6 rows
7097 :
7098 : // 3.06s for 4.7e6 rows
7099 : //RefRows refrows(0, nrows - 1);
7100 : //msc_p->uvw().putColumnCells(refrows, mscIn_p->uvw().getColumn());
7101 :
7102 44 : msc_p->uvw().putColumn(mscIn_p->uvw().getColumn()); // 2.74s for 4.7e6 rows
7103 : os << LogIO::DEBUG1
7104 : << "Copying uvw took " << timer.real() << "s."
7105 44 : << LogIO::POST;
7106 :
7107 44 : msc_p->arrayId().putColumn(mscIn_p->arrayId().getColumn());
7108 44 : msc_p->processorId().putColumn(mscIn_p->processorId().getColumn());
7109 :
7110 44 : timer.mark();
7111 44 : relabelIDs();
7112 : os << LogIO::DEBUG1
7113 : << "relabelIDs took " << timer.real() << "s."
7114 44 : << LogIO::POST;
7115 :
7116 44 : return true;
7117 44 : }
7118 :
7119 44 : Bool SubMS::writeAllMainRows(const Vector<MS::PredefinedColumns>& colNames)
7120 : {
7121 88 : LogIO os(LogOrigin("SubMS", "writeAllMainRows()"));
7122 44 : Bool success = true;
7123 44 : Timer timer;
7124 :
7125 44 : fillAccessoryMainCols();
7126 :
7127 : //Deal with data, flags, sigma, and weights.
7128 44 : timer.mark();
7129 44 : if(keepShape_p){
7130 41 : Vector<MS::PredefinedColumns> complexCols;
7131 41 : const Bool doFloat = sepFloat(colNames, complexCols);
7132 41 : const uInt nDataCols = complexCols.nelements();
7133 41 : const Bool writeToDataCol = mustConvertToData(nDataCols, complexCols);
7134 :
7135 41 : copyDataFlagsWtSp(complexCols, writeToDataCol);
7136 41 : if(doFloat)
7137 0 : msc_p->floatData().putColumn(mscIn_p->floatData());
7138 41 : }
7139 : else{
7140 3 : doChannelMods(colNames);
7141 : }
7142 : os << LogIO::DEBUG1
7143 : << "Total data read/write time = " << timer.real()
7144 44 : << LogIO::POST;
7145 :
7146 44 : return success;
7147 44 : }
7148 :
7149 44 : Bool SubMS::existsFlagCategory() const
7150 : {
7151 44 : Bool hasFC = false;
7152 88 : if(!mscIn_p->flagCategory().isNull() &&
7153 44 : mscIn_p->flagCategory().isDefined(0)){
7154 0 : IPosition fcshape(mscIn_p->flagCategory().shape(0));
7155 0 : IPosition fshape(mscIn_p->flag().shape(0));
7156 :
7157 : // I don't know or care how many flag categories there are.
7158 0 : hasFC = fcshape(0) == fshape(0) && fcshape(1) == fshape(1);
7159 0 : }
7160 44 : return hasFC;
7161 : }
7162 :
7163 0 : Bool SubMS::getDataColumn(ArrayColumn<Complex>& data,
7164 : const MS::PredefinedColumns colName)
7165 : {
7166 0 : if(colName == MS::DATA)
7167 0 : data.reference(mscIn_p->data());
7168 0 : else if(colName == MS::MODEL_DATA)
7169 0 : data.reference(mscIn_p->modelData());
7170 0 : else if(colName == MS::LAG_DATA)
7171 0 : data.reference(mscIn_p->lagData());
7172 : else // The honored-by-time-if-nothing-else
7173 0 : data.reference(mscIn_p->correctedData()); // default.
7174 0 : return true;
7175 : }
7176 :
7177 0 : Bool SubMS::getDataColumn(ArrayColumn<Float>& data,
7178 : const MS::PredefinedColumns colName)
7179 : {
7180 0 : LogIO os(LogOrigin("SubMS", "getDataColumn()"));
7181 :
7182 0 : if(colName != MS::FLOAT_DATA)
7183 : os << LogIO::WARN
7184 : << "Using FLOAT_DATA (because it has type Float) instead of the requested "
7185 : << colName
7186 0 : << LogIO::POST;
7187 :
7188 0 : data.reference(mscIn_p->floatData());
7189 0 : return true;
7190 0 : }
7191 :
7192 0 : Bool SubMS::putDataColumn(MSColumns& msc, ArrayColumn<Complex>& data,
7193 : const MS::PredefinedColumns colName,
7194 : const Bool writeToDataCol)
7195 : {
7196 0 : if(writeToDataCol || colName == MS::DATA)
7197 0 : msc.data().putColumn(data);
7198 0 : else if (colName == MS::MODEL_DATA)
7199 0 : msc.modelData().putColumn(data);
7200 0 : else if (colName == MS::CORRECTED_DATA)
7201 0 : msc.correctedData().putColumn(data);
7202 : //else if(colName == MS::FLOAT_DATA) // promotion from Float
7203 : // msc.floatData().putColumn(data); // to Complex is pvt?
7204 0 : else if(colName == MS::LAG_DATA)
7205 0 : msc.lagData().putColumn(data);
7206 : else
7207 0 : return false;
7208 0 : return true;
7209 : }
7210 :
7211 0 : void SubMS::setFitOrder(Int fitorder, Bool advise)
7212 : {
7213 0 : fitorder_p = fitorder;
7214 :
7215 0 : if(advise){
7216 0 : LogIO os(LogOrigin("SubMS", "setFitOrder()"));
7217 :
7218 0 : if(fitorder < 0)
7219 : os << LogIO::NORMAL
7220 0 : << "Keeping the continuum.";
7221 0 : else if(fitorder > 1)
7222 : os << LogIO::WARN
7223 0 : << "Fit orders > 1 tend to drastically add noise to line channels.";
7224 0 : os << LogIO::POST;
7225 0 : }
7226 0 : }
7227 :
7228 0 : Bool SubMS::shouldWatch(Bool& conflict, const String& col,
7229 : const String& uncombinable,
7230 : const Bool verbose) const
7231 : {
7232 0 : Bool wantWatch = !combine_p.contains(col);
7233 :
7234 0 : if(!wantWatch && uncombinable.contains(col)){
7235 0 : conflict = true;
7236 0 : wantWatch = false;
7237 :
7238 0 : if(verbose){
7239 0 : LogIO os(LogOrigin("SubMS", "shouldWatch()"));
7240 :
7241 : os << LogIO::WARN
7242 : << "Combining by " << col
7243 : << " was requested, but it is not allowed by this operation and will be ignored."
7244 0 : << LogIO::POST;
7245 0 : }
7246 : }
7247 0 : return wantWatch;
7248 : }
7249 :
7250 0 : Bool SubMS::setSortOrder(Block<Int>& sort, const String& uncombinable,
7251 : const Bool verbose) const
7252 : {
7253 0 : Bool conflict = false;
7254 0 : uInt n_cols_to_watch = 7; // 3 + #(watchables), whether or not they are watched.
7255 :
7256 : // Already separated by the chunking.
7257 : //const Bool watch_array(!combine_p.contains("arr")); // Pirate talk for "array".
7258 :
7259 0 : Bool watch_obs = shouldWatch(conflict, "obs", uncombinable, verbose);
7260 0 : Bool watch_scan = shouldWatch(conflict, "scan", uncombinable, verbose);
7261 0 : Bool watch_spw = shouldWatch(conflict, "spw", uncombinable, verbose);
7262 0 : Bool watch_state = shouldWatch(conflict, "state", uncombinable, verbose);
7263 :
7264 : // if(watch_obs)
7265 : // ++n_cols_to_watch;
7266 : // if(watch_scan)
7267 : // ++n_cols_to_watch;
7268 : // if(watch_spw)
7269 : // ++n_cols_to_watch;
7270 : // if(watch_state)
7271 : // ++n_cols_to_watch;
7272 :
7273 0 : uInt colnum = 1;
7274 :
7275 0 : sort.resize(n_cols_to_watch);
7276 0 : sort[0] = MS::ARRAY_ID;
7277 0 : if(watch_scan){
7278 0 : sort[colnum] = MS::SCAN_NUMBER;
7279 0 : ++colnum;
7280 : }
7281 0 : if(watch_state){
7282 0 : sort[colnum] = MS::STATE_ID;
7283 0 : ++colnum;
7284 : }
7285 0 : sort[colnum] = MS::FIELD_ID;
7286 0 : ++colnum;
7287 0 : if(watch_spw){
7288 0 : sort[colnum] = MS::DATA_DESC_ID;
7289 0 : ++colnum;
7290 : }
7291 0 : sort[colnum] = MS::TIME;
7292 0 : ++colnum;
7293 0 : if(watch_obs){
7294 0 : sort[colnum] = MS::OBSERVATION_ID;
7295 0 : ++colnum;
7296 : }
7297 :
7298 : // Now all the axes that should be combined should be added, so that they end
7299 : // up in the same chunk.
7300 0 : if(!watch_scan){
7301 0 : sort[colnum] = MS::SCAN_NUMBER;
7302 0 : ++colnum;
7303 : }
7304 0 : if(!watch_state){
7305 0 : sort[colnum] = MS::STATE_ID;
7306 0 : ++colnum;
7307 : }
7308 0 : if(!watch_spw){
7309 0 : sort[colnum] = MS::DATA_DESC_ID;
7310 0 : ++colnum;
7311 : }
7312 0 : if(!watch_obs){
7313 0 : sort[colnum] = MS::OBSERVATION_ID;
7314 : //++colnum;
7315 : }
7316 :
7317 0 : return !conflict;
7318 : }
7319 :
7320 0 : Bool SubMS::subtractContinuum(const Vector<MS::PredefinedColumns>& colNames,
7321 : const VBRemapper& vbmaps)
7322 : {
7323 0 : LogIO os(LogOrigin("SubMS", "subtractContinuum()"));
7324 0 : Bool retval = true;
7325 :
7326 0 : if(colNames.nelements() != 1){
7327 : os << LogIO::SEVERE
7328 : << "The continuum cannot be subtracted from > 1 *DATA column at a time."
7329 0 : << LogIO::POST;
7330 0 : return false;
7331 : }
7332 :
7333 0 : Block<Int> sort;
7334 0 : if(!setSortOrder(sort, "obs,scan,state", false)){
7335 : os << LogIO::WARN
7336 : << "This version of continuum subtraction intentionally does not support\n"
7337 : << "time smearing. The only recommended (and used) values for combine in\n"
7338 : << "this case are '' or 'spw'."
7339 0 : << LogIO::POST;
7340 : }
7341 :
7342 : // Aaargh...everywhere else VisIter is used a timeInterval of 0 is treated as
7343 : // DBL_MAX, meaning that TIME can be in sort but effectively be ignored for
7344 : // major chunking. Why couldn't they just have said DBL_MAX in the first
7345 : // place?
7346 0 : ROVisibilityIterator viIn(mssel_p, sort, false, DBL_MIN);
7347 :
7348 : // Make sure it is initialized before any copies are made.
7349 0 : viIn.originChunks();
7350 :
7351 0 : VBGContinuumSubtractor vbgcs(msOut_p, msc_p, vbmaps, viIn, fitorder_p,
7352 0 : colNames[0], fitspw_p, fitoutspw_p);
7353 0 : vbgcs.setTVIDebug(tvi_debug);
7354 0 : vbgcs.setWantCont(want_cont_p);
7355 0 : GroupProcessor gp(viIn, &vbgcs);
7356 0 : gp.setTVIDebug(tvi_debug);
7357 :
7358 0 : retval = gp.go();
7359 :
7360 : // TODO: Support uvcontsub(3)'s spw parameter by
7361 : // * filtering the output by fitoutspw_p
7362 : // * remapping DDID as necessary, taking (union)spw into account
7363 : // * filtering and rewriting the DATA_DESC_ID and SPECTRAL_WINDOW subtables.
7364 :
7365 0 : return retval;
7366 0 : }
7367 :
7368 0 : void SubMS::fill_vbmaps(std::map<VisBufferComponents::EnumType, std::map<Int, Int> >& vbmaps)
7369 : {
7370 : // In general, _IDs which are row numbers in a subtable must be
7371 : // remapped, and those which are not probably shouldn't be.
7372 0 : if(antennaSel_p){
7373 0 : std::map<Int, Int> antIndexer;
7374 :
7375 0 : fillAntIndexer(antIndexer, mscIn_p);
7376 0 : vbmaps[VisBufferComponents::Ant1] = antIndexer;
7377 0 : vbmaps[VisBufferComponents::Ant2] = antIndexer;
7378 0 : }
7379 :
7380 0 : if(!allEQ(spwRelabel_p, spw_p)){
7381 0 : std::map<Int, Int> ddidMapper;
7382 :
7383 0 : for(uInt i = 0; i < oldDDSpwMatch_p.nelements(); ++i)
7384 0 : ddidMapper[i] = spwRelabel_p[oldDDSpwMatch_p[i]];
7385 :
7386 0 : vbmaps[VisBufferComponents::DataDescriptionId] = ddidMapper;
7387 0 : }
7388 :
7389 0 : if(fieldid_p.nelements() < mscIn_p->field().nrow()){
7390 0 : std::map<Int, Int> fldMapper;
7391 :
7392 0 : make_map2(fldMapper, fieldRelabel_p);
7393 0 : vbmaps[VisBufferComponents::FieldId] = fldMapper;
7394 0 : }
7395 :
7396 0 : if(selObsId_p.nelements() > 0 && selObsId_p.nelements() < mscIn_p->observation().nrow()){
7397 0 : std::map<Int, Int> obsMapper;
7398 :
7399 0 : make_map(obsMapper, selObsId_p);
7400 0 : vbmaps[VisBufferComponents::ObservationId] = obsMapper;
7401 0 : }
7402 :
7403 : //std::map<Int, Int> procMapper;
7404 : //make_map(procMapper, mscIn_p->processorId().getColumn());
7405 :
7406 0 : if(stateRemapper_p.size() < 1)
7407 0 : make_map(stateRemapper_p, mscIn_p->stateId().getColumn());
7408 0 : if(stateRemapper_p.size() < mscIn_p->state().nrow())
7409 0 : vbmaps[VisBufferComponents::StateId] = stateRemapper_p;
7410 0 : }
7411 :
7412 41 : Bool SubMS::copyDataFlagsWtSp(const Vector<MS::PredefinedColumns>& colNames,
7413 : const Bool writeToDataCol)
7414 : {
7415 41 : Block<Int> columns;
7416 : // include scan and state iteration, for more optimal iteration
7417 41 : columns.resize(6);
7418 41 : columns[0]=MS::ARRAY_ID;
7419 41 : columns[1]=MS::SCAN_NUMBER;
7420 41 : columns[2]=MS::STATE_ID;
7421 41 : columns[3]=MS::FIELD_ID;
7422 41 : columns[4]=MS::DATA_DESC_ID;
7423 41 : columns[5]=MS::TIME;
7424 :
7425 : #ifdef COPYTIMER
7426 : Timer timer;
7427 : timer.mark();
7428 :
7429 : Vector<Int> inscan, outscan;
7430 : #endif
7431 :
7432 41 : ROVisIter viIn(mssel_p,columns,0.0);
7433 41 : VisIter viOut(msOut_p,columns,0.0);
7434 41 : viIn.setRowBlocking(1000);
7435 41 : viOut.setRowBlocking(1000);
7436 41 : Int iChunk(0), iChunklet(0);
7437 41 : Cube<Complex> data;
7438 41 : Cube<Bool> flag;
7439 41 : Array<Bool> flagcat;
7440 :
7441 41 : Matrix<Float> wtmat;
7442 41 : viIn.originChunks(); // Makes me feel better.
7443 41 : const Bool doWtSp(viIn.existsWeightSpectrum());
7444 41 : Cube<Float> wtsp;
7445 :
7446 41 : uInt ninrows = mssel_p.nrow();
7447 : ProgressMeter meter(0.0, ninrows * 1.0, "split", "rows copied", "", "",
7448 82 : true, 1);
7449 41 : uInt inrowsdone = 0; // only for the meter.
7450 :
7451 41 : uInt nDataCols = colNames.nelements();
7452 :
7453 : // Is CORRECTED_DATA being moved to DATA?
7454 41 : Bool fromCorrToData = writeToDataCol && nDataCols == 1;
7455 41 : if(fromCorrToData)
7456 33 : fromCorrToData = colNames[0] == MS::CORRECTED_DATA;
7457 :
7458 41 : Bool doFC = existsFlagCategory();
7459 :
7460 41 : for (iChunk=0,viOut.originChunks(),viIn.originChunks();
7461 1336 : viOut.moreChunks(),viIn.moreChunks();
7462 1295 : viOut.nextChunk(),viIn.nextChunk(),++iChunk) {
7463 1295 : inrowsdone += viIn.nRowChunk();
7464 :
7465 : // The following can help evaluable in/out index alignment
7466 : /*
7467 : cout << "****iChunk=" << iChunk
7468 : << " scn: " << viIn.scan(inscan)(0) << "/" << viOut.scan(outscan)(0) << " "
7469 : << "fld: " << viIn.fieldId() << "/" << viOut.fieldId() << " "
7470 : << "ddi: " << viIn.dataDescriptionId() << "/" << viOut.dataDescriptionId() << " "
7471 : << "spw: " << viIn.spectralWindow() << "/" << viOut.spectralWindow() << " "
7472 : << endl;
7473 : */
7474 1295 : for (iChunklet=0,viIn.origin(),viOut.origin();
7475 3278 : viIn.more(),viOut.more();
7476 1983 : viIn++,viOut++,++iChunklet) { //
7477 :
7478 : // cout << "nRows = " << viIn.nRow() << "/" << viOut.nRow() << endl;
7479 :
7480 : #ifdef COPYTIMER
7481 : timer.mark();
7482 : #endif
7483 1983 : viIn.flag(flag);
7484 1983 : viOut.setFlag(flag);
7485 1983 : if(doFC){
7486 0 : viIn.flagCategory(flagcat);
7487 0 : viOut.setFlagCategory(flagcat);
7488 : }
7489 1983 : if(fromCorrToData) {
7490 50 : viIn.weightMat(wtmat);
7491 50 : viOut.setWeightMat(wtmat);
7492 50 : arrayTransformInPlace(wtmat, subms::wtToSigma); // for corrected weights.
7493 50 : viOut.setSigmaMat(wtmat);
7494 : }
7495 : else {
7496 1933 : viIn.sigmaMat(wtmat); // Yes, I'm reusing wtmat.
7497 1933 : viOut.setSigmaMat(wtmat);
7498 1933 : arrayTransformInPlace(wtmat, subms::sigToWeight); // for corrected weights.
7499 1933 : viOut.setWeightMat(wtmat);
7500 : }
7501 :
7502 1983 : if(doWtSp){
7503 1916 : viIn.weightSpectrum(wtsp);
7504 1916 : viOut.setWeightSpectrum(wtsp);
7505 : }
7506 :
7507 4019 : for(uInt colnum = 0; colnum < nDataCols; ++colnum){
7508 2036 : if(writeToDataCol || colNames[colnum] == MS::DATA) {
7509 : // write DATA, MODEL_DATA, or CORRECTED_DATA to DATA
7510 1983 : switch (colNames[colnum]) {
7511 1925 : case MS::DATA:
7512 1925 : viIn.visibility(data,VisibilityIterator::Observed);
7513 1925 : break;
7514 8 : case MS::MODEL_DATA:
7515 8 : viIn.visibility(data,VisibilityIterator::Model);
7516 8 : break;
7517 50 : case MS::CORRECTED_DATA:
7518 50 : viIn.visibility(data,VisibilityIterator::Corrected);
7519 50 : break;
7520 0 : default:
7521 0 : throw(AipsError("Unrecognized input column!"));
7522 : break;
7523 : }
7524 1983 : viOut.setVis(data,VisibilityIterator::Observed);
7525 : }
7526 53 : else if (colNames[colnum] == MS::MODEL_DATA) {
7527 : // write MODEL_DATA to MODEL_DATA
7528 26 : viIn.visibility(data,VisibilityIterator::Model);
7529 26 : viOut.setVis(data,VisibilityIterator::Model);
7530 : }
7531 27 : else if (colNames[colnum] == MS::CORRECTED_DATA) {
7532 : // write CORRECTED_DATA to CORRECTED_DATA
7533 27 : viIn.visibility(data,VisibilityIterator::Corrected);
7534 27 : viOut.setVis(data,VisibilityIterator::Corrected);
7535 : }
7536 : //else if(colNames[colnum] == MS::FLOAT_DATA) // TBD
7537 : // else if(colNames[colnum] == MS::LAG_DATA) // TBD
7538 : else
7539 0 : return false;
7540 : }
7541 :
7542 : #ifdef COPYTIMER
7543 : Double t=timer.real();
7544 : cout << "Chunk: " << iChunk << " " << iChunklet
7545 : << " scn: " << viIn.scan(inscan)(0) << "/" << viOut.scan(outscan)(0)
7546 : << " "
7547 : << " spw: " << viIn.spectralWindow() << "/" << viOut.spectralWindow()
7548 : << " : "
7549 : << data.nelements() << " cells = "
7550 : << data.nelements()*8.e-6 << " MB in "
7551 : << t << " sec, for " << data.nelements()*8.e-6/t << " MB/s"
7552 : << endl;
7553 : #endif
7554 :
7555 : }
7556 1295 : meter.update(inrowsdone);
7557 : }
7558 41 : return true;
7559 41 : }
7560 :
7561 0 : Bool SubMS::putDataColumn(MSColumns& msc, ArrayColumn<Float>& data,
7562 : const MS::PredefinedColumns colName,
7563 : const Bool writeToDataCol)
7564 : {
7565 0 : LogIO os(LogOrigin("SubMS", "putDataColumn()"));
7566 :
7567 0 : if(writeToDataCol)
7568 : os << LogIO::NORMAL
7569 : << "Writing to FLOAT_DATA instead of DATA."
7570 0 : << LogIO::POST;
7571 :
7572 0 : if(colName == MS::FLOAT_DATA){
7573 0 : msc.floatData().putColumn(data);
7574 : }
7575 : else{
7576 : os << LogIO::SEVERE
7577 : << "Float data cannot be written to "
7578 : << MS::columnName(colName)
7579 0 : << LogIO::POST;
7580 0 : return false;
7581 : }
7582 0 : return true;
7583 0 : }
7584 :
7585 : // Sets outcol to row numbers in the corresponding subtable of its ms that
7586 : // correspond to the values of incol.
7587 : //
7588 : // Can only be used when incol and outcol have the same # of rows!
7589 : //
7590 44 : void SubMS::remapColumn(ScalarColumn<Int>& outcol,
7591 : const ScalarColumn<Int>& incol)
7592 : {
7593 44 : uInt nrows = incol.nrow();
7594 :
7595 44 : if(nrows != outcol.nrow()){
7596 0 : ostringstream ostr;
7597 :
7598 0 : ostr << "SubMS::remapColumn(): the # of input rows, " << nrows
7599 0 : << ", != the # of output rows, " << outcol.nrow();
7600 0 : throw(AipsError(ostr.str()));
7601 0 : }
7602 :
7603 44 : std::map<Int, Int> mapper;
7604 44 : Vector<Int> inv(incol.getColumn());
7605 :
7606 44 : make_map(mapper, inv);
7607 44 : if(mapper.size() == 1){
7608 43 : outcol.fillColumn(0); // Just a little optimization.
7609 : }
7610 : else{
7611 1 : Vector<Int> outv(nrows);
7612 :
7613 1 : if(mapper.size() > 0){
7614 46501 : for(uInt k = 0; k < nrows; ++k)
7615 46500 : outv[k] = mapper[inv[k]];
7616 : }
7617 : else
7618 0 : incol.getColumn(outv);
7619 1 : outcol.putColumn(outv);
7620 1 : }
7621 44 : }
7622 :
7623 44 : void SubMS::remapColumn(ScalarColumn<Int>& outcol,
7624 : const ScalarColumn<Int>& incol,
7625 : const Vector<Int>& selvals)
7626 : {
7627 44 : uInt nrows = incol.nrow();
7628 :
7629 44 : if(nrows != outcol.nrow()){
7630 0 : ostringstream ostr;
7631 :
7632 0 : ostr << "SubMS::remapColumn(): the # of input rows, " << nrows
7633 0 : << ", != the # of output rows, " << outcol.nrow();
7634 0 : throw(AipsError(ostr.str()));
7635 0 : }
7636 :
7637 44 : std::map<Int, Int> mapper;
7638 44 : Vector<Int> inv(incol.getColumn());
7639 44 : Vector<Int> outv(nrows);
7640 :
7641 44 : make_map(mapper, selvals);
7642 44 : if(mapper.size() == 1){
7643 0 : outcol.fillColumn(0); // Just a little optimization.
7644 : }
7645 : else{
7646 44 : Vector<Int> outv(nrows);
7647 :
7648 44 : if(mapper.size() > 0){
7649 0 : for(uInt k = 0; k < nrows; ++k)
7650 0 : outv[k] = mapper[inv[k]];
7651 : }
7652 : else
7653 44 : incol.getColumn(outv);
7654 44 : outcol.putColumn(outv);
7655 44 : }
7656 44 : }
7657 :
7658 : // Realigns some _ID vectors so that the output looks like a whole dataset
7659 : // instead of part of one. (i.e. we don't want references to unselected spws,
7660 : // etc.)
7661 44 : void SubMS::relabelIDs()
7662 : {
7663 44 : const ScalarColumn<Int> inDDID(mscIn_p->dataDescId());
7664 44 : const ScalarColumn<Int> fieldId(mscIn_p->fieldId());
7665 :
7666 815895 : for(Int k = inDDID.nrow(); k--;){
7667 815851 : msc_p->dataDescId().put(k, spwRelabel_p[oldDDSpwMatch_p[inDDID(k)]]);
7668 815851 : msc_p->fieldId().put(k, fieldRelabel_p[fieldId(k)]);
7669 : }
7670 :
7671 : //remapColumn(msc_p->arrayId(), mscIn_p->arrayId());
7672 44 : remapColumn(msc_p->stateId(), mscIn_p->stateId());
7673 : //remapColumn(msc_p->processorId(), mscIn_p->processorId());
7674 44 : remapColumn(msc_p->observationId(), mscIn_p->observationId(), selObsId_p);
7675 44 : }
7676 :
7677 0 : Bool SubMS::writeSomeMainRows(const Vector<MS::PredefinedColumns>& colNames)
7678 : {
7679 0 : LogIO os(LogOrigin("SubMS", "writeSomeMainRows()"));
7680 0 : Bool retval = true;
7681 :
7682 : os << LogIO::DEBUG1 // helpdesk ticket in from Oleg Smirnov (ODU-232630)
7683 : << "Before fillAntIndexer(): "
7684 0 : << Memory::allocatedMemoryInBytes() / (1024.0 * 1024.0) << " MB"
7685 0 : << LogIO::POST;
7686 :
7687 : // A set of maps from input ID to output ID, keyed by VisBufferComponent.
7688 0 : std::map<VisBufferComponents::EnumType, std::map<Int, Int> > vbmaps;
7689 0 : fill_vbmaps(vbmaps);
7690 0 : VBRemapper remapper(vbmaps);
7691 :
7692 : //things to be taken care of in doTimeAver() or subtractContinuum...
7693 : // flagRow ScanNumber uvw weight
7694 : // sigma ant1 ant2 time
7695 : // timeCentroid feed1 feed2 exposure
7696 : // stateId processorId observationId arrayId
7697 0 : if(fitorder_p >= 0)
7698 0 : retval = subtractContinuum(colNames, remapper); // writeToDataCol = complexCols == 1
7699 : else
7700 0 : retval = (corrString_p != "") ? doTimeAverVisIterator(colNames, remapper)
7701 0 : : doTimeAver(colNames, remapper);
7702 0 : return retval;
7703 0 : }
7704 :
7705 184 : uInt SubMS::addOptionalColumns(const Table& inTab, Table& outTab,
7706 : const Bool beLazy)
7707 : {
7708 184 : uInt nAdded = 0;
7709 184 : const TableDesc& inTD = inTab.actualTableDesc();
7710 :
7711 : // Only rely on the # of columns if you are sure that inTab and outTab
7712 : // can't have the same # of columns without having _different_ columns,
7713 : // i.e. use beLazy if outTab.actualTableDesc() is in its default state.
7714 184 : uInt nInCol = inTD.ncolumn();
7715 184 : if(!beLazy || nInCol > outTab.actualTableDesc().ncolumn()){
7716 110 : LogIO os(LogOrigin("SubMS", "addOptionalColumns()"));
7717 :
7718 55 : Vector<String> oldColNames = inTD.columnNames();
7719 :
7720 860 : for(uInt k = 0; k < nInCol; ++k){
7721 805 : if(!outTab.actualTableDesc().isColumn(oldColNames[k])){
7722 : //TableDesc tabDesc;
7723 : try{
7724 : //M::addColumnToDesc(tabDesc, M::columnType(oldColNames[k]));
7725 : //if(tabDesc.ncolumn()) // The tabDesc[0] is too
7726 : // outTab.addColumn(tabDesc[0]); // dangerous otherwise - it
7727 : //else // can dump core without
7728 : // throw(AipsError("Unknown column")); // throwing an exception.
7729 285 : outTab.addColumn(inTD.columnDesc(k), false);
7730 285 : ++nAdded;
7731 : }
7732 0 : catch(...){ // NOT AipsError x
7733 : os << LogIO::WARN
7734 0 : << "Could not add column " << oldColNames[k] << " to "
7735 : << outTab.tableName()
7736 0 : << LogIO::POST;
7737 0 : }
7738 : }
7739 : }
7740 55 : }
7741 184 : return nAdded;
7742 184 : }
7743 :
7744 0 : Bool SubMS::copyCols(Table& out, const Table& in, const Bool flush)
7745 : {
7746 0 : LogIO os(LogOrigin("SubMS", "copyCols()"));
7747 0 : const TableDesc& inTD = in.actualTableDesc();
7748 0 : Vector<String> inColNames = inTD.columnNames();
7749 0 : uInt nInCol = inTD.ncolumn();
7750 0 : Bool retval = true;
7751 :
7752 0 : if(in.nrow() > out.nrow())
7753 0 : out.addRow(in.nrow() - out.nrow());
7754 :
7755 0 : for(uInt k = 0; k < nInCol; ++k){
7756 : // Add the input column desc to out if necessary.
7757 0 : if(!out.actualTableDesc().isColumn(inColNames[k])){
7758 : try{
7759 0 : out.addColumn(inTD.columnDesc(k), false);
7760 : }
7761 0 : catch(...){ // NOT AipsError x
7762 : os << LogIO::WARN
7763 0 : << "Could not add column " << inColNames[k] << " to "
7764 : << out.tableName()
7765 0 : << LogIO::POST;
7766 0 : retval = false;
7767 0 : }
7768 : }
7769 :
7770 : // I can't see a way to explicitly* avoid constructing these in each
7771 : // iteration. (attach() would implicitly construct them.)
7772 : // * without relying on compiler optimization.
7773 0 : TableColumn incol(in, inColNames[k]);
7774 0 : TableColumn outcol(out, inColNames[k]);
7775 :
7776 0 : outcol.putColumn(incol);
7777 0 : }
7778 0 : if(flush)
7779 0 : out.flush();
7780 0 : return retval;
7781 0 : }
7782 :
7783 44 : Bool SubMS::copyAntenna(){
7784 44 : const MSAntenna& oldAnt = mssel_p.antenna();
7785 44 : MSAntenna& newAnt = msOut_p.antenna();
7786 44 : const MSAntennaColumns incols(oldAnt);
7787 44 : MSAntennaColumns outcols(newAnt);
7788 44 : Bool retval = false;
7789 :
7790 44 : outcols.setOffsetRef(MPosition::castType(incols.offsetMeas().getMeasRef().getType()));
7791 44 : outcols.setPositionRef(MPosition::castType(incols.positionMeas().getMeasRef().getType()));
7792 :
7793 44 : if(!antennaSel_p){
7794 44 : TableCopy::copyRows(newAnt, oldAnt);
7795 44 : retval = true;
7796 : }
7797 : else{
7798 0 : uInt nAnt = antNewIndex_p.nelements();
7799 0 : if(nAnt > oldAnt.nrow()) // Don't use min() here,
7800 0 : nAnt = oldAnt.nrow(); // it's too overloaded.
7801 :
7802 0 : for(uInt k = 0; k < nAnt; ++k){
7803 0 : if(antNewIndex_p[k] > -1)
7804 0 : TableCopy::copyRows(newAnt, oldAnt, antNewIndex_p[k], k, 1, false);
7805 : }
7806 0 : retval = true;
7807 : }
7808 44 : return retval;
7809 44 : }
7810 :
7811 :
7812 44 : Bool SubMS::copyFeed()
7813 : {
7814 44 : const MSFeed& oldFeed = mssel_p.feed();
7815 :
7816 : // if(oldFeed.nrow() < 1) Useless, because it ignores spw selection
7817 :
7818 44 : MSFeed& newFeed = msOut_p.feed();
7819 44 : const MSFeedColumns incols(oldFeed);
7820 44 : MSFeedColumns outcols(newFeed);
7821 :
7822 44 : outcols.setDirectionRef(MDirection::castType(incols.beamOffsetMeas().getMeasRef().getType()));
7823 44 : outcols.setEpochRef(MEpoch::castType(incols.timeMeas().getMeasRef().getType()));
7824 44 : outcols.setPositionRef(MPosition::castType(incols.positionMeas().getMeasRef().getType()));
7825 :
7826 44 : if(!antennaSel_p && allEQ(spwRelabel_p, spw_p)){
7827 27 : TableCopy::copyRows(newFeed, oldFeed);
7828 : }
7829 : else{
7830 17 : const Vector<Int>& antIds = incols.antennaId().getColumn();
7831 17 : const Vector<Int>& spwIds = incols.spectralWindowId().getColumn();
7832 :
7833 : // Copy selected rows.
7834 17 : uInt totNFeeds = antIds.nelements();
7835 17 : uInt totalSelFeeds = 0;
7836 17 : Int maxSelAntp1 = antNewIndex_p.nelements();
7837 1982 : for (uInt k = 0; k < totNFeeds; ++k){
7838 : // antenna must be selected, and spwId must be -1 (any) or selected.
7839 3930 : if(antIds[k] < maxSelAntp1 && antNewIndex_p[antIds[k]] > -1 &&
7840 1965 : (spwIds[k] < 0 || spwRelabel_p[spwIds[k]] > -1)){
7841 : // outtab intab outrow inrow nrows
7842 249 : TableCopy::copyRows(newFeed, oldFeed, totalSelFeeds, k, 1, false);
7843 249 : ++totalSelFeeds;
7844 : }
7845 : }
7846 :
7847 : // Remap antenna and spw #s.
7848 17 : ScalarColumn<Int>& antCol = outcols.antennaId();
7849 17 : ScalarColumn<Int>& spwCol = outcols.spectralWindowId();
7850 :
7851 266 : for(uInt k = 0; k < totalSelFeeds; ++k){
7852 249 : antCol.put(k, antNewIndex_p[antCol(k)]);
7853 249 : if(spwCol(k) > -1)
7854 160 : spwCol.put(k, spwRelabel_p[spwCol(k)]);
7855 : }
7856 17 : }
7857 :
7858 44 : if(newFeed.nrow() < 1){
7859 0 : LogIO os(LogOrigin("SubMS", "copyFeed()"));
7860 0 : os << LogIO::SEVERE << "No feeds were selected." << LogIO::POST;
7861 0 : return false;
7862 0 : }
7863 44 : return true;
7864 44 : }
7865 :
7866 44 : Bool SubMS::copyFlag_Cmd(){
7867 : // Like POINTING, FLAG_CMD is supposed to exist but is allowed not to.
7868 44 : if(Table::isReadable(mssel_p.flagCmdTableName())){
7869 : // An attempt to select from FLAG_CMD by timerange. Fails because the
7870 : // TEN refers to the main table, not FLAG_CMD.
7871 : // TableExprNode condition;
7872 :
7873 : // if(timeRange_p != "" &&
7874 : // msTimeGramParseCommand(&ms_p, timeRange_p, condition) == 0){
7875 : // const TableExprNode *timeNode = 0x0;
7876 :
7877 : // timeNode = msTimeGramParseNode();
7878 : // if(timeNode && !timeNode->isNull())
7879 : // condition = *timeNode;
7880 : // }
7881 :
7882 44 : const MSFlagCmd& oldFlag_Cmd = mssel_p.flagCmd();
7883 :
7884 44 : if(oldFlag_Cmd.nrow() > 0){
7885 : // Could be declared as Table&
7886 2 : MSFlagCmd& newFlag_Cmd = msOut_p.flagCmd();
7887 :
7888 4 : LogIO os(LogOrigin("SubMS", "copyFlag_Cmd()"));
7889 :
7890 : // Add optional columns if present in oldFlag_Cmd.
7891 2 : uInt nAddedCols = addOptionalColumns(oldFlag_Cmd, newFlag_Cmd, true);
7892 : os << LogIO::DEBUG1 << "FLAG_CMD has " << nAddedCols
7893 2 : << " optional columns." << LogIO::POST;
7894 :
7895 2 : const MSFlagCmdColumns oldFCs(oldFlag_Cmd);
7896 2 : MSFlagCmdColumns newFCs(newFlag_Cmd);
7897 2 : newFCs.setEpochRef(MEpoch::castType(oldFCs.timeMeas().getMeasRef().getType()));
7898 :
7899 : //if(!antennaSel_p && timeRange_p == ""){
7900 2 : TableCopy::copyRows(newFlag_Cmd, oldFlag_Cmd);
7901 : // }
7902 : // else{
7903 : // const ScalarColumn<Double>& time = oldFCs.time();
7904 :
7905 : // uInt nTRanges = selTimeRanges_p.ncolumn();
7906 :
7907 : // uInt outRow = 0;
7908 : // for (uInt inRow = 0; inRow < antIds.nrow(); ++inRow){
7909 : // Int newAntInd = antIds(inRow);
7910 : // if(antennaSel_p)
7911 : // newAntInd = antNewIndex_p[newAntInd];
7912 : // Double t = time(inRow);
7913 :
7914 : // if(newAntInd > -1){
7915 : // Bool matchT = false;
7916 : // for(uInt tr = 0; tr < nTRanges; ++tr){
7917 : // if(t >= selTimeRanges_p(0, tr) && t <= selTimeRanges_p(1, tr)){
7918 : // matchT = true;
7919 : // break;
7920 : // }
7921 : // }
7922 :
7923 : // if(matchT){
7924 : // TableCopy::copyRows(newFlag_Cmd, oldFlag_Cmd, outRow, inRow, 1, false);
7925 : // outants.put(outRow, newAntInd);
7926 : // ++outRow;
7927 : // }
7928 : // }
7929 : // }
7930 2 : }
7931 : }
7932 44 : return true;
7933 : }
7934 :
7935 44 : Bool SubMS::copyHistory(){
7936 44 : const MSHistory& oldHistory = mssel_p.history();
7937 :
7938 : // Could be declared as Table&
7939 44 : MSHistory& newHistory = msOut_p.history();
7940 :
7941 88 : LogIO os(LogOrigin("SubMS", "copyHistory()"));
7942 :
7943 : // Add optional columns if present in oldHistory.
7944 44 : uInt nAddedCols = addOptionalColumns(oldHistory, newHistory, true);
7945 : os << LogIO::DEBUG1 << "HISTORY has " << nAddedCols
7946 44 : << " optional columns." << LogIO::POST;
7947 :
7948 44 : const MSHistoryColumns oldHCs(oldHistory);
7949 44 : MSHistoryColumns newHCs(newHistory);
7950 44 : newHCs.setEpochRef(MEpoch::castType(oldHCs.timeMeas().getMeasRef().getType()));
7951 :
7952 44 : TableCopy::copyRows(newHistory, oldHistory);
7953 44 : return true;
7954 44 : }
7955 :
7956 44 : Bool SubMS::copySource(){
7957 : //Source is an optional table, so it may not exist
7958 44 : if(Table::isReadable(mssel_p.sourceTableName())){
7959 88 : LogIO os(LogOrigin("SubMS", "copySource()"));
7960 :
7961 44 : const MSSource& oldSource = mssel_p.source();
7962 44 : MSSource& newSource = msOut_p.source();
7963 :
7964 : // Add optional columns if present in oldSource.
7965 44 : uInt nAddedCols = addOptionalColumns(oldSource, newSource, true);
7966 : os << LogIO::DEBUG1 << "SOURCE has " << nAddedCols
7967 44 : << " optional columns." << LogIO::POST;
7968 :
7969 44 : const MSSourceColumns incols(oldSource);
7970 44 : MSSourceColumns outcols(newSource);
7971 :
7972 : // Copy the Measures frame info. This has to be done before filling the
7973 : // rows.
7974 44 : outcols.setEpochRef(MEpoch::castType(incols.timeMeas().getMeasRef().getType()));
7975 44 : outcols.setDirectionRef(MDirection::castType(incols.directionMeas().getMeasRef().getType()));
7976 44 : outcols.setPositionRef(MPosition::castType(incols.positionMeas().getMeasRef().getType()));
7977 44 : outcols.setFrequencyRef(MFrequency::castType(incols.restFrequencyMeas().getMeasRef().getType()));
7978 44 : outcols.setRadialVelocityRef(MRadialVelocity::castType(incols.sysvelMeas().getMeasRef().getType()));
7979 :
7980 44 : const ScalarColumn<Int>& inSId = incols.sourceId();
7981 44 : ScalarColumn<Int>& outSId = outcols.sourceId();
7982 44 : const ScalarColumn<Int>& inSPW = incols.spectralWindowId();
7983 44 : ScalarColumn<Int>& outSPW = outcols.spectralWindowId();
7984 :
7985 : // 2009-06-09: It is hard to say whether to remap pulsarID when the
7986 : // PULSAR table is not described in the MS v2.0 def'n.
7987 : // const ScalarColumn<Int>& inPId = incols.pulsarId();
7988 : // ScalarColumn<Int>& outPId = outcols.pulsarId();
7989 :
7990 44 : uInt outrn = 0; // row number in output.
7991 44 : uInt nInputRows = inSId.nrow();
7992 44 : Int maxSId = sourceRelabel_p.nelements(); // inSidVal is Int.
7993 44 : Int maxSPWId = spwRelabel_p.nelements();
7994 1849 : for(uInt inrn = 0; inrn < nInputRows; ++inrn){
7995 1805 : Int inSidVal = inSId(inrn);
7996 1805 : Int inSPWVal = inSPW(inrn); // -1 means the source is valid for any SPW.
7997 :
7998 1805 : if(inSidVal >= maxSId)
7999 : os << LogIO::WARN
8000 0 : << "Invalid SOURCE ID in SOURCE table row " << inrn << LogIO::POST;
8001 1805 : if(inSPWVal >= maxSPWId)
8002 : os << LogIO::WARN
8003 0 : << "Invalid SPW ID in SOURCE table row " << inrn << LogIO::POST;
8004 :
8005 1805 : if((inSidVal > -1) && (inSidVal < maxSId) &&
8006 5322 : (sourceRelabel_p[inSidVal] > -1) &&
8007 1712 : ((inSPWVal == -1) || (inSPWVal < maxSPWId && spwRelabel_p[inSPWVal] > -1))){
8008 : // Copy inrn to outrn.
8009 266 : TableCopy::copyRows(newSource, oldSource, outrn, inrn, 1);
8010 266 : outSId.put(outrn, sourceRelabel_p[inSidVal]);
8011 266 : outSPW.put(outrn, inSPWVal > -1 ? spwRelabel_p[inSPWVal] : -1);
8012 :
8013 266 : ++outrn;
8014 : }
8015 : }
8016 :
8017 44 : return true;
8018 44 : }
8019 :
8020 0 : return false;
8021 : }
8022 :
8023 44 : Bool SubMS::copyGenericSubtables(){
8024 88 : LogIO os(LogOrigin("SubMS", "copyGenericSubtables()"));
8025 :
8026 : // Already handled subtables will be removed from this, so a modifiable copy
8027 : // is needed.
8028 44 : TableRecord inkws(mssel_p.keywordSet());
8029 :
8030 : // Some of the standard subtables need special handling,
8031 : // e.g. DATA_DESCRIPTION, SPECTRAL_WINDOW, and ANTENNA, so they are already
8032 : // defined in msOut_p. Several more (e.g. FLAG_CMD) were also already
8033 : // created by MS::createDefaultSubtables(). Don't try to write over them - a
8034 : // locking error will result.
8035 44 : const TableRecord& outkws = msOut_p.keywordSet();
8036 668 : for(uInt i = 0; i < outkws.nfields(); ++i){
8037 : // os << LogIO::DEBUG1
8038 : // << "outkws.name(" << i << "): " << outkws.name(i)
8039 : // << LogIO::POST;
8040 624 : if(outkws.type(i) == TpTable && inkws.isDefined(outkws.name(i)))
8041 580 : inkws.removeField(outkws.name(i));
8042 : }
8043 :
8044 : // Includes a flush.
8045 : //msOut_p.unlock();
8046 :
8047 : // msOut_p.rwKeywordSet() (pass a reference, not a copy) will put a lock on
8048 : // msOut_p.
8049 44 : TableCopy::copySubTables(msOut_p.rwKeywordSet(), inkws, msOut_p.tableName(),
8050 : msOut_p.tableType(), mssel_p);
8051 : // TableCopy::copySubTables(Table, Table, Bool) includes this other code,
8052 : // which seems to be copying subtables at one level deeper, but not
8053 : // recursively?
8054 44 : const TableDesc& inDesc = mssel_p.tableDesc();
8055 44 : const TableDesc& outDesc = msOut_p.tableDesc();
8056 1077 : for(uInt i = 0; i < outDesc.ncolumn(); ++i){
8057 : // Only writable cols can have keywords (and thus subtables) defined.
8058 1033 : if(msOut_p.isColumnWritable(i)){
8059 1033 : const String& name = outDesc[i].name();
8060 :
8061 1033 : if(inDesc.isColumn(name)){
8062 1032 : TableColumn outCol(msOut_p, name);
8063 1032 : TableColumn inCol(mssel_p, name);
8064 :
8065 1032 : TableCopy::copySubTables(outCol.rwKeywordSet(), inCol.keywordSet(),
8066 : msOut_p.tableName(), msOut_p.tableType(),
8067 : mssel_p);
8068 :
8069 : // Copy the keywords if column is FLOAT_DATA
8070 1032 : if (name == "FLOAT_DATA")
8071 0 : copyMainTableKeywords(outCol.rwKeywordSet(), inCol.keywordSet());
8072 :
8073 1032 : }
8074 : }
8075 : }
8076 :
8077 44 : return true;
8078 44 : }
8079 :
8080 44 : Bool SubMS::copyObservation()
8081 : {
8082 44 : const MSObservation& oldObs = mssel_p.observation();
8083 44 : MSObservation& newObs = msOut_p.observation();
8084 44 : const MSObservationColumns oldObsCols(oldObs);
8085 44 : MSObservationColumns newObsCols(newObs);
8086 44 : newObsCols.setEpochRef(MEpoch::castType(oldObsCols.releaseDateMeas().getMeasRef().getType()));
8087 :
8088 44 : uInt nObs = selObsId_p.nelements();
8089 44 : if(nObs > 0){
8090 0 : for(uInt outrn = 0; outrn < nObs; ++outrn)
8091 0 : TableCopy::copyRows(newObs, oldObs, outrn, selObsId_p[outrn], 1);
8092 : }
8093 : else // '' -> '*'
8094 44 : TableCopy::copyRows(newObs, oldObs);
8095 :
8096 : //W TableCopy::deepCopy(newObs, oldObs, false);
8097 :
8098 44 : return true;
8099 44 : }
8100 :
8101 44 : Bool SubMS::copyProcessor()
8102 : {
8103 44 : const MSProcessor& oldProc = mssel_p.processor();
8104 44 : MSProcessor& newProc = msOut_p.processor();
8105 :
8106 44 : TableCopy::copyRows(newProc, oldProc);
8107 : //W TableCopy::deepCopy(newProc, oldProc, false);
8108 :
8109 44 : return true;
8110 : }
8111 :
8112 44 : Bool SubMS::copyState()
8113 : {
8114 : // STATE is allowed to not exist, even though it is not optional in the MS
8115 : // def'n. For one thing, split dropped it for quite a while.
8116 44 : if(Table::isReadable(mssel_p.stateTableName())){
8117 88 : LogIO os(LogOrigin("SubMS", "copyState()"));
8118 44 : const MSState& oldState = mssel_p.state();
8119 :
8120 44 : if(oldState.nrow() > 0){
8121 5 : MSState& newState = msOut_p.state();
8122 5 : const MSStateColumns oldStateCols(oldState);
8123 5 : MSStateColumns newStateCols(newState);
8124 :
8125 : // Initialize stateRemapper_p if necessary.
8126 5 : if(stateRemapper_p.size() < 1)
8127 5 : make_map(stateRemapper_p, mscIn_p->stateId().getColumn());
8128 :
8129 5 : uInt nStates = stateRemapper_p.size();
8130 :
8131 : // stateRemapper_p goes from input to output, as is wanted in most
8132 : // places. Here we need a map going the other way, so make one.
8133 5 : Vector<Int> outStateToInState(nStates);
8134 5 : std::map<Int, Int>::iterator mit;
8135 :
8136 14 : for(mit = stateRemapper_p.begin(); mit != stateRemapper_p.end(); ++mit)
8137 9 : outStateToInState[(*mit).second] = (*mit).first;
8138 :
8139 14 : for(uInt outrn = 0; outrn < nStates; ++outrn)
8140 9 : TableCopy::copyRows(newState, oldState, outrn,
8141 9 : outStateToInState[outrn], 1);
8142 5 : }
8143 44 : }
8144 44 : return true;
8145 : }
8146 :
8147 122 : void SubMS::createSubtables(MeasurementSet& ms, Table::TableOption option)
8148 : {
8149 0 : SetupNewTable antennaSetup(ms.antennaTableName(),
8150 122 : MSAntenna::requiredTableDesc(),option);
8151 244 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::ANTENNA),
8152 244 : Table(antennaSetup));
8153 0 : SetupNewTable dataDescSetup(ms.dataDescriptionTableName(),
8154 122 : MSDataDescription::requiredTableDesc(),option);
8155 244 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::DATA_DESCRIPTION),
8156 244 : Table(dataDescSetup));
8157 0 : SetupNewTable feedSetup(ms.feedTableName(),
8158 122 : MSFeed::requiredTableDesc(),option);
8159 122 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::FEED), Table(feedSetup));
8160 0 : SetupNewTable flagCmdSetup(ms.flagCmdTableName(),
8161 122 : MSFlagCmd::requiredTableDesc(),option);
8162 244 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::FLAG_CMD),
8163 244 : Table(flagCmdSetup));
8164 0 : SetupNewTable fieldSetup(ms.fieldTableName(),
8165 122 : MSField::requiredTableDesc(),option);
8166 122 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::FIELD), Table(fieldSetup));
8167 0 : SetupNewTable historySetup(ms.historyTableName(),
8168 122 : MSHistory::requiredTableDesc(),option);
8169 244 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::HISTORY),
8170 244 : Table(historySetup));
8171 0 : SetupNewTable observationSetup(ms.observationTableName(),
8172 122 : MSObservation::requiredTableDesc(),option);
8173 244 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::OBSERVATION),
8174 244 : Table(observationSetup));
8175 0 : SetupNewTable polarizationSetup(ms.polarizationTableName(),
8176 122 : MSPolarization::requiredTableDesc(),option);
8177 244 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::POLARIZATION),
8178 244 : Table(polarizationSetup));
8179 0 : SetupNewTable processorSetup(ms.processorTableName(),
8180 122 : MSProcessor::requiredTableDesc(),option);
8181 244 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::PROCESSOR),
8182 244 : Table(processorSetup));
8183 0 : SetupNewTable spectralWindowSetup(ms.spectralWindowTableName(),
8184 122 : MSSpectralWindow::requiredTableDesc(),option);
8185 244 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::SPECTRAL_WINDOW),
8186 244 : Table(spectralWindowSetup));
8187 0 : SetupNewTable stateSetup(ms.stateTableName(),
8188 122 : MSState::requiredTableDesc(),option);
8189 244 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::STATE),
8190 244 : Table(stateSetup));
8191 :
8192 : // add the optional Source sub table to allow for specification of the rest
8193 : // frequency
8194 0 : SetupNewTable sourceSetup(ms.sourceTableName(), MSSource::requiredTableDesc(),
8195 122 : option);
8196 244 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::SOURCE),
8197 244 : Table(sourceSetup, 0));
8198 :
8199 : // update the references to the subtable keywords
8200 122 : ms.initRefs();
8201 122 : }
8202 :
8203 44 : Bool SubMS::copyPointing(){
8204 88 : LogIO os(LogOrigin("SubMS", "copyPointing()"));
8205 :
8206 : //Pointing is allowed to not exist
8207 44 : if(Table::isReadable(mssel_p.pointingTableName())){
8208 : // An attempt to select from POINTING by timerange. Fails because the
8209 : // TEN refers to the main table, not POINTING.
8210 : // TableExprNode condition;
8211 :
8212 : // if(timeRange_p != "" &&
8213 : // msTimeGramParseCommand(&ms_p, timeRange_p, condition) == 0){
8214 : // const TableExprNode *timeNode = 0x0;
8215 :
8216 : // timeNode = msTimeGramParseNode();
8217 : // if(timeNode && !timeNode->isNull())
8218 : // condition = *timeNode;
8219 : // }
8220 :
8221 : //Wconst Table oldPoint(mssel_p.pointingTableName(), Table::Old);
8222 44 : const MSPointing& oldPoint = mssel_p.pointing();
8223 :
8224 44 : if(!antennaSel_p && timeRange_p == ""){
8225 44 : copySubtable(MS::keywordName(MS::POINTING), oldPoint);
8226 : }
8227 : else{
8228 0 : setupNewPointing();
8229 :
8230 0 : if(oldPoint.nrow() > 0){
8231 : // Could be declared as Table&
8232 0 : MSPointing& newPoint = msOut_p.pointing();
8233 : // Add optional columns if present in oldPoint.
8234 0 : uInt nAddedCols = addOptionalColumns(oldPoint, newPoint, true);
8235 : os << LogIO::DEBUG1 << "POINTING has " << nAddedCols
8236 0 : << " optional columns." << LogIO::POST;
8237 :
8238 : // W = Works, DW = Doesn't Work
8239 : //DW msOut_p.pointing() = mssel_p.pointing();
8240 : //DW //TableCopy::copyInfo(newPoint, oldPoint);
8241 : //W TableColumn newTC(newPoint, "DIRECTION");
8242 : //W const ScalarColumn<MDirection> oldTC(oldPoint, "DIRECTION");
8243 : //W const TableColumn oldTC(oldPoint, "DIRECTION");
8244 : //W newTC.rwKeywordSet() = oldTC.keywordSet();
8245 :
8246 0 : const MSPointingColumns oldPCs(oldPoint);
8247 0 : MSPointingColumns newPCs(newPoint);
8248 0 : newPCs.setEpochRef(MEpoch::castType(oldPCs.timeMeas().getMeasRef().getType()));
8249 0 : newPCs.setDirectionRef(MDirection::castType(oldPCs.directionMeasCol().getMeasRef().getType()));
8250 0 : newPCs.setEncoderDirectionRef(MDirection::castType(oldPCs.encoderMeas().getMeasRef().getType()));
8251 :
8252 0 : const ScalarColumn<Int>& antIds = oldPCs.antennaId();
8253 0 : const ScalarColumn<Double>& time = oldPCs.time();
8254 0 : ScalarColumn<Int>& outants = newPCs.antennaId();
8255 :
8256 0 : uInt nTRanges = selTimeRanges_p.ncolumn();
8257 :
8258 0 : uInt outRow = 0;
8259 0 : Int maxSelAntp1 = antNewIndex_p.nelements(); // Int for comparison
8260 : // with newAntInd.
8261 0 : for (uInt inRow = 0; inRow < antIds.nrow(); ++inRow){
8262 0 : Int newAntInd = antIds(inRow);
8263 0 : if(antennaSel_p)
8264 0 : newAntInd = newAntInd < maxSelAntp1 ? antNewIndex_p[newAntInd] : -1;
8265 0 : Double t = time(inRow);
8266 :
8267 0 : if(newAntInd > -1){
8268 0 : Bool matchT = false;
8269 0 : for(uInt tr = 0; tr < nTRanges; ++tr){
8270 0 : if(t >= selTimeRanges_p(0, tr) && t <= selTimeRanges_p(1, tr)){
8271 0 : matchT = true;
8272 0 : break;
8273 : }
8274 : }
8275 :
8276 0 : if(matchT){
8277 0 : TableCopy::copyRows(newPoint, oldPoint, outRow, inRow, 1, false);
8278 0 : outants.put(outRow, newAntInd);
8279 0 : ++outRow;
8280 : }
8281 : }
8282 : }
8283 0 : }
8284 : }
8285 : }
8286 : else
8287 0 : setupNewPointing(); // Make an empty stub for MSColumns.
8288 :
8289 44 : return true;
8290 44 : }
8291 :
8292 0 : void SubMS::setupNewPointing()
8293 : {
8294 0 : SetupNewTable pointingSetup(msOut_p.pointingTableName(),
8295 0 : MSPointing::requiredTableDesc(), Table::New);
8296 : // POINTING can be large, set some sensible defaults for storageMgrs
8297 0 : IncrementalStMan ismPointing ("ISMPointing");
8298 0 : StandardStMan ssmPointing("SSMPointing", 32768);
8299 0 : pointingSetup.bindAll(ismPointing, true);
8300 0 : pointingSetup.bindColumn(MSPointing::columnName(MSPointing::DIRECTION),
8301 : ssmPointing);
8302 0 : pointingSetup.bindColumn(MSPointing::columnName(MSPointing::TARGET),
8303 : ssmPointing);
8304 0 : pointingSetup.bindColumn(MSPointing::columnName(MSPointing::TIME),
8305 : ssmPointing);
8306 0 : msOut_p.rwKeywordSet().defineTable(MS::keywordName(MS::POINTING),
8307 0 : Table(pointingSetup));
8308 0 : msOut_p.initRefs();
8309 0 : }
8310 :
8311 44 : Bool SubMS::copyWeather(){
8312 : // Weather is allowed to not exist.
8313 44 : if(Table::isReadable(mssel_p.weatherTableName())){
8314 5 : const MSWeather& oldWeath = mssel_p.weather();
8315 :
8316 5 : if(oldWeath.nrow() > 0){
8317 : // Add a WEATHER subtable to msOut_p with 0 rows for now.
8318 5 : Table::TableOption option = Table::New;
8319 5 : TableDesc weatherTD = MSWeather::requiredTableDesc();
8320 5 : SetupNewTable weatherSetup(msOut_p.weatherTableName(), weatherTD,
8321 10 : option);
8322 10 : msOut_p.rwKeywordSet().defineTable(MS::keywordName(MS::WEATHER),
8323 10 : Table(weatherSetup,0));
8324 : // update the references to the subtable keywords
8325 5 : msOut_p.initRefs();
8326 :
8327 5 : MSWeather& newWeath = msOut_p.weather(); // Could be declared as
8328 : // Table&
8329 :
8330 10 : LogIO os(LogOrigin("SubMS", "copyWeather()"));
8331 :
8332 5 : uInt nAddedCols = addOptionalColumns(oldWeath, newWeath, true);
8333 : os << LogIO::DEBUG1 << "WEATHER has " << nAddedCols
8334 5 : << " optional columns." << LogIO::POST;
8335 :
8336 5 : const MSWeatherColumns oldWCs(oldWeath);
8337 5 : MSWeatherColumns newWCs(newWeath);
8338 5 : newWCs.setEpochRef(MEpoch::castType(oldWCs.timeMeas().getMeasRef().getType()));
8339 :
8340 5 : if(!antennaSel_p){
8341 5 : TableCopy::copyRows(newWeath, oldWeath);
8342 : }
8343 : else{
8344 0 : const Vector<Int>& antIds(oldWCs.antennaId().getColumn());
8345 0 : ScalarColumn<Int>& outants = newWCs.antennaId();
8346 :
8347 0 : uInt selRow = 0;
8348 0 : Int maxSelAntp1 = antNewIndex_p.nelements();
8349 :
8350 0 : for(uInt k = 0; k < antIds.nelements(); ++k){
8351 0 : if(antIds[k] > -1){ // Weather station is on antenna?
8352 0 : if(antIds[k] < maxSelAntp1){
8353 0 : Int newAntInd = antNewIndex_p[antIds[k]]; // remap ant num
8354 :
8355 0 : if(newAntInd > -1){ // Ant selected?
8356 0 : TableCopy::copyRows(newWeath, oldWeath, selRow, k, 1);
8357 0 : outants.put(selRow, newAntInd);
8358 0 : ++selRow;
8359 : }
8360 : }
8361 : }
8362 : else{
8363 0 : TableCopy::copyRows(newWeath, oldWeath, selRow, k, 1);
8364 0 : outants.put(selRow, -1); // means valid for all antennas.
8365 0 : ++selRow;
8366 : }
8367 : }
8368 0 : }
8369 5 : }
8370 : }
8371 44 : return true;
8372 : }
8373 :
8374 44 : Bool SubMS::copySyscal()
8375 : {
8376 : // SYSCAL is allowed to not exist.
8377 44 : if(Table::isReadable(mssel_p.sysCalTableName())){
8378 5 : const MSSysCal& oldSysc = mssel_p.sysCal();
8379 :
8380 5 : if(oldSysc.nrow() > 0){
8381 : // Add a SYSCAL subtable to msOut_p with 0 rows for now.
8382 1 : Table::TableOption option = Table::New;
8383 1 : TableDesc sysCalTD = MSSysCal::requiredTableDesc();
8384 1 : SetupNewTable sysCalSetup(msOut_p.sysCalTableName(), sysCalTD,
8385 2 : option);
8386 2 : msOut_p.rwKeywordSet().defineTable(MS::keywordName(MS::SYSCAL),
8387 2 : Table(sysCalSetup, 0));
8388 : // update the references to the subtable keywords
8389 1 : msOut_p.initRefs();
8390 :
8391 : // Could be declared as Table&.
8392 1 : MSSysCal& newSysc = msOut_p.sysCal();
8393 :
8394 2 : LogIO os(LogOrigin("SubMS", "copySysCal()"));
8395 :
8396 1 : uInt nAddedCols = addOptionalColumns(oldSysc, newSysc, true);
8397 : os << LogIO::DEBUG1 << "SYSCAL has " << nAddedCols
8398 1 : << " optional columns." << LogIO::POST;
8399 :
8400 1 : const MSSysCalColumns incols(oldSysc);
8401 1 : MSSysCalColumns outcols(newSysc);
8402 1 : outcols.setEpochRef(MEpoch::castType(incols.timeMeas().getMeasRef().getType()));
8403 :
8404 1 : if(!antennaSel_p && allEQ(spwRelabel_p, spw_p)){
8405 0 : TableCopy::copyRows(newSysc, oldSysc);
8406 : }
8407 : else{
8408 1 : const Vector<Int>& antIds = incols.antennaId().getColumn();
8409 1 : const Vector<Int>& spwIds = incols.spectralWindowId().getColumn();
8410 :
8411 : // Copy selected rows.
8412 1 : uInt totNSyscals = antIds.nelements();
8413 1 : uInt totalSelSyscals = 0;
8414 1 : Int maxSelAntp1 = antNewIndex_p.nelements(); // Int for comparison with antIds.
8415 121 : for(uInt k = 0; k < totNSyscals; ++k){
8416 : // antenna must be selected, and spwId must be -1 (any) or selected.
8417 240 : if(antIds[k] < maxSelAntp1 && antNewIndex_p[antIds[k]] > -1 &&
8418 120 : (spwIds[k] < 0 || spwRelabel_p[spwIds[k]] > -1)){
8419 : // outtab intab outrow inrow nrows
8420 0 : TableCopy::copyRows(newSysc, oldSysc, totalSelSyscals, k, 1, false);
8421 0 : ++totalSelSyscals;
8422 : }
8423 : }
8424 :
8425 : // Remap antenna and spw #s.
8426 1 : ScalarColumn<Int>& antCol = outcols.antennaId();
8427 1 : ScalarColumn<Int>& spwCol = outcols.spectralWindowId();
8428 :
8429 1 : for(uInt k = 0; k < totalSelSyscals; ++k){
8430 0 : antCol.put(k, antNewIndex_p[antCol(k)]);
8431 0 : if(spwCol(k) > -1)
8432 0 : spwCol.put(k, spwRelabel_p[spwCol(k)]);
8433 : }
8434 1 : }
8435 1 : }
8436 : }
8437 44 : return true;
8438 : }
8439 :
8440 46 : void SubMS::copySubtable(const String& tabName, const Table& inTab,
8441 : const Bool doFilter)
8442 : {
8443 46 : String outName(msOut_p.tableName() + '/' + tabName);
8444 :
8445 46 : if(PlainTable::tableCache()(outName))
8446 0 : PlainTable::tableCache().remove(outName);
8447 46 : inTab.deepCopy(outName, Table::New, false, Table::AipsrcEndian,
8448 : doFilter);
8449 46 : Table outTab(outName, Table::Update);
8450 46 : msOut_p.rwKeywordSet().defineTable(tabName, outTab);
8451 46 : msOut_p.initRefs();
8452 46 : }
8453 :
8454 88 : Bool SubMS::filterOptSubtable(const String& subtabname)
8455 : {
8456 176 : LogIO os(LogOrigin("SubMS", "filterOptSubtable()"));
8457 :
8458 : // subtabname is allowed to not exist. Use ms_p instead of mssel_p, because
8459 : // the latter has a random name which does NOT necessarily lead to
8460 : // subtabname. (And if selection took care of subtables, we probably
8461 : // wouldn't have to do it here.)
8462 88 : if(Table::isReadable(ms_p.tableName() + '/' + subtabname)){
8463 8 : const Table intab(ms_p.tableName() + '/' + subtabname);
8464 :
8465 4 : if(intab.nrow() > 0){
8466 : // Add feed if selecting by it is ever added.
8467 2 : Bool doFilter = antennaSel_p || !allEQ(spwRelabel_p, spw_p);
8468 :
8469 2 : copySubtable(subtabname, intab, doFilter);
8470 :
8471 2 : if(doFilter){
8472 : // At this point msOut_p has subtab with 0 rows.
8473 4 : Table outtab(msOut_p.tableName() + '/' + subtabname, Table::Update);
8474 :
8475 2 : ScalarColumn<Int> inAntIdCol(intab, "ANTENNA_ID"); // + FEED_ID if it
8476 2 : ScalarColumn<Int> inSpwIdCol(intab, "SPECTRAL_WINDOW_ID"); // ever changed.
8477 2 : const Vector<Int>& antIds = inAntIdCol.getColumn();
8478 2 : const Vector<Int>& spwIds = inSpwIdCol.getColumn();
8479 :
8480 : // Copy selected rows.
8481 2 : uInt totNOuttabs = antIds.nelements();
8482 2 : uInt totalSelOuttabs = 0;
8483 2 : Int maxSelAntp1 = antNewIndex_p.nelements(); // Int for comparison with
8484 : // antIds.
8485 2 : Bool haveRemappingProblem = false;
8486 786 : for(uInt inrow = 0; inrow < totNOuttabs; ++inrow){
8487 : // antenna must be selected, and spwId must be -1 (any) or selected.
8488 : // Extra care must be taken because for a while MSes had CALDEVICE
8489 : // and SYSPOWER, but the ANTENNA_ID and SPECTRAL_WINDOW_ID of those
8490 : // subtables were not being remapped by split.
8491 784 : if(antIds[inrow] < maxSelAntp1 && antNewIndex_p[antIds[inrow]] > -1){
8492 :
8493 2352 : if(spwIds[inrow] < 0 || (spwIds[inrow] <
8494 784 : static_cast<Int>(spwRelabel_p.nelements()) &&
8495 784 : spwRelabel_p[spwIds[inrow]] > -1)){
8496 136 : TableCopy::copyRows(outtab, intab, totalSelOuttabs, inrow, 1, false);
8497 136 : ++totalSelOuttabs;
8498 : }
8499 : // Ideally we'd like to catch antenna errors too. They are
8500 : // avoided, but because of the way antNewIndex_p is made,
8501 : // antIds[inrow] >= maxSelAntp1
8502 : // is not necessarily an error. It's not even possible to catch
8503 : // all the spw errors, so we settle for catching the ones we can
8504 : // and reliably avoiding segfaults.
8505 648 : else if(spwIds[inrow] >= static_cast<Int>(spwRelabel_p.nelements()))
8506 0 : haveRemappingProblem = true;
8507 : }
8508 : }
8509 :
8510 2 : if(haveRemappingProblem)
8511 : os << LogIO::WARN
8512 : << "At least one row of " << intab.tableName()
8513 : << " has an antenna or spw mismatch.\n"
8514 : << "(Presumably from an older split, sorry.)\n"
8515 : << "If " << subtabname
8516 : << " is important, it should be fixed with tb or browsetable,\n"
8517 : << "or by redoing the split that made " << ms_p.tableName()
8518 : << " (check its history)."
8519 0 : << LogIO::POST;
8520 :
8521 : // Remap antenna and spw #s.
8522 2 : ScalarColumn<Int> outAntCol(outtab, "ANTENNA_ID");
8523 2 : ScalarColumn<Int> outSpwCol(outtab, "SPECTRAL_WINDOW_ID");
8524 :
8525 138 : for(uInt k = 0; k < totalSelOuttabs; ++k){
8526 136 : outAntCol.put(k, antNewIndex_p[outAntCol(k)]);
8527 136 : if(outSpwCol(k) > -1)
8528 136 : outSpwCol.put(k, spwRelabel_p[outSpwCol(k)]);
8529 : }
8530 2 : }
8531 : }
8532 4 : }
8533 88 : return true;
8534 88 : }
8535 :
8536 : // writeDiffSpwShape() was the VisIter-using channel averager, which sounds
8537 : // great, but:
8538 : // 0. If VisIter's sort order is different from the one in the MS, then if you
8539 : // write _any_ columns using VisIter-fetched data, then you must write _all_ of
8540 : // them. This is crucially important for channel averaging in split: normally
8541 : // only *DATA, FLAG*, WEIGHT, and SIGMA would have to be updated, but if using
8542 : // VisIter, the ANTENNA*, FEED*, STATE_ID, etc. have to be updated too because
8543 : // they could be rearranged.
8544 : //
8545 : // There does not appear to be an easy way of getting the MS's starting sort
8546 : // order, i.e. AFAIK it is not written into a header.
8547 : //
8548 : // 1. If FLOAT_DATA is present, VisIter will ignore DATA. (G. Moellenbrock,
8549 : // =casa-staff, 1/15/2010)
8550 :
8551 3 : Bool SubMS::doChannelMods(const Vector<MS::PredefinedColumns>& datacols)
8552 : {
8553 6 : LogIO os(LogOrigin("SubMS", "doChannelMods()"));
8554 :
8555 3 : Vector<MS::PredefinedColumns> cmplxColLabels;
8556 3 : const Bool doFloat = sepFloat(datacols, cmplxColLabels);
8557 3 : const uInt nCmplx = cmplxColLabels.nelements();
8558 3 : if(doFloat && nCmplx > 0) // 2010-12-14
8559 : os << LogIO::WARN
8560 : << "Using VisIter to average both FLOAT_DATA and another DATA column is extremely experimental."
8561 0 : << LogIO::POST;
8562 :
8563 : //ArrayColumn<Complex> outCmplxCols[nCmplx];
8564 : //outDataColMap(outCmplxCols, nCmplx, cmplxColLabels);
8565 3 : const Bool writeToData = mustConvertToData(nCmplx, cmplxColLabels);
8566 :
8567 : // Is CORRECTED_DATA being moved to DATA?
8568 3 : Bool fromCorrToData = writeToData && nCmplx == 1;
8569 3 : if(fromCorrToData)
8570 0 : fromCorrToData = cmplxColLabels[0] == MS::CORRECTED_DATA;
8571 :
8572 3 : Vector<Int> spwindex(max(spw_p) + 1);
8573 3 : spwindex.set(-1);
8574 9 : for(uInt k = 0; k < spw_p.nelements(); ++k)
8575 6 : spwindex[spw_p[k]] = k;
8576 :
8577 3 : Block<Int> columns;
8578 : // include scan and state iteration, for more optimal iteration
8579 3 : columns.resize(6);
8580 3 : columns[0]=MS::ARRAY_ID;
8581 3 : columns[1]=MS::SCAN_NUMBER;
8582 3 : columns[2]=MS::STATE_ID;
8583 3 : columns[3]=MS::FIELD_ID;
8584 3 : columns[4]=MS::DATA_DESC_ID;
8585 3 : columns[5]=MS::TIME;
8586 :
8587 : #ifdef COPYTIMER
8588 : Timer timer;
8589 : timer.mark();
8590 :
8591 : Vector<Int> inscan, outscan;
8592 : #endif
8593 :
8594 3 : ROVisIterator viIn(mssel_p, columns, 0.0);
8595 : //ROVisibilityIterator viIn(mssel_p, columns, 0.0);
8596 3 : VisIter viOut(msOut_p,columns,0.0);
8597 :
8598 3 : viIn.setRowBlocking(1000);
8599 3 : viOut.setRowBlocking(1000);
8600 : //viIn.slurp();
8601 : //cerr << "Finished slurping." << endl;
8602 :
8603 : // Translate chanSlices_p into the form vb.channelAve() wants.
8604 3 : Vector<Matrix<Int> > chanAveBounds;
8605 3 : viIn.slicesToMatrices(chanAveBounds, chanSlices_p, widths_p);
8606 :
8607 : // // If we don't want to skip every (width - 1) out of width channels,
8608 : // // the increments in chanSlices_p must be set to 1.
8609 : // if(averageChannel_p){
8610 : // for(uInt spwind = 0; spwind < chanSlices_p.nelements(); ++spwind){
8611 : // Vector<Slice>& spwsls = chanSlices_p[spwind];
8612 :
8613 : // for(uInt slnum = 0; slnum < spwsls.nelements(); ++slnum){
8614 : // Slice& sl = spwsls[slnum];
8615 :
8616 : // spwsls[slnum] = Slice(sl.start(), sl.length());
8617 : // }
8618 : // }
8619 : // }
8620 :
8621 : // Apply selection
8622 : // for(uInt spwind = 0; spwind < spw_p.nelements(); ++spwind)
8623 : // viOut.selectChannel(1, chanStart_p[spwind], nchan_p[spwind],
8624 : // chanStep_p[spwind], spw_p[spwind]);
8625 3 : viIn.selectChannel(chanSlices_p); // ROVisIterator
8626 3 : viIn.selectCorrelation(corrSlices_p);
8627 :
8628 3 : viIn.originChunks(); // Makes me feel better.
8629 :
8630 3 : const Bool doSpWeight = viIn.existsWeightSpectrum();
8631 :
8632 3 : Bool doFC = existsFlagCategory();
8633 3 : uInt rowsdone = 0;
8634 3 : ProgressMeter meter(0.0, mssel_p.nrow() * 1.0, "split", "rows averaged", "", "",
8635 9 : true, 1);
8636 3 : Cube<Complex> vis;
8637 3 : Cube<Float> floatvis;
8638 3 : VisBuffer vb(viIn);
8639 3 : Matrix<Float> wtmat;
8640 :
8641 3 : for(viOut.originChunks(), viIn.originChunks();
8642 15 : viOut.moreChunks(), viIn.moreChunks();
8643 12 : viOut.nextChunk(), viIn.nextChunk()){
8644 24 : for(viIn.origin(),viOut.origin(); viIn.more(),viOut.more();
8645 12 : ++viIn, ++viOut){
8646 12 : uInt rowsnow = vb.nRow();
8647 :
8648 12 : if(rowsnow > 0){
8649 : //RefRows rr(rowsdone, rowsdone + rowsnow - 1);
8650 :
8651 : // Preload the things that need to be channel averaged.
8652 48 : for(uInt colind = 0; colind < nCmplx; ++colind){
8653 36 : if(cmplxColLabels[colind] == MS::DATA)
8654 12 : vb.visCube();
8655 24 : else if(cmplxColLabels[colind] == MS::MODEL_DATA)
8656 12 : vb.modelVisCube();
8657 12 : else if(cmplxColLabels[colind] == MS::CORRECTED_DATA)
8658 12 : vb.correctedVisCube();
8659 : }
8660 12 : if(doFloat)
8661 0 : vb.floatDataCube();
8662 :
8663 : // The flags and weights are already loaded by this point, UNLESS the
8664 : // row flag was true for all the rows. Make sure they're loaded, or
8665 : // they could end up with the wrong shape.
8666 12 : vb.flagCube();
8667 : // if(viIn.existsWeightSpectrum())
8668 : // vb.weightSpectrum();
8669 : // vb.weightMat();
8670 12 : if(doFC)
8671 0 : vb.flagCategory();
8672 :
8673 12 : vb.channelAve(chanAveBounds[viIn.spectralWindow()],false);
8674 :
8675 12 : if(nCmplx > 0){
8676 12 : if(vb.flagCube().shape() !=
8677 12 : vb.dataCube(cmplxColLabels[0]).shape())
8678 0 : throw(AipsError("Shape error after channel averaging!"));
8679 : }
8680 0 : else if(doFloat){
8681 0 : if(vb.flagCube().shape() != vb.floatDataCube().shape())
8682 0 : throw(AipsError("Shape error after channel averaging!"));
8683 : }
8684 : // else we aren't doing anything, it seems.
8685 :
8686 : // Write the output.
8687 48 : for(uInt colind = 0; colind < nCmplx; ++colind){
8688 36 : if(cmplxColLabels[colind] == MS::DATA)
8689 12 : viOut.setVis(vb.visCube(), VisibilityIterator::Observed);
8690 24 : else if(cmplxColLabels[colind] == MS::MODEL_DATA)
8691 12 : viOut.setVis(vb.modelVisCube(),
8692 : writeToData ? VisibilityIterator::Observed :
8693 : VisibilityIterator::Model);
8694 12 : else if(cmplxColLabels[colind] == MS::CORRECTED_DATA)
8695 12 : viOut.setVis(vb.correctedVisCube(),
8696 : writeToData ? VisibilityIterator::Observed :
8697 : VisibilityIterator::Corrected);
8698 : }
8699 : //if(doFloat)
8700 : // viOut.setFloatData(vb.floatDataCube()); TBD!
8701 12 : viOut.setFlag(vb.flagCube());
8702 12 : if(doFC)
8703 0 : viOut.setFlagCategory(vb.flagCategory());
8704 :
8705 :
8706 12 : if(doSpWeight)
8707 0 : viOut.setWeightSpectrum(vb.weightSpectrum());
8708 :
8709 :
8710 12 : if(fromCorrToData) {
8711 0 : wtmat.reference(vb.weightMat());
8712 0 : viOut.setWeightMat(wtmat);
8713 0 : arrayTransformInPlace(wtmat, subms::wtToSigma); // for corrected weights.
8714 0 : viOut.setSigmaMat(wtmat);
8715 : }
8716 : else {
8717 12 : wtmat.reference(vb.sigmaMat()); // Yes, I'm reusing wtmat.
8718 12 : viOut.setSigmaMat(wtmat);
8719 12 : arrayTransformInPlace(wtmat, subms::sigToWeight); // for corrected weights.
8720 12 : viOut.setWeightMat(wtmat);
8721 : }
8722 :
8723 12 : rowsdone += rowsnow;
8724 : }
8725 : }
8726 12 : meter.update(rowsdone);
8727 : } // End of for(viIn.originChunks(); viIn.moreChunks(); viIn.nextChunk())
8728 3 : os << LogIO::NORMAL << "Data binned." << LogIO::POST;
8729 :
8730 : //const ColumnDescSet& cds = mssel_p.tableDesc().columnDescSet();
8731 : //const ColumnDesc& cdesc = cds[MS::columnName(MS::DATA)];
8732 : //ROTiledStManAccessor tacc(mssel_p, cdesc.dataManagerGroup());
8733 : //tacc.showCacheStatistics(cerr); // A 99.x% hit rate is good. 0% is bad.
8734 :
8735 : os << LogIO::DEBUG1 // helpdesk ticket in from Oleg Smirnov (ODU-232630)
8736 6 : << "Post binning memory: " << Memory::allocatedMemoryInBytes() / (1024.0 * 1024.0) << " MB"
8737 3 : << LogIO::POST;
8738 :
8739 3 : return true;
8740 3 : }
8741 :
8742 : // // Sets mapper to the distinct values of mscol, in increasing order.
8743 : // // A static method that is used by SubMS, but doesn't necessarily have to go
8744 : // // with it. It may belong in something more MSColumnsish.
8745 : // void SubMS::make_map(const Vector<Int>& mscol, Vector<Int>& mapper)
8746 : // {
8747 : // std::set<Int> valSet;
8748 :
8749 : // for(Int i = mscol.nelements(); i--;) // Strange, but slightly more
8750 : // valSet.insert(mscol[i]); // efficient than going forward.
8751 : // mapper.resize(valSet.size());
8752 :
8753 : // uInt remaval = 0;
8754 : // for(std::set<Int>::const_iterator vs_iter = valSet.begin();
8755 : // vs_iter != valSet.end(); ++vs_iter){
8756 : // mapper[remaval] = *vs_iter;
8757 : // ++remaval;
8758 : // }
8759 : // }
8760 :
8761 93 : void SubMS::make_map(std::map<Int, Int>& mapper, const Vector<Int>& inv)
8762 : {
8763 93 : std::set<Int> valSet;
8764 :
8765 868889 : for(Int i = inv.nelements(); i--;) // Strange, but slightly more
8766 868796 : valSet.insert(inv[i]); // efficient than going forward.
8767 :
8768 93 : uInt remaval = 0;
8769 93 : for(std::set<Int>::const_iterator vs_iter = valSet.begin();
8770 150 : vs_iter != valSet.end(); ++vs_iter){
8771 57 : mapper[*vs_iter] = remaval;
8772 57 : ++remaval;
8773 : }
8774 93 : }
8775 :
8776 0 : void SubMS::make_map2(std::map<Int, Int>& mapper, const Vector<Int>& inv)
8777 : {
8778 0 : LogIO os(LogOrigin("SubMS", "make_map2()"));
8779 : // This method assumes the int vector contains mapping scheme already
8780 : // if inv[i] is not selected one => -1 so should be skipped
8781 : // ith vector element is mapped value of index i
8782 : // Created for remapping of field Ids with fieldRelable_p (TT 2012.07.27)
8783 0 : for(Vector<Int>::const_iterator vs_iter = inv.begin();
8784 0 : vs_iter != inv.end(); ++vs_iter){
8785 0 : if (*vs_iter!=-1) {
8786 0 : Int dist=std::distance(inv.begin(),vs_iter);
8787 0 : mapper.insert(std::make_pair(dist, *vs_iter));
8788 : os << LogIO::DEBUG1
8789 0 : << " *vs_iter="<< *vs_iter
8790 : << " index="<< dist
8791 0 : << LogIO::POST;
8792 : }
8793 0 : }
8794 0 : }
8795 : //
8796 :
8797 0 : void SubMS::remap(Vector<Int>& col, const Vector<Int>& mapper)
8798 : {
8799 0 : if(mapper.nelements() > 0)
8800 0 : for(Int row = col.nelements(); row--;)
8801 0 : col[row] = mapper[col[row]];
8802 0 : }
8803 :
8804 0 : void SubMS::remap(Vector<Int>& col, const std::map<Int, Int>& mapper)
8805 : {
8806 0 : if(mapper.size() > 0)
8807 0 : for(Int row = col.nelements(); row--;)
8808 0 : col[row] = mapper.find(col[row])->second;
8809 0 : }
8810 :
8811 : // Returns rv s.t. mapper[rv] == ov, assuming that mapper[i + 1] >= mapper[i]
8812 : // for 0 <= i < mapper.nelements() - 1.
8813 : // i can be supplied as the first guess.
8814 0 : uInt SubMS::remapped(const Int ov, const Vector<Int>& mapper, uInt i=0)
8815 : {
8816 0 : uInt nvals = mapper.nelements();
8817 0 : uInt nvalsm1 = nvals - 1;
8818 :
8819 0 : if(i >= nvals) // Second guess the guess.
8820 0 : i = nvals >> 1;
8821 :
8822 : // Do a widening search for the brackets, since i is probably close to the
8823 : // answer.
8824 0 : if(mapper[i] == ov)
8825 0 : return i;
8826 :
8827 0 : uInt inc = 1;
8828 0 : uInt lb = i;
8829 : uInt ub;
8830 0 : if(ov > mapper[lb]){ // Hunt up.
8831 0 : if(lb == nvalsm1)
8832 0 : return lb;
8833 0 : ub = lb + 1;
8834 0 : while(ov >= mapper[ub]){
8835 0 : lb = ub;
8836 0 : inc += inc;
8837 0 : ub = lb + inc;
8838 0 : if(ub > nvalsm1){
8839 0 : ub = nvals;
8840 0 : break;
8841 : }
8842 : }
8843 : }
8844 : else{ // Hunt down.
8845 0 : ub = lb;
8846 0 : --lb;
8847 0 : while(ov < mapper[lb]){
8848 0 : ub = lb;
8849 0 : inc += inc;
8850 0 : if(inc >= ub){
8851 0 : lb = 0;
8852 0 : break;
8853 : }
8854 : else
8855 0 : lb = ub - inc;
8856 : }
8857 : }
8858 :
8859 0 : i = lb + ((ub - lb) >> 1); // (lb + ub) / 2 might overflow.
8860 0 : while(mapper[i] != ov && ub - lb > 1){
8861 0 : if(mapper[i] < ov)
8862 0 : lb = i;
8863 : else
8864 0 : ub = i;
8865 0 : i = lb + ((ub - lb) >> 1);
8866 : }
8867 0 : return i;
8868 : }
8869 :
8870 0 : uInt SubMS::fillAntIndexer(std::map<Int, Int>& antIndexer, const MSColumns *msc)
8871 : {
8872 0 : const Vector<Int>& ant1 = msc->antenna1().getColumn();
8873 0 : const Vector<Int>& ant2 = msc->antenna2().getColumn();
8874 :
8875 0 : std::set<Int> ants;
8876 0 : for(Int i = ant1.nelements(); i--;){ // Strange, but slightly more
8877 0 : ants.insert(ant1[i]); // efficient than going forward.
8878 0 : ants.insert(ant2[i]);
8879 : }
8880 0 : uInt nant = ants.size();
8881 :
8882 0 : Vector<Int> selAnt(nant);
8883 0 : Int remaval = 0;
8884 0 : for(std::set<Int>::const_iterator ant_iter = ants.begin();
8885 0 : ant_iter != ants.end(); ++ant_iter){
8886 0 : selAnt[remaval] = *ant_iter;
8887 0 : ++remaval;
8888 : }
8889 :
8890 0 : for(uInt j = 0; j < nant; ++j)
8891 0 : antIndexer[selAnt[j]] = static_cast<Int>(j);
8892 0 : return nant;
8893 0 : }
8894 :
8895 0 : const ArrayColumn<Complex>& SubMS::right_column(const MSColumns *msclala,
8896 : const MS::PredefinedColumns col)
8897 : {
8898 0 : if(col == MS::DATA)
8899 0 : return msclala->data();
8900 0 : else if(col == MS::MODEL_DATA)
8901 0 : return msclala->modelData();
8902 : // else if(col == MS::FLOAT_DATA) // Not complex.
8903 : // return msclala->floatData();
8904 0 : else if(col == MS::LAG_DATA)
8905 0 : return msclala->lagData();
8906 : else // The honored-by-time-if-nothing-else
8907 0 : return msclala->correctedData(); // default.
8908 : }
8909 :
8910 0 : ArrayColumn<Complex>& SubMS::right_column(MSColumns *msclala,
8911 : const MS::PredefinedColumns col,
8912 : const Bool writeToDataCol)
8913 : {
8914 0 : if(writeToDataCol || col == MS::DATA)
8915 0 : return msclala->data();
8916 0 : else if(col == MS::MODEL_DATA)
8917 0 : return msclala->modelData();
8918 : // else if(col == MS::FLOAT_DATA) // Not complex.
8919 : // return msclala->floatData();
8920 0 : else if(col == MS::LAG_DATA)
8921 0 : return msclala->lagData();
8922 : else // The honored-by-time-if-nothing-else
8923 0 : return msclala->correctedData(); // default.
8924 : }
8925 :
8926 44 : Bool SubMS::sepFloat(const Vector<MS::PredefinedColumns>& anyDataCols,
8927 : Vector<MS::PredefinedColumns>& complexDataCols)
8928 : {
8929 : // Determine whether FLOAT_DATA is in anyDataCols[], and fill
8930 : // complexDataCols[] with the Complex members of anyDataCols[].
8931 44 : Bool doFloat = false;
8932 44 : uInt ntok = anyDataCols.nelements();
8933 :
8934 44 : complexDataCols.resize(ntok);
8935 44 : uInt j = 0;
8936 109 : for(uInt i = 0; i < ntok; ++i){
8937 65 : if(anyDataCols[i] != MS::FLOAT_DATA){
8938 65 : complexDataCols[j] = anyDataCols[i];
8939 65 : ++j;
8940 : }
8941 : else
8942 0 : doFloat = true;
8943 : }
8944 44 : if(doFloat)
8945 0 : complexDataCols.resize(j, true);
8946 44 : return doFloat;
8947 : }
8948 :
8949 0 : Bool SubMS::doTimeAver(const Vector<MS::PredefinedColumns>& dataColNames,
8950 : const VBRemapper& remapper)
8951 : {
8952 0 : LogIO os(LogOrigin("SubMS", "doTimeAver()"));
8953 :
8954 : //No channel averaging with time averaging ... it's better this way, but
8955 : //maybe that should be revisited with VisibilityIterator.
8956 0 : if(chanStep_p[0] > 1){
8957 0 : throw(AipsError("Simultaneous time and channel averaging is not handled."));
8958 : return false;
8959 : }
8960 :
8961 : os << LogIO::DEBUG1 // helpdesk ticket from Oleg Smirnov (ODU-232630)
8962 : << "Before msOut_p.addRow(): "
8963 0 : << Memory::allocatedMemoryInBytes() / (1024.0 * 1024.0) << " MB"
8964 0 : << LogIO::POST;
8965 :
8966 0 : Vector<MS::PredefinedColumns> cmplxColLabels;
8967 0 : const Bool doFloat = sepFloat(dataColNames, cmplxColLabels);
8968 0 : const uInt nCmplx = cmplxColLabels.nelements();
8969 0 : if(doFloat && cmplxColLabels.nelements() > 0) // 2010-12-14
8970 : os << LogIO::WARN
8971 : << "Using VisibilityIterator to average both FLOAT_DATA and another DATA column is extremely experimental."
8972 0 : << LogIO::POST;
8973 :
8974 : // Is CORRECTED_DATA being moved to DATA?
8975 0 : Bool fromCorrToData = nCmplx == 1 && cmplxColLabels[0] == MS::CORRECTED_DATA;
8976 :
8977 0 : ArrayColumn<Complex> *outCmplxCols = new ArrayColumn<Complex>[nCmplx];
8978 0 : getDataColMap(outCmplxCols, nCmplx, cmplxColLabels);
8979 :
8980 : // We may need to watch for chunks (timebins) that should be split because of
8981 : // changes in scan, etc. (CAS-2401). The old split way would have
8982 : // temporarily shortened timeBin, but vi.setInterval() does not work without
8983 : // calling vi.originChunks(), so that approach does not work with
8984 : // VisibilityIterator. Instead, get VisibilityIterator's sort (which also
8985 : // controls how the chunks are split) to do the work.
8986 0 : Block<Int> sort;
8987 0 : if(!setSortOrder(sort, "spw", false))
8988 : os << LogIO::WARN
8989 : << "The request to combine spws while time averaging is being ignored."
8990 0 : << LogIO::POST;
8991 :
8992 : // MSIter tends to produce output INTERVALs that are longer than the
8993 : // requested interval length, by ~0.5 input integrations for a random
8994 : // timeBin_p. Giving it timeBin_p - 0.5 * interval[0] removes the bias and
8995 : // brings it almost in line with binTimes() (which uses -0.5 *
8996 : // interval[bin_start]).
8997 : //
8998 : // late April 2011: MSIter removed the bias, which threw off the correction.
8999 : // October 2011: The bias seems to be back, possibly because of a change in
9000 : // when MSInterval's "offset" is reset.
9001 : // But, then, practically, timebins can be cut short but never
9002 : // lengthened by changes in scan, state, or obs ID, so it seems
9003 : // better to leave the bias in!
9004 : //
9005 : //Double tbin = mscIn_p->interval()(0);
9006 : //tbin = timeBin_p > tbin ? timeBin_p - 0.5 * tbin : timeBin_p;
9007 0 : ROVisibilityIterator vi(mssel_p, sort, timeBin_p);
9008 : //vi.slurp();
9009 : //cerr << "Finished slurping." << endl;
9010 :
9011 : // Apply selection
9012 0 : for(uInt spwind = 0; spwind < spw_p.nelements(); ++spwind)
9013 0 : vi.selectChannel(1, chanStart_p[spwind], nchan_p[spwind],
9014 0 : chanStep_p[spwind], spw_p[spwind]);
9015 : //vi.selectChannel(chanSlices_p); // ROVisIterator
9016 : //vi.selectCorrelation(corrSlices_p);
9017 :
9018 : // Translate chanSlices_p into the form vb.channelAve() wants.
9019 0 : Vector<Matrix<Int> > chanAveBounds;
9020 0 : vi.slicesToMatrices(chanAveBounds, chanSlices_p, widths_p);
9021 :
9022 0 : Matrix<Float> wtmat;
9023 0 : const Bool doSpWeight = vi.existsWeightSpectrum();
9024 :
9025 : //os << LogIO::NORMAL2 << "outNrow = " << msOut_p.nrow() << LogIO::POST;
9026 :
9027 : // All of this ddid/spw confusion really needs cleaning up.
9028 : // a map from input to output
9029 : // DATA_DESC_ID. (ddidmap[input_ddid] = output_ddid. Setting ddidmap to -1
9030 : // for unselected ddids will help make it obvious if unexpected ddids sneak
9031 : // through.) Vector<Int> ddidmap(oldDDSpwMatch_p.nelements());
9032 : // ddidmap.set(-1);
9033 : // for(uInt i = 0; i < ddidmap.nelements(); ++i){
9034 : // Int oldspwid = oldDDSpwMatch_p[i];
9035 :
9036 : // if(oldspwid > -1 && oldspwid < spwRelabel_p.nelements())
9037 : // ddidmap[i] = spwRelabel_p[oldspwid];
9038 : // }
9039 :
9040 0 : uInt rowsdone = 0; // Output rows, used for the RefRows.
9041 :
9042 0 : uInt ninrows = mssel_p.nrow();
9043 : ProgressMeter meter(0.0, ninrows * 1.0, "split", "rows averaged", "", "",
9044 0 : true, 1);
9045 0 : uInt inrowsdone = 0; // only for the meter.
9046 :
9047 0 : VisChunkAverager vca(dataColNames, doSpWeight, chanAveBounds);
9048 :
9049 0 : Bool doFC = existsFlagCategory();
9050 :
9051 : // Iterate through the chunks. A timebin will have multiple chunks if it has
9052 : // > 1 arrays, fields, or ddids.
9053 0 : for(vi.originChunks(); vi.moreChunks(); vi.nextChunk()){
9054 0 : vca.reset(); // Should be done at the start of each chunk.
9055 :
9056 0 : inrowsdone += vi.nRowChunk();
9057 :
9058 : // Fill and time average vi's current chunk.
9059 0 : VisBuffer& avb(vca.average(vi));
9060 0 : uInt rowsnow = avb.nRow();
9061 :
9062 0 : if(rowsnow > 0){
9063 0 : RefRows rowstoadd(rowsdone, rowsdone + rowsnow - 1);
9064 :
9065 : // msOut_p.addRow(rowsnow, true);
9066 0 : msOut_p.addRow(rowsnow); // Try it without initialization.
9067 :
9068 : // avb.freqAveCubes(); // Watch out, weight must currently be handled separately.
9069 :
9070 0 : remapper.remap(avb);
9071 :
9072 : // Fill in the nonaveraging values from slotv0.
9073 0 : msc_p->antenna1().putColumnCells(rowstoadd, avb.antenna1());
9074 0 : msc_p->antenna2().putColumnCells(rowstoadd, avb.antenna2());
9075 :
9076 0 : Vector<Int> arrID(rowsnow);
9077 0 : arrID.set(avb.arrayId()); // Don't remap!
9078 0 : msc_p->arrayId().putColumnCells(rowstoadd, arrID);
9079 :
9080 : // outCmplxCols determines whether the input column is output to DATA or not.
9081 0 : for(uInt datacol = 0; datacol < nCmplx; ++datacol){
9082 0 : if(dataColNames[datacol] == MS::DATA)
9083 0 : outCmplxCols[datacol].putColumnCells(rowstoadd, avb.visCube());
9084 0 : else if(dataColNames[datacol] == MS::MODEL_DATA)
9085 0 : outCmplxCols[datacol].putColumnCells(rowstoadd, avb.modelVisCube());
9086 0 : else if(dataColNames[datacol] == MS::CORRECTED_DATA)
9087 0 : outCmplxCols[datacol].putColumnCells(rowstoadd, avb.correctedVisCube());
9088 : }
9089 0 : if(doFloat)
9090 0 : msc_p->floatData().putColumnCells(rowstoadd, avb.floatDataCube());
9091 :
9092 0 : Vector<Int> ddID(rowsnow);
9093 0 : ddID.set(avb.dataDescriptionId());
9094 0 : msc_p->dataDescId().putColumnCells(rowstoadd, ddID);
9095 :
9096 0 : msc_p->exposure().putColumnCells(rowstoadd, avb.exposure());
9097 0 : msc_p->feed1().putColumnCells(rowstoadd, avb.feed1());
9098 0 : msc_p->feed2().putColumnCells(rowstoadd, avb.feed2());
9099 :
9100 0 : Vector<Int> fieldID(rowsnow);
9101 0 : fieldID.set(avb.fieldId());
9102 0 : msc_p->fieldId().putColumnCells(rowstoadd, fieldID);
9103 :
9104 0 : msc_p->flagRow().putColumnCells(rowstoadd, avb.flagRow());
9105 0 : msc_p->flag().putColumnCells(rowstoadd, avb.flagCube());
9106 :
9107 0 : if(doFC)
9108 0 : msc_p->flagCategory().putColumnCells(rowstoadd, avb.flagCategory());
9109 :
9110 0 : msc_p->interval().putColumnCells(rowstoadd, avb.timeInterval());
9111 0 : msc_p->observationId().putColumnCells(rowstoadd, avb.observationId());
9112 0 : msc_p->processorId().putColumnCells(rowstoadd, avb.processorId());
9113 0 : msc_p->scanNumber().putColumnCells(rowstoadd, avb.scan()); // Don't remap!
9114 :
9115 0 : if(doSpWeight)
9116 0 : msc_p->weightSpectrum().putColumnCells(rowstoadd, avb.weightSpectrum());
9117 :
9118 0 : if(fromCorrToData) {
9119 0 : wtmat.reference(avb.weightMat());
9120 0 : msc_p->weight().putColumnCells(rowstoadd, wtmat);
9121 0 : arrayTransformInPlace(wtmat, subms::wtToSigma); // sig=1/sqrt(wt)
9122 0 : msc_p->sigma().putColumnCells(rowstoadd, wtmat);
9123 : }
9124 : else {
9125 0 : wtmat.reference(avb.sigmaMat()); // Yes, I'm reusing wtmat.
9126 0 : msc_p->sigma().putColumnCells(rowstoadd, wtmat);
9127 0 : arrayTransformInPlace(wtmat, subms::sigToWeight); // wt=1/sig^2
9128 0 : msc_p->weight().putColumnCells(rowstoadd, wtmat);
9129 : }
9130 :
9131 :
9132 0 : msc_p->stateId().putColumnCells(rowstoadd, avb.stateId());
9133 0 : msc_p->time().putColumnCells(rowstoadd, avb.time());
9134 0 : msc_p->timeCentroid().putColumnCells(rowstoadd, avb.timeCentroid());
9135 0 : msc_p->uvw().putColumnCells(rowstoadd, avb.uvwMat());
9136 :
9137 0 : rowsdone += rowsnow;
9138 0 : }
9139 0 : meter.update(inrowsdone);
9140 : } // End of for(vi.originChunks(); vi.moreChunks(); vi.nextChunk())
9141 0 : delete [] outCmplxCols;
9142 0 : os << LogIO::NORMAL << "Data binned." << LogIO::POST;
9143 :
9144 : //const ColumnDescSet& cds = mssel_p.tableDesc().columnDescSet();
9145 : //const ColumnDesc& cdesc = cds[MS::columnName(MS::DATA)];
9146 : //ROTiledStManAccessor tacc(mssel_p, cdesc.dataManagerGroup());
9147 : //tacc.showCacheStatistics(cerr); // A 99.x% hit rate is good. 0% is bad.
9148 :
9149 : os << LogIO::DEBUG1 // helpdesk ticket in from Oleg Smirnov (ODU-232630)
9150 0 : << "Post binning memory: " << Memory::allocatedMemoryInBytes() / (1024.0 * 1024.0) << " MB"
9151 0 : << LogIO::POST;
9152 :
9153 0 : if(rowsdone < 1){
9154 : os << LogIO::WARN
9155 : << "No rows were written. Is all the selected input flagged?"
9156 0 : << LogIO::POST;
9157 0 : return false;
9158 : }
9159 0 : return true;
9160 0 : }
9161 :
9162 : // This should become the default soon (with a name change).
9163 0 : Bool SubMS::doTimeAverVisIterator(const Vector<MS::PredefinedColumns>& dataColNames,
9164 : const VBRemapper& remapper)
9165 : {
9166 0 : LogIO os(LogOrigin("SubMS", "doTimeAverVisIterator()"));
9167 :
9168 : //No channel averaging with time averaging ... it's better this way, but
9169 : //maybe that should be revisited with VisibilityIterator.
9170 0 : if(chanStep_p[0] > 1){
9171 0 : throw(AipsError("Simultaneous time and channel averaging is not handled."));
9172 : return false;
9173 : }
9174 :
9175 : os << LogIO::DEBUG1 // helpdesk ticket from Oleg Smirnov (ODU-232630)
9176 : << "Before msOut_p.addRow(): "
9177 0 : << Memory::allocatedMemoryInBytes() / (1024.0 * 1024.0) << " MB"
9178 0 : << LogIO::POST;
9179 :
9180 0 : Vector<MS::PredefinedColumns> cmplxColLabels;
9181 0 : const Bool doFloat = sepFloat(dataColNames, cmplxColLabels);
9182 0 : const uInt nCmplx = cmplxColLabels.nelements();
9183 0 : if(doFloat && nCmplx > 0) // 2010-12-14
9184 : os << LogIO::WARN
9185 : << "Using VisIterator to average both FLOAT_DATA and another DATA column is extremely experimental."
9186 0 : << LogIO::POST;
9187 :
9188 : // Is CORRECTED_DATA being moved to DATA?
9189 0 : Bool fromCorrToData = nCmplx == 1 && cmplxColLabels[0] == MS::CORRECTED_DATA;
9190 :
9191 0 : ArrayColumn<Complex> *outCmplxCols = new ArrayColumn<Complex>[nCmplx];
9192 0 : getDataColMap(outCmplxCols, nCmplx, cmplxColLabels);
9193 :
9194 : // We may need to watch for chunks (timebins) that should be split because of
9195 : // changes in scan, etc. (CAS-2401). The old split way would have
9196 : // temporarily shortened timeBin, but vi.setInterval() does not work without
9197 : // calling vi.originChunks(), so that approach does not work with VisIterator.
9198 : // Instead, get VisIterator's sort (which also controls how the chunks are split)
9199 : // to do the work.
9200 0 : Block<Int> sort;
9201 0 : if(!setSortOrder(sort, "spw", false))
9202 : os << LogIO::WARN
9203 : << "The request to combine spws while time averaging is being ignored."
9204 0 : << LogIO::POST;
9205 :
9206 : // MSIter tends to produce output INTERVALs that are longer than the
9207 : // requested interval length, by ~0.5 input integrations for a random
9208 : // timeBin_p. Giving it timeBin_p - 0.5 * interval[0] removes the bias and
9209 : // brings it almost in line with binTimes() (which uses -0.5 *
9210 : // interval[bin_start]).
9211 : //
9212 : // late April 2011: MSIter removed the bias, which threw off the correction.
9213 : // October 2011: The bias seems to be back, possibly because of a change in
9214 : // when MSInterval's "offset" is reset.
9215 : // But, then, practically, timebins can be cut short but never
9216 : // lengthened by changes in scan, state, or obs ID, so it seems
9217 : // better to leave the bias in!
9218 : //
9219 : //Double tbin = mscIn_p->interval()(0);
9220 : //tbin = timeBin_p > tbin ? timeBin_p - 0.5 * tbin : timeBin_p;
9221 0 : ROVisIterator vi(mssel_p, sort, timeBin_p);
9222 :
9223 : // Apply selection
9224 0 : vi.selectChannel(chanSlices_p); // ROVisIterator
9225 0 : vi.selectCorrelation(corrSlices_p);
9226 :
9227 : // Translate chanSlices_p into the form vb.channelAve() wants.
9228 0 : Vector<Matrix<Int> > chanAveBounds;
9229 0 : vi.slicesToMatrices(chanAveBounds, chanSlices_p, widths_p);
9230 :
9231 0 : Matrix<Float> wtmat;
9232 0 : const Bool doSpWeight = vi.existsWeightSpectrum();
9233 :
9234 : //os << LogIO::NORMAL2 << "outNrow = " << msOut_p.nrow() << LogIO::POST;
9235 :
9236 : // All of this ddid/spw confusion really needs cleaning up.
9237 : // a map from input to output
9238 : // DATA_DESC_ID. (ddidmap[input_ddid] = output_ddid. Setting ddidmap to -1
9239 : // for unselected ddids will help make it obvious if unexpected ddids sneak
9240 : // through.) Vector<Int> ddidmap(oldDDSpwMatch_p.nelements());
9241 : // ddidmap.set(-1);
9242 : // for(uInt i = 0; i < ddidmap.nelements(); ++i){
9243 : // Int oldspwid = oldDDSpwMatch_p[i];
9244 :
9245 : // if(oldspwid > -1 && oldspwid < spwRelabel_p.nelements())
9246 : // ddidmap[i] = spwRelabel_p[oldspwid];
9247 : // }
9248 :
9249 0 : uInt rowsdone = 0; // Output rows, used for the RefRows.
9250 :
9251 0 : uInt ninrows = mssel_p.nrow();
9252 : ProgressMeter meter(0.0, ninrows * 1.0, "split", "rows averaged", "", "",
9253 0 : true, 1);
9254 0 : uInt inrowsdone = 0; // only for the meter.
9255 :
9256 0 : VisChunkAverager vca(dataColNames, doSpWeight, chanAveBounds);
9257 :
9258 0 : Bool doFC = existsFlagCategory();
9259 :
9260 : // Iterate through the chunks. A timebin will have multiple chunks if it has
9261 : // > 1 arrays, fields, or ddids.
9262 0 : for(vi.originChunks(); vi.moreChunks(); vi.nextChunk()){
9263 0 : vca.reset(); // Should be done at the start of each chunk.
9264 :
9265 0 : inrowsdone += vi.nRowChunk();
9266 :
9267 : // Fill and time average vi's current chunk.
9268 0 : VisBuffer& avb(vca.average(vi));
9269 0 : uInt rowsnow = avb.nRow();
9270 :
9271 0 : if(rowsnow > 0){
9272 0 : RefRows rowstoadd(rowsdone, rowsdone + rowsnow - 1);
9273 :
9274 : // msOut_p.addRow(rowsnow, true);
9275 0 : msOut_p.addRow(rowsnow); // Try it without initialization.
9276 :
9277 : // avb.freqAveCubes(); // Watch out, weight must currently be handled
9278 : // separately.
9279 :
9280 0 : remapper.remap(avb);
9281 :
9282 : // Fill in the nonaveraging values from slotv0.
9283 0 : msc_p->antenna1().putColumnCells(rowstoadd, avb.antenna1());
9284 0 : msc_p->antenna2().putColumnCells(rowstoadd, avb.antenna2());
9285 :
9286 0 : Vector<Int> arrID(rowsnow);
9287 0 : arrID.set(avb.arrayId()); // Don't remap!
9288 0 : msc_p->arrayId().putColumnCells(rowstoadd, arrID);
9289 :
9290 : // outCmplxCols determines whether the input column is output to DATA or not.
9291 0 : for(uInt datacol = 0; datacol < nCmplx; ++datacol){
9292 0 : if(dataColNames[datacol] == MS::DATA)
9293 0 : outCmplxCols[datacol].putColumnCells(rowstoadd, avb.visCube());
9294 0 : else if(dataColNames[datacol] == MS::MODEL_DATA)
9295 0 : outCmplxCols[datacol].putColumnCells(rowstoadd, avb.modelVisCube());
9296 0 : else if(dataColNames[datacol] == MS::CORRECTED_DATA)
9297 0 : outCmplxCols[datacol].putColumnCells(rowstoadd, avb.correctedVisCube());
9298 : }
9299 0 : if(doFloat)
9300 0 : msc_p->floatData().putColumnCells(rowstoadd, avb.floatDataCube());
9301 :
9302 0 : Vector<Int> ddID(rowsnow);
9303 0 : ddID.set(avb.dataDescriptionId());
9304 0 : msc_p->dataDescId().putColumnCells(rowstoadd, ddID);
9305 :
9306 0 : msc_p->exposure().putColumnCells(rowstoadd, avb.exposure());
9307 0 : msc_p->feed1().putColumnCells(rowstoadd, avb.feed1());
9308 0 : msc_p->feed2().putColumnCells(rowstoadd, avb.feed2());
9309 :
9310 0 : Vector<Int> fieldID(rowsnow);
9311 0 : fieldID.set(avb.fieldId());
9312 0 : msc_p->fieldId().putColumnCells(rowstoadd, fieldID);
9313 :
9314 0 : msc_p->flagRow().putColumnCells(rowstoadd, avb.flagRow());
9315 0 : msc_p->flag().putColumnCells(rowstoadd, avb.flagCube());
9316 :
9317 0 : if(doFC)
9318 0 : msc_p->flagCategory().putColumnCells(rowstoadd, avb.flagCategory());
9319 :
9320 0 : msc_p->interval().putColumnCells(rowstoadd, avb.timeInterval());
9321 0 : msc_p->observationId().putColumnCells(rowstoadd, avb.observationId());
9322 0 : msc_p->processorId().putColumnCells(rowstoadd, avb.processorId());
9323 0 : msc_p->scanNumber().putColumnCells(rowstoadd, avb.scan()); // Don't remap!
9324 :
9325 0 : if(doSpWeight)
9326 0 : msc_p->weightSpectrum().putColumnCells(rowstoadd, avb.weightSpectrum());
9327 :
9328 0 : if(fromCorrToData) {
9329 0 : wtmat.reference(avb.weightMat());
9330 0 : msc_p->weight().putColumnCells(rowstoadd, wtmat);
9331 0 : arrayTransformInPlace(wtmat, subms::wtToSigma); // sig=1/sqrt(wt)
9332 0 : msc_p->sigma().putColumnCells(rowstoadd, wtmat);
9333 : }
9334 : else {
9335 0 : wtmat.reference(avb.sigmaMat()); // Yes, I'm reusing wtmat.
9336 0 : msc_p->sigma().putColumnCells(rowstoadd, wtmat);
9337 0 : arrayTransformInPlace(wtmat, subms::sigToWeight); // wt = 1/sig^2
9338 0 : msc_p->weight().putColumnCells(rowstoadd, wtmat);
9339 : }
9340 :
9341 0 : msc_p->stateId().putColumnCells(rowstoadd, avb.stateId());
9342 0 : msc_p->time().putColumnCells(rowstoadd, avb.time());
9343 0 : msc_p->timeCentroid().putColumnCells(rowstoadd, avb.timeCentroid());
9344 0 : msc_p->uvw().putColumnCells(rowstoadd, avb.uvwMat());
9345 :
9346 0 : rowsdone += rowsnow;
9347 0 : }
9348 0 : meter.update(inrowsdone);
9349 : } // End of for(vi.originChunks(); vi.moreChunks(); vi.nextChunk())
9350 0 : delete [] outCmplxCols;
9351 0 : os << LogIO::NORMAL << "Data binned." << LogIO::POST;
9352 :
9353 : os << LogIO::DEBUG1 // helpdesk ticket in from Oleg Smirnov (ODU-232630)
9354 0 : << "Post binning memory: " << Memory::allocatedMemoryInBytes() / (1024.0 * 1024.0) << " MB"
9355 0 : << LogIO::POST;
9356 :
9357 0 : if(rowsdone < 1){
9358 : os << LogIO::WARN
9359 : << "No rows were written. Is all the selected input flagged?"
9360 0 : << LogIO::POST;
9361 0 : return false;
9362 : }
9363 0 : return true;
9364 0 : }
9365 :
9366 0 : void SubMS::getDataColMap(MSColumns* msc, ArrayColumn<Complex>* mapper,
9367 : uInt ntok,
9368 : const Vector<MS::PredefinedColumns>& colEnums)
9369 : {
9370 : // Set up a map from dataColumn indices to ArrayColumns in the output.
9371 : // mapper has to be a pointer (gasp!), not a Vector, because
9372 : // Vector<ArrayColumn<Complex> > mapper(ntok) would implicitly call
9373 : // .resize(), which uses =, which is banned for ArrayColumn.
9374 :
9375 0 : if(mustConvertToData(ntok, colEnums)){
9376 0 : mapper[0].reference(msc->data());
9377 : }
9378 : else{
9379 0 : for(uInt i = 0; i < ntok; ++i){
9380 0 : if(colEnums[i] == MS::CORRECTED_DATA)
9381 0 : mapper[i].reference(msc->correctedData());
9382 0 : else if(colEnums[i] == MS::MODEL_DATA)
9383 0 : mapper[i].reference(msc->modelData());
9384 0 : else if(colEnums[i] == MS::LAG_DATA)
9385 0 : mapper[i].reference(msc->lagData());
9386 : else // The output default !=
9387 0 : mapper[i].reference(msc->data()); // the input default.
9388 : }
9389 : }
9390 0 : }
9391 :
9392 : inline Bool SubMS::areDataShapesConstant()
9393 : {
9394 : return allSame(inNumChan_p) && allSame(nchan_p) && allSame(inNumCorr_p) && allSame(ncorr_p);
9395 : }
9396 :
9397 0 : Bool isAllColumns(const Vector<MS::PredefinedColumns>& colNames)
9398 : {
9399 0 : Bool dCol=false, mCol=false, cCol=false;
9400 0 : for(uInt i=0;i<colNames.nelements();i++)
9401 : {
9402 0 : if (colNames[i] == MS::DATA) dCol=true;
9403 0 : else if (colNames[i] == MS::MODEL_DATA) mCol=true;
9404 0 : else if (colNames[i] == MS::CORRECTED_DATA) cCol=true;
9405 : // else turn off all?
9406 : }
9407 0 : return (dCol && mCol && cCol);
9408 : }
9409 :
9410 : // -----------------------------------------------------------------------
9411 : // Work-around to copy the keywords of the FLOAT_DATA column to the output MS
9412 : // -----------------------------------------------------------------------
9413 0 : void SubMS::copyMainTableKeywords (TableRecord& outKeys,
9414 : const TableRecord& inKeys)
9415 : {
9416 0 : for (uInt i=0; i<inKeys.nfields(); i++) {
9417 0 : if (inKeys.type(i) == TpString) {
9418 : // Add keywords for MAIN table columns such as FLOAT_DATA
9419 0 : String ikey = inKeys.name(i);
9420 0 : if (!outKeys.isDefined (ikey)) {
9421 0 : String keyval;
9422 0 : inKeys.get(ikey, keyval);
9423 0 : outKeys.define(ikey,keyval);
9424 0 : }
9425 :
9426 0 : }
9427 :
9428 : }
9429 0 : }
9430 :
9431 : } //#End casa namespace
|