1 /*
2  * Copyright (c) 2011-2021, The OSKAR Developers.
3  * See the LICENSE file at the top-level directory of this distribution.
4  */
5 
6 #include "ms/oskar_measurement_set.h"
7 #include "ms/private_ms.h"
8 
9 #include <tables/Tables.h>
10 #include <casa/Arrays/Vector.h>
11 
12 #include <cstdlib>
13 #include <cstdio>
14 
15 using namespace casacore;
16 
_oskar_ms_open(const char * filename,bool readonly)17 static oskar_MeasurementSet* _oskar_ms_open(const char* filename, bool readonly)
18 {
19     oskar_MeasurementSet* p = (oskar_MeasurementSet*)
20             calloc(1, sizeof(oskar_MeasurementSet));
21     p->num_receptors = 2;
22     Vector<Double> range(2, 0.0);
23 
24     try
25     {
26         // Create the MeasurementSet. Storage managers are recreated as needed.
27         TableLock::LockOption lock = TableLock::PermanentLocking;
28         Table::TableOption mode = Table::Update;
29         if (readonly)
30         {
31             lock = TableLock::NoLocking;
32             mode = Table::Old;
33         }
34 #ifdef OSKAR_MS_NEW
35         p->ms = new Table(filename, lock, mode);
36         bind_refs(p);
37 #else
38         p->ms = new MeasurementSet(filename, lock, mode);
39 
40         // Create the MSMainColumns and MSColumns objects for accessing data
41         // in the main table and subtables.
42         p->msc = new MSColumns(*(p->ms));
43         p->msmc = new MSMainColumns(*(p->ms));
44 #endif
45     }
46     catch (AipsError& e)
47     {
48         fprintf(stderr, "Caught AipsError: %s\n", e.what());
49         fflush(stderr);
50         oskar_ms_close(p);
51         return 0;
52     }
53 
54 #ifdef OSKAR_MS_NEW
55     Table spw(p->ms->tableName() + "/SPECTRAL_WINDOW", Table::Old);
56     Table field(p->ms->tableName() + "/FIELD", Table::Old);
57     const int num_spectral_windows = spw.nrow();
58     const int num_fields = field.nrow();
59 #else
60     const int num_spectral_windows = p->ms->spectralWindow().nrow();
61     const int num_fields = p->ms->field().nrow();
62 #endif
63 
64     // Refuse to open if there is more than one spectral window.
65     if (num_spectral_windows != 1)
66     {
67         fprintf(stderr, "OSKAR can read Measurement Sets with one spectral "
68                 "window only. Use 'split' or 'mstransform' in CASA to select "
69                 "the spectral window first.\n");
70         fflush(stderr);
71         oskar_ms_close(p);
72         return 0;
73     }
74 
75     // Refuse to open if there is more than one field.
76     if (num_fields != 1)
77     {
78         fprintf(stderr, "OSKAR can read Measurement Sets with one target "
79                 "field only. Use 'split' or 'mstransform' in CASA to select "
80                 "the target field first.\n");
81         fflush(stderr);
82         oskar_ms_close(p);
83         return 0;
84     }
85 
86 #ifdef OSKAR_MS_NEW
87     // Get the data dimensions.
88     Table pol(p->ms->tableName() + "/POLARIZATION", Table::Old);
89     ScalarColumn<Int> numCorr(pol, "NUM_CORR");
90     if (pol.nrow() > 0)
91     {
92         p->num_pols = numCorr.get(0);
93     }
94     if (num_spectral_windows > 0)
95     {
96         ScalarColumn<Int> numChan(spw, "NUM_CHAN");
97         ScalarColumn<Double> refFrequency(spw, "REF_FREQUENCY");
98         ArrayColumn<Double> chanWidth(spw, "CHAN_WIDTH");
99         p->num_channels = numChan.get(0);
100         p->freq_start_hz = refFrequency.get(0);
101         p->freq_inc_hz = (chanWidth.get(0))(IPosition(1, 0));
102     }
103     Table antenna(p->ms->tableName() + "/ANTENNA", Table::Old);
104     p->num_stations = antenna.nrow();
105     if (p->ms->nrow() > 0)
106     {
107         p->time_inc_sec = p->msmc.interval.get(0);
108     }
109 
110     // Get the phase centre.
111     if (num_fields > 0)
112     {
113         ArrayColumn<Double> phaseDir(field, "PHASE_DIR");
114         Matrix<Double> dir;
115         phaseDir.get(0, dir);
116         if (dir.nrow() > 1)
117         {
118             p->phase_centre_rad[0] = dir(0, 0);
119             p->phase_centre_rad[1] = dir(1, 0);
120         }
121     }
122 
123     // Get the time range.
124     Table observation(p->ms->tableName() + "/OBSERVATION", Table::Old);
125     ArrayColumn<Double> timeRange(observation, "TIME_RANGE");
126     if (observation.nrow() > 0)
127     {
128         timeRange.get(0, range);
129     }
130 #else
131     // Get the data dimensions.
132     if (p->ms->polarization().nrow() > 0)
133         p->num_pols = p->msc->polarization().numCorr().get(0);
134     if (num_spectral_windows > 0)
135     {
136         p->num_channels = p->msc->spectralWindow().numChan().get(0);
137         p->freq_start_hz = p->msc->spectralWindow().refFrequency().get(0);
138         p->freq_inc_hz = (p->msc->spectralWindow().chanWidth().get(0))(
139                 IPosition(1, 0));
140     }
141     p->num_stations = p->ms->antenna().nrow();
142     if (p->ms->nrow() > 0)
143         p->time_inc_sec = p->msc->interval().get(0);
144 
145     // Get the phase centre.
146     if (num_fields > 0)
147     {
148         Vector<MDirection> dir;
149         p->msc->field().phaseDirMeasCol().get(0, dir, true);
150         if (dir.size() > 0)
151         {
152             Vector<Double> v = dir(0).getAngle().getValue();
153             p->phase_centre_rad[0] = v(0);
154             p->phase_centre_rad[1] = v(1);
155         }
156     }
157 
158     // Get the time range.
159     if (p->msc->observation().nrow() > 0)
160         p->msc->observation().timeRange().get(0, range);
161 #endif
162     p->start_time = range[0];
163     p->end_time = range[1];
164 
165     return p;
166 }
167 
oskar_ms_open(const char * filename)168 oskar_MeasurementSet* oskar_ms_open(const char* filename)
169 {
170     return _oskar_ms_open(filename, false);
171 }
172 
oskar_ms_open_readonly(const char * filename)173 oskar_MeasurementSet* oskar_ms_open_readonly(const char* filename)
174 {
175     return _oskar_ms_open(filename, true);
176 }
177