Line data Source code
1 : //# ATCAFiller.cc: ATCA filler - reads rpfits, creates MeasurementSet
2 : //# Copyright (C) 2004
3 : //# Associated Universities, Inc. Washington DC, USA.
4 : //#
5 : //# This library is free software; you can redistribute it and/or modify it
6 : //# under the terms of the GNU Library General Public License as published by
7 : //# the Free Software Foundation; either version 2 of the License, or (at your
8 : //# option) any later version.
9 : //#
10 : //# This library is distributed in the hope that it will be useful, but WITHOUT
11 : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 : //# License for more details.
14 : //#
15 : //# You should have received a copy of the GNU Library General Public License
16 : //# along with this library; if not, write to the Free Software Foundation,
17 : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 : //#
19 : //# Correspondence concerning AIPS++ should be addressed as follows:
20 : //# Internet email: aips2-request@nrao.edu.
21 : //# Postal address: AIPS++ Project Office
22 : //# National Radio Astronomy Observatory
23 : //# 520 Edgemont Road
24 : //# Charlottesville, VA 22903-2475 USA
25 : //#
26 :
27 :
28 : #include <atnf/atca/ATCAFiller.h>
29 : #include <atnf/atca/ATAtmosphere.h>
30 : #include <casacore/casa/Arrays/Cube.h>
31 : #include <casacore/casa/Utilities/GenSort.h>
32 : #include <casacore/scimath/Mathematics/FFTServer.h>
33 : #include <casacore/casa/OS/DirectoryIterator.h>
34 : #include <casacore/casa/OS/RegularFile.h>
35 : #include <casacore/tables/Tables.h>
36 : #include <atnf/rpfits/RPFITS.h>
37 : #include <casacore/ms/MeasurementSets/MSTileLayout.h>
38 :
39 : using namespace casacore;
40 : namespace casa {
41 :
42 0 : Int myround(Double x) { return Int(floor(x+0.5));}
43 :
44 1 : ATCAFiller::ATCAFiller():
45 : appendMode_p(false),
46 : storedHeader_p(false),
47 : skipScan_p(false),
48 : skipData_p(false),
49 : firstHeader_p(false),
50 : listHeader_p(false),
51 : fileSize_p(0),
52 : birdie_p(false),
53 : reweight_p(false),
54 : noxycorr_p(false),
55 : obsType_p(0),
56 : hires_p(false),
57 : init_p(false),
58 : lastUT_p(0),
59 : bandWidth1_p(0),
60 : numChan1_p(0),
61 : shadow_p(0),
62 : autoFlag_p(true),
63 : flagScanType_p(false),
64 1 : flagCount_p(NFLAG,0)
65 1 : {}
66 :
67 1 : ATCAFiller::~ATCAFiller()
68 1 : {}
69 :
70 1 : Bool ATCAFiller::open(const String& msName, const Vector<String>& rpfitsFiles,
71 : const Vector<String>& options, Int opcor)
72 :
73 : {
74 : Int opt;
75 :
76 3 : LogOrigin orig("ATCAFiller", "open()", WHERE);
77 1 : os_p = LogIO(orig);
78 1 : rpfitsFiles_p = Directory::shellExpand(rpfitsFiles, false);
79 1 : GenSort<String>::sort(rpfitsFiles_p);
80 1 : if (rpfitsFiles_p.nelements() > 0) {
81 1 : os_p << LogIO::NORMAL << "Expanded file names are : " << endl;
82 2 : for (uInt i=0; i<rpfitsFiles_p.nelements(); i++) {
83 1 : if (rpfitsFiles_p(i).empty()) {
84 0 : os_p << "Input file number " << i+1 << " is empty" << LogIO::EXCEPTION;
85 : }
86 1 : os_p << rpfitsFiles_p(i) << endl;
87 : }
88 : } else {
89 0 : os_p << "Input file names vector is empty" << LogIO::EXCEPTION;
90 : }
91 2 : Vector<String> opts;
92 1 : if (options.nelements()==1) {
93 1 : opts=stringToVector(options(0),std::regex(" |,"));
94 : } else {
95 0 : opts=options;
96 : }
97 1 : opcor_p=opcor;
98 :
99 1 : Bool compress=false;
100 : // cerr<<"options="<<opts<<endl;
101 2 : for (opt=0; opt<Int(opts.nelements()); opt++) {
102 1 : if (downcase(opts(opt)) == "birdie") {
103 0 : birdie_p = true;
104 : }
105 1 : if (downcase(opts(opt)) == "reweight") {
106 0 : reweight_p = true;
107 : }
108 1 : if (downcase(opts(opt)) == "noxycorr") {
109 0 : noxycorr_p = true;
110 : }
111 1 : if (downcase(opts(opt)) == "compress") {
112 0 : compress = true;
113 : }
114 1 : if (downcase(opts(opt)) == "fastmosaic") {
115 0 : obsType_p=1;
116 : }
117 1 : if (downcase(opts(opt)) == "noautoflag") {
118 0 : autoFlag_p=false;
119 : }
120 1 : if (downcase(opts(opt)) == "hires") {
121 0 : hires_p=true;
122 : }
123 1 : if (downcase(opts(opt)) == "noac") {
124 1 : noac_p = true;
125 : }
126 : }
127 : // Check if this is CABB data or old ATCA data by checking the
128 : // INSTRUMENT keyword (ATCA, ATCABB)
129 1 : cabb_p = checkCABB(rpfitsFiles_p(0));
130 1 : reweight_p = reweight_p && !cabb_p;
131 1 : atms_p = makeTable(msName,compress,cabb_p);
132 1 : msc_p = new MSColumns(atms_p);
133 1 : msScanInfo_p = atms_p.keywordSet().asTable("ATCA_SCAN_INFO");
134 :
135 1 : String comp;
136 1 : if (compress) comp="Comp";
137 1 : dataAccessor_p = TiledDataStManAccessor(atms_p,"TiledData"+comp);
138 1 : sigmaAccessor_p = TiledDataStManAccessor(atms_p,"TiledSigma");
139 1 : flagAccessor_p = TiledDataStManAccessor(atms_p,"TiledFlag");
140 1 : flagCatAccessor_p = TiledDataStManAccessor(atms_p,"TiledFlagCategory");
141 :
142 1 : prev_fieldId_p = -1;
143 1 : lastWeatherUT_p=0;
144 1 : errCount_p=0;
145 1 : init();
146 1 : init_p=true;
147 2 : return true;
148 : }
149 :
150 :
151 1 : TableDesc ATCAFiller::atcaTableDesc(Bool compress)
152 : {
153 1 : TableDesc td = MS::requiredTableDesc();
154 : // add the data column
155 1 : MS::addColumnToDesc(td,MS::DATA,2);
156 : // and its unit
157 1 : td.rwColumnDesc(MS::columnName(MS::DATA)).rwKeywordSet().define("UNIT","Jy");
158 1 : if (compress) {
159 0 : String col = MS::columnName(MS::DATA);
160 0 : td.addColumn(ArrayColumnDesc<Int>(col+"_COMPRESSED",
161 0 : "observed data compressed",2));
162 0 : td.addColumn(ScalarColumnDesc<Float>(col+"_SCALE"));
163 0 : td.addColumn(ScalarColumnDesc<Float>(col+"_OFFSET"));
164 : }
165 :
166 : // add ATCA specific columns here..
167 1 : MS::addColumnToDesc(td,MS::PULSAR_BIN);
168 :
169 2 : td.addColumn(ScalarColumnDesc<Int>("ATCA_SYSCAL_ID_ANT1",
170 1 : "Index into SysCal table for Antenna1"));
171 2 : td.addColumn(ScalarColumnDesc<Int>("ATCA_SYSCAL_ID_ANT2",
172 1 : "Index into SysCal table for Antenna2"));
173 : // the tiled column indices
174 2 : td.addColumn(ScalarColumnDesc<Int>("DATA_HYPERCUBE_ID",
175 1 : "Index for Data Tiling"));
176 2 : td.addColumn(ScalarColumnDesc<Int>("SIGMA_HYPERCUBE_ID",
177 1 : "Index for Sigma Tiling"));
178 2 : td.addColumn(ScalarColumnDesc<Int>("FLAG_HYPERCUBE_ID",
179 1 : "Index for Flag Tiling"));
180 2 : td.addColumn(ScalarColumnDesc<Int>("FLAG_CATEGORY_HYPERCUBE_ID",
181 1 : "Index for Flag Category Tiling"));
182 :
183 1 : return td;
184 : }
185 :
186 1 : MeasurementSet ATCAFiller::makeTable(const String& tableName, Bool compress,
187 : Bool cabb)
188 : {
189 : // make the MeasurementSet Table
190 2 : TableDesc atDesc = atcaTableDesc(compress);
191 :
192 2 : String colData = MS::columnName(MS::DATA);
193 2 : String comp1,comp2;
194 1 : if (compress) { comp1="Comp"; comp2="_COMPRESSED";}
195 :
196 : // define tiled hypercube for the data
197 2 : Vector<String> coordColNames(0); //# don't use coord columns
198 1 : atDesc.defineHypercolumn("TiledData"+comp1,3,
199 2 : stringToVector(colData+comp2),
200 : coordColNames,
201 2 : stringToVector("DATA_HYPERCUBE_ID"));
202 1 : atDesc.defineHypercolumn("TiledSigma",2,
203 2 : stringToVector(MS::columnName(MS::SIGMA)),
204 : coordColNames,
205 2 : stringToVector("SIGMA_HYPERCUBE_ID"));
206 1 : atDesc.defineHypercolumn("TiledFlag",3,
207 2 : stringToVector(MS::columnName(MS::FLAG)),
208 : coordColNames,
209 2 : stringToVector("FLAG_HYPERCUBE_ID"));
210 1 : atDesc.defineHypercolumn("TiledFlagCategory",4,
211 2 : stringToVector(MS::columnName(MS::FLAG_CATEGORY)),
212 : coordColNames,
213 2 : stringToVector("FLAG_CATEGORY_HYPERCUBE_ID"));
214 :
215 2 : SetupNewTable newtab(tableName, atDesc, Table::New);
216 :
217 : // Set the default Storage Manager to be the incremental one
218 2 : IncrementalStMan incrStMan ("IncrementalData");
219 1 : newtab.bindAll(incrStMan, true);
220 : // Make an exception for fast varying data
221 2 : StandardStMan stStMan ("StandardData");
222 1 : newtab.bindColumn(MS::columnName(MS::UVW),stStMan);
223 1 : newtab.bindColumn(MS::columnName(MS::ANTENNA2),stStMan);
224 1 : newtab.bindColumn("ATCA_SYSCAL_ID_ANT2",stStMan);
225 1 : if (compress) {
226 0 : newtab.bindColumn(colData+"_SCALE",stStMan);
227 0 : newtab.bindColumn(colData+"_OFFSET",stStMan);
228 : }
229 :
230 :
231 2 : TiledDataStMan tiledStMan1("TiledData"+comp1);
232 : // Bind the DATA & FLAG column to the tiled stman
233 1 : newtab.bindColumn(MS::columnName(MS::DATA)+comp2,tiledStMan1);
234 1 : newtab.bindColumn("DATA_HYPERCUBE_ID",tiledStMan1);
235 1 : if (compress) {;
236 0 : CompressComplex ccData(colData,colData+"_COMPRESSED",
237 0 : colData+"_SCALE",colData+"_OFFSET", true);
238 0 : newtab.bindColumn(MS::columnName(MS::DATA),ccData);
239 : }
240 :
241 2 : TiledDataStMan tiledStMan2("TiledSigma");
242 : // Bind the SIGMA column to its own tiled stman
243 1 : newtab.bindColumn(MS::columnName(MS::SIGMA),tiledStMan2);
244 1 : newtab.bindColumn("SIGMA_HYPERCUBE_ID",tiledStMan2);
245 :
246 2 : TiledDataStMan tiledStMan3("TiledFlag");
247 : // Bind the FLAG column to its own tiled stman
248 1 : newtab.bindColumn(MS::columnName(MS::FLAG),tiledStMan3);
249 1 : newtab.bindColumn("FLAG_HYPERCUBE_ID",tiledStMan3);
250 :
251 2 : TiledDataStMan tiledStMan3c("TiledFlagCategory");
252 : // Bind the FLAG_CATEGORY column to its own tiled stman
253 1 : newtab.bindColumn(MS::columnName(MS::FLAG_CATEGORY),tiledStMan3c);
254 1 : newtab.bindColumn("FLAG_CATEGORY_HYPERCUBE_ID",tiledStMan3c);
255 :
256 :
257 : // create the table (with 0 rows)
258 1 : MeasurementSet ms(newtab, 0);
259 : // create the subtables
260 1 : makeSubTables(ms, Table::New, cabb);
261 :
262 2 : return ms;
263 : }
264 :
265 1 : void ATCAFiller::makeSubTables(MS& ms, Table::TableOption option, Bool cabb)
266 : {
267 : // This routine is modeled after MS::makeDummySubtables
268 : // we make new tables with 0 rows
269 1 : Int nrow=0;
270 :
271 : // Set up the subtables for the ATCA MS
272 :
273 : // Antenna
274 2 : TableDesc antTD=MSAntenna::requiredTableDesc();
275 1 : MSAntenna::addColumnToDesc(antTD, MSAntenna::PHASED_ARRAY_ID);
276 1 : MSAntenna::addColumnToDesc(antTD, MSAntenna::ORBIT_ID);
277 2 : SetupNewTable antennaSetup(ms.antennaTableName(),antTD,option);
278 2 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::ANTENNA),
279 2 : Table(antennaSetup,nrow));
280 :
281 : // Data descr
282 2 : TableDesc datadescTD=MSDataDescription::requiredTableDesc();
283 2 : SetupNewTable datadescSetup(ms.dataDescriptionTableName(),datadescTD,option);
284 2 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::DATA_DESCRIPTION),
285 2 : Table(datadescSetup,nrow));
286 :
287 : // Feed
288 2 : TableDesc feedTD=MSFeed::requiredTableDesc();
289 1 : MSFeed::addColumnToDesc(feedTD, MSFeed::PHASED_FEED_ID);
290 2 : SetupNewTable feedSetup(ms.feedTableName(),feedTD,option);
291 2 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::FEED),
292 2 : Table(feedSetup,nrow));
293 :
294 : // Field
295 2 : TableDesc fieldTD=MSField::requiredTableDesc();
296 2 : SetupNewTable fieldSetup(ms.fieldTableName(),fieldTD,option);
297 2 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::FIELD),
298 2 : Table(fieldSetup,nrow));
299 :
300 : // Flag_cmd
301 2 : TableDesc flagcmdTD=MSFlagCmd::requiredTableDesc();
302 2 : SetupNewTable flagcmdSetup(ms.flagCmdTableName(),flagcmdTD,option);
303 2 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::FLAG_CMD),
304 2 : Table(flagcmdSetup,nrow));
305 :
306 :
307 : // Observation
308 2 : TableDesc obsTD=MSObservation::requiredTableDesc();
309 2 : SetupNewTable observationSetup(ms.observationTableName(),obsTD,option);
310 2 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::OBSERVATION),
311 2 : Table(observationSetup,nrow));
312 :
313 : // History
314 2 : TableDesc historyTD=MSHistory::requiredTableDesc();
315 2 : SetupNewTable historySetup(ms.historyTableName(),historyTD,option);
316 2 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::HISTORY),
317 2 : Table(historySetup,nrow));
318 :
319 : // Pointing
320 2 : TableDesc pointingTD=MSPointing::requiredTableDesc();
321 1 : MSPointing::addColumnToDesc(pointingTD, MSPointing::POINTING_OFFSET);
322 2 : SetupNewTable pointingSetup(ms.pointingTableName(),pointingTD,option);
323 : // Pointing table can be large, set some sensible defaults for storageMgrs
324 2 : IncrementalStMan ismPointing ("ISMPointing");
325 2 : StandardStMan ssmPointing("SSMPointing",32768);
326 1 : pointingSetup.bindAll(ismPointing,true);
327 1 : pointingSetup.bindColumn(MSPointing::columnName(MSPointing::ANTENNA_ID),
328 : ssmPointing);
329 2 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::POINTING),
330 2 : Table(pointingSetup,nrow));
331 :
332 : // Polarization
333 2 : TableDesc polTD=MSPolarization::requiredTableDesc();
334 2 : SetupNewTable polSetup(ms.polarizationTableName(),polTD,option);
335 2 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::POLARIZATION),
336 2 : Table(polSetup,nrow));
337 :
338 : // Processor
339 2 : TableDesc processorTD=MSProcessor::requiredTableDesc();
340 2 : SetupNewTable processorSetup(ms.processorTableName(),processorTD,option);
341 2 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::PROCESSOR),
342 2 : Table(processorSetup,nrow));
343 :
344 : // Source
345 2 : TableDesc sourceTD=MSSource::requiredTableDesc();
346 1 : MSSource::addColumnToDesc(sourceTD, MSSource::SYSVEL);
347 1 : MSSource::addColumnToDesc(sourceTD, MSSource::NUM_LINES);
348 1 : MSSource::addColumnToDesc(sourceTD, MSSource::TRANSITION);
349 1 : MSSource::addColumnToDesc(sourceTD, MSSource::REST_FREQUENCY);
350 :
351 2 : SetupNewTable sourceSetup(ms.sourceTableName(),sourceTD,option);
352 2 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::SOURCE),
353 2 : Table(sourceSetup,nrow));
354 :
355 :
356 : // SpectralWindow
357 2 : TableDesc spwTD=MSSpectralWindow::requiredTableDesc();
358 1 : if (!cabb) spwTD.addColumn(ScalarColumnDesc<Int>("ATCA_SAMPLER_BITS",
359 0 : "Number of bits used for sampling"));
360 2 : SetupNewTable spectralWindowSetup(ms.spectralWindowTableName(),spwTD,option);
361 2 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::SPECTRAL_WINDOW),
362 2 : Table(spectralWindowSetup,nrow));
363 :
364 : // State
365 2 : TableDesc stateTD=MSState::requiredTableDesc();
366 2 : SetupNewTable stateSetup(ms.stateTableName(),stateTD,option);
367 2 : ms.rwKeywordSet().defineTable(MS::keywordName(MS::STATE),
368 2 : Table(stateSetup,nrow));
369 :
370 : // SysCal
371 2 : TableDesc sysCalTD=MSSysCal::requiredTableDesc();
372 2 : Vector<String> cols(4);
373 1 : if (!cabb) {
374 0 : sysCalTD.addColumn(ArrayColumnDesc<Float>
375 : ("ATCA_SAMP_STATS_NEG",
376 : "Sampler statistics, negative level",
377 0 : IPosition(1,2),ColumnDesc::Direct));
378 0 : sysCalTD.addColumn(ArrayColumnDesc<Float>
379 : ("ATCA_SAMP_STATS_ZERO",
380 : "Sampler statistics, zero level",
381 0 : IPosition(1,2),ColumnDesc::Direct));
382 0 : sysCalTD.addColumn(ArrayColumnDesc<Float>
383 : ("ATCA_SAMP_STATS_POS",
384 : "Sampler statistics, positive level",
385 0 : IPosition(1,2),ColumnDesc::Direct));
386 0 : cols(1)="ATCA_SAMP_STATS_NEG";
387 0 : cols(2)="ATCA_SAMP_STATS_ZERO";
388 0 : cols(3)="ATCA_SAMP_STATS_POS";
389 : } else {
390 2 : sysCalTD.addColumn(ArrayColumnDesc<Float>
391 : ("ATCA_GTP",
392 : "Noise Cal On+Off Autocorrelation",
393 3 : IPosition(1,2),ColumnDesc::Direct));
394 2 : sysCalTD.addColumn(ArrayColumnDesc<Float>
395 : ("ATCA_SDO",
396 : "Noise Cal On-Off Autocorrelation",
397 3 : IPosition(1,2),ColumnDesc::Direct));
398 2 : sysCalTD.addColumn(ArrayColumnDesc<Float>
399 : ("ATCA_CALJY",
400 : "Calibration factor",
401 3 : IPosition(1,2),ColumnDesc::Direct));
402 :
403 1 : cols(1)="ATCA_GTP";
404 1 : cols(2)="ATCA_SDO";
405 1 : cols(3)="ATCA_CALJY";
406 : }
407 2 : sysCalTD.addColumn(ScalarColumnDesc<Float>
408 : ("ATCA_XY_AMPLITUDE",
409 1 : "Noise source cross correlation amplitude"));
410 2 : sysCalTD.addColumn(ScalarColumnDesc<Float>
411 : ("ATCA_TRACK_ERR_MAX",
412 1 : "Max tracking error over non blanked cycle"));
413 3 : TableQuantumDesc tqd1(sysCalTD,"ATCA_TRACK_ERR_MAX",Unit("arcsec"));
414 1 : tqd1.write(sysCalTD);
415 2 : sysCalTD.addColumn(ScalarColumnDesc<Float>
416 : ("ATCA_TRACK_ERR_RMS",
417 1 : "RMS tracking error over non blanked cycle"));
418 3 : TableQuantumDesc tqd2(sysCalTD,"ATCA_TRACK_ERR_RMS",Unit("arcsec"));
419 1 : tqd2.write(sysCalTD);
420 :
421 2 : MSSysCal::addColumnToDesc(sysCalTD, MSSysCal::TSYS,
422 2 : IPosition(1, 2), ColumnDesc::Direct);
423 2 : MSSysCal::addColumnToDesc(sysCalTD, MSSysCal::TCAL,
424 2 : IPosition(1, 2), ColumnDesc::Direct);
425 2 : MSSysCal::addColumnToDesc(sysCalTD, MSSysCal::TRX,
426 2 : IPosition(1, 2),ColumnDesc::Direct);
427 1 : MSSysCal::addColumnToDesc(sysCalTD, MSSysCal::TSYS_FLAG);
428 1 : MSSysCal::addColumnToDesc(sysCalTD, MSSysCal::PHASE_DIFF);
429 1 : MSSysCal::addColumnToDesc(sysCalTD, MSSysCal::PHASE_DIFF_FLAG);
430 1 : MSSysCal::addColumnToDesc(sysCalTD, MSSysCal::TCAL_FLAG);
431 1 : MSSysCal::addColumnToDesc(sysCalTD, MSSysCal::TRX_FLAG);
432 1 : cols(0) = MSSysCal::columnName(MSSysCal::TSYS);
433 1 : sysCalTD.defineHypercolumn("TiledSysCal",2,cols);
434 2 : SetupNewTable sysCalSetup(ms.sysCalTableName(),sysCalTD,option);
435 2 : IncrementalStMan incStMan;
436 1 : sysCalSetup.bindAll(incStMan);
437 3 : TiledColumnStMan tiledStManSysCal("TiledSysCal",IPosition(2,2,1024));
438 :
439 5 : for (uInt i=0; i<cols.nelements(); i++) {
440 4 : sysCalSetup.bindColumn(cols(i),tiledStManSysCal);
441 : }
442 2 : ms.rwKeywordSet().defineTable(ms.keywordName(MS::SYSCAL),
443 2 : Table(sysCalSetup,nrow));
444 :
445 : // Weather
446 2 : TableDesc weatherTD=MSWeather::requiredTableDesc();
447 1 : MSWeather::addColumnToDesc(weatherTD,MSWeather::PRESSURE);
448 1 : MSWeather::addColumnToDesc(weatherTD,MSWeather::REL_HUMIDITY);
449 1 : MSWeather::addColumnToDesc(weatherTD,MSWeather::TEMPERATURE);
450 1 : MSWeather::addColumnToDesc(weatherTD,MSWeather::WIND_DIRECTION);
451 1 : MSWeather::addColumnToDesc(weatherTD,MSWeather::WIND_SPEED);
452 1 : MSWeather::addColumnToDesc(weatherTD,MSWeather::PRESSURE_FLAG);
453 1 : MSWeather::addColumnToDesc(weatherTD,MSWeather::REL_HUMIDITY_FLAG);
454 1 : MSWeather::addColumnToDesc(weatherTD,MSWeather::TEMPERATURE_FLAG);
455 1 : MSWeather::addColumnToDesc(weatherTD,MSWeather::WIND_DIRECTION_FLAG);
456 1 : MSWeather::addColumnToDesc(weatherTD,MSWeather::WIND_SPEED_FLAG);
457 2 : weatherTD.addColumn(ScalarColumnDesc<Float>
458 : ("ATCA_RAIN_GAUGE",
459 1 : "Rain since 10am local time"));
460 3 : TableQuantumDesc tqds0(weatherTD,"ATCA_RAIN_GAUGE",Unit("mm"));
461 1 : tqds0.write(weatherTD);
462 2 : weatherTD.addColumn(ScalarColumnDesc<Float>
463 : ("ATCA_SEEMON_PHASE",
464 1 : "Seeing monitor raw phase at 22GHz"));
465 3 : TableQuantumDesc tqds1(weatherTD,"ATCA_SEEMON_PHASE",Unit("rad"));
466 1 : tqds1.write(weatherTD);
467 2 : weatherTD.addColumn(ScalarColumnDesc<Float>
468 : ("ATCA_SEEMON_RMS",
469 1 : "Seeing monitor RMS phase"));
470 3 : TableQuantumDesc tqds2(weatherTD,"ATCA_SEEMON_RMS",Unit("mm"));
471 1 : tqds2.write(weatherTD);
472 2 : weatherTD.addColumn(ScalarColumnDesc<Bool>
473 : ("ATCA_SEEMON_FLAG",
474 1 : "Seeing monitor flag"));
475 2 : SetupNewTable weatherSetup(ms.weatherTableName(),weatherTD,option);
476 2 : ms.rwKeywordSet().defineTable(ms.keywordName(MS::WEATHER),
477 2 : Table(weatherSetup,nrow));
478 :
479 : // ATCA_SCAN_INFO
480 2 : TableDesc atsiTD;
481 2 : atsiTD.addColumn(ScalarColumnDesc<Int>("ANTENNA_ID",
482 1 : "Antenna Id"));
483 2 : atsiTD.addColumn(ScalarColumnDesc<Int>("SCAN_ID",
484 1 : "Scan number from main table"));
485 2 : atsiTD.addColumn(ScalarColumnDesc<Int>("SPECTRAL_WINDOW_ID",
486 1 : "Spectral window Id"));
487 2 : atsiTD.addColumn(ArrayColumnDesc<Int>("FINE_ATTENUATOR",
488 : "Fine Attenuator setting A,B",
489 3 : IPosition(1,2),ColumnDesc::Direct));
490 2 : atsiTD.addColumn(ArrayColumnDesc<Int>("COARSE_ATTENUATOR",
491 : "COARSE Attenuator setting A,B",
492 3 : IPosition(1,2),ColumnDesc::Direct));
493 2 : atsiTD.addColumn(ArrayColumnDesc<Int>("MM_ATTENUATOR",
494 : "mm Attenuator setting A,B",
495 3 : IPosition(1,2),ColumnDesc::Direct));
496 2 : atsiTD.addColumn(ArrayColumnDesc<Float>("SUBREFLECTOR",
497 : "Subreflector position(center,edge/tilt)",
498 3 : IPosition(1,2),ColumnDesc::Direct));
499 3 : TableQuantumDesc tqd3(atsiTD,"SUBREFLECTOR",Unit("m"));
500 1 : tqd3.write(atsiTD);
501 2 : atsiTD.addColumn(ScalarColumnDesc<String>("CORR_CONFIG",
502 1 : "Correlator configuration"));
503 2 : atsiTD.addColumn(ScalarColumnDesc<String>("SCAN_TYPE",
504 1 : "Scan type"));
505 2 : atsiTD.addColumn(ScalarColumnDesc<String>("COORD_TYPE",
506 1 : "CAOBS Coordinate type"));
507 2 : atsiTD.addColumn(ScalarColumnDesc<String>("POINTING_INFO",
508 1 : "Pointing info - details of last point scan"));
509 2 : atsiTD.addColumn(ScalarColumnDesc<Bool>("LINE_MODE",
510 1 : "Line Mode: true=spectrum, false=mfs"));
511 2 : atsiTD.addColumn(ScalarColumnDesc<Int>("CACAL_CNT",
512 1 : "Online calibration counter"));
513 :
514 2 : SetupNewTable scanInfoSetup(ms.tableName()+"/ATCA_SCAN_INFO",atsiTD,option);
515 2 : IncrementalStMan incSIStMan("ISMScanInfo");
516 2 : StandardStMan stdSIStMan("SSMScanInfo",32768);
517 1 : scanInfoSetup.bindAll(incSIStMan);
518 1 : scanInfoSetup.bindColumn("ANTENNA_ID",stdSIStMan);
519 2 : ms.rwKeywordSet().defineTable("ATCA_SCAN_INFO",
520 2 : Table(scanInfoSetup,nrow));
521 :
522 : // update the references to the subtable keywords
523 1 : ms.initRefs();
524 1 : }
525 :
526 :
527 1 : void ATCAFiller::init()
528 : {
529 : //Initialize selection
530 1 : scanRange(0, 0);
531 1 : freqRange(0.0,1.e30);
532 2 : Vector<String> fieldNames(0);
533 1 : fields(fieldNames);
534 :
535 : // extra ID columns in main table
536 1 : colSysCalIdAnt1.attach(atms_p,"ATCA_SYSCAL_ID_ANT1");
537 1 : colSysCalIdAnt2.attach(atms_p,"ATCA_SYSCAL_ID_ANT2");
538 :
539 : // extra spectralWindow table columns
540 1 : if (!cabb_p) colSamplerBits.attach(atms_p.spectralWindow(),"ATCA_SAMPLER_BITS");
541 :
542 : // extra syscal table columns
543 1 : if (cabb_p) {
544 1 : colGTP.attach(atms_p.sysCal(),"ATCA_GTP");
545 1 : colSDO.attach(atms_p.sysCal(),"ATCA_SDO");
546 1 : colCalJy.attach(atms_p.sysCal(),"ATCA_CALJY");
547 : } else {
548 0 : colSamplerStatsNeg.attach(atms_p.sysCal(),"ATCA_SAMP_STATS_NEG");
549 0 : colSamplerStatsZero.attach(atms_p.sysCal(),"ATCA_SAMP_STATS_ZERO");
550 0 : colSamplerStatsPos.attach(atms_p.sysCal(),"ATCA_SAMP_STATS_POS");
551 : }
552 : // cParAngle.attach(sysCalTable,"ParalAngle");
553 1 : colXYAmplitude.attach(atms_p.sysCal(),"ATCA_XY_AMPLITUDE");
554 1 : colTrackErrMax.attach(atms_p.sysCal(),"ATCA_TRACK_ERR_MAX");
555 1 : colTrackErrRMS.attach(atms_p.sysCal(),"ATCA_TRACK_ERR_RMS");
556 :
557 : // ScanInfo table columns
558 1 : Table sit(atms_p.keywordSet().asTable("ATCA_SCAN_INFO"));
559 1 : colScanInfoAntId.attach(sit,"ANTENNA_ID");
560 1 : colScanInfoScanId.attach(sit,"SCAN_ID");
561 1 : colScanInfoSpWId.attach(sit,"SPECTRAL_WINDOW_ID");
562 1 : colScanInfoCacal.attach(sit,"CACAL_CNT");
563 1 : colScanInfoFine.attach(sit,"FINE_ATTENUATOR");
564 1 : colScanInfoCoarse.attach(sit,"COARSE_ATTENUATOR");
565 1 : colScanInfommAtt.attach(sit,"MM_ATTENUATOR");
566 1 : colScanInfoSubreflector.attach(sit,"SUBREFLECTOR");
567 1 : colScanInfoCorrConfig.attach(sit,"CORR_CONFIG");
568 1 : colScanInfoScanType.attach(sit,"SCAN_TYPE");
569 1 : colScanInfoCoordType.attach(sit,"COORD_TYPE");
570 1 : colScanInfoPointInfo.attach(sit,"POINTING_INFO");
571 1 : colScanInfoLineMode.attach(sit,"LINE_MODE");
572 :
573 : // Extra weather table columns
574 1 : colWeatherRainGauge.attach(atms_p.weather(),"ATCA_RAIN_GAUGE");
575 1 : colWeatherSeeMonPhase.attach(atms_p.weather(),"ATCA_SEEMON_PHASE");
576 1 : colWeatherSeeMonRMS.attach(atms_p.weather(),"ATCA_SEEMON_RMS");
577 1 : colWeatherSeeMonFlag.attach(atms_p.weather(),"ATCA_SEEMON_FLAG");
578 :
579 1 : nScan_p=nSpW_p=nField_p=scanNo_p=0;
580 1 : gotAN_p=false;
581 1 : }
582 :
583 : // list the current scan and return the current day in mjd
584 1 : void ATCAFiller::listScan(Double & mjd, Int scan, Double ut)
585 : {
586 : // Convert observation date to mjd
587 : Int day,month,year;
588 1 : sscanf(names_.datobs,"%4d-%2d-%2d",&year,&month,&day);
589 1 : MVTime mjd_date(year,month,(Double)day);
590 1 : mjd=mjd_date.second();
591 1 : mjd_date=MVTime((mjd_date.second()+ut)/C::day);
592 1 : os_p << LogIO::NORMAL << "Scan # : "<< scan << endl;
593 1 : os_p << LogIO::NORMAL << "Object : "<< String(names_.object,16) << endl;
594 1 : os_p << LogIO::NORMAL << "Date : "<< mjd_date.string(MVTime::YMD)
595 1 : << LogIO::POST;
596 1 : }
597 :
598 :
599 1 : Bool ATCAFiller::fill() {
600 1 : if (!init_p) return false;
601 1 : if (!appendMode_p) {
602 1 : firstHeader_p = true;
603 1 : skipScan_p=false;
604 1 : skipData_p=false;
605 :
606 1 : nScan_p=1; // we've seen the 1st header
607 1 : scanNo_p=-1; // make zero based for storage in MS
608 :
609 : Int fileno;
610 1 : Int offset=0;
611 :
612 2 : for (fileno=0; fileno<Int(rpfitsFiles_p.nelements())-offset; fileno++) {
613 1 : listHeader_p = true;
614 1 : currentFile_p = rpfitsFiles_p(fileno);
615 1 : fill1(currentFile_p);
616 : }
617 :
618 1 : os_p << LogIO::DEBUGGING << "FillFeed" << LogIO::POST;
619 1 : fillFeedTable();
620 :
621 1 : fillObservationTable();
622 :
623 1 : fillMeasureReferences();
624 1 : os_p << LogIO::DEBUGGING << "#spectral windows " << nSpW_p << LogIO::POST;
625 :
626 :
627 : } else { // appendMode
628 0 : if (!eof_p) {
629 0 : fill1(currentFile_p);
630 : } else {
631 :
632 0 : RegularFile rFile(currentFile_p);
633 0 : uInt newSize = rFile.size();
634 0 : os_p << LogIO::NORMAL << "new file size " << newSize << LogIO::POST;
635 :
636 0 : if ( newSize != fileSize_p) {
637 0 : fill1(currentFile_p);
638 : } else {
639 :
640 0 : Int jstat=1; // close file
641 0 : rpfitsin_(&jstat, vis, weight, &baseline, &ut, &u, &v, &w,
642 : &flg, &bin, &if_no, &sourceno);
643 :
644 0 : os_p << LogIO::NORMAL << "Look for next file ..." << LogIO::POST;
645 :
646 0 : Vector<String> elts=stringToVector(currentFile_p,std::regex("/"));
647 0 : String rpfitsDir_p = "";
648 0 : if (elts.nelements()>1) {
649 0 : Int m = elts.nelements() - 1;
650 0 : for (Int n=0; n < m; n++) {
651 0 : rpfitsDir_p = rpfitsDir_p + elts(n) + "/";
652 : }
653 : }
654 0 : os_p << LogIO::DEBUGGING << "RPFITSDIR : " << rpfitsDir_p << LogIO::POST;
655 :
656 0 : Directory dir(rpfitsDir_p);
657 0 : Regex regexp(".*\\.[cxv]+[0-9]+");
658 :
659 0 : DirectoryIterator dirIter(dir, regexp);
660 :
661 0 : String entry;
662 0 : Bool found = false;
663 0 : while (!dirIter.pastEnd()) {
664 0 : entry = rpfitsDir_p+dirIter.name();
665 0 : os_p << LogIO::DEBUGGING << " file: "<< entry << LogIO::POST;
666 0 : if (found) break;
667 0 : if (entry == currentFile_p) found = true;
668 0 : dirIter++;
669 : }
670 :
671 0 : os_p << LogIO::NORMAL << " new file: "<< entry << LogIO::POST;
672 :
673 0 : if (entry == currentFile_p) {
674 0 : os_p << LogIO::NORMAL << " No new file..."<< LogIO::POST;
675 : } else {
676 0 : String oldstr = String(currentFile_p.at(1, currentFile_p.length()));
677 0 : os_p << LogIO::DEBUGGING << " oldstr... "<< oldstr << LogIO::POST;
678 0 : String newstr = String(entry.at(1, entry.length()));
679 0 : os_p << LogIO::DEBUGGING << " newstr... "<< newstr << LogIO::POST;
680 :
681 0 : if (oldstr.after(Regex(".*\\.")) != newstr.after(Regex(".*\\."))) {
682 0 : os_p << LogIO::NORMAL << " Project changed..."<< LogIO::POST;
683 : } else {
684 0 : currentFile_p = entry;
685 0 : listHeader_p = true;
686 0 : fill1(currentFile_p);
687 : }
688 : }
689 : }
690 : }
691 : }
692 : // flag the last integration for shadowing
693 1 : if (shadow_p>0) shadow(0,true);
694 :
695 : // flush the table and unlock it
696 : // NOTE: this still keeps a reference to the table which causes problems
697 : // when the ms do calls close (it wants to write to the table)
698 1 : flush();
699 1 : unlock();
700 :
701 1 : return true;
702 : }
703 :
704 1 : Bool ATCAFiller::checkCABB(const String& rpfitsFile)
705 : {
706 : Int jstat;
707 2 : Regex trailing(" *$"); // trailing blanks
708 :
709 2 : String file = rpfitsFile;
710 1 : os_p << LogIO::NORMAL <<"Checking header of file "<<file<< LogIO::POST;
711 1 : strcpy(names_.file,file.chars());
712 1 : jstat=-2; // open rpfits file and read first header
713 1 : param_.ncard=-1; // collect cards into card array
714 1 : rpfitsin_(&jstat, vis, weight, &baseline, &ut, &u, &v, &w, &flg, &bin,
715 : &if_no, &sourceno);
716 1 : if (jstat==-1) {
717 0 : os_p << LogIO::SEVERE << " Error opening RPFits file: "<<file
718 0 : << LogIO::POST;
719 0 : return false;
720 : }
721 : // read INSTRUMENT keyword
722 2 : String instrument = String(names_.instrument,16).before(trailing);
723 : // close the file
724 1 : jstat=1;
725 1 : rpfitsin_(&jstat, vis, weight, &baseline, &ut, &u, &v, &w, &flg, &bin,
726 : &if_no, &sourceno);
727 1 : if (instrument=="ATCABB") {
728 1 : os_p<< LogIO::NORMAL<<"CABB data detected"<<LogIO::POST;
729 1 : return true;
730 : }
731 0 : else return false;
732 : }
733 :
734 1 : Bool ATCAFiller::fill1(const String& rpfitsFile)
735 : {
736 : Int jstat;
737 2 : Regex trailing(" *$"); // trailing blanks
738 :
739 2 : String file = rpfitsFile;
740 1 : if (listHeader_p == true) {
741 1 : os_p << LogIO::NORMAL <<"Reading file "<<file<< LogIO::POST;
742 1 : strcpy(names_.file,file.chars());
743 1 : jstat=-2; // open rpfits file and read first header
744 1 : param_.ncard=-1; // collect cards into card array
745 1 : rpfitsin_(&jstat, vis, weight, &baseline, &ut, &u, &v, &w, &flg, &bin,
746 : &if_no, &sourceno);
747 1 : if (jstat==-1) {
748 0 : os_p << LogIO::SEVERE << " Error opening RPFits file: "<<file
749 0 : << LogIO::POST;
750 0 : return false;
751 : }
752 : }
753 : // Otherwise we enter fill1 for the second time with the same file name
754 :
755 : // prepare to read data blocks, rpfitsin will tell us if
756 : // there is a header to be read instead
757 1 : jstat=0;
758 :
759 1 : Double lastUT=0,lastUT2=0;
760 1 : Int lastScanNo=-1,lastIF=-1;
761 1 : flagCount_p=0;
762 1502 : while (jstat==0) {
763 1501 : rpfitsin_(&jstat, vis, weight, &baseline, &ut, &u, &v, &w, &flg, &bin,
764 : &if_no, &sourceno);
765 :
766 1501 : switch(jstat) {
767 0 : case -1: // read failed
768 0 : os_p << LogIO::WARN <<
769 0 : "rpfitsin: read failed, retrying"<< LogIO::POST;
770 0 : jstat=0;
771 0 : break;
772 1482 : case 0: // found data: store header (incl Tables) and data
773 1482 : if (listHeader_p) { listScan(mjd0_p,nScan_p,ut); listHeader_p=false;}
774 :
775 : // do we want this scan?
776 1482 : if (skipScan_p || nScan_p<firstScan_p ||
777 1482 : (lastScan_p>0 && nScan_p>lastScan_p)) {
778 : //if (!skipScan_p) cerr<<"ss1=T"<<endl;
779 0 : skipScan_p=true;
780 : } else {
781 : // if_no and sourceno are not (always) set properly
782 : // for syscal records
783 1482 : if (baseline==-1) {if_no=1; sourceno=1;}
784 :
785 : // check if if_no valid
786 1482 : if (!if_.if_found|| if_no>if_.n_if) {
787 : //if (!skipScan_p)cerr<<"ss2=T"<<endl;
788 0 : skipScan_p=true;
789 : // assume not wanted or ^ garbled data
790 : } else {
791 : // check if we want this field
792 1482 : if (lastUT!=ut) {
793 138 : String field=String(names_.object,16).before(trailing);
794 69 : if (fieldSelection_p.nelements()>0 && fieldSelection_p(0).length()>0 &&
795 0 : !(anyEQ(fieldSelection_p,field))) {
796 : //cerr<< "Field:"<<field<<"-"<<fieldSelection_p.nelements()<<endl;
797 : //if (!skipScan_p) cerr<<"ss3=T"<<endl;
798 0 : skipScan_p=true;
799 : }
800 : }
801 1482 : if (!skipScan_p) {
802 1482 : if_no--; // go from 1-based to 0-based indexing (f2c)
803 1482 : sourceno--; // same here
804 : // skip unselected or garbled data
805 1482 : skipData_p=Bool(if_no<0 || !selected(if_no) || sourceno<0);
806 : // reject auto correlations?
807 1482 : if (noac_p) skipData_p |= (Int(baseline)%257==0);
808 : //cerr<<"SkipData="<<skipData_p<< " ifno="<<if_no<< " sourceno="<<sourceno<<endl;
809 : }
810 : }
811 : }
812 1482 : if (!skipScan_p && !skipData_p && firstHeader_p && anten_.nant>0) {
813 1 : nAnt_p=anten_.nant;
814 1 : Int NChan=if_.if_nfreq[if_no];
815 1 : Int NPol=if_.if_nstok[if_no];
816 1 : firstHeader_p=false;
817 1 : os_p << LogIO::NORMAL << " First data/header has NAnt="<<nAnt_p<<
818 1 : ", NChan="<<NChan<<", NPol="<<NPol<< LogIO::POST;
819 : }
820 1482 : if (!skipScan_p && !skipData_p) {
821 912 : if (anten_.nant>0 && anten_.nant!=nAnt_p) {
822 0 : os_p << LogIO::WARN << "#antennas changed from "<< nAnt_p <<
823 0 : " to "<<anten_.nant<<", skipping scan"<< LogIO::POST;
824 : //if (!skipScan_p)cerr<<"ss4=T"<<endl;
825 0 : skipScan_p=true;
826 : }
827 : }
828 1482 : if (!skipScan_p && !skipData_p && !storedHeader_p) {
829 1 : storeHeader();
830 1 : scanNo_p++;
831 1 : storedHeader_p=true;
832 : }
833 1482 : if (!skipScan_p) {
834 1482 : if (baseline==-1) {
835 : // we want at least some of the syscal data for this scan
836 57 : storeSysCal();
837 : }
838 1425 : else if (!skipData_p) {
839 855 : if (lastUT2!=ut || lastIF!=if_no){
840 57 : checkSpW(if_no); // we need to check these every integration to
841 57 : if (lastUT2!=ut) checkField();// cope with freq. switching and mosaicing
842 57 : lastUT2=ut;
843 57 : lastIF=if_no;
844 : }
845 855 : storeData();
846 : }
847 : }
848 1482 : skipData_p=false;
849 1482 : break;
850 0 : case 1:
851 0 : if (skipScan_p || scanNo_p==lastScanNo) {
852 : //cerr<<"ScanNo_p="<<scanNo_p<<" lastScanNo="<<lastScanNo<<" skipScan_p="<<skipScan_p<<endl;
853 0 : os_p << LogIO::NORMAL << "Scan "<<nScan_p <<" skipped"<<LogIO::POST;
854 : } else {
855 0 : os_p << LogIO::NORMAL << "Scan "<<nScan_p <<" stored"<< LogIO::POST;
856 : }
857 0 : lastScanNo=scanNo_p;
858 0 : nScan_p++;
859 0 : errCount_p=0;
860 0 : os_p << LogIO::DEBUGGING << "Read new header "<< LogIO::POST;
861 0 : jstat=-1;
862 0 : param_.ncard=-1;
863 0 : rpfitsin_(&jstat, vis, weight, &baseline, &ut, &u, &v, &w,
864 : &flg, &bin, &if_no, &sourceno);
865 0 : jstat=0;
866 :
867 0 : listScan(mjd0_p,nScan_p,ut);
868 0 : storedHeader_p=false;
869 0 : skipScan_p=false; //cerr<<"ss=F"<<endl;
870 0 : eof_p = false;
871 0 : if (!appendMode_p) break;
872 : // suppress this break to return after each end of scan
873 : // (actually each beginning of a new scan) in on line mode
874 :
875 : case 3:
876 1 : if (jstat == 3) { // because of the break suppression in case 1
877 1 : if (!skipScan_p && !skipData_p && !storedHeader_p) {
878 0 : storeHeader(True); // store sole header at end of file
879 0 : scanNo_p++; // to capture last commands & log messages
880 0 : storedHeader_p=true;
881 : }
882 1 : os_p << LogIO::NORMAL << "End of File" << LogIO::POST;
883 1 : eof_p = true;
884 1 : nScan_p++; // increment for next scan
885 : // print flagging stats for last scan
886 1 : if (flagCount_p(COUNT)>0) {
887 2 : Vector<Float> perc(NFLAG);
888 7 : for (Int i=0; i<NFLAG; i++) perc(i)=0.1*((1000*flagCount_p(i))/flagCount_p(COUNT));
889 1 : os_p<< LogIO::NORMAL <<"Number of rows selected : "<<flagCount_p(COUNT)<<endl;
890 1 : os_p<< LogIO::NORMAL <<"Flagged : "<<perc(FLAG)<<"%"<<endl;
891 1 : os_p<< LogIO::NORMAL <<" Antenna off source : "<<perc(ONLINE)<<"%"<<endl;
892 1 : os_p<< LogIO::NORMAL <<" ScanType (Point/Paddle): "<<perc(SCANTYPE)<<"%"<<endl;
893 1 : if (!cabb_p) os_p<< LogIO::NORMAL <<" Bad Sampler stats : "<<perc(SYSCAL)<<"%"<<endl;
894 1 : if (shadow_p>0) os_p<< LogIO::NORMAL <<" Antenna shadowed : "<<perc(SHADOW)<<"%"<<LogIO::POST;
895 : }
896 : }
897 :
898 1 : if (appendMode_p) {
899 : // after bumping one time at the end of the file or after the
900 : // first scan
901 :
902 0 : RegularFile rFile(file);
903 0 : fileSize_p = rFile.size();
904 :
905 0 : os_p << LogIO::NORMAL << "old file size " << fileSize_p
906 0 : << " Waiting ..." << LogIO::POST;
907 :
908 0 : flush();
909 0 : unlock();
910 :
911 : } else {
912 1 : jstat=1; // close file
913 1 : rpfitsin_(&jstat, vis, weight, &baseline, &ut, &u, &v, &w,
914 : &flg, &bin, &if_no, &sourceno);
915 : }
916 1 : jstat=1; // exit loop
917 1 : break;
918 0 : case 4:
919 0 : os_p << LogIO::WARN
920 : << "rpfitsin: found FG Table, ignoring it"
921 0 : << LogIO::POST;
922 0 : jstat=0;
923 0 : break;
924 18 : case 5:
925 : // jstat == 5 is usually record padding at the end of an integration.
926 : // just continue on loading..
927 18 : jstat=0;
928 18 : break;
929 0 : default:
930 0 : os_p << LogIO::WARN << "unknown rpfitsin return value: "
931 0 : <<jstat<< LogIO::POST;
932 0 : jstat=0;
933 : }
934 1501 : lastUT=ut;
935 : }
936 :
937 : // uncomment this if things take unexpectedly long
938 : // dataAccessor_p.showCacheStatistics(cout);
939 : // sigmaAccessor_p.showCacheStatistics(cout);
940 1 : return true;
941 : }
942 :
943 :
944 :
945 :
946 1 : void ATCAFiller::fillMeasureReferences()
947 : {
948 1 : String key("MEASURE_REFERENCE");
949 1 : msc_p->time().rwKeywordSet().define(key,"UTC");
950 1 : msc_p->uvw().rwKeywordSet().define(key,"J2000");
951 1 : msc_p->antenna().position().rwKeywordSet().define(key,"ITRF");
952 1 : msc_p->feed().time().rwKeywordSet().define(key,"UTC");
953 1 : msc_p->field().time().rwKeywordSet().define(key,"UTC");
954 1 : msc_p->field().delayDir().rwKeywordSet().define(key,"J2000");
955 1 : msc_p->field().phaseDir().rwKeywordSet().define(key,"J2000");
956 1 : msc_p->field().referenceDir().rwKeywordSet().define(key,"J2000");
957 1 : msc_p->source().time().rwKeywordSet().define(key,"UTC");
958 1 : msc_p->source().direction().rwKeywordSet().define(key,"J2000");
959 1 : msc_p->history().time().rwKeywordSet().define(key,"UTC");
960 1 : msc_p->spectralWindow().chanFreq().rwKeywordSet().define(key,"TOPO");
961 1 : msc_p->spectralWindow().refFrequency().rwKeywordSet().define(key,"TOPO");
962 :
963 : MFrequency::Types tp;
964 1 : MFrequency::getType(tp, msc_p->spectralWindow().refFrequency().keywordSet().asString("MEASURE_REFERENCE"));
965 1 : Int meas_freq_ref = tp;
966 1 : msc_p->spectralWindow().measFreqRef().fillColumn(meas_freq_ref);
967 1 : msc_p->sysCal().time().rwKeywordSet().define(key,"UTC");
968 1 : msc_p->weather().time().rwKeywordSet().define(key,"UTC");
969 1 : msc_p->pointing().direction().rwKeywordSet().define(key,"J2000");
970 1 : msc_p->pointing().pointingOffset().rwKeywordSet().define(key,"AZEL");
971 1 : }
972 :
973 2 : ATCAFiller & ATCAFiller::scanRange(Int first, Int last)
974 : {
975 2 : firstScan_p=first;
976 2 : lastScan_p=max(0,last);
977 2 : return *this;
978 : }
979 :
980 2 : ATCAFiller & ATCAFiller::freqRange(Double low, Double high)
981 : {
982 2 : lowFreq_p=low;
983 2 : highFreq_p=high;
984 2 : return *this;
985 : }
986 :
987 1 : ATCAFiller & ATCAFiller::freqSel(const Vector<Int>& spws)
988 : {
989 1 : spws_p=spws;
990 1 : return *this;
991 : }
992 :
993 2 : ATCAFiller & ATCAFiller::fields(const Vector<String>& fieldList)
994 : {
995 2 : fieldSelection_p=fieldList;
996 2 : return *this;
997 : }
998 :
999 0 : ATCAFiller & ATCAFiller::bandwidth1(Int bandwidth1)
1000 : {
1001 0 : bandWidth1_p=0;
1002 0 : for (Int bw=2; bw<=256; bw*=2) {
1003 0 : if(bw==bandwidth1) {
1004 0 : bandWidth1_p=bw;
1005 0 : break;
1006 : }
1007 : }
1008 0 : return *this;
1009 : }
1010 :
1011 0 : ATCAFiller & ATCAFiller::numChan1(Int numchan1)
1012 : {
1013 0 : numChan1_p=0;
1014 0 : for (Int nchan=32; nchan<=16384; nchan*=2) {
1015 0 : if((numchan1==nchan) || (numchan1==(nchan+1))) {
1016 0 : numChan1_p=nchan+1;
1017 0 : break;
1018 : }
1019 : }
1020 0 : return *this;
1021 : }
1022 :
1023 0 : ATCAFiller & ATCAFiller::shadow(Float diam)
1024 : {
1025 0 : shadow_p=0;
1026 0 : if (diam>0) shadow_p=diam;
1027 0 : return *this;
1028 : }
1029 :
1030 1 : ATCAFiller & ATCAFiller::edge(float edge)
1031 : {
1032 1 : edge_p=edge;
1033 1 : return *this;
1034 : }
1035 :
1036 1 : void ATCAFiller::storeHeader(bool last) {
1037 : // Bool skip=false;
1038 2 : Regex trailing(" *$"); // trailing blanks
1039 :
1040 : // First check antenna Table and store any new stations encountered
1041 1 : if (!gotAN_p && anten_.nant>0) {
1042 1 : if (anten_.an_found) {
1043 1 : gotAN_p=true;
1044 :
1045 7 : for (Int i=0; i<nAnt_p; i++) {
1046 6 : Int ant=Int(anten_.ant_num[i]); // 1-based !
1047 6 : if (ant!=i+1) {
1048 0 : os_p << LogIO::SEVERE
1049 : << "AN table corrupt, will try next one " << ant <<":"<<i<<":"<<nAnt_p
1050 0 : << LogIO::POST;
1051 0 : gotAN_p=false;
1052 0 : break;
1053 : }
1054 6 : atms_p.antenna().addRow();
1055 6 : Int n=atms_p.antenna().nrow()-1;
1056 :
1057 12 : String instrument = String(names_.instrument,16).before(trailing);
1058 12 : String station(&names_.sta[i*8],8);
1059 6 : os_p << LogIO::NORMAL <<"Antenna : "<< station << " ";
1060 12 : Vector<Double> xyz(3);
1061 6 : xyz(0)=doubles_.x[i];xyz(1)=doubles_.y[i];xyz(2)=doubles_.z[i];
1062 6 : os_p << " position:"<<xyz << endl;
1063 6 : if (instrument=="ATCA" || cabb_p) {
1064 12 : String antName;
1065 : // construct antenna name
1066 12 : ostringstream ostr; ostr << "CA0" <<i+1;
1067 6 : String str = ostr.str();
1068 6 : msc_p->antenna().name().put(n,str);
1069 6 : msc_p->antenna().station().put(n,atcaPosToStation(xyz));
1070 : } else {
1071 0 : msc_p->antenna().station().put(n,station.before(trailing));
1072 0 : msc_p->antenna().name().put(n,station.before(trailing));
1073 : }
1074 6 : msc_p->antenna().orbitId().put(n,-1);
1075 6 : msc_p->antenna().phasedArrayId().put(n,-1);
1076 6 : msc_p->antenna().dishDiameter().put(n,22.0);
1077 6 : msc_p->antenna().type().put(n, "GROUND-BASED");
1078 :
1079 6 : if (anten_.ant_mount[i]==0) {
1080 6 : msc_p->antenna().mount().put(n,"alt-az");
1081 : }
1082 : else {
1083 0 : msc_p->antenna().mount().put(n,"bizarre");
1084 : }
1085 6 : msc_p->antenna().position().put(n,xyz);
1086 12 : Vector<Double> offset(3); offset=0.;
1087 : // todo: figure out coordinate system of offset
1088 6 : offset(0)=doubles_.axis_offset[i];
1089 6 : msc_p->antenna().offset().put(n,offset);
1090 : // todo: values below may have to be stored elsewhere
1091 : //Vector<String> ft(2);
1092 : //ft(0)=String(&names_.feed_type[i*4],2);
1093 : //ft(1)=String(&names_.feed_type[i*4+2],2);
1094 : // cFeedType.put(n,ft);
1095 : //Vector<Double> pa(2);
1096 : //pa(0)=doubles_.feed_pa[i*2];pa(1)=doubles_.feed_pa[i*2+1];
1097 : // cFeedPA.put(n,pa);
1098 : //Matrix<Double> feedcal(1,1);//feedcal :split out on if and pol?
1099 : //feedcal(0,0)=0.0;
1100 : // cFeedCal.put(n,feedcal);
1101 : }
1102 1 : os_p.post();
1103 : } else {
1104 0 : os_p << LogIO::SEVERE <<
1105 0 : "No AN Table found before start of data!"<< LogIO::POST;
1106 : }
1107 : }
1108 :
1109 : // Check if current if_no already in SpW Table, add it if not.
1110 1 : if (!last) checkSpW(if_no);
1111 :
1112 : // Check if current Observation info already stored, add it if not
1113 1 : checkObservation();
1114 :
1115 : // Store the ATCA header cards
1116 1 : storeATCAHeader(last);
1117 :
1118 : // Check if we've seen current source before, if not add to table
1119 1 : if (!last) checkField();
1120 1 : }
1121 :
1122 1 : void ATCAFiller::storeATCAHeader(Bool last) {
1123 1 : uInt ncard = abs(param_.ncard);
1124 : //cout<<" #cards = "<<ncard<<endl;
1125 1 : String cards = String(names_.card,ncard*80);
1126 1 : const Int nTypes = 10;
1127 1 : Block<String> types(nTypes);
1128 1 : types[0]= "OBSLOG";
1129 1 : types[1] = "ATTEN";
1130 1 : types[2] = "SUBREFL";
1131 1 : types[3] = "CORR_CFG";
1132 1 : types[4] = "SCANTYPE";
1133 1 : types[5] = "COORDTYP";
1134 1 : types[6] = "LINEMODE";
1135 1 : types[7] = "CACALCNT";
1136 1 : types[8] = "POINTCOR";
1137 1 : types[9] = "POINTINF";
1138 1 : String obsLog = "";
1139 1 : String config = "none";
1140 1 : const Int nIF = if_.n_if;
1141 1 : const Int nAnt = anten_.nant;
1142 1 : Cube<Int> fine(2,nIF,nAnt,0),coarse(2,nIF,6,0);
1143 1 : Matrix<Int> mmAtt(nIF,nAnt,0);
1144 1 : Vector<Float> subrPos(nAnt,0),subrTilt(nAnt,0);
1145 1 : Matrix<Float> pointCorr(2,nAnt,0);
1146 1 : newPointingCorr_p=false;
1147 1 : flagScanType_p=false;
1148 1 : String scanType,coordType,pointInfo;
1149 1 : Vector<Bool> lineMode(nIF);
1150 1 : Int cacalCnt=0;
1151 1 : const Regex trailing(" *$"); // trailing blanks
1152 1 : Bool foundAny = false;
1153 1 : String::size_type pos=cards.find("EPHEM12"); // last 'standard' card
1154 : //cout << "pos="<<pos<<" String::npos=="<<String::npos<<endl;
1155 1 : if (pos==String::npos) return;
1156 1 : uInt iFirst=pos/80+1;
1157 43 : for (uInt i=iFirst; i<ncard; i++) {
1158 : // extract card
1159 84 : String card = cards.substr(i*80,80);
1160 : //cout << "card = "<< card<<endl;
1161 : // read antenna number (if present)
1162 42 : Int ant = 0;
1163 42 : pos=card.find("CA0");
1164 42 : if (pos!=String::npos) istringstream(card.substr(pos+2,2))>> ant;
1165 42 : ant-=1; // zero based indexing
1166 42 : if (ant>=nAnt) ant = -1;
1167 462 : for (Int j=0; j<nTypes; j++) {
1168 420 : if (card.find(types[j])==0) {
1169 20 : foundAny=true;
1170 : //cout << "Found card :"<<types[j]<<", ant="<<ant<<endl;
1171 20 : switch (j) {
1172 3 : case 0: obsLog+=card.substr(8,72).before(trailing);
1173 3 : obsLog+="\n";
1174 3 : break;
1175 6 : case 1: { //ATTEN
1176 6 : String::size_type pos=card.find("FINE=");
1177 6 : if (pos!=String::npos && ant>=0) {
1178 0 : for (Int k=0; k<nIF; k++) {
1179 0 : istringstream(card.substr(pos+5+k*2,1))>>fine(0,k,ant);
1180 0 : istringstream(card.substr(pos+6+k*2,1))>>fine(1,k,ant);
1181 : }
1182 : }
1183 6 : pos=card.find("COARSE=");
1184 6 : if (pos!=String::npos && ant>=0) {
1185 0 : for (Int k=0; k<nIF; k++) {
1186 0 : istringstream(card.substr(pos+7+k*2,1))>>coarse(0,k,ant);
1187 0 : istringstream(card.substr(pos+8+k*2,1))>>coarse(1,k,ant);
1188 : }
1189 : }
1190 6 : pos=card.find("MM=");
1191 6 : if (pos!=String::npos && ant>=0) {
1192 0 : istringstream(card.substr(pos+3,2))>>mmAtt(0,ant);
1193 0 : istringstream(card.substr(pos+6,2))>>mmAtt(1,ant);
1194 : }
1195 : }
1196 6 : break;
1197 6 : case 2: { //SUBREFL
1198 6 : String::size_type pos=card.find("POS=");
1199 6 : if (pos!=String::npos && ant>=0) {
1200 6 : istringstream(card.substr(pos+4,6))>>subrPos(ant);
1201 : }
1202 6 : pos=card.find("TILT=");
1203 6 : if (pos!=String::npos && ant>=0) {
1204 6 : istringstream(card.substr(pos+5,6))>>subrTilt(ant);
1205 : }
1206 : }
1207 6 : break;
1208 1 : case 3: {// CORR_CFG
1209 1 : String::size_type pos=card.find("=");
1210 1 : if (pos!=String::npos) {
1211 1 : config=card.substr(pos+3,80-pos-3).before(trailing);
1212 : }
1213 : }
1214 1 : break;
1215 1 : case 4: {// SCANTYPE
1216 1 : String::size_type pos=card.find("=");
1217 1 : if (pos!=String::npos) {
1218 1 : scanType=card.substr(pos+2,80-pos-3).before(trailing);
1219 : }
1220 2 : if (scanType=="PADDLE"||scanType=="POINT"||scanType=="XPOINT"
1221 2 : ||scanType=="EARLY") {
1222 0 : flagScanType_p=true;
1223 : }
1224 : }
1225 1 : break;
1226 1 : case 5: {// COORDTYP
1227 1 : String::size_type pos=card.find("=");
1228 1 : if (pos!=String::npos) {
1229 1 : coordType=card.substr(pos+2,80-pos-3).before(trailing);
1230 : }
1231 : }
1232 1 : break;
1233 1 : case 6: {// LINEMODE
1234 1 : String::size_type pos=card.find("=");
1235 1 : if (pos!=String::npos) {
1236 1 : lineMode(0)=(card[pos+2]=='T');
1237 1 : if (nIF>1) lineMode(1)=(card[pos+4]=='T');
1238 : }
1239 : }
1240 1 : break;
1241 1 : case 7: {// CACALCNT
1242 1 : String::size_type pos=card.find("=");
1243 1 : if (pos!=String::npos) {
1244 1 : istringstream(card.substr(pos+1,7))>>cacalCnt;
1245 : }
1246 : }
1247 1 : break;
1248 0 : case 8: {// POINTCOR
1249 0 : String::size_type pos=card.find("Az=");
1250 0 : if (pos!=String::npos && ant>=0) {
1251 0 : istringstream(card.substr(pos+3,6))>>pointCorr(0,ant);
1252 0 : newPointingCorr_p=true;
1253 : }
1254 0 : pos=card.find("El=");
1255 0 : if (pos!=String::npos && ant>=0) {
1256 0 : istringstream(card.substr(pos+3,6))>>pointCorr(1,ant);
1257 0 : newPointingCorr_p=true;
1258 : }
1259 : }
1260 0 : break;
1261 0 : case 9: {// POINTINF
1262 0 : pointInfo = card.substr(9).before(trailing);
1263 : }
1264 0 : break;
1265 0 : default:
1266 0 : cerr << "Missing SCAN_INFO card type in switch statement"<<endl;
1267 : }
1268 : //cout <<" Match: cardname = "<<types[j]<<" : "<<card<<endl;
1269 : }
1270 : }
1271 : }
1272 1 : if (!foundAny) return;
1273 1 : Vector<String> tmp;
1274 1 : if (msc_p->observation().log().isDefined(obsId_p)) {
1275 0 : tmp=msc_p->observation().log()(obsId_p);
1276 : }
1277 1 : if (tmp.nelements()==0) tmp.resize(1);
1278 1 : Int index=tmp.nelements()-1;
1279 1 : tmp(index)+=obsLog;
1280 1 : msc_p->observation().log().put(obsId_p,tmp);
1281 1 : if ((nAnt*nIF)==0 || last) return;
1282 :
1283 : // find out spectral window index of IFs
1284 2 : Vector<Int> spwId(nIF,-1);
1285 1 : if (if_no>=0) spwId(if_no)=spWId_p;
1286 1 : if (nIF>1) {
1287 4 : for (Int ifNum=0; ifNum<nIF; ifNum++) {
1288 3 : if (ifNum!=if_no) {
1289 2 : if (selected(ifNum)) spwId(ifNum)=checkSpW(ifNum);
1290 : }
1291 : }
1292 : }
1293 : // reset to original spW
1294 1 : if (if_no>0) checkSpW(if_no);
1295 :
1296 1 : Int row=msScanInfo_p.nrow();
1297 1 : msScanInfo_p.addRow(nAnt*nIF);
1298 1 : colScanInfoScanId.put(row,scanNo_p+1);
1299 1 : colScanInfoCacal.put(row,cacalCnt);
1300 1 : colScanInfoCorrConfig.put(row,config);
1301 1 : colScanInfoScanType.put(row,scanType);
1302 1 : colScanInfoCoordType.put(row,coordType);
1303 1 : colScanInfoPointInfo.put(row,pointInfo);
1304 1 : if (newPointingCorr_p) {
1305 0 : pointingCorr_p.reference(pointCorr);
1306 : } else {
1307 1 : pointingCorr_p.resize(0,0);
1308 : }
1309 :
1310 2 : Vector<Int> f(2),c(2),m(2);
1311 2 : Vector<Float> sr(2);
1312 4 : for (Int i=0; i<nIF; i++) {
1313 3 : colScanInfoSpWId.put(row,spwId(i));
1314 3 : colScanInfoLineMode.put(row,lineMode(i));
1315 21 : for (Int ant=0; ant<nAnt; ant++) {
1316 18 : colScanInfoAntId.put(row,ant);
1317 18 : if (!cabb_p) {
1318 0 : f(0)=fine(0,i,ant); f(1)=fine(1,i,ant);
1319 0 : c(0)=coarse(0,i,ant); c(1)=coarse(1,i,ant);
1320 0 : colScanInfoFine.put(row,f);
1321 0 : colScanInfoCoarse.put(row,c);
1322 : }
1323 18 : m(0)=mmAtt(0,ant); m(1)=mmAtt(1,ant);
1324 18 : colScanInfommAtt.put(row,m);
1325 18 : sr(0)=subrPos(ant)/1000.0; sr(1)=subrTilt(ant)/1000.; // convert to meter
1326 18 : colScanInfoSubreflector.put(row,sr);
1327 18 : row++;
1328 : }
1329 : }
1330 : }
1331 :
1332 6 : String ATCAFiller::atcaPosToStation(Vector<Double>& xyz) {
1333 6 : String station("NONE");
1334 : // determine station from xyz position
1335 : // Use W106 as reference
1336 6 : Double x106 = -4751615.0l;
1337 6 : Double y106 = 2791719.246l;
1338 6 : Double z106 = -3200483.747l;
1339 6 : Double incr = 6000.0l/392;
1340 6 : Bool north = (xyz(2)-z106)>1.0;
1341 6 : Bool east = (xyz(0)-x106)<1.0;
1342 6 : Int n = Int(floor(0.5l+
1343 6 : sqrt((xyz(0)-x106)*(xyz(0)-x106)+
1344 6 : (xyz(1)-y106)*(xyz(1)-y106)+
1345 6 : (xyz(2)-z106)*(xyz(2)-z106))/incr));
1346 6 : Bool invalid = (n>392);
1347 6 : if (!invalid) {
1348 6 : if (north) {
1349 0 : ostringstream ostr; ostr << "N"<<n;
1350 0 : station = ostr.str();
1351 : } else {
1352 6 : if (east) n = 106 -n; else n += 106;
1353 6 : ostringstream ostr; ostr << "W"<<n;
1354 6 : station = ostr.str();
1355 : }
1356 : }
1357 6 : return station;
1358 : }
1359 :
1360 117 : Int ATCAFiller::checkSpW(Int ifNumber,Bool log) {
1361 : // Check if current if_no already in SpW Table
1362 : // Add it if not, set SpWId_p index for our SpW Table
1363 : // NOTE we should use ddId instead of SpWid everywhere, for now
1364 : // we create one SpWId per ddId so they always match, this may result
1365 : // in duplicate spw rows if only the pol info changed..
1366 117 : Regex trailing(" *$"); // trailing blanks
1367 117 : if (if_.if_found) {
1368 117 : spWId_p=-1;
1369 234 : for (Int i=0; i<nSpW_p; i++) {
1370 231 : Double freq = msc_p->spectralWindow().refFrequency()(i);
1371 231 : Double bw = msc_p->spectralWindow().totalBandwidth()(i);
1372 231 : Int nchan = msc_p->spectralWindow().numChan()(i);
1373 231 : Int polId = msc_p->dataDescription().polarizationId()(i);
1374 231 : Int npol = msc_p->polarization().numCorr()(polId);
1375 : // compare freq and bw, cope with case where birdie option has reduced bw
1376 231 : if (doubles_.if_freq[ifNumber]==freq &&
1377 114 : doubles_.if_bw[ifNumber]>=bw && doubles_.if_bw[ifNumber]<2*bw &&
1378 114 : (if_.if_nfreq[ifNumber] == nchan || (nchan<33 &&
1379 0 : if_.if_nfreq[ifNumber]==33)) &&
1380 114 : if_.if_nstok[ifNumber]==npol) {
1381 114 : spWId_p=i;
1382 114 : break;
1383 : }
1384 : }
1385 117 : if (spWId_p<0) { // i.e. not found
1386 3 : spWId_p=nSpW_p++;
1387 3 : atms_p.spectralWindow().addRow();
1388 3 : Int n=atms_p.spectralWindow().nrow()-1;
1389 3 : Double refFreq=doubles_.if_freq[ifNumber];
1390 3 : msc_p->spectralWindow().refFrequency().put(n,refFreq);
1391 : // no doppler tracking
1392 3 : Int nchan = if_.if_nfreq[ifNumber];
1393 3 : Int npol =if_.if_nstok[ifNumber];
1394 :
1395 3 : if (log) os_p << LogIO::NORMAL<<
1396 : "IF "<< ifNumber+1 <<
1397 : " : Frequency = "<< refFreq/1.e6 << " MHz" <<
1398 3 : ", bandwidth = " << doubles_.if_bw[ifNumber]/1.e6 << "MHz" <<
1399 3 : ", #channels = "<< nchan << LogIO::POST;
1400 :
1401 3 : Double refChan=doubles_.if_ref[ifNumber]-1; // make zero based
1402 3 : Double chanSpac = doubles_.if_bw[ifNumber]/max(1,nchan-1);
1403 3 : Int inversion=if_.if_invert[ifNumber];
1404 3 : msc_p->spectralWindow().netSideband().put(n,inversion);
1405 3 : chanSpac*=inversion;
1406 3 : Double chanBW = abs(chanSpac);
1407 3 : if (!cabb_p && nchan==33) chanBW=chanBW*1.6; // roughly
1408 3 : if (!cabb_p && nchan==65) chanBW=chanBW*1.3; // guess
1409 :
1410 : // do birdie check here - reduce number of channels we will store
1411 : // for 33 channel data (drop half the channels + edge) and fix
1412 : // spw description
1413 3 : if (birdie_p && nchan == 33 && !cabb_p) {
1414 0 : Int bchan = birdChan(refFreq/1.e9, (Int)refChan, chanSpac/1.e9);
1415 0 : Int edge = 3 + (bchan+1)%2;
1416 0 : nchan = (nchan - 2*edge + 1)/2;
1417 0 : chanSpac*=2;
1418 0 : refChan = (refChan - edge)/2;
1419 : }
1420 6 : Vector<Double> chanFreq(nchan), resolution(nchan),width(nchan);
1421 4134 : for (Int ichan=0; ichan<nchan; ichan++)
1422 4131 : chanFreq(ichan)=refFreq+(ichan-refChan)*chanSpac;
1423 3 : msc_p->spectralWindow().chanFreq().put(n,chanFreq);
1424 3 : resolution=chanBW;
1425 3 : width=chanSpac;
1426 3 : msc_p->spectralWindow().resolution().put(n,resolution);
1427 3 : msc_p->spectralWindow().chanWidth().put(n, width);
1428 3 : msc_p->spectralWindow().effectiveBW().put(n, resolution);
1429 3 : msc_p->spectralWindow().totalBandwidth().put(n,
1430 3 : (nchan<33 ? abs(nchan*chanSpac) : doubles_.if_bw[ifNumber]));
1431 3 : msc_p->spectralWindow().numChan().put(n,nchan);
1432 :
1433 6 : Vector<Int> corrType(npol);
1434 6 : Matrix<Int> corrProduct(2,npol); corrProduct=0;
1435 3 : if (log) os_p << LogIO::NORMAL << " : Polarizations ";
1436 15 : for (Int i=0; i<npol; i++) {
1437 36 : corrType(i) = Stokes::type
1438 12 : (String(&names_.if_cstok[2*(i+ifNumber*MaxNPol)],2).before(trailing));
1439 : }
1440 6 : Vector<Int> tmp(npol); tmp=corrType;
1441 : // Sort the polarizations to standard order
1442 3 : GenSort<Int>::sort(corrType);
1443 3 : if (corrIndex_p.nrow()==0) {
1444 1 : corrIndex_p.resize(64,4);
1445 : }
1446 3 : if (Int(corrIndex_p.nrow())<=spWId_p) {
1447 0 : corrIndex_p.resize(nSpW_p,4,true);
1448 : }
1449 : // Get the sort indices to rearrange the data to standard order
1450 15 : for (Int i=0;i<npol;i++) {
1451 60 : for (Int j=0;j<npol;j++) {
1452 48 : if (corrType(j)==tmp(i)) corrIndex_p(spWId_p,i)=j;
1453 : }
1454 : }
1455 :
1456 : // Figure out the correlation products from the polarizations
1457 3 : corrProduct.resize(2,npol); corrProduct=0;
1458 15 : for (Int i=0; i<npol; i++) {
1459 12 : Stokes::StokesTypes s=Stokes::type(corrType(i));
1460 24 : Fallible<Int> receptor=Stokes::receptor1(s);
1461 12 : if (receptor.isValid()) corrProduct(0,i)=receptor;
1462 12 : receptor=Stokes::receptor2(s);
1463 12 : if (receptor.isValid()) corrProduct(1,i)=receptor;
1464 12 : if (i>0 && log) os_p << " , ";
1465 12 : if (log) os_p << Stokes::name(s)<< " - " << corrType(i);
1466 : }
1467 3 : if (log) os_p << LogIO::POST;
1468 :
1469 : // try to find matching pol row
1470 3 : Int nPolRow = atms_p.polarization().nrow();
1471 3 : Int polRow = -1;
1472 3 : for (Int i = 0; i< nPolRow; i++) {
1473 2 : if (msc_p->polarization().numCorr()(i)== Int(if_.if_nstok[ifNumber])) {
1474 2 : if (allEQ(msc_p->polarization().corrType()(i),corrType)) {
1475 2 : polRow=i;
1476 2 : break;
1477 : }
1478 : }
1479 : }
1480 : // add new pol id if needed
1481 3 : if (polRow==-1) {
1482 1 : atms_p.polarization().addRow();
1483 1 : polRow = nPolRow;
1484 1 : msc_p->polarization().numCorr().put(polRow,Int(if_.if_nstok[ifNumber]));
1485 1 : msc_p->polarization().corrType().put(polRow,corrType);
1486 1 : msc_p->polarization().corrProduct().put(polRow,corrProduct);
1487 1 : msc_p->polarization().flagRow().put(polRow, false);
1488 : }
1489 3 : atms_p.dataDescription().addRow();
1490 3 : msc_p->dataDescription().spectralWindowId().put(n, spWId_p);
1491 3 : msc_p->dataDescription().polarizationId().put(n, polRow);
1492 3 : msc_p->dataDescription().flagRow().put(n, false);
1493 :
1494 3 : msc_p->spectralWindow().ifConvChain().put(n,Int(if_.if_chain[ifNumber])-1);
1495 3 : if (!cabb_p) colSamplerBits.put(n,Int(if_.if_sampl[ifNumber]));
1496 :
1497 : // set up the TiledStorageManagers
1498 6 : Record values1, values2, values3, values3c;
1499 3 : values1.define("DATA_HYPERCUBE_ID",spWId_p);
1500 3 : values2.define("SIGMA_HYPERCUBE_ID",spWId_p);
1501 3 : values3.define("FLAG_HYPERCUBE_ID",spWId_p);
1502 3 : values3c.define("FLAG_CATEGORY_HYPERCUBE_ID",spWId_p);
1503 :
1504 6 : Record values4; values4.define("MODEL_HYPERCUBE_ID",spWId_p);
1505 6 : Record values5; values5.define("CORRECTED_HYPERCUBE_ID",spWId_p);
1506 : //Record values6; values6.define("IMAGING_WT_HYPERCUBE_ID",spWId_p);
1507 :
1508 3 : Int nChan=msc_p->spectralWindow().numChan()(spWId_p);
1509 3 : Int nCorr=msc_p->polarization().numCorr()(polRow);
1510 3 : Int nCat=3;
1511 :
1512 : // Choose an appropriate tileshape
1513 6 : IPosition dataShape(2,nCorr,nChan);
1514 3 : IPosition tileShape = MSTileLayout::tileShape(dataShape,obsType_p,"ATCA");
1515 3 : dataAccessor_p.addHypercube(IPosition(3,nCorr,nChan,0),
1516 : tileShape,values1);
1517 3 : sigmaAccessor_p.addHypercube(IPosition(2,nCorr,0),
1518 6 : IPosition(2,tileShape(0),tileShape(2)),
1519 : values2);
1520 3 : flagAccessor_p.addHypercube(IPosition(3,nCorr,nChan,0),
1521 : tileShape,values3);
1522 3 : flagCatAccessor_p.addHypercube(IPosition(4,nCorr,nChan,nCat,0),
1523 6 : IPosition(4,tileShape(0),tileShape(1),
1524 3 : 1,tileShape(2)),values3c);
1525 :
1526 : }
1527 : }
1528 234 : return spWId_p;
1529 : }
1530 :
1531 :
1532 1 : void ATCAFiller::checkObservation() {
1533 2 : const Regex trailing(" *$"); // trailing blanks
1534 : // Check if current observer already in OBSERVATION table
1535 2 : String observer;
1536 1 : obsId_p=-1;
1537 1 : for (uInt i=0; i<atms_p.observation().nrow(); i++) {
1538 0 : msc_p->observation().observer().get(i,observer);
1539 0 : if (String(names_.rp_observer,16).before(trailing)==observer) {
1540 0 : obsId_p=i;
1541 0 : break;
1542 : }
1543 : }
1544 1 : if (obsId_p<0) {
1545 : // not found, so add it
1546 1 : atms_p.observation().addRow();
1547 1 : obsId_p=atms_p.observation().nrow()-1;
1548 2 : msc_p->observation().observer().put(obsId_p,
1549 2 : String(names_.rp_observer,16).before(trailing));
1550 : // decode project from rpfits file name..
1551 2 : String project=rpfitsFiles_p(0).after(Regex(".*\\."));
1552 1 : if (project.contains(";")) project=project.before(";");
1553 1 : msc_p->observation().project().put(obsId_p,project);
1554 : }
1555 1 : }
1556 :
1557 77 : void ATCAFiller::checkField() {
1558 : // Check if current source already in Field Table
1559 : // Add it if not, set fieldId_p index for our Field Table
1560 : // For now, we have 1 source per field, we may handle mosaicing differently
1561 : // at some point.
1562 154 : const Regex trailing(" *$"); // trailing blanks
1563 : //0.1 arcsec tolerance for positional coincidence
1564 77 : const Double PosTol=0.1*C::arcsec;
1565 :
1566 77 : if (su_.su_found) {
1567 77 : fieldId_p=-1;
1568 77 : Bool seenSource = false;
1569 : Int numPol;
1570 154 : String name;
1571 154 : String su_name=String(&names_.su_name[sourceno*16],16).before(trailing);
1572 77 : for (Int i=0; i<nField_p; i++) {
1573 76 : msc_p->field().name().get(i,name);
1574 76 : msc_p->field().numPoly().get(i,numPol);
1575 :
1576 76 : if (su_name==name) {
1577 76 : IPosition shape(2, 2, numPol+1);
1578 76 : Matrix<Double> phaseDir(shape);
1579 76 : msc_p->field().phaseDir().get(i,phaseDir);
1580 76 : if (abs(phaseDir(0, 0)-doubles_.su_ra[sourceno])<PosTol) {
1581 76 : if (abs(phaseDir(1, 0)-doubles_.su_dec[sourceno])<PosTol) {
1582 76 : fieldId_p=i; // found it!
1583 : // now check if we've seen this field for this spectral window
1584 152 : Vector<Int> sourceIdCol = msc_p->source().sourceId().getColumn();
1585 152 : Vector<Int> spwIdCol = msc_p->source().spectralWindowId().getColumn();
1586 228 : Vector<Int> spwids = spwIdCol(sourceIdCol==i).getCompressedArray();
1587 76 : seenSource = (spwids.nelements()>0) && anyEQ(spwids,spWId_p);
1588 76 : break;
1589 : }
1590 : }
1591 : }
1592 : }
1593 :
1594 77 : if (fieldId_p<0 || !seenSource) { // i.e. not found, or not at this spwid
1595 6 : String src = String(&names_.su_name[sourceno*16],16);
1596 :
1597 3 : nsources_p++;
1598 3 : sources_p = src;
1599 :
1600 3 : Double epoch=mjd0_p+Double(proper_.pm_epoch);
1601 3 : Int numPol = 0;
1602 3 : if (abs(proper_.pm_ra)+abs(proper_.pm_dec) > 0) {
1603 0 : numPol = 1;
1604 : }
1605 6 : IPosition shape(2, 2, numPol+1);
1606 6 : Matrix<Double> dir(shape);
1607 : // convert proper motions from s & " per year to rad/s
1608 3 : const Double arcsecPerYear=C::arcsec/(365.25*C::day);
1609 3 : dir(0, 0)=doubles_.su_ra[sourceno];
1610 3 : dir(1, 0)=doubles_.su_dec[sourceno];
1611 3 : if (numPol>0) {
1612 0 : dir(0, 1)=proper_.pm_ra*15.*arcsecPerYear; // (15"/s)
1613 0 : dir(1, 1)=proper_.pm_dec*arcsecPerYear;
1614 : }
1615 :
1616 3 : if (fieldId_p<0) {
1617 1 : os_p << LogIO::DEBUGGING << "Found field:" << src << LogIO::POST;
1618 1 : if (numPol>0) os_p << LogIO::DEBUGGING << "Field:" << src << " has proper motion parameters"<<LogIO::POST;
1619 1 : fieldId_p=nField_p++;
1620 1 : atms_p.field().addRow();
1621 1 : Int nf=atms_p.field().nrow()-1;
1622 : // for now we have 1 field/source
1623 1 : msc_p->field().sourceId().put(nf,fieldId_p);
1624 1 : msc_p->field().name().put(nf,src.before(trailing));
1625 :
1626 1 : msc_p->field().phaseDir().put(nf,dir);
1627 1 : msc_p->field().delayDir().put(nf,dir);
1628 1 : msc_p->field().referenceDir().put(nf, dir);
1629 1 : msc_p->field().numPoly().put(nf, numPol);
1630 1 : msc_p->field().time().put(nf,epoch);
1631 3 : msc_p->field().code().put(nf,String(&names_.su_cal[sourceno*16],
1632 2 : 16).before(trailing));
1633 : }
1634 3 : dir(0, 0)=doubles_.su_pra[sourceno];
1635 3 : dir(1, 0)=doubles_.su_pdec[sourceno];
1636 6 : Vector<Double> srcdir(2);
1637 3 : srcdir(0)=doubles_.su_ra[sourceno];
1638 3 : srcdir(1)=doubles_.su_dec[sourceno];
1639 3 : atms_p.source().addRow();
1640 3 : Int ns=atms_p.source().nrow()-1;
1641 3 : msc_p->source().sourceId().put(ns,fieldId_p);
1642 3 : msc_p->source().name().put(ns,src.before(trailing));
1643 3 : msc_p->source().direction().put(ns,srcdir);
1644 6 : Vector<Double> rate(2);
1645 3 : rate(0)=proper_.pm_ra*15.*arcsecPerYear; // (15"/s)
1646 3 : rate(1)=proper_.pm_dec*arcsecPerYear;
1647 3 : msc_p->source().properMotion().put(ns,rate);
1648 3 : msc_p->source().time().put(ns,epoch);
1649 3 : msc_p->source().interval().put(ns,DBL_MAX);
1650 : // assume source is at infinity, specify as zero
1651 : //Vector<Double> pos(3); pos=0.;
1652 : //msc_p->source().position().put(ns,pos);
1653 :
1654 : //suRow["VelRefFrame"].put(Int(spect_.ivelref));
1655 : // need to specify reference frame for velocity as well
1656 : // vel1 may be velocity at channel 1 instead of ref freq..
1657 :
1658 3 : msc_p->source().spectralWindowId().put(ns,spWId_p);
1659 6 : Vector<Double> sysv(1),restFreq(1);
1660 3 : Vector<String> transition(1);
1661 3 : sysv = Double(doubles_.vel1);
1662 3 : msc_p->source().sysvel().put(ns, sysv);
1663 3 : msc_p->source().numLines().put(ns,1);
1664 3 : restFreq(0) = Double(doubles_.rfreq);
1665 3 : if (restFreq(0)<1.0) {
1666 : // fill in an appropriate default
1667 3 : Double freq = msc_p->spectralWindow().refFrequency()(spWId_p);
1668 3 : Double bw = msc_p->spectralWindow().totalBandwidth()(spWId_p);
1669 3 : if ( freq>1200.e6 && freq< 1450.e6 && bw <64.e6) {
1670 0 : restFreq(0)= 1420.4e6;
1671 0 : transition(0)="HI";
1672 : } else {
1673 3 : restFreq(0) = freq;
1674 3 : transition(0) = "";
1675 : }
1676 : }
1677 3 : msc_p->source().transition().put(ns,transition);
1678 3 : msc_p->source().restFrequency().put(ns,restFreq);
1679 :
1680 : // dummy fill
1681 3 : msc_p->source().calibrationGroup().put(ns,-1);
1682 : }
1683 :
1684 77 : Bool fillPointingTable=False; //Imaging fails with pointing table filled
1685 77 : if (fillPointingTable &&
1686 0 : (fieldId_p != prev_fieldId_p || newPointingCorr_p)) {
1687 0 : prev_fieldId_p = fieldId_p;
1688 0 : Double epoch=mjd0_p+Double(proper_.pm_epoch);
1689 0 : Int np=atms_p.pointing().nrow();
1690 0 : IPosition shape(2, 2, 1);
1691 0 : Matrix<Double> pointingDir(shape,0.0);
1692 0 : pointingDir(0, 0)=doubles_.su_pra[sourceno];
1693 0 : pointingDir(1, 0)=doubles_.su_pdec[sourceno];
1694 0 : Matrix<Double> pointingOffset(shape,0.0);
1695 0 : for (Int i=0; i<nAnt_p; i++) {
1696 0 : atms_p.pointing().addRow();
1697 0 : msc_p->pointing().antennaId().put(np+i, i+1);
1698 0 : if (newPointingCorr_p) {
1699 0 : pointingOffset(0, 0)=pointingCorr_p(0,i)*C::arcsec;
1700 0 : pointingOffset(1, 0)=pointingCorr_p(0,i)*C::arcsec;
1701 : }
1702 0 : if (i==0) { // ISM storage
1703 0 : msc_p->pointing().time().put(np,epoch);
1704 0 : msc_p->pointing().interval().put(np,DBL_MAX);
1705 0 : msc_p->pointing().numPoly().put(np, 0);
1706 0 : msc_p->pointing().direction().put(np,pointingDir);
1707 0 : msc_p->pointing().pointingOffset().put(np,pointingOffset);
1708 0 : msc_p->pointing().tracking().put(np,True);
1709 : } else {
1710 0 : if (newPointingCorr_p) {
1711 0 : msc_p->pointing().pointingOffset().put(np,pointingOffset);
1712 : }
1713 : }
1714 : }
1715 : }
1716 : }
1717 77 : }
1718 :
1719 :
1720 57 : void ATCAFiller::storeSysCal()
1721 : {
1722 : // Conversion factor for atmospheric pressure
1723 114 : Vector<String> const pressure_unit = msc_p->weather().pressure().keywordSet().asArrayString("QuantumUnits");
1724 57 : auto const pressure_conversion = Quantum<Double>(1.0, Unit("mbar")).getValue(Unit(pressure_unit[0]));
1725 :
1726 : // RPFITS SysCal table layout:
1727 : // sc_.sc_ant = 7 (1-6 is antenna 1-6 syscal data, 7th has ant=0 weather data)
1728 : // sc_cal(q,if,ant) (in practice sc_.sc_if is always 1 since ~1999)
1729 : // q=0 : ant
1730 : // 1 : if
1731 : // 2 : XYPhase (deg)
1732 : // 3 : tsysX (sqrt(tsys*10))
1733 : // 4 : tsysY
1734 : // 5-7: samp-stats X
1735 : // 8-10:samp-stats Y
1736 : // 11 : Parallactic Angle (deg)
1737 : // 12 : Flag
1738 : // 13 : XYAmp (Jy)
1739 : // 15: Tracking error Max (arcsec)
1740 : // 16: Tracking error RMS (arcsec)
1741 57 : Int last_if_no=-2; // if_no can come out to be -1 if syscal rec is blank
1742 57 : Bool skip=false;
1743 57 : sourceno=sc_.sc_srcno-1; // 0-based source number for this syscal record
1744 57 : Int scq=sc_.sc_q, scif=sc_.sc_if;
1745 114 : for (Int i=0; i<scif; i++) {
1746 456 : for (Int ant=0; ant<sc_.sc_ant; ant++) {
1747 399 : if (Int(sc_.sc_cal[scq*(i+scif*ant)+0])==0) {
1748 : // special syscal record with antenna==0
1749 : // field 7-12 contain weather data
1750 57 : if (sc_.sc_ut!=lastWeatherUT_p) {
1751 19 : lastWeatherUT_p = sc_.sc_ut;
1752 19 : Int nAnt = max(1,sc_.sc_ant-1);
1753 19 : Int row=atms_p.weather().nrow();
1754 19 : atms_p.weather().addRow(nAnt);
1755 19 : Double time=mjd0_p+Double(sc_.sc_ut);
1756 133 : for (Int iAnt=0; iAnt<nAnt; iAnt++,row++) {
1757 114 : msc_p->weather().antennaId().put(row,iAnt);
1758 114 : msc_p->weather().time().put(row,time);
1759 114 : msc_p->weather().interval().put(row,Double(param_.intbase));
1760 114 : msc_p->weather().temperature().put(row,
1761 114 : Double(sc_.sc_cal[scq*(i+scif*ant)+1])+273.15); // C to K
1762 114 : msc_p->weather().pressure().put(row,
1763 114 : Double(sc_.sc_cal[scq*(i+scif*ant)+2])*pressure_conversion); // mBar to Pa/hPa
1764 114 : msc_p->weather().relHumidity().put(row,
1765 114 : Double(sc_.sc_cal[scq*(i+scif*ant)+3]));
1766 114 : msc_p->weather().windSpeed().put(row,
1767 114 : Double(sc_.sc_cal[scq*(i+scif*ant)+4])/3.6); // km/s to m/s
1768 114 : msc_p->weather().windDirection().put(row,
1769 114 : Double(sc_.sc_cal[scq*(i+scif*ant)+5])*C::pi/180.0); // deg to rad
1770 114 : msc_p->weather().temperatureFlag().put(row, Bool(sc_.sc_cal[scq*(i+scif*ant)+6]));
1771 114 : msc_p->weather().pressureFlag().put(row, Bool(sc_.sc_cal[scq*(i+scif*ant)+6]));
1772 114 : msc_p->weather().relHumidityFlag().put(row, Bool(sc_.sc_cal[scq*(i+scif*ant)+6]));
1773 114 : msc_p->weather().windSpeedFlag().put(row, Bool(sc_.sc_cal[scq*(i+scif*ant)+6]));
1774 114 : msc_p->weather().windDirectionFlag().put(row,Bool(sc_.sc_cal[scq*(i+scif*ant)+6]));
1775 114 : colWeatherRainGauge.put(row, Float(sc_.sc_cal[scq*(i+scif*ant)+7]));
1776 114 : colWeatherSeeMonPhase.put(row, Float(sc_.sc_cal[scq*(i+scif*ant)+8]));
1777 114 : colWeatherSeeMonRMS.put(row, Float(sc_.sc_cal[scq*(i+scif*ant)+9])/1000);
1778 114 : colWeatherSeeMonFlag.put(row, Bool(sc_.sc_cal[scq*(i+scif*ant)+10]));
1779 : }
1780 : }
1781 57 : continue;
1782 : }
1783 342 : if_no=Int(sc_.sc_cal[scq*(i+scif*ant)+1])-1; // make 0-based
1784 342 : if (if_no!=last_if_no) { // check if we want this one
1785 57 : last_if_no=if_no;
1786 57 : skip=Bool(if_no<0 || if_no>=if_.n_if || !selected(if_no));
1787 57 : if (!skip) {
1788 57 : checkSpW(if_no); // sets spWId_p corresponding to this if_no
1789 57 : checkField(); // sets fieldId_p
1790 : }
1791 : }
1792 342 : if (!skip) {
1793 342 : atms_p.sysCal().addRow();
1794 342 : Int n=atms_p.sysCal().nrow()-1;
1795 342 : Double time=mjd0_p+Double(sc_.sc_ut);
1796 342 : msc_p->sysCal().time().put(n,time);
1797 342 : msc_p->sysCal().antennaId()
1798 342 : .put(n,Int(sc_.sc_cal[scq*(i+scif*ant)+0]-1)); // make 0-based
1799 342 : msc_p->sysCal().feedId().put(n,0);
1800 342 : msc_p->sysCal().interval().put(n,Double(param_.intbase));
1801 342 : msc_p->sysCal().spectralWindowId().put(n,spWId_p);
1802 :
1803 342 : msc_p->sysCal().phaseDiff().put(n,sc_.sc_cal[scq*(i+scif*ant)+2]);
1804 :
1805 684 : Vector<Float> tSys(2);
1806 : // convert from sqrt(tsys*10) to true tsys
1807 342 : tSys(0)=square(sc_.sc_cal[scq*(i+scif*ant)+3])/10.;
1808 342 : tSys(1)=square(sc_.sc_cal[scq*(i+scif*ant)+4])/10.;
1809 :
1810 342 : msc_p->sysCal().tsys().put(n,tSys);
1811 :
1812 684 : Vector<Float> a(2),b(2),c(2);
1813 1026 : for (Int j=0; j<2; j++) {
1814 684 : a(j)=sc_.sc_cal[scq*(i+scif*ant)+5+j*3];
1815 684 : b(j)=sc_.sc_cal[scq*(i+scif*ant)+6+j*3];
1816 684 : c(j)=sc_.sc_cal[scq*(i+scif*ant)+7+j*3];
1817 : }
1818 342 : if (cabb_p) {
1819 342 : colGTP.put(n,a);
1820 342 : colSDO.put(n,b);
1821 342 : colCalJy.put(n,c);
1822 : } else {
1823 0 : colSamplerStatsNeg.put(n,a);
1824 0 : colSamplerStatsZero.put(n,b);
1825 0 : colSamplerStatsPos.put(n,c);
1826 : }
1827 : //cParAngle.put(n,sc_.sc_cal[scq*(i+scif*ant)+11]);
1828 342 : msc_p->sysCal().phaseDiffFlag().
1829 342 : put(n,(sc_.sc_cal[scq*(i+scif*ant)+12]!=0));
1830 342 : msc_p->sysCal().tsysFlag().
1831 342 : put(n,(sc_.sc_cal[scq*(i+scif*ant)+12]!=0));
1832 342 : colXYAmplitude.put(n,sc_.sc_cal[scq*(i+scif*ant)+13]);
1833 342 : msc_p->sysCal().tcalFlag().put(n,true);
1834 342 : msc_p->sysCal().trxFlag().put(n,true);
1835 342 : colTrackErrMax.put(n,Float(sc_.sc_cal[scq*(i+scif*ant)+14]));
1836 342 : colTrackErrRMS.put(n,Float(sc_.sc_cal[scq*(i+scif*ant)+15]));
1837 : }
1838 : }
1839 : }
1840 57 : }
1841 :
1842 :
1843 0 : void ATCAFiller::reweight()
1844 : {
1845 0 : Int npol =if_.if_nstok[if_no];
1846 0 : Int nfreq=33;
1847 0 : Int n=2*nfreq-2;
1848 0 : FFTServer<Float, Complex> server;
1849 :
1850 0 : Vector<Complex> cscr(33);
1851 0 : Vector<Float> rscr(64);
1852 :
1853 : static Float wts[64]={ 1.000000,
1854 : 1.028847, 1.0526778, 1.0711329, 1.083963, 1.0909837, 1.0921189,
1855 : 1.0873495, 1.0767593, 1.0605253, 1.0389025, 1.0122122,
1856 : 0.9808576, 0.9453095, 0.9060848, 0.8637353, 0.8188493,
1857 : 0.7720414, 0.7239398, 0.6751758, 0.6263670, 0.5781130,
1858 : 0.5310048, 0.4856412, 0.4426092, 0.4025391, 0.3661798,
1859 : 0.3346139, 0.3096083, 0.2951138, 0.3024814, 0.6209788, 1.000000,
1860 : 0.6209788, 0.3024814, 0.2951138, 0.3096083, 0.3346139,
1861 : 0.3661798, 0.4025391, 0.4426092, 0.4856412, 0.5310048,
1862 : 0.5781130, 0.6263670, 0.6751758, 0.7239398, 0.7720414,
1863 : 0.8188493, 0.8637353, 0.9060848, 0.9453095, 0.9808576,
1864 : 1.0122122, 1.0389025, 1.0605253, 1.0767593, 1.0873495, 1.0921189,
1865 : 1.0909837, 1.083963, 1.0711329, 1.0526778, 1.028847 };
1866 :
1867 0 : for (Int p=0; p<npol; p++) {
1868 0 : for (Int i=0; i<nfreq; i++)
1869 0 : cscr(i) = Complex(vis[0+2*(p+i*npol)],vis[1+2*(p+i*npol)]);
1870 0 : server.fft0(rscr, cscr);
1871 0 : for (Int i=0; i<n; i++) rscr(i) = rscr(i)*wts[i];
1872 0 : server.fft0(cscr, rscr);
1873 0 : for (Int i=0; i<nfreq; i++) {
1874 0 : vis[0+2*(p+i*npol)] = real(cscr(i));
1875 0 : vis[1+2*(p+i*npol)] = imag(cscr(i));
1876 : }
1877 : }
1878 0 : }
1879 :
1880 0 : Int ATCAFiller::birdChan(Double refFreq, Int refChan, Double chanSpac)
1881 : {
1882 0 : Double flo = 0.128* myround(refFreq/0.128);
1883 0 : Int chan = refChan + myround((flo - refFreq)/chanSpac);
1884 0 : if(chan <= 0) {
1885 : // os_p << LogIO::NORMAL << "CHAN " << chan << " ";
1886 0 : chan = chan + myround(0.128/fabs(chanSpac));
1887 : }
1888 : //os_p << LogIO::NORMAL << "birdie channel = " << chan << " refFreq="<<refFreq << " flo="<<flo <<"\n";
1889 0 : return chan;
1890 : }
1891 :
1892 855 : void ATCAFiller::storeData()
1893 : {
1894 855 : const double MJD01Jul2004 = 2453187.5; // 12mm receiver xy inversion end
1895 855 : const double MJD18Oct2007 = 2454390.5; // 3mm CA02 xyphase valid
1896 :
1897 855 : atms_p.addRow();
1898 :
1899 1710 : const RecordFieldId rfid1("DATA_HYPERCUBE_ID");
1900 1710 : const RecordFieldId rfid2("SIGMA_HYPERCUBE_ID");
1901 1710 : const RecordFieldId rfid3("FLAG_HYPERCUBE_ID");
1902 1710 : const RecordFieldId rfid3c("FLAG_CATEGORY_HYPERCUBE_ID");
1903 1710 : Record values1, values2, values3, values3c;
1904 855 : values1.define(rfid1,spWId_p);
1905 855 : values2.define(rfid2,spWId_p);
1906 855 : values3.define(rfid3,spWId_p);
1907 855 : values3c.define(rfid3c,spWId_p);
1908 :
1909 855 : dataAccessor_p.extendHypercube(1,values1);
1910 855 : sigmaAccessor_p.extendHypercube(1,values2);
1911 855 : flagAccessor_p.extendHypercube(1,values3);
1912 855 : flagCatAccessor_p.extendHypercube(1,values3c);
1913 :
1914 1710 : Record values4, values5, values6;
1915 :
1916 855 : Int n=atms_p.nrow()-1;
1917 855 : if (n==0) gotSysCalId_p=false;
1918 :
1919 855 : Int npol =if_.if_nstok[if_no];
1920 855 : Int nfreq=if_.if_nfreq[if_no];
1921 1710 : Regex trailing(" *$"); // trailing blanks
1922 1710 : String instrument = String(names_.instrument,16).before(trailing);
1923 855 : Bool atca = (instrument=="ATCA");
1924 855 : Bool atlba = (instrument=="ATLBA");
1925 :
1926 : // fill in the easy items
1927 : // make antenna numbers 0-based
1928 855 : Int ant1=Int(baseline)/256-1, ant2=Int(baseline)%256-1;
1929 855 : msc_p->antenna1().put(n,ant1);
1930 855 : msc_p->antenna2().put(n,ant2);
1931 855 : Bool flagData=flg;
1932 855 : if (flagData) { flagCount_p(ONLINE)++;}
1933 855 : if (autoFlag_p && flagScanType_p) { flagData=true; flagCount_p(SCANTYPE)++;}
1934 855 : Double exposure=Double(param_.intbase);
1935 : // averaging = number of integration periods averaged by correlator: 1,2 or 3
1936 855 : Int averaging = 1;
1937 855 : if (param_.intime>0) averaging = Int(exposure/param_.intime)+1;
1938 855 : Double interval = averaging*Double(param_.intime);
1939 : // check for old data with intbase set to zero
1940 855 : Double blank=51.e-3; // standard 51 ms blank time at end of integration
1941 855 : if (exposure<0.001) exposure = interval-blank;
1942 855 : if (interval==0.0) interval = exposure;
1943 :
1944 : // Is binning mode active?
1945 855 : Int nBin = Int(floor(param_.intime/exposure+0.01));
1946 855 : if (nBin<4) nBin=1; // short exposure due to long hold period..
1947 855 : msc_p->dataDescId().put(n, spWId_p);
1948 855 : if (ut!=lastUT_p) { // the ISM columns that don't change within integration
1949 19 : msc_p->arrayId().put(n,0);
1950 19 : msc_p->exposure().put(n,exposure);
1951 19 : msc_p->feed1().put(n,0);
1952 19 : msc_p->feed2().put(n,0);
1953 19 : msc_p->fieldId().put(n,fieldId_p);
1954 19 : msc_p->interval().put(n,interval);
1955 19 : msc_p->observationId().put(n,obsId_p);
1956 19 : msc_p->processorId().put(n,-1);
1957 19 : msc_p->scanNumber().put(n,scanNo_p);
1958 19 : msc_p->stateId().put(n,-1);
1959 19 : Double mjd=mjd0_p+ut;
1960 : // try to figure out what the midpoint of the integration interval was
1961 19 : if (nBin>1 || !atca) {
1962 19 : msc_p->time().put(n,mjd);
1963 : } else {
1964 0 : msc_p->time().put(n,floor((mjd+exposure/2+blank*(averaging+1)/2
1965 0 : -interval/2)*1000+0.5)/1000);
1966 : }
1967 : // time centroid is the centroid of the exposure window
1968 : // it is the time used for the uvw & phase calculation
1969 : // [note that cacor corrects uvw for change in centroid from caobs value
1970 : // due to blank, hold and averaging, but not binning]
1971 19 : msc_p->timeCentroid().put(n,mjd);
1972 : }
1973 855 : Int pulsarBin = max(0,bin-1);// make zero-based (but catch unset value)
1974 855 : msc_p->pulsarBin().put(n,pulsarBin);
1975 855 : if (hires_p && nBin>1) {
1976 : // in hires mode we adjust timeCentroid to match the bin centers, but
1977 : // uvw's still refer to center of interval (now given by time column)
1978 : // Time column will still be in time order, but TimeCentroid is not.
1979 0 : Double midTime = msc_p->time()(n);
1980 0 : msc_p->timeCentroid().put(n,midTime+(pulsarBin-nBin/2+0.5)*exposure/averaging);
1981 : }
1982 1710 : Vector<Double> uvw(3); uvw(0)=u; uvw(1)=v; uvw(2)=w;
1983 855 : msc_p->uvw().put(n,uvw);
1984 :
1985 : // use exposure time as weight
1986 1710 : Vector<Float> Weight(npol); Weight=exposure;
1987 855 : msc_p->weight().put(n,Weight);
1988 : //# Vector<Float> weightSpectrum(nfreq); weightSpectrum=exposure;
1989 : //# msc_p->weightSpectrum().put(n,weightSpectrum);
1990 :
1991 : // Find the indices into the sysCal table for this row
1992 855 : if (!gotSysCalId_p || ut!=lastUT_p || spWId_p!=lastSpWId_p) {
1993 855 : lastUT_p=ut;
1994 855 : lastSpWId_p=spWId_p;
1995 : // we need to get the new syscal info
1996 : // search backwards from last syscal row
1997 855 : Bool done=false;
1998 855 : Int nsc=atms_p.sysCal().nrow();
1999 : //# os_p << LogIO::NORMAL << " Current number of syscal rows="<<nsc<<LogIO::POST;
2000 855 : sysCalId_p.resize(nAnt_p); sysCalId_p=-1;
2001 : // search backwards, as it should be a recent entry
2002 5985 : for (Int i=nsc-1; (i>=0 && !done); i--) {
2003 10260 : if (nearAbs(msc_p->sysCal().time()(i),mjd0_p+ut,0.5) &&
2004 5130 : msc_p->sysCal().spectralWindowId()(i)==spWId_p) {
2005 5130 : Int ant=msc_p->sysCal().antennaId()(i);
2006 5130 : if (ant>=0 && ant<nAnt_p) { //valid antenna
2007 5130 : sysCalId_p(ant)=i;
2008 5130 : done=(!(anyEQ(sysCalId_p,-1)));
2009 : }
2010 : }
2011 : }
2012 855 : if (!done && atca) {
2013 0 : errCount_p++;
2014 0 : if (errCount_p<3) os_p << LogIO::WARN <<"Warning: some syscal info is missing"<< LogIO::POST;
2015 : }
2016 : }
2017 : // set a sysCalId in the main table to point to
2018 : // the sysCal subtable row - missing points get a -1
2019 855 : colSysCalIdAnt1.put(n,sysCalId_p(ant1));
2020 855 : colSysCalIdAnt2.put(n,sysCalId_p(ant2));
2021 :
2022 : // Check for bad sampler stats now that we've found the syscal data
2023 855 : if (!flagData && autoFlag_p && (!atlba && !cabb_p && samplerFlag(n))) {
2024 0 : flagData=true; flagCount_p(SYSCAL)++;
2025 : }
2026 855 : flagCount_p(COUNT)++;
2027 855 : if (flagData) flagCount_p(FLAG)++;
2028 855 : msc_p->flagRow().put(n,flagData);
2029 :
2030 :
2031 : // flags and data
2032 855 : const Int nCat = 3; // three initial categories
2033 : // define the categories
2034 1710 : Vector<String> cat(nCat);
2035 855 : cat(0)="FLAG_CMD";
2036 855 : cat(1)="ORIGINAL";
2037 855 : cat(2)="USER";
2038 855 : msc_p->flagCategory().rwKeywordSet().define("CATEGORY",cat);
2039 :
2040 : // Gibbs reweighting
2041 855 : if (nfreq == 33) {
2042 285 : if (reweight_p) reweight();
2043 : }
2044 :
2045 : // do birdie check here - reduce number of channels we will store
2046 : // for 33 channel data (drop half the channels + edge)
2047 855 : Double refFreq=doubles_.if_freq[if_no];
2048 855 : Double refChan=doubles_.if_ref[if_no]-1; // make zero based
2049 855 : Double chanSpac = doubles_.if_bw[if_no]/max(1,nfreq-1);
2050 855 : Int inversion=if_.if_invert[if_no];
2051 855 : chanSpac*=inversion;
2052 855 : Int bchan = -1;
2053 855 : Int edge = 0;
2054 855 : if (birdie_p && atca) {
2055 0 : bchan = birdChan(refFreq/1.e9, (Int)refChan, chanSpac/1.e9);
2056 0 : if (nfreq == 33) { // ATCA continuum mode - flag edge + every other channel
2057 0 : edge = 3 + (bchan+1)%2;
2058 0 : nfreq = (nfreq - 2*edge + 1)/2;
2059 0 : chanSpac*=2;
2060 0 : refChan = (refChan - edge)/2;
2061 0 : bchan = (bchan -edge)/2;
2062 : }
2063 : }
2064 855 : Bool band12mm = (refFreq>13.e9 && refFreq<28.e9);
2065 855 : Bool band3mm = (refFreq>75.e9);
2066 :
2067 1710 : Matrix<Complex> VIS(npol,nfreq);
2068 1710 : Cube<Bool> flagCat(npol,nfreq,nCat,false);
2069 1710 : Matrix<Bool> flags= flagCat.xyPlane(1); // references flagCat's storage
2070 :
2071 :
2072 855 : if (birdie_p) {
2073 0 : if (bchan >= 0 && bchan < nfreq) {
2074 0 : for (Int i=0; i<npol; i++) {
2075 0 : flags(i, bchan) = true;
2076 : }
2077 : }
2078 : }
2079 :
2080 : // Some corrections as specified by Bob Sault(2000/09/07):
2081 : //Conjugate all data if the IF_INVERT switch is negative
2082 : //Negate the XY and YX correlations (both real and imag parts) for all
2083 : // except 12mm observations.
2084 : //The xyphase measurement should also be multiplied by the IF_INVERT switch
2085 : //sign. The xyphase measurement is the phase of a correlation. So to
2086 : //correct the data with the xyphase measurement, you will want to multiply
2087 : //by gains whose phase has the opposite sign to the measurements.
2088 : //Note any Gibbs reweighting needs to be done before any xyphase correction
2089 : //is done.
2090 :
2091 :
2092 : // correct for inversion - conjugate data; skip birdie channels
2093 : // resort pols
2094 1178190 : for (Int j=0; j<nfreq; j++) {
2095 1177335 : Int k = (edge>0 ? (2*j+edge) : j);
2096 5886675 : for (Int i=0; i<npol; i++) {
2097 4709340 : Int ipol = corrIndex_p(spWId_p,i);
2098 4709340 : VIS(ipol,j)=Complex(vis[0+2*(i+k*npol)],inversion*vis[1+2*(i+k*npol)]);
2099 : }
2100 : }
2101 : // Flag NaNs
2102 2565 : Matrix<Bool> nanFlags = isNaN(real(VIS));
2103 855 : nanFlags |= isNaN(imag(VIS));
2104 855 : flags |= nanFlags;
2105 :
2106 : // Flag CABB birdies and RFI
2107 855 : if (cabb_p) rfiFlag(flags);
2108 :
2109 : // correct for xy phase - multiply y correlation with opposite of xyphase
2110 855 : Int id1 = sysCalId_p(ant1);
2111 855 : Complex gain1 = (id1!=-1 && !msc_p->sysCal().phaseDiffFlag()(id1) ?
2112 540 : exp(Complex(0,1)*msc_p->sysCal().phaseDiff()(id1)*inversion):
2113 855 : Complex(1,0));
2114 : // negate xyphase for second antenna since the correlation product uses conjugate for ant2
2115 855 : Int id2 = sysCalId_p(ant2);
2116 855 : Complex gain2 = (id2!=-1 && !msc_p->sysCal().phaseDiffFlag()(id2) ?
2117 540 : exp(-Complex(0,1)*msc_p->sysCal().phaseDiff()(id2)*inversion):
2118 855 : Complex(1,0));
2119 855 : Int polId = msc_p->dataDescription().polarizationId()(spWId_p);
2120 1710 : Vector<Int> corrType = msc_p->polarization().corrType()(polId);
2121 : // 3mm receiver on CA02 got valid xyphase on 18Oct2007
2122 855 : if (noxycorr_p || (band3mm && mjd0_p<MJD18Oct2007)) { gain1=gain2=1; }
2123 855 : if (band3mm && mjd0_p>=MJD18Oct2007) {
2124 0 : if (ant1!=1) gain1 = 1;
2125 0 : if (ant2!=1) gain2 = 1;
2126 : }
2127 : // "-" because XY and YX corr need to be negated, except for 12mm until 2004
2128 855 : if (!band12mm || mjd0_p>MJD01Jul2004) { gain1=-gain1; gain2=-gain2;}
2129 4275 : for (Int i=0; i<npol; i++) {
2130 3420 : switch (corrType(i)) {
2131 855 : case Stokes::XX :
2132 855 : break;
2133 855 : case Stokes::XY :
2134 : {
2135 1710 : Vector<Complex> tmp(VIS.row(i));
2136 855 : tmp*=gain2;
2137 : }
2138 855 : break;
2139 855 : case Stokes::YX :
2140 : {
2141 1710 : Vector<Complex> tmp(VIS.row(i));
2142 855 : tmp*=gain1;
2143 : }
2144 855 : break;
2145 855 : case Stokes::YY :
2146 : {
2147 855 : Vector<Complex> tmp(VIS.row(i));
2148 855 : tmp*=(gain1*gain2);
2149 : }
2150 855 : break;
2151 0 : default:
2152 0 : break;
2153 : }
2154 : }
2155 :
2156 855 : msc_p->data().put(n,VIS);
2157 : // CASA wants all flags set if flagRow is set
2158 855 : if (flagData) flags=flagData;
2159 855 : msc_p->flag().put(n,flags);
2160 855 : msc_p->flagCategory().put(n,flagCat);
2161 :
2162 : // now calculate the sigma for this row
2163 : //
2164 1710 : Vector<Double> chnbw;
2165 855 : msc_p->spectralWindow().resolution().get(spWId_p,chnbw);
2166 1710 : Vector<Float> tsys1,tsys2;
2167 : //# os_p << LogIO::NORMAL << "Looking up syscal info at rows: "<<sysCalId_p(ant1)<<" and "<<
2168 : //# sysCalId_p(ant2)<< LogIO::POST;
2169 :
2170 855 : if (sysCalId_p(ant1)!=-1 && !msc_p->sysCal().tsysFlag()(sysCalId_p(ant1)))
2171 540 : msc_p->sysCal().tsys().get(sysCalId_p(ant1),tsys1);
2172 315 : else { tsys1.resize(nAnt_p); tsys1=50.;}
2173 855 : if (sysCalId_p(ant2)!=-1 && !msc_p->sysCal().tsysFlag()(sysCalId_p(ant2)))
2174 540 : msc_p->sysCal().tsys().get(sysCalId_p(ant2),tsys2);
2175 315 : else { tsys2.resize(nAnt_p); tsys2=50.;}
2176 1710 : Vector<Float> sigma(npol); sigma=0.;
2177 1710 : Matrix<Int> corrProduct(2,npol);
2178 855 : msc_p->polarization().corrProduct().get(polId,corrProduct);
2179 :
2180 : // sigma=sqrt(Tx1*Tx2)/sqrt(chnbw*intTime)*JyPerK;
2181 855 : Float JyPerK=13.; // guess for ATCA dishes at 3-20cm
2182 855 : Float factor=sqrt(chnbw(0)*exposure)/JyPerK;
2183 4275 : for (Int pol=0; pol<npol; pol++) {
2184 3420 : Float tsysAv=tsys1(corrProduct(0,pol))*tsys2(corrProduct(1,pol));
2185 3420 : if (tsysAv>=0 && factor>0 ) sigma(pol)=sqrt(tsysAv)/factor;
2186 : }
2187 855 : msc_p->sigma().put(n,sigma);
2188 :
2189 : // determine shadowing & flag data with shadowed antennas
2190 855 : if (shadow_p>0) shadow(n);
2191 :
2192 855 : }
2193 :
2194 855 : void ATCAFiller::rfiFlag(Matrix<Bool> & flags) {
2195 : // CABB birdies
2196 : // 1 MHz mode
2197 855 : const int nb1=11;
2198 : static const int b1[nb1] = {640,256,768,1408,1280,1920,1792,1176,156,128,1152};
2199 : // 64 MHz mode
2200 855 : const int nb2=3;
2201 : static const int b2[nb2] = {8,16,24};
2202 :
2203 : // Get details of spectrum
2204 855 : Int nfreq=if_.if_nfreq[if_no];
2205 855 : Double bw=doubles_.if_bw[if_no];
2206 855 : Int chn=0;
2207 : // Flag birdies and edge channels
2208 855 : if (bw>2.e9) {
2209 570 : chn = nfreq*edge_p/200;
2210 570 : if (nfreq==2049) {
2211 : // CABB 2049 chan * 1 MHz continuum mode
2212 3420 : for (Int i=0; i<nb1; i++) {
2213 3135 : flags.column(b1[i])=true;
2214 : }
2215 285 : } else if (nfreq==33) {
2216 : // CABB 33 chan * 64 MHz continuum mode
2217 1140 : for (Int i=0; i<nb2; i++) {
2218 855 : flags.column(b2[i])=true;
2219 : }
2220 : }
2221 285 : } else if (bw<1.e9 && nfreq>=2049) {
2222 : // CABB zoom mode, 2049 or more channels (combined zooms)
2223 285 : chn = 2049*edge_p/200;
2224 : }
2225 47310 : for (Int i=0; i<chn; i++) flags.column(i)=true;
2226 47310 : for (Int i=nfreq-chn; i<nfreq; i++) flags.column(i)=true;
2227 855 : }
2228 :
2229 1 : void ATCAFiller::fillFeedTable() {
2230 : // At present there is always only a single feed per antenna (at any
2231 : // given spectralwindow).
2232 1 : Int nAnt=atms_p.antenna().nrow();
2233 : // Int nSpW=atms_p.spectralWindow().nrow();
2234 : // Only X and Y receptors available
2235 2 : Vector<String> rec_type(2); rec_type(0)="X"; rec_type(1)="Y";
2236 2 : Matrix<Complex> polResponse(2,2);
2237 1 : polResponse=0.; polResponse(0,0)=polResponse(1,1)=1.;
2238 2 : Matrix<Double> offset(2,2); offset=0.;
2239 2 : Vector<Double> position(3); position=0.;
2240 : // X feed is at 45 degrees, Y at 135 degrees for all except 7mm
2241 2 : Vector<Double> receptorAngle(2);
2242 1 : receptorAngle(0)=45*C::degree;
2243 1 : receptorAngle(1)=135*C::degree;
2244 : // Single entry, so we use the first spectral window
2245 1 : Double f = msc_p->spectralWindow().refFrequency()(0);
2246 1 : if (f>30e9 && f<50e9) receptorAngle+=90*C::degree;
2247 :
2248 : // fill the feed table
2249 1 : Int row=-1;
2250 : // in principle we should have a separate entry for each SpectralWindow
2251 : // but at present all this is 'dummy' filled
2252 : // for (Int spw=0; spw<nSpW; spw++) {
2253 7 : for (Int ant=0; ant<nAnt; ant++) {
2254 6 : atms_p.feed().addRow(); row++;
2255 6 : msc_p->feed().antennaId().put(row,ant);
2256 6 : msc_p->feed().beamId().put(row,-1);
2257 6 : msc_p->feed().feedId().put(row,0);
2258 6 : msc_p->feed().interval().put(row,DBL_MAX);
2259 6 : msc_p->feed().phasedFeedId().put(row,-1);
2260 6 : msc_p->feed().spectralWindowId().put(row,-1); //spw);
2261 6 : msc_p->feed().time().put(row,0.);
2262 6 : msc_p->feed().numReceptors().put(row,2);
2263 6 : msc_p->feed().beamOffset().put(row,offset);
2264 6 : msc_p->feed().polarizationType().put(row,rec_type);
2265 6 : msc_p->feed().polResponse().put(row,polResponse);
2266 6 : msc_p->feed().position().put(row,position);
2267 6 : msc_p->feed().receptorAngle().put(row,receptorAngle);
2268 : }
2269 1 : }
2270 :
2271 1 : void ATCAFiller::fillObservationTable()
2272 : {
2273 2 : Vector<Double> tim = msc_p->time().getColumn();
2274 2 : Vector<Int> obsid = msc_p->observationId().getColumn();
2275 : Int startInd;
2276 : Int endInd;
2277 :
2278 1 : Int nObs=atms_p.observation().nrow();
2279 2 : Vector<Double> vt(2);
2280 2 : for (Int obs=0; obs<nObs; obs++) {
2281 : // fill time range
2282 1 : startInd = 0;
2283 1 : endInd = atms_p.nrow()-1;
2284 1 : for (uInt i=0; i<atms_p.nrow(); i++) {
2285 1 : if (obsid(i) == obs) { startInd = i; break; }
2286 : }
2287 856 : for (uInt i=startInd; i<atms_p.nrow(); i++) {
2288 855 : if (obsid(i) > obs) { endInd = i-1; break; }
2289 : }
2290 1 : vt(0) = tim(startInd);
2291 1 : vt(1) = tim(endInd);
2292 1 : msc_p->observation().timeRange().put(obs, vt);
2293 1 : msc_p->observation().releaseDate().put(obs,vt(1)+18*30.5*86400);
2294 : // telescope name
2295 1 : msc_p->observation().telescopeName().put(obs, "ATCA");
2296 : }
2297 1 : }
2298 :
2299 1 : void ATCAFiller::flush()
2300 : {
2301 1 : atms_p.flush();
2302 1 : atms_p.antenna().flush();
2303 1 : atms_p.dataDescription().flush();
2304 1 : atms_p.feed().flush();
2305 1 : atms_p.field().flush();
2306 1 : atms_p.observation().flush();
2307 1 : atms_p.history().flush();
2308 1 : atms_p.pointing().flush();
2309 1 : atms_p.polarization().flush();
2310 1 : atms_p.source().flush();
2311 1 : atms_p.spectralWindow().flush();
2312 1 : atms_p.sysCal().flush();
2313 1 : atms_p.weather().flush();
2314 1 : }
2315 :
2316 1 : void ATCAFiller::unlock()
2317 : {
2318 1 : atms_p.unlock();
2319 1 : atms_p.antenna().unlock();
2320 1 : atms_p.dataDescription().unlock();
2321 1 : atms_p.feed().unlock();
2322 1 : atms_p.field().unlock();
2323 1 : atms_p.observation().unlock();
2324 1 : atms_p.history().unlock();
2325 1 : atms_p.pointing().unlock();
2326 1 : atms_p.polarization().unlock();
2327 1 : atms_p.source().unlock();
2328 1 : atms_p.spectralWindow().unlock();
2329 1 : atms_p.sysCal().unlock();
2330 1 : atms_p.weather().unlock();
2331 1 : }
2332 :
2333 1541 : Bool ATCAFiller::selected(Int ifNum)
2334 : {
2335 1541 : Bool select=true;
2336 : //Check for rotten eggs
2337 1541 : if (if_.if_nfreq[ifNum]==0)
2338 0 : select=false;
2339 : // check if we want this frequency
2340 1541 : if (spws_p.nelements()>0 && spws_p(0)>=0 && !anyEQ(spws_p,ifNum)) {
2341 0 : select=false;
2342 : } else {
2343 : // check if we want this frequency
2344 1541 : if (lowFreq_p>0 && (doubles_.if_freq[ifNum]-lowFreq_p)<0)
2345 0 : select=false;
2346 : else {
2347 1541 : if (highFreq_p>0 && (highFreq_p-doubles_.if_freq[ifNum])<0)
2348 0 : select=false;
2349 : else {
2350 : // check if we want this bandwidth on the first IF
2351 1541 : if (bandWidth1_p>0 &&
2352 0 : (bandWidth1_p != myround(doubles_.if_bw[ifNum]/1.e6)))
2353 0 : select=false;
2354 : else {
2355 : // check if we want this number of channels on the first IF
2356 1541 : if (numChan1_p>0 && numChan1_p != if_.if_nfreq[ifNum])
2357 0 : select=false;
2358 : }
2359 : }
2360 : }
2361 : }
2362 1541 : return select;
2363 : }
2364 :
2365 0 : void ATCAFiller::shadow(Int row, Bool last)
2366 : {
2367 : // 1. collect together all rows with the same time
2368 : // 2. determine which antennas are shadowed
2369 : // 3. flag all baselines involving a shadowed antenna
2370 :
2371 0 : if (last || msc_p->time()(row)!=prevTime_p) {
2372 : // flag previous rows if needed
2373 0 : if (nRowCache_p>0) {
2374 0 : Vector<Bool> flag(nAnt_p); flag=false;
2375 0 : Vector<Double> uvw;
2376 0 : for (Int i=0; i< nRowCache_p; i++) {
2377 0 : Int k=rowCache_p[i];
2378 : // check for shadowing: projected baseline < shadow diameter
2379 0 : uvw = msc_p->uvw()(k);
2380 0 : double uvd2=uvw(0)*uvw(0)+uvw(1)*uvw(1);
2381 0 : if (uvd2>0) {
2382 0 : Bool shadowed = (uvd2<shadow_p*shadow_p);
2383 0 : if (shadowed) {
2384 : // w term decides which antenna is being shadowed
2385 0 : if (uvw(2)>0) {
2386 0 : flag(msc_p->antenna2()(k))=true;
2387 : // cout << " Shadowed: antenna2="<<msc_p->antenna2()(k)<<" for row "
2388 : // <<k<<" time="<< msc_p->timeMeas()(k) <<endl;
2389 : } else {
2390 0 : flag(msc_p->antenna1()(k))=true;
2391 : // cout << " Shadowed: antenna1="<<msc_p->antenna1()(k)<<" for row "
2392 : // <<k<<" time="<<msc_p->timeMeas()(k) <<endl;
2393 : }
2394 : }
2395 : }
2396 : }
2397 : // now flag rows with shadowed antennas
2398 0 : for (Int i=0; i< nRowCache_p; i++) {
2399 0 : Int k=rowCache_p[i];
2400 0 : Int ant1 = msc_p->antenna1()(k);
2401 0 : Int ant2 = msc_p->antenna2()(k);
2402 0 : if (flag(ant1) || flag(ant2)) {
2403 0 : flagCount_p(SHADOW)++;
2404 0 : msc_p->flagRow().put(k,true);
2405 : }
2406 : }
2407 : }
2408 : // reinitialize
2409 0 : if (!last) {
2410 0 : nRowCache_p=0;
2411 0 : prevTime_p=msc_p->time()(row);
2412 : }
2413 : }
2414 0 : if (!last) {
2415 0 : if (Int(rowCache_p.nelements())<=nRowCache_p) {
2416 0 : rowCache_p.resize(2*(nRowCache_p+1),true);
2417 : }
2418 0 : rowCache_p[nRowCache_p++]=row;
2419 : }
2420 0 : }
2421 :
2422 0 : Bool ATCAFiller::samplerFlag(Int row, Double posNegTolerance,
2423 : Double zeroTolerance) {
2424 : // check the sampler stats for the current row, return false if data needs to
2425 : // be flagged
2426 :
2427 0 : const Float posNegRef = 17.3;
2428 0 : const Float zeroRef =50.0;
2429 0 : Vector<Int> rows(2);
2430 0 : rows(0) = colSysCalIdAnt1(row);
2431 0 : rows(1) = colSysCalIdAnt2(row);
2432 0 : Bool flag = rows(0)<0 || rows(1)<0;
2433 0 : for (Int i=0; (!flag && i<2); i++) {
2434 0 : Vector<Float> neg = colSamplerStatsNeg(rows(i));
2435 0 : Vector<Float> pos = colSamplerStatsPos(rows(i));
2436 0 : Vector<Float> zero = colSamplerStatsZero(rows(i));
2437 0 : flag |=(abs(neg(0)-posNegRef)>posNegTolerance) ||
2438 0 : (abs(neg(1)-posNegRef)>posNegTolerance) ||
2439 0 : (abs(pos(0)-posNegRef)>posNegTolerance) ||
2440 0 : (abs(pos(1)-posNegRef)>posNegTolerance) ||
2441 0 : (abs(zero(0)-zeroRef)>zeroTolerance) ||
2442 0 : (abs(zero(1)-zeroRef)>zeroTolerance);
2443 : }
2444 0 : return flag;
2445 : }
2446 :
2447 0 : Vector<Double> ATCAFiller::opacities(Vector<Double> fGHz, Float tempK,Float humi,Float press,
2448 : Float height) {
2449 : // use (former) ASAP/Miriad code to calculate zenith opacities at a range of frequencies
2450 : // given the surface weather conditions
2451 :
2452 0 : ATAtmosphere atm = ATAtmosphere(tempK,press*100.,humi/100.);
2453 0 : atm.setObservatoryElevation(height);
2454 0 : return atm.zenithOpacities(fGHz*1e9);
2455 : }
2456 :
2457 : } //# end casa namespace
|