Line data Source code
1 : /*
2 : * ScantableIterator.h
3 : *
4 : * Created on: Jan 28, 2016
5 : * Author: nakazato
6 : */
7 :
8 : #ifndef SINGLEDISH_FILLER_SCANTABLEITERATOR_H_
9 : #define SINGLEDISH_FILLER_SCANTABLEITERATOR_H_
10 :
11 : #include <casacore/casa/Arrays/Vector.h>
12 : #include <casacore/casa/Utilities/Compare.h>
13 : #include <casacore/casa/Utilities/Sort.h>
14 :
15 : #include <casacore/measures/Measures/MFrequency.h>
16 :
17 : #include <casacore/tables/Tables/Table.h>
18 : #include <casacore/tables/Tables/ScalarColumn.h>
19 : #include <casacore/tables/Tables/ArrayColumn.h>
20 : #include <casacore/tables/TaQL/ExprNode.h>
21 : #include <singledishfiller/Filler/FieldRecord.h>
22 : #include <singledishfiller/Filler/FillerUtil.h>
23 : #include <singledishfiller/Filler/SourceRecord.h>
24 : #include <singledishfiller/Filler/SpectralWindowRecord.h>
25 : #include <singledishfiller/Filler/SysCalRecord.h>
26 :
27 : using namespace casacore;
28 :
29 : namespace {
30 : template<class T>
31 0 : inline void getDataRangePerId(casacore::Vector<casacore::uInt> const &index_list,
32 : casacore::Vector<T> const &id_list, size_t start,
33 : size_t end, std::map<T, casacore::Block<casacore::uInt> > &range_index) {
34 0 : casacore::uInt id_prev = id_list[index_list[start]];
35 0 : casacore::uInt id_min = index_list[start];
36 0 : casacore::uInt id_max = 0;
37 0 : casacore::Block < casacore::uInt > current_index(2);
38 0 : for (casacore::uInt i = start + 1; i < end; ++i) {
39 0 : casacore::uInt j = index_list[i];
40 0 : casacore::uInt current_id = id_list[j];
41 : // std::cout << "weather_id = " << weather_id << " id_prev = " << id_prev
42 : // << " time range (" << time_min << "," << time_max << ")" << std::endl;
43 0 : if (current_id != id_prev) {
44 0 : id_max = index_list[i - 1];
45 0 : current_index[0] = id_min;
46 0 : current_index[1] = id_max;
47 0 : range_index[id_prev] = current_index;
48 :
49 0 : id_prev = current_id;
50 0 : id_min = j;
51 : }
52 : }
53 0 : casacore::uInt last_id = id_list[index_list[end - 1]];
54 0 : if (range_index.find(last_id) == range_index.end()) {
55 0 : id_max = index_list[end - 1];
56 0 : current_index[0] = id_min;
57 0 : current_index[1] = id_max;
58 0 : range_index[last_id] = current_index;
59 : }
60 0 : }
61 :
62 : }
63 :
64 : namespace casa { //# NAMESPACE CASA - BEGIN
65 :
66 : class ScantableIteratorBase {
67 : public:
68 0 : ScantableIteratorBase() :
69 0 : current_iter_(0), num_iter_(0) {
70 0 : }
71 0 : virtual ~ScantableIteratorBase() {
72 0 : }
73 0 : void initialize(size_t num_iter) {
74 0 : num_iter_ = num_iter;
75 0 : current_iter_ = 0;
76 0 : }
77 0 : bool moreData() const {
78 0 : return current_iter_ < num_iter_;
79 : }
80 0 : void next() {
81 0 : ++current_iter_;
82 0 : }
83 :
84 : protected:
85 : size_t current_iter_;
86 :
87 : private:
88 : size_t num_iter_;
89 : };
90 :
91 : template<class _Product, class _Record>
92 : class ScantableIteratorInterface: public ScantableIteratorBase {
93 : public:
94 : using Product = _Product;
95 : using Record = _Record;
96 0 : ScantableIteratorInterface(casacore::Table const &table) :
97 0 : ScantableIteratorBase(), main_table_(table) {
98 0 : }
99 0 : virtual ~ScantableIteratorInterface() {}
100 : virtual void getEntry(Record &record) = 0;
101 : virtual void getProduct(Product *p) = 0;
102 : protected:
103 : casacore::Table const main_table_;
104 : };
105 :
106 : class ScantableFrequenciesIterator final :
107 : public ScantableIteratorInterface<std::map<casacore::Int, casacore::Int>, sdfiller::SpectralWindowRecord> {
108 : public:
109 0 : ScantableFrequenciesIterator(casacore::Table const &table) :
110 0 : ScantableIteratorInterface(table) {
111 0 : casacore::TableRecord const &header = main_table_.keywordSet();
112 0 : sub_table_ = header.asTable("FREQUENCIES");
113 : //size_t nrow = sub_table_.nrow();
114 0 : casacore::ScalarColumn < casacore::uInt > ifno_column(main_table_, "IFNO");
115 0 : casacore::Vector < casacore::uInt > ifno_list = ifno_column.getColumn();
116 0 : casacore::Sort sorter;
117 0 : sorter.sortKey(ifno_list.data(), TpUInt);
118 0 : casacore::Vector < casacore::uInt > index_vector;
119 0 : casacore::uInt n = sorter.sort(index_vector, ifno_list.nelements(),
120 : casacore::Sort::HeapSort | casacore::Sort::NoDuplicates);
121 :
122 0 : initialize(n);
123 0 : ifno_list_.resize(n);
124 0 : for (casacore::uInt i = 0; i < n; ++i) {
125 0 : ifno_list_[i] = ifno_list[index_vector[i]];
126 : }
127 :
128 0 : casacore::ScalarColumn < casacore::uInt > freq_id_column(main_table_, "FREQ_ID");
129 :
130 : // attach columns
131 0 : id_column_.attach(sub_table_, "ID");
132 0 : refpix_column_.attach(sub_table_, "REFPIX");
133 0 : refval_column_.attach(sub_table_, "REFVAL");
134 0 : increment_column_.attach(sub_table_, "INCREMENT");
135 0 : id_list_ = id_column_.getColumn();
136 0 : }
137 0 : virtual ~ScantableFrequenciesIterator() {
138 0 : }
139 :
140 0 : void getEntry(Record &record) override {
141 0 : size_t const irow = current_iter_;
142 : // std::cout << "getEntry for row " << irow << std::endl;
143 0 : casacore::Int spw_id = ifno_list_[irow];
144 0 : casacore::Table subtable = main_table_(main_table_.col("IFNO") == (casacore::uInt) spw_id, 1);
145 0 : casacore::ScalarColumn < casacore::uInt > freq_id_column(subtable, "FREQ_ID");
146 0 : casacore::uInt freq_id = freq_id_column(0);
147 0 : casacore::Int jrow = -1;
148 0 : for (casacore::uInt i = 0; i < id_list_.size(); ++i) {
149 0 : if (id_list_[i] == freq_id) {
150 0 : jrow = (casacore::Int) i;
151 0 : break;
152 : }
153 : }
154 0 : casacore::ArrayColumn<casacore::uChar> flag_column(subtable, "FLAGTRA");
155 0 : casacore::Int num_chan = flag_column.shape(0)[0];
156 0 : casacore::String freq_frame = sub_table_.keywordSet().asString("BASEFRAME");
157 : casacore::MFrequency::Types frame_type;
158 0 : casacore::Bool status = casacore::MFrequency::getType(frame_type, freq_frame);
159 0 : if (!status) {
160 0 : frame_type = casacore::MFrequency::N_Types;
161 : }
162 0 : casacore::Double refpix = refpix_column_(jrow);
163 0 : casacore::Double refval = refval_column_(jrow);
164 0 : casacore::Double increment = increment_column_(jrow);
165 : // std::cout << "spw " << spw_id << " nchan " << num_chan << " mfr "
166 : // << (casacore::Int) frame_type << " (" << freq_frame << ") ref " << refpix << ", "
167 : // << refval << ", " << increment << std::endl;
168 0 : record.spw_id = spw_id;
169 0 : record.num_chan = num_chan;
170 0 : record.meas_freq_ref = frame_type;
171 0 : record.refpix = refpix;
172 0 : record.refval = refval;
173 0 : record.increment = increment;
174 :
175 : // update product
176 0 : product_[spw_id] = num_chan;
177 0 : }
178 0 : void getProduct(Product *p) override {
179 0 : if (p) {
180 0 : for (auto iter = product_.begin(); iter != product_.end(); ++iter) {
181 0 : (*p)[iter->first] = iter->second;
182 : }
183 : }
184 0 : }
185 :
186 : private:
187 : casacore::Table sub_table_;
188 : casacore::ScalarColumn<casacore::uInt> id_column_;
189 : casacore::ScalarColumn<casacore::Double> refpix_column_;
190 : casacore::ScalarColumn<casacore::Double> refval_column_;
191 : casacore::ScalarColumn<casacore::Double> increment_column_;
192 : casacore::Vector<casacore::uInt> ifno_list_;
193 : casacore::Vector<casacore::uInt> id_list_;
194 : Product product_;
195 : };
196 :
197 : class ScantableFieldIterator final :
198 : public ScantableIteratorInterface<std::map<casacore::String, casacore::Int>, sdfiller::FieldRecord> {
199 : public:
200 0 : ScantableFieldIterator(casacore::Table const &table) :
201 0 : ScantableIteratorInterface(table), row_list_(), is_reserved_(), field_column_(
202 0 : main_table_, "FIELDNAME"), source_column_(main_table_, "SRCNAME"), time_column_(
203 0 : main_table_, "TIME"), direction_column_(main_table_, "SRCDIRECTION"), scanrate_column_(
204 0 : main_table_, "SCANRATE"), direction_storage_(2, 2, 0.0) {
205 0 : casacore::Vector < casacore::String > field_name_list = field_column_.getColumn();
206 0 : casacore::Sort sorter;
207 0 : sorter.sortKey(field_name_list.data(), TpString);
208 0 : casacore::uInt n = sorter.sort(row_list_, field_name_list.size(),
209 : casacore::Sort::QuickSort | casacore::Sort::NoDuplicates);
210 0 : is_reserved_.resize(n);
211 0 : is_reserved_ = false;
212 0 : initialize(n);
213 0 : }
214 :
215 0 : virtual ~ScantableFieldIterator() {
216 0 : }
217 :
218 0 : void getEntry(Record &record) override {
219 0 : casacore::uInt const irow = row_list_[current_iter_];
220 0 : casacore::String field_name_with_id = field_column_(irow);
221 0 : auto pos = field_name_with_id.find("__");
222 : auto defaultFieldId =
223 0 : [&]() {
224 0 : casacore::Int my_field_id = 0;
225 0 : while (is_reserved_[my_field_id] && (casacore::uInt)my_field_id < is_reserved_.size()) {
226 0 : my_field_id++;
227 : }
228 0 : if ((casacore::uInt)my_field_id >= is_reserved_.size()) {
229 0 : throw casacore::AipsError("Internal inconsistency in FIELD_ID numbering");
230 : }
231 0 : is_reserved_[my_field_id] = true;
232 0 : return my_field_id;
233 0 : };
234 0 : if (pos != casacore::String::npos) {
235 0 : record.name = field_name_with_id.substr(0, pos);
236 0 : casacore::Int field_id = casacore::String::toInt(field_name_with_id.substr(pos + 2));
237 0 : if (field_id < 0 || (casacore::uInt) field_id >= is_reserved_.size()) {
238 0 : record.field_id = defaultFieldId();
239 0 : } else if (!is_reserved_[field_id]) {
240 0 : record.field_id = field_id;
241 0 : is_reserved_[field_id] = true;
242 : } else {
243 0 : record.field_id = defaultFieldId();
244 : }
245 : } else {
246 0 : record.name = field_name_with_id;
247 0 : record.field_id = defaultFieldId();
248 : }
249 0 : record.time = time_column_(irow) * 86400.0;
250 0 : record.source_name = source_column_(irow);
251 0 : record.frame = casacore::MDirection::J2000;
252 : casacore::Matrix < Double
253 0 : > direction(direction_storage_(casacore::IPosition(2, 0, 0), casacore::IPosition(2, 1, 0)));
254 : // std::cout << "direction = " << direction << " (shape " << direction.shape()
255 : // << ")" << std::endl;
256 0 : direction_storage_.column(0) = direction_column_(irow);
257 0 : if (scanrate_column_.isDefined(irow)) {
258 0 : casacore::Vector < casacore::Double > scan_rate = scanrate_column_(irow);
259 0 : if (anyNE(scan_rate, 0.0)) {
260 0 : direction_storage_.column(1) = scan_rate;
261 0 : direction.reference(direction_storage_);
262 : }
263 0 : }
264 : // std::cout << "direction = " << direction << " (shape " << direction.shape()
265 : // << ")" << std::endl;
266 0 : record.direction = direction;
267 :
268 : // update product
269 0 : product_[field_name_with_id] = record.field_id;
270 0 : }
271 0 : void getProduct(Product *p) override {
272 0 : if (p) {
273 0 : for (auto iter = product_.begin(); iter != product_.end(); ++iter) {
274 0 : (*p)[iter->first] = iter->second;
275 : }
276 : }
277 0 : }
278 :
279 : private:
280 : casacore::Vector<casacore::uInt> row_list_;
281 : casacore::Vector<casacore::Bool> is_reserved_;
282 : casacore::ScalarColumn<casacore::String> field_column_;
283 : casacore::ScalarColumn<casacore::String> source_column_;
284 : casacore::ScalarColumn<casacore::Double> time_column_;
285 : casacore::ArrayColumn<casacore::Double> direction_column_;
286 : casacore::ArrayColumn<casacore::Double> scanrate_column_;
287 : casacore::Matrix<casacore::Double> direction_storage_;
288 : Product product_;
289 : };
290 :
291 : class ScantableSourceIterator final :
292 : public ScantableIteratorInterface<void *, sdfiller::SourceRecord> {
293 : public:
294 0 : ScantableSourceIterator(casacore::Table const &table) :
295 0 : ScantableIteratorInterface(table), name_column_(main_table_, "SRCNAME"), direction_column_(
296 0 : main_table_, "SRCDIRECTION"), proper_motion_column_(main_table_,
297 0 : "SRCPROPERMOTION"), sysvel_column_(main_table_, "SRCVELOCITY"), molecule_id_column_(
298 0 : main_table_, "MOLECULE_ID"), ifno_column_(main_table_, "IFNO"), molecules_table_(), row_list_(), source_id_map_() {
299 0 : casacore::TableRecord const &header = main_table_.keywordSet();
300 0 : molecules_table_ = header.asTable("MOLECULES");
301 0 : restfrequency_column_.attach(molecules_table_, "RESTFREQUENCY");
302 0 : molecule_name_column_.attach(molecules_table_, "NAME");
303 0 : casacore::Vector < casacore::String > source_name_list = name_column_.getColumn();
304 0 : casacore::Vector < casacore::uInt > ifno_list = ifno_column_.getColumn();
305 0 : casacore::Sort sorter;
306 0 : sorter.sortKey(source_name_list.data(), TpString);
307 0 : casacore::Vector < casacore::uInt > unique_vector;
308 0 : casacore::uInt num_unique = sorter.sort(unique_vector, source_name_list.size(),
309 : casacore::Sort::QuickSort | casacore::Sort::NoDuplicates);
310 0 : for (casacore::uInt i = 0; i < num_unique; ++i) {
311 0 : source_id_map_[name_column_(unique_vector[i])] = (casacore::Int) i;
312 : }
313 0 : casacore::Sort sorter2;
314 0 : sorter2.sortKey(source_name_list.data(), TpString);
315 0 : sorter2.sortKey(ifno_list.data(), TpUInt);
316 0 : unique_vector.resize();
317 0 : num_unique = sorter2.sort(row_list_, source_name_list.size(),
318 : casacore::Sort::QuickSort | casacore::Sort::NoDuplicates);
319 : // for (casacore::uInt i = 0; i < num_unique; ++i) {
320 : // std::cout << i << ": SRCNAME \"" << name_column_(row_list_[i])
321 : // << "\" IFNO " << ifno_column_(row_list_[i]) << std::endl;
322 : // }
323 0 : initialize(num_unique);
324 :
325 : // generate molecule_id_map_
326 0 : casacore::ScalarColumn < casacore::uInt > id_column(molecules_table_, "ID");
327 0 : casacore::Vector < casacore::uInt > molecule_id_list = id_column.getColumn();
328 0 : for (casacore::uInt i = 0; i < id_column.nrow(); ++i) {
329 0 : molecule_id_map_[molecule_id_list[i]] = i;
330 : }
331 :
332 : // generate sorted_index_
333 0 : casacore::uInt nrow_main = main_table_.nrow();
334 0 : casacore::ScalarColumn < casacore::String > srcname_column(main_table_, "SRCNAME");
335 0 : casacore::ScalarColumn < casacore::uInt > ifno_column(main_table_, "IFNO");
336 0 : casacore::ScalarColumn < casacore::Double > time_column(main_table_, "TIME");
337 0 : casacore::ScalarColumn < casacore::Double > &interval_column = time_column;
338 0 : casacore::Sort sorter3;
339 0 : casacore::Vector < casacore::String > srcname_list = srcname_column.getColumn();
340 0 : casacore::Vector < casacore::Double > time_list = time_column.getColumn();
341 0 : sorter3.sortKey(srcname_list.data(), TpString, 0, casacore::Sort::Ascending);
342 0 : sorter3.sortKey(ifno_list.data(), TpUInt, 0, casacore::Sort::Ascending);
343 0 : sorter3.sortKey(time_list.data(), TpDouble, 0, casacore::Sort::Ascending);
344 0 : casacore::Vector < casacore::uInt > index_list;
345 0 : sorter3.sort(index_list, nrow_main, casacore::Sort::QuickSort);
346 :
347 0 : std::vector<size_t> srcname_boundary;
348 0 : srcname_boundary.push_back(0u);
349 0 : casacore::String current = srcname_list[index_list[0]];
350 0 : for (casacore::uInt i = 1; i < nrow_main; ++i) {
351 0 : casacore::String name = srcname_list[index_list[i]];
352 0 : if (current != name) {
353 0 : srcname_boundary.push_back(i);
354 0 : current = name;
355 : }
356 0 : }
357 0 : srcname_boundary.push_back(nrow_main);
358 :
359 0 : constexpr double kDay2Sec = 86400.0;
360 0 : interval_column.attach(main_table_, "INTERVAL");
361 0 : time_range_.clear();
362 0 : for (size_t i = 0; i < srcname_boundary.size() - 1; ++i) {
363 0 : casacore::String name = srcname_list[index_list[srcname_boundary[i]]];
364 0 : size_t start = srcname_boundary[i];
365 0 : size_t end = srcname_boundary[i + 1];
366 0 : std::map<casacore::uInt, casacore::Block<casacore::Double> > range;
367 0 : std::map<casacore::uInt, casacore::Block<casacore::uInt> > range_index;
368 0 : getDataRangePerId(index_list, ifno_list, start, end,
369 : range_index);
370 0 : for (auto iter = range_index.begin(); iter != range_index.end(); ++iter) {
371 0 : casacore::Block<casacore::uInt> idx = iter->second;
372 0 : casacore::Block<casacore::Double> time_range(2);
373 0 : time_range[0] = time_list[idx[0]] * kDay2Sec
374 0 : - 0.5 * interval_column(idx[0]);
375 0 : time_range[1] = time_list[idx[1]] * kDay2Sec
376 0 : + 0.5 * interval_column(idx[1]);
377 0 : range[iter->first] = time_range;
378 0 : }
379 0 : time_range_[name] = range;
380 0 : }
381 :
382 : // for (auto i = time_range_.begin(); i != time_range_.end(); ++i) {
383 : // std::cout << "SRCNAME \"" << i->first << "\": " << std::endl;
384 : // for (auto j = i->second.begin(); j != i->second.end(); ++j) {
385 : // std::cout << " " << j->first << ": " << j->second[0] << " "
386 : // << j->second[1] << std::endl;
387 : // }
388 : // }
389 0 : }
390 :
391 0 : virtual ~ScantableSourceIterator() {
392 0 : }
393 :
394 0 : void getEntry(sdfiller::SourceRecord &record) override {
395 0 : casacore::uInt const irow = row_list_[current_iter_];
396 0 : casacore::uInt const ifno = ifno_column_(irow);
397 0 : record.name = name_column_(irow);
398 0 : record.source_id = source_id_map_[record.name];
399 0 : record.spw_id = ifno; //ifno_column_(irow);
400 0 : record.direction = casacore::MDirection(
401 0 : casacore::Quantum<casacore::Vector<casacore::Double> >(direction_column_(irow), "rad"),
402 0 : casacore::MDirection::J2000);
403 0 : record.proper_motion = proper_motion_column_(irow);
404 0 : casacore::uInt molecule_id = molecule_id_column_(irow);
405 0 : auto iter = molecule_id_map_.find(molecule_id);
406 0 : if (iter != molecule_id_map_.end()) {
407 0 : casacore::uInt jrow = iter->second;
408 0 : if (restfrequency_column_.isDefined(jrow)) {
409 0 : record.rest_frequency = restfrequency_column_(jrow);
410 : }
411 0 : if (molecule_name_column_.isDefined(jrow)) {
412 0 : record.transition = molecule_name_column_(jrow);
413 : }
414 : }
415 : // 2016/02/04 TN
416 : // comment out the following else block since if no ID is found in
417 : // molecule_id_map_ it indicates that there is no corresponding
418 : // entry in MOLECULES table for given MOLECULE_ID. Serch result is
419 : // always empty table.
420 : // else {
421 : // casacore::Table t = molecules_table_(molecules_table_.col("ID") == molecule_id, 1);
422 : // if (t.nrow() == 1) {
423 : // casacore::ArrayColumn<casacore::Double> rest_freq_column(t, "RESTFREQUENCY");
424 : // casacore::ArrayColumn<casacore::String> molecule_name_column(t, "NAME");
425 : // if (rest_freq_column.isDefined(0)) {
426 : // record.rest_frequency = rest_freq_column(0);
427 : // }
428 : // if (molecule_name_column.isDefined(0)) {
429 : // record.transition = molecule_name_column(0);
430 : // }
431 : // }
432 : // }
433 0 : casacore::Double sysvel = sysvel_column_(irow);
434 0 : record.num_lines = record.rest_frequency.size();
435 0 : record.sysvel = casacore::Vector < casacore::Double > (record.num_lines, sysvel);
436 :
437 : // casacore::Table t = main_table_(
438 : // main_table_.col("SRCNAME") == record.name
439 : // && main_table_.col("IFNO") == record.spw_id);
440 : // time_column_.attach(t, "TIME");
441 : // casacore::Vector < casacore::Double > time_list = time_column_.getColumn();
442 : // casacore::Sort sorter;
443 : // sorter.sortKey(time_list.data(), TpDouble);
444 : // casacore::Vector < casacore::uInt > index_vector;
445 : // casacore::uInt n = sorter.sort(index_vector, time_list.size());
446 : // interval_column_.attach(t, "INTERVAL");
447 : // constexpr double kDay2Sec = 86400.0;
448 : // casacore::Double time_min = time_list[index_vector[0]] * kDay2Sec
449 : // - 0.5 * interval_column_(index_vector[0]);
450 : // casacore::Double time_max = time_list[index_vector[n - 1]] * kDay2Sec
451 : // + 0.5 * interval_column_(index_vector[n - 1]);
452 0 : casacore::Block<casacore::Double> const &time_range = time_range_[record.name][ifno];
453 0 : casacore::Double time_min = time_range[0];
454 0 : casacore::Double time_max = time_range[1];
455 0 : record.time = 0.5 * (time_min + time_max);
456 0 : record.interval = (time_max - time_min);
457 0 : }
458 0 : void getProduct(Product */*p*/) override {
459 :
460 0 : }
461 :
462 : private:
463 : casacore::ScalarColumn<casacore::String> name_column_;
464 : casacore::ArrayColumn<casacore::Double> direction_column_;
465 : casacore::ArrayColumn<casacore::Double> proper_motion_column_;
466 : casacore::ScalarColumn<casacore::Double> sysvel_column_;
467 : casacore::ScalarColumn<casacore::uInt> molecule_id_column_;
468 : casacore::ScalarColumn<casacore::uInt> ifno_column_;
469 : casacore::ScalarColumn<casacore::Double> time_column_;
470 : casacore::ScalarColumn<casacore::Double> interval_column_;
471 : casacore::ArrayColumn<casacore::Double> restfrequency_column_;
472 : casacore::ArrayColumn<casacore::String> molecule_name_column_;
473 : casacore::Table molecules_table_;
474 : casacore::Vector<casacore::uInt> row_list_;
475 : std::map<casacore::String, casacore::Int> source_id_map_;
476 : std::map<casacore::uInt, casacore::uInt> molecule_id_map_;
477 : std::map<casacore::String, std::map<casacore::uInt, casacore::Block<casacore::Double> > > time_range_;
478 : };
479 :
480 : } //# NAMESPACE CASA - END
481 :
482 : #endif /* SINGLEDISH_FILLER_SCANTABLEITERATOR_H_ */
|