00001 //# MirFiller.h: defines the MirFiller class for filling Miriad data 00002 //# Copyright (C) 2000,2001,2002 00003 //# Associated Universities, Inc. Washington DC, USA. 00004 //# 00005 //# This library is free software; you can redistribute it and/or modify it 00006 //# under the terms of the GNU Library General Public License as published by 00007 //# the Free Software Foundation; either version 2 of the License, or (at your 00008 //# option) any later version. 00009 //# 00010 //# This library is distributed in the hope that it will be useful, but WITHOUT 00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00012 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00013 //# License for more details. 00014 //# 00015 //# You should have received a copy of the GNU Library General Public License 00016 //# along with this library; if not, write to the Free Software Foundation, 00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 00018 //# 00019 //# Correspondence concerning AIPS++ should be addressed as follows: 00020 //# Internet email: aips2-request@nrao.edu. 00021 //# Postal address: AIPS++ Project Office 00022 //# National Radio Astronomy Observatory 00023 //# 520 Edgemont Road 00024 //# Charlottesville, VA 22903-2475 USA 00025 //# 00026 //# 00027 //# $Id: MirFiller.h,v 1.2 2009/09/03 23:28:32 pteuben Exp $ 00028 00029 #ifndef BIMA_MIRFILLER_H 00030 #define BIMA_MIRFILLER_H 00031 00032 #include <casa/Containers/List.h> 00033 #include <casa/Arrays/Vector.h> 00034 #include <casa/Arrays/Cube.h> 00035 #include <casa/Arrays/Matrix.h> 00036 #include <casa/Logging/LogIO.h> 00037 00038 #include <miriad/Filling/MirVarHandler.h> 00039 #include <miriad/Filling/MirVisReader.h> 00040 00041 #include <casa/namespace.h> 00042 //# Forward Declarations 00043 namespace casa { //# NAMESPACE CASA - BEGIN 00044 class Record; 00045 class String; 00046 class AipsError; 00047 class MeasurementSet; 00048 //class FillMetadata; 00049 //class GlishRecord; 00050 } //# NAMESPACE CASA - END 00051 00052 class MirPol; 00053 class MirSource; 00054 class MirFreqSetup; 00055 class UnavailableMiriadDataSelectionError; 00056 00057 class FillMetadata; 00058 00059 // <summary> 00060 // BIMA MIRIAD dataset to MeasurementSet2 filler 00061 // </summary> 00062 // 00063 // <use visibility=export> 00064 // 00065 // <reviewed reviewer="" date="yyyy/mm/dd" tests="" demos=""> 00066 // </reviewed> 00067 // 00068 // <prerequisite> 00069 // <li> <linkto class="Record">Record</linkto> -- for holding options 00070 // </prerequisite> 00071 // 00072 // <etymology> 00073 // MirFiller is the successor to the BimaFiller (class and application). 00074 // It attempts to be more general in its filling of Miriad data while still 00075 // retaining special functionality for BIMA data specifically. 00076 // </etymology> 00077 // 00078 // <synopsis> 00079 // MirFiller converts an input Miriad dataset into an output MeasurementSet 00080 // (ver. 2). It is attached to its Miriad dataset at construction; it can 00081 // subsequently be used to fill several output MSes, perhaps with different 00082 // data from the input dataset, in sequence (i.e. it is not thread-safe). 00083 // 00084 // Default use of this class would be to construct an instance attached to 00085 // a Miriad dataset, and then call its <src>fill()</src> method, passing 00086 // it the output measurement set name. This will load all data found in 00087 // the input dataset into the measurement set. Restricting the filling to 00088 // specific spectral windows can be controled via the <src>select()</src> 00089 // function. 00090 // 00091 // <h3>Miriad Dataset Spectral Layout and 00092 // its Mapping to the Measurement Set</h3> 00093 // 00094 // Each record in a Miriad dataset organizes its correlation data by 00095 // spectral windows and so-called wideband channels. Each Miriad 00096 // spectral window contains data from a band of frequencies, broken up 00097 // into some number of channels. (Because each channel, then, is 00098 // fairly narrow in bandwidth, these correlations are often referred 00099 // to as "narrow-band" data.) The wideband channels, in general, 00100 // contain single correlations, averaged over some band at potentially 00101 // arbitrary frequencies; that is, they are bolometer-like 00102 // measurements. 00103 // 00104 // With BIMA Miriad datasets, the wideband channels are used to store 00105 // wide-band averages of the spectral windows. More specifically, the 00106 // first wideband channel contains the average of all spectral windows 00107 // channels associated with the lower sideband (the first Nwin/2 00108 // windows), and the second wideband channel contains the average of 00109 // the upper sideband windows. The remaining wideband channels 00110 // contain the averages of each of the spectral windows (in the same 00111 // order). Thus, if the BIMA Miriad dataset contains Nwin spectral windows, 00112 // there will be Nwin+2 wideband channels. The first Nwin/2 windows will 00113 // be from the lower sideband, and the rest, from the upper sideband. 00114 // 00115 // When the Miriad data is converted to an MS, each spectral window and each 00116 // wideband channel is loaded into a separate MS spectral window. Thus, for 00117 // a BIMA dataset with Nwin windows, the output MS (by default) will contain 00118 // Nwin*2+2 spectral windows. The <src>select()</src> function can be used 00119 // to restrict the windows that get written. 00120 // 00121 // <h3>Polarization</h3> 00122 // 00123 // Miriad datasets stores correlations for different polarizations in 00124 // separate records, even if they were observed simultaneously. 00125 // (Thus, it is up to the Miriad I/O software to properly combine 00126 // records to form new Stokes correlations.) This is in contrast to 00127 // AIPS++ which can store polarizations observed at the same time in the 00128 // same record. Furthermore, BIMA can only observe one polarization at 00129 // a time. Thus, how polarizations should be loaded from a Miriad dataset 00130 // into an AIPS++ Measurment Set depends in part on whether the 00131 // polarizations were (effectively) observed simultaneously. It might 00132 // also depend on whether polarization calibration is needed and how it 00133 // should be done. 00134 // 00135 // The standard recipe for handling raw BIMA polarization data calls for 00136 // the sampling of the polarizations to be loaded into separate records. 00137 // This makes time-based editing easier. Once the polarization gains are 00138 // applied, one usually time-averages the data over several polarization 00139 // switching cycles; in effect, then, one can consider the polarizations 00140 // as having been observed simultaneously. Thus, in this time-averaging 00141 // step, one collapses the different polarizations into single records for 00142 // standard handling by the imaging tools. (Note: the software to support 00143 // this operation is still in development as of this writing.) 00144 // 00145 // The "joinpol" option (set with setOptions()) allows one to control 00146 // whether an attempt is made to load polarizations into the same record. 00147 // If joinpol is false, all polarizations are loaded into different records; 00148 // each record will point to a different polarization setup in the 00149 // POLARIZATION table (with each setup containing only one correlation type). 00150 // If joinpol is true, then fill() will look for polarizations with the same 00151 // time stamp and load them into the same record; the POLARIZATION table will 00152 // then only have one setup containing all correlations. Any polarizations 00153 // that are not found are set to zero. Thus, for a raw BIMA data 00154 // containing multiple polarizations, joinpol equal to true will produce a 00155 // much large dataset than joinpol equal to false because of all the extra 00156 // zero visibilities that get loaded in. 00157 // </synopsis> 00158 // 00159 // <example> 00160 // <srcblock> 00161 // // open Miriad dataset 3c273 for filling 00162 // MirFiller filler('3c273'); 00163 // 00164 // // if needed, set some options 00165 // Record opts = filler.getOptions(); 00166 // RecordFieldPtr<Double>(opts, "scanlim").define(600); 00167 // RecordFieldPtr<Bool>(opts, "verbose").define(True); 00168 // filler.setOptions(opts); 00169 // 00170 // // if desired, chose the windows to write 00171 // Vector<Int> wide(0) // do not write out any wideband channels 00172 // Vector<Int> splwin(filler.nspect()); 00173 // for(Int i=0; i < splwin.nelements(); i++) splwin(i) = i; 00174 // filler.select(wide, splwin); 00175 // 00176 // // fill the output MS 00177 // filler.fill('3c273.ms'); 00178 // </srcblock> 00179 // </example> 00180 // 00181 // <motivation> 00182 // The important features of this class are: 00183 // <ul> 00184 // <li> Input spectral windows are loaded into separate output windows. 00185 // This allows windows to have different rest frequencies associated 00186 // with them. It also allows channels within a window to be 00187 // contiguous in frequency and having the same width. 00188 // <li> Wideband channels are each placed in their own window. This is 00189 // particularly important for the sideband averages, which are used 00190 // to calculate the G-Jones which can be applied to the spectral 00191 // windows. 00192 // <li> Associations are set to connect spectral windows and their averages. 00193 // This allows the averages to be recalculated if necessary (e.g. 00194 // after flagging). 00195 // <li> Different polarizations are by default loaded into separate 00196 // records as is appropriate for raw BIMA data; however, if 00197 // simultaneously measured polarizations exist, an option can be 00198 // set to join them into a single record. 00199 // </ul> 00200 // </motivation> 00201 // 00202 // <thrown> 00203 // <li> <linkto class="AipsError">AipsError</linkto> -- if the input 00204 // dataset is not in Miriad format or cannot be opened. 00205 // <li> <linkto class="MiriadFormatError">MiriadFormatError</linkto> 00206 // -- if an illegal format condition is found in the input 00207 // Miriad dataset. 00208 // <li> <linkto class="UnavailableMiriadDataSelectionError"> 00209 // UnavailableMiriadDataSelectionError</linkto> -- if the data 00210 // selection is known to be out of range. 00211 // </thrown> 00212 // 00213 // <todo asof="2001/03/01"> 00214 // <li> load planet source models 00215 // <li> a splitWindows option may be needed 00216 // <li> a more sophisticated handling of multiple polarization setups 00217 // may be needed 00218 // <li> system temperatures are currently loaded into the SYSCAL as 00219 // single-element arrays, regardless of the "official" number of 00220 // polarization receptors. This is not strictly in compliance with 00221 // the MS2 spec, so it should be fixed. 00222 // <li> change getOptions() interface to get output from user (?) 00223 // </todo> 00224 00225 class MirFiller : public MirVarHandler { 00226 private: 00227 uInt debug; // debugging level 00228 00229 public: 00230 00231 // create the filler, attaching it to a Miriad dataset. <src>mirfile</src> 00232 // is the dataset filename, and <src>dbg</src> is the debug level (see 00233 // <linkto class="MirFiller:setDebug"><src>setDebugLevel()</src></linkto>). 00234 MirFiller(const String& mirfile, Bool scan=True, Int dbg=0); 00235 00236 // destruct this filler 00237 virtual ~MirFiller(); 00238 00239 // set the debugging level which controls the amount of debugging 00240 // messages that are printed to the terminal (as opposed to the logger). 00241 // A value of zero or less will cause no extra messages to be printed; 00242 // increasing values will increase the amount of messages. 00243 void setDebugLevel(Int level) { 00244 debug = (level < 0) ? 0 : (uInt) level; 00245 rdr_p.setDebugLevel(debug); 00246 } 00247 00248 // set the debugging level which controls the amount of debugging 00249 // messages that are printed to the terminal. A value of zero or less 00250 // means that no extra messages will be printed; increasing values will 00251 // increase the amount of messages. 00252 Int getDebugLevel() const { return debug; } 00253 00254 // return true if the debugging level is at least as high as a given 00255 // level. 00256 Bool Debug(Int level) { return (((uInt) level) <= debug); } 00257 00258 // return true if this filler should be verbose in its messages. This 00259 // will be true if the verbose option is enabled or the debug level is 00260 // greater than 1. 00261 Bool verbose() { return (verbose_p || debug > 1); } 00262 00263 // return basic characteristics of the input dataset as a GlishRecord. If 00264 // scan is True (the default), the entire file will be (re-) scanned 00265 // using the current values for the obslim and scanlim options. 00266 // If verbose is true (the 00267 // default), send a description to the logger. 00268 //GlishRecord summary(Bool verbose=True, Bool scan=True); 00269 00270 // fill the output MS according to the current selections and options 00271 // msfile is the output name to use; it should not already exist. 00272 void fill(const String& msfile) { 00273 if (joinpol_p) 00274 joinFill(msfile); 00275 else 00276 noJoinFill(msfile); 00277 } 00278 00279 // select spectral data from the input Miriad dataset. wideChans is a 00280 // list of one-based channel indices. narrowWins is a list of one-based 00281 // window indices. The default is to choose all available wide channels 00282 // and windows. polsel is a polarization selection: only the correlation 00283 // types present will be loaded; a NULL value means take all polarizations 00284 // found. (See also the joinpol option under setOptions().) 00285 void selectSpectra(const Vector<Int>& wideChans, 00286 const Vector<Int>& narrowWins); 00287 // throw(UnavailableMiriadDataSelectionError); 00288 00289 // select the polarizations to load. An empty setup means by default 00290 // take all polarizations found in the dataset. 00291 void selectPols(ConstMirPolSetup &polsel); 00292 00293 // set the options for filling. The options are set via a Record object 00294 // for which the following keys are recognized: 00295 // <pre> 00296 // scanlim the scan time jump limit, in seconds. If the jump in 00297 // time between two consecutive Miriad records is greater 00298 // than this limit the scan number that gets written out 00299 // for that record will be incremented. A change in source 00300 // will always increment the scan number unless scanlim is 00301 // negative; in this case, all records are forced to have 00302 // the same scan number. The default is 5 minutes. 00303 // 00304 // obslim the observation ID time jump limit, in seconds. The 00305 // observation ID is meant to delimit two tracks that might 00306 // appear in the same file. If the jump in time 00307 // between two consecutive Miriad records is greater than 00308 // this limit the scan number that gets written out for 00309 // that record will be incremented. The ID will always be 00310 // incremented if there is a change in telescope or array 00311 // configuration unless obslim is negative, in which case, 00312 // all records will be forced to have the same observation 00313 // ID. The default is 4 hours. 00314 // 00315 // tilesize the tiling size to use (in channels?) for storing data 00316 // in the MS using the TiledStorageManager. If the value 00317 // is <= 0, the standard (non-tiled) storage manager will 00318 // be used. The default is 32. 00319 // 00320 // wideconv the convention to use for interpreting the wideband channels. 00321 // The allowed values are "bima" and "none". In the "bima" 00322 // convention, the first two wideband channels are the lower & 00323 // upper sideband averages and the remaining channels represent 00324 // averages of each of the spectral line windows. Currently, 00325 // this option only affects the writing out of window 00326 // associations: if wideconv="bima", the associations linking 00327 // wideband windows to spectral line windows will be written 00328 // according to the convention. 00329 // 00330 // joinpol If true, multiple polarizations are loaded as a single 00331 // polarization setup. Which polarizations are included 00332 // depend on the polarization selections. If false (the 00333 // default), each polarization is loaded as a separate setup. 00334 // 00335 // tsyswt If true (the default), the SIGMA and WEIGHT columns will 00336 // be filled with values based on the system temperatures, if 00337 // found. If false, these columns will be filled with values=1. 00338 // The SYSCAL table will be filled if system temperatures are 00339 // present, regardless of the value of this option. 00340 // 00341 // planetfit The maximum fit order to use when fitting the direction of a 00342 // planet-tracking field. The actual order used may be less than 00343 // this if there is insufficient data. The default is 3. 00344 // updmodelint This is the amount of time to wait before updating the 00345 // model. By default this is 8 hours. 00346 // 00347 // movfield if true, exact field positions tracking a moving object will 00348 // be written to subtable called BIMA_MOVING_FIELDS. 00349 // 00350 // compress if true, selected columns will be compressed using scaled 00351 // integers. This limits the dynamic range to about 65000:1. 00352 // The default is true. 00353 // 00354 // verbose if true, send extra messages to the logger 00355 // </pre> 00356 void setOptions(const Record &opts); 00357 00358 // get the current filling options 00359 Record getOptions(); 00360 00361 // handle an update to the integration time; 00362 // this is a callback routine that is part of the MirVarHandler 00363 // interface which must be implemented. This implementation does 00364 // nothing. 00365 virtual void updateIntTime(FillMetadata &fm, Double time); 00366 00367 // handle an update to the observatory; 00368 // this is a callback routine that is part of the MirVarHandler 00369 // interface which must be implemented. This implementation flushes 00370 // records for the FEED subtable for the last observatory, and adds 00371 // a PROCESSOR subtable record for the next table. 00372 virtual void updateObservatory(FillMetadata &fm, Double time); 00373 00374 // handle an update to the array configuration; 00375 // this is a callback routine that is part of the MirVarHandler 00376 // interface which must be implemented 00377 virtual void updateArray(FillMetadata &fm, Double time); 00378 00379 // handle an update to the SOURCE_MODEL column of the SOURCE subtable. 00380 // Maybe that this gets incorporated into updateSource at sometime, have 00381 // to examine logistics. REWRITEME. dgoscha 00382 virtual void updateSourceModel(FillMetadata &fm, Double time); 00383 00384 // handle an update to the array configuration; 00385 // this is a callback routine that is part of the MirVarHandler 00386 // interface which must be implemented 00387 virtual void updatePolSetup(FillMetadata &fm, Double time); 00388 00389 // handle an update to the source; 00390 // this is a callback routine that is part of the MirVarHandler 00391 // interface which must be implemented 00392 virtual void updateSource(FillMetadata &fm, Double time); 00393 00394 // handle an update to the observing field; 00395 // this is a callback routine that is part of the MirVarHandler 00396 // interface which must be implemented 00397 virtual void updateField(FillMetadata &fm, Double time); 00398 00399 // handle an update to the frequency setup; 00400 // this is a callback routine that is part of the MirVarHandler 00401 // interface which must be implemented 00402 virtual void updateFreqSetup(FillMetadata &fm, Double time); 00403 00404 // handle an update to system temperatures 00405 // this is a callback routine that is part of the MirVarHandler 00406 // interface which must be implemented 00407 virtual void updateTsys(FillMetadata &fm, Double time); 00408 00409 private: 00410 00411 // open and setup the output MS. This includes all initialization that 00412 // can be done without reading any data from the input Miriad dataset. 00413 MeasurementSet *setupMS(const String& msfile, Int tileSize=0, 00414 Bool needSrcModel=True); 00415 00416 // initialize the output MS. This is called after the first input record 00417 // is read in from the input Miriad dataset. It will initialize certain 00418 // subtables (currently, POINTING, PROCESSOR, HISTORY, FEED, and 00419 // POLARIZATION) based on static or otherwise non-tracked variable 00420 // information. 00421 void initMS(::FillMetadata& fm); 00422 00423 void noJoinFill(const String& msfile); 00424 void joinFill(const String& msfile); 00425 00426 Bool nearAbs(Double a, Double b, Double tol) { 00427 return (abs(a-b) < tol); 00428 } 00429 00430 // add the current observation information as a new record to the 00431 // output ms's OBSERVATION subtable 00432 void flushObsRecord(FillMetadata& fm, Double time); 00433 00434 // add the records to the FEED subtable for the current set of antennas 00435 // and polarizations 00436 void flushFeedRecords(FillMetadata& fm, Double time); 00437 00438 // check for moving objects in source list and adjust FIELD subtable 00439 // accordingly 00440 void flushMovingFields(FillMetadata& fm, Double time); 00441 00442 // add the records to the POINTING subtable for the current set of antennas 00443 void flushPointingRecords(FillMetadata& fm, Double time); 00444 00445 // add a new set of antenna positions 00446 void addAntennaPositions(FillMetadata &fm, Double time); 00447 00448 // add the current source to the SOURCE subtable 00449 uInt addSource(FillMetadata &fm, double time); 00450 00451 // add the current field to the FIELD subtable 00452 void addField(FillMetadata &fm, double time); 00453 00454 // add subtable records for the current correlator setup 00455 void addCorrelatorSetup(FillMetadata &fm, double time); 00456 00457 // add a POLARIZATION record for the current polarization type. 00458 void addPolarization(FillMetadata &fm, Bool addCurrentOnly=False); 00459 00460 // add DATA_DESCRIPTION records for the current polarization 00461 // and frequency setup 00462 void addDataDesc(FillMetadata &fm); 00463 00464 // write out the miriad history into the HISTORY table 00465 void flushHistory(FillMetadata &fm); 00466 00467 // copy the history from a given HISTORY table 00468 void copyHistoryFrom(FillMetadata &fm, String tablename); 00469 00470 // add a processor record for the current frequency setup 00471 void addProcessor(FillMetadata &fm); 00472 00473 // add a filler message to the HISTORY table 00474 void addHistoryMessage(FillMetadata &fm, String priority, 00475 String origin, String msg); 00476 00477 // add a record to the SysCal table 00478 void addTsysRecords(FillMetadata &fm, Double time, Cube<Float>& tsys); 00479 00480 // initialize the STATE table 00481 void initState(FillMetadata &fm); 00482 00483 // create a polynomial fit for the direction to a moving source 00484 //PJT 00485 Bool fitskymotion(Matrix<Double> &dirfit, const Vector<Double> &time, 00486 const Vector<Double> &ra, const Vector<Double> &dec); 00487 00488 // info that doesn't change during life of filler 00489 MirVisReader rdr_p; 00490 LogIO log_p; 00491 00492 // selection info 00493 Vector<Bool> widesel_p, winsel_p; 00494 Int nwinsel_p, nwidesel_p; 00495 ConstMirPolSetup *defpolsel_p; 00496 00497 // options 00498 String histbl_p; 00499 Double scanlim_p, obslim_p; 00500 Int tilesize_p, planetfit_p; 00501 Bool verbose_p, joinpol_p, tsyswt_p, movfield_p, compress_p; 00502 00503 enum wideConventions { NONE=0, BIMA, MIRIAD, NCONV }; 00504 static String wideconvnames[]; 00505 wideConventions wideconv_p; 00506 00507 Double updmodelint_p; 00508 }; 00509 00510 00511 #endif 00512 00513