General Purpose Geodetic Library
SgVlbiSessionIoFringes.cpp
Go to the documentation of this file.
1 /*
2  *
3  * This file is a part of Space Geodetic Library. The library is used by
4  * nuSolve, a part of CALC/SOLVE system, and designed to make analysis of
5  * geodetic VLBI observations.
6  * Copyright (C) 2015-2020 Sergei Bolotin.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #include <iostream>
24 #include <stdlib.h>
25 
26 
27 
28 #include <QtCore/QDateTime>
29 #include <QtCore/QDir>
30 #include <QtCore/QFile>
31 #include <QtCore/QFileInfo>
32 #include <QtCore/QList>
33 #include <QtCore/QMap>
34 #include <QtCore/QRegularExpression>
35 #include <QtCore/QTextStream>
36 #include <QtCore/QVector>
37 
38 
39 #include <SgVlbiSession.h>
40 
41 #include <SgConstants.h>
42 #include <SgLogger.h>
43 #include <SgVersion.h>
44 #include <SgVlbiBand.h>
45 #include <SgVlbiObservation.h>
46 
47 
48 
49 
50 
51 #ifdef HAVE_MK4_DATA_H
52 extern "C"
53 {
54 // workaround "complex" stuff:
55  #define T230_VERSION 0
56  #include <hops/mk4_data.h>
57 }
58 #endif
59 //
60 //
61 #ifdef HAVE_MK4_DFIO_H
62 extern "C"
63 {
64  #include <hops/mk4_dfio.h>
65 }
66 #endif
67 //
68 //
69 #ifdef HAVE_MK4_VEX_H
70 // workaround warnings about redefinitions of TRUE and FALSE (Qt vs HOPS):
71 # ifdef FALSE
72 # define FALSE_SAVED FALSE
73 # undef FALSE
74 # endif
75 # ifdef TRUE
76 # define TRUE_SAVED TRUE
77 # undef TRUE
78 # endif
79 extern "C"
80 {
81  #include <hops/mk4_vex.h>
82 }
83 # ifdef FALSE_SAVED
84 # undef FALSE
85 # define FALSE FALSE_SAVED
86 # undef FALSE_SAVED
87 # endif
88 # ifdef TRUE_SAVED
89 # undef TRUE
90 # define TRUE TRUE_SAVED
91 # undef TRUE_SAVED
92 # endif
93 #endif
94 
95 
96 
97 
98 
99 /*=======================================================================================================
100 *
101 * Auxiliary data structures
102 *
103 *======================================================================================================*/
104 
105 
106 
107 
108 /*=======================================================================================================
109 *
110 * I/O utilities:
111 *
112 *======================================================================================================*/
113 //
114 #if !defined HAVE_MK4_DATA_H || !defined HAVE_MK4_DFIO_H || !defined HAVE_MK4_VEX_H
115 bool SgVlbiSession::getDataFromFringeFiles(const QString&, const QString&, const QString&,
116  const QString&, const QString&, const QList<QString>&)
117 {
118  std::cout << "HOPS were not found.\n";
120  "::getDataFromFringeFiles(): cannot read fringe files, the software was compiled without HOPS "
121  "support");
122  return false;
123 };
124 
125 
126 
127 //
128 void SgVlbiSession::parseVexFile(const QString&, QString&, QString&)
129 {
130 };
131 
132 
133 
134 //
135 void SgVlbiSession::processVexFile(const QString&, QMap<QString, StationInfo>&, VexInfo&,
136  const QMap<QString, QString>&, QString&)
137 {
138 };
139 
140 
141 
142 //
143 void SgVlbiSession::processFringeFile(const QString&, const QString&, const QMap<QString, StationInfo>&,
144  const VexInfo&, const QString&, const QMap<QString, QString>&, const QMap<QString, QString>&,
145  const QMap<QString, QString>&, const QMap<QString, QString>&, const QMap<QString, QString>&,
146  const QMap<QString, int>&, int&)
147 {
148 };
149 
150 
151 
152 //
154 {
155  return false;
156 };
157 //
158 //
159 //
160 //
161 #else
162 //
163 //
164 //
165 //
166 // auxiliary data structures (we do not need them outside of this file):
167 struct ChannelInfo
168 {
169  QString name_; /* External channel name */
170  QString polarization_; /* R or L */
171  double sky_frequency_; /* Hz */
172  QString net_sideband_; /* U or L */
173  double bandwidth_; /* Hz */
174  QString band_id_; /* Linkword (internal use) */
175  QString chan_id_; /* Linkword (internal use) */
176  QString bbc_id_; /* Linkword (internal use) */
177  QString pcal_id_; /* Linkword (internal use) */
178  QString if_id_; /* Linkword (internal use) */
179  int bbc_no_; /* Physical BBC# */
180  QString if_name_; /* Physical IF name */
181  double if_total_lo_; /* Hz */
182  QString if_sideband_; /* U or L */
183  ChannelInfo();
184  ChannelInfo(const ChannelInfo& ci);
185  ChannelInfo& operator=(const ChannelInfo& ci);
186 };
187 //
188 ChannelInfo::ChannelInfo() :
189  name_(""),
190  polarization_(""),
191  net_sideband_(""),
192  band_id_(""),
193  chan_id_(""),
194  bbc_id_(""),
195  pcal_id_(""),
196  if_id_(""),
197  if_name_(""),
198  if_sideband_("")
199 {
200  sky_frequency_ = -1.0;
201  bandwidth_ = -1.0;
202  bbc_no_ = -1;
203  if_total_lo_ = -1.0;
204 };
205 ChannelInfo::ChannelInfo(const ChannelInfo& ci)
206 {
207  name_ = ci.name_;
208  polarization_ = ci.polarization_;
209  sky_frequency_ = ci.sky_frequency_;
210  net_sideband_ = ci.net_sideband_;
211  bandwidth_ = ci.bandwidth_;
212  band_id_ = ci.band_id_;
213  chan_id_ = ci.chan_id_;
214  bbc_id_ = ci.bbc_id_;
215  pcal_id_ = ci.pcal_id_;
216  if_id_ = ci.if_id_;
217  bbc_no_ = ci.bbc_no_;
218  if_name_ = ci.if_name_;
219  if_total_lo_ = ci.if_total_lo_;
220  if_sideband_ = ci.if_sideband_;
221 };
222 ChannelInfo& ChannelInfo::operator=(const ChannelInfo& ci)
223 {
224  name_ = ci.name_;
225  polarization_ = ci.polarization_;
226  sky_frequency_ = ci.sky_frequency_;
227  net_sideband_ = ci.net_sideband_;
228  bandwidth_ = ci.bandwidth_;
229  band_id_ = ci.band_id_;
230  chan_id_ = ci.chan_id_;
231  bbc_id_ = ci.bbc_id_;
232  pcal_id_ = ci.pcal_id_;
233  if_id_ = ci.if_id_;
234  bbc_no_ = ci.bbc_no_;
235  if_name_ = ci.if_name_;
236  if_total_lo_ = ci.if_total_lo_;
237  if_sideband_ = ci.if_sideband_;
238  return *this;
239 };
240 //
241 //
242 //
243 struct StationInfo
244 {
245  QString name_;
246  QString id_2char_;
247  QString id_1char_;
248  int recorderType_;
249  int trackFormat_;
250  int bits_sample_;
251  double sampleRate_;
252  QMap<QString, ChannelInfo> channelByName_;
253  StationInfo();
254  StationInfo(const StationInfo& si);
255  StationInfo& operator=(const StationInfo& si);
256 };
257 //
258 StationInfo::StationInfo() :
259  name_(""),
260  id_2char_(""),
261  id_1char_(""),
262  channelByName_()
263 {
264  recorderType_ = -1;
265  trackFormat_ = -1;
266  bits_sample_ = -1;
267  sampleRate_ = -1.0;
268 };
269 //
270 StationInfo::StationInfo(const StationInfo& si) :
271  name_(si.name_),
272  id_2char_(si.id_2char_),
273  id_1char_(si.id_1char_),
274  channelByName_()
275 {
276  recorderType_ = si.recorderType_;
277  trackFormat_ = si.trackFormat_;
278  bits_sample_ = si.bits_sample_;
279  sampleRate_ = si.sampleRate_;
280  channelByName_.clear();
281  for (QMap<QString, ChannelInfo>::const_iterator it=si.channelByName_.begin();
282  it!=si.channelByName_.end(); ++it)
283  channelByName_.insert(it.key(), it.value());
284 };
285 StationInfo& StationInfo::operator=(const StationInfo& si)
286 {
287  name_ = si.name_;
288  id_2char_ = si.id_2char_;
289  id_1char_ = si.id_1char_;
290  recorderType_ = si.recorderType_;
291  trackFormat_ = si.trackFormat_;
292  bits_sample_ = si.bits_sample_;
293  sampleRate_ = si.sampleRate_;
294  channelByName_.clear();
295  for (QMap<QString, ChannelInfo>::const_iterator it=si.channelByName_.begin();
296  it!=si.channelByName_.end(); ++it)
297  channelByName_.insert(it.key(), it.value());
298  return *this;
299 };
300 //
301 
302 
303 
304 struct VexInfo
305 {
306  double sampleRate_;
307  double apLength_;
308  QString expName_;
309  VexInfo();
310  VexInfo(const VexInfo& vi);
311  VexInfo& operator=(const VexInfo& vi);
312 };
313 //
314 VexInfo::VexInfo() : expName_("")
315 {
316  sampleRate_ = -1.0;
317  apLength_ = -1.0;
318 };
319 VexInfo::VexInfo(const VexInfo& vi)
320 {
321  *this = vi;
322 };
323 VexInfo& VexInfo::operator=(const VexInfo& vi)
324 {
325  sampleRate_ = vi.sampleRate_;
326  apLength_ = vi.apLength_;
327  expName_ = vi.expName_;
328  return *this;
329 };
330 //
331 
332 
333 
334 //
335 struct FringeFileName
336 {
337  QString baselineId_;
338  QString bandId_;
339  QString sequenceId_;
340  QString rootCodeId_;
341  bool isOk_;
342  int sequenceNumber_;
343  FringeFileName();
344  inline FringeFileName(const FringeFileName& fn) {*this = fn;};
345  FringeFileName(const QString fileName);
346  QString fileName() const
347  {return isOk_?(baselineId_ + "." + bandId_ + "." + sequenceId_ + "." + rootCodeId_):"";};
348  QString id() const
349  {return isOk_?(baselineId_ + "." + bandId_):"";};
350  FringeFileName& operator=(const FringeFileName& fn);
351 };
352 //
353 FringeFileName::FringeFileName() : baselineId_(""), bandId_(""), sequenceId_(""), rootCodeId_("")
354 {
355  isOk_ = false;
356  sequenceNumber_ = 0;
357 };
358 //
359 FringeFileName::FringeFileName(const QString fileName) :
360  baselineId_(""), bandId_(""), sequenceId_(""), rootCodeId_("")
361 {
362  isOk_ = false;
363  sequenceNumber_ = 0;
364  QStringList itemList=fileName.split('.');
365  if (itemList.size() == 4)
366  {
367  baselineId_ = itemList.at(0);
368  bandId_ = itemList.at(1);
369  sequenceId_ = itemList.at(2);
370  rootCodeId_ = itemList.at(3);
371  if (baselineId_.size()==2 && baselineId_.at(0)!=baselineId_.at(1) &&
372  bandId_.size()==1 && sequenceId_.size()>0 && rootCodeId_.size()>0)
373  sequenceNumber_ = sequenceId_.toInt(&isOk_);
374  };
375 };
376 //
377 FringeFileName& FringeFileName::operator=(const FringeFileName& fn)
378 {
379  baselineId_ = fn.baselineId_;
380  bandId_ = fn.bandId_;
381  sequenceId_ = fn.sequenceId_;
382  rootCodeId_ = fn.rootCodeId_;
383  isOk_ = fn.isOk_;
384  sequenceNumber_ = fn.sequenceNumber_;
385  return *this;
386 };
387 
388 
389 
390 
391 
392 //
393 class FringeFileMap : public QMap<QString, FringeFileName>
394 {
395 public:
396  inline FringeFileMap() : QMap<QString, FringeFileName>() {};
397  inline ~FringeFileMap() {clear();};
398  void registerFileName(const QString fileName);
399 };
400 //
401 void FringeFileMap::registerFileName(const QString fileName)
402 {
403  FringeFileName ffName(fileName);
404  if (ffName.isOk_)
405  {
406  if (contains(ffName.id()))
407  {
408  if (value(ffName.id()).sequenceNumber_ < ffName.sequenceNumber_)
409  {
411  "FringeFileMap::registerFileName(): the fringe file name " +
412  (*this)[ffName.id()].fileName() + " is being replaced by " + ffName.fileName());
413  (*this)[ffName.id()] = ffName;
414  };
415  }
416  else
417  {
418  insert(ffName.id(), ffName);
419  }
420  };
421 };
422 
423 
424 
425 //
426 struct CorelRootFileName
427 {
428  QString sourceId_;
429  QString rootCodeId_;
430  bool isOk_;
431  CorelRootFileName();
432  CorelRootFileName(const QString fileName);
433  inline CorelRootFileName(const CorelRootFileName& cr) {*this = cr;};
434 
435  QString fileName() const
436  {return isOk_?(sourceId_ + "." + rootCodeId_):"";};
437  CorelRootFileName& operator=(const CorelRootFileName& cr);
438 };
439 //
440 CorelRootFileName::CorelRootFileName() : sourceId_(""), rootCodeId_("")
441 {
442  isOk_ = false;
443 };
444 //
445 CorelRootFileName::CorelRootFileName(const QString fileName) :
446  sourceId_(""), rootCodeId_("")
447 {
448  isOk_ = false;
449  QStringList itemList=fileName.split('.');
450  if (itemList.size() == 2)
451  {
452  sourceId_ = itemList.at(0);
453  rootCodeId_ = itemList.at(1);
454  isOk_ = true;
455  };
456 };
457 //
458 CorelRootFileName& CorelRootFileName::operator=(const CorelRootFileName& cr)
459 {
460  sourceId_ = cr.sourceId_;
461  rootCodeId_ = cr.rootCodeId_;
462  isOk_ = cr.isOk_;
463  return *this;
464 };
465 
466 
467 
468 
469 
470 
471 
472 
473 
474 
475 
476 // end of aux data structures
477 
478 
479 //
480 //
481 //
482 bool SgVlbiSession::getDataFromFringeFiles(const QString& path2data,
483  const QString& altDatabaseName, const QString& altCorrelatorName,
484  const QString& historyFileName, const QString& mapFileName,
485  const QList<QString>& fringeErrorCodes2Skip)
486 {
487  bool isOk=false, isScanDirOk;
488  QDir dir(path2data);
489  QList<QString> dirsOfScans;
490  QStringList dirList;
491  QRegExp reScanDirName("[0-9]{3}-[0-9]{4}[a-zA-Z]{0,1}");
492 //QRegExp reVexFileName("^([0-9a-zA-Z+-_]{1,8})\\.([\\w]{6,7})$");
493  int idx;
494  // per scan entries:
495 // QString vexFileName("");
496  FringeFileMap scanFileNames;
497  QMap<QString, CorelRootFileName>
498  crootById;
499  QString sPiName, sExperDescr;
500  QMap<QString, int> piNamesByCount, expDescrsByCount, expNameByCount;
501  QMap<int, int> expSerialNumByCount;
502  QString correlatorComments(historyFileName);
503  QString correlatorName("");
504  QMap<QString, QString> stnNameById, stnNameByI; // maps of station name by 2- and 1-char Ids
505  //
506  // for name maps:
507  QMap<QString, QString> stn2stn;
508  QMap<QString, QString> src2src;
509  QMap<QString, QString> bnd2bnd;
510  QMap<QString, int> fringeErrorCodeByInt;
511  QMap<QString, int> corrNameByCount;
512  // an alternative database name:
513  QRegularExpression reOldDbName("(\\d{2})([A-Z]{3})(\\d{2})([A-Z0-9]{1,2})");
514  QRegularExpression reNewDbName("(\\d{8})-([\\S]{2,12})");
515  QRegularExpressionMatch match;
516 
517  dirList = dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name);
518  if (dirList.size() == 0)
519  {
521  "::getDataFromFringeFiles(): nothing to read");
522  return isOk;
523  };
524  //
525  //
526  importMapFile(mapFileName, stn2stn, src2src, bnd2bnd);
527  if (stn2stn.size())
529  "::getDataFromFringeFiles(): loaded " + QString("").setNum(stn2stn.size()) +
530  " entries for station name maps");
531  if (src2src.size())
533  "::getDataFromFringeFiles(): loaded " + QString("").setNum(src2src.size()) +
534  " entries for source name maps");
535  if (bnd2bnd.size())
537  "::getDataFromFringeFiles(): loaded " + QString("").setNum(bnd2bnd.size()) +
538  " entries for bnd name maps");
539  if (fringeErrorCodes2Skip.size())
540  {
541  for (int i=0; i<fringeErrorCodes2Skip.size(); i++)
542  fringeErrorCodeByInt.insert(fringeErrorCodes2Skip.at(i), 1);
543  };
544  //
545  //
546  for (int i=0; i<dirList.size(); i++)
547  dirsOfScans << dirList.at(i);
548 
550  "::getDataFromFringeFiles(): filtered " + QString("").setNum(dirsOfScans.size()) +
551  " scan entries from " + QString("").setNum(dirList.size()) + " total number of directories");
552 
553  stnNameById.clear();
554  stnNameByI.clear();
555  for (int i=0; i<dirsOfScans.size(); i++)
556  {
557  const QString &inDirName=dirsOfScans.at(i);
558  CorelRootFileName croot;
559 
560  dir.setPath(path2data + "/" + inDirName);
561  dirList.clear();
562  dirList = dir.entryList(QDir::Files | QDir::NoDotAndDotDot | QDir::Readable, QDir::Name);
563 
565  "::getDataFromFringeFiles(): processing directory '" + dir.path() + "'");
566 
567  isScanDirOk = true;
568  scanFileNames.clear();
569  crootById.clear();
570  //
571  // analyze what we get:
572  QStringList listOfVexFiles;
573  for (int j=0; j<dirList.size(); j++)
574  {
575  const QString &fileName=dirList.at(j);
576  CorelRootFileName croot(fileName);
577  if (croot.isOk_)
578  {
579  if (!crootById.contains(croot.rootCodeId_))
580  crootById.insert(croot.rootCodeId_, croot);
581  else
583  "::getDataFromFringeFiles(): the croot file " + fileName + " with crootId '" +
584  croot.rootCodeId_ + "' already registered as '" +
585  crootById.value(croot.rootCodeId_).fileName() + "'");
586  }
587  else
588  scanFileNames.registerFileName(fileName);
589  };
590  // check our containers:
591  if (crootById.size() < 1)
592  {
594  "::getDataFromFringeFiles(): cannot find any VEX file in the directory " + dir.path() +
595  ", skipped");
596  isScanDirOk = false;
597  };
598  if (scanFileNames.size() < 1)
599  {
601  "::getDataFromFringeFiles(): cannot find any usable fringe file in the directory " +
602  dir.path() + ", skipped");
603  isScanDirOk = false;
604  };
605  //
606  if (isScanDirOk)
607  {
608  QMap<QString, QMap<QString, StationInfo> >
609  stnInfoByNameById;
610  QMap<QString, VexInfo> vexInfoById;
611  //
612  // ok, first, read VEXes:
613  for (QMap<QString, CorelRootFileName>::iterator it=crootById.begin(); it!=crootById.end(); ++it)
614  {
615  VexInfo vi;
616  QMap<QString, StationInfo>
617  stnInfoByName;
618  const QString &vexFileName=it.value().fileName();
619  //
620  // collect available data from a VEX file (data that we should expect in the scan dir):
621 
622  processVexFile(dir.path() + "/" + vexFileName, stnInfoByName, vi, stn2stn, correlatorName);
623  if (correlatorName == "difx" || correlatorName == "sfxc")
624  correlatorName = "";
625  vexInfoById.insert(it.key(), vi);
626  stnInfoByNameById.insert(it.key(), stnInfoByName);
627 
628  // check station names and ids:
629  for (QMap<QString, StationInfo>::iterator it=stnInfoByName.begin();
630  it!=stnInfoByName.end(); ++it)
631  {
632  const QString& stnName=it.value().name_;
633  const QString& stn2chrId=it.value().id_2char_;
634  const QString& stn1chrId=it.value().id_1char_;
635  // check 2-chars id:
636  if (stnNameById.contains(stn2chrId))
637  {
638  if (stnNameById.value(stn2chrId) != stnName)
639  {
641  "::getDataFromFringeFiles(): -------------------------------------------");
643  "::getDataFromFringeFiles(): the croot file " + inDirName + "/" + vexFileName +
644  " contains station identities that missmatch previous data:");
646  "::getDataFromFringeFiles(): " + stnNameById.value(stn2chrId) + "[" +
647  stn2chrId + "] != " + stnName);
649  "::getDataFromFringeFiles(): -------------------------------------------");
650  };
651  }
652  else
653  stnNameById.insert(stn2chrId, stnName);
654  // check 1-chars id:
655  if (stnNameByI.contains(stn1chrId))
656  {
657  if (stnNameByI.value(stn1chrId) != stnName)
658  {
660  "::getDataFromFringeFiles(): -------------------------------------------");
662  "::getDataFromFringeFiles(): the croot file " + inDirName + "/" + vexFileName +
663  " contains station identities that missmatch previous data:");
665  "::getDataFromFringeFiles(): " + stnNameByI.value(stn1chrId) + "[" +
666  stn1chrId + "] != " + stnName);
668  "::getDataFromFringeFiles(): -------------------------------------------");
669  };
670  }
671  else
672  stnNameByI.insert(stn1chrId, stnName);
673  };
674  //
675  parseVexFile(dir.path() + "/" + vexFileName, sPiName, sExperDescr);
676  // collect all available P.I. names and experiment descriptions to check consistency (later)
677  piNamesByCount[sPiName]++;
678  expDescrsByCount[sExperDescr]++;
679  expNameByCount[vi.expName_]++;
680  corrNameByCount[correlatorName]++;
682  "::getDataFromFringeFiles(): the corel.root file " + vexFileName + " has been processed");
683  };
684  //
685  for (QMap<QString, FringeFileName>::iterator jt=scanFileNames.begin(); jt!=scanFileNames.end();
686  ++jt)
687  {
688  FringeFileName &ffn=jt.value();
689  const QString &crootId=ffn.rootCodeId_;
690  int sn;
691  if (!(crootById.contains(crootId) && vexInfoById.contains(crootId) &&
692  stnInfoByNameById.contains(crootId)))
694  "::getDataFromFringeFiles(): cannot find a corel.root file for the fringe file '" +
695  ffn.fileName() + "' with rootId=[" + crootId + "], skipped");
696  else
697  {
698  sn = 0;
699  processFringeFile(dir.path(), ffn.fileName(), stnInfoByNameById.value(crootId),
700  vexInfoById.value(crootId), crootById.value(crootId).fileName(), stnNameById, stnNameByI,
701  stn2stn, src2src, bnd2bnd, fringeErrorCodeByInt, sn);
702  expSerialNumByCount[sn]++;
703  };
704  };
705  //
706  // end of data processing.
707  };
708  };
709  //
710  //
711  // check: did we read something at all:
712  if (!bands_.size())
713  {
715  "::getDataFromFringeFiles(): nothing useful found");
716  return false;
717  };
718  //
719  //
720  setOriginType(OT_MK4); // flag it
721  setCorrelatorType("MK4 ");
724  //
725  //
726  // set global stuff here:
727  //
728  if (piNamesByCount.count() == 1)
729  {
730  if (piNamesByCount.begin().key().size())
731  setPiAgencyName(piNamesByCount.begin().key());
732  else
733  setPiAgencyName("Undefined");
735  "::getDataFromFringeFiles(): session P.I agency name was set to " + getPiAgencyName());
736  }
737  else
738  {
739  // need add more diagnostics here:
740  setPiAgencyName("Mixed");
742  "::getDataFromFringeFiles(): more than one PI agency names collected:");
743  for (QMap<QString, int>::iterator itt=piNamesByCount.begin(); itt!=piNamesByCount.end(); ++itt)
745  "::getDataFromFringeFiles(): \"" + itt.key() + "\" => " + QString("").setNum(itt.value()));
746  };
747  if (expNameByCount.count() == 1)
748  {
749  if (expNameByCount.begin().key().size())
750  setSessionCode(expNameByCount.begin().key().toUpper()); // take into account Mike Titus effect
751  else
752  setSessionCode("Undefined");
754  "::getDataFromFringeFiles(): session code was set to " + getSessionCode());
755  }
756  else
757  {
758  // need add more diagnostics here:
759  setSessionCode("Mixed");
761  "::getDataFromFringeFiles(): more than one experiment name found:");
762  for (QMap<QString, int>::iterator itt=expNameByCount.begin(); itt!=expNameByCount.end(); ++itt)
764  "::getDataFromFringeFiles(): \"" + itt.key() + "\" => " + QString("").setNum(itt.value()));
765  };
766  if (expDescrsByCount.count() == 1)
767  {
768  if (expDescrsByCount.begin().key().size())
769  setDescription(expDescrsByCount.begin().key());
770  else
771  setDescription("Undefined");
773  "::getDataFromFringeFiles(): session description was set to " + getDescription());
774  }
775  else
776  {
777  // need add more diagnostics here:
778  setDescription("Mixed");
780  "::getDataFromFringeFiles(): more than one experiment description found:");
781  for (QMap<QString, int>::iterator itt=expDescrsByCount.begin(); itt!=expDescrsByCount.end(); ++itt)
783  "::getDataFromFringeFiles(): \"" + itt.key() + "\" => " + QString("").setNum(itt.value()));
784  };
785  //
786  if (getExperimentSerialNumber() == 0) // is not set through command line arg
787  {
788  if (expSerialNumByCount.count() == 1)
789  {
790  int n;
791  n = expSerialNumByCount.begin().key();
792  if (0<n && n!=16383)
793  {
794  setExperimentSerialNumber(expSerialNumByCount.begin().key());
796  "::getDataFromFringeFiles(): session serial number was set to " +
797  QString("").sprintf("%d", getExperimentSerialNumber()));
798  }
799  else
801  "::getDataFromFringeFiles(): the observations do not have correct experiment serial number " +
802  QString("").sprintf("(==%d)", n));
803  }
804  else
805  {
806  // need add more diagnostics here:
808  "::getDataFromFringeFiles(): more than one experiment serial number found:");
809  for (QMap<int, int>::iterator it=expSerialNumByCount.begin(); it!=expSerialNumByCount.end(); ++it)
811  "::getDataFromFringeFiles(): " + QString("").sprintf("%d -> %d times", it.key(), it.value()));
812  };
813  };
814  if (corrNameByCount.count() == 1)
815  {
816  if (corrNameByCount.begin().key().size())
817  {
818  setCorrelatorName(corrNameByCount.begin().key());
820  "::getDataFromFringeFiles(): correlator name was set to \"" + getCorrelatorName() + "\"");
821  }
822  else
823  {
824  setCorrelatorName("");
826  "::getDataFromFringeFiles(): cannot find correlator name in the vex files");
827  };
828  }
829  else
830  {
831  // need add more diagnostics here:
832  setCorrelatorName("Mixed");
834  "::getDataFromFringeFiles(): more than one correlator name collected:");
835  for (QMap<QString, int>::iterator itt=corrNameByCount.begin(); itt!=corrNameByCount.end(); ++itt)
837  "::getDataFromFringeFiles(): \"" + itt.key() + "\" => " + QString("").setNum(itt.value()));
838  };
839  //
840  //
841  // if a user has provided an alternative database name, check it:
842  if (2 < altDatabaseName.size())
843  {
844  if ((match=reOldDbName.match(altDatabaseName)).hasMatch())
845  {
846  setName(altDatabaseName);
847  setNetworkSuffix(altDatabaseName.at(8));
848  setOfficialName("UNKN");
849  setSubmitterName("UNKN");
850  setSchedulerName("UNKN");
852  "::getDataFromFringeFiles(): database name was explicitly set to " + altDatabaseName +
853  ", a version 1 database name pattern");
854  }
855  else if ((match=reNewDbName.match(altDatabaseName)).hasMatch())
856  {
857  setName(altDatabaseName);
858  setNetworkSuffix("-");
859  setOfficialName("UNKN");
860  setSubmitterName("UNKN");
861  setSchedulerName("UNKN");
863  "::getDataFromFringeFiles(): database name was explicitly set to " + altDatabaseName +
864  ", a version 2 database name pattern");
865  }
866  else
868  "::getDataFromFringeFiles(): the provided database name, " + altDatabaseName +
869  ", does not fit any known pattern and was ignored");
870  };
871  //
872  //
873  QMap<double, SgVlbiBand*> bandByFreq;
874  QString str("");
875  for (int i=0; i<bands_.size(); i++)
876  {
877  SgVlbiBand *band=bands_.at(i);
878  QString bandKey=band->getKey();
879  band->setTCreation(SgMJD::currentMJD().toUtc());
880  band->setInputFileName(path2data + "/*");
881  band->setInputFileVersion(0);
882  //
883  // quick'n'dirty:
884  idx = 0;
885  SgVlbiObservable *o=observations_.at(idx)->observable(bandKey);
886  while (!o && idx<observations_.size())
887  o = observations_.at(idx++)->observable(bandKey);
888  if (o)
890  else
892  "::getDataFromFringeFiles(): cannot set up a frequency for " + bandKey + "-band");
893  if (bandByFreq.contains(band->getFrequency()))
894  {
896  "::getDataFromFringeFiles(): the frequency " + QString("").setNum(band->getFrequency()) +
897  " is already registered");
898  }
899  else
900  bandByFreq.insert(band->getFrequency(), band);
901  };
902  //
903  //
904  // load correlator's comments for history records:
905  //
906  if (correlatorComments.size()==0)
907  {
908  dir.setPath(path2data + "/../control/");
909  str = "";
910  if (!dir.exists())
912  "::getDataFromFringeFiles(): cannot get correlator comments, the directory does not exist: " +
913  dir.path());
914  else
915  {
916  dirList.clear();
917  dirList = dir.entryList(QStringList() << "*.corr",
918  QDir::Files | QDir::NoDotAndDotDot | QDir::Readable, QDir::Name);
919  if (dirList.size() == 0)
920  {
922  "::getDataFromFringeFiles(): cannot get correlator comments, no any *.corr file found: " +
923  dir.path());
924  }
925  else if (dirList.size() > 1)
926  {
928  "::getDataFromFringeFiles(): found more than one file with correlator comments:");
929  for (int j=0; j<dirList.size(); j++)
931  "::getDataFromFringeFiles(): " + dirList.at(j));
932  str = dirList.at(0);
934  "::getDataFromFringeFiles(): picked up this one: " + str);
935  }
936  else
937  str = dirList.at(0);
938  };
939  if (str.size())
940  correlatorComments = path2data + "/../control/" + str;
941  };
942  if (correlatorComments.size())
943  getCorrelatorHistory(correlatorComments);
944  else
945  {
946  for (int i=0; i<bands_.size(); i++)
947  {
948  bands_.at(i)->history().addHistoryRecord("== The correlator report was not provided. ==",
949  SgMJD::currentMJD().toUtc());
950  bands_.at(i)->history().addHistoryRecord("== ", SgMJD::currentMJD().toUtc());
951  };
953  "::getDataFromFringeFiles(): the correlator report was not provided.");
954  };
955  //
956  //
957  // set up a primary band:
958  // standard IVS case:
959  QString primeBandKey;
960  if (bandByKey_.size()==2 && bandByKey_.contains("X") && bandByKey_.contains("S"))
961  {
963  "::getDataFromFringeFiles(): importing typical IVS session");
964  primaryBand_ = bandByKey_.value("X");
965  }
966  else
967  {
969  "::getDataFromFringeFiles(): importing a foreign session setup");
970  if (bandByFreq.size() > 1)
971  primaryBand_ = bandByFreq.begin().value();
972  else
973  primaryBand_ = bands_.at(0);
974  };
976  primeBandKey = primaryBand_->getKey();
977  //
978  // remove observations that are not in the primary band:
979  int num;
980  idx = num = 0;
981  while (idx<observations_.size())
982  {
983  SgVlbiObservation *obs=observations_.at(idx);
984  if (!obs->observable(primeBandKey))
985  {
987  "::getDataFromFringeFiles(): the observation " + obs->getKey() +
988  " of the scan " + obs->getScanName() + " is being removed from the data set");
989  observationByKey_.remove(obs->getKey());
990  observations_.removeAt(idx);
991  idx--;
992  num++;
993  delete obs;
994  };
995  idx++;
996  };
997  if (num)
998  {
1000  "::getDataFromFringeFiles(): " + QString("").setNum(num) +
1001  " second-band-only observation" + (num==1?" was":"s were") + " removed");
1002  //
1003  // check source list:
1004  // ...
1005  };
1006  //
1007  //
1008  if (selfCheck(false))
1010  "::getDataFromFringeFiles(): session selfcheck complete");
1011  else
1012  {
1014  "::getDataFromFringeFiles(): the selfcheck for the session failed");
1015  return false;
1016  };
1017  //
1018  // overwrite correlator name with user-provided info:
1019  if (altCorrelatorName.size())
1020  {
1021  setCorrelatorName(altCorrelatorName);
1023  "::getDataFromFringeFiles(): correlator name was explicitly set to \"" + altCorrelatorName + "\"");
1024  };
1025  //
1026  //
1027  // calculate aux data:
1028  for (int i=0; i<observations_.size(); i++)
1029  {
1030  SgVlbiObservation *obs=observations_.at(i);
1031  for (QMap<QString, SgVlbiObservable*>::iterator it=obs->observableByKey().begin();
1032  it!=obs->observableByKey().end(); ++it)
1033  {
1034  SgVlbiObservable *o=it.value();
1035  o->calcPhaseCalDelay();
1036  };
1037  };
1039  "::getDataFromFringeFiles(): phase cal delays were calculated");
1040  //
1041  //
1042  return true;
1043 };
1044 
1045 
1046 
1047 //
1048 void SgVlbiSession::parseVexFile(const QString& vexFileName, QString& sPiName, QString& sExpDescr)
1049 {
1050  QFile f(vexFileName);
1051  QString str;
1052  bool foundPiName, foundExpDescr;
1053 // QRegExp reExpDescr("^\\s*exper_description\\s*=\\s*(\\S+\\s*)+;$");
1054  QRegExp reExpDescr("^\\s*exper_description\\s*=\\s*\"?(\\S+.*\\S+)\"?;$");
1055  QRegExp rePiName("^\\s*PI_name\\s*=\\s*(\\S+);");
1056 
1057 
1058  foundPiName = foundExpDescr = false;
1059  if (f.open(QFile::ReadOnly))
1060  {
1061  QTextStream s(&f);
1062  //
1063  while (!s.atEnd() && !(foundPiName && foundExpDescr))
1064  {
1065  str = s.readLine();
1066  if (str.contains(reExpDescr))
1067  {
1068  sExpDescr = reExpDescr.cap(1);
1069  if (sExpDescr.at(0) == '\"')
1070  sExpDescr.remove(0,1);
1071  if (sExpDescr.at(sExpDescr.size()-1) == '\"')
1072  sExpDescr.chop(1);
1073  foundExpDescr = true;
1074  }
1075  else if (str.contains(rePiName))
1076  {
1077  sPiName = rePiName.cap(1);
1078  foundPiName = true;
1079  };
1080  };
1081  if (false && !foundPiName) // modern PIs do not bother to provide PI name
1083  "::parseVexFile(): PI Name was not found; the file is " + vexFileName);
1084  if (!foundExpDescr)
1086  "::parseVexFile(): Experiment Description was not found; the file is " + vexFileName);
1087 
1088  f.close();
1089  s.setDevice(NULL);
1090  }
1091  else
1093  "::parseVexFile(): cannot open a file " + vexFileName + " for reading");
1094 };
1095 
1096 
1097 
1098 //
1099 void SgVlbiSession::processVexFile(const QString& vexFileName, QMap<QString, StationInfo> &stationByName,
1100  VexInfo& vi, const QMap<QString, QString>& stn2stn, QString& correlatorName)
1101 {
1102  bool have2clearEnv;
1103  QString path2textFiles(PATH_2_HOPS_SHARE);
1104 
1105  have2clearEnv = false;
1106  if (!getenv("TEXT"))
1107  {
1108  path2textFiles += QString("/text");
1109  setenv("TEXT", qPrintable(path2textFiles), 0);
1110  have2clearEnv = true;
1111  /*
1112  logger->write(SgLogger::DBG, SgLogger::IO, className() +
1113  "::processVexFile(): the env.variable TEXT was set to " + path2textFiles);
1114  */
1115  };
1116  //
1117  //
1118  int rc=0;
1119  char vexkey[2]={0,0};
1120  char *filename;
1121  vex vexRoot;
1122  scan_struct *scan=NULL;
1123  evex_struct *evex=NULL;
1124  *vexRoot.filename = 0;
1125 
1126  filename = new char[vexFileName.size() + 1];
1127  strcpy(filename, qPrintable(vexFileName));
1128 
1129  if ((rc=get_vex(filename, OVEX | EVEX | IVEX | LVEX, vexkey, &vexRoot)) != 0)
1130  {
1132  "::processVexFile(): cannot get_vex the file " + vexFileName + "; RC=" + QString("").setNum(rc));
1133  }
1134  else if (!(scan=vexRoot.ovex))
1135  {
1137  "::processVexFile(): the ovex struct is NULL");
1138  }
1139  else if (!(evex=vexRoot.evex))
1140  {
1142  "::processVexFile(): the evex struct is NULL");
1143  }
1144  else
1145  {
1146  QString sScanName("");
1147  QString sSrcName("");
1148  int numStns;
1149 
1150  vi.expName_ = scan->exper_name;
1151  vi.apLength_ = evex->ap_length;
1152 
1153  stationByName.clear();
1154  // SAMPLRAT
1155  // APLENGTH
1156  // BBC IND
1157  // BIT SAMPL
1158  // LO FREQ
1159  source_struct &src=scan->src;
1160  sScanName = scan->scan_name;
1161  correlatorName = scan->correlator;
1162  sSrcName = src.source_name;
1163  numStns = scan->nst;
1164  for (int i=0; i<numStns; i++)
1165  {
1166  station_struct &stn=scan->st[i];
1167  int maxNumChannels=sizeof(stn.channels)/sizeof(chan_struct);
1168  StationInfo station;
1169  station.name_.sprintf("%-8s", stn.site_name);
1170  // map it:
1171  if (stn2stn.size() && stn2stn.contains(station.name_) && stn2stn.value(station.name_).size()>1)
1172  {
1173  station.name_ = stn2stn.value(station.name_);
1175  "::processVexFile(): the input station name \"" + stn.site_name + "\" has been mapped to \"" +
1176  station.name_ + "\"");
1177  };
1178  station.id_2char_ = stn.site_id;
1179  station.id_1char_ = stn.mk4_site_id;
1180  if (stn.recorder_type != I_UNDEFINED)
1181  station.recorderType_ = stn.recorder_type;
1182  else if (stn.rack_type != I_UNDEFINED)
1183  station.recorderType_ = stn.rack_type;
1184  if (stn.track_format != I_UNDEFINED)
1185  station.trackFormat_ = stn.track_format;
1186  if (stn.bits_sample != I_UNDEFINED)
1187  station.bits_sample_ = stn.bits_sample;
1188  if (stn.samplerate != F_UNDEFINED)
1189  station.sampleRate_ = stn.samplerate;
1190  for (int j=0; j<maxNumChannels; j++)
1191  {
1192  chan_struct &chan=stn.channels[j];
1193  if (chan.sky_frequency > 1.0e3)
1194  {
1195  ChannelInfo channel;
1196  channel.name_ = chan.chan_name;
1197  channel.polarization_ = chan.polarization;
1198  channel.sky_frequency_ = chan.sky_frequency;
1199  channel.net_sideband_ = chan.net_sideband;
1200  channel.bandwidth_ = chan.bandwidth;
1201  channel.band_id_ = chan.band_id;
1202  channel.chan_id_ = chan.chan_id;
1203  channel.bbc_id_ = chan.bbc_id;
1204  channel.pcal_id_ = chan.pcal_id;
1205  channel.if_id_ = chan.if_id;
1206  channel.bbc_no_ = chan.bbc_no;
1207  channel.if_name_ = chan.if_name;
1208  channel.if_total_lo_ = chan.if_total_lo;
1209  channel.if_sideband_ = chan.if_sideband;
1210  station.channelByName_[channel.name_] = channel;
1211  };
1212  };
1213  if (stationByName.contains(station.name_))
1215  "::processVexFile(): got a duplicate record for the station \"" + station.name_ + "\"");
1216  stationByName[station.name_] = station;
1217  };
1218  };
1219  //
1220  // clear stuff:
1221  delete[] filename;
1222  if (have2clearEnv)
1223  unsetenv("TEXT");
1224 };
1225 
1226 
1227 
1228 //
1229 void SgVlbiSession::processFringeFile(const QString& path2file, const QString& fringeFileName,
1230  const QMap<QString, StationInfo>& stnsInfo, const VexInfo& vexInfo, const QString& vexFileName,
1231  const QMap<QString, QString>& stnNameById, const QMap<QString, QString>& stnNameByI,
1232  const QMap<QString, QString>& stn2stn, const QMap<QString, QString>& src2src,
1233  const QMap<QString, QString>& bnd2bnd, const QMap<QString, int>& fringeErrorCodeByInt,
1234  int& expSerialNumber)
1235 {
1236  int rc=0;
1237  char *filename;
1238  mk4_fringe fringe;
1239  QString str("");
1240  QString bandKey("");
1241  QRegExp reBandName("^(\\S*)([0-9a-zA-Z]{2})\\.([a-zA-Z]{1})\\."
1242  "\\d+\\.([0-9a-zA-Z]{5,7})$");
1243  //
1244  fringe.nalloc = 0;
1245  str = path2file + "/" + fringeFileName;
1246  filename = new char[str.size() + 1];
1247  strcpy(filename, qPrintable(str));
1248  //
1249  if (fringeFileName.contains(reBandName))
1250  {
1251  bandKey = reBandName.cap(3);
1252  };
1253  //
1254  // check map of bands:
1255  if (bnd2bnd.size())
1256  {
1257  if (!check4NameMap(bnd2bnd, bandKey))
1258  {
1260  "::processFringeFile(): skipping the observation " + fringeFileName +
1261  ": the band \"" + bandKey + "\" have to be skipped");
1262  clear_mk4fringe(&fringe);
1263  delete[] filename;
1264  return;
1265  };
1266  };
1267  //
1268  if ((rc=read_mk4fringe(filename, &fringe)) != 0)
1269  {
1271  "::processFringeFile(): cannot read_mk4fringe the file " + str +
1272  "; RC=" + QString("").setNum(rc));
1273  }
1274  else if (!bandKey.size())
1275  {
1277  "::processFringeFile(): cannot figure out a name of band from the file name " + str);
1278  }
1279  else
1280  {
1281  type_200 *t200=fringe.t200;
1282  type_201 *t201=fringe.t201;
1283  type_202 *t202=fringe.t202;
1284  type_203 *t203=fringe.t203;
1285  type_204 *t204=fringe.t204;
1286  type_205 *t205=fringe.t205;
1287  type_206 *t206=fringe.t206;
1288  type_207 *t207=fringe.t207;
1289  type_208 *t208=fringe.t208;
1290  type_210 *t210=fringe.t210;
1291  //type_212 *t212=fringe.t212[0];
1292 
1293  if (fringeErrorCodeByInt.size() && t208->errcode != ' ')
1294  {
1295  if (fringeErrorCodeByInt.contains("*") ||
1296  fringeErrorCodeByInt.contains(QString(t208->errcode)))
1297  {
1299  "::processFringeFile(): skipping the observation " + fringeFileName +
1300  ": the fringe error code is \"" + QString(t208->errcode) + "\"");
1301  clear_mk4fringe(&fringe);
1302  delete[] filename;
1303  return;
1304  };
1305  };
1306 
1307 /*
1308 // fringeErrorCodeByInt
1309  if (t208->errcode != ' ')
1310  {
1311  logger->write(SgLogger::INF, SgLogger::IO, className() +
1312  "::processFringeFile(): skipping the observation " + fringeFileName +
1313  ": the fringe error code is \"" + QString(t208->errcode) + "\"");
1314  clear_mk4fringe(&fringe);
1315  delete[] filename;
1316  return;
1317  };
1318 */
1319 
1320  // check is it already imported:
1321  SgVlbiBand *band=NULL;
1322  //
1323  QString station1Name, station2Name, sourceName, baselineName;
1324  QString scanName, scanId, obsKey;
1325  int obsIdx;
1326  int nTmp;
1327  double f;
1328  SgMJD epoch;
1329  SgVlbiStationInfo *station1Info, *station2Info;
1330  SgVlbiStationInfo *bandStation1Info, *bandStation2Info;
1331  SgVlbiSourceInfo *sourceInfo, *bandSourceInfo;
1332  SgVlbiBaselineInfo *baselineInfo, *bandBaselineInfo;
1333  SgVlbiObservation *obs=NULL;
1334  SgVlbiObservable *o=NULL;
1335  SgVlbiAuxObservation *auxObs_1=NULL, *auxObs_2=NULL;
1336 
1337  double refFreq=0.0;
1338  bool isSbdSigmaNan, isSbdSigmaInf;
1339  bool isGrdSigmaNan, isGrdSigmaInf;
1340  bool isPhrSigmaNan, isPhrSigmaInf;
1341  bool isTmp;
1342  char buff1[32], buff2[32];
1343  int numOfChannels;
1344  double effFreq4GR=0.0, effFreq4PH=0.0, effFreq4RT=0.0;
1345 
1346 
1347  if (bandByKey_.contains(bandKey))
1348  band = bandByKey_.value(bandKey);
1349  else
1350  {
1351  band = new SgVlbiBand;
1352  band->setKey(bandKey);
1353  bands_.append(band);
1354  bandByKey_.insert(bandKey, band);
1355  };
1356  //
1357  epoch.setUpEpoch(t200->frt.year, 0, t200->frt.day, // Fringe Reference Time
1358  t200->frt.hour, t200->frt.minute, t200->frt.second);
1359 
1360  // stations and source names:
1361  // the t202's char fields are not null-terminated strings, just arrays
1362  memset(buff1, 0, 32);
1363  memset(buff2, 0, 32);
1364  strncpy(buff1, t202->ref_name, 8);
1365  strncpy(buff2, t202->rem_name, 8);
1366  station1Name.sprintf("%-8s", buff1);
1367  station2Name.sprintf("%-8s", buff2);
1368  sourceName .sprintf("%-8s", t201->source);
1369  //
1370  // map the names:
1371  if (stn2stn.size())
1372  {
1373  if (!check4NameMap(stn2stn, station1Name))
1374  {
1376  "::processFringeFile(): skipping the observation " + fringeFileName +
1377  ": the station \"" + station1Name + "\" have to be skipped");
1378  clear_mk4fringe(&fringe);
1379  delete[] filename;
1380  return;
1381  };
1382  if (!check4NameMap(stn2stn, station2Name))
1383  {
1385  "::processFringeFile(): skipping the observation " + fringeFileName +
1386  ": the station \"" + station2Name + "\" have to be skipped");
1387  clear_mk4fringe(&fringe);
1388  delete[] filename;
1389  return;
1390  };
1391  };
1392  if (src2src.size())
1393  {
1394  if (!check4NameMap(src2src, sourceName))
1395  {
1397  "::processFringeFile(): skipping the observation " + fringeFileName +
1398  ": the source \"" + sourceName + "\" have to be skipped");
1399  clear_mk4fringe(&fringe);
1400  delete[] filename;
1401  return;
1402  };
1403  };
1404  //
1405  //
1406  // verify stations names and ids:
1407  // one-char id:
1408  str = QString(t202->baseline[0]);
1409  if (!stnNameByI.contains(str))
1410  {
1412  "::processFringeFile(): cannot find a station for ref one-char id '" + str + "'");
1413  clear_mk4fringe(&fringe);
1414  delete[] filename;
1415  return;
1416  }
1417  else if (stnNameByI.value(str) != station1Name)
1418  {
1420  "::processFringeFile(): the file '" + filename + "' contains wrong station identities: " +
1421  station1Name + " instead of " + stnNameByI.value(str) + " with CId='" + str + "'");
1422  clear_mk4fringe(&fringe);
1423  delete[] filename;
1424  return;
1425  };
1426  str = QString(t202->baseline[1]);
1427  if (!stnNameByI.contains(str))
1428  {
1430  "::processFringeFile(): cannot find a station for rem one-char id '" + str + "'");
1431  clear_mk4fringe(&fringe);
1432  delete[] filename;
1433  return;
1434  }
1435  else if (stnNameByI.value(str) != station2Name)
1436  {
1438  "::processFringeFile(): the file '" + filename + "' contains wrong station identities: " +
1439  station2Name + " instead of " + stnNameByI.value(str) + " with CId='" + str + "'");
1440  clear_mk4fringe(&fringe);
1441  delete[] filename;
1442  return;
1443  };
1444  // two-chars id:
1445  str = QString(t202->ref_intl_id[0]);
1446  str += QString(t202->ref_intl_id[1]);
1447  if (!stnNameById.contains(str))
1448  {
1450  "::processFringeFile(): cannot find a station for two-char id '" + str + "'");
1451  clear_mk4fringe(&fringe);
1452  delete[] filename;
1453  return;
1454  }
1455  else if (stnNameById.value(str) != station1Name)
1456  {
1458  "::processFringeFile(): the file '" + filename + "' contains wrong station identities: " +
1459  station1Name + " instead of " + stnNameById.value(str) + " with SId='" + str + "'");
1460  clear_mk4fringe(&fringe);
1461  delete[] filename;
1462  return;
1463  };
1464  str = QString(t202->rem_intl_id[0]);
1465  str += QString(t202->rem_intl_id[1]);
1466  if (!stnNameById.contains(str))
1467  {
1469  "::processFringeFile(): cannot find a station for two-char id '" + str + "'");
1470  clear_mk4fringe(&fringe);
1471  delete[] filename;
1472  return;
1473  }
1474  else if (stnNameById.value(str) != station2Name)
1475  {
1477  "::processFringeFile(): the file '" + filename + "' contains wrong station identities: " +
1478  station2Name + " instead of " + stnNameById.value(str) + " with SId='" + str + "'");
1479  clear_mk4fringe(&fringe);
1480  delete[] filename;
1481  return;
1482  };
1483  // ok here
1484  //
1485  baselineName = station1Name + ":" + station2Name;
1486  // scanId and scanName:
1487  scanId = epoch.toString(SgMJD::F_INTERNAL) + "@" + sourceName;
1488  if (t200->scan_name)
1489  scanName.sprintf("%-10s", t200->scan_name);
1490  else
1491  scanName.sprintf("%03d-%02d:%02d:%04.1f@%s",
1492  epoch.calcDayOfYear(), epoch.calcHour(), epoch.calcMin(), epoch.calcSec(),
1493  qPrintable(sourceName));
1494 
1495  // pick up or create an observation:
1496  obsKey.sprintf("%s",
1497  qPrintable(epoch.toString(SgMJD::F_INTERNAL) + "-" + baselineName + "@" + sourceName));
1498  if (observationByKey_.contains(obsKey))
1499  obs = observationByKey_.value(obsKey);
1500  else
1501  {
1502  obs = new SgVlbiObservation(this);
1503  obs->setMJD(epoch);
1504  obs->setScanName(scanName);
1505  obs->setScanId(scanId);
1506  obs->setCorrRootFileName(vexFileName);
1507  obs->setKey(obsKey);
1508  obs->setMediaIdx(observations_.size());
1509  observations_.append(obs);
1510  observationByKey_.insert(obsKey, obs);
1511  };
1512  o = new SgVlbiObservable(obs, band);
1513  obsIdx = obs->getMediaIdx();
1514  o->setMediaIdx(obsIdx);
1515  if (!obs->addObservable(bandKey, o))
1516  {
1518  "::processFringeFile(): failed to add the observable at the baseline <" +
1519  station1Name + ":" + station2Name + "> observing " + sourceName + " source at " +
1520  epoch.toString(SgMJD::F_YYYYMMDDHHMMSSSS) + " on the " + bandKey + "-band");
1521  };
1522  obs->setupActiveObservable(bandKey);
1523  // determine number of channels:
1524  numOfChannels = 0;
1525  nTmp = 16; // ver "00" has dimension of 16
1526  if (t205->version_no[0] == '0' && t205->version_no[1] == '0')
1527  {}
1528  else if (t205->version_no[0] == '0' && t205->version_no[1] == '1')
1529  nTmp = 64;
1530  else
1532  "::processFringeFile(): unknown version of the type_205 struct: " +
1533  path2file + "/" + fringeFileName);
1534  for (int i=0; i<nTmp; i++)
1535  if (t205->ffit_chan[i].channels[0]>-1 ||
1536  t205->ffit_chan[i].channels[1]>-1 )
1537  numOfChannels++;
1538  o->allocateChannelsSetupStorages(numOfChannels);
1539  expSerialNumber = t200->expt_no;
1540  //
1541  //
1542  // station #1:
1543  if (stationsByName_.contains(station1Name))
1544  station1Info = stationsByName_.value(station1Name);
1545  else // new station, add it to the container and register its index:
1546  {
1547  station1Info = new SgVlbiStationInfo(stationsByName_.size(), station1Name);
1548  stationsByName_.insert(station1Info->getKey(), station1Info);
1549  stationsByIdx_.insert(station1Info->getIdx(), station1Info);
1550  station1Info->setCid(t202->baseline[0]);
1551  station1Info->setSid(t202->ref_intl_id[0], t202->ref_intl_id[1]);
1552  };
1553  // station #2:
1554  if (stationsByName_.contains(station2Name))
1555  station2Info = stationsByName_.value(station2Name);
1556  else // new station, add it to the container and register its index:
1557  {
1558  station2Info = new SgVlbiStationInfo(stationsByName_.size(), station2Name);
1559  stationsByName_.insert(station2Info->getKey(), station2Info);
1560  stationsByIdx_.insert(station2Info->getIdx(), station2Info);
1561  station2Info->setCid(t202->baseline[1]);
1562  station2Info->setSid(t202->rem_intl_id[0], t202->rem_intl_id[1]);
1563  };
1564  // source:
1565  if (sourcesByName_.contains(sourceName))
1566  sourceInfo = sourcesByName_.value(sourceName);
1567  else // new source, add it to the container and register its index:
1568  {
1569  sourceInfo = new SgVlbiSourceInfo(sourcesByName_.size(), sourceName);
1570  sourcesByName_.insert(sourceInfo->getKey(), sourceInfo);
1571  sourcesByIdx_.insert(sourceInfo->getIdx(), sourceInfo);
1572  };
1573  // baseline:
1574  if (baselinesByName_.contains(baselineName))
1575  baselineInfo = baselinesByName_.value(baselineName);
1576  else // new baseline, add it to the container and register its index:
1577  {
1578  baselineInfo = new SgVlbiBaselineInfo(baselinesByName_.size(), baselineName);
1579  baselinesByName_.insert(baselineInfo->getKey(), baselineInfo);
1580  baselinesByIdx_.insert(baselineInfo->getIdx(), baselineInfo);
1581  };
1582  // 4band:
1583  // band's station #1:
1584  if (band->stationsByName().contains(station1Name))
1585  bandStation1Info = band->stationsByName().value(station1Name);
1586  else // new station, add it to the container:
1587  {
1588  bandStation1Info = new SgVlbiStationInfo(station1Info->getIdx(), station1Name);
1589  band->stationsByName().insert(bandStation1Info->getKey(), bandStation1Info);
1590  band->stationsByIdx().insert(bandStation1Info->getIdx(), bandStation1Info);
1591  };
1592  // band's station #2:
1593  if (band->stationsByName().contains(station2Name))
1594  bandStation2Info = band->stationsByName().value(station2Name);
1595  else // new station, add it to the container:
1596  {
1597  bandStation2Info = new SgVlbiStationInfo(station2Info->getIdx(), station2Name);
1598  band->stationsByName().insert(bandStation2Info->getKey(), bandStation2Info);
1599  band->stationsByIdx().insert(bandStation2Info->getIdx(), bandStation2Info);
1600  };
1601  // band's source:
1602  if (band->sourcesByName().contains(sourceName))
1603  bandSourceInfo = band->sourcesByName().value(sourceName);
1604  else // new source, add it to the container:
1605  {
1606  bandSourceInfo = new SgVlbiSourceInfo(sourceInfo->getIdx(), sourceName);
1607  band->sourcesByName().insert(bandSourceInfo->getKey(), bandSourceInfo);
1608  band->sourcesByIdx().insert(bandSourceInfo->getIdx(), bandSourceInfo);
1609  };
1610  // band's baselines:
1611  if (band->baselinesByName().contains(baselineName))
1612  bandBaselineInfo = band->baselinesByName().value(baselineName);
1613  else // new baseline, add it to the container and register its index:
1614  {
1615  bandBaselineInfo = new SgVlbiBaselineInfo(baselineInfo->getIdx(), baselineName);
1616  band->baselinesByName().insert(bandBaselineInfo->getKey(), bandBaselineInfo);
1617  band->baselinesByIdx().insert(bandBaselineInfo->getIdx(), bandBaselineInfo);
1618  };
1619  //
1620  obs->setStation1Idx(station1Info->getIdx());
1621  obs->setStation2Idx(station2Info->getIdx());
1622  obs->setSourceIdx(sourceInfo->getIdx());
1623  obs->setBaselineIdx(baselineInfo->getIdx());
1624  obs->setApLength(vexInfo.apLength_);
1625  //
1626  // plus additional info:
1627  o->setFourfitOutputFName(fringeFileName);
1628  //
1629  // collect observables:
1630  // single band delay:
1631 
1632  o->sbDelay().setValue(1.0e-6*t208->tot_sbd_ref);
1633  // group delay:
1634  o->grDelay().setValue(1.0e-6*t208->tot_mbd_ref);
1635  // delay rate:
1636  o->phDRate().setValue(1.0e-6*t208->tot_rate_ref);
1637  //
1638  // workaround the DBH "feature":
1639  isSbdSigmaNan = isSbdSigmaInf = isGrdSigmaNan = isGrdSigmaInf = isPhrSigmaNan = isPhrSigmaInf
1640  = false;
1641  // single band delay sigma (in microsec):
1642  f = t208->sbd_error;
1643  if (isinf(f) != 0)
1644  {
1646  "::processFringeFile(): the observation #" + QString("").setNum(obsIdx) +
1647  " at the baseline <" + baselineName + "> observing " + sourceName + " source at " +
1649  " contains wrong sigma (inf) for the single band delay", true);
1650  isSbdSigmaInf = true;
1651  f = 1.0;
1652  };
1653  if (isnan(f) != 0)
1654  {
1656  "::processFringeFile(): the observation #" + QString("").setNum(obsIdx) +
1657  " at the baseline <" + baselineName + "> observing " + sourceName + " source at " +
1659  " contains wrong sigma (nan) for the single band delay", true);
1660  isSbdSigmaNan = true;
1661  f = 1.0;
1662  };
1663  o->sbDelay().setSigma(1.0e-6*f);
1664  //
1665  // group delay sigma (in seconds):
1666  f = t208->mbd_error;
1667  if (isinf(f) != 0)
1668  {
1670  "::processFringeFile(): the observation #" + QString("").setNum(obsIdx) +
1671  " at the baseline <" + baselineName + "> observing " + sourceName + " source at " +
1673  " contains wrong sigma (inf) for the group delay", true);
1674  isGrdSigmaInf = true;
1675  f = 1.0e-6;
1676  };
1677  if (isnan(f) != 0)
1678  {
1680  "::processFringeFile(): the observation #" + QString("").setNum(obsIdx) +
1681  " at the baseline <" + baselineName + "> observing " + sourceName + " source at " +
1683  " contains wrong sigma (nan) for the group delay", true);
1684  isGrdSigmaNan = true;
1685  f = 1.0e-6;
1686  };
1687  o->grDelay().setSigma(1.0e-6*f);
1688  //
1689  // delay rate sigma:
1690  f = t208->rate_error;
1691  if (isinf(f) != 0)
1692  {
1694  "::processFringeFile(): the observation #" + QString("").setNum(obsIdx) +
1695  " at the baseline <" + baselineName + "> observing " + sourceName + " source at " +
1697  " contains wrong sigma (inf) for the group delay", true);
1698  isPhrSigmaInf = true;
1699  f = 1.0e-6;
1700  };
1701  if (isnan(f) != 0)
1702  {
1704  "::processFringeFile(): the observation #" + QString("").setNum(obsIdx) +
1705  " at the baseline <" + baselineName + "> observing " + sourceName + " source at " +
1707  " contains wrong sigma (nan) for the group delay", true);
1708  isPhrSigmaNan = true;
1709  f = 1.0e-6;
1710  };
1711  o->phDRate().setSigma(1.0e-6*f);
1712  // complain:
1713  if (isSbdSigmaNan || isSbdSigmaInf ||
1714  isGrdSigmaNan || isGrdSigmaInf ||
1715  isPhrSigmaNan || isPhrSigmaInf )
1716  {
1717  QString s1(""), s2(""), s3("");
1718  s1 = (isSbdSigmaNan || isGrdSigmaNan || isPhrSigmaNan)?"(nan)":"(inf)";
1719  if (isSbdSigmaNan || isSbdSigmaInf)
1720  s2 = "single band delay, ";
1721  if (isGrdSigmaNan || isGrdSigmaInf)
1722  s2+= "group delay, ";
1723  if (isPhrSigmaNan || isPhrSigmaInf)
1724  s2+= "delay rate, ";
1725  s2 = s2.left(s2.size() - 2);
1726  if (o->getFourfitOutputFName().size())
1727  s3 = obs->getScanName().trimmed() + "/" + o->getFourfitOutputFName();
1728 
1730  "::processFringeFile(): The observation #" + QString("").setNum(obsIdx) +
1731  ", " + s3 + " contains wrong sigma " + s1 + " for " + s2 + ".");
1732  };
1733  //
1734  // single band:
1735  o->sbDelay().setResidualFringeFitting(1.0e-6*t208->resid_sbd); // sec
1736  // group delay:
1737  o->grDelay().setResidualFringeFitting(1.0e-6*t208->resid_mbd); // sec
1738  // delay rate:
1739  o->phDRate().setResidualFringeFitting(1.0e-6*t208->resid_rate); // sec per sec
1740  //
1741  //
1742  o->grDelay().setAmbiguitySpacing(1.0e-6*t208->ambiguity); // usec->sec
1743  str = t208->quality;
1744  nTmp = str.toInt(&isTmp);
1745  o->setQualityFactor(isTmp ? nTmp : 0);
1746  o->setErrorCode(QString(t208->errcode));
1747  //
1748  memset(buff1, 0, 32);
1749  strncpy(buff1, t208->tape_qcode, sizeof(t208->tape_qcode)<32?sizeof(t208->tape_qcode):31);
1750  o->setTapeQualityCode(buff1);
1751  //
1752  o->setReferenceFrequency((refFreq=t205->ref_freq));
1753  o->setCorrCoeff(t208->amplitude);
1754  o->setTotalPhase(t208->totphase_ref*DEG2RAD); // in radians
1755  o->setIncohChanAddAmp(t208->inc_chan_ampl);
1756  o->setIncohSegmAddAmp(t208->inc_seg_ampl);
1757  o->setSnr(t208->snr);
1758  o->setProbabOfFalseDetection(t208->prob_false);
1759  o->setGeocenterTotalPhase(t208->totphase*DEG2RAD); // in radians
1760  o->setGeocenterResidPhase(t208->resphase*DEG2RAD); // in radians
1761  o->setAprioriDra(0, 1.0e-6*t208->adelay);
1762  o->setAprioriDra(1, 1.0e-6*t208->arate);
1763  o->setAprioriDra(2, 1.0e-6*t208->aaccel);
1764  // single band:
1765  o->sbDelay().setGeocenterValue(1.0e-6*t208->tot_sbd); // sec
1766  // group delay:
1767  o->grDelay().setGeocenterValue(1.0e-6*t208->tot_mbd); // sec
1768  // delay rate:
1769  o->phDRate().setGeocenterValue(1.0e-6*t208->tot_rate);// sec per sec
1770  //
1771  // VGOS contribution:
1772  str = QString(t208->version_no[0]);
1773  str += QString(t208->version_no[1]);
1774  nTmp = str.toInt(&isTmp);
1775  if (isTmp)
1776  {
1777  if (nTmp > 0)
1778  {
1779  obs->setDTec(t201->dispersion);
1780  f = t208->tec_error;
1781 // if (!isnormal(f))
1782  if (!isfinite(f))
1783  {
1785  "::processFringeFile(): the observation #" + QString("").setNum(obsIdx) +
1786  " at the baseline <" + baselineName + "> observing " + sourceName + " source at " +
1788  " contains unnormal value (" + QString("").setNum(t208->tec_error) + ") of diffTEC sigma" +
1789  "; corrected to 1e3", true);
1790  f = 1.0e3;
1791  };
1792  obs->setDTecStdDev(f);
1793  };
1794  }
1795  else
1797  "::processFringeFile(): cannot convert version number [" + str +
1798  "] to integer type: " + o->strId());
1799  //
1800  //
1801  // alloc auxiliary data:
1802  if (!station1Info->auxObservationByScanId()->contains(scanId)) // new scan, insert data:
1803  {
1804  auxObs_1 = new SgVlbiAuxObservation;
1805  auxObs_1->setMJD(epoch);
1806  auxObs_1->setAzimuthAngle (t202->ref_az *DEG2RAD);
1807  auxObs_1->setElevationAngle (t202->ref_elev *DEG2RAD);
1808  auxObs_1->setEstZenithDelay (t202->ref_zdelay*1.0e-6); // musec -> sec
1809  auxObs_1->setTapeId(QString("").sprintf("%.8s", t202->ref_tape));
1810  station1Info->auxObservationByScanId()->insert(scanId, auxObs_1);
1811  }
1812  else
1813  auxObs_1 = station1Info->auxObservationByScanId()->value(scanId);
1814  if (!station2Info->auxObservationByScanId()->contains(scanId)) // new scan, insert data:
1815  {
1816  auxObs_2 = new SgVlbiAuxObservation;
1817  auxObs_2->setMJD(epoch);
1818  auxObs_2->setAzimuthAngle (t202->rem_az *DEG2RAD);
1819  auxObs_2->setElevationAngle (t202->rem_elev *DEG2RAD);
1820  auxObs_2->setEstZenithDelay (t202->rem_zdelay*1.0e-6); // musec -> sec
1821  auxObs_2->setTapeId(QString("").sprintf("%.8s", t202->rem_tape));
1822  station2Info->auxObservationByScanId()->insert(scanId, auxObs_2);
1823  }
1824  else
1825  auxObs_2 = station2Info->auxObservationByScanId()->value(scanId);
1826  //
1827  // aux data:
1828  o->setStartOffset(t200->start_offset);
1829  o->setStopOffset (t200->stop_offset);
1830  o->setCentrOffset(t205->offset);
1831  o->setEffIntegrationTime(t206->intg_time);
1832  o->setAcceptedRatio(t206->accept_ratio);
1833  o->setDiscardRatio(t206->discard);
1834 
1835  o->setCorrelStarElev_1(t202->ref_elev *DEG2RAD);
1836  o->setCorrelStarElev_2(t202->rem_elev *DEG2RAD);
1837  o->setCorrelZdelay_1 (t202->ref_zdelay*1.0e-6); // musec -> sec
1838  o->setCorrelZdelay_2 (t202->rem_zdelay*1.0e-6); // musec -> sec
1839 
1840  // set up epochs of events:
1841  // correlation:
1842  epoch.setUpEpoch( t200->corr_date.year, 0,
1843  t200->corr_date.day,
1844  t200->corr_date.hour,
1845  t200->corr_date.minute,
1846  t200->corr_date.second);
1847  o->setEpochOfCorrelation(epoch);
1848  // fringing:
1849  epoch.setUpEpoch( t200->fourfit_date.year, 0,
1850  t200->fourfit_date.day,
1851  t200->fourfit_date.hour,
1852  t200->fourfit_date.minute,
1853  t200->fourfit_date.second);
1854  o->setEpochOfFourfitting(epoch);
1855  // nominal scan time:
1856  epoch.setUpEpoch( t200->scantime.year, 0,
1857  t200->scantime.day,
1858  t200->scantime.hour,
1859  t200->scantime.minute,
1860  t200->scantime.second);
1861  o->setEpochOfScan(epoch);
1862  //
1863  // "central" scan epoch:
1864  epoch.setUpEpoch( t205->utc_central.year, 0,
1865  t205->utc_central.day,
1866  t205->utc_central.hour,
1867  t205->utc_central.minute,
1868  t205->utc_central.second);
1869  o->setEpochCentral(epoch);
1870  // and another couple of epochs:
1871  // "start":
1872  epoch.setUpEpoch( t205->start.year, 0,
1873  t205->start.day,
1874  t205->start.hour,
1875  t205->start.minute,
1876  t205->start.second);
1877  o->setTstart(epoch);
1878  // "stop":
1879  epoch.setUpEpoch( t205->stop.year, 0,
1880  t205->stop.day,
1881  t205->stop.hour,
1882  t205->stop.minute,
1883  t205->stop.second);
1884  o->setTstop(epoch);
1885  //
1886  // sample rate (mimic read_mk4.f):
1887  bool hasStn_1Info=false, hasStn_2Info=false;
1888  StationInfo si_1, si_2;
1889  if (stnsInfo.contains(station1Name))
1890  {
1891  si_1 = stnsInfo[station1Name];
1892  hasStn_1Info = true;
1893  }
1894  else
1896  "::processFringeFile(): the station#1, " + station1Name + ", was not found in the VEX file");
1897  if (stnsInfo.contains(station2Name))
1898  {
1899  si_2 = stnsInfo[station2Name];
1900  hasStn_2Info = true;
1901  }
1902  else
1904  "::processFringeFile(): the station#2, " + station2Name + ", was not found in the VEX file");
1905  if (hasStn_1Info && hasStn_2Info && si_1.sampleRate_ != si_2.sampleRate_)
1906  {
1908  "::processFringeFile(): stations sample rates mismatch: " +
1909  QString("").sprintf("%g vs %g.", si_1.sampleRate_, si_2.sampleRate_) + ": " + o->strId());
1910  };
1911  f = t203->channels[0].sample_rate*1.0e3;
1912  if (hasStn_1Info && fabs(si_1.sampleRate_ - f)>0.0 && si_1.sampleRate_>0.0)
1913  {
1914  if (t204->ff_version[0] <= 3)
1915  f = si_1.sampleRate_;
1916  else
1918  "::processFringeFile(): OVEX and Fringe sample rates mismatch: " +
1919  QString("").sprintf("%g vs %g.", si_1.sampleRate_, f) + ": " + o->strId());
1920  };
1921  o->setSampleRate(f);
1922  //
1923  if (hasStn_1Info && hasStn_2Info && si_1.bits_sample_ != si_2.bits_sample_)
1925  "::processFringeFile(): stations bits per sample mismatch: " +
1926  QString("").sprintf("%d vs %d", si_1.bits_sample_, si_2.bits_sample_) + ": " + o->strId());
1927  if (hasStn_1Info)
1928  o->setBitsPerSample(si_1.bits_sample_);
1929  //
1930  // collect data necessary to evaluate the effective frequencies (for ionospheric correction):
1931  isTmp = ( t206->version_no[0]=='0' &&
1932  t206->version_no[1]=='0' ); // this version does not contain weights
1933  for (int i=0; i<numOfChannels; i++)
1934  {
1935  int idx=t205->ffit_chan[i].channels[0];
1936  if (idx==-1)
1937  {
1939  "::processFringeFile(): first channel index is -1, switch to the second one");
1940  idx=t205->ffit_chan[i].channels[1];
1941  };
1942  o->numOfAccPeriodsByChan_USB()->setElement(i, t206->accepted[i].usb);
1943  o->numOfAccPeriodsByChan_LSB()->setElement(i, t206->accepted[i].lsb);
1944  o->numOfSamplesByChan_USB()->setElement (i, isTmp?0.0:t206->weights[i].usb);
1945  o->numOfSamplesByChan_LSB()->setElement (i, isTmp?0.0:t206->weights[i].lsb);
1946  o->refFreqByChan()->setElement (i, t203->channels[idx].ref_freq*1.0e-6); // ->MHz
1947  (*o->polarization_1ByChan())[i] = t203->channels[idx].refpol;
1948  (*o->polarization_2ByChan())[i] = t203->channels[idx].rempol;
1949  o->fringeAmplitudeByChan()->setElement (i, t210->amp_phas[i].ampl);
1950  o->fringePhaseByChan()->setElement (i, t210->amp_phas[i].phase*DEG2RAD);
1951  // phase calibration data:
1952  o->phaseCalData_1ByChan()->setElement (0,i, t207->ref_pcamp [i].usb*1.0e4);
1953  o->phaseCalData_2ByChan()->setElement (0,i, t207->rem_pcamp [i].usb*1.0e4);
1954  o->phaseCalData_1ByChan()->setElement (1,i, t207->ref_pcphase [i].usb*DEG2RAD);
1955  o->phaseCalData_2ByChan()->setElement (1,i, t207->rem_pcphase [i].usb*DEG2RAD);
1956  o->phaseCalData_1ByChan()->setElement (2,i, t207->ref_pcfreq [i].usb*1.0e-3);
1957  o->phaseCalData_2ByChan()->setElement (2,i, t207->rem_pcfreq [i].usb*1.0e-3);
1958  o->phaseCalData_1ByChan()->setElement (3,i, t207->ref_pcoffset[i].usb*DEG2RAD);
1959  o->phaseCalData_2ByChan()->setElement (3,i, t207->rem_pcoffset[i].usb*DEG2RAD);
1960  o->phaseCalData_1ByChan()->setElement (4,i, t207->ref_errate [i]);
1961  o->phaseCalData_2ByChan()->setElement (4,i, t207->rem_errate [i]);
1962  // check and rescale phase cal data
1963  // compare usb and lsb pcal's:
1964  // amps:
1965  if (fabs(t207->ref_pcamp[i].usb - t207->ref_pcamp[i].lsb) > 1.0e-8)
1967  "::processFringeFile(): reference station, sidebands have different phase cal amplitudes: " +
1968  QString("").sprintf("%g vs %g, diff=%g", t207->ref_pcamp[i].usb, t207->ref_pcamp[i].lsb,
1969  fabs(t207->ref_pcamp[i].usb - t207->ref_pcamp[i].lsb)));
1970  if (fabs(t207->rem_pcamp[i].usb - t207->rem_pcamp[i].lsb) > 1.0e-8)
1972  "::processFringeFile(): remote station, sidebands have different phase cal amplitudes: " +
1973  QString("").sprintf("%g vs %g, diff=%g", t207->rem_pcamp[i].usb, t207->rem_pcamp[i].lsb,
1974  fabs(t207->rem_pcamp[i].usb - t207->rem_pcamp[i].lsb)));
1975  // phases:
1976  if (fabs(t207->ref_pcphase[i].usb - t207->ref_pcphase[i].lsb) > 1.0e-8)
1978  "::processFringeFile(): reference station, sidebands have different phase cal phases: " +
1979  QString("").sprintf("%g vs %g, diff=%g", t207->ref_pcphase[i].usb, t207->ref_pcphase[i].lsb,
1980  fabs(t207->ref_pcphase[i].usb - t207->ref_pcphase[i].lsb)));
1981  if (fabs(t207->rem_pcphase[i].usb - t207->rem_pcphase[i].lsb) > 1.0e-8)
1983  "::processFringeFile(): remote station, sidebands have different phase cal phases: " +
1984  QString("").sprintf("%g vs %g, diff=%g", t207->rem_pcphase[i].usb, t207->rem_pcphase[i].lsb,
1985  fabs(t207->rem_pcphase[i].usb - t207->rem_pcphase[i].lsb)));
1986  if (t207->ref_errate[i] != 0.0)
1988  "::processFringeFile(): reference station has a non-zero pcal error rate: " +
1989  QString("").sprintf("%g", t207->ref_errate[i]));
1990  if (t207->rem_errate[i] != 0.0)
1992  "::processFringeFile(): remote station has a non-zero pcal error rate: " +
1993  QString("").sprintf("%g", t207->ref_errate[i]));
1994  //
1995  // ok, continue:
1996  (*o->chanIdByChan()) [i] = t205->ffit_chan[i].ffit_chan_id;
1997  (*o->corelIndexNumUSB())[i] = t205->ffit_chan[i].channels[0]>-1 ?
1998  t203->channels[t205->ffit_chan[i].channels[0]].index:-1;
1999  (*o->corelIndexNumLSB())[i] = t205->ffit_chan[i].channels[1]>-1 ?
2000  t203->channels[t205->ffit_chan[i].channels[1]].index:-1;
2001  //
2002  // station #1:
2003  str = t203->channels[idx].ref_chan_id;
2004  if (hasStn_1Info)
2005  {
2006  if (si_1.channelByName_.contains(str))
2007  {
2008  const ChannelInfo &ci=si_1.channelByName_.value(str);
2009  o->loFreqByChan_1()->setElement(i, ci.if_total_lo_);
2010  (*o->bbcIdxByChan_1())[i] = ci.bbc_no_;
2011  }
2012  else
2013  {
2015  "::processFringeFile(): cannot find channel ID [" + str + "] in the corel root file " +
2016  vexFileName + " for the station " + station1Info->getKey());
2017  };
2018  };
2019  // station #2:
2020  str = t203->channels[idx].rem_chan_id;
2021  if (hasStn_2Info)
2022  {
2023  if (si_2.channelByName_.contains(str))
2024  {
2025  const ChannelInfo &ci=si_2.channelByName_.value(str);
2026  o->loFreqByChan_2()->setElement(i, ci.if_total_lo_);
2027  (*o->bbcIdxByChan_2())[i] = ci.bbc_no_;
2028  }
2029  else
2030  {
2032  "::processFringeFile(): cannot find channel ID [" + str + "] in the corel root file " +
2033  vexFileName + " for the station " + station2Info->getKey());
2034  };
2035  };
2036  //
2037  //
2038  //
2039  };
2040  // check and rescale phase cal data
2041  for (int i=0; i<numOfChannels; i++)
2042  {
2043  for (int j=0; j<5; j++)
2044  {
2045  if (isnan(o->phaseCalData_1ByChan()->getElement (j,i)))
2046  {
2048  "::processFringeFile(): st1 one of phase cal values is NAN " +
2049  QString("").sprintf("(chan=%d:dat=%d)", i, j) + " from the scan " + obs->getScanName() +
2050  " fringefile " + fringeFileName);
2051  o->phaseCalData_1ByChan()->setElement (j,i, -100.0);
2052  };
2053  if (isnan(o->phaseCalData_2ByChan()->getElement (j,i)))
2054  {
2056  "::processFringeFile(): st2 one of phase cal values is NAN " +
2057  QString("").sprintf("(chan=%d:dat=%d)", i, j) + " from the scan " + obs->getScanName() +
2058  " fringefile " + fringeFileName);
2059  o->phaseCalData_2ByChan()->setElement (j,i, -100.0);
2060  };
2061  };
2062  };
2063  //
2065  *o->refFreqByChan(), *o->fringeAmplitudeByChan(),
2067  o->getSampleRate(), refFreq, numOfChannels,
2068  effFreq4GR, effFreq4PH, effFreq4RT, getCorrelatorType(), o->strId());
2069  o->grDelay().setEffFreq(effFreq4GR);
2070  o->phDelay().setEffFreq(effFreq4PH);
2071  o->phDRate().setEffFreq(effFreq4RT);
2072  o->setPhaseCalModes(t207->pcal_mode);
2073  //
2074  //
2075  o->setFourfitVersion(0, t204->ff_version[0]);
2076  o->setFourfitVersion(1, t204->ff_version[1]);
2077  o->setFourfitControlFile(t204->control_file);
2078  o->setFourfitCommandOverride(t204->override);
2079  //
2080  o->setPhaseCalRates(0, t207->ref_pcrate*1.0e-6);
2081  o->setPhaseCalRates(1, t207->rem_pcrate*1.0e-6);
2082  o->setUvFrPerAsec(0, t202->u);
2083  o->setUvFrPerAsec(1, t202->v);
2084  o->setUrVr(0, t202->uf);
2085  o->setUrVr(1, t202->vf);
2086  o->setCorrClocks(0, 0, t202->ref_clock*1.0e-6); // musec -> sec
2087  o->setCorrClocks(0, 1, t202->rem_clock*1.0e-6); // musec -> sec
2088  o->setCorrClocks(1, 0, t202->ref_clockrate);
2089  o->setCorrClocks(1, 1, t202->rem_clockrate);
2090  o->setInstrDelay(0, t202->ref_idelay*1.0e-6); // musec -> sec
2091  o->setInstrDelay(1, t202->rem_idelay*1.0e-6); // musec -> sec
2092  o->setNlags(t202->nlags);
2093  for (int i=0; i<6; i++)
2094  o->setFourfitSearchParameters(i, t205->search[i]);
2095  o->setHopsRevisionNumber(t200->software_rev[0]);
2096  // check the rest of array, if the fields are non-zero, complain:
2097  for (unsigned int i=1; i<sizeof(type_200::software_rev)/sizeof(short); i++)
2098  if (t200->software_rev[i] != 0)
2100  "::processFringeFile(): type200's software revision has more than one meaningful field at " +
2101  "the scan " + obs->getScanName() + " fringefile " + fringeFileName);
2102 
2103  //
2104  // per band statistics:
2105  bandStation1Info->incNumTotal(DT_DELAY);
2106  bandStation2Info->incNumTotal(DT_DELAY);
2107  bandSourceInfo->incNumTotal(DT_DELAY);
2108  bandBaselineInfo->incNumTotal(DT_DELAY);
2109 
2110  bandStation1Info->incNumTotal(DT_RATE);
2111  bandStation2Info->incNumTotal(DT_RATE);
2112  bandSourceInfo->incNumTotal(DT_RATE);
2113  bandBaselineInfo->incNumTotal(DT_RATE);
2114  //
2115  clear_mk4fringe(&fringe);
2116  };
2117  //
2118  // clear stuff:
2119  delete[] filename;
2120 };
2121 
2122 
2123 
2124 //
2125 bool SgVlbiSession::getCorrelatorHistory(const QString& fileName)
2126 {
2127  QString str, strAux;
2128  QFile f(fileName);
2129  if (!bands_.size())
2130  {
2132  "::getCorrelatorHistory(): the session has no any band");
2133  return false;
2134  };
2135  SgVlbiHistory &history=bands_.at(0)->history();
2136  if (!f.exists())
2137  {
2139  "::getCorrelatorHistory(): the history file [" + f.fileName() + "] does not exist");
2140  return false;
2141  }
2142  else
2143  {
2144  if (f.open(QFile::ReadOnly))
2145  {
2146  QTextStream s(&f);
2147  int numOfStrs(0);
2148  QFileInfo fi(f.fileName());
2149  QDateTime d(fi.lastModified());
2150 
2151 //std::cout << " fi.lastModified(): " << qPrintable(fi.lastModified().toString()) << "\n";
2152 //std::cout << " fi.created (): " << qPrintable(fi.created().toString()) << "\n";
2153 
2154  // dealing with Qt's bug: in the current version of Qt QFileInfo::created() returns last modified
2155  // epoch, while QFileInfo::lastModified() reports time of creation (hope, they will fix it later):
2156  if (d < fi.created())
2157  d = fi.created();
2158  d = d.toUTC(); // keep history records in UTC
2159  // check the last modified epoch, sometimes when clocks at comuters are not synchronized,
2160  // it can show time that is ahead of the current time:
2161  QDateTime ct(QDateTime::currentDateTimeUtc());
2162  SgMJD tCreated( d.date().year(), d.date().month(), d.date().day(),
2163  d.time().hour(), d.time().minute(),
2164  d.time().second()+d.time().msec()*0.001);
2165  SgMJD tCurrent( ct.date().year(), ct.date().month(), ct.date().day(),
2166  ct.time().hour(), ct.time().minute(),
2167  ct.time().second()+ct.time().msec()*0.001);
2168  if (tCurrent < tCreated) // the file was created in future:
2169  {
2171  "::getCorrelatorHistory(): the correlator report file has the `last modified time' that "
2172  "is from future, " + tCreated.toString(SgMJD::F_YYYYMMDDHHMMSSSS) + ", the current time is: " +
2173  tCurrent.toString(SgMJD::F_YYYYMMDDHHMMSSSS) + ". The difference is " +
2174  interval2Str(tCreated - tCurrent));
2175  tCreated = tCurrent - 60.0/DAY2SEC;
2177  "::getCorrelatorHistory(): the `last modified time' of the correlator report file "
2178  "has been adjuted to " + tCreated.toString(SgMJD::F_YYYYMMDDHHMMSSSS));
2179  };
2180  while (!s.atEnd())
2181  {
2182  str = s.readLine();
2183  history.append(new SgVlbiHistoryRecord(tCreated, 1, str));
2184  numOfStrs++;
2185  };
2186  f.close();
2187  s.setDevice(NULL);
2189  "::getCorrelatorHistory(): read " + QString("").setNum(numOfStrs) +
2190  " strings from the history file [" + f.fileName() + "]");
2191  }
2192  else
2193  {
2195  "::getCorrelatorHistory(): cannot open the history file [" + f.fileName() + "] for read access");
2196  return false;
2197  };
2198  };
2199  // propagate to other bands:
2200  if (bands_.size() > 1)
2201  {
2202  for (int bIdx=1; bIdx<bands_.size(); bIdx++)
2203  {
2204  SgVlbiHistory &historyDest=bands_.at(bIdx)->history();
2205  for (int i=0; i<history.size(); i++)
2206  historyDest.append(new SgVlbiHistoryRecord(history.at(i)->getEpoch(),
2207  history.at(i)->getVersion(), history.at(i)->getText()));
2209  "::getCorrelatorHistory(): the history records were propagated to the " +
2210  bands_.at(bIdx)->getKey() + "-band");
2211  };
2212  }
2213  return true;
2214 };
2215 
2216 
2217 
2218 
2219 
2220 #endif // !defined HAVE_MK4_DATA_H || !defined HAVE_MK4_DFIO_H || !defined HAVE_MK4_VEX_H
2221 /*=====================================================================================================*/
2222 
2223 
2224 
2225 
2226 /*=====================================================================================================*/
SgLogger * logger
Definition: SgLogger.cpp:231
QString interval2Str(double days)
Definition: SgMJD.cpp:1371
#define DAY2SEC
radians to mas:
Definition: SgMathSupport.h:69
#define DEG2RAD
degrees to seconds:
Definition: SgMathSupport.h:49
QMap< QString, QString > src2src
QMap< QString, QString > stn2stn
void evaluateEffectiveFreqs(const SgVector &numOfAccPeriodsByChan_USB, const SgVector &numOfAccPeriodsByChan_LSB, const SgVector &refFreqByChan, const SgVector &fringeAmplitudeByChan, const SgVector &numOfSamplesByChan_USB, const SgVector &numOfSamplesByChan_LSB, double sampleRate, double refFreq, int numOfChannels, double &effFreq4GR, double &effFreq4PH, double &effFreq4RT, const QString &correlatorType, const QString &oId, bool useEqualWeights=false)
@ DT_DELAY
Definition: SgWrmsable.h:44
@ DT_RATE
Definition: SgWrmsable.h:45
void addAttr(uint a)
Definition: SgAttribute.h:202
virtual void write(LogLevel, quint32, const QString &, bool=false)
Definition: SgLogger.cpp:88
@ IO_TXT
Definition: SgLogger.h:65
@ IO_DBH
Definition: SgLogger.h:67
Definition: SgMJD.h:59
@ F_YYYYMMDDHHMMSSSS
Long verbose: Fri, the 2nd of Apr, 2010; 17hr 02min 43.6400sec.
Definition: SgMJD.h:67
@ F_INTERNAL
Digits, date and time: 20100402.71.
Definition: SgMJD.h:72
QString toString(Format format=F_Verbose) const
Definition: SgMJD.cpp:1008
int calcHour() const
Definition: SgMJD.h:493
int calcDayOfYear() const
Definition: SgMJD.cpp:238
static SgMJD currentMJD()
Definition: SgMJD.cpp:119
void setUpEpoch(int year, int month, int day, int hour, int min, double sec)
Definition: SgMJD.cpp:255
int calcMin() const
Definition: SgMJD.h:500
double calcSec() const
Definition: SgMJD.h:507
void setElement(unsigned int i, unsigned int j, double d)
Definition: SgMatrix.h:402
double getElement(unsigned int i, unsigned int j) const
Definition: SgMatrix.h:385
void setKey(const QString &key)
Definition: SgObjectInfo.h:447
int getIdx() const
Definition: SgObjectInfo.h:335
void incNumTotal(DataType, int=1)
Definition: SgObjectInfo.h:519
const QString & getKey() const
Definition: SgObjectInfo.h:319
virtual int getMediaIdx() const
virtual void setMediaIdx(int idx)
virtual void setMJD(const SgMJD &)
void setElement(unsigned int i, double d)
Definition: SgVector.h:348
void setAzimuthAngle(double angle)
void setEstZenithDelay(double d)
void setElevationAngle(double angle)
void setTapeId(const QString id)
void setFrequency(double f)
Definition: SgVlbiBand.h:402
void setTCreation(const SgMJD &t)
Definition: SgVlbiBand.h:410
QMap< QString, SgVlbiBaselineInfo * > & baselinesByName()
Definition: SgVlbiBand.h:376
QMap< QString, SgVlbiStationInfo * > & stationsByName()
Definition: SgVlbiBand.h:368
void setInputFileName(const QString &fileName)
Definition: SgVlbiBand.h:418
void setInputFileVersion(int version)
Definition: SgVlbiBand.h:426
QMap< int, SgVlbiBaselineInfo * > & baselinesByIdx()
Definition: SgVlbiBand.h:304
QMap< QString, SgVlbiSourceInfo * > & sourcesByName()
Definition: SgVlbiBand.h:384
QMap< int, SgVlbiSourceInfo * > & sourcesByIdx()
Definition: SgVlbiBand.h:312
double getFrequency() const
Definition: SgVlbiBand.h:320
QMap< int, SgVlbiStationInfo * > & stationsByIdx()
Definition: SgVlbiBand.h:296
@ Attr_PRIMARY
the band is a primary band;
Definition: SgVlbiBand.h:60
void setAmbiguitySpacing(double)
void setEffFreq(double)
void setResidualFringeFitting(double r)
void setGeocenterValue(double)
QVector< int > * corelIndexNumLSB()
void setEpochOfCorrelation(const SgMJD &)
const QString & getFourfitOutputFName() const
void setEpochCentral(const SgMJD &)
void setBitsPerSample(int bps)
void setTstart(const SgMJD &t)
void setCorrClocks(int i, int j, double d)
void setTotalPhase(double)
void setHopsRevisionNumber(int num)
double getSampleRate() const
QVector< char > * polarization_1ByChan()
SgVector * loFreqByChan_1()
QVector< char > * chanIdByChan()
void setIncohSegmAddAmp(double d)
QVector< int > * corelIndexNumUSB()
void setPhaseCalModes(int modes)
SgMatrix * phaseCalData_2ByChan()
void setAcceptedRatio(double d)
void setTstop(const SgMJD &t)
void setEpochOfFourfitting(const SgMJD &)
SgVector * numOfAccPeriodsByChan_LSB()
void setIncohChanAddAmp(double d)
void setCentrOffset(double offset)
void setEffIntegrationTime(double d)
void setFourfitOutputFName(const QString &)
QVector< char > * polarization_2ByChan()
SgVector * numOfAccPeriodsByChan_USB()
QVector< int > * bbcIdxByChan_1()
void setFourfitControlFile(const QString &cf)
SgVlbiMeasurement & phDRate()
void setGeocenterResidPhase(double d)
void setCorrelStarElev_2(double v)
void setSnr(double)
void setProbabOfFalseDetection(double d)
void setQualityFactor(int)
QString strId() const
void setNlags(int n)
void setGeocenterTotalPhase(double d)
void setDiscardRatio(double d)
SgVector * fringeAmplitudeByChan()
void setCorrCoeff(double)
void setEpochOfScan(const SgMJD &)
void setUrVr(int i, double d)
void setCorrelZdelay_1(double v)
SgVector * numOfSamplesByChan_LSB()
void setAprioriDra(int i, double d)
void setInstrDelay(int i, double d)
void setPhaseCalRates(int i, double d)
void setStopOffset(int offset)
void setUvFrPerAsec(int i, double d)
void setErrorCode(const QString &)
SgMatrix * phaseCalData_1ByChan()
SgVector * numOfSamplesByChan_USB()
void setFourfitCommandOverride(const QString &co)
void setReferenceFrequency(double)
void setCorrelZdelay_2(double v)
double getReferenceFrequency() const
void allocateChannelsSetupStorages(int numOfChans)
SgVlbiMeasurement & phDelay()
void setTapeQualityCode(const QString &code)
SgVector * loFreqByChan_2()
SgVlbiMeasurement & grDelay()
void setStartOffset(int offset)
SgVlbiMeasurement & sbDelay()
SgVector * fringePhaseByChan()
SgVector * refFreqByChan()
void setFourfitSearchParameters(int i, double d)
void setSampleRate(double sr)
void setCorrelStarElev_1(double v)
QVector< int > * bbcIdxByChan_2()
void setFourfitVersion(int idx, int ver)
void setStation1Idx(short int idx)
void setScanId(const QString &sId)
void setSourceIdx(short int idx)
void setApLength(double d)
bool addObservable(const QString &, const SgVlbiObservable &)
void setDTecStdDev(double e)
void setScanName(const QString &sName)
void setDTec(double d)
void setupActiveObservable(const QString &)
void setCorrRootFileName(const QString &sName)
void setStation2Idx(short int idx)
SgVlbiObservable * observable(const QString &)
const QString & getScanName() const
QMap< QString, SgVlbiObservable * > & observableByKey()
const QString & getKey()
void setBaselineIdx(short int idx)
void setKey(const QString &)
const QString & getCorrelatorType() const
void setOfficialName(const QString &name)
void setSchedulerName(const QString &name)
void setSessionCode(const QString &code)
void setDescription(const QString &description)
@ OT_MK4
observations are from Mk4-compatible correlator output;
void setName(const QString &name)
void setCorrelatorType(const QString &name)
CorrelatorPostProcSoftware cppsSoft_
@ Attr_FF_CREATED
the session has been imported from correlator;//vgosDbMake
const QString & getCorrelatorName() const
int getExperimentSerialNumber() const
void setExperimentSerialNumber(int sn)
const QString & getPiAgencyName() const
const QString & getDescription() const
void setNetworkSuffix(const QString &suffix)
void setSubmitterName(const QString &name)
void setCorrelatorName(const QString &name)
const QString & getSessionCode() const
void setPiAgencyName(const QString &name)
void setOriginType(OriginType type)
StationsByName stationsByName_
QMap< QString, SgVlbiObservation * > observationByKey_
bool getDataFromFringeFiles(const QString &path2, const QString &altDatabaseName, const QString &altCorrelatorName, const QString &historyFileName, const QString &mapFileName, const QList< QString > &)
QList< SgVlbiBand * > bands_
void processFringeFile(const QString &path2file, const QString &fringeFileName, const QMap< QString, StationInfo > &stnsInfo, const VexInfo &, const QString &vexFileName, const QMap< QString, QString > &stnNameById, const QMap< QString, QString > &stnNameByI, const QMap< QString, QString > &stn2stn, const QMap< QString, QString > &src2src, const QMap< QString, QString > &bnd2bnd, const QMap< QString, int > &fringeErrorCodeByInt, int &expSerialNumber)
bool selfCheck(bool guiExpected)
QMap< QString, SgVlbiBand * > bandByKey_
QList< SgVlbiObservation * > observations_
bool getCorrelatorHistory(const QString &fileName)
QMap< int, SgVlbiStationInfo * > stationsByIdx_
void importMapFile(const QString &mapFileName, QMap< QString, QString > &map4Stn, QMap< QString, QString > &map4Src, QMap< QString, QString > &map4Bnd)
void parseVexFile(const QString &, QString &, QString &)
BaselinesByName baselinesByName_
void processVexFile(const QString &, QMap< QString, StationInfo > &, VexInfo &, const QMap< QString, QString > &stn2stn, QString &correlatorName)
SgVlbiBand * primaryBand_
static QString className()
QMap< int, SgVlbiBaselineInfo * > baselinesByIdx_
SourcesByName sourcesByName_
bool check4NameMap(const QMap< QString, QString > &map, QString &name)
QMap< int, SgVlbiSourceInfo * > sourcesByIdx_
QMap< QString, SgVlbiAuxObservation * > * auxObservationByScanId()
void setSid(char c1, char c2)