Line data Source code
1 : //# NewCalTable.cc: Implementation of NewCalTable.h
2 : //# Copyright (C) 2011
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: casa-feedback@nrao.edu.
21 : //# Postal address: AIPS++ Project Office
22 : //# National Radio Astronomy Observatory
23 : //# 520 Edgemont Road
24 : //# Charlottesville, VA 22903-2475 USA
25 : //#
26 : //# $Id$
27 : //----------------------------------------------------------------------------
28 :
29 : #include <synthesis/CalTables/NewCalTable.h>
30 : #include <synthesis/CalTables/CTColumns.h>
31 : #include <synthesis/CalTables/CTMainColumns.h>
32 : #include <casacore/ms/MeasurementSets/MeasurementSet.h>
33 : #include <casacore/ms/MSOper/MSMetaData.h>
34 : #include <casacore/tables/Tables/ScalarColumn.h>
35 : #include <casacore/tables/Tables/ScaColDesc.h>
36 : #include <casacore/tables/Tables/SetupNewTab.h>
37 : #include <casacore/tables/Tables/TableCopy.h>
38 : #include <casacore/tables/Tables/TableRow.h>
39 : #include <casacore/tables/TaQL/TableParse.h>
40 : #include <casacore/tables/Tables/TableInfo.h>
41 : #include <casacore/measures/Measures/MEpoch.h>
42 : #include <casacore/casa/Arrays.h>
43 : #include <casacore/casa/Arrays/ArrayMath.h>
44 : #include <casacore/casa/Logging/LogIO.h>
45 : #include <synthesis/CalTables/CTEnums.h>
46 :
47 : using namespace casacore;
48 : namespace casa { //# NAMESPACE CASA - BEGIN
49 :
50 : //----------------------------------------------------------------------------
51 :
52 2771 : NewCalTable::NewCalTable() :
53 2771 : Table()
54 : {
55 : // Form CTDesc from parameters
56 2771 : String parTypeStr("Complex");
57 :
58 5542 : CTDesc nctd(parTypeStr,"unknown","unknown","unknown");
59 :
60 : // Form underlying generic Table according to the CTDesc
61 5542 : SetupNewTable calMainTab("nullNewCalTable.tempMemCalTable",nctd.calMainDesc(),Table::New);
62 2771 : Table tab(calMainTab, Table::Memory, 0, false);
63 2771 : *this = tab;
64 :
65 : // Set the table info record
66 2771 : this->setTableInfo();
67 2771 : };
68 :
69 : //----------------------------------------------------------------------------
70 :
71 230670 : NewCalTable::~NewCalTable()
72 : {
73 : // Default desctructor
74 230670 : };
75 :
76 : //----------------------------------------------------------------------------
77 433 : NewCalTable::NewCalTable (const String& tableName, CTDesc& ctableDesc,
78 433 : Table::TableOption access, Table::TableType ttype):
79 433 : Table()
80 : {
81 : // Construct from a cal table name, descriptor and access option.
82 : // Used for creating new tables.
83 : // Input:
84 : // tableName const String& Cal table name
85 : // ctableDesc const CTDesc& Cal table descriptor
86 : // access Table::TableOption Access mode
87 : // ttype Table::TableType Memory or Plain
88 : //
89 :
90 433 : if (access == Table::New || access == Table::NewNoReplace ||
91 : access == Table::Scratch) {
92 :
93 : // Form underlying generic Table according to the supplied desc
94 433 : SetupNewTable calMainTab(tableName,ctableDesc.calMainDesc(),access);
95 433 : Table tab(calMainTab, ttype, 0, false);
96 433 : *this = tab;
97 :
98 : // Set the table info record
99 433 : this->setTableInfo();
100 :
101 : // Form (empty) subtables
102 433 : this->createSubTables();
103 433 : }
104 : else
105 0 : throw(AipsError("Creating NewCalTable from scratch must use access=Table::New or TableNewNoReplace or Table::Scratch"));
106 433 : };
107 :
108 :
109 : //----------------------------------------------------------------------------
110 0 : NewCalTable::NewCalTable (SetupNewTable& newtab, uInt nrow, Bool initialize):
111 0 : Table(newtab, nrow, initialize)
112 : {
113 : // Construct from a cal table name, descriptor and access option.
114 : // Used for creating new tables.
115 : // Input:
116 : // newtab SetupNewtable&
117 : // nrow uInt n rows
118 : // initialize Bool
119 : //
120 0 : };
121 :
122 : //----------------------------------------------------------------------------
123 : // Create an empty NewCalTable conveniently
124 47 : NewCalTable::NewCalTable(String tableName,VisCalEnum::VCParType parType,
125 47 : String typeName,String msName,Bool doSingleChan) :
126 47 : Table()
127 : {
128 : // Form CTDesc from parameters
129 47 : String parTypeStr = ((parType==VisCalEnum::COMPLEX) ? "Complex" : "Float");
130 :
131 47 : CTDesc nctd(parTypeStr,msName,typeName,"unknown");
132 :
133 : // Form underlying generic Table according to the CTDesc
134 94 : SetupNewTable calMainTab(tableName+".tempMemCalTable",nctd.calMainDesc(),Table::New);
135 47 : Table tab(calMainTab, Table::Memory, 0, false);
136 47 : *this = tab;
137 :
138 : // Set the table info record
139 47 : this->setTableInfo();
140 :
141 : // Add (empty) subtables
142 47 : this->createSubTables();
143 :
144 : // Copy subtables from the supplied MS
145 47 : this->setMetaInfo(msName);
146 :
147 : // Reset Spw channelization, if nec.
148 : // (very basic, uses chan n/2 freq)
149 47 : if (doSingleChan)
150 37 : this->makeSpwSingleChan();
151 :
152 47 : }
153 :
154 : //----------------------------------------------------------------------------
155 765 : NewCalTable::NewCalTable (const String& tableName, Table::TableOption access,
156 765 : Table::TableType ttype): Table(tableName,access)
157 : {
158 : // Construct from an existing cal table, and access option.
159 : //
160 : // Input:
161 : // tableName const String& Cal table name
162 : // access Table::TableOption Access mode
163 : // ttype Table::TableType Memory or Plain
164 : //
165 : //cerr<<"ctor: from existing cal table with name, option"<<endl;
166 :
167 765 : if (ttype==Table::Memory)
168 455 : *this = this->copyToMemoryTable(tableName+".tempMemCalTable");
169 :
170 2272 : if (!this->tableDesc().isColumn(NCT::fieldName(NCT::OBSERVATION_ID)) ||
171 1507 : !this->keywordSet().isDefined("OBSERVATION"))
172 23 : addPhoneyObs();
173 :
174 : // Attach subtable accessors
175 765 : attachSubTables();
176 :
177 765 : };
178 :
179 0 : NewCalTable::NewCalTable (const String& tableName,
180 : const casacore::TableLock& lockOptions, Table::TableOption access,
181 0 : Table::TableType ttype): Table(tableName, lockOptions, access)
182 : {
183 : // Construct from an existing cal table, with lock, access, and type options.
184 0 : if (ttype==Table::Memory)
185 0 : *this = this->copyToMemoryTable(tableName+".tempMemCalTable");
186 0 : if (!this->tableDesc().isColumn(NCT::fieldName(NCT::OBSERVATION_ID)) ||
187 0 : !this->keywordSet().isDefined("OBSERVATION")) {
188 0 : addPhoneyObs();
189 : }
190 0 : attachSubTables();
191 0 : }
192 : //----------------------------------------------------------------------------
193 :
194 : // Factory method that has Back Compat option
195 455 : NewCalTable NewCalTable::createCT(const String& tableName,
196 : Table::TableOption access,
197 : Table::TableType ttype,
198 : Bool doBackCompat) {
199 : // Handle back compat
200 455 : if (doBackCompat)
201 455 : NewCalTable::CTBackCompat(tableName);
202 :
203 : // Ordinary ctor
204 455 : return NewCalTable(tableName,access,ttype);
205 :
206 : }
207 : // Factory method that has Back Compat option
208 0 : NewCalTable* NewCalTable::createCTptr(const String& tableName,
209 : Table::TableOption access,
210 : Table::TableType ttype,
211 : Bool doBackCompat) {
212 : // Handle back compat
213 0 : if (doBackCompat)
214 0 : NewCalTable::CTBackCompat(tableName);
215 :
216 : // Ordinary ctor
217 0 : return new NewCalTable(tableName,access,ttype);
218 :
219 : }
220 :
221 : //----------------------------------------------------------------------------
222 2 : NewCalTable::NewCalTable(String tableName, String CorF,
223 : Int nObs, Int nScanPerObs, Int nTimePerScan,
224 : Int nAnt, Int nSpw, Vector<Int> nChan,
225 : Int nFld,
226 : Double rTime, Double tint,
227 2 : Bool disk, Bool verbose) :
228 2 : Table()
229 : {
230 :
231 2 : String caltype("");
232 2 : if (CorF=="Complex")
233 2 : caltype="T";
234 0 : else if (CorF=="Float")
235 0 : caltype="K";
236 : else
237 0 : throw(AipsError("CorF must be 'Complex' or 'Float'"));
238 :
239 4 : CTDesc nctd(CorF,"none",caltype,"circ");
240 :
241 : // Form underlying generic Table according to the supplied desc
242 4 : SetupNewTable calMainTab(tableName+".tempMemCalTable",nctd.calMainDesc(),Table::New);
243 2 : Table tab(calMainTab, Table::Memory, 0, false);
244 2 : *this = tab;
245 :
246 : // Set the table info record
247 2 : this->setTableInfo();
248 :
249 : // Add (empty) subtables
250 2 : this->createSubTables();
251 :
252 : // Fill it generically
253 2 : this->fillGenericContents(nObs,nScanPerObs,nTimePerScan,
254 : nAnt,nSpw,nChan,
255 : nFld,rTime,tint,verbose);
256 :
257 2 : if (disk) {
258 : // Write it out to disk
259 0 : if (verbose) cout << "Writing out to disk: "+tableName << endl;
260 0 : this->writeToDisk(tableName);
261 : }
262 :
263 2 : }
264 :
265 : // Create an empty NewCalTable from a SimpleSimVi2Parameters object
266 0 : NewCalTable::NewCalTable(String tableName, String CorF, String caltype,
267 : const vi::SimpleSimVi2Parameters& ssp,
268 0 : Bool disk,Bool verbose) :
269 0 : Table()
270 : {
271 :
272 0 : if (CorF!="Complex" &&
273 0 : CorF!="Float")
274 0 : throw(AipsError("CorF must be 'Complex' or 'Float'"));
275 :
276 0 : CTDesc nctd(CorF,"none",caltype,"circ");
277 :
278 : // Form underlying generic Table according to the supplied desc
279 0 : SetupNewTable calMainTab(tableName+".tempMemCalTable",nctd.calMainDesc(),Table::New);
280 0 : Table tab(calMainTab, Table::Memory, 0, false);
281 0 : *this = tab;
282 :
283 : // Set the table info record
284 0 : this->setTableInfo();
285 :
286 : // Add (empty) subtables
287 0 : this->createSubTables();
288 :
289 : // Fill generic subtables, according to SimpleSimVi2Parameters
290 0 : fillGenericObs(ssp);
291 0 : fillGenericField(ssp);
292 0 : fillGenericAntenna(ssp);
293 0 : fillGenericSpw(ssp);
294 :
295 0 : if (disk) {
296 : // Write it out to disk
297 0 : if (verbose) cout << "Writing out to disk: "+tableName << endl;
298 0 : this->writeToDisk(tableName);
299 : }
300 :
301 0 : }
302 :
303 :
304 :
305 : //----------------------------------------------------------------------------
306 :
307 109014 : NewCalTable::NewCalTable (const Table& table): Table(table)
308 : {
309 : // Construct from an existing table object
310 : //cerr<<"constructed from an existing newcaltable as table"<<endl;
311 109014 : attachSubTables();
312 109014 : };
313 :
314 : //----------------------------------------------------------------------------
315 :
316 13427 : NewCalTable::NewCalTable (const NewCalTable& other): Table(other)
317 : {
318 : // Copy constructor
319 : // Input:
320 : // other const NewCalTable& Existing NewCalTable object
321 : //
322 : //cerr<<"copy constructor ...."<<endl;
323 13427 : copyMemCalSubtables(other);
324 13427 : attachSubTables();
325 13427 : };
326 :
327 : //----------------------------------------------------------------------------
328 :
329 6165 : NewCalTable& NewCalTable::operator= (const NewCalTable& other)
330 : {
331 : // Assignment operator
332 : // Input:
333 : // other const CalTable& RHS CalTable object
334 : //
335 : //cerr<<"assignment operator..."<<endl;
336 6165 : if (this != &other) {
337 6165 : clearSubtables();
338 6165 : Table::operator=(other);
339 6165 : if (!conformant(this->tableDesc()))
340 0 : throw (AipsError("NewCalTable( const NewCalTable&) - "
341 0 : "table is not a valid caltable"));
342 6165 : attachSubTables();
343 : }
344 6165 : return *this;
345 : };
346 :
347 :
348 : //----------------------------------------------------------------------------
349 :
350 : // Handle backward compatibility
351 458 : Bool NewCalTable::CTBackCompat(const String& caltable) {
352 :
353 458 : Bool doBC(false);
354 :
355 : // Detect backward compatibility issues
356 458 : Table tab(caltable,Table::Old);
357 :
358 : // pre-v41 had no OBSERVATION/OBSERVATION_ID
359 1364 : doBC=(!tab.tableDesc().isColumn(NCT::fieldName(NCT::OBSERVATION_ID)) ||
360 906 : !tab.keywordSet().isDefined("OBSERVATION"));
361 :
362 458 : if (doBC)
363 10 : NewCalTable backcompat(caltable,Table::Update,Table::Plain);
364 :
365 458 : return true;
366 :
367 458 : }
368 :
369 :
370 : //----------------------------------------------------------------------------
371 3253 : void NewCalTable::setTableInfo() {
372 3253 : this->tableInfo().setType(TableInfo::type(TableInfo::ME_CALIBRATION));
373 3253 : this->tableInfo().setSubType(this->tableDesc().getType());
374 3253 : }
375 :
376 : //----------------------------------------------------------------------------
377 482 : void NewCalTable::createSubTables() {
378 :
379 : // Names
380 482 : String calObsName=this->tableName()+"/OBSERVATION";
381 482 : String calAntennaName=this->tableName()+"/ANTENNA";
382 482 : String calFieldName=this->tableName()+"/FIELD";
383 482 : String calSpectralWindowName=this->tableName()+"/SPECTRAL_WINDOW";
384 482 : String calHistoryName=this->tableName()+"/HISTORY";
385 :
386 482 : Table::TableOption access(Table::TableOption(this->tableOption()));
387 482 : Table::TableType type(this->tableType());
388 :
389 : // Assign them to keywords
390 482 : SetupNewTable obstab(calObsName,CTObservation::requiredTableDesc(),access);
391 482 : this->rwKeywordSet().defineTable("OBSERVATION", Table(obstab,type));
392 482 : observation_p = CTObservation(this->keywordSet().asTable("OBSERVATION"));
393 :
394 482 : SetupNewTable antennatab(calAntennaName,CTAntenna::requiredTableDesc(),access);
395 482 : this->rwKeywordSet().defineTable("ANTENNA", Table(antennatab,type));
396 482 : antenna_p = CTAntenna(this->keywordSet().asTable("ANTENNA"));
397 :
398 482 : SetupNewTable fieldtab(calFieldName,CTField::requiredTableDesc(),access);
399 482 : this->rwKeywordSet().defineTable("FIELD", Table(fieldtab,type));
400 482 : field_p = CTField(this->keywordSet().asTable("FIELD"));
401 :
402 482 : SetupNewTable spwtab(calSpectralWindowName,CTSpectralWindow::requiredTableDesc(),access);
403 482 : this->rwKeywordSet().defineTable("SPECTRAL_WINDOW", Table(spwtab,type));
404 482 : spectralWindow_p = CTSpectralWindow(this->keywordSet().asTable("SPECTRAL_WINDOW"));
405 :
406 482 : SetupNewTable histab(calHistoryName,CTHistory::requiredTableDesc(),access);
407 482 : this->rwKeywordSet().defineTable("HISTORY", Table(histab,type));
408 482 : history_p = CTHistory(this->keywordSet().asTable("HISTORY"));
409 482 : };
410 :
411 :
412 : //----------------------------------------------------------------------------
413 129371 : void NewCalTable::attachSubTables()
414 : {
415 :
416 129371 : if (this->keywordSet().isDefined("OBSERVATION"))
417 122865 : observation_p = CTObservation(this->keywordSet().asTable("OBSERVATION"));
418 :
419 129371 : if (this->keywordSet().isDefined("ANTENNA"))
420 122865 : antenna_p = CTAntenna(this->keywordSet().asTable("ANTENNA"));
421 :
422 129371 : if (this->keywordSet().isDefined("FIELD"))
423 122865 : field_p = CTField(this->keywordSet().asTable("FIELD"));
424 :
425 129371 : if (this->keywordSet().isDefined("SPECTRAL_WINDOW"))
426 122865 : spectralWindow_p = CTSpectralWindow(this->keywordSet().asTable("SPECTRAL_WINDOW"));
427 :
428 129371 : if (this->keywordSet().isDefined("HISTORY"))
429 122865 : history_p = CTHistory(this->keywordSet().asTable("HISTORY"));
430 :
431 129371 : }
432 :
433 : //----------------------------------------------------------------------------
434 6165 : void NewCalTable::clearSubtables()
435 : {
436 6165 : observation_p=CTObservation();
437 6165 : antenna_p=CTAntenna();
438 6165 : field_p=CTField();
439 6165 : spectralWindow_p=CTSpectralWindow();
440 6165 : history_p = CTHistory();
441 6165 : }
442 : //----------------------------------------------------------------------------
443 13427 : void NewCalTable::copyMemCalSubtables(const NewCalTable & other)
444 : {
445 13427 : copyMemCalSubtable(other.observation_p, observation_p);
446 13427 : copyMemCalSubtable(other.antenna_p, antenna_p);
447 13427 : copyMemCalSubtable(other.field_p, field_p);
448 13427 : copyMemCalSubtable(other.spectralWindow_p, spectralWindow_p);
449 13427 : copyMemCalSubtable(other.history_p, history_p);
450 13427 : }
451 : //----------------------------------------------------------------------------
452 67135 : void NewCalTable::copyMemCalSubtable(const Table & otherCalsubtable, Table & calSubtable )
453 : {
454 : //if (! otherCalsubtable.isNull () && otherCalsubtable.tableType() == Table::Memory){
455 67135 : if (! otherCalsubtable.isNull ()){
456 66950 : calSubtable = otherCalsubtable;
457 : }
458 67135 : }
459 :
460 : //----------------------------------------------------------------------------
461 128 : Bool NewCalTable::isComplex() {
462 128 : return (this->keywordSet().asString("ParType")=="Complex");
463 : }
464 :
465 : //----------------------------------------------------------------------------
466 0 : String NewCalTable::polBasis() {
467 0 : return this->keywordSet().asString("PolBasis");
468 : }
469 :
470 : //----------------------------------------------------------------------------
471 5 : String NewCalTable::CASAvers() {
472 5 : if (this->keywordSet().fieldNumber("CASA_Version")==-1)
473 : // Handle non-existent keyword
474 0 : return String("Unknown");
475 : else
476 5 : return this->keywordSet().asString("CASA_Version");
477 : }
478 :
479 : //----------------------------------------------------------------------------
480 0 : Record NewCalTable::getRowMain (const Int& jrow)
481 : {
482 : // Get a row from cal_main
483 : // Input:
484 : // jrow const Int& Row number
485 : // Output:
486 : // getRowMain Record Row record
487 : //
488 0 : ROTableRow trow (*this);
489 0 : trow.get (jrow);
490 0 : return trow.record();
491 0 : };
492 :
493 : //----------------------------------------------------------------------------
494 0 : void NewCalTable::putRowMain (const Int& jrow, CTMainRecord& tableRec)
495 : {
496 : // Get a row from cal_main
497 : // Input:
498 : // jrow const Int& Row number
499 : // tableRec const CalMainRecord& Table record
500 : //
501 : // Add rows as required
502 0 : Int nMaxRow = this->nrow();
503 0 : Int nAdd = jrow - nMaxRow + 1;
504 0 : if (nAdd > 0) {
505 0 : this->addRow (nAdd);
506 : };
507 :
508 : // Write the record
509 0 : TableRow trow (*this);
510 0 : TableRecord trec = tableRec.record();
511 0 : trow.putMatchingFields (jrow, trec);
512 0 : };
513 :
514 : //----------------------------------------------------------------------------
515 480 : void NewCalTable::setMetaInfo(const String& msName)
516 : {
517 : // set Meta data info:
518 : // put parent MS name and (for now) make copy of Antenna, Field, and SpW
519 : // sub-tables.
520 480 : MeasurementSet inms(msName);
521 480 : const MSObservation msobstab = inms.observation();
522 480 : const MSAntenna msantab = inms.antenna();
523 480 : const MSField msfldtab = inms.field();
524 480 : const MSSpectralWindow msspwtab = inms.spectralWindow();
525 :
526 : // deep copy subtables from an MS to NCT
527 : // by TableCopy::copyRows
528 : //copy obs table
529 480 : CTObservation calobstab(this->observation());
530 480 : TableCopy::copyRows(calobstab,msobstab);
531 : //copy antenna table
532 480 : CTAntenna calantab(this->antenna());
533 480 : TableCopy::copyRows(calantab,msantab);
534 :
535 : //copy field table
536 480 : CTField calfldtab(this->field());
537 480 : TableCopy::copyRows(calfldtab,msfldtab);
538 :
539 : // copy nominal Eph object directions into CTField
540 480 : handleEphObj(msfldtab,msName);
541 :
542 : //copy spectralWindow table
543 480 : CTSpectralWindow calspwtab(this->spectralWindow());
544 480 : TableCopy::copyRows(calspwtab,msspwtab);
545 :
546 : // Record only the basename of the MS
547 480 : this->rwKeywordSet().define(RecordFieldId("MSName"),Path(msName).baseName());
548 480 : }
549 :
550 480 : void NewCalTable::handleEphObj(const MSField& msfldtab,const String& msName) {
551 :
552 : // If EPHEMERIS_ID column exists in the MS FIELD subtable, we
553 : // may have some Eph Objects to get directions for.
554 480 : const String ephColName = MSField::columnName(MSField::EPHEMERIS_ID);
555 480 : if (msfldtab.actualTableDesc().isColumn(ephColName)) {
556 344 : MSFieldColumns msfcol(msfldtab);
557 344 : Vector<Int> ephid=msfcol.ephemerisId().getColumn();
558 :
559 : // Do nothing if no eph objects
560 344 : if (max(ephid)<0) return;
561 :
562 0 : const MeasurementSet ms(msName);
563 0 : MSMetaData msmd(&ms,-1.0f);
564 0 : CTFieldColumns ctfcol(field_p);
565 0 : for (uInt i=0;i<ephid.nelements();++i) {
566 0 : if (ephid(i)>-1) {
567 0 : Matrix<Double> dir(2,1,0.0);
568 : // Calculate nominal position from the MS
569 0 : dir=msmd.getReferenceDirection(i).getAngle().getValue();
570 : // Write the nominal position into the caltable dir columns
571 0 : ctfcol.referenceDir().put(i,dir);
572 0 : ctfcol.phaseDir().put(i,dir);
573 0 : ctfcol.delayDir().put(i,dir);
574 0 : }
575 : }
576 688 : }
577 480 : }
578 :
579 :
580 : //----------------------------------------------------------------------------
581 6165 : Bool NewCalTable::conformant(const TableDesc& tabDesc)
582 : {
583 : // Check if input table description is confomrant with
584 : // the new caltable format (or should I named this "validate" ...as
585 : // in MS case...)
586 6165 : Bool eqDType=false;
587 6165 : CTDesc calTD = CTDesc(false); // opt out of OBS_ID, because we aren't insisting on it yet
588 6165 : TableDesc requiredCalTD = calTD.calMainDesc();
589 6165 : Bool isCalTableDesc = tabDesc.columnDescSet().isSuperset(requiredCalTD.columnDescSet(), eqDType);
590 6165 : if (!isCalTableDesc) {
591 0 : cerr<<"NewCalTable::conformant: tabDesc is not superset of requiredCalMain"<<endl;
592 : };
593 6165 : Vector<String> colNames(requiredCalTD.columnNames());
594 6165 : Vector<String> incolNames(tabDesc.columnNames());
595 6165 : uInt ncols = colNames.nelements();
596 73980 : for (uInt j=0; j < ncols; j++) {
597 : }
598 6165 : Bool check = true;
599 73980 : for (uInt i=0; i < ncols; i++) {
600 67815 : TableRecord keySet = tabDesc[colNames(i)].keywordSet();
601 67815 : TableRecord reqKeySet = requiredCalTD[colNames(i)].keywordSet();
602 67815 : if (reqKeySet.isDefined("QuantumUnits")) {
603 12330 : check = keySet.isDefined("QuantumUnits");
604 12330 : if (!check) {
605 0 : cerr<<"NewCalTable::conformant: column:"<<colNames(i)<<" does not have a unit"<<endl;
606 : }
607 : else {
608 12330 : check = allEQ(keySet.asArrayString("QuantumUnits"), reqKeySet.asArrayString("QuantumUnits"));
609 12330 : if (!check) {
610 0 : cerr<<"NewCalTable::conformant column:"<<colNames(i)
611 0 : <<" has an invalid QuantumUnits:"<<keySet.asArrayString("QuantumUnits")<<endl;
612 : }
613 : }
614 : }
615 67815 : }
616 12330 : return isCalTableDesc && check;
617 6165 : };
618 :
619 : //----------------------------------------------------------------------------
620 504 : void NewCalTable::writeToDisk(const String& outTableName)
621 : {
622 504 : Block<String> sortcols(4);
623 504 : sortcols[0]="SPECTRAL_WINDOW_ID";
624 504 : sortcols[1]="TIME";
625 504 : sortcols[2]="ANTENNA1";
626 504 : sortcols[3]="ANTENNA2";
627 504 : Table sorted = this->sort(sortcols,Sort::Ascending,Sort::HeapSort);
628 504 : sorted.deepCopy(outTableName,Table::New);
629 504 : };
630 :
631 780 : Complex NewCalTable::NCTtestvalueC(Int iant,Int ispw,Double ich,Double time,Double refTime,Double tint) {
632 :
633 780 : Double a=1.0 + Double(iant)/10.0 + Double(ispw)/100.0 + ich/10000.0;
634 780 : Double dt=(time-refTime)/tint;
635 780 : Double p=dt+ich/100.0;
636 780 : return Complex(Float(a*cos(p)),Float(a*sin(p)));
637 :
638 : }
639 :
640 0 : Float NewCalTable::NCTtestvalueF(Int iant,Int ispw,Double ich,Double time,Double refTime,Double tint) {
641 :
642 0 : Double dt=(time-refTime)/tint;
643 0 : Double a=dt + Double(iant)/10.0 + Double(ispw)/100.0 + ich/10000.0;
644 0 : return Float(a);
645 :
646 : }
647 :
648 :
649 : //----------------------------------------------------------------------------
650 2 : void NewCalTable::fillGenericContents(Int nObs, Int nScanPerObs,Int nTimePerScan,
651 : Int nAnt, Int nSpw, Vector<Int> nChan,
652 : Int nFld,
653 : Double rTime, Double tint,
654 : Bool verbose) {
655 :
656 : // Cope with unspecified time info
657 2 : if (rTime==0.0) rTime=4832568000.0;
658 2 : if (tint==0.0) tint=60.0;
659 :
660 2 : if (verbose) {
661 0 : cout << nFld << " "
662 0 : << nAnt << " "
663 0 : << nSpw << " "
664 0 : << nChan << " "
665 0 : << nObs << " "
666 0 : << nScanPerObs << " "
667 0 : << nTimePerScan << " "
668 0 : << endl;
669 0 : cout.precision(15);
670 : }
671 :
672 : // fill subtables
673 2 : fillGenericObs(nObs);
674 2 : fillGenericField(nFld);
675 2 : fillGenericAntenna(nAnt);
676 2 : fillGenericSpw(nSpw,nChan);
677 :
678 : // The per-solution antenna indices
679 2 : Vector<Int> antlist(nAnt);
680 2 : indgen(antlist);
681 2 : Int refant=0; // for ANTENNA2
682 :
683 : // T-like
684 2 : Int nPar(1);
685 :
686 2 : Double thistime(rTime-tint); // first sample will be at rTime
687 :
688 2 : CTMainColumns ncmc(*this);
689 :
690 2 : Int thisscan(0);
691 7 : for (Int iobs=0;iobs<nObs;++iobs) {
692 5 : if (verbose) cout << "Obs=" << iobs << endl;
693 5 : Int thisfield(-1);
694 14 : for (Int iscan=0;iscan<nScanPerObs;++iscan) {
695 9 : thisscan+=1; // unique scans
696 9 : thisfield+=1; // each scan is a new field
697 9 : thisfield=thisfield%nFld; // never more than nFld-1
698 9 : if (verbose) cout << " Scan=" << thisscan << " Field=" <<thisfield << endl;
699 36 : for (Int itime=0;itime<nTimePerScan;++itime) {
700 27 : thistime+=tint; // every tint
701 27 : if (verbose) cout << " Time="<< thistime << endl;
702 :
703 105 : for (Int ispw=0;ispw<nSpw;++ispw) {
704 :
705 78 : if (verbose) cout << " Spw=" << ispw << endl;
706 :
707 : // add rows
708 78 : Int nAddRows=nAnt;
709 78 : RefRows rows(this->nrow(),this->nrow()+nAddRows-1,1);
710 78 : this->addRow(nAddRows);
711 :
712 78 : if (verbose) cout << " Adding " << nAnt << " rows; total=" << this->nrow() << endl;
713 :
714 : // fill columns in new rows
715 78 : ncmc.time().putColumnCells(rows,Vector<Double>(nAddRows,thistime));
716 78 : ncmc.interval().putColumnCells(rows,Vector<Double>(nAddRows,tint));
717 78 : ncmc.fieldId().putColumnCells(rows,Vector<Int>(nAddRows,thisfield));
718 78 : ncmc.spwId().putColumnCells(rows,Vector<Int>(nAddRows,ispw));
719 78 : ncmc.antenna1().putColumnCells(rows,antlist);
720 78 : ncmc.antenna2().putColumnCells(rows,Vector<Int>(nAddRows,refant));
721 78 : ncmc.obsId().putColumnCells(rows,Vector<Int>(nAddRows,iobs));
722 78 : ncmc.scanNo().putColumnCells(rows,Vector<Int>(nAddRows,thisscan));
723 :
724 :
725 78 : if (isComplex()) {
726 78 : Cube<Complex> par(nPar,nChan(ispw),nAddRows);
727 858 : for (Int iant=0;iant<nAnt;++iant) {
728 1560 : for (Int ich=0;ich<nChan(ispw);++ich) {
729 780 : par.xyPlane(iant).column(ich)=NCTtestvalueC(iant,ispw,ich,thistime,rTime,tint);
730 : }
731 : }
732 78 : ncmc.cparam().putColumnCells(rows,par);
733 78 : }
734 : else {
735 0 : Cube<Float> par(nPar,nChan(ispw),nAddRows);
736 0 : for (Int iant=0;iant<nAnt;++iant) {
737 0 : for (Int ich=0;ich<nChan(ispw);++ich) {
738 0 : par.xyPlane(iant).column(ich)=NCTtestvalueF(iant,ispw,ich,thistime,rTime,tint);
739 : }
740 : }
741 0 : ncmc.fparam().putColumnCells(rows,par);
742 0 : }
743 :
744 78 : Cube<Float> parerr(nPar,nChan(ispw),nAddRows);
745 78 : parerr=0.001;
746 78 : ncmc.paramerr().putColumnCells(rows,parerr);
747 78 : Cube<Float> snr(nPar,nChan(ispw),nAddRows);
748 78 : snr=999.0;
749 78 : ncmc.snr().putColumnCells(rows,snr);
750 78 : Cube<Float> wt(nPar,nChan(ispw),nAddRows);
751 78 : wt=1.0;
752 78 : ncmc.weight().putColumnCells(rows,wt);
753 78 : Cube<Bool> flag(nPar,nChan(ispw),nAddRows);
754 78 : flag=false;
755 78 : ncmc.flag().putColumnCells(rows,flag);
756 78 : }
757 : }
758 : }
759 : }
760 :
761 2 : }
762 :
763 : //----------------------------------------------------------------------------
764 25 : void NewCalTable::fillGenericObs(Int nObs) {
765 :
766 25 : this->observation().addRow(nObs);
767 25 : MSObservationColumns oc(this->observation());
768 25 : Vector<Double> tr(2,0.0);
769 25 : tr(1)=7609161600.0; // the year 2100 (forever-ish)
770 53 : for (Int iobs=0;iobs<nObs;++iobs) {
771 28 : oc.timeRange().put(iobs,tr);
772 28 : oc.observer().put(iobs,String("unknown"));
773 28 : oc.project().put(iobs,String("unknown"));
774 28 : oc.telescopeName().put(iobs,String("unknown"));
775 28 : oc.flagRow().put(iobs,false);
776 : }
777 25 : }
778 :
779 : //----------------------------------------------------------------------------
780 2 : void NewCalTable::fillGenericField(Int nFld) {
781 :
782 2 : this->field().addRow(nFld);
783 2 : MSFieldColumns fc(this->field());
784 5 : for (Int ifld=0;ifld<nFld;++ifld) {
785 3 : fc.name().put(ifld,("Field_"+String::toString(ifld)));
786 3 : fc.flagRow().put(ifld,false);
787 : }
788 2 : }
789 :
790 :
791 :
792 : //----------------------------------------------------------------------------
793 2 : void NewCalTable::fillGenericAntenna(Int nAnt) {
794 :
795 2 : this->antenna().addRow(nAnt);
796 2 : MSAntennaColumns ac(this->antenna());
797 22 : for (Int iant=0;iant<nAnt;++iant) {
798 20 : ac.name().put(iant,("Antenna_"+String::toString(iant)));
799 20 : ac.station().put(iant,("Station_"+String::toString(iant)));
800 20 : ac.type().put(iant,"GROUND-BASED");
801 20 : ac.mount().put(iant,"ALT-AZ");
802 20 : ac.dishDiameter().put(iant,25.0);
803 20 : ac.offset().put(iant,Vector<Double>(3,0.0));
804 20 : ac.position().put(iant,Vector<Double>(3,0.0));
805 20 : ac.flagRow().put(iant,false);
806 : }
807 :
808 2 : }
809 :
810 :
811 : //----------------------------------------------------------------------------
812 2 : void NewCalTable::fillGenericSpw(Int nSpw,Vector<Int>& nChan) {
813 :
814 2 : this->spectralWindow().addRow(nSpw);
815 2 : MSSpWindowColumns sc(this->spectralWindow());
816 7 : for (Int ispw=0;ispw<nSpw;++ispw) {
817 5 : Double refFreq(60.0e9+Double(ispw)*1.0e9); // Every GHz
818 5 : Double width(1.0e6); // 1 MHz channels
819 5 : Vector<Double> chanfreq(nChan(ispw),refFreq);
820 10 : for (Int ich=0;ich<nChan(ispw);++ich) chanfreq(ich)+=(Double(ich)+0.5)*width;
821 :
822 5 : sc.name().put(ispw,("SPW_"+String::toString(ispw)));
823 5 : sc.refFrequency().put(ispw,refFreq);
824 5 : sc.numChan().put(ispw,nChan(ispw));
825 5 : sc.chanFreq().put(ispw,chanfreq);
826 :
827 5 : Vector<Double> res(nChan(ispw),width);
828 :
829 5 : sc.chanWidth().put(ispw,res);
830 5 : sc.effectiveBW().put(ispw,res);
831 5 : sc.resolution().put(ispw,res);
832 5 : sc.totalBandwidth().put(ispw,sum(res));
833 5 : sc.flagRow().put(ispw,false);
834 5 : }
835 2 : }
836 :
837 : //----------------------------------------------------------------------------
838 0 : void NewCalTable::fillGenericObs(const vi::SimpleSimVi2Parameters& /*ssp*/) {
839 0 : this->fillGenericObs(1); // Just one, for now
840 0 : }
841 :
842 : //----------------------------------------------------------------------------
843 0 : void NewCalTable::fillGenericField(const vi::SimpleSimVi2Parameters& ssp) {
844 0 : this->fillGenericField(ssp.nField_);
845 0 : }
846 :
847 : //----------------------------------------------------------------------------
848 0 : void NewCalTable::fillGenericAntenna(const vi::SimpleSimVi2Parameters& ssp) {
849 0 : this->fillGenericAntenna(ssp.nAnt_);
850 0 : }
851 :
852 :
853 : //----------------------------------------------------------------------------
854 0 : void NewCalTable::fillGenericSpw(const vi::SimpleSimVi2Parameters& ssp) {
855 :
856 : // Gather info from the SimpleSimVi2Parameters
857 0 : const Int& nSpw(ssp.nSpw_);
858 0 : const Vector<Int>& nChan(ssp.nChan_);
859 :
860 0 : this->spectralWindow().addRow(nSpw);
861 0 : MSSpWindowColumns sc(this->spectralWindow());
862 0 : for (Int ispw=0;ispw<nSpw;++ispw) {
863 0 : const Double& refFreq(ssp.refFreq_(ispw));
864 0 : const Double& width(ssp.df_(ispw));
865 0 : Vector<Double> chanfreq(nChan(ispw),refFreq);
866 0 : for (Int ich=0;ich<nChan(ispw);++ich) chanfreq(ich)+=(Double(ich)+0.5)*width;
867 :
868 0 : sc.name().put(ispw,("SPW_"+String::toString(ispw)));
869 0 : sc.refFrequency().put(ispw,refFreq);
870 0 : sc.numChan().put(ispw,nChan(ispw));
871 0 : sc.chanFreq().put(ispw,chanfreq);
872 :
873 0 : Vector<Double> res(nChan(ispw),width);
874 :
875 0 : sc.chanWidth().put(ispw,res);
876 0 : sc.effectiveBW().put(ispw,res);
877 0 : sc.resolution().put(ispw,res);
878 0 : sc.totalBandwidth().put(ispw,sum(res));
879 0 : sc.flagRow().put(ispw,false);
880 0 : }
881 0 : }
882 :
883 :
884 :
885 : //----------------------------------------------------------------------------
886 18876 : void NewCalTable::fillAntBasedMainRows(uInt nrows,
887 : Double time,Double interval,
888 : Int fieldId,uInt spwId,Int scanNo,
889 : const Vector<Int>& ant1list, Int refant,
890 : const Cube<Complex>& cparam,
891 : const Cube<Bool>& flag,
892 : const Cube<Float>& paramErr,
893 : const Cube<Float>& snr) {
894 :
895 : // Forward to obsId-capable method with obsID=0
896 18876 : this->fillAntBasedMainRows(nrows,
897 : time,interval,
898 : fieldId,spwId,0,scanNo,
899 : ant1list,refant,
900 : cparam,flag,paramErr,snr);
901 :
902 18876 : }
903 :
904 18876 : void NewCalTable::fillAntBasedMainRows(uInt nrows,
905 : Double time,Double interval,
906 : Int fieldId,uInt spwId,Int obsId, Int scanNo,
907 : const Vector<Int>& ant1list, Int refant,
908 : const Cube<Complex>& cparam,
909 : const Cube<Bool>& flag,
910 : const Cube<Float>& paramErr,
911 : const Cube<Float>& snr) {
912 :
913 : // Verify that we are Complex
914 18876 : TableRecord keywords=this->keywordSet();
915 56628 : if (!keywords.isDefined("ParType") ||
916 37752 : keywords.asString("ParType")!="Complex")
917 0 : throw(AipsError("NewCalTable::fillAntBasedMainRows: NewCalTable's ParType is not Complex"));
918 :
919 : // First, verify internal consistency
920 18876 : IPosition csh=cparam.shape();
921 :
922 : // Data must conform to specified nrows
923 18876 : AlwaysAssert( (cparam.nplane()==nrows), AipsError);
924 18876 : AlwaysAssert( (cparam.shape()==flag.shape()), AipsError);
925 :
926 : // Stat arrays much match cparam shape
927 18876 : if (paramErr.nelements()>0)
928 18876 : AlwaysAssert( (paramErr.shape()==cparam.shape()), AipsError);
929 18876 : if (snr.nelements()>0)
930 18876 : AlwaysAssert( (snr.shape()==cparam.shape()), AipsError);
931 :
932 : // Specified indices must be rational
933 18876 : AlwaysAssert( (spwId<this->spectralWindow().nrow()), AipsError);
934 18876 : AlwaysAssert( (fieldId<Int(this->field().nrow())), AipsError);
935 :
936 : // Handle ant1list
937 18876 : Vector<Int> ant1;
938 18876 : if (ant1list.nelements()>0) {
939 0 : AlwaysAssert( (min(ant1list)>0), AipsError); // must be definite
940 0 : AlwaysAssert( (max(ant1list)<Int(this->antenna().nrow())), AipsError);
941 0 : ant1.reference(ant1list);
942 : }
943 : else {
944 : // Generate the ant1 list
945 18876 : ant1.resize(nrows);
946 18876 : indgen(ant1);
947 : }
948 :
949 : // All seems well, so add rows
950 18876 : RefRows rows(this->nrow(),this->nrow()+nrows-1,1);
951 18876 : this->addRow(nrows);
952 :
953 18876 : CTMainColumns mc(*this);
954 :
955 : // Meta-info (these are uniform for all rows)
956 18876 : mc.time().putColumnCells(rows,Vector<Double>(nrows,time));
957 18876 : mc.fieldId().putColumnCells(rows,Vector<Int>(nrows,fieldId));
958 18876 : mc.spwId().putColumnCells(rows,Vector<Int>(nrows,spwId));
959 18876 : mc.obsId().putColumnCells(rows,Vector<Int>(nrows,obsId));
960 18876 : mc.scanNo().putColumnCells(rows,Vector<Int>(nrows,scanNo));
961 18876 : mc.interval().putColumnCells(rows,Vector<Double>(nrows,interval));
962 :
963 : // Antenna
964 18876 : mc.antenna1().putColumnCells(rows,ant1);
965 18876 : mc.antenna2().putColumnCells(rows,Vector<Int>(nrows,refant)); // uniform
966 :
967 : // Complex CPARAM column
968 18876 : mc.cparam().putColumnCells(rows,cparam);
969 :
970 : // Fill stats
971 18876 : mc.flag().putColumnCells(rows,flag);
972 18876 : if (paramErr.nelements()>0)
973 18876 : mc.paramerr().putColumnCells(rows,paramErr);
974 : else
975 : // zeros, w/ correct shape
976 0 : mc.paramerr().putColumnCells(rows,Cube<Float>(csh,0.0));
977 18876 : if (snr.nelements()>0)
978 18876 : mc.snr().putColumnCells(rows,snr);
979 : else
980 : // ones, w/ correct shape
981 0 : mc.paramerr().putColumnCells(rows,Cube<Float>(csh,1.0));
982 :
983 18876 : }
984 :
985 0 : void NewCalTable::setSpwFreqs(Int spw, const Vector<Double>& freq,
986 : const Vector<Double>& chanwidth) {
987 :
988 :
989 0 : MSSpWindowColumns spwcol(this->spectralWindow());
990 :
991 0 : AlwaysAssert( (spw<Int(spwcol.nrow())), AipsError );
992 :
993 0 : uInt nchan=freq.nelements();
994 0 : IPosition sh(1,nchan);
995 :
996 0 : spwcol.numChan().put(spw,nchan);
997 0 : spwcol.chanFreq().setShape(spw,sh);
998 0 : spwcol.chanFreq().put(spw,freq);
999 :
1000 0 : if (chanwidth.nelements()==0) {
1001 :
1002 0 : if (nchan>1) {
1003 0 : Double width=freq(1)-freq(0);
1004 0 : Vector<Double> widthV(nchan,width);
1005 :
1006 0 : spwcol.chanWidth().setShape(spw,sh);
1007 0 : spwcol.chanWidth().put(spw,widthV);
1008 0 : spwcol.resolution().setShape(spw,sh);
1009 0 : spwcol.resolution().put(spw,widthV);
1010 0 : spwcol.effectiveBW().setShape(spw,sh);
1011 0 : spwcol.effectiveBW().put(spw,widthV);
1012 :
1013 0 : Double totalBW=nchan*width;
1014 0 : spwcol.totalBandwidth().put(spw,totalBW);
1015 0 : }
1016 : else
1017 0 : throw(AipsError("NewCalTable::setSpwFreqs: Problem resetting SPECTRAL_WINDOW info"));
1018 :
1019 :
1020 : }
1021 : else {
1022 0 : AlwaysAssert( (chanwidth.nelements()==nchan), AipsError);
1023 :
1024 0 : spwcol.chanWidth().setShape(spw,sh);
1025 0 : spwcol.chanWidth().put(spw,chanwidth);
1026 0 : spwcol.resolution().setShape(spw,sh);
1027 0 : spwcol.resolution().put(spw,chanwidth);
1028 0 : spwcol.effectiveBW().setShape(spw,sh);
1029 0 : spwcol.effectiveBW().put(spw,chanwidth);
1030 :
1031 0 : spwcol.totalBandwidth().put(spw,sum(chanwidth));
1032 :
1033 : }
1034 :
1035 :
1036 0 : }
1037 :
1038 : // Set FLAG_ROW in SPECTRAL_WINDOW subtable for spws absent in MAIN
1039 : // (this enables append to permit revision when appropriate)
1040 473 : void NewCalTable::flagAbsentSpws() {
1041 :
1042 473 : CTColumns ctcol(*this);
1043 :
1044 : // Extract unique spws in MAIN
1045 473 : Vector<Int> spwids;
1046 473 : ctcol.spwId().getColumn(spwids);
1047 473 : Int nspw=genSort(spwids,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
1048 473 : spwids.resize(nspw,true);
1049 :
1050 : // Revise SPW FLAG_ROW
1051 473 : Vector<Bool> spwfr;
1052 473 : ctcol.spectralWindow().flagRow().getColumn(spwfr);
1053 473 : spwfr.set(true);
1054 6637 : for (Int ispw=0;ispw<nspw;++ispw) {
1055 6164 : uInt thisspw=spwids(ispw);
1056 6164 : if (thisspw<spwfr.nelements())
1057 6164 : spwfr(thisspw)=false; // unflagged
1058 : else
1059 0 : throw(AipsError("NewCalTable::flagAbsentSpws: Main table contains spwids not in SpW subtable"));
1060 : }
1061 :
1062 : // Put FLAG_ROW back
1063 473 : ctcol.spectralWindow().flagRow().putColumn(spwfr);
1064 :
1065 473 : }
1066 : // Merge SPW subtable rows from another NewCalTable
1067 6 : void NewCalTable::mergeSpwMetaInfo(const NewCalTable& other) {
1068 :
1069 : // Access this' SPW subtable
1070 6 : CTSpWindowColumns spwcols(this->spectralWindow());
1071 :
1072 : // Access other's SPW subtable
1073 6 : ROCTSpWindowColumns ospwcols(other.spectralWindow());
1074 :
1075 : // Just make sure that they have the same number of rows:
1076 : // (should be guaranteed by having been derived from the same MS)
1077 6 : if (spwcols.nrow()!=ospwcols.nrow())
1078 0 : throw(AipsError("NewCalTable::mergeSpwMetaInfo: Attempt to merge unrelated SPW subtables."));
1079 :
1080 : // Loop over other's spws
1081 6 : uInt onspw=ospwcols.nrow();
1082 25 : for (uInt ispw=0;ispw<onspw;++ispw) {
1083 :
1084 : // Only if other's ispw is not flagged...
1085 19 : if (!ospwcols.flagRow()(ispw)) {
1086 :
1087 : try {
1088 :
1089 : // Certain meta info must already be equivalent
1090 12 : AlwaysAssert( spwcols.name()(ispw)==ospwcols.name()(ispw), AipsError);
1091 12 : AlwaysAssert( spwcols.measFreqRef()(ispw)==ospwcols.measFreqRef()(ispw), AipsError);
1092 12 : AlwaysAssert( spwcols.netSideband()(ispw)==ospwcols.netSideband()(ispw), AipsError);
1093 12 : AlwaysAssert( spwcols.ifConvChain()(ispw)==ospwcols.ifConvChain()(ispw), AipsError);
1094 12 : AlwaysAssert( spwcols.freqGroup()(ispw)==ospwcols.freqGroup()(ispw), AipsError);
1095 12 : AlwaysAssert( spwcols.freqGroupName()(ispw)==ospwcols.freqGroupName()(ispw), AipsError);
1096 : }
1097 0 : catch ( AipsError x ) {
1098 0 : throw(AipsError("Spw meta information incongruent; cannot merge it for append."));
1099 0 : }
1100 :
1101 : // ...and this' ispw _is_ flagged
1102 12 : if (spwcols.flagRow()(ispw)) {
1103 :
1104 : // Copy from other to this:
1105 1 : Int nchan=ospwcols.numChan()(ispw);
1106 1 : IPosition sh(1,nchan);
1107 :
1108 1 : spwcols.numChan().put(ispw,nchan);
1109 1 : spwcols.chanFreq().setShape(ispw,sh);
1110 1 : spwcols.chanFreq().put(ispw,ospwcols.chanFreq()(ispw));
1111 1 : spwcols.chanWidth().setShape(ispw,sh);
1112 1 : spwcols.chanWidth().put(ispw,ospwcols.chanWidth()(ispw));
1113 1 : spwcols.resolution().setShape(ispw,sh);
1114 1 : spwcols.resolution().put(ispw,ospwcols.resolution()(ispw));
1115 1 : spwcols.effectiveBW().setShape(ispw,sh);
1116 1 : spwcols.effectiveBW().put(ispw,ospwcols.effectiveBW()(ispw));
1117 :
1118 1 : spwcols.refFrequency().put(ispw,ospwcols.refFrequency()(ispw));
1119 1 : spwcols.totalBandwidth().put(ispw,ospwcols.totalBandwidth()(ispw));
1120 :
1121 : // this' row now unflagged
1122 1 : spwcols.flagRow().put(ispw,false);
1123 :
1124 1 : }
1125 : else {
1126 :
1127 : try {
1128 :
1129 : // Assert equivalence in all meaningful rows
1130 11 : AlwaysAssert( spwcols.numChan()(ispw)==ospwcols.numChan()(ispw), AipsError);
1131 11 : AlwaysAssert( allEQ(spwcols.chanFreq()(ispw),ospwcols.chanFreq()(ispw)), AipsError);
1132 11 : AlwaysAssert( allEQ(spwcols.chanWidth()(ispw),ospwcols.chanWidth()(ispw)), AipsError);
1133 11 : AlwaysAssert( allEQ(spwcols.resolution()(ispw),ospwcols.resolution()(ispw)), AipsError);
1134 11 : AlwaysAssert( allEQ(spwcols.effectiveBW()(ispw),ospwcols.effectiveBW()(ispw)), AipsError);
1135 11 : AlwaysAssert( spwcols.refFrequency()(ispw)==ospwcols.refFrequency()(ispw), AipsError);
1136 11 : AlwaysAssert( spwcols.totalBandwidth()(ispw)==ospwcols.totalBandwidth()(ispw), AipsError);
1137 : }
1138 0 : catch ( AipsError err ) {
1139 0 : throw(AipsError("Error merging spw="+String::toString(ispw)+"'s meta info"));
1140 0 : }
1141 : }
1142 : }
1143 :
1144 : } // ispw
1145 :
1146 :
1147 6 : }
1148 :
1149 :
1150 :
1151 :
1152 25 : void NewCalTable::addHistoryMessage(String app, String message) {
1153 :
1154 25 : Int row=this->history().nrow();
1155 25 : this->history().addRow(1);
1156 :
1157 25 : MSHistoryColumns hcol(this->history());
1158 :
1159 : // Add the current data
1160 25 : Time date;
1161 50 : MEpoch now(MVEpoch(date.modifiedJulianDay()),MEpoch::Ref(MEpoch::UTC));
1162 25 : hcol.timeMeas().put(row,now);
1163 :
1164 : // The application
1165 25 : hcol.application().put(row,app);
1166 :
1167 : // Write the message
1168 25 : hcol.message().put(row,message);
1169 :
1170 : // Fill in some other columns with emptiness
1171 25 : hcol.objectId().put(row,-1);
1172 25 : hcol.observationId().put(row,-1);
1173 :
1174 25 : }
1175 :
1176 37 : void NewCalTable::makeSpwSingleChan() {
1177 :
1178 37 : MSSpWindowColumns spwcol(this->spectralWindow());
1179 :
1180 : // Reset each spw to a single channel
1181 670 : for (uInt ispw=0;ispw<spwcol.nrow();++ispw) {
1182 :
1183 : Int nchan;
1184 633 : spwcol.numChan().get(ispw,nchan);
1185 633 : IPosition ip(1,1);
1186 633 : if (nchan>1) {
1187 527 : Vector<Double> midFreq;
1188 527 : spwcol.chanFreq().get(ispw,midFreq);
1189 527 : midFreq(0)=midFreq(nchan/2);
1190 527 : midFreq.resize(1,true);
1191 : Double totBW;
1192 527 : spwcol.totalBandwidth().get(ispw,totBW);
1193 527 : Vector<Double> totBWv(1,totBW);
1194 :
1195 527 : spwcol.numChan().put(ispw,1);
1196 :
1197 527 : spwcol.chanFreq().setShape(ispw,ip);
1198 527 : spwcol.chanFreq().put(ispw,midFreq);
1199 :
1200 527 : spwcol.chanWidth().setShape(ispw,ip);
1201 527 : spwcol.chanWidth().put(ispw,totBWv);
1202 527 : spwcol.effectiveBW().setShape(ispw,ip);
1203 527 : spwcol.effectiveBW().put(ispw,totBWv);
1204 527 : spwcol.resolution().setShape(ispw,ip);
1205 527 : spwcol.resolution().put(ispw,totBWv);
1206 :
1207 527 : }
1208 633 : }
1209 37 : }
1210 :
1211 23 : void NewCalTable::addPhoneyObs() {
1212 :
1213 23 : TableType ntype(this->tableType());
1214 :
1215 23 : ostringstream msg;
1216 23 : msg << "Found pre-v4.1 caltable (" << this->tableName() << "); attempting to update..." << endl;
1217 :
1218 : // If absent, add OBSERVATION_ID column and OBSERVATION
1219 : // ONLY if caltable is writable (on disk) or a Memory table
1220 23 : if ( (ntype==Table::Plain && this->isWritable()) ||
1221 : (ntype==Table::Memory) ) {
1222 :
1223 : // Add phoney OBSERVATION_ID column and fill with zeros
1224 23 : if (!this->tableDesc().isColumn(NCT::fieldName(NCT::OBSERVATION_ID))) {
1225 23 : ScalarColumnDesc<Int> obscoldesc(NCT::fieldName (NCT::OBSERVATION_ID),ColumnDesc::Direct);
1226 23 : this->addColumn(obscoldesc,false);
1227 23 : CTMainColumns mc(*this);
1228 23 : mc.obsId().fillColumn(0);
1229 23 : }
1230 :
1231 : // Add dummy OBSERVATION subtable with 1 row
1232 23 : if (!this->keywordSet().isDefined("OBSERVATION")) {
1233 23 : String calObsName=this->tableName()+"/OBSERVATION";
1234 23 : Table::TableOption access(Table::NewNoReplace);
1235 23 : SetupNewTable obstab(calObsName,CTObservation::requiredTableDesc(),access);
1236 23 : this->rwKeywordSet().defineTable("OBSERVATION", Table(obstab,ntype)); // same type as parent table
1237 23 : observation_p = CTObservation(this->keywordSet().asTable("OBSERVATION"));
1238 23 : fillGenericObs(1);
1239 23 : }
1240 :
1241 23 : msg << "SUCCEEDED: trivial OBSERVATION/OBSERVATION_ID have been added.";
1242 :
1243 23 : LogIO log;
1244 23 : log << msg.str() << LogIO::WARN;
1245 :
1246 23 : }
1247 : else {
1248 0 : msg << "FAILED: caltable is not writable.";
1249 0 : msg << " Please run cb.updatecaltable on this caltable, OR";
1250 0 : msg << " regenerate this caltable in v4.1 or later.";
1251 0 : throw(AipsError(msg.str()));
1252 : }
1253 :
1254 23 : }
1255 :
1256 :
1257 :
1258 : } //# NAMESPACE CASA - END
|