source: branches/mergetest/external/atnf/PKSIO/PKSMS2writer.cc @ 1779

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

New Development: Yes

JIRA Issue: No (test merging alma branch)

Ready for Test: Yes

Interface Changes: Yes

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s):

Description:


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.