source: branches/alma/external-alma/atnf/PKSIO/PKSMS2writer.cc@ 2731

Last change on this file since 2731 was 1771, checked in by Kana Sugimoto, 14 years ago

New Development: No

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s):

Description: merged Jonas' change for filler.

(Description by Jonas) Increase tile sizes to 1MB a few places that I missed earlier.


File size: 38.3 KB
Line 
1//#---------------------------------------------------------------------------
2//# PKSMS2writer.cc: Class to write Parkes multibeam data to a measurementset.
3//#---------------------------------------------------------------------------
4//# livedata - processing pipeline for single-dish, multibeam spectral data.
5//# Copyright (C) 2000-2009, Australia Telescope National Facility, CSIRO
6//#
7//# This file is part of livedata.
8//#
9//# livedata is free software: you can redistribute it and/or modify it under
10//# the terms of the GNU General Public License as published by the Free
11//# Software Foundation, either version 3 of the License, or (at your option)
12//# any later version.
13//#
14//# livedata is distributed in the hope that it will be useful, but WITHOUT
15//# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16//# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17//# more details.
18//#
19//# You should have received a copy of the GNU General Public License along
20//# with livedata. If not, see <http://www.gnu.org/licenses/>.
21//#
22//# Correspondence concerning livedata may be directed to:
23//# Internet email: mcalabre@atnf.csiro.au
24//# Postal address: Dr. Mark Calabretta
25//# Australia Telescope National Facility, CSIRO
26//# PO Box 76
27//# Epping NSW 1710
28//# AUSTRALIA
29//#
30//# http://www.atnf.csiro.au/computing/software/livedata.html
31//# $Id: PKSMS2writer.cc,v 19.16 2009-09-29 07:33:38 cal103 Exp $
32//#---------------------------------------------------------------------------
33
34#include <atnf/PKSIO/PKSrecord.h>
35#include <atnf/PKSIO/PKSMS2writer.h>
36
37#include <casa/Arrays/ArrayUtil.h>
38#include <casa/Arrays/ArrayMath.h>
39#include <casa/Arrays/ArrayLogical.h>
40#include <casa/Arrays/Cube.h>
41#include <casa/BasicSL/Complex.h>
42#include <casa/BasicSL/Constants.h>
43#include <casa/Quanta/QC.h>
44#include <casa/Logging/LogIO.h>
45#include <measures/Measures/Stokes.h>
46#include <tables/Tables/ArrColDesc.h>
47#include <tables/Tables/IncrementalStMan.h>
48#include <tables/Tables/ScaColDesc.h>
49#include <tables/Tables/SetupNewTab.h>
50#include <tables/Tables/StandardStMan.h>
51#include <tables/Tables/Table.h>
52#include <tables/Tables/TableDesc.h>
53#include <tables/Tables/TiledShapeStMan.h>
54
55// Class name
56const string className = "PKSMS2writer" ;
57
58//------------------------------------------------- PKSMS2writer::PKSMS2writer
59
60// Default constructor.
61
62PKSMS2writer::PKSMS2writer()
63{
64 cPKSMS = 0x0;
65}
66
67//------------------------------------------------ PKSMS2writer::~PKSMS2writer
68
69// Destructor.
70
71PKSMS2writer::~PKSMS2writer()
72{
73 close();
74}
75
76//------------------------------------------------------- PKSMS2writer::create
77
78// Create the output MS and and write static data.
79
80Int PKSMS2writer::create(
81 const String msName,
82 const String observer,
83 const String project,
84 const String antName,
85 const Vector<Double> antPosition,
86 const String obsMode,
87 const String bunit,
88 const Float equinox,
89 const String dopplerFrame,
90 const Vector<uInt> nChan,
91 const Vector<uInt> nPol,
92 const Vector<Bool> haveXPol,
93 const Bool haveBase)
94{
95 const string methodName = "create()" ;
96 LogIO os( LogOrigin( className, methodName, WHERE ) ) ;
97
98 if (cPKSMS) {
99 os << LogIO::SEVERE << "Output MS already open, close it first." << LogIO::POST ;
100 return 1;
101 }
102
103 // Open a MS table.
104 TableDesc pksDesc = MS::requiredTableDesc();
105
106 cNChan.assign(nChan);
107 cNPol.assign(nPol);
108 cHaveXPol.assign(haveXPol);
109
110 Int maxNPol = max(cNPol);
111 cGBT = cAPEX = cSMT = cALMA = cATF = False;
112
113 String telName = antName;
114 // check if it is GBT data
115 if (antName.contains("GBT")) {
116 cGBT = True;
117 }
118 else if (antName.contains("APEX")) {
119 cAPEX = True;
120 }
121 else if (antName.contains("HHT") || antName.contains("SMT")) {
122 cSMT = True;
123 }
124 else if (antName.contains("ALMA")) {
125 cALMA = True;
126 }
127 else if (antName.contains("ATF")) {
128 cATF = True;
129 telName="ATF";
130 }
131
132 // Add the non-standard CALFCTR column.
133 pksDesc.addColumn(ArrayColumnDesc<Float>("CALFCTR", "Calibration factors",
134 IPosition(1,maxNPol), ColumnDesc::Direct));
135
136 // Add the optional FLOAT_DATA column.
137 MS::addColumnToDesc(pksDesc, MS::FLOAT_DATA, 2);
138 //pksDesc.rwColumnDesc(MS::columnName(MS::FLOAT_DATA)).rwKeywordSet().
139 // define("UNIT", String("Jy"));
140 pksDesc.rwColumnDesc(MS::columnName(MS::FLOAT_DATA)).rwKeywordSet().
141 define("UNIT", bunit);
142 pksDesc.rwColumnDesc(MS::columnName(MS::FLOAT_DATA)).rwKeywordSet().
143 define("MEASURE_TYPE", "");
144
145 if ((cHaveBase = haveBase)) {
146 // Add the non-standard BASELIN and BASESUB columns.
147 pksDesc.addColumn(ArrayColumnDesc<Float>("BASELIN", "Linear baseline fit",
148 IPosition(2,2,maxNPol), ColumnDesc::Direct));
149 pksDesc.addColumn(ArrayColumnDesc<Float>("BASESUB", "Baseline subtracted",
150 IPosition(2,24,maxNPol), ColumnDesc::Direct));
151 }
152
153 // Add the optional DATA column if cross-polarizations are to be recorded.
154 if (ntrue(cHaveXPol)) {
155 // Add the non-standard XCALFCTR column.
156 pksDesc.addColumn(ScalarColumnDesc<Complex>("XCALFCTR",
157 "Cross-polarization calibration factor"));
158
159 MS::addColumnToDesc(pksDesc, MS::DATA, 2);
160 //pksDesc.rwColumnDesc(MS::columnName(MS::DATA)).rwKeywordSet().
161 // define("UNIT", "Jy");
162 pksDesc.rwColumnDesc(MS::columnName(MS::DATA)).rwKeywordSet().
163 define("UNIT", bunit);
164 pksDesc.rwColumnDesc(MS::columnName(MS::DATA)).rwKeywordSet().
165 define("MEASURE_TYPE", "");
166 }
167
168 // Define hypercube for the float data (without coordinates).
169 pksDesc.defineHypercolumn("TiledData", 3,
170 stringToVector(MS::columnName(MS::FLOAT_DATA)));
171
172 SetupNewTable newtab(msName, pksDesc, Table::New);
173
174 // Set Incremental Storage Manager as the default.
175 IncrementalStMan incrStMan("ISMData");
176 newtab.bindAll(incrStMan, True);
177
178 // Use TiledShapeStMan for the FLOAT_DATA hypercube with tile size 1 MB.
179 TiledShapeStMan tiledStMan("TiledData", IPosition(3,1,128,2048));
180 newtab.bindColumn(MS::columnName(MS::FLOAT_DATA), tiledStMan);
181
182 // Use Standard Storage Manager to handle columns that change for each row.
183 StandardStMan stdStMan;
184 newtab.bindColumn(MS::columnName(MS::SCAN_NUMBER), stdStMan);
185 newtab.bindColumn(MS::columnName(MS::TIME), stdStMan);
186 newtab.bindColumn(MS::columnName(MS::SIGMA), stdStMan);
187 if (maxNPol > 2) {
188 newtab.bindColumn(MS::columnName(MS::DATA), stdStMan);
189 }
190
191 // Create the measurementset.
192 cPKSMS = new MeasurementSet(newtab, 0);
193
194 // Create subtables.
195 TableDesc antennaDesc = MSAntenna::requiredTableDesc();
196 SetupNewTable antennaSetup(cPKSMS->antennaTableName(), antennaDesc,
197 Table::New);
198 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::ANTENNA),
199 Table(antennaSetup));
200
201 TableDesc dataDescDesc = MSDataDescription::requiredTableDesc();
202 SetupNewTable dataDescSetup(cPKSMS->dataDescriptionTableName(), dataDescDesc,
203 Table::New);
204 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::DATA_DESCRIPTION),
205 Table(dataDescSetup));
206
207 TableDesc dopplerDesc = MSDoppler::requiredTableDesc();
208 SetupNewTable dopplerSetup(cPKSMS->dopplerTableName(), dopplerDesc,
209 Table::New);
210 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::DOPPLER),
211 Table(dopplerSetup));
212
213 TableDesc feedDesc = MSFeed::requiredTableDesc();
214 MSFeed::addColumnToDesc(feedDesc, MSFeedEnums::FOCUS_LENGTH);
215 SetupNewTable feedSetup(cPKSMS->feedTableName(), feedDesc, Table::New);
216 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::FEED),
217 Table(feedSetup));
218
219 TableDesc fieldDesc = MSField::requiredTableDesc();
220 SetupNewTable fieldSetup(cPKSMS->fieldTableName(), fieldDesc, Table::New);
221 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::FIELD),
222 Table(fieldSetup));
223
224 TableDesc flagCmdDesc = MSFlagCmd::requiredTableDesc();
225 SetupNewTable flagCmdSetup(cPKSMS->flagCmdTableName(), flagCmdDesc,
226 Table::New);
227 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::FLAG_CMD),
228 Table(flagCmdSetup));
229
230 TableDesc historyDesc = MSHistory::requiredTableDesc();
231 SetupNewTable historySetup(cPKSMS->historyTableName(), historyDesc,
232 Table::New);
233 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::HISTORY),
234 Table(historySetup));
235
236 TableDesc observationDesc = MSObservation::requiredTableDesc();
237 SetupNewTable observationSetup(cPKSMS->observationTableName(),
238 observationDesc, Table::New);
239 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::OBSERVATION),
240 Table(observationSetup));
241
242 TableDesc pointingDesc = MSPointing::requiredTableDesc();
243 SetupNewTable pointingSetup(cPKSMS->pointingTableName(), pointingDesc,
244 Table::New);
245 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::POINTING),
246 Table(pointingSetup));
247
248 TableDesc polarizationDesc = MSPolarization::requiredTableDesc();
249 SetupNewTable polarizationSetup(cPKSMS->polarizationTableName(),
250 polarizationDesc, Table::New);
251 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::POLARIZATION),
252 Table(polarizationSetup));
253
254 TableDesc processorDesc = MSProcessor::requiredTableDesc();
255 SetupNewTable processorSetup(cPKSMS->processorTableName(), processorDesc,
256 Table::New);
257 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::PROCESSOR),
258 Table(processorSetup));
259
260 TableDesc sourceDesc = MSSource::requiredTableDesc();
261 MSSource::addColumnToDesc(sourceDesc, MSSourceEnums::TRANSITION, 1);
262 MSSource::addColumnToDesc(sourceDesc, MSSourceEnums::REST_FREQUENCY,
263 1);
264 MSSource::addColumnToDesc(sourceDesc, MSSourceEnums::SYSVEL, 1);
265 SetupNewTable sourceSetup(cPKSMS->sourceTableName(), sourceDesc,
266 Table::New);
267 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::SOURCE),
268 Table(sourceSetup));
269
270 TableDesc spectralWindowDesc = MSSpectralWindow::requiredTableDesc();
271 MSSpectralWindow::addColumnToDesc(spectralWindowDesc,
272 MSSpectralWindowEnums::DOPPLER_ID);
273 SetupNewTable spectralWindowSetup(cPKSMS->spectralWindowTableName(),
274 spectralWindowDesc, Table::New);
275 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::SPECTRAL_WINDOW),
276 Table(spectralWindowSetup));
277
278 TableDesc stateDesc = MSState::requiredTableDesc();
279 SetupNewTable stateSetup(cPKSMS->stateTableName(), stateDesc, Table::New);
280 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::STATE),
281 Table(stateSetup));
282
283 TableDesc sysCalDesc = MSSysCal::requiredTableDesc();
284 MSSysCal::addColumnToDesc(sysCalDesc, MSSysCalEnums::TCAL, 1);
285 MSSysCal::addColumnToDesc(sysCalDesc, MSSysCalEnums::TSYS, 1);
286 SetupNewTable sysCalSetup(cPKSMS->sysCalTableName(), sysCalDesc,
287 Table::New);
288 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::SYSCAL),
289 Table(sysCalSetup));
290
291 TableDesc weatherDesc = MSWeather::requiredTableDesc();
292 MSWeather::addColumnToDesc(weatherDesc, MSWeatherEnums::PRESSURE);
293 MSWeather::addColumnToDesc(weatherDesc, MSWeatherEnums::REL_HUMIDITY);
294 MSWeather::addColumnToDesc(weatherDesc, MSWeatherEnums::TEMPERATURE);
295 SetupNewTable weatherSetup(cPKSMS->weatherTableName(), weatherDesc,
296 Table::New);
297 cPKSMS->rwKeywordSet().defineTable(MS::keywordName(MS::WEATHER),
298 Table(weatherSetup));
299
300 cPKSMS->initRefs();
301
302 // Measurementset subtables.
303 cAntenna = cPKSMS->antenna();
304 cDataDescription = cPKSMS->dataDescription();
305 cDoppler = cPKSMS->doppler();
306 cFeed = cPKSMS->feed();
307 cField = cPKSMS->field();
308 cFlagCmd = cPKSMS->flagCmd();
309 cHistory = cPKSMS->history();
310 cObservation = cPKSMS->observation();
311 cPointing = cPKSMS->pointing();
312 cPolarization = cPKSMS->polarization();
313 cProcessor = cPKSMS->processor();
314 cSource = cPKSMS->source();
315 cSpectralWindow = cPKSMS->spectralWindow();
316 cState = cPKSMS->state();
317 cSysCal = cPKSMS->sysCal();
318 cWeather = cPKSMS->weather();
319
320 // Measurementset table columns;
321 cMSCols = new MSColumns(*cPKSMS);
322 cAntennaCols = new MSAntennaColumns(cAntenna);
323 cDataDescCols = new MSDataDescColumns(cDataDescription);
324 cDopplerCols = new MSDopplerColumns(cDoppler);
325 cFeedCols = new MSFeedColumns(cFeed);
326 cFieldCols = new MSFieldColumns(cField);
327 cFlagCmdCols = new MSFlagCmdColumns(cFlagCmd);
328 cHistoryCols = new MSHistoryColumns(cHistory);
329 cObservationCols = new MSObservationColumns(cObservation);
330 cPointingCols = new MSPointingColumns(cPointing);
331 cPolarizationCols = new MSPolarizationColumns(cPolarization);
332 cProcessorCols = new MSProcessorColumns(cProcessor);
333 cSourceCols = new MSSourceColumns(cSource);
334 cSpWindowCols = new MSSpWindowColumns(cSpectralWindow);
335 cStateCols = new MSStateColumns(cState);
336 cSysCalCols = new MSSysCalColumns(cSysCal);
337 cWeatherCols = new MSWeatherColumns(cWeather);
338
339 cCalFctrCol = new ArrayColumn<Float>(*cPKSMS, "CALFCTR");
340 if (cHaveBase) {
341 cBaseLinCol = new ArrayColumn<Float>(*cPKSMS, "BASELIN");
342 cBaseSubCol = new ArrayColumn<Float>(*cPKSMS, "BASESUB");
343 }
344 if (ntrue(cHaveXPol)) {
345 cXCalFctrCol = new ScalarColumn<Complex>(*cPKSMS, "XCALFCTR");
346 }
347
348
349 // Define Measure references.
350 Vector<String> flagCat(1, "BAD");
351 cMSCols->sigma().rwKeywordSet().define("UNIT", "K");
352 cMSCols->flagCategory().rwKeywordSet().define("CATEGORY", flagCat);
353
354 String dirref;
355 if (equinox == 1950.0f) {
356 dirref = "B1950";
357 } else {
358 dirref = "J2000";
359 }
360
361 cFieldCols->delayDir().rwKeywordSet().asrwRecord("MEASINFO").
362 define("Ref", dirref);
363 cFieldCols->phaseDir().rwKeywordSet().asrwRecord("MEASINFO").
364 define("Ref", dirref);
365 cFieldCols->referenceDir().rwKeywordSet().asrwRecord("MEASINFO").
366 define("Ref", dirref);
367
368 cPointingCols->direction().rwKeywordSet().asrwRecord("MEASINFO").
369 define("Ref", dirref);
370 cPointingCols->target().rwKeywordSet().asrwRecord("MEASINFO").
371 define("Ref", dirref);
372
373 cSourceCols->direction().rwKeywordSet().asrwRecord("MEASINFO").
374 define("Ref", dirref);
375 cSourceCols->restFrequency().rwKeywordSet().asrwRecord("MEASINFO").
376 define("Ref", "REST");
377
378 // Translate Doppler frame name.
379 if (dopplerFrame == "TOPOCENT") {
380 MFrequency::getType(cDopplerFrame, "TOPO");
381 } else if (dopplerFrame == "GEOCENTR") {
382 MFrequency::getType(cDopplerFrame, "GEO");
383 } else if (dopplerFrame == "BARYCENT") {
384 MFrequency::getType(cDopplerFrame, "BARY");
385 } else if (dopplerFrame == "GALACTOC") {
386 MFrequency::getType(cDopplerFrame, "GALACTO");
387 } else if (dopplerFrame == "LOCALGRP") {
388 MFrequency::getType(cDopplerFrame, "LGROUP");
389 } else if (dopplerFrame == "CMBDIPOL") {
390 MFrequency::getType(cDopplerFrame, "CMB");
391 } else if (dopplerFrame == "SOURCE") {
392 MFrequency::getType(cDopplerFrame, "REST");
393 } else if (dopplerFrame == "LSRK") {
394 MFrequency::getType(cDopplerFrame, "LSRK");
395 }
396
397
398 // Store static data.
399 addAntennaEntry(antName, antPosition);
400 addDopplerEntry();
401 addFeedEntry();
402 //addObservationEntry(observer, project);
403 addObservationEntry(observer, project, telName);
404 addProcessorEntry();
405
406 return 0;
407}
408
409//-------------------------------------------------------- PKSMS2writer::write
410
411// Write the next data record.
412
413/**
414Int PKSMS2writer::write(
415 const Int scanNo,
416 const Int cycleNo,
417 const Double mjd,
418 const Double interval,
419 const String fieldName,
420 const String srcName,
421 const Vector<Double> srcDir,
422 const Vector<Double> srcPM,
423 const Double srcVel,
424 const String obsMode,
425 const Int IFno,
426 const Double refFreq,
427 const Double bandwidth,
428 const Double freqInc,
429 //const Double restFreq,
430 const Vector<Double> restFreq,
431 const Vector<Float> tcal,
432 const String tcalTime,
433 const Float azimuth,
434 const Float elevation,
435 const Float parAngle,
436 const Float focusAxi,
437 const Float focusTan,
438 const Float focusRot,
439 const Float temperature,
440 const Float pressure,
441 const Float humidity,
442 const Float windSpeed,
443 const Float windAz,
444 const Int refBeam,
445 const Int beamNo,
446 const Vector<Double> direction,
447 const Vector<Double> scanRate,
448 const Vector<Float> tsys,
449 const Vector<Float> sigma,
450 const Vector<Float> calFctr,
451 const Matrix<Float> baseLin,
452 const Matrix<Float> baseSub,
453 const Matrix<Float> &spectra,
454 const Matrix<uChar> &flagged,
455 const uInt flagrow,
456 const Complex xCalFctr,
457 const Vector<Complex> &xPol)
458**/
459Int PKSMS2writer::write(
460 const PKSrecord &pksrec)
461{
462 // Extend the time range in the OBSERVATION subtable.
463 Vector<Double> timerange(2);
464 cObservationCols->timeRange().get(0, timerange);
465 Double time = pksrec.mjd*86400.0;
466 if (timerange(0) == 0.0) {
467 timerange(0) = time;
468 }
469 timerange(1) = time;
470 cObservationCols->timeRange().put(0, timerange);
471
472 Int iIF = pksrec.IFno - 1;
473 Int nChan = cNChan(iIF);
474 Int nPol = cNPol(iIF);
475
476 // IFno is the 1-relative row number in the DATA_DESCRIPTION,
477 // SPECTRAL_WINDOW, and POLARIZATION subtables.
478 if (Int(cDataDescription.nrow()) < pksrec.IFno) {
479 // Add a new entry to each subtable.
480 addDataDescriptionEntry(pksrec.IFno);
481 addSpectralWindowEntry(pksrec.IFno, nChan, pksrec.refFreq,
482 pksrec.bandwidth, pksrec.freqInc);
483 addPolarizationEntry(pksrec.IFno, nPol);
484 }
485
486 // Find or add the source to the SOURCE subtable.
487 Int srcId = addSourceEntry(pksrec.srcName, pksrec.srcDir, pksrec.srcPM,
488 pksrec.restFreq, pksrec.srcVel);
489
490 // Find or add the obsMode to the STATE subtable.
491 Int stateId = addStateEntry(pksrec.obsType);
492
493 // FIELD subtable.
494 //Vector<Double> scanRate(2);
495 //scanRate(0) = pksrec.scanRate(0);
496 //scanRate(1) = pksrec.scanRate(1);
497 Int fieldId = addFieldEntry(pksrec.fieldName, time, pksrec.direction,
498 pksrec.scanRate, srcId);
499
500 // POINTING subtable.
501 addPointingEntry(time, pksrec.interval, pksrec.fieldName, pksrec.direction,
502 pksrec.scanRate);
503
504 // SYSCAL subtable.
505 addSysCalEntry(pksrec.beamNo, iIF, time, pksrec.interval, pksrec.tcal,
506 pksrec.tsys, nPol);
507
508 // Handle weather information.
509 ROScalarColumn<Double> wTime(cWeather, "TIME");
510 Int nWeather = wTime.nrow();
511 if (nWeather == 0 || time > wTime(nWeather-1)) {
512 addWeatherEntry(time, pksrec.interval, pksrec.pressure, pksrec.humidity,
513 pksrec.temperature);
514 }
515
516
517 // Extend the main table.
518 cPKSMS->addRow();
519 Int irow = cPKSMS->nrow() - 1;
520
521 // Keys.
522 cMSCols->time().put(irow, time);
523 cMSCols->antenna1().put(irow, 0);
524 cMSCols->antenna2().put(irow, 0);
525 cMSCols->feed1().put(irow, pksrec.beamNo-1);
526 cMSCols->feed2().put(irow, pksrec.beamNo-1);
527 cMSCols->dataDescId().put(irow, iIF);
528 cMSCols->processorId().put(irow, 0);
529 cMSCols->fieldId().put(irow, fieldId);
530
531 // Non-key attributes.
532 cMSCols->interval().put(irow, pksrec.interval);
533 cMSCols->exposure().put(irow, pksrec.interval);
534 cMSCols->timeCentroid().put(irow, time);
535 cMSCols->scanNumber().put(irow, pksrec.scanNo);
536 cMSCols->arrayId().put(irow, 0);
537 cMSCols->observationId().put(irow, 0);
538 cMSCols->stateId().put(irow, stateId);
539
540 Vector<Double> uvw(3, 0.0);
541 cMSCols->uvw().put(irow, uvw);
542
543 // Baseline fit parameters.
544 if (cHaveBase) {
545 cBaseLinCol->put(irow, pksrec.baseLin);
546
547 if (pksrec.baseSub.nrow() == 24) {
548 cBaseSubCol->put(irow, pksrec.baseSub);
549
550 } else {
551 Matrix<Float> tmp(24, 2, 0.0f);
552 for (Int ipol = 0; ipol < nPol; ipol++) {
553 for (uInt j = 0; j < pksrec.baseSub.nrow(); j++) {
554 tmp(j,ipol) = pksrec.baseSub(j,ipol);
555 }
556 }
557 cBaseSubCol->put(irow, tmp);
558 }
559 }
560
561 // Transpose spectra.
562 Matrix<Float> tmpData(nPol, nChan);
563 Matrix<Bool> tmpFlag(nPol, nChan);
564 for (Int ipol = 0; ipol < nPol; ipol++) {
565 for (Int ichan = 0; ichan < nChan; ichan++) {
566 tmpData(ipol,ichan) = pksrec.spectra(ichan,ipol);
567 tmpFlag(ipol,ichan) = pksrec.flagged(ichan,ipol);
568 }
569 }
570
571 cCalFctrCol->put(irow, pksrec.calFctr);
572 cMSCols->floatData().put(irow, tmpData);
573 cMSCols->flag().put(irow, tmpFlag);
574
575 // Cross-polarization spectra.
576 if (cHaveXPol(iIF)) {
577 cXCalFctrCol->put(irow, pksrec.xCalFctr);
578 cMSCols->data().put(irow, pksrec.xPol);
579 }
580
581 cMSCols->sigma().put(irow, pksrec.sigma);
582
583 //Vector<Float> weight(1, 1.0f);
584 Vector<Float> weight(nPol, 1.0f);
585 cMSCols->weight().put(irow, weight);
586 //imaging weight
587 //Vector<Float> imagingWeight(nChan);
588 //cMSCols->imagingWeight().put(irow, imagingWeight);
589
590 // Flag information.
591 Cube<Bool> flags(nPol, nChan, 1, False);
592 //cMSCols->flag().put(irow, flags.xyPlane(0));
593 cMSCols->flagCategory().put(irow, flags);
594 // Row-based flagging info. (True:>0, False:0)
595 cMSCols->flagRow().put(irow, (pksrec.flagrow > 0));
596
597
598 return 0;
599}
600
601//-------------------------------------------------------- PKSMS2writer::close
602
603// Close the measurementset, flushing all associated tables.
604
605void PKSMS2writer::close()
606{
607 // Delete table column accessors.
608 delete cMSCols; cMSCols=0;
609 delete cAntennaCols; cAntennaCols=0;
610 delete cDataDescCols; cDataDescCols=0;
611 delete cDopplerCols; cDopplerCols=0;
612 delete cFeedCols; cFeedCols=0;
613 delete cFieldCols; cFieldCols=0;
614 delete cFlagCmdCols; cFlagCmdCols=0;
615 delete cHistoryCols; cHistoryCols=0;
616 delete cObservationCols; cObservationCols=0;
617 delete cPointingCols; cPointingCols=0;
618 delete cPolarizationCols; cPolarizationCols=0;
619 delete cProcessorCols; cProcessorCols=0;
620 delete cSourceCols; cSourceCols=0;
621 delete cSpWindowCols; cSpWindowCols=0;
622 delete cStateCols; cStateCols=0;
623 delete cSysCalCols; cSysCalCols=0;
624 delete cWeatherCols; cWeatherCols=0;
625
626 delete cCalFctrCol; cCalFctrCol=0;
627 if (cHaveBase) {
628 delete cBaseLinCol; cBaseLinCol=0;
629 delete cBaseSubCol; cBaseSubCol=0;
630 }
631 if (ntrue(cHaveXPol)) {
632 delete cXCalFctrCol; cXCalFctrCol=0;
633 }
634
635 // Release all subtables.
636 cAntenna = MSAntenna();
637 cDataDescription = MSDataDescription();
638 cDoppler = MSDoppler();
639 cFeed = MSFeed();
640 cField = MSField();
641 cFlagCmd = MSFlagCmd();
642 cHistory = MSHistory();
643 cObservation = MSObservation();
644 cPointing = MSPointing();
645 cPolarization = MSPolarization();
646 cProcessor = MSProcessor();
647 cSource = MSSource();
648 cSpectralWindow = MSSpectralWindow();
649 cState = MSState();
650 cSysCal = MSSysCal();
651 cWeather = MSWeather();
652 // Release the main table.
653 delete cPKSMS;
654 cPKSMS=0x0;
655}
656
657//---------------------------------------------- PKSMS2writer::addAntennaEntry
658
659// Add an entry to the ANTENNA subtable.
660
661Int PKSMS2writer::addAntennaEntry(
662 const String antName,
663 const Vector<Double> &antPosition)
664{
665 // Extend the ANTENNA subtable.
666 cAntenna.addRow();
667 Int n = cAntenna.nrow() - 1;
668
669 // do specific things for GBT
670 // Data.
671 // plus some more telescopes
672 cAntennaCols->name().put(n, antName);
673 //cAntennaCols->station().put(n, "ATNF_PARKES");
674 if (cGBT) {
675 cAntennaCols->station().put(n, "GREENBANK");
676 cAntennaCols->dishDiameter().put(n, 110.0);
677 }
678 else if (cAPEX) {
679 cAntennaCols->station().put(n, "CHAJNANTOR");
680 cAntennaCols->dishDiameter().put(n, 12.0);
681 }
682 else if (cALMA) {
683 // this needs to be changed in future...
684 cAntennaCols->station().put(n, "CHAJNANTOR");
685 cAntennaCols->dishDiameter().put(n, 12.0);
686 }
687 else if (cATF) {
688 //pad name for the antenna is static...
689 String stname="unknown";
690 if (antName.contains("DV")) {
691 stname="PAD001";
692 }
693 if (antName.contains("DA")) {
694 stname="PAD002";
695 }
696 cAntennaCols->station().put(n, stname);
697 cAntennaCols->dishDiameter().put(n, 12.0);
698 }
699 else if (cSMT) {
700 cAntennaCols->station().put(n, "MT_GRAHAM");
701 cAntennaCols->dishDiameter().put(n, 10.0);
702 }
703 else {
704 cAntennaCols->station().put(n, "ATNF_PARKES");
705 cAntennaCols->dishDiameter().put(n, 64.0);
706 }
707 cAntennaCols->type().put(n, "GROUND-BASED");
708 cAntennaCols->mount().put(n, "ALT-AZ");
709 cAntennaCols->position().put(n, antPosition);
710 Vector<Double> antOffset(3, 0.0);
711 cAntennaCols->offset().put(n, antOffset);
712 //cAntennaCols->dishDiameter().put(n, 64.0);
713 //if (cGBT) {
714 // cAntennaCols->dishDiameter().put(n, 110.0);
715 //}
716 //else {
717 // cAntennaCols->dishDiameter().put(n, 64.0);
718 //}
719 // Flags.
720 cAntennaCols->flagRow().put(n, False);
721
722 return n;
723}
724
725//-------------------------------------- PKSMS2writer::addDataDescriptionEntry
726
727// Add an entry to the DATA_DESCRIPTION subtable.
728
729Int PKSMS2writer::addDataDescriptionEntry(
730 const Int IFno)
731{
732 // Extend the DATA_DESCRIPTION subtable.
733 while (Int(cDataDescription.nrow()) < IFno) {
734 cDataDescription.addRow();
735 }
736 Int n = IFno - 1;
737
738 // Data.
739 cDataDescCols->spectralWindowId().put(n, n);
740 cDataDescCols->polarizationId().put(n, n);
741
742 // Flags.
743 cDataDescCols->flagRow().put(n, False);
744
745 return n;
746}
747
748//---------------------------------------------- PKSMS2writer::addDopplerEntry
749
750// Add an entry to the DOPPLER subtable.
751
752Int PKSMS2writer::addDopplerEntry()
753{
754 // Extend the DOPPLER subtable.
755 cDoppler.addRow();
756 Int n = cDoppler.nrow() - 1;
757
758 // Keys.
759 cDopplerCols->dopplerId().put(n, n);
760 cDopplerCols->sourceId().put(n, 0);
761
762 // Data.
763 cDopplerCols->transitionId().put(n, 0);
764
765 return n;
766}
767
768//------------------------------------------------- PKSMS2writer::addFeedEntry
769
770// Add an entry to the FEED subtable.
771
772Int PKSMS2writer::addFeedEntry()
773{
774 Int n = cFeed.nrow() - 1;
775 for (Int iBeam = 0; iBeam < 13; iBeam++) {
776 // Extend the FEED subtable.
777 cFeed.addRow();
778 n++;
779
780 // Keys.
781 cFeedCols->antennaId().put(n, cAntenna.nrow()-1);
782 cFeedCols->feedId().put(n, iBeam);
783 cFeedCols->spectralWindowId().put(n, -1);
784 cFeedCols->time().put(n, 0.0);
785 cFeedCols->interval().put(n, -1.0);
786
787 // Data description.
788 cFeedCols->numReceptors().put(n, 2);
789
790 // Data.
791 cFeedCols->beamId().put(n, -1);
792
793 Matrix<Double> beamOffset(2, 2, 0.0);
794 cFeedCols->beamOffset().put(n, beamOffset);
795
796 cFeedCols->focusLength().put(n, 26.0);
797
798 Vector<String> polarizationType(2);
799 polarizationType(0) = "X";
800 polarizationType(1) = "Y";
801 cFeedCols->polarizationType().put(n, polarizationType);
802
803 Matrix<Complex> polResponse(2, 2, Complex(0.0));
804 for (Int i = 0; i < 2; i++) {
805 polResponse(i,i) = Complex(1.0, 0.0);
806 }
807 cFeedCols->polResponse().put(n, polResponse);
808
809 Vector<Double> position(3, 0.0);
810 cFeedCols->position().put(n, position);
811
812 Vector<Double> receptorAngle(2, C::pi_4);
813 receptorAngle(1) += C::pi_2;
814 cFeedCols->receptorAngle().put(n, receptorAngle);
815 }
816
817 return n;
818}
819
820//------------------------------------------------ PKSMS2writer::addFieldEntry
821
822// Add an entry to the FIELD subtable.
823
824Int PKSMS2writer::addFieldEntry(
825 const String fieldName,
826 const Double time,
827 const Vector<Double> direction,
828 const Vector<Double> scanRate,
829 const Int srcId)
830{
831
832 ROScalarColumn<String> fldn(cField, "NAME");
833 ROScalarColumn<Int> sourceid(cField, "SOURCE_ID");
834 Int n;
835 Int nFld = cField.nrow();
836 for (n = 0; n < nFld; n++) {
837 if (fldn(n) == fieldName && sourceid(n) == srcId) {
838 break;
839 }
840 }
841
842 // Extend the FIELD subtable.
843 if (n == nFld) {
844 cField.addRow();
845 //Int n = cField.nrow() - 1;
846
847 // Data.
848 cFieldCols->name().put(n, fieldName);
849 if (cGBT) {
850 cFieldCols->code().put(n, " ");
851 }
852 else {
853 cFieldCols->code().put(n, "DRIFT");
854 }
855 cFieldCols->time().put(n, time);
856
857 //Matrix<Double> track(2, 2);
858 Matrix<Double> track(2, 1);
859 track.column(0) = direction;
860 //track.column(1) = scanRate;
861 cFieldCols->numPoly().put(n, 1);
862 cFieldCols->delayDir().put(n, track);
863 cFieldCols->phaseDir().put(n, track);
864 cFieldCols->referenceDir().put(n, track);
865 cFieldCols->sourceId().put(n, srcId);
866
867 // Flags.
868 cFieldCols->flagRow().put(n, False);
869 }
870
871 return n;
872}
873
874//------------------------------------------ PKSMS2writer::addObservationEntry
875
876// Add an entry to the OBSERVATION subtable.
877
878Int PKSMS2writer::addObservationEntry(
879 const String observer,
880 const String project,
881 const String antName)
882{
883 // Extend the OBSERVATION subtable.
884 cObservation.addRow();
885 Int n = cObservation.nrow() - 1;
886
887 // Data.
888 //cObservationCols->telescopeName().put(n, "Parkes");
889 cObservationCols->telescopeName().put(n, antName);
890 Vector<Double> timerange(2, 0.0);
891 cObservationCols->timeRange().put(n, timerange);
892 cObservationCols->observer().put(n, observer);
893 Vector<String> log(1, "none");
894 cObservationCols->log().put(n, log);
895 //cObservationCols->scheduleType().put(n, "ATNF");
896 cObservationCols->scheduleType().put(n, "");
897 Vector<String> schedule(1, "Not available");
898 cObservationCols->schedule().put(n, schedule);
899 cObservationCols->project().put(n, project);
900 cObservationCols->releaseDate().put(n, 0.0);
901
902 // Flags.
903 cObservationCols->flagRow().put(n, False);
904
905 return n;
906}
907
908//--------------------------------------------- PKSMS2writer::addPointingEntry
909
910// Modified to fill pointing data if the direction is the pointing direction.
911// So the following comment is no longer true.
912
913// Add an entry to the POINTING subtable. This compulsory subtable simply
914// duplicates information in the FIELD subtable.
915
916Int PKSMS2writer::addPointingEntry(
917 const Double time,
918 const Double interval,
919 const String fieldName,
920 const Vector<Double> direction,
921 const Vector<Double> scanRate)
922{
923
924 ROScalarColumn<Double> tms(cPointing, "TIME");
925 Int n;
926 Int ntm = cPointing.nrow();
927 for (n = 0; n < ntm; n++) {
928 if (tms(n) == time) {
929 break;
930 }
931 }
932
933 if (n == ntm) {
934 // Extend the POINTING subtable.
935 cPointing.addRow();
936 //Int n = cPointing.nrow() - 1;
937
938 // Keys.
939 cPointingCols->antennaId().put(n, 0);
940 cPointingCols->time().put(n, time);
941 cPointingCols->interval().put(n, interval);
942
943 // Data.
944 cPointingCols->name().put(n, fieldName);
945 cPointingCols->numPoly().put(n, 1);
946 cPointingCols->timeOrigin().put(n, time);
947
948 //Matrix<Double> track(2, 2);
949 Matrix<Double> track(2, 1);
950 track.column(0) = direction;
951 //track.column(1) = scanRate;
952 cPointingCols->direction().put(n, track);
953 cPointingCols->target().put(n, track);
954 cPointingCols->tracking().put(n, True);
955 }
956 return n;
957}
958
959//----------------------------------------- PKSMS2writer::addPolarizationEntry
960
961// Add an entry to the POLARIZATION subtable.
962
963Int PKSMS2writer::addPolarizationEntry(
964 const Int IFno,
965 const Int nPol)
966{
967 // Extend the POLARIZATION subtable.
968 while (Int(cPolarization.nrow()) < IFno) {
969 cPolarization.addRow();
970 }
971 Int n = IFno - 1;
972
973 // Data description.
974 cPolarizationCols->numCorr().put(n, nPol);
975
976 // Data.
977 Vector<Int> corrType(2);
978 if (nPol == 1) {
979 corrType.resize(1);
980 corrType(0) = Stokes::XX;
981 }
982 else {
983 //Vector<Int> corrType(2);
984 corrType(0) = Stokes::XX;
985 corrType(1) = Stokes::YY;
986 }
987 cPolarizationCols->corrType().put(n, corrType);
988
989 Matrix<Int> corrProduct(2,2,1);
990 if (nPol == 1) {
991 corrProduct.resize(2,1,1);
992 corrProduct(1,0) = 0;
993 }
994 if (nPol == 2) {
995 corrProduct(1,0) = 0;
996 corrProduct(0,1) = 0;
997 }
998 cPolarizationCols->corrProduct().put(n, corrProduct);
999
1000 // Flags.
1001 cPolarizationCols->flagRow().put(n, False);
1002
1003 return n;
1004}
1005
1006
1007//-------------------------------------------- PKSMS2writer::addProcessorEntry
1008
1009// Add an entry to the PROCESSOR subtable.
1010
1011Int PKSMS2writer::addProcessorEntry()
1012{
1013 // Extend the PROCESSOR subtable.
1014 cProcessor.addRow();
1015 Int n = cProcessor.nrow() - 1;
1016
1017 // Data.
1018 cProcessorCols->type().put(n, "SPECTROMETER");
1019 cProcessorCols->subType().put(n, "MULTIBEAM");
1020 cProcessorCols->typeId().put(n, -1);
1021 cProcessorCols->modeId().put(n, -1);
1022
1023 // Flags.
1024 cProcessorCols->flagRow().put(n, False);
1025
1026 return n;
1027}
1028
1029//----------------------------------------------- PKSMS2writer::addSourceEntry
1030
1031// Add an entry to the SOURCE subtable.
1032
1033Int PKSMS2writer::addSourceEntry(
1034 const String name,
1035 const Vector<Double> direction,
1036 const Vector<Double> properMotion,
1037 //const Double restFreq,
1038 const Vector<Double> restFreq,
1039 const Double radialVelocity)
1040{
1041 // Look for an entry in the SOURCE subtable.
1042 ROScalarColumn<String> sources(cSource, "NAME");
1043 Int n;
1044 Int nSrc = sources.nrow();
1045 for (n = 0; n < nSrc; n++) {
1046 if (sources(n) == name) {
1047 break;
1048 }
1049 }
1050
1051 if (n == nSrc) {
1052 // Not found, add a new entry to the SOURCE subtable.
1053 cSource.addRow();
1054
1055 // Keys.
1056 cSourceCols->sourceId().put(n, n);
1057 cSourceCols->time().put(n, 0.0);
1058 cSourceCols->interval().put(n, -1.0);
1059 cSourceCols->spectralWindowId().put(n, -1);
1060
1061 // Data description.
1062 cSourceCols->numLines().put(n, 1);
1063
1064 // Data.
1065 cSourceCols->name().put(n, name);
1066 cSourceCols->calibrationGroup().put(n, 0);
1067 cSourceCols->code().put(n, "");
1068 cSourceCols->direction().put(n, direction);
1069// Vector<Double> position(3, 0.0);
1070// cSourceCols->position().put(n, position);
1071 cSourceCols->properMotion().put(n, properMotion);
1072// Vector<Double> restFrequency(1, restFreq);
1073// cSourceCols->restFrequency().put(n, restFrequency);
1074 cSourceCols->restFrequency().put(n, restFreq);
1075 Vector<Double> sysvel(1, radialVelocity);
1076 cSourceCols->sysvel().put(n, sysvel);
1077 }
1078
1079 return n;
1080}
1081
1082//--------------------------------------- PKSMS2writer::addSpectralWindowEntry
1083
1084// Add an entry to the SPECTRAL_WINDOW subtable.
1085
1086Int PKSMS2writer::addSpectralWindowEntry(
1087 const Int IFno,
1088 const Int nChan,
1089 const Double refFreq,
1090 const Double bandwidth,
1091 const Double freqInc)
1092{
1093 // Extend the SPECTRAL_WINDOW subtable.
1094 while (Int(cSpectralWindow.nrow()) < IFno) {
1095 cSpectralWindow.addRow();
1096 }
1097 Int n = IFno - 1;
1098
1099 // Data description.
1100 cSpWindowCols->numChan().put(n, nChan);
1101
1102 // Data.
1103 //cSpWindowCols->name().put(n, "L-band");
1104 cSpWindowCols->name().put(n, " ");
1105 cSpWindowCols->refFrequency().put(n, refFreq);
1106
1107 // 0-relative reference channel number.
1108 Double refChan = nChan / 2;
1109 Vector<Double> freqs(nChan);
1110 for (Int i = 0; i < nChan; i++) {
1111 freqs(i) = refFreq + (i - refChan)*freqInc;
1112 }
1113 cSpWindowCols->chanFreq().put(n, freqs);
1114
1115 Vector<Double> chanWidths(nChan, freqInc);
1116 cSpWindowCols->chanWidth().put(n, chanWidths);
1117
1118 cSpWindowCols->measFreqRef().put(n, cDopplerFrame);
1119 cSpWindowCols->effectiveBW().put(n, chanWidths);
1120
1121 Vector<Double> resolution(nChan, fabs(freqInc));
1122 cSpWindowCols->resolution().put(n, resolution);
1123
1124 cSpWindowCols->totalBandwidth().put(n, bandwidth);
1125 cSpWindowCols->netSideband().put(n, 0);
1126 cSpWindowCols->ifConvChain().put(n, -1);
1127 cSpWindowCols->freqGroup().put(n, 0);
1128 cSpWindowCols->freqGroupName().put(n, " ");
1129 cSpWindowCols->dopplerId().put(n, 0);
1130
1131 // Flags.
1132 cSpWindowCols->flagRow().put(n, False);
1133
1134 return n;
1135}
1136
1137//------------------------------------------------ PKSMS2writer::addStateEntry
1138
1139// Add an entry to the STATE subtable.
1140
1141Int PKSMS2writer::addStateEntry(
1142 const String obsType)
1143{
1144 // Look for an entry in the STATE subtable.
1145 for (uInt n = 0; n < cStateCols->nrow(); n++) {
1146 if (cStateCols->obsMode()(n) == obsType) {
1147 return n;
1148 }
1149 }
1150
1151 // Not found, extend the STATE subtable.
1152 cState.addRow();
1153 uInt n = cStateCols->nrow() - 1;
1154
1155 // Data.
1156 if (obsType.contains("RF")) {
1157 cStateCols->sig().put(n, False);
1158 cStateCols->ref().put(n, True);
1159 } else if (!obsType.contains("PA")) {
1160 // Signal and reference are both false for "paddle" data.
1161 cStateCols->sig().put(n, True);
1162 cStateCols->ref().put(n, False);
1163 }
1164
1165 cStateCols->load().put(n, 0.0);
1166 cStateCols->cal().put(n, 0.0);
1167 cStateCols->subScan().put(n, 0);
1168 cStateCols->obsMode().put(n, obsType);
1169
1170 // Flags.
1171 cStateCols->flagRow().put(n, False);
1172
1173 return n;
1174}
1175
1176//----------------------------------------------- PKSMS2writer::addSysCalEntry
1177
1178// Add an entry to the SYSCAL subtable.
1179
1180Int PKSMS2writer::addSysCalEntry(
1181 const Int beamNo,
1182 const Int spWinId,
1183 const Double time,
1184 const Double interval,
1185 const Vector<Float> tcal,
1186 const Vector<Float> tsys,
1187 const Int nPol)
1188{
1189 LogIO os(LogOrigin("PKSMS2writer", "addSysCalEntry()", WHERE));
1190
1191 // Extend the SYSCAL subtable.
1192 cSysCal.addRow();
1193 Int n = cSysCal.nrow() - 1;
1194
1195 //check fo consistency with n pol
1196 //here assume size of Tcal vector = npol
1197 Vector<Float> inTcal(nPol,0);
1198 Int ndim = tcal.shape()(0);
1199 Vector<Float> tmpTcal = tcal;
1200 if (nPol != ndim) {
1201 os << LogIO::WARN
1202 << "Found "<< ndim <<" Tcal value(s) for the data with "<<nPol<<" polarization(s)"
1203 << "(expecting one Tcal per pol)."<<endl
1204 << "First "<< nPol << " Tcal value(s) will be filled." << LogIO::POST;
1205 tmpTcal.resize(nPol, True);
1206 inTcal = tmpTcal;
1207 }
1208 // Keys.
1209 cSysCalCols->antennaId().put(n, 0);
1210 cSysCalCols->feedId().put(n, beamNo-1);
1211 cSysCalCols->spectralWindowId().put(n, spWinId);
1212 cSysCalCols->time().put(n, time);
1213 cSysCalCols->interval().put(n, interval);
1214
1215 // Data.
1216 //cSysCalCols->tcal().put(n, tcal);
1217 cSysCalCols->tcal().put(n, inTcal);
1218 cSysCalCols->tsys().put(n, tsys);
1219
1220 return n;
1221}
1222
1223//---------------------------------------------- PKSMS2writer::addWeatherEntry
1224
1225// Add an entry to the WEATHER subtable.
1226
1227Int PKSMS2writer::addWeatherEntry(
1228 const Double time,
1229 const Double interval,
1230 const Double pressure,
1231 const Double relHumidity,
1232 const Double temperature)
1233{
1234 // Extend the WEATHER subtable.
1235 cWeather.addRow();
1236 Int n = cWeather.nrow() - 1;
1237
1238 // Keys.
1239 cWeatherCols->antennaId().put(n, 0);
1240 cWeatherCols->time().put(n, time);
1241 cWeatherCols->interval().put(n, interval);
1242
1243 // Data.
1244 cWeatherCols->pressure().put(n, pressure);
1245 cWeatherCols->relHumidity().put(n, relHumidity);
1246 cWeatherCols->temperature().put(n, temperature);
1247
1248 return n;
1249}
Note: See TracBrowser for help on using the repository browser.